From 5ea2bcdfbf46fc3aac239ea371a9561053cc977a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 12 Jun 2025 08:29:07 +0200 Subject: [PATCH 0001/2711] printk: ringbuffer: Add KUnit test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The KUnit test validates the correct operation of the ringbuffer. A separate dedicated ringbuffer is used so that the global printk ringbuffer is not touched. Co-developed-by: John Ogness Signed-off-by: John Ogness Signed-off-by: Thomas Weißschuh Reviewed-by: Petr Mladek Link: https://patch.msgid.link/20250612-printk-ringbuffer-test-v3-1-550c088ee368@linutronix.de Signed-off-by: Petr Mladek --- init/Kconfig | 12 + kernel/printk/.kunitconfig | 3 + kernel/printk/Makefile | 2 + kernel/printk/printk_ringbuffer.c | 5 + kernel/printk/printk_ringbuffer_kunit_test.c | 295 +++++++++++++++++++ 5 files changed, 317 insertions(+) create mode 100644 kernel/printk/.kunitconfig create mode 100644 kernel/printk/printk_ringbuffer_kunit_test.c diff --git a/init/Kconfig b/init/Kconfig index af4c2f085455..73e64172b564 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1667,6 +1667,18 @@ config PRINTK very difficult to diagnose system problems, saying N here is strongly discouraged. +config PRINTK_RINGBUFFER_KUNIT_TEST + tristate "KUnit Test for the printk ringbuffer" if !KUNIT_ALL_TESTS + depends on PRINTK && KUNIT + default KUNIT_ALL_TESTS + help + This builds the printk ringbuffer KUnit test suite. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation. + + If unsure, say N. + config BUG bool "BUG() support" if EXPERT default y diff --git a/kernel/printk/.kunitconfig b/kernel/printk/.kunitconfig new file mode 100644 index 000000000000..f31458fd1a92 --- /dev/null +++ b/kernel/printk/.kunitconfig @@ -0,0 +1,3 @@ +CONFIG_KUNIT=y +CONFIG_PRINTK=y +CONFIG_PRINTK_RINGBUFFER_KUNIT_TEST=y diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile index 39a2b61c7232..f8004ac3983d 100644 --- a/kernel/printk/Makefile +++ b/kernel/printk/Makefile @@ -7,3 +7,5 @@ obj-$(CONFIG_PRINTK_INDEX) += index.o obj-$(CONFIG_PRINTK) += printk_support.o printk_support-y := printk_ringbuffer.o printk_support-$(CONFIG_SYSCTL) += sysctl.o + +obj-$(CONFIG_PRINTK_RINGBUFFER_KUNIT_TEST) += printk_ringbuffer_kunit_test.o diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c index d9fb053cff67..bc811de18316 100644 --- a/kernel/printk/printk_ringbuffer.c +++ b/kernel/printk/printk_ringbuffer.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include #include #include @@ -1685,6 +1686,7 @@ fail: memset(r, 0, sizeof(*r)); return false; } +EXPORT_SYMBOL_IF_KUNIT(prb_reserve); /* Commit the data (possibly finalizing it) and restore interrupts. */ static void _prb_commit(struct prb_reserved_entry *e, unsigned long state_val) @@ -1759,6 +1761,7 @@ void prb_commit(struct prb_reserved_entry *e) if (head_id != e->id) desc_make_final(e->rb, e->id); } +EXPORT_SYMBOL_IF_KUNIT(prb_commit); /** * prb_final_commit() - Commit and finalize (previously reserved) data to @@ -2184,6 +2187,7 @@ bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq, { return _prb_read_valid(rb, &seq, r, NULL); } +EXPORT_SYMBOL_IF_KUNIT(prb_read_valid); /** * prb_read_valid_info() - Non-blocking read of meta data for a requested @@ -2333,6 +2337,7 @@ void prb_init(struct printk_ringbuffer *rb, infos[0].seq = -(u64)_DESCS_COUNT(descbits); infos[_DESCS_COUNT(descbits) - 1].seq = 0; } +EXPORT_SYMBOL_IF_KUNIT(prb_init); /** * prb_record_text_space() - Query the full actual used ringbuffer space for diff --git a/kernel/printk/printk_ringbuffer_kunit_test.c b/kernel/printk/printk_ringbuffer_kunit_test.c new file mode 100644 index 000000000000..4081ae051d8e --- /dev/null +++ b/kernel/printk/printk_ringbuffer_kunit_test.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "printk_ringbuffer.h" + +/* + * This KUnit tests the data integrity of the lockless printk_ringbuffer. + * From multiple CPUs it writes messages of varying length and content while + * a reader validates the correctness of the messages. + * + * IMPORTANT: The more CPUs you can use for this KUnit, the better! + * + * The test works by starting "num_online_cpus() - 1" writer threads, each + * pinned to their own CPU. Each writer thread loops, writing data of varying + * length into a printk_ringbuffer as fast as possible. The data content is + * an embedded data struct followed by string content repeating the byte: + * + * 'A' + CPUID + * + * The reader is running on the remaining online CPU, or if there is only one + * CPU on the same as the writer. + * It ensures that the embedded struct content is consistent with the string + * and that the string * is terminated and is composed of the same repeating + * byte as its first byte. + * + * Because the threads are running in such tight loops, they will call + * cond_resched() from time to time so the system stays functional. + * + * If the reader encounters an error, the test is aborted and some + * information about the error is reported. + * The runtime of the test can be configured with the runtime_ms module parameter. + * + * Note that the test is performed on a separate printk_ringbuffer instance + * and not the instance used by printk(). + */ + +static unsigned long runtime_ms = 10 * MSEC_PER_SEC; +module_param(runtime_ms, ulong, 0400); + +/* test data structure */ +struct prbtest_rbdata { + unsigned int len; + char text[] __counted_by(len); +}; + +#define MAX_RBDATA_TEXT_SIZE 0x7f +/* +1 for terminator. */ +#define MAX_PRB_RECORD_SIZE (sizeof(struct prbtest_rbdata) + MAX_RBDATA_TEXT_SIZE + 1) + +struct prbtest_data { + struct kunit *test; + struct printk_ringbuffer *ringbuffer; + /* used by writers to signal reader of new records */ + wait_queue_head_t new_record_wait; +}; + +struct prbtest_thread_data { + unsigned long num; + struct prbtest_data *test_data; +}; + +static void prbtest_fail_record(struct kunit *test, const struct prbtest_rbdata *dat, u64 seq) +{ + KUNIT_FAIL(test, "BAD RECORD: seq=%llu len=%u text=%.*s\n", + seq, dat->len, + dat->len <= MAX_RBDATA_TEXT_SIZE ? dat->len : -1, + dat->len <= MAX_RBDATA_TEXT_SIZE ? dat->text : ""); +} + +static bool prbtest_check_data(const struct prbtest_rbdata *dat) +{ + unsigned int len; + + /* Sane length? */ + if (dat->len < 1 || dat->len > MAX_RBDATA_TEXT_SIZE) + return false; + + if (dat->text[dat->len] != '\0') + return false; + + /* String repeats with the same character? */ + len = dat->len; + while (len--) { + if (dat->text[len] != dat->text[0]) + return false; + } + + return true; +} + +static int prbtest_writer(void *data) +{ + struct prbtest_thread_data *tr = data; + char text_id = 'A' + tr->num; + struct prb_reserved_entry e; + struct prbtest_rbdata *dat; + u32 record_size, text_size; + unsigned long count = 0; + struct printk_record r; + + kunit_info(tr->test_data->test, "start thread %03lu (writer)\n", tr->num); + + for (;;) { + /* ensure at least 1 character */ + text_size = get_random_u32_inclusive(1, MAX_RBDATA_TEXT_SIZE); + /* +1 for terminator. */ + record_size = sizeof(struct prbtest_rbdata) + text_size + 1; + WARN_ON_ONCE(record_size > MAX_PRB_RECORD_SIZE); + + /* specify the text sizes for reservation */ + prb_rec_init_wr(&r, record_size); + + if (prb_reserve(&e, tr->test_data->ringbuffer, &r)) { + r.info->text_len = record_size; + + dat = (struct prbtest_rbdata *)r.text_buf; + dat->len = text_size; + memset(dat->text, text_id, text_size); + dat->text[text_size] = 0; + + prb_commit(&e); + + wake_up_interruptible(&tr->test_data->new_record_wait); + } + + if ((count++ & 0x3fff) == 0) + cond_resched(); + + if (kthread_should_stop()) + break; + } + + kunit_info(tr->test_data->test, "end thread %03lu: wrote=%lu\n", tr->num, count); + + return 0; +} + +struct prbtest_wakeup_timer { + struct timer_list timer; + struct task_struct *task; +}; + +static void prbtest_wakeup_callback(struct timer_list *timer) +{ + struct prbtest_wakeup_timer *wakeup = timer_container_of(wakeup, timer, timer); + + set_tsk_thread_flag(wakeup->task, TIF_NOTIFY_SIGNAL); + wake_up_process(wakeup->task); +} + +static int prbtest_reader(struct prbtest_data *test_data, unsigned long timeout_ms) +{ + struct prbtest_wakeup_timer wakeup; + char text_buf[MAX_PRB_RECORD_SIZE]; + unsigned long count = 0; + struct printk_info info; + struct printk_record r; + u64 seq = 0; + + wakeup.task = current; + timer_setup_on_stack(&wakeup.timer, prbtest_wakeup_callback, 0); + mod_timer(&wakeup.timer, jiffies + msecs_to_jiffies(timeout_ms)); + + prb_rec_init_rd(&r, &info, text_buf, sizeof(text_buf)); + + kunit_info(test_data->test, "start reader\n"); + + while (!wait_event_interruptible(test_data->new_record_wait, + prb_read_valid(test_data->ringbuffer, seq, &r))) { + /* check/track the sequence */ + if (info.seq < seq) + KUNIT_FAIL(test_data->test, "BAD SEQ READ: request=%llu read=%llu\n", + seq, info.seq); + + if (!prbtest_check_data((struct prbtest_rbdata *)r.text_buf)) + prbtest_fail_record(test_data->test, + (struct prbtest_rbdata *)r.text_buf, info.seq); + + if ((count++ & 0x3fff) == 0) + cond_resched(); + + seq = info.seq + 1; + } + + timer_delete_sync(&wakeup.timer); + timer_destroy_on_stack(&wakeup.timer); + + kunit_info(test_data->test, "end reader: read=%lu seq=%llu\n", count, info.seq); + + return 0; +} + +KUNIT_DEFINE_ACTION_WRAPPER(prbtest_kthread_cleanup, kthread_stop, struct task_struct *); + +static void prbtest_add_kthread_cleanup(struct kunit *test, struct task_struct *kthread) +{ + int err; + + err = kunit_add_action_or_reset(test, prbtest_kthread_cleanup, kthread); + KUNIT_ASSERT_EQ(test, err, 0); +} + +static inline void prbtest_prb_reinit(struct printk_ringbuffer *rb) +{ + prb_init(rb, rb->text_data_ring.data, rb->text_data_ring.size_bits, rb->desc_ring.descs, + rb->desc_ring.count_bits, rb->desc_ring.infos); +} + +static void test_readerwriter(struct kunit *test) +{ + /* Equivalent to CONFIG_LOG_BUF_SHIFT=13 */ + DEFINE_PRINTKRB(test_rb, 8, 5); + + struct prbtest_thread_data *thread_data; + struct prbtest_data *test_data; + struct task_struct *thread; + cpumask_t test_cpus; + int cpu, reader_cpu; + + cpus_read_lock(); + /* + * Failure of KUNIT_ASSERT() kills the current task + * so it can not be called while the CPU hotplug lock is held. + * Instead use a snapshot of the online CPUs. + * If they change during test execution it is unfortunate but not a grave error. + */ + cpumask_copy(&test_cpus, cpu_online_mask); + cpus_read_unlock(); + + /* One CPU is for the reader, all others are writers */ + reader_cpu = cpumask_first(&test_cpus); + if (cpumask_weight(&test_cpus) == 1) + kunit_warn(test, "more than one CPU is recommended"); + else + cpumask_clear_cpu(reader_cpu, &test_cpus); + + /* KUnit test can get restarted more times. */ + prbtest_prb_reinit(&test_rb); + + test_data = kunit_kmalloc(test, sizeof(*test_data), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, test_data); + test_data->test = test; + test_data->ringbuffer = &test_rb; + init_waitqueue_head(&test_data->new_record_wait); + + kunit_info(test, "running for %lu ms\n", runtime_ms); + + for_each_cpu(cpu, &test_cpus) { + thread_data = kunit_kmalloc(test, sizeof(*thread_data), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, thread_data); + thread_data->test_data = test_data; + thread_data->num = cpu; + + thread = kthread_run_on_cpu(prbtest_writer, thread_data, cpu, + "prbtest writer %u"); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, thread); + prbtest_add_kthread_cleanup(test, thread); + } + + kunit_info(test, "starting test\n"); + + set_cpus_allowed_ptr(current, cpumask_of(reader_cpu)); + prbtest_reader(test_data, runtime_ms); + + kunit_info(test, "completed test\n"); +} + +static struct kunit_case prb_test_cases[] = { + KUNIT_CASE_SLOW(test_readerwriter), + {} +}; + +static struct kunit_suite prb_test_suite = { + .name = "printk-ringbuffer", + .test_cases = prb_test_cases, +}; +kunit_test_suite(prb_test_suite); + +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); +MODULE_AUTHOR("John Ogness "); +MODULE_DESCRIPTION("printk_ringbuffer KUnit test"); +MODULE_LICENSE("GPL"); From 254e8fb5e67643a19a8dd6e142262ec83b30c3c7 Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Wed, 2 Jul 2025 11:51:55 +0200 Subject: [PATCH 0002/2711] printk: ringbuffer: Explain why the KUnit test ignores failed writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The KUnit test ignores prb_reserve() failures on purpose. It tries to push the ringbuffer beyond limits. Note that it is a know problem that writes might fail in this situation. printk() tries to prevent this problem by: + allocating big enough data buffer, see log_buf_add_cpu(). + allocating enough descriptors by using small enough average record, see PRB_AVGBITS. + storing the record with disabled interrupts, see vprintk_store(). Also the amount of printk() messages is always somehow bound in practice. And they are serialized when they are printed from many CPUs on purpose, for example, when printing backtraces. Reviewed-by: John Ogness Reviewed-by: Thomas Weißschuh Link: https://patch.msgid.link/20250702095157.110916-2-pmladek@suse.com Signed-off-by: Petr Mladek --- kernel/printk/printk_ringbuffer_kunit_test.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kernel/printk/printk_ringbuffer_kunit_test.c b/kernel/printk/printk_ringbuffer_kunit_test.c index 4081ae051d8e..217dcc14670c 100644 --- a/kernel/printk/printk_ringbuffer_kunit_test.c +++ b/kernel/printk/printk_ringbuffer_kunit_test.c @@ -123,6 +123,19 @@ static int prbtest_writer(void *data) /* specify the text sizes for reservation */ prb_rec_init_wr(&r, record_size); + /* + * Reservation can fail if: + * + * - No free descriptor is available. + * - The buffer is full, and the oldest record is reserved + * but not yet committed. + * + * It actually happens in this test because all CPUs are trying + * to write an unbounded number of messages in a tight loop. + * These failures are intentionally ignored because this test + * focuses on races, ringbuffer consistency, and pushing system + * usability limits. + */ if (prb_reserve(&e, tr->test_data->ringbuffer, &r)) { r.info->text_len = record_size; From d18d7989e3da1f2753d49cb24d916f357e340f76 Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Wed, 2 Jul 2025 11:51:57 +0200 Subject: [PATCH 0003/2711] printk: kunit: Fix __counted_by() in struct prbtest_rbdata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __counted_by() has to point to a variable which defines the size of the related array. The code must never access the array beyond this limit. struct prbtest_rbdata currently stores the length of the string. And the code access the array beyond the limit when writing or reading the trailing '\0'. Store the size of the string, including the trailing '\0' if we wanted to keep __counted_by(). Consistently use "_size" suffix when the trailing '\0' is counted. Note that MAX_RBDATA_TEXT_SIZE was originally used to limit the text length. When touching the code, make sure that @text_size produced by get_random_u32_inclusive() stays within the limits. Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/eaea66b9-266a-46e7-980d-33f40ad4b215@sabinyo.mountain Suggested-by: Thomas Weißschuh Reviewed-by: John Ogness Reviewed-by: Thomas Weißschuh Link: https://patch.msgid.link/20250702095157.110916-4-pmladek@suse.com Signed-off-by: Petr Mladek --- kernel/printk/printk_ringbuffer_kunit_test.c | 47 +++++++++++--------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/kernel/printk/printk_ringbuffer_kunit_test.c b/kernel/printk/printk_ringbuffer_kunit_test.c index 217dcc14670c..e67e1815f4c8 100644 --- a/kernel/printk/printk_ringbuffer_kunit_test.c +++ b/kernel/printk/printk_ringbuffer_kunit_test.c @@ -52,13 +52,12 @@ module_param(runtime_ms, ulong, 0400); /* test data structure */ struct prbtest_rbdata { - unsigned int len; - char text[] __counted_by(len); + unsigned int size; + char text[] __counted_by(size); }; -#define MAX_RBDATA_TEXT_SIZE 0x7f -/* +1 for terminator. */ -#define MAX_PRB_RECORD_SIZE (sizeof(struct prbtest_rbdata) + MAX_RBDATA_TEXT_SIZE + 1) +#define MAX_RBDATA_TEXT_SIZE 0x80 +#define MAX_PRB_RECORD_SIZE (sizeof(struct prbtest_rbdata) + MAX_RBDATA_TEXT_SIZE) struct prbtest_data { struct kunit *test; @@ -74,25 +73,29 @@ struct prbtest_thread_data { static void prbtest_fail_record(struct kunit *test, const struct prbtest_rbdata *dat, u64 seq) { - KUNIT_FAIL(test, "BAD RECORD: seq=%llu len=%u text=%.*s\n", - seq, dat->len, - dat->len <= MAX_RBDATA_TEXT_SIZE ? dat->len : -1, - dat->len <= MAX_RBDATA_TEXT_SIZE ? dat->text : ""); + unsigned int len; + + len = dat->size - 1; + + KUNIT_FAIL(test, "BAD RECORD: seq=%llu size=%u text=%.*s\n", + seq, dat->size, + len < MAX_RBDATA_TEXT_SIZE ? len : -1, + len < MAX_RBDATA_TEXT_SIZE ? dat->text : ""); } static bool prbtest_check_data(const struct prbtest_rbdata *dat) { unsigned int len; - /* Sane length? */ - if (dat->len < 1 || dat->len > MAX_RBDATA_TEXT_SIZE) + /* Sane size? At least one character + trailing '\0' */ + if (dat->size < 2 || dat->size > MAX_RBDATA_TEXT_SIZE) return false; - if (dat->text[dat->len] != '\0') + len = dat->size - 1; + if (dat->text[len] != '\0') return false; /* String repeats with the same character? */ - len = dat->len; while (len--) { if (dat->text[len] != dat->text[0]) return false; @@ -114,10 +117,14 @@ static int prbtest_writer(void *data) kunit_info(tr->test_data->test, "start thread %03lu (writer)\n", tr->num); for (;;) { - /* ensure at least 1 character */ - text_size = get_random_u32_inclusive(1, MAX_RBDATA_TEXT_SIZE); - /* +1 for terminator. */ - record_size = sizeof(struct prbtest_rbdata) + text_size + 1; + /* ensure at least 1 character + trailing '\0' */ + text_size = get_random_u32_inclusive(2, MAX_RBDATA_TEXT_SIZE); + if (WARN_ON_ONCE(text_size < 2)) + text_size = 2; + if (WARN_ON_ONCE(text_size > MAX_RBDATA_TEXT_SIZE)) + text_size = MAX_RBDATA_TEXT_SIZE; + + record_size = sizeof(struct prbtest_rbdata) + text_size; WARN_ON_ONCE(record_size > MAX_PRB_RECORD_SIZE); /* specify the text sizes for reservation */ @@ -140,9 +147,9 @@ static int prbtest_writer(void *data) r.info->text_len = record_size; dat = (struct prbtest_rbdata *)r.text_buf; - dat->len = text_size; - memset(dat->text, text_id, text_size); - dat->text[text_size] = 0; + dat->size = text_size; + memset(dat->text, text_id, text_size - 1); + dat->text[text_size - 1] = '\0'; prb_commit(&e); From 5225c689dd9048b67ddf3044da68cc17ab1aa04e Mon Sep 17 00:00:00 2001 From: Ali Nasrolahi Date: Thu, 24 Jul 2025 21:28:19 +0330 Subject: [PATCH 0004/2711] staging: rtl8723bs: fix comment formatting in basic_types.h This patch fixes several block comment formatting issues in basic_types.h to comply with the Linux kernel coding style. Changes include: - Aligning comment markers with asterisks in multi-line comments - Reformatting long lines for better readability - Improving consistency in comment structure - Fixing typos in comments These changes improve readability and remove checkpatch.pl warnings. No functional changes introduced. Signed-off-by: Ali Nasrolahi Link: https://lore.kernel.org/r/20250724175819.29142-1-A.Nasrolahi01@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../staging/rtl8723bs/include/basic_types.h | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/drivers/staging/rtl8723bs/include/basic_types.h b/drivers/staging/rtl8723bs/include/basic_types.h index 24626e65fc7f..1c2da18e6210 100644 --- a/drivers/staging/rtl8723bs/include/basic_types.h +++ b/drivers/staging/rtl8723bs/include/basic_types.h @@ -22,11 +22,11 @@ /* TODO: Belows are Sync from SD7-Driver. It is necessary to check correctness */ /* - *Call endian free function when + * Call endian free function when * 1. Read/write packet content. * 2. Before write integer to IO. * 3. After read integer from IO. -*/ + */ /* */ /* Byte Swapping routine. */ @@ -68,7 +68,8 @@ (*((u32 *)(_ptr))) = EF2BYTE(_val); \ } while (0) -/* Create a bit mask +/* + * Create a bit mask * Examples: * BIT_LEN_MASK_32(0) => 0x00000000 * BIT_LEN_MASK_32(1) => 0x00000001 @@ -82,7 +83,8 @@ #define BIT_LEN_MASK_8(__bitlen) \ (0xFF >> (8 - (__bitlen))) -/* Create an offset bit mask +/* + * Create an offset bit mask * Examples: * BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003 * BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000 @@ -94,7 +96,8 @@ #define BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) \ (BIT_LEN_MASK_8(__bitlen) << (__bitoffset)) -/*Description: +/* + * Description: * Return 4-byte value in host byte ordering from * 4-byte pointer in little-endian system. */ @@ -105,11 +108,11 @@ #define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ (EF1BYTE(*((u8 *)(__pstart)))) -/* */ -/* Description: */ -/* Translate subfield (continuous bits in little-endian) of 4-byte value in litten byte to */ -/* 4-byte value in host byte ordering. */ -/* */ +/* + * Description: + * Translate subfield (continuous bits in little-endian) of 4-byte value in + * little byte to 4-byte value in host byte ordering. + */ #define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ (\ (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \ @@ -126,11 +129,11 @@ BIT_LEN_MASK_8(__bitlen) \ ) -/* */ -/* Description: */ -/* Mask subfield (continuous bits in little-endian) of 4-byte value in litten byte oredering */ -/* and return the result in 4-byte value in host byte ordering. */ -/* */ +/* + * Description: + * Mask subfield (continuous bits in little-endian) of 4-byte value in little + * byte ordering and return the result in 4-byte value in host byte ordering. + */ #define LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ (\ LE_P4BYTE_TO_HOST_4BYTE(__pstart) & \ @@ -147,10 +150,10 @@ (~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen)) \ ) -/* */ -/* Description: */ -/* Set subfield of little-endian 4-byte value to specified value. */ -/* */ +/* + * Description: + * Set subfield of little-endian 4-byte value to specified value. + */ #define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \ *((u32 *)(__pstart)) = \ ( \ From 520c9fde09b557559fe512cc5b2ba689cd08567e Mon Sep 17 00:00:00 2001 From: Bruce Qin Date: Thu, 24 Jul 2025 21:25:33 +0200 Subject: [PATCH 0005/2711] staging: rtl8723bs: fix if-statement alignment and line continuation in rtw_ap.c This patch fixes several style issues in a multiline if-statement: - Moved '&&' to the end of the previous line to follow logical continuation style - Fixed indentation to align with the opening parenthesis of the expression - Avoided ending a line with an open parenthesis '(' - Moved closing ')' to the end of the last expression line (as suggested by the maintainer) These changes improve readability and conform to Linux kernel coding conventions. No functional changes. Signed-off-by: Bruce Qin Link: https://lore.kernel.org/r/20250724192533.21141-1-bqn9090@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_ap.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c index b2e7e7267aa4..0908f2234f67 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ap.c +++ b/drivers/staging/rtl8723bs/core/rtw_ap.c @@ -258,11 +258,9 @@ void expire_timeout_chk(struct adapter *padapter) } else { /* TODO: Aging mechanism to digest frames in sleep_q to */ /* avoid running out of xmitframe */ - if (psta->sleepq_len > (NR_XMITFRAME / pstapriv->asoc_list_cnt) - && padapter->xmitpriv.free_xmitframe_cnt < (( - NR_XMITFRAME / pstapriv->asoc_list_cnt - ) / 2) - ) + if (psta->sleepq_len > (NR_XMITFRAME / pstapriv->asoc_list_cnt) && + padapter->xmitpriv.free_xmitframe_cnt < + ((NR_XMITFRAME / pstapriv->asoc_list_cnt) / 2)) wakeup_sta_to_xmit(padapter, psta); } } From 4a9e0777bf0beb00c6e96cf311bd7c4c255ab341 Mon Sep 17 00:00:00 2001 From: Len Bao Date: Sun, 27 Jul 2025 10:10:47 +0000 Subject: [PATCH 0006/2711] staging: octeon: Use 'u64' instead of 'uint64_t' in union cvmx_pip_wqe_word2 In the kernel type 'u64' is preferred over type 'uint64_t'. So, refactor the 'union cvmx_pip_wqe_word2' to use the former. At the same time, take advantage of this to align the bits quantity to improve readability. Also, separate the structs with blank lines to gain readability. Signed-off-by: Len Bao Link: https://lore.kernel.org/r/20250727101052.41181-1-len.bao@gmx.us Signed-off-by: Greg Kroah-Hartman --- drivers/staging/octeon/octeon-stubs.h | 136 +++++++++++++------------- 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/drivers/staging/octeon/octeon-stubs.h b/drivers/staging/octeon/octeon-stubs.h index 44cced319c11..35b5078ba51e 100644 --- a/drivers/staging/octeon/octeon-stubs.h +++ b/drivers/staging/octeon/octeon-stubs.h @@ -43,81 +43,83 @@ #define CVMX_POW_WQ_INT_PC 0 union cvmx_pip_wqe_word2 { - uint64_t u64; + u64 u64; + struct { - uint64_t bufs:8; - uint64_t ip_offset:8; - uint64_t vlan_valid:1; - uint64_t vlan_stacked:1; - uint64_t unassigned:1; - uint64_t vlan_cfi:1; - uint64_t vlan_id:12; - uint64_t pr:4; - uint64_t unassigned2:8; - uint64_t dec_ipcomp:1; - uint64_t tcp_or_udp:1; - uint64_t dec_ipsec:1; - uint64_t is_v6:1; - uint64_t software:1; - uint64_t L4_error:1; - uint64_t is_frag:1; - uint64_t IP_exc:1; - uint64_t is_bcast:1; - uint64_t is_mcast:1; - uint64_t not_IP:1; - uint64_t rcv_error:1; - uint64_t err_code:8; + u64 bufs : 8; + u64 ip_offset : 8; + u64 vlan_valid : 1; + u64 vlan_stacked : 1; + u64 unassigned : 1; + u64 vlan_cfi : 1; + u64 vlan_id : 12; + u64 pr : 4; + u64 unassigned2 : 8; + u64 dec_ipcomp : 1; + u64 tcp_or_udp : 1; + u64 dec_ipsec : 1; + u64 is_v6 : 1; + u64 software : 1; + u64 L4_error : 1; + u64 is_frag : 1; + u64 IP_exc : 1; + u64 is_bcast : 1; + u64 is_mcast : 1; + u64 not_IP : 1; + u64 rcv_error : 1; + u64 err_code : 8; } s; + struct { - uint64_t bufs:8; - uint64_t ip_offset:8; - uint64_t vlan_valid:1; - uint64_t vlan_stacked:1; - uint64_t unassigned:1; - uint64_t vlan_cfi:1; - uint64_t vlan_id:12; - uint64_t port:12; - uint64_t dec_ipcomp:1; - uint64_t tcp_or_udp:1; - uint64_t dec_ipsec:1; - uint64_t is_v6:1; - uint64_t software:1; - uint64_t L4_error:1; - uint64_t is_frag:1; - uint64_t IP_exc:1; - uint64_t is_bcast:1; - uint64_t is_mcast:1; - uint64_t not_IP:1; - uint64_t rcv_error:1; - uint64_t err_code:8; + u64 bufs : 8; + u64 ip_offset : 8; + u64 vlan_valid : 1; + u64 vlan_stacked : 1; + u64 unassigned : 1; + u64 vlan_cfi : 1; + u64 vlan_id : 12; + u64 port : 12; + u64 dec_ipcomp : 1; + u64 tcp_or_udp : 1; + u64 dec_ipsec : 1; + u64 is_v6 : 1; + u64 software : 1; + u64 L4_error : 1; + u64 is_frag : 1; + u64 IP_exc : 1; + u64 is_bcast : 1; + u64 is_mcast : 1; + u64 not_IP : 1; + u64 rcv_error : 1; + u64 err_code : 8; } s_cn68xx; struct { - uint64_t unused1:16; - uint64_t vlan:16; - uint64_t unused2:32; + u64 unused1 : 16; + u64 vlan : 16; + u64 unused2 : 32; } svlan; - struct { - uint64_t bufs:8; - uint64_t unused:8; - uint64_t vlan_valid:1; - uint64_t vlan_stacked:1; - uint64_t unassigned:1; - uint64_t vlan_cfi:1; - uint64_t vlan_id:12; - uint64_t pr:4; - uint64_t unassigned2:12; - uint64_t software:1; - uint64_t unassigned3:1; - uint64_t is_rarp:1; - uint64_t is_arp:1; - uint64_t is_bcast:1; - uint64_t is_mcast:1; - uint64_t not_IP:1; - uint64_t rcv_error:1; - uint64_t err_code:8; - } snoip; + struct { + u64 bufs : 8; + u64 unused : 8; + u64 vlan_valid : 1; + u64 vlan_stacked : 1; + u64 unassigned : 1; + u64 vlan_cfi : 1; + u64 vlan_id : 12; + u64 pr : 4; + u64 unassigned2 : 12; + u64 software : 1; + u64 unassigned3 : 1; + u64 is_rarp : 1; + u64 is_arp : 1; + u64 is_bcast : 1; + u64 is_mcast : 1; + u64 not_IP : 1; + u64 rcv_error : 1; + u64 err_code : 8; + } snoip; }; union cvmx_pip_wqe_word0 { From 08a2e17462dc3b78693124530396eadd380badee Mon Sep 17 00:00:00 2001 From: Zhuoheng Li Date: Tue, 5 Aug 2025 10:38:16 +0800 Subject: [PATCH 0007/2711] staging: rtl8723bs: fix space-before-tab warnings Fixes multiple coding style issues reported by checkpatch.pl: "WARNING: please, no space before tabs". This patch only adjusts whitespace indentation without changing functionality. Signed-off-by: Zhuoheng Li Link: https://lore.kernel.org/r/20250805023816.3741-1-15620332615@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme.c | 51 ++++---- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 121 +++++++++--------- drivers/staging/rtl8723bs/core/rtw_pwrctrl.c | 10 +- 3 files changed, 85 insertions(+), 97 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index 692d0c2b766d..28154b6a64c2 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -567,12 +567,14 @@ void rtw_add_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork) rtw_update_scanned_network(adapter, pnetwork); } -/* select the desired network based on the capability of the (i)bss. */ -/* check items: (1) security */ -/* (2) network_type */ -/* (3) WMM */ -/* (4) HT */ -/* (5) others */ +/* select the desired network based on the capability of the (i)bss. + * check items: + * (1) security + * (2) network_type + * (3) WMM + * (4) HT + * (5) others + */ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwork); int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwork) { @@ -1841,9 +1843,9 @@ exit: signed int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, signed int keyid, u8 set_tx, bool enqueue) { u8 keylen; - struct cmd_obj *pcmd; + struct cmd_obj *pcmd; struct setkey_parm *psetkeyparm; - struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; signed int res = _SUCCESS; psetkeyparm = rtw_zmalloc(sizeof(struct setkey_parm)); @@ -1942,17 +1944,16 @@ int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_ } -/* */ -/* Ported from 8185: IsInPreAuthKeyList(). (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) */ -/* Added by Annie, 2006-05-07. */ -/* */ -/* Search by BSSID, */ -/* Return Value: */ -/* -1 :if there is no pre-auth key in the table */ -/* >= 0 :if there is pre-auth key, and return the entry id */ -/* */ -/* */ - +/* Ported from 8185: IsInPreAuthKeyList(). + * (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) + * Added by Annie, 2006-05-07. + * + * Search by BSSID, + * + * Return Value: + * -1: if there is no pre-auth key in the table + * >=0: if there is pre-auth key, and return the entry id + */ static int SecIsInPMKIDList(struct adapter *Adapter, u8 *bssid) { struct security_priv *p = &Adapter->securitypriv; @@ -2099,7 +2100,7 @@ void rtw_joinbss_reset(struct adapter *padapter) u8 threshold; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; /* todo: if you want to do something io/reg/hw setting before join_bss, please add code here */ @@ -2125,8 +2126,8 @@ void rtw_joinbss_reset(struct adapter *padapter) void rtw_ht_use_default_setting(struct adapter *padapter) { - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; struct registry_priv *pregistrypriv = &padapter->registrypriv; bool bHwLDPCSupport = false, bHwSTBCSupport = false; bool bHwSupportBeamformer = false, bHwSupportBeamformee = false; @@ -2200,7 +2201,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ u8 cbw40_enable = 0, stbc_rx_enable = 0, operation_bw = 0; struct registry_priv *pregistrypriv = &padapter->registrypriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; phtpriv->ht_option = false; @@ -2321,7 +2322,7 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe int len; struct ieee80211_ht_cap *pht_capie; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; struct registry_priv *pregistrypriv = &padapter->registrypriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -2443,7 +2444,7 @@ void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitfr void rtw_append_exented_cap(struct adapter *padapter, u8 *out_ie, uint *pout_len) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; u8 cap_content[8] = {0}; if (phtpriv->bss_coexist) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index bc980d21d50e..a830646fbcb1 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -937,10 +937,10 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) u16 capab_info; struct rtw_ieee802_11_elems elems; struct sta_info *pstat; - unsigned char *p, *pos, *wpa_ie; + unsigned char *p, *pos, *wpa_ie; unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; int i, ie_len, wpa_ie_len, left; - unsigned char supportRate[16]; + unsigned char supportRate[16]; int supportRateNum; unsigned short status = WLAN_STATUS_SUCCESS; unsigned short frame_type, ie_offset = 0; @@ -1122,9 +1122,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) if (!wpa_ie) { if (elems.wps_ie) { pstat->flags |= WLAN_STA_WPS; - /* wpabuf_free(sta->wps_ie); */ - /* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */ - /* elems.wps_ie_len - 4); */ } else { pstat->flags |= WLAN_STA_MAYBE_WPS; } @@ -1502,11 +1499,12 @@ unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame) return _SUCCESS; } - /* Commented by Albert 20130604 */ - /* Before sending the auth frame to start the STA/GC mode connection with AP/GO, */ - /* we will send the deauth first. */ - /* However, the Win8.1 with BRCM Wi-Fi will send the deauth with reason code 6 to us after receieving our deauth. */ - /* Added the following code to avoid this case. */ + /* Commented by Albert 20130604 + * Before sending the auth frame to start the STA/GC mode connection with AP/GO, + * we will send the deauth first. + * However, the Win8.1 with BRCM Wi-Fi will send the deauth with reason code 6 to us after receieving our deauth. + * Added the following code to avoid this case. + */ if ((pmlmeinfo->state & WIFI_FW_AUTH_STATE) || (pmlmeinfo->state & WIFI_FW_ASSOC_STATE)) { if (reason == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA) { @@ -1626,8 +1624,8 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra u8 *addr; struct sta_info *psta = NULL; struct recv_reorder_ctrl *preorder_ctrl; - unsigned char *frame_body; - unsigned char category, action; + unsigned char *frame_body; + unsigned char category, action; unsigned short tid, status; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); @@ -2259,10 +2257,10 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p { struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - unsigned char *pframe; + unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; __le16 *fctrl; - unsigned char *mac, *bssid; + unsigned char *mac, *bssid; struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); u8 *pwps_ie; @@ -2456,12 +2454,12 @@ static int _issue_probereq(struct adapter *padapter, int ret = _FAIL; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - unsigned char *pframe; + unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; __le16 *fctrl; - unsigned char *mac; - unsigned char bssrate[NumRates]; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + unsigned char *mac; + unsigned char bssrate[NumRates]; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); int bssrate_len = 0; @@ -2486,11 +2484,11 @@ static int _issue_probereq(struct adapter *padapter, *(fctrl) = 0; if (da) { - /* unicast probe request frame */ + /* unicast probe request frame */ memcpy(pwlanhdr->addr1, da, ETH_ALEN); memcpy(pwlanhdr->addr3, da, ETH_ALEN); } else { - /* broadcast probe request frame */ + /* broadcast probe request frame */ eth_broadcast_addr(pwlanhdr->addr1); eth_broadcast_addr(pwlanhdr->addr3); } @@ -2584,13 +2582,13 @@ void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short { struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - unsigned char *pframe; + unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; __le16 *fctrl; unsigned int val32; unsigned short val16; int use_shared_key = 0; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); __le16 le_tmp; @@ -2841,14 +2839,14 @@ void issue_assocreq(struct adapter *padapter) int ret = _FAIL; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - unsigned char *pframe; + unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; __le16 *fctrl; __le16 val16; unsigned int i, j, index = 0; unsigned char bssrate[NumRates], sta_bssrate[NumRates]; struct ndis_80211_var_ie *pIE; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); @@ -3018,7 +3016,7 @@ static int _issue_nulldata(struct adapter *padapter, unsigned char *da, int ret = _FAIL; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - unsigned char *pframe; + unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; __le16 *fctrl; struct xmit_priv *pxmitpriv; @@ -3163,11 +3161,11 @@ static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, int ret = _FAIL; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - unsigned char *pframe; + unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; __le16 *fctrl; u16 *qc; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); @@ -3272,10 +3270,10 @@ static int _issue_deauth(struct adapter *padapter, unsigned char *da, { struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - unsigned char *pframe; + unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; __le16 *fctrl; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); int ret = _FAIL; @@ -3366,10 +3364,10 @@ void issue_action_SA_Query(struct adapter *padapter, unsigned char *raddr, unsig u8 category = RTW_WLAN_CATEGORY_SA_QUERY; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - u8 *pframe; + u8 *pframe; struct ieee80211_hdr *pwlanhdr; __le16 *fctrl; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); __le16 le_tmp; @@ -3439,15 +3437,15 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch enum ieee80211_max_ampdu_length_exp max_rx_ampdu_factor; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - u8 *pframe; + u8 *pframe; struct ieee80211_hdr *pwlanhdr; __le16 *fctrl; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct sta_info *psta; - struct sta_priv *pstapriv = &padapter->stapriv; - struct registry_priv *pregpriv = &padapter->registrypriv; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + struct registry_priv *pregpriv = &padapter->registrypriv; __le16 le_tmp; pmgntframe = alloc_mgtxmitframe(pxmitpriv); @@ -3585,11 +3583,11 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter) unsigned char category, action; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - unsigned char *pframe; + unsigned char *pframe; struct ieee80211_hdr *pwlanhdr; __le16 *fctrl; struct wlan_network *pnetwork = NULL; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); @@ -3798,7 +3796,7 @@ Following are some utility functions for WiFi MLME void site_survey(struct adapter *padapter) { - unsigned char survey_channel = 0, val8; + unsigned char survey_channel = 0, val8; enum rt_scan_type ScanType = SCAN_PASSIVE; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); @@ -3867,7 +3865,7 @@ void site_survey(struct adapter *padapter) set_survey_timer(pmlmeext, channel_scan_time_ms); } else { - /* channel number is 0 or this channel is not valid. */ + /* channel number is 0 or this channel is not valid. */ { pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; @@ -4144,12 +4142,13 @@ void start_clnt_join(struct adapter *padapter) rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); - /* Because of AP's not receiving deauth before */ - /* AP may: 1)not response auth or 2)deauth us after link is complete */ - /* issue deauth before issuing auth to deal with the situation */ - - /* Commented by Albert 2012/07/21 */ - /* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */ + /* Because of AP's not receiving deauth before + * AP may: 1)not response auth or 2)deauth us after link is complete + * issue deauth before issuing auth to deal with the situation + * + * Commented by Albert 2012/07/21 + * For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. + */ { /* To avoid connecting to AP fail during resume process, change retry count from 5 to 1 */ issue_deauth_ex(padapter, pnetwork->mac_address, WLAN_REASON_DEAUTH_LEAVING, 1, 100); @@ -4322,7 +4321,6 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid k++; } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) { chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; -/* chplan_new[k].ScanType = chplan_sta[i].ScanType; */ chplan_new[k].ScanType = SCAN_PASSIVE; i++; k++; @@ -4340,7 +4338,6 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid (chplan_sta[i].ChannelNum <= 14)) { chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; -/* chplan_new[k].ScanType = chplan_sta[i].ScanType; */ chplan_new[k].ScanType = SCAN_PASSIVE; i++; k++; @@ -4460,7 +4457,7 @@ void report_surveydone_event(struct adapter *padapter) u32 cmdsz; struct surveydone_event *psurveydone_evt; struct C2HEvent_Header *pc2h_evt_hdr; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj)); @@ -4504,7 +4501,7 @@ void report_join_res(struct adapter *padapter, int res) u32 cmdsz; struct joinbss_event *pjoinbss_evt; struct C2HEvent_Header *pc2h_evt_hdr; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct cmd_priv *pcmdpriv = &padapter->cmdpriv; @@ -4554,7 +4551,7 @@ void report_wmm_edca_update(struct adapter *padapter) u32 cmdsz; struct wmm_event *pwmm_event; struct C2HEvent_Header *pc2h_evt_hdr; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj)); @@ -4600,7 +4597,7 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsi int mac_id; struct stadel_event *pdel_sta_evt; struct C2HEvent_Header *pc2h_evt_hdr; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj)); @@ -4651,7 +4648,7 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int u32 cmdsz; struct stassoc_event *padd_sta_evt; struct C2HEvent_Header *pc2h_evt_hdr; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj)); @@ -4755,7 +4752,7 @@ void update_sta_info(struct adapter *padapter, struct sta_info *psta) static void rtw_mlmeext_disconnect(struct adapter *padapter) { - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); @@ -4805,7 +4802,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); - struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_priv *pstapriv = &padapter->stapriv; u8 join_type; struct sta_info *psta; @@ -4983,11 +4980,11 @@ static u8 chk_ap_is_alive(struct adapter *padapter, struct sta_info *psta) void linked_status_chk(struct adapter *padapter) { u32 i; - struct sta_info *psta; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct sta_info *psta; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_priv *pstapriv = &padapter->stapriv; if (is_client_associated_to_ap(padapter)) { @@ -5091,8 +5088,8 @@ void survey_timer_hdl(struct timer_list *t) timer_container_of(padapter, t, mlmeextpriv.survey_timer); struct cmd_obj *ph2c; struct sitesurvey_parm *psurveyPara; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; /* issue rtw_sitesurvey_cmd */ if (pmlmeext->sitesurvey_res.state > SCAN_START) { @@ -5124,12 +5121,8 @@ void link_timer_hdl(struct timer_list *t) { struct adapter *padapter = timer_container_of(padapter, t, mlmeextpriv.link_timer); - /* static unsigned int rx_pkt = 0; */ - /* static u64 tx_cnt = 0; */ - /* struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); */ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - /* struct sta_priv *pstapriv = &padapter->stapriv; */ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index 6a2583d0d3eb..7b643ac320f0 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -430,10 +430,7 @@ s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms) return err; } -/* */ -/* Description: */ -/* Enter the leisure power save mode. */ -/* */ +/* Description: Enter the leisure power save mode. */ void LPS_Enter(struct adapter *padapter, const char *msg) { struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); @@ -466,10 +463,7 @@ void LPS_Enter(struct adapter *padapter, const char *msg) } } -/* */ -/* Description: */ -/* Leave the leisure power save mode. */ -/* */ +/* Description: Leave the leisure power save mode. */ void LPS_Leave(struct adapter *padapter, const char *msg) { #define LPS_LEAVE_TIMEOUT_MS 100 From 7c0480fd766efced3a3df25b202f6914135576a7 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 1 Aug 2025 10:31:24 +0200 Subject: [PATCH 0008/2711] staging: rtl8723bs: remove wrapper rtw_os_indicate_scan_done The function rtw_os_indicate_scan_done is just a wrapper around rtw_cfg80211_indicate_scan_done. Use rtw_cfg80211_indicate_scan_done directly and remove the wrapper. Signed-off-by: Michael Straube Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250801083131.82915-2-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme.c | 2 +- drivers/staging/rtl8723bs/include/mlme_osdep.h | 1 - drivers/staging/rtl8723bs/os_dep/mlme_linux.c | 5 ----- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index 28154b6a64c2..6932bd3b2054 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -911,7 +911,7 @@ void rtw_indicate_disconnect(struct adapter *padapter) inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted) { - rtw_os_indicate_scan_done(padapter, aborted); + rtw_cfg80211_indicate_scan_done(padapter, aborted); if ((!adapter_to_pwrctl(padapter)->bInSuspend) && (!check_fwstate(&padapter->mlmepriv, diff --git a/drivers/staging/rtl8723bs/include/mlme_osdep.h b/drivers/staging/rtl8723bs/include/mlme_osdep.h index f0d19637fb0f..c84c84c68286 100644 --- a/drivers/staging/rtl8723bs/include/mlme_osdep.h +++ b/drivers/staging/rtl8723bs/include/mlme_osdep.h @@ -11,7 +11,6 @@ extern void rtw_init_mlme_timer(struct adapter *padapter); extern void rtw_os_indicate_disconnect(struct adapter *adapter); extern void rtw_os_indicate_connect(struct adapter *adapter); -void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted); extern void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie); void rtw_reset_securitypriv(struct adapter *adapter); diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c index fd4ae870a617..09bf363efa8b 100644 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c @@ -53,11 +53,6 @@ void rtw_os_indicate_connect(struct adapter *adapter) rtw_signal_process(adapter->pid[2], SIGALRM); } -void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted) -{ - rtw_cfg80211_indicate_scan_done(padapter, aborted); -} - static struct rt_pmkid_list backupPMKIDList[NUM_PMKID_CACHE]; void rtw_reset_securitypriv(struct adapter *adapter) { From 6f9ada0a6916c80a3d0e7ed11c773b51b227f2e0 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 1 Aug 2025 10:31:25 +0200 Subject: [PATCH 0009/2711] staging: rtl8723bs: move init_mlme_ext_timer to core/rtw_mlme_ext.c Move the function init_mlme_ext_timer from os_dep/mlme_linux.c to core/rtw_mlme_ext.c to reduce code in the os_dep directory. Signed-off-by: Michael Straube Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250801083131.82915-3-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 9 +++++++++ drivers/staging/rtl8723bs/include/rtw_mlme_ext.h | 1 - drivers/staging/rtl8723bs/os_dep/mlme_linux.c | 8 -------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index a830646fbcb1..a897c433d2b0 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -374,6 +374,15 @@ static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_c return chanset_size; } +static void init_mlme_ext_timer(struct adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + timer_setup(&pmlmeext->survey_timer, survey_timer_hdl, 0); + timer_setup(&pmlmeext->link_timer, link_timer_hdl, 0); + timer_setup(&pmlmeext->sa_query_timer, sa_query_timer_hdl, 0); +} + void init_mlme_ext_priv(struct adapter *padapter) { struct registry_priv *pregistrypriv = &padapter->registrypriv; diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h index 2080408743ef..58e2d8e159d6 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h @@ -426,7 +426,6 @@ void init_mlme_default_rate_set(struct adapter *padapter); void init_mlme_ext_priv(struct adapter *padapter); int init_hw_mlme_ext(struct adapter *padapter); void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext); -extern void init_mlme_ext_timer(struct adapter *padapter); extern void init_addba_retry_timer(struct adapter *padapter, struct sta_info *psta); extern struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv); diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c index 09bf363efa8b..d22d6cf3cb11 100644 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c @@ -164,11 +164,3 @@ void init_addba_retry_timer(struct adapter *padapter, struct sta_info *psta) timer_setup(&psta->addba_retry_timer, addba_timer_hdl, 0); } -void init_mlme_ext_timer(struct adapter *padapter) -{ - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - - timer_setup(&pmlmeext->survey_timer, survey_timer_hdl, 0); - timer_setup(&pmlmeext->link_timer, link_timer_hdl, 0); - timer_setup(&pmlmeext->sa_query_timer, sa_query_timer_hdl, 0); -} From 472646fce339a3a4af144cf458f3ac16a3c30d13 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 1 Aug 2025 10:31:26 +0200 Subject: [PATCH 0010/2711] staging: rtl8723bs: move rtw_init_mlme_timer to core/rtw_mlme.c Move the function rtw_init_mlme_timer from os_dep/mlme_linux.c to core/rtw_mlme.c to reduce code in the os_dep directory. Signed-off-by: Michael Straube Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250801083131.82915-4-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme.c | 30 +++++++++++++++++++ .../staging/rtl8723bs/include/mlme_osdep.h | 1 - drivers/staging/rtl8723bs/os_dep/mlme_linux.c | 30 ------------------- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index 6932bd3b2054..dbeba9cdfa73 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -9,6 +9,36 @@ #include #include +static void _dynamic_check_timer_handler(struct timer_list *t) +{ + struct adapter *adapter = + timer_container_of(adapter, t, mlmepriv.dynamic_chk_timer); + + rtw_dynamic_check_timer_handler(adapter); + + _set_timer(&adapter->mlmepriv.dynamic_chk_timer, 2000); +} + +static void _rtw_set_scan_deny_timer_hdl(struct timer_list *t) +{ + struct adapter *adapter = + timer_container_of(adapter, t, mlmepriv.set_scan_deny_timer); + + rtw_clear_scan_deny(adapter); +} + +static void rtw_init_mlme_timer(struct adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + timer_setup(&pmlmepriv->assoc_timer, _rtw_join_timeout_handler, 0); + timer_setup(&pmlmepriv->scan_to_timer, rtw_scan_timeout_handler, 0); + timer_setup(&pmlmepriv->dynamic_chk_timer, + _dynamic_check_timer_handler, 0); + timer_setup(&pmlmepriv->set_scan_deny_timer, + _rtw_set_scan_deny_timer_hdl, 0); +} + int rtw_init_mlme_priv(struct adapter *padapter) { int i; diff --git a/drivers/staging/rtl8723bs/include/mlme_osdep.h b/drivers/staging/rtl8723bs/include/mlme_osdep.h index c84c84c68286..4bb7a01caf4a 100644 --- a/drivers/staging/rtl8723bs/include/mlme_osdep.h +++ b/drivers/staging/rtl8723bs/include/mlme_osdep.h @@ -8,7 +8,6 @@ #define __MLME_OSDEP_H_ -extern void rtw_init_mlme_timer(struct adapter *padapter); extern void rtw_os_indicate_disconnect(struct adapter *adapter); extern void rtw_os_indicate_connect(struct adapter *adapter); extern void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie); diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c index d22d6cf3cb11..5cb27ddab769 100644 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c @@ -6,36 +6,6 @@ ******************************************************************************/ #include -static void _dynamic_check_timer_handler(struct timer_list *t) -{ - struct adapter *adapter = - timer_container_of(adapter, t, mlmepriv.dynamic_chk_timer); - - rtw_dynamic_check_timer_handler(adapter); - - _set_timer(&adapter->mlmepriv.dynamic_chk_timer, 2000); -} - -static void _rtw_set_scan_deny_timer_hdl(struct timer_list *t) -{ - struct adapter *adapter = - timer_container_of(adapter, t, mlmepriv.set_scan_deny_timer); - - rtw_clear_scan_deny(adapter); -} - -void rtw_init_mlme_timer(struct adapter *padapter) -{ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - timer_setup(&pmlmepriv->assoc_timer, _rtw_join_timeout_handler, 0); - timer_setup(&pmlmepriv->scan_to_timer, rtw_scan_timeout_handler, 0); - timer_setup(&pmlmepriv->dynamic_chk_timer, - _dynamic_check_timer_handler, 0); - timer_setup(&pmlmepriv->set_scan_deny_timer, - _rtw_set_scan_deny_timer_hdl, 0); -} - void rtw_os_indicate_connect(struct adapter *adapter) { struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); From eec9d92d080d324b390ad55514199c1b1298ea18 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 1 Aug 2025 10:31:27 +0200 Subject: [PATCH 0011/2711] staging: rtl8723bs: remove wrapper init_addba_retry_timer The function init_addba_retry_timer is just a wrapper around timer_setup. Remove the wrapper and use timer_setup directly. Signed-off-by: Michael Straube Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250801083131.82915-5-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_sta_mgt.c | 2 +- drivers/staging/rtl8723bs/include/rtw_mlme_ext.h | 1 - drivers/staging/rtl8723bs/os_dep/mlme_linux.c | 6 ------ 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c index 1d2b53c76afc..4d51e6993ca2 100644 --- a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c @@ -229,7 +229,7 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) for (i = 0; i < 16; i++) memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); - init_addba_retry_timer(pstapriv->padapter, psta); + timer_setup(&psta->addba_retry_timer, addba_timer_hdl, 0); /* for A-MPDU Rx reordering buffer control */ for (i = 0; i < 16 ; i++) { diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h index 58e2d8e159d6..53fac838c36a 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h @@ -426,7 +426,6 @@ void init_mlme_default_rate_set(struct adapter *padapter); void init_mlme_ext_priv(struct adapter *padapter); int init_hw_mlme_ext(struct adapter *padapter); void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext); -extern void init_addba_retry_timer(struct adapter *padapter, struct sta_info *psta); extern struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv); /* void fill_fwpriv(struct adapter *padapter, struct fw_priv *pfwpriv); */ diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c index 5cb27ddab769..f85e17ae0e7f 100644 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c @@ -128,9 +128,3 @@ void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie) kfree(buff); } } - -void init_addba_retry_timer(struct adapter *padapter, struct sta_info *psta) -{ - timer_setup(&psta->addba_retry_timer, addba_timer_hdl, 0); -} - From ff059535aa64677d80c4c3c7b99e983989108c68 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 1 Aug 2025 10:31:28 +0200 Subject: [PATCH 0012/2711] staging: rtl8723bs: merge rtw_os_indicate_connect into rtw_indicate_connect Merge the functionality of the function rtw_os_indicate_connect into the function rtw_indicate_connect to reduce code in the os_dep directory. Signed-off-by: Michael Straube Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250801083131.82915-6-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme.c | 13 +++++++++++-- drivers/staging/rtl8723bs/include/mlme_osdep.h | 1 - drivers/staging/rtl8723bs/os_dep/mlme_linux.c | 17 ----------------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index dbeba9cdfa73..b77dbf104692 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -903,12 +903,21 @@ void rtw_indicate_connect(struct adapter *padapter) set_fwstate(pmlmepriv, _FW_LINKED); - rtw_os_indicate_connect(padapter); + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || + check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { + rtw_cfg80211_ibss_indicate_connect(padapter); + } else { + rtw_cfg80211_indicate_connect(padapter); + } + + netif_carrier_on(padapter->pnetdev); + + if (padapter->pid[2] != 0) + rtw_signal_process(padapter->pid[2], SIGALRM); } rtw_set_to_roam(padapter, 0); rtw_set_scan_deny(padapter, 3000); - } /* diff --git a/drivers/staging/rtl8723bs/include/mlme_osdep.h b/drivers/staging/rtl8723bs/include/mlme_osdep.h index 4bb7a01caf4a..00c0a44c125a 100644 --- a/drivers/staging/rtl8723bs/include/mlme_osdep.h +++ b/drivers/staging/rtl8723bs/include/mlme_osdep.h @@ -9,7 +9,6 @@ extern void rtw_os_indicate_disconnect(struct adapter *adapter); -extern void rtw_os_indicate_connect(struct adapter *adapter); extern void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie); void rtw_reset_securitypriv(struct adapter *adapter); diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c index f85e17ae0e7f..326acbd8dc84 100644 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c @@ -6,23 +6,6 @@ ******************************************************************************/ #include -void rtw_os_indicate_connect(struct adapter *adapter) -{ - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); - - if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || - (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) { - rtw_cfg80211_ibss_indicate_connect(adapter); - } else { - rtw_cfg80211_indicate_connect(adapter); - } - - netif_carrier_on(adapter->pnetdev); - - if (adapter->pid[2] != 0) - rtw_signal_process(adapter->pid[2], SIGALRM); -} - static struct rt_pmkid_list backupPMKIDList[NUM_PMKID_CACHE]; void rtw_reset_securitypriv(struct adapter *adapter) { From 7bb7804420b7a728ca990ff4872e7b5ba44ea780 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 1 Aug 2025 10:31:29 +0200 Subject: [PATCH 0013/2711] staging: rtl8723bs: merge rtw_os_indicate_disconnect into rtw_indicate_disconnect Merge the functionality of the function rtw_os_indicate_disconnect into the function rtw_indicate_disconnect to reduce code in the os_dep directory. Signed-off-by: Michael Straube Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250801083131.82915-7-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme.c | 12 ++++++++---- drivers/staging/rtl8723bs/include/mlme_osdep.h | 1 - drivers/staging/rtl8723bs/os_dep/mlme_linux.c | 12 ------------ 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index b77dbf104692..d0579cba3e32 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -932,10 +932,14 @@ void rtw_indicate_disconnect(struct adapter *padapter) if (rtw_to_roam(padapter) > 0) _clr_fwstate_(pmlmepriv, _FW_LINKED); - if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) - || (rtw_to_roam(padapter) <= 0) - ) { - rtw_os_indicate_disconnect(padapter); + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) || rtw_to_roam(padapter) <= 0) { + /* Do it first for tx broadcast pkt after disconnection issue! */ + netif_carrier_off(padapter->pnetdev); + + rtw_cfg80211_indicate_disconnect(padapter); + + /* modify for CONFIG_IEEE80211W, none 11w also can use the same command */ + rtw_reset_securitypriv_cmd(padapter); /* set ips_deny_time to avoid enter IPS before LPS leave */ rtw_set_ips_deny(padapter, 3000); diff --git a/drivers/staging/rtl8723bs/include/mlme_osdep.h b/drivers/staging/rtl8723bs/include/mlme_osdep.h index 00c0a44c125a..8e8b5de285dc 100644 --- a/drivers/staging/rtl8723bs/include/mlme_osdep.h +++ b/drivers/staging/rtl8723bs/include/mlme_osdep.h @@ -8,7 +8,6 @@ #define __MLME_OSDEP_H_ -extern void rtw_os_indicate_disconnect(struct adapter *adapter); extern void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie); void rtw_reset_securitypriv(struct adapter *adapter); diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c index 326acbd8dc84..d2f4855e9d9d 100644 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c @@ -66,18 +66,6 @@ void rtw_reset_securitypriv(struct adapter *adapter) spin_unlock_bh(&adapter->security_key_mutex); } -void rtw_os_indicate_disconnect(struct adapter *adapter) -{ - /* struct rt_pmkid_list backupPMKIDList[ NUM_PMKID_CACHE ]; */ - - netif_carrier_off(adapter->pnetdev); /* Do it first for tx broadcast pkt after disconnection issue! */ - - rtw_cfg80211_indicate_disconnect(adapter); - - /* modify for CONFIG_IEEE80211W, none 11w also can use the same command */ - rtw_reset_securitypriv_cmd(adapter); -} - void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie) { uint len; From 522440e4176a67339c2e9a9db2a5d87cd87e656f Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 1 Aug 2025 10:31:30 +0200 Subject: [PATCH 0014/2711] staging: rtl8723bs: move rtw_report_sec_ie to core/rtw_mlme.c Move the function rtw_report_sec_ie from os_dep/mlme_linux.c to core/rtw_mlme.c to reduce code in the os_dep directory. Signed-off-by: Michael Straube Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250801083131.82915-8-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme.c | 34 +++++++++++++++++++ .../staging/rtl8723bs/include/mlme_osdep.h | 2 -- drivers/staging/rtl8723bs/os_dep/mlme_linux.c | 34 ------------------- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index d0579cba3e32..5a5ca148ac8b 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -2034,6 +2034,40 @@ static int rtw_append_pmkid(struct adapter *Adapter, int iEntry, u8 *ie, uint ie return ie_len; } +static void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie) +{ + uint len; + u8 *buff, *p, i; + union iwreq_data wrqu; + + buff = NULL; + if (authmode == WLAN_EID_VENDOR_SPECIFIC) { + buff = rtw_zmalloc(IW_CUSTOM_MAX); + if (!buff) + return; + + p = buff; + + p += scnprintf(p, IW_CUSTOM_MAX - (p - buff), "ASSOCINFO(ReqIEs ="); + + len = sec_ie[1] + 2; + len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX; + + for (i = 0; i < len; i++) + p += scnprintf(p, IW_CUSTOM_MAX - (p - buff), "%02x", sec_ie[i]); + + p += scnprintf(p, IW_CUSTOM_MAX - (p - buff), ")"); + + memset(&wrqu, 0, sizeof(wrqu)); + + wrqu.data.length = p - buff; + + wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? wrqu.data.length : IW_CUSTOM_MAX; + + kfree(buff); + } +} + signed int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len) { u8 authmode = 0x0; diff --git a/drivers/staging/rtl8723bs/include/mlme_osdep.h b/drivers/staging/rtl8723bs/include/mlme_osdep.h index 8e8b5de285dc..3930d9e6dab7 100644 --- a/drivers/staging/rtl8723bs/include/mlme_osdep.h +++ b/drivers/staging/rtl8723bs/include/mlme_osdep.h @@ -8,8 +8,6 @@ #define __MLME_OSDEP_H_ -extern void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie); - void rtw_reset_securitypriv(struct adapter *adapter); #endif /* _MLME_OSDEP_H_ */ diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c index d2f4855e9d9d..918d9496d7cc 100644 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c @@ -65,37 +65,3 @@ void rtw_reset_securitypriv(struct adapter *adapter) /* add for CONFIG_IEEE80211W, none 11w also can use */ spin_unlock_bh(&adapter->security_key_mutex); } - -void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie) -{ - uint len; - u8 *buff, *p, i; - union iwreq_data wrqu; - - buff = NULL; - if (authmode == WLAN_EID_VENDOR_SPECIFIC) { - buff = rtw_zmalloc(IW_CUSTOM_MAX); - if (!buff) - return; - - p = buff; - - p += scnprintf(p, IW_CUSTOM_MAX - (p - buff), "ASSOCINFO(ReqIEs ="); - - len = sec_ie[1] + 2; - len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX; - - for (i = 0; i < len; i++) - p += scnprintf(p, IW_CUSTOM_MAX - (p - buff), "%02x", sec_ie[i]); - - p += scnprintf(p, IW_CUSTOM_MAX - (p - buff), ")"); - - memset(&wrqu, 0, sizeof(wrqu)); - - wrqu.data.length = p - buff; - - wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? wrqu.data.length : IW_CUSTOM_MAX; - - kfree(buff); - } -} From c158e7c293836f55a5cf1bc24f062573c13c5b1d Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 1 Aug 2025 10:31:31 +0200 Subject: [PATCH 0015/2711] staging: rtl8723bs: move rtw_reset_securitypriv to core/rtw_mlme.c Move the function rtw_reset_securitypriv from os_dep/mlme_linux.c to core/rtw_mlme.c to reduce code in the os_dep directory. The file os_dep/mlme_linux.c is finally empty now and we can remove it. Signed-off-by: Michael Straube Tested-by: Hans de Goede Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250801083131.82915-9-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/Makefile | 1 - drivers/staging/rtl8723bs/core/rtw_mlme.c | 60 +++++++++++++++++ drivers/staging/rtl8723bs/include/drv_types.h | 1 - .../staging/rtl8723bs/include/mlme_osdep.h | 13 ---- drivers/staging/rtl8723bs/include/rtw_mlme.h | 1 + drivers/staging/rtl8723bs/os_dep/mlme_linux.c | 67 ------------------- 6 files changed, 61 insertions(+), 82 deletions(-) delete mode 100644 drivers/staging/rtl8723bs/include/mlme_osdep.h delete mode 100644 drivers/staging/rtl8723bs/os_dep/mlme_linux.c diff --git a/drivers/staging/rtl8723bs/Makefile b/drivers/staging/rtl8723bs/Makefile index 8560b84a3146..19c0525ec3e0 100644 --- a/drivers/staging/rtl8723bs/Makefile +++ b/drivers/staging/rtl8723bs/Makefile @@ -48,7 +48,6 @@ r8723bs-y = \ hal/HalHWImg8723B_RF.o \ hal/HalPhyRf_8723B.o \ os_dep/ioctl_cfg80211.o \ - os_dep/mlme_linux.o \ os_dep/osdep_service.o \ os_dep/os_intfs.o \ os_dep/recv_linux.o \ diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index 5a5ca148ac8b..fdf06b5253a7 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -1118,6 +1118,66 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net rtw_update_ht_cap(padapter, cur_network->network.ies, cur_network->network.ie_length, (u8) cur_network->network.configuration.ds_config); } +static struct rt_pmkid_list backupPMKIDList[NUM_PMKID_CACHE]; +void rtw_reset_securitypriv(struct adapter *adapter) +{ + u8 backupPMKIDIndex = 0; + u8 backupTKIPCountermeasure = 0x00; + u32 backupTKIPcountermeasure_time = 0; + /* add for CONFIG_IEEE80211W, none 11w also can use */ + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + + spin_lock_bh(&adapter->security_key_mutex); + + if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { + /* 802.1x */ + /* Added by Albert 2009/02/18 */ + /* We have to backup the PMK information for WiFi PMK Caching test item. */ + /* */ + /* Backup the btkip_countermeasure information. */ + /* When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */ + + memcpy(&backupPMKIDList[0], &adapter->securitypriv.PMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); + backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; + backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure; + backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time; + + /* reset RX BIP packet number */ + pmlmeext->mgnt_80211w_IPN_rx = 0; + + memset((unsigned char *)&adapter->securitypriv, 0, sizeof(struct security_priv)); + + /* Added by Albert 2009/02/18 */ + /* Restore the PMK information to securitypriv structure for the following connection. */ + memcpy(&adapter->securitypriv.PMKIDList[0], &backupPMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); + adapter->securitypriv.PMKIDIndex = backupPMKIDIndex; + adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure; + adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time; + + adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; + adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; + + } else { + /* reset values in securitypriv */ + /* if (adapter->mlmepriv.fw_state & WIFI_STATION_STATE) */ + /* */ + struct security_priv *psec_priv = &adapter->securitypriv; + + psec_priv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ + psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_; + psec_priv->dot11PrivacyKeyIndex = 0; + + psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_; + psec_priv->dot118021XGrpKeyid = 1; + + psec_priv->ndisauthtype = Ndis802_11AuthModeOpen; + psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled; + /* */ + } + /* add for CONFIG_IEEE80211W, none 11w also can use */ + spin_unlock_bh(&adapter->security_key_mutex); +} + /* Notes: the function could be > passive_level (the same context as Rx tasklet) */ /* pnetwork : returns from rtw_joinbss_event_callback */ /* ptarget_wlan: found from scanned_queue */ diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h index 080c321665c0..f1c16ddacc83 100644 --- a/drivers/staging/rtl8723bs/include/drv_types.h +++ b/drivers/staging/rtl8723bs/include/drv_types.h @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/staging/rtl8723bs/include/mlme_osdep.h b/drivers/staging/rtl8723bs/include/mlme_osdep.h deleted file mode 100644 index 3930d9e6dab7..000000000000 --- a/drivers/staging/rtl8723bs/include/mlme_osdep.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __MLME_OSDEP_H_ -#define __MLME_OSDEP_H_ - - -void rtw_reset_securitypriv(struct adapter *adapter); - -#endif /* _MLME_OSDEP_H_ */ diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme.h b/drivers/staging/rtl8723bs/include/rtw_mlme.h index 3cf68b85eb32..4c15d0194d4f 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme.h @@ -395,5 +395,6 @@ u8 rtw_to_roam(struct adapter *adapter); int rtw_select_roaming_candidate(struct mlme_priv *pmlmepriv); void rtw_sta_media_status_rpt(struct adapter *adapter, struct sta_info *psta, u32 mstatus); +void rtw_reset_securitypriv(struct adapter *adapter); #endif /* __RTL871X_MLME_H_ */ diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c deleted file mode 100644 index 918d9496d7cc..000000000000 --- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * - * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#include - -static struct rt_pmkid_list backupPMKIDList[NUM_PMKID_CACHE]; -void rtw_reset_securitypriv(struct adapter *adapter) -{ - u8 backupPMKIDIndex = 0; - u8 backupTKIPCountermeasure = 0x00; - u32 backupTKIPcountermeasure_time = 0; - /* add for CONFIG_IEEE80211W, none 11w also can use */ - struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; - - spin_lock_bh(&adapter->security_key_mutex); - - if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { - /* 802.1x */ - /* Added by Albert 2009/02/18 */ - /* We have to backup the PMK information for WiFi PMK Caching test item. */ - /* */ - /* Backup the btkip_countermeasure information. */ - /* When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */ - - memcpy(&backupPMKIDList[0], &adapter->securitypriv.PMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); - backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; - backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure; - backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time; - - /* reset RX BIP packet number */ - pmlmeext->mgnt_80211w_IPN_rx = 0; - - memset((unsigned char *)&adapter->securitypriv, 0, sizeof(struct security_priv)); - - /* Added by Albert 2009/02/18 */ - /* Restore the PMK information to securitypriv structure for the following connection. */ - memcpy(&adapter->securitypriv.PMKIDList[0], &backupPMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); - adapter->securitypriv.PMKIDIndex = backupPMKIDIndex; - adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure; - adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time; - - adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; - adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; - - } else { - /* reset values in securitypriv */ - /* if (adapter->mlmepriv.fw_state & WIFI_STATION_STATE) */ - /* */ - struct security_priv *psec_priv = &adapter->securitypriv; - - psec_priv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ - psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_; - psec_priv->dot11PrivacyKeyIndex = 0; - - psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_; - psec_priv->dot118021XGrpKeyid = 1; - - psec_priv->ndisauthtype = Ndis802_11AuthModeOpen; - psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled; - /* */ - } - /* add for CONFIG_IEEE80211W, none 11w also can use */ - spin_unlock_bh(&adapter->security_key_mutex); -} From 498a14ce8e898eac7d55977625dc93c1e918e1d5 Mon Sep 17 00:00:00 2001 From: Jannik Rehkemper Date: Thu, 7 Aug 2025 20:54:37 +0200 Subject: [PATCH 0016/2711] staging: rtl8723bs: fix checkpatch spaces preferred around that Added spaces where prefered or required by the checkpatch.pl script to adhere codestyle. Signed-off-by: Jannik Rehkemper Link: https://lore.kernel.org/r/20250807185436.853318-2-jannik@jrehkemper.de Signed-off-by: Greg Kroah-Hartman --- .../staging/rtl8723bs/core/rtw_wlan_util.c | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index 0c6072d08661..1def9758852c 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -170,10 +170,10 @@ void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *bssrat void set_mcs_rate_by_mask(u8 *mcs_set, u32 mask) { - u8 mcs_rate_1r = (u8)(mask&0xff); - u8 mcs_rate_2r = (u8)((mask>>8)&0xff); - u8 mcs_rate_3r = (u8)((mask>>16)&0xff); - u8 mcs_rate_4r = (u8)((mask>>24)&0xff); + u8 mcs_rate_1r = (u8)(mask & 0xff); + u8 mcs_rate_2r = (u8)((mask >> 8) & 0xff); + u8 mcs_rate_3r = (u8)((mask >> 16) & 0xff); + u8 mcs_rate_4r = (u8)((mask >> 24) & 0xff); mcs_set[0] &= mcs_rate_1r; mcs_set[1] &= mcs_rate_2r; @@ -267,21 +267,21 @@ inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch) dvobj->on_oper_ch_time = jiffies; #ifdef DBG_CH_SWITCH - cnt += scnprintf(msg+cnt, len-cnt, "switch to ch %3u", ch); + cnt += scnprintf(msg + cnt, len - cnt, "switch to ch %3u", ch); for (i = 0; i < dvobj->iface_nums; i++) { struct adapter *iface = dvobj->padapters[i]; - cnt += scnprintf(msg+cnt, len-cnt, " [%s:", ADPT_ARG(iface)); + cnt += scnprintf(msg + cnt, len - cnt, " [%s:", ADPT_ARG(iface)); if (iface->mlmeextpriv.cur_channel == ch) - cnt += scnprintf(msg+cnt, len-cnt, "C"); + cnt += scnprintf(msg + cnt, len - cnt, "C"); else - cnt += scnprintf(msg+cnt, len-cnt, "_"); + cnt += scnprintf(msg + cnt, len - cnt, "_"); if (iface->wdinfo.listen_channel == ch && !rtw_p2p_chk_state(&iface->wdinfo, P2P_STATE_NONE)) - cnt += scnprintf(msg+cnt, len-cnt, "L"); + cnt += scnprintf(msg + cnt, len - cnt, "L"); else - cnt += scnprintf(msg+cnt, len-cnt, "_"); - cnt += scnprintf(msg+cnt, len-cnt, "]"); + cnt += scnprintf(msg + cnt, len - cnt, "_"); + cnt += scnprintf(msg + cnt, len - cnt, "]"); } #endif /* DBG_CH_SWITCH */ @@ -381,7 +381,7 @@ int is_client_associated_to_ap(struct adapter *padapter) pmlmeext = &padapter->mlmeextpriv; pmlmeinfo = &(pmlmeext->mlmext_info); - if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)) + if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE)) return true; else return _FAIL; @@ -392,7 +392,7 @@ int is_client_associated_to_ibss(struct adapter *padapter) struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) + if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) return true; else return _FAIL; @@ -431,7 +431,7 @@ void invalidate_cam_all(struct adapter *padapter) spin_lock_bh(&cam_ctl->lock); cam_ctl->bitmap = 0; - memset(dvobj->cam_cache, 0, sizeof(struct cam_entry_cache)*TOTAL_CAM_ENTRY); + memset(dvobj->cam_cache, 0, sizeof(struct cam_entry_cache) * TOTAL_CAM_ENTRY); spin_unlock_bh(&cam_ctl->lock); } @@ -453,7 +453,7 @@ void _write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key) break; default: i = (j - 2) << 2; - val = (key[i] | (key[i+1] << 8) | (key[i+2] << 16) | (key[i+3] << 24)); + val = (key[i] | (key[i + 1] << 8) | (key[i + 2] << 16) | (key[i + 3] << 24)); break; } @@ -522,7 +522,7 @@ static bool _rtw_camid_is_gk(struct adapter *adapter, u8 cam_id) if (!(cam_ctl->bitmap & BIT(cam_id))) goto exit; - ret = (dvobj->cam_cache[cam_id].ctrl&BIT6)?true:false; + ret = (dvobj->cam_cache[cam_id].ctrl & BIT6) ? true : false; exit: return ret; @@ -537,7 +537,7 @@ static s16 _rtw_camid_search(struct adapter *adapter, u8 *addr, s16 kid) for (i = 0; i < TOTAL_CAM_ENTRY; i++) { if (addr && memcmp(dvobj->cam_cache[i].mac, addr, ETH_ALEN)) continue; - if (kid >= 0 && kid != (dvobj->cam_cache[i].ctrl&0x03)) + if (kid >= 0 && kid != (dvobj->cam_cache[i].ctrl & 0x03)) continue; cam_id = i; @@ -571,7 +571,7 @@ s16 rtw_camid_alloc(struct adapter *adapter, struct sta_info *sta, u8 kid) mlmeinfo = &adapter->mlmeextpriv.mlmext_info; - if ((((mlmeinfo->state&0x03) == WIFI_FW_AP_STATE) || ((mlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) + if ((((mlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) || ((mlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) && !sta) { /* AP/Ad-hoc mode group key: static alloction to default key by key ID */ if (kid > 3) { @@ -585,7 +585,7 @@ s16 rtw_camid_alloc(struct adapter *adapter, struct sta_info *sta, u8 kid) cam_id = kid; } else { int i; - u8 *addr = sta?sta->hwaddr:NULL; + u8 *addr = sta ? sta->hwaddr : NULL; if (!sta) { if (!(mlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { @@ -792,7 +792,7 @@ void WMMOnAssocRsp(struct adapter *padapter) switch (ACI) { case 0x0: rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); - acm_mask |= (ACM ? BIT(1):0); + acm_mask |= (ACM ? BIT(1) : 0); edca[XMIT_BE_QUEUE] = acParm; break; @@ -804,13 +804,13 @@ void WMMOnAssocRsp(struct adapter *padapter) case 0x2: rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); - acm_mask |= (ACM ? BIT(2):0); + acm_mask |= (ACM ? BIT(2) : 0); edca[XMIT_VI_QUEUE] = acParm; break; case 0x3: rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); - acm_mask |= (ACM ? BIT(3):0); + acm_mask |= (ACM ? BIT(3) : 0); edca[XMIT_VO_QUEUE] = acParm; break; } @@ -1170,7 +1170,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) ht_info_infos_0 = 0; } if (ht_cap_info != cur_network->bcn_info.ht_cap_info || - ((ht_info_infos_0&0x03) != (cur_network->bcn_info.ht_info_infos_0&0x03))) { + ((ht_info_infos_0 & 0x03) != (cur_network->bcn_info.ht_info_infos_0 & 0x03))) { { /* bcn_info_update */ cur_network->bcn_info.ht_cap_info = ht_cap_info; @@ -1238,12 +1238,12 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) goto _mismatch; if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) { - pbuf = rtw_get_wpa_ie(&bssid->ies[12], &wpa_ielen, bssid->ie_length-12); + pbuf = rtw_get_wpa_ie(&bssid->ies[12], &wpa_ielen, bssid->ie_length - 12); if (pbuf && (wpa_ielen > 0)) { rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is_8021x); } else { - pbuf = rtw_get_wpa2_ie(&bssid->ies[12], &wpa_ielen, bssid->ie_length-12); + pbuf = rtw_get_wpa2_ie(&bssid->ies[12], &wpa_ielen, bssid->ie_length - 12); if (pbuf && (wpa_ielen > 0)) rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, @@ -1630,7 +1630,7 @@ void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr) if (psta) { param = le16_to_cpu(preq->BA_para_set); - tid = (param>>2)&0x0f; + tid = (param >> 2) & 0x0f; preorder_ctrl = &psta->recvreorder_ctrl[tid]; @@ -1648,7 +1648,7 @@ void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) pIE = pframe + sizeof(struct ieee80211_hdr_3addr); pbuf = (__le32 *)pIE; - pmlmeext->TSFValue = le32_to_cpu(*(pbuf+1)); + pmlmeext->TSFValue = le32_to_cpu(*(pbuf + 1)); pmlmeext->TSFValue = pmlmeext->TSFValue << 32; @@ -1674,14 +1674,14 @@ void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) pIE = pframe + sizeof(struct ieee80211_hdr_3addr); pbuf = (__le32 *)pIE; - tsf = le32_to_cpu(*(pbuf+1)); + tsf = le32_to_cpu(*(pbuf + 1)); tsf = tsf << 32; tsf |= le32_to_cpu(*pbuf); /* delay = (timestamp mod 1024*100)/1000 (unit: ms) */ /* delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval*1024))/1000; */ - delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval*1024)); - delay_ms = delay_ms/1000; + delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval * 1024)); + delay_ms = delay_ms / 1000; if (delay_ms >= 8) pmlmeext->bcn_delay_cnt[8]++; From 5f5743e5b599bafe2ec5df2d33f616217a778135 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Fri, 8 Aug 2025 23:48:30 +0300 Subject: [PATCH 0017/2711] staging: axis-fifo: remove unnecessary dev_set_drvdata() calls Remove unnecessary dev_set_drvdata() calls - driver_data will be set to NULL in device_unbind_cleanup() at driver exit time. This allows us to remove the 'err_initial' label, simplifying the probe function a bit. Signed-off-by: Ovidiu Panait Link: https://lore.kernel.org/r/20250808204831.2618122-1-ovidiu.panait.oss@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/axis-fifo/axis-fifo.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index 57ed58065eba..06f7cfab4c6a 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -693,10 +693,8 @@ static int axis_fifo_probe(struct platform_device *pdev) /* get iospace for the device and request physical memory */ fifo->base_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &r_mem); - if (IS_ERR(fifo->base_addr)) { - rc = PTR_ERR(fifo->base_addr); - goto err_initial; - } + if (IS_ERR(fifo->base_addr)) + return PTR_ERR(fifo->base_addr); dev_dbg(fifo->dt_device, "remapped memory to 0x%p\n", fifo->base_addr); @@ -711,7 +709,7 @@ static int axis_fifo_probe(struct platform_device *pdev) rc = axis_fifo_parse_dt(fifo); if (rc) - goto err_initial; + return rc; reset_ip_core(fifo); @@ -723,7 +721,7 @@ static int axis_fifo_probe(struct platform_device *pdev) /* get IRQ resource */ rc = platform_get_irq(pdev, 0); if (rc < 0) - goto err_initial; + return rc; /* request IRQ */ fifo->irq = rc; @@ -732,7 +730,7 @@ static int axis_fifo_probe(struct platform_device *pdev) if (rc) { dev_err(fifo->dt_device, "couldn't allocate interrupt %i\n", fifo->irq); - goto err_initial; + return rc; } /* ---------------------------- @@ -747,15 +745,11 @@ static int axis_fifo_probe(struct platform_device *pdev) fifo->miscdev.parent = dev; rc = misc_register(&fifo->miscdev); if (rc < 0) - goto err_initial; + return rc; axis_fifo_debugfs_init(fifo); return 0; - -err_initial: - dev_set_drvdata(dev, NULL); - return rc; } static void axis_fifo_remove(struct platform_device *pdev) @@ -765,7 +759,6 @@ static void axis_fifo_remove(struct platform_device *pdev) debugfs_remove(fifo->debugfs_dir); misc_deregister(&fifo->miscdev); - dev_set_drvdata(dev, NULL); } static const struct of_device_id axis_fifo_of_match[] = { From dced755df3bc49e417ee4de45eec89bf5570b192 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 31 Jul 2025 12:25:44 -0700 Subject: [PATCH 0018/2711] thunderbolt: Compare HMAC values in constant time To prevent timing attacks, HMAC value comparison needs to be constant time. Replace the memcmp() with the correct function, crypto_memneq(). Fixes: f67cf491175a ("thunderbolt: Add support for Internal Connection Manager (ICM)") Signed-off-by: Eric Biggers Signed-off-by: Mika Westerberg --- drivers/thunderbolt/domain.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c index 45239703745e..7e0eb3c07f1c 100644 --- a/drivers/thunderbolt/domain.c +++ b/drivers/thunderbolt/domain.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "tb.h" @@ -748,7 +749,7 @@ int tb_domain_challenge_switch_key(struct tb *tb, struct tb_switch *sw) goto err_free_shash; /* The returned HMAC must match the one we calculated */ - if (memcmp(response, hmac, sizeof(hmac))) { + if (crypto_memneq(response, hmac, sizeof(hmac))) { ret = -EKEYREJECTED; goto err_free_shash; } From 0eff12ce88e1e77c465cbaa22d450fd268cd9b74 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 31 Jul 2025 12:25:45 -0700 Subject: [PATCH 0019/2711] thunderbolt: Use HMAC-SHA256 library instead of crypto_shash Use the hmac_sha256_usingrawkey() library function instead of the "hmac(sha256)" crypto_shash. This is simpler and faster. As a cleanup, change the input data parameters from "challenge, sizeof(hmac)" to "challenge, sizeof(challenge)", so that the size is being taken of the correct buffer. This is not a functional change, since it happens that sizeof(hmac) == sizeof(challenge). Replace the selection of CRYPTO and CRYPTO_HASH with CRYPTO_LIB_SHA256 and CRYPTO_LIB_UTILS. The latter is needed for crypto_memneq() which was previously being pulled in via CRYPTO. Signed-off-by: Eric Biggers Signed-off-by: Mika Westerberg --- drivers/thunderbolt/Kconfig | 4 ++-- drivers/thunderbolt/domain.c | 44 +++++------------------------------- 2 files changed, 8 insertions(+), 40 deletions(-) diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig index 0abdb69ee9f4..db3b0bef48f4 100644 --- a/drivers/thunderbolt/Kconfig +++ b/drivers/thunderbolt/Kconfig @@ -4,8 +4,8 @@ menuconfig USB4 depends on PCI select APPLE_PROPERTIES if EFI_STUB && X86 select CRC32 - select CRYPTO - select CRYPTO_HASH + select CRYPTO_LIB_SHA256 + select CRYPTO_LIB_UTILS select NVMEM help USB4 and Thunderbolt driver. USB4 is the public specification diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c index 7e0eb3c07f1c..5272c255e046 100644 --- a/drivers/thunderbolt/domain.c +++ b/drivers/thunderbolt/domain.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include "tb.h" @@ -709,8 +709,6 @@ int tb_domain_challenge_switch_key(struct tb *tb, struct tb_switch *sw) u8 response[TB_SWITCH_KEY_SIZE]; u8 hmac[TB_SWITCH_KEY_SIZE]; struct tb_switch *parent_sw; - struct crypto_shash *tfm; - struct shash_desc *shash; int ret; if (!tb->cm_ops->approve_switch || !tb->cm_ops->challenge_switch_key) @@ -726,45 +724,15 @@ int tb_domain_challenge_switch_key(struct tb *tb, struct tb_switch *sw) if (ret) return ret; - tfm = crypto_alloc_shash("hmac(sha256)", 0, 0); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); - - ret = crypto_shash_setkey(tfm, sw->key, TB_SWITCH_KEY_SIZE); - if (ret) - goto err_free_tfm; - - shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm), - GFP_KERNEL); - if (!shash) { - ret = -ENOMEM; - goto err_free_tfm; - } - - shash->tfm = tfm; - - memset(hmac, 0, sizeof(hmac)); - ret = crypto_shash_digest(shash, challenge, sizeof(hmac), hmac); - if (ret) - goto err_free_shash; + static_assert(sizeof(hmac) == SHA256_DIGEST_SIZE); + hmac_sha256_usingrawkey(sw->key, TB_SWITCH_KEY_SIZE, + challenge, sizeof(challenge), hmac); /* The returned HMAC must match the one we calculated */ - if (crypto_memneq(response, hmac, sizeof(hmac))) { - ret = -EKEYREJECTED; - goto err_free_shash; - } - - crypto_free_shash(tfm); - kfree(shash); + if (crypto_memneq(response, hmac, sizeof(hmac))) + return -EKEYREJECTED; return tb->cm_ops->approve_switch(tb, sw); - -err_free_shash: - kfree(shash); -err_free_tfm: - crypto_free_shash(tfm); - - return ret; } /** From add7b05aeeb417c86239e6731a168e6c46b83279 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Tue, 22 Jul 2025 17:11:49 +0800 Subject: [PATCH 0020/2711] PCI: qcom: Select PCI Power Control Slot driver Select the pwrctrl driver, which is utilized to manage the power supplies of the devices connected to the standard PCI slots conforming to specification like PCIe CEM. This ensures that the voltage rails of the standard PCI slots on some platforms eg. X1E80100-QCP can be correctly turned on/off if they are described in PCIe Root Port device tree node. Signed-off-by: Qiang Yu Signed-off-by: Wenbin Yao [mani: reworded subject and description] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250722091151.1423332-2-quic_wenbyao@quicinc.com --- drivers/pci/controller/dwc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index ff6b6d9e18ec..deafc512b079 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -298,6 +298,7 @@ config PCIE_QCOM select CRC8 select PCIE_QCOM_COMMON select PCI_HOST_COMMON + select PCI_PWRCTRL_SLOT help Say Y here to enable PCIe controller support on Qualcomm SoCs. The PCIe controller uses the DesignWare core plus Qualcomm-specific From d96ac5bdc52b271b4f8ac0670a203913666b8758 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Aug 2025 21:25:18 +0200 Subject: [PATCH 0021/2711] PCI: rcar-gen4: Fix PHY initialization R-Car V4H Reference Manual R19UH0186EJ0130 Rev.1.30 Apr. 21, 2025 page 4581 Figure 104.3b Initial Setting of PCIEC(example), middle of the figure indicates that fourth write into register 0x148 [2:0] is 0x3 or GENMASK(1, 0). The current code writes GENMASK(11, 0) which is a typo. Fix the typo. Fixes: faf5a975ee3b ("PCI: rcar-gen4: Add support for R-Car V4H") Signed-off-by: Marek Vasut Signed-off-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250806192548.133140-1-marek.vasut+renesas@mailbox.org --- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index 18055807a4f5..366e21bffcbe 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -701,7 +701,7 @@ static int rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(23, 22), BIT(22)); rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(18, 16), GENMASK(17, 16)); rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(7, 6), BIT(6)); - rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(2, 0), GENMASK(11, 0)); + rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(2, 0), GENMASK(1, 0)); rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x1d4, GENMASK(16, 15), GENMASK(16, 15)); rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x514, BIT(26), BIT(26)); rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x0f8, BIT(16), 0); From 0b9275edc3543d0d2d03313a7c8de5157d61b189 Mon Sep 17 00:00:00 2001 From: Sai Krishna Musham Date: Thu, 7 Aug 2025 13:10:18 +0530 Subject: [PATCH 0022/2711] dt-bindings: PCI: amd-mdb: Add example usage of reset-gpios for PCIe RP PERST# Update the device tree binding example to include usage of the `reset-gpios` property in PCIe Root Port (RP) bridge node for PERST# signal handling. Signed-off-by: Sai Krishna Musham Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250807074019.811672-2-sai.krishna.musham@amd.com --- .../bindings/pci/amd,versal2-mdb-host.yaml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/amd,versal2-mdb-host.yaml b/Documentation/devicetree/bindings/pci/amd,versal2-mdb-host.yaml index 43dc2585c237..421e1116ae7e 100644 --- a/Documentation/devicetree/bindings/pci/amd,versal2-mdb-host.yaml +++ b/Documentation/devicetree/bindings/pci/amd,versal2-mdb-host.yaml @@ -71,6 +71,17 @@ properties: - "#address-cells" - "#interrupt-cells" +patternProperties: + '^pcie@[0-2],0$': + type: object + $ref: /schemas/pci/pci-pci-bridge.yaml# + + properties: + reg: + maxItems: 1 + + unevaluatedProperties: false + required: - reg - reg-names @@ -87,6 +98,7 @@ examples: - | #include #include + #include soc { #address-cells = <2>; @@ -112,6 +124,16 @@ examples: #size-cells = <2>; #interrupt-cells = <1>; device_type = "pci"; + + pcie@0,0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + reset-gpios = <&tca6416_u37 7 GPIO_ACTIVE_LOW>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + }; + pcie_intc_0: interrupt-controller { #address-cells = <0>; #interrupt-cells = <1>; From 1d0156c8b230ca74272708a3206684e6d6157302 Mon Sep 17 00:00:00 2001 From: Sai Krishna Musham Date: Thu, 7 Aug 2025 13:10:19 +0530 Subject: [PATCH 0023/2711] PCI: amd-mdb: Add support for PCIe RP PERST# signal handling Add support for handling the AMD Versal Gen 2 MDB PCIe Root Port PERST# signal via a GPIO by parsing the new PCIe bridge node to acquire the reset GPIO. If the bridge node is not found, fall back to acquiring it from the PCIe host bridge node. As part of this, update the interrupt controller node parsing to use of_get_child_by_name() instead of of_get_next_child(), since the PCIe host bridge node now has multiple children. This ensures the correct node is selected during initialization. Signed-off-by: Sai Krishna Musham Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250807074019.811672-3-sai.krishna.musham@amd.com --- drivers/pci/controller/dwc/pcie-amd-mdb.c | 52 ++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-amd-mdb.c b/drivers/pci/controller/dwc/pcie-amd-mdb.c index 9f7251a16d32..3c6e837465bb 100644 --- a/drivers/pci/controller/dwc/pcie-amd-mdb.c +++ b/drivers/pci/controller/dwc/pcie-amd-mdb.c @@ -18,6 +18,7 @@ #include #include +#include "../../pci.h" #include "pcie-designware.h" #define AMD_MDB_TLP_IR_STATUS_MISC 0x4C0 @@ -56,6 +57,7 @@ * @slcr: MDB System Level Control and Status Register (SLCR) base * @intx_domain: INTx IRQ domain pointer * @mdb_domain: MDB IRQ domain pointer + * @perst_gpio: GPIO descriptor for PERST# signal handling * @intx_irq: INTx IRQ interrupt number */ struct amd_mdb_pcie { @@ -63,6 +65,7 @@ struct amd_mdb_pcie { void __iomem *slcr; struct irq_domain *intx_domain; struct irq_domain *mdb_domain; + struct gpio_desc *perst_gpio; int intx_irq; }; @@ -284,7 +287,7 @@ static int amd_mdb_pcie_init_irq_domains(struct amd_mdb_pcie *pcie, struct device_node *pcie_intc_node; int err; - pcie_intc_node = of_get_next_child(node, NULL); + pcie_intc_node = of_get_child_by_name(node, "interrupt-controller"); if (!pcie_intc_node) { dev_err(dev, "No PCIe Intc node found\n"); return -ENODEV; @@ -402,6 +405,28 @@ static int amd_mdb_setup_irq(struct amd_mdb_pcie *pcie, return 0; } +static int amd_mdb_parse_pcie_port(struct amd_mdb_pcie *pcie) +{ + struct device *dev = pcie->pci.dev; + struct device_node *pcie_port_node __maybe_unused; + + /* + * This platform currently supports only one Root Port, so the loop + * will execute only once. + * TODO: Enhance the driver to handle multiple Root Ports in the future. + */ + for_each_child_of_node_with_prefix(dev->of_node, pcie_port_node, "pcie") { + pcie->perst_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(pcie_port_node), + "reset", GPIOD_OUT_HIGH, NULL); + if (IS_ERR(pcie->perst_gpio)) + return dev_err_probe(dev, PTR_ERR(pcie->perst_gpio), + "Failed to request reset GPIO\n"); + return 0; + } + + return -ENODEV; +} + static int amd_mdb_add_pcie_port(struct amd_mdb_pcie *pcie, struct platform_device *pdev) { @@ -426,6 +451,12 @@ static int amd_mdb_add_pcie_port(struct amd_mdb_pcie *pcie, pp->ops = &amd_mdb_pcie_host_ops; + if (pcie->perst_gpio) { + mdelay(PCIE_T_PVPERL_MS); + gpiod_set_value_cansleep(pcie->perst_gpio, 0); + mdelay(PCIE_RESET_CONFIG_WAIT_MS); + } + err = dw_pcie_host_init(pp); if (err) { dev_err(dev, "Failed to initialize host, err=%d\n", err); @@ -444,6 +475,7 @@ static int amd_mdb_pcie_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct amd_mdb_pcie *pcie; struct dw_pcie *pci; + int ret; pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) @@ -454,6 +486,24 @@ static int amd_mdb_pcie_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pcie); + ret = amd_mdb_parse_pcie_port(pcie); + /* + * If amd_mdb_parse_pcie_port returns -ENODEV, it indicates that the + * PCIe Bridge node was not found in the device tree. This is not + * considered a fatal error and will trigger a fallback where the + * reset GPIO is acquired directly from the PCIe Host Bridge node. + */ + if (ret) { + if (ret != -ENODEV) + return ret; + + pcie->perst_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(pcie->perst_gpio)) + return dev_err_probe(dev, PTR_ERR(pcie->perst_gpio), + "Failed to request reset GPIO\n"); + } + return amd_mdb_add_pcie_port(pcie, pdev); } From 57a75fa9d56e310e883e4377205690e88c05781b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 1 Aug 2025 16:34:45 +0300 Subject: [PATCH 0024/2711] PCI: endpoint: pci-ep-msi: Fix NULL vs IS_ERR() check in pci_epf_write_msi_msg() The pci_epc_get() function returns error pointers. It never returns NULL. Update the check to match. Fixes: 1c3b002c6bf6 ("PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller") Signed-off-by: Dan Carpenter Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Link: https://patch.msgid.link/aIzCdV8jyBeql-Oa@stanley.mountain --- drivers/pci/endpoint/pci-ep-msi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c index 9ca89cbfec15..1b58357b905f 100644 --- a/drivers/pci/endpoint/pci-ep-msi.c +++ b/drivers/pci/endpoint/pci-ep-msi.c @@ -24,7 +24,7 @@ static void pci_epf_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg) struct pci_epf *epf; epc = pci_epc_get(dev_name(msi_desc_to_dev(desc))); - if (!epc) + if (IS_ERR(epc)) return; epf = list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list); From b26fc701a25195134ff0327709a0421767c4c7b2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 1 Aug 2025 16:34:37 +0300 Subject: [PATCH 0025/2711] PCI: xgene-msi: Return negative -EINVAL in xgene_msi_handler_setup() There is a typo so we accidentally return positive EINVAL instead of negative -EINVAL. Add the missing '-' character. Fixes: 6aceb36f17ab ("PCI: xgene-msi: Restructure handler setup/teardown") Signed-off-by: Dan Carpenter Signed-off-by: Manivannan Sadhasivam Acked-by: Marc Zyngier Link: https://patch.msgid.link/aIzCbVd93ivPinne@stanley.mountain --- drivers/pci/controller/pci-xgene-msi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pci-xgene-msi.c b/drivers/pci/controller/pci-xgene-msi.c index 0a37a3f1809c..654639bccd10 100644 --- a/drivers/pci/controller/pci-xgene-msi.c +++ b/drivers/pci/controller/pci-xgene-msi.c @@ -311,7 +311,7 @@ static int xgene_msi_handler_setup(struct platform_device *pdev) msi_val = xgene_msi_int_read(xgene_msi, i); if (msi_val) { dev_err(&pdev->dev, "Failed to clear spurious IRQ\n"); - return EINVAL; + return -EINVAL; } irq = platform_get_irq(pdev, i); From 1ccc2e20fe1d3b91395de8ca9ce0efe070287534 Mon Sep 17 00:00:00 2001 From: Darshan Rathod Date: Fri, 1 Aug 2025 16:17:05 +0530 Subject: [PATCH 0026/2711] platform/x86: dell_rbu: fix assignment in if condition warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor to remove assignments from inside if conditions, as required by kernel coding style. This improves code readability and resolves checkpatch.pl warnings: ERROR: do not use assignment in if condition Signed-off-by: Darshan Rathod Link: https://lore.kernel.org/r/20250801104705.1824495-1-darshanrathod475@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/dell/dell_rbu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c index 2a140d1c656a..403df9bd9522 100644 --- a/drivers/platform/x86/dell/dell_rbu.c +++ b/drivers/platform/x86/dell/dell_rbu.c @@ -232,7 +232,8 @@ static int packetize_data(const u8 *data, size_t length) done = 1; } - if ((rc = create_packet(temp, packet_length))) + rc = create_packet(temp, packet_length); + if (rc) return rc; pr_debug("%p:%td\n", temp, (end - temp)); @@ -276,7 +277,7 @@ static int do_packet_read(char *data, struct packet_data *newpacket, return bytes_copied; } -static int packet_read_list(char *data, size_t * pread_length) +static int packet_read_list(char *data, size_t *pread_length) { struct packet_data *newpacket; int temp_count = 0; @@ -445,7 +446,8 @@ static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) bytes_left = rbu_data.imagesize - pos; data_length = min(bytes_left, count); - if ((retval = packet_read_list(ptempBuf, &data_length)) < 0) + retval = packet_read_list(ptempBuf, &data_length); + if (retval < 0) goto read_rbu_data_exit; if ((pos + count) > rbu_data.imagesize) { From 3bffbe0497f9e3c7d80f22d9d0f60c984d42ab6d Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 29 Jul 2025 11:16:31 +0800 Subject: [PATCH 0027/2711] platform/x86: wmi-capdata01: Remove unneeded semicolon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecessary semicolons reported by Coccinelle/coccicheck and the semantic patch at scripts/coccinelle/misc/semicolon.cocci. Signed-off-by: Chen Ni Link: https://lore.kernel.org/r/20250729031631.1644740-1-nichen@iscas.ac.cn Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/lenovo/wmi-capdata01.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/lenovo/wmi-capdata01.c b/drivers/platform/x86/lenovo/wmi-capdata01.c index c922680b3cba..fc7e3454e71d 100644 --- a/drivers/platform/x86/lenovo/wmi-capdata01.c +++ b/drivers/platform/x86/lenovo/wmi-capdata01.c @@ -93,7 +93,7 @@ int lwmi_cd01_get_data(struct cd01_list *list, u32 attribute_id, struct capdata0 continue; memcpy(output, &list->data[idx], sizeof(list->data[idx])); return 0; - }; + } return -EINVAL; } From 5bf83c54bab5eb15a2749c6c52b6f96d425490bc Mon Sep 17 00:00:00 2001 From: Sricharan Ramabadhran Date: Mon, 11 Aug 2025 14:39:52 +0530 Subject: [PATCH 0028/2711] clk: qcom: apss-ipq5424: Add ipq5424 apss clock controller CPU on Qualcomm ipq5424 is clocked by huayra PLL with RCG support. Add support for the APSS PLL, RCG and clock enable for ipq5424. The PLL, RCG register space are clubbed. Hence adding new APSS driver for both PLL and RCG/CBC control. Also the L3 cache has a separate pll and needs to be scaled along with the CPU and is modeled as an ICC clock. [ Removed clock notifier, moved L3 pll to icc-clk, used existing alpha pll structure ] Co-developed-by: Md Sadre Alam Signed-off-by: Md Sadre Alam Signed-off-by: Sricharan Ramabadhran Signed-off-by: Varadarajan Narayanan Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250811090954.2854440-3-quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 9 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/apss-ipq5424.c | 265 ++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 drivers/clk/qcom/apss-ipq5424.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 6cb6cd3e1778..aeb6197d7c90 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -187,6 +187,15 @@ config IPQ_APSS_PLL Say Y if you want to support CPU frequency scaling on ipq based devices. +config IPQ_APSS_5424 + tristate "IPQ APSS Clock Controller" + select IPQ_APSS_PLL + default y if IPQ_GCC_5424 + help + Support for APSS Clock controller on Qualcom IPQ5424 platform. + Say Y if you want to support CPU frequency scaling on ipq based + devices. + config IPQ_APSS_6018 tristate "IPQ APSS Clock Controller" select IPQ_APSS_PLL diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index ddb7e06fae40..98de55eb6402 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_CLK_X1E80100_TCSRCC) += tcsrcc-x1e80100.o obj-$(CONFIG_CLK_X1P42100_GPUCC) += gpucc-x1p42100.o obj-$(CONFIG_CLK_QCM2290_GPUCC) += gpucc-qcm2290.o obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o +obj-$(CONFIG_IPQ_APSS_5424) += apss-ipq5424.o obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o obj-$(CONFIG_IPQ_CMN_PLL) += ipq-cmn-pll.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o diff --git a/drivers/clk/qcom/apss-ipq5424.c b/drivers/clk/qcom/apss-ipq5424.c new file mode 100644 index 000000000000..4c67f722e009 --- /dev/null +++ b/drivers/clk/qcom/apss-ipq5424.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "common.h" + +enum { + DT_XO, + DT_CLK_REF, +}; + +enum { + P_XO, + P_GPLL0, + P_APSS_PLL_EARLY, + P_L3_PLL, +}; + +struct apss_clk { + struct notifier_block cpu_clk_notifier; + struct clk_hw *hw; + struct device *dev; + struct clk *l3_clk; +}; + +static const struct alpha_pll_config apss_pll_config = { + .l = 0x3b, + .config_ctl_val = 0x08200920, + .config_ctl_hi_val = 0x05008001, + .config_ctl_hi1_val = 0x04000000, + .user_ctl_val = 0xf, +}; + +static struct clk_alpha_pll ipq5424_apss_pll = { + .offset = 0x0, + .config = &apss_pll_config, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_HUAYRA_2290], + .flags = SUPPORTS_DYNAMIC_UPDATE, + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "apss_pll", + .parent_data = &(const struct clk_parent_data) { + .index = DT_XO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_huayra_ops, + }, + }, +}; + +static const struct clk_parent_data parents_apss_silver_clk_src[] = { + { .index = DT_XO }, + { .index = DT_CLK_REF }, + { .hw = &ipq5424_apss_pll.clkr.hw }, +}; + +static const struct parent_map parents_apss_silver_clk_src_map[] = { + { P_XO, 0 }, + { P_GPLL0, 4 }, + { P_APSS_PLL_EARLY, 5 }, +}; + +static const struct freq_tbl ftbl_apss_clk_src[] = { + F(816000000, P_APSS_PLL_EARLY, 1, 0, 0), + F(1416000000, P_APSS_PLL_EARLY, 1, 0, 0), + F(1800000000, P_APSS_PLL_EARLY, 1, 0, 0), + { } +}; + +static struct clk_rcg2 apss_silver_clk_src = { + .cmd_rcgr = 0x0080, + .freq_tbl = ftbl_apss_clk_src, + .hid_width = 5, + .parent_map = parents_apss_silver_clk_src_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "apss_silver_clk_src", + .parent_data = parents_apss_silver_clk_src, + .num_parents = ARRAY_SIZE(parents_apss_silver_clk_src), + .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_branch apss_silver_core_clk = { + .halt_reg = 0x008c, + .clkr = { + .enable_reg = 0x008c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "apss_silver_core_clk", + .parent_hws = (const struct clk_hw *[]) { + &apss_silver_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct alpha_pll_config l3_pll_config = { + .l = 0x29, + .config_ctl_val = 0x08200920, + .config_ctl_hi_val = 0x05008001, + .config_ctl_hi1_val = 0x04000000, + .user_ctl_val = 0xf, +}; + +static struct clk_alpha_pll ipq5424_l3_pll = { + .offset = 0x10000, + .config = &l3_pll_config, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_HUAYRA_2290], + .flags = SUPPORTS_DYNAMIC_UPDATE, + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "l3_pll", + .parent_data = &(const struct clk_parent_data) { + .index = DT_XO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_huayra_ops, + }, + }, +}; + +static const struct clk_parent_data parents_l3_clk_src[] = { + { .index = DT_XO }, + { .index = DT_CLK_REF }, + { .hw = &ipq5424_l3_pll.clkr.hw }, +}; + +static const struct parent_map parents_l3_clk_src_map[] = { + { P_XO, 0 }, + { P_GPLL0, 4 }, + { P_L3_PLL, 5 }, +}; + +static const struct freq_tbl ftbl_l3_clk_src[] = { + F(816000000, P_L3_PLL, 1, 0, 0), + F(984000000, P_L3_PLL, 1, 0, 0), + F(1272000000, P_L3_PLL, 1, 0, 0), + { } +}; + +static struct clk_rcg2 l3_clk_src = { + .cmd_rcgr = 0x10080, + .freq_tbl = ftbl_l3_clk_src, + .hid_width = 5, + .parent_map = parents_l3_clk_src_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "l3_clk_src", + .parent_data = parents_l3_clk_src, + .num_parents = ARRAY_SIZE(parents_l3_clk_src), + .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_branch l3_core_clk = { + .halt_reg = 0x1008c, + .clkr = { + .enable_reg = 0x1008c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "l3_clk", + .parent_hws = (const struct clk_hw *[]) { + &l3_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct regmap_config apss_ipq5424_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x20000, + .fast_io = true, +}; + +static struct clk_regmap *apss_ipq5424_clks[] = { + [APSS_PLL_EARLY] = &ipq5424_apss_pll.clkr, + [APSS_SILVER_CLK_SRC] = &apss_silver_clk_src.clkr, + [APSS_SILVER_CORE_CLK] = &apss_silver_core_clk.clkr, + [L3_PLL] = &ipq5424_l3_pll.clkr, + [L3_CLK_SRC] = &l3_clk_src.clkr, + [L3_CORE_CLK] = &l3_core_clk.clkr, +}; + +static struct clk_alpha_pll *ipa5424_apss_plls[] = { + &ipq5424_l3_pll, + &ipq5424_apss_pll, +}; + +static struct qcom_cc_driver_data ipa5424_apss_driver_data = { + .alpha_plls = ipa5424_apss_plls, + .num_alpha_plls = ARRAY_SIZE(ipa5424_apss_plls), +}; + +#define IPQ_APPS_PLL_ID (5424 * 3) /* some unique value */ + +static const struct qcom_icc_hws_data icc_ipq5424_cpu_l3[] = { + { MASTER_CPU, SLAVE_L3, L3_CORE_CLK }, +}; + +static const struct qcom_cc_desc apss_ipq5424_desc = { + .config = &apss_ipq5424_regmap_config, + .clks = apss_ipq5424_clks, + .num_clks = ARRAY_SIZE(apss_ipq5424_clks), + .icc_hws = icc_ipq5424_cpu_l3, + .num_icc_hws = ARRAY_SIZE(icc_ipq5424_cpu_l3), + .icc_first_node_id = IPQ_APPS_PLL_ID, + .driver_data = &ipa5424_apss_driver_data, +}; + +static int apss_ipq5424_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &apss_ipq5424_desc); +} + +static const struct of_device_id apss_ipq5424_match_table[] = { + { .compatible = "qcom,ipq5424-apss-clk" }, + { } +}; +MODULE_DEVICE_TABLE(of, apss_ipq5424_match_table); + +static struct platform_driver apss_ipq5424_driver = { + .probe = apss_ipq5424_probe, + .driver = { + .name = "apss-ipq5424-clk", + .of_match_table = apss_ipq5424_match_table, + .sync_state = icc_sync_state, + }, +}; + +module_platform_driver(apss_ipq5424_driver); + +MODULE_DESCRIPTION("QCOM APSS IPQ5424 CLK Driver"); +MODULE_LICENSE("GPL"); From 6ef38b0c16c20701fb8a06d2d2114080fbc785ad Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 2 Aug 2025 13:44:44 +0200 Subject: [PATCH 0029/2711] clk: qcom: Remove double-space after assignment operator This is an oddly common hiccup across clk/qcom.. Remove it in hopes to reduce spread through copy-paste. Signed-off-by: Konrad Dybcio Reviewed-by: Imran Shaik Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250802-topic-clk_qc_doublespace-v1-1-2cae59ba7d59@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/a7-pll.c | 2 +- drivers/clk/qcom/clk-alpha-pll.c | 26 +++++++++++++------------- drivers/clk/qcom/clk-rcg.c | 2 +- drivers/clk/qcom/clk-rcg2.c | 8 ++++---- drivers/clk/qcom/clk-rpmh.c | 6 +++--- drivers/clk/qcom/clk-smd-rpm.c | 8 ++++---- drivers/clk/qcom/gcc-qcs404.c | 2 +- drivers/clk/qcom/gpucc-sa8775p.c | 6 +++--- drivers/clk/qcom/gpucc-sc7180.c | 2 +- drivers/clk/qcom/gpucc-sm6350.c | 4 ++-- drivers/clk/qcom/gpucc-sm8150.c | 2 +- drivers/clk/qcom/gpucc-sm8250.c | 2 +- drivers/clk/qcom/lpassaudiocc-sc7280.c | 4 ++-- drivers/clk/qcom/lpasscc-sc8280xp.c | 4 ++-- drivers/clk/qcom/lpasscc-sm6115.c | 2 +- drivers/clk/qcom/lpasscorecc-sc7180.c | 2 +- drivers/clk/qcom/mmcc-sdm660.c | 2 +- drivers/clk/qcom/nsscc-ipq9574.c | 2 +- 18 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/clk/qcom/a7-pll.c b/drivers/clk/qcom/a7-pll.c index c4a53e5db229..bf7159f5b456 100644 --- a/drivers/clk/qcom/a7-pll.c +++ b/drivers/clk/qcom/a7-pll.c @@ -27,7 +27,7 @@ static struct clk_alpha_pll a7pll = { .clkr = { .hw.init = &(struct clk_init_data){ .name = "a7pll", - .parent_data = &(const struct clk_parent_data){ + .parent_data = &(const struct clk_parent_data){ .fw_name = "bi_tcxo", }, .num_parents = 1, diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index fec6eb376e27..81a1ce42285f 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -66,7 +66,7 @@ #define GET_PLL_TYPE(pll) (((pll)->regs - clk_alpha_pll_regs[0]) / PLL_OFF_MAX_REGS) const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { - [CLK_ALPHA_PLL_TYPE_DEFAULT] = { + [CLK_ALPHA_PLL_TYPE_DEFAULT] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, [PLL_OFF_ALPHA_VAL_U] = 0x0c, @@ -77,7 +77,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL_U] = 0x20, [PLL_OFF_STATUS] = 0x24, }, - [CLK_ALPHA_PLL_TYPE_HUAYRA] = { + [CLK_ALPHA_PLL_TYPE_HUAYRA] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, [PLL_OFF_USER_CTL] = 0x10, @@ -87,7 +87,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL_U] = 0x20, [PLL_OFF_STATUS] = 0x24, }, - [CLK_ALPHA_PLL_TYPE_HUAYRA_APSS] = { + [CLK_ALPHA_PLL_TYPE_HUAYRA_APSS] = { [PLL_OFF_L_VAL] = 0x08, [PLL_OFF_ALPHA_VAL] = 0x10, [PLL_OFF_USER_CTL] = 0x18, @@ -97,7 +97,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL] = 0x30, [PLL_OFF_TEST_CTL_U] = 0x34, }, - [CLK_ALPHA_PLL_TYPE_HUAYRA_2290] = { + [CLK_ALPHA_PLL_TYPE_HUAYRA_2290] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, [PLL_OFF_USER_CTL] = 0x0c, @@ -110,7 +110,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_OPMODE] = 0x28, [PLL_OFF_STATUS] = 0x38, }, - [CLK_ALPHA_PLL_TYPE_BRAMMO] = { + [CLK_ALPHA_PLL_TYPE_BRAMMO] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, [PLL_OFF_ALPHA_VAL_U] = 0x0c, @@ -119,7 +119,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL] = 0x1c, [PLL_OFF_STATUS] = 0x24, }, - [CLK_ALPHA_PLL_TYPE_FABIA] = { + [CLK_ALPHA_PLL_TYPE_FABIA] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_USER_CTL] = 0x0c, [PLL_OFF_USER_CTL_U] = 0x10, @@ -147,7 +147,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_OPMODE] = 0x38, [PLL_OFF_ALPHA_VAL] = 0x40, }, - [CLK_ALPHA_PLL_TYPE_AGERA] = { + [CLK_ALPHA_PLL_TYPE_AGERA] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, [PLL_OFF_USER_CTL] = 0x0c, @@ -157,7 +157,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL_U] = 0x1c, [PLL_OFF_STATUS] = 0x2c, }, - [CLK_ALPHA_PLL_TYPE_ZONDA] = { + [CLK_ALPHA_PLL_TYPE_ZONDA] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, [PLL_OFF_USER_CTL] = 0x0c, @@ -243,7 +243,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL] = 0x28, [PLL_OFF_TEST_CTL_U] = 0x2c, }, - [CLK_ALPHA_PLL_TYPE_DEFAULT_EVO] = { + [CLK_ALPHA_PLL_TYPE_DEFAULT_EVO] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, [PLL_OFF_ALPHA_VAL_U] = 0x0c, @@ -254,7 +254,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_CONFIG_CTL] = 0x20, [PLL_OFF_STATUS] = 0x24, }, - [CLK_ALPHA_PLL_TYPE_BRAMMO_EVO] = { + [CLK_ALPHA_PLL_TYPE_BRAMMO_EVO] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, [PLL_OFF_ALPHA_VAL_U] = 0x0c, @@ -275,7 +275,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL] = 0x30, [PLL_OFF_TEST_CTL_U] = 0x34, }, - [CLK_ALPHA_PLL_TYPE_STROMER_PLUS] = { + [CLK_ALPHA_PLL_TYPE_STROMER_PLUS] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_USER_CTL] = 0x08, [PLL_OFF_USER_CTL_U] = 0x0c, @@ -286,7 +286,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_ALPHA_VAL] = 0x24, [PLL_OFF_ALPHA_VAL_U] = 0x28, }, - [CLK_ALPHA_PLL_TYPE_ZONDA_OLE] = { + [CLK_ALPHA_PLL_TYPE_ZONDA_OLE] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, [PLL_OFF_USER_CTL] = 0x0c, @@ -301,7 +301,7 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_OPMODE] = 0x30, [PLL_OFF_STATUS] = 0x3c, }, - [CLK_ALPHA_PLL_TYPE_NSS_HUAYRA] = { + [CLK_ALPHA_PLL_TYPE_NSS_HUAYRA] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, [PLL_OFF_TEST_CTL] = 0x0c, diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index 987141c91fe0..31f0650b48ba 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c @@ -423,7 +423,7 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, rate = tmp; } } else { - rate = clk_hw_get_rate(p); + rate = clk_hw_get_rate(p); } req->best_parent_hw = p; req->best_parent_rate = rate; diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 8001fd9faf9d..e18cb8807d73 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -201,7 +201,7 @@ __clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, u32 cfg) regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m); m &= mask; regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), &n); - n = ~n; + n = ~n; n &= mask; n += m; mode = cfg & CFG_MODE_MASK; @@ -274,7 +274,7 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, rate = tmp; } } else { - rate = clk_hw_get_rate(p); + rate = clk_hw_get_rate(p); } req->best_parent_hw = p; req->best_parent_rate = rate; @@ -311,7 +311,7 @@ __clk_rcg2_select_conf(struct clk_hw *hw, const struct freq_multi_tbl *f, if (!p) continue; - parent_rate = clk_hw_get_rate(p); + parent_rate = clk_hw_get_rate(p); rate = calc_rate(parent_rate, conf->n, conf->m, conf->n, conf->pre_div); if (rate == req_rate) { @@ -382,7 +382,7 @@ static int _freq_tbl_fm_determine_rate(struct clk_hw *hw, const struct freq_mult rate = tmp; } } else { - rate = clk_hw_get_rate(p); + rate = clk_hw_get_rate(p); } req->best_parent_hw = p; diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 1496fb3de4be..5103a464d86d 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -87,7 +87,7 @@ static DEFINE_MUTEX(rpmh_clk_lock); .hw.init = &(struct clk_init_data){ \ .ops = &clk_rpmh_ops, \ .name = #_name, \ - .parent_data = &(const struct clk_parent_data){ \ + .parent_data = &(const struct clk_parent_data){ \ .fw_name = "xo", \ .name = "xo_board", \ }, \ @@ -105,7 +105,7 @@ static DEFINE_MUTEX(rpmh_clk_lock); .hw.init = &(struct clk_init_data){ \ .ops = &clk_rpmh_ops, \ .name = #_name "_ao", \ - .parent_data = &(const struct clk_parent_data){ \ + .parent_data = &(const struct clk_parent_data){ \ .fw_name = "xo", \ .name = "xo_board", \ }, \ @@ -182,7 +182,7 @@ static int clk_rpmh_send_aggregate_command(struct clk_rpmh *c) } c->last_sent_aggr_state = c->aggr_state; - c->peer->last_sent_aggr_state = c->last_sent_aggr_state; + c->peer->last_sent_aggr_state = c->last_sent_aggr_state; return 0; } diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 3bf6df3884a5..103db984a40b 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -30,7 +30,7 @@ .hw.init = &(struct clk_init_data){ \ .ops = &clk_smd_rpm_ops, \ .name = #_name, \ - .parent_data = &(const struct clk_parent_data){ \ + .parent_data = &(const struct clk_parent_data){ \ .fw_name = "xo", \ .name = "xo_board", \ }, \ @@ -47,7 +47,7 @@ .hw.init = &(struct clk_init_data){ \ .ops = &clk_smd_rpm_ops, \ .name = #_active, \ - .parent_data = &(const struct clk_parent_data){ \ + .parent_data = &(const struct clk_parent_data){ \ .fw_name = "xo", \ .name = "xo_board", \ }, \ @@ -74,7 +74,7 @@ .hw.init = &(struct clk_init_data){ \ .ops = &clk_smd_rpm_branch_ops, \ .name = #_name, \ - .parent_data = &(const struct clk_parent_data){ \ + .parent_data = &(const struct clk_parent_data){ \ .fw_name = "xo", \ .name = "xo_board", \ }, \ @@ -92,7 +92,7 @@ .hw.init = &(struct clk_init_data){ \ .ops = &clk_smd_rpm_branch_ops, \ .name = #_active, \ - .parent_data = &(const struct clk_parent_data){ \ + .parent_data = &(const struct clk_parent_data){ \ .fw_name = "xo", \ .name = "xo_board", \ }, \ diff --git a/drivers/clk/qcom/gcc-qcs404.c b/drivers/clk/qcom/gcc-qcs404.c index 5ca003c9bfba..efc75a3814ab 100644 --- a/drivers/clk/qcom/gcc-qcs404.c +++ b/drivers/clk/qcom/gcc-qcs404.c @@ -2754,7 +2754,7 @@ static struct clk_regmap *gcc_qcs404_clocks[] = { [GCC_DCC_CLK] = &gcc_dcc_clk.clkr, [GCC_DCC_XO_CLK] = &gcc_dcc_xo_clk.clkr, [GCC_WCSS_Q6_AHB_CLK] = &gcc_wdsp_q6ss_ahbs_clk.clkr, - [GCC_WCSS_Q6_AXIM_CLK] = &gcc_wdsp_q6ss_axim_clk.clkr, + [GCC_WCSS_Q6_AXIM_CLK] = &gcc_wdsp_q6ss_axim_clk.clkr, }; diff --git a/drivers/clk/qcom/gpucc-sa8775p.c b/drivers/clk/qcom/gpucc-sa8775p.c index 78cad622cb5a..25dcc5912f99 100644 --- a/drivers/clk/qcom/gpucc-sa8775p.c +++ b/drivers/clk/qcom/gpucc-sa8775p.c @@ -365,7 +365,7 @@ static struct clk_branch gpu_cc_cx_gmu_clk = { &gpu_cc_gmu_clk_src.clkr.hw, }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_aon_ops, }, }, @@ -414,7 +414,7 @@ static struct clk_branch gpu_cc_cxo_clk = { &gpu_cc_xo_clk_src.clkr.hw, }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -499,7 +499,7 @@ static struct clk_branch gpu_cc_hub_cx_int_clk = { &gpu_cc_hub_cx_int_div_clk_src.clkr.hw, }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_aon_ops, }, }, diff --git a/drivers/clk/qcom/gpucc-sc7180.c b/drivers/clk/qcom/gpucc-sc7180.c index a7bf44544b95..97287488e05a 100644 --- a/drivers/clk/qcom/gpucc-sc7180.c +++ b/drivers/clk/qcom/gpucc-sc7180.c @@ -42,7 +42,7 @@ static struct clk_alpha_pll gpu_cc_pll1 = { .clkr = { .hw.init = &(struct clk_init_data){ .name = "gpu_cc_pll1", - .parent_data = &(const struct clk_parent_data){ + .parent_data = &(const struct clk_parent_data){ .fw_name = "bi_tcxo", }, .num_parents = 1, diff --git a/drivers/clk/qcom/gpucc-sm6350.c b/drivers/clk/qcom/gpucc-sm6350.c index ee89c42413f8..efbee1518dd3 100644 --- a/drivers/clk/qcom/gpucc-sm6350.c +++ b/drivers/clk/qcom/gpucc-sm6350.c @@ -67,7 +67,7 @@ static struct clk_alpha_pll gpu_cc_pll0 = { .clkr = { .hw.init = &(struct clk_init_data){ .name = "gpu_cc_pll0", - .parent_data = &(const struct clk_parent_data){ + .parent_data = &(const struct clk_parent_data){ .index = DT_BI_TCXO, .fw_name = "bi_tcxo", }, @@ -111,7 +111,7 @@ static struct clk_alpha_pll gpu_cc_pll1 = { .clkr = { .hw.init = &(struct clk_init_data){ .name = "gpu_cc_pll1", - .parent_data = &(const struct clk_parent_data){ + .parent_data = &(const struct clk_parent_data){ .index = DT_BI_TCXO, .fw_name = "bi_tcxo", }, diff --git a/drivers/clk/qcom/gpucc-sm8150.c b/drivers/clk/qcom/gpucc-sm8150.c index 7ce91208c0bc..5701031c17f3 100644 --- a/drivers/clk/qcom/gpucc-sm8150.c +++ b/drivers/clk/qcom/gpucc-sm8150.c @@ -53,7 +53,7 @@ static struct clk_alpha_pll gpu_cc_pll1 = { .clkr = { .hw.init = &(struct clk_init_data){ .name = "gpu_cc_pll1", - .parent_data = &(const struct clk_parent_data){ + .parent_data = &(const struct clk_parent_data){ .fw_name = "bi_tcxo", }, .num_parents = 1, diff --git a/drivers/clk/qcom/gpucc-sm8250.c b/drivers/clk/qcom/gpucc-sm8250.c index ca0a1681d352..eee3208640cd 100644 --- a/drivers/clk/qcom/gpucc-sm8250.c +++ b/drivers/clk/qcom/gpucc-sm8250.c @@ -56,7 +56,7 @@ static struct clk_alpha_pll gpu_cc_pll1 = { .clkr = { .hw.init = &(struct clk_init_data){ .name = "gpu_cc_pll1", - .parent_data = &(const struct clk_parent_data){ + .parent_data = &(const struct clk_parent_data){ .fw_name = "bi_tcxo", }, .num_parents = 1, diff --git a/drivers/clk/qcom/lpassaudiocc-sc7280.c b/drivers/clk/qcom/lpassaudiocc-sc7280.c index 3ff123bffa11..7e2172969289 100644 --- a/drivers/clk/qcom/lpassaudiocc-sc7280.c +++ b/drivers/clk/qcom/lpassaudiocc-sc7280.c @@ -709,8 +709,8 @@ static const struct qcom_cc_desc lpass_audio_cc_sc7280_desc = { }; static const struct qcom_reset_map lpass_audio_cc_sc7280_resets[] = { - [LPASS_AUDIO_SWR_RX_CGCR] = { 0xa0, 1 }, - [LPASS_AUDIO_SWR_TX_CGCR] = { 0xa8, 1 }, + [LPASS_AUDIO_SWR_RX_CGCR] = { 0xa0, 1 }, + [LPASS_AUDIO_SWR_TX_CGCR] = { 0xa8, 1 }, [LPASS_AUDIO_SWR_WSA_CGCR] = { 0xb0, 1 }, }; diff --git a/drivers/clk/qcom/lpasscc-sc8280xp.c b/drivers/clk/qcom/lpasscc-sc8280xp.c index 9fd9498d7dc8..ff839788c40e 100644 --- a/drivers/clk/qcom/lpasscc-sc8280xp.c +++ b/drivers/clk/qcom/lpasscc-sc8280xp.c @@ -18,9 +18,9 @@ #include "reset.h" static const struct qcom_reset_map lpass_audiocc_sc8280xp_resets[] = { - [LPASS_AUDIO_SWR_RX_CGCR] = { 0xa0, 1 }, + [LPASS_AUDIO_SWR_RX_CGCR] = { 0xa0, 1 }, [LPASS_AUDIO_SWR_WSA_CGCR] = { 0xb0, 1 }, - [LPASS_AUDIO_SWR_WSA2_CGCR] = { 0xd8, 1 }, + [LPASS_AUDIO_SWR_WSA2_CGCR] = { 0xd8, 1 }, }; static const struct regmap_config lpass_audiocc_sc8280xp_regmap_config = { diff --git a/drivers/clk/qcom/lpasscc-sm6115.c b/drivers/clk/qcom/lpasscc-sm6115.c index 8ffdab71b948..ac6d219233b4 100644 --- a/drivers/clk/qcom/lpasscc-sm6115.c +++ b/drivers/clk/qcom/lpasscc-sm6115.c @@ -17,7 +17,7 @@ #include "reset.h" static const struct qcom_reset_map lpass_audiocc_sm6115_resets[] = { - [LPASS_AUDIO_SWR_RX_CGCR] = { .reg = 0x98, .bit = 1, .udelay = 500 }, + [LPASS_AUDIO_SWR_RX_CGCR] = { .reg = 0x98, .bit = 1, .udelay = 500 }, }; static struct regmap_config lpass_audiocc_sm6115_regmap_config = { diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c index 5937b071533b..5174bd3dcdc5 100644 --- a/drivers/clk/qcom/lpasscorecc-sc7180.c +++ b/drivers/clk/qcom/lpasscorecc-sc7180.c @@ -42,7 +42,7 @@ static const struct alpha_pll_config lpass_lpaaudio_dig_pll_config = { }; static const u8 clk_alpha_pll_regs_offset[][PLL_OFF_MAX_REGS] = { - [CLK_ALPHA_PLL_TYPE_FABIA] = { + [CLK_ALPHA_PLL_TYPE_FABIA] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_CAL_L_VAL] = 0x8, [PLL_OFF_USER_CTL] = 0x0c, diff --git a/drivers/clk/qcom/mmcc-sdm660.c b/drivers/clk/qcom/mmcc-sdm660.c index e69fc65b13da..b723c536dfb6 100644 --- a/drivers/clk/qcom/mmcc-sdm660.c +++ b/drivers/clk/qcom/mmcc-sdm660.c @@ -74,7 +74,7 @@ static struct clk_alpha_pll mmpll0 = { }, }; -static struct clk_alpha_pll mmpll6 = { +static struct clk_alpha_pll mmpll6 = { .offset = 0xf0, .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr = { diff --git a/drivers/clk/qcom/nsscc-ipq9574.c b/drivers/clk/qcom/nsscc-ipq9574.c index 64c6b05ff066..c8b11b04a7c2 100644 --- a/drivers/clk/qcom/nsscc-ipq9574.c +++ b/drivers/clk/qcom/nsscc-ipq9574.c @@ -3016,7 +3016,7 @@ static const struct qcom_reset_map nss_cc_ipq9574_resets[] = { [NSSPORT4_RESET] = { .reg = 0x28a24, .bitmask = GENMASK(5, 4) }, [NSSPORT5_RESET] = { .reg = 0x28a24, .bitmask = GENMASK(3, 2) }, [NSSPORT6_RESET] = { .reg = 0x28a24, .bitmask = GENMASK(1, 0) }, - [EDMA_HW_RESET] = { .reg = 0x28a08, .bitmask = GENMASK(16, 15) }, + [EDMA_HW_RESET] = { .reg = 0x28a08, .bitmask = GENMASK(16, 15) }, }; static const struct regmap_config nss_cc_ipq9574_regmap_config = { From 2f7b168323c22faafb1fbf94ef93b7ce5efc15c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 2 Aug 2025 12:55:46 +0300 Subject: [PATCH 0030/2711] clk: qcom: gcc-ipq6018: rework nss_port5 clock to multiple conf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework nss_port5 to use the new multiple configuration implementation and correctly fix the clocks for this port under some corner case. In OpenWrt, this patch avoids intermittent dmesg errors of the form nss_port5_rx_clk_src: rcg didn't update its configuration. This is a mechanical, straightforward port of commit e88f03230dc07aa3293b6aeb078bd27370bb2594 ("clk: qcom: gcc-ipq8074: rework nss_port5/6 clock to multiple conf") to gcc-ipq6018, with two conflicts resolved: different frequency of the P_XO clock source, and only 5 Ethernet ports. This was originally developed by JiaY-shi . Link: https://lore.kernel.org/all/20231220221724.3822-4-ansuelsmth@gmail.com/ Signed-off-by: Marko Mäkelä Tested-by: Marko Mäkelä Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250802095546.295448-1-marko.makela@iki.fi Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-ipq6018.c | 60 +++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/drivers/clk/qcom/gcc-ipq6018.c b/drivers/clk/qcom/gcc-ipq6018.c index d861191b0c85..d4fc491a18b2 100644 --- a/drivers/clk/qcom/gcc-ipq6018.c +++ b/drivers/clk/qcom/gcc-ipq6018.c @@ -511,15 +511,23 @@ static struct clk_rcg2 apss_ahb_clk_src = { }, }; -static const struct freq_tbl ftbl_nss_port5_rx_clk_src[] = { - F(24000000, P_XO, 1, 0, 0), - F(25000000, P_UNIPHY1_RX, 12.5, 0, 0), - F(25000000, P_UNIPHY0_RX, 5, 0, 0), - F(78125000, P_UNIPHY1_RX, 4, 0, 0), - F(125000000, P_UNIPHY1_RX, 2.5, 0, 0), - F(125000000, P_UNIPHY0_RX, 1, 0, 0), - F(156250000, P_UNIPHY1_RX, 2, 0, 0), - F(312500000, P_UNIPHY1_RX, 1, 0, 0), +static const struct freq_conf ftbl_nss_port5_rx_clk_src_25[] = { + C(P_UNIPHY1_RX, 12.5, 0, 0), + C(P_UNIPHY0_RX, 5, 0, 0), +}; + +static const struct freq_conf ftbl_nss_port5_rx_clk_src_125[] = { + C(P_UNIPHY1_RX, 2.5, 0, 0), + C(P_UNIPHY0_RX, 1, 0, 0), +}; + +static const struct freq_multi_tbl ftbl_nss_port5_rx_clk_src[] = { + FMS(24000000, P_XO, 1, 0, 0), + FM(25000000, ftbl_nss_port5_rx_clk_src_25), + FMS(78125000, P_UNIPHY1_RX, 4, 0, 0), + FM(125000000, ftbl_nss_port5_rx_clk_src_125), + FMS(156250000, P_UNIPHY1_RX, 2, 0, 0), + FMS(312500000, P_UNIPHY1_RX, 1, 0, 0), { } }; @@ -547,26 +555,34 @@ gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map[] = { static struct clk_rcg2 nss_port5_rx_clk_src = { .cmd_rcgr = 0x68060, - .freq_tbl = ftbl_nss_port5_rx_clk_src, + .freq_multi_tbl = ftbl_nss_port5_rx_clk_src, .hid_width = 5, .parent_map = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map, .clkr.hw.init = &(struct clk_init_data){ .name = "nss_port5_rx_clk_src", .parent_data = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias, .num_parents = 7, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_fm_ops, }, }; -static const struct freq_tbl ftbl_nss_port5_tx_clk_src[] = { - F(24000000, P_XO, 1, 0, 0), - F(25000000, P_UNIPHY1_TX, 12.5, 0, 0), - F(25000000, P_UNIPHY0_TX, 5, 0, 0), - F(78125000, P_UNIPHY1_TX, 4, 0, 0), - F(125000000, P_UNIPHY1_TX, 2.5, 0, 0), - F(125000000, P_UNIPHY0_TX, 1, 0, 0), - F(156250000, P_UNIPHY1_TX, 2, 0, 0), - F(312500000, P_UNIPHY1_TX, 1, 0, 0), +static const struct freq_conf ftbl_nss_port5_tx_clk_src_25[] = { + C(P_UNIPHY1_TX, 12.5, 0, 0), + C(P_UNIPHY0_TX, 5, 0, 0), +}; + +static const struct freq_conf ftbl_nss_port5_tx_clk_src_125[] = { + C(P_UNIPHY1_TX, 2.5, 0, 0), + C(P_UNIPHY0_TX, 1, 0, 0), +}; + +static const struct freq_multi_tbl ftbl_nss_port5_tx_clk_src[] = { + FMS(24000000, P_XO, 1, 0, 0), + FM(25000000, ftbl_nss_port5_tx_clk_src_25), + FMS(78125000, P_UNIPHY1_TX, 4, 0, 0), + FM(125000000, ftbl_nss_port5_tx_clk_src_125), + FMS(156250000, P_UNIPHY1_TX, 2, 0, 0), + FMS(312500000, P_UNIPHY1_TX, 1, 0, 0), { } }; @@ -594,14 +610,14 @@ gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map[] = { static struct clk_rcg2 nss_port5_tx_clk_src = { .cmd_rcgr = 0x68068, - .freq_tbl = ftbl_nss_port5_tx_clk_src, + .freq_multi_tbl = ftbl_nss_port5_tx_clk_src, .hid_width = 5, .parent_map = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map, .clkr.hw.init = &(struct clk_init_data){ .name = "nss_port5_tx_clk_src", .parent_data = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias, .num_parents = 7, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_fm_ops, }, }; From 24b2d3c452e5f3facaf9c664aaaa9fc7fa4bc6bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 10 Jun 2025 13:58:18 +0300 Subject: [PATCH 0031/2711] PCI: Use header type defines in pci_setup_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace literals with PCI_HEADER_TYPE_* defines in pci_setup_device(). Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250610105820.7126-1-ilpo.jarvinen@linux.intel.com --- drivers/pci/probe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f41128f91ca7..505e9a602118 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1985,8 +1985,8 @@ int pci_setup_device(struct pci_dev *dev) dev->sysdata = dev->bus->sysdata; dev->dev.parent = dev->bus->bridge; dev->dev.bus = &pci_bus_type; - dev->hdr_type = hdr_type & 0x7f; - dev->multifunction = !!(hdr_type & 0x80); + dev->hdr_type = FIELD_GET(PCI_HEADER_TYPE_MASK, hdr_type); + dev->multifunction = FIELD_GET(PCI_HEADER_TYPE_MFD, hdr_type); dev->error_state = pci_channel_io_normal; set_pcie_port_type(dev); From aa84931ba7f989c263a79a3a962524b5830d0e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 10 Jun 2025 13:58:19 +0300 Subject: [PATCH 0032/2711] PCI: Clean up early_dump_pci_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert 256 to PCI_CFG_SPACE_SIZE and 4 to sizeof(u32) and avoid i / 4 construct by changing the iteration. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250610105820.7126-2-ilpo.jarvinen@linux.intel.com --- drivers/pci/probe.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 505e9a602118..b06f0d19f9a7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -3,6 +3,7 @@ * PCI detection and setup code */ +#include #include #include #include @@ -1912,16 +1913,16 @@ static int pci_intx_mask_broken(struct pci_dev *dev) static void early_dump_pci_device(struct pci_dev *pdev) { - u32 value[256 / 4]; + u32 value[PCI_CFG_SPACE_SIZE / sizeof(u32)]; int i; pci_info(pdev, "config space:\n"); - for (i = 0; i < 256; i += 4) - pci_read_config_dword(pdev, i, &value[i / 4]); + for (i = 0; i < ARRAY_SIZE(value); i++) + pci_read_config_dword(pdev, i * sizeof(u32), &value[i]); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, - value, 256, false); + value, ARRAY_SIZE(value) * sizeof(u32), false); } static const char *pci_type_str(struct pci_dev *dev) From c763fae8c4231e426033f62c21be60db4b6659a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 10 Jun 2025 13:58:20 +0300 Subject: [PATCH 0033/2711] PCI: Clean up pci_scan_child_bus_extend() loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_scan_child_bus_extend() open-codes device number iteration in the for loop. Convert to use PCI_DEVFN() and add PCI_MAX_NR_DEVS (there seems to be no pre-existing define for this purpose). Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250610105820.7126-3-ilpo.jarvinen@linux.intel.com --- drivers/pci/pci.h | 1 + drivers/pci/probe.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 34f65d69662e..e1ad32b9eb56 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -8,6 +8,7 @@ struct pcie_tlp_log; /* Number of possible devfns: 0.0 to 1f.7 inclusive */ #define MAX_NR_DEVFNS 256 +#define PCI_MAX_NR_DEVS 32 #define MAX_NR_LANES 16 diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index b06f0d19f9a7..591aee60e3d0 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -3046,14 +3046,14 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus, { unsigned int used_buses, normal_bridges = 0, hotplug_bridges = 0; unsigned int start = bus->busn_res.start; - unsigned int devfn, cmax, max = start; + unsigned int devnr, cmax, max = start; struct pci_dev *dev; dev_dbg(&bus->dev, "scanning bus\n"); /* Go find them, Rover! */ - for (devfn = 0; devfn < 256; devfn += 8) - pci_scan_slot(bus, devfn); + for (devnr = 0; devnr < PCI_MAX_NR_DEVS; devnr++) + pci_scan_slot(bus, PCI_DEVFN(devnr, 0)); /* Reserve buses for SR-IOV capability */ used_buses = pci_iov_bus_range(bus); From a22250fe933dbd1da9a9683506ae3f489ccc579d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 10 Jun 2025 14:48:02 +0300 Subject: [PATCH 0034/2711] PCI: Add Extended Tag + MRRS quirk for Xeon 6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When bifurcated to x2, Xeon 6 Root Port performance is sensitive to the configuration of Extended Tags, Max Read Request Size (MRRS), and 10-Bit Tag Requester (note: there is currently no 10-Bit Tag support in the kernel). While those can be configured to the recommended values by FW, kernel may decide to overwrite the initial values. Add a quirk that disallows enabling Extended Tags and setting MRRS larger than 128B for devices under Xeon 6 Root Ports if the Root Port is bifurcated to x2. Use the host bridge's enable_device hook to overwrite MRRS if it's set to >128B for the device to be enabled. The earlier attempts to implement this quirk polluted PCI core code with the checks necessary to support this quirk. Using the enable_device hook keeps the quirk well-contained, away from the PCI core code. Suggested-by: Lukas Wunner Link: https://cdrdv2.intel.com/v1/dl/getContent/837176 Signed-off-by: Ilpo Järvinen [bhelgaas: 2x -> x2, rename quirk] Signed-off-by: Bjorn Helgaas Reviewed-by: Lukas Wunner Reviewed-by: Dan Williams Link: https://patch.msgid.link/20250610114802.7460-1-ilpo.jarvinen@linux.intel.com --- arch/x86/pci/fixup.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index e7e71490bd25..25076a5acd96 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -294,6 +294,46 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_r DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_rootport_aspm_quirk); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk); +/* + * PCIe devices underneath Xeon 6 PCIe Root Port bifurcated to x2 have lower + * performance with Extended Tags and MRRS > 128B. Work around the performance + * problems by disabling Extended Tags and limiting MRRS to 128B. + * + * https://cdrdv2.intel.com/v1/dl/getContent/837176 + */ +static int limit_mrrs_to_128(struct pci_host_bridge *b, struct pci_dev *pdev) +{ + int readrq = pcie_get_readrq(pdev); + + if (readrq > 128) + pcie_set_readrq(pdev, 128); + + return 0; +} + +static void pci_xeon_x2_bifurc_quirk(struct pci_dev *pdev) +{ + struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus); + u32 linkcap; + + pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &linkcap); + if (FIELD_GET(PCI_EXP_LNKCAP_MLW, linkcap) != 0x2) + return; + + bridge->no_ext_tags = 1; + bridge->enable_device = limit_mrrs_to_128; + pci_info(pdev, "Disabling Extended Tags and limiting MRRS to 128B (performance reasons due to x2 PCIe link)\n"); +} + +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db0, pci_xeon_x2_bifurc_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db1, pci_xeon_x2_bifurc_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db2, pci_xeon_x2_bifurc_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db3, pci_xeon_x2_bifurc_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db6, pci_xeon_x2_bifurc_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db7, pci_xeon_x2_bifurc_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db8, pci_xeon_x2_bifurc_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db9, pci_xeon_x2_bifurc_quirk); + /* * Fixup to mark boot BIOS video selected by BIOS before it changes * From 1d33d9e46c08e952853e821ab8e0b46cb248bc1f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 31 Jul 2025 11:00:17 +0100 Subject: [PATCH 0035/2711] PCI: hotplug: Clean up spaces in messages Remove extraneous space before newline in messages. Signed-off-by: Colin Ian King [bhelgaas: squash into one patch, commit log] Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250731100017.2165781-1-colin.i.king@gmail.com Link: https://patch.msgid.link/20250731101036.2167812-1-colin.i.king@gmail.com --- drivers/pci/hotplug/cpqphp_pci.c | 8 ++++---- drivers/pci/hotplug/ibmphp_hpc.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index ef7534a3ca40..88929360fe77 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -1302,7 +1302,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); - dbg("populated slot =%d \n", populated_slot); + dbg("populated slot = %d\n", populated_slot); if (!populated_slot) { io_node->next = ctrl->io_head; ctrl->io_head = io_node; @@ -1325,7 +1325,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); - dbg("populated slot =%d \n", populated_slot); + dbg("populated slot = %d\n", populated_slot); if (!populated_slot) { mem_node->next = ctrl->mem_head; ctrl->mem_head = mem_node; @@ -1349,7 +1349,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st p_mem_node->length = pre_mem_length << 16; dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); - dbg("populated slot =%d \n", populated_slot); + dbg("populated slot = %d\n", populated_slot); if (!populated_slot) { p_mem_node->next = ctrl->p_mem_head; @@ -1373,7 +1373,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st bus_node->length = max_bus - secondary_bus + 1; dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); - dbg("populated slot =%d \n", populated_slot); + dbg("populated slot = %d\n", populated_slot); if (!populated_slot) { bus_node->next = ctrl->bus_head; ctrl->bus_head = bus_node; diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index a5720d12e573..2324167656a6 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -124,7 +124,7 @@ static u8 i2c_ctrl_read(struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 i unsigned long ultemp; unsigned long data; // actual data HILO format - debug_polling("%s - Entry WPGBbar[%p] index[%x] \n", __func__, WPGBbar, index); + debug_polling("%s - Entry WPGBbar[%p] index[%x]\n", __func__, WPGBbar, index); //-------------------------------------------------------------------- // READ - step 1 @@ -147,7 +147,7 @@ static u8 i2c_ctrl_read(struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 i ultemp = ultemp << 8; data |= ultemp; } else { - err("this controller type is not supported \n"); + err("this controller type is not supported\n"); return HPC_ERROR; } @@ -258,7 +258,7 @@ static u8 i2c_ctrl_write(struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 ultemp = ultemp << 8; data |= ultemp; } else { - err("this controller type is not supported \n"); + err("this controller type is not supported\n"); return HPC_ERROR; } From ebc7086b39e5e4f3d3ca82caaea20538c9b62d42 Mon Sep 17 00:00:00 2001 From: Marcos Del Sol Vives Date: Sun, 6 Jul 2025 01:32:08 +0200 Subject: [PATCH 0036/2711] PCI: Disable MSI on RDC PCI to PCIe bridges RDC PCI to PCIe bridges, present on Vortex86DX3 and Vortex86EX2 SoCs, do not support MSIs. If enabled, interrupts generated by PCIe devices never reach the processor. I have contacted the manufacturer (DM&P) and they confirmed that PCI MSIs need to be disabled for them. Signed-off-by: Marcos Del Sol Vives Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250705233209.721507-1-marcos@orca.pet --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d97335a40193..6eb3d20386e9 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2717,6 +2717,7 @@ static void quirk_disable_msi(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0xa238, quirk_disable_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x5a3f, quirk_disable_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_RDC, 0x1031, quirk_disable_msi); /* * The APC bridge device in AMD 780 family northbridges has some random From a42938e80357a13f8b8592111e63f2e33a919863 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Fri, 8 Aug 2025 16:37:01 +0800 Subject: [PATCH 0037/2711] zonefs: correct some spelling mistakes Trivial fix to spelling mistake in comment text. (1) fix "unwriten"->"unwritten" (2) fix "writen"->"written" Signed-off-by: Xichao Zhao Signed-off-by: Damien Le Moal --- fs/zonefs/file.c | 2 +- fs/zonefs/super.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c index fd3a5922f6c3..90e2ad8ee5f4 100644 --- a/fs/zonefs/file.c +++ b/fs/zonefs/file.c @@ -85,7 +85,7 @@ static int zonefs_write_iomap_begin(struct inode *inode, loff_t offset, /* * For conventional zones, all blocks are always mapped. For sequential * zones, all blocks after always mapped below the inode size (zone - * write pointer) and unwriten beyond. + * write pointer) and unwritten beyond. */ mutex_lock(&zi->i_truncate_mutex); iomap->bdev = inode->i_sb->s_bdev; diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c index 4dc7f967c861..70be0b3dda49 100644 --- a/fs/zonefs/super.c +++ b/fs/zonefs/super.c @@ -268,7 +268,7 @@ static void zonefs_handle_io_error(struct inode *inode, struct blk_zone *zone, * Check the zone condition: if the zone is not "bad" (offline or * read-only), read errors are simply signaled to the IO issuer as long * as there is no inconsistency between the inode size and the amount of - * data writen in the zone (data_size). + * data written in the zone (data_size). */ data_size = zonefs_check_zone_condition(sb, z, zone); isize = i_size_read(inode); @@ -282,7 +282,7 @@ static void zonefs_handle_io_error(struct inode *inode, struct blk_zone *zone, * For the latter case, the cause may be a write IO error or an external * action on the device. Two error patterns exist: * 1) The inode size is lower than the amount of data in the zone: - * a write operation partially failed and data was writen at the end + * a write operation partially failed and data was written at the end * of the file. This can happen in the case of a large direct IO * needing several BIOs and/or write requests to be processed. * 2) The inode size is larger than the amount of data in the zone: From be477c3924f80809871df12f72d80d405d482ba2 Mon Sep 17 00:00:00 2001 From: Satya Priya Kakitapalli Date: Thu, 10 Jul 2025 18:30:39 +0530 Subject: [PATCH 0038/2711] dt-bindings: clock: qcom,videocc: Add sc8180x compatible The sc8180x video clock controller block is identical to that of sm8150. Add a new compatible string for sc8180x videocc and use sm8150 as fallback. Signed-off-by: Satya Priya Kakitapalli Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250710-sc8180x-videocc-dt-v4-1-07a9d9d5e0e6@quicinc.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,videocc.yaml | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/qcom,videocc.yaml b/Documentation/devicetree/bindings/clock/qcom,videocc.yaml index 5f7738d6835c..f4ff9acef9d5 100644 --- a/Documentation/devicetree/bindings/clock/qcom,videocc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,videocc.yaml @@ -23,13 +23,17 @@ description: | properties: compatible: - enum: - - qcom,sc7180-videocc - - qcom,sc7280-videocc - - qcom,sdm845-videocc - - qcom,sm6350-videocc - - qcom,sm8150-videocc - - qcom,sm8250-videocc + oneOf: + - enum: + - qcom,sc7180-videocc + - qcom,sc7280-videocc + - qcom,sdm845-videocc + - qcom,sm6350-videocc + - qcom,sm8150-videocc + - qcom,sm8250-videocc + - items: + - const: qcom,sc8180x-videocc + - const: qcom,sm8150-videocc clocks: minItems: 1 @@ -110,8 +114,9 @@ allOf: - if: properties: compatible: - enum: - - qcom,sm8150-videocc + contains: + enum: + - qcom,sm8150-videocc then: properties: clocks: From 78a474b5a31a25e0a77e50df42be925f7cb575e6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 11 Aug 2025 15:54:04 +0200 Subject: [PATCH 0039/2711] dt-bindings: phy: fsl,imx8mq-usb: Drop 'db' suffix duplicating dtschema A common property unit suffix '-db' was added to dtschema, thus in-kernel bindings should not reference the type. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250811-dt-bindings-db-v1-2-457301523bb5@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml index 22dd91591a09..6a47e08e0e97 100644 --- a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml +++ b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml @@ -76,7 +76,6 @@ properties: description: Adjust TX de-emphasis attenuation in dB at nominal 3.5dB point as per USB specification - $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 maximum: 36 From a84eeacbf9325fd7f604b80f246aaba157730cd5 Mon Sep 17 00:00:00 2001 From: Jeongjun Park Date: Thu, 17 Jul 2025 20:26:43 +0900 Subject: [PATCH 0040/2711] HID: steelseries: refactor probe() and remove() steelseries_srws1_probe() still does not use devm_kzalloc() and devm_led_classdev_register(), so there is a lot of code to safely manage heap, which reduces readability and may cause memory leaks due to minor patch mistakes in the future. Therefore, it should be changed to use devm_kzalloc() and devm_led_classdev_register() to easily and safely manage heap. Also, the current steelseries driver mainly checks sd->quriks to determine which product a specific HID device is, which is not the correct way. remove(), unlike probe(), does not receive struct hid_device_id as an argument, so it must check hdev unconditionally to know which product it is. However, since struct steelseries_device and struct steelseries_srws1_data have different structures, if SRWS1 is removed in remove(), converts hdev->dev, which is initialized to struct steelseries_srws1_data, to struct steelseries_device and uses it. This causes various memory-related bugs as completely unexpected values exist in member variables of the structure. Therefore, in order to modify probe() and remove() to work properly, Arctis 1, 9 should be added to HID_USB_DEVICE and some functions should be modified to check hdev->product when determining HID device product. Fixes: a0c76896c3fb ("HID: steelseries: Add support for Arctis 1 XBox") Signed-off-by: Jeongjun Park Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 2 + drivers/hid/hid-quirks.c | 2 + drivers/hid/hid-steelseries.c | 109 ++++++++++++---------------------- 3 files changed, 43 insertions(+), 70 deletions(-) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 5a1096283855..b7098cdc845a 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1292,6 +1292,8 @@ #define USB_VENDOR_ID_STEELSERIES 0x1038 #define USB_DEVICE_ID_STEELSERIES_SRWS1 0x1410 +#define USB_DEVICE_ID_STEELSERIES_ARCTIS_1 0x12b6 +#define USB_DEVICE_ID_STEELSERIES_ARCTIS_9 0x12c2 #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index ff11f1ad344d..fffe296920c9 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -692,6 +692,8 @@ static const struct hid_device_id hid_have_special_driver[] = { #endif #if IS_ENABLED(CONFIG_HID_STEELSERIES) { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_9) }, #endif #if IS_ENABLED(CONFIG_HID_SUNPLUS) { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c index d4bd7848b8c6..8af98d67959e 100644 --- a/drivers/hid/hid-steelseries.c +++ b/drivers/hid/hid-steelseries.c @@ -249,11 +249,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev, { int ret, i; struct led_classdev *led; + struct steelseries_srws1_data *drv_data; size_t name_sz; char *name; - struct steelseries_srws1_data *drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); - + drv_data = devm_kzalloc(&hdev->dev, sizeof(*drv_data), GFP_KERNEL); if (drv_data == NULL) { hid_err(hdev, "can't alloc SRW-S1 memory\n"); return -ENOMEM; @@ -264,18 +264,18 @@ static int steelseries_srws1_probe(struct hid_device *hdev, ret = hid_parse(hdev); if (ret) { hid_err(hdev, "parse failed\n"); - goto err_free; + goto err; } if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) { ret = -ENODEV; - goto err_free; + goto err; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { hid_err(hdev, "hw start failed\n"); - goto err_free; + goto err; } /* register led subsystem */ @@ -288,10 +288,10 @@ static int steelseries_srws1_probe(struct hid_device *hdev, name_sz = strlen(hdev->uniq) + 16; /* 'ALL', for setting all LEDs simultaneously */ - led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); + led = devm_kzalloc(&hdev->dev, sizeof(struct led_classdev)+name_sz, GFP_KERNEL); if (!led) { hid_err(hdev, "can't allocate memory for LED ALL\n"); - goto err_led; + goto out; } name = (void *)(&led[1]); @@ -303,16 +303,18 @@ static int steelseries_srws1_probe(struct hid_device *hdev, led->brightness_set = steelseries_srws1_led_all_set_brightness; drv_data->led[SRWS1_NUMBER_LEDS] = led; - ret = led_classdev_register(&hdev->dev, led); - if (ret) - goto err_led; + ret = devm_led_classdev_register(&hdev->dev, led); + if (ret) { + hid_err(hdev, "failed to register LED %d. Aborting.\n", SRWS1_NUMBER_LEDS); + goto out; /* let the driver continue without LEDs */ + } /* Each individual LED */ for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { - led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); + led = devm_kzalloc(&hdev->dev, sizeof(struct led_classdev)+name_sz, GFP_KERNEL); if (!led) { hid_err(hdev, "can't allocate memory for LED %d\n", i); - goto err_led; + break; } name = (void *)(&led[1]); @@ -324,53 +326,18 @@ static int steelseries_srws1_probe(struct hid_device *hdev, led->brightness_set = steelseries_srws1_led_set_brightness; drv_data->led[i] = led; - ret = led_classdev_register(&hdev->dev, led); + ret = devm_led_classdev_register(&hdev->dev, led); if (ret) { hid_err(hdev, "failed to register LED %d. Aborting.\n", i); -err_led: - /* Deregister all LEDs (if any) */ - for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) { - led = drv_data->led[i]; - drv_data->led[i] = NULL; - if (!led) - continue; - led_classdev_unregister(led); - kfree(led); - } - goto out; /* but let the driver continue without LEDs */ + break; /* but let the driver continue without LEDs */ } } out: return 0; -err_free: - kfree(drv_data); +err: return ret; } - -static void steelseries_srws1_remove(struct hid_device *hdev) -{ - int i; - struct led_classdev *led; - - struct steelseries_srws1_data *drv_data = hid_get_drvdata(hdev); - - if (drv_data) { - /* Deregister LEDs (if any) */ - for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) { - led = drv_data->led[i]; - drv_data->led[i] = NULL; - if (!led) - continue; - led_classdev_unregister(led); - kfree(led); - } - - } - - hid_hw_stop(hdev); - kfree(drv_data); -} #endif #define STEELSERIES_HEADSET_BATTERY_TIMEOUT_MS 3000 @@ -405,13 +372,12 @@ static int steelseries_headset_request_battery(struct hid_device *hdev, static void steelseries_headset_fetch_battery(struct hid_device *hdev) { - struct steelseries_device *sd = hid_get_drvdata(hdev); int ret = 0; - if (sd->quirks & STEELSERIES_ARCTIS_1) + if (hdev->product == USB_DEVICE_ID_STEELSERIES_ARCTIS_1) ret = steelseries_headset_request_battery(hdev, arctis_1_battery_request, sizeof(arctis_1_battery_request)); - else if (sd->quirks & STEELSERIES_ARCTIS_9) + else if (hdev->product == USB_DEVICE_ID_STEELSERIES_ARCTIS_9) ret = steelseries_headset_request_battery(hdev, arctis_9_battery_request, sizeof(arctis_9_battery_request)); @@ -567,14 +533,7 @@ static int steelseries_probe(struct hid_device *hdev, const struct hid_device_id struct steelseries_device *sd; int ret; - sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL); - if (!sd) - return -ENOMEM; - hid_set_drvdata(hdev, sd); - sd->hdev = hdev; - sd->quirks = id->driver_data; - - if (sd->quirks & STEELSERIES_SRWS1) { + if (hdev->product == USB_DEVICE_ID_STEELSERIES_SRWS1) { #if IS_BUILTIN(CONFIG_LEDS_CLASS) || \ (IS_MODULE(CONFIG_LEDS_CLASS) && IS_MODULE(CONFIG_HID_STEELSERIES)) return steelseries_srws1_probe(hdev, id); @@ -583,6 +542,13 @@ static int steelseries_probe(struct hid_device *hdev, const struct hid_device_id #endif } + sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL); + if (!sd) + return -ENOMEM; + hid_set_drvdata(hdev, sd); + sd->hdev = hdev; + sd->quirks = id->driver_data; + ret = hid_parse(hdev); if (ret) return ret; @@ -610,17 +576,19 @@ static int steelseries_probe(struct hid_device *hdev, const struct hid_device_id static void steelseries_remove(struct hid_device *hdev) { - struct steelseries_device *sd = hid_get_drvdata(hdev); + struct steelseries_device *sd; unsigned long flags; - if (sd->quirks & STEELSERIES_SRWS1) { + if (hdev->product == USB_DEVICE_ID_STEELSERIES_SRWS1) { #if IS_BUILTIN(CONFIG_LEDS_CLASS) || \ (IS_MODULE(CONFIG_LEDS_CLASS) && IS_MODULE(CONFIG_HID_STEELSERIES)) - steelseries_srws1_remove(hdev); + goto srws1_remove; #endif return; } + sd = hid_get_drvdata(hdev); + spin_lock_irqsave(&sd->lock, flags); sd->removed = true; spin_unlock_irqrestore(&sd->lock, flags); @@ -628,6 +596,7 @@ static void steelseries_remove(struct hid_device *hdev) cancel_delayed_work_sync(&sd->battery_work); hid_hw_close(hdev); +srws1_remove: hid_hw_stop(hdev); } @@ -667,10 +636,10 @@ static int steelseries_headset_raw_event(struct hid_device *hdev, unsigned long flags; /* Not a headset */ - if (sd->quirks & STEELSERIES_SRWS1) + if (hdev->product == USB_DEVICE_ID_STEELSERIES_SRWS1) return 0; - if (sd->quirks & STEELSERIES_ARCTIS_1) { + if (hdev->product == USB_DEVICE_ID_STEELSERIES_ARCTIS_1) { hid_dbg(sd->hdev, "Parsing raw event for Arctis 1 headset (%*ph)\n", size, read_buf); if (size < ARCTIS_1_BATTERY_RESPONSE_LEN || @@ -688,7 +657,7 @@ static int steelseries_headset_raw_event(struct hid_device *hdev, } } - if (sd->quirks & STEELSERIES_ARCTIS_9) { + if (hdev->product == USB_DEVICE_ID_STEELSERIES_ARCTIS_9) { hid_dbg(sd->hdev, "Parsing raw event for Arctis 9 headset (%*ph)\n", size, read_buf); if (size < ARCTIS_9_BATTERY_RESPONSE_LEN) { @@ -757,11 +726,11 @@ static const struct hid_device_id steelseries_devices[] = { .driver_data = STEELSERIES_SRWS1 }, { /* SteelSeries Arctis 1 Wireless for XBox */ - HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, 0x12b6), - .driver_data = STEELSERIES_ARCTIS_1 }, + HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_1), + .driver_data = STEELSERIES_ARCTIS_1 }, { /* SteelSeries Arctis 9 Wireless for XBox */ - HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, 0x12c2), + HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_9), .driver_data = STEELSERIES_ARCTIS_9 }, { } From 1860b13beca829c056179c63530eebfec9a3efb4 Mon Sep 17 00:00:00 2001 From: Liu Song Date: Thu, 24 Jul 2025 10:36:26 +0800 Subject: [PATCH 0041/2711] HID: Intel-thc-hid: Intel-thc: Use str_true_false() helper Remove hard-coded strings by using the str_true_false() helper function. Signed-off-by: Liu Song Reviewed-by: Even Xu Signed-off-by: Jiri Kosina --- drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c index 6f2263869b20..2b794bb481a0 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "intel-thc-dev.h" #include "intel-thc-hw.h" @@ -664,7 +665,7 @@ int thc_interrupt_quiesce(const struct thc_device *dev, bool int_quiesce) if (ret) { dev_err_once(dev->dev, "Timeout while waiting THC idle, target quiesce state = %s\n", - int_quiesce ? "true" : "false"); + str_true_false(int_quiesce)); return ret; } From b31e3bd7447a6e826c27bd2b1eeb26b8af73551c Mon Sep 17 00:00:00 2001 From: Liu Song Date: Thu, 24 Jul 2025 10:38:16 +0800 Subject: [PATCH 0042/2711] HID: uclogic: Use str_true_false() helper Remove hard-coded strings by using the str_true_false() helper function. Signed-off-by: Liu Song Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 4a17f7332c3f..ffa14a4621ef 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -20,6 +20,7 @@ #include #include #include +#include /** * uclogic_params_pen_inrange_to_str() - Convert a pen in-range reporting type @@ -59,7 +60,7 @@ static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev, size_t i; hid_dbg(hdev, "\t.usage_invalid = %s\n", - (pen->usage_invalid ? "true" : "false")); + str_true_false(pen->usage_invalid)); hid_dbg(hdev, "\t.desc_ptr = %p\n", pen->desc_ptr); hid_dbg(hdev, "\t.desc_size = %u\n", pen->desc_size); hid_dbg(hdev, "\t.id = %u\n", pen->id); @@ -74,9 +75,9 @@ static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev, hid_dbg(hdev, "\t.inrange = %s\n", uclogic_params_pen_inrange_to_str(pen->inrange)); hid_dbg(hdev, "\t.fragmented_hires = %s\n", - (pen->fragmented_hires ? "true" : "false")); + str_true_false(pen->fragmented_hires)); hid_dbg(hdev, "\t.tilt_y_flipped = %s\n", - (pen->tilt_y_flipped ? "true" : "false")); + str_true_false(pen->tilt_y_flipped)); } /** @@ -119,8 +120,7 @@ void uclogic_params_hid_dbg(const struct hid_device *hdev, { size_t i; - hid_dbg(hdev, ".invalid = %s\n", - params->invalid ? "true" : "false"); + hid_dbg(hdev, ".invalid = %s\n", str_true_false(params->invalid)); hid_dbg(hdev, ".desc_ptr = %p\n", params->desc_ptr); hid_dbg(hdev, ".desc_size = %u\n", params->desc_size); hid_dbg(hdev, ".pen = {\n"); From 5a5f478ed7c7394dadb65a96f409e0749caefed5 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 11 Aug 2025 22:11:34 -0500 Subject: [PATCH 0043/2711] clk: qcom: dispcc-sc7280: Add dispcc resets Like many other platforms the sc7280 display clock controller provides a couple of resets for the display subsystem. In particular the MDSS_CORE_BCR is useful to reset the display subsystem to a known state during boot, so add these. Signed-off-by: Bjorn Andersson Reviewed-by: Taniya Das Link: https://lore.kernel.org/r/20250811-sc7280-mdss-reset-v1-2-83ceff1d48de@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/dispcc-sc7280.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/qcom/dispcc-sc7280.c b/drivers/clk/qcom/dispcc-sc7280.c index 8bdf57734a3d..465dc06c8712 100644 --- a/drivers/clk/qcom/dispcc-sc7280.c +++ b/drivers/clk/qcom/dispcc-sc7280.c @@ -17,6 +17,7 @@ #include "clk-regmap-divider.h" #include "common.h" #include "gdsc.h" +#include "reset.h" enum { P_BI_TCXO, @@ -847,6 +848,11 @@ static struct gdsc *disp_cc_sc7280_gdscs[] = { [DISP_CC_MDSS_CORE_GDSC] = &disp_cc_mdss_core_gdsc, }; +static const struct qcom_reset_map disp_cc_sc7280_resets[] = { + [DISP_CC_MDSS_CORE_BCR] = { 0x1000 }, + [DISP_CC_MDSS_RSCC_BCR] = { 0x2000 }, +}; + static const struct regmap_config disp_cc_sc7280_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -861,6 +867,8 @@ static const struct qcom_cc_desc disp_cc_sc7280_desc = { .num_clks = ARRAY_SIZE(disp_cc_sc7280_clocks), .gdscs = disp_cc_sc7280_gdscs, .num_gdscs = ARRAY_SIZE(disp_cc_sc7280_gdscs), + .resets = disp_cc_sc7280_resets, + .num_resets = ARRAY_SIZE(disp_cc_sc7280_resets), }; static const struct of_device_id disp_cc_sc7280_match_table[] = { From 8b63fee9f62361a7d96394611ba05734ec21e2eb Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 25 Jul 2025 18:11:00 +0800 Subject: [PATCH 0044/2711] soundwire: debugfs: add SCP_SDCA_IntStatX and SCP_SDCA_IntMaskX registers This patch added SCP_SDCA_IntStatX and SCP_SDCA_IntMaskX registers. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20250725101100.1106673-1-shumingf@realtek.com Signed-off-by: Vinod Koul --- drivers/soundwire/debugfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c index 230a51489486..1e0f9318b616 100644 --- a/drivers/soundwire/debugfs.c +++ b/drivers/soundwire/debugfs.c @@ -91,6 +91,8 @@ static int sdw_slave_reg_show(struct seq_file *s_file, void *data) ret += sdw_sprintf(slave, buf, ret, i); for (i = SDW_SCP_DEVID_0; i <= SDW_SCP_DEVID_5; i++) ret += sdw_sprintf(slave, buf, ret, i); + for (i = SDW_SCP_SDCA_INT1; i <= SDW_SCP_SDCA_INTMASK4; i++) + ret += sdw_sprintf(slave, buf, ret, i); for (i = SDW_SCP_FRAMECTRL_B0; i <= SDW_SCP_BUSCLOCK_SCALE_B0; i++) ret += sdw_sprintf(slave, buf, ret, i); for (i = SDW_SCP_FRAMECTRL_B1; i <= SDW_SCP_BUSCLOCK_SCALE_B1; i++) From 22fb4ad898853323f4943de3e0dc555915547ccc Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Mon, 11 Aug 2025 20:25:19 +0800 Subject: [PATCH 0045/2711] cxl/hdm: Use str_plural() to simplify the code Use the string choice helper function str_plural() to simplify the code. Signed-off-by: Xichao Zhao Reviewed-by: Alison Schofield Reviewed-by: Dave Jiang Link: https://patch.msgid.link/20250811122519.543554-1-zhao.xichao@vivo.com Signed-off-by: Dave Jiang --- drivers/cxl/core/hdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index e9e1d555cec6..37176c0a781f 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -197,7 +197,7 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, */ if (should_emulate_decoders(info)) { dev_dbg(dev, "Fallback map %d range register%s\n", info->ranges, - info->ranges > 1 ? "s" : ""); + str_plural(info->ranges)); cxlhdm->decoder_count = info->ranges; } From 733c4e9bcec9c481afee3891218277d9ecd06599 Mon Sep 17 00:00:00 2001 From: Nai-Chen Cheng Date: Tue, 12 Aug 2025 00:49:46 +0800 Subject: [PATCH 0046/2711] cxl/region: use str_enabled_disabled() instead of ternary operator Replace ternary operator with str_enabled_disabled() helper to enhance code readability and consistency. [dj: Fix spelling in commit log and subject. ] Signed-off-by: Nai-Chen Cheng Reviewed-by: Alison Schofield Link: https://patch.msgid.link/20250812-cxl-region-string-choices-v1-1-50200b0bc782@gmail.com Signed-off-by: Dave Jiang --- drivers/cxl/core/region.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 71cc42d05248..83d58787b5af 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include "core.h" @@ -1468,9 +1469,7 @@ static int cxl_port_setup_targets(struct cxl_port *port, dev_name(port->uport_dev), dev_name(&port->dev), __func__, cxld->interleave_ways, cxld->interleave_granularity, - (cxld->flags & CXL_DECODER_F_ENABLE) ? - "enabled" : - "disabled", + str_enabled_disabled(cxld->flags & CXL_DECODER_F_ENABLE), cxld->hpa_range.start, cxld->hpa_range.end); return -ENXIO; } From 534b9bdeb4b80d843ca9f924524d4d103ad6605e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 Jun 2025 22:52:45 -0700 Subject: [PATCH 0047/2711] Input: tca6416-keypad - remove the driver This input driver predates proper GPIO driver for the chip and now can be replaced with the generic gpio-keys. Remove the driver. Link: https://lore.kernel.org/r/ajfsei3keh4jjasd4lshjicgqixew7bak3cmty3suoliskzgz4@vj3ijycfxy4i Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 18 -- drivers/input/keyboard/Makefile | 1 - drivers/input/keyboard/tca6416-keypad.c | 305 ------------------------ include/linux/tca6416_keypad.h | 30 --- 4 files changed, 354 deletions(-) delete mode 100644 drivers/input/keyboard/tca6416-keypad.c delete mode 100644 include/linux/tca6416_keypad.h diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 7c4f309a4cb6..f3474026d192 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -262,24 +262,6 @@ config KEYBOARD_GPIO_POLLED To compile this driver as a module, choose M here: the module will be called gpio_keys_polled. -config KEYBOARD_TCA6416 - tristate "TCA6416/TCA6408A Keypad Support" - depends on I2C - help - This driver implements basic keypad functionality - for keys connected through TCA6416/TCA6408A IO expanders. - - Say Y here if your device has keys connected to - TCA6416/TCA6408A IO expander. Your board-specific setup logic - must also provide pin-mask details(of which TCA6416 pins - are used for keypad). - - If enabled the entire TCA6416 device will be managed through - this driver. - - To compile this driver as a module, choose M here: the - module will be called tca6416_keypad. - config KEYBOARD_TCA8418 tristate "TCA8418 Keypad Support" depends on I2C diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 8bc20ab2b103..c0134da14580 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o -obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c deleted file mode 100644 index fbc674d7b9f0..000000000000 --- a/drivers/input/keyboard/tca6416-keypad.c +++ /dev/null @@ -1,305 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for keys on TCA6416 I2C IO expander - * - * Copyright (C) 2010 Texas Instruments - * - * Author : Sriramakrishnan.A.G. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TCA6416_INPUT 0 -#define TCA6416_OUTPUT 1 -#define TCA6416_INVERT 2 -#define TCA6416_DIRECTION 3 - -#define TCA6416_POLL_INTERVAL 100 /* msec */ - -static const struct i2c_device_id tca6416_id[] = { - { "tca6416-keys", 16, }, - { "tca6408-keys", 8, }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tca6416_id); - -struct tca6416_keypad_chip { - uint16_t reg_output; - uint16_t reg_direction; - uint16_t reg_input; - - struct i2c_client *client; - struct input_dev *input; - int io_size; - u16 pinmask; - bool use_polling; - struct tca6416_button buttons[]; -}; - -static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val) -{ - int error; - - error = chip->io_size > 8 ? - i2c_smbus_write_word_data(chip->client, reg << 1, val) : - i2c_smbus_write_byte_data(chip->client, reg, val); - if (error < 0) { - dev_err(&chip->client->dev, - "%s failed, reg: %d, val: %d, error: %d\n", - __func__, reg, val, error); - return error; - } - - return 0; -} - -static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val) -{ - int retval; - - retval = chip->io_size > 8 ? - i2c_smbus_read_word_data(chip->client, reg << 1) : - i2c_smbus_read_byte_data(chip->client, reg); - if (retval < 0) { - dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n", - __func__, reg, retval); - return retval; - } - - *val = (u16)retval; - return 0; -} - -static void tca6416_keys_scan(struct input_dev *input) -{ - struct tca6416_keypad_chip *chip = input_get_drvdata(input); - u16 reg_val, val; - int error, i, pin_index; - - error = tca6416_read_reg(chip, TCA6416_INPUT, ®_val); - if (error) - return; - - reg_val &= chip->pinmask; - - /* Figure out which lines have changed */ - val = reg_val ^ chip->reg_input; - chip->reg_input = reg_val; - - for (i = 0, pin_index = 0; i < 16; i++) { - if (val & (1 << i)) { - struct tca6416_button *button = &chip->buttons[pin_index]; - unsigned int type = button->type ?: EV_KEY; - int state = ((reg_val & (1 << i)) ? 1 : 0) - ^ button->active_low; - - input_event(input, type, button->code, !!state); - input_sync(input); - } - - if (chip->pinmask & (1 << i)) - pin_index++; - } -} - -/* - * This is threaded IRQ handler and this can (and will) sleep. - */ -static irqreturn_t tca6416_keys_isr(int irq, void *dev_id) -{ - tca6416_keys_scan(dev_id); - - return IRQ_HANDLED; -} - -static int tca6416_keys_open(struct input_dev *dev) -{ - struct tca6416_keypad_chip *chip = input_get_drvdata(dev); - - if (!chip->use_polling) { - /* Get initial device state in case it has switches */ - tca6416_keys_scan(dev); - enable_irq(chip->client->irq); - } - - return 0; -} - -static void tca6416_keys_close(struct input_dev *dev) -{ - struct tca6416_keypad_chip *chip = input_get_drvdata(dev); - - if (!chip->use_polling) - disable_irq(chip->client->irq); -} - -static int tca6416_setup_registers(struct tca6416_keypad_chip *chip) -{ - int error; - - error = tca6416_read_reg(chip, TCA6416_OUTPUT, &chip->reg_output); - if (error) - return error; - - error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction); - if (error) - return error; - - /* ensure that keypad pins are set to input */ - error = tca6416_write_reg(chip, TCA6416_DIRECTION, - chip->reg_direction | chip->pinmask); - if (error) - return error; - - error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction); - if (error) - return error; - - error = tca6416_read_reg(chip, TCA6416_INPUT, &chip->reg_input); - if (error) - return error; - - chip->reg_input &= chip->pinmask; - - return 0; -} - -static int tca6416_keypad_probe(struct i2c_client *client) -{ - const struct i2c_device_id *id = i2c_client_get_device_id(client); - struct tca6416_keys_platform_data *pdata; - struct tca6416_keypad_chip *chip; - struct input_dev *input; - int error; - int i; - - /* Check functionality */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { - dev_err(&client->dev, "%s adapter not supported\n", - dev_driver_string(&client->adapter->dev)); - return -ENODEV; - } - - pdata = dev_get_platdata(&client->dev); - if (!pdata) { - dev_dbg(&client->dev, "no platform data\n"); - return -EINVAL; - } - - chip = devm_kzalloc(&client->dev, - struct_size(chip, buttons, pdata->nbuttons), - GFP_KERNEL); - if (!chip) - return -ENOMEM; - - input = devm_input_allocate_device(&client->dev); - if (!input) - return -ENOMEM; - - chip->client = client; - chip->input = input; - chip->io_size = id->driver_data; - chip->pinmask = pdata->pinmask; - chip->use_polling = pdata->use_polling; - - input->phys = "tca6416-keys/input0"; - input->name = client->name; - - input->open = tca6416_keys_open; - input->close = tca6416_keys_close; - - input->id.bustype = BUS_HOST; - input->id.vendor = 0x0001; - input->id.product = 0x0001; - input->id.version = 0x0100; - - /* Enable auto repeat feature of Linux input subsystem */ - if (pdata->rep) - __set_bit(EV_REP, input->evbit); - - for (i = 0; i < pdata->nbuttons; i++) { - unsigned int type; - - chip->buttons[i] = pdata->buttons[i]; - type = (pdata->buttons[i].type) ?: EV_KEY; - input_set_capability(input, type, pdata->buttons[i].code); - } - - input_set_drvdata(input, chip); - - /* - * Initialize cached registers from their original values. - * we can't share this chip with another i2c master. - */ - error = tca6416_setup_registers(chip); - if (error) - return error; - - if (chip->use_polling) { - error = input_setup_polling(input, tca6416_keys_scan); - if (error) { - dev_err(&client->dev, "Failed to setup polling\n"); - return error; - } - - input_set_poll_interval(input, TCA6416_POLL_INTERVAL); - } else { - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, tca6416_keys_isr, - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT | - IRQF_NO_AUTOEN, - "tca6416-keypad", input); - if (error) { - dev_dbg(&client->dev, - "Unable to claim irq %d; error %d\n", - client->irq, error); - return error; - } - } - - error = input_register_device(input); - if (error) { - dev_dbg(&client->dev, - "Unable to register input device, error: %d\n", error); - return error; - } - - i2c_set_clientdata(client, chip); - - return 0; -} - -static struct i2c_driver tca6416_keypad_driver = { - .driver = { - .name = "tca6416-keypad", - }, - .probe = tca6416_keypad_probe, - .id_table = tca6416_id, -}; - -static int __init tca6416_keypad_init(void) -{ - return i2c_add_driver(&tca6416_keypad_driver); -} - -subsys_initcall(tca6416_keypad_init); - -static void __exit tca6416_keypad_exit(void) -{ - i2c_del_driver(&tca6416_keypad_driver); -} -module_exit(tca6416_keypad_exit); - -MODULE_AUTHOR("Sriramakrishnan "); -MODULE_DESCRIPTION("Keypad driver over tca6416 IO expander"); -MODULE_LICENSE("GPL"); diff --git a/include/linux/tca6416_keypad.h b/include/linux/tca6416_keypad.h deleted file mode 100644 index 5cf6f6f82aa7..000000000000 --- a/include/linux/tca6416_keypad.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * tca6416 keypad platform support - * - * Copyright (C) 2010 Texas Instruments - * - * Author: Sriramakrishnan - */ - -#ifndef _TCA6416_KEYS_H -#define _TCA6416_KEYS_H - -#include - -struct tca6416_button { - /* Configuration parameters */ - int code; /* input event code (KEY_*, SW_*) */ - int active_low; - int type; /* input event type (EV_KEY, EV_SW) */ -}; - -struct tca6416_keys_platform_data { - struct tca6416_button *buttons; - int nbuttons; - unsigned int rep:1; /* enable input subsystem auto repeat */ - uint16_t pinmask; - uint16_t invert; - int use_polling; /* use polling if Interrupt is not connected*/ -}; -#endif From c12e371a31d6a835d28330d582e953ae94c2e3e2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 Jun 2025 23:03:37 -0700 Subject: [PATCH 0048/2711] Input: tca8418_keypad - switch to using module_i2c_driver() With kernel supporting deferred probing there is no longer need to play games with different initcall levels trying to influence probe order. Switch the driver to use standard module_i2c_driver() to register the driver. Link: https://lore.kernel.org/r/dhb2wzrhspbjh2gbt3iny7odsrpq2bbqldq276zuxwc4bnhgbl@qkbxj6yrihqv Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca8418_keypad.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 76fc19ffe21d..68c0afafee7b 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -373,18 +373,7 @@ static struct i2c_driver tca8418_keypad_driver = { .probe = tca8418_keypad_probe, .id_table = tca8418_id, }; - -static int __init tca8418_keypad_init(void) -{ - return i2c_add_driver(&tca8418_keypad_driver); -} -subsys_initcall(tca8418_keypad_init); - -static void __exit tca8418_keypad_exit(void) -{ - i2c_del_driver(&tca8418_keypad_driver); -} -module_exit(tca8418_keypad_exit); +module_i2c_driver(tca8418_keypad_driver); MODULE_AUTHOR("Kyle Manna "); MODULE_DESCRIPTION("Keypad driver for TCA8418"); From 524b2b76f365fb90a7f894ac17261ea760464e2c Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 4 Aug 2025 01:00:09 -0700 Subject: [PATCH 0049/2711] cxl: Move hpa_to_spa callback to a new root decoder ops structure The root decoder's HPA to SPA translation logic was implemented using a single function pointer. In preparation for additional per-decoder callbacks, convert this into a struct cxl_rd_ops and move the hpa_to_spa pointer into it. To avoid maintaining a static ops instance populated with mostly NULL pointers, allocate the ops structure dynamically only when a platform requires overrides (e.g. XOR interleave decoding). The setup can be extended as additional callbacks are added. Co-developed-by: Dave Jiang Signed-off-by: Alison Schofield Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/818530c82c351a9c0d3a204f593068dd2126a5a9.1754290144.git.alison.schofield@intel.com Signed-off-by: Dave Jiang --- drivers/cxl/acpi.c | 10 +++++++--- drivers/cxl/core/port.c | 1 + drivers/cxl/core/region.c | 11 ++++++++--- drivers/cxl/cxl.h | 12 +++++++++--- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 712624cba2b6..b8d69460a368 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -20,7 +20,6 @@ static const guid_t acpi_cxl_qtg_id_guid = GUID_INIT(0xF365F9A6, 0xA7DE, 0x4071, 0xA6, 0x6A, 0xB4, 0x0C, 0x0B, 0x4F, 0x8E, 0x52); - static u64 cxl_xor_hpa_to_spa(struct cxl_root_decoder *cxlrd, u64 hpa) { struct cxl_cxims_data *cximsd = cxlrd->platform_data; @@ -472,8 +471,13 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws, cxlrd->qos_class = cfmws->qtg_id; - if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_XOR) - cxlrd->hpa_to_spa = cxl_xor_hpa_to_spa; + if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_XOR) { + cxlrd->ops = kzalloc(sizeof(*cxlrd->ops), GFP_KERNEL); + if (!cxlrd->ops) + return -ENOMEM; + + cxlrd->ops->hpa_to_spa = cxl_xor_hpa_to_spa; + } rc = cxl_decoder_add(cxld, target_map); if (rc) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 29197376b18e..8f36ff413f5d 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -450,6 +450,7 @@ static void cxl_root_decoder_release(struct device *dev) if (atomic_read(&cxlrd->region_id) >= 0) memregion_free(atomic_read(&cxlrd->region_id)); __cxl_decoder_release(&cxlrd->cxlsd.cxld); + kfree(cxlrd->ops); kfree(cxlrd); } diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 71cc42d05248..06cac5d28bf1 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -2918,6 +2918,11 @@ static bool cxl_is_hpa_in_chunk(u64 hpa, struct cxl_region *cxlr, int pos) return false; } +static bool has_hpa_to_spa(struct cxl_root_decoder *cxlrd) +{ + return cxlrd->ops && cxlrd->ops->hpa_to_spa; +} + u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa) { @@ -2972,8 +2977,8 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, hpa = hpa_offset + p->res->start + p->cache_size; /* Root decoder translation overrides typical modulo decode */ - if (cxlrd->hpa_to_spa) - hpa = cxlrd->hpa_to_spa(cxlrd, hpa); + if (has_hpa_to_spa(cxlrd)) + hpa = cxlrd->ops->hpa_to_spa(cxlrd, hpa); if (!cxl_resource_contains_addr(p->res, hpa)) { dev_dbg(&cxlr->dev, @@ -2982,7 +2987,7 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, } /* Simple chunk check, by pos & gran, only applies to modulo decodes */ - if (!cxlrd->hpa_to_spa && (!cxl_is_hpa_in_chunk(hpa, cxlr, pos))) + if (!has_hpa_to_spa(cxlrd) && (!cxl_is_hpa_in_chunk(hpa, cxlr, pos))) return ULLONG_MAX; return hpa; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 847e37be42c4..4b247ab18883 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -419,27 +419,33 @@ struct cxl_switch_decoder { }; struct cxl_root_decoder; -typedef u64 (*cxl_hpa_to_spa_fn)(struct cxl_root_decoder *cxlrd, u64 hpa); +/** + * struct cxl_rd_ops - CXL root decoder callback operations + * @hpa_to_spa: Convert host physical address to system physical address + */ +struct cxl_rd_ops { + u64 (*hpa_to_spa)(struct cxl_root_decoder *cxlrd, u64 hpa); +}; /** * struct cxl_root_decoder - Static platform CXL address decoder * @res: host / parent resource for region allocations * @cache_size: extended linear cache size if exists, otherwise zero. * @region_id: region id for next region provisioning event - * @hpa_to_spa: translate CXL host-physical-address to Platform system-physical-address * @platform_data: platform specific configuration data * @range_lock: sync region autodiscovery by address range * @qos_class: QoS performance class cookie + * @ops: CXL root decoder operations * @cxlsd: base cxl switch decoder */ struct cxl_root_decoder { struct resource *res; resource_size_t cache_size; atomic_t region_id; - cxl_hpa_to_spa_fn hpa_to_spa; void *platform_data; struct mutex range_lock; int qos_class; + struct cxl_rd_ops *ops; struct cxl_switch_decoder cxlsd; }; From b83ee9614a3ec196111f0ae54335b99700f78b45 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 4 Aug 2025 01:00:10 -0700 Subject: [PATCH 0050/2711] cxl: Define a SPA->CXL HPA root decoder callback for XOR Math When DPA->SPA translation was introduced, it included a helper that applied the XOR maps to do the CXL HPA -> SPA translation for XOR region interleaves. In preparation for adding SPA->DPA address translation, introduce the reverse callback. The root decoder callback is defined generically and not all usages may be self inverting like this XOR function. Add another root decoder callback that is the spa_to_hpa function. Update the existing cxl_xor_hpa_to_spa() with a name that reflects what it does without directionality: cxl_apply_xor_maps(), a generic parameter: addr replaces hpa, and code comments stating that the function supports the translation in either direction. Signed-off-by: Alison Schofield Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/79d9d72230c599cae94d7221781ead6392ae6d3f.1754290144.git.alison.schofield@intel.com Signed-off-by: Dave Jiang --- drivers/cxl/acpi.c | 27 ++++++++++++++++----------- drivers/cxl/cxl.h | 2 ++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index b8d69460a368..f1625212b08b 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -20,7 +20,7 @@ static const guid_t acpi_cxl_qtg_id_guid = GUID_INIT(0xF365F9A6, 0xA7DE, 0x4071, 0xA6, 0x6A, 0xB4, 0x0C, 0x0B, 0x4F, 0x8E, 0x52); -static u64 cxl_xor_hpa_to_spa(struct cxl_root_decoder *cxlrd, u64 hpa) +static u64 cxl_apply_xor_maps(struct cxl_root_decoder *cxlrd, u64 addr) { struct cxl_cxims_data *cximsd = cxlrd->platform_data; int hbiw = cxlrd->cxlsd.nr_targets; @@ -29,19 +29,23 @@ static u64 cxl_xor_hpa_to_spa(struct cxl_root_decoder *cxlrd, u64 hpa) /* No xormaps for host bridge interleave ways of 1 or 3 */ if (hbiw == 1 || hbiw == 3) - return hpa; + return addr; /* - * For root decoders using xormaps (hbiw: 2,4,6,8,12,16) restore - * the position bit to its value before the xormap was applied at - * HPA->DPA translation. + * In regions using XOR interleave arithmetic the CXL HPA may not + * be the same as the SPA. This helper performs the SPA->CXL HPA + * or the CXL HPA->SPA translation. Since XOR is self-inverting, + * so is this function. + * + * For root decoders using xormaps (hbiw: 2,4,6,8,12,16) applying the + * xormaps will toggle a position bit. * * pos is the lowest set bit in an XORMAP - * val is the XORALLBITS(HPA & XORMAP) + * val is the XORALLBITS(addr & XORMAP) * * XORALLBITS: The CXL spec (3.1 Table 9-22) defines XORALLBITS * as an operation that outputs a single bit by XORing all the - * bits in the input (hpa & xormap). Implement XORALLBITS using + * bits in the input (addr & xormap). Implement XORALLBITS using * hweight64(). If the hamming weight is even the XOR of those * bits results in val==0, if odd the XOR result is val==1. */ @@ -50,11 +54,11 @@ static u64 cxl_xor_hpa_to_spa(struct cxl_root_decoder *cxlrd, u64 hpa) if (!cximsd->xormaps[i]) continue; pos = __ffs(cximsd->xormaps[i]); - val = (hweight64(hpa & cximsd->xormaps[i]) & 1); - hpa = (hpa & ~(1ULL << pos)) | (val << pos); + val = (hweight64(addr & cximsd->xormaps[i]) & 1); + addr = (addr & ~(1ULL << pos)) | (val << pos); } - return hpa; + return addr; } struct cxl_cxims_context { @@ -476,7 +480,8 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws, if (!cxlrd->ops) return -ENOMEM; - cxlrd->ops->hpa_to_spa = cxl_xor_hpa_to_spa; + cxlrd->ops->hpa_to_spa = cxl_apply_xor_maps; + cxlrd->ops->spa_to_hpa = cxl_apply_xor_maps; } rc = cxl_decoder_add(cxld, target_map); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 4b247ab18883..4fe3df06f57a 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -422,9 +422,11 @@ struct cxl_root_decoder; /** * struct cxl_rd_ops - CXL root decoder callback operations * @hpa_to_spa: Convert host physical address to system physical address + * @spa_to_hpa: Convert system physical address to host physical address */ struct cxl_rd_ops { u64 (*hpa_to_spa)(struct cxl_root_decoder *cxlrd, u64 hpa); + u64 (*spa_to_hpa)(struct cxl_root_decoder *cxlrd, u64 spa); }; /** From dc181170491bda9944f95ca39017667fe7fd767d Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 4 Aug 2025 01:00:11 -0700 Subject: [PATCH 0051/2711] cxl/region: Introduce SPA to DPA address translation Add infrastructure to translate System Physical Addresses (SPA) to Device Physical Addresses (DPA) within CXL regions. This capability will be used by follow-on patches that add poison inject and clear operations at the region level. The SPA-to-DPA translation process follows these steps: 1. Apply root decoder transformations (SPA to HPA) if configured. 2. Extract the position in region interleave from the HPA offset. 3. Extract the DPA offset from the HPA offset. 4. Use position to find endpoint decoder. 5. Use endpoint decoder to find memdev and calculate DPA from offset. 6. Return the result - a memdev and a DPA. It is Step 1 above that makes this a driver level operation and not work we can push to user space. Rather than exporting the XOR maps for root decoders configured with XOR interleave, the driver performs this complex calculation for the user. Steps 2 and 3 follow the CXL Spec 3.2 Section 8.2.4.20.13 Implementation Note: Device Decode Logic. These calculations mirror much of the logic introduced earlier in DPA to SPA translation, see cxl_dpa_to_hpa(), where the driver needed to reverse the spec defined 'Device Decode Logic'. Signed-off-by: Alison Schofield Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/422f0e27742c6ca9a11f7cd83e6ba9fa1a8d0c74.1754290144.git.alison.schofield@intel.com Signed-off-by: Dave Jiang --- drivers/cxl/core/region.c | 101 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 06cac5d28bf1..f492d1291e72 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -2923,6 +2923,11 @@ static bool has_hpa_to_spa(struct cxl_root_decoder *cxlrd) return cxlrd->ops && cxlrd->ops->hpa_to_spa; } +static bool has_spa_to_hpa(struct cxl_root_decoder *cxlrd) +{ + return cxlrd->ops && cxlrd->ops->spa_to_hpa; +} + u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa) { @@ -2993,6 +2998,102 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, return hpa; } +struct dpa_result { + struct cxl_memdev *cxlmd; + u64 dpa; +}; + +static int __maybe_unused region_offset_to_dpa_result(struct cxl_region *cxlr, + u64 offset, + struct dpa_result *result) +{ + struct cxl_region_params *p = &cxlr->params; + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); + struct cxl_endpoint_decoder *cxled; + u64 hpa, hpa_offset, dpa_offset; + u64 bits_upper, bits_lower; + u64 shifted, rem, temp; + u16 eig = 0; + u8 eiw = 0; + int pos; + + lockdep_assert_held(&cxl_rwsem.region); + lockdep_assert_held(&cxl_rwsem.dpa); + + /* Input validation ensures valid ways and gran */ + granularity_to_eig(p->interleave_granularity, &eig); + ways_to_eiw(p->interleave_ways, &eiw); + + /* + * If the root decoder has SPA to CXL HPA callback, use it. Otherwise + * CXL HPA is assumed to equal SPA. + */ + if (has_spa_to_hpa(cxlrd)) { + hpa = cxlrd->ops->spa_to_hpa(cxlrd, p->res->start + offset); + hpa_offset = hpa - p->res->start; + } else { + hpa_offset = offset; + } + /* + * Interleave position: CXL Spec 3.2 Section 8.2.4.20.13 + * eiw < 8 + * Position is in the IW bits at HPA_OFFSET[IG+8+IW-1:IG+8]. + * Per spec "remove IW bits starting with bit position IG+8" + * eiw >= 8 + * Position is not explicitly stored in HPA_OFFSET bits. It is + * derived from the modulo operation of the upper bits using + * the total number of interleave ways. + */ + if (eiw < 8) { + pos = (hpa_offset >> (eig + 8)) & GENMASK(eiw - 1, 0); + } else { + shifted = hpa_offset >> (eig + 8); + div64_u64_rem(shifted, p->interleave_ways, &rem); + pos = rem; + } + if (pos < 0 || pos >= p->nr_targets) { + dev_dbg(&cxlr->dev, "Invalid position %d for %d targets\n", + pos, p->nr_targets); + return -ENXIO; + } + + /* + * DPA offset: CXL Spec 3.2 Section 8.2.4.20.13 + * Lower bits [IG+7:0] pass through unchanged + * (eiw < 8) + * Per spec: DPAOffset[51:IG+8] = (HPAOffset[51:IG+IW+8] >> IW) + * Clear the position bits to isolate upper section, then + * reverse the left shift by eiw that occurred during DPA->HPA + * (eiw >= 8) + * Per spec: DPAOffset[51:IG+8] = HPAOffset[51:IG+IW] / 3 + * Extract upper bits from the correct bit range and divide by 3 + * to recover the original DPA upper bits + */ + bits_lower = hpa_offset & GENMASK_ULL(eig + 7, 0); + if (eiw < 8) { + temp = hpa_offset &= ~((u64)GENMASK(eig + eiw + 8 - 1, 0)); + dpa_offset = temp >> eiw; + } else { + bits_upper = div64_u64(hpa_offset >> (eig + eiw), 3); + dpa_offset = bits_upper << (eig + 8); + } + dpa_offset |= bits_lower; + + /* Look-up and return the result: a memdev and a DPA */ + for (int i = 0; i < p->nr_targets; i++) { + cxled = p->targets[i]; + if (cxled->pos != pos) + continue; + result->cxlmd = cxled_to_memdev(cxled); + result->dpa = cxl_dpa_resource_start(cxled) + dpa_offset; + + return 0; + } + dev_err(&cxlr->dev, "No device found for position %d\n", pos); + + return -ENXIO; +} + static struct lock_class_key cxl_pmem_region_key; static int cxl_pmem_region_alloc(struct cxl_region *cxlr) From 25a0207828bc52f1ebb6588f9417eb43ca4960a3 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 4 Aug 2025 01:00:12 -0700 Subject: [PATCH 0052/2711] cxl/core: Add locked variants of the poison inject and clear funcs The core functions that validate and send inject and clear commands to the memdev devices require holding both the dpa_rwsem and the region_rwsem. In preparation for another caller of these functions that must hold the locks upon entry, split the work into a locked and unlocked pair. Consideration was given to moving the locking to both callers, however, the existing caller is not in the core (mem.c) and cannot access the locks. Signed-off-by: Alison Schofield Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/1d601f586975195733984ca63d1b5789bbe8690f.1754290144.git.alison.schofield@intel.com Signed-off-by: Dave Jiang --- drivers/cxl/core/memdev.c | 52 +++++++++++++++++++++++++++------------ drivers/cxl/cxlmem.h | 2 ++ 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index c569e00a511f..90d3390d9c7c 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -276,7 +276,7 @@ static int cxl_validate_poison_dpa(struct cxl_memdev *cxlmd, u64 dpa) return 0; } -int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa) +int cxl_inject_poison_locked(struct cxl_memdev *cxlmd, u64 dpa) { struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; struct cxl_mbox_inject_poison inject; @@ -288,13 +288,8 @@ int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa) if (!IS_ENABLED(CONFIG_DEBUG_FS)) return 0; - ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); - if ((rc = ACQUIRE_ERR(rwsem_read_intr, ®ion_rwsem))) - return rc; - - ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); - if ((rc = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) - return rc; + lockdep_assert_held(&cxl_rwsem.dpa); + lockdep_assert_held(&cxl_rwsem.region); rc = cxl_validate_poison_dpa(cxlmd, dpa); if (rc) @@ -324,9 +319,24 @@ int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa) return 0; } + +int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa) +{ + int rc; + + ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); + if ((rc = ACQUIRE_ERR(rwsem_read_intr, ®ion_rwsem))) + return rc; + + ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) + return rc; + + return cxl_inject_poison_locked(cxlmd, dpa); +} EXPORT_SYMBOL_NS_GPL(cxl_inject_poison, "CXL"); -int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa) +int cxl_clear_poison_locked(struct cxl_memdev *cxlmd, u64 dpa) { struct cxl_mailbox *cxl_mbox = &cxlmd->cxlds->cxl_mbox; struct cxl_mbox_clear_poison clear; @@ -338,13 +348,8 @@ int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa) if (!IS_ENABLED(CONFIG_DEBUG_FS)) return 0; - ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); - if ((rc = ACQUIRE_ERR(rwsem_read_intr, ®ion_rwsem))) - return rc; - - ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); - if ((rc = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) - return rc; + lockdep_assert_held(&cxl_rwsem.dpa); + lockdep_assert_held(&cxl_rwsem.region); rc = cxl_validate_poison_dpa(cxlmd, dpa); if (rc) @@ -383,6 +388,21 @@ int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa) return 0; } + +int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa) +{ + int rc; + + ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); + if ((rc = ACQUIRE_ERR(rwsem_read_intr, ®ion_rwsem))) + return rc; + + ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) + return rc; + + return cxl_clear_poison_locked(cxlmd, dpa); +} EXPORT_SYMBOL_NS_GPL(cxl_clear_poison, "CXL"); static struct attribute *cxl_memdev_attributes[] = { diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 751478dfc410..434031a0c1f7 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -869,6 +869,8 @@ int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, int cxl_trigger_poison_list(struct cxl_memdev *cxlmd); int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa); int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa); +int cxl_inject_poison_locked(struct cxl_memdev *cxlmd, u64 dpa); +int cxl_clear_poison_locked(struct cxl_memdev *cxlmd, u64 dpa); #ifdef CONFIG_CXL_EDAC_MEM_FEATURES int devm_cxl_memdev_edac_register(struct cxl_memdev *cxlmd); From c3dd67681c70cc95cc2c889b1b58a1667bb1c48b Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 4 Aug 2025 01:00:13 -0700 Subject: [PATCH 0053/2711] cxl/region: Add inject and clear poison by region offset Add CXL region debugfs attributes to inject and clear poison based on an offset into the region. These new interfaces allow users to operate on poison at the region level without needing to resolve Device Physical Addresses (DPA) or target individual memdevs. The implementation uses a new helper, region_offset_to_dpa_result() that applies decoder interleave logic, including XOR-based address decoding when applicable. Note that XOR decodes rely on driver internal xormaps which are not exposed to userspace. So, this support is not only a simplification of poison operations that could be done using existing per memdev operations, but also it enables this functionality for XOR interleaved regions for the first time. New debugfs attributes are added in /sys/kernel/debug/cxl/regionX/: inject_poison and clear_poison. These are only exposed if all memdevs participating in the region support both inject and clear commands, ensuring consistent and reliable behavior across multi-device regions. If tracing is enabled, these operations are logged as cxl_poison events in /sys/kernel/tracing/trace. The ABI documentation warns users of the significant risks that come with using these capabilities. A CXL Maturity Map update shows this user flow is now supported. Signed-off-by: Alison Schofield Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/f3fd8628ab57ea79704fb2d645902cd499c066af.1754290144.git.alison.schofield@intel.com Signed-off-by: Dave Jiang --- Documentation/ABI/testing/debugfs-cxl | 87 ++++++++++++ Documentation/driver-api/cxl/maturity-map.rst | 2 +- drivers/cxl/core/core.h | 4 + drivers/cxl/core/memdev.c | 8 ++ drivers/cxl/core/region.c | 131 +++++++++++++++++- 5 files changed, 228 insertions(+), 4 deletions(-) diff --git a/Documentation/ABI/testing/debugfs-cxl b/Documentation/ABI/testing/debugfs-cxl index e95e21f131e9..2989d4da96c1 100644 --- a/Documentation/ABI/testing/debugfs-cxl +++ b/Documentation/ABI/testing/debugfs-cxl @@ -19,6 +19,20 @@ Description: is returned to the user. The inject_poison attribute is only visible for devices supporting the capability. + TEST-ONLY INTERFACE: This interface is intended for testing + and validation purposes only. It is not a data repair mechanism + and should never be used on production systems or live data. + + DATA LOSS RISK: For CXL persistent memory (PMEM) devices, + poison injection can result in permanent data loss. Injected + poison may render data permanently inaccessible even after + clearing, as the clear operation writes zeros and does not + recover original data. + + SYSTEM STABILITY RISK: For volatile memory, poison injection + can cause kernel crashes, system instability, or unpredictable + behavior if the poisoned addresses are accessed by running code + or critical kernel structures. What: /sys/kernel/debug/cxl/memX/clear_poison Date: April, 2023 @@ -35,6 +49,79 @@ Description: The clear_poison attribute is only visible for devices supporting the capability. + TEST-ONLY INTERFACE: This interface is intended for testing + and validation purposes only. It is not a data repair mechanism + and should never be used on production systems or live data. + + CLEAR IS NOT DATA RECOVERY: This operation writes zeros to the + specified address range and removes the address from the poison + list. It does NOT recover or restore original data that may have + been present before poison injection. Any original data at the + cleared address is permanently lost and replaced with zeros. + + CLEAR IS NOT A REPAIR MECHANISM: This interface is for testing + purposes only and should not be used as a data repair tool. + Clearing poison is fundamentally different from data recovery + or error correction. + +What: /sys/kernel/debug/cxl/regionX/inject_poison +Date: August, 2025 +Contact: linux-cxl@vger.kernel.org +Description: + (WO) When a Host Physical Address (HPA) is written to this + attribute, the region driver translates it to a Device + Physical Address (DPA) and identifies the corresponding + memdev. It then sends an inject poison command to that memdev + at the translated DPA. Refer to the memdev ABI entry at: + /sys/kernel/debug/cxl/memX/inject_poison for the detailed + behavior. This attribute is only visible if all memdevs + participating in the region support both inject and clear + poison commands. + + TEST-ONLY INTERFACE: This interface is intended for testing + and validation purposes only. It is not a data repair mechanism + and should never be used on production systems or live data. + + DATA LOSS RISK: For CXL persistent memory (PMEM) devices, + poison injection can result in permanent data loss. Injected + poison may render data permanently inaccessible even after + clearing, as the clear operation writes zeros and does not + recover original data. + + SYSTEM STABILITY RISK: For volatile memory, poison injection + can cause kernel crashes, system instability, or unpredictable + behavior if the poisoned addresses are accessed by running code + or critical kernel structures. + +What: /sys/kernel/debug/cxl/regionX/clear_poison +Date: August, 2025 +Contact: linux-cxl@vger.kernel.org +Description: + (WO) When a Host Physical Address (HPA) is written to this + attribute, the region driver translates it to a Device + Physical Address (DPA) and identifies the corresponding + memdev. It then sends a clear poison command to that memdev + at the translated DPA. Refer to the memdev ABI entry at: + /sys/kernel/debug/cxl/memX/clear_poison for the detailed + behavior. This attribute is only visible if all memdevs + participating in the region support both inject and clear + poison commands. + + TEST-ONLY INTERFACE: This interface is intended for testing + and validation purposes only. It is not a data repair mechanism + and should never be used on production systems or live data. + + CLEAR IS NOT DATA RECOVERY: This operation writes zeros to the + specified address range and removes the address from the poison + list. It does NOT recover or restore original data that may have + been present before poison injection. Any original data at the + cleared address is permanently lost and replaced with zeros. + + CLEAR IS NOT A REPAIR MECHANISM: This interface is for testing + purposes only and should not be used as a data repair tool. + Clearing poison is fundamentally different from data recovery + or error correction. + What: /sys/kernel/debug/cxl/einj_types Date: January, 2024 KernelVersion: v6.9 diff --git a/Documentation/driver-api/cxl/maturity-map.rst b/Documentation/driver-api/cxl/maturity-map.rst index 1330f3f52129..282c1102dd81 100644 --- a/Documentation/driver-api/cxl/maturity-map.rst +++ b/Documentation/driver-api/cxl/maturity-map.rst @@ -173,7 +173,7 @@ Accelerator User Flow Support ----------------- -* [0] Inject & clear poison by HPA +* [2] Inject & clear poison by region offset Details ======= diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 2669f251d677..eac8cc1bdaa0 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -135,6 +135,10 @@ enum cxl_poison_trace_type { CXL_POISON_TRACE_CLEAR, }; +enum poison_cmd_enabled_bits; +bool cxl_memdev_has_poison_cmd(struct cxl_memdev *cxlmd, + enum poison_cmd_enabled_bits cmd); + long cxl_pci_get_latency(struct pci_dev *pdev); int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c); int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index 90d3390d9c7c..e370d733e440 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -200,6 +200,14 @@ static ssize_t security_erase_store(struct device *dev, static struct device_attribute dev_attr_security_erase = __ATTR(erase, 0200, NULL, security_erase_store); +bool cxl_memdev_has_poison_cmd(struct cxl_memdev *cxlmd, + enum poison_cmd_enabled_bits cmd) +{ + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); + + return test_bit(cmd, mds->poison.enabled_cmds); +} + static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd) { struct cxl_dev_state *cxlds = cxlmd->cxlds; diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index f492d1291e72..1e2911af9060 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -2,6 +2,7 @@ /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ #include #include +#include #include #include #include @@ -3003,9 +3004,8 @@ struct dpa_result { u64 dpa; }; -static int __maybe_unused region_offset_to_dpa_result(struct cxl_region *cxlr, - u64 offset, - struct dpa_result *result) +static int region_offset_to_dpa_result(struct cxl_region *cxlr, u64 offset, + struct dpa_result *result) { struct cxl_region_params *p = &cxlr->params; struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); @@ -3648,6 +3648,105 @@ static void shutdown_notifiers(void *_cxlr) unregister_mt_adistance_algorithm(&cxlr->adist_notifier); } +static void remove_debugfs(void *dentry) +{ + debugfs_remove_recursive(dentry); +} + +static int validate_region_offset(struct cxl_region *cxlr, u64 offset) +{ + struct cxl_region_params *p = &cxlr->params; + resource_size_t region_size; + u64 hpa; + + if (offset < p->cache_size) { + dev_err(&cxlr->dev, + "Offset %#llx is within extended linear cache %#llx\n", + offset, p->cache_size); + return -EINVAL; + } + + region_size = resource_size(p->res); + if (offset >= region_size) { + dev_err(&cxlr->dev, "Offset %#llx exceeds region size %#llx\n", + offset, region_size); + return -EINVAL; + } + + hpa = p->res->start + offset; + if (hpa < p->res->start || hpa > p->res->end) { + dev_err(&cxlr->dev, "HPA %#llx not in region %pr\n", hpa, + p->res); + return -EINVAL; + } + + return 0; +} + +static int cxl_region_debugfs_poison_inject(void *data, u64 offset) +{ + struct dpa_result result = { .dpa = ULLONG_MAX, .cxlmd = NULL }; + struct cxl_region *cxlr = data; + int rc; + + ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); + if ((rc = ACQUIRE_ERR(rwsem_read_intr, ®ion_rwsem))) + return rc; + + ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) + return rc; + + if (validate_region_offset(cxlr, offset)) + return -EINVAL; + + rc = region_offset_to_dpa_result(cxlr, offset, &result); + if (rc || !result.cxlmd || result.dpa == ULLONG_MAX) { + dev_dbg(&cxlr->dev, + "Failed to resolve DPA for region offset %#llx rc %d\n", + offset, rc); + + return rc ? rc : -EINVAL; + } + + return cxl_inject_poison_locked(result.cxlmd, result.dpa); +} + +DEFINE_DEBUGFS_ATTRIBUTE(cxl_poison_inject_fops, NULL, + cxl_region_debugfs_poison_inject, "%llx\n"); + +static int cxl_region_debugfs_poison_clear(void *data, u64 offset) +{ + struct dpa_result result = { .dpa = ULLONG_MAX, .cxlmd = NULL }; + struct cxl_region *cxlr = data; + int rc; + + ACQUIRE(rwsem_read_intr, region_rwsem)(&cxl_rwsem.region); + if ((rc = ACQUIRE_ERR(rwsem_read_intr, ®ion_rwsem))) + return rc; + + ACQUIRE(rwsem_read_intr, dpa_rwsem)(&cxl_rwsem.dpa); + if ((rc = ACQUIRE_ERR(rwsem_read_intr, &dpa_rwsem))) + return rc; + + if (validate_region_offset(cxlr, offset)) + return -EINVAL; + + rc = region_offset_to_dpa_result(cxlr, offset, &result); + if (rc || !result.cxlmd || result.dpa == ULLONG_MAX) { + dev_dbg(&cxlr->dev, + "Failed to resolve DPA for region offset %#llx rc %d\n", + offset, rc); + + return rc ? rc : -EINVAL; + } + + return cxl_clear_poison_locked(result.cxlmd, result.dpa); +} + +DEFINE_DEBUGFS_ATTRIBUTE(cxl_poison_clear_fops, NULL, + cxl_region_debugfs_poison_clear, "%llx\n"); + static int cxl_region_can_probe(struct cxl_region *cxlr) { struct cxl_region_params *p = &cxlr->params; @@ -3677,6 +3776,7 @@ static int cxl_region_probe(struct device *dev) { struct cxl_region *cxlr = to_cxl_region(dev); struct cxl_region_params *p = &cxlr->params; + bool poison_supported = true; int rc; rc = cxl_region_can_probe(cxlr); @@ -3700,6 +3800,31 @@ static int cxl_region_probe(struct device *dev) if (rc) return rc; + /* Create poison attributes if all memdevs support the capabilities */ + for (int i = 0; i < p->nr_targets; i++) { + struct cxl_endpoint_decoder *cxled = p->targets[i]; + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); + + if (!cxl_memdev_has_poison_cmd(cxlmd, CXL_POISON_ENABLED_INJECT) || + !cxl_memdev_has_poison_cmd(cxlmd, CXL_POISON_ENABLED_CLEAR)) { + poison_supported = false; + break; + } + } + + if (poison_supported) { + struct dentry *dentry; + + dentry = cxl_debugfs_create_dir(dev_name(dev)); + debugfs_create_file("inject_poison", 0200, dentry, cxlr, + &cxl_poison_inject_fops); + debugfs_create_file("clear_poison", 0200, dentry, cxlr, + &cxl_poison_clear_fops); + rc = devm_add_action_or_reset(dev, remove_debugfs, dentry); + if (rc) + return rc; + } + switch (cxlr->mode) { case CXL_PARTMODE_PMEM: rc = devm_cxl_region_edac_register(cxlr); From 689a54acb56858c85de8c7285db82b8ae6dbf683 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 23 Jul 2025 13:01:28 +0300 Subject: [PATCH 0054/2711] phy: cdns-dphy: Store hs_clk_rate and return it The DPHY driver does not return the actual hs_clk_rate, so the DSI driver has no idea what clock was actually achieved. Set the realized hs_clk_rate to the opts struct, so that the DSI driver gets it back. Reviewed-by: Aradhya Bhatia Tested-by: Parth Pancholi Tested-by: Jayesh Choudhary Acked-by: Vinod Koul Reviewed-by: Devarsh Thakkar Signed-off-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20250723-cdns-dphy-hs-clk-rate-fix-v1-1-d4539d44cbe7@ideasonboard.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/cdns-dphy.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index ed87a3970f83..f79ec4fab409 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -79,6 +79,7 @@ struct cdns_dphy_cfg { u8 pll_ipdiv; u8 pll_opdiv; u16 pll_fbdiv; + u32 hs_clk_rate; unsigned int nlanes; }; @@ -154,6 +155,9 @@ static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy, cfg->pll_ipdiv, pll_ref_hz); + cfg->hs_clk_rate = div_u64((u64)pll_ref_hz * cfg->pll_fbdiv, + 2 * cfg->pll_opdiv * cfg->pll_ipdiv); + return 0; } @@ -297,6 +301,7 @@ static int cdns_dphy_config_from_opts(struct phy *phy, if (ret) return ret; + opts->hs_clk_rate = cfg->hs_clk_rate; opts->wakeup = cdns_dphy_get_wakeup_time_ns(dphy) / 1000; return 0; From 2674eb7114ff37a7da55767860d49642eba39329 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 23 Jul 2025 13:01:29 +0300 Subject: [PATCH 0055/2711] phy: cdns-dphy: Remove leftover code The code in cdns-dphy has probably been part of a DSI driver in the past. Remove DSI defines and variables which are not used or do not actually do anything. Also rename cdns_dsi_get_dphy_pll_cfg() to cdns_dphy_get_pll_cfg(), i.e. drop the "dsi", as it's not relevant here. Reviewed-by: Aradhya Bhatia Tested-by: Parth Pancholi Acked-by: Vinod Koul Tested-by: Jayesh Choudhary Reviewed-by: Devarsh Thakkar Signed-off-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20250723-cdns-dphy-hs-clk-rate-fix-v1-2-d4539d44cbe7@ideasonboard.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/cdns-dphy.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index f79ec4fab409..33a42e72362e 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -55,14 +55,6 @@ #define DPHY_PSM_CFG_FROM_REG BIT(0) #define DPHY_PSM_CLK_DIV(x) ((x) << 1) -#define DSI_HBP_FRAME_OVERHEAD 12 -#define DSI_HSA_FRAME_OVERHEAD 14 -#define DSI_HFP_FRAME_OVERHEAD 6 -#define DSI_HSS_VSS_VSE_FRAME_OVERHEAD 4 -#define DSI_BLANKING_FRAME_OVERHEAD 6 -#define DSI_NULL_FRAME_OVERHEAD 6 -#define DSI_EOT_PKT_SIZE 4 - #define DPHY_TX_J721E_WIZ_PLL_CTRL 0xF04 #define DPHY_TX_J721E_WIZ_STATUS 0xF08 #define DPHY_TX_J721E_WIZ_RST_CTRL 0xF0C @@ -117,10 +109,9 @@ static const unsigned int tx_bands[] = { 870, 950, 1000, 1200, 1400, 1600, 1800, 2000, 2200, 2500 }; -static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy, - struct cdns_dphy_cfg *cfg, - struct phy_configure_opts_mipi_dphy *opts, - unsigned int *dsi_hfp_ext) +static int cdns_dphy_get_pll_cfg(struct cdns_dphy *dphy, + struct cdns_dphy_cfg *cfg, + struct phy_configure_opts_mipi_dphy *opts) { unsigned long pll_ref_hz = clk_get_rate(dphy->pll_ref_clk); u64 dlane_bps; @@ -289,15 +280,13 @@ static int cdns_dphy_config_from_opts(struct phy *phy, struct cdns_dphy_cfg *cfg) { struct cdns_dphy *dphy = phy_get_drvdata(phy); - unsigned int dsi_hfp_ext = 0; int ret; ret = phy_mipi_dphy_config_validate(opts); if (ret) return ret; - ret = cdns_dsi_get_dphy_pll_cfg(dphy, cfg, - opts, &dsi_hfp_ext); + ret = cdns_dphy_get_pll_cfg(dphy, cfg, opts); if (ret) return ret; From 497e78c7a3a069f4fc62ef501d067fea27db6af4 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Mon, 24 Feb 2025 18:10:05 +0530 Subject: [PATCH 0056/2711] phy: cadence: cdns-dphy-rx: Add runtime PM support Enable runtime power management for the device. The PHY framework handles calling pm_runtime_(get|put)_sync when powering on/off this device. Signed-off-by: Jai Luthra Link: https://lore.kernel.org/r/20250224-cdns_phy_pm-v1-1-0fe2c544cc87@ideasonboard.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/cdns-dphy-rx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/cadence/cdns-dphy-rx.c b/drivers/phy/cadence/cdns-dphy-rx.c index 7729cf80a9bd..3ac80141189c 100644 --- a/drivers/phy/cadence/cdns-dphy-rx.c +++ b/drivers/phy/cadence/cdns-dphy-rx.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define DPHY_PMA_CMN(reg) (reg) @@ -265,7 +266,7 @@ static int cdns_dphy_rx_probe(struct platform_device *pdev) return PTR_ERR(provider); } - return 0; + return devm_pm_runtime_enable(dev); } static const struct of_device_id cdns_dphy_rx_of_match[] = { From 8209b3f79703b8ff09f84a79c46ead0df7260d9f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 15:16:23 +0200 Subject: [PATCH 0057/2711] phy: ti: omap-usb2: enable compile testing Nothing seems to prevent the driver from being built on non-TI platforms so enable compile testing for wider build coverage. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724131623.2662-1-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig index b905902d5750..b40f28019131 100644 --- a/drivers/phy/ti/Kconfig +++ b/drivers/phy/ti/Kconfig @@ -62,7 +62,7 @@ config OMAP_CONTROL_PHY config OMAP_USB2 tristate "OMAP USB2 PHY Driver" - depends on ARCH_OMAP2PLUS || ARCH_K3 + depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST depends on USB_SUPPORT select GENERIC_PHY select USB_PHY From 7bb14b61b7d03db770b7e8871493f5b9b2be2b79 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 23 Jul 2025 07:23:22 +0000 Subject: [PATCH 0058/2711] phy: rockchip: naneng-combphy: Enable U3 OTG port for RK3568 The boot firmware may disable the U3 port early during boot and leave it up to the controller or PHY driver to re-enable U3 when needed. The Rockchip USBDP PHY driver currently does this for RK3576 and RK3588, something the Rockchip Naneng Combo PHY driver never does for RK3568. This may result in USB 3.0 ports being limited to only using USB 2.0 or in special cases not working at all on RK3568. Write to PIPE_GRF USB3OTGx_CON1 reg to ensure the U3 port is enabled when a PHY with PHY_TYPE_USB3 mode is used. Fixes: 7160820d742a ("phy: rockchip: add naneng combo phy for RK3568") Signed-off-by: Jonas Karlman Link: https://lore.kernel.org/r/20250723072324.2246498-1-jonas@kwiboo.se Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index ce91fb1d5167..17c6310f4b54 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -137,6 +137,8 @@ struct rockchip_combphy_grfcfg { struct combphy_reg pipe_xpcs_phy_ready; struct combphy_reg pipe_pcie1l0_sel; struct combphy_reg pipe_pcie1l1_sel; + struct combphy_reg u3otg0_port_en; + struct combphy_reg u3otg1_port_en; }; struct rockchip_combphy_cfg { @@ -594,6 +596,14 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false); rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true); + switch (priv->id) { + case 0: + rockchip_combphy_param_write(priv->pipe_grf, &cfg->u3otg0_port_en, true); + break; + case 1: + rockchip_combphy_param_write(priv->pipe_grf, &cfg->u3otg1_port_en, true); + break; + } break; case PHY_TYPE_SATA: @@ -737,6 +747,8 @@ static const struct rockchip_combphy_grfcfg rk3568_combphy_grfcfgs = { /* pipe-grf */ .pipe_con0_for_sata = { 0x0000, 15, 0, 0x00, 0x2220 }, .pipe_xpcs_phy_ready = { 0x0040, 2, 2, 0x00, 0x01 }, + .u3otg0_port_en = { 0x0104, 15, 0, 0x0181, 0x1100 }, + .u3otg1_port_en = { 0x0144, 15, 0, 0x0181, 0x1100 }, }; static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = { From 4ca28157bd52dfa6df665f8854d754cc03f45acf Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 28 Jul 2025 10:29:43 +0000 Subject: [PATCH 0059/2711] dt-bindings: soc: rockchip: Add RK3528 pipe-phy GRF syscon Add compatible string for pipe-phy GRF found on RK3528 SoC, which controls misc settings for the integrated naneng-combphy. Signed-off-by: Yao Zi Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250728102947.38984-3-ziyao@disroot.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/soc/rockchip/grf.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml index 1ab0b092e2a5..fe5361713167 100644 --- a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml +++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml @@ -16,6 +16,7 @@ properties: - enum: - rockchip,rk3288-sgrf - rockchip,rk3528-ioc-grf + - rockchip,rk3528-pipe-phy-grf - rockchip,rk3528-vo-grf - rockchip,rk3528-vpu-grf - rockchip,rk3562-ioc-grf From 43a9fade69799bd10e315e87cdc60a3f75b85414 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 28 Jul 2025 10:29:44 +0000 Subject: [PATCH 0060/2711] dt-bindings: phy: rockchip: naneng-combphy: Add power-domains property Though isn't described in existing devicetrees, most Rockchip combphys belong to a specific power-domain of the SoC. Taking RK3588 as example, combphy 0 and combphy 2 belong to the PD_BUS domain. Document the power-domains property to allow describing the information correctly in devicetree. Signed-off-by: Yao Zi Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250728102947.38984-4-ziyao@disroot.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml index 3e101c3c5ea9..db293d2fbf1a 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml @@ -45,6 +45,9 @@ properties: phy-supply: description: Single PHY regulator + power-domains: + maxItems: 1 + rockchip,enable-ssc: type: boolean description: From b6c02cba32b9902b2b51dee740f1d3af8271820a Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 28 Jul 2025 10:29:45 +0000 Subject: [PATCH 0061/2711] dt-bindings: phy: rockchip: naneng-combphy: Add RK3528 variant Rockchip RK3528 ships one naneng-combphy which operates in either PCIe or USB 3 mode. Document its compatible string. Signed-off-by: Yao Zi Acked-by: Conor Dooley Reviewed-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250728102947.38984-5-ziyao@disroot.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml index db293d2fbf1a..379b08bd9e97 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml @@ -12,6 +12,7 @@ maintainers: properties: compatible: enum: + - rockchip,rk3528-naneng-combphy - rockchip,rk3562-naneng-combphy - rockchip,rk3568-naneng-combphy - rockchip,rk3576-naneng-combphy @@ -108,7 +109,9 @@ allOf: properties: compatible: contains: - const: rockchip,rk3588-naneng-combphy + enum: + - rockchip,rk3528-naneng-combphy + - rockchip,rk3588-naneng-combphy then: properties: resets: From b3bbc6afcff50e2fd4d51dd64929e62d66fdc814 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 28 Jul 2025 10:29:46 +0000 Subject: [PATCH 0062/2711] phy: rockchip: naneng-combphy: Add SoC prefix to register definitions All supported variants of naneng-combphy follow a register layout similar to the RK3568 variant with some exceptions of SoC-specific registers. Add RK3568 prefix for the common set of registers and the corresponding SoC prefix for SoC-specific registers, making usage of definitions clear and preparing for future COMBPHY variants with a different register layout. Signed-off-by: Yao Zi Reviewed-by: Heiko Stuebner Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250728102947.38984-6-ziyao@disroot.org Signed-off-by: Vinod Koul --- .../rockchip/phy-rockchip-naneng-combphy.c | 522 +++++++++--------- 1 file changed, 269 insertions(+), 253 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 17c6310f4b54..ce84166cd772 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -21,78 +21,80 @@ #define REF_CLOCK_100MHz (100 * HZ_PER_MHZ) /* COMBO PHY REG */ -#define PHYREG6 0x14 -#define PHYREG6_PLL_DIV_MASK GENMASK(7, 6) -#define PHYREG6_PLL_DIV_SHIFT 6 -#define PHYREG6_PLL_DIV_2 1 +#define RK3568_PHYREG6 0x14 +#define RK3568_PHYREG6_PLL_DIV_MASK GENMASK(7, 6) +#define RK3568_PHYREG6_PLL_DIV_SHIFT 6 +#define RK3568_PHYREG6_PLL_DIV_2 1 -#define PHYREG7 0x18 -#define PHYREG7_TX_RTERM_MASK GENMASK(7, 4) -#define PHYREG7_TX_RTERM_SHIFT 4 -#define PHYREG7_TX_RTERM_50OHM 8 -#define PHYREG7_RX_RTERM_MASK GENMASK(3, 0) -#define PHYREG7_RX_RTERM_SHIFT 0 -#define PHYREG7_RX_RTERM_44OHM 15 +#define RK3568_PHYREG7 0x18 +#define RK3568_PHYREG7_TX_RTERM_MASK GENMASK(7, 4) +#define RK3568_PHYREG7_TX_RTERM_SHIFT 4 +#define RK3568_PHYREG7_TX_RTERM_50OHM 8 +#define RK3568_PHYREG7_RX_RTERM_MASK GENMASK(3, 0) +#define RK3568_PHYREG7_RX_RTERM_SHIFT 0 +#define RK3568_PHYREG7_RX_RTERM_44OHM 15 -#define PHYREG8 0x1C -#define PHYREG8_SSC_EN BIT(4) +#define RK3568_PHYREG8 0x1C +#define RK3568_PHYREG8_SSC_EN BIT(4) -#define PHYREG10 0x24 -#define PHYREG10_SSC_PCM_MASK GENMASK(3, 0) -#define PHYREG10_SSC_PCM_3500PPM 7 +#define RK3568_PHYREG11 0x28 +#define RK3568_PHYREG11_SU_TRIM_0_7 0xF0 -#define PHYREG11 0x28 -#define PHYREG11_SU_TRIM_0_7 0xF0 +#define RK3568_PHYREG12 0x2C +#define RK3568_PHYREG12_PLL_LPF_ADJ_VALUE 4 -#define PHYREG12 0x2C -#define PHYREG12_PLL_LPF_ADJ_VALUE 4 +#define RK3568_PHYREG13 0x30 +#define RK3568_PHYREG13_RESISTER_MASK GENMASK(5, 4) +#define RK3568_PHYREG13_RESISTER_SHIFT 0x4 +#define RK3568_PHYREG13_RESISTER_HIGH_Z 3 +#define RK3568_PHYREG13_CKRCV_AMP0 BIT(7) -#define PHYREG13 0x30 -#define PHYREG13_RESISTER_MASK GENMASK(5, 4) -#define PHYREG13_RESISTER_SHIFT 0x4 -#define PHYREG13_RESISTER_HIGH_Z 3 -#define PHYREG13_CKRCV_AMP0 BIT(7) +#define RK3568_PHYREG14 0x34 +#define RK3568_PHYREG14_CKRCV_AMP1 BIT(0) -#define PHYREG14 0x34 -#define PHYREG14_CKRCV_AMP1 BIT(0) +#define RK3568_PHYREG15 0x38 +#define RK3568_PHYREG15_CTLE_EN BIT(0) +#define RK3568_PHYREG15_SSC_CNT_MASK GENMASK(7, 6) +#define RK3568_PHYREG15_SSC_CNT_SHIFT 6 +#define RK3568_PHYREG15_SSC_CNT_VALUE 1 -#define PHYREG15 0x38 -#define PHYREG15_CTLE_EN BIT(0) -#define PHYREG15_SSC_CNT_MASK GENMASK(7, 6) -#define PHYREG15_SSC_CNT_SHIFT 6 -#define PHYREG15_SSC_CNT_VALUE 1 +#define RK3568_PHYREG16 0x3C +#define RK3568_PHYREG16_SSC_CNT_VALUE 0x5f -#define PHYREG16 0x3C -#define PHYREG16_SSC_CNT_VALUE 0x5f +#define RK3568_PHYREG18 0x44 +#define RK3568_PHYREG18_PLL_LOOP 0x32 -#define PHYREG17 0x40 +#define RK3568_PHYREG32 0x7C +#define RK3568_PHYREG32_SSC_MASK GENMASK(7, 4) +#define RK3568_PHYREG32_SSC_DIR_MASK GENMASK(5, 4) +#define RK3568_PHYREG32_SSC_DIR_SHIFT 4 +#define RK3568_PHYREG32_SSC_UPWARD 0 +#define RK3568_PHYREG32_SSC_DOWNWARD 1 +#define RK3568_PHYREG32_SSC_OFFSET_MASK GENMASK(7, 6) +#define RK3568_PHYREG32_SSC_OFFSET_SHIFT 6 +#define RK3568_PHYREG32_SSC_OFFSET_500PPM 1 -#define PHYREG18 0x44 -#define PHYREG18_PLL_LOOP 0x32 +#define RK3568_PHYREG33 0x80 +#define RK3568_PHYREG33_PLL_KVCO_MASK GENMASK(4, 2) +#define RK3568_PHYREG33_PLL_KVCO_SHIFT 2 +#define RK3568_PHYREG33_PLL_KVCO_VALUE 2 +#define RK3576_PHYREG33_PLL_KVCO_VALUE 4 -#define PHYREG21 0x50 -#define PHYREG21_RX_SQUELCH_VAL 0x0D +/* RK3588 COMBO PHY registers */ +#define RK3588_PHYREG27 0x6C +#define RK3588_PHYREG27_RX_TRIM 0x4C -#define PHYREG27 0x6C -#define PHYREG27_RX_TRIM_RK3588 0x4C +/* RK3576 COMBO PHY registers */ +#define RK3576_PHYREG10 0x24 +#define RK3576_PHYREG10_SSC_PCM_MASK GENMASK(3, 0) +#define RK3576_PHYREG10_SSC_PCM_3500PPM 7 -#define PHYREG30 0x74 +#define RK3576_PHYREG17 0x40 -#define PHYREG32 0x7C -#define PHYREG32_SSC_MASK GENMASK(7, 4) -#define PHYREG32_SSC_DIR_MASK GENMASK(5, 4) -#define PHYREG32_SSC_DIR_SHIFT 4 -#define PHYREG32_SSC_UPWARD 0 -#define PHYREG32_SSC_DOWNWARD 1 -#define PHYREG32_SSC_OFFSET_MASK GENMASK(7, 6) -#define PHYREG32_SSC_OFFSET_SHIFT 6 -#define PHYREG32_SSC_OFFSET_500PPM 1 +#define RK3576_PHYREG21 0x50 +#define RK3576_PHYREG21_RX_SQUELCH_VAL 0x0D -#define PHYREG33 0x80 -#define PHYREG33_PLL_KVCO_MASK GENMASK(4, 2) -#define PHYREG33_PLL_KVCO_SHIFT 2 -#define PHYREG33_PLL_KVCO_VALUE 2 -#define PHYREG33_PLL_KVCO_VALUE_RK3576 4 +#define RK3576_PHYREG30 0x74 struct rockchip_combphy_priv; @@ -407,9 +409,8 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) switch (priv->type) { case PHY_TYPE_PCIE: /* Set SSC downward spread spectrum */ - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, - PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, - PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true); @@ -418,29 +419,30 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) break; case PHY_TYPE_USB3: /* Set SSC downward spread spectrum */ - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, - PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, - PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, + RK3568_PHYREG32); /* Enable adaptive CTLE for USB3.0 Rx */ - rockchip_combphy_updatel(priv, PHYREG15_CTLE_EN, - PHYREG15_CTLE_EN, PHYREG15); + rockchip_combphy_updatel(priv, RK3568_PHYREG15_CTLE_EN, + RK3568_PHYREG15_CTLE_EN, RK3568_PHYREG15); /* Set PLL KVCO fine tuning signals */ - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, BIT(3), PHYREG33); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + BIT(3), RK3568_PHYREG33); /* Set PLL LPF R1 to su_trim[10:7]=1001 */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); /* Set PLL input clock divider 1/2 */ - val = FIELD_PREP(PHYREG6_PLL_DIV_MASK, PHYREG6_PLL_DIV_2); - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, val, PHYREG6); + val = FIELD_PREP(RK3568_PHYREG6_PLL_DIV_MASK, RK3568_PHYREG6_PLL_DIV_2); + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, val, RK3568_PHYREG6); /* Set PLL loop divider */ - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); /* Set PLL KVCO to min and set PLL charge pump current to max */ - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_sel_usb, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); @@ -458,11 +460,12 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) case REF_CLOCK_24MHz: if (priv->type == PHY_TYPE_USB3) { /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz */ - val = FIELD_PREP(PHYREG15_SSC_CNT_MASK, PHYREG15_SSC_CNT_VALUE); - rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK, - val, PHYREG15); + val = FIELD_PREP(RK3568_PHYREG15_SSC_CNT_MASK, + RK3568_PHYREG15_SSC_CNT_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG15_SSC_CNT_MASK, + val, RK3568_PHYREG15); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); } break; case REF_CLOCK_25MHz: @@ -472,19 +475,20 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { /* PLL KVCO tuning fine */ - val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE); - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3568_PHYREG33_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Enable controlling random jitter, aka RMJ */ - writel(0x4, priv->mmio + PHYREG12); + writel(0x4, priv->mmio + RK3568_PHYREG12); - val = PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT; - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, - val, PHYREG6); + val = RK3568_PHYREG6_PLL_DIV_2 << RK3568_PHYREG6_PLL_DIV_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, + val, RK3568_PHYREG6); - writel(0x32, priv->mmio + PHYREG18); - writel(0xf0, priv->mmio + PHYREG11); + writel(0x32, priv->mmio + RK3568_PHYREG18); + writel(0xf0, priv->mmio + RK3568_PHYREG11); } break; default: @@ -495,20 +499,21 @@ static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) if (priv->ext_refclk) { rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { - val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT; - val |= PHYREG13_CKRCV_AMP0; - rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13); + val = RK3568_PHYREG13_RESISTER_HIGH_Z << RK3568_PHYREG13_RESISTER_SHIFT; + val |= RK3568_PHYREG13_CKRCV_AMP0; + rockchip_combphy_updatel(priv, RK3568_PHYREG13_RESISTER_MASK, val, + RK3568_PHYREG13); - val = readl(priv->mmio + PHYREG14); - val |= PHYREG14_CKRCV_AMP1; - writel(val, priv->mmio + PHYREG14); + val = readl(priv->mmio + RK3568_PHYREG14); + val |= RK3568_PHYREG14_CKRCV_AMP1; + writel(val, priv->mmio + RK3568_PHYREG14); } } if (priv->enable_ssc) { - val = readl(priv->mmio + PHYREG8); - val |= PHYREG8_SSC_EN; - writel(val, priv->mmio + PHYREG8); + val = readl(priv->mmio + RK3568_PHYREG8); + val |= RK3568_PHYREG8_SSC_EN; + writel(val, priv->mmio + RK3568_PHYREG8); } return 0; @@ -555,9 +560,9 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) switch (priv->type) { case PHY_TYPE_PCIE: /* Set SSC downward spread spectrum. */ - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, - PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, - PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true); @@ -567,30 +572,28 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) case PHY_TYPE_USB3: /* Set SSC downward spread spectrum. */ - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, - PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, - PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT, + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); /* Enable adaptive CTLE for USB3.0 Rx. */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* Set PLL KVCO fine tuning signals. */ - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT, - PHYREG33); + val = RK3568_PHYREG33_PLL_KVCO_VALUE << RK3568_PHYREG33_PLL_KVCO_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, val, RK3568_PHYREG33); /* Enable controlling random jitter. */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); /* Set PLL input clock divider 1/2. */ - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, - PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT, - PHYREG6); + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, + RK3568_PHYREG6_PLL_DIV_2 << RK3568_PHYREG6_PLL_DIV_SHIFT, + RK3568_PHYREG6); - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_sel_usb, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); @@ -608,16 +611,16 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) case PHY_TYPE_SATA: /* Enable adaptive CTLE for SATA Rx. */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* * Set tx_rterm=50ohm and rx_rterm=44ohm for SATA. * 0: 60ohm, 8: 50ohm 15: 44ohm (by step abort 1ohm) */ - val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT; - val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT; - writel(val, priv->mmio + PHYREG7); + val = RK3568_PHYREG7_TX_RTERM_50OHM << RK3568_PHYREG7_TX_RTERM_SHIFT; + val |= RK3568_PHYREG7_RX_RTERM_44OHM << RK3568_PHYREG7_RX_RTERM_SHIFT; + writel(val, priv->mmio + RK3568_PHYREG7); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true); @@ -652,11 +655,11 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) case REF_CLOCK_24MHz: if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) { /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz. */ - val = PHYREG15_SSC_CNT_VALUE << PHYREG15_SSC_CNT_SHIFT; - rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK, - val, PHYREG15); + val = RK3568_PHYREG15_SSC_CNT_VALUE << RK3568_PHYREG15_SSC_CNT_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG15_SSC_CNT_MASK, + val, RK3568_PHYREG15); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); } break; @@ -668,24 +671,26 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { /* PLL KVCO fine tuning. */ - val = PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT; - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = RK3568_PHYREG33_PLL_KVCO_VALUE << RK3568_PHYREG33_PLL_KVCO_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Enable controlling random jitter. */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); - val = PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT; - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, - val, PHYREG6); + val = RK3568_PHYREG6_PLL_DIV_2 << RK3568_PHYREG6_PLL_DIV_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, + val, RK3568_PHYREG6); - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); } else if (priv->type == PHY_TYPE_SATA) { /* downward spread spectrum +500ppm */ - val = PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT; - val |= PHYREG32_SSC_OFFSET_500PPM << PHYREG32_SSC_OFFSET_SHIFT; - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + val |= RK3568_PHYREG32_SSC_OFFSET_500PPM << + RK3568_PHYREG32_SSC_OFFSET_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, + RK3568_PHYREG32); } break; @@ -697,20 +702,21 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv) if (priv->ext_refclk) { rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { - val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT; - val |= PHYREG13_CKRCV_AMP0; - rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13); + val = RK3568_PHYREG13_RESISTER_HIGH_Z << RK3568_PHYREG13_RESISTER_SHIFT; + val |= RK3568_PHYREG13_CKRCV_AMP0; + rockchip_combphy_updatel(priv, RK3568_PHYREG13_RESISTER_MASK, val, + RK3568_PHYREG13); - val = readl(priv->mmio + PHYREG14); - val |= PHYREG14_CKRCV_AMP1; - writel(val, priv->mmio + PHYREG14); + val = readl(priv->mmio + RK3568_PHYREG14); + val |= RK3568_PHYREG14_CKRCV_AMP1; + writel(val, priv->mmio + RK3568_PHYREG14); } } if (priv->enable_ssc) { - val = readl(priv->mmio + PHYREG8); - val |= PHYREG8_SSC_EN; - writel(val, priv->mmio + PHYREG8); + val = readl(priv->mmio + RK3568_PHYREG8); + val |= RK3568_PHYREG8_SSC_EN; + writel(val, priv->mmio + RK3568_PHYREG8); } return 0; @@ -771,8 +777,8 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) switch (priv->type) { case PHY_TYPE_PCIE: /* Set SSC downward spread spectrum */ - val = FIELD_PREP(PHYREG32_SSC_MASK, PHYREG32_SSC_DOWNWARD); - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + val = FIELD_PREP(RK3568_PHYREG32_SSC_MASK, RK3568_PHYREG32_SSC_DOWNWARD); + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true); @@ -782,32 +788,33 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) case PHY_TYPE_USB3: /* Set SSC downward spread spectrum */ - val = FIELD_PREP(PHYREG32_SSC_MASK, PHYREG32_SSC_DOWNWARD); - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + val = FIELD_PREP(RK3568_PHYREG32_SSC_MASK, RK3568_PHYREG32_SSC_DOWNWARD); + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); /* Enable adaptive CTLE for USB3.0 Rx */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* Set PLL KVCO fine tuning signals */ - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, BIT(3), PHYREG33); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, BIT(3), + RK3568_PHYREG33); /* Set PLL LPF R1 to su_trim[10:7]=1001 */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); /* Set PLL input clock divider 1/2 */ - val = FIELD_PREP(PHYREG6_PLL_DIV_MASK, PHYREG6_PLL_DIV_2); - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, val, PHYREG6); + val = FIELD_PREP(RK3568_PHYREG6_PLL_DIV_MASK, RK3568_PHYREG6_PLL_DIV_2); + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, val, RK3568_PHYREG6); /* Set PLL loop divider */ - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); /* Set PLL KVCO to min and set PLL charge pump current to max */ - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); /* Set Rx squelch input filler bandwidth */ - writel(PHYREG21_RX_SQUELCH_VAL, priv->mmio + PHYREG21); + writel(RK3576_PHYREG21_RX_SQUELCH_VAL, priv->mmio + RK3576_PHYREG21); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false); @@ -816,14 +823,14 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) case PHY_TYPE_SATA: /* Enable adaptive CTLE for SATA Rx */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* Set tx_rterm = 50 ohm and rx_rterm = 43.5 ohm */ - val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT; - val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT; - writel(val, priv->mmio + PHYREG7); + val = RK3568_PHYREG7_TX_RTERM_50OHM << RK3568_PHYREG7_TX_RTERM_SHIFT; + val |= RK3568_PHYREG7_RX_RTERM_44OHM << RK3568_PHYREG7_RX_RTERM_SHIFT; + writel(val, priv->mmio + RK3568_PHYREG7); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true); @@ -845,19 +852,21 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_24m, true); if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) { /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz */ - val = FIELD_PREP(PHYREG15_SSC_CNT_MASK, PHYREG15_SSC_CNT_VALUE); - rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK, - val, PHYREG15); + val = FIELD_PREP(RK3568_PHYREG15_SSC_CNT_MASK, + RK3568_PHYREG15_SSC_CNT_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG15_SSC_CNT_MASK, + val, RK3568_PHYREG15); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); } else if (priv->type == PHY_TYPE_PCIE) { /* PLL KVCO tuning fine */ - val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576); - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3576_PHYREG33_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Set up rx_pck invert and rx msb to disable */ - writel(0x00, priv->mmio + PHYREG27); + writel(0x00, priv->mmio + RK3588_PHYREG27); /* * Set up SU adjust signal: @@ -865,11 +874,11 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) * su_trim[15:8], PLL LPF R1 adujst bits[9:7]=3'b011 * su_trim[31:24], CKDRV adjust */ - writel(0x90, priv->mmio + PHYREG11); - writel(0x02, priv->mmio + PHYREG12); - writel(0x57, priv->mmio + PHYREG14); + writel(0x90, priv->mmio + RK3568_PHYREG11); + writel(0x02, priv->mmio + RK3568_PHYREG12); + writel(0x57, priv->mmio + RK3568_PHYREG14); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); } break; @@ -881,15 +890,16 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { /* gate_tx_pck_sel length select work for L1SS */ - writel(0xc0, priv->mmio + PHYREG30); + writel(0xc0, priv->mmio + RK3576_PHYREG30); /* PLL KVCO tuning fine */ - val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576); - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3576_PHYREG33_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */ - writel(0x4c, priv->mmio + PHYREG27); + writel(0x4c, priv->mmio + RK3588_PHYREG27); /* * Set up SU adjust signal: @@ -899,20 +909,23 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) * su_trim[23:16], CKRCV adjust * su_trim[31:24], CKDRV adjust */ - writel(0x90, priv->mmio + PHYREG11); - writel(0x43, priv->mmio + PHYREG12); - writel(0x88, priv->mmio + PHYREG13); - writel(0x56, priv->mmio + PHYREG14); + writel(0x90, priv->mmio + RK3568_PHYREG11); + writel(0x43, priv->mmio + RK3568_PHYREG12); + writel(0x88, priv->mmio + RK3568_PHYREG13); + writel(0x56, priv->mmio + RK3568_PHYREG14); } else if (priv->type == PHY_TYPE_SATA) { /* downward spread spectrum +500ppm */ - val = FIELD_PREP(PHYREG32_SSC_DIR_MASK, PHYREG32_SSC_DOWNWARD); - val |= FIELD_PREP(PHYREG32_SSC_OFFSET_MASK, PHYREG32_SSC_OFFSET_500PPM); - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + val = FIELD_PREP(RK3568_PHYREG32_SSC_DIR_MASK, + RK3568_PHYREG32_SSC_DOWNWARD); + val |= FIELD_PREP(RK3568_PHYREG32_SSC_OFFSET_MASK, + RK3568_PHYREG32_SSC_OFFSET_500PPM); + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, + RK3568_PHYREG32); /* ssc ppm adjust to 3500ppm */ - rockchip_combphy_updatel(priv, PHYREG10_SSC_PCM_MASK, - PHYREG10_SSC_PCM_3500PPM, - PHYREG10); + rockchip_combphy_updatel(priv, RK3576_PHYREG10_SSC_PCM_MASK, + RK3576_PHYREG10_SSC_PCM_3500PPM, + RK3576_PHYREG10); } break; @@ -924,12 +937,13 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) if (priv->ext_refclk) { rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { - val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576); - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3576_PHYREG33_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Set up rx_trim: PLL LPF C1 85pf R1 2.5kohm */ - writel(0x0c, priv->mmio + PHYREG27); + writel(0x0c, priv->mmio + RK3588_PHYREG27); /* * Set up SU adjust signal: @@ -939,25 +953,25 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) * su_trim[23:16], CKRCV adjust * su_trim[31:24], CKDRV adjust */ - writel(0x90, priv->mmio + PHYREG11); - writel(0x43, priv->mmio + PHYREG12); - writel(0x88, priv->mmio + PHYREG13); - writel(0x56, priv->mmio + PHYREG14); + writel(0x90, priv->mmio + RK3568_PHYREG11); + writel(0x43, priv->mmio + RK3568_PHYREG12); + writel(0x88, priv->mmio + RK3568_PHYREG13); + writel(0x56, priv->mmio + RK3568_PHYREG14); } } if (priv->enable_ssc) { - val = readl(priv->mmio + PHYREG8); - val |= PHYREG8_SSC_EN; - writel(val, priv->mmio + PHYREG8); + val = readl(priv->mmio + RK3568_PHYREG8); + val |= RK3568_PHYREG8_SSC_EN; + writel(val, priv->mmio + RK3568_PHYREG8); if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_24MHz) { /* Set PLL loop divider */ - writel(0x00, priv->mmio + PHYREG17); - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); + writel(0x00, priv->mmio + RK3576_PHYREG17); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); /* Set up rx_pck invert and rx msb to disable */ - writel(0x00, priv->mmio + PHYREG27); + writel(0x00, priv->mmio + RK3588_PHYREG27); /* * Set up SU adjust signal: @@ -966,16 +980,17 @@ static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv) * su_trim[23:16], CKRCV adjust * su_trim[31:24], CKDRV adjust */ - writel(0x90, priv->mmio + PHYREG11); - writel(0x02, priv->mmio + PHYREG12); - writel(0x08, priv->mmio + PHYREG13); - writel(0x57, priv->mmio + PHYREG14); - writel(0x40, priv->mmio + PHYREG15); + writel(0x90, priv->mmio + RK3568_PHYREG11); + writel(0x02, priv->mmio + RK3568_PHYREG12); + writel(0x08, priv->mmio + RK3568_PHYREG13); + writel(0x57, priv->mmio + RK3568_PHYREG14); + writel(0x40, priv->mmio + RK3568_PHYREG15); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); - val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576); - writel(val, priv->mmio + PHYREG33); + val = FIELD_PREP(RK3568_PHYREG33_PLL_KVCO_MASK, + RK3576_PHYREG33_PLL_KVCO_VALUE); + writel(val, priv->mmio + RK3568_PHYREG33); } } @@ -1045,30 +1060,28 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) break; case PHY_TYPE_USB3: /* Set SSC downward spread spectrum */ - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, - PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, - PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, RK3568_PHYREG32); /* Enable adaptive CTLE for USB3.0 Rx. */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* Set PLL KVCO fine tuning signals. */ - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT, - PHYREG33); + val = RK3568_PHYREG33_PLL_KVCO_VALUE << RK3568_PHYREG33_PLL_KVCO_SHIFT, + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, val, RK3568_PHYREG33); /* Enable controlling random jitter. */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); /* Set PLL input clock divider 1/2. */ - rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, - PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT, - PHYREG6); + rockchip_combphy_updatel(priv, RK3568_PHYREG6_PLL_DIV_MASK, + RK3568_PHYREG6_PLL_DIV_2 << RK3568_PHYREG6_PLL_DIV_SHIFT, + RK3568_PHYREG6); - writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG18_PLL_LOOP, priv->mmio + RK3568_PHYREG18); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false); @@ -1076,16 +1089,16 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) break; case PHY_TYPE_SATA: /* Enable adaptive CTLE for SATA Rx. */ - val = readl(priv->mmio + PHYREG15); - val |= PHYREG15_CTLE_EN; - writel(val, priv->mmio + PHYREG15); + val = readl(priv->mmio + RK3568_PHYREG15); + val |= RK3568_PHYREG15_CTLE_EN; + writel(val, priv->mmio + RK3568_PHYREG15); /* * Set tx_rterm=50ohm and rx_rterm=44ohm for SATA. * 0: 60ohm, 8: 50ohm 15: 44ohm (by step abort 1ohm) */ - val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT; - val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT; - writel(val, priv->mmio + PHYREG7); + val = RK3568_PHYREG7_TX_RTERM_50OHM << RK3568_PHYREG7_TX_RTERM_SHIFT; + val |= RK3568_PHYREG7_RX_RTERM_44OHM << RK3568_PHYREG7_RX_RTERM_SHIFT; + writel(val, priv->mmio + RK3568_PHYREG7); rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true); rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true); @@ -1107,11 +1120,11 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) case REF_CLOCK_24MHz: if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) { /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz. */ - val = PHYREG15_SSC_CNT_VALUE << PHYREG15_SSC_CNT_SHIFT; - rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK, - val, PHYREG15); + val = RK3568_PHYREG15_SSC_CNT_VALUE << RK3568_PHYREG15_SSC_CNT_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG15_SSC_CNT_MASK, + val, RK3568_PHYREG15); - writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + writel(RK3568_PHYREG16_SSC_CNT_VALUE, priv->mmio + RK3568_PHYREG16); } break; @@ -1122,23 +1135,25 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); if (priv->type == PHY_TYPE_PCIE) { /* PLL KVCO fine tuning. */ - val = 4 << PHYREG33_PLL_KVCO_SHIFT; - rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, - val, PHYREG33); + val = 4 << RK3568_PHYREG33_PLL_KVCO_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, + val, RK3568_PHYREG33); /* Enable controlling random jitter. */ - writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + writel(RK3568_PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + RK3568_PHYREG12); /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */ - writel(PHYREG27_RX_TRIM_RK3588, priv->mmio + PHYREG27); + writel(RK3588_PHYREG27_RX_TRIM, priv->mmio + RK3588_PHYREG27); /* Set up su_trim: */ - writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + writel(RK3568_PHYREG11_SU_TRIM_0_7, priv->mmio + RK3568_PHYREG11); } else if (priv->type == PHY_TYPE_SATA) { /* downward spread spectrum +500ppm */ - val = PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT; - val |= PHYREG32_SSC_OFFSET_500PPM << PHYREG32_SSC_OFFSET_SHIFT; - rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + val = RK3568_PHYREG32_SSC_DOWNWARD << RK3568_PHYREG32_SSC_DIR_SHIFT; + val |= RK3568_PHYREG32_SSC_OFFSET_500PPM << + RK3568_PHYREG32_SSC_OFFSET_SHIFT; + rockchip_combphy_updatel(priv, RK3568_PHYREG32_SSC_MASK, val, + RK3568_PHYREG32); } break; default: @@ -1149,20 +1164,21 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) if (priv->ext_refclk) { rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { - val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT; - val |= PHYREG13_CKRCV_AMP0; - rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13); + val = RK3568_PHYREG13_RESISTER_HIGH_Z << RK3568_PHYREG13_RESISTER_SHIFT; + val |= RK3568_PHYREG13_CKRCV_AMP0; + rockchip_combphy_updatel(priv, RK3568_PHYREG13_RESISTER_MASK, val, + RK3568_PHYREG13); - val = readl(priv->mmio + PHYREG14); - val |= PHYREG14_CKRCV_AMP1; - writel(val, priv->mmio + PHYREG14); + val = readl(priv->mmio + RK3568_PHYREG14); + val |= RK3568_PHYREG14_CKRCV_AMP1; + writel(val, priv->mmio + RK3568_PHYREG14); } } if (priv->enable_ssc) { - val = readl(priv->mmio + PHYREG8); - val |= PHYREG8_SSC_EN; - writel(val, priv->mmio + PHYREG8); + val = readl(priv->mmio + RK3568_PHYREG8); + val |= RK3568_PHYREG8_SSC_EN; + writel(val, priv->mmio + RK3568_PHYREG8); } return 0; From bbcca4fac873c66388c687eeecd9ca6b12b601b7 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 28 Jul 2025 10:29:47 +0000 Subject: [PATCH 0063/2711] phy: rockchip: naneng-combphy: Add RK3528 support Rockchip RK3528 integrates one naneng-combphy that is able to operate in PCIe and USB3 mode. The control logic is similar to previous variants of naneng-combphy but the register layout is apparently different from the RK3568 one. Signed-off-by: Yao Zi Reviewed-by: Heiko Stuebner Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250728102947.38984-7-ziyao@disroot.org Signed-off-by: Vinod Koul --- .../rockchip/phy-rockchip-naneng-combphy.c | 189 +++++++++++++++++- 1 file changed, 188 insertions(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index ce84166cd772..0d25872e6712 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -20,7 +20,46 @@ #define REF_CLOCK_25MHz (25 * HZ_PER_MHZ) #define REF_CLOCK_100MHz (100 * HZ_PER_MHZ) -/* COMBO PHY REG */ +/* RK3528 COMBO PHY REG */ +#define RK3528_PHYREG6 0x18 +#define RK3528_PHYREG6_PLL_KVCO GENMASK(12, 10) +#define RK3528_PHYREG6_PLL_KVCO_VALUE 0x2 +#define RK3528_PHYREG6_SSC_DIR GENMASK(5, 4) +#define RK3528_PHYREG6_SSC_UPWARD 0 +#define RK3528_PHYREG6_SSC_DOWNWARD 1 + +#define RK3528_PHYREG40 0x100 +#define RK3528_PHYREG40_SSC_EN BIT(20) +#define RK3528_PHYREG40_SSC_CNT GENMASK(10, 0) +#define RK3528_PHYREG40_SSC_CNT_VALUE 0x17d + +#define RK3528_PHYREG42 0x108 +#define RK3528_PHYREG42_CKDRV_CLK_SEL BIT(29) +#define RK3528_PHYREG42_CKDRV_CLK_PLL 0 +#define RK3528_PHYREG42_CKDRV_CLK_CKRCV 1 +#define RK3528_PHYREG42_PLL_LPF_R1_ADJ GENMASK(10, 7) +#define RK3528_PHYREG42_PLL_LPF_R1_ADJ_VALUE 0x9 +#define RK3528_PHYREG42_PLL_CHGPUMP_CUR_ADJ GENMASK(6, 4) +#define RK3528_PHYREG42_PLL_CHGPUMP_CUR_ADJ_VALUE 0x7 +#define RK3528_PHYREG42_PLL_KVCO_ADJ GENMASK(2, 0) +#define RK3528_PHYREG42_PLL_KVCO_ADJ_VALUE 0x0 + +#define RK3528_PHYREG80 0x200 +#define RK3528_PHYREG80_CTLE_EN BIT(17) + +#define RK3528_PHYREG81 0x204 +#define RK3528_PHYREG81_CDR_PHASE_PATH_GAIN_2X BIT(5) +#define RK3528_PHYREG81_SLEW_RATE_CTRL GENMASK(2, 0) +#define RK3528_PHYREG81_SLEW_RATE_CTRL_SLOW 0x7 + +#define RK3528_PHYREG83 0x20c +#define RK3528_PHYREG83_RX_SQUELCH GENMASK(2, 0) +#define RK3528_PHYREG83_RX_SQUELCH_VALUE 0x6 + +#define RK3528_PHYREG86 0x218 +#define RK3528_PHYREG86_RTERM_DET_CLK_EN BIT(14) + +/* RK3568 COMBO PHY REG */ #define RK3568_PHYREG6 0x14 #define RK3568_PHYREG6_PLL_DIV_MASK GENMASK(7, 6) #define RK3568_PHYREG6_PLL_DIV_SHIFT 6 @@ -400,6 +439,150 @@ static int rockchip_combphy_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(phy_provider); } +static int rk3528_combphy_cfg(struct rockchip_combphy_priv *priv) +{ + const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg; + unsigned long rate; + u32 val; + + /* Set SSC downward spread spectrum */ + val = FIELD_PREP(RK3528_PHYREG6_SSC_DIR, RK3528_PHYREG6_SSC_DOWNWARD); + rockchip_combphy_updatel(priv, RK3528_PHYREG6_SSC_DIR, val, RK3528_PHYREG6); + + switch (priv->type) { + case PHY_TYPE_PCIE: + rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_pcie, true); + break; + case PHY_TYPE_USB3: + /* Enable adaptive CTLE for USB3.0 Rx */ + rockchip_combphy_updatel(priv, RK3528_PHYREG80_CTLE_EN, RK3528_PHYREG80_CTLE_EN, + RK3528_PHYREG80); + + /* Set slow slew rate control for PI */ + val = FIELD_PREP(RK3528_PHYREG81_SLEW_RATE_CTRL, + RK3528_PHYREG81_SLEW_RATE_CTRL_SLOW); + rockchip_combphy_updatel(priv, RK3528_PHYREG81_SLEW_RATE_CTRL, val, + RK3528_PHYREG81); + + /* Set CDR phase path with 2x gain */ + rockchip_combphy_updatel(priv, RK3528_PHYREG81_CDR_PHASE_PATH_GAIN_2X, + RK3528_PHYREG81_CDR_PHASE_PATH_GAIN_2X, RK3528_PHYREG81); + + /* Set Rx squelch input filler bandwidth */ + val = FIELD_PREP(RK3528_PHYREG83_RX_SQUELCH, RK3528_PHYREG83_RX_SQUELCH_VALUE); + rockchip_combphy_updatel(priv, RK3528_PHYREG83_RX_SQUELCH, val, RK3528_PHYREG83); + + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false); + rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true); + rockchip_combphy_param_write(priv->pipe_grf, &cfg->u3otg0_port_en, true); + break; + default: + dev_err(priv->dev, "incompatible PHY type\n"); + return -EINVAL; + } + + rate = clk_get_rate(priv->refclk); + + switch (rate) { + case REF_CLOCK_24MHz: + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_24m, true); + if (priv->type == PHY_TYPE_USB3) { + /* Set ssc_cnt[10:0]=00101111101 & 31.5KHz */ + val = FIELD_PREP(RK3528_PHYREG40_SSC_CNT, RK3528_PHYREG40_SSC_CNT_VALUE); + rockchip_combphy_updatel(priv, RK3528_PHYREG40_SSC_CNT, val, + RK3528_PHYREG40); + } else if (priv->type == PHY_TYPE_PCIE) { + /* tx_trim[14]=1, Enable the counting clock of the rterm detect */ + rockchip_combphy_updatel(priv, RK3528_PHYREG86_RTERM_DET_CLK_EN, + RK3528_PHYREG86_RTERM_DET_CLK_EN, RK3528_PHYREG86); + } + break; + case REF_CLOCK_100MHz: + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); + if (priv->type == PHY_TYPE_PCIE) { + /* PLL KVCO tuning fine */ + val = FIELD_PREP(RK3528_PHYREG6_PLL_KVCO, RK3528_PHYREG6_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3528_PHYREG6_PLL_KVCO, val, + RK3528_PHYREG6); + + /* su_trim[6:4]=111, [10:7]=1001, [2:0]=000, swing 650mv */ + writel(0x570804f0, priv->mmio + RK3528_PHYREG42); + } + break; + default: + dev_err(priv->dev, "Unsupported rate: %lu\n", rate); + return -EINVAL; + } + + if (device_property_read_bool(priv->dev, "rockchip,ext-refclk")) { + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); + + if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { + val = FIELD_PREP(RK3528_PHYREG42_CKDRV_CLK_SEL, + RK3528_PHYREG42_CKDRV_CLK_CKRCV); + val |= FIELD_PREP(RK3528_PHYREG42_PLL_LPF_R1_ADJ, + RK3528_PHYREG42_PLL_LPF_R1_ADJ_VALUE); + val |= FIELD_PREP(RK3528_PHYREG42_PLL_CHGPUMP_CUR_ADJ, + RK3528_PHYREG42_PLL_CHGPUMP_CUR_ADJ_VALUE); + val |= FIELD_PREP(RK3528_PHYREG42_PLL_KVCO_ADJ, + RK3528_PHYREG42_PLL_KVCO_ADJ_VALUE); + rockchip_combphy_updatel(priv, + RK3528_PHYREG42_CKDRV_CLK_SEL | + RK3528_PHYREG42_PLL_LPF_R1_ADJ | + RK3528_PHYREG42_PLL_CHGPUMP_CUR_ADJ | + RK3528_PHYREG42_PLL_KVCO_ADJ, + val, RK3528_PHYREG42); + + val = FIELD_PREP(RK3528_PHYREG6_PLL_KVCO, RK3528_PHYREG6_PLL_KVCO_VALUE); + rockchip_combphy_updatel(priv, RK3528_PHYREG6_PLL_KVCO, val, + RK3528_PHYREG6); + } + } + + if (priv->type == PHY_TYPE_PCIE) { + if (device_property_read_bool(priv->dev, "rockchip,enable-ssc")) + rockchip_combphy_updatel(priv, RK3528_PHYREG40_SSC_EN, + RK3528_PHYREG40_SSC_EN, RK3528_PHYREG40); + } + + return 0; +} + +static const struct rockchip_combphy_grfcfg rk3528_combphy_grfcfgs = { + /* pipe-phy-grf */ + .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 }, + .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 }, + .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 }, + .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 }, + .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 }, + .pipe_clk_24m = { 0x0004, 14, 13, 0x00, 0x00 }, + .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 }, + .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 }, + .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 }, + .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 }, + .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 }, + .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 }, + .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x110 }, + .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x00 }, + .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x101 }, + .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 }, + /* pipe-grf */ + .u3otg0_port_en = { 0x0044, 15, 0, 0x0181, 0x1100 }, +}; + +static const struct rockchip_combphy_cfg rk3528_combphy_cfgs = { + .num_phys = 1, + .phy_ids = { + 0xffdc0000, + }, + .grfcfg = &rk3528_combphy_grfcfgs, + .combphy_cfg = rk3528_combphy_cfg, +}; + static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv) { const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg; @@ -1225,6 +1408,10 @@ static const struct rockchip_combphy_cfg rk3588_combphy_cfgs = { }; static const struct of_device_id rockchip_combphy_of_match[] = { + { + .compatible = "rockchip,rk3528-naneng-combphy", + .data = &rk3528_combphy_cfgs, + }, { .compatible = "rockchip,rk3562-naneng-combphy", .data = &rk3562_combphy_cfgs, From 09d1b78cdec9a615d16610b3ba235988eaafec28 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:13 +0200 Subject: [PATCH 0064/2711] phy: broadcom: brcm-sata: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-2-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/broadcom/phy-brcm-sata.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c index d52dd065e862..fb69e21a0292 100644 --- a/drivers/phy/broadcom/phy-brcm-sata.c +++ b/drivers/phy/broadcom/phy-brcm-sata.c @@ -850,4 +850,3 @@ MODULE_DESCRIPTION("Broadcom SATA PHY driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marc Carino"); MODULE_AUTHOR("Brian Norris"); -MODULE_ALIAS("platform:phy-brcm-sata"); From b05d249ecef55bdf9a6da4cd4ec4ba469df5c0ba Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:14 +0200 Subject: [PATCH 0065/2711] phy: broadcom: brcm-usb: drop unused module alias Since commit 9d5f51dcdb64 ("phy: usb: Add support for new Synopsys USB controller on the 7211b0") the driver only supports OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-3-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/broadcom/phy-brcm-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index 0666864c2f77..59d756a10d6c 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -691,7 +691,6 @@ static struct platform_driver brcm_usb_driver = { module_platform_driver(brcm_usb_driver); -MODULE_ALIAS("platform:brcmstb-usb-phy"); MODULE_AUTHOR("Al Cooper "); MODULE_DESCRIPTION("BRCM USB PHY driver"); MODULE_LICENSE("GPL v2"); From 3531c467843812ca87c5349cd4c5b35cdfbd63df Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:15 +0200 Subject: [PATCH 0066/2711] phy: cadence: Sierra: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-4-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 74613382ccb0..92ab1a31646a 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -2919,7 +2919,6 @@ static struct platform_driver cdns_sierra_driver = { }; module_platform_driver(cdns_sierra_driver); -MODULE_ALIAS("platform:cdns_sierra"); MODULE_AUTHOR("Cadence Design Systems"); MODULE_DESCRIPTION("CDNS sierra phy driver"); MODULE_LICENSE("GPL v2"); From 48d420835fab3df9ae4afbce65d96ab9f485ff04 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:16 +0200 Subject: [PATCH 0067/2711] phy: hisilicon: hi6220-usb: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-5-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/hisilicon/phy-hi6220-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/hisilicon/phy-hi6220-usb.c b/drivers/phy/hisilicon/phy-hi6220-usb.c index 97bd363dfe87..22d8d8a8dabe 100644 --- a/drivers/phy/hisilicon/phy-hi6220-usb.c +++ b/drivers/phy/hisilicon/phy-hi6220-usb.c @@ -161,5 +161,4 @@ static struct platform_driver hi6220_phy_driver = { module_platform_driver(hi6220_phy_driver); MODULE_DESCRIPTION("HISILICON HI6220 USB PHY driver"); -MODULE_ALIAS("platform:hi6220-usb-phy"); MODULE_LICENSE("GPL"); From bd86f188b4e698b04416160495a8387785a0f021 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:17 +0200 Subject: [PATCH 0068/2711] phy: qualcomm: ipq806x-usb: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-6-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c index 06392ed7c91b..f22c0000479f 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c @@ -559,7 +559,6 @@ static struct platform_driver qcom_ipq806x_usb_phy_driver = { module_platform_driver(qcom_ipq806x_usb_phy_driver); -MODULE_ALIAS("platform:phy-qcom-ipq806x-usb"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Andy Gross "); MODULE_AUTHOR("Ivan T. Ivanov "); From c6986f867a330ff58ded64bda47484f20b7e2ef2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:18 +0200 Subject: [PATCH 0069/2711] phy: samsung: exynos5-usbdrd: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-7-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/samsung/phy-exynos5-usbdrd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c index dd660ebe8045..a88ba95bdc8f 100644 --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c @@ -2417,4 +2417,3 @@ module_platform_driver(exynos5_usb3drd_phy); MODULE_DESCRIPTION("Samsung Exynos5 SoCs USB 3.0 DRD controller PHY driver"); MODULE_AUTHOR("Vivek Gautam "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:exynos5_usb3drd_phy"); From 824cdd26af27479458ae3472c64b4ebd31c1d82d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:19 +0200 Subject: [PATCH 0070/2711] phy: samsung: usb2: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-8-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/samsung/phy-samsung-usb2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/samsung/phy-samsung-usb2.c b/drivers/phy/samsung/phy-samsung-usb2.c index 9de744cd6f39..d2749b67cf8f 100644 --- a/drivers/phy/samsung/phy-samsung-usb2.c +++ b/drivers/phy/samsung/phy-samsung-usb2.c @@ -258,4 +258,3 @@ module_platform_driver(samsung_usb2_phy_driver); MODULE_DESCRIPTION("Samsung S5P/Exynos SoC USB PHY driver"); MODULE_AUTHOR("Kamil Debski "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:samsung-usb2-phy"); From 9cbc01aad21fcdff6a2139c2d8656a8ec61a79e4 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:20 +0200 Subject: [PATCH 0071/2711] phy: ti: omap-usb2: drop unused module alias Since commit 478b6c7436c2 ("usb: phy: omap-usb2: Don't use omap_get_control_dev()") the driver only supports OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-9-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-omap-usb2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/ti/phy-omap-usb2.c b/drivers/phy/ti/phy-omap-usb2.c index c1a0ef979142..7096d9c89a96 100644 --- a/drivers/phy/ti/phy-omap-usb2.c +++ b/drivers/phy/ti/phy-omap-usb2.c @@ -520,7 +520,6 @@ static struct platform_driver omap_usb2_driver = { module_platform_driver(omap_usb2_driver); -MODULE_ALIAS("platform:omap_usb2"); MODULE_AUTHOR("Texas Instruments Inc."); MODULE_DESCRIPTION("OMAP USB2 phy driver"); MODULE_LICENSE("GPL v2"); From dbe76a96ad784fbb1872a92999479bf9d02b900e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:21 +0200 Subject: [PATCH 0072/2711] phy: ti: ti-pipe3: drop unused module alias Since commit 918ee0d21ba4 ("usb: phy: omap-usb3: Don't use omap_get_control_dev()") the driver only supports OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-10-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-ti-pipe3.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c index da2cbacb982c..a910c179ea6e 100644 --- a/drivers/phy/ti/phy-ti-pipe3.c +++ b/drivers/phy/ti/phy-ti-pipe3.c @@ -929,7 +929,6 @@ static struct platform_driver ti_pipe3_driver = { module_platform_driver(ti_pipe3_driver); -MODULE_ALIAS("platform:ti_pipe3"); MODULE_AUTHOR("Texas Instruments Inc."); MODULE_DESCRIPTION("TI PIPE3 phy driver"); MODULE_LICENSE("GPL v2"); From a27576076b6befd634154715220298a97ad4b24a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:22 +0200 Subject: [PATCH 0073/2711] phy: ti: dm816x-usb: drop unused module alias The driver has never supported anything but OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-11-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-dm816x-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/ti/phy-dm816x-usb.c b/drivers/phy/ti/phy-dm816x-usb.c index e8f842d4e841..d274831b731c 100644 --- a/drivers/phy/ti/phy-dm816x-usb.c +++ b/drivers/phy/ti/phy-dm816x-usb.c @@ -269,7 +269,6 @@ static struct platform_driver dm816x_usb_phy_driver = { module_platform_driver(dm816x_usb_phy_driver); -MODULE_ALIAS("platform:dm816x_usb"); MODULE_AUTHOR("Tony Lindgren "); MODULE_DESCRIPTION("dm816x usb phy driver"); MODULE_LICENSE("GPL v2"); From 8eb3a6f7a1881d2cfd4f7d741e263ce6999bcbc9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Jul 2025 17:48:23 +0200 Subject: [PATCH 0074/2711] phy: ti: omap-control: drop unused module alias Since commit 4fd06af96b93 ("usb: phy: omap-control: Get rid of platform data") the driver only supports OF probe so drop the unused platform module alias. Signed-off-by: Johan Hovold Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250724154823.15998-12-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-omap-control.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/ti/phy-omap-control.c b/drivers/phy/ti/phy-omap-control.c index 2fdb8f4241c7..4968434312f8 100644 --- a/drivers/phy/ti/phy-omap-control.c +++ b/drivers/phy/ti/phy-omap-control.c @@ -334,7 +334,6 @@ static void __exit omap_control_phy_exit(void) } module_exit(omap_control_phy_exit); -MODULE_ALIAS("platform:omap_control_phy"); MODULE_AUTHOR("Texas Instruments Inc."); MODULE_DESCRIPTION("OMAP Control Module PHY Driver"); MODULE_LICENSE("GPL v2"); From 791cfbe1c56076c9d3bcf856b5175bfbc9c5a2d4 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 9 Jul 2025 16:55:14 +0200 Subject: [PATCH 0075/2711] dt-bindings: phy: qcom,snps-eusb2-repeater: Document qcom,tune-res-fsdif Document the FS Differential TX Output Resistance Tuning value found on the eUSB2 repeater on Qualcomm PMICs. The tuning values have special meanings, being different offsets of the resistance to the default value in Ohms but the exact meaning is not relevant here, as the correct tuning is determined by hardware engineers to make sure the electrical properties are as expected. Signed-off-by: Luca Weiss Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250709-sm7635-eusb-repeater-v2-1-b6eff075c097@fairphone.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml index 27f064a71c9f..6bfd11657e29 100644 --- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml @@ -52,6 +52,12 @@ properties: minimum: 0 maximum: 7 + qcom,tune-res-fsdif: + $ref: /schemas/types.yaml#/definitions/uint8 + description: FS Differential TX Output Resistance Tuning + minimum: 0 + maximum: 7 + required: - compatible - reg From 08bde1e7c71396fcf96b0410b1c4cb6bee5b8741 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 9 Jul 2025 16:55:15 +0200 Subject: [PATCH 0076/2711] phy: qualcomm: phy-qcom-eusb2-repeater: Support tune-res-fsdif prop Support reading the FS Differential TX Output Resistance Tuning from devicetree and writing the register, as required on some boards. Reviewed-by: Abel Vesa Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20250709-sm7635-eusb-repeater-v2-2-b6eff075c097@fairphone.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c index e0f2acc8109c..b2f8f1314e90 100644 --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c @@ -136,6 +136,9 @@ static int eusb2_repeater_init(struct phy *phy) if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &val)) regmap_write(regmap, base + EUSB2_TUNE_IUSB2, val); + if (!of_property_read_u8(np, "qcom,tune-res-fsdif", &val)) + regmap_write(regmap, base + EUSB2_TUNE_RES_FSDIF, val); + /* Wait for status OK */ ret = regmap_read_poll_timeout(regmap, base + EUSB2_RPTR_STATUS, poll_val, poll_val & RPTR_OK, 10, 5); From 5edc4054655009691deb79142af1ffe5aba0a224 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 9 Jul 2025 16:55:16 +0200 Subject: [PATCH 0077/2711] dt-bindings: phy: qcom,snps-eusb2-repeater: Add compatible for PMIV0104 Add a dt-bindings compatible string for the Qualcomm's PMIV0104 PMIC. Acked-by: Krzysztof Kozlowski Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20250709-sm7635-eusb-repeater-v2-3-b6eff075c097@fairphone.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml index 6bfd11657e29..5bf0d6c9c025 100644 --- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml @@ -22,6 +22,7 @@ properties: - const: qcom,pm8550b-eusb2-repeater - enum: - qcom,pm8550b-eusb2-repeater + - qcom,pmiv0104-eusb2-repeater - qcom,smb2360-eusb2-repeater reg: From ce872bce1140eec07ed624e537687244a5c01397 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 9 Jul 2025 16:55:17 +0200 Subject: [PATCH 0078/2711] phy: qualcomm: phy-qcom-eusb2-repeater: Add support for PMIV0104 Add support for the eUSB2 repeater found on the PMIV0104. There is no default init table for this PMIC, just the board-specific tuning parameters are used on top of the default tuning values. Reviewed-by: Abel Vesa Reviewed-by: Neil Armstrong Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20250709-sm7635-eusb-repeater-v2-4-b6eff075c097@fairphone.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c index b2f8f1314e90..3629b926108a 100644 --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c @@ -82,6 +82,14 @@ static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = { .num_vregs = ARRAY_SIZE(pm8550b_vreg_l), }; +static const struct eusb2_repeater_cfg pmiv0104_eusb2_cfg = { + /* No PMIC-specific init sequence, only board level tuning via DT */ + .init_tbl = (struct eusb2_repeater_init_tbl_reg[]) {}, + .init_tbl_num = 0, + .vreg_list = pm8550b_vreg_l, + .num_vregs = ARRAY_SIZE(pm8550b_vreg_l), +}; + static const struct eusb2_repeater_cfg smb2360_eusb2_cfg = { .init_tbl = smb2360_init_tbl, .init_tbl_num = ARRAY_SIZE(smb2360_init_tbl), @@ -262,6 +270,10 @@ static const struct of_device_id eusb2_repeater_of_match_table[] = { .compatible = "qcom,pm8550b-eusb2-repeater", .data = &pm8550b_eusb2_cfg, }, + { + .compatible = "qcom,pmiv0104-eusb2-repeater", + .data = &pmiv0104_eusb2_cfg, + }, { .compatible = "qcom,smb2360-eusb2-repeater", .data = &smb2360_eusb2_cfg, From aaa76d1cbd73a7e8ddb9d92423b017eb98d2b335 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 11 Aug 2025 10:02:34 +0300 Subject: [PATCH 0079/2711] thunderbolt: Use Linux Foundation IDs for XDomain discovery There are other vendors now that have their own USB4 host router hardware so using the Intel donated IDs may confuse users. For this reason switch to use USB IDs provided by the Linux Foundation for XDomain discovery. Link: https://lore.kernel.org/linux-usb/20250722175026.1994846-1-Raju.Rangoju@amd.com/ Cc: Raju Rangoju Acked-by: Greg Kroah-Hartman Reviewed-by: Mario Limonciello (AMD) > Signed-off-by: Mika Westerberg --- drivers/thunderbolt/xdomain.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index b0630e6d9472..fffa28cc491d 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -2562,10 +2562,9 @@ int tb_xdomain_init(void) * Rest of the properties are filled dynamically based on these * when the P2P connection is made. */ - tb_property_add_immediate(xdomain_property_dir, "vendorid", - PCI_VENDOR_ID_INTEL); - tb_property_add_text(xdomain_property_dir, "vendorid", "Intel Corp."); - tb_property_add_immediate(xdomain_property_dir, "deviceid", 0x1); + tb_property_add_immediate(xdomain_property_dir, "vendorid", 0x1d6b); + tb_property_add_text(xdomain_property_dir, "vendorid", "Linux"); + tb_property_add_immediate(xdomain_property_dir, "deviceid", 0x0004); tb_property_add_immediate(xdomain_property_dir, "devicerv", 0x80000100); xdomain_property_block_gen = get_random_u32(); From 265dca4380753af9aa9480c7c201c820d6e7905e Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Mon, 11 Aug 2025 09:09:05 +0200 Subject: [PATCH 0080/2711] staging: rtl8723bs: use crypto_xor_cpy Use the in-kernel function crypto_xor_cpy instead of the custom function bitwise_xor, as using in-kernel functions is preferred over custom implementations. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250811070906.27232-2-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_security.c | 46 +++++++------------ 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index e9f382c280d9..08d179857203 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -7,6 +7,7 @@ #include #include #include +#include static const char * const _security_type_str[] = { "N/A", @@ -641,7 +642,6 @@ exit: /**** Function Prototypes ****/ /*****************************/ -static void bitwise_xor(u8 *ina, u8 *inb, u8 *out); static void construct_mic_iv(u8 *mic_header1, signed int qc_exists, signed int a4_exists, @@ -849,18 +849,6 @@ static void construct_ctr_preload(u8 *ctr_preload, ctr_preload[15] = (unsigned char) (c % 256); } -/************************************/ -/* bitwise_xor() */ -/* A 128 bit, bitwise exclusive or */ -/************************************/ -static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) -{ - signed int i; - - for (i = 0; i < 16; i++) - out[i] = ina[i] ^ inb[i]; -} - static signed int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen) { @@ -941,13 +929,13 @@ static signed int aes_cipher(u8 *key, uint hdrlen, /* Calculate MIC */ aes128k128d(key, mic_iv, aes_out); - bitwise_xor(aes_out, mic_header1, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, mic_header1, 16); aes128k128d(key, chain_buffer, aes_out); - bitwise_xor(aes_out, mic_header2, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, mic_header2, 16); aes128k128d(key, chain_buffer, aes_out); for (i = 0; i < num_blocks; i++) { - bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, &pframe[payload_index], 16); payload_index += 16; aes128k128d(key, chain_buffer, aes_out); @@ -960,7 +948,7 @@ static signed int aes_cipher(u8 *key, uint hdrlen, for (j = 0; j < payload_remainder; j++) padded_buffer[j] = pframe[payload_index++]; - bitwise_xor(aes_out, padded_buffer, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, padded_buffer, 16); aes128k128d(key, chain_buffer, aes_out); } @@ -977,7 +965,7 @@ static signed int aes_cipher(u8 *key, uint hdrlen, pn_vector, i+1, frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, &pframe[payload_index], 16); for (j = 0; j < 16; j++) pframe[payload_index++] = chain_buffer[j]; } @@ -995,7 +983,7 @@ static signed int aes_cipher(u8 *key, uint hdrlen, padded_buffer[j] = pframe[payload_index+j]; aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, padded_buffer, 16); for (j = 0; j < payload_remainder; j++) pframe[payload_index++] = chain_buffer[j]; } @@ -1011,7 +999,7 @@ static signed int aes_cipher(u8 *key, uint hdrlen, padded_buffer[j] = pframe[j+hdrlen+8+plen]; aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, padded_buffer, 16); for (j = 0; j < 8; j++) pframe[payload_index++] = chain_buffer[j]; @@ -1137,7 +1125,7 @@ static signed int aes_decipher(u8 *key, uint hdrlen, frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, &pframe[payload_index], 16); for (j = 0; j < 16; j++) pframe[payload_index++] = chain_buffer[j]; @@ -1156,7 +1144,7 @@ static signed int aes_decipher(u8 *key, uint hdrlen, padded_buffer[j] = pframe[payload_index+j]; aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, padded_buffer, 16); for (j = 0; j < payload_remainder; j++) pframe[payload_index++] = chain_buffer[j]; } @@ -1187,13 +1175,13 @@ static signed int aes_decipher(u8 *key, uint hdrlen, /* Calculate MIC */ aes128k128d(key, mic_iv, aes_out); - bitwise_xor(aes_out, mic_header1, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, mic_header1, 16); aes128k128d(key, chain_buffer, aes_out); - bitwise_xor(aes_out, mic_header2, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, mic_header2, 16); aes128k128d(key, chain_buffer, aes_out); for (i = 0; i < num_blocks; i++) { - bitwise_xor(aes_out, &message[payload_index], chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, &message[payload_index], 16); payload_index += 16; aes128k128d(key, chain_buffer, aes_out); @@ -1206,7 +1194,7 @@ static signed int aes_decipher(u8 *key, uint hdrlen, for (j = 0; j < payload_remainder; j++) padded_buffer[j] = message[payload_index++]; - bitwise_xor(aes_out, padded_buffer, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, padded_buffer, 16); aes128k128d(key, chain_buffer, aes_out); } @@ -1223,7 +1211,7 @@ static signed int aes_decipher(u8 *key, uint hdrlen, frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &message[payload_index], chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, &message[payload_index], 16); for (j = 0; j < 16; j++) message[payload_index++] = chain_buffer[j]; } @@ -1241,7 +1229,7 @@ static signed int aes_decipher(u8 *key, uint hdrlen, padded_buffer[j] = message[payload_index+j]; aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, padded_buffer, 16); for (j = 0; j < payload_remainder; j++) message[payload_index++] = chain_buffer[j]; } @@ -1256,7 +1244,7 @@ static signed int aes_decipher(u8 *key, uint hdrlen, padded_buffer[j] = message[j+hdrlen+8+plen-8]; aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); + crypto_xor_cpy(chain_buffer, aes_out, padded_buffer, 16); for (j = 0; j < 8; j++) message[payload_index++] = chain_buffer[j]; From 6e5187d82d9b20eb72938deda625a1976148241c Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Mon, 11 Aug 2025 09:09:06 +0200 Subject: [PATCH 0081/2711] staging: rtl8723bs: remove unnecessary forward declarations Remove unnecessary forward declarations of static functions to improve readability. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250811070906.27232-3-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_security.c | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index 08d179857203..8367fd15c6b1 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -638,36 +638,6 @@ exit: #define MAX_MSG_SIZE 2048 -/*****************************/ -/**** Function Prototypes ****/ -/*****************************/ - -static void construct_mic_iv(u8 *mic_header1, - signed int qc_exists, - signed int a4_exists, - u8 *mpdu, - uint payload_length, - u8 *pn_vector, - uint frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ -static void construct_mic_header1(u8 *mic_header1, - signed int header_length, - u8 *mpdu, - uint frtype); /* for CONFIG_IEEE80211W, none 11w also can use */ -static void construct_mic_header2(u8 *mic_header2, - u8 *mpdu, - signed int a4_exists, - signed int qc_exists); -static void construct_ctr_preload(u8 *ctr_preload, - signed int a4_exists, - signed int qc_exists, - u8 *mpdu, - u8 *pn_vector, - signed int c, - uint frtype); /* for CONFIG_IEEE80211W, none 11w also can use */ - -static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext); - - /****************************************/ /* aes128k128d() */ /* Performs a 128 bit AES encrypt with */ From e5b264e0a201254a38836b794ff362e8400f3df7 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Mon, 11 Aug 2025 11:54:17 +0300 Subject: [PATCH 0082/2711] staging: axis-fifo: use unique identifiers in device names Axis-fifo devices use physical addresses in their name, for example 'axis_fifo_0x43c00000'. This is generally frowned upon and it does not follow the usual naming scheme that uses unique identifiers. Therefore, use ida_alloc()/ida_free() to implement unique identifiers for axis-fifo device names (i.e. axis_fifo0, axis_fifo1, etc.). Signed-off-by: Ovidiu Panait Link: https://lore.kernel.org/r/20250811085417.2641674-2-ovidiu.panait.oss@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/axis-fifo/axis-fifo.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index 06f7cfab4c6a..e8aa632e0a31 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -107,6 +107,8 @@ static long read_timeout = 1000; /* ms to wait before read() times out */ static long write_timeout = 1000; /* ms to wait before write() times out */ +static DEFINE_IDA(axis_fifo_ida); + /* ---------------------------- * module command-line arguments * ---------------------------- @@ -123,6 +125,7 @@ MODULE_PARM_DESC(write_timeout, "ms to wait before blocking write() timing out; */ struct axis_fifo { + int id; int irq; /* interrupt */ void __iomem *base_addr; /* kernel space memory */ @@ -698,10 +701,6 @@ static int axis_fifo_probe(struct platform_device *pdev) dev_dbg(fifo->dt_device, "remapped memory to 0x%p\n", fifo->base_addr); - /* create unique device name */ - snprintf(device_name, 32, "%s_%pa", DRIVER_NAME, &r_mem->start); - dev_dbg(fifo->dt_device, "device name [%s]\n", device_name); - /* ---------------------------- * init IP * ---------------------------- @@ -737,6 +736,11 @@ static int axis_fifo_probe(struct platform_device *pdev) * init char device * ---------------------------- */ + fifo->id = ida_alloc(&axis_fifo_ida, GFP_KERNEL); + if (fifo->id < 0) + return fifo->id; + + snprintf(device_name, 32, "%s%d", DRIVER_NAME, fifo->id); /* create character device */ fifo->miscdev.fops = &fops; @@ -744,8 +748,10 @@ static int axis_fifo_probe(struct platform_device *pdev) fifo->miscdev.name = device_name; fifo->miscdev.parent = dev; rc = misc_register(&fifo->miscdev); - if (rc < 0) + if (rc < 0) { + ida_free(&axis_fifo_ida, fifo->id); return rc; + } axis_fifo_debugfs_init(fifo); @@ -759,6 +765,7 @@ static void axis_fifo_remove(struct platform_device *pdev) debugfs_remove(fifo->debugfs_dir); misc_deregister(&fifo->miscdev); + ida_free(&axis_fifo_ida, fifo->id); } static const struct of_device_id axis_fifo_of_match[] = { @@ -798,6 +805,7 @@ module_init(axis_fifo_init); static void __exit axis_fifo_exit(void) { platform_driver_unregister(&axis_fifo_driver); + ida_destroy(&axis_fifo_ida); } module_exit(axis_fifo_exit); From 260221b2a053a30e30575fa90c326590e8fb0c76 Mon Sep 17 00:00:00 2001 From: Yuri Martins Date: Tue, 12 Aug 2025 01:56:06 +0000 Subject: [PATCH 0083/2711] staging: vc04_services/vchiq-mmal: fix typos in comments Fix three spelling mistakes found in comments across the vchiq-mmal driver component: - recived -> received - servie -> service - enque -> enqueues Signed-off-by: Yuri Martins Link: https://lore.kernel.org/r/20250812015524.64413-1-yurimartins2004@hotmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h | 2 +- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 2 +- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h index 471413248a14..1889494425eb 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h @@ -13,7 +13,7 @@ /* * all the data structures which serialise the MMAL protocol. note - * these are directly mapped onto the recived message data. + * these are directly mapped onto the received message data. * * BEWARE: They seem to *assume* pointers are u32 and that there is no * structure padding! diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c index 3fe482bd2793..c2b5a37915f2 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c @@ -326,7 +326,7 @@ static int bulk_receive(struct vchiq_mmal_instance *instance, * committed a buffer_to_host operation to the mmal * port without the buffer to back it up (underflow * handling) and there is no obvious way to deal with - * this - how is the mmal servie going to react when + * this - how is the mmal service going to react when * we fail to do the xfer and reschedule a buffer when * it arrives? perhaps a starved flag to indicate a * waiting bulk receive? diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h index 97abe4bdcfc5..8c3959f6f97f 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h @@ -115,7 +115,7 @@ int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance, /* enable a mmal port * - * enables a port and if a buffer callback provided enque buffer + * enables a port and, if a buffer callback provided, enqueues buffer * headers as appropriate for the port. */ int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance, From 784ad808ae864490b93db0f650b8b6417eb7ce68 Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Fri, 25 Jul 2025 11:51:58 +0530 Subject: [PATCH 0084/2711] usb: dwc3: qcom: Add shutdown handler Currently during system reboot, SMMU disables its translations while devices like USB may still be actively using DMA buffers. This can lead to NOC errors and system crashes due to invalid memory access. Address this by adding a shutdown callback to dwc3-qcom, which ensures proper teardown of UDC stack and prevents DWC3 controller from accessing memory after SMMU translation is disabled. Reuse the existing remove callback for this purpose. Signed-off-by: Prashanth K Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20250725062158.2418961-1-prashanth.k@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index ca7e1c02773a..308360a32c93 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -764,11 +764,14 @@ static void dwc3_qcom_remove(struct platform_device *pdev) struct dwc3 *dwc = platform_get_drvdata(pdev); struct dwc3_qcom *qcom = to_dwc3_qcom(dwc); + if (pm_runtime_resume_and_get(qcom->dev) < 0) + return; + dwc3_core_remove(&qcom->dwc); - clk_bulk_disable_unprepare(qcom->num_clocks, qcom->clks); - dwc3_qcom_interconnect_exit(qcom); + + pm_runtime_put_noidle(qcom->dev); } static int dwc3_qcom_pm_suspend(struct device *dev) @@ -873,6 +876,7 @@ MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match); static struct platform_driver dwc3_qcom_driver = { .probe = dwc3_qcom_probe, .remove = dwc3_qcom_remove, + .shutdown = dwc3_qcom_remove, .driver = { .name = "dwc3-qcom", .pm = pm_ptr(&dwc3_qcom_dev_pm_ops), From e58ebd14a5f15eccf3dd45edf4bc900b346096bf Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 5 Aug 2025 12:47:29 +0100 Subject: [PATCH 0085/2711] dt-bindings: usb: renesas,usbhs: Add RZ/T2H and RZ/N2H support Document the USBHS controller for the Renesas RZ/T2H (r9a09g077) and RZ/N2H (r9a09g087) SoCs. While the USBHS block is similar to the one found on the RZ/G2L SoC, it differs slightly in terms of interrupt configuration, clock/reset requirements, and register bit definitions. Due to these differences, a new compatible string `renesas,usbhs-r9a09g077` is introduced for the RZ/T2H SoC. The USBHS controller on the RZ/N2H (r9a09g087) SoC is identical to that on the RZ/T2H, so it uses the `renesas,usbhs-r9a09g077` compatible string as a fallback. Signed-off-by: Lad Prabhakar Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250805114730.2491238-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/renesas,usbhs.yaml | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml index a19816bbb1fd..0b8b90dd1951 100644 --- a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml +++ b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml @@ -59,6 +59,12 @@ properties: - renesas,usbhs-r8a77995 # R-Car D3 - const: renesas,rcar-gen3-usbhs + - const: renesas,usbhs-r9a09g077 # RZ/T2H + + - items: + - const: renesas,usbhs-r9a09g087 # RZ/N2H + - const: renesas,usbhs-r9a09g077 # RZ/T2H + reg: maxItems: 1 @@ -141,9 +147,25 @@ allOf: required: - resets else: - properties: - interrupts: - maxItems: 1 + if: + properties: + compatible: + contains: + const: renesas,usbhs-r9a09g077 + then: + properties: + resets: false + clocks: + maxItems: 1 + interrupts: + items: + - description: USB function interrupt USB_FI + - description: USB function DMA0 transmit completion interrupt USB_FDMA0 + - description: USB function DMA1 transmit completion interrupt USB_FDMA1 + else: + properties: + interrupts: + maxItems: 1 additionalProperties: false From 015709748ca921975ac1c91b40f664ca8c370eb6 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 5 Aug 2025 12:47:30 +0100 Subject: [PATCH 0086/2711] usb: renesas_usbhs: Add support for RZ/T2H SoC Add support for the Renesas RZ/T2H (r9a09g077) SoC by adding a compatible string to the usbhs_of_match table. The USBHS controller on the RZ/T2H is functionally similar to the one found on the RZ/G2L. While there are minor differences in register fields (for example, the AWAIT[8:13] bits in SYSCFG1 register), the current driver does not configure these, allowing reuse of the existing usbhs_rzg2l_plat_info for the RZ/T2H. Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20250805114730.2491238-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 18a6ef4dce51..8f536f2c500f 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -579,6 +579,10 @@ static const struct of_device_id usbhs_of_match[] = { .compatible = "renesas,usbhs-r9a07g054", .data = &usbhs_rzg2l_plat_info, }, + { + .compatible = "renesas,usbhs-r9a09g077", + .data = &usbhs_rzg2l_plat_info, + }, { .compatible = "renesas,rcar-gen2-usbhs", .data = &usbhs_rcar_gen2_plat_info, From b12daf363f3d4ded1c12d01ab7c45b6179c586ab Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Fri, 1 Aug 2025 16:52:02 +0900 Subject: [PATCH 0087/2711] USB: lower "Device is not authorized for usage" message to info This message is not a useful error in practice: - when using tools such as usbguard, the message is always printed but it does not presume anything regarding the actual device acceptance (later 'authorized to connect' message is at info level, and not displayed on console) - this can be a source of flood if a usb device connection is flaky - ... and it is only displayed as the result of an admin action (modifying authorized_default), working as intended, so not likely to be an error. This is still useful to know when looking at usb devices problems, so info seems appropriate for this class of messages together with the later eventual authorized message. Signed-off-by: Dominique Martinet Link: https://lore.kernel.org/r/20250801-usb-auth-v1-1-a59bfdf0293f@atmark-techno.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 4 ++-- drivers/usb/core/generic.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index c3177034b779..69216c3951fd 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -332,10 +332,10 @@ static int usb_probe_interface(struct device *dev) return error; if (udev->authorized == 0) { - dev_err(&intf->dev, "Device is not authorized for usage\n"); + dev_info(&intf->dev, "Device is not authorized for usage\n"); return error; } else if (intf->authorized == 0) { - dev_err(&intf->dev, "Interface %d is not authorized for usage\n", + dev_info(&intf->dev, "Interface %d is not authorized for usage\n", intf->altsetting->desc.bInterfaceNumber); return error; } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 9c6ae5e1198b..a48994e11ef3 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -243,7 +243,7 @@ int usb_generic_driver_probe(struct usb_device *udev) * with the driver core and lets interface drivers bind to them. */ if (udev->authorized == 0) - dev_err(&udev->dev, "Device is not authorized for usage\n"); + dev_info(&udev->dev, "Device is not authorized for usage\n"); else { c = usb_choose_configuration(udev); if (c >= 0) { From 4b58e0638c4b0f4b80c87b1c711b065eca559551 Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Tue, 5 Aug 2025 11:33:37 +0200 Subject: [PATCH 0088/2711] usb: misc: eud: Remove error print for devm_add_action_or_reset() When `devm_add_action_or_reset()` fails, it is due to a failed memory allocation and will thus return `-ENOMEM`. `dev_err_probe()` doesn't do anything when error is `-ENOMEM`. Therefore, remove the useless call to `dev_err_probe()` when `devm_add_action_or_reset()` fails, and just return the value instead. Signed-off-by: Waqar Hameed Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/pndo6sukt8u.a.out@axis.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/qcom_eud.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c index 83079c414b4f..67832790acad 100644 --- a/drivers/usb/misc/qcom_eud.c +++ b/drivers/usb/misc/qcom_eud.c @@ -193,8 +193,7 @@ static int eud_probe(struct platform_device *pdev) ret = devm_add_action_or_reset(chip->dev, eud_role_switch_release, chip); if (ret) - return dev_err_probe(chip->dev, ret, - "failed to add role switch release action\n"); + return ret; chip->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->base)) From aeb0169217ebf91b65927c7ce5f27318b2059aa4 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Tue, 29 Jul 2025 14:57:08 +0530 Subject: [PATCH 0089/2711] usb: dwc3: qcom: Remove extcon functionality from glue layer Historically Qualcomm DWC3 glue driver supported both extcon and usb-role-switch kinds of notifications. When Bjorn contributed [1] the flattened representation for the DWC3 host controller, he also kept both extcon and usb-role-switch support in the flattened driver & bindings. Currently there are no in-kernel users for flattened DWC3 and extcon. As device's DT needs to be manually converted from legacy to the flat DWC3 representation, we can drop (legacy / deprecated) extcon support from the new DWC3 glue driver, significantly simplifying the code. This potentially affects flattening effort for the following platforms: Platforms currently using linux,extcon-usb-gpio device that need to switch to gpio-usb-b-connector: - apq8096-db820c, - msm8996-sony-xperia-tone-dora Platforms currently using linux,extcon-usb-gpio device that need to switch to gpio-usb-c-connector (not supported at this moment) or to implement typec support - msm8996-sony-xperia-tone-kagura - msm8996-sony-xperia-tone-keyaki - msm8998-fxtec-pro1 - msm8998-sony-xperia-yoshino-lilac - msm8998-sony-xperia-yoshino-maple - msm8998-sony-xperia-yoshino-poplar - sda660-inforce-ifc6560 - sdm630-sony-xperia-nile-discovery - sdm630-sony-xperia-nile-pioneer - sdm630-sony-xperia-nile-voyager - sdm660-xiaomi-lavender - sm6125-sony-xperia-seine-pdx201 - sm6125-xiaomi-ginkgo - sm6125-xiaomi-laurel-sprout Platforms using TI TUSB320L chip need to switch to represent the USB-C connector properly (and to have a typec-class driver for the TUSB320L chip): - msm8996-xiaomi-gemini - msm8996pro-xiaomi-natrium - msm8996pro-xiaomi-scoprpio Commit message suggested by Dmitry Baryshkov. [1]: https://lore.kernel.org/all/20250414-dwc3-refactor-v7-0-f015b358722d@oss.qualcomm.com/ Signed-off-by: Krishna Kurapati Acked-by: Thinh Nguyen Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250729092708.3628187-1-krishna.kurapati@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 90 +----------------------------------- 1 file changed, 1 insertion(+), 89 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 308360a32c93..8a9018ca650c 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -79,11 +78,6 @@ struct dwc3_qcom { struct dwc3_qcom_port ports[DWC3_QCOM_MAX_PORTS]; u8 num_ports; - struct extcon_dev *edev; - struct extcon_dev *host_edev; - struct notifier_block vbus_nb; - struct notifier_block host_nb; - enum usb_dr_mode mode; bool is_suspended; bool pm_suspended; @@ -119,8 +113,7 @@ static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val) /* * TODO: Make the in-core role switching code invoke dwc3_qcom_vbus_override_enable(), - * validate that the in-core extcon support is functional, and drop extcon - * handling from the glue + * validate that the in-core extcon support is functional */ static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable) { @@ -137,80 +130,6 @@ static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable) } } -static int dwc3_qcom_vbus_notifier(struct notifier_block *nb, - unsigned long event, void *ptr) -{ - struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, vbus_nb); - - /* enable vbus override for device mode */ - dwc3_qcom_vbus_override_enable(qcom, event); - qcom->mode = event ? USB_DR_MODE_PERIPHERAL : USB_DR_MODE_HOST; - - return NOTIFY_DONE; -} - -static int dwc3_qcom_host_notifier(struct notifier_block *nb, - unsigned long event, void *ptr) -{ - struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, host_nb); - - /* disable vbus override in host mode */ - dwc3_qcom_vbus_override_enable(qcom, !event); - qcom->mode = event ? USB_DR_MODE_HOST : USB_DR_MODE_PERIPHERAL; - - return NOTIFY_DONE; -} - -static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom) -{ - struct device *dev = qcom->dev; - struct extcon_dev *host_edev; - int ret; - - if (!of_property_present(dev->of_node, "extcon")) - return 0; - - qcom->edev = extcon_get_edev_by_phandle(dev, 0); - if (IS_ERR(qcom->edev)) - return dev_err_probe(dev, PTR_ERR(qcom->edev), - "Failed to get extcon\n"); - - qcom->vbus_nb.notifier_call = dwc3_qcom_vbus_notifier; - - qcom->host_edev = extcon_get_edev_by_phandle(dev, 1); - if (IS_ERR(qcom->host_edev)) - qcom->host_edev = NULL; - - ret = devm_extcon_register_notifier(dev, qcom->edev, EXTCON_USB, - &qcom->vbus_nb); - if (ret < 0) { - dev_err(dev, "VBUS notifier register failed\n"); - return ret; - } - - if (qcom->host_edev) - host_edev = qcom->host_edev; - else - host_edev = qcom->edev; - - qcom->host_nb.notifier_call = dwc3_qcom_host_notifier; - ret = devm_extcon_register_notifier(dev, host_edev, EXTCON_USB_HOST, - &qcom->host_nb); - if (ret < 0) { - dev_err(dev, "Host notifier register failed\n"); - return ret; - } - - /* Update initial VBUS override based on extcon state */ - if (extcon_get_state(qcom->edev, EXTCON_USB) || - !extcon_get_state(host_edev, EXTCON_USB_HOST)) - dwc3_qcom_vbus_notifier(&qcom->vbus_nb, true, qcom->edev); - else - dwc3_qcom_vbus_notifier(&qcom->vbus_nb, false, qcom->edev); - - return 0; -} - static int dwc3_qcom_interconnect_enable(struct dwc3_qcom *qcom) { int ret; @@ -737,11 +656,6 @@ static int dwc3_qcom_probe(struct platform_device *pdev) if (qcom->mode != USB_DR_MODE_HOST) dwc3_qcom_vbus_override_enable(qcom, true); - /* register extcon to override sw_vbus on Vbus change later */ - ret = dwc3_qcom_register_extcon(qcom); - if (ret) - goto interconnect_exit; - wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source"); device_init_wakeup(&pdev->dev, wakeup_source); @@ -749,8 +663,6 @@ static int dwc3_qcom_probe(struct platform_device *pdev) return 0; -interconnect_exit: - dwc3_qcom_interconnect_exit(qcom); remove_core: dwc3_core_remove(&qcom->dwc); clk_disable: From 186e8f2bdba551f3ae23396caccd452d985c23e3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 7 Aug 2025 18:55:00 +0300 Subject: [PATCH 0090/2711] usb: host: max3421-hcd: Fix error pointer dereference in probe cleanup The kthread_run() function returns error pointers so the max3421_hcd->spi_thread pointer can be either error pointers or NULL. Check for both before dereferencing it. Fixes: 05dfa5c9bc37 ("usb: host: max3421-hcd: fix "spi_rd8" uses dynamic stack allocation warning") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/aJTMVAPtRe5H6jug@stanley.mountain Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/max3421-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index dcf31a592f5d..4b5f03f683f7 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1916,7 +1916,7 @@ error: if (hcd) { kfree(max3421_hcd->tx); kfree(max3421_hcd->rx); - if (max3421_hcd->spi_thread) + if (!IS_ERR_OR_NULL(max3421_hcd->spi_thread)) kthread_stop(max3421_hcd->spi_thread); usb_put_hcd(hcd); } From 738812440b3c9083188191caa62ef950cf1ed9ed Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 7 Aug 2025 16:43:50 -0500 Subject: [PATCH 0091/2711] dt-bindings: usb: Drop duplicate nvidia,tegra20-ehci.txt The nvidia,tegra20-ehci binding is already documented in ci-hdrc-usb2.yaml, so drop the old text binding. Signed-off-by: "Rob Herring (Arm)" Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250807214351.4172243-1-robh@kernel.org Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/nvidia,tegra20-ehci.txt | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt deleted file mode 100644 index f60785f73d3d..000000000000 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt +++ /dev/null @@ -1,23 +0,0 @@ -Tegra SOC USB controllers - -The device node for a USB controller that is part of a Tegra -SOC is as described in the document "Open Firmware Recommended -Practice : Universal Serial Bus" with the following modifications -and additions : - -Required properties : - - compatible : For Tegra20, must contain "nvidia,tegra20-ehci". - For Tegra30, must contain "nvidia,tegra30-ehci". Otherwise, must contain - "nvidia,-ehci" plus at least one of the above, where is - tegra114, tegra124, tegra132, or tegra210. - - nvidia,phy : phandle of the PHY that the controller is connected to. - - clocks : Must contain one entry, for the module clock. - See ../clocks/clock-bindings.txt for details. - - resets : Must contain an entry for each entry in reset-names. - See ../reset/reset.txt for details. - - reset-names : Must include the following entries: - - usb - -Optional properties: - - nvidia,needs-double-reset : boolean is to be set for some of the Tegra20 - USB ports, which need reset twice due to hardware issues. From c0485e864a2eaa1d5a84c71e573dd236d0e885ae Mon Sep 17 00:00:00 2001 From: Komal Bajaj Date: Thu, 31 Jul 2025 14:31:32 +0530 Subject: [PATCH 0092/2711] usb: misc: qcom_eud: Access EUD_MODE_MANAGER2 through secure calls EUD_MODE_MANAGER2 register is mapped to a memory region that is marked as read-only for operating system running at EL1, enforcing access restrictions that prohibit direct memory-mapped writes via writel(). Attempts to write to this region from HLOS can result in silent failures or memory access violations, particularly when toggling EUD (Embedded USB Debugger) state. To ensure secure register access, modify the driver to use qcom_scm_io_writel(), which routes the write operation to Qualcomm Secure Channel Monitor (SCM). SCM has the necessary permissions to access protected memory regions, enabling reliable control over EUD state. SC7280, the only user of EUD is also affected, indicating that this could never have worked on a properly fused device. Fixes: 9a1bf58ccd44 ("usb: misc: eud: Add driver support for Embedded USB Debugger(EUD)") Signed-off-by: Melody Olvera Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Reviewed-by: Souradeep Chowdhury Signed-off-by: Komal Bajaj Link: https://lore.kernel.org/r/20250731-eud_mode_manager_secure_access-v8-1-4a5dcbb79f41@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/Kconfig | 1 + drivers/usb/misc/qcom_eud.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 6497c4e81e95..9bf8fc6247ba 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -147,6 +147,7 @@ config USB_APPLEDISPLAY config USB_QCOM_EUD tristate "QCOM Embedded USB Debugger(EUD) Driver" depends on ARCH_QCOM || COMPILE_TEST + select QCOM_SCM select USB_ROLE_SWITCH help This module enables support for Qualcomm Technologies, Inc. diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c index 67832790acad..926419ca560f 100644 --- a/drivers/usb/misc/qcom_eud.c +++ b/drivers/usb/misc/qcom_eud.c @@ -15,6 +15,7 @@ #include #include #include +#include #define EUD_REG_INT1_EN_MASK 0x0024 #define EUD_REG_INT_STATUS_1 0x0044 @@ -34,7 +35,7 @@ struct eud_chip { struct device *dev; struct usb_role_switch *role_sw; void __iomem *base; - void __iomem *mode_mgr; + phys_addr_t mode_mgr; unsigned int int_status; int irq; bool enabled; @@ -43,18 +44,29 @@ struct eud_chip { static int enable_eud(struct eud_chip *priv) { + int ret; + + ret = qcom_scm_io_writel(priv->mode_mgr + EUD_REG_EUD_EN2, 1); + if (ret) + return ret; + writel(EUD_ENABLE, priv->base + EUD_REG_CSR_EUD_EN); writel(EUD_INT_VBUS | EUD_INT_SAFE_MODE, priv->base + EUD_REG_INT1_EN_MASK); - writel(1, priv->mode_mgr + EUD_REG_EUD_EN2); return usb_role_switch_set_role(priv->role_sw, USB_ROLE_DEVICE); } -static void disable_eud(struct eud_chip *priv) +static int disable_eud(struct eud_chip *priv) { + int ret; + + ret = qcom_scm_io_writel(priv->mode_mgr + EUD_REG_EUD_EN2, 0); + if (ret) + return ret; + writel(0, priv->base + EUD_REG_CSR_EUD_EN); - writel(0, priv->mode_mgr + EUD_REG_EUD_EN2); + return 0; } static ssize_t enable_show(struct device *dev, @@ -82,11 +94,12 @@ static ssize_t enable_store(struct device *dev, chip->enabled = enable; else disable_eud(chip); + } else { - disable_eud(chip); + ret = disable_eud(chip); } - return count; + return ret < 0 ? ret : count; } static DEVICE_ATTR_RW(enable); @@ -178,6 +191,7 @@ static void eud_role_switch_release(void *data) static int eud_probe(struct platform_device *pdev) { struct eud_chip *chip; + struct resource *res; int ret; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); @@ -199,9 +213,10 @@ static int eud_probe(struct platform_device *pdev) if (IS_ERR(chip->base)) return PTR_ERR(chip->base); - chip->mode_mgr = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(chip->mode_mgr)) - return PTR_ERR(chip->mode_mgr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -ENODEV; + chip->mode_mgr = res->start; chip->irq = platform_get_irq(pdev, 0); if (chip->irq < 0) From 96c08ff80b8fce45e49fee5eba4b40b1654eb5aa Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 6 Aug 2025 14:46:12 +0300 Subject: [PATCH 0093/2711] tty: sysrq: delete unnecessary check This code checks if (write) is true twice in a row. It's more readable to delete the first check. Signed-off-by: Dan Carpenter Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/aJNAhHtKkhWjosDV@stanley.mountain Signed-off-by: Greg Kroah-Hartman --- drivers/tty/sysrq.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 97f8a9a52285..1f78b0db3b25 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -1133,8 +1133,7 @@ static int sysrq_sysctl_handler(const struct ctl_table *table, int write, * Behaves like do_proc_dointvec as t does not have min nor max. */ ret = proc_dointvec_minmax(&t, write, buffer, lenp, ppos); - - if (ret || !write) + if (ret) return ret; if (write) From d903f5c60a0ea95aa03d5158d38bb057da6eae3e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 4 Aug 2025 17:20:40 -0500 Subject: [PATCH 0094/2711] dt-bindings: clock: Convert silabs,si514/544 to DT schema Convert the Silicon Labs SI514 and SI544 bindings to DT schema format. Combine the bindings into a single schema as they are the same. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250804222042.4083656-1-robh@kernel.org Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- .../bindings/clock/silabs,si514.txt | 24 --------- .../bindings/clock/silabs,si544.txt | 25 --------- .../bindings/clock/silabs,si544.yaml | 54 +++++++++++++++++++ 3 files changed, 54 insertions(+), 49 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/silabs,si514.txt delete mode 100644 Documentation/devicetree/bindings/clock/silabs,si544.txt create mode 100644 Documentation/devicetree/bindings/clock/silabs,si544.yaml diff --git a/Documentation/devicetree/bindings/clock/silabs,si514.txt b/Documentation/devicetree/bindings/clock/silabs,si514.txt deleted file mode 100644 index a4f28ec86f35..000000000000 --- a/Documentation/devicetree/bindings/clock/silabs,si514.txt +++ /dev/null @@ -1,24 +0,0 @@ -Binding for Silicon Labs 514 programmable I2C clock generator. - -Reference -This binding uses the common clock binding[1]. Details about the device can be -found in the datasheet[2]. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Si514 datasheet - https://www.silabs.com/Support%20Documents/TechnicalDocs/si514.pdf - -Required properties: - - compatible: Shall be "silabs,si514" - - reg: I2C device address. - - #clock-cells: From common clock bindings: Shall be 0. - -Optional properties: - - clock-output-names: From common clock bindings. Recommended to be "si514". - -Example: - si514: clock-generator@55 { - reg = <0x55>; - #clock-cells = <0>; - compatible = "silabs,si514"; - }; diff --git a/Documentation/devicetree/bindings/clock/silabs,si544.txt b/Documentation/devicetree/bindings/clock/silabs,si544.txt deleted file mode 100644 index b86535b80920..000000000000 --- a/Documentation/devicetree/bindings/clock/silabs,si544.txt +++ /dev/null @@ -1,25 +0,0 @@ -Binding for Silicon Labs 544 programmable I2C clock generator. - -Reference -This binding uses the common clock binding[1]. Details about the device can be -found in the datasheet[2]. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Si544 datasheet - https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf - -Required properties: - - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according - to the speed grade of the chip. - - reg: I2C device address. - - #clock-cells: From common clock bindings: Shall be 0. - -Optional properties: - - clock-output-names: From common clock bindings. Recommended to be "si544". - -Example: - si544: clock-controller@55 { - reg = <0x55>; - #clock-cells = <0>; - compatible = "silabs,si544b"; - }; diff --git a/Documentation/devicetree/bindings/clock/silabs,si544.yaml b/Documentation/devicetree/bindings/clock/silabs,si544.yaml new file mode 100644 index 000000000000..f87e71867108 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/silabs,si544.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/silabs,si544.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Silicon Labs SI514/SI544 clock generator + +maintainers: + - Mike Looijmans + +description: > + Silicon Labs 514/544 programmable I2C clock generator. Details about the device + can be found in the datasheet: + + https://www.silabs.com/Support%20Documents/TechnicalDocs/si514.pdf + https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf + +properties: + compatible: + enum: + - silabs,si514 + - silabs,si544a + - silabs,si544b + - silabs,si544c + + reg: + maxItems: 1 + + "#clock-cells": + const: 0 + + clock-output-names: + maxItems: 1 + +required: + - compatible + - reg + - "#clock-cells" + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + clock-controller@55 { + reg = <0x55>; + #clock-cells = <0>; + compatible = "silabs,si544b"; + }; + }; From b02011c8c61f1e61d6b4edf6a9e24620c965d376 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 4 Aug 2025 17:20:32 -0500 Subject: [PATCH 0095/2711] dt-bindings: clock: Convert silabs,si5341 to DT schema Convert the Silicon Labs SI5341 binding to DT schema format. It's a straight-forward conversion. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250804222034.4083410-1-robh@kernel.org Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- .../bindings/clock/silabs,si5341.txt | 175 -------------- .../bindings/clock/silabs,si5341.yaml | 217 ++++++++++++++++++ 2 files changed, 217 insertions(+), 175 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/silabs,si5341.txt create mode 100644 Documentation/devicetree/bindings/clock/silabs,si5341.yaml diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt b/Documentation/devicetree/bindings/clock/silabs,si5341.txt deleted file mode 100644 index ce55aba0ce22..000000000000 --- a/Documentation/devicetree/bindings/clock/silabs,si5341.txt +++ /dev/null @@ -1,175 +0,0 @@ -Binding for Silicon Labs Si5340, Si5341 Si5342, Si5344 and Si5345 programmable -i2c clock generator. - -Reference -[1] Si5341 Data Sheet - https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf -[2] Si5341 Reference Manual - https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf -[3] Si5345 Reference Manual - https://www.silabs.com/documents/public/reference-manuals/Si5345-44-42-D-RM.pdf - -The Si5341 and Si5340 are programmable i2c clock generators with up to 10 output -clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which -in turn can be directed to any of the 10 (or 4) outputs through a divider. -The internal structure of the clock generators can be found in [2]. -The Si5345 is similar to the Si5341 with the addition of fractional input -dividers and automatic input selection, as described in [3]. -The Si5342 and Si5344 are smaller versions of the Si5345, with 2 or 4 outputs. - -The driver can be used in "as is" mode, reading the current settings from the -chip at boot, in case you have a (pre-)programmed device. If the PLL is not -configured when the driver probes, it assumes the driver must fully initialize -it. - -The device type, speed grade and revision are determined runtime by probing. - -The driver currently does not support any fancy input configurations. They can -still be programmed into the chip and the driver will leave them "as is". - -==I2C device node== - -Required properties: -- compatible: shall be one of the following: - "silabs,si5340" - Si5340 A/B/C/D - "silabs,si5341" - Si5341 A/B/C/D - "silabs,si5342" - Si5342 A/B/C/D - "silabs,si5344" - Si5344 A/B/C/D - "silabs,si5345" - Si5345 A/B/C/D -- reg: i2c device address, usually 0x74 -- #clock-cells: from common clock binding; shall be set to 2. - The first value is "0" for outputs, "1" for synthesizers. - The second value is the output or synthesizer index. -- clocks: from common clock binding; list of parent clock handles, - corresponding to inputs. Use a fixed clock for the "xtal" input. - At least one must be present. -- clock-names: One of: "xtal", "in0", "in1", "in2" - -Optional properties: -- vdd-supply: Regulator node for VDD -- vdda-supply: Regulator node for VDDA -- vdds-supply: Regulator node for VDDS -- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL - feedback divider. Must be such that the PLL output is in the valid range. For - example, to create 14GHz from a 48MHz xtal, use m-num=14000 and m-den=48. Only - the fraction matters, using 3500 and 12 will deliver the exact same result. - If these are not specified, and the PLL is not yet programmed when the driver - probes, the PLL will be set to 14GHz. -- silabs,reprogram: When present, the driver will always assume the device must - be initialized, and always performs the soft-reset routine. Since this will - temporarily stop all output clocks, don't do this if the chip is generating - the CPU clock for example. -- silabs,xaxb-ext-clk: When present, indicates that the XA/XB pins are used - in EXTCLK (external reference clock) rather than XTAL (crystal) mode. -- interrupts: Interrupt for INTRb pin. -- silabs,iovdd-33: When present, indicates that the I2C lines are using 3.3V - rather than 1.8V thresholds. -- vddoX-supply (where X is an output index): Regulator node for VDDO for the - specified output. The driver selects the output VDD_SEL setting based on this - voltage. -- #address-cells: shall be set to 1. -- #size-cells: shall be set to 0. - - -== Child nodes: Outputs == - -The child nodes list the output clocks. - -Each of the clock outputs can be overwritten individually by using a child node. -If a child node for a clock output is not set, the configuration remains -unchanged. - -Required child node properties: -- reg: number of clock output. - -Optional child node properties: -- silabs,format: Output format, one of: - 1 = differential (defaults to LVDS levels) - 2 = low-power (defaults to HCSL levels) - 4 = LVCMOS -- silabs,common-mode: Manually override output common mode, see [2] for values -- silabs,amplitude: Manually override output amplitude, see [2] for values -- silabs,synth-master: boolean. If present, this output is allowed to change the - multisynth frequency dynamically. -- silabs,silabs,disable-high: boolean. If set, the clock output is driven HIGH - when disabled, otherwise it's driven LOW. - -==Example== - -/* 48MHz reference crystal */ -ref48: ref48M { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <48000000>; -}; - -i2c-master-node { - /* Programmable clock (for logic) */ - si5341: clock-generator@74 { - reg = <0x74>; - compatible = "silabs,si5341"; - #clock-cells = <2>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&ref48>; - clock-names = "xtal"; - - silabs,pll-m-num = <14000>; /* PLL at 14.0 GHz */ - silabs,pll-m-den = <48>; - silabs,reprogram; /* Chips are not programmed, always reset */ - - out@0 { - reg = <0>; - silabs,format = <1>; /* LVDS 3v3 */ - silabs,common-mode = <3>; - silabs,amplitude = <3>; - silabs,synth-master; - }; - - /* - * Output 6 configuration: - * LVDS 1v8 - */ - out@6 { - reg = <6>; - silabs,format = <1>; /* LVDS 1v8 */ - silabs,common-mode = <13>; - silabs,amplitude = <3>; - }; - - /* - * Output 8 configuration: - * HCSL 3v3 - */ - out@8 { - reg = <8>; - silabs,format = <2>; - silabs,common-mode = <11>; - silabs,amplitude = <3>; - }; - }; -}; - -some-video-node { - /* Standard clock bindings */ - clock-names = "pixel"; - clocks = <&si5341 0 7>; /* Output 7 */ - - /* Set output 7 to use syntesizer 3 as its parent */ - assigned-clocks = <&si5341 0 7>, <&si5341 1 3>; - assigned-clock-parents = <&si5341 1 3>; - /* Set output 7 to 148.5 MHz using a synth frequency of 594 MHz */ - assigned-clock-rates = <148500000>, <594000000>; -}; - -some-audio-node { - clock-names = "i2s-clk"; - clocks = <&si5341 0 0>; - /* - * since output 0 is a synth-master, the synth will be automatically set - * to an appropriate frequency when the audio driver requests another - * frequency. We give control over synth 2 to this output here. - */ - assigned-clocks = <&si5341 0 0>; - assigned-clock-parents = <&si5341 1 2>; -}; diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.yaml b/Documentation/devicetree/bindings/clock/silabs,si5341.yaml new file mode 100644 index 000000000000..b4f7efdf0b7b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/silabs,si5341.yaml @@ -0,0 +1,217 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/silabs,si5341.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Silicon Labs Si5340/1/2/4/5 programmable i2c clock generator + +maintainers: + - Mike Looijmans + +description: > + Silicon Labs Si5340, Si5341 Si5342, Si5344 and Si5345 programmable i2c clock + generator. + + Reference + [1] Si5341 Data Sheet + https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf + [2] Si5341 Reference Manual + https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf + [3] Si5345 Reference Manual + https://www.silabs.com/documents/public/reference-manuals/Si5345-44-42-D-RM.pdf + + The Si5341 and Si5340 are programmable i2c clock generators with up to 10 output + clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which + in turn can be directed to any of the 10 (or 4) outputs through a divider. + The internal structure of the clock generators can be found in [2]. + The Si5345 is similar to the Si5341 with the addition of fractional input + dividers and automatic input selection, as described in [3]. + The Si5342 and Si5344 are smaller versions of the Si5345, with 2 or 4 outputs. + + The driver can be used in "as is" mode, reading the current settings from the + chip at boot, in case you have a (pre-)programmed device. If the PLL is not + configured when the driver probes, it assumes the driver must fully initialize + it. + + The device type, speed grade and revision are determined runtime by probing. + +properties: + compatible: + enum: + - silabs,si5340 + - silabs,si5341 + - silabs,si5342 + - silabs,si5344 + - silabs,si5345 + + reg: + maxItems: 1 + + "#clock-cells": + const: 2 + description: > + The first value is "0" for outputs, "1" for synthesizers. + + The second value is the output or synthesizer index. + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + clocks: + minItems: 1 + maxItems: 4 + + clock-names: + minItems: 1 + items: + - const: xtal + - const: in0 + - const: in1 + - const: in2 + + interrupts: + maxItems: 1 + description: Interrupt for INTRb pin + + vdd-supply: + description: Regulator node for VDD + + vdda-supply: + description: Regulator node for VDDA + + vdds-supply: + description: Regulator node for VDDS + + silabs,pll-m-num: + description: + Numerator for PLL feedback divider. Must be such that the PLL output is in + the valid range. For example, to create 14GHz from a 48MHz xtal, use + m-num=14000 and m-den=48. Only the fraction matters, using 3500 and 12 + will deliver the exact same result. If these are not specified, and the + PLL is not yet programmed when the driver probes, the PLL will be set to + 14GHz. + $ref: /schemas/types.yaml#/definitions/uint32 + + silabs,pll-m-den: + description: Denominator for PLL feedback divider + $ref: /schemas/types.yaml#/definitions/uint32 + + silabs,reprogram: + description: Always perform soft-reset and reinitialize PLL + type: boolean + + silabs,xaxb-ext-clk: + description: Use XA/XB pins as external reference clock + type: boolean + + silabs,iovdd-33: + description: I2C lines use 3.3V thresholds + type: boolean + +patternProperties: + "^vddo[0-9]-supply$": true + + "^out@[0-9]$": + description: > + Output-specific override nodes + + Each of the clock outputs can be overwritten individually by using a child + node. If a child node for a clock output is not set, the configuration + remains unchanged. + type: object + additionalProperties: false + + properties: + reg: + description: Number of clock output + maximum: 9 + + silabs,format: + description: Output format + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 4] + + silabs,common-mode: + description: Override output common mode + $ref: /schemas/types.yaml#/definitions/uint32 + + silabs,amplitude: + description: Override output amplitude + $ref: /schemas/types.yaml#/definitions/uint32 + + silabs,synth-master: + description: Allow dynamic multisynth rate control + type: boolean + + silabs,disable-high: + description: Drive output HIGH when disabled + type: boolean + + required: + - reg + +required: + - compatible + - reg + - "#clock-cells" + - "#address-cells" + - "#size-cells" + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + clock-generator@74 { + reg = <0x74>; + compatible = "silabs,si5341"; + #clock-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&ref48>; + clock-names = "xtal"; + + silabs,pll-m-num = <14000>; /* PLL at 14.0 GHz */ + silabs,pll-m-den = <48>; + silabs,reprogram; /* Chips are not programmed, always reset */ + + out@0 { + reg = <0>; + silabs,format = <1>; /* LVDS 3v3 */ + silabs,common-mode = <3>; + silabs,amplitude = <3>; + silabs,synth-master; + }; + + /* + * Output 6 configuration: + * LVDS 1v8 + */ + out@6 { + reg = <6>; + silabs,format = <1>; /* LVDS 1v8 */ + silabs,common-mode = <13>; + silabs,amplitude = <3>; + }; + + /* + * Output 8 configuration: + * HCSL 3v3 + */ + out@8 { + reg = <8>; + silabs,format = <2>; + silabs,common-mode = <11>; + silabs,amplitude = <3>; + }; + }; + }; From 7513cc391400ef1b27c422b251c2444097ed1ce7 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 4 Aug 2025 17:20:08 -0500 Subject: [PATCH 0096/2711] dt-bindings: clock: Convert silabs,si570 to DT schema Convert the Silicon Labs SI570 binding to DT schema format. It's a straight-forward conversion. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250804222010.4082782-1-robh@kernel.org Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- .../bindings/clock/silabs,si570.txt | 41 ---------- .../bindings/clock/silabs,si570.yaml | 80 +++++++++++++++++++ 2 files changed, 80 insertions(+), 41 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/silabs,si570.txt create mode 100644 Documentation/devicetree/bindings/clock/silabs,si570.yaml diff --git a/Documentation/devicetree/bindings/clock/silabs,si570.txt b/Documentation/devicetree/bindings/clock/silabs,si570.txt deleted file mode 100644 index 5dda17df1ac5..000000000000 --- a/Documentation/devicetree/bindings/clock/silabs,si570.txt +++ /dev/null @@ -1,41 +0,0 @@ -Binding for Silicon Labs 570, 571, 598 and 599 programmable -I2C clock generators. - -Reference -This binding uses the common clock binding[1]. Details about the devices can be -found in the data sheets[2][3]. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Si570/571 Data Sheet - https://www.silabs.com/Support%20Documents/TechnicalDocs/si570.pdf -[3] Si598/599 Data Sheet - https://www.silabs.com/Support%20Documents/TechnicalDocs/si598-99.pdf - -Required properties: - - compatible: Shall be one of "silabs,si570", "silabs,si571", - "silabs,si598", "silabs,si599" - - reg: I2C device address. - - #clock-cells: From common clock bindings: Shall be 0. - - factory-fout: Factory set default frequency. This frequency is part specific. - The correct frequency for the part used has to be provided in - order to generate the correct output frequencies. For more - details, please refer to the data sheet. - - temperature-stability: Temperature stability of the device in PPM. Should be - one of: 7, 20, 50 or 100. - -Optional properties: - - clock-output-names: From common clock bindings. Recommended to be "si570". - - clock-frequency: Output frequency to generate. This defines the output - frequency set during boot. It can be reprogrammed during - runtime through the common clock framework. - - silabs,skip-recall: Do not perform NVM->RAM recall operation. It will rely - on hardware loading of RAM from NVM at power on. - -Example: - si570: clock-generator@5d { - #clock-cells = <0>; - compatible = "silabs,si570"; - temperature-stability = <50>; - reg = <0x5d>; - factory-fout = <156250000>; - }; diff --git a/Documentation/devicetree/bindings/clock/silabs,si570.yaml b/Documentation/devicetree/bindings/clock/silabs,si570.yaml new file mode 100644 index 000000000000..90e2f79e2b2a --- /dev/null +++ b/Documentation/devicetree/bindings/clock/silabs,si570.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/silabs,si570.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Silicon Labs Si570/Si571/Si598/Si599 programmable I2C clock generator + +maintainers: + - Soren Brinkmann + +description: > + Silicon Labs 570, 571, 598 and 599 programmable I2C clock generators. Details + about the devices can be found in the data sheets[1][2]. + + [1] Si570/571 Data Sheet + https://www.silabs.com/Support%20Documents/TechnicalDocs/si570.pdf + [2] Si598/599 Data Sheet + https://www.silabs.com/Support%20Documents/TechnicalDocs/si598-99.pdf + +properties: + compatible: + enum: + - silabs,si570 + - silabs,si571 + - silabs,si598 + - silabs,si599 + + reg: + maxItems: 1 + + '#clock-cells': + const: 0 + + factory-fout: + description: Factory-set default frequency in Hz. + $ref: /schemas/types.yaml#/definitions/uint32 + + temperature-stability: + description: Temperature stability of the device in PPM. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 7 + - 20 + - 50 + - 100 + + clock-output-names: + maxItems: 1 + + clock-frequency: + description: Output frequency to generate at boot; can be reprogrammed at runtime. + + silabs,skip-recall: + description: Skip the NVM-to-RAM recall operation during boot. + type: boolean + +required: + - compatible + - reg + - '#clock-cells' + - factory-fout + - temperature-stability + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + clock-generator@5d { + compatible = "silabs,si570"; + reg = <0x5d>; + #clock-cells = <0>; + temperature-stability = <50>; + factory-fout = <156250000>; + }; + }; From d0a2dee7d4585a7ebab45bf63eebeb8b6944e88f Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 13 Aug 2025 07:11:01 +0200 Subject: [PATCH 0097/2711] PCI/AER: Allow drivers to opt in to Bus Reset on Non-Fatal Errors When Advanced Error Reporting was introduced in September 2006 by commit 6c2b374d7485 ("PCI-Express AER implemetation: AER core and aerdriver"), it sought to adhere to the recovery flow and callbacks specified in Documentation/PCI/pci-error-recovery.rst. That document had been added in January 2006, when Enhanced Error Handling (EEH) was introduced for PowerPC with commit 065c6359071c ("[PATCH] PCI Error Recovery: documentation"). However the AER driver deviates from the document in that it never performs a Secondary Bus Reset on Non-Fatal Errors, but always on Fatal Errors. By contrast, EEH allows drivers to opt in or out of a Bus Reset regardless of error severity, by returning PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_CAN_RECOVER from their ->error_detected() callback. If all drivers agree that they can recover without a Bus Reset, EEH skips it. Should one of them request a Bus Reset, it overrides all other drivers. This inconsistency between EEH and AER seems problematic because drivers need to be aware of and cope with it. The file Documentation/PCI/pcieaer-howto.rst hints at a rationale for always performing a Bus Reset on Fatal Errors: "Fatal errors [...] cause the link to be unreliable. [...] This [reset_link] callback is used to reset the PCIe physical link when a fatal error happens. If an error message indicates a fatal error, [...] performing link reset at upstream is necessary." There's no such rationale provided for never performing a Bus Reset on Non-Fatal Errors. The "xe" driver has a need to attempt a reset of local units on graphics cards upon a Non-Fatal Error. If that is insufficient for recovery, the driver wants to opt in to a Bus Reset. Accommodate such use cases and align AER more closely with EEH by performing a Bus Reset in pcie_do_recovery() if drivers request it and the faulting device's channel_state is pci_channel_io_normal. The AER driver sets this channel_state for Non-Fatal Errors. For Fatal Errors, it uses pci_channel_io_frozen. This limits the deviation from Documentation/PCI/pci-error-recovery.rst and EEH to the unconditional Bus Reset on Fatal Errors. pcie_do_recovery() is also invoked by the Downstream Port Containment and Error Disconnect Recover drivers. They both set the channel_state to pci_channel_io_frozen, hence pcie_do_recovery() continues to always invoke the ->reset_subordinates() callback in their case. That is necessary because the callback brings the link back up at the containing Downstream Port. There are two behavioral changes resulting from this commit: First, if channel_state is pci_channel_io_normal and one of the affected drivers returns PCI_ERS_RESULT_NEED_RESET from its ->error_detected() callback, a Bus Reset will now be performed. There are drivers doing this and although it would be possible to avoid a behavioral change by letting them return PCI_ERS_RESULT_CAN_RECOVER instead, the impression I got from examination of all drivers is that they actually expect or want a Bus Reset (cxl_error_detected() is a case in point). In any case, if they can cope with a Bus Reset on Fatal Errors, they shouldn't have issues with a Bus Reset on Non-Fatal Errors. Second, if channel_state is pci_channel_io_frozen and all affected drivers return PCI_ERS_RESULT_CAN_RECOVER from ->error_detected(), their ->mmio_enabled() callback is now invoked prior to performing a Bus Reset, instead of afterwards. This actually makes sense: For example, drivers/scsi/sym53c8xx_2/sym_glue.c dumps debug registers in its ->mmio_enabled() callback. Doing so after reset right now captures the post-reset state instead of the faulting state, which is useless. There is only one other driver which implements ->mmio_enabled() and returns PCI_ERS_RESULT_CAN_RECOVER from ->error_detected() for channel_state pci_channel_io_frozen, drivers/scsi/ipr.c (IBM Power RAID). It appears to only be used on EEH platforms. So the second behavioral change is limited to these two drivers. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/28fd805043bb57af390168d05abb30898cf4fc58.1755008151.git.lukas@wunner.de --- drivers/pci/pcie/err.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index de6381c690f5..e795e5ae6b03 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -217,15 +217,10 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev, pci_walk_bridge(bridge, pci_pm_runtime_get_sync, NULL); pci_dbg(bridge, "broadcast error_detected message\n"); - if (state == pci_channel_io_frozen) { + if (state == pci_channel_io_frozen) pci_walk_bridge(bridge, report_frozen_detected, &status); - if (reset_subordinates(bridge) != PCI_ERS_RESULT_RECOVERED) { - pci_warn(bridge, "subordinate device reset failed\n"); - goto failed; - } - } else { + else pci_walk_bridge(bridge, report_normal_detected, &status); - } if (status == PCI_ERS_RESULT_CAN_RECOVER) { status = PCI_ERS_RESULT_RECOVERED; @@ -233,6 +228,14 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev, pci_walk_bridge(bridge, report_mmio_enabled, &status); } + if (status == PCI_ERS_RESULT_NEED_RESET || + state == pci_channel_io_frozen) { + if (reset_subordinates(bridge) != PCI_ERS_RESULT_RECOVERED) { + pci_warn(bridge, "subordinate device reset failed\n"); + goto failed; + } + } + if (status == PCI_ERS_RESULT_NEED_RESET) { /* * TODO: Should call platform-specific From 1cbc5e25fb70e942a7a735a1f3d6dd391afc9b29 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 13 Aug 2025 07:11:02 +0200 Subject: [PATCH 0098/2711] PCI/ERR: Fix uevent on failure to recover Upon failure to recover from a PCIe error through AER, DPC or EDR, a uevent is sent to inform user space about disconnection of the bridge whose subordinate devices failed to recover. However the bridge itself is not disconnected. Instead, a uevent should be sent for each of the subordinate devices. Only if the "bridge" happens to be a Root Complex Event Collector or Integrated Endpoint does it make sense to send a uevent for it (because there are no subordinate devices). Right now if there is a mix of subordinate devices with and without pci_error_handlers, a BEGIN_RECOVERY event is sent for those with pci_error_handlers but no FAILED_RECOVERY event is ever sent for them afterwards. Fix it. Fixes: 856e1eb9bdd4 ("PCI/AER: Add uevents in AER and EEH error/resume") Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org # v4.16+ Link: https://patch.msgid.link/68fc527a380821b5d861dd554d2ce42cb739591c.1755008151.git.lukas@wunner.de --- drivers/pci/pcie/err.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index e795e5ae6b03..21d554359fb1 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -108,6 +108,12 @@ static int report_normal_detected(struct pci_dev *dev, void *data) return report_error_detected(dev, pci_channel_io_normal, data); } +static int report_perm_failure_detected(struct pci_dev *dev, void *data) +{ + pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT); + return 0; +} + static int report_mmio_enabled(struct pci_dev *dev, void *data) { struct pci_driver *pdrv; @@ -272,7 +278,7 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev, failed: pci_walk_bridge(bridge, pci_pm_runtime_put, NULL); - pci_uevent_ers(bridge, PCI_ERS_RESULT_DISCONNECT); + pci_walk_bridge(bridge, report_perm_failure_detected, NULL); pci_info(bridge, "device recovery failed\n"); From 9011f0667c93df2034f2ff33eae37ddf9bdd0ef9 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 13 Aug 2025 07:11:03 +0200 Subject: [PATCH 0099/2711] PCI/ERR: Notify drivers on failure to recover According to Documentation/PCI/pci-error-recovery.rst, the following shall occur on failure to recover from a PCIe Uncorrectable Error: STEP 6: Permanent Failure ------------------------- A "permanent failure" has occurred, and the platform cannot recover the device. The platform will call error_detected() with a pci_channel_state_t value of pci_channel_io_perm_failure. The device driver should, at this point, assume the worst. It should cancel all pending I/O, refuse all new I/O, returning -EIO to higher layers. The device driver should then clean up all of its memory and remove itself from kernel operations, much as it would during system shutdown. Sathya notes that AER does not call error_detected() on failure and thus deviates from the document (as well as EEH, for which the document was originally added). Most drivers do nothing on permanent failure, but the SCSI drivers and a number of Ethernet drivers do take advantage of the notification to flush queues and give up resources. Amend AER to notify such drivers and align with the documentation and EEH. Link: https://lore.kernel.org/r/f496fc0f-64d7-46a4-8562-dba74e31a956@linux.intel.com/ Suggested-by: Sathyanarayanan Kuppuswamy Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/ec212d4d4f5c65d29349df33acdc9768ff8279d1.1755008151.git.lukas@wunner.de --- drivers/pci/pcie/err.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 21d554359fb1..930bb60fb761 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -110,7 +110,19 @@ static int report_normal_detected(struct pci_dev *dev, void *data) static int report_perm_failure_detected(struct pci_dev *dev, void *data) { + struct pci_driver *pdrv; + const struct pci_error_handlers *err_handler; + + device_lock(&dev->dev); + pdrv = dev->driver; + if (!pdrv || !pdrv->err_handler || !pdrv->err_handler->error_detected) + goto out; + + err_handler = pdrv->err_handler; + err_handler->error_detected(dev, pci_channel_io_perm_failure); +out: pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT); + device_unlock(&dev->dev); return 0; } From 45bc82563d5505327d97963bc54d3709939fa8f8 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 13 Aug 2025 07:11:04 +0200 Subject: [PATCH 0100/2711] PCI/ERR: Update device error_state already after reset After a Fatal Error has been reported by a device and has been recovered through a Secondary Bus Reset, AER updates the device's error_state to pci_channel_io_normal before invoking its driver's ->resume() callback. By contrast, EEH updates the error_state earlier, namely after resetting the device and before invoking its driver's ->slot_reset() callback. Commit c58dc575f3c8 ("powerpc/pseries: Set error_state to pci_channel_io_normal in eeh_report_reset()") explains in great detail that the earlier invocation is necessitated by various drivers checking accessibility of the device with pci_channel_offline() and avoiding accesses if it returns true. It returns true for any other error_state than pci_channel_io_normal. The device should be accessible already after reset, hence the reasoning is that it's safe to update the error_state immediately afterwards. This deviation between AER and EEH seems problematic because drivers behave differently depending on which error recovery mechanism the platform uses. Three drivers have gone so far as to update the error_state themselves, presumably to work around AER's behavior. For consistency, amend AER to update the error_state at the same recovery steps as EEH. Drop the now unnecessary workaround from the three drivers. Keep updating the error_state before ->resume() in case ->error_detected() or ->mmio_enabled() return PCI_ERS_RESULT_RECOVERED, which causes ->slot_reset() to be skipped. There are drivers doing this even for Fatal Errors, e.g. mhi_pci_error_detected(). Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/4517af6359ffb9d66152b827a5d2833459144e3f.1755008151.git.lukas@wunner.de --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 1 - drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 2 -- drivers/pci/pcie/err.c | 3 ++- drivers/scsi/qla2xxx/qla_os.c | 5 ----- 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index d7cdea8f604d..91e7b38143ea 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -4215,7 +4215,6 @@ static pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *pdev) struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); int err = 0; - pdev->error_state = pci_channel_io_normal; err = pci_enable_device(pdev); if (err) goto disconnect; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 53cdd36c4123..e051d8c7a28d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -3766,8 +3766,6 @@ static int qlcnic_attach_func(struct pci_dev *pdev) struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; - pdev->error_state = pci_channel_io_normal; - err = pci_enable_device(pdev); if (err) return err; diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 930bb60fb761..bebe4bc111d7 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -153,7 +153,8 @@ static int report_slot_reset(struct pci_dev *dev, void *data) device_lock(&dev->dev); pdrv = dev->driver; - if (!pdrv || !pdrv->err_handler || !pdrv->err_handler->slot_reset) + if (!pci_dev_set_io_state(dev, pci_channel_io_normal) || + !pdrv || !pdrv->err_handler || !pdrv->err_handler->slot_reset) goto out; err_handler = pdrv->err_handler; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d4b484c0fd9d..4460421834cb 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -7883,11 +7883,6 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) "Slot Reset.\n"); ha->pci_error_state = QLA_PCI_SLOT_RESET; - /* Workaround: qla2xxx driver which access hardware earlier - * needs error state to be pci_channel_io_online. - * Otherwise mailbox command timesout. - */ - pdev->error_state = pci_channel_io_normal; pci_restore_state(pdev); From cc4a7a21e815f81f782506d9f554ff2158e70ce8 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 13 Aug 2025 07:11:05 +0200 Subject: [PATCH 0101/2711] PCI/ERR: Remove remnants of .link_reset() callback Back in 2017, commit 2fd260f03b6a ("PCI/AER: Remove unused .link_reset() callback") removed .link_reset() from struct pci_error_handlers, but left a few code comments behind which still mention it. Remove them. The code comments in the SolarFlare Ethernet drivers point out that no .mmio_enabled() callback is needed because the driver's .error_detected() callback always returns PCI_ERS_RESULT_NEED_RESET, which causes pcie_do_recovery() to skip .mmio_enabled(). That's not quite correct because efx_io_error_detected() does return PCI_ERS_RESULT_RECOVERED under certain conditions and then .mmio_enabled() would indeed be called if it were implemented. Remove this misleading portion of the code comment as well. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/1d72a891a7f57115e78a73046e776f7e0c8cd68f.1755008151.git.lukas@wunner.de --- drivers/net/ethernet/sfc/efx_common.c | 3 --- drivers/net/ethernet/sfc/falcon/efx.c | 3 --- drivers/net/ethernet/sfc/siena/efx_common.c | 3 --- drivers/scsi/lpfc/lpfc_init.c | 2 +- 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/net/ethernet/sfc/efx_common.c b/drivers/net/ethernet/sfc/efx_common.c index 5a14d94163b1..e8fdbb62d872 100644 --- a/drivers/net/ethernet/sfc/efx_common.c +++ b/drivers/net/ethernet/sfc/efx_common.c @@ -1258,9 +1258,6 @@ out: /* For simplicity and reliability, we always require a slot reset and try to * reset the hardware when a pci error affecting the device is detected. - * We leave both the link_reset and mmio_enabled callback unimplemented: - * with our request for slot reset the mmio_enabled callback will never be - * called, and the link_reset callback is not used by AER or EEH mechanisms. */ const struct pci_error_handlers efx_err_handlers = { .error_detected = efx_io_error_detected, diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c index b07f7e4e2877..0c784656fde9 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.c +++ b/drivers/net/ethernet/sfc/falcon/efx.c @@ -3128,9 +3128,6 @@ out: /* For simplicity and reliability, we always require a slot reset and try to * reset the hardware when a pci error affecting the device is detected. - * We leave both the link_reset and mmio_enabled callback unimplemented: - * with our request for slot reset the mmio_enabled callback will never be - * called, and the link_reset callback is not used by AER or EEH mechanisms. */ static const struct pci_error_handlers ef4_err_handlers = { .error_detected = ef4_io_error_detected, diff --git a/drivers/net/ethernet/sfc/siena/efx_common.c b/drivers/net/ethernet/sfc/siena/efx_common.c index a0966f879664..35036cc902fe 100644 --- a/drivers/net/ethernet/sfc/siena/efx_common.c +++ b/drivers/net/ethernet/sfc/siena/efx_common.c @@ -1285,9 +1285,6 @@ out: /* For simplicity and reliability, we always require a slot reset and try to * reset the hardware when a pci error affecting the device is detected. - * We leave both the link_reset and mmio_enabled callback unimplemented: - * with our request for slot reset the mmio_enabled callback will never be - * called, and the link_reset callback is not used by AER or EEH mechanisms. */ const struct pci_error_handlers efx_siena_err_handlers = { .error_detected = efx_io_error_detected, diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4081d2a358ee..cf08bb5b37c3 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -14377,7 +14377,7 @@ lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba) * as desired. * * Return codes - * PCI_ERS_RESULT_CAN_RECOVER - can be recovered with reset_link + * PCI_ERS_RESULT_CAN_RECOVER - can be recovered without reset * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery * PCI_ERS_RESULT_DISCONNECT - device could not be recovered **/ From bedeb73fb9848df572bd6e06bcac3bb374cd0e5b Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 4 Aug 2025 12:53:03 -0500 Subject: [PATCH 0102/2711] dt-bindings: clock: Remove unused fujitsu,mb86s70-crg11 binding The fujitsu,mb86s70-crg11 binding is unused. The driver for it was removed in 2017. It's not used for Synquacer DT either like some other mb86s70 bindings are. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250804175304.3423965-1-robh@kernel.org Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- .../bindings/clock/fujitsu,mb86s70-crg11.txt | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/fujitsu,mb86s70-crg11.txt diff --git a/Documentation/devicetree/bindings/clock/fujitsu,mb86s70-crg11.txt b/Documentation/devicetree/bindings/clock/fujitsu,mb86s70-crg11.txt deleted file mode 100644 index 332396265689..000000000000 --- a/Documentation/devicetree/bindings/clock/fujitsu,mb86s70-crg11.txt +++ /dev/null @@ -1,26 +0,0 @@ -Fujitsu CRG11 clock driver bindings ------------------------------------ - -Required properties : -- compatible : Shall contain "fujitsu,mb86s70-crg11" -- #clock-cells : Shall be 3 {cntrlr domain port} - -The consumer specifies the desired clock pointing to its phandle. - -Example: - - clock: crg11 { - compatible = "fujitsu,mb86s70-crg11"; - #clock-cells = <3>; - }; - - mhu: mhu0@2b1f0000 { - #mbox-cells = <1>; - compatible = "arm,mhu"; - reg = <0 0x2B1F0000 0x1000>; - interrupts = <0 36 4>, /* LP Non-Sec */ - <0 35 4>, /* HP Non-Sec */ - <0 37 4>; /* Secure */ - clocks = <&clock 0 2 1>; /* Cntrlr:0 Domain:2 Port:1 */ - clock-names = "clk"; - }; From 6793ca9a43c8c9262802af3e6096df0fa2dcaa6c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 11 Aug 2025 17:17:01 -0500 Subject: [PATCH 0103/2711] dt-bindings: clock: adi,axi-clkgen: add clock-output-names property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional `clock-output-names` property to the ADI AXI Clock Generator binding. This is already being used in the Linux driver and real-world dtbs, so we should document it to allow for correct binding validation. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20250811-dt-bindings-clk-axi-clkgen-add-clock-output-names-property-v1-1-f02727736aa7@baylibre.com Reviewed-by: Nuno Sá Acked-by: Conor Dooley Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml b/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml index 2b2041818a0a..6eea1a41150a 100644 --- a/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml +++ b/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml @@ -42,6 +42,9 @@ properties: - const: clkin2 - const: s_axi_aclk + clock-output-names: + maxItems: 1 + '#clock-cells': const: 0 @@ -65,4 +68,5 @@ examples: reg = <0xff000000 0x1000>; clocks = <&osc 1>, <&clkc 15>; clock-names = "clkin1", "s_axi_aclk"; + clock-output-names = "spi_sclk"; }; From ab81f2f79c683c94bac622aafafbe8232e547159 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Aug 2025 17:56:25 +0200 Subject: [PATCH 0104/2711] PCI/pwrctrl: Fix double cleanup on devm_add_action_or_reset() failure When devm_add_action_or_reset() fails, it calls the passed cleanup function. Hence the caller must not repeat that cleanup. Replace the "goto err_regulator_free" by the actual freeing, as there will never be a need again for a second user of this label. Fixes: 75996c92f4de309f ("PCI/pwrctrl: Add pwrctrl driver for PCI slots") Signed-off-by: Geert Uytterhoeven Signed-off-by: Bjorn Helgaas Tested-by: Marek Vasut # V4H Sparrow Hawk Reviewed-by: Manivannan Sadhasivam Reviewed-by: Marek Vasut Acked-by: Bartosz Golaszewski Link: https://patch.msgid.link/7b1386e6162e70e6d631c87f6323d2ab971bc1c5.1755100324.git.geert+renesas@glider.be --- drivers/pci/pwrctrl/slot.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c index 6e138310b45b..3320494b62d8 100644 --- a/drivers/pci/pwrctrl/slot.c +++ b/drivers/pci/pwrctrl/slot.c @@ -49,13 +49,14 @@ static int pci_pwrctrl_slot_probe(struct platform_device *pdev) ret = regulator_bulk_enable(slot->num_supplies, slot->supplies); if (ret < 0) { dev_err_probe(dev, ret, "Failed to enable slot regulators\n"); - goto err_regulator_free; + regulator_bulk_free(slot->num_supplies, slot->supplies); + return ret; } ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_power_off, slot); if (ret) - goto err_regulator_disable; + return ret; clk = devm_clk_get_optional_enabled(dev, NULL); if (IS_ERR(clk)) { @@ -70,13 +71,6 @@ static int pci_pwrctrl_slot_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "Failed to register pwrctrl driver\n"); return 0; - -err_regulator_disable: - regulator_bulk_disable(slot->num_supplies, slot->supplies); -err_regulator_free: - regulator_bulk_free(slot->num_supplies, slot->supplies); - - return ret; } static const struct of_device_id pci_pwrctrl_slot_of_match[] = { From 1ad82f9db13d85667366044acdfb02009d576c5a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 1 Aug 2025 20:03:35 +0300 Subject: [PATCH 0105/2711] misc: pci_endpoint_test: Fix array underflow in pci_endpoint_test_ioctl() Commit eefb83790a0d ("misc: pci_endpoint_test: Add doorbell test case") added NO_BAR (-1) to the pci_barno enum which, in practical terms, changes the enum from an unsigned int to a signed int. If the user passes a negative number in pci_endpoint_test_ioctl() then it results in an array underflow in pci_endpoint_test_bar(). Fixes: eefb83790a0d ("misc: pci_endpoint_test: Add doorbell test case") Signed-off-by: Dan Carpenter Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/aIzzZ4vc6ZrmM9rI@suswa --- drivers/misc/pci_endpoint_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 1c156a3f845e..f935175d8bf5 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -937,7 +937,7 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case PCITEST_BAR: bar = arg; - if (bar > BAR_5) + if (bar <= NO_BAR || bar > BAR_5) goto ret; if (is_am654_pci_dev(pdev) && bar == BAR_0) goto ret; From 152a09361bb2b0679277406be43d797d05e2104b Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 31 Jul 2025 14:49:01 +0200 Subject: [PATCH 0106/2711] Documentation: PCI: endpoint: Document BAR assignment It is now possible to assign BARs while creating a vNTB endpoint function. Update the documentation accordingly. Suggested-by: Bjorn Helgaas Signed-off-by: Jerome Brunet Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250731-vntb-doc-v1-1-95a0e0cd28d0@baylibre.com --- Documentation/PCI/endpoint/pci-vntb-howto.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/PCI/endpoint/pci-vntb-howto.rst b/Documentation/PCI/endpoint/pci-vntb-howto.rst index 70d3bc90893f..9a7a2f0a6849 100644 --- a/Documentation/PCI/endpoint/pci-vntb-howto.rst +++ b/Documentation/PCI/endpoint/pci-vntb-howto.rst @@ -90,8 +90,9 @@ of the function device and is populated with the following NTB specific attributes that can be configured by the user:: # ls functions/pci_epf_vntb/func1/pci_epf_vntb.0/ - db_count mw1 mw2 mw3 mw4 num_mws - spad_count + ctrl_bar db_count mw1_bar mw2_bar mw3_bar mw4_bar spad_count + db_bar mw1 mw2 mw3 mw4 num_mws vbus_number + vntb_vid vntb_pid A sample configuration for NTB function is given below:: @@ -100,6 +101,10 @@ A sample configuration for NTB function is given below:: # echo 1 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/num_mws # echo 0x100000 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/mw1 +By default, each construct is assigned a BAR, as needed and in order. +Should a specific BAR setup be required by the platform, BAR may be assigned +to each construct using the related ``XYZ_bar`` entry. + A sample configuration for virtual NTB driver for virtual PCI bus:: # echo 0x1957 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_vid From 8ba38a7a9a699905b84fa97578a8291010dec273 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 24 Jun 2025 17:59:18 +0300 Subject: [PATCH 0107/2711] x86/vsyscall: Do not require X86_PF_INSTR to emulate vsyscall emulate_vsyscall() expects to see X86_PF_INSTR in PFEC on a vsyscall page fault, but the CPU does not report X86_PF_INSTR if neither X86_FEATURE_NX nor X86_FEATURE_SMEP are enabled. X86_FEATURE_NX should be enabled on nearly all 64-bit CPUs, except for early P4 processors that did not support this feature. Instead of explicitly checking for X86_PF_INSTR, compare the fault address to RIP. On machines with X86_FEATURE_NX enabled, issue a warning if RIP is equal to fault address but X86_PF_INSTR is absent. [ dhansen: flesh out code comments ] Originally-by: Dave Hansen Reported-by: Andrew Cooper Signed-off-by: Kirill A. Shutemov Signed-off-by: Dave Hansen Reviewed-by: Andrew Cooper Link: https://lore.kernel.org/all/bd81a98b-f8d4-4304-ac55-d4151a1a77ab@intel.com Link: https://lore.kernel.org/all/20250624145918.2720487-1-kirill.shutemov%40linux.intel.com --- arch/x86/entry/vsyscall/vsyscall_64.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index c9103a6fa06e..6e6c0a740837 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -124,7 +124,12 @@ bool emulate_vsyscall(unsigned long error_code, if ((error_code & (X86_PF_WRITE | X86_PF_USER)) != X86_PF_USER) return false; - if (!(error_code & X86_PF_INSTR)) { + /* + * Assume that faults at regs->ip are because of an + * instruction fetch. Return early and avoid + * emulation for faults during data accesses: + */ + if (address != regs->ip) { /* Failed vsyscall read */ if (vsyscall_mode == EMULATE) return false; @@ -136,13 +141,19 @@ bool emulate_vsyscall(unsigned long error_code, return false; } + /* + * X86_PF_INSTR is only set when NX is supported. When + * available, use it to double-check that the emulation code + * is only being used for instruction fetches: + */ + if (cpu_feature_enabled(X86_FEATURE_NX)) + WARN_ON_ONCE(!(error_code & X86_PF_INSTR)); + /* * No point in checking CS -- the only way to get here is a user mode * trap to a high address, which means that we're in 64-bit user code. */ - WARN_ON_ONCE(address != regs->ip); - if (vsyscall_mode == NONE) { warn_bad_vsyscall(KERN_INFO, regs, "vsyscall attempted with vsyscall=none"); From faab3ae329a6efb96995aeb72a68a99f664fed38 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 23 Jun 2025 12:39:55 -0700 Subject: [PATCH 0108/2711] rcu: Document that rcu_barrier() hurries lazy callbacks This commit adds to the rcu_barrier() kerneldoc header stating that this function hurries lazy callbacks and that it does not normally result in additional RCU grace periods. Signed-off-by: Paul E. McKenney --- kernel/rcu/tree.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 8eff357b0436..1291e0761d70 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -3800,6 +3800,11 @@ static void rcu_barrier_handler(void *cpu_in) * to complete. For example, if there are no RCU callbacks queued anywhere * in the system, then rcu_barrier() is within its rights to return * immediately, without waiting for anything, much less an RCU grace period. + * In fact, rcu_barrier() will normally not result in any RCU grace periods + * beyond those that were already destined to be executed. + * + * In kernels built with CONFIG_RCU_LAZY=y, this function also hurries all + * pending lazy RCU callbacks. */ void rcu_barrier(void) { From 3da01ffe1aeaa0d427ab5235ba735226670a80d9 Mon Sep 17 00:00:00 2001 From: "Xin Li (Intel)" Date: Tue, 15 Jul 2025 23:33:20 -0700 Subject: [PATCH 0109/2711] x86/fred: Remove ENDBR64 from FRED entry points The FRED specification has been changed in v9.0 to state that there is no need for FRED event handlers to begin with ENDBR64, because in the presence of supervisor indirect branch tracking, FRED event delivery does not enter the WAIT_FOR_ENDBRANCH state. As a result, remove ENDBR64 from FRED entry points. Then add ANNOTATE_NOENDBR to indicate that FRED entry points will never be used for indirect calls to suppress an objtool warning. This change implies that any indirect CALL/JMP to FRED entry points causes #CP in the presence of supervisor indirect branch tracking. Credit goes to Jennifer Miller and other contributors from Arizona State University whose research shows that placing ENDBR at entry points has negative value thus led to this change. Note: This is obviously an incompatible change to the FRED architecture. But, it's OK because there no FRED systems out in the wild today. All production hardware and late pre-production hardware will follow the FRED v9 spec and be compatible with this approach. [ dhansen: add note to changelog about incompatibility ] Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code") Signed-off-by: Xin Li (Intel) Signed-off-by: Dave Hansen Reviewed-by: H. Peter Anvin (Intel) Reviewed-by: Andrew Cooper Link: https://lore.kernel.org/linux-hardening/Z60NwR4w%2F28Z7XUa@ubun/ Cc:stable@vger.kernel.org Link: https://lore.kernel.org/all/20250716063320.1337818-1-xin%40zytor.com --- arch/x86/entry/entry_64_fred.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/entry/entry_64_fred.S b/arch/x86/entry/entry_64_fred.S index 29c5c32c16c3..907bd233c6c1 100644 --- a/arch/x86/entry/entry_64_fred.S +++ b/arch/x86/entry/entry_64_fred.S @@ -16,7 +16,7 @@ .macro FRED_ENTER UNWIND_HINT_END_OF_STACK - ENDBR + ANNOTATE_NOENDBR PUSH_AND_CLEAR_REGS movq %rsp, %rdi /* %rdi -> pt_regs */ .endm From 5d03847175e81e86d4865456c15638faaf7c0634 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 12 Aug 2025 15:42:29 +0200 Subject: [PATCH 0110/2711] thunderbolt: Use is_pciehp instead of is_hotplug_bridge The thunderbolt driver sets up device link dependencies from hotplug ports to the Host Router (aka Native Host Interface, NHI). When resuming from system sleep, this allows the Host Router to re-establish tunnels to attached Thunderbolt devices before the hotplug ports resume. To identify the hotplug ports, the driver utilizes the is_hotplug_bridge flag which also encompasses ACPI slots handled by the ACPI hotplug driver. Thunderbolt hotplug ports are always Hot-Plug Capable PCIe ports, so it is more apt to identify them with the is_pciehp flag. Similarly, hotplug ports on older Thunderbolt controllers have broken MSI support and are quirked to use legacy INTx interrupts instead. The quirk identifies them with is_hotplug_bridge, even though all affected ports are also matched by is_pciehp. So use is_pciehp here as well. Signed-off-by: Lukas Wunner Acked-by: Bjorn Helgaas Signed-off-by: Mika Westerberg --- drivers/pci/quirks.c | 2 +- drivers/thunderbolt/tb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d97335a40193..17315a825674 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3829,7 +3829,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, 0xcf80, quirk_no_pm_reset); */ static void quirk_thunderbolt_hotplug_msi(struct pci_dev *pdev) { - if (pdev->is_hotplug_bridge && + if (pdev->is_pciehp && (pdev->device != PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C || pdev->revision <= 1)) pdev->no_msi = 1; diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index c14ab1fbeeaf..83a33fc1486a 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -3336,7 +3336,7 @@ static bool tb_apple_add_links(struct tb_nhi *nhi) if (!pci_is_pcie(pdev)) continue; if (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM || - !pdev->is_hotplug_bridge) + !pdev->is_pciehp) continue; link = device_link_add(&pdev->dev, &nhi->pdev->dev, From 3fc36ae6abd263a5cbf93b2f5539eccc1fc753f7 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Fri, 25 Jul 2025 15:40:17 +0200 Subject: [PATCH 0111/2711] tty: serial: ip22zilog: Use platform device for probing After commit 84a9582fd203 ("serial: core: Start managing serial controllers to enable runtime PM") serial drivers need to provide a device in struct uart_port.dev otherwise an oops happens. To fix this issue for ip22zilog driver switch driver to a platform driver and setup the serial device in sgi-ip22 code. Signed-off-by: Thomas Bogendoerfer Link: https://lore.kernel.org/r/20250725134018.136113-1-tsbogend@alpha.franken.de Signed-off-by: Greg Kroah-Hartman --- arch/mips/sgi-ip22/ip22-platform.c | 32 +++ drivers/tty/serial/ip22zilog.c | 360 ++++++++++++----------------- 2 files changed, 179 insertions(+), 213 deletions(-) diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c index 0b2002e02a47..3a53690b4b33 100644 --- a/arch/mips/sgi-ip22/ip22-platform.c +++ b/arch/mips/sgi-ip22/ip22-platform.c @@ -221,3 +221,35 @@ static int __init sgi_ds1286_devinit(void) } device_initcall(sgi_ds1286_devinit); + +#define SGI_ZILOG_BASE (HPC3_CHIP0_BASE + \ + offsetof(struct hpc3_regs, pbus_extregs[6]) + \ + offsetof(struct sgioc_regs, uart)) + +static struct resource sgi_zilog_resources[] = { + { + .start = SGI_ZILOG_BASE, + .end = SGI_ZILOG_BASE + 15, + .flags = IORESOURCE_MEM + }, + { + .start = SGI_SERIAL_IRQ, + .end = SGI_SERIAL_IRQ, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device zilog_device = { + .name = "ip22zilog", + .id = 0, + .num_resources = ARRAY_SIZE(sgi_zilog_resources), + .resource = sgi_zilog_resources, +}; + + +static int __init sgi_zilog_devinit(void) +{ + return platform_device_register(&zilog_device); +} + +device_initcall(sgi_zilog_devinit); diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index c2cae50f06f3..6e19c6713849 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -50,8 +51,9 @@ #define ZSDELAY_LONG() udelay(20) #define ZS_WSYNC(channel) do { } while (0) -#define NUM_IP22ZILOG 1 -#define NUM_CHANNELS (NUM_IP22ZILOG * 2) +#define NUM_CHANNELS 2 +#define CHANNEL_B 0 +#define CHANNEL_A 1 #define ZS_CLOCK 3672000 /* Zilog input clock rate. */ #define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */ @@ -62,9 +64,6 @@ struct uart_ip22zilog_port { struct uart_port port; - /* IRQ servicing chain. */ - struct uart_ip22zilog_port *next; - /* Current values of Zilog write registers. */ unsigned char curregs[NUM_ZSREGS]; @@ -72,7 +71,6 @@ struct uart_ip22zilog_port { #define IP22ZILOG_FLAG_IS_CONS 0x00000004 #define IP22ZILOG_FLAG_IS_KGDB 0x00000008 #define IP22ZILOG_FLAG_MODEM_STATUS 0x00000010 -#define IP22ZILOG_FLAG_IS_CHANNEL_A 0x00000020 #define IP22ZILOG_FLAG_REGS_HELD 0x00000040 #define IP22ZILOG_FLAG_TX_STOPPED 0x00000080 #define IP22ZILOG_FLAG_TX_ACTIVE 0x00000100 @@ -84,6 +82,8 @@ struct uart_ip22zilog_port { unsigned char prev_status; }; +static struct uart_ip22zilog_port ip22zilog_port_table[NUM_CHANNELS]; + #define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel *)((PORT)->membase)) #define UART_ZILOG(PORT) ((struct uart_ip22zilog_port *)(PORT)) #define IP22ZILOG_GET_CURR_REG(PORT, REGNUM) \ @@ -93,7 +93,6 @@ struct uart_ip22zilog_port { #define ZS_IS_CONS(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CONS) #define ZS_IS_KGDB(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_KGDB) #define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS) -#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A) #define ZS_REGS_HELD(UP) ((UP)->flags & IP22ZILOG_FLAG_REGS_HELD) #define ZS_TX_STOPPED(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED) #define ZS_TX_ACTIVE(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE) @@ -423,60 +422,57 @@ ack_tx_int: static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) { - struct uart_ip22zilog_port *up = dev_id; + struct uart_ip22zilog_port *up; + struct zilog_channel *channel; + unsigned char r3; + bool push = false; - while (up) { - struct zilog_channel *channel - = ZILOG_CHANNEL_FROM_PORT(&up->port); - unsigned char r3; - bool push = false; + up = &ip22zilog_port_table[CHANNEL_A]; + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - uart_port_lock(&up->port); - r3 = read_zsreg(channel, R3); + uart_port_lock(&up->port); + r3 = read_zsreg(channel, R3); - /* Channel A */ - if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { - writeb(RES_H_IUS, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); + /* Channel A */ + if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { + writeb(RES_H_IUS, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); - if (r3 & CHARxIP) - push = ip22zilog_receive_chars(up, channel); - if (r3 & CHAEXT) - ip22zilog_status_handle(up, channel); - if (r3 & CHATxIP) - ip22zilog_transmit_chars(up, channel); - } - uart_port_unlock(&up->port); - - if (push) - tty_flip_buffer_push(&up->port.state->port); - - /* Channel B */ - up = up->next; - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - push = false; - - uart_port_lock(&up->port); - if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { - writeb(RES_H_IUS, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - - if (r3 & CHBRxIP) - push = ip22zilog_receive_chars(up, channel); - if (r3 & CHBEXT) - ip22zilog_status_handle(up, channel); - if (r3 & CHBTxIP) - ip22zilog_transmit_chars(up, channel); - } - uart_port_unlock(&up->port); - - if (push) - tty_flip_buffer_push(&up->port.state->port); - - up = up->next; + if (r3 & CHARxIP) + push = ip22zilog_receive_chars(up, channel); + if (r3 & CHAEXT) + ip22zilog_status_handle(up, channel); + if (r3 & CHATxIP) + ip22zilog_transmit_chars(up, channel); } + uart_port_unlock(&up->port); + + if (push) + tty_flip_buffer_push(&up->port.state->port); + + /* Channel B */ + up = &ip22zilog_port_table[CHANNEL_B]; + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + push = false; + + uart_port_lock(&up->port); + if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { + writeb(RES_H_IUS, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + + if (r3 & CHBRxIP) + push = ip22zilog_receive_chars(up, channel); + if (r3 & CHBEXT) + ip22zilog_status_handle(up, channel); + if (r3 & CHBTxIP) + ip22zilog_transmit_chars(up, channel); + } + uart_port_unlock(&up->port); + + if (push) + tty_flip_buffer_push(&up->port.state->port); return IRQ_HANDLED; } @@ -692,16 +688,16 @@ static void __ip22zilog_reset(struct uart_ip22zilog_port *up) udelay(100); } - if (!ZS_IS_CHANNEL_A(up)) { - up++; - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - } + up = &ip22zilog_port_table[CHANNEL_A]; + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + write_zsreg(channel, R9, FHWRES); ZSDELAY_LONG(); (void) read_zsreg(channel, R0); up->flags |= IP22ZILOG_FLAG_RESET_DONE; - up->next->flags |= IP22ZILOG_FLAG_RESET_DONE; + up = &ip22zilog_port_table[CHANNEL_B]; + up->flags |= IP22ZILOG_FLAG_RESET_DONE; } static void __ip22zilog_startup(struct uart_ip22zilog_port *up) @@ -942,47 +938,6 @@ static const struct uart_ops ip22zilog_pops = { .verify_port = ip22zilog_verify_port, }; -static struct uart_ip22zilog_port *ip22zilog_port_table; -static struct zilog_layout **ip22zilog_chip_regs; - -static struct uart_ip22zilog_port *ip22zilog_irq_chain; -static int zilog_irq = -1; - -static void * __init alloc_one_table(unsigned long size) -{ - return kzalloc(size, GFP_KERNEL); -} - -static void __init ip22zilog_alloc_tables(void) -{ - ip22zilog_port_table = (struct uart_ip22zilog_port *) - alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port)); - ip22zilog_chip_regs = (struct zilog_layout **) - alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *)); - - if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) { - panic("IP22-Zilog: Cannot allocate IP22-Zilog tables."); - } -} - -/* Get the address of the registers for IP22-Zilog instance CHIP. */ -static struct zilog_layout * __init get_zs(int chip) -{ - unsigned long base; - - if (chip < 0 || chip >= NUM_IP22ZILOG) { - panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip); - } - - /* Not probe-able, hard code it. */ - base = (unsigned long) &sgioc->uart; - - zilog_irq = SGI_SERIAL_IRQ; - request_mem_region(base, 8, "IP22-Zilog"); - - return (struct zilog_layout *) base; -} - #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ #ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE @@ -1070,144 +1025,123 @@ static struct uart_driver ip22zilog_reg = { #endif }; -static void __init ip22zilog_prepare(void) +static void __init ip22zilog_prepare(struct uart_ip22zilog_port *up) { unsigned char sysrq_on = IS_ENABLED(CONFIG_SERIAL_IP22_ZILOG_CONSOLE); - struct uart_ip22zilog_port *up; - struct zilog_layout *rp; - int channel, chip; + int brg; - /* - * Temporary fix. - */ - for (channel = 0; channel < NUM_CHANNELS; channel++) - spin_lock_init(&ip22zilog_port_table[channel].port.lock); + spin_lock_init(&up->port.lock); - ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1]; - up = &ip22zilog_port_table[0]; - for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--) - up[channel].next = &up[channel - 1]; - up[channel].next = NULL; + up->port.iotype = UPIO_MEM; + up->port.uartclk = ZS_CLOCK; + up->port.fifosize = 1; + up->port.has_sysrq = sysrq_on; + up->port.ops = &ip22zilog_pops; + up->port.type = PORT_IP22ZILOG; - for (chip = 0; chip < NUM_IP22ZILOG; chip++) { - if (!ip22zilog_chip_regs[chip]) { - ip22zilog_chip_regs[chip] = rp = get_zs(chip); - - up[(chip * 2) + 0].port.membase = (char *) &rp->channelB; - up[(chip * 2) + 1].port.membase = (char *) &rp->channelA; - - /* In theory mapbase is the physical address ... */ - up[(chip * 2) + 0].port.mapbase = - (unsigned long) ioremap((unsigned long) &rp->channelB, 8); - up[(chip * 2) + 1].port.mapbase = - (unsigned long) ioremap((unsigned long) &rp->channelA, 8); - } - - /* Channel A */ - up[(chip * 2) + 0].port.iotype = UPIO_MEM; - up[(chip * 2) + 0].port.irq = zilog_irq; - up[(chip * 2) + 0].port.uartclk = ZS_CLOCK; - up[(chip * 2) + 0].port.fifosize = 1; - up[(chip * 2) + 0].port.has_sysrq = sysrq_on; - up[(chip * 2) + 0].port.ops = &ip22zilog_pops; - up[(chip * 2) + 0].port.type = PORT_IP22ZILOG; - up[(chip * 2) + 0].port.flags = 0; - up[(chip * 2) + 0].port.line = (chip * 2) + 0; - up[(chip * 2) + 0].flags = 0; - - /* Channel B */ - up[(chip * 2) + 1].port.iotype = UPIO_MEM; - up[(chip * 2) + 1].port.irq = zilog_irq; - up[(chip * 2) + 1].port.uartclk = ZS_CLOCK; - up[(chip * 2) + 1].port.fifosize = 1; - up[(chip * 2) + 1].port.has_sysrq = sysrq_on; - up[(chip * 2) + 1].port.ops = &ip22zilog_pops; - up[(chip * 2) + 1].port.type = PORT_IP22ZILOG; - up[(chip * 2) + 1].port.line = (chip * 2) + 1; - up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A; - } - - for (channel = 0; channel < NUM_CHANNELS; channel++) { - struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel]; - int brg; - - /* Normal serial TTY. */ - up->parity_mask = 0xff; - up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; - up->curregs[R4] = PAR_EVEN | X16CLK | SB1; - up->curregs[R3] = RxENAB | Rx8; - up->curregs[R5] = TxENAB | Tx8; - up->curregs[R9] = NV | MIE; - up->curregs[R10] = NRZ; - up->curregs[R11] = TCBR | RCBR; - brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR); - up->curregs[R12] = (brg & 0xff); - up->curregs[R13] = (brg >> 8) & 0xff; - up->curregs[R14] = BRENAB; - } + /* Normal serial TTY. */ + up->parity_mask = 0xff; + up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + up->curregs[R4] = PAR_EVEN | X16CLK | SB1; + up->curregs[R3] = RxENAB | Rx8; + up->curregs[R5] = TxENAB | Tx8; + up->curregs[R9] = NV | MIE; + up->curregs[R10] = NRZ; + up->curregs[R11] = TCBR | RCBR; + brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR); + up->curregs[R12] = (brg & 0xff); + up->curregs[R13] = (brg >> 8) & 0xff; + up->curregs[R14] = BRENAB; } -static int __init ip22zilog_ports_init(void) +static int ip22zilog_probe(struct platform_device *pdev) { - int ret; + struct uart_ip22zilog_port *up; + char __iomem *membase; + struct resource *res; + int irq; + int i; - printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG); + up = &ip22zilog_port_table[CHANNEL_B]; + if (up->port.dev) + return -ENOSPC; - ip22zilog_prepare(); + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; - if (request_irq(zilog_irq, ip22zilog_interrupt, 0, - "IP22-Zilog", ip22zilog_irq_chain)) { + membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(membase)) + return PTR_ERR(membase); + + ip22zilog_prepare(up); + + up->port.mapbase = res->start + offsetof(struct zilog_layout, channelB); + up->port.membase = membase + offsetof(struct zilog_layout, channelB); + up->port.line = 0; + up->port.dev = &pdev->dev; + up->port.irq = irq; + + up = &ip22zilog_port_table[CHANNEL_A]; + ip22zilog_prepare(up); + + up->port.mapbase = res->start + offsetof(struct zilog_layout, channelA); + up->port.membase = membase + offsetof(struct zilog_layout, channelA); + up->port.line = 1; + up->port.dev = &pdev->dev; + up->port.irq = irq; + + if (request_irq(irq, ip22zilog_interrupt, 0, + "IP22-Zilog", NULL)) { panic("IP22-Zilog: Unable to register zs interrupt handler.\n"); } - ret = uart_register_driver(&ip22zilog_reg); - if (ret == 0) { - int i; - - for (i = 0; i < NUM_CHANNELS; i++) { - struct uart_ip22zilog_port *up = &ip22zilog_port_table[i]; - - uart_add_one_port(&ip22zilog_reg, &up->port); - } - } - - return ret; -} - -static int __init ip22zilog_init(void) -{ - /* IP22 Zilog setup is hard coded, no probing to do. */ - ip22zilog_alloc_tables(); - ip22zilog_ports_init(); + for (i = 0; i < NUM_CHANNELS; i++) + uart_add_one_port(&ip22zilog_reg, + &ip22zilog_port_table[i].port); return 0; } -static void __exit ip22zilog_exit(void) +static void ip22zilog_remove(struct platform_device *pdev) { int i; - struct uart_ip22zilog_port *up; for (i = 0; i < NUM_CHANNELS; i++) { - up = &ip22zilog_port_table[i]; - - uart_remove_one_port(&ip22zilog_reg, &up->port); + uart_remove_one_port(&ip22zilog_reg, + &ip22zilog_port_table[i].port); + ip22zilog_port_table[i].port.dev = NULL; } +} - /* Free IO mem */ - up = &ip22zilog_port_table[0]; - for (i = 0; i < NUM_IP22ZILOG; i++) { - if (up[(i * 2) + 0].port.mapbase) { - iounmap((void*)up[(i * 2) + 0].port.mapbase); - up[(i * 2) + 0].port.mapbase = 0; - } - if (up[(i * 2) + 1].port.mapbase) { - iounmap((void*)up[(i * 2) + 1].port.mapbase); - up[(i * 2) + 1].port.mapbase = 0; - } +static struct platform_driver ip22zilog_driver = { + .probe = ip22zilog_probe, + .remove = ip22zilog_remove, + .driver = { + .name = "ip22zilog" } +}; +static int __init ip22zilog_init(void) +{ + int ret; + + ret = uart_register_driver(&ip22zilog_reg); + if (ret) + return ret; + + ret = platform_driver_register(&ip22zilog_driver); + if (ret) + uart_unregister_driver(&ip22zilog_reg); + + return ret; + +} + +static void __exit ip22zilog_exit(void) +{ uart_unregister_driver(&ip22zilog_reg); + platform_driver_unregister(&ip22zilog_driver); } module_init(ip22zilog_init); From 672a37ba8af1f2ebcedeb94aea2cdd047f805f30 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 7 Aug 2025 18:54:37 +0300 Subject: [PATCH 0112/2711] serial: max310x: Add error checking in probe() Check if devm_i2c_new_dummy_device() fails. Fixes: 2e1f2d9a9bdb ("serial: max310x: implement I2C support") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/aJTMPZiKqeXSE-KM@stanley.mountain Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ce260e9949c3..d9a0100b92d2 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1644,6 +1644,8 @@ static int max310x_i2c_probe(struct i2c_client *client) port_client = devm_i2c_new_dummy_device(&client->dev, client->adapter, port_addr); + if (IS_ERR(port_client)) + return PTR_ERR(port_client); regcfg_i2c.name = max310x_regmap_name(i); regmaps[i] = devm_regmap_init_i2c(port_client, ®cfg_i2c); From d9b7679611d320db4f4436f0281a7797f2e06e15 Mon Sep 17 00:00:00 2001 From: Abinash Singh Date: Thu, 7 Aug 2025 03:21:33 +0530 Subject: [PATCH 0113/2711] serial: 8250_platform: Reduce stack usage in serial8250_probe_acpi() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function serial8250_probe_acpi() in 8250_platform.c triggered a frame size warning: drivers/tty/serial/8250/8250_platform.c: In function ‘serial8250_probe_acpi’: drivers/tty/serial/8250/8250_platform.c:152:1: warning: the frame size of 1160 bytes is larger than 1024 bytes [-Wframe-larger-than=] This patch reduces the stack usage by dynamically allocating the `uart` structure using kzalloc(), rather than placing it on the stack. This eliminates the overflow warning and improves kernel robustness. Signed-off-by: Abinash Singh Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20250806215134.4921-2-abinashsinghlalotra@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_platform.c | 26 ++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c index c0343bfb8064..9938aeb917d8 100644 --- a/drivers/tty/serial/8250/8250_platform.c +++ b/drivers/tty/serial/8250/8250_platform.c @@ -10,6 +10,7 @@ */ #include #include +#include #include #include #include @@ -110,41 +111,44 @@ void __init serial8250_isa_init_ports(void) static int serial8250_probe_acpi(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct uart_8250_port uart = { }; struct resource *regs; int ret, line; + struct uart_8250_port *uart __free(kfree) = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) + return -ENOMEM; + regs = platform_get_mem_or_io(pdev, 0); if (!regs) return dev_err_probe(dev, -EINVAL, "no registers defined\n"); switch (resource_type(regs)) { case IORESOURCE_IO: - uart.port.iobase = regs->start; + uart->port.iobase = regs->start; break; case IORESOURCE_MEM: - uart.port.mapbase = regs->start; - uart.port.mapsize = resource_size(regs); - uart.port.flags = UPF_IOREMAP; + uart->port.mapbase = regs->start; + uart->port.mapsize = resource_size(regs); + uart->port.flags = UPF_IOREMAP; break; default: return -EINVAL; } /* default clock frequency */ - uart.port.uartclk = 1843200; - uart.port.type = PORT_16550A; - uart.port.dev = &pdev->dev; - uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + uart->port.uartclk = 1843200; + uart->port.type = PORT_16550A; + uart->port.dev = &pdev->dev; + uart->port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; - ret = uart_read_and_validate_port_properties(&uart.port); + ret = uart_read_and_validate_port_properties(&uart->port); /* no interrupt -> fall back to polling */ if (ret == -ENXIO) ret = 0; if (ret) return ret; - line = serial8250_register_8250_port(&uart); + line = serial8250_register_8250_port(uart); if (line < 0) return line; From bd673d2b714106fdac67e65f7d399a66893d0936 Mon Sep 17 00:00:00 2001 From: Abinash Singh Date: Thu, 7 Aug 2025 03:21:34 +0530 Subject: [PATCH 0114/2711] serial: 8250_platform: Reduce stack usage in serial8250_probe_platform() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function serial8250_probe_platform() in 8250_platform.c triggered a frame size warning: drivers/tty/serial/8250/8250_platform.c: In function ‘serial8250_probe_platform.isra’: drivers/tty/serial/8250/8250_platform.c:201:1: warning: the frame size of 1184 bytes is larger than 1024 bytes [-Wframe-larger-than=] This patch reduces the stack usage by dynamically allocating the `uart` structure using kzalloc(), rather than placing it on the stack. This eliminates the overflow warning and improves kernel robustness. Signed-off-by: Abinash Singh Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20250806215134.4921-3-abinashsinghlalotra@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_platform.c | 61 +++++++++++++------------ 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c index 9938aeb917d8..b27981340e76 100644 --- a/drivers/tty/serial/8250/8250_platform.c +++ b/drivers/tty/serial/8250/8250_platform.c @@ -157,43 +157,44 @@ static int serial8250_probe_acpi(struct platform_device *pdev) static int serial8250_probe_platform(struct platform_device *dev, struct plat_serial8250_port *p) { - struct uart_8250_port uart; int ret, i, irqflag = 0; - memset(&uart, 0, sizeof(uart)); + struct uart_8250_port *uart __free(kfree) = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) + return -ENOMEM; if (share_irqs) irqflag = IRQF_SHARED; for (i = 0; p && p->flags != 0; p++, i++) { - uart.port.iobase = p->iobase; - uart.port.membase = p->membase; - uart.port.irq = p->irq; - uart.port.irqflags = p->irqflags; - uart.port.uartclk = p->uartclk; - uart.port.regshift = p->regshift; - uart.port.iotype = p->iotype; - uart.port.flags = p->flags; - uart.port.mapbase = p->mapbase; - uart.port.mapsize = p->mapsize; - uart.port.hub6 = p->hub6; - uart.port.has_sysrq = p->has_sysrq; - uart.port.private_data = p->private_data; - uart.port.type = p->type; - uart.bugs = p->bugs; - uart.port.serial_in = p->serial_in; - uart.port.serial_out = p->serial_out; - uart.dl_read = p->dl_read; - uart.dl_write = p->dl_write; - uart.port.handle_irq = p->handle_irq; - uart.port.handle_break = p->handle_break; - uart.port.set_termios = p->set_termios; - uart.port.set_ldisc = p->set_ldisc; - uart.port.get_mctrl = p->get_mctrl; - uart.port.pm = p->pm; - uart.port.dev = &dev->dev; - uart.port.irqflags |= irqflag; - ret = serial8250_register_8250_port(&uart); + uart->port.iobase = p->iobase; + uart->port.membase = p->membase; + uart->port.irq = p->irq; + uart->port.irqflags = p->irqflags; + uart->port.uartclk = p->uartclk; + uart->port.regshift = p->regshift; + uart->port.iotype = p->iotype; + uart->port.flags = p->flags; + uart->port.mapbase = p->mapbase; + uart->port.mapsize = p->mapsize; + uart->port.hub6 = p->hub6; + uart->port.has_sysrq = p->has_sysrq; + uart->port.private_data = p->private_data; + uart->port.type = p->type; + uart->bugs = p->bugs; + uart->port.serial_in = p->serial_in; + uart->port.serial_out = p->serial_out; + uart->dl_read = p->dl_read; + uart->dl_write = p->dl_write; + uart->port.handle_irq = p->handle_irq; + uart->port.handle_break = p->handle_break; + uart->port.set_termios = p->set_termios; + uart->port.set_ldisc = p->set_ldisc; + uart->port.get_mctrl = p->get_mctrl; + uart->port.pm = p->pm; + uart->port.dev = &dev->dev; + uart->port.irqflags |= irqflag; + ret = serial8250_register_8250_port(uart); if (ret < 0) { dev_err(&dev->dev, "unable to register port at index %d " "(IO%lx MEM%llx IRQ%d): %d\n", i, From 8672b18cde548748ac04a3aa247369ac2d4c2985 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sun, 10 Aug 2025 18:14:25 -0400 Subject: [PATCH 0115/2711] tty: serial: mvebu-uart: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch appended to the "under-the-cut" portion of the patch. Signed-off-by: Brian Masney Link: https://lore.kernel.org/r/20250810-tty-round-rate-v1-1-849009f3bdfd@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mvebu-uart.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 5de57b77abdb..8e52be2b34ea 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -1264,14 +1264,16 @@ static unsigned long mvebu_uart_clock_recalc_rate(struct clk_hw *hw, return parent_rate / uart_clock_base->div; } -static long mvebu_uart_clock_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int mvebu_uart_clock_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct mvebu_uart_clock *uart_clock = to_uart_clock(hw); struct mvebu_uart_clock_base *uart_clock_base = to_uart_clock_base(uart_clock); - return *parent_rate / uart_clock_base->div; + req->rate = req->best_parent_rate / uart_clock_base->div; + + return 0; } static int mvebu_uart_clock_set_rate(struct clk_hw *hw, unsigned long rate, @@ -1293,7 +1295,7 @@ static const struct clk_ops mvebu_uart_clock_ops = { .is_enabled = mvebu_uart_clock_is_enabled, .save_context = mvebu_uart_clock_save_context, .restore_context = mvebu_uart_clock_restore_context, - .round_rate = mvebu_uart_clock_round_rate, + .determine_rate = mvebu_uart_clock_determine_rate, .set_rate = mvebu_uart_clock_set_rate, .recalc_rate = mvebu_uart_clock_recalc_rate, }; From c3e7966c60745f87a0b73672a85c920099f90a7e Mon Sep 17 00:00:00 2001 From: Zong Jiang Date: Tue, 12 Aug 2025 13:48:18 +0800 Subject: [PATCH 0116/2711] serial: qcom-geni: Dynamically allocate UART ports Replace the static allocation of UART ports with dynamic allocation using devm_kzalloc. This change removes the fixed-size array and instead allocates each UART port structure on demand during probe, improving memory efficiency and scalability. Signed-off-by: Zong Jiang Link: https://lore.kernel.org/r/20250812054819.3748649-2-quic_zongjian@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 44 ++++++++------------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 32ec632fd080..080c18ddbdde 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -164,33 +164,6 @@ static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport) return container_of(uport, struct qcom_geni_serial_port, uport); } -static struct qcom_geni_serial_port qcom_geni_uart_ports[GENI_UART_PORTS] = { - [0] = { - .uport = { - .iotype = UPIO_MEM, - .ops = &qcom_geni_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - }, - [1] = { - .uport = { - .iotype = UPIO_MEM, - .ops = &qcom_geni_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - }, - [2] = { - .uport = { - .iotype = UPIO_MEM, - .ops = &qcom_geni_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - }, -}; - static struct qcom_geni_serial_port qcom_geni_console_port = { .uport = { .iotype = UPIO_MEM, @@ -285,7 +258,7 @@ static const char *qcom_geni_serial_get_type(struct uart_port *uport) return "MSM"; } -static struct qcom_geni_serial_port *get_port_from_line(int line, bool console) +static struct qcom_geni_serial_port *get_port_from_line(int line, bool console, struct device *dev) { struct qcom_geni_serial_port *port; int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS; @@ -306,7 +279,14 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console) if (line < 0) return ERR_PTR(-ENXIO); - port = &qcom_geni_uart_ports[line]; + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return ERR_PTR(-ENOMEM); + + port->uport.iotype = UPIO_MEM; + port->uport.ops = &qcom_geni_uart_pops; + port->uport.flags = UPF_BOOT_AUTOCONF; + port->uport.line = line; } return port; } @@ -554,7 +534,7 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS); - port = get_port_from_line(co->index, true); + port = get_port_from_line(co->index, true, NULL); if (IS_ERR(port)) return; @@ -1511,7 +1491,7 @@ static int qcom_geni_console_setup(struct console *co, char *options) if (co->index >= GENI_UART_CONS_PORTS || co->index < 0) return -ENXIO; - port = get_port_from_line(co->index, true); + port = get_port_from_line(co->index, true, NULL); if (IS_ERR(port)) { pr_err("Invalid line %d\n", co->index); return PTR_ERR(port); @@ -1866,7 +1846,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) line = of_alias_get_id(pdev->dev.of_node, "hsuart"); } - port = get_port_from_line(line, data->console); + port = get_port_from_line(line, data->console, &pdev->dev); if (IS_ERR(port)) { dev_err(&pdev->dev, "Invalid line %d\n", line); return PTR_ERR(port); From 9391ab1ed9b3fe0d1af7d7858d9bf42f476628c8 Mon Sep 17 00:00:00 2001 From: Zong Jiang Date: Tue, 12 Aug 2025 13:48:19 +0800 Subject: [PATCH 0117/2711] serial: qcom-geni: Make UART port count configurable via Kconfig Replace the hardcoded GENI_UART_PORTS macro with a new Kconfig option SERIAL_QCOM_GENI_UART_PORTS to allow platforms to configure the maximum number of UART ports supported by the driver at build time. This improves flexibility for platforms that require more than the previously fixed number of UART ports, and avoids unnecessary allocation for unused ports. Signed-off-by: Zong Jiang Link: https://lore.kernel.org/r/20250812054819.3748649-3-quic_zongjian@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 8 ++++++++ drivers/tty/serial/qcom_geni_serial.c | 5 ++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 44427415a80d..e661f5951f55 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -928,6 +928,14 @@ config SERIAL_QCOM_GENI_CONSOLE Serial console driver for Qualcomm Technologies Inc's GENI based QUP hardware. +config SERIAL_QCOM_GENI_UART_PORTS + int "Maximum number of GENI UART ports" + depends on SERIAL_QCOM_GENI + default "8" + help + Set this to the maximum number of serial ports you want the driver + to support. + config SERIAL_VT8500 bool "VIA VT8500 on-chip serial port support" depends on ARCH_VT8500 || COMPILE_TEST diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 080c18ddbdde..9c7b1cea7cfe 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -77,7 +77,6 @@ #define STALE_TIMEOUT 16 #define DEFAULT_BITS_PER_CHAR 10 #define GENI_UART_CONS_PORTS 1 -#define GENI_UART_PORTS 3 #define DEF_FIFO_DEPTH_WORDS 16 #define DEF_TX_WM 2 #define DEF_FIFO_WIDTH_BITS 32 @@ -261,7 +260,7 @@ static const char *qcom_geni_serial_get_type(struct uart_port *uport) static struct qcom_geni_serial_port *get_port_from_line(int line, bool console, struct device *dev) { struct qcom_geni_serial_port *port; - int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS; + int nr_ports = console ? GENI_UART_CONS_PORTS : CONFIG_SERIAL_QCOM_GENI_UART_PORTS; if (console) { if (line < 0 || line >= nr_ports) @@ -1652,7 +1651,7 @@ static struct uart_driver qcom_geni_uart_driver = { .owner = THIS_MODULE, .driver_name = "qcom_geni_uart", .dev_name = "ttyHS", - .nr = GENI_UART_PORTS, + .nr = CONFIG_SERIAL_QCOM_GENI_UART_PORTS, }; static int geni_serial_resources_on(struct uart_port *uport) From 27fce9e8c6f031b526bf471e1076abca31473464 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 14 Aug 2025 17:21:20 +0200 Subject: [PATCH 0118/2711] PCI: endpoint: Drop superfluous pci_epc_features initialization struct pci_epc_features has static storage duration, so all struct members are zero initialized implicitly. Thus, remove explicit zero initialization for features that are *not* supported so we don't have to touch existing drivers as new features are added. Signed-off-by: Niklas Cassel [bhelgaas: squash together, expand commit log rationale] Signed-off-by: Bjorn Helgaas Reviewed-by: Geert Uytterhoeven #rcar-ep, rcar-gen4 Link: https://patch.msgid.link/20250814152119.1562063-16-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-17-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-18-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-19-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-20-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-21-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-22-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-23-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-24-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-25-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-26-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-27-cassel@kernel.org Link: https://patch.msgid.link/20250814152119.1562063-28-cassel@kernel.org --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 2 -- drivers/pci/controller/dwc/pci-dra7xx.c | 1 - drivers/pci/controller/dwc/pci-imx6.c | 4 ---- drivers/pci/controller/dwc/pci-keystone.c | 1 - drivers/pci/controller/dwc/pcie-artpec6.c | 2 -- drivers/pci/controller/dwc/pcie-designware-plat.c | 1 - drivers/pci/controller/dwc/pcie-dw-rockchip.c | 2 -- drivers/pci/controller/dwc/pcie-keembay.c | 1 - drivers/pci/controller/dwc/pcie-qcom-ep.c | 1 - drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 -- drivers/pci/controller/dwc/pcie-tegra194.c | 2 -- drivers/pci/controller/pcie-rcar-ep.c | 2 -- drivers/pci/controller/pcie-rockchip-ep.c | 1 - 13 files changed, 22 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 77c5a19b2ab1..f3565164f142 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -608,14 +608,12 @@ static int cdns_pcie_ep_start(struct pci_epc *epc) } static const struct pci_epc_features cdns_pcie_epc_vf_features = { - .linkup_notifier = false, .msi_capable = true, .msix_capable = true, .align = 65536, }; static const struct pci_epc_features cdns_pcie_epc_features = { - .linkup_notifier = false, .msi_capable = true, .msix_capable = true, .align = 256, diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index f97f5266d196..01cfd9aeb0b8 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -426,7 +426,6 @@ static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, static const struct pci_epc_features dra7xx_pcie_epc_features = { .linkup_notifier = true, .msi_capable = true, - .msix_capable = false, }; static const struct pci_epc_features* diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 80e48746bbaf..7ee21fac81a6 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1387,9 +1387,7 @@ static int imx_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } static const struct pci_epc_features imx8m_pcie_epc_features = { - .linkup_notifier = false, .msi_capable = true, - .msix_capable = false, .bar[BAR_1] = { .type = BAR_RESERVED, }, .bar[BAR_3] = { .type = BAR_RESERVED, }, .bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = SZ_256, }, @@ -1398,9 +1396,7 @@ static const struct pci_epc_features imx8m_pcie_epc_features = { }; static const struct pci_epc_features imx8q_pcie_epc_features = { - .linkup_notifier = false, .msi_capable = true, - .msix_capable = false, .bar[BAR_1] = { .type = BAR_RESERVED, }, .bar[BAR_3] = { .type = BAR_RESERVED, }, .bar[BAR_5] = { .type = BAR_RESERVED, }, diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 2b2632e513b5..7d7aede54ed3 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -960,7 +960,6 @@ static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } static const struct pci_epc_features ks_pcie_am654_epc_features = { - .linkup_notifier = false, .msi_capable = true, .msix_capable = true, .bar[BAR_0] = { .type = BAR_RESERVED, }, diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 234c8cbcae3a..f4a136ee2daf 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -370,9 +370,7 @@ static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } static const struct pci_epc_features artpec6_pcie_epc_features = { - .linkup_notifier = false, .msi_capable = true, - .msix_capable = false, }; static const struct pci_epc_features * diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 771b9d9be077..12f41886c65d 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -61,7 +61,6 @@ static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } static const struct pci_epc_features dw_plat_pcie_epc_features = { - .linkup_notifier = false, .msi_capable = true, .msix_capable = true, }; diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index b5f5eee5a50e..c045353fa493 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -325,7 +325,6 @@ static const struct pci_epc_features rockchip_pcie_epc_features_rk3568 = { .linkup_notifier = true, .msi_capable = true, .msix_capable = true, - .intx_capable = false, .align = SZ_64K, .bar[BAR_0] = { .type = BAR_RESIZABLE, }, .bar[BAR_1] = { .type = BAR_RESIZABLE, }, @@ -346,7 +345,6 @@ static const struct pci_epc_features rockchip_pcie_epc_features_rk3588 = { .linkup_notifier = true, .msi_capable = true, .msix_capable = true, - .intx_capable = false, .align = SZ_64K, .bar[BAR_0] = { .type = BAR_RESIZABLE, }, .bar[BAR_1] = { .type = BAR_RESIZABLE, }, diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c index 67dd3337b447..60e74ac782af 100644 --- a/drivers/pci/controller/dwc/pcie-keembay.c +++ b/drivers/pci/controller/dwc/pcie-keembay.c @@ -309,7 +309,6 @@ static int keembay_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } static const struct pci_epc_features keembay_pcie_epc_features = { - .linkup_notifier = false, .msi_capable = true, .msix_capable = true, .bar[BAR_0] = { .only_64bit = true, }, diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index bf7c6ac0f3e3..60afb4d0134c 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -831,7 +831,6 @@ static void qcom_pcie_ep_init_debugfs(struct qcom_pcie_ep *pcie_ep) static const struct pci_epc_features qcom_pcie_epc_features = { .linkup_notifier = true, .msi_capable = true, - .msix_capable = false, .align = SZ_4K, .bar[BAR_0] = { .only_64bit = true, }, .bar[BAR_1] = { .type = BAR_RESERVED, }, diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index 18055807a4f5..0621df691aec 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -398,9 +398,7 @@ static int rcar_gen4_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } static const struct pci_epc_features rcar_gen4_pcie_epc_features = { - .linkup_notifier = false, .msi_capable = true, - .msix_capable = false, .bar[BAR_1] = { .type = BAR_RESERVED, }, .bar[BAR_3] = { .type = BAR_RESERVED, }, .bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256 }, diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 4f26086f25da..0e413857649f 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1998,8 +1998,6 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, static const struct pci_epc_features tegra_pcie_epc_features = { .linkup_notifier = true, - .msi_capable = false, - .msix_capable = false, .bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M, .only_64bit = true, }, .bar[BAR_1] = { .type = BAR_RESERVED, }, diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c index a8a966844cf3..657875ef4657 100644 --- a/drivers/pci/controller/pcie-rcar-ep.c +++ b/drivers/pci/controller/pcie-rcar-ep.c @@ -436,9 +436,7 @@ static void rcar_pcie_ep_stop(struct pci_epc *epc) } static const struct pci_epc_features rcar_pcie_epc_features = { - .linkup_notifier = false, .msi_capable = true, - .msix_capable = false, /* use 64-bit BARs so mark BAR[1,3,5] as reserved */ .bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = 128, .only_64bit = true, }, diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index 300cd85fa035..799461335762 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -694,7 +694,6 @@ static int rockchip_pcie_ep_setup_irq(struct pci_epc *epc) static const struct pci_epc_features rockchip_pcie_epc_features = { .linkup_notifier = true, .msi_capable = true, - .msix_capable = false, .intx_capable = true, .align = ROCKCHIP_PCIE_AT_SIZE_ALIGN, }; From 4239b174c2fc8307a1939ebaf51118109935a8fc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:48 +0200 Subject: [PATCH 0119/2711] clk: remove unneeded 'fast_io' parameter in regmap_config When using MMIO with regmap, fast_io is implied. No need to set it again. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250813161517.4746-3-wsa+renesas@sang-engineering.com Signed-off-by: Stephen Boyd --- drivers/clk/actions/owl-common.c | 1 - drivers/clk/clk-axm5516.c | 1 - drivers/clk/nxp/clk-lpc32xx.c | 1 - drivers/clk/qcom/a53-pll.c | 1 - drivers/clk/qcom/a7-pll.c | 1 - drivers/clk/qcom/apss-ipq-pll.c | 1 - drivers/clk/qcom/clk-cbf-8996.c | 1 - drivers/clk/qcom/clk-cpu-8996.c | 1 - drivers/clk/qcom/hfpll.c | 1 - drivers/clk/qcom/ipq-cmn-pll.c | 1 - drivers/clk/thead/clk-th1520-ap.c | 1 - 11 files changed, 11 deletions(-) diff --git a/drivers/clk/actions/owl-common.c b/drivers/clk/actions/owl-common.c index c62024b7c737..b3dded204dc5 100644 --- a/drivers/clk/actions/owl-common.c +++ b/drivers/clk/actions/owl-common.c @@ -18,7 +18,6 @@ static const struct regmap_config owl_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x00cc, - .fast_io = true, }; static void owl_clk_set_regmap(const struct owl_clk_desc *desc, diff --git a/drivers/clk/clk-axm5516.c b/drivers/clk/clk-axm5516.c index 4a3462ee8f3e..3823383f3fa6 100644 --- a/drivers/clk/clk-axm5516.c +++ b/drivers/clk/clk-axm5516.c @@ -529,7 +529,6 @@ static const struct regmap_config axmclk_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x1fffc, - .fast_io = true, }; static const struct of_device_id axmclk_match_table[] = { diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index e00f270bc6aa..96a1a527b380 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -68,7 +68,6 @@ static const struct regmap_config lpc32xx_scb_regmap_config = { .reg_stride = 4, .val_format_endian = REGMAP_ENDIAN_LITTLE, .max_register = 0x114, - .fast_io = true, }; static struct regmap *clk_regmap; diff --git a/drivers/clk/qcom/a53-pll.c b/drivers/clk/qcom/a53-pll.c index f43d455ab4b8..724a642311e5 100644 --- a/drivers/clk/qcom/a53-pll.c +++ b/drivers/clk/qcom/a53-pll.c @@ -33,7 +33,6 @@ static const struct regmap_config a53pll_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x40, - .fast_io = true, }; static struct pll_freq_tbl *qcom_a53pll_get_freq_tbl(struct device *dev) diff --git a/drivers/clk/qcom/a7-pll.c b/drivers/clk/qcom/a7-pll.c index c4a53e5db229..f95aefc43119 100644 --- a/drivers/clk/qcom/a7-pll.c +++ b/drivers/clk/qcom/a7-pll.c @@ -50,7 +50,6 @@ static const struct regmap_config a7pll_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x1000, - .fast_io = true, }; static int qcom_a7pll_probe(struct platform_device *pdev) diff --git a/drivers/clk/qcom/apss-ipq-pll.c b/drivers/clk/qcom/apss-ipq-pll.c index d6c1aea7e9e1..3a8987fe7008 100644 --- a/drivers/clk/qcom/apss-ipq-pll.c +++ b/drivers/clk/qcom/apss-ipq-pll.c @@ -169,7 +169,6 @@ static const struct regmap_config ipq_pll_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x40, - .fast_io = true, }; static int apss_ipq_pll_probe(struct platform_device *pdev) diff --git a/drivers/clk/qcom/clk-cbf-8996.c b/drivers/clk/qcom/clk-cbf-8996.c index ce4efcd995ea..0b40ed601f9a 100644 --- a/drivers/clk/qcom/clk-cbf-8996.c +++ b/drivers/clk/qcom/clk-cbf-8996.c @@ -212,7 +212,6 @@ static const struct regmap_config cbf_msm8996_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x10000, - .fast_io = true, .val_format_endian = REGMAP_ENDIAN_LITTLE, }; diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c index 72689448a653..21d13c0841ed 100644 --- a/drivers/clk/qcom/clk-cpu-8996.c +++ b/drivers/clk/qcom/clk-cpu-8996.c @@ -411,7 +411,6 @@ static const struct regmap_config cpu_msm8996_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x80210, - .fast_io = true, .val_format_endian = REGMAP_ENDIAN_LITTLE, }; diff --git a/drivers/clk/qcom/hfpll.c b/drivers/clk/qcom/hfpll.c index b0b0cb074b4a..385964196185 100644 --- a/drivers/clk/qcom/hfpll.c +++ b/drivers/clk/qcom/hfpll.c @@ -99,7 +99,6 @@ static const struct regmap_config hfpll_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x30, - .fast_io = true, }; static int qcom_hfpll_probe(struct platform_device *pdev) diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c index b3d7169c63e5..dafbf5732048 100644 --- a/drivers/clk/qcom/ipq-cmn-pll.c +++ b/drivers/clk/qcom/ipq-cmn-pll.c @@ -108,7 +108,6 @@ static const struct regmap_config ipq_cmn_pll_regmap_config = { .reg_stride = 4, .val_bits = 32, .max_register = 0x7fc, - .fast_io = true, }; static const struct cmn_pll_fixed_output_clk ipq5018_output_clks[] = { diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index cf1bba58f641..cff4f014bddb 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -1056,7 +1056,6 @@ static const struct regmap_config th1520_clk_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, }; struct th1520_plat_data { From c123519bffd29e6320d3a8c4977f9e5a86d6b83d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 7 Aug 2025 09:22:37 +0200 Subject: [PATCH 0120/2711] clk: npcm: select CONFIG_AUXILIARY_BUS There are very rare randconfig builds that turn on this driver but don't already select CONFIG_AUXILIARY_BUS from another driver, and this results in a build failure: arm-linux-gnueabi-ld: drivers/clk/clk-npcm8xx.o: in function `npcm8xx_clock_driver_init': clk-npcm8xx.c:(.init.text+0x18): undefined reference to `__auxiliary_driver_register' Select the bus here, as all other clk drivers using it do. Fixes: e0b255df027e ("clk: npcm8xx: add clock controller") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20250807072241.4190376-1-arnd@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 4d56475f94fc..b1425aed6593 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -364,6 +364,7 @@ config COMMON_CLK_LOCHNAGAR config COMMON_CLK_NPCM8XX tristate "Clock driver for the NPCM8XX SoC Family" depends on ARCH_NPCM || COMPILE_TEST + select AUXILIARY_BUS help This driver supports the clocks on the Nuvoton BMC NPCM8XX SoC Family, all the clocks are initialized by the bootloader, so this driver From 37d1ade89606875c9cd6eb3b4ee416b7e1800fc4 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Wed, 13 Aug 2025 22:45:24 +0800 Subject: [PATCH 0121/2711] PCI: Clean up __pci_find_next_cap_ttl() readability Refactor the __pci_find_next_cap_ttl() to improve code clarity: - Replace magic number 0x40 with PCI_STD_HEADER_SIZEOF. - Use ALIGN_DOWN() for position alignment instead of manual bitmask. - Extract PCI capability fields via FIELD_GET() with standardized masks. - Add necessary headers (linux/align.h). No functional changes intended. Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Bjorn Helgaas Tested-by: Niklas Schnelle Acked-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250813144529.303548-2-18255117159@163.com --- drivers/pci/pci.c | 9 +++++---- include/uapi/linux/pci_regs.h | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b0f4d98036cd..40a5c87d9a6b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -432,17 +433,17 @@ static u8 __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, pci_bus_read_config_byte(bus, devfn, pos, &pos); while ((*ttl)--) { - if (pos < 0x40) + if (pos < PCI_STD_HEADER_SIZEOF) break; - pos &= ~3; + pos = ALIGN_DOWN(pos, 4); pci_bus_read_config_word(bus, devfn, pos, &ent); - id = ent & 0xff; + id = FIELD_GET(PCI_CAP_ID_MASK, ent); if (id == 0xff) break; if (id == cap) return pos; - pos = (ent >> 8); + pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, ent); } return 0; } diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index f5b17745de60..1bba99b46227 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -207,6 +207,9 @@ /* Capability lists */ +#define PCI_CAP_ID_MASK 0x00ff /* Capability ID mask */ +#define PCI_CAP_LIST_NEXT_MASK 0xff00 /* Next Capability Pointer mask */ + #define PCI_CAP_LIST_ID 0 /* Capability ID */ #define PCI_CAP_ID_PM 0x01 /* Power Management */ #define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ From 3c02084d8fa521192ea19722b1e5efae8096d939 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Wed, 13 Aug 2025 22:45:25 +0800 Subject: [PATCH 0122/2711] PCI: Refactor capability search into PCI_FIND_NEXT_CAP() The PCI Capability search functionality is duplicated across the PCI core and several controller drivers. The core's current implementation requires fully initialized PCI device and bus structures, which prevents controller drivers from using it during early initialization phases before these structures are available. Move the Capability search logic into a PCI_FIND_NEXT_CAP() macro that accepts a config space accessor function as an argument. This enables controller drivers to perform Capability discovery using their early access mechanisms prior to full device initialization while sharing the Capability search code. Convert the existing PCI core Capability search implementation to use PCI_FIND_NEXT_CAP(). Controller drivers can later use this with their early access mechanisms while maintaining the existing protection against infinite loops through preserved TTL checks. Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Bjorn Helgaas Tested-by: Niklas Schnelle Link: https://patch.msgid.link/20250813144529.303548-3-18255117159@163.com --- drivers/pci/pci.c | 42 ++++++++---------------------------------- drivers/pci/pci.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 34 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 40a5c87d9a6b..ac2658d946ea 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -424,36 +423,10 @@ found: return 1; } -static u8 __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, - u8 pos, int cap, int *ttl) -{ - u8 id; - u16 ent; - - pci_bus_read_config_byte(bus, devfn, pos, &pos); - - while ((*ttl)--) { - if (pos < PCI_STD_HEADER_SIZEOF) - break; - pos = ALIGN_DOWN(pos, 4); - pci_bus_read_config_word(bus, devfn, pos, &ent); - - id = FIELD_GET(PCI_CAP_ID_MASK, ent); - if (id == 0xff) - break; - if (id == cap) - return pos; - pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, ent); - } - return 0; -} - static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap) { - int ttl = PCI_FIND_CAP_TTL; - - return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl); + return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, bus, devfn); } u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) @@ -649,7 +622,7 @@ EXPORT_SYMBOL_GPL(pci_get_dsn); static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap) { - int rc, ttl = PCI_FIND_CAP_TTL; + int rc; u8 cap, mask; if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST) @@ -657,8 +630,8 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap) else mask = HT_5BIT_CAP_MASK; - pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos, - PCI_CAP_ID_HT, &ttl); + pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, + PCI_CAP_ID_HT, dev->bus, dev->devfn); while (pos) { rc = pci_read_config_byte(dev, pos + 3, &cap); if (rc != PCIBIOS_SUCCESSFUL) @@ -667,9 +640,10 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap) if ((cap & mask) == ht_cap) return pos; - pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, - pos + PCI_CAP_LIST_NEXT, - PCI_CAP_ID_HT, &ttl); + pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, + pos + PCI_CAP_LIST_NEXT, + PCI_CAP_ID_HT, dev->bus, + dev->devfn); } return 0; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 34f65d69662e..81580987509f 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -2,6 +2,8 @@ #ifndef DRIVERS_PCI_H #define DRIVERS_PCI_H +#include +#include #include struct pcie_tlp_log; @@ -88,6 +90,49 @@ bool pcie_cap_has_lnkctl(const struct pci_dev *dev); bool pcie_cap_has_lnkctl2(const struct pci_dev *dev); bool pcie_cap_has_rtctl(const struct pci_dev *dev); +/* Standard Capability finder */ +/** + * PCI_FIND_NEXT_CAP - Find a PCI standard capability + * @read_cfg: Function pointer for reading PCI config space + * @start: Starting position to begin search + * @cap: Capability ID to find + * @args: Arguments to pass to read_cfg function + * + * Search the capability list in PCI config space to find @cap. + * Implements TTL (time-to-live) protection against infinite loops. + * + * Return: Position of the capability if found, 0 otherwise. + */ +#define PCI_FIND_NEXT_CAP(read_cfg, start, cap, args...) \ +({ \ + int __ttl = PCI_FIND_CAP_TTL; \ + u8 __id, __found_pos = 0; \ + u8 __pos = (start); \ + u16 __ent; \ + \ + read_cfg##_byte(args, __pos, &__pos); \ + \ + while (__ttl--) { \ + if (__pos < PCI_STD_HEADER_SIZEOF) \ + break; \ + \ + __pos = ALIGN_DOWN(__pos, 4); \ + read_cfg##_word(args, __pos, &__ent); \ + \ + __id = FIELD_GET(PCI_CAP_ID_MASK, __ent); \ + if (__id == 0xff) \ + break; \ + \ + if (__id == (cap)) { \ + __found_pos = __pos; \ + break; \ + } \ + \ + __pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, __ent); \ + } \ + __found_pos; \ +}) + /* Functions internal to the PCI core code */ #ifdef CONFIG_DMI From 4d909bf1a53eb1e2e4d523a8d6f66532ac1bae0b Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Wed, 13 Aug 2025 22:45:26 +0800 Subject: [PATCH 0123/2711] PCI: Refactor extended capability search into PCI_FIND_NEXT_EXT_CAP() Move the extended Capability search logic into a PCI_FIND_NEXT_EXT_CAP() macro that accepts a config space accessor function as an argument. This enables controller drivers to perform Capability discovery using their early access mechanisms prior to full device initialization while sharing the Capability search code. Convert the existing PCI core extended Capability search implementation to use PCI_FIND_NEXT_EXT_CAP(). Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Bjorn Helgaas Tested-by: Niklas Schnelle Link: https://patch.msgid.link/20250813144529.303548-4-18255117159@163.com --- drivers/pci/pci.c | 35 ++--------------------------------- drivers/pci/pci.h | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index ac2658d946ea..e698278229f2 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -527,42 +527,11 @@ EXPORT_SYMBOL(pci_bus_find_capability); */ u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap) { - u32 header; - int ttl; - u16 pos = PCI_CFG_SPACE_SIZE; - - /* minimum 8 bytes per capability */ - ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; - if (dev->cfg_size <= PCI_CFG_SPACE_SIZE) return 0; - if (start) - pos = start; - - if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL) - return 0; - - /* - * If we have no capabilities, this is indicated by cap ID, - * cap version and next pointer all being 0. - */ - if (header == 0) - return 0; - - while (ttl-- > 0) { - if (PCI_EXT_CAP_ID(header) == cap && pos != start) - return pos; - - pos = PCI_EXT_CAP_NEXT(header); - if (pos < PCI_CFG_SPACE_SIZE) - break; - - if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL) - break; - } - - return 0; + return PCI_FIND_NEXT_EXT_CAP(pci_bus_read_config, start, cap, + dev->bus, dev->devfn); } EXPORT_SYMBOL_GPL(pci_find_next_ext_capability); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 81580987509f..7fb44faf2c44 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -133,6 +133,46 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev); __found_pos; \ }) +/* Extended Capability finder */ +/** + * PCI_FIND_NEXT_EXT_CAP - Find a PCI extended capability + * @read_cfg: Function pointer for reading PCI config space + * @start: Starting position to begin search (0 for initial search) + * @cap: Extended capability ID to find + * @args: Arguments to pass to read_cfg function + * + * Search the extended capability list in PCI config space to find @cap. + * Implements TTL protection against infinite loops using a calculated + * maximum search count. + * + * Return: Position of the capability if found, 0 otherwise. + */ +#define PCI_FIND_NEXT_EXT_CAP(read_cfg, start, cap, args...) \ +({ \ + u16 __pos = (start) ?: PCI_CFG_SPACE_SIZE; \ + u16 __found_pos = 0; \ + int __ttl, __ret; \ + u32 __header; \ + \ + __ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; \ + while (__ttl-- > 0 && __pos >= PCI_CFG_SPACE_SIZE) { \ + __ret = read_cfg##_dword(args, __pos, &__header); \ + if (__ret != PCIBIOS_SUCCESSFUL) \ + break; \ + \ + if (__header == 0) \ + break; \ + \ + if (PCI_EXT_CAP_ID(__header) == (cap) && __pos != start) {\ + __found_pos = __pos; \ + break; \ + } \ + \ + __pos = PCI_EXT_CAP_NEXT(__header); \ + } \ + __found_pos; \ +}) + /* Functions internal to the PCI core code */ #ifdef CONFIG_DMI From 8ffc9f234fdf332310015d507ae22db9a2820d37 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Wed, 13 Aug 2025 22:45:27 +0800 Subject: [PATCH 0124/2711] PCI: dwc: Implement capability search using PCI core APIs The PCI core now provides generic PCI_FIND_NEXT_CAP() and PCI_FIND_NEXT_EXT_CAP() macros to search for PCI capabilities, using config accessors we supply. Use them in the DWC driver to implement dw_pcie_find_capability() and dw_pcie_find_ext_capability() instead of duplicating the algorithm. Signed-off-by: Hans Zhang <18255117159@163.com> [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250813144529.303548-5-18255117159@163.com --- drivers/pci/controller/dwc/pcie-designware.c | 77 ++------------------ drivers/pci/controller/dwc/pcie-designware.h | 21 ++++++ 2 files changed, 26 insertions(+), 72 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 89aad5a08928..5fe0744d4235 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -213,83 +213,16 @@ void dw_pcie_version_detect(struct dw_pcie *pci) pci->type = ver; } -/* - * These interfaces resemble the pci_find_*capability() interfaces, but these - * are for configuring host controllers, which are bridges *to* PCI devices but - * are not PCI devices themselves. - */ -static u8 __dw_pcie_find_next_cap(struct dw_pcie *pci, u8 cap_ptr, - u8 cap) -{ - u8 cap_id, next_cap_ptr; - u16 reg; - - if (!cap_ptr) - return 0; - - reg = dw_pcie_readw_dbi(pci, cap_ptr); - cap_id = (reg & 0x00ff); - - if (cap_id > PCI_CAP_ID_MAX) - return 0; - - if (cap_id == cap) - return cap_ptr; - - next_cap_ptr = (reg & 0xff00) >> 8; - return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap); -} - u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap) { - u8 next_cap_ptr; - u16 reg; - - reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST); - next_cap_ptr = (reg & 0x00ff); - - return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap); + return PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap, + pci); } EXPORT_SYMBOL_GPL(dw_pcie_find_capability); -static u16 dw_pcie_find_next_ext_capability(struct dw_pcie *pci, u16 start, - u8 cap) -{ - u32 header; - int ttl; - int pos = PCI_CFG_SPACE_SIZE; - - /* minimum 8 bytes per capability */ - ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; - - if (start) - pos = start; - - header = dw_pcie_readl_dbi(pci, pos); - /* - * If we have no capabilities, this is indicated by cap ID, - * cap version and next pointer all being 0. - */ - if (header == 0) - return 0; - - while (ttl-- > 0) { - if (PCI_EXT_CAP_ID(header) == cap && pos != start) - return pos; - - pos = PCI_EXT_CAP_NEXT(header); - if (pos < PCI_CFG_SPACE_SIZE) - break; - - header = dw_pcie_readl_dbi(pci, pos); - } - - return 0; -} - u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap) { - return dw_pcie_find_next_ext_capability(pci, 0, cap); + return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, pci); } EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability); @@ -302,8 +235,8 @@ static u16 __dw_pcie_find_vsec_capability(struct dw_pcie *pci, u16 vendor_id, if (vendor_id != dw_pcie_readw_dbi(pci, PCI_VENDOR_ID)) return 0; - while ((vsec = dw_pcie_find_next_ext_capability(pci, vsec, - PCI_EXT_CAP_ID_VNDR))) { + while ((vsec = PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, vsec, + PCI_EXT_CAP_ID_VNDR, pci))) { header = dw_pcie_readl_dbi(pci, vsec + PCI_VNDR_HEADER); if (PCI_VNDR_HEADER_ID(header) == vsec_id) return vsec; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 00f52d472dcd..b5e7e18138a6 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -609,6 +609,27 @@ static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val) dw_pcie_write_dbi2(pci, reg, 0x4, val); } +static inline int dw_pcie_read_cfg_byte(struct dw_pcie *pci, int where, + u8 *val) +{ + *val = dw_pcie_readb_dbi(pci, where); + return PCIBIOS_SUCCESSFUL; +} + +static inline int dw_pcie_read_cfg_word(struct dw_pcie *pci, int where, + u16 *val) +{ + *val = dw_pcie_readw_dbi(pci, where); + return PCIBIOS_SUCCESSFUL; +} + +static inline int dw_pcie_read_cfg_dword(struct dw_pcie *pci, int where, + u32 *val) +{ + *val = dw_pcie_readl_dbi(pci, where); + return PCIBIOS_SUCCESSFUL; +} + static inline unsigned int dw_pcie_ep_get_dbi_offset(struct dw_pcie_ep *ep, u8 func_no) { From a1e1c10878d7ea5147bef02a068061a9c3e1461a Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Wed, 13 Aug 2025 17:40:03 +0800 Subject: [PATCH 0125/2711] clk: tegra: Remove redundant semicolons Remove unnecessary semicolons. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250813094003.552308-1-liaoyuanhong@vivo.com Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-dfll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index 58fa5a59e0c7..22dc29432eff 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -882,7 +882,7 @@ static void dfll_set_frequency_request(struct tegra_dfll *td, { u32 val = 0; int force_val; - int coef = 128; /* FIXME: td->cg_scale? */; + int coef = 128; /* FIXME: td->cg_scale? */ force_val = (req->lut_index - td->lut_safe) * coef / td->cg; force_val = clamp(force_val, FORCE_MIN, FORCE_MAX); From 539b06e9e0d805aec5f8f7407483c90c71a13209 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 29 Jul 2025 10:27:35 +0800 Subject: [PATCH 0126/2711] clk: clk-axi-clkgen: remove unneeded semicolon Remove unnecessary semicolons reported by Coccinelle/coccicheck and the semantic patch at scripts/coccinelle/misc/semicolon.cocci. Signed-off-by: Chen Ni Link: https://lore.kernel.org/r/20250729022735.1437560-1-nichen@iscas.ac.cn Signed-off-by: Stephen Boyd --- drivers/clk/clk-axi-clkgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index aec62301fa06..fa5ccef73e60 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -540,7 +540,7 @@ static int axi_clkgen_setup_limits(struct axi_clkgen *axi_clkgen, default: return dev_err_probe(dev, -ENODEV, "Unknown speed grade %d\n", speed_grade); - }; + } /* Overwrite vco limits for ultrascale+ */ if (tech == ADI_AXI_FPGA_TECH_ULTRASCALE_PLUS) { From bbf7d0468d0da71d76cc6ec9bc8a224325d07b6b Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 7 Aug 2025 15:55:38 +0200 Subject: [PATCH 0127/2711] PCI/AER: Fix missing uevent on recovery when a reset is requested Since commit 7b42d97e99d3 ("PCI/ERR: Always report current recovery status for udev") AER uses the result of error_detected() as parameter to pci_uevent_ers(). As pci_uevent_ers() however does not handle PCI_ERS_RESULT_NEED_RESET this results in a missing uevent for the beginning of recovery if drivers request a reset. Fix this by treating PCI_ERS_RESULT_NEED_RESET as beginning recovery. Fixes: 7b42d97e99d3 ("PCI/ERR: Always report current recovery status for udev") Signed-off-by: Niklas Schnelle Signed-off-by: Bjorn Helgaas Reviewed-by: Lukas Wunner Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250807-add_err_uevents-v5-1-adf85b0620b0@linux.ibm.com --- drivers/pci/pci-driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 63665240ae87..6405acdb5d0f 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1596,6 +1596,7 @@ void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type) switch (err_type) { case PCI_ERS_RESULT_NONE: case PCI_ERS_RESULT_CAN_RECOVER: + case PCI_ERS_RESULT_NEED_RESET: envp[idx++] = "ERROR_EVENT=BEGIN_RECOVERY"; envp[idx++] = "DEVICE_ONLINE=0"; break; From dab32f2576a39d5f54f3dbbbc718d92fa5109ce9 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 7 Aug 2025 15:55:39 +0200 Subject: [PATCH 0128/2711] s390/pci: Use pci_uevent_ers() in PCI recovery Issue uevents on s390 during PCI recovery using pci_uevent_ers() as done by EEH and AER PCIe recovery routines. Signed-off-by: Niklas Schnelle Signed-off-by: Bjorn Helgaas Reviewed-by: Lukas Wunner Link: https://patch.msgid.link/20250807-add_err_uevents-v5-2-adf85b0620b0@linux.ibm.com --- arch/s390/pci/pci_event.c | 3 +++ drivers/pci/pci-driver.c | 2 +- include/linux/pci.h | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index d930416d4c90..b95376041501 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c @@ -88,6 +88,7 @@ static pci_ers_result_t zpci_event_notify_error_detected(struct pci_dev *pdev, pci_ers_result_t ers_res = PCI_ERS_RESULT_DISCONNECT; ers_res = driver->err_handler->error_detected(pdev, pdev->error_state); + pci_uevent_ers(pdev, ers_res); if (ers_result_indicates_abort(ers_res)) pr_info("%s: Automatic recovery failed after initial reporting\n", pci_name(pdev)); else if (ers_res == PCI_ERS_RESULT_NEED_RESET) @@ -244,6 +245,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) ers_res = PCI_ERS_RESULT_RECOVERED; if (ers_res != PCI_ERS_RESULT_RECOVERED) { + pci_uevent_ers(pdev, PCI_ERS_RESULT_DISCONNECT); pr_err("%s: Automatic recovery failed; operator intervention is required\n", pci_name(pdev)); status_str = "failed (driver can't recover)"; @@ -253,6 +255,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) pr_info("%s: The device is ready to resume operations\n", pci_name(pdev)); if (driver->err_handler->resume) driver->err_handler->resume(pdev); + pci_uevent_ers(pdev, PCI_ERS_RESULT_RECOVERED); out_unlock: pci_dev_unlock(pdev); zpci_report_status(zdev, "recovery", status_str); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 6405acdb5d0f..302d61783f6c 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1582,7 +1582,7 @@ static int pci_uevent(const struct device *dev, struct kobj_uevent_env *env) return 0; } -#if defined(CONFIG_PCIEAER) || defined(CONFIG_EEH) +#if defined(CONFIG_PCIEAER) || defined(CONFIG_EEH) || defined(CONFIG_S390) /** * pci_uevent_ers - emit a uevent during recovery path of PCI device * @pdev: PCI device undergoing error recovery diff --git a/include/linux/pci.h b/include/linux/pci.h index 59876de13860..7735acf6f349 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -2764,7 +2764,7 @@ static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev) return false; } -#if defined(CONFIG_PCIEPORTBUS) || defined(CONFIG_EEH) +#if defined(CONFIG_PCIEPORTBUS) || defined(CONFIG_EEH) || defined(CONFIG_S390) void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type); #endif From 704e5dd1c02371dfc7d22e1520102b197a3b628b Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 7 Aug 2025 15:55:40 +0200 Subject: [PATCH 0129/2711] powerpc/eeh: Use result of error_detected() in uevent Ever since uevent support was added for AER and EEH with commit 856e1eb9bdd4 ("PCI/AER: Add uevents in AER and EEH error/resume"), it reported PCI_ERS_RESULT_NONE as uevent when recovery begins. Commit 7b42d97e99d3 ("PCI/ERR: Always report current recovery status for udev") subsequently amended AER to report the actual return value of error_detected(). Make the same change to EEH to align it with AER and s390. Suggested-by: Lukas Wunner Link: https://lore.kernel.org/linux-pci/aIp6LiKJor9KLVpv@wunner.de/ Signed-off-by: Niklas Schnelle Signed-off-by: Bjorn Helgaas Reviewed-by: Lukas Wunner Reviewed-by: Kuppuswamy Sathyanarayanan Acked-by: Mahesh Salgaonkar Link: https://patch.msgid.link/20250807-add_err_uevents-v5-3-adf85b0620b0@linux.ibm.com --- arch/powerpc/kernel/eeh_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 48ad0116f359..ef78ff77cf8f 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -334,7 +334,7 @@ static enum pci_ers_result eeh_report_error(struct eeh_dev *edev, rc = driver->err_handler->error_detected(pdev, pci_channel_io_frozen); edev->in_error = true; - pci_uevent_ers(pdev, PCI_ERS_RESULT_NONE); + pci_uevent_ers(pdev, rc); return rc; } From 7fdc1d1b02e471c2ad4292705265706e003430a0 Mon Sep 17 00:00:00 2001 From: Raviteja Laggyshetty Date: Thu, 14 Aug 2025 14:54:19 +0000 Subject: [PATCH 0130/2711] dt-bindings: interconnect: document the RPMh Network-On-Chip interconnect in Glymur SoC Document the RPMh Network-On-Chip Interconnect in Glymur platform. Co-developed-by: Odelu Kukatla Signed-off-by: Odelu Kukatla Reviewed-by: "Rob Herring (Arm)" Signed-off-by: Raviteja Laggyshetty Link: https://lore.kernel.org/r/20250814-glymur-icc-v2-1-596cca6b6015@oss.qualcomm.com Signed-off-by: Georgi Djakov --- .../interconnect/qcom,glymur-rpmh.yaml | 172 +++++++++++++++ .../interconnect/qcom,glymur-rpmh.h | 205 ++++++++++++++++++ 2 files changed, 377 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,glymur-rpmh.yaml create mode 100644 include/dt-bindings/interconnect/qcom,glymur-rpmh.h diff --git a/Documentation/devicetree/bindings/interconnect/qcom,glymur-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,glymur-rpmh.yaml new file mode 100644 index 000000000000..d55a7bcf5591 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,glymur-rpmh.yaml @@ -0,0 +1,172 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,glymur-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on GLYMUR + +maintainers: + - Raviteja Laggyshetty + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + + See also: include/dt-bindings/interconnect/qcom,glymur-rpmh.h + +properties: + compatible: + enum: + - qcom,glymur-aggre1-noc + - qcom,glymur-aggre2-noc + - qcom,glymur-aggre3-noc + - qcom,glymur-aggre4-noc + - qcom,glymur-clk-virt + - qcom,glymur-cnoc-cfg + - qcom,glymur-cnoc-main + - qcom,glymur-hscnoc + - qcom,glymur-lpass-ag-noc + - qcom,glymur-lpass-lpiaon-noc + - qcom,glymur-lpass-lpicx-noc + - qcom,glymur-mc-virt + - qcom,glymur-mmss-noc + - qcom,glymur-nsinoc + - qcom,glymur-nsp-noc + - qcom,glymur-oobm-ss-noc + - qcom,glymur-pcie-east-anoc + - qcom,glymur-pcie-east-slv-noc + - qcom,glymur-pcie-west-anoc + - qcom,glymur-pcie-west-slv-noc + - qcom,glymur-system-noc + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 4 + +required: + - compatible + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,glymur-clk-virt + - qcom,glymur-mc-virt + then: + properties: + reg: false + else: + required: + - reg + + - if: + properties: + compatible: + contains: + enum: + - qcom,glymur-pcie-west-anoc + then: + properties: + clocks: + items: + - description: aggre PCIE_3A WEST AXI clock + - description: aggre PCIE_3B WEST AXI clock + - description: aggre PCIE_4 WEST AXI clock + - description: aggre PCIE_6 WEST AXI clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,glymur-pcie-east-anoc + then: + properties: + clocks: + items: + - description: aggre PCIE_5 EAST AXI clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,glymur-aggre2-noc + then: + properties: + clocks: + items: + - description: aggre USB3 TERT AXI clock + - description: aggre USB4_2 AXI clock + - description: aggre UFS PHY AXI clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,glymur-aggre4-noc + then: + properties: + clocks: + items: + - description: aggre USB3 PRIM AXI clock + - description: aggre USB3 SEC AXI clock + - description: aggre USB4_0 AXI clock + - description: aggre USB4_1 AXI clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,glymur-pcie-west-anoc + - qcom,glymur-pcie-east-anoc + - qcom,glymur-aggre2-noc + - qcom,glymur-aggre4-noc + then: + required: + - clocks + else: + properties: + clocks: false + +unevaluatedProperties: false + +examples: + - | + #include + clk_virt: interconnect-0 { + compatible = "qcom,glymur-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,glymur-aggre1-noc"; + reg = <0x016e0000 0x14400>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre4_noc: interconnect@1740000 { + compatible = "qcom,glymur-aggre4-noc"; + reg = <0x01740000 0x14400>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + clocks = <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, + <&gcc GCC_AGGRE_USB4_0_AXI_CLK>, + <&gcc GCC_AGGRE_USB4_1_AXI_CLK>; + }; diff --git a/include/dt-bindings/interconnect/qcom,glymur-rpmh.h b/include/dt-bindings/interconnect/qcom,glymur-rpmh.h new file mode 100644 index 000000000000..6a0e754345e4 --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,glymur-rpmh.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_GLYMUR_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_GLYMUR_H + +#define MASTER_CRYPTO 0 +#define MASTER_SOCCP_PROC 1 +#define MASTER_QDSS_ETR 2 +#define MASTER_QDSS_ETR_1 3 +#define SLAVE_A1NOC_SNOC 4 + +#define MASTER_UFS_MEM 0 +#define MASTER_USB3_2 1 +#define MASTER_USB4_2 2 +#define SLAVE_A2NOC_SNOC 3 + +#define MASTER_QSPI_0 0 +#define MASTER_QUP_0 1 +#define MASTER_QUP_1 2 +#define MASTER_QUP_2 3 +#define MASTER_SP 4 +#define MASTER_SDCC_2 5 +#define MASTER_SDCC_4 6 +#define MASTER_USB2 7 +#define MASTER_USB3_MP 8 +#define SLAVE_A3NOC_SNOC 9 + +#define MASTER_USB3_0 0 +#define MASTER_USB3_1 1 +#define MASTER_USB4_0 2 +#define MASTER_USB4_1 3 +#define SLAVE_A4NOC_HSCNOC 4 + +#define MASTER_QUP_CORE_0 0 +#define MASTER_QUP_CORE_1 1 +#define MASTER_QUP_CORE_2 2 +#define SLAVE_QUP_CORE_0 3 +#define SLAVE_QUP_CORE_1 4 +#define SLAVE_QUP_CORE_2 5 + +#define MASTER_CNOC_CFG 0 +#define SLAVE_AHB2PHY_SOUTH 1 +#define SLAVE_AHB2PHY_NORTH 2 +#define SLAVE_AHB2PHY_2 3 +#define SLAVE_AHB2PHY_3 4 +#define SLAVE_AV1_ENC_CFG 5 +#define SLAVE_CAMERA_CFG 6 +#define SLAVE_CLK_CTL 7 +#define SLAVE_CRYPTO_0_CFG 8 +#define SLAVE_DISPLAY_CFG 9 +#define SLAVE_GFX3D_CFG 10 +#define SLAVE_IMEM_CFG 11 +#define SLAVE_PCIE_0_CFG 12 +#define SLAVE_PCIE_1_CFG 13 +#define SLAVE_PCIE_2_CFG 14 +#define SLAVE_PCIE_3A_CFG 15 +#define SLAVE_PCIE_3B_CFG 16 +#define SLAVE_PCIE_4_CFG 17 +#define SLAVE_PCIE_5_CFG 18 +#define SLAVE_PCIE_6_CFG 19 +#define SLAVE_PCIE_RSCC 20 +#define SLAVE_PDM 21 +#define SLAVE_PRNG 22 +#define SLAVE_QDSS_CFG 23 +#define SLAVE_QSPI_0 24 +#define SLAVE_QUP_0 25 +#define SLAVE_QUP_1 26 +#define SLAVE_QUP_2 27 +#define SLAVE_SDCC_2 28 +#define SLAVE_SDCC_4 29 +#define SLAVE_SMMUV3_CFG 30 +#define SLAVE_TCSR 31 +#define SLAVE_TLMM 32 +#define SLAVE_UFS_MEM_CFG 33 +#define SLAVE_USB2 34 +#define SLAVE_USB3_0 35 +#define SLAVE_USB3_1 36 +#define SLAVE_USB3_2 37 +#define SLAVE_USB3_MP 38 +#define SLAVE_USB4_0 39 +#define SLAVE_USB4_1 40 +#define SLAVE_USB4_2 41 +#define SLAVE_VENUS_CFG 42 +#define SLAVE_CNOC_PCIE_SLAVE_EAST_CFG 43 +#define SLAVE_CNOC_PCIE_SLAVE_WEST_CFG 44 +#define SLAVE_LPASS_QTB_CFG 45 +#define SLAVE_CNOC_MNOC_CFG 46 +#define SLAVE_NSP_QTB_CFG 47 +#define SLAVE_PCIE_EAST_ANOC_CFG 48 +#define SLAVE_PCIE_WEST_ANOC_CFG 49 +#define SLAVE_QDSS_STM 50 +#define SLAVE_TCU 51 + +#define MASTER_HSCNOC_CNOC 0 +#define SLAVE_AOSS 1 +#define SLAVE_IPC_ROUTER_CFG 2 +#define SLAVE_SOCCP 3 +#define SLAVE_TME_CFG 4 +#define SLAVE_APPSS 5 +#define SLAVE_CNOC_CFG 6 +#define SLAVE_BOOT_IMEM 7 +#define SLAVE_IMEM 8 + +#define MASTER_GPU_TCU 0 +#define MASTER_PCIE_TCU 1 +#define MASTER_SYS_TCU 2 +#define MASTER_APPSS_PROC 3 +#define MASTER_AGGRE_NOC_EAST 4 +#define MASTER_GFX3D 5 +#define MASTER_LPASS_GEM_NOC 6 +#define MASTER_MNOC_HF_MEM_NOC 7 +#define MASTER_MNOC_SF_MEM_NOC 8 +#define MASTER_COMPUTE_NOC 9 +#define MASTER_PCIE_EAST 10 +#define MASTER_PCIE_WEST 11 +#define MASTER_SNOC_SF_MEM_NOC 12 +#define MASTER_WLAN_Q6 13 +#define MASTER_GIC 14 +#define SLAVE_HSCNOC_CNOC 15 +#define SLAVE_LLCC 16 +#define SLAVE_PCIE_EAST 17 +#define SLAVE_PCIE_WEST 18 + +#define MASTER_LPIAON_NOC 0 +#define SLAVE_LPASS_GEM_NOC 1 + +#define MASTER_LPASS_LPINOC 0 +#define SLAVE_LPIAON_NOC_LPASS_AG_NOC 1 + +#define MASTER_LPASS_PROC 0 +#define SLAVE_LPICX_NOC_LPIAON_NOC 1 + +#define MASTER_LLCC 0 +#define SLAVE_EBI1 1 + +#define MASTER_AV1_ENC 0 +#define MASTER_CAMNOC_HF 1 +#define MASTER_CAMNOC_ICP 2 +#define MASTER_CAMNOC_SF 3 +#define MASTER_EVA 4 +#define MASTER_MDP 5 +#define MASTER_CDSP_HCP 6 +#define MASTER_VIDEO 7 +#define MASTER_VIDEO_CV_PROC 8 +#define MASTER_VIDEO_V_PROC 9 +#define MASTER_CNOC_MNOC_CFG 10 +#define SLAVE_MNOC_HF_MEM_NOC 11 +#define SLAVE_MNOC_SF_MEM_NOC 12 +#define SLAVE_SERVICE_MNOC 13 + +#define MASTER_CPUCP 0 +#define SLAVE_NSINOC_SYSTEM_NOC 1 +#define SLAVE_SERVICE_NSINOC 2 + +#define MASTER_CDSP_PROC 0 +#define SLAVE_NSP0_HSC_NOC 1 + +#define MASTER_OOBMSS_SP_PROC 0 +#define SLAVE_OOBMSS_SNOC 1 + +#define MASTER_PCIE_EAST_ANOC_CFG 0 +#define MASTER_PCIE_0 1 +#define MASTER_PCIE_1 2 +#define MASTER_PCIE_5 3 +#define SLAVE_PCIE_EAST_MEM_NOC 4 +#define SLAVE_SERVICE_PCIE_EAST_AGGRE_NOC 5 + +#define MASTER_HSCNOC_PCIE_EAST 0 +#define MASTER_CNOC_PCIE_EAST_SLAVE_CFG 1 +#define SLAVE_HSCNOC_PCIE_EAST_MS_MPU_CFG 2 +#define SLAVE_SERVICE_PCIE_EAST 3 +#define SLAVE_PCIE_0 4 +#define SLAVE_PCIE_1 5 +#define SLAVE_PCIE_5 6 + +#define MASTER_PCIE_WEST_ANOC_CFG 0 +#define MASTER_PCIE_2 1 +#define MASTER_PCIE_3A 2 +#define MASTER_PCIE_3B 3 +#define MASTER_PCIE_4 4 +#define MASTER_PCIE_6 5 +#define SLAVE_PCIE_WEST_MEM_NOC 6 +#define SLAVE_SERVICE_PCIE_WEST_AGGRE_NOC 7 + +#define MASTER_HSCNOC_PCIE_WEST 0 +#define MASTER_CNOC_PCIE_WEST_SLAVE_CFG 1 +#define SLAVE_HSCNOC_PCIE_WEST_MS_MPU_CFG 2 +#define SLAVE_SERVICE_PCIE_WEST 3 +#define SLAVE_PCIE_2 4 +#define SLAVE_PCIE_3A 5 +#define SLAVE_PCIE_3B 6 +#define SLAVE_PCIE_4 7 +#define SLAVE_PCIE_6 8 + +#define MASTER_A1NOC_SNOC 0 +#define MASTER_A2NOC_SNOC 1 +#define MASTER_A3NOC_SNOC 2 +#define MASTER_NSINOC_SNOC 3 +#define MASTER_OOBMSS 4 +#define SLAVE_SNOC_GEM_NOC_SF 5 + +#endif From 42d590d100f2e47e47d974a902b9ed610e464824 Mon Sep 17 00:00:00 2001 From: Zqiang Date: Wed, 13 Aug 2025 21:30:02 +0800 Subject: [PATCH 0131/2711] rcu: Remove local_irq_save/restore() in rcu_preempt_deferred_qs_handler() The per-CPU rcu_data structure's ->defer_qs_iw field is initialized by IRQ_WORK_INIT_HARD(), which means that the subsequent invocation of rcu_preempt_deferred_qs_handler() will always be executed with interrupts disabled. This commit therefore removes the local_irq_save/restore() operations from rcu_preempt_deferred_qs_handler() and adds a call to lockdep_assert_irqs_disabled() in order to enable lockdep to diagnose mistaken invocations of this function from interrupts-enabled code. Signed-off-by: Zqiang Signed-off-by: Paul E. McKenney --- kernel/rcu/tree_plugin.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 4cd170b2d655..d85763336b3c 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -626,11 +626,10 @@ notrace void rcu_preempt_deferred_qs(struct task_struct *t) */ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) { - unsigned long flags; struct rcu_data *rdp; + lockdep_assert_irqs_disabled(); rdp = container_of(iwp, struct rcu_data, defer_qs_iw); - local_irq_save(flags); /* * If the IRQ work handler happens to run in the middle of RCU read-side @@ -647,8 +646,6 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp) */ if (rcu_preempt_depth() > 0) WRITE_ONCE(rdp->defer_qs_iw_pending, DEFER_QS_IDLE); - - local_irq_restore(flags); } /* From f39494089aaa1022008eee245fb83ef1ae911b6d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 15 Jul 2025 21:09:13 -0700 Subject: [PATCH 0132/2711] srcu: Move rcu_is_watching() checks to srcu_read_{,un}lock_fast() The rcu_is_watching() warnings are currently in the SRCU-tree implementations of __srcu_read_lock_fast() and __srcu_read_unlock_fast(). However, this makes it difficult to create _notrace variants of srcu_read_lock_fast() and srcu_read_unlock_fast(). This commit therefore moves these checks to srcu_read_lock_fast(), srcu_read_unlock_fast(), srcu_down_read_fast(), and srcu_up_read_fast(). Signed-off-by: Paul E. McKenney Reviewed-by: Joel Fernandes Cc: Mathieu Desnoyers Cc: Steven Rostedt Cc: Sebastian Andrzej Siewior Cc: --- include/linux/srcu.h | 4 ++++ include/linux/srcutree.h | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/srcu.h b/include/linux/srcu.h index f179700fecaf..478c73d067f7 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -275,6 +275,7 @@ static inline struct srcu_ctr __percpu *srcu_read_lock_fast(struct srcu_struct * { struct srcu_ctr __percpu *retval; + RCU_LOCKDEP_WARN(!rcu_is_watching(), "RCU must be watching srcu_read_lock_fast()."); srcu_check_read_flavor_force(ssp, SRCU_READ_FLAVOR_FAST); retval = __srcu_read_lock_fast(ssp); rcu_try_lock_acquire(&ssp->dep_map); @@ -295,6 +296,7 @@ static inline struct srcu_ctr __percpu *srcu_read_lock_fast(struct srcu_struct * static inline struct srcu_ctr __percpu *srcu_down_read_fast(struct srcu_struct *ssp) __acquires(ssp) { WARN_ON_ONCE(IS_ENABLED(CONFIG_PROVE_RCU) && in_nmi()); + RCU_LOCKDEP_WARN(!rcu_is_watching(), "RCU must be watching srcu_down_read_fast()."); srcu_check_read_flavor_force(ssp, SRCU_READ_FLAVOR_FAST); return __srcu_read_lock_fast(ssp); } @@ -389,6 +391,7 @@ static inline void srcu_read_unlock_fast(struct srcu_struct *ssp, struct srcu_ct srcu_check_read_flavor(ssp, SRCU_READ_FLAVOR_FAST); srcu_lock_release(&ssp->dep_map); __srcu_read_unlock_fast(ssp, scp); + RCU_LOCKDEP_WARN(!rcu_is_watching(), "RCU must be watching srcu_read_unlock_fast()."); } /** @@ -405,6 +408,7 @@ static inline void srcu_up_read_fast(struct srcu_struct *ssp, struct srcu_ctr __ WARN_ON_ONCE(IS_ENABLED(CONFIG_PROVE_RCU) && in_nmi()); srcu_check_read_flavor(ssp, SRCU_READ_FLAVOR_FAST); __srcu_read_unlock_fast(ssp, scp); + RCU_LOCKDEP_WARN(!rcu_is_watching(), "RCU must be watching srcu_up_read_fast()."); } /** diff --git a/include/linux/srcutree.h b/include/linux/srcutree.h index bf44d8d1e69e..043b5a67ef71 100644 --- a/include/linux/srcutree.h +++ b/include/linux/srcutree.h @@ -244,7 +244,6 @@ static inline struct srcu_ctr __percpu *__srcu_read_lock_fast(struct srcu_struct { struct srcu_ctr __percpu *scp = READ_ONCE(ssp->srcu_ctrp); - RCU_LOCKDEP_WARN(!rcu_is_watching(), "RCU must be watching srcu_read_lock_fast()."); if (!IS_ENABLED(CONFIG_NEED_SRCU_NMI_SAFE)) this_cpu_inc(scp->srcu_locks.counter); /* Y */ else @@ -275,7 +274,6 @@ static inline void __srcu_read_unlock_fast(struct srcu_struct *ssp, struct srcu_ this_cpu_inc(scp->srcu_unlocks.counter); /* Z */ else atomic_long_inc(raw_cpu_ptr(&scp->srcu_unlocks)); /* Z */ - RCU_LOCKDEP_WARN(!rcu_is_watching(), "RCU must be watching srcu_read_unlock_fast()."); } void __srcu_check_read_flavor(struct srcu_struct *ssp, int read_flavor); From 7e2a2d060da4860af37e1000dc62a30a1551d9e8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 16 Jul 2025 09:12:16 -0700 Subject: [PATCH 0133/2711] srcu: Add srcu_read_lock_fast_notrace() and srcu_read_unlock_fast_notrace() This commit adds no-trace variants of the srcu_read_lock_fast() and srcu_read_unlock_fast() functions for tracing use. [ paulmck: Apply notrace feedback from Joel Fernandes, Steven Rostedt, and Mathieu Desnoyers. ] [ paulmck: Apply excess-notrace feedback from Boqun Feng. ] Link: https://lore.kernel.org/all/20250721162433.10454-1-paulmck@kernel.org Signed-off-by: Paul E. McKenney Reviewed-by: Joel Fernandes Cc: Mathieu Desnoyers Cc: Steven Rostedt Cc: Sebastian Andrzej Siewior Cc: --- include/linux/srcu.h | 25 +++++++++++++++++++++++++ include/linux/srcutree.h | 5 +++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/include/linux/srcu.h b/include/linux/srcu.h index 478c73d067f7..7a692bf8f99b 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -282,6 +282,20 @@ static inline struct srcu_ctr __percpu *srcu_read_lock_fast(struct srcu_struct * return retval; } +/* + * Used by tracing, cannot be traced and cannot call lockdep. + * See srcu_read_lock_fast() for more information. + */ +static inline struct srcu_ctr __percpu *srcu_read_lock_fast_notrace(struct srcu_struct *ssp) + __acquires(ssp) +{ + struct srcu_ctr __percpu *retval; + + srcu_check_read_flavor_force(ssp, SRCU_READ_FLAVOR_FAST); + retval = __srcu_read_lock_fast(ssp); + return retval; +} + /** * srcu_down_read_fast - register a new reader for an SRCU-protected structure. * @ssp: srcu_struct in which to register the new reader. @@ -394,6 +408,17 @@ static inline void srcu_read_unlock_fast(struct srcu_struct *ssp, struct srcu_ct RCU_LOCKDEP_WARN(!rcu_is_watching(), "RCU must be watching srcu_read_unlock_fast()."); } +/* + * Used by tracing, cannot be traced and cannot call lockdep. + * See srcu_read_unlock_fast() for more information. + */ +static inline void srcu_read_unlock_fast_notrace(struct srcu_struct *ssp, + struct srcu_ctr __percpu *scp) __releases(ssp) +{ + srcu_check_read_flavor(ssp, SRCU_READ_FLAVOR_FAST); + __srcu_read_unlock_fast(ssp, scp); +} + /** * srcu_up_read_fast - unregister a old reader from an SRCU-protected structure. * @ssp: srcu_struct in which to unregister the old reader. diff --git a/include/linux/srcutree.h b/include/linux/srcutree.h index 043b5a67ef71..4d2fee4d3828 100644 --- a/include/linux/srcutree.h +++ b/include/linux/srcutree.h @@ -240,7 +240,7 @@ static inline struct srcu_ctr __percpu *__srcu_ctr_to_ptr(struct srcu_struct *ss * on architectures that support NMIs but do not supply NMI-safe * implementations of this_cpu_inc(). */ -static inline struct srcu_ctr __percpu *__srcu_read_lock_fast(struct srcu_struct *ssp) +static inline struct srcu_ctr __percpu notrace *__srcu_read_lock_fast(struct srcu_struct *ssp) { struct srcu_ctr __percpu *scp = READ_ONCE(ssp->srcu_ctrp); @@ -267,7 +267,8 @@ static inline struct srcu_ctr __percpu *__srcu_read_lock_fast(struct srcu_struct * on architectures that support NMIs but do not supply NMI-safe * implementations of this_cpu_inc(). */ -static inline void __srcu_read_unlock_fast(struct srcu_struct *ssp, struct srcu_ctr __percpu *scp) +static inline void notrace +__srcu_read_unlock_fast(struct srcu_struct *ssp, struct srcu_ctr __percpu *scp) { barrier(); /* Avoid leaking the critical section. */ if (!IS_ENABLED(CONFIG_NEED_SRCU_NMI_SAFE)) From cacadb630375b8c30ca4d0300812178bb884c0b0 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 16 Jul 2025 09:19:39 -0700 Subject: [PATCH 0134/2711] srcu: Add guards for notrace variants of SRCU-fast readers This adds the usual scoped_guard(srcu_fast_notrace, &my_srcu) and guard(srcu_fast_notrace)(&my_srcu). Signed-off-by: Paul E. McKenney Reviewed-by: Joel Fernandes Cc: Mathieu Desnoyers Cc: Steven Rostedt Cc: Sebastian Andrzej Siewior Cc: --- include/linux/srcu.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/srcu.h b/include/linux/srcu.h index 7a692bf8f99b..ada65b58bc4c 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -515,4 +515,9 @@ DEFINE_LOCK_GUARD_1(srcu_fast, struct srcu_struct, srcu_read_unlock_fast(_T->lock, _T->scp), struct srcu_ctr __percpu *scp) +DEFINE_LOCK_GUARD_1(srcu_fast_notrace, struct srcu_struct, + _T->scp = srcu_read_lock_fast_notrace(_T->lock), + srcu_read_unlock_fast_notrace(_T->lock, _T->scp), + struct srcu_ctr __percpu *scp) + #endif From e95f6ccdbc71663b9f4b24a166e85bd8e6720318 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 10 Jul 2025 16:41:53 -0700 Subject: [PATCH 0135/2711] rcutorture: Fix jitter.sh spin time An embarrassing syntax error in jitter.sh makes for fixed spin time. This commit therefore makes it be variable, as intended, albeit with very coarse-grained adjustment. Signed-off-by: Paul E. McKenney --- .../selftests/rcutorture/bin/jitter.sh | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/jitter.sh b/tools/testing/selftests/rcutorture/bin/jitter.sh index fd1ffaa5a135..3c1e5d3f8805 100755 --- a/tools/testing/selftests/rcutorture/bin/jitter.sh +++ b/tools/testing/selftests/rcutorture/bin/jitter.sh @@ -39,6 +39,22 @@ do fi done +# Uses global variables startsecs, startns, endsecs, endns, and limit. +# Exit code is success for time not yet elapsed and failure otherwise. +function timecheck { + local done=`awk -v limit=$limit \ + -v startsecs=$startsecs \ + -v startns=$startns \ + -v endsecs=$endsecs \ + -v endns=$endns < /dev/null ' + BEGIN { + delta = (endsecs - startsecs) * 1000 * 1000; + delta += int((endns - startns) / 1000); + print delta >= limit; + }'` + return $done +} + while : do # Check for done. @@ -85,15 +101,20 @@ do n=$(($n+1)) sleep .$sleeptime - # Spin a random duration + # Spin a random duration, but with rather coarse granularity. limit=`awk -v me=$me -v n=$n -v spinmax=$spinmax 'BEGIN { srand(n + me + systime()); printf("%06d", int(rand() * spinmax)); }' < /dev/null` n=$(($n+1)) - for i in {1..$limit} + startsecs=`date +%s` + startns=`date +%N` + endsecs=$startns + endns=$endns + while timecheck do - echo > /dev/null + endsecs=`date +%s` + endns=`date +%N` done done From bd89367e05e8cf55eacf8627b0b3ed55b938d6fd Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 16 Jul 2025 09:10:35 -0700 Subject: [PATCH 0136/2711] torture: Add --do-normal parameter to torture.sh help text The --do-normal parameter was missing from the torture.sh script's help text, so this commit adds it. Hopefully better late than never! Signed-off-by: Paul E. McKenney --- tools/testing/selftests/rcutorture/bin/torture.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/rcutorture/bin/torture.sh b/tools/testing/selftests/rcutorture/bin/torture.sh index 611bc03a8dc7..a33ba109ef0b 100755 --- a/tools/testing/selftests/rcutorture/bin/torture.sh +++ b/tools/testing/selftests/rcutorture/bin/torture.sh @@ -94,6 +94,7 @@ usage () { echo " --do-kvfree / --do-no-kvfree / --no-kvfree" echo " --do-locktorture / --do-no-locktorture / --no-locktorture" echo " --do-none" + echo " --do-normal / --do-no-normal / --no-normal" echo " --do-rcuscale / --do-no-rcuscale / --no-rcuscale" echo " --do-rcutasksflavors / --do-no-rcutasksflavors / --no-rcutasksflavors" echo " --do-rcutorture / --do-no-rcutorture / --no-rcutorture" From b930ff84f3072df7ab3b0f1cd3a8bb5d02ec4dec Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 6 Aug 2025 15:59:32 -0700 Subject: [PATCH 0137/2711] torture: Announce kernel boot status at torture-test startup Sometimes a given system takes surprisingly long to boot, for example, in one recent case, 70 seconds instead of three seconds. It would be good to fix these slow-boot issues, but it would also be good for the torture tests to announce that the system was still booting at the start of the test. Especially for tests that have a greater probability of false positives when run in the single-CPU boot-time environment. Yes, those tests should defend themselves, but we should also make this situation easier to diagnose. This commit therefore causes torture_print_module_parms() to print "still booting" at the end of its printk() that dumps out the values of its module parameters. Signed-off-by: Paul E. McKenney --- kernel/torture.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/torture.c b/kernel/torture.c index 3a0a8cc60401..5abb4b25d971 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -797,8 +797,9 @@ static unsigned long torture_init_jiffies; static void torture_print_module_parms(void) { - pr_alert("torture module --- %s: disable_onoff_at_boot=%d ftrace_dump_at_shutdown=%d verbose_sleep_frequency=%d verbose_sleep_duration=%d random_shuffle=%d\n", - torture_type, disable_onoff_at_boot, ftrace_dump_at_shutdown, verbose_sleep_frequency, verbose_sleep_duration, random_shuffle); + pr_alert("torture module --- %s: disable_onoff_at_boot=%d ftrace_dump_at_shutdown=%d verbose_sleep_frequency=%d verbose_sleep_duration=%d random_shuffle=%d%s\n", + torture_type, disable_onoff_at_boot, ftrace_dump_at_shutdown, verbose_sleep_frequency, verbose_sleep_duration, random_shuffle, + rcu_inkernel_boot_has_ended() ? "" : " still booting"); } /* From 1b0f583843287275298a559c14e10769fd771cec Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 6 Aug 2025 16:07:33 -0700 Subject: [PATCH 0138/2711] rcutorture: Suppress "Writer stall state" reports during boot When rcutorture is running on only the one boot-time CPU while that CPU is busy invoking initcall() functions, the added load is quite likely to unduly delay the RCU grace-period kthread, rcutorture readers, and much else besides. This can result in rcu_torture_stats_print() reporting rcutorture writer stalls, which are not really a bug in that environment. After all, one CPU can only do so much. This commit therefore suppresses rcutorture writer stalls while the kernel is booting, that is, while rcu_inkernel_boot_has_ended() continues returning false. Signed-off-by: Paul E. McKenney --- kernel/rcu/rcutorture.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 7a893d51d02b..49e048da4f68 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -2756,7 +2756,8 @@ rcu_torture_stats_print(void) cur_ops->stats(); if (rtcv_snap == rcu_torture_current_version && rcu_access_pointer(rcu_torture_current) && - !rcu_stall_is_suppressed()) { + !rcu_stall_is_suppressed() && + rcu_inkernel_boot_has_ended()) { int __maybe_unused flags = 0; unsigned long __maybe_unused gp_seq = 0; From 9a316fe3adcac5655303958faef0e2cb1fedca1d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 6 Aug 2025 16:35:26 -0700 Subject: [PATCH 0139/2711] rcutorture: Delay rcutorture readers and writers until boot completes The rcutorture writers and (especially) readers are the biggest CPU hogs of the bunch, so this commit therefore makes them wait until boot has completed. This makes the current setting of the boot_ended local variable dead code, so while in the area, this commit removes that as well. Signed-off-by: Paul E. McKenney --- kernel/rcu/rcutorture.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 49e048da4f68..1578d3305657 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1528,7 +1528,7 @@ static void do_rtws_sync(struct torture_random_state *trsp, void (*sync)(void)) static int rcu_torture_writer(void *arg) { - bool boot_ended; + bool booting_still = false; bool can_expedite = !rcu_gp_is_expedited() && !rcu_gp_is_normal(); unsigned long cookie; struct rcu_gp_oldstate cookie_full; @@ -1539,6 +1539,7 @@ rcu_torture_writer(void *arg) struct rcu_gp_oldstate gp_snap1_full; int i; int idx; + unsigned long j; int oldnice = task_nice(current); struct rcu_gp_oldstate *rgo = NULL; int rgo_size = 0; @@ -1581,6 +1582,16 @@ rcu_torture_writer(void *arg) rgo_size = cur_ops->poll_active_full; } + // If the system is still booting, let it finish. + j = jiffies; + while (!torture_must_stop() && !rcu_inkernel_boot_has_ended()) { + booting_still = true; + schedule_timeout_interruptible(HZ); + } + if (booting_still) + pr_alert("%s" TORTURE_FLAG " Waited %lu jiffies for boot to complete.\n", + torture_type, jiffies - j); + do { rcu_torture_writer_state = RTWS_FIXED_DELAY; torture_hrtimeout_us(500, 1000, &rand); @@ -1769,13 +1780,11 @@ rcu_torture_writer(void *arg) !rcu_gp_is_normal(); } rcu_torture_writer_state = RTWS_STUTTER; - boot_ended = rcu_inkernel_boot_has_ended(); stutter_waited = stutter_wait("rcu_torture_writer"); if (stutter_waited && !atomic_read(&rcu_fwd_cb_nodelay) && !cur_ops->slow_gps && !torture_must_stop() && - boot_ended && time_after(jiffies, stallsdone)) for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) if (list_empty(&rcu_tortures[i].rtort_free) && @@ -2437,7 +2446,8 @@ rcu_torture_reader(void *arg) torture_hrtimeout_us(500, 1000, &rand); lastsleep = jiffies + 10; } - while (torture_num_online_cpus() < mynumonline && !torture_must_stop()) + while (!torture_must_stop() && + (torture_num_online_cpus() < mynumonline || !rcu_inkernel_boot_has_ended())) schedule_timeout_interruptible(HZ / 5); stutter_wait("rcu_torture_reader"); } while (!torture_must_stop()); From 6e9c48b3e34b8ade2e6881c8b1f3838f5c2ab804 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 13 Aug 2025 20:16:29 -0700 Subject: [PATCH 0140/2711] torture: Delay CPU-hotplug operations until boot completes CPU-hotplug operations invoke stop-machine, which can hog CPUs, which is not a great thing to do before boot has completed. This commit therefore makes the CPU-hotplug operations hold off until boot has completed. Signed-off-by: Paul E. McKenney --- kernel/torture.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/torture.c b/kernel/torture.c index 5abb4b25d971..1ea9f67953a7 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -359,6 +359,8 @@ torture_onoff(void *arg) torture_hrtimeout_jiffies(onoff_holdoff, &rand); VERBOSE_TOROUT_STRING("torture_onoff end holdoff"); } + while (!rcu_inkernel_boot_has_ended()) + schedule_timeout_interruptible(HZ / 10); while (!torture_must_stop()) { if (disable_onoff_at_boot && !rcu_inkernel_boot_has_ended()) { torture_hrtimeout_jiffies(HZ / 10, &rand); From 51c285baa3fa04b95843da8e2f9895138ea64dd4 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 13 Aug 2025 20:41:04 -0700 Subject: [PATCH 0141/2711] rcutorture: Delay forward-progress testing until boot completes Forward-progress testing can hog CPUs, which is not a great thing to do before boot has completed. This commit therefore makes the CPU-hotplug operations hold off until boot has completed. Signed-off-by: Paul E. McKenney --- kernel/rcu/rcutorture.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 1578d3305657..b8a684459381 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -3457,6 +3457,8 @@ static int rcu_torture_fwd_prog(void *args) int tested_tries = 0; VERBOSE_TOROUT_STRING("rcu_torture_fwd_progress task started"); + while (!rcu_inkernel_boot_has_ended()) + schedule_timeout_interruptible(HZ / 10); rcu_bind_current_to_nocb(); if (!IS_ENABLED(CONFIG_SMP) || !IS_ENABLED(CONFIG_RCU_BOOST)) set_user_nice(current, MAX_NICE); From f345a4798dab800159b09d088e7bdae0f16076c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:49 +0200 Subject: [PATCH 0142/2711] HID: pidff: Use direction fix only for conditional effects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The already fixed bug in SDL only affected conditional effects. This should fix FFB in Forza Horizion 4/5 on Moza Devices as Forza Horizon flips the constant force direction instead of using negative magnitude values. Changing the direction in the effect directly in pidff_upload_effect() would affect it's value in further operations like comparing to the old effect and/or just reading the effect values in the user application. This, in turn, would lead to constant PID_SET_EFFECT spam as the effect direction would constantly not match the value that's set by the application. This way, it's still transparent to any software/API. Only affects conditional effects now so it's better for it to explicitly state that in the name. If any HW ever needs fixed direction for other effects, we'll add more quirks. Signed-off-by: Tomasz Pakuła Reviewed-by: Oleg Makarenko Signed-off-by: Jiri Kosina --- drivers/hid/hid-universal-pidff.c | 20 ++++++++++---------- drivers/hid/usbhid/hid-pidff.c | 28 +++++++++++++++++++++++----- drivers/hid/usbhid/hid-pidff.h | 2 +- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/hid/hid-universal-pidff.c b/drivers/hid/hid-universal-pidff.c index 554a6559aeb7..70fce0f88e82 100644 --- a/drivers/hid/hid-universal-pidff.c +++ b/drivers/hid/hid-universal-pidff.c @@ -144,25 +144,25 @@ static int universal_pidff_input_configured(struct hid_device *hdev, static const struct hid_device_id universal_pidff_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3), - .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3_2), - .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5), - .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5_2), - .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9), - .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9_2), - .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12), - .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12_2), - .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21), - .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21_2), - .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C5) }, { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C12) }, { HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_DFP), diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 614a20b62023..c6b4f61e535d 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -205,6 +205,14 @@ struct pidff_device { u8 effect_count; }; +static int pidff_is_effect_conditional(struct ff_effect *effect) +{ + return effect->type == FF_SPRING || + effect->type == FF_DAMPER || + effect->type == FF_INERTIA || + effect->type == FF_FRICTION; +} + /* * Clamp value for a given field */ @@ -294,6 +302,20 @@ static void pidff_set_duration(struct pidff_usage *usage, u16 duration) pidff_set_time(usage, duration); } +static void pidff_set_effect_direction(struct pidff_device *pidff, + struct ff_effect *effect) +{ + u16 direction = effect->direction; + + /* Use fixed direction if needed */ + if (pidff->quirks & HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION && + pidff_is_effect_conditional(effect)) + direction = PIDFF_FIXED_WHEEL_DIRECTION; + + pidff->effect_direction->value[0] = + pidff_rescale(direction, U16_MAX, pidff->effect_direction); +} + /* * Send envelope report to the device */ @@ -395,11 +417,7 @@ static void pidff_set_effect_report(struct pidff_device *pidff, pidff->set_effect[PID_GAIN].field->logical_maximum; pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; - /* Use fixed direction if needed */ - pidff->effect_direction->value[0] = pidff_rescale( - pidff->quirks & HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION ? - PIDFF_FIXED_WHEEL_DIRECTION : effect->direction, - U16_MAX, pidff->effect_direction); + pidff_set_effect_direction(pidff, effect); /* Omit setting delay field if it's missing */ if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY)) diff --git a/drivers/hid/usbhid/hid-pidff.h b/drivers/hid/usbhid/hid-pidff.h index a53a8b436baa..f321f675e131 100644 --- a/drivers/hid/usbhid/hid-pidff.h +++ b/drivers/hid/usbhid/hid-pidff.h @@ -16,7 +16,7 @@ #define HID_PIDFF_QUIRK_PERMISSIVE_CONTROL BIT(2) /* Use fixed 0x4000 direction during SET_EFFECT report upload */ -#define HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION BIT(3) +#define HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION BIT(3) /* Force all periodic effects to be uploaded as SINE */ #define HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY BIT(4) From a02c78f708515b236086bf0a9ad4ac7884e78546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:50 +0200 Subject: [PATCH 0143/2711] HID: pidff: Remove unhelpful pidff_set_actuators helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Abstracts away too little of the functionality and replaces a nice, defined value with a magic bool. There's no actual need for it. Signed-off-by: Tomasz Pakuła Reviewed-by: Oleg Makarenko Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index c6b4f61e535d..3cf844f7ad4a 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -605,16 +605,6 @@ static void pidff_set_device_control(struct pidff_device *pidff, int field) hid_hw_wait(pidff->hid); } -/* - * Modify actuators state - */ -static void pidff_set_actuators(struct pidff_device *pidff, bool enable) -{ - hid_dbg(pidff->hid, "%s actuators\n", enable ? "Enable" : "Disable"); - pidff_set_device_control(pidff, - enable ? PID_ENABLE_ACTUATORS : PID_DISABLE_ACTUATORS); -} - /* * Reset the device, stop all effects, enable actuators */ @@ -626,7 +616,7 @@ static void pidff_reset(struct pidff_device *pidff) pidff->effect_count = 0; pidff_set_device_control(pidff, PID_STOP_ALL_EFFECTS); - pidff_set_actuators(pidff, 1); + pidff_set_device_control(pidff, PID_ENABLE_ACTUATORS); } /* From 6513cfdd838e18c9d2289b0d19474936e37ee5cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:51 +0200 Subject: [PATCH 0144/2711] HID: pidff: Remove unneeded debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the envelope settings work correctly and even if we wanted to debug something about the envelope report, we would not only need the attack level but it's length and fade properties to have a full image. Signed-off-by: Tomasz Pakuła Reviewed-by: Oleg Makarenko Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 3cf844f7ad4a..75fc6dbe435c 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -339,10 +339,6 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, pidff_set_time(&pidff->set_envelope[PID_FADE_TIME], envelope->fade_length); - hid_dbg(pidff->hid, "attack %u => %d\n", - envelope->attack_level, - pidff->set_envelope[PID_ATTACK_LEVEL].value[0]); - hid_hw_request(pidff->hid, pidff->reports[PID_SET_ENVELOPE], HID_REQ_SET_REPORT); } From 8de2cef6d0de8cdddee8d653a18791525af26fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:52 +0200 Subject: [PATCH 0145/2711] HID: pidff: Use ARRAY_SIZE macro instead of sizeof MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Could lead to issues when arrays won't be 8 bit fields Signed-off-by: Tomasz Pakuła Reviewed-by: Oleg Makarenko Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 75fc6dbe435c..2f9fbe4c52d7 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -158,20 +158,20 @@ struct pidff_usage { struct pidff_device { struct hid_device *hid; - struct hid_report *reports[sizeof(pidff_reports)]; + struct hid_report *reports[ARRAY_SIZE(pidff_reports)]; - struct pidff_usage set_effect[sizeof(pidff_set_effect)]; - struct pidff_usage set_envelope[sizeof(pidff_set_envelope)]; - struct pidff_usage set_condition[sizeof(pidff_set_condition)]; - struct pidff_usage set_periodic[sizeof(pidff_set_periodic)]; - struct pidff_usage set_constant[sizeof(pidff_set_constant)]; - struct pidff_usage set_ramp[sizeof(pidff_set_ramp)]; + struct pidff_usage set_effect[ARRAY_SIZE(pidff_set_effect)]; + struct pidff_usage set_envelope[ARRAY_SIZE(pidff_set_envelope)]; + struct pidff_usage set_condition[ARRAY_SIZE(pidff_set_condition)]; + struct pidff_usage set_periodic[ARRAY_SIZE(pidff_set_periodic)]; + struct pidff_usage set_constant[ARRAY_SIZE(pidff_set_constant)]; + struct pidff_usage set_ramp[ARRAY_SIZE(pidff_set_ramp)]; - struct pidff_usage device_gain[sizeof(pidff_device_gain)]; - struct pidff_usage block_load[sizeof(pidff_block_load)]; - struct pidff_usage pool[sizeof(pidff_pool)]; - struct pidff_usage effect_operation[sizeof(pidff_effect_operation)]; - struct pidff_usage block_free[sizeof(pidff_block_free)]; + struct pidff_usage device_gain[ARRAY_SIZE(pidff_device_gain)]; + struct pidff_usage block_load[ARRAY_SIZE(pidff_block_load)]; + struct pidff_usage pool[ARRAY_SIZE(pidff_pool)]; + struct pidff_usage effect_operation[ARRAY_SIZE(pidff_effect_operation)]; + struct pidff_usage block_free[ARRAY_SIZE(pidff_block_free)]; /* * Special field is a field that is not composed of @@ -194,10 +194,10 @@ struct pidff_device { /* Special field in effect_operation */ struct hid_field *effect_operation_status; - int control_id[sizeof(pidff_device_control)]; - int type_id[sizeof(pidff_effect_types)]; - int status_id[sizeof(pidff_block_load_status)]; - int operation_id[sizeof(pidff_effect_operation_status)]; + int control_id[ARRAY_SIZE(pidff_device_control)]; + int type_id[ARRAY_SIZE(pidff_effect_types)]; + int status_id[ARRAY_SIZE(pidff_block_load_status)]; + int operation_id[ARRAY_SIZE(pidff_effect_operation_status)]; int pid_id[PID_EFFECTS_MAX]; @@ -583,7 +583,7 @@ static void pidff_set_device_control(struct pidff_device *pidff, int field) hid_dbg(pidff->hid, "DEVICE_CONTROL is a bitmask\n"); /* Clear current bitmask */ - for (i = 0; i < sizeof(pidff_device_control); i++) { + for (i = 0; i < ARRAY_SIZE(pidff_device_control); i++) { index = pidff->control_id[i]; if (index < 1) continue; @@ -999,7 +999,7 @@ static int pidff_check_usage(int usage) { int i; - for (i = 0; i < sizeof(pidff_reports); i++) + for (i = 0; i < ARRAY_SIZE(pidff_reports); i++) if (usage == (HID_UP_PID | pidff_reports[i])) return i; @@ -1117,7 +1117,7 @@ static int pidff_find_special_keys(int *keys, struct hid_field *fld, #define PIDFF_FIND_SPECIAL_KEYS(keys, field, name) \ pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \ - sizeof(pidff_ ## name)) + ARRAY_SIZE(pidff_ ## name)) /* * Find and check the special fields @@ -1184,7 +1184,7 @@ static int pidff_find_special_fields(struct pidff_device *pidff) if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status, block_load_status) != - sizeof(pidff_block_load_status)) { + ARRAY_SIZE(pidff_block_load_status)) { hid_err(pidff->hid, "block load status identifiers not found\n"); return -1; @@ -1192,7 +1192,7 @@ static int pidff_find_special_fields(struct pidff_device *pidff) if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status, effect_operation_status) != - sizeof(pidff_effect_operation_status)) { + ARRAY_SIZE(pidff_effect_operation_status)) { hid_err(pidff->hid, "effect operation identifiers not found\n"); return -1; } @@ -1208,7 +1208,7 @@ static int pidff_find_effects(struct pidff_device *pidff, { int i; - for (i = 0; i < sizeof(pidff_effect_types); i++) { + for (i = 0; i < ARRAY_SIZE(pidff_effect_types); i++) { int pidff_type = pidff->type_id[i]; if (pidff->set_effect_type->usage[pidff_type].hid != @@ -1258,7 +1258,7 @@ static int pidff_find_effects(struct pidff_device *pidff, #define PIDFF_FIND_FIELDS(name, report, strict) \ pidff_find_fields(pidff->name, pidff_ ## name, \ pidff->reports[report], \ - sizeof(pidff_ ## name), strict) + ARRAY_SIZE(pidff_ ## name), strict) /* * Fill and check the pidff_usages From c7ad7812fb8c9319a5148b3c8f14b0b0b3d7e015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:53 +0200 Subject: [PATCH 0146/2711] HID: pidff: Treat PID_REQUIRED_REPORTS as count, not max MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's naming suggests it's a count of the records required by the USB PID standard and this driver. Signed-off-by: Tomasz Pakuła Reviewed-by: Oleg Makarenko Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 2f9fbe4c52d7..cff79e76c211 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -33,7 +33,7 @@ #define PID_DEVICE_CONTROL 6 #define PID_CREATE_NEW_EFFECT 7 -#define PID_REQUIRED_REPORTS 7 +#define PID_REQUIRED_REPORTS 8 #define PID_SET_ENVELOPE 8 #define PID_SET_CONDITION 9 @@ -1056,7 +1056,7 @@ static int pidff_reports_ok(struct pidff_device *pidff) { int i; - for (i = 0; i <= PID_REQUIRED_REPORTS; i++) { + for (i = 0; i < PID_REQUIRED_REPORTS; i++) { if (!pidff->reports[i]) { hid_dbg(pidff->hid, "%d missing\n", i); return 0; From 7f3d7bc0df4bdc23d31cf0f90b6e20c45129465e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:54 +0200 Subject: [PATCH 0147/2711] HID: pidff: Better quirk assigment when searching for fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assign quirks directly when they're discovered. Way easier to understand without relying on return values. Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 59 +++++++++++----------------------- 1 file changed, 18 insertions(+), 41 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index cff79e76c211..c88442a087f1 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -943,7 +943,8 @@ static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude) * Find fields from a report and fill a pidff_usage */ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, - struct hid_report *report, int count, int strict) + struct hid_report *report, int count, int strict, + u32 *quirks) { if (!report) { pr_debug("%s, null report\n", __func__); @@ -951,7 +952,6 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, } int i, j, k, found; - int return_value = 0; for (k = 0; k < count; k++) { found = 0; @@ -979,17 +979,17 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, if (!found && table[k] == pidff_set_effect[PID_START_DELAY]) { pr_debug("Delay field not found, but that's OK\n"); pr_debug("Setting MISSING_DELAY quirk\n"); - return_value |= HID_PIDFF_QUIRK_MISSING_DELAY; + *quirks |= HID_PIDFF_QUIRK_MISSING_DELAY; } else if (!found && table[k] == pidff_set_condition[PID_PARAM_BLOCK_OFFSET]) { pr_debug("PBO field not found, but that's OK\n"); pr_debug("Setting MISSING_PBO quirk\n"); - return_value |= HID_PIDFF_QUIRK_MISSING_PBO; + *quirks |= HID_PIDFF_QUIRK_MISSING_PBO; } else if (!found && strict) { pr_debug("failed to locate %d\n", k); return -1; } } - return return_value; + return 0; } /* @@ -1258,26 +1258,17 @@ static int pidff_find_effects(struct pidff_device *pidff, #define PIDFF_FIND_FIELDS(name, report, strict) \ pidff_find_fields(pidff->name, pidff_ ## name, \ pidff->reports[report], \ - ARRAY_SIZE(pidff_ ## name), strict) + ARRAY_SIZE(pidff_ ## name), strict, &pidff->quirks) /* * Fill and check the pidff_usages */ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) { - int status = 0; - - /* Save info about the device not having the DELAY ffb field. */ - status = PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1); - if (status == -1) { + if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) { hid_err(pidff->hid, "unknown set_effect report layout\n"); return -ENODEV; } - pidff->quirks |= status; - - if (status & HID_PIDFF_QUIRK_MISSING_DELAY) - hid_dbg(pidff->hid, "Adding MISSING_DELAY quirk\n"); - PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0); if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) { @@ -1311,39 +1302,25 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) "has periodic effect but no envelope\n"); } - if (test_bit(FF_CONSTANT, dev->ffbit) && - PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) { + if (PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1) && + test_and_clear_bit(FF_CONSTANT, dev->ffbit)) hid_warn(pidff->hid, "unknown constant effect layout\n"); - clear_bit(FF_CONSTANT, dev->ffbit); - } - if (test_bit(FF_RAMP, dev->ffbit) && - PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) { + if (PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1) && + test_and_clear_bit(FF_RAMP, dev->ffbit)) hid_warn(pidff->hid, "unknown ramp effect layout\n"); - clear_bit(FF_RAMP, dev->ffbit); - } - if (test_bit(FF_SPRING, dev->ffbit) || - test_bit(FF_DAMPER, dev->ffbit) || - test_bit(FF_FRICTION, dev->ffbit) || - test_bit(FF_INERTIA, dev->ffbit)) { - status = PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1); - - if (status < 0) { + if (PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) { + if (test_and_clear_bit(FF_SPRING, dev->ffbit) || + test_and_clear_bit(FF_DAMPER, dev->ffbit) || + test_and_clear_bit(FF_FRICTION, dev->ffbit) || + test_and_clear_bit(FF_INERTIA, dev->ffbit)) hid_warn(pidff->hid, "unknown condition effect layout\n"); - clear_bit(FF_SPRING, dev->ffbit); - clear_bit(FF_DAMPER, dev->ffbit); - clear_bit(FF_FRICTION, dev->ffbit); - clear_bit(FF_INERTIA, dev->ffbit); - } - pidff->quirks |= status; } - if (test_bit(FF_PERIODIC, dev->ffbit) && - PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) { + if (PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1) && + test_and_clear_bit(FF_PERIODIC, dev->ffbit)) hid_warn(pidff->hid, "unknown periodic effect layout\n"); - clear_bit(FF_PERIODIC, dev->ffbit); - } PIDFF_FIND_FIELDS(pool, PID_POOL, 0); From b974b372a9b0aa409ccf05dae8a267d4486f37b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:55 +0200 Subject: [PATCH 0148/2711] HID: pidff: Simplify HID field/usage searching logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some deduplication and splitting into separate functions. This is now way easier to comprehend and parse mentally. Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 105 +++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index c88442a087f1..2e8eac944be0 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -939,6 +939,43 @@ static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude) pidff_autocenter(dev->ff->private, magnitude); } +/* + * Find specific usage in a given hid_field + */ +static int pidff_find_usage(struct hid_field *fld, unsigned int usage_code) +{ + for (int i = 0; i < fld->maxusage; i++) { + if (fld->usage[i].hid == usage_code) + return i; + } + return -1; +} + +/* + * Find hid_field with a specific usage. Return the usage index as well + */ +static int pidff_find_field_with_usage(int *usage_index, + struct hid_report *report, + unsigned int usage_code) +{ + for (int i = 0; i < report->maxfield; i++) { + struct hid_field *fld = report->field[i]; + + if (fld->maxusage != fld->report_count) { + pr_debug("maxusage and report_count do not match, skipping\n"); + continue; + } + + int index = pidff_find_usage(fld, usage_code); + + if (index >= 0) { + *usage_index = index; + return i; + } + } + return -1; +} + /* * Find fields from a report and fill a pidff_usage */ @@ -946,46 +983,38 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, struct hid_report *report, int count, int strict, u32 *quirks) { + const u8 block_offset = pidff_set_condition[PID_PARAM_BLOCK_OFFSET]; + const u8 delay = pidff_set_effect[PID_START_DELAY]; + if (!report) { pr_debug("%s, null report\n", __func__); return -1; } - int i, j, k, found; + for (int i = 0; i < count; i++) { + int index; + int found = pidff_find_field_with_usage(&index, report, + HID_UP_PID | table[i]); - for (k = 0; k < count; k++) { - found = 0; - for (i = 0; i < report->maxfield; i++) { - if (report->field[i]->maxusage != - report->field[i]->report_count) { - pr_debug("maxusage and report_count do not match, skipping\n"); - continue; - } - for (j = 0; j < report->field[i]->maxusage; j++) { - if (report->field[i]->usage[j].hid == - (HID_UP_PID | table[k])) { - pr_debug("found %d at %d->%d\n", - k, i, j); - usage[k].field = report->field[i]; - usage[k].value = - &report->field[i]->value[j]; - found = 1; - break; - } - } - if (found) - break; + if (found >= 0) { + pr_debug("found %d at %d->%d\n", i, found, index); + usage[i].field = report->field[found]; + usage[i].value = &report->field[found]->value[index]; + continue; } - if (!found && table[k] == pidff_set_effect[PID_START_DELAY]) { + + if (table[i] == delay) { pr_debug("Delay field not found, but that's OK\n"); pr_debug("Setting MISSING_DELAY quirk\n"); *quirks |= HID_PIDFF_QUIRK_MISSING_DELAY; - } else if (!found && table[k] == pidff_set_condition[PID_PARAM_BLOCK_OFFSET]) { + + } else if (table[i] == block_offset) { pr_debug("PBO field not found, but that's OK\n"); pr_debug("Setting MISSING_PBO quirk\n"); *quirks |= HID_PIDFF_QUIRK_MISSING_PBO; - } else if (!found && strict) { - pr_debug("failed to locate %d\n", k); + + } else if (strict) { + pr_debug("failed to locate %d\n", i); return -1; } } @@ -1054,9 +1083,7 @@ static void pidff_find_reports(struct hid_device *hid, int report_type, */ static int pidff_reports_ok(struct pidff_device *pidff) { - int i; - - for (i = 0; i < PID_REQUIRED_REPORTS; i++) { + for (int i = 0; i < PID_REQUIRED_REPORTS; i++) { if (!pidff->reports[i]) { hid_dbg(pidff->hid, "%d missing\n", i); return 0; @@ -1077,9 +1104,7 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report, return NULL; } - int i; - - for (i = 0; i < report->maxfield; i++) { + for (int i = 0; i < report->maxfield; i++) { if (report->field[i]->logical == (HID_UP_PID | usage) && report->field[i]->report_count > 0) { if (!enforce_min || @@ -1099,18 +1124,12 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report, static int pidff_find_special_keys(int *keys, struct hid_field *fld, const u8 *usagetable, int count) { - - int i, j; int found = 0; - for (i = 0; i < count; i++) { - for (j = 0; j < fld->maxusage; j++) { - if (fld->usage[j].hid == (HID_UP_PID | usagetable[i])) { - keys[i] = j + 1; - found++; - break; - } - } + for (int i = 0; i < count; i++) { + keys[i] = pidff_find_usage(fld, HID_UP_PID | usagetable[i]) + 1; + if (keys[i]) + found++; } return found; } From 1d72e7bd340b552160df0baca1a85fd1992abe49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:56 +0200 Subject: [PATCH 0149/2711] HID: pidff: Add support for AXES_ENABLE field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AXES_ENABLE can be used in place of DIRECTION_ENABLE to indicate, which FFB-enabled axes will be affected by a given effect. EFFECT_DIRECTION enables all and uses the first direction only while AXES_ENABLE is a bitmask and bit indexes are the same as the defined GD usages in the EFFECT_DIRECTION array. Each axis can have it's own direction in this case. Search for AXES_ENABLE, set AXES_ENABLE for all axes if DIRECTION_ENABLE is not used. Search for specific axes in the direction array. Save their indexes. This let us know what axes are actually available on the device and which bit in the AXES_ENABLE field corresponds to which axis. Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 91 ++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 2e8eac944be0..0f49d2836e9e 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -51,6 +51,7 @@ static const u8 pidff_reports[] = { /* PID special fields */ #define PID_EFFECT_TYPE 0x25 +#define PID_AXES_ENABLE 0x55 #define PID_DIRECTION 0x57 #define PID_EFFECT_OPERATION_ARRAY 0x78 #define PID_BLOCK_LOAD_STATUS 0x8b @@ -150,6 +151,31 @@ static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b }; /* Polar direction 90 degrees (East) */ #define PIDFF_FIXED_WHEEL_DIRECTION 0x4000 +/* AXES_ENABLE and DIRECTION axes */ +enum pid_axes { + PID_AXIS_X, + PID_AXIS_Y, + PID_AXIS_Z, + PID_AXIS_RX, + PID_AXIS_RY, + PID_AXIS_RZ, + PID_AXIS_SLIDER, + PID_AXIS_DIAL, + PID_AXIS_WHEEL, + PID_AXES_COUNT, +}; +static const u8 pidff_direction_axis[] = { + HID_USAGE & HID_GD_X, + HID_USAGE & HID_GD_Y, + HID_USAGE & HID_GD_Z, + HID_USAGE & HID_GD_RX, + HID_USAGE & HID_GD_RY, + HID_USAGE & HID_GD_RZ, + HID_USAGE & HID_GD_SLIDER, + HID_USAGE & HID_GD_DIAL, + HID_USAGE & HID_GD_WHEEL, +}; + struct pidff_usage { struct hid_field *field; s32 *value; @@ -184,6 +210,7 @@ struct pidff_device { /* Special fields in set_effect */ struct hid_field *set_effect_type; struct hid_field *effect_direction; + struct hid_field *axes_enable; /* Special field in device_control */ struct hid_field *device_control; @@ -198,11 +225,13 @@ struct pidff_device { int type_id[ARRAY_SIZE(pidff_effect_types)]; int status_id[ARRAY_SIZE(pidff_block_load_status)]; int operation_id[ARRAY_SIZE(pidff_effect_operation_status)]; + int direction_axis_id[ARRAY_SIZE(pidff_direction_axis)]; int pid_id[PID_EFFECTS_MAX]; u32 quirks; u8 effect_count; + u8 axis_count; }; static int pidff_is_effect_conditional(struct ff_effect *effect) @@ -306,14 +335,37 @@ static void pidff_set_effect_direction(struct pidff_device *pidff, struct ff_effect *effect) { u16 direction = effect->direction; + int direction_enable = 1; /* Use fixed direction if needed */ if (pidff->quirks & HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION && pidff_is_effect_conditional(effect)) direction = PIDFF_FIXED_WHEEL_DIRECTION; + pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = direction_enable; pidff->effect_direction->value[0] = pidff_rescale(direction, U16_MAX, pidff->effect_direction); + + if (direction_enable) + return; + + /* + * For use with improved FFB API + * We want to read the selected axes and their direction from the effect + * struct and only enable those. For now, enable all axes. + * + */ + for (int i = 0; i < PID_AXES_COUNT; i++) { + /* HID index starts with 1 */ + int index = pidff->direction_axis_id[i] - 1; + + if (index < 0) + continue; + + pidff->axes_enable->value[index] = 1; + pidff->effect_direction->value[index] = pidff_rescale( + direction, U16_MAX, pidff->effect_direction); + } } /* @@ -411,7 +463,6 @@ static void pidff_set_effect_report(struct pidff_device *pidff, effect->trigger.interval); pidff->set_effect[PID_GAIN].value[0] = pidff->set_effect[PID_GAIN].field->logical_maximum; - pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; pidff_set_effect_direction(pidff, effect); @@ -1122,12 +1173,13 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report, * Fill a pidff->*_id struct table */ static int pidff_find_special_keys(int *keys, struct hid_field *fld, - const u8 *usagetable, int count) + const u8 *usagetable, int count, + unsigned int usage_page) { int found = 0; for (int i = 0; i < count; i++) { - keys[i] = pidff_find_usage(fld, HID_UP_PID | usagetable[i]) + 1; + keys[i] = pidff_find_usage(fld, usage_page | usagetable[i]) + 1; if (keys[i]) found++; } @@ -1136,7 +1188,11 @@ static int pidff_find_special_keys(int *keys, struct hid_field *fld, #define PIDFF_FIND_SPECIAL_KEYS(keys, field, name) \ pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \ - ARRAY_SIZE(pidff_ ## name)) + ARRAY_SIZE(pidff_ ## name), HID_UP_PID) + +#define PIDFF_FIND_GENERAL_DESKTOP(keys, field, name) \ + pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \ + ARRAY_SIZE(pidff_ ## name), HID_UP_GENDESK) /* * Find and check the special fields @@ -1151,6 +1207,9 @@ static int pidff_find_special_fields(struct pidff_device *pidff) pidff->set_effect_type = pidff_find_special_field(pidff->reports[PID_SET_EFFECT], PID_EFFECT_TYPE, 1); + pidff->axes_enable = + pidff_find_special_field(pidff->reports[PID_SET_EFFECT], + PID_AXES_ENABLE, 0); pidff->effect_direction = pidff_find_special_field(pidff->reports[PID_SET_EFFECT], PID_DIRECTION, 0); @@ -1216,6 +1275,30 @@ static int pidff_find_special_fields(struct pidff_device *pidff) return -1; } + if (!pidff->axes_enable) + hid_info(pidff->hid, "axes enable field not found!\n"); + else + hid_dbg(pidff->hid, "axes enable report count: %u\n", + pidff->axes_enable->report_count); + + uint found = PIDFF_FIND_GENERAL_DESKTOP(direction_axis_id, axes_enable, + direction_axis); + + pidff->axis_count = found; + hid_dbg(pidff->hid, "found direction axes: %u", found); + + for (int i = 0; i < sizeof(pidff_direction_axis); i++) { + if (!pidff->direction_axis_id[i]) + continue; + + hid_dbg(pidff->hid, "axis %d, usage: 0x%04x, index: %d", i + 1, + pidff_direction_axis[i], pidff->direction_axis_id[i]); + } + + if (pidff->axes_enable && found != pidff->axes_enable->report_count) + hid_warn(pidff->hid, "axes_enable: %u != direction axes: %u", + pidff->axes_enable->report_count, found); + return 0; } From 1abfcd86e38c3466acefd0069bf6b3c2514fb886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:57 +0200 Subject: [PATCH 0150/2711] HID: pidff: Update debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomasz Pakuła Better indicate what operation is requested on a given effect (play or stop). Previously, we only had the info about requesting playback but this could be misleading when the looop count is 0. Add debug print that shows what device control command was actually sent to the device. Print out its hex hid usage. Make field_index const to make sure it won't be changed by mistake later. Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 0f49d2836e9e..689419b20bf0 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -623,8 +623,7 @@ static void pidff_set_gain_report(struct pidff_device *pidff, u16 gain) */ static void pidff_set_device_control(struct pidff_device *pidff, int field) { - int i, index; - int field_index = pidff->control_id[field]; + const int field_index = pidff->control_id[field]; if (field_index < 1) return; @@ -634,8 +633,9 @@ static void pidff_set_device_control(struct pidff_device *pidff, int field) hid_dbg(pidff->hid, "DEVICE_CONTROL is a bitmask\n"); /* Clear current bitmask */ - for (i = 0; i < ARRAY_SIZE(pidff_device_control); i++) { - index = pidff->control_id[i]; + for (int i = 0; i < ARRAY_SIZE(pidff_device_control); i++) { + int index = pidff->control_id[i]; + if (index < 1) continue; @@ -650,6 +650,8 @@ static void pidff_set_device_control(struct pidff_device *pidff, int field) hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); hid_hw_wait(pidff->hid); + hid_dbg(pidff->hid, "Device control command 0x%02x sent", + pidff_device_control[field]); } /* @@ -751,6 +753,9 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) { pidff->effect_operation[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; + hid_dbg(pidff->hid, "%s PID effect %d", n == 0 ? "stopping" : "playing", + pid_id); + if (n == 0) { pidff->effect_operation_status->value[0] = pidff->operation_id[PID_EFFECT_STOP]; @@ -772,6 +777,8 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value) { struct pidff_device *pidff = dev->ff->private; + hid_dbg(pidff->hid, "requesting %s on FF effect %d", + value == 0 ? "stop" : "playback", effect_id); pidff_playback_pid(pidff, pidff->pid_id[effect_id], value); return 0; } From 7fbaa031b94182a9c9e58310935a2f74265ef78d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:58 +0200 Subject: [PATCH 0151/2711] HID: pidff: Rework pidff_upload_effect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One of the more complicated functions. Expunge some of the logic to separate functions (FF -> PID id conversion) Add a macro for envelope check to make it more readable in the upload function. All this made it possible to to expunge common code from the big switch statement and reduce the overall function size considerably. Now it can fit on one screen. Move the effect_cout logic from report functions to upload/erase functions. Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 243 ++++++++++++++++----------------- 1 file changed, 115 insertions(+), 128 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 689419b20bf0..32d42792c95a 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -142,7 +142,7 @@ static const u8 pidff_effect_types[] = { #define PID_BLOCK_LOAD_SUCCESS 0 #define PID_BLOCK_LOAD_FULL 1 #define PID_BLOCK_LOAD_ERROR 2 -static const u8 pidff_block_load_status[] = { 0x8c, 0x8d, 0x8e}; +static const u8 pidff_block_load_status[] = { 0x8c, 0x8d, 0x8e }; #define PID_EFFECT_START 0 #define PID_EFFECT_STOP 1 @@ -242,6 +242,62 @@ static int pidff_is_effect_conditional(struct ff_effect *effect) effect->type == FF_FRICTION; } +/* + * Get PID effect index from FF effect type. + * Return 0 if invalid. + */ +static int pidff_effect_ff_to_pid(struct ff_effect *effect) +{ + switch (effect->type) { + case FF_CONSTANT: + return PID_CONSTANT; + case FF_RAMP: + return PID_RAMP; + case FF_SPRING: + return PID_SPRING; + case FF_DAMPER: + return PID_DAMPER; + case FF_INERTIA: + return PID_INERTIA; + case FF_FRICTION: + return PID_FRICTION; + case FF_PERIODIC: + switch (effect->u.periodic.waveform) { + case FF_SQUARE: + return PID_SQUARE; + case FF_TRIANGLE: + return PID_TRIANGLE; + case FF_SINE: + return PID_SINE; + case FF_SAW_UP: + return PID_SAW_UP; + case FF_SAW_DOWN: + return PID_SAW_DOWN; + } + } + pr_err("invalid effect type\n"); + return -EINVAL; +} + +/* + * Get effect id in the device descriptor. + * Return 0 if invalid. + */ +static int pidff_get_effect_type_id(struct pidff_device *pidff, + struct ff_effect *effect) +{ + int id = pidff_effect_ff_to_pid(effect); + + if (id < 0) + return 0; + + if (effect->type == FF_PERIODIC && + pidff->quirks & HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY) + id = PID_SINE; + + return pidff->type_id[id]; +} + /* * Clamp value for a given field */ @@ -387,12 +443,12 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, pidff->set_envelope[PID_FADE_LEVEL].field); pidff_set_time(&pidff->set_envelope[PID_ATTACK_TIME], - envelope->attack_length); + envelope->attack_length); pidff_set_time(&pidff->set_envelope[PID_FADE_TIME], - envelope->fade_length); + envelope->fade_length); hid_hw_request(pidff->hid, pidff->reports[PID_SET_ENVELOPE], - HID_REQ_SET_REPORT); + HID_REQ_SET_REPORT); } /* @@ -401,7 +457,7 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, static int pidff_needs_set_envelope(struct ff_envelope *envelope, struct ff_envelope *old) { - bool needs_new_envelope; + int needs_new_envelope; needs_new_envelope = envelope->attack_level != 0 || envelope->fade_level != 0 || @@ -409,8 +465,7 @@ static int pidff_needs_set_envelope(struct ff_envelope *envelope, envelope->fade_length != 0; if (!needs_new_envelope) - return false; - + return 0; if (!old) return needs_new_envelope; @@ -423,8 +478,8 @@ static int pidff_needs_set_envelope(struct ff_envelope *envelope, /* * Send constant force report to the device */ -static void pidff_set_constant_force_report(struct pidff_device *pidff, - struct ff_effect *effect) +static void pidff_set_constant_report(struct pidff_device *pidff, + struct ff_effect *effect) { pidff->set_constant[PID_EFFECT_BLOCK_INDEX].value[0] = pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; @@ -432,7 +487,7 @@ static void pidff_set_constant_force_report(struct pidff_device *pidff, effect->u.constant.level); hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONSTANT], - HID_REQ_SET_REPORT); + HID_REQ_SET_REPORT); } /* @@ -583,8 +638,8 @@ static int pidff_needs_set_condition(struct ff_effect *effect, /* * Send ramp force report to the device */ -static void pidff_set_ramp_force_report(struct pidff_device *pidff, - struct ff_effect *effect) +static void pidff_set_ramp_report(struct pidff_device *pidff, + struct ff_effect *effect) { pidff->set_ramp[PID_EFFECT_BLOCK_INDEX].value[0] = pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; @@ -593,7 +648,7 @@ static void pidff_set_ramp_force_report(struct pidff_device *pidff, pidff_set_signed(&pidff->set_ramp[PID_RAMP_END], effect->u.ramp.end_level); hid_hw_request(pidff->hid, pidff->reports[PID_SET_RAMP], - HID_REQ_SET_REPORT); + HID_REQ_SET_REPORT); } /* @@ -703,9 +758,6 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) { int j; - if (!pidff->effect_count) - pidff_reset(pidff); - pidff->create_new_effect_type->value[0] = efnum; hid_hw_request(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], HID_REQ_SET_REPORT); @@ -725,8 +777,6 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) hid_dbg(pidff->hid, "device reported free memory: %d bytes\n", pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); - - pidff->effect_count++; return 0; } if (pidff->block_load_status->value[0] == @@ -767,7 +817,7 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) } hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], - HID_REQ_SET_REPORT); + HID_REQ_SET_REPORT); } /* @@ -791,10 +841,7 @@ static void pidff_erase_pid(struct pidff_device *pidff, int pid_id) { pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_FREE], - HID_REQ_SET_REPORT); - - if (pidff->effect_count > 0) - pidff->effect_count--; + HID_REQ_SET_REPORT); } /* @@ -816,139 +863,79 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id) pidff_playback_pid(pidff, pid_id, 0); pidff_erase_pid(pidff, pid_id); + if (pidff->effect_count > 0) + pidff->effect_count--; + + hid_dbg(pidff->hid, "current effect count: %d", pidff->effect_count); return 0; } +#define PIDFF_SET_REPORT_IF_NEEDED(type, effect, old) \ + ({ if (!old || pidff_needs_set_## type(effect, old)) \ + pidff_set_ ##type## _report(pidff, effect); }) + +#define PIDFF_SET_ENVELOPE_IF_NEEDED(type, effect, old) \ + ({ if (pidff_needs_set_envelope(&effect->u.type.envelope, \ + old ? &old->u.type.envelope : NULL)) \ + pidff_set_envelope_report(pidff, &effect->u.type.envelope); }) + /* * Effect upload handler */ -static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, +static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *new, struct ff_effect *old) { struct pidff_device *pidff = dev->ff->private; - int type_id; - int error; + const int type_id = pidff_get_effect_type_id(pidff, new); - pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0; - if (old) { - pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = - pidff->pid_id[effect->id]; + if (!type_id) { + hid_err(pidff->hid, "effect type not supported\n"); + return -EINVAL; } - switch (effect->type) { + if (!pidff->effect_count) + pidff_reset(pidff); + + if (!old) { + int error = pidff_request_effect_upload(pidff, type_id); + + if (error) + return error; + + pidff->effect_count++; + hid_dbg(pidff->hid, "current effect count: %d", pidff->effect_count); + pidff->pid_id[new->id] = + pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; + } + + pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = + pidff->pid_id[new->id]; + + PIDFF_SET_REPORT_IF_NEEDED(effect, new, old); + switch (new->type) { case FF_CONSTANT: - if (!old) { - error = pidff_request_effect_upload(pidff, - pidff->type_id[PID_CONSTANT]); - if (error) - return error; - } - if (!old || pidff_needs_set_effect(effect, old)) - pidff_set_effect_report(pidff, effect); - if (!old || pidff_needs_set_constant(effect, old)) - pidff_set_constant_force_report(pidff, effect); - if (pidff_needs_set_envelope(&effect->u.constant.envelope, - old ? &old->u.constant.envelope : NULL)) - pidff_set_envelope_report(pidff, &effect->u.constant.envelope); + PIDFF_SET_REPORT_IF_NEEDED(constant, new, old); + PIDFF_SET_ENVELOPE_IF_NEEDED(constant, new, old); break; case FF_PERIODIC: - if (!old) { - switch (effect->u.periodic.waveform) { - case FF_SQUARE: - type_id = PID_SQUARE; - break; - case FF_TRIANGLE: - type_id = PID_TRIANGLE; - break; - case FF_SINE: - type_id = PID_SINE; - break; - case FF_SAW_UP: - type_id = PID_SAW_UP; - break; - case FF_SAW_DOWN: - type_id = PID_SAW_DOWN; - break; - default: - hid_err(pidff->hid, "invalid waveform\n"); - return -EINVAL; - } - - if (pidff->quirks & HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY) - type_id = PID_SINE; - - error = pidff_request_effect_upload(pidff, - pidff->type_id[type_id]); - if (error) - return error; - } - if (!old || pidff_needs_set_effect(effect, old)) - pidff_set_effect_report(pidff, effect); - if (!old || pidff_needs_set_periodic(effect, old)) - pidff_set_periodic_report(pidff, effect); - if (pidff_needs_set_envelope(&effect->u.periodic.envelope, - old ? &old->u.periodic.envelope : NULL)) - pidff_set_envelope_report(pidff, &effect->u.periodic.envelope); + PIDFF_SET_REPORT_IF_NEEDED(periodic, new, old); + PIDFF_SET_ENVELOPE_IF_NEEDED(periodic, new, old); break; case FF_RAMP: - if (!old) { - error = pidff_request_effect_upload(pidff, - pidff->type_id[PID_RAMP]); - if (error) - return error; - } - if (!old || pidff_needs_set_effect(effect, old)) - pidff_set_effect_report(pidff, effect); - if (!old || pidff_needs_set_ramp(effect, old)) - pidff_set_ramp_force_report(pidff, effect); - if (pidff_needs_set_envelope(&effect->u.ramp.envelope, - old ? &old->u.ramp.envelope : NULL)) - pidff_set_envelope_report(pidff, &effect->u.ramp.envelope); + PIDFF_SET_REPORT_IF_NEEDED(ramp, new, old); + PIDFF_SET_ENVELOPE_IF_NEEDED(ramp, new, old); break; case FF_SPRING: case FF_DAMPER: case FF_INERTIA: case FF_FRICTION: - if (!old) { - switch (effect->type) { - case FF_SPRING: - type_id = PID_SPRING; - break; - case FF_DAMPER: - type_id = PID_DAMPER; - break; - case FF_INERTIA: - type_id = PID_INERTIA; - break; - case FF_FRICTION: - type_id = PID_FRICTION; - break; - } - error = pidff_request_effect_upload(pidff, - pidff->type_id[type_id]); - if (error) - return error; - } - if (!old || pidff_needs_set_effect(effect, old)) - pidff_set_effect_report(pidff, effect); - if (!old || pidff_needs_set_condition(effect, old)) - pidff_set_condition_report(pidff, effect); + PIDFF_SET_REPORT_IF_NEEDED(condition, new, old); break; - - default: - hid_err(pidff->hid, "invalid type\n"); - return -EINVAL; } - - if (!old) - pidff->pid_id[effect->id] = - pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; - hid_dbg(pidff->hid, "uploaded\n"); - return 0; } From c774a9d78dba045e6d044e7a7e4fbb6deb0e9cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:09:59 +0200 Subject: [PATCH 0152/2711] HID: pidff: Separate check for infinite duration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will be used in a few more places so this makes sure it will always work the same. Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 32d42792c95a..534fb28f6e55 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -242,6 +242,11 @@ static int pidff_is_effect_conditional(struct ff_effect *effect) effect->type == FF_FRICTION; } +static int pidff_is_duration_infinite(u16 duration) +{ + return duration == FF_INFINITE || duration == PID_INFINITE; +} + /* * Get PID effect index from FF effect type. * Return 0 if invalid. @@ -374,12 +379,8 @@ static void pidff_set_time(struct pidff_usage *usage, u16 time) static void pidff_set_duration(struct pidff_usage *usage, u16 duration) { - /* Infinite value conversion from Linux API -> PID */ - if (duration == FF_INFINITE) - duration = PID_INFINITE; - /* PID defines INFINITE as the max possible value for duration field */ - if (duration == PID_INFINITE) { + if (pidff_is_duration_infinite(duration)) { usage->value[0] = (1U << usage->field->report_size) - 1; return; } From c2dc9f0b368c08c34674311cf78407718d5715a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:10:00 +0200 Subject: [PATCH 0153/2711] HID: pidff: PERMISSIVE_CONTROL quirk autodetection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes force feedback for devices built with MMOS firmware and many more not yet detected devices. Update quirks mask debug message to always contain all 32 bits of data. Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 534fb28f6e55..3fd51ad5cf56 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -1210,8 +1210,16 @@ static int pidff_find_special_fields(struct pidff_device *pidff) PID_DIRECTION, 0); pidff->device_control = pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL], - PID_DEVICE_CONTROL_ARRAY, - !(pidff->quirks & HID_PIDFF_QUIRK_PERMISSIVE_CONTROL)); + PID_DEVICE_CONTROL_ARRAY, 1); + + /* Detect and set permissive control quirk */ + if (!pidff->device_control) { + pr_debug("Setting PERMISSIVE_CONTROL quirk\n"); + pidff->quirks |= HID_PIDFF_QUIRK_PERMISSIVE_CONTROL; + pidff->device_control = pidff_find_special_field( + pidff->reports[PID_DEVICE_CONTROL], + PID_DEVICE_CONTROL_ARRAY, 0); + } pidff->block_load_status = pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD], @@ -1552,7 +1560,7 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks) ff->playback = pidff_playback; hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula \n"); - hid_dbg(dev, "Active quirks mask: 0x%x\n", pidff->quirks); + hid_dbg(dev, "Active quirks mask: 0x%08x\n", pidff->quirks); hid_device_io_stop(hid); From 82b2496227337b4651f32f336645ccc4c14054a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:10:01 +0200 Subject: [PATCH 0154/2711] HID: pidff: Remove Anssi's email address from info msg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some users might try to contact him about issues and he's no longer active when it comes to the driver development/fixes. Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 3fd51ad5cf56..ebebac5c4384 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -1559,7 +1559,7 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks) ff->set_autocenter = pidff_set_autocenter; ff->playback = pidff_playback; - hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula \n"); + hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula\n"); hid_dbg(dev, "Active quirks mask: 0x%08x\n", pidff->quirks); hid_device_io_stop(hid); From 63cc21dd8be7cff663309750bb609d5b2e888c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:10:02 +0200 Subject: [PATCH 0155/2711] HID: pidff: Define all cardinal directions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Will be used by ff-effect based autocentering Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index ebebac5c4384..7f4c1186a44d 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -148,8 +148,12 @@ static const u8 pidff_block_load_status[] = { 0x8c, 0x8d, 0x8e }; #define PID_EFFECT_STOP 1 static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b }; -/* Polar direction 90 degrees (East) */ -#define PIDFF_FIXED_WHEEL_DIRECTION 0x4000 +#define PID_DIRECTION_NORTH 0x0000 +#define PID_DIRECTION_EAST 0x4000 +#define PID_DIRECTION_SOUTH 0x8000 +#define PID_DIRECTION_WEST 0xc000 + +#define PIDFF_FIXED_WHEEL_DIRECTION PID_DIRECTION_EAST /* AXES_ENABLE and DIRECTION axes */ enum pid_axes { From ae42428fb4e3d2eed344f0d6fcfa778bc8b8f80a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:10:03 +0200 Subject: [PATCH 0156/2711] HID: pidff: clang-format pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 55 ++++++++++++++++------------------ 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 7f4c1186a44d..50a8924edfcc 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -9,12 +9,11 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "hid-pidff.h" +#include #include +#include #include #include -#include -#include - #define PID_EFFECTS_MAX 64 #define PID_INFINITE U16_MAX @@ -321,7 +320,7 @@ static s32 pidff_clamp(s32 i, struct hid_field *field) static int pidff_rescale(int i, int max, struct hid_field *field) { return i * (field->logical_maximum - field->logical_minimum) / max + - field->logical_minimum; + field->logical_minimum; } /* @@ -367,18 +366,18 @@ static void pidff_set_signed(struct pidff_usage *usage, s16 value) else { if (value < 0) usage->value[0] = - pidff_rescale(-value, -S16_MIN, usage->field); + pidff_rescale(-value, -S16_MIN, usage->field); else usage->value[0] = - pidff_rescale(value, S16_MAX, usage->field); + pidff_rescale(value, S16_MAX, usage->field); } pr_debug("calculated from %d to %d\n", value, usage->value[0]); } static void pidff_set_time(struct pidff_usage *usage, u16 time) { - usage->value[0] = pidff_clamp( - pidff_rescale_time(time, usage->field), usage->field); + usage->value[0] = pidff_clamp(pidff_rescale_time(time, usage->field), + usage->field); } static void pidff_set_duration(struct pidff_usage *usage, u16 duration) @@ -516,11 +515,11 @@ static void pidff_set_effect_report(struct pidff_device *pidff, pidff->create_new_effect_type->value[0]; pidff_set_duration(&pidff->set_effect[PID_DURATION], - effect->replay.length); + effect->replay.length); pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button; pidff_set_time(&pidff->set_effect[PID_TRIGGER_REPEAT_INT], - effect->trigger.interval); + effect->trigger.interval); pidff->set_effect[PID_GAIN].value[0] = pidff->set_effect[PID_GAIN].field->logical_maximum; @@ -529,10 +528,10 @@ static void pidff_set_effect_report(struct pidff_device *pidff, /* Omit setting delay field if it's missing */ if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY)) pidff_set_time(&pidff->set_effect[PID_START_DELAY], - effect->replay.delay); + effect->replay.delay); hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT], - HID_REQ_SET_REPORT); + HID_REQ_SET_REPORT); } /* @@ -562,10 +561,10 @@ static void pidff_set_periodic_report(struct pidff_device *pidff, effect->u.periodic.offset); pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase); pidff_set_time(&pidff->set_periodic[PID_PERIOD], - effect->u.periodic.period); + effect->u.periodic.period); hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC], - HID_REQ_SET_REPORT); + HID_REQ_SET_REPORT); } /* @@ -612,7 +611,7 @@ static void pidff_set_condition_report(struct pidff_device *pidff, pidff_set(&pidff->set_condition[PID_DEAD_BAND], effect->u.condition[i].deadband); hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONDITION], - HID_REQ_SET_REPORT); + HID_REQ_SET_REPORT); } } @@ -675,7 +674,7 @@ static void pidff_set_gain_report(struct pidff_device *pidff, u16 gain) pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN], - HID_REQ_SET_REPORT); + HID_REQ_SET_REPORT); } /* @@ -761,21 +760,19 @@ static void pidff_fetch_pool(struct pidff_device *pidff) */ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) { - int j; - pidff->create_new_effect_type->value[0] = efnum; hid_hw_request(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], - HID_REQ_SET_REPORT); + HID_REQ_SET_REPORT); hid_dbg(pidff->hid, "create_new_effect sent, type: %d\n", efnum); pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0; pidff->block_load_status->value[0] = 0; hid_hw_wait(pidff->hid); - for (j = 0; j < 60; j++) { + for (int i = 0; i < 60; i++) { hid_dbg(pidff->hid, "pid_block_load requested\n"); hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_LOAD], - HID_REQ_GET_REPORT); + HID_REQ_GET_REPORT); hid_hw_wait(pidff->hid); if (pidff->block_load_status->value[0] == pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) { @@ -857,8 +854,8 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id) struct pidff_device *pidff = dev->ff->private; int pid_id = pidff->pid_id[effect_id]; - hid_dbg(pidff->hid, "starting to erase %d/%d\n", - effect_id, pidff->pid_id[effect_id]); + hid_dbg(pidff->hid, "starting to erase %d/%d\n", effect_id, + pidff->pid_id[effect_id]); /* * Wait for the queue to clear. We do not want @@ -978,7 +975,7 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) pidff->set_effect[PID_START_DELAY].value[0] = 0; hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT], - HID_REQ_SET_REPORT); + HID_REQ_SET_REPORT); } /* @@ -1269,7 +1266,7 @@ static int pidff_find_special_fields(struct pidff_device *pidff) if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status, block_load_status) != - ARRAY_SIZE(pidff_block_load_status)) { + ARRAY_SIZE(pidff_block_load_status)) { hid_err(pidff->hid, "block load status identifiers not found\n"); return -1; @@ -1277,7 +1274,7 @@ static int pidff_find_special_fields(struct pidff_device *pidff) if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status, effect_operation_status) != - ARRAY_SIZE(pidff_effect_operation_status)) { + ARRAY_SIZE(pidff_effect_operation_status)) { hid_err(pidff->hid, "effect operation identifiers not found\n"); return -1; } @@ -1482,8 +1479,8 @@ static int pidff_check_autocenter(struct pidff_device *pidff, int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks) { struct pidff_device *pidff; - struct hid_input *hidinput = list_entry(hid->inputs.next, - struct hid_input, list); + struct hid_input *hidinput = + list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *dev = hidinput->input; struct ff_device *ff; int max_effects; @@ -1570,7 +1567,7 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks) return 0; - fail: +fail: hid_device_io_stop(hid); kfree(pidff); From 5b9cae8c6472e44702b2c19e78055248fab94043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:10:04 +0200 Subject: [PATCH 0157/2711] HID: universal-pidff: clang-format pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/hid-universal-pidff.c | 59 ++++++++++++++++--------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/drivers/hid/hid-universal-pidff.c b/drivers/hid/hid-universal-pidff.c index 70fce0f88e82..549dac555d40 100644 --- a/drivers/hid/hid-universal-pidff.c +++ b/drivers/hid/hid-universal-pidff.c @@ -8,12 +8,12 @@ * Copyright (c) 2024, 2025 Tomasz Pakuła */ -#include -#include -#include -#include #include "hid-ids.h" #include "usbhid/hid-pidff.h" +#include +#include +#include +#include #define JOY_RANGE (BTN_DEAD - BTN_JOYSTICK + 1) @@ -21,8 +21,10 @@ * Map buttons manually to extend the default joystick button limit */ static int universal_pidff_input_mapping(struct hid_device *hdev, - struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) + struct hid_input *hi, + struct hid_field *field, + struct hid_usage *usage, + unsigned long **bit, int *max) { if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON) return 0; @@ -126,65 +128,64 @@ static int universal_pidff_input_configured(struct hid_device *hdev, if (!test_bit(axis, input->absbit)) continue; - input_set_abs_params(input, axis, - input->absinfo[axis].minimum, - input->absinfo[axis].maximum, - axis == ABS_X ? 0 : 8, 0); + input_set_abs_params(input, axis, input->absinfo[axis].minimum, + input->absinfo[axis].maximum, + axis == ABS_X ? 0 : 8, 0); } /* Remove fuzz and deadzone from the second joystick axis */ if (hdev->vendor == USB_VENDOR_ID_FFBEAST && hdev->product == USB_DEVICE_ID_FFBEAST_JOYSTICK) input_set_abs_params(input, ABS_Y, - input->absinfo[ABS_Y].minimum, - input->absinfo[ABS_Y].maximum, 0, 0); + input->absinfo[ABS_Y].minimum, + input->absinfo[ABS_Y].maximum, 0, 0); return 0; } static const struct hid_device_id universal_pidff_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3), - .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3_2), - .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5), - .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5_2), - .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9), - .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9_2), - .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12), - .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12_2), - .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21), - .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21_2), - .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, + .driver_data = HID_PIDFF_QUIRK_FIX_CONDITIONAL_DIRECTION }, { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C5) }, { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C12) }, { HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_DFP), - .driver_data = HID_PIDFF_QUIRK_PERMISSIVE_CONTROL }, + .driver_data = HID_PIDFF_QUIRK_PERMISSIVE_CONTROL }, { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_JOYSTICK), }, { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_RUDDER), }, { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V10), - .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, + .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12), - .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, + .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE), - .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, + .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE_2), - .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, + .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_LITE_STAR_GT987), - .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, + .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_INVICTA) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_FORTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_LA_PRIMA) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_TONY_KANAAN) }, - { } + {} }; MODULE_DEVICE_TABLE(hid, universal_pidff_devices); From 13120abdb0d70431fb0c0cda29bec184aee782a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Wed, 13 Aug 2025 22:10:05 +0200 Subject: [PATCH 0158/2711] HID: pidff: Reduce PID_EFFECT_OPERATION spam MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep track of effect's loop_count to reduce the spam of ffb play commands coming from some games. This should speed up normal magnitude etc updates and slightly increase max possible FFB refresh rate. Helps games like Dirt Rally 2.0, F1 2023, WRC from KT Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 36 ++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 50a8924edfcc..0342c0a3f476 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -184,6 +184,12 @@ struct pidff_usage { s32 *value; }; +struct pidff_effect { + int pid_id; + int is_infinite; + unsigned int loop_count; +}; + struct pidff_device { struct hid_device *hid; @@ -202,6 +208,8 @@ struct pidff_device { struct pidff_usage effect_operation[ARRAY_SIZE(pidff_effect_operation)]; struct pidff_usage block_free[ARRAY_SIZE(pidff_block_free)]; + struct pidff_effect effect[PID_EFFECTS_MAX]; + /* * Special field is a field that is not composed of * usage<->value pairs that pidff_usage values are @@ -230,8 +238,6 @@ struct pidff_device { int operation_id[ARRAY_SIZE(pidff_effect_operation_status)]; int direction_axis_id[ARRAY_SIZE(pidff_direction_axis)]; - int pid_id[PID_EFFECTS_MAX]; - u32 quirks; u8 effect_count; u8 axis_count; @@ -798,6 +804,12 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) return -EIO; } +static int pidff_needs_playback(struct pidff_device *pidff, int effect_id, int n) +{ + return pidff->effect[effect_id].is_infinite || + pidff->effect[effect_id].loop_count != n; +} + /* * Play the effect with PID id n times */ @@ -829,9 +841,14 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value) { struct pidff_device *pidff = dev->ff->private; + if (!pidff_needs_playback(pidff, effect_id, value)) + return 0; + hid_dbg(pidff->hid, "requesting %s on FF effect %d", value == 0 ? "stop" : "playback", effect_id); - pidff_playback_pid(pidff, pidff->pid_id[effect_id], value); + + pidff->effect[effect_id].loop_count = value; + pidff_playback_pid(pidff, pidff->effect[effect_id].pid_id, value); return 0; } @@ -852,10 +869,9 @@ static void pidff_erase_pid(struct pidff_device *pidff, int pid_id) static int pidff_erase_effect(struct input_dev *dev, int effect_id) { struct pidff_device *pidff = dev->ff->private; - int pid_id = pidff->pid_id[effect_id]; + int pid_id = pidff->effect[effect_id].pid_id; - hid_dbg(pidff->hid, "starting to erase %d/%d\n", effect_id, - pidff->pid_id[effect_id]); + hid_dbg(pidff->hid, "starting to erase %d/%d\n", effect_id, pid_id); /* * Wait for the queue to clear. We do not want @@ -906,12 +922,16 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *new, pidff->effect_count++; hid_dbg(pidff->hid, "current effect count: %d", pidff->effect_count); - pidff->pid_id[new->id] = + pidff->effect[new->id].loop_count = 0; + pidff->effect[new->id].pid_id = pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; } + pidff->effect[new->id].is_infinite = + pidff_is_duration_infinite(new->replay.length); + pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = - pidff->pid_id[new->id]; + pidff->effect[new->id].pid_id; PIDFF_SET_REPORT_IF_NEEDED(effect, new, old); switch (new->type) { From 450bbe43ef90a213d66fac1def64050d9d9ada8e Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Mon, 21 Jul 2025 14:12:32 +0000 Subject: [PATCH 0159/2711] crypto: ccp - New bit-field definitions for SNP_PLATFORM_STATUS command Define new bit-field definitions returned by SNP_PLATFORM_STATUS command such as new capabilities like SNP_FEATURE_INFO command availability, ciphertext hiding enabled and capability. Reviewed-by: Tom Lendacky Signed-off-by: Ashish Kalra Reviewed-by: Kim Phillips Signed-off-by: Herbert Xu --- include/uapi/linux/psp-sev.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/psp-sev.h b/include/uapi/linux/psp-sev.h index eeb20dfb1fda..c2fd324623c4 100644 --- a/include/uapi/linux/psp-sev.h +++ b/include/uapi/linux/psp-sev.h @@ -185,6 +185,10 @@ struct sev_user_data_get_id2 { * @mask_chip_id: whether chip id is present in attestation reports or not * @mask_chip_key: whether attestation reports are signed or not * @vlek_en: VLEK (Version Loaded Endorsement Key) hashstick is loaded + * @feature_info: whether SNP_FEATURE_INFO command is available + * @rapl_dis: whether RAPL is disabled + * @ciphertext_hiding_cap: whether platform has ciphertext hiding capability + * @ciphertext_hiding_en: whether ciphertext hiding is enabled * @rsvd1: reserved * @guest_count: the number of guest currently managed by the firmware * @current_tcb_version: current TCB version @@ -200,7 +204,11 @@ struct sev_user_data_snp_status { __u32 mask_chip_id:1; /* Out */ __u32 mask_chip_key:1; /* Out */ __u32 vlek_en:1; /* Out */ - __u32 rsvd1:29; + __u32 feature_info:1; /* Out */ + __u32 rapl_dis:1; /* Out */ + __u32 ciphertext_hiding_cap:1; /* Out */ + __u32 ciphertext_hiding_en:1; /* Out */ + __u32 rsvd1:25; __u32 guest_count; /* Out */ __u64 current_tcb_version; /* Out */ __u64 reported_tcb_version; /* Out */ From 459daec42ea0cf5e276dfb82e90ed91e2db45d9e Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Mon, 21 Jul 2025 14:12:51 +0000 Subject: [PATCH 0160/2711] crypto: ccp - Cache SEV platform status and platform state Cache the SEV platform status into sev_device structure and use this cached SEV platform status for api_major/minor/build. The platform state is unique between SEV and SNP and hence needs to be tracked independently. Remove the state field from sev_device structure and instead track SEV state from the cached SEV platform status. Suggested-by: Tom Lendacky Reviewed-by: Tom Lendacky Signed-off-by: Ashish Kalra Reviewed-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 22 ++++++++++++---------- drivers/crypto/ccp/sev-dev.h | 3 ++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index e058ba027792..528013be1c0a 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1286,7 +1286,7 @@ static int __sev_platform_init_locked(int *error) sev = psp_master->sev_data; - if (sev->state == SEV_STATE_INIT) + if (sev->sev_plat_status.state == SEV_STATE_INIT) return 0; __sev_platform_init_handle_tmr(sev); @@ -1318,7 +1318,7 @@ static int __sev_platform_init_locked(int *error) return rc; } - sev->state = SEV_STATE_INIT; + sev->sev_plat_status.state = SEV_STATE_INIT; /* Prepare for first SEV guest launch after INIT */ wbinvd_on_all_cpus(); @@ -1347,7 +1347,7 @@ static int _sev_platform_init_locked(struct sev_platform_init_args *args) sev = psp_master->sev_data; - if (sev->state == SEV_STATE_INIT) + if (sev->sev_plat_status.state == SEV_STATE_INIT) return 0; rc = __sev_snp_init_locked(&args->error); @@ -1384,7 +1384,7 @@ static int __sev_platform_shutdown_locked(int *error) sev = psp->sev_data; - if (sev->state == SEV_STATE_UNINIT) + if (sev->sev_plat_status.state == SEV_STATE_UNINIT) return 0; ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error); @@ -1394,7 +1394,7 @@ static int __sev_platform_shutdown_locked(int *error) return ret; } - sev->state = SEV_STATE_UNINIT; + sev->sev_plat_status.state = SEV_STATE_UNINIT; dev_dbg(sev->dev, "SEV firmware shutdown\n"); return ret; @@ -1502,7 +1502,7 @@ static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp, bool wr if (!writable) return -EPERM; - if (sev->state == SEV_STATE_UNINIT) { + if (sev->sev_plat_status.state == SEV_STATE_UNINIT) { rc = sev_move_to_init_state(argp, &shutdown_required); if (rc) return rc; @@ -1551,7 +1551,7 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) data.len = input.length; cmd: - if (sev->state == SEV_STATE_UNINIT) { + if (sev->sev_plat_status.state == SEV_STATE_UNINIT) { ret = sev_move_to_init_state(argp, &shutdown_required); if (ret) goto e_free_blob; @@ -1606,10 +1606,12 @@ static int sev_get_api_version(void) return 1; } + /* Cache SEV platform status */ + sev->sev_plat_status = status; + sev->api_major = status.api_major; sev->api_minor = status.api_minor; sev->build = status.build; - sev->state = status.state; return 0; } @@ -1837,7 +1839,7 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable) data.oca_cert_len = input.oca_cert_len; /* If platform is not in INIT state then transition it to INIT */ - if (sev->state != SEV_STATE_INIT) { + if (sev->sev_plat_status.state != SEV_STATE_INIT) { ret = sev_move_to_init_state(argp, &shutdown_required); if (ret) goto e_free_oca; @@ -2008,7 +2010,7 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) cmd: /* If platform is not in INIT state then transition it to INIT. */ - if (sev->state != SEV_STATE_INIT) { + if (sev->sev_plat_status.state != SEV_STATE_INIT) { if (!writable) { ret = -EPERM; goto e_free_cert; diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h index 3e4e5574e88a..24dd8ff8afaa 100644 --- a/drivers/crypto/ccp/sev-dev.h +++ b/drivers/crypto/ccp/sev-dev.h @@ -42,7 +42,6 @@ struct sev_device { struct sev_vdata *vdata; - int state; unsigned int int_rcvd; wait_queue_head_t int_queue; struct sev_misc_dev *misc; @@ -57,6 +56,8 @@ struct sev_device { bool cmd_buf_backup_active; bool snp_initialized; + + struct sev_user_data_status sev_plat_status; }; int sev_dev_init(struct psp_device *psp); From 33cfb80d1910b41d1a25cef89b159c945aff0f24 Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Mon, 21 Jul 2025 14:13:10 +0000 Subject: [PATCH 0161/2711] crypto: ccp - Add support for SNP_FEATURE_INFO command The FEATURE_INFO command provides hypervisors with a programmatic means to learn about the supported features of the currently loaded firmware. This command mimics the CPUID instruction relative to sub-leaf input and the four unsigned integer output values. To obtain information regarding the features present in the currently loaded SEV firmware, use the SNP_FEATURE_INFO command. Cache the SNP platform status and feature information from CPUID 0x8000_0024 in the sev_device structure. If SNP is enabled, utilize this cached SNP platform status for the API major, minor and build version. Reviewed-by: Tom Lendacky Signed-off-by: Ashish Kalra Reviewed-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 72 ++++++++++++++++++++++++++++++++++++ drivers/crypto/ccp/sev-dev.h | 3 ++ include/linux/psp-sev.h | 29 +++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 528013be1c0a..a3941254d61f 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -233,6 +233,7 @@ static int sev_cmd_buffer_len(int cmd) case SEV_CMD_SNP_GUEST_REQUEST: return sizeof(struct sev_data_snp_guest_request); case SEV_CMD_SNP_CONFIG: return sizeof(struct sev_user_data_snp_config); case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit); + case SEV_CMD_SNP_FEATURE_INFO: return sizeof(struct sev_data_snp_feature_info); default: return 0; } @@ -1073,6 +1074,67 @@ static void snp_set_hsave_pa(void *arg) wrmsrq(MSR_VM_HSAVE_PA, 0); } +static int snp_get_platform_data(struct sev_device *sev, int *error) +{ + struct sev_data_snp_feature_info snp_feat_info; + struct snp_feature_info *feat_info; + struct sev_data_snp_addr buf; + struct page *page; + int rc; + + /* + * This function is expected to be called before SNP is + * initialized. + */ + if (sev->snp_initialized) + return -EINVAL; + + buf.address = __psp_pa(&sev->snp_plat_status); + rc = sev_do_cmd(SEV_CMD_SNP_PLATFORM_STATUS, &buf, error); + if (rc) { + dev_err(sev->dev, "SNP PLATFORM_STATUS command failed, ret = %d, error = %#x\n", + rc, *error); + return rc; + } + + sev->api_major = sev->snp_plat_status.api_major; + sev->api_minor = sev->snp_plat_status.api_minor; + sev->build = sev->snp_plat_status.build_id; + + /* + * Do feature discovery of the currently loaded firmware, + * and cache feature information from CPUID 0x8000_0024, + * sub-function 0. + */ + if (!sev->snp_plat_status.feature_info) + return 0; + + /* + * Use dynamically allocated structure for the SNP_FEATURE_INFO + * command to ensure structure is 8-byte aligned, and does not + * cross a page boundary. + */ + page = alloc_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + feat_info = page_address(page); + snp_feat_info.length = sizeof(snp_feat_info); + snp_feat_info.ecx_in = 0; + snp_feat_info.feature_info_paddr = __psp_pa(feat_info); + + rc = sev_do_cmd(SEV_CMD_SNP_FEATURE_INFO, &snp_feat_info, error); + if (!rc) + sev->snp_feat_info_0 = *feat_info; + else + dev_err(sev->dev, "SNP FEATURE_INFO command failed, ret = %d, error = %#x\n", + rc, *error); + + __free_page(page); + + return rc; +} + static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) { struct sev_data_range_list *range_list = arg; @@ -1599,6 +1661,16 @@ static int sev_get_api_version(void) struct sev_user_data_status status; int error = 0, ret; + /* + * Cache SNP platform status and SNP feature information + * if SNP is available. + */ + if (cc_platform_has(CC_ATTR_HOST_SEV_SNP)) { + ret = snp_get_platform_data(sev, &error); + if (ret) + return 1; + } + ret = sev_platform_status(&status, &error); if (ret) { dev_err(sev->dev, diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h index 24dd8ff8afaa..5aed2595c9ae 100644 --- a/drivers/crypto/ccp/sev-dev.h +++ b/drivers/crypto/ccp/sev-dev.h @@ -58,6 +58,9 @@ struct sev_device { bool snp_initialized; struct sev_user_data_status sev_plat_status; + + struct sev_user_data_snp_status snp_plat_status; + struct snp_feature_info snp_feat_info_0; }; int sev_dev_init(struct psp_device *psp); diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h index 0f5f94137f6d..5fb6ae0f51cc 100644 --- a/include/linux/psp-sev.h +++ b/include/linux/psp-sev.h @@ -107,6 +107,7 @@ enum sev_cmd { SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX = 0x0CA, SEV_CMD_SNP_COMMIT = 0x0CB, SEV_CMD_SNP_VLEK_LOAD = 0x0CD, + SEV_CMD_SNP_FEATURE_INFO = 0x0CE, SEV_CMD_MAX, }; @@ -814,6 +815,34 @@ struct sev_data_snp_commit { u32 len; } __packed; +/** + * struct sev_data_snp_feature_info - SEV_SNP_FEATURE_INFO structure + * + * @length: len of the command buffer read by the PSP + * @ecx_in: subfunction index + * @feature_info_paddr : System Physical Address of the FEATURE_INFO structure + */ +struct sev_data_snp_feature_info { + u32 length; + u32 ecx_in; + u64 feature_info_paddr; +} __packed; + +/** + * struct feature_info - FEATURE_INFO structure + * + * @eax: output of SNP_FEATURE_INFO command + * @ebx: output of SNP_FEATURE_INFO command + * @ecx: output of SNP_FEATURE_INFO command + * #edx: output of SNP_FEATURE_INFO command + */ +struct snp_feature_info { + u32 eax; + u32 ebx; + u32 ecx; + u32 edx; +} __packed; + #ifdef CONFIG_CRYPTO_DEV_SP_PSP /** From 45d59bd4a3e0f0475b3646e8b9936d34794e503d Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Mon, 21 Jul 2025 14:13:27 +0000 Subject: [PATCH 0162/2711] crypto: ccp - Introduce new API interface to indicate SEV-SNP Ciphertext hiding feature Implement an API that checks the overall feature support for SEV-SNP ciphertext hiding. This API verifies both the support of the SEV firmware for the feature and its enablement in the platform's BIOS. Reviewed-by: Tom Lendacky Signed-off-by: Ashish Kalra Reviewed-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 21 +++++++++++++++++++++ include/linux/psp-sev.h | 5 +++++ 2 files changed, 26 insertions(+) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index a3941254d61f..58c9e040e9ac 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1074,6 +1074,27 @@ static void snp_set_hsave_pa(void *arg) wrmsrq(MSR_VM_HSAVE_PA, 0); } +bool sev_is_snp_ciphertext_hiding_supported(void) +{ + struct psp_device *psp = psp_master; + struct sev_device *sev; + + if (!psp || !psp->sev_data) + return false; + + sev = psp->sev_data; + + /* + * Feature information indicates if CipherTextHiding feature is + * supported by the SEV firmware and additionally platform status + * indicates if CipherTextHiding feature is enabled in the + * Platform BIOS. + */ + return ((sev->snp_feat_info_0.ecx & SNP_CIPHER_TEXT_HIDING_SUPPORTED) && + sev->snp_plat_status.ciphertext_hiding_cap); +} +EXPORT_SYMBOL_GPL(sev_is_snp_ciphertext_hiding_supported); + static int snp_get_platform_data(struct sev_device *sev, int *error) { struct sev_data_snp_feature_info snp_feat_info; diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h index 5fb6ae0f51cc..d83185b4268b 100644 --- a/include/linux/psp-sev.h +++ b/include/linux/psp-sev.h @@ -843,6 +843,8 @@ struct snp_feature_info { u32 edx; } __packed; +#define SNP_CIPHER_TEXT_HIDING_SUPPORTED BIT(3) + #ifdef CONFIG_CRYPTO_DEV_SP_PSP /** @@ -986,6 +988,7 @@ void *psp_copy_user_blob(u64 uaddr, u32 len); void *snp_alloc_firmware_page(gfp_t mask); void snp_free_firmware_page(void *addr); void sev_platform_shutdown(void); +bool sev_is_snp_ciphertext_hiding_supported(void); #else /* !CONFIG_CRYPTO_DEV_SP_PSP */ @@ -1022,6 +1025,8 @@ static inline void snp_free_firmware_page(void *addr) { } static inline void sev_platform_shutdown(void) { } +static inline bool sev_is_snp_ciphertext_hiding_supported(void) { return false; } + #endif /* CONFIG_CRYPTO_DEV_SP_PSP */ #endif /* __PSP_SEV_H__ */ From c9760b0fca6bfa250c02e14bfe81c542f3626a72 Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Mon, 21 Jul 2025 14:13:55 +0000 Subject: [PATCH 0163/2711] crypto: ccp - Add support to enable CipherTextHiding on SNP_INIT_EX To enable ciphertext hiding, it must be specified in the SNP_INIT_EX command as part of SNP initialization. Modify the sev_platform_init_args structure, which is used as input to sev_platform_init(), to include a field that, when non-zero, indicates that ciphertext hiding should be enabled and specifies the maximum ASID that can be used for an SEV-SNP guest. Reviewed-by: Tom Lendacky Signed-off-by: Ashish Kalra Reviewed-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 12 +++++++++--- include/linux/psp-sev.h | 10 ++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 58c9e040e9ac..334405461657 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1186,7 +1186,7 @@ static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) return 0; } -static int __sev_snp_init_locked(int *error) +static int __sev_snp_init_locked(int *error, unsigned int max_snp_asid) { struct psp_device *psp = psp_master; struct sev_data_snp_init_ex data; @@ -1247,6 +1247,12 @@ static int __sev_snp_init_locked(int *error) } memset(&data, 0, sizeof(data)); + + if (max_snp_asid) { + data.ciphertext_hiding_en = 1; + data.max_snp_asid = max_snp_asid; + } + data.init_rmp = 1; data.list_paddr_en = 1; data.list_paddr = __psp_pa(snp_range_list); @@ -1433,7 +1439,7 @@ static int _sev_platform_init_locked(struct sev_platform_init_args *args) if (sev->sev_plat_status.state == SEV_STATE_INIT) return 0; - rc = __sev_snp_init_locked(&args->error); + rc = __sev_snp_init_locked(&args->error, args->max_snp_asid); if (rc && rc != -ENODEV) return rc; @@ -1516,7 +1522,7 @@ static int snp_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_req { int error, rc; - rc = __sev_snp_init_locked(&error); + rc = __sev_snp_init_locked(&error, 0); if (rc) { argp->error = SEV_RET_INVALID_PLATFORM_STATE; return rc; diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h index d83185b4268b..e0dbcb4b4fd9 100644 --- a/include/linux/psp-sev.h +++ b/include/linux/psp-sev.h @@ -748,10 +748,13 @@ struct sev_data_snp_guest_request { struct sev_data_snp_init_ex { u32 init_rmp:1; u32 list_paddr_en:1; - u32 rsvd:30; + u32 rapl_dis:1; + u32 ciphertext_hiding_en:1; + u32 rsvd:28; u32 rsvd1; u64 list_paddr; - u8 rsvd2[48]; + u16 max_snp_asid; + u8 rsvd2[46]; } __packed; /** @@ -800,10 +803,13 @@ struct sev_data_snp_shutdown_ex { * @probe: True if this is being called as part of CCP module probe, which * will defer SEV_INIT/SEV_INIT_EX firmware initialization until needed * unless psp_init_on_probe module param is set + * @max_snp_asid: When non-zero, enable ciphertext hiding and specify the + * maximum ASID that can be used for an SEV-SNP guest. */ struct sev_platform_init_args { int error; bool probe; + unsigned int max_snp_asid; }; /** From 81109696f09cf4c712366323f657d9879a40c626 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jul 2025 11:57:54 +0100 Subject: [PATCH 0164/2711] crypto: stm32 - Fix spelling mistake "STMicrolectronics" -> "STMicroelectronics" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a spelling mistake in the module description text. Fix it. Signed-off-by: Colin Ian King Acked-by: Maxime Méré Signed-off-by: Herbert Xu --- drivers/crypto/stm32/stm32-cryp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c index a89b4c5d62a0..5e82e8a1f71a 100644 --- a/drivers/crypto/stm32/stm32-cryp.c +++ b/drivers/crypto/stm32/stm32-cryp.c @@ -2781,5 +2781,5 @@ static struct platform_driver stm32_cryp_driver = { module_platform_driver(stm32_cryp_driver); MODULE_AUTHOR("Fabien Dessenne "); -MODULE_DESCRIPTION("STMicrolectronics STM32 CRYP hardware driver"); +MODULE_DESCRIPTION("STMicroelectronics STM32 CRYP hardware driver"); MODULE_LICENSE("GPL"); From 9ea349e4b94114f9fd8f01102b7db66edd9bd026 Mon Sep 17 00:00:00 2001 From: Vijay Sundar Selvamani Date: Fri, 25 Jul 2025 10:09:29 +0100 Subject: [PATCH 0165/2711] crypto: qat - add ring buffer idle telemetry counter for GEN6 Add a new performance counter that measures the average ring buffer idle duration. This metric is now included in the telemetry counters exposed via debugfs for QAT GEN6 devices. Update the documentation to reflect the new idle duration counter Co-developed-by: George Abraham P Signed-off-by: George Abraham P Signed-off-by: Vijay Sundar Selvamani Signed-off-by: Suman Kumar Chakraborty Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- Documentation/ABI/testing/debugfs-driver-qat_telemetry | 1 + drivers/crypto/intel/qat/qat_common/adf_gen6_tl.c | 8 ++++++++ drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h | 1 + 3 files changed, 10 insertions(+) diff --git a/Documentation/ABI/testing/debugfs-driver-qat_telemetry b/Documentation/ABI/testing/debugfs-driver-qat_telemetry index 0dfd8d97e169..53abf9275147 100644 --- a/Documentation/ABI/testing/debugfs-driver-qat_telemetry +++ b/Documentation/ABI/testing/debugfs-driver-qat_telemetry @@ -57,6 +57,7 @@ Description: (RO) Reports device telemetry counters. gp_lat_acc_avg average get to put latency [ns] bw_in PCIe, write bandwidth [Mbps] bw_out PCIe, read bandwidth [Mbps] + re_acc_avg average ring empty time [ns] at_page_req_lat_avg Address Translator(AT), average page request latency [ns] at_trans_lat_avg AT, average page translation latency [ns] diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen6_tl.c b/drivers/crypto/intel/qat/qat_common/adf_gen6_tl.c index cf804f95838a..633b0c05fbdb 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen6_tl.c +++ b/drivers/crypto/intel/qat/qat_common/adf_gen6_tl.c @@ -57,6 +57,10 @@ static const struct adf_tl_dbg_counter dev_counters[] = { /* Maximum uTLB used. */ ADF_TL_COUNTER(AT_MAX_UTLB_USED_NAME, ADF_TL_SIMPLE_COUNT, ADF_GEN6_TL_DEV_REG_OFF(reg_tl_at_max_utlb_used)), + /* Ring Empty average[ns] across all rings */ + ADF_TL_COUNTER_LATENCY(RE_ACC_NAME, ADF_TL_COUNTER_NS_AVG, + ADF_GEN6_TL_DEV_REG_OFF(reg_tl_re_acc), + ADF_GEN6_TL_DEV_REG_OFF(reg_tl_re_cnt)), }; /* Accelerator utilization counters */ @@ -122,6 +126,10 @@ static const struct adf_tl_dbg_counter rp_counters[] = { /* Payload DevTLB miss rate. */ ADF_TL_COUNTER(AT_PAYLD_DTLB_MISS_NAME, ADF_TL_SIMPLE_COUNT, ADF_GEN6_TL_RP_REG_OFF(reg_tl_at_payld_devtlb_miss)), + /* Ring Empty average[ns]. */ + ADF_TL_COUNTER_LATENCY(RE_ACC_NAME, ADF_TL_COUNTER_NS_AVG, + ADF_GEN6_TL_RP_REG_OFF(reg_tl_re_acc), + ADF_GEN6_TL_RP_REG_OFF(reg_tl_re_cnt)), }; void adf_gen6_init_tl_data(struct adf_tl_hw_data *tl_data) diff --git a/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h b/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h index 11cc9eae19b3..9efab3f76a3f 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h +++ b/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h @@ -17,6 +17,7 @@ struct adf_accel_dev; #define LAT_ACC_NAME "gp_lat_acc_avg" #define BW_IN_NAME "bw_in" #define BW_OUT_NAME "bw_out" +#define RE_ACC_NAME "re_acc_avg" #define PAGE_REQ_LAT_NAME "at_page_req_lat_avg" #define AT_TRANS_LAT_NAME "at_trans_lat_avg" #define AT_MAX_UTLB_USED_NAME "at_max_tlb_used" From 3ed63344657a48b19be6f4a697d94a436c0c7edc Mon Sep 17 00:00:00 2001 From: Vijay Sundar Selvamani Date: Fri, 25 Jul 2025 10:09:30 +0100 Subject: [PATCH 0166/2711] crypto: qat - add command queue telemetry counters for GEN6 Add slice-specific command queue counters for QAT GEN6 devices to monitor utilization metrics, including wait time, execution duration, and release events. Update the documentation to reflect the new command queue counter functionality. Co-developed-by: George Abraham P Signed-off-by: George Abraham P Signed-off-by: Vijay Sundar Selvamani Signed-off-by: Suman Kumar Chakraborty Reviewed-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../ABI/testing/debugfs-driver-qat_telemetry | 26 +++++ .../crypto/intel/qat/qat_common/adf_gen6_tl.c | 104 ++++++++++++++++++ .../intel/qat/qat_common/adf_telemetry.c | 19 ++++ .../intel/qat/qat_common/adf_telemetry.h | 5 + .../intel/qat/qat_common/adf_tl_debugfs.c | 52 +++++++++ .../intel/qat/qat_common/adf_tl_debugfs.h | 4 + 6 files changed, 210 insertions(+) diff --git a/Documentation/ABI/testing/debugfs-driver-qat_telemetry b/Documentation/ABI/testing/debugfs-driver-qat_telemetry index 53abf9275147..06097ee0f154 100644 --- a/Documentation/ABI/testing/debugfs-driver-qat_telemetry +++ b/Documentation/ABI/testing/debugfs-driver-qat_telemetry @@ -86,6 +86,32 @@ Description: (RO) Reports device telemetry counters. exec_cph execution count of Cipher slice N util_ath utilization of Authentication slice N [%] exec_ath execution count of Authentication slice N + cmdq_wait_cnv wait time for cmdq N to get Compression and verify + slice ownership + cmdq_exec_cnv Compression and verify slice execution time while + owned by cmdq N + cmdq_drain_cnv time taken for cmdq N to release Compression and + verify slice ownership + cmdq_wait_dcprz wait time for cmdq N to get Decompression + slice N ownership + cmdq_exec_dcprz Decompression slice execution time while + owned by cmdq N + cmdq_drain_dcprz time taken for cmdq N to release Decompression + slice ownership + cmdq_wait_pke wait time for cmdq N to get PKE slice ownership + cmdq_exec_pke PKE slice execution time while owned by cmdq N + cmdq_drain_pke time taken for cmdq N to release PKE slice + ownership + cmdq_wait_ucs wait time for cmdq N to get UCS slice ownership + cmdq_exec_ucs UCS slice execution time while owned by cmdq N + cmdq_drain_ucs time taken for cmdq N to release UCS slice + ownership + cmdq_wait_ath wait time for cmdq N to get Authentication slice + ownership + cmdq_exec_ath Authentication slice execution time while owned + by cmdq N + cmdq_drain_ath time taken for cmdq N to release Authentication + slice ownership ======================= ======================================== The telemetry report file can be read with the following command:: diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen6_tl.c b/drivers/crypto/intel/qat/qat_common/adf_gen6_tl.c index 633b0c05fbdb..faa60b04c406 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen6_tl.c +++ b/drivers/crypto/intel/qat/qat_common/adf_gen6_tl.c @@ -21,6 +21,25 @@ #define SLICE_IDX(sl) offsetof(struct icp_qat_fw_init_admin_slice_cnt, sl##_cnt) +#define ADF_GEN6_TL_CMDQ_WAIT_COUNTER(_name) \ + ADF_TL_COUNTER("cmdq_wait_" #_name, ADF_TL_SIMPLE_COUNT, \ + ADF_TL_CMDQ_REG_OFF(_name, reg_tm_cmdq_wait_cnt, gen6)) +#define ADF_GEN6_TL_CMDQ_EXEC_COUNTER(_name) \ + ADF_TL_COUNTER("cmdq_exec_" #_name, ADF_TL_SIMPLE_COUNT, \ + ADF_TL_CMDQ_REG_OFF(_name, reg_tm_cmdq_exec_cnt, gen6)) +#define ADF_GEN6_TL_CMDQ_DRAIN_COUNTER(_name) \ + ADF_TL_COUNTER("cmdq_drain_" #_name, ADF_TL_SIMPLE_COUNT, \ + ADF_TL_CMDQ_REG_OFF(_name, reg_tm_cmdq_drain_cnt, \ + gen6)) + +#define CPR_QUEUE_COUNT 5 +#define DCPR_QUEUE_COUNT 3 +#define PKE_QUEUE_COUNT 1 +#define WAT_QUEUE_COUNT 7 +#define WCP_QUEUE_COUNT 7 +#define USC_QUEUE_COUNT 3 +#define ATH_QUEUE_COUNT 2 + /* Device level counters. */ static const struct adf_tl_dbg_counter dev_counters[] = { /* PCIe partial transactions. */ @@ -99,6 +118,80 @@ static const struct adf_tl_dbg_counter sl_exec_counters[ADF_TL_SL_CNT_COUNT] = { [SLICE_IDX(ath)] = ADF_GEN6_TL_SL_EXEC_COUNTER(ath), }; +static const struct adf_tl_dbg_counter cnv_cmdq_counters[] = { + ADF_GEN6_TL_CMDQ_WAIT_COUNTER(cnv), + ADF_GEN6_TL_CMDQ_EXEC_COUNTER(cnv), + ADF_GEN6_TL_CMDQ_DRAIN_COUNTER(cnv) +}; + +#define NUM_CMDQ_COUNTERS ARRAY_SIZE(cnv_cmdq_counters) + +static const struct adf_tl_dbg_counter dcprz_cmdq_counters[] = { + ADF_GEN6_TL_CMDQ_WAIT_COUNTER(dcprz), + ADF_GEN6_TL_CMDQ_EXEC_COUNTER(dcprz), + ADF_GEN6_TL_CMDQ_DRAIN_COUNTER(dcprz) +}; + +static_assert(ARRAY_SIZE(dcprz_cmdq_counters) == NUM_CMDQ_COUNTERS); + +static const struct adf_tl_dbg_counter pke_cmdq_counters[] = { + ADF_GEN6_TL_CMDQ_WAIT_COUNTER(pke), + ADF_GEN6_TL_CMDQ_EXEC_COUNTER(pke), + ADF_GEN6_TL_CMDQ_DRAIN_COUNTER(pke) +}; + +static_assert(ARRAY_SIZE(pke_cmdq_counters) == NUM_CMDQ_COUNTERS); + +static const struct adf_tl_dbg_counter wat_cmdq_counters[] = { + ADF_GEN6_TL_CMDQ_WAIT_COUNTER(wat), + ADF_GEN6_TL_CMDQ_EXEC_COUNTER(wat), + ADF_GEN6_TL_CMDQ_DRAIN_COUNTER(wat) +}; + +static_assert(ARRAY_SIZE(wat_cmdq_counters) == NUM_CMDQ_COUNTERS); + +static const struct adf_tl_dbg_counter wcp_cmdq_counters[] = { + ADF_GEN6_TL_CMDQ_WAIT_COUNTER(wcp), + ADF_GEN6_TL_CMDQ_EXEC_COUNTER(wcp), + ADF_GEN6_TL_CMDQ_DRAIN_COUNTER(wcp) +}; + +static_assert(ARRAY_SIZE(wcp_cmdq_counters) == NUM_CMDQ_COUNTERS); + +static const struct adf_tl_dbg_counter ucs_cmdq_counters[] = { + ADF_GEN6_TL_CMDQ_WAIT_COUNTER(ucs), + ADF_GEN6_TL_CMDQ_EXEC_COUNTER(ucs), + ADF_GEN6_TL_CMDQ_DRAIN_COUNTER(ucs) +}; + +static_assert(ARRAY_SIZE(ucs_cmdq_counters) == NUM_CMDQ_COUNTERS); + +static const struct adf_tl_dbg_counter ath_cmdq_counters[] = { + ADF_GEN6_TL_CMDQ_WAIT_COUNTER(ath), + ADF_GEN6_TL_CMDQ_EXEC_COUNTER(ath), + ADF_GEN6_TL_CMDQ_DRAIN_COUNTER(ath) +}; + +static_assert(ARRAY_SIZE(ath_cmdq_counters) == NUM_CMDQ_COUNTERS); + +/* CMDQ drain counters. */ +static const struct adf_tl_dbg_counter *cmdq_counters[ADF_TL_SL_CNT_COUNT] = { + /* Compression accelerator execution count. */ + [SLICE_IDX(cpr)] = cnv_cmdq_counters, + /* Decompression accelerator execution count. */ + [SLICE_IDX(dcpr)] = dcprz_cmdq_counters, + /* PKE execution count. */ + [SLICE_IDX(pke)] = pke_cmdq_counters, + /* Wireless Authentication accelerator execution count. */ + [SLICE_IDX(wat)] = wat_cmdq_counters, + /* Wireless Cipher accelerator execution count. */ + [SLICE_IDX(wcp)] = wcp_cmdq_counters, + /* UCS accelerator execution count. */ + [SLICE_IDX(ucs)] = ucs_cmdq_counters, + /* Authentication accelerator execution count. */ + [SLICE_IDX(ath)] = ath_cmdq_counters, +}; + /* Ring pair counters. */ static const struct adf_tl_dbg_counter rp_counters[] = { /* PCIe partial transactions. */ @@ -136,6 +229,7 @@ void adf_gen6_init_tl_data(struct adf_tl_hw_data *tl_data) { tl_data->layout_sz = ADF_GEN6_TL_LAYOUT_SZ; tl_data->slice_reg_sz = ADF_GEN6_TL_SLICE_REG_SZ; + tl_data->cmdq_reg_sz = ADF_GEN6_TL_CMDQ_REG_SZ; tl_data->rp_reg_sz = ADF_GEN6_TL_RP_REG_SZ; tl_data->num_hbuff = ADF_GEN6_TL_NUM_HIST_BUFFS; tl_data->max_rp = ADF_GEN6_TL_MAX_RP_NUM; @@ -147,8 +241,18 @@ void adf_gen6_init_tl_data(struct adf_tl_hw_data *tl_data) tl_data->num_dev_counters = ARRAY_SIZE(dev_counters); tl_data->sl_util_counters = sl_util_counters; tl_data->sl_exec_counters = sl_exec_counters; + tl_data->cmdq_counters = cmdq_counters; + tl_data->num_cmdq_counters = NUM_CMDQ_COUNTERS; tl_data->rp_counters = rp_counters; tl_data->num_rp_counters = ARRAY_SIZE(rp_counters); tl_data->max_sl_cnt = ADF_GEN6_TL_MAX_SLICES_PER_TYPE; + + tl_data->multiplier.cpr_cnt = CPR_QUEUE_COUNT; + tl_data->multiplier.dcpr_cnt = DCPR_QUEUE_COUNT; + tl_data->multiplier.pke_cnt = PKE_QUEUE_COUNT; + tl_data->multiplier.wat_cnt = WAT_QUEUE_COUNT; + tl_data->multiplier.wcp_cnt = WCP_QUEUE_COUNT; + tl_data->multiplier.ucs_cnt = USC_QUEUE_COUNT; + tl_data->multiplier.ath_cnt = ATH_QUEUE_COUNT; } EXPORT_SYMBOL_GPL(adf_gen6_init_tl_data); diff --git a/drivers/crypto/intel/qat/qat_common/adf_telemetry.c b/drivers/crypto/intel/qat/qat_common/adf_telemetry.c index 74fb0c2ed241..b64142db1f0d 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_telemetry.c +++ b/drivers/crypto/intel/qat/qat_common/adf_telemetry.c @@ -212,6 +212,23 @@ int adf_tl_halt(struct adf_accel_dev *accel_dev) return ret; } +static void adf_set_cmdq_cnt(struct adf_accel_dev *accel_dev, + struct adf_tl_hw_data *tl_data) +{ + struct icp_qat_fw_init_admin_slice_cnt *slice_cnt, *cmdq_cnt; + + slice_cnt = &accel_dev->telemetry->slice_cnt; + cmdq_cnt = &accel_dev->telemetry->cmdq_cnt; + + cmdq_cnt->cpr_cnt = slice_cnt->cpr_cnt * tl_data->multiplier.cpr_cnt; + cmdq_cnt->dcpr_cnt = slice_cnt->dcpr_cnt * tl_data->multiplier.dcpr_cnt; + cmdq_cnt->pke_cnt = slice_cnt->pke_cnt * tl_data->multiplier.pke_cnt; + cmdq_cnt->wat_cnt = slice_cnt->wat_cnt * tl_data->multiplier.wat_cnt; + cmdq_cnt->wcp_cnt = slice_cnt->wcp_cnt * tl_data->multiplier.wcp_cnt; + cmdq_cnt->ucs_cnt = slice_cnt->ucs_cnt * tl_data->multiplier.ucs_cnt; + cmdq_cnt->ath_cnt = slice_cnt->ath_cnt * tl_data->multiplier.ath_cnt; +} + int adf_tl_run(struct adf_accel_dev *accel_dev, int state) { struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev); @@ -235,6 +252,8 @@ int adf_tl_run(struct adf_accel_dev *accel_dev, int state) return ret; } + adf_set_cmdq_cnt(accel_dev, tl_data); + telemetry->hbuffs = state; atomic_set(&telemetry->state, state); diff --git a/drivers/crypto/intel/qat/qat_common/adf_telemetry.h b/drivers/crypto/intel/qat/qat_common/adf_telemetry.h index e54a406cc1b4..02d75c3c214a 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_telemetry.h +++ b/drivers/crypto/intel/qat/qat_common/adf_telemetry.h @@ -28,19 +28,23 @@ struct dentry; struct adf_tl_hw_data { size_t layout_sz; size_t slice_reg_sz; + size_t cmdq_reg_sz; size_t rp_reg_sz; size_t msg_cnt_off; const struct adf_tl_dbg_counter *dev_counters; const struct adf_tl_dbg_counter *sl_util_counters; const struct adf_tl_dbg_counter *sl_exec_counters; + const struct adf_tl_dbg_counter **cmdq_counters; const struct adf_tl_dbg_counter *rp_counters; u8 num_hbuff; u8 cpp_ns_per_cycle; u8 bw_units_to_bytes; u8 num_dev_counters; u8 num_rp_counters; + u8 num_cmdq_counters; u8 max_rp; u8 max_sl_cnt; + struct icp_qat_fw_init_admin_slice_cnt multiplier; }; struct adf_telemetry { @@ -69,6 +73,7 @@ struct adf_telemetry { struct mutex wr_lock; struct delayed_work work_ctx; struct icp_qat_fw_init_admin_slice_cnt slice_cnt; + struct icp_qat_fw_init_admin_slice_cnt cmdq_cnt; }; #ifdef CONFIG_DEBUG_FS diff --git a/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.c b/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.c index a32db273842a..b81f70576683 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.c @@ -339,6 +339,48 @@ static int tl_calc_and_print_sl_counters(struct adf_accel_dev *accel_dev, return 0; } +static int tl_print_cmdq_counter(struct adf_telemetry *telemetry, + const struct adf_tl_dbg_counter *ctr, + struct seq_file *s, u8 cnt_id, u8 counter) +{ + size_t cmdq_regs_sz = GET_TL_DATA(telemetry->accel_dev).cmdq_reg_sz; + size_t offset_inc = cnt_id * cmdq_regs_sz; + struct adf_tl_dbg_counter slice_ctr; + char cnt_name[MAX_COUNT_NAME_SIZE]; + + slice_ctr = *(ctr + counter); + slice_ctr.offset1 += offset_inc; + snprintf(cnt_name, MAX_COUNT_NAME_SIZE, "%s%d", slice_ctr.name, cnt_id); + + return tl_calc_and_print_counter(telemetry, s, &slice_ctr, cnt_name); +} + +static int tl_calc_and_print_cmdq_counters(struct adf_accel_dev *accel_dev, + struct seq_file *s, u8 cnt_type, + u8 cnt_id) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev); + struct adf_telemetry *telemetry = accel_dev->telemetry; + const struct adf_tl_dbg_counter **cmdq_tl_counters; + const struct adf_tl_dbg_counter *ctr; + u8 counter; + int ret; + + cmdq_tl_counters = tl_data->cmdq_counters; + ctr = cmdq_tl_counters[cnt_type]; + + for (counter = 0; counter < tl_data->num_cmdq_counters; counter++) { + ret = tl_print_cmdq_counter(telemetry, ctr, s, cnt_id, counter); + if (ret) { + dev_notice(&GET_DEV(accel_dev), + "invalid slice utilization counter type\n"); + return ret; + } + } + + return 0; +} + static void tl_print_msg_cnt(struct seq_file *s, u32 msg_cnt) { seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, SNAPSHOT_CNT_MSG); @@ -352,6 +394,7 @@ static int tl_print_dev_data(struct adf_accel_dev *accel_dev, struct adf_telemetry *telemetry = accel_dev->telemetry; const struct adf_tl_dbg_counter *dev_tl_counters; u8 num_dev_counters = tl_data->num_dev_counters; + u8 *cmdq_cnt = (u8 *)&telemetry->cmdq_cnt; u8 *sl_cnt = (u8 *)&telemetry->slice_cnt; const struct adf_tl_dbg_counter *ctr; unsigned int i; @@ -387,6 +430,15 @@ static int tl_print_dev_data(struct adf_accel_dev *accel_dev, } } + /* Print per command queue telemetry. */ + for (i = 0; i < ADF_TL_SL_CNT_COUNT; i++) { + for (j = 0; j < cmdq_cnt[i]; j++) { + ret = tl_calc_and_print_cmdq_counters(accel_dev, s, i, j); + if (ret) + return ret; + } + } + return 0; } diff --git a/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h b/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h index 9efab3f76a3f..97c5eeaa1b17 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h +++ b/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h @@ -44,6 +44,10 @@ struct adf_accel_dev; (ADF_TL_DEV_REG_OFF(slice##_slices[0], qat_gen) + \ offsetof(struct adf_##qat_gen##_tl_slice_data_regs, reg)) +#define ADF_TL_CMDQ_REG_OFF(slice, reg, qat_gen) \ + (ADF_TL_DEV_REG_OFF(slice##_cmdq[0], qat_gen) + \ + offsetof(struct adf_##qat_gen##_tl_cmdq_data_regs, reg)) + #define ADF_TL_RP_REG_OFF(reg, qat_gen) \ (ADF_TL_DATA_REG_OFF(tl_ring_pairs_data_regs[0], qat_gen) + \ offsetof(struct adf_##qat_gen##_tl_ring_pair_data_regs, reg)) From 4e53be21dd0315c00eaf40cc8f8c0facd4d9a6b2 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Mon, 28 Jul 2025 14:03:30 +0200 Subject: [PATCH 0167/2711] crypto: keembay - Add missing check after sg_nents_for_len() sg_nents_for_len() returns an int which is negative in case of error. Fixes: 472b04444cd3 ("crypto: keembay - Add Keem Bay OCS HCU driver") Signed-off-by: Thomas Fourier Signed-off-by: Herbert Xu --- drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c b/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c index 8f9e21ced0fe..48281d882260 100644 --- a/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c +++ b/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c @@ -232,7 +232,7 @@ static int kmb_ocs_dma_prepare(struct ahash_request *req) struct device *dev = rctx->hcu_dev->dev; unsigned int remainder = 0; unsigned int total; - size_t nents; + int nents; size_t count; int rc; int i; @@ -253,6 +253,9 @@ static int kmb_ocs_dma_prepare(struct ahash_request *req) /* Determine the number of scatter gather list entries to process. */ nents = sg_nents_for_len(req->src, rctx->sg_data_total - remainder); + if (nents < 0) + return nents; + /* If there are entries to process, map them. */ if (nents) { rctx->sg_dma_nents = dma_map_sg(dev, req->src, nents, From ed53a5050f42a3243a7ed8dfa49030e54034b952 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Mon, 28 Jul 2025 18:43:03 -0500 Subject: [PATCH 0168/2711] crypto: ccp - Fix checks for SNP_VLEK_LOAD input buffer length The SNP_VLEK_LOAD IOCTL currently fails due to sev_cmd_buffer_len() returning the default expected buffer length of 0 instead of the correct value, which would be sizeof(struct sev_user_data_snp_vlek_load). Add specific handling for SNP_VLEK_LOAD so the correct expected size is returned. Reported-by: Diego GonzalezVillalobos Cc: Diego GonzalezVillalobos Fixes: 332d2c1d713e ("crypto: ccp: Add the SNP_VLEK_LOAD command") Signed-off-by: Michael Roth Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 334405461657..4f000dc2e639 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -234,6 +234,7 @@ static int sev_cmd_buffer_len(int cmd) case SEV_CMD_SNP_CONFIG: return sizeof(struct sev_user_data_snp_config); case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit); case SEV_CMD_SNP_FEATURE_INFO: return sizeof(struct sev_data_snp_feature_info); + case SEV_CMD_SNP_VLEK_LOAD: return sizeof(struct sev_user_data_snp_vlek_load); default: return 0; } From efaa2d815a0e4d1c06750e587100f6f7f4ee5497 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 29 Jul 2025 17:28:00 +0200 Subject: [PATCH 0169/2711] hwrng: nomadik - add ARM_AMBA dependency Compile-testing this driver is only possible when the AMBA bus driver is available in the kernel: x86_64-linux-ld: drivers/char/hw_random/nomadik-rng.o: in function `nmk_rng_remove': nomadik-rng.c:(.text+0x67): undefined reference to `amba_release_regions' x86_64-linux-ld: drivers/char/hw_random/nomadik-rng.o: in function `nmk_rng_probe': nomadik-rng.c:(.text+0xee): undefined reference to `amba_request_regions' x86_64-linux-ld: nomadik-rng.c:(.text+0x18d): undefined reference to `amba_release_regions' The was previously implied by the 'depends on ARCH_NOMADIK', but needs to be specified for the COMPILE_TEST case. Fixes: d5e93b3374e4 ("hwrng: Kconfig - Add helper dependency on COMPILE_TEST") Signed-off-by: Arnd Bergmann Signed-off-by: Herbert Xu --- drivers/char/hw_random/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index c85827843447..7826fd7c4603 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -312,6 +312,7 @@ config HW_RANDOM_INGENIC_TRNG config HW_RANDOM_NOMADIK tristate "ST-Ericsson Nomadik Random Number Generator support" depends on ARCH_NOMADIK || COMPILE_TEST + depends on ARM_AMBA default HW_RANDOM help This driver provides kernel-side support for the Random Number From 817fcdbd4ca29834014a5dadbe8e11efeb12800c Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Thu, 31 Jul 2025 20:17:27 +0800 Subject: [PATCH 0170/2711] hwrng: timeriomem - Use us_to_ktime() where appropriate It is better to replace ns_to_ktime() with us_to_ktime(), which can make the code clearer. Signed-off-by: Xichao Zhao Signed-off-by: Herbert Xu --- drivers/char/hw_random/timeriomem-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index b95f6d0f17ed..e61f06393209 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -150,7 +150,7 @@ static int timeriomem_rng_probe(struct platform_device *pdev) priv->rng_ops.quality = pdata->quality; } - priv->period = ns_to_ktime(period * NSEC_PER_USEC); + priv->period = us_to_ktime(period); init_completion(&priv->completion); hrtimer_setup(&priv->timer, timeriomem_rng_trigger, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); From d2236198839ca57610d1f7be7c61fb8c95f2fca6 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Thu, 7 Aug 2025 13:44:44 +0200 Subject: [PATCH 0171/2711] lib/lzo: add unlikely hints to overrun checks The NEED_* macros do an implicit goto in case the safety bounds checks fail. Add the unlikely hints as this is the error case and not a hot path. The final assembly is slightly shorter and some jumps got reordered according to the hints. text data bss dec hex filename 2294 16 0 2310 906 pre/lzo1x_decompress_safe.o 2277 16 0 2293 8f5 post/lzo1x_decompress_safe.o text data bss dec hex filename 3444 48 0 3492 da4 pre/lzo1x_compress_safe.o 3372 48 0 3420 d5c post/lzo1x_compress_safe.o Signed-off-by: David Sterba Signed-off-by: Herbert Xu --- lib/lzo/lzo1x_compress.c | 2 +- lib/lzo/lzo1x_decompress_safe.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c index 7b10ca86a893..01586af2347f 100644 --- a/lib/lzo/lzo1x_compress.c +++ b/lib/lzo/lzo1x_compress.c @@ -26,7 +26,7 @@ #define HAVE_OP(x) 1 #endif -#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun +#define NEED_OP(x) if (unlikely(!HAVE_OP(x))) goto output_overrun static noinline int LZO_SAFE(lzo1x_1_do_compress)(const unsigned char *in, size_t in_len, diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c index c94f4928e188..318abb82c63d 100644 --- a/lib/lzo/lzo1x_decompress_safe.c +++ b/lib/lzo/lzo1x_decompress_safe.c @@ -22,9 +22,9 @@ #define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) #define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) -#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun -#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun -#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun +#define NEED_IP(x) if (unlikely(!HAVE_IP(x))) goto input_overrun +#define NEED_OP(x) if (unlikely(!HAVE_OP(x))) goto output_overrun +#define TEST_LB(m_pos) if (unlikely((m_pos) < out)) goto lookbehind_overrun /* This MAX_255_COUNT is the maximum number of times we can add 255 to a base * count without overflowing an integer. The multiply will overflow when From 34c065fe1d0dbb08073d83559d3173bb4f17dcc5 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Fri, 8 Aug 2025 15:44:26 +0800 Subject: [PATCH 0172/2711] crypto: ccp - Remove redundant __GFP_ZERO Remove the redundant __GFP_ZERO flag from kzalloc() since kzalloc() inherently zeroes memory. Signed-off-by: Qianfeng Rong Reviewed-by: Mario Limonciello Signed-off-by: Herbert Xu --- drivers/crypto/ccp/hsti.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/hsti.c b/drivers/crypto/ccp/hsti.c index 1b39a4fb55c0..0ab3708951af 100644 --- a/drivers/crypto/ccp/hsti.c +++ b/drivers/crypto/ccp/hsti.c @@ -84,7 +84,7 @@ static int psp_poulate_hsti(struct psp_device *psp) return 0; /* Allocate command-response buffer */ - req = kzalloc(sizeof(*req), GFP_KERNEL | __GFP_ZERO); + req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) return -ENOMEM; From d75c7021c08e8ae3f311ef2464dca0eaf75fab9f Mon Sep 17 00:00:00 2001 From: Rodrigo Gobbi Date: Thu, 17 Jul 2025 19:13:49 -0300 Subject: [PATCH 0173/2711] iio: adc: spear_adc: mask SPEAR_ADC_STATUS channel and avg sample before setting register avg sample info is a bit field coded inside the following bits: 5,6,7 and 8 of a device status register. Channel num info the same, but over bits: 1, 2 and 3. Mask both values in order to avoid touching other register bits, since the first info (avg sample), came from DT. Signed-off-by: Rodrigo Gobbi Reviewed-by: David Lechner Link: https://patch.msgid.link/20250717221559.158872-1-rodrigo.gobbi.7@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/spear_adc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index e3a865c79686..df100dce77da 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -29,9 +30,9 @@ /* Bit definitions for SPEAR_ADC_STATUS */ #define SPEAR_ADC_STATUS_START_CONVERSION BIT(0) -#define SPEAR_ADC_STATUS_CHANNEL_NUM(x) ((x) << 1) +#define SPEAR_ADC_STATUS_CHANNEL_NUM_MASK GENMASK(3, 1) #define SPEAR_ADC_STATUS_ADC_ENABLE BIT(4) -#define SPEAR_ADC_STATUS_AVG_SAMPLE(x) ((x) << 5) +#define SPEAR_ADC_STATUS_AVG_SAMPLE_MASK GENMASK(8, 5) #define SPEAR_ADC_STATUS_VREF_INTERNAL BIT(9) #define SPEAR_ADC_DATA_MASK 0x03ff @@ -157,8 +158,8 @@ static int spear_adc_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: mutex_lock(&st->lock); - status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) | - SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) | + status = FIELD_PREP(SPEAR_ADC_STATUS_CHANNEL_NUM_MASK, chan->channel) | + FIELD_PREP(SPEAR_ADC_STATUS_AVG_SAMPLE_MASK, st->avg_samples) | SPEAR_ADC_STATUS_START_CONVERSION | SPEAR_ADC_STATUS_ADC_ENABLE; if (st->vref_external == 0) From 83d76bf0360f7041d03d8f70301b0a8f96c9c872 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 23 Jul 2025 08:56:45 +0000 Subject: [PATCH 0174/2711] dt-bindings: iio: adc: rockchip-saradc: Allow use of a power-domain The SARADC controller in most Rockchip SoCs are part of power domains that are always powered on, i.e. PD_BUS or PD_PERI. These always powered on power domains have typically not been described in the device tree. Because these power domains have been left out of the device tree there has not been any real need to properly describe the power domain of the SARADC controller. On RK3528 the SARADC controller is part of the PD_VPU power domain. Add support to describe an optional power-domains for the SARADC controller in Rockchip SoCs. Signed-off-by: Jonas Karlman Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250723085654.2273324-4-jonas@kwiboo.se Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml index 41e0c56ef8e3..f776041fd08f 100644 --- a/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml @@ -47,6 +47,9 @@ properties: - const: saradc - const: apb_pclk + power-domains: + maxItems: 1 + resets: maxItems: 1 From f235ec59343b2a7cb5844a5656aca6360829ca4b Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 22 Jul 2025 17:39:17 -0500 Subject: [PATCH 0175/2711] iio: proximity: mb1232: use stack allocated scan struct Use a stack allocated struct for the scan data instead of using the driver state to store the struct. The scan data is not used outside of the interrupt handler function so the struct does not need to exist outside of that scope. Signed-off-by: David Lechner Link: https://patch.msgid.link/20250722-iio-proximity-mb1232-use-stack-allocated-scan-struct-v1-1-b4ef77e9ddea@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/mb1232.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/iio/proximity/mb1232.c b/drivers/iio/proximity/mb1232.c index 01783486bc7d..34b49c54e68b 100644 --- a/drivers/iio/proximity/mb1232.c +++ b/drivers/iio/proximity/mb1232.c @@ -42,11 +42,6 @@ struct mb1232_data { */ struct completion ranging; int irqnr; - /* Ensure correct alignment of data to push to IIO buffer */ - struct { - s16 distance; - aligned_s64 ts; - } scan; }; static irqreturn_t mb1232_handle_irq(int irq, void *dev_id) @@ -120,12 +115,16 @@ static irqreturn_t mb1232_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct mb1232_data *data = iio_priv(indio_dev); + struct { + s16 distance; + aligned_s64 ts; + } scan = { }; - data->scan.distance = mb1232_read_distance(data); - if (data->scan.distance < 0) + scan.distance = mb1232_read_distance(data); + if (scan.distance < 0) goto err; - iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), pf->timestamp); err: From 8e7a21e103d7192ae267045cca79290f31333910 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 22 Jul 2025 17:34:45 -0500 Subject: [PATCH 0176/2711] iio: proximity: pulsedlight-lidar-lite-v2: use stack allocated scan struct Use a stack allocated struct for the scan data instead of using the driver state to store the struct. The scan data is not used outside of the interrupt handler function so the struct does not need to exist outside of that scope. Signed-off-by: David Lechner Link: https://patch.msgid.link/20250722-iio-proximity-pulsedlight-lidar-lite-v2-use-stack-allocated-scan-struct-v1-1-4c253339b941@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 1deaf70e92ce..01c013acfda2 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -43,12 +43,6 @@ struct lidar_data { int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len); int i2c_enabled; - - /* Ensure timestamp is naturally aligned */ - struct { - u16 chan; - aligned_s64 timestamp; - } scan; }; static const struct iio_chan_spec lidar_channels[] = { @@ -235,11 +229,14 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private) struct iio_dev *indio_dev = pf->indio_dev; struct lidar_data *data = iio_priv(indio_dev); int ret; + struct { + u16 chan; + aligned_s64 timestamp; + } scan = { }; - ret = lidar_get_measurement(data, &data->scan.chan); + ret = lidar_get_measurement(data, &scan.chan); if (!ret) { - iio_push_to_buffers_with_ts(indio_dev, &data->scan, - sizeof(data->scan), + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), iio_get_time_ns(indio_dev)); } else if (ret != -EINVAL) { dev_err(&data->client->dev, "cannot read LIDAR measurement"); From ff2501ff5c329a1a8bb0715e033d3b8af1e76de2 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 22 Jul 2025 17:26:39 -0500 Subject: [PATCH 0177/2711] iio: proximity: vl53l0x-i2c: use stack allocated scan struct Use a stack allocated struct for the scan data instead of using the driver state to store the struct. The scan data is not used outside of the interrupt handler function so the struct does not need to exist outside of that scope. Signed-off-by: David Lechner Link: https://patch.msgid.link/20250722-iio-proximity-vl53l0x-i2c-use-stack-allocated-scan-struct-v1-1-42f127a6834f@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/vl53l0x-i2c.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index ef4aa7b2835e..b4d82f24be29 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -57,11 +57,6 @@ struct vl53l0x_data { struct regulator *vdd_supply; struct gpio_desc *reset_gpio; struct iio_trigger *trig; - - struct { - u16 chan; - aligned_s64 timestamp; - } scan; }; static int vl53l0x_clear_irq(struct vl53l0x_data *data) @@ -84,6 +79,10 @@ static irqreturn_t vl53l0x_trigger_handler(int irq, void *priv) struct vl53l0x_data *data = iio_priv(indio_dev); u8 buffer[12]; int ret; + struct { + u16 chan; + aligned_s64 timestamp; + } scan = { }; ret = i2c_smbus_read_i2c_block_data(data->client, VL_REG_RESULT_RANGE_STATUS, @@ -93,8 +92,8 @@ static irqreturn_t vl53l0x_trigger_handler(int irq, void *priv) else if (ret != 12) return -EREMOTEIO; - data->scan.chan = get_unaligned_be16(&buffer[10]); - iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + scan.chan = get_unaligned_be16(&buffer[10]); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); From b76c739c3d11d1dacc8efe7fa873bee28ac991f1 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 22 Jul 2025 16:52:38 -0500 Subject: [PATCH 0178/2711] iio: fix iio_push_to_buffers_with_ts() typo Replace iio_push_to_buffer_with_ts() with iio_push_to_buffers_with_ts() in some documentation comments in iio.h. The latter is the correct name of the function, the former doesn't exist. Signed-off-by: David Lechner Link: https://patch.msgid.link/20250722-iio-fix-iio_push_to_buffer_with_ts-typo-v1-1-6ac9efb856d3@baylibre.com Signed-off-by: Jonathan Cameron --- include/linux/iio/iio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index d11668f14a3e..2f5560646ee4 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -779,7 +779,7 @@ static inline void *iio_device_get_drvdata(const struct iio_dev *indio_dev) * them safe for use with non-coherent DMA. * * A number of drivers also use this on buffers that include a 64-bit timestamp - * that is used with iio_push_to_buffer_with_ts(). Therefore, in the case where + * that is used with iio_push_to_buffers_with_ts(). Therefore, in the case where * DMA alignment is not sufficient for proper timestamp alignment, we align to * 8 bytes instead. */ @@ -794,7 +794,7 @@ static inline void *iio_device_get_drvdata(const struct iio_dev *indio_dev) * @name: identifier name of the buffer * @count: number of elements in the buffer * - * Declares a buffer that is safe to use with iio_push_to_buffer_with_ts(). In + * Declares a buffer that is safe to use with iio_push_to_buffers_with_ts(). In * addition to allocating enough space for @count elements of @type, it also * allocates space for a s64 timestamp at the end of the buffer and ensures * proper alignment of the timestamp. From 5335f93d28143b6288ca6d8cec1f05b033c456c1 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 22 Jul 2025 14:35:02 -0500 Subject: [PATCH 0179/2711] iio: proximity: sx9500: use stack allocated struct for scan data Use a stack-allocated struct in sx9500_trigger_handler() to hold the IIO buffer scan data. Since the scan buffer isn't used outside of this function, it doesn't need to be in struct sx9500_data. By always allocating enough space for the maximum number of channels, we can avoid having to reallocate the buffer each time buffered reads are enabled. Signed-off-by: David Lechner Link: https://patch.msgid.link/20250722-iio-use-more-iio_declare_buffer_with_ts-4-v2-1-9e566f3a4c6a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9500.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 05844f17a15f..6c67bae7488c 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -88,7 +88,6 @@ struct sx9500_data { bool prox_stat[SX9500_NUM_CHANNELS]; bool event_enabled[SX9500_NUM_CHANNELS]; bool trigger_enabled; - u16 *buffer; /* Remember enabled channels and sample rate during suspend. */ unsigned int suspend_ctrl0; struct completion completion; @@ -578,22 +577,6 @@ out_unlock: return ret; } -static int sx9500_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) -{ - struct sx9500_data *data = iio_priv(indio_dev); - - mutex_lock(&data->mutex); - kfree(data->buffer); - data->buffer = kzalloc(indio_dev->scan_bytes, GFP_KERNEL); - mutex_unlock(&data->mutex); - - if (data->buffer == NULL) - return -ENOMEM; - - return 0; -} - static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( "2.500000 3.333333 5 6.666666 8.333333 11.111111 16.666666 33.333333"); @@ -612,7 +595,6 @@ static const struct iio_info sx9500_info = { .write_raw = &sx9500_write_raw, .read_event_config = &sx9500_read_event_config, .write_event_config = &sx9500_write_event_config, - .update_scan_mode = &sx9500_update_scan_mode, }; static int sx9500_set_trigger_state(struct iio_trigger *trig, @@ -649,6 +631,10 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private) struct iio_dev *indio_dev = pf->indio_dev; struct sx9500_data *data = iio_priv(indio_dev); int val, bit, ret, i = 0; + struct { + u16 chan[SX9500_NUM_CHANNELS]; + aligned_s64 timestamp; + } scan = { }; mutex_lock(&data->mutex); @@ -658,10 +644,10 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private) if (ret < 0) goto out; - data->buffer[i++] = val; + scan.chan[i++] = val; } - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev)); out: @@ -984,7 +970,6 @@ static void sx9500_remove(struct i2c_client *client) iio_triggered_buffer_cleanup(indio_dev); if (client->irq > 0) iio_trigger_unregister(data->trig); - kfree(data->buffer); } static int sx9500_suspend(struct device *dev) From c9100ef6db6ec437d2f64e294ae50a8ec4b16856 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 21 Jul 2025 17:21:08 -0500 Subject: [PATCH 0180/2711] iio: proximity: srf08: use stack allocated scan buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a stack allocated scan struct in srf08_trigger_handler(). Since the scan buffer isn't used outside of this function and doesn't need to be DMA-safe, it doesn't need to be in struct srf08_data. We can also eliminate an extra local variable for the return value of srf08_read_ranging() by using scan.chan directly. Reviewed-by: Andreas Klinger Signed-off-by: David Lechner Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250721-iio-use-more-iio_declare_buffer_with_ts-6-v2-1-8b66e5b4e75a@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/srf08.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c index 6e32fdfd161b..d7e4cc48cfbf 100644 --- a/drivers/iio/proximity/srf08.c +++ b/drivers/iio/proximity/srf08.c @@ -63,12 +63,6 @@ struct srf08_data { int range_mm; struct mutex lock; - /* Ensure timestamp is naturally aligned */ - struct { - s16 chan; - aligned_s64 timestamp; - } scan; - /* Sensor-Type */ enum srf08_sensor_type sensor_type; @@ -182,16 +176,18 @@ static irqreturn_t srf08_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct srf08_data *data = iio_priv(indio_dev); - s16 sensor_data; + struct { + s16 chan; + aligned_s64 timestamp; + } scan = { }; - sensor_data = srf08_read_ranging(data); - if (sensor_data < 0) + scan.chan = srf08_read_ranging(data); + if (scan.chan < 0) goto err; mutex_lock(&data->lock); - data->scan.chan = sensor_data; - iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), pf->timestamp); mutex_unlock(&data->lock); From 97b262d24ae28b1e86586a927c8be9df9747fb56 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 21 Jul 2025 18:16:34 -0500 Subject: [PATCH 0181/2711] iio: accel: bma180: use stack allocated buffer for scan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the scan struct to the stack instead of being in the driver state struct. The buffer is only used in a single function and does not need to be DMA-safe so it does not need to exist outside of that function's scope. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250721-iio-use-more-iio_declare_buffer_with_ts-v2-1-f8fb11b8add8@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 4fccbcb76e04..8925f5279e62 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -139,11 +139,6 @@ struct bma180_data { int scale; int bw; bool pmode; - /* Ensure timestamp is naturally aligned */ - struct { - s16 chan[4]; - aligned_s64 timestamp; - } scan; }; enum bma180_chan { @@ -870,6 +865,10 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) struct bma180_data *data = iio_priv(indio_dev); s64 time_ns = iio_get_time_ns(indio_dev); int bit, ret, i = 0; + struct { + s16 chan[4]; + aligned_s64 timestamp; + } scan = { }; mutex_lock(&data->mutex); @@ -879,12 +878,12 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) mutex_unlock(&data->mutex); goto err; } - data->scan.chan[i++] = ret; + scan.chan[i++] = ret; } mutex_unlock(&data->mutex); - iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), time_ns); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), time_ns); err: iio_trigger_notify_done(indio_dev->trig); From 972b1d5dee9eaa31ec8c20cfbea369f30bab416b Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 21 Jul 2025 17:12:47 -0500 Subject: [PATCH 0182/2711] iio: adc: ti-adc081c: use individual model structures instead of array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the ti-adc081c driver to use individual model structures instead of an array. This reduces the verbosity of the code. Also, the data is now const as it should have been in the first place. The ADCxx1C_MODEL() macro is dropped to be consistent with similar model definitions in other drivers. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250721-iio-const-data-11-v2-1-c3fec12511ee@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-adc081c.c | 40 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index 4f514db5c26e..8ef51c57912d 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -102,27 +102,23 @@ struct adcxx1c_model { int bits; }; -#define ADCxx1C_MODEL(_name, _bits) \ - { \ - .channels = _name ## _channels, \ - .bits = (_bits), \ - } - DEFINE_ADCxx1C_CHANNELS(adc081c, 8); DEFINE_ADCxx1C_CHANNELS(adc101c, 10); DEFINE_ADCxx1C_CHANNELS(adc121c, 12); -/* Model ids are indexes in _models array */ -enum adcxx1c_model_id { - ADC081C = 0, - ADC101C = 1, - ADC121C = 2, +static const struct adcxx1c_model adc081c_model = { + .channels = adc081c_channels, + .bits = 8, }; -static struct adcxx1c_model adcxx1c_models[] = { - ADCxx1C_MODEL(adc081c, 8), - ADCxx1C_MODEL(adc101c, 10), - ADCxx1C_MODEL(adc121c, 12), +static const struct adcxx1c_model adc101c_model = { + .channels = adc101c_channels, + .bits = 10, +}; + +static const struct adcxx1c_model adc121c_model = { + .channels = adc121c_channels, + .bits = 12, }; static const struct iio_info adc081c_info = { @@ -203,24 +199,24 @@ static int adc081c_probe(struct i2c_client *client) } static const struct i2c_device_id adc081c_id[] = { - { "adc081c", (kernel_ulong_t)&adcxx1c_models[ADC081C] }, - { "adc101c", (kernel_ulong_t)&adcxx1c_models[ADC101C] }, - { "adc121c", (kernel_ulong_t)&adcxx1c_models[ADC121C] }, + { "adc081c", (kernel_ulong_t)&adc081c_model }, + { "adc101c", (kernel_ulong_t)&adc101c_model }, + { "adc121c", (kernel_ulong_t)&adc121c_model }, { } }; MODULE_DEVICE_TABLE(i2c, adc081c_id); static const struct acpi_device_id adc081c_acpi_match[] = { /* Used on some AAEON boards */ - { "ADC081C", (kernel_ulong_t)&adcxx1c_models[ADC081C] }, + { "ADC081C", (kernel_ulong_t)&adc081c_model }, { } }; MODULE_DEVICE_TABLE(acpi, adc081c_acpi_match); static const struct of_device_id adc081c_of_match[] = { - { .compatible = "ti,adc081c", .data = &adcxx1c_models[ADC081C] }, - { .compatible = "ti,adc101c", .data = &adcxx1c_models[ADC101C] }, - { .compatible = "ti,adc121c", .data = &adcxx1c_models[ADC121C] }, + { .compatible = "ti,adc081c", .data = &adc081c_model }, + { .compatible = "ti,adc101c", .data = &adc101c_model }, + { .compatible = "ti,adc121c", .data = &adc121c_model }, { } }; MODULE_DEVICE_TABLE(of, adc081c_of_match); From cddbb2f9e46e08968089ee21cb9bc80ad7306140 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jul 2025 11:47:43 +0100 Subject: [PATCH 0183/2711] iio: magnetometer: Fix spelling mistake "Magenetometer" -> "Magnetometer" There is a spelling mistake in the HID_SENSOR_MAGNETOMETER_3D Kconfig, fix it. Signed-off-by: Colin Ian King Link: https://patch.msgid.link/20250724104743.139892-1-colin.i.king@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 3debf1320ad1..c7809e5aa3a4 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -123,7 +123,7 @@ config HID_SENSOR_MAGNETOMETER_3D select IIO_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER - tristate "HID Magenetometer 3D" + tristate "HID Magnetometer 3D" help Say yes here to build support for the HID SENSOR Magnetometer 3D. From 07306551cb76d61b02391d26a2e85c7711e92e1c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 24 Jul 2025 13:13:46 +0200 Subject: [PATCH 0184/2711] dt-bindings: iio: Drop unused header includes in examples Drop includes of headers which example code does not use. No functional impact. Signed-off-by: Krzysztof Kozlowski Reviewed-by: David Heidelberg Acked-by: Matti Vaittinen Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250724111345.47889-5-krzysztof.kozlowski@linaro.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml | 1 - Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml | 2 -- Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml | 2 -- Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml | 2 -- Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml | 2 -- Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml | 1 - Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml | 1 - Documentation/devicetree/bindings/iio/accel/kionix,kxsd9.yaml | 1 - Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml | 1 - Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml | 1 - Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml | 1 - Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml | 1 - Documentation/devicetree/bindings/iio/adc/ti,adc128s052.yaml | 1 - Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml | 1 - Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml | 1 - .../devicetree/bindings/iio/imu/invensense,icm42600.yaml | 2 -- Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml | 2 -- Documentation/devicetree/bindings/iio/light/st,vl6180.yaml | 1 - .../bindings/iio/magnetometer/voltafield,af8133j.yaml | 1 - Documentation/devicetree/bindings/iio/pressure/bmp085.yaml | 1 - 20 files changed, 26 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml index 5887021cc90f..3dc973b98f81 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml @@ -37,7 +37,6 @@ unevaluatedProperties: false examples: - | - #include #include spi { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml index 0c5b64cae965..3a8c69eecfde 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml @@ -57,7 +57,6 @@ unevaluatedProperties: false examples: - | - #include #include i2c { #address-cells = <1>; @@ -73,7 +72,6 @@ examples: }; }; - | - #include #include spi { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml index 84d949392012..a23a626bfab6 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml @@ -56,7 +56,6 @@ unevaluatedProperties: false examples: - | - #include #include i2c { #address-cells = <1>; @@ -72,7 +71,6 @@ examples: }; }; - | - #include #include spi { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml index c07261c71013..f39e2912731f 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml @@ -58,7 +58,6 @@ unevaluatedProperties: false examples: - | - #include #include i2c { #address-cells = <1>; @@ -74,7 +73,6 @@ examples: }; }; - | - #include #include spi { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml index 62465e36a590..88aa67bf2280 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml @@ -37,7 +37,6 @@ unevaluatedProperties: false examples: - | - #include #include i2c { #address-cells = <1>; @@ -52,7 +51,6 @@ examples: }; }; - | - #include #include spi { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml b/Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml index 457a709b583c..85c9537f1f02 100644 --- a/Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml +++ b/Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml @@ -107,7 +107,6 @@ examples: }; }; - | - # include spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml b/Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml index 8723a336229e..c5fedcf998f2 100644 --- a/Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml +++ b/Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml @@ -40,7 +40,6 @@ additionalProperties: false examples: - | - #include #include i2c { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/accel/kionix,kxsd9.yaml b/Documentation/devicetree/bindings/iio/accel/kionix,kxsd9.yaml index f64d99b35492..53de921768ac 100644 --- a/Documentation/devicetree/bindings/iio/accel/kionix,kxsd9.yaml +++ b/Documentation/devicetree/bindings/iio/accel/kionix,kxsd9.yaml @@ -57,7 +57,6 @@ examples: }; }; - | - # include spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml index ddec9747436c..705adbe88def 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml @@ -93,7 +93,6 @@ unevaluatedProperties: false examples: - | - #include #include i2c { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml index 21ee319d4675..62d906e24997 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml @@ -379,7 +379,6 @@ unevaluatedProperties: false examples: # Example AD7173-8 with external reference connected to REF+/REF-: - | - #include #include spi { diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml index c28db0d635a0..b9dc04b0d307 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml @@ -278,7 +278,6 @@ examples: - | #include #include - #include pmic { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml b/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml index 2a8ad4fdfc6b..f0a1347ba4db 100644 --- a/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml +++ b/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml @@ -50,7 +50,6 @@ unevaluatedProperties: false examples: - | - #include spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/adc/ti,adc128s052.yaml b/Documentation/devicetree/bindings/iio/adc/ti,adc128s052.yaml index 775eee972b12..044b66a3b00c 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti,adc128s052.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ti,adc128s052.yaml @@ -44,7 +44,6 @@ unevaluatedProperties: false examples: - | - #include spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml index bf5a43a81d59..71f9f9b745cb 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml @@ -59,7 +59,6 @@ unevaluatedProperties: false examples: - | - #include #include spi { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml index 4cacc9948726..3a725ece7ec4 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml @@ -44,7 +44,6 @@ unevaluatedProperties: false examples: - | - #include #include spi { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml index d4d4e5c3d856..119e28a833fd 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -74,7 +74,6 @@ unevaluatedProperties: false examples: - | - #include #include i2c { #address-cells = <1>; @@ -91,7 +90,6 @@ examples: }; }; - | - #include #include spi { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml b/Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml index 688100b240bc..2930b3386703 100644 --- a/Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml +++ b/Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml @@ -47,7 +47,6 @@ unevaluatedProperties: false examples: - | - #include #include i2c { #address-cells = <1>; @@ -63,7 +62,6 @@ examples: }; }; - | - #include #include spi { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/light/st,vl6180.yaml b/Documentation/devicetree/bindings/iio/light/st,vl6180.yaml index 27c36ab7990d..8598fb631aac 100644 --- a/Documentation/devicetree/bindings/iio/light/st,vl6180.yaml +++ b/Documentation/devicetree/bindings/iio/light/st,vl6180.yaml @@ -32,7 +32,6 @@ required: examples: - | - #include i2c { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml b/Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml index b6ab01a6914a..ed42dc5afb99 100644 --- a/Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml +++ b/Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml @@ -44,7 +44,6 @@ additionalProperties: false examples: - | - #include #include i2c { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml b/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml index 706b7e24f182..b9ea37317b53 100644 --- a/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml +++ b/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml @@ -109,7 +109,6 @@ examples: }; - | # include - # include spi { #address-cells = <1>; #size-cells = <0>; From 1c3e87983cf0d71139afe88db440e3a42ea34ebe Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 24 Jul 2025 13:13:47 +0200 Subject: [PATCH 0185/2711] dt-bindings: iio: adc: Replace hard-coded GPIO/IRQ flag with a define For readability use known defines instead of hard-coding GPIO or interrupt flag. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Acked-by: Matti Vaittinen Link: https://patch.msgid.link/20250724111345.47889-6-krzysztof.kozlowski@linaro.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml | 2 +- Documentation/devicetree/bindings/iio/adc/rohm,bd79124.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml index ef8d51e74c08..592854766583 100644 --- a/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml +++ b/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml @@ -63,6 +63,6 @@ examples: vdd-supply = <&adc_vdd>; vref-supply = <&adc_vref>; spi-max-frequency = <1000000>; - shutdown-gpios = <&gpio 26 1>; + shutdown-gpios = <&gpio 26 GPIO_ACTIVE_LOW>; }; }; diff --git a/Documentation/devicetree/bindings/iio/adc/rohm,bd79124.yaml b/Documentation/devicetree/bindings/iio/adc/rohm,bd79124.yaml index 503285823376..4a8f127de7e3 100644 --- a/Documentation/devicetree/bindings/iio/adc/rohm,bd79124.yaml +++ b/Documentation/devicetree/bindings/iio/adc/rohm,bd79124.yaml @@ -81,7 +81,7 @@ examples: reg = <0x10>; interrupt-parent = <&gpio1>; - interrupts = <29 8>; + interrupts = <29 IRQ_TYPE_LEVEL_LOW>; vdd-supply = <&dummyreg>; iovdd-supply = <&dummyreg>; From 971255565074b160d5d05d6b0d9e6f70cbb7c4a9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 24 Jul 2025 13:13:48 +0200 Subject: [PATCH 0186/2711] dt-bindings: iio: adc: samsung,exynos-adc: Use correct IRQ level in example The interrupt line to GIC is IRQ_TYPE_LEVEL_HIGH, so use that instead of "none". Also replace the hard-coded GIC_SPI flag. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Alim Akhtar Reviewed-by: Sam Protsenko Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250724111345.47889-7-krzysztof.kozlowski@linaro.org Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/samsung,exynos-adc.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml index 4e40f6bed5db..8069e99ddac8 100644 --- a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml @@ -128,10 +128,12 @@ allOf: examples: - | + #include + adc: adc@12d10000 { compatible = "samsung,exynos-adc-v1"; reg = <0x12d10000 0x100>; - interrupts = <0 106 0>; + interrupts = ; #io-channel-cells = <1>; clocks = <&clock 303>; @@ -152,11 +154,12 @@ examples: - | #include + #include adc@126c0000 { compatible = "samsung,exynos3250-adc"; reg = <0x126c0000 0x100>; - interrupts = <0 137 0>; + interrupts = ; #io-channel-cells = <1>; clocks = <&cmu CLK_TSADC>, From 0a84f5105b405d8506707d244f225b040dfb04f4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 24 Jul 2025 13:13:49 +0200 Subject: [PATCH 0187/2711] dt-bindings: iio: light: Simplify interrupts property in the example dynaimage,al3010 and dynaimage,al3320a are I2C devices, so their interrupts are not routed to GIC and rarely first interrupt cell is <0>. This looks like copy-paste from some SoC block, so drop it and also for readability use known defines instead of hard-coding interrupt flag. Signed-off-by: Krzysztof Kozlowski Reviewed-by: David Heidelberg Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250724111345.47889-8-krzysztof.kozlowski@linaro.org Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/light/dynaimage,al3010.yaml | 2 +- .../devicetree/bindings/iio/light/dynaimage,al3320a.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/light/dynaimage,al3010.yaml b/Documentation/devicetree/bindings/iio/light/dynaimage,al3010.yaml index f1048c30e73e..1472c997c16f 100644 --- a/Documentation/devicetree/bindings/iio/light/dynaimage,al3010.yaml +++ b/Documentation/devicetree/bindings/iio/light/dynaimage,al3010.yaml @@ -42,6 +42,6 @@ examples: compatible = "dynaimage,al3010"; reg = <0x1c>; vdd-supply = <&vdd_reg>; - interrupts = <0 99 4>; + interrupts = <99 IRQ_TYPE_LEVEL_HIGH>; }; }; diff --git a/Documentation/devicetree/bindings/iio/light/dynaimage,al3320a.yaml b/Documentation/devicetree/bindings/iio/light/dynaimage,al3320a.yaml index 8249be99cff9..d06db737cd9e 100644 --- a/Documentation/devicetree/bindings/iio/light/dynaimage,al3320a.yaml +++ b/Documentation/devicetree/bindings/iio/light/dynaimage,al3320a.yaml @@ -40,6 +40,6 @@ examples: compatible = "dynaimage,al3320a"; reg = <0x1c>; vdd-supply = <&vdd_reg>; - interrupts = <0 99 4>; + interrupts = <99 IRQ_TYPE_LEVEL_HIGH>; }; }; From 49baeed7b3ba82a10749fefdb6144a3817b7ad75 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 21 Jul 2025 16:03:09 +0100 Subject: [PATCH 0188/2711] iio: light: vl6180: remove space before \n newline There is an extraneous space before a newline in a dev_err_probe message. Remove it. Signed-off-by: Colin Ian King Link: https://patch.msgid.link/20250721150310.2601679-1-colin.i.king@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/vl6180.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index cc4f2e5404aa..38706424089c 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -722,7 +722,7 @@ static int vl6180_probe(struct i2c_client *client) IRQF_ONESHOT, indio_dev->name, indio_dev); if (ret) - return dev_err_probe(&client->dev, ret, "devm_request_irq error \n"); + return dev_err_probe(&client->dev, ret, "devm_request_irq error\n"); init_completion(&data->completion); From 9ae68c9bb12a3a6cc7df59f9ee3ff5879d97cda9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 13 Jul 2025 17:59:55 +0200 Subject: [PATCH 0189/2711] iio: adc: ti-adc12138: Simplify with devm_clk_get_enabled() Driver is getting clock and almost immediately enabling it, with the devm_request_irq() as the only relevant code executed between, thus the probe path and cleanups can be simplified with devm_clk_get_enabled(). Move devm_request_irq() earlier, so the interrupt handler will be registered before clock is enabled. This might be important in case regulator supplies are enabled by other device driver and this device raises interrupt immediately after clock sarts ticking. The change does not reverse cleanup paths - first regulator will be disabled, then clock and finally interrupt handler freed. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250713-iio-clk-get-enabled-v1-1-70abc1f9ce6c@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-adc12138.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/iio/adc/ti-adc12138.c b/drivers/iio/adc/ti-adc12138.c index 9dc465a10ffc..e5ec4b073daa 100644 --- a/drivers/iio/adc/ti-adc12138.c +++ b/drivers/iio/adc/ti-adc12138.c @@ -38,15 +38,13 @@ enum { struct adc12138 { struct spi_device *spi; unsigned int id; - /* conversion clock */ - struct clk *cclk; /* positive analog voltage reference */ struct regulator *vref_p; /* negative analog voltage reference */ struct regulator *vref_n; struct mutex lock; struct completion complete; - /* The number of cclk periods for the S/H's acquisition time */ + /* The number of conversion clock periods for the S/H's acquisition time */ unsigned int acquisition_time; /* * Maximum size needed: 16x 2 bytes ADC data + 8 bytes timestamp. @@ -400,6 +398,7 @@ static int adc12138_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct adc12138 *adc; + struct clk *cclk; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); @@ -435,9 +434,14 @@ static int adc12138_probe(struct spi_device *spi) if (ret) adc->acquisition_time = 10; - adc->cclk = devm_clk_get(&spi->dev, NULL); - if (IS_ERR(adc->cclk)) - return PTR_ERR(adc->cclk); + ret = devm_request_irq(&spi->dev, spi->irq, adc12138_eoc_handler, + IRQF_TRIGGER_RISING, indio_dev->name, indio_dev); + if (ret) + return ret; + + cclk = devm_clk_get_enabled(&spi->dev, NULL); + if (IS_ERR(cclk)) + return PTR_ERR(cclk); adc->vref_p = devm_regulator_get(&spi->dev, "vref-p"); if (IS_ERR(adc->vref_p)) @@ -454,18 +458,9 @@ static int adc12138_probe(struct spi_device *spi) return ret; } - ret = devm_request_irq(&spi->dev, spi->irq, adc12138_eoc_handler, - IRQF_TRIGGER_RISING, indio_dev->name, indio_dev); - if (ret) - return ret; - - ret = clk_prepare_enable(adc->cclk); - if (ret) - return ret; - ret = regulator_enable(adc->vref_p); if (ret) - goto err_clk_disable; + return ret; if (!IS_ERR(adc->vref_n)) { ret = regulator_enable(adc->vref_n); @@ -496,8 +491,6 @@ err_vref_n_disable: regulator_disable(adc->vref_n); err_vref_p_disable: regulator_disable(adc->vref_p); -err_clk_disable: - clk_disable_unprepare(adc->cclk); return ret; } @@ -512,7 +505,6 @@ static void adc12138_remove(struct spi_device *spi) if (!IS_ERR(adc->vref_n)) regulator_disable(adc->vref_n); regulator_disable(adc->vref_p); - clk_disable_unprepare(adc->cclk); } static const struct of_device_id adc12138_dt_ids[] = { From 329cb8be151948d3462a99f204725dcbdeb61623 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 10 Jul 2025 17:22:00 -0500 Subject: [PATCH 0190/2711] iio: adc: ad7173: add SPI offload support Enable SPI offload support for the AD7173 ADC driver. The scan_type used for SPI offload is assuming that we are using the ad411x_ad717x HDL project [1] which always stores data words in 32-bits. Link: https://analogdevicesinc.github.io/hdl/projects/ad411x_ad717x/index.html [1] Reviewed-by: Andy Shevchenko Signed-off-by: David Lechner Link: https://patch.msgid.link/20250710-iio-adc-ad7173-add-spi-offload-support-v4-1-536857c4e043@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 4413207be28f..9a32a18cc804 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -746,6 +746,7 @@ static const struct ad_sigma_delta_info ad7173_sigma_delta_info_4_slots = { .set_mode = ad7173_set_mode, .has_registers = true, .has_named_irqs = true, + .supports_spi_offload = true, .addr_shift = 0, .read_mask = BIT(6), .status_ch_mask = GENMASK(3, 0), @@ -762,6 +763,7 @@ static const struct ad_sigma_delta_info ad7173_sigma_delta_info_8_slots = { .set_mode = ad7173_set_mode, .has_registers = true, .has_named_irqs = true, + .supports_spi_offload = true, .addr_shift = 0, .read_mask = BIT(6), .status_ch_mask = GENMASK(3, 0), @@ -778,6 +780,7 @@ static const struct ad_sigma_delta_info ad7173_sigma_delta_info_16_slots = { .set_mode = ad7173_set_mode, .has_registers = true, .has_named_irqs = true, + .supports_spi_offload = true, .addr_shift = 0, .read_mask = BIT(6), .status_ch_mask = GENMASK(3, 0), @@ -1595,6 +1598,11 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) if (st->info->data_reg_only_16bit) chan_arr[chan_index].scan_type = ad4113_scan_type; + if (ad_sigma_delta_has_spi_offload(&st->sd)) { + chan_arr[chan_index].scan_type.storagebits = 32; + chan_arr[chan_index].scan_type.endianness = IIO_CPU; + } + chan_index++; } @@ -1685,6 +1693,12 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) if (st->info->data_reg_only_16bit) chan_arr[chan_index].scan_type = ad4113_scan_type; + /* Assuming SPI offload is ad411x_ad717x HDL project. */ + if (ad_sigma_delta_has_spi_offload(&st->sd)) { + chan_arr[chan_index].scan_type.storagebits = 32; + chan_arr[chan_index].scan_type.endianness = IIO_CPU; + } + chan_index++; } return 0; From e4be2f593daba5881ad65e1ed1d5924b7248ff75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 25 Jul 2025 07:32:55 +0100 Subject: [PATCH 0191/2711] iio: buffer: buffer-cb: drop double initialization of demux list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the call to INIT_LIST_HEAD(&cb_buff->buffer.demux_list). That's already done in iio_buffer_init(&cb_buff->buffer). Signed-off-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250725-iio-minor-cleanup-v1-1-4e561372142e@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-cb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c index 4befc9f55201..3e27385069ed 100644 --- a/drivers/iio/buffer/industrialio-buffer-cb.c +++ b/drivers/iio/buffer/industrialio-buffer-cb.c @@ -68,7 +68,6 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, cb_buff->private = private; cb_buff->cb = cb; cb_buff->buffer.access = &iio_cb_access; - INIT_LIST_HEAD(&cb_buff->buffer.demux_list); cb_buff->channels = iio_channel_get_all(dev); if (IS_ERR(cb_buff->channels)) { From 33c52b2d85b7c04386b1dda1428c0160ec29169e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 10 Jul 2025 17:39:53 -0500 Subject: [PATCH 0192/2711] iio: ABI: alphabetize filter types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put the filter types in alphabetical order by name. This makes it easier to find a specific filter type when looking through the documentation. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250710-iio-adc-ad7137-add-filter-support-v1-4-acffe401c4d2@baylibre.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 7e31b8cd49b3..2fb2cea4b192 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -2281,21 +2281,21 @@ Description: conversion time. Poor noise performance. * "sinc3" - The digital sinc3 filter. Moderate 1st conversion time. Good noise performance. - * "sinc4" - Sinc 4. Excellent noise performance. Long - 1st conversion time. - * "sinc5" - The digital sinc5 filter. Excellent noise - performance - * "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion - time. - * "sinc3+rej60" - Sinc3 + 60Hz rejection. - * "sinc3+sinc1" - Sinc3 + averaging by 8. Low 1st conversion - time. * "sinc3+pf1" - Sinc3 + device specific Post Filter 1. * "sinc3+pf2" - Sinc3 + device specific Post Filter 2. * "sinc3+pf3" - Sinc3 + device specific Post Filter 3. * "sinc3+pf4" - Sinc3 + device specific Post Filter 4. - * "sinc5+pf1" - Sinc5 + device specific Post Filter 1. + * "sinc3+rej60" - Sinc3 + 60Hz rejection. + * "sinc3+sinc1" - Sinc3 + averaging by 8. Low 1st conversion + time. + * "sinc4" - Sinc 4. Excellent noise performance. Long + 1st conversion time. + * "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion + time. + * "sinc5" - The digital sinc5 filter. Excellent noise + performance * "sinc5+avg" - Sinc5 + averaging by 4. + * "sinc5+pf1" - Sinc5 + device specific Post Filter 1. * "wideband" - filter with wideband low ripple passband and sharp transition band. From 9da51431c33230a46fec5ddc0a7a3a848c393f7b Mon Sep 17 00:00:00 2001 From: Akshay Jindal Date: Mon, 28 Jul 2025 21:44:41 +0530 Subject: [PATCH 0193/2711] iio: light: ltr390: Add debugfs register access support Add support for debugfs_reg_access through the driver's iio_info structure to enable low-level register read/write access for debugging. Signed-off-by: Akshay Jindal Link: https://patch.msgid.link/20250728161445.13261-1-akshayaj.lkd@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/ltr390.c | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c index ee59bbb8aa09..7733830dca67 100644 --- a/drivers/iio/light/ltr390.c +++ b/drivers/iio/light/ltr390.c @@ -38,12 +38,21 @@ #define LTR390_ALS_UVS_GAIN 0x05 #define LTR390_PART_ID 0x06 #define LTR390_MAIN_STATUS 0x07 + #define LTR390_ALS_DATA 0x0D +#define LTR390_ALS_DATA_BYTE(n) (LTR390_ALS_DATA + (n)) + #define LTR390_UVS_DATA 0x10 +#define LTR390_UVS_DATA_BYTE(n) (LTR390_UVS_DATA + (n)) + #define LTR390_INT_CFG 0x19 #define LTR390_INT_PST 0x1A + #define LTR390_THRESH_UP 0x21 +#define LTR390_THRESH_UP_BYTE(n) (LTR390_THRESH_UP + (n)) + #define LTR390_THRESH_LOW 0x24 +#define LTR390_THRESH_LOW_BYTE(n) (LTR390_THRESH_LOW + (n)) #define LTR390_PART_NUMBER_ID 0xb #define LTR390_ALS_UVS_GAIN_MASK GENMASK(2, 0) @@ -98,11 +107,39 @@ struct ltr390_data { int int_time_us; }; +static const struct regmap_range ltr390_readable_reg_ranges[] = { + regmap_reg_range(LTR390_MAIN_CTRL, LTR390_MAIN_CTRL), + regmap_reg_range(LTR390_ALS_UVS_MEAS_RATE, LTR390_MAIN_STATUS), + regmap_reg_range(LTR390_ALS_DATA_BYTE(0), LTR390_UVS_DATA_BYTE(2)), + regmap_reg_range(LTR390_INT_CFG, LTR390_INT_PST), + regmap_reg_range(LTR390_THRESH_UP_BYTE(0), LTR390_THRESH_LOW_BYTE(2)), +}; + +static const struct regmap_access_table ltr390_readable_reg_table = { + .yes_ranges = ltr390_readable_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(ltr390_readable_reg_ranges), +}; + +static const struct regmap_range ltr390_writeable_reg_ranges[] = { + regmap_reg_range(LTR390_MAIN_CTRL, LTR390_MAIN_CTRL), + regmap_reg_range(LTR390_ALS_UVS_MEAS_RATE, LTR390_ALS_UVS_GAIN), + regmap_reg_range(LTR390_INT_CFG, LTR390_INT_PST), + regmap_reg_range(LTR390_THRESH_UP_BYTE(0), LTR390_THRESH_LOW_BYTE(2)), +}; + +static const struct regmap_access_table ltr390_writeable_reg_table = { + .yes_ranges = ltr390_writeable_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(ltr390_writeable_reg_ranges), +}; + static const struct regmap_config ltr390_regmap_config = { .name = "ltr390", .reg_bits = 8, .reg_stride = 1, .val_bits = 8, + .max_register = LTR390_THRESH_LOW_BYTE(2), + .rd_table = <r390_readable_reg_table, + .wr_table = <r390_writeable_reg_table, }; /* Sampling frequency is in mili Hz and mili Seconds */ @@ -586,6 +623,20 @@ static int ltr390_write_event_config(struct iio_dev *indio_dev, } } +static int ltr390_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, unsigned int writeval, + unsigned int *readval) +{ + struct ltr390_data *data = iio_priv(indio_dev); + + guard(mutex)(&data->lock); + + if (readval) + return regmap_read(data->regmap, reg, readval); + + return regmap_write(data->regmap, reg, writeval); +} + static const struct iio_info ltr390_info = { .read_raw = ltr390_read_raw, .write_raw = ltr390_write_raw, @@ -594,6 +645,7 @@ static const struct iio_info ltr390_info = { .read_event_config = ltr390_read_event_config, .write_event_value = ltr390_write_event_value, .write_event_config = ltr390_write_event_config, + .debugfs_reg_access = ltr390_debugfs_reg_access, }; static irqreturn_t ltr390_interrupt_handler(int irq, void *private) From 73c8b83b4aedae07b3c45379fe14be5a2734cbca Mon Sep 17 00:00:00 2001 From: Rodrigo Gobbi Date: Fri, 1 Aug 2025 19:10:00 -0300 Subject: [PATCH 0194/2711] dt-bindings: iio: pressure: add invensense,icp10100 There is no txt file for it, add yaml for invensense,icp10100 which is already used in the driver. Also, document other compatibles for ICP-101xx family and add invensense,icp10100 as a fallback. Acked-by: Jean-Baptiste Maneyrol Signed-off-by: Rodrigo Gobbi Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250801221424.132305-1-rodrigo.gobbi.7@gmail.com Signed-off-by: Jonathan Cameron --- .../iio/pressure/invensense,icp10100.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/pressure/invensense,icp10100.yaml diff --git a/Documentation/devicetree/bindings/iio/pressure/invensense,icp10100.yaml b/Documentation/devicetree/bindings/iio/pressure/invensense,icp10100.yaml new file mode 100644 index 000000000000..5d980aa04bb3 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/pressure/invensense,icp10100.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/pressure/invensense,icp10100.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: InvenSense ICP-101xx Barometric Pressure Sensors + +maintainers: + - Jean-Baptiste Maneyrol + +description: | + Support for ICP-101xx family: ICP-10100, ICP-10101, ICP-10110, ICP-10111. + Those devices uses a simple I2C communication bus, measuring the pressure + in a ultra-low noise at the lowest power. + Datasheet: https://product.tdk.com/system/files/dam/doc/product/sensor/pressure/capacitive-pressure/data_sheet/ds-000186-icp-101xx.pdf + +properties: + compatible: + oneOf: + - items: + - enum: + - invensense,icp10101 + - invensense,icp10110 + - invensense,icp10111 + - const: invensense,icp10100 + - const: invensense,icp10100 + + reg: + maxItems: 1 + + vdd-supply: true + +required: + - compatible + - reg + - vdd-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + pressure@63 { + compatible = "invensense,icp10101", "invensense,icp10100"; + reg = <0x63>; + vdd-supply = <&vdd_1v8>; + }; + }; +... From c6eac16025eb9760132b5cc5e70d9ae109801593 Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Sun, 27 Jul 2025 21:00:08 +0000 Subject: [PATCH 0195/2711] iio: accel: adxl345: simplify tap suppress bit Simplify setting the tap suppress bit by applying regmap_assign_bit(). As a result, the defines can be reorganized for better clarity. Signed-off-by: Lothar Rubusch Link: https://patch.msgid.link/20250727210014.27766-2-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index b7dfd0007aa0..e293fc917972 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -34,12 +34,10 @@ #define ADXL345_INT2 1 #define ADXL345_REG_TAP_AXIS_MSK GENMASK(2, 0) -#define ADXL345_REG_TAP_SUPPRESS_MSK BIT(3) -#define ADXL345_REG_TAP_SUPPRESS BIT(3) - #define ADXL345_TAP_Z_EN BIT(0) #define ADXL345_TAP_Y_EN BIT(1) #define ADXL345_TAP_X_EN BIT(2) +#define ADXL345_REG_TAP_SUPPRESS BIT(3) /* single/double tap */ enum adxl345_tap_type { @@ -368,9 +366,8 @@ static int adxl345_set_doubletap_en(struct adxl345_state *st, bool en) * Generally suppress detection of spikes during the latency period as * double taps here, this is fully optional for double tap detection */ - ret = regmap_update_bits(st->regmap, ADXL345_REG_TAP_AXIS, - ADXL345_REG_TAP_SUPPRESS_MSK, - en ? ADXL345_REG_TAP_SUPPRESS : 0x00); + ret = regmap_assign_bits(st->regmap, ADXL345_REG_TAP_AXIS, + ADXL345_REG_TAP_SUPPRESS, en); if (ret) return ret; From 66a1af6d8a636bc7f6bb5ee0ae6b8d4b12631280 Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Sun, 27 Jul 2025 21:00:09 +0000 Subject: [PATCH 0196/2711] iio: accel: adxl345: add activity event feature Enable the sensor to detect activity and trigger interrupts accordingly. Activity events are determined based on a threshold, which is initialized to a sensible default during probe. This default value is adopted from the legacy ADXL345 input driver to maintain consistent behavior. The combination of activity detection, ODR configuration, and range settings lays the groundwork for the activity/inactivity hysteresis mechanism, which will be implemented in a subsequent patch. As such, portions of this patch prepare switch-case structures to support those upcoming changes. Signed-off-by: Lothar Rubusch Link: https://patch.msgid.link/20250727210014.27766-3-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 240 ++++++++++++++++++++++++++++++- 1 file changed, 238 insertions(+), 2 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index e293fc917972..8ff1784403ba 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -39,6 +39,11 @@ #define ADXL345_TAP_X_EN BIT(2) #define ADXL345_REG_TAP_SUPPRESS BIT(3) +#define ADXL345_ACT_Z_EN BIT(4) +#define ADXL345_ACT_Y_EN BIT(5) +#define ADXL345_ACT_X_EN BIT(6) +#define ADXL345_ACT_XYZ_EN (ADXL345_ACT_Z_EN | ADXL345_ACT_Y_EN | ADXL345_ACT_X_EN) + /* single/double tap */ enum adxl345_tap_type { ADXL345_SINGLE_TAP, @@ -62,6 +67,19 @@ static const unsigned int adxl345_tap_time_reg[] = { [ADXL345_TAP_TIME_DUR] = ADXL345_REG_DUR, }; +/* activity/inactivity */ +enum adxl345_activity_type { + ADXL345_ACTIVITY, +}; + +static const unsigned int adxl345_act_int_reg[] = { + [ADXL345_ACTIVITY] = ADXL345_INT_ACTIVITY, +}; + +static const unsigned int adxl345_act_thresh_reg[] = { + [ADXL345_ACTIVITY] = ADXL345_REG_THRESH_ACT, +}; + enum adxl345_odr { ADXL345_ODR_0P10HZ = 0, ADXL345_ODR_0P20HZ, @@ -142,6 +160,14 @@ struct adxl345_state { }; static const struct iio_event_spec adxl345_events[] = { + { + /* activity */ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_type = + BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE), + }, { /* single tap */ .type = IIO_EV_TYPE_GESTURE, @@ -235,6 +261,87 @@ static int adxl345_set_measure_en(struct adxl345_state *st, bool en) ADXL345_POWER_CTL_MEASURE, en); } +/* activity / inactivity */ + +static int adxl345_is_act_inact_en(struct adxl345_state *st, + enum adxl345_activity_type type) +{ + unsigned int axis_ctrl; + unsigned int regval; + bool en; + int ret; + + ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, &axis_ctrl); + if (ret) + return ret; + + /* Check if axis for activity are enabled */ + switch (type) { + case ADXL345_ACTIVITY: + en = FIELD_GET(ADXL345_ACT_XYZ_EN, axis_ctrl); + if (!en) + return false; + break; + default: + return -EINVAL; + } + + /* Check if specific interrupt is enabled */ + ret = regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, ®val); + if (ret) + return ret; + + return adxl345_act_int_reg[type] & regval; +} + +static int adxl345_set_act_inact_en(struct adxl345_state *st, + enum adxl345_activity_type type, + bool cmd_en) +{ + unsigned int axis_ctrl; + unsigned int threshold; + int ret; + + if (cmd_en) { + /* When turning on, check if threshold is valid */ + ret = regmap_read(st->regmap, + adxl345_act_thresh_reg[type], + &threshold); + if (ret) + return ret; + + if (!threshold) /* Just ignore the command if threshold is 0 */ + return 0; + } + + /* Start modifying configuration registers */ + ret = adxl345_set_measure_en(st, false); + if (ret) + return ret; + + /* Enable axis according to the command */ + switch (type) { + case ADXL345_ACTIVITY: + axis_ctrl = ADXL345_ACT_XYZ_EN; + break; + default: + return -EINVAL; + } + + ret = regmap_assign_bits(st->regmap, ADXL345_REG_ACT_INACT_CTRL, + axis_ctrl, cmd_en); + if (ret) + return ret; + + /* Enable the interrupt line, according to the command */ + ret = regmap_assign_bits(st->regmap, ADXL345_REG_INT_ENABLE, + adxl345_act_int_reg[type], cmd_en); + if (ret) + return ret; + + return adxl345_set_measure_en(st, true); +} + /* tap */ static int _adxl345_set_tap_int(struct adxl345_state *st, @@ -621,6 +728,31 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, return adxl345_set_measure_en(st, true); } +static int adxl345_read_mag_config(struct adxl345_state *st, + enum iio_event_direction dir, + enum adxl345_activity_type type_act) +{ + switch (dir) { + case IIO_EV_DIR_RISING: + return !!adxl345_is_act_inact_en(st, type_act); + default: + return -EINVAL; + } +} + +static int adxl345_write_mag_config(struct adxl345_state *st, + enum iio_event_direction dir, + enum adxl345_activity_type type_act, + bool state) +{ + switch (dir) { + case IIO_EV_DIR_RISING: + return adxl345_set_act_inact_en(st, type_act, state); + default: + return -EINVAL; + } +} + static int adxl345_read_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, @@ -631,6 +763,9 @@ static int adxl345_read_event_config(struct iio_dev *indio_dev, int ret; switch (type) { + case IIO_EV_TYPE_MAG: + return adxl345_read_mag_config(st, dir, + ADXL345_ACTIVITY); case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -662,6 +797,10 @@ static int adxl345_write_event_config(struct iio_dev *indio_dev, struct adxl345_state *st = iio_priv(indio_dev); switch (type) { + case IIO_EV_TYPE_MAG: + return adxl345_write_mag_config(st, dir, + ADXL345_ACTIVITY, + state); case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -676,6 +815,58 @@ static int adxl345_write_event_config(struct iio_dev *indio_dev, } } +static int adxl345_read_mag_value(struct adxl345_state *st, + enum iio_event_direction dir, + enum iio_event_info info, + enum adxl345_activity_type type_act, + int *val, int *val2) +{ + unsigned int threshold; + int ret; + + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + ret = regmap_read(st->regmap, + adxl345_act_thresh_reg[type_act], + &threshold); + if (ret) + return ret; + *val = 62500 * threshold; + *val2 = MICRO; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int adxl345_write_mag_value(struct adxl345_state *st, + enum iio_event_direction dir, + enum iio_event_info info, + enum adxl345_activity_type type_act, + int val, int val2) +{ + switch (info) { + case IIO_EV_INFO_VALUE: + /* Scaling factor 62.5mg/LSB, i.e. ~16g corresponds to 0xff */ + val = DIV_ROUND_CLOSEST(val * MICRO + val2, 62500); + switch (dir) { + case IIO_EV_DIR_RISING: + return regmap_write(st->regmap, + adxl345_act_thresh_reg[type_act], + val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + static int adxl345_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, @@ -688,6 +879,10 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev, int ret; switch (type) { + case IIO_EV_TYPE_MAG: + return adxl345_read_mag_value(st, dir, info, + ADXL345_ACTIVITY, + val, val2); case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -738,6 +933,13 @@ static int adxl345_write_event_value(struct iio_dev *indio_dev, return ret; switch (type) { + case IIO_EV_TYPE_MAG: + ret = adxl345_write_mag_value(st, dir, info, + ADXL345_ACTIVITY, + val, val2); + if (ret) + return ret; + break; case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -977,6 +1179,7 @@ static int adxl345_fifo_push(struct iio_dev *indio_dev, } static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat, + enum iio_modifier act_dir, enum iio_modifier tap_dir) { s64 ts = iio_get_time_ns(indio_dev); @@ -1004,6 +1207,16 @@ static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat, return ret; } + if (FIELD_GET(ADXL345_INT_ACTIVITY, int_stat)) { + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, act_dir, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + ts); + if (ret) + return ret; + } + if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) { samples = adxl345_get_samples(st); if (samples < 0) @@ -1031,6 +1244,7 @@ static irqreturn_t adxl345_irq_handler(int irq, void *p) struct adxl345_state *st = iio_priv(indio_dev); unsigned int regval; enum iio_modifier tap_dir = IIO_NO_MOD; + enum iio_modifier act_dir = IIO_NO_MOD; u32 axis_ctrl; int int_stat; int ret; @@ -1039,7 +1253,8 @@ static irqreturn_t adxl345_irq_handler(int irq, void *p) if (ret) return IRQ_NONE; - if (FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl)) { + if (FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl) || + FIELD_GET(ADXL345_ACT_XYZ_EN, axis_ctrl)) { ret = regmap_read(st->regmap, ADXL345_REG_ACT_TAP_STATUS, ®val); if (ret) return IRQ_NONE; @@ -1050,12 +1265,19 @@ static irqreturn_t adxl345_irq_handler(int irq, void *p) tap_dir = IIO_MOD_Y; else if (FIELD_GET(ADXL345_TAP_X_EN, regval)) tap_dir = IIO_MOD_X; + + if (FIELD_GET(ADXL345_ACT_Z_EN, regval)) + act_dir = IIO_MOD_Z; + else if (FIELD_GET(ADXL345_ACT_Y_EN, regval)) + act_dir = IIO_MOD_Y; + else if (FIELD_GET(ADXL345_ACT_X_EN, regval)) + act_dir = IIO_MOD_X; } if (regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, &int_stat)) return IRQ_NONE; - if (adxl345_push_event(indio_dev, int_stat, tap_dir)) + if (adxl345_push_event(indio_dev, int_stat, act_dir, tap_dir)) goto err; if (FIELD_GET(ADXL345_INT_OVERRUN, int_stat)) @@ -1223,6 +1445,20 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, if (ret) return ret; + /* + * Initialized with sensible default values to streamline + * sensor operation. These defaults are partly derived from + * the previous input driver for the ADXL345 and partly + * based on the recommendations provided in the datasheet. + */ + ret = regmap_write(st->regmap, ADXL345_REG_ACT_INACT_CTRL, 0); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_ACT, 6); + if (ret) + return ret; + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, tap_threshold); if (ret) return ret; From 8a1536cc4a1c8cf83d9f49a5cafa6cec62d9ff7b Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Sun, 27 Jul 2025 21:00:10 +0000 Subject: [PATCH 0197/2711] iio: accel: adxl345: add inactivity feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the sensor’s inactivity feature in the driver. When both activity and inactivity detection are enabled, the sensor sets a link bit that ties the two functions together. This also enables auto-sleep mode, allowing the sensor to automatically enter sleep state upon detecting inactivity. Inactivity detection relies on a configurable threshold and a specified time period. If sensor measurements remain below the threshold for the defined duration, the sensor transitions to the inactivity state. When an Output Data Rate (ODR) is set, the inactivity time period is automatically adjusted to a sensible default. Higher ODRs result in shorter inactivity timeouts, while lower ODRs allow longer durations-within reasonable upper and lower bounds. This is important because features like auto-sleep operate effectively only between 12.5 Hz and 400 Hz. These defaults are applied when the sample rate is modified, but users can override them by explicitly setting a custom inactivity timeout. Similarly, configuring the g-range provides default threshold values for both activity and inactivity detection. These are implicit defaults meant to simplify configuration, but they can also be manually overridden as needed. Signed-off-by: Lothar Rubusch Link: https://patch.msgid.link/20250727210014.27766-4-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 241 ++++++++++++++++++++++++++++++- 1 file changed, 237 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 8ff1784403ba..1272d8107f0d 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -34,11 +34,20 @@ #define ADXL345_INT2 1 #define ADXL345_REG_TAP_AXIS_MSK GENMASK(2, 0) +#define ADXL345_REG_TAP_SUPPRESS_MSK BIT(3) +#define ADXL345_REG_TAP_SUPPRESS BIT(3) +#define ADXL345_POWER_CTL_INACT_MSK (ADXL345_POWER_CTL_AUTO_SLEEP | ADXL345_POWER_CTL_LINK) + #define ADXL345_TAP_Z_EN BIT(0) #define ADXL345_TAP_Y_EN BIT(1) #define ADXL345_TAP_X_EN BIT(2) #define ADXL345_REG_TAP_SUPPRESS BIT(3) +#define ADXL345_INACT_Z_EN BIT(0) +#define ADXL345_INACT_Y_EN BIT(1) +#define ADXL345_INACT_X_EN BIT(2) +#define ADXL345_INACT_XYZ_EN (ADXL345_INACT_Z_EN | ADXL345_INACT_Y_EN | ADXL345_INACT_X_EN) + #define ADXL345_ACT_Z_EN BIT(4) #define ADXL345_ACT_Y_EN BIT(5) #define ADXL345_ACT_X_EN BIT(6) @@ -70,14 +79,17 @@ static const unsigned int adxl345_tap_time_reg[] = { /* activity/inactivity */ enum adxl345_activity_type { ADXL345_ACTIVITY, + ADXL345_INACTIVITY, }; static const unsigned int adxl345_act_int_reg[] = { [ADXL345_ACTIVITY] = ADXL345_INT_ACTIVITY, + [ADXL345_INACTIVITY] = ADXL345_INT_INACTIVITY, }; static const unsigned int adxl345_act_thresh_reg[] = { [ADXL345_ACTIVITY] = ADXL345_REG_THRESH_ACT, + [ADXL345_INACTIVITY] = ADXL345_REG_THRESH_INACT, }; enum adxl345_odr { @@ -145,6 +157,14 @@ static const int adxl345_fullres_range_tbl[][2] = { [ADXL345_16G_RANGE] = { 0, 38312 }, }; +/* scaling */ +static const int adxl345_range_factor_tbl[] = { + [ADXL345_2G_RANGE] = 1, + [ADXL345_4G_RANGE] = 2, + [ADXL345_8G_RANGE] = 4, + [ADXL345_16G_RANGE] = 8, +}; + struct adxl345_state { const struct adxl345_chip_info *info; struct regmap *regmap; @@ -212,10 +232,30 @@ enum adxl345_chans { chan_x, chan_y, chan_z, }; +static const struct iio_event_spec adxl345_fake_chan_events[] = { + { + /* inactivity */ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type = + BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_PERIOD), + }, +}; + static const struct iio_chan_spec adxl345_channels[] = { ADXL345_CHANNEL(0, chan_x, X), ADXL345_CHANNEL(1, chan_y, Y), ADXL345_CHANNEL(2, chan_z, Z), + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X_AND_Y_AND_Z, + .scan_index = -1, /* Fake channel */ + .event_spec = adxl345_fake_chan_events, + .num_event_specs = ARRAY_SIZE(adxl345_fake_chan_events), + }, }; static const unsigned long adxl345_scan_masks[] = { @@ -263,6 +303,52 @@ static int adxl345_set_measure_en(struct adxl345_state *st, bool en) /* activity / inactivity */ +/** + * adxl345_set_inact_time - Configure inactivity time explicitly or by ODR. + * @st: The sensor state instance. + * @val_s: A desired time value, between 0 and 255. + * + * Inactivity time can be configured between 1 and 255 seconds. If a user sets + * val_s to 0, a default inactivity time is calculated automatically (since 0 is + * also invalid and undefined by the sensor). + * + * In such cases, power consumption should be considered: the inactivity period + * should be shorter at higher sampling frequencies and longer at lower ones. + * Specifically, for frequencies above 255 Hz, the default is set to 10 seconds; + * for frequencies below 10 Hz, it defaults to 255 seconds. + * + * The calculation method subtracts the integer part of the configured sample + * frequency from 255 to estimate the inactivity time in seconds. Sub-Hertz + * values are ignored in this approximation. Since the recommended output data + * rates (ODRs) for features like activity/inactivity detection, sleep modes, + * and free fall range between 12.5 Hz and 400 Hz, frequencies outside this + * range will either use the defined boundary defaults or require explicit + * configuration via val_s. + * + * Return: 0 or error value. + */ +static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s) +{ + int max_boundary = U8_MAX; + int min_boundary = 10; + unsigned int val = min(val_s, U8_MAX); + enum adxl345_odr odr; + unsigned int regval; + int ret; + + if (val == 0) { + ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val); + if (ret) + return ret; + + odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval); + val = clamp(max_boundary - adxl345_odr_tbl[odr][0], + min_boundary, max_boundary); + } + + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); +} + static int adxl345_is_act_inact_en(struct adxl345_state *st, enum adxl345_activity_type type) { @@ -282,6 +368,11 @@ static int adxl345_is_act_inact_en(struct adxl345_state *st, if (!en) return false; break; + case ADXL345_INACTIVITY: + en = FIELD_GET(ADXL345_INACT_XYZ_EN, axis_ctrl); + if (!en) + return false; + break; default: return -EINVAL; } @@ -294,12 +385,32 @@ static int adxl345_is_act_inact_en(struct adxl345_state *st, return adxl345_act_int_reg[type] & regval; } +static int adxl345_set_act_inact_linkbit(struct adxl345_state *st, + enum adxl345_activity_type type, + bool en) +{ + int act_en, inact_en; + + act_en = adxl345_is_act_inact_en(st, ADXL345_ACTIVITY); + if (act_en < 0) + return act_en; + + inact_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY); + if (inact_en < 0) + return inact_en; + + return regmap_assign_bits(st->regmap, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_INACT_MSK, + en && act_en && inact_en); +} + static int adxl345_set_act_inact_en(struct adxl345_state *st, enum adxl345_activity_type type, bool cmd_en) { unsigned int axis_ctrl; unsigned int threshold; + unsigned int period; int ret; if (cmd_en) { @@ -312,6 +423,18 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, if (!threshold) /* Just ignore the command if threshold is 0 */ return 0; + + /* When turning on inactivity, check if inact time is valid */ + if (type == ADXL345_INACTIVITY) { + ret = regmap_read(st->regmap, + ADXL345_REG_TIME_INACT, + &period); + if (ret) + return ret; + + if (!period) + return 0; + } } /* Start modifying configuration registers */ @@ -324,6 +447,9 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, case ADXL345_ACTIVITY: axis_ctrl = ADXL345_ACT_XYZ_EN; break; + case ADXL345_INACTIVITY: + axis_ctrl = ADXL345_INACT_XYZ_EN; + break; default: return -EINVAL; } @@ -339,6 +465,11 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, if (ret) return ret; + /* Set link-bit and auto-sleep only when ACT and INACT are enabled */ + ret = adxl345_set_act_inact_linkbit(st, type, cmd_en); + if (ret) + return ret; + return adxl345_set_measure_en(st, true); } @@ -570,9 +701,16 @@ static int adxl345_find_odr(struct adxl345_state *st, int val, static int adxl345_set_odr(struct adxl345_state *st, enum adxl345_odr odr) { - return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE, + int ret; + + ret = regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE, ADXL345_BW_RATE_MSK, FIELD_PREP(ADXL345_BW_RATE_MSK, odr)); + if (ret) + return ret; + + /* update inactivity time by ODR */ + return adxl345_set_inact_time(st, 0); } static int adxl345_find_range(struct adxl345_state *st, int val, int val2, @@ -593,9 +731,49 @@ static int adxl345_find_range(struct adxl345_state *st, int val, int val2, static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range range) { - return regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT, + unsigned int act_threshold, inact_threshold; + unsigned int range_old; + unsigned int regval; + int ret; + + ret = regmap_read(st->regmap, ADXL345_REG_DATA_FORMAT, ®val); + if (ret) + return ret; + range_old = FIELD_GET(ADXL345_DATA_FORMAT_RANGE, regval); + + ret = regmap_read(st->regmap, + adxl345_act_thresh_reg[ADXL345_ACTIVITY], + &act_threshold); + if (ret) + return ret; + + ret = regmap_read(st->regmap, + adxl345_act_thresh_reg[ADXL345_INACTIVITY], + &inact_threshold); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT, ADXL345_DATA_FORMAT_RANGE, FIELD_PREP(ADXL345_DATA_FORMAT_RANGE, range)); + if (ret) + return ret; + + act_threshold = act_threshold * adxl345_range_factor_tbl[range_old] + / adxl345_range_factor_tbl[range]; + act_threshold = min(U8_MAX, max(1, act_threshold)); + + inact_threshold = inact_threshold * adxl345_range_factor_tbl[range_old] + / adxl345_range_factor_tbl[range]; + inact_threshold = min(U8_MAX, max(1, inact_threshold)); + + ret = regmap_write(st->regmap, adxl345_act_thresh_reg[ADXL345_ACTIVITY], + act_threshold); + if (ret) + return ret; + + return regmap_write(st->regmap, adxl345_act_thresh_reg[ADXL345_INACTIVITY], + inact_threshold); } static int adxl345_read_avail(struct iio_dev *indio_dev, @@ -730,11 +908,14 @@ static int adxl345_write_raw(struct iio_dev *indio_dev, static int adxl345_read_mag_config(struct adxl345_state *st, enum iio_event_direction dir, - enum adxl345_activity_type type_act) + enum adxl345_activity_type type_act, + enum adxl345_activity_type type_inact) { switch (dir) { case IIO_EV_DIR_RISING: return !!adxl345_is_act_inact_en(st, type_act); + case IIO_EV_DIR_FALLING: + return !!adxl345_is_act_inact_en(st, type_inact); default: return -EINVAL; } @@ -743,11 +924,14 @@ static int adxl345_read_mag_config(struct adxl345_state *st, static int adxl345_write_mag_config(struct adxl345_state *st, enum iio_event_direction dir, enum adxl345_activity_type type_act, + enum adxl345_activity_type type_inact, bool state) { switch (dir) { case IIO_EV_DIR_RISING: return adxl345_set_act_inact_en(st, type_act, state); + case IIO_EV_DIR_FALLING: + return adxl345_set_act_inact_en(st, type_inact, state); default: return -EINVAL; } @@ -765,7 +949,8 @@ static int adxl345_read_event_config(struct iio_dev *indio_dev, switch (type) { case IIO_EV_TYPE_MAG: return adxl345_read_mag_config(st, dir, - ADXL345_ACTIVITY); + ADXL345_ACTIVITY, + ADXL345_INACTIVITY); case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -800,6 +985,7 @@ static int adxl345_write_event_config(struct iio_dev *indio_dev, case IIO_EV_TYPE_MAG: return adxl345_write_mag_config(st, dir, ADXL345_ACTIVITY, + ADXL345_INACTIVITY, state); case IIO_EV_TYPE_GESTURE: switch (dir) { @@ -819,9 +1005,11 @@ static int adxl345_read_mag_value(struct adxl345_state *st, enum iio_event_direction dir, enum iio_event_info info, enum adxl345_activity_type type_act, + enum adxl345_activity_type type_inact, int *val, int *val2) { unsigned int threshold; + unsigned int period; int ret; switch (info) { @@ -836,9 +1024,26 @@ static int adxl345_read_mag_value(struct adxl345_state *st, *val = 62500 * threshold; *val2 = MICRO; return IIO_VAL_FRACTIONAL; + case IIO_EV_DIR_FALLING: + ret = regmap_read(st->regmap, + adxl345_act_thresh_reg[type_inact], + &threshold); + if (ret) + return ret; + *val = 62500 * threshold; + *val2 = MICRO; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; } + case IIO_EV_INFO_PERIOD: + ret = regmap_read(st->regmap, + ADXL345_REG_TIME_INACT, + &period); + if (ret) + return ret; + *val = period; + return IIO_VAL_INT; default: return -EINVAL; } @@ -848,6 +1053,7 @@ static int adxl345_write_mag_value(struct adxl345_state *st, enum iio_event_direction dir, enum iio_event_info info, enum adxl345_activity_type type_act, + enum adxl345_activity_type type_inact, int val, int val2) { switch (info) { @@ -859,9 +1065,15 @@ static int adxl345_write_mag_value(struct adxl345_state *st, return regmap_write(st->regmap, adxl345_act_thresh_reg[type_act], val); + case IIO_EV_DIR_FALLING: + return regmap_write(st->regmap, + adxl345_act_thresh_reg[type_inact], + val); default: return -EINVAL; } + case IIO_EV_INFO_PERIOD: + return adxl345_set_inact_time(st, val); default: return -EINVAL; } @@ -882,6 +1094,7 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev, case IIO_EV_TYPE_MAG: return adxl345_read_mag_value(st, dir, info, ADXL345_ACTIVITY, + ADXL345_INACTIVITY, val, val2); case IIO_EV_TYPE_GESTURE: switch (info) { @@ -936,6 +1149,7 @@ static int adxl345_write_event_value(struct iio_dev *indio_dev, case IIO_EV_TYPE_MAG: ret = adxl345_write_mag_value(st, dir, info, ADXL345_ACTIVITY, + ADXL345_INACTIVITY, val, val2); if (ret) return ret; @@ -1217,6 +1431,17 @@ static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat, return ret; } + if (FIELD_GET(ADXL345_INT_INACTIVITY, int_stat)) { + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_FALLING), + ts); + if (ret) + return ret; + } + if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) { samples = adxl345_get_samples(st); if (samples < 0) @@ -1455,10 +1680,18 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, if (ret) return ret; + ret = regmap_write(st->regmap, ADXL345_REG_TIME_INACT, 0x37); + if (ret) + return ret; + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_ACT, 6); if (ret) return ret; + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_INACT, 4); + if (ret) + return ret; + ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, tap_threshold); if (ret) return ret; From 31f7679bb69abfd3a0175608f8b0ee721cea8544 Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Sun, 27 Jul 2025 21:00:11 +0000 Subject: [PATCH 0198/2711] iio: accel: adxl345: add coupling detection for activity/inactivity Enable AC/DC coupling configuration for activity and inactivity detection by setting the AC/DC bit. Extend existing magnitude-based detection with adaptive AC-coupled mode. Use DC-coupled mode to compare acceleration samples directly against configured thresholds. Use AC-coupled mode to compare samples against a reference taken at the start of activity detection. Implement DC-coupled events using MAG, and AC-coupled events using MAG_ADAPTIVE. Expose configuration of thresholds and periods via separate sysfs handles. Note that both coupling modes share the same sensor registers, so activity or inactivity detection cannot be configured for both AC and DC simultaneously. Apply the most recently configured mode. Simplify event handling and support adaptive AC-coupling. Signed-off-by: Lothar Rubusch Link: https://patch.msgid.link/20250727210014.27766-5-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 254 +++++++++++++++++++++++++++++-- 1 file changed, 240 insertions(+), 14 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 1272d8107f0d..2722addde895 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -46,13 +46,18 @@ #define ADXL345_INACT_Z_EN BIT(0) #define ADXL345_INACT_Y_EN BIT(1) #define ADXL345_INACT_X_EN BIT(2) +#define ADXL345_REG_INACT_ACDC BIT(3) #define ADXL345_INACT_XYZ_EN (ADXL345_INACT_Z_EN | ADXL345_INACT_Y_EN | ADXL345_INACT_X_EN) #define ADXL345_ACT_Z_EN BIT(4) #define ADXL345_ACT_Y_EN BIT(5) #define ADXL345_ACT_X_EN BIT(6) +#define ADXL345_REG_ACT_ACDC BIT(7) #define ADXL345_ACT_XYZ_EN (ADXL345_ACT_Z_EN | ADXL345_ACT_Y_EN | ADXL345_ACT_X_EN) +#define ADXL345_COUPLING_DC 0 +#define ADXL345_COUPLING_AC 1 + /* single/double tap */ enum adxl345_tap_type { ADXL345_SINGLE_TAP, @@ -80,16 +85,29 @@ static const unsigned int adxl345_tap_time_reg[] = { enum adxl345_activity_type { ADXL345_ACTIVITY, ADXL345_INACTIVITY, + ADXL345_ACTIVITY_AC, + ADXL345_INACTIVITY_AC, }; static const unsigned int adxl345_act_int_reg[] = { [ADXL345_ACTIVITY] = ADXL345_INT_ACTIVITY, [ADXL345_INACTIVITY] = ADXL345_INT_INACTIVITY, + [ADXL345_ACTIVITY_AC] = ADXL345_INT_ACTIVITY, + [ADXL345_INACTIVITY_AC] = ADXL345_INT_INACTIVITY, }; static const unsigned int adxl345_act_thresh_reg[] = { [ADXL345_ACTIVITY] = ADXL345_REG_THRESH_ACT, [ADXL345_INACTIVITY] = ADXL345_REG_THRESH_INACT, + [ADXL345_ACTIVITY_AC] = ADXL345_REG_THRESH_ACT, + [ADXL345_INACTIVITY_AC] = ADXL345_REG_THRESH_INACT, +}; + +static const unsigned int adxl345_act_acdc_msk[] = { + [ADXL345_ACTIVITY] = ADXL345_REG_ACT_ACDC, + [ADXL345_INACTIVITY] = ADXL345_REG_INACT_ACDC, + [ADXL345_ACTIVITY_AC] = ADXL345_REG_ACT_ACDC, + [ADXL345_INACTIVITY_AC] = ADXL345_REG_INACT_ACDC, }; enum adxl345_odr { @@ -188,6 +206,14 @@ static const struct iio_event_spec adxl345_events[] = { BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE), }, + { + /* activity, ac bit set */ + .type = IIO_EV_TYPE_MAG_ADAPTIVE, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_type = + BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE), + }, { /* single tap */ .type = IIO_EV_TYPE_GESTURE, @@ -242,6 +268,15 @@ static const struct iio_event_spec adxl345_fake_chan_events[] = { BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_PERIOD), }, + { + /* inactivity, AC bit set */ + .type = IIO_EV_TYPE_MAG_ADAPTIVE, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type = + BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_PERIOD), + }, }; static const struct iio_chan_spec adxl345_channels[] = { @@ -349,12 +384,114 @@ static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s) return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); } +/** + * adxl345_is_act_inact_ac() - Verify if AC or DC coupling is currently enabled. + * + * @st: The device data. + * @type: The activity or inactivity type. + * + * Given a type of activity / inactivity combined with either AC coupling set or + * default to DC, this function verifies if the combination is currently + * configured, hence enabled or not. + * + * Return: true if configured coupling matches the provided type, else a negative + * error value. + */ +static int adxl345_is_act_inact_ac(struct adxl345_state *st, + enum adxl345_activity_type type) +{ + unsigned int regval; + bool coupling; + int ret; + + ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val); + if (ret) + return ret; + + coupling = adxl345_act_acdc_msk[type] & regval; + + switch (type) { + case ADXL345_ACTIVITY: + case ADXL345_INACTIVITY: + return coupling == ADXL345_COUPLING_DC; + case ADXL345_ACTIVITY_AC: + case ADXL345_INACTIVITY_AC: + return coupling == ADXL345_COUPLING_AC; + default: + return -EINVAL; + } +} + +/** + * adxl345_set_act_inact_ac() - Configure AC coupling or DC coupling. + * + * @st: The device data. + * @type: Provide a type of activity or inactivity. + * @cmd_en: enable or disable AC coupling. + * + * Enables AC coupling or DC coupling depending on the provided type argument. + * Note: Activity and inactivity can be either AC coupled or DC coupled not + * both at the same time. + * + * Return: 0 if successful, else error value. + */ +static int adxl345_set_act_inact_ac(struct adxl345_state *st, + enum adxl345_activity_type type, + bool cmd_en) +{ + unsigned int act_inact_ac; + + if (type == ADXL345_ACTIVITY_AC || type == ADXL345_INACTIVITY_AC) + act_inact_ac = ADXL345_COUPLING_AC && cmd_en; + else + act_inact_ac = ADXL345_COUPLING_DC && cmd_en; + + /* + * A setting of false selects dc-coupled operation, and a setting of + * true enables ac-coupled operation. In dc-coupled operation, the + * current acceleration magnitude is compared directly with + * ADXL345_REG_THRESH_ACT and ADXL345_REG_THRESH_INACT to determine + * whether activity or inactivity is detected. + * + * In ac-coupled operation for activity detection, the acceleration + * value at the start of activity detection is taken as a reference + * value. New samples of acceleration are then compared to this + * reference value, and if the magnitude of the difference exceeds the + * ADXL345_REG_THRESH_ACT value, the device triggers an activity + * interrupt. + * + * Similarly, in ac-coupled operation for inactivity detection, a + * reference value is used for comparison and is updated whenever the + * device exceeds the inactivity threshold. After the reference value + * is selected, the device compares the magnitude of the difference + * between the reference value and the current acceleration with + * ADXL345_REG_THRESH_INACT. If the difference is less than the value in + * ADXL345_REG_THRESH_INACT for the time in ADXL345_REG_TIME_INACT, the + * device is considered inactive and the inactivity interrupt is + * triggered. [quoted from p. 24, ADXL345 datasheet Rev. G] + * + * In a conclusion, the first acceleration snapshot sample which hit the + * threshold in a particular direction is always taken as acceleration + * reference value to that direction. Since for the hardware activity + * and inactivity depend on the x/y/z axis, so do ac and dc coupling. + * Note, this sw driver always enables or disables all three x/y/z axis + * for detection via act_axis_ctrl and inact_axis_ctrl, respectively. + * Where in dc-coupling samples are compared against the thresholds, in + * ac-coupling measurement difference to the first acceleration + * reference value are compared against the threshold. So, ac-coupling + * allows for a bit more dynamic compensation depending on the initial + * sample. + */ + return regmap_assign_bits(st->regmap, ADXL345_REG_ACT_INACT_CTRL, + adxl345_act_acdc_msk[type], act_inact_ac); +} + static int adxl345_is_act_inact_en(struct adxl345_state *st, enum adxl345_activity_type type) { unsigned int axis_ctrl; unsigned int regval; - bool en; + bool int_en, en; int ret; ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, &axis_ctrl); @@ -364,11 +501,13 @@ static int adxl345_is_act_inact_en(struct adxl345_state *st, /* Check if axis for activity are enabled */ switch (type) { case ADXL345_ACTIVITY: + case ADXL345_ACTIVITY_AC: en = FIELD_GET(ADXL345_ACT_XYZ_EN, axis_ctrl); if (!en) return false; break; case ADXL345_INACTIVITY: + case ADXL345_INACTIVITY_AC: en = FIELD_GET(ADXL345_INACT_XYZ_EN, axis_ctrl); if (!en) return false; @@ -382,23 +521,40 @@ static int adxl345_is_act_inact_en(struct adxl345_state *st, if (ret) return ret; - return adxl345_act_int_reg[type] & regval; + int_en = adxl345_act_int_reg[type] & regval; + if (!int_en) + return false; + + /* Check if configured coupling matches provided type */ + return adxl345_is_act_inact_ac(st, type); } static int adxl345_set_act_inact_linkbit(struct adxl345_state *st, enum adxl345_activity_type type, bool en) { + int act_ac_en, inact_ac_en; int act_en, inact_en; act_en = adxl345_is_act_inact_en(st, ADXL345_ACTIVITY); if (act_en < 0) return act_en; + act_ac_en = adxl345_is_act_inact_en(st, ADXL345_ACTIVITY_AC); + if (act_ac_en < 0) + return act_ac_en; + inact_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY); if (inact_en < 0) return inact_en; + inact_ac_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY_AC); + if (inact_ac_en < 0) + return inact_ac_en; + + inact_en = inact_en || inact_ac_en; + act_en = act_en || act_ac_en; + return regmap_assign_bits(st->regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_INACT_MSK, en && act_en && inact_en); @@ -425,7 +581,7 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, return 0; /* When turning on inactivity, check if inact time is valid */ - if (type == ADXL345_INACTIVITY) { + if (type == ADXL345_INACTIVITY || type == ADXL345_INACTIVITY_AC) { ret = regmap_read(st->regmap, ADXL345_REG_TIME_INACT, &period); @@ -435,6 +591,16 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, if (!period) return 0; } + } else { + /* + * When turning off an activity, ensure that the correct + * coupling event is specified. This step helps prevent misuse - + * for example, if an AC-coupled activity is active and the + * current call attempts to turn off a DC-coupled activity, this + * inconsistency should be detected here. + */ + if (adxl345_is_act_inact_ac(st, type) <= 0) + return 0; } /* Start modifying configuration registers */ @@ -445,9 +611,11 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, /* Enable axis according to the command */ switch (type) { case ADXL345_ACTIVITY: + case ADXL345_ACTIVITY_AC: axis_ctrl = ADXL345_ACT_XYZ_EN; break; case ADXL345_INACTIVITY: + case ADXL345_INACTIVITY_AC: axis_ctrl = ADXL345_INACT_XYZ_EN; break; default: @@ -459,6 +627,11 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, if (ret) return ret; + /* Update AC/DC-coupling according to the command */ + ret = adxl345_set_act_inact_ac(st, type, cmd_en); + if (ret) + return ret; + /* Enable the interrupt line, according to the command */ ret = regmap_assign_bits(st->regmap, ADXL345_REG_INT_ENABLE, adxl345_act_int_reg[type], cmd_en); @@ -951,6 +1124,10 @@ static int adxl345_read_event_config(struct iio_dev *indio_dev, return adxl345_read_mag_config(st, dir, ADXL345_ACTIVITY, ADXL345_INACTIVITY); + case IIO_EV_TYPE_MAG_ADAPTIVE: + return adxl345_read_mag_config(st, dir, + ADXL345_ACTIVITY_AC, + ADXL345_INACTIVITY_AC); case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -987,6 +1164,11 @@ static int adxl345_write_event_config(struct iio_dev *indio_dev, ADXL345_ACTIVITY, ADXL345_INACTIVITY, state); + case IIO_EV_TYPE_MAG_ADAPTIVE: + return adxl345_write_mag_config(st, dir, + ADXL345_ACTIVITY_AC, + ADXL345_INACTIVITY_AC, + state); case IIO_EV_TYPE_GESTURE: switch (dir) { case IIO_EV_DIR_SINGLETAP: @@ -1096,6 +1278,11 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev, ADXL345_ACTIVITY, ADXL345_INACTIVITY, val, val2); + case IIO_EV_TYPE_MAG_ADAPTIVE: + return adxl345_read_mag_value(st, dir, info, + ADXL345_ACTIVITY_AC, + ADXL345_INACTIVITY_AC, + val, val2); case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -1154,6 +1341,14 @@ static int adxl345_write_event_value(struct iio_dev *indio_dev, if (ret) return ret; break; + case IIO_EV_TYPE_MAG_ADAPTIVE: + ret = adxl345_write_mag_value(st, dir, info, + ADXL345_ACTIVITY_AC, + ADXL345_INACTIVITY_AC, + val, val2); + if (ret) + return ret; + break; case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: @@ -1398,6 +1593,7 @@ static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat, { s64 ts = iio_get_time_ns(indio_dev); struct adxl345_state *st = iio_priv(indio_dev); + unsigned int regval; int samples; int ret = -ENOENT; @@ -1422,22 +1618,52 @@ static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat, } if (FIELD_GET(ADXL345_INT_ACTIVITY, int_stat)) { - ret = iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, act_dir, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - ts); + ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val); + if (ret) + return ret; + + if (FIELD_GET(ADXL345_REG_ACT_ACDC, regval)) { + /* AC coupled */ + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, act_dir, + IIO_EV_TYPE_MAG_ADAPTIVE, + IIO_EV_DIR_RISING), + ts); + + } else { + /* DC coupled, relying on THRESH */ + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, act_dir, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + ts); + } if (ret) return ret; } if (FIELD_GET(ADXL345_INT_INACTIVITY, int_stat)) { - ret = iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, - IIO_MOD_X_AND_Y_AND_Z, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_FALLING), - ts); + ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val); + if (ret) + return ret; + + if (FIELD_GET(ADXL345_REG_INACT_ACDC, regval)) { + /* AC coupled */ + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG_ADAPTIVE, + IIO_EV_DIR_FALLING), + ts); + } else { + /* DC coupled, relying on THRESH */ + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_FALLING), + ts); + } if (ret) return ret; } From f6f22950d925c5e42ac5aeadafafcfc3c5c7b360 Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Sun, 27 Jul 2025 21:00:12 +0000 Subject: [PATCH 0199/2711] iio: accel: adxl345: extend inactivity time for less than 1s Inactivity and free-fall events are essentially the same type of sensor events. Therefore, inactivity detection (normally set for periods between 1 and 255 seconds) can be extended for shorter durations to support free-fall detection. For periods shorter than 1 second, the driver automatically configures the threshold and duration using the free-fall register. For periods longer than 1 second, it uses the inactivity threshold and duration using the inactivity registers. When using the free-fall register, the link bit is not set, which means auto-sleep cannot be enabled if activity detection is also active. Signed-off-by: Lothar Rubusch Link: https://patch.msgid.link/20250727210014.27766-6-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 200 +++++++++++++++++++++---------- 1 file changed, 138 insertions(+), 62 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 2722addde895..78e3f799ecc1 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -47,6 +47,7 @@ #define ADXL345_INACT_Y_EN BIT(1) #define ADXL345_INACT_X_EN BIT(2) #define ADXL345_REG_INACT_ACDC BIT(3) +#define ADXL345_ACT_INACT_NO_AXIS_EN 0x00 #define ADXL345_INACT_XYZ_EN (ADXL345_INACT_Z_EN | ADXL345_INACT_Y_EN | ADXL345_INACT_X_EN) #define ADXL345_ACT_Z_EN BIT(4) @@ -57,6 +58,7 @@ #define ADXL345_COUPLING_DC 0 #define ADXL345_COUPLING_AC 1 +#define ADXL345_REG_NO_ACDC 0x00 /* single/double tap */ enum adxl345_tap_type { @@ -87,6 +89,7 @@ enum adxl345_activity_type { ADXL345_INACTIVITY, ADXL345_ACTIVITY_AC, ADXL345_INACTIVITY_AC, + ADXL345_INACTIVITY_FF, }; static const unsigned int adxl345_act_int_reg[] = { @@ -94,6 +97,7 @@ static const unsigned int adxl345_act_int_reg[] = { [ADXL345_INACTIVITY] = ADXL345_INT_INACTIVITY, [ADXL345_ACTIVITY_AC] = ADXL345_INT_ACTIVITY, [ADXL345_INACTIVITY_AC] = ADXL345_INT_INACTIVITY, + [ADXL345_INACTIVITY_FF] = ADXL345_INT_FREE_FALL, }; static const unsigned int adxl345_act_thresh_reg[] = { @@ -101,6 +105,7 @@ static const unsigned int adxl345_act_thresh_reg[] = { [ADXL345_INACTIVITY] = ADXL345_REG_THRESH_INACT, [ADXL345_ACTIVITY_AC] = ADXL345_REG_THRESH_ACT, [ADXL345_INACTIVITY_AC] = ADXL345_REG_THRESH_INACT, + [ADXL345_INACTIVITY_FF] = ADXL345_REG_THRESH_FF, }; static const unsigned int adxl345_act_acdc_msk[] = { @@ -108,6 +113,7 @@ static const unsigned int adxl345_act_acdc_msk[] = { [ADXL345_INACTIVITY] = ADXL345_REG_INACT_ACDC, [ADXL345_ACTIVITY_AC] = ADXL345_REG_ACT_ACDC, [ADXL345_INACTIVITY_AC] = ADXL345_REG_INACT_ACDC, + [ADXL345_INACTIVITY_FF] = ADXL345_REG_NO_ACDC, }; enum adxl345_odr { @@ -190,6 +196,9 @@ struct adxl345_state { u8 watermark; u8 fifo_mode; + u8 inact_threshold; + u32 inact_time_ms; + u32 tap_duration_us; u32 tap_latent_us; u32 tap_window_us; @@ -338,10 +347,72 @@ static int adxl345_set_measure_en(struct adxl345_state *st, bool en) /* activity / inactivity */ +static int adxl345_set_inact_threshold(struct adxl345_state *st, + unsigned int threshold) +{ + int ret; + + st->inact_threshold = min(U8_MAX, threshold); + + ret = regmap_write(st->regmap, + adxl345_act_thresh_reg[ADXL345_INACTIVITY], + st->inact_threshold); + if (ret) + return ret; + + return regmap_write(st->regmap, + adxl345_act_thresh_reg[ADXL345_INACTIVITY_FF], + st->inact_threshold); +} + +static int adxl345_set_default_time(struct adxl345_state *st) +{ + int max_boundary = U8_MAX; + int min_boundary = 10; + enum adxl345_odr odr; + unsigned int regval; + unsigned int val; + int ret; + + /* Generated inactivity time based on ODR */ + ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val); + if (ret) + return ret; + + odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval); + val = clamp(max_boundary - adxl345_odr_tbl[odr][0], + min_boundary, max_boundary); + st->inact_time_ms = MILLI * val; + + /* Inactivity time in s */ + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); +} + +static int adxl345_set_inactivity_time(struct adxl345_state *st, u32 val_int) +{ + st->inact_time_ms = MILLI * val_int; + + return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val_int); +} + +static int adxl345_set_freefall_time(struct adxl345_state *st, u32 val_fract) +{ + /* + * Datasheet max. value is 255 * 5000 us = 1.275000 seconds. + * + * Recommended values between 100ms and 350ms (0x14 to 0x46) + */ + st->inact_time_ms = DIV_ROUND_UP(val_fract, MILLI); + + return regmap_write(st->regmap, ADXL345_REG_TIME_FF, + DIV_ROUND_CLOSEST(val_fract, 5)); +} + /** * adxl345_set_inact_time - Configure inactivity time explicitly or by ODR. * @st: The sensor state instance. - * @val_s: A desired time value, between 0 and 255. + * @val_int: The inactivity time, integer part. + * @val_fract: The inactivity time, fractional part when val_int is 0. * * Inactivity time can be configured between 1 and 255 seconds. If a user sets * val_s to 0, a default inactivity time is calculated automatically (since 0 is @@ -362,26 +433,24 @@ static int adxl345_set_measure_en(struct adxl345_state *st, bool en) * * Return: 0 or error value. */ -static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_s) +static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_int, + u32 val_fract) { - int max_boundary = U8_MAX; - int min_boundary = 10; - unsigned int val = min(val_s, U8_MAX); - enum adxl345_odr odr; - unsigned int regval; - int ret; - - if (val == 0) { - ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val); - if (ret) - return ret; - - odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval); - val = clamp(max_boundary - adxl345_odr_tbl[odr][0], - min_boundary, max_boundary); + if (val_int > 0) { + /* Time >= 1s, inactivity */ + return adxl345_set_inactivity_time(st, val_int); + } else if (val_int == 0) { + if (val_fract > 0) { + /* Time < 1s, free-fall */ + return adxl345_set_freefall_time(st, val_fract); + } else if (val_fract == 0) { + /* Time == 0.0s */ + return adxl345_set_default_time(st); + } } - return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val); + /* Do not support negative or wrong input. */ + return -EINVAL; } /** @@ -404,6 +473,9 @@ static int adxl345_is_act_inact_ac(struct adxl345_state *st, bool coupling; int ret; + if (type == ADXL345_INACTIVITY_FF) + return true; + ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val); if (ret) return ret; @@ -512,6 +584,9 @@ static int adxl345_is_act_inact_en(struct adxl345_state *st, if (!en) return false; break; + case ADXL345_INACTIVITY_FF: + en = true; + break; default: return -EINVAL; } @@ -544,15 +619,20 @@ static int adxl345_set_act_inact_linkbit(struct adxl345_state *st, if (act_ac_en < 0) return act_ac_en; - inact_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY); - if (inact_en < 0) - return inact_en; + if (type == ADXL345_INACTIVITY_FF) { + inact_en = false; + } else { + inact_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY); + if (inact_en < 0) + return inact_en; - inact_ac_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY_AC); - if (inact_ac_en < 0) - return inact_ac_en; + inact_ac_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY_AC); + if (inact_ac_en < 0) + return inact_ac_en; + + inact_en = inact_en || inact_ac_en; + } - inact_en = inact_en || inact_ac_en; act_en = act_en || act_ac_en; return regmap_assign_bits(st->regmap, ADXL345_REG_POWER_CTL, @@ -571,11 +651,15 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, if (cmd_en) { /* When turning on, check if threshold is valid */ - ret = regmap_read(st->regmap, - adxl345_act_thresh_reg[type], - &threshold); - if (ret) - return ret; + if (type == ADXL345_ACTIVITY || type == ADXL345_ACTIVITY_AC) { + ret = regmap_read(st->regmap, + adxl345_act_thresh_reg[type], + &threshold); + if (ret) + return ret; + } else { + threshold = st->inact_threshold; + } if (!threshold) /* Just ignore the command if threshold is 0 */ return 0; @@ -618,6 +702,9 @@ static int adxl345_set_act_inact_en(struct adxl345_state *st, case ADXL345_INACTIVITY_AC: axis_ctrl = ADXL345_INACT_XYZ_EN; break; + case ADXL345_INACTIVITY_FF: + axis_ctrl = ADXL345_ACT_INACT_NO_AXIS_EN; + break; default: return -EINVAL; } @@ -883,7 +970,7 @@ static int adxl345_set_odr(struct adxl345_state *st, enum adxl345_odr odr) return ret; /* update inactivity time by ODR */ - return adxl345_set_inact_time(st, 0); + return adxl345_set_inact_time(st, 0, 0); } static int adxl345_find_range(struct adxl345_state *st, int val, int val2, @@ -920,12 +1007,6 @@ static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range range) if (ret) return ret; - ret = regmap_read(st->regmap, - adxl345_act_thresh_reg[ADXL345_INACTIVITY], - &inact_threshold); - if (ret) - return ret; - ret = regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT, ADXL345_DATA_FORMAT_RANGE, FIELD_PREP(ADXL345_DATA_FORMAT_RANGE, range)); @@ -936,6 +1017,7 @@ static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range range) / adxl345_range_factor_tbl[range]; act_threshold = min(U8_MAX, max(1, act_threshold)); + inact_threshold = st->inact_threshold; inact_threshold = inact_threshold * adxl345_range_factor_tbl[range_old] / adxl345_range_factor_tbl[range]; inact_threshold = min(U8_MAX, max(1, inact_threshold)); @@ -945,8 +1027,7 @@ static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range range) if (ret) return ret; - return regmap_write(st->regmap, adxl345_act_thresh_reg[ADXL345_INACTIVITY], - inact_threshold); + return adxl345_set_inact_threshold(st, inact_threshold); } static int adxl345_read_avail(struct iio_dev *indio_dev, @@ -1191,7 +1272,6 @@ static int adxl345_read_mag_value(struct adxl345_state *st, int *val, int *val2) { unsigned int threshold; - unsigned int period; int ret; switch (info) { @@ -1207,25 +1287,16 @@ static int adxl345_read_mag_value(struct adxl345_state *st, *val2 = MICRO; return IIO_VAL_FRACTIONAL; case IIO_EV_DIR_FALLING: - ret = regmap_read(st->regmap, - adxl345_act_thresh_reg[type_inact], - &threshold); - if (ret) - return ret; - *val = 62500 * threshold; + *val = 62500 * st->inact_threshold; *val2 = MICRO; return IIO_VAL_FRACTIONAL; default: return -EINVAL; } case IIO_EV_INFO_PERIOD: - ret = regmap_read(st->regmap, - ADXL345_REG_TIME_INACT, - &period); - if (ret) - return ret; - *val = period; - return IIO_VAL_INT; + *val = st->inact_time_ms; + *val2 = MILLI; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; } @@ -1248,14 +1319,12 @@ static int adxl345_write_mag_value(struct adxl345_state *st, adxl345_act_thresh_reg[type_act], val); case IIO_EV_DIR_FALLING: - return regmap_write(st->regmap, - adxl345_act_thresh_reg[type_inact], - val); + return adxl345_set_inact_threshold(st, val); default: return -EINVAL; } case IIO_EV_INFO_PERIOD: - return adxl345_set_inact_time(st, val); + return adxl345_set_inact_time(st, val, val2); default: return -EINVAL; } @@ -1668,6 +1737,17 @@ static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat, return ret; } + if (FIELD_GET(ADXL345_INT_FREE_FALL, int_stat)) { + ret = iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_FALLING), + ts); + if (ret) + return ret; + } + if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) { samples = adxl345_get_samples(st); if (samples < 0) @@ -1906,15 +1986,11 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, if (ret) return ret; - ret = regmap_write(st->regmap, ADXL345_REG_TIME_INACT, 0x37); - if (ret) - return ret; - ret = regmap_write(st->regmap, ADXL345_REG_THRESH_ACT, 6); if (ret) return ret; - ret = regmap_write(st->regmap, ADXL345_REG_THRESH_INACT, 4); + ret = adxl345_set_inact_threshold(st, 4); if (ret) return ret; From fdcb9cb9178ac3066cf907fe5d74ad3c856c2d46 Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Sun, 27 Jul 2025 21:00:13 +0000 Subject: [PATCH 0200/2711] docs: iio: add documentation for adxl345 driver The documentation describes the ADXL345 driver, IIO interface, interface usage and configuration. Signed-off-by: Lothar Rubusch Link: https://patch.msgid.link/20250727210014.27766-7-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/iio/adxl345.rst | 418 ++++++++++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + 2 files changed, 419 insertions(+) create mode 100644 Documentation/iio/adxl345.rst diff --git a/Documentation/iio/adxl345.rst b/Documentation/iio/adxl345.rst new file mode 100644 index 000000000000..8ee01b8b87f4 --- /dev/null +++ b/Documentation/iio/adxl345.rst @@ -0,0 +1,418 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============== +ADXL345 driver +=============== + +This driver supports Analog Device's ADXL345/375 on SPI/I2C bus. + +1. Supported Devices +==================== + +* `ADXL345 `_ +* `ADXL375 `_ + +The ADXL345 is a generic purpose low power, 3-axis accelerometer with selectable +measurement ranges. The ADXL345 supports the ±2 g, ±4 g, ±8 g, and ±16 g ranges. + +2. Device Attributes +==================== + +Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``, +where X is the IIO index of the device. Under these folders reside a set of +device files, depending on the characteristics and features of the hardware +device in questions. These files are consistently generalized and documented in +the IIO ABI documentation. + +The following table shows the ADXL345 related device files, found in the +specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. + ++-------------------------------------------+----------------------------------------------------------+ +| 3-Axis Accelerometer related device files | Description | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_sampling_frequency | Currently selected sample rate. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_sampling_frequency_available | Available sampling frequency configurations. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_scale | Scale/range for the accelerometer channels. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_scale_available | Available scale ranges for the accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_x_raw | Raw X-axis accelerometer channel value. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_y_calibbias | y-axis acceleration offset correction | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_y_raw | Raw Y-axis accelerometer channel value. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_z_calibbias | Calibration offset for the Z-axis accelerometer channel. | ++-------------------------------------------+----------------------------------------------------------+ +| in_accel_z_raw | Raw Z-axis accelerometer channel value. | ++-------------------------------------------+----------------------------------------------------------+ + +Channel Processed Values +------------------------- + +A channel value can be read from its _raw attribute. The value returned is the +raw value as reported by the devices. To get the processed value of the channel, +apply the following formula: + +.. code-block:: bash + + processed value = (_raw + _offset) * _scale + +Where _offset and _scale are device attributes. If no _offset attribute is +present, simply assume its value is 0. + ++-------------------------------------+---------------------------+ +| Channel type | Measurement unit | ++-------------------------------------+---------------------------+ +| Acceleration on X, Y, and Z axis | Meters per second squared | ++-------------------------------------+---------------------------+ + +Sensor Events +------------- + +Specific IIO events are triggered by their corresponding interrupts. The sensor +driver supports either none or a single active interrupt (INT) line, selectable +from the two available options: INT1 or INT2. The active INT line should be +specified in the device tree. If no INT line is configured, the sensor defaults +to FIFO bypass mode, where event detection is disabled and only X, Y, and Z axis +measurements are available. + +The table below lists the ADXL345-related device files located in the +device-specific path: ``/sys/bus/iio/devices/iio:deviceX/events``. +Note that activity and inactivity detection are DC-coupled by default; +therefore, only the AC-coupled activity and inactivity events are explicitly +listed. + ++---------------------------------------------+---------------------------------------------+ +| Event handle | Description | ++---------------------------------------------+---------------------------------------------+ +| in_accel_gesture_doubletap_en | Enable double tap detection on all axis | ++---------------------------------------------+---------------------------------------------+ +| in_accel_gesture_doubletap_reset_timeout | Double tap window in [us] | ++---------------------------------------------+---------------------------------------------+ +| in_accel_gesture_doubletap_tap2_min_delay | Double tap latent in [us] | ++---------------------------------------------+---------------------------------------------+ +| in_accel_gesture_singletap_timeout | Single tap duration in [us] | ++---------------------------------------------+---------------------------------------------+ +| in_accel_gesture_singletap_value | Single tap threshold value in 62.5/LSB | ++---------------------------------------------+---------------------------------------------+ +| in_accel_mag_falling_period | Inactivity time in seconds | ++---------------------------------------------+---------------------------------------------+ +| in_accel_mag_falling_value | Inactivity threshold value in 62.5/LSB | ++---------------------------------------------+---------------------------------------------+ +| in_accel_mag_adaptive_rising_en | Enable AC coupled activity on X axis | ++---------------------------------------------+---------------------------------------------+ +| in_accel_mag_adaptive_falling_period | AC coupled inactivity time in seconds | ++---------------------------------------------+---------------------------------------------+ +| in_accel_mag_adaptive_falling_value | AC coupled inactivity threshold in 62.5/LSB | ++---------------------------------------------+---------------------------------------------+ +| in_accel_mag_adaptive_rising_value | AC coupled activity threshold in 62.5/LSB | ++---------------------------------------------+---------------------------------------------+ +| in_accel_mag_rising_en | Enable activity detection on X axis | ++---------------------------------------------+---------------------------------------------+ +| in_accel_mag_rising_value | Activity threshold value in 62.5/LSB | ++---------------------------------------------+---------------------------------------------+ +| in_accel_x_gesture_singletap_en | Enable single tap detection on X axis | ++---------------------------------------------+---------------------------------------------+ +| in_accel_x&y&z_mag_falling_en | Enable inactivity detection on all axis | ++---------------------------------------------+---------------------------------------------+ +| in_accel_x&y&z_mag_adaptive_falling_en | Enable AC coupled inactivity on all axis | ++---------------------------------------------+---------------------------------------------+ +| in_accel_y_gesture_singletap_en | Enable single tap detection on Y axis | ++---------------------------------------------+---------------------------------------------+ +| in_accel_z_gesture_singletap_en | Enable single tap detection on Z axis | ++---------------------------------------------+---------------------------------------------+ + +Please refer to the sensor's datasheet for a detailed description of this +functionality. + +Manually setting the **ODR** will cause the driver to estimate default values +for inactivity detection timing, where higher ODR values correspond to longer +default wait times, and lower ODR values to shorter ones. If these defaults do +not meet your application’s needs, you can explicitly configure the inactivity +wait time. Setting this value to 0 will revert to the default behavior. + +When changing the **g range** configuration, the driver attempts to estimate +appropriate activity and inactivity thresholds by scaling the default values +based on the ratio of the previous range to the new one. The resulting threshold +will never be zero and will always fall between 1 and 255, corresponding to up +to 62.5 g/LSB as specified in the datasheet. However, you can override these +estimated thresholds by setting explicit values. + +When **activity** and **inactivity** events are enabled, the driver +automatically manages hysteresis behavior by setting the **link** and +**auto-sleep** bits. The link bit connects the activity and inactivity +functions, so that one follows the other. The auto-sleep function puts the +sensor into sleep mode when inactivity is detected, reducing power consumption +to the sub-12.5 Hz rate. + +In DC-coupled mode, the current acceleration magnitude is directly compared to +the values in the THRESH_ACT and THRESH_INACT registers to determine activity or +inactivity. In contrast, AC-coupled activity detection uses the acceleration +value at the start of detection as a reference point, and subsequent samples are +compared against this reference. While DC-coupling is the default mode-comparing +live values to fixed thresholds-AC-coupling relies on an internal filter +relative to the configured threshold. + +AC and DC coupling modes are configured separately for activity and inactivity +detection, but only one mode can be active at a time for each. For example, if +AC-coupled activity detection is enabled and then DC-coupled mode is set, only +DC-coupled activity detection will be active. In other words, only the most +recent configuration is applied. + +**Single tap** detection can be configured per the datasheet by setting the +threshold and duration parameters. When only single tap detection is enabled, +the single tap interrupt triggers as soon as the acceleration exceeds the +threshold (marking the start of the duration) and then falls below it, provided +the duration limit is not exceeded. If both single tap and double tap detections +are enabled, the single tap interrupt is triggered only after the double tap +event has been either confirmed or dismissed. + +To configure **double tap** detection, you must also set the window and latency +parameters in microseconds (µs). The latency period begins once the single tap +signal drops below the threshold and acts as a waiting time during which any +spikes are ignored for double tap detection. After the latency period ends, the +detection window starts. If the acceleration rises above the threshold and then +falls below it again within this window, a double tap event is triggered upon +the fall below the threshold. + +Double tap event detection is thoroughly explained in the datasheet. After a +single tap event is detected, a double tap event may follow, provided the signal +meets certain criteria. However, double tap detection can be invalidated for +three reasons: + +* If the **suppress bit** is set, any acceleration spike above the tap + threshold during the tap latency period immediately invalidates the double tap + detection. In other words, no spikes are allowed during latency when the + suppress bit is active. + +* The double tap event is invalid if the acceleration is above the threshold at + the start of the double tap window. + +* Double tap detection is also invalidated if the acceleration duration exceeds + the limit set by the duration register. + +For double tap detection, the same duration applies as for single tap: the +acceleration must rise above the threshold and then fall below it within the +specified duration. Note that the suppress bit is typically enabled when double +tap detection is active. + +Usage Examples +-------------- + +Show device name: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat name + adxl345 + +Show accelerometer channels value: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw + -1 + root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw + 2 + root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw + -253 + +Set calibration offset for accelerometer channels: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias + 0 + + root:/sys/bus/iio/devices/iio:device0> echo 50 > in_accel_x_calibbias + root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias + 50 + +Given the 13-bit full resolution, the available ranges are calculated by the +following formula: + +.. code-block:: bash + + (g * 2 * 9.80665) / (2^(resolution) - 1) * 100; for g := 2|4|8|16 + +Scale range configuration: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_scale + 0.478899 + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_scale_available + 0.478899 0.957798 1.915595 3.831190 + + root:/sys/bus/iio/devices/iio:device0> echo 1.915595 > ./in_accel_scale + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_scale + 1.915595 + +Set output data rate (ODR): + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_sampling_frequency + 200.000000 + + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_sampling_frequency_available + 0.097000 0.195000 0.390000 0.781000 1.562000 3.125000 6.250000 12.500000 25.000000 50.000000 100.000000 200.000000 400.000000 800.000000 1600.000000 3200.000000 + + root:/sys/bus/iio/devices/iio:device0> echo 1.562000 > ./in_accel_sampling_frequency + root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_sampling_frequency + 1.562000 + +Configure one or several events: + +.. code-block:: bash + + root:> cd /sys/bus/iio/devices/iio:device0 + + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./buffer0/in_accel_x_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./buffer0/in_accel_y_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./buffer0/in_accel_z_en + + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./scan_elements/in_accel_x_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./scan_elements/in_accel_y_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./scan_elements/in_accel_z_en + + root:/sys/bus/iio/devices/iio:device0> echo 14 > ./in_accel_x_calibbias + root:/sys/bus/iio/devices/iio:device0> echo 2 > ./in_accel_y_calibbias + root:/sys/bus/iio/devices/iio:device0> echo -250 > ./in_accel_z_calibbias + + root:/sys/bus/iio/devices/iio:device0> echo 24 > ./buffer0/length + + ## AC coupled activity, threshold [62.5/LSB] + root:/sys/bus/iio/devices/iio:device0> echo 6 > ./events/in_accel_mag_adaptive_rising_value + + ## AC coupled inactivity, threshold, [62.5/LSB] + root:/sys/bus/iio/devices/iio:device0> echo 4 > ./events/in_accel_mag_adaptive_falling_value + + ## AC coupled inactivity, time [s] + root:/sys/bus/iio/devices/iio:device0> echo 3 > ./events/in_accel_mag_adaptive_falling_period + + ## singletap, threshold + root:/sys/bus/iio/devices/iio:device0> echo 35 > ./events/in_accel_gesture_singletap_value + + ## singletap, duration [us] + root:/sys/bus/iio/devices/iio:device0> echo 0.001875 > ./events/in_accel_gesture_singletap_timeout + + ## doubletap, window [us] + root:/sys/bus/iio/devices/iio:device0> echo 0.025 > ./events/in_accel_gesture_doubletap_reset_timeout + + ## doubletap, latent [us] + root:/sys/bus/iio/devices/iio:device0> echo 0.025 > ./events/in_accel_gesture_doubletap_tap2_min_delay + + ## AC coupled activity, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_mag_adaptive_rising_en + + ## AC coupled inactivity, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_x\&y\&z_mag_adaptive_falling_en + + ## singletap, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_x_gesture_singletap_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_y_gesture_singletap_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_z_gesture_singletap_en + + ## doubletap, enable + root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_gesture_doubletap_en + +Verify incoming events: + +.. code-block:: bash + + root:# iio_event_monitor adxl345 + Found IIO device with name adxl345 with device number 0 + Event: time: 1739063415957073383, type: accel(z), channel: 0, evtype: mag, direction: rising + Event: time: 1739063415963770218, type: accel(z), channel: 0, evtype: mag, direction: rising + Event: time: 1739063416002563061, type: accel(z), channel: 0, evtype: gesture, direction: singletap + Event: time: 1739063426271128739, type: accel(x&y&z), channel: 0, evtype: mag, direction: falling + Event: time: 1739063436539080713, type: accel(x&y&z), channel: 0, evtype: mag, direction: falling + Event: time: 1739063438357970381, type: accel(z), channel: 0, evtype: mag, direction: rising + Event: time: 1739063446726161586, type: accel(z), channel: 0, evtype: mag, direction: rising + Event: time: 1739063446727892670, type: accel(z), channel: 0, evtype: mag, direction: rising + Event: time: 1739063446743019768, type: accel(z), channel: 0, evtype: mag, direction: rising + Event: time: 1739063446744650696, type: accel(z), channel: 0, evtype: mag, direction: rising + Event: time: 1739063446763559386, type: accel(z), channel: 0, evtype: gesture, direction: singletap + Event: time: 1739063448818126480, type: accel(x&y&z), channel: 0, evtype: mag, direction: falling + ... + +Activity and inactivity belong together and indicate state changes as follows + +.. code-block:: bash + + root:# iio_event_monitor adxl345 + Found IIO device with name adxl345 with device number 0 + Event: time: 1744648001133946293, type: accel(x), channel: 0, evtype: mag, direction: rising + + Event: time: 1744648057724775499, type: accel(x&y&z), channel: 0, evtype: mag, direction: falling + ... + +3. Device Buffers +================= + +This driver supports IIO buffers. + +All devices support retrieving the raw acceleration and temperature measurements +using buffers. + +Usage examples +-------------- + +Select channels for buffer read: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_accel_x_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_accel_y_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_accel_z_en + +Set the number of samples to be stored in the buffer: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length + +Enable buffer readings: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable + +Obtain buffered data: + +.. code-block:: bash + + root:> iio_readdev -b 16 -s 1024 adxl345 | hexdump -d + WARNING: High-speed mode not enabled + 0000000 00003 00012 00013 00005 00010 00011 00005 00011 + 0000010 00013 00004 00012 00011 00003 00012 00014 00007 + 0000020 00011 00013 00004 00013 00014 00003 00012 00013 + 0000030 00004 00012 00013 00005 00011 00011 00005 00012 + 0000040 00014 00005 00012 00014 00004 00010 00012 00004 + 0000050 00013 00011 00003 00011 00012 00005 00011 00013 + 0000060 00003 00012 00012 00003 00012 00012 00004 00012 + 0000070 00012 00003 00013 00013 00003 00013 00012 00005 + 0000080 00012 00013 00003 00011 00012 00005 00012 00013 + 0000090 00003 00013 00011 00005 00013 00014 00003 00012 + 00000a0 00012 00003 00012 00013 00004 00012 00015 00004 + 00000b0 00014 00011 00003 00014 00013 00004 00012 00011 + 00000c0 00004 00012 00013 00004 00014 00011 00004 00013 + 00000d0 00012 00002 00014 00012 00005 00012 00013 00005 + 00000e0 00013 00013 00003 00013 00013 00005 00012 00013 + 00000f0 00004 00014 00015 00005 00012 00011 00005 00012 + ... + +See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered +data is structured. + +4. IIO Interfacing Tools +======================== + +See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO +interfacing tools. diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index c106402a91f7..9d34d9c89c43 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -33,6 +33,7 @@ Industrial I/O Kernel Drivers adis16550 adxl313 adxl380 + adxl345 bno055 ep93xx_adc opt4060 From ee6ef19778fd7604ddf6c3a3e307c0f36748f70c Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Sun, 27 Jul 2025 21:00:14 +0000 Subject: [PATCH 0201/2711] docs: iio: describe inactivity and free-fall detection on the ADXL345 Describe the inactivity detection additionally using the free-fall register. Due to the controversial discussions on the mailing list, this section of the documentation will be committed separately to allow for a more focused and detailed elaboration of the topic. Signed-off-by: Lothar Rubusch Link: https://patch.msgid.link/20250727210014.27766-8-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/iio/adxl345.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Documentation/iio/adxl345.rst b/Documentation/iio/adxl345.rst index 8ee01b8b87f4..4bd038cb4a37 100644 --- a/Documentation/iio/adxl345.rst +++ b/Documentation/iio/adxl345.rst @@ -150,6 +150,30 @@ functions, so that one follows the other. The auto-sleep function puts the sensor into sleep mode when inactivity is detected, reducing power consumption to the sub-12.5 Hz rate. +The inactivity time is configurable between 1 and 255 seconds. In addition to +inactivity detection, the sensor also supports free-fall detection, which, from +the IIO perspective, is treated as a fall in magnitude across all axes. In +sensor terms, free-fall is defined using an inactivity period ranging from 0.000 +to 1.000 seconds. + +The driver behaves as follows: +* If the configured inactivity period is 1 second or more, the driver uses the + sensor's inactivity register. This allows the event to be linked with + activity detection, use auto-sleep, and be either AC- or DC-coupled. + +* If the inactivity period is less than 1 second, the event is treated as plain + inactivity or free-fall detection. In this case, auto-sleep and coupling + (AC/DC) are not applied. + +* If an inactivity time of 0 seconds is configured, the driver selects a + heuristically determined default period (greater than 1 second) to optimize + power consumption. This also uses the inactivity register. + +Note: According to the datasheet, the optimal ODR for detecting activity, +or inactivity (or when operating with the free-fall register) should fall within +the range of 12.5 Hz to 400 Hz. The recommended free-fall threshold is between +300 mg and 600 mg (register values 0x05 to 0x09). + In DC-coupled mode, the current acceleration magnitude is directly compared to the values in the THRESH_ACT and THRESH_INACT registers to determine activity or inactivity. In contrast, AC-coupled activity detection uses the acceleration From f01701a8545f55d01a0e5f15c3dc67a7977fddc9 Mon Sep 17 00:00:00 2001 From: Marcelo Schmitt Date: Fri, 8 Aug 2025 16:02:03 -0300 Subject: [PATCH 0202/2711] MAINTAINERS: Update max30208 maintainership Update MAX30208 temperature sensor driver maintainer. The previous maintainer's email bounces and no longer works. Also mark the driver as supported. Reported-by: Dave Hansen Closes: https://lore.kernel.org/linux-iio/20250808174901.4556B33A@davehans-spike.ostc.intel.com/ Signed-off-by: Marcelo Schmitt Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250808190203.7493-1-marcelo.schmitt@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..be5ac7972bed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15008,9 +15008,9 @@ F: Documentation/devicetree/bindings/regulator/maxim,max20086.yaml F: drivers/regulator/max20086-regulator.c MAXIM MAX30208 TEMPERATURE SENSOR DRIVER -M: Rajat Khandelwal +M: Marcelo Schmitt L: linux-iio@vger.kernel.org -S: Maintained +S: Supported F: drivers/iio/temperature/max30208.c MAXIM MAX77650 PMIC MFD DRIVER From d2d75e25262e4d6e5aa453a89c60742e6808cdbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 8 Aug 2025 17:12:33 +0100 Subject: [PATCH 0203/2711] iio: imu: adis16475: remove extra line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove extra line before adis16475_probe(). Signed-off-by: Nuno Sá Link: https://patch.msgid.link/20250808-adis15475-extraline-v1-1-e3259a466e95@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 924395b7e3b4..ab39bea1e729 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -1930,7 +1930,6 @@ static int adis16475_config_irq_pin(struct adis16475 *st) return 0; } - static int adis16475_probe(struct spi_device *spi) { struct iio_dev *indio_dev; From ed187a201be15f7ea4200dc32a6b07de87e21f19 Mon Sep 17 00:00:00 2001 From: Stefano Manni Date: Thu, 7 Aug 2025 09:48:49 +0200 Subject: [PATCH 0204/2711] iio: adc: ad799x: add reference voltage capability to chip_info If the chip supports an external reference voltage on REFIN pin then the "vref-supply" regulator may be used. This commit partially refactors 6b104e7895ab16b9b7f466c5f2ca282b87f661e8 to add the capability of the chip to have an external voltage reference and then remove the ugly conditional check on chip id. Suggested-by: Andy Shevchenko Signed-off-by: Stefano Manni Acked-by: Andy Shevchenko Reviewed-by: David Lechner Link: https://patch.msgid.link/20250807074850.130831-2-stefano.manni@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 9c02f9199139..f645995b0929 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -114,11 +114,13 @@ struct ad799x_chip_config { * @num_channels: number of channels * @noirq_config: device configuration w/o IRQ * @irq_config: device configuration w/IRQ + * @has_vref: device supports external reference voltage */ struct ad799x_chip_info { int num_channels; const struct ad799x_chip_config noirq_config; const struct ad799x_chip_config irq_config; + bool has_vref; }; struct ad799x_state { @@ -604,6 +606,7 @@ static const struct iio_event_spec ad799x_events[] = { static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { [ad7991] = { .num_channels = 5, + .has_vref = true, .noirq_config = { .channel = { AD799X_CHANNEL(0, 12), @@ -617,6 +620,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, [ad7995] = { .num_channels = 5, + .has_vref = true, .noirq_config = { .channel = { AD799X_CHANNEL(0, 10), @@ -630,6 +634,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, [ad7999] = { .num_channels = 5, + .has_vref = true, .noirq_config = { .channel = { AD799X_CHANNEL(0, 8), @@ -809,32 +814,22 @@ static int ad799x_probe(struct i2c_client *client) return ret; /* check if an external reference is supplied */ - st->vref = devm_regulator_get_optional(&client->dev, "vref"); - - if (IS_ERR(st->vref)) { - if (PTR_ERR(st->vref) == -ENODEV) { + if (chip_info->has_vref) { + st->vref = devm_regulator_get_optional(&client->dev, "vref"); + ret = PTR_ERR_OR_ZERO(st->vref); + if (ret) { + if (ret != -ENODEV) + goto error_disable_reg; st->vref = NULL; dev_info(&client->dev, "Using VCC reference voltage\n"); - } else { - ret = PTR_ERR(st->vref); - goto error_disable_reg; } - } - if (st->vref) { - /* - * Use external reference voltage if supported by hardware. - * This is optional if voltage / regulator present, use VCC otherwise. - */ - if ((st->id == ad7991) || (st->id == ad7995) || (st->id == ad7999)) { + if (st->vref) { dev_info(&client->dev, "Using external reference voltage\n"); extra_config |= AD7991_REF_SEL; ret = regulator_enable(st->vref); if (ret) goto error_disable_reg; - } else { - st->vref = NULL; - dev_warn(&client->dev, "Supplied reference not supported\n"); } } From b515c701bbdfa453e2e57ae542863f1baf2c35b1 Mon Sep 17 00:00:00 2001 From: Stefano Manni Date: Thu, 7 Aug 2025 09:48:50 +0200 Subject: [PATCH 0205/2711] iio: adc: ad799x: add reference voltage to ad7994 AD7994 supports external reference voltage on REFIN pin so if a vref-supply has been defined it shall be used. Signed-off-by: Stefano Manni Reviewed-by: Andy Shevchenko Reviewed-by: David Lechner Link: https://patch.msgid.link/20250807074850.130831-3-stefano.manni@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index f645995b0929..108bb22162ef 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -692,6 +692,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, [ad7994] = { .num_channels = 5, + .has_vref = true, .noirq_config = { .channel = { AD799X_CHANNEL(0, 12), From 65e8202f03224d56896202610a5875060bb775d9 Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Tue, 5 Aug 2025 11:33:33 +0200 Subject: [PATCH 0206/2711] iio: Remove error prints for devm_add_action_or_reset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `devm_add_action_or_reset()` fails, it is due to a failed memory allocation and will thus return `-ENOMEM`. `dev_err_probe()` doesn't do anything when error is `-ENOMEM`. Therefore, remove the useless call to `dev_err_probe()` when `devm_add_action_or_reset()` fails, and just return the value instead. Signed-off-by: Waqar Hameed Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/pndectqm7te.a.out@axis.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/msa311.c | 2 +- drivers/iio/adc/ad4130.c | 3 +-- drivers/iio/adc/ad7124.c | 2 +- drivers/iio/adc/ad7173.c | 3 +-- drivers/iio/adc/mt6577_auxadc.c | 3 +-- drivers/iio/adc/pac1921.c | 3 +-- drivers/iio/adc/rockchip_saradc.c | 3 +-- drivers/iio/adc/ti-ads1119.c | 3 +-- drivers/iio/adc/ti-ads7924.c | 6 ++---- drivers/iio/frequency/adf4350.c | 3 +-- drivers/iio/light/al3000a.c | 2 +- drivers/iio/light/apds9306.c | 2 +- drivers/iio/light/bh1745.c | 3 +-- drivers/iio/light/opt4001.c | 3 +-- drivers/iio/light/opt4060.c | 3 +-- drivers/iio/magnetometer/als31300.c | 2 +- drivers/iio/magnetometer/tmag5273.c | 2 +- drivers/iio/proximity/vl53l0x-i2c.c | 3 +-- drivers/iio/temperature/mlx90635.c | 6 ++---- 19 files changed, 21 insertions(+), 36 deletions(-) diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index 3e10225410e8..2ccb22317bdc 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -1195,7 +1195,7 @@ static int msa311_probe(struct i2c_client *i2c) */ err = devm_add_action_or_reset(dev, msa311_powerdown, msa311); if (err) - return dev_err_probe(dev, err, "can't add powerdown action\n"); + return err; err = pm_runtime_set_active(dev); if (err) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index dcdb5778f7d6..5567ae5dee88 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -2035,8 +2035,7 @@ static int ad4130_probe(struct spi_device *spi) ret = devm_add_action_or_reset(dev, ad4130_disable_regulators, st); if (ret) - return dev_err_probe(dev, ret, - "Failed to add regulators disable action\n"); + return ret; ret = ad4130_soft_reset(st); if (ret) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 9808df2e9242..4481a4ca7ac3 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -1300,7 +1300,7 @@ static int ad7124_probe(struct spi_device *spi) ret = devm_add_action_or_reset(&spi->dev, ad7124_reg_disable, st->vref[i]); if (ret) - return dev_err_probe(dev, ret, "Failed to register disable handler for regulator #%d\n", i); + return ret; } st->mclk = devm_clk_get_enabled(&spi->dev, "mclk"); diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 9a32a18cc804..21a2e9b86959 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -1731,8 +1731,7 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev) ret = devm_add_action_or_reset(dev, ad7173_disable_regulators, st); if (ret) - return dev_err_probe(dev, ret, - "Failed to add regulators disable action\n"); + return ret; ret = device_property_match_property_string(dev, "clock-names", ad7173_clk_sel, diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index 3343b54e8e44..fe9e3ece3fda 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -297,8 +297,7 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) ret = devm_add_action_or_reset(&pdev->dev, mt6577_power_off, adc_dev); if (ret) - return dev_err_probe(&pdev->dev, ret, - "Failed to add action to managed power off\n"); + return ret; ret = devm_iio_device_register(&pdev->dev, indio_dev); if (ret < 0) diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c index 72aa4ca2e5a4..35433250b008 100644 --- a/drivers/iio/adc/pac1921.c +++ b/drivers/iio/adc/pac1921.c @@ -1279,8 +1279,7 @@ static int pac1921_probe(struct i2c_client *client) ret = devm_add_action_or_reset(dev, pac1921_regulator_disable, priv->vdd); if (ret) - return dev_err_probe(dev, ret, - "Cannot add action for vdd regulator disposal\n"); + return ret; msleep(PAC1921_POWERUP_TIME_MS); diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index bd62daea0a3e..926971cb50bf 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -527,8 +527,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev) ret = devm_add_action_or_reset(&pdev->dev, rockchip_saradc_regulator_disable, info); if (ret) - return dev_err_probe(&pdev->dev, ret, - "failed to register devm action\n"); + return ret; ret = regulator_get_voltage(info->vref); if (ret < 0) diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c index d2f86e1ec656..3e4f79dfb078 100644 --- a/drivers/iio/adc/ti-ads1119.c +++ b/drivers/iio/adc/ti-ads1119.c @@ -778,8 +778,7 @@ static int ads1119_probe(struct i2c_client *client) ret = devm_add_action_or_reset(dev, ads1119_powerdown, st); if (ret) - return dev_err_probe(dev, ret, - "Failed to add powerdown action\n"); + return ret; return devm_iio_device_register(dev, indio_dev); } diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c index b1f745f75dbe..46255c530cb4 100644 --- a/drivers/iio/adc/ti-ads7924.c +++ b/drivers/iio/adc/ti-ads7924.c @@ -399,8 +399,7 @@ static int ads7924_probe(struct i2c_client *client) ret = devm_add_action_or_reset(dev, ads7924_reg_disable, data->vref_reg); if (ret) - return dev_err_probe(dev, ret, - "failed to add regulator disable action\n"); + return ret; ret = ads7924_reset(indio_dev); if (ret < 0) @@ -414,8 +413,7 @@ static int ads7924_probe(struct i2c_client *client) ret = devm_add_action_or_reset(dev, ads7924_set_idle_mode, data); if (ret) - return dev_err_probe(dev, ret, - "failed to add idle mode action\n"); + return ret; /* Use minimum signal acquire time. */ ret = regmap_update_bits(data->regmap, ADS7924_ACQCONFIG_REG, diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 47f1c7e9efa9..6665409a9a87 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -673,8 +673,7 @@ static int adf4350_probe(struct spi_device *spi) ret = devm_add_action_or_reset(&spi->dev, adf4350_power_down, indio_dev); if (ret) - return dev_err_probe(&spi->dev, ret, - "Failed to add action to managed power down\n"); + return ret; return devm_iio_device_register(&spi->dev, indio_dev); } diff --git a/drivers/iio/light/al3000a.c b/drivers/iio/light/al3000a.c index 6f301c067045..9871096cbab3 100644 --- a/drivers/iio/light/al3000a.c +++ b/drivers/iio/light/al3000a.c @@ -94,7 +94,7 @@ static int al3000a_init(struct al3000a_data *data) ret = devm_add_action_or_reset(dev, al3000a_set_pwr_off, data); if (ret) - return dev_err_probe(dev, ret, "failed to add action\n"); + return ret; ret = regmap_write(data->regmap, AL3000A_REG_SYSTEM, AL3000A_CONFIG_RESET); if (ret) diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index f676da245aa7..5eb33e8e3ad9 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -1309,7 +1309,7 @@ static int apds9306_probe(struct i2c_client *client) ret = devm_add_action_or_reset(dev, apds9306_powerdown, data); if (ret) - return dev_err_probe(dev, ret, "failed to add action or reset\n"); + return ret; ret = devm_iio_device_register(dev, indio_dev); if (ret) diff --git a/drivers/iio/light/bh1745.c b/drivers/iio/light/bh1745.c index 4e9bd8f831f7..c7c604c96f6e 100644 --- a/drivers/iio/light/bh1745.c +++ b/drivers/iio/light/bh1745.c @@ -814,8 +814,7 @@ static int bh1745_init(struct bh1745_data *data) ret = devm_add_action_or_reset(dev, bh1745_power_off, data); if (ret) - return dev_err_probe(dev, ret, - "Failed to add action or reset\n"); + return ret; return 0; } diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c index ba4eb82d9bc2..95167273bb90 100644 --- a/drivers/iio/light/opt4001.c +++ b/drivers/iio/light/opt4001.c @@ -428,8 +428,7 @@ static int opt4001_probe(struct i2c_client *client) opt4001_chip_off_action, chip); if (ret < 0) - return dev_err_probe(&client->dev, ret, - "Failed to setup power off action\n"); + return ret; return devm_iio_device_register(&client->dev, indio_dev); } diff --git a/drivers/iio/light/opt4060.c b/drivers/iio/light/opt4060.c index 566f1bb8fe2a..7a1b6c703823 100644 --- a/drivers/iio/light/opt4060.c +++ b/drivers/iio/light/opt4060.c @@ -1299,8 +1299,7 @@ static int opt4060_probe(struct i2c_client *client) ret = devm_add_action_or_reset(dev, opt4060_chip_off_action, chip); if (ret < 0) - return dev_err_probe(dev, ret, - "Failed to setup power off action\n"); + return ret; ret = opt4060_setup_buffer(chip, indio_dev); if (ret) diff --git a/drivers/iio/magnetometer/als31300.c b/drivers/iio/magnetometer/als31300.c index f72af829715f..928e1378304c 100644 --- a/drivers/iio/magnetometer/als31300.c +++ b/drivers/iio/magnetometer/als31300.c @@ -373,7 +373,7 @@ static int als31300_probe(struct i2c_client *i2c) ret = devm_add_action_or_reset(dev, als31300_power_down, data); if (ret) - return dev_err_probe(dev, ret, "failed to add powerdown action\n"); + return ret; indio_dev->info = &als31300_info; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c index 2ca5c26f0091..bdb656b031b1 100644 --- a/drivers/iio/magnetometer/tmag5273.c +++ b/drivers/iio/magnetometer/tmag5273.c @@ -642,7 +642,7 @@ static int tmag5273_probe(struct i2c_client *i2c) */ ret = devm_add_action_or_reset(dev, tmag5273_power_down, data); if (ret) - return dev_err_probe(dev, ret, "failed to add powerdown action\n"); + return ret; ret = pm_runtime_set_active(dev); if (ret < 0) diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index b4d82f24be29..696340ec027a 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -351,8 +351,7 @@ static int vl53l0x_probe(struct i2c_client *client) error = devm_add_action_or_reset(&client->dev, vl53l0x_power_off, data); if (error) - return dev_err_probe(&client->dev, error, - "Failed to install poweroff action\n"); + return ret; indio_dev->name = "vl53l0x"; indio_dev->info = &vl53l0x_info; diff --git a/drivers/iio/temperature/mlx90635.c b/drivers/iio/temperature/mlx90635.c index f7f88498ba0e..1175c7887ae1 100644 --- a/drivers/iio/temperature/mlx90635.c +++ b/drivers/iio/temperature/mlx90635.c @@ -977,8 +977,7 @@ static int mlx90635_probe(struct i2c_client *client) ret = devm_add_action_or_reset(&client->dev, mlx90635_disable_regulator, mlx90635); if (ret < 0) - return dev_err_probe(&client->dev, ret, - "failed to setup regulator cleanup action\n"); + return ret; ret = mlx90635_wakeup(mlx90635); if (ret < 0) @@ -986,8 +985,7 @@ static int mlx90635_probe(struct i2c_client *client) ret = devm_add_action_or_reset(&client->dev, mlx90635_sleep, mlx90635); if (ret < 0) - return dev_err_probe(&client->dev, ret, - "failed to setup low power cleanup\n"); + return ret; ret = regmap_read(mlx90635->regmap_ee, MLX90635_EE_VERSION, &dsp_version); if (ret < 0) From 7e2d03d00475b1a560e7e8f166b7534f4ade8fff Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Mon, 28 Jul 2025 09:54:44 +0200 Subject: [PATCH 0207/2711] dt-bindings: iio: light: veml6046x00: add color sensor Add a new compatible for Vishay high accuracy RGBIR color sensor veml6046x00. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Andreas Klinger Link: https://patch.msgid.link/20250728075447.338725-2-ak@it-klinger.de Signed-off-by: Jonathan Cameron --- .../iio/light/vishay,veml6046x00.yaml | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/light/vishay,veml6046x00.yaml diff --git a/Documentation/devicetree/bindings/iio/light/vishay,veml6046x00.yaml b/Documentation/devicetree/bindings/iio/light/vishay,veml6046x00.yaml new file mode 100644 index 000000000000..112d448ff0bf --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/vishay,veml6046x00.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/light/vishay,veml6046x00.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Vishay VEML6046X00 High accuracy RGBIR color sensor + +maintainers: + - Andreas Klinger + +description: + VEML6046X00 datasheet at https://www.vishay.com/docs/80173/veml6046x00.pdf + +properties: + compatible: + enum: + - vishay,veml6046x00 + + reg: + maxItems: 1 + + vdd-supply: true + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - vdd-supply + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + color-sensor@29 { + compatible = "vishay,veml6046x00"; + reg = <0x29>; + vdd-supply = <&vdd_reg>; + interrupt-parent = <&gpio2>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + }; + }; +... From 4bfb29e8be7338ad33b905a7ce11fd26d0139287 Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Mon, 28 Jul 2025 09:54:45 +0200 Subject: [PATCH 0208/2711] iio: light: add support for veml6046x00 RGBIR color sensor Add Vishay VEML6046X00 high accuracy RGBIR color sensor. This sensor provides three colour (red, green and blue) as well as one infrared (IR) channel through I2C. Support direct and buffered mode. An optional interrupt for signaling green colour threshold underflow or overflow is not supported so far. Signed-off-by: Andreas Klinger Link: https://patch.msgid.link/20250728075447.338725-3-ak@it-klinger.de Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 13 + drivers/iio/light/Makefile | 1 + drivers/iio/light/veml6046x00.c | 1030 +++++++++++++++++++++++++++++++ 3 files changed, 1044 insertions(+) create mode 100644 drivers/iio/light/veml6046x00.c diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 4a7d983c9cd4..ac1408d374c9 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -724,6 +724,19 @@ config VEML6040 To compile this driver as a module, choose M here: the module will be called veml6040. +config VEML6046X00 + tristate "VEML6046X00 RGBIR color sensor" + select REGMAP_I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + depends on I2C + help + Say Y here if you want to build a driver for the Vishay VEML6046X00 + high accuracy RGBIR color sensor. + + To compile this driver as a module, choose M here: the + module will be called veml6046x00. + config VEML6070 tristate "VEML6070 UV A light sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 8229ebe6edc4..c0048e0d5ca8 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_VCNL4035) += vcnl4035.o obj-$(CONFIG_VEML3235) += veml3235.o obj-$(CONFIG_VEML6030) += veml6030.o obj-$(CONFIG_VEML6040) += veml6040.o +obj-$(CONFIG_VEML6046X00) += veml6046x00.o obj-$(CONFIG_VEML6070) += veml6070.o obj-$(CONFIG_VEML6075) += veml6075.o obj-$(CONFIG_VL6180) += vl6180.o diff --git a/drivers/iio/light/veml6046x00.c b/drivers/iio/light/veml6046x00.c new file mode 100644 index 000000000000..e60f24d46e7b --- /dev/null +++ b/drivers/iio/light/veml6046x00.c @@ -0,0 +1,1030 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * VEML6046X00 High Accuracy RGBIR Color Sensor + * + * Copyright (c) 2025 Andreas Klinger + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +/* + * Device registers + * Those which are accessed as bulk io are omitted + */ +#define VEML6046X00_REG_CONF0 0x00 +#define VEML6046X00_REG_CONF1 0x01 +#define VEML6046X00_REG_THDH 0x04 +#define VEML6046X00_REG_THDL 0x06 +#define VEML6046X00_REG_R 0x10 +#define VEML6046X00_REG_G 0x12 +#define VEML6046X00_REG_B 0x14 +#define VEML6046X00_REG_IR 0x16 +#define VEML6046X00_REG_ID 0x18 +#define VEML6046X00_REG_INT 0x1A +#define VEML6046X00_REG_INT_H 0x1B + +/* Bit masks for specific functionality */ +#define VEML6046X00_CONF0_ON_0 BIT(0) +#define VEML6046X00_CONF0_INT BIT(1) +#define VEML6046X00_CONF0_AF_TRIG BIT(2) +#define VEML6046X00_CONF0_AF BIT(3) +#define VEML6046X00_CONF0_IT GENMASK(6, 4) +#define VEML6046X00_CONF1_CAL BIT(0) +#define VEML6046X00_CONF1_PERS GENMASK(2, 1) +#define VEML6046X00_CONF1_GAIN GENMASK(4, 3) +#define VEML6046X00_CONF1_PD_D2 BIT(6) +#define VEML6046X00_CONF1_ON_1 BIT(7) +#define VEML6046X00_INT_TH_H BIT(1) +#define VEML6046X00_INT_TH_L BIT(2) +#define VEML6046X00_INT_DRDY BIT(3) +#define VEML6046X00_INT_MASK \ + (VEML6046X00_INT_TH_H | VEML6046X00_INT_TH_L | VEML6046X00_INT_DRDY) + +#define VEML6046X00_GAIN_1 0x0 +#define VEML6046X00_GAIN_2 0x1 +#define VEML6046X00_GAIN_0_66 0x2 +#define VEML6046X00_GAIN_0_5 0x3 + +#define VEML6046X00_PD_2_2 0x0 +#define VEML6046X00_PD_1_2 BIT(6) + +/* Autosuspend delay */ +#define VEML6046X00_AUTOSUSPEND_MS (3 * MSEC_PER_SEC) + +enum veml6046x00_scan { + VEML6046X00_SCAN_R, + VEML6046X00_SCAN_G, + VEML6046X00_SCAN_B, + VEML6046X00_SCAN_IR, + VEML6046X00_SCAN_TIMESTAMP, +}; + +/** + * struct veml6046x00_rf - Regmap field of configuration registers. + * @int_en: Interrupt enable of green channel. + * @mode: Mode of operation. + * Driver uses always Active force mode. + * @trig: Trigger to be set in active force mode for starting + * measurement. + * @it: Integration time. + * @pers: Persistense - Number of threshold crossing for triggering + * interrupt. + */ +struct veml6046x00_rf { + struct regmap_field *int_en; + struct regmap_field *mode; + struct regmap_field *trig; + struct regmap_field *it; + struct regmap_field *pers; +}; + +/** + * struct veml6046x00_data - Private data of driver. + * @regmap: Regmap definition of sensor. + * @trig: Industrial-IO trigger. + * @rf: Regmap field of configuration. + */ +struct veml6046x00_data { + struct regmap *regmap; + struct iio_trigger *trig; + struct veml6046x00_rf rf; +}; + +/** + * DOC: Valid integration times (IT) + * + * static const int veml6046x00_it contains the array with valid IT. + * + * Register value to be read or written in regmap_field it on veml6046x00 is + * identical with array index. + * This means there is no separate translation table between valid integration + * times and register values needed. The index of the array is identical with + * the register value. + * + * The array is in the form as expected by the callback of the sysfs attribute + * integration_time_available (IIO_CHAN_INFO_INT_TIME). So there is no + * additional conversion needed. + */ +static const int veml6046x00_it[][2] = { + { 0, 3125 }, + { 0, 6250 }, + { 0, 12500 }, + { 0, 25000 }, + { 0, 50000 }, + { 0, 100000 }, + { 0, 200000 }, + { 0, 400000 }, +}; + +/** + * DOC: Handling of gain and photodiode size (PD) + * + * Gains here in the driver are not exactly the same as in the datasheet of the + * sensor. The gain in the driver is a combination of the gain of the sensor + * with the photodiode size (PD). + * The following combinations are possible: + * gain(driver) = gain(sensor) * PD + * 0.25 = x0.5 * 1/2 + * 0.33 = x0.66 * 1/2 + * 0.5 = x0.5 * 2/2 + * 0.66 = x0.66 * 2/2 + * 1 = x1 * 2/2 + * 2 = x2 * 2/2 + */ + +/** + * struct veml6046x00_gain_pd - Translation of gain and photodiode size (PD). + * @gain_sen: Gain used in the sensor as described in the datasheet of the + * sensor + * @pd: Photodiode size in the sensor + * + * This is the translation table from the gain used in the driver (and also used + * by the userspace interface in sysfs) to the gain and PD used in the sensor + * hardware. + * + * There are six gain values visible to the user (0.25 .. 2) which translate to + * two different gains in the sensor hardware (x0.5 .. x2) and two PD (1/2 and + * 2/2). Theoretical are there eight combinations, but gain values 0.5 and 1 are + * doubled and therefore the combination with the larger PD (2/2) is taken as + * more photodiode cells are supposed to deliver a more precise result. + */ +struct veml6046x00_gain_pd { + unsigned int gain_sen; + unsigned int pd; +}; + +static const struct veml6046x00_gain_pd veml6046x00_gain_pd[] = { + { .gain_sen = VEML6046X00_GAIN_0_5, .pd = VEML6046X00_PD_1_2 }, + { .gain_sen = VEML6046X00_GAIN_0_66, .pd = VEML6046X00_PD_1_2 }, + { .gain_sen = VEML6046X00_GAIN_0_5, .pd = VEML6046X00_PD_2_2 }, + { .gain_sen = VEML6046X00_GAIN_0_66, .pd = VEML6046X00_PD_2_2 }, + { .gain_sen = VEML6046X00_GAIN_1, .pd = VEML6046X00_PD_2_2 }, + { .gain_sen = VEML6046X00_GAIN_2, .pd = VEML6046X00_PD_2_2 }, +}; + +/** + * DOC: Factors for calculation of lux + * + * static const int veml6046x00_it_gains contains the factors for calculation of + * lux. + * + * Depending on the set up integration time (IT), gain and photodiode size (PD) + * the measured raw values are different if the light is constant. As the gain + * and PD are already coupled in the driver (see &struct veml6046x00_gain_pd) + * there are two dimensions remaining: IT and gain(driver). + * + * The array of available factors for a certain IT are grouped together in the + * same form as expected by the callback of scale_available + * (IIO_CHAN_INFO_SCALE). + * + * Factors for lux / raw count are taken directly from the datasheet. + */ +static const int veml6046x00_it_gains[][6][2] = { + /* integration time: 3.125 ms */ + { + { 5, 376000 }, /* gain: x0.25 */ + { 4, 72700 }, /* gain: x0.33 */ + { 2, 688000 }, /* gain: x0.5 */ + { 2, 36400 }, /* gain: x0.66 */ + { 1, 344000 }, /* gain: x1 */ + { 0, 672000 }, /* gain: x2 */ + }, + /* integration time: 6.25 ms */ + { + { 2, 688000 }, /* gain: x0.25 */ + { 2, 36350 }, /* gain: x0.33 */ + { 1, 344000 }, /* gain: x0.5 */ + { 1, 18200 }, /* gain: x0.66 */ + { 0, 672000 }, /* gain: x1 */ + { 0, 336000 }, /* gain: x2 */ + }, + /* integration time: 12.5 ms */ + { + { 1, 344000 }, /* gain: x0.25 */ + { 1, 18175 }, /* gain: x0.33 */ + { 0, 672000 }, /* gain: x0.5 */ + { 0, 509100 }, /* gain: x0.66 */ + { 0, 336000 }, /* gain: x1 */ + { 0, 168000 }, /* gain: x2 */ + }, + /* integration time: 25 ms */ + { + { 0, 672000 }, /* gain: x0.25 */ + { 0, 509087 }, /* gain: x0.33 */ + { 0, 336000 }, /* gain: x0.5 */ + { 0, 254550 }, /* gain: x0.66 */ + { 0, 168000 }, /* gain: x1 */ + { 0, 84000 }, /* gain: x2 */ + }, + /* integration time: 50 ms */ + { + { 0, 336000 }, /* gain: x0.25 */ + { 0, 254543 }, /* gain: x0.33 */ + { 0, 168000 }, /* gain: x0.5 */ + { 0, 127275 }, /* gain: x0.66 */ + { 0, 84000 }, /* gain: x1 */ + { 0, 42000 }, /* gain: x2 */ + }, + /* integration time: 100 ms */ + { + { 0, 168000 }, /* gain: x0.25 */ + { 0, 127271 }, /* gain: x0.33 */ + { 0, 84000 }, /* gain: x0.5 */ + { 0, 63637 }, /* gain: x0.66 */ + { 0, 42000 }, /* gain: x1 */ + { 0, 21000 }, /* gain: x2 */ + }, + /* integration time: 200 ms */ + { + { 0, 84000 }, /* gain: x0.25 */ + { 0, 63635 }, /* gain: x0.33 */ + { 0, 42000 }, /* gain: x0.5 */ + { 0, 31818 }, /* gain: x0.66 */ + { 0, 21000 }, /* gain: x1 */ + { 0, 10500 }, /* gain: x2 */ + }, + /* integration time: 400 ms */ + { + { 0, 42000 }, /* gain: x0.25 */ + { 0, 31817 }, /* gain: x0.33 */ + { 0, 21000 }, /* gain: x0.5 */ + { 0, 15909 }, /* gain: x0.66 */ + { 0, 10500 }, /* gain: x1 */ + { 0, 5250 }, /* gain: x2 */ + }, +}; + +/* + * Two bits (RGB_ON_0 and RGB_ON_1) must be cleared to power on the device. + */ +static int veml6046x00_power_on(struct veml6046x00_data *data) +{ + int ret; + struct device *dev = regmap_get_device(data->regmap); + + ret = regmap_clear_bits(data->regmap, VEML6046X00_REG_CONF0, + VEML6046X00_CONF0_ON_0); + if (ret) { + dev_err(dev, "Failed to set bit for power on %d\n", ret); + return ret; + } + + return regmap_clear_bits(data->regmap, VEML6046X00_REG_CONF1, + VEML6046X00_CONF1_ON_1); +} + +/* + * Two bits (RGB_ON_0 and RGB_ON_1) must be set to power off the device. + */ +static int veml6046x00_shutdown(struct veml6046x00_data *data) +{ + int ret; + struct device *dev = regmap_get_device(data->regmap); + + ret = regmap_set_bits(data->regmap, VEML6046X00_REG_CONF0, + VEML6046X00_CONF0_ON_0); + if (ret) { + dev_err(dev, "Failed to set bit for shutdown %d\n", ret); + return ret; + } + + return regmap_set_bits(data->regmap, VEML6046X00_REG_CONF1, + VEML6046X00_CONF1_ON_1); +} + +static void veml6046x00_shutdown_action(void *data) +{ + veml6046x00_shutdown(data); +} + +static const struct iio_chan_spec veml6046x00_channels[] = { + { + .type = IIO_INTENSITY, + .address = VEML6046X00_REG_R, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_RED, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index = VEML6046X00_SCAN_R, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + }, + { + .type = IIO_INTENSITY, + .address = VEML6046X00_REG_G, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_GREEN, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index = VEML6046X00_SCAN_G, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + }, + { + .type = IIO_INTENSITY, + .address = VEML6046X00_REG_B, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BLUE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index = VEML6046X00_SCAN_B, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + }, + { + .type = IIO_INTENSITY, + .address = VEML6046X00_REG_IR, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_IR, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index = VEML6046X00_SCAN_IR, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(VEML6046X00_SCAN_TIMESTAMP), +}; + +static const struct regmap_config veml6046x00_regmap_config = { + .name = "veml6046x00_regm", + .reg_bits = 8, + .val_bits = 8, + .max_register = VEML6046X00_REG_INT_H, +}; + +static const struct reg_field veml6046x00_rf_int_en = + REG_FIELD(VEML6046X00_REG_CONF0, 1, 1); + +static const struct reg_field veml6046x00_rf_trig = + REG_FIELD(VEML6046X00_REG_CONF0, 2, 2); + +static const struct reg_field veml6046x00_rf_mode = + REG_FIELD(VEML6046X00_REG_CONF0, 3, 3); + +static const struct reg_field veml6046x00_rf_it = + REG_FIELD(VEML6046X00_REG_CONF0, 4, 6); + +static const struct reg_field veml6046x00_rf_pers = + REG_FIELD(VEML6046X00_REG_CONF1, 1, 2); + +static int veml6046x00_regfield_init(struct veml6046x00_data *data) +{ + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(data->regmap); + struct regmap_field *rm_field; + struct veml6046x00_rf *rf = &data->rf; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml6046x00_rf_int_en); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->int_en = rm_field; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml6046x00_rf_mode); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->mode = rm_field; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml6046x00_rf_trig); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->trig = rm_field; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml6046x00_rf_it); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->it = rm_field; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml6046x00_rf_pers); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->pers = rm_field; + + return 0; +} + +static int veml6046x00_get_it_index(struct veml6046x00_data *data) +{ + int ret; + unsigned int reg; + + ret = regmap_field_read(data->rf.it, ®); + if (ret) + return ret; + + /* register value is identical with index of array */ + if (reg >= ARRAY_SIZE(veml6046x00_it)) + return -EINVAL; + + return reg; +} + +static int veml6046x00_get_it_usec(struct veml6046x00_data *data, unsigned int *it_usec) +{ + int ret; + unsigned int reg; + + ret = regmap_field_read(data->rf.it, ®); + if (ret) + return ret; + + if (reg >= ARRAY_SIZE(veml6046x00_it)) + return -EINVAL; + + *it_usec = veml6046x00_it[reg][1]; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int veml6046x00_set_it(struct iio_dev *iio, int val, int val2) +{ + struct veml6046x00_data *data = iio_priv(iio); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(veml6046x00_it); i++) { + if ((veml6046x00_it[i][0] == val) && + (veml6046x00_it[i][1] == val2)) + return regmap_field_write(data->rf.it, i); + } + + return -EINVAL; +} + +static int veml6046x00_get_val_gain_idx(struct veml6046x00_data *data, int val, + int val2) +{ + unsigned int i; + int it_idx; + + it_idx = veml6046x00_get_it_index(data); + if (it_idx < 0) + return it_idx; + + for (i = 0; i < ARRAY_SIZE(veml6046x00_it_gains[it_idx]); i++) { + if ((veml6046x00_it_gains[it_idx][i][0] == val) && + (veml6046x00_it_gains[it_idx][i][1] == val2)) + return i; + } + + return -EINVAL; +} + +static int veml6046x00_get_gain_idx(struct veml6046x00_data *data) +{ + int ret; + unsigned int i, reg, reg_gain, reg_pd; + + ret = regmap_read(data->regmap, VEML6046X00_REG_CONF1, ®); + if (ret) + return ret; + + reg_gain = FIELD_GET(VEML6046X00_CONF1_GAIN, reg); + reg_pd = reg & VEML6046X00_CONF1_PD_D2; + + for (i = 0; i < ARRAY_SIZE(veml6046x00_gain_pd); i++) { + if ((veml6046x00_gain_pd[i].gain_sen == reg_gain) && + (veml6046x00_gain_pd[i].pd == reg_pd)) + return i; + } + + return -EINVAL; +} + +static int veml6046x00_set_scale(struct iio_dev *iio, int val, int val2) +{ + struct veml6046x00_data *data = iio_priv(iio); + unsigned int new_scale; + int gain_idx; + + gain_idx = veml6046x00_get_val_gain_idx(data, val, val2); + if (gain_idx < 0) + return gain_idx; + + new_scale = FIELD_PREP(VEML6046X00_CONF1_GAIN, + veml6046x00_gain_pd[gain_idx].gain_sen) | + veml6046x00_gain_pd[gain_idx].pd; + + return regmap_update_bits(data->regmap, VEML6046X00_REG_CONF1, + VEML6046X00_CONF1_GAIN | + VEML6046X00_CONF1_PD_D2, + new_scale); +} + +static int veml6046x00_get_scale(struct veml6046x00_data *data, + int *val, int *val2) +{ + int gain_idx, it_idx; + + gain_idx = veml6046x00_get_gain_idx(data); + if (gain_idx < 0) + return gain_idx; + + it_idx = veml6046x00_get_it_index(data); + if (it_idx < 0) + return it_idx; + + *val = veml6046x00_it_gains[it_idx][gain_idx][0]; + *val2 = veml6046x00_it_gains[it_idx][gain_idx][1]; + + return IIO_VAL_INT_PLUS_MICRO; +} + +/** + * veml6046x00_read_data_ready() - Read data ready bit + * @data: Private data. + * + * Helper function for reading data ready bit from interrupt register. + * + * Return: + * * %1 - Data is available (AF_DATA_READY is set) + * * %0 - No data available + * * %-EIO - Error during bulk read + */ +static int veml6046x00_read_data_ready(struct veml6046x00_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + int ret; + u8 reg[2]; + + /* + * Note from the vendor, but not explicitly in the datasheet: we + * should always read both registers together. + */ + ret = regmap_bulk_read(data->regmap, VEML6046X00_REG_INT, + ®, sizeof(reg)); + if (ret) { + dev_err(dev, "Failed to read interrupt register %d\n", ret); + return -EIO; + } + + if (reg[1] & VEML6046X00_INT_DRDY) + return 1; + + return 0; +} + +/** + * veml6046x00_wait_data_available() - Wait until data is available + * @iio: Industrial IO. + * @usecs: Microseconds to wait for data. + * + * This function waits for a certain bit in the interrupt register which signals + * that there is data to be read available. + * + * It tries it two times with a waiting time of usecs in between. + * + * Return: + * * %1 - Data is available (AF_DATA_READY is set) + * * %0 - Timeout, no data available after usecs timeout + * * %-EIO - Error during bulk read + */ +static int veml6046x00_wait_data_available(struct iio_dev *iio, unsigned int usecs) +{ + struct veml6046x00_data *data = iio_priv(iio); + int ret; + + ret = veml6046x00_read_data_ready(data); + if (ret) + return ret; + + fsleep(usecs); + return veml6046x00_read_data_ready(data); +} + +static int veml6046x00_single_read(struct iio_dev *iio, + enum iio_modifier modifier, int *val) +{ + struct veml6046x00_data *data = iio_priv(iio); + struct device *dev = regmap_get_device(data->regmap); + unsigned int addr, it_usec; + int ret; + __le16 reg; + + switch (modifier) { + case IIO_MOD_LIGHT_RED: + addr = VEML6046X00_REG_R; + break; + case IIO_MOD_LIGHT_GREEN: + addr = VEML6046X00_REG_G; + break; + case IIO_MOD_LIGHT_BLUE: + addr = VEML6046X00_REG_B; + break; + case IIO_MOD_LIGHT_IR: + addr = VEML6046X00_REG_IR; + break; + default: + return -EINVAL; + } + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = veml6046x00_get_it_usec(data, &it_usec); + if (ret < 0) { + dev_err(dev, "Failed to get integration time ret: %d", ret); + goto out; + } + + ret = regmap_field_write(data->rf.mode, 1); + if (ret) { + dev_err(dev, "Failed to write mode ret: %d", ret); + goto out; + } + + ret = regmap_field_write(data->rf.trig, 1); + if (ret) { + dev_err(dev, "Failed to write trigger ret: %d", ret); + goto out; + } + + /* integration time + 12.5 % to ensure completion */ + fsleep(it_usec + it_usec / 8); + + ret = veml6046x00_wait_data_available(iio, it_usec * 4); + if (ret < 0) + goto out; + if (ret == 0) { + ret = -EAGAIN; + goto out; + } + + if (!iio_device_claim_direct(iio)) { + ret = -EBUSY; + goto out; + } + + ret = regmap_bulk_read(data->regmap, addr, ®, sizeof(reg)); + iio_device_release_direct(iio); + if (ret) + goto out; + + *val = le16_to_cpu(reg); + + ret = IIO_VAL_INT; + +out: + pm_runtime_put_autosuspend(dev); + + return ret; +} + +static int veml6046x00_read_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct veml6046x00_data *data = iio_priv(iio); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type != IIO_INTENSITY) + return -EINVAL; + return veml6046x00_single_read(iio, chan->channel2, val); + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + return veml6046x00_get_it_usec(data, val2); + case IIO_CHAN_INFO_SCALE: + return veml6046x00_get_scale(data, val, val2); + default: + return -EINVAL; + } +} + +static int veml6046x00_read_avail(struct iio_dev *iio, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct veml6046x00_data *data = iio_priv(iio); + int it_idx; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *vals = (int *)&veml6046x00_it; + *length = 2 * ARRAY_SIZE(veml6046x00_it); + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + it_idx = veml6046x00_get_it_index(data); + if (it_idx < 0) + return it_idx; + *vals = (int *)&veml6046x00_it_gains[it_idx]; + *length = 2 * ARRAY_SIZE(veml6046x00_it_gains[it_idx]); + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int veml6046x00_write_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + return veml6046x00_set_it(iio, val, val2); + case IIO_CHAN_INFO_SCALE: + return veml6046x00_set_scale(iio, val, val2); + default: + return -EINVAL; + } +} + +static const struct iio_info veml6046x00_info_no_irq = { + .read_raw = veml6046x00_read_raw, + .read_avail = veml6046x00_read_avail, + .write_raw = veml6046x00_write_raw, +}; + +static int veml6046x00_buffer_preenable(struct iio_dev *iio) +{ + struct veml6046x00_data *data = iio_priv(iio); + struct device *dev = regmap_get_device(data->regmap); + int ret; + + ret = regmap_field_write(data->rf.mode, 0); + if (ret) { + dev_err(dev, "Failed to set mode %d\n", ret); + return ret; + } + + ret = regmap_field_write(data->rf.trig, 0); + if (ret) { + /* + * no unrolling of mode as it is set appropriately with next + * single read. + */ + dev_err(dev, "Failed to set trigger %d\n", ret); + return ret; + } + + return pm_runtime_resume_and_get(dev); +} + +static int veml6046x00_buffer_postdisable(struct iio_dev *iio) +{ + struct veml6046x00_data *data = iio_priv(iio); + struct device *dev = regmap_get_device(data->regmap); + int ret; + + ret = regmap_field_write(data->rf.mode, 1); + if (ret) { + dev_err(dev, "Failed to set mode %d\n", ret); + return ret; + } + + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static const struct iio_buffer_setup_ops veml6046x00_buffer_setup_ops = { + .preenable = veml6046x00_buffer_preenable, + .postdisable = veml6046x00_buffer_postdisable, +}; + +static irqreturn_t veml6046x00_trig_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *iio = pf->indio_dev; + struct veml6046x00_data *data = iio_priv(iio); + int ret; + struct { + __le16 chans[4]; + aligned_s64 timestamp; + } scan; + + ret = regmap_bulk_read(data->regmap, VEML6046X00_REG_R, + &scan.chans, sizeof(scan.chans)); + if (ret) + goto done; + + iio_push_to_buffers_with_ts(iio, &scan, sizeof(scan), + iio_get_time_ns(iio)); + +done: + iio_trigger_notify_done(iio->trig); + + return IRQ_HANDLED; +} + +static int veml6046x00_validate_part_id(struct veml6046x00_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + unsigned int part_id; + int ret; + __le16 reg; + + ret = regmap_bulk_read(data->regmap, VEML6046X00_REG_ID, + ®, sizeof(reg)); + if (ret) + return dev_err_probe(dev, ret, "Failed to read ID\n"); + + part_id = le16_to_cpu(reg); + if (part_id != 0x01) + dev_info(dev, "Unknown ID %#04x\n", part_id); + + return 0; +} + +static int veml6046x00_setup_device(struct iio_dev *iio) +{ + struct veml6046x00_data *data = iio_priv(iio); + struct device *dev = regmap_get_device(data->regmap); + int ret; + __le16 reg16; + + reg16 = cpu_to_le16(VEML6046X00_CONF0_AF); + ret = regmap_bulk_write(data->regmap, VEML6046X00_REG_CONF0, + ®16, sizeof(reg16)); + if (ret) + return dev_err_probe(dev, ret, "Failed to set configuration\n"); + + reg16 = cpu_to_le16(0); + ret = regmap_bulk_write(data->regmap, VEML6046X00_REG_THDL, + ®16, sizeof(reg16)); + if (ret) + return dev_err_probe(dev, ret, "Failed to set low threshold\n"); + + reg16 = cpu_to_le16(U16_MAX); + ret = regmap_bulk_write(data->regmap, VEML6046X00_REG_THDH, + ®16, sizeof(reg16)); + if (ret) + return dev_err_probe(dev, ret, "Failed to set high threshold\n"); + + ret = regmap_bulk_read(data->regmap, VEML6046X00_REG_INT, + ®16, sizeof(reg16)); + if (ret) + return dev_err_probe(dev, ret, "Failed to clear interrupts\n"); + + return 0; +} + +static int veml6046x00_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct veml6046x00_data *data; + struct iio_dev *iio; + struct regmap *regmap; + int ret; + + regmap = devm_regmap_init_i2c(i2c, &veml6046x00_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Failed to set regmap\n"); + + iio = devm_iio_device_alloc(dev, sizeof(*data)); + if (!iio) + return -ENOMEM; + + data = iio_priv(iio); + /* struct iio_dev is retrieved via dev_get_drvdata(). */ + i2c_set_clientdata(i2c, iio); + data->regmap = regmap; + + ret = veml6046x00_regfield_init(data); + if (ret) + return dev_err_probe(dev, ret, "Failed to init regfield\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulator\n"); + + /* bring device in a known state and switch device on */ + ret = veml6046x00_setup_device(iio); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(dev, veml6046x00_shutdown_action, data); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to add shut down action\n"); + + ret = pm_runtime_set_active(dev); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to activate PM runtime\n"); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable PM runtime\n"); + + pm_runtime_get_noresume(dev); + pm_runtime_set_autosuspend_delay(dev, VEML6046X00_AUTOSUSPEND_MS); + pm_runtime_use_autosuspend(dev); + + ret = veml6046x00_validate_part_id(data); + if (ret) + return dev_err_probe(dev, ret, "Failed to validate device ID\n"); + + iio->name = "veml6046x00"; + iio->channels = veml6046x00_channels; + iio->num_channels = ARRAY_SIZE(veml6046x00_channels); + iio->modes = INDIO_DIRECT_MODE; + + iio->info = &veml6046x00_info_no_irq; + + ret = devm_iio_triggered_buffer_setup(dev, iio, NULL, + veml6046x00_trig_handler, + &veml6046x00_buffer_setup_ops); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register triggered buffer"); + + pm_runtime_put_autosuspend(dev); + + ret = devm_iio_device_register(dev, iio); + if (ret) + return dev_err_probe(dev, ret, "Failed to register iio device"); + + return 0; +} + +static int veml6046x00_runtime_suspend(struct device *dev) +{ + struct veml6046x00_data *data = iio_priv(dev_get_drvdata(dev)); + + return veml6046x00_shutdown(data); +} + +static int veml6046x00_runtime_resume(struct device *dev) +{ + struct veml6046x00_data *data = iio_priv(dev_get_drvdata(dev)); + + return veml6046x00_power_on(data); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(veml6046x00_pm_ops, + veml6046x00_runtime_suspend, + veml6046x00_runtime_resume, NULL); + +static const struct of_device_id veml6046x00_of_match[] = { + { .compatible = "vishay,veml6046x00" }, + { } +}; +MODULE_DEVICE_TABLE(of, veml6046x00_of_match); + +static const struct i2c_device_id veml6046x00_id[] = { + { "veml6046x00" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, veml6046x00_id); + +static struct i2c_driver veml6046x00_driver = { + .driver = { + .name = "veml6046x00", + .of_match_table = veml6046x00_of_match, + .pm = pm_ptr(&veml6046x00_pm_ops), + }, + .probe = veml6046x00_probe, + .id_table = veml6046x00_id, +}; +module_i2c_driver(veml6046x00_driver); + +MODULE_AUTHOR("Andreas Klinger "); +MODULE_DESCRIPTION("VEML6046X00 RGBIR Color Sensor"); +MODULE_LICENSE("GPL"); From 4c0cdcf130a7b69a8a43167fb3b4183f7edfd60e Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Mon, 28 Jul 2025 09:54:46 +0200 Subject: [PATCH 0209/2711] MAINTAINER: add maintainer for veml6046x00 Add maintainer for Vishay veml6046x00 RGBIR color sensor driver and dt binding. Signed-off-by: Andreas Klinger Link: https://patch.msgid.link/20250728075447.338725-4-ak@it-klinger.de Signed-off-by: Jonathan Cameron --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index be5ac7972bed..df0ea951b8c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26803,6 +26803,12 @@ S: Maintained F: Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml F: drivers/iio/light/veml6030.c +VISHAY VEML6046X00 RGBIR COLOR SENSOR DRIVER +M: Andreas Klinger +S: Maintained +F: Documentation/devicetree/bindings/iio/light/vishay,veml6046x00.yaml +F: drivers/iio/light/veml6046x00.c + VISHAY VEML6075 UVA AND UVB LIGHT SENSOR DRIVER M: Javier Carrasco S: Maintained From c1d7b8fe67e6b05a4a521d00ddc015811cb29b61 Mon Sep 17 00:00:00 2001 From: Erick Setubal Bacurau Date: Fri, 15 Aug 2025 09:00:01 +0200 Subject: [PATCH 0210/2711] docs: iio: bno055: Correct wording in driver documentation Fix typos and improve wording in the bno055 driver documentation. Signed-off-by: Erick Setubal Bacurau Reviewed-by: Bagas Sanjaya Link: https://patch.msgid.link/20250815070001.55185-1-erick.setubal@gmx.de Signed-off-by: Jonathan Cameron --- Documentation/iio/bno055.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/iio/bno055.rst b/Documentation/iio/bno055.rst index f1111ff3fe2e..c6042586b2ae 100644 --- a/Documentation/iio/bno055.rst +++ b/Documentation/iio/bno055.rst @@ -9,11 +9,11 @@ BNO055 driver This driver supports Bosch BNO055 IMUs (on both serial and I2C busses). -Accelerometer, magnetometer and gyroscope measures are always provided. +Accelerometer, magnetometer and gyroscope measurements are always available. When "fusion_enable" sysfs attribute is set to 1, orientation (both Euler angles and quaternion), linear velocity and gravity vector are also provided, but some sensor settings (e.g. low pass filtering and range) -became locked (the IMU firmware controls them). +become locked (the IMU firmware controls them). This driver supports also IIO buffers. @@ -24,14 +24,14 @@ The IMU continuously performs an autocalibration procedure if (and only if) operating in fusion mode. The magnetometer autocalibration can however be disabled by writing 0 in the sysfs in_magn_calibration_fast_enable attribute. -The driver provides access to autocalibration flags (i.e. you can known if -the IMU has successfully autocalibrated) and to the calibration data blob. +The driver provides access to autocalibration flags (i.e. you can determine +if the IMU has successfully autocalibrated) and to the calibration data blob. The user can save this blob in a firmware file (i.e. in /lib/firmware) that the driver looks for at probe time. If found, then the IMU is initialized with this calibration data. This saves the user from performing the -calibration procedure every time (which consist of moving the IMU in -various way). +calibration procedure every time (which consists of moving the IMU in +various ways). The driver looks for calibration data file using two different names: first a file whose name is suffixed with the IMU unique ID (exposed in sysfs as From 79ca9bf90c8ac9f4f3560aa50dcf37d59d218c76 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:50:27 +0300 Subject: [PATCH 0211/2711] iio: adc: ad7476: Simplify chip type detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ad7476 driver uses a table of structures for defining the IC variant specific data. Table is indexed using enum values, which are picked by SPI ID. Having the table and an enum adds extra complexity and may encourage adding IC specific quircks in the code, instead of centralizing the IC differences in one place, the chip-info. Simplify this by dropping the table and using individual structures for the IC specific data, and storing the IC specific structure's address directly in the SPI ID data. Finally, switch to the spi_get_device_match_data() and add a check for the return value. Signed-off-by: Matti Vaittinen Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/9e179bb3ba52303448ae4a559c1f011acd3f2fa6.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7476.c | 296 +++++++++++++++++++-------------------- 1 file changed, 146 insertions(+), 150 deletions(-) diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index aea734aa06bd..9869526c1524 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -52,29 +52,6 @@ struct ad7476_state { unsigned char data[ALIGN(2, sizeof(s64)) + sizeof(s64)] __aligned(IIO_DMA_MINALIGN); }; -enum ad7476_supported_device_ids { - ID_AD7091, - ID_AD7091R, - ID_AD7273, - ID_AD7274, - ID_AD7276, - ID_AD7277, - ID_AD7278, - ID_AD7466, - ID_AD7467, - ID_AD7468, - ID_AD7475, - ID_AD7495, - ID_AD7940, - ID_ADC081S, - ID_ADC101S, - ID_ADC121S, - ID_ADS7866, - ID_ADS7867, - ID_ADS7868, - ID_LTC2314_14, -}; - static void ad7091_convst(struct ad7476_state *st) { if (!st->convst_gpio) @@ -190,102 +167,119 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, #define ADS786X_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \ BIT(IIO_CHAN_INFO_RAW)) -static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { - [ID_AD7091] = { - .channel[0] = AD7091R_CHAN(12), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .convst_channel[0] = AD7091R_CONVST_CHAN(12), - .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .reset = ad7091_reset, - }, - [ID_AD7091R] = { - .channel[0] = AD7091R_CHAN(12), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .convst_channel[0] = AD7091R_CONVST_CHAN(12), - .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .int_vref_uv = 2500000, - .has_vref = true, - .reset = ad7091_reset, - }, - [ID_AD7273] = { - .channel[0] = AD7940_CHAN(10), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .has_vref = true, - }, - [ID_AD7274] = { - .channel[0] = AD7940_CHAN(12), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .has_vref = true, - }, - [ID_AD7276] = { - .channel[0] = AD7940_CHAN(12), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_AD7277] = { - .channel[0] = AD7940_CHAN(10), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_AD7278] = { - .channel[0] = AD7940_CHAN(8), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_AD7466] = { - .channel[0] = AD7476_CHAN(12), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_AD7467] = { - .channel[0] = AD7476_CHAN(10), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_AD7468] = { - .channel[0] = AD7476_CHAN(8), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_AD7475] = { - .channel[0] = AD7476_CHAN(12), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .has_vref = true, - .has_vdrive = true, - }, - [ID_AD7495] = { - .channel[0] = AD7476_CHAN(12), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .int_vref_uv = 2500000, - .has_vdrive = true, - }, - [ID_AD7940] = { - .channel[0] = AD7940_CHAN(14), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_ADC081S] = { - .channel[0] = ADC081S_CHAN(8), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_ADC101S] = { - .channel[0] = ADC081S_CHAN(10), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_ADC121S] = { - .channel[0] = ADC081S_CHAN(12), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_ADS7866] = { - .channel[0] = ADS786X_CHAN(12), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_ADS7867] = { - .channel[0] = ADS786X_CHAN(10), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_ADS7868] = { - .channel[0] = ADS786X_CHAN(8), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - }, - [ID_LTC2314_14] = { - .channel[0] = AD7940_CHAN(14), - .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .has_vref = true, - }, +static const struct ad7476_chip_info ad7091_chip_info = { + .channel[0] = AD7091R_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .convst_channel[0] = AD7091R_CONVST_CHAN(12), + .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .reset = ad7091_reset, +}; + +static const struct ad7476_chip_info ad7091r_chip_info = { + .channel[0] = AD7091R_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .convst_channel[0] = AD7091R_CONVST_CHAN(12), + .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .int_vref_uv = 2500000, + .has_vref = true, + .reset = ad7091_reset, +}; + +static const struct ad7476_chip_info ad7273_chip_info = { + .channel[0] = AD7940_CHAN(10), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .has_vref = true, +}; + +static const struct ad7476_chip_info ad7274_chip_info = { + .channel[0] = AD7940_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .has_vref = true, +}; + +static const struct ad7476_chip_info ad7276_chip_info = { + .channel[0] = AD7940_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info ad7277_chip_info = { + .channel[0] = AD7940_CHAN(10), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info ad7278_chip_info = { + .channel[0] = AD7940_CHAN(8), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info ad7466_chip_info = { + .channel[0] = AD7476_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info ad7467_chip_info = { + .channel[0] = AD7476_CHAN(10), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info ad7468_chip_info = { + .channel[0] = AD7476_CHAN(8), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info ad7475_chip_info = { + .channel[0] = AD7476_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .has_vref = true, + .has_vdrive = true, +}; + +static const struct ad7476_chip_info ad7495_chip_info = { + .channel[0] = AD7476_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .int_vref_uv = 2500000, + .has_vdrive = true, +}; + +static const struct ad7476_chip_info ad7940_chip_info = { + .channel[0] = AD7940_CHAN(14), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info adc081s_chip_info = { + .channel[0] = ADC081S_CHAN(8), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info adc101s_chip_info = { + .channel[0] = ADC081S_CHAN(10), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info adc121s_chip_info = { + .channel[0] = ADC081S_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info ads7866_chip_info = { + .channel[0] = ADS786X_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info ads7867_chip_info = { + .channel[0] = ADS786X_CHAN(10), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info ads7868_chip_info = { + .channel[0] = ADS786X_CHAN(8), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7476_chip_info ltc2314_14_chip_info = { + .channel[0] = AD7940_CHAN(14), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .has_vref = true, }; static const struct iio_info ad7476_info = { @@ -311,8 +305,10 @@ static int ad7476_probe(struct spi_device *spi) return -ENOMEM; st = iio_priv(indio_dev); - st->chip_info = - &ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODEV; reg = devm_regulator_get(&spi->dev, "vcc"); if (IS_ERR(reg)) @@ -408,41 +404,41 @@ static int ad7476_probe(struct spi_device *spi) } static const struct spi_device_id ad7476_id[] = { - { "ad7091", ID_AD7091 }, - { "ad7091r", ID_AD7091R }, - { "ad7273", ID_AD7273 }, - { "ad7274", ID_AD7274 }, - { "ad7276", ID_AD7276}, - { "ad7277", ID_AD7277 }, - { "ad7278", ID_AD7278 }, - { "ad7466", ID_AD7466 }, - { "ad7467", ID_AD7467 }, - { "ad7468", ID_AD7468 }, - { "ad7475", ID_AD7475 }, - { "ad7476", ID_AD7466 }, - { "ad7476a", ID_AD7466 }, - { "ad7477", ID_AD7467 }, - { "ad7477a", ID_AD7467 }, - { "ad7478", ID_AD7468 }, - { "ad7478a", ID_AD7468 }, - { "ad7495", ID_AD7495 }, - { "ad7910", ID_AD7467 }, - { "ad7920", ID_AD7466 }, - { "ad7940", ID_AD7940 }, - { "adc081s", ID_ADC081S }, - { "adc101s", ID_ADC101S }, - { "adc121s", ID_ADC121S }, - { "ads7866", ID_ADS7866 }, - { "ads7867", ID_ADS7867 }, - { "ads7868", ID_ADS7868 }, + { "ad7091", (kernel_ulong_t)&ad7091_chip_info }, + { "ad7091r", (kernel_ulong_t)&ad7091r_chip_info }, + { "ad7273", (kernel_ulong_t)&ad7273_chip_info }, + { "ad7274", (kernel_ulong_t)&ad7274_chip_info }, + { "ad7276", (kernel_ulong_t)&ad7276_chip_info }, + { "ad7277", (kernel_ulong_t)&ad7277_chip_info }, + { "ad7278", (kernel_ulong_t)&ad7278_chip_info }, + { "ad7466", (kernel_ulong_t)&ad7466_chip_info }, + { "ad7467", (kernel_ulong_t)&ad7467_chip_info }, + { "ad7468", (kernel_ulong_t)&ad7468_chip_info }, + { "ad7475", (kernel_ulong_t)&ad7475_chip_info }, + { "ad7476", (kernel_ulong_t)&ad7466_chip_info }, + { "ad7476a", (kernel_ulong_t)&ad7466_chip_info }, + { "ad7477", (kernel_ulong_t)&ad7467_chip_info }, + { "ad7477a", (kernel_ulong_t)&ad7467_chip_info }, + { "ad7478", (kernel_ulong_t)&ad7468_chip_info }, + { "ad7478a", (kernel_ulong_t)&ad7468_chip_info }, + { "ad7495", (kernel_ulong_t)&ad7495_chip_info }, + { "ad7910", (kernel_ulong_t)&ad7467_chip_info }, + { "ad7920", (kernel_ulong_t)&ad7466_chip_info }, + { "ad7940", (kernel_ulong_t)&ad7940_chip_info }, + { "adc081s", (kernel_ulong_t)&adc081s_chip_info }, + { "adc101s", (kernel_ulong_t)&adc101s_chip_info }, + { "adc121s", (kernel_ulong_t)&adc121s_chip_info }, + { "ads7866", (kernel_ulong_t)&ads7866_chip_info }, + { "ads7867", (kernel_ulong_t)&ads7867_chip_info }, + { "ads7868", (kernel_ulong_t)&ads7868_chip_info }, /* * The ROHM BU79100G is identical to the TI's ADS7866 from the software * point of view. The binding document mandates the ADS7866 to be * marked as a fallback for the BU79100G, but we still need the SPI ID * here to make the module loading work. */ - { "bu79100g", ID_ADS7866 }, - { "ltc2314-14", ID_LTC2314_14 }, + { "bu79100g", (kernel_ulong_t)&ads7866_chip_info }, + { "ltc2314-14", (kernel_ulong_t)<c2314_14_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7476_id); From 72e42b4849c8f0a29ae679eaa4e191cd7698c463 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:50:41 +0300 Subject: [PATCH 0212/2711] iio: adc: ad7476: Simplify scale handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ad7476 driver supports variants with different amount of supply regulators. On some variants there is only VCC, which is used as a reference voltage. Others have separate VREF regulator, and some rely on internal VREF. Some have both internal VREF and option to connect external one. The ad7476 driver reads the regulator voltage only when the user asks to get the scale. This means the driver needs to do some dancing while picking the correct reference regulator (or internal reference), and store it for the later use. According to the discussion [1] variable voltage references are rare, making it hard to justify the added complexity for supporting those. Drop the support for the variable voltage references and simplify things by using the managed regulator get and enable interfaces. Link: https://lore.kernel.org/linux-iio/20250331122247.05c6b09d@jic23-huawei/ #1 Signed-off-by: Matti Vaittinen Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: $URL #1 Link: https://patch.msgid.link/4a497cc5ac0f6506c1c94d10849e0ae1cacf1191.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7476.c | 84 ++++++++++------------------------------ 1 file changed, 21 insertions(+), 63 deletions(-) diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 9869526c1524..f117aafd8fad 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -39,10 +39,10 @@ struct ad7476_chip_info { struct ad7476_state { struct spi_device *spi; const struct ad7476_chip_info *chip_info; - struct regulator *ref_reg; struct gpio_desc *convst_gpio; struct spi_transfer xfer; struct spi_message msg; + int scale_mv; /* * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. @@ -111,7 +111,6 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, { int ret; struct ad7476_state *st = iio_priv(indio_dev); - int scale_uv; switch (m) { case IIO_CHAN_INFO_RAW: @@ -126,14 +125,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - if (st->ref_reg) { - scale_uv = regulator_get_voltage(st->ref_reg); - if (scale_uv < 0) - return scale_uv; - } else { - scale_uv = st->chip_info->int_vref_uv; - } - *val = scale_uv / 1000; + *val = st->scale_mv; *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; } @@ -286,18 +278,10 @@ static const struct iio_info ad7476_info = { .read_raw = &ad7476_read_raw, }; -static void ad7476_reg_disable(void *data) -{ - struct regulator *reg = data; - - regulator_disable(reg); -} - static int ad7476_probe(struct spi_device *spi) { struct ad7476_state *st; struct iio_dev *indio_dev; - struct regulator *reg; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); @@ -310,58 +294,32 @@ static int ad7476_probe(struct spi_device *spi) if (!st->chip_info) return -ENODEV; - reg = devm_regulator_get(&spi->dev, "vcc"); - if (IS_ERR(reg)) - return PTR_ERR(reg); - - ret = regulator_enable(reg); - if (ret) - return ret; - - ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable, reg); - if (ret) - return ret; - - /* Either vcc or vref (below) as appropriate */ - if (!st->chip_info->int_vref_uv) - st->ref_reg = reg; + /* Use VCC for reference voltage if vref / internal vref aren't used */ + if (!st->chip_info->int_vref_uv && !st->chip_info->has_vref) { + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc"); + if (ret < 0) + return ret; + st->scale_mv = ret / 1000; + } else { + ret = devm_regulator_get_enable(&spi->dev, "vcc"); + if (ret < 0) + return ret; + } if (st->chip_info->has_vref) { - - /* If a device has an internal reference vref is optional */ - if (st->chip_info->int_vref_uv) { - reg = devm_regulator_get_optional(&spi->dev, "vref"); - if (IS_ERR(reg) && (PTR_ERR(reg) != -ENODEV)) - return PTR_ERR(reg); - } else { - reg = devm_regulator_get(&spi->dev, "vref"); - if (IS_ERR(reg)) - return PTR_ERR(reg); - } - - if (!IS_ERR(reg)) { - ret = regulator_enable(reg); - if (ret) + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0) { + /* Vref is optional if a device has an internal reference */ + if (!st->chip_info->int_vref_uv || ret != -ENODEV) return ret; - - ret = devm_add_action_or_reset(&spi->dev, - ad7476_reg_disable, - reg); - if (ret) - return ret; - st->ref_reg = reg; } else { - /* - * Can only get here if device supports both internal - * and external reference, but the regulator connected - * to the external reference is not connected. - * Set the reference regulator pointer to NULL to - * indicate this. - */ - st->ref_reg = NULL; + st->scale_mv = ret / 1000; } } + if (!st->scale_mv) + st->scale_mv = st->chip_info->int_vref_uv / 1000; + if (st->chip_info->has_vdrive) { ret = devm_regulator_get_enable(&spi->dev, "vdrive"); if (ret) From 1003d539930177b552e48881c1805fd2bc20066a Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:50:55 +0300 Subject: [PATCH 0213/2711] iio: adc: ad7476: Use mV for internal reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ad7476 supports some ICs with an internal reference voltage. For those ICs the reference voltage has been hard-coded as micro volts, but the value which is later used in code needs to be milli volts. This results the need to divide hard coded voltage by 1000 before using it. Simplify code by changing the hard-coded voltage to millivolts and by dropping the division. Signed-off-by: Matti Vaittinen Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/1c26529fcc039a3ce8b5a336948229ec727ee281.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7476.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index f117aafd8fad..7b6d36999afc 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -27,7 +27,7 @@ struct ad7476_state; struct ad7476_chip_info { - unsigned int int_vref_uv; + unsigned int int_vref_mv; struct iio_chan_spec channel[2]; /* channels used when convst gpio is defined */ struct iio_chan_spec convst_channel[2]; @@ -172,7 +172,7 @@ static const struct ad7476_chip_info ad7091r_chip_info = { .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .convst_channel[0] = AD7091R_CONVST_CHAN(12), .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .int_vref_uv = 2500000, + .int_vref_mv = 2500, .has_vref = true, .reset = ad7091_reset, }; @@ -229,7 +229,7 @@ static const struct ad7476_chip_info ad7475_chip_info = { static const struct ad7476_chip_info ad7495_chip_info = { .channel[0] = AD7476_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .int_vref_uv = 2500000, + .int_vref_mv = 2500, .has_vdrive = true, }; @@ -295,7 +295,7 @@ static int ad7476_probe(struct spi_device *spi) return -ENODEV; /* Use VCC for reference voltage if vref / internal vref aren't used */ - if (!st->chip_info->int_vref_uv && !st->chip_info->has_vref) { + if (!st->chip_info->int_vref_mv && !st->chip_info->has_vref) { ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc"); if (ret < 0) return ret; @@ -310,7 +310,7 @@ static int ad7476_probe(struct spi_device *spi) ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); if (ret < 0) { /* Vref is optional if a device has an internal reference */ - if (!st->chip_info->int_vref_uv || ret != -ENODEV) + if (!st->chip_info->int_vref_mv || ret != -ENODEV) return ret; } else { st->scale_mv = ret / 1000; @@ -318,7 +318,7 @@ static int ad7476_probe(struct spi_device *spi) } if (!st->scale_mv) - st->scale_mv = st->chip_info->int_vref_uv / 1000; + st->scale_mv = st->chip_info->int_vref_mv; if (st->chip_info->has_vdrive) { ret = devm_regulator_get_enable(&spi->dev, "vdrive"); From 5e6847a02e44be0fa8e61d081d64666f6748793e Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:51:06 +0300 Subject: [PATCH 0214/2711] iio: adc: ad7476: Use correct channel for bit info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ad7476 supports ADCs which use separate GPIO for starting the conversion. For such devices, the driver uses different channel information if the GPIO is found. The bit information is still always used from the original (non 'convstart') channels. This has not been causing problems because the bit information for the 'convstart' -channel and the 'normal' -channel is identical. It, however, will cause issues if an IC has different characteristics for an 'convstart' -channel and regular channel. Furthermore, this will cause problems if a device always requires the convstart GPIO and thus only defines the convstart channel. Signed-off-by: Matti Vaittinen Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/70619e39023bc497ef68cc1eff11943ab68cbdf8.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7476.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 7b6d36999afc..fc701267358e 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -121,8 +121,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - *val = (ret >> st->chip_info->channel[0].scan_type.shift) & - GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0); + *val = (ret >> chan->scan_type.shift) & + GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = st->scale_mv; @@ -345,7 +345,7 @@ static int ad7476_probe(struct spi_device *spi) /* Setup default message */ st->xfer.rx_buf = &st->data; - st->xfer.len = st->chip_info->channel[0].scan_type.storagebits / 8; + st->xfer.len = indio_dev->channels[0].scan_type.storagebits / 8; spi_message_init(&st->msg); spi_message_add_tail(&st->xfer, &st->msg); From 0be6a47ec4505df0731ad943ee427b84e4c2a5fb Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:51:17 +0300 Subject: [PATCH 0215/2711] iio: adc: ad7476: use *_cansleep GPIO APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ad7476 driver supports ADCs which require a GPIO pin to be used to start conversion. The GPIO line status seems to be always toggled from a process context, either from the user-initiated "raw-read conversion", or from a threaded IRQ handler. Furthermore, these ICs are connected via SPI bus, which is usually implemented in a way that the access to the device can sleep. The GPIO here is toggled from the same context which is reading the results over SPI. Thus it seems very likely these GPIOs are toggled from a context which can sleep. Swap the gpiod_set_value() to gpiod_set_value_cansleep() accordinlgy. Suggested-by: Nuno Sá Signed-off-by: Matti Vaittinen Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/a2d4b77e9739662797a1609f436b7f9807e1ac67.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7476.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index fc701267358e..1445f0f599d9 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -57,9 +57,9 @@ static void ad7091_convst(struct ad7476_state *st) if (!st->convst_gpio) return; - gpiod_set_value(st->convst_gpio, 0); + gpiod_set_value_cansleep(st->convst_gpio, 0); udelay(1); /* CONVST pulse width: 10 ns min */ - gpiod_set_value(st->convst_gpio, 1); + gpiod_set_value_cansleep(st->convst_gpio, 1); udelay(1); /* Conversion time: 650 ns max */ } From 84977a7af821014f880efd9e8e0edbf0aa17f80f Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:51:28 +0300 Subject: [PATCH 0216/2711] iio: adc: ad7476: Drop convstart chan_spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ad7476 driver defines separate chan_spec structures for operation with and without convstart GPIO. At quick glance this may seem as if the driver did provide more than 1 data-channel to users - one for the regular data, other for the data obtained with the convstart GPIO. The only difference between the 'convstart' and 'non convstart' -channels is presence / absence of the BIT(IIO_CHAN_INFO_RAW) in channel's flags. We can drop the convstart channel spec, and related convstart macro, by allocating a mutable per driver instance channel spec and adding the flag in probe if needed. This will simplify the driver with the cost of added memory consumption. Assuming there aren't systems with very many ADCs and very few resources, this tradeoff seems worth making. Simplify the driver by dropping the 'convstart' channel spec and allocating the channel spec for each driver instance. Signed-off-by: Matti Vaittinen Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/cd7c72e3ee00f279d3381873f54e0c5b75b5ad11.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7476.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 1445f0f599d9..ad9e629f0cbd 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -6,6 +6,7 @@ * Copyright 2010 Analog Devices Inc. */ +#include #include #include #include @@ -29,8 +30,6 @@ struct ad7476_state; struct ad7476_chip_info { unsigned int int_vref_mv; struct iio_chan_spec channel[2]; - /* channels used when convst gpio is defined */ - struct iio_chan_spec convst_channel[2]; void (*reset)(struct ad7476_state *); bool has_vref; bool has_vdrive; @@ -42,6 +41,7 @@ struct ad7476_state { struct gpio_desc *convst_gpio; struct spi_transfer xfer; struct spi_message msg; + struct iio_chan_spec channel[2]; int scale_mv; /* * DMA (thus cache coherency maintenance) may require the @@ -154,24 +154,18 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, #define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \ BIT(IIO_CHAN_INFO_RAW)) #define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0) -#define AD7091R_CONVST_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), \ - BIT(IIO_CHAN_INFO_RAW)) #define ADS786X_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \ BIT(IIO_CHAN_INFO_RAW)) static const struct ad7476_chip_info ad7091_chip_info = { .channel[0] = AD7091R_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .convst_channel[0] = AD7091R_CONVST_CHAN(12), - .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .reset = ad7091_reset, }; static const struct ad7476_chip_info ad7091r_chip_info = { .channel[0] = AD7091R_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .convst_channel[0] = AD7091R_CONVST_CHAN(12), - .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .int_vref_mv = 2500, .has_vref = true, .reset = ad7091_reset, @@ -282,6 +276,7 @@ static int ad7476_probe(struct spi_device *spi) { struct ad7476_state *st; struct iio_dev *indio_dev; + unsigned int i; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); @@ -332,16 +327,28 @@ static int ad7476_probe(struct spi_device *spi) if (IS_ERR(st->convst_gpio)) return PTR_ERR(st->convst_gpio); + /* + * This will never happen. Unless someone changes the channel specs + * in this driver. And if someone does, without changing the loop + * below, then we'd better immediately produce a big fat error, before + * the change proceeds from that developer's table. + */ + static_assert(ARRAY_SIZE(st->channel) == ARRAY_SIZE(st->chip_info->channel)); + for (i = 0; i < ARRAY_SIZE(st->channel); i++) { + st->channel[i] = st->chip_info->channel[i]; + if (st->convst_gpio) + __set_bit(IIO_CHAN_INFO_RAW, + &st->channel[i].info_mask_separate); + } + st->spi = spi; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = st->chip_info->channel; - indio_dev->num_channels = 2; + indio_dev->channels = st->channel; + indio_dev->num_channels = ARRAY_SIZE(st->channel); indio_dev->info = &ad7476_info; - if (st->convst_gpio) - indio_dev->channels = st->chip_info->convst_channel; /* Setup default message */ st->xfer.rx_buf = &st->data; From 27ec39c7090a8ad954426acf7121b4b5f2ec0043 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:51:39 +0300 Subject: [PATCH 0217/2711] iio: adc: ad7476: Conditionally call convstart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ad7476 supports two IC variants which may have a 'convstart' -GPIO for starting the conversion. Currently the driver calls a function which tries to access the GPIO for all of the IC variants, whether they support 'convstart' or not. This is not an error because this function returns early if GPIO information is not populated. We can do a tad better by calling this function only for the ICs which have the 'convstart' by providing a function pointer to the convstart function from the chip_info structure, and calling this function only for the ICs which have the function pointer set. This does also allow to support ICs which require different convstart handling than the currently supported ICs. Call convstart function only on the ICs which can support it and allow IC-specific convstart functions for the ICs which require different handling. Signed-off-by: Matti Vaittinen Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/9760cde888fac7335c17d7ab63d5fb2e7c59ac51.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7476.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index ad9e629f0cbd..6cb2cbeafbd3 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -31,6 +31,7 @@ struct ad7476_chip_info { unsigned int int_vref_mv; struct iio_chan_spec channel[2]; void (*reset)(struct ad7476_state *); + void (*conversion_pre_op)(struct ad7476_state *st); bool has_vref; bool has_vdrive; }; @@ -70,7 +71,8 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) struct ad7476_state *st = iio_priv(indio_dev); int b_sent; - ad7091_convst(st); + if (st->chip_info->conversion_pre_op) + st->chip_info->conversion_pre_op(st); b_sent = spi_sync(st->spi, &st->msg); if (b_sent < 0) @@ -94,7 +96,8 @@ static int ad7476_scan_direct(struct ad7476_state *st) { int ret; - ad7091_convst(st); + if (st->chip_info->conversion_pre_op) + st->chip_info->conversion_pre_op(st); ret = spi_sync(st->spi, &st->msg); if (ret) @@ -160,12 +163,14 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, static const struct ad7476_chip_info ad7091_chip_info = { .channel[0] = AD7091R_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .conversion_pre_op = ad7091_convst, .reset = ad7091_reset, }; static const struct ad7476_chip_info ad7091r_chip_info = { .channel[0] = AD7091R_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .conversion_pre_op = ad7091_convst, .int_vref_mv = 2500, .has_vref = true, .reset = ad7091_reset, From 260bb98ce3df870ef3d73361f6918463bc88a5b6 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:51:50 +0300 Subject: [PATCH 0218/2711] dt-bindings: iio: adc: ad7476: Drop redundant prop: true The ad7476 supports a few variants with different power-supplies and control GPIOs. The binding first unconditionally introduces all the properties, and later sets them 'true' or 'false' based on the combatible. The 'true' seems to be implied by the initial property introduction so the 'true' -branches in later conditional handling (based on the compatible) can be omitted. Drop the redundant true -branches. Signed-off-by: Matti Vaittinen Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/bee66444bf628ba9a34a02738a1842e2abc14290.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7476.yaml | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml index d0cb32f136e5..db2a9662bd94 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml @@ -106,19 +106,17 @@ allOf: - vcc-supply # Devices with a vref - if: - properties: - compatible: - contains: - enum: - - adi,ad7091r - - adi,ad7273 - - adi,ad7274 - - adi,ad7475 - - lltc,ltc2314-14 + not: + properties: + compatible: + contains: + enum: + - adi,ad7091r + - adi,ad7273 + - adi,ad7274 + - adi,ad7475 + - lltc,ltc2314-14 then: - properties: - vref-supply: true - else: properties: vref-supply: false # Devices with a vref where it is not optional @@ -135,29 +133,25 @@ allOf: required: - vref-supply - if: - properties: - compatible: - contains: - enum: - - adi,ad7475 - - adi,ad7495 + not: + properties: + compatible: + contains: + enum: + - adi,ad7475 + - adi,ad7495 then: - properties: - vdrive-supply: true - else: properties: vdrive-supply: false - if: - properties: - compatible: - contains: - enum: - - adi,ad7091 - - adi,ad7091r + not: + properties: + compatible: + contains: + enum: + - adi,ad7091 + - adi,ad7091r then: - properties: - adi,conversion-start-gpios: true - else: properties: adi,conversion-start-gpios: false From 261b90763fc4d51637abd44ae248a6183fc2de4d Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:52:04 +0300 Subject: [PATCH 0219/2711] dt-bindings: iio: adc: ad7476: Add ROHM bd79105 The ROHM BD79105 is a simple, 16-bit, 1-channel ADC with a 'CONVSTART' pin used to start the ADC conversion. Other than the 'CONVSTART', there are 3 supply pins (one used as a reference), analog inputs, ground and communication pins. It's worth noting that the pin somewhat confusingly labeled as 'DIN', is a pin which should be used as a chip-select. The IC does not have any writable registers. The device is designed so that the output pin can, in addition to outputting the data, be used as a 'data-ready'-IRQ. There are cases where the IRQ can't be used (because it is delivered via SPI data-line). Hence, some systems may use a GPIO for polling the data readiness. Add a compatible for the bd79105 and add the data-ready GPIO to the binding. Signed-off-by: Matti Vaittinen Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/3f70f68665225be3091f8a0412e74037b6a2a88e.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7476.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml index db2a9662bd94..55880191c511 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml @@ -41,6 +41,7 @@ properties: - adi,ad7910 - adi,ad7920 - adi,ad7940 + - rohm,bd79105 - ti,adc081s - ti,adc101s - ti,adc121s @@ -55,6 +56,11 @@ properties: reg: maxItems: 1 + interrupts: + description: + The data-ready interrupt. Provided via DOUT pin. + maxItems: 1 + vcc-supply: description: Main powersupply voltage for the chips, sometimes referred to as VDD on @@ -75,6 +81,10 @@ properties: description: A GPIO used to trigger the start of a conversion maxItems: 1 + rdy-gpios: + description: A GPIO for detecting the data-ready. + maxItems: 1 + required: - compatible - reg @@ -82,6 +92,20 @@ required: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# +# Devices with an IRQ + - if: + properties: + compatible: + contains: + enum: + - rohm,bd79105 + then: + properties: + interrupts: true + else: + properties: + interrupts: false + # Devices where reference is vcc - if: properties: @@ -116,6 +140,7 @@ allOf: - adi,ad7274 - adi,ad7475 - lltc,ltc2314-14 + - rohm,bd79105 then: properties: vref-supply: false @@ -129,6 +154,7 @@ allOf: - adi,ad7274 - adi,ad7475 - lltc,ltc2314-14 + - rohm,bd79105 then: required: - vref-supply @@ -140,9 +166,23 @@ allOf: enum: - adi,ad7475 - adi,ad7495 + - rohm,bd79105 then: properties: vdrive-supply: false + + # Devices which support polling the data-ready via GPIO + - if: + not: + properties: + compatible: + contains: + enum: + - rohm,bd79105 + then: + properties: + rdy-gpios: false + - if: not: properties: @@ -151,10 +191,22 @@ allOf: enum: - adi,ad7091 - adi,ad7091r + - rohm,bd79105 then: properties: adi,conversion-start-gpios: false + # Devices with a convstart GPIO where it is not optional + - if: + properties: + compatible: + contains: + enum: + - rohm,bd79105 + then: + required: + - adi,conversion-start-gpios + unevaluatedProperties: false examples: From 6c27bf9bbfb72ccdd4821551ae8a28fe47c4e878 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:52:22 +0300 Subject: [PATCH 0220/2711] iio: adc: ad7476: Support ROHM BD79105 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ROHM BD79105 is a simple 16-bit ADC accessible via SPI*. The BD79105 has a CONVSTART pin, which must be set high to start the ADC conversion. Unlike with the ad7091 and ad7091r which also have a CONVSTART pin, the BD79105 requires that the pin must remain high also for the duration of the SPI access. (*) Couple of words about the SPI. The BD79105 has pins named as CONVSTART, SCLK, DIN and DOUT. For the curious reader, DIN is not SPI ISO. DIN is a signal which can be used as a chip-select. When DIN is pulled low, the ADC will output the completed measurement via DOUT as SCLK is clocked. According to the data-sheet, the DIN can also be used for daisy-chaining multiple ADCs. Furthermore, DOUT can be used also for a 'data-ready' -IRQ. These modes aren't supported by this driver. Support reading ADC scale and data from the BD79105 using SPI, when DIN is used as a chip-select. Signed-off-by: Matti Vaittinen Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/6ee06d551256db9213ccbe72f44cfe9452717716.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7476.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 6cb2cbeafbd3..1bec6657394c 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -32,8 +32,10 @@ struct ad7476_chip_info { struct iio_chan_spec channel[2]; void (*reset)(struct ad7476_state *); void (*conversion_pre_op)(struct ad7476_state *st); + void (*conversion_post_op)(struct ad7476_state *st); bool has_vref; bool has_vdrive; + bool convstart_required; }; struct ad7476_state { @@ -64,6 +66,18 @@ static void ad7091_convst(struct ad7476_state *st) udelay(1); /* Conversion time: 650 ns max */ } +static void bd79105_convst_disable(struct ad7476_state *st) +{ + gpiod_set_value_cansleep(st->convst_gpio, 0); +} + +static void bd79105_convst_enable(struct ad7476_state *st) +{ + gpiod_set_value_cansleep(st->convst_gpio, 1); + /* Worst case, 2790 ns required for conversion */ + ndelay(2790); +} + static irqreturn_t ad7476_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -81,6 +95,8 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) iio_push_to_buffers_with_ts(indio_dev, st->data, sizeof(st->data), iio_get_time_ns(indio_dev)); done: + if (st->chip_info->conversion_post_op) + st->chip_info->conversion_post_op(st); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -103,6 +119,9 @@ static int ad7476_scan_direct(struct ad7476_state *st) if (ret) return ret; + if (st->chip_info->conversion_post_op) + st->chip_info->conversion_post_op(st); + return be16_to_cpup((__be16 *)st->data); } @@ -273,6 +292,22 @@ static const struct ad7476_chip_info ltc2314_14_chip_info = { .has_vref = true, }; +static const struct ad7476_chip_info bd79105_chip_info = { + .channel[0] = AD7091R_CHAN(16), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + /* + * The BD79105 starts ADC data conversion when the CONVSTART line is + * set HIGH. The CONVSTART must be kept HIGH until the data has been + * read from the ADC. + */ + .conversion_pre_op = bd79105_convst_enable, + .conversion_post_op = bd79105_convst_disable, + /* BD79105 won't do conversion without convstart */ + .convstart_required = true, + .has_vref = true, + .has_vdrive = true, +}; + static const struct iio_info ad7476_info = { .read_raw = &ad7476_read_raw, }; @@ -332,6 +367,9 @@ static int ad7476_probe(struct spi_device *spi) if (IS_ERR(st->convst_gpio)) return PTR_ERR(st->convst_gpio); + if (st->chip_info->convstart_required && !st->convst_gpio) + return dev_err_probe(&spi->dev, -EINVAL, "No convstart GPIO\n"); + /* * This will never happen. Unless someone changes the channel specs * in this driver. And if someone does, without changing the loop @@ -401,6 +439,7 @@ static const struct spi_device_id ad7476_id[] = { { "ads7866", (kernel_ulong_t)&ads7866_chip_info }, { "ads7867", (kernel_ulong_t)&ads7867_chip_info }, { "ads7868", (kernel_ulong_t)&ads7868_chip_info }, + { "bd79105", (kernel_ulong_t)&bd79105_chip_info }, /* * The ROHM BU79100G is identical to the TI's ADS7866 from the software * point of view. The binding document mandates the ADS7866 to be From 9125457108ab3ed21ed0a6dc61bbd9cfeaac1c42 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 11 Aug 2025 11:52:34 +0300 Subject: [PATCH 0221/2711] MAINTAINERS: A driver for simple 1-channel SPI ADCs Add undersigned as a maintainer for the ad7476.c which supports a few simple 1-channel ADC connected to SPI. Signed-off-by: Matti Vaittinen Link: https://patch.msgid.link/b952b543547523951ca87dcac86ba7a00a1c7673.1754901948.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index df0ea951b8c5..76cba707a2c9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -457,6 +457,11 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml F: Documentation/iio/ad7380.rst F: drivers/iio/adc/ad7380.c +AD7476 ADC DRIVER FOR VARIOUS SIMPLE 1-CHANNEL SPI ADCs +M: Matti Vaittinen +S: Maintained +F: drivers/iio/adc/ad7476.c + AD7877 TOUCHSCREEN DRIVER M: Michael Hennerich S: Supported From 2c748d2783a0ce7259901dee17b83a273fc54d4a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:51 +0200 Subject: [PATCH 0222/2711] iio: remove unneeded 'fast_io' parameter in regmap_config When using MMIO with regmap, fast_io is implied. No need to set it again. Signed-off-by: Wolfram Sang Link: https://patch.msgid.link/20250813161517.4746-6-wsa+renesas@sang-engineering.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/sun4i-gpadc-iio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 6b8d6bee1873..e4bc2e199a07 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -154,7 +154,6 @@ static const struct regmap_config sun4i_gpadc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, }; static int sun4i_prepare_for_irq(struct iio_dev *indio_dev, int channel, From a57d6b855041ecb9c45b5b973a18d1fff611b95f Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Wed, 13 Aug 2025 17:58:35 -0500 Subject: [PATCH 0223/2711] iio: health: afe4403: Do not store dev pointer in device struct The device *dev is only used in probe(), so no need to store it in the device local data struct. In all the places in probe() we did use that, just use a new local variable for the same. Signed-off-by: Andrew Davis Link: https://patch.msgid.link/20250813225840.576305-1-afd@ti.com Signed-off-by: Jonathan Cameron --- drivers/iio/health/afe4403.c | 46 +++++++++++++++++------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 30d3f984b032..99bf1bcbea40 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -58,7 +58,6 @@ static const struct reg_field afe4403_reg_fields[] = { /** * struct afe4403_data - AFE4403 device instance data - * @dev: Device structure * @spi: SPI device handle * @regmap: Register map of the device * @fields: Register fields of the device @@ -68,7 +67,6 @@ static const struct reg_field afe4403_reg_fields[] = { * @buffer: Used to construct data layout to push into IIO buffer. */ struct afe4403_data { - struct device *dev; struct spi_device *spi; struct regmap *regmap; struct regmap_field *fields[F_MAX_FIELDS]; @@ -460,63 +458,63 @@ static DEFINE_SIMPLE_DEV_PM_OPS(afe4403_pm_ops, afe4403_suspend, static int afe4403_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct iio_dev *indio_dev; struct afe4403_data *afe; int i, ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*afe)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*afe)); if (!indio_dev) return -ENOMEM; afe = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); - afe->dev = &spi->dev; afe->spi = spi; afe->irq = spi->irq; afe->regmap = devm_regmap_init_spi(spi, &afe4403_regmap_config); if (IS_ERR(afe->regmap)) { - dev_err(afe->dev, "Unable to allocate register map\n"); + dev_err(dev, "Unable to allocate register map\n"); return PTR_ERR(afe->regmap); } for (i = 0; i < F_MAX_FIELDS; i++) { - afe->fields[i] = devm_regmap_field_alloc(afe->dev, afe->regmap, + afe->fields[i] = devm_regmap_field_alloc(dev, afe->regmap, afe4403_reg_fields[i]); if (IS_ERR(afe->fields[i])) { - dev_err(afe->dev, "Unable to allocate regmap fields\n"); + dev_err(dev, "Unable to allocate regmap fields\n"); return PTR_ERR(afe->fields[i]); } } - afe->regulator = devm_regulator_get(afe->dev, "tx_sup"); + afe->regulator = devm_regulator_get(dev, "tx_sup"); if (IS_ERR(afe->regulator)) - return dev_err_probe(afe->dev, PTR_ERR(afe->regulator), + return dev_err_probe(dev, PTR_ERR(afe->regulator), "Unable to get regulator\n"); ret = regulator_enable(afe->regulator); if (ret) { - dev_err(afe->dev, "Unable to enable regulator\n"); + dev_err(dev, "Unable to enable regulator\n"); return ret; } - ret = devm_add_action_or_reset(afe->dev, afe4403_regulator_disable, afe->regulator); + ret = devm_add_action_or_reset(dev, afe4403_regulator_disable, afe->regulator); if (ret) { - dev_err(afe->dev, "Unable to add regulator disable action\n"); + dev_err(dev, "Unable to add regulator disable action\n"); return ret; } ret = regmap_write(afe->regmap, AFE440X_CONTROL0, AFE440X_CONTROL0_SW_RESET); if (ret) { - dev_err(afe->dev, "Unable to reset device\n"); + dev_err(dev, "Unable to reset device\n"); return ret; } ret = regmap_multi_reg_write(afe->regmap, afe4403_reg_sequences, ARRAY_SIZE(afe4403_reg_sequences)); if (ret) { - dev_err(afe->dev, "Unable to set register defaults\n"); + dev_err(dev, "Unable to set register defaults\n"); return ret; } @@ -527,45 +525,45 @@ static int afe4403_probe(struct spi_device *spi) indio_dev->info = &afe4403_iio_info; if (afe->irq > 0) { - afe->trig = devm_iio_trigger_alloc(afe->dev, + afe->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); if (!afe->trig) { - dev_err(afe->dev, "Unable to allocate IIO trigger\n"); + dev_err(dev, "Unable to allocate IIO trigger\n"); return -ENOMEM; } iio_trigger_set_drvdata(afe->trig, indio_dev); - ret = devm_iio_trigger_register(afe->dev, afe->trig); + ret = devm_iio_trigger_register(dev, afe->trig); if (ret) { - dev_err(afe->dev, "Unable to register IIO trigger\n"); + dev_err(dev, "Unable to register IIO trigger\n"); return ret; } - ret = devm_request_threaded_irq(afe->dev, afe->irq, + ret = devm_request_threaded_irq(dev, afe->irq, iio_trigger_generic_data_rdy_poll, NULL, IRQF_ONESHOT, AFE4403_DRIVER_NAME, afe->trig); if (ret) { - dev_err(afe->dev, "Unable to request IRQ\n"); + dev_err(dev, "Unable to request IRQ\n"); return ret; } } - ret = devm_iio_triggered_buffer_setup(afe->dev, indio_dev, + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, &iio_pollfunc_store_time, afe4403_trigger_handler, NULL); if (ret) { - dev_err(afe->dev, "Unable to setup buffer\n"); + dev_err(dev, "Unable to setup buffer\n"); return ret; } - ret = devm_iio_device_register(afe->dev, indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret) { - dev_err(afe->dev, "Unable to register IIO device\n"); + dev_err(dev, "Unable to register IIO device\n"); return ret; } From 7c1ece9b7063987582531501e935a5619788e38a Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Wed, 13 Aug 2025 17:58:38 -0500 Subject: [PATCH 0224/2711] iio: health: afe4404: Do not store dev pointer in device struct The device *dev is only used in probe(), so no need to store it in the device local data struct. In all the places in probe() we did use that, just use a new local variable for the same. Signed-off-by: Andrew Davis Link: https://patch.msgid.link/20250813225840.576305-4-afd@ti.com Signed-off-by: Jonathan Cameron --- drivers/iio/health/afe4404.c | 46 +++++++++++++++++------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index b2727effecaa..29e030943f59 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -77,7 +77,6 @@ static const struct reg_field afe4404_reg_fields[] = { /** * struct afe4404_data - AFE4404 device instance data - * @dev: Device structure * @regmap: Register map of the device * @fields: Register fields of the device * @regulator: Pointer to the regulator for the IC @@ -86,7 +85,6 @@ static const struct reg_field afe4404_reg_fields[] = { * @buffer: Used to construct a scan to push to the iio buffer. */ struct afe4404_data { - struct device *dev; struct regmap *regmap; struct regmap_field *fields[F_MAX_FIELDS]; struct regulator *regulator; @@ -468,62 +466,62 @@ static DEFINE_SIMPLE_DEV_PM_OPS(afe4404_pm_ops, afe4404_suspend, static int afe4404_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct iio_dev *indio_dev; struct afe4404_data *afe; int i, ret; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*afe)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*afe)); if (!indio_dev) return -ENOMEM; afe = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); - afe->dev = &client->dev; afe->irq = client->irq; afe->regmap = devm_regmap_init_i2c(client, &afe4404_regmap_config); if (IS_ERR(afe->regmap)) { - dev_err(afe->dev, "Unable to allocate register map\n"); + dev_err(dev, "Unable to allocate register map\n"); return PTR_ERR(afe->regmap); } for (i = 0; i < F_MAX_FIELDS; i++) { - afe->fields[i] = devm_regmap_field_alloc(afe->dev, afe->regmap, + afe->fields[i] = devm_regmap_field_alloc(dev, afe->regmap, afe4404_reg_fields[i]); if (IS_ERR(afe->fields[i])) { - dev_err(afe->dev, "Unable to allocate regmap fields\n"); + dev_err(dev, "Unable to allocate regmap fields\n"); return PTR_ERR(afe->fields[i]); } } - afe->regulator = devm_regulator_get(afe->dev, "tx_sup"); + afe->regulator = devm_regulator_get(dev, "tx_sup"); if (IS_ERR(afe->regulator)) - return dev_err_probe(afe->dev, PTR_ERR(afe->regulator), + return dev_err_probe(dev, PTR_ERR(afe->regulator), "Unable to get regulator\n"); ret = regulator_enable(afe->regulator); if (ret) { - dev_err(afe->dev, "Unable to enable regulator\n"); + dev_err(dev, "Unable to enable regulator\n"); return ret; } - ret = devm_add_action_or_reset(afe->dev, afe4404_regulator_disable, afe->regulator); + ret = devm_add_action_or_reset(dev, afe4404_regulator_disable, afe->regulator); if (ret) { - dev_err(afe->dev, "Unable to enable regulator\n"); + dev_err(dev, "Unable to enable regulator\n"); return ret; } ret = regmap_write(afe->regmap, AFE440X_CONTROL0, AFE440X_CONTROL0_SW_RESET); if (ret) { - dev_err(afe->dev, "Unable to reset device\n"); + dev_err(dev, "Unable to reset device\n"); return ret; } ret = regmap_multi_reg_write(afe->regmap, afe4404_reg_sequences, ARRAY_SIZE(afe4404_reg_sequences)); if (ret) { - dev_err(afe->dev, "Unable to set register defaults\n"); + dev_err(dev, "Unable to set register defaults\n"); return ret; } @@ -534,45 +532,45 @@ static int afe4404_probe(struct i2c_client *client) indio_dev->info = &afe4404_iio_info; if (afe->irq > 0) { - afe->trig = devm_iio_trigger_alloc(afe->dev, + afe->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); if (!afe->trig) { - dev_err(afe->dev, "Unable to allocate IIO trigger\n"); + dev_err(dev, "Unable to allocate IIO trigger\n"); return -ENOMEM; } iio_trigger_set_drvdata(afe->trig, indio_dev); - ret = devm_iio_trigger_register(afe->dev, afe->trig); + ret = devm_iio_trigger_register(dev, afe->trig); if (ret) { - dev_err(afe->dev, "Unable to register IIO trigger\n"); + dev_err(dev, "Unable to register IIO trigger\n"); return ret; } - ret = devm_request_threaded_irq(afe->dev, afe->irq, + ret = devm_request_threaded_irq(dev, afe->irq, iio_trigger_generic_data_rdy_poll, NULL, IRQF_ONESHOT, AFE4404_DRIVER_NAME, afe->trig); if (ret) { - dev_err(afe->dev, "Unable to request IRQ\n"); + dev_err(dev, "Unable to request IRQ\n"); return ret; } } - ret = devm_iio_triggered_buffer_setup(afe->dev, indio_dev, + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, &iio_pollfunc_store_time, afe4404_trigger_handler, NULL); if (ret) { - dev_err(afe->dev, "Unable to setup buffer\n"); + dev_err(dev, "Unable to setup buffer\n"); return ret; } - ret = devm_iio_device_register(afe->dev, indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret) { - dev_err(afe->dev, "Unable to register IIO device\n"); + dev_err(dev, "Unable to register IIO device\n"); return ret; } From 946bfea3657a3b569ce1e59b29014ef5eb8c6c30 Mon Sep 17 00:00:00 2001 From: Akshay Jindal Date: Thu, 14 Aug 2025 09:15:43 +0530 Subject: [PATCH 0225/2711] iio: light: ltr390: Add device powerdown functionality via devm api Use devm_add_action_or_reset() to do cleanup when the device is removed. Signed-off-by: Akshay Jindal Link: https://patch.msgid.link/20250814034544.93331-1-akshayaj.lkd@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/ltr390.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c index 7733830dca67..2e1cf62e8201 100644 --- a/drivers/iio/light/ltr390.c +++ b/drivers/iio/light/ltr390.c @@ -680,6 +680,22 @@ static irqreturn_t ltr390_interrupt_handler(int irq, void *private) return IRQ_HANDLED; } +static void ltr390_powerdown(void *priv) +{ + struct ltr390_data *data = priv; + + guard(mutex)(&data->lock); + + /* Ensure that power off and interrupts are disabled */ + if (regmap_clear_bits(data->regmap, LTR390_INT_CFG, + LTR390_LS_INT_EN) < 0) + dev_err(&data->client->dev, "failed to disable interrupts\n"); + + if (regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, + LTR390_SENSOR_ENABLE) < 0) + dev_err(&data->client->dev, "failed to disable sensor\n"); +} + static int ltr390_probe(struct i2c_client *client) { struct ltr390_data *data; @@ -693,7 +709,6 @@ static int ltr390_probe(struct i2c_client *client) return -ENOMEM; data = iio_priv(indio_dev); - data->regmap = devm_regmap_init_i2c(client, <r390_regmap_config); if (IS_ERR(data->regmap)) return dev_err_probe(dev, PTR_ERR(data->regmap), @@ -733,6 +748,10 @@ static int ltr390_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "failed to enable the sensor\n"); + ret = devm_add_action_or_reset(dev, ltr390_powerdown, data); + if (ret) + return dev_err_probe(dev, ret, "failed to add action or reset\n"); + if (client->irq) { ret = devm_request_threaded_irq(dev, client->irq, NULL, ltr390_interrupt_handler, From ea9b042129275b084d13ef2f571ffd439ed47533 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Wed, 13 Aug 2025 15:55:56 +0800 Subject: [PATCH 0226/2711] iio: adc: ti-tsc2046: use us_to_ktime() where appropriate Given scan_interval_us and time_per_scan_us are both in usecs, it makes more sense to use us_to_ktime() helper rather than converting to nanosecs as needed for ns_to_ktime(). Signed-off-by: Xichao Zhao Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250813075556.466872-1-zhao.xichao@vivo.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-tsc2046.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c index 74471f08662e..8eb717b11cff 100644 --- a/drivers/iio/adc/ti-tsc2046.c +++ b/drivers/iio/adc/ti-tsc2046.c @@ -535,8 +535,7 @@ static enum hrtimer_restart tsc2046_adc_timer(struct hrtimer *hrtimer) if (priv->poll_cnt < TI_TSC2046_POLL_CNT) { priv->poll_cnt++; hrtimer_start(&priv->trig_timer, - ns_to_ktime(priv->scan_interval_us * - NSEC_PER_USEC), + us_to_ktime(priv->scan_interval_us), HRTIMER_MODE_REL_SOFT); if (priv->poll_cnt >= TI_TSC2046_MIN_POLL_CNT) { @@ -605,8 +604,7 @@ static void tsc2046_adc_reenable_trigger(struct iio_trigger *trig) * many samples. Reduce the sample rate for default (touchscreen) use * case. */ - tim = ns_to_ktime((priv->scan_interval_us - priv->time_per_scan_us) * - NSEC_PER_USEC); + tim = us_to_ktime(priv->scan_interval_us - priv->time_per_scan_us); hrtimer_start(&priv->trig_timer, tim, HRTIMER_MODE_REL_SOFT); } From 26f0675fba4360516ee717ecc5ea099fe6819f1b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 12 Aug 2025 15:24:46 +0200 Subject: [PATCH 0227/2711] dt-bindings: iio: Replace bouncing Analog emails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Emails to stefan.popa@analog.com and alexandru.tachici@analog.com bounce permanently: Remote Server returned '550 5.1.10 RESOLVER.ADR.RecipientNotFound; Recipient not found by SMTP address lookup' so replace them with Marcelo Schmitt and Nuno Sá (listed alphabetically by first name) from Analog where appropriate. Acked-by: Rob Herring (Arm) Signed-off-by: Krzysztof Kozlowski Acked-by: Nuno Sá Acked-by: Marcelo Schmitt Link: https://patch.msgid.link/20250812132445.75398-2-krzysztof.kozlowski@linaro.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml | 3 ++- Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml | 3 ++- Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml | 3 ++- Documentation/devicetree/bindings/iio/adc/lltc,ltc2496.yaml | 1 - Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml | 3 ++- Documentation/devicetree/bindings/iio/frequency/adf4371.yaml | 3 ++- Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml | 3 ++- 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml index 3dc973b98f81..a92e153705f3 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: ADIS16240 Programmable Impact Sensor and Recorder driver maintainers: - - Alexandru Tachici + - Marcelo Schmitt + - Nuno Sá description: | ADIS16240 Programmable Impact Sensor and Recorder driver that supports diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml index 88aa67bf2280..0ba0df46c3a9 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Analog Devices ADXL372 3-Axis, +/-(200g) Digital Accelerometer maintainers: - - Stefan Popa + - Marcelo Schmitt + - Nuno Sá description: | Analog Devices ADXL372 3-Axis, +/-(200g) Digital Accelerometer that supports diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml index 7146a654ae38..4dd5395730c1 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml @@ -8,7 +8,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Analog Devices AD7124 ADC device driver maintainers: - - Stefan Popa + - Marcelo Schmitt + - Nuno Sá description: | Bindings for the Analog Devices AD7124 ADC device. Datasheet can be diff --git a/Documentation/devicetree/bindings/iio/adc/lltc,ltc2496.yaml b/Documentation/devicetree/bindings/iio/adc/lltc,ltc2496.yaml index 5207c919abe0..eac48166fe72 100644 --- a/Documentation/devicetree/bindings/iio/adc/lltc,ltc2496.yaml +++ b/Documentation/devicetree/bindings/iio/adc/lltc,ltc2496.yaml @@ -9,7 +9,6 @@ title: Linear Technology / Analog Devices LTC2496 ADC maintainers: - Lars-Peter Clausen - Michael Hennerich - - Stefan Popa properties: compatible: diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml index 82b0eed6a7b7..091cc93f1f90 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml @@ -8,7 +8,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Analog Devices AD5770R DAC device driver maintainers: - - Alexandru Tachici + - Marcelo Schmitt + - Nuno Sá description: | Bindings for the Analog Devices AD5770R current DAC device. Datasheet can be diff --git a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml index 53d607441612..2e1ff77fd1de 100644 --- a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml +++ b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Analog Devices ADF4371/ADF4372 Wideband Synthesizers maintainers: - - Popa Stefan + - Marcelo Schmitt + - Nuno Sá description: | Analog Devices ADF4371/ADF4372 SPI Wideband Synthesizers diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml index 7a1a74fec281..43ecf46e9c20 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Analog Devices ADIS16480 and similar IMUs maintainers: - - Alexandru Tachici + - Marcelo Schmitt + - Nuno Sá properties: compatible: From e819000c692ab8c27b8cbbb386180e2f1d2e23b0 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Tue, 12 Aug 2025 07:12:58 -0400 Subject: [PATCH 0228/2711] iio: iio_format_list() should set stride=1 for IIO_VAL_CHAR iio_format_list() sets a stride across the val array of 1 for INT type, and 2 for all others. Add IIO_VAL_CHAR so it also gets a stride of 1 assuming val is an array of integers with char type values. No drivers currently use this, but I found this issue adding an avail callback for IIO_INFO_THERMOCOUPLE_TYPE for a driver I'm working on. Signed-off-by: Ben Collins Reviewed-by: David Lechner Link: https://patch.msgid.link/vidvwybkm3vwmtopihyaj6tlvswwa5ixmgptfzpk5ujl2ixjjb@olz6275ftabs Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 159d6c5ca3ce..eb6a54f8115d 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -790,6 +790,7 @@ static ssize_t iio_format_list(char *buf, const int *vals, int type, int length, switch (type) { case IIO_VAL_INT: + case IIO_VAL_CHAR: stride = 1; break; default: From 6830d3ed4d641691fc93611040f363b821df2fec Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 12 Aug 2025 16:04:22 +0800 Subject: [PATCH 0229/2711] iio: adc: imx93_adc: keep one style of the hex values Use capital letters consistently for hex values. Signed-off-by: Haibo Chen Reviewed-by: Frank Li Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250812-adc-v2-1-0260833f13b8@nxp.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/imx93_adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index 7feaafd2316f..8471737ac04a 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -32,11 +32,11 @@ #define IMX93_ADC_PCDR0 0x100 #define IMX93_ADC_PCDR1 0x104 #define IMX93_ADC_PCDR2 0x108 -#define IMX93_ADC_PCDR3 0x10c +#define IMX93_ADC_PCDR3 0x10C #define IMX93_ADC_PCDR4 0x110 #define IMX93_ADC_PCDR5 0x114 #define IMX93_ADC_PCDR6 0x118 -#define IMX93_ADC_PCDR7 0x11c +#define IMX93_ADC_PCDR7 0x11C #define IMX93_ADC_CALSTAT 0x39C /* ADC bit shift */ From 12c9b09e981ab14ebec8e4eefa946cbd26dd306b Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 12 Aug 2025 16:04:23 +0800 Subject: [PATCH 0230/2711] iio: adc: imx93_adc: load calibrated values even calibration failed ADC calibration might fail because of the noise on reference voltage. To avoid calibration fail, need to meet the following requirement: ADC reference voltage Noise < 1.8V * 1/2^ENOB For the case which the ADC reference voltage on board do not meet the requirement, still load the calibrated values, so ADC can also work but maybe not that accurate. Signed-off-by: Haibo Chen Reviewed-by: Frank Li Reviewed-by: Primoz Fiser Link: https://patch.msgid.link/20250812-adc-v2-2-0260833f13b8@nxp.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/imx93_adc.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index 8471737ac04a..17b0a2548b0a 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -38,6 +38,7 @@ #define IMX93_ADC_PCDR6 0x118 #define IMX93_ADC_PCDR7 0x11C #define IMX93_ADC_CALSTAT 0x39C +#define IMX93_ADC_CALCFG0 0x3A0 /* ADC bit shift */ #define IMX93_ADC_MCR_MODE_MASK BIT(29) @@ -58,6 +59,8 @@ #define IMX93_ADC_IMR_ECH_MASK BIT(0) #define IMX93_ADC_PCDR_CDATA_MASK GENMASK(11, 0) +#define IMX93_ADC_CALCFG0_LDFAIL_MASK BIT(4) + /* ADC status */ #define IMX93_ADC_MSR_ADCSTATUS_IDLE 0 #define IMX93_ADC_MSR_ADCSTATUS_POWER_DOWN 1 @@ -145,7 +148,7 @@ static void imx93_adc_config_ad_clk(struct imx93_adc *adc) static int imx93_adc_calibration(struct imx93_adc *adc) { - u32 mcr, msr; + u32 mcr, msr, calcfg; int ret; /* make sure ADC in power down mode */ @@ -158,6 +161,11 @@ static int imx93_adc_calibration(struct imx93_adc *adc) imx93_adc_power_up(adc); + /* Enable loading of calibrated values even in fail condition */ + calcfg = readl(adc->regs + IMX93_ADC_CALCFG0); + calcfg |= IMX93_ADC_CALCFG0_LDFAIL_MASK; + writel(calcfg, adc->regs + IMX93_ADC_CALCFG0); + /* * TODO: we use the default TSAMP/NRSMPL/AVGEN in MCR, * can add the setting of these bit if need in future. @@ -180,9 +188,13 @@ static int imx93_adc_calibration(struct imx93_adc *adc) /* check whether calbration is success or not */ msr = readl(adc->regs + IMX93_ADC_MSR); if (msr & IMX93_ADC_MSR_CALFAIL_MASK) { + /* + * Only give warning here, this means the noise of the + * reference voltage do not meet the requirement: + * ADC reference voltage Noise < 1.8V * 1/2^ENOB + * And the resault of ADC is not that accurate. + */ dev_warn(adc->dev, "ADC calibration failed!\n"); - imx93_adc_power_down(adc); - return -EAGAIN; } return 0; From f1c675141a5f29f8936ca5f8299511200346831b Mon Sep 17 00:00:00 2001 From: Akshay Bansod Date: Mon, 11 Aug 2025 22:26:40 +0530 Subject: [PATCH 0231/2711] iio: st_lsm6dsx: Replace scnprintf() with sysfs_emit() Update the sysfs interface for sampling frequency and scale attributes. Replace `scnprintf()` with `sysfs_emit_at()` which is PAGE_SIZE-aware and recommended for use in sysfs. Signed-off-by: Akshay Bansod Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250811165641.1214347-1-akbansd@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index c65ad49829e7..d8cb4b0218d5 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -2035,10 +2035,10 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, odr_table = &sensor->hw->settings->odr_table[sensor->id]; for (i = 0; i < odr_table->odr_len; i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%03d ", - odr_table->odr_avl[i].milli_hz / 1000, - odr_table->odr_avl[i].milli_hz % 1000); - buf[len - 1] = '\n'; + len += sysfs_emit_at(buf, len, "%d.%03d%c", + odr_table->odr_avl[i].milli_hz / 1000, + odr_table->odr_avl[i].milli_hz % 1000, + (i == odr_table->odr_len - 1) ? '\n' : ' '); return len; } @@ -2054,9 +2054,9 @@ static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev, fs_table = &hw->settings->fs_table[sensor->id]; for (i = 0; i < fs_table->fs_len; i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "0.%09u ", - fs_table->fs_avl[i].gain); - buf[len - 1] = '\n'; + len += sysfs_emit_at(buf, len, "0.%09u%c", + fs_table->fs_avl[i].gain, + (i == fs_table->fs_len - 1) ? '\n' : ' '); return len; } From 8ffc13805971d81e9c605abec8f223d704f0a61a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Mon, 11 Aug 2025 17:13:33 +0100 Subject: [PATCH 0232/2711] iio: dac: ad5791: drop unused member of struct ad5791_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The regulator pointers reg_vdd and reg_vss are no longer used. So drop them. Signed-off-by: Nuno Sá Reviewed-by: David Lechner Link: https://patch.msgid.link/20250811-ad5791-drop-unused-v1-1-3412fbf3ba36@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5791.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 41582f2b90fb..ae7297f08398 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -80,8 +80,6 @@ struct ad5791_chip_info { /** * struct ad5791_state - driver instance specific data * @spi: spi_device - * @reg_vdd: positive supply regulator - * @reg_vss: negative supply regulator * @gpio_reset: reset gpio * @gpio_clear: clear gpio * @gpio_ldac: load dac gpio @@ -100,8 +98,6 @@ struct ad5791_chip_info { */ struct ad5791_state { struct spi_device *spi; - struct regulator *reg_vdd; - struct regulator *reg_vss; struct gpio_desc *gpio_reset; struct gpio_desc *gpio_clear; struct gpio_desc *gpio_ldac; From 783efeb58fefb13911a3f47d6e38a32780359f10 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:26 +0100 Subject: [PATCH 0233/2711] iio: light: acpi-als: Use a structure for layout of data to push to buffer. Using a structure makes the padding and alignment rules explicit, removing the need for a comment. Also move the storage to the stack as it is only 16 bytes. Cc: Gwendal Grignou Link: https://patch.msgid.link/20250802164436.515988-7-jic23@kernel.org Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko --- drivers/iio/light/acpi-als.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index 032e6cae8b80..511ed37e783e 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -49,20 +49,10 @@ static const struct iio_chan_spec acpi_als_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(1), }; -/* - * The event buffer contains timestamp and all the data from - * the ACPI0008 block. There are multiple, but so far we only - * support _ALI (illuminance): One channel, padding and timestamp. - */ -#define ACPI_ALS_EVT_BUFFER_SIZE \ - (sizeof(s32) + sizeof(s32) + sizeof(s64)) - struct acpi_als { struct acpi_device *device; struct mutex lock; struct iio_trigger *trig; - - s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE / sizeof(s32)] __aligned(8); }; /* @@ -152,7 +142,10 @@ static irqreturn_t acpi_als_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct acpi_als *als = iio_priv(indio_dev); - s32 *buffer = als->evt_buffer; + struct { + s32 light; + aligned_s64 ts; + } scan = { }; s32 val; int ret; @@ -161,7 +154,7 @@ static irqreturn_t acpi_als_trigger_handler(int irq, void *p) ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val); if (ret < 0) goto out; - *buffer = val; + scan.light = val; /* * When coming from own trigger via polls, set polling function @@ -174,7 +167,7 @@ static irqreturn_t acpi_als_trigger_handler(int irq, void *p) if (!pf->timestamp) pf->timestamp = iio_get_time_ns(indio_dev); - iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp); + iio_push_to_buffers_with_timestamp(indio_dev, &scan, pf->timestamp); out: mutex_unlock(&als->lock); iio_trigger_notify_done(indio_dev->trig); From ea85f5e2391dd551cea30863d4806d3264a8ec38 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:27 +0100 Subject: [PATCH 0234/2711] iio: light: acpi-als: Use iio_push_to_buffers_with_ts() to allow runtime source size check This function allows for runtime detection of undersized storage which can be non obvious due to the injection of a timestamp within the helper. Cc: Gwendal Grignou Link: https://patch.msgid.link/20250802164436.515988-8-jic23@kernel.org Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko --- drivers/iio/light/acpi-als.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index 511ed37e783e..d5d1a8b9c035 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -167,7 +167,7 @@ static irqreturn_t acpi_als_trigger_handler(int irq, void *p) if (!pf->timestamp) pf->timestamp = iio_get_time_ns(indio_dev); - iio_push_to_buffers_with_timestamp(indio_dev, &scan, pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), pf->timestamp); out: mutex_unlock(&als->lock); iio_trigger_notify_done(indio_dev->trig); From 656c45811d33b07f0bfcd8bd803976c73a6951cc Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:28 +0100 Subject: [PATCH 0235/2711] iio: light: adjd_s311: Use iio_push_to_buffers_with_ts() to allow source size runtime check Also move the structure used as the source to the stack as it is only 16 bytes and not the target of an DMA or similar. Reviewed-by: Matti Vaittinen Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250802164436.515988-9-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/adjd_s311.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index cf96e3dd8bc6..edb3d9dc8bed 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -54,10 +54,6 @@ struct adjd_s311_data { struct i2c_client *client; - struct { - s16 chans[4]; - aligned_s64 ts; - } scan; }; enum adjd_s311_channel_idx { @@ -120,6 +116,10 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) struct adjd_s311_data *data = iio_priv(indio_dev); s64 time_ns = iio_get_time_ns(indio_dev); int i, j = 0; + struct { + s16 chans[4]; + aligned_s64 ts; + } scan = { }; int ret = adjd_s311_req_data(indio_dev); if (ret < 0) @@ -131,10 +131,10 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) if (ret < 0) goto done; - data->scan.chans[j++] = ret & ADJD_S311_DATA_MASK; + scan.chans[j++] = ret & ADJD_S311_DATA_MASK; } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), time_ns); done: iio_trigger_notify_done(indio_dev->trig); From f0ffec3b4fa7e430f92302ee233c79aeb021fe14 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:29 +0100 Subject: [PATCH 0236/2711] iio: light: isl29125: Use iio_push_to_buffers_with_ts() to allow source size runtime check Also move the structure used as the source to the stack as it is only 16 bytes and not the target of an DMA or similar. Reviewed-by: Matti Vaittinen Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250802164436.515988-10-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/isl29125.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index 6bc23b164cc5..3acb8a4f1d12 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -51,11 +51,6 @@ struct isl29125_data { struct i2c_client *client; u8 conf1; - /* Ensure timestamp is naturally aligned */ - struct { - u16 chans[3]; - aligned_s64 timestamp; - } scan; }; #define ISL29125_CHANNEL(_color, _si) { \ @@ -179,6 +174,11 @@ static irqreturn_t isl29125_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct isl29125_data *data = iio_priv(indio_dev); int i, j = 0; + /* Ensure timestamp is naturally aligned */ + struct { + u16 chans[3]; + aligned_s64 timestamp; + } scan = { }; iio_for_each_active_channel(indio_dev, i) { int ret = i2c_smbus_read_word_data(data->client, @@ -186,10 +186,10 @@ static irqreturn_t isl29125_trigger_handler(int irq, void *p) if (ret < 0) goto done; - data->scan.chans[j++] = ret; + scan.chans[j++] = ret; } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), iio_get_time_ns(indio_dev)); done: From 596081d33bd872e5148439f2da0172fcc56d956f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:30 +0100 Subject: [PATCH 0237/2711] iio: light: max44000: Use iio_push_to_buffers_with_ts() to allow source size runtime check Use iio_push_to_buffers_with_ts() to allow source size runtime check. Also move the structure used as the source to the stack as it is only 16 bytes and not the target of an DMA or similar. Reviewed-by: Matti Vaittinen Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250802164436.515988-11-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/max44000.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index e8b767680133..039d45af3a7f 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -75,11 +75,6 @@ struct max44000_data { struct mutex lock; struct regmap *regmap; - /* Ensure naturally aligned timestamp */ - struct { - u16 channels[2]; - aligned_s64 ts; - } scan; }; /* Default scale is set to the minimum of 0.03125 or 1 / (1 << 5) lux */ @@ -496,24 +491,29 @@ static irqreturn_t max44000_trigger_handler(int irq, void *p) int index = 0; unsigned int regval; int ret; + struct { + u16 channels[2]; + aligned_s64 ts; + } scan = { }; + mutex_lock(&data->lock); if (test_bit(MAX44000_SCAN_INDEX_ALS, indio_dev->active_scan_mask)) { ret = max44000_read_alsval(data); if (ret < 0) goto out_unlock; - data->scan.channels[index++] = ret; + scan.channels[index++] = ret; } if (test_bit(MAX44000_SCAN_INDEX_PRX, indio_dev->active_scan_mask)) { ret = regmap_read(data->regmap, MAX44000_REG_PRX_DATA, ®val); if (ret < 0) goto out_unlock; - data->scan.channels[index] = regval; + scan.channels[index] = regval; } mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; From cb8453db633071ae2b8fefd4be37d74e925d16f5 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:31 +0100 Subject: [PATCH 0238/2711] iio: light: st_uvis25: Use iio_push_to_buffers_with_ts() to allow source size runtime check Use iio_push_to_buffers_with_ts() to allow source size runtime check. Also move the structure used as the source to the stack as it is only 16 bytes and not the target of an DMA or similar. Reviewed-by: Matti Vaittinen Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250802164436.515988-12-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/st_uvis25.h | 5 ----- drivers/iio/light/st_uvis25_core.c | 12 +++++++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/iio/light/st_uvis25.h b/drivers/iio/light/st_uvis25.h index 1f93e3dc45c2..78bc56aad129 100644 --- a/drivers/iio/light/st_uvis25.h +++ b/drivers/iio/light/st_uvis25.h @@ -27,11 +27,6 @@ struct st_uvis25_hw { struct iio_trigger *trig; bool enabled; int irq; - /* Ensure timestamp is naturally aligned */ - struct { - u8 chan; - aligned_s64 ts; - } scan; }; extern const struct dev_pm_ops st_uvis25_pm_ops; diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index 124a8f9204a9..bcd729a9924e 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -234,15 +234,21 @@ static irqreturn_t st_uvis25_buffer_handler_thread(int irq, void *p) struct st_uvis25_hw *hw = iio_priv(iio_dev); unsigned int val; int err; + /* Ensure timestamp is naturally aligned */ + struct { + u8 chan; + aligned_s64 ts; + } scan = { }; + err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, &val); if (err < 0) goto out; - hw->scan.chan = val; + scan.chan = val; - iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan, - iio_get_time_ns(iio_dev)); + iio_push_to_buffers_with_ts(iio_dev, &scan, sizeof(scan), + iio_get_time_ns(iio_dev)); out: iio_trigger_notify_done(hw->trig); From 7cacdd9380e4f8e3dd8cbb410f79061fb078ccdb Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:32 +0100 Subject: [PATCH 0239/2711] iio: light: tcs3414: Use iio_push_to_buffers_with_ts() to allow source size runtime check Use iio_push_to_buffers_with_ts() to allow source size runtime check. Also move the structure used as the source to the stack as it is only 16 bytes and not the target of an DMA or similar. Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250802164436.515988-13-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/tcs3414.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 39268f855c77..5be461e6dbdb 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -53,11 +53,6 @@ struct tcs3414_data { u8 control; u8 gain; u8 timing; - /* Ensure timestamp is naturally aligned */ - struct { - u16 chans[4]; - aligned_s64 timestamp; - } scan; }; #define TCS3414_CHANNEL(_color, _si, _addr) { \ @@ -204,6 +199,12 @@ static irqreturn_t tcs3414_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct tcs3414_data *data = iio_priv(indio_dev); int i, j = 0; + /* Ensure timestamp is naturally aligned */ + struct { + u16 chans[4]; + aligned_s64 timestamp; + } scan = { }; + iio_for_each_active_channel(indio_dev, i) { int ret = i2c_smbus_read_word_data(data->client, @@ -211,10 +212,10 @@ static irqreturn_t tcs3414_trigger_handler(int irq, void *p) if (ret < 0) goto done; - data->scan.chans[j++] = ret; + scan.chans[j++] = ret; } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), iio_get_time_ns(indio_dev)); done: From 66c556aa8358cd71979da9738a810e6074918daa Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:33 +0100 Subject: [PATCH 0240/2711] iio: light: tcs3472: Use iio_push_to_buffers_with_ts() to allow source size runtime check Use iio_push_to_buffers_with_ts() to allow source size runtime check. Also move the structure used as the source to the stack as it is only 16 bytes and not the target of an DMA or similar. Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250802164436.515988-14-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/tcs3472.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 0f8bf8503edd..12429a3261b3 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -64,11 +64,6 @@ struct tcs3472_data { u8 control; u8 atime; u8 apers; - /* Ensure timestamp is naturally aligned */ - struct { - u16 chans[4]; - aligned_s64 timestamp; - } scan; }; static const struct iio_event_spec tcs3472_events[] = { @@ -377,6 +372,11 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct tcs3472_data *data = iio_priv(indio_dev); int i, j = 0; + /* Ensure timestamp is naturally aligned */ + struct { + u16 chans[4]; + aligned_s64 timestamp; + } scan = { }; int ret = tcs3472_req_data(data); if (ret < 0) @@ -388,10 +388,10 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p) if (ret < 0) goto done; - data->scan.chans[j++] = ret; + scan.chans[j++] = ret; } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), iio_get_time_ns(indio_dev)); done: From 19487b50ac7f26c0287d65bb697a4a3aca616d9b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:34 +0100 Subject: [PATCH 0241/2711] iio: light: vcnl4000: Use a structure to make buffer arrangement explicit. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the need for comments to describe the buffer passed to iio_push_to_buffers_with_timestamp(). Reviewed-by: Mårten Lindahl Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250802164436.515988-15-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/vcnl4000.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 90e7d4421abf..eccf690eae8c 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1662,7 +1662,10 @@ static irqreturn_t vcnl4010_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct vcnl4000_data *data = iio_priv(indio_dev); const unsigned long *active_scan_mask = indio_dev->active_scan_mask; - u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */ + struct { + u16 chan; + aligned_s64 ts; + } scan = { }; bool data_read = false; unsigned long isr; int val = 0; @@ -1682,7 +1685,7 @@ static irqreturn_t vcnl4010_trigger_handler(int irq, void *p) if (ret < 0) goto end; - buffer[0] = val; + scan.chan = val; data_read = true; } } @@ -1695,7 +1698,7 @@ static irqreturn_t vcnl4010_trigger_handler(int irq, void *p) if (!data_read) goto end; - iio_push_to_buffers_with_timestamp(indio_dev, buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev)); end: From 2bbaf41ac9f70092bbd48d779a176d2ee6a0131f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:35 +0100 Subject: [PATCH 0242/2711] iio: light: vl6180: Use iio_push_to_buffers_with_ts() to allow source size runtime check Use iio_push_to_buffers_with_ts() to allow source size runtime check. Also move the structure used as the source to the stack as it is only 16 bytes and not the target of an DMA or similar. Cc: Abhash Jha Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250802164436.515988-16-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/vl6180.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index 38706424089c..c1314b144367 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -96,11 +96,6 @@ struct vl6180_data { unsigned int als_it_ms; unsigned int als_meas_rate; unsigned int range_meas_rate; - - struct { - u16 chan[2]; - aligned_s64 timestamp; - } scan; }; enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX }; @@ -545,6 +540,11 @@ static irqreturn_t vl6180_trigger_handler(int irq, void *priv) struct vl6180_data *data = iio_priv(indio_dev); s64 time_ns = iio_get_time_ns(indio_dev); int ret, bit, i = 0; + struct { + u16 chan[2]; + aligned_s64 timestamp; + } scan = { }; + iio_for_each_active_channel(indio_dev, bit) { if (vl6180_chan_regs_table[bit].word) @@ -560,10 +560,10 @@ static irqreturn_t vl6180_trigger_handler(int irq, void *priv) return IRQ_HANDLED; } - data->scan.chan[i++] = ret; + scan.chan[i++] = ret; } - iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), time_ns); iio_trigger_notify_done(indio_dev->trig); /* Clear the interrupt flag after data read */ From 1ab10737fcc9cc7aca6f3d49911c0fd953dc5aed Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 2 Aug 2025 17:44:36 +0100 Subject: [PATCH 0243/2711] iio: light: Simple conversions to iio_push_to_buffers_with_ts() This new function allows for runtime checks on the provided source buffer being of sufficient size to accommodate the enabled channel data layout and the naturally aligned s64 timestamp (which is non obvious and a frequent source of bugs in the past). This patch includes the remaining simple cases for light sensor drivers. Cc: Mudit Sharma Cc: Jiri Kosina Cc: Srinivas Pandruvada Cc: Javier Carrasco Cc: Matti Vaittinen Reviewed-by: Matti Vaittinen Acked-by: Srinivas Pandruvada Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250802164436.515988-17-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/bh1745.c | 4 ++-- drivers/iio/light/hid-sensor-als.c | 5 +++-- drivers/iio/light/ltr501.c | 4 ++-- drivers/iio/light/opt4060.c | 2 +- drivers/iio/light/rohm-bu27034.c | 3 ++- drivers/iio/light/rpr0521.c | 4 ++-- drivers/iio/light/si1145.c | 5 +++-- drivers/iio/light/vcnl4000.c | 4 ++-- drivers/iio/light/veml6030.c | 2 +- 9 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/iio/light/bh1745.c b/drivers/iio/light/bh1745.c index c7c604c96f6e..10b00344bbed 100644 --- a/drivers/iio/light/bh1745.c +++ b/drivers/iio/light/bh1745.c @@ -755,8 +755,8 @@ static irqreturn_t bh1745_trigger_handler(int interrupt, void *p) scan.chans[j++] = value; } - iio_push_to_buffers_with_timestamp(indio_dev, &scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 830e5ae7f34a..384572844162 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -262,8 +262,9 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev, if (!als_state->timestamp) als_state->timestamp = iio_get_time_ns(indio_dev); - iio_push_to_buffers_with_timestamp(indio_dev, &als_state->scan, - als_state->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &als_state->scan, + sizeof(als_state->scan), + als_state->timestamp); als_state->timestamp = 0; } diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index debf57a52d1c..022e0693983b 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -1315,8 +1315,8 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p) scan.channels[j++] = psdata & LTR501_PS_DATA_MASK; } - iio_push_to_buffers_with_timestamp(indio_dev, &scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/opt4060.c b/drivers/iio/light/opt4060.c index 7a1b6c703823..aa10400e0a1f 100644 --- a/drivers/iio/light/opt4060.c +++ b/drivers/iio/light/opt4060.c @@ -1104,7 +1104,7 @@ static irqreturn_t opt4060_trigger_handler(int irq, void *p) } } - iio_push_to_buffers_with_timestamp(idev, &raw, pf->timestamp); + iio_push_to_buffers_with_ts(idev, &raw, sizeof(raw), pf->timestamp); err_read: iio_trigger_notify_done(idev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/light/rohm-bu27034.c b/drivers/iio/light/rohm-bu27034.c index 7cec5e943373..28d111ac8c0a 100644 --- a/drivers/iio/light/rohm-bu27034.c +++ b/drivers/iio/light/rohm-bu27034.c @@ -1193,7 +1193,8 @@ static int bu27034_buffer_thread(void *arg) */ data->scan.mlux = (u32)mlux; } - iio_push_to_buffers_with_timestamp(idev, &data->scan, tstamp); + iio_push_to_buffers_with_ts(idev, &data->scan, + sizeof(data->scan), tstamp); } return 0; diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index c50183f07240..fbd116272921 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -457,8 +457,8 @@ static irqreturn_t rpr0521_trigger_consumer_handler(int irq, void *p) data->scan.channels, (3 * 2) + 1); /* 3 * 16-bit + (discarded) int clear reg. */ if (!err) - iio_push_to_buffers_with_timestamp(indio_dev, - &data->scan, pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &data->scan, + sizeof(data->scan), pf->timestamp); else dev_err(&data->client->dev, "Trigger consumer can't read from sensor.\n"); diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c index 4aa02afd853e..f8eb251eca8d 100644 --- a/drivers/iio/light/si1145.c +++ b/drivers/iio/light/si1145.c @@ -494,8 +494,9 @@ static irqreturn_t si1145_trigger_handler(int irq, void *private) goto done; } - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, data->buffer, + sizeof(data->buffer), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index eccf690eae8c..cc81a30b7c70 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1698,8 +1698,8 @@ static irqreturn_t vcnl4010_trigger_handler(int irq, void *p) if (!data_read) goto end; - iio_push_to_buffers_with_timestamp(indio_dev, &scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); end: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index 0945f146bedb..6bcacae3863c 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -903,7 +903,7 @@ static irqreturn_t veml6030_trigger_handler(int irq, void *p) scan.chans[i++] = reg; } - iio_push_to_buffers_with_timestamp(iio, &scan, pf->timestamp); + iio_push_to_buffers_with_ts(iio, &scan, sizeof(scan), pf->timestamp); done: iio_trigger_notify_done(iio->trig); From c851b71fd6cdbf3000bf0a2354592a0f09db3ba3 Mon Sep 17 00:00:00 2001 From: Venkat Jayaraman Date: Thu, 14 Aug 2025 09:30:28 -0700 Subject: [PATCH 0244/2711] usb: typec: ucsi: Add support for READ_POWER_LEVEL command Add support for UCSI READ_POWER_LEVEL command as per UCSI specification v2.1 and above to debugfs. Following power related fields will be exposed as files in debugfs:- peak_current (Peak current), avg_current (Average current) and vbus_voltage (VBUS voltage) These files will be updated either when a READ_POWER_LEVEL command is sent from OS or when a device is connected. Reviewed-by: Heikki Krogerus Signed-off-by: Venkat Jayaraman Link: https://lore.kernel.org/r/20250814163028.18058-1-venkat.jayaraman@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/debugfs.c | 31 +++++++++++++++++++++++++++++++ drivers/usb/typec/ucsi/ucsi.c | 16 ++++++++++++++++ drivers/usb/typec/ucsi/ucsi.h | 13 +++++++++++++ 3 files changed, 60 insertions(+) diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c index 92ebf1a2defd..f73f2b54554e 100644 --- a/drivers/usb/typec/ucsi/debugfs.c +++ b/drivers/usb/typec/ucsi/debugfs.c @@ -35,6 +35,7 @@ static int ucsi_cmd(void *data, u64 val) case UCSI_SET_SINK_PATH: case UCSI_SET_NEW_CAM: case UCSI_SET_USB: + case UCSI_READ_POWER_LEVEL: ret = ucsi_send_command(ucsi, val, NULL, 0); break; case UCSI_GET_CAPABILITY: @@ -80,6 +81,33 @@ static int ucsi_resp_show(struct seq_file *s, void *not_used) } DEFINE_SHOW_ATTRIBUTE(ucsi_resp); +static int ucsi_peak_curr_show(struct seq_file *m, void *v) +{ + struct ucsi *ucsi = m->private; + + seq_printf(m, "%u mA\n", ucsi->connector->peak_current); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(ucsi_peak_curr); + +static int ucsi_avg_curr_show(struct seq_file *m, void *v) +{ + struct ucsi *ucsi = m->private; + + seq_printf(m, "%u mA\n", ucsi->connector->avg_current); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(ucsi_avg_curr); + +static int ucsi_vbus_volt_show(struct seq_file *m, void *v) +{ + struct ucsi *ucsi = m->private; + + seq_printf(m, "%u mV\n", ucsi->connector->vbus_voltage); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(ucsi_vbus_volt); + void ucsi_debugfs_register(struct ucsi *ucsi) { ucsi->debugfs = kzalloc(sizeof(*ucsi->debugfs), GFP_KERNEL); @@ -89,6 +117,9 @@ void ucsi_debugfs_register(struct ucsi *ucsi) ucsi->debugfs->dentry = debugfs_create_dir(dev_name(ucsi->dev), ucsi_debugfs_root); debugfs_create_file("command", 0200, ucsi->debugfs->dentry, ucsi, &ucsi_cmd_fops); debugfs_create_file("response", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_resp_fops); + debugfs_create_file("peak_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_peak_curr_fops); + debugfs_create_file("avg_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_avg_curr_fops); + debugfs_create_file("vbus_voltage", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_vbus_volt_fops); } void ucsi_debugfs_unregister(struct ucsi *ucsi) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 5739ea2abdd1..0d6b0cf5a7cd 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1217,9 +1217,11 @@ static void ucsi_handle_connector_change(struct work_struct *work) struct ucsi_connector *con = container_of(work, struct ucsi_connector, work); struct ucsi *ucsi = con->ucsi; + u8 curr_scale, volt_scale; enum typec_role role; u16 change; int ret; + u32 val; mutex_lock(&con->lock); @@ -1291,6 +1293,20 @@ static void ucsi_handle_connector_change(struct work_struct *work) if (change & UCSI_CONSTAT_BC_CHANGE) ucsi_port_psy_changed(con); + if (UCSI_CONSTAT(con, PWR_READING_READY_V2_1)) { + curr_scale = UCSI_CONSTAT(con, CURRENT_SCALE_V2_1); + volt_scale = UCSI_CONSTAT(con, VOLTAGE_SCALE_V2_1); + + val = UCSI_CONSTAT(con, PEAK_CURRENT_V2_1); + con->peak_current = UCSI_CONSTAT_CURR_SCALE_MULT * curr_scale * val; + + val = UCSI_CONSTAT(con, AVG_CURRENT_V2_1); + con->avg_current = UCSI_CONSTAT_CURR_SCALE_MULT * curr_scale * val; + + val = UCSI_CONSTAT(con, VBUS_VOLTAGE_V2_1); + con->vbus_voltage = UCSI_CONSTAT_VOLT_SCALE_MULT * volt_scale * val; + } + out_unlock: mutex_unlock(&con->lock); } diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index ebd7c27c2cc7..e301d9012936 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -131,6 +131,7 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); #define UCSI_GET_PD_MESSAGE 0x15 #define UCSI_GET_CAM_CS 0x18 #define UCSI_SET_SINK_PATH 0x1c +#define UCSI_READ_POWER_LEVEL 0x1e #define UCSI_SET_USB 0x21 #define UCSI_GET_LPM_PPM_INFO 0x22 @@ -359,6 +360,14 @@ struct ucsi_cable_property { #define UCSI_CONSTAT_BC_SLOW_CHARGING 2 #define UCSI_CONSTAT_BC_TRICKLE_CHARGING 3 #define UCSI_CONSTAT_PD_VERSION_V1_2 UCSI_DECLARE_BITFIELD_V1_2(70, 16) +#define UCSI_CONSTAT_PWR_READING_READY_V2_1 UCSI_DECLARE_BITFIELD_V2_1(89, 1) +#define UCSI_CONSTAT_CURRENT_SCALE_V2_1 UCSI_DECLARE_BITFIELD_V2_1(90, 3) +#define UCSI_CONSTAT_PEAK_CURRENT_V2_1 UCSI_DECLARE_BITFIELD_V2_1(93, 16) +#define UCSI_CONSTAT_AVG_CURRENT_V2_1 UCSI_DECLARE_BITFIELD_V2_1(109, 16) +#define UCSI_CONSTAT_VOLTAGE_SCALE_V2_1 UCSI_DECLARE_BITFIELD_V2_1(125, 4) +#define UCSI_CONSTAT_VBUS_VOLTAGE_V2_1 UCSI_DECLARE_BITFIELD_V2_1(129, 16) +#define UCSI_CONSTAT_CURR_SCALE_MULT 5 +#define UCSI_CONSTAT_VOLT_SCALE_MULT 5 /* Connector Status Change Bits. */ #define UCSI_CONSTAT_EXT_SUPPLY_CHANGE BIT(1) @@ -519,6 +528,10 @@ struct ucsi_connector { u32 src_pdos[PDO_MAX_OBJECTS]; int num_pdos; + u32 peak_current; + u32 avg_current; + u32 vbus_voltage; + /* USB PD objects */ struct usb_power_delivery *pd; struct usb_power_delivery_capabilities *port_source_caps; From 23cd838a178a81183da9db6cb3390bb540b000a5 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 15 Aug 2025 14:31:21 +0300 Subject: [PATCH 0245/2711] USB: Check no positive return values from pm_runtime_resume_and_get() pm_runtime_resume_and_get() always returns a negative error code or zero; there's no need to check for positive values such as returned by pm_runtime_get_sync(). Simply drop the check. Signed-off-by: Sakari Ailus Link: https://lore.kernel.org/r/20250815113121.925641-1-sakari.ailus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 69216c3951fd..25358cf3e324 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1723,8 +1723,6 @@ int usb_autoresume_device(struct usb_device *udev) dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&udev->dev.power.usage_count), status); - if (status > 0) - status = 0; return status; } @@ -1829,8 +1827,6 @@ int usb_autopm_get_interface(struct usb_interface *intf) dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&intf->dev.power.usage_count), status); - if (status > 0) - status = 0; return status; } EXPORT_SYMBOL_GPL(usb_autopm_get_interface); From 956606bafb5fc6e5968aadcda86fc0037e1d7548 Mon Sep 17 00:00:00 2001 From: raub camaioni Date: Fri, 15 Aug 2025 09:07:21 -0400 Subject: [PATCH 0246/2711] usb: gadget: f_ncm: Fix MAC assignment NCM ethernet This fix is already present in f_ecm.c and was never propagated to f_ncm.c When creating multiple NCM ethernet devices on a composite usb gadget device each MAC address on the HOST side will be identical. Having the same MAC on different network interfaces is bad. This fix updates the MAC address inside the ncm_strings_defs global during the ncm_bind call. This ensures each device has a unique MAC. In f_ecm.c ecm_string_defs is updated in the same way. The defunct MAC assignment in ncm_alloc has been removed. Signed-off-by: raub camaioni Link: https://lore.kernel.org/r/20250815131358.1047525-1-raubcameo@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_ncm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 58b0dd575af3..cad111f33552 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1463,6 +1463,8 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) ncm_opts->bound = true; + ncm_string_defs[1].s = ncm->ethaddr; + us = usb_gstrings_attach(cdev, ncm_strings, ARRAY_SIZE(ncm_string_defs)); if (IS_ERR(us)) { @@ -1771,7 +1773,6 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi) mutex_unlock(&opts->lock); return ERR_PTR(-EINVAL); } - ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr; spin_lock_init(&ncm->lock); ncm_reset_values(ncm); From 4847d1187402a5027d9a04393f12d52a5a1d7f98 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:41 +0200 Subject: [PATCH 0247/2711] console: introduce console_lock guard()s Having this, guards like these work: guard(console_lock)(); or scoped_guard(console_lock) { ... } See e.g. "vc_screen: use guard()s" later in this series. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-2-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/console.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/console.h b/include/linux/console.h index 8f10d0a85bb4..031a58dc2b91 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -666,6 +666,8 @@ void vcs_remove_sysfs(int index); */ extern atomic_t ignore_console_lock_warning; +DEFINE_LOCK_GUARD_0(console_lock, console_lock(), console_unlock()); + extern void console_init(void); /* For deferred console takeover */ From e8398b8aed50382c21fcec77e80a5314e7c45c25 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:42 +0200 Subject: [PATCH 0248/2711] tty: introduce tty_port_tty guard() Having this, guards like these work: scoped_guard(tty_port_tty, port) tty_wakeup(scoped_tty()); See e.g. "tty_port: use scoped_guard()" later in this series. The definitions depend on CONFIG_TTY. It's due to tty_kref_put(). On !CONFIG_TTY, it is an inline and its declaration would conflict. The guards are not needed in that case, of course. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-3-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/tty_port.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h index 332ddb93603e..660c254f1efe 100644 --- a/include/linux/tty_port.h +++ b/include/linux/tty_port.h @@ -270,4 +270,18 @@ static inline void tty_port_tty_vhangup(struct tty_port *port) __tty_port_tty_hangup(port, false, false); } +#ifdef CONFIG_TTY +void tty_kref_put(struct tty_struct *tty); +__DEFINE_CLASS_IS_CONDITIONAL(tty_port_tty, true); +__DEFINE_UNLOCK_GUARD(tty_port_tty, struct tty_struct, tty_kref_put(_T->lock)); +static inline class_tty_port_tty_t class_tty_port_tty_constructor(struct tty_port *tport) +{ + class_tty_port_tty_t _t = { + .lock = tty_port_tty_get(tport), + }; + return _t; +} +#define scoped_tty() ((struct tty_struct *)(__guard_ptr(tty_port_tty)(&scope))) +#endif + #endif From 0fd60b689b0dacce659253ec15cb3d3bf660e30b Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:43 +0200 Subject: [PATCH 0249/2711] serial: introduce uart_port_lock() guard()s Having this, guards like these work: guard(uart_port_lock_irq)(&up->port); or scoped_guard(uart_port_lock_irqsave, port) { ... } See e.g. "serial: 8250: use guard()s" later in this series. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-4-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/serial_core.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 84b4648ead7e..666430b47899 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -788,6 +788,19 @@ static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned lo spin_unlock_irqrestore(&up->lock, flags); } +DEFINE_GUARD(uart_port_lock, struct uart_port *, uart_port_lock(_T), uart_port_unlock(_T)); +DEFINE_GUARD_COND(uart_port_lock, _try, uart_port_trylock(_T)); + +DEFINE_GUARD(uart_port_lock_irq, struct uart_port *, uart_port_lock_irq(_T), + uart_port_unlock_irq(_T)); + +DEFINE_LOCK_GUARD_1(uart_port_lock_irqsave, struct uart_port, + uart_port_lock_irqsave(_T->lock, &_T->flags), + uart_port_unlock_irqrestore(_T->lock, _T->flags), + unsigned long flags); +DEFINE_LOCK_GUARD_1_COND(uart_port_lock_irqsave, _try, + uart_port_trylock_irqsave(_T->lock, &_T->flags)); + static inline int serial_port_in(struct uart_port *up, int offset) { return up->serial_in(up, offset); From 9f8da7b2f90cb5fb4c585d5e8aa89dfd724bd377 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:44 +0200 Subject: [PATCH 0250/2711] serial: 8250: introduce RPM guard()s Having this, guards like these work: guard(serial8250_rpm)(up); or scoped_guard(serial8250_rpm, up) { ... } See e.g. "serial: 8250: use guard()s" later in this series. And make them available to anyone (EXPORT + put in 8250.h) as drivers open code this anyway. The _tx ones are not defined as they would have no user. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-5-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 5 +++++ drivers/tty/serial/8250/8250_port.c | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index cfe6ba286b45..58e64c4e1e3a 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -186,6 +186,11 @@ static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up, void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p); +void serial8250_rpm_get(struct uart_8250_port *p); +void serial8250_rpm_put(struct uart_8250_port *p); +DEFINE_GUARD(serial8250_rpm, struct uart_8250_port *, + serial8250_rpm_get(_T), serial8250_rpm_put(_T)); + static inline u32 serial_dl_read(struct uart_8250_port *up) { return up->dl_read(up); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 2da9db960d09..5afae4025696 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -508,20 +508,22 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) } EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); -static void serial8250_rpm_get(struct uart_8250_port *p) +void serial8250_rpm_get(struct uart_8250_port *p) { if (!(p->capabilities & UART_CAP_RPM)) return; pm_runtime_get_sync(p->port.dev); } +EXPORT_SYMBOL_GPL(serial8250_rpm_get); -static void serial8250_rpm_put(struct uart_8250_port *p) +void serial8250_rpm_put(struct uart_8250_port *p) { if (!(p->capabilities & UART_CAP_RPM)) return; pm_runtime_mark_last_busy(p->port.dev); pm_runtime_put_autosuspend(p->port.dev); } +EXPORT_SYMBOL_GPL(serial8250_rpm_put); /** * serial8250_em485_init() - put uart_8250_port into rs485 emulating From 88d65e22c8bf7a4b6d61098d67727d14f1c5930f Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:45 +0200 Subject: [PATCH 0251/2711] tty: tty_port: use guard()s Having all the new guards, use them in the tty_port code. This improves readability, makes error handling easier, and marks locked portions of code explicit. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-6-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_port.c | 168 ++++++++++++++++++----------------------- 1 file changed, 74 insertions(+), 94 deletions(-) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 5b4d5fb99a59..fe67c5cb0a3f 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -63,12 +63,8 @@ static void tty_port_default_lookahead_buf(struct tty_port *port, const u8 *p, static void tty_port_default_wakeup(struct tty_port *port) { - struct tty_struct *tty = tty_port_tty_get(port); - - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } + scoped_guard(tty_port_tty, port) + tty_wakeup(scoped_tty()); } const struct tty_port_client_operations tty_port_default_client_ops = { @@ -225,26 +221,27 @@ EXPORT_SYMBOL_GPL(tty_port_unregister_device); int tty_port_alloc_xmit_buf(struct tty_port *port) { /* We may sleep in get_zeroed_page() */ - mutex_lock(&port->buf_mutex); - if (port->xmit_buf == NULL) { - port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL); - if (port->xmit_buf) - kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE); - } - mutex_unlock(&port->buf_mutex); + guard(mutex)(&port->buf_mutex); + + if (port->xmit_buf) + return 0; + + port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL); if (port->xmit_buf == NULL) return -ENOMEM; + + kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE); + return 0; } EXPORT_SYMBOL(tty_port_alloc_xmit_buf); void tty_port_free_xmit_buf(struct tty_port *port) { - mutex_lock(&port->buf_mutex); + guard(mutex)(&port->buf_mutex); free_page((unsigned long)port->xmit_buf); port->xmit_buf = NULL; INIT_KFIFO(port->xmit_fifo); - mutex_unlock(&port->buf_mutex); } EXPORT_SYMBOL(tty_port_free_xmit_buf); @@ -301,13 +298,8 @@ EXPORT_SYMBOL(tty_port_put); */ struct tty_struct *tty_port_tty_get(struct tty_port *port) { - unsigned long flags; - struct tty_struct *tty; - - spin_lock_irqsave(&port->lock, flags); - tty = tty_kref_get(port->tty); - spin_unlock_irqrestore(&port->lock, flags); - return tty; + guard(spinlock_irqsave)(&port->lock); + return tty_kref_get(port->tty); } EXPORT_SYMBOL(tty_port_tty_get); @@ -321,12 +313,9 @@ EXPORT_SYMBOL(tty_port_tty_get); */ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) { - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); + guard(spinlock_irqsave)(&port->lock); tty_kref_put(port->tty); port->tty = tty_kref_get(tty); - spin_unlock_irqrestore(&port->lock, flags); } EXPORT_SYMBOL(tty_port_tty_set); @@ -342,24 +331,24 @@ EXPORT_SYMBOL(tty_port_tty_set); */ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) { - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); + if (port->console) - goto out; + return; - if (tty_port_initialized(port)) { - tty_port_set_initialized(port, false); - /* - * Drop DTR/RTS if HUPCL is set. This causes any attached - * modem to hang up the line. - */ - if (tty && C_HUPCL(tty)) - tty_port_lower_dtr_rts(port); + if (!tty_port_initialized(port)) + return; - if (port->ops->shutdown) - port->ops->shutdown(port); - } -out: - mutex_unlock(&port->mutex); + tty_port_set_initialized(port, false); + /* + * Drop DTR/RTS if HUPCL is set. This causes any attached + * modem to hang up the line. + */ + if (tty && C_HUPCL(tty)) + tty_port_lower_dtr_rts(port); + + if (port->ops->shutdown) + port->ops->shutdown(port); } /** @@ -374,15 +363,15 @@ out: void tty_port_hangup(struct tty_port *port) { struct tty_struct *tty; - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - port->count = 0; - tty = port->tty; - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); - port->tty = NULL; - spin_unlock_irqrestore(&port->lock, flags); + scoped_guard(spinlock_irqsave, &port->lock) { + port->count = 0; + tty = port->tty; + if (tty) + set_bit(TTY_IO_ERROR, &tty->flags); + port->tty = NULL; + } + tty_port_set_active(port, false); tty_port_shutdown(port, tty); tty_kref_put(tty); @@ -393,15 +382,16 @@ EXPORT_SYMBOL(tty_port_hangup); void __tty_port_tty_hangup(struct tty_port *port, bool check_clocal, bool async) { - struct tty_struct *tty = tty_port_tty_get(port); + scoped_guard(tty_port_tty, port) { + struct tty_struct *tty = scoped_tty(); - if (tty && (!check_clocal || !C_CLOCAL(tty))) { - if (async) - tty_hangup(tty); - else - tty_vhangup(tty); + if (!check_clocal || !C_CLOCAL(tty)) { + if (async) + tty_hangup(tty); + else + tty_vhangup(tty); + } } - tty_kref_put(tty); } EXPORT_SYMBOL_GPL(__tty_port_tty_hangup); @@ -490,7 +480,6 @@ int tty_port_block_til_ready(struct tty_port *port, struct tty_struct *tty, struct file *filp) { int do_clocal = 0, retval; - unsigned long flags; DEFINE_WAIT(wait); /* if non-blocking mode is set we can pass directly to open unless @@ -519,10 +508,10 @@ int tty_port_block_til_ready(struct tty_port *port, retval = 0; /* The port lock protects the port counts */ - spin_lock_irqsave(&port->lock, flags); - port->count--; - port->blocked_open++; - spin_unlock_irqrestore(&port->lock, flags); + scoped_guard(spinlock_irqsave, &port->lock) { + port->count--; + port->blocked_open++; + } while (1) { /* Indicate we are open */ @@ -561,11 +550,11 @@ int tty_port_block_til_ready(struct tty_port *port, /* Update counts. A parallel hangup will have set count to zero and * we must not mess that up further. */ - spin_lock_irqsave(&port->lock, flags); - if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; - spin_unlock_irqrestore(&port->lock, flags); + scoped_guard(spinlock_irqsave, &port->lock) { + if (!tty_hung_up_p(filp)) + port->count++; + port->blocked_open--; + } if (retval == 0) tty_port_set_active(port, true); return retval; @@ -604,28 +593,24 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty) int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp) { - unsigned long flags; - if (tty_hung_up_p(filp)) return 0; - spin_lock_irqsave(&port->lock, flags); - if (tty->count == 1 && port->count != 1) { - tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__, - port->count); - port->count = 1; - } - if (--port->count < 0) { - tty_warn(tty, "%s: bad port count (%d)\n", __func__, - port->count); - port->count = 0; - } + scoped_guard(spinlock_irqsave, &port->lock) { + if (tty->count == 1 && port->count != 1) { + tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__, + port->count); + port->count = 1; + } + if (--port->count < 0) { + tty_warn(tty, "%s: bad port count (%d)\n", __func__, + port->count); + port->count = 0; + } - if (port->count) { - spin_unlock_irqrestore(&port->lock, flags); - return 0; + if (port->count) + return 0; } - spin_unlock_irqrestore(&port->lock, flags); tty->closing = 1; @@ -744,9 +729,8 @@ EXPORT_SYMBOL_GPL(tty_port_install); int tty_port_open(struct tty_port *port, struct tty_struct *tty, struct file *filp) { - spin_lock_irq(&port->lock); - ++port->count; - spin_unlock_irq(&port->lock); + scoped_guard(spinlock_irq, &port->lock) + ++port->count; tty_port_tty_set(port, tty); /* @@ -755,21 +739,17 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty, * port mutex. */ - mutex_lock(&port->mutex); - - if (!tty_port_initialized(port)) { + scoped_guard(mutex, &port->mutex) { + if (tty_port_initialized(port)) + break; clear_bit(TTY_IO_ERROR, &tty->flags); if (port->ops->activate) { int retval = port->ops->activate(port, tty); - - if (retval) { - mutex_unlock(&port->mutex); + if (retval) return retval; - } } tty_port_set_initialized(port, true); } - mutex_unlock(&port->mutex); return tty_port_block_til_ready(port, tty, filp); } EXPORT_SYMBOL(tty_port_open); From 81600e92a0ececef093ab85f4b56be7468412e76 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:46 +0200 Subject: [PATCH 0252/2711] mxser: use tty_port_tty guard() in mxser_port_isr() Use scoped_guard() and reorder the function. This is done separately from the other changes, as it is slighly more intrusive: scoped_guard() handles the have-tty case and returns. The non-tty case is done at the end of the function. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-7-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 68 +++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 2fc13cc02cc5..b070ebf9f51a 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1600,54 +1600,50 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port static bool mxser_port_isr(struct mxser_port *port) { - struct tty_struct *tty; u8 iir, status; - bool error = false; iir = inb(port->ioaddr + UART_IIR); if (iir & UART_IIR_NO_INT) return true; iir &= MOXA_MUST_IIR_MASK; - tty = tty_port_tty_get(&port->port); - if (!tty) { - status = inb(port->ioaddr + UART_LSR); - outb(port->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, - port->ioaddr + UART_FCR); - inb(port->ioaddr + UART_MSR); - error = true; - goto put_tty; + scoped_guard(tty_port_tty, &port->port) { + struct tty_struct *tty = scoped_tty(); + + status = inb(port->ioaddr + UART_LSR); + + if (port->board->must_hwid) { + if (iir == MOXA_MUST_IIR_GDA || + iir == MOXA_MUST_IIR_RDA || + iir == MOXA_MUST_IIR_RTO || + iir == MOXA_MUST_IIR_LSR) + status = mxser_receive_chars(tty, port, status); + } else { + status &= port->read_status_mask; + if (status & UART_LSR_DR) + status = mxser_receive_chars(tty, port, status); + } + + mxser_check_modem_status(tty, port); + + if (port->board->must_hwid) { + if (iir == 0x02 && (status & UART_LSR_THRE)) + mxser_transmit_chars(tty, port); + } else { + if (status & UART_LSR_THRE) + mxser_transmit_chars(tty, port); + } + + return false; } status = inb(port->ioaddr + UART_LSR); + outb(port->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + port->ioaddr + UART_FCR); + inb(port->ioaddr + UART_MSR); - if (port->board->must_hwid) { - if (iir == MOXA_MUST_IIR_GDA || - iir == MOXA_MUST_IIR_RDA || - iir == MOXA_MUST_IIR_RTO || - iir == MOXA_MUST_IIR_LSR) - status = mxser_receive_chars(tty, port, status); - } else { - status &= port->read_status_mask; - if (status & UART_LSR_DR) - status = mxser_receive_chars(tty, port, status); - } - - mxser_check_modem_status(tty, port); - - if (port->board->must_hwid) { - if (iir == 0x02 && (status & UART_LSR_THRE)) - mxser_transmit_chars(tty, port); - } else { - if (status & UART_LSR_THRE) - mxser_transmit_chars(tty, port); - } - -put_tty: - tty_kref_put(tty); - - return error; + return true; } /* From 793b450112964f6d460a6ef1beff077d2e617ebd Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:47 +0200 Subject: [PATCH 0253/2711] mxser: use guard()s Having all the new guards, use them in the mxser code. This improves readability, makes error handling easier, and marks locked portions of code explicit. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-8-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 197 +++++++++++++++++--------------------------- 1 file changed, 74 insertions(+), 123 deletions(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index b070ebf9f51a..94677fec685e 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -442,11 +442,8 @@ static void __mxser_start_tx(struct mxser_port *info) static void mxser_start_tx(struct mxser_port *info) { - unsigned long flags; - - spin_lock_irqsave(&info->slock, flags); + guard(spinlock_irqsave)(&info->slock); __mxser_start_tx(info); - spin_unlock_irqrestore(&info->slock, flags); } static void __mxser_stop_tx(struct mxser_port *info) @@ -465,17 +462,15 @@ static bool mxser_carrier_raised(struct tty_port *port) static void mxser_dtr_rts(struct tty_port *port, bool active) { struct mxser_port *mp = container_of(port, struct mxser_port, port); - unsigned long flags; u8 mcr; - spin_lock_irqsave(&mp->slock, flags); + guard(spinlock_irqsave)(&mp->slock); mcr = inb(mp->ioaddr + UART_MCR); if (active) mcr |= UART_MCR_DTR | UART_MCR_RTS; else mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); outb(mcr, mp->ioaddr + UART_MCR); - spin_unlock_irqrestore(&mp->slock, flags); } static int mxser_set_baud(struct tty_struct *tty, speed_t newspd) @@ -828,32 +823,28 @@ static void mxser_stop_rx(struct mxser_port *info) static void mxser_shutdown_port(struct tty_port *port) { struct mxser_port *info = container_of(port, struct mxser_port, port); - unsigned long flags; - spin_lock_irqsave(&info->slock, flags); + scoped_guard(spinlock_irqsave, &info->slock) { + mxser_stop_rx(info); - mxser_stop_rx(info); + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&info->port.delta_msr_wait); - /* - * clear delta_msr_wait queue to avoid mem leaks: we may free the irq - * here so the queue might never be waken up - */ - wake_up_interruptible(&info->port.delta_msr_wait); + info->IER = 0; + outb(0x00, info->ioaddr + UART_IER); - info->IER = 0; - outb(0x00, info->ioaddr + UART_IER); + /* clear Rx/Tx FIFO's */ + mxser_disable_and_clear_FIFO(info); - /* clear Rx/Tx FIFO's */ - mxser_disable_and_clear_FIFO(info); + /* read data port to reset things */ + (void)inb(info->ioaddr + UART_RX); - /* read data port to reset things */ - (void) inb(info->ioaddr + UART_RX); - - - if (info->board->must_hwid) - mxser_must_no_sw_flow_control(info->ioaddr); - - spin_unlock_irqrestore(&info->slock, flags); + if (info->board->must_hwid) + mxser_must_no_sw_flow_control(info->ioaddr); + } /* make sure ISR is not running while we free the buffer */ synchronize_irq(info->board->irq); @@ -880,15 +871,13 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) static void mxser_flush_buffer(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - unsigned long flags; - spin_lock_irqsave(&info->slock, flags); - kfifo_reset(&info->port.xmit_fifo); + scoped_guard(spinlock_irqsave, &info->slock) { + kfifo_reset(&info->port.xmit_fifo); - outb(info->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, - info->ioaddr + UART_FCR); - - spin_unlock_irqrestore(&info->slock, flags); + outb(info->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + info->ioaddr + UART_FCR); + } tty_wakeup(tty); } @@ -901,14 +890,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) static ssize_t mxser_write(struct tty_struct *tty, const u8 *buf, size_t count) { struct mxser_port *info = tty->driver_data; - unsigned long flags; size_t written; bool is_empty; - spin_lock_irqsave(&info->slock, flags); - written = kfifo_in(&info->port.xmit_fifo, buf, count); - is_empty = kfifo_is_empty(&info->port.xmit_fifo); - spin_unlock_irqrestore(&info->slock, flags); + scoped_guard(spinlock_irqsave, &info->slock) { + written = kfifo_in(&info->port.xmit_fifo, buf, count); + is_empty = kfifo_is_empty(&info->port.xmit_fifo); + } if (!is_empty && !tty->flow.stopped) if (!tty->hw_stopped || mxser_16550A_or_MUST(info)) @@ -920,14 +908,9 @@ static ssize_t mxser_write(struct tty_struct *tty, const u8 *buf, size_t count) static int mxser_put_char(struct tty_struct *tty, u8 ch) { struct mxser_port *info = tty->driver_data; - unsigned long flags; - int ret; - spin_lock_irqsave(&info->slock, flags); - ret = kfifo_put(&info->port.xmit_fifo, ch); - spin_unlock_irqrestore(&info->slock, flags); - - return ret; + guard(spinlock_irqsave)(&info->slock); + return kfifo_put(&info->port.xmit_fifo, ch); } @@ -968,7 +951,7 @@ static int mxser_get_serial_info(struct tty_struct *tty, struct tty_port *port = &info->port; unsigned int closing_wait, close_delay; - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); close_delay = jiffies_to_msecs(info->port.close_delay) / 10; closing_wait = info->port.closing_wait; @@ -984,7 +967,7 @@ static int mxser_get_serial_info(struct tty_struct *tty, ss->close_delay = close_delay; ss->closing_wait = closing_wait; ss->custom_divisor = MXSER_CUSTOM_DIVISOR; - mutex_unlock(&port->mutex); + return 0; } @@ -994,20 +977,15 @@ static int mxser_set_serial_info(struct tty_struct *tty, struct mxser_port *info = tty->driver_data; struct tty_port *port = &info->port; speed_t baud; - unsigned long sl_flags; unsigned int old_speed, close_delay, closing_wait; - int retval = 0; if (tty_io_error(tty)) return -EIO; - mutex_lock(&port->mutex); + guard(mutex)(&port->mutex); - if (ss->irq != info->board->irq || - ss->port != info->ioaddr) { - mutex_unlock(&port->mutex); + if (ss->irq != info->board->irq || ss->port != info->ioaddr) return -EINVAL; - } old_speed = port->flags & ASYNC_SPD_MASK; @@ -1020,10 +998,9 @@ static int mxser_set_serial_info(struct tty_struct *tty, if ((ss->baud_base != MXSER_BAUD_BASE) || (close_delay != port->close_delay) || (closing_wait != port->closing_wait) || - ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { - mutex_unlock(&port->mutex); + ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) return -EPERM; - } + port->flags = (port->flags & ~ASYNC_USR_MASK) | (ss->flags & ASYNC_USR_MASK); } else { @@ -1039,10 +1016,9 @@ static int mxser_set_serial_info(struct tty_struct *tty, (ss->baud_base != MXSER_BAUD_BASE || ss->custom_divisor != MXSER_CUSTOM_DIVISOR)) { - if (ss->custom_divisor == 0) { - mutex_unlock(&port->mutex); + if (ss->custom_divisor == 0) return -EINVAL; - } + baud = ss->baud_base / ss->custom_divisor; tty_encode_baud_rate(tty, baud, baud); } @@ -1054,16 +1030,17 @@ static int mxser_set_serial_info(struct tty_struct *tty, if (tty_port_initialized(port)) { if (old_speed != (port->flags & ASYNC_SPD_MASK)) { - spin_lock_irqsave(&info->slock, sl_flags); + guard(spinlock_irqsave)(&info->slock); mxser_change_speed(tty, NULL); - spin_unlock_irqrestore(&info->slock, sl_flags); } - } else { - retval = mxser_activate(port, tty); - if (retval == 0) - tty_port_set_initialized(port, true); + + return 0; } - mutex_unlock(&port->mutex); + + int retval = mxser_activate(port, tty); + if (retval == 0) + tty_port_set_initialized(port, true); + return retval; } @@ -1080,13 +1057,11 @@ static int mxser_set_serial_info(struct tty_struct *tty, static int mxser_get_lsr_info(struct mxser_port *info, unsigned int __user *value) { - unsigned char status; unsigned int result; - unsigned long flags; + u8 status; - spin_lock_irqsave(&info->slock, flags); - status = inb(info->ioaddr + UART_LSR); - spin_unlock_irqrestore(&info->slock, flags); + scoped_guard(spinlock_irqsave, &info->slock) + status = inb(info->ioaddr + UART_LSR); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); return put_user(result, value); } @@ -1095,16 +1070,15 @@ static int mxser_tiocmget(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; unsigned char control; - unsigned long flags; u8 msr; if (tty_io_error(tty)) return -EIO; - spin_lock_irqsave(&info->slock, flags); - control = info->MCR; - msr = mxser_check_modem_status(tty, info); - spin_unlock_irqrestore(&info->slock, flags); + scoped_guard(spinlock_irqsave, &info->slock) { + control = info->MCR; + msr = mxser_check_modem_status(tty, info); + } return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | @@ -1118,12 +1092,11 @@ static int mxser_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct mxser_port *info = tty->driver_data; - unsigned long flags; if (tty_io_error(tty)) return -EIO; - spin_lock_irqsave(&info->slock, flags); + guard(spinlock_irqsave)(&info->slock); if (set & TIOCM_RTS) info->MCR |= UART_MCR_RTS; @@ -1136,7 +1109,7 @@ static int mxser_tiocmset(struct tty_struct *tty, info->MCR &= ~UART_MCR_DTR; outb(info->MCR, info->ioaddr + UART_MCR); - spin_unlock_irqrestore(&info->slock, flags); + return 0; } @@ -1144,12 +1117,11 @@ static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg, struct async_icount *cprev) { struct async_icount cnow; - unsigned long flags; int ret; - spin_lock_irqsave(&info->slock, flags); - cnow = info->icount; /* atomic copy */ - spin_unlock_irqrestore(&info->slock, flags); + /* atomic copy */ + scoped_guard(spinlock_irqsave, &info->slock) + cnow = info->icount; ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || @@ -1179,19 +1151,17 @@ static int mxser_ioctl_op_mode(struct mxser_port *port, int index, bool set, if (opmode & ~OP_MODE_MASK) return -EINVAL; - spin_lock_irq(&port->slock); + guard(spinlock_irq)(&port->slock); val = inb(port->opmode_ioaddr); val &= ~(OP_MODE_MASK << shiftbit); val |= (opmode << shiftbit); outb(val, port->opmode_ioaddr); - spin_unlock_irq(&port->slock); return 0; } - spin_lock_irq(&port->slock); - opmode = inb(port->opmode_ioaddr) >> shiftbit; - spin_unlock_irq(&port->slock); + scoped_guard(spinlock_irq, &port->slock) + opmode = inb(port->opmode_ioaddr) >> shiftbit; return put_user(opmode & OP_MODE_MASK, u_opmode); } @@ -1201,7 +1171,6 @@ static int mxser_ioctl(struct tty_struct *tty, { struct mxser_port *info = tty->driver_data; struct async_icount cnow; - unsigned long flags; void __user *argp = (void __user *)arg; if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) @@ -1221,9 +1190,9 @@ static int mxser_ioctl(struct tty_struct *tty, * Caller should use TIOCGICOUNT to see which one it was */ case TIOCMIWAIT: - spin_lock_irqsave(&info->slock, flags); - cnow = info->icount; /* note the counters on entry */ - spin_unlock_irqrestore(&info->slock, flags); + /* note the counters on entry */ + scoped_guard(spinlock_irqsave, &info->slock) + cnow = info->icount; return wait_event_interruptible(info->port.delta_msr_wait, mxser_cflags_changed(info, arg, &cnow)); @@ -1246,11 +1215,9 @@ static int mxser_get_icount(struct tty_struct *tty, { struct mxser_port *info = tty->driver_data; struct async_icount cnow; - unsigned long flags; - spin_lock_irqsave(&info->slock, flags); - cnow = info->icount; - spin_unlock_irqrestore(&info->slock, flags); + scoped_guard(spinlock_irqsave, &info->slock) + cnow = info->icount; icount->frame = cnow.frame; icount->brk = cnow.brk; @@ -1328,34 +1295,28 @@ static void mxser_unthrottle(struct tty_struct *tty) static void mxser_stop(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - unsigned long flags; - spin_lock_irqsave(&info->slock, flags); + guard(spinlock_irqsave)(&info->slock); if (info->IER & UART_IER_THRI) __mxser_stop_tx(info); - spin_unlock_irqrestore(&info->slock, flags); } static void mxser_start(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - unsigned long flags; - spin_lock_irqsave(&info->slock, flags); + guard(spinlock_irqsave)(&info->slock); if (!kfifo_is_empty(&info->port.xmit_fifo)) __mxser_start_tx(info); - spin_unlock_irqrestore(&info->slock, flags); } static void mxser_set_termios(struct tty_struct *tty, const struct ktermios *old_termios) { struct mxser_port *info = tty->driver_data; - unsigned long flags; - spin_lock_irqsave(&info->slock, flags); - mxser_change_speed(tty, old_termios); - spin_unlock_irqrestore(&info->slock, flags); + scoped_guard(spinlock_irqsave, &info->slock) + mxser_change_speed(tty, old_termios); if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { tty->hw_stopped = false; @@ -1367,9 +1328,8 @@ static void mxser_set_termios(struct tty_struct *tty, tty->flow.stopped = 0; if (info->board->must_hwid) { - spin_lock_irqsave(&info->slock, flags); + guard(spinlock_irqsave)(&info->slock); mxser_must_set_rx_sw_flow_control(info->ioaddr, false); - spin_unlock_irqrestore(&info->slock, flags); } mxser_start(tty); @@ -1378,14 +1338,8 @@ static void mxser_set_termios(struct tty_struct *tty, static bool mxser_tx_empty(struct mxser_port *info) { - unsigned long flags; - u8 lsr; - - spin_lock_irqsave(&info->slock, flags); - lsr = inb(info->ioaddr + UART_LSR); - spin_unlock_irqrestore(&info->slock, flags); - - return !(lsr & UART_LSR_TEMT); + guard(spinlock_irqsave)(&info->slock); + return !(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT); } /* @@ -1459,17 +1413,15 @@ static void mxser_hangup(struct tty_struct *tty) static int mxser_rs_break(struct tty_struct *tty, int break_state) { struct mxser_port *info = tty->driver_data; - unsigned long flags; u8 lcr; - spin_lock_irqsave(&info->slock, flags); + guard(spinlock_irqsave)(&info->slock); lcr = inb(info->ioaddr + UART_LCR); if (break_state == -1) lcr |= UART_LCR_SBC; else lcr &= ~UART_LCR_SBC; outb(lcr, info->ioaddr + UART_LCR); - spin_unlock_irqrestore(&info->slock, flags); return 0; } @@ -1672,12 +1624,11 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) port = &brd->ports[i]; int_cnt = 0; - spin_lock(&port->slock); + guard(spinlock)(&port->slock); do { if (mxser_port_isr(port)) break; } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); - spin_unlock(&port->slock); } } From 56609c0500514d35c7e35adca3bfe6f0061785bf Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:48 +0200 Subject: [PATCH 0254/2711] serial: serial_core: use guard()s Having all the new guards, use them in the serial_core code. This improves readability, makes error handling easier, and marks locked portions of code explicit. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-9-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 143 +++++++++++++------------------ 1 file changed, 59 insertions(+), 84 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 86d404d649a3..4757293ece8c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -177,15 +177,13 @@ static void uart_start(struct tty_struct *tty) static void uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) { - unsigned long flags; unsigned int old; - uart_port_lock_irqsave(port, &flags); + guard(uart_port_lock_irqsave)(port); old = port->mctrl; port->mctrl = (old & ~clear) | set; if (old != port->mctrl && !(port->rs485.flags & SER_RS485_ENABLED)) port->ops->set_mctrl(port, port->mctrl); - uart_port_unlock_irqrestore(port, flags); } #define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) @@ -220,7 +218,7 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state /* * Set modem status enables based on termios cflag */ - uart_port_lock_irq(uport); + guard(uart_port_lock_irq)(uport); if (termios->c_cflag & CRTSCTS) uport->status |= UPSTAT_CTS_ENABLE; else @@ -241,7 +239,6 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state else __uart_start(state); } - uart_port_unlock_irq(uport); } static int uart_alloc_xmit_buf(struct tty_port *port) @@ -711,7 +708,6 @@ static void uart_send_xchar(struct tty_struct *tty, u8 ch) { struct uart_state *state = tty->driver_data; struct uart_port *port; - unsigned long flags; port = uart_port_ref(state); if (!port) @@ -720,11 +716,10 @@ static void uart_send_xchar(struct tty_struct *tty, u8 ch) if (port->ops->send_xchar) port->ops->send_xchar(port, ch); else { - uart_port_lock_irqsave(port, &flags); + guard(uart_port_lock_irqsave)(port); port->x_char = ch; if (ch) port->ops->start_tx(port); - uart_port_unlock_irqrestore(port, flags); } uart_port_deref(port); } @@ -1089,7 +1084,6 @@ static int uart_tiocmget(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; struct uart_port *uport; - int result; guard(mutex)(&port->mutex); @@ -1097,12 +1091,9 @@ static int uart_tiocmget(struct tty_struct *tty) if (!uport || tty_io_error(tty)) return -EIO; - uart_port_lock_irq(uport); - result = uport->mctrl; - result |= uport->ops->get_mctrl(uport); - uart_port_unlock_irq(uport); + guard(uart_port_lock_irq)(uport); - return result; + return uport->mctrl | uport->ops->get_mctrl(uport); } static int @@ -1226,16 +1217,15 @@ static int uart_wait_modem_status(struct uart_state *state, unsigned long arg) uport = uart_port_ref(state); if (!uport) return -EIO; - uart_port_lock_irq(uport); - memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); - uart_enable_ms(uport); - uart_port_unlock_irq(uport); + scoped_guard(uart_port_lock_irq, uport) { + memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); + uart_enable_ms(uport); + } add_wait_queue(&port->delta_msr_wait, &wait); for (;;) { - uart_port_lock_irq(uport); - memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); - uart_port_unlock_irq(uport); + scoped_guard(uart_port_lock_irq, uport) + memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); set_current_state(TASK_INTERRUPTIBLE); @@ -1430,7 +1420,6 @@ static void uart_set_rs485_rx_during_tx(struct uart_port *port, static int uart_rs485_config(struct uart_port *port) { struct serial_rs485 *rs485 = &port->rs485; - unsigned long flags; int ret; if (!(rs485->flags & SER_RS485_ENABLED)) @@ -1440,9 +1429,8 @@ static int uart_rs485_config(struct uart_port *port) uart_set_rs485_termination(port, rs485); uart_set_rs485_rx_during_tx(port, rs485); - uart_port_lock_irqsave(port, &flags); - ret = port->rs485_config(port, NULL, rs485); - uart_port_unlock_irqrestore(port, flags); + scoped_guard(uart_port_lock_irqsave, port) + ret = port->rs485_config(port, NULL, rs485); if (ret) { memset(rs485, 0, sizeof(*rs485)); /* unset GPIOs */ @@ -1456,12 +1444,10 @@ static int uart_rs485_config(struct uart_port *port) static int uart_get_rs485_config(struct uart_port *port, struct serial_rs485 __user *rs485) { - unsigned long flags; struct serial_rs485 aux; - uart_port_lock_irqsave(port, &flags); - aux = port->rs485; - uart_port_unlock_irqrestore(port, flags); + scoped_guard(uart_port_lock_irqsave, port) + aux = port->rs485; if (copy_to_user(rs485, &aux, sizeof(aux))) return -EFAULT; @@ -1474,7 +1460,6 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, { struct serial_rs485 rs485; int ret; - unsigned long flags; if (!(port->rs485_supported.flags & SER_RS485_ENABLED)) return -ENOTTY; @@ -1489,16 +1474,16 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, uart_set_rs485_termination(port, &rs485); uart_set_rs485_rx_during_tx(port, &rs485); - uart_port_lock_irqsave(port, &flags); - ret = port->rs485_config(port, &tty->termios, &rs485); - if (!ret) { - port->rs485 = rs485; + scoped_guard(uart_port_lock_irqsave, port) { + ret = port->rs485_config(port, &tty->termios, &rs485); + if (!ret) { + port->rs485 = rs485; - /* Reset RTS and other mctrl lines when disabling RS485 */ - if (!(rs485.flags & SER_RS485_ENABLED)) - port->ops->set_mctrl(port, port->mctrl); + /* Reset RTS and other mctrl lines when disabling RS485 */ + if (!(rs485.flags & SER_RS485_ENABLED)) + port->ops->set_mctrl(port, port->mctrl); + } } - uart_port_unlock_irqrestore(port, flags); if (ret) { /* restore old GPIO settings */ gpiod_set_value_cansleep(port->rs485_term_gpio, @@ -1517,15 +1502,13 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, static int uart_get_iso7816_config(struct uart_port *port, struct serial_iso7816 __user *iso7816) { - unsigned long flags; struct serial_iso7816 aux; if (!port->iso7816_config) return -ENOTTY; - uart_port_lock_irqsave(port, &flags); - aux = port->iso7816; - uart_port_unlock_irqrestore(port, flags); + scoped_guard(uart_port_lock_irqsave, port) + aux = port->iso7816; if (copy_to_user(iso7816, &aux, sizeof(aux))) return -EFAULT; @@ -1537,8 +1520,7 @@ static int uart_set_iso7816_config(struct uart_port *port, struct serial_iso7816 __user *iso7816_user) { struct serial_iso7816 iso7816; - int i, ret; - unsigned long flags; + int i; if (!port->iso7816_config) return -ENOTTY; @@ -1554,11 +1536,11 @@ static int uart_set_iso7816_config(struct uart_port *port, if (iso7816.reserved[i]) return -EINVAL; - uart_port_lock_irqsave(port, &flags); - ret = port->iso7816_config(port, &iso7816); - uart_port_unlock_irqrestore(port, flags); - if (ret) - return ret; + scoped_guard(uart_port_lock_irqsave, port) { + int ret = port->iso7816_config(port, &iso7816); + if (ret) + return ret; + } if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816))) return -EFAULT; @@ -1770,9 +1752,8 @@ static void uart_tty_port_shutdown(struct tty_port *port) if (WARN(!uport, "detached port still initialized!\n")) return; - uart_port_lock_irq(uport); - uport->ops->stop_rx(uport); - uart_port_unlock_irq(uport); + scoped_guard(uart_port_lock_irq, uport) + uport->ops->stop_rx(uport); serial_base_port_shutdown(uport); uart_port_shutdown(port); @@ -2044,9 +2025,8 @@ static void uart_line_info(struct seq_file *m, struct uart_state *state) pm_state = state->pm_state; if (pm_state != UART_PM_STATE_ON) uart_change_pm(state, UART_PM_STATE_ON); - uart_port_lock_irq(uport); - status = uport->ops->get_mctrl(uport); - uart_port_unlock_irq(uport); + scoped_guard(uart_port_lock_irq, uport) + status = uport->ops->get_mctrl(uport); if (pm_state != UART_PM_STATE_ON) uart_change_pm(state, pm_state); @@ -2355,9 +2335,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) */ if (!console_suspend_enabled && uart_console(uport)) { if (uport->ops->start_rx) { - uart_port_lock_irq(uport); + guard(uart_port_lock_irq)(uport); uport->ops->stop_rx(uport); - uart_port_unlock_irq(uport); } device_set_awake_path(uport->dev); return 0; @@ -2373,15 +2352,15 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) tty_port_set_suspended(port, true); tty_port_set_initialized(port, false); - uart_port_lock_irq(uport); - ops->stop_tx(uport); - if (!(uport->rs485.flags & SER_RS485_ENABLED)) - ops->set_mctrl(uport, 0); - /* save mctrl so it can be restored on resume */ - mctrl = uport->mctrl; - uport->mctrl = 0; - ops->stop_rx(uport); - uart_port_unlock_irq(uport); + scoped_guard(uart_port_lock_irq, uport) { + ops->stop_tx(uport); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, 0); + /* save mctrl so it can be restored on resume */ + mctrl = uport->mctrl; + uport->mctrl = 0; + ops->stop_rx(uport); + } /* * Wait for the transmitter to empty. @@ -2450,9 +2429,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) uart_change_pm(state, UART_PM_STATE_ON); uport->ops->set_termios(uport, &termios, NULL); if (!console_suspend_enabled && uport->ops->start_rx) { - uart_port_lock_irq(uport); + guard(uart_port_lock_irq)(uport); uport->ops->start_rx(uport); - uart_port_unlock_irq(uport); } if (console_suspend_enabled) console_resume(uport->cons); @@ -2463,10 +2441,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) int ret; uart_change_pm(state, UART_PM_STATE_ON); - uart_port_lock_irq(uport); - if (!(uport->rs485.flags & SER_RS485_ENABLED)) - ops->set_mctrl(uport, 0); - uart_port_unlock_irq(uport); + scoped_guard(uart_port_lock_irq, uport) + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, 0); if (console_suspend_enabled || !uart_console(uport)) { /* Protected by port mutex for now */ struct tty_struct *tty = port->tty; @@ -2476,11 +2453,11 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) if (tty) uart_change_line_settings(tty, state, NULL); uart_rs485_config(uport); - uart_port_lock_irq(uport); - if (!(uport->rs485.flags & SER_RS485_ENABLED)) - ops->set_mctrl(uport, uport->mctrl); - ops->start_tx(uport); - uart_port_unlock_irq(uport); + scoped_guard(uart_port_lock_irq, uport) { + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, uport->mctrl); + ops->start_tx(uport); + } tty_port_set_initialized(port, true); } else { /* @@ -2574,8 +2551,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, } if (port->type != PORT_UNKNOWN) { - unsigned long flags; - uart_report_port(drv, port); /* Synchronize with possible boot console. */ @@ -2590,11 +2565,11 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, * keep the DTR setting that is set in uart_set_options() * We probably don't need a spinlock around this, but */ - uart_port_lock_irqsave(port, &flags); - port->mctrl &= TIOCM_DTR; - if (!(port->rs485.flags & SER_RS485_ENABLED)) - port->ops->set_mctrl(port, port->mctrl); - uart_port_unlock_irqrestore(port, flags); + scoped_guard(uart_port_lock_irqsave, port) { + port->mctrl &= TIOCM_DTR; + if (!(port->rs485.flags & SER_RS485_ENABLED)) + port->ops->set_mctrl(port, port->mctrl); + } uart_rs485_config(port); From b339809edda15939e7d46b429c420c2bfe4ad946 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:49 +0200 Subject: [PATCH 0255/2711] serial: 8250: use guard()s Having all the new guards, use them in the 8250 code. This improves readability, makes error handling easier, and marks locked portions of code explicit. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-10-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 71 +++---- drivers/tty/serial/8250/8250_port.c | 294 +++++++++++----------------- 2 files changed, 144 insertions(+), 221 deletions(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index feb920c5b2e8..82c3636451e5 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -72,7 +72,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) struct list_head *l, *end = NULL; int pass_counter = 0, handled = 0; - spin_lock(&i->lock); + guard(spinlock)(&i->lock); l = i->head; do { @@ -91,8 +91,6 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) break; } while (l != end); - spin_unlock(&i->lock); - return IRQ_RETVAL(handled); } @@ -132,22 +130,19 @@ static struct irq_info *serial_get_or_create_irq_info(const struct uart_8250_por { struct irq_info *i; - mutex_lock(&hash_mutex); + guard(mutex)(&hash_mutex); hash_for_each_possible(irq_lists, i, node, up->port.irq) if (i->irq == up->port.irq) - goto unlock; + return i; i = kzalloc(sizeof(*i), GFP_KERNEL); - if (i == NULL) { - i = ERR_PTR(-ENOMEM); - goto unlock; - } + if (i == NULL) + return ERR_PTR(-ENOMEM); + spin_lock_init(&i->lock); i->irq = up->port.irq; hash_add(irq_lists, &i->node, i->irq); -unlock: - mutex_unlock(&hash_mutex); return i; } @@ -161,23 +156,21 @@ static int serial_link_irq_chain(struct uart_8250_port *up) if (IS_ERR(i)) return PTR_ERR(i); - spin_lock_irq(&i->lock); + scoped_guard(spinlock_irq, &i->lock) { + if (i->head) { + list_add(&up->list, i->head); - if (i->head) { - list_add(&up->list, i->head); - spin_unlock_irq(&i->lock); + return 0; + } - ret = 0; - } else { INIT_LIST_HEAD(&up->list); i->head = &up->list; - spin_unlock_irq(&i->lock); - ret = request_irq(up->port.irq, serial8250_interrupt, - up->port.irqflags, up->port.name, i); - if (ret < 0) - serial_do_unlink(i, up); } + ret = request_irq(up->port.irq, serial8250_interrupt, up->port.irqflags, up->port.name, i); + if (ret < 0) + serial_do_unlink(i, up); + return ret; } @@ -670,16 +663,12 @@ static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_ static void serial_8250_overrun_backoff_work(struct work_struct *work) { - struct uart_8250_port *up = - container_of(to_delayed_work(work), struct uart_8250_port, - overrun_backoff); - struct uart_port *port = &up->port; - unsigned long flags; + struct uart_8250_port *up = container_of(to_delayed_work(work), struct uart_8250_port, + overrun_backoff); - uart_port_lock_irqsave(port, &flags); + guard(uart_port_lock_irqsave)(&up->port); up->ier |= UART_IER_RLSI | UART_IER_RDI; serial_out(up, UART_IER, up->ier); - uart_port_unlock_irqrestore(port, flags); } /** @@ -698,12 +687,12 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work) int serial8250_register_8250_port(const struct uart_8250_port *up) { struct uart_8250_port *uart; - int ret = -ENOSPC; + int ret; if (up->port.uartclk == 0) return -EINVAL; - mutex_lock(&serial_mutex); + guard(mutex)(&serial_mutex); uart = serial8250_find_match_or_unused(&up->port); if (!uart) { @@ -713,15 +702,13 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) */ uart = serial8250_setup_port(nr_uarts); if (!uart) - goto unlock; + return -ENOSPC; nr_uarts++; } /* Check if it is CIR already. We check this below again, see there why. */ - if (uart->port.type == PORT_8250_CIR) { - ret = -ENODEV; - goto unlock; - } + if (uart->port.type == PORT_8250_CIR) + return -ENODEV; if (uart->port.dev) uart_remove_one_port(&serial8250_reg, &uart->port); @@ -855,14 +842,10 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) uart->overrun_backoff_time_ms = 0; } -unlock: - mutex_unlock(&serial_mutex); - return ret; err: uart->port.dev = NULL; - mutex_unlock(&serial_mutex); return ret; } EXPORT_SYMBOL(serial8250_register_8250_port); @@ -878,14 +861,11 @@ void serial8250_unregister_port(int line) { struct uart_8250_port *uart = &serial8250_ports[line]; - mutex_lock(&serial_mutex); + guard(mutex)(&serial_mutex); if (uart->em485) { - unsigned long flags; - - uart_port_lock_irqsave(&uart->port, &flags); + guard(uart_port_lock_irqsave)(&uart->port); serial8250_em485_destroy(uart); - uart_port_unlock_irqrestore(&uart->port, flags); } uart_remove_one_port(&serial8250_reg, &uart->port); @@ -901,7 +881,6 @@ void serial8250_unregister_port(int line) } else { uart->port.dev = NULL; } - mutex_unlock(&serial_mutex); } EXPORT_SYMBOL(serial8250_unregister_port); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 5afae4025696..719faf92aa8a 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -674,28 +674,27 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { unsigned char lcr = 0, efr = 0; - serial8250_rpm_get(p); + guard(serial8250_rpm)(p); - if (p->capabilities & UART_CAP_SLEEP) { - /* Synchronize UART_IER access against the console. */ - uart_port_lock_irq(&p->port); - if (p->capabilities & UART_CAP_EFR) { - lcr = serial_in(p, UART_LCR); - efr = serial_in(p, UART_EFR); - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, UART_EFR_ECB); - serial_out(p, UART_LCR, 0); - } - serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); - if (p->capabilities & UART_CAP_EFR) { - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, efr); - serial_out(p, UART_LCR, lcr); - } - uart_port_unlock_irq(&p->port); + if (!(p->capabilities & UART_CAP_SLEEP)) + return; + + /* Synchronize UART_IER access against the console. */ + guard(uart_port_lock_irq)(&p->port); + + if (p->capabilities & UART_CAP_EFR) { + lcr = serial_in(p, UART_LCR); + efr = serial_in(p, UART_EFR); + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, UART_EFR_ECB); + serial_out(p, UART_LCR, 0); + } + serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, efr); + serial_out(p, UART_LCR, lcr); } - - serial8250_rpm_put(p); } /* Clear the interrupt registers. */ @@ -1231,9 +1230,8 @@ static void autoconfig_irq(struct uart_8250_port *up) probe_irq_off(probe_irq_on()); save_mcr = serial8250_in_MCR(up); /* Synchronize UART_IER access against the console. */ - uart_port_lock_irq(port); - save_ier = serial_in(up, UART_IER); - uart_port_unlock_irq(port); + scoped_guard(uart_port_lock_irq, port) + save_ier = serial_in(up, UART_IER); serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2); irqs = probe_irq_on(); @@ -1246,9 +1244,8 @@ static void autoconfig_irq(struct uart_8250_port *up) UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); } /* Synchronize UART_IER access against the console. */ - uart_port_lock_irq(port); - serial_out(up, UART_IER, UART_IER_ALL_INTR); - uart_port_unlock_irq(port); + scoped_guard(uart_port_lock_irq, port) + serial_out(up, UART_IER, UART_IER_ALL_INTR); serial8250_clear_interrupts(port); serial_out(up, UART_TX, 0xFF); udelay(20); @@ -1256,9 +1253,8 @@ static void autoconfig_irq(struct uart_8250_port *up) serial8250_out_MCR(up, save_mcr); /* Synchronize UART_IER access against the console. */ - uart_port_lock_irq(port); - serial_out(up, UART_IER, save_ier); - uart_port_unlock_irq(port); + scoped_guard(uart_port_lock_irq, port) + serial_out(up, UART_IER, save_ier); if (port->flags & UPF_FOURPORT) outb_p(save_ICP, ICP); @@ -1273,12 +1269,10 @@ static void serial8250_stop_rx(struct uart_port *port) /* Port locked to synchronize UART_IER access against the console. */ lockdep_assert_held_once(&port->lock); - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); serial_port_out(port, UART_IER, up->ier); - - serial8250_rpm_put(up); } /** @@ -1322,17 +1316,15 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) struct uart_8250_em485 *em485 = container_of(t, struct uart_8250_em485, stop_tx_timer); struct uart_8250_port *p = em485->port; - unsigned long flags; - serial8250_rpm_get(p); - uart_port_lock_irqsave(&p->port, &flags); + guard(serial8250_rpm)(p); + guard(uart_port_lock_irqsave)(&p->port); + if (em485->active_timer == &em485->stop_tx_timer) { p->rs485_stop_tx(p, true); em485->active_timer = NULL; em485->tx_stopped = true; } - uart_port_unlock_irqrestore(&p->port, flags); - serial8250_rpm_put(p); return HRTIMER_NORESTART; } @@ -1407,7 +1399,7 @@ static void serial8250_stop_tx(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); __stop_tx(up); /* @@ -1417,7 +1409,6 @@ static void serial8250_stop_tx(struct uart_port *port) up->acr |= UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); } - serial8250_rpm_put(up); } static inline void __start_tx(struct uart_port *port) @@ -1512,14 +1503,13 @@ static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t) struct uart_8250_em485 *em485 = container_of(t, struct uart_8250_em485, start_tx_timer); struct uart_8250_port *p = em485->port; - unsigned long flags; - uart_port_lock_irqsave(&p->port, &flags); + guard(uart_port_lock_irqsave)(&p->port); + if (em485->active_timer == &em485->start_tx_timer) { __start_tx(&p->port); em485->active_timer = NULL; } - uart_port_unlock_irqrestore(&p->port, flags); return HRTIMER_NORESTART; } @@ -1587,9 +1577,8 @@ static void serial8250_enable_ms(struct uart_port *port) up->ier |= UART_IER_MSI; - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); serial_port_out(port, UART_IER, up->ier); - serial8250_rpm_put(up); } void serial8250_read_char(struct uart_8250_port *up, u16 lsr) @@ -1850,15 +1839,11 @@ static int serial8250_default_handle_irq(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned int iir; - int ret; - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); iir = serial_port_in(port, UART_IIR); - ret = serial8250_handle_irq(port, iir); - - serial8250_rpm_put(up); - return ret; + return serial8250_handle_irq(port, iir); } /* @@ -1869,16 +1854,14 @@ static int serial8250_default_handle_irq(struct uart_port *port) */ static int serial8250_tx_threshold_handle_irq(struct uart_port *port) { - unsigned long flags; unsigned int iir = serial_port_in(port, UART_IIR); /* TX Threshold IRQ triggered so load up FIFO */ if ((iir & UART_IIR_ID) == UART_IIR_THRI) { struct uart_8250_port *up = up_to_u8250p(port); - uart_port_lock_irqsave(port, &flags); + guard(uart_port_lock_irqsave)(port); serial8250_tx_chars(up); - uart_port_unlock_irqrestore(port, flags); } iir = serial_port_in(port, UART_IIR); @@ -1888,19 +1871,14 @@ static int serial8250_tx_threshold_handle_irq(struct uart_port *port) static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned int result = 0; - unsigned long flags; - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); + guard(uart_port_lock_irqsave)(port); - uart_port_lock_irqsave(port, &flags); if (!serial8250_tx_dma_running(up) && uart_lsr_tx_empty(serial_lsr_in(up))) - result = TIOCSER_TEMT; - uart_port_unlock_irqrestore(port, flags); + return TIOCSER_TEMT; - serial8250_rpm_put(up); - - return result; + return 0; } unsigned int serial8250_do_get_mctrl(struct uart_port *port) @@ -1909,9 +1887,8 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port) unsigned int status; unsigned int val; - serial8250_rpm_get(up); - status = serial8250_modem_status(up); - serial8250_rpm_put(up); + scoped_guard(serial8250_rpm, up) + status = serial8250_modem_status(up); val = serial8250_MSR_to_TIOCM(status); if (up->gpios) @@ -1955,17 +1932,15 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) static void serial8250_break_ctl(struct uart_port *port, int break_state) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - serial8250_rpm_get(up); - uart_port_lock_irqsave(port, &flags); + guard(serial8250_rpm)(up); + guard(uart_port_lock_irqsave)(port); + if (break_state == -1) up->lcr |= UART_LCR_SBC; else up->lcr &= ~UART_LCR_SBC; serial_port_out(port, UART_LCR, up->lcr); - uart_port_unlock_irqrestore(port, flags); - serial8250_rpm_put(up); } /* Returns true if @bits were set, false on timeout */ @@ -2025,22 +2000,15 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) static int serial8250_get_poll_char(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - int status; u16 lsr; - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); lsr = serial_port_in(port, UART_LSR); + if (!(lsr & UART_LSR_DR)) + return NO_POLL_CHAR; - if (!(lsr & UART_LSR_DR)) { - status = NO_POLL_CHAR; - goto out; - } - - status = serial_port_in(port, UART_RX); -out: - serial8250_rpm_put(up); - return status; + return serial_port_in(port, UART_RX); } @@ -2058,7 +2026,7 @@ static void serial8250_put_poll_char(struct uart_port *port, * should allow safe lockless usage here. */ - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); /* * First save the IER then disable the interrupts */ @@ -2077,7 +2045,6 @@ static void serial8250_put_poll_char(struct uart_port *port, */ wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); serial_port_out(port, UART_IER, ier); - serial8250_rpm_put(up); } #endif /* CONFIG_CONSOLE_POLL */ @@ -2085,16 +2052,15 @@ static void serial8250_put_poll_char(struct uart_port *port, static void serial8250_startup_special(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; switch (port->type) { - case PORT_16C950: + case PORT_16C950: { /* * Wake up and initialize UART * * Synchronize UART_IER access against the console. */ - uart_port_lock_irqsave(port, &flags); + guard(uart_port_lock_irqsave)(port); up->acr = 0; serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); serial_port_out(port, UART_EFR, UART_EFR_ECB); @@ -2104,18 +2070,18 @@ static void serial8250_startup_special(struct uart_port *port) serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); serial_port_out(port, UART_EFR, UART_EFR_ECB); serial_port_out(port, UART_LCR, 0); - uart_port_unlock_irqrestore(port, flags); break; + } case PORT_DA830: /* * Reset the port * * Synchronize UART_IER access against the console. */ - uart_port_lock_irqsave(port, &flags); - serial_port_out(port, UART_IER, 0); - serial_port_out(port, UART_DA830_PWREMU_MGMT, 0); - uart_port_unlock_irqrestore(port, flags); + scoped_guard(uart_port_lock_irqsave, port) { + serial_port_out(port, UART_IER, 0); + serial_port_out(port, UART_DA830_PWREMU_MGMT, 0); + } mdelay(10); /* Enable Tx, Rx and free run mode */ @@ -2173,7 +2139,6 @@ static void serial8250_set_TRG_levels(struct uart_port *port) static void serial8250_THRE_test(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; bool iir_noint1, iir_noint2; if (!port->irq) @@ -2193,19 +2158,17 @@ static void serial8250_THRE_test(struct uart_port *port) * * Synchronize UART_IER access against the console. */ - uart_port_lock_irqsave(port, &flags); - - wait_for_xmitr(up, UART_LSR_THRE); - serial_port_out_sync(port, UART_IER, UART_IER_THRI); - udelay(1); /* allow THRE to set */ - iir_noint1 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT; - serial_port_out(port, UART_IER, 0); - serial_port_out_sync(port, UART_IER, UART_IER_THRI); - udelay(1); /* allow a working UART time to re-assert THRE */ - iir_noint2 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT; - serial_port_out(port, UART_IER, 0); - - uart_port_unlock_irqrestore(port, flags); + scoped_guard(uart_port_lock_irqsave, port) { + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow THRE to set */ + iir_noint1 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT; + serial_port_out(port, UART_IER, 0); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow a working UART time to re-assert THRE */ + iir_noint2 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT; + serial_port_out(port, UART_IER, 0); + } if (port->irqflags & IRQF_SHARED) enable_irq(port->irq); @@ -2269,14 +2232,11 @@ static void serial8250_iir_txen_test(struct uart_port *port) static void serial8250_initialize(struct uart_port *port) { - unsigned long flags; - - uart_port_lock_irqsave(port, &flags); + guard(uart_port_lock_irqsave)(port); serial_port_out(port, UART_LCR, UART_LCR_WLEN8); serial8250_init_mctrl(port); serial8250_iir_txen_test(port); - uart_port_unlock_irqrestore(port, flags); } int serial8250_do_startup(struct uart_port *port) @@ -2295,7 +2255,7 @@ int serial8250_do_startup(struct uart_port *port) if (port->iotype != up->cur_iotype) set_io_from_upio(port); - serial8250_rpm_get(up); + guard(serial8250_rpm)(up); serial8250_startup_special(port); @@ -2315,8 +2275,7 @@ int serial8250_do_startup(struct uart_port *port) if (!(port->flags & UPF_BUGGY_UART) && (serial_port_in(port, UART_LSR) == 0xff)) { dev_info_ratelimited(port->dev, "LSR safety check engaged!\n"); - retval = -ENODEV; - goto out; + return -ENODEV; } serial8250_set_TRG_levels(port); @@ -2327,7 +2286,7 @@ int serial8250_do_startup(struct uart_port *port) retval = up->ops->setup_irq(up); if (retval) - goto out; + return retval; serial8250_THRE_test(port); @@ -2376,10 +2335,8 @@ int serial8250_do_startup(struct uart_port *port) outb_p(0x80, icp); inb_p(icp); } - retval = 0; -out: - serial8250_rpm_put(up); - return retval; + + return 0; } EXPORT_SYMBOL_GPL(serial8250_do_startup); @@ -2393,7 +2350,6 @@ static int serial8250_startup(struct uart_port *port) void serial8250_do_shutdown(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; serial8250_rpm_get(up); /* @@ -2401,26 +2357,26 @@ void serial8250_do_shutdown(struct uart_port *port) * * Synchronize UART_IER access against the console. */ - uart_port_lock_irqsave(port, &flags); - up->ier = 0; - serial_port_out(port, UART_IER, 0); - uart_port_unlock_irqrestore(port, flags); + scoped_guard(uart_port_lock_irqsave, port) { + up->ier = 0; + serial_port_out(port, UART_IER, 0); + } synchronize_irq(port->irq); if (up->dma) serial8250_release_dma(up); - uart_port_lock_irqsave(port, &flags); - if (port->flags & UPF_FOURPORT) { - /* reset interrupts on the AST Fourport board */ - inb((port->iobase & 0xfe0) | 0x1f); - port->mctrl |= TIOCM_OUT1; - } else - port->mctrl &= ~TIOCM_OUT2; + scoped_guard(uart_port_lock_irqsave, port) { + if (port->flags & UPF_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + inb((port->iobase & 0xfe0) | 0x1f); + port->mctrl |= TIOCM_OUT1; + } else + port->mctrl &= ~TIOCM_OUT2; - serial8250_set_mctrl(port, port->mctrl); - uart_port_unlock_irqrestore(port, flags); + serial8250_set_mctrl(port, port->mctrl); + } /* * Disable break condition and FIFOs @@ -2612,33 +2568,27 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) { struct tty_port *tport = &port->state->port; - struct tty_struct *tty; - tty = tty_port_tty_get(tport); - if (!tty) { - mutex_lock(&tport->mutex); + scoped_guard(tty_port_tty, tport) { + struct tty_struct *tty = scoped_tty(); + + guard(rwsem_write)(&tty->termios_rwsem); + guard(mutex)(&tport->mutex); + + if (port->uartclk == uartclk) + return; + port->uartclk = uartclk; - mutex_unlock(&tport->mutex); + + if (!tty_port_initialized(tport)) + return; + + serial8250_do_set_termios(port, &tty->termios, NULL); + return; } - - down_write(&tty->termios_rwsem); - mutex_lock(&tport->mutex); - - if (port->uartclk == uartclk) - goto out_unlock; - + guard(mutex)(&tport->mutex); port->uartclk = uartclk; - - if (!tty_port_initialized(tport)) - goto out_unlock; - - serial8250_do_set_termios(port, &tty->termios, NULL); - -out_unlock: - mutex_unlock(&tport->mutex); - up_write(&tty->termios_rwsem); - tty_kref_put(tty); } EXPORT_SYMBOL_GPL(serial8250_update_uartclk); @@ -2793,7 +2743,6 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) { struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; unsigned int baud, quot, frac = 0; u8 lcr; @@ -2803,27 +2752,24 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, quot = serial8250_get_divisor(port, baud, &frac); /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. + * Ok, we're now changing the port state. Do it with interrupts disabled. * * Synchronize UART_IER access against the console. */ - serial8250_rpm_get(up); - uart_port_lock_irqsave(port, &flags); + scoped_guard(serial8250_rpm, up) { + guard(uart_port_lock_irqsave)(port); - up->lcr = lcr; - serial8250_set_trigger_for_slow_speed(port, termios, baud); - serial8250_set_afe(port, termios); - uart_update_timeout(port, termios->c_cflag, baud); - serial8250_set_errors_and_ignores(port, termios); - serial8250_set_ier(port, termios); - serial8250_set_efr(port, termios); - serial8250_set_divisor(port, baud, quot, frac); - serial8250_set_fcr(port, termios); - serial8250_set_mctrl(port, port->mctrl); - - uart_port_unlock_irqrestore(port, flags); - serial8250_rpm_put(up); + up->lcr = lcr; + serial8250_set_trigger_for_slow_speed(port, termios, baud); + serial8250_set_afe(port, termios); + uart_update_timeout(port, termios->c_cflag, baud); + serial8250_set_errors_and_ignores(port, termios); + serial8250_set_ier(port, termios); + serial8250_set_efr(port, termios); + serial8250_set_divisor(port, baud, quot, frac); + serial8250_set_fcr(port, termios); + serial8250_set_mctrl(port, port->mctrl); + } /* Don't rewrite B0 */ if (tty_termios_baud_rate(termios)) @@ -2845,15 +2791,13 @@ void serial8250_do_set_ldisc(struct uart_port *port, struct ktermios *termios) { if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; - uart_port_lock_irq(port); + guard(uart_port_lock_irq)(port); serial8250_enable_ms(port); - uart_port_unlock_irq(port); } else { port->flags &= ~UPF_HARDPPS_CD; if (!UART_ENABLE_MS(port, termios->c_cflag)) { - uart_port_lock_irq(port); + guard(uart_port_lock_irq)(port); serial8250_disable_ms(port); - uart_port_unlock_irq(port); } } } From 9a2225f2a7214cc04a03a09768b19215a3fe4c16 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:50 +0200 Subject: [PATCH 0256/2711] serial: 8250_core: use guard() in serial_unlink_irq_chain() Having all the new guards, use them in the 8250 code. This improves readability, makes error handling easier, and marks locked portions of code explicit. serial_unlink_irq_chain() is done separately here because with the guard() used, those BUG_ON()s can be switched WARN_ON()s as we can actually handle the conditions and return (despite something went really wrong). Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-11-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 82c3636451e5..7d931693b311 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -178,20 +178,22 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up) { struct irq_info *i; - mutex_lock(&hash_mutex); + guard(mutex)(&hash_mutex); hash_for_each_possible(irq_lists, i, node, up->port.irq) - if (i->irq == up->port.irq) - break; + if (i->irq == up->port.irq) { + if (WARN_ON(i->head == NULL)) + return; - BUG_ON(i == NULL); - BUG_ON(i->head == NULL); + if (list_empty(i->head)) + free_irq(up->port.irq, i); - if (list_empty(i->head)) - free_irq(up->port.irq, i); + serial_do_unlink(i, up); - serial_do_unlink(i, up); - mutex_unlock(&hash_mutex); + return; + } + + WARN_ON(1); } /* From 302c8145e68f4bef1770472fa5114e923472db7b Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:51 +0200 Subject: [PATCH 0257/2711] serial: 8250_omap: extract omap_8250_set_termios_atomic() To use guard()s easily in omap_8250_set_termios(), split it into atomic and non-atomic part. The former can be easily guarded -- without a need of indenting or moving code. omap_8250_set_termios() would likely profit from a cleanup similar to one in serial8250_do_set_termios() in commit cdc4a3e0b235 ("serial: 8250: extract serial8250_set_fcr()") and earlier. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-12-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 39 ++++++++++++++++++----------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 6707f55bdbe7..ba03955fdc6e 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -369,18 +369,12 @@ static void omap8250_restore_regs(struct uart_8250_port *up) serial8250_em485_stop_tx(up, true); } -/* - * OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have - * some differences in how we want to handle flow control. - */ -static void omap_8250_set_termios(struct uart_port *port, - struct ktermios *termios, - const struct ktermios *old) +static void omap_8250_set_termios_atomic(struct uart_port *port, struct ktermios *termios, + const struct ktermios *old, unsigned int baud) { struct uart_8250_port *up = up_to_u8250p(port); struct omap8250_priv *priv = port->private_data; - unsigned char cval = 0; - unsigned int baud; + u8 cval; cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag)); @@ -393,12 +387,6 @@ static void omap_8250_set_termios(struct uart_port *port, if (termios->c_cflag & CMSPAR) cval |= UART_LCR_SPAR; - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, - port->uartclk / 16 / UART_DIV_MAX, - port->uartclk / 13); omap_8250_get_divisor(port, baud, priv); /* @@ -518,6 +506,27 @@ static void omap_8250_set_termios(struct uart_port *port, uart_port_unlock_irq(&up->port); pm_runtime_mark_last_busy(port->dev); pm_runtime_put_autosuspend(port->dev); +} + +/* + * OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have + * some differences in how we want to handle flow control. + */ +static void omap_8250_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) +{ + struct omap8250_priv *priv = port->private_data; + unsigned int baud; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / UART_DIV_MAX, + port->uartclk / 13); + + omap_8250_set_termios_atomic(port, termios, old, baud); /* calculate wakeup latency constraint */ priv->calc_latency = USEC_PER_SEC * 64 * 8 / baud; From 7345b07f3c03778bb480736062cdba09d902fd99 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:52 +0200 Subject: [PATCH 0258/2711] serial: 8250_omap: use guard()s Having all the new guards, use them in the 8250_omap code. This improves readability, makes error handling easier, and marks locked portions of code explicit. For this to work, UART_CAP_RPM has to be set to up->capabilities a bit earlier. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-13-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 110 ++++++++++------------------ 1 file changed, 38 insertions(+), 72 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index ba03955fdc6e..bb23afdd63f2 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -393,8 +393,8 @@ static void omap_8250_set_termios_atomic(struct uart_port *port, struct ktermios * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - pm_runtime_get_sync(port->dev); - uart_port_lock_irq(port); + guard(serial8250_rpm)(up); + guard(uart_port_lock_irq)(port); /* * Update the per-port timeout. @@ -502,10 +502,6 @@ static void omap_8250_set_termios_atomic(struct uart_port *port, struct ktermios } } omap8250_restore_regs(up); - - uart_port_unlock_irq(&up->port); - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); } /* @@ -546,10 +542,9 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, struct uart_8250_port *up = up_to_u8250p(port); u8 efr; - pm_runtime_get_sync(port->dev); - + guard(serial8250_rpm)(up); /* Synchronize UART_IER access against the console. */ - uart_port_lock_irq(port); + guard(uart_port_lock_irq)(port); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); efr = serial_in(up, UART_EFR); @@ -560,11 +555,6 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(up, UART_EFR, efr); serial_out(up, UART_LCR, 0); - - uart_port_unlock_irq(port); - - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); } static void omap_serial_fill_features_erratas(struct uart_8250_port *up, @@ -736,7 +726,11 @@ static int omap_8250_startup(struct uart_port *port) return ret; } - pm_runtime_get_sync(port->dev); +#ifdef CONFIG_PM + up->capabilities |= UART_CAP_RPM; +#endif + + guard(serial8250_rpm)(up); serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); @@ -759,14 +753,10 @@ static int omap_8250_startup(struct uart_port *port) } /* Synchronize UART_IER access against the console. */ - uart_port_lock_irq(port); - up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_out(up, UART_IER, up->ier); - uart_port_unlock_irq(port); - -#ifdef CONFIG_PM - up->capabilities |= UART_CAP_RPM; -#endif + scoped_guard(uart_port_lock_irq, port) { + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); + } /* Enable module level wake up */ priv->wer = OMAP_UART_WER_MOD_WKUP; @@ -775,15 +765,12 @@ static int omap_8250_startup(struct uart_port *port) serial_out(up, UART_OMAP_WER, priv->wer); if (up->dma && !(priv->habit & UART_HAS_EFR2)) { - uart_port_lock_irq(port); + guard(uart_port_lock_irq)(port); up->dma->rx_dma(up); - uart_port_unlock_irq(port); } enable_irq(port->irq); - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); return 0; } @@ -792,7 +779,7 @@ static void omap_8250_shutdown(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); struct omap8250_priv *priv = port->private_data; - pm_runtime_get_sync(port->dev); + guard(serial8250_rpm)(up); flush_work(&priv->qos_work); if (up->dma) @@ -803,10 +790,11 @@ static void omap_8250_shutdown(struct uart_port *port) serial_out(up, UART_OMAP_EFR2, 0x0); /* Synchronize UART_IER access against the console. */ - uart_port_lock_irq(port); - up->ier = 0; - serial_out(up, UART_IER, 0); - uart_port_unlock_irq(port); + scoped_guard(uart_port_lock_irq, port) { + up->ier = 0; + serial_out(up, UART_IER, 0); + } + disable_irq_nosync(port->irq); dev_pm_clear_wake_irq(port->dev); @@ -819,46 +807,33 @@ static void omap_8250_shutdown(struct uart_port *port) if (up->lcr & UART_LCR_SBC) serial_out(up, UART_LCR, up->lcr & ~UART_LCR_SBC); serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); } static void omap_8250_throttle(struct uart_port *port) { struct omap8250_priv *priv = port->private_data; - unsigned long flags; - pm_runtime_get_sync(port->dev); + guard(serial8250_rpm)(up_to_u8250p(port)); + guard(uart_port_lock_irqsave)(port); - uart_port_lock_irqsave(port, &flags); port->ops->stop_rx(port); priv->throttled = true; - uart_port_unlock_irqrestore(port, flags); - - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); } static void omap_8250_unthrottle(struct uart_port *port) { struct omap8250_priv *priv = port->private_data; struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - - pm_runtime_get_sync(port->dev); + guard(serial8250_rpm)(up); /* Synchronize UART_IER access against the console. */ - uart_port_lock_irqsave(port, &flags); + guard(uart_port_lock_irqsave)(port); + priv->throttled = false; if (up->dma) up->dma->rx_dma(up); up->ier |= UART_IER_RLSI | UART_IER_RDI; serial_out(up, UART_IER, up->ier); - uart_port_unlock_irqrestore(port, flags); - - pm_runtime_mark_last_busy(port->dev); - pm_runtime_put_autosuspend(port->dev); } static int omap8250_rs485_config(struct uart_port *port, @@ -996,30 +971,26 @@ static void __dma_rx_complete(void *param) struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; struct dma_tx_state state; - unsigned long flags; /* Synchronize UART_IER access against the console. */ - uart_port_lock_irqsave(&p->port, &flags); + guard(uart_port_lock_irqsave)(&p->port); /* * If the tx status is not DMA_COMPLETE, then this is a delayed * completion callback. A previous RX timeout flush would have * already pushed the data, so exit. */ - if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) != - DMA_COMPLETE) { - uart_port_unlock_irqrestore(&p->port, flags); + if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) != DMA_COMPLETE) return; - } - __dma_rx_do_complete(p); - if (!priv->throttled) { - p->ier |= UART_IER_RLSI | UART_IER_RDI; - serial_out(p, UART_IER, p->ier); - if (!(priv->habit & UART_HAS_EFR2)) - omap_8250_rx_dma(p); - } - uart_port_unlock_irqrestore(&p->port, flags); + __dma_rx_do_complete(p); + if (priv->throttled) + return; + + p->ier |= UART_IER_RLSI | UART_IER_RDI; + serial_out(p, UART_IER, p->ier); + if (!(priv->habit & UART_HAS_EFR2)) + omap_8250_rx_dma(p); } static void omap_8250_rx_dma_flush(struct uart_8250_port *p) @@ -1117,14 +1088,13 @@ static void omap_8250_dma_tx_complete(void *param) struct uart_8250_port *p = param; struct uart_8250_dma *dma = p->dma; struct tty_port *tport = &p->port.state->port; - unsigned long flags; bool en_thri = false; struct omap8250_priv *priv = p->port.private_data; dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, UART_XMIT_SIZE, DMA_TO_DEVICE); - uart_port_lock_irqsave(&p->port, &flags); + guard(uart_port_lock_irqsave)(&p->port); dma->tx_running = 0; @@ -1152,8 +1122,6 @@ static void omap_8250_dma_tx_complete(void *param) dma->tx_err = 1; serial8250_set_THRI(p); } - - uart_port_unlock_irqrestore(&p->port, flags); } static int omap_8250_tx_dma(struct uart_8250_port *p) @@ -1804,15 +1772,13 @@ static int omap8250_runtime_resume(struct device *dev) up = serial8250_get_port(priv->line); if (up && omap8250_lost_context(up)) { - uart_port_lock_irq(&up->port); + guard(uart_port_lock_irq)(&up->port); omap8250_restore_regs(up); - uart_port_unlock_irq(&up->port); } if (up && up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2)) { - uart_port_lock_irq(&up->port); + guard(uart_port_lock_irq)(&up->port); omap_8250_rx_dma(up); - uart_port_unlock_irq(&up->port); } atomic_set(&priv->active, 1); From 54faf0473b15b762404d33d38cf613388ef94142 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:53 +0200 Subject: [PATCH 0259/2711] serial: 8250_rsa: use guard()s Having all the new guards, use them in the 8250_rsa code. This improves readability, makes error handling easier, and marks locked portions of code explicit. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-14-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_rsa.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c index d34093cc03ad..ff52ad02f6be 100644 --- a/drivers/tty/serial/8250/8250_rsa.c +++ b/drivers/tty/serial/8250/8250_rsa.c @@ -140,9 +140,8 @@ void rsa_enable(struct uart_8250_port *up) return; if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { - uart_port_lock_irq(&up->port); + guard(uart_port_lock_irq)(&up->port); __rsa_enable(up); - uart_port_unlock_irq(&up->port); } if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) serial_out(up, UART_RSA_FRR, 0); @@ -165,7 +164,8 @@ void rsa_disable(struct uart_8250_port *up) if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) return; - uart_port_lock_irq(&up->port); + guard(uart_port_lock_irq)(&up->port); + mode = serial_in(up, UART_RSA_MSR); result = !(mode & UART_RSA_MSR_FIFO); @@ -177,7 +177,6 @@ void rsa_disable(struct uart_8250_port *up) if (result) up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; - uart_port_unlock_irq(&up->port); } EXPORT_SYMBOL_GPL_FOR_MODULES(rsa_disable, "8250_base"); From 2fe16088c3c77cd96e64363927ddc98f66de8e8b Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:54 +0200 Subject: [PATCH 0260/2711] tty/vt: use guard()s in con_font_set/get() and con_{set,get}_unimap() Having all the new guards, use them in the 8250_rsa code. This improves readability, makes error handling easier, and marks locked portions of code explicit. The new __free()-annotated declarations are moved to the allocation points as is preferred: https://lore.kernel.org/all/CAHk-=wjvh_LUpa=864joG2JJXs3+viO-kLzLidR2JLyMr4MNwA@mail.gmail.com/ Except font_data in con_font_get(). The scope in there would not match the expected lifetime. But the declaration is moved closer. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-15-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 84 ++++++++++++++++------------------ drivers/tty/vt/vt.c | 89 +++++++++++++++++-------------------- 2 files changed, 78 insertions(+), 95 deletions(-) diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index bb4bb272ebec..8eb9d745a868 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -637,32 +637,28 @@ static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc, int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) { - int err = 0, err1; struct uni_pagedict *dict; - struct unipair *unilist, *plist; + struct unipair *plist; + int err = 0; if (!ct) return 0; - unilist = vmemdup_array_user(list, ct, sizeof(*unilist)); + struct unipair *unilist __free(kvfree) = vmemdup_array_user(list, ct, sizeof(*unilist)); if (IS_ERR(unilist)) return PTR_ERR(unilist); - console_lock(); + guard(console_lock)(); /* Save original vc_unipagdir_loc in case we allocate a new one */ dict = *vc->uni_pagedict_loc; - if (!dict) { - err = -EINVAL; - goto out_unlock; - } + if (!dict) + return -EINVAL; if (dict->refcount > 1) { dict = con_unshare_unimap(vc, dict); - if (IS_ERR(dict)) { - err = PTR_ERR(dict); - goto out_unlock; - } + if (IS_ERR(dict)) + return PTR_ERR(dict); } else if (dict == dflt) { dflt = NULL; } @@ -671,7 +667,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) * Insert user specified unicode pairs into new table. */ for (plist = unilist; ct; ct--, plist++) { - err1 = con_insert_unipair(dict, plist->unicode, plist->fontpos); + int err1 = con_insert_unipair(dict, plist->unicode, plist->fontpos); if (err1) err = err1; } @@ -680,15 +676,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) * Merge with fontmaps of any other virtual consoles. */ if (con_unify_unimap(vc, dict)) - goto out_unlock; + return err; for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) set_inverse_transl(vc, dict, m); set_inverse_trans_unicode(dict); -out_unlock: - console_unlock(); - kvfree(unilist); return err; } @@ -787,50 +780,49 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, { ushort ect; struct uni_pagedict *dict; - struct unipair *unilist; unsigned int d, r, g; - int ret = 0; - unilist = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL); + struct unipair *unilist __free(kvfree) = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL); if (!unilist) return -ENOMEM; - console_lock(); + scoped_guard(console_lock) { + ect = 0; + dict = *vc->uni_pagedict_loc; + if (!dict) + break; - ect = 0; - dict = *vc->uni_pagedict_loc; - if (!dict) - goto unlock; - - for (d = 0; d < UNI_DIRS; d++) { - u16 **dir = dict->uni_pgdir[d]; - if (!dir) - continue; - - for (r = 0; r < UNI_DIR_ROWS; r++) { - u16 *row = dir[r]; - if (!row) + for (d = 0; d < UNI_DIRS; d++) { + u16 **dir = dict->uni_pgdir[d]; + if (!dir) continue; - for (g = 0; g < UNI_ROW_GLYPHS; g++, row++) { - if (*row >= MAX_GLYPH) + for (r = 0; r < UNI_DIR_ROWS; r++) { + u16 *row = dir[r]; + if (!row) continue; - if (ect < ct) { - unilist[ect].unicode = UNI(d, r, g); - unilist[ect].fontpos = *row; + + for (g = 0; g < UNI_ROW_GLYPHS; g++, row++) { + if (*row >= MAX_GLYPH) + continue; + if (ect < ct) { + unilist[ect].unicode = UNI(d, r, g); + unilist[ect].fontpos = *row; + } + ect++; } - ect++; } } } -unlock: - console_unlock(); + if (copy_to_user(list, unilist, min(ect, ct) * sizeof(*unilist))) - ret = -EFAULT; + return -EFAULT; if (put_user(ect, uct)) - ret = -EFAULT; - kvfree(unilist); - return ret ? ret : (ect <= ct) ? 0 : -ENOMEM; + return -EFAULT; + if (ect > ct) + return -ENOMEM; + + return 0; } /* diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 62049ceb34de..100d6cb26887 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4801,57 +4801,51 @@ void reset_palette(struct vc_data *vc) static int con_font_get(struct vc_data *vc, struct console_font_op *op) { struct console_font font; - int rc = -EINVAL; int c; unsigned int vpitch = op->op == KD_FONT_OP_GET_TALL ? op->height : 32; if (vpitch > max_font_height) return -EINVAL; + void *font_data __free(kvfree) = NULL; if (op->data) { - font.data = kvzalloc(max_font_size, GFP_KERNEL); + font.data = font_data = kvzalloc(max_font_size, GFP_KERNEL); if (!font.data) return -ENOMEM; } else font.data = NULL; - console_lock(); - if (vc->vc_mode != KD_TEXT) - rc = -EINVAL; - else if (vc->vc_sw->con_font_get) - rc = vc->vc_sw->con_font_get(vc, &font, vpitch); - else - rc = -ENOSYS; - console_unlock(); + scoped_guard(console_lock) { + if (vc->vc_mode != KD_TEXT) + return -EINVAL; + if (!vc->vc_sw->con_font_get) + return -ENOSYS; - if (rc) - goto out; + int ret = vc->vc_sw->con_font_get(vc, &font, vpitch); + if (ret) + return ret; + } c = (font.width+7)/8 * vpitch * font.charcount; if (op->data && font.charcount > op->charcount) - rc = -ENOSPC; + return -ENOSPC; if (font.width > op->width || font.height > op->height) - rc = -ENOSPC; - if (rc) - goto out; + return -ENOSPC; op->height = font.height; op->width = font.width; op->charcount = font.charcount; if (op->data && copy_to_user(op->data, font.data, c)) - rc = -EFAULT; + return -EFAULT; -out: - kvfree(font.data); - return rc; + return 0; } static int con_font_set(struct vc_data *vc, const struct console_font_op *op) { struct console_font font; - int rc = -EINVAL; int size; unsigned int vpitch = op->op == KD_FONT_OP_SET_TALL ? op->height : 32; @@ -4870,7 +4864,7 @@ static int con_font_set(struct vc_data *vc, const struct console_font_op *op) if (size > max_font_size) return -ENOSPC; - font.data = memdup_user(op->data, size); + void *font_data __free(kfree) = font.data = memdup_user(op->data, size); if (IS_ERR(font.data)) return PTR_ERR(font.data); @@ -4878,18 +4872,17 @@ static int con_font_set(struct vc_data *vc, const struct console_font_op *op) font.width = op->width; font.height = op->height; - console_lock(); + guard(console_lock)(); + if (vc->vc_mode != KD_TEXT) - rc = -EINVAL; - else if (vc->vc_sw->con_font_set) { - if (vc_is_sel(vc)) - clear_selection(); - rc = vc->vc_sw->con_font_set(vc, &font, vpitch, op->flags); - } else - rc = -ENOSYS; - console_unlock(); - kfree(font.data); - return rc; + return -EINVAL; + if (!vc->vc_sw->con_font_set) + return -ENOSYS; + + if (vc_is_sel(vc)) + clear_selection(); + + return vc->vc_sw->con_font_set(vc, &font, vpitch, op->flags); } static int con_font_default(struct vc_data *vc, struct console_font_op *op) @@ -4897,8 +4890,6 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) struct console_font font = {.width = op->width, .height = op->height}; char name[MAX_FONT_NAME]; char *s = name; - int rc; - if (!op->data) s = NULL; @@ -4907,23 +4898,23 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) else name[MAX_FONT_NAME - 1] = 0; - console_lock(); - if (vc->vc_mode != KD_TEXT) { - console_unlock(); - return -EINVAL; - } - if (vc->vc_sw->con_font_default) { + scoped_guard(console_lock) { + if (vc->vc_mode != KD_TEXT) + return -EINVAL; + if (!vc->vc_sw->con_font_default) + return -ENOSYS; + if (vc_is_sel(vc)) clear_selection(); - rc = vc->vc_sw->con_font_default(vc, &font, s); - } else - rc = -ENOSYS; - console_unlock(); - if (!rc) { - op->width = font.width; - op->height = font.height; + int ret = vc->vc_sw->con_font_default(vc, &font, s); + if (ret) + return ret; } - return rc; + + op->width = font.width; + op->height = font.height; + + return 0; } int con_font_op(struct vc_data *vc, struct console_font_op *op) From e730c373b6ff16a177e132859bf6ea4dbb15105f Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:55 +0200 Subject: [PATCH 0261/2711] tty/vt: use guard()s Having all the new guards, use them in the vt code. This improves readability, makes error handling easier, and marks locked portions of code explicit. A local free_page_ptr __free guard is introduced for __get_free_page/free_page (with proper casts). This could be made public in include/. But I am not sure if there are more possible users, so keeping completely private here. Signed-off-by: "Jiri Slaby (SUSE)" Link: https://lore.kernel.org/r/20250814072456.182853-16-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 32 +++--- drivers/tty/vt/selection.c | 20 ++-- drivers/tty/vt/vc_screen.c | 74 ++++++-------- drivers/tty/vt/vt.c | 98 ++++++++----------- drivers/tty/vt/vt_ioctl.c | 190 ++++++++++++++++-------------------- 5 files changed, 170 insertions(+), 244 deletions(-) diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 8eb9d745a868..7a11c3f2e875 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -361,10 +361,10 @@ int con_set_trans_old(unsigned char __user * arg) inbuf[i] = UNI_DIRECT_BASE | ch; } - console_lock(); + guard(console_lock)(); memcpy(translations[USER_MAP], inbuf, sizeof(inbuf)); update_user_maps(); - console_unlock(); + return 0; } @@ -374,13 +374,11 @@ int con_get_trans_old(unsigned char __user * arg) unsigned short *p = translations[USER_MAP]; unsigned char outbuf[E_TABSZ]; - console_lock(); - for (i = 0; i < ARRAY_SIZE(outbuf); i++) - { - ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); - outbuf[i] = (ch & ~0xff) ? 0 : ch; - } - console_unlock(); + scoped_guard(console_lock) + for (i = 0; i < ARRAY_SIZE(outbuf); i++) { + ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); + outbuf[i] = (ch & ~0xff) ? 0 : ch; + } return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0; } @@ -392,10 +390,10 @@ int con_set_trans_new(ushort __user * arg) if (copy_from_user(inbuf, arg, sizeof(inbuf))) return -EFAULT; - console_lock(); + guard(console_lock)(); memcpy(translations[USER_MAP], inbuf, sizeof(inbuf)); update_user_maps(); - console_unlock(); + return 0; } @@ -403,9 +401,8 @@ int con_get_trans_new(ushort __user * arg) { unsigned short outbuf[E_TABSZ]; - console_lock(); - memcpy(outbuf, translations[USER_MAP], sizeof(outbuf)); - console_unlock(); + scoped_guard(console_lock) + memcpy(outbuf, translations[USER_MAP], sizeof(outbuf)); return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0; } @@ -571,11 +568,8 @@ static int con_do_clear_unimap(struct vc_data *vc) int con_clear_unimap(struct vc_data *vc) { - int ret; - console_lock(); - ret = con_do_clear_unimap(vc); - console_unlock(); - return ret; + guard(console_lock)(); + return con_do_clear_unimap(vc); } static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc, diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 24b0a53e5a79..07d3b93975d3 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -127,9 +127,8 @@ int sel_loadlut(u32 __user *lut) if (copy_from_user(tmplut, lut, sizeof(inwordLut))) return -EFAULT; - console_lock(); + guard(console_lock)(); memcpy(inwordLut, tmplut, sizeof(inwordLut)); - console_unlock(); return 0; } @@ -375,15 +374,9 @@ static int vc_selection(struct vc_data *vc, struct tiocl_selection *v, int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) { - int ret; - - mutex_lock(&vc_sel.lock); - console_lock(); - ret = vc_selection(vc_cons[fg_console].d, v, tty); - console_unlock(); - mutex_unlock(&vc_sel.lock); - - return ret; + guard(mutex)(&vc_sel.lock); + guard(console_lock)(); + return vc_selection(vc_cons[fg_console].d, v, tty); } EXPORT_SYMBOL_GPL(set_selection_kernel); @@ -409,9 +402,8 @@ int paste_selection(struct tty_struct *tty) const char *bps = bp ? bracketed_paste_start : NULL; const char *bpe = bp ? bracketed_paste_end : NULL; - console_lock(); - poke_blanked_console(); - console_unlock(); + scoped_guard(console_lock) + poke_blanked_console(); ld = tty_ldisc_ref_wait(tty); if (!ld) diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 79b33d998d43..c814644ef4ee 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -53,6 +53,8 @@ #define HEADER_SIZE 4u #define CON_BUF_SIZE (IS_ENABLED(CONFIG_BASE_SMALL) ? 256 : PAGE_SIZE) +DEFINE_FREE(free_page_ptr, void *, if (_T) free_page((unsigned long)_T)); + /* * Our minor space: * @@ -72,7 +74,6 @@ #define use_unicode(inode) (iminor(inode) & 64) #define use_attributes(inode) (iminor(inode) & 128) - struct vcs_poll_data { struct notifier_block notifier; unsigned int cons_num; @@ -231,15 +232,13 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) struct vc_data *vc; int size; - console_lock(); - vc = vcs_vc(inode, NULL); - if (!vc) { - console_unlock(); - return -ENXIO; - } + scoped_guard(console_lock) { + vc = vcs_vc(inode, NULL); + if (!vc) + return -ENXIO; - size = vcs_size(vc, use_attributes(inode), use_unicode(inode)); - console_unlock(); + size = vcs_size(vc, use_attributes(inode), use_unicode(inode)); + } if (size < 0) return size; return fixed_size_llseek(file, offset, orig, size); @@ -369,11 +368,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct vcs_poll_data *poll; unsigned int read; ssize_t ret; - char *con_buf; loff_t pos; bool viewed, attr, uni_mode; - con_buf = (char *) __get_free_page(GFP_KERNEL); + char *con_buf __free(free_page_ptr) = (char *)__get_free_page(GFP_KERNEL); if (!con_buf) return -ENOMEM; @@ -382,17 +380,16 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) /* Select the proper current console and verify * sanity of the situation under the console lock. */ - console_lock(); + guard(console_lock)(); uni_mode = use_unicode(inode); attr = use_attributes(inode); - ret = -EINVAL; if (pos < 0) - goto unlock_out; + return -EINVAL; /* we enforce 32-bit alignment for pos and count in unicode mode */ if (uni_mode && (pos | count) & 3) - goto unlock_out; + return -EINVAL; poll = file->private_data; if (count && poll) @@ -468,10 +465,8 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) } *ppos += read; if (read) - ret = read; -unlock_out: - console_unlock(); - free_page((unsigned long) con_buf); + return read; + return ret; } @@ -591,7 +586,6 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct inode *inode = file_inode(file); struct vc_data *vc; - char *con_buf; u16 *org0, *org; unsigned int written; int size; @@ -602,7 +596,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) if (use_unicode(inode)) return -EOPNOTSUPP; - con_buf = (char *) __get_free_page(GFP_KERNEL); + char *con_buf __free(free_page_ptr) = (char *)__get_free_page(GFP_KERNEL); if (!con_buf) return -ENOMEM; @@ -611,22 +605,18 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) /* Select the proper current console and verify * sanity of the situation under the console lock. */ - console_lock(); + guard(console_lock)(); attr = use_attributes(inode); - ret = -ENXIO; vc = vcs_vc(inode, &viewed); if (!vc) - goto unlock_out; + return -ENXIO; size = vcs_size(vc, attr, false); - if (size < 0) { - ret = size; - goto unlock_out; - } - ret = -EINVAL; + if (size < 0) + return size; if (pos < 0 || pos > size) - goto unlock_out; + return -EINVAL; if (count > size - pos) count = size - pos; written = 0; @@ -651,8 +641,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) */ if (written) break; - ret = -EFAULT; - goto unlock_out; + return -EFAULT; } } @@ -664,15 +653,13 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) if (!vc) { if (written) break; - ret = -ENXIO; - goto unlock_out; + return -ENXIO; } size = vcs_size(vc, attr, false); if (size < 0) { if (written) break; - ret = size; - goto unlock_out; + return size; } if (pos >= size) break; @@ -702,9 +689,6 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) if (written) vcs_scr_updated(vc); -unlock_out: - console_unlock(); - free_page((unsigned long) con_buf); return ret; } @@ -754,17 +738,17 @@ vcs_open(struct inode *inode, struct file *filp) unsigned int currcons = console(inode); bool attr = use_attributes(inode); bool uni_mode = use_unicode(inode); - int ret = 0; /* we currently don't support attributes in unicode mode */ if (attr && uni_mode) return -EOPNOTSUPP; - console_lock(); - if(currcons && !vc_cons_allocated(currcons-1)) - ret = -ENXIO; - console_unlock(); - return ret; + guard(console_lock)(); + + if (currcons && !vc_cons_allocated(currcons - 1)) + return -ENXIO; + + return 0; } static int vcs_release(struct inode *inode, struct file *file) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 100d6cb26887..869261141535 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1317,12 +1317,9 @@ EXPORT_SYMBOL(__vc_resize); static int vt_resize(struct tty_struct *tty, struct winsize *ws) { struct vc_data *vc = tty->driver_data; - int ret; - console_lock(); - ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row, false); - console_unlock(); - return ret; + guard(console_lock)(); + return vc_do_resize(tty, vc, ws->ws_col, ws->ws_row, false); } struct vc_data *vc_deallocate(unsigned int currcons) @@ -3135,12 +3132,11 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count) if (in_interrupt()) return count; - console_lock(); + guard(console_lock)(); currcons = vc->vc_num; if (!vc_cons_allocated(currcons)) { /* could this happen? */ pr_warn_once("con_write: tty %d not allocated\n", currcons+1); - console_unlock(); return 0; } @@ -3184,7 +3180,7 @@ rescan_last_byte: con_flush(vc, &draw); console_conditional_schedule(); notify_update(vc); - console_unlock(); + return n; } @@ -3199,7 +3195,7 @@ rescan_last_byte: */ static void console_callback(struct work_struct *ignored) { - console_lock(); + guard(console_lock)(); if (want_console >= 0) { if (want_console != fg_console && @@ -3228,8 +3224,6 @@ static void console_callback(struct work_struct *ignored) blank_timer_expired = 0; } notify_update(vc_cons[fg_console].d); - - console_unlock(); } int set_console(int nr) @@ -3433,9 +3427,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) return -EPERM; return paste_selection(tty); case TIOCL_UNBLANKSCREEN: - console_lock(); - unblank_screen(); - console_unlock(); + scoped_guard(console_lock) + unblank_screen(); break; case TIOCL_SELLOADLUT: if (!capable(CAP_SYS_ADMIN)) @@ -3451,9 +3444,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) data = vt_get_shift_state(); return put_user(data, p); case TIOCL_GETMOUSEREPORTING: - console_lock(); /* May be overkill */ - data = mouse_reporting(); - console_unlock(); + scoped_guard(console_lock) /* May be overkill */ + data = mouse_reporting(); return put_user(data, p); case TIOCL_SETVESABLANK: return set_vesa_blanking(param); @@ -3484,15 +3476,14 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) * Needs the console lock here. Note that lots of other calls * need fixing before the lock is actually useful! */ - console_lock(); - scrollfront(vc_cons[fg_console].d, lines); - console_unlock(); + scoped_guard(console_lock) + scrollfront(vc_cons[fg_console].d, lines); break; case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */ - console_lock(); - ignore_poke = 1; - do_blank_screen(0); - console_unlock(); + scoped_guard(console_lock) { + ignore_poke = 1; + do_blank_screen(0); + } break; case TIOCL_BLANKEDSCREEN: return console_blanked; @@ -3582,9 +3573,8 @@ static void con_flush_chars(struct tty_struct *tty) if (in_interrupt()) /* from flush_to_ldisc */ return; - console_lock(); + guard(console_lock)(); set_cursor(vc); - console_unlock(); } /* @@ -3596,22 +3586,20 @@ static int con_install(struct tty_driver *driver, struct tty_struct *tty) struct vc_data *vc; int ret; - console_lock(); + guard(console_lock)(); ret = vc_allocate(currcons); if (ret) - goto unlock; + return ret; vc = vc_cons[currcons].d; /* Still being freed */ - if (vc->port.tty) { - ret = -ERESTARTSYS; - goto unlock; - } + if (vc->port.tty) + return -ERESTARTSYS; ret = tty_port_install(&vc->port, driver, tty); if (ret) - goto unlock; + return ret; tty->driver_data = vc; vc->port.tty = tty; @@ -3625,9 +3613,8 @@ static int con_install(struct tty_driver *driver, struct tty_struct *tty) tty->termios.c_iflag |= IUTF8; else tty->termios.c_iflag &= ~IUTF8; -unlock: - console_unlock(); - return ret; + + return 0; } static int con_open(struct tty_struct *tty, struct file *filp) @@ -3646,9 +3633,9 @@ static void con_shutdown(struct tty_struct *tty) { struct vc_data *vc = tty->driver_data; BUG_ON(vc == NULL); - console_lock(); + + guard(console_lock)(); vc->port.tty = NULL; - console_unlock(); } static void con_cleanup(struct tty_struct *tty) @@ -4137,15 +4124,13 @@ static ssize_t store_bind(struct device *dev, struct device_attribute *attr, struct con_driver *con = dev_get_drvdata(dev); int bind = simple_strtoul(buf, NULL, 0); - console_lock(); + guard(console_lock)(); if (bind) vt_bind(con); else vt_unbind(con); - console_unlock(); - return count; } @@ -4155,9 +4140,8 @@ static ssize_t show_bind(struct device *dev, struct device_attribute *attr, struct con_driver *con = dev_get_drvdata(dev); int bind; - console_lock(); - bind = con_is_bound(con->con); - console_unlock(); + scoped_guard(console_lock) + bind = con_is_bound(con->con); return sysfs_emit(buf, "%i\n", bind); } @@ -4429,7 +4413,7 @@ static void con_driver_unregister_callback(struct work_struct *ignored) { int i; - console_lock(); + guard(console_lock)(); for (i = 0; i < MAX_NR_CON_DRIVER; i++) { struct con_driver *con_driver = ®istered_con_driver[i]; @@ -4454,8 +4438,6 @@ static void con_driver_unregister_callback(struct work_struct *ignored) con_driver->first = 0; con_driver->last = 0; } - - console_unlock(); } /* @@ -4491,9 +4473,8 @@ EXPORT_SYMBOL_GPL(do_take_over_console); */ void give_up_console(const struct consw *csw) { - console_lock(); + guard(console_lock)(); do_unregister_con_driver(csw); - console_unlock(); } EXPORT_SYMBOL(give_up_console); @@ -4541,9 +4522,8 @@ static int set_vesa_blanking(u8 __user *mode_user) if (get_user(mode, mode_user)) return -EFAULT; - console_lock(); + guard(console_lock)(); vesa_blank_mode = (mode <= VESA_BLANK_MAX) ? mode : VESA_NO_BLANKING; - console_unlock(); return 0; } @@ -4729,7 +4709,7 @@ int con_set_cmap(unsigned char __user *arg) if (copy_from_user(colormap, arg, sizeof(colormap))) return -EFAULT; - console_lock(); + guard(console_lock)(); for (i = k = 0; i < 16; i++) { default_red[i] = colormap[k++]; default_grn[i] = colormap[k++]; @@ -4745,7 +4725,6 @@ int con_set_cmap(unsigned char __user *arg) } set_palette(vc_cons[i].d); } - console_unlock(); return 0; } @@ -4755,13 +4734,12 @@ int con_get_cmap(unsigned char __user *arg) int i, k; unsigned char colormap[3*16]; - console_lock(); - for (i = k = 0; i < 16; i++) { - colormap[k++] = default_red[i]; - colormap[k++] = default_grn[i]; - colormap[k++] = default_blu[i]; - } - console_unlock(); + scoped_guard(console_lock) + for (i = k = 0; i < 16; i++) { + colormap[k++] = default_red[i]; + colormap[k++] = default_grn[i]; + colormap[k++] = default_blu[i]; + } if (copy_to_user(arg, colormap, sizeof(colormap))) return -EFAULT; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 61342e06970a..c9f11c4bd9fe 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -373,15 +373,13 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd, break; } - case KDSETMODE: + case KDSETMODE: { if (!perm) return -EPERM; - console_lock(); - ret = vt_kdsetmode(vc, arg); - console_unlock(); - return ret; - + guard(console_lock)(); + return vt_kdsetmode(vc, arg); + } case KDGETMODE: return put_user(vc->vc_mode, (int __user *)arg); @@ -601,23 +599,21 @@ static int vt_setactivate(struct vt_setactivate __user *sa) vsa.console--; vsa.console = array_index_nospec(vsa.console, MAX_NR_CONSOLES); - console_lock(); - ret = vc_allocate(vsa.console); - if (ret) { - console_unlock(); - return ret; - } + scoped_guard(console_lock) { + ret = vc_allocate(vsa.console); + if (ret) + return ret; - /* - * This is safe providing we don't drop the console sem between - * vc_allocate and finishing referencing nvc. - */ - nvc = vc_cons[vsa.console].d; - nvc->vt_mode = vsa.mode; - nvc->vt_mode.frsig = 0; - put_pid(nvc->vt_pid); - nvc->vt_pid = get_pid(task_pid(current)); - console_unlock(); + /* + * This is safe providing we don't drop the console sem between + * vc_allocate and finishing referencing nvc. + */ + nvc = vc_cons[vsa.console].d; + nvc->vt_mode = vsa.mode; + nvc->vt_mode.frsig = 0; + put_pid(nvc->vt_pid); + nvc->vt_pid = get_pid(task_pid(current)); + } /* Commence switch and lock */ /* Review set_console locks */ @@ -630,19 +626,18 @@ static int vt_setactivate(struct vt_setactivate __user *sa) static int vt_disallocate(unsigned int vc_num) { struct vc_data *vc = NULL; - int ret = 0; - console_lock(); - if (vt_busy(vc_num)) - ret = -EBUSY; - else if (vc_num) - vc = vc_deallocate(vc_num); - console_unlock(); + scoped_guard(console_lock) { + if (vt_busy(vc_num)) + return -EBUSY; + if (vc_num) + vc = vc_deallocate(vc_num); + } if (vc && vc_num >= MIN_NR_CONSOLES) tty_port_put(&vc->port); - return ret; + return 0; } /* deallocate all unused consoles, but leave 0 */ @@ -651,13 +646,12 @@ static void vt_disallocate_all(void) struct vc_data *vc[MAX_NR_CONSOLES]; int i; - console_lock(); - for (i = 1; i < MAX_NR_CONSOLES; i++) - if (!vt_busy(i)) - vc[i] = vc_deallocate(i); - else - vc[i] = NULL; - console_unlock(); + scoped_guard(console_lock) + for (i = 1; i < MAX_NR_CONSOLES; i++) + if (!vt_busy(i)) + vc[i] = vc_deallocate(i); + else + vc[i] = NULL; for (i = 1; i < MAX_NR_CONSOLES; i++) { if (vc[i] && i >= MIN_NR_CONSOLES) @@ -703,7 +697,7 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs) if (!vc_cons[i].d) continue; - console_lock(); + guard(console_lock)(); vcp = vc_cons[i].d; if (vcp) { int ret; @@ -718,11 +712,9 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs) if (ret) { vcp->vc_scan_lines = save_scan_lines; vcp->vc_cell_height = save_cell_height; - console_unlock(); return ret; } } - console_unlock(); } return 0; @@ -770,7 +762,7 @@ int vt_ioctl(struct tty_struct *tty, if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) return -EINVAL; - console_lock(); + guard(console_lock)(); vc->vt_mode = tmp; /* the frsig is ignored, so we set it to 0 */ vc->vt_mode.frsig = 0; @@ -778,7 +770,6 @@ int vt_ioctl(struct tty_struct *tty, vc->vt_pid = get_pid(task_pid(current)); /* no switch is required -- saw@shade.msu.ru */ vc->vt_newvt = -1; - console_unlock(); break; } @@ -787,9 +778,8 @@ int vt_ioctl(struct tty_struct *tty, struct vt_mode tmp; int rc; - console_lock(); - memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode)); - console_unlock(); + scoped_guard(console_lock) + memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode)); rc = copy_to_user(up, &tmp, sizeof(struct vt_mode)); if (rc) @@ -811,12 +801,10 @@ int vt_ioctl(struct tty_struct *tty, return -EFAULT; state = 1; /* /dev/tty0 is always open */ - console_lock(); /* required by vt_in_use() */ - for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; - ++i, mask <<= 1) - if (vt_in_use(i)) - state |= mask; - console_unlock(); + scoped_guard(console_lock) /* required by vt_in_use() */ + for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) + if (vt_in_use(i)) + state |= mask; return put_user(state, &vtstat->v_state); } @@ -824,11 +812,10 @@ int vt_ioctl(struct tty_struct *tty, * Returns the first available (non-opened) console. */ case VT_OPENQRY: - console_lock(); /* required by vt_in_use() */ - for (i = 0; i < MAX_NR_CONSOLES; ++i) - if (!vt_in_use(i)) - break; - console_unlock(); + scoped_guard(console_lock) /* required by vt_in_use() */ + for (i = 0; i < MAX_NR_CONSOLES; ++i) + if (!vt_in_use(i)) + break; i = i < MAX_NR_CONSOLES ? (i+1) : -1; return put_user(i, (int __user *)arg); @@ -845,11 +832,11 @@ int vt_ioctl(struct tty_struct *tty, arg--; arg = array_index_nospec(arg, MAX_NR_CONSOLES); - console_lock(); - ret = vc_allocate(arg); - console_unlock(); - if (ret) - return ret; + scoped_guard(console_lock) { + ret = vc_allocate(arg); + if (ret) + return ret; + } set_console(arg); break; @@ -880,15 +867,13 @@ int vt_ioctl(struct tty_struct *tty, * 2: completed switch-to OK */ case VT_RELDISP: + { if (!perm) return -EPERM; - console_lock(); - ret = vt_reldisp(vc, arg); - console_unlock(); - - return ret; - + guard(console_lock)(); + return vt_reldisp(vc, arg); + } /* * Disallocate memory associated to VT (but leave VT1) @@ -917,7 +902,7 @@ int vt_ioctl(struct tty_struct *tty, get_user(cc, &vtsizes->v_cols)) return -EFAULT; - console_lock(); + guard(console_lock)(); for (i = 0; i < MAX_NR_CONSOLES; i++) { vc = vc_cons[i].d; @@ -926,7 +911,6 @@ int vt_ioctl(struct tty_struct *tty, __vc_resize(vc_cons[i].d, cc, ll, true); } } - console_unlock(); break; } @@ -996,20 +980,17 @@ void vc_SAK(struct work_struct *work) struct vc_data *vc; struct tty_struct *tty; - console_lock(); + guard(console_lock)(); vc = vc_con->d; - if (vc) { - /* FIXME: review tty ref counting */ - tty = vc->port.tty; - /* - * SAK should also work in all raw modes and reset - * them properly. - */ - if (tty) - __do_SAK(tty); - reset_vc(vc); - } - console_unlock(); + if (!vc) + return; + + /* FIXME: review tty ref counting */ + tty = vc->port.tty; + /* SAK should also work in all raw modes and reset them properly. */ + if (tty) + __do_SAK(tty); + reset_vc(vc); } #ifdef CONFIG_COMPAT @@ -1287,31 +1268,29 @@ int vt_move_to_console(unsigned int vt, int alloc) { int prev; - console_lock(); - /* Graphics mode - up to X */ - if (disable_vt_switch) { - console_unlock(); - return 0; - } - prev = fg_console; + scoped_guard(console_lock) { + /* Graphics mode - up to X */ + if (disable_vt_switch) + return 0; - if (alloc && vc_allocate(vt)) { - /* we can't have a free VC for now. Too bad, - * we don't want to mess the screen for now. */ - console_unlock(); - return -ENOSPC; - } + prev = fg_console; - if (set_console(vt)) { - /* - * We're unable to switch to the SUSPEND_CONSOLE. - * Let the calling function know so it can decide - * what to do. - */ - console_unlock(); - return -EIO; + if (alloc && vc_allocate(vt)) { + /* + * We can't have a free VC for now. Too bad, we don't want to mess the + * screen for now. + */ + return -ENOSPC; + } + + if (set_console(vt)) { + /* + * We're unable to switch to the SUSPEND_CONSOLE. Let the calling function + * know so it can decide what to do. + */ + return -EIO; + } } - console_unlock(); if (vt_waitactive(vt + 1)) { pr_debug("Suspend: Can't switch VCs."); return -EINTR; @@ -1328,8 +1307,7 @@ int vt_move_to_console(unsigned int vt, int alloc) */ void pm_set_vt_switch(int do_switch) { - console_lock(); + guard(console_lock)(); disable_vt_switch = !do_switch; - console_unlock(); } EXPORT_SYMBOL(pm_set_vt_switch); From 7cd9f5d6c5a3f31d2b282d31ddc4d78ff83a5c08 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Thu, 14 Aug 2025 09:24:56 +0200 Subject: [PATCH 0262/2711] s390/char/con3270: use tty_port_tty guard() Having the new tty_port_tty guard, use it in tty3270_resize(). This makes the code easier to read. The winsize is now defined in the scope and initialized immediately, so that it's obvious. Signed-off-by: "Jiri Slaby (SUSE)" Cc: Heiko Carstens Cc: Vasily Gorbik Cc: Alexander Gordeev Cc: Christian Borntraeger Cc: Sven Schnelle Acked-by: Heiko Carstens Link: https://lore.kernel.org/r/20250814072456.182853-17-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/s390/char/con3270.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index b78b86e8f281..a367f95c7c53 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -970,8 +970,6 @@ static void tty3270_resize(struct raw3270_view *view, char **old_rcl_lines, **new_rcl_lines; char *old_prompt, *new_prompt; char *old_input, *new_input; - struct tty_struct *tty; - struct winsize ws; size_t prompt_sz; int new_allocated, old_allocated = tp->allocated_lines; @@ -1023,14 +1021,14 @@ static void tty3270_resize(struct raw3270_view *view, kfree(old_prompt); tty3270_free_recall(old_rcl_lines); tty3270_set_timer(tp, 1); - /* Informat tty layer about new size */ - tty = tty_port_tty_get(&tp->port); - if (!tty) - return; - ws.ws_row = tty3270_tty_rows(tp); - ws.ws_col = tp->view.cols; - tty_do_resize(tty, &ws); - tty_kref_put(tty); + /* Inform the tty layer about new size */ + scoped_guard(tty_port_tty, &tp->port) { + struct winsize ws = { + .ws_row = tty3270_tty_rows(tp), + .ws_col = tp->view.cols, + }; + tty_do_resize(scoped_tty(), &ws); + } return; out_screen: tty3270_free_screen(screen, new_rows); From 35e3d0cd8e89d811b915593cbd8d9891d21d4a1a Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sat, 16 Aug 2025 20:05:09 +0800 Subject: [PATCH 0263/2711] iio: imu: inv_icm42600: use min() to improve code Use min() to reduce code in inv_icm42600_buffer_update_fifo_period() and inv_icm42600_buffer_update_watermark(), and improve readability. Signed-off-by: Qianfeng Rong Reviewed-by: David Lechner Link: https://patch.msgid.link/20250816120510.355835-1-rongqianfeng@vivo.com Signed-off-by: Jonathan Cameron --- .../imu/inv_icm42600/inv_icm42600_buffer.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index 7c4ed981db04..ca744aaee542 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -100,7 +101,7 @@ ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel, void inv_icm42600_buffer_update_fifo_period(struct inv_icm42600_state *st) { - u32 period_gyro, period_accel, period; + u32 period_gyro, period_accel; if (st->fifo.en & INV_ICM42600_SENSOR_GYRO) period_gyro = inv_icm42600_odr_to_period(st->conf.gyro.odr); @@ -112,12 +113,7 @@ void inv_icm42600_buffer_update_fifo_period(struct inv_icm42600_state *st) else period_accel = U32_MAX; - if (period_gyro <= period_accel) - period = period_gyro; - else - period = period_accel; - - st->fifo.period = period; + st->fifo.period = min(period_gyro, period_accel); } int inv_icm42600_buffer_set_fifo_en(struct inv_icm42600_state *st, @@ -204,7 +200,7 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st) { size_t packet_size, wm_size; unsigned int wm_gyro, wm_accel, watermark; - u32 period_gyro, period_accel, period; + u32 period_gyro, period_accel; u32 latency_gyro, latency_accel, latency; bool restore; __le16 raw_wm; @@ -237,13 +233,8 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st) latency = latency_gyro - (latency_accel % latency_gyro); else latency = latency_accel - (latency_gyro % latency_accel); - /* use the shortest period */ - if (period_gyro <= period_accel) - period = period_gyro; - else - period = period_accel; /* all this works because periods are multiple of each others */ - watermark = latency / period; + watermark = latency / min(period_gyro, period_accel); if (watermark < 1) watermark = 1; /* update effective watermark */ From 26d48cc203e1c4d79b0bb6c7e2cdcaea5f548971 Mon Sep 17 00:00:00 2001 From: Chandra Mohan Sundar Date: Sat, 16 Aug 2025 19:07:55 +0530 Subject: [PATCH 0264/2711] iio: adc: ad7768-1: Remove logically dead code The clamp macro returns a value within the specified range. In ad7768_set_freq(), the value returned from clamp() is checked against zero, which is not possible since the value would always be between 50 and 1024000. Removed the 'if' check. This issue was reported by static coverity analyser as logically dead code. Signed-off-by: Chandra Mohan Sundar Link: https://patch.msgid.link/20250816133757.98624-1-chandramohan.explore@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index ca8fa91796ca..a27591bbf7df 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -687,8 +687,6 @@ static int ad7768_set_freq(struct ad7768_state *st, int ret; freq = clamp(freq, 50, 1024000); - if (freq == 0) - return -EINVAL; mclk_div = DIV_ROUND_CLOSEST(st->mclk_freq, freq * st->oversampling_ratio); /* Find the closest match for the desired sampling frequency */ From 5576d8098052952a6c95af86ad3dcb341554ac75 Mon Sep 17 00:00:00 2001 From: Inbaraj E Date: Thu, 14 Aug 2025 19:39:32 +0530 Subject: [PATCH 0265/2711] dt-bindings: clock: Add CAM_CSI clock macro for FSD CAM_CSI block has ACLK, PCLK and PLL clocks. PCLK id is already assigned. To use PCLK and PLL clock in driver add id macro for CAM_CSI_PLL and CAM_CSI_PCLK. Signed-off-by: Inbaraj E Link: https://lore.kernel.org/r/20250814140943.22531-2-inbaraj.e@samsung.com Signed-off-by: Krzysztof Kozlowski --- include/dt-bindings/clock/fsd-clk.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/dt-bindings/clock/fsd-clk.h b/include/dt-bindings/clock/fsd-clk.h index 3f7b64d93558..58fdec8f4c2a 100644 --- a/include/dt-bindings/clock/fsd-clk.h +++ b/include/dt-bindings/clock/fsd-clk.h @@ -139,5 +139,18 @@ #define CAM_CSI2_1_IPCLKPORT_I_ACLK 10 #define CAM_CSI2_2_IPCLKPORT_I_ACLK 11 #define CAM_CSI2_3_IPCLKPORT_I_ACLK 12 +#define CAM_CSI_PLL 13 +#define CAM_CSI0_0_IPCLKPORT_I_PCLK 14 +#define CAM_CSI0_1_IPCLKPORT_I_PCLK 15 +#define CAM_CSI0_2_IPCLKPORT_I_PCLK 16 +#define CAM_CSI0_3_IPCLKPORT_I_PCLK 17 +#define CAM_CSI1_0_IPCLKPORT_I_PCLK 18 +#define CAM_CSI1_1_IPCLKPORT_I_PCLK 19 +#define CAM_CSI1_2_IPCLKPORT_I_PCLK 20 +#define CAM_CSI1_3_IPCLKPORT_I_PCLK 21 +#define CAM_CSI2_0_IPCLKPORT_I_PCLK 22 +#define CAM_CSI2_1_IPCLKPORT_I_PCLK 23 +#define CAM_CSI2_2_IPCLKPORT_I_PCLK 24 +#define CAM_CSI2_3_IPCLKPORT_I_PCLK 25 #endif /*_DT_BINDINGS_CLOCK_FSD_H */ From 1a713bd3b0c60d826bdde633919bedc1fd38df4d Mon Sep 17 00:00:00 2001 From: Inbaraj E Date: Thu, 14 Aug 2025 19:39:33 +0530 Subject: [PATCH 0266/2711] clk: samsung: fsd: Add clk id for PCLK and PLL in CAM_CSI block Add clock id for PCLK and PLL. These clock id will be used for operation of CSI driver. PCLK is AXI2APB clock used for register access. PLL clock is main clock source for CAM_CSI block. Signed-off-by: Inbaraj E Link: https://lore.kernel.org/r/20250814140943.22531-3-inbaraj.e@samsung.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-fsd.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/clk/samsung/clk-fsd.c b/drivers/clk/samsung/clk-fsd.c index 594931334574..4124d65e3d18 100644 --- a/drivers/clk/samsung/clk-fsd.c +++ b/drivers/clk/samsung/clk-fsd.c @@ -89,7 +89,7 @@ #define CLKS_NR_FSYS1 (PCIE_LINK1_IPCLKPORT_SLV_ACLK + 1) #define CLKS_NR_IMEM (IMEM_TMU_GT_IPCLKPORT_I_CLK_TS + 1) #define CLKS_NR_MFC (MFC_MFC_IPCLKPORT_ACLK + 1) -#define CLKS_NR_CAM_CSI (CAM_CSI2_3_IPCLKPORT_I_ACLK + 1) +#define CLKS_NR_CAM_CSI (CAM_CSI2_3_IPCLKPORT_I_PCLK + 1) static const unsigned long cmu_clk_regs[] __initconst = { PLL_LOCKTIME_PLL_SHARED0, @@ -1646,7 +1646,7 @@ static const struct samsung_pll_rate_table pll_cam_csi_rate_table[] __initconst }; static const struct samsung_pll_clock cam_csi_pll_clks[] __initconst = { - PLL(pll_142xx, 0, "fout_pll_cam_csi", "fin_pll", + PLL(pll_142xx, CAM_CSI_PLL, "fout_pll_cam_csi", "fin_pll", PLL_LOCKTIME_PLL_CAM_CSI, PLL_CON0_PLL_CAM_CSI, pll_cam_csi_rate_table), }; @@ -1682,51 +1682,51 @@ static const struct samsung_gate_clock cam_csi_gate_clks[] __initconst = { GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__NOC, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI0_0_IPCLKPORT_I_ACLK, "cam_csi0_0_ipclkport_i_aclk", "dout_cam_csi0_aclk", GAT_CAM_CSI0_0_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi0_0_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI0_0_IPCLKPORT_I_PCLK, "cam_csi0_0_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI0_0_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI0_1_IPCLKPORT_I_ACLK, "cam_csi0_1_ipclkport_i_aclk", "dout_cam_csi0_aclk", GAT_CAM_CSI0_1_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi0_1_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI0_1_IPCLKPORT_I_PCLK, "cam_csi0_1_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI0_1_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI0_2_IPCLKPORT_I_ACLK, "cam_csi0_2_ipclkport_i_aclk", "dout_cam_csi0_aclk", GAT_CAM_CSI0_2_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi0_2_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI0_2_IPCLKPORT_I_PCLK, "cam_csi0_2_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI0_2_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI0_3_IPCLKPORT_I_ACLK, "cam_csi0_3_ipclkport_i_aclk", "dout_cam_csi0_aclk", GAT_CAM_CSI0_3_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi0_3_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI0_3_IPCLKPORT_I_PCLK, "cam_csi0_3_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI0_3_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI1_0_IPCLKPORT_I_ACLK, "cam_csi1_0_ipclkport_i_aclk", "dout_cam_csi1_aclk", GAT_CAM_CSI1_0_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi1_0_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI1_0_IPCLKPORT_I_PCLK, "cam_csi1_0_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI1_0_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI1_1_IPCLKPORT_I_ACLK, "cam_csi1_1_ipclkport_i_aclk", "dout_cam_csi1_aclk", GAT_CAM_CSI1_1_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi1_1_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI1_1_IPCLKPORT_I_PCLK, "cam_csi1_1_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI1_1_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI1_2_IPCLKPORT_I_ACLK, "cam_csi1_2_ipclkport_i_aclk", "dout_cam_csi1_aclk", GAT_CAM_CSI1_2_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi1_2_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI1_2_IPCLKPORT_I_PCLK, "cam_csi1_2_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI1_2_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI1_3_IPCLKPORT_I_ACLK, "cam_csi1_3_ipclkport_i_aclk", "dout_cam_csi1_aclk", GAT_CAM_CSI1_3_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi1_3_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI1_3_IPCLKPORT_I_PCLK, "cam_csi1_3_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI1_3_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI2_0_IPCLKPORT_I_ACLK, "cam_csi2_0_ipclkport_i_aclk", "dout_cam_csi2_aclk", GAT_CAM_CSI2_0_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi2_0_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI2_0_IPCLKPORT_I_PCLK, "cam_csi2_0_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI2_0_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI2_1_IPCLKPORT_I_ACLK, "cam_csi2_1_ipclkport_i_aclk", "dout_cam_csi2_aclk", GAT_CAM_CSI2_1_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi2_1_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI2_1_IPCLKPORT_I_PCLK, "cam_csi2_1_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI2_1_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI2_2_IPCLKPORT_I_ACLK, "cam_csi2_2_ipclkport_i_aclk", "dout_cam_csi2_aclk", GAT_CAM_CSI2_2_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi2_2_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI2_2_IPCLKPORT_I_PCLK, "cam_csi2_2_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI2_2_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CAM_CSI2_3_IPCLKPORT_I_ACLK, "cam_csi2_3_ipclkport_i_aclk", "dout_cam_csi2_aclk", GAT_CAM_CSI2_3_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0), - GATE(0, "cam_csi2_3_ipclkport_i_pclk", "dout_cam_csi_busp", + GATE(CAM_CSI2_3_IPCLKPORT_I_PCLK, "cam_csi2_3_ipclkport_i_pclk", "dout_cam_csi_busp", GAT_CAM_CSI2_3_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(0, "cam_ns_brdg_cam_csi_ipclkport_clk__psoc_cam_csi__clk_cam_csi_d", "dout_cam_csi_busd", From 4d2604833e8ea79e77de98aa97a94b94a9733962 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Sun, 17 Aug 2025 13:50:34 +0000 Subject: [PATCH 0267/2711] binder: remove MODULE_LICENSE() The MODULE_LICENSE() macro is intended for drivers that can be built as loadable modules. The binder driver is always built-in, using this macro here is unnecessary and potentially confusing. Remove it. Cc: Salvatore Bonaccorso Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20250817135034.3692902-1-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 312b462e349d..28634f786e70 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -7088,5 +7088,3 @@ device_initcall(binder_init); #define CREATE_TRACE_POINTS #include "binder_trace.h" - -MODULE_LICENSE("GPL v2"); From 2c1afbf36c0296314a1cee6cea00b5b73fabfc4e Mon Sep 17 00:00:00 2001 From: Raviteja Laggyshetty Date: Thu, 14 Aug 2025 14:54:20 +0000 Subject: [PATCH 0268/2711] interconnect: qcom: icc-rpmh: increase MAX_PORTS to support four QoS ports Update the MAX_PORTS value to 4 to program four QoS ports available on the Glymur SoC's interconnect master node. Co-developed-by: Odelu Kukatla Signed-off-by: Odelu Kukatla Signed-off-by: Raviteja Laggyshetty Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250814-glymur-icc-v2-2-596cca6b6015@oss.qualcomm.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpmh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h index bd8d730249b1..307f48412563 100644 --- a/drivers/interconnect/qcom/icc-rpmh.h +++ b/drivers/interconnect/qcom/icc-rpmh.h @@ -53,7 +53,7 @@ struct bcm_db { u8 reserved; }; -#define MAX_PORTS 2 +#define MAX_PORTS 4 /** * struct qcom_icc_qosbox - Qualcomm specific QoS config From 5c5f2221821a4371b5f33347538c3b87c01c8779 Mon Sep 17 00:00:00 2001 From: Raviteja Laggyshetty Date: Thu, 14 Aug 2025 14:54:21 +0000 Subject: [PATCH 0269/2711] interconnect: qcom: add glymur interconnect provider driver Add driver for the Qualcomm interconnect buses found in glymur based platforms. The topology consists of several NoCs that are controlled by a remote processor that collects the aggregated bandwidth for each master-slave pairs. Co-developed-by: Odelu Kukatla Signed-off-by: Odelu Kukatla Signed-off-by: Raviteja Laggyshetty Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250814-glymur-icc-v2-3-596cca6b6015@oss.qualcomm.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/Kconfig | 9 + drivers/interconnect/qcom/Makefile | 2 + drivers/interconnect/qcom/glymur.c | 2543 ++++++++++++++++++++++++++++ 3 files changed, 2554 insertions(+) create mode 100644 drivers/interconnect/qcom/glymur.c diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index 31dc4781abef..5b4bb9f1382b 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -8,6 +8,15 @@ config INTERCONNECT_QCOM config INTERCONNECT_QCOM_BCM_VOTER tristate +config INTERCONNECT_QCOM_GLYMUR + tristate "Qualcomm GLYMUR interconnect driver" + depends on INTERCONNECT_QCOM_RPMH_POSSIBLE + select INTERCONNECT_QCOM_RPMH + select INTERCONNECT_QCOM_BCM_VOTER + help + This is a driver for the Qualcomm Network-on-Chip on glymur-based + platforms. + config INTERCONNECT_QCOM_MSM8909 tristate "Qualcomm MSM8909 interconnect driver" depends on INTERCONNECT_QCOM diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index f16ac242eba5..cf8cba73ee3e 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM) += interconnect_qcom.o interconnect_qcom-y := icc-common.o icc-bcm-voter-objs := bcm-voter.o +qnoc-glymur-objs := glymur.o qnoc-milos-objs := milos.o qnoc-msm8909-objs := msm8909.o qnoc-msm8916-objs := msm8916.o @@ -46,6 +47,7 @@ qnoc-x1e80100-objs := x1e80100.o icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o +obj-$(CONFIG_INTERCONNECT_QCOM_GLYMUR) += qnoc-glymur.o obj-$(CONFIG_INTERCONNECT_QCOM_MILOS) += qnoc-milos.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8909) += qnoc-msm8909.o obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o diff --git a/drivers/interconnect/qcom/glymur.c b/drivers/interconnect/qcom/glymur.c new file mode 100644 index 000000000000..cf20b5752dbb --- /dev/null +++ b/drivers/interconnect/qcom/glymur.c @@ -0,0 +1,2543 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "bcm-voter.h" +#include "icc-rpmh.h" + +static struct qcom_icc_node qup0_core_slave = { + .name = "qup0_core_slave", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qup1_core_slave = { + .name = "qup1_core_slave", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qup2_core_slave = { + .name = "qup2_core_slave", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ahb2phy0 = { + .name = "qhs_ahb2phy0", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ahb2phy1 = { + .name = "qhs_ahb2phy1", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ahb2phy2 = { + .name = "qhs_ahb2phy2", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ahb2phy3 = { + .name = "qhs_ahb2phy3", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_av1_enc_cfg = { + .name = "qhs_av1_enc_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_camera_cfg = { + .name = "qhs_camera_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_clk_ctl = { + .name = "qhs_clk_ctl", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_crypto0_cfg = { + .name = "qhs_crypto0_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_display_cfg = { + .name = "qhs_display_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_gpuss_cfg = { + .name = "qhs_gpuss_cfg", + .channels = 1, + .buswidth = 8, +}; + +static struct qcom_icc_node qhs_imem_cfg = { + .name = "qhs_imem_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pcie0_cfg = { + .name = "qhs_pcie0_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pcie1_cfg = { + .name = "qhs_pcie1_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pcie2_cfg = { + .name = "qhs_pcie2_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pcie3a_cfg = { + .name = "qhs_pcie3a_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pcie3b_cfg = { + .name = "qhs_pcie3b_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pcie4_cfg = { + .name = "qhs_pcie4_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pcie5_cfg = { + .name = "qhs_pcie5_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pcie6_cfg = { + .name = "qhs_pcie6_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pcie_rscc = { + .name = "qhs_pcie_rscc", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_pdm = { + .name = "qhs_pdm", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_prng = { + .name = "qhs_prng", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qdss_cfg = { + .name = "qhs_qdss_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qspi = { + .name = "qhs_qspi", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qup0 = { + .name = "qhs_qup0", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qup1 = { + .name = "qhs_qup1", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_qup2 = { + .name = "qhs_qup2", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_sdc2 = { + .name = "qhs_sdc2", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_sdc4 = { + .name = "qhs_sdc4", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_smmuv3_cfg = { + .name = "qhs_smmuv3_cfg", + .channels = 1, + .buswidth = 8, +}; + +static struct qcom_icc_node qhs_tcsr = { + .name = "qhs_tcsr", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_tlmm = { + .name = "qhs_tlmm", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ufs_mem_cfg = { + .name = "qhs_ufs_mem_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_usb2_0_cfg = { + .name = "qhs_usb2_0_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_usb3_0_cfg = { + .name = "qhs_usb3_0_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_usb3_1_cfg = { + .name = "qhs_usb3_1_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_usb3_2_cfg = { + .name = "qhs_usb3_2_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_usb3_mp_cfg = { + .name = "qhs_usb3_mp_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_usb4_0_cfg = { + .name = "qhs_usb4_0_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_usb4_1_cfg = { + .name = "qhs_usb4_1_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_usb4_2_cfg = { + .name = "qhs_usb4_2_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_venus_cfg = { + .name = "qhs_venus_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qss_lpass_qtb_cfg = { + .name = "qss_lpass_qtb_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qss_nsp_qtb_cfg = { + .name = "qss_nsp_qtb_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node xs_qdss_stm = { + .name = "xs_qdss_stm", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node xs_sys_tcu_cfg = { + .name = "xs_sys_tcu_cfg", + .channels = 1, + .buswidth = 8, +}; + +static struct qcom_icc_node qhs_aoss = { + .name = "qhs_aoss", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_ipc_router = { + .name = "qhs_ipc_router", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_soccp = { + .name = "qhs_soccp", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_tme_cfg = { + .name = "qhs_tme_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qns_apss = { + .name = "qns_apss", + .channels = 1, + .buswidth = 8, +}; + +static struct qcom_icc_node qxs_boot_imem = { + .name = "qxs_boot_imem", + .channels = 1, + .buswidth = 16, +}; + +static struct qcom_icc_node qxs_imem = { + .name = "qxs_imem", + .channels = 1, + .buswidth = 8, +}; + +static struct qcom_icc_node ebi = { + .name = "ebi", + .channels = 12, + .buswidth = 4, +}; + +static struct qcom_icc_node srvc_mnoc = { + .name = "srvc_mnoc", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node srvc_nsinoc = { + .name = "srvc_nsinoc", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node srvc_pcie_east_aggre_noc = { + .name = "srvc_pcie_east_aggre_noc", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_hscnoc_pcie_east_ms_mpu_cfg = { + .name = "qhs_hscnoc_pcie_east_ms_mpu_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node srvc_pcie_east = { + .name = "srvc_pcie_east", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node xs_pcie_0 = { + .name = "xs_pcie_0", + .channels = 1, + .buswidth = 16, +}; + +static struct qcom_icc_node xs_pcie_1 = { + .name = "xs_pcie_1", + .channels = 1, + .buswidth = 32, +}; + +static struct qcom_icc_node xs_pcie_5 = { + .name = "xs_pcie_5", + .channels = 1, + .buswidth = 32, +}; + +static struct qcom_icc_node srvc_pcie_west_aggre_noc = { + .name = "srvc_pcie_west_aggre_noc", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node qhs_hscnoc_pcie_west_ms_mpu_cfg = { + .name = "qhs_hscnoc_pcie_west_ms_mpu_cfg", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node srvc_pcie_west = { + .name = "srvc_pcie_west", + .channels = 1, + .buswidth = 4, +}; + +static struct qcom_icc_node xs_pcie_2 = { + .name = "xs_pcie_2", + .channels = 1, + .buswidth = 16, +}; + +static struct qcom_icc_node xs_pcie_3a = { + .name = "xs_pcie_3a", + .channels = 1, + .buswidth = 64, +}; + +static struct qcom_icc_node xs_pcie_3b = { + .name = "xs_pcie_3b", + .channels = 1, + .buswidth = 32, +}; + +static struct qcom_icc_node xs_pcie_4 = { + .name = "xs_pcie_4", + .channels = 1, + .buswidth = 16, +}; + +static struct qcom_icc_node xs_pcie_6 = { + .name = "xs_pcie_6", + .channels = 1, + .buswidth = 16, +}; + +static struct qcom_icc_node qup0_core_master = { + .name = "qup0_core_master", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qup0_core_slave }, +}; + +static struct qcom_icc_node qup1_core_master = { + .name = "qup1_core_master", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qup1_core_slave }, +}; + +static struct qcom_icc_node qup2_core_master = { + .name = "qup2_core_master", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qup2_core_slave }, +}; + +static struct qcom_icc_node llcc_mc = { + .name = "llcc_mc", + .channels = 12, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &ebi }, +}; + +static struct qcom_icc_node qsm_mnoc_cfg = { + .name = "qsm_mnoc_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &srvc_mnoc }, +}; + +static struct qcom_icc_node qsm_pcie_east_anoc_cfg = { + .name = "qsm_pcie_east_anoc_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &srvc_pcie_east_aggre_noc }, +}; + +static struct qcom_icc_node qnm_hscnoc_pcie_east = { + .name = "qnm_hscnoc_pcie_east", + .channels = 1, + .buswidth = 32, + .num_links = 3, + .link_nodes = (struct qcom_icc_node *[]) { &xs_pcie_0, &xs_pcie_1, + &xs_pcie_5 }, +}; + +static struct qcom_icc_node qsm_cnoc_pcie_east_slave_cfg = { + .name = "qsm_cnoc_pcie_east_slave_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qhs_hscnoc_pcie_east_ms_mpu_cfg, + &srvc_pcie_east }, +}; + +static struct qcom_icc_node qsm_pcie_west_anoc_cfg = { + .name = "qsm_pcie_west_anoc_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &srvc_pcie_west_aggre_noc }, +}; + +static struct qcom_icc_node qnm_hscnoc_pcie_west = { + .name = "qnm_hscnoc_pcie_west", + .channels = 1, + .buswidth = 32, + .num_links = 5, + .link_nodes = (struct qcom_icc_node *[]) { &xs_pcie_2, &xs_pcie_3a, + &xs_pcie_3b, &xs_pcie_4, + &xs_pcie_6 }, +}; + +static struct qcom_icc_node qsm_cnoc_pcie_west_slave_cfg = { + .name = "qsm_cnoc_pcie_west_slave_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qhs_hscnoc_pcie_west_ms_mpu_cfg, + &srvc_pcie_west }, +}; + +static struct qcom_icc_node qss_cnoc_pcie_slave_east_cfg = { + .name = "qss_cnoc_pcie_slave_east_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qsm_cnoc_pcie_east_slave_cfg }, +}; + +static struct qcom_icc_node qss_cnoc_pcie_slave_west_cfg = { + .name = "qss_cnoc_pcie_slave_west_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qsm_cnoc_pcie_west_slave_cfg }, +}; + +static struct qcom_icc_node qss_mnoc_cfg = { + .name = "qss_mnoc_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qsm_mnoc_cfg }, +}; + +static struct qcom_icc_node qss_pcie_east_anoc_cfg = { + .name = "qss_pcie_east_anoc_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qsm_pcie_east_anoc_cfg }, +}; + +static struct qcom_icc_node qss_pcie_west_anoc_cfg = { + .name = "qss_pcie_west_anoc_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qsm_pcie_west_anoc_cfg }, +}; + +static struct qcom_icc_node qns_llcc = { + .name = "qns_llcc", + .channels = 12, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &llcc_mc }, +}; + +static struct qcom_icc_node qns_pcie_east = { + .name = "qns_pcie_east", + .channels = 1, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_hscnoc_pcie_east }, +}; + +static struct qcom_icc_node qns_pcie_west = { + .name = "qns_pcie_west", + .channels = 1, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_hscnoc_pcie_west }, +}; + +static struct qcom_icc_node qsm_cfg = { + .name = "qsm_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 51, + .link_nodes = (struct qcom_icc_node *[]) { &qhs_ahb2phy0, &qhs_ahb2phy1, + &qhs_ahb2phy2, &qhs_ahb2phy3, + &qhs_av1_enc_cfg, &qhs_camera_cfg, + &qhs_clk_ctl, &qhs_crypto0_cfg, + &qhs_display_cfg, &qhs_gpuss_cfg, + &qhs_imem_cfg, &qhs_pcie0_cfg, + &qhs_pcie1_cfg, &qhs_pcie2_cfg, + &qhs_pcie3a_cfg, &qhs_pcie3b_cfg, + &qhs_pcie4_cfg, &qhs_pcie5_cfg, + &qhs_pcie6_cfg, &qhs_pcie_rscc, + &qhs_pdm, &qhs_prng, + &qhs_qdss_cfg, &qhs_qspi, + &qhs_qup0, &qhs_qup1, + &qhs_qup2, &qhs_sdc2, + &qhs_sdc4, &qhs_smmuv3_cfg, + &qhs_tcsr, &qhs_tlmm, + &qhs_ufs_mem_cfg, &qhs_usb2_0_cfg, + &qhs_usb3_0_cfg, &qhs_usb3_1_cfg, + &qhs_usb3_2_cfg, &qhs_usb3_mp_cfg, + &qhs_usb4_0_cfg, &qhs_usb4_1_cfg, + &qhs_usb4_2_cfg, &qhs_venus_cfg, + &qss_cnoc_pcie_slave_east_cfg, &qss_cnoc_pcie_slave_west_cfg, + &qss_lpass_qtb_cfg, &qss_mnoc_cfg, + &qss_nsp_qtb_cfg, &qss_pcie_east_anoc_cfg, + &qss_pcie_west_anoc_cfg, &xs_qdss_stm, + &xs_sys_tcu_cfg }, +}; + +static struct qcom_icc_node xm_gic = { + .name = "xm_gic", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x33000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_llcc }, +}; + +static struct qcom_icc_node qss_cfg = { + .name = "qss_cfg", + .channels = 1, + .buswidth = 4, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qsm_cfg }, +}; + +static struct qcom_icc_node qnm_hscnoc_cnoc = { + .name = "qnm_hscnoc_cnoc", + .channels = 1, + .buswidth = 16, + .num_links = 8, + .link_nodes = (struct qcom_icc_node *[]) { &qhs_aoss, &qhs_ipc_router, + &qhs_soccp, &qhs_tme_cfg, + &qns_apss, &qss_cfg, + &qxs_boot_imem, &qxs_imem }, +}; + +static struct qcom_icc_node qns_hscnoc_cnoc = { + .name = "qns_hscnoc_cnoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_hscnoc_cnoc }, +}; + +static struct qcom_icc_node alm_gpu_tcu = { + .name = "alm_gpu_tcu", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x933000 }, + .prio = 1, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc }, +}; + +static struct qcom_icc_node alm_pcie_qtc = { + .name = "alm_pcie_qtc", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x51f000 }, + .prio = 3, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc }, +}; + +static struct qcom_icc_node alm_sys_tcu = { + .name = "alm_sys_tcu", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x51f080 }, + .prio = 6, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc }, +}; + +static struct qcom_icc_node chm_apps = { + .name = "chm_apps", + .channels = 6, + .buswidth = 32, + .num_links = 4, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc, + &qns_pcie_east, &qns_pcie_west }, +}; + +static struct qcom_icc_node qnm_aggre_noc_east = { + .name = "qnm_aggre_noc_east", + .channels = 1, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x934000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 4, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc, + &qns_pcie_east, &qns_pcie_west }, +}; + +static struct qcom_icc_node qnm_gpu = { + .name = "qnm_gpu", + .channels = 4, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 4, + .port_offsets = { 0x935000, 0x936000, 0x937000, 0x938000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 4, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc, + &qns_pcie_east, &qns_pcie_west }, +}; + +static struct qcom_icc_node qnm_lpass = { + .name = "qnm_lpass", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x939000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 4, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc, + &qns_pcie_east, &qns_pcie_west }, +}; + +static struct qcom_icc_node qnm_mnoc_hf = { + .name = "qnm_mnoc_hf", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x721000, 0x721080 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 4, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc, + &qns_pcie_east, &qns_pcie_west }, +}; + +static struct qcom_icc_node qnm_mnoc_sf = { + .name = "qnm_mnoc_sf", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x721100, 0x721180 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 4, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc, + &qns_pcie_east, &qns_pcie_west }, +}; + +static struct qcom_icc_node qnm_nsp_noc = { + .name = "qnm_nsp_noc", + .channels = 4, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 4, + .port_offsets = { 0x816000, 0x816080, 0x816100, 0x816180 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 4, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc, + &qns_pcie_east, &qns_pcie_west }, +}; + +static struct qcom_icc_node qnm_pcie_east = { + .name = "qnm_pcie_east", + .channels = 1, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x93a000 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc }, +}; + +static struct qcom_icc_node qnm_pcie_west = { + .name = "qnm_pcie_west", + .channels = 1, + .buswidth = 64, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x721200 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc }, +}; + +static struct qcom_icc_node qnm_snoc_sf = { + .name = "qnm_snoc_sf", + .channels = 1, + .buswidth = 64, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x51f100 }, + .prio = 2, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 4, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc, + &qns_pcie_east, &qns_pcie_west }, +}; + +static struct qcom_icc_node qxm_wlan_q6 = { + .name = "qxm_wlan_q6", + .channels = 1, + .buswidth = 8, + .num_links = 4, + .link_nodes = (struct qcom_icc_node *[]) { &qns_hscnoc_cnoc, &qns_llcc, + &qns_pcie_east, &qns_pcie_west }, +}; + +static struct qcom_icc_node qns_a4noc_hscnoc = { + .name = "qns_a4noc_hscnoc", + .channels = 1, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_aggre_noc_east }, +}; + +static struct qcom_icc_node qns_lpass_ag_noc_gemnoc = { + .name = "qns_lpass_ag_noc_gemnoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_lpass }, +}; + +static struct qcom_icc_node qns_mem_noc_hf = { + .name = "qns_mem_noc_hf", + .channels = 2, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_hf }, +}; + +static struct qcom_icc_node qns_mem_noc_sf = { + .name = "qns_mem_noc_sf", + .channels = 2, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_sf }, +}; + +static struct qcom_icc_node qns_nsp_hscnoc = { + .name = "qns_nsp_hscnoc", + .channels = 4, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_nsp_noc }, +}; + +static struct qcom_icc_node qns_pcie_east_mem_noc = { + .name = "qns_pcie_east_mem_noc", + .channels = 1, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_pcie_east }, +}; + +static struct qcom_icc_node qns_pcie_west_mem_noc = { + .name = "qns_pcie_west_mem_noc", + .channels = 1, + .buswidth = 64, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_pcie_west }, +}; + +static struct qcom_icc_node qns_gemnoc_sf = { + .name = "qns_gemnoc_sf", + .channels = 1, + .buswidth = 64, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_snoc_sf }, +}; + +static struct qcom_icc_node xm_usb3_0 = { + .name = "xm_usb3_0", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xa000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a4noc_hscnoc }, +}; + +static struct qcom_icc_node xm_usb3_1 = { + .name = "xm_usb3_1", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xb000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a4noc_hscnoc }, +}; + +static struct qcom_icc_node xm_usb4_0 = { + .name = "xm_usb4_0", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xc000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a4noc_hscnoc }, +}; + +static struct qcom_icc_node xm_usb4_1 = { + .name = "xm_usb4_1", + .channels = 1, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a4noc_hscnoc }, +}; + +static struct qcom_icc_node qnm_lpiaon_noc = { + .name = "qnm_lpiaon_noc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_lpass_ag_noc_gemnoc }, +}; + +static struct qcom_icc_node qnm_av1_enc = { + .name = "qnm_av1_enc", + .channels = 1, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x30000 }, + .prio = 4, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_camnoc_hf = { + .name = "qnm_camnoc_hf", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x29000, 0x2a000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf }, +}; + +static struct qcom_icc_node qnm_camnoc_icp = { + .name = "qnm_camnoc_icp", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x2b000 }, + .prio = 4, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_camnoc_sf = { + .name = "qnm_camnoc_sf", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x2c000, 0x2d000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_eva = { + .name = "qnm_eva", + .channels = 1, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x34000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_mdp = { + .name = "qnm_mdp", + .channels = 2, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 2, + .port_offsets = { 0x2e000, 0x2f000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf }, +}; + +static struct qcom_icc_node qnm_vapss_hcp = { + .name = "qnm_vapss_hcp", + .channels = 1, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_video = { + .name = "qnm_video", + .channels = 4, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 4, + .port_offsets = { 0x31000, 0x32000, 0x37000, 0x38000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_video_cv_cpu = { + .name = "qnm_video_cv_cpu", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x33000 }, + .prio = 4, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_video_v_cpu = { + .name = "qnm_video_v_cpu", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x35000 }, + .prio = 4, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf }, +}; + +static struct qcom_icc_node qnm_nsp = { + .name = "qnm_nsp", + .channels = 4, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_nsp_hscnoc }, +}; + +static struct qcom_icc_node xm_pcie_0 = { + .name = "xm_pcie_0", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xb000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_east_mem_noc }, +}; + +static struct qcom_icc_node xm_pcie_1 = { + .name = "xm_pcie_1", + .channels = 1, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xc000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_east_mem_noc }, +}; + +static struct qcom_icc_node xm_pcie_5 = { + .name = "xm_pcie_5", + .channels = 1, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_east_mem_noc }, +}; + +static struct qcom_icc_node xm_pcie_2 = { + .name = "xm_pcie_2", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_west_mem_noc }, +}; + +static struct qcom_icc_node xm_pcie_3a = { + .name = "xm_pcie_3a", + .channels = 1, + .buswidth = 64, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd200 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_west_mem_noc }, +}; + +static struct qcom_icc_node xm_pcie_3b = { + .name = "xm_pcie_3b", + .channels = 1, + .buswidth = 32, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd400 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_west_mem_noc }, +}; + +static struct qcom_icc_node xm_pcie_4 = { + .name = "xm_pcie_4", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd600 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_west_mem_noc }, +}; + +static struct qcom_icc_node xm_pcie_6 = { + .name = "xm_pcie_6", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd800 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 0, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_west_mem_noc }, +}; + +static struct qcom_icc_node qnm_aggre1_noc = { + .name = "qnm_aggre1_noc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_node qnm_aggre2_noc = { + .name = "qnm_aggre2_noc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_node qnm_aggre3_noc = { + .name = "qnm_aggre3_noc", + .channels = 1, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_node qnm_nsi_noc = { + .name = "qnm_nsi_noc", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x1c000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_node qnm_oobmss = { + .name = "qnm_oobmss", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x1b000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_node qns_a1noc_snoc = { + .name = "qns_a1noc_snoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_aggre1_noc }, +}; + +static struct qcom_icc_node qns_a2noc_snoc = { + .name = "qns_a2noc_snoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_aggre2_noc }, +}; + +static struct qcom_icc_node qns_a3noc_snoc = { + .name = "qns_a3noc_snoc", + .channels = 1, + .buswidth = 32, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_aggre3_noc }, +}; + +static struct qcom_icc_node qns_lpass_aggnoc = { + .name = "qns_lpass_aggnoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_lpiaon_noc }, +}; + +static struct qcom_icc_node qns_system_noc = { + .name = "qns_system_noc", + .channels = 1, + .buswidth = 8, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_nsi_noc }, +}; + +static struct qcom_icc_node qns_oobmss_snoc = { + .name = "qns_oobmss_snoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_oobmss }, +}; + +static struct qcom_icc_node qxm_crypto = { + .name = "qxm_crypto", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xb000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, +}; + +static struct qcom_icc_node qxm_soccp = { + .name = "qxm_soccp", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xe000 }, + .prio = 0, + .urg_fwd = 1, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, +}; + +static struct qcom_icc_node xm_qdss_etr_0 = { + .name = "xm_qdss_etr_0", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xc000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, +}; + +static struct qcom_icc_node xm_qdss_etr_1 = { + .name = "xm_qdss_etr_1", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xd000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc }, +}; + +static struct qcom_icc_node xm_ufs_mem = { + .name = "xm_ufs_mem", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0xa000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node xm_usb3_2 = { + .name = "xm_usb3_2", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x8000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node xm_usb4_2 = { + .name = "xm_usb4_2", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x9000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc }, +}; + +static struct qcom_icc_node qhm_qspi = { + .name = "qhm_qspi", + .channels = 1, + .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x10000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a3noc_snoc }, +}; + +static struct qcom_icc_node qhm_qup0 = { + .name = "qhm_qup0", + .channels = 1, + .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x11000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a3noc_snoc }, +}; + +static struct qcom_icc_node qhm_qup1 = { + .name = "qhm_qup1", + .channels = 1, + .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x12000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a3noc_snoc }, +}; + +static struct qcom_icc_node qhm_qup2 = { + .name = "qhm_qup2", + .channels = 1, + .buswidth = 4, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x13000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a3noc_snoc }, +}; + +static struct qcom_icc_node qxm_sp = { + .name = "qxm_sp", + .channels = 1, + .buswidth = 8, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a3noc_snoc }, +}; + +static struct qcom_icc_node xm_sdc2 = { + .name = "xm_sdc2", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x18000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a3noc_snoc }, +}; + +static struct qcom_icc_node xm_sdc4 = { + .name = "xm_sdc4", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x14000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a3noc_snoc }, +}; + +static struct qcom_icc_node xm_usb2_0 = { + .name = "xm_usb2_0", + .channels = 1, + .buswidth = 8, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x15000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a3noc_snoc }, +}; + +static struct qcom_icc_node xm_usb3_mp = { + .name = "xm_usb3_mp", + .channels = 1, + .buswidth = 16, + .qosbox = &(const struct qcom_icc_qosbox) { + .num_ports = 1, + .port_offsets = { 0x16000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, + }, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_a3noc_snoc }, +}; + +static struct qcom_icc_node qnm_lpass_lpinoc = { + .name = "qnm_lpass_lpinoc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_lpass_aggnoc }, +}; + +static struct qcom_icc_node xm_cpucp = { + .name = "xm_cpucp", + .channels = 1, + .buswidth = 8, + .num_links = 2, + .link_nodes = (struct qcom_icc_node *[]) { &qns_system_noc, &srvc_nsinoc }, +}; + +static struct qcom_icc_node xm_mem_sp = { + .name = "xm_mem_sp", + .channels = 1, + .buswidth = 8, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_oobmss_snoc }, +}; + +static struct qcom_icc_node qns_lpi_aon_noc = { + .name = "qns_lpi_aon_noc", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qnm_lpass_lpinoc }, +}; + +static struct qcom_icc_node qnm_lpinoc_dsp_qns4m = { + .name = "qnm_lpinoc_dsp_qns4m", + .channels = 1, + .buswidth = 16, + .num_links = 1, + .link_nodes = (struct qcom_icc_node *[]) { &qns_lpi_aon_noc }, +}; + +static struct qcom_icc_bcm bcm_acv = { + .name = "ACV", + .enable_mask = BIT(3), + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_ce0 = { + .name = "CE0", + .num_nodes = 1, + .nodes = { &qxm_crypto }, +}; + +static struct qcom_icc_bcm bcm_cn0 = { + .name = "CN0", + .keepalive = true, + .enable_mask = BIT(0), + .num_nodes = 60, + .nodes = { &qsm_cfg, &qhs_ahb2phy0, + &qhs_ahb2phy1, &qhs_ahb2phy2, + &qhs_ahb2phy3, &qhs_av1_enc_cfg, + &qhs_camera_cfg, &qhs_clk_ctl, + &qhs_crypto0_cfg, &qhs_gpuss_cfg, + &qhs_imem_cfg, &qhs_pcie0_cfg, + &qhs_pcie1_cfg, &qhs_pcie2_cfg, + &qhs_pcie3a_cfg, &qhs_pcie3b_cfg, + &qhs_pcie4_cfg, &qhs_pcie5_cfg, + &qhs_pcie6_cfg, &qhs_pcie_rscc, + &qhs_pdm, &qhs_prng, + &qhs_qdss_cfg, &qhs_qspi, + &qhs_qup0, &qhs_qup1, + &qhs_qup2, &qhs_sdc2, + &qhs_sdc4, &qhs_smmuv3_cfg, + &qhs_tcsr, &qhs_tlmm, + &qhs_ufs_mem_cfg, &qhs_usb2_0_cfg, + &qhs_usb3_0_cfg, &qhs_usb3_1_cfg, + &qhs_usb3_2_cfg, &qhs_usb3_mp_cfg, + &qhs_usb4_0_cfg, &qhs_usb4_1_cfg, + &qhs_usb4_2_cfg, &qhs_venus_cfg, + &qss_cnoc_pcie_slave_east_cfg, &qss_cnoc_pcie_slave_west_cfg, + &qss_lpass_qtb_cfg, &qss_mnoc_cfg, + &qss_nsp_qtb_cfg, &qss_pcie_east_anoc_cfg, + &qss_pcie_west_anoc_cfg, &xs_qdss_stm, + &xs_sys_tcu_cfg, &qnm_hscnoc_cnoc, + &qhs_aoss, &qhs_ipc_router, + &qhs_soccp, &qhs_tme_cfg, + &qns_apss, &qss_cfg, + &qxs_boot_imem, &qxs_imem }, +}; + +static struct qcom_icc_bcm bcm_cn1 = { + .name = "CN1", + .num_nodes = 1, + .nodes = { &qhs_display_cfg }, +}; + +static struct qcom_icc_bcm bcm_co0 = { + .name = "CO0", + .enable_mask = BIT(0), + .num_nodes = 2, + .nodes = { &qnm_nsp, &qns_nsp_hscnoc }, +}; + +static struct qcom_icc_bcm bcm_lp0 = { + .name = "LP0", + .num_nodes = 2, + .nodes = { &qnm_lpass_lpinoc, &qns_lpass_aggnoc }, +}; + +static struct qcom_icc_bcm bcm_mc0 = { + .name = "MC0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_mm0 = { + .name = "MM0", + .num_nodes = 1, + .nodes = { &qns_mem_noc_hf }, +}; + +static struct qcom_icc_bcm bcm_mm1 = { + .name = "MM1", + .enable_mask = BIT(0), + .num_nodes = 11, + .nodes = { &qnm_av1_enc, &qnm_camnoc_hf, + &qnm_camnoc_icp, &qnm_camnoc_sf, + &qnm_eva, &qnm_mdp, + &qnm_vapss_hcp, &qnm_video, + &qnm_video_cv_cpu, &qnm_video_v_cpu, + &qns_mem_noc_sf }, +}; + +static struct qcom_icc_bcm bcm_qup0 = { + .name = "QUP0", + .vote_scale = 1, + .keepalive = true, + .num_nodes = 1, + .nodes = { &qup0_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup1 = { + .name = "QUP1", + .vote_scale = 1, + .keepalive = true, + .num_nodes = 1, + .nodes = { &qup1_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup2 = { + .name = "QUP2", + .vote_scale = 1, + .keepalive = true, + .num_nodes = 1, + .nodes = { &qup2_core_slave }, +}; + +static struct qcom_icc_bcm bcm_sh0 = { + .name = "SH0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_llcc }, +}; + +static struct qcom_icc_bcm bcm_sh1 = { + .name = "SH1", + .enable_mask = BIT(0), + .num_nodes = 18, + .nodes = { &alm_gpu_tcu, &alm_pcie_qtc, + &alm_sys_tcu, &chm_apps, + &qnm_aggre_noc_east, &qnm_gpu, + &qnm_lpass, &qnm_mnoc_hf, + &qnm_mnoc_sf, &qnm_nsp_noc, + &qnm_pcie_east, &qnm_pcie_west, + &qnm_snoc_sf, &qxm_wlan_q6, + &xm_gic, &qns_hscnoc_cnoc, + &qns_pcie_east, &qns_pcie_west }, +}; + +static struct qcom_icc_bcm bcm_sn0 = { + .name = "SN0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_bcm bcm_sn1 = { + .name = "SN1", + .enable_mask = BIT(0), + .num_nodes = 1, + .nodes = { &qnm_oobmss }, +}; + +static struct qcom_icc_bcm bcm_sn2 = { + .name = "SN2", + .num_nodes = 1, + .nodes = { &qnm_aggre1_noc }, +}; + +static struct qcom_icc_bcm bcm_sn3 = { + .name = "SN3", + .num_nodes = 1, + .nodes = { &qnm_aggre2_noc }, +}; + +static struct qcom_icc_bcm bcm_sn4 = { + .name = "SN4", + .num_nodes = 1, + .nodes = { &qnm_aggre3_noc }, +}; + +static struct qcom_icc_bcm bcm_sn5 = { + .name = "SN5", + .num_nodes = 1, + .nodes = { &qns_a4noc_hscnoc }, +}; + +static struct qcom_icc_bcm bcm_sn6 = { + .name = "SN6", + .num_nodes = 4, + .nodes = { &qns_pcie_east_mem_noc, &qnm_hscnoc_pcie_east, + &qns_pcie_west_mem_noc, &qnm_hscnoc_pcie_west }, +}; + +static struct qcom_icc_bcm * const aggre1_noc_bcms[] = { + &bcm_ce0, +}; + +static struct qcom_icc_node * const aggre1_noc_nodes[] = { + [MASTER_CRYPTO] = &qxm_crypto, + [MASTER_SOCCP_PROC] = &qxm_soccp, + [MASTER_QDSS_ETR] = &xm_qdss_etr_0, + [MASTER_QDSS_ETR_1] = &xm_qdss_etr_1, + [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc, +}; + +static const struct regmap_config glymur_aggre1_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x14400, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_aggre1_noc = { + .config = &glymur_aggre1_noc_regmap_config, + .nodes = aggre1_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), + .bcms = aggre1_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre1_noc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_node * const aggre2_noc_nodes[] = { + [MASTER_UFS_MEM] = &xm_ufs_mem, + [MASTER_USB3_2] = &xm_usb3_2, + [MASTER_USB4_2] = &xm_usb4_2, + [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc, +}; + +static const struct regmap_config glymur_aggre2_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x14400, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_aggre2_noc = { + .config = &glymur_aggre2_noc_regmap_config, + .nodes = aggre2_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre2_noc_nodes), + .alloc_dyn_id = true, + .qos_requires_clocks = true, +}; + +static struct qcom_icc_node * const aggre3_noc_nodes[] = { + [MASTER_QSPI_0] = &qhm_qspi, + [MASTER_QUP_0] = &qhm_qup0, + [MASTER_QUP_1] = &qhm_qup1, + [MASTER_QUP_2] = &qhm_qup2, + [MASTER_SP] = &qxm_sp, + [MASTER_SDCC_2] = &xm_sdc2, + [MASTER_SDCC_4] = &xm_sdc4, + [MASTER_USB2] = &xm_usb2_0, + [MASTER_USB3_MP] = &xm_usb3_mp, + [SLAVE_A3NOC_SNOC] = &qns_a3noc_snoc, +}; + +static const struct regmap_config glymur_aggre3_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1d400, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_aggre3_noc = { + .config = &glymur_aggre3_noc_regmap_config, + .nodes = aggre3_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre3_noc_nodes), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const aggre4_noc_bcms[] = { + &bcm_sn5, +}; + +static struct qcom_icc_node * const aggre4_noc_nodes[] = { + [MASTER_USB3_0] = &xm_usb3_0, + [MASTER_USB3_1] = &xm_usb3_1, + [MASTER_USB4_0] = &xm_usb4_0, + [MASTER_USB4_1] = &xm_usb4_1, + [SLAVE_A4NOC_HSCNOC] = &qns_a4noc_hscnoc, +}; + +static const struct regmap_config glymur_aggre4_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x14400, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_aggre4_noc = { + .config = &glymur_aggre4_noc_regmap_config, + .nodes = aggre4_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre4_noc_nodes), + .bcms = aggre4_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre4_noc_bcms), + .alloc_dyn_id = true, + .qos_requires_clocks = true, +}; + +static struct qcom_icc_bcm * const clk_virt_bcms[] = { + &bcm_qup0, + &bcm_qup1, + &bcm_qup2, +}; + +static struct qcom_icc_node * const clk_virt_nodes[] = { + [MASTER_QUP_CORE_0] = &qup0_core_master, + [MASTER_QUP_CORE_1] = &qup1_core_master, + [MASTER_QUP_CORE_2] = &qup2_core_master, + [SLAVE_QUP_CORE_0] = &qup0_core_slave, + [SLAVE_QUP_CORE_1] = &qup1_core_slave, + [SLAVE_QUP_CORE_2] = &qup2_core_slave, +}; + +static const struct qcom_icc_desc glymur_clk_virt = { + .nodes = clk_virt_nodes, + .num_nodes = ARRAY_SIZE(clk_virt_nodes), + .bcms = clk_virt_bcms, + .num_bcms = ARRAY_SIZE(clk_virt_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const cnoc_cfg_bcms[] = { + &bcm_cn0, + &bcm_cn1, +}; + +static struct qcom_icc_node * const cnoc_cfg_nodes[] = { + [MASTER_CNOC_CFG] = &qsm_cfg, + [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy0, + [SLAVE_AHB2PHY_NORTH] = &qhs_ahb2phy1, + [SLAVE_AHB2PHY_2] = &qhs_ahb2phy2, + [SLAVE_AHB2PHY_3] = &qhs_ahb2phy3, + [SLAVE_AV1_ENC_CFG] = &qhs_av1_enc_cfg, + [SLAVE_CAMERA_CFG] = &qhs_camera_cfg, + [SLAVE_CLK_CTL] = &qhs_clk_ctl, + [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg, + [SLAVE_DISPLAY_CFG] = &qhs_display_cfg, + [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg, + [SLAVE_IMEM_CFG] = &qhs_imem_cfg, + [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg, + [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg, + [SLAVE_PCIE_2_CFG] = &qhs_pcie2_cfg, + [SLAVE_PCIE_3A_CFG] = &qhs_pcie3a_cfg, + [SLAVE_PCIE_3B_CFG] = &qhs_pcie3b_cfg, + [SLAVE_PCIE_4_CFG] = &qhs_pcie4_cfg, + [SLAVE_PCIE_5_CFG] = &qhs_pcie5_cfg, + [SLAVE_PCIE_6_CFG] = &qhs_pcie6_cfg, + [SLAVE_PCIE_RSCC] = &qhs_pcie_rscc, + [SLAVE_PDM] = &qhs_pdm, + [SLAVE_PRNG] = &qhs_prng, + [SLAVE_QDSS_CFG] = &qhs_qdss_cfg, + [SLAVE_QSPI_0] = &qhs_qspi, + [SLAVE_QUP_0] = &qhs_qup0, + [SLAVE_QUP_1] = &qhs_qup1, + [SLAVE_QUP_2] = &qhs_qup2, + [SLAVE_SDCC_2] = &qhs_sdc2, + [SLAVE_SDCC_4] = &qhs_sdc4, + [SLAVE_SMMUV3_CFG] = &qhs_smmuv3_cfg, + [SLAVE_TCSR] = &qhs_tcsr, + [SLAVE_TLMM] = &qhs_tlmm, + [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg, + [SLAVE_USB2] = &qhs_usb2_0_cfg, + [SLAVE_USB3_0] = &qhs_usb3_0_cfg, + [SLAVE_USB3_1] = &qhs_usb3_1_cfg, + [SLAVE_USB3_2] = &qhs_usb3_2_cfg, + [SLAVE_USB3_MP] = &qhs_usb3_mp_cfg, + [SLAVE_USB4_0] = &qhs_usb4_0_cfg, + [SLAVE_USB4_1] = &qhs_usb4_1_cfg, + [SLAVE_USB4_2] = &qhs_usb4_2_cfg, + [SLAVE_VENUS_CFG] = &qhs_venus_cfg, + [SLAVE_CNOC_PCIE_SLAVE_EAST_CFG] = &qss_cnoc_pcie_slave_east_cfg, + [SLAVE_CNOC_PCIE_SLAVE_WEST_CFG] = &qss_cnoc_pcie_slave_west_cfg, + [SLAVE_LPASS_QTB_CFG] = &qss_lpass_qtb_cfg, + [SLAVE_CNOC_MNOC_CFG] = &qss_mnoc_cfg, + [SLAVE_NSP_QTB_CFG] = &qss_nsp_qtb_cfg, + [SLAVE_PCIE_EAST_ANOC_CFG] = &qss_pcie_east_anoc_cfg, + [SLAVE_PCIE_WEST_ANOC_CFG] = &qss_pcie_west_anoc_cfg, + [SLAVE_QDSS_STM] = &xs_qdss_stm, + [SLAVE_TCU] = &xs_sys_tcu_cfg, +}; + +static const struct regmap_config glymur_cnoc_cfg_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x6600, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_cnoc_cfg = { + .config = &glymur_cnoc_cfg_regmap_config, + .nodes = cnoc_cfg_nodes, + .num_nodes = ARRAY_SIZE(cnoc_cfg_nodes), + .bcms = cnoc_cfg_bcms, + .num_bcms = ARRAY_SIZE(cnoc_cfg_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const cnoc_main_bcms[] = { + &bcm_cn0, +}; + +static struct qcom_icc_node * const cnoc_main_nodes[] = { + [MASTER_HSCNOC_CNOC] = &qnm_hscnoc_cnoc, + [SLAVE_AOSS] = &qhs_aoss, + [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router, + [SLAVE_SOCCP] = &qhs_soccp, + [SLAVE_TME_CFG] = &qhs_tme_cfg, + [SLAVE_APPSS] = &qns_apss, + [SLAVE_CNOC_CFG] = &qss_cfg, + [SLAVE_BOOT_IMEM] = &qxs_boot_imem, + [SLAVE_IMEM] = &qxs_imem, +}; + +static const struct regmap_config glymur_cnoc_main_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x17080, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_cnoc_main = { + .config = &glymur_cnoc_main_regmap_config, + .nodes = cnoc_main_nodes, + .num_nodes = ARRAY_SIZE(cnoc_main_nodes), + .bcms = cnoc_main_bcms, + .num_bcms = ARRAY_SIZE(cnoc_main_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const hscnoc_bcms[] = { + &bcm_sh0, + &bcm_sh1, +}; + +static struct qcom_icc_node * const hscnoc_nodes[] = { + [MASTER_GPU_TCU] = &alm_gpu_tcu, + [MASTER_PCIE_TCU] = &alm_pcie_qtc, + [MASTER_SYS_TCU] = &alm_sys_tcu, + [MASTER_APPSS_PROC] = &chm_apps, + [MASTER_AGGRE_NOC_EAST] = &qnm_aggre_noc_east, + [MASTER_GFX3D] = &qnm_gpu, + [MASTER_LPASS_GEM_NOC] = &qnm_lpass, + [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf, + [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf, + [MASTER_COMPUTE_NOC] = &qnm_nsp_noc, + [MASTER_PCIE_EAST] = &qnm_pcie_east, + [MASTER_PCIE_WEST] = &qnm_pcie_west, + [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf, + [MASTER_WLAN_Q6] = &qxm_wlan_q6, + [MASTER_GIC] = &xm_gic, + [SLAVE_HSCNOC_CNOC] = &qns_hscnoc_cnoc, + [SLAVE_LLCC] = &qns_llcc, + [SLAVE_PCIE_EAST] = &qns_pcie_east, + [SLAVE_PCIE_WEST] = &qns_pcie_west, +}; + +static const struct regmap_config glymur_hscnoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x93a080, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_hscnoc = { + .config = &glymur_hscnoc_regmap_config, + .nodes = hscnoc_nodes, + .num_nodes = ARRAY_SIZE(hscnoc_nodes), + .bcms = hscnoc_bcms, + .num_bcms = ARRAY_SIZE(hscnoc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_node * const lpass_ag_noc_nodes[] = { + [MASTER_LPIAON_NOC] = &qnm_lpiaon_noc, + [SLAVE_LPASS_GEM_NOC] = &qns_lpass_ag_noc_gemnoc, +}; + +static const struct regmap_config glymur_lpass_ag_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xe080, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_lpass_ag_noc = { + .config = &glymur_lpass_ag_noc_regmap_config, + .nodes = lpass_ag_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const lpass_lpiaon_noc_bcms[] = { + &bcm_lp0, +}; + +static struct qcom_icc_node * const lpass_lpiaon_noc_nodes[] = { + [MASTER_LPASS_LPINOC] = &qnm_lpass_lpinoc, + [SLAVE_LPIAON_NOC_LPASS_AG_NOC] = &qns_lpass_aggnoc, +}; + +static const struct regmap_config glymur_lpass_lpiaon_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x19080, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_lpass_lpiaon_noc = { + .config = &glymur_lpass_lpiaon_noc_regmap_config, + .nodes = lpass_lpiaon_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_lpiaon_noc_nodes), + .bcms = lpass_lpiaon_noc_bcms, + .num_bcms = ARRAY_SIZE(lpass_lpiaon_noc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_node * const lpass_lpicx_noc_nodes[] = { + [MASTER_LPASS_PROC] = &qnm_lpinoc_dsp_qns4m, + [SLAVE_LPICX_NOC_LPIAON_NOC] = &qns_lpi_aon_noc, +}; + +static const struct regmap_config glymur_lpass_lpicx_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x44080, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_lpass_lpicx_noc = { + .config = &glymur_lpass_lpicx_noc_regmap_config, + .nodes = lpass_lpicx_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_lpicx_noc_nodes), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const mc_virt_bcms[] = { + &bcm_acv, + &bcm_mc0, +}; + +static struct qcom_icc_node * const mc_virt_nodes[] = { + [MASTER_LLCC] = &llcc_mc, + [SLAVE_EBI1] = &ebi, +}; + +static const struct qcom_icc_desc glymur_mc_virt = { + .nodes = mc_virt_nodes, + .num_nodes = ARRAY_SIZE(mc_virt_nodes), + .bcms = mc_virt_bcms, + .num_bcms = ARRAY_SIZE(mc_virt_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const mmss_noc_bcms[] = { + &bcm_mm0, + &bcm_mm1, +}; + +static struct qcom_icc_node * const mmss_noc_nodes[] = { + [MASTER_AV1_ENC] = &qnm_av1_enc, + [MASTER_CAMNOC_HF] = &qnm_camnoc_hf, + [MASTER_CAMNOC_ICP] = &qnm_camnoc_icp, + [MASTER_CAMNOC_SF] = &qnm_camnoc_sf, + [MASTER_EVA] = &qnm_eva, + [MASTER_MDP] = &qnm_mdp, + [MASTER_CDSP_HCP] = &qnm_vapss_hcp, + [MASTER_VIDEO] = &qnm_video, + [MASTER_VIDEO_CV_PROC] = &qnm_video_cv_cpu, + [MASTER_VIDEO_V_PROC] = &qnm_video_v_cpu, + [MASTER_CNOC_MNOC_CFG] = &qsm_mnoc_cfg, + [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf, + [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf, + [SLAVE_SERVICE_MNOC] = &srvc_mnoc, +}; + +static const struct regmap_config glymur_mmss_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x5b800, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_mmss_noc = { + .config = &glymur_mmss_noc_regmap_config, + .nodes = mmss_noc_nodes, + .num_nodes = ARRAY_SIZE(mmss_noc_nodes), + .bcms = mmss_noc_bcms, + .num_bcms = ARRAY_SIZE(mmss_noc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_node * const nsinoc_nodes[] = { + [MASTER_CPUCP] = &xm_cpucp, + [SLAVE_NSINOC_SYSTEM_NOC] = &qns_system_noc, + [SLAVE_SERVICE_NSINOC] = &srvc_nsinoc, +}; + +static const struct regmap_config glymur_nsinoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x14080, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_nsinoc = { + .config = &glymur_nsinoc_regmap_config, + .nodes = nsinoc_nodes, + .num_nodes = ARRAY_SIZE(nsinoc_nodes), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const nsp_noc_bcms[] = { + &bcm_co0, +}; + +static struct qcom_icc_node * const nsp_noc_nodes[] = { + [MASTER_CDSP_PROC] = &qnm_nsp, + [SLAVE_NSP0_HSC_NOC] = &qns_nsp_hscnoc, +}; + +static const struct regmap_config glymur_nsp_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x21280, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_nsp_noc = { + .config = &glymur_nsp_noc_regmap_config, + .nodes = nsp_noc_nodes, + .num_nodes = ARRAY_SIZE(nsp_noc_nodes), + .bcms = nsp_noc_bcms, + .num_bcms = ARRAY_SIZE(nsp_noc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_node * const oobm_ss_noc_nodes[] = { + [MASTER_OOBMSS_SP_PROC] = &xm_mem_sp, + [SLAVE_OOBMSS_SNOC] = &qns_oobmss_snoc, +}; + +static const struct regmap_config glymur_oobm_ss_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1e080, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_oobm_ss_noc = { + .config = &glymur_oobm_ss_noc_regmap_config, + .nodes = oobm_ss_noc_nodes, + .num_nodes = ARRAY_SIZE(oobm_ss_noc_nodes), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const pcie_east_anoc_bcms[] = { + &bcm_sn6, +}; + +static struct qcom_icc_node * const pcie_east_anoc_nodes[] = { + [MASTER_PCIE_EAST_ANOC_CFG] = &qsm_pcie_east_anoc_cfg, + [MASTER_PCIE_0] = &xm_pcie_0, + [MASTER_PCIE_1] = &xm_pcie_1, + [MASTER_PCIE_5] = &xm_pcie_5, + [SLAVE_PCIE_EAST_MEM_NOC] = &qns_pcie_east_mem_noc, + [SLAVE_SERVICE_PCIE_EAST_AGGRE_NOC] = &srvc_pcie_east_aggre_noc, +}; + +static const struct regmap_config glymur_pcie_east_anoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xf300, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_pcie_east_anoc = { + .config = &glymur_pcie_east_anoc_regmap_config, + .nodes = pcie_east_anoc_nodes, + .num_nodes = ARRAY_SIZE(pcie_east_anoc_nodes), + .bcms = pcie_east_anoc_bcms, + .num_bcms = ARRAY_SIZE(pcie_east_anoc_bcms), + .alloc_dyn_id = true, + .qos_requires_clocks = true, +}; + +static struct qcom_icc_bcm * const pcie_east_slv_noc_bcms[] = { + &bcm_sn6, +}; + +static struct qcom_icc_node * const pcie_east_slv_noc_nodes[] = { + [MASTER_HSCNOC_PCIE_EAST] = &qnm_hscnoc_pcie_east, + [MASTER_CNOC_PCIE_EAST_SLAVE_CFG] = &qsm_cnoc_pcie_east_slave_cfg, + [SLAVE_HSCNOC_PCIE_EAST_MS_MPU_CFG] = &qhs_hscnoc_pcie_east_ms_mpu_cfg, + [SLAVE_SERVICE_PCIE_EAST] = &srvc_pcie_east, + [SLAVE_PCIE_0] = &xs_pcie_0, + [SLAVE_PCIE_1] = &xs_pcie_1, + [SLAVE_PCIE_5] = &xs_pcie_5, +}; + +static const struct regmap_config glymur_pcie_east_slv_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xe080, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_pcie_east_slv_noc = { + .config = &glymur_pcie_east_slv_noc_regmap_config, + .nodes = pcie_east_slv_noc_nodes, + .num_nodes = ARRAY_SIZE(pcie_east_slv_noc_nodes), + .bcms = pcie_east_slv_noc_bcms, + .num_bcms = ARRAY_SIZE(pcie_east_slv_noc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const pcie_west_anoc_bcms[] = { + &bcm_sn6, +}; + +static struct qcom_icc_node * const pcie_west_anoc_nodes[] = { + [MASTER_PCIE_WEST_ANOC_CFG] = &qsm_pcie_west_anoc_cfg, + [MASTER_PCIE_2] = &xm_pcie_2, + [MASTER_PCIE_3A] = &xm_pcie_3a, + [MASTER_PCIE_3B] = &xm_pcie_3b, + [MASTER_PCIE_4] = &xm_pcie_4, + [MASTER_PCIE_6] = &xm_pcie_6, + [SLAVE_PCIE_WEST_MEM_NOC] = &qns_pcie_west_mem_noc, + [SLAVE_SERVICE_PCIE_WEST_AGGRE_NOC] = &srvc_pcie_west_aggre_noc, +}; + +static const struct regmap_config glymur_pcie_west_anoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xf580, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_pcie_west_anoc = { + .config = &glymur_pcie_west_anoc_regmap_config, + .nodes = pcie_west_anoc_nodes, + .num_nodes = ARRAY_SIZE(pcie_west_anoc_nodes), + .bcms = pcie_west_anoc_bcms, + .num_bcms = ARRAY_SIZE(pcie_west_anoc_bcms), + .alloc_dyn_id = true, + .qos_requires_clocks = true, +}; + +static struct qcom_icc_bcm * const pcie_west_slv_noc_bcms[] = { + &bcm_sn6, +}; + +static struct qcom_icc_node * const pcie_west_slv_noc_nodes[] = { + [MASTER_HSCNOC_PCIE_WEST] = &qnm_hscnoc_pcie_west, + [MASTER_CNOC_PCIE_WEST_SLAVE_CFG] = &qsm_cnoc_pcie_west_slave_cfg, + [SLAVE_HSCNOC_PCIE_WEST_MS_MPU_CFG] = &qhs_hscnoc_pcie_west_ms_mpu_cfg, + [SLAVE_SERVICE_PCIE_WEST] = &srvc_pcie_west, + [SLAVE_PCIE_2] = &xs_pcie_2, + [SLAVE_PCIE_3A] = &xs_pcie_3a, + [SLAVE_PCIE_3B] = &xs_pcie_3b, + [SLAVE_PCIE_4] = &xs_pcie_4, + [SLAVE_PCIE_6] = &xs_pcie_6, +}; + +static const struct regmap_config glymur_pcie_west_slv_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xf180, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_pcie_west_slv_noc = { + .config = &glymur_pcie_west_slv_noc_regmap_config, + .nodes = pcie_west_slv_noc_nodes, + .num_nodes = ARRAY_SIZE(pcie_west_slv_noc_nodes), + .bcms = pcie_west_slv_noc_bcms, + .num_bcms = ARRAY_SIZE(pcie_west_slv_noc_bcms), + .alloc_dyn_id = true, +}; + +static struct qcom_icc_bcm * const system_noc_bcms[] = { + &bcm_sn0, + &bcm_sn1, + &bcm_sn2, + &bcm_sn3, + &bcm_sn4, +}; + +static struct qcom_icc_node * const system_noc_nodes[] = { + [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc, + [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc, + [MASTER_A3NOC_SNOC] = &qnm_aggre3_noc, + [MASTER_NSINOC_SNOC] = &qnm_nsi_noc, + [MASTER_OOBMSS] = &qnm_oobmss, + [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf, +}; + +static const struct regmap_config glymur_system_noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1c080, + .fast_io = true, +}; + +static const struct qcom_icc_desc glymur_system_noc = { + .config = &glymur_system_noc_regmap_config, + .nodes = system_noc_nodes, + .num_nodes = ARRAY_SIZE(system_noc_nodes), + .bcms = system_noc_bcms, + .num_bcms = ARRAY_SIZE(system_noc_bcms), + .alloc_dyn_id = true, +}; + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,glymur-aggre1-noc", .data = &glymur_aggre1_noc}, + { .compatible = "qcom,glymur-aggre2-noc", .data = &glymur_aggre2_noc}, + { .compatible = "qcom,glymur-aggre3-noc", .data = &glymur_aggre3_noc}, + { .compatible = "qcom,glymur-aggre4-noc", .data = &glymur_aggre4_noc}, + { .compatible = "qcom,glymur-clk-virt", .data = &glymur_clk_virt}, + { .compatible = "qcom,glymur-cnoc-cfg", .data = &glymur_cnoc_cfg}, + { .compatible = "qcom,glymur-cnoc-main", .data = &glymur_cnoc_main}, + { .compatible = "qcom,glymur-hscnoc", .data = &glymur_hscnoc}, + { .compatible = "qcom,glymur-lpass-ag-noc", .data = &glymur_lpass_ag_noc}, + { .compatible = "qcom,glymur-lpass-lpiaon-noc", .data = &glymur_lpass_lpiaon_noc}, + { .compatible = "qcom,glymur-lpass-lpicx-noc", .data = &glymur_lpass_lpicx_noc}, + { .compatible = "qcom,glymur-mc-virt", .data = &glymur_mc_virt}, + { .compatible = "qcom,glymur-mmss-noc", .data = &glymur_mmss_noc}, + { .compatible = "qcom,glymur-nsinoc", .data = &glymur_nsinoc}, + { .compatible = "qcom,glymur-nsp-noc", .data = &glymur_nsp_noc}, + { .compatible = "qcom,glymur-oobm-ss-noc", .data = &glymur_oobm_ss_noc}, + { .compatible = "qcom,glymur-pcie-east-anoc", .data = &glymur_pcie_east_anoc}, + { .compatible = "qcom,glymur-pcie-east-slv-noc", .data = &glymur_pcie_east_slv_noc}, + { .compatible = "qcom,glymur-pcie-west-anoc", .data = &glymur_pcie_west_anoc}, + { .compatible = "qcom,glymur-pcie-west-slv-noc", .data = &glymur_pcie_west_slv_noc}, + { .compatible = "qcom,glymur-system-noc", .data = &glymur_system_noc}, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, + .driver = { + .name = "qnoc-glymur", + .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, + }, +}; + +static int __init qnoc_driver_init(void) +{ + return platform_driver_register(&qnoc_driver); +} +core_initcall(qnoc_driver_init); + +static void __exit qnoc_driver_exit(void) +{ + platform_driver_unregister(&qnoc_driver); +} +module_exit(qnoc_driver_exit); + +MODULE_DESCRIPTION("GLYMUR NoC driver"); +MODULE_LICENSE("GPL"); From 0cb6f1e436accba7882bb3115408d1474c1e14af Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 1 Dec 2023 18:53:40 +0100 Subject: [PATCH 0270/2711] KVM: x86: Implement test_cc() in C Current test_cc() uses the fastop infrastructure to test flags using SETcc instructions. However, int3_emulate_jcc() already fully implements the flags->CC mapping, use that. Removes a pile of gnarly asm. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103439.637049932@infradead.org --- arch/x86/include/asm/text-patching.h | 20 ++++++++++------ arch/x86/kvm/emulate.c | 34 ++-------------------------- 2 files changed, 15 insertions(+), 39 deletions(-) diff --git a/arch/x86/include/asm/text-patching.h b/arch/x86/include/asm/text-patching.h index 5337f1be18f6..f2d142a0a862 100644 --- a/arch/x86/include/asm/text-patching.h +++ b/arch/x86/include/asm/text-patching.h @@ -178,9 +178,9 @@ void int3_emulate_ret(struct pt_regs *regs) } static __always_inline -void int3_emulate_jcc(struct pt_regs *regs, u8 cc, unsigned long ip, unsigned long disp) +bool __emulate_cc(unsigned long flags, u8 cc) { - static const unsigned long jcc_mask[6] = { + static const unsigned long cc_mask[6] = { [0] = X86_EFLAGS_OF, [1] = X86_EFLAGS_CF, [2] = X86_EFLAGS_ZF, @@ -193,15 +193,21 @@ void int3_emulate_jcc(struct pt_regs *regs, u8 cc, unsigned long ip, unsigned lo bool match; if (cc < 0xc) { - match = regs->flags & jcc_mask[cc >> 1]; + match = flags & cc_mask[cc >> 1]; } else { - match = ((regs->flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^ - ((regs->flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT); + match = ((flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^ + ((flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT); if (cc >= 0xe) - match = match || (regs->flags & X86_EFLAGS_ZF); + match = match || (flags & X86_EFLAGS_ZF); } - if ((match && !invert) || (!match && invert)) + return (match && !invert) || (!match && invert); +} + +static __always_inline +void int3_emulate_jcc(struct pt_regs *regs, u8 cc, unsigned long ip, unsigned long disp) +{ + if (__emulate_cc(regs->flags, cc)) ip += disp; int3_emulate_jmp(regs, ip); diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 1349e278cd2a..9526d692a1d6 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "x86.h" #include "tss.h" @@ -416,31 +417,6 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop); ON64(FOP3E(op##q, rax, rdx, cl)) \ FOP_END -/* Special case for SETcc - 1 instruction per cc */ -#define FOP_SETCC(op) \ - FOP_FUNC(op) \ - #op " %al \n\t" \ - FOP_RET(op) - -FOP_START(setcc) -FOP_SETCC(seto) -FOP_SETCC(setno) -FOP_SETCC(setc) -FOP_SETCC(setnc) -FOP_SETCC(setz) -FOP_SETCC(setnz) -FOP_SETCC(setbe) -FOP_SETCC(setnbe) -FOP_SETCC(sets) -FOP_SETCC(setns) -FOP_SETCC(setp) -FOP_SETCC(setnp) -FOP_SETCC(setl) -FOP_SETCC(setnl) -FOP_SETCC(setle) -FOP_SETCC(setnle) -FOP_END; - FOP_START(salc) FOP_FUNC(salc) "pushf; sbb %al, %al; popf \n\t" @@ -1068,13 +1044,7 @@ static int em_bsr_c(struct x86_emulate_ctxt *ctxt) static __always_inline u8 test_cc(unsigned int condition, unsigned long flags) { - u8 rc; - void (*fop)(void) = (void *)em_setcc + FASTOP_SIZE * (condition & 0xf); - - flags = (flags & EFLAGS_MASK) | X86_EFLAGS_IF; - asm("push %[flags]; popf; " CALL_NOSPEC - : "=a"(rc), ASM_CALL_CONSTRAINT : [thunk_target]"r"(fop), [flags]"r"(flags)); - return rc; + return __emulate_cc(flags, condition & 0xf); } static void fetch_register_operand(struct operand *op) From 6204aea36b74cd2001a142e92e492e301597eafb Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 26 Apr 2025 11:51:49 +0200 Subject: [PATCH 0271/2711] KVM: x86: Introduce EM_ASM_1 Replace fastops with C based stubs. There are a bunch of problems with the current fastop infrastructure, most all related to their special calling convention, which bypasses the normal C-ABI. There are two immediate problems with this at present: - it relies on RET preserving EFLAGS; whereas C-ABI does not. - it circumvents compiler based control-flow-integrity checking because its all asm magic. The first is a problem for some mitigations where the x86_indirect_return_thunk needs to include non-trivial work that clobbers EFLAGS (eg. the Skylake call depth tracking thing). The second is a problem because it presents a 'naked' indirect call on kCFI builds, making it a prime target for control flow hijacking. Additionally, given that a large chunk of virtual machine performance relies on absolutely avoiding vmexit these days, this emulation stuff just isn't that critical for performance anymore. As such, replace the fastop calls with normal C functions using the 'execute' member. As noted by Paolo: this code was performance critical for pre-Westmere (2010) and only when running big real mode code. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103439.773781574@infradead.org --- arch/x86/kvm/emulate.c | 71 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 9526d692a1d6..5b8a1adeb456 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -267,11 +267,56 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt) X86_EFLAGS_PF|X86_EFLAGS_CF) #ifdef CONFIG_X86_64 -#define ON64(x) x +#define ON64(x...) x #else -#define ON64(x) +#define ON64(x...) #endif +#define EM_ASM_START(op) \ +static int em_##op(struct x86_emulate_ctxt *ctxt) \ +{ \ + unsigned long flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF; \ + int bytes = 1, ok = 1; \ + if (!(ctxt->d & ByteOp)) \ + bytes = ctxt->dst.bytes; \ + switch (bytes) { + +#define __EM_ASM(str) \ + asm("push %[flags]; popf \n\t" \ + "10: " str \ + "pushf; pop %[flags] \n\t" \ + "11: \n\t" \ + : "+a" (ctxt->dst.val), \ + "+d" (ctxt->src.val), \ + [flags] "+D" (flags), \ + "+S" (ok) \ + : "c" (ctxt->src2.val)) + +#define __EM_ASM_1(op, dst) \ + __EM_ASM(#op " %%" #dst " \n\t") + +#define __EM_ASM_1_EX(op, dst) \ + __EM_ASM(#op " %%" #dst " \n\t" \ + _ASM_EXTABLE_TYPE_REG(10b, 11f, EX_TYPE_ZERO_REG, %%esi)) + +#define __EM_ASM_2(op, dst, src) \ + __EM_ASM(#op " %%" #src ", %%" #dst " \n\t") + +#define EM_ASM_END \ + } \ + ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK); \ + return !ok ? emulate_de(ctxt) : X86EMUL_CONTINUE; \ +} + +/* 1-operand, using "a" (dst) */ +#define EM_ASM_1(op) \ + EM_ASM_START(op) \ + case 1: __EM_ASM_1(op##b, al); break; \ + case 2: __EM_ASM_1(op##w, ax); break; \ + case 4: __EM_ASM_1(op##l, eax); break; \ + ON64(case 8: __EM_ASM_1(op##q, rax); break;) \ + EM_ASM_END + /* * fastop functions have a special calling convention: * @@ -1002,10 +1047,10 @@ FASTOP3WCL(shrd); FASTOP2W(imul); -FASTOP1(not); -FASTOP1(neg); -FASTOP1(inc); -FASTOP1(dec); +EM_ASM_1(not); +EM_ASM_1(neg); +EM_ASM_1(inc); +EM_ASM_1(dec); FASTOP2CL(rol); FASTOP2CL(ror); @@ -4021,8 +4066,8 @@ static const struct opcode group2[] = { static const struct opcode group3[] = { F(DstMem | SrcImm | NoWrite, em_test), F(DstMem | SrcImm | NoWrite, em_test), - F(DstMem | SrcNone | Lock, em_not), - F(DstMem | SrcNone | Lock, em_neg), + I(DstMem | SrcNone | Lock, em_not), + I(DstMem | SrcNone | Lock, em_neg), F(DstXacc | Src2Mem, em_mul_ex), F(DstXacc | Src2Mem, em_imul_ex), F(DstXacc | Src2Mem, em_div_ex), @@ -4030,14 +4075,14 @@ static const struct opcode group3[] = { }; static const struct opcode group4[] = { - F(ByteOp | DstMem | SrcNone | Lock, em_inc), - F(ByteOp | DstMem | SrcNone | Lock, em_dec), + I(ByteOp | DstMem | SrcNone | Lock, em_inc), + I(ByteOp | DstMem | SrcNone | Lock, em_dec), N, N, N, N, N, N, }; static const struct opcode group5[] = { - F(DstMem | SrcNone | Lock, em_inc), - F(DstMem | SrcNone | Lock, em_dec), + I(DstMem | SrcNone | Lock, em_inc), + I(DstMem | SrcNone | Lock, em_dec), I(SrcMem | NearBranch | IsBranch, em_call_near_abs), I(SrcMemFAddr | ImplicitOps | IsBranch, em_call_far), I(SrcMem | NearBranch | IsBranch, em_jmp_abs), @@ -4237,7 +4282,7 @@ static const struct opcode opcode_table[256] = { /* 0x38 - 0x3F */ F6ALU(NoWrite, em_cmp), N, N, /* 0x40 - 0x4F */ - X8(F(DstReg, em_inc)), X8(F(DstReg, em_dec)), + X8(I(DstReg, em_inc)), X8(I(DstReg, em_dec)), /* 0x50 - 0x57 */ X8(I(SrcReg | Stack, em_push)), /* 0x58 - 0x5F */ From b26deb0cad4af9f522496fd25dc3ebca759e65a4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 26 Apr 2025 12:25:21 +0200 Subject: [PATCH 0272/2711] KVM: x86: Introduce EM_ASM_2 Replace the FASTOP2 instructions. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103439.903697475@infradead.org --- arch/x86/kvm/emulate.c | 85 +++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 5b8a1adeb456..ec4793fe347c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -317,6 +317,15 @@ static int em_##op(struct x86_emulate_ctxt *ctxt) \ ON64(case 8: __EM_ASM_1(op##q, rax); break;) \ EM_ASM_END +/* 2-operand, using "a" (dst), "d" (src) */ +#define EM_ASM_2(op) \ + EM_ASM_START(op) \ + case 1: __EM_ASM_2(op##b, al, dl); break; \ + case 2: __EM_ASM_2(op##w, ax, dx); break; \ + case 4: __EM_ASM_2(op##l, eax, edx); break; \ + ON64(case 8: __EM_ASM_2(op##q, rax, rdx); break;) \ + EM_ASM_END + /* * fastop functions have a special calling convention: * @@ -1027,15 +1036,16 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt, return rc; } -FASTOP2(add); -FASTOP2(or); -FASTOP2(adc); -FASTOP2(sbb); -FASTOP2(and); -FASTOP2(sub); -FASTOP2(xor); -FASTOP2(cmp); -FASTOP2(test); +EM_ASM_2(add); +EM_ASM_2(or); +EM_ASM_2(adc); +EM_ASM_2(sbb); +EM_ASM_2(and); +EM_ASM_2(sub); +EM_ASM_2(xor); +EM_ASM_2(cmp); +EM_ASM_2(test); +EM_ASM_2(xadd); FASTOP1SRC2(mul, mul_ex); FASTOP1SRC2(imul, imul_ex); @@ -1067,7 +1077,6 @@ FASTOP2W(bts); FASTOP2W(btr); FASTOP2W(btc); -FASTOP2(xadd); FASTOP2R(cmp, cmp_r); @@ -2304,7 +2313,7 @@ static int em_cmpxchg(struct x86_emulate_ctxt *ctxt) ctxt->dst.val = reg_read(ctxt, VCPU_REGS_RAX); ctxt->src.orig_val = ctxt->src.val; ctxt->src.val = ctxt->dst.orig_val; - fastop(ctxt, em_cmp); + em_cmp(ctxt); if (ctxt->eflags & X86_EFLAGS_ZF) { /* Success: write back to memory; no update of EAX */ @@ -3069,7 +3078,7 @@ static int em_das(struct x86_emulate_ctxt *ctxt) ctxt->src.type = OP_IMM; ctxt->src.val = 0; ctxt->src.bytes = 1; - fastop(ctxt, em_or); + em_or(ctxt); ctxt->eflags &= ~(X86_EFLAGS_AF | X86_EFLAGS_CF); if (cf) ctxt->eflags |= X86_EFLAGS_CF; @@ -3095,7 +3104,7 @@ static int em_aam(struct x86_emulate_ctxt *ctxt) ctxt->src.type = OP_IMM; ctxt->src.val = 0; ctxt->src.bytes = 1; - fastop(ctxt, em_or); + em_or(ctxt); return X86EMUL_CONTINUE; } @@ -3113,7 +3122,7 @@ static int em_aad(struct x86_emulate_ctxt *ctxt) ctxt->src.type = OP_IMM; ctxt->src.val = 0; ctxt->src.bytes = 1; - fastop(ctxt, em_or); + em_or(ctxt); return X86EMUL_CONTINUE; } @@ -3998,9 +4007,9 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt) #define I2bvIP(_f, _e, _i, _p) \ IIP((_f) | ByteOp, _e, _i, _p), IIP(_f, _e, _i, _p) -#define F6ALU(_f, _e) F2bv((_f) | DstMem | SrcReg | ModRM, _e), \ - F2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e), \ - F2bv(((_f) & ~Lock) | DstAcc | SrcImm, _e) +#define I6ALU(_f, _e) I2bv((_f) | DstMem | SrcReg | ModRM, _e), \ + I2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e), \ + I2bv(((_f) & ~Lock) | DstAcc | SrcImm, _e) static const struct opcode group7_rm0[] = { N, @@ -4038,14 +4047,14 @@ static const struct opcode group7_rm7[] = { }; static const struct opcode group1[] = { - F(Lock, em_add), - F(Lock | PageTable, em_or), - F(Lock, em_adc), - F(Lock, em_sbb), - F(Lock | PageTable, em_and), - F(Lock, em_sub), - F(Lock, em_xor), - F(NoWrite, em_cmp), + I(Lock, em_add), + I(Lock | PageTable, em_or), + I(Lock, em_adc), + I(Lock, em_sbb), + I(Lock | PageTable, em_and), + I(Lock, em_sub), + I(Lock, em_xor), + I(NoWrite, em_cmp), }; static const struct opcode group1A[] = { @@ -4064,8 +4073,8 @@ static const struct opcode group2[] = { }; static const struct opcode group3[] = { - F(DstMem | SrcImm | NoWrite, em_test), - F(DstMem | SrcImm | NoWrite, em_test), + I(DstMem | SrcImm | NoWrite, em_test), + I(DstMem | SrcImm | NoWrite, em_test), I(DstMem | SrcNone | Lock, em_not), I(DstMem | SrcNone | Lock, em_neg), F(DstXacc | Src2Mem, em_mul_ex), @@ -4258,29 +4267,29 @@ static const struct instr_dual instr_dual_8d = { static const struct opcode opcode_table[256] = { /* 0x00 - 0x07 */ - F6ALU(Lock, em_add), + I6ALU(Lock, em_add), I(ImplicitOps | Stack | No64 | Src2ES, em_push_sreg), I(ImplicitOps | Stack | No64 | Src2ES, em_pop_sreg), /* 0x08 - 0x0F */ - F6ALU(Lock | PageTable, em_or), + I6ALU(Lock | PageTable, em_or), I(ImplicitOps | Stack | No64 | Src2CS, em_push_sreg), N, /* 0x10 - 0x17 */ - F6ALU(Lock, em_adc), + I6ALU(Lock, em_adc), I(ImplicitOps | Stack | No64 | Src2SS, em_push_sreg), I(ImplicitOps | Stack | No64 | Src2SS, em_pop_sreg), /* 0x18 - 0x1F */ - F6ALU(Lock, em_sbb), + I6ALU(Lock, em_sbb), I(ImplicitOps | Stack | No64 | Src2DS, em_push_sreg), I(ImplicitOps | Stack | No64 | Src2DS, em_pop_sreg), /* 0x20 - 0x27 */ - F6ALU(Lock | PageTable, em_and), N, N, + I6ALU(Lock | PageTable, em_and), N, N, /* 0x28 - 0x2F */ - F6ALU(Lock, em_sub), N, I(ByteOp | DstAcc | No64, em_das), + I6ALU(Lock, em_sub), N, I(ByteOp | DstAcc | No64, em_das), /* 0x30 - 0x37 */ - F6ALU(Lock, em_xor), N, N, + I6ALU(Lock, em_xor), N, N, /* 0x38 - 0x3F */ - F6ALU(NoWrite, em_cmp), N, N, + I6ALU(NoWrite, em_cmp), N, N, /* 0x40 - 0x4F */ X8(I(DstReg, em_inc)), X8(I(DstReg, em_dec)), /* 0x50 - 0x57 */ @@ -4306,7 +4315,7 @@ static const struct opcode opcode_table[256] = { G(DstMem | SrcImm, group1), G(ByteOp | DstMem | SrcImm | No64, group1), G(DstMem | SrcImmByte, group1), - F2bv(DstMem | SrcReg | ModRM | NoWrite, em_test), + I2bv(DstMem | SrcReg | ModRM | NoWrite, em_test), I2bv(DstMem | SrcReg | ModRM | Lock | PageTable, em_xchg), /* 0x88 - 0x8F */ I2bv(DstMem | SrcReg | ModRM | Mov | PageTable, em_mov), @@ -4329,7 +4338,7 @@ static const struct opcode opcode_table[256] = { I2bv(SrcSI | DstDI | Mov | String | TwoMemOp, em_mov), F2bv(SrcSI | DstDI | String | NoWrite | TwoMemOp, em_cmp_r), /* 0xA8 - 0xAF */ - F2bv(DstAcc | SrcImm | NoWrite, em_test), + I2bv(DstAcc | SrcImm | NoWrite, em_test), I2bv(SrcAcc | DstDI | Mov | String, em_mov), I2bv(SrcSI | DstAcc | Mov | String, em_mov), F2bv(SrcAcc | DstDI | String | NoWrite, em_cmp_r), @@ -4467,7 +4476,7 @@ static const struct opcode twobyte_table[256] = { I(DstReg | SrcMem | ModRM, em_bsr_c), D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov), /* 0xC0 - 0xC7 */ - F2bv(DstMem | SrcReg | ModRM | SrcWrite | Lock, em_xadd), + I2bv(DstMem | SrcReg | ModRM | SrcWrite | Lock, em_xadd), N, ID(0, &instr_dual_0f_c3), N, N, N, GD(0, &group9), /* 0xC8 - 0xCF */ From 2df2b52c98db03c10ebe93fa270b1e2baf47f8a0 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 26 Apr 2025 12:52:05 +0200 Subject: [PATCH 0273/2711] KVM: x86: Introduce EM_ASM_2R Replace the FASTOP2R instruction. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103440.024933524@infradead.org --- arch/x86/kvm/emulate.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index ec4793fe347c..7af30efe15c9 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -326,6 +326,15 @@ static int em_##op(struct x86_emulate_ctxt *ctxt) \ ON64(case 8: __EM_ASM_2(op##q, rax, rdx); break;) \ EM_ASM_END +/* 2-operand, reversed */ +#define EM_ASM_2R(op, name) \ + EM_ASM_START(name) \ + case 1: __EM_ASM_2(op##b, dl, al); break; \ + case 2: __EM_ASM_2(op##w, dx, ax); break; \ + case 4: __EM_ASM_2(op##l, edx, eax); break; \ + ON64(case 8: __EM_ASM_2(op##q, rdx, rax); break;) \ + EM_ASM_END + /* * fastop functions have a special calling convention: * @@ -1077,8 +1086,7 @@ FASTOP2W(bts); FASTOP2W(btr); FASTOP2W(btc); - -FASTOP2R(cmp, cmp_r); +EM_ASM_2R(cmp, cmp_r); static int em_bsf_c(struct x86_emulate_ctxt *ctxt) { @@ -4336,12 +4344,12 @@ static const struct opcode opcode_table[256] = { I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov), I2bv(DstMem | SrcAcc | Mov | MemAbs | PageTable, em_mov), I2bv(SrcSI | DstDI | Mov | String | TwoMemOp, em_mov), - F2bv(SrcSI | DstDI | String | NoWrite | TwoMemOp, em_cmp_r), + I2bv(SrcSI | DstDI | String | NoWrite | TwoMemOp, em_cmp_r), /* 0xA8 - 0xAF */ I2bv(DstAcc | SrcImm | NoWrite, em_test), I2bv(SrcAcc | DstDI | Mov | String, em_mov), I2bv(SrcSI | DstAcc | Mov | String, em_mov), - F2bv(SrcAcc | DstDI | String | NoWrite, em_cmp_r), + I2bv(SrcAcc | DstDI | String | NoWrite, em_cmp_r), /* 0xB0 - 0xB7 */ X8(I(ByteOp | DstReg | SrcImm | Mov, em_mov)), /* 0xB8 - 0xBF */ From 975e51783cfd0abc303817e8bf1ab2f630834c2a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 26 Apr 2025 12:30:37 +0200 Subject: [PATCH 0274/2711] KVM: x86: Introduce EM_ASM_2W Replace the FASTOP2W instructions. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103440.142923581@infradead.org --- arch/x86/kvm/emulate.c | 47 +++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 7af30efe15c9..05a97ece5a99 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -335,6 +335,15 @@ static int em_##op(struct x86_emulate_ctxt *ctxt) \ ON64(case 8: __EM_ASM_2(op##q, rdx, rax); break;) \ EM_ASM_END +/* 2-operand, word only (no byte op) */ +#define EM_ASM_2W(op) \ + EM_ASM_START(op) \ + case 1: break; \ + case 2: __EM_ASM_2(op##w, ax, dx); break; \ + case 4: __EM_ASM_2(op##l, eax, edx); break; \ + ON64(case 8: __EM_ASM_2(op##q, rax, rdx); break;) \ + EM_ASM_END + /* * fastop functions have a special calling convention: * @@ -1064,7 +1073,7 @@ FASTOP1SRC2EX(idiv, idiv_ex); FASTOP3WCL(shld); FASTOP3WCL(shrd); -FASTOP2W(imul); +EM_ASM_2W(imul); EM_ASM_1(not); EM_ASM_1(neg); @@ -1079,12 +1088,12 @@ FASTOP2CL(shl); FASTOP2CL(shr); FASTOP2CL(sar); -FASTOP2W(bsf); -FASTOP2W(bsr); -FASTOP2W(bt); -FASTOP2W(bts); -FASTOP2W(btr); -FASTOP2W(btc); +EM_ASM_2W(bsf); +EM_ASM_2W(bsr); +EM_ASM_2W(bt); +EM_ASM_2W(bts); +EM_ASM_2W(btr); +EM_ASM_2W(btc); EM_ASM_2R(cmp, cmp_r); @@ -1093,7 +1102,7 @@ static int em_bsf_c(struct x86_emulate_ctxt *ctxt) /* If src is zero, do not writeback, but update flags */ if (ctxt->src.val == 0) ctxt->dst.type = OP_NONE; - return fastop(ctxt, em_bsf); + return em_bsf(ctxt); } static int em_bsr_c(struct x86_emulate_ctxt *ctxt) @@ -1101,7 +1110,7 @@ static int em_bsr_c(struct x86_emulate_ctxt *ctxt) /* If src is zero, do not writeback, but update flags */ if (ctxt->src.val == 0) ctxt->dst.type = OP_NONE; - return fastop(ctxt, em_bsr); + return em_bsr(ctxt); } static __always_inline u8 test_cc(unsigned int condition, unsigned long flags) @@ -3221,7 +3230,7 @@ static int em_xchg(struct x86_emulate_ctxt *ctxt) static int em_imul_3op(struct x86_emulate_ctxt *ctxt) { ctxt->dst.val = ctxt->src2.val; - return fastop(ctxt, em_imul); + return em_imul(ctxt); } static int em_cwd(struct x86_emulate_ctxt *ctxt) @@ -4135,10 +4144,10 @@ static const struct group_dual group7 = { { static const struct opcode group8[] = { N, N, N, N, - F(DstMem | SrcImmByte | NoWrite, em_bt), - F(DstMem | SrcImmByte | Lock | PageTable, em_bts), - F(DstMem | SrcImmByte | Lock, em_btr), - F(DstMem | SrcImmByte | Lock | PageTable, em_btc), + I(DstMem | SrcImmByte | NoWrite, em_bt), + I(DstMem | SrcImmByte | Lock | PageTable, em_bts), + I(DstMem | SrcImmByte | Lock, em_btr), + I(DstMem | SrcImmByte | Lock | PageTable, em_btc), }; /* @@ -4459,27 +4468,27 @@ static const struct opcode twobyte_table[256] = { /* 0xA0 - 0xA7 */ I(Stack | Src2FS, em_push_sreg), I(Stack | Src2FS, em_pop_sreg), II(ImplicitOps, em_cpuid, cpuid), - F(DstMem | SrcReg | ModRM | BitOp | NoWrite, em_bt), + I(DstMem | SrcReg | ModRM | BitOp | NoWrite, em_bt), F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shld), F(DstMem | SrcReg | Src2CL | ModRM, em_shld), N, N, /* 0xA8 - 0xAF */ I(Stack | Src2GS, em_push_sreg), I(Stack | Src2GS, em_pop_sreg), II(EmulateOnUD | ImplicitOps, em_rsm, rsm), - F(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_bts), + I(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_bts), F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shrd), F(DstMem | SrcReg | Src2CL | ModRM, em_shrd), - GD(0, &group15), F(DstReg | SrcMem | ModRM, em_imul), + GD(0, &group15), I(DstReg | SrcMem | ModRM, em_imul), /* 0xB0 - 0xB7 */ I2bv(DstMem | SrcReg | ModRM | Lock | PageTable | SrcWrite, em_cmpxchg), I(DstReg | SrcMemFAddr | ModRM | Src2SS, em_lseg), - F(DstMem | SrcReg | ModRM | BitOp | Lock, em_btr), + I(DstMem | SrcReg | ModRM | BitOp | Lock, em_btr), I(DstReg | SrcMemFAddr | ModRM | Src2FS, em_lseg), I(DstReg | SrcMemFAddr | ModRM | Src2GS, em_lseg), D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov), /* 0xB8 - 0xBF */ N, N, G(BitOp, group8), - F(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_btc), + I(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_btc), I(DstReg | SrcMem | ModRM, em_bsf_c), I(DstReg | SrcMem | ModRM, em_bsr_c), D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov), From 67e944aff63cb6b9c236d9cc2b4d870aeefd306f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 26 Apr 2025 12:34:42 +0200 Subject: [PATCH 0275/2711] KVM: x86: Introduce EM_ASM_2CL Replace the FASTOP2CL instructions. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103440.251039692@infradead.org --- arch/x86/kvm/emulate.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 05a97ece5a99..9a7854093981 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -344,6 +344,15 @@ static int em_##op(struct x86_emulate_ctxt *ctxt) \ ON64(case 8: __EM_ASM_2(op##q, rax, rdx); break;) \ EM_ASM_END +/* 2-operand, using "a" (dst) and CL (src2) */ +#define EM_ASM_2CL(op) \ + EM_ASM_START(op) \ + case 1: __EM_ASM_2(op##b, al, cl); break; \ + case 2: __EM_ASM_2(op##w, ax, cl); break; \ + case 4: __EM_ASM_2(op##l, eax, cl); break; \ + ON64(case 8: __EM_ASM_2(op##q, rax, cl); break;) \ + EM_ASM_END + /* * fastop functions have a special calling convention: * @@ -1080,13 +1089,13 @@ EM_ASM_1(neg); EM_ASM_1(inc); EM_ASM_1(dec); -FASTOP2CL(rol); -FASTOP2CL(ror); -FASTOP2CL(rcl); -FASTOP2CL(rcr); -FASTOP2CL(shl); -FASTOP2CL(shr); -FASTOP2CL(sar); +EM_ASM_2CL(rol); +EM_ASM_2CL(ror); +EM_ASM_2CL(rcl); +EM_ASM_2CL(rcr); +EM_ASM_2CL(shl); +EM_ASM_2CL(shr); +EM_ASM_2CL(sar); EM_ASM_2W(bsf); EM_ASM_2W(bsr); @@ -4079,14 +4088,14 @@ static const struct opcode group1A[] = { }; static const struct opcode group2[] = { - F(DstMem | ModRM, em_rol), - F(DstMem | ModRM, em_ror), - F(DstMem | ModRM, em_rcl), - F(DstMem | ModRM, em_rcr), - F(DstMem | ModRM, em_shl), - F(DstMem | ModRM, em_shr), - F(DstMem | ModRM, em_shl), - F(DstMem | ModRM, em_sar), + I(DstMem | ModRM, em_rol), + I(DstMem | ModRM, em_ror), + I(DstMem | ModRM, em_rcl), + I(DstMem | ModRM, em_rcr), + I(DstMem | ModRM, em_shl), + I(DstMem | ModRM, em_shr), + I(DstMem | ModRM, em_shl), + I(DstMem | ModRM, em_sar), }; static const struct opcode group3[] = { From af4fe07aa1e07610d3208a85210b896c87e2105e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 26 Apr 2025 12:40:12 +0200 Subject: [PATCH 0276/2711] KVM: x86: Introduce EM_ASM_1SRC2 Replace the FASTOP1SRC2*() instructions. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103440.394654786@infradead.org --- arch/x86/kvm/emulate.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 9a7854093981..beac2f4c4744 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -317,6 +317,24 @@ static int em_##op(struct x86_emulate_ctxt *ctxt) \ ON64(case 8: __EM_ASM_1(op##q, rax); break;) \ EM_ASM_END +/* 1-operand, using "c" (src2) */ +#define EM_ASM_1SRC2(op, name) \ + EM_ASM_START(name) \ + case 1: __EM_ASM_1(op##b, cl); break; \ + case 2: __EM_ASM_1(op##w, cx); break; \ + case 4: __EM_ASM_1(op##l, ecx); break; \ + ON64(case 8: __EM_ASM_1(op##q, rcx); break;) \ + EM_ASM_END + +/* 1-operand, using "c" (src2) with exception */ +#define EM_ASM_1SRC2EX(op, name) \ + EM_ASM_START(name) \ + case 1: __EM_ASM_1_EX(op##b, cl); break; \ + case 2: __EM_ASM_1_EX(op##w, cx); break; \ + case 4: __EM_ASM_1_EX(op##l, ecx); break; \ + ON64(case 8: __EM_ASM_1_EX(op##q, rcx); break;) \ + EM_ASM_END + /* 2-operand, using "a" (dst), "d" (src) */ #define EM_ASM_2(op) \ EM_ASM_START(op) \ @@ -1074,10 +1092,10 @@ EM_ASM_2(cmp); EM_ASM_2(test); EM_ASM_2(xadd); -FASTOP1SRC2(mul, mul_ex); -FASTOP1SRC2(imul, imul_ex); -FASTOP1SRC2EX(div, div_ex); -FASTOP1SRC2EX(idiv, idiv_ex); +EM_ASM_1SRC2(mul, mul_ex); +EM_ASM_1SRC2(imul, imul_ex); +EM_ASM_1SRC2EX(div, div_ex); +EM_ASM_1SRC2EX(idiv, idiv_ex); FASTOP3WCL(shld); FASTOP3WCL(shrd); @@ -4103,10 +4121,10 @@ static const struct opcode group3[] = { I(DstMem | SrcImm | NoWrite, em_test), I(DstMem | SrcNone | Lock, em_not), I(DstMem | SrcNone | Lock, em_neg), - F(DstXacc | Src2Mem, em_mul_ex), - F(DstXacc | Src2Mem, em_imul_ex), - F(DstXacc | Src2Mem, em_div_ex), - F(DstXacc | Src2Mem, em_idiv_ex), + I(DstXacc | Src2Mem, em_mul_ex), + I(DstXacc | Src2Mem, em_imul_ex), + I(DstXacc | Src2Mem, em_div_ex), + I(DstXacc | Src2Mem, em_idiv_ex), }; static const struct opcode group4[] = { From 2d82acd7d6a7eba2ed2bf84ab7440c1ad7c27958 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 26 Apr 2025 12:47:50 +0200 Subject: [PATCH 0277/2711] KVM: x86: Introduce EM_ASM_3WCL Replace the FASTOP3WCL instructions. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103440.513865075@infradead.org --- arch/x86/kvm/emulate.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index beac2f4c4744..390b8a93cd2c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -302,6 +302,9 @@ static int em_##op(struct x86_emulate_ctxt *ctxt) \ #define __EM_ASM_2(op, dst, src) \ __EM_ASM(#op " %%" #src ", %%" #dst " \n\t") +#define __EM_ASM_3(op, dst, src, src2) \ + __EM_ASM(#op " %%" #src2 ", %%" #src ", %%" #dst " \n\t") + #define EM_ASM_END \ } \ ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK); \ @@ -371,6 +374,16 @@ static int em_##op(struct x86_emulate_ctxt *ctxt) \ ON64(case 8: __EM_ASM_2(op##q, rax, cl); break;) \ EM_ASM_END +/* 3-operand, using "a" (dst), "d" (src) and CL (src2) */ +#define EM_ASM_3WCL(op) \ + EM_ASM_START(op) \ + case 1: break; \ + case 2: __EM_ASM_3(op##w, ax, dx, cl); break; \ + case 4: __EM_ASM_3(op##l, eax, edx, cl); break; \ + ON64(case 8: __EM_ASM_3(op##q, rax, rdx, cl); break;) \ + EM_ASM_END + + /* * fastop functions have a special calling convention: * @@ -1097,8 +1110,8 @@ EM_ASM_1SRC2(imul, imul_ex); EM_ASM_1SRC2EX(div, div_ex); EM_ASM_1SRC2EX(idiv, idiv_ex); -FASTOP3WCL(shld); -FASTOP3WCL(shrd); +EM_ASM_3WCL(shld); +EM_ASM_3WCL(shrd); EM_ASM_2W(imul); @@ -4496,14 +4509,14 @@ static const struct opcode twobyte_table[256] = { I(Stack | Src2FS, em_push_sreg), I(Stack | Src2FS, em_pop_sreg), II(ImplicitOps, em_cpuid, cpuid), I(DstMem | SrcReg | ModRM | BitOp | NoWrite, em_bt), - F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shld), - F(DstMem | SrcReg | Src2CL | ModRM, em_shld), N, N, + I(DstMem | SrcReg | Src2ImmByte | ModRM, em_shld), + I(DstMem | SrcReg | Src2CL | ModRM, em_shld), N, N, /* 0xA8 - 0xAF */ I(Stack | Src2GS, em_push_sreg), I(Stack | Src2GS, em_pop_sreg), II(EmulateOnUD | ImplicitOps, em_rsm, rsm), I(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_bts), - F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shrd), - F(DstMem | SrcReg | Src2CL | ModRM, em_shrd), + I(DstMem | SrcReg | Src2ImmByte | ModRM, em_shrd), + I(DstMem | SrcReg | Src2CL | ModRM, em_shrd), GD(0, &group15), I(DstReg | SrcMem | ModRM, em_imul), /* 0xB0 - 0xB7 */ I2bv(DstMem | SrcReg | ModRM | Lock | PageTable | SrcWrite, em_cmpxchg), From 77892e1fef34db650aa3de4be1d27267ca7f1330 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 26 Apr 2025 13:07:14 +0200 Subject: [PATCH 0278/2711] KVM: x86: Convert em_salc() to C Implement the SALC (Set AL if Carry) instruction in C. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103440.634145269@infradead.org --- arch/x86/kvm/emulate.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 390b8a93cd2c..94008cd12f1e 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -529,11 +529,14 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop); ON64(FOP3E(op##q, rax, rdx, cl)) \ FOP_END -FOP_START(salc) -FOP_FUNC(salc) -"pushf; sbb %al, %al; popf \n\t" -FOP_RET(salc) -FOP_END; +static int em_salc(struct x86_emulate_ctxt *ctxt) +{ + /* + * Set AL 0xFF if CF is set, or 0x00 when clear. + */ + ctxt->dst.val = 0xFF * !!(ctxt->eflags & X86_EFLAGS_CF); + return X86EMUL_CONTINUE; +} /* * XXX: inoutclob user must know where the argument is being expanded. @@ -4423,7 +4426,7 @@ static const struct opcode opcode_table[256] = { G(Src2CL | ByteOp, group2), G(Src2CL, group2), I(DstAcc | SrcImmUByte | No64, em_aam), I(DstAcc | SrcImmUByte | No64, em_aad), - F(DstAcc | ByteOp | No64, em_salc), + I(DstAcc | ByteOp | No64, em_salc), I(DstAcc | SrcXLat | ByteOp, em_mov), /* 0xD8 - 0xDF */ N, E(0, &escape_d9), N, E(0, &escape_db), N, E(0, &escape_dd), N, N, From a1d34a444ce8c9a6ec4376247f80f0b777c6d3fe Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 26 Apr 2025 12:55:35 +0200 Subject: [PATCH 0279/2711] KVM: x86: Remove fastops No more FASTOPs, remove the remains. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103440.751192860@infradead.org --- arch/x86/kvm/emulate.c | 172 +---------------------------------------- 1 file changed, 1 insertion(+), 171 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 94008cd12f1e..796d0c64f9ba 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -167,7 +167,6 @@ #define Unaligned ((u64)2 << 41) /* Explicitly unaligned (e.g. MOVDQU) */ #define Avx ((u64)3 << 41) /* Advanced Vector Extensions */ #define Aligned16 ((u64)4 << 41) /* Aligned to 16 byte boundary (e.g. FXSAVE) */ -#define Fastop ((u64)1 << 44) /* Use opcode::u.fastop */ #define NoWrite ((u64)1 << 45) /* No writeback */ #define SrcWrite ((u64)1 << 46) /* Write back src operand */ #define NoMod ((u64)1 << 47) /* Mod field is ignored */ @@ -203,7 +202,6 @@ struct opcode { const struct escape *esc; const struct instr_dual *idual; const struct mode_dual *mdual; - void (*fastop)(struct fastop *fake); } u; int (*check_perm)(struct x86_emulate_ctxt *ctxt); }; @@ -383,152 +381,6 @@ static int em_##op(struct x86_emulate_ctxt *ctxt) \ ON64(case 8: __EM_ASM_3(op##q, rax, rdx, cl); break;) \ EM_ASM_END - -/* - * fastop functions have a special calling convention: - * - * dst: rax (in/out) - * src: rdx (in/out) - * src2: rcx (in) - * flags: rflags (in/out) - * ex: rsi (in:fastop pointer, out:zero if exception) - * - * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for - * different operand sizes can be reached by calculation, rather than a jump - * table (which would be bigger than the code). - * - * The 16 byte alignment, considering 5 bytes for the RET thunk, 3 for ENDBR - * and 1 for the straight line speculation INT3, leaves 7 bytes for the - * body of the function. Currently none is larger than 4. - */ -static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop); - -#define FASTOP_SIZE 16 - -#define __FOP_FUNC(name) \ - ".align " __stringify(FASTOP_SIZE) " \n\t" \ - ".type " name ", @function \n\t" \ - name ":\n\t" \ - ASM_ENDBR \ - IBT_NOSEAL(name) - -#define FOP_FUNC(name) \ - __FOP_FUNC(#name) - -#define __FOP_RET(name) \ - "11: " ASM_RET \ - ".size " name ", .-" name "\n\t" - -#define FOP_RET(name) \ - __FOP_RET(#name) - -#define __FOP_START(op, align) \ - extern void em_##op(struct fastop *fake); \ - asm(".pushsection .text, \"ax\" \n\t" \ - ".global em_" #op " \n\t" \ - ".align " __stringify(align) " \n\t" \ - "em_" #op ":\n\t" - -#define FOP_START(op) __FOP_START(op, FASTOP_SIZE) - -#define FOP_END \ - ".popsection") - -#define __FOPNOP(name) \ - __FOP_FUNC(name) \ - __FOP_RET(name) - -#define FOPNOP() \ - __FOPNOP(__stringify(__UNIQUE_ID(nop))) - -#define FOP1E(op, dst) \ - __FOP_FUNC(#op "_" #dst) \ - "10: " #op " %" #dst " \n\t" \ - __FOP_RET(#op "_" #dst) - -#define FOP1EEX(op, dst) \ - FOP1E(op, dst) _ASM_EXTABLE_TYPE_REG(10b, 11b, EX_TYPE_ZERO_REG, %%esi) - -#define FASTOP1(op) \ - FOP_START(op) \ - FOP1E(op##b, al) \ - FOP1E(op##w, ax) \ - FOP1E(op##l, eax) \ - ON64(FOP1E(op##q, rax)) \ - FOP_END - -/* 1-operand, using src2 (for MUL/DIV r/m) */ -#define FASTOP1SRC2(op, name) \ - FOP_START(name) \ - FOP1E(op, cl) \ - FOP1E(op, cx) \ - FOP1E(op, ecx) \ - ON64(FOP1E(op, rcx)) \ - FOP_END - -/* 1-operand, using src2 (for MUL/DIV r/m), with exceptions */ -#define FASTOP1SRC2EX(op, name) \ - FOP_START(name) \ - FOP1EEX(op, cl) \ - FOP1EEX(op, cx) \ - FOP1EEX(op, ecx) \ - ON64(FOP1EEX(op, rcx)) \ - FOP_END - -#define FOP2E(op, dst, src) \ - __FOP_FUNC(#op "_" #dst "_" #src) \ - #op " %" #src ", %" #dst " \n\t" \ - __FOP_RET(#op "_" #dst "_" #src) - -#define FASTOP2(op) \ - FOP_START(op) \ - FOP2E(op##b, al, dl) \ - FOP2E(op##w, ax, dx) \ - FOP2E(op##l, eax, edx) \ - ON64(FOP2E(op##q, rax, rdx)) \ - FOP_END - -/* 2 operand, word only */ -#define FASTOP2W(op) \ - FOP_START(op) \ - FOPNOP() \ - FOP2E(op##w, ax, dx) \ - FOP2E(op##l, eax, edx) \ - ON64(FOP2E(op##q, rax, rdx)) \ - FOP_END - -/* 2 operand, src is CL */ -#define FASTOP2CL(op) \ - FOP_START(op) \ - FOP2E(op##b, al, cl) \ - FOP2E(op##w, ax, cl) \ - FOP2E(op##l, eax, cl) \ - ON64(FOP2E(op##q, rax, cl)) \ - FOP_END - -/* 2 operand, src and dest are reversed */ -#define FASTOP2R(op, name) \ - FOP_START(name) \ - FOP2E(op##b, dl, al) \ - FOP2E(op##w, dx, ax) \ - FOP2E(op##l, edx, eax) \ - ON64(FOP2E(op##q, rdx, rax)) \ - FOP_END - -#define FOP3E(op, dst, src, src2) \ - __FOP_FUNC(#op "_" #dst "_" #src "_" #src2) \ - #op " %" #src2 ", %" #src ", %" #dst " \n\t"\ - __FOP_RET(#op "_" #dst "_" #src "_" #src2) - -/* 3-operand, word-only, src2=cl */ -#define FASTOP3WCL(op) \ - FOP_START(op) \ - FOPNOP() \ - FOP3E(op##w, ax, dx, cl) \ - FOP3E(op##l, eax, edx, cl) \ - ON64(FOP3E(op##q, rax, rdx, cl)) \ - FOP_END - static int em_salc(struct x86_emulate_ctxt *ctxt) { /* @@ -4052,7 +3904,6 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt) #define MD(_f, _m) { .flags = ((_f) | ModeDual), .u.mdual = (_m) } #define E(_f, _e) { .flags = ((_f) | Escape | ModRM), .u.esc = (_e) } #define I(_f, _e) { .flags = (_f), .u.execute = (_e) } -#define F(_f, _e) { .flags = (_f) | Fastop, .u.fastop = (_e) } #define II(_f, _e, _i) \ { .flags = (_f)|Intercept, .u.execute = (_e), .intercept = x86_intercept_##_i } #define IIP(_f, _e, _i, _p) \ @@ -5158,24 +5009,6 @@ static void fetch_possible_mmx_operand(struct operand *op) kvm_read_mmx_reg(op->addr.mm, &op->mm_val); } -static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop) -{ - ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF; - - if (!(ctxt->d & ByteOp)) - fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE; - - asm("push %[flags]; popf; " CALL_NOSPEC " ; pushf; pop %[flags]\n" - : "+a"(ctxt->dst.val), "+d"(ctxt->src.val), [flags]"+D"(flags), - [thunk_target]"+S"(fop), ASM_CALL_CONSTRAINT - : "c"(ctxt->src2.val)); - - ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK); - if (!fop) /* exception is returned in fop variable */ - return emulate_de(ctxt); - return X86EMUL_CONTINUE; -} - void init_decode_cache(struct x86_emulate_ctxt *ctxt) { /* Clear fields that are set conditionally but read without a guard. */ @@ -5340,10 +5173,7 @@ special_insn: ctxt->eflags &= ~X86_EFLAGS_RF; if (ctxt->execute) { - if (ctxt->d & Fastop) - rc = fastop(ctxt, ctxt->fop); - else - rc = ctxt->execute(ctxt); + rc = ctxt->execute(ctxt); if (rc != X86EMUL_CONTINUE) goto done; goto writeback; From 0e20f1f4c2cb77130cfe903a058a08883645dc4b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 12 Apr 2025 13:55:49 +0200 Subject: [PATCH 0280/2711] x86/hyperv: Clean up hv_do_hypercall() What used to be a simple few instructions has turned into a giant mess (for x86_64). Not only does it use static_branch wrong, it mixes it with dynamic branches for no apparent reason. Notably it uses static_branch through an out-of-line function call, which completely defeats the purpose, since instead of a simple JMP/NOP site, you get a CALL+RET+TEST+Jcc sequence in return, which is absolutely idiotic. Add to that a dynamic test of hyperv_paravisor_present, something which is set once and never changed. Replace all this idiocy with a single direct function call to the right hypercall variant. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Michael Kelley Tested-by: Michael Kelley Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103440.897136093@infradead.org --- arch/x86/hyperv/hv_init.c | 20 +++++ arch/x86/hyperv/ivm.c | 15 ++++ arch/x86/include/asm/mshyperv.h | 137 ++++++++++---------------------- arch/x86/kernel/cpu/mshyperv.c | 19 +++-- 4 files changed, 89 insertions(+), 102 deletions(-) diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index afdbda2dd7b7..5ef1e647ebc0 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -37,7 +37,27 @@ #include void *hv_hypercall_pg; + +#ifdef CONFIG_X86_64 +u64 hv_std_hypercall(u64 control, u64 param1, u64 param2) +{ + u64 hv_status; + + if (!hv_hypercall_pg) + return U64_MAX; + + register u64 __r8 asm("r8") = param2; + asm volatile (CALL_NOSPEC + : "=a" (hv_status), ASM_CALL_CONSTRAINT, + "+c" (control), "+d" (param1), "+r" (__r8) + : THUNK_TARGET(hv_hypercall_pg) + : "cc", "memory", "r9", "r10", "r11"); + + return hv_status; +} +#else EXPORT_SYMBOL_GPL(hv_hypercall_pg); +#endif union hv_ghcb * __percpu *hv_ghcb_pg; diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c index ade6c665c97e..21042fa49088 100644 --- a/arch/x86/hyperv/ivm.c +++ b/arch/x86/hyperv/ivm.c @@ -385,9 +385,23 @@ int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu) return ret; } +u64 hv_snp_hypercall(u64 control, u64 param1, u64 param2) +{ + u64 hv_status; + + register u64 __r8 asm("r8") = param2; + asm volatile("vmmcall" + : "=a" (hv_status), ASM_CALL_CONSTRAINT, + "+c" (control), "+d" (param1), "+r" (__r8) + : : "cc", "memory", "r9", "r10", "r11"); + + return hv_status; +} + #else static inline void hv_ghcb_msr_write(u64 msr, u64 value) {} static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {} +u64 hv_snp_hypercall(u64 control, u64 param1, u64 param2) { return U64_MAX; } #endif /* CONFIG_AMD_MEM_ENCRYPT */ #ifdef CONFIG_INTEL_TDX_GUEST @@ -437,6 +451,7 @@ u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2) #else static inline void hv_tdx_msr_write(u64 msr, u64 value) {} static inline void hv_tdx_msr_read(u64 msr, u64 *value) {} +u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2) { return U64_MAX; } #endif /* CONFIG_INTEL_TDX_GUEST */ #if defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST) diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index abc4659f5809..605abd02158d 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -39,16 +40,21 @@ static inline unsigned char hv_get_nmi_reason(void) return 0; } -#if IS_ENABLED(CONFIG_HYPERV) -extern bool hyperv_paravisor_present; +extern u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2); +extern u64 hv_snp_hypercall(u64 control, u64 param1, u64 param2); +extern u64 hv_std_hypercall(u64 control, u64 param1, u64 param2); +#if IS_ENABLED(CONFIG_HYPERV) extern void *hv_hypercall_pg; extern union hv_ghcb * __percpu *hv_ghcb_pg; bool hv_isolation_type_snp(void); bool hv_isolation_type_tdx(void); -u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2); + +#ifdef CONFIG_X86_64 +DECLARE_STATIC_CALL(hv_hypercall, hv_std_hypercall); +#endif /* * DEFAULT INIT GPAT and SEGMENT LIMIT value in struct VMSA @@ -65,37 +71,15 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output) { u64 input_address = input ? virt_to_phys(input) : 0; u64 output_address = output ? virt_to_phys(output) : 0; - u64 hv_status; #ifdef CONFIG_X86_64 - if (hv_isolation_type_tdx() && !hyperv_paravisor_present) - return hv_tdx_hypercall(control, input_address, output_address); - - if (hv_isolation_type_snp() && !hyperv_paravisor_present) { - __asm__ __volatile__("mov %[output_address], %%r8\n" - "vmmcall" - : "=a" (hv_status), ASM_CALL_CONSTRAINT, - "+c" (control), "+d" (input_address) - : [output_address] "r" (output_address) - : "cc", "memory", "r8", "r9", "r10", "r11"); - return hv_status; - } - - if (!hv_hypercall_pg) - return U64_MAX; - - __asm__ __volatile__("mov %[output_address], %%r8\n" - CALL_NOSPEC - : "=a" (hv_status), ASM_CALL_CONSTRAINT, - "+c" (control), "+d" (input_address) - : [output_address] "r" (output_address), - THUNK_TARGET(hv_hypercall_pg) - : "cc", "memory", "r8", "r9", "r10", "r11"); + return static_call_mod(hv_hypercall)(control, input_address, output_address); #else u32 input_address_hi = upper_32_bits(input_address); u32 input_address_lo = lower_32_bits(input_address); u32 output_address_hi = upper_32_bits(output_address); u32 output_address_lo = lower_32_bits(output_address); + u64 hv_status; if (!hv_hypercall_pg) return U64_MAX; @@ -108,48 +92,30 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output) "D"(output_address_hi), "S"(output_address_lo), THUNK_TARGET(hv_hypercall_pg) : "cc", "memory"); -#endif /* !x86_64 */ return hv_status; +#endif /* !x86_64 */ } /* Fast hypercall with 8 bytes of input and no output */ static inline u64 _hv_do_fast_hypercall8(u64 control, u64 input1) { +#ifdef CONFIG_X86_64 + return static_call_mod(hv_hypercall)(control, input1, 0); +#else + u32 input1_hi = upper_32_bits(input1); + u32 input1_lo = lower_32_bits(input1); u64 hv_status; -#ifdef CONFIG_X86_64 - if (hv_isolation_type_tdx() && !hyperv_paravisor_present) - return hv_tdx_hypercall(control, input1, 0); - - if (hv_isolation_type_snp() && !hyperv_paravisor_present) { - __asm__ __volatile__( - "vmmcall" - : "=a" (hv_status), ASM_CALL_CONSTRAINT, - "+c" (control), "+d" (input1) - :: "cc", "r8", "r9", "r10", "r11"); - } else { - __asm__ __volatile__(CALL_NOSPEC - : "=a" (hv_status), ASM_CALL_CONSTRAINT, - "+c" (control), "+d" (input1) - : THUNK_TARGET(hv_hypercall_pg) - : "cc", "r8", "r9", "r10", "r11"); - } -#else - { - u32 input1_hi = upper_32_bits(input1); - u32 input1_lo = lower_32_bits(input1); - - __asm__ __volatile__ (CALL_NOSPEC - : "=A"(hv_status), - "+c"(input1_lo), - ASM_CALL_CONSTRAINT - : "A" (control), - "b" (input1_hi), - THUNK_TARGET(hv_hypercall_pg) - : "cc", "edi", "esi"); - } -#endif + __asm__ __volatile__ (CALL_NOSPEC + : "=A"(hv_status), + "+c"(input1_lo), + ASM_CALL_CONSTRAINT + : "A" (control), + "b" (input1_hi), + THUNK_TARGET(hv_hypercall_pg) + : "cc", "edi", "esi"); return hv_status; +#endif } static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1) @@ -162,45 +128,24 @@ static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1) /* Fast hypercall with 16 bytes of input */ static inline u64 _hv_do_fast_hypercall16(u64 control, u64 input1, u64 input2) { +#ifdef CONFIG_X86_64 + return static_call_mod(hv_hypercall)(control, input1, input2); +#else + u32 input1_hi = upper_32_bits(input1); + u32 input1_lo = lower_32_bits(input1); + u32 input2_hi = upper_32_bits(input2); + u32 input2_lo = lower_32_bits(input2); u64 hv_status; -#ifdef CONFIG_X86_64 - if (hv_isolation_type_tdx() && !hyperv_paravisor_present) - return hv_tdx_hypercall(control, input1, input2); - - if (hv_isolation_type_snp() && !hyperv_paravisor_present) { - __asm__ __volatile__("mov %[input2], %%r8\n" - "vmmcall" - : "=a" (hv_status), ASM_CALL_CONSTRAINT, - "+c" (control), "+d" (input1) - : [input2] "r" (input2) - : "cc", "r8", "r9", "r10", "r11"); - } else { - __asm__ __volatile__("mov %[input2], %%r8\n" - CALL_NOSPEC - : "=a" (hv_status), ASM_CALL_CONSTRAINT, - "+c" (control), "+d" (input1) - : [input2] "r" (input2), - THUNK_TARGET(hv_hypercall_pg) - : "cc", "r8", "r9", "r10", "r11"); - } -#else - { - u32 input1_hi = upper_32_bits(input1); - u32 input1_lo = lower_32_bits(input1); - u32 input2_hi = upper_32_bits(input2); - u32 input2_lo = lower_32_bits(input2); - - __asm__ __volatile__ (CALL_NOSPEC - : "=A"(hv_status), - "+c"(input1_lo), ASM_CALL_CONSTRAINT - : "A" (control), "b" (input1_hi), - "D"(input2_hi), "S"(input2_lo), - THUNK_TARGET(hv_hypercall_pg) - : "cc"); - } -#endif + __asm__ __volatile__ (CALL_NOSPEC + : "=A"(hv_status), + "+c"(input1_lo), ASM_CALL_CONSTRAINT + : "A" (control), "b" (input1_hi), + "D"(input2_hi), "S"(input2_lo), + THUNK_TARGET(hv_hypercall_pg) + : "cc"); return hv_status; +#endif } static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2) diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index c78f860419d6..3c71effe9ff5 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -38,10 +38,6 @@ bool hv_nested; struct ms_hyperv_info ms_hyperv; -/* Used in modules via hv_do_hypercall(): see arch/x86/include/asm/mshyperv.h */ -bool hyperv_paravisor_present __ro_after_init; -EXPORT_SYMBOL_GPL(hyperv_paravisor_present); - #if IS_ENABLED(CONFIG_HYPERV) static inline unsigned int hv_get_nested_msr(unsigned int reg) { @@ -288,8 +284,18 @@ static void __init x86_setup_ops_for_tsc_pg_clock(void) old_restore_sched_clock_state = x86_platform.restore_sched_clock_state; x86_platform.restore_sched_clock_state = hv_restore_sched_clock_state; } + +#ifdef CONFIG_X86_64 +DEFINE_STATIC_CALL(hv_hypercall, hv_std_hypercall); +EXPORT_STATIC_CALL_TRAMP_GPL(hv_hypercall); +#define hypercall_update(hc) static_call_update(hv_hypercall, hc) +#endif #endif /* CONFIG_HYPERV */ +#ifndef hypercall_update +#define hypercall_update(hc) (void)hc +#endif + static uint32_t __init ms_hyperv_platform(void) { u32 eax; @@ -484,14 +490,14 @@ static void __init ms_hyperv_init_platform(void) ms_hyperv.shared_gpa_boundary = BIT_ULL(ms_hyperv.shared_gpa_boundary_bits); - hyperv_paravisor_present = !!ms_hyperv.paravisor_present; - pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n", ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b); if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP) { static_branch_enable(&isolation_type_snp); + if (!ms_hyperv.paravisor_present) + hypercall_update(hv_snp_hypercall); } else if (hv_get_isolation_type() == HV_ISOLATION_TYPE_TDX) { static_branch_enable(&isolation_type_tdx); @@ -499,6 +505,7 @@ static void __init ms_hyperv_init_platform(void) ms_hyperv.hints &= ~HV_X64_APIC_ACCESS_RECOMMENDED; if (!ms_hyperv.paravisor_present) { + hypercall_update(hv_tdx_hypercall); /* * Mark the Hyper-V TSC page feature as disabled * in a TDX VM without paravisor so that the From c8ed0812646e1335c80a8f204c1b92b2f9d76119 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 12 Apr 2025 13:55:55 +0200 Subject: [PATCH 0281/2711] x86/hyperv: Use direct call to hypercall-page Instead of using an indirect call to the hypercall page, use a direct call instead. This avoids all CFI problems, including the one where the hypercall page doesn't have IBT on. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Michael Kelley Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103441.011387946@infradead.org --- arch/x86/hyperv/hv_init.c | 61 +++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index 5ef1e647ebc0..e890fd37e9c2 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -39,23 +38,41 @@ void *hv_hypercall_pg; #ifdef CONFIG_X86_64 +static u64 __hv_hyperfail(u64 control, u64 param1, u64 param2) +{ + return U64_MAX; +} + +DEFINE_STATIC_CALL(__hv_hypercall, __hv_hyperfail); + u64 hv_std_hypercall(u64 control, u64 param1, u64 param2) { u64 hv_status; - if (!hv_hypercall_pg) - return U64_MAX; - register u64 __r8 asm("r8") = param2; - asm volatile (CALL_NOSPEC + asm volatile ("call " STATIC_CALL_TRAMP_STR(__hv_hypercall) : "=a" (hv_status), ASM_CALL_CONSTRAINT, "+c" (control), "+d" (param1), "+r" (__r8) - : THUNK_TARGET(hv_hypercall_pg) - : "cc", "memory", "r9", "r10", "r11"); + : : "cc", "memory", "r9", "r10", "r11"); return hv_status; } + +typedef u64 (*hv_hypercall_f)(u64 control, u64 param1, u64 param2); + +static inline void hv_set_hypercall_pg(void *ptr) +{ + hv_hypercall_pg = ptr; + + if (!ptr) + ptr = &__hv_hyperfail; + static_call_update(__hv_hypercall, (hv_hypercall_f)ptr); +} #else +static inline void hv_set_hypercall_pg(void *ptr) +{ + hv_hypercall_pg = ptr; +} EXPORT_SYMBOL_GPL(hv_hypercall_pg); #endif @@ -350,7 +367,7 @@ static int hv_suspend(void) * pointer is restored on resume. */ hv_hypercall_pg_saved = hv_hypercall_pg; - hv_hypercall_pg = NULL; + hv_set_hypercall_pg(NULL); /* Disable the hypercall page in the hypervisor */ rdmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); @@ -376,7 +393,7 @@ static void hv_resume(void) vmalloc_to_pfn(hv_hypercall_pg_saved); wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); - hv_hypercall_pg = hv_hypercall_pg_saved; + hv_set_hypercall_pg(hv_hypercall_pg_saved); hv_hypercall_pg_saved = NULL; /* @@ -496,8 +513,8 @@ void __init hyperv_init(void) if (hv_isolation_type_tdx() && !ms_hyperv.paravisor_present) goto skip_hypercall_pg_init; - hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, - VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX, + hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, MODULES_VADDR, + MODULES_END, GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, NUMA_NO_NODE, __builtin_return_address(0)); if (hv_hypercall_pg == NULL) @@ -535,27 +552,9 @@ void __init hyperv_init(void) wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); } -skip_hypercall_pg_init: - /* - * Some versions of Hyper-V that provide IBT in guest VMs have a bug - * in that there's no ENDBR64 instruction at the entry to the - * hypercall page. Because hypercalls are invoked via an indirect call - * to the hypercall page, all hypercall attempts fail when IBT is - * enabled, and Linux panics. For such buggy versions, disable IBT. - * - * Fixed versions of Hyper-V always provide ENDBR64 on the hypercall - * page, so if future Linux kernel versions enable IBT for 32-bit - * builds, additional hypercall page hackery will be required here - * to provide an ENDBR32. - */ -#ifdef CONFIG_X86_KERNEL_IBT - if (cpu_feature_enabled(X86_FEATURE_IBT) && - *(u32 *)hv_hypercall_pg != gen_endbr()) { - setup_clear_cpu_cap(X86_FEATURE_IBT); - pr_warn("Disabling IBT because of Hyper-V bug\n"); - } -#endif + hv_set_hypercall_pg(hv_hypercall_pg); +skip_hypercall_pg_init: /* * hyperv_init() is called before LAPIC is initialized: see * apic_intr_mode_init() -> x86_platform.apic_post_init() and From 2d1435b742156f6d4adc8b9ab0f24b35d879266e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 2 May 2025 07:24:01 -0700 Subject: [PATCH 0282/2711] x86/fred: Install system vector handlers even if FRED isn't fully enabled Install the system vector IRQ handlers for FRED even if FRED isn't fully enabled in hardware. This will allow KVM to use the FRED IRQ path even on non-FRED hardware, which in turn will eliminate a non-CFI indirect CALL (KVM currently invokes the IRQ handler via an IDT lookup on the vector). [sean: extract from diff, drop stub, write changelog] Signed-off-by: Sean Christopherson Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20250714103441.121251108@infradead.org --- arch/x86/include/asm/idtentry.h | 9 ++------- arch/x86/kernel/irqinit.c | 6 ++++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index a4ec27c67988..abd637e54e94 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -460,17 +460,12 @@ __visible noinstr void func(struct pt_regs *regs, \ #endif void idt_install_sysvec(unsigned int n, const void *function); - -#ifdef CONFIG_X86_FRED void fred_install_sysvec(unsigned int vector, const idtentry_t function); -#else -static inline void fred_install_sysvec(unsigned int vector, const idtentry_t function) { } -#endif #define sysvec_install(vector, function) { \ - if (cpu_feature_enabled(X86_FEATURE_FRED)) \ + if (IS_ENABLED(CONFIG_X86_FRED)) \ fred_install_sysvec(vector, function); \ - else \ + if (!cpu_feature_enabled(X86_FEATURE_FRED)) \ idt_install_sysvec(vector, asm_##function); \ } diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index f79c5edc0b89..6ab9eac64670 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c @@ -97,9 +97,11 @@ void __init native_init_IRQ(void) /* Execute any quirks before the call gates are initialised: */ x86_init.irqs.pre_vector_init(); - if (cpu_feature_enabled(X86_FEATURE_FRED)) + /* FRED's IRQ path may be used even if FRED isn't fully enabled. */ + if (IS_ENABLED(CONFIG_X86_FRED)) fred_complete_exception_setup(); - else + + if (!cpu_feature_enabled(X86_FEATURE_FRED)) idt_setup_apic_and_irq_gates(); lapic_assign_system_vectors(); From deed19b9b28724bd32e85063c60718c0a6803906 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 6 Jun 2025 13:04:25 +0200 Subject: [PATCH 0283/2711] x86/fred: Play nice with invoking asm_fred_entry_from_kvm() on non-FRED hardware Modify asm_fred_entry_from_kvm() to allow it to be invoked by KVM even when FRED isn't fully enabled, e.g. when running with CONFIG_X86_FRED=y on non-FRED hardware. This will allow forcing KVM to always use the FRED entry points for 64-bit kernels, which in turn will eliminate a rather gross non-CFI indirect call that KVM uses to trampoline IRQs by doing IDT lookups. The point of asm_fred_entry_from_kvm() is to bridge between C (vmx:handle_external_interrupt_irqoff()) and more C (__fred_entry_from_kvm()) while changing the calling context to appear like an interrupt (pt_regs). Making the whole thing bound by C ABI. All that remains for non-FRED hardware is to restore RSP (to undo the redzone and alignment). However the trivial change would result in code like: push %rbp mov %rsp, %rbp sub $REDZONE, %rsp and $MASK, %rsp PUSH_AND_CLEAR_REGS push %rbp POP_REGS pop %rbp <-- *objtool fail* mov %rbp, %rsp pop %rbp ret And this will confuse objtool something wicked -- it gets confused by the extra pop %rbp, not realizing the push and pop preserve the value. Rather than trying to each objtool about this, recognise that since the code is bound by C ABI on both ends and interrupts are not allowed to change pt_regs (only exceptions are) it is sufficient to PUSH_REGS in order to create pt_regs, but there is no reason to POP_REGS -- provided the callee-saved registers are preserved. So avoid clearing callee-saved regs and skip POP_REGS. [Original patch by Sean; much of this version by Josh; Changelog, comments and final form by Peterz] Originally-by: Sean Christopherson Signed-off-by: Josh Poimboeuf Signed-off-by: Peter Zijlstra (Intel) Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103441.245417052@infradead.org --- arch/x86/entry/calling.h | 11 +++++------ arch/x86/entry/entry_64_fred.S | 35 ++++++++++++++++++++++++++-------- arch/x86/kernel/asm-offsets.c | 1 + 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h index 94519688b007..77e2d920a640 100644 --- a/arch/x86/entry/calling.h +++ b/arch/x86/entry/calling.h @@ -99,7 +99,7 @@ For 32-bit we have the following conventions - kernel is built with .endif .endm -.macro CLEAR_REGS clear_bp=1 +.macro CLEAR_REGS clear_callee=1 /* * Sanitize registers of values that a speculation attack might * otherwise want to exploit. The lower registers are likely clobbered @@ -113,20 +113,19 @@ For 32-bit we have the following conventions - kernel is built with xorl %r9d, %r9d /* nospec r9 */ xorl %r10d, %r10d /* nospec r10 */ xorl %r11d, %r11d /* nospec r11 */ + .if \clear_callee xorl %ebx, %ebx /* nospec rbx */ - .if \clear_bp xorl %ebp, %ebp /* nospec rbp */ - .endif xorl %r12d, %r12d /* nospec r12 */ xorl %r13d, %r13d /* nospec r13 */ xorl %r14d, %r14d /* nospec r14 */ xorl %r15d, %r15d /* nospec r15 */ - + .endif .endm -.macro PUSH_AND_CLEAR_REGS rdx=%rdx rcx=%rcx rax=%rax save_ret=0 clear_bp=1 unwind_hint=1 +.macro PUSH_AND_CLEAR_REGS rdx=%rdx rcx=%rcx rax=%rax save_ret=0 clear_callee=1 unwind_hint=1 PUSH_REGS rdx=\rdx, rcx=\rcx, rax=\rax, save_ret=\save_ret unwind_hint=\unwind_hint - CLEAR_REGS clear_bp=\clear_bp + CLEAR_REGS clear_callee=\clear_callee .endm .macro POP_REGS pop_rdi=1 diff --git a/arch/x86/entry/entry_64_fred.S b/arch/x86/entry/entry_64_fred.S index 29c5c32c16c3..0d00ec8ee79a 100644 --- a/arch/x86/entry/entry_64_fred.S +++ b/arch/x86/entry/entry_64_fred.S @@ -112,18 +112,37 @@ SYM_FUNC_START(asm_fred_entry_from_kvm) push %rax /* Return RIP */ push $0 /* Error code, 0 for IRQ/NMI */ - PUSH_AND_CLEAR_REGS clear_bp=0 unwind_hint=0 + PUSH_AND_CLEAR_REGS clear_callee=0 unwind_hint=0 + movq %rsp, %rdi /* %rdi -> pt_regs */ - call __fred_entry_from_kvm /* Call the C entry point */ - POP_REGS - ERETS -1: /* - * Objtool doesn't understand what ERETS does, this hint tells it that - * yes, we'll reach here and with what stack state. A save/restore pair - * isn't strictly needed, but it's the simplest form. + * At this point: {rdi, rsi, rdx, rcx, r8, r9}, {r10, r11}, {rax, rdx} + * are clobbered, which corresponds to: arguments, extra caller-saved + * and return. All registers a C function is allowed to clobber. + * + * Notably, the callee-saved registers: {rbx, r12, r13, r14, r15} + * are untouched, with the exception of rbp, which carries the stack + * frame and will be restored before exit. + * + * Further calling another C function will not alter this state. + */ + call __fred_entry_from_kvm /* Call the C entry point */ + + /* + * When FRED, use ERETS to potentially clear NMIs, otherwise simply + * restore the stack pointer. + */ + ALTERNATIVE "nop; nop; mov %rbp, %rsp", \ + __stringify(add $C_PTREGS_SIZE, %rsp; ERETS), \ + X86_FEATURE_FRED + +1: /* + * Objtool doesn't understand ERETS, and the cfi register state is + * different from initial_func_cfi due to PUSH_REGS. Tell it the state + * is similar to where UNWIND_HINT_SAVE is. */ UNWIND_HINT_RESTORE + pop %rbp RET diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 6259b474073b..32ba599a51f8 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c @@ -102,6 +102,7 @@ static void __used common(void) BLANK(); DEFINE(PTREGS_SIZE, sizeof(struct pt_regs)); + OFFSET(C_PTREGS_SIZE, pt_regs, orig_ax); /* TLB state for the entry code */ OFFSET(TLB_STATE_user_pcid_flush_mask, tlb_state, user_pcid_flush_mask); From 28d11e4548b75d0960429344f12d5f6cc9cee25b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 1 May 2025 11:10:39 -0700 Subject: [PATCH 0284/2711] x86/fred: KVM: VMX: Always use FRED for IRQs when CONFIG_X86_FRED=y Now that FRED provides C-code entry points for handling IRQs, use the FRED infrastructure for forwarding IRQs even if FRED is fully disabled, e.g. isn't supported in hardware. Avoiding the non-FRED assembly trampolines into the IDT handlers for IRQs eliminates the associated non-CFI indirect call (KVM performs a CALL by doing a lookup on the IDT using the IRQ vector). Keep NMIs on the legacy IDT path, as the FRED NMI entry code relies on FRED's architectural behavior with respect to NMI blocking, i.e. doesn't jump through the myriad hoops needed to deal with IRET "unexpectedly" unmasking NMIs. KVM's NMI path already makes a direct CALL to C-code, i.e. isn't problematic for CFI. KVM does make a short detour through assembly code to build the stack frame, but the "FRED entry from KVM" path does the same. Force FRED for 64-bit kernels if KVM_INTEL is enabled, as the benefits of eliminating the IRQ trampoline usage far outwieghts the code overhead for FRED. Suggested-by: Peter Zijlstra Signed-off-by: Sean Christopherson Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20250714103441.381946911@infradead.org --- arch/x86/kvm/Kconfig | 1 + arch/x86/kvm/vmx/vmx.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 2c86673155c9..b92ef117f355 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -97,6 +97,7 @@ config KVM_INTEL depends on KVM && IA32_FEAT_CTL select KVM_GENERIC_PRIVATE_MEM if INTEL_TDX_HOST select KVM_GENERIC_MEMORY_ATTRIBUTES if INTEL_TDX_HOST + select X86_FRED if X86_64 help Provides support for KVM on processors equipped with Intel's VT extensions, a.k.a. Virtual Machine Extensions (VMX). diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index aa157fe5b7b3..f7f6c04a41d6 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6913,8 +6913,14 @@ static void handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu, "unexpected VM-Exit interrupt info: 0x%x", intr_info)) return; + /* + * Invoke the kernel's IRQ handler for the vector. Use the FRED path + * when it's available even if FRED isn't fully enabled, e.g. even if + * FRED isn't supported in hardware, in order to avoid the indirect + * CALL in the non-FRED path. + */ kvm_before_interrupt(vcpu, KVM_HANDLING_IRQ); - if (cpu_feature_enabled(X86_FEATURE_FRED)) + if (IS_ENABLED(CONFIG_X86_FRED)) fred_entry_from_kvm(EVENT_TYPE_EXTINT, vector); else vmx_do_interrupt_irqoff(gate_offset((gate_desc *)host_idt_base + vector)); From 894af4a1cde61c3401f237184fb770f72ff12df8 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 12 Apr 2025 13:56:01 +0200 Subject: [PATCH 0285/2711] objtool: Validate kCFI calls Validate that all indirect calls adhere to kCFI rules. Notably doing nocfi indirect call to a cfi function is broken. Apparently some Rust 'core' code violates this and explodes when ran with FineIBT. All the ANNOTATE_NOCFI_SYM sites are prime targets for attackers. - runtime EFI is especially henous because it also needs to disable IBT. Basically calling unknown code without CFI protection at runtime is a massice security issue. - Kexec image handover; if you can exploit this, you get to keep it :-) Signed-off-by: Peter Zijlstra (Intel) Acked-by: Josh Poimboeuf Acked-by: Sean Christopherson Link: https://lkml.kernel.org/r/20250714103441.496787279@infradead.org --- arch/x86/kernel/machine_kexec_64.c | 4 +++ arch/x86/kvm/vmx/vmenter.S | 4 +++ arch/x86/platform/efi/efi_stub_64.S | 4 +++ drivers/misc/lkdtm/perms.c | 5 ++++ include/linux/objtool.h | 10 +++++++ include/linux/objtool_types.h | 1 + tools/include/linux/objtool_types.h | 1 + tools/objtool/check.c | 42 +++++++++++++++++++++++++++++ tools/objtool/include/objtool/elf.h | 1 + 9 files changed, 72 insertions(+) diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 697fb99406e6..8593760c255a 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -453,6 +453,10 @@ void __nocfi machine_kexec(struct kimage *image) __ftrace_enabled_restore(save_ftrace_enabled); } +/* + * Handover to the next kernel, no CFI concern. + */ +ANNOTATE_NOCFI_SYM(machine_kexec); /* arch-dependent functionality related to kexec file-based syscall */ diff --git a/arch/x86/kvm/vmx/vmenter.S b/arch/x86/kvm/vmx/vmenter.S index 0a6cf5bff2aa..bc255d709d8a 100644 --- a/arch/x86/kvm/vmx/vmenter.S +++ b/arch/x86/kvm/vmx/vmenter.S @@ -361,6 +361,10 @@ SYM_FUNC_END(vmread_error_trampoline) .section .text, "ax" +#ifndef CONFIG_X86_FRED + SYM_FUNC_START(vmx_do_interrupt_irqoff) VMX_DO_EVENT_IRQOFF CALL_NOSPEC _ASM_ARG1 SYM_FUNC_END(vmx_do_interrupt_irqoff) + +#endif diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S index 2206b8bc47b8..f0a5fba0717e 100644 --- a/arch/x86/platform/efi/efi_stub_64.S +++ b/arch/x86/platform/efi/efi_stub_64.S @@ -11,6 +11,10 @@ #include SYM_FUNC_START(__efi_call) + /* + * The EFI code doesn't have any CFI, annotate away the CFI violation. + */ + ANNOTATE_NOCFI_SYM pushq %rbp movq %rsp, %rbp and $~0xf, %rsp diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c index 6c24426104ba..e1f5e9abb301 100644 --- a/drivers/misc/lkdtm/perms.c +++ b/drivers/misc/lkdtm/perms.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -86,6 +87,10 @@ static noinline __nocfi void execute_location(void *dst, bool write) func(); pr_err("FAIL: func returned\n"); } +/* + * Explicitly doing the wrong thing for testing. + */ +ANNOTATE_NOCFI_SYM(execute_location); static void execute_user_location(void *dst) { diff --git a/include/linux/objtool.h b/include/linux/objtool.h index 366ad004d794..46ebaa46e6c5 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -184,6 +184,15 @@ * WARN using UD2. */ #define ANNOTATE_REACHABLE(label) __ASM_ANNOTATE(label, ANNOTYPE_REACHABLE) +/* + * This should not be used; it annotates away CFI violations. There are a few + * valid use cases like kexec handover to the next kernel image, and there is + * no security concern there. + * + * There are also a few real issues annotated away, like EFI because we can't + * control the EFI code. + */ +#define ANNOTATE_NOCFI_SYM(sym) asm(__ASM_ANNOTATE(sym, ANNOTYPE_NOCFI)) #else #define ANNOTATE_NOENDBR ANNOTATE type=ANNOTYPE_NOENDBR @@ -194,6 +203,7 @@ #define ANNOTATE_INTRA_FUNCTION_CALL ANNOTATE type=ANNOTYPE_INTRA_FUNCTION_CALL #define ANNOTATE_UNRET_BEGIN ANNOTATE type=ANNOTYPE_UNRET_BEGIN #define ANNOTATE_REACHABLE ANNOTATE type=ANNOTYPE_REACHABLE +#define ANNOTATE_NOCFI_SYM ANNOTATE type=ANNOTYPE_NOCFI #endif #if defined(CONFIG_NOINSTR_VALIDATION) && \ diff --git a/include/linux/objtool_types.h b/include/linux/objtool_types.h index df5d9fa84dba..aceac94632c8 100644 --- a/include/linux/objtool_types.h +++ b/include/linux/objtool_types.h @@ -65,5 +65,6 @@ struct unwind_hint { #define ANNOTYPE_IGNORE_ALTS 6 #define ANNOTYPE_INTRA_FUNCTION_CALL 7 #define ANNOTYPE_REACHABLE 8 +#define ANNOTYPE_NOCFI 9 #endif /* _LINUX_OBJTOOL_TYPES_H */ diff --git a/tools/include/linux/objtool_types.h b/tools/include/linux/objtool_types.h index df5d9fa84dba..aceac94632c8 100644 --- a/tools/include/linux/objtool_types.h +++ b/tools/include/linux/objtool_types.h @@ -65,5 +65,6 @@ struct unwind_hint { #define ANNOTYPE_IGNORE_ALTS 6 #define ANNOTYPE_INTRA_FUNCTION_CALL 7 #define ANNOTYPE_REACHABLE 8 +#define ANNOTYPE_NOCFI 9 #endif /* _LINUX_OBJTOOL_TYPES_H */ diff --git a/tools/objtool/check.c b/tools/objtool/check.c index d14f20ef1db1..79eab61cd944 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -2392,6 +2392,8 @@ static int __annotate_ifc(struct objtool_file *file, int type, struct instructio static int __annotate_late(struct objtool_file *file, int type, struct instruction *insn) { + struct symbol *sym; + switch (type) { case ANNOTYPE_NOENDBR: /* early */ @@ -2433,6 +2435,15 @@ static int __annotate_late(struct objtool_file *file, int type, struct instructi insn->dead_end = false; break; + case ANNOTYPE_NOCFI: + sym = insn->sym; + if (!sym) { + ERROR_INSN(insn, "dodgy NOCFI annotation"); + return -1; + } + insn->sym->nocfi = 1; + break; + default: ERROR_INSN(insn, "Unknown annotation type: %d", type); return -1; @@ -4002,6 +4013,37 @@ static int validate_retpoline(struct objtool_file *file) warnings++; } + if (!opts.cfi) + return warnings; + + /* + * kCFI call sites look like: + * + * movl $(-0x12345678), %r10d + * addl -4(%r11), %r10d + * jz 1f + * ud2 + * 1: cs call __x86_indirect_thunk_r11 + * + * Verify all indirect calls are kCFI adorned by checking for the + * UD2. Notably, doing __nocfi calls to regular (cfi) functions is + * broken. + */ + list_for_each_entry(insn, &file->retpoline_call_list, call_node) { + struct symbol *sym = insn->sym; + + if (sym && (sym->type == STT_NOTYPE || + sym->type == STT_FUNC) && !sym->nocfi) { + struct instruction *prev = + prev_insn_same_sym(file, insn); + + if (!prev || prev->type != INSN_BUG) { + WARN_INSN(insn, "no-cfi indirect call!"); + warnings++; + } + } + } + return warnings; } diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 0a2fa3ac0079..df8434d3b744 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -70,6 +70,7 @@ struct symbol { u8 local_label : 1; u8 frame_pointer : 1; u8 ignore : 1; + u8 nocfi : 1; struct list_head pv_target; struct reloc *relocs; struct section *group_sec; From 52ff2b840bc723f3be1f096f8017c78e0515858c Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Sun, 17 Aug 2025 20:13:50 +0300 Subject: [PATCH 0286/2711] staging: axis-fifo: fix maximum TX packet length check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 2ca34b508774 ("staging: axis-fifo: Correct handling of tx_fifo_depth for size validation"), write() operations with packets larger than 'tx_fifo_depth - 4' words are no longer rejected with -EINVAL. Fortunately, the packets are not actually getting transmitted to hardware, otherwise they would be raising a 'Transmit Packet Overrun Error' interrupt, which requires a reset of the TX circuit to recover from. Instead, the request times out inside wait_event_interruptible_timeout() and always returns -EAGAIN, since the wake up condition can never be true for these packets. But still, they unnecessarily block other tasks from writing to the FIFO and the EAGAIN return code signals userspace to retry the write() call, even though it will always fail and time out. According to the AXI4-Stream FIFO reference manual (PG080), the maximum valid packet length is 'tx_fifo_depth - 4' words, so attempting to send larger packets is invalid and should not be happening in the first place: > The maximum packet that can be transmitted is limited by the size of > the FIFO, which is (C_TX_FIFO_DEPTH–4)*(data interface width/8) bytes. Therefore, bring back the old behavior and outright reject packets larger than 'tx_fifo_depth - 4' with -EINVAL. Add a comment to explain why the check is necessary. The dev_err() message was removed to avoid cluttering the dmesg log if an invalid packet is received from userspace. Fixes: 2ca34b508774 ("staging: axis-fifo: Correct handling of tx_fifo_depth for size validation") Cc: stable@vger.kernel.org Signed-off-by: Ovidiu Panait Link: https://lore.kernel.org/r/20250817171350.872105-1-ovidiu.panait.oss@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/axis-fifo/axis-fifo.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index 57ed58065eba..8d5bbe81b499 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -322,11 +322,17 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf, return -EINVAL; } - if (words_to_write > fifo->tx_fifo_depth) { - dev_err(fifo->dt_device, "tried to write more words [%u] than slots in the fifo buffer [%u]\n", - words_to_write, fifo->tx_fifo_depth); + /* + * In 'Store-and-Forward' mode, the maximum packet that can be + * transmitted is limited by the size of the FIFO, which is + * (C_TX_FIFO_DEPTH–4)*(data interface width/8) bytes. + * + * Do not attempt to send a packet larger than 'tx_fifo_depth - 4', + * otherwise a 'Transmit Packet Overrun Error' interrupt will be + * raised, which requires a reset of the TX circuit to recover. + */ + if (words_to_write > (fifo->tx_fifo_depth - 4)) return -EINVAL; - } if (fifo->write_flags & O_NONBLOCK) { /* From e6a9530b3ee7407b70b60e4df70688db0d239e1a Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 18 Aug 2025 08:39:53 -0700 Subject: [PATCH 0287/2711] cxl: Fix emit of type resource_size_t argument for validate_region_offset() 0day reported warnings of: drivers/cxl/core/region.c:3664:25: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=] drivers/cxl/core/region.c:3671:37: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=] Replace %#llx with %pr to emit resource_size_t arguments. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508160513.NAZ9i9rQ-lkp@intel.com/ Cc: Alison Schofield Reviewed-by: Alison Schofield Link: https://patch.msgid.link/20250818153953.3658952-1-dave.jiang@intel.com Signed-off-by: Dave Jiang --- drivers/cxl/core/region.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 3c39e2c9942b..29d3809ab2bb 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -3660,15 +3660,15 @@ static int validate_region_offset(struct cxl_region *cxlr, u64 offset) if (offset < p->cache_size) { dev_err(&cxlr->dev, - "Offset %#llx is within extended linear cache %#llx\n", - offset, p->cache_size); + "Offset %#llx is within extended linear cache %pr\n", + offset, &p->cache_size); return -EINVAL; } region_size = resource_size(p->res); if (offset >= region_size) { - dev_err(&cxlr->dev, "Offset %#llx exceeds region size %#llx\n", - offset, region_size); + dev_err(&cxlr->dev, "Offset %#llx exceeds region size %pr\n", + offset, ®ion_size); return -EINVAL; } From f1bbfc405e3d36545f4fd1931c3e1d32396d1b63 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 18 Aug 2025 11:12:22 +0300 Subject: [PATCH 0288/2711] dt-bindings: iio: adc: Add BD7910[0,1,2,3] The ROHM BD79100, BD79101, BD79102, BD79103 are very similar ADCs as the ROHM BD79104. The BD79100 has only 1 channel. BD79101 has 2 channels and the BD79102 has 4 channels. Both BD79103 and BD79104 have 4 channels, and, based on the data sheets, they seem identical from the software point-of-view. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Reviewed-by: David Lechner Link: https://patch.msgid.link/0874c5933cf56430b9440d19ff46f746e4897952.1755504346.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/rohm,bd79104.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml b/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml index f0a1347ba4db..d5192ec58f59 100644 --- a/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml +++ b/Documentation/devicetree/bindings/iio/adc/rohm,bd79104.yaml @@ -14,7 +14,15 @@ description: | properties: compatible: - const: rohm,bd79104 + oneOf: + - enum: + - rohm,bd79100 + - rohm,bd79101 + - rohm,bd79102 + - rohm,bd79104 + - items: + - const: rohm,bd79103 + - const: rohm,bd79104 reg: maxItems: 1 From 7fe5b83fbcefb100c4fcec034a4a55507cd493e2 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 18 Aug 2025 11:12:39 +0300 Subject: [PATCH 0289/2711] iio: adc: adc128s052: Simplify matching chip_data The adc128s052 driver supports a few different ICs. IC specific configuration data is stored in an array. IC data, residing in a specific point of the array, is pointed from the SPI device match data. There is no need to have the chip config data structures in an array and splitting them out of an array has at least following benefits: - Chip-specific structures can be named after the chips they support. This makes referring them a tad cleaner, compared to using a generic array name with a numerical index. - Avoid all potential 'out of bounds' errors which can result if the array is changed. Split the chip configuration data array to individual structures. Signed-off-by: Matti Vaittinen Reviewed-by: David Lechner Link: https://patch.msgid.link/943b6f4852ff0944eeaa0366cbe3b5aaf440cf23.1755504346.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-adc128s052.c | 78 +++++++++++++++++---------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index 1b46a8155803..81153253529e 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -124,26 +124,30 @@ static const struct iio_chan_spec adc124s021_channels[] = { static const char * const bd79104_regulators[] = { "iovdd" }; -static const struct adc128_configuration adc128_config[] = { - { - .channels = adc128s052_channels, - .num_channels = ARRAY_SIZE(adc128s052_channels), - .refname = "vref", - }, { - .channels = adc122s021_channels, - .num_channels = ARRAY_SIZE(adc122s021_channels), - .refname = "vref", - }, { - .channels = adc124s021_channels, - .num_channels = ARRAY_SIZE(adc124s021_channels), - .refname = "vref", - }, { - .channels = adc128s052_channels, - .num_channels = ARRAY_SIZE(adc128s052_channels), - .refname = "vdd", - .other_regulators = &bd79104_regulators, - .num_other_regulators = 1, - }, +static const struct adc128_configuration adc122s_config = { + .channels = adc122s021_channels, + .num_channels = ARRAY_SIZE(adc122s021_channels), + .refname = "vref", +}; + +static const struct adc128_configuration adc124s_config = { + .channels = adc124s021_channels, + .num_channels = ARRAY_SIZE(adc124s021_channels), + .refname = "vref", +}; + +static const struct adc128_configuration adc128s_config = { + .channels = adc128s052_channels, + .num_channels = ARRAY_SIZE(adc128s052_channels), + .refname = "vref", +}; + +static const struct adc128_configuration bd79104_config = { + .channels = adc128s052_channels, + .num_channels = ARRAY_SIZE(adc128s052_channels), + .refname = "vdd", + .other_regulators = &bd79104_regulators, + .num_other_regulators = 1, }; static const struct iio_info adc128_info = { @@ -199,33 +203,33 @@ static int adc128_probe(struct spi_device *spi) } static const struct of_device_id adc128_of_match[] = { - { .compatible = "ti,adc128s052", .data = &adc128_config[0] }, - { .compatible = "ti,adc122s021", .data = &adc128_config[1] }, - { .compatible = "ti,adc122s051", .data = &adc128_config[1] }, - { .compatible = "ti,adc122s101", .data = &adc128_config[1] }, - { .compatible = "ti,adc124s021", .data = &adc128_config[2] }, - { .compatible = "ti,adc124s051", .data = &adc128_config[2] }, - { .compatible = "ti,adc124s101", .data = &adc128_config[2] }, - { .compatible = "rohm,bd79104", .data = &adc128_config[3] }, + { .compatible = "ti,adc128s052", .data = &adc128s_config }, + { .compatible = "ti,adc122s021", .data = &adc122s_config }, + { .compatible = "ti,adc122s051", .data = &adc122s_config }, + { .compatible = "ti,adc122s101", .data = &adc122s_config }, + { .compatible = "ti,adc124s021", .data = &adc124s_config }, + { .compatible = "ti,adc124s051", .data = &adc124s_config }, + { .compatible = "ti,adc124s101", .data = &adc124s_config }, + { .compatible = "rohm,bd79104", .data = &bd79104_config }, { } }; MODULE_DEVICE_TABLE(of, adc128_of_match); static const struct spi_device_id adc128_id[] = { - { "adc128s052", (kernel_ulong_t)&adc128_config[0] }, - { "adc122s021", (kernel_ulong_t)&adc128_config[1] }, - { "adc122s051", (kernel_ulong_t)&adc128_config[1] }, - { "adc122s101", (kernel_ulong_t)&adc128_config[1] }, - { "adc124s021", (kernel_ulong_t)&adc128_config[2] }, - { "adc124s051", (kernel_ulong_t)&adc128_config[2] }, - { "adc124s101", (kernel_ulong_t)&adc128_config[2] }, - { "bd79104", (kernel_ulong_t)&adc128_config[3] }, + { "adc128s052", (kernel_ulong_t)&adc128s_config }, + { "adc122s021", (kernel_ulong_t)&adc122s_config }, + { "adc122s051", (kernel_ulong_t)&adc122s_config }, + { "adc122s101", (kernel_ulong_t)&adc122s_config }, + { "adc124s021", (kernel_ulong_t)&adc124s_config }, + { "adc124s051", (kernel_ulong_t)&adc124s_config }, + { "adc124s101", (kernel_ulong_t)&adc124s_config }, + { "bd79104", (kernel_ulong_t)&bd79104_config }, { } }; MODULE_DEVICE_TABLE(spi, adc128_id); static const struct acpi_device_id adc128_acpi_match[] = { - { "AANT1280", (kernel_ulong_t)&adc128_config[2] }, + { "AANT1280", (kernel_ulong_t)&adc124s_config }, { } }; MODULE_DEVICE_TABLE(acpi, adc128_acpi_match); From 9e9b0b97b0c76e378c8cb407b62a79b5053993a5 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 18 Aug 2025 11:12:52 +0300 Subject: [PATCH 0290/2711] iio: adc: adc128s052: Rename channel structs The adc128s052 can be used to drive a few other ADCs but the TI's ADCs it was originally intended for. The TI's IC variants model numbers don't (trivially) explain the channel configuration (for a reader working with other than TI's ICs). Rename the channel configuration structures to explicitly explain they are used for simple ADCs, having 2, 4 or 8 channels. Signed-off-by: Matti Vaittinen Reviewed-by: David Lechner Link: https://patch.msgid.link/e737f2b416e25d8e4e734e2765b0e21a3f0ae0bb.1755504346.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-adc128s052.c | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index 81153253529e..9b8ecaca01ed 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -99,7 +99,19 @@ static int adc128_read_raw(struct iio_dev *indio_dev, .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ } -static const struct iio_chan_spec adc128s052_channels[] = { +static const struct iio_chan_spec simple_2chan_adc_channels[] = { + ADC128_VOLTAGE_CHANNEL(0), + ADC128_VOLTAGE_CHANNEL(1), +}; + +static const struct iio_chan_spec simple_4chan_adc_channels[] = { + ADC128_VOLTAGE_CHANNEL(0), + ADC128_VOLTAGE_CHANNEL(1), + ADC128_VOLTAGE_CHANNEL(2), + ADC128_VOLTAGE_CHANNEL(3), +}; + +static const struct iio_chan_spec simple_8chan_adc_channels[] = { ADC128_VOLTAGE_CHANNEL(0), ADC128_VOLTAGE_CHANNEL(1), ADC128_VOLTAGE_CHANNEL(2), @@ -110,41 +122,29 @@ static const struct iio_chan_spec adc128s052_channels[] = { ADC128_VOLTAGE_CHANNEL(7), }; -static const struct iio_chan_spec adc122s021_channels[] = { - ADC128_VOLTAGE_CHANNEL(0), - ADC128_VOLTAGE_CHANNEL(1), -}; - -static const struct iio_chan_spec adc124s021_channels[] = { - ADC128_VOLTAGE_CHANNEL(0), - ADC128_VOLTAGE_CHANNEL(1), - ADC128_VOLTAGE_CHANNEL(2), - ADC128_VOLTAGE_CHANNEL(3), -}; - static const char * const bd79104_regulators[] = { "iovdd" }; static const struct adc128_configuration adc122s_config = { - .channels = adc122s021_channels, - .num_channels = ARRAY_SIZE(adc122s021_channels), + .channels = simple_2chan_adc_channels, + .num_channels = ARRAY_SIZE(simple_2chan_adc_channels), .refname = "vref", }; static const struct adc128_configuration adc124s_config = { - .channels = adc124s021_channels, - .num_channels = ARRAY_SIZE(adc124s021_channels), + .channels = simple_4chan_adc_channels, + .num_channels = ARRAY_SIZE(simple_4chan_adc_channels), .refname = "vref", }; static const struct adc128_configuration adc128s_config = { - .channels = adc128s052_channels, - .num_channels = ARRAY_SIZE(adc128s052_channels), + .channels = simple_8chan_adc_channels, + .num_channels = ARRAY_SIZE(simple_8chan_adc_channels), .refname = "vref", }; static const struct adc128_configuration bd79104_config = { - .channels = adc128s052_channels, - .num_channels = ARRAY_SIZE(adc128s052_channels), + .channels = simple_8chan_adc_channels, + .num_channels = ARRAY_SIZE(simple_8chan_adc_channels), .refname = "vdd", .other_regulators = &bd79104_regulators, .num_other_regulators = 1, From 4340feb4972e80f84ef2dff4383578f11c415e3f Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 18 Aug 2025 11:13:05 +0300 Subject: [PATCH 0291/2711] iio: adc: adc128s052: Support ROHM BD7910[0,1,2,3] The ROHM BD79100, BD79101, BD79102, BD79103 are very similar ADCs as the ROHM BD79104. The BD79100 has only 1 channel. BD79101 has 2 channels and the BD79102 has 4 channels. Both BD79103 and BD79104 have 4 channels, and, based on the data sheets, they seem identical from the software point-of-view. Signed-off-by: Matti Vaittinen Reviewed-by: David Lechner Link: https://patch.msgid.link/bb7a775fd1a6135889a72ae63c45e2a4347a2aa5.1755504346.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-adc128s052.c | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index 9b8ecaca01ed..4ae65793ad9b 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -99,6 +99,10 @@ static int adc128_read_raw(struct iio_dev *indio_dev, .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ } +static const struct iio_chan_spec simple_1chan_adc_channels[] = { + ADC128_VOLTAGE_CHANNEL(0), +}; + static const struct iio_chan_spec simple_2chan_adc_channels[] = { ADC128_VOLTAGE_CHANNEL(0), ADC128_VOLTAGE_CHANNEL(1), @@ -142,6 +146,30 @@ static const struct adc128_configuration adc128s_config = { .refname = "vref", }; +static const struct adc128_configuration bd79100_config = { + .channels = simple_1chan_adc_channels, + .num_channels = ARRAY_SIZE(simple_1chan_adc_channels), + .refname = "vdd", + .other_regulators = &bd79104_regulators, + .num_other_regulators = 1, +}; + +static const struct adc128_configuration bd79101_config = { + .channels = simple_2chan_adc_channels, + .num_channels = ARRAY_SIZE(simple_2chan_adc_channels), + .refname = "vdd", + .other_regulators = &bd79104_regulators, + .num_other_regulators = 1, +}; + +static const struct adc128_configuration bd79102_config = { + .channels = simple_4chan_adc_channels, + .num_channels = ARRAY_SIZE(simple_4chan_adc_channels), + .refname = "vdd", + .other_regulators = &bd79104_regulators, + .num_other_regulators = 1, +}; + static const struct adc128_configuration bd79104_config = { .channels = simple_8chan_adc_channels, .num_channels = ARRAY_SIZE(simple_8chan_adc_channels), @@ -210,6 +238,10 @@ static const struct of_device_id adc128_of_match[] = { { .compatible = "ti,adc124s021", .data = &adc124s_config }, { .compatible = "ti,adc124s051", .data = &adc124s_config }, { .compatible = "ti,adc124s101", .data = &adc124s_config }, + { .compatible = "rohm,bd79100", .data = &bd79100_config }, + { .compatible = "rohm,bd79101", .data = &bd79101_config }, + { .compatible = "rohm,bd79102", .data = &bd79102_config }, + { .compatible = "rohm,bd79103", .data = &bd79104_config }, { .compatible = "rohm,bd79104", .data = &bd79104_config }, { } }; @@ -223,6 +255,10 @@ static const struct spi_device_id adc128_id[] = { { "adc124s021", (kernel_ulong_t)&adc124s_config }, { "adc124s051", (kernel_ulong_t)&adc124s_config }, { "adc124s101", (kernel_ulong_t)&adc124s_config }, + { "bd79100", (kernel_ulong_t)&bd79100_config }, + { "bd79101", (kernel_ulong_t)&bd79101_config }, + { "bd79102", (kernel_ulong_t)&bd79102_config }, + { "bd79103", (kernel_ulong_t)&bd79104_config }, { "bd79104", (kernel_ulong_t)&bd79104_config }, { } }; From 788c57f4766bd5802af9918ea350053a91488c60 Mon Sep 17 00:00:00 2001 From: Jorge Marques Date: Mon, 18 Aug 2025 16:44:23 +0200 Subject: [PATCH 0292/2711] docs: iio: ad3552r: Fix malformed code-block directive Missing required double dot and line break. Fixes: ede84c455659 ("docs: iio: add documentation for ad3552r driver") Signed-off-by: Jorge Marques Reviewed-by: David Lechner Link: https://patch.msgid.link/20250818-docs-ad3552r-code-block-fix-v1-1-4430cbc26676@analog.com Signed-off-by: Jonathan Cameron --- Documentation/iio/ad3552r.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/iio/ad3552r.rst b/Documentation/iio/ad3552r.rst index f5d59e4e86c7..4274e35f503d 100644 --- a/Documentation/iio/ad3552r.rst +++ b/Documentation/iio/ad3552r.rst @@ -64,7 +64,8 @@ specific debugfs path ``/sys/kernel/debug/iio/iio:deviceX``. Usage examples -------------- -. code-block:: bash +.. code-block:: bash + root:/sys/bus/iio/devices/iio:device0# cat data_source normal root:/sys/bus/iio/devices/iio:device0# echo -n ramp-16bit > data_source From aaa75cbd5d4f63e4edf8b74118d367361dcf92f7 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sat, 16 Aug 2025 16:44:44 +0800 Subject: [PATCH 0293/2711] clk: thead: th1520-ap: describe gate clocks with clk_gate Similar to previous situation of mux clocks, the gate clocks of clk-th1520-ap drivers are also using a helper that creates a temporary struct clk_hw and abandons the struct clk_hw in struct ccu_common, which prevents clock gates to be clock parents. Do the similar refactor of dropping struct ccu_common and directly use struct clk_gate here. This patch mimics the refactor done on struct ccu_mux in 54edba916e29 ("clk: thead: th1520-ap: Describe mux clocks with clk_mux"). Fixes: ae81b69fd2b1 ("clk: thead: Add support for T-Head TH1520 AP_SUBSYS clocks") Signed-off-by: Icenowy Zheng Reviewed-by: Drew Fustini Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 378 +++++++++++++++--------------- 1 file changed, 183 insertions(+), 195 deletions(-) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index cf1bba58f641..4dbd1df9a86d 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -48,8 +48,9 @@ struct ccu_mux { }; struct ccu_gate { - u32 enable; - struct ccu_common common; + int clkid; + u32 reg; + struct clk_gate gate; }; struct ccu_div { @@ -87,12 +88,12 @@ struct ccu_pll { 0), \ } -#define CCU_GATE(_clkid, _struct, _name, _parent, _reg, _gate, _flags) \ +#define CCU_GATE(_clkid, _struct, _name, _parent, _reg, _bit, _flags) \ struct ccu_gate _struct = { \ - .enable = _gate, \ - .common = { \ - .clkid = _clkid, \ - .cfg0 = _reg, \ + .clkid = _clkid, \ + .reg = _reg, \ + .gate = { \ + .bit_idx = _bit, \ .hw.init = CLK_HW_INIT_PARENTS_DATA( \ _name, \ _parent, \ @@ -120,13 +121,6 @@ static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw) return container_of(common, struct ccu_div, common); } -static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw) -{ - struct ccu_common *common = hw_to_ccu_common(hw); - - return container_of(common, struct ccu_gate, common); -} - static u8 ccu_get_parent_helper(struct ccu_common *common, struct ccu_internal *mux) { @@ -786,128 +780,128 @@ static const struct clk_parent_data emmc_sdio_ref_clk_pd[] = { { .hw = &emmc_sdio_ref_clk.hw }, }; -static CCU_GATE(CLK_BROM, brom_clk, "brom", ahb2_cpusys_hclk_pd, 0x100, BIT(4), 0); -static CCU_GATE(CLK_BMU, bmu_clk, "bmu", axi4_cpusys2_aclk_pd, 0x100, BIT(5), 0); +static CCU_GATE(CLK_BROM, brom_clk, "brom", ahb2_cpusys_hclk_pd, 0x100, 4, 0); +static CCU_GATE(CLK_BMU, bmu_clk, "bmu", axi4_cpusys2_aclk_pd, 0x100, 5, 0); static CCU_GATE(CLK_AON2CPU_A2X, aon2cpu_a2x_clk, "aon2cpu-a2x", axi4_cpusys2_aclk_pd, - 0x134, BIT(8), 0); + 0x134, 8, 0); static CCU_GATE(CLK_X2X_CPUSYS, x2x_cpusys_clk, "x2x-cpusys", axi4_cpusys2_aclk_pd, - 0x134, BIT(7), 0); + 0x134, 7, 0); static CCU_GATE(CLK_CPU2AON_X2H, cpu2aon_x2h_clk, "cpu2aon-x2h", axi_aclk_pd, - 0x138, BIT(8), CLK_IGNORE_UNUSED); + 0x138, 8, CLK_IGNORE_UNUSED); static CCU_GATE(CLK_CPU2PERI_X2H, cpu2peri_x2h_clk, "cpu2peri-x2h", axi4_cpusys2_aclk_pd, - 0x140, BIT(9), CLK_IGNORE_UNUSED); + 0x140, 9, CLK_IGNORE_UNUSED); static CCU_GATE(CLK_PERISYS_APB1_HCLK, perisys_apb1_hclk, "perisys-apb1-hclk", perisys_ahb_hclk_pd, - 0x150, BIT(9), CLK_IGNORE_UNUSED); + 0x150, 9, CLK_IGNORE_UNUSED); static CCU_GATE(CLK_PERISYS_APB2_HCLK, perisys_apb2_hclk, "perisys-apb2-hclk", perisys_ahb_hclk_pd, - 0x150, BIT(10), CLK_IGNORE_UNUSED); + 0x150, 10, CLK_IGNORE_UNUSED); static CCU_GATE(CLK_PERISYS_APB3_HCLK, perisys_apb3_hclk, "perisys-apb3-hclk", perisys_ahb_hclk_pd, - 0x150, BIT(11), CLK_IGNORE_UNUSED); + 0x150, 11, CLK_IGNORE_UNUSED); static CCU_GATE(CLK_PERISYS_APB4_HCLK, perisys_apb4_hclk, "perisys-apb4-hclk", perisys_ahb_hclk_pd, - 0x150, BIT(12), 0); -static CCU_GATE(CLK_NPU_AXI, npu_axi_clk, "npu-axi", axi_aclk_pd, 0x1c8, BIT(5), 0); -static CCU_GATE(CLK_CPU2VP, cpu2vp_clk, "cpu2vp", axi_aclk_pd, 0x1e0, BIT(13), 0); -static CCU_GATE(CLK_EMMC_SDIO, emmc_sdio_clk, "emmc-sdio", emmc_sdio_ref_clk_pd, 0x204, BIT(30), 0); -static CCU_GATE(CLK_GMAC1, gmac1_clk, "gmac1", gmac_pll_clk_pd, 0x204, BIT(26), 0); -static CCU_GATE(CLK_PADCTRL1, padctrl1_clk, "padctrl1", perisys_apb_pclk_pd, 0x204, BIT(24), 0); -static CCU_GATE(CLK_DSMART, dsmart_clk, "dsmart", perisys_apb_pclk_pd, 0x204, BIT(23), 0); -static CCU_GATE(CLK_PADCTRL0, padctrl0_clk, "padctrl0", perisys_apb_pclk_pd, 0x204, BIT(22), 0); -static CCU_GATE(CLK_GMAC_AXI, gmac_axi_clk, "gmac-axi", axi4_cpusys2_aclk_pd, 0x204, BIT(21), 0); -static CCU_GATE(CLK_GPIO3, gpio3_clk, "gpio3-clk", peri2sys_apb_pclk_pd, 0x204, BIT(20), 0); -static CCU_GATE(CLK_GMAC0, gmac0_clk, "gmac0", gmac_pll_clk_pd, 0x204, BIT(19), 0); -static CCU_GATE(CLK_PWM, pwm_clk, "pwm", perisys_apb_pclk_pd, 0x204, BIT(18), 0); -static CCU_GATE(CLK_QSPI0, qspi0_clk, "qspi0", video_pll_clk_pd, 0x204, BIT(17), 0); -static CCU_GATE(CLK_QSPI1, qspi1_clk, "qspi1", video_pll_clk_pd, 0x204, BIT(16), 0); -static CCU_GATE(CLK_SPI, spi_clk, "spi", video_pll_clk_pd, 0x204, BIT(15), 0); -static CCU_GATE(CLK_UART0_PCLK, uart0_pclk, "uart0-pclk", perisys_apb_pclk_pd, 0x204, BIT(14), 0); -static CCU_GATE(CLK_UART1_PCLK, uart1_pclk, "uart1-pclk", perisys_apb_pclk_pd, 0x204, BIT(13), 0); -static CCU_GATE(CLK_UART2_PCLK, uart2_pclk, "uart2-pclk", perisys_apb_pclk_pd, 0x204, BIT(12), 0); -static CCU_GATE(CLK_UART3_PCLK, uart3_pclk, "uart3-pclk", perisys_apb_pclk_pd, 0x204, BIT(11), 0); -static CCU_GATE(CLK_UART4_PCLK, uart4_pclk, "uart4-pclk", perisys_apb_pclk_pd, 0x204, BIT(10), 0); -static CCU_GATE(CLK_UART5_PCLK, uart5_pclk, "uart5-pclk", perisys_apb_pclk_pd, 0x204, BIT(9), 0); -static CCU_GATE(CLK_GPIO0, gpio0_clk, "gpio0-clk", perisys_apb_pclk_pd, 0x204, BIT(8), 0); -static CCU_GATE(CLK_GPIO1, gpio1_clk, "gpio1-clk", perisys_apb_pclk_pd, 0x204, BIT(7), 0); -static CCU_GATE(CLK_GPIO2, gpio2_clk, "gpio2-clk", peri2sys_apb_pclk_pd, 0x204, BIT(6), 0); -static CCU_GATE(CLK_I2C0, i2c0_clk, "i2c0", perisys_apb_pclk_pd, 0x204, BIT(5), 0); -static CCU_GATE(CLK_I2C1, i2c1_clk, "i2c1", perisys_apb_pclk_pd, 0x204, BIT(4), 0); -static CCU_GATE(CLK_I2C2, i2c2_clk, "i2c2", perisys_apb_pclk_pd, 0x204, BIT(3), 0); -static CCU_GATE(CLK_I2C3, i2c3_clk, "i2c3", perisys_apb_pclk_pd, 0x204, BIT(2), 0); -static CCU_GATE(CLK_I2C4, i2c4_clk, "i2c4", perisys_apb_pclk_pd, 0x204, BIT(1), 0); -static CCU_GATE(CLK_I2C5, i2c5_clk, "i2c5", perisys_apb_pclk_pd, 0x204, BIT(0), 0); -static CCU_GATE(CLK_SPINLOCK, spinlock_clk, "spinlock", ahb2_cpusys_hclk_pd, 0x208, BIT(10), 0); -static CCU_GATE(CLK_DMA, dma_clk, "dma", axi4_cpusys2_aclk_pd, 0x208, BIT(8), 0); -static CCU_GATE(CLK_MBOX0, mbox0_clk, "mbox0", apb3_cpusys_pclk_pd, 0x208, BIT(7), 0); -static CCU_GATE(CLK_MBOX1, mbox1_clk, "mbox1", apb3_cpusys_pclk_pd, 0x208, BIT(6), 0); -static CCU_GATE(CLK_MBOX2, mbox2_clk, "mbox2", apb3_cpusys_pclk_pd, 0x208, BIT(5), 0); -static CCU_GATE(CLK_MBOX3, mbox3_clk, "mbox3", apb3_cpusys_pclk_pd, 0x208, BIT(4), 0); -static CCU_GATE(CLK_WDT0, wdt0_clk, "wdt0", apb3_cpusys_pclk_pd, 0x208, BIT(3), 0); -static CCU_GATE(CLK_WDT1, wdt1_clk, "wdt1", apb3_cpusys_pclk_pd, 0x208, BIT(2), 0); -static CCU_GATE(CLK_TIMER0, timer0_clk, "timer0", apb3_cpusys_pclk_pd, 0x208, BIT(1), 0); -static CCU_GATE(CLK_TIMER1, timer1_clk, "timer1", apb3_cpusys_pclk_pd, 0x208, BIT(0), 0); -static CCU_GATE(CLK_SRAM0, sram0_clk, "sram0", axi_aclk_pd, 0x20c, BIT(4), 0); -static CCU_GATE(CLK_SRAM1, sram1_clk, "sram1", axi_aclk_pd, 0x20c, BIT(3), 0); -static CCU_GATE(CLK_SRAM2, sram2_clk, "sram2", axi_aclk_pd, 0x20c, BIT(2), 0); -static CCU_GATE(CLK_SRAM3, sram3_clk, "sram3", axi_aclk_pd, 0x20c, BIT(1), 0); + 0x150, 12, 0); +static CCU_GATE(CLK_NPU_AXI, npu_axi_clk, "npu-axi", axi_aclk_pd, 0x1c8, 5, 0); +static CCU_GATE(CLK_CPU2VP, cpu2vp_clk, "cpu2vp", axi_aclk_pd, 0x1e0, 13, 0); +static CCU_GATE(CLK_EMMC_SDIO, emmc_sdio_clk, "emmc-sdio", emmc_sdio_ref_clk_pd, 0x204, 30, 0); +static CCU_GATE(CLK_GMAC1, gmac1_clk, "gmac1", gmac_pll_clk_pd, 0x204, 26, 0); +static CCU_GATE(CLK_PADCTRL1, padctrl1_clk, "padctrl1", perisys_apb_pclk_pd, 0x204, 24, 0); +static CCU_GATE(CLK_DSMART, dsmart_clk, "dsmart", perisys_apb_pclk_pd, 0x204, 23, 0); +static CCU_GATE(CLK_PADCTRL0, padctrl0_clk, "padctrl0", perisys_apb_pclk_pd, 0x204, 22, 0); +static CCU_GATE(CLK_GMAC_AXI, gmac_axi_clk, "gmac-axi", axi4_cpusys2_aclk_pd, 0x204, 21, 0); +static CCU_GATE(CLK_GPIO3, gpio3_clk, "gpio3-clk", peri2sys_apb_pclk_pd, 0x204, 20, 0); +static CCU_GATE(CLK_GMAC0, gmac0_clk, "gmac0", gmac_pll_clk_pd, 0x204, 19, 0); +static CCU_GATE(CLK_PWM, pwm_clk, "pwm", perisys_apb_pclk_pd, 0x204, 18, 0); +static CCU_GATE(CLK_QSPI0, qspi0_clk, "qspi0", video_pll_clk_pd, 0x204, 17, 0); +static CCU_GATE(CLK_QSPI1, qspi1_clk, "qspi1", video_pll_clk_pd, 0x204, 16, 0); +static CCU_GATE(CLK_SPI, spi_clk, "spi", video_pll_clk_pd, 0x204, 15, 0); +static CCU_GATE(CLK_UART0_PCLK, uart0_pclk, "uart0-pclk", perisys_apb_pclk_pd, 0x204, 14, 0); +static CCU_GATE(CLK_UART1_PCLK, uart1_pclk, "uart1-pclk", perisys_apb_pclk_pd, 0x204, 13, 0); +static CCU_GATE(CLK_UART2_PCLK, uart2_pclk, "uart2-pclk", perisys_apb_pclk_pd, 0x204, 12, 0); +static CCU_GATE(CLK_UART3_PCLK, uart3_pclk, "uart3-pclk", perisys_apb_pclk_pd, 0x204, 11, 0); +static CCU_GATE(CLK_UART4_PCLK, uart4_pclk, "uart4-pclk", perisys_apb_pclk_pd, 0x204, 10, 0); +static CCU_GATE(CLK_UART5_PCLK, uart5_pclk, "uart5-pclk", perisys_apb_pclk_pd, 0x204, 9, 0); +static CCU_GATE(CLK_GPIO0, gpio0_clk, "gpio0-clk", perisys_apb_pclk_pd, 0x204, 8, 0); +static CCU_GATE(CLK_GPIO1, gpio1_clk, "gpio1-clk", perisys_apb_pclk_pd, 0x204, 7, 0); +static CCU_GATE(CLK_GPIO2, gpio2_clk, "gpio2-clk", peri2sys_apb_pclk_pd, 0x204, 6, 0); +static CCU_GATE(CLK_I2C0, i2c0_clk, "i2c0", perisys_apb_pclk_pd, 0x204, 5, 0); +static CCU_GATE(CLK_I2C1, i2c1_clk, "i2c1", perisys_apb_pclk_pd, 0x204, 4, 0); +static CCU_GATE(CLK_I2C2, i2c2_clk, "i2c2", perisys_apb_pclk_pd, 0x204, 3, 0); +static CCU_GATE(CLK_I2C3, i2c3_clk, "i2c3", perisys_apb_pclk_pd, 0x204, 2, 0); +static CCU_GATE(CLK_I2C4, i2c4_clk, "i2c4", perisys_apb_pclk_pd, 0x204, 1, 0); +static CCU_GATE(CLK_I2C5, i2c5_clk, "i2c5", perisys_apb_pclk_pd, 0x204, 0, 0); +static CCU_GATE(CLK_SPINLOCK, spinlock_clk, "spinlock", ahb2_cpusys_hclk_pd, 0x208, 10, 0); +static CCU_GATE(CLK_DMA, dma_clk, "dma", axi4_cpusys2_aclk_pd, 0x208, 8, 0); +static CCU_GATE(CLK_MBOX0, mbox0_clk, "mbox0", apb3_cpusys_pclk_pd, 0x208, 7, 0); +static CCU_GATE(CLK_MBOX1, mbox1_clk, "mbox1", apb3_cpusys_pclk_pd, 0x208, 6, 0); +static CCU_GATE(CLK_MBOX2, mbox2_clk, "mbox2", apb3_cpusys_pclk_pd, 0x208, 5, 0); +static CCU_GATE(CLK_MBOX3, mbox3_clk, "mbox3", apb3_cpusys_pclk_pd, 0x208, 4, 0); +static CCU_GATE(CLK_WDT0, wdt0_clk, "wdt0", apb3_cpusys_pclk_pd, 0x208, 3, 0); +static CCU_GATE(CLK_WDT1, wdt1_clk, "wdt1", apb3_cpusys_pclk_pd, 0x208, 2, 0); +static CCU_GATE(CLK_TIMER0, timer0_clk, "timer0", apb3_cpusys_pclk_pd, 0x208, 1, 0); +static CCU_GATE(CLK_TIMER1, timer1_clk, "timer1", apb3_cpusys_pclk_pd, 0x208, 0, 0); +static CCU_GATE(CLK_SRAM0, sram0_clk, "sram0", axi_aclk_pd, 0x20c, 4, 0); +static CCU_GATE(CLK_SRAM1, sram1_clk, "sram1", axi_aclk_pd, 0x20c, 3, 0); +static CCU_GATE(CLK_SRAM2, sram2_clk, "sram2", axi_aclk_pd, 0x20c, 2, 0); +static CCU_GATE(CLK_SRAM3, sram3_clk, "sram3", axi_aclk_pd, 0x20c, 1, 0); static CCU_GATE(CLK_AXI4_VO_ACLK, axi4_vo_aclk, "axi4-vo-aclk", - video_pll_clk_pd, 0x0, BIT(0), 0); + video_pll_clk_pd, 0x0, 0, 0); static CCU_GATE(CLK_GPU_CORE, gpu_core_clk, "gpu-core-clk", video_pll_clk_pd, - 0x0, BIT(3), 0); + 0x0, 3, 0); static CCU_GATE(CLK_GPU_CFG_ACLK, gpu_cfg_aclk, "gpu-cfg-aclk", - video_pll_clk_pd, 0x0, BIT(4), 0); + video_pll_clk_pd, 0x0, 4, 0); static CCU_GATE(CLK_DPU_PIXELCLK0, dpu0_pixelclk, "dpu0-pixelclk", - video_pll_clk_pd, 0x0, BIT(5), 0); + video_pll_clk_pd, 0x0, 5, 0); static CCU_GATE(CLK_DPU_PIXELCLK1, dpu1_pixelclk, "dpu1-pixelclk", - video_pll_clk_pd, 0x0, BIT(6), 0); + video_pll_clk_pd, 0x0, 6, 0); static CCU_GATE(CLK_DPU_HCLK, dpu_hclk, "dpu-hclk", video_pll_clk_pd, 0x0, - BIT(7), 0); + 7, 0); static CCU_GATE(CLK_DPU_ACLK, dpu_aclk, "dpu-aclk", video_pll_clk_pd, 0x0, - BIT(8), 0); + 8, 0); static CCU_GATE(CLK_DPU_CCLK, dpu_cclk, "dpu-cclk", video_pll_clk_pd, 0x0, - BIT(9), 0); + 9, 0); static CCU_GATE(CLK_HDMI_SFR, hdmi_sfr_clk, "hdmi-sfr-clk", video_pll_clk_pd, - 0x0, BIT(10), 0); + 0x0, 10, 0); static CCU_GATE(CLK_HDMI_PCLK, hdmi_pclk, "hdmi-pclk", video_pll_clk_pd, 0x0, - BIT(11), 0); + 11, 0); static CCU_GATE(CLK_HDMI_CEC, hdmi_cec_clk, "hdmi-cec-clk", video_pll_clk_pd, - 0x0, BIT(12), 0); + 0x0, 12, 0); static CCU_GATE(CLK_MIPI_DSI0_PCLK, mipi_dsi0_pclk, "mipi-dsi0-pclk", - video_pll_clk_pd, 0x0, BIT(13), 0); + video_pll_clk_pd, 0x0, 13, 0); static CCU_GATE(CLK_MIPI_DSI1_PCLK, mipi_dsi1_pclk, "mipi-dsi1-pclk", - video_pll_clk_pd, 0x0, BIT(14), 0); + video_pll_clk_pd, 0x0, 14, 0); static CCU_GATE(CLK_MIPI_DSI0_CFG, mipi_dsi0_cfg_clk, "mipi-dsi0-cfg-clk", - video_pll_clk_pd, 0x0, BIT(15), 0); + video_pll_clk_pd, 0x0, 15, 0); static CCU_GATE(CLK_MIPI_DSI1_CFG, mipi_dsi1_cfg_clk, "mipi-dsi1-cfg-clk", - video_pll_clk_pd, 0x0, BIT(16), 0); + video_pll_clk_pd, 0x0, 16, 0); static CCU_GATE(CLK_MIPI_DSI0_REFCLK, mipi_dsi0_refclk, "mipi-dsi0-refclk", - video_pll_clk_pd, 0x0, BIT(17), 0); + video_pll_clk_pd, 0x0, 17, 0); static CCU_GATE(CLK_MIPI_DSI1_REFCLK, mipi_dsi1_refclk, "mipi-dsi1-refclk", - video_pll_clk_pd, 0x0, BIT(18), 0); + video_pll_clk_pd, 0x0, 18, 0); static CCU_GATE(CLK_HDMI_I2S, hdmi_i2s_clk, "hdmi-i2s-clk", video_pll_clk_pd, - 0x0, BIT(19), 0); + 0x0, 19, 0); static CCU_GATE(CLK_X2H_DPU1_ACLK, x2h_dpu1_aclk, "x2h-dpu1-aclk", - video_pll_clk_pd, 0x0, BIT(20), 0); + video_pll_clk_pd, 0x0, 20, 0); static CCU_GATE(CLK_X2H_DPU_ACLK, x2h_dpu_aclk, "x2h-dpu-aclk", - video_pll_clk_pd, 0x0, BIT(21), 0); + video_pll_clk_pd, 0x0, 21, 0); static CCU_GATE(CLK_AXI4_VO_PCLK, axi4_vo_pclk, "axi4-vo-pclk", - video_pll_clk_pd, 0x0, BIT(22), 0); + video_pll_clk_pd, 0x0, 22, 0); static CCU_GATE(CLK_IOPMP_VOSYS_DPU_PCLK, iopmp_vosys_dpu_pclk, - "iopmp-vosys-dpu-pclk", video_pll_clk_pd, 0x0, BIT(23), 0); + "iopmp-vosys-dpu-pclk", video_pll_clk_pd, 0x0, 23, 0); static CCU_GATE(CLK_IOPMP_VOSYS_DPU1_PCLK, iopmp_vosys_dpu1_pclk, - "iopmp-vosys-dpu1-pclk", video_pll_clk_pd, 0x0, BIT(24), 0); + "iopmp-vosys-dpu1-pclk", video_pll_clk_pd, 0x0, 24, 0); static CCU_GATE(CLK_IOPMP_VOSYS_GPU_PCLK, iopmp_vosys_gpu_pclk, - "iopmp-vosys-gpu-pclk", video_pll_clk_pd, 0x0, BIT(25), 0); + "iopmp-vosys-gpu-pclk", video_pll_clk_pd, 0x0, 25, 0); static CCU_GATE(CLK_IOPMP_DPU1_ACLK, iopmp_dpu1_aclk, "iopmp-dpu1-aclk", - video_pll_clk_pd, 0x0, BIT(27), 0); + video_pll_clk_pd, 0x0, 27, 0); static CCU_GATE(CLK_IOPMP_DPU_ACLK, iopmp_dpu_aclk, "iopmp-dpu-aclk", - video_pll_clk_pd, 0x0, BIT(28), 0); + video_pll_clk_pd, 0x0, 28, 0); static CCU_GATE(CLK_IOPMP_GPU_ACLK, iopmp_gpu_aclk, "iopmp-gpu-aclk", - video_pll_clk_pd, 0x0, BIT(29), 0); + video_pll_clk_pd, 0x0, 29, 0); static CCU_GATE(CLK_MIPIDSI0_PIXCLK, mipi_dsi0_pixclk, "mipi-dsi0-pixclk", - video_pll_clk_pd, 0x0, BIT(30), 0); + video_pll_clk_pd, 0x0, 30, 0); static CCU_GATE(CLK_MIPIDSI1_PIXCLK, mipi_dsi1_pixclk, "mipi-dsi1-pixclk", - video_pll_clk_pd, 0x0, BIT(31), 0); + video_pll_clk_pd, 0x0, 31, 0); static CCU_GATE(CLK_HDMI_PIXCLK, hdmi_pixclk, "hdmi-pixclk", video_pll_clk_pd, - 0x4, BIT(0), 0); + 0x4, 0, 0); static CLK_FIXED_FACTOR_HW(gmac_pll_clk_100m, "gmac-pll-clk-100m", &gmac_pll_clk.common.hw, 10, 1, 0); @@ -963,93 +957,93 @@ static struct ccu_mux *th1520_mux_clks[] = { &uart_sclk, }; -static struct ccu_common *th1520_gate_clks[] = { - &emmc_sdio_clk.common, - &aon2cpu_a2x_clk.common, - &x2x_cpusys_clk.common, - &brom_clk.common, - &bmu_clk.common, - &cpu2aon_x2h_clk.common, - &cpu2peri_x2h_clk.common, - &cpu2vp_clk.common, - &perisys_apb1_hclk.common, - &perisys_apb2_hclk.common, - &perisys_apb3_hclk.common, - &perisys_apb4_hclk.common, - &npu_axi_clk.common, - &gmac1_clk.common, - &padctrl1_clk.common, - &dsmart_clk.common, - &padctrl0_clk.common, - &gmac_axi_clk.common, - &gpio3_clk.common, - &gmac0_clk.common, - &pwm_clk.common, - &qspi0_clk.common, - &qspi1_clk.common, - &spi_clk.common, - &uart0_pclk.common, - &uart1_pclk.common, - &uart2_pclk.common, - &uart3_pclk.common, - &uart4_pclk.common, - &uart5_pclk.common, - &gpio0_clk.common, - &gpio1_clk.common, - &gpio2_clk.common, - &i2c0_clk.common, - &i2c1_clk.common, - &i2c2_clk.common, - &i2c3_clk.common, - &i2c4_clk.common, - &i2c5_clk.common, - &spinlock_clk.common, - &dma_clk.common, - &mbox0_clk.common, - &mbox1_clk.common, - &mbox2_clk.common, - &mbox3_clk.common, - &wdt0_clk.common, - &wdt1_clk.common, - &timer0_clk.common, - &timer1_clk.common, - &sram0_clk.common, - &sram1_clk.common, - &sram2_clk.common, - &sram3_clk.common, +static struct ccu_gate *th1520_gate_clks[] = { + &emmc_sdio_clk, + &aon2cpu_a2x_clk, + &x2x_cpusys_clk, + &brom_clk, + &bmu_clk, + &cpu2aon_x2h_clk, + &cpu2peri_x2h_clk, + &cpu2vp_clk, + &perisys_apb1_hclk, + &perisys_apb2_hclk, + &perisys_apb3_hclk, + &perisys_apb4_hclk, + &npu_axi_clk, + &gmac1_clk, + &padctrl1_clk, + &dsmart_clk, + &padctrl0_clk, + &gmac_axi_clk, + &gpio3_clk, + &gmac0_clk, + &pwm_clk, + &qspi0_clk, + &qspi1_clk, + &spi_clk, + &uart0_pclk, + &uart1_pclk, + &uart2_pclk, + &uart3_pclk, + &uart4_pclk, + &uart5_pclk, + &gpio0_clk, + &gpio1_clk, + &gpio2_clk, + &i2c0_clk, + &i2c1_clk, + &i2c2_clk, + &i2c3_clk, + &i2c4_clk, + &i2c5_clk, + &spinlock_clk, + &dma_clk, + &mbox0_clk, + &mbox1_clk, + &mbox2_clk, + &mbox3_clk, + &wdt0_clk, + &wdt1_clk, + &timer0_clk, + &timer1_clk, + &sram0_clk, + &sram1_clk, + &sram2_clk, + &sram3_clk, }; -static struct ccu_common *th1520_vo_gate_clks[] = { - &axi4_vo_aclk.common, - &gpu_core_clk.common, - &gpu_cfg_aclk.common, - &dpu0_pixelclk.common, - &dpu1_pixelclk.common, - &dpu_hclk.common, - &dpu_aclk.common, - &dpu_cclk.common, - &hdmi_sfr_clk.common, - &hdmi_pclk.common, - &hdmi_cec_clk.common, - &mipi_dsi0_pclk.common, - &mipi_dsi1_pclk.common, - &mipi_dsi0_cfg_clk.common, - &mipi_dsi1_cfg_clk.common, - &mipi_dsi0_refclk.common, - &mipi_dsi1_refclk.common, - &hdmi_i2s_clk.common, - &x2h_dpu1_aclk.common, - &x2h_dpu_aclk.common, - &axi4_vo_pclk.common, - &iopmp_vosys_dpu_pclk.common, - &iopmp_vosys_dpu1_pclk.common, - &iopmp_vosys_gpu_pclk.common, - &iopmp_dpu1_aclk.common, - &iopmp_dpu_aclk.common, - &iopmp_gpu_aclk.common, - &mipi_dsi0_pixclk.common, - &mipi_dsi1_pixclk.common, - &hdmi_pixclk.common +static struct ccu_gate *th1520_vo_gate_clks[] = { + &axi4_vo_aclk, + &gpu_core_clk, + &gpu_cfg_aclk, + &dpu0_pixelclk, + &dpu1_pixelclk, + &dpu_hclk, + &dpu_aclk, + &dpu_cclk, + &hdmi_sfr_clk, + &hdmi_pclk, + &hdmi_cec_clk, + &mipi_dsi0_pclk, + &mipi_dsi1_pclk, + &mipi_dsi0_cfg_clk, + &mipi_dsi1_cfg_clk, + &mipi_dsi0_refclk, + &mipi_dsi1_refclk, + &hdmi_i2s_clk, + &x2h_dpu1_aclk, + &x2h_dpu_aclk, + &axi4_vo_pclk, + &iopmp_vosys_dpu_pclk, + &iopmp_vosys_dpu1_pclk, + &iopmp_vosys_gpu_pclk, + &iopmp_dpu1_aclk, + &iopmp_dpu_aclk, + &iopmp_gpu_aclk, + &mipi_dsi0_pixclk, + &mipi_dsi1_pixclk, + &hdmi_pixclk }; static const struct regmap_config th1520_clk_regmap_config = { @@ -1063,7 +1057,7 @@ struct th1520_plat_data { struct ccu_common **th1520_pll_clks; struct ccu_common **th1520_div_clks; struct ccu_mux **th1520_mux_clks; - struct ccu_common **th1520_gate_clks; + struct ccu_gate **th1520_gate_clks; int nr_clks; int nr_pll_clks; @@ -1102,7 +1096,6 @@ static int th1520_clk_probe(struct platform_device *pdev) struct regmap *map; void __iomem *base; - struct clk_hw *hw; int ret, i; plat_data = device_get_match_data(&pdev->dev); @@ -1161,20 +1154,15 @@ static int th1520_clk_probe(struct platform_device *pdev) } for (i = 0; i < plat_data->nr_gate_clks; i++) { - struct ccu_gate *cg = hw_to_ccu_gate(&plat_data->th1520_gate_clks[i]->hw); + struct ccu_gate *cg = plat_data->th1520_gate_clks[i]; - plat_data->th1520_gate_clks[i]->map = map; + cg->gate.reg = base + cg->reg; - hw = devm_clk_hw_register_gate_parent_data(dev, - cg->common.hw.init->name, - cg->common.hw.init->parent_data, - cg->common.hw.init->flags, - base + cg->common.cfg0, - ffs(cg->enable) - 1, 0, NULL); - if (IS_ERR(hw)) - return PTR_ERR(hw); + ret = devm_clk_hw_register(dev, &cg->gate.hw); + if (ret) + return ret; - priv->hws[cg->common.clkid] = hw; + priv->hws[cg->clkid] = &cg->gate.hw; } if (plat_data == &th1520_ap_platdata) { From 9e99b992c8874f323091d50a5e4727bbd138192d Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sat, 16 Aug 2025 16:44:45 +0800 Subject: [PATCH 0294/2711] clk: thead: th1520-ap: fix parent of padctrl0 clock The padctrl0 clock seems to be a child of the perisys_apb4_hclk clock, gating the later makes padctrl0 registers stuck too. Fix this relationship. Fixes: ae81b69fd2b1 ("clk: thead: Add support for T-Head TH1520 AP_SUBSYS clocks") Signed-off-by: Icenowy Zheng Reviewed-by: Drew Fustini Reviewed-by: Troy Mitchell Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index 4dbd1df9a86d..8a5d69963837 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -798,13 +798,17 @@ static CCU_GATE(CLK_PERISYS_APB3_HCLK, perisys_apb3_hclk, "perisys-apb3-hclk", p 0x150, 11, CLK_IGNORE_UNUSED); static CCU_GATE(CLK_PERISYS_APB4_HCLK, perisys_apb4_hclk, "perisys-apb4-hclk", perisys_ahb_hclk_pd, 0x150, 12, 0); +static const struct clk_parent_data perisys_apb4_hclk_pd[] = { + { .hw = &perisys_apb4_hclk.gate.hw }, +}; + static CCU_GATE(CLK_NPU_AXI, npu_axi_clk, "npu-axi", axi_aclk_pd, 0x1c8, 5, 0); static CCU_GATE(CLK_CPU2VP, cpu2vp_clk, "cpu2vp", axi_aclk_pd, 0x1e0, 13, 0); static CCU_GATE(CLK_EMMC_SDIO, emmc_sdio_clk, "emmc-sdio", emmc_sdio_ref_clk_pd, 0x204, 30, 0); static CCU_GATE(CLK_GMAC1, gmac1_clk, "gmac1", gmac_pll_clk_pd, 0x204, 26, 0); static CCU_GATE(CLK_PADCTRL1, padctrl1_clk, "padctrl1", perisys_apb_pclk_pd, 0x204, 24, 0); static CCU_GATE(CLK_DSMART, dsmart_clk, "dsmart", perisys_apb_pclk_pd, 0x204, 23, 0); -static CCU_GATE(CLK_PADCTRL0, padctrl0_clk, "padctrl0", perisys_apb_pclk_pd, 0x204, 22, 0); +static CCU_GATE(CLK_PADCTRL0, padctrl0_clk, "padctrl0", perisys_apb4_hclk_pd, 0x204, 22, 0); static CCU_GATE(CLK_GMAC_AXI, gmac_axi_clk, "gmac-axi", axi4_cpusys2_aclk_pd, 0x204, 21, 0); static CCU_GATE(CLK_GPIO3, gpio3_clk, "gpio3-clk", peri2sys_apb_pclk_pd, 0x204, 20, 0); static CCU_GATE(CLK_GMAC0, gmac0_clk, "gmac0", gmac_pll_clk_pd, 0x204, 19, 0); From c51a37ffea3813374a8f7955abbba6da25357388 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Sat, 16 Aug 2025 17:11:10 +0800 Subject: [PATCH 0295/2711] clk: thead: Correct parent for DPU pixel clocks The dpu0_pixelclk and dpu1_pixelclk gates were incorrectly parented to the video_pll_clk. According to the TH1520 TRM, the "dpu0_pixelclk" should be sourced from "DPU0 PLL DIV CLK". In this driver, "DPU0 PLL DIV CLK" corresponds to the `dpu0_clk` clock, which is a divider whose parent is the `dpu0_pll_clk`. This patch corrects the clock hierarchy by reparenting `dpu0_pixelclk` to `dpu0_clk`. By symmetry, `dpu1_pixelclk` is also reparented to its correct source, `dpu1_clk`. Fixes: 50d4b157fa96 ("clk: thead: Add clock support for VO subsystem in T-HEAD TH1520 SoC") Reported-by: Icenowy Zheng Signed-off-by: Michal Wilczynski [Icenowy: add Drew's R-b and rebased atop ccu_gate refactor] Reviewed-by: Drew Fustini Signed-off-by: Icenowy Zheng Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index 8a5d69963837..ec52726fbea9 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -761,6 +761,10 @@ static struct ccu_div dpu0_clk = { }, }; +static const struct clk_parent_data dpu0_clk_pd[] = { + { .hw = &dpu0_clk.common.hw } +}; + static struct ccu_div dpu1_clk = { .div = TH_CCU_DIV_FLAGS(0, 8, CLK_DIVIDER_ONE_BASED), .common = { @@ -773,6 +777,10 @@ static struct ccu_div dpu1_clk = { }, }; +static const struct clk_parent_data dpu1_clk_pd[] = { + { .hw = &dpu1_clk.common.hw } +}; + static CLK_FIXED_FACTOR_HW(emmc_sdio_ref_clk, "emmc-sdio-ref", &video_pll_clk.common.hw, 4, 1, 0); @@ -853,9 +861,9 @@ static CCU_GATE(CLK_GPU_CORE, gpu_core_clk, "gpu-core-clk", video_pll_clk_pd, static CCU_GATE(CLK_GPU_CFG_ACLK, gpu_cfg_aclk, "gpu-cfg-aclk", video_pll_clk_pd, 0x0, 4, 0); static CCU_GATE(CLK_DPU_PIXELCLK0, dpu0_pixelclk, "dpu0-pixelclk", - video_pll_clk_pd, 0x0, 5, 0); + dpu0_clk_pd, 0x0, 5, 0); static CCU_GATE(CLK_DPU_PIXELCLK1, dpu1_pixelclk, "dpu1-pixelclk", - video_pll_clk_pd, 0x0, 6, 0); + dpu1_clk_pd, 0x0, 6, 0); static CCU_GATE(CLK_DPU_HCLK, dpu_hclk, "dpu-hclk", video_pll_clk_pd, 0x0, 7, 0); static CCU_GATE(CLK_DPU_ACLK, dpu_aclk, "dpu-aclk", video_pll_clk_pd, 0x0, From 56a48c1833aa1ede82cc3833d73750597eccfdb0 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sat, 16 Aug 2025 17:11:11 +0800 Subject: [PATCH 0296/2711] clk: thead: add support for enabling/disabling PLLs The 2nd control word of T-Head TH1520 PLLs contains a bit to put the VCO into reset state, which means disabling the PLL. Some PLLs are put to disabled state by the bootloader, and the clock driver should be able to enable them. Add support for enabling/disabling PLLs. PLLs other than DPU ones are set CLK_IS_CRITICAL to prevent killing the system -- they're meant to drive CPU or system buses (even the GMAC/Video ones are driving arbitrary buses). Signed-off-by: Icenowy Zheng Reviewed-by: Drew Fustini Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 38 +++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index ec52726fbea9..d81445e24a96 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -18,6 +18,7 @@ #define TH1520_PLL_FBDIV GENMASK(19, 8) #define TH1520_PLL_REFDIV GENMASK(5, 0) #define TH1520_PLL_BYPASS BIT(30) +#define TH1520_PLL_VCO_RST BIT(29) #define TH1520_PLL_DSMPD BIT(24) #define TH1520_PLL_FRAC GENMASK(23, 0) #define TH1520_PLL_FRAC_BITS 24 @@ -236,6 +237,30 @@ static const struct clk_ops ccu_div_ops = { .determine_rate = clk_hw_determine_rate_no_reparent, }; +static void ccu_pll_disable(struct clk_hw *hw) +{ + struct ccu_pll *pll = hw_to_ccu_pll(hw); + + regmap_set_bits(pll->common.map, pll->common.cfg1, + TH1520_PLL_VCO_RST); +} + +static int ccu_pll_enable(struct clk_hw *hw) +{ + struct ccu_pll *pll = hw_to_ccu_pll(hw); + + return regmap_clear_bits(pll->common.map, pll->common.cfg1, + TH1520_PLL_VCO_RST); +} + +static int ccu_pll_is_enabled(struct clk_hw *hw) +{ + struct ccu_pll *pll = hw_to_ccu_pll(hw); + + return !regmap_test_bits(pll->common.map, pll->common.cfg1, + TH1520_PLL_VCO_RST); +} + static unsigned long th1520_pll_vco_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -293,6 +318,9 @@ static unsigned long ccu_pll_recalc_rate(struct clk_hw *hw, } static const struct clk_ops clk_pll_ops = { + .disable = ccu_pll_disable, + .enable = ccu_pll_enable, + .is_enabled = ccu_pll_is_enabled, .recalc_rate = ccu_pll_recalc_rate, }; @@ -308,7 +336,7 @@ static struct ccu_pll cpu_pll0_clk = { .hw.init = CLK_HW_INIT_PARENTS_DATA("cpu-pll0", osc_24m_clk, &clk_pll_ops, - 0), + CLK_IS_CRITICAL), }, }; @@ -320,7 +348,7 @@ static struct ccu_pll cpu_pll1_clk = { .hw.init = CLK_HW_INIT_PARENTS_DATA("cpu-pll1", osc_24m_clk, &clk_pll_ops, - 0), + CLK_IS_CRITICAL), }, }; @@ -332,7 +360,7 @@ static struct ccu_pll gmac_pll_clk = { .hw.init = CLK_HW_INIT_PARENTS_DATA("gmac-pll", osc_24m_clk, &clk_pll_ops, - 0), + CLK_IS_CRITICAL), }, }; @@ -352,7 +380,7 @@ static struct ccu_pll video_pll_clk = { .hw.init = CLK_HW_INIT_PARENTS_DATA("video-pll", osc_24m_clk, &clk_pll_ops, - 0), + CLK_IS_CRITICAL), }, }; @@ -404,7 +432,7 @@ static struct ccu_pll tee_pll_clk = { .hw.init = CLK_HW_INIT_PARENTS_DATA("tee-pll", osc_24m_clk, &clk_pll_ops, - 0), + CLK_IS_CRITICAL), }, }; From 8fede7ff692cc06791269cd7c68b2bd2f62af159 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sat, 16 Aug 2025 17:11:12 +0800 Subject: [PATCH 0297/2711] clk: thead: support changing DPU pixel clock rate The DPU pixel clock rate corresponds to the required dot clock of the display mode, so it needs to be tweakable. Add support to change it, by adding generic divider setting code, arming the code to the dpu0/dpu1 clocks, and setting the pixel clock connected to the DPU (after a gate) to CLK_SET_RATE_PARENT to propagate it to the dividers. Signed-off-by: Icenowy Zheng Reviewed-by: Drew Fustini Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 63 ++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index d81445e24a96..54222b3219cc 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -56,6 +56,7 @@ struct ccu_gate { struct ccu_div { u32 enable; + u32 div_en; struct ccu_div_internal div; struct ccu_internal mux; struct ccu_common common; @@ -192,6 +193,55 @@ static unsigned long ccu_div_recalc_rate(struct clk_hw *hw, return rate; } +static int ccu_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct ccu_div *cd = hw_to_ccu_div(hw); + unsigned int val; + + if (cd->div_en) + return divider_determine_rate(hw, req, NULL, + cd->div.width, cd->div.flags); + + regmap_read(cd->common.map, cd->common.cfg0, &val); + val = val >> cd->div.shift; + val &= GENMASK(cd->div.width - 1, 0); + return divider_ro_determine_rate(hw, req, NULL, cd->div.width, + cd->div.flags, val); +} + +static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ccu_div *cd = hw_to_ccu_div(hw); + int val = divider_get_val(rate, parent_rate, NULL, + cd->div.width, cd->div.flags); + unsigned int curr_val, reg_val; + + if (val < 0) + return val; + + regmap_read(cd->common.map, cd->common.cfg0, ®_val); + curr_val = reg_val >> cd->div.shift; + curr_val &= GENMASK(cd->div.width - 1, 0); + + if (!cd->div_en && curr_val != val) + return -EINVAL; + + reg_val &= ~cd->div_en; + regmap_write(cd->common.map, cd->common.cfg0, reg_val); + udelay(1); + + reg_val &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift); + reg_val |= val << cd->div.shift; + regmap_write(cd->common.map, cd->common.cfg0, reg_val); + + reg_val |= cd->div_en; + regmap_write(cd->common.map, cd->common.cfg0, reg_val); + + return 0; +} + static u8 ccu_div_get_parent(struct clk_hw *hw) { struct ccu_div *cd = hw_to_ccu_div(hw); @@ -234,7 +284,8 @@ static const struct clk_ops ccu_div_ops = { .get_parent = ccu_div_get_parent, .set_parent = ccu_div_set_parent, .recalc_rate = ccu_div_recalc_rate, - .determine_rate = clk_hw_determine_rate_no_reparent, + .set_rate = ccu_div_set_rate, + .determine_rate = ccu_div_determine_rate, }; static void ccu_pll_disable(struct clk_hw *hw) @@ -778,6 +829,7 @@ static struct ccu_div venc_clk = { }; static struct ccu_div dpu0_clk = { + .div_en = BIT(8), .div = TH_CCU_DIV_FLAGS(0, 8, CLK_DIVIDER_ONE_BASED), .common = { .clkid = CLK_DPU0, @@ -785,7 +837,7 @@ static struct ccu_div dpu0_clk = { .hw.init = CLK_HW_INIT_PARENTS_HW("dpu0", dpu0_pll_clk_parent, &ccu_div_ops, - 0), + CLK_SET_RATE_UNGATE), }, }; @@ -794,6 +846,7 @@ static const struct clk_parent_data dpu0_clk_pd[] = { }; static struct ccu_div dpu1_clk = { + .div_en = BIT(8), .div = TH_CCU_DIV_FLAGS(0, 8, CLK_DIVIDER_ONE_BASED), .common = { .clkid = CLK_DPU1, @@ -801,7 +854,7 @@ static struct ccu_div dpu1_clk = { .hw.init = CLK_HW_INIT_PARENTS_HW("dpu1", dpu1_pll_clk_parent, &ccu_div_ops, - 0), + CLK_SET_RATE_UNGATE), }, }; @@ -889,9 +942,9 @@ static CCU_GATE(CLK_GPU_CORE, gpu_core_clk, "gpu-core-clk", video_pll_clk_pd, static CCU_GATE(CLK_GPU_CFG_ACLK, gpu_cfg_aclk, "gpu-cfg-aclk", video_pll_clk_pd, 0x0, 4, 0); static CCU_GATE(CLK_DPU_PIXELCLK0, dpu0_pixelclk, "dpu0-pixelclk", - dpu0_clk_pd, 0x0, 5, 0); + dpu0_clk_pd, 0x0, 5, CLK_SET_RATE_PARENT); static CCU_GATE(CLK_DPU_PIXELCLK1, dpu1_pixelclk, "dpu1-pixelclk", - dpu1_clk_pd, 0x0, 6, 0); + dpu1_clk_pd, 0x0, 6, CLK_SET_RATE_PARENT); static CCU_GATE(CLK_DPU_HCLK, dpu_hclk, "dpu-hclk", video_pll_clk_pd, 0x0, 7, 0); static CCU_GATE(CLK_DPU_ACLK, dpu_aclk, "dpu-aclk", video_pll_clk_pd, 0x0, From c567bc5fc68c4388c00e11fc65fd14fe86b52070 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sat, 16 Aug 2025 17:11:13 +0800 Subject: [PATCH 0298/2711] clk: thead: th1520-ap: set all AXI clocks to CLK_IS_CRITICAL The AXI crossbar of TH1520 has no proper timeout handling, which means gating AXI clocks can easily lead to bus timeout and thus system hang. Set all AXI clock gates to CLK_IS_CRITICAL. All these clock gates are ungated by default on system reset. In addition, convert all current CLK_IGNORE_UNUSED usage to CLK_IS_CRITICAL to prevent unwanted clock gating. Signed-off-by: Icenowy Zheng Reviewed-by: Drew Fustini Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index 54222b3219cc..26e55e1c6014 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -559,7 +559,7 @@ static struct ccu_div axi4_cpusys2_aclk = { .hw.init = CLK_HW_INIT_PARENTS_HW("axi4-cpusys2-aclk", gmac_pll_clk_parent, &ccu_div_ops, - 0), + CLK_IS_CRITICAL), }, }; @@ -581,7 +581,7 @@ static struct ccu_div axi_aclk = { .hw.init = CLK_HW_INIT_PARENTS_DATA("axi-aclk", axi_parents, &ccu_div_ops, - 0), + CLK_IS_CRITICAL), }, }; @@ -730,7 +730,7 @@ static struct ccu_div apb_pclk = { .hw.init = CLK_HW_INIT_PARENTS_DATA("apb-pclk", apb_parents, &ccu_div_ops, - CLK_IGNORE_UNUSED), + CLK_IS_CRITICAL), }, }; @@ -761,7 +761,7 @@ static struct ccu_div vi_clk = { .hw.init = CLK_HW_INIT_PARENTS_HW("vi", video_pll_clk_parent, &ccu_div_ops, - 0), + CLK_IS_CRITICAL), }, }; @@ -786,7 +786,7 @@ static struct ccu_div vo_axi_clk = { .hw.init = CLK_HW_INIT_PARENTS_HW("vo-axi", video_pll_clk_parent, &ccu_div_ops, - 0), + CLK_IS_CRITICAL), }, }; @@ -811,7 +811,7 @@ static struct ccu_div vp_axi_clk = { .hw.init = CLK_HW_INIT_PARENTS_HW("vp-axi", video_pll_clk_parent, &ccu_div_ops, - CLK_IGNORE_UNUSED), + CLK_IS_CRITICAL), }, }; @@ -872,27 +872,27 @@ static const struct clk_parent_data emmc_sdio_ref_clk_pd[] = { static CCU_GATE(CLK_BROM, brom_clk, "brom", ahb2_cpusys_hclk_pd, 0x100, 4, 0); static CCU_GATE(CLK_BMU, bmu_clk, "bmu", axi4_cpusys2_aclk_pd, 0x100, 5, 0); static CCU_GATE(CLK_AON2CPU_A2X, aon2cpu_a2x_clk, "aon2cpu-a2x", axi4_cpusys2_aclk_pd, - 0x134, 8, 0); + 0x134, 8, CLK_IS_CRITICAL); static CCU_GATE(CLK_X2X_CPUSYS, x2x_cpusys_clk, "x2x-cpusys", axi4_cpusys2_aclk_pd, - 0x134, 7, 0); + 0x134, 7, CLK_IS_CRITICAL); static CCU_GATE(CLK_CPU2AON_X2H, cpu2aon_x2h_clk, "cpu2aon-x2h", axi_aclk_pd, - 0x138, 8, CLK_IGNORE_UNUSED); + 0x138, 8, CLK_IS_CRITICAL); static CCU_GATE(CLK_CPU2PERI_X2H, cpu2peri_x2h_clk, "cpu2peri-x2h", axi4_cpusys2_aclk_pd, - 0x140, 9, CLK_IGNORE_UNUSED); + 0x140, 9, CLK_IS_CRITICAL); static CCU_GATE(CLK_PERISYS_APB1_HCLK, perisys_apb1_hclk, "perisys-apb1-hclk", perisys_ahb_hclk_pd, - 0x150, 9, CLK_IGNORE_UNUSED); + 0x150, 9, CLK_IS_CRITICAL); static CCU_GATE(CLK_PERISYS_APB2_HCLK, perisys_apb2_hclk, "perisys-apb2-hclk", perisys_ahb_hclk_pd, - 0x150, 10, CLK_IGNORE_UNUSED); + 0x150, 10, CLK_IS_CRITICAL); static CCU_GATE(CLK_PERISYS_APB3_HCLK, perisys_apb3_hclk, "perisys-apb3-hclk", perisys_ahb_hclk_pd, - 0x150, 11, CLK_IGNORE_UNUSED); + 0x150, 11, CLK_IS_CRITICAL); static CCU_GATE(CLK_PERISYS_APB4_HCLK, perisys_apb4_hclk, "perisys-apb4-hclk", perisys_ahb_hclk_pd, 0x150, 12, 0); static const struct clk_parent_data perisys_apb4_hclk_pd[] = { { .hw = &perisys_apb4_hclk.gate.hw }, }; -static CCU_GATE(CLK_NPU_AXI, npu_axi_clk, "npu-axi", axi_aclk_pd, 0x1c8, 5, 0); -static CCU_GATE(CLK_CPU2VP, cpu2vp_clk, "cpu2vp", axi_aclk_pd, 0x1e0, 13, 0); +static CCU_GATE(CLK_NPU_AXI, npu_axi_clk, "npu-axi", axi_aclk_pd, 0x1c8, 5, CLK_IS_CRITICAL); +static CCU_GATE(CLK_CPU2VP, cpu2vp_clk, "cpu2vp", axi_aclk_pd, 0x1e0, 13, CLK_IS_CRITICAL); static CCU_GATE(CLK_EMMC_SDIO, emmc_sdio_clk, "emmc-sdio", emmc_sdio_ref_clk_pd, 0x204, 30, 0); static CCU_GATE(CLK_GMAC1, gmac1_clk, "gmac1", gmac_pll_clk_pd, 0x204, 26, 0); static CCU_GATE(CLK_PADCTRL1, padctrl1_clk, "padctrl1", perisys_apb_pclk_pd, 0x204, 24, 0); @@ -936,11 +936,11 @@ static CCU_GATE(CLK_SRAM2, sram2_clk, "sram2", axi_aclk_pd, 0x20c, 2, 0); static CCU_GATE(CLK_SRAM3, sram3_clk, "sram3", axi_aclk_pd, 0x20c, 1, 0); static CCU_GATE(CLK_AXI4_VO_ACLK, axi4_vo_aclk, "axi4-vo-aclk", - video_pll_clk_pd, 0x0, 0, 0); + video_pll_clk_pd, 0x0, 0, CLK_IS_CRITICAL); static CCU_GATE(CLK_GPU_CORE, gpu_core_clk, "gpu-core-clk", video_pll_clk_pd, 0x0, 3, 0); static CCU_GATE(CLK_GPU_CFG_ACLK, gpu_cfg_aclk, "gpu-cfg-aclk", - video_pll_clk_pd, 0x0, 4, 0); + video_pll_clk_pd, 0x0, 4, CLK_IS_CRITICAL); static CCU_GATE(CLK_DPU_PIXELCLK0, dpu0_pixelclk, "dpu0-pixelclk", dpu0_clk_pd, 0x0, 5, CLK_SET_RATE_PARENT); static CCU_GATE(CLK_DPU_PIXELCLK1, dpu1_pixelclk, "dpu1-pixelclk", @@ -972,9 +972,9 @@ static CCU_GATE(CLK_MIPI_DSI1_REFCLK, mipi_dsi1_refclk, "mipi-dsi1-refclk", static CCU_GATE(CLK_HDMI_I2S, hdmi_i2s_clk, "hdmi-i2s-clk", video_pll_clk_pd, 0x0, 19, 0); static CCU_GATE(CLK_X2H_DPU1_ACLK, x2h_dpu1_aclk, "x2h-dpu1-aclk", - video_pll_clk_pd, 0x0, 20, 0); + video_pll_clk_pd, 0x0, 20, CLK_IS_CRITICAL); static CCU_GATE(CLK_X2H_DPU_ACLK, x2h_dpu_aclk, "x2h-dpu-aclk", - video_pll_clk_pd, 0x0, 21, 0); + video_pll_clk_pd, 0x0, 21, CLK_IS_CRITICAL); static CCU_GATE(CLK_AXI4_VO_PCLK, axi4_vo_pclk, "axi4-vo-pclk", video_pll_clk_pd, 0x0, 22, 0); static CCU_GATE(CLK_IOPMP_VOSYS_DPU_PCLK, iopmp_vosys_dpu_pclk, @@ -984,11 +984,11 @@ static CCU_GATE(CLK_IOPMP_VOSYS_DPU1_PCLK, iopmp_vosys_dpu1_pclk, static CCU_GATE(CLK_IOPMP_VOSYS_GPU_PCLK, iopmp_vosys_gpu_pclk, "iopmp-vosys-gpu-pclk", video_pll_clk_pd, 0x0, 25, 0); static CCU_GATE(CLK_IOPMP_DPU1_ACLK, iopmp_dpu1_aclk, "iopmp-dpu1-aclk", - video_pll_clk_pd, 0x0, 27, 0); + video_pll_clk_pd, 0x0, 27, CLK_IS_CRITICAL); static CCU_GATE(CLK_IOPMP_DPU_ACLK, iopmp_dpu_aclk, "iopmp-dpu-aclk", - video_pll_clk_pd, 0x0, 28, 0); + video_pll_clk_pd, 0x0, 28, CLK_IS_CRITICAL); static CCU_GATE(CLK_IOPMP_GPU_ACLK, iopmp_gpu_aclk, "iopmp-gpu-aclk", - video_pll_clk_pd, 0x0, 29, 0); + video_pll_clk_pd, 0x0, 29, CLK_IS_CRITICAL); static CCU_GATE(CLK_MIPIDSI0_PIXCLK, mipi_dsi0_pixclk, "mipi-dsi0-pixclk", video_pll_clk_pd, 0x0, 30, 0); static CCU_GATE(CLK_MIPIDSI1_PIXCLK, mipi_dsi1_pixclk, "mipi-dsi1-pixclk", From edafd4f3fd52a614c5cee2684559367eac2286dc Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 9 Aug 2025 15:29:16 +0530 Subject: [PATCH 0299/2711] dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Document the SM8750 QMP PCIe PHY Gen3 x2 Document the QMP PCIe PHY on the SM8750 platform. Signed-off-by: Krishna Chaitanya Chundru Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250809-pakala-v1-1-abf1c416dbaa@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml index a1ae8c7988c8..cb706cf8219d 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -42,6 +42,7 @@ properties: - qcom,sm8550-qmp-gen4x2-pcie-phy - qcom,sm8650-qmp-gen3x2-pcie-phy - qcom,sm8650-qmp-gen4x2-pcie-phy + - qcom,sm8750-qmp-gen3x2-pcie-phy - qcom,x1e80100-qmp-gen3x2-pcie-phy - qcom,x1e80100-qmp-gen4x2-pcie-phy - qcom,x1e80100-qmp-gen4x4-pcie-phy @@ -164,6 +165,7 @@ allOf: - qcom,sm8550-qmp-gen4x2-pcie-phy - qcom,sm8650-qmp-gen3x2-pcie-phy - qcom,sm8650-qmp-gen4x2-pcie-phy + - qcom,sm8750-qmp-gen3x2-pcie-phy then: properties: clocks: From 0f051749c804b5a4f485013c0e3c932e1dd9f70b Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Sat, 9 Aug 2025 15:29:17 +0530 Subject: [PATCH 0300/2711] phy: qcom-qmp-pcie: add dual lane PHY support for SM8750 The PCIe Gen3 x2 PHY for SM8750 uses new phy, add the required registers and offsets for this phy. Signed-off-by: Krishna Chaitanya Chundru Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250809-pakala-v1-2-abf1c416dbaa@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 149 ++++++++++++++++++ drivers/phy/qualcomm/phy-qcom-qmp-pcs-v7.h | 2 + .../qualcomm/phy-qcom-qmp-qserdes-txrx-v7.h | 4 +- 3 files changed, 154 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 95830dcfdec9..8fdc146ef732 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -93,6 +93,13 @@ static const unsigned int pciephy_v6_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_POWER_DOWN_CONTROL, }; +static const unsigned int pciephy_v7_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V7_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V7_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V7_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V7_PCS_POWER_DOWN_CONTROL, +}; + static const struct qmp_phy_init_tbl msm8998_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14), QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), @@ -2590,6 +2597,108 @@ static const struct qmp_phy_init_tbl sm8650_qmp_gen4x2_pcie_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B6, 0xff), }; +static const struct qmp_phy_init_tbl sm8750_qmp_gen3x2_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_EN_CENTER, 0x1), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_PER1, 0x62), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_STEP_SIZE1_MODE0, 0xf8), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_STEP_SIZE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_STEP_SIZE1_MODE1, 0x93), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SSC_STEP_SIZE2_MODE1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SYS_CLK_CTRL, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CP_CTRL_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CP_CTRL_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_LOCK_CMP_EN, 0x42), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_LOCK_CMP1_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_LOCK_CMP2_MODE0, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_LOCK_CMP1_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_LOCK_CMP2_MODE1, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DEC_START_MODE0, 0x41), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DEC_START_MODE1, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START2_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START3_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START1_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START2_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_DIV_FRAC_START3_MODE1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_VCO_TUNE_MAP, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CLK_SELECT, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_HSCLK_SEL_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CORECLK_DIV_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CMN_CONFIG_1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_ADDITIONAL_MISC_3, 0x0F), + QMP_PHY_INIT_CFG(QSERDES_V7_COM_CORE_CLK_EN, 0xA0), +}; + +static const struct qmp_phy_init_tbl sm8750_qmp_gen3x2_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V7_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_GM_CAL, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_00_HIGH, 0xBF), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_00_HIGH2, 0xBF), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_00_HIGH3, 0xB7), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_00_HIGH4, 0xEA), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_00_LOW, 0x3F), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_01_HIGH, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_01_HIGH2, 0x49), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_01_HIGH3, 0x1B), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_01_HIGH4, 0x9C), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_01_LOW, 0xD1), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_10_HIGH, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_10_HIGH2, 0x49), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_10_HIGH3, 0x1B), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_10_HIGH4, 0x9C), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_MODE_10_LOW, 0xD1), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_TX_ADAPT_PRE_THRESH1, 0x3E), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_TX_ADAPT_PRE_THRESH2, 0x1E), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_TX_ADAPT_POST_THRESH, 0xD2), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_UCDR_FO_GAIN, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_UCDR_SO_GAIN, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_UCDR_SB2_THRESH1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_UCDR_SB2_THRESH2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_VGA_CAL_CNTRL2, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_SIGDET_ENABLES, 0x1C), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_SIGDET_CNTRL, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_RX_IDAC_TSETTLE_LOW, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V7_RX_SIGDET_CAL_TRIM, 0x08), +}; + +static const struct qmp_phy_init_tbl sm8750_qmp_gen3x2_pcie_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V7_TX_LANE_MODE_1, 0x35), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_LANE_MODE_3, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_LANE_MODE_4, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_LANE_MODE_5, 0x7F), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_PI_QEC_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_RES_CODE_LANE_OFFSET_RX, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V7_TX_RES_CODE_LANE_OFFSET_TX, 0x14), +}; + +static const struct qmp_phy_init_tbl sm8750_qmp_gen3x2_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V7_PCS_REFGEN_REQ_CONFIG1, 0x05), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_RX_SIGDET_LVL, 0x77), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_RATE_SLEW_CNTRL1, 0x0B), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_EQ_CONFIG2, 0x0F), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_PCS_TX_RX_CONFIG, 0x8C), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_G12S1_TXDEEMPH_M6DB, 0x17), + QMP_PHY_INIT_CFG(QPHY_V7_PCS_G3S2_PRE_GAIN, 0x2E), +}; + +static const struct qmp_phy_init_tbl sm8750_qmp_gen3x2_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_EQ_CONFIG1, 0x1E), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_RXEQEVAL_TIME, 0x27), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2, 0x1D), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4, 0x07), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xC1), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00), +}; + static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x2_pcie_serdes_alt_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x14), QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f), @@ -3207,6 +3316,16 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v5_30 = { .rx2 = 0x3a00, }; +static const struct qmp_pcie_offsets qmp_pcie_offsets_v7 = { + .serdes = 0x0, + .pcs = 0x400, + .pcs_misc = 0x800, + .tx = 0x1000, + .rx = 0x1200, + .tx2 = 0x1800, + .rx2 = 0x1a00, +}; + static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_20 = { .serdes = 0x1000, .pcs = 0x1200, @@ -3996,6 +4115,33 @@ static const struct qmp_phy_cfg sm8550_qmp_gen3x2_pciephy_cfg = { .phy_status = PHYSTATUS, }; +static const struct qmp_phy_cfg sm8750_qmp_gen3x2_pciephy_cfg = { + .lanes = 2, + + .offsets = &qmp_pcie_offsets_v7, + + .tbls = { + .serdes = sm8750_qmp_gen3x2_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(sm8750_qmp_gen3x2_pcie_serdes_tbl), + .tx = sm8750_qmp_gen3x2_pcie_tx_tbl, + .tx_num = ARRAY_SIZE(sm8750_qmp_gen3x2_pcie_tx_tbl), + .rx = sm8750_qmp_gen3x2_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(sm8750_qmp_gen3x2_pcie_rx_tbl), + .pcs = sm8750_qmp_gen3x2_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(sm8750_qmp_gen3x2_pcie_pcs_tbl), + .pcs_misc = sm8750_qmp_gen3x2_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(sm8750_qmp_gen3x2_pcie_pcs_misc_tbl), + }, + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = pciephy_v7_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS, +}; + static const struct qmp_phy_cfg sm8550_qmp_gen4x2_pciephy_cfg = { .lanes = 2, @@ -5099,6 +5245,9 @@ static const struct of_device_id qmp_pcie_of_match_table[] = { }, { .compatible = "qcom,sm8650-qmp-gen4x2-pcie-phy", .data = &sm8650_qmp_gen4x2_pciephy_cfg, + }, { + .compatible = "qcom,sm8750-qmp-gen3x2-pcie-phy", + .data = &sm8750_qmp_gen3x2_pciephy_cfg, }, { .compatible = "qcom,x1e80100-qmp-gen3x2-pcie-phy", .data = &sm8550_qmp_gen3x2_pciephy_cfg, diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v7.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v7.h index c7759892ed2e..4b7fcaa6a374 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v7.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v7.h @@ -17,6 +17,8 @@ #define QPHY_V7_PCS_LOCK_DETECT_CONFIG3 0x0cc #define QPHY_V7_PCS_LOCK_DETECT_CONFIG6 0x0d8 #define QPHY_V7_PCS_REFGEN_REQ_CONFIG1 0x0dc +#define QPHY_V7_PCS_G12S1_TXDEEMPH_M6DB 0x168 +#define QPHY_V7_PCS_G3S2_PRE_GAIN 0x170 #define QPHY_V7_PCS_RX_SIGDET_LVL 0x188 #define QPHY_V7_PCS_RCVR_DTCT_DLY_P1U2_L 0x190 #define QPHY_V7_PCS_RCVR_DTCT_DLY_P1U2_H 0x194 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v7.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v7.h index 91f865b11347..6ab943ff57ff 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v7.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v7.h @@ -40,6 +40,8 @@ #define QSERDES_V7_RX_UCDR_SB2_GAIN1 0x54 #define QSERDES_V7_RX_UCDR_SB2_GAIN2 0x58 #define QSERDES_V7_RX_AUX_DATA_TCOARSE_TFINE 0x60 +#define QSERDES_V7_RX_TX_ADAPT_PRE_THRESH1 0xc4 +#define QSERDES_V7_RX_TX_ADAPT_PRE_THRESH2 0xc8 #define QSERDES_V7_RX_TX_ADAPT_POST_THRESH 0xcc #define QSERDES_V7_RX_VGA_CAL_CNTRL1 0xd4 #define QSERDES_V7_RX_VGA_CAL_CNTRL2 0xd8 @@ -50,7 +52,7 @@ #define QSERDES_V7_RX_RX_IDAC_TSETTLE_LOW 0xf8 #define QSERDES_V7_RX_RX_IDAC_TSETTLE_HIGH 0xfc #define QSERDES_V7_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x110 -#define QSERDES_V7_RX_SIDGET_ENABLES 0x118 +#define QSERDES_V7_RX_SIGDET_ENABLES 0x118 #define QSERDES_V7_RX_SIGDET_CNTRL 0x11c #define QSERDES_V7_RX_SIGDET_DEGLITCH_CNTRL 0x124 #define QSERDES_V7_RX_RX_MODE_00_LOW 0x15c From b33b696f86f6d17c9083d69a13d7f32380d818d3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2025 23:52:57 +0200 Subject: [PATCH 0301/2711] platform/x86: int3472: Convert int3472_gpio_map to use C99 initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert int3472_gpio_map to use C99 initializers to make it clearer which struct field is set to which value. Suggested-by: Andy Shevchenko Signed-off-by: Hans de Goede Reviewed-by: Sakari Ailus Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20250725215259.402796-2-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/int3472/discrete.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 4c0aed6e626f..f3e7e0ab7fad 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -142,10 +142,18 @@ struct int3472_gpio_map { }; static const struct int3472_gpio_map int3472_gpio_map[] = { - /* mt9m114 designs declare a powerdown pin which controls the regulators */ - { "INT33F0", INT3472_GPIO_TYPE_POWERDOWN, INT3472_GPIO_TYPE_POWER_ENABLE, false, "vdd" }, - /* ov7251 driver / DT-bindings expect "enable" as con_id for reset */ - { "INT347E", INT3472_GPIO_TYPE_RESET, INT3472_GPIO_TYPE_RESET, false, "enable" }, + { /* mt9m114 designs declare a powerdown pin which controls the regulators */ + .hid = "INT33F0", + .type_from = INT3472_GPIO_TYPE_POWERDOWN, + .type_to = INT3472_GPIO_TYPE_POWER_ENABLE, + .con_id = "vdd", + }, + { /* ov7251 driver / DT-bindings expect "enable" as con_id for reset */ + .hid = "INT347E", + .type_from = INT3472_GPIO_TYPE_RESET, + .type_to = INT3472_GPIO_TYPE_RESET, + .con_id = "enable", + }, }; static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3472, u8 *type, From f11f8948a826afba66355302ba7e4b3e36333038 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2025 23:52:58 +0200 Subject: [PATCH 0302/2711] platform/x86: int3472: Rework regulator enable-time handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of hardcoding the regulator enable-time for INT3472_GPIO_TYPE- POWER_ENABLE and -HANDSHAKE, make int3472_get_con_id_and_polarity() set the enable-time. This will allow overriding the enable time through quirks in the int3472_gpio_map[]. Signed-off-by: Hans de Goede Reviewed-by: Sakari Ailus Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20250725215259.402796-3-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/int3472/discrete.c | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index f3e7e0ab7fad..791ea565fdc1 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -129,6 +129,7 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472, * @hid: The ACPI HID of the device without the instance number e.g. INT347E * @type_from: The GPIO type from ACPI ?SDT * @type_to: The assigned GPIO type, typically same as @type_from + * @enable_time_us: Enable time in usec for GPIOs mapped to regulators * @con_id: The name of the GPIO for the device * @polarity_low: GPIO_ACTIVE_LOW true if the @polarity_low is true, * GPIO_ACTIVE_HIGH otherwise @@ -138,6 +139,7 @@ struct int3472_gpio_map { u8 type_from; u8 type_to; bool polarity_low; + unsigned int enable_time_us; const char *con_id; }; @@ -147,6 +149,7 @@ static const struct int3472_gpio_map int3472_gpio_map[] = { .type_from = INT3472_GPIO_TYPE_POWERDOWN, .type_to = INT3472_GPIO_TYPE_POWER_ENABLE, .con_id = "vdd", + .enable_time_us = GPIO_REGULATOR_ENABLE_TIME, }, { /* ov7251 driver / DT-bindings expect "enable" as con_id for reset */ .hid = "INT347E", @@ -157,7 +160,8 @@ static const struct int3472_gpio_map int3472_gpio_map[] = { }; static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3472, u8 *type, - const char **con_id, unsigned long *gpio_flags) + const char **con_id, unsigned long *gpio_flags, + unsigned int *enable_time_us) { struct acpi_device *adev = int3472->sensor; unsigned int i; @@ -181,9 +185,12 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 *gpio_flags = int3472_gpio_map[i].polarity_low ? GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH; *con_id = int3472_gpio_map[i].con_id; + *enable_time_us = int3472_gpio_map[i].enable_time_us; return; } + *enable_time_us = GPIO_REGULATOR_ENABLE_TIME; + switch (*type) { case INT3472_GPIO_TYPE_RESET: *con_id = "reset"; @@ -208,6 +215,8 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 case INT3472_GPIO_TYPE_HANDSHAKE: *con_id = "dvdd"; *gpio_flags = GPIO_ACTIVE_HIGH; + /* Setups using a handshake pin need 25 ms enable delay */ + *enable_time_us = 25 * USEC_PER_MSEC; break; default: *con_id = "unknown"; @@ -252,13 +261,15 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, void *data) { struct int3472_discrete_device *int3472 = data; + const char *second_sensor = NULL; struct acpi_resource_gpio *agpio; + unsigned int enable_time_us; u8 active_value, pin, type; + unsigned long gpio_flags; union acpi_object *obj; struct gpio_desc *gpio; const char *err_msg; const char *con_id; - unsigned long gpio_flags; int ret; if (!acpi_gpio_get_io_resource(ares, &agpio)) @@ -281,7 +292,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, type = FIELD_GET(INT3472_GPIO_DSM_TYPE, obj->integer.value); - int3472_get_con_id_and_polarity(int3472, &type, &con_id, &gpio_flags); + int3472_get_con_id_and_polarity(int3472, &type, &con_id, &gpio_flags, &enable_time_us); pin = FIELD_GET(INT3472_GPIO_DSM_PIN, obj->integer.value); /* Pin field is not really used under Windows and wraps around at 8 bits */ @@ -330,21 +341,13 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, break; case INT3472_GPIO_TYPE_POWER_ENABLE: - ret = skl_int3472_register_regulator(int3472, gpio, - GPIO_REGULATOR_ENABLE_TIME, - con_id, - int3472->quirks.avdd_second_sensor); - if (ret) - err_msg = "Failed to map power-enable to sensor\n"; - - break; + second_sensor = int3472->quirks.avdd_second_sensor; + fallthrough; case INT3472_GPIO_TYPE_HANDSHAKE: - /* Setups using a handshake pin need 25 ms enable delay */ - ret = skl_int3472_register_regulator(int3472, gpio, - 25 * USEC_PER_MSEC, - con_id, NULL); + ret = skl_int3472_register_regulator(int3472, gpio, enable_time_us, + con_id, second_sensor); if (ret) - err_msg = "Failed to map handshake to sensor\n"; + err_msg = "Failed to register regulator\n"; break; default: /* Never reached */ From 30359c239ba8394c8e774151d26914db18dc4976 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2025 23:52:59 +0200 Subject: [PATCH 0303/2711] platform/x86: int3472: Increase ov08x40 handshake GPIO delay to 45 ms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On HP laptops with an ov08x40 sensor the 25 ms delay coming from Intel's out of tree drivers is not enough. Testing has confirmed that 45 ms does work. Add a quirk to the int3472_gpio_map[] to increase the delay to 45 ms to fix probing of the ov08x40 sensor failing on these laptops. Note this only impacts laptops which actually use an ov08x40 sensor with a handshake GPIO. Link: https://bugzilla.redhat.com/show_bug.cgi?id=2333331 Signed-off-by: Hans de Goede Reviewed-by: Sakari Ailus Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20250725215259.402796-4-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/int3472/discrete.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 791ea565fdc1..8d721c23f801 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -157,6 +157,13 @@ static const struct int3472_gpio_map int3472_gpio_map[] = { .type_to = INT3472_GPIO_TYPE_RESET, .con_id = "enable", }, + { /* ov08x40's handshake pin needs a 45 ms delay on some HP laptops */ + .hid = "OVTI08F4", + .type_from = INT3472_GPIO_TYPE_HANDSHAKE, + .type_to = INT3472_GPIO_TYPE_HANDSHAKE, + .con_id = "dvdd", + .enable_time_us = 45 * USEC_PER_MSEC, + }, }; static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3472, u8 *type, From 6e6fe5a99048c020594d815a1c0f8ad183073e66 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jul 2025 11:54:22 +0100 Subject: [PATCH 0304/2711] misc: Fix spelling mistake "STMicroeletronics" -> "STMicroelectronics" There is are spelling mistakes in the SENSORS_LIS3_SPI and SENSORS_LIS3_I2C Kconfig. Fix them. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20250724105422.140186-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lis3lv02d/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/lis3lv02d/Kconfig b/drivers/misc/lis3lv02d/Kconfig index 56005243a230..9d546a42a563 100644 --- a/drivers/misc/lis3lv02d/Kconfig +++ b/drivers/misc/lis3lv02d/Kconfig @@ -4,7 +4,7 @@ # config SENSORS_LIS3_SPI - tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" + tristate "STMicroelectronics LIS3LV02Dx three-axis digital accelerometer (SPI)" depends on !ACPI && SPI_MASTER && INPUT select SENSORS_LIS3LV02D help @@ -20,7 +20,7 @@ config SENSORS_LIS3_SPI is called lis3lv02d_spi. config SENSORS_LIS3_I2C - tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)" + tristate "STMicroelectronics LIS3LV02Dx three-axis digital accelerometer (I2C)" depends on I2C && INPUT select SENSORS_LIS3LV02D help From 807221d3c5ff6e3c91ff57bc82a0b7a541462e20 Mon Sep 17 00:00:00 2001 From: Ricky Wu Date: Tue, 12 Aug 2025 14:35:21 +0800 Subject: [PATCH 0305/2711] misc: rtsx_pci: Add separate CD/WP pin polarity reversal support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the Card Detect (CD) and Write Protect (WP) pins shared the same reverse polarity setting in the configuration space. This meant both signals were reversed together, without the ability to configure them individually. This patch introduces two new parameters: sd_cd_reverse_en – enable reverse polarity for the CD pin. sd_wp_reverse_en – enable reverse polarity for the WP pin. With this change, the controller can now support: 1.Reversing both CD and WP pins together (original behavior). 2.Reversing CD and WP pins separately (newly added behavior), if supported by the configuration space. This provides greater flexibility when dealing with devices that have independent polarity requirements for CD and WP pins. Signed-off-by: Ricky Wu Link: https://lore.kernel.org/r/20250812063521.2427696-1-ricky_wu@realtek.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/rts5227.c | 13 ++++++++++--- drivers/misc/cardreader/rts5228.c | 12 ++++++++++-- drivers/misc/cardreader/rts5249.c | 16 +++++++++++++--- drivers/misc/cardreader/rts5264.c | 20 ++++++++++++++++---- drivers/misc/cardreader/rts5264.h | 1 + drivers/misc/cardreader/rtsx_pcr.h | 2 ++ include/linux/rtsx_pci.h | 2 ++ 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/drivers/misc/cardreader/rts5227.c b/drivers/misc/cardreader/rts5227.c index cd512284bfb3..46444bb47f65 100644 --- a/drivers/misc/cardreader/rts5227.c +++ b/drivers/misc/cardreader/rts5227.c @@ -79,6 +79,10 @@ static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr) pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); if (rtsx_reg_check_reverse_socket(reg)) pcr->flags |= PCR_REVERSE_SOCKET; + if (rtsx_reg_check_cd_reverse(reg)) + pcr->option.sd_cd_reverse_en = 1; + if (rtsx_reg_check_wp_reverse(reg)) + pcr->option.sd_wp_reverse_en = 1; } static void rts5227_init_from_cfg(struct rtsx_pcr *pcr) @@ -127,8 +131,10 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) /* Configure force_clock_req */ if (pcr->flags & PCR_REVERSE_SOCKET) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x30, 0x30); - else - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x30, 0x00); + else { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x20, option->sd_cd_reverse_en << 5); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x10, option->sd_wp_reverse_en << 4); + } if (CHK_PCI_PID(pcr, 0x522A)) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_AUTOLOAD_CFG1, @@ -350,6 +356,8 @@ void rts5227_init_params(struct rtsx_pcr *pcr) pcr->ms_pull_ctl_disable_tbl = rts5227_ms_pull_ctl_disable_tbl; pcr->reg_pm_ctrl3 = PM_CTRL3; + pcr->option.sd_cd_reverse_en = 0; + pcr->option.sd_wp_reverse_en = 0; } static int rts522a_optimize_phy(struct rtsx_pcr *pcr) @@ -508,5 +516,4 @@ void rts522a_init_params(struct rtsx_pcr *pcr) pcr->hw_param.interrupt_en |= SD_OC_INT_EN; pcr->hw_param.ocp_glitch = SD_OCP_GLITCH_10M; pcr->option.sd_800mA_ocp_thd = RTS522A_OCP_THD_800; - } diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c index 0c7f10bcf6f1..db7e735ac24f 100644 --- a/drivers/misc/cardreader/rts5228.c +++ b/drivers/misc/cardreader/rts5228.c @@ -84,6 +84,10 @@ static void rtsx5228_fetch_vendor_settings(struct rtsx_pcr *pcr) pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); if (rtsx_reg_check_reverse_socket(reg)) pcr->flags |= PCR_REVERSE_SOCKET; + if (rtsx_reg_check_cd_reverse(reg)) + pcr->option.sd_cd_reverse_en = 1; + if (rtsx_reg_check_wp_reverse(reg)) + pcr->option.sd_wp_reverse_en = 1; } static int rts5228_optimize_phy(struct rtsx_pcr *pcr) @@ -432,8 +436,10 @@ static int rts5228_extra_init_hw(struct rtsx_pcr *pcr) if (pcr->flags & PCR_REVERSE_SOCKET) rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x30); - else - rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00); + else { + rtsx_pci_write_register(pcr, PETXCFG, 0x20, option->sd_cd_reverse_en << 5); + rtsx_pci_write_register(pcr, PETXCFG, 0x10, option->sd_wp_reverse_en << 4); + } /* * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced @@ -720,4 +726,6 @@ void rts5228_init_params(struct rtsx_pcr *pcr) hw_param->interrupt_en |= SD_OC_INT_EN; hw_param->ocp_glitch = SD_OCP_GLITCH_800U; option->sd_800mA_ocp_thd = RTS5228_LDO1_OCP_THD_930; + option->sd_cd_reverse_en = 0; + option->sd_wp_reverse_en = 0; } diff --git a/drivers/misc/cardreader/rts5249.c b/drivers/misc/cardreader/rts5249.c index 6c81040e18be..38aefd8db452 100644 --- a/drivers/misc/cardreader/rts5249.c +++ b/drivers/misc/cardreader/rts5249.c @@ -60,6 +60,7 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr) pci_read_config_dword(pdev, PCR_SETTING_REG1, ®); pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); + pci_write_config_dword(pdev, 0x718, 0x0007C000); if (!rtsx_vendor_setting_valid(reg)) { pcr_dbg(pcr, "skip fetch vendor setting\n"); @@ -82,6 +83,10 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr) pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); if (rtsx_reg_check_reverse_socket(reg)) pcr->flags |= PCR_REVERSE_SOCKET; + if (rtsx_reg_check_cd_reverse(reg)) + pcr->option.sd_cd_reverse_en = 1; + if (rtsx_reg_check_wp_reverse(reg)) + pcr->option.sd_wp_reverse_en = 1; } static void rts5249_init_from_cfg(struct rtsx_pcr *pcr) @@ -254,9 +259,11 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) /* Configure driving */ rts5249_fill_driving(pcr, OUTPUT_3V3); if (pcr->flags & PCR_REVERSE_SOCKET) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0xB0); - else - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0x80); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x30, 0x30); + else { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x20, option->sd_cd_reverse_en << 5); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x10, option->sd_wp_reverse_en << 4); + } rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF); @@ -572,6 +579,9 @@ void rts5249_init_params(struct rtsx_pcr *pcr) option->ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5249_DEF; option->ltr_l1off_snooze_sspwrgate = LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF; + + option->sd_cd_reverse_en = 0; + option->sd_wp_reverse_en = 0; } static int rts524a_write_phy(struct rtsx_pcr *pcr, u8 addr, u16 val) diff --git a/drivers/misc/cardreader/rts5264.c b/drivers/misc/cardreader/rts5264.c index d050c9fff7ac..99a2d5ea6421 100644 --- a/drivers/misc/cardreader/rts5264.c +++ b/drivers/misc/cardreader/rts5264.c @@ -527,8 +527,16 @@ static void rts5264_init_from_hw(struct rtsx_pcr *pcr) pcr->rtd3_en = rts5264_reg_to_rtd3(lval2); - if (rts5264_reg_check_reverse_socket(lval2)) - pcr->flags |= PCR_REVERSE_SOCKET; + if (rts5264_reg_check_reverse_socket(lval2)) { + if (is_version_higher_than(pcr, PID_5264, RTS5264_IC_VER_B)) + pcr->option.sd_cd_reverse_en = 1; + else + pcr->flags |= PCR_REVERSE_SOCKET; + } + + if (rts5264_reg_check_wp_reverse(lval2) && + is_version_higher_than(pcr, PID_5264, RTS5264_IC_VER_B)) + pcr->option.sd_wp_reverse_en = 1; pci_read_config_dword(pdev, setting_reg1, &lval1); pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", setting_reg1, lval1); @@ -622,8 +630,10 @@ static int rts5264_extra_init_hw(struct rtsx_pcr *pcr) if (pcr->flags & PCR_REVERSE_SOCKET) rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x30); - else - rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00); + else { + rtsx_pci_write_register(pcr, PETXCFG, 0x20, option->sd_cd_reverse_en << 5); + rtsx_pci_write_register(pcr, PETXCFG, 0x10, option->sd_wp_reverse_en << 4); + } /* * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced @@ -957,4 +967,6 @@ void rts5264_init_params(struct rtsx_pcr *pcr) hw_param->interrupt_en |= (SD_OC_INT_EN | SD_OVP_INT_EN); hw_param->ocp_glitch = SD_OCP_GLITCH_800U | SDVIO_OCP_GLITCH_800U; option->sd_800mA_ocp_thd = RTS5264_LDO1_OCP_THD_1150; + option->sd_cd_reverse_en = 0; + option->sd_wp_reverse_en = 0; } diff --git a/drivers/misc/cardreader/rts5264.h b/drivers/misc/cardreader/rts5264.h index f3e81daa708d..611ee253367c 100644 --- a/drivers/misc/cardreader/rts5264.h +++ b/drivers/misc/cardreader/rts5264.h @@ -14,6 +14,7 @@ #define rts5264_reg_to_aspm(reg) \ (((~(reg) >> 28) & 0x02) | (((reg) >> 28) & 0x01)) #define rts5264_reg_check_reverse_socket(reg) ((reg) & 0x04) +#define rts5264_reg_check_wp_reverse(reg) ((reg) & 0x8000) #define rts5264_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 22) & 0x03) #define rts5264_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 16) & 0x03) #define rts5264_reg_to_rtd3(reg) ((reg) & 0x08) diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h index 8e5951b61143..40562ff2be13 100644 --- a/drivers/misc/cardreader/rtsx_pcr.h +++ b/drivers/misc/cardreader/rtsx_pcr.h @@ -100,6 +100,8 @@ static inline u8 map_sd_drive(int idx) #define rtsx_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 5) & 0x03) #define rtsx_reg_to_card_drive_sel(reg) ((((reg) >> 25) & 0x01) << 6) #define rtsx_reg_check_reverse_socket(reg) ((reg) & 0x4000) +#define rtsx_reg_check_cd_reverse(reg) ((reg) & 0x800000) +#define rtsx_reg_check_wp_reverse(reg) ((reg) & 0x400000) #define rts5209_reg_to_aspm(reg) (((reg) >> 5) & 0x03) #define rts5209_reg_check_ms_pmos(reg) (!((reg) & 0x08)) #define rts5209_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 3) & 0x07) diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index 3b4c36705a9b..3c5689356004 100644 --- a/include/linux/rtsx_pci.h +++ b/include/linux/rtsx_pci.h @@ -1160,6 +1160,8 @@ struct rtsx_cr_option { bool ocp_en; u8 sd_400mA_ocp_thd; u8 sd_800mA_ocp_thd; + u8 sd_cd_reverse_en; + u8 sd_wp_reverse_en; }; /* From 82bfe76853762a7d2b7d699da0e5dbd094f8f998 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Aug 2025 15:05:15 +0200 Subject: [PATCH 0306/2711] misc: apds990x: Drop superfluous return statement Drop a return statement that immediately follows another return statement, and thus is never executed. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/673e667895603b1a1b1ae8ec89e333ac15f4412b.1755090287.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/misc/apds990x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index e7d73c972f65..58946c4ff1a5 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -984,7 +984,6 @@ static ssize_t apds990x_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", !pm_runtime_suspended(dev)); - return 0; } static ssize_t apds990x_power_state_store(struct device *dev, From 89fb7d737f9a3467406c9729609319a8d633e97a Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 13 Aug 2025 20:01:08 +0200 Subject: [PATCH 0307/2711] misc: hisi_hikey_usb: Use str_enabled_disabled() in hub_power_ctrl() Remove hard-coded strings by using the str_enabled_disabled() helper function and silence the following Coccinelle/coccicheck warning reported by string_choices.cocci: opportunity for str_enabled_disabled(value) Signed-off-by: Thorsten Blum Acked-by: John Stultz Link: https://lore.kernel.org/r/20250813180108.209096-2-thorsten.blum@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/misc/hisi_hikey_usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/misc/hisi_hikey_usb.c b/drivers/misc/hisi_hikey_usb.c index ffe7b945a298..2c6e448a47f1 100644 --- a/drivers/misc/hisi_hikey_usb.c +++ b/drivers/misc/hisi_hikey_usb.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #define DEVICE_DRIVER_NAME "hisi_hikey_usb" @@ -67,7 +68,7 @@ static void hub_power_ctrl(struct hisi_hikey_usb *hisi_hikey_usb, int value) if (ret) dev_err(hisi_hikey_usb->dev, "Can't switch regulator state to %s\n", - value ? "enabled" : "disabled"); + str_enabled_disabled(value)); } static void usb_switch_ctrl(struct hisi_hikey_usb *hisi_hikey_usb, From 9e57dbcbde250acab44205ee4cc897c4a87c56d9 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Mon, 18 Aug 2025 18:58:06 +0530 Subject: [PATCH 0308/2711] rust: miscdevice: update ARef import to sync::aref Update the import of `ARef` in misc_device sample to use `sync::aref` instead of `types`. This is part of the ongoing effort to move `ARef` and `AlwaysRefCounted` to the `sync` module for better modularity and type organization. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250818132806.134248-1-shankari.ak0208@gmail.com Signed-off-by: Greg Kroah-Hartman --- samples/rust/rust_misc_device.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_device.rs index e7ab77448f75..911b9320d3c0 100644 --- a/samples/rust/rust_misc_device.rs +++ b/samples/rust/rust_misc_device.rs @@ -105,8 +105,7 @@ use kernel::{ miscdevice::{MiscDevice, MiscDeviceOptions, MiscDeviceRegistration}, new_mutex, prelude::*, - sync::Mutex, - types::ARef, + sync::{aref::ARef, Mutex}, uaccess::{UserSlice, UserSliceReader, UserSliceWriter}, }; From 8ac646d6dfbf8e42bdb31b71e03a7984557ab1b1 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 14 Jul 2025 23:34:12 +0800 Subject: [PATCH 0309/2711] char: misc: Move drivers/misc/misc_minor_kunit.c to drivers/char/ drivers/misc/misc_minor_kunit.c is to test APIs defined in drivers/char/misc.c, but is not in the same directory as the later. Move misc_minor_kunit.c to drivers/char/. Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20250714-rfc_miscdev-v6-1-2ed949665bde@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/Makefile | 1 + drivers/{misc => char}/misc_minor_kunit.c | 0 drivers/misc/Makefile | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename drivers/{misc => char}/misc_minor_kunit.c (100%) diff --git a/drivers/char/Makefile b/drivers/char/Makefile index e9b360cdc99a..1291369b9126 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -6,6 +6,7 @@ obj-y += mem.o random.o obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o obj-y += misc.o +obj-$(CONFIG_TEST_MISC_MINOR) += misc_minor_kunit.o obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o diff --git a/drivers/misc/misc_minor_kunit.c b/drivers/char/misc_minor_kunit.c similarity index 100% rename from drivers/misc/misc_minor_kunit.c rename to drivers/char/misc_minor_kunit.c diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e2e66f5f4fb8..b32a2597d246 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KGDB_TESTS) += kgdbts.o -obj-$(CONFIG_TEST_MISC_MINOR) += misc_minor_kunit.o obj-$(CONFIG_SGI_XP) += sgi-xp/ obj-$(CONFIG_SGI_GRU) += sgi-gru/ obj-$(CONFIG_SMPRO_ERRMON) += smpro-errmon.o From f4e47affdb2edb99834dfd03f5ea8a899bbb98f0 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 14 Jul 2025 23:34:13 +0800 Subject: [PATCH 0310/2711] char: misc: Adapt and add test cases for simple minor space division Adapt and add test cases for next change which regards minor whose value > macro MISC_DYNAMIC_MINOR as invalid parameter when register miscdevice, hence get a simple minor space division below: < MISC_DYNAMIC_MINOR: fixed minor code == MISC_DYNAMIC_MINOR: indicator to request dynamic minor code > MISC_DYNAMIC_MINOR: dynamic minor code requested Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20250714-rfc_miscdev-v6-2-2ed949665bde@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc_minor_kunit.c | 51 ++++++++++++++------------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/drivers/char/misc_minor_kunit.c b/drivers/char/misc_minor_kunit.c index 30eceac5f1b6..3184f383bea8 100644 --- a/drivers/char/misc_minor_kunit.c +++ b/drivers/char/misc_minor_kunit.c @@ -7,12 +7,6 @@ #include #include -/* dynamic minor (2) */ -static struct miscdevice dev_dynamic_minor = { - .minor = 2, - .name = "dev_dynamic_minor", -}; - /* static minor (LCD_MINOR) */ static struct miscdevice dev_static_minor = { .minor = LCD_MINOR, @@ -25,16 +19,6 @@ static struct miscdevice dev_misc_dynamic_minor = { .name = "dev_misc_dynamic_minor", }; -static void kunit_dynamic_minor(struct kunit *test) -{ - int ret; - - ret = misc_register(&dev_dynamic_minor); - KUNIT_EXPECT_EQ(test, 0, ret); - KUNIT_EXPECT_EQ(test, 2, dev_dynamic_minor.minor); - misc_deregister(&dev_dynamic_minor); -} - static void kunit_static_minor(struct kunit *test) { int ret; @@ -157,13 +141,7 @@ static bool is_valid_dynamic_minor(int minor) { if (minor < 0) return false; - if (minor == MISC_DYNAMIC_MINOR) - return false; - if (minor >= 0 && minor <= 15) - return false; - if (minor >= 128 && minor < MISC_DYNAMIC_MINOR) - return false; - return true; + return minor > MISC_DYNAMIC_MINOR; } static int miscdev_test_open(struct inode *inode, struct file *file) @@ -557,7 +535,7 @@ static void __init miscdev_test_conflict(struct kunit *test) */ miscstat.minor = miscdyn.minor; ret = misc_register(&miscstat); - KUNIT_EXPECT_EQ(test, ret, -EBUSY); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); if (ret == 0) misc_deregister(&miscstat); @@ -590,8 +568,9 @@ static void __init miscdev_test_conflict_reverse(struct kunit *test) misc_deregister(&miscdyn); ret = misc_register(&miscstat); - KUNIT_EXPECT_EQ(test, ret, 0); - KUNIT_EXPECT_EQ(test, miscstat.minor, miscdyn.minor); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); + if (ret == 0) + misc_deregister(&miscstat); /* * Try to register a dynamic minor after registering a static minor @@ -601,20 +580,32 @@ static void __init miscdev_test_conflict_reverse(struct kunit *test) miscdyn.minor = MISC_DYNAMIC_MINOR; ret = misc_register(&miscdyn); KUNIT_EXPECT_EQ(test, ret, 0); - KUNIT_EXPECT_NE(test, miscdyn.minor, miscstat.minor); + KUNIT_EXPECT_EQ(test, miscdyn.minor, miscstat.minor); KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); if (ret == 0) misc_deregister(&miscdyn); +} - miscdev_test_can_open(test, &miscstat); +/* Take minor(> MISC_DYNAMIC_MINOR) as invalid when register miscdevice */ +static void miscdev_test_invalid_input(struct kunit *test) +{ + struct miscdevice misc_test = { + .minor = MISC_DYNAMIC_MINOR + 1, + .name = "misc_test", + .fops = &miscdev_test_fops, + }; + int ret; - misc_deregister(&miscstat); + ret = misc_register(&misc_test); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); + if (ret == 0) + misc_deregister(&misc_test); } static struct kunit_case test_cases[] = { - KUNIT_CASE(kunit_dynamic_minor), KUNIT_CASE(kunit_static_minor), KUNIT_CASE(kunit_misc_dynamic_minor), + KUNIT_CASE(miscdev_test_invalid_input), KUNIT_CASE_PARAM(miscdev_test_twice, miscdev_gen_params), KUNIT_CASE_PARAM(miscdev_test_duplicate_minor, miscdev_gen_params), KUNIT_CASE(miscdev_test_duplicate_name), From f5597840ac907858ad2a462b00e4a68fd199121e Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 14 Jul 2025 23:34:14 +0800 Subject: [PATCH 0311/2711] char: misc: Disallow registering miscdevice whose minor > MISC_DYNAMIC_MINOR Currently, It is allowed to register miscdevice with minor > 255 which is defined by macro MISC_DYNAMIC_MINOR, and cause: - Chaos regarding division and management of minor codes. - Registering failure if the minor was allocated to other dynamic request. Fortunately, in-kernel users have not had such usage yet. Fix by refusing to register miscdevice whose minor > 255. Also bring in a very simple minor code space division and management: < 255 : Fixed minor code == 255 : Indicator to request dynamic minor code > 255 : Dynamic minor code requested, 1048320 minor codes totally And all fixed minors allocated should be registered in 'linux/miscdevice.h' Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20250714-rfc_miscdev-v6-3-2ed949665bde@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc.c | 6 ++++++ include/linux/miscdevice.h | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 558302a64dd9..b8e66466184f 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -210,6 +210,12 @@ int misc_register(struct miscdevice *misc) int err = 0; bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR); + if (misc->minor > MISC_DYNAMIC_MINOR) { + pr_err("Invalid fixed minor %d for miscdevice '%s'\n", + misc->minor, misc->name); + return -EINVAL; + } + INIT_LIST_HEAD(&misc->list); mutex_lock(&misc_mtx); diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 3e6deb00fc85..565b88efeb23 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -71,6 +71,14 @@ #define USERIO_MINOR 240 #define VHOST_VSOCK_MINOR 241 #define RFKILL_MINOR 242 + +/* + * Misc char device minor code space division related to below macro: + * + * < 255 : Fixed minor code + * == 255 : Indicator to request dynamic minor code + * > 255 : Dynamic minor code requested, 1048320 minor codes totally. + */ #define MISC_DYNAMIC_MINOR 255 struct miscdevice { From 2334668aaf410382412b8c81f7014283f3e80354 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 14 Jul 2025 23:34:15 +0800 Subject: [PATCH 0312/2711] char: misc: Add a case to test registering miscdevice again without reinitialization For miscdevice who wants dynamic minor, add a cast to test if it can be successfully registered again without reinitialization: 1) Provide Both miscdevice @dev_A and @dev_B want to request dynamic minor by initializing their minor to MISC_DYNAMIC_MINOR. 2) Register then de-register @dev_A. 3) Register @dev_B. 4) Register @dev_A again without reinitialization. 5) Check if @dev_A can be successfully registered. Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20250714-rfc_miscdev-v6-4-2ed949665bde@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc_minor_kunit.c | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/char/misc_minor_kunit.c b/drivers/char/misc_minor_kunit.c index 3184f383bea8..6fc8b05169c5 100644 --- a/drivers/char/misc_minor_kunit.c +++ b/drivers/char/misc_minor_kunit.c @@ -602,6 +602,49 @@ static void miscdev_test_invalid_input(struct kunit *test) misc_deregister(&misc_test); } +/* + * Verify if @miscdyn_a can still be registered successfully without + * reinitialization even if its minor ever owned was requested by + * another miscdevice such as @miscdyn_b. + */ +static void miscdev_test_dynamic_reentry(struct kunit *test) +{ + struct miscdevice miscdyn_a = { + .name = "miscdyn_a", + .minor = MISC_DYNAMIC_MINOR, + .fops = &miscdev_test_fops, + }; + struct miscdevice miscdyn_b = { + .name = "miscdyn_b", + .minor = MISC_DYNAMIC_MINOR, + .fops = &miscdev_test_fops, + }; + int ret, minor_a; + + ret = misc_register(&miscdyn_a); + KUNIT_ASSERT_EQ(test, ret, 0); + KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn_a.minor)); + minor_a = miscdyn_a.minor; + if (ret != 0) + return; + misc_deregister(&miscdyn_a); + + ret = misc_register(&miscdyn_b); + KUNIT_ASSERT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, miscdyn_b.minor, minor_a); + if (ret != 0) + return; + + ret = misc_register(&miscdyn_a); + KUNIT_ASSERT_EQ(test, ret, 0); + KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn_a.minor)); + KUNIT_EXPECT_NE(test, miscdyn_a.minor, miscdyn_b.minor); + if (ret == 0) + misc_deregister(&miscdyn_a); + + misc_deregister(&miscdyn_b); +} + static struct kunit_case test_cases[] = { KUNIT_CASE(kunit_static_minor), KUNIT_CASE(kunit_misc_dynamic_minor), @@ -611,6 +654,7 @@ static struct kunit_case test_cases[] = { KUNIT_CASE(miscdev_test_duplicate_name), KUNIT_CASE(miscdev_test_duplicate_name_leak), KUNIT_CASE_PARAM(miscdev_test_duplicate_error, miscdev_gen_params), + KUNIT_CASE(miscdev_test_dynamic_reentry), {} }; From 52e2bb5ff089d65e2c7d982fe2826dc88e473d50 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 14 Jul 2025 23:34:16 +0800 Subject: [PATCH 0313/2711] char: misc: Make misc_register() reentry for miscdevice who wants dynamic minor For miscdevice who wants dynamic minor, it may fail to be registered again without reinitialization after being de-registered, which is illustrated by kunit test case miscdev_test_dynamic_reentry() newly added. There is a real case found by cascardo when a part of minor range were contained by range [0, 255): 1) wmi/dell-smbios registered minor 122, and acpi_thermal_rel registered minor 123 2) unbind "int3400 thermal" driver from its device, this will de-register acpi_thermal_rel 3) rmmod then insmod dell_smbios again, now wmi/dell-smbios is using minor 123 4) bind the device to "int3400 thermal" driver again, acpi_thermal_rel fails to register. Some drivers may reuse the miscdevice structure after they are deregistered If the intention is to allocate a dynamic minor, if the minor number is not reset to MISC_DYNAMIC_MINOR before calling misc_register(), it will try to register a previously dynamically allocated minor number, which may have been registered by a different driver. One such case is the acpi_thermal_rel misc device, registered by the int3400 thermal driver. If the device is unbound from the driver and later bound, if there was another dynamic misc device registered in between, it would fail to register the acpi_thermal_rel misc device. Other drivers behave similarly. Actually, this kind of issue is prone to happen if APIs misc_register()/misc_deregister() are invoked by driver's probe()/remove() separately. Instead of fixing all the drivers, just reset the minor member to MISC_DYNAMIC_MINOR in misc_deregister() in case it was a dynamically allocated minor number, as error handling of misc_register() does. Cc: Thadeu Lima de Souza Cascardo Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20250714-rfc_miscdev-v6-5-2ed949665bde@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/char/misc.c b/drivers/char/misc.c index b8e66466184f..96ed343cf5c8 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -288,6 +288,8 @@ void misc_deregister(struct miscdevice *misc) list_del(&misc->list); device_destroy(&misc_class, MKDEV(MISC_MAJOR, misc->minor)); misc_minor_free(misc->minor); + if (misc->minor > MISC_DYNAMIC_MINOR) + misc->minor = MISC_DYNAMIC_MINOR; mutex_unlock(&misc_mtx); } EXPORT_SYMBOL(misc_deregister); From 1ba0fb42aa6a5f072b1b8c0b0520b32ad4ef4b45 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 14 Jul 2025 23:34:17 +0800 Subject: [PATCH 0314/2711] char: misc: Does not request module for miscdevice with dynamic minor misc_open() may request module for miscdevice with dynamic minor, which is meaningless since: - The dynamic minor allocated is unknown in advance without registering miscdevice firstly. - Macro MODULE_ALIAS_MISCDEV() is not applicable for dynamic minor. Fix by only requesting module for miscdevice with fixed minor. Acked-by: Thadeu Lima de Souza Cascardo Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20250714-rfc_miscdev-v6-6-2ed949665bde@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 96ed343cf5c8..a0aae0fc7926 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -132,7 +132,8 @@ static int misc_open(struct inode *inode, struct file *file) break; } - if (!new_fops) { + /* Only request module for fixed minor code */ + if (!new_fops && minor < MISC_DYNAMIC_MINOR) { mutex_unlock(&misc_mtx); request_module("char-major-%d-%d", MISC_MAJOR, minor); mutex_lock(&misc_mtx); @@ -144,10 +145,11 @@ static int misc_open(struct inode *inode, struct file *file) new_fops = fops_get(iter->fops); break; } - if (!new_fops) - goto fail; } + if (!new_fops) + goto fail; + /* * Place the miscdevice in the file's * private_data so it can be used by the From d7f8d0758b975db8406c91cf242d46cd9611ba3e Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 14 Jul 2025 23:34:18 +0800 Subject: [PATCH 0315/2711] char: misc: Register fixed minor EISA_EEPROM_MINOR in linux/miscdevice.h Move fixed minor EISA_EEPROM_MINOR definition to linux/miscdevice.h. Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20250714-rfc_miscdev-v6-7-2ed949665bde@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/parisc/eisa_eeprom.c | 2 -- include/linux/miscdevice.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c index 443b15422fc1..601cbb22574f 100644 --- a/drivers/parisc/eisa_eeprom.c +++ b/drivers/parisc/eisa_eeprom.c @@ -15,8 +15,6 @@ #include #include -#define EISA_EEPROM_MINOR 241 - static loff_t eisa_eeprom_llseek(struct file *file, loff_t offset, int origin) { return fixed_size_llseek(file, offset, origin, HPEE_MAX_LENGTH); diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 565b88efeb23..7d0aa718499c 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -70,6 +70,7 @@ #define UHID_MINOR 239 #define USERIO_MINOR 240 #define VHOST_VSOCK_MINOR 241 +#define EISA_EEPROM_MINOR 241 #define RFKILL_MINOR 242 /* From 51ad6d97151c88976a93cdc023d6cd27dce48c38 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 14 Jul 2025 23:34:19 +0800 Subject: [PATCH 0316/2711] sparc: kernel: apc: Remove macro APC_MINOR definition Macro APC_MINOR is defined as MISC_DYNAMIC_MINOR to request dynamic minor, but its name 'APC_MINOR' looks like fixed minor. Remove the macro definition and directly use MISC_DYNAMIC_MINOR instead. Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20250714-rfc_miscdev-v6-8-2ed949665bde@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/apc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c index d44725d37e30..849db20e7165 100644 --- a/arch/sparc/kernel/apc.c +++ b/arch/sparc/kernel/apc.c @@ -28,7 +28,6 @@ * #define APC_DEBUG_LED */ -#define APC_MINOR MISC_DYNAMIC_MINOR #define APC_OBPNAME "power-management" #define APC_DEVNAME "apc" @@ -138,7 +137,7 @@ static const struct file_operations apc_fops = { .llseek = noop_llseek, }; -static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops }; +static struct miscdevice apc_miscdev = { MISC_DYNAMIC_MINOR, APC_DEVNAME, &apc_fops }; static int apc_probe(struct platform_device *op) { From 0e805e8b007d42502dbb7b883cae4794890a40ff Mon Sep 17 00:00:00 2001 From: Nai-Chen Cheng Date: Wed, 6 Aug 2025 14:27:11 +0800 Subject: [PATCH 0317/2711] greybus: svc: use string choice helpers instead of ternary operator Replace ternary operator with str_enabled_disabled() helper to improve code readability and consistency. Generated using Coccinelle semantic patch. Signed-off-by: Nai-Chen Cheng Reviewed-by: Alex Elder Link: https://lore.kernel.org/r/20250806-greybus-string-choices-v1-1-3e1c91048b62@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/greybus/svc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/greybus/svc.c b/drivers/greybus/svc.c index 4256467fcd35..35ea7147dca6 100644 --- a/drivers/greybus/svc.c +++ b/drivers/greybus/svc.c @@ -10,6 +10,7 @@ #include #include #include +#include #define SVC_INTF_EJECT_TIMEOUT 9000 #define SVC_INTF_ACTIVATE_TIMEOUT 6000 @@ -73,7 +74,7 @@ static ssize_t watchdog_show(struct device *dev, struct device_attribute *attr, struct gb_svc *svc = to_gb_svc(dev); return sprintf(buf, "%s\n", - gb_svc_watchdog_enabled(svc) ? "enabled" : "disabled"); + str_enabled_disabled(gb_svc_watchdog_enabled(svc))); } static ssize_t watchdog_store(struct device *dev, From c585a4ad322c9aa64263aeb8004a523d0151b1c3 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Mon, 11 Aug 2025 20:23:58 +0800 Subject: [PATCH 0318/2711] hpet: Use str_plural() to simplify the code Use the string choice helper function str_plural() to simplify the code. Signed-off-by: Xichao Zhao Link: https://lore.kernel.org/r/20250811122358.542190-1-zhao.xichao@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/hpet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 0713ea2b2a51..4f5ccd3a1f56 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -867,7 +867,7 @@ int hpet_alloc(struct hpet_data *hdp) printk(KERN_INFO "hpet%u: at MMIO 0x%lx, IRQ%s", hpetp->hp_which, hdp->hd_phys_address, - hpetp->hp_ntimer > 1 ? "s" : ""); + str_plural(hpetp->hp_ntimer)); for (i = 0; i < hpetp->hp_ntimer; i++) printk(KERN_CONT "%s %u", i > 0 ? "," : "", hdp->hd_irq[i]); printk(KERN_CONT "\n"); From 46b4ddd2c4951c073a16bbf271221240fe2584e5 Mon Sep 17 00:00:00 2001 From: Abd-Alrhman Masalkhi Date: Thu, 17 Jul 2025 06:39:32 +0000 Subject: [PATCH 0319/2711] dt-bindings: eeprom: Add ST M24LR support Add support for STMicroelectronics M24LR RFID/NFC EEPROM chips. These devices use two I2C addresses: the primary address provides access to control and system parameter registers, while the secondary address is used for EEPROM access. Signed-off-by: Abd-Alrhman Masalkhi Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250717063934.5083-2-abd.masalkhi@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/eeprom/st,m24lr.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/eeprom/st,m24lr.yaml diff --git a/Documentation/devicetree/bindings/eeprom/st,m24lr.yaml b/Documentation/devicetree/bindings/eeprom/st,m24lr.yaml new file mode 100644 index 000000000000..0a0820e9d11f --- /dev/null +++ b/Documentation/devicetree/bindings/eeprom/st,m24lr.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/eeprom/st,m24lr.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics M24LR NFC/RFID EEPROM + +maintainers: + - Abd-Alrhman Masalkhi + +description: + STMicroelectronics M24LR series are dual-interface (RF + I2C) + EEPROM chips. These devices support I2C-based access to both + memory and a system area that controls authentication and configuration. + They expose two I2C addresses, one for the system parameter sector and + one for the EEPROM. + +allOf: + - $ref: /schemas/nvmem/nvmem.yaml# + +properties: + compatible: + enum: + - st,m24lr04e-r + - st,m24lr16e-r + - st,m24lr64e-r + + reg: + items: + - description: I2C address used for control/system registers + - description: I2C address used for EEPROM memory access + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + eeprom@57 { + compatible = "st,m24lr04e-r"; + reg = <0x57>, /* primary-device */ + <0x53>; /* secondary-device */ + }; + }; +... From cd5c5e0231c538a5d2d4a73f3b3ffc77ff08449c Mon Sep 17 00:00:00 2001 From: Abd-Alrhman Masalkhi Date: Thu, 17 Jul 2025 06:39:33 +0000 Subject: [PATCH 0320/2711] eeprom: add driver for ST M24LR series RFID/NFC EEPROM chips adds support for STMicroelectronics M24LRxx devices, which expose two separate I2C addresses: one for system control and one for EEPROM access. The driver implements both a sysfs-based interface for control registers (e.g. UID, password authentication) and an nvmem provider for EEPROM access. Signed-off-by: Abd-Alrhman Masalkhi Link: https://lore.kernel.org/r/20250717063934.5083-3-abd.masalkhi@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/Kconfig | 18 ++ drivers/misc/eeprom/Makefile | 1 + drivers/misc/eeprom/m24lr.c | 606 +++++++++++++++++++++++++++++++++++ 3 files changed, 625 insertions(+) create mode 100644 drivers/misc/eeprom/m24lr.c diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 0bef5b93bd6d..4d0ce47aa282 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -120,4 +120,22 @@ config EEPROM_EE1004 This driver can also be built as a module. If so, the module will be called ee1004. +config EEPROM_M24LR + tristate "STMicroelectronics M24LR RFID/NFC EEPROM support" + depends on I2C && SYSFS + select REGMAP_I2C + select NVMEM + select NVMEM_SYSFS + help + This enables support for STMicroelectronics M24LR RFID/NFC EEPROM + chips. These dual-interface devices expose two I2C addresses: + one for EEPROM memory access and another for control and system + configuration (e.g. UID, password handling). + + This driver provides a sysfs interface for control functions and + integrates with the nvmem subsystem for EEPROM access. + + To compile this driver as a module, choose M here: the + module will be called m24lr. + endmenu diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index 65794e526d5d..8f311fd6a4ce 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o obj-$(CONFIG_EEPROM_IDT_89HPESX) += idt_89hpesx.o obj-$(CONFIG_EEPROM_EE1004) += ee1004.o +obj-$(CONFIG_EEPROM_M24LR) += m24lr.o diff --git a/drivers/misc/eeprom/m24lr.c b/drivers/misc/eeprom/m24lr.c new file mode 100644 index 000000000000..0e37f74881ce --- /dev/null +++ b/drivers/misc/eeprom/m24lr.c @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * m24lr.c - Sysfs control interface for ST M24LR series RFID/NFC chips + * + * Copyright (c) 2025 Abd-Alrhman Masalkhi + * + * This driver implements both the sysfs-based control interface and EEPROM + * access for STMicroelectronics M24LR series chips (e.g., M24LR04E-R). + * It provides access to control registers for features such as password + * authentication, memory protection, and device configuration. In addition, + * it manages read and write operations to the EEPROM region of the chip. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define M24LR_WRITE_TIMEOUT 25u +#define M24LR_READ_TIMEOUT (M24LR_WRITE_TIMEOUT) + +/** + * struct m24lr_chip - describes chip-specific sysfs layout + * @sss_len: the length of the sss region + * @page_size: chip-specific limit on the maximum number of bytes allowed + * in a single write operation. + * @eeprom_size: size of the EEPROM in byte + * + * Supports multiple M24LR chip variants (e.g., M24LRxx) by allowing each + * to define its own set of sysfs attributes, depending on its available + * registers and features. + */ +struct m24lr_chip { + unsigned int sss_len; + unsigned int page_size; + unsigned int eeprom_size; +}; + +/** + * struct m24lr - core driver data for M24LR chip control + * @uid: 64 bits unique identifier stored in the device + * @sss_len: the length of the sss region + * @page_size: chip-specific limit on the maximum number of bytes allowed + * in a single write operation. + * @eeprom_size: size of the EEPROM in byte + * @ctl_regmap: regmap interface for accessing the system parameter sector + * @eeprom_regmap: regmap interface for accessing the EEPROM + * @lock: mutex to synchronize operations to the device + * + * Central data structure holding the state and resources used by the + * M24LR device driver. + */ +struct m24lr { + u64 uid; + unsigned int sss_len; + unsigned int page_size; + unsigned int eeprom_size; + struct regmap *ctl_regmap; + struct regmap *eeprom_regmap; + struct mutex lock; /* synchronize operations to the device */ +}; + +static const struct regmap_range m24lr_ctl_vo_ranges[] = { + regmap_reg_range(0, 63), +}; + +static const struct regmap_access_table m24lr_ctl_vo_table = { + .yes_ranges = m24lr_ctl_vo_ranges, + .n_yes_ranges = ARRAY_SIZE(m24lr_ctl_vo_ranges), +}; + +static const struct regmap_config m24lr_ctl_regmap_conf = { + .name = "m24lr_ctl", + .reg_stride = 1, + .reg_bits = 16, + .val_bits = 8, + .disable_locking = false, + .cache_type = REGCACHE_RBTREE,/* Flat can't be used, there's huge gap */ + .volatile_table = &m24lr_ctl_vo_table, +}; + +/* Chip descriptor for M24LR04E-R variant */ +static const struct m24lr_chip m24lr04e_r_chip = { + .page_size = 4, + .eeprom_size = 512, + .sss_len = 4, +}; + +/* Chip descriptor for M24LR16E-R variant */ +static const struct m24lr_chip m24lr16e_r_chip = { + .page_size = 4, + .eeprom_size = 2048, + .sss_len = 16, +}; + +/* Chip descriptor for M24LR64E-R variant */ +static const struct m24lr_chip m24lr64e_r_chip = { + .page_size = 4, + .eeprom_size = 8192, + .sss_len = 64, +}; + +static const struct i2c_device_id m24lr_ids[] = { + { "m24lr04e-r", (kernel_ulong_t)&m24lr04e_r_chip}, + { "m24lr16e-r", (kernel_ulong_t)&m24lr16e_r_chip}, + { "m24lr64e-r", (kernel_ulong_t)&m24lr64e_r_chip}, + { } +}; +MODULE_DEVICE_TABLE(i2c, m24lr_ids); + +static const struct of_device_id m24lr_of_match[] = { + { .compatible = "st,m24lr04e-r", .data = &m24lr04e_r_chip}, + { .compatible = "st,m24lr16e-r", .data = &m24lr16e_r_chip}, + { .compatible = "st,m24lr64e-r", .data = &m24lr64e_r_chip}, + { } +}; +MODULE_DEVICE_TABLE(of, m24lr_of_match); + +/** + * m24lr_regmap_read - read data using regmap with retry on failure + * @regmap: regmap instance for the device + * @buf: buffer to store the read data + * @size: number of bytes to read + * @offset: starting register address + * + * Attempts to read a block of data from the device with retries and timeout. + * Some M24LR chips may transiently NACK reads (e.g., during internal write + * cycles), so this function retries with a short sleep until the timeout + * expires. + * + * Returns: + * Number of bytes read on success, + * -ETIMEDOUT if the read fails within the timeout window. + */ +static ssize_t m24lr_regmap_read(struct regmap *regmap, u8 *buf, + size_t size, unsigned int offset) +{ + int err; + unsigned long timeout, read_time; + ssize_t ret = -ETIMEDOUT; + + timeout = jiffies + msecs_to_jiffies(M24LR_READ_TIMEOUT); + do { + read_time = jiffies; + + err = regmap_bulk_read(regmap, offset, buf, size); + if (!err) { + ret = size; + break; + } + + usleep_range(1000, 2000); + } while (time_before(read_time, timeout)); + + return ret; +} + +/** + * m24lr_regmap_write - write data using regmap with retry on failure + * @regmap: regmap instance for the device + * @buf: buffer containing the data to write + * @size: number of bytes to write + * @offset: starting register address + * + * Attempts to write a block of data to the device with retries and a timeout. + * Some M24LR devices may NACK I2C writes while an internal write operation + * is in progress. This function retries the write operation with a short delay + * until it succeeds or the timeout is reached. + * + * Returns: + * Number of bytes written on success, + * -ETIMEDOUT if the write fails within the timeout window. + */ +static ssize_t m24lr_regmap_write(struct regmap *regmap, const u8 *buf, + size_t size, unsigned int offset) +{ + int err; + unsigned long timeout, write_time; + ssize_t ret = -ETIMEDOUT; + + timeout = jiffies + msecs_to_jiffies(M24LR_WRITE_TIMEOUT); + + do { + write_time = jiffies; + + err = regmap_bulk_write(regmap, offset, buf, size); + if (!err) { + ret = size; + break; + } + + usleep_range(1000, 2000); + } while (time_before(write_time, timeout)); + + return ret; +} + +static ssize_t m24lr_read(struct m24lr *m24lr, u8 *buf, size_t size, + unsigned int offset, bool is_eeprom) +{ + struct regmap *regmap; + ssize_t ret; + + if (is_eeprom) + regmap = m24lr->eeprom_regmap; + else + regmap = m24lr->ctl_regmap; + + mutex_lock(&m24lr->lock); + ret = m24lr_regmap_read(regmap, buf, size, offset); + mutex_unlock(&m24lr->lock); + + return ret; +} + +/** + * m24lr_write - write buffer to M24LR device with page alignment handling + * @m24lr: pointer to driver context + * @buf: data buffer to write + * @size: number of bytes to write + * @offset: target register address in the device + * @is_eeprom: true if the write should target the EEPROM, + * false if it should target the system parameters sector. + * + * Writes data to the M24LR device using regmap, split into chunks no larger + * than page_size to respect device-specific write limitations (e.g., page + * size or I2C hold-time concerns). Each chunk is aligned to the page boundary + * defined by page_size. + * + * Returns: + * Total number of bytes written on success, + * A negative error code if any write fails. + */ +static ssize_t m24lr_write(struct m24lr *m24lr, const u8 *buf, size_t size, + unsigned int offset, bool is_eeprom) +{ + unsigned int n, next_sector; + struct regmap *regmap; + ssize_t ret = 0; + ssize_t err; + + if (is_eeprom) + regmap = m24lr->eeprom_regmap; + else + regmap = m24lr->ctl_regmap; + + n = min_t(unsigned int, size, m24lr->page_size); + next_sector = roundup(offset + 1, m24lr->page_size); + if (offset + n > next_sector) + n = next_sector - offset; + + mutex_lock(&m24lr->lock); + while (n) { + err = m24lr_regmap_write(regmap, buf + offset, n, offset); + if (IS_ERR_VALUE(err)) { + if (!ret) + ret = err; + + break; + } + + offset += n; + size -= n; + ret += n; + n = min_t(unsigned int, size, m24lr->page_size); + } + mutex_unlock(&m24lr->lock); + + return ret; +} + +/** + * m24lr_write_pass - Write password to M24LR043-R using secure format + * @m24lr: Pointer to device control structure + * @buf: Input buffer containing hex-encoded password + * @count: Number of bytes in @buf + * @code: Operation code to embed between password copies + * + * This function parses a 4-byte password, encodes it in big-endian format, + * and constructs a 9-byte sequence of the form: + * + * [BE(password), code, BE(password)] + * + * The result is written to register 0x0900 (2304), which is the password + * register in M24LR04E-R chip. + * + * Return: Number of bytes written on success, or negative error code on failure + */ +static ssize_t m24lr_write_pass(struct m24lr *m24lr, const char *buf, + size_t count, u8 code) +{ + __be32 be_pass; + u8 output[9]; + ssize_t ret; + u32 pass; + int err; + + if (!count) + return -EINVAL; + + if (count > 8) + return -EINVAL; + + err = kstrtou32(buf, 16, &pass); + if (err) + return err; + + be_pass = cpu_to_be32(pass); + + memcpy(output, &be_pass, sizeof(be_pass)); + output[4] = code; + memcpy(output + 5, &be_pass, sizeof(be_pass)); + + mutex_lock(&m24lr->lock); + ret = m24lr_regmap_write(m24lr->ctl_regmap, output, 9, 2304); + mutex_unlock(&m24lr->lock); + + return ret; +} + +static ssize_t m24lr_read_reg_le(struct m24lr *m24lr, u64 *val, + unsigned int reg_addr, + unsigned int reg_size) +{ + ssize_t ret; + __le64 input = 0; + + ret = m24lr_read(m24lr, (u8 *)&input, reg_size, reg_addr, false); + if (IS_ERR_VALUE(ret)) + return ret; + + if (ret != reg_size) + return -EINVAL; + + switch (reg_size) { + case 1: + *val = *(u8 *)&input; + break; + case 2: + *val = le16_to_cpu((__le16)input); + break; + case 4: + *val = le32_to_cpu((__le32)input); + break; + case 8: + *val = le64_to_cpu((__le64)input); + break; + default: + return -EINVAL; + }; + + return 0; +} + +static int m24lr_nvmem_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + ssize_t err; + struct m24lr *m24lr = priv; + + if (!bytes) + return bytes; + + if (offset + bytes > m24lr->eeprom_size) + return -EINVAL; + + err = m24lr_read(m24lr, val, bytes, offset, true); + if (IS_ERR_VALUE(err)) + return err; + + return 0; +} + +static int m24lr_nvmem_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + ssize_t err; + struct m24lr *m24lr = priv; + + if (!bytes) + return -EINVAL; + + if (offset + bytes > m24lr->eeprom_size) + return -EINVAL; + + err = m24lr_write(m24lr, val, bytes, offset, true); + if (IS_ERR_VALUE(err)) + return err; + + return 0; +} + +static ssize_t m24lr_ctl_sss_read(struct file *filep, struct kobject *kobj, + const struct bin_attribute *attr, char *buf, + loff_t offset, size_t count) +{ + struct m24lr *m24lr = attr->private; + + if (!count) + return count; + + if (size_add(offset, count) > m24lr->sss_len) + return -EINVAL; + + return m24lr_read(m24lr, buf, count, offset, false); +} + +static ssize_t m24lr_ctl_sss_write(struct file *filep, struct kobject *kobj, + const struct bin_attribute *attr, char *buf, + loff_t offset, size_t count) +{ + struct m24lr *m24lr = attr->private; + + if (!count) + return -EINVAL; + + if (size_add(offset, count) > m24lr->sss_len) + return -EINVAL; + + return m24lr_write(m24lr, buf, count, offset, false); +} +static BIN_ATTR(sss, 0600, m24lr_ctl_sss_read, m24lr_ctl_sss_write, 0); + +static ssize_t new_pass_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev)); + + return m24lr_write_pass(m24lr, buf, count, 7); +} +static DEVICE_ATTR_WO(new_pass); + +static ssize_t unlock_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev)); + + return m24lr_write_pass(m24lr, buf, count, 9); +} +static DEVICE_ATTR_WO(unlock); + +static ssize_t uid_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev)); + + return sysfs_emit(buf, "%llx\n", m24lr->uid); +} +static DEVICE_ATTR_RO(uid); + +static ssize_t total_sectors_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev)); + + return sysfs_emit(buf, "%x\n", m24lr->sss_len); +} +static DEVICE_ATTR_RO(total_sectors); + +static struct attribute *m24lr_ctl_dev_attrs[] = { + &dev_attr_unlock.attr, + &dev_attr_new_pass.attr, + &dev_attr_uid.attr, + &dev_attr_total_sectors.attr, + NULL, +}; + +static const struct m24lr_chip *m24lr_get_chip(struct device *dev) +{ + const struct m24lr_chip *ret; + const struct i2c_device_id *id; + + id = i2c_match_id(m24lr_ids, to_i2c_client(dev)); + + if (dev->of_node && of_match_device(m24lr_of_match, dev)) + ret = of_device_get_match_data(dev); + else if (id) + ret = (void *)id->driver_data; + else + ret = acpi_device_get_match_data(dev); + + return ret; +} + +static int m24lr_probe(struct i2c_client *client) +{ + struct regmap_config eeprom_regmap_conf = {0}; + struct nvmem_config nvmem_conf = {0}; + struct device *dev = &client->dev; + struct i2c_client *eeprom_client; + const struct m24lr_chip *chip; + struct regmap *eeprom_regmap; + struct nvmem_device *nvmem; + struct regmap *ctl_regmap; + struct m24lr *m24lr; + u32 regs[2]; + long err; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -EOPNOTSUPP; + + chip = m24lr_get_chip(dev); + if (!chip) + return -ENODEV; + + m24lr = devm_kzalloc(dev, sizeof(struct m24lr), GFP_KERNEL); + if (!m24lr) + return -ENOMEM; + + err = device_property_read_u32_array(dev, "reg", regs, ARRAY_SIZE(regs)); + if (err) + return dev_err_probe(dev, err, "Failed to read 'reg' property\n"); + + /* Create a second I2C client for the eeprom interface */ + eeprom_client = devm_i2c_new_dummy_device(dev, client->adapter, regs[1]); + if (IS_ERR(eeprom_client)) + return dev_err_probe(dev, PTR_ERR(eeprom_client), + "Failed to create dummy I2C client for the EEPROM\n"); + + ctl_regmap = devm_regmap_init_i2c(client, &m24lr_ctl_regmap_conf); + if (IS_ERR(ctl_regmap)) + return dev_err_probe(dev, PTR_ERR(ctl_regmap), + "Failed to init regmap\n"); + + eeprom_regmap_conf.name = "m24lr_eeprom"; + eeprom_regmap_conf.reg_bits = 16; + eeprom_regmap_conf.val_bits = 8; + eeprom_regmap_conf.disable_locking = true; + eeprom_regmap_conf.max_register = chip->eeprom_size - 1; + + eeprom_regmap = devm_regmap_init_i2c(eeprom_client, + &eeprom_regmap_conf); + if (IS_ERR(eeprom_regmap)) + return dev_err_probe(dev, PTR_ERR(eeprom_regmap), + "Failed to init regmap\n"); + + mutex_init(&m24lr->lock); + m24lr->sss_len = chip->sss_len; + m24lr->page_size = chip->page_size; + m24lr->eeprom_size = chip->eeprom_size; + m24lr->eeprom_regmap = eeprom_regmap; + m24lr->ctl_regmap = ctl_regmap; + + nvmem_conf.dev = &eeprom_client->dev; + nvmem_conf.owner = THIS_MODULE; + nvmem_conf.type = NVMEM_TYPE_EEPROM; + nvmem_conf.reg_read = m24lr_nvmem_read; + nvmem_conf.reg_write = m24lr_nvmem_write; + nvmem_conf.size = chip->eeprom_size; + nvmem_conf.word_size = 1; + nvmem_conf.stride = 1; + nvmem_conf.priv = m24lr; + + nvmem = devm_nvmem_register(dev, &nvmem_conf); + if (IS_ERR(nvmem)) + return dev_err_probe(dev, PTR_ERR(nvmem), + "Failed to register nvmem\n"); + + i2c_set_clientdata(client, m24lr); + i2c_set_clientdata(eeprom_client, m24lr); + + bin_attr_sss.size = chip->sss_len; + bin_attr_sss.private = m24lr; + err = sysfs_create_bin_file(&dev->kobj, &bin_attr_sss); + if (err) + return dev_err_probe(dev, err, + "Failed to create sss bin file\n"); + + /* test by reading the uid, if success store it */ + err = m24lr_read_reg_le(m24lr, &m24lr->uid, 2324, sizeof(m24lr->uid)); + if (IS_ERR_VALUE(err)) + goto remove_bin_file; + + return 0; + +remove_bin_file: + sysfs_remove_bin_file(&dev->kobj, &bin_attr_sss); + + return err; +} + +static void m24lr_remove(struct i2c_client *client) +{ + sysfs_remove_bin_file(&client->dev.kobj, &bin_attr_sss); +} + +ATTRIBUTE_GROUPS(m24lr_ctl_dev); + +static struct i2c_driver m24lr_driver = { + .driver = { + .name = "m24lr", + .of_match_table = m24lr_of_match, + .dev_groups = m24lr_ctl_dev_groups, + }, + .probe = m24lr_probe, + .remove = m24lr_remove, + .id_table = m24lr_ids, +}; +module_i2c_driver(m24lr_driver); + +MODULE_AUTHOR("Abd-Alrhman Masalkhi"); +MODULE_DESCRIPTION("st m24lr control driver"); +MODULE_LICENSE("GPL"); From bb7aa579efd68c905159b03b255d1437f9f4201b Mon Sep 17 00:00:00 2001 From: Abd-Alrhman Masalkhi Date: Thu, 17 Jul 2025 06:39:34 +0000 Subject: [PATCH 0321/2711] ABI: sysfs: add documentation for ST M24LR EEPROM and control interface Add sysfs ABI documentation for the STMicroelectronics M24LR device, covering both the control interface (e.g., unlock, password update, UID, total sectors, and SSS entries) and EEPROM access via the nvmem subsystem. Signed-off-by: Abd-Alrhman Masalkhi Link: https://lore.kernel.org/r/20250717063934.5083-4-abd.masalkhi@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-bus-i2c-devices-m24lr | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-i2c-devices-m24lr diff --git a/Documentation/ABI/testing/sysfs-bus-i2c-devices-m24lr b/Documentation/ABI/testing/sysfs-bus-i2c-devices-m24lr new file mode 100644 index 000000000000..7c51ce8d38ba --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-i2c-devices-m24lr @@ -0,0 +1,100 @@ +What: /sys/bus/i2c/devices/-/unlock +Date: 2025-07-04 +KernelVersion: 6.17 +Contact: Abd-Alrhman Masalkhi +Description: + Write-only attribute used to present a password and unlock + access to protected areas of the M24LR chip, including + configuration registers such as the Sector Security Status + (SSS) bytes. A valid password must be written to enable write + access to these regions via the I2C interface. + + Format: + - Hexadecimal string representing a 32-bit (4-byte) password + - Accepts 1 to 8 hex digits (e.g., "c", "1F", "a1b2c3d4") + - No "0x" prefix, whitespace, or trailing newline + - Case-insensitive + + Behavior: + - If the password matches the internal stored value, + access to protected memory/configuration is granted + - If the password does not match the internally stored value, + it will fail silently + +What: /sys/bus/i2c/devices/-/new_pass +Date: 2025-07-04 +KernelVersion: 6.17 +Contact: Abd-Alrhman Masalkhi +Description: + Write-only attribute used to update the password required to + unlock the M24LR chip. + + Format: + - Hexadecimal string representing a new 32-bit password + - Accepts 1 to 8 hex digits (e.g., "1A", "ffff", "c0ffee00") + - No "0x" prefix, whitespace, or trailing newline + - Case-insensitive + + Behavior: + - Overwrites the current password stored in the I2C password + register + - Requires the device to be unlocked before changing the + password + - If the device is locked, the write silently fails + +What: /sys/bus/i2c/devices/-/uid +Date: 2025-07-04 +KernelVersion: 6.17 +Contact: Abd-Alrhman Masalkhi +Description: + Read-only attribute that exposes the 8-byte unique identifier + programmed into the M24LR chip at the factory. + + Format: + - Lowercase hexadecimal string representing a 64-bit value + - 1 to 16 hex digits (e.g., "e00204f12345678") + - No "0x" prefix + - Includes a trailing newline + +What: /sys/bus/i2c/devices/-/total_sectors +Date: 2025-07-04 +KernelVersion: 6.17 +Contact: Abd-Alrhman Masalkhi +Description: + Read-only attribute that exposes the total number of EEPROM + sectors available in the M24LR chip. + + Format: + - 1 to 2 hex digits (e.g. "F") + - No "0x" prefix + - Includes a trailing newline + + Notes: + - Value is encoded by the chip and corresponds to the EEPROM + size (e.g., 3 = 4 kbit for M24LR04E-R) + +What: /sys/bus/i2c/devices/-/sss +Date: 2025-07-04 +KernelVersion: 6.17 +Contact: Abd-Alrhman Masalkhi +Description: + Read/write binary attribute representing the Sector Security + Status (SSS) bytes for all EEPROM sectors in STMicroelectronics + M24LR chips. + + Each EEPROM sector has one SSS byte, which controls I2C and + RF access through protection bits and optional password + authentication. + + Format: + - The file contains one byte per EEPROM sector + - Byte at offset N corresponds to sector N + - Binary access only; use tools like dd, Python, or C that + support byte-level I/O and offset control. + + Notes: + - The number of valid bytes in this file is equal to the + value exposed by 'total_sectors' file + - Write access requires prior password authentication in + I2C mode + - Refer to the M24LR datasheet for full SSS bit layout From 4afc5bf0a1849f0ed3ea1d9fd9d0e79b23a67f96 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Sun, 27 Jul 2025 18:29:04 +0000 Subject: [PATCH 0322/2711] binder: pre-allocate binder_transaction Move the allocation of 'struct binder_transaction' to the beginning of the binder_transaction() function, along with the initialization of all the members that are known at that time. This minor refactoring helps to consolidate the usage of transaction information at later points. This patch is in preparation for binder's generic netlink implementation and no functional changes are intended. Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20250727182932.2499194-2-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 64 +++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 28634f786e70..d1d1051cdedb 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3042,6 +3042,30 @@ static void binder_transaction(struct binder_proc *proc, binder_set_extended_error(&thread->ee, t_debug_id, BR_OK, 0); binder_inner_proc_unlock(proc); + t = kzalloc(sizeof(*t), GFP_KERNEL); + if (!t) { + binder_txn_error("%d:%d cannot allocate transaction\n", + thread->pid, proc->pid); + return_error = BR_FAILED_REPLY; + return_error_param = -ENOMEM; + return_error_line = __LINE__; + goto err_alloc_t_failed; + } + INIT_LIST_HEAD(&t->fd_fixups); + binder_stats_created(BINDER_STAT_TRANSACTION); + spin_lock_init(&t->lock); + t->debug_id = t_debug_id; + t->start_time = t_start_time; + t->from_pid = proc->pid; + t->from_tid = thread->pid; + t->sender_euid = task_euid(proc->tsk); + t->code = tr->code; + t->flags = tr->flags; + t->priority = task_nice(current); + t->work.type = BINDER_WORK_TRANSACTION; + if (!reply && !(tr->flags & TF_ONE_WAY)) + t->from = thread; + if (reply) { binder_inner_proc_lock(proc); in_reply_to = thread->transaction_stack; @@ -3228,24 +3252,13 @@ static void binder_transaction(struct binder_proc *proc, } binder_inner_proc_unlock(proc); } + + t->to_proc = target_proc; + t->to_thread = target_thread; if (target_thread) e->to_thread = target_thread->pid; e->to_proc = target_proc->pid; - /* TODO: reuse incoming transaction for reply */ - t = kzalloc(sizeof(*t), GFP_KERNEL); - if (t == NULL) { - binder_txn_error("%d:%d cannot allocate transaction\n", - thread->pid, proc->pid); - return_error = BR_FAILED_REPLY; - return_error_param = -ENOMEM; - return_error_line = __LINE__; - goto err_alloc_t_failed; - } - INIT_LIST_HEAD(&t->fd_fixups); - binder_stats_created(BINDER_STAT_TRANSACTION); - spin_lock_init(&t->lock); - tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); if (tcomplete == NULL) { binder_txn_error("%d:%d cannot allocate work for transaction\n", @@ -3257,9 +3270,6 @@ static void binder_transaction(struct binder_proc *proc, } binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); - t->debug_id = t_debug_id; - t->start_time = t_start_time; - if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, "%d:%d BC_REPLY %d -> %d:%d, data size %lld-%lld-%lld\n", @@ -3275,19 +3285,6 @@ static void binder_transaction(struct binder_proc *proc, (u64)tr->data_size, (u64)tr->offsets_size, (u64)extra_buffers_size); - if (!reply && !(tr->flags & TF_ONE_WAY)) - t->from = thread; - else - t->from = NULL; - t->from_pid = proc->pid; - t->from_tid = thread->pid; - t->sender_euid = task_euid(proc->tsk); - t->to_proc = target_proc; - t->to_thread = target_thread; - t->code = tr->code; - t->flags = tr->flags; - t->priority = task_nice(current); - if (target_node && target_node->txn_security_ctx) { u32 secid; size_t added_size; @@ -3684,7 +3681,6 @@ static void binder_transaction(struct binder_proc *proc, tcomplete->type = BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT; else tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; - t->work.type = BINDER_WORK_TRANSACTION; if (reply) { binder_enqueue_thread_work(thread, tcomplete); @@ -3783,9 +3779,6 @@ err_get_secctx_failed: err_alloc_tcomplete_failed: if (trace_binder_txn_latency_free_enabled()) binder_txn_latency_free(t); - kfree(t); - binder_stats_deleted(BINDER_STAT_TRANSACTION); -err_alloc_t_failed: err_bad_todo_list: err_bad_call_stack: err_empty_call_stack: @@ -3795,6 +3788,9 @@ err_invalid_target_handle: binder_dec_node(target_node, 1, 0); binder_dec_node_tmpref(target_node); } + kfree(t); + binder_stats_deleted(BINDER_STAT_TRANSACTION); +err_alloc_t_failed: binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, "%d:%d transaction %s to %d:%d failed %d/%d/%d, code %u size %lld-%lld line %d\n", From 5cd0645b43c7edf55518272a6c69230a5c631729 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Sun, 27 Jul 2025 18:29:05 +0000 Subject: [PATCH 0323/2711] binder: add t->is_async and t->is_reply Replace the t->need_reply flag with the more descriptive t->is_async and and t->is_reply flags. The 'need_reply' flag was only used for debugging purposes and the new flags can be used to distinguish between the type of transactions too: sync, async and reply. For now, only update the logging in print_binder_transaction_ilocked(). However, the new flags can be used in the future to replace the current patterns and improve readability. e.g.: - if (!reply && !(tr->flags & TF_ONE_WAY)) + if (t->is_async) This patch is in preparation for binder's generic netlink implementation and no functional changes are intended. Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20250727182932.2499194-3-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 7 ++++--- drivers/android/binder_internal.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index d1d1051cdedb..e4f9cbc6c93f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3063,6 +3063,8 @@ static void binder_transaction(struct binder_proc *proc, t->flags = tr->flags; t->priority = task_nice(current); t->work.type = BINDER_WORK_TRANSACTION; + t->is_async = !reply && (tr->flags & TF_ONE_WAY); + t->is_reply = reply; if (!reply && !(tr->flags & TF_ONE_WAY)) t->from = thread; @@ -3708,7 +3710,6 @@ static void binder_transaction(struct binder_proc *proc, * the target replies (or there is an error). */ binder_enqueue_deferred_thread_work_ilocked(thread, tcomplete); - t->need_reply = 1; t->from_parent = thread->transaction_stack; thread->transaction_stack = t; binder_inner_proc_unlock(proc); @@ -6320,13 +6321,13 @@ static void print_binder_transaction_ilocked(struct seq_file *m, spin_lock(&t->lock); to_proc = t->to_proc; seq_printf(m, - "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d elapsed %lldms", + "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld a%d r%d elapsed %lldms", prefix, t->debug_id, t, t->from_pid, t->from_tid, to_proc ? to_proc->pid : 0, t->to_thread ? t->to_thread->pid : 0, - t->code, t->flags, t->priority, t->need_reply, + t->code, t->flags, t->priority, t->is_async, t->is_reply, ktime_ms_delta(current_time, t->start_time)); spin_unlock(&t->lock); diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 8b08976146ba..342574bfd28a 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -537,8 +537,8 @@ struct binder_transaction { struct binder_proc *to_proc; struct binder_thread *to_thread; struct binder_transaction *to_parent; - unsigned need_reply:1; - /* unsigned is_dead:1; */ /* not used at the moment */ + unsigned is_async:1; + unsigned is_reply:1; struct binder_buffer *buffer; unsigned int code; From 63740349eba78f242bcbf60d5244d7f2b2600853 Mon Sep 17 00:00:00 2001 From: Li Li Date: Sun, 27 Jul 2025 18:29:06 +0000 Subject: [PATCH 0324/2711] binder: introduce transaction reports via netlink Introduce a generic netlink multicast event to report binder transaction failures to userspace. This allows subscribers to monitor these events and take appropriate actions, such as stopping a misbehaving application that is spamming a service with huge amount of transactions. The multicast event contains full details of the failed transactions, including the sender/target PIDs, payload size and specific error code. This interface is defined using a YAML spec, from which the UAPI and kernel headers and source are auto-generated. Signed-off-by: Li Li Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20250727182932.2499194-4-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- Documentation/netlink/specs/binder.yaml | 93 +++++++++++++++++++++ MAINTAINERS | 1 + drivers/android/Kconfig | 1 + drivers/android/Makefile | 2 +- drivers/android/binder.c | 85 ++++++++++++++++++- drivers/android/binder_netlink.c | 31 +++++++ drivers/android/binder_netlink.h | 20 +++++ include/uapi/linux/android/binder_netlink.h | 37 ++++++++ 8 files changed, 265 insertions(+), 5 deletions(-) create mode 100644 Documentation/netlink/specs/binder.yaml create mode 100644 drivers/android/binder_netlink.c create mode 100644 drivers/android/binder_netlink.h create mode 100644 include/uapi/linux/android/binder_netlink.h diff --git a/Documentation/netlink/specs/binder.yaml b/Documentation/netlink/specs/binder.yaml new file mode 100644 index 000000000000..140b77a6afee --- /dev/null +++ b/Documentation/netlink/specs/binder.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +# +# Copyright 2025 Google LLC +# +--- +name: binder +protocol: genetlink +uapi-header: linux/android/binder_netlink.h +doc: Binder interface over generic netlink + +attribute-sets: + - + name: report + doc: | + Attributes included within a transaction failure report. The elements + correspond directly with the specific transaction that failed, along + with the error returned to the sender e.g. BR_DEAD_REPLY. + + attributes: + - + name: error + type: u32 + doc: The enum binder_driver_return_protocol returned to the sender. + - + name: context + type: string + doc: The binder context where the transaction occurred. + - + name: from_pid + type: u32 + doc: The PID of the sender process. + - + name: from_tid + type: u32 + doc: The TID of the sender thread. + - + name: to_pid + type: u32 + doc: | + The PID of the recipient process. This attribute may not be present + if the target could not be determined. + - + name: to_tid + type: u32 + doc: | + The TID of the recipient thread. This attribute may not be present + if the target could not be determined. + - + name: is_reply + type: flag + doc: When present, indicates the failed transaction is a reply. + - + name: flags + type: u32 + doc: The bitmask of enum transaction_flags from the transaction. + - + name: code + type: u32 + doc: The application-defined code from the transaction. + - + name: data_size + type: u32 + doc: The transaction payload size in bytes. + +operations: + list: + - + name: report + doc: | + A multicast event sent to userspace subscribers to notify them about + binder transaction failures. The generated report provides the full + details of the specific transaction that failed. The intention is for + programs to monitor these events and react to the failures as needed. + + attribute-set: report + mcgrp: report + event: + attributes: + - error + - context + - from_pid + - from_tid + - to_pid + - to_tid + - is_reply + - flags + - code + - data_size + +mcast-groups: + list: + - + name: report diff --git a/MAINTAINERS b/MAINTAINERS index daf520a13bdf..febc92cca659 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1790,6 +1790,7 @@ M: Suren Baghdasaryan L: linux-kernel@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git +F: Documentation/netlink/specs/binder.yaml F: drivers/android/ ANDROID GOLDFISH PIC DRIVER diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 5b3b8041f827..75af3cf472c8 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -4,6 +4,7 @@ menu "Android" config ANDROID_BINDER_IPC bool "Android Binder IPC Driver" depends on MMU + depends on NET default n help Binder is used in Android for both communication between processes, diff --git a/drivers/android/Makefile b/drivers/android/Makefile index c5d47be0276c..f422f91e026b 100644 --- a/drivers/android/Makefile +++ b/drivers/android/Makefile @@ -2,5 +2,5 @@ ccflags-y += -I$(src) # needed for trace events obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o -obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o +obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o binder_netlink.o obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += tests/ diff --git a/drivers/android/binder.c b/drivers/android/binder.c index e4f9cbc6c93f..edfa15d39d6f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -74,6 +74,7 @@ #include +#include "binder_netlink.h" #include "binder_internal.h" #include "binder_trace.h" @@ -2993,6 +2994,67 @@ static void binder_set_txn_from_error(struct binder_transaction *t, int id, binder_thread_dec_tmpref(from); } +/** + * binder_netlink_report() - report a transaction failure via netlink + * @proc: the binder proc sending the transaction + * @t: the binder transaction that failed + * @data_size: the user provided data size for the transaction + * @error: enum binder_driver_return_protocol returned to sender + */ +static void binder_netlink_report(struct binder_proc *proc, + struct binder_transaction *t, + u32 data_size, + u32 error) +{ + const char *context = proc->context->name; + struct sk_buff *skb; + void *hdr; + + if (!genl_has_listeners(&binder_nl_family, &init_net, + BINDER_NLGRP_REPORT)) + return; + + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return; + + hdr = genlmsg_put(skb, 0, 0, &binder_nl_family, 0, BINDER_CMD_REPORT); + if (!hdr) + goto free_skb; + + if (nla_put_u32(skb, BINDER_A_REPORT_ERROR, error) || + nla_put_string(skb, BINDER_A_REPORT_CONTEXT, context) || + nla_put_u32(skb, BINDER_A_REPORT_FROM_PID, t->from_pid) || + nla_put_u32(skb, BINDER_A_REPORT_FROM_TID, t->from_tid)) + goto cancel_skb; + + if (t->to_proc && + nla_put_u32(skb, BINDER_A_REPORT_TO_PID, t->to_proc->pid)) + goto cancel_skb; + + if (t->to_thread && + nla_put_u32(skb, BINDER_A_REPORT_TO_TID, t->to_thread->pid)) + goto cancel_skb; + + if (t->is_reply && nla_put_flag(skb, BINDER_A_REPORT_IS_REPLY)) + goto cancel_skb; + + if (nla_put_u32(skb, BINDER_A_REPORT_FLAGS, t->flags) || + nla_put_u32(skb, BINDER_A_REPORT_CODE, t->code) || + nla_put_u32(skb, BINDER_A_REPORT_DATA_SIZE, data_size)) + goto cancel_skb; + + genlmsg_end(skb, hdr); + genlmsg_multicast(&binder_nl_family, skb, 0, BINDER_NLGRP_REPORT, + GFP_KERNEL); + return; + +cancel_skb: + genlmsg_cancel(skb, hdr); +free_skb: + nlmsg_free(skb); +} + static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply, @@ -3679,10 +3741,13 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_copy_data_failed; } - if (t->buffer->oneway_spam_suspect) + if (t->buffer->oneway_spam_suspect) { tcomplete->type = BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT; - else + binder_netlink_report(proc, t, tr->data_size, + BR_ONEWAY_SPAM_SUSPECT); + } else { tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; + } if (reply) { binder_enqueue_thread_work(thread, tcomplete); @@ -3730,8 +3795,11 @@ static void binder_transaction(struct binder_proc *proc, * process and is put in a pending queue, waiting for the target * process to be unfrozen. */ - if (return_error == BR_TRANSACTION_PENDING_FROZEN) + if (return_error == BR_TRANSACTION_PENDING_FROZEN) { tcomplete->type = BINDER_WORK_TRANSACTION_PENDING; + binder_netlink_report(proc, t, tr->data_size, + return_error); + } binder_enqueue_thread_work(thread, tcomplete); if (return_error && return_error != BR_TRANSACTION_PENDING_FROZEN) @@ -3789,6 +3857,8 @@ err_invalid_target_handle: binder_dec_node(target_node, 1, 0); binder_dec_node_tmpref(target_node); } + + binder_netlink_report(proc, t, tr->data_size, return_error); kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); err_alloc_t_failed: @@ -7059,12 +7129,19 @@ static int __init binder_init(void) } } - ret = init_binderfs(); + ret = genl_register_family(&binder_nl_family); if (ret) goto err_init_binder_device_failed; + ret = init_binderfs(); + if (ret) + goto err_init_binderfs_failed; + return ret; +err_init_binderfs_failed: + genl_unregister_family(&binder_nl_family); + err_init_binder_device_failed: hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) { misc_deregister(&device->miscdev); diff --git a/drivers/android/binder_netlink.c b/drivers/android/binder_netlink.c new file mode 100644 index 000000000000..d05397a50ca6 --- /dev/null +++ b/drivers/android/binder_netlink.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/binder.yaml */ +/* YNL-GEN kernel source */ + +#include +#include + +#include "binder_netlink.h" + +#include + +/* Ops table for binder */ +static const struct genl_split_ops binder_nl_ops[] = { +}; + +static const struct genl_multicast_group binder_nl_mcgrps[] = { + [BINDER_NLGRP_REPORT] = { "report", }, +}; + +struct genl_family binder_nl_family __ro_after_init = { + .name = BINDER_FAMILY_NAME, + .version = BINDER_FAMILY_VERSION, + .netnsok = true, + .parallel_ops = true, + .module = THIS_MODULE, + .split_ops = binder_nl_ops, + .n_split_ops = ARRAY_SIZE(binder_nl_ops), + .mcgrps = binder_nl_mcgrps, + .n_mcgrps = ARRAY_SIZE(binder_nl_mcgrps), +}; diff --git a/drivers/android/binder_netlink.h b/drivers/android/binder_netlink.h new file mode 100644 index 000000000000..882c7a6b537e --- /dev/null +++ b/drivers/android/binder_netlink.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/binder.yaml */ +/* YNL-GEN kernel header */ + +#ifndef _LINUX_BINDER_GEN_H +#define _LINUX_BINDER_GEN_H + +#include +#include + +#include + +enum { + BINDER_NLGRP_REPORT, +}; + +extern struct genl_family binder_nl_family; + +#endif /* _LINUX_BINDER_GEN_H */ diff --git a/include/uapi/linux/android/binder_netlink.h b/include/uapi/linux/android/binder_netlink.h new file mode 100644 index 000000000000..b218f96d6668 --- /dev/null +++ b/include/uapi/linux/android/binder_netlink.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/binder.yaml */ +/* YNL-GEN uapi header */ + +#ifndef _UAPI_LINUX_ANDROID_BINDER_NETLINK_H +#define _UAPI_LINUX_ANDROID_BINDER_NETLINK_H + +#define BINDER_FAMILY_NAME "binder" +#define BINDER_FAMILY_VERSION 1 + +enum { + BINDER_A_REPORT_ERROR = 1, + BINDER_A_REPORT_CONTEXT, + BINDER_A_REPORT_FROM_PID, + BINDER_A_REPORT_FROM_TID, + BINDER_A_REPORT_TO_PID, + BINDER_A_REPORT_TO_TID, + BINDER_A_REPORT_IS_REPLY, + BINDER_A_REPORT_FLAGS, + BINDER_A_REPORT_CODE, + BINDER_A_REPORT_DATA_SIZE, + + __BINDER_A_REPORT_MAX, + BINDER_A_REPORT_MAX = (__BINDER_A_REPORT_MAX - 1) +}; + +enum { + BINDER_CMD_REPORT = 1, + + __BINDER_CMD_MAX, + BINDER_CMD_MAX = (__BINDER_CMD_MAX - 1) +}; + +#define BINDER_MCGRP_REPORT "report" + +#endif /* _UAPI_LINUX_ANDROID_BINDER_NETLINK_H */ From f37b55ded8ed35424ebb91a4d012527071e1f601 Mon Sep 17 00:00:00 2001 From: Li Li Date: Sun, 27 Jul 2025 18:29:07 +0000 Subject: [PATCH 0325/2711] binder: add transaction_report feature entry Add "transaction_report" to the binderfs feature list, to help userspace determine if the "BINDER_CMD_REPORT" generic netlink api is supported by the binder driver. Signed-off-by: Li Li Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20250727182932.2499194-5-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 8 ++++++++ .../selftests/filesystems/binderfs/binderfs_test.c | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 0d9d95a7fb60..be8e64eb39ec 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -59,6 +59,7 @@ struct binder_features { bool oneway_spam_detection; bool extended_error; bool freeze_notification; + bool transaction_report; }; static const struct constant_table binderfs_param_stats[] = { @@ -76,6 +77,7 @@ static struct binder_features binder_features = { .oneway_spam_detection = true, .extended_error = true, .freeze_notification = true, + .transaction_report = true, }; static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb) @@ -601,6 +603,12 @@ static int init_binder_features(struct super_block *sb) if (IS_ERR(dentry)) return PTR_ERR(dentry); + dentry = binderfs_create_file(dir, "transaction_report", + &binder_features_fops, + &binder_features.transaction_report); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + return 0; } diff --git a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c index 81db85a5cc16..39a68078a79b 100644 --- a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c +++ b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c @@ -65,6 +65,7 @@ static int __do_binderfs_test(struct __test_metadata *_metadata) "oneway_spam_detection", "extended_error", "freeze_notification", + "transaction_report", }; change_mountns(_metadata); From 8a61a53b07f23ff12330086b293b6b492d35b8a0 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Sun, 27 Jul 2025 18:29:08 +0000 Subject: [PATCH 0326/2711] binder: add tracepoint for netlink reports Add a tracepoint to capture the same details that are being sent through the generic netlink interface during transaction failures. This provides a useful debugging tool to observe the events independently from the netlink listeners. Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20250727182932.2499194-6-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 2 ++ drivers/android/binder_trace.h | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index edfa15d39d6f..8c99ceaa303b 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3014,6 +3014,8 @@ static void binder_netlink_report(struct binder_proc *proc, BINDER_NLGRP_REPORT)) return; + trace_binder_netlink_report(context, t, data_size, error); + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!skb) return; diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h index 97a78e5623db..fa5eb61cf580 100644 --- a/drivers/android/binder_trace.h +++ b/drivers/android/binder_trace.h @@ -402,6 +402,43 @@ TRACE_EVENT(binder_return, "unknown") ); +TRACE_EVENT(binder_netlink_report, + TP_PROTO(const char *context, + struct binder_transaction *t, + u32 data_size, + u32 error), + TP_ARGS(context, t, data_size, error), + TP_STRUCT__entry( + __field(const char *, context) + __field(u32, error) + __field(int, from_pid) + __field(int, from_tid) + __field(int, to_pid) + __field(int, to_tid) + __field(bool, is_reply) + __field(unsigned int, flags) + __field(unsigned int, code) + __field(size_t, data_size) + ), + TP_fast_assign( + __entry->context = context; + __entry->error = error; + __entry->from_pid = t->from_pid; + __entry->from_tid = t->from_tid; + __entry->to_pid = t->to_proc ? t->to_proc->pid : 0; + __entry->to_tid = t->to_thread ? t->to_thread->pid : 0; + __entry->is_reply = t->is_reply; + __entry->flags = t->flags; + __entry->code = t->code; + __entry->data_size = data_size; + ), + TP_printk("from %d:%d to %d:%d context=%s error=%d is_reply=%d flags=0x%x code=0x%x size=%zu", + __entry->from_pid, __entry->from_tid, + __entry->to_pid, __entry->to_tid, + __entry->context, __entry->error, __entry->is_reply, + __entry->flags, __entry->code, __entry->data_size) +); + #endif /* _BINDER_TRACE_H */ #undef TRACE_INCLUDE_PATH From 834a2d0155d15832cd13a688b4f2f1d0b7c1b855 Mon Sep 17 00:00:00 2001 From: Luke Yang Date: Thu, 14 Aug 2025 15:01:36 -0400 Subject: [PATCH 0327/2711] staging: gpib: tidy-up comments Improve comment readability: - "//comment" -> "// comment" - Align comments vertically in columns - Enforce consistency between "// comments" and "/* comments */" Signed-off-by: Luke Yang Link: https://lore.kernel.org/r/aJ4ykOs_MmjnQdPa@luyang-thinkpadp1gen7.toromso.csb Signed-off-by: Greg Kroah-Hartman --- .../gpib/agilent_82357a/agilent_82357a.c | 18 ++-- .../gpib/agilent_82357a/agilent_82357a.h | 10 +-- drivers/staging/gpib/cb7210/cb7210.h | 4 +- drivers/staging/gpib/cec/cec_gpib.c | 2 +- drivers/staging/gpib/common/gpib_os.c | 2 +- drivers/staging/gpib/common/iblib.c | 2 +- drivers/staging/gpib/eastwood/fluke_gpib.c | 2 +- drivers/staging/gpib/fmh_gpib/fmh_gpib.c | 2 +- drivers/staging/gpib/gpio/gpib_bitbang.c | 14 +-- drivers/staging/gpib/hp_82341/hp_82341.c | 12 +-- drivers/staging/gpib/hp_82341/hp_82341.h | 40 ++++----- drivers/staging/gpib/include/amccs5933.h | 4 +- drivers/staging/gpib/include/gpib_types.h | 3 +- drivers/staging/gpib/include/nec7210.h | 26 +++--- .../staging/gpib/include/nec7210_registers.h | 4 +- drivers/staging/gpib/include/plx9050.h | 8 +- drivers/staging/gpib/include/tms9914.h | 90 +++++++++---------- .../staging/gpib/include/tnt4882_registers.h | 22 ++--- drivers/staging/gpib/ines/ines.h | 12 +-- drivers/staging/gpib/ines/ines_gpib.c | 4 +- drivers/staging/gpib/nec7210/nec7210.c | 6 +- drivers/staging/gpib/ni_usb/ni_usb_gpib.c | 10 +-- drivers/staging/gpib/ni_usb/ni_usb_gpib.h | 10 +-- drivers/staging/gpib/pc2/pc2_gpib.c | 4 +- drivers/staging/gpib/tms9914/tms9914.c | 10 +-- drivers/staging/gpib/tnt4882/mite.h | 10 +-- drivers/staging/gpib/tnt4882/tnt4882_gpib.c | 4 +- 27 files changed, 168 insertions(+), 167 deletions(-) diff --git a/drivers/staging/gpib/agilent_82357a/agilent_82357a.c b/drivers/staging/gpib/agilent_82357a/agilent_82357a.c index b923dc606d1d..77c8e549b208 100644 --- a/drivers/staging/gpib/agilent_82357a/agilent_82357a.c +++ b/drivers/staging/gpib/agilent_82357a/agilent_82357a.c @@ -449,8 +449,8 @@ static int agilent_82357a_read(struct gpib_board *board, u8 *buffer, size_t leng if (!out_data) return -ENOMEM; out_data[i++] = DATA_PIPE_CMD_READ; - out_data[i++] = 0; //primary address when ARF_NO_ADDR is not set - out_data[i++] = 0; //secondary address when ARF_NO_ADDR is not set + out_data[i++] = 0; // primary address when ARF_NO_ADDR is not set + out_data[i++] = 0; // secondary address when ARF_NO_ADDR is not set out_data[i] = ARF_NO_ADDRESS | ARF_END_ON_EOI; if (a_priv->eos_mode & REOS) out_data[i] |= ARF_END_ON_EOS_CHAR; @@ -532,7 +532,7 @@ static int agilent_82357a_read(struct gpib_board *board, u8 *buffer, size_t leng */ agilent_82357a_take_control_internal(board, 0); - //FIXME check trailing flags for error + // FIXME check trailing flags for error return retval; } @@ -966,7 +966,7 @@ static int agilent_82357a_parallel_poll(struct gpib_board *board, u8 *result) dev_err(&usb_dev->dev, "write_registers() returned error\n"); return retval; } - udelay(2); //silly, since usb write will take way longer + udelay(2); // silly, since usb write will take way longer read.address = CPTR; retval = agilent_82357a_read_registers(a_priv, &read, 1, 1); if (retval) { @@ -989,31 +989,31 @@ static int agilent_82357a_parallel_poll(struct gpib_board *board, u8 *result) static void agilent_82357a_parallel_poll_configure(struct gpib_board *board, u8 config) { - //board can only be system controller + // board can only be system controller return;// 0; } static void agilent_82357a_parallel_poll_response(struct gpib_board *board, int ist) { - //board can only be system controller + // board can only be system controller return;// 0; } static void agilent_82357a_serial_poll_response(struct gpib_board *board, u8 status) { - //board can only be system controller + // board can only be system controller return;// 0; } static u8 agilent_82357a_serial_poll_status(struct gpib_board *board) { - //board can only be system controller + // board can only be system controller return 0; } static void agilent_82357a_return_to_local(struct gpib_board *board) { - //board can only be system controller + // board can only be system controller return;// 0; } diff --git a/drivers/staging/gpib/agilent_82357a/agilent_82357a.h b/drivers/staging/gpib/agilent_82357a/agilent_82357a.h index 23aa4799eb86..33ac558e5552 100644 --- a/drivers/staging/gpib/agilent_82357a/agilent_82357a.h +++ b/drivers/staging/gpib/agilent_82357a/agilent_82357a.h @@ -20,7 +20,7 @@ enum usb_vendor_ids { enum usb_device_ids { USB_DEVICE_ID_AGILENT_82357A = 0x0107, USB_DEVICE_ID_AGILENT_82357A_PREINIT = 0x0007, // device id before firmware is loaded - USB_DEVICE_ID_AGILENT_82357B = 0x0718, // device id before firmware is loaded + USB_DEVICE_ID_AGILENT_82357B = 0x0718, // device id before firmware is loaded USB_DEVICE_ID_AGILENT_82357B_PREINIT = 0x0518, // device id before firmware is loaded }; @@ -129,10 +129,10 @@ struct agilent_82357a_priv { struct urb *bulk_urb; struct urb *interrupt_urb; u8 *interrupt_buffer; - struct mutex bulk_transfer_lock; // bulk transfer lock - struct mutex bulk_alloc_lock; // bulk transfer allocation lock - struct mutex interrupt_alloc_lock; // interrupt allocation lock - struct mutex control_alloc_lock; // control message allocation lock + struct mutex bulk_transfer_lock; // bulk transfer lock + struct mutex bulk_alloc_lock; // bulk transfer allocation lock + struct mutex interrupt_alloc_lock; // interrupt allocation lock + struct mutex control_alloc_lock; // control message allocation lock struct timer_list bulk_timer; struct agilent_82357a_urb_ctx context; unsigned int bulk_out_endpoint; diff --git a/drivers/staging/gpib/cb7210/cb7210.h b/drivers/staging/gpib/cb7210/cb7210.h index 13f127563ab3..ddc841ff87ae 100644 --- a/drivers/staging/gpib/cb7210/cb7210.h +++ b/drivers/staging/gpib/cb7210/cb7210.h @@ -56,10 +56,10 @@ enum cb7210_page_in { }; enum hs_regs { - //write registers + // write registers HS_MODE = 0x8, /* HS_MODE register */ HS_INT_LEVEL = 0x9, /* HS_INT_LEVEL register */ - //read registers + // read registers HS_STATUS = 0x8, /* HS_STATUS register */ }; diff --git a/drivers/staging/gpib/cec/cec_gpib.c b/drivers/staging/gpib/cec/cec_gpib.c index 0c9d10ee7cd2..dbf9b95baabc 100644 --- a/drivers/staging/gpib/cec/cec_gpib.c +++ b/drivers/staging/gpib/cec/cec_gpib.c @@ -206,7 +206,7 @@ static struct gpib_interface cec_pci_interface = { .parallel_poll_configure = cec_parallel_poll_configure, .parallel_poll_response = cec_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX - .line_status = NULL, //XXX + .line_status = NULL, // XXX .update_status = cec_update_status, .primary_address = cec_primary_address, .secondary_address = cec_secondary_address, diff --git a/drivers/staging/gpib/common/gpib_os.c b/drivers/staging/gpib/common/gpib_os.c index 2a0465ce16c4..9dbbac8b8436 100644 --- a/drivers/staging/gpib/common/gpib_os.c +++ b/drivers/staging/gpib/common/gpib_os.c @@ -326,7 +326,7 @@ static int setup_serial_poll(struct gpib_board *board, unsigned int usec_timeout cmd_string[i++] = MLA(board->pad); /* controller's listen address */ if (board->sad >= 0) cmd_string[i++] = MSA(board->sad); - cmd_string[i++] = SPE; //serial poll enable + cmd_string[i++] = SPE; // serial poll enable ret = board->interface->command(board, cmd_string, i, &bytes_written); if (ret < 0 || bytes_written < i) { diff --git a/drivers/staging/gpib/common/iblib.c b/drivers/staging/gpib/common/iblib.c index 549280d9a6e9..7cbb6a467177 100644 --- a/drivers/staging/gpib/common/iblib.c +++ b/drivers/staging/gpib/common/iblib.c @@ -608,7 +608,7 @@ static int wait_satisfied(struct wait_info *winfo, struct gpib_status_queue *sta *status = temp_status; return 1; } -//XXX does wait for END work? +// XXX does wait for END work? return 0; } diff --git a/drivers/staging/gpib/eastwood/fluke_gpib.c b/drivers/staging/gpib/eastwood/fluke_gpib.c index 491356433249..3ae848e3f738 100644 --- a/drivers/staging/gpib/eastwood/fluke_gpib.c +++ b/drivers/staging/gpib/eastwood/fluke_gpib.c @@ -507,7 +507,7 @@ static int fluke_accel_write(struct gpib_board *board, u8 *buffer, size_t length } if (retval < 0) return retval; - //handle sending of last byte with eoi + // handle sending of last byte with eoi if (send_eoi) { size_t num_bytes; diff --git a/drivers/staging/gpib/fmh_gpib/fmh_gpib.c b/drivers/staging/gpib/fmh_gpib/fmh_gpib.c index 4138f3d2bae7..164dcfc3c9ef 100644 --- a/drivers/staging/gpib/fmh_gpib/fmh_gpib.c +++ b/drivers/staging/gpib/fmh_gpib/fmh_gpib.c @@ -523,7 +523,7 @@ static int fmh_gpib_accel_write(struct gpib_board *board, u8 *buffer, } if (retval < 0) return retval; - //handle sending of last byte with eoi + // handle sending of last byte with eoi if (send_eoi) { size_t num_bytes; diff --git a/drivers/staging/gpib/gpio/gpib_bitbang.c b/drivers/staging/gpib/gpio/gpib_bitbang.c index 17884810fd69..22a55f3f794d 100644 --- a/drivers/staging/gpib/gpio/gpib_bitbang.c +++ b/drivers/staging/gpib/gpio/gpib_bitbang.c @@ -277,8 +277,8 @@ struct bb_priv { int ndac_mode; /* nrfd interrupt mode 0/1 -> edge/levels */ int dav_tx; /* keep trace of DAV status while sending */ int dav_rx; /* keep trace of DAV status while receiving */ - u8 eos; // eos character - short eos_flags; // eos mode + u8 eos; /* eos character */ + short eos_flags; /* eos mode */ short eos_check; /* eos check required in current operation ... */ short eos_check_8; /* ... with byte comparison */ short eos_mask_7; /* ... with 7 bit masked character */ @@ -290,14 +290,14 @@ struct bb_priv { u8 *rbuf; u8 *wbuf; int end_flag; - int r_busy; /* 0==idle 1==busy */ + int r_busy; /* 0==idle 1==busy */ int w_busy; int write_done; - int cmd; /* 1 = cmd write in progress */ + int cmd; /* 1 = cmd write in progress */ size_t w_cnt; size_t length; u8 *w_buf; - spinlock_t rw_lock; // protect mods to rw_lock + spinlock_t rw_lock; /* protect mods to rw_lock */ int phase; int ndac_idle; int ndac_seq; @@ -1462,8 +1462,8 @@ static inline void SET_DIR_READ(struct bb_priv *priv) gpiod_set_value(TE, 0); /* set NDAC and NRFD to transmit and DAV to receive */ } - gpiod_direction_output(NRFD, 0); // hold off the talker - gpiod_direction_output(NDAC, 0); // data not accepted + gpiod_direction_output(NRFD, 0); /* hold off the talker */ + gpiod_direction_output(NDAC, 0); /* data not accepted */ priv->direction = DIR_READ; } diff --git a/drivers/staging/gpib/hp_82341/hp_82341.c b/drivers/staging/gpib/hp_82341/hp_82341.c index e5c1997ce7d9..1a2ad0560e14 100644 --- a/drivers/staging/gpib/hp_82341/hp_82341.c +++ b/drivers/staging/gpib/hp_82341/hp_82341.c @@ -38,7 +38,7 @@ static int hp_82341_accel_read(struct gpib_board *board, u8 *buffer, size_t leng unsigned short event_status; int i; int num_fifo_bytes; - //hardware doesn't support checking for end-of-string character when using fifo + // hardware doesn't support checking for end-of-string character when using fifo if (tms_priv->eos_flags & REOS) return tms9914_read(board, tms_priv, buffer, length, end, bytes_read); @@ -49,7 +49,7 @@ static int hp_82341_accel_read(struct gpib_board *board, u8 *buffer, size_t leng *bytes_read = 0; if (length == 0) return 0; - //disable fifo for the moment + // disable fifo for the moment outb(DIRECTION_GPIB_TO_HOST_BIT, hp_priv->iobase[3] + BUFFER_CONTROL_REG); /* * Handle corner case of board not in holdoff and one byte has slipped in already. @@ -154,7 +154,7 @@ static int restart_write_fifo(struct gpib_board *board, struct hp_82341_priv *hp while (1) { int status; - //restart doesn't work if data holdoff is in effect + // restart doesn't work if data holdoff is in effect status = tms9914_line_status(board, tms_priv); if ((status & BUS_NRFD) == 0) { outb(RESTART_STREAM_BIT, hp_priv->iobase[0] + STREAM_STATUS_REG); @@ -764,7 +764,7 @@ static int hp_82341_attach(struct gpib_board *board, const struct gpib_board_con ENABLE_TI_INTERRUPT_EVENT_BIT, hp_priv->iobase[0] + EVENT_ENABLE_REG); outb(ENABLE_BUFFER_END_INTERRUPT_BIT | ENABLE_TERMINAL_COUNT_INTERRUPT_BIT | ENABLE_TI_INTERRUPT_BIT, hp_priv->iobase[0] + INTERRUPT_ENABLE_REG); - //write clear event register + // write clear event register outb((TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT | BUFFER_END_EVENT_BIT | TERMINAL_COUNT_EVENT_BIT), hp_priv->iobase[0] + EVENT_STATUS_REG); @@ -867,7 +867,7 @@ static irqreturn_t hp_82341_interrupt(int irq, void *arg) event_status = inb(hp_priv->iobase[0] + EVENT_STATUS_REG); if (event_status & INTERRUPT_PENDING_EVENT_BIT) retval = IRQ_HANDLED; - //write-clear status bits + // write-clear status bits if (event_status & (TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT | BUFFER_END_EVENT_BIT | TERMINAL_COUNT_EVENT_BIT)) { outb(event_status & (TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT | @@ -901,7 +901,7 @@ static void set_transfer_counter(struct hp_82341_priv *hp_priv, int count) outb(complement & 0xff, hp_priv->iobase[1] + TRANSFER_COUNT_LOW_REG); outb((complement >> 8) & 0xff, hp_priv->iobase[1] + TRANSFER_COUNT_MID_REG); - //I don't think the hi count reg is even used, but oh well + // I don't think the hi count reg is even used, but oh well outb((complement >> 16) & 0xf, hp_priv->iobase[1] + TRANSFER_COUNT_HIGH_REG); } diff --git a/drivers/staging/gpib/hp_82341/hp_82341.h b/drivers/staging/gpib/hp_82341/hp_82341.h index 370a3d4576eb..859ef2899acb 100644 --- a/drivers/staging/gpib/hp_82341/hp_82341.h +++ b/drivers/staging/gpib/hp_82341/hp_82341.h @@ -65,7 +65,7 @@ enum config_control_status_bits { IRQ_SELECT_MASK = 0x7, DMA_CONFIG_MASK = 0x18, ENABLE_DMA_CONFIG_BIT = 0x20, - XILINX_READY_BIT = 0x40, //read only + XILINX_READY_BIT = 0x40, // read only DONE_PGL_BIT = 0x80 }; @@ -94,7 +94,7 @@ static inline unsigned int IRQ_SELECT_BITS(int irq) }; enum mode_control_status_bits { - SLOT8_BIT = 0x1, // read only + SLOT8_BIT = 0x1, // read only ACTIVE_CONTROLLER_BIT = 0x2, // read only ENABLE_DMA_BIT = 0x4, SYSTEM_CONTROLLER_BIT = 0x8, @@ -106,12 +106,12 @@ enum mode_control_status_bits { enum monitor_bits { MONITOR_INTERRUPT_PENDING_BIT = 0x1, // read only MONITOR_CLEAR_HOLDOFF_BIT = 0x2, // write only - MONITOR_PPOLL_BIT = 0x4, // write clear - MONITOR_SRQ_BIT = 0x8, // write clear - MONITOR_IFC_BIT = 0x10, // write clear - MONITOR_REN_BIT = 0x20, // write clear - MONITOR_END_BIT = 0x40, // write clear - MONITOR_DAV_BIT = 0x80 // write clear + MONITOR_PPOLL_BIT = 0x4, // write clear + MONITOR_SRQ_BIT = 0x8, // write clear + MONITOR_IFC_BIT = 0x10, // write clear + MONITOR_REN_BIT = 0x20, // write clear + MONITOR_END_BIT = 0x40, // write clear + MONITOR_DAV_BIT = 0x80 // write clear }; enum interrupt_enable_bits { @@ -123,36 +123,36 @@ enum interrupt_enable_bits { }; enum event_status_bits { - TI_INTERRUPT_EVENT_BIT = 0x1, //write clear + TI_INTERRUPT_EVENT_BIT = 0x1, // write clear INTERRUPT_PENDING_EVENT_BIT = 0x2, // read only - POINTERS_EQUAL_EVENT_BIT = 0x4, //write clear - BUFFER_END_EVENT_BIT = 0x10, //write clear + POINTERS_EQUAL_EVENT_BIT = 0x4, // write clear + BUFFER_END_EVENT_BIT = 0x10, // write clear TERMINAL_COUNT_EVENT_BIT = 0x20, // write clear DMA_TERMINAL_COUNT_EVENT_BIT = 0x80, // write clear }; enum event_enable_bits { - ENABLE_TI_INTERRUPT_EVENT_BIT = 0x1, //write clear - ENABLE_POINTERS_EQUAL_EVENT_BIT = 0x4, //write clear - ENABLE_BUFFER_END_EVENT_BIT = 0x10, //write clear - ENABLE_TERMINAL_COUNT_EVENT_BIT = 0x20, // write clear + ENABLE_TI_INTERRUPT_EVENT_BIT = 0x1, // write clear + ENABLE_POINTERS_EQUAL_EVENT_BIT = 0x4, // write clear + ENABLE_BUFFER_END_EVENT_BIT = 0x10, // write clear + ENABLE_TERMINAL_COUNT_EVENT_BIT = 0x20, // write clear ENABLE_DMA_TERMINAL_COUNT_EVENT_BIT = 0x80, // write clear }; enum stream_status_bits { - HALTED_STATUS_BIT = 0x1, //read - RESTART_STREAM_BIT = 0x1 //write + HALTED_STATUS_BIT = 0x1, // read + RESTART_STREAM_BIT = 0x1 // write }; enum buffer_control_bits { DIRECTION_GPIB_TO_HOST_BIT = 0x20, // transfer direction (set for gpib to host) - ENABLE_TI_BUFFER_BIT = 0x40, //enable fifo - FAST_WR_EN_BIT = 0x80, // 350 ns t1 delay? + ENABLE_TI_BUFFER_BIT = 0x40, // enable fifo + FAST_WR_EN_BIT = 0x80, // 350 ns t1 delay? }; // registers accessible through isapnp chip on 82341d enum hp_82341d_pnp_registers { - PIO_DATA_REG = 0x20, //read/write pio data lines + PIO_DATA_REG = 0x20, // read/write pio data lines PIO_DIRECTION_REG = 0x21, // set pio data line directions (set for input) }; diff --git a/drivers/staging/gpib/include/amccs5933.h b/drivers/staging/gpib/include/amccs5933.h index 4de0f6797458..d7f63c795096 100644 --- a/drivers/staging/gpib/include/amccs5933.h +++ b/drivers/staging/gpib/include/amccs5933.h @@ -24,7 +24,7 @@ extern inline int INCOMING_MAILBOX_REG(unsigned int mailbox) enum { OUTBOX_EMPTY_INTR_BIT = 0x10, // enable outbox empty interrupt INBOX_FULL_INTR_BIT = 0x1000, // enable inbox full interrupt - INBOX_INTR_CS_BIT = 0x20000, // read, or write clear inbox full interrupt + INBOX_INTR_CS_BIT = 0x20000, // read, or write clear inbox full interrupt INTR_ASSERTED_BIT = 0x800000, // read only, interrupt asserted }; @@ -52,7 +52,7 @@ extern inline int OUTBOX_SELECT_BITS(unsigned int mailbox) return (mailbox & 0x3) << 2; }; -//BMCSR bits +// BMCSR bits enum { MBOX_FLAGS_RESET_BIT = 0x08000000, // resets mailbox empty/full flags }; diff --git a/drivers/staging/gpib/include/gpib_types.h b/drivers/staging/gpib/include/gpib_types.h index db040c80d778..998abb379749 100644 --- a/drivers/staging/gpib/include/gpib_types.h +++ b/drivers/staging/gpib/include/gpib_types.h @@ -273,7 +273,8 @@ struct gpib_board { struct mutex big_gpib_mutex; /* pid of last process to lock the board mutex */ pid_t locking_pid; - spinlock_t locking_pid_spinlock; // lock for setting locking pid + /* lock for setting locking pid */ + spinlock_t locking_pid_spinlock; /* Spin lock for dealing with races with the interrupt handler */ spinlock_t spinlock; /* Watchdog timer to enable timeouts */ diff --git a/drivers/staging/gpib/include/nec7210.h b/drivers/staging/gpib/include/nec7210.h index 312217b4580e..9835aa5ef4ff 100644 --- a/drivers/staging/gpib/include/nec7210.h +++ b/drivers/staging/gpib/include/nec7210.h @@ -22,18 +22,18 @@ struct nec7210_priv { u32 iobase; #endif void __iomem *mmiobase; - unsigned int offset; // offset between successive nec7210 io addresses + unsigned int offset; // offset between successive nec7210 io addresses unsigned int dma_channel; u8 *dma_buffer; unsigned int dma_buffer_length; // length of dma buffer dma_addr_t dma_buffer_addr; // bus address of board->buffer for use with dma // software copy of bits written to registers u8 reg_bits[8]; - u8 auxa_bits; // bits written to auxiliary register A - u8 auxb_bits; // bits written to auxiliary register B + u8 auxa_bits; // bits written to auxiliary register A + u8 auxb_bits; // bits written to auxiliary register B // used to keep track of board's state, bit definitions given below unsigned long state; - /* lock for chips that extend the nec7210 registers by paging in alternate regs */ + // lock for chips that extend the nec7210 registers by paging in alternate regs spinlock_t register_page_lock; // wrappers for outb, inb, readb, or writeb u8 (*read_byte)(struct nec7210_priv *priv, unsigned int register_number); @@ -64,17 +64,17 @@ static inline void write_byte(struct nec7210_priv *priv, u8 byte, unsigned int r // struct nec7210_priv.state bit numbers enum { - PIO_IN_PROGRESS_BN, // pio transfer in progress + PIO_IN_PROGRESS_BN, // pio transfer in progress DMA_READ_IN_PROGRESS_BN, // dma read transfer in progress DMA_WRITE_IN_PROGRESS_BN, // dma write transfer in progress - READ_READY_BN, // board has data byte available to read - WRITE_READY_BN, // board is ready to send a data byte - COMMAND_READY_BN, // board is ready to send a command byte - RECEIVED_END_BN, // received END - BUS_ERROR_BN, // output error has occurred - RFD_HOLDOFF_BN, // rfd holdoff in effect - DEV_CLEAR_BN, // device clear received - ADR_CHANGE_BN, // address state change occurred + READ_READY_BN, // board has data byte available to read + WRITE_READY_BN, // board is ready to send a data byte + COMMAND_READY_BN, // board is ready to send a command byte + RECEIVED_END_BN, // received END + BUS_ERROR_BN, // output error has occurred + RFD_HOLDOFF_BN, // rfd holdoff in effect + DEV_CLEAR_BN, // device clear received + ADR_CHANGE_BN, // address state change occurred }; // interface functions diff --git a/drivers/staging/gpib/include/nec7210_registers.h b/drivers/staging/gpib/include/nec7210_registers.h index 97c53ac8e805..067983d7a07f 100644 --- a/drivers/staging/gpib/include/nec7210_registers.h +++ b/drivers/staging/gpib/include/nec7210_registers.h @@ -11,7 +11,7 @@ enum nec7210_chipset { NEC7210, // The original TNT4882, // NI NAT4882, // NI - CB7210, // measurement computing + CB7210, // measurement computing IOT7210, // iotech IGPIB7210, // Ines TNT5004, // NI (minor differences to TNT4882) @@ -48,7 +48,7 @@ enum nec7210_read_regs { ADR1, // address 2 }; -//bit definitions common to nec-7210 compatible registers +// bit definitions common to nec-7210 compatible registers // ISR1: interrupt status register 1 enum isr1_bits { diff --git a/drivers/staging/gpib/include/plx9050.h b/drivers/staging/gpib/include/plx9050.h index 66c56335f5c0..c911b285a0ca 100644 --- a/drivers/staging/gpib/include/plx9050.h +++ b/drivers/staging/gpib/include/plx9050.h @@ -23,10 +23,10 @@ enum plx9050_intcsr_bits { PLX9050_LINTR2_STATUS_BIT = 0x20, PLX9050_PCI_INTR_EN_BIT = 0x40, PLX9050_SOFT_INTR_BIT = 0x80, - PLX9050_LINTR1_SELECT_ENABLE_BIT = 0x100, //9052 extension - PLX9050_LINTR2_SELECT_ENABLE_BIT = 0x200, //9052 extension - PLX9050_LINTR1_EDGE_CLEAR_BIT = 0x400, //9052 extension - PLX9050_LINTR2_EDGE_CLEAR_BIT = 0x800, //9052 extension + PLX9050_LINTR1_SELECT_ENABLE_BIT = 0x100, // 9052 extension + PLX9050_LINTR2_SELECT_ENABLE_BIT = 0x200, // 9052 extension + PLX9050_LINTR1_EDGE_CLEAR_BIT = 0x400, // 9052 extension + PLX9050_LINTR2_EDGE_CLEAR_BIT = 0x800, // 9052 extension }; enum plx9050_cntrl_bits { diff --git a/drivers/staging/gpib/include/tms9914.h b/drivers/staging/gpib/include/tms9914.h index 50a9d3b22619..e66b75e0fda8 100644 --- a/drivers/staging/gpib/include/tms9914.h +++ b/drivers/staging/gpib/include/tms9914.h @@ -30,10 +30,10 @@ struct tms9914_priv { u8 imr0_bits, imr1_bits; // bits written to address mode register u8 admr_bits; - u8 auxa_bits; // bits written to auxiliary register A + u8 auxa_bits; // bits written to auxiliary register A // used to keep track of board's state, bit definitions given below unsigned long state; - u8 eos; // eos character + u8 eos; // eos character short eos_flags; u8 spoll_status; enum tms9914_holdoff_mode holdoff_mode; @@ -67,15 +67,15 @@ static inline void write_byte(struct tms9914_priv *priv, u8 byte, unsigned int r // struct tms9914_priv.state bit numbers enum { - PIO_IN_PROGRESS_BN, // pio transfer in progress + PIO_IN_PROGRESS_BN, // pio transfer in progress DMA_READ_IN_PROGRESS_BN, // dma read transfer in progress DMA_WRITE_IN_PROGRESS_BN, // dma write transfer in progress - READ_READY_BN, // board has data byte available to read - WRITE_READY_BN, // board is ready to send a data byte - COMMAND_READY_BN, // board is ready to send a command byte - RECEIVED_END_BN, // received END - BUS_ERROR_BN, // bus error - DEV_CLEAR_BN, // device clear received + READ_READY_BN, // board has data byte available to read + WRITE_READY_BN, // board is ready to send a data byte + COMMAND_READY_BN, // board is ready to send a command byte + RECEIVED_END_BN, // received END + BUS_ERROR_BN, // bus error + DEV_CLEAR_BN, // device clear received }; // interface functions @@ -150,23 +150,23 @@ enum { IMR0 = 0, /* interrupt mask 0 */ IMR1 = 1, /* interrupt mask 1 */ AUXCR = 3, /* auxiliary command */ - ADR = 4, // address register - SPMR = 5, // serial poll mode register + ADR = 4, /* address register */ + SPMR = 5, /* serial poll mode register */ PPR = 6, /* parallel poll */ CDOR = 7, /* data out register */ }; // read registers enum { - ISR0 = 0, /* interrupt status 0 */ - ISR1 = 1, /* interrupt status 1 */ - ADSR = 2, /* address status */ - BSR = 3, /* bus status */ - CPTR = 6, /* command pass thru */ - DIR = 7, /* data in register */ + ISR0 = 0, /* interrupt status 0 */ + ISR1 = 1, /* interrupt status 1 */ + ADSR = 2, /* address status */ + BSR = 3, /* bus status */ + CPTR = 6, /* command pass thru */ + DIR = 7, /* data in register */ }; -//bit definitions common to tms9914 compatible registers +// bit definitions common to tms9914 compatible registers /* ISR0 - Register bits */ enum isr0_bits { @@ -248,33 +248,33 @@ enum bus_status_bits { /*---------------------------------------------------------*/ enum aux_cmd_bits { - AUX_CS = 0x80, /* set bit instead of clearing it, used with commands marked 'd' below */ - AUX_CHIP_RESET = 0x0, /* d Chip reset */ - AUX_INVAL = 0x1, // release dac holdoff, invalid command byte - AUX_VAL = (AUX_INVAL | AUX_CS), // release dac holdoff, valid command byte - AUX_RHDF = 0x2, /* X Release RFD holdoff */ - AUX_HLDA = 0x3, /* d holdoff on all data */ - AUX_HLDE = 0x4, /* d holdoff on EOI only */ - AUX_NBAF = 0x5, /* X Set new byte available false */ - AUX_FGET = 0x6, /* d force GET */ - AUX_RTL = 0x7, /* d return to local */ - AUX_SEOI = 0x8, /* X send EOI with next byte */ - AUX_LON = 0x9, /* d Listen only */ - AUX_TON = 0xa, /* d Talk only */ - AUX_GTS = 0xb, /* X goto standby */ - AUX_TCA = 0xc, /* X take control asynchronously */ - AUX_TCS = 0xd, /* X take " synchronously */ - AUX_RPP = 0xe, /* d Request parallel poll */ - AUX_SIC = 0xf, /* d send interface clear */ - AUX_SRE = 0x10, /* d send remote enable */ - AUX_RQC = 0x11, /* X request control */ - AUX_RLC = 0x12, /* X release control */ - AUX_DAI = 0x13, /* d disable all interrupts */ - AUX_PTS = 0x14, /* X pass through next secondary */ - AUX_STDL = 0x15, /* d short T1 delay */ - AUX_SHDW = 0x16, /* d shadow handshake */ - AUX_VSTDL = 0x17, /* d very short T1 delay (smj9914 extension) */ - AUX_RSV2 = 0x18, /* d request service bit 2 (smj9914 extension) */ + AUX_CS = 0x80, /* set bit instead of clearing it, used with commands marked 'd' below */ + AUX_CHIP_RESET = 0x0, /* d Chip reset */ + AUX_INVAL = 0x1, /* release dac holdoff, invalid command byte */ + AUX_VAL = (AUX_INVAL | AUX_CS), /* release dac holdoff, valid command byte */ + AUX_RHDF = 0x2, /* X Release RFD holdoff */ + AUX_HLDA = 0x3, /* d holdoff on all data */ + AUX_HLDE = 0x4, /* d holdoff on EOI only */ + AUX_NBAF = 0x5, /* X Set new byte available false */ + AUX_FGET = 0x6, /* d force GET */ + AUX_RTL = 0x7, /* d return to local */ + AUX_SEOI = 0x8, /* X send EOI with next byte */ + AUX_LON = 0x9, /* d Listen only */ + AUX_TON = 0xa, /* d Talk only */ + AUX_GTS = 0xb, /* X goto standby */ + AUX_TCA = 0xc, /* X take control asynchronously */ + AUX_TCS = 0xd, /* X take " synchronously */ + AUX_RPP = 0xe, /* d Request parallel poll */ + AUX_SIC = 0xf, /* d send interface clear */ + AUX_SRE = 0x10, /* d send remote enable */ + AUX_RQC = 0x11, /* X request control */ + AUX_RLC = 0x12, /* X release control */ + AUX_DAI = 0x13, /* d disable all interrupts */ + AUX_PTS = 0x14, /* X pass through next secondary */ + AUX_STDL = 0x15, /* d short T1 delay */ + AUX_SHDW = 0x16, /* d shadow handshake */ + AUX_VSTDL = 0x17, /* d very short T1 delay (smj9914 extension) */ + AUX_RSV2 = 0x18, /* d request service bit 2 (smj9914 extension) */ }; #endif //_TMS9914_H diff --git a/drivers/staging/gpib/include/tnt4882_registers.h b/drivers/staging/gpib/include/tnt4882_registers.h index 1b1441cd03d5..d54c4cc61168 100644 --- a/drivers/staging/gpib/include/tnt4882_registers.h +++ b/drivers/staging/gpib/include/tnt4882_registers.h @@ -32,11 +32,11 @@ enum { CMDR = 0x1c, // command register TIMER = 0x1e, // timer register - STS1 = 0x10, /* T488 Status Register 1 */ - STS2 = 0x1c, /* T488 Status Register 2 */ + STS1 = 0x10, // T488 Status Register 1 + STS2 = 0x1c, // T488 Status Register 2 ISR0 = IMR0, - ISR3 = 0x1a, /* T488 Interrupt Status Register 3 */ - BCR = 0x1f, /* bus control/status register */ + ISR3 = 0x1a, // T488 Interrupt Status Register 3 + BCR = 0x1f, // bus control/status register BSR = BCR, }; @@ -107,11 +107,11 @@ enum imr0_bits { /* ISR0 -- Interrupt Status Register 0 */ enum isr0_bits { - TNT_SYNC_BIT = 0x1, /* handshake sync */ - TNT_TO_BIT = 0x2, /* timeout */ - TNT_ATNI_BIT = 0x4, /* ATN interrupt */ + TNT_SYNC_BIT = 0x1, /* handshake sync */ + TNT_TO_BIT = 0x2, /* timeout */ + TNT_ATNI_BIT = 0x4, /* ATN interrupt */ TNT_IFCI_BIT = 0x8, /* interface clear interrupt */ - TNT_EOS_BIT = 0x10, /* end of string */ + TNT_EOS_BIT = 0x10, /* end of string */ TNT_NL_BIT = 0x20, /* new line receive */ TNT_STBO_BIT = 0x40, /* status byte out */ TNT_NBA_BIT = 0x80, /* new byte available */ @@ -129,7 +129,7 @@ enum isr3_bits { }; enum keyreg_bits { - MSTD = 0x20, // enable 350ns T1 delay + MSTD = 0x20, /* enable 350ns T1 delay */ }; /* STS1 -- Status Register 1 (read only) */ @@ -157,7 +157,7 @@ enum tnt4882_aux_cmds { AUX_9914 = 0x15, // switch to 9914 mode AUX_REQT = 0x18, AUX_REQF = 0x19, - AUX_PAGEIN = 0x50, /* page in alternate registers */ + AUX_PAGEIN = 0x50, // page in alternate registers AUX_HLDI = 0x51, // rfd holdoff immediately AUX_CLEAR_END = 0x55, AUX_7210 = 0x99, // switch to 7210 mode @@ -183,7 +183,7 @@ enum auxi_bits { enum sasr_bits { ACRDY_BIT = 0x4, /* acceptor ready state */ - ADHS_BIT = 0x8, /* acceptor data holdoff state */ + ADHS_BIT = 0x8, /* acceptor data holdoff state */ ANHS2_BIT = 0x10, /* acceptor not ready holdoff immediately state */ ANHS1_BIT = 0x20, /* acceptor not ready holdoff state */ AEHS_BIT = 0x40, /* acceptor end holdoff state */ diff --git a/drivers/staging/gpib/ines/ines.h b/drivers/staging/gpib/ines/ines.h index f0210ce2470d..6ad57e9a1216 100644 --- a/drivers/staging/gpib/ines/ines.h +++ b/drivers/staging/gpib/ines/ines.h @@ -97,9 +97,9 @@ enum extend_mode_bits { TR3_TRIG_ENABLE_BIT = 0x1, // enable generation of trigger pulse T/R3 pin // clear message available status bit when chip writes byte with EOI true MAV_ENABLE_BIT = 0x2, - EOS1_ENABLE_BIT = 0x4, // enable eos register 1 - EOS2_ENABLE_BIT = 0x8, // enable eos register 2 - EOIDIS_BIT = 0x10, // disable EOI interrupt when doing rfd holdoff on end? + EOS1_ENABLE_BIT = 0x4, // enable eos register 1 + EOS2_ENABLE_BIT = 0x8, // enable eos register 2 + EOIDIS_BIT = 0x10, // disable EOI interrupt when doing rfd holdoff on end? XFER_COUNTER_ENABLE_BIT = 0x20, XFER_COUNTER_OUTPUT_BIT = 0x40, // use counter for output, clear for input // when xfer counter hits 0, assert EOI on write or RFD holdoff on read @@ -121,10 +121,10 @@ enum ines_admr_bits { }; enum xdma_control_bits { - DMA_OUTPUT_BIT = 0x1, // use dma for output, clear for input + DMA_OUTPUT_BIT = 0x1, // use dma for output, clear for input ENABLE_SYNC_DMA_BIT = 0x2, - DMA_ACCESS_EVERY_CYCLE = 0x4,// dma accesses fifo every cycle, clear for every other cycle - DMA_16BIT = 0x8, // clear for 8 bit transfers + DMA_ACCESS_EVERY_CYCLE = 0x4, // dma accesses fifo every cycle, clear for every other cycle + DMA_16BIT = 0x8, // clear for 8 bit transfers }; enum bus_control_monitor_bits { diff --git a/drivers/staging/gpib/ines/ines_gpib.c b/drivers/staging/gpib/ines/ines_gpib.c index c851fd014f48..a3cf846fd0f9 100644 --- a/drivers/staging/gpib/ines/ines_gpib.c +++ b/drivers/staging/gpib/ines/ines_gpib.c @@ -152,7 +152,7 @@ static int ines_accel_read(struct gpib_board *board, u8 *buffer, write_byte(nec_priv, INES_RFD_HLD_IMMEDIATE, AUXMR); - //clear in fifo + // clear in fifo nec7210_set_reg_bits(nec_priv, ADMR, IN_FIFO_ENABLE_BIT, 0); nec7210_set_reg_bits(nec_priv, ADMR, IN_FIFO_ENABLE_BIT, IN_FIFO_ENABLE_BIT); @@ -225,7 +225,7 @@ static int ines_accel_write(struct gpib_board *board, u8 *buffer, size_t length, unsigned int num_bytes, i; *bytes_written = 0; - //clear out fifo + // clear out fifo nec7210_set_reg_bits(nec_priv, ADMR, OUT_FIFO_ENABLE_BIT, 0); nec7210_set_reg_bits(nec_priv, ADMR, OUT_FIFO_ENABLE_BIT, OUT_FIFO_ENABLE_BIT); diff --git a/drivers/staging/gpib/nec7210/nec7210.c b/drivers/staging/gpib/nec7210/nec7210.c index 34a1cae4f486..bbf39367f5e4 100644 --- a/drivers/staging/gpib/nec7210/nec7210.c +++ b/drivers/staging/gpib/nec7210/nec7210.c @@ -779,10 +779,10 @@ int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv, *bytes_written = 0; - clear_bit(DEV_CLEAR_BN, &priv->state); //XXX + clear_bit(DEV_CLEAR_BN, &priv->state); // XXX if (send_eoi) - length-- ; /* save the last byte for sending EOI */ + length-- ; // save the last byte for sending EOI if (length > 0) { // isa dma transfer @@ -1005,7 +1005,7 @@ void nec7210_board_online(struct nec7210_priv *priv, const struct gpib_board *bo nec7210_primary_address(board, priv, board->pad); nec7210_secondary_address(board, priv, board->sad, board->sad >= 0); - // enable interrupts + /* enable interrupts */ priv->reg_bits[IMR1] = HR_ERRIE | HR_DECIE | HR_ENDIE | HR_DETIE | HR_CPTIE | HR_DOIE | HR_DIIE; priv->reg_bits[IMR2] = IMR2_ENABLE_INTR_MASK; diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c index 73ea72f34c0a..4dec87d12687 100644 --- a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c +++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c @@ -29,7 +29,7 @@ static void ni_usb_stop(struct ni_usb_priv *ni_priv); static DEFINE_MUTEX(ni_usb_hotplug_lock); -//calculates a reasonable timeout in that can be passed to usb functions +// calculates a reasonable timeout in that can be passed to usb functions static inline unsigned long ni_usb_timeout_msecs(unsigned int usec) { if (usec == 0) @@ -327,7 +327,7 @@ static void ni_usb_soft_update_status(struct gpib_board *board, unsigned int ni_ board->status &= ~clear_mask; board->status &= ~ni_usb_ibsta_mask; board->status |= ni_usb_ibsta & ni_usb_ibsta_mask; - //FIXME should generate events on DTAS and DCAS + // FIXME should generate events on DTAS and DCAS spin_lock_irqsave(&board->spinlock, flags); /* remove set status bits from monitored set why ?***/ @@ -569,7 +569,7 @@ static int ni_usb_write_registers(struct ni_usb_priv *ni_priv, mutex_unlock(&ni_priv->addressed_transfer_lock); ni_usb_parse_reg_write_status_block(in_data, &status, ®_writes_completed); - //FIXME parse extra 09 status bits and termination + // FIXME parse extra 09 status bits and termination kfree(in_data); if (status.id != NIUSB_REG_WRITE_ID) { dev_err(&usb_dev->dev, "parse error, id=0x%x != NIUSB_REG_WRITE_ID\n", status.id); @@ -1106,7 +1106,7 @@ static int ni_usb_request_system_control(struct gpib_board *board, int request_c return 0; } -//FIXME maybe the interface should have a "pulse interface clear" function that can return an error? +// FIXME maybe the interface should have a "pulse interface clear" function that can return an error? static void ni_usb_interface_clear(struct gpib_board *board, int assert) { int retval; @@ -1363,7 +1363,7 @@ static int ni_usb_parallel_poll(struct gpib_board *board, u8 *result) return -ENOMEM; out_data[i++] = NIUSB_IBRPP_ID; - out_data[i++] = 0xf0; //FIXME: this should be the parallel poll timeout code + out_data[i++] = 0xf0; // FIXME: this should be the parallel poll timeout code out_data[i++] = 0x0; out_data[i++] = 0x0; i += ni_usb_bulk_termination(&out_data[i]); diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.h b/drivers/staging/gpib/ni_usb/ni_usb_gpib.h index b011e131201c..688f5e08792f 100644 --- a/drivers/staging/gpib/ni_usb/ni_usb_gpib.h +++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.h @@ -72,10 +72,10 @@ struct ni_usb_priv { struct urb *bulk_urb; struct urb *interrupt_urb; u8 interrupt_buffer[0x11]; - struct mutex addressed_transfer_lock; // protect transfer lock - struct mutex bulk_transfer_lock; // protect bulk message sends - struct mutex control_transfer_lock; // protect control messages - struct mutex interrupt_transfer_lock; // protect interrupt messages + struct mutex addressed_transfer_lock; // protect transfer lock + struct mutex bulk_transfer_lock; // protect bulk message sends + struct mutex control_transfer_lock; // protect control messages + struct mutex interrupt_transfer_lock; // protect interrupt messages struct timer_list bulk_timer; struct ni_usb_urb_ctx context; int product_id; @@ -145,7 +145,7 @@ enum ni_usb_error_codes { * CIC with no listener */ NIUSB_NO_LISTENER_ERROR = 8, - // get NIUSB_TIMEOUT_ERROR on board read/write timeout + /* get NIUSB_TIMEOUT_ERROR on board read/write timeout */ NIUSB_TIMEOUT_ERROR = 10, }; diff --git a/drivers/staging/gpib/pc2/pc2_gpib.c b/drivers/staging/gpib/pc2/pc2_gpib.c index 2282492025b7..9f3943d1df66 100644 --- a/drivers/staging/gpib/pc2/pc2_gpib.c +++ b/drivers/staging/gpib/pc2/pc2_gpib.c @@ -36,7 +36,7 @@ static const int pc2_2a_iosize = 16; static const int pc2a_reg_offset = 0x400; static const int pc2_reg_offset = 1; -//interrupt service routine +// interrupt service routine static irqreturn_t pc2_interrupt(int irq, void *arg); static irqreturn_t pc2a_interrupt(int irq, void *arg); @@ -593,7 +593,7 @@ static struct gpib_interface pc2a_cb7210_interface = { .parallel_poll_configure = pc2_parallel_poll_configure, .parallel_poll_response = pc2_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX - .line_status = NULL, //XXX + .line_status = NULL, // XXX .update_status = pc2_update_status, .primary_address = pc2_primary_address, .secondary_address = pc2_secondary_address, diff --git a/drivers/staging/gpib/tms9914/tms9914.c b/drivers/staging/gpib/tms9914/tms9914.c index 04d57108efc7..0d11b80bb982 100644 --- a/drivers/staging/gpib/tms9914/tms9914.c +++ b/drivers/staging/gpib/tms9914/tms9914.c @@ -647,7 +647,7 @@ static void check_my_address_state(struct gpib_board *board, } else if (cmd_byte == MTA(board->pad)) { priv->primary_talk_addressed = 1; if (board->sad < 0) - //make active talker + // make active talker write_byte(priv, AUX_TON | AUX_CS, AUXCR); } else if (board->sad >= 0 && priv->primary_talk_addressed && cmd_byte == MSA(board->sad)) { @@ -730,7 +730,7 @@ irqreturn_t tms9914_interrupt_have_status(struct gpib_board *board, struct tms99 if (status0 & HR_SPAS) { priv->spoll_status &= ~request_service_bit; write_byte(priv, priv->spoll_status, SPMR); - //FIXME: set SPOLL status bit + // FIXME: set SPOLL status bit } // record service request in status if (status1 & HR_SRQ) @@ -841,7 +841,7 @@ void tms9914_board_reset(struct tms9914_priv *priv) /* parallel poll unconfigure */ write_byte(priv, 0, PPR); - // request for data holdoff + /* request for data holdoff */ tms9914_set_holdoff_mode(priv, TMS9914_HOLDOFF_ALL); } EXPORT_SYMBOL_GPL(tms9914_board_reset); @@ -852,7 +852,7 @@ void tms9914_online(struct gpib_board *board, struct tms9914_priv *priv) tms9914_primary_address(board, priv, board->pad); tms9914_secondary_address(board, priv, board->sad, board->sad >= 0); - // enable tms9914 interrupts + /* enable tms9914 interrupts */ priv->imr0_bits |= HR_MACIE | HR_RLCIE | HR_ENDIE | HR_BOIE | HR_BIIE | HR_SPASIE; priv->imr1_bits |= HR_MAIE | HR_SRQIE | HR_UNCIE | HR_ERRIE | HR_IFCIE | @@ -861,7 +861,7 @@ void tms9914_online(struct gpib_board *board, struct tms9914_priv *priv) write_byte(priv, priv->imr1_bits, IMR1); write_byte(priv, AUX_DAI, AUXCR); - // turn off reset state + /* turn off reset state */ write_byte(priv, AUX_CHIP_RESET, AUXCR); } EXPORT_SYMBOL_GPL(tms9914_online); diff --git a/drivers/staging/gpib/tnt4882/mite.h b/drivers/staging/gpib/tnt4882/mite.h index 522d6b56cb7d..a1fdba9672a0 100644 --- a/drivers/staging/gpib/tnt4882/mite.h +++ b/drivers/staging/gpib/tnt4882/mite.h @@ -219,15 +219,15 @@ void mite_list_devices(void); #define MITE_AMHOST_A24_BLOCK 0x3b enum mite_registers { - MITE_IODWBSR = 0xc0, //IO Device Window Base Size Register - MITE_CSIGR = 0x460, //chip signature - MITE_IODWBSR_1 = 0xc4, // IO Device Window Base Size Register 1 (used by 6602 boards) + MITE_IODWBSR = 0xc0, // IO Device Window Base Size Register + MITE_CSIGR = 0x460, // chip signature + MITE_IODWBSR_1 = 0xc4, // IO Device Window Base Size Register 1 (used by 6602 boards) MITE_IODWCR_1 = 0xf4 }; enum MITE_IODWBSR_bits { - WENAB = 0x80, // window enable - WENAB_6602 = 0x8c // window enable for 6602 boards + WENAB = 0x80, // window enable + WENAB_6602 = 0x8c // window enable for 6602 boards }; #endif diff --git a/drivers/staging/gpib/tnt4882/tnt4882_gpib.c b/drivers/staging/gpib/tnt4882/tnt4882_gpib.c index a17b69e34986..29c6884e01fd 100644 --- a/drivers/staging/gpib/tnt4882/tnt4882_gpib.c +++ b/drivers/staging/gpib/tnt4882/tnt4882_gpib.c @@ -570,7 +570,7 @@ static irqreturn_t tnt4882_internal_interrupt(struct gpib_board *board) if (isr0_bits & TNT_IFCI_BIT) push_gpib_event(board, EVENT_IFC); - //XXX don't need this wakeup, one below should do? + // XXX don't need this wakeup, one below should do? // wake_up_interruptible(&board->wait); if (isr3_bits & HR_NFF) @@ -730,7 +730,7 @@ static int tnt4882_parallel_poll(struct gpib_board *board, u8 *result) if (tnt_priv->nec7210_priv.type != NEC7210) { tnt_priv->auxg_bits |= RPP2_BIT; write_byte(&tnt_priv->nec7210_priv, tnt_priv->auxg_bits, AUXMR); - udelay(2); //FIXME use parallel poll timeout + udelay(2); // FIXME use parallel poll timeout *result = read_byte(&tnt_priv->nec7210_priv, CPTR); tnt_priv->auxg_bits &= ~RPP2_BIT; write_byte(&tnt_priv->nec7210_priv, tnt_priv->auxg_bits, AUXMR); From 5141ae32d4b8971d7b689854fd47a200e695bda3 Mon Sep 17 00:00:00 2001 From: Nino Zhang Date: Mon, 18 Aug 2025 23:26:41 +0800 Subject: [PATCH 0328/2711] staging: rtl8723bs: fix coding style issues in core/rtw_mlme.c Fix blank line issues in coding style: - Remove unnecessary blank lines after an open brace '{'. - Remove unnecessary blank lines before a closing brace '}'. - Add missing blank lines after variable declarations. - Add blank lines after function, struct, union, and enum declarations. Signed-off-by: Nino Zhang Link: https://lore.kernel.org/r/20250818152641.106740-1-ninozhang001@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme.c | 29 ++--------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index fdf06b5253a7..c06d990350e6 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -200,7 +200,6 @@ void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwor void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork) { - struct __queue *free_queue = &pmlmepriv->free_bss_pool; if (!pnetwork) @@ -255,11 +254,9 @@ void rtw_free_network_queue(struct adapter *padapter, u8 isfreeall) phead = get_list_head(scanned_queue); list_for_each_safe(plist, tmp, phead) { - pnetwork = list_entry(plist, struct wlan_network, list); _rtw_free_network(pmlmepriv, pnetwork, isfreeall); - } spin_unlock_bh(&scanned_queue->lock); @@ -348,7 +345,6 @@ int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork) ret = true; return ret; - } inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b) @@ -378,7 +374,6 @@ int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst, u8 fea (d_cap & WLAN_CAPABILITY_IBSS)) && ((s_cap & WLAN_CAPABILITY_ESS) == (d_cap & WLAN_CAPABILITY_ESS)); - } struct wlan_network *_rtw_find_same_network(struct __queue *scanned_queue, struct wlan_network *network) @@ -410,7 +405,6 @@ struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue) phead = get_list_head(scanned_queue); list_for_each(plist, phead) { - pwlan = list_entry(plist, struct wlan_network, list); if (!pwlan->fixed) { @@ -419,7 +413,6 @@ struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue) } } return oldest; - } void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, @@ -454,7 +447,6 @@ void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, sq_final = dst->phy_info.signal_quality; rssi_final = dst->rssi; } - } if (update_ie) { @@ -516,7 +508,6 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t if (!oldest || time_after(oldest->last_scanned, pnetwork->last_scanned)) oldest = pnetwork; - } /* If we didn't find a match, then get a new network slot to initialize @@ -560,7 +551,6 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t pnetwork->network.phy_info.signal_quality = 0; list_add_tail(&pnetwork->list, &queue->queue); - } } else { /* we have an entry and we are going to update it. But this entry may @@ -623,7 +613,6 @@ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwor return true; else return false; - } if (adapter->registrypriv.wifi_spec == 1) { /* for correct flow of 8021X to do.... */ u8 *p = NULL; @@ -900,7 +889,6 @@ void rtw_indicate_connect(struct adapter *padapter) pmlmepriv->to_join = false; if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { - set_fwstate(pmlmepriv, _FW_LINKED); if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || @@ -974,7 +962,6 @@ void rtw_scan_abort(struct adapter *adapter) pmlmeext->scan_abort = true; while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) && jiffies_to_msecs(start) <= 200) { - if (adapter->bDriverStopped || adapter->bSurpriseRemoved) break; @@ -1067,7 +1054,6 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str } return psta; - } /* pnetwork : returns from rtw_joinbss_event_callback */ @@ -1502,11 +1488,11 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { - rtw_free_stainfo(adapter, psta); if (adapter->stapriv.asoc_sta_count == 1) {/* a sta + bc/mc_stainfo (not Ibss_stainfo) */ u8 ret = _SUCCESS; + spin_lock_bh(&pmlmepriv->scanned_queue.lock); /* free old ibss network */ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.mac_address); @@ -1536,7 +1522,6 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) if (ret != _SUCCESS) goto unlock; } - } unlock: @@ -1595,7 +1580,6 @@ void _rtw_join_timeout_handler(struct timer_list *t) /* indicate disconnect for the case that join_timeout and check_fwstate != FW_LINKED */ rtw_cfg80211_indicate_disconnect(adapter); - } spin_unlock_bh(&pmlmepriv->lock); @@ -1645,7 +1629,6 @@ static void rtw_auto_scan_handler(struct adapter *padapter) if (pmlmepriv->auto_scan_int_ms != 0 && jiffies_to_msecs(jiffies - pmlmepriv->scan_start_time) > pmlmepriv->auto_scan_int_ms) { - if (!padapter->registrypriv.wifi_spec) { if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) == true) goto exit; @@ -1778,12 +1761,10 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme) phead = get_list_head(queue); list_for_each(mlme->pscanned, phead) { - pnetwork = list_entry(mlme->pscanned, struct wlan_network, list); rtw_check_roaming_candidate(mlme, &candidate, pnetwork); - } if (!candidate) { @@ -1875,12 +1856,10 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) phead = get_list_head(queue); list_for_each(pmlmepriv->pscanned, phead) { - pnetwork = list_entry(pmlmepriv->pscanned, struct wlan_network, list); rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork); - } if (!candidate) { @@ -1968,7 +1947,6 @@ signed int rtw_set_key(struct adapter *adapter, struct security_priv *psecurityp adapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid); switch (psetkeyparm->algorithm) { - case _WEP40_: keylen = 5; memcpy(&psetkeyparm->key[0], &psecuritypriv->dot11DefKey[keyid].skey[0], keylen); @@ -2044,7 +2022,6 @@ int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_ } return ielength; - } /* Ported from 8185: IsInPreAuthKeyList(). @@ -2449,7 +2426,6 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ } return phtpriv->ht_option; - } /* the function is > passive_level (in critical_section) */ @@ -2484,7 +2460,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe max_ampdu_sz = 1 << (max_ampdu_sz+3); /* max_ampdu_sz (kbytes); */ phtpriv->rx_ampdu_maxlen = max_ampdu_sz; - } len = 0; @@ -2575,7 +2550,6 @@ void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitfr rtw_addbareq_cmd(padapter, (u8) priority, pattrib->ra); } } - } void rtw_append_exented_cap(struct adapter *padapter, u8 *out_ie, uint *pout_len) @@ -2616,6 +2590,7 @@ void rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) _rtw_roaming(padapter, tgt_network); spin_unlock_bh(&pmlmepriv->lock); } + void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; From a895dc47ceba63feb711905440585cf2b16e9ce2 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 3 Jul 2025 14:08:45 +0200 Subject: [PATCH 0329/2711] PCI: mediatek-gen3: Implement sys clock ready time setting In preparation to add support for the PCI-Express Gen3 controller found in newer MediaTek SoCs, such as the Dimensity 9400 MT6991 and the MT8196 Chromebook SoC, add the definition for the PCIE Resource Control register and a new sys_clk_rdy_time_us variable in platform data. If sys_clk_rdy_time_us is found (> 0), set the new value in the aforementioned register only after configuring the controller to RC mode, as this may otherwise be reset. Overriding the register defaults for SYS_CLK_RDY_TIME allows to work around sys_clk_rdy signal glitching in MT6991 and MT8196. Signed-off-by: AngeloGioacchino Del Regno [mani: used FIELD_MODIFY() to simplify mask and update] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250703120847.121826-2-angelogioacchino.delregno@collabora.com --- drivers/pci/controller/pcie-mediatek-gen3.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c index 97147f43e41c..aa7bd22b144c 100644 --- a/drivers/pci/controller/pcie-mediatek-gen3.c +++ b/drivers/pci/controller/pcie-mediatek-gen3.c @@ -102,6 +102,9 @@ #define PCIE_MSI_SET_ADDR_HI_BASE 0xc80 #define PCIE_MSI_SET_ADDR_HI_OFFSET 0x04 +#define PCIE_RESOURCE_CTRL_REG 0xd2c +#define PCIE_RSRC_SYS_CLK_RDY_TIME_MASK GENMASK(7, 0) + #define PCIE_ICMD_PM_REG 0x198 #define PCIE_TURN_OFF_LINK BIT(4) @@ -149,6 +152,7 @@ enum mtk_gen3_pcie_flags { * struct mtk_gen3_pcie_pdata - differentiate between host generations * @power_up: pcie power_up callback * @phy_resets: phy reset lines SoC data. + * @sys_clk_rdy_time_us: System clock ready time override (microseconds) * @flags: pcie device flags. */ struct mtk_gen3_pcie_pdata { @@ -157,6 +161,7 @@ struct mtk_gen3_pcie_pdata { const char *id[MAX_NUM_PHY_RESETS]; int num_resets; } phy_resets; + u8 sys_clk_rdy_time_us; u32 flags; }; @@ -435,6 +440,14 @@ static int mtk_pcie_startup_port(struct mtk_gen3_pcie *pcie) writel_relaxed(val, pcie->base + PCIE_CONF_LINK2_CTL_STS); } + /* If parameter is present, adjust SYS_CLK_RDY_TIME to avoid glitching */ + if (pcie->soc->sys_clk_rdy_time_us) { + val = readl_relaxed(pcie->base + PCIE_RESOURCE_CTRL_REG); + FIELD_MODIFY(PCIE_RSRC_SYS_CLK_RDY_TIME_MASK, &val, + pcie->soc->sys_clk_rdy_time_us); + writel_relaxed(val, pcie->base + PCIE_RESOURCE_CTRL_REG); + } + /* Set class code */ val = readl_relaxed(pcie->base + PCIE_PCI_IDS_1); val &= ~GENMASK(31, 8); From 0106b6c114cf8b77d801d9e280b221f8b4d5595b Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 3 Jul 2025 14:08:46 +0200 Subject: [PATCH 0330/2711] dt-bindings: PCI: mediatek-gen3: Add support for MT6991/MT8196 Add compatible strings for MT8196 and MT6991 (which are fully compatible between each other) and clock definitions. These new SoCs don't have tl_96m and tl_32k clocks, but need an AHB to APB bus clock and a low power clock. Signed-off-by: AngeloGioacchino Del Regno [mani: changed 'maxItems' to 'minItems' for reset] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250703120847.121826-3-angelogioacchino.delregno@collabora.com --- .../bindings/pci/mediatek-pcie-gen3.yaml | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml b/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml index 162406e0691a..0278845701ce 100644 --- a/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml +++ b/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml @@ -52,7 +52,12 @@ properties: - mediatek,mt8188-pcie - mediatek,mt8195-pcie - const: mediatek,mt8192-pcie + - items: + - enum: + - mediatek,mt6991-pcie + - const: mediatek,mt8196-pcie - const: mediatek,mt8192-pcie + - const: mediatek,mt8196-pcie - const: airoha,en7581-pcie reg: @@ -212,6 +217,36 @@ allOf: mediatek,pbus-csr: false + - if: + properties: + compatible: + contains: + enum: + - mediatek,mt8196-pcie + then: + properties: + clocks: + minItems: 6 + + clock-names: + items: + - const: pl_250m + - const: tl_26m + - const: bus + - const: low_power + - const: peri_26m + - const: peri_mem + + resets: + minItems: 2 + + reset-names: + items: + - const: phy + - const: mac + + mediatek,pbus-csr: false + - if: properties: compatible: From 81fedb39a9f0da301a11c7a3b81d91c3b9024462 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 3 Jul 2025 14:08:47 +0200 Subject: [PATCH 0331/2711] PCI: mediatek-gen3: Add support for MediaTek MT8196 SoC Introduce support for the PCI-Express Gen3 controller found in the MT8196 (and MT6991) SoC by adding a compatible string and platform specific data. Signed-off-by: AngeloGioacchino Del Regno Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250703120847.121826-4-angelogioacchino.delregno@collabora.com --- drivers/pci/controller/pcie-mediatek-gen3.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c index aa7bd22b144c..75ddb8bee168 100644 --- a/drivers/pci/controller/pcie-mediatek-gen3.c +++ b/drivers/pci/controller/pcie-mediatek-gen3.c @@ -1340,6 +1340,15 @@ static const struct mtk_gen3_pcie_pdata mtk_pcie_soc_mt8192 = { }, }; +static const struct mtk_gen3_pcie_pdata mtk_pcie_soc_mt8196 = { + .power_up = mtk_pcie_power_up, + .phy_resets = { + .id[0] = "phy", + .num_resets = 1, + }, + .sys_clk_rdy_time_us = 10, +}; + static const struct mtk_gen3_pcie_pdata mtk_pcie_soc_en7581 = { .power_up = mtk_pcie_en7581_power_up, .phy_resets = { @@ -1354,6 +1363,7 @@ static const struct mtk_gen3_pcie_pdata mtk_pcie_soc_en7581 = { static const struct of_device_id mtk_pcie_of_match[] = { { .compatible = "airoha,en7581-pcie", .data = &mtk_pcie_soc_en7581 }, { .compatible = "mediatek,mt8192-pcie", .data = &mtk_pcie_soc_mt8192 }, + { .compatible = "mediatek,mt8196-pcie", .data = &mtk_pcie_soc_mt8196 }, {}, }; MODULE_DEVICE_TABLE(of, mtk_pcie_of_match); From 6777885605e1538bd8126360c62669c4615690c1 Mon Sep 17 00:00:00 2001 From: Vipin Sharma Date: Mon, 7 Jul 2025 22:47:14 +0000 Subject: [PATCH 0332/2711] KVM: x86/mmu: Track possible NX huge pages separately for TDP vs. Shadow MMU Track possible NX huge pages for the TDP MMU separately from Shadow MMUs in anticipation of doing recovery for the TDP MMU while holding mmu_lock for read instead of write. Use a small structure to hold the list of pages along with the number of pages/entries in the list, as relying on kvm->stat.nx_lpage_splits to calculating the number of pages to recover would result in over-zapping when both TDP and Shadow MMUs are active. Suggested-by: Sean Christopherson Suggested-by: David Matlack Signed-off-by: Vipin Sharma Co-developed-by: James Houghton Signed-off-by: James Houghton Link: https://lore.kernel.org/r/20250707224720.4016504-2-jthoughton@google.com [sean: rewrite changelog, use #ifdef instead of dummy KVM_TDP_MMU #define] Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 39 ++++++++++++++-------- arch/x86/kvm/mmu/mmu.c | 59 ++++++++++++++++++++++----------- arch/x86/kvm/mmu/mmu_internal.h | 6 ++-- arch/x86/kvm/mmu/tdp_mmu.c | 4 +-- 4 files changed, 72 insertions(+), 36 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f19a76d3ca0e..c038d7cd187d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1348,6 +1348,30 @@ enum kvm_apicv_inhibit { __APICV_INHIBIT_REASON(LOGICAL_ID_ALIASED), \ __APICV_INHIBIT_REASON(PHYSICAL_ID_TOO_BIG) +struct kvm_possible_nx_huge_pages { + /* + * A list of kvm_mmu_page structs that, if zapped, could possibly be + * replaced by an NX huge page. A shadow page is on this list if its + * existence disallows an NX huge page (nx_huge_page_disallowed is set) + * and there are no other conditions that prevent a huge page, e.g. + * the backing host page is huge, dirtly logging is not enabled for its + * memslot, etc... Note, zapping shadow pages on this list doesn't + * guarantee an NX huge page will be created in its stead, e.g. if the + * guest attempts to execute from the region then KVM obviously can't + * create an NX huge page (without hanging the guest). + */ + struct list_head pages; + u64 nr_pages; +}; + +enum kvm_mmu_type { + KVM_SHADOW_MMU, +#ifdef CONFIG_X86_64 + KVM_TDP_MMU, +#endif + KVM_NR_MMU_TYPES, +}; + struct kvm_arch { unsigned long n_used_mmu_pages; unsigned long n_requested_mmu_pages; @@ -1360,18 +1384,7 @@ struct kvm_arch { bool pre_fault_allowed; struct hlist_head *mmu_page_hash; struct list_head active_mmu_pages; - /* - * A list of kvm_mmu_page structs that, if zapped, could possibly be - * replaced by an NX huge page. A shadow page is on this list if its - * existence disallows an NX huge page (nx_huge_page_disallowed is set) - * and there are no other conditions that prevent a huge page, e.g. - * the backing host page is huge, dirtly logging is not enabled for its - * memslot, etc... Note, zapping shadow pages on this list doesn't - * guarantee an NX huge page will be created in its stead, e.g. if the - * guest attempts to execute from the region then KVM obviously can't - * create an NX huge page (without hanging the guest). - */ - struct list_head possible_nx_huge_pages; + struct kvm_possible_nx_huge_pages possible_nx_huge_pages[KVM_NR_MMU_TYPES]; #ifdef CONFIG_KVM_EXTERNAL_WRITE_TRACKING struct kvm_page_track_notifier_head track_notifier_head; #endif @@ -1526,7 +1539,7 @@ struct kvm_arch { * is held in read mode: * - tdp_mmu_roots (above) * - the link field of kvm_mmu_page structs used by the TDP MMU - * - possible_nx_huge_pages; + * - possible_nx_huge_pages[KVM_TDP_MMU]; * - the possible_nx_huge_page_link field of kvm_mmu_page structs used * by the TDP MMU * Because the lock is only taken within the MMU lock, strictly diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 6e838cb6c9e1..e0d6579db531 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -776,7 +776,8 @@ static void account_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp) kvm_flush_remote_tlbs_gfn(kvm, gfn, PG_LEVEL_4K); } -void track_possible_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp) +void track_possible_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp, + enum kvm_mmu_type mmu_type) { /* * If it's possible to replace the shadow page with an NX huge page, @@ -790,8 +791,9 @@ void track_possible_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp) return; ++kvm->stat.nx_lpage_splits; + ++kvm->arch.possible_nx_huge_pages[mmu_type].nr_pages; list_add_tail(&sp->possible_nx_huge_page_link, - &kvm->arch.possible_nx_huge_pages); + &kvm->arch.possible_nx_huge_pages[mmu_type].pages); } static void account_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp, @@ -800,7 +802,7 @@ static void account_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp, sp->nx_huge_page_disallowed = true; if (nx_huge_page_possible) - track_possible_nx_huge_page(kvm, sp); + track_possible_nx_huge_page(kvm, sp, KVM_SHADOW_MMU); } static void unaccount_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp) @@ -819,12 +821,14 @@ static void unaccount_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp) kvm_mmu_gfn_allow_lpage(slot, gfn); } -void untrack_possible_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp) +void untrack_possible_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp, + enum kvm_mmu_type mmu_type) { if (list_empty(&sp->possible_nx_huge_page_link)) return; --kvm->stat.nx_lpage_splits; + --kvm->arch.possible_nx_huge_pages[mmu_type].nr_pages; list_del_init(&sp->possible_nx_huge_page_link); } @@ -832,7 +836,7 @@ static void unaccount_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp) { sp->nx_huge_page_disallowed = false; - untrack_possible_nx_huge_page(kvm, sp); + untrack_possible_nx_huge_page(kvm, sp, KVM_SHADOW_MMU); } static struct kvm_memory_slot *gfn_to_memslot_dirty_bitmap(struct kvm_vcpu *vcpu, @@ -6737,11 +6741,12 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm) int kvm_mmu_init_vm(struct kvm *kvm) { - int r; + int r, i; kvm->arch.shadow_mmio_value = shadow_mmio_value; INIT_LIST_HEAD(&kvm->arch.active_mmu_pages); - INIT_LIST_HEAD(&kvm->arch.possible_nx_huge_pages); + for (i = 0; i < KVM_NR_MMU_TYPES; ++i) + INIT_LIST_HEAD(&kvm->arch.possible_nx_huge_pages[i].pages); spin_lock_init(&kvm->arch.mmu_unsync_pages_lock); if (tdp_mmu_enabled) { @@ -7582,16 +7587,32 @@ static int set_nx_huge_pages_recovery_param(const char *val, const struct kernel return err; } -static void kvm_recover_nx_huge_pages(struct kvm *kvm) +static unsigned long nx_huge_pages_to_zap(struct kvm *kvm, + enum kvm_mmu_type mmu_type) { - unsigned long nx_lpage_splits = kvm->stat.nx_lpage_splits; + unsigned long pages = READ_ONCE(kvm->arch.possible_nx_huge_pages[mmu_type].nr_pages); + unsigned int ratio = READ_ONCE(nx_huge_pages_recovery_ratio); + + return ratio ? DIV_ROUND_UP(pages, ratio) : 0; +} + +static void kvm_recover_nx_huge_pages(struct kvm *kvm, + enum kvm_mmu_type mmu_type) +{ +#ifdef CONFIG_X86_64 + const bool is_tdp_mmu = mmu_type == KVM_TDP_MMU; +#else + const bool is_tdp_mmu = false; +#endif + unsigned long to_zap = nx_huge_pages_to_zap(kvm, mmu_type); + struct list_head *nx_huge_pages; struct kvm_memory_slot *slot; - int rcu_idx; struct kvm_mmu_page *sp; - unsigned int ratio; LIST_HEAD(invalid_list); bool flush = false; - ulong to_zap; + int rcu_idx; + + nx_huge_pages = &kvm->arch.possible_nx_huge_pages[mmu_type].pages; rcu_idx = srcu_read_lock(&kvm->srcu); write_lock(&kvm->mmu_lock); @@ -7603,10 +7624,8 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm) */ rcu_read_lock(); - ratio = READ_ONCE(nx_huge_pages_recovery_ratio); - to_zap = ratio ? DIV_ROUND_UP(nx_lpage_splits, ratio) : 0; for ( ; to_zap; --to_zap) { - if (list_empty(&kvm->arch.possible_nx_huge_pages)) + if (list_empty(nx_huge_pages)) break; /* @@ -7616,7 +7635,7 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm) * the total number of shadow pages. And because the TDP MMU * doesn't use active_mmu_pages. */ - sp = list_first_entry(&kvm->arch.possible_nx_huge_pages, + sp = list_first_entry(nx_huge_pages, struct kvm_mmu_page, possible_nx_huge_page_link); WARN_ON_ONCE(!sp->nx_huge_page_disallowed); @@ -7653,7 +7672,7 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm) if (slot && kvm_slot_dirty_track_enabled(slot)) unaccount_nx_huge_page(kvm, sp); - else if (is_tdp_mmu_page(sp)) + else if (is_tdp_mmu) flush |= kvm_tdp_mmu_zap_sp(kvm, sp); else kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list); @@ -7684,9 +7703,10 @@ static void kvm_nx_huge_page_recovery_worker_kill(void *data) static bool kvm_nx_huge_page_recovery_worker(void *data) { struct kvm *kvm = data; + long remaining_time; bool enabled; uint period; - long remaining_time; + int i; enabled = calc_nx_huge_pages_recovery_period(&period); if (!enabled) @@ -7701,7 +7721,8 @@ static bool kvm_nx_huge_page_recovery_worker(void *data) } __set_current_state(TASK_RUNNING); - kvm_recover_nx_huge_pages(kvm); + for (i = 0; i < KVM_NR_MMU_TYPES; ++i) + kvm_recover_nx_huge_pages(kvm, i); kvm->arch.nx_huge_page_last = get_jiffies_64(); return true; } diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index 65f3c89d7c5d..0b772c758f37 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -416,7 +416,9 @@ int kvm_mmu_max_mapping_level(struct kvm *kvm, void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault); void disallowed_hugepage_adjust(struct kvm_page_fault *fault, u64 spte, int cur_level); -void track_possible_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp); -void untrack_possible_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp); +void track_possible_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp, + enum kvm_mmu_type mmu_type); +void untrack_possible_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp, + enum kvm_mmu_type mmu_type); #endif /* __KVM_X86_MMU_INTERNAL_H */ diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 7f3d7229b2c1..48b070f9f4e1 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -355,7 +355,7 @@ static void tdp_mmu_unlink_sp(struct kvm *kvm, struct kvm_mmu_page *sp) spin_lock(&kvm->arch.tdp_mmu_pages_lock); sp->nx_huge_page_disallowed = false; - untrack_possible_nx_huge_page(kvm, sp); + untrack_possible_nx_huge_page(kvm, sp, KVM_TDP_MMU); spin_unlock(&kvm->arch.tdp_mmu_pages_lock); } @@ -1303,7 +1303,7 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) fault->req_level >= iter.level) { spin_lock(&kvm->arch.tdp_mmu_pages_lock); if (sp->nx_huge_page_disallowed) - track_possible_nx_huge_page(kvm, sp); + track_possible_nx_huge_page(kvm, sp, KVM_TDP_MMU); spin_unlock(&kvm->arch.tdp_mmu_pages_lock); } } From 62105564226e5711cc117769ff7874970b126efe Mon Sep 17 00:00:00 2001 From: Vipin Sharma Date: Mon, 7 Jul 2025 22:47:15 +0000 Subject: [PATCH 0333/2711] KVM: x86/mmu: Rename kvm_tdp_mmu_zap_sp() to better indicate its purpose kvm_tdp_mmu_zap_sp() is only used for NX huge page recovery, so rename it to kvm_tdp_mmu_zap_possible_nx_huge_page(). In a future commit, this function will be changed to include logic specific to NX huge page recovery. Signed-off-by: Vipin Sharma Signed-off-by: James Houghton https://lore.kernel.org/r/20250707224720.4016504-3-jthoughton@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/mmu.c | 2 +- arch/x86/kvm/mmu/tdp_mmu.c | 3 ++- arch/x86/kvm/mmu/tdp_mmu.h | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index e0d6579db531..a9aafa88de2b 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -7673,7 +7673,7 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm, if (slot && kvm_slot_dirty_track_enabled(slot)) unaccount_nx_huge_page(kvm, sp); else if (is_tdp_mmu) - flush |= kvm_tdp_mmu_zap_sp(kvm, sp); + flush |= kvm_tdp_mmu_zap_possible_nx_huge_page(kvm, sp); else kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list); WARN_ON_ONCE(sp->nx_huge_page_disallowed); diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 48b070f9f4e1..19907eb04a9c 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -925,7 +925,8 @@ static void tdp_mmu_zap_root(struct kvm *kvm, struct kvm_mmu_page *root, rcu_read_unlock(); } -bool kvm_tdp_mmu_zap_sp(struct kvm *kvm, struct kvm_mmu_page *sp) +bool kvm_tdp_mmu_zap_possible_nx_huge_page(struct kvm *kvm, + struct kvm_mmu_page *sp) { u64 old_spte; diff --git a/arch/x86/kvm/mmu/tdp_mmu.h b/arch/x86/kvm/mmu/tdp_mmu.h index 52acf99d40a0..bd62977c9199 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.h +++ b/arch/x86/kvm/mmu/tdp_mmu.h @@ -64,7 +64,8 @@ static inline struct kvm_mmu_page *tdp_mmu_get_root(struct kvm_vcpu *vcpu, } bool kvm_tdp_mmu_zap_leafs(struct kvm *kvm, gfn_t start, gfn_t end, bool flush); -bool kvm_tdp_mmu_zap_sp(struct kvm *kvm, struct kvm_mmu_page *sp); +bool kvm_tdp_mmu_zap_possible_nx_huge_page(struct kvm *kvm, + struct kvm_mmu_page *sp); void kvm_tdp_mmu_zap_all(struct kvm *kvm); void kvm_tdp_mmu_invalidate_roots(struct kvm *kvm, enum kvm_tdp_mmu_root_types root_types); From a57750909580a4e3f7278ea6c13336677ea46af6 Mon Sep 17 00:00:00 2001 From: Vipin Sharma Date: Mon, 7 Jul 2025 22:47:16 +0000 Subject: [PATCH 0334/2711] KVM: x86/mmu: Recover TDP MMU NX huge pages using MMU read lock Use MMU read lock to recover TDP MMU NX huge pages. To prevent concurrent modification of the list of potential huge pages, iterate over the list under tdp_mmu_pages_lock protection and unaccount the page before dropping the lock. Zapping under MMU read lock unblocks vCPUs which are waiting for MMU read lock, which solves a guest jitter issue on Windows VMs which were observing an increase in network latency. Do not zap an SPTE if: - The SPTE is a root page. - The SPTE does not point at the SP's page table. If the SPTE does not point at the SP's page table, then something else has change the SPTE, so KVM cannot safely zap it. Warn if zapping SPTE fails and current SPTE is still pointing to same page table, as it should be impossible for the CMPXCHG to fail due to all other write scenarios being mutually exclusive. There is always a race between dirty logging, vCPU faults, and NX huge page recovery for backing a gfn by an NX huge page or an executable small page. Unaccounting sooner during the list traversal increases the window of that race, but functionally, it is okay. Accounting doesn't protect against iTLB multi-hit bug, it is there purely to prevent KVM from bouncing a gfn between two page sizes. The only downside is that a vCPU will end up doing more work in tearing down all the child SPTEs. This should be a very rare race. Suggested-by: Sean Christopherson Signed-off-by: Vipin Sharma Co-developed-by: James Houghton Signed-off-by: James Houghton Link: https://lore.kernel.org/r/20250707224720.4016504-4-jthoughton@google.com [sean: clean up kvm_mmu_sp_dirty_logging_enabled() and the changelog] Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/mmu.c | 100 +++++++++++++++++++++++-------------- arch/x86/kvm/mmu/tdp_mmu.c | 42 +++++++++++++--- 2 files changed, 98 insertions(+), 44 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index a9aafa88de2b..92ff15969a36 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -7596,17 +7596,43 @@ static unsigned long nx_huge_pages_to_zap(struct kvm *kvm, return ratio ? DIV_ROUND_UP(pages, ratio) : 0; } +static bool kvm_mmu_sp_dirty_logging_enabled(struct kvm *kvm, + struct kvm_mmu_page *sp) +{ + struct kvm_memory_slot *slot; + + /* + * Skip the memslot lookup if dirty tracking can't possibly be enabled, + * as memslot lookups are relatively expensive. + * + * If a memslot update is in progress, reading an incorrect value of + * kvm->nr_memslots_dirty_logging is not a problem: if it is becoming + * zero, KVM will do an unnecessary memslot lookup; if it is becoming + * nonzero, the page will be zapped unnecessarily. Either way, this + * only affects efficiency in racy situations, and not correctness. + */ + if (!atomic_read(&kvm->nr_memslots_dirty_logging)) + return false; + + slot = __gfn_to_memslot(kvm_memslots_for_spte_role(kvm, sp->role), sp->gfn); + if (WARN_ON_ONCE(!slot)) + return false; + + return kvm_slot_dirty_track_enabled(slot); +} + static void kvm_recover_nx_huge_pages(struct kvm *kvm, - enum kvm_mmu_type mmu_type) + const enum kvm_mmu_type mmu_type) { #ifdef CONFIG_X86_64 const bool is_tdp_mmu = mmu_type == KVM_TDP_MMU; + spinlock_t *tdp_mmu_pages_lock = &kvm->arch.tdp_mmu_pages_lock; #else const bool is_tdp_mmu = false; + spinlock_t *tdp_mmu_pages_lock = NULL; #endif unsigned long to_zap = nx_huge_pages_to_zap(kvm, mmu_type); struct list_head *nx_huge_pages; - struct kvm_memory_slot *slot; struct kvm_mmu_page *sp; LIST_HEAD(invalid_list); bool flush = false; @@ -7615,7 +7641,10 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm, nx_huge_pages = &kvm->arch.possible_nx_huge_pages[mmu_type].pages; rcu_idx = srcu_read_lock(&kvm->srcu); - write_lock(&kvm->mmu_lock); + if (is_tdp_mmu) + read_lock(&kvm->mmu_lock); + else + write_lock(&kvm->mmu_lock); /* * Zapping TDP MMU shadow pages, including the remote TLB flush, must @@ -7625,8 +7654,14 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm, rcu_read_lock(); for ( ; to_zap; --to_zap) { - if (list_empty(nx_huge_pages)) + if (is_tdp_mmu) + spin_lock(tdp_mmu_pages_lock); + + if (list_empty(nx_huge_pages)) { + if (is_tdp_mmu) + spin_unlock(tdp_mmu_pages_lock); break; + } /* * We use a separate list instead of just using active_mmu_pages @@ -7641,50 +7676,38 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm, WARN_ON_ONCE(!sp->nx_huge_page_disallowed); WARN_ON_ONCE(!sp->role.direct); + unaccount_nx_huge_page(kvm, sp); + + if (is_tdp_mmu) + spin_unlock(tdp_mmu_pages_lock); + /* - * Unaccount and do not attempt to recover any NX Huge Pages - * that are being dirty tracked, as they would just be faulted - * back in as 4KiB pages. The NX Huge Pages in this slot will be - * recovered, along with all the other huge pages in the slot, - * when dirty logging is disabled. - * - * Since gfn_to_memslot() is relatively expensive, it helps to - * skip it if it the test cannot possibly return true. On the - * other hand, if any memslot has logging enabled, chances are - * good that all of them do, in which case unaccount_nx_huge_page() - * is much cheaper than zapping the page. - * - * If a memslot update is in progress, reading an incorrect value - * of kvm->nr_memslots_dirty_logging is not a problem: if it is - * becoming zero, gfn_to_memslot() will be done unnecessarily; if - * it is becoming nonzero, the page will be zapped unnecessarily. - * Either way, this only affects efficiency in racy situations, - * and not correctness. + * Do not attempt to recover any NX Huge Pages that are being + * dirty tracked, as they would just be faulted back in as 4KiB + * pages. The NX Huge Pages in this slot will be recovered, + * along with all the other huge pages in the slot, when dirty + * logging is disabled. */ - slot = NULL; - if (atomic_read(&kvm->nr_memslots_dirty_logging)) { - struct kvm_memslots *slots; + if (!kvm_mmu_sp_dirty_logging_enabled(kvm, sp)) { + if (is_tdp_mmu) + flush |= kvm_tdp_mmu_zap_possible_nx_huge_page(kvm, sp); + else + kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list); - slots = kvm_memslots_for_spte_role(kvm, sp->role); - slot = __gfn_to_memslot(slots, sp->gfn); - WARN_ON_ONCE(!slot); } - if (slot && kvm_slot_dirty_track_enabled(slot)) - unaccount_nx_huge_page(kvm, sp); - else if (is_tdp_mmu) - flush |= kvm_tdp_mmu_zap_possible_nx_huge_page(kvm, sp); - else - kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list); WARN_ON_ONCE(sp->nx_huge_page_disallowed); if (need_resched() || rwlock_needbreak(&kvm->mmu_lock)) { kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, flush); rcu_read_unlock(); - cond_resched_rwlock_write(&kvm->mmu_lock); - flush = false; + if (is_tdp_mmu) + cond_resched_rwlock_read(&kvm->mmu_lock); + else + cond_resched_rwlock_write(&kvm->mmu_lock); + flush = false; rcu_read_lock(); } } @@ -7692,7 +7715,10 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm, rcu_read_unlock(); - write_unlock(&kvm->mmu_lock); + if (is_tdp_mmu) + read_unlock(&kvm->mmu_lock); + else + write_unlock(&kvm->mmu_lock); srcu_read_unlock(&kvm->srcu, rcu_idx); } diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 19907eb04a9c..31d921705dee 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -928,21 +928,49 @@ static void tdp_mmu_zap_root(struct kvm *kvm, struct kvm_mmu_page *root, bool kvm_tdp_mmu_zap_possible_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp) { - u64 old_spte; + struct tdp_iter iter = { + .old_spte = sp->ptep ? kvm_tdp_mmu_read_spte(sp->ptep) : 0, + .sptep = sp->ptep, + .level = sp->role.level + 1, + .gfn = sp->gfn, + .as_id = kvm_mmu_page_as_id(sp), + }; + + lockdep_assert_held_read(&kvm->mmu_lock); + + if (WARN_ON_ONCE(!is_tdp_mmu_page(sp))) + return false; /* - * This helper intentionally doesn't allow zapping a root shadow page, - * which doesn't have a parent page table and thus no associated entry. + * Root shadow pages don't have a parent page table and thus no + * associated entry, but they can never be possible NX huge pages. */ if (WARN_ON_ONCE(!sp->ptep)) return false; - old_spte = kvm_tdp_mmu_read_spte(sp->ptep); - if (WARN_ON_ONCE(!is_shadow_present_pte(old_spte))) + /* + * Since mmu_lock is held in read mode, it's possible another task has + * already modified the SPTE. Zap the SPTE if and only if the SPTE + * points at the SP's page table, as checking shadow-present isn't + * sufficient, e.g. the SPTE could be replaced by a leaf SPTE, or even + * another SP. Note, spte_to_child_pt() also checks that the SPTE is + * shadow-present, i.e. guards against zapping a frozen SPTE. + */ + if ((tdp_ptep_t)sp->spt != spte_to_child_pt(iter.old_spte, iter.level)) return false; - tdp_mmu_set_spte(kvm, kvm_mmu_page_as_id(sp), sp->ptep, old_spte, - SHADOW_NONPRESENT_VALUE, sp->gfn, sp->role.level + 1); + /* + * If a different task modified the SPTE, then it should be impossible + * for the SPTE to still be used for the to-be-zapped SP. Non-leaf + * SPTEs don't have Dirty bits, KVM always sets the Accessed bit when + * creating non-leaf SPTEs, and all other bits are immutable for non- + * leaf SPTEs, i.e. the only legal operations for non-leaf SPTEs are + * zapping and replacement. + */ + if (tdp_mmu_set_spte_atomic(kvm, &iter, SHADOW_NONPRESENT_VALUE)) { + WARN_ON_ONCE((tdp_ptep_t)sp->spt == spte_to_child_pt(iter.old_spte, iter.level)); + return false; + } return true; } From a585b87614511e4272305bb5acf406f19f7dcade Mon Sep 17 00:00:00 2001 From: James Houghton Date: Fri, 11 Jul 2025 00:17:42 +0000 Subject: [PATCH 0335/2711] KVM: selftests: Fix signedness issue with vCPU mmap size check Check that the return value of KVM_GET_VCPU_MMAP_SIZE is non-negative before comparing with sizeof(kvm_run). If KVM_GET_VCPU_MMAP_SIZE fails, it will return -1, and `-1 > sizeof(kvm_run)` is true, so the ASSERT passes. There are no other locations in tools/testing/selftests/kvm that make the same mistake. Signed-off-by: James Houghton Link: https://lore.kernel.org/r/20250711001742.1965347-1-jthoughton@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/lib/kvm_util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index c3f5142b0a54..40e18034ac23 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -24,7 +24,7 @@ uint32_t guest_random_seed; struct guest_random_state guest_rng; static uint32_t last_guest_seed; -static int vcpu_mmap_sz(void); +static size_t vcpu_mmap_sz(void); int __open_path_or_exit(const char *path, int flags, const char *enoent_help) { @@ -1321,14 +1321,14 @@ void vm_guest_mem_fallocate(struct kvm_vm *vm, uint64_t base, uint64_t size, } /* Returns the size of a vCPU's kvm_run structure. */ -static int vcpu_mmap_sz(void) +static size_t vcpu_mmap_sz(void) { int dev_fd, ret; dev_fd = open_kvm_dev_path_or_exit(); ret = ioctl(dev_fd, KVM_GET_VCPU_MMAP_SIZE, NULL); - TEST_ASSERT(ret >= sizeof(struct kvm_run), + TEST_ASSERT(ret >= 0 && ret >= sizeof(struct kvm_run), KVM_IOCTL_ERROR(KVM_GET_VCPU_MMAP_SIZE, ret)); close(dev_fd); @@ -1369,7 +1369,7 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) TEST_ASSERT_VM_VCPU_IOCTL(vcpu->fd >= 0, KVM_CREATE_VCPU, vcpu->fd, vm); TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->run), "vcpu mmap size " - "smaller than expected, vcpu_mmap_sz: %i expected_min: %zi", + "smaller than expected, vcpu_mmap_sz: %zi expected_min: %zi", vcpu_mmap_sz(), sizeof(*vcpu->run)); vcpu->run = (struct kvm_run *) mmap(NULL, vcpu_mmap_sz(), PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, 0); From e2bcf62a2e78f8d7e95485c0347bccfba3c5e459 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 6 Aug 2025 15:51:59 -0700 Subject: [PATCH 0336/2711] KVM: selftests: Move Intel and AMD module param helpers to x86/processor.h Move the x86 specific helpers for getting kvm_{amd,intel} module params to x86 where they belong. Expose the module-agnostic helpers globally, there is nothing secret about the logic. Link: https://lore.kernel.org/r/20250806225159.1687326-1-seanjc@google.com Signed-off-by: Sean Christopherson --- .../testing/selftests/kvm/include/kvm_util.h | 17 ++++++---- .../selftests/kvm/include/x86/processor.h | 20 +++++++++++ tools/testing/selftests/kvm/lib/kvm_util.c | 34 ++----------------- 3 files changed, 33 insertions(+), 38 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 23a506d7eca3..652ac01e1adc 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -260,13 +260,18 @@ int __open_path_or_exit(const char *path, int flags, const char *enoent_help); int open_path_or_exit(const char *path, int flags); int open_kvm_dev_path_or_exit(void); -bool get_kvm_param_bool(const char *param); -bool get_kvm_intel_param_bool(const char *param); -bool get_kvm_amd_param_bool(const char *param); +int kvm_get_module_param_integer(const char *module_name, const char *param); +bool kvm_get_module_param_bool(const char *module_name, const char *param); -int get_kvm_param_integer(const char *param); -int get_kvm_intel_param_integer(const char *param); -int get_kvm_amd_param_integer(const char *param); +static inline bool get_kvm_param_bool(const char *param) +{ + return kvm_get_module_param_bool("kvm", param); +} + +static inline int get_kvm_param_integer(const char *param) +{ + return kvm_get_module_param_integer("kvm", param); +} unsigned int kvm_check_cap(long cap); diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h index 2efb05c2f2fb..488d516c4f6f 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -1314,6 +1314,26 @@ static inline uint8_t xsetbv_safe(uint32_t index, uint64_t value) bool kvm_is_tdp_enabled(void); +static inline bool get_kvm_intel_param_bool(const char *param) +{ + return kvm_get_module_param_bool("kvm_intel", param); +} + +static inline bool get_kvm_amd_param_bool(const char *param) +{ + return kvm_get_module_param_bool("kvm_amd", param); +} + +static inline int get_kvm_intel_param_integer(const char *param) +{ + return kvm_get_module_param_integer("kvm_intel", param); +} + +static inline int get_kvm_amd_param_integer(const char *param) +{ + return kvm_get_module_param_integer("kvm_amd", param); +} + static inline bool kvm_is_pmu_enabled(void) { return get_kvm_param_bool("enable_pmu"); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 40e18034ac23..98cb8073c82b 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -95,7 +95,7 @@ static ssize_t get_module_param(const char *module_name, const char *param, return bytes_read; } -static int get_module_param_integer(const char *module_name, const char *param) +int kvm_get_module_param_integer(const char *module_name, const char *param) { /* * 16 bytes to hold a 64-bit value (1 byte per char), 1 byte for the @@ -119,7 +119,7 @@ static int get_module_param_integer(const char *module_name, const char *param) return atoi_paranoid(value); } -static bool get_module_param_bool(const char *module_name, const char *param) +bool kvm_get_module_param_bool(const char *module_name, const char *param) { char value; ssize_t r; @@ -135,36 +135,6 @@ static bool get_module_param_bool(const char *module_name, const char *param) TEST_FAIL("Unrecognized value '%c' for boolean module param", value); } -bool get_kvm_param_bool(const char *param) -{ - return get_module_param_bool("kvm", param); -} - -bool get_kvm_intel_param_bool(const char *param) -{ - return get_module_param_bool("kvm_intel", param); -} - -bool get_kvm_amd_param_bool(const char *param) -{ - return get_module_param_bool("kvm_amd", param); -} - -int get_kvm_param_integer(const char *param) -{ - return get_module_param_integer("kvm", param); -} - -int get_kvm_intel_param_integer(const char *param) -{ - return get_module_param_integer("kvm_intel", param); -} - -int get_kvm_amd_param_integer(const char *param) -{ - return get_module_param_integer("kvm_amd", param); -} - /* * Capability * From 05f297c3e39f62f579458a59ab1b1c8bf3fc1c51 Mon Sep 17 00:00:00 2001 From: Gopi Krishna Menon Date: Wed, 13 Aug 2025 21:17:51 +0530 Subject: [PATCH 0337/2711] KVM: selftests: fix minor typo in cpumodel_subfuncs Specifically, fix spelling of "available" in main function. Signed-off-by: Gopi Krishna Menon Link: https://lore.kernel.org/r/20250813154751.5725-1-krishnagopi487@gmail.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/s390/cpumodel_subfuncs_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/s390/cpumodel_subfuncs_test.c b/tools/testing/selftests/kvm/s390/cpumodel_subfuncs_test.c index 27255880dabd..aded795d42be 100644 --- a/tools/testing/selftests/kvm/s390/cpumodel_subfuncs_test.c +++ b/tools/testing/selftests/kvm/s390/cpumodel_subfuncs_test.c @@ -291,7 +291,7 @@ int main(int argc, char *argv[]) ksft_test_result_pass("%s\n", testlist[idx].subfunc_name); free(array); } else { - ksft_test_result_skip("%s feature is not avaialable\n", + ksft_test_result_skip("%s feature is not available\n", testlist[idx].subfunc_name); } } From e750f85391286a4c8100275516973324b621a269 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Jul 2025 12:06:38 -0700 Subject: [PATCH 0338/2711] KVM: x86: Don't (re)check L1 intercepts when completing userspace I/O When completing emulation of instruction that generated a userspace exit for I/O, don't recheck L1 intercepts as KVM has already finished that phase of instruction execution, i.e. has already committed to allowing L2 to perform I/O. If L1 (or host userspace) modifies the I/O permission bitmaps during the exit to userspace, KVM will treat the access as being intercepted despite already having emulated the I/O access. Pivot on EMULTYPE_NO_DECODE to detect that KVM is completing emulation. Of the three users of EMULTYPE_NO_DECODE, only complete_emulated_io() (the intended "recipient") can reach the code in question. gp_interception()'s use is mutually exclusive with is_guest_mode(), and complete_emulated_insn_gp() unconditionally pairs EMULTYPE_NO_DECODE with EMULTYPE_SKIP. The bad behavior was detected by a syzkaller program that toggles port I/O interception during the userspace I/O exit, ultimately resulting in a WARN on vcpu->arch.pio.count being non-zero due to KVM no completing emulation of the I/O instruction. WARNING: CPU: 23 PID: 1083 at arch/x86/kvm/x86.c:8039 emulator_pio_in_out+0x154/0x170 [kvm] Modules linked in: kvm_intel kvm irqbypass CPU: 23 UID: 1000 PID: 1083 Comm: repro Not tainted 6.16.0-rc5-c1610d2d66b1-next-vm #74 NONE Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:emulator_pio_in_out+0x154/0x170 [kvm] PKRU: 55555554 Call Trace: kvm_fast_pio+0xd6/0x1d0 [kvm] vmx_handle_exit+0x149/0x610 [kvm_intel] kvm_arch_vcpu_ioctl_run+0xda8/0x1ac0 [kvm] kvm_vcpu_ioctl+0x244/0x8c0 [kvm] __x64_sys_ioctl+0x8a/0xd0 do_syscall_64+0x5d/0xc60 entry_SYSCALL_64_after_hwframe+0x4b/0x53 Reported-by: syzbot+cc2032ba16cc2018ca25@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/68790db4.a00a0220.3af5df.0020.GAE@google.com Fixes: 8a76d7f25f8f ("KVM: x86: Add x86 callback for intercept check") Cc: stable@vger.kernel.org Cc: Jim Mattson Link: https://lore.kernel.org/r/20250715190638.1899116-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/emulate.c | 9 ++++----- arch/x86/kvm/kvm_emulate.h | 3 +-- arch/x86/kvm/x86.c | 15 ++++++++------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 1349e278cd2a..542d3664afa3 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -5107,12 +5107,11 @@ void init_decode_cache(struct x86_emulate_ctxt *ctxt) ctxt->mem_read.end = 0; } -int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) +int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, bool check_intercepts) { const struct x86_emulate_ops *ops = ctxt->ops; int rc = X86EMUL_CONTINUE; int saved_dst_type = ctxt->dst.type; - bool is_guest_mode = ctxt->ops->is_guest_mode(ctxt); ctxt->mem_read.pos = 0; @@ -5160,7 +5159,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) fetch_possible_mmx_operand(&ctxt->dst); } - if (unlikely(is_guest_mode) && ctxt->intercept) { + if (unlikely(check_intercepts) && ctxt->intercept) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_PRE_EXCEPT); if (rc != X86EMUL_CONTINUE) @@ -5189,7 +5188,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } - if (unlikely(is_guest_mode) && (ctxt->d & Intercept)) { + if (unlikely(check_intercepts) && (ctxt->d & Intercept)) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_POST_EXCEPT); if (rc != X86EMUL_CONTINUE) @@ -5243,7 +5242,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) special_insn: - if (unlikely(is_guest_mode) && (ctxt->d & Intercept)) { + if (unlikely(check_intercepts) && (ctxt->d & Intercept)) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_POST_MEMACCESS); if (rc != X86EMUL_CONTINUE) diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index c1df5acfacaf..7b5ddb787a25 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -235,7 +235,6 @@ struct x86_emulate_ops { void (*set_nmi_mask)(struct x86_emulate_ctxt *ctxt, bool masked); bool (*is_smm)(struct x86_emulate_ctxt *ctxt); - bool (*is_guest_mode)(struct x86_emulate_ctxt *ctxt); int (*leave_smm)(struct x86_emulate_ctxt *ctxt); void (*triple_fault)(struct x86_emulate_ctxt *ctxt); int (*set_xcr)(struct x86_emulate_ctxt *ctxt, u32 index, u64 xcr); @@ -521,7 +520,7 @@ bool x86_page_table_writing_insn(struct x86_emulate_ctxt *ctxt); #define EMULATION_RESTART 1 #define EMULATION_INTERCEPTED 2 void init_decode_cache(struct x86_emulate_ctxt *ctxt); -int x86_emulate_insn(struct x86_emulate_ctxt *ctxt); +int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, bool check_intercepts); int emulator_task_switch(struct x86_emulate_ctxt *ctxt, u16 tss_selector, int idt_index, int reason, bool has_error_code, u32 error_code); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a1c49bc681c4..79057622fa76 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8470,11 +8470,6 @@ static bool emulator_is_smm(struct x86_emulate_ctxt *ctxt) return is_smm(emul_to_vcpu(ctxt)); } -static bool emulator_is_guest_mode(struct x86_emulate_ctxt *ctxt) -{ - return is_guest_mode(emul_to_vcpu(ctxt)); -} - #ifndef CONFIG_KVM_SMM static int emulator_leave_smm(struct x86_emulate_ctxt *ctxt) { @@ -8558,7 +8553,6 @@ static const struct x86_emulate_ops emulate_ops = { .guest_cpuid_is_intel_compatible = emulator_guest_cpuid_is_intel_compatible, .set_nmi_mask = emulator_set_nmi_mask, .is_smm = emulator_is_smm, - .is_guest_mode = emulator_is_guest_mode, .leave_smm = emulator_leave_smm, .triple_fault = emulator_triple_fault, .set_xcr = emulator_set_xcr, @@ -9143,7 +9137,14 @@ restart: ctxt->exception.address = 0; } - r = x86_emulate_insn(ctxt); + /* + * Check L1's instruction intercepts when emulating instructions for + * L2, unless KVM is re-emulating a previously decoded instruction, + * e.g. to complete userspace I/O, in which case KVM has already + * checked the intercepts. + */ + r = x86_emulate_insn(ctxt, is_guest_mode(vcpu) && + !(emulation_type & EMULTYPE_NO_DECODE)); if (r == EMULATION_INTERCEPTED) return 1; From a1f2418c3eea05a2a11ec76a1913e9e8e77039ff Mon Sep 17 00:00:00 2001 From: Xin Li Date: Mon, 14 Jul 2025 18:25:17 -0700 Subject: [PATCH 0339/2711] KVM: VMX: Fix an indentation Fix an indentation by replacing 8 spaces with a tab. While at it, add empty lines before and after for better readability. Signed-off-by: Xin Li (Intel) Link: https://lore.kernel.org/r/20250715012517.694429-1-xin@zytor.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index aa157fe5b7b3..92fe8d200335 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8525,7 +8525,9 @@ __init int vmx_hardware_setup(void) */ if (!static_cpu_has(X86_FEATURE_SELFSNOOP)) kvm_caps.supported_quirks &= ~KVM_X86_QUIRK_IGNORE_GUEST_PAT; - kvm_caps.inapplicable_quirks &= ~KVM_X86_QUIRK_IGNORE_GUEST_PAT; + + kvm_caps.inapplicable_quirks &= ~KVM_X86_QUIRK_IGNORE_GUEST_PAT; + return r; } From 65391feb042b2b2cfc4263d64d41a66ef4a7e03e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 26 Jun 2025 10:16:01 -0700 Subject: [PATCH 0340/2711] KVM: VMX: Add host MSR read/write helpers to consolidate preemption handling Add host MSR read/write helpers to consolidate preemption handling to prepare for adding FRED RSP0 access functions without duplicating the preemption handling code. Signed-off-by: Xin Li (Intel) Link: https://lore.kernel.org/r/20250626171601.2293914-1-xin@zytor.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 92fe8d200335..6ed6c9e97577 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -1344,22 +1344,35 @@ static void vmx_prepare_switch_to_host(struct vcpu_vmx *vmx) } #ifdef CONFIG_X86_64 -static u64 vmx_read_guest_kernel_gs_base(struct vcpu_vmx *vmx) +static u64 vmx_read_guest_host_msr(struct vcpu_vmx *vmx, u32 msr, u64 *cache) { preempt_disable(); if (vmx->vt.guest_state_loaded) - rdmsrq(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); + *cache = read_msr(msr); preempt_enable(); - return vmx->msr_guest_kernel_gs_base; + return *cache; +} + +static void vmx_write_guest_host_msr(struct vcpu_vmx *vmx, u32 msr, u64 data, + u64 *cache) +{ + preempt_disable(); + if (vmx->vt.guest_state_loaded) + wrmsrns(msr, data); + preempt_enable(); + *cache = data; +} + +static u64 vmx_read_guest_kernel_gs_base(struct vcpu_vmx *vmx) +{ + return vmx_read_guest_host_msr(vmx, MSR_KERNEL_GS_BASE, + &vmx->msr_guest_kernel_gs_base); } static void vmx_write_guest_kernel_gs_base(struct vcpu_vmx *vmx, u64 data) { - preempt_disable(); - if (vmx->vt.guest_state_loaded) - wrmsrq(MSR_KERNEL_GS_BASE, data); - preempt_enable(); - vmx->msr_guest_kernel_gs_base = data; + vmx_write_guest_host_msr(vmx, MSR_KERNEL_GS_BASE, data, + &vmx->msr_guest_kernel_gs_base); } #endif From cf6a8401b6a12c3bdd54c7414af28625ec6450da Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 7 Aug 2025 22:49:43 +0800 Subject: [PATCH 0341/2711] KVM: remove redundant __GFP_NOWARN Commit 16f5dfbc851b ("gfp: include __GFP_NOWARN in GFP_NOWAIT") made GFP_NOWAIT implicitly include __GFP_NOWARN. Therefore, explicit __GFP_NOWARN combined with GFP_NOWAIT (e.g., `GFP_NOWAIT | __GFP_NOWARN`) is now redundant. Let's clean up these redundant flags across subsystems. Signed-off-by: Qianfeng Rong Link: https://lore.kernel.org/r/20250807144943.581663-1-rongqianfeng@vivo.com Signed-off-by: Sean Christopherson --- virt/kvm/async_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 0ee4816b079a..b8aaa96b799b 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -192,7 +192,7 @@ bool kvm_setup_async_pf(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, * do alloc nowait since if we are going to sleep anyway we * may as well sleep faulting in page */ - work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT | __GFP_NOWARN); + work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT); if (!work) return false; From 7cbb14d361bd562fd6e2b3a96c13d5567fd3067a Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Fri, 8 Aug 2025 15:45:32 +0800 Subject: [PATCH 0342/2711] KVM: TDX: Remove redundant __GFP_ZERO Remove the redundant __GFP_ZERO flag from kcalloc() since kcalloc() inherently zeroes memory. Signed-off-by: Qianfeng Rong Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20250808074532.215098-1-rongqianfeng@vivo.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/tdx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 66744f5768c8..6784aaaced87 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -2480,7 +2480,7 @@ static int __tdx_td_init(struct kvm *kvm, struct td_params *td_params, /* TDVPS = TDVPR(4K page) + TDCX(multiple 4K pages), -1 for TDVPR. */ kvm_tdx->td.tdcx_nr_pages = tdx_sysinfo->td_ctrl.tdvps_base_size / PAGE_SIZE - 1; tdcs_pages = kcalloc(kvm_tdx->td.tdcs_nr_pages, sizeof(*kvm_tdx->td.tdcs_pages), - GFP_KERNEL | __GFP_ZERO); + GFP_KERNEL); if (!tdcs_pages) goto free_tdr; From 68e61f6fd65610e73b17882f86fedfd784d99229 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 11 Jul 2025 10:27:46 -0700 Subject: [PATCH 0343/2711] KVM: SVM: Emulate PERF_CNTR_GLOBAL_STATUS_SET for PerfMonV2 Emulate PERF_CNTR_GLOBAL_STATUS_SET when PerfMonV2 is enumerated to the guest, as the MSR is supposed to exist in all AMD v2 PMUs. Fixes: 4a2771895ca6 ("KVM: x86/svm/pmu: Add AMD PerfMonV2 support") Cc: stable@vger.kernel.org Cc: Sandipan Das Link: https://lore.kernel.org/r/20250711172746.1579423-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/msr-index.h | 1 + arch/x86/kvm/pmu.c | 5 +++++ arch/x86/kvm/svm/pmu.c | 1 + arch/x86/kvm/x86.c | 2 ++ 4 files changed, 9 insertions(+) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index b65c3ba5fa14..20fa4a79df13 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -733,6 +733,7 @@ #define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS 0xc0000300 #define MSR_AMD64_PERF_CNTR_GLOBAL_CTL 0xc0000301 #define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR 0xc0000302 +#define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_SET 0xc0000303 /* AMD Hardware Feedback Support MSRs */ #define MSR_AMD_WORKLOAD_CLASS_CONFIG 0xc0000500 diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 75e9cfc689f8..a84fb3d28885 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -650,6 +650,7 @@ int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = pmu->global_ctrl; break; case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR: + case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_SET: case MSR_CORE_PERF_GLOBAL_OVF_CTRL: msr_info->data = 0; break; @@ -711,6 +712,10 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (!msr_info->host_initiated) pmu->global_status &= ~data; break; + case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_SET: + if (!msr_info->host_initiated) + pmu->global_status |= data & ~pmu->global_status_rsvd; + break; default: kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index); return kvm_pmu_call(set_msr)(vcpu, msr_info); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 288f7f2a46f2..aa4379e46e96 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -113,6 +113,7 @@ static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS: case MSR_AMD64_PERF_CNTR_GLOBAL_CTL: case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR: + case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_SET: return pmu->version > 1; default: if (msr > MSR_F15H_PERF_CTR5 && diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 79057622fa76..5dc32f2fe391 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -367,6 +367,7 @@ static const u32 msrs_to_save_pmu[] = { MSR_AMD64_PERF_CNTR_GLOBAL_CTL, MSR_AMD64_PERF_CNTR_GLOBAL_STATUS, MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR, + MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_SET, }; static u32 msrs_to_save[ARRAY_SIZE(msrs_to_save_base) + @@ -7353,6 +7354,7 @@ static void kvm_probe_msr_to_save(u32 msr_index) case MSR_AMD64_PERF_CNTR_GLOBAL_CTL: case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS: case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR: + case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_SET: if (!kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2)) return; break; From 0910dd7c9ad45a2605c45fd2bf3d1bcac087687c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:09 -0700 Subject: [PATCH 0344/2711] KVM: SVM: Skip fastpath emulation on VM-Exit if next RIP isn't valid Skip the WRMSR and HLT fastpaths in SVM's VM-Exit handler if the next RIP isn't valid, e.g. because KVM is running with nrips=false. SVM must decode and emulate to skip the instruction if the CPU doesn't provide the next RIP, and getting the instruction bytes to decode requires reading guest memory. Reading guest memory through the emulator can fault, i.e. can sleep, which is disallowed since the fastpath handlers run with IRQs disabled. BUG: sleeping function called from invalid context at ./include/linux/uaccess.h:106 in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 32611, name: qemu preempt_count: 1, expected: 0 INFO: lockdep is turned off. irq event stamp: 30580 hardirqs last enabled at (30579): [] vcpu_run+0x1787/0x1db0 [kvm] hardirqs last disabled at (30580): [] __schedule+0x1e2/0xed0 softirqs last enabled at (30570): [] fpu_swap_kvm_fpstate+0x44/0x210 softirqs last disabled at (30568): [] fpu_swap_kvm_fpstate+0x44/0x210 CPU: 298 UID: 0 PID: 32611 Comm: qemu Tainted: G U 6.16.0-smp--e6c618b51cfe-sleep #782 NONE Tainted: [U]=USER Hardware name: Google Astoria-Turin/astoria, BIOS 0.20241223.2-0 01/17/2025 Call Trace: dump_stack_lvl+0x7d/0xb0 __might_resched+0x271/0x290 __might_fault+0x28/0x80 kvm_vcpu_read_guest_page+0x8d/0xc0 [kvm] kvm_fetch_guest_virt+0x92/0xc0 [kvm] __do_insn_fetch_bytes+0xf3/0x1e0 [kvm] x86_decode_insn+0xd1/0x1010 [kvm] x86_emulate_instruction+0x105/0x810 [kvm] __svm_skip_emulated_instruction+0xc4/0x140 [kvm_amd] handle_fastpath_invd+0xc4/0x1a0 [kvm] vcpu_run+0x11a1/0x1db0 [kvm] kvm_arch_vcpu_ioctl_run+0x5cc/0x730 [kvm] kvm_vcpu_ioctl+0x578/0x6a0 [kvm] __se_sys_ioctl+0x6d/0xb0 do_syscall_64+0x8a/0x2c0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x7f479d57a94b Note, this is essentially a reapply of commit 5c30e8101e8d ("KVM: SVM: Skip WRMSR fastpath on VM-Exit if next RIP isn't valid"), but with different justification (KVM now grabs SRCU when skipping the instruction for other reasons). Fixes: b439eb8ab578 ("Revert "KVM: SVM: Skip WRMSR fastpath on VM-Exit if next RIP isn't valid"") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250805190526.1453366-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index d9931c6c4bc6..829d9d46718d 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4181,13 +4181,21 @@ static int svm_vcpu_pre_run(struct kvm_vcpu *vcpu) static fastpath_t svm_exit_handlers_fastpath(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); + struct vmcb_control_area *control = &svm->vmcb->control; + + /* + * Next RIP must be provided as IRQs are disabled, and accessing guest + * memory to decode the instruction might fault, i.e. might sleep. + */ + if (!nrips || !control->next_rip) + return EXIT_FASTPATH_NONE; if (is_guest_mode(vcpu)) return EXIT_FASTPATH_NONE; - switch (svm->vmcb->control.exit_code) { + switch (control->exit_code) { case SVM_EXIT_MSR: - if (!svm->vmcb->control.exit_info_1) + if (!control->exit_info_1) break; return handle_fastpath_set_msr_irqoff(vcpu); case SVM_EXIT_HLT: From 49be82d4ad2ea3329c77b9e6010507baf1c66134 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 28 Jul 2025 17:28:43 +0200 Subject: [PATCH 0345/2711] arch/x86/kvm/ioapic: Remove license boilerplate with bad FSF address The Free Software Foundation does not reside in "59 Temple Place" anymore, so we should not mention that address in the source code here. But instead of updating the address to their current location, let's rather drop the license boilerplate text here and use a proper SPDX license identifier instead. The text talks about the "GNU *Lesser* General Public License" and "any later version", so LGPL-2.1+ is the right choice here. Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20250728152843.310260-1-thuth@redhat.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/ioapic.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 2b5d389bca5f..2c2783296aed 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later /* * Copyright (C) 2001 MandrakeSoft S.A. * Copyright 2010 Red Hat, Inc. and/or its affiliates. @@ -8,20 +9,6 @@ * http://www.linux-mandrake.com/ * http://www.mandrakesoft.com/ * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * * Yunhong Jiang * Yaozu (Eddie) Dong * Based on Xen 3.1 code. From 1f0654dc75b8b4945988f802e4e532ff722ecce7 Mon Sep 17 00:00:00 2001 From: Ewan Hai Date: Mon, 18 Aug 2025 04:30:34 -0400 Subject: [PATCH 0346/2711] KVM: x86: allow CPUID 0xC000_0000 to proceed on Zhaoxin CPUs Bypass the Centaur-only filter for the CPUID signature leaf so that processing continues when the CPU vendor is Zhaoxin. Signed-off-by: Ewan Hai Link: https://lore.kernel.org/r/20250818083034.93935-1-ewanhai-oc@zhaoxin.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/cpuid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index e2836a255b16..bee8c869259f 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -1820,7 +1820,8 @@ static int get_cpuid_func(struct kvm_cpuid_array *array, u32 func, int r; if (func == CENTAUR_CPUID_SIGNATURE && - boot_cpu_data.x86_vendor != X86_VENDOR_CENTAUR) + boot_cpu_data.x86_vendor != X86_VENDOR_CENTAUR && + boot_cpu_data.x86_vendor != X86_VENDOR_ZHAOXIN) return 0; r = do_cpuid_func(array, func, type); From cc63f918a215a24a72992295566cab5f8f89b08e Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Sat, 19 Jul 2025 21:58:45 -0400 Subject: [PATCH 0347/2711] kvm: x86: simplify kvm_vector_to_index() Use find_nth_bit() and make the function almost a one-liner. Signed-off-by: Yury Norov Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 8172c2042dd6..5bfa6ec324af 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1064,16 +1064,9 @@ EXPORT_SYMBOL_GPL(kvm_apic_match_dest); int kvm_vector_to_index(u32 vector, u32 dest_vcpus, const unsigned long *bitmap, u32 bitmap_size) { - u32 mod; - int i, idx = -1; - - mod = vector % dest_vcpus; - - for (i = 0; i <= mod; i++) { - idx = find_next_bit(bitmap, bitmap_size, idx + 1); - BUG_ON(idx == bitmap_size); - } + int idx = find_nth_bit(bitmap, bitmap_size, vector % dest_vcpus); + BUG_ON(idx >= bitmap_size); return idx; } From 15daa58e78cef70945324db162d1afbf3f493fb6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:10 -0700 Subject: [PATCH 0348/2711] KVM: x86: Add kvm_icr_to_lapic_irq() helper to allow for fastpath IPIs Extract the code for converting an ICR message into a kvm_lapic_irq structure into a local helper so that a fast-only IPI path can share the conversion logic. No functional change intended. Link: https://lore.kernel.org/r/20250805190526.1453366-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 5bfa6ec324af..68fda104195c 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1474,24 +1474,30 @@ void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector) } EXPORT_SYMBOL_GPL(kvm_apic_set_eoi_accelerated); +static void kvm_icr_to_lapic_irq(struct kvm_lapic *apic, u32 icr_low, + u32 icr_high, struct kvm_lapic_irq *irq) +{ + /* KVM has no delay and should always clear the BUSY/PENDING flag. */ + WARN_ON_ONCE(icr_low & APIC_ICR_BUSY); + + irq->vector = icr_low & APIC_VECTOR_MASK; + irq->delivery_mode = icr_low & APIC_MODE_MASK; + irq->dest_mode = icr_low & APIC_DEST_MASK; + irq->level = (icr_low & APIC_INT_ASSERT) != 0; + irq->trig_mode = icr_low & APIC_INT_LEVELTRIG; + irq->shorthand = icr_low & APIC_SHORT_MASK; + irq->msi_redir_hint = false; + if (apic_x2apic_mode(apic)) + irq->dest_id = icr_high; + else + irq->dest_id = GET_XAPIC_DEST_FIELD(icr_high); +} + void kvm_apic_send_ipi(struct kvm_lapic *apic, u32 icr_low, u32 icr_high) { struct kvm_lapic_irq irq; - /* KVM has no delay and should always clear the BUSY/PENDING flag. */ - WARN_ON_ONCE(icr_low & APIC_ICR_BUSY); - - irq.vector = icr_low & APIC_VECTOR_MASK; - irq.delivery_mode = icr_low & APIC_MODE_MASK; - irq.dest_mode = icr_low & APIC_DEST_MASK; - irq.level = (icr_low & APIC_INT_ASSERT) != 0; - irq.trig_mode = icr_low & APIC_INT_LEVELTRIG; - irq.shorthand = icr_low & APIC_SHORT_MASK; - irq.msi_redir_hint = false; - if (apic_x2apic_mode(apic)) - irq.dest_id = icr_high; - else - irq.dest_id = GET_XAPIC_DEST_FIELD(icr_high); + kvm_icr_to_lapic_irq(apic, icr_low, icr_high, &irq); trace_kvm_apic_ipi(icr_low, irq.dest_id); From 777414340085711cafd3807a72c531107c0ff7f6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:11 -0700 Subject: [PATCH 0349/2711] KVM: x86: Only allow "fast" IPIs in fastpath WRMSR(X2APIC_ICR) handler Explicitly restrict fastpath ICR writes to IPIs that are "fast", i.e. can be delivered without having to walk all vCPUs, and that target at most 16 vCPUs. Artificially restricting ICR writes to physical mode guarantees at most one vCPU will receive in IPI (because x2APIC IDs are read-only), but that delivery might not be "fast". E.g. even if the vCPU exists, KVM might have to iterate over 4096 vCPUs to find the right one. Limiting delivery to fast IPIs aligns the WRMSR fastpath with kvm_arch_set_irq_inatomic() (which also runs with IRQs disabled), and will allow dropping the semi-arbitrary restrictions on delivery mode and type. Link: https://lore.kernel.org/r/20250805190526.1453366-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 27 +++++++++++++++++++++++++-- arch/x86/kvm/lapic.h | 2 +- arch/x86/kvm/x86.c | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 68fda104195c..252e77c88ae2 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2432,7 +2432,7 @@ EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); #define X2APIC_ICR_RESERVED_BITS (GENMASK_ULL(31, 20) | GENMASK_ULL(17, 16) | BIT(13)) -int kvm_x2apic_icr_write(struct kvm_lapic *apic, u64 data) +static int __kvm_x2apic_icr_write(struct kvm_lapic *apic, u64 data, bool fast) { if (data & X2APIC_ICR_RESERVED_BITS) return 1; @@ -2447,7 +2447,20 @@ int kvm_x2apic_icr_write(struct kvm_lapic *apic, u64 data) */ data &= ~APIC_ICR_BUSY; - kvm_apic_send_ipi(apic, (u32)data, (u32)(data >> 32)); + if (fast) { + struct kvm_lapic_irq irq; + int ignored; + + kvm_icr_to_lapic_irq(apic, (u32)data, (u32)(data >> 32), &irq); + + if (!kvm_irq_delivery_to_apic_fast(apic->vcpu->kvm, apic, &irq, + &ignored, NULL)) + return -EWOULDBLOCK; + + trace_kvm_apic_ipi((u32)data, irq.dest_id); + } else { + kvm_apic_send_ipi(apic, (u32)data, (u32)(data >> 32)); + } if (kvm_x86_ops.x2apic_icr_is_split) { kvm_lapic_set_reg(apic, APIC_ICR, data); kvm_lapic_set_reg(apic, APIC_ICR2, data >> 32); @@ -2458,6 +2471,16 @@ int kvm_x2apic_icr_write(struct kvm_lapic *apic, u64 data) return 0; } +static int kvm_x2apic_icr_write(struct kvm_lapic *apic, u64 data) +{ + return __kvm_x2apic_icr_write(apic, data, false); +} + +int kvm_x2apic_icr_write_fast(struct kvm_lapic *apic, u64 data) +{ + return __kvm_x2apic_icr_write(apic, data, true); +} + static u64 kvm_x2apic_icr_read(struct kvm_lapic *apic) { if (kvm_x86_ops.x2apic_icr_is_split) diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 72de14527698..1b2d408816aa 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -137,7 +137,7 @@ int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu); void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu); -int kvm_x2apic_icr_write(struct kvm_lapic *apic, u64 data); +int kvm_x2apic_icr_write_fast(struct kvm_lapic *apic, u64 data); int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data); int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5dc32f2fe391..1b64c71458a2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2150,7 +2150,7 @@ static int handle_fastpath_set_x2apic_icr_irqoff(struct kvm_vcpu *vcpu, u64 data ((data & APIC_DEST_MASK) == APIC_DEST_PHYSICAL) && ((data & APIC_MODE_MASK) == APIC_DM_FIXED) && ((u32)(data >> 32) != X2APIC_BROADCAST)) - return kvm_x2apic_icr_write(vcpu->arch.apic, data); + return kvm_x2apic_icr_write_fast(vcpu->arch.apic, data); return 1; } From aeeb4c7fff525e0fd71ec28162b713b8cb1ec943 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:12 -0700 Subject: [PATCH 0350/2711] KVM: x86: Drop semi-arbitrary restrictions on IPI type in fastpath Drop the restrictions on fastpath IPIs only working for fixed IRQs with a physical destination now that the fastpath is explicitly limited to "fast" delivery. Limiting delivery to a single physical APIC ID guarantees only one vCPU will receive the event, but that isn't necessary "fast", e.g. if the targeted vCPU is the last of 4096 vCPUs. And logical destination mode or shorthand (to self) can also be fast, e.g. if only a few vCPUs are being targeted. Lastly, there's nothing inherently slow about delivering an NMI, INIT, SIPI, SMI, etc., i.e. there's no reason to artificially limit fastpath delivery to fixed vector IRQs. Link: https://lore.kernel.org/r/20250805190526.1453366-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1b64c71458a2..6d93547526e6 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2146,13 +2146,7 @@ static int handle_fastpath_set_x2apic_icr_irqoff(struct kvm_vcpu *vcpu, u64 data if (!lapic_in_kernel(vcpu) || !apic_x2apic_mode(vcpu->arch.apic)) return 1; - if (((data & APIC_SHORT_MASK) == APIC_DEST_NOSHORT) && - ((data & APIC_DEST_MASK) == APIC_DEST_PHYSICAL) && - ((data & APIC_MODE_MASK) == APIC_DM_FIXED) && - ((u32)(data >> 32) != X2APIC_BROADCAST)) - return kvm_x2apic_icr_write_fast(vcpu->arch.apic, data); - - return 1; + return kvm_x2apic_icr_write_fast(vcpu->arch.apic, data); } static int handle_fastpath_set_tscdeadline(struct kvm_vcpu *vcpu, u64 data) From 0a94b2042419f7896f5d362465731506e43bc319 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:13 -0700 Subject: [PATCH 0351/2711] KVM: x86: Unconditionally handle MSR_IA32_TSC_DEADLINE in fastpath exits Drop the fastpath VM-Exit requirement that KVM can use the hypervisor timer to emulate the APIC timer in TSC deadline mode. I.e. unconditionally handle MSR_IA32_TSC_DEADLINE WRMSRs in the fastpath. Restricting the fastpath to *maybe* using the VMX preemption timer is ineffective and unnecessary. If the requested deadline can't be programmed into the VMX preemption timer, KVM will fall back to hrtimers, i.e. the restriction is ineffective as far as preventing any kind of worst case scenario. But guarding against a worst case scenario is completely unnecessary as the "slow" path, start_sw_tscdeadline() => hrtimer_start(), explicitly disables IRQs. In fact, the worst case scenario is when KVM thinks it can use the VMX preemption timer, as KVM will eat the overhead of calling into vmx_set_hv_timer() and falling back to hrtimers. Opportunistically limit kvm_can_use_hv_timer() to lapic.c as the fastpath code was the only external user. Stating the obvious, this allows handling MSR_IA32_TSC_DEADLINE writes in the fastpath on AMD CPUs. Link: https://lore.kernel.org/r/20250805190526.1453366-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 2 +- arch/x86/kvm/lapic.h | 1 - arch/x86/kvm/x86.c | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 252e77c88ae2..0c10b1e003c7 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -130,7 +130,7 @@ static bool kvm_can_post_timer_interrupt(struct kvm_vcpu *vcpu) (kvm_mwait_in_guest(vcpu->kvm) || kvm_hlt_in_guest(vcpu->kvm)); } -bool kvm_can_use_hv_timer(struct kvm_vcpu *vcpu) +static bool kvm_can_use_hv_timer(struct kvm_vcpu *vcpu) { return kvm_x86_ops.set_hv_timer && !(kvm_mwait_in_guest(vcpu->kvm) || diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 1b2d408816aa..8b00e29741de 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -249,7 +249,6 @@ void kvm_lapic_switch_to_hv_timer(struct kvm_vcpu *vcpu); void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu); bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu); void kvm_lapic_restart_hv_timer(struct kvm_vcpu *vcpu); -bool kvm_can_use_hv_timer(struct kvm_vcpu *vcpu); static inline enum lapic_mode kvm_apic_mode(u64 apic_base) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6d93547526e6..366c8c7f2e43 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2151,9 +2151,6 @@ static int handle_fastpath_set_x2apic_icr_irqoff(struct kvm_vcpu *vcpu, u64 data static int handle_fastpath_set_tscdeadline(struct kvm_vcpu *vcpu, u64 data) { - if (!kvm_can_use_hv_timer(vcpu)) - return 1; - kvm_set_lapic_tscdeadline_msr(vcpu, data); return 0; } From aebcbb60977323c21c8d89eb4298e454f8e89299 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:14 -0700 Subject: [PATCH 0352/2711] KVM: x86: Acquire SRCU in WRMSR fastpath iff instruction needs to be skipped Acquire SRCU in the WRMSR fastpath if and only if an instruction needs to be skipped, i.e. only if the fastpath succeeds. The reasoning in commit 3f2739bd1e0b ("KVM: x86: Acquire SRCU read lock when handling fastpath MSR writes") about "avoid having to play whack-a-mole" seems sound, but in hindsight unconditionally acquiring SRCU does more harm than good. While acquiring/releasing SRCU isn't slow per se, the things that are _protected_ by kvm->srcu are generally safe to access only in the "slow" VM-Exit path. E.g. accessing memslots in generic helpers is never safe, because accessing guest memory with IRQs disabled is unless unsafe (except when kvm_vcpu_read_guest_atomic() is used, but that API should never be used in emulation helpers). In other words, playing whack-a-mole is actually desirable in this case, because every access to an asset protected by kvm->srcu warrants further scrutiny. Link: https://lore.kernel.org/r/20250805190526.1453366-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 366c8c7f2e43..a5d7ab23d432 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2159,10 +2159,8 @@ fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu) { u32 msr = kvm_rcx_read(vcpu); u64 data; - fastpath_t ret; bool handled; - - kvm_vcpu_srcu_read_lock(vcpu); + int r; switch (msr) { case APIC_BASE_MSR + (APIC_ICR >> 4): @@ -2178,19 +2176,16 @@ fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu) break; } - if (handled) { - if (!kvm_skip_emulated_instruction(vcpu)) - ret = EXIT_FASTPATH_EXIT_USERSPACE; - else - ret = EXIT_FASTPATH_REENTER_GUEST; - trace_kvm_msr_write(msr, data); - } else { - ret = EXIT_FASTPATH_NONE; - } + if (!handled) + return EXIT_FASTPATH_NONE; + kvm_vcpu_srcu_read_lock(vcpu); + r = kvm_skip_emulated_instruction(vcpu); kvm_vcpu_srcu_read_unlock(vcpu); - return ret; + trace_kvm_msr_write(msr, data); + + return r ? EXIT_FASTPATH_REENTER_GUEST : EXIT_FASTPATH_EXIT_USERSPACE; } EXPORT_SYMBOL_GPL(handle_fastpath_set_msr_irqoff); From aa2e4f029341c0b56645d49cd5959946cdab31b9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:15 -0700 Subject: [PATCH 0353/2711] KVM: x86: Unconditionally grab data from EDX:EAX in WRMSR fastpath Always grab EDX:EAX in the WRMSR fastpath to deduplicate and simplify the case statements, and to prepare for handling immediate variants of WRMSRNS in the fastpath (the data register is explicitly provided in that case). There's no harm in reading the registers, as their values are always available, i.e. don't require VMREADs (or similarly slow operations). No real functional change intended. Cc: Xin Li Link: https://lore.kernel.org/r/20250805190526.1453366-8-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a5d7ab23d432..343bb38840dc 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2157,18 +2157,16 @@ static int handle_fastpath_set_tscdeadline(struct kvm_vcpu *vcpu, u64 data) fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu) { + u64 data = kvm_read_edx_eax(vcpu); u32 msr = kvm_rcx_read(vcpu); - u64 data; bool handled; int r; switch (msr) { case APIC_BASE_MSR + (APIC_ICR >> 4): - data = kvm_read_edx_eax(vcpu); handled = !handle_fastpath_set_x2apic_icr_irqoff(vcpu, data); break; case MSR_IA32_TSC_DEADLINE: - data = kvm_read_edx_eax(vcpu); handled = !handle_fastpath_set_tscdeadline(vcpu, data); break; default: From d618fb4e43a0287a54551aa01be58c75ac668671 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:16 -0700 Subject: [PATCH 0354/2711] KVM: x86: Fold WRMSR fastpath helpers into the main handler Fold the per-MSR WRMSR fastpath helpers into the main handler now that the IPI path in particular is relatively tiny. In addition to eliminating a decent amount of boilerplate, this removes the ugly -errno/1/0 => bool conversion (which is "necessitated" by kvm_x2apic_icr_write_fast()). Opportunistically drop the comment about IPIs, as the purpose of the fastpath is hopefully self-evident, and _if_ it needs more documentation, the documentation (and rules!) should be placed in a more central location. No functional change intended. Link: https://lore.kernel.org/r/20250805190526.1453366-9-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 343bb38840dc..f5e933f0e21a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2134,48 +2134,24 @@ static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu) kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending(); } -/* - * The fast path for frequent and performance sensitive wrmsr emulation, - * i.e. the sending of IPI, sending IPI early in the VM-Exit flow reduces - * the latency of virtual IPI by avoiding the expensive bits of transitioning - * from guest to host, e.g. reacquiring KVM's SRCU lock. In contrast to the - * other cases which must be called after interrupts are enabled on the host. - */ -static int handle_fastpath_set_x2apic_icr_irqoff(struct kvm_vcpu *vcpu, u64 data) -{ - if (!lapic_in_kernel(vcpu) || !apic_x2apic_mode(vcpu->arch.apic)) - return 1; - - return kvm_x2apic_icr_write_fast(vcpu->arch.apic, data); -} - -static int handle_fastpath_set_tscdeadline(struct kvm_vcpu *vcpu, u64 data) -{ - kvm_set_lapic_tscdeadline_msr(vcpu, data); - return 0; -} - fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu) { u64 data = kvm_read_edx_eax(vcpu); u32 msr = kvm_rcx_read(vcpu); - bool handled; int r; switch (msr) { case APIC_BASE_MSR + (APIC_ICR >> 4): - handled = !handle_fastpath_set_x2apic_icr_irqoff(vcpu, data); + if (!lapic_in_kernel(vcpu) || !apic_x2apic_mode(vcpu->arch.apic) || + kvm_x2apic_icr_write_fast(vcpu->arch.apic, data)) + return EXIT_FASTPATH_NONE; break; case MSR_IA32_TSC_DEADLINE: - handled = !handle_fastpath_set_tscdeadline(vcpu, data); + kvm_set_lapic_tscdeadline_msr(vcpu, data); break; default: - handled = false; - break; - } - - if (!handled) return EXIT_FASTPATH_NONE; + } kvm_vcpu_srcu_read_lock(vcpu); r = kvm_skip_emulated_instruction(vcpu); From a3e80bf73ee1f89ad4ccd53dd4f2654e23e72529 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:17 -0700 Subject: [PATCH 0355/2711] KVM: x86/pmu: Move kvm_init_pmu_capability() to pmu.c Move kvm_init_pmu_capability() to pmu.c so that future changes can access variables that have no business being visible outside of pmu.c. kvm_init_pmu_capability() is called once per module load, there's is zero reason it needs to be inlined. No functional change intended. Cc: Dapeng Mi Cc: Sandipan Das Reviewed-by: Dapeng Mi Link: https://lore.kernel.org/r/20250805190526.1453366-10-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/pmu.h | 47 +--------------------------------------------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index a84fb3d28885..adb0fb8f6bb7 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -96,6 +96,53 @@ void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops) #undef __KVM_X86_PMU_OP } +void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops) +{ + bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL; + int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS; + + /* + * Hybrid PMUs don't play nice with virtualization without careful + * configuration by userspace, and KVM's APIs for reporting supported + * vPMU features do not account for hybrid PMUs. Disable vPMU support + * for hybrid PMUs until KVM gains a way to let userspace opt-in. + */ + if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU)) + enable_pmu = false; + + if (enable_pmu) { + perf_get_x86_pmu_capability(&kvm_pmu_cap); + + /* + * WARN if perf did NOT disable hardware PMU if the number of + * architecturally required GP counters aren't present, i.e. if + * there are a non-zero number of counters, but fewer than what + * is architecturally required. + */ + if (!kvm_pmu_cap.num_counters_gp || + WARN_ON_ONCE(kvm_pmu_cap.num_counters_gp < min_nr_gp_ctrs)) + enable_pmu = false; + else if (is_intel && !kvm_pmu_cap.version) + enable_pmu = false; + } + + if (!enable_pmu) { + memset(&kvm_pmu_cap, 0, sizeof(kvm_pmu_cap)); + return; + } + + kvm_pmu_cap.version = min(kvm_pmu_cap.version, 2); + kvm_pmu_cap.num_counters_gp = min(kvm_pmu_cap.num_counters_gp, + pmu_ops->MAX_NR_GP_COUNTERS); + kvm_pmu_cap.num_counters_fixed = min(kvm_pmu_cap.num_counters_fixed, + KVM_MAX_NR_FIXED_COUNTERS); + + kvm_pmu_eventsel.INSTRUCTIONS_RETIRED = + perf_get_hw_event_config(PERF_COUNT_HW_INSTRUCTIONS); + kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED = + perf_get_hw_event_config(PERF_COUNT_HW_BRANCH_INSTRUCTIONS); +} + static inline void __kvm_perf_overflow(struct kvm_pmc *pmc, bool in_pmi) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index ad89d0bd6005..13477066eb40 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -180,52 +180,7 @@ static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc) extern struct x86_pmu_capability kvm_pmu_cap; extern struct kvm_pmu_emulated_event_selectors kvm_pmu_eventsel; -static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops) -{ - bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL; - int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS; - - /* - * Hybrid PMUs don't play nice with virtualization without careful - * configuration by userspace, and KVM's APIs for reporting supported - * vPMU features do not account for hybrid PMUs. Disable vPMU support - * for hybrid PMUs until KVM gains a way to let userspace opt-in. - */ - if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU)) - enable_pmu = false; - - if (enable_pmu) { - perf_get_x86_pmu_capability(&kvm_pmu_cap); - - /* - * WARN if perf did NOT disable hardware PMU if the number of - * architecturally required GP counters aren't present, i.e. if - * there are a non-zero number of counters, but fewer than what - * is architecturally required. - */ - if (!kvm_pmu_cap.num_counters_gp || - WARN_ON_ONCE(kvm_pmu_cap.num_counters_gp < min_nr_gp_ctrs)) - enable_pmu = false; - else if (is_intel && !kvm_pmu_cap.version) - enable_pmu = false; - } - - if (!enable_pmu) { - memset(&kvm_pmu_cap, 0, sizeof(kvm_pmu_cap)); - return; - } - - kvm_pmu_cap.version = min(kvm_pmu_cap.version, 2); - kvm_pmu_cap.num_counters_gp = min(kvm_pmu_cap.num_counters_gp, - pmu_ops->MAX_NR_GP_COUNTERS); - kvm_pmu_cap.num_counters_fixed = min(kvm_pmu_cap.num_counters_fixed, - KVM_MAX_NR_FIXED_COUNTERS); - - kvm_pmu_eventsel.INSTRUCTIONS_RETIRED = - perf_get_hw_event_config(PERF_COUNT_HW_INSTRUCTIONS); - kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED = - perf_get_hw_event_config(PERF_COUNT_HW_BRANCH_INSTRUCTIONS); -} +void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops); static inline void kvm_pmu_request_counter_reprogram(struct kvm_pmc *pmc) { From 43f5bea2639ccca59541f33d62342543b4461937 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:18 -0700 Subject: [PATCH 0356/2711] KVM: x86/pmu: Add wrappers for counting emulated instructions/branches Add wrappers for triggering instruction retired and branch retired PMU events in anticipation of reworking the internal mechanisms to track which PMCs need to be evaluated, e.g. to avoid having to walk and check every PMC. Opportunistically bury "struct kvm_pmu_emulated_event_selectors" in pmu.c. No functional change intended. Link: https://lore.kernel.org/r/20250805190526.1453366-11-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 22 ++++++++++++++++++---- arch/x86/kvm/pmu.h | 9 ++------- arch/x86/kvm/vmx/nested.c | 2 +- arch/x86/kvm/x86.c | 6 +++--- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index adb0fb8f6bb7..9040bf20e851 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -29,8 +29,11 @@ struct x86_pmu_capability __read_mostly kvm_pmu_cap; EXPORT_SYMBOL_GPL(kvm_pmu_cap); -struct kvm_pmu_emulated_event_selectors __read_mostly kvm_pmu_eventsel; -EXPORT_SYMBOL_GPL(kvm_pmu_eventsel); +struct kvm_pmu_emulated_event_selectors { + u64 INSTRUCTIONS_RETIRED; + u64 BRANCH_INSTRUCTIONS_RETIRED; +}; +static struct kvm_pmu_emulated_event_selectors __read_mostly kvm_pmu_eventsel; /* Precise Distribution of Instructions Retired (PDIR) */ static const struct x86_cpu_id vmx_pebs_pdir_cpu[] = { @@ -912,7 +915,7 @@ static inline bool cpl_is_matched(struct kvm_pmc *pmc) select_user; } -void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) +static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) { DECLARE_BITMAP(bitmap, X86_PMC_IDX_MAX); struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); @@ -949,7 +952,18 @@ void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) kvm_pmu_incr_counter(pmc); } } -EXPORT_SYMBOL_GPL(kvm_pmu_trigger_event); + +void kvm_pmu_instruction_retired(struct kvm_vcpu *vcpu) +{ + kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.INSTRUCTIONS_RETIRED); +} +EXPORT_SYMBOL_GPL(kvm_pmu_instruction_retired); + +void kvm_pmu_branch_retired(struct kvm_vcpu *vcpu) +{ + kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED); +} +EXPORT_SYMBOL_GPL(kvm_pmu_branch_retired); static bool is_masked_filter_valid(const struct kvm_x86_pmu_event_filter *filter) { diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 13477066eb40..740af816af37 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -23,11 +23,6 @@ #define KVM_FIXED_PMC_BASE_IDX INTEL_PMC_IDX_FIXED -struct kvm_pmu_emulated_event_selectors { - u64 INSTRUCTIONS_RETIRED; - u64 BRANCH_INSTRUCTIONS_RETIRED; -}; - struct kvm_pmu_ops { struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu, unsigned int idx, u64 *mask); @@ -178,7 +173,6 @@ static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc) } extern struct x86_pmu_capability kvm_pmu_cap; -extern struct kvm_pmu_emulated_event_selectors kvm_pmu_eventsel; void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops); @@ -227,7 +221,8 @@ void kvm_pmu_init(struct kvm_vcpu *vcpu); void kvm_pmu_cleanup(struct kvm_vcpu *vcpu); void kvm_pmu_destroy(struct kvm_vcpu *vcpu); int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp); -void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel); +void kvm_pmu_instruction_retired(struct kvm_vcpu *vcpu); +void kvm_pmu_branch_retired(struct kvm_vcpu *vcpu); bool is_vmware_backdoor_pmc(u32 pmc_idx); diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index b8ea1969113d..db2fd4eedc90 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -3690,7 +3690,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) return 1; } - kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED); + kvm_pmu_branch_retired(vcpu); if (CC(evmptrld_status == EVMPTRLD_VMFAIL)) return nested_vmx_failInvalid(vcpu); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f5e933f0e21a..c44d3d64270b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8820,7 +8820,7 @@ int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu) if (unlikely(!r)) return 0; - kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.INSTRUCTIONS_RETIRED); + kvm_pmu_instruction_retired(vcpu); /* * rflags is the old, "raw" value of the flags. The new value has @@ -9161,9 +9161,9 @@ writeback: */ if (!ctxt->have_exception || exception_type(ctxt->exception.vector) == EXCPT_TRAP) { - kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.INSTRUCTIONS_RETIRED); + kvm_pmu_instruction_retired(vcpu); if (ctxt->is_branch) - kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED); + kvm_pmu_branch_retired(vcpu); kvm_rip_write(vcpu, ctxt->eip); if (r && (ctxt->tf || (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP))) r = kvm_vcpu_do_singlestep(vcpu); From 5dfd498bad5f07b7419b5f834d95f7b61e767048 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:19 -0700 Subject: [PATCH 0357/2711] KVM: x86/pmu: Calculate set of to-be-emulated PMCs at time of WRMSRs Calculate and track PMCs that are counting instructions/branches retired when the PMC's event selector (or fixed counter control) is modified instead evaluating the event selector on-demand. Immediately recalc a PMC's configuration on writes to avoid false negatives/positives when KVM skips an emulated WRMSR, which is guaranteed to occur before the main run loop processes KVM_REQ_PMU. Out of an abundance of caution, and because it's relatively cheap, recalc reprogrammed PMCs in kvm_pmu_handle_event() as well. Recalculating in response to KVM_REQ_PMU _should_ be unnecessary, but for now be paranoid to avoid introducing easily-avoidable bugs in edge cases. The code can be removed in the future if necessary, e.g. in the unlikely event that the overhead of recalculating to-be-emulated PMCs is noticeable. Note! Deliberately don't check the PMU event filters, as doing so could result in KVM consuming stale information. Tracking which PMCs are counting branches/instructions will allow grabbing SRCU in the fastpath VM-Exit handlers if and only if a PMC event might be triggered (to consult the event filters), and will also allow the upcoming mediated PMU to do the right thing with respect to counting instructions (the mediated PMU won't be able to update PMCs in the VM-Exit fastpath). Reviewed-by: Dapeng Mi Link: https://lore.kernel.org/r/20250805190526.1453366-12-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 3 ++ arch/x86/kvm/pmu.c | 75 ++++++++++++++++++++++++--------- arch/x86/kvm/pmu.h | 4 ++ 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f19a76d3ca0e..d7680612ba1e 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -579,6 +579,9 @@ struct kvm_pmu { DECLARE_BITMAP(all_valid_pmc_idx, X86_PMC_IDX_MAX); DECLARE_BITMAP(pmc_in_use, X86_PMC_IDX_MAX); + DECLARE_BITMAP(pmc_counting_instructions, X86_PMC_IDX_MAX); + DECLARE_BITMAP(pmc_counting_branches, X86_PMC_IDX_MAX); + u64 ds_area; u64 pebs_enable; u64 pebs_enable_rsvd; diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 9040bf20e851..8070097c5c4a 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -542,6 +542,47 @@ static int reprogram_counter(struct kvm_pmc *pmc) eventsel & ARCH_PERFMON_EVENTSEL_INT); } +static bool pmc_is_event_match(struct kvm_pmc *pmc, u64 eventsel) +{ + /* + * Ignore checks for edge detect (all events currently emulated by KVM + * are always rising edges), pin control (unsupported by modern CPUs), + * and counter mask and its invert flag (KVM doesn't emulate multiple + * events in a single clock cycle). + * + * Note, the uppermost nibble of AMD's mask overlaps Intel's IN_TX (bit + * 32) and IN_TXCP (bit 33), as well as two reserved bits (bits 35:34). + * Checking the "in HLE/RTM transaction" flags is correct as the vCPU + * can't be in a transaction if KVM is emulating an instruction. + * + * Checking the reserved bits might be wrong if they are defined in the + * future, but so could ignoring them, so do the simple thing for now. + */ + return !((pmc->eventsel ^ eventsel) & AMD64_RAW_EVENT_MASK_NB); +} + +void kvm_pmu_recalc_pmc_emulation(struct kvm_pmu *pmu, struct kvm_pmc *pmc) +{ + bitmap_clear(pmu->pmc_counting_instructions, pmc->idx, 1); + bitmap_clear(pmu->pmc_counting_branches, pmc->idx, 1); + + /* + * Do NOT consult the PMU event filters, as the filters must be checked + * at the time of emulation to ensure KVM uses fresh information, e.g. + * omitting a PMC from a bitmap could result in a missed event if the + * filter is changed to allow counting the event. + */ + if (!pmc_speculative_in_use(pmc)) + return; + + if (pmc_is_event_match(pmc, kvm_pmu_eventsel.INSTRUCTIONS_RETIRED)) + bitmap_set(pmu->pmc_counting_instructions, pmc->idx, 1); + + if (pmc_is_event_match(pmc, kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED)) + bitmap_set(pmu->pmc_counting_branches, pmc->idx, 1); +} +EXPORT_SYMBOL_GPL(kvm_pmu_recalc_pmc_emulation); + void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) { DECLARE_BITMAP(bitmap, X86_PMC_IDX_MAX); @@ -577,6 +618,9 @@ void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) */ if (unlikely(pmu->need_cleanup)) kvm_pmu_cleanup(vcpu); + + kvm_for_each_pmc(pmu, pmc, bit, bitmap) + kvm_pmu_recalc_pmc_emulation(pmu, pmc); } int kvm_pmu_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx) @@ -915,7 +959,8 @@ static inline bool cpl_is_matched(struct kvm_pmc *pmc) select_user; } -static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) +static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, + const unsigned long *event_pmcs) { DECLARE_BITMAP(bitmap, X86_PMC_IDX_MAX); struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); @@ -924,29 +969,17 @@ static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) BUILD_BUG_ON(sizeof(pmu->global_ctrl) * BITS_PER_BYTE != X86_PMC_IDX_MAX); + if (bitmap_empty(event_pmcs, X86_PMC_IDX_MAX)) + return; + if (!kvm_pmu_has_perf_global_ctrl(pmu)) - bitmap_copy(bitmap, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX); - else if (!bitmap_and(bitmap, pmu->all_valid_pmc_idx, + bitmap_copy(bitmap, event_pmcs, X86_PMC_IDX_MAX); + else if (!bitmap_and(bitmap, event_pmcs, (unsigned long *)&pmu->global_ctrl, X86_PMC_IDX_MAX)) return; kvm_for_each_pmc(pmu, pmc, i, bitmap) { - /* - * Ignore checks for edge detect (all events currently emulated - * but KVM are always rising edges), pin control (unsupported - * by modern CPUs), and counter mask and its invert flag (KVM - * doesn't emulate multiple events in a single clock cycle). - * - * Note, the uppermost nibble of AMD's mask overlaps Intel's - * IN_TX (bit 32) and IN_TXCP (bit 33), as well as two reserved - * bits (bits 35:34). Checking the "in HLE/RTM transaction" - * flags is correct as the vCPU can't be in a transaction if - * KVM is emulating an instruction. Checking the reserved bits - * might be wrong if they are defined in the future, but so - * could ignoring them, so do the simple thing for now. - */ - if (((pmc->eventsel ^ eventsel) & AMD64_RAW_EVENT_MASK_NB) || - !pmc_event_is_allowed(pmc) || !cpl_is_matched(pmc)) + if (!pmc_event_is_allowed(pmc) || !cpl_is_matched(pmc)) continue; kvm_pmu_incr_counter(pmc); @@ -955,13 +988,13 @@ static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 eventsel) void kvm_pmu_instruction_retired(struct kvm_vcpu *vcpu) { - kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.INSTRUCTIONS_RETIRED); + kvm_pmu_trigger_event(vcpu, vcpu_to_pmu(vcpu)->pmc_counting_instructions); } EXPORT_SYMBOL_GPL(kvm_pmu_instruction_retired); void kvm_pmu_branch_retired(struct kvm_vcpu *vcpu) { - kvm_pmu_trigger_event(vcpu, kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED); + kvm_pmu_trigger_event(vcpu, vcpu_to_pmu(vcpu)->pmc_counting_branches); } EXPORT_SYMBOL_GPL(kvm_pmu_branch_retired); diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 740af816af37..cb93a936a177 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -176,8 +176,12 @@ extern struct x86_pmu_capability kvm_pmu_cap; void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops); +void kvm_pmu_recalc_pmc_emulation(struct kvm_pmu *pmu, struct kvm_pmc *pmc); + static inline void kvm_pmu_request_counter_reprogram(struct kvm_pmc *pmc) { + kvm_pmu_recalc_pmc_emulation(pmc_to_pmu(pmc), pmc); + set_bit(pmc->idx, pmc_to_pmu(pmc)->reprogram_pmi); kvm_make_request(KVM_REQ_PMU, pmc->vcpu); } From 6b6f1adc43320494197ddbefbe933faea21e2d10 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:20 -0700 Subject: [PATCH 0358/2711] KVM: x86/pmu: Rename pmc_speculative_in_use() to pmc_is_locally_enabled() Rename pmc_speculative_in_use() to pmc_is_locally_enabled() to better capture what it actually tracks, and to show its relationship to pmc_is_globally_enabled(). While neither AMD nor Intel refer to event selectors or the fixed counter control MSR as "local", it's the obvious name to pair with "global". As for "speculative", there's absolutely nothing speculative about the checks. E.g. for PMUs without PERF_GLOBAL_CTRL, from the guest's perspective, the counters are "in use" without any qualifications. No functional change intended. Reviewed-by: Dapeng Mi Link: https://lore.kernel.org/r/20250805190526.1453366-13-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 6 +++--- arch/x86/kvm/pmu.h | 2 +- arch/x86/kvm/vmx/pmu_intel.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 8070097c5c4a..55b995c3ed08 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -493,7 +493,7 @@ static bool check_pmu_event_filter(struct kvm_pmc *pmc) static bool pmc_event_is_allowed(struct kvm_pmc *pmc) { - return pmc_is_globally_enabled(pmc) && pmc_speculative_in_use(pmc) && + return pmc_is_globally_enabled(pmc) && pmc_is_locally_enabled(pmc) && check_pmu_event_filter(pmc); } @@ -572,7 +572,7 @@ void kvm_pmu_recalc_pmc_emulation(struct kvm_pmu *pmu, struct kvm_pmc *pmc) * omitting a PMC from a bitmap could result in a missed event if the * filter is changed to allow counting the event. */ - if (!pmc_speculative_in_use(pmc)) + if (!pmc_is_locally_enabled(pmc)) return; if (pmc_is_event_match(pmc, kvm_pmu_eventsel.INSTRUCTIONS_RETIRED)) @@ -912,7 +912,7 @@ void kvm_pmu_cleanup(struct kvm_vcpu *vcpu) pmu->pmc_in_use, X86_PMC_IDX_MAX); kvm_for_each_pmc(pmu, pmc, i, bitmask) { - if (pmc->perf_event && !pmc_speculative_in_use(pmc)) + if (pmc->perf_event && !pmc_is_locally_enabled(pmc)) pmc_stop_counter(pmc); } diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index cb93a936a177..08ae644db00e 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -160,7 +160,7 @@ static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr) return NULL; } -static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc) +static inline bool pmc_is_locally_enabled(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 0b173602821b..07baff96300f 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -762,7 +762,7 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu) int bit, hw_idx; kvm_for_each_pmc(pmu, pmc, bit, (unsigned long *)&pmu->global_ctrl) { - if (!pmc_speculative_in_use(pmc) || + if (!pmc_is_locally_enabled(pmc) || !pmc_is_globally_enabled(pmc) || !pmc->perf_event) continue; From e630bb52d27f4191324d3443ecb2b115d7fb14b2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:21 -0700 Subject: [PATCH 0359/2711] KVM: x86/pmu: Open code pmc_event_is_allowed() in its callers Open code pmc_event_is_allowed() in its callers, as kvm_pmu_trigger_event() only needs to check the event filter (both global and local enables are consulted outside of the loop). No functional change intended. Reviewed-by: Dapeng Mi Link: https://lore.kernel.org/r/20250805190526.1453366-14-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 55b995c3ed08..fa3464559698 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -491,12 +491,6 @@ static bool check_pmu_event_filter(struct kvm_pmc *pmc) return is_fixed_event_allowed(filter, pmc->idx); } -static bool pmc_event_is_allowed(struct kvm_pmc *pmc) -{ - return pmc_is_globally_enabled(pmc) && pmc_is_locally_enabled(pmc) && - check_pmu_event_filter(pmc); -} - static int reprogram_counter(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); @@ -507,7 +501,8 @@ static int reprogram_counter(struct kvm_pmc *pmc) emulate_overflow = pmc_pause_counter(pmc); - if (!pmc_event_is_allowed(pmc)) + if (!pmc_is_globally_enabled(pmc) || !pmc_is_locally_enabled(pmc) || + !check_pmu_event_filter(pmc)) return 0; if (emulate_overflow) @@ -979,7 +974,8 @@ static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, return; kvm_for_each_pmc(pmu, pmc, i, bitmap) { - if (!pmc_event_is_allowed(pmc) || !cpl_is_matched(pmc)) + if (!pmc_is_globally_enabled(pmc) || !pmc_is_locally_enabled(pmc) || + !check_pmu_event_filter(pmc) || !cpl_is_matched(pmc)) continue; kvm_pmu_incr_counter(pmc); From 58baa649ea09e7b719d0ef51aba894d63c2bb64f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:22 -0700 Subject: [PATCH 0360/2711] KVM: x86/pmu: Drop redundant check on PMC being globally enabled for emulation When triggering PMC events in response to emulation, drop the redundant checks on a PMC being globally and locally enabled, as the passed in bitmap contains only PMCs that are locally enabled (and counting the right event), and the local copy of the bitmap has already been masked with global_ctrl. No true functional change intended. Reviewed-by: Dapeng Mi Link: https://lore.kernel.org/r/20250805190526.1453366-15-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index fa3464559698..744717d379cb 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -974,7 +974,7 @@ static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, return; kvm_for_each_pmc(pmu, pmc, i, bitmap) { - if (!pmc_is_globally_enabled(pmc) || !pmc_is_locally_enabled(pmc) || + if (!pmc_is_locally_enabled(pmc) || !check_pmu_event_filter(pmc) || !cpl_is_matched(pmc)) continue; From 8709656514c1106933befcdefdcc5fd9bc013ed2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:23 -0700 Subject: [PATCH 0361/2711] KVM: x86/pmu: Drop redundant check on PMC being locally enabled for emulation Drop the check on a PMC being locally enabled when triggering emulated events, as the bitmap of passed-in PMCs only contains locally enabled PMCs. Reviewed-by: Dapeng Mi Link: https://lore.kernel.org/r/20250805190526.1453366-16-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 744717d379cb..b7514082e1ac 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -974,8 +974,7 @@ static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, return; kvm_for_each_pmc(pmu, pmc, i, bitmap) { - if (!pmc_is_locally_enabled(pmc) || - !check_pmu_event_filter(pmc) || !cpl_is_matched(pmc)) + if (!check_pmu_event_filter(pmc) || !cpl_is_matched(pmc)) continue; kvm_pmu_incr_counter(pmc); From 3eced8b07bb984a3bd2959f0644c14929c848c3b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:24 -0700 Subject: [PATCH 0362/2711] KVM: x86/pmu: Rename check_pmu_event_filter() to pmc_is_event_allowed() Rename check_pmu_event_filter() to make its polarity more obvious, and to connect the dots to is_gp_event_allowed() and is_fixed_event_allowed(). No functional change intended. Reviewed-by: Dapeng Mi Link: https://lore.kernel.org/r/20250805190526.1453366-17-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index b7514082e1ac..a1b8223a11f8 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -476,7 +476,7 @@ static bool is_fixed_event_allowed(struct kvm_x86_pmu_event_filter *filter, return true; } -static bool check_pmu_event_filter(struct kvm_pmc *pmc) +static bool pmc_is_event_allowed(struct kvm_pmc *pmc) { struct kvm_x86_pmu_event_filter *filter; struct kvm *kvm = pmc->vcpu->kvm; @@ -502,7 +502,7 @@ static int reprogram_counter(struct kvm_pmc *pmc) emulate_overflow = pmc_pause_counter(pmc); if (!pmc_is_globally_enabled(pmc) || !pmc_is_locally_enabled(pmc) || - !check_pmu_event_filter(pmc)) + !pmc_is_event_allowed(pmc)) return 0; if (emulate_overflow) @@ -974,7 +974,7 @@ static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, return; kvm_for_each_pmc(pmu, pmc, i, bitmap) { - if (!check_pmu_event_filter(pmc) || !cpl_is_matched(pmc)) + if (!pmc_is_event_allowed(pmc) || !cpl_is_matched(pmc)) continue; kvm_pmu_incr_counter(pmc); From 8bb8b60c95c55c13f9924f3f090232e14d035d43 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:25 -0700 Subject: [PATCH 0363/2711] KVM: x86: Push acquisition of SRCU in fastpath into kvm_pmu_trigger_event() Acquire SRCU in the VM-Exit fastpath if and only if KVM needs to check the PMU event filter, to further trim the amount of code that is executed with SRCU protection in the fastpath. Counter-intuitively, holding SRCU can do more harm than good due to masking potential bugs, and introducing a new SRCU-protected asset to code reachable via kvm_skip_emulated_instruction() would be quite notable, i.e. definitely worth auditing. E.g. the primary user of kvm->srcu is KVM's memslots, accessing memslots all but guarantees guest memory may be accessed, accessing guest memory can fault, and page faults might sleep, which isn't allowed while IRQs are disabled. Not acquiring SRCU means the (hypothetical) illegal sleep would be flagged when running with PROVE_RCU=y, even if DEBUG_ATOMIC_SLEEP=n. Note, performance is NOT a motivating factor, as SRCU lock/unlock only adds ~15 cycles of latency to fastpath VM-Exits. I.e. overhead isn't a concern _if_ SRCU protection needs to be extended beyond PMU events, e.g. to honor userspace MSR filters. Reviewed-by: Dapeng Mi Link: https://lore.kernel.org/r/20250805190526.1453366-18-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 4 +++- arch/x86/kvm/x86.c | 18 +++++------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index a1b8223a11f8..40b076a7a5f6 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -960,7 +960,7 @@ static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, DECLARE_BITMAP(bitmap, X86_PMC_IDX_MAX); struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); struct kvm_pmc *pmc; - int i; + int i, idx; BUILD_BUG_ON(sizeof(pmu->global_ctrl) * BITS_PER_BYTE != X86_PMC_IDX_MAX); @@ -973,12 +973,14 @@ static void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, (unsigned long *)&pmu->global_ctrl, X86_PMC_IDX_MAX)) return; + idx = srcu_read_lock(&vcpu->kvm->srcu); kvm_for_each_pmc(pmu, pmc, i, bitmap) { if (!pmc_is_event_allowed(pmc) || !cpl_is_matched(pmc)) continue; kvm_pmu_incr_counter(pmc); } + srcu_read_unlock(&vcpu->kvm->srcu, idx); } void kvm_pmu_instruction_retired(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c44d3d64270b..093bfc8d00b3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2138,7 +2138,6 @@ fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu) { u64 data = kvm_read_edx_eax(vcpu); u32 msr = kvm_rcx_read(vcpu); - int r; switch (msr) { case APIC_BASE_MSR + (APIC_ICR >> 4): @@ -2153,13 +2152,12 @@ fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu) return EXIT_FASTPATH_NONE; } - kvm_vcpu_srcu_read_lock(vcpu); - r = kvm_skip_emulated_instruction(vcpu); - kvm_vcpu_srcu_read_unlock(vcpu); - trace_kvm_msr_write(msr, data); - return r ? EXIT_FASTPATH_REENTER_GUEST : EXIT_FASTPATH_EXIT_USERSPACE; + if (!kvm_skip_emulated_instruction(vcpu)) + return EXIT_FASTPATH_EXIT_USERSPACE; + + return EXIT_FASTPATH_REENTER_GUEST; } EXPORT_SYMBOL_GPL(handle_fastpath_set_msr_irqoff); @@ -11254,13 +11252,7 @@ EXPORT_SYMBOL_GPL(kvm_emulate_halt); fastpath_t handle_fastpath_hlt(struct kvm_vcpu *vcpu) { - int ret; - - kvm_vcpu_srcu_read_lock(vcpu); - ret = kvm_emulate_halt(vcpu); - kvm_vcpu_srcu_read_unlock(vcpu); - - if (!ret) + if (!kvm_emulate_halt(vcpu)) return EXIT_FASTPATH_EXIT_USERSPACE; if (kvm_vcpu_running(vcpu)) From 6c3d4b917995a17f515943ccd39ba11b81753b0d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 12:05:26 -0700 Subject: [PATCH 0364/2711] KVM: x86: Add a fastpath handler for INVD Add a fastpath handler for INVD so that the common fastpath logic can be trivially tested on both Intel and AMD. Under KVM, INVD is always: (a) intercepted, (b) available to the guest, and (c) emulated as a nop, with no side effects. Combined with INVD not having any inputs or outputs, i.e. no register constraints, INVD is the perfect instruction for exercising KVM's fastpath as it can be inserted into practically any guest-side code stream. Link: https://lore.kernel.org/r/20250805190526.1453366-19-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 2 ++ arch/x86/kvm/vmx/vmx.c | 2 ++ arch/x86/kvm/x86.c | 9 +++++++++ arch/x86/kvm/x86.h | 1 + 4 files changed, 14 insertions(+) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 829d9d46718d..f7e1e665a826 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4200,6 +4200,8 @@ static fastpath_t svm_exit_handlers_fastpath(struct kvm_vcpu *vcpu) return handle_fastpath_set_msr_irqoff(vcpu); case SVM_EXIT_HLT: return handle_fastpath_hlt(vcpu); + case SVM_EXIT_INVD: + return handle_fastpath_invd(vcpu); default: break; } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index aa157fe5b7b3..95765db52992 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7175,6 +7175,8 @@ static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu, return handle_fastpath_preemption_timer(vcpu, force_immediate_exit); case EXIT_REASON_HLT: return handle_fastpath_hlt(vcpu); + case EXIT_REASON_INVD: + return handle_fastpath_invd(vcpu); default: return EXIT_FASTPATH_NONE; } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 093bfc8d00b3..6e56d5cff44d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2087,6 +2087,15 @@ int kvm_emulate_invd(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_emulate_invd); +fastpath_t handle_fastpath_invd(struct kvm_vcpu *vcpu) +{ + if (!kvm_emulate_invd(vcpu)) + return EXIT_FASTPATH_EXIT_USERSPACE; + + return EXIT_FASTPATH_REENTER_GUEST; +} +EXPORT_SYMBOL_GPL(handle_fastpath_invd); + int kvm_handle_invalid_op(struct kvm_vcpu *vcpu) { kvm_queue_exception(vcpu, UD_VECTOR); diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index bcfd9b719ada..46220b04cdf2 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -439,6 +439,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, int emulation_type, void *insn, int insn_len); fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu); fastpath_t handle_fastpath_hlt(struct kvm_vcpu *vcpu); +fastpath_t handle_fastpath_invd(struct kvm_vcpu *vcpu); extern struct kvm_caps kvm_caps; extern struct kvm_host_values kvm_host; From 3c7cb84145336721eddc86982532df84bbc80853 Mon Sep 17 00:00:00 2001 From: Xin Li Date: Tue, 5 Aug 2025 13:22:19 -0700 Subject: [PATCH 0365/2711] x86/cpufeatures: Add a CPU feature bit for MSR immediate form instructions The immediate form of MSR access instructions are primarily motivated by performance, not code size: by having the MSR number in an immediate, it is available *much* earlier in the pipeline, which allows the hardware much more leeway about how a particular MSR is handled. Use a scattered CPU feature bit for MSR immediate form instructions. Suggested-by: Borislav Petkov (AMD) Signed-off-by: Xin Li (Intel) Link: https://lore.kernel.org/r/20250805202224.1475590-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/kernel/cpu/scattered.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 06fc0479a23f..eb859299d514 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -495,6 +495,7 @@ #define X86_FEATURE_TSA_SQ_NO (21*32+11) /* AMD CPU not vulnerable to TSA-SQ */ #define X86_FEATURE_TSA_L1_NO (21*32+12) /* AMD CPU not vulnerable to TSA-L1 */ #define X86_FEATURE_CLEAR_CPU_BUF_VM (21*32+13) /* Clear CPU buffers using VERW before VMRUN */ +#define X86_FEATURE_MSR_IMM (21*32+14) /* MSR immediate form instructions */ /* * BUG word(s) diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index 6b868afb26c3..cf4ae822bcc0 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -27,6 +27,7 @@ static const struct cpuid_bit cpuid_bits[] = { { X86_FEATURE_APERFMPERF, CPUID_ECX, 0, 0x00000006, 0 }, { X86_FEATURE_EPB, CPUID_ECX, 3, 0x00000006, 0 }, { X86_FEATURE_INTEL_PPIN, CPUID_EBX, 0, 0x00000007, 1 }, + { X86_FEATURE_MSR_IMM, CPUID_ECX, 5, 0x00000007, 1 }, { X86_FEATURE_APX, CPUID_EDX, 21, 0x00000007, 1 }, { X86_FEATURE_RRSBA_CTRL, CPUID_EDX, 2, 0x00000007, 2 }, { X86_FEATURE_BHI_CTRL, CPUID_EDX, 4, 0x00000007, 2 }, From ec400f6c2f2703cb6c698dd00b28cfdb8ee5cdcc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 5 Aug 2025 13:22:20 -0700 Subject: [PATCH 0366/2711] KVM: x86: Rename local "ecx" variables to "msr" and "pmc" as appropriate Rename "ecx" variables in {RD,WR}MSR and RDPMC helpers to "msr" and "pmc" respectively, in anticipation of adding support for the immediate variants of RDMSR and WRMSRNS, and to better document what the variables hold (versus where the data originated). No functional change intended. Link: https://lore.kernel.org/r/20250805202224.1475590-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6e56d5cff44d..f7c5db3d2652 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1573,10 +1573,10 @@ EXPORT_SYMBOL_GPL(kvm_get_dr); int kvm_emulate_rdpmc(struct kvm_vcpu *vcpu) { - u32 ecx = kvm_rcx_read(vcpu); + u32 pmc = kvm_rcx_read(vcpu); u64 data; - if (kvm_pmu_rdpmc(vcpu, ecx, &data)) { + if (kvm_pmu_rdpmc(vcpu, pmc, &data)) { kvm_inject_gp(vcpu, 0); return 1; } @@ -2027,23 +2027,23 @@ static int kvm_msr_user_space(struct kvm_vcpu *vcpu, u32 index, int kvm_emulate_rdmsr(struct kvm_vcpu *vcpu) { - u32 ecx = kvm_rcx_read(vcpu); + u32 msr = kvm_rcx_read(vcpu); u64 data; int r; - r = kvm_get_msr_with_filter(vcpu, ecx, &data); + r = kvm_get_msr_with_filter(vcpu, msr, &data); if (!r) { - trace_kvm_msr_read(ecx, data); + trace_kvm_msr_read(msr, data); kvm_rax_write(vcpu, data & -1u); kvm_rdx_write(vcpu, (data >> 32) & -1u); } else { /* MSR read failed? See if we should ask user space */ - if (kvm_msr_user_space(vcpu, ecx, KVM_EXIT_X86_RDMSR, 0, + if (kvm_msr_user_space(vcpu, msr, KVM_EXIT_X86_RDMSR, 0, complete_fast_rdmsr, r)) return 0; - trace_kvm_msr_read_ex(ecx); + trace_kvm_msr_read_ex(msr); } return kvm_x86_call(complete_emulated_msr)(vcpu, r); @@ -2052,23 +2052,23 @@ EXPORT_SYMBOL_GPL(kvm_emulate_rdmsr); int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu) { - u32 ecx = kvm_rcx_read(vcpu); + u32 msr = kvm_rcx_read(vcpu); u64 data = kvm_read_edx_eax(vcpu); int r; - r = kvm_set_msr_with_filter(vcpu, ecx, data); + r = kvm_set_msr_with_filter(vcpu, msr, data); if (!r) { - trace_kvm_msr_write(ecx, data); + trace_kvm_msr_write(msr, data); } else { /* MSR write failed? See if we should ask user space */ - if (kvm_msr_user_space(vcpu, ecx, KVM_EXIT_X86_WRMSR, data, + if (kvm_msr_user_space(vcpu, msr, KVM_EXIT_X86_WRMSR, data, complete_fast_msr_access, r)) return 0; /* Signal all other negative errors to userspace */ if (r < 0) return r; - trace_kvm_msr_write_ex(ecx, data); + trace_kvm_msr_write_ex(msr, data); } return kvm_x86_call(complete_emulated_msr)(vcpu, r); From 87a877de367d835b527d1086f75727123ef85fc4 Mon Sep 17 00:00:00 2001 From: Xin Li Date: Tue, 5 Aug 2025 13:22:21 -0700 Subject: [PATCH 0367/2711] KVM: x86: Rename handle_fastpath_set_msr_irqoff() to handle_fastpath_wrmsr() Rename the WRMSR fastpath API to drop "irqoff", as that information is redundant (the fastpath always runs with IRQs disabled), and to prepare for adding a fastpath for the immediate variant of WRMSRNS. No functional change intended. Signed-off-by: Xin Li (Intel) [sean: split to separate patch, write changelog] Link: https://lore.kernel.org/r/20250805202224.1475590-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 2 +- arch/x86/kvm/vmx/vmx.c | 2 +- arch/x86/kvm/x86.c | 4 ++-- arch/x86/kvm/x86.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index f7e1e665a826..ca550c4fa174 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4197,7 +4197,7 @@ static fastpath_t svm_exit_handlers_fastpath(struct kvm_vcpu *vcpu) case SVM_EXIT_MSR: if (!control->exit_info_1) break; - return handle_fastpath_set_msr_irqoff(vcpu); + return handle_fastpath_wrmsr(vcpu); case SVM_EXIT_HLT: return handle_fastpath_hlt(vcpu); case SVM_EXIT_INVD: diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 95765db52992..ae2c8c10e5d2 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7170,7 +7170,7 @@ static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu, switch (vmx_get_exit_reason(vcpu).basic) { case EXIT_REASON_MSR_WRITE: - return handle_fastpath_set_msr_irqoff(vcpu); + return handle_fastpath_wrmsr(vcpu); case EXIT_REASON_PREEMPTION_TIMER: return handle_fastpath_preemption_timer(vcpu, force_immediate_exit); case EXIT_REASON_HLT: diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f7c5db3d2652..85e40d61d18b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2143,7 +2143,7 @@ static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu) kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending(); } -fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu) +fastpath_t handle_fastpath_wrmsr(struct kvm_vcpu *vcpu) { u64 data = kvm_read_edx_eax(vcpu); u32 msr = kvm_rcx_read(vcpu); @@ -2168,7 +2168,7 @@ fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu) return EXIT_FASTPATH_REENTER_GUEST; } -EXPORT_SYMBOL_GPL(handle_fastpath_set_msr_irqoff); +EXPORT_SYMBOL_GPL(handle_fastpath_wrmsr); /* * Adapt set_msr() to msr_io()'s calling convention diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 46220b04cdf2..2dab9c9d6199 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -437,7 +437,7 @@ int x86_decode_emulated_instruction(struct kvm_vcpu *vcpu, int emulation_type, void *insn, int insn_len); int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, int emulation_type, void *insn, int insn_len); -fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu); +fastpath_t handle_fastpath_wrmsr(struct kvm_vcpu *vcpu); fastpath_t handle_fastpath_hlt(struct kvm_vcpu *vcpu); fastpath_t handle_fastpath_invd(struct kvm_vcpu *vcpu); From 885df2d2109a60f84d84639ce6d95a91045f6c45 Mon Sep 17 00:00:00 2001 From: Xin Li Date: Tue, 5 Aug 2025 13:22:22 -0700 Subject: [PATCH 0368/2711] KVM: x86: Add support for RDMSR/WRMSRNS w/ immediate on Intel Add support for the immediate forms of RDMSR and WRMSRNS (currently Intel-only). The immediate variants are only valid in 64-bit mode, and use a single general purpose register for the data (the register is also encoded in the instruction, i.e. not implicit like regular RDMSR/WRMSR). The immediate variants are primarily motivated by performance, not code size: by having the MSR index in an immediate, it is available *much* earlier in the CPU pipeline, which allows hardware much more leeway about how a particular MSR is handled. Intel VMX support for the immediate forms of MSR accesses communicates exit information to the host as follows: 1) The immediate form of RDMSR uses VM-Exit Reason 84. 2) The immediate form of WRMSRNS uses VM-Exit Reason 85. 3) For both VM-Exit reasons 84 and 85, the Exit Qualification field is set to the MSR index that triggered the VM-Exit. 4) Bits 3 ~ 6 of the VM-Exit Instruction Information field are set to the register encoding used by the immediate form of the instruction, i.e. the destination register for RDMSR, and the source for WRMSRNS. 5) The VM-Exit Instruction Length field records the size of the immediate form of the MSR instruction. To deal with userspace RDMSR exits, stash the destination register in a new kvm_vcpu_arch field, similar to cui_linear_rip, pio, etc. Alternatively, the register could be saved in kvm_run.msr or re-retrieved from the VMCS, but the former would require sanitizing the value to ensure userspace doesn't clobber the value to an out-of-bounds index, and the latter would require a new one-off kvm_x86_ops hook. Don't bother adding support for the instructions in KVM's emulator, as the only way for RDMSR/WRMSR to be encountered is if KVM is emulating large swaths of code due to invalid guest state, and a vCPU cannot have invalid guest state while in 64-bit mode. Signed-off-by: Xin Li (Intel) [sean: minor tweaks, massage and expand changelog] Link: https://lore.kernel.org/r/20250805202224.1475590-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 3 ++ arch/x86/include/uapi/asm/vmx.h | 6 +++- arch/x86/kvm/vmx/nested.c | 13 ++++++-- arch/x86/kvm/vmx/vmx.c | 21 +++++++++++++ arch/x86/kvm/vmx/vmx.h | 5 +++ arch/x86/kvm/x86.c | 55 +++++++++++++++++++++++++++------ 6 files changed, 90 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index d7680612ba1e..dbdec6025fde 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -929,6 +929,7 @@ struct kvm_vcpu_arch { bool emulate_regs_need_sync_from_vcpu; int (*complete_userspace_io)(struct kvm_vcpu *vcpu); unsigned long cui_linear_rip; + int cui_rdmsr_imm_reg; gpa_t time; s8 pvclock_tsc_shift; @@ -2158,7 +2159,9 @@ int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, bool host_initiat int kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data); int kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data); int kvm_emulate_rdmsr(struct kvm_vcpu *vcpu); +int kvm_emulate_rdmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg); int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu); +int kvm_emulate_wrmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg); int kvm_emulate_as_nop(struct kvm_vcpu *vcpu); int kvm_emulate_invd(struct kvm_vcpu *vcpu); int kvm_emulate_mwait(struct kvm_vcpu *vcpu); diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h index f0f4a4cf84a7..9792e329343e 100644 --- a/arch/x86/include/uapi/asm/vmx.h +++ b/arch/x86/include/uapi/asm/vmx.h @@ -94,6 +94,8 @@ #define EXIT_REASON_BUS_LOCK 74 #define EXIT_REASON_NOTIFY 75 #define EXIT_REASON_TDCALL 77 +#define EXIT_REASON_MSR_READ_IMM 84 +#define EXIT_REASON_MSR_WRITE_IMM 85 #define VMX_EXIT_REASONS \ { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ @@ -158,7 +160,9 @@ { EXIT_REASON_TPAUSE, "TPAUSE" }, \ { EXIT_REASON_BUS_LOCK, "BUS_LOCK" }, \ { EXIT_REASON_NOTIFY, "NOTIFY" }, \ - { EXIT_REASON_TDCALL, "TDCALL" } + { EXIT_REASON_TDCALL, "TDCALL" }, \ + { EXIT_REASON_MSR_READ_IMM, "MSR_READ_IMM" }, \ + { EXIT_REASON_MSR_WRITE_IMM, "MSR_WRITE_IMM" } #define VMX_EXIT_REASON_FLAGS \ { VMX_EXIT_REASONS_FAILED_VMENTRY, "FAILED_VMENTRY" } diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index db2fd4eedc90..798776dddd43 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -6216,19 +6216,26 @@ static bool nested_vmx_exit_handled_msr(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, union vmx_exit_reason exit_reason) { - u32 msr_index = kvm_rcx_read(vcpu); + u32 msr_index; gpa_t bitmap; if (!nested_cpu_has(vmcs12, CPU_BASED_USE_MSR_BITMAPS)) return true; + if (exit_reason.basic == EXIT_REASON_MSR_READ_IMM || + exit_reason.basic == EXIT_REASON_MSR_WRITE_IMM) + msr_index = vmx_get_exit_qual(vcpu); + else + msr_index = kvm_rcx_read(vcpu); + /* * The MSR_BITMAP page is divided into four 1024-byte bitmaps, * for the four combinations of read/write and low/high MSR numbers. * First we need to figure out which of the four to use: */ bitmap = vmcs12->msr_bitmap; - if (exit_reason.basic == EXIT_REASON_MSR_WRITE) + if (exit_reason.basic == EXIT_REASON_MSR_WRITE || + exit_reason.basic == EXIT_REASON_MSR_WRITE_IMM) bitmap += 2048; if (msr_index >= 0xc0000000) { msr_index -= 0xc0000000; @@ -6527,6 +6534,8 @@ static bool nested_vmx_l1_wants_exit(struct kvm_vcpu *vcpu, return nested_cpu_has2(vmcs12, SECONDARY_EXEC_DESC); case EXIT_REASON_MSR_READ: case EXIT_REASON_MSR_WRITE: + case EXIT_REASON_MSR_READ_IMM: + case EXIT_REASON_MSR_WRITE_IMM: return nested_vmx_exit_handled_msr(vcpu, vmcs12, exit_reason); case EXIT_REASON_INVALID_STATE: return true; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index ae2c8c10e5d2..44423d5f0e27 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6003,6 +6003,23 @@ static int handle_notify(struct kvm_vcpu *vcpu) return 1; } +static int vmx_get_msr_imm_reg(struct kvm_vcpu *vcpu) +{ + return vmx_get_instr_info_reg(vmcs_read32(VMX_INSTRUCTION_INFO)); +} + +static int handle_rdmsr_imm(struct kvm_vcpu *vcpu) +{ + return kvm_emulate_rdmsr_imm(vcpu, vmx_get_exit_qual(vcpu), + vmx_get_msr_imm_reg(vcpu)); +} + +static int handle_wrmsr_imm(struct kvm_vcpu *vcpu) +{ + return kvm_emulate_wrmsr_imm(vcpu, vmx_get_exit_qual(vcpu), + vmx_get_msr_imm_reg(vcpu)); +} + /* * The exit handlers return 1 if the exit was handled fully and guest execution * may resume. Otherwise they set the kvm_run parameter to indicate what needs @@ -6061,6 +6078,8 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { [EXIT_REASON_ENCLS] = handle_encls, [EXIT_REASON_BUS_LOCK] = handle_bus_lock_vmexit, [EXIT_REASON_NOTIFY] = handle_notify, + [EXIT_REASON_MSR_READ_IMM] = handle_rdmsr_imm, + [EXIT_REASON_MSR_WRITE_IMM] = handle_wrmsr_imm, }; static const int kvm_vmx_max_exit_handlers = @@ -6495,6 +6514,8 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath) #ifdef CONFIG_MITIGATION_RETPOLINE if (exit_reason.basic == EXIT_REASON_MSR_WRITE) return kvm_emulate_wrmsr(vcpu); + else if (exit_reason.basic == EXIT_REASON_MSR_WRITE_IMM) + return handle_wrmsr_imm(vcpu); else if (exit_reason.basic == EXIT_REASON_PREEMPTION_TIMER) return handle_preemption_timer(vcpu); else if (exit_reason.basic == EXIT_REASON_INTERRUPT_WINDOW) diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index d3389baf3ab3..24d65dac5e89 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -706,6 +706,11 @@ static inline bool vmx_guest_state_valid(struct kvm_vcpu *vcpu) void dump_vmcs(struct kvm_vcpu *vcpu); +static inline int vmx_get_instr_info_reg(u32 vmx_instr_info) +{ + return (vmx_instr_info >> 3) & 0xf; +} + static inline int vmx_get_instr_info_reg2(u32 vmx_instr_info) { return (vmx_instr_info >> 28) & 0xf; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 85e40d61d18b..efd45b2e8f45 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1991,6 +1991,15 @@ static int complete_fast_rdmsr(struct kvm_vcpu *vcpu) return complete_fast_msr_access(vcpu); } +static int complete_fast_rdmsr_imm(struct kvm_vcpu *vcpu) +{ + if (!vcpu->run->msr.error) + kvm_register_write(vcpu, vcpu->arch.cui_rdmsr_imm_reg, + vcpu->run->msr.data); + + return complete_fast_msr_access(vcpu); +} + static u64 kvm_msr_reason(int r) { switch (r) { @@ -2025,39 +2034,53 @@ static int kvm_msr_user_space(struct kvm_vcpu *vcpu, u32 index, return 1; } -int kvm_emulate_rdmsr(struct kvm_vcpu *vcpu) +static int __kvm_emulate_rdmsr(struct kvm_vcpu *vcpu, u32 msr, int reg, + int (*complete_rdmsr)(struct kvm_vcpu *)) { - u32 msr = kvm_rcx_read(vcpu); u64 data; int r; r = kvm_get_msr_with_filter(vcpu, msr, &data); - if (!r) { trace_kvm_msr_read(msr, data); - kvm_rax_write(vcpu, data & -1u); - kvm_rdx_write(vcpu, (data >> 32) & -1u); + if (reg < 0) { + kvm_rax_write(vcpu, data & -1u); + kvm_rdx_write(vcpu, (data >> 32) & -1u); + } else { + kvm_register_write(vcpu, reg, data); + } } else { /* MSR read failed? See if we should ask user space */ if (kvm_msr_user_space(vcpu, msr, KVM_EXIT_X86_RDMSR, 0, - complete_fast_rdmsr, r)) + complete_rdmsr, r)) return 0; trace_kvm_msr_read_ex(msr); } return kvm_x86_call(complete_emulated_msr)(vcpu, r); } + +int kvm_emulate_rdmsr(struct kvm_vcpu *vcpu) +{ + return __kvm_emulate_rdmsr(vcpu, kvm_rcx_read(vcpu), -1, + complete_fast_rdmsr); +} EXPORT_SYMBOL_GPL(kvm_emulate_rdmsr); -int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu) +int kvm_emulate_rdmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg) +{ + vcpu->arch.cui_rdmsr_imm_reg = reg; + + return __kvm_emulate_rdmsr(vcpu, msr, reg, complete_fast_rdmsr_imm); +} +EXPORT_SYMBOL_GPL(kvm_emulate_rdmsr_imm); + +static int __kvm_emulate_wrmsr(struct kvm_vcpu *vcpu, u32 msr, u64 data) { - u32 msr = kvm_rcx_read(vcpu); - u64 data = kvm_read_edx_eax(vcpu); int r; r = kvm_set_msr_with_filter(vcpu, msr, data); - if (!r) { trace_kvm_msr_write(msr, data); } else { @@ -2073,8 +2096,20 @@ int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu) return kvm_x86_call(complete_emulated_msr)(vcpu, r); } + +int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu) +{ + return __kvm_emulate_wrmsr(vcpu, kvm_rcx_read(vcpu), + kvm_read_edx_eax(vcpu)); +} EXPORT_SYMBOL_GPL(kvm_emulate_wrmsr); +int kvm_emulate_wrmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg) +{ + return __kvm_emulate_wrmsr(vcpu, msr, kvm_register_read(vcpu, reg)); +} +EXPORT_SYMBOL_GPL(kvm_emulate_wrmsr_imm); + int kvm_emulate_as_nop(struct kvm_vcpu *vcpu) { return kvm_skip_emulated_instruction(vcpu); From ec93675a325191c95bc322a4471c2f194f7211fc Mon Sep 17 00:00:00 2001 From: Xin Li Date: Tue, 5 Aug 2025 13:22:23 -0700 Subject: [PATCH 0369/2711] KVM: VMX: Support the immediate form of WRMSRNS in the VM-Exit fastpath Add support for handling "WRMSRNS with an immediate" VM-Exits in KVM's fastpath. On Intel, all writes to the x2APIC ICR and to the TSC Deadline MSR are non-serializing, i.e. it's highly likely guest kernels will switch to using WRMSRNS when possible. And in general, any MSR written via WRMSRNS is probably worth handling in the fastpath, as the entire point of WRMSRNS is to shave cycles in hot paths. Signed-off-by: Xin Li (Intel) [sean: rewrite changelog, split rename to separate patch] Link: https://lore.kernel.org/r/20250805202224.1475590-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 3 +++ arch/x86/kvm/x86.c | 17 +++++++++++++---- arch/x86/kvm/x86.h | 1 + 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 44423d5f0e27..a3f0d458be9d 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7192,6 +7192,9 @@ static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu, switch (vmx_get_exit_reason(vcpu).basic) { case EXIT_REASON_MSR_WRITE: return handle_fastpath_wrmsr(vcpu); + case EXIT_REASON_MSR_WRITE_IMM: + return handle_fastpath_wrmsr_imm(vcpu, vmx_get_exit_qual(vcpu), + vmx_get_msr_imm_reg(vcpu)); case EXIT_REASON_PREEMPTION_TIMER: return handle_fastpath_preemption_timer(vcpu, force_immediate_exit); case EXIT_REASON_HLT: diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index efd45b2e8f45..b47a6a4ced15 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2178,11 +2178,8 @@ static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu) kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending(); } -fastpath_t handle_fastpath_wrmsr(struct kvm_vcpu *vcpu) +static fastpath_t __handle_fastpath_wrmsr(struct kvm_vcpu *vcpu, u32 msr, u64 data) { - u64 data = kvm_read_edx_eax(vcpu); - u32 msr = kvm_rcx_read(vcpu); - switch (msr) { case APIC_BASE_MSR + (APIC_ICR >> 4): if (!lapic_in_kernel(vcpu) || !apic_x2apic_mode(vcpu->arch.apic) || @@ -2203,8 +2200,20 @@ fastpath_t handle_fastpath_wrmsr(struct kvm_vcpu *vcpu) return EXIT_FASTPATH_REENTER_GUEST; } + +fastpath_t handle_fastpath_wrmsr(struct kvm_vcpu *vcpu) +{ + return __handle_fastpath_wrmsr(vcpu, kvm_rcx_read(vcpu), + kvm_read_edx_eax(vcpu)); +} EXPORT_SYMBOL_GPL(handle_fastpath_wrmsr); +fastpath_t handle_fastpath_wrmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg) +{ + return __handle_fastpath_wrmsr(vcpu, msr, kvm_register_read(vcpu, reg)); +} +EXPORT_SYMBOL_GPL(handle_fastpath_wrmsr_imm); + /* * Adapt set_msr() to msr_io()'s calling convention */ diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 2dab9c9d6199..eb3088684e8a 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -438,6 +438,7 @@ int x86_decode_emulated_instruction(struct kvm_vcpu *vcpu, int emulation_type, int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, int emulation_type, void *insn, int insn_len); fastpath_t handle_fastpath_wrmsr(struct kvm_vcpu *vcpu); +fastpath_t handle_fastpath_wrmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg); fastpath_t handle_fastpath_hlt(struct kvm_vcpu *vcpu); fastpath_t handle_fastpath_invd(struct kvm_vcpu *vcpu); From d90ebf5a06ecc6d4d7f72d12c5029519af8f838d Mon Sep 17 00:00:00 2001 From: Xin Li Date: Tue, 5 Aug 2025 13:22:24 -0700 Subject: [PATCH 0370/2711] KVM: x86: Advertise support for the immediate form of MSR instructions Advertise support for the immediate form of MSR instructions to userspace if the instructions are supported by the underlying CPU, and KVM is using VMX, i.e. is running on an Intel-compatible CPU. For SVM, explicitly clear X86_FEATURE_MSR_IMM to ensure KVM doesn't over- report support if AMD-compatible CPUs ever implement the immediate forms, as SVM will likely require explicit enablement in KVM. Signed-off-by: Xin Li (Intel) [sean: massage changelog] Link: https://lore.kernel.org/r/20250805202224.1475590-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/cpuid.c | 6 +++++- arch/x86/kvm/reverse_cpuid.h | 5 +++++ arch/x86/kvm/svm/svm.c | 6 +++++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index dbdec6025fde..735b5d1e62dd 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -774,6 +774,7 @@ enum kvm_only_cpuid_leafs { CPUID_7_2_EDX, CPUID_24_0_EBX, CPUID_8000_0021_ECX, + CPUID_7_1_ECX, NR_KVM_CPU_CAPS, NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS, diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index bee8c869259f..2705545f67fe 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -985,6 +985,10 @@ void kvm_set_cpu_caps(void) F(LAM), ); + kvm_cpu_cap_init(CPUID_7_1_ECX, + SCATTERED_F(MSR_IMM), + ); + kvm_cpu_cap_init(CPUID_7_1_EDX, F(AVX_VNNI_INT8), F(AVX_NE_CONVERT), @@ -1411,9 +1415,9 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) goto out; cpuid_entry_override(entry, CPUID_7_1_EAX); + cpuid_entry_override(entry, CPUID_7_1_ECX); cpuid_entry_override(entry, CPUID_7_1_EDX); entry->ebx = 0; - entry->ecx = 0; } if (max_idx >= 2) { entry = do_host_cpuid(array, function, 2); diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h index c53b92379e6e..743ab25ba787 100644 --- a/arch/x86/kvm/reverse_cpuid.h +++ b/arch/x86/kvm/reverse_cpuid.h @@ -25,6 +25,9 @@ #define KVM_X86_FEATURE_SGX2 KVM_X86_FEATURE(CPUID_12_EAX, 1) #define KVM_X86_FEATURE_SGX_EDECCSSA KVM_X86_FEATURE(CPUID_12_EAX, 11) +/* Intel-defined sub-features, CPUID level 0x00000007:1 (ECX) */ +#define KVM_X86_FEATURE_MSR_IMM KVM_X86_FEATURE(CPUID_7_1_ECX, 5) + /* Intel-defined sub-features, CPUID level 0x00000007:1 (EDX) */ #define X86_FEATURE_AVX_VNNI_INT8 KVM_X86_FEATURE(CPUID_7_1_EDX, 4) #define X86_FEATURE_AVX_NE_CONVERT KVM_X86_FEATURE(CPUID_7_1_EDX, 5) @@ -87,6 +90,7 @@ static const struct cpuid_reg reverse_cpuid[] = { [CPUID_7_2_EDX] = { 7, 2, CPUID_EDX}, [CPUID_24_0_EBX] = { 0x24, 0, CPUID_EBX}, [CPUID_8000_0021_ECX] = {0x80000021, 0, CPUID_ECX}, + [CPUID_7_1_ECX] = { 7, 1, CPUID_ECX}, }; /* @@ -128,6 +132,7 @@ static __always_inline u32 __feature_translate(int x86_feature) KVM_X86_TRANSLATE_FEATURE(BHI_CTRL); KVM_X86_TRANSLATE_FEATURE(TSA_SQ_NO); KVM_X86_TRANSLATE_FEATURE(TSA_L1_NO); + KVM_X86_TRANSLATE_FEATURE(MSR_IMM); default: return x86_feature; } diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index ca550c4fa174..7e7821ee8ee1 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5311,8 +5311,12 @@ static __init void svm_set_cpu_caps(void) /* CPUID 0x8000001F (SME/SEV features) */ sev_set_cpu_caps(); - /* Don't advertise Bus Lock Detect to guest if SVM support is absent */ + /* + * Clear capabilities that are automatically configured by common code, + * but that require explicit SVM support (that isn't yet implemented). + */ kvm_cpu_cap_clear(X86_FEATURE_BUS_LOCK_DETECT); + kvm_cpu_cap_clear(X86_FEATURE_MSR_IMM); } static __init int svm_hardware_setup(void) From d2dcf25a4cf2d9058a866c2237884287209b8d19 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Mon, 11 Aug 2025 19:55:09 -0700 Subject: [PATCH 0371/2711] KVM: x86: Rename kvm_{g,s}et_msr()* to show that they emulate guest accesses Rename kvm_{g,s}et_msr_with_filter() kvm_{g,s}et_msr() to kvm_emulate_msr_{read,write} __kvm_emulate_msr_{read,write} to make it more obvious that KVM uses these helpers to emulate guest behaviors, i.e., host_initiated == false in these helpers. Suggested-by: Sean Christopherson Suggested-by: Chao Gao Signed-off-by: Yang Weijiang Reviewed-by: Maxim Levitsky Reviewed-by: Chao Gao Tested-by: Mathias Krause Tested-by: John Allen Signed-off-by: Chao Gao Tested-by: Rick Edgecombe Link: https://lore.kernel.org/r/20250812025606.74625-2-chao.gao@intel.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 8 ++++---- arch/x86/kvm/smm.c | 4 ++-- arch/x86/kvm/vmx/nested.c | 14 +++++++------- arch/x86/kvm/x86.c | 27 ++++++++++++++------------- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 735b5d1e62dd..3f59554df6b1 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2154,11 +2154,11 @@ void kvm_prepare_event_vectoring_exit(struct kvm_vcpu *vcpu, gpa_t gpa); void kvm_enable_efer_bits(u64); bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer); -int kvm_get_msr_with_filter(struct kvm_vcpu *vcpu, u32 index, u64 *data); -int kvm_set_msr_with_filter(struct kvm_vcpu *vcpu, u32 index, u64 data); +int kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data); +int kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data); int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, bool host_initiated); -int kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data); -int kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data); +int __kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data); +int __kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data); int kvm_emulate_rdmsr(struct kvm_vcpu *vcpu); int kvm_emulate_rdmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg); int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/smm.c b/arch/x86/kvm/smm.c index 9864c057187d..5dd8a1646800 100644 --- a/arch/x86/kvm/smm.c +++ b/arch/x86/kvm/smm.c @@ -529,7 +529,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, vcpu->arch.smbase = smstate->smbase; - if (kvm_set_msr(vcpu, MSR_EFER, smstate->efer & ~EFER_LMA)) + if (__kvm_emulate_msr_write(vcpu, MSR_EFER, smstate->efer & ~EFER_LMA)) return X86EMUL_UNHANDLEABLE; rsm_load_seg_64(vcpu, &smstate->tr, VCPU_SREG_TR); @@ -620,7 +620,7 @@ int emulator_leave_smm(struct x86_emulate_ctxt *ctxt) /* And finally go back to 32-bit mode. */ efer = 0; - kvm_set_msr(vcpu, MSR_EFER, efer); + __kvm_emulate_msr_write(vcpu, MSR_EFER, efer); } #endif diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 798776dddd43..2156c9a854f4 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -997,7 +997,7 @@ static u32 nested_vmx_load_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count) __func__, i, e.index, e.reserved); goto fail; } - if (kvm_set_msr_with_filter(vcpu, e.index, e.value)) { + if (kvm_emulate_msr_write(vcpu, e.index, e.value)) { pr_debug_ratelimited( "%s cannot write MSR (%u, 0x%x, 0x%llx)\n", __func__, i, e.index, e.value); @@ -1033,7 +1033,7 @@ static bool nested_vmx_get_vmexit_msr_value(struct kvm_vcpu *vcpu, } } - if (kvm_get_msr_with_filter(vcpu, msr_index, data)) { + if (kvm_emulate_msr_read(vcpu, msr_index, data)) { pr_debug_ratelimited("%s cannot read MSR (0x%x)\n", __func__, msr_index); return false; @@ -2770,8 +2770,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL) && kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu)) && - WARN_ON_ONCE(kvm_set_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL, - vmcs12->guest_ia32_perf_global_ctrl))) { + WARN_ON_ONCE(__kvm_emulate_msr_write(vcpu, MSR_CORE_PERF_GLOBAL_CTRL, + vmcs12->guest_ia32_perf_global_ctrl))) { *entry_failure_code = ENTRY_FAIL_DEFAULT; return -EINVAL; } @@ -4758,8 +4758,8 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, } if ((vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) && kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu))) - WARN_ON_ONCE(kvm_set_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL, - vmcs12->host_ia32_perf_global_ctrl)); + WARN_ON_ONCE(__kvm_emulate_msr_write(vcpu, MSR_CORE_PERF_GLOBAL_CTRL, + vmcs12->host_ia32_perf_global_ctrl)); /* Set L1 segment info according to Intel SDM 27.5.2 Loading Host Segment and Descriptor-Table Registers */ @@ -4937,7 +4937,7 @@ static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu) goto vmabort; } - if (kvm_set_msr_with_filter(vcpu, h.index, h.value)) { + if (kvm_emulate_msr_write(vcpu, h.index, h.value)) { pr_debug_ratelimited( "%s WRMSR failed (%u, 0x%x, 0x%llx)\n", __func__, j, h.index, h.value); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b47a6a4ced15..e1eff02f37c7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1933,33 +1933,33 @@ static int kvm_get_msr_ignored_check(struct kvm_vcpu *vcpu, __kvm_get_msr); } -int kvm_get_msr_with_filter(struct kvm_vcpu *vcpu, u32 index, u64 *data) +int kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data) { if (!kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_READ)) return KVM_MSR_RET_FILTERED; return kvm_get_msr_ignored_check(vcpu, index, data, false); } -EXPORT_SYMBOL_GPL(kvm_get_msr_with_filter); +EXPORT_SYMBOL_GPL(kvm_emulate_msr_read); -int kvm_set_msr_with_filter(struct kvm_vcpu *vcpu, u32 index, u64 data) +int kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data) { if (!kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_WRITE)) return KVM_MSR_RET_FILTERED; return kvm_set_msr_ignored_check(vcpu, index, data, false); } -EXPORT_SYMBOL_GPL(kvm_set_msr_with_filter); +EXPORT_SYMBOL_GPL(kvm_emulate_msr_write); -int kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data) +int __kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data) { return kvm_get_msr_ignored_check(vcpu, index, data, false); } -EXPORT_SYMBOL_GPL(kvm_get_msr); +EXPORT_SYMBOL_GPL(__kvm_emulate_msr_read); -int kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data) +int __kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data) { return kvm_set_msr_ignored_check(vcpu, index, data, false); } -EXPORT_SYMBOL_GPL(kvm_set_msr); +EXPORT_SYMBOL_GPL(__kvm_emulate_msr_write); static void complete_userspace_rdmsr(struct kvm_vcpu *vcpu) { @@ -2040,7 +2040,8 @@ static int __kvm_emulate_rdmsr(struct kvm_vcpu *vcpu, u32 msr, int reg, u64 data; int r; - r = kvm_get_msr_with_filter(vcpu, msr, &data); + r = kvm_emulate_msr_read(vcpu, msr, &data); + if (!r) { trace_kvm_msr_read(msr, data); @@ -2080,7 +2081,7 @@ static int __kvm_emulate_wrmsr(struct kvm_vcpu *vcpu, u32 msr, u64 data) { int r; - r = kvm_set_msr_with_filter(vcpu, msr, data); + r = kvm_emulate_msr_write(vcpu, msr, data); if (!r) { trace_kvm_msr_write(msr, data); } else { @@ -8366,7 +8367,7 @@ static int emulator_get_msr_with_filter(struct x86_emulate_ctxt *ctxt, struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); int r; - r = kvm_get_msr_with_filter(vcpu, msr_index, pdata); + r = kvm_emulate_msr_read(vcpu, msr_index, pdata); if (r < 0) return X86EMUL_UNHANDLEABLE; @@ -8389,7 +8390,7 @@ static int emulator_set_msr_with_filter(struct x86_emulate_ctxt *ctxt, struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); int r; - r = kvm_set_msr_with_filter(vcpu, msr_index, data); + r = kvm_emulate_msr_write(vcpu, msr_index, data); if (r < 0) return X86EMUL_UNHANDLEABLE; @@ -8409,7 +8410,7 @@ static int emulator_set_msr_with_filter(struct x86_emulate_ctxt *ctxt, static int emulator_get_msr(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata) { - return kvm_get_msr(emul_to_vcpu(ctxt), msr_index, pdata); + return __kvm_emulate_msr_read(emul_to_vcpu(ctxt), msr_index, pdata); } static int emulator_check_rdpmc_early(struct x86_emulate_ctxt *ctxt, u32 pmc) From db07f3d0eb19663d8fb61b40c19b26703c9a1b1a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 11 Aug 2025 19:55:10 -0700 Subject: [PATCH 0372/2711] KVM: x86: Use double-underscore read/write MSR helpers as appropriate Use the double-underscore helpers for emulating MSR reads and writes in he no-underscore versions to better capture the relationship between the two sets of APIs (the double-underscore versions don't honor userspace MSR filters). No functional change intended. Signed-off-by: Chao Gao Tested-by: Rick Edgecombe Link: https://lore.kernel.org/r/20250812025606.74625-3-chao.gao@intel.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e1eff02f37c7..52ad2d2f41cb 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1933,22 +1933,6 @@ static int kvm_get_msr_ignored_check(struct kvm_vcpu *vcpu, __kvm_get_msr); } -int kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data) -{ - if (!kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_READ)) - return KVM_MSR_RET_FILTERED; - return kvm_get_msr_ignored_check(vcpu, index, data, false); -} -EXPORT_SYMBOL_GPL(kvm_emulate_msr_read); - -int kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data) -{ - if (!kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_WRITE)) - return KVM_MSR_RET_FILTERED; - return kvm_set_msr_ignored_check(vcpu, index, data, false); -} -EXPORT_SYMBOL_GPL(kvm_emulate_msr_write); - int __kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data) { return kvm_get_msr_ignored_check(vcpu, index, data, false); @@ -1961,6 +1945,25 @@ int __kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data) } EXPORT_SYMBOL_GPL(__kvm_emulate_msr_write); +int kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data) +{ + if (!kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_READ)) + return KVM_MSR_RET_FILTERED; + + return __kvm_emulate_msr_read(vcpu, index, data); +} +EXPORT_SYMBOL_GPL(kvm_emulate_msr_read); + +int kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data) +{ + if (!kvm_msr_allowed(vcpu, index, KVM_MSR_FILTER_WRITE)) + return KVM_MSR_RET_FILTERED; + + return __kvm_emulate_msr_write(vcpu, index, data); +} +EXPORT_SYMBOL_GPL(kvm_emulate_msr_write); + + static void complete_userspace_rdmsr(struct kvm_vcpu *vcpu) { if (!vcpu->run->msr.error) { From c2aa58b226abf5ac6d355fb1f3b7c4284a7b5cab Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Mon, 11 Aug 2025 19:55:11 -0700 Subject: [PATCH 0373/2711] KVM: x86: Add kvm_msr_{read,write}() helpers Wrap __kvm_{get,set}_msr() into two new helpers for KVM usage and use the helpers to replace existing usage of the raw functions. kvm_msr_{read,write}() are KVM-internal helpers, i.e. used when KVM needs to get/set a MSR value for emulating CPU behavior, i.e., host_initiated == %true in the helpers. Suggested-by: Sean Christopherson Signed-off-by: Yang Weijiang Reviewed-by: Maxim Levitsky Tested-by: Mathias Krause Tested-by: John Allen Signed-off-by: Chao Gao Tested-by: Rick Edgecombe Link: https://lore.kernel.org/r/20250812025606.74625-4-chao.gao@intel.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 3 ++- arch/x86/kvm/cpuid.c | 2 +- arch/x86/kvm/x86.c | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 3f59554df6b1..b1f87b5750f8 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2156,9 +2156,10 @@ void kvm_enable_efer_bits(u64); bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer); int kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data); int kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data); -int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, bool host_initiated); int __kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data); int __kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data); +int kvm_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data); +int kvm_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data); int kvm_emulate_rdmsr(struct kvm_vcpu *vcpu); int kvm_emulate_rdmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg); int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 2705545f67fe..ad6cadf09930 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -2006,7 +2006,7 @@ bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, if (function == 7 && index == 0) { u64 data; if ((*ebx & (feature_bit(RTM) | feature_bit(HLE))) && - !__kvm_get_msr(vcpu, MSR_IA32_TSX_CTRL, &data, true) && + !kvm_msr_read(vcpu, MSR_IA32_TSX_CTRL, &data) && (data & TSX_CTRL_CPUID_CLEAR)) *ebx &= ~(feature_bit(RTM) | feature_bit(HLE)); } else if (function == 0x80000007) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 52ad2d2f41cb..59a431dce015 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1899,8 +1899,8 @@ static int kvm_set_msr_ignored_check(struct kvm_vcpu *vcpu, * Returns 0 on success, non-0 otherwise. * Assumes vcpu_load() was already called. */ -int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, - bool host_initiated) +static int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, + bool host_initiated) { struct msr_data msr; int ret; @@ -1926,6 +1926,16 @@ int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, return ret; } +int kvm_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data) +{ + return __kvm_set_msr(vcpu, index, data, true); +} + +int kvm_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data) +{ + return __kvm_get_msr(vcpu, index, data, true); +} + static int kvm_get_msr_ignored_check(struct kvm_vcpu *vcpu, u32 index, u64 *data, bool host_initiated) { @@ -12472,7 +12482,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) MSR_IA32_MISC_ENABLE_BTS_UNAVAIL; __kvm_set_xcr(vcpu, 0, XFEATURE_MASK_FP); - __kvm_set_msr(vcpu, MSR_IA32_XSS, 0, true); + kvm_msr_write(vcpu, MSR_IA32_XSS, 0); } /* All GPRs except RDX (handled below) are zeroed on RESET/INIT. */ From 41f6710f99f4337924e3929e8e7a51c74f800b91 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 11 Aug 2025 19:55:12 -0700 Subject: [PATCH 0374/2711] KVM: x86: Manually clear MPX state only on INIT Don't manually clear/zero MPX state on RESET, as the guest FPU state is zero allocated and KVM only does RESET during vCPU creation, i.e. the relevant state is guaranteed to be all zeroes. Opportunistically move the relevant code into a helper in anticipation of adding support for CET shadow stacks, which also has state that is zeroed on INIT. Signed-off-by: Yang Weijiang Tested-by: Mathias Krause Tested-by: John Allen Signed-off-by: Chao Gao Tested-by: Rick Edgecombe Link: https://lore.kernel.org/r/20250812025606.74625-5-chao.gao@intel.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 59a431dce015..d398ee84c8f3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -12398,6 +12398,35 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) kvfree(vcpu->arch.cpuid_entries); } +static void kvm_xstate_reset(struct kvm_vcpu *vcpu, bool init_event) +{ + struct fpstate *fpstate = vcpu->arch.guest_fpu.fpstate; + + /* + * Guest FPU state is zero allocated and so doesn't need to be manually + * cleared on RESET, i.e. during vCPU creation. + */ + if (!init_event || !fpstate) + return; + + /* + * On INIT, only select XSTATE components are zeroed, most components + * are unchanged. Currently, the only components that are zeroed and + * supported by KVM are MPX related. + */ + if (!kvm_mpx_supported()) + return; + + /* + * All paths that lead to INIT are required to load the guest's FPU + * state (because most paths are buried in KVM_RUN). + */ + kvm_put_guest_fpu(vcpu); + fpstate_clear_xstate_component(fpstate, XFEATURE_BNDREGS); + fpstate_clear_xstate_component(fpstate, XFEATURE_BNDCSR); + kvm_load_guest_fpu(vcpu); +} + void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) { struct kvm_cpuid_entry2 *cpuid_0x1; @@ -12455,22 +12484,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) kvm_async_pf_hash_reset(vcpu); vcpu->arch.apf.halted = false; - if (vcpu->arch.guest_fpu.fpstate && kvm_mpx_supported()) { - struct fpstate *fpstate = vcpu->arch.guest_fpu.fpstate; - - /* - * All paths that lead to INIT are required to load the guest's - * FPU state (because most paths are buried in KVM_RUN). - */ - if (init_event) - kvm_put_guest_fpu(vcpu); - - fpstate_clear_xstate_component(fpstate, XFEATURE_BNDREGS); - fpstate_clear_xstate_component(fpstate, XFEATURE_BNDCSR); - - if (init_event) - kvm_load_guest_fpu(vcpu); - } + kvm_xstate_reset(vcpu, init_event); if (!init_event) { vcpu->arch.smbase = 0x30000; From c26675447faff8c4ddc1dc5d2cd28326b8181aaf Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Mon, 11 Aug 2025 19:55:13 -0700 Subject: [PATCH 0375/2711] KVM: x86: Zero XSTATE components on INIT by iterating over supported features Tweak the code a bit to facilitate resetting more xstate components in the future, e.g., CET's xstate-managed MSRs. No functional change intended. Suggested-by: Sean Christopherson Tested-by: Mathias Krause Tested-by: John Allen Signed-off-by: Chao Gao Tested-by: Rick Edgecombe Link: https://lore.kernel.org/r/20250812025606.74625-6-chao.gao@intel.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d398ee84c8f3..8bfba7d8f750 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -12401,6 +12401,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) static void kvm_xstate_reset(struct kvm_vcpu *vcpu, bool init_event) { struct fpstate *fpstate = vcpu->arch.guest_fpu.fpstate; + u64 xfeatures_mask; + int i; /* * Guest FPU state is zero allocated and so doesn't need to be manually @@ -12414,16 +12416,20 @@ static void kvm_xstate_reset(struct kvm_vcpu *vcpu, bool init_event) * are unchanged. Currently, the only components that are zeroed and * supported by KVM are MPX related. */ - if (!kvm_mpx_supported()) + xfeatures_mask = (kvm_caps.supported_xcr0 | kvm_caps.supported_xss) & + (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); + if (!xfeatures_mask) return; + BUILD_BUG_ON(sizeof(xfeatures_mask) * BITS_PER_BYTE <= XFEATURE_MAX); + /* * All paths that lead to INIT are required to load the guest's FPU * state (because most paths are buried in KVM_RUN). */ kvm_put_guest_fpu(vcpu); - fpstate_clear_xstate_component(fpstate, XFEATURE_BNDREGS); - fpstate_clear_xstate_component(fpstate, XFEATURE_BNDCSR); + for_each_set_bit(i, (unsigned long *)&xfeatures_mask, XFEATURE_MAX) + fpstate_clear_xstate_component(fpstate, i); kvm_load_guest_fpu(vcpu); } From 148bda0cfeae913b1212c4c683e6d3f6ae1a5e69 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 30 Jun 2025 21:21:31 +0200 Subject: [PATCH 0376/2711] clk: renesas: r9a08g045: Add I3C clocks and resets Extracted from the BSP driver and rebased. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250630192438.38311-2-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g045-cpg.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c index ed0661997928..643dec45e39d 100644 --- a/drivers/clk/renesas/r9a08g045-cpg.c +++ b/drivers/clk/renesas/r9a08g045-cpg.c @@ -183,6 +183,7 @@ static const struct cpg_core_clk r9a08g045_core_clks[] __initconst = { DEF_G3S_DIV("P3", R9A08G045_CLK_P3, CLK_PLL3_DIV2_4, DIVPL3C, G3S_DIVPL3C_STS, dtable_1_32, 0, 0, 0, NULL), DEF_FIXED("P3_DIV2", CLK_P3_DIV2, R9A08G045_CLK_P3, 1, 2), + DEF_FIXED("P5", R9A08G045_CLK_P5, CLK_PLL2_DIV2, 1, 4), DEF_FIXED("ZT", R9A08G045_CLK_ZT, CLK_PLL3_DIV2_8, 1, 1), DEF_FIXED("S0", R9A08G045_CLK_S0, CLK_SEL_PLL4, 1, 2), DEF_FIXED("OSC", R9A08G045_OSCCLK, CLK_EXTAL, 1, 1), @@ -291,6 +292,10 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = { MSTOP(BUS_MCPU2, BIT(14))), DEF_MOD("tsu_pclk", R9A08G045_TSU_PCLK, R9A08G045_CLK_TSU, 0x5ac, 0, MSTOP(BUS_MCPU2, BIT(15))), + DEF_MOD("i3c_pclk", R9A08G045_I3C_PCLK, R9A08G045_CLK_TSU, 0x610, 0, + MSTOP(BUS_MCPU3, BIT(10))), + DEF_MOD("i3c_tclk", R9A08G045_I3C_TCLK, R9A08G045_CLK_P5, 0x610, 1, + MSTOP(BUS_MCPU3, BIT(10))), DEF_MOD("vbat_bclk", R9A08G045_VBAT_BCLK, R9A08G045_OSCCLK, 0x614, 0, MSTOP(BUS_MCPU3, GENMASK(8, 7))), }; @@ -331,6 +336,8 @@ static const struct rzg2l_reset r9a08g045_resets[] = { DEF_RST(R9A08G045_ADC_PRESETN, 0x8a8, 0), DEF_RST(R9A08G045_ADC_ADRST_N, 0x8a8, 1), DEF_RST(R9A08G045_TSU_PRESETN, 0x8ac, 0), + DEF_RST(R9A08G045_I3C_TRESETN, 0x910, 0), + DEF_RST(R9A08G045_I3C_PRESETN, 0x910, 1), DEF_RST(R9A08G045_VBAT_BRESETN, 0x914, 0), }; From 6b234eda88d781d244094836afc37c90b57832f3 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 4 Jul 2025 19:14:02 +0300 Subject: [PATCH 0377/2711] clk: renesas: r9a08g045: Add PCIe clocks and resets Add clocks and resets for the PCIe IP available on the Renesas RZ/G3S SoC. The clkl1pm clock is required for PCIe link power management (PM) control and should be enabled based on the state of the CLKREQ# pin. Therefore, mark it as a no_pm clock to allow the PCIe driver to manage it during link PM transitions. Tested-by: Wolfram Sang Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250704161410.3931884-3-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g045-cpg.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c index 643dec45e39d..c4639ad22b8b 100644 --- a/drivers/clk/renesas/r9a08g045-cpg.c +++ b/drivers/clk/renesas/r9a08g045-cpg.c @@ -292,6 +292,10 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = { MSTOP(BUS_MCPU2, BIT(14))), DEF_MOD("tsu_pclk", R9A08G045_TSU_PCLK, R9A08G045_CLK_TSU, 0x5ac, 0, MSTOP(BUS_MCPU2, BIT(15))), + DEF_MOD("pci_aclk", R9A08G045_PCI_ACLK, R9A08G045_CLK_M0, 0x608, 0, + MSTOP(BUS_PERI_COM, BIT(10))), + DEF_MOD("pci_clkl1pm", R9A08G045_PCI_CLKL1PM, R9A08G045_CLK_ZT, 0x608, 1, + MSTOP(BUS_PERI_COM, BIT(10))), DEF_MOD("i3c_pclk", R9A08G045_I3C_PCLK, R9A08G045_CLK_TSU, 0x610, 0, MSTOP(BUS_MCPU3, BIT(10))), DEF_MOD("i3c_tclk", R9A08G045_I3C_TCLK, R9A08G045_CLK_P5, 0x610, 1, @@ -336,6 +340,13 @@ static const struct rzg2l_reset r9a08g045_resets[] = { DEF_RST(R9A08G045_ADC_PRESETN, 0x8a8, 0), DEF_RST(R9A08G045_ADC_ADRST_N, 0x8a8, 1), DEF_RST(R9A08G045_TSU_PRESETN, 0x8ac, 0), + DEF_RST(R9A08G045_PCI_ARESETN, 0x908, 0), + DEF_RST(R9A08G045_PCI_RST_B, 0x908, 1), + DEF_RST(R9A08G045_PCI_RST_GP_B, 0x908, 2), + DEF_RST(R9A08G045_PCI_RST_PS_B, 0x908, 3), + DEF_RST(R9A08G045_PCI_RST_RSM_B, 0x908, 4), + DEF_RST(R9A08G045_PCI_RST_CFG_B, 0x908, 5), + DEF_RST(R9A08G045_PCI_RST_LOAD_B, 0x908, 6), DEF_RST(R9A08G045_I3C_TRESETN, 0x910, 0), DEF_RST(R9A08G045_I3C_PRESETN, 0x910, 1), DEF_RST(R9A08G045_VBAT_BRESETN, 0x914, 0), @@ -349,6 +360,10 @@ static const unsigned int r9a08g045_crit_mod_clks[] __initconst = { MOD_CLK_BASE + R9A08G045_VBAT_BCLK, }; +static const unsigned int r9a08g045_no_pm_mod_clks[] = { + MOD_CLK_BASE + R9A08G045_PCI_CLKL1PM, +}; + const struct rzg2l_cpg_info r9a08g045_cpg_info = { /* Core Clocks */ .core_clks = r9a08g045_core_clks, @@ -365,6 +380,10 @@ const struct rzg2l_cpg_info r9a08g045_cpg_info = { .num_mod_clks = ARRAY_SIZE(r9a08g045_mod_clks), .num_hw_mod_clks = R9A08G045_VBAT_BCLK + 1, + /* No PM modules Clocks */ + .no_pm_mod_clks = r9a08g045_no_pm_mod_clks, + .num_no_pm_mod_clks = ARRAY_SIZE(r9a08g045_no_pm_mod_clks), + /* Resets */ .resets = r9a08g045_resets, .num_resets = R9A08G045_VBAT_BRESETN + 1, /* Last reset ID + 1 */ From 059db30b32e968fdbf6e416411fb78d481ff94bd Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Fri, 1 Aug 2025 10:48:21 +0200 Subject: [PATCH 0378/2711] clk: renesas: r9a09g047: Add DMAC clocks and resets Add clock and reset entries for the Renesas RZ/G3E DMAC IPs. Signed-off-by: Tommaso Merciai Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250801084825.471011-2-tommaso.merciai.xr@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a09g047-cpg.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/clk/renesas/r9a09g047-cpg.c b/drivers/clk/renesas/r9a09g047-cpg.c index 26e2be7667eb..4e8881e0006b 100644 --- a/drivers/clk/renesas/r9a09g047-cpg.c +++ b/drivers/clk/renesas/r9a09g047-cpg.c @@ -48,6 +48,8 @@ enum clk_ids { CLK_PLLDTY_ACPU_DIV2, CLK_PLLDTY_ACPU_DIV4, CLK_PLLDTY_DIV8, + CLK_PLLDTY_RCPU, + CLK_PLLDTY_RCPU_DIV4, CLK_PLLETH_DIV_250_FIX, CLK_PLLETH_DIV_125_FIX, CLK_CSDIV_PLLETH_GBE0, @@ -157,6 +159,8 @@ static const struct cpg_core_clk r9a09g047_core_clks[] __initconst = { DEF_SMUX(".smux2_gbe1_txclk", CLK_SMUX2_GBE1_TXCLK, SSEL1_SELCTL0, smux2_gbe1_txclk), DEF_SMUX(".smux2_gbe1_rxclk", CLK_SMUX2_GBE1_RXCLK, SSEL1_SELCTL1, smux2_gbe1_rxclk), DEF_FIXED(".plldty_div16", CLK_PLLDTY_DIV16, CLK_PLLDTY, 1, 16), + DEF_DDIV(".plldty_rcpu", CLK_PLLDTY_RCPU, CLK_PLLDTY, CDDIV3_DIVCTL2, dtable_2_64), + DEF_FIXED(".plldty_rcpu_div4", CLK_PLLDTY_RCPU_DIV4, CLK_PLLDTY_RCPU, 1, 4), DEF_DDIV(".pllvdo_cru0", CLK_PLLVDO_CRU0, CLK_PLLVDO, CDDIV3_DIVCTL3, dtable_2_4), DEF_DDIV(".pllvdo_gpu", CLK_PLLVDO_GPU, CLK_PLLVDO, CDDIV3_DIVCTL1, dtable_2_64), @@ -180,6 +184,16 @@ static const struct cpg_core_clk r9a09g047_core_clks[] __initconst = { }; static const struct rzv2h_mod_clk r9a09g047_mod_clks[] __initconst = { + DEF_MOD("dmac_0_aclk", CLK_PLLCM33_GEAR, 0, 0, 0, 0, + BUS_MSTOP(5, BIT(9))), + DEF_MOD("dmac_1_aclk", CLK_PLLDTY_ACPU_DIV2, 0, 1, 0, 1, + BUS_MSTOP(3, BIT(2))), + DEF_MOD("dmac_2_aclk", CLK_PLLDTY_ACPU_DIV2, 0, 2, 0, 2, + BUS_MSTOP(3, BIT(3))), + DEF_MOD("dmac_3_aclk", CLK_PLLDTY_RCPU_DIV4, 0, 3, 0, 3, + BUS_MSTOP(10, BIT(11))), + DEF_MOD("dmac_4_aclk", CLK_PLLDTY_RCPU_DIV4, 0, 4, 0, 4, + BUS_MSTOP(10, BIT(12))), DEF_MOD_CRITICAL("icu_0_pclk_i", CLK_PLLCM33_DIV16, 0, 5, 0, 5, BUS_MSTOP_NONE), DEF_MOD_CRITICAL("gic_0_gicclk", CLK_PLLDTY_ACPU_DIV4, 1, 3, 0, 19, @@ -300,6 +314,11 @@ static const struct rzv2h_mod_clk r9a09g047_mod_clks[] __initconst = { static const struct rzv2h_reset r9a09g047_resets[] __initconst = { DEF_RST(3, 0, 1, 1), /* SYS_0_PRESETN */ + DEF_RST(3, 1, 1, 2), /* DMAC_0_ARESETN */ + DEF_RST(3, 2, 1, 3), /* DMAC_1_ARESETN */ + DEF_RST(3, 3, 1, 4), /* DMAC_2_ARESETN */ + DEF_RST(3, 4, 1, 5), /* DMAC_3_ARESETN */ + DEF_RST(3, 5, 1, 6), /* DMAC_4_ARESETN */ DEF_RST(3, 6, 1, 7), /* ICU_0_PRESETN_I */ DEF_RST(3, 8, 1, 9), /* GIC_0_GICRESET_N */ DEF_RST(3, 9, 1, 10), /* GIC_0_DBG_GICRESET_N */ From 45bf4bff2814b78dc2a98e692f7e49399e2d2ce1 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 4 Aug 2025 21:26:43 +0100 Subject: [PATCH 0379/2711] clk: renesas: r9a09g077: Add USB core and module clocks Add module and core clocks used by USB. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250804202643.3967484-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a09g077-cpg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r9a09g077-cpg.c b/drivers/clk/renesas/r9a09g077-cpg.c index c920d6a9707f..704d14d31e87 100644 --- a/drivers/clk/renesas/r9a09g077-cpg.c +++ b/drivers/clk/renesas/r9a09g077-cpg.c @@ -67,7 +67,7 @@ enum rzt2h_clk_types { enum clk_ids { /* Core Clock Outputs exported to DT */ - LAST_DT_CORE_CLK = R9A09G077_SDHI_CLKHS, + LAST_DT_CORE_CLK = R9A09G077_USB_CLK, /* External Input Clocks */ CLK_EXTAL, @@ -150,12 +150,14 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = { DEF_FIXED("PCLKL", R9A09G077_CLK_PCLKL, CLK_SEL_CLK_PLL1, 16, 1), DEF_FIXED("PCLKAM", R9A09G077_CLK_PCLKAM, CLK_PLL4D1, 12, 1), DEF_FIXED("SDHI_CLKHS", R9A09G077_SDHI_CLKHS, CLK_SEL_CLK_PLL2, 1, 1), + DEF_FIXED("USB_CLK", R9A09G077_USB_CLK, CLK_PLL4D1, 48, 1), }; static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = { DEF_MOD("sci0fck", 8, CLK_SCI0ASYNC), DEF_MOD("iic0", 100, R9A09G077_CLK_PCLKL), DEF_MOD("iic1", 101, R9A09G077_CLK_PCLKL), + DEF_MOD("usb", 408, R9A09G077_CLK_PCLKAM), DEF_MOD("iic2", 601, R9A09G077_CLK_PCLKL), DEF_MOD("sdhi0", 1212, R9A09G077_CLK_PCLKAM), DEF_MOD("sdhi1", 1213, R9A09G077_CLK_PCLKAM), From f0cb3463d0244765ab66792a88dc5e2152c130e1 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 6 Aug 2025 12:21:26 +0300 Subject: [PATCH 0380/2711] clk: renesas: r9a08g045: Add MSTOP for GPIO The GPIO module also supports MSTOP. Add it in the description of the gpio clock. Fixes: c49695952746 ("clk: renesas: r9a08g045: Drop power domain instantiation") Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806092129.621194-2-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g045-cpg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c index c4639ad22b8b..79e7b19c7882 100644 --- a/drivers/clk/renesas/r9a08g045-cpg.c +++ b/drivers/clk/renesas/r9a08g045-cpg.c @@ -285,7 +285,8 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = { MSTOP(BUS_MCPU2, BIT(5))), DEF_MOD("scif5_clk_pck", R9A08G045_SCIF5_CLK_PCK, R9A08G045_CLK_P0, 0x584, 5, MSTOP(BUS_MCPU3, BIT(4))), - DEF_MOD("gpio_hclk", R9A08G045_GPIO_HCLK, R9A08G045_OSCCLK, 0x598, 0, 0), + DEF_MOD("gpio_hclk", R9A08G045_GPIO_HCLK, R9A08G045_OSCCLK, 0x598, 0, + MSTOP(BUS_PERI_CPU, BIT(6))), DEF_MOD("adc_adclk", R9A08G045_ADC_ADCLK, R9A08G045_CLK_TSU, 0x5a8, 0, MSTOP(BUS_MCPU2, BIT(14))), DEF_MOD("adc_pclk", R9A08G045_ADC_PCLK, R9A08G045_CLK_TSU, 0x5a8, 1, From 56de5e305d4ba25eed5740b338f7ecb8cf342aa6 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 6 Aug 2025 12:21:27 +0300 Subject: [PATCH 0381/2711] clk: renesas: r9a07g044: Add MSTOP for RZ/G2L Add MSTOP configuration for all the module clocks on the RZ/G2L based SoCs (RZ/G2L, RZ/G2LC, RZ/V2L). Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806092129.621194-3-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a07g044-cpg.c | 154 ++++++++++++++-------------- drivers/clk/renesas/rzg2l-cpg.h | 1 + 2 files changed, 78 insertions(+), 77 deletions(-) diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c index c851d4eeebbe..fdbc0635a869 100644 --- a/drivers/clk/renesas/r9a07g044-cpg.c +++ b/drivers/clk/renesas/r9a07g044-cpg.c @@ -242,163 +242,163 @@ static const struct { } mod_clks = { .common = { DEF_MOD("gic", R9A07G044_GIC600_GICCLK, R9A07G044_CLK_P1, - 0x514, 0, 0), + 0x514, 0, MSTOP(BUS_REG1, BIT(7))), DEF_MOD("ia55_pclk", R9A07G044_IA55_PCLK, R9A07G044_CLK_P2, - 0x518, 0, 0), + 0x518, 0, MSTOP(BUS_PERI_CPU, BIT(13))), DEF_MOD("ia55_clk", R9A07G044_IA55_CLK, R9A07G044_CLK_P1, - 0x518, 1, 0), + 0x518, 1, MSTOP(BUS_PERI_CPU, BIT(13))), DEF_MOD("dmac_aclk", R9A07G044_DMAC_ACLK, R9A07G044_CLK_P1, - 0x52c, 0, 0), + 0x52c, 0, MSTOP(BUS_REG1, BIT(2))), DEF_MOD("dmac_pclk", R9A07G044_DMAC_PCLK, CLK_P1_DIV2, - 0x52c, 1, 0), + 0x52c, 1, MSTOP(BUS_REG1, BIT(3))), DEF_MOD("ostm0_pclk", R9A07G044_OSTM0_PCLK, R9A07G044_CLK_P0, - 0x534, 0, 0), + 0x534, 0, MSTOP(BUS_REG0, BIT(4))), DEF_MOD("ostm1_pclk", R9A07G044_OSTM1_PCLK, R9A07G044_CLK_P0, - 0x534, 1, 0), + 0x534, 1, MSTOP(BUS_REG0, BIT(5))), DEF_MOD("ostm2_pclk", R9A07G044_OSTM2_PCLK, R9A07G044_CLK_P0, - 0x534, 2, 0), + 0x534, 2, MSTOP(BUS_REG0, BIT(6))), DEF_MOD("mtu_x_mck", R9A07G044_MTU_X_MCK_MTU3, R9A07G044_CLK_P0, - 0x538, 0, 0), + 0x538, 0, MSTOP(BUS_MCPU1, BIT(2))), DEF_MOD("gpt_pclk", R9A07G044_GPT_PCLK, R9A07G044_CLK_P0, - 0x540, 0, 0), + 0x540, 0, MSTOP(BUS_MCPU1, BIT(4))), DEF_MOD("poeg_a_clkp", R9A07G044_POEG_A_CLKP, R9A07G044_CLK_P0, - 0x544, 0, 0), + 0x544, 0, MSTOP(BUS_MCPU1, BIT(5))), DEF_MOD("poeg_b_clkp", R9A07G044_POEG_B_CLKP, R9A07G044_CLK_P0, - 0x544, 1, 0), + 0x544, 1, MSTOP(BUS_MCPU1, BIT(6))), DEF_MOD("poeg_c_clkp", R9A07G044_POEG_C_CLKP, R9A07G044_CLK_P0, - 0x544, 2, 0), + 0x544, 2, MSTOP(BUS_MCPU1, BIT(7))), DEF_MOD("poeg_d_clkp", R9A07G044_POEG_D_CLKP, R9A07G044_CLK_P0, - 0x544, 3, 0), + 0x544, 3, MSTOP(BUS_MCPU1, BIT(8))), DEF_MOD("wdt0_pclk", R9A07G044_WDT0_PCLK, R9A07G044_CLK_P0, - 0x548, 0, 0), + 0x548, 0, MSTOP(BUS_REG0, BIT(2))), DEF_MOD("wdt0_clk", R9A07G044_WDT0_CLK, R9A07G044_OSCCLK, - 0x548, 1, 0), + 0x548, 1, MSTOP(BUS_REG0, BIT(2))), DEF_MOD("wdt1_pclk", R9A07G044_WDT1_PCLK, R9A07G044_CLK_P0, - 0x548, 2, 0), + 0x548, 2, MSTOP(BUS_REG0, BIT(3))), DEF_MOD("wdt1_clk", R9A07G044_WDT1_CLK, R9A07G044_OSCCLK, - 0x548, 3, 0), + 0x548, 3, MSTOP(BUS_REG0, BIT(3))), DEF_MOD("spi_clk2", R9A07G044_SPI_CLK2, R9A07G044_CLK_SPI1, - 0x550, 0, 0), + 0x550, 0, MSTOP(BUS_MCPU1, BIT(1))), DEF_MOD("spi_clk", R9A07G044_SPI_CLK, R9A07G044_CLK_SPI0, - 0x550, 1, 0), + 0x550, 1, MSTOP(BUS_MCPU1, BIT(1))), DEF_MOD("sdhi0_imclk", R9A07G044_SDHI0_IMCLK, CLK_SD0_DIV4, - 0x554, 0, 0), + 0x554, 0, MSTOP(BUS_PERI_COM, BIT(0))), DEF_MOD("sdhi0_imclk2", R9A07G044_SDHI0_IMCLK2, CLK_SD0_DIV4, - 0x554, 1, 0), + 0x554, 1, MSTOP(BUS_PERI_COM, BIT(0))), DEF_MOD("sdhi0_clk_hs", R9A07G044_SDHI0_CLK_HS, R9A07G044_CLK_SD0, - 0x554, 2, 0), + 0x554, 2, MSTOP(BUS_PERI_COM, BIT(0))), DEF_MOD("sdhi0_aclk", R9A07G044_SDHI0_ACLK, R9A07G044_CLK_P1, - 0x554, 3, 0), + 0x554, 3, MSTOP(BUS_PERI_COM, BIT(0))), DEF_MOD("sdhi1_imclk", R9A07G044_SDHI1_IMCLK, CLK_SD1_DIV4, - 0x554, 4, 0), + 0x554, 4, MSTOP(BUS_PERI_COM, BIT(1))), DEF_MOD("sdhi1_imclk2", R9A07G044_SDHI1_IMCLK2, CLK_SD1_DIV4, - 0x554, 5, 0), + 0x554, 5, MSTOP(BUS_PERI_COM, BIT(1))), DEF_MOD("sdhi1_clk_hs", R9A07G044_SDHI1_CLK_HS, R9A07G044_CLK_SD1, - 0x554, 6, 0), + 0x554, 6, MSTOP(BUS_PERI_COM, BIT(1))), DEF_MOD("sdhi1_aclk", R9A07G044_SDHI1_ACLK, R9A07G044_CLK_P1, - 0x554, 7, 0), + 0x554, 7, MSTOP(BUS_PERI_COM, BIT(1))), DEF_MOD("gpu_clk", R9A07G044_GPU_CLK, R9A07G044_CLK_G, - 0x558, 0, 0), + 0x558, 0, MSTOP(BUS_REG1, BIT(4))), DEF_MOD("gpu_axi_clk", R9A07G044_GPU_AXI_CLK, R9A07G044_CLK_P1, 0x558, 1, 0), DEF_MOD("gpu_ace_clk", R9A07G044_GPU_ACE_CLK, R9A07G044_CLK_P1, 0x558, 2, 0), DEF_MOD("cru_sysclk", R9A07G044_CRU_SYSCLK, CLK_M2_DIV2, - 0x564, 0, 0), + 0x564, 0, MSTOP(BUS_PERI_VIDEO, BIT(3))), DEF_MOD("cru_vclk", R9A07G044_CRU_VCLK, R9A07G044_CLK_M2, - 0x564, 1, 0), + 0x564, 1, MSTOP(BUS_PERI_VIDEO, BIT(3))), DEF_MOD("cru_pclk", R9A07G044_CRU_PCLK, R9A07G044_CLK_ZT, - 0x564, 2, 0), + 0x564, 2, MSTOP(BUS_PERI_VIDEO, BIT(3))), DEF_MOD("cru_aclk", R9A07G044_CRU_ACLK, R9A07G044_CLK_M0, - 0x564, 3, 0), + 0x564, 3, MSTOP(BUS_PERI_VIDEO, BIT(3))), DEF_MOD("dsi_pll_clk", R9A07G044_MIPI_DSI_PLLCLK, R9A07G044_CLK_M1, - 0x568, 0, 0), + 0x568, 0, MSTOP(BUS_PERI_VIDEO, GENMASK(6, 5))), DEF_MOD("dsi_sys_clk", R9A07G044_MIPI_DSI_SYSCLK, CLK_M2_DIV2, - 0x568, 1, 0), + 0x568, 1, MSTOP(BUS_PERI_VIDEO, GENMASK(6, 5))), DEF_MOD("dsi_aclk", R9A07G044_MIPI_DSI_ACLK, R9A07G044_CLK_P1, - 0x568, 2, 0), + 0x568, 2, MSTOP(BUS_PERI_VIDEO, GENMASK(6, 5))), DEF_MOD("dsi_pclk", R9A07G044_MIPI_DSI_PCLK, R9A07G044_CLK_P2, - 0x568, 3, 0), + 0x568, 3, MSTOP(BUS_PERI_VIDEO, GENMASK(6, 5))), DEF_MOD("dsi_vclk", R9A07G044_MIPI_DSI_VCLK, R9A07G044_CLK_M3, - 0x568, 4, 0), + 0x568, 4, MSTOP(BUS_PERI_VIDEO, GENMASK(6, 5))), DEF_MOD("dsi_lpclk", R9A07G044_MIPI_DSI_LPCLK, R9A07G044_CLK_M4, - 0x568, 5, 0), + 0x568, 5, MSTOP(BUS_PERI_VIDEO, GENMASK(6, 5))), DEF_COUPLED("lcdc_a", R9A07G044_LCDC_CLK_A, R9A07G044_CLK_M0, - 0x56c, 0, 0), + 0x56c, 0, MSTOP(BUS_PERI_VIDEO, GENMASK(8, 7))), DEF_COUPLED("lcdc_p", R9A07G044_LCDC_CLK_P, R9A07G044_CLK_ZT, - 0x56c, 0, 0), + 0x56c, 0, MSTOP(BUS_PERI_VIDEO, GENMASK(8, 7))), DEF_MOD("lcdc_clk_d", R9A07G044_LCDC_CLK_D, R9A07G044_CLK_M3, - 0x56c, 1, 0), + 0x56c, 1, MSTOP(BUS_PERI_VIDEO, BIT(9))), DEF_MOD("ssi0_pclk", R9A07G044_SSI0_PCLK2, R9A07G044_CLK_P0, - 0x570, 0, 0), + 0x570, 0, MSTOP(BUS_MCPU1, BIT(10))), DEF_MOD("ssi0_sfr", R9A07G044_SSI0_PCLK_SFR, R9A07G044_CLK_P0, - 0x570, 1, 0), + 0x570, 1, MSTOP(BUS_MCPU1, BIT(10))), DEF_MOD("ssi1_pclk", R9A07G044_SSI1_PCLK2, R9A07G044_CLK_P0, - 0x570, 2, 0), + 0x570, 2, MSTOP(BUS_MCPU1, BIT(11))), DEF_MOD("ssi1_sfr", R9A07G044_SSI1_PCLK_SFR, R9A07G044_CLK_P0, - 0x570, 3, 0), + 0x570, 3, MSTOP(BUS_MCPU1, BIT(11))), DEF_MOD("ssi2_pclk", R9A07G044_SSI2_PCLK2, R9A07G044_CLK_P0, - 0x570, 4, 0), + 0x570, 4, MSTOP(BUS_MCPU1, BIT(12))), DEF_MOD("ssi2_sfr", R9A07G044_SSI2_PCLK_SFR, R9A07G044_CLK_P0, - 0x570, 5, 0), + 0x570, 5, MSTOP(BUS_MCPU1, BIT(12))), DEF_MOD("ssi3_pclk", R9A07G044_SSI3_PCLK2, R9A07G044_CLK_P0, - 0x570, 6, 0), + 0x570, 6, MSTOP(BUS_MCPU1, BIT(13))), DEF_MOD("ssi3_sfr", R9A07G044_SSI3_PCLK_SFR, R9A07G044_CLK_P0, - 0x570, 7, 0), + 0x570, 7, MSTOP(BUS_MCPU1, BIT(13))), DEF_MOD("usb0_host", R9A07G044_USB_U2H0_HCLK, R9A07G044_CLK_P1, - 0x578, 0, 0), + 0x578, 0, MSTOP(BUS_PERI_COM, BIT(5))), DEF_MOD("usb1_host", R9A07G044_USB_U2H1_HCLK, R9A07G044_CLK_P1, - 0x578, 1, 0), + 0x578, 1, MSTOP(BUS_PERI_COM, BIT(7))), DEF_MOD("usb0_func", R9A07G044_USB_U2P_EXR_CPUCLK, R9A07G044_CLK_P1, - 0x578, 2, 0), + 0x578, 2, MSTOP(BUS_PERI_COM, BIT(6))), DEF_MOD("usb_pclk", R9A07G044_USB_PCLK, R9A07G044_CLK_P1, - 0x578, 3, 0), + 0x578, 3, MSTOP(BUS_PERI_COM, BIT(4))), DEF_COUPLED("eth0_axi", R9A07G044_ETH0_CLK_AXI, R9A07G044_CLK_M0, - 0x57c, 0, 0), + 0x57c, 0, MSTOP(BUS_PERI_COM, BIT(2))), DEF_COUPLED("eth0_chi", R9A07G044_ETH0_CLK_CHI, R9A07G044_CLK_ZT, - 0x57c, 0, 0), + 0x57c, 0, MSTOP(BUS_PERI_COM, BIT(2))), DEF_COUPLED("eth1_axi", R9A07G044_ETH1_CLK_AXI, R9A07G044_CLK_M0, - 0x57c, 1, 0), + 0x57c, 1, MSTOP(BUS_PERI_COM, BIT(3))), DEF_COUPLED("eth1_chi", R9A07G044_ETH1_CLK_CHI, R9A07G044_CLK_ZT, - 0x57c, 1, 0), + 0x57c, 1, MSTOP(BUS_PERI_COM, BIT(3))), DEF_MOD("i2c0", R9A07G044_I2C0_PCLK, R9A07G044_CLK_P0, - 0x580, 0, 0), + 0x580, 0, MSTOP(BUS_MCPU2, BIT(10))), DEF_MOD("i2c1", R9A07G044_I2C1_PCLK, R9A07G044_CLK_P0, - 0x580, 1, 0), + 0x580, 1, MSTOP(BUS_MCPU2, BIT(11))), DEF_MOD("i2c2", R9A07G044_I2C2_PCLK, R9A07G044_CLK_P0, - 0x580, 2, 0), + 0x580, 2, MSTOP(BUS_MCPU2, BIT(12))), DEF_MOD("i2c3", R9A07G044_I2C3_PCLK, R9A07G044_CLK_P0, - 0x580, 3, 0), + 0x580, 3, MSTOP(BUS_MCPU2, BIT(13))), DEF_MOD("scif0", R9A07G044_SCIF0_CLK_PCK, R9A07G044_CLK_P0, - 0x584, 0, 0), + 0x584, 0, MSTOP(BUS_MCPU2, BIT(1))), DEF_MOD("scif1", R9A07G044_SCIF1_CLK_PCK, R9A07G044_CLK_P0, - 0x584, 1, 0), + 0x584, 1, MSTOP(BUS_MCPU2, BIT(2))), DEF_MOD("scif2", R9A07G044_SCIF2_CLK_PCK, R9A07G044_CLK_P0, - 0x584, 2, 0), + 0x584, 2, MSTOP(BUS_MCPU2, BIT(3))), DEF_MOD("scif3", R9A07G044_SCIF3_CLK_PCK, R9A07G044_CLK_P0, - 0x584, 3, 0), + 0x584, 3, MSTOP(BUS_MCPU2, BIT(4))), DEF_MOD("scif4", R9A07G044_SCIF4_CLK_PCK, R9A07G044_CLK_P0, - 0x584, 4, 0), + 0x584, 4, MSTOP(BUS_MCPU2, BIT(5))), DEF_MOD("sci0", R9A07G044_SCI0_CLKP, R9A07G044_CLK_P0, - 0x588, 0, 0), + 0x588, 0, MSTOP(BUS_MCPU2, BIT(7))), DEF_MOD("sci1", R9A07G044_SCI1_CLKP, R9A07G044_CLK_P0, - 0x588, 1, 0), + 0x588, 1, MSTOP(BUS_MCPU2, BIT(8))), DEF_MOD("rspi0", R9A07G044_RSPI0_CLKB, R9A07G044_CLK_P0, - 0x590, 0, 0), + 0x590, 0, MSTOP(BUS_MCPU1, BIT(14))), DEF_MOD("rspi1", R9A07G044_RSPI1_CLKB, R9A07G044_CLK_P0, - 0x590, 1, 0), + 0x590, 1, MSTOP(BUS_MCPU1, BIT(15))), DEF_MOD("rspi2", R9A07G044_RSPI2_CLKB, R9A07G044_CLK_P0, - 0x590, 2, 0), + 0x590, 2, MSTOP(BUS_MCPU2, BIT(0))), DEF_MOD("canfd", R9A07G044_CANFD_PCLK, R9A07G044_CLK_P0, - 0x594, 0, 0), + 0x594, 0, MSTOP(BUS_MCPU2, BIT(9))), DEF_MOD("gpio", R9A07G044_GPIO_HCLK, R9A07G044_OSCCLK, - 0x598, 0, 0), + 0x598, 0, MSTOP(BUS_PERI_CPU, BIT(6))), DEF_MOD("adc_adclk", R9A07G044_ADC_ADCLK, R9A07G044_CLK_TSU, - 0x5a8, 0, 0), + 0x5a8, 0, MSTOP(BUS_MCPU2, BIT(14))), DEF_MOD("adc_pclk", R9A07G044_ADC_PCLK, R9A07G044_CLK_P0, - 0x5a8, 1, 0), + 0x5a8, 1, MSTOP(BUS_MCPU2, BIT(14))), DEF_MOD("tsu_pclk", R9A07G044_TSU_PCLK, R9A07G044_CLK_TSU, - 0x5ac, 0, 0), + 0x5ac, 0, MSTOP(BUS_MCPU2, BIT(15))), }, #ifdef CONFIG_CLK_R9A07G054 .drp = { diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 0a71c5ec24b6..55e815be16c8 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -34,6 +34,7 @@ #define CPG_BUS_PERI_COM_MSTOP (0xB6C) #define CPG_BUS_PERI_CPU_MSTOP (0xB70) #define CPG_BUS_PERI_DDR_MSTOP (0xB74) +#define CPG_BUS_PERI_VIDEO_MSTOP (0xB78) #define CPG_BUS_REG0_MSTOP (0xB7C) #define CPG_BUS_REG1_MSTOP (0xB80) #define CPG_BUS_TZCDDR_MSTOP (0xB84) From 0f078d37aeeefa197f4ffff6acd677cd3220a070 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 6 Aug 2025 12:21:28 +0300 Subject: [PATCH 0382/2711] clk: renesas: r9a07g043: Add MSTOP for RZ/G2UL Add MSTOP configuration for all the module clocks on the RZ/G2UL based SoCs (RZ/G2UL, RZ/Five). Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806092129.621194-4-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a07g043-cpg.c | 132 ++++++++++++++-------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c index 02dc5cecfd8d..f050f8565916 100644 --- a/drivers/clk/renesas/r9a07g043-cpg.c +++ b/drivers/clk/renesas/r9a07g043-cpg.c @@ -164,143 +164,143 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { static const struct rzg2l_mod_clk r9a07g043_mod_clks[] = { #ifdef CONFIG_ARM64 DEF_MOD("gic", R9A07G043_GIC600_GICCLK, R9A07G043_CLK_P1, - 0x514, 0, 0), + 0x514, 0, MSTOP(BUS_REG1, BIT(7))), DEF_MOD("ia55_pclk", R9A07G043_IA55_PCLK, R9A07G043_CLK_P2, - 0x518, 0, 0), + 0x518, 0, MSTOP(BUS_PERI_CPU, BIT(13))), DEF_MOD("ia55_clk", R9A07G043_IA55_CLK, R9A07G043_CLK_P1, - 0x518, 1, 0), + 0x518, 1, MSTOP(BUS_PERI_CPU, BIT(13))), #endif #ifdef CONFIG_RISCV DEF_MOD("iax45_pclk", R9A07G043_IAX45_PCLK, R9A07G043_CLK_P2, - 0x518, 0, 0), + 0x518, 0, MSTOP(BUS_PERI_CPU, BIT(13))), DEF_MOD("iax45_clk", R9A07G043_IAX45_CLK, R9A07G043_CLK_P1, - 0x518, 1, 0), + 0x518, 1, MSTOP(BUS_PERI_CPU, BIT(13))), #endif DEF_MOD("dmac_aclk", R9A07G043_DMAC_ACLK, R9A07G043_CLK_P1, - 0x52c, 0, 0), + 0x52c, 0, MSTOP(BUS_REG1, BIT(2))), DEF_MOD("dmac_pclk", R9A07G043_DMAC_PCLK, CLK_P1_DIV2, - 0x52c, 1, 0), + 0x52c, 1, MSTOP(BUS_REG1, BIT(3))), DEF_MOD("ostm0_pclk", R9A07G043_OSTM0_PCLK, R9A07G043_CLK_P0, - 0x534, 0, 0), + 0x534, 0, MSTOP(BUS_REG0, BIT(4))), DEF_MOD("ostm1_pclk", R9A07G043_OSTM1_PCLK, R9A07G043_CLK_P0, - 0x534, 1, 0), + 0x534, 1, MSTOP(BUS_REG0, BIT(5))), DEF_MOD("ostm2_pclk", R9A07G043_OSTM2_PCLK, R9A07G043_CLK_P0, - 0x534, 2, 0), + 0x534, 2, MSTOP(BUS_REG0, BIT(6))), DEF_MOD("mtu_x_mck", R9A07G043_MTU_X_MCK_MTU3, R9A07G043_CLK_P0, - 0x538, 0, 0), + 0x538, 0, MSTOP(BUS_MCPU1, BIT(2))), DEF_MOD("wdt0_pclk", R9A07G043_WDT0_PCLK, R9A07G043_CLK_P0, - 0x548, 0, 0), + 0x548, 0, MSTOP(BUS_REG0, BIT(2))), DEF_MOD("wdt0_clk", R9A07G043_WDT0_CLK, R9A07G043_OSCCLK, - 0x548, 1, 0), + 0x548, 1, MSTOP(BUS_REG0, BIT(2))), DEF_MOD("spi_clk2", R9A07G043_SPI_CLK2, R9A07G043_CLK_SPI1, - 0x550, 0, 0), + 0x550, 0, MSTOP(BUS_MCPU1, BIT(1))), DEF_MOD("spi_clk", R9A07G043_SPI_CLK, R9A07G043_CLK_SPI0, - 0x550, 1, 0), + 0x550, 1, MSTOP(BUS_MCPU1, BIT(1))), DEF_MOD("sdhi0_imclk", R9A07G043_SDHI0_IMCLK, CLK_SD0_DIV4, - 0x554, 0, 0), + 0x554, 0, MSTOP(BUS_PERI_COM, BIT(0))), DEF_MOD("sdhi0_imclk2", R9A07G043_SDHI0_IMCLK2, CLK_SD0_DIV4, - 0x554, 1, 0), + 0x554, 1, MSTOP(BUS_PERI_COM, BIT(0))), DEF_MOD("sdhi0_clk_hs", R9A07G043_SDHI0_CLK_HS, R9A07G043_CLK_SD0, - 0x554, 2, 0), + 0x554, 2, MSTOP(BUS_PERI_COM, BIT(0))), DEF_MOD("sdhi0_aclk", R9A07G043_SDHI0_ACLK, R9A07G043_CLK_P1, - 0x554, 3, 0), + 0x554, 3, MSTOP(BUS_PERI_COM, BIT(0))), DEF_MOD("sdhi1_imclk", R9A07G043_SDHI1_IMCLK, CLK_SD1_DIV4, - 0x554, 4, 0), + 0x554, 4, MSTOP(BUS_PERI_COM, BIT(1))), DEF_MOD("sdhi1_imclk2", R9A07G043_SDHI1_IMCLK2, CLK_SD1_DIV4, - 0x554, 5, 0), + 0x554, 5, MSTOP(BUS_PERI_COM, BIT(1))), DEF_MOD("sdhi1_clk_hs", R9A07G043_SDHI1_CLK_HS, R9A07G043_CLK_SD1, - 0x554, 6, 0), + 0x554, 6, MSTOP(BUS_PERI_COM, BIT(1))), DEF_MOD("sdhi1_aclk", R9A07G043_SDHI1_ACLK, R9A07G043_CLK_P1, - 0x554, 7, 0), + 0x554, 7, MSTOP(BUS_PERI_COM, BIT(1))), #ifdef CONFIG_ARM64 DEF_MOD("cru_sysclk", R9A07G043_CRU_SYSCLK, CLK_M2_DIV2, - 0x564, 0, 0), + 0x564, 0, MSTOP(BUS_PERI_VIDEO, BIT(3))), DEF_MOD("cru_vclk", R9A07G043_CRU_VCLK, R9A07G043_CLK_M2, - 0x564, 1, 0), + 0x564, 1, MSTOP(BUS_PERI_VIDEO, BIT(3))), DEF_MOD("cru_pclk", R9A07G043_CRU_PCLK, R9A07G043_CLK_ZT, - 0x564, 2, 0), + 0x564, 2, MSTOP(BUS_PERI_VIDEO, BIT(3))), DEF_MOD("cru_aclk", R9A07G043_CRU_ACLK, R9A07G043_CLK_M0, - 0x564, 3, 0), + 0x564, 3, MSTOP(BUS_PERI_VIDEO, BIT(3))), DEF_COUPLED("lcdc_clk_a", R9A07G043_LCDC_CLK_A, R9A07G043_CLK_M0, - 0x56c, 0, 0), + 0x56c, 0, MSTOP(BUS_PERI_VIDEO, GENMASK(8, 7))), DEF_COUPLED("lcdc_clk_p", R9A07G043_LCDC_CLK_P, R9A07G043_CLK_ZT, - 0x56c, 0, 0), + 0x56c, 0, MSTOP(BUS_PERI_VIDEO, GENMASK(8, 7))), DEF_MOD("lcdc_clk_d", R9A07G043_LCDC_CLK_D, R9A07G043_CLK_M3, - 0x56c, 1, 0), + 0x56c, 1, MSTOP(BUS_PERI_VIDEO, BIT(9))), #endif DEF_MOD("ssi0_pclk", R9A07G043_SSI0_PCLK2, R9A07G043_CLK_P0, - 0x570, 0, 0), + 0x570, 0, MSTOP(BUS_MCPU1, BIT(10))), DEF_MOD("ssi0_sfr", R9A07G043_SSI0_PCLK_SFR, R9A07G043_CLK_P0, - 0x570, 1, 0), + 0x570, 1, MSTOP(BUS_MCPU1, BIT(10))), DEF_MOD("ssi1_pclk", R9A07G043_SSI1_PCLK2, R9A07G043_CLK_P0, - 0x570, 2, 0), + 0x570, 2, MSTOP(BUS_MCPU1, BIT(11))), DEF_MOD("ssi1_sfr", R9A07G043_SSI1_PCLK_SFR, R9A07G043_CLK_P0, - 0x570, 3, 0), + 0x570, 3, MSTOP(BUS_MCPU1, BIT(11))), DEF_MOD("ssi2_pclk", R9A07G043_SSI2_PCLK2, R9A07G043_CLK_P0, - 0x570, 4, 0), + 0x570, 4, MSTOP(BUS_MCPU1, BIT(12))), DEF_MOD("ssi2_sfr", R9A07G043_SSI2_PCLK_SFR, R9A07G043_CLK_P0, - 0x570, 5, 0), + 0x570, 5, MSTOP(BUS_MCPU1, BIT(12))), DEF_MOD("ssi3_pclk", R9A07G043_SSI3_PCLK2, R9A07G043_CLK_P0, - 0x570, 6, 0), + 0x570, 6, MSTOP(BUS_MCPU1, BIT(13))), DEF_MOD("ssi3_sfr", R9A07G043_SSI3_PCLK_SFR, R9A07G043_CLK_P0, - 0x570, 7, 0), + 0x570, 7, MSTOP(BUS_MCPU1, BIT(13))), DEF_MOD("usb0_host", R9A07G043_USB_U2H0_HCLK, R9A07G043_CLK_P1, - 0x578, 0, 0), + 0x578, 0, MSTOP(BUS_PERI_COM, BIT(5))), DEF_MOD("usb1_host", R9A07G043_USB_U2H1_HCLK, R9A07G043_CLK_P1, - 0x578, 1, 0), + 0x578, 1, MSTOP(BUS_PERI_COM, BIT(7))), DEF_MOD("usb0_func", R9A07G043_USB_U2P_EXR_CPUCLK, R9A07G043_CLK_P1, - 0x578, 2, 0), + 0x578, 2, MSTOP(BUS_PERI_COM, BIT(6))), DEF_MOD("usb_pclk", R9A07G043_USB_PCLK, R9A07G043_CLK_P1, - 0x578, 3, 0), + 0x578, 3, MSTOP(BUS_PERI_COM, BIT(4))), DEF_COUPLED("eth0_axi", R9A07G043_ETH0_CLK_AXI, R9A07G043_CLK_M0, - 0x57c, 0, 0), + 0x57c, 0, MSTOP(BUS_PERI_COM, BIT(2))), DEF_COUPLED("eth0_chi", R9A07G043_ETH0_CLK_CHI, R9A07G043_CLK_ZT, - 0x57c, 0, 0), + 0x57c, 0, MSTOP(BUS_PERI_COM, BIT(2))), DEF_COUPLED("eth1_axi", R9A07G043_ETH1_CLK_AXI, R9A07G043_CLK_M0, - 0x57c, 1, 0), + 0x57c, 1, MSTOP(BUS_PERI_COM, BIT(3))), DEF_COUPLED("eth1_chi", R9A07G043_ETH1_CLK_CHI, R9A07G043_CLK_ZT, - 0x57c, 1, 0), + 0x57c, 1, MSTOP(BUS_PERI_COM, BIT(3))), DEF_MOD("i2c0", R9A07G043_I2C0_PCLK, R9A07G043_CLK_P0, - 0x580, 0, 0), + 0x580, 0, MSTOP(BUS_MCPU2, BIT(10))), DEF_MOD("i2c1", R9A07G043_I2C1_PCLK, R9A07G043_CLK_P0, - 0x580, 1, 0), + 0x580, 1, MSTOP(BUS_MCPU2, BIT(11))), DEF_MOD("i2c2", R9A07G043_I2C2_PCLK, R9A07G043_CLK_P0, - 0x580, 2, 0), + 0x580, 2, MSTOP(BUS_MCPU2, BIT(12))), DEF_MOD("i2c3", R9A07G043_I2C3_PCLK, R9A07G043_CLK_P0, - 0x580, 3, 0), + 0x580, 3, MSTOP(BUS_MCPU2, BIT(13))), DEF_MOD("scif0", R9A07G043_SCIF0_CLK_PCK, R9A07G043_CLK_P0, - 0x584, 0, 0), + 0x584, 0, MSTOP(BUS_MCPU2, BIT(1))), DEF_MOD("scif1", R9A07G043_SCIF1_CLK_PCK, R9A07G043_CLK_P0, - 0x584, 1, 0), + 0x584, 1, MSTOP(BUS_MCPU2, BIT(2))), DEF_MOD("scif2", R9A07G043_SCIF2_CLK_PCK, R9A07G043_CLK_P0, - 0x584, 2, 0), + 0x584, 2, MSTOP(BUS_MCPU2, BIT(3))), DEF_MOD("scif3", R9A07G043_SCIF3_CLK_PCK, R9A07G043_CLK_P0, - 0x584, 3, 0), + 0x584, 3, MSTOP(BUS_MCPU2, BIT(4))), DEF_MOD("scif4", R9A07G043_SCIF4_CLK_PCK, R9A07G043_CLK_P0, - 0x584, 4, 0), + 0x584, 4, MSTOP(BUS_MCPU2, BIT(5))), DEF_MOD("sci0", R9A07G043_SCI0_CLKP, R9A07G043_CLK_P0, - 0x588, 0, 0), + 0x588, 0, MSTOP(BUS_MCPU2, BIT(7))), DEF_MOD("sci1", R9A07G043_SCI1_CLKP, R9A07G043_CLK_P0, - 0x588, 1, 0), + 0x588, 1, MSTOP(BUS_MCPU2, BIT(8))), DEF_MOD("rspi0", R9A07G043_RSPI0_CLKB, R9A07G043_CLK_P0, - 0x590, 0, 0), + 0x590, 0, MSTOP(BUS_MCPU1, BIT(14))), DEF_MOD("rspi1", R9A07G043_RSPI1_CLKB, R9A07G043_CLK_P0, - 0x590, 1, 0), + 0x590, 1, MSTOP(BUS_MCPU1, BIT(15))), DEF_MOD("rspi2", R9A07G043_RSPI2_CLKB, R9A07G043_CLK_P0, - 0x590, 2, 0), + 0x590, 2, MSTOP(BUS_MCPU2, BIT(0))), DEF_MOD("canfd", R9A07G043_CANFD_PCLK, R9A07G043_CLK_P0, - 0x594, 0, 0), + 0x594, 0, MSTOP(BUS_MCPU2, BIT(9))), DEF_MOD("gpio", R9A07G043_GPIO_HCLK, R9A07G043_OSCCLK, - 0x598, 0, 0), + 0x598, 0, MSTOP(BUS_PERI_CPU, BIT(6))), DEF_MOD("adc_adclk", R9A07G043_ADC_ADCLK, R9A07G043_CLK_TSU, - 0x5a8, 0, 0), + 0x5a8, 0, MSTOP(BUS_MCPU2, BIT(14))), DEF_MOD("adc_pclk", R9A07G043_ADC_PCLK, R9A07G043_CLK_P0, - 0x5a8, 1, 0), + 0x5a8, 1, MSTOP(BUS_MCPU2, BIT(14))), DEF_MOD("tsu_pclk", R9A07G043_TSU_PCLK, R9A07G043_CLK_TSU, - 0x5ac, 0, 0), + 0x5ac, 0, MSTOP(BUS_MCPU2, BIT(15))), #ifdef CONFIG_RISCV DEF_MOD("nceplic_aclk", R9A07G043_NCEPLIC_ACLK, R9A07G043_CLK_P1, - 0x608, 0, 0), + 0x608, 0, MSTOP(BUS_REG1, BIT(7))), #endif }; From 8933612860fd0087a0e27dfca01106a98ccc334a Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 6 Aug 2025 12:21:29 +0300 Subject: [PATCH 0383/2711] clk: renesas: r9a07g04[34]: Use tabs instead of spaces Use tabs instead of spaces in the CRU clock descriptions to match the formatting used in the rest of the clock definitions. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250806092129.621194-5-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a07g043-cpg.c | 8 ++++---- drivers/clk/renesas/r9a07g044-cpg.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c index f050f8565916..33e9a1223c72 100644 --- a/drivers/clk/renesas/r9a07g043-cpg.c +++ b/drivers/clk/renesas/r9a07g043-cpg.c @@ -213,13 +213,13 @@ static const struct rzg2l_mod_clk r9a07g043_mod_clks[] = { DEF_MOD("sdhi1_aclk", R9A07G043_SDHI1_ACLK, R9A07G043_CLK_P1, 0x554, 7, MSTOP(BUS_PERI_COM, BIT(1))), #ifdef CONFIG_ARM64 - DEF_MOD("cru_sysclk", R9A07G043_CRU_SYSCLK, CLK_M2_DIV2, + DEF_MOD("cru_sysclk", R9A07G043_CRU_SYSCLK, CLK_M2_DIV2, 0x564, 0, MSTOP(BUS_PERI_VIDEO, BIT(3))), - DEF_MOD("cru_vclk", R9A07G043_CRU_VCLK, R9A07G043_CLK_M2, + DEF_MOD("cru_vclk", R9A07G043_CRU_VCLK, R9A07G043_CLK_M2, 0x564, 1, MSTOP(BUS_PERI_VIDEO, BIT(3))), - DEF_MOD("cru_pclk", R9A07G043_CRU_PCLK, R9A07G043_CLK_ZT, + DEF_MOD("cru_pclk", R9A07G043_CRU_PCLK, R9A07G043_CLK_ZT, 0x564, 2, MSTOP(BUS_PERI_VIDEO, BIT(3))), - DEF_MOD("cru_aclk", R9A07G043_CRU_ACLK, R9A07G043_CLK_M0, + DEF_MOD("cru_aclk", R9A07G043_CRU_ACLK, R9A07G043_CLK_M0, 0x564, 3, MSTOP(BUS_PERI_VIDEO, BIT(3))), DEF_COUPLED("lcdc_clk_a", R9A07G043_LCDC_CLK_A, R9A07G043_CLK_M0, 0x56c, 0, MSTOP(BUS_PERI_VIDEO, GENMASK(8, 7))), diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c index fdbc0635a869..0dd264877b9a 100644 --- a/drivers/clk/renesas/r9a07g044-cpg.c +++ b/drivers/clk/renesas/r9a07g044-cpg.c @@ -303,13 +303,13 @@ static const struct { 0x558, 1, 0), DEF_MOD("gpu_ace_clk", R9A07G044_GPU_ACE_CLK, R9A07G044_CLK_P1, 0x558, 2, 0), - DEF_MOD("cru_sysclk", R9A07G044_CRU_SYSCLK, CLK_M2_DIV2, + DEF_MOD("cru_sysclk", R9A07G044_CRU_SYSCLK, CLK_M2_DIV2, 0x564, 0, MSTOP(BUS_PERI_VIDEO, BIT(3))), - DEF_MOD("cru_vclk", R9A07G044_CRU_VCLK, R9A07G044_CLK_M2, + DEF_MOD("cru_vclk", R9A07G044_CRU_VCLK, R9A07G044_CLK_M2, 0x564, 1, MSTOP(BUS_PERI_VIDEO, BIT(3))), - DEF_MOD("cru_pclk", R9A07G044_CRU_PCLK, R9A07G044_CLK_ZT, + DEF_MOD("cru_pclk", R9A07G044_CRU_PCLK, R9A07G044_CLK_ZT, 0x564, 2, MSTOP(BUS_PERI_VIDEO, BIT(3))), - DEF_MOD("cru_aclk", R9A07G044_CRU_ACLK, R9A07G044_CLK_M0, + DEF_MOD("cru_aclk", R9A07G044_CRU_ACLK, R9A07G044_CLK_M0, 0x564, 3, MSTOP(BUS_PERI_VIDEO, BIT(3))), DEF_MOD("dsi_pll_clk", R9A07G044_MIPI_DSI_PLLCLK, R9A07G044_CLK_M1, 0x568, 0, MSTOP(BUS_PERI_VIDEO, GENMASK(6, 5))), From 58afc207832f750e692f5e72656fa551cacb9e3a Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:24 -0400 Subject: [PATCH 0384/2711] clk: renesas: rzg2l: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250811-clk-for-stephen-round-rate-v1-92-b3bf97b038dc@redhat.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 187233302818..b508823f9723 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -824,11 +824,10 @@ static unsigned long rzg2l_cpg_sipll5_recalc_rate(struct clk_hw *hw, return pll5_rate; } -static long rzg2l_cpg_sipll5_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *parent_rate) +static int rzg2l_cpg_sipll5_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - return rate; + return 0; } static int rzg2l_cpg_sipll5_set_rate(struct clk_hw *hw, @@ -902,7 +901,7 @@ static int rzg2l_cpg_sipll5_set_rate(struct clk_hw *hw, static const struct clk_ops rzg2l_cpg_sipll5_ops = { .recalc_rate = rzg2l_cpg_sipll5_recalc_rate, - .round_rate = rzg2l_cpg_sipll5_round_rate, + .determine_rate = rzg2l_cpg_sipll5_determine_rate, .set_rate = rzg2l_cpg_sipll5_set_rate, }; From 54653bb3ec83d1f717adab6108db82a3966d19ee Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:25 -0400 Subject: [PATCH 0385/2711] clk: renesas: rzv2h: remove round_rate() in favor of determine_rate() This driver implements both the determine_rate() and round_rate() clk ops, and the round_rate() clk ops is deprecated. When both are defined, clk_core_determine_round_nolock() from the clk core will only use the determine_rate() clk ops, so let's remove the round_rate() clk ops since it's unused. Signed-off-by: Brian Masney Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250811-clk-for-stephen-round-rate-v1-93-b3bf97b038dc@redhat.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzv2h-cpg.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c index f468afbb54e2..58ccbae0f904 100644 --- a/drivers/clk/renesas/rzv2h-cpg.c +++ b/drivers/clk/renesas/rzv2h-cpg.c @@ -294,15 +294,6 @@ static unsigned long rzv2h_ddiv_recalc_rate(struct clk_hw *hw, divider->flags, divider->width); } -static long rzv2h_ddiv_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_divider *divider = to_clk_divider(hw); - - return divider_round_rate(hw, rate, prate, divider->table, - divider->width, divider->flags); -} - static int rzv2h_ddiv_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { @@ -359,7 +350,6 @@ ddiv_timeout: static const struct clk_ops rzv2h_ddiv_clk_divider_ops = { .recalc_rate = rzv2h_ddiv_recalc_rate, - .round_rate = rzv2h_ddiv_round_rate, .determine_rate = rzv2h_ddiv_determine_rate, .set_rate = rzv2h_ddiv_set_rate, }; From 07e7ccd804dc2aac6f3f96129a86b02391b5002d Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 12 Aug 2025 18:17:20 +0100 Subject: [PATCH 0386/2711] clk: renesas: r9a09g077: Add module clocks for SCI1-SCI5 Add asynchronous core clocks and module clocks for SCI channels 1 through 5 on the RZ/T2H SoC. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250812171720.3245851-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a09g077-cpg.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/clk/renesas/r9a09g077-cpg.c b/drivers/clk/renesas/r9a09g077-cpg.c index 704d14d31e87..1fdd764f9b91 100644 --- a/drivers/clk/renesas/r9a09g077-cpg.c +++ b/drivers/clk/renesas/r9a09g077-cpg.c @@ -46,8 +46,13 @@ #define DIVCA55C2 CONF_PACK(SCKCR2, 10, 1) #define DIVCA55C3 CONF_PACK(SCKCR2, 11, 1) #define DIVCA55S CONF_PACK(SCKCR2, 12, 1) +#define DIVSCI5ASYNC CONF_PACK(SCKCR2, 18, 2) #define DIVSCI0ASYNC CONF_PACK(SCKCR3, 6, 2) +#define DIVSCI1ASYNC CONF_PACK(SCKCR3, 8, 2) +#define DIVSCI2ASYNC CONF_PACK(SCKCR3, 10, 2) +#define DIVSCI3ASYNC CONF_PACK(SCKCR3, 12, 2) +#define DIVSCI4ASYNC CONF_PACK(SCKCR3, 14, 2) #define SEL_PLL CONF_PACK(SCKCR, 22, 1) @@ -84,6 +89,11 @@ enum clk_ids { CLK_SEL_CLK_PLL4, CLK_PLL4D1, CLK_SCI0ASYNC, + CLK_SCI1ASYNC, + CLK_SCI2ASYNC, + CLK_SCI3ASYNC, + CLK_SCI4ASYNC, + CLK_SCI5ASYNC, /* Module Clocks */ MOD_CLK_BASE, @@ -133,6 +143,16 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = { DEF_FIXED(".pll4d1", CLK_PLL4D1, CLK_SEL_CLK_PLL4, 1, 1), DEF_DIV(".sci0async", CLK_SCI0ASYNC, CLK_PLL4D1, DIVSCI0ASYNC, dtable_24_25_30_32), + DEF_DIV(".sci1async", CLK_SCI1ASYNC, CLK_PLL4D1, DIVSCI1ASYNC, + dtable_24_25_30_32), + DEF_DIV(".sci2async", CLK_SCI2ASYNC, CLK_PLL4D1, DIVSCI2ASYNC, + dtable_24_25_30_32), + DEF_DIV(".sci3async", CLK_SCI3ASYNC, CLK_PLL4D1, DIVSCI3ASYNC, + dtable_24_25_30_32), + DEF_DIV(".sci4async", CLK_SCI4ASYNC, CLK_PLL4D1, DIVSCI4ASYNC, + dtable_24_25_30_32), + DEF_DIV(".sci5async", CLK_SCI5ASYNC, CLK_PLL4D1, DIVSCI5ASYNC, + dtable_24_25_30_32), /* Core output clk */ DEF_DIV("CA55C0", R9A09G077_CLK_CA55C0, CLK_SEL_CLK_PLL0, DIVCA55C0, @@ -155,9 +175,14 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = { static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = { DEF_MOD("sci0fck", 8, CLK_SCI0ASYNC), + DEF_MOD("sci1fck", 9, CLK_SCI1ASYNC), + DEF_MOD("sci2fck", 10, CLK_SCI2ASYNC), + DEF_MOD("sci3fck", 11, CLK_SCI3ASYNC), + DEF_MOD("sci4fck", 12, CLK_SCI4ASYNC), DEF_MOD("iic0", 100, R9A09G077_CLK_PCLKL), DEF_MOD("iic1", 101, R9A09G077_CLK_PCLKL), DEF_MOD("usb", 408, R9A09G077_CLK_PCLKAM), + DEF_MOD("sci5fck", 600, CLK_SCI5ASYNC), DEF_MOD("iic2", 601, R9A09G077_CLK_PCLKL), DEF_MOD("sdhi0", 1212, R9A09G077_CLK_PCLKAM), DEF_MOD("sdhi1", 1213, R9A09G077_CLK_PCLKAM), From 75c21418beb92382dda164fdc2554610b49ed441 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 19 Aug 2025 01:15:22 +0100 Subject: [PATCH 0387/2711] phy: sun4i-usb: drop num_phys assumption So far we set a number of expected Allwinner USB PHY instances for any given compatible string, and would fail if we do not find every PHY described properly in the DT (missing reset/PMU/clocks). This is somewhat redundant, as the DT only describes the resources for the implemented PHYs, but goes in line with being strict about firmware descriptions, and rather fixing things in the driver code, based on the compatible string. However this causes issues when we make a mistake, like we did recently on the A523: there are actually three USB PHYs, not two, as we assumed. Changing the number in the driver and the compatible string would cause all kinds of compatibility issues, both with older and newer DTs. To avoid problems with newer kernels and older or newer DTs, we can change the driver code to deduce the number of PHY instances from what's described in the DT. This has the added advantage of not requiring new compatible strings for new SoCs when just the number of PHYs change, which already happened and might occur again in the future. Drop the num_phys member from the config struct, and remove the fixed number of PHYs from each SoC's config description. Then enumerate the usb_reset properties for all of the maximum four PHY instances, and just stop once we cannot find such a property anymore. The binding describes the reset property as mandatory for each PHY instance, and each DT in the kernel tree matches exactly the num_phys value in the current driver code, so we can rely on that. Apart from being more future proof, this will solve the A523 mishap: Older DTs would just describe two PHYs, whereas newer ones would feature all three of them. In any case we would get a valid number, matching the other nodes in the DT. Older kernels would always enumerate two PHYs, which at least does not cause any regressions. Signed-off-by: Andre Przywara Link: https://lore.kernel.org/r/20250819001522.13011-1-andre.przywara@arm.com Signed-off-by: Vinod Koul --- drivers/phy/allwinner/phy-sun4i-usb.c | 38 +++++++++------------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index 8873aed3a52a..59d38d88efb0 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -97,7 +97,6 @@ #define POLL_TIME msecs_to_jiffies(250) struct sun4i_usb_phy_cfg { - int num_phys; int hsic_index; u32 disc_thresh; u32 hci_phy_ctl_clear; @@ -115,6 +114,7 @@ struct sun4i_usb_phy_data { const struct sun4i_usb_phy_cfg *cfg; enum usb_dr_mode dr_mode; spinlock_t reg_lock; /* guard access to phyctl reg */ + int num_phys; struct sun4i_usb_phy { struct phy *phy; void __iomem *pmu; @@ -686,7 +686,7 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev, { struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); - if (args->args[0] >= data->cfg->num_phys) + if (args->args[0] >= data->num_phys) return ERR_PTR(-ENODEV); if (data->cfg->missing_phys & BIT(args->args[0])) @@ -779,13 +779,22 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return ret; } - for (i = 0; i < data->cfg->num_phys; i++) { + for (i = 0; i < MAX_PHYS; i++) { struct sun4i_usb_phy *phy = data->phys + i; char name[32]; if (data->cfg->missing_phys & BIT(i)) continue; + snprintf(name, sizeof(name), "usb%d_reset", i); + phy->reset = devm_reset_control_get(dev, name); + if (IS_ERR(phy->reset)) { + if (PTR_ERR(phy->reset) == -ENOENT) + break; + dev_err(dev, "failed to get reset %s\n", name); + return PTR_ERR(phy->reset); + } + snprintf(name, sizeof(name), "usb%d_vbus", i); phy->vbus = devm_regulator_get_optional(dev, name); if (IS_ERR(phy->vbus)) { @@ -828,13 +837,6 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } } - snprintf(name, sizeof(name), "usb%d_reset", i); - phy->reset = devm_reset_control_get(dev, name); - if (IS_ERR(phy->reset)) { - dev_err(dev, "failed to get reset %s\n", name); - return PTR_ERR(phy->reset); - } - if (i || data->cfg->phy0_dual_route) { /* No pmu for musb */ snprintf(name, sizeof(name), "pmu%d", i); phy->pmu = devm_platform_ioremap_resource_byname(pdev, name); @@ -851,6 +853,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) phy->index = i; phy_set_drvdata(phy->phy, &data->phys[i]); } + data->num_phys = i; data->id_det_irq = gpiod_to_irq(data->id_det_gpio); if (data->id_det_irq > 0) { @@ -901,28 +904,24 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } static const struct sun4i_usb_phy_cfg suniv_f1c100s_cfg = { - .num_phys = 1, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, }; static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = { - .num_phys = 3, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, }; static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = { - .num_phys = 2, .disc_thresh = 2, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, }; static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = { - .num_phys = 3, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, @@ -930,14 +929,12 @@ static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = { }; static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = { - .num_phys = 3, .disc_thresh = 2, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, }; static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = { - .num_phys = 2, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, @@ -945,7 +942,6 @@ static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = { }; static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = { - .num_phys = 2, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -953,7 +949,6 @@ static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = { }; static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = { - .num_phys = 3, .hsic_index = 2, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -961,7 +956,6 @@ static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = { }; static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { - .num_phys = 4, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -970,7 +964,6 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { }; static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = { - .num_phys = 3, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -979,7 +972,6 @@ static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = { }; static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = { - .num_phys = 1, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -988,7 +980,6 @@ static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = { }; static const struct sun4i_usb_phy_cfg sun20i_d1_cfg = { - .num_phys = 2, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, .hci_phy_ctl_clear = PHY_CTL_SIDDQ, @@ -997,7 +988,6 @@ static const struct sun4i_usb_phy_cfg sun20i_d1_cfg = { }; static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { - .num_phys = 2, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, @@ -1006,7 +996,6 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { }; static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = { - .num_phys = 4, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, .phy0_dual_route = true, @@ -1015,7 +1004,6 @@ static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = { }; static const struct sun4i_usb_phy_cfg sun50i_h616_cfg = { - .num_phys = 4, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, From e1e1e77f7df7cbee959ba024e5475907fe561c98 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:58 +0200 Subject: [PATCH 0388/2711] phy: remove unneeded 'fast_io' parameter in regmap_config When using MMIO with regmap, fast_io is implied. No need to set it again. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250813161517.4746-13-wsa+renesas@sang-engineering.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 1 - drivers/phy/rockchip/phy-rockchip-usbdp.c | 1 - drivers/phy/ti/phy-am654-serdes.c | 1 - drivers/phy/ti/phy-j721e-wiz.c | 1 - 4 files changed, 4 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c index 79db57ee90d1..01bbf668e05e 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -795,7 +795,6 @@ static const struct regmap_config rk_hdptx_phy_regmap_config = { .val_bits = 32, .writeable_reg = rk_hdptx_phy_is_rw_reg, .readable_reg = rk_hdptx_phy_is_rw_reg, - .fast_io = true, .max_register = 0x18b4, }; diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index c066cc0a7b4f..010e9d2d6fac 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -1430,7 +1430,6 @@ static const struct regmap_config rk_udphy_pma_regmap_cfg = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .fast_io = true, .max_register = 0x20dc, }; diff --git a/drivers/phy/ti/phy-am654-serdes.c b/drivers/phy/ti/phy-am654-serdes.c index 431b223996e0..5b6c27aa7e8b 100644 --- a/drivers/phy/ti/phy-am654-serdes.c +++ b/drivers/phy/ti/phy-am654-serdes.c @@ -99,7 +99,6 @@ static const struct regmap_config serdes_am654_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, .max_register = 0x1ffc, }; diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index ab2a4f2c0a5b..a8b440c6c46b 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1319,7 +1319,6 @@ static const struct regmap_config wiz_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .fast_io = true, }; static struct wiz_data j721e_16g_data = { From 03777dbd8c9d825fc6f792e4e85be9e4ce4c7f8f Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Wed, 23 Jul 2025 09:12:11 +0200 Subject: [PATCH 0389/2711] x86/kconfig: Drop unused and needless config X86_64_SMP As part of 38a4968b3190 ("x86/percpu/64: Remove INIT_PER_CPU macros"), the only use of the config option X86_64_SMP in the kernel tree is removed. As this config option X86_64_SMP is just equivalent to X86_64 && SMP, the source code in the tree just uses that expression in the few places where needed. Note further that this option cannot be explicitly enabled or disabled when configuring the kernel build configuration. Drop this needless and unused config option. No functional change. Signed-off-by: Lukas Bulwahn Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20250723071211.622802-1-lukas.bulwahn@redhat.com --- arch/x86/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 58d890fe2100..2eb3bb6fb371 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -410,10 +410,6 @@ config HAVE_INTEL_TXT def_bool y depends on INTEL_IOMMU && ACPI -config X86_64_SMP - def_bool y - depends on X86_64 && SMP - config ARCH_SUPPORTS_UPROBES def_bool y From a8f9de937dbf7bdabda72bd0c51e201e550129c2 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Thu, 14 Aug 2025 09:39:43 +0800 Subject: [PATCH 0390/2711] phy: rockchip: naneng-combphy: Convert comma to semicolon Replace comma between expressions with semicolons. Using a ',' in place of a ';' can have unintended side effects. Although that is not the case here, it is seems best to use ';' unless ',' is intended. Found by inspection. No functional change intended. Compile tested only. Signed-off-by: Chen Ni Link: https://lore.kernel.org/r/20250814013943.2905307-1-nichen@iscas.ac.cn Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 0d25872e6712..a3ef19807b9e 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -1252,7 +1252,7 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) writel(val, priv->mmio + RK3568_PHYREG15); /* Set PLL KVCO fine tuning signals. */ - val = RK3568_PHYREG33_PLL_KVCO_VALUE << RK3568_PHYREG33_PLL_KVCO_SHIFT, + val = RK3568_PHYREG33_PLL_KVCO_VALUE << RK3568_PHYREG33_PLL_KVCO_SHIFT; rockchip_combphy_updatel(priv, RK3568_PHYREG33_PLL_KVCO_MASK, val, RK3568_PHYREG33); /* Enable controlling random jitter. */ From 3bad7fe22796a420c6e16b591c37ed1bd6cc2a30 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Aug 2025 18:33:19 +0200 Subject: [PATCH 0391/2711] dt-bindings: phy: qcom,sc8280xp-qmp-usb43dp: Reference usb-switch.yaml to allow mode-switch The QMP USB3/DP Combo PHY can work in 3 modes: - DisplayPort Only - USB3 Only - USB3 + DisplayPort Combo mode In order to switch between those modes, the PHY needs to receive Type-C events, allow marking to the phy with the mode-switch property in order to allow the PHY to Type-C events. Reference usb-switch.yaml as a simpler way to allow the mode-switch property instead of duplicating the property definition. Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Signed-off-by: Konrad Dybcio Tested-by: Neil Armstrong # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-1-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml index 38ce04c35d94..c8bc512df08b 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml @@ -73,10 +73,8 @@ properties: description: See include/dt-bindings/phy/phy-qcom-qmp.h - orientation-switch: - description: - Flag the PHY as possible handler of USB Type-C orientation switching - type: boolean + mode-switch: true + orientation-switch: true ports: $ref: /schemas/graph.yaml#/properties/ports @@ -106,6 +104,7 @@ required: - "#phy-cells" allOf: + - $ref: /schemas/usb/usb-switch.yaml# - if: properties: compatible: From 5daf1bbc73e249075373e030e7221f46c175e04b Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 7 Aug 2025 18:33:20 +0200 Subject: [PATCH 0392/2711] phy: qcom: qmp-combo: Rename 'mode' to 'phy_mode' There are a numbers of ""modes"" involved: USB mode, Type-C mode (with its altmodes), phy_mode and QMP_PHY mode (DP/combo/USB/off). Rename the generic sounding 'mode' to 'phy_mode' to hopefully make the code easier to follow. Reviewed-by: Dmitry Baryshkov Signed-off-by: Konrad Dybcio Reviewed-by: Neil Armstrong Tested-by: Neil Armstrong # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-2-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index f07d097b129f..30749943f662 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -1846,7 +1846,7 @@ struct qmp_combo { int init_count; struct phy *usb_phy; - enum phy_mode mode; + enum phy_mode phy_mode; unsigned int usb_init_count; struct phy *dp_phy; @@ -3282,7 +3282,7 @@ static int qmp_combo_usb_set_mode(struct phy *phy, enum phy_mode mode, int submo { struct qmp_combo *qmp = phy_get_drvdata(phy); - qmp->mode = mode; + qmp->phy_mode = mode; return 0; } @@ -3311,8 +3311,8 @@ static void qmp_combo_enable_autonomous_mode(struct qmp_combo *qmp) void __iomem *pcs_misc = qmp->pcs_misc; u32 intr_mask; - if (qmp->mode == PHY_MODE_USB_HOST_SS || - qmp->mode == PHY_MODE_USB_DEVICE_SS) + if (qmp->phy_mode == PHY_MODE_USB_HOST_SS || + qmp->phy_mode == PHY_MODE_USB_DEVICE_SS) intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN; else intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL; @@ -3355,7 +3355,7 @@ static int __maybe_unused qmp_combo_runtime_suspend(struct device *dev) { struct qmp_combo *qmp = dev_get_drvdata(dev); - dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); + dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->phy_mode); if (!qmp->init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); @@ -3375,7 +3375,7 @@ static int __maybe_unused qmp_combo_runtime_resume(struct device *dev) struct qmp_combo *qmp = dev_get_drvdata(dev); int ret = 0; - dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); + dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->phy_mode); if (!qmp->init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); From 86390472554b2e8fb4cba16a139cade94be58f72 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Aug 2025 18:33:21 +0200 Subject: [PATCH 0393/2711] phy: qcom: qmp-combo: store DP phy power state Switching the PHY Mode requires the DisplayPort PHY to be powered off, keep track of the DisplayPort phy power state. Reviewed-by: Dmitry Baryshkov Signed-off-by: Neil Armstrong Signed-off-by: Konrad Dybcio Tested-by: Neil Armstrong # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-3-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 30749943f662..839503575497 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -1853,6 +1853,7 @@ struct qmp_combo { unsigned int dp_aux_cfg; struct phy_configure_opts_dp dp_opts; unsigned int dp_init_count; + bool dp_powered_on; struct clk_fixed_rate pipe_clk_fixed; struct clk_hw dp_link_hw; @@ -3133,6 +3134,8 @@ static int qmp_combo_dp_power_on(struct phy *phy) /* Configure link rate, swing, etc. */ cfg->configure_dp_phy(qmp); + qmp->dp_powered_on = true; + mutex_unlock(&qmp->phy_mutex); return 0; @@ -3147,6 +3150,8 @@ static int qmp_combo_dp_power_off(struct phy *phy) /* Assert DP PHY power down */ writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + qmp->dp_powered_on = false; + mutex_unlock(&qmp->phy_mutex); return 0; From dd331112c0adaebbc8fc767fc805da4a641576db Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Aug 2025 18:33:22 +0200 Subject: [PATCH 0394/2711] phy: qcom: qmp-combo: introduce QMPPHY_MODE Introduce an enum for the QMP Combo PHY modes, use it in the QMP commmon phy init function and default to COMBO mode. Signed-off-by: Neil Armstrong [konrad: some renaming and rewording] Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Tested-by: Neil Armstrong # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-4-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 44 ++++++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 839503575497..c65837fc9e4c 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -62,6 +62,12 @@ #define PHY_INIT_COMPLETE_TIMEOUT 10000 +enum qmpphy_mode { + QMPPHY_MODE_USB3DP = 0, + QMPPHY_MODE_DP_ONLY, + QMPPHY_MODE_USB3_ONLY, +}; + /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { /* PCS registers */ @@ -1844,6 +1850,7 @@ struct qmp_combo { struct mutex phy_mutex; int init_count; + enum qmpphy_mode qmpphy_mode; struct phy *usb_phy; enum phy_mode phy_mode; @@ -3037,12 +3044,33 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force) if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) val |= SW_PORTSELECT_VAL; writel(val, com + QPHY_V3_DP_COM_TYPEC_CTRL); - writel(USB3_MODE | DP_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL); - /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ - qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, - SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | - SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + switch (qmp->qmpphy_mode) { + case QMPPHY_MODE_USB3DP: + writel(USB3_MODE | DP_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL); + + /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ + qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + break; + + case QMPPHY_MODE_DP_ONLY: + writel(DP_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL); + + /* bring QMP DP PHY PCS block out of reset */ + qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_DPPHY_RESET_MUX | SW_DPPHY_RESET); + break; + + case QMPPHY_MODE_USB3_ONLY: + writel(USB3_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL); + + /* bring QMP USB PHY PCS block out of reset */ + qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + break; + } qphy_clrbits(com, QPHY_V3_DP_COM_SWI_CTRL, 0x03); qphy_clrbits(com, QPHY_V3_DP_COM_SW_RESET, SW_RESET); @@ -4053,6 +4081,12 @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; + /* + * The hw default is USB3_ONLY, but USB3+DP mode lets us more easily + * check both sub-blocks' init tables for blunders at probe time. + */ + qmp->qmpphy_mode = QMPPHY_MODE_USB3DP; + qmp->usb_phy = devm_phy_create(dev, usb_np, &qmp_combo_usb_phy_ops); if (IS_ERR(qmp->usb_phy)) { ret = PTR_ERR(qmp->usb_phy); From 896277138c1344cf9f5c415298f048ee29da274d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Aug 2025 18:33:23 +0200 Subject: [PATCH 0395/2711] phy: qcom: qmp-combo: register a typec mux to change the QMPPHY_MODE Register a typec mux in order to change the PHY mode on the Type-C mux events depending on the mode and the svid when in Altmode setup. The DisplayPort phy should be left enabled if is still powered on by the DRM DisplayPort controller, so bail out until the DisplayPort PHY is not powered off. The Type-C Mode/SVID only changes on plug/unplug, and USB SAFE states will be set in between of USB-Only, Combo and DisplayPort Only so this will leave enough time to the DRM DisplayPort controller to turn of the DisplayPort PHY. Signed-off-by: Neil Armstrong [konrad: renaming, rewording, bug fixes] Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Tested-by: Neil Armstrong # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-5-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 118 +++++++++++++++++++++- 1 file changed, 113 insertions(+), 5 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index c65837fc9e4c..7b5af30f1d02 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1868,6 +1869,8 @@ struct qmp_combo { struct typec_switch_dev *sw; enum typec_orientation orientation; + + struct typec_mux_dev *mux; }; static void qmp_v3_dp_aux_init(struct qmp_combo *qmp); @@ -3802,17 +3805,109 @@ static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw, return 0; } -static void qmp_combo_typec_unregister(void *data) +static int qmp_combo_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state) +{ + struct qmp_combo *qmp = typec_mux_get_drvdata(mux); + const struct qmp_phy_cfg *cfg = qmp->cfg; + enum qmpphy_mode new_mode; + unsigned int svid; + + guard(mutex)(&qmp->phy_mutex); + + if (state->alt) + svid = state->alt->svid; + else + svid = 0; + + if (svid == USB_TYPEC_DP_SID) { + switch (state->mode) { + /* DP Only */ + case TYPEC_DP_STATE_C: + case TYPEC_DP_STATE_E: + new_mode = QMPPHY_MODE_DP_ONLY; + break; + + /* DP + USB */ + case TYPEC_DP_STATE_D: + case TYPEC_DP_STATE_F: + + /* Safe fallback...*/ + default: + new_mode = QMPPHY_MODE_USB3DP; + break; + } + } else { + /* No DP SVID => don't care, assume it's just USB3 */ + new_mode = QMPPHY_MODE_USB3_ONLY; + } + + if (new_mode == qmp->qmpphy_mode) { + dev_dbg(qmp->dev, "typec_mux_set: same qmpphy mode, bail out\n"); + return 0; + } + + if (qmp->qmpphy_mode != QMPPHY_MODE_USB3_ONLY && qmp->dp_powered_on) { + dev_dbg(qmp->dev, "typec_mux_set: DP PHY is still in use, delaying switch\n"); + return 0; + } + + dev_dbg(qmp->dev, "typec_mux_set: switching from qmpphy mode %d to %d\n", + qmp->qmpphy_mode, new_mode); + + qmp->qmpphy_mode = new_mode; + + if (qmp->init_count) { + if (qmp->usb_init_count) + qmp_combo_usb_power_off(qmp->usb_phy); + + if (qmp->dp_init_count) + writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); + + qmp_combo_com_exit(qmp, true); + + /* Now everything's powered down, power up the right PHYs */ + qmp_combo_com_init(qmp, true); + + if (new_mode == QMPPHY_MODE_DP_ONLY) { + if (qmp->usb_init_count) + qmp->usb_init_count--; + } + + if (new_mode == QMPPHY_MODE_USB3DP || new_mode == QMPPHY_MODE_USB3_ONLY) { + qmp_combo_usb_power_on(qmp->usb_phy); + if (!qmp->usb_init_count) + qmp->usb_init_count++; + } + + if (new_mode == QMPPHY_MODE_DP_ONLY || new_mode == QMPPHY_MODE_USB3DP) { + if (qmp->dp_init_count) + cfg->dp_aux_init(qmp); + } + } + + return 0; +} + +static void qmp_combo_typec_switch_unregister(void *data) { struct qmp_combo *qmp = data; typec_switch_unregister(qmp->sw); } -static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) +static void qmp_combo_typec_mux_unregister(void *data) +{ + struct qmp_combo *qmp = data; + + typec_mux_unregister(qmp->mux); +} + +static int qmp_combo_typec_register(struct qmp_combo *qmp) { struct typec_switch_desc sw_desc = {}; + struct typec_mux_desc mux_desc = { }; struct device *dev = qmp->dev; + int ret; sw_desc.drvdata = qmp; sw_desc.fwnode = dev->fwnode; @@ -3823,10 +3918,23 @@ static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) return PTR_ERR(qmp->sw); } - return devm_add_action_or_reset(dev, qmp_combo_typec_unregister, qmp); + ret = devm_add_action_or_reset(dev, qmp_combo_typec_switch_unregister, qmp); + if (ret) + return ret; + + mux_desc.drvdata = qmp; + mux_desc.fwnode = dev->fwnode; + mux_desc.set = qmp_combo_typec_mux_set; + qmp->mux = typec_mux_register(dev, &mux_desc); + if (IS_ERR(qmp->mux)) { + dev_err(dev, "Unable to register typec mux: %pe\n", qmp->mux); + return PTR_ERR(qmp->mux); + } + + return devm_add_action_or_reset(dev, qmp_combo_typec_mux_unregister, qmp); } #else -static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) +static int qmp_combo_typec_register(struct qmp_combo *qmp) { return 0; } @@ -4059,7 +4167,7 @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; - ret = qmp_combo_typec_switch_register(qmp); + ret = qmp_combo_typec_register(qmp); if (ret) goto err_node_put; From ab9c8aeb2d208381a7c948ea2f753cbe8a451502 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 22:52:05 +0100 Subject: [PATCH 0396/2711] dt-bindings: phy: renesas,usb2-phy: Add RZ/T2H and RZ/N2H support Document the USB2 PHY controller for the Renesas RZ/T2H (r9a09g077) and RZ/N2H (r9a09g087) SoCs. These SoCs share the same PHY block, which is similar to the one on RZ/G2L but differs in clocks, resets, and register bits. To account for these differences, a new compatible string `renesas,usb2-phy-r9a09g077` is introduced. The RZ/N2H SoC uses the same PHY as RZ/T2H, so it reuses the RZ/T2H compatible string as a fallback. Signed-off-by: Lad Prabhakar Acked-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20250808215209.3692744-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- .../bindings/phy/renesas,usb2-phy.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml b/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml index f45c5f039ae8..179cb4bfc424 100644 --- a/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml @@ -44,6 +44,12 @@ properties: - const: renesas,usb2-phy-r9a09g056 # RZ/V2N - const: renesas,usb2-phy-r9a09g057 + - const: renesas,usb2-phy-r9a09g077 # RZ/T2H + + - items: + - const: renesas,usb2-phy-r9a09g087 # RZ/N2H + - const: renesas,usb2-phy-r9a09g077 + reg: maxItems: 1 @@ -120,6 +126,17 @@ allOf: required: - resets + - if: + properties: + compatible: + contains: + const: renesas,usb2-phy-r9a09g077 + then: + properties: + clocks: + minItems: 2 + resets: false + additionalProperties: false examples: From f75806d26318c08ddb79652cce89086e4da17257 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 22:52:06 +0100 Subject: [PATCH 0397/2711] phy: renesas: rcar-gen3-usb2: store drvdata pointer in channel Store the SoC-specific driver data pointer (struct rcar_gen3_phy_drv_data) directly in struct rcar_gen3_chan instead of copying individual flags into separate channel members. Obtain the drvdata with of_device_get_match_data() in probe and assign it to channel->phy_data. Update all call sites to reference `channel->phy_data->*` for SoC-specific behaviour (for example no_adp_ctrl and utmi_ctrl). Remove the redundant soc_no_adp_ctrl and utmi_ctrl fields from struct rcar_gen3_chan. This simplifies the probe path, reduces duplication, and makes it easier to extend the driver with additional platform-specific fields in the future. Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20250808215209.3692744-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 27 ++++++++++-------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 47beb94cd424..7ac56102aed0 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -122,6 +122,7 @@ struct rcar_gen3_phy { struct rcar_gen3_chan { void __iomem *base; struct device *dev; /* platform_device's device */ + const struct rcar_gen3_phy_drv_data *phy_data; struct extcon_dev *extcon; struct rcar_gen3_phy rphys[NUM_OF_PHYS]; struct regulator *vbus; @@ -133,8 +134,6 @@ struct rcar_gen3_chan { bool extcon_host; bool is_otg_channel; bool uses_otg_pins; - bool soc_no_adp_ctrl; - bool utmi_ctrl; }; struct rcar_gen3_phy_drv_data { @@ -204,7 +203,7 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) u32 val; dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); - if (ch->soc_no_adp_ctrl) { + if (ch->phy_data->no_adp_ctrl) { if (ch->vbus) regulator_hardware_enable(ch->vbus, vbus); @@ -290,7 +289,7 @@ static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) if (!ch->uses_otg_pins) return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; - if (ch->soc_no_adp_ctrl) + if (ch->phy_data->no_adp_ctrl) return !!(readl(ch->base + USB2_LINECTRL1) & USB2_LINECTRL1_USB2_IDMON); return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); @@ -421,7 +420,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) USB2_LINECTRL1_DMRPD_EN | USB2_LINECTRL1_DM_RPD; writel(val, usb2_base + USB2_LINECTRL1); - if (!ch->soc_no_adp_ctrl) { + if (!ch->phy_data->no_adp_ctrl) { val = readl(usb2_base + USB2_VBCTRL); val &= ~USB2_VBCTRL_OCCLREN; writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); @@ -487,7 +486,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) if (rphy->int_enable_bits) rcar_gen3_init_otg(channel); - if (channel->utmi_ctrl) { + if (channel->phy_data->utmi_ctrl) { val = readl(usb2_base + USB2_REGEN_CG_CTRL) | USB2_REGEN_CG_CTRL_UPHY_WEN; writel(val, usb2_base + USB2_REGEN_CG_CTRL); @@ -730,7 +729,6 @@ rpm_put: static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { - const struct rcar_gen3_phy_drv_data *phy_data; struct device *dev = &pdev->dev; struct rcar_gen3_chan *channel; struct phy_provider *provider; @@ -773,8 +771,8 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) */ pm_runtime_enable(dev); - phy_data = of_device_get_match_data(dev); - if (!phy_data) { + channel->phy_data = of_device_get_match_data(dev); + if (!channel->phy_data) { ret = -EINVAL; goto error; } @@ -782,22 +780,19 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) platform_set_drvdata(pdev, channel); channel->dev = dev; - if (phy_data->init_bus) { + if (channel->phy_data->init_bus) { ret = rcar_gen3_phy_usb2_init_bus(channel); if (ret) goto error; } - channel->soc_no_adp_ctrl = phy_data->no_adp_ctrl; - if (phy_data->no_adp_ctrl) + if (channel->phy_data->no_adp_ctrl) channel->obint_enable_bits = USB2_OBINT_IDCHG_EN; - channel->utmi_ctrl = phy_data->utmi_ctrl; - spin_lock_init(&channel->lock); for (i = 0; i < NUM_OF_PHYS; i++) { channel->rphys[i].phy = devm_phy_create(dev, NULL, - phy_data->phy_usb2_ops); + channel->phy_data->phy_usb2_ops); if (IS_ERR(channel->rphys[i].phy)) { dev_err(dev, "Failed to create USB2 PHY\n"); ret = PTR_ERR(channel->rphys[i].phy); @@ -808,7 +803,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) phy_set_drvdata(channel->rphys[i].phy, &channel->rphys[i]); } - if (channel->soc_no_adp_ctrl && channel->is_otg_channel) + if (channel->phy_data->no_adp_ctrl && channel->is_otg_channel) channel->vbus = devm_regulator_get_exclusive(dev, "vbus"); else channel->vbus = devm_regulator_get_optional(dev, "vbus"); From 4b7aa47e4c2c921b9511389bf42a4e30d64373e6 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 22:52:07 +0100 Subject: [PATCH 0398/2711] phy: renesas: rcar-gen3-usb2: Allow SoC-specific OBINT bits via phy_data Update the PHY driver to support SoC-specific OBINT enable bits by introducing the `obint_enable_bits` field in the `rcar_gen3_phy_drv_data` structure. This allows each SoC to specify bits required. Signed-off-by: Lad Prabhakar Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250808215209.3692744-4-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 27 ++++++++++++------------ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 7ac56102aed0..a37af7d8f2f4 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -71,8 +71,7 @@ /* OBINTSTA and OBINTEN */ #define USB2_OBINT_SESSVLDCHG BIT(12) #define USB2_OBINT_IDDIGCHG BIT(11) -#define USB2_OBINT_BITS (USB2_OBINT_SESSVLDCHG | \ - USB2_OBINT_IDDIGCHG) +#define USB2_OBINT_IDCHG_EN BIT(0) /* RZ/G2L specific */ /* VBCTRL */ #define USB2_VBCTRL_OCCLREN BIT(16) @@ -93,7 +92,6 @@ #define USB2_ADPCTRL_DRVVBUS BIT(4) /* RZ/G2L specific */ -#define USB2_OBINT_IDCHG_EN BIT(0) #define USB2_LINECTRL1_USB2_IDMON BIT(0) #define NUM_OF_PHYS 4 @@ -130,7 +128,6 @@ struct rcar_gen3_chan { struct work_struct work; spinlock_t lock; /* protects access to hardware and driver data structure. */ enum usb_dr_mode dr_mode; - u32 obint_enable_bits; bool extcon_host; bool is_otg_channel; bool uses_otg_pins; @@ -141,6 +138,7 @@ struct rcar_gen3_phy_drv_data { bool no_adp_ctrl; bool init_bus; bool utmi_ctrl; + u32 obint_enable_bits; }; /* @@ -225,9 +223,9 @@ static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable) u32 val = readl(usb2_base + USB2_OBINTEN); if (ch->uses_otg_pins && enable) - val |= ch->obint_enable_bits; + val |= ch->phy_data->obint_enable_bits; else - val &= ~ch->obint_enable_bits; + val &= ~ch->phy_data->obint_enable_bits; writel(val, usb2_base + USB2_OBINTEN); } @@ -430,7 +428,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) mdelay(20); writel(0xffffffff, usb2_base + USB2_OBINTSTA); - writel(ch->obint_enable_bits, usb2_base + USB2_OBINTEN); + writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTEN); rcar_gen3_device_recognition(ch); } @@ -450,9 +448,9 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) scoped_guard(spinlock, &ch->lock) { status = readl(usb2_base + USB2_OBINTSTA); - if (status & ch->obint_enable_bits) { + if (status & ch->phy_data->obint_enable_bits) { dev_vdbg(dev, "%s: %08x\n", __func__, status); - writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA); + writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA); rcar_gen3_device_recognition(ch); ret = IRQ_HANDLED; } @@ -591,28 +589,35 @@ static const struct phy_ops rz_g1c_phy_usb2_ops = { static const struct rcar_gen3_phy_drv_data rcar_gen3_phy_usb2_data = { .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, .no_adp_ctrl = false, + .obint_enable_bits = USB2_OBINT_SESSVLDCHG | + USB2_OBINT_IDDIGCHG, }; static const struct rcar_gen3_phy_drv_data rz_g1c_phy_usb2_data = { .phy_usb2_ops = &rz_g1c_phy_usb2_ops, .no_adp_ctrl = false, + .obint_enable_bits = USB2_OBINT_SESSVLDCHG | + USB2_OBINT_IDDIGCHG, }; static const struct rcar_gen3_phy_drv_data rz_g2l_phy_usb2_data = { .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, .no_adp_ctrl = true, + .obint_enable_bits = USB2_OBINT_IDCHG_EN, }; static const struct rcar_gen3_phy_drv_data rz_g3s_phy_usb2_data = { .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, .no_adp_ctrl = true, .init_bus = true, + .obint_enable_bits = USB2_OBINT_IDCHG_EN, }; static const struct rcar_gen3_phy_drv_data rz_v2h_phy_usb2_data = { .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, .no_adp_ctrl = true, .utmi_ctrl = true, + .obint_enable_bits = USB2_OBINT_IDCHG_EN, }; static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { @@ -747,7 +752,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) if (IS_ERR(channel->base)) return PTR_ERR(channel->base); - channel->obint_enable_bits = USB2_OBINT_BITS; channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node); if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { channel->is_otg_channel = true; @@ -786,9 +790,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) goto error; } - if (channel->phy_data->no_adp_ctrl) - channel->obint_enable_bits = USB2_OBINT_IDCHG_EN; - spin_lock_init(&channel->lock); for (i = 0; i < NUM_OF_PHYS; i++) { channel->rphys[i].phy = devm_phy_create(dev, NULL, From b725741f1c21e8507a58ae86c5a80ca383f96852 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 22:52:08 +0100 Subject: [PATCH 0399/2711] phy: renesas: rcar-gen3-usb2: Add support for RZ/T2H SoC Add initial support for the Renesas RZ/T2H SoC to the R-Car Gen3 USB2 PHY driver. The RZ/T2H SoC requires configuration of additional hardware-specific bits for proper VBUS level control and OTG operation. Introduce the `vblvl_ctrl` flag in the SoC-specific driver data to enable handling of VBUS level selection logic using `VBCTRL.VBLVL` bits. This is required for managing the VBUS status detection and drive logic based on SoC-specific needs. Signed-off-by: Lad Prabhakar Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250808215209.3692744-5-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 82 ++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index a37af7d8f2f4..8caef9cb228c 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -9,6 +9,8 @@ * Copyright (C) 2014 Cogent Embedded, Inc. */ +#include +#include #include #include #include @@ -69,13 +71,20 @@ #define USB2_COMMCTRL_OTG_PERI BIT(31) /* 1 = Peripheral mode */ /* OBINTSTA and OBINTEN */ +#define USB2_OBINTSTA_CLEAR GENMASK(31, 0) #define USB2_OBINT_SESSVLDCHG BIT(12) #define USB2_OBINT_IDDIGCHG BIT(11) +#define USB2_OBINT_VBSTAINT BIT(3) #define USB2_OBINT_IDCHG_EN BIT(0) /* RZ/G2L specific */ /* VBCTRL */ +#define USB2_VBCTRL_VBSTA_MASK GENMASK(31, 28) +#define USB2_VBCTRL_VBSTA_DEFAULT 2 +#define USB2_VBCTRL_VBLVL_MASK GENMASK(23, 20) +#define USB2_VBCTRL_VBLVL(m) FIELD_PREP_CONST(USB2_VBCTRL_VBLVL_MASK, (m)) #define USB2_VBCTRL_OCCLREN BIT(16) #define USB2_VBCTRL_DRVVBUSSEL BIT(8) +#define USB2_VBCTRL_SIDDQREL BIT(2) #define USB2_VBCTRL_VBOUT BIT(0) /* LINECTRL1 */ @@ -88,6 +97,7 @@ /* ADPCTRL */ #define USB2_ADPCTRL_OTGSESSVLD BIT(20) #define USB2_ADPCTRL_IDDIG BIT(19) +#define USB2_ADPCTRL_VBUSVALID BIT(18) #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ #define USB2_ADPCTRL_DRVVBUS BIT(4) @@ -138,6 +148,7 @@ struct rcar_gen3_phy_drv_data { bool no_adp_ctrl; bool init_bus; bool utmi_ctrl; + bool vblvl_ctrl; u32 obint_enable_bits; }; @@ -201,7 +212,7 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) u32 val; dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); - if (ch->phy_data->no_adp_ctrl) { + if (ch->phy_data->no_adp_ctrl || ch->phy_data->vblvl_ctrl) { if (ch->vbus) regulator_hardware_enable(ch->vbus, vbus); @@ -284,6 +295,16 @@ static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) { + if (ch->phy_data->vblvl_ctrl) { + bool vbus_valid; + bool device; + + device = !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); + vbus_valid = !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_VBUSVALID); + + return !(device && !vbus_valid); + } + if (!ch->uses_otg_pins) return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; @@ -419,11 +440,20 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) writel(val, usb2_base + USB2_LINECTRL1); if (!ch->phy_data->no_adp_ctrl) { - val = readl(usb2_base + USB2_VBCTRL); - val &= ~USB2_VBCTRL_OCCLREN; - writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); - val = readl(usb2_base + USB2_ADPCTRL); - writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); + if (ch->phy_data->vblvl_ctrl) { + val = readl(usb2_base + USB2_VBCTRL); + val = (val & ~USB2_VBCTRL_VBLVL_MASK) | USB2_VBCTRL_VBLVL(2); + writel(val, usb2_base + USB2_VBCTRL); + val = readl(usb2_base + USB2_ADPCTRL); + writel(val | USB2_ADPCTRL_IDPULLUP | USB2_ADPCTRL_DRVVBUS, + usb2_base + USB2_ADPCTRL); + } else { + val = readl(usb2_base + USB2_VBCTRL); + val &= ~USB2_VBCTRL_OCCLREN; + writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); + val = readl(usb2_base + USB2_ADPCTRL); + writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); + } } mdelay(20); @@ -433,6 +463,23 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) rcar_gen3_device_recognition(ch); } +static void rcar_gen3_configure_vblvl_ctrl(struct rcar_gen3_chan *ch) +{ + void __iomem *usb2_base = ch->base; + u32 val; + + if (!ch->phy_data->vblvl_ctrl) + return; + + val = readl(usb2_base + USB2_VBCTRL); + if ((val & USB2_VBCTRL_VBSTA_MASK) == + FIELD_PREP_CONST(USB2_VBCTRL_VBSTA_MASK, USB2_VBCTRL_VBSTA_DEFAULT)) + val &= ~USB2_VBCTRL_VBLVL_MASK; + else + val |= USB2_VBCTRL_VBLVL(USB2_VBCTRL_VBSTA_DEFAULT); + writel(val, usb2_base + USB2_VBCTRL); +} + static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) { struct rcar_gen3_chan *ch = _ch; @@ -450,8 +497,12 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) status = readl(usb2_base + USB2_OBINTSTA); if (status & ch->phy_data->obint_enable_bits) { dev_vdbg(dev, "%s: %08x\n", __func__, status); - writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA); + if (ch->phy_data->vblvl_ctrl) + writel(USB2_OBINTSTA_CLEAR, usb2_base + USB2_OBINTSTA); + else + writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA); rcar_gen3_device_recognition(ch); + rcar_gen3_configure_vblvl_ctrl(ch); ret = IRQ_HANDLED; } } @@ -484,6 +535,13 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) if (rphy->int_enable_bits) rcar_gen3_init_otg(channel); + if (channel->phy_data->vblvl_ctrl) { + /* SIDDQ mode release */ + writel(readl(usb2_base + USB2_VBCTRL) | USB2_VBCTRL_SIDDQREL, + usb2_base + USB2_VBCTRL); + udelay(250); + } + if (channel->phy_data->utmi_ctrl) { val = readl(usb2_base + USB2_REGEN_CG_CTRL) | USB2_REGEN_CG_CTRL_UPHY_WEN; writel(val, usb2_base + USB2_REGEN_CG_CTRL); @@ -613,6 +671,12 @@ static const struct rcar_gen3_phy_drv_data rz_g3s_phy_usb2_data = { .obint_enable_bits = USB2_OBINT_IDCHG_EN, }; +static const struct rcar_gen3_phy_drv_data rz_t2h_phy_usb2_data = { + .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, + .vblvl_ctrl = true, + .obint_enable_bits = USB2_OBINT_IDCHG_EN | USB2_OBINT_VBSTAINT, +}; + static const struct rcar_gen3_phy_drv_data rz_v2h_phy_usb2_data = { .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, .no_adp_ctrl = true, @@ -645,6 +709,10 @@ static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { .compatible = "renesas,usb2-phy-r9a09g057", .data = &rz_v2h_phy_usb2_data, }, + { + .compatible = "renesas,usb2-phy-r9a09g077", + .data = &rz_t2h_phy_usb2_data, + }, { .compatible = "renesas,rzg2l-usb2-phy", .data = &rz_g2l_phy_usb2_data, From 5f54134428b48261151c725c64b40be54e373345 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 8 Aug 2025 22:52:09 +0100 Subject: [PATCH 0400/2711] phy: renesas: rcar-gen3-usb2: Move debug print after register value is updated Relocate the debug print in rcar_gen3_enable_vbus_ctrl() to appear after the `val` variable is assigned and updated based on the VBUS state. This ensures that the debug log reflects the actual register value being written, improving debugging accuracy. Signed-off-by: Lad Prabhakar Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250808215209.3692744-6-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 8caef9cb228c..7b4a6e8b7508 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -211,7 +211,6 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) u32 vbus_ctrl_val = USB2_ADPCTRL_DRVVBUS; u32 val; - dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); if (ch->phy_data->no_adp_ctrl || ch->phy_data->vblvl_ctrl) { if (ch->vbus) regulator_hardware_enable(ch->vbus, vbus); @@ -225,6 +224,7 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) val |= vbus_ctrl_val; else val &= ~vbus_ctrl_val; + dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); writel(val, usb2_base + vbus_ctrl_reg); } From ce489635960a6a3fcb0abe0918994f2d8deb02ed Mon Sep 17 00:00:00 2001 From: Yongxing Mou Date: Wed, 30 Jul 2025 15:27:25 +0800 Subject: [PATCH 0401/2711] dt-bindings: phy: Add eDP PHY compatible for QCS8300 Add compatible string for the supported eDP PHY on QCS8300 platform. QCS8300 have the same eDP PHY with SA8775P. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yongxing Mou Link: https://lore.kernel.org/r/20250730072725.1433360-1-quic_yongmou@quicinc.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,edp-phy.yaml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index 293fb6a9b1c3..eb97181cbb95 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -16,13 +16,18 @@ description: properties: compatible: - enum: - - qcom,sa8775p-edp-phy - - qcom,sc7280-edp-phy - - qcom,sc8180x-edp-phy - - qcom,sc8280xp-dp-phy - - qcom,sc8280xp-edp-phy - - qcom,x1e80100-dp-phy + oneOf: + - enum: + - qcom,sa8775p-edp-phy + - qcom,sc7280-edp-phy + - qcom,sc8180x-edp-phy + - qcom,sc8280xp-dp-phy + - qcom,sc8280xp-edp-phy + - qcom,x1e80100-dp-phy + - items: + - enum: + - qcom,qcs8300-edp-phy + - const: qcom,sa8775p-edp-phy reg: items: From 38404274bbee1f0001a490c0dc98aac32a4d7c9d Mon Sep 17 00:00:00 2001 From: Akhilesh Patil Date: Thu, 24 Jul 2025 16:05:07 +0530 Subject: [PATCH 0402/2711] phy: ingenic: use core driver model helper to handle probe errors Use core driver model helper dev_err_probe() defined at drivers/base/core.c in driver probe path to propagate errors. standardize and improve the code of deferred probe error handling using this helper for ingenic usb phy driver. Inspired by, commit a787e5400a1ce ("driver core: add device probe log helper") Signed-off-by: Akhilesh Patil Cc: Andrzej Hajda Link: https://lore.kernel.org/r/aIIMW971BYsIk4As@bhairav-test.ee.iitb.ac.in Signed-off-by: Vinod Koul --- drivers/phy/ingenic/phy-ingenic-usb.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/phy/ingenic/phy-ingenic-usb.c b/drivers/phy/ingenic/phy-ingenic-usb.c index eb2721f72a4c..7e62d46850fd 100644 --- a/drivers/phy/ingenic/phy-ingenic-usb.c +++ b/drivers/phy/ingenic/phy-ingenic-usb.c @@ -339,17 +339,13 @@ static int ingenic_usb_phy_probe(struct platform_device *pdev) priv->clk = devm_clk_get(dev, NULL); if (IS_ERR(priv->clk)) { err = PTR_ERR(priv->clk); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get clock\n"); - return err; + return dev_err_probe(dev, err, "Failed to get clock\n"); } priv->vcc_supply = devm_regulator_get(dev, "vcc"); if (IS_ERR(priv->vcc_supply)) { err = PTR_ERR(priv->vcc_supply); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get regulator\n"); - return err; + return dev_err_probe(dev, err, "Failed to get regulator\n"); } priv->phy = devm_phy_create(dev, NULL, &ingenic_usb_phy_ops); From 72dd8b2914b5db1dccf902971c2ea6b541711b28 Mon Sep 17 00:00:00 2001 From: Abin Joseph Date: Tue, 22 Jul 2025 12:32:55 +0530 Subject: [PATCH 0403/2711] dmaengine: zynqmp_dma: Add shutdown operation support Add shutdown callback to ensure that DMA operations are properly stopped and resources are released during system shutdown or kexec operations. Fix incorrect PM state handling in the remove function that was causing clock disable warnings during the shutdown operations, which was not implemented earlier. The original logic used pm_runtime_enabled() check after calling the pm_runtime_disable(), would always evaluate to true after the disable call, which leads to unconditionally calling the runtime_suspend regardless of the device's actual power state. During shutdown, the device may already be suspended with clock disabled from the autosuspend timer, causing the clock framework to warn about the double-disable attempt. The pm_runtime_active() function checks the actual device power state rather than the PM subsystem's enabled/disabled status. ensuring the runtime_suspend is only called when the device is in active power state. This prevents clock warnings during shutdown while maintaining proper cleanup during normal remove operations. Signed-off-by: Abin Joseph Reviewed-by: Radhey Shyam Pandey Link: https://lore.kernel.org/r/20250722070255.28944-1-abin.joseph@amd.com Signed-off-by: Vinod Koul --- drivers/dma/xilinx/zynqmp_dma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index d05fc5fcc77d..f7e584de4335 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -1173,9 +1173,9 @@ static void zynqmp_dma_remove(struct platform_device *pdev) dma_async_device_unregister(&zdev->common); zynqmp_dma_chan_remove(zdev->chan); - pm_runtime_disable(zdev->dev); - if (!pm_runtime_enabled(zdev->dev)) + if (pm_runtime_active(zdev->dev)) zynqmp_dma_runtime_suspend(zdev->dev); + pm_runtime_disable(zdev->dev); } static const struct of_device_id zynqmp_dma_of_match[] = { @@ -1193,6 +1193,7 @@ static struct platform_driver zynqmp_dma_driver = { }, .probe = zynqmp_dma_probe, .remove = zynqmp_dma_remove, + .shutdown = zynqmp_dma_remove, }; module_platform_driver(zynqmp_dma_driver); From 7a430af7d135be5042f14987bce16f6b40a3f694 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 12 Aug 2025 15:33:07 -0500 Subject: [PATCH 0404/2711] dt-bindings: dma: nvidia,tegra20-apbdma: Add undocumented compatibles and "clock-names" Add the undocumented NVIDIA APBDMA compatibles and "clock-names" which are already in use. There doesn't appear to be any per compatible differences. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250812203308.727731-1-robh@kernel.org Signed-off-by: Vinod Koul --- .../bindings/dma/nvidia,tegra20-apbdma.yaml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/dma/nvidia,tegra20-apbdma.yaml b/Documentation/devicetree/bindings/dma/nvidia,tegra20-apbdma.yaml index a2ffd5209b3b..ea40c4e27a97 100644 --- a/Documentation/devicetree/bindings/dma/nvidia,tegra20-apbdma.yaml +++ b/Documentation/devicetree/bindings/dma/nvidia,tegra20-apbdma.yaml @@ -18,10 +18,17 @@ maintainers: properties: compatible: oneOf: - - const: nvidia,tegra20-apbdma + - enum: + - nvidia,tegra114-apbdma + - nvidia,tegra20-apbdma - items: - const: nvidia,tegra30-apbdma - const: nvidia,tegra20-apbdma + - items: + - enum: + - nvidia,tegra124-apbdma + - nvidia,tegra210-apbdma + - const: nvidia,tegra148-apbdma reg: maxItems: 1 @@ -32,6 +39,9 @@ properties: clocks: maxItems: 1 + clock-names: + const: dma + interrupts: description: Should contain all of the per-channel DMA interrupts in From 847164d47098f55e99503819300b36cca20cb4f7 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 11 Aug 2025 00:58:59 +0200 Subject: [PATCH 0405/2711] dmaengine: idxd: Replace memset(0) + strscpy() with strscpy_pad() Replace memset(0) followed by strscpy() with strscpy_pad() to improve idxd_load_iaa_device_defaults(). This avoids zeroing the memory before copying the strings and ensures the destination buffers are only written to once, simplifying the code and improving efficiency. Signed-off-by: Thorsten Blum Reviewed-by: Dave Jiang Link: https://lore.kernel.org/r/20250810225858.2953-2-thorsten.blum@linux.dev Signed-off-by: Vinod Koul --- drivers/dma/idxd/defaults.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/dma/idxd/defaults.c b/drivers/dma/idxd/defaults.c index c607ae8dd12c..2bbbcd02a0da 100644 --- a/drivers/dma/idxd/defaults.c +++ b/drivers/dma/idxd/defaults.c @@ -36,12 +36,10 @@ int idxd_load_iaa_device_defaults(struct idxd_device *idxd) group->num_wqs++; /* set name to "iaa_crypto" */ - memset(wq->name, 0, WQ_NAME_SIZE + 1); - strscpy(wq->name, "iaa_crypto", WQ_NAME_SIZE + 1); + strscpy_pad(wq->name, "iaa_crypto"); /* set driver_name to "crypto" */ - memset(wq->driver_name, 0, DRIVER_NAME_SIZE + 1); - strscpy(wq->driver_name, "crypto", DRIVER_NAME_SIZE + 1); + strscpy_pad(wq->driver_name, "crypto"); engine = idxd->engines[0]; From c937969a503ebf45e0bebafee4122db22b0091bd Mon Sep 17 00:00:00 2001 From: Anil S Keshavamurthy Date: Fri, 1 Aug 2025 14:59:35 -0700 Subject: [PATCH 0406/2711] dmaengine: idxd: Add a new IAA device ID for Wildcat Lake family platforms A new IAA device ID, 0xfd2d, is introduced across all Wildcat Lake family platforms. Add the device ID to the IDXD driver. Signed-off-by: Anil S Keshavamurthy Signed-off-by: Vinicius Costa Gomes Reviewed-by: Dave Jiang Link: https://lore.kernel.org/r/20250801215936.188555-1-vinicius.gomes@intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/init.c | 2 ++ drivers/dma/idxd/registers.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 35bdefd3728b..f98aa41fa42e 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -80,6 +80,8 @@ static struct pci_device_id idxd_pci_tbl[] = { { PCI_DEVICE_DATA(INTEL, IAA_DMR, &idxd_driver_data[IDXD_TYPE_IAX]) }, /* IAA PTL platforms */ { PCI_DEVICE_DATA(INTEL, IAA_PTL, &idxd_driver_data[IDXD_TYPE_IAX]) }, + /* IAA WCL platforms */ + { PCI_DEVICE_DATA(INTEL, IAA_WCL, &idxd_driver_data[IDXD_TYPE_IAX]) }, { 0, } }; MODULE_DEVICE_TABLE(pci, idxd_pci_tbl); diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h index 9c1c546fe443..0d84bd7a680b 100644 --- a/drivers/dma/idxd/registers.h +++ b/drivers/dma/idxd/registers.h @@ -10,6 +10,7 @@ #define PCI_DEVICE_ID_INTEL_DSA_DMR 0x1212 #define PCI_DEVICE_ID_INTEL_IAA_DMR 0x1216 #define PCI_DEVICE_ID_INTEL_IAA_PTL 0xb02d +#define PCI_DEVICE_ID_INTEL_IAA_WCL 0xfd2d #define DEVICE_VERSION_1 0x100 #define DEVICE_VERSION_2 0x200 From 1daede86fef9e9890c5781541ad4934c776858c5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 30 Jul 2025 17:27:12 +0100 Subject: [PATCH 0407/2711] dmaengine: ppc4xx: Remove space before newline There is a extraneous space before a newline in pr_err and dev_dbg messages. Remove the spaces. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20250730162712.2086439-1-colin.i.king@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/ppc4xx/adma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index 9d2a5a967a99..61500ad7c850 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -874,7 +874,7 @@ static int ppc440spe_dma2_pq_slot_count(dma_addr_t *srcs, pr_err("%s: src_cnt=%d, state=%d, addr_count=%d, order=%lld\n", __func__, src_cnt, state, addr_count, order); for (i = 0; i < src_cnt; i++) - pr_err("\t[%d] 0x%llx \n", i, srcs[i]); + pr_err("\t[%d] 0x%llx\n", i, srcs[i]); BUG(); } @@ -3636,7 +3636,7 @@ static void ppc440spe_adma_issue_pending(struct dma_chan *chan) ppc440spe_chan = to_ppc440spe_adma_chan(chan); dev_dbg(ppc440spe_chan->device->common.dev, - "ppc440spe adma%d: %s %d \n", ppc440spe_chan->device->id, + "ppc440spe adma%d: %s %d\n", ppc440spe_chan->device->id, __func__, ppc440spe_chan->pending); if (ppc440spe_chan->pending) { From a35da57357221a989e59ced9407ba4f2d4d6d2d2 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Tue, 19 Aug 2025 10:57:49 +0200 Subject: [PATCH 0408/2711] crypto: x86 - Remove CONFIG_AS_GFNI Current minimum required version of binutils is 2.30, which supports GFNI instruction mnemonics. Remove check for assembler support of GFNI instructions and all relevant macros for conditional compilation. No functional change intended. Signed-off-by: Uros Bizjak Signed-off-by: Borislav Petkov (AMD) Acked-by: Herbert Xu Link: https://lore.kernel.org/20250819085855.333380-1-ubizjak@gmail.com --- arch/x86/Kconfig.assembler | 5 ----- arch/x86/crypto/Kconfig | 2 +- arch/x86/crypto/aria-aesni-avx-asm_64.S | 10 ---------- arch/x86/crypto/aria-aesni-avx2-asm_64.S | 10 +--------- arch/x86/crypto/aria_aesni_avx2_glue.c | 4 +--- arch/x86/crypto/aria_aesni_avx_glue.c | 4 +--- 6 files changed, 4 insertions(+), 31 deletions(-) diff --git a/arch/x86/Kconfig.assembler b/arch/x86/Kconfig.assembler index c827f694fb72..6b95be002465 100644 --- a/arch/x86/Kconfig.assembler +++ b/arch/x86/Kconfig.assembler @@ -6,11 +6,6 @@ config AS_AVX512 help Supported by binutils >= 2.25 and LLVM integrated assembler -config AS_GFNI - def_bool $(as-instr,vgf2p8mulb %xmm0$(comma)%xmm1$(comma)%xmm2) - help - Supported by binutils >= 2.30 and LLVM integrated assembler - config AS_VAES def_bool $(as-instr,vaesenc %ymm0$(comma)%ymm1$(comma)%ymm2) help diff --git a/arch/x86/crypto/Kconfig b/arch/x86/crypto/Kconfig index 94016c60561e..2f8a447f3546 100644 --- a/arch/x86/crypto/Kconfig +++ b/arch/x86/crypto/Kconfig @@ -319,7 +319,7 @@ config CRYPTO_ARIA_AESNI_AVX2_X86_64 config CRYPTO_ARIA_GFNI_AVX512_X86_64 tristate "Ciphers: ARIA with modes: ECB, CTR (AVX512/GFNI)" - depends on 64BIT && AS_GFNI + depends on 64BIT select CRYPTO_SKCIPHER select CRYPTO_ALGAPI select CRYPTO_ARIA diff --git a/arch/x86/crypto/aria-aesni-avx-asm_64.S b/arch/x86/crypto/aria-aesni-avx-asm_64.S index 9556dacd9841..932fb17308e7 100644 --- a/arch/x86/crypto/aria-aesni-avx-asm_64.S +++ b/arch/x86/crypto/aria-aesni-avx-asm_64.S @@ -295,7 +295,6 @@ vpshufb t1, t0, t2; \ vpxor t2, x7, x7; -#ifdef CONFIG_AS_GFNI #define aria_sbox_8way_gfni(x0, x1, x2, x3, \ x4, x5, x6, x7, \ t0, t1, t2, t3, \ @@ -318,8 +317,6 @@ vgf2p8affineinvqb $0, t2, x3, x3; \ vgf2p8affineinvqb $0, t2, x7, x7 -#endif /* CONFIG_AS_GFNI */ - #define aria_sbox_8way(x0, x1, x2, x3, \ x4, x5, x6, x7, \ t0, t1, t2, t3, \ @@ -561,7 +558,6 @@ y4, y5, y6, y7, \ mem_tmp, 8); -#ifdef CONFIG_AS_GFNI #define aria_fe_gfni(x0, x1, x2, x3, \ x4, x5, x6, x7, \ y0, y1, y2, y3, \ @@ -719,8 +715,6 @@ y4, y5, y6, y7, \ mem_tmp, 8); -#endif /* CONFIG_AS_GFNI */ - /* NB: section is mergeable, all elements must be aligned 16-byte blocks */ .section .rodata.cst16, "aM", @progbits, 16 .align 16 @@ -772,7 +766,6 @@ .Ltf_hi__x2__and__fwd_aff: .octa 0x3F893781E95FE1576CDA64D2BA0CB204 -#ifdef CONFIG_AS_GFNI /* AES affine: */ #define tf_aff_const BV8(1, 1, 0, 0, 0, 1, 1, 0) .Ltf_aff_bitmatrix: @@ -871,7 +864,6 @@ BV8(0, 0, 0, 0, 0, 1, 0, 0), BV8(0, 0, 0, 0, 0, 0, 1, 0), BV8(0, 0, 0, 0, 0, 0, 0, 1)) -#endif /* CONFIG_AS_GFNI */ /* 4-bit mask */ .section .rodata.cst4.L0f0f0f0f, "aM", @progbits, 4 @@ -1140,7 +1132,6 @@ SYM_TYPED_FUNC_START(aria_aesni_avx_ctr_crypt_16way) RET; SYM_FUNC_END(aria_aesni_avx_ctr_crypt_16way) -#ifdef CONFIG_AS_GFNI SYM_FUNC_START_LOCAL(__aria_aesni_avx_gfni_crypt_16way) /* input: * %r9: rk @@ -1359,4 +1350,3 @@ SYM_TYPED_FUNC_START(aria_aesni_avx_gfni_ctr_crypt_16way) FRAME_END RET; SYM_FUNC_END(aria_aesni_avx_gfni_ctr_crypt_16way) -#endif /* CONFIG_AS_GFNI */ diff --git a/arch/x86/crypto/aria-aesni-avx2-asm_64.S b/arch/x86/crypto/aria-aesni-avx2-asm_64.S index c60fa2980630..ed53d4f46bd7 100644 --- a/arch/x86/crypto/aria-aesni-avx2-asm_64.S +++ b/arch/x86/crypto/aria-aesni-avx2-asm_64.S @@ -302,7 +302,6 @@ vpbroadcastb ((round * 16) + idx + 4)(rk), t0; \ vpxor t0, x7, x7; -#ifdef CONFIG_AS_GFNI #define aria_sbox_8way_gfni(x0, x1, x2, x3, \ x4, x5, x6, x7, \ t0, t1, t2, t3, \ @@ -325,7 +324,6 @@ vgf2p8affineinvqb $0, t2, x3, x3; \ vgf2p8affineinvqb $0, t2, x7, x7 -#endif /* CONFIG_AS_GFNI */ #define aria_sbox_8way(x0, x1, x2, x3, \ x4, x5, x6, x7, \ t0, t1, t2, t3, \ @@ -598,7 +596,7 @@ aria_load_state_8way(y0, y1, y2, y3, \ y4, y5, y6, y7, \ mem_tmp, 8); -#ifdef CONFIG_AS_GFNI + #define aria_fe_gfni(x0, x1, x2, x3, \ x4, x5, x6, x7, \ y0, y1, y2, y3, \ @@ -752,7 +750,6 @@ aria_load_state_8way(y0, y1, y2, y3, \ y4, y5, y6, y7, \ mem_tmp, 8); -#endif /* CONFIG_AS_GFNI */ .section .rodata.cst32.shufb_16x16b, "aM", @progbits, 32 .align 32 @@ -806,7 +803,6 @@ .Ltf_hi__x2__and__fwd_aff: .octa 0x3F893781E95FE1576CDA64D2BA0CB204 -#ifdef CONFIG_AS_GFNI .section .rodata.cst8, "aM", @progbits, 8 .align 8 /* AES affine: */ @@ -868,8 +864,6 @@ BV8(0, 0, 0, 0, 0, 0, 1, 0), BV8(0, 0, 0, 0, 0, 0, 0, 1)) -#endif /* CONFIG_AS_GFNI */ - /* 4-bit mask */ .section .rodata.cst4.L0f0f0f0f, "aM", @progbits, 4 .align 4 @@ -1219,7 +1213,6 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_ctr_crypt_32way) RET; SYM_FUNC_END(aria_aesni_avx2_ctr_crypt_32way) -#ifdef CONFIG_AS_GFNI SYM_FUNC_START_LOCAL(__aria_aesni_avx2_gfni_crypt_32way) /* input: * %r9: rk @@ -1438,4 +1431,3 @@ SYM_TYPED_FUNC_START(aria_aesni_avx2_gfni_ctr_crypt_32way) FRAME_END RET; SYM_FUNC_END(aria_aesni_avx2_gfni_ctr_crypt_32way) -#endif /* CONFIG_AS_GFNI */ diff --git a/arch/x86/crypto/aria_aesni_avx2_glue.c b/arch/x86/crypto/aria_aesni_avx2_glue.c index 007b250f774c..1487a49bfbac 100644 --- a/arch/x86/crypto/aria_aesni_avx2_glue.c +++ b/arch/x86/crypto/aria_aesni_avx2_glue.c @@ -26,7 +26,6 @@ asmlinkage void aria_aesni_avx2_ctr_crypt_32way(const void *ctx, u8 *dst, const u8 *src, u8 *keystream, u8 *iv); EXPORT_SYMBOL_GPL(aria_aesni_avx2_ctr_crypt_32way); -#ifdef CONFIG_AS_GFNI asmlinkage void aria_aesni_avx2_gfni_encrypt_32way(const void *ctx, u8 *dst, const u8 *src); EXPORT_SYMBOL_GPL(aria_aesni_avx2_gfni_encrypt_32way); @@ -37,7 +36,6 @@ asmlinkage void aria_aesni_avx2_gfni_ctr_crypt_32way(const void *ctx, u8 *dst, const u8 *src, u8 *keystream, u8 *iv); EXPORT_SYMBOL_GPL(aria_aesni_avx2_gfni_ctr_crypt_32way); -#endif /* CONFIG_AS_GFNI */ static struct aria_avx_ops aria_ops; @@ -213,7 +211,7 @@ static int __init aria_avx2_init(void) return -ENODEV; } - if (boot_cpu_has(X86_FEATURE_GFNI) && IS_ENABLED(CONFIG_AS_GFNI)) { + if (boot_cpu_has(X86_FEATURE_GFNI)) { aria_ops.aria_encrypt_16way = aria_aesni_avx_gfni_encrypt_16way; aria_ops.aria_decrypt_16way = aria_aesni_avx_gfni_decrypt_16way; aria_ops.aria_ctr_crypt_16way = aria_aesni_avx_gfni_ctr_crypt_16way; diff --git a/arch/x86/crypto/aria_aesni_avx_glue.c b/arch/x86/crypto/aria_aesni_avx_glue.c index 4c88ef4eba82..e4e3d78915a5 100644 --- a/arch/x86/crypto/aria_aesni_avx_glue.c +++ b/arch/x86/crypto/aria_aesni_avx_glue.c @@ -26,7 +26,6 @@ asmlinkage void aria_aesni_avx_ctr_crypt_16way(const void *ctx, u8 *dst, const u8 *src, u8 *keystream, u8 *iv); EXPORT_SYMBOL_GPL(aria_aesni_avx_ctr_crypt_16way); -#ifdef CONFIG_AS_GFNI asmlinkage void aria_aesni_avx_gfni_encrypt_16way(const void *ctx, u8 *dst, const u8 *src); EXPORT_SYMBOL_GPL(aria_aesni_avx_gfni_encrypt_16way); @@ -37,7 +36,6 @@ asmlinkage void aria_aesni_avx_gfni_ctr_crypt_16way(const void *ctx, u8 *dst, const u8 *src, u8 *keystream, u8 *iv); EXPORT_SYMBOL_GPL(aria_aesni_avx_gfni_ctr_crypt_16way); -#endif /* CONFIG_AS_GFNI */ static struct aria_avx_ops aria_ops; @@ -199,7 +197,7 @@ static int __init aria_avx_init(void) return -ENODEV; } - if (boot_cpu_has(X86_FEATURE_GFNI) && IS_ENABLED(CONFIG_AS_GFNI)) { + if (boot_cpu_has(X86_FEATURE_GFNI)) { aria_ops.aria_encrypt_16way = aria_aesni_avx_gfni_encrypt_16way; aria_ops.aria_decrypt_16way = aria_aesni_avx_gfni_decrypt_16way; aria_ops.aria_ctr_crypt_16way = aria_aesni_avx_gfni_ctr_crypt_16way; From 46e2c5d604c7de1083ddf7a5f53edcf2eb3f4d12 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 15 Jul 2025 12:10:05 -0700 Subject: [PATCH 0409/2711] doc: Update whatisRCU.rst for recent RCU API additions Bring this file kicking and screaming into the year 2025! [ paulmck: Apply feedback from Bagas Sanjaya. ] Signed-off-by: Paul E. McKenney --- Documentation/RCU/whatisRCU.rst | 146 +++++++++++++++++++++++++------- 1 file changed, 116 insertions(+), 30 deletions(-) diff --git a/Documentation/RCU/whatisRCU.rst b/Documentation/RCU/whatisRCU.rst index be2eb6be16ec..cf0b0ac9f463 100644 --- a/Documentation/RCU/whatisRCU.rst +++ b/Documentation/RCU/whatisRCU.rst @@ -1021,32 +1021,41 @@ RCU list traversal:: list_entry_rcu list_entry_lockless list_first_entry_rcu + list_first_or_null_rcu + list_tail_rcu list_next_rcu + list_next_or_null_rcu list_for_each_entry_rcu list_for_each_entry_continue_rcu list_for_each_entry_from_rcu - list_first_or_null_rcu - list_next_or_null_rcu + list_for_each_entry_lockless hlist_first_rcu hlist_next_rcu hlist_pprev_rcu hlist_for_each_entry_rcu + hlist_for_each_entry_rcu_notrace hlist_for_each_entry_rcu_bh hlist_for_each_entry_from_rcu hlist_for_each_entry_continue_rcu hlist_for_each_entry_continue_rcu_bh hlist_nulls_first_rcu + hlist_nulls_next_rcu hlist_nulls_for_each_entry_rcu + hlist_nulls_for_each_entry_safe hlist_bl_first_rcu hlist_bl_for_each_entry_rcu RCU pointer/list update:: rcu_assign_pointer + rcu_replace_pointer + INIT_LIST_HEAD_RCU list_add_rcu list_add_tail_rcu list_del_rcu list_replace_rcu + list_splice_init_rcu + list_splice_tail_init_rcu hlist_add_behind_rcu hlist_add_before_rcu hlist_add_head_rcu @@ -1054,34 +1063,53 @@ RCU pointer/list update:: hlist_del_rcu hlist_del_init_rcu hlist_replace_rcu - list_splice_init_rcu - list_splice_tail_init_rcu hlist_nulls_del_init_rcu hlist_nulls_del_rcu hlist_nulls_add_head_rcu + hlist_nulls_add_tail_rcu + hlist_nulls_add_fake + hlists_swap_heads_rcu hlist_bl_add_head_rcu - hlist_bl_del_init_rcu hlist_bl_del_rcu hlist_bl_set_first_rcu RCU:: - Critical sections Grace period Barrier + Critical sections Grace period Barrier - rcu_read_lock synchronize_net rcu_barrier - rcu_read_unlock synchronize_rcu - rcu_dereference synchronize_rcu_expedited - rcu_read_lock_held call_rcu - rcu_dereference_check kfree_rcu - rcu_dereference_protected + rcu_read_lock synchronize_net rcu_barrier + rcu_read_unlock synchronize_rcu + guard(rcu)() synchronize_rcu_expedited + scoped_guard(rcu) synchronize_rcu_mult + rcu_dereference call_rcu + rcu_dereference_check call_rcu_hurry + rcu_dereference_protected kfree_rcu + rcu_read_lock_held kvfree_rcu + rcu_read_lock_any_held kfree_rcu_mightsleep + rcu_pointer_handoff cond_synchronize_rcu + unrcu_pointer cond_synchronize_rcu_full + cond_synchronize_rcu_expedited + cond_synchronize_rcu_expedited_full + get_completed_synchronize_rcu + get_completed_synchronize_rcu_full + get_state_synchronize_rcu + get_state_synchronize_rcu_full + poll_state_synchronize_rcu + poll_state_synchronize_rcu_full + same_state_synchronize_rcu + same_state_synchronize_rcu_full + start_poll_synchronize_rcu + start_poll_synchronize_rcu_full + start_poll_synchronize_rcu_expedited + start_poll_synchronize_rcu_expedited_full bh:: Critical sections Grace period Barrier - rcu_read_lock_bh call_rcu rcu_barrier - rcu_read_unlock_bh synchronize_rcu - [local_bh_disable] synchronize_rcu_expedited + rcu_read_lock_bh [Same as RCU] [Same as RCU] + rcu_read_unlock_bh + [local_bh_disable] [and friends] rcu_dereference_bh rcu_dereference_bh_check @@ -1092,9 +1120,9 @@ sched:: Critical sections Grace period Barrier - rcu_read_lock_sched call_rcu rcu_barrier - rcu_read_unlock_sched synchronize_rcu - [preempt_disable] synchronize_rcu_expedited + rcu_read_lock_sched [Same as RCU] [Same as RCU] + rcu_read_unlock_sched + [preempt_disable] [and friends] rcu_read_lock_sched_notrace rcu_read_unlock_sched_notrace @@ -1104,46 +1132,104 @@ sched:: rcu_read_lock_sched_held +RCU: Initialization/cleanup/ordering:: + + RCU_INIT_POINTER + RCU_INITIALIZER + RCU_POINTER_INITIALIZER + init_rcu_head + destroy_rcu_head + init_rcu_head_on_stack + destroy_rcu_head_on_stack + SLAB_TYPESAFE_BY_RCU + + +RCU: Quiescents states and control:: + + cond_resched_tasks_rcu_qs + rcu_all_qs + rcu_softirq_qs_periodic + rcu_end_inkernel_boot + rcu_expedite_gp + rcu_gp_is_expedited + rcu_unexpedite_gp + rcu_cpu_stall_reset + rcu_head_after_call_rcu + rcu_is_watching + + +RCU-sync primitive:: + + rcu_sync_is_idle + rcu_sync_init + rcu_sync_enter + rcu_sync_exit + rcu_sync_dtor + + RCU-Tasks:: - Critical sections Grace period Barrier + Critical sections Grace period Barrier - N/A call_rcu_tasks rcu_barrier_tasks + N/A call_rcu_tasks rcu_barrier_tasks synchronize_rcu_tasks RCU-Tasks-Rude:: - Critical sections Grace period Barrier + Critical sections Grace period Barrier - N/A N/A - synchronize_rcu_tasks_rude + N/A synchronize_rcu_tasks_rude rcu_barrier_tasks_rude + call_rcu_tasks_rude RCU-Tasks-Trace:: - Critical sections Grace period Barrier + Critical sections Grace period Barrier - rcu_read_lock_trace call_rcu_tasks_trace rcu_barrier_tasks_trace + rcu_read_lock_trace call_rcu_tasks_trace rcu_barrier_tasks_trace rcu_read_unlock_trace synchronize_rcu_tasks_trace + guard(rcu_tasks_trace)() + scoped_guard(rcu_tasks_trace) + + +SRCU list traversal:: + list_for_each_entry_srcu + hlist_for_each_entry_srcu SRCU:: - Critical sections Grace period Barrier + Critical sections Grace period Barrier - srcu_read_lock call_srcu srcu_barrier - srcu_read_unlock synchronize_srcu - srcu_dereference synchronize_srcu_expedited + srcu_read_lock call_srcu srcu_barrier + srcu_read_unlock synchronize_srcu + srcu_read_lock_fast synchronize_srcu_expedited + srcu_read_unlock_fast get_state_synchronize_srcu + srcu_read_lock_nmisafe start_poll_synchronize_srcu + srcu_read_unlock_nmisafe start_poll_synchronize_srcu_expedited + srcu_read_lock_notrace poll_state_synchronize_srcu + srcu_read_unlock_notrace + srcu_down_read + srcu_up_read + srcu_down_read_fast + srcu_up_read_fast + guard(srcu)() + scoped_guard(srcu) + srcu_read_lock_held + srcu_dereference srcu_dereference_check + srcu_dereference_notrace srcu_read_lock_held -SRCU: Initialization/cleanup:: + +SRCU: Initialization/cleanup/ordering:: DEFINE_SRCU DEFINE_STATIC_SRCU init_srcu_struct cleanup_srcu_struct + smp_mb__after_srcu_read_unlock All: lockdep-checked RCU utility APIs:: From 820f8da73dfeccf32e7b6580b4c41d0d3e2c2e02 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 15 Jul 2025 12:19:33 -0700 Subject: [PATCH 0410/2711] doc: Add RCU guards to checklist.rst Also note that RCU guards can be easier to use. Signed-off-by: Paul E. McKenney --- Documentation/RCU/checklist.rst | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/Documentation/RCU/checklist.rst b/Documentation/RCU/checklist.rst index 7de3e308f330..c9bfb2b218e5 100644 --- a/Documentation/RCU/checklist.rst +++ b/Documentation/RCU/checklist.rst @@ -69,7 +69,13 @@ over a rather long period of time, but improvements are always welcome! Explicit disabling of preemption (preempt_disable(), for example) can serve as rcu_read_lock_sched(), but is less readable and prevents lockdep from detecting locking issues. Acquiring a - spinlock also enters an RCU read-side critical section. + raw spinlock also enters an RCU read-side critical section. + + The guard(rcu)() and scoped_guard(rcu) primitives designate + the remainder of the current scope or the next statement, + respectively, as the RCU read-side critical section. Use of + these guards can be less error-prone than rcu_read_lock(), + rcu_read_unlock(), and friends. Please note that you *cannot* rely on code known to be built only in non-preemptible kernels. Such code can and will break, @@ -405,9 +411,11 @@ over a rather long period of time, but improvements are always welcome! 13. Unlike most flavors of RCU, it *is* permissible to block in an SRCU read-side critical section (demarked by srcu_read_lock() and srcu_read_unlock()), hence the "SRCU": "sleepable RCU". - Please note that if you don't need to sleep in read-side critical - sections, you should be using RCU rather than SRCU, because RCU - is almost always faster and easier to use than is SRCU. + As with RCU, guard(srcu)() and scoped_guard(srcu) forms are + available, and often provide greater ease of use. Please note + that if you don't need to sleep in read-side critical sections, + you should be using RCU rather than SRCU, because RCU is almost + always faster and easier to use than is SRCU. Also unlike other forms of RCU, explicit initialization and cleanup is required either at build time via DEFINE_SRCU() @@ -443,10 +451,13 @@ over a rather long period of time, but improvements are always welcome! real-time workloads than is synchronize_rcu_expedited(). It is also permissible to sleep in RCU Tasks Trace read-side - critical section, which are delimited by rcu_read_lock_trace() and - rcu_read_unlock_trace(). However, this is a specialized flavor - of RCU, and you should not use it without first checking with - its current users. In most cases, you should instead use SRCU. + critical section, which are delimited by rcu_read_lock_trace() + and rcu_read_unlock_trace(). However, this is a specialized + flavor of RCU, and you should not use it without first checking + with its current users. In most cases, you should instead + use SRCU. As with RCU and SRCU, guard(rcu_tasks_trace)() and + scoped_guard(rcu_tasks_trace) are available, and often provide + greater ease of use. Note that rcu_assign_pointer() relates to SRCU just as it does to other forms of RCU, but instead of rcu_dereference() you should From d33b01d793d91e0c9db5a7360bab35da0cb8a453 Mon Sep 17 00:00:00 2001 From: Akira Yokosawa Date: Wed, 23 Jul 2025 17:59:10 +0900 Subject: [PATCH 0411/2711] rcu: docs: Requirements.rst: Abide by conventions of kernel documentation Here is a list of conventions applied here: - Don't mark up function names, to be taken care of by the automarkup extension. Just say func(). - Instead of ".. code-block:: none", just say "::". - Mark inline literals by a pair of ``xxxx``. Don't use rust doc's dialect of `yyyy`. - Instead of emphasizing headings by **strong emphasis**, use sub-level title adornments, in this case "^^^^^^^^^^" and make them proper sub-sections under "Hotplug CPU". Signed-off-by: Akira Yokosawa Cc: Joel Fernandes Signed-off-by: Neeraj Upadhyay (AMD) Signed-off-by: Paul E. McKenney --- .../RCU/Design/Requirements/Requirements.rst | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/Documentation/RCU/Design/Requirements/Requirements.rst b/Documentation/RCU/Design/Requirements/Requirements.rst index b0395540296b..f24b3c0b9b0d 100644 --- a/Documentation/RCU/Design/Requirements/Requirements.rst +++ b/Documentation/RCU/Design/Requirements/Requirements.rst @@ -1973,9 +1973,7 @@ code, and the FQS loop, all of which refer to or modify this bookkeeping. Note that grace period initialization (rcu_gp_init()) must carefully sequence CPU hotplug scanning with grace period state changes. For example, the following race could occur in rcu_gp_init() if rcu_seq_start() were to happen -after the CPU hotplug scanning. - -.. code-block:: none +after the CPU hotplug scanning:: CPU0 (rcu_gp_init) CPU1 CPU2 --------------------- ---- ---- @@ -2008,22 +2006,22 @@ after the CPU hotplug scanning. kfree(r1); r2 = *r0; // USE-AFTER-FREE! -By incrementing gp_seq first, CPU1's RCU read-side critical section +By incrementing ``gp_seq`` first, CPU1's RCU read-side critical section is guaranteed to not be missed by CPU2. -**Concurrent Quiescent State Reporting for Offline CPUs** +Concurrent Quiescent State Reporting for Offline CPUs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RCU must ensure that CPUs going offline report quiescent states to avoid blocking grace periods. This requires careful synchronization to handle race conditions -**Race condition causing Offline CPU to hang GP** +Race condition causing Offline CPU to hang GP +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -A race between CPU offlining and new GP initialization (gp_init) may occur -because `rcu_report_qs_rnp()` in `rcutree_report_cpu_dead()` must temporarily -release the `rcu_node` lock to wake the RCU grace-period kthread: - -.. code-block:: none +A race between CPU offlining and new GP initialization (gp_init()) may occur +because rcu_report_qs_rnp() in rcutree_report_cpu_dead() must temporarily +release the ``rcu_node`` lock to wake the RCU grace-period kthread:: CPU1 (going offline) CPU0 (GP kthread) -------------------- ----------------- @@ -2044,15 +2042,14 @@ release the `rcu_node` lock to wake the RCU grace-period kthread: // Reacquire lock (but too late) rnp->qsmaskinitnext &= ~mask // Finally clears bit -Without `ofl_lock`, the new grace period includes the offline CPU and waits +Without ``ofl_lock``, the new grace period includes the offline CPU and waits forever for its quiescent state causing a GP hang. -**A solution with ofl_lock** +A solution with ofl_lock +^^^^^^^^^^^^^^^^^^^^^^^^ -The `ofl_lock` (offline lock) prevents `rcu_gp_init()` from running during -the vulnerable window when `rcu_report_qs_rnp()` has released `rnp->lock`: - -.. code-block:: none +The ``ofl_lock`` (offline lock) prevents rcu_gp_init() from running during +the vulnerable window when rcu_report_qs_rnp() has released ``rnp->lock``:: CPU0 (rcu_gp_init) CPU1 (rcutree_report_cpu_dead) ------------------ ------------------------------ @@ -2065,21 +2062,20 @@ the vulnerable window when `rcu_report_qs_rnp()` has released `rnp->lock`: arch_spin_unlock(&ofl_lock) ---> // Now CPU1 can proceed } // But snapshot already taken -**Another race causing GP hangs in rcu_gpu_init(): Reporting QS for Now-offline CPUs** +Another race causing GP hangs in rcu_gpu_init(): Reporting QS for Now-offline CPUs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ After the first loop takes an atomic snapshot of online CPUs, as shown above, -the second loop in `rcu_gp_init()` detects CPUs that went offline between -releasing `ofl_lock` and acquiring the per-node `rnp->lock`. This detection is -crucial because: +the second loop in rcu_gp_init() detects CPUs that went offline between +releasing ``ofl_lock`` and acquiring the per-node ``rnp->lock``. +This detection is crucial because: 1. The CPU might have gone offline after the snapshot but before the second loop 2. The offline CPU cannot report its own QS if it's already dead 3. Without this detection, the grace period would wait forever for CPUs that are now offline. -The second loop performs this detection safely: - -.. code-block:: none +The second loop performs this detection safely:: rcu_for_each_node_breadth_first(rnp) { raw_spin_lock_irqsave_rcu_node(rnp, flags); @@ -2093,10 +2089,10 @@ The second loop performs this detection safely: } This approach ensures atomicity: quiescent state reporting for offline CPUs -happens either in `rcu_gp_init()` (second loop) or in `rcutree_report_cpu_dead()`, -never both and never neither. The `rnp->lock` held throughout the sequence -prevents races - `rcutree_report_cpu_dead()` also acquires this lock when -clearing `qsmaskinitnext`, ensuring mutual exclusion. +happens either in rcu_gp_init() (second loop) or in rcutree_report_cpu_dead(), +never both and never neither. The ``rnp->lock`` held throughout the sequence +prevents races - rcutree_report_cpu_dead() also acquires this lock when +clearing ``qsmaskinitnext``, ensuring mutual exclusion. Scheduler and RCU ~~~~~~~~~~~~~~~~~ From c4c432dfb00fcb69d56cc9778f527cce71cec9bb Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 22 Jul 2025 15:52:25 +0800 Subject: [PATCH 0412/2711] remoteproc: imx_dsp_rproc: Add support of recovery and coredump process When enabled FW recovery, but is broken because software reset is missed in this recovery flow. So move software reset from imx_dsp_runtime_resume() to .load() and clear memory before loading firmware to make recovery work. Add call rproc_coredump_set_elf_info() to initialize the elf info for coredump, otherwise coredump will report error "ELF class is not set". Fixes: ec0e5549f358 ("remoteproc: imx_dsp_rproc: Add remoteproc driver for DSP on i.MX") Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/20250722075225.544319-1-shengjiu.wang@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_dsp_rproc.c | 45 +++++++++++++++++++----------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index 5ee622bf5352..6e78a01755c7 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -774,7 +774,6 @@ static int imx_dsp_rproc_prepare(struct rproc *rproc) { struct imx_dsp_rproc *priv = rproc->priv; struct device *dev = rproc->dev.parent; - struct rproc_mem_entry *carveout; int ret; ret = imx_dsp_rproc_add_carveout(priv); @@ -785,15 +784,6 @@ static int imx_dsp_rproc_prepare(struct rproc *rproc) pm_runtime_get_sync(dev); - /* - * Clear buffers after pm rumtime for internal ocram is not - * accessible if power and clock are not enabled. - */ - list_for_each_entry(carveout, &rproc->carveouts, node) { - if (carveout->va) - memset(carveout->va, 0, carveout->len); - } - return 0; } @@ -1022,13 +1012,39 @@ static int imx_dsp_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw return 0; } +static int imx_dsp_rproc_load(struct rproc *rproc, const struct firmware *fw) +{ + struct imx_dsp_rproc *priv = rproc->priv; + const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; + struct rproc_mem_entry *carveout; + int ret; + + /* Reset DSP if needed */ + if (dsp_dcfg->reset) + dsp_dcfg->reset(priv); + /* + * Clear buffers after pm rumtime for internal ocram is not + * accessible if power and clock are not enabled. + */ + list_for_each_entry(carveout, &rproc->carveouts, node) { + if (carveout->va) + memset(carveout->va, 0, carveout->len); + } + + ret = imx_dsp_rproc_elf_load_segments(rproc, fw); + if (ret) + return ret; + + return 0; +} + static const struct rproc_ops imx_dsp_rproc_ops = { .prepare = imx_dsp_rproc_prepare, .unprepare = imx_dsp_rproc_unprepare, .start = imx_dsp_rproc_start, .stop = imx_dsp_rproc_stop, .kick = imx_dsp_rproc_kick, - .load = imx_dsp_rproc_elf_load_segments, + .load = imx_dsp_rproc_load, .parse_fw = imx_dsp_rproc_parse_fw, .handle_rsc = imx_dsp_rproc_handle_rsc, .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, @@ -1189,6 +1205,8 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev) goto err_detach_domains; } + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_XTENSA); + pm_runtime_enable(dev); return 0; @@ -1214,7 +1232,6 @@ static int imx_dsp_runtime_resume(struct device *dev) { struct rproc *rproc = dev_get_drvdata(dev); struct imx_dsp_rproc *priv = rproc->priv; - const struct imx_dsp_rproc_dcfg *dsp_dcfg = priv->dsp_dcfg; int ret; /* @@ -1235,10 +1252,6 @@ static int imx_dsp_runtime_resume(struct device *dev) return ret; } - /* Reset DSP if needed */ - if (dsp_dcfg->reset) - dsp_dcfg->reset(priv); - return 0; } From f9a4c582e508c210d1e8e70493a69c6e5708476c Mon Sep 17 00:00:00 2001 From: Hiago De Franco Date: Wed, 6 Aug 2025 14:48:17 -0300 Subject: [PATCH 0413/2711] remoteproc: k3: Remove remote processor mailbox ping As of today, pinging the remote processor during k3_rproc_request_mbox() does not have any functional effect. This behavior was originally based on the OMAP remoteproc driver, where the idea was to send messages such as suspend requests (among others) to the remote processor, but this was never upstreamed. Currently, the ping message has no effect in upstream usage and causes an unread message to remain in the mailbox, which ultimately prevents the system from entering suspend mode: Freezing remaining freezable tasks completed (elapsed 0.001 seconds) printk: Suspending console(s) (use no_console_suspend to debug) omap-mailbox 29000000.mailbox: fifo 1 has unexpected unread messages omap-mailbox 29000000.mailbox: PM: dpm_run_callback(): platform_pm_suspend returns -16 omap-mailbox 29000000.mailbox: PM: failed to suspend: error -16 The ping is only replied if the remote core firmware is capable of doing it, otherwise the unread message stays into the mailbox. Remove the ping and fix the suspend issue. Suggested-by: Andrew Davis Signed-off-by: Hiago De Franco Acked-by: Andrew Davis Link: https://lore.kernel.org/r/20250806-v1-fix-am62-hmp-suspend-v1-1-1c4a81bb5dde@toradex.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/ti_k3_common.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/remoteproc/ti_k3_common.c b/drivers/remoteproc/ti_k3_common.c index d4f20900f33b..8266e11914af 100644 --- a/drivers/remoteproc/ti_k3_common.c +++ b/drivers/remoteproc/ti_k3_common.c @@ -160,7 +160,6 @@ int k3_rproc_request_mbox(struct rproc *rproc) struct k3_rproc *kproc = rproc->priv; struct mbox_client *client = &kproc->client; struct device *dev = kproc->dev; - int ret; client->dev = dev; client->tx_done = NULL; @@ -173,20 +172,6 @@ int k3_rproc_request_mbox(struct rproc *rproc) return dev_err_probe(dev, PTR_ERR(kproc->mbox), "mbox_request_channel failed\n"); - /* - * Ping the remote processor, this is only for sanity-sake for now; - * there is no functional effect whatsoever. - * - * Note that the reply will _not_ arrive immediately: this message - * will wait in the mailbox fifo until the remote processor is booted. - */ - ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); - if (ret < 0) { - dev_err(dev, "mbox_send_message failed (%pe)\n", ERR_PTR(ret)); - mbox_free_channel(kproc->mbox); - return ret; - } - return 0; } EXPORT_SYMBOL_GPL(k3_rproc_request_mbox); From 6238784e502b6a9fbeb3a6b77284b29baa4135cc Mon Sep 17 00:00:00 2001 From: Sungho Kim Date: Wed, 20 Aug 2025 19:57:14 +0900 Subject: [PATCH 0414/2711] PCI/P2PDMA: Fix incorrect pointer usage in devm_kfree() call The error handling path in pci_p2pdma_add_resource() contains a bug in its `pgmap_free` label. Memory is allocated for the `p2p_pgmap` struct, and the pointer is stored in `p2p_pgmap`. However, the error path calls devm_kfree() with `pgmap`, which is a pointer to a member field within the `p2p_pgmap` struct, not the base pointer of the allocation. Correct the bug by passing the correct base pointer, `p2p_pgmap`, to devm_kfree(). Signed-off-by: Sungho Kim Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe Link: https://patch.msgid.link/20250820105714.2939896-1-sungho.kim@furiosa.ai --- drivers/pci/p2pdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index da5657a02007..1cb5e423eed4 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -360,7 +360,7 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size, pages_free: devm_memunmap_pages(&pdev->dev, pgmap); pgmap_free: - devm_kfree(&pdev->dev, pgmap); + devm_kfree(&pdev->dev, p2p_pgmap); return error; } EXPORT_SYMBOL_GPL(pci_p2pdma_add_resource); From 3a33020d22bff1650af59314b6faea7efb04bf89 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Tue, 19 Aug 2025 22:58:28 +0800 Subject: [PATCH 0415/2711] PCI: dwc: ep: Implement capability search using PCI core APIs The PCI core now provides generic PCI_FIND_NEXT_CAP() macros to search for PCI capabilities, using config accessors we supply. Use them in the DWC EP driver to implement dw_pcie_ep_find_capability() instead of duplicating the algorithm. Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250819145828.438541-1-18255117159@163.com --- .../pci/controller/dwc/pcie-designware-ep.c | 31 ++----------------- drivers/pci/controller/dwc/pcie-designware.h | 21 +++++++++++++ 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 0ae54a94809b..7f2112c2fb21 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -69,37 +69,10 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) } EXPORT_SYMBOL_GPL(dw_pcie_ep_reset_bar); -static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no, - u8 cap_ptr, u8 cap) -{ - u8 cap_id, next_cap_ptr; - u16 reg; - - if (!cap_ptr) - return 0; - - reg = dw_pcie_ep_readw_dbi(ep, func_no, cap_ptr); - cap_id = (reg & 0x00ff); - - if (cap_id > PCI_CAP_ID_MAX) - return 0; - - if (cap_id == cap) - return cap_ptr; - - next_cap_ptr = (reg & 0xff00) >> 8; - return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); -} - static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) { - u8 next_cap_ptr; - u16 reg; - - reg = dw_pcie_ep_readw_dbi(ep, func_no, PCI_CAPABILITY_LIST); - next_cap_ptr = (reg & 0x00ff); - - return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); + return PCI_FIND_NEXT_CAP(dw_pcie_ep_read_cfg, PCI_CAPABILITY_LIST, + cap, ep, func_no); } /** diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index b5e7e18138a6..a44f2113925d 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -695,6 +695,27 @@ static inline u8 dw_pcie_ep_readb_dbi(struct dw_pcie_ep *ep, u8 func_no, return dw_pcie_ep_read_dbi(ep, func_no, reg, 0x1); } +static inline int dw_pcie_ep_read_cfg_byte(struct dw_pcie_ep *ep, u8 func_no, + int where, u8 *val) +{ + *val = dw_pcie_ep_readb_dbi(ep, func_no, where); + return PCIBIOS_SUCCESSFUL; +} + +static inline int dw_pcie_ep_read_cfg_word(struct dw_pcie_ep *ep, u8 func_no, + int where, u16 *val) +{ + *val = dw_pcie_ep_readw_dbi(ep, func_no, where); + return PCIBIOS_SUCCESSFUL; +} + +static inline int dw_pcie_ep_read_cfg_dword(struct dw_pcie_ep *ep, u8 func_no, + int where, u32 *val) +{ + *val = dw_pcie_ep_readl_dbi(ep, func_no, where); + return PCIBIOS_SUCCESSFUL; +} + static inline unsigned int dw_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep, u8 func_no) { From 18ac51ae9df925292a4d8ca6550a199924ae9e17 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Wed, 13 Aug 2025 22:45:28 +0800 Subject: [PATCH 0416/2711] PCI: cadence: Implement capability search using PCI core APIs The PCI core now provides generic PCI_FIND_NEXT_CAP() and PCI_FIND_NEXT_EXT_CAP() macros to search for PCI capabilities, using config accessors we supply. Use them in the CDNS driver to add cdns_pcie_find_capability() and cdns_pcie_find_ext_capability() interfaces. Signed-off-by: Hans Zhang <18255117159@163.com> [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250813144529.303548-6-18255117159@163.com --- drivers/pci/controller/cadence/pcie-cadence.c | 14 ++++++++ drivers/pci/controller/cadence/pcie-cadence.h | 34 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c index 70a19573440e..c45585ae1746 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.c +++ b/drivers/pci/controller/cadence/pcie-cadence.c @@ -8,6 +8,20 @@ #include #include "pcie-cadence.h" +#include "../../pci.h" + +u8 cdns_pcie_find_capability(struct cdns_pcie *pcie, u8 cap) +{ + return PCI_FIND_NEXT_CAP(cdns_pcie_read_cfg, PCI_CAPABILITY_LIST, + cap, pcie); +} +EXPORT_SYMBOL_GPL(cdns_pcie_find_capability); + +u16 cdns_pcie_find_ext_capability(struct cdns_pcie *pcie, u8 cap) +{ + return PCI_FIND_NEXT_EXT_CAP(cdns_pcie_read_cfg, 0, cap, pcie); +} +EXPORT_SYMBOL_GPL(cdns_pcie_find_ext_capability); void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie) { diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h index 1d81c4bf6c6d..9eebf8f02abc 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.h +++ b/drivers/pci/controller/cadence/pcie-cadence.h @@ -367,6 +367,37 @@ static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg) return readl(pcie->reg_base + reg); } +static inline u16 cdns_pcie_readw(struct cdns_pcie *pcie, u32 reg) +{ + return readw(pcie->reg_base + reg); +} + +static inline u8 cdns_pcie_readb(struct cdns_pcie *pcie, u32 reg) +{ + return readb(pcie->reg_base + reg); +} + +static inline int cdns_pcie_read_cfg_byte(struct cdns_pcie *pcie, int where, + u8 *val) +{ + *val = cdns_pcie_readb(pcie, where); + return PCIBIOS_SUCCESSFUL; +} + +static inline int cdns_pcie_read_cfg_word(struct cdns_pcie *pcie, int where, + u16 *val) +{ + *val = cdns_pcie_readw(pcie, where); + return PCIBIOS_SUCCESSFUL; +} + +static inline int cdns_pcie_read_cfg_dword(struct cdns_pcie *pcie, int where, + u32 *val) +{ + *val = cdns_pcie_readl(pcie, where); + return PCIBIOS_SUCCESSFUL; +} + static inline u32 cdns_pcie_read_sz(void __iomem *addr, int size) { void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4); @@ -536,6 +567,9 @@ static inline void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep) } #endif +u8 cdns_pcie_find_capability(struct cdns_pcie *pcie, u8 cap); +u16 cdns_pcie_find_ext_capability(struct cdns_pcie *pcie, u8 cap); + void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie); void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn, From 907912c1daa7d87ec179ab35f6326e98233ae03a Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Wed, 13 Aug 2025 22:45:29 +0800 Subject: [PATCH 0417/2711] PCI: cadence: Use cdns_pcie_find_*capability() to avoid hardcoding offsets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCI capability/extended capability offsets are not guaranteed to be the same across all SoCs integrating the Cadence PCIe IP. Use the cdns_pcie_find_{ext}_capability() APIs to find the capabilities, which avoids hardcoding the offsets in the driver. Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen Acked-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250813144529.303548-7-18255117159@163.com --- .../pci/controller/cadence/pcie-cadence-ep.c | 38 +++++++++++-------- drivers/pci/controller/cadence/pcie-cadence.h | 5 --- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 77c5a19b2ab1..5529ed84649f 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -21,12 +21,13 @@ static u8 cdns_pcie_get_fn_from_vfn(struct cdns_pcie *pcie, u8 fn, u8 vfn) { - u32 cap = CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET; u32 first_vf_offset, stride; + u16 cap; if (vfn == 0) return fn; + cap = cdns_pcie_find_ext_capability(pcie, PCI_EXT_CAP_ID_SRIOV); first_vf_offset = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_SRIOV_VF_OFFSET); stride = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_SRIOV_VF_STRIDE); fn = fn + first_vf_offset + ((vfn - 1) * stride); @@ -38,10 +39,11 @@ static int cdns_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn, struct pci_epf_header *hdr) { struct cdns_pcie_ep *ep = epc_get_drvdata(epc); - u32 cap = CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET; struct cdns_pcie *pcie = &ep->pcie; u32 reg; + u16 cap; + cap = cdns_pcie_find_ext_capability(pcie, PCI_EXT_CAP_ID_SRIOV); if (vfn > 1) { dev_err(&epc->dev, "Only Virtual Function #1 has deviceID\n"); return -EINVAL; @@ -227,9 +229,10 @@ static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 nr_irqs) struct cdns_pcie_ep *ep = epc_get_drvdata(epc); struct cdns_pcie *pcie = &ep->pcie; u8 mmc = order_base_2(nr_irqs); - u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; u16 flags; + u8 cap; + cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSI); fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn); /* @@ -249,9 +252,10 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn) { struct cdns_pcie_ep *ep = epc_get_drvdata(epc); struct cdns_pcie *pcie = &ep->pcie; - u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; u16 flags, mme; + u8 cap; + cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSIX); fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn); /* Validate that the MSI feature is actually enabled. */ @@ -272,9 +276,10 @@ static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) { struct cdns_pcie_ep *ep = epc_get_drvdata(epc); struct cdns_pcie *pcie = &ep->pcie; - u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; u32 val, reg; + u8 cap; + cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSIX); func_no = cdns_pcie_get_fn_from_vfn(pcie, func_no, vfunc_no); reg = cap + PCI_MSIX_FLAGS; @@ -292,9 +297,10 @@ static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, { struct cdns_pcie_ep *ep = epc_get_drvdata(epc); struct cdns_pcie *pcie = &ep->pcie; - u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; u32 val, reg; + u8 cap; + cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSIX); fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn); reg = cap + PCI_MSIX_FLAGS; @@ -380,11 +386,11 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn, u8 interrupt_num) { struct cdns_pcie *pcie = &ep->pcie; - u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; u16 flags, mme, data, data_mask; - u8 msi_count; u64 pci_addr, pci_addr_mask = 0xff; + u8 msi_count, cap; + cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSI); fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn); /* Check whether the MSI feature has been enabled by the PCI host. */ @@ -432,14 +438,14 @@ static int cdns_pcie_ep_map_msi_irq(struct pci_epc *epc, u8 fn, u8 vfn, u32 *msi_addr_offset) { struct cdns_pcie_ep *ep = epc_get_drvdata(epc); - u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; struct cdns_pcie *pcie = &ep->pcie; u64 pci_addr, pci_addr_mask = 0xff; u16 flags, mme, data, data_mask; - u8 msi_count; + u8 msi_count, cap; int ret; int i; + cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSI); fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn); /* Check whether the MSI feature has been enabled by the PCI host. */ @@ -482,16 +488,16 @@ static int cdns_pcie_ep_map_msi_irq(struct pci_epc *epc, u8 fn, u8 vfn, static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn, u16 interrupt_num) { - u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; u32 tbl_offset, msg_data, reg; struct cdns_pcie *pcie = &ep->pcie; struct pci_epf_msix_tbl *msix_tbl; struct cdns_pcie_epf *epf; u64 pci_addr_mask = 0xff; u64 msg_addr; + u8 bir, cap; u16 flags; - u8 bir; + cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSIX); epf = &ep->epf[fn]; if (vfn > 0) epf = &epf->epf[vfn - 1]; @@ -565,7 +571,9 @@ static int cdns_pcie_ep_start(struct pci_epc *epc) int max_epfs = sizeof(epc->function_num_map) * 8; int ret, epf, last_fn; u32 reg, value; + u8 cap; + cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_EXP); /* * BIT(0) is hardwired to 1, hence function 0 is always enabled * and can't be disabled anyway. @@ -589,12 +597,10 @@ static int cdns_pcie_ep_start(struct pci_epc *epc) continue; value = cdns_pcie_ep_fn_readl(pcie, epf, - CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET + - PCI_EXP_DEVCAP); + cap + PCI_EXP_DEVCAP); value &= ~PCI_EXP_DEVCAP_FLR; cdns_pcie_ep_fn_writel(pcie, epf, - CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET + - PCI_EXP_DEVCAP, value); + cap + PCI_EXP_DEVCAP, value); } } diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h index 9eebf8f02abc..88cec0dc2067 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.h +++ b/drivers/pci/controller/cadence/pcie-cadence.h @@ -125,11 +125,6 @@ */ #define CDNS_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & GENMASK(19, 12)) -#define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET 0x90 -#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET 0xb0 -#define CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET 0xc0 -#define CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET 0x200 - /* * Endpoint PF Registers */ From 1f43a3401debb9d06aa434ec6fecae676963d6f3 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 19 Aug 2025 17:01:24 +0800 Subject: [PATCH 0418/2711] usb: typec: qcom-pmic-typec: use kcalloc() instead of kzalloc() Replace devm_kzalloc() with devm_kcalloc() in qcom_pmic_typec_pdphy_probe() and qcom_pmic_typec_port_probe() for safer memory allocation with built-in overflow protection. Signed-off-by: Qianfeng Rong Reviewed-by: Dmitry Baryshkov Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20250819090125.540682-1-rongqianfeng@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c | 2 +- drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c index 18303b34594b..c8b1463e6e8b 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c @@ -567,7 +567,7 @@ int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev, if (!res->nr_irqs || res->nr_irqs > PMIC_PDPHY_MAX_IRQS) return -EINVAL; - irq_data = devm_kzalloc(dev, sizeof(*irq_data) * res->nr_irqs, + irq_data = devm_kcalloc(dev, res->nr_irqs, sizeof(*irq_data), GFP_KERNEL); if (!irq_data) return -ENOMEM; diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c index 4fc83dcfae64..8051eaa46991 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c @@ -713,7 +713,7 @@ int qcom_pmic_typec_port_probe(struct platform_device *pdev, if (!res->nr_irqs || res->nr_irqs > PMIC_TYPEC_MAX_IRQS) return -EINVAL; - irq_data = devm_kzalloc(dev, sizeof(*irq_data) * res->nr_irqs, + irq_data = devm_kcalloc(dev, res->nr_irqs, sizeof(*irq_data), GFP_KERNEL); if (!irq_data) return -ENOMEM; From d15fbd3ea75bc893b46e9f4df6f9469db0f93897 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 19 Aug 2025 19:24:51 +0800 Subject: [PATCH 0419/2711] usb: typec: mux: Remove the use of dev_err_probe() The dev_err_probe() doesn't do anything when error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Reviewed-by: Romain Gantois Link: https://lore.kernel.org/r/20250819112451.587817-1-zhao.xichao@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/mux/tusb1046.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/mux/tusb1046.c b/drivers/usb/typec/mux/tusb1046.c index b4f45c217b59..3c1a4551c2fb 100644 --- a/drivers/usb/typec/mux/tusb1046.c +++ b/drivers/usb/typec/mux/tusb1046.c @@ -129,7 +129,7 @@ static int tusb1046_i2c_probe(struct i2c_client *client) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) - return dev_err_probe(dev, -ENOMEM, "failed to allocate driver data\n"); + return -ENOMEM; priv->client = client; From 706c3c02eecd41dc675e9102b3719661cd3e30e2 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 19 Aug 2025 20:09:27 +0800 Subject: [PATCH 0420/2711] tty: serial: Modify the use of dev_err_probe() The dev_err_probe() doesn't do anything when error is '-ENOMEM'. Make the following two changes: (1) Replace -ENOMEM with -ENOSPC in max3100_probe(). (2) Just return -ENOMEM instead in max310x_probe(). Signed-off-by: Xichao Zhao Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/20250819120927.607744-1-zhao.xichao@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 2 +- drivers/tty/serial/max310x.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 67d80f8f801e..3faa1b6aa3ee 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -705,7 +705,7 @@ static int max3100_probe(struct spi_device *spi) break; if (i == MAX_MAX3100) { mutex_unlock(&max3100s_lock); - return dev_err_probe(dev, -ENOMEM, "too many MAX3100 chips\n"); + return dev_err_probe(dev, -ENOSPC, "too many MAX3100 chips\n"); } max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL); diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index d9a0100b92d2..e8749b862970 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1269,8 +1269,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty /* Alloc port structure */ s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL); if (!s) - return dev_err_probe(dev, -ENOMEM, - "Error allocating port structure\n"); + return -ENOMEM; /* Always ask for fixed clock rate from a property. */ device_property_read_u32(dev, "clock-frequency", &uartclk); From 411053cb6657a3cf8db50a2d004a112070ca14b2 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 19 Aug 2025 09:13:44 -0300 Subject: [PATCH 0421/2711] dt-bindings: w1: imx: Add an entry for the interrupts property There is an interrupt line connected to the one-wire block on the i.MX51 and i.MX53. Add an entry for the interrupt property to avoid the following dt-schema warning: 'interrupts' does not match any of the regexes: '^pinctrl-[0-9]+$' Signed-off-by: Fabio Estevam Acked-by: Conor Dooley Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250819121344.2765940-1-festevam@gmail.com Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/w1/fsl-imx-owire.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/w1/fsl-imx-owire.yaml b/Documentation/devicetree/bindings/w1/fsl-imx-owire.yaml index 55adea827c34..2c1bbc0eb05a 100644 --- a/Documentation/devicetree/bindings/w1/fsl-imx-owire.yaml +++ b/Documentation/devicetree/bindings/w1/fsl-imx-owire.yaml @@ -24,6 +24,9 @@ properties: reg: maxItems: 1 + interrupts: + maxItems: 1 + clocks: maxItems: 1 @@ -40,5 +43,6 @@ examples: owire@63fa4000 { compatible = "fsl,imx53-owire", "fsl,imx21-owire"; reg = <0x63fa4000 0x4000>; + interrupts = <88>; clocks = <&clks IMX5_CLK_OWIRE_GATE>; }; From 4593311290006793a38a9cbd91d4a65b63cd7b76 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Tue, 19 Aug 2025 10:57:50 +0200 Subject: [PATCH 0422/2711] crypto: X86 - Remove CONFIG_AS_VAES Current minimum required version of binutils is 2.30, which supports VAES instruction mnemonics. Remove check for assembler support of VAES instructions and all relevant macros for conditional compilation. No functional change intended. Signed-off-by: Uros Bizjak Signed-off-by: Borislav Petkov (AMD) Acked-by: Herbert Xu Link: https://lore.kernel.org/20250819085855.333380-2-ubizjak@gmail.com --- arch/x86/Kconfig.assembler | 5 ----- arch/x86/crypto/Makefile | 2 +- arch/x86/crypto/aes-ctr-avx-x86_64.S | 4 ++-- arch/x86/crypto/aes-xts-avx-x86_64.S | 4 ++-- arch/x86/crypto/aesni-intel_glue.c | 14 +++++++------- 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/arch/x86/Kconfig.assembler b/arch/x86/Kconfig.assembler index 6b95be002465..8d1808407674 100644 --- a/arch/x86/Kconfig.assembler +++ b/arch/x86/Kconfig.assembler @@ -6,11 +6,6 @@ config AS_AVX512 help Supported by binutils >= 2.25 and LLVM integrated assembler -config AS_VAES - def_bool $(as-instr,vaesenc %ymm0$(comma)%ymm1$(comma)%ymm2) - help - Supported by binutils >= 2.30 and LLVM integrated assembler - config AS_VPCLMULQDQ def_bool $(as-instr,vpclmulqdq \$0x10$(comma)%ymm0$(comma)%ymm1$(comma)%ymm2) help diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index d402963d6b57..50f1c0414c00 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -47,7 +47,7 @@ aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o aesni-intel-$(CONFIG_64BIT) += aes-ctr-avx-x86_64.o \ aes-gcm-aesni-x86_64.o \ aes-xts-avx-x86_64.o -ifeq ($(CONFIG_AS_VAES)$(CONFIG_AS_VPCLMULQDQ),yy) +ifeq ($(CONFIG_AS_VPCLMULQDQ),y) aesni-intel-$(CONFIG_64BIT) += aes-gcm-avx10-x86_64.o endif diff --git a/arch/x86/crypto/aes-ctr-avx-x86_64.S b/arch/x86/crypto/aes-ctr-avx-x86_64.S index bbbfd80f5a50..ec957b25b062 100644 --- a/arch/x86/crypto/aes-ctr-avx-x86_64.S +++ b/arch/x86/crypto/aes-ctr-avx-x86_64.S @@ -552,7 +552,7 @@ SYM_TYPED_FUNC_START(aes_xctr_crypt_aesni_avx) _aes_ctr_crypt 1 SYM_FUNC_END(aes_xctr_crypt_aesni_avx) -#if defined(CONFIG_AS_VAES) && defined(CONFIG_AS_VPCLMULQDQ) +#if defined(CONFIG_AS_VPCLMULQDQ) .set VL, 32 .set USE_AVX512, 0 SYM_TYPED_FUNC_START(aes_ctr64_crypt_vaes_avx2) @@ -570,4 +570,4 @@ SYM_FUNC_END(aes_ctr64_crypt_vaes_avx512) SYM_TYPED_FUNC_START(aes_xctr_crypt_vaes_avx512) _aes_ctr_crypt 1 SYM_FUNC_END(aes_xctr_crypt_vaes_avx512) -#endif // CONFIG_AS_VAES && CONFIG_AS_VPCLMULQDQ +#endif // CONFIG_AS_VPCLMULQDQ diff --git a/arch/x86/crypto/aes-xts-avx-x86_64.S b/arch/x86/crypto/aes-xts-avx-x86_64.S index db79cdf81588..e44e56817d82 100644 --- a/arch/x86/crypto/aes-xts-avx-x86_64.S +++ b/arch/x86/crypto/aes-xts-avx-x86_64.S @@ -886,7 +886,7 @@ SYM_TYPED_FUNC_START(aes_xts_decrypt_aesni_avx) _aes_xts_crypt 0 SYM_FUNC_END(aes_xts_decrypt_aesni_avx) -#if defined(CONFIG_AS_VAES) && defined(CONFIG_AS_VPCLMULQDQ) +#if defined(CONFIG_AS_VPCLMULQDQ) .set VL, 32 .set USE_AVX512, 0 SYM_TYPED_FUNC_START(aes_xts_encrypt_vaes_avx2) @@ -904,4 +904,4 @@ SYM_FUNC_END(aes_xts_encrypt_vaes_avx512) SYM_TYPED_FUNC_START(aes_xts_decrypt_vaes_avx512) _aes_xts_crypt 0 SYM_FUNC_END(aes_xts_decrypt_vaes_avx512) -#endif /* CONFIG_AS_VAES && CONFIG_AS_VPCLMULQDQ */ +#endif /* CONFIG_AS_VPCLMULQDQ */ diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index 061b1ced93c5..d5a2f5b2c01b 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -828,7 +828,7 @@ static struct skcipher_alg skcipher_algs_##suffix[] = {{ \ }} DEFINE_AVX_SKCIPHER_ALGS(aesni_avx, "aesni-avx", 500); -#if defined(CONFIG_AS_VAES) && defined(CONFIG_AS_VPCLMULQDQ) +#if defined(CONFIG_AS_VPCLMULQDQ) DEFINE_AVX_SKCIPHER_ALGS(vaes_avx2, "vaes-avx2", 600); DEFINE_AVX_SKCIPHER_ALGS(vaes_avx512, "vaes-avx512", 800); #endif @@ -912,7 +912,7 @@ struct aes_gcm_key_avx10 { #define FLAG_RFC4106 BIT(0) #define FLAG_ENC BIT(1) #define FLAG_AVX BIT(2) -#if defined(CONFIG_AS_VAES) && defined(CONFIG_AS_VPCLMULQDQ) +#if defined(CONFIG_AS_VPCLMULQDQ) # define FLAG_AVX10_256 BIT(3) # define FLAG_AVX10_512 BIT(4) #else @@ -1519,7 +1519,7 @@ DEFINE_GCM_ALGS(aesni_avx, FLAG_AVX, "generic-gcm-aesni-avx", "rfc4106-gcm-aesni-avx", AES_GCM_KEY_AESNI_SIZE, 500); -#if defined(CONFIG_AS_VAES) && defined(CONFIG_AS_VPCLMULQDQ) +#if defined(CONFIG_AS_VPCLMULQDQ) /* aes_gcm_algs_vaes_avx10_256 */ DEFINE_GCM_ALGS(vaes_avx10_256, FLAG_AVX10_256, "generic-gcm-vaes-avx10_256", "rfc4106-gcm-vaes-avx10_256", @@ -1529,7 +1529,7 @@ DEFINE_GCM_ALGS(vaes_avx10_256, FLAG_AVX10_256, DEFINE_GCM_ALGS(vaes_avx10_512, FLAG_AVX10_512, "generic-gcm-vaes-avx10_512", "rfc4106-gcm-vaes-avx10_512", AES_GCM_KEY_AVX10_SIZE, 800); -#endif /* CONFIG_AS_VAES && CONFIG_AS_VPCLMULQDQ */ +#endif /* CONFIG_AS_VPCLMULQDQ */ static int __init register_avx_algs(void) { @@ -1551,7 +1551,7 @@ static int __init register_avx_algs(void) * Similarly, the assembler support was added at about the same time. * For simplicity, just always check for VAES and VPCLMULQDQ together. */ -#if defined(CONFIG_AS_VAES) && defined(CONFIG_AS_VPCLMULQDQ) +#if defined(CONFIG_AS_VPCLMULQDQ) if (!boot_cpu_has(X86_FEATURE_AVX2) || !boot_cpu_has(X86_FEATURE_VAES) || !boot_cpu_has(X86_FEATURE_VPCLMULQDQ) || @@ -1592,7 +1592,7 @@ static int __init register_avx_algs(void) ARRAY_SIZE(aes_gcm_algs_vaes_avx10_512)); if (err) return err; -#endif /* CONFIG_AS_VAES && CONFIG_AS_VPCLMULQDQ */ +#endif /* CONFIG_AS_VPCLMULQDQ */ return 0; } @@ -1607,7 +1607,7 @@ static void unregister_avx_algs(void) { unregister_skciphers(skcipher_algs_aesni_avx); unregister_aeads(aes_gcm_algs_aesni_avx); -#if defined(CONFIG_AS_VAES) && defined(CONFIG_AS_VPCLMULQDQ) +#if defined(CONFIG_AS_VPCLMULQDQ) unregister_skciphers(skcipher_algs_vaes_avx2); unregister_skciphers(skcipher_algs_vaes_avx512); unregister_aeads(aes_gcm_algs_vaes_avx10_256); From e084e9f8151f1d37b085317752d36b4fa2fec9b9 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Tue, 19 Aug 2025 10:57:51 +0200 Subject: [PATCH 0423/2711] crypto: x86 - Remove CONFIG_AS_VPCLMULQDQ Current minimum required version of binutils is 2.30, which supports VPCLMULQDQ instruction mnemonics. Remove check for assembler support of VPCLMULQDQ instructions and all relevant macros for conditional compilation. No functional change intended. Signed-off-by: Uros Bizjak Signed-off-by: Borislav Petkov (AMD) Acked-by: Herbert Xu Link: https://lore.kernel.org/20250819085855.333380-3-ubizjak@gmail.com --- arch/x86/Kconfig.assembler | 5 ----- arch/x86/crypto/Makefile | 6 ++---- arch/x86/crypto/aes-ctr-avx-x86_64.S | 2 -- arch/x86/crypto/aes-xts-avx-x86_64.S | 2 -- arch/x86/crypto/aesni-intel_glue.c | 22 +++------------------- 5 files changed, 5 insertions(+), 32 deletions(-) diff --git a/arch/x86/Kconfig.assembler b/arch/x86/Kconfig.assembler index 8d1808407674..ea0e9dfdfc5c 100644 --- a/arch/x86/Kconfig.assembler +++ b/arch/x86/Kconfig.assembler @@ -6,11 +6,6 @@ config AS_AVX512 help Supported by binutils >= 2.25 and LLVM integrated assembler -config AS_VPCLMULQDQ - def_bool $(as-instr,vpclmulqdq \$0x10$(comma)%ymm0$(comma)%ymm1$(comma)%ymm2) - help - Supported by binutils >= 2.30 and LLVM integrated assembler - config AS_WRUSS def_bool $(as-instr64,wrussq %rax$(comma)(%rbx)) help diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 50f1c0414c00..419252db968c 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -46,10 +46,8 @@ obj-$(CONFIG_CRYPTO_AES_NI_INTEL) += aesni-intel.o aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o aesni-intel-$(CONFIG_64BIT) += aes-ctr-avx-x86_64.o \ aes-gcm-aesni-x86_64.o \ - aes-xts-avx-x86_64.o -ifeq ($(CONFIG_AS_VPCLMULQDQ),y) -aesni-intel-$(CONFIG_64BIT) += aes-gcm-avx10-x86_64.o -endif + aes-xts-avx-x86_64.o \ + aes-gcm-avx10-x86_64.o obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o diff --git a/arch/x86/crypto/aes-ctr-avx-x86_64.S b/arch/x86/crypto/aes-ctr-avx-x86_64.S index ec957b25b062..2745918f68ee 100644 --- a/arch/x86/crypto/aes-ctr-avx-x86_64.S +++ b/arch/x86/crypto/aes-ctr-avx-x86_64.S @@ -552,7 +552,6 @@ SYM_TYPED_FUNC_START(aes_xctr_crypt_aesni_avx) _aes_ctr_crypt 1 SYM_FUNC_END(aes_xctr_crypt_aesni_avx) -#if defined(CONFIG_AS_VPCLMULQDQ) .set VL, 32 .set USE_AVX512, 0 SYM_TYPED_FUNC_START(aes_ctr64_crypt_vaes_avx2) @@ -570,4 +569,3 @@ SYM_FUNC_END(aes_ctr64_crypt_vaes_avx512) SYM_TYPED_FUNC_START(aes_xctr_crypt_vaes_avx512) _aes_ctr_crypt 1 SYM_FUNC_END(aes_xctr_crypt_vaes_avx512) -#endif // CONFIG_AS_VPCLMULQDQ diff --git a/arch/x86/crypto/aes-xts-avx-x86_64.S b/arch/x86/crypto/aes-xts-avx-x86_64.S index e44e56817d82..a30753a3e207 100644 --- a/arch/x86/crypto/aes-xts-avx-x86_64.S +++ b/arch/x86/crypto/aes-xts-avx-x86_64.S @@ -886,7 +886,6 @@ SYM_TYPED_FUNC_START(aes_xts_decrypt_aesni_avx) _aes_xts_crypt 0 SYM_FUNC_END(aes_xts_decrypt_aesni_avx) -#if defined(CONFIG_AS_VPCLMULQDQ) .set VL, 32 .set USE_AVX512, 0 SYM_TYPED_FUNC_START(aes_xts_encrypt_vaes_avx2) @@ -904,4 +903,3 @@ SYM_FUNC_END(aes_xts_encrypt_vaes_avx512) SYM_TYPED_FUNC_START(aes_xts_decrypt_vaes_avx512) _aes_xts_crypt 0 SYM_FUNC_END(aes_xts_decrypt_vaes_avx512) -#endif /* CONFIG_AS_VPCLMULQDQ */ diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index d5a2f5b2c01b..d953ac470aae 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -828,10 +828,8 @@ static struct skcipher_alg skcipher_algs_##suffix[] = {{ \ }} DEFINE_AVX_SKCIPHER_ALGS(aesni_avx, "aesni-avx", 500); -#if defined(CONFIG_AS_VPCLMULQDQ) DEFINE_AVX_SKCIPHER_ALGS(vaes_avx2, "vaes-avx2", 600); DEFINE_AVX_SKCIPHER_ALGS(vaes_avx512, "vaes-avx512", 800); -#endif /* The common part of the x86_64 AES-GCM key struct */ struct aes_gcm_key { @@ -912,17 +910,8 @@ struct aes_gcm_key_avx10 { #define FLAG_RFC4106 BIT(0) #define FLAG_ENC BIT(1) #define FLAG_AVX BIT(2) -#if defined(CONFIG_AS_VPCLMULQDQ) -# define FLAG_AVX10_256 BIT(3) -# define FLAG_AVX10_512 BIT(4) -#else - /* - * This should cause all calls to the AVX10 assembly functions to be - * optimized out, avoiding the need to ifdef each call individually. - */ -# define FLAG_AVX10_256 0 -# define FLAG_AVX10_512 0 -#endif +#define FLAG_AVX10_256 BIT(3) +#define FLAG_AVX10_512 BIT(4) static inline struct aes_gcm_key * aes_gcm_key_get(struct crypto_aead *tfm, int flags) @@ -1519,7 +1508,6 @@ DEFINE_GCM_ALGS(aesni_avx, FLAG_AVX, "generic-gcm-aesni-avx", "rfc4106-gcm-aesni-avx", AES_GCM_KEY_AESNI_SIZE, 500); -#if defined(CONFIG_AS_VPCLMULQDQ) /* aes_gcm_algs_vaes_avx10_256 */ DEFINE_GCM_ALGS(vaes_avx10_256, FLAG_AVX10_256, "generic-gcm-vaes-avx10_256", "rfc4106-gcm-vaes-avx10_256", @@ -1529,7 +1517,6 @@ DEFINE_GCM_ALGS(vaes_avx10_256, FLAG_AVX10_256, DEFINE_GCM_ALGS(vaes_avx10_512, FLAG_AVX10_512, "generic-gcm-vaes-avx10_512", "rfc4106-gcm-vaes-avx10_512", AES_GCM_KEY_AVX10_SIZE, 800); -#endif /* CONFIG_AS_VPCLMULQDQ */ static int __init register_avx_algs(void) { @@ -1551,7 +1538,6 @@ static int __init register_avx_algs(void) * Similarly, the assembler support was added at about the same time. * For simplicity, just always check for VAES and VPCLMULQDQ together. */ -#if defined(CONFIG_AS_VPCLMULQDQ) if (!boot_cpu_has(X86_FEATURE_AVX2) || !boot_cpu_has(X86_FEATURE_VAES) || !boot_cpu_has(X86_FEATURE_VPCLMULQDQ) || @@ -1592,7 +1578,7 @@ static int __init register_avx_algs(void) ARRAY_SIZE(aes_gcm_algs_vaes_avx10_512)); if (err) return err; -#endif /* CONFIG_AS_VPCLMULQDQ */ + return 0; } @@ -1607,12 +1593,10 @@ static void unregister_avx_algs(void) { unregister_skciphers(skcipher_algs_aesni_avx); unregister_aeads(aes_gcm_algs_aesni_avx); -#if defined(CONFIG_AS_VPCLMULQDQ) unregister_skciphers(skcipher_algs_vaes_avx2); unregister_skciphers(skcipher_algs_vaes_avx512); unregister_aeads(aes_gcm_algs_vaes_avx10_256); unregister_aeads(aes_gcm_algs_vaes_avx10_512); -#endif } #else /* CONFIG_X86_64 */ static struct aead_alg aes_gcm_algs_aesni[0]; From ae7c0996c0e0f7d3bd3665020e1fbb4d99b7373e Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Tue, 19 Aug 2025 10:57:52 +0200 Subject: [PATCH 0424/2711] x86/kconfig: Remove CONFIG_AS_AVX512 Commit 5f5305dea066 ("raid6: skip avx512 checks") and commit bc23fe6dc172 ("crypto: x86 - Remove CONFIG_AS_AVX512 handling") removed all uses of CONFIG_AS_AVX512. Remove check for assembler support of AVX-512 instructions. Signed-off-by: Uros Bizjak Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20250819085855.333380-4-ubizjak@gmail.com --- arch/x86/Kconfig.assembler | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/x86/Kconfig.assembler b/arch/x86/Kconfig.assembler index ea0e9dfdfc5c..b1c59fb0a4c9 100644 --- a/arch/x86/Kconfig.assembler +++ b/arch/x86/Kconfig.assembler @@ -1,11 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2020 Jason A. Donenfeld . All Rights Reserved. -config AS_AVX512 - def_bool $(as-instr,vpmovm2b %k1$(comma)%zmm5) - help - Supported by binutils >= 2.25 and LLVM integrated assembler - config AS_WRUSS def_bool $(as-instr64,wrussq %rax$(comma)(%rbx)) help From 73c94172e278197fbed9f6a7b7550edc5bc1fbad Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Thu, 21 Aug 2025 13:55:21 +0000 Subject: [PATCH 0425/2711] netlink: specs: binder: replace underscores with dashes in names The usage of underscores is no longer allowed for the 'name' format in the yaml spec. Instead, dashes should be used. This fixes the build issue reported by Thorsten that showed up on linux-next. Note this change has no impact on C code. Cc: Jakub Kicinski Reported-by: Thorsten Leemhuis Closes: https://lore.kernel.org/all/e21744a4-0155-40ec-b8c1-d81b14107c9f@leemhuis.info/ Fixes: 63740349eba7 ("binder: introduce transaction reports via netlink") Signed-off-by: Carlos Llamas Reviewed-by: Jakub Kicinski Link: https://lore.kernel.org/r/20250821135522.2878772-1-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- Documentation/netlink/specs/binder.yaml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Documentation/netlink/specs/binder.yaml b/Documentation/netlink/specs/binder.yaml index 140b77a6afee..0f0575ad1265 100644 --- a/Documentation/netlink/specs/binder.yaml +++ b/Documentation/netlink/specs/binder.yaml @@ -26,27 +26,27 @@ attribute-sets: type: string doc: The binder context where the transaction occurred. - - name: from_pid + name: from-pid type: u32 doc: The PID of the sender process. - - name: from_tid + name: from-tid type: u32 doc: The TID of the sender thread. - - name: to_pid + name: to-pid type: u32 doc: | The PID of the recipient process. This attribute may not be present if the target could not be determined. - - name: to_tid + name: to-tid type: u32 doc: | The TID of the recipient thread. This attribute may not be present if the target could not be determined. - - name: is_reply + name: is-reply type: flag doc: When present, indicates the failed transaction is a reply. - @@ -58,7 +58,7 @@ attribute-sets: type: u32 doc: The application-defined code from the transaction. - - name: data_size + name: data-size type: u32 doc: The transaction payload size in bytes. @@ -78,14 +78,14 @@ operations: attributes: - error - context - - from_pid - - from_tid - - to_pid - - to_tid - - is_reply + - from-pid + - from-tid + - to-pid + - to-tid + - is-reply - flags - code - - data_size + - data-size mcast-groups: list: From c78af20374a1c9c230cc535857d2af3de5d4442c Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 19 Aug 2025 16:48:26 -0700 Subject: [PATCH 0426/2711] KVM: SEV: Drop GHCB_VERSION_DEFAULT and open code it Remove the GHCB_VERSION_DEFAULT macro and open code it with '2'. The macro is used conditionally and is not a true default. KVM ABI does not advertise/emumerates the default GHCB version. Any future change to this macro would silently alter the ABI and potentially break existing deployments that rely on the current behavior. Additionally, move the GHCB version assignment earlier in the code flow and update the comment to clarify that KVM_SEV_INIT2 defaults to version 2, while KVM_SEV_INIT forces version 1. No functional change intended. Cc: Thomas Lendacky Cc: Michael Roth Suggested-by: Sean Christopherson Signed-off-by: Nikunj A Dadhania Link: https://lore.kernel.org/r/20250819234833.3080255-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 2fbdebf79fbb..212f790eedd4 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -37,7 +37,6 @@ #include "trace.h" #define GHCB_VERSION_MAX 2ULL -#define GHCB_VERSION_DEFAULT 2ULL #define GHCB_VERSION_MIN 1ULL #define GHCB_HV_FT_SUPPORTED (GHCB_HV_FT_SNP | GHCB_HV_FT_SNP_AP_CREATION) @@ -421,6 +420,14 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, if (data->ghcb_version > GHCB_VERSION_MAX || (!es_active && data->ghcb_version)) return -EINVAL; + /* + * KVM supports the full range of mandatory features defined by version + * 2 of the GHCB protocol, so default to that for SEV-ES guests created + * via KVM_SEV_INIT2 (KVM_SEV_INIT forces version 1). + */ + if (es_active && !data->ghcb_version) + data->ghcb_version = 2; + if (unlikely(sev->active)) return -EINVAL; @@ -429,14 +436,6 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, sev->vmsa_features = data->vmsa_features; sev->ghcb_version = data->ghcb_version; - /* - * Currently KVM supports the full range of mandatory features defined - * by version 2 of the GHCB protocol, so default to that for SEV-ES - * guests created via KVM_SEV_INIT2. - */ - if (sev->es_active && !sev->ghcb_version) - sev->ghcb_version = GHCB_VERSION_DEFAULT; - if (vm_type == KVM_X86_SNP_VM) sev->vmsa_features |= SVM_SEV_FEAT_SNP_ACTIVE; From 00f0b959ffb094ea677ca24a0bd14d300a3013a0 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 19 Aug 2025 16:48:27 -0700 Subject: [PATCH 0427/2711] KVM: SEV: Enforce minimum GHCB version requirement for SEV-SNP guests Require a minimum GHCB version of 2 when starting SEV-SNP guests through KVM_SEV_INIT2. When a VMM attempts to start an SEV-SNP guest with an incompatible GHCB version (less than 2), reject the request early rather than allowing the guest kernel to start with an incorrect protocol version and fail later with GHCB_SNP_UNSUPPORTED guest termination. Not enforcing the minimum version typically causes the guest to request termination with GHCB_SNP_UNSUPPORTED error code: kvm_amd: SEV-ES guest requested termination: 0x0:0x2 Fixes: 4af663c2f64a ("KVM: SEV: Allow per-guest configuration of GHCB protocol version") Cc: Thomas Lendacky Cc: Sean Christopherson Cc: Michael Roth Signed-off-by: Nikunj A Dadhania Link: https://lore.kernel.org/r/20250819234833.3080255-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 212f790eedd4..e88dce598785 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -405,6 +405,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, struct kvm_sev_info *sev = to_kvm_sev_info(kvm); struct sev_platform_init_args init_args = {0}; bool es_active = vm_type != KVM_X86_SEV_VM; + bool snp_active = vm_type == KVM_X86_SNP_VM; u64 valid_vmsa_features = es_active ? sev_supported_vmsa_features : 0; int ret; @@ -428,6 +429,9 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, if (es_active && !data->ghcb_version) data->ghcb_version = 2; + if (snp_active && data->ghcb_version < 2) + return -EINVAL; + if (unlikely(sev->active)) return -EINVAL; @@ -436,7 +440,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, sev->vmsa_features = data->vmsa_features; sev->ghcb_version = data->ghcb_version; - if (vm_type == KVM_X86_SNP_VM) + if (snp_active) sev->vmsa_features |= SVM_SEV_FEAT_SNP_ACTIVE; ret = sev_asid_new(sev); @@ -454,7 +458,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, } /* This needs to happen after SEV/SNP firmware initialization. */ - if (vm_type == KVM_X86_SNP_VM) { + if (snp_active) { ret = snp_guest_req_init(kvm); if (ret) goto e_free; From 7b59c73fd611eae87e60e8bb0ab83a1475d8a3a7 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 19 Aug 2025 16:48:28 -0700 Subject: [PATCH 0428/2711] x86/cpufeatures: Add SNP Secure TSC The Secure TSC feature for SEV-SNP allows guests to securely use the RDTSC and RDTSCP instructions, ensuring that the parameters used cannot be altered by the hypervisor once the guest is launched. For more details, refer to the AMD64 APM Vol 2, Section "Secure TSC". Acked-by: Borislav Petkov (AMD) Reviewed-by: Tom Lendacky Tested-by: Vaishali Thakkar Signed-off-by: Nikunj A Dadhania Link: https://lore.kernel.org/r/20250819234833.3080255-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/cpufeatures.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 06fc0479a23f..f53d4943ea63 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -444,6 +444,7 @@ #define X86_FEATURE_VM_PAGE_FLUSH (19*32+ 2) /* VM Page Flush MSR is supported */ #define X86_FEATURE_SEV_ES (19*32+ 3) /* "sev_es" Secure Encrypted Virtualization - Encrypted State */ #define X86_FEATURE_SEV_SNP (19*32+ 4) /* "sev_snp" Secure Encrypted Virtualization - Secure Nested Paging */ +#define X86_FEATURE_SNP_SECURE_TSC (19*32+ 8) /* SEV-SNP Secure TSC */ #define X86_FEATURE_V_TSC_AUX (19*32+ 9) /* Virtual TSC_AUX */ #define X86_FEATURE_SME_COHERENT (19*32+10) /* hardware-enforced cache coherency */ #define X86_FEATURE_DEBUG_SWAP (19*32+14) /* "debug_swap" SEV-ES full debug state swap support */ From 34bd82aab15b8b9e8e9d923267283c84aa8c2789 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 19 Aug 2025 16:48:29 -0700 Subject: [PATCH 0429/2711] KVM: SVM: Move SEV-ES VMSA allocation to a dedicated sev_vcpu_create() helper Add a dedicated sev_vcpu_create() helper to allocate the VMSA page for SEV-ES+ vCPUs, and to allow for consolidating a variety of related SEV+ code in the near future. No functional change intended. Reviewed-by: Nikunj A Dadhania Link: https://lore.kernel.org/r/20250819234833.3080255-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 20 ++++++++++++++++++++ arch/x86/kvm/svm/svm.c | 25 +++++++------------------ arch/x86/kvm/svm/svm.h | 2 ++ 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index e88dce598785..c17cc4eb0fe1 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -4561,6 +4561,26 @@ void sev_init_vmcb(struct vcpu_svm *svm) sev_es_init_vmcb(svm); } +int sev_vcpu_create(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + struct page *vmsa_page; + + if (!sev_es_guest(vcpu->kvm)) + return 0; + + /* + * SEV-ES guests require a separate (from the VMCB) VMSA page used to + * contain the encrypted register state of the guest. + */ + vmsa_page = snp_safe_alloc_page(); + if (!vmsa_page) + return -ENOMEM; + + svm->sev_es.vmsa = page_address(vmsa_page); + return 0; +} + void sev_es_vcpu_reset(struct vcpu_svm *svm) { struct kvm_vcpu *vcpu = &svm->vcpu; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index d9931c6c4bc6..3d4c14e0244f 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1275,7 +1275,6 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm; struct page *vmcb01_page; - struct page *vmsa_page = NULL; int err; BUILD_BUG_ON(offsetof(struct vcpu_svm, vcpu) != 0); @@ -1286,24 +1285,18 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu) if (!vmcb01_page) goto out; - if (sev_es_guest(vcpu->kvm)) { - /* - * SEV-ES guests require a separate VMSA page used to contain - * the encrypted register state of the guest. - */ - vmsa_page = snp_safe_alloc_page(); - if (!vmsa_page) - goto error_free_vmcb_page; - } + err = sev_vcpu_create(vcpu); + if (err) + goto error_free_vmcb_page; err = avic_init_vcpu(svm); if (err) - goto error_free_vmsa_page; + goto error_free_sev; svm->msrpm = svm_vcpu_alloc_msrpm(); if (!svm->msrpm) { err = -ENOMEM; - goto error_free_vmsa_page; + goto error_free_sev; } svm->x2avic_msrs_intercepted = true; @@ -1312,16 +1305,12 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu) svm->vmcb01.pa = __sme_set(page_to_pfn(vmcb01_page) << PAGE_SHIFT); svm_switch_vmcb(svm, &svm->vmcb01); - if (vmsa_page) - svm->sev_es.vmsa = page_address(vmsa_page); - svm->guest_state_loaded = false; return 0; -error_free_vmsa_page: - if (vmsa_page) - __free_page(vmsa_page); +error_free_sev: + sev_free_vcpu(vcpu); error_free_vmcb_page: __free_page(vmcb01_page); out: diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 58b9d168e0c8..cf2569b5451a 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -854,6 +854,7 @@ static inline struct page *snp_safe_alloc_page(void) return snp_safe_alloc_page_node(numa_node_id(), GFP_KERNEL_ACCOUNT); } +int sev_vcpu_create(struct kvm_vcpu *vcpu); void sev_free_vcpu(struct kvm_vcpu *vcpu); void sev_vm_destroy(struct kvm *kvm); void __init sev_set_cpu_caps(void); @@ -880,6 +881,7 @@ static inline struct page *snp_safe_alloc_page(void) return snp_safe_alloc_page_node(numa_node_id(), GFP_KERNEL_ACCOUNT); } +static inline int sev_vcpu_create(struct kvm_vcpu *vcpu) { return 0; } static inline void sev_free_vcpu(struct kvm_vcpu *vcpu) {} static inline void sev_vm_destroy(struct kvm *kvm) {} static inline void __init sev_set_cpu_caps(void) {} From 3d4e882e3439593b406fa226bcdd48c92d2222a6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 19 Aug 2025 16:48:30 -0700 Subject: [PATCH 0430/2711] KVM: SEV: Move init of SNP guest state into sev_init_vmcb() Move the initialization of SNP guest state from svm_vcpu_reset() into sev_init_vmcb() to reduce the number of paths that deal with INIT/RESET for SEV+ vCPUs from 4+ to 1. Plumb in @init_event as necessary. Opportunistically check for an SNP guest outside of sev_snp_init_protected_guest_state() so that sev_init_vmcb() is consistent with respect to checking for SEV-ES+ and SNP+ guests. No functional change intended. Reviewed-by: Nikunj A Dadhania Link: https://lore.kernel.org/r/20250819234833.3080255-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 16 +++++++++------- arch/x86/kvm/svm/svm.c | 9 +++------ arch/x86/kvm/svm/svm.h | 4 +--- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index c17cc4eb0fe1..c5726b091680 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1975,7 +1975,7 @@ static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm) kvm_for_each_vcpu(i, dst_vcpu, dst_kvm) { dst_svm = to_svm(dst_vcpu); - sev_init_vmcb(dst_svm); + sev_init_vmcb(dst_svm, false); if (!dst->es_active) continue; @@ -3887,7 +3887,7 @@ next_range: /* * Invoked as part of svm_vcpu_reset() processing of an init event. */ -void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) +static void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); struct kvm_memory_slot *slot; @@ -3895,9 +3895,6 @@ void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) kvm_pfn_t pfn; gfn_t gfn; - if (!sev_snp_guest(vcpu->kvm)) - return; - guard(mutex)(&svm->sev_es.snp_vmsa_mutex); if (!svm->sev_es.snp_ap_waiting_for_reset) @@ -4546,8 +4543,10 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm) svm_clr_intercept(svm, INTERCEPT_XSETBV); } -void sev_init_vmcb(struct vcpu_svm *svm) +void sev_init_vmcb(struct vcpu_svm *svm, bool init_event) { + struct kvm_vcpu *vcpu = &svm->vcpu; + svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ENABLE; clr_exception_intercept(svm, UD_VECTOR); @@ -4557,7 +4556,10 @@ void sev_init_vmcb(struct vcpu_svm *svm) */ clr_exception_intercept(svm, GP_VECTOR); - if (sev_es_guest(svm->vcpu.kvm)) + if (init_event && sev_snp_guest(vcpu->kvm)) + sev_snp_init_protected_guest_state(vcpu); + + if (sev_es_guest(vcpu->kvm)) sev_es_init_vmcb(svm); } diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 3d4c14e0244f..8ed135dbd649 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1083,7 +1083,7 @@ static void svm_recalc_intercepts_after_set_cpuid(struct kvm_vcpu *vcpu) svm_recalc_msr_intercepts(vcpu); } -static void init_vmcb(struct kvm_vcpu *vcpu) +static void init_vmcb(struct kvm_vcpu *vcpu, bool init_event) { struct vcpu_svm *svm = to_svm(vcpu); struct vmcb *vmcb = svm->vmcb01.ptr; @@ -1221,7 +1221,7 @@ static void init_vmcb(struct kvm_vcpu *vcpu) svm_set_intercept(svm, INTERCEPT_BUSLOCK); if (sev_guest(vcpu->kvm)) - sev_init_vmcb(svm); + sev_init_vmcb(svm, init_event); svm_hv_init_vmcb(vmcb); @@ -1256,10 +1256,7 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) svm->spec_ctrl = 0; svm->virt_spec_ctrl = 0; - if (init_event) - sev_snp_init_protected_guest_state(vcpu); - - init_vmcb(vcpu); + init_vmcb(vcpu, init_event); if (!init_event) __svm_vcpu_reset(vcpu); diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index cf2569b5451a..321480ebe62f 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -826,7 +826,7 @@ void avic_refresh_virtual_apic_mode(struct kvm_vcpu *vcpu); /* sev.c */ int pre_sev_run(struct vcpu_svm *svm, int cpu); -void sev_init_vmcb(struct vcpu_svm *svm); +void sev_init_vmcb(struct vcpu_svm *svm, bool init_event); void sev_vcpu_after_set_cpuid(struct vcpu_svm *svm); int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in); void sev_es_vcpu_reset(struct vcpu_svm *svm); @@ -864,7 +864,6 @@ int sev_cpu_init(struct svm_cpu_data *sd); int sev_dev_get_attr(u32 group, u64 attr, u64 *val); extern unsigned int max_sev_asid; void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code); -void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu); int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order); void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end); int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn); @@ -891,7 +890,6 @@ static inline int sev_cpu_init(struct svm_cpu_data *sd) { return 0; } static inline int sev_dev_get_attr(u32 group, u64 attr, u64 *val) { return -ENXIO; } #define max_sev_asid 0 static inline void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) {} -static inline void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) {} static inline int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order) { return 0; From baf6ed177290db5873f318626970fa7fd4060579 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 19 Aug 2025 16:48:31 -0700 Subject: [PATCH 0431/2711] KVM: SEV: Set RESET GHCB MSR value during sev_es_init_vmcb() Set the RESET value for the GHCB "MSR" during sev_es_init_vmcb() instead of sev_es_vcpu_reset() to allow for dropping sev_es_vcpu_reset() entirely. Note, the call to sev_init_vmcb() from sev_migrate_from() also kinda sorta emulates a RESET, but sev_migrate_from() immediately overwrites ghcb_gpa with the source's current value, so whether or not stuffing the GHCB version is correct/desirable is moot. No functional change intended. Reviewed-by: Nikunj A Dadhania Link: https://lore.kernel.org/r/20250819234833.3080255-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index c5726b091680..ee7a05843548 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -4480,7 +4480,7 @@ void sev_vcpu_after_set_cpuid(struct vcpu_svm *svm) vcpu->arch.reserved_gpa_bits &= ~(1UL << (best->ebx & 0x3f)); } -static void sev_es_init_vmcb(struct vcpu_svm *svm) +static void sev_es_init_vmcb(struct vcpu_svm *svm, bool init_event) { struct kvm_sev_info *sev = to_kvm_sev_info(svm->vcpu.kvm); struct vmcb *vmcb = svm->vmcb01.ptr; @@ -4541,6 +4541,15 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm) /* Can't intercept XSETBV, HV can't modify XCR0 directly */ svm_clr_intercept(svm, INTERCEPT_XSETBV); + + /* + * Set the GHCB MSR value as per the GHCB specification when emulating + * vCPU RESET for an SEV-ES guest. + */ + if (!init_event) + set_ghcb_msr(svm, GHCB_MSR_SEV_INFO((__u64)sev->ghcb_version, + GHCB_VERSION_MIN, + sev_enc_bit)); } void sev_init_vmcb(struct vcpu_svm *svm, bool init_event) @@ -4560,7 +4569,7 @@ void sev_init_vmcb(struct vcpu_svm *svm, bool init_event) sev_snp_init_protected_guest_state(vcpu); if (sev_es_guest(vcpu->kvm)) - sev_es_init_vmcb(svm); + sev_es_init_vmcb(svm, init_event); } int sev_vcpu_create(struct kvm_vcpu *vcpu) @@ -4585,17 +4594,6 @@ int sev_vcpu_create(struct kvm_vcpu *vcpu) void sev_es_vcpu_reset(struct vcpu_svm *svm) { - struct kvm_vcpu *vcpu = &svm->vcpu; - struct kvm_sev_info *sev = to_kvm_sev_info(vcpu->kvm); - - /* - * Set the GHCB MSR value as per the GHCB specification when emulating - * vCPU RESET for an SEV-ES guest. - */ - set_ghcb_msr(svm, GHCB_MSR_SEV_INFO((__u64)sev->ghcb_version, - GHCB_VERSION_MIN, - sev_enc_bit)); - mutex_init(&svm->sev_es.snp_vmsa_mutex); } From f7b1f0c1620db689e085569035a659340a3209c3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 19 Aug 2025 16:48:32 -0700 Subject: [PATCH 0432/2711] KVM: SEV: Fold sev_es_vcpu_reset() into sev_vcpu_create() Fold the remaining line of sev_es_vcpu_reset() into sev_vcpu_create() as there's no need for a dedicated RESET hook just to init a mutex, and the mutex should be initialized as early as possible anyways. No functional change intended. Reviewed-by: Nikunj A Dadhania Link: https://lore.kernel.org/r/20250819234833.3080255-8-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 7 ++----- arch/x86/kvm/svm/svm.c | 3 --- arch/x86/kvm/svm/svm.h | 1 - 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index ee7a05843548..7d1d34e45310 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -4577,6 +4577,8 @@ int sev_vcpu_create(struct kvm_vcpu *vcpu) struct vcpu_svm *svm = to_svm(vcpu); struct page *vmsa_page; + mutex_init(&svm->sev_es.snp_vmsa_mutex); + if (!sev_es_guest(vcpu->kvm)) return 0; @@ -4592,11 +4594,6 @@ int sev_vcpu_create(struct kvm_vcpu *vcpu) return 0; } -void sev_es_vcpu_reset(struct vcpu_svm *svm) -{ - mutex_init(&svm->sev_es.snp_vmsa_mutex); -} - void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa) { struct kvm *kvm = svm->vcpu.kvm; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 8ed135dbd649..b237b4081c91 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1244,9 +1244,6 @@ static void __svm_vcpu_reset(struct kvm_vcpu *vcpu) svm->nmi_masked = false; svm->awaiting_iret_completion = false; - - if (sev_es_guest(vcpu->kvm)) - sev_es_vcpu_reset(svm); } static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 321480ebe62f..3c7f208b7935 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -829,7 +829,6 @@ int pre_sev_run(struct vcpu_svm *svm, int cpu); void sev_init_vmcb(struct vcpu_svm *svm, bool init_event); void sev_vcpu_after_set_cpuid(struct vcpu_svm *svm); int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in); -void sev_es_vcpu_reset(struct vcpu_svm *svm); void sev_es_recalc_msr_intercepts(struct kvm_vcpu *vcpu); void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector); void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa); From a311fce2b694599cede76c5d7a0905336bc09803 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 19 Aug 2025 16:48:33 -0700 Subject: [PATCH 0433/2711] KVM: SVM: Enable Secure TSC for SNP guests Add support for Secure TSC, allowing userspace to configure the Secure TSC feature for SNP guests. Use the SNP specification's desired TSC frequency parameter during the SNP_LAUNCH_START command to set the mean TSC frequency in KHz for Secure TSC enabled guests. Always use kvm->arch.arch.default_tsc_khz as the TSC frequency that is passed to SNP guests in the SNP_LAUNCH_START command. The default value is the host TSC frequency. The userspace can optionally change the TSC frequency via the KVM_SET_TSC_KHZ ioctl before calling the SNP_LAUNCH_START ioctl. Introduce the read-only MSR GUEST_TSC_FREQ (0xc0010134) that returns guest's effective frequency in MHZ when Secure TSC is enabled for SNP guests. Disable interception of this MSR when Secure TSC is enabled. Note that GUEST_TSC_FREQ MSR is accessible only to the guest and not from the hypervisor context. Co-developed-by: Ketan Chaturvedi Signed-off-by: Ketan Chaturvedi Reviewed-by: Kai Huang Reviewed-by: Tom Lendacky Signed-off-by: Nikunj A Dadhania [sean: contain Secure TSC to sev.c] Link: https://lore.kernel.org/r/20250819234833.3080255-9-seanjc@google.com [sean: return -EINVAL if TSC frequency is '0'] Signed-off-by: Sean Christopherson --- arch/x86/include/asm/svm.h | 1 + arch/x86/kvm/svm/sev.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index ffc27f676243..17f6c3fedeee 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -299,6 +299,7 @@ static_assert((X2AVIC_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == X2AVIC_ #define SVM_SEV_FEAT_RESTRICTED_INJECTION BIT(3) #define SVM_SEV_FEAT_ALTERNATE_INJECTION BIT(4) #define SVM_SEV_FEAT_DEBUG_SWAP BIT(5) +#define SVM_SEV_FEAT_SECURE_TSC BIT(9) #define VMCB_ALLOWED_SEV_FEATURES_VALID BIT_ULL(63) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 7d1d34e45310..86fd270a1d6e 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -146,6 +146,14 @@ static bool sev_vcpu_has_debug_swap(struct vcpu_svm *svm) return sev->vmsa_features & SVM_SEV_FEAT_DEBUG_SWAP; } +static bool snp_is_secure_tsc_enabled(struct kvm *kvm) +{ + struct kvm_sev_info *sev = to_kvm_sev_info(kvm); + + return (sev->vmsa_features & SVM_SEV_FEAT_SECURE_TSC) && + !WARN_ON_ONCE(!sev_snp_guest(kvm)); +} + /* Must be called with the sev_bitmap_lock held */ static bool __sev_recycle_asids(unsigned int min_asid, unsigned int max_asid) { @@ -415,6 +423,9 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, if (data->flags) return -EINVAL; + if (!snp_active) + valid_vmsa_features &= ~SVM_SEV_FEAT_SECURE_TSC; + if (data->vmsa_features & ~valid_vmsa_features) return -EINVAL; @@ -2187,6 +2198,13 @@ static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) if (!(params.policy & SNP_POLICY_MASK_RSVD_MBO)) return -EINVAL; + if (snp_is_secure_tsc_enabled(kvm)) { + if (WARN_ON_ONCE(!kvm->arch.default_tsc_khz)) + return -EINVAL; + + start.desired_tsc_khz = kvm->arch.default_tsc_khz; + } + sev->policy = params.policy; sev->snp_context = snp_context_create(kvm, argp); @@ -2195,6 +2213,7 @@ static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) start.gctx_paddr = __psp_pa(sev->snp_context); start.policy = params.policy; + memcpy(start.gosvw, params.gosvw, sizeof(params.gosvw)); rc = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_LAUNCH_START, &start, &argp->error); if (rc) { @@ -3085,6 +3104,9 @@ out: sev_supported_vmsa_features = 0; if (sev_es_debug_swap_enabled) sev_supported_vmsa_features |= SVM_SEV_FEAT_DEBUG_SWAP; + + if (sev_snp_enabled && tsc_khz && cpu_feature_enabled(X86_FEATURE_SNP_SECURE_TSC)) + sev_supported_vmsa_features |= SVM_SEV_FEAT_SECURE_TSC; } void sev_hardware_unsetup(void) @@ -4452,6 +4474,9 @@ void sev_es_recalc_msr_intercepts(struct kvm_vcpu *vcpu) !guest_cpu_cap_has(vcpu, X86_FEATURE_RDTSCP) && !guest_cpu_cap_has(vcpu, X86_FEATURE_RDPID)); + svm_set_intercept_for_msr(vcpu, MSR_AMD64_GUEST_TSC_FREQ, MSR_TYPE_R, + !snp_is_secure_tsc_enabled(vcpu->kvm)); + /* * For SEV-ES, accesses to MSR_IA32_XSS should not be intercepted if * the host/guest supports its use. @@ -4591,6 +4616,9 @@ int sev_vcpu_create(struct kvm_vcpu *vcpu) return -ENOMEM; svm->sev_es.vmsa = page_address(vmsa_page); + + vcpu->arch.guest_tsc_protected = snp_is_secure_tsc_enabled(vcpu->kvm); + return 0; } From 2ec25d34169580922fc6e398fb0cb2591d19349c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 1 Jul 2025 21:29:15 -0700 Subject: [PATCH 0434/2711] Input: move input_bits_to_string() to input-compat.c The input_bits_to_string() function has special handling for compat tasks, formatting the output as a sequence of 32-bit hex values. To better isolate compatibility-related code, move it from drivers/input/input.c to drivers/input/input-compat.c. No functional change intended. Signed-off-by: Dmitry Torokhov --- drivers/input/input-compat.c | 30 ++++++++++++++++++++++++++++++ drivers/input/input-compat.h | 3 +++ drivers/input/input.c | 35 ----------------------------------- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c index 2ccd3eedbd67..a5043193ead8 100644 --- a/drivers/input/input-compat.c +++ b/drivers/input/input-compat.c @@ -6,6 +6,7 @@ */ #include +#include #include #include "input-compat.h" @@ -94,6 +95,28 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size, return 0; } +int input_bits_to_string(char *buf, int buf_size, unsigned long bits, + bool skip_empty) +{ + int len = 0; + + if (in_compat_syscall()) { + u32 dword = bits >> 32; + if (dword || !skip_empty) + len += snprintf(buf, buf_size, "%x ", dword); + + dword = bits & 0xffffffffUL; + if (dword || !skip_empty || len) + len += snprintf(buf + len, max(buf_size - len, 0), + "%x", dword); + } else { + if (bits || !skip_empty) + len += snprintf(buf, buf_size, "%lx", bits); + } + + return len; +} + #else int input_event_from_user(const char __user *buffer, @@ -126,6 +149,13 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size, return 0; } +int input_bits_to_string(char *buf, int buf_size, unsigned long bits, + bool skip_empty) +{ + return bits || !skip_empty ? + snprintf(buf, buf_size, "%lx", bits) : 0; +} + #endif /* CONFIG_COMPAT */ EXPORT_SYMBOL_GPL(input_event_from_user); diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h index 3b7bb12b023b..99c87ceb923d 100644 --- a/drivers/input/input-compat.h +++ b/drivers/input/input-compat.h @@ -75,4 +75,7 @@ int input_event_to_user(char __user *buffer, int input_ff_effect_from_user(const char __user *buffer, size_t size, struct ff_effect *effect); +int input_bits_to_string(char *buf, int buf_size, unsigned long bits, + bool skip_empty); + #endif /* _INPUT_COMPAT_H */ diff --git a/drivers/input/input.c b/drivers/input/input.c index 1da41324362b..9ec817acfeb1 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -998,41 +998,6 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han return error; } -#ifdef CONFIG_COMPAT - -static int input_bits_to_string(char *buf, int buf_size, - unsigned long bits, bool skip_empty) -{ - int len = 0; - - if (in_compat_syscall()) { - u32 dword = bits >> 32; - if (dword || !skip_empty) - len += snprintf(buf, buf_size, "%x ", dword); - - dword = bits & 0xffffffffUL; - if (dword || !skip_empty || len) - len += snprintf(buf + len, max(buf_size - len, 0), - "%x", dword); - } else { - if (bits || !skip_empty) - len += snprintf(buf, buf_size, "%lx", bits); - } - - return len; -} - -#else /* !CONFIG_COMPAT */ - -static int input_bits_to_string(char *buf, int buf_size, - unsigned long bits, bool skip_empty) -{ - return bits || !skip_empty ? - snprintf(buf, buf_size, "%lx", bits) : 0; -} - -#endif - #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_bus_input_dir; From c07329a66cad285faff6c11aaa10eefe1abcfc47 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:52 +0200 Subject: [PATCH 0435/2711] Input: remove unneeded 'fast_io' parameter in regmap_config When using MMIO with regmap, fast_io is implied. No need to set it again. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250813161517.4746-7-wsa+renesas@sang-engineering.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/fsl-imx25-tcq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c index a32708652d10..ff270b3b8572 100644 --- a/drivers/input/touchscreen/fsl-imx25-tcq.c +++ b/drivers/input/touchscreen/fsl-imx25-tcq.c @@ -39,7 +39,6 @@ struct mx25_tcq_priv { }; static const struct regmap_config mx25_tcq_regconfig = { - .fast_io = true, .max_register = 0x5c, .reg_bits = 32, .val_bits = 32, From df595059d54383c42607b59f1f9ea74dade280fe Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 6 Aug 2025 11:16:51 -0700 Subject: [PATCH 0436/2711] Input: include export.h in modules using EXPORT_SYMBOL*() A number of modules in the input subsystem use EXPORT_SYMBOL() and friends without explicitly including the corresponding header . While the build currently succeeds due to this header being pulled in transitively, this is not guaranteed to be the case in the future. Let's add the explicit include to make the dependencies clear and prevent future build breakage. Signed-off-by: Dmitry Torokhov --- drivers/input/ff-core.c | 2 +- drivers/input/ff-memless.c | 1 + drivers/input/gameport/gameport.c | 1 + drivers/input/input-poller.c | 1 + drivers/input/input.c | 1 + drivers/input/joystick/iforce/iforce-main.c | 1 + drivers/input/joystick/iforce/iforce-packets.c | 1 + drivers/input/misc/ad714x.c | 1 + drivers/input/misc/adxl34x.c | 1 + drivers/input/misc/cma3000_d0x.c | 1 + drivers/input/rmi4/rmi_2d_sensor.c | 1 + drivers/input/rmi4/rmi_bus.c | 1 + drivers/input/rmi4/rmi_driver.c | 1 + drivers/input/serio/hil_mlc.c | 1 + drivers/input/serio/hp_sdc.c | 1 + drivers/input/serio/i8042.c | 1 + drivers/input/serio/libps2.c | 1 + drivers/input/serio/serio.c | 1 + drivers/input/sparse-keymap.c | 1 + drivers/input/touch-overlay.c | 1 + drivers/input/touchscreen.c | 1 + drivers/input/touchscreen/ad7879.c | 1 + drivers/input/touchscreen/cyttsp_core.c | 1 + drivers/input/touchscreen/goodix_berlin_core.c | 1 + drivers/input/touchscreen/tsc200x-core.c | 1 + drivers/input/touchscreen/wm9705.c | 1 + drivers/input/touchscreen/wm9712.c | 1 + drivers/input/touchscreen/wm9713.c | 1 + drivers/input/touchscreen/wm97xx-core.c | 1 + 29 files changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index b527308cb52e..66f7ffe8c7e0 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -8,9 +8,9 @@ /* #define DEBUG */ +#include #include #include -#include #include #include #include diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index 91636479ee3c..e0c1c61aae71 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index a832bc46bc92..f4f12dd00fff 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include diff --git a/drivers/input/input-poller.c b/drivers/input/input-poller.c index 9c57713a6151..1ce83d6521bb 100644 --- a/drivers/input/input-poller.c +++ b/drivers/input/input-poller.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include diff --git a/drivers/input/input.c b/drivers/input/input.c index 9ec817acfeb1..a500e1e276c2 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) KBUILD_BASENAME ": " fmt +#include #include #include #include diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 55e6321adab9..86d09faa685c 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -6,6 +6,7 @@ * USB/RS232 I-Force joysticks and wheels. */ +#include #include #include "iforce.h" diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 74181d5123cd..fd1cd731d781 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -6,6 +6,7 @@ * USB/RS232 I-Force joysticks and wheels. */ +#include #include #include "iforce.h" diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c index d106f37df6bc..c9fa789337ba 100644 --- a/drivers/input/misc/ad714x.c +++ b/drivers/input/misc/ad714x.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index 7cafbf8d5f1a..ac7674647c09 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c index cfc12332bee1..b4232b0a3957 100644 --- a/drivers/input/misc/cma3000_d0x.c +++ b/drivers/input/misc/cma3000_d0x.c @@ -6,6 +6,7 @@ * Author: Hemanth V */ +#include #include #include #include diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c index b7fe6eb35a4e..ea3eb87a89af 100644 --- a/drivers/input/rmi4/rmi_2d_sensor.c +++ b/drivers/input/rmi4/rmi_2d_sensor.c @@ -4,6 +4,7 @@ * Copyright (c) 2011 Unixphere */ +#include #include #include #include diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 5f98c3bcfd46..b85ee9db87b0 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -4,6 +4,7 @@ * Copyright (c) 2011 Unixphere */ +#include #include #include #include diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 2168b6cd7167..ccd9338a44db 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "rmi_bus.h" #include "rmi_driver.h" diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index 94e8bcbbf94d..3fedfc5abc73 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -54,6 +54,7 @@ #include #include +#include #include #include #include diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 0eec4c5585cb..1461ef319f92 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -63,6 +63,7 @@ #include #include +#include #include #include #include diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index cab5a4c5baf5..c135254665b6 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index c22ea532276e..269df83a167d 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -8,6 +8,7 @@ #include +#include #include #include #include diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 4468018cef66..2b5ddc5dac19 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 96f23ae57d5a..164f8fcfd1aa 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -10,6 +10,7 @@ * Copyright (C) 2005 Dmitry Torokhov */ +#include #include #include #include diff --git a/drivers/input/touch-overlay.c b/drivers/input/touch-overlay.c index 8806373f7a4a..b9fd82c4829d 100644 --- a/drivers/input/touch-overlay.c +++ b/drivers/input/touch-overlay.c @@ -5,6 +5,7 @@ * Copyright (c) 2023 Javier Carrasco */ +#include #include #include #include diff --git a/drivers/input/touchscreen.c b/drivers/input/touchscreen.c index 4620e20d0190..d699b24bb548 100644 --- a/drivers/input/touchscreen.c +++ b/drivers/input/touchscreen.c @@ -6,6 +6,7 @@ * Copyright (c) 2014 Sebastian Reichel */ +#include #include #include #include diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 8b4f3e3660b8..4c448f39bf57 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index b8ce6012364c..9e729910fbc8 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include diff --git a/drivers/input/touchscreen/goodix_berlin_core.c b/drivers/input/touchscreen/goodix_berlin_core.c index c78d512d97cd..83f28b870531 100644 --- a/drivers/input/touchscreen/goodix_berlin_core.c +++ b/drivers/input/touchscreen/goodix_berlin_core.c @@ -24,6 +24,7 @@ */ #include +#include #include #include #include diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index 82d7d1cf5010..eba53613b005 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -10,6 +10,7 @@ * based on TSC2301 driver by Klaus K. Pedersen */ +#include #include #include #include diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c index 4b55d5e1ea0f..96484aae030c 100644 --- a/drivers/input/touchscreen/wm9705.c +++ b/drivers/input/touchscreen/wm9705.c @@ -9,6 +9,7 @@ * Russell King */ +#include #include #include #include diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c index 6947714dfefa..087ece57741a 100644 --- a/drivers/input/touchscreen/wm9712.c +++ b/drivers/input/touchscreen/wm9712.c @@ -9,6 +9,7 @@ * Russell King */ +#include #include #include #include diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c index a67fbe304f92..6f13f46ce6e6 100644 --- a/drivers/input/touchscreen/wm9713.c +++ b/drivers/input/touchscreen/wm9713.c @@ -9,6 +9,7 @@ * Russell King */ +#include #include #include #include diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index b25771a8df2b..96354c44af87 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -29,6 +29,7 @@ * - Support for async sampling control for noisy LCDs. */ +#include #include #include #include From fb43a9e696e1ecba8781b5ea601db07802f50a9f Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 18 Aug 2025 14:38:13 -0400 Subject: [PATCH 0437/2711] dt-bindings: input: convert lpc32xx-key.txt to yaml format Convert lpc32xx-key.txt to yaml format. Additional changes: - set maximum of key-row(column) to 4. - add ref to matrix-keymap.yaml. Reviewed-by: Vladimir Zapolskiy Signed-off-by: Frank Li Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250818183814.3603308-1-Frank.Li@nxp.com Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/lpc32xx-key.txt | 34 ----------- .../bindings/input/nxp,lpc3220-key.yaml | 61 +++++++++++++++++++ 2 files changed, 61 insertions(+), 34 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/lpc32xx-key.txt create mode 100644 Documentation/devicetree/bindings/input/nxp,lpc3220-key.yaml diff --git a/Documentation/devicetree/bindings/input/lpc32xx-key.txt b/Documentation/devicetree/bindings/input/lpc32xx-key.txt deleted file mode 100644 index 2b075a080d30..000000000000 --- a/Documentation/devicetree/bindings/input/lpc32xx-key.txt +++ /dev/null @@ -1,34 +0,0 @@ -NXP LPC32xx Key Scan Interface - -This binding is based on the matrix-keymap binding with the following -changes: - -Required Properties: -- compatible: Should be "nxp,lpc3220-key" -- reg: Physical base address of the controller and length of memory mapped - region. -- interrupts: The interrupt number to the cpu. -- clocks: phandle to clock controller plus clock-specifier pair -- nxp,debounce-delay-ms: Debounce delay in ms -- nxp,scan-delay-ms: Repeated scan period in ms -- linux,keymap: the key-code to be reported when the key is pressed - and released, see also - Documentation/devicetree/bindings/input/matrix-keymap.txt - -Note: keypad,num-rows and keypad,num-columns are required, and must be equal -since LPC32xx only supports square matrices - -Example: - - key@40050000 { - compatible = "nxp,lpc3220-key"; - reg = <0x40050000 0x1000>; - clocks = <&clk LPC32XX_CLK_KEY>; - interrupt-parent = <&sic1>; - interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; - keypad,num-rows = <1>; - keypad,num-columns = <1>; - nxp,debounce-delay-ms = <3>; - nxp,scan-delay-ms = <34>; - linux,keymap = <0x00000002>; - }; diff --git a/Documentation/devicetree/bindings/input/nxp,lpc3220-key.yaml b/Documentation/devicetree/bindings/input/nxp,lpc3220-key.yaml new file mode 100644 index 000000000000..9e0d977bdf5c --- /dev/null +++ b/Documentation/devicetree/bindings/input/nxp,lpc3220-key.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/nxp,lpc3220-key.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP LPC32xx Key Scan Interface + +maintainers: + - Frank Li + +properties: + compatible: + const: nxp,lpc3220-key + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + nxp,debounce-delay-ms: + description: Debounce delay in ms + + nxp,scan-delay-ms: + description: Repeated scan period in ms + +required: + - compatible + - reg + - interrupts + - clocks + - nxp,debounce-delay-ms + - nxp,scan-delay-ms + - linux,keymap + +allOf: + - $ref: matrix-keymap.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + key@40050000 { + compatible = "nxp,lpc3220-key"; + reg = <0x40050000 0x1000>; + clocks = <&clk LPC32XX_CLK_KEY>; + interrupt-parent = <&sic1>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; + keypad,num-rows = <1>; + keypad,num-columns = <1>; + nxp,debounce-delay-ms = <3>; + nxp,scan-delay-ms = <34>; + linux,keymap = <0x00000002>; + }; From 11d5674fc2e5e75ccaa13685a909c14e033544b7 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 11 Aug 2025 12:44:00 +0800 Subject: [PATCH 0438/2711] crypto: hash - Make HASH_MAX_DESCSIZE a bit more obvious Move S390_SHA_CTX_SIZE into crypto/hash.h so that the derivation of HASH_MAX_DESCSIZE is less cryptic. Signed-off-by: Herbert Xu --- arch/s390/crypto/sha.h | 8 +++++++- include/crypto/hash.h | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/arch/s390/crypto/sha.h b/arch/s390/crypto/sha.h index cadb4b13622a..b9cd9572dd35 100644 --- a/arch/s390/crypto/sha.h +++ b/arch/s390/crypto/sha.h @@ -10,14 +10,15 @@ #ifndef _CRYPTO_ARCH_S390_SHA_H #define _CRYPTO_ARCH_S390_SHA_H +#include #include #include +#include #include /* must be big enough for the largest SHA variant */ #define CPACF_MAX_PARMBLOCK_SIZE SHA3_STATE_SIZE #define SHA_MAX_BLOCK_SIZE SHA3_224_BLOCK_SIZE -#define S390_SHA_CTX_SIZE sizeof(struct s390_sha_ctx) struct s390_sha_ctx { u64 count; /* message length in bytes */ @@ -42,4 +43,9 @@ int s390_sha_update_blocks(struct shash_desc *desc, const u8 *data, int s390_sha_finup(struct shash_desc *desc, const u8 *src, unsigned int len, u8 *out); +static inline void __check_s390_sha_ctx_size(void) +{ + BUILD_BUG_ON(S390_SHA_CTX_SIZE != sizeof(struct s390_sha_ctx)); +} + #endif diff --git a/include/crypto/hash.h b/include/crypto/hash.h index bbaeae705ef0..586700332c73 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -177,14 +177,26 @@ struct shash_desc { #define HASH_MAX_DIGESTSIZE 64 +/* + * The size of a core hash state and a partial block. The final byte + * is the length of the partial block. + */ +#define HASH_STATE_AND_BLOCK(state, block) ((state) + (block) + 1) + + /* Worst case is sha3-224. */ -#define HASH_MAX_STATESIZE 200 + 144 + 1 +#define HASH_MAX_STATESIZE HASH_STATE_AND_BLOCK(200, 144) + +/* This needs to match arch/s390/crypto/sha.h. */ +#define S390_SHA_CTX_SIZE 216 /* * Worst case is hmac(sha3-224-s390). Its context is a nested 'shash_desc' * containing a 'struct s390_sha_ctx'. */ -#define HASH_MAX_DESCSIZE (sizeof(struct shash_desc) + 361) +#define SHA3_224_S390_DESCSIZE HASH_STATE_AND_BLOCK(S390_SHA_CTX_SIZE, 144) +#define HASH_MAX_DESCSIZE (sizeof(struct shash_desc) + \ + SHA3_224_S390_DESCSIZE) #define MAX_SYNC_HASH_REQSIZE (sizeof(struct ahash_request) + \ HASH_MAX_DESCSIZE) From 361fa7f813e7056cecdb24f3582ab0ad4a088e4e Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 11 Aug 2025 11:24:57 +0200 Subject: [PATCH 0439/2711] crypto: octeontx2 - Call strscpy() with correct size argument In otx2_cpt_dl_custom_egrp_create(), strscpy() is called with the length of the source string rather than the size of the destination buffer. This is fine as long as the destination buffer is larger than the source string, but we should still use the destination buffer size instead to call strscpy() as intended. And since 'tmp_buf' is a fixed-size buffer, we can safely omit the size argument and let strscpy() infer it using sizeof(). Fixes: d9d7749773e8 ("crypto: octeontx2 - add apis for custom engine groups") Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c index cc47e361089a..ebdf4efa09d4 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c @@ -1615,7 +1615,7 @@ int otx2_cpt_dl_custom_egrp_create(struct otx2_cptpf_dev *cptpf, return -EINVAL; } err_msg = "Invalid engine group format"; - strscpy(tmp_buf, ctx->val.vstr, strlen(ctx->val.vstr) + 1); + strscpy(tmp_buf, ctx->val.vstr); start = tmp_buf; has_se = has_ie = has_ae = false; From 56a50e37fee038d004866e5a2c479706d6034017 Mon Sep 17 00:00:00 2001 From: Yunseong Kim Date: Sat, 16 Aug 2025 14:30:29 +0000 Subject: [PATCH 0440/2711] crypto: ccp - Fix typo in psp_populate_hsti function name The function "psp_poulate_hsti" was misspelled. This patch corrects the typo to "psp_populate_hsti" in both the function definition and its call site within psp_init_hsti(). Signed-off-by: Yunseong Kim Reviewed-by: Mario Limonciello > --- Signed-off-by: Herbert Xu --- drivers/crypto/ccp/hsti.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/ccp/hsti.c b/drivers/crypto/ccp/hsti.c index 0ab3708951af..36f6534fbe08 100644 --- a/drivers/crypto/ccp/hsti.c +++ b/drivers/crypto/ccp/hsti.c @@ -74,7 +74,7 @@ struct attribute_group psp_security_attr_group = { .is_visible = psp_security_is_visible, }; -static int psp_poulate_hsti(struct psp_device *psp) +static int psp_populate_hsti(struct psp_device *psp) { struct hsti_request *req; int ret; @@ -114,7 +114,7 @@ int psp_init_hsti(struct psp_device *psp) int ret; if (PSP_FEATURE(psp, HSTI)) { - ret = psp_poulate_hsti(psp); + ret = psp_populate_hsti(psp); if (ret) return ret; } From 501302d5cee0d8e8ec2c4a5919c37e0df9abc99b Mon Sep 17 00:00:00 2001 From: Xiao Liang Date: Sun, 17 Aug 2025 00:30:15 +0800 Subject: [PATCH 0441/2711] padata: Reset next CPU when reorder sequence wraps around When seq_nr wraps around, the next reorder job with seq 0 is hashed to the first CPU in padata_do_serial(). Correspondingly, need reset pd->cpu to the first one when pd->processed wraps around. Otherwise, if the number of used CPUs is not a power of 2, padata_find_next() will be checking a wrong list, hence deadlock. Fixes: 6fc4dbcf0276 ("padata: Replace delayed timer with immediate workqueue in padata_reorder") Cc: Signed-off-by: Xiao Liang Signed-off-by: Herbert Xu --- kernel/padata.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/padata.c b/kernel/padata.c index f85f8bd788d0..833740d75483 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -291,8 +291,12 @@ static void padata_reorder(struct padata_priv *padata) struct padata_serial_queue *squeue; int cb_cpu; - cpu = cpumask_next_wrap(cpu, pd->cpumask.pcpu); processed++; + /* When sequence wraps around, reset to the first CPU. */ + if (unlikely(processed == 0)) + cpu = cpumask_first(pd->cpumask.pcpu); + else + cpu = cpumask_next_wrap(cpu, pd->cpumask.pcpu); cb_cpu = padata->cb_cpu; squeue = per_cpu_ptr(pd->squeue, cb_cpu); From 5be502174bf0f5d0aafaab57fa4512723d6d2973 Mon Sep 17 00:00:00 2001 From: "Xin Li (Intel)" Date: Fri, 22 Aug 2025 00:16:44 -0700 Subject: [PATCH 0442/2711] x86/entry/fred: Push __KERNEL_CS directly Push __KERNEL_CS directly, rather than moving it into RAX and then pushing RAX. No functional changes. Suggested-by: H. Peter Anvin (Intel) Signed-off-by: Xin Li (Intel) Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20250822071644.1405268-1-xin@zytor.com --- arch/x86/entry/entry_64_fred.S | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/entry/entry_64_fred.S b/arch/x86/entry/entry_64_fred.S index 29c5c32c16c3..cb5ff2b1f6e7 100644 --- a/arch/x86/entry/entry_64_fred.S +++ b/arch/x86/entry/entry_64_fred.S @@ -97,8 +97,7 @@ SYM_FUNC_START(asm_fred_entry_from_kvm) push %rdi /* fred_ss handed in by the caller */ push %rbp pushf - mov $__KERNEL_CS, %rax - push %rax + push $__KERNEL_CS /* * Unlike the IDT event delivery, FRED _always_ pushes an error code From d20a5d96eddb95b4faa33247ec653a580c48fdfa Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Mon, 16 Jun 2025 10:30:41 +0200 Subject: [PATCH 0443/2711] x86/idle: Use MONITORX and MWAITX mnemonics in Current minimum required version of binutils is 2.30, which supports MONITORX and MWAITX instruction mnemonics. Replace the byte-wise specification of MONITORX and MWAITX with these proper mnemonics. No functional change intended. Signed-off-by: Uros Bizjak Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20250616083056.157460-1-ubizjak@gmail.com --- arch/x86/include/asm/mwait.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h index 6ca6516c7492..e4815e15dc9a 100644 --- a/arch/x86/include/asm/mwait.h +++ b/arch/x86/include/asm/mwait.h @@ -36,9 +36,7 @@ static __always_inline void __monitor(const void *eax, u32 ecx, u32 edx) static __always_inline void __monitorx(const void *eax, u32 ecx, u32 edx) { - /* "monitorx %eax, %ecx, %edx" */ - asm volatile(".byte 0x0f, 0x01, 0xfa" - :: "a" (eax), "c" (ecx), "d"(edx)); + asm volatile("monitorx" :: "a" (eax), "c" (ecx), "d"(edx)); } static __always_inline void __mwait(u32 eax, u32 ecx) @@ -80,9 +78,7 @@ static __always_inline void __mwaitx(u32 eax, u32 ebx, u32 ecx) { /* No need for TSA buffer clearing on AMD */ - /* "mwaitx %eax, %ebx, %ecx" */ - asm volatile(".byte 0x0f, 0x01, 0xfb" - :: "a" (eax), "b" (ebx), "c" (ecx)); + asm volatile("mwaitx" :: "a" (eax), "b" (ebx), "c" (ecx)); } /* From 8495e00fe654962bdd83dd6ca8f32918c50f3454 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Tue, 19 Aug 2025 07:45:59 +0700 Subject: [PATCH 0444/2711] Documentation: RCU: Wrap kvm-remote.sh rerun snippet in literal code block Unlike other kvm*.sh snippets in RCU torture test documentation, kvm-remote.sh rerun snippet isn't formatted as literal code block, causing it to be definition list instead in htmldocs output. Wrap it like the rest. Fixes: 0c208a793022 ("doc: Update torture.rst") Signed-off-by: Bagas Sanjaya Signed-off-by: Paul E. McKenney Reviewed-by: Randy Dunlap --- Documentation/RCU/torture.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/RCU/torture.rst b/Documentation/RCU/torture.rst index 4b1f99c4181f..cc57d01ed700 100644 --- a/Documentation/RCU/torture.rst +++ b/Documentation/RCU/torture.rst @@ -364,7 +364,7 @@ systems must come first. The kvm.sh ``--dryrun scenarios`` argument is useful for working out how many scenarios may be run in one batch across a group of systems. -You can also re-run a previous remote run in a manner similar to kvm.sh: +You can also re-run a previous remote run in a manner similar to kvm.sh:: kvm-remote.sh "system0 system1 system2 system3 system4 system5" \ tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28-remote \ From 326b16baed677edcc706ee44791716a610a8edf0 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Tue, 19 Aug 2025 08:26:19 +0700 Subject: [PATCH 0445/2711] Documentation: RCU: Reduce toctree depth toctree index for RCU currently has maximum depth of 3. Since no docs currently use more than 3 section heading levels, this effectively spills the entire docs hierarchy. Tidy up by reducing toctree depth to 2 (only showing docs title and second-level sections). Signed-off-by: Bagas Sanjaya Signed-off-by: Paul E. McKenney --- Documentation/RCU/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/RCU/index.rst b/Documentation/RCU/index.rst index 84a79903f6a8..e1be5b3c2c67 100644 --- a/Documentation/RCU/index.rst +++ b/Documentation/RCU/index.rst @@ -7,7 +7,7 @@ RCU concepts ============ .. toctree:: - :maxdepth: 3 + :maxdepth: 2 checklist lockdep From 9832258da7f1bc2051c536a2068e880d49570de2 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Tue, 19 Aug 2025 08:26:20 +0700 Subject: [PATCH 0446/2711] Documentation: RCU: Retitle toctree index toctree index title ("RCU concepts") is rather a misnomer: RCU concepts is already described in rcu.rst, whereas the toctree suggests that the docs themes about handbook on RCU subsystem instead. Edit the title to reflect the fact. Signed-off-by: Bagas Sanjaya Signed-off-by: Paul E. McKenney --- Documentation/RCU/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/RCU/index.rst b/Documentation/RCU/index.rst index e1be5b3c2c67..ef26c78507d3 100644 --- a/Documentation/RCU/index.rst +++ b/Documentation/RCU/index.rst @@ -1,9 +1,9 @@ .. SPDX-License-Identifier: GPL-2.0 -.. _rcu_concepts: +.. _rcu_handbook: ============ -RCU concepts +RCU Handbook ============ .. toctree:: From 14b0a12a70414f7a3119e9d661a8bcab42492b8e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 19 Aug 2025 08:38:06 -0700 Subject: [PATCH 0447/2711] doc: Fix typo in RCU's torture.rst documentation s/you// Reported-by: Randy Dunlap Signed-off-by: Paul E. McKenney --- Documentation/RCU/torture.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/RCU/torture.rst b/Documentation/RCU/torture.rst index cc57d01ed700..1ad5cc793811 100644 --- a/Documentation/RCU/torture.rst +++ b/Documentation/RCU/torture.rst @@ -344,7 +344,7 @@ painstaking and error-prone. And this is why the kvm-remote.sh script exists. -If you the following command works:: +If the following command works:: ssh system0 date From de117fe3f50f962d927b17b8de6632ee197b70ae Mon Sep 17 00:00:00 2001 From: Nikil Paul S Date: Tue, 19 Aug 2025 18:05:46 +0000 Subject: [PATCH 0448/2711] docs: rcu: Replace multiple dead OLS links in RTFP.txt This patch updates several dead OLS links in RTFP.txt, replacing them with working copies hosted on kernel.org. Originally posted as part of a 2-patch series, this is now being sent as a standalone v4 patch to avoid confusion. Signed-off-by: Nikil Paul S Signed-off-by: Paul E. McKenney --- Documentation/RCU/RTFP.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt index db8f16b392aa..8d4e8de4c460 100644 --- a/Documentation/RCU/RTFP.txt +++ b/Documentation/RCU/RTFP.txt @@ -641,7 +641,7 @@ Orran Krieger and Rusty Russell and Dipankar Sarma and Maneesh Soni" ,Month="July" ,Year="2001" ,note="Available: -\url{http://www.linuxsymposium.org/2001/abstracts/readcopy.php} +\url{https://kernel.org/doc/ols/2001/read-copy.pdf} \url{http://www.rdrop.com/users/paulmck/RCU/rclock_OLS.2001.05.01c.pdf} [Viewed June 23, 2004]" ,annotation={ @@ -1480,7 +1480,7 @@ Suparna Bhattacharya" ,Year="2006" ,pages="v2 123-138" ,note="Available: -\url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184} +\url{https://kernel.org/doc/ols/2006/ols2006v2-pages-131-146.pdf} \url{http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf} [Viewed January 1, 2007]" ,annotation={ @@ -1511,7 +1511,7 @@ Canis Rufus and Zoicon5 and Anome and Hal Eisen" ,Year="2006" ,pages="v2 249-254" ,note="Available: -\url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184} +\url{https://kernel.org/doc/ols/2006/ols2006v2-pages-249-262.pdf} [Viewed January 11, 2009]" ,annotation={ Uses RCU-protected radix tree for a lockless page cache. From 3e15cccf3ea272ae40942e8a5a741bb69a56f654 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 21 Aug 2025 21:41:16 +0800 Subject: [PATCH 0449/2711] rcutorture: Use kcalloc() instead of kzalloc() Use kcalloc() in rcu_torture_writer() to gain built-in overflow protection, making memory allocation safer when calculating allocation size compared to explicit multiplication. Change sizeof(ulo[0]) and sizeof(rgo[0]) to sizeof(*ulo) and sizeof(*rgo), as this is more consistent with coding conventions. Signed-off-by: Qianfeng Rong Signed-off-by: Paul E. McKenney --- kernel/rcu/rcutorture.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index b8a684459381..29fe3c01312f 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1572,12 +1572,12 @@ rcu_torture_writer(void *arg) return 0; } if (cur_ops->poll_active > 0) { - ulo = kzalloc(cur_ops->poll_active * sizeof(ulo[0]), GFP_KERNEL); + ulo = kcalloc(cur_ops->poll_active, sizeof(*ulo), GFP_KERNEL); if (!WARN_ON(!ulo)) ulo_size = cur_ops->poll_active; } if (cur_ops->poll_active_full > 0) { - rgo = kzalloc(cur_ops->poll_active_full * sizeof(rgo[0]), GFP_KERNEL); + rgo = kcalloc(cur_ops->poll_active_full, sizeof(*rgo), GFP_KERNEL); if (!WARN_ON(!rgo)) rgo_size = cur_ops->poll_active_full; } From 9a0352dd45225597cb8d4a4d79cf5b53f3609ae3 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 21 Aug 2025 21:41:17 +0800 Subject: [PATCH 0450/2711] refscale: Use kcalloc() instead of kzalloc() Use kcalloc() in main_func() to gain built-in overflow protection, making memory allocation safer when calculating allocation size compared to explicit multiplication. Signed-off-by: Qianfeng Rong Signed-off-by: Paul E. McKenney --- kernel/rcu/refscale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rcu/refscale.c b/kernel/rcu/refscale.c index df646e0694a8..5840fac06feb 100644 --- a/kernel/rcu/refscale.c +++ b/kernel/rcu/refscale.c @@ -1021,7 +1021,7 @@ static int main_func(void *arg) set_user_nice(current, MAX_NICE); VERBOSE_SCALEOUT("main_func task started"); - result_avg = kzalloc(nruns * sizeof(*result_avg), GFP_KERNEL); + result_avg = kcalloc(nruns, sizeof(*result_avg), GFP_KERNEL); buf = kzalloc(800 + 64, GFP_KERNEL); if (!result_avg || !buf) { SCALEOUT_ERRSTRING("out of memory"); From 81e39b6d89b5148480f607f93a88cd16f7df6f4a Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 8 Jul 2025 13:19:20 +0300 Subject: [PATCH 0451/2711] MAINTAINERS: Update the file list in the TDX entry. This includes files that were previously missed in the TDX entry file list and makes it more future-proof. Most importantly, this now covers the recently added KVM enabling. [ dhansen: move from explicit files to "tdx" filename match ] Signed-off-by: Kirill A. Shutemov Signed-off-by: Dave Hansen Link: https://lore.kernel.org/all/20250708101922.50560-2-kirill.shutemov%40linux.intel.com --- MAINTAINERS | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index daf520a13bdf..31632e78de80 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27329,13 +27329,8 @@ L: x86@kernel.org L: linux-coco@lists.linux.dev S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/tdx -F: Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest -F: arch/x86/boot/compressed/tdx* -F: arch/x86/coco/tdx/ -F: arch/x86/include/asm/shared/tdx.h -F: arch/x86/include/asm/tdx.h -F: arch/x86/virt/vmx/tdx/ -F: drivers/virt/coco/tdx-guest +N: tdx +K: \b(tdx) X86 VDSO M: Andy Lutomirski From 957e3855407d943577695531931e8aec938733d2 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 8 Jul 2025 13:19:21 +0300 Subject: [PATCH 0452/2711] MAINTAINERS: Add Rick Edgecombe as a TDX reviewer Rick worked extensively to enable TDX in KVM. He will continue to work on TDX and should be involved in discussions regarding TDX. Add Rick as a TDX reviewer. Signed-off-by: Kirill A. Shutemov Signed-off-by: Dave Hansen Link: https://lore.kernel.org/all/20250708101922.50560-3-kirill.shutemov%40linux.intel.com --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 31632e78de80..86fae8935629 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27325,6 +27325,7 @@ F: arch/x86/kernel/unwind_*.c X86 TRUST DOMAIN EXTENSIONS (TDX) M: Kirill A. Shutemov R: Dave Hansen +R: Rick Edgecombe L: x86@kernel.org L: linux-coco@lists.linux.dev S: Supported From d8b483ba4336470805cc04c3a263ddc126c90175 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Wed, 9 Jul 2025 22:10:35 +0800 Subject: [PATCH 0453/2711] MAINTAINERS: Add KVM mail list to the TDX entry KVM is the primary user of TDX within the kernel, and it is KVM that provides support for running TDX guests. Add the KVM mailing list to the TDX entry so that KVM people can be informed of proposed changes and updates related to TDX. Signed-off-by: Xiaoyao Li Signed-off-by: Dave Hansen Acked-by: Sean Christopherson Link: https://lore.kernel.org/all/20250709141035.70299-1-xiaoyao.li%40intel.com --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 86fae8935629..707cac7fb95d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27328,6 +27328,7 @@ R: Dave Hansen R: Rick Edgecombe L: x86@kernel.org L: linux-coco@lists.linux.dev +L: kvm@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/tdx N: tdx From 94272b084a745940e076a170d8193ac3427292e6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 19 Aug 2025 18:58:09 +0300 Subject: [PATCH 0454/2711] x86/tdx: Eliminate duplicate code in tdx_clear_page() tdx_clear_page() and reset_tdx_pages() duplicate the TDX page clearing logic. Rename reset_tdx_pages() to tdx_quirk_reset_paddr() and create tdx_quirk_reset_page() to call tdx_quirk_reset_paddr() and be used in place of tdx_clear_page(). The new name reflects that, in fact, the clearing is necessary only for hardware with a certain quirk. That is dealt with in a subsequent patch but doing the rename here avoids additional churn. Note reset_tdx_pages() is slightly different from tdx_clear_page() because, more appropriately, it uses mb() in place of __mb(). Except when extra debugging is enabled (kcsan at present), mb() just calls __mb(). Signed-off-by: Adrian Hunter Signed-off-by: Dave Hansen Reviewed-by: Kirill A. Shutemov Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Reviewed-by: Rick Edgecombe Acked-by: Kai Huang Acked-by: Sean Christopherson Acked-by: Vishal Annapurve Link: https://lore.kernel.org/all/20250819155811.136099-2-adrian.hunter%40intel.com --- arch/x86/include/asm/tdx.h | 2 ++ arch/x86/kvm/vmx/tdx.c | 25 +++---------------------- arch/x86/virt/vmx/tdx/tdx.c | 10 ++++++++-- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 7ddef3a69866..57b46f05ff97 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -131,6 +131,8 @@ int tdx_guest_keyid_alloc(void); u32 tdx_get_nr_guest_keyids(void); void tdx_guest_keyid_free(unsigned int keyid); +void tdx_quirk_reset_page(struct page *page); + struct tdx_td { /* TD root structure: */ struct page *tdr_page; diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 66744f5768c8..f457b2e578b2 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -281,25 +281,6 @@ static inline void tdx_disassociate_vp(struct kvm_vcpu *vcpu) vcpu->cpu = -1; } -static void tdx_clear_page(struct page *page) -{ - const void *zero_page = (const void *) page_to_virt(ZERO_PAGE(0)); - void *dest = page_to_virt(page); - unsigned long i; - - /* - * The page could have been poisoned. MOVDIR64B also clears - * the poison bit so the kernel can safely use the page again. - */ - for (i = 0; i < PAGE_SIZE; i += 64) - movdir64b(dest + i, zero_page); - /* - * MOVDIR64B store uses WC buffer. Prevent following memory reads - * from seeing potentially poisoned cache. - */ - __mb(); -} - static void tdx_no_vcpus_enter_start(struct kvm *kvm) { struct kvm_tdx *kvm_tdx = to_kvm_tdx(kvm); @@ -345,7 +326,7 @@ static int tdx_reclaim_page(struct page *page) r = __tdx_reclaim_page(page); if (!r) - tdx_clear_page(page); + tdx_quirk_reset_page(page); return r; } @@ -593,7 +574,7 @@ static void tdx_reclaim_td_control_pages(struct kvm *kvm) pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err); return; } - tdx_clear_page(kvm_tdx->td.tdr_page); + tdx_quirk_reset_page(kvm_tdx->td.tdr_page); __free_page(kvm_tdx->td.tdr_page); kvm_tdx->td.tdr_page = NULL; @@ -1714,7 +1695,7 @@ static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn, pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err); return -EIO; } - tdx_clear_page(page); + tdx_quirk_reset_page(page); tdx_unpin(kvm, page); return 0; } diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index c7a9a087ccaf..fc8d8e444f15 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -637,7 +637,7 @@ err: * clear these pages. Note this function doesn't flush cache of * these TDX private pages. The caller should make sure of that. */ -static void reset_tdx_pages(unsigned long base, unsigned long size) +static void tdx_quirk_reset_paddr(unsigned long base, unsigned long size) { const void *zero_page = (const void *)page_address(ZERO_PAGE(0)); unsigned long phys, end; @@ -654,9 +654,15 @@ static void reset_tdx_pages(unsigned long base, unsigned long size) mb(); } +void tdx_quirk_reset_page(struct page *page) +{ + tdx_quirk_reset_paddr(page_to_phys(page), PAGE_SIZE); +} +EXPORT_SYMBOL_GPL(tdx_quirk_reset_page); + static void tdmr_reset_pamt(struct tdmr_info *tdmr) { - tdmr_do_pamt_func(tdmr, reset_tdx_pages); + tdmr_do_pamt_func(tdmr, tdx_quirk_reset_paddr); } static void tdmrs_reset_pamt_all(struct tdmr_info_list *tdmr_list) From a27b008a5d7e8c49740dfd4b560cd2d1abe722e4 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 19 Aug 2025 18:58:10 +0300 Subject: [PATCH 0455/2711] x86/tdx: Tidy reset_pamt functions tdx_quirk_reset_paddr() was renamed to reflect that, in fact, the clearing is necessary only for hardware with a certain quirk. That is dealt with in a subsequent patch. Rename reset_pamt functions to contain "quirk" to reflect the new functionality, and remove the now misleading comment. Signed-off-by: Adrian Hunter Signed-off-by: Dave Hansen Reviewed-by: Rick Edgecombe Reviewed-by: Binbin Wu Acked-by: Kai Huang Acked-by: Vishal Annapurve Link: https://lore.kernel.org/all/20250819155811.136099-3-adrian.hunter%40intel.com --- arch/x86/virt/vmx/tdx/tdx.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index fc8d8e444f15..9e4638f68ba0 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -660,17 +660,17 @@ void tdx_quirk_reset_page(struct page *page) } EXPORT_SYMBOL_GPL(tdx_quirk_reset_page); -static void tdmr_reset_pamt(struct tdmr_info *tdmr) +static void tdmr_quirk_reset_pamt(struct tdmr_info *tdmr) { tdmr_do_pamt_func(tdmr, tdx_quirk_reset_paddr); } -static void tdmrs_reset_pamt_all(struct tdmr_info_list *tdmr_list) +static void tdmrs_quirk_reset_pamt_all(struct tdmr_info_list *tdmr_list) { int i; for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) - tdmr_reset_pamt(tdmr_entry(tdmr_list, i)); + tdmr_quirk_reset_pamt(tdmr_entry(tdmr_list, i)); } static unsigned long tdmrs_count_pamt_kb(struct tdmr_info_list *tdmr_list) @@ -1142,15 +1142,7 @@ err_reset_pamts: * to the kernel. */ wbinvd_on_all_cpus(); - /* - * According to the TDX hardware spec, if the platform - * doesn't have the "partial write machine check" - * erratum, any kernel read/write will never cause #MC - * in kernel space, thus it's OK to not convert PAMTs - * back to normal. But do the conversion anyway here - * as suggested by the TDX spec. - */ - tdmrs_reset_pamt_all(&tdx_tdmr_list); + tdmrs_quirk_reset_pamt_all(&tdx_tdmr_list); err_free_pamts: tdmrs_free_pamt_all(&tdx_tdmr_list); err_free_tdmrs: From 01fb93a363e0583a3ce48098aca5ab9825a5b790 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 19 Aug 2025 18:58:11 +0300 Subject: [PATCH 0456/2711] x86/tdx: Skip clearing reclaimed pages unless X86_BUG_TDX_PW_MCE is present Avoid clearing reclaimed TDX private pages unless the platform is affected by the X86_BUG_TDX_PW_MCE erratum. This significantly reduces VM shutdown time on unaffected systems. Background KVM currently clears reclaimed TDX private pages using MOVDIR64B, which: - Clears the TD Owner bit (which identifies TDX private memory) and integrity metadata without triggering integrity violations. - Clears poison from cache lines without consuming it, avoiding MCEs on access (refer TDX Module Base spec. 1348549-006US section 6.5. Handling Machine Check Events during Guest TD Operation). The TDX module also uses MOVDIR64B to initialize private pages before use. If cache flushing is needed, it sets TDX_FEATURES.CLFLUSH_BEFORE_ALLOC. However, KVM currently flushes unconditionally, refer commit 94c477a751c7b ("x86/virt/tdx: Add SEAMCALL wrappers to add TD private pages") In contrast, when private pages are reclaimed, the TDX Module handles flushing via the TDH.PHYMEM.CACHE.WB SEAMCALL. Problem Clearing all private pages during VM shutdown is costly. For guests with a large amount of memory it can take minutes. Solution TDX Module Base Architecture spec. documents that private pages reclaimed from a TD should be initialized using MOVDIR64B, in order to avoid integrity violation or TD bit mismatch detection when later being read using a shared HKID, refer April 2025 spec. "Page Initialization" in section "8.6.2. Platforms not Using ACT: Required Cache Flush and Initialization by the Host VMM" That is an overstatement and will be clarified in coming versions of the spec. In fact, as outlined in "Table 16.2: Non-ACT Platforms Checks on Memory" and "Table 16.3: Non-ACT Platforms Checks on Memory Reads in Li Mode" in the same spec, there is no issue accessing such reclaimed pages using a shared key that does not have integrity enabled. Linux always uses KeyID 0 which never has integrity enabled. KeyID 0 is also the TME KeyID which disallows integrity, refer "TME Policy/Encryption Algorithm" bit description in "Intel Architecture Memory Encryption Technologies" spec version 1.6 April 2025. So there is no need to clear pages to avoid integrity violations. There remains a risk of poison consumption. However, in the context of TDX, it is expected that there would be a machine check associated with the original poisoning. On some platforms that results in a panic. However platforms may support "SEAM_NR" Machine Check capability, in which case Linux machine check handler marks the page as poisoned, which prevents it from being allocated anymore, refer commit 7911f145de5fe ("x86/mce: Implement recovery for errors in TDX/SEAM non-root mode") Improvement By skipping the clearing step on unaffected platforms, shutdown time can improve by up to 40%. On platforms with the X86_BUG_TDX_PW_MCE erratum (SPR and EMR), continue clearing because these platforms may trigger poison on partial writes to previously-private pages, even with KeyID 0, refer commit 1e536e1068970 ("x86/cpu: Detect TDX partial write machine check erratum") Signed-off-by: Adrian Hunter Signed-off-by: Dave Hansen Reviewed-by: Kirill A. Shutemov Reviewed-by: Rick Edgecombe Reviewed-by: Xiaoyao Li Reviewed-by: Binbin Wu Acked-by: Kai Huang Acked-by: Vishal Annapurve Link: https://lore.kernel.org/all/20250819155811.136099-4-adrian.hunter%40intel.com --- arch/x86/virt/vmx/tdx/tdx.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 9e4638f68ba0..823850399bb7 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -633,15 +633,19 @@ err: } /* - * Convert TDX private pages back to normal by using MOVDIR64B to - * clear these pages. Note this function doesn't flush cache of - * these TDX private pages. The caller should make sure of that. + * Convert TDX private pages back to normal by using MOVDIR64B to clear these + * pages. Typically, any write to the page will convert it from TDX private back + * to normal kernel memory. Systems with the X86_BUG_TDX_PW_MCE erratum need to + * do the conversion explicitly via MOVDIR64B. */ static void tdx_quirk_reset_paddr(unsigned long base, unsigned long size) { const void *zero_page = (const void *)page_address(ZERO_PAGE(0)); unsigned long phys, end; + if (!boot_cpu_has_bug(X86_BUG_TDX_PW_MCE)) + return; + end = base + size; for (phys = base; phys < end; phys += 64) movdir64b(__va(phys), zero_page); From 86e6815b316ec0ea8c4bb3c16a033219a52b6060 Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Fri, 6 Jun 2025 13:10:35 -0400 Subject: [PATCH 0457/2711] x86/mm: Change cpa_flush() to call flush_kernel_range() directly The function cpa_flush() calls __flush_tlb_one_kernel() and flush_tlb_all(). Replacing that with a call to flush_tlb_kernel_range() allows cpa_flush() to make use of INVLPGB or RAR without any additional changes. Initialize invlpgb_count_max to 1, since flush_tlb_kernel_range() can now be called before invlpgb_count_max has been initialized to the value read from CPUID. [riel: remove now unused __cpa_flush_tlb] Signed-off-by: Yu-cheng Yu Signed-off-by: Rik van Riel Signed-off-by: Dave Hansen Acked-by: Dave Hansen Link: https://lore.kernel.org/all/20250606171112.4013261-4-riel%40surriel.com --- arch/x86/mm/pat/set_memory.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index 8834c76f91c9..d2d54b8c4dbb 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -399,15 +399,6 @@ static void cpa_flush_all(unsigned long cache) on_each_cpu(__cpa_flush_all, (void *) cache, 1); } -static void __cpa_flush_tlb(void *data) -{ - struct cpa_data *cpa = data; - unsigned int i; - - for (i = 0; i < cpa->numpages; i++) - flush_tlb_one_kernel(fix_addr(__cpa_addr(cpa, i))); -} - static int collapse_large_pages(unsigned long addr, struct list_head *pgtables); static void cpa_collapse_large_pages(struct cpa_data *cpa) @@ -444,6 +435,7 @@ static void cpa_collapse_large_pages(struct cpa_data *cpa) static void cpa_flush(struct cpa_data *cpa, int cache) { + unsigned long start, end; unsigned int i; BUG_ON(irqs_disabled() && !early_boot_irqs_disabled); @@ -453,10 +445,12 @@ static void cpa_flush(struct cpa_data *cpa, int cache) goto collapse_large_pages; } - if (cpa->force_flush_all || cpa->numpages > tlb_single_page_flush_ceiling) - flush_tlb_all(); - else - on_each_cpu(__cpa_flush_tlb, cpa, 1); + start = fix_addr(__cpa_addr(cpa, 0)); + end = fix_addr(__cpa_addr(cpa, cpa->numpages)); + if (cpa->force_flush_all) + end = TLB_FLUSH_ALL; + + flush_tlb_kernel_range(start, end); if (!cache) goto collapse_large_pages; From 966f504977e3a04fcadbaf199e3302e95e8958b7 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Mon, 16 Jun 2025 10:35:57 +0200 Subject: [PATCH 0458/2711] x86/asm: Use RDPKRU and WRPKRU mnemonics in Current minimum required version of binutils is 2.30, which supports RDPKRU and WRPKRU instruction mnemonics. Replace the byte-wise specification of RDPKRU and WRPKRU with these proper mnemonics. No functional change intended. Signed-off-by: Uros Bizjak Signed-off-by: Borislav Petkov (AMD) Acked-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/20250616083611.157740-1-ubizjak@gmail.com --- arch/x86/include/asm/special_insns.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h index fde2bd7af19e..c99914569352 100644 --- a/arch/x86/include/asm/special_insns.h +++ b/arch/x86/include/asm/special_insns.h @@ -75,9 +75,7 @@ static inline u32 rdpkru(void) * "rdpkru" instruction. Places PKRU contents in to EAX, * clears EDX and requires that ecx=0. */ - asm volatile(".byte 0x0f,0x01,0xee\n\t" - : "=a" (pkru), "=d" (edx) - : "c" (ecx)); + asm volatile("rdpkru" : "=a" (pkru), "=d" (edx) : "c" (ecx)); return pkru; } @@ -89,8 +87,7 @@ static inline void wrpkru(u32 pkru) * "wrpkru" instruction. Loads contents in EAX to PKRU, * requires that ecx = edx = 0. */ - asm volatile(".byte 0x0f,0x01,0xef\n\t" - : : "a" (pkru), "c"(ecx), "d"(edx)); + asm volatile("wrpkru" : : "a" (pkru), "c"(ecx), "d"(edx)); } #else From 045f6a6e4dbaa0ecdee43bc2362676ff62ba5456 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 1 Aug 2025 10:45:31 +0200 Subject: [PATCH 0459/2711] x86/mtrr: Remove license boilerplate text with bad FSF address The Free Software Foundation does not reside in "675 Mass Ave, Cambridge" anymore, so no need to mention that address in the source code here. But instead of updating the address to their current location, just drop the license boilerplate text and use a proper SPDX license identifier instead. The text talks about the "GNU *Library* General Public License" and "any later version", so LGPL-2.0+ is the right choice here. [ bp: Massage commit message. ] Signed-off-by: Thomas Huth Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/20250801084531.34089-1-thuth@redhat.com --- arch/x86/include/asm/mtrr.h | 15 +-------------- arch/x86/kernel/cpu/mtrr/cleanup.c | 15 +-------------- arch/x86/kernel/cpu/mtrr/mtrr.c | 15 +-------------- 3 files changed, 3 insertions(+), 42 deletions(-) diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index c69e269937c5..76b95bd1a405 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.0+ */ /* Generic MTRR (Memory Type Range Register) ioctls. Copyright (C) 1997-1999 Richard Gooch - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - Richard Gooch may be reached by email at rgooch@atnf.csiro.au The postal address is: Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c index 18cf79d6e2c5..763534d77f59 100644 --- a/arch/x86/kernel/cpu/mtrr/cleanup.c +++ b/arch/x86/kernel/cpu/mtrr/cleanup.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: LGPL-2.0+ /* * MTRR (Memory Type Range Register) cleanup * * Copyright (C) 2009 Yinghai Lu - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.c b/arch/x86/kernel/cpu/mtrr/mtrr.c index ecbda0341a8a..4b3d492afe17 100644 --- a/arch/x86/kernel/cpu/mtrr/mtrr.c +++ b/arch/x86/kernel/cpu/mtrr/mtrr.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: LGPL-2.0+ /* Generic MTRR (Memory Type Range Register) driver. Copyright (C) 1997-2000 Richard Gooch Copyright (c) 2002 Patrick Mochel - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - Richard Gooch may be reached by email at rgooch@atnf.csiro.au The postal address is: Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. From 290434474c332a2ba9c8499fe699c7f2e1153280 Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Sun, 6 Apr 2025 17:18:42 +0100 Subject: [PATCH 0460/2711] fs/9p: Refresh metadata in d_revalidate for uncached mode too Currently if another process keeps a file open, due to existing dentry in the dcache, other processes will not see updated metadata of that file if it is changed on the server, even in uncached mode. This can also manifest as -ENODATA when reading a file that has shrunk on the server (even if it's re-opened in another process), or -ENOTSUPP if the file has changed type (e.g. regular file to directory) on the server. We can end up in a situation where both `readdir` or `read` fails until the file is closed by all processes using it. This commit fixes that, and invalidates the dentry altogether if the inode type is changed (for uncached mode). Signed-off-by: Tingmao Wang Message-ID: Signed-off-by: Dominique Martinet --- fs/9p/vfs_dentry.c | 11 ++++++++++- fs/9p/vfs_inode.c | 8 +++++++- fs/9p/vfs_inode_dotl.c | 8 +++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 04795508a795..ffa45ee38f83 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -66,6 +66,7 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) struct p9_fid *fid; struct inode *inode; struct v9fs_inode *v9inode; + unsigned int cached; if (flags & LOOKUP_RCU) return -ECHILD; @@ -75,7 +76,11 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) goto out_valid; v9inode = V9FS_I(inode); - if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) { + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); + + cached = v9ses->cache & (CACHE_META | CACHE_LOOSE); + + if (!cached || v9inode->cache_validity & V9FS_INO_INVALID_ATTR) { int retval; struct v9fs_session_info *v9ses; @@ -92,6 +97,8 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) if (retval == -ENOENT) return 0; + if (!cached && v9inode->cache_validity & V9FS_INO_INVALID_ATTR) + return 0; if (retval < 0) return retval; } @@ -127,6 +134,8 @@ const struct dentry_operations v9fs_cached_dentry_operations = { }; const struct dentry_operations v9fs_dentry_operations = { + .d_revalidate = v9fs_lookup_revalidate, + .d_weak_revalidate = __v9fs_lookup_revalidate, .d_release = v9fs_dentry_release, .d_unalias_trylock = v9fs_dentry_unalias_trylock, .d_unalias_unlock = v9fs_dentry_unalias_unlock, diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 399d455d50d6..caff65d8b2bb 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1349,8 +1349,14 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) * Don't update inode if the file type is different */ umode = p9mode2unixmode(v9ses, st, &rdev); - if (inode_wrong_type(inode, umode)) + if (inode_wrong_type(inode, umode)) { + /* + * Do this as a way of letting the caller know the inode should not + * be reused + */ + v9fs_invalidate_inode_attr(inode); goto out; + } /* * We don't want to refresh inode->i_size, diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 5b5fda617b80..0fafc603b64a 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -902,8 +902,14 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode) /* * Don't update inode if the file type is different */ - if (inode_wrong_type(inode, st->st_mode)) + if (inode_wrong_type(inode, st->st_mode)) { + /* + * Do this as a way of letting the caller know the inode should not + * be reused + */ + v9fs_invalidate_inode_attr(inode); goto out; + } /* * We don't want to refresh inode->i_size, From 0172a934747f21d2fca4870ec84518c97f5178fc Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Sun, 6 Apr 2025 17:18:43 +0100 Subject: [PATCH 0461/2711] fs/9p: Invalidate dentry if inode type change detected in cached mode This is an extension of the last commit to cached mode as well. While server-side changes when using cached mode is not expected, when it does happen we can get things like -EOPNOTSUPP. With this change at least when we realize the inode has updated (for example after a `touch` on the client), we can get a new one. Signed-off-by: Tingmao Wang Message-ID: <01afd3c77d5cda181780dc931baa8f3fc54562c8.1743956147.git.m@maowtm.org> Signed-off-by: Dominique Martinet --- fs/9p/vfs_dentry.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index ffa45ee38f83..ddf7424b5850 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -97,7 +97,7 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) if (retval == -ENOENT) return 0; - if (!cached && v9inode->cache_validity & V9FS_INO_INVALID_ATTR) + if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) return 0; if (retval < 0) return retval; From c667c54c5875bf57641cd3bedc2cae66f2f08854 Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Sun, 6 Apr 2025 17:18:44 +0100 Subject: [PATCH 0462/2711] fs/9p: Add p9_debug(VFS) in d_revalidate This was a useful debugging / validation aid, and can explain why a GETATTR request is made. Signed-off-by: Tingmao Wang Message-ID: <00829a99549e33d26139fa4d756c466629f13e00.1743956147.git.m@maowtm.org> Signed-off-by: Dominique Martinet --- fs/9p/vfs_dentry.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index ddf7424b5850..f3248a3e5402 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -85,8 +85,13 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) struct v9fs_session_info *v9ses; fid = v9fs_fid_lookup(dentry); - if (IS_ERR(fid)) + if (IS_ERR(fid)) { + p9_debug( + P9_DEBUG_VFS, + "v9fs_fid_lookup: dentry = %pd (%p), got error %pe\n", + dentry, dentry, fid); return PTR_ERR(fid); + } v9ses = v9fs_inode2v9ses(inode); if (v9fs_proto_dotl(v9ses)) @@ -95,14 +100,25 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) retval = v9fs_refresh_inode(fid, inode); p9_fid_put(fid); - if (retval == -ENOENT) + if (retval == -ENOENT) { + p9_debug(P9_DEBUG_VFS, "dentry: %pd (%p) invalidated due to ENOENT\n", + dentry, dentry); return 0; - if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) + } + if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) { + p9_debug(P9_DEBUG_VFS, "dentry: %pd (%p) invalidated due to type change\n", + dentry, dentry); return 0; - if (retval < 0) + } + if (retval < 0) { + p9_debug(P9_DEBUG_VFS, + "refresh inode: dentry = %pd (%p), got error %pe\n", + dentry, dentry, ERR_PTR(retval)); return retval; + } } out_valid: + p9_debug(P9_DEBUG_VFS, "dentry: %pd (%p) is valid\n", dentry, dentry); return 1; } From c04db81cd0288dfc68b7a0f7d09bd49b40bba451 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Sun, 22 Jun 2025 22:39:56 +0900 Subject: [PATCH 0463/2711] net/9p: Fix buffer overflow in USB transport layer A buffer overflow vulnerability exists in the USB 9pfs transport layer where inconsistent size validation between packet header parsing and actual data copying allows a malicious USB host to overflow heap buffers. The issue occurs because: - usb9pfs_rx_header() validates only the declared size in packet header - usb9pfs_rx_complete() uses req->actual (actual received bytes) for memcpy This allows an attacker to craft packets with small declared size (bypassing validation) but large actual payload (triggering overflow in memcpy). Add validation in usb9pfs_rx_complete() to ensure req->actual does not exceed the buffer capacity before copying data. Reported-by: Yuhao Jiang Closes: https://lkml.kernel.org/r/20250616132539.63434-1-danisjiang@gmail.com Fixes: a3be076dc174 ("net/9p/usbg: Add new usb gadget function transport") Cc: stable@vger.kernel.org Message-ID: <20250622-9p-usb_overflow-v3-1-ab172691b946@codewreck.org> Signed-off-by: Dominique Martinet --- net/9p/trans_usbg.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/net/9p/trans_usbg.c b/net/9p/trans_usbg.c index 6b694f117aef..468f7e8f0277 100644 --- a/net/9p/trans_usbg.c +++ b/net/9p/trans_usbg.c @@ -231,6 +231,8 @@ static void usb9pfs_rx_complete(struct usb_ep *ep, struct usb_request *req) struct f_usb9pfs *usb9pfs = ep->driver_data; struct usb_composite_dev *cdev = usb9pfs->function.config->cdev; struct p9_req_t *p9_rx_req; + unsigned int req_size = req->actual; + int status = REQ_STATUS_RCVD; if (req->status) { dev_err(&cdev->gadget->dev, "%s usb9pfs complete --> %d, %d/%d\n", @@ -242,11 +244,19 @@ static void usb9pfs_rx_complete(struct usb_ep *ep, struct usb_request *req) if (!p9_rx_req) return; - memcpy(p9_rx_req->rc.sdata, req->buf, req->actual); + if (req_size > p9_rx_req->rc.capacity) { + dev_err(&cdev->gadget->dev, + "%s received data size %u exceeds buffer capacity %zu\n", + ep->name, req_size, p9_rx_req->rc.capacity); + req_size = 0; + status = REQ_STATUS_ERROR; + } - p9_rx_req->rc.size = req->actual; + memcpy(p9_rx_req->rc.sdata, req->buf, req_size); - p9_client_cb(usb9pfs->client, p9_rx_req, REQ_STATUS_RCVD); + p9_rx_req->rc.size = req_size; + + p9_client_cb(usb9pfs->client, p9_rx_req, status); p9_req_put(usb9pfs->client, p9_rx_req); complete(&usb9pfs->received); From 674b56aa57f9379854cb6798c3bbcef7e7b51ab7 Mon Sep 17 00:00:00 2001 From: Nalivayko Sergey Date: Tue, 15 Jul 2025 18:48:15 +0300 Subject: [PATCH 0464/2711] net/9p: fix double req put in p9_fd_cancelled Syzkaller reports a KASAN issue as below: general protection fault, probably for non-canonical address 0xfbd59c0000000021: 0000 [#1] PREEMPT SMP KASAN NOPTI KASAN: maybe wild-memory-access in range [0xdead000000000108-0xdead00000000010f] CPU: 0 PID: 5083 Comm: syz-executor.2 Not tainted 6.1.134-syzkaller-00037-g855bd1d7d838 #0 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 RIP: 0010:__list_del include/linux/list.h:114 [inline] RIP: 0010:__list_del_entry include/linux/list.h:137 [inline] RIP: 0010:list_del include/linux/list.h:148 [inline] RIP: 0010:p9_fd_cancelled+0xe9/0x200 net/9p/trans_fd.c:734 Call Trace: p9_client_flush+0x351/0x440 net/9p/client.c:614 p9_client_rpc+0xb6b/0xc70 net/9p/client.c:734 p9_client_version net/9p/client.c:920 [inline] p9_client_create+0xb51/0x1240 net/9p/client.c:1027 v9fs_session_init+0x1f0/0x18f0 fs/9p/v9fs.c:408 v9fs_mount+0xba/0xcb0 fs/9p/vfs_super.c:126 legacy_get_tree+0x108/0x220 fs/fs_context.c:632 vfs_get_tree+0x8e/0x300 fs/super.c:1573 do_new_mount fs/namespace.c:3056 [inline] path_mount+0x6a6/0x1e90 fs/namespace.c:3386 do_mount fs/namespace.c:3399 [inline] __do_sys_mount fs/namespace.c:3607 [inline] __se_sys_mount fs/namespace.c:3584 [inline] __x64_sys_mount+0x283/0x300 fs/namespace.c:3584 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x35/0x80 arch/x86/entry/common.c:81 entry_SYSCALL_64_after_hwframe+0x6e/0xd8 This happens because of a race condition between: - The 9p client sending an invalid flush request and later cleaning it up; - The 9p client in p9_read_work() canceled all pending requests. Thread 1 Thread 2 ... p9_client_create() ... p9_fd_create() ... p9_conn_create() ... // start Thread 2 INIT_WORK(&m->rq, p9_read_work); p9_read_work() ... p9_client_rpc() ... ... p9_conn_cancel() ... spin_lock(&m->req_lock); ... p9_fd_cancelled() ... ... spin_unlock(&m->req_lock); // status rewrite p9_client_cb(m->client, req, REQ_STATUS_ERROR) // first remove list_del(&req->req_list); ... spin_lock(&m->req_lock) ... // second remove list_del(&req->req_list); spin_unlock(&m->req_lock) ... Commit 74d6a5d56629 ("9p/trans_fd: Fix concurrency del of req_list in p9_fd_cancelled/p9_read_work") fixes a concurrency issue in the 9p filesystem client where the req_list could be deleted simultaneously by both p9_read_work and p9_fd_cancelled functions, but for the case where req->status equals REQ_STATUS_RCVD. Update the check for req->status in p9_fd_cancelled to skip processing not just received requests, but anything that is not SENT, as whatever changed the state from SENT also removed the request from its list. Found by Linux Verification Center (linuxtesting.org) with Syzkaller. Fixes: afd8d6541155 ("9P: Add cancelled() to the transport functions.") Cc: stable@vger.kernel.org Signed-off-by: Nalivayko Sergey Message-ID: <20250715154815.3501030-1-Sergey.Nalivayko@kaspersky.com> [updated the check from status == RECV || status == ERROR to status != SENT] Signed-off-by: Dominique Martinet --- net/9p/trans_fd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 339ec4e54778..8992d8bebbdd 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -726,10 +726,10 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req) p9_debug(P9_DEBUG_TRANS, "client %p req %p\n", client, req); spin_lock(&m->req_lock); - /* Ignore cancelled request if message has been received - * before lock. - */ - if (req->status == REQ_STATUS_RCVD) { + /* Ignore cancelled request if status changed since the request was + * processed in p9_client_flush() + */ + if (req->status != REQ_STATUS_SENT) { spin_unlock(&m->req_lock); return 0; } From 05c58c9415d1369387aedd28518fd0fdaeabd178 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:30 -0400 Subject: [PATCH 0465/2711] clk: samsung: cpu: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Link: https://lore.kernel.org/r/20250811-clk-for-stephen-round-rate-v1-98-b3bf97b038dc@redhat.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-cpu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c index 4e1ebd8a30b1..300f8d5d3c48 100644 --- a/drivers/clk/samsung/clk-cpu.c +++ b/drivers/clk/samsung/clk-cpu.c @@ -567,12 +567,14 @@ static int exynos850_cpuclk_post_rate_change(struct clk_notifier_data *ndata, /* -------------------------------------------------------------------------- */ /* Common round rate callback usable for all types of CPU clocks */ -static long exynos_cpuclk_round_rate(struct clk_hw *hw, unsigned long drate, - unsigned long *prate) +static int exynos_cpuclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_hw *parent = clk_hw_get_parent(hw); - *prate = clk_hw_round_rate(parent, drate); - return *prate; + req->best_parent_rate = clk_hw_round_rate(parent, req->rate); + req->rate = req->best_parent_rate; + + return 0; } /* Common recalc rate callback usable for all types of CPU clocks */ @@ -591,7 +593,7 @@ static unsigned long exynos_cpuclk_recalc_rate(struct clk_hw *hw, static const struct clk_ops exynos_cpuclk_clk_ops = { .recalc_rate = exynos_cpuclk_recalc_rate, - .round_rate = exynos_cpuclk_round_rate, + .determine_rate = exynos_cpuclk_determine_rate, }; /* From e278e39b014d789fb670695d422ff33c3ef56040 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:31 -0400 Subject: [PATCH 0466/2711] clk: samsung: pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Link: https://lore.kernel.org/r/20250811-clk-for-stephen-round-rate-v1-99-b3bf97b038dc@redhat.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-pll.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index e4faf02b631e..3c04a0388ff9 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -49,8 +49,8 @@ static const struct samsung_pll_rate_table *samsung_get_pll_settings( return NULL; } -static long samsung_pll_round_rate(struct clk_hw *hw, - unsigned long drate, unsigned long *prate) +static int samsung_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct samsung_clk_pll *pll = to_clk_pll(hw); const struct samsung_pll_rate_table *rate_table = pll->rate_table; @@ -58,12 +58,17 @@ static long samsung_pll_round_rate(struct clk_hw *hw, /* Assuming rate_table is in descending order */ for (i = 0; i < pll->rate_count; i++) { - if (drate >= rate_table[i].rate) - return rate_table[i].rate; + if (req->rate >= rate_table[i].rate) { + req->rate = rate_table[i].rate; + + return 0; + } } /* return minimum supported value */ - return rate_table[i - 1].rate; + req->rate = rate_table[i - 1].rate; + + return 0; } static bool pll_early_timeout = true; @@ -298,7 +303,7 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll35xx_clk_ops = { .recalc_rate = samsung_pll35xx_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll35xx_set_rate, .enable = samsung_pll3xxx_enable, .disable = samsung_pll3xxx_disable, @@ -411,7 +416,7 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll36xx_clk_ops = { .recalc_rate = samsung_pll36xx_recalc_rate, .set_rate = samsung_pll36xx_set_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .enable = samsung_pll3xxx_enable, .disable = samsung_pll3xxx_disable, }; @@ -514,7 +519,7 @@ static int samsung_pll0822x_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll0822x_clk_ops = { .recalc_rate = samsung_pll0822x_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll0822x_set_rate, .enable = samsung_pll3xxx_enable, .disable = samsung_pll3xxx_disable, @@ -612,7 +617,7 @@ static int samsung_pll0831x_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll0831x_clk_ops = { .recalc_rate = samsung_pll0831x_recalc_rate, .set_rate = samsung_pll0831x_set_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .enable = samsung_pll3xxx_enable, .disable = samsung_pll3xxx_disable, }; @@ -735,7 +740,7 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll45xx_clk_ops = { .recalc_rate = samsung_pll45xx_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll45xx_set_rate, }; @@ -880,7 +885,7 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll46xx_clk_ops = { .recalc_rate = samsung_pll46xx_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll46xx_set_rate, }; @@ -1093,7 +1098,7 @@ static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll2550xx_clk_ops = { .recalc_rate = samsung_pll2550xx_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll2550xx_set_rate, }; @@ -1185,7 +1190,7 @@ static int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll2650x_clk_ops = { .recalc_rate = samsung_pll2650x_recalc_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, .set_rate = samsung_pll2650x_set_rate, }; @@ -1277,7 +1282,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops samsung_pll2650xx_clk_ops = { .recalc_rate = samsung_pll2650xx_recalc_rate, .set_rate = samsung_pll2650xx_set_rate, - .round_rate = samsung_pll_round_rate, + .determine_rate = samsung_pll_determine_rate, }; static const struct clk_ops samsung_pll2650xx_clk_min_ops = { From ab6d91d141a801dadf9eed7860b2ea09c9268149 Mon Sep 17 00:00:00 2001 From: Nickolay Goppen Date: Fri, 15 Aug 2025 19:56:51 +0300 Subject: [PATCH 0467/2711] dt-bindings: clock: gcc-sdm660: Add LPASS/CDSP vote clocks/GDSCs Add defines for the missing clocks, which are required to power up the related remote processors. Co-developed-by: Konrad Dybcio Signed-off-by: Konrad Dybcio Signed-off-by: Nickolay Goppen Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250815-gcc-sdm660-vote-clocks-and-gdscs-v1-1-c5a8af040093@yandex.ru Signed-off-by: Bjorn Andersson --- include/dt-bindings/clock/qcom,gcc-sdm660.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/dt-bindings/clock/qcom,gcc-sdm660.h b/include/dt-bindings/clock/qcom,gcc-sdm660.h index 74c22f67da21..f19018b742f5 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm660.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm660.h @@ -138,10 +138,16 @@ #define GCC_UFS_UNIPRO_CORE_HW_CTL_CLK 128 #define GCC_RX0_USB2_CLKREF_CLK 129 #define GCC_RX1_USB2_CLKREF_CLK 130 +#define GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK 131 +#define GCC_HLOS1_VOTE_TURING_ADSP_SMMU_CLK 132 +#define GCC_HLOS2_VOTE_TURING_ADSP_SMMU_CLK 133 #define PCIE_0_GDSC 0 #define UFS_GDSC 1 #define USB_30_GDSC 2 +#define HLOS1_VOTE_TURING_ADSP_GDSC 3 +#define HLOS2_VOTE_TURING_ADSP_GDSC 4 +#define HLOS1_VOTE_LPASS_ADSP_GDSC 5 #define GCC_QUSB2PHY_PRIM_BCR 0 #define GCC_QUSB2PHY_SEC_BCR 1 From d9f1c08cf2648184c58eb57159232b5f0b818bbf Mon Sep 17 00:00:00 2001 From: Nickolay Goppen Date: Fri, 15 Aug 2025 19:56:52 +0300 Subject: [PATCH 0468/2711] clk: qcom: gcc-sdm660: Add missing LPASS/CDSP vote clocks For the proper functioning of SMMUs related to the audio/compute DSPs, it makes sense that the clocks and power domains they rely on for communication should be online. Add the vote clocks & GDSCs that, when enabled, ensure all such requirements are met, through various internal mechanisms. Co-developed-by: Konrad Dybcio Signed-off-by: Konrad Dybcio Signed-off-by: Nickolay Goppen Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250815-gcc-sdm660-vote-clocks-and-gdscs-v1-2-c5a8af040093@yandex.ru Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-sdm660.c | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c index 01a76f1b5b4c..20253a06a583 100644 --- a/drivers/clk/qcom/gcc-sdm660.c +++ b/drivers/clk/qcom/gcc-sdm660.c @@ -2247,6 +2247,45 @@ static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = { }, }; +static struct clk_branch hlos1_vote_lpass_adsp_smmu_clk = { + .halt_reg = 0x7d014, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x7d014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "hlos1_vote_lpass_adsp_smmu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch hlos1_vote_turing_adsp_smmu_clk = { + .halt_reg = 0x7d048, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x7d048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "hlos1_vote_turing_adsp_smmu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch hlos2_vote_turing_adsp_smmu_clk = { + .halt_reg = 0x7e048, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x7e048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "hlos2_vote_turing_adsp_smmu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct gdsc ufs_gdsc = { .gdscr = 0x75004, .gds_hw_ctrl = 0x0, @@ -2277,6 +2316,33 @@ static struct gdsc pcie_0_gdsc = { .flags = VOTABLE, }; +static struct gdsc hlos1_vote_turing_adsp_gdsc = { + .gdscr = 0x7d04c, + .pd = { + .name = "hlos1_vote_turing_adsp_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos2_vote_turing_adsp_gdsc = { + .gdscr = 0x7e04c, + .pd = { + .name = "hlos2_vote_turing_adsp_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_lpass_adsp_gdsc = { + .gdscr = 0x7d034, + .pd = { + .name = "hlos1_vote_lpass_adsp_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + static struct clk_hw *gcc_sdm660_hws[] = { &xo.hw, &gpll0_early_div.hw, @@ -2409,12 +2475,18 @@ static struct clk_regmap *gcc_sdm660_clocks[] = { [USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr, [USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr, [USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr, + [GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK] = &hlos1_vote_lpass_adsp_smmu_clk.clkr, + [GCC_HLOS1_VOTE_TURING_ADSP_SMMU_CLK] = &hlos1_vote_turing_adsp_smmu_clk.clkr, + [GCC_HLOS2_VOTE_TURING_ADSP_SMMU_CLK] = &hlos2_vote_turing_adsp_smmu_clk.clkr, }; static struct gdsc *gcc_sdm660_gdscs[] = { [UFS_GDSC] = &ufs_gdsc, [USB_30_GDSC] = &usb_30_gdsc, [PCIE_0_GDSC] = &pcie_0_gdsc, + [HLOS1_VOTE_TURING_ADSP_GDSC] = &hlos1_vote_turing_adsp_gdsc, + [HLOS2_VOTE_TURING_ADSP_GDSC] = &hlos2_vote_turing_adsp_gdsc, + [HLOS1_VOTE_LPASS_ADSP_GDSC] = &hlos1_vote_lpass_adsp_gdsc, }; static const struct qcom_reset_map gcc_sdm660_resets[] = { From 7d50d9bf1cd00d6bab0abf3b01d5d261aa6a2b04 Mon Sep 17 00:00:00 2001 From: Troy Mitchell Date: Mon, 11 Aug 2025 21:40:33 +0800 Subject: [PATCH 0469/2711] dt-bindings: clock: spacemit: CLK_SSPA_I2S_BCLK for SSPA In order to use the virtual clock SSPAx_I2S_BCLK in the device tree and register it in the driver, this patch introduces the macro definition. Fixes: 1b72c59db0add ("clk: spacemit: Add clock support for SpacemiT K1 SoC") Acked-by: Rob Herring (Arm) Signed-off-by: Troy Mitchell Link: https://lore.kernel.org/r/20250811-k1-clk-i2s-v5-1-ebadd06e1e91@linux.spacemit.com Signed-off-by: Yixun Lan --- include/dt-bindings/clock/spacemit,k1-syscon.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dt-bindings/clock/spacemit,k1-syscon.h b/include/dt-bindings/clock/spacemit,k1-syscon.h index 2714c3fe66cd..505205453d7f 100644 --- a/include/dt-bindings/clock/spacemit,k1-syscon.h +++ b/include/dt-bindings/clock/spacemit,k1-syscon.h @@ -182,6 +182,8 @@ #define CLK_SSPA1_BUS 97 #define CLK_TSEN_BUS 98 #define CLK_IPC_AP2AUD_BUS 99 +#define CLK_SSPA0_I2S_BCLK 100 +#define CLK_SSPA1_I2S_BCLK 101 /* APBC resets */ #define RESET_UART0 0 From c536e00d58dc8db3e1e430a8e6830bc22d2a38e3 Mon Sep 17 00:00:00 2001 From: Troy Mitchell Date: Mon, 11 Aug 2025 21:40:34 +0800 Subject: [PATCH 0470/2711] clk: spacemit: fix sspax_clk Hardware Requirement: BIT[3] of this register must be set if need to select i2s_bclk as SSPA parent clock, to solve this, introduces a new SSPAx_I2S_BCLK clock as the virtual gate clock. Fixes: 1b72c59db0add ("clk: spacemit: Add clock support for SpacemiT K1 SoC") Suggested-by: Yao Zi Reviewed-by: Haylen Chu Signed-off-by: Troy Mitchell Link: https://lore.kernel.org/r/20250811-k1-clk-i2s-v5-2-ebadd06e1e91@linux.spacemit.com Signed-off-by: Yixun Lan --- drivers/clk/spacemit/ccu-k1.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/clk/spacemit/ccu-k1.c b/drivers/clk/spacemit/ccu-k1.c index 65e6de030717..62cdba516a29 100644 --- a/drivers/clk/spacemit/ccu-k1.c +++ b/drivers/clk/spacemit/ccu-k1.c @@ -247,7 +247,14 @@ CCU_GATE_DEFINE(aib_clk, CCU_PARENT_NAME(vctcxo_24m), APBC_AIB_CLK_RST, BIT(1), CCU_GATE_DEFINE(onewire_clk, CCU_PARENT_NAME(vctcxo_24m), APBC_ONEWIRE_CLK_RST, BIT(1), 0); -static const struct clk_parent_data sspa_parents[] = { +/* + * When i2s_bclk is selected as the parent clock of sspa, + * the hardware requires bit3 to be set + */ +CCU_GATE_DEFINE(sspa0_i2s_bclk, CCU_PARENT_HW(i2s_bclk), APBC_SSPA0_CLK_RST, BIT(3), 0); +CCU_GATE_DEFINE(sspa1_i2s_bclk, CCU_PARENT_HW(i2s_bclk), APBC_SSPA1_CLK_RST, BIT(3), 0); + +static const struct clk_parent_data sspa0_parents[] = { CCU_PARENT_HW(pll1_d384_6p4), CCU_PARENT_HW(pll1_d192_12p8), CCU_PARENT_HW(pll1_d96_25p6), @@ -255,10 +262,22 @@ static const struct clk_parent_data sspa_parents[] = { CCU_PARENT_HW(pll1_d768_3p2), CCU_PARENT_HW(pll1_d1536_1p6), CCU_PARENT_HW(pll1_d3072_0p8), - CCU_PARENT_HW(i2s_bclk), + CCU_PARENT_HW(sspa0_i2s_bclk), }; -CCU_MUX_GATE_DEFINE(sspa0_clk, sspa_parents, APBC_SSPA0_CLK_RST, 4, 3, BIT(1), 0); -CCU_MUX_GATE_DEFINE(sspa1_clk, sspa_parents, APBC_SSPA1_CLK_RST, 4, 3, BIT(1), 0); +CCU_MUX_GATE_DEFINE(sspa0_clk, sspa0_parents, APBC_SSPA0_CLK_RST, 4, 3, BIT(1), 0); + +static const struct clk_parent_data sspa1_parents[] = { + CCU_PARENT_HW(pll1_d384_6p4), + CCU_PARENT_HW(pll1_d192_12p8), + CCU_PARENT_HW(pll1_d96_25p6), + CCU_PARENT_HW(pll1_d48_51p2), + CCU_PARENT_HW(pll1_d768_3p2), + CCU_PARENT_HW(pll1_d1536_1p6), + CCU_PARENT_HW(pll1_d3072_0p8), + CCU_PARENT_HW(sspa1_i2s_bclk), +}; +CCU_MUX_GATE_DEFINE(sspa1_clk, sspa1_parents, APBC_SSPA1_CLK_RST, 4, 3, BIT(1), 0); + CCU_GATE_DEFINE(dro_clk, CCU_PARENT_HW(apb_clk), APBC_DRO_CLK_RST, BIT(1), 0); CCU_GATE_DEFINE(ir_clk, CCU_PARENT_HW(apb_clk), APBC_IR_CLK_RST, BIT(1), 0); CCU_GATE_DEFINE(tsen_clk, CCU_PARENT_HW(apb_clk), APBC_TSEN_CLK_RST, BIT(1), 0); @@ -865,6 +884,8 @@ static struct clk_hw *k1_ccu_apbc_hws[] = { [CLK_SSPA1_BUS] = &sspa1_bus_clk.common.hw, [CLK_TSEN_BUS] = &tsen_bus_clk.common.hw, [CLK_IPC_AP2AUD_BUS] = &ipc_ap2aud_bus_clk.common.hw, + [CLK_SSPA0_I2S_BCLK] = &sspa0_i2s_bclk.common.hw, + [CLK_SSPA1_I2S_BCLK] = &sspa1_i2s_bclk.common.hw, }; static const struct spacemit_ccu_data k1_ccu_apbc_data = { From 36ee9770a8b24c71805760cb160c25ef91192823 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Sun, 15 Jun 2025 23:27:47 +0900 Subject: [PATCH 0471/2711] counter: Alphabetize component_id sysfs attributes Documentation list Prefer alphabetical order for the component_id sysfs attributes list in the Counter ABI Documentation file. This should make it easier for users to locate a component_id attribute in the list and its respective Documentation entry. Suggested-by: David Lechner Link: https://lore.kernel.org/r/20250615-alphabetize-component_id-doc-v1-1-4c5943b41198@kernel.org Signed-off-by: William Breathitt Gray --- Documentation/ABI/testing/sysfs-bus-counter | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-counter b/Documentation/ABI/testing/sysfs-bus-counter index 3e8259e56d38..3e7eddd8aff3 100644 --- a/Documentation/ABI/testing/sysfs-bus-counter +++ b/Documentation/ABI/testing/sysfs-bus-counter @@ -309,26 +309,26 @@ Description: What: /sys/bus/counter/devices/counterX/cascade_counts_enable_component_id What: /sys/bus/counter/devices/counterX/external_input_phase_clock_select_component_id -What: /sys/bus/counter/devices/counterX/countY/compare_component_id What: /sys/bus/counter/devices/counterX/countY/capture_component_id What: /sys/bus/counter/devices/counterX/countY/ceiling_component_id -What: /sys/bus/counter/devices/counterX/countY/floor_component_id +What: /sys/bus/counter/devices/counterX/countY/compare_component_id What: /sys/bus/counter/devices/counterX/countY/count_mode_component_id What: /sys/bus/counter/devices/counterX/countY/direction_component_id What: /sys/bus/counter/devices/counterX/countY/enable_component_id What: /sys/bus/counter/devices/counterX/countY/error_noise_component_id +What: /sys/bus/counter/devices/counterX/countY/floor_component_id +What: /sys/bus/counter/devices/counterX/countY/num_overflows_component_id What: /sys/bus/counter/devices/counterX/countY/prescaler_component_id What: /sys/bus/counter/devices/counterX/countY/preset_component_id What: /sys/bus/counter/devices/counterX/countY/preset_enable_component_id What: /sys/bus/counter/devices/counterX/countY/signalZ_action_component_id -What: /sys/bus/counter/devices/counterX/countY/num_overflows_component_id What: /sys/bus/counter/devices/counterX/signalY/cable_fault_component_id What: /sys/bus/counter/devices/counterX/signalY/cable_fault_enable_component_id What: /sys/bus/counter/devices/counterX/signalY/filter_clock_prescaler_component_id +What: /sys/bus/counter/devices/counterX/signalY/frequency_component_id What: /sys/bus/counter/devices/counterX/signalY/index_polarity_component_id What: /sys/bus/counter/devices/counterX/signalY/polarity_component_id What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode_component_id -What: /sys/bus/counter/devices/counterX/signalY/frequency_component_id KernelVersion: 5.16 Contact: linux-iio@vger.kernel.org Description: From 51548c36b37d0e84bd43a5f20bcbc36f70e61c5a Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Thu, 7 Aug 2025 15:21:08 +0200 Subject: [PATCH 0472/2711] counter: ti-ecap-capture: Use devm_pm_runtime_enable() There is no need to register a manual `devm` action for `pm_runtime_disable()` when `devm_pm_runtime_enable()` exists. It does the same thing (but also calls `pm_runtime_dont_use_autosuspend()`, which should be fine here). Moreover, when `devm_add_action_or_reset()` fails, it is due to a failed memory allocation and will thus return `-ENOMEM`. `dev_err_probe()` doesn't do anything when error is `-ENOMEM`. Therefore, the call to `dev_err_probe()` is useless. Note that `devm_pm_runtime_enable()` has a tail call to `devm_add_action_or_reset()` and thus returns that value. Therefore, replace `dev_err_probe()` with the returning value. Signed-off-by: Waqar Hameed Acked-by: Andrew Davis Link: https://lore.kernel.org/r/pnda54bjmij.a.out@axis.com Signed-off-by: William Breathitt Gray --- drivers/counter/ti-ecap-capture.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/counter/ti-ecap-capture.c b/drivers/counter/ti-ecap-capture.c index 3faaf7f60539..3586a7ab9887 100644 --- a/drivers/counter/ti-ecap-capture.c +++ b/drivers/counter/ti-ecap-capture.c @@ -465,11 +465,6 @@ static irqreturn_t ecap_cnt_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static void ecap_cnt_pm_disable(void *dev) -{ - pm_runtime_disable(dev); -} - static int ecap_cnt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -523,12 +518,9 @@ static int ecap_cnt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, counter_dev); - pm_runtime_enable(dev); - - /* Register a cleanup callback to care for disabling PM */ - ret = devm_add_action_or_reset(dev, ecap_cnt_pm_disable, dev); + ret = devm_pm_runtime_enable(dev); if (ret) - return dev_err_probe(dev, ret, "failed to add pm disable action\n"); + return ret; ret = devm_counter_add(dev, counter_dev); if (ret) From d20a8a8ecdb7c3807bdd738338930f0796678cd4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 19 Aug 2025 18:02:53 +0300 Subject: [PATCH 0473/2711] iio: proximity: vl53l0x-i2c: Fix error code in probe() Commit 65e8202f0322 ("iio: Remove error prints for devm_add_action_or_reset()") accidentally introduced a bug where we returned "ret" but the error code was stored in "error" if devm_add_action_or_reset() failed. Using two variables to store error codes is unnecessary and confusing. Delete the "error" variable and use "ret" everywhere instead. Fixes: 65e8202f0322 ("iio: Remove error prints for devm_add_action_or_reset()") Signed-off-by: Dan Carpenter Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/aKSSHTdJf5QoYiRx@stanley.mountain Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/vl53l0x-i2c.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index 696340ec027a..ad3e46d47fa8 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -311,7 +311,6 @@ static int vl53l0x_probe(struct i2c_client *client) { struct vl53l0x_data *data; struct iio_dev *indio_dev; - int error; int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); @@ -344,13 +343,13 @@ static int vl53l0x_probe(struct i2c_client *client) return dev_err_probe(&client->dev, PTR_ERR(data->reset_gpio), "Cannot get reset GPIO\n"); - error = vl53l0x_power_on(data); - if (error) - return dev_err_probe(&client->dev, error, + ret = vl53l0x_power_on(data); + if (ret) + return dev_err_probe(&client->dev, ret, "Failed to power on the chip\n"); - error = devm_add_action_or_reset(&client->dev, vl53l0x_power_off, data); - if (error) + ret = devm_add_action_or_reset(&client->dev, vl53l0x_power_off, data); + if (ret) return ret; indio_dev->name = "vl53l0x"; From 086e410063be831d2a5622aa313b459122b02942 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Tue, 19 Aug 2025 16:00:53 +0100 Subject: [PATCH 0474/2711] staging: iio: adc: ad7816: Drop unnecessary dev_set_drvdata() call Remove the call to `dev_set_drvdata()` and the associated comment since private data is never read. Signed-off-by: Salah Triki Reviewed-by: David Lechner Link: https://patch.msgid.link/aKSRpTuwA0P-ZaUS@pc Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7816.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index 4774df778de9..172acf135f3b 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -359,8 +359,6 @@ static int ad7816_probe(struct spi_device *spi_dev) if (!indio_dev) return -ENOMEM; chip = iio_priv(indio_dev); - /* this is only used for device removal purposes */ - dev_set_drvdata(&spi_dev->dev, indio_dev); chip->spi_dev = spi_dev; for (i = 0; i <= AD7816_CS_MAX; i++) From 3f33d1530c2c9576b57ecd220bfa7e527184a80b Mon Sep 17 00:00:00 2001 From: Salih Erim Date: Wed, 20 Aug 2025 11:05:19 +0100 Subject: [PATCH 0475/2711] MAINTAINERS: Update xilinx-ams driver maintainers Anand left AMD/Xilinx some time ago. Salih and Connall are new maintainers of xilinx-ams driver. Signed-off-by: Salih Erim Acked-by: Rob Herring (Arm) Acked-by: Michal Simek Acked-by: O'Griofa, Conall Link: https://patch.msgid.link/20250820100519.2272509-1-salih.erim@amd.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml | 3 ++- MAINTAINERS | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml b/Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml index a403392fb263..3ae1a0bab38f 100644 --- a/Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml +++ b/Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml @@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Xilinx Zynq Ultrascale AMS controller maintainers: - - Anand Ashok Dumbre + - Salih Erim + - Conall O'Griofa description: | The AMS (Analog Monitoring System) includes an ADC as well as on-chip sensors diff --git a/MAINTAINERS b/MAINTAINERS index 76cba707a2c9..af1c8d2bfb3d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27550,7 +27550,8 @@ F: include/uapi/linux/dqblk_xfs.h F: include/uapi/linux/fsmap.h XILINX AMS DRIVER -M: Anand Ashok Dumbre +M: Salih Erim +M: Conall O'Griofa L: linux-iio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/iio/adc/xlnx,zynqmp-ams.yaml From 666a22bb31e48ec467b77ec61fe1630a18ea0c2d Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Thu, 21 Aug 2025 16:06:45 +0800 Subject: [PATCH 0476/2711] iio: accel: msa311: Remove dev_err_probe() if error is -ENOMEM The dev_err_probe() doesn't do anything when the error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250821080723.525379-2-zhao.xichao@vivo.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/msa311.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index 2ccb22317bdc..cded0b3a8559 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -990,7 +990,7 @@ static int msa311_check_partid(struct msa311_priv *msa311) msa311->chip_name = devm_kasprintf(dev, GFP_KERNEL, "msa311-%02x", partid); if (!msa311->chip_name) - return dev_err_probe(dev, -ENOMEM, "can't alloc chip name\n"); + return -ENOMEM; return 0; } @@ -1069,8 +1069,7 @@ static int msa311_setup_interrupts(struct msa311_priv *msa311) trig = devm_iio_trigger_alloc(dev, "%s-new-data", msa311->chip_name); if (!trig) - return dev_err_probe(dev, -ENOMEM, - "can't allocate newdata trigger\n"); + return -ENOMEM; msa311->new_data_trig = trig; msa311->new_data_trig->ops = &msa311_new_data_trig_ops; @@ -1153,8 +1152,7 @@ static int msa311_probe(struct i2c_client *i2c) indio_dev = devm_iio_device_alloc(dev, sizeof(*msa311)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, - "IIO device allocation failed\n"); + return -ENOMEM; msa311 = iio_priv(indio_dev); msa311->dev = dev; From 3a4cdd1155de2c7d90a35d67b779774045e4cbb1 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Thu, 21 Aug 2025 16:06:46 +0800 Subject: [PATCH 0477/2711] iio: adc: Remove dev_err_probe() if error is -ENOMEM The dev_err_probe() doesn't do anything when the error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Reviewed-by: Martin Blumenstingl # meson_saradc Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250821080723.525379-3-zhao.xichao@vivo.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hx711.c | 2 +- drivers/iio/adc/imx93_adc.c | 3 +-- drivers/iio/adc/mcp3564.c | 2 +- drivers/iio/adc/meson_saradc.c | 2 +- drivers/iio/adc/rockchip_saradc.c | 3 +-- drivers/iio/adc/spear_adc.c | 3 +-- drivers/iio/adc/ti-ads1119.c | 6 ++---- drivers/iio/adc/ti-ads7924.c | 3 +-- drivers/iio/adc/vf610_adc.c | 2 +- 9 files changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index 7235fa9e13d5..1db8b68a8f64 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -465,7 +465,7 @@ static int hx711_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx711_data)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, "failed to allocate IIO device\n"); + return -ENOMEM; hx711_data = iio_priv(indio_dev); hx711_data->dev = dev; diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index 17b0a2548b0a..b865bbc94517 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -320,8 +320,7 @@ static int imx93_adc_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, - "Failed allocating iio device\n"); + return -ENOMEM; adc = iio_priv(indio_dev); adc->dev = dev; diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c index a68f1cd6883e..cd679ff10a97 100644 --- a/drivers/iio/adc/mcp3564.c +++ b/drivers/iio/adc/mcp3564.c @@ -1019,7 +1019,7 @@ static int mcp3564_parse_fw_children(struct iio_dev *indio_dev) channels = devm_kcalloc(dev, num_ch, sizeof(*channels), GFP_KERNEL); if (!channels) - return dev_err_probe(dev, -ENOMEM, "Can't allocate memory\n"); + return -ENOMEM; device_for_each_child_node_scoped(dev, child) { node_name = fwnode_get_name(child); diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 4ff88603e4fc..f7e7172ef4f6 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -1357,7 +1357,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, "failed allocating iio device\n"); + return -ENOMEM; priv = iio_priv(indio_dev); init_completion(&priv->done); diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index 926971cb50bf..6721da0ed7bb 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -466,8 +466,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); if (!indio_dev) - return dev_err_probe(&pdev->dev, -ENOMEM, - "failed allocating iio device\n"); + return -ENOMEM; info = iio_priv(indio_dev); diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index df100dce77da..50b0a607baeb 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -275,8 +275,7 @@ static int spear_adc_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, - "failed allocating iio device\n"); + return -ENOMEM; st = iio_priv(indio_dev); st->dev = dev; diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c index 3e4f79dfb078..2d70b2662f41 100644 --- a/drivers/iio/adc/ti-ads1119.c +++ b/drivers/iio/adc/ti-ads1119.c @@ -693,8 +693,7 @@ static int ads1119_probe(struct i2c_client *client) indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, - "Failed to allocate IIO device\n"); + return -ENOMEM; st = iio_priv(indio_dev); st->client = client; @@ -750,8 +749,7 @@ static int ads1119_probe(struct i2c_client *client) indio_dev->name, iio_device_id(indio_dev)); if (!st->trig) - return dev_err_probe(dev, -ENOMEM, - "Failed to allocate IIO trigger\n"); + return -ENOMEM; st->trig->ops = &ads1119_trigger_ops; iio_trigger_set_drvdata(st->trig, indio_dev); diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c index 46255c530cb4..bbcc4fc22b6e 100644 --- a/drivers/iio/adc/ti-ads7924.c +++ b/drivers/iio/adc/ti-ads7924.c @@ -355,8 +355,7 @@ static int ads7924_probe(struct i2c_client *client) indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, - "failed to allocate iio device\n"); + return -ENOMEM; data = iio_priv(indio_dev); diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 1b3b1843a801..d7182ed0d2a7 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -832,7 +832,7 @@ static int vf610_adc_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc)); if (!indio_dev) - return dev_err_probe(&pdev->dev, -ENOMEM, "Failed allocating iio device\n"); + return -ENOMEM; info = iio_priv(indio_dev); info->dev = &pdev->dev; From e407199c961f229463c9ede59d319182a2d58904 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Thu, 21 Aug 2025 16:06:47 +0800 Subject: [PATCH 0478/2711] iio: chemical: Remove dev_err_probe() if error is -ENOMEM The dev_err_probe() doesn't do anything when the error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Reviewed-by: Gustavo Silva # for ens160 Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250821080723.525379-4-zhao.xichao@vivo.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/ens160_core.c | 3 +-- drivers/iio/chemical/scd30_core.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c index 6cec60074827..86bde4a91bf7 100644 --- a/drivers/iio/chemical/ens160_core.c +++ b/drivers/iio/chemical/ens160_core.c @@ -305,8 +305,7 @@ static int ens160_setup_trigger(struct iio_dev *indio_dev, int irq) trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); if (!trig) - return dev_err_probe(dev, -ENOMEM, - "failed to allocate trigger\n"); + return -ENOMEM; trig->ops = &ens160_trigger_ops; iio_trigger_set_drvdata(trig, indio_dev); diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c index 5df1926cd5d9..a665fcb78806 100644 --- a/drivers/iio/chemical/scd30_core.c +++ b/drivers/iio/chemical/scd30_core.c @@ -635,7 +635,7 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev) trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); if (!trig) - return dev_err_probe(dev, -ENOMEM, "failed to allocate trigger\n"); + return -ENOMEM; trig->ops = &scd30_trigger_ops; iio_trigger_set_drvdata(trig, indio_dev); From d3a7db87dad680b87473bd5d79139142cb88bbde Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Thu, 21 Aug 2025 16:06:48 +0800 Subject: [PATCH 0479/2711] iio: imu: bmi323: Remove dev_err_probe() if error is -ENOMEM The dev_err_probe() doesn't do anything when the error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250821080723.525379-5-zhao.xichao@vivo.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/bmi323/bmi323_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c index fc54d464a3ae..6bcb9a436581 100644 --- a/drivers/iio/imu/bmi323/bmi323_core.c +++ b/drivers/iio/imu/bmi323/bmi323_core.c @@ -2112,8 +2112,7 @@ int bmi323_core_probe(struct device *dev) indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, - "Failed to allocate device\n"); + return -ENOMEM; ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names), regulator_names); From 660586969ea3add4a2a29437d89ef5a6d87a5aaa Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Thu, 21 Aug 2025 16:06:49 +0800 Subject: [PATCH 0480/2711] iio: light: Remove dev_err_probe() if error is -ENOMEM The dev_err_probe() doesn't do anything when the error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250821080723.525379-6-zhao.xichao@vivo.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/opt4060.c | 2 +- drivers/iio/light/veml6040.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/light/opt4060.c b/drivers/iio/light/opt4060.c index aa10400e0a1f..981c704e7df5 100644 --- a/drivers/iio/light/opt4060.c +++ b/drivers/iio/light/opt4060.c @@ -1212,7 +1212,7 @@ static int opt4060_setup_trigger(struct opt4060_chip *chip, struct iio_dev *idev name = devm_kasprintf(chip->dev, GFP_KERNEL, "%s-opt4060", dev_name(chip->dev)); if (!name) - return dev_err_probe(chip->dev, -ENOMEM, "Failed to alloc chip name\n"); + return -ENOMEM; ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL, opt4060_irq_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, diff --git a/drivers/iio/light/veml6040.c b/drivers/iio/light/veml6040.c index 71a594b2ec85..f563f9f0ee67 100644 --- a/drivers/iio/light/veml6040.c +++ b/drivers/iio/light/veml6040.c @@ -219,8 +219,7 @@ static int veml6040_probe(struct i2c_client *client) indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, - "IIO device allocation failed\n"); + return -ENOMEM; regmap = devm_regmap_init_i2c(client, &veml6040_regmap_config); if (IS_ERR(regmap)) From 7216d7b9beb87f4afd62d737f024254ca3c0746c Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Thu, 21 Aug 2025 16:06:50 +0800 Subject: [PATCH 0481/2711] iio: proximity: Remove dev_err_probe() if error is -ENOMEM The dev_err_probe() doesn't do anything when the error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250821080723.525379-7-zhao.xichao@vivo.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/d3323aa.c | 3 +-- drivers/iio/proximity/hx9023s.c | 3 +-- drivers/iio/proximity/irsd200.c | 6 ++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/iio/proximity/d3323aa.c b/drivers/iio/proximity/d3323aa.c index d4c3dbea9bb0..30821f583454 100644 --- a/drivers/iio/proximity/d3323aa.c +++ b/drivers/iio/proximity/d3323aa.c @@ -722,8 +722,7 @@ static int d3323aa_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) - return dev_err_probe(dev, -ENOMEM, - "Could not allocate iio device\n"); + return -ENOMEM; data = iio_priv(indio_dev); data->dev = dev; diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c index 33781c314728..2918dfc0df54 100644 --- a/drivers/iio/proximity/hx9023s.c +++ b/drivers/iio/proximity/hx9023s.c @@ -1141,8 +1141,7 @@ static int hx9023s_probe(struct i2c_client *client) indio_dev->name, iio_device_id(indio_dev)); if (!data->trig) - return dev_err_probe(dev, -ENOMEM, - "iio trigger alloc failed\n"); + return -ENOMEM; data->trig->ops = &hx9023s_trigger_ops; iio_trigger_set_drvdata(data->trig, indio_dev); diff --git a/drivers/iio/proximity/irsd200.c b/drivers/iio/proximity/irsd200.c index 253e4aef22fb..65af31d43453 100644 --- a/drivers/iio/proximity/irsd200.c +++ b/drivers/iio/proximity/irsd200.c @@ -862,8 +862,7 @@ static int irsd200_probe(struct i2c_client *client) indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) - return dev_err_probe(&client->dev, -ENOMEM, - "Could not allocate iio device\n"); + return -ENOMEM; data = iio_priv(indio_dev); data->dev = &client->dev; @@ -916,8 +915,7 @@ static int irsd200_probe(struct i2c_client *client) trigger = devm_iio_trigger_alloc(data->dev, "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); if (!trigger) - return dev_err_probe(data->dev, -ENOMEM, - "Could not allocate iio trigger\n"); + return -ENOMEM; trigger->ops = &irsd200_trigger_ops; iio_trigger_set_drvdata(trigger, data); From 1f53971032a582dc8bcc7d26acfcfe2bf1ae51d6 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Thu, 21 Aug 2025 16:06:51 +0800 Subject: [PATCH 0482/2711] iio: temperature: mlx90635: Remove dev_err_probe() if error is -ENOMEM The dev_err_probe() doesn't do anything when the error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Acked-by: Crt Mori Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250821080723.525379-8-zhao.xichao@vivo.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mlx90635.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/temperature/mlx90635.c b/drivers/iio/temperature/mlx90635.c index 1175c7887ae1..0ba08504e990 100644 --- a/drivers/iio/temperature/mlx90635.c +++ b/drivers/iio/temperature/mlx90635.c @@ -939,7 +939,7 @@ static int mlx90635_probe(struct i2c_client *client) indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mlx90635)); if (!indio_dev) - return dev_err_probe(&client->dev, -ENOMEM, "failed to allocate device\n"); + return -ENOMEM; regmap = devm_regmap_init_i2c(client, &mlx90635_regmap); if (IS_ERR(regmap)) From d6d389646a35daae9fc1f21fe9221dcb7b3cc41f Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Fri, 22 Aug 2025 09:23:50 -0400 Subject: [PATCH 0483/2711] dt-bindings: iio: mcp9600: Set default 3 for thermocouple-type As is already documented in this file, Type-K is the default, so make that explicit in the dt-bindings. Signed-off-by: Ben Collins Reviewed-by: Krzysztof Kozlowski Reviewed-by: David Lechner Link: https://patch.msgid.link/20250822-upstream-changes-v8-1-40bb1739e3e2@watter.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/temperature/microchip,mcp9600.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml b/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml index d2cafa38a544..57b387a1accc 100644 --- a/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml @@ -37,6 +37,7 @@ properties: thermocouple-type: $ref: /schemas/types.yaml#/definitions/uint32 + default: 3 description: Type of thermocouple (THERMOCOUPLE_TYPE_K if omitted). Use defines in dt-bindings/iio/temperature/thermocouple.h. From f6a52403fd2c1b581d4f78d79def57b803f29635 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Fri, 22 Aug 2025 09:23:51 -0400 Subject: [PATCH 0484/2711] dt-bindings: iio: mcp9600: Add microchip,mcp9601 and add constraints Add microchip,mcp9601 compatible in addition to the original microchip,mcp9600 to designate support between these two chips. The current dt-binding has open-circuit and short-circuit as interrupt names, but these are only supported in mcp9601. The OC and SC detection requires that mcp9601 VSENSE be wired up, which not only enables the OC SC interrupts, but also the OC and SC status register bits. Add a microchip,vsense boolean to show the chip is wired for this support. Add constraints so this feature only applies if the mcp9601 compatible is selected. Signed-off-by: Ben Collins Reviewed-by: Krzysztof Kozlowski Reviewed-by: David Lechner Link: https://patch.msgid.link/20250822-upstream-changes-v8-2-40bb1739e3e2@watter.com Signed-off-by: Jonathan Cameron --- .../iio/temperature/microchip,mcp9600.yaml | 55 ++++++++++++++++++- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml b/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml index 57b387a1accc..effe3bee495d 100644 --- a/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/iio/temperature/microchip,mcp9600.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Microchip MCP9600 thermocouple EMF converter +title: Microchip MCP9600 and similar thermocouple EMF converters maintainers: - Andrew Hepp @@ -14,7 +14,11 @@ description: properties: compatible: - const: microchip,mcp9600 + oneOf: + - const: microchip,mcp9600 + - items: + - const: microchip,mcp9601 + - const: microchip,mcp9600 reg: maxItems: 1 @@ -43,8 +47,37 @@ properties: Use defines in dt-bindings/iio/temperature/thermocouple.h. Supported types are B, E, J, K, N, R, S, T. + microchip,vsense: + type: boolean + description: + This flag indicates that the chip has been wired with VSENSE to + enable open and short circuit detect. + vdd-supply: true +allOf: + - if: + properties: + compatible: + not: + contains: + const: microchip,mcp9601 + then: + properties: + interrupts: + minItems: 1 + maxItems: 4 + interrupt-names: + minItems: 1 + maxItems: 4 + items: + enum: + - alert1 + - alert2 + - alert3 + - alert4 + microchip,vsense: false + required: - compatible - reg @@ -64,8 +97,24 @@ examples: reg = <0x60>; interrupt-parent = <&gpio>; interrupts = <25 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "open-circuit"; + interrupt-names = "alert1"; thermocouple-type = ; vdd-supply = <&vdd>; }; }; + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + temperature-sensor@62 { + compatible = "microchip,mcp9601", "microchip,mcp9600"; + reg = <0x62>; + interrupt-parent = <&gpio>; + interrupts = <22 IRQ_TYPE_EDGE_RISING>, <23 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "open-circuit", "short-circuit"; + vdd-supply = <&vdd>; + microchip,vsense; + }; + }; From 74cae3eb72a07da8f9d623c19d7b74dd028d3861 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Fri, 22 Aug 2025 09:23:52 -0400 Subject: [PATCH 0485/2711] iio: mcp9600: White space and fixed width cleanup Make tabs consistent for register definitions and also fix width to byte size. Signed-off-by: Ben Collins Reviewed-by: David Lechner Reviewed-by: Andy Shevchenko Reviewed-by: David Lechner Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250822-upstream-changes-v8-3-40bb1739e3e2@watter.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mcp9600.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index 6e9108d5cf75..40906bb200ec 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -23,25 +23,25 @@ #include /* MCP9600 registers */ -#define MCP9600_HOT_JUNCTION 0x0 -#define MCP9600_COLD_JUNCTION 0x2 -#define MCP9600_STATUS 0x4 +#define MCP9600_HOT_JUNCTION 0x00 +#define MCP9600_COLD_JUNCTION 0x02 +#define MCP9600_STATUS 0x04 #define MCP9600_STATUS_ALERT(x) BIT(x) -#define MCP9600_ALERT_CFG1 0x8 +#define MCP9600_ALERT_CFG1 0x08 #define MCP9600_ALERT_CFG(x) (MCP9600_ALERT_CFG1 + (x - 1)) #define MCP9600_ALERT_CFG_ENABLE BIT(0) #define MCP9600_ALERT_CFG_ACTIVE_HIGH BIT(2) #define MCP9600_ALERT_CFG_FALLING BIT(3) #define MCP9600_ALERT_CFG_COLD_JUNCTION BIT(4) -#define MCP9600_ALERT_HYSTERESIS1 0xc +#define MCP9600_ALERT_HYSTERESIS1 0x0c #define MCP9600_ALERT_HYSTERESIS(x) (MCP9600_ALERT_HYSTERESIS1 + (x - 1)) #define MCP9600_ALERT_LIMIT1 0x10 #define MCP9600_ALERT_LIMIT(x) (MCP9600_ALERT_LIMIT1 + (x - 1)) #define MCP9600_ALERT_LIMIT_MASK GENMASK(15, 2) -#define MCP9600_DEVICE_ID 0x20 +#define MCP9600_DEVICE_ID 0x20 /* MCP9600 device id value */ -#define MCP9600_DEVICE_ID_MCP9600 0x40 +#define MCP9600_DEVICE_ID_MCP9600 0x40 #define MCP9600_ALERT_COUNT 4 From 5efd60c974a2c2647a2ce87fb2e396011274cfed Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Fri, 22 Aug 2025 09:23:53 -0400 Subject: [PATCH 0486/2711] iio: mcp9600: Recognize chip id for mcp9601 The current driver works with mcp9601, but emits a warning because it does not recognize the chip id. MCP9601 is a superset of MCP9600. The drivers works without changes on this chipset. However, the 9601 chip supports open/closed-circuit detection if wired properly, so we'll need to be able to differentiate between them. Moved "struct mcp9600_data" up in the file since a later patch will need it and chip_info before the declarations. Signed-off-by: Ben Collins Reviewed-by: David Lechner Link: https://patch.msgid.link/20250822-upstream-changes-v8-4-40bb1739e3e2@watter.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/Kconfig | 8 ++-- drivers/iio/temperature/mcp9600.c | 68 +++++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig index 1244d8e17d50..9328b2250ace 100644 --- a/drivers/iio/temperature/Kconfig +++ b/drivers/iio/temperature/Kconfig @@ -173,11 +173,13 @@ config MAX31865 will be called max31865. config MCP9600 - tristate "MCP9600 thermocouple EMF converter" + tristate "MCP9600 and similar thermocouple EMF converters" depends on I2C help - If you say yes here you get support for MCP9600 - thermocouple EMF converter connected via I2C. + If you say yes here you get support for... + - MCP9600 + - MCP9601 + ...thermocouple EMF converters connected via I2C. This driver can also be built as a module. If so, the module will be called mcp9600. diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index 40906bb200ec..51ed780ea72f 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -42,6 +42,7 @@ /* MCP9600 device id value */ #define MCP9600_DEVICE_ID_MCP9600 0x40 +#define MCP9600_DEVICE_ID_MCP9601 0x41 #define MCP9600_ALERT_COUNT 4 @@ -82,6 +83,15 @@ static const struct iio_event_spec mcp9600_events[] = { }, }; +struct mcp_chip_info { + u8 chip_id; + const char *chip_name; +}; + +struct mcp9600_data { + struct i2c_client *client; +}; + #define MCP9600_CHANNELS(hj_num_ev, hj_ev_spec_off, cj_num_ev, cj_ev_spec_off) \ { \ { \ @@ -123,10 +133,6 @@ static const struct iio_chan_spec mcp9600_channels[][2] = { MCP9600_CHANNELS(2, 0, 2, 0), /* Alerts: 1 2 3 4 */ }; -struct mcp9600_data { - struct i2c_client *client; -}; - static int mcp9600_read(struct mcp9600_data *data, struct iio_chan_spec const *chan, int *val) { @@ -416,18 +422,36 @@ static int mcp9600_probe_alerts(struct iio_dev *indio_dev) static int mcp9600_probe(struct i2c_client *client) { + struct device *dev = &client->dev; + const struct mcp_chip_info *chip_info; struct iio_dev *indio_dev; struct mcp9600_data *data; - int ret, ch_sel; + int ch_sel, dev_id; - ret = i2c_smbus_read_byte_data(client, MCP9600_DEVICE_ID); - if (ret < 0) - return dev_err_probe(&client->dev, ret, "Failed to read device ID\n"); - if (ret != MCP9600_DEVICE_ID_MCP9600) - dev_warn(&client->dev, "Expected ID %x, got %x\n", - MCP9600_DEVICE_ID_MCP9600, ret); + chip_info = i2c_get_match_data(client); + if (!chip_info) + return dev_err_probe(dev, -ENODEV, + "No chip-info found for device\n"); - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + dev_id = i2c_smbus_read_byte_data(client, MCP9600_DEVICE_ID); + if (dev_id < 0) + return dev_err_probe(dev, dev_id, "Failed to read device ID\n"); + + switch (dev_id) { + case MCP9600_DEVICE_ID_MCP9600: + case MCP9600_DEVICE_ID_MCP9601: + if (dev_id != chip_info->chip_id) + dev_warn(dev, + "Expected id %02x, but device responded with %02x\n", + chip_info->chip_id, dev_id); + break; + + default: + dev_warn(dev, "Unknown id %x, using %x\n", dev_id, + chip_info->chip_id); + } + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; @@ -439,22 +463,34 @@ static int mcp9600_probe(struct i2c_client *client) return ch_sel; indio_dev->info = &mcp9600_info; - indio_dev->name = "mcp9600"; + indio_dev->name = chip_info->chip_name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = mcp9600_channels[ch_sel]; indio_dev->num_channels = ARRAY_SIZE(mcp9600_channels[ch_sel]); - return devm_iio_device_register(&client->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } +static const struct mcp_chip_info mcp9600_chip_info = { + .chip_id = MCP9600_DEVICE_ID_MCP9600, + .chip_name = "mcp9600", +}; + +static const struct mcp_chip_info mcp9601_chip_info = { + .chip_id = MCP9600_DEVICE_ID_MCP9601, + .chip_name = "mcp9601", +}; + static const struct i2c_device_id mcp9600_id[] = { - { "mcp9600" }, + { "mcp9600", .driver_data = (kernel_ulong_t)&mcp9600_chip_info }, + { "mcp9601", .driver_data = (kernel_ulong_t)&mcp9601_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, mcp9600_id); static const struct of_device_id mcp9600_of_match[] = { - { .compatible = "microchip,mcp9600" }, + { .compatible = "microchip,mcp9600", .data = &mcp9600_chip_info }, + { .compatible = "microchip,mcp9601", .data = &mcp9601_chip_info }, { } }; MODULE_DEVICE_TABLE(of, mcp9600_of_match); From 46809b9f43b406b7a13c091275e56e611d4e5de4 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Fri, 22 Aug 2025 09:23:54 -0400 Subject: [PATCH 0487/2711] iio: mcp9600: Add support for thermocouple-type dt-bindings documentation for this driver claims to support thermocouple-type, but the driver does not actually make use of the property. Implement usage of the property to configure the chip for the selected thermocouple-type. Signed-off-by: Ben Collins Reviewed-by: David Lechner Link: https://patch.msgid.link/20250822-upstream-changes-v8-5-40bb1739e3e2@watter.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mcp9600.c | 71 ++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index 51ed780ea72f..aa42c2b1a369 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -22,11 +22,15 @@ #include #include +#include + /* MCP9600 registers */ #define MCP9600_HOT_JUNCTION 0x00 #define MCP9600_COLD_JUNCTION 0x02 #define MCP9600_STATUS 0x04 #define MCP9600_STATUS_ALERT(x) BIT(x) +#define MCP9600_SENSOR_CFG 0x05 +#define MCP9600_SENSOR_TYPE_MASK GENMASK(6, 4) #define MCP9600_ALERT_CFG1 0x08 #define MCP9600_ALERT_CFG(x) (MCP9600_ALERT_CFG1 + (x - 1)) #define MCP9600_ALERT_CFG_ENABLE BIT(0) @@ -66,6 +70,30 @@ static const char * const mcp9600_alert_name[MCP9600_ALERT_COUNT] = { [MCP9600_ALERT4] = "alert4", }; +/* Map between dt-bindings enum and the chip's type value */ +static const unsigned int mcp9600_type_map[] = { + [THERMOCOUPLE_TYPE_K] = 0, + [THERMOCOUPLE_TYPE_J] = 1, + [THERMOCOUPLE_TYPE_T] = 2, + [THERMOCOUPLE_TYPE_N] = 3, + [THERMOCOUPLE_TYPE_S] = 4, + [THERMOCOUPLE_TYPE_E] = 5, + [THERMOCOUPLE_TYPE_B] = 6, + [THERMOCOUPLE_TYPE_R] = 7, +}; + +/* Map thermocouple type to a char for iio info in sysfs */ +static const int mcp9600_tc_types[] = { + [THERMOCOUPLE_TYPE_K] = 'K', + [THERMOCOUPLE_TYPE_J] = 'J', + [THERMOCOUPLE_TYPE_T] = 'T', + [THERMOCOUPLE_TYPE_N] = 'N', + [THERMOCOUPLE_TYPE_S] = 'S', + [THERMOCOUPLE_TYPE_E] = 'E', + [THERMOCOUPLE_TYPE_B] = 'B', + [THERMOCOUPLE_TYPE_R] = 'R', +}; + static const struct iio_event_spec mcp9600_events[] = { { .type = IIO_EV_TYPE_THRESH, @@ -90,14 +118,34 @@ struct mcp_chip_info { struct mcp9600_data { struct i2c_client *client; + u32 thermocouple_type; }; +static int mcp9600_config(struct mcp9600_data *data) +{ + struct i2c_client *client = data->client; + int ret; + u8 cfg; + + cfg = FIELD_PREP(MCP9600_SENSOR_TYPE_MASK, + mcp9600_type_map[data->thermocouple_type]); + + ret = i2c_smbus_write_byte_data(client, MCP9600_SENSOR_CFG, cfg); + if (ret < 0) { + dev_err(&client->dev, "Failed to set sensor configuration\n"); + return ret; + } + + return 0; +} + #define MCP9600_CHANNELS(hj_num_ev, hj_ev_spec_off, cj_num_ev, cj_ev_spec_off) \ { \ { \ .type = IIO_TEMP, \ .address = MCP9600_HOT_JUNCTION, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_THERMOCOUPLE_TYPE) | \ BIT(IIO_CHAN_INFO_SCALE), \ .event_spec = &mcp9600_events[hj_ev_spec_off], \ .num_event_specs = hj_num_ev, \ @@ -165,6 +213,9 @@ static int mcp9600_read_raw(struct iio_dev *indio_dev, *val = 62; *val2 = 500000; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_THERMOCOUPLE_TYPE: + *val = mcp9600_tc_types[data->thermocouple_type]; + return IIO_VAL_CHAR; default: return -EINVAL; } @@ -426,7 +477,7 @@ static int mcp9600_probe(struct i2c_client *client) const struct mcp_chip_info *chip_info; struct iio_dev *indio_dev; struct mcp9600_data *data; - int ch_sel, dev_id; + int ch_sel, dev_id, ret; chip_info = i2c_get_match_data(client); if (!chip_info) @@ -458,6 +509,24 @@ static int mcp9600_probe(struct i2c_client *client) data = iio_priv(indio_dev); data->client = client; + /* Accept type from dt with default of Type-K. */ + data->thermocouple_type = THERMOCOUPLE_TYPE_K; + ret = device_property_read_u32(dev, "thermocouple-type", + &data->thermocouple_type); + if (ret && ret != -EINVAL) + return dev_err_probe(dev, ret, + "Error reading thermocouple-type property\n"); + + if (data->thermocouple_type >= ARRAY_SIZE(mcp9600_type_map)) + return dev_err_probe(dev, -EINVAL, + "Invalid thermocouple-type property %u.\n", + data->thermocouple_type); + + /* Set initial config. */ + ret = mcp9600_config(data); + if (ret) + return ret; + ch_sel = mcp9600_probe_alerts(indio_dev); if (ch_sel < 0) return ch_sel; From a4ee7e220c1a83e18ac32e5a3a70461e1accd652 Mon Sep 17 00:00:00 2001 From: Xing Guo Date: Tue, 19 Aug 2025 14:56:34 +0800 Subject: [PATCH 0488/2711] docs: iio: Fix unexpected indentation for adxl345. Resolved the following building error: Documentation/iio/adxl345.rst:161: ERROR: Unexpected indentation. [docutils] Fixes: fdcb9cb9178a ("docs: iio: add documentation for adxl345 driver") Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/linux-next/20250818124124.5b978e64@canb.auug.org.au Signed-off-by: Xing Guo Link: https://patch.msgid.link/20250819065634.1154322-1-higuoxing@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/iio/adxl345.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/iio/adxl345.rst b/Documentation/iio/adxl345.rst index 4bd038cb4a37..afdb35f8b72e 100644 --- a/Documentation/iio/adxl345.rst +++ b/Documentation/iio/adxl345.rst @@ -157,6 +157,7 @@ sensor terms, free-fall is defined using an inactivity period ranging from 0.000 to 1.000 seconds. The driver behaves as follows: + * If the configured inactivity period is 1 second or more, the driver uses the sensor's inactivity register. This allows the event to be linked with activity detection, use auto-sleep, and be either AC- or DC-coupled. From ccef0530e60dc59b36cac1cae2d9a7d7f86ca99f Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 19 Aug 2025 20:50:17 +0800 Subject: [PATCH 0489/2711] iio: common: scmi_iio: use kcalloc() instead of kzalloc() Replace calls of devm_kzalloc() with devm_kcalloc() in scmi_alloc_iiodev() and scmi_iio_set_sampling_freq_avail() for safer memory allocation with built-in overflow protection. Similarly, use array_size() instead of explicit multiplication for 'sensor->sensor_info->intervals.count * 2'. Signed-off-by: Qianfeng Rong Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250819125017.635182-1-rongqianfeng@vivo.com Signed-off-by: Jonathan Cameron --- drivers/iio/common/scmi_sensors/scmi_iio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c index da516c46e057..39c61c47022a 100644 --- a/drivers/iio/common/scmi_sensors/scmi_iio.c +++ b/drivers/iio/common/scmi_sensors/scmi_iio.c @@ -521,9 +521,9 @@ static int scmi_iio_set_sampling_freq_avail(struct iio_dev *iio_dev) int i; sensor->freq_avail = - devm_kzalloc(&iio_dev->dev, - sizeof(*sensor->freq_avail) * - (sensor->sensor_info->intervals.count * 2), + devm_kcalloc(&iio_dev->dev, + array_size(sensor->sensor_info->intervals.count, 2), + sizeof(*sensor->freq_avail), GFP_KERNEL); if (!sensor->freq_avail) return -ENOMEM; @@ -597,8 +597,8 @@ scmi_alloc_iiodev(struct scmi_device *sdev, iiodev->info = &scmi_iio_info; iio_channels = - devm_kzalloc(dev, - sizeof(*iio_channels) * (iiodev->num_channels), + devm_kcalloc(dev, iiodev->num_channels, + sizeof(*iio_channels), GFP_KERNEL); if (!iio_channels) return ERR_PTR(-ENOMEM); From 3c63ba1c430af1c0dcd68dd36f2246980621dcba Mon Sep 17 00:00:00 2001 From: Aleksandar Gerasimovski Date: Mon, 11 Aug 2025 13:09:04 +0000 Subject: [PATCH 0490/2711] iio/adc/pac1934: fix channel disable configuration There are two problems with the chip configuration in this driver: - First, is that writing 12 bytes (ARRAY_SIZE(regs)) would anyhow lead to a config overflow due to HW auto increment implementation in the chip. - Second, the i2c_smbus_write_block_data write ends up in writing unexpected value to the channel_dis register, this is because the smbus size that is 0x03 in this case gets written to the register. The PAC1931/2/3/4 data sheet does not really specify that block write is indeed supported. This problem is probably not visible on PAC1934 version where all channels are used as the chip is properly configured by luck, but in our case whenusing PAC1931 this leads to nonfunctional device. Fixes: 0fb528c8255b (iio: adc: adding support for PAC193x) Suggested-by: Rene Straub Signed-off-by: Aleksandar Gerasimovski Reviewed-by: Marius Cristea Link: https://patch.msgid.link/20250811130904.2481790-1-aleksandar.gerasimovski@belden.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/pac1934.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index 09fe88eb3fb0..2e442e46f679 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -88,6 +88,7 @@ #define PAC1934_VPOWER_3_ADDR 0x19 #define PAC1934_VPOWER_4_ADDR 0x1A #define PAC1934_REFRESH_V_REG_ADDR 0x1F +#define PAC1934_SLOW_REG_ADDR 0x20 #define PAC1934_CTRL_STAT_REGS_ADDR 0x1C #define PAC1934_PID_REG_ADDR 0xFD #define PAC1934_MID_REG_ADDR 0xFE @@ -1265,8 +1266,23 @@ static int pac1934_chip_configure(struct pac1934_chip_info *info) /* no SLOW triggered REFRESH, clear POR */ regs[PAC1934_SLOW_REG_OFF] = 0; - ret = i2c_smbus_write_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR, - ARRAY_SIZE(regs), (u8 *)regs); + /* + * Write the three bytes sequentially, as the device does not support + * block write. + */ + ret = i2c_smbus_write_byte_data(client, PAC1934_CTRL_STAT_REGS_ADDR, + regs[PAC1934_CHANNEL_DIS_REG_OFF]); + if (ret) + return ret; + + ret = i2c_smbus_write_byte_data(client, + PAC1934_CTRL_STAT_REGS_ADDR + PAC1934_NEG_PWR_REG_OFF, + regs[PAC1934_NEG_PWR_REG_OFF]); + if (ret) + return ret; + + ret = i2c_smbus_write_byte_data(client, PAC1934_SLOW_REG_ADDR, + regs[PAC1934_SLOW_REG_OFF]); if (ret) return ret; From dc757dc1572d579c2634c05d0a03c5676227c571 Mon Sep 17 00:00:00 2001 From: Cryolitia PukNgae Date: Thu, 21 Aug 2025 15:52:36 +0800 Subject: [PATCH 0491/2711] iio: imu: bmi270: Match PNP ID found on newer GPD firmware GPD devices originally used BMI160 sensors with the "BMI0160" PNP ID. When they switched to BMI260 sensors in newer hardware, they reused the existing Windows driver which accepts both "BMI0160" and "BMI0260" IDs. Consequently, they kept "BMI0160" in DSDT tables for new BMI260 devices, causing driver mismatches in Linux. 1. GPD updated BIOS v0.40+[1] for newer devices to report "BMI0260" for BMI260 sensors to avoid loading the bmi160 driver on Linux. While this isn't Bosch's VID; 2. Bosch's official Windows driver uses "BMI0260" as a compatible ID 3. We're seeing real devices shipping with "BMI0260" in DSDT The DSDT excerpt of GPD G1619-04 with BIOS v0.40: Scope (_SB.I2CC) { Device (BMA2) { Name (_ADR, Zero) // _ADR: Address Name (_HID, "BMI0260") // _HID: Hardware ID Name (_CID, "BMI0260") // _CID: Compatible ID Name (_DDN, "Accelerometer") // _DDN: DOS Device Name Name (_UID, One) // _UID: Unique ID Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings { Name (RBUF, ResourceTemplate () { I2cSerialBusV2 (0x0069, ControllerInitiated, 0x00061A80, AddressingMode7Bit, "\\_SB.I2CC", 0x00, ResourceConsumer, , Exclusive, ) }) Return (RBUF) /* \_SB_.I2CC.BMA2._CRS.RBUF */ } # omit some noise } } Link: http://download.softwincn.com/WIN%20Max%202024/Max2-7840-BIOS-V0.41.zip #1 Signed-off-by: Cryolitia PukNgae Reviewed-by: Andy Shevchenko Acked-by: Alex Lanzano Link: https://patch.msgid.link/20250821-bmi270-gpd-acpi-v4-1-5279b471d749@uniontech.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/bmi270/bmi270_i2c.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/imu/bmi270/bmi270_i2c.c b/drivers/iio/imu/bmi270/bmi270_i2c.c index c77839b03a96..b909a421ad01 100644 --- a/drivers/iio/imu/bmi270/bmi270_i2c.c +++ b/drivers/iio/imu/bmi270/bmi270_i2c.c @@ -41,6 +41,8 @@ static const struct i2c_device_id bmi270_i2c_id[] = { static const struct acpi_device_id bmi270_acpi_match[] = { /* GPD Win Mini, Aya Neo AIR Pro, OXP Mini Pro, etc. */ { "BMI0160", (kernel_ulong_t)&bmi260_chip_info }, + /* GPD Win Max 2 2023(sincice BIOS v0.40), etc. */ + { "BMI0260", (kernel_ulong_t)&bmi260_chip_info }, { } }; From 21feb435be9b19a0be8b2c44a9efb7a5296c9a66 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 18 Aug 2025 16:00:13 -0400 Subject: [PATCH 0492/2711] dt-bindings: iio: adc: max1238: Add #io-channel-cells property Add #io-channel-cells property with a constant value of 1 because it is multi-channel ADC. Fix below CHECK_DTBS warnings: arch/arm/boot/dts/nxp/ls/ls1021a-iot.dtb: adc@35 (maxim,max1239): '#io-channel-cells' does not match any of the regexes: '^pinctrl-[0-9]+$' from schema $id: http://devicetree.org/schemas/iio/adc/maxim,max1238.yaml# Signed-off-by: Frank Li Acked-by: Conor Dooley Link: https://patch.msgid.link/20250818200014.3700738-1-Frank.Li@nxp.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml index 60d7b34e3286..ae3c89393f1a 100644 --- a/Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml +++ b/Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml @@ -53,6 +53,9 @@ properties: reg: maxItems: 1 + "#io-channel-cells": + const: 1 + vcc-supply: true vref-supply: description: Optional external reference. If not supplied, internal From 60ad9a07319283e6e1094cef3e972e754315c024 Mon Sep 17 00:00:00 2001 From: Junjie Cao Date: Wed, 20 Aug 2025 08:47:55 +0800 Subject: [PATCH 0493/2711] iio: core: switch info_mask fields to unsigned long to match find_bit helpers for_each_set_bit()/find_*_bit() expect arrays of unsigned long (see include/linux/find.h), but industrialio-core passed const long * into iio_device_add_info_mask_type{,_avail}(). These masks are used purely as bit arrays and are populated via BIT() (1UL << n). Switch the info_mask_* fields and the corresponding function parameters to unsigned long so the types match the helpers. This removes sparse warnings about signedness mismatches (seen with 'make C=1' CF='-Wsparse-all') without changing behavior or struct layout. No functional change intended. Suggested-by: Jonathan Cameron Signed-off-by: Junjie Cao Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250820004755.69627-1-junjie.cao@intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 4 ++-- include/linux/iio/iio.h | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index eb6a54f8115d..38848d753a33 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1244,7 +1244,7 @@ static int iio_device_add_channel_label(struct iio_dev *indio_dev, static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, enum iio_shared_by shared_by, - const long *infomask) + const unsigned long *infomask) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); int i, ret, attrcount = 0; @@ -1274,7 +1274,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, enum iio_shared_by shared_by, - const long *infomask) + const unsigned long *infomask) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); int i, ret, attrcount = 0; diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 2f5560646ee4..872ebdf0dd77 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -271,14 +271,14 @@ struct iio_chan_spec { unsigned int num_ext_scan_type; }; }; - long info_mask_separate; - long info_mask_separate_available; - long info_mask_shared_by_type; - long info_mask_shared_by_type_available; - long info_mask_shared_by_dir; - long info_mask_shared_by_dir_available; - long info_mask_shared_by_all; - long info_mask_shared_by_all_available; + unsigned long info_mask_separate; + unsigned long info_mask_separate_available; + unsigned long info_mask_shared_by_type; + unsigned long info_mask_shared_by_type_available; + unsigned long info_mask_shared_by_dir; + unsigned long info_mask_shared_by_dir_available; + unsigned long info_mask_shared_by_all; + unsigned long info_mask_shared_by_all_available; const struct iio_event_spec *event_spec; unsigned int num_event_specs; const struct iio_chan_spec_ext_info *ext_info; From 5c2bf13c9ae951d63c97b367f4e7989d4913dcf3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 21 Aug 2025 10:31:51 +0200 Subject: [PATCH 0494/2711] dt-bindings: iio: adi,ltc2664: Minor whitespace cleanup in example The DTS code coding style expects exactly one space around '=' character. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250821083150.46554-2-krzysztof.kozlowski@linaro.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml index 1aece3392b77..4688eccfeb89 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml @@ -174,7 +174,7 @@ examples: channel@1 { reg = <1>; - output-range-microvolt= <0 10000000>; + output-range-microvolt = <0 10000000>; }; }; }; From feb500c7ae7a198db4d2757901bce562feeefa5e Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 14 Jul 2025 20:28:47 -0400 Subject: [PATCH 0495/2711] iio: xilinx-ams: Unmask interrupts after updating alarms To convert level-triggered alarms into edge-triggered IIO events, alarms are masked when they are triggered. To ensure we catch subsequent alarms, we then periodically poll to see if the alarm is still active. If it isn't, we unmask it. Active but masked alarms are stored in current_masked_alarm. If an active alarm is disabled, it will remain set in current_masked_alarm until ams_unmask_worker clears it. If the alarm is re-enabled before ams_unmask_worker runs, then it will never be cleared from current_masked_alarm. This will prevent the alarm event from being pushed even if the alarm is still active. Fix this by recalculating current_masked_alarm immediately when enabling or disabling alarms. Fixes: d5c70627a794 ("iio: adc: Add Xilinx AMS driver") Signed-off-by: Sean Anderson Reviewed-by: O'Griofa, Conall Tested-by: Erim, Salih Acked-by: Erim, Salih Link: https://patch.msgid.link/20250715002847.2035228-1-sean.anderson@linux.dev Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-ams.c | 45 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 76dd0343f5f7..180d4140993d 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -389,6 +389,29 @@ static void ams_update_pl_alarm(struct ams *ams, unsigned long alarm_mask) ams_pl_update_reg(ams, AMS_REG_CONFIG3, AMS_REGCFG3_ALARM_MASK, cfg); } +static void ams_unmask(struct ams *ams) +{ + unsigned int status, unmask; + + status = readl(ams->base + AMS_ISR_0); + + /* Clear those bits which are not active anymore */ + unmask = (ams->current_masked_alarm ^ status) & ams->current_masked_alarm; + + /* Clear status of disabled alarm */ + unmask |= ams->intr_mask; + + ams->current_masked_alarm &= status; + + /* Also clear those which are masked out anyway */ + ams->current_masked_alarm &= ~ams->intr_mask; + + /* Clear the interrupts before we unmask them */ + writel(unmask, ams->base + AMS_ISR_0); + + ams_update_intrmask(ams, ~AMS_ALARM_MASK, ~AMS_ALARM_MASK); +} + static void ams_update_alarm(struct ams *ams, unsigned long alarm_mask) { unsigned long flags; @@ -401,6 +424,7 @@ static void ams_update_alarm(struct ams *ams, unsigned long alarm_mask) spin_lock_irqsave(&ams->intr_lock, flags); ams_update_intrmask(ams, AMS_ISR0_ALARM_MASK, ~alarm_mask); + ams_unmask(ams); spin_unlock_irqrestore(&ams->intr_lock, flags); } @@ -1035,28 +1059,9 @@ static void ams_handle_events(struct iio_dev *indio_dev, unsigned long events) static void ams_unmask_worker(struct work_struct *work) { struct ams *ams = container_of(work, struct ams, ams_unmask_work.work); - unsigned int status, unmask; spin_lock_irq(&ams->intr_lock); - - status = readl(ams->base + AMS_ISR_0); - - /* Clear those bits which are not active anymore */ - unmask = (ams->current_masked_alarm ^ status) & ams->current_masked_alarm; - - /* Clear status of disabled alarm */ - unmask |= ams->intr_mask; - - ams->current_masked_alarm &= status; - - /* Also clear those which are masked out anyway */ - ams->current_masked_alarm &= ~ams->intr_mask; - - /* Clear the interrupts before we unmask them */ - writel(unmask, ams->base + AMS_ISR_0); - - ams_update_intrmask(ams, ~AMS_ALARM_MASK, ~AMS_ALARM_MASK); - + ams_unmask(ams); spin_unlock_irq(&ams->intr_lock); /* If still pending some alarm re-trigger the timer */ From 1315cc2dbd5034f566e20ddce4d675cb9e6d4ddd Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 14 Jul 2025 20:30:58 -0400 Subject: [PATCH 0496/2711] iio: xilinx-ams: Fix AMS_ALARM_THR_DIRECT_MASK AMS_ALARM_THR_DIRECT_MASK should be bit 0, not bit 1. This would cause hysteresis to be enabled with a lower threshold of -28C. The temperature alarm would never deassert even if the temperature dropped below the upper threshold. Fixes: d5c70627a794 ("iio: adc: Add Xilinx AMS driver") Signed-off-by: Sean Anderson Reviewed-by: O'Griofa, Conall Tested-by: Erim, Salih Acked-by: Erim, Salih Link: https://patch.msgid.link/20250715003058.2035656-1-sean.anderson@linux.dev Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-ams.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 180d4140993d..124470c92529 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -118,7 +118,7 @@ #define AMS_ALARM_THRESHOLD_OFF_10 0x10 #define AMS_ALARM_THRESHOLD_OFF_20 0x20 -#define AMS_ALARM_THR_DIRECT_MASK BIT(1) +#define AMS_ALARM_THR_DIRECT_MASK BIT(0) #define AMS_ALARM_THR_MIN 0x0000 #define AMS_ALARM_THR_MAX (BIT(16) - 1) From 9c6674035ea3d49f687c43e4a26146719ef6e414 Mon Sep 17 00:00:00 2001 From: Dixit Parmar Date: Fri, 22 Aug 2025 09:19:49 +0530 Subject: [PATCH 0497/2711] iio: accel: Drop unnecessary -ENOMEM messages The drivers do not require their own error messages for error -ENOMEM, memory allocation failures. So remove the dev_err() messages from the probe(). Signed-off-by: Dixit Parmar Link: https://patch.msgid.link/20250822-enomam_logs-v1-1-db87f2974552@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma220_spi.c | 4 +--- drivers/iio/accel/dmard06.c | 4 +--- drivers/iio/accel/dmard09.c | 4 +--- drivers/iio/accel/dmard10.c | 4 +--- drivers/iio/accel/mc3230.c | 4 +--- drivers/iio/accel/mma7660.c | 4 +--- drivers/iio/accel/stk8312.c | 4 +--- drivers/iio/accel/stk8ba50.c | 4 +--- 8 files changed, 8 insertions(+), 24 deletions(-) diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 38f7498431ee..01592eebf05b 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -255,10 +255,8 @@ static int bma220_probe(struct spi_device *spi) struct bma220_data *data; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data)); - if (!indio_dev) { - dev_err(&spi->dev, "iio allocation failed!\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->spi_device = spi; diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c index fb14894c66f9..33f225d73e7b 100644 --- a/drivers/iio/accel/dmard06.c +++ b/drivers/iio/accel/dmard06.c @@ -137,10 +137,8 @@ static int dmard06_probe(struct i2c_client *client) } indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dmard06)); - if (!indio_dev) { - dev_err(&client->dev, "Failed to allocate iio device\n"); + if (!indio_dev) return -ENOMEM; - } dmard06 = iio_priv(indio_dev); dmard06->client = client; diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c index 4ec70ca6910d..d9290e3b9c46 100644 --- a/drivers/iio/accel/dmard09.c +++ b/drivers/iio/accel/dmard09.c @@ -95,10 +95,8 @@ static int dmard09_probe(struct i2c_client *client) struct dmard09_data *data; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) { - dev_err(&client->dev, "iio allocation failed\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->client = client; diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index 71cd1928baa6..575e8510e1bd 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -191,10 +191,8 @@ static int dmard10_probe(struct i2c_client *client) return (ret < 0) ? ret : -ENODEV; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) { - dev_err(&client->dev, "iio allocation failed!\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->client = client; diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c index e2853090fa6e..3e494f9ddc56 100644 --- a/drivers/iio/accel/mc3230.c +++ b/drivers/iio/accel/mc3230.c @@ -169,10 +169,8 @@ static int mc3230_probe(struct i2c_client *client) } indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) { - dev_err(&client->dev, "iio allocation failed!\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->chip_info = chip_info; diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index d0a16f227903..be3213600cf4 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -192,10 +192,8 @@ static int mma7660_probe(struct i2c_client *client) struct mma7660_data *data; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) { - dev_err(&client->dev, "iio allocation failed!\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->client = client; diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 89569ce221d7..f31c6ab3392d 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -504,10 +504,8 @@ static int stk8312_probe(struct i2c_client *client) struct stk8312_data *data; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) { - dev_err(&client->dev, "iio allocation failed!\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->client = client; diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index c1d7e7dcb09b..384f1fbcbcb3 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -385,10 +385,8 @@ static int stk8ba50_probe(struct i2c_client *client) struct stk8ba50_data *data; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) { - dev_err(&client->dev, "iio allocation failed!\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->client = client; From c7979dbdc7be870c15a050ab0c6f6646ded73967 Mon Sep 17 00:00:00 2001 From: Dixit Parmar Date: Fri, 22 Aug 2025 09:19:50 +0530 Subject: [PATCH 0498/2711] iio: adc: Drop unnecessary -ENOMEM messages The drivers do not require their own error messages for error -ENOMEM, memory allocation failures. So remove the dev_err() messages from the probe(). Signed-off-by: Dixit Parmar Link: https://patch.msgid.link/20250822-enomam_logs-v1-2-db87f2974552@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7949.c | 4 +--- drivers/iio/adc/bcm_iproc_adc.c | 4 +--- drivers/iio/adc/cpcap-adc.c | 6 ++---- drivers/iio/adc/da9150-gpadc.c | 5 ++--- drivers/iio/adc/dln2-adc.c | 9 +++------ drivers/iio/adc/exynos_adc.c | 4 +--- drivers/iio/adc/imx7d_adc.c | 4 +--- drivers/iio/adc/imx8qxp-adc.c | 4 +--- drivers/iio/adc/mxs-lradc-adc.c | 4 +--- drivers/iio/adc/palmas_gpadc.c | 4 +--- drivers/iio/adc/rn5t618-adc.c | 4 +--- drivers/iio/adc/stm32-dfsdm-adc.c | 4 +--- drivers/iio/adc/stmpe-adc.c | 4 +--- drivers/iio/adc/ti-adc084s021.c | 4 +--- drivers/iio/adc/ti-ads131e08.c | 8 ++------ drivers/iio/adc/ti_am335x_adc.c | 5 ++--- drivers/iio/adc/twl4030-madc.c | 4 +--- drivers/iio/adc/viperboard_adc.c | 4 +--- 18 files changed, 24 insertions(+), 61 deletions(-) diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c index 202561cad401..b35d299a3977 100644 --- a/drivers/iio/adc/ad7949.c +++ b/drivers/iio/adc/ad7949.c @@ -316,10 +316,8 @@ static int ad7949_spi_probe(struct spi_device *spi) int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*ad7949_adc)); - if (!indio_dev) { - dev_err(dev, "can not allocate iio device\n"); + if (!indio_dev) return -ENOMEM; - } indio_dev->info = &ad7949_spi_info; indio_dev->name = spi_get_device_id(spi)->name; diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index f258668b0dc7..6426c9e6ccc9 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -511,10 +511,8 @@ static int iproc_adc_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_priv)); - if (!indio_dev) { - dev_err(&pdev->dev, "failed to allocate iio device\n"); + if (!indio_dev) return -ENOMEM; - } adc_priv = iio_priv(indio_dev); platform_set_drvdata(pdev, indio_dev); diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index ba7cbd3b4822..d9ee2ea116a7 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -953,11 +953,9 @@ static int cpcap_adc_probe(struct platform_device *pdev) int error; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*ddata)); - if (!indio_dev) { - dev_err(&pdev->dev, "failed to allocate iio device\n"); - + if (!indio_dev) return -ENOMEM; - } + ddata = iio_priv(indio_dev); ddata->ato = device_get_match_data(&pdev->dev); if (!ddata->ato) diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c index b99291ce2a45..625e3a8e4d03 100644 --- a/drivers/iio/adc/da9150-gpadc.c +++ b/drivers/iio/adc/da9150-gpadc.c @@ -308,10 +308,9 @@ static int da9150_gpadc_probe(struct platform_device *pdev) int irq, ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc)); - if (!indio_dev) { - dev_err(&pdev->dev, "Failed to allocate IIO device\n"); + if (!indio_dev) return -ENOMEM; - } + gpadc = iio_priv(indio_dev); gpadc->da9150 = da9150; diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c index 5aea7644780f..eb902a946efe 100644 --- a/drivers/iio/adc/dln2-adc.c +++ b/drivers/iio/adc/dln2-adc.c @@ -584,10 +584,8 @@ static int dln2_adc_probe(struct platform_device *pdev) int i, ret, chans; indio_dev = devm_iio_device_alloc(dev, sizeof(*dln2)); - if (!indio_dev) { - dev_err(dev, "failed allocating iio device\n"); + if (!indio_dev) return -ENOMEM; - } dln2 = iio_priv(indio_dev); dln2->pdev = pdev; @@ -628,10 +626,9 @@ static int dln2_adc_probe(struct platform_device *pdev) dln2->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); - if (!dln2->trig) { - dev_err(dev, "failed to allocate trigger\n"); + if (!dln2->trig) return -ENOMEM; - } + iio_trigger_set_drvdata(dln2->trig, dln2); ret = devm_iio_trigger_register(dev, dln2->trig); if (ret) { diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 4614cf848535..32cfc4002b1b 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -798,10 +798,8 @@ static int exynos_adc_probe(struct platform_device *pdev) int irq; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc)); - if (!indio_dev) { - dev_err(&pdev->dev, "failed allocating iio device\n"); + if (!indio_dev) return -ENOMEM; - } info = iio_priv(indio_dev); diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c index 09ce71f6e941..039c0387da23 100644 --- a/drivers/iio/adc/imx7d_adc.c +++ b/drivers/iio/adc/imx7d_adc.c @@ -482,10 +482,8 @@ static int imx7d_adc_probe(struct platform_device *pdev) int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*info)); - if (!indio_dev) { - dev_err(&pdev->dev, "Failed allocating iio device\n"); + if (!indio_dev) return -ENOMEM; - } info = iio_priv(indio_dev); info->dev = dev; diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c index be13a6ed7e00..427ee9f24408 100644 --- a/drivers/iio/adc/imx8qxp-adc.c +++ b/drivers/iio/adc/imx8qxp-adc.c @@ -315,10 +315,8 @@ static int imx8qxp_adc_probe(struct platform_device *pdev) int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); - if (!indio_dev) { - dev_err(dev, "Failed allocating iio device\n"); + if (!indio_dev) return -ENOMEM; - } adc = iio_priv(indio_dev); adc->dev = dev; diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c index 92baf3f5f560..dda5182a5076 100644 --- a/drivers/iio/adc/mxs-lradc-adc.c +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -697,10 +697,8 @@ static int mxs_lradc_adc_probe(struct platform_device *pdev) /* Allocate the IIO device. */ iio = devm_iio_device_alloc(dev, sizeof(*adc)); - if (!iio) { - dev_err(dev, "Failed to allocate IIO device\n"); + if (!iio) return -ENOMEM; - } adc = iio_priv(iio); adc->lradc = lradc; diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 7c01e33be04c..3f433064618e 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -885,10 +885,8 @@ static int palmas_gpadc_probe(struct platform_device *pdev) return -EINVAL; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc)); - if (!indio_dev) { - dev_err(&pdev->dev, "iio_device_alloc failed\n"); + if (!indio_dev) return -ENOMEM; - } adc = iio_priv(indio_dev); adc->dev = &pdev->dev; diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c index d6f6b351f2af..f78fc795b69a 100644 --- a/drivers/iio/adc/rn5t618-adc.c +++ b/drivers/iio/adc/rn5t618-adc.c @@ -199,10 +199,8 @@ static int rn5t618_adc_probe(struct platform_device *pdev) struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent); iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc)); - if (!iio_dev) { - dev_err(&pdev->dev, "failed allocating iio device\n"); + if (!iio_dev) return -ENOMEM; - } adc = iio_priv(iio_dev); adc->dev = &pdev->dev; diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index c2d21eecafe7..74b1b4dc6e81 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1764,10 +1764,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) dev_data = of_device_get_match_data(dev); iio = devm_iio_device_alloc(dev, sizeof(*adc)); - if (!iio) { - dev_err(dev, "%s: Failed to allocate IIO\n", __func__); + if (!iio) return -ENOMEM; - } adc = iio_priv(iio); adc->dfsdm = dev_get_drvdata(dev->parent); diff --git a/drivers/iio/adc/stmpe-adc.c b/drivers/iio/adc/stmpe-adc.c index b0add5a2eab5..8e26c47edc08 100644 --- a/drivers/iio/adc/stmpe-adc.c +++ b/drivers/iio/adc/stmpe-adc.c @@ -267,10 +267,8 @@ static int stmpe_adc_probe(struct platform_device *pdev) return irq_adc; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct stmpe_adc)); - if (!indio_dev) { - dev_err(&pdev->dev, "failed allocating iio device\n"); + if (!indio_dev) return -ENOMEM; - } info = iio_priv(indio_dev); mutex_init(&info->lock); diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c index 50a474f4d9f5..a100f770fa1c 100644 --- a/drivers/iio/adc/ti-adc084s021.c +++ b/drivers/iio/adc/ti-adc084s021.c @@ -200,10 +200,8 @@ static int adc084s021_probe(struct spi_device *spi) int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); - if (!indio_dev) { - dev_err(&spi->dev, "Failed to allocate IIO device\n"); + if (!indio_dev) return -ENOMEM; - } adc = iio_priv(indio_dev); adc->spi = spi; diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c index b18f30d3fdbe..742acc6d8cf9 100644 --- a/drivers/iio/adc/ti-ads131e08.c +++ b/drivers/iio/adc/ti-ads131e08.c @@ -807,10 +807,8 @@ static int ads131e08_probe(struct spi_device *spi) } indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) { - dev_err(&spi->dev, "failed to allocate IIO device\n"); + if (!indio_dev) return -ENOMEM; - } st = iio_priv(indio_dev); st->info = info; @@ -841,10 +839,8 @@ static int ads131e08_probe(struct spi_device *spi) st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); - if (!st->trig) { - dev_err(&spi->dev, "failed to allocate IIO trigger\n"); + if (!st->trig) return -ENOMEM; - } st->trig->ops = &ads131e08_trigger_ops; st->trig->dev.parent = &spi->dev; diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index fe1509d3b1e7..99f274adc870 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -631,10 +631,9 @@ static int tiadc_probe(struct platform_device *pdev) } indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev)); - if (!indio_dev) { - dev_err(&pdev->dev, "failed to allocate iio device\n"); + if (!indio_dev) return -ENOMEM; - } + adc_dev = iio_priv(indio_dev); adc_dev->mfd_tscadc = ti_tscadc_dev_get(pdev); diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index 0ea51ddeaa0a..fe3b31ec976e 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -758,10 +758,8 @@ static int twl4030_madc_probe(struct platform_device *pdev) } iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc)); - if (!iio_dev) { - dev_err(&pdev->dev, "failed allocating iio device\n"); + if (!iio_dev) return -ENOMEM; - } madc = iio_priv(iio_dev); madc->dev = &pdev->dev; diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c index 1028b101cf56..9bb0b83c8f67 100644 --- a/drivers/iio/adc/viperboard_adc.c +++ b/drivers/iio/adc/viperboard_adc.c @@ -113,10 +113,8 @@ static int vprbrd_adc_probe(struct platform_device *pdev) /* registering iio */ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc)); - if (!indio_dev) { - dev_err(&pdev->dev, "failed allocating iio device\n"); + if (!indio_dev) return -ENOMEM; - } adc = iio_priv(indio_dev); adc->vb = vb; From eeca066c9d990450017d141e993cf051aac2c430 Mon Sep 17 00:00:00 2001 From: Dixit Parmar Date: Fri, 22 Aug 2025 09:19:51 +0530 Subject: [PATCH 0499/2711] iio: dac: Drop unnecessary -ENOMEM messages The drivers do not require their own error messages for error -ENOMEM, memory allocation failures. So remove the dev_err() messages from the probe(). Signed-off-by: Dixit Parmar Link: https://patch.msgid.link/20250822-enomam_logs-v1-3-db87f2974552@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5380.c | 4 +--- drivers/iio/dac/ad5764.c | 4 +--- drivers/iio/dac/ds4424.c | 4 +--- drivers/iio/dac/ti-dac7311.c | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 0ddce7b218e3..8b813cee7625 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -371,10 +371,8 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); - if (indio_dev == NULL) { - dev_err(dev, "Failed to allocate iio device\n"); + if (indio_dev == NULL) return -ENOMEM; - } st = iio_priv(indio_dev); diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c index 26c049d5b73a..fbbd7105a80c 100644 --- a/drivers/iio/dac/ad5764.c +++ b/drivers/iio/dac/ad5764.c @@ -278,10 +278,8 @@ static int ad5764_probe(struct spi_device *spi) int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (indio_dev == NULL) { - dev_err(&spi->dev, "Failed to allocate iio device\n"); + if (indio_dev == NULL) return -ENOMEM; - } st = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c index a26a99753418..a8198ba4f98a 100644 --- a/drivers/iio/dac/ds4424.c +++ b/drivers/iio/dac/ds4424.c @@ -221,10 +221,8 @@ static int ds4424_probe(struct i2c_client *client) int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) { - dev_err(&client->dev, "iio dev alloc failed.\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); diff --git a/drivers/iio/dac/ti-dac7311.c b/drivers/iio/dac/ti-dac7311.c index 3d2ce61f0db6..5c1c5213962f 100644 --- a/drivers/iio/dac/ti-dac7311.c +++ b/drivers/iio/dac/ti-dac7311.c @@ -242,10 +242,8 @@ static int ti_dac_probe(struct spi_device *spi) int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*ti_dac)); - if (!indio_dev) { - dev_err(dev, "can not allocate iio device\n"); + if (!indio_dev) return -ENOMEM; - } spi->mode = SPI_MODE_1; spi->bits_per_word = 16; From fc3a8049293cef455fc585cfd36892e3992aeb14 Mon Sep 17 00:00:00 2001 From: Dixit Parmar Date: Fri, 22 Aug 2025 09:19:52 +0530 Subject: [PATCH 0500/2711] iio: health: Drop unnecessary -ENOMEM messages The drivers do not require their own error messages for error -ENOMEM, memory allocation failures. So remove the dev_err() messages from the probe(). Signed-off-by: Dixit Parmar Link: https://patch.msgid.link/20250822-enomam_logs-v1-4-db87f2974552@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/health/afe4403.c | 4 +--- drivers/iio/health/afe4404.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 99bf1bcbea40..0e5a512e3bb8 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -529,10 +529,8 @@ static int afe4403_probe(struct spi_device *spi) "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); - if (!afe->trig) { - dev_err(dev, "Unable to allocate IIO trigger\n"); + if (!afe->trig) return -ENOMEM; - } iio_trigger_set_drvdata(afe->trig, indio_dev); diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 29e030943f59..768d794e574b 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -536,10 +536,8 @@ static int afe4404_probe(struct i2c_client *client) "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); - if (!afe->trig) { - dev_err(dev, "Unable to allocate IIO trigger\n"); + if (!afe->trig) return -ENOMEM; - } iio_trigger_set_drvdata(afe->trig, indio_dev); From fba366e66b15f2261d269ec6bcb73cb2ab7d599f Mon Sep 17 00:00:00 2001 From: Dixit Parmar Date: Fri, 22 Aug 2025 09:19:53 +0530 Subject: [PATCH 0501/2711] iio: humidity: Drop unnecessary -ENOMEM messages The drivers do not require their own error messages for error -ENOMEM, memory allocation failures. So remove the dev_err() messages from the probe(). Signed-off-by: Dixit Parmar Link: https://patch.msgid.link/20250822-enomam_logs-v1-5-db87f2974552@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/am2315.c | 4 +--- drivers/iio/humidity/dht11.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index f021c3e6d886..02ca23eb8991 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -224,10 +224,8 @@ static int am2315_probe(struct i2c_client *client) struct am2315_data *data; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) { - dev_err(&client->dev, "iio allocation failed!\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->client = client; diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 73d2033954e7..980cb946bbf7 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -294,10 +294,8 @@ static int dht11_probe(struct platform_device *pdev) struct iio_dev *iio; iio = devm_iio_device_alloc(dev, sizeof(*dht11)); - if (!iio) { - dev_err(dev, "Failed to allocate IIO device\n"); + if (!iio) return -ENOMEM; - } dht11 = iio_priv(iio); dht11->dev = dev; From bdba20f5e642046b84c288d89a9443b3139b7981 Mon Sep 17 00:00:00 2001 From: Dixit Parmar Date: Fri, 22 Aug 2025 09:19:54 +0530 Subject: [PATCH 0502/2711] iio: light: Drop unnecessary -ENOMEM messages The drivers do not require their own error messages for error -ENOMEM, memory allocation failures. So remove the dev_err() messages from the probe(). Signed-off-by: Dixit Parmar Link: https://patch.msgid.link/20250822-enomam_logs-v1-6-db87f2974552@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/stk3310.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 81dd2bfc22c0..a75a83594a7e 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -607,10 +607,8 @@ static int stk3310_probe(struct i2c_client *client) struct stk3310_data *data; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) { - dev_err(&client->dev, "iio allocation failed!\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->client = client; From 368e8718875f17ac38dc7e1019b170aaee703289 Mon Sep 17 00:00:00 2001 From: Dixit Parmar Date: Fri, 22 Aug 2025 09:19:55 +0530 Subject: [PATCH 0503/2711] iio: potentiostat: Drop unnecessary -ENOMEM messages The drivers do not require their own error messages for error -ENOMEM, memory allocation failures. So remove the dev_err() messages from the probe(). Signed-off-by: Dixit Parmar Link: https://patch.msgid.link/20250822-enomam_logs-v1-7-db87f2974552@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/potentiostat/lmp91000.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index 030498d0b763..eccc2a34358f 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -321,10 +321,8 @@ static int lmp91000_probe(struct i2c_client *client) data->trig = devm_iio_trigger_alloc(dev, "%s-mux%d", indio_dev->name, iio_device_id(indio_dev)); - if (!data->trig) { - dev_err(dev, "cannot allocate iio trigger.\n"); + if (!data->trig) return -ENOMEM; - } init_completion(&data->completion); From b5e04043b45067d3a5992588c862f62099afae75 Mon Sep 17 00:00:00 2001 From: Dixit Parmar Date: Fri, 22 Aug 2025 09:19:56 +0530 Subject: [PATCH 0504/2711] iio: pressure: Drop unnecessary -ENOMEM messages The drivers do not require their own error messages for error -ENOMEM, memory allocation failures. So remove the dev_err() messages from the probe(). Signed-off-by: Dixit Parmar Link: https://patch.msgid.link/20250822-enomam_logs-v1-8-db87f2974552@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/dlhl60d.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/pressure/dlhl60d.c b/drivers/iio/pressure/dlhl60d.c index 6a13cf2eaf50..8bad7162fec6 100644 --- a/drivers/iio/pressure/dlhl60d.c +++ b/drivers/iio/pressure/dlhl60d.c @@ -289,10 +289,8 @@ static int dlh_probe(struct i2c_client *client) } indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); - if (!indio_dev) { - dev_err(&client->dev, "failed to allocate iio device\n"); + if (!indio_dev) return -ENOMEM; - } i2c_set_clientdata(client, indio_dev); From 1f6fcf7fb4ca49c19960b9545f9cd352ac2b7a31 Mon Sep 17 00:00:00 2001 From: Dixit Parmar Date: Fri, 22 Aug 2025 09:19:57 +0530 Subject: [PATCH 0505/2711] iio: proximity: Drop unnecessary -ENOMEM messages The drivers do not require their own error messages for error -ENOMEM, memory allocation failures. So remove the dev_err() messages from the probe(). Signed-off-by: Dixit Parmar Link: https://patch.msgid.link/20250822-enomam_logs-v1-9-db87f2974552@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/ping.c | 4 +--- drivers/iio/proximity/srf04.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/iio/proximity/ping.c b/drivers/iio/proximity/ping.c index c5b4e1378b7d..e3487094d7be 100644 --- a/drivers/iio/proximity/ping.c +++ b/drivers/iio/proximity/ping.c @@ -280,10 +280,8 @@ static int ping_probe(struct platform_device *pdev) struct iio_dev *indio_dev; indio_dev = devm_iio_device_alloc(dev, sizeof(struct ping_data)); - if (!indio_dev) { - dev_err(dev, "failed to allocate IIO device\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->dev = dev; diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c index b059bac1078b..f9d32f9aba1f 100644 --- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -253,10 +253,8 @@ static int srf04_probe(struct platform_device *pdev) int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(struct srf04_data)); - if (!indio_dev) { - dev_err(dev, "failed to allocate IIO device\n"); + if (!indio_dev) return -ENOMEM; - } data = iio_priv(indio_dev); data->dev = dev; From 681386fe5365591d044fe03d7ae05e5419a78d83 Mon Sep 17 00:00:00 2001 From: Dixit Parmar Date: Fri, 22 Aug 2025 09:19:58 +0530 Subject: [PATCH 0506/2711] iio: temperature: Drop unnecessary -ENOMEM messages The drivers do not require their own error messages for error -ENOMEM, memory allocation failures. So remove the dev_err() messages from the probe(). Signed-off-by: Dixit Parmar Link: https://patch.msgid.link/20250822-enomam_logs-v1-10-db87f2974552@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mlx90632.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index ae4ea587e7f9..c4bf5dc2f266 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -1178,10 +1178,8 @@ static int mlx90632_probe(struct i2c_client *client) int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mlx90632)); - if (!indio_dev) { - dev_err(&client->dev, "Failed to allocate device\n"); + if (!indio_dev) return -ENOMEM; - } regmap = devm_regmap_init_i2c(client, &mlx90632_regmap); if (IS_ERR(regmap)) { From 4c4e17f2701316e0cac16e19366056f464feded5 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 2 Jul 2025 17:25:59 +0200 Subject: [PATCH 0507/2711] clk: amlogic: naming consistency alignment Amlogic clock controller drivers are all doing the same thing, more or less. Yet, over the years, tiny (and often pointless) differences have emerged. This makes reviews more difficult, allows some errors to slip through and make it more difficult to exploit SoC commonalities, leading to code duplication. This change enforce, wherever possible, a consistent and predictable scheme when it comes to code organisation and naming, The scheme chosen is what was used the most already, to try and minimise the size of the ugly resulting diff. Here are some of the rules applied: - Aligning clock names, variable names and IDs. - ID cannot change (used in DT) - Variable names w/ SoC name prefixes - Clock names w/o SoC name prefixes, except pclks for historic reasons - Composite clock systematic naming : mux: X_sel, div:X_div, gate:X - Parent table systematically named with the same name as the clock and a '_parents' suffix - Group various tables next to the related clock - etc ... Doing so removes what would otherwise show up as unrelated diff in following changes. It will allow to introduce common definitions for peripheral clocks, probe helpers, composite clocks, etc ... making further review and maintenance easier. Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-1-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-2-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-3-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-4-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-5-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-6-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-7-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-8-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-9-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-10-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-11-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-12-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-13-e163c9a1fc21@baylibre.com Link: https://lore.kernel.org/r/20250702-meson-clk-cleanup-24-v1-14-e163c9a1fc21@baylibre.com Reviewed-by: Chuan Liu # For c3 and s4 [jbrunet: squashed all naming alignment changes together] Signed-off-by: Jerome Brunet --- drivers/clk/meson/a1-peripherals.c | 944 ++++++------- drivers/clk/meson/a1-pll.c | 76 +- drivers/clk/meson/axg-aoclk.c | 116 +- drivers/clk/meson/axg.c | 211 ++- drivers/clk/meson/c3-peripherals.c | 1227 +++++++++-------- drivers/clk/meson/c3-pll.c | 198 +-- drivers/clk/meson/g12a-aoclk.c | 207 +-- drivers/clk/meson/g12a.c | 2008 ++++++++++++++-------------- drivers/clk/meson/gxbb-aoclk.c | 104 +- drivers/clk/meson/gxbb.c | 573 ++++---- drivers/clk/meson/meson8-ddr.c | 27 +- drivers/clk/meson/meson8b.c | 714 +++++----- drivers/clk/meson/s4-peripherals.c | 746 +++++------ drivers/clk/meson/s4-pll.c | 34 +- 14 files changed, 3564 insertions(+), 3621 deletions(-) diff --git a/drivers/clk/meson/a1-peripherals.c b/drivers/clk/meson/a1-peripherals.c index 1f5d445d44fe..9e352dba5477 100644 --- a/drivers/clk/meson/a1-peripherals.c +++ b/drivers/clk/meson/a1-peripherals.c @@ -46,7 +46,7 @@ #define PSRAM_CLK_CTRL 0xf4 #define DMC_CLK_CTRL 0xf8 -static struct clk_regmap xtal_in = { +static struct clk_regmap a1_xtal_in = { .data = &(struct clk_regmap_gate_data){ .offset = SYS_OSCIN_CTRL, .bit_idx = 0, @@ -61,7 +61,7 @@ static struct clk_regmap xtal_in = { }, }; -static struct clk_regmap fixpll_in = { +static struct clk_regmap a1_fixpll_in = { .data = &(struct clk_regmap_gate_data){ .offset = SYS_OSCIN_CTRL, .bit_idx = 1, @@ -76,7 +76,7 @@ static struct clk_regmap fixpll_in = { }, }; -static struct clk_regmap usb_phy_in = { +static struct clk_regmap a1_usb_phy_in = { .data = &(struct clk_regmap_gate_data){ .offset = SYS_OSCIN_CTRL, .bit_idx = 2, @@ -91,7 +91,7 @@ static struct clk_regmap usb_phy_in = { }, }; -static struct clk_regmap usb_ctrl_in = { +static struct clk_regmap a1_usb_ctrl_in = { .data = &(struct clk_regmap_gate_data){ .offset = SYS_OSCIN_CTRL, .bit_idx = 3, @@ -106,7 +106,7 @@ static struct clk_regmap usb_ctrl_in = { }, }; -static struct clk_regmap hifipll_in = { +static struct clk_regmap a1_hifipll_in = { .data = &(struct clk_regmap_gate_data){ .offset = SYS_OSCIN_CTRL, .bit_idx = 4, @@ -121,7 +121,7 @@ static struct clk_regmap hifipll_in = { }, }; -static struct clk_regmap syspll_in = { +static struct clk_regmap a1_syspll_in = { .data = &(struct clk_regmap_gate_data){ .offset = SYS_OSCIN_CTRL, .bit_idx = 5, @@ -136,7 +136,7 @@ static struct clk_regmap syspll_in = { }, }; -static struct clk_regmap dds_in = { +static struct clk_regmap a1_dds_in = { .data = &(struct clk_regmap_gate_data){ .offset = SYS_OSCIN_CTRL, .bit_idx = 6, @@ -151,7 +151,7 @@ static struct clk_regmap dds_in = { }, }; -static struct clk_regmap rtc_32k_in = { +static struct clk_regmap a1_rtc_32k_in = { .data = &(struct clk_regmap_gate_data){ .offset = RTC_BY_OSCIN_CTRL0, .bit_idx = 31, @@ -166,7 +166,7 @@ static struct clk_regmap rtc_32k_in = { }, }; -static const struct meson_clk_dualdiv_param clk_32k_div_table[] = { +static const struct meson_clk_dualdiv_param a1_32k_div_table[] = { { .dual = 1, .n1 = 733, @@ -177,7 +177,7 @@ static const struct meson_clk_dualdiv_param clk_32k_div_table[] = { {} }; -static struct clk_regmap rtc_32k_div = { +static struct clk_regmap a1_rtc_32k_div = { .data = &(struct meson_clk_dualdiv_data){ .n1 = { .reg_off = RTC_BY_OSCIN_CTRL0, @@ -204,19 +204,19 @@ static struct clk_regmap rtc_32k_div = { .shift = 28, .width = 1, }, - .table = clk_32k_div_table, + .table = a1_32k_div_table, }, .hw.init = &(struct clk_init_data){ .name = "rtc_32k_div", .ops = &meson_clk_dualdiv_ops, .parent_hws = (const struct clk_hw *[]) { - &rtc_32k_in.hw + &a1_rtc_32k_in.hw }, .num_parents = 1, }, }; -static struct clk_regmap rtc_32k_xtal = { +static struct clk_regmap a1_rtc_32k_xtal = { .data = &(struct clk_regmap_gate_data){ .offset = RTC_BY_OSCIN_CTRL1, .bit_idx = 24, @@ -225,13 +225,13 @@ static struct clk_regmap rtc_32k_xtal = { .name = "rtc_32k_xtal", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &rtc_32k_in.hw + &a1_rtc_32k_in.hw }, .num_parents = 1, }, }; -static struct clk_regmap rtc_32k_sel = { +static struct clk_regmap a1_rtc_32k_sel = { .data = &(struct clk_regmap_mux_data) { .offset = RTC_CTRL, .mask = 0x3, @@ -242,15 +242,15 @@ static struct clk_regmap rtc_32k_sel = { .name = "rtc_32k_sel", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &rtc_32k_xtal.hw, - &rtc_32k_div.hw, + &a1_rtc_32k_xtal.hw, + &a1_rtc_32k_div.hw, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap rtc = { +static struct clk_regmap a1_rtc = { .data = &(struct clk_regmap_gate_data){ .offset = RTC_BY_OSCIN_CTRL0, .bit_idx = 30, @@ -259,38 +259,38 @@ static struct clk_regmap rtc = { .name = "rtc", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &rtc_32k_sel.hw + &a1_rtc_32k_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static u32 mux_table_sys[] = { 0, 1, 2, 3, 7 }; -static const struct clk_parent_data sys_parents[] = { +static u32 a1_sys_parents_val_table[] = { 0, 1, 2, 3, 7 }; +static const struct clk_parent_data a1_sys_parents[] = { { .fw_name = "xtal" }, { .fw_name = "fclk_div2" }, { .fw_name = "fclk_div3" }, { .fw_name = "fclk_div5" }, - { .hw = &rtc.hw }, + { .hw = &a1_rtc.hw }, }; -static struct clk_regmap sys_b_sel = { +static struct clk_regmap a1_sys_b_sel = { .data = &(struct clk_regmap_mux_data){ .offset = SYS_CLK_CTRL0, .mask = 0x7, .shift = 26, - .table = mux_table_sys, + .table = a1_sys_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "sys_b_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_data = sys_parents, - .num_parents = ARRAY_SIZE(sys_parents), + .parent_data = a1_sys_parents, + .num_parents = ARRAY_SIZE(a1_sys_parents), }, }; -static struct clk_regmap sys_b_div = { +static struct clk_regmap a1_sys_b_div = { .data = &(struct clk_regmap_div_data){ .offset = SYS_CLK_CTRL0, .shift = 16, @@ -300,14 +300,14 @@ static struct clk_regmap sys_b_div = { .name = "sys_b_div", .ops = &clk_regmap_divider_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &sys_b_sel.hw + &a1_sys_b_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap sys_b = { +static struct clk_regmap a1_sys_b = { .data = &(struct clk_regmap_gate_data){ .offset = SYS_CLK_CTRL0, .bit_idx = 29, @@ -316,29 +316,29 @@ static struct clk_regmap sys_b = { .name = "sys_b", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &sys_b_div.hw + &a1_sys_b_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap sys_a_sel = { +static struct clk_regmap a1_sys_a_sel = { .data = &(struct clk_regmap_mux_data){ .offset = SYS_CLK_CTRL0, .mask = 0x7, .shift = 10, - .table = mux_table_sys, + .table = a1_sys_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "sys_a_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_data = sys_parents, - .num_parents = ARRAY_SIZE(sys_parents), + .parent_data = a1_sys_parents, + .num_parents = ARRAY_SIZE(a1_sys_parents), }, }; -static struct clk_regmap sys_a_div = { +static struct clk_regmap a1_sys_a_div = { .data = &(struct clk_regmap_div_data){ .offset = SYS_CLK_CTRL0, .shift = 0, @@ -348,14 +348,14 @@ static struct clk_regmap sys_a_div = { .name = "sys_a_div", .ops = &clk_regmap_divider_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &sys_a_sel.hw + &a1_sys_a_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap sys_a = { +static struct clk_regmap a1_sys_a = { .data = &(struct clk_regmap_gate_data){ .offset = SYS_CLK_CTRL0, .bit_idx = 13, @@ -364,14 +364,14 @@ static struct clk_regmap sys_a = { .name = "sys_a", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &sys_a_div.hw + &a1_sys_a_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap sys = { +static struct clk_regmap a1_sys = { .data = &(struct clk_regmap_mux_data){ .offset = SYS_CLK_CTRL0, .mask = 0x1, @@ -381,8 +381,8 @@ static struct clk_regmap sys = { .name = "sys", .ops = &clk_regmap_mux_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &sys_a.hw, - &sys_b.hw, + &a1_sys_a.hw, + &a1_sys_b.hw, }, .num_parents = 2, /* @@ -398,32 +398,32 @@ static struct clk_regmap sys = { }, }; -static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 }; -static const struct clk_parent_data dsp_ab_parent_data[] = { +static u32 a1_dsp_parents_val_table[] = { 0, 1, 2, 3, 4, 7 }; +static const struct clk_parent_data a1_dsp_parents[] = { { .fw_name = "xtal", }, { .fw_name = "fclk_div2", }, { .fw_name = "fclk_div3", }, { .fw_name = "fclk_div5", }, { .fw_name = "hifi_pll", }, - { .hw = &rtc.hw }, + { .hw = &a1_rtc.hw }, }; -static struct clk_regmap dspa_a_sel = { +static struct clk_regmap a1_dspa_a_sel = { .data = &(struct clk_regmap_mux_data){ .offset = DSPA_CLK_CTRL0, .mask = 0x7, .shift = 10, - .table = mux_table_dsp_ab, + .table = a1_dsp_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "dspa_a_sel", .ops = &clk_regmap_mux_ops, - .parent_data = dsp_ab_parent_data, - .num_parents = ARRAY_SIZE(dsp_ab_parent_data), + .parent_data = a1_dsp_parents, + .num_parents = ARRAY_SIZE(a1_dsp_parents), }, }; -static struct clk_regmap dspa_a_div = { +static struct clk_regmap a1_dspa_a_div = { .data = &(struct clk_regmap_div_data){ .offset = DSPA_CLK_CTRL0, .shift = 0, @@ -433,14 +433,14 @@ static struct clk_regmap dspa_a_div = { .name = "dspa_a_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &dspa_a_sel.hw + &a1_dspa_a_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspa_a = { +static struct clk_regmap a1_dspa_a = { .data = &(struct clk_regmap_gate_data){ .offset = DSPA_CLK_CTRL0, .bit_idx = 13, @@ -449,29 +449,29 @@ static struct clk_regmap dspa_a = { .name = "dspa_a", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &dspa_a_div.hw + &a1_dspa_a_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspa_b_sel = { +static struct clk_regmap a1_dspa_b_sel = { .data = &(struct clk_regmap_mux_data){ .offset = DSPA_CLK_CTRL0, .mask = 0x7, .shift = 26, - .table = mux_table_dsp_ab, + .table = a1_dsp_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "dspa_b_sel", .ops = &clk_regmap_mux_ops, - .parent_data = dsp_ab_parent_data, - .num_parents = ARRAY_SIZE(dsp_ab_parent_data), + .parent_data = a1_dsp_parents, + .num_parents = ARRAY_SIZE(a1_dsp_parents), }, }; -static struct clk_regmap dspa_b_div = { +static struct clk_regmap a1_dspa_b_div = { .data = &(struct clk_regmap_div_data){ .offset = DSPA_CLK_CTRL0, .shift = 16, @@ -481,14 +481,14 @@ static struct clk_regmap dspa_b_div = { .name = "dspa_b_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &dspa_b_sel.hw + &a1_dspa_b_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspa_b = { +static struct clk_regmap a1_dspa_b = { .data = &(struct clk_regmap_gate_data){ .offset = DSPA_CLK_CTRL0, .bit_idx = 29, @@ -497,14 +497,14 @@ static struct clk_regmap dspa_b = { .name = "dspa_b", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &dspa_b_div.hw + &a1_dspa_b_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspa_sel = { +static struct clk_regmap a1_dspa_sel = { .data = &(struct clk_regmap_mux_data){ .offset = DSPA_CLK_CTRL0, .mask = 0x1, @@ -514,15 +514,15 @@ static struct clk_regmap dspa_sel = { .name = "dspa_sel", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &dspa_a.hw, - &dspa_b.hw, + &a1_dspa_a.hw, + &a1_dspa_b.hw, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspa_en = { +static struct clk_regmap a1_dspa_en = { .data = &(struct clk_regmap_gate_data){ .offset = DSPA_CLK_EN, .bit_idx = 1, @@ -531,14 +531,14 @@ static struct clk_regmap dspa_en = { .name = "dspa_en", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &dspa_sel.hw + &a1_dspa_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspa_en_nic = { +static struct clk_regmap a1_dspa_en_nic = { .data = &(struct clk_regmap_gate_data){ .offset = DSPA_CLK_EN, .bit_idx = 0, @@ -547,29 +547,29 @@ static struct clk_regmap dspa_en_nic = { .name = "dspa_en_nic", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &dspa_sel.hw + &a1_dspa_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspb_a_sel = { +static struct clk_regmap a1_dspb_a_sel = { .data = &(struct clk_regmap_mux_data){ .offset = DSPB_CLK_CTRL0, .mask = 0x7, .shift = 10, - .table = mux_table_dsp_ab, + .table = a1_dsp_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "dspb_a_sel", .ops = &clk_regmap_mux_ops, - .parent_data = dsp_ab_parent_data, - .num_parents = ARRAY_SIZE(dsp_ab_parent_data), + .parent_data = a1_dsp_parents, + .num_parents = ARRAY_SIZE(a1_dsp_parents), }, }; -static struct clk_regmap dspb_a_div = { +static struct clk_regmap a1_dspb_a_div = { .data = &(struct clk_regmap_div_data){ .offset = DSPB_CLK_CTRL0, .shift = 0, @@ -579,14 +579,14 @@ static struct clk_regmap dspb_a_div = { .name = "dspb_a_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &dspb_a_sel.hw + &a1_dspb_a_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspb_a = { +static struct clk_regmap a1_dspb_a = { .data = &(struct clk_regmap_gate_data){ .offset = DSPB_CLK_CTRL0, .bit_idx = 13, @@ -595,29 +595,29 @@ static struct clk_regmap dspb_a = { .name = "dspb_a", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &dspb_a_div.hw + &a1_dspb_a_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspb_b_sel = { +static struct clk_regmap a1_dspb_b_sel = { .data = &(struct clk_regmap_mux_data){ .offset = DSPB_CLK_CTRL0, .mask = 0x7, .shift = 26, - .table = mux_table_dsp_ab, + .table = a1_dsp_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "dspb_b_sel", .ops = &clk_regmap_mux_ops, - .parent_data = dsp_ab_parent_data, - .num_parents = ARRAY_SIZE(dsp_ab_parent_data), + .parent_data = a1_dsp_parents, + .num_parents = ARRAY_SIZE(a1_dsp_parents), }, }; -static struct clk_regmap dspb_b_div = { +static struct clk_regmap a1_dspb_b_div = { .data = &(struct clk_regmap_div_data){ .offset = DSPB_CLK_CTRL0, .shift = 16, @@ -627,14 +627,14 @@ static struct clk_regmap dspb_b_div = { .name = "dspb_b_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &dspb_b_sel.hw + &a1_dspb_b_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspb_b = { +static struct clk_regmap a1_dspb_b = { .data = &(struct clk_regmap_gate_data){ .offset = DSPB_CLK_CTRL0, .bit_idx = 29, @@ -643,14 +643,14 @@ static struct clk_regmap dspb_b = { .name = "dspb_b", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &dspb_b_div.hw + &a1_dspb_b_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspb_sel = { +static struct clk_regmap a1_dspb_sel = { .data = &(struct clk_regmap_mux_data){ .offset = DSPB_CLK_CTRL0, .mask = 0x1, @@ -660,15 +660,15 @@ static struct clk_regmap dspb_sel = { .name = "dspb_sel", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &dspb_a.hw, - &dspb_b.hw, + &a1_dspb_a.hw, + &a1_dspb_b.hw, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspb_en = { +static struct clk_regmap a1_dspb_en = { .data = &(struct clk_regmap_gate_data){ .offset = DSPB_CLK_EN, .bit_idx = 1, @@ -677,14 +677,14 @@ static struct clk_regmap dspb_en = { .name = "dspb_en", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &dspb_sel.hw + &a1_dspb_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dspb_en_nic = { +static struct clk_regmap a1_dspb_en_nic = { .data = &(struct clk_regmap_gate_data){ .offset = DSPB_CLK_EN, .bit_idx = 0, @@ -693,14 +693,14 @@ static struct clk_regmap dspb_en_nic = { .name = "dspb_en_nic", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &dspb_sel.hw + &a1_dspb_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap clk_24m = { +static struct clk_regmap a1_24m = { .data = &(struct clk_regmap_gate_data){ .offset = CLK12_24_CTRL, .bit_idx = 11, @@ -715,20 +715,20 @@ static struct clk_regmap clk_24m = { }, }; -static struct clk_fixed_factor clk_24m_div2 = { +static struct clk_fixed_factor a1_24m_div2 = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ .name = "24m_div2", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &clk_24m.hw + &a1_24m.hw }, .num_parents = 1, }, }; -static struct clk_regmap clk_12m = { +static struct clk_regmap a1_12m = { .data = &(struct clk_regmap_gate_data){ .offset = CLK12_24_CTRL, .bit_idx = 10, @@ -737,13 +737,13 @@ static struct clk_regmap clk_12m = { .name = "12m", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &clk_24m_div2.hw + &a1_24m_div2.hw }, .num_parents = 1, }, }; -static struct clk_regmap fclk_div2_divn_pre = { +static struct clk_regmap a1_fclk_div2_divn_pre = { .data = &(struct clk_regmap_div_data){ .offset = CLK12_24_CTRL, .shift = 0, @@ -759,7 +759,7 @@ static struct clk_regmap fclk_div2_divn_pre = { }, }; -static struct clk_regmap fclk_div2_divn = { +static struct clk_regmap a1_fclk_div2_divn = { .data = &(struct clk_regmap_gate_data){ .offset = CLK12_24_CTRL, .bit_idx = 12, @@ -768,7 +768,7 @@ static struct clk_regmap fclk_div2_divn = { .name = "fclk_div2_divn", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div2_divn_pre.hw + &a1_fclk_div2_divn_pre.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -779,10 +779,10 @@ static struct clk_regmap fclk_div2_divn = { * the index 2 is sys_pll_div16, it will be implemented in the CPU clock driver, * the index 4 is the clock measurement source, it's not supported yet */ -static u32 gen_table[] = { 0, 1, 3, 5, 6, 7, 8 }; -static const struct clk_parent_data gen_parent_data[] = { +static u32 a1_gen_parents_val_table[] = { 0, 1, 3, 5, 6, 7, 8 }; +static const struct clk_parent_data a1_gen_parents[] = { { .fw_name = "xtal", }, - { .hw = &rtc.hw }, + { .hw = &a1_rtc.hw }, { .fw_name = "hifi_pll", }, { .fw_name = "fclk_div2", }, { .fw_name = "fclk_div3", }, @@ -790,18 +790,18 @@ static const struct clk_parent_data gen_parent_data[] = { { .fw_name = "fclk_div7", }, }; -static struct clk_regmap gen_sel = { +static struct clk_regmap a1_gen_sel = { .data = &(struct clk_regmap_mux_data){ .offset = GEN_CLK_CTRL, .mask = 0xf, .shift = 12, - .table = gen_table, + .table = a1_gen_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "gen_sel", .ops = &clk_regmap_mux_ops, - .parent_data = gen_parent_data, - .num_parents = ARRAY_SIZE(gen_parent_data), + .parent_data = a1_gen_parents, + .num_parents = ARRAY_SIZE(a1_gen_parents), /* * The GEN clock can be connected to an external pad, so it * may be set up directly from the device tree. Additionally, @@ -813,7 +813,7 @@ static struct clk_regmap gen_sel = { }, }; -static struct clk_regmap gen_div = { +static struct clk_regmap a1_gen_div = { .data = &(struct clk_regmap_div_data){ .offset = GEN_CLK_CTRL, .shift = 0, @@ -823,14 +823,14 @@ static struct clk_regmap gen_div = { .name = "gen_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &gen_sel.hw + &a1_gen_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap gen = { +static struct clk_regmap a1_gen = { .data = &(struct clk_regmap_gate_data){ .offset = GEN_CLK_CTRL, .bit_idx = 11, @@ -839,14 +839,14 @@ static struct clk_regmap gen = { .name = "gen", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &gen_div.hw + &a1_gen_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap saradc_sel = { +static struct clk_regmap a1_saradc_sel = { .data = &(struct clk_regmap_mux_data){ .offset = SAR_ADC_CLK_CTRL, .mask = 0x1, @@ -857,13 +857,13 @@ static struct clk_regmap saradc_sel = { .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { { .fw_name = "xtal", }, - { .hw = &sys.hw, }, + { .hw = &a1_sys.hw, }, }, .num_parents = 2, }, }; -static struct clk_regmap saradc_div = { +static struct clk_regmap a1_saradc_div = { .data = &(struct clk_regmap_div_data){ .offset = SAR_ADC_CLK_CTRL, .shift = 0, @@ -873,14 +873,14 @@ static struct clk_regmap saradc_div = { .name = "saradc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &saradc_sel.hw + &a1_saradc_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap saradc = { +static struct clk_regmap a1_saradc = { .data = &(struct clk_regmap_gate_data){ .offset = SAR_ADC_CLK_CTRL, .bit_idx = 8, @@ -889,20 +889,20 @@ static struct clk_regmap saradc = { .name = "saradc", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &saradc_div.hw + &a1_saradc_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data pwm_abcd_parents[] = { +static const struct clk_parent_data a1_pwm_abcd_parents[] = { { .fw_name = "xtal", }, - { .hw = &sys.hw }, - { .hw = &rtc.hw }, + { .hw = &a1_sys.hw }, + { .hw = &a1_rtc.hw }, }; -static struct clk_regmap pwm_a_sel = { +static struct clk_regmap a1_pwm_a_sel = { .data = &(struct clk_regmap_mux_data){ .offset = PWM_CLK_AB_CTRL, .mask = 0x1, @@ -911,12 +911,12 @@ static struct clk_regmap pwm_a_sel = { .hw.init = &(struct clk_init_data){ .name = "pwm_a_sel", .ops = &clk_regmap_mux_ops, - .parent_data = pwm_abcd_parents, - .num_parents = ARRAY_SIZE(pwm_abcd_parents), + .parent_data = a1_pwm_abcd_parents, + .num_parents = ARRAY_SIZE(a1_pwm_abcd_parents), }, }; -static struct clk_regmap pwm_a_div = { +static struct clk_regmap a1_pwm_a_div = { .data = &(struct clk_regmap_div_data){ .offset = PWM_CLK_AB_CTRL, .shift = 0, @@ -926,14 +926,14 @@ static struct clk_regmap pwm_a_div = { .name = "pwm_a_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_a_sel.hw + &a1_pwm_a_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap pwm_a = { +static struct clk_regmap a1_pwm_a = { .data = &(struct clk_regmap_gate_data){ .offset = PWM_CLK_AB_CTRL, .bit_idx = 8, @@ -942,14 +942,14 @@ static struct clk_regmap pwm_a = { .name = "pwm_a", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_a_div.hw + &a1_pwm_a_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap pwm_b_sel = { +static struct clk_regmap a1_pwm_b_sel = { .data = &(struct clk_regmap_mux_data){ .offset = PWM_CLK_AB_CTRL, .mask = 0x1, @@ -958,12 +958,12 @@ static struct clk_regmap pwm_b_sel = { .hw.init = &(struct clk_init_data){ .name = "pwm_b_sel", .ops = &clk_regmap_mux_ops, - .parent_data = pwm_abcd_parents, - .num_parents = ARRAY_SIZE(pwm_abcd_parents), + .parent_data = a1_pwm_abcd_parents, + .num_parents = ARRAY_SIZE(a1_pwm_abcd_parents), }, }; -static struct clk_regmap pwm_b_div = { +static struct clk_regmap a1_pwm_b_div = { .data = &(struct clk_regmap_div_data){ .offset = PWM_CLK_AB_CTRL, .shift = 16, @@ -973,14 +973,14 @@ static struct clk_regmap pwm_b_div = { .name = "pwm_b_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_b_sel.hw + &a1_pwm_b_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap pwm_b = { +static struct clk_regmap a1_pwm_b = { .data = &(struct clk_regmap_gate_data){ .offset = PWM_CLK_AB_CTRL, .bit_idx = 24, @@ -989,14 +989,14 @@ static struct clk_regmap pwm_b = { .name = "pwm_b", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_b_div.hw + &a1_pwm_b_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap pwm_c_sel = { +static struct clk_regmap a1_pwm_c_sel = { .data = &(struct clk_regmap_mux_data){ .offset = PWM_CLK_CD_CTRL, .mask = 0x1, @@ -1005,12 +1005,12 @@ static struct clk_regmap pwm_c_sel = { .hw.init = &(struct clk_init_data){ .name = "pwm_c_sel", .ops = &clk_regmap_mux_ops, - .parent_data = pwm_abcd_parents, - .num_parents = ARRAY_SIZE(pwm_abcd_parents), + .parent_data = a1_pwm_abcd_parents, + .num_parents = ARRAY_SIZE(a1_pwm_abcd_parents), }, }; -static struct clk_regmap pwm_c_div = { +static struct clk_regmap a1_pwm_c_div = { .data = &(struct clk_regmap_div_data){ .offset = PWM_CLK_CD_CTRL, .shift = 0, @@ -1020,14 +1020,14 @@ static struct clk_regmap pwm_c_div = { .name = "pwm_c_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_c_sel.hw + &a1_pwm_c_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap pwm_c = { +static struct clk_regmap a1_pwm_c = { .data = &(struct clk_regmap_gate_data){ .offset = PWM_CLK_CD_CTRL, .bit_idx = 8, @@ -1036,14 +1036,14 @@ static struct clk_regmap pwm_c = { .name = "pwm_c", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_c_div.hw + &a1_pwm_c_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap pwm_d_sel = { +static struct clk_regmap a1_pwm_d_sel = { .data = &(struct clk_regmap_mux_data){ .offset = PWM_CLK_CD_CTRL, .mask = 0x1, @@ -1052,12 +1052,12 @@ static struct clk_regmap pwm_d_sel = { .hw.init = &(struct clk_init_data){ .name = "pwm_d_sel", .ops = &clk_regmap_mux_ops, - .parent_data = pwm_abcd_parents, - .num_parents = ARRAY_SIZE(pwm_abcd_parents), + .parent_data = a1_pwm_abcd_parents, + .num_parents = ARRAY_SIZE(a1_pwm_abcd_parents), }, }; -static struct clk_regmap pwm_d_div = { +static struct clk_regmap a1_pwm_d_div = { .data = &(struct clk_regmap_div_data){ .offset = PWM_CLK_CD_CTRL, .shift = 16, @@ -1067,14 +1067,14 @@ static struct clk_regmap pwm_d_div = { .name = "pwm_d_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_d_sel.hw + &a1_pwm_d_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap pwm_d = { +static struct clk_regmap a1_pwm_d = { .data = &(struct clk_regmap_gate_data){ .offset = PWM_CLK_CD_CTRL, .bit_idx = 24, @@ -1083,21 +1083,21 @@ static struct clk_regmap pwm_d = { .name = "pwm_d", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_d_div.hw + &a1_pwm_d_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data pwm_ef_parents[] = { +static const struct clk_parent_data a1_pwm_ef_parents[] = { { .fw_name = "xtal", }, - { .hw = &sys.hw }, + { .hw = &a1_sys.hw }, { .fw_name = "fclk_div5", }, - { .hw = &rtc.hw }, + { .hw = &a1_rtc.hw }, }; -static struct clk_regmap pwm_e_sel = { +static struct clk_regmap a1_pwm_e_sel = { .data = &(struct clk_regmap_mux_data){ .offset = PWM_CLK_EF_CTRL, .mask = 0x3, @@ -1106,12 +1106,12 @@ static struct clk_regmap pwm_e_sel = { .hw.init = &(struct clk_init_data){ .name = "pwm_e_sel", .ops = &clk_regmap_mux_ops, - .parent_data = pwm_ef_parents, - .num_parents = ARRAY_SIZE(pwm_ef_parents), + .parent_data = a1_pwm_ef_parents, + .num_parents = ARRAY_SIZE(a1_pwm_ef_parents), }, }; -static struct clk_regmap pwm_e_div = { +static struct clk_regmap a1_pwm_e_div = { .data = &(struct clk_regmap_div_data){ .offset = PWM_CLK_EF_CTRL, .shift = 0, @@ -1121,14 +1121,14 @@ static struct clk_regmap pwm_e_div = { .name = "pwm_e_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_e_sel.hw + &a1_pwm_e_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap pwm_e = { +static struct clk_regmap a1_pwm_e = { .data = &(struct clk_regmap_gate_data){ .offset = PWM_CLK_EF_CTRL, .bit_idx = 8, @@ -1137,14 +1137,14 @@ static struct clk_regmap pwm_e = { .name = "pwm_e", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_e_div.hw + &a1_pwm_e_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap pwm_f_sel = { +static struct clk_regmap a1_pwm_f_sel = { .data = &(struct clk_regmap_mux_data){ .offset = PWM_CLK_EF_CTRL, .mask = 0x3, @@ -1153,12 +1153,12 @@ static struct clk_regmap pwm_f_sel = { .hw.init = &(struct clk_init_data){ .name = "pwm_f_sel", .ops = &clk_regmap_mux_ops, - .parent_data = pwm_ef_parents, - .num_parents = ARRAY_SIZE(pwm_ef_parents), + .parent_data = a1_pwm_ef_parents, + .num_parents = ARRAY_SIZE(a1_pwm_ef_parents), }, }; -static struct clk_regmap pwm_f_div = { +static struct clk_regmap a1_pwm_f_div = { .data = &(struct clk_regmap_div_data){ .offset = PWM_CLK_EF_CTRL, .shift = 16, @@ -1168,14 +1168,14 @@ static struct clk_regmap pwm_f_div = { .name = "pwm_f_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_f_sel.hw + &a1_pwm_f_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap pwm_f = { +static struct clk_regmap a1_pwm_f = { .data = &(struct clk_regmap_gate_data){ .offset = PWM_CLK_EF_CTRL, .bit_idx = 24, @@ -1184,7 +1184,7 @@ static struct clk_regmap pwm_f = { .name = "pwm_f", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &pwm_f_div.hw + &a1_pwm_f_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1200,14 +1200,14 @@ static struct clk_regmap pwm_f = { * --------------------|/ * 24M */ -static const struct clk_parent_data spicc_spifc_parents[] = { +static const struct clk_parent_data a1_spi_parents[] = { { .fw_name = "fclk_div2"}, { .fw_name = "fclk_div3"}, { .fw_name = "fclk_div5"}, { .fw_name = "hifi_pll" }, }; -static struct clk_regmap spicc_sel = { +static struct clk_regmap a1_spicc_sel = { .data = &(struct clk_regmap_mux_data){ .offset = SPICC_CLK_CTRL, .mask = 0x3, @@ -1216,12 +1216,12 @@ static struct clk_regmap spicc_sel = { .hw.init = &(struct clk_init_data){ .name = "spicc_sel", .ops = &clk_regmap_mux_ops, - .parent_data = spicc_spifc_parents, - .num_parents = ARRAY_SIZE(spicc_spifc_parents), + .parent_data = a1_spi_parents, + .num_parents = ARRAY_SIZE(a1_spi_parents), }, }; -static struct clk_regmap spicc_div = { +static struct clk_regmap a1_spicc_div = { .data = &(struct clk_regmap_div_data){ .offset = SPICC_CLK_CTRL, .shift = 0, @@ -1231,14 +1231,14 @@ static struct clk_regmap spicc_div = { .name = "spicc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &spicc_sel.hw + &a1_spicc_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap spicc_sel2 = { +static struct clk_regmap a1_spicc_sel2 = { .data = &(struct clk_regmap_mux_data){ .offset = SPICC_CLK_CTRL, .mask = 0x1, @@ -1248,7 +1248,7 @@ static struct clk_regmap spicc_sel2 = { .name = "spicc_sel2", .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { - { .hw = &spicc_div.hw }, + { .hw = &a1_spicc_div.hw }, { .fw_name = "xtal", }, }, .num_parents = 2, @@ -1256,7 +1256,7 @@ static struct clk_regmap spicc_sel2 = { }, }; -static struct clk_regmap spicc = { +static struct clk_regmap a1_spicc = { .data = &(struct clk_regmap_gate_data){ .offset = SPICC_CLK_CTRL, .bit_idx = 8, @@ -1265,14 +1265,14 @@ static struct clk_regmap spicc = { .name = "spicc", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &spicc_sel2.hw + &a1_spicc_sel2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap ts_div = { +static struct clk_regmap a1_ts_div = { .data = &(struct clk_regmap_div_data){ .offset = TS_CLK_CTRL, .shift = 0, @@ -1288,7 +1288,7 @@ static struct clk_regmap ts_div = { }, }; -static struct clk_regmap ts = { +static struct clk_regmap a1_ts = { .data = &(struct clk_regmap_gate_data){ .offset = TS_CLK_CTRL, .bit_idx = 8, @@ -1297,14 +1297,14 @@ static struct clk_regmap ts = { .name = "ts", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &ts_div.hw + &a1_ts_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap spifc_sel = { +static struct clk_regmap a1_spifc_sel = { .data = &(struct clk_regmap_mux_data){ .offset = SPIFC_CLK_CTRL, .mask = 0x3, @@ -1313,12 +1313,12 @@ static struct clk_regmap spifc_sel = { .hw.init = &(struct clk_init_data){ .name = "spifc_sel", .ops = &clk_regmap_mux_ops, - .parent_data = spicc_spifc_parents, - .num_parents = ARRAY_SIZE(spicc_spifc_parents), + .parent_data = a1_spi_parents, + .num_parents = ARRAY_SIZE(a1_spi_parents), }, }; -static struct clk_regmap spifc_div = { +static struct clk_regmap a1_spifc_div = { .data = &(struct clk_regmap_div_data){ .offset = SPIFC_CLK_CTRL, .shift = 0, @@ -1328,14 +1328,14 @@ static struct clk_regmap spifc_div = { .name = "spifc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &spifc_sel.hw + &a1_spifc_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap spifc_sel2 = { +static struct clk_regmap a1_spifc_sel2 = { .data = &(struct clk_regmap_mux_data){ .offset = SPIFC_CLK_CTRL, .mask = 0x1, @@ -1345,7 +1345,7 @@ static struct clk_regmap spifc_sel2 = { .name = "spifc_sel2", .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { - { .hw = &spifc_div.hw }, + { .hw = &a1_spifc_div.hw }, { .fw_name = "xtal", }, }, .num_parents = 2, @@ -1353,7 +1353,7 @@ static struct clk_regmap spifc_sel2 = { }, }; -static struct clk_regmap spifc = { +static struct clk_regmap a1_spifc = { .data = &(struct clk_regmap_gate_data){ .offset = SPIFC_CLK_CTRL, .bit_idx = 8, @@ -1362,21 +1362,21 @@ static struct clk_regmap spifc = { .name = "spifc", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &spifc_sel2.hw + &a1_spifc_sel2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data usb_bus_parents[] = { +static const struct clk_parent_data a1_usb_bus_parents[] = { { .fw_name = "xtal", }, - { .hw = &sys.hw }, + { .hw = &a1_sys.hw }, { .fw_name = "fclk_div3", }, { .fw_name = "fclk_div5", }, }; -static struct clk_regmap usb_bus_sel = { +static struct clk_regmap a1_usb_bus_sel = { .data = &(struct clk_regmap_mux_data){ .offset = USB_BUSCLK_CTRL, .mask = 0x3, @@ -1385,13 +1385,13 @@ static struct clk_regmap usb_bus_sel = { .hw.init = &(struct clk_init_data){ .name = "usb_bus_sel", .ops = &clk_regmap_mux_ops, - .parent_data = usb_bus_parents, - .num_parents = ARRAY_SIZE(usb_bus_parents), + .parent_data = a1_usb_bus_parents, + .num_parents = ARRAY_SIZE(a1_usb_bus_parents), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap usb_bus_div = { +static struct clk_regmap a1_usb_bus_div = { .data = &(struct clk_regmap_div_data){ .offset = USB_BUSCLK_CTRL, .shift = 0, @@ -1401,14 +1401,14 @@ static struct clk_regmap usb_bus_div = { .name = "usb_bus_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &usb_bus_sel.hw + &a1_usb_bus_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap usb_bus = { +static struct clk_regmap a1_usb_bus = { .data = &(struct clk_regmap_gate_data){ .offset = USB_BUSCLK_CTRL, .bit_idx = 8, @@ -1417,21 +1417,21 @@ static struct clk_regmap usb_bus = { .name = "usb_bus", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &usb_bus_div.hw + &a1_usb_bus_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data sd_emmc_psram_dmc_parents[] = { +static const struct clk_parent_data a1_sd_emmc_parents[] = { { .fw_name = "fclk_div2", }, { .fw_name = "fclk_div3", }, { .fw_name = "fclk_div5", }, { .fw_name = "hifi_pll", }, }; -static struct clk_regmap sd_emmc_sel = { +static struct clk_regmap a1_sd_emmc_sel = { .data = &(struct clk_regmap_mux_data){ .offset = SD_EMMC_CLK_CTRL, .mask = 0x3, @@ -1440,12 +1440,12 @@ static struct clk_regmap sd_emmc_sel = { .hw.init = &(struct clk_init_data){ .name = "sd_emmc_sel", .ops = &clk_regmap_mux_ops, - .parent_data = sd_emmc_psram_dmc_parents, - .num_parents = ARRAY_SIZE(sd_emmc_psram_dmc_parents), + .parent_data = a1_sd_emmc_parents, + .num_parents = ARRAY_SIZE(a1_sd_emmc_parents), }, }; -static struct clk_regmap sd_emmc_div = { +static struct clk_regmap a1_sd_emmc_div = { .data = &(struct clk_regmap_div_data){ .offset = SD_EMMC_CLK_CTRL, .shift = 0, @@ -1455,14 +1455,14 @@ static struct clk_regmap sd_emmc_div = { .name = "sd_emmc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &sd_emmc_sel.hw + &a1_sd_emmc_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap sd_emmc_sel2 = { +static struct clk_regmap a1_sd_emmc_sel2 = { .data = &(struct clk_regmap_mux_data){ .offset = SD_EMMC_CLK_CTRL, .mask = 0x1, @@ -1472,7 +1472,7 @@ static struct clk_regmap sd_emmc_sel2 = { .name = "sd_emmc_sel2", .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { - { .hw = &sd_emmc_div.hw }, + { .hw = &a1_sd_emmc_div.hw }, { .fw_name = "xtal", }, }, .num_parents = 2, @@ -1480,7 +1480,7 @@ static struct clk_regmap sd_emmc_sel2 = { }, }; -static struct clk_regmap sd_emmc = { +static struct clk_regmap a1_sd_emmc = { .data = &(struct clk_regmap_gate_data){ .offset = SD_EMMC_CLK_CTRL, .bit_idx = 8, @@ -1489,14 +1489,14 @@ static struct clk_regmap sd_emmc = { .name = "sd_emmc", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &sd_emmc_sel2.hw + &a1_sd_emmc_sel2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap psram_sel = { +static struct clk_regmap a1_psram_sel = { .data = &(struct clk_regmap_mux_data){ .offset = PSRAM_CLK_CTRL, .mask = 0x3, @@ -1505,12 +1505,12 @@ static struct clk_regmap psram_sel = { .hw.init = &(struct clk_init_data){ .name = "psram_sel", .ops = &clk_regmap_mux_ops, - .parent_data = sd_emmc_psram_dmc_parents, - .num_parents = ARRAY_SIZE(sd_emmc_psram_dmc_parents), + .parent_data = a1_sd_emmc_parents, + .num_parents = ARRAY_SIZE(a1_sd_emmc_parents), }, }; -static struct clk_regmap psram_div = { +static struct clk_regmap a1_psram_div = { .data = &(struct clk_regmap_div_data){ .offset = PSRAM_CLK_CTRL, .shift = 0, @@ -1520,14 +1520,14 @@ static struct clk_regmap psram_div = { .name = "psram_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &psram_sel.hw + &a1_psram_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap psram_sel2 = { +static struct clk_regmap a1_psram_sel2 = { .data = &(struct clk_regmap_mux_data){ .offset = PSRAM_CLK_CTRL, .mask = 0x1, @@ -1537,7 +1537,7 @@ static struct clk_regmap psram_sel2 = { .name = "psram_sel2", .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { - { .hw = &psram_div.hw }, + { .hw = &a1_psram_div.hw }, { .fw_name = "xtal", }, }, .num_parents = 2, @@ -1545,7 +1545,7 @@ static struct clk_regmap psram_sel2 = { }, }; -static struct clk_regmap psram = { +static struct clk_regmap a1_psram = { .data = &(struct clk_regmap_gate_data){ .offset = PSRAM_CLK_CTRL, .bit_idx = 8, @@ -1554,14 +1554,14 @@ static struct clk_regmap psram = { .name = "psram", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &psram_sel2.hw + &a1_psram_sel2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dmc_sel = { +static struct clk_regmap a1_dmc_sel = { .data = &(struct clk_regmap_mux_data){ .offset = DMC_CLK_CTRL, .mask = 0x3, @@ -1570,12 +1570,12 @@ static struct clk_regmap dmc_sel = { .hw.init = &(struct clk_init_data){ .name = "dmc_sel", .ops = &clk_regmap_mux_ops, - .parent_data = sd_emmc_psram_dmc_parents, - .num_parents = ARRAY_SIZE(sd_emmc_psram_dmc_parents), + .parent_data = a1_sd_emmc_parents, + .num_parents = ARRAY_SIZE(a1_sd_emmc_parents), }, }; -static struct clk_regmap dmc_div = { +static struct clk_regmap a1_dmc_div = { .data = &(struct clk_regmap_div_data){ .offset = DMC_CLK_CTRL, .shift = 0, @@ -1585,14 +1585,14 @@ static struct clk_regmap dmc_div = { .name = "dmc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &dmc_sel.hw + &a1_dmc_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dmc_sel2 = { +static struct clk_regmap a1_dmc_sel2 = { .data = &(struct clk_regmap_mux_data){ .offset = DMC_CLK_CTRL, .mask = 0x1, @@ -1602,7 +1602,7 @@ static struct clk_regmap dmc_sel2 = { .name = "dmc_sel2", .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { - { .hw = &dmc_div.hw }, + { .hw = &a1_dmc_div.hw }, { .fw_name = "xtal", }, }, .num_parents = 2, @@ -1610,7 +1610,7 @@ static struct clk_regmap dmc_sel2 = { }, }; -static struct clk_regmap dmc = { +static struct clk_regmap a1_dmc = { .data = &(struct clk_regmap_gate_data){ .offset = DMC_CLK_CTRL, .bit_idx = 8, @@ -1619,14 +1619,14 @@ static struct clk_regmap dmc = { .name = "dmc", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &dmc_sel2.hw + &a1_dmc_sel2.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap ceca_32k_in = { +static struct clk_regmap a1_ceca_32k_in = { .data = &(struct clk_regmap_gate_data){ .offset = CECA_CLK_CTRL0, .bit_idx = 31, @@ -1641,7 +1641,7 @@ static struct clk_regmap ceca_32k_in = { }, }; -static struct clk_regmap ceca_32k_div = { +static struct clk_regmap a1_ceca_32k_div = { .data = &(struct meson_clk_dualdiv_data){ .n1 = { .reg_off = CECA_CLK_CTRL0, @@ -1668,19 +1668,19 @@ static struct clk_regmap ceca_32k_div = { .shift = 28, .width = 1, }, - .table = clk_32k_div_table, + .table = a1_32k_div_table, }, .hw.init = &(struct clk_init_data){ .name = "ceca_32k_div", .ops = &meson_clk_dualdiv_ops, .parent_hws = (const struct clk_hw *[]) { - &ceca_32k_in.hw + &a1_ceca_32k_in.hw }, .num_parents = 1, }, }; -static struct clk_regmap ceca_32k_sel_pre = { +static struct clk_regmap a1_ceca_32k_sel_pre = { .data = &(struct clk_regmap_mux_data) { .offset = CECA_CLK_CTRL1, .mask = 0x1, @@ -1691,15 +1691,15 @@ static struct clk_regmap ceca_32k_sel_pre = { .name = "ceca_32k_sel_pre", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &ceca_32k_div.hw, - &ceca_32k_in.hw, + &a1_ceca_32k_div.hw, + &a1_ceca_32k_in.hw, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap ceca_32k_sel = { +static struct clk_regmap a1_ceca_32k_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CECA_CLK_CTRL1, .mask = 0x1, @@ -1710,14 +1710,14 @@ static struct clk_regmap ceca_32k_sel = { .name = "ceca_32k_sel", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &ceca_32k_sel_pre.hw, - &rtc.hw, + &a1_ceca_32k_sel_pre.hw, + &a1_rtc.hw, }, .num_parents = 2, }, }; -static struct clk_regmap ceca_32k_out = { +static struct clk_regmap a1_ceca_32k_out = { .data = &(struct clk_regmap_gate_data){ .offset = CECA_CLK_CTRL0, .bit_idx = 30, @@ -1726,14 +1726,14 @@ static struct clk_regmap ceca_32k_out = { .name = "ceca_32k_out", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &ceca_32k_sel.hw + &a1_ceca_32k_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap cecb_32k_in = { +static struct clk_regmap a1_cecb_32k_in = { .data = &(struct clk_regmap_gate_data){ .offset = CECB_CLK_CTRL0, .bit_idx = 31, @@ -1748,7 +1748,7 @@ static struct clk_regmap cecb_32k_in = { }, }; -static struct clk_regmap cecb_32k_div = { +static struct clk_regmap a1_cecb_32k_div = { .data = &(struct meson_clk_dualdiv_data){ .n1 = { .reg_off = CECB_CLK_CTRL0, @@ -1775,19 +1775,19 @@ static struct clk_regmap cecb_32k_div = { .shift = 28, .width = 1, }, - .table = clk_32k_div_table, + .table = a1_32k_div_table, }, .hw.init = &(struct clk_init_data){ .name = "cecb_32k_div", .ops = &meson_clk_dualdiv_ops, .parent_hws = (const struct clk_hw *[]) { - &cecb_32k_in.hw + &a1_cecb_32k_in.hw }, .num_parents = 1, }, }; -static struct clk_regmap cecb_32k_sel_pre = { +static struct clk_regmap a1_cecb_32k_sel_pre = { .data = &(struct clk_regmap_mux_data) { .offset = CECB_CLK_CTRL1, .mask = 0x1, @@ -1798,15 +1798,15 @@ static struct clk_regmap cecb_32k_sel_pre = { .name = "cecb_32k_sel_pre", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &cecb_32k_div.hw, - &cecb_32k_in.hw, + &a1_cecb_32k_div.hw, + &a1_cecb_32k_in.hw, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap cecb_32k_sel = { +static struct clk_regmap a1_cecb_32k_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CECB_CLK_CTRL1, .mask = 0x1, @@ -1817,14 +1817,14 @@ static struct clk_regmap cecb_32k_sel = { .name = "cecb_32k_sel", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &cecb_32k_sel_pre.hw, - &rtc.hw, + &a1_cecb_32k_sel_pre.hw, + &a1_rtc.hw, }, .num_parents = 2, }, }; -static struct clk_regmap cecb_32k_out = { +static struct clk_regmap a1_cecb_32k_out = { .data = &(struct clk_regmap_gate_data){ .offset = CECB_CLK_CTRL0, .bit_idx = 30, @@ -1833,241 +1833,243 @@ static struct clk_regmap cecb_32k_out = { .name = "cecb_32k_out", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &cecb_32k_sel.hw + &a1_cecb_32k_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -#define MESON_GATE(_name, _reg, _bit) \ - MESON_PCLK(_name, _reg, _bit, &sys.hw) +#define A1_PCLK(_name, _reg, _bit) \ + MESON_PCLK(a1_##_name, _reg, _bit, &a1_sys.hw) -static MESON_GATE(clktree, SYS_CLK_EN0, 0); -static MESON_GATE(reset_ctrl, SYS_CLK_EN0, 1); -static MESON_GATE(analog_ctrl, SYS_CLK_EN0, 2); -static MESON_GATE(pwr_ctrl, SYS_CLK_EN0, 3); -static MESON_GATE(pad_ctrl, SYS_CLK_EN0, 4); -static MESON_GATE(sys_ctrl, SYS_CLK_EN0, 5); -static MESON_GATE(temp_sensor, SYS_CLK_EN0, 6); -static MESON_GATE(am2axi_dev, SYS_CLK_EN0, 7); -static MESON_GATE(spicc_b, SYS_CLK_EN0, 8); -static MESON_GATE(spicc_a, SYS_CLK_EN0, 9); -static MESON_GATE(msr, SYS_CLK_EN0, 10); -static MESON_GATE(audio, SYS_CLK_EN0, 11); -static MESON_GATE(jtag_ctrl, SYS_CLK_EN0, 12); -static MESON_GATE(saradc_en, SYS_CLK_EN0, 13); -static MESON_GATE(pwm_ef, SYS_CLK_EN0, 14); -static MESON_GATE(pwm_cd, SYS_CLK_EN0, 15); -static MESON_GATE(pwm_ab, SYS_CLK_EN0, 16); -static MESON_GATE(cec, SYS_CLK_EN0, 17); -static MESON_GATE(i2c_s, SYS_CLK_EN0, 18); -static MESON_GATE(ir_ctrl, SYS_CLK_EN0, 19); -static MESON_GATE(i2c_m_d, SYS_CLK_EN0, 20); -static MESON_GATE(i2c_m_c, SYS_CLK_EN0, 21); -static MESON_GATE(i2c_m_b, SYS_CLK_EN0, 22); -static MESON_GATE(i2c_m_a, SYS_CLK_EN0, 23); -static MESON_GATE(acodec, SYS_CLK_EN0, 24); -static MESON_GATE(otp, SYS_CLK_EN0, 25); -static MESON_GATE(sd_emmc_a, SYS_CLK_EN0, 26); -static MESON_GATE(usb_phy, SYS_CLK_EN0, 27); -static MESON_GATE(usb_ctrl, SYS_CLK_EN0, 28); -static MESON_GATE(sys_dspb, SYS_CLK_EN0, 29); -static MESON_GATE(sys_dspa, SYS_CLK_EN0, 30); -static MESON_GATE(dma, SYS_CLK_EN0, 31); -static MESON_GATE(irq_ctrl, SYS_CLK_EN1, 0); -static MESON_GATE(nic, SYS_CLK_EN1, 1); -static MESON_GATE(gic, SYS_CLK_EN1, 2); -static MESON_GATE(uart_c, SYS_CLK_EN1, 3); -static MESON_GATE(uart_b, SYS_CLK_EN1, 4); -static MESON_GATE(uart_a, SYS_CLK_EN1, 5); -static MESON_GATE(sys_psram, SYS_CLK_EN1, 6); -static MESON_GATE(rsa, SYS_CLK_EN1, 8); -static MESON_GATE(coresight, SYS_CLK_EN1, 9); -static MESON_GATE(am2axi_vad, AXI_CLK_EN, 0); -static MESON_GATE(audio_vad, AXI_CLK_EN, 1); -static MESON_GATE(axi_dmc, AXI_CLK_EN, 3); -static MESON_GATE(axi_psram, AXI_CLK_EN, 4); -static MESON_GATE(ramb, AXI_CLK_EN, 5); -static MESON_GATE(rama, AXI_CLK_EN, 6); -static MESON_GATE(axi_spifc, AXI_CLK_EN, 7); -static MESON_GATE(axi_nic, AXI_CLK_EN, 8); -static MESON_GATE(axi_dma, AXI_CLK_EN, 9); -static MESON_GATE(cpu_ctrl, AXI_CLK_EN, 10); -static MESON_GATE(rom, AXI_CLK_EN, 11); -static MESON_GATE(prod_i2c, AXI_CLK_EN, 12); +static A1_PCLK(clktree, SYS_CLK_EN0, 0); +static A1_PCLK(reset_ctrl, SYS_CLK_EN0, 1); +static A1_PCLK(analog_ctrl, SYS_CLK_EN0, 2); +static A1_PCLK(pwr_ctrl, SYS_CLK_EN0, 3); +static A1_PCLK(pad_ctrl, SYS_CLK_EN0, 4); +static A1_PCLK(sys_ctrl, SYS_CLK_EN0, 5); +static A1_PCLK(temp_sensor, SYS_CLK_EN0, 6); +static A1_PCLK(am2axi_dev, SYS_CLK_EN0, 7); +static A1_PCLK(spicc_b, SYS_CLK_EN0, 8); +static A1_PCLK(spicc_a, SYS_CLK_EN0, 9); +static A1_PCLK(msr, SYS_CLK_EN0, 10); +static A1_PCLK(audio, SYS_CLK_EN0, 11); +static A1_PCLK(jtag_ctrl, SYS_CLK_EN0, 12); +static A1_PCLK(saradc_en, SYS_CLK_EN0, 13); +static A1_PCLK(pwm_ef, SYS_CLK_EN0, 14); +static A1_PCLK(pwm_cd, SYS_CLK_EN0, 15); +static A1_PCLK(pwm_ab, SYS_CLK_EN0, 16); +static A1_PCLK(cec, SYS_CLK_EN0, 17); +static A1_PCLK(i2c_s, SYS_CLK_EN0, 18); +static A1_PCLK(ir_ctrl, SYS_CLK_EN0, 19); +static A1_PCLK(i2c_m_d, SYS_CLK_EN0, 20); +static A1_PCLK(i2c_m_c, SYS_CLK_EN0, 21); +static A1_PCLK(i2c_m_b, SYS_CLK_EN0, 22); +static A1_PCLK(i2c_m_a, SYS_CLK_EN0, 23); +static A1_PCLK(acodec, SYS_CLK_EN0, 24); +static A1_PCLK(otp, SYS_CLK_EN0, 25); +static A1_PCLK(sd_emmc_a, SYS_CLK_EN0, 26); +static A1_PCLK(usb_phy, SYS_CLK_EN0, 27); +static A1_PCLK(usb_ctrl, SYS_CLK_EN0, 28); +static A1_PCLK(sys_dspb, SYS_CLK_EN0, 29); +static A1_PCLK(sys_dspa, SYS_CLK_EN0, 30); +static A1_PCLK(dma, SYS_CLK_EN0, 31); + +static A1_PCLK(irq_ctrl, SYS_CLK_EN1, 0); +static A1_PCLK(nic, SYS_CLK_EN1, 1); +static A1_PCLK(gic, SYS_CLK_EN1, 2); +static A1_PCLK(uart_c, SYS_CLK_EN1, 3); +static A1_PCLK(uart_b, SYS_CLK_EN1, 4); +static A1_PCLK(uart_a, SYS_CLK_EN1, 5); +static A1_PCLK(sys_psram, SYS_CLK_EN1, 6); +static A1_PCLK(rsa, SYS_CLK_EN1, 8); +static A1_PCLK(coresight, SYS_CLK_EN1, 9); + +static A1_PCLK(am2axi_vad, AXI_CLK_EN, 0); +static A1_PCLK(audio_vad, AXI_CLK_EN, 1); +static A1_PCLK(axi_dmc, AXI_CLK_EN, 3); +static A1_PCLK(axi_psram, AXI_CLK_EN, 4); +static A1_PCLK(ramb, AXI_CLK_EN, 5); +static A1_PCLK(rama, AXI_CLK_EN, 6); +static A1_PCLK(axi_spifc, AXI_CLK_EN, 7); +static A1_PCLK(axi_nic, AXI_CLK_EN, 8); +static A1_PCLK(axi_dma, AXI_CLK_EN, 9); +static A1_PCLK(cpu_ctrl, AXI_CLK_EN, 10); +static A1_PCLK(rom, AXI_CLK_EN, 11); +static A1_PCLK(prod_i2c, AXI_CLK_EN, 12); /* Array of all clocks registered by this provider */ -static struct clk_hw *a1_periphs_hw_clks[] = { - [CLKID_XTAL_IN] = &xtal_in.hw, - [CLKID_FIXPLL_IN] = &fixpll_in.hw, - [CLKID_USB_PHY_IN] = &usb_phy_in.hw, - [CLKID_USB_CTRL_IN] = &usb_ctrl_in.hw, - [CLKID_HIFIPLL_IN] = &hifipll_in.hw, - [CLKID_SYSPLL_IN] = &syspll_in.hw, - [CLKID_DDS_IN] = &dds_in.hw, - [CLKID_SYS] = &sys.hw, - [CLKID_CLKTREE] = &clktree.hw, - [CLKID_RESET_CTRL] = &reset_ctrl.hw, - [CLKID_ANALOG_CTRL] = &analog_ctrl.hw, - [CLKID_PWR_CTRL] = &pwr_ctrl.hw, - [CLKID_PAD_CTRL] = &pad_ctrl.hw, - [CLKID_SYS_CTRL] = &sys_ctrl.hw, - [CLKID_TEMP_SENSOR] = &temp_sensor.hw, - [CLKID_AM2AXI_DIV] = &am2axi_dev.hw, - [CLKID_SPICC_B] = &spicc_b.hw, - [CLKID_SPICC_A] = &spicc_a.hw, - [CLKID_MSR] = &msr.hw, - [CLKID_AUDIO] = &audio.hw, - [CLKID_JTAG_CTRL] = &jtag_ctrl.hw, - [CLKID_SARADC_EN] = &saradc_en.hw, - [CLKID_PWM_EF] = &pwm_ef.hw, - [CLKID_PWM_CD] = &pwm_cd.hw, - [CLKID_PWM_AB] = &pwm_ab.hw, - [CLKID_CEC] = &cec.hw, - [CLKID_I2C_S] = &i2c_s.hw, - [CLKID_IR_CTRL] = &ir_ctrl.hw, - [CLKID_I2C_M_D] = &i2c_m_d.hw, - [CLKID_I2C_M_C] = &i2c_m_c.hw, - [CLKID_I2C_M_B] = &i2c_m_b.hw, - [CLKID_I2C_M_A] = &i2c_m_a.hw, - [CLKID_ACODEC] = &acodec.hw, - [CLKID_OTP] = &otp.hw, - [CLKID_SD_EMMC_A] = &sd_emmc_a.hw, - [CLKID_USB_PHY] = &usb_phy.hw, - [CLKID_USB_CTRL] = &usb_ctrl.hw, - [CLKID_SYS_DSPB] = &sys_dspb.hw, - [CLKID_SYS_DSPA] = &sys_dspa.hw, - [CLKID_DMA] = &dma.hw, - [CLKID_IRQ_CTRL] = &irq_ctrl.hw, - [CLKID_NIC] = &nic.hw, - [CLKID_GIC] = &gic.hw, - [CLKID_UART_C] = &uart_c.hw, - [CLKID_UART_B] = &uart_b.hw, - [CLKID_UART_A] = &uart_a.hw, - [CLKID_SYS_PSRAM] = &sys_psram.hw, - [CLKID_RSA] = &rsa.hw, - [CLKID_CORESIGHT] = &coresight.hw, - [CLKID_AM2AXI_VAD] = &am2axi_vad.hw, - [CLKID_AUDIO_VAD] = &audio_vad.hw, - [CLKID_AXI_DMC] = &axi_dmc.hw, - [CLKID_AXI_PSRAM] = &axi_psram.hw, - [CLKID_RAMB] = &ramb.hw, - [CLKID_RAMA] = &rama.hw, - [CLKID_AXI_SPIFC] = &axi_spifc.hw, - [CLKID_AXI_NIC] = &axi_nic.hw, - [CLKID_AXI_DMA] = &axi_dma.hw, - [CLKID_CPU_CTRL] = &cpu_ctrl.hw, - [CLKID_ROM] = &rom.hw, - [CLKID_PROC_I2C] = &prod_i2c.hw, - [CLKID_DSPA_SEL] = &dspa_sel.hw, - [CLKID_DSPB_SEL] = &dspb_sel.hw, - [CLKID_DSPA_EN] = &dspa_en.hw, - [CLKID_DSPA_EN_NIC] = &dspa_en_nic.hw, - [CLKID_DSPB_EN] = &dspb_en.hw, - [CLKID_DSPB_EN_NIC] = &dspb_en_nic.hw, - [CLKID_RTC] = &rtc.hw, - [CLKID_CECA_32K] = &ceca_32k_out.hw, - [CLKID_CECB_32K] = &cecb_32k_out.hw, - [CLKID_24M] = &clk_24m.hw, - [CLKID_12M] = &clk_12m.hw, - [CLKID_FCLK_DIV2_DIVN] = &fclk_div2_divn.hw, - [CLKID_GEN] = &gen.hw, - [CLKID_SARADC_SEL] = &saradc_sel.hw, - [CLKID_SARADC] = &saradc.hw, - [CLKID_PWM_A] = &pwm_a.hw, - [CLKID_PWM_B] = &pwm_b.hw, - [CLKID_PWM_C] = &pwm_c.hw, - [CLKID_PWM_D] = &pwm_d.hw, - [CLKID_PWM_E] = &pwm_e.hw, - [CLKID_PWM_F] = &pwm_f.hw, - [CLKID_SPICC] = &spicc.hw, - [CLKID_TS] = &ts.hw, - [CLKID_SPIFC] = &spifc.hw, - [CLKID_USB_BUS] = &usb_bus.hw, - [CLKID_SD_EMMC] = &sd_emmc.hw, - [CLKID_PSRAM] = &psram.hw, - [CLKID_DMC] = &dmc.hw, - [CLKID_SYS_A_SEL] = &sys_a_sel.hw, - [CLKID_SYS_A_DIV] = &sys_a_div.hw, - [CLKID_SYS_A] = &sys_a.hw, - [CLKID_SYS_B_SEL] = &sys_b_sel.hw, - [CLKID_SYS_B_DIV] = &sys_b_div.hw, - [CLKID_SYS_B] = &sys_b.hw, - [CLKID_DSPA_A_SEL] = &dspa_a_sel.hw, - [CLKID_DSPA_A_DIV] = &dspa_a_div.hw, - [CLKID_DSPA_A] = &dspa_a.hw, - [CLKID_DSPA_B_SEL] = &dspa_b_sel.hw, - [CLKID_DSPA_B_DIV] = &dspa_b_div.hw, - [CLKID_DSPA_B] = &dspa_b.hw, - [CLKID_DSPB_A_SEL] = &dspb_a_sel.hw, - [CLKID_DSPB_A_DIV] = &dspb_a_div.hw, - [CLKID_DSPB_A] = &dspb_a.hw, - [CLKID_DSPB_B_SEL] = &dspb_b_sel.hw, - [CLKID_DSPB_B_DIV] = &dspb_b_div.hw, - [CLKID_DSPB_B] = &dspb_b.hw, - [CLKID_RTC_32K_IN] = &rtc_32k_in.hw, - [CLKID_RTC_32K_DIV] = &rtc_32k_div.hw, - [CLKID_RTC_32K_XTAL] = &rtc_32k_xtal.hw, - [CLKID_RTC_32K_SEL] = &rtc_32k_sel.hw, - [CLKID_CECB_32K_IN] = &cecb_32k_in.hw, - [CLKID_CECB_32K_DIV] = &cecb_32k_div.hw, - [CLKID_CECB_32K_SEL_PRE] = &cecb_32k_sel_pre.hw, - [CLKID_CECB_32K_SEL] = &cecb_32k_sel.hw, - [CLKID_CECA_32K_IN] = &ceca_32k_in.hw, - [CLKID_CECA_32K_DIV] = &ceca_32k_div.hw, - [CLKID_CECA_32K_SEL_PRE] = &ceca_32k_sel_pre.hw, - [CLKID_CECA_32K_SEL] = &ceca_32k_sel.hw, - [CLKID_DIV2_PRE] = &fclk_div2_divn_pre.hw, - [CLKID_24M_DIV2] = &clk_24m_div2.hw, - [CLKID_GEN_SEL] = &gen_sel.hw, - [CLKID_GEN_DIV] = &gen_div.hw, - [CLKID_SARADC_DIV] = &saradc_div.hw, - [CLKID_PWM_A_SEL] = &pwm_a_sel.hw, - [CLKID_PWM_A_DIV] = &pwm_a_div.hw, - [CLKID_PWM_B_SEL] = &pwm_b_sel.hw, - [CLKID_PWM_B_DIV] = &pwm_b_div.hw, - [CLKID_PWM_C_SEL] = &pwm_c_sel.hw, - [CLKID_PWM_C_DIV] = &pwm_c_div.hw, - [CLKID_PWM_D_SEL] = &pwm_d_sel.hw, - [CLKID_PWM_D_DIV] = &pwm_d_div.hw, - [CLKID_PWM_E_SEL] = &pwm_e_sel.hw, - [CLKID_PWM_E_DIV] = &pwm_e_div.hw, - [CLKID_PWM_F_SEL] = &pwm_f_sel.hw, - [CLKID_PWM_F_DIV] = &pwm_f_div.hw, - [CLKID_SPICC_SEL] = &spicc_sel.hw, - [CLKID_SPICC_DIV] = &spicc_div.hw, - [CLKID_SPICC_SEL2] = &spicc_sel2.hw, - [CLKID_TS_DIV] = &ts_div.hw, - [CLKID_SPIFC_SEL] = &spifc_sel.hw, - [CLKID_SPIFC_DIV] = &spifc_div.hw, - [CLKID_SPIFC_SEL2] = &spifc_sel2.hw, - [CLKID_USB_BUS_SEL] = &usb_bus_sel.hw, - [CLKID_USB_BUS_DIV] = &usb_bus_div.hw, - [CLKID_SD_EMMC_SEL] = &sd_emmc_sel.hw, - [CLKID_SD_EMMC_DIV] = &sd_emmc_div.hw, - [CLKID_SD_EMMC_SEL2] = &sd_emmc_sel2.hw, - [CLKID_PSRAM_SEL] = &psram_sel.hw, - [CLKID_PSRAM_DIV] = &psram_div.hw, - [CLKID_PSRAM_SEL2] = &psram_sel2.hw, - [CLKID_DMC_SEL] = &dmc_sel.hw, - [CLKID_DMC_DIV] = &dmc_div.hw, - [CLKID_DMC_SEL2] = &dmc_sel2.hw, +static struct clk_hw *a1_peripherals_hw_clks[] = { + [CLKID_XTAL_IN] = &a1_xtal_in.hw, + [CLKID_FIXPLL_IN] = &a1_fixpll_in.hw, + [CLKID_USB_PHY_IN] = &a1_usb_phy_in.hw, + [CLKID_USB_CTRL_IN] = &a1_usb_ctrl_in.hw, + [CLKID_HIFIPLL_IN] = &a1_hifipll_in.hw, + [CLKID_SYSPLL_IN] = &a1_syspll_in.hw, + [CLKID_DDS_IN] = &a1_dds_in.hw, + [CLKID_SYS] = &a1_sys.hw, + [CLKID_CLKTREE] = &a1_clktree.hw, + [CLKID_RESET_CTRL] = &a1_reset_ctrl.hw, + [CLKID_ANALOG_CTRL] = &a1_analog_ctrl.hw, + [CLKID_PWR_CTRL] = &a1_pwr_ctrl.hw, + [CLKID_PAD_CTRL] = &a1_pad_ctrl.hw, + [CLKID_SYS_CTRL] = &a1_sys_ctrl.hw, + [CLKID_TEMP_SENSOR] = &a1_temp_sensor.hw, + [CLKID_AM2AXI_DIV] = &a1_am2axi_dev.hw, + [CLKID_SPICC_B] = &a1_spicc_b.hw, + [CLKID_SPICC_A] = &a1_spicc_a.hw, + [CLKID_MSR] = &a1_msr.hw, + [CLKID_AUDIO] = &a1_audio.hw, + [CLKID_JTAG_CTRL] = &a1_jtag_ctrl.hw, + [CLKID_SARADC_EN] = &a1_saradc_en.hw, + [CLKID_PWM_EF] = &a1_pwm_ef.hw, + [CLKID_PWM_CD] = &a1_pwm_cd.hw, + [CLKID_PWM_AB] = &a1_pwm_ab.hw, + [CLKID_CEC] = &a1_cec.hw, + [CLKID_I2C_S] = &a1_i2c_s.hw, + [CLKID_IR_CTRL] = &a1_ir_ctrl.hw, + [CLKID_I2C_M_D] = &a1_i2c_m_d.hw, + [CLKID_I2C_M_C] = &a1_i2c_m_c.hw, + [CLKID_I2C_M_B] = &a1_i2c_m_b.hw, + [CLKID_I2C_M_A] = &a1_i2c_m_a.hw, + [CLKID_ACODEC] = &a1_acodec.hw, + [CLKID_OTP] = &a1_otp.hw, + [CLKID_SD_EMMC_A] = &a1_sd_emmc_a.hw, + [CLKID_USB_PHY] = &a1_usb_phy.hw, + [CLKID_USB_CTRL] = &a1_usb_ctrl.hw, + [CLKID_SYS_DSPB] = &a1_sys_dspb.hw, + [CLKID_SYS_DSPA] = &a1_sys_dspa.hw, + [CLKID_DMA] = &a1_dma.hw, + [CLKID_IRQ_CTRL] = &a1_irq_ctrl.hw, + [CLKID_NIC] = &a1_nic.hw, + [CLKID_GIC] = &a1_gic.hw, + [CLKID_UART_C] = &a1_uart_c.hw, + [CLKID_UART_B] = &a1_uart_b.hw, + [CLKID_UART_A] = &a1_uart_a.hw, + [CLKID_SYS_PSRAM] = &a1_sys_psram.hw, + [CLKID_RSA] = &a1_rsa.hw, + [CLKID_CORESIGHT] = &a1_coresight.hw, + [CLKID_AM2AXI_VAD] = &a1_am2axi_vad.hw, + [CLKID_AUDIO_VAD] = &a1_audio_vad.hw, + [CLKID_AXI_DMC] = &a1_axi_dmc.hw, + [CLKID_AXI_PSRAM] = &a1_axi_psram.hw, + [CLKID_RAMB] = &a1_ramb.hw, + [CLKID_RAMA] = &a1_rama.hw, + [CLKID_AXI_SPIFC] = &a1_axi_spifc.hw, + [CLKID_AXI_NIC] = &a1_axi_nic.hw, + [CLKID_AXI_DMA] = &a1_axi_dma.hw, + [CLKID_CPU_CTRL] = &a1_cpu_ctrl.hw, + [CLKID_ROM] = &a1_rom.hw, + [CLKID_PROC_I2C] = &a1_prod_i2c.hw, + [CLKID_DSPA_SEL] = &a1_dspa_sel.hw, + [CLKID_DSPB_SEL] = &a1_dspb_sel.hw, + [CLKID_DSPA_EN] = &a1_dspa_en.hw, + [CLKID_DSPA_EN_NIC] = &a1_dspa_en_nic.hw, + [CLKID_DSPB_EN] = &a1_dspb_en.hw, + [CLKID_DSPB_EN_NIC] = &a1_dspb_en_nic.hw, + [CLKID_RTC] = &a1_rtc.hw, + [CLKID_CECA_32K] = &a1_ceca_32k_out.hw, + [CLKID_CECB_32K] = &a1_cecb_32k_out.hw, + [CLKID_24M] = &a1_24m.hw, + [CLKID_12M] = &a1_12m.hw, + [CLKID_FCLK_DIV2_DIVN] = &a1_fclk_div2_divn.hw, + [CLKID_GEN] = &a1_gen.hw, + [CLKID_SARADC_SEL] = &a1_saradc_sel.hw, + [CLKID_SARADC] = &a1_saradc.hw, + [CLKID_PWM_A] = &a1_pwm_a.hw, + [CLKID_PWM_B] = &a1_pwm_b.hw, + [CLKID_PWM_C] = &a1_pwm_c.hw, + [CLKID_PWM_D] = &a1_pwm_d.hw, + [CLKID_PWM_E] = &a1_pwm_e.hw, + [CLKID_PWM_F] = &a1_pwm_f.hw, + [CLKID_SPICC] = &a1_spicc.hw, + [CLKID_TS] = &a1_ts.hw, + [CLKID_SPIFC] = &a1_spifc.hw, + [CLKID_USB_BUS] = &a1_usb_bus.hw, + [CLKID_SD_EMMC] = &a1_sd_emmc.hw, + [CLKID_PSRAM] = &a1_psram.hw, + [CLKID_DMC] = &a1_dmc.hw, + [CLKID_SYS_A_SEL] = &a1_sys_a_sel.hw, + [CLKID_SYS_A_DIV] = &a1_sys_a_div.hw, + [CLKID_SYS_A] = &a1_sys_a.hw, + [CLKID_SYS_B_SEL] = &a1_sys_b_sel.hw, + [CLKID_SYS_B_DIV] = &a1_sys_b_div.hw, + [CLKID_SYS_B] = &a1_sys_b.hw, + [CLKID_DSPA_A_SEL] = &a1_dspa_a_sel.hw, + [CLKID_DSPA_A_DIV] = &a1_dspa_a_div.hw, + [CLKID_DSPA_A] = &a1_dspa_a.hw, + [CLKID_DSPA_B_SEL] = &a1_dspa_b_sel.hw, + [CLKID_DSPA_B_DIV] = &a1_dspa_b_div.hw, + [CLKID_DSPA_B] = &a1_dspa_b.hw, + [CLKID_DSPB_A_SEL] = &a1_dspb_a_sel.hw, + [CLKID_DSPB_A_DIV] = &a1_dspb_a_div.hw, + [CLKID_DSPB_A] = &a1_dspb_a.hw, + [CLKID_DSPB_B_SEL] = &a1_dspb_b_sel.hw, + [CLKID_DSPB_B_DIV] = &a1_dspb_b_div.hw, + [CLKID_DSPB_B] = &a1_dspb_b.hw, + [CLKID_RTC_32K_IN] = &a1_rtc_32k_in.hw, + [CLKID_RTC_32K_DIV] = &a1_rtc_32k_div.hw, + [CLKID_RTC_32K_XTAL] = &a1_rtc_32k_xtal.hw, + [CLKID_RTC_32K_SEL] = &a1_rtc_32k_sel.hw, + [CLKID_CECB_32K_IN] = &a1_cecb_32k_in.hw, + [CLKID_CECB_32K_DIV] = &a1_cecb_32k_div.hw, + [CLKID_CECB_32K_SEL_PRE] = &a1_cecb_32k_sel_pre.hw, + [CLKID_CECB_32K_SEL] = &a1_cecb_32k_sel.hw, + [CLKID_CECA_32K_IN] = &a1_ceca_32k_in.hw, + [CLKID_CECA_32K_DIV] = &a1_ceca_32k_div.hw, + [CLKID_CECA_32K_SEL_PRE] = &a1_ceca_32k_sel_pre.hw, + [CLKID_CECA_32K_SEL] = &a1_ceca_32k_sel.hw, + [CLKID_DIV2_PRE] = &a1_fclk_div2_divn_pre.hw, + [CLKID_24M_DIV2] = &a1_24m_div2.hw, + [CLKID_GEN_SEL] = &a1_gen_sel.hw, + [CLKID_GEN_DIV] = &a1_gen_div.hw, + [CLKID_SARADC_DIV] = &a1_saradc_div.hw, + [CLKID_PWM_A_SEL] = &a1_pwm_a_sel.hw, + [CLKID_PWM_A_DIV] = &a1_pwm_a_div.hw, + [CLKID_PWM_B_SEL] = &a1_pwm_b_sel.hw, + [CLKID_PWM_B_DIV] = &a1_pwm_b_div.hw, + [CLKID_PWM_C_SEL] = &a1_pwm_c_sel.hw, + [CLKID_PWM_C_DIV] = &a1_pwm_c_div.hw, + [CLKID_PWM_D_SEL] = &a1_pwm_d_sel.hw, + [CLKID_PWM_D_DIV] = &a1_pwm_d_div.hw, + [CLKID_PWM_E_SEL] = &a1_pwm_e_sel.hw, + [CLKID_PWM_E_DIV] = &a1_pwm_e_div.hw, + [CLKID_PWM_F_SEL] = &a1_pwm_f_sel.hw, + [CLKID_PWM_F_DIV] = &a1_pwm_f_div.hw, + [CLKID_SPICC_SEL] = &a1_spicc_sel.hw, + [CLKID_SPICC_DIV] = &a1_spicc_div.hw, + [CLKID_SPICC_SEL2] = &a1_spicc_sel2.hw, + [CLKID_TS_DIV] = &a1_ts_div.hw, + [CLKID_SPIFC_SEL] = &a1_spifc_sel.hw, + [CLKID_SPIFC_DIV] = &a1_spifc_div.hw, + [CLKID_SPIFC_SEL2] = &a1_spifc_sel2.hw, + [CLKID_USB_BUS_SEL] = &a1_usb_bus_sel.hw, + [CLKID_USB_BUS_DIV] = &a1_usb_bus_div.hw, + [CLKID_SD_EMMC_SEL] = &a1_sd_emmc_sel.hw, + [CLKID_SD_EMMC_DIV] = &a1_sd_emmc_div.hw, + [CLKID_SD_EMMC_SEL2] = &a1_sd_emmc_sel2.hw, + [CLKID_PSRAM_SEL] = &a1_psram_sel.hw, + [CLKID_PSRAM_DIV] = &a1_psram_div.hw, + [CLKID_PSRAM_SEL2] = &a1_psram_sel2.hw, + [CLKID_DMC_SEL] = &a1_dmc_sel.hw, + [CLKID_DMC_DIV] = &a1_dmc_div.hw, + [CLKID_DMC_SEL2] = &a1_dmc_sel2.hw, }; -static const struct regmap_config a1_periphs_regmap_cfg = { +static const struct regmap_config a1_peripherals_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .max_register = DMC_CLK_CTRL, }; -static struct meson_clk_hw_data a1_periphs_clks = { - .hws = a1_periphs_hw_clks, - .num = ARRAY_SIZE(a1_periphs_hw_clks), +static struct meson_clk_hw_data a1_peripherals_clks = { + .hws = a1_peripherals_hw_clks, + .num = ARRAY_SIZE(a1_peripherals_hw_clks), }; -static int meson_a1_periphs_probe(struct platform_device *pdev) +static int a1_peripherals_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; void __iomem *base; @@ -2079,36 +2081,36 @@ static int meson_a1_periphs_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(base), "can't ioremap resource\n"); - map = devm_regmap_init_mmio(dev, base, &a1_periphs_regmap_cfg); + map = devm_regmap_init_mmio(dev, base, &a1_peripherals_regmap_cfg); if (IS_ERR(map)) return dev_err_probe(dev, PTR_ERR(map), "can't init regmap mmio region\n"); - for (clkid = 0; clkid < a1_periphs_clks.num; clkid++) { - err = devm_clk_hw_register(dev, a1_periphs_clks.hws[clkid]); + for (clkid = 0; clkid < a1_peripherals_clks.num; clkid++) { + err = devm_clk_hw_register(dev, a1_peripherals_clks.hws[clkid]); if (err) return dev_err_probe(dev, err, "clock[%d] registration failed\n", clkid); } - return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, &a1_periphs_clks); + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, &a1_peripherals_clks); } -static const struct of_device_id a1_periphs_clkc_match_table[] = { +static const struct of_device_id a1_peripherals_clkc_match_table[] = { { .compatible = "amlogic,a1-peripherals-clkc", }, {} }; -MODULE_DEVICE_TABLE(of, a1_periphs_clkc_match_table); +MODULE_DEVICE_TABLE(of, a1_peripherals_clkc_match_table); -static struct platform_driver a1_periphs_clkc_driver = { - .probe = meson_a1_periphs_probe, +static struct platform_driver a1_peripherals_clkc_driver = { + .probe = a1_peripherals_clkc_probe, .driver = { .name = "a1-peripherals-clkc", - .of_match_table = a1_periphs_clkc_match_table, + .of_match_table = a1_peripherals_clkc_match_table, }, }; -module_platform_driver(a1_periphs_clkc_driver); +module_platform_driver(a1_peripherals_clkc_driver); MODULE_DESCRIPTION("Amlogic A1 Peripherals Clock Controller driver"); MODULE_AUTHOR("Jian Hu "); diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c index dabd4fad1f57..79ef4cbe9553 100644 --- a/drivers/clk/meson/a1-pll.c +++ b/drivers/clk/meson/a1-pll.c @@ -26,7 +26,7 @@ #include -static struct clk_regmap fixed_pll_dco = { +static struct clk_regmap a1_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = ANACTRL_FIXPLL_CTRL0, @@ -69,7 +69,7 @@ static struct clk_regmap fixed_pll_dco = { }, }; -static struct clk_regmap fixed_pll = { +static struct clk_regmap a1_fixed_pll = { .data = &(struct clk_regmap_gate_data){ .offset = ANACTRL_FIXPLL_CTRL0, .bit_idx = 20, @@ -78,18 +78,18 @@ static struct clk_regmap fixed_pll = { .name = "fixed_pll", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &fixed_pll_dco.hw + &a1_fixed_pll_dco.hw }, .num_parents = 1, }, }; -static const struct pll_mult_range hifi_pll_mult_range = { +static const struct pll_mult_range a1_hifi_pll_range = { .min = 32, .max = 64, }; -static const struct reg_sequence hifi_init_regs[] = { +static const struct reg_sequence a1_hifi_pll_init_regs[] = { { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 }, { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 }, { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 }, @@ -97,7 +97,7 @@ static const struct reg_sequence hifi_init_regs[] = { { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18000 }, }; -static struct clk_regmap hifi_pll = { +static struct clk_regmap a1_hifi_pll = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = ANACTRL_HIFIPLL_CTRL0, @@ -134,9 +134,9 @@ static struct clk_regmap hifi_pll = { .shift = 6, .width = 1, }, - .range = &hifi_pll_mult_range, - .init_regs = hifi_init_regs, - .init_count = ARRAY_SIZE(hifi_init_regs), + .range = &a1_hifi_pll_range, + .init_regs = a1_hifi_pll_init_regs, + .init_count = ARRAY_SIZE(a1_hifi_pll_init_regs), }, .hw.init = &(struct clk_init_data){ .name = "hifi_pll", @@ -148,20 +148,20 @@ static struct clk_regmap hifi_pll = { }, }; -static struct clk_fixed_factor fclk_div2_div = { +static struct clk_fixed_factor a1_fclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &fixed_pll.hw + &a1_fixed_pll.hw }, .num_parents = 1, }, }; -static struct clk_regmap fclk_div2 = { +static struct clk_regmap a1_fclk_div2 = { .data = &(struct clk_regmap_gate_data){ .offset = ANACTRL_FIXPLL_CTRL0, .bit_idx = 21, @@ -170,7 +170,7 @@ static struct clk_regmap fclk_div2 = { .name = "fclk_div2", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div2_div.hw + &a1_fclk_div2_div.hw }, .num_parents = 1, /* @@ -186,20 +186,20 @@ static struct clk_regmap fclk_div2 = { }, }; -static struct clk_fixed_factor fclk_div3_div = { +static struct clk_fixed_factor a1_fclk_div3_div = { .mult = 1, .div = 3, .hw.init = &(struct clk_init_data){ .name = "fclk_div3_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &fixed_pll.hw + &a1_fixed_pll.hw }, .num_parents = 1, }, }; -static struct clk_regmap fclk_div3 = { +static struct clk_regmap a1_fclk_div3 = { .data = &(struct clk_regmap_gate_data){ .offset = ANACTRL_FIXPLL_CTRL0, .bit_idx = 22, @@ -208,7 +208,7 @@ static struct clk_regmap fclk_div3 = { .name = "fclk_div3", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div3_div.hw + &a1_fclk_div3_div.hw }, .num_parents = 1, /* @@ -219,20 +219,20 @@ static struct clk_regmap fclk_div3 = { }, }; -static struct clk_fixed_factor fclk_div5_div = { +static struct clk_fixed_factor a1_fclk_div5_div = { .mult = 1, .div = 5, .hw.init = &(struct clk_init_data){ .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &fixed_pll.hw + &a1_fixed_pll.hw }, .num_parents = 1, }, }; -static struct clk_regmap fclk_div5 = { +static struct clk_regmap a1_fclk_div5 = { .data = &(struct clk_regmap_gate_data){ .offset = ANACTRL_FIXPLL_CTRL0, .bit_idx = 23, @@ -241,7 +241,7 @@ static struct clk_regmap fclk_div5 = { .name = "fclk_div5", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div5_div.hw + &a1_fclk_div5_div.hw }, .num_parents = 1, /* @@ -252,20 +252,20 @@ static struct clk_regmap fclk_div5 = { }, }; -static struct clk_fixed_factor fclk_div7_div = { +static struct clk_fixed_factor a1_fclk_div7_div = { .mult = 1, .div = 7, .hw.init = &(struct clk_init_data){ .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &fixed_pll.hw + &a1_fixed_pll.hw }, .num_parents = 1, }, }; -static struct clk_regmap fclk_div7 = { +static struct clk_regmap a1_fclk_div7 = { .data = &(struct clk_regmap_gate_data){ .offset = ANACTRL_FIXPLL_CTRL0, .bit_idx = 24, @@ -274,7 +274,7 @@ static struct clk_regmap fclk_div7 = { .name = "fclk_div7", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div7_div.hw + &a1_fclk_div7_div.hw }, .num_parents = 1, }, @@ -282,17 +282,17 @@ static struct clk_regmap fclk_div7 = { /* Array of all clocks registered by this provider */ static struct clk_hw *a1_pll_hw_clks[] = { - [CLKID_FIXED_PLL_DCO] = &fixed_pll_dco.hw, - [CLKID_FIXED_PLL] = &fixed_pll.hw, - [CLKID_FCLK_DIV2_DIV] = &fclk_div2_div.hw, - [CLKID_FCLK_DIV3_DIV] = &fclk_div3_div.hw, - [CLKID_FCLK_DIV5_DIV] = &fclk_div5_div.hw, - [CLKID_FCLK_DIV7_DIV] = &fclk_div7_div.hw, - [CLKID_FCLK_DIV2] = &fclk_div2.hw, - [CLKID_FCLK_DIV3] = &fclk_div3.hw, - [CLKID_FCLK_DIV5] = &fclk_div5.hw, - [CLKID_FCLK_DIV7] = &fclk_div7.hw, - [CLKID_HIFI_PLL] = &hifi_pll.hw, + [CLKID_FIXED_PLL_DCO] = &a1_fixed_pll_dco.hw, + [CLKID_FIXED_PLL] = &a1_fixed_pll.hw, + [CLKID_FCLK_DIV2_DIV] = &a1_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &a1_fclk_div3_div.hw, + [CLKID_FCLK_DIV5_DIV] = &a1_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &a1_fclk_div7_div.hw, + [CLKID_FCLK_DIV2] = &a1_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &a1_fclk_div3.hw, + [CLKID_FCLK_DIV5] = &a1_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &a1_fclk_div7.hw, + [CLKID_HIFI_PLL] = &a1_hifi_pll.hw, }; static const struct regmap_config a1_pll_regmap_cfg = { @@ -307,7 +307,7 @@ static struct meson_clk_hw_data a1_pll_clks = { .num = ARRAY_SIZE(a1_pll_hw_clks), }; -static int meson_a1_pll_probe(struct platform_device *pdev) +static int a1_pll_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; void __iomem *base; @@ -344,7 +344,7 @@ static const struct of_device_id a1_pll_clkc_match_table[] = { MODULE_DEVICE_TABLE(of, a1_pll_clkc_match_table); static struct platform_driver a1_pll_clkc_driver = { - .probe = meson_a1_pll_probe, + .probe = a1_pll_clkc_probe, .driver = { .name = "a1-pll-clkc", .of_match_table = a1_pll_clkc_match_table, diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index cd5d0b5ebdb2..a0c58dc8e950 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -35,7 +35,7 @@ #define AO_RTC_ALT_CLK_CNTL1 0x98 #define AXG_AO_GATE(_name, _bit) \ -static struct clk_regmap axg_aoclk_##_name = { \ +static struct clk_regmap axg_ao_##_name = { \ .data = &(struct clk_regmap_gate_data) { \ .offset = (AO_RTI_GEN_CNTL_REG0), \ .bit_idx = (_bit), \ @@ -59,7 +59,7 @@ AXG_AO_GATE(uart2, 5); AXG_AO_GATE(ir_blaster, 6); AXG_AO_GATE(saradc, 7); -static struct clk_regmap axg_aoclk_cts_oscin = { +static struct clk_regmap axg_ao_cts_oscin = { .data = &(struct clk_regmap_gate_data){ .offset = AO_RTI_PWR_CNTL_REG0, .bit_idx = 14, @@ -74,7 +74,7 @@ static struct clk_regmap axg_aoclk_cts_oscin = { }, }; -static struct clk_regmap axg_aoclk_32k_pre = { +static struct clk_regmap axg_ao_32k_pre = { .data = &(struct clk_regmap_gate_data){ .offset = AO_RTC_ALT_CLK_CNTL0, .bit_idx = 31, @@ -83,7 +83,7 @@ static struct clk_regmap axg_aoclk_32k_pre = { .name = "axg_ao_32k_pre", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &axg_aoclk_cts_oscin.hw + &axg_ao_cts_oscin.hw }, .num_parents = 1, }, @@ -99,7 +99,7 @@ static const struct meson_clk_dualdiv_param axg_32k_div_table[] = { }, {} }; -static struct clk_regmap axg_aoclk_32k_div = { +static struct clk_regmap axg_ao_32k_div = { .data = &(struct meson_clk_dualdiv_data){ .n1 = { .reg_off = AO_RTC_ALT_CLK_CNTL0, @@ -132,13 +132,13 @@ static struct clk_regmap axg_aoclk_32k_div = { .name = "axg_ao_32k_div", .ops = &meson_clk_dualdiv_ops, .parent_hws = (const struct clk_hw *[]) { - &axg_aoclk_32k_pre.hw + &axg_ao_32k_pre.hw }, .num_parents = 1, }, }; -static struct clk_regmap axg_aoclk_32k_sel = { +static struct clk_regmap axg_ao_32k_sel = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTC_ALT_CLK_CNTL1, .mask = 0x1, @@ -149,15 +149,15 @@ static struct clk_regmap axg_aoclk_32k_sel = { .name = "axg_ao_32k_sel", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &axg_aoclk_32k_div.hw, - &axg_aoclk_32k_pre.hw, + &axg_ao_32k_div.hw, + &axg_ao_32k_pre.hw, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap axg_aoclk_32k = { +static struct clk_regmap axg_ao_32k = { .data = &(struct clk_regmap_gate_data){ .offset = AO_RTC_ALT_CLK_CNTL0, .bit_idx = 30, @@ -166,14 +166,14 @@ static struct clk_regmap axg_aoclk_32k = { .name = "axg_ao_32k", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &axg_aoclk_32k_sel.hw + &axg_ao_32k_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap axg_aoclk_cts_rtc_oscin = { +static struct clk_regmap axg_ao_cts_rtc_oscin = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTI_PWR_CNTL_REG0, .mask = 0x1, @@ -184,7 +184,7 @@ static struct clk_regmap axg_aoclk_cts_rtc_oscin = { .name = "axg_ao_cts_rtc_oscin", .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { - { .hw = &axg_aoclk_32k.hw }, + { .hw = &axg_ao_32k.hw }, { .fw_name = "ext_32k-0", }, }, .num_parents = 2, @@ -192,7 +192,7 @@ static struct clk_regmap axg_aoclk_cts_rtc_oscin = { }, }; -static struct clk_regmap axg_aoclk_clk81 = { +static struct clk_regmap axg_ao_clk81 = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTI_PWR_CNTL_REG0, .mask = 0x1, @@ -200,68 +200,74 @@ static struct clk_regmap axg_aoclk_clk81 = { .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ + /* + * NOTE: this is one of the infamous clock the pwm driver + * can request directly by its global name. It's wrong but + * there is not much we can do about it until the support + * for the old pwm bindings is dropped + */ .name = "axg_ao_clk81", .ops = &clk_regmap_mux_ro_ops, .parent_data = (const struct clk_parent_data []) { { .fw_name = "mpeg-clk", }, - { .hw = &axg_aoclk_cts_rtc_oscin.hw }, + { .hw = &axg_ao_cts_rtc_oscin.hw }, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap axg_aoclk_saradc_mux = { +static struct clk_regmap axg_ao_saradc_mux = { .data = &(struct clk_regmap_mux_data) { .offset = AO_SAR_CLK, .mask = 0x3, .shift = 9, }, .hw.init = &(struct clk_init_data){ - .name = "axg_ao_saradc_mux", + .name = "ao_saradc_mux", .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { { .fw_name = "xtal", }, - { .hw = &axg_aoclk_clk81.hw }, + { .hw = &axg_ao_clk81.hw }, }, .num_parents = 2, }, }; -static struct clk_regmap axg_aoclk_saradc_div = { +static struct clk_regmap axg_ao_saradc_div = { .data = &(struct clk_regmap_div_data) { .offset = AO_SAR_CLK, .shift = 0, .width = 8, }, .hw.init = &(struct clk_init_data){ - .name = "axg_ao_saradc_div", + .name = "ao_saradc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &axg_aoclk_saradc_mux.hw + &axg_ao_saradc_mux.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap axg_aoclk_saradc_gate = { +static struct clk_regmap axg_ao_saradc_gate = { .data = &(struct clk_regmap_gate_data) { .offset = AO_SAR_CLK, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "axg_ao_saradc_gate", + .name = "ao_saradc_gate", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &axg_aoclk_saradc_div.hw + &axg_ao_saradc_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const unsigned int axg_aoclk_reset[] = { +static const unsigned int axg_ao_reset[] = { [RESET_AO_REMOTE] = 16, [RESET_AO_I2C_MASTER] = 18, [RESET_AO_I2C_SLAVE] = 19, @@ -270,53 +276,53 @@ static const unsigned int axg_aoclk_reset[] = { [RESET_AO_IR_BLASTER] = 23, }; -static struct clk_hw *axg_aoclk_hw_clks[] = { - [CLKID_AO_REMOTE] = &axg_aoclk_remote.hw, - [CLKID_AO_I2C_MASTER] = &axg_aoclk_i2c_master.hw, - [CLKID_AO_I2C_SLAVE] = &axg_aoclk_i2c_slave.hw, - [CLKID_AO_UART1] = &axg_aoclk_uart1.hw, - [CLKID_AO_UART2] = &axg_aoclk_uart2.hw, - [CLKID_AO_IR_BLASTER] = &axg_aoclk_ir_blaster.hw, - [CLKID_AO_SAR_ADC] = &axg_aoclk_saradc.hw, - [CLKID_AO_CLK81] = &axg_aoclk_clk81.hw, - [CLKID_AO_SAR_ADC_SEL] = &axg_aoclk_saradc_mux.hw, - [CLKID_AO_SAR_ADC_DIV] = &axg_aoclk_saradc_div.hw, - [CLKID_AO_SAR_ADC_CLK] = &axg_aoclk_saradc_gate.hw, - [CLKID_AO_CTS_OSCIN] = &axg_aoclk_cts_oscin.hw, - [CLKID_AO_32K_PRE] = &axg_aoclk_32k_pre.hw, - [CLKID_AO_32K_DIV] = &axg_aoclk_32k_div.hw, - [CLKID_AO_32K_SEL] = &axg_aoclk_32k_sel.hw, - [CLKID_AO_32K] = &axg_aoclk_32k.hw, - [CLKID_AO_CTS_RTC_OSCIN] = &axg_aoclk_cts_rtc_oscin.hw, +static struct clk_hw *axg_ao_hw_clks[] = { + [CLKID_AO_REMOTE] = &axg_ao_remote.hw, + [CLKID_AO_I2C_MASTER] = &axg_ao_i2c_master.hw, + [CLKID_AO_I2C_SLAVE] = &axg_ao_i2c_slave.hw, + [CLKID_AO_UART1] = &axg_ao_uart1.hw, + [CLKID_AO_UART2] = &axg_ao_uart2.hw, + [CLKID_AO_IR_BLASTER] = &axg_ao_ir_blaster.hw, + [CLKID_AO_SAR_ADC] = &axg_ao_saradc.hw, + [CLKID_AO_CLK81] = &axg_ao_clk81.hw, + [CLKID_AO_SAR_ADC_SEL] = &axg_ao_saradc_mux.hw, + [CLKID_AO_SAR_ADC_DIV] = &axg_ao_saradc_div.hw, + [CLKID_AO_SAR_ADC_CLK] = &axg_ao_saradc_gate.hw, + [CLKID_AO_CTS_OSCIN] = &axg_ao_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &axg_ao_32k_pre.hw, + [CLKID_AO_32K_DIV] = &axg_ao_32k_div.hw, + [CLKID_AO_32K_SEL] = &axg_ao_32k_sel.hw, + [CLKID_AO_32K] = &axg_ao_32k.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &axg_ao_cts_rtc_oscin.hw, }; -static const struct meson_aoclk_data axg_aoclkc_data = { +static const struct meson_aoclk_data axg_ao_clkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, - .num_reset = ARRAY_SIZE(axg_aoclk_reset), - .reset = axg_aoclk_reset, + .num_reset = ARRAY_SIZE(axg_ao_reset), + .reset = axg_ao_reset, .hw_clks = { - .hws = axg_aoclk_hw_clks, - .num = ARRAY_SIZE(axg_aoclk_hw_clks), + .hws = axg_ao_hw_clks, + .num = ARRAY_SIZE(axg_ao_hw_clks), }, }; -static const struct of_device_id axg_aoclkc_match_table[] = { +static const struct of_device_id axg_ao_clkc_match_table[] = { { .compatible = "amlogic,meson-axg-aoclkc", - .data = &axg_aoclkc_data, + .data = &axg_ao_clkc_data, }, { } }; -MODULE_DEVICE_TABLE(of, axg_aoclkc_match_table); +MODULE_DEVICE_TABLE(of, axg_ao_clkc_match_table); -static struct platform_driver axg_aoclkc_driver = { +static struct platform_driver axg_ao_clkc_driver = { .probe = meson_aoclkc_probe, .driver = { - .name = "axg-aoclkc", - .of_match_table = axg_aoclkc_match_table, + .name = "axg-ao-clkc", + .of_match_table = axg_ao_clkc_match_table, }, }; -module_platform_driver(axg_aoclkc_driver); +module_platform_driver(axg_ao_clkc_driver); MODULE_DESCRIPTION("Amlogic AXG Always-ON Clock Controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 208833c3ee95..7273178d33f7 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -333,7 +333,7 @@ static struct clk_regmap axg_gp0_pll = { }, }; -static const struct reg_sequence axg_hifi_init_regs[] = { +static const struct reg_sequence axg_hifi_pll_init_regs[] = { { .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 }, { .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x0a6a3a88 }, @@ -374,8 +374,8 @@ static struct clk_regmap axg_hifi_pll_dco = { .width = 1, }, .table = axg_gp0_pll_params_table, - .init_regs = axg_hifi_init_regs, - .init_count = ARRAY_SIZE(axg_hifi_init_regs), + .init_regs = axg_hifi_pll_init_regs, + .init_count = ARRAY_SIZE(axg_hifi_pll_init_regs), .flags = CLK_MESON_PLL_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ @@ -780,7 +780,7 @@ static const struct pll_params_table axg_pcie_pll_params_table[] = { { /* sentinel */ }, }; -static const struct reg_sequence axg_pcie_init_regs[] = { +static const struct reg_sequence axg_pcie_pll_init_regs[] = { { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x0084a2aa }, { .reg = HHI_PCIE_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x0a47488e }, @@ -823,8 +823,8 @@ static struct clk_regmap axg_pcie_pll_dco = { .width = 1, }, .table = axg_pcie_pll_params_table, - .init_regs = axg_pcie_init_regs, - .init_count = ARRAY_SIZE(axg_pcie_init_regs), + .init_regs = axg_pcie_pll_init_regs, + .init_count = ARRAY_SIZE(axg_pcie_pll_init_regs), }, .hw.init = &(struct clk_init_data){ .name = "pcie_pll_dco", @@ -935,8 +935,9 @@ static struct clk_regmap axg_pcie_cml_en1 = { }, }; -static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; -static const struct clk_parent_data clk81_parent_data[] = { +/* clk81 is often referred as "mpeg_clk" */ +static u32 clk81_parents_val_table[] = { 0, 2, 3, 4, 5, 6, 7 }; +static const struct clk_parent_data clk81_parents[] = { { .fw_name = "xtal", }, { .hw = &axg_fclk_div7.hw }, { .hw = &axg_mpll1.hw }, @@ -946,32 +947,32 @@ static const struct clk_parent_data clk81_parent_data[] = { { .hw = &axg_fclk_div5.hw }, }; -static struct clk_regmap axg_mpeg_clk_sel = { +static struct clk_regmap axg_clk81_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_MPEG_CLK_CNTL, .mask = 0x7, .shift = 12, - .table = mux_table_clk81, + .table = clk81_parents_val_table, }, .hw.init = &(struct clk_init_data){ - .name = "mpeg_clk_sel", + .name = "clk81_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_data = clk81_parent_data, - .num_parents = ARRAY_SIZE(clk81_parent_data), + .parent_data = clk81_parents, + .num_parents = ARRAY_SIZE(clk81_parents), }, }; -static struct clk_regmap axg_mpeg_clk_div = { +static struct clk_regmap axg_clk81_div = { .data = &(struct clk_regmap_div_data){ .offset = HHI_MPEG_CLK_CNTL, .shift = 0, .width = 7, }, .hw.init = &(struct clk_init_data){ - .name = "mpeg_clk_div", + .name = "clk81_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &axg_mpeg_clk_sel.hw + &axg_clk81_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -987,14 +988,14 @@ static struct clk_regmap axg_clk81 = { .name = "clk81", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &axg_mpeg_clk_div.hw + &axg_clk81_div.hw }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), }, }; -static const struct clk_parent_data axg_sd_emmc_clk0_parent_data[] = { +static const struct clk_parent_data axg_sd_emmc_clk0_parents[] = { { .fw_name = "xtal", }, { .hw = &axg_fclk_div2.hw }, { .hw = &axg_fclk_div3.hw }, @@ -1018,8 +1019,8 @@ static struct clk_regmap axg_sd_emmc_b_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = axg_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_data), + .parent_data = axg_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1068,8 +1069,8 @@ static struct clk_regmap axg_sd_emmc_c_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = axg_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_data), + .parent_data = axg_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1110,7 +1111,7 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = { /* VPU Clock */ -static const struct clk_hw *axg_vpu_parent_hws[] = { +static const struct clk_hw *axg_vpu_parents[] = { &axg_fclk_div4.hw, &axg_fclk_div3.hw, &axg_fclk_div5.hw, @@ -1126,8 +1127,8 @@ static struct clk_regmap axg_vpu_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = axg_vpu_parent_hws, - .num_parents = ARRAY_SIZE(axg_vpu_parent_hws), + .parent_hws = axg_vpu_parents, + .num_parents = ARRAY_SIZE(axg_vpu_parents), /* We need a specific parent for VPU clock source, let it be set in DT */ .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -1175,8 +1176,8 @@ static struct clk_regmap axg_vpu_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = axg_vpu_parent_hws, - .num_parents = ARRAY_SIZE(axg_vpu_parent_hws), + .parent_hws = axg_vpu_parents, + .num_parents = ARRAY_SIZE(axg_vpu_parents), /* We need a specific parent for VPU clock source, let it be set in DT */ .flags = CLK_SET_RATE_NO_REPARENT, }, @@ -1244,8 +1245,8 @@ static struct clk_regmap axg_vapb_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vapb_0_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = axg_vpu_parent_hws, - .num_parents = ARRAY_SIZE(axg_vpu_parent_hws), + .parent_hws = axg_vpu_parents, + .num_parents = ARRAY_SIZE(axg_vpu_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1292,8 +1293,8 @@ static struct clk_regmap axg_vapb_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vapb_1_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = axg_vpu_parent_hws, - .num_parents = ARRAY_SIZE(axg_vpu_parent_hws), + .parent_hws = axg_vpu_parents, + .num_parents = ARRAY_SIZE(axg_vpu_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1365,7 +1366,7 @@ static struct clk_regmap axg_vapb = { /* Video Clocks */ -static const struct clk_hw *axg_vclk_parent_hws[] = { +static const struct clk_hw *axg_vclk_parents[] = { &axg_gp0_pll.hw, &axg_fclk_div4.hw, &axg_fclk_div3.hw, @@ -1384,8 +1385,8 @@ static struct clk_regmap axg_vclk_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = axg_vclk_parent_hws, - .num_parents = ARRAY_SIZE(axg_vclk_parent_hws), + .parent_hws = axg_vclk_parents, + .num_parents = ARRAY_SIZE(axg_vclk_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -1399,8 +1400,8 @@ static struct clk_regmap axg_vclk2_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk2_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = axg_vclk_parent_hws, - .num_parents = ARRAY_SIZE(axg_vclk_parent_hws), + .parent_hws = axg_vclk_parents, + .num_parents = ARRAY_SIZE(axg_vclk_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -1739,8 +1740,8 @@ static struct clk_fixed_factor axg_vclk2_div12 = { }, }; -static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const struct clk_hw *axg_cts_parent_hws[] = { +static u32 axg_cts_encl_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *axg_cts_encl_parents[] = { &axg_vclk_div1.hw, &axg_vclk_div2.hw, &axg_vclk_div4.hw, @@ -1758,13 +1759,13 @@ static struct clk_regmap axg_cts_encl_sel = { .offset = HHI_VIID_CLK_DIV, .mask = 0xf, .shift = 12, - .table = mux_table_cts_sel, + .table = axg_cts_encl_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_encl_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = axg_cts_parent_hws, - .num_parents = ARRAY_SIZE(axg_cts_parent_hws), + .parent_hws = axg_cts_encl_parents, + .num_parents = ARRAY_SIZE(axg_cts_encl_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -1787,8 +1788,8 @@ static struct clk_regmap axg_cts_encl = { /* MIPI DSI Host Clock */ -static u32 mux_table_axg_vdin_meas[] = { 0, 1, 2, 3, 6, 7 }; -static const struct clk_parent_data axg_vdin_meas_parent_data[] = { +static u32 axg_vdin_meas_parents_val_table[] = { 0, 1, 2, 3, 6, 7 }; +static const struct clk_parent_data axg_vdin_meas_parents[] = { { .fw_name = "xtal", }, { .hw = &axg_fclk_div4.hw }, { .hw = &axg_fclk_div3.hw }, @@ -1803,13 +1804,13 @@ static struct clk_regmap axg_vdin_meas_sel = { .mask = 0x7, .shift = 21, .flags = CLK_MUX_ROUND_CLOSEST, - .table = mux_table_axg_vdin_meas, + .table = axg_vdin_meas_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "vdin_meas_sel", .ops = &clk_regmap_mux_ops, - .parent_data = axg_vdin_meas_parent_data, - .num_parents = ARRAY_SIZE(axg_vdin_meas_parent_data), + .parent_data = axg_vdin_meas_parents, + .num_parents = ARRAY_SIZE(axg_vdin_meas_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1845,9 +1846,8 @@ static struct clk_regmap axg_vdin_meas = { }, }; -static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, - 9, 10, 11, 13, 14, }; -static const struct clk_parent_data gen_clk_parent_data[] = { +static u32 gen_clk_parents_val_table[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; +static const struct clk_parent_data gen_clk_parents[] = { { .fw_name = "xtal", }, { .hw = &axg_hifi_pll.hw }, { .hw = &axg_mpll0.hw }, @@ -1866,7 +1866,7 @@ static struct clk_regmap axg_gen_clk_sel = { .offset = HHI_GEN_CLK_CNTL, .mask = 0xf, .shift = 12, - .table = mux_table_gen_clk, + .table = gen_clk_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "gen_clk_sel", @@ -1877,8 +1877,8 @@ static struct clk_regmap axg_gen_clk_sel = { * hifi_pll, mpll0, mpll1, mpll2, mpll3, fdiv4, * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll */ - .parent_data = gen_clk_parent_data, - .num_parents = ARRAY_SIZE(gen_clk_parent_data), + .parent_data = gen_clk_parents, + .num_parents = ARRAY_SIZE(gen_clk_parents), }, }; @@ -1915,59 +1915,59 @@ static struct clk_regmap axg_gen_clk = { }, }; -#define MESON_GATE(_name, _reg, _bit) \ - MESON_PCLK(_name, _reg, _bit, &axg_clk81.hw) +#define AXG_PCLK(_name, _reg, _bit) \ + MESON_PCLK(axg_##_name, _reg, _bit, &axg_clk81.hw) /* Everything Else (EE) domain gates */ -static MESON_GATE(axg_ddr, HHI_GCLK_MPEG0, 0); -static MESON_GATE(axg_audio_locker, HHI_GCLK_MPEG0, 2); -static MESON_GATE(axg_mipi_dsi_host, HHI_GCLK_MPEG0, 3); -static MESON_GATE(axg_isa, HHI_GCLK_MPEG0, 5); -static MESON_GATE(axg_pl301, HHI_GCLK_MPEG0, 6); -static MESON_GATE(axg_periphs, HHI_GCLK_MPEG0, 7); -static MESON_GATE(axg_spicc_0, HHI_GCLK_MPEG0, 8); -static MESON_GATE(axg_i2c, HHI_GCLK_MPEG0, 9); -static MESON_GATE(axg_rng0, HHI_GCLK_MPEG0, 12); -static MESON_GATE(axg_uart0, HHI_GCLK_MPEG0, 13); -static MESON_GATE(axg_mipi_dsi_phy, HHI_GCLK_MPEG0, 14); -static MESON_GATE(axg_spicc_1, HHI_GCLK_MPEG0, 15); -static MESON_GATE(axg_pcie_a, HHI_GCLK_MPEG0, 16); -static MESON_GATE(axg_pcie_b, HHI_GCLK_MPEG0, 17); -static MESON_GATE(axg_hiu_reg, HHI_GCLK_MPEG0, 19); -static MESON_GATE(axg_assist_misc, HHI_GCLK_MPEG0, 23); -static MESON_GATE(axg_emmc_b, HHI_GCLK_MPEG0, 25); -static MESON_GATE(axg_emmc_c, HHI_GCLK_MPEG0, 26); -static MESON_GATE(axg_dma, HHI_GCLK_MPEG0, 27); -static MESON_GATE(axg_spi, HHI_GCLK_MPEG0, 30); +static AXG_PCLK(ddr, HHI_GCLK_MPEG0, 0); +static AXG_PCLK(audio_locker, HHI_GCLK_MPEG0, 2); +static AXG_PCLK(mipi_dsi_host, HHI_GCLK_MPEG0, 3); +static AXG_PCLK(isa, HHI_GCLK_MPEG0, 5); +static AXG_PCLK(pl301, HHI_GCLK_MPEG0, 6); +static AXG_PCLK(periphs, HHI_GCLK_MPEG0, 7); +static AXG_PCLK(spicc_0, HHI_GCLK_MPEG0, 8); +static AXG_PCLK(i2c, HHI_GCLK_MPEG0, 9); +static AXG_PCLK(rng0, HHI_GCLK_MPEG0, 12); +static AXG_PCLK(uart0, HHI_GCLK_MPEG0, 13); +static AXG_PCLK(mipi_dsi_phy, HHI_GCLK_MPEG0, 14); +static AXG_PCLK(spicc_1, HHI_GCLK_MPEG0, 15); +static AXG_PCLK(pcie_a, HHI_GCLK_MPEG0, 16); +static AXG_PCLK(pcie_b, HHI_GCLK_MPEG0, 17); +static AXG_PCLK(hiu_reg, HHI_GCLK_MPEG0, 19); +static AXG_PCLK(assist_misc, HHI_GCLK_MPEG0, 23); +static AXG_PCLK(emmc_b, HHI_GCLK_MPEG0, 25); +static AXG_PCLK(emmc_c, HHI_GCLK_MPEG0, 26); +static AXG_PCLK(dma, HHI_GCLK_MPEG0, 27); +static AXG_PCLK(spi, HHI_GCLK_MPEG0, 30); -static MESON_GATE(axg_audio, HHI_GCLK_MPEG1, 0); -static MESON_GATE(axg_eth_core, HHI_GCLK_MPEG1, 3); -static MESON_GATE(axg_uart1, HHI_GCLK_MPEG1, 16); -static MESON_GATE(axg_g2d, HHI_GCLK_MPEG1, 20); -static MESON_GATE(axg_usb0, HHI_GCLK_MPEG1, 21); -static MESON_GATE(axg_usb1, HHI_GCLK_MPEG1, 22); -static MESON_GATE(axg_reset, HHI_GCLK_MPEG1, 23); -static MESON_GATE(axg_usb_general, HHI_GCLK_MPEG1, 26); -static MESON_GATE(axg_ahb_arb0, HHI_GCLK_MPEG1, 29); -static MESON_GATE(axg_efuse, HHI_GCLK_MPEG1, 30); -static MESON_GATE(axg_boot_rom, HHI_GCLK_MPEG1, 31); +static AXG_PCLK(audio, HHI_GCLK_MPEG1, 0); +static AXG_PCLK(eth_core, HHI_GCLK_MPEG1, 3); +static AXG_PCLK(uart1, HHI_GCLK_MPEG1, 16); +static AXG_PCLK(g2d, HHI_GCLK_MPEG1, 20); +static AXG_PCLK(usb0, HHI_GCLK_MPEG1, 21); +static AXG_PCLK(usb1, HHI_GCLK_MPEG1, 22); +static AXG_PCLK(reset, HHI_GCLK_MPEG1, 23); +static AXG_PCLK(usb_general, HHI_GCLK_MPEG1, 26); +static AXG_PCLK(ahb_arb0, HHI_GCLK_MPEG1, 29); +static AXG_PCLK(efuse, HHI_GCLK_MPEG1, 30); +static AXG_PCLK(boot_rom, HHI_GCLK_MPEG1, 31); -static MESON_GATE(axg_ahb_data_bus, HHI_GCLK_MPEG2, 1); -static MESON_GATE(axg_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); -static MESON_GATE(axg_usb1_to_ddr, HHI_GCLK_MPEG2, 8); -static MESON_GATE(axg_usb0_to_ddr, HHI_GCLK_MPEG2, 9); -static MESON_GATE(axg_mmc_pclk, HHI_GCLK_MPEG2, 11); -static MESON_GATE(axg_vpu_intr, HHI_GCLK_MPEG2, 25); -static MESON_GATE(axg_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); -static MESON_GATE(axg_gic, HHI_GCLK_MPEG2, 30); +static AXG_PCLK(ahb_data_bus, HHI_GCLK_MPEG2, 1); +static AXG_PCLK(ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static AXG_PCLK(usb1_to_ddr, HHI_GCLK_MPEG2, 8); +static AXG_PCLK(usb0_to_ddr, HHI_GCLK_MPEG2, 9); +static AXG_PCLK(mmc_pclk, HHI_GCLK_MPEG2, 11); +static AXG_PCLK(vpu_intr, HHI_GCLK_MPEG2, 25); +static AXG_PCLK(sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); +static AXG_PCLK(gic, HHI_GCLK_MPEG2, 30); /* Always On (AO) domain gates */ -static MESON_GATE(axg_ao_media_cpu, HHI_GCLK_AO, 0); -static MESON_GATE(axg_ao_ahb_sram, HHI_GCLK_AO, 1); -static MESON_GATE(axg_ao_ahb_bus, HHI_GCLK_AO, 2); -static MESON_GATE(axg_ao_iface, HHI_GCLK_AO, 3); -static MESON_GATE(axg_ao_i2c, HHI_GCLK_AO, 4); +static AXG_PCLK(ao_media_cpu, HHI_GCLK_AO, 0); +static AXG_PCLK(ao_ahb_sram, HHI_GCLK_AO, 1); +static AXG_PCLK(ao_ahb_bus, HHI_GCLK_AO, 2); +static AXG_PCLK(ao_iface, HHI_GCLK_AO, 3); +static AXG_PCLK(ao_i2c, HHI_GCLK_AO, 4); /* Array of all clocks provided by this provider */ @@ -1980,8 +1980,8 @@ static struct clk_hw *axg_hw_clks[] = { [CLKID_FCLK_DIV5] = &axg_fclk_div5.hw, [CLKID_FCLK_DIV7] = &axg_fclk_div7.hw, [CLKID_GP0_PLL] = &axg_gp0_pll.hw, - [CLKID_MPEG_SEL] = &axg_mpeg_clk_sel.hw, - [CLKID_MPEG_DIV] = &axg_mpeg_clk_div.hw, + [CLKID_MPEG_SEL] = &axg_clk81_sel.hw, + [CLKID_MPEG_DIV] = &axg_clk81_div.hw, [CLKID_CLK81] = &axg_clk81.hw, [CLKID_MPLL0] = &axg_mpll0.hw, [CLKID_MPLL1] = &axg_mpll1.hw, @@ -2117,21 +2117,20 @@ static const struct meson_eeclkc_data axg_clkc_data = { }, }; - -static const struct of_device_id clkc_match_table[] = { +static const struct of_device_id axg_clkc_match_table[] = { { .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data }, {} }; -MODULE_DEVICE_TABLE(of, clkc_match_table); +MODULE_DEVICE_TABLE(of, axg_clkc_match_table); -static struct platform_driver axg_driver = { +static struct platform_driver axg_clkc_driver = { .probe = meson_eeclkc_probe, .driver = { .name = "axg-clkc", - .of_match_table = clkc_match_table, + .of_match_table = axg_clkc_match_table, }, }; -module_platform_driver(axg_driver); +module_platform_driver(axg_clkc_driver); MODULE_DESCRIPTION("Amlogic AXG Main Clock Controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/meson/c3-peripherals.c b/drivers/clk/meson/c3-peripherals.c index a25e7d5dc669..a09cb1435ab1 100644 --- a/drivers/clk/meson/c3-peripherals.c +++ b/drivers/clk/meson/c3-peripherals.c @@ -48,7 +48,7 @@ #define SPIFC_CLK_CTRL 0x1a0 #define NNA_CLK_CTRL 0x220 -static struct clk_regmap rtc_xtal_clkin = { +static struct clk_regmap c3_rtc_xtal_clkin = { .data = &(struct clk_regmap_gate_data) { .offset = RTC_BY_OSCIN_CTRL0, .bit_idx = 31, @@ -63,12 +63,12 @@ static struct clk_regmap rtc_xtal_clkin = { }, }; -static const struct meson_clk_dualdiv_param rtc_32k_div_table[] = { +static const struct meson_clk_dualdiv_param c3_rtc_32k_div_table[] = { { 733, 732, 8, 11, 1 }, { /* sentinel */ } }; -static struct clk_regmap rtc_32k_div = { +static struct clk_regmap c3_rtc_32k_div = { .data = &(struct meson_clk_dualdiv_data) { .n1 = { .reg_off = RTC_BY_OSCIN_CTRL0, @@ -95,39 +95,39 @@ static struct clk_regmap rtc_32k_div = { .shift = 28, .width = 1, }, - .table = rtc_32k_div_table, + .table = c3_rtc_32k_div_table, }, .hw.init = &(struct clk_init_data) { .name = "rtc_32k_div", .ops = &meson_clk_dualdiv_ops, .parent_hws = (const struct clk_hw *[]) { - &rtc_xtal_clkin.hw + &c3_rtc_xtal_clkin.hw }, .num_parents = 1, }, }; -static const struct clk_parent_data rtc_32k_mux_parent_data[] = { - { .hw = &rtc_32k_div.hw }, - { .hw = &rtc_xtal_clkin.hw } +static const struct clk_parent_data c3_rtc_32k_parents[] = { + { .hw = &c3_rtc_32k_div.hw }, + { .hw = &c3_rtc_xtal_clkin.hw } }; -static struct clk_regmap rtc_32k_mux = { +static struct clk_regmap c3_rtc_32k_sel = { .data = &(struct clk_regmap_mux_data) { .offset = RTC_BY_OSCIN_CTRL1, .mask = 0x1, .shift = 24, }, .hw.init = &(struct clk_init_data) { - .name = "rtc_32k_mux", + .name = "rtc_32k_sel", .ops = &clk_regmap_mux_ops, - .parent_data = rtc_32k_mux_parent_data, - .num_parents = ARRAY_SIZE(rtc_32k_mux_parent_data), + .parent_data = c3_rtc_32k_parents, + .num_parents = ARRAY_SIZE(c3_rtc_32k_parents), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap rtc_32k = { +static struct clk_regmap c3_rtc_32k = { .data = &(struct clk_regmap_gate_data) { .offset = RTC_BY_OSCIN_CTRL0, .bit_idx = 30, @@ -136,20 +136,20 @@ static struct clk_regmap rtc_32k = { .name = "rtc_32k", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &rtc_32k_mux.hw + &c3_rtc_32k_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data rtc_clk_mux_parent_data[] = { +static const struct clk_parent_data c3_rtc_clk_parents[] = { { .fw_name = "oscin" }, - { .hw = &rtc_32k.hw }, + { .hw = &c3_rtc_32k.hw }, { .fw_name = "pad_osc" } }; -static struct clk_regmap rtc_clk = { +static struct clk_regmap c3_rtc_clk = { .data = &(struct clk_regmap_mux_data) { .offset = RTC_CTRL, .mask = 0x3, @@ -158,62 +158,62 @@ static struct clk_regmap rtc_clk = { .hw.init = &(struct clk_init_data) { .name = "rtc_clk", .ops = &clk_regmap_mux_ops, - .parent_data = rtc_clk_mux_parent_data, - .num_parents = ARRAY_SIZE(rtc_clk_mux_parent_data), + .parent_data = c3_rtc_clk_parents, + .num_parents = ARRAY_SIZE(c3_rtc_clk_parents), .flags = CLK_SET_RATE_PARENT, }, }; -#define C3_CLK_GATE(_name, _reg, _bit, _fw_name, _ops, _flags) \ -struct clk_regmap _name = { \ +#define C3_PCLK(_name, _reg, _bit, _fw_name, _ops, _flags) \ +struct clk_regmap c3_##_name = { \ .data = &(struct clk_regmap_gate_data){ \ .offset = (_reg), \ .bit_idx = (_bit), \ }, \ .hw.init = &(struct clk_init_data) { \ - .name = #_name, \ + .name = "c3_" #_name, \ .ops = _ops, \ .parent_data = &(const struct clk_parent_data) { \ - .fw_name = #_fw_name, \ + .fw_name = (_fw_name), \ }, \ .num_parents = 1, \ .flags = (_flags), \ }, \ } -#define C3_SYS_GATE(_name, _reg, _bit, _flags) \ - C3_CLK_GATE(_name, _reg, _bit, sysclk, \ - &clk_regmap_gate_ops, _flags) +#define C3_SYS_PCLK(_name, _reg, _bit, _flags) \ + C3_PCLK(_name, _reg, _bit, "sysclk", \ + &clk_regmap_gate_ops, _flags) -#define C3_SYS_GATE_RO(_name, _reg, _bit) \ - C3_CLK_GATE(_name, _reg, _bit, sysclk, \ - &clk_regmap_gate_ro_ops, 0) +#define C3_SYS_PCLK_RO(_name, _reg, _bit) \ + C3_PCLK(_name, _reg, _bit, "sysclk", \ + &clk_regmap_gate_ro_ops, 0) -static C3_SYS_GATE(sys_reset_ctrl, SYS_CLK_EN0_REG0, 1, 0); -static C3_SYS_GATE(sys_pwr_ctrl, SYS_CLK_EN0_REG0, 3, 0); -static C3_SYS_GATE(sys_pad_ctrl, SYS_CLK_EN0_REG0, 4, 0); -static C3_SYS_GATE(sys_ctrl, SYS_CLK_EN0_REG0, 5, 0); -static C3_SYS_GATE(sys_ts_pll, SYS_CLK_EN0_REG0, 6, 0); +static C3_SYS_PCLK(sys_reset_ctrl, SYS_CLK_EN0_REG0, 1, 0); +static C3_SYS_PCLK(sys_pwr_ctrl, SYS_CLK_EN0_REG0, 3, 0); +static C3_SYS_PCLK(sys_pad_ctrl, SYS_CLK_EN0_REG0, 4, 0); +static C3_SYS_PCLK(sys_ctrl, SYS_CLK_EN0_REG0, 5, 0); +static C3_SYS_PCLK(sys_ts_pll, SYS_CLK_EN0_REG0, 6, 0); /* * NOTE: sys_dev_arb provides the clock to the ETH and SPICC arbiters that * access the AXI bus. */ -static C3_SYS_GATE(sys_dev_arb, SYS_CLK_EN0_REG0, 7, 0); +static C3_SYS_PCLK(sys_dev_arb, SYS_CLK_EN0_REG0, 7, 0); /* * FIXME: sys_mmc_pclk provides the clock for the DDR PHY, DDR will only be * initialized in bl2, and this clock should not be touched in linux. */ -static C3_SYS_GATE_RO(sys_mmc_pclk, SYS_CLK_EN0_REG0, 8); +static C3_SYS_PCLK_RO(sys_mmc_pclk, SYS_CLK_EN0_REG0, 8); /* * NOTE: sys_cpu_ctrl provides the clock for CPU controller. After clock is * disabled, cpu_clk and other key CPU-related configurations cannot take effect. */ -static C3_SYS_GATE(sys_cpu_ctrl, SYS_CLK_EN0_REG0, 11, CLK_IS_CRITICAL); -static C3_SYS_GATE(sys_jtag_ctrl, SYS_CLK_EN0_REG0, 12, 0); -static C3_SYS_GATE(sys_ir_ctrl, SYS_CLK_EN0_REG0, 13, 0); +static C3_SYS_PCLK(sys_cpu_ctrl, SYS_CLK_EN0_REG0, 11, CLK_IS_CRITICAL); +static C3_SYS_PCLK(sys_jtag_ctrl, SYS_CLK_EN0_REG0, 12, 0); +static C3_SYS_PCLK(sys_ir_ctrl, SYS_CLK_EN0_REG0, 13, 0); /* * NOTE: sys_irq_ctrl provides the clock for IRQ controller. The IRQ controller @@ -221,18 +221,18 @@ static C3_SYS_GATE(sys_ir_ctrl, SYS_CLK_EN0_REG0, 13, 0); * AOCPU. If the clock is disabled, interrupt-related functions will occurs an * exception. */ -static C3_SYS_GATE(sys_irq_ctrl, SYS_CLK_EN0_REG0, 14, CLK_IS_CRITICAL); -static C3_SYS_GATE(sys_msr_clk, SYS_CLK_EN0_REG0, 15, 0); -static C3_SYS_GATE(sys_rom, SYS_CLK_EN0_REG0, 16, 0); -static C3_SYS_GATE(sys_uart_f, SYS_CLK_EN0_REG0, 17, 0); -static C3_SYS_GATE(sys_cpu_apb, SYS_CLK_EN0_REG0, 18, 0); -static C3_SYS_GATE(sys_rsa, SYS_CLK_EN0_REG0, 19, 0); -static C3_SYS_GATE(sys_sar_adc, SYS_CLK_EN0_REG0, 20, 0); -static C3_SYS_GATE(sys_startup, SYS_CLK_EN0_REG0, 21, 0); -static C3_SYS_GATE(sys_secure, SYS_CLK_EN0_REG0, 22, 0); -static C3_SYS_GATE(sys_spifc, SYS_CLK_EN0_REG0, 23, 0); -static C3_SYS_GATE(sys_nna, SYS_CLK_EN0_REG0, 25, 0); -static C3_SYS_GATE(sys_eth_mac, SYS_CLK_EN0_REG0, 26, 0); +static C3_SYS_PCLK(sys_irq_ctrl, SYS_CLK_EN0_REG0, 14, CLK_IS_CRITICAL); +static C3_SYS_PCLK(sys_msr_clk, SYS_CLK_EN0_REG0, 15, 0); +static C3_SYS_PCLK(sys_rom, SYS_CLK_EN0_REG0, 16, 0); +static C3_SYS_PCLK(sys_uart_f, SYS_CLK_EN0_REG0, 17, 0); +static C3_SYS_PCLK(sys_cpu_apb, SYS_CLK_EN0_REG0, 18, 0); +static C3_SYS_PCLK(sys_rsa, SYS_CLK_EN0_REG0, 19, 0); +static C3_SYS_PCLK(sys_sar_adc, SYS_CLK_EN0_REG0, 20, 0); +static C3_SYS_PCLK(sys_startup, SYS_CLK_EN0_REG0, 21, 0); +static C3_SYS_PCLK(sys_secure, SYS_CLK_EN0_REG0, 22, 0); +static C3_SYS_PCLK(sys_spifc, SYS_CLK_EN0_REG0, 23, 0); +static C3_SYS_PCLK(sys_nna, SYS_CLK_EN0_REG0, 25, 0); +static C3_SYS_PCLK(sys_eth_mac, SYS_CLK_EN0_REG0, 26, 0); /* * FIXME: sys_gic provides the clock for GIC(Generic Interrupt Controller). @@ -240,8 +240,8 @@ static C3_SYS_GATE(sys_eth_mac, SYS_CLK_EN0_REG0, 26, 0); * used by our GIC is the public driver in kernel, and there is no management * clock in the driver. */ -static C3_SYS_GATE(sys_gic, SYS_CLK_EN0_REG0, 27, CLK_IS_CRITICAL); -static C3_SYS_GATE(sys_rama, SYS_CLK_EN0_REG0, 28, 0); +static C3_SYS_PCLK(sys_gic, SYS_CLK_EN0_REG0, 27, CLK_IS_CRITICAL); +static C3_SYS_PCLK(sys_rama, SYS_CLK_EN0_REG0, 28, 0); /* * NOTE: sys_big_nic provides the clock to the control bus of the NIC(Network @@ -249,84 +249,84 @@ static C3_SYS_GATE(sys_rama, SYS_CLK_EN0_REG0, 28, 0); * SPIFC, CAPU, JTAG, EMMC, SDIO, sec_top, USB, Audio, ETH, SPICC) in the * system. After clock is disabled, The NIC cannot work. */ -static C3_SYS_GATE(sys_big_nic, SYS_CLK_EN0_REG0, 29, CLK_IS_CRITICAL); -static C3_SYS_GATE(sys_ramb, SYS_CLK_EN0_REG0, 30, 0); -static C3_SYS_GATE(sys_audio_pclk, SYS_CLK_EN0_REG0, 31, 0); -static C3_SYS_GATE(sys_pwm_kl, SYS_CLK_EN0_REG1, 0, 0); -static C3_SYS_GATE(sys_pwm_ij, SYS_CLK_EN0_REG1, 1, 0); -static C3_SYS_GATE(sys_usb, SYS_CLK_EN0_REG1, 2, 0); -static C3_SYS_GATE(sys_sd_emmc_a, SYS_CLK_EN0_REG1, 3, 0); -static C3_SYS_GATE(sys_sd_emmc_c, SYS_CLK_EN0_REG1, 4, 0); -static C3_SYS_GATE(sys_pwm_ab, SYS_CLK_EN0_REG1, 5, 0); -static C3_SYS_GATE(sys_pwm_cd, SYS_CLK_EN0_REG1, 6, 0); -static C3_SYS_GATE(sys_pwm_ef, SYS_CLK_EN0_REG1, 7, 0); -static C3_SYS_GATE(sys_pwm_gh, SYS_CLK_EN0_REG1, 8, 0); -static C3_SYS_GATE(sys_spicc_1, SYS_CLK_EN0_REG1, 9, 0); -static C3_SYS_GATE(sys_spicc_0, SYS_CLK_EN0_REG1, 10, 0); -static C3_SYS_GATE(sys_uart_a, SYS_CLK_EN0_REG1, 11, 0); -static C3_SYS_GATE(sys_uart_b, SYS_CLK_EN0_REG1, 12, 0); -static C3_SYS_GATE(sys_uart_c, SYS_CLK_EN0_REG1, 13, 0); -static C3_SYS_GATE(sys_uart_d, SYS_CLK_EN0_REG1, 14, 0); -static C3_SYS_GATE(sys_uart_e, SYS_CLK_EN0_REG1, 15, 0); -static C3_SYS_GATE(sys_i2c_m_a, SYS_CLK_EN0_REG1, 16, 0); -static C3_SYS_GATE(sys_i2c_m_b, SYS_CLK_EN0_REG1, 17, 0); -static C3_SYS_GATE(sys_i2c_m_c, SYS_CLK_EN0_REG1, 18, 0); -static C3_SYS_GATE(sys_i2c_m_d, SYS_CLK_EN0_REG1, 19, 0); -static C3_SYS_GATE(sys_i2c_s_a, SYS_CLK_EN0_REG1, 20, 0); -static C3_SYS_GATE(sys_rtc, SYS_CLK_EN0_REG1, 21, 0); -static C3_SYS_GATE(sys_ge2d, SYS_CLK_EN0_REG1, 22, 0); -static C3_SYS_GATE(sys_isp, SYS_CLK_EN0_REG1, 23, 0); -static C3_SYS_GATE(sys_gpv_isp_nic, SYS_CLK_EN0_REG1, 24, 0); -static C3_SYS_GATE(sys_gpv_cve_nic, SYS_CLK_EN0_REG1, 25, 0); -static C3_SYS_GATE(sys_mipi_dsi_host, SYS_CLK_EN0_REG1, 26, 0); -static C3_SYS_GATE(sys_mipi_dsi_phy, SYS_CLK_EN0_REG1, 27, 0); -static C3_SYS_GATE(sys_eth_phy, SYS_CLK_EN0_REG1, 28, 0); -static C3_SYS_GATE(sys_acodec, SYS_CLK_EN0_REG1, 29, 0); -static C3_SYS_GATE(sys_dwap, SYS_CLK_EN0_REG1, 30, 0); -static C3_SYS_GATE(sys_dos, SYS_CLK_EN0_REG1, 31, 0); -static C3_SYS_GATE(sys_cve, SYS_CLK_EN0_REG2, 0, 0); -static C3_SYS_GATE(sys_vout, SYS_CLK_EN0_REG2, 1, 0); -static C3_SYS_GATE(sys_vc9000e, SYS_CLK_EN0_REG2, 2, 0); -static C3_SYS_GATE(sys_pwm_mn, SYS_CLK_EN0_REG2, 3, 0); -static C3_SYS_GATE(sys_sd_emmc_b, SYS_CLK_EN0_REG2, 4, 0); +static C3_SYS_PCLK(sys_big_nic, SYS_CLK_EN0_REG0, 29, CLK_IS_CRITICAL); +static C3_SYS_PCLK(sys_ramb, SYS_CLK_EN0_REG0, 30, 0); +static C3_SYS_PCLK(sys_audio_pclk, SYS_CLK_EN0_REG0, 31, 0); +static C3_SYS_PCLK(sys_pwm_kl, SYS_CLK_EN0_REG1, 0, 0); +static C3_SYS_PCLK(sys_pwm_ij, SYS_CLK_EN0_REG1, 1, 0); +static C3_SYS_PCLK(sys_usb, SYS_CLK_EN0_REG1, 2, 0); +static C3_SYS_PCLK(sys_sd_emmc_a, SYS_CLK_EN0_REG1, 3, 0); +static C3_SYS_PCLK(sys_sd_emmc_c, SYS_CLK_EN0_REG1, 4, 0); +static C3_SYS_PCLK(sys_pwm_ab, SYS_CLK_EN0_REG1, 5, 0); +static C3_SYS_PCLK(sys_pwm_cd, SYS_CLK_EN0_REG1, 6, 0); +static C3_SYS_PCLK(sys_pwm_ef, SYS_CLK_EN0_REG1, 7, 0); +static C3_SYS_PCLK(sys_pwm_gh, SYS_CLK_EN0_REG1, 8, 0); +static C3_SYS_PCLK(sys_spicc_1, SYS_CLK_EN0_REG1, 9, 0); +static C3_SYS_PCLK(sys_spicc_0, SYS_CLK_EN0_REG1, 10, 0); +static C3_SYS_PCLK(sys_uart_a, SYS_CLK_EN0_REG1, 11, 0); +static C3_SYS_PCLK(sys_uart_b, SYS_CLK_EN0_REG1, 12, 0); +static C3_SYS_PCLK(sys_uart_c, SYS_CLK_EN0_REG1, 13, 0); +static C3_SYS_PCLK(sys_uart_d, SYS_CLK_EN0_REG1, 14, 0); +static C3_SYS_PCLK(sys_uart_e, SYS_CLK_EN0_REG1, 15, 0); +static C3_SYS_PCLK(sys_i2c_m_a, SYS_CLK_EN0_REG1, 16, 0); +static C3_SYS_PCLK(sys_i2c_m_b, SYS_CLK_EN0_REG1, 17, 0); +static C3_SYS_PCLK(sys_i2c_m_c, SYS_CLK_EN0_REG1, 18, 0); +static C3_SYS_PCLK(sys_i2c_m_d, SYS_CLK_EN0_REG1, 19, 0); +static C3_SYS_PCLK(sys_i2c_s_a, SYS_CLK_EN0_REG1, 20, 0); +static C3_SYS_PCLK(sys_rtc, SYS_CLK_EN0_REG1, 21, 0); +static C3_SYS_PCLK(sys_ge2d, SYS_CLK_EN0_REG1, 22, 0); +static C3_SYS_PCLK(sys_isp, SYS_CLK_EN0_REG1, 23, 0); +static C3_SYS_PCLK(sys_gpv_isp_nic, SYS_CLK_EN0_REG1, 24, 0); +static C3_SYS_PCLK(sys_gpv_cve_nic, SYS_CLK_EN0_REG1, 25, 0); +static C3_SYS_PCLK(sys_mipi_dsi_host, SYS_CLK_EN0_REG1, 26, 0); +static C3_SYS_PCLK(sys_mipi_dsi_phy, SYS_CLK_EN0_REG1, 27, 0); +static C3_SYS_PCLK(sys_eth_phy, SYS_CLK_EN0_REG1, 28, 0); +static C3_SYS_PCLK(sys_acodec, SYS_CLK_EN0_REG1, 29, 0); +static C3_SYS_PCLK(sys_dwap, SYS_CLK_EN0_REG1, 30, 0); +static C3_SYS_PCLK(sys_dos, SYS_CLK_EN0_REG1, 31, 0); +static C3_SYS_PCLK(sys_cve, SYS_CLK_EN0_REG2, 0, 0); +static C3_SYS_PCLK(sys_vout, SYS_CLK_EN0_REG2, 1, 0); +static C3_SYS_PCLK(sys_vc9000e, SYS_CLK_EN0_REG2, 2, 0); +static C3_SYS_PCLK(sys_pwm_mn, SYS_CLK_EN0_REG2, 3, 0); +static C3_SYS_PCLK(sys_sd_emmc_b, SYS_CLK_EN0_REG2, 4, 0); -#define C3_AXI_GATE(_name, _reg, _bit, _flags) \ - C3_CLK_GATE(_name, _reg, _bit, axiclk, \ - &clk_regmap_gate_ops, _flags) +#define C3_AXI_PCLK(_name, _reg, _bit, _flags) \ + C3_PCLK(_name, _reg, _bit, "axiclk", \ + &clk_regmap_gate_ops, _flags) /* * NOTE: axi_sys_nic provides the clock to the AXI bus of the system NIC. After * clock is disabled, The NIC cannot work. */ -static C3_AXI_GATE(axi_sys_nic, AXI_CLK_EN0, 2, CLK_IS_CRITICAL); -static C3_AXI_GATE(axi_isp_nic, AXI_CLK_EN0, 3, 0); -static C3_AXI_GATE(axi_cve_nic, AXI_CLK_EN0, 4, 0); -static C3_AXI_GATE(axi_ramb, AXI_CLK_EN0, 5, 0); -static C3_AXI_GATE(axi_rama, AXI_CLK_EN0, 6, 0); +static C3_AXI_PCLK(axi_sys_nic, AXI_CLK_EN0, 2, CLK_IS_CRITICAL); +static C3_AXI_PCLK(axi_isp_nic, AXI_CLK_EN0, 3, 0); +static C3_AXI_PCLK(axi_cve_nic, AXI_CLK_EN0, 4, 0); +static C3_AXI_PCLK(axi_ramb, AXI_CLK_EN0, 5, 0); +static C3_AXI_PCLK(axi_rama, AXI_CLK_EN0, 6, 0); /* * NOTE: axi_cpu_dmc provides the clock to the AXI bus where the CPU accesses * the DDR. After clock is disabled, The CPU will not have access to the DDR. */ -static C3_AXI_GATE(axi_cpu_dmc, AXI_CLK_EN0, 7, CLK_IS_CRITICAL); -static C3_AXI_GATE(axi_nic, AXI_CLK_EN0, 8, 0); -static C3_AXI_GATE(axi_dma, AXI_CLK_EN0, 9, 0); +static C3_AXI_PCLK(axi_cpu_dmc, AXI_CLK_EN0, 7, CLK_IS_CRITICAL); +static C3_AXI_PCLK(axi_nic, AXI_CLK_EN0, 8, 0); +static C3_AXI_PCLK(axi_dma, AXI_CLK_EN0, 9, 0); /* * NOTE: axi_mux_nic provides the clock to the NIC's AXI bus for NN(Neural * Network) and other devices(CPU, EMMC, SDIO, sec_top, USB, Audio, ETH, SPICC) * to access RAM space. */ -static C3_AXI_GATE(axi_mux_nic, AXI_CLK_EN0, 10, 0); -static C3_AXI_GATE(axi_cve, AXI_CLK_EN0, 12, 0); +static C3_AXI_PCLK(axi_mux_nic, AXI_CLK_EN0, 10, 0); +static C3_AXI_PCLK(axi_cve, AXI_CLK_EN0, 12, 0); /* * NOTE: axi_dev1_dmc provides the clock for the peripherals(EMMC, SDIO, * sec_top, USB, Audio, ETH, SPICC) to access the AXI bus of the DDR. */ -static C3_AXI_GATE(axi_dev1_dmc, AXI_CLK_EN0, 13, 0); -static C3_AXI_GATE(axi_dev0_dmc, AXI_CLK_EN0, 14, 0); -static C3_AXI_GATE(axi_dsp_dmc, AXI_CLK_EN0, 15, 0); +static C3_AXI_PCLK(axi_dev1_dmc, AXI_CLK_EN0, 13, 0); +static C3_AXI_PCLK(axi_dev0_dmc, AXI_CLK_EN0, 14, 0); +static C3_AXI_PCLK(axi_dsp_dmc, AXI_CLK_EN0, 15, 0); /* * clk_12_24m model @@ -335,7 +335,7 @@ static C3_AXI_GATE(axi_dsp_dmc, AXI_CLK_EN0, 15, 0); * xtal---->| gate |---->| div |------------>| pad | * |------| |-----| |-----| */ -static struct clk_regmap clk_12_24m_in = { +static struct clk_regmap c3_clk_12_24m_in = { .data = &(struct clk_regmap_gate_data) { .offset = CLK12_24_CTRL, .bit_idx = 11, @@ -350,7 +350,7 @@ static struct clk_regmap clk_12_24m_in = { }, }; -static struct clk_regmap clk_12_24m = { +static struct clk_regmap c3_clk_12_24m = { .data = &(struct clk_regmap_div_data) { .offset = CLK12_24_CTRL, .shift = 10, @@ -360,14 +360,14 @@ static struct clk_regmap clk_12_24m = { .name = "clk_12_24m", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &clk_12_24m_in.hw + &c3_clk_12_24m_in.hw }, .num_parents = 1, }, }; /* Fix me: set value 0 will div by 2 like value 1 */ -static struct clk_regmap fclk_25m_div = { +static struct clk_regmap c3_fclk_25m_div = { .data = &(struct clk_regmap_div_data) { .offset = CLK12_24_CTRL, .shift = 0, @@ -383,7 +383,7 @@ static struct clk_regmap fclk_25m_div = { }, }; -static struct clk_regmap fclk_25m = { +static struct clk_regmap c3_fclk_25m = { .data = &(struct clk_regmap_gate_data) { .offset = CLK12_24_CTRL, .bit_idx = 12, @@ -392,7 +392,7 @@ static struct clk_regmap fclk_25m = { .name = "fclk_25m", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_25m_div.hw + &c3_fclk_25m_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -404,11 +404,10 @@ static struct clk_regmap fclk_25m = { * is manged by clock measures module. Their hardware are out of clock tree. * Channel 4 8 9 10 11 13 14 15 16 18 are not connected. */ -static u32 gen_parent_table[] = { 0, 1, 2, 5, 6, 7, 17, 19, 20, 21, 22, 23, 24}; - -static const struct clk_parent_data gen_parent_data[] = { +static u32 c3_gen_parents_val_table[] = { 0, 1, 2, 5, 6, 7, 17, 19, 20, 21, 22, 23, 24}; +static const struct clk_parent_data c3_gen_parents[] = { { .fw_name = "oscin" }, - { .hw = &rtc_clk.hw }, + { .hw = &c3_rtc_clk.hw }, { .fw_name = "sysplldiv16" }, { .fw_name = "gp0" }, { .fw_name = "gp1" }, @@ -422,22 +421,22 @@ static const struct clk_parent_data gen_parent_data[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap gen_sel = { +static struct clk_regmap c3_gen_sel = { .data = &(struct clk_regmap_mux_data) { .offset = GEN_CLK_CTRL, .mask = 0x1f, .shift = 12, - .table = gen_parent_table, + .table = c3_gen_parents_val_table, }, .hw.init = &(struct clk_init_data) { .name = "gen_sel", .ops = &clk_regmap_mux_ops, - .parent_data = gen_parent_data, - .num_parents = ARRAY_SIZE(gen_parent_data), + .parent_data = c3_gen_parents, + .num_parents = ARRAY_SIZE(c3_gen_parents), }, }; -static struct clk_regmap gen_div = { +static struct clk_regmap c3_gen_div = { .data = &(struct clk_regmap_div_data) { .offset = GEN_CLK_CTRL, .shift = 0, @@ -447,14 +446,14 @@ static struct clk_regmap gen_div = { .name = "gen_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &gen_sel.hw + &c3_gen_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap gen = { +static struct clk_regmap c3_gen = { .data = &(struct clk_regmap_gate_data) { .offset = GEN_CLK_CTRL, .bit_idx = 11, @@ -463,19 +462,19 @@ static struct clk_regmap gen = { .name = "gen", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &gen_div.hw + &c3_gen_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data saradc_parent_data[] = { +static const struct clk_parent_data c3_saradc_parents[] = { { .fw_name = "oscin" }, { .fw_name = "sysclk" } }; -static struct clk_regmap saradc_sel = { +static struct clk_regmap c3_saradc_sel = { .data = &(struct clk_regmap_mux_data) { .offset = SAR_CLK_CTRL0, .mask = 0x1, @@ -484,12 +483,12 @@ static struct clk_regmap saradc_sel = { .hw.init = &(struct clk_init_data) { .name = "saradc_sel", .ops = &clk_regmap_mux_ops, - .parent_data = saradc_parent_data, - .num_parents = ARRAY_SIZE(saradc_parent_data), + .parent_data = c3_saradc_parents, + .num_parents = ARRAY_SIZE(c3_saradc_parents), }, }; -static struct clk_regmap saradc_div = { +static struct clk_regmap c3_saradc_div = { .data = &(struct clk_regmap_div_data) { .offset = SAR_CLK_CTRL0, .shift = 0, @@ -499,14 +498,14 @@ static struct clk_regmap saradc_div = { .name = "saradc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &saradc_sel.hw + &c3_saradc_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap saradc = { +static struct clk_regmap c3_saradc = { .data = &(struct clk_regmap_gate_data) { .offset = SAR_CLK_CTRL0, .bit_idx = 8, @@ -515,21 +514,21 @@ static struct clk_regmap saradc = { .name = "saradc", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &saradc_div.hw + &c3_saradc_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data pwm_parent_data[] = { +static const struct clk_parent_data c3_pwm_parents[] = { { .fw_name = "oscin" }, { .fw_name = "gp1" }, { .fw_name = "fdiv4" }, { .fw_name = "fdiv3" } }; -#define AML_PWM_CLK_MUX(_name, _reg, _shift) { \ +#define C3_PWM_CLK_MUX(_name, _reg, _shift) { \ .data = &(struct clk_regmap_mux_data) { \ .offset = _reg, \ .mask = 0x3, \ @@ -538,12 +537,12 @@ static const struct clk_parent_data pwm_parent_data[] = { .hw.init = &(struct clk_init_data) { \ .name = #_name "_sel", \ .ops = &clk_regmap_mux_ops, \ - .parent_data = pwm_parent_data, \ - .num_parents = ARRAY_SIZE(pwm_parent_data), \ + .parent_data = c3_pwm_parents, \ + .num_parents = ARRAY_SIZE(c3_pwm_parents), \ }, \ } -#define AML_PWM_CLK_DIV(_name, _reg, _shift) { \ +#define C3_PWM_CLK_DIV(_name, _reg, _shift) { \ .data = &(struct clk_regmap_div_data) { \ .offset = _reg, \ .shift = _shift, \ @@ -558,7 +557,7 @@ static const struct clk_parent_data pwm_parent_data[] = { }, \ } -#define AML_PWM_CLK_GATE(_name, _reg, _bit) { \ +#define C3_PWM_CLK_GATE(_name, _reg, _bit) { \ .data = &(struct clk_regmap_gate_data) { \ .offset = _reg, \ .bit_idx = _bit, \ @@ -572,105 +571,105 @@ static const struct clk_parent_data pwm_parent_data[] = { }, \ } -static struct clk_regmap pwm_a_sel = - AML_PWM_CLK_MUX(pwm_a, PWM_CLK_AB_CTRL, 9); -static struct clk_regmap pwm_a_div = - AML_PWM_CLK_DIV(pwm_a, PWM_CLK_AB_CTRL, 0); -static struct clk_regmap pwm_a = - AML_PWM_CLK_GATE(pwm_a, PWM_CLK_AB_CTRL, 8); +static struct clk_regmap c3_pwm_a_sel = + C3_PWM_CLK_MUX(pwm_a, PWM_CLK_AB_CTRL, 9); +static struct clk_regmap c3_pwm_a_div = + C3_PWM_CLK_DIV(pwm_a, PWM_CLK_AB_CTRL, 0); +static struct clk_regmap c3_pwm_a = + C3_PWM_CLK_GATE(pwm_a, PWM_CLK_AB_CTRL, 8); -static struct clk_regmap pwm_b_sel = - AML_PWM_CLK_MUX(pwm_b, PWM_CLK_AB_CTRL, 25); -static struct clk_regmap pwm_b_div = - AML_PWM_CLK_DIV(pwm_b, PWM_CLK_AB_CTRL, 16); -static struct clk_regmap pwm_b = - AML_PWM_CLK_GATE(pwm_b, PWM_CLK_AB_CTRL, 24); +static struct clk_regmap c3_pwm_b_sel = + C3_PWM_CLK_MUX(pwm_b, PWM_CLK_AB_CTRL, 25); +static struct clk_regmap c3_pwm_b_div = + C3_PWM_CLK_DIV(pwm_b, PWM_CLK_AB_CTRL, 16); +static struct clk_regmap c3_pwm_b = + C3_PWM_CLK_GATE(pwm_b, PWM_CLK_AB_CTRL, 24); -static struct clk_regmap pwm_c_sel = - AML_PWM_CLK_MUX(pwm_c, PWM_CLK_CD_CTRL, 9); -static struct clk_regmap pwm_c_div = - AML_PWM_CLK_DIV(pwm_c, PWM_CLK_CD_CTRL, 0); -static struct clk_regmap pwm_c = - AML_PWM_CLK_GATE(pwm_c, PWM_CLK_CD_CTRL, 8); +static struct clk_regmap c3_pwm_c_sel = + C3_PWM_CLK_MUX(pwm_c, PWM_CLK_CD_CTRL, 9); +static struct clk_regmap c3_pwm_c_div = + C3_PWM_CLK_DIV(pwm_c, PWM_CLK_CD_CTRL, 0); +static struct clk_regmap c3_pwm_c = + C3_PWM_CLK_GATE(pwm_c, PWM_CLK_CD_CTRL, 8); -static struct clk_regmap pwm_d_sel = - AML_PWM_CLK_MUX(pwm_d, PWM_CLK_CD_CTRL, 25); -static struct clk_regmap pwm_d_div = - AML_PWM_CLK_DIV(pwm_d, PWM_CLK_CD_CTRL, 16); -static struct clk_regmap pwm_d = - AML_PWM_CLK_GATE(pwm_d, PWM_CLK_CD_CTRL, 24); +static struct clk_regmap c3_pwm_d_sel = + C3_PWM_CLK_MUX(pwm_d, PWM_CLK_CD_CTRL, 25); +static struct clk_regmap c3_pwm_d_div = + C3_PWM_CLK_DIV(pwm_d, PWM_CLK_CD_CTRL, 16); +static struct clk_regmap c3_pwm_d = + C3_PWM_CLK_GATE(pwm_d, PWM_CLK_CD_CTRL, 24); -static struct clk_regmap pwm_e_sel = - AML_PWM_CLK_MUX(pwm_e, PWM_CLK_EF_CTRL, 9); -static struct clk_regmap pwm_e_div = - AML_PWM_CLK_DIV(pwm_e, PWM_CLK_EF_CTRL, 0); -static struct clk_regmap pwm_e = - AML_PWM_CLK_GATE(pwm_e, PWM_CLK_EF_CTRL, 8); +static struct clk_regmap c3_pwm_e_sel = + C3_PWM_CLK_MUX(pwm_e, PWM_CLK_EF_CTRL, 9); +static struct clk_regmap c3_pwm_e_div = + C3_PWM_CLK_DIV(pwm_e, PWM_CLK_EF_CTRL, 0); +static struct clk_regmap c3_pwm_e = + C3_PWM_CLK_GATE(pwm_e, PWM_CLK_EF_CTRL, 8); -static struct clk_regmap pwm_f_sel = - AML_PWM_CLK_MUX(pwm_f, PWM_CLK_EF_CTRL, 25); -static struct clk_regmap pwm_f_div = - AML_PWM_CLK_DIV(pwm_f, PWM_CLK_EF_CTRL, 16); -static struct clk_regmap pwm_f = - AML_PWM_CLK_GATE(pwm_f, PWM_CLK_EF_CTRL, 24); +static struct clk_regmap c3_pwm_f_sel = + C3_PWM_CLK_MUX(pwm_f, PWM_CLK_EF_CTRL, 25); +static struct clk_regmap c3_pwm_f_div = + C3_PWM_CLK_DIV(pwm_f, PWM_CLK_EF_CTRL, 16); +static struct clk_regmap c3_pwm_f = + C3_PWM_CLK_GATE(pwm_f, PWM_CLK_EF_CTRL, 24); -static struct clk_regmap pwm_g_sel = - AML_PWM_CLK_MUX(pwm_g, PWM_CLK_GH_CTRL, 9); -static struct clk_regmap pwm_g_div = - AML_PWM_CLK_DIV(pwm_g, PWM_CLK_GH_CTRL, 0); -static struct clk_regmap pwm_g = - AML_PWM_CLK_GATE(pwm_g, PWM_CLK_GH_CTRL, 8); +static struct clk_regmap c3_pwm_g_sel = + C3_PWM_CLK_MUX(pwm_g, PWM_CLK_GH_CTRL, 9); +static struct clk_regmap c3_pwm_g_div = + C3_PWM_CLK_DIV(pwm_g, PWM_CLK_GH_CTRL, 0); +static struct clk_regmap c3_pwm_g = + C3_PWM_CLK_GATE(pwm_g, PWM_CLK_GH_CTRL, 8); -static struct clk_regmap pwm_h_sel = - AML_PWM_CLK_MUX(pwm_h, PWM_CLK_GH_CTRL, 25); -static struct clk_regmap pwm_h_div = - AML_PWM_CLK_DIV(pwm_h, PWM_CLK_GH_CTRL, 16); -static struct clk_regmap pwm_h = - AML_PWM_CLK_GATE(pwm_h, PWM_CLK_GH_CTRL, 24); +static struct clk_regmap c3_pwm_h_sel = + C3_PWM_CLK_MUX(pwm_h, PWM_CLK_GH_CTRL, 25); +static struct clk_regmap c3_pwm_h_div = + C3_PWM_CLK_DIV(pwm_h, PWM_CLK_GH_CTRL, 16); +static struct clk_regmap c3_pwm_h = + C3_PWM_CLK_GATE(pwm_h, PWM_CLK_GH_CTRL, 24); -static struct clk_regmap pwm_i_sel = - AML_PWM_CLK_MUX(pwm_i, PWM_CLK_IJ_CTRL, 9); -static struct clk_regmap pwm_i_div = - AML_PWM_CLK_DIV(pwm_i, PWM_CLK_IJ_CTRL, 0); -static struct clk_regmap pwm_i = - AML_PWM_CLK_GATE(pwm_i, PWM_CLK_IJ_CTRL, 8); +static struct clk_regmap c3_pwm_i_sel = + C3_PWM_CLK_MUX(pwm_i, PWM_CLK_IJ_CTRL, 9); +static struct clk_regmap c3_pwm_i_div = + C3_PWM_CLK_DIV(pwm_i, PWM_CLK_IJ_CTRL, 0); +static struct clk_regmap c3_pwm_i = + C3_PWM_CLK_GATE(pwm_i, PWM_CLK_IJ_CTRL, 8); -static struct clk_regmap pwm_j_sel = - AML_PWM_CLK_MUX(pwm_j, PWM_CLK_IJ_CTRL, 25); -static struct clk_regmap pwm_j_div = - AML_PWM_CLK_DIV(pwm_j, PWM_CLK_IJ_CTRL, 16); -static struct clk_regmap pwm_j = - AML_PWM_CLK_GATE(pwm_j, PWM_CLK_IJ_CTRL, 24); +static struct clk_regmap c3_pwm_j_sel = + C3_PWM_CLK_MUX(pwm_j, PWM_CLK_IJ_CTRL, 25); +static struct clk_regmap c3_pwm_j_div = + C3_PWM_CLK_DIV(pwm_j, PWM_CLK_IJ_CTRL, 16); +static struct clk_regmap c3_pwm_j = + C3_PWM_CLK_GATE(pwm_j, PWM_CLK_IJ_CTRL, 24); -static struct clk_regmap pwm_k_sel = - AML_PWM_CLK_MUX(pwm_k, PWM_CLK_KL_CTRL, 9); -static struct clk_regmap pwm_k_div = - AML_PWM_CLK_DIV(pwm_k, PWM_CLK_KL_CTRL, 0); -static struct clk_regmap pwm_k = - AML_PWM_CLK_GATE(pwm_k, PWM_CLK_KL_CTRL, 8); +static struct clk_regmap c3_pwm_k_sel = + C3_PWM_CLK_MUX(pwm_k, PWM_CLK_KL_CTRL, 9); +static struct clk_regmap c3_pwm_k_div = + C3_PWM_CLK_DIV(pwm_k, PWM_CLK_KL_CTRL, 0); +static struct clk_regmap c3_pwm_k = + C3_PWM_CLK_GATE(pwm_k, PWM_CLK_KL_CTRL, 8); -static struct clk_regmap pwm_l_sel = - AML_PWM_CLK_MUX(pwm_l, PWM_CLK_KL_CTRL, 25); -static struct clk_regmap pwm_l_div = - AML_PWM_CLK_DIV(pwm_l, PWM_CLK_KL_CTRL, 16); -static struct clk_regmap pwm_l = - AML_PWM_CLK_GATE(pwm_l, PWM_CLK_KL_CTRL, 24); +static struct clk_regmap c3_pwm_l_sel = + C3_PWM_CLK_MUX(pwm_l, PWM_CLK_KL_CTRL, 25); +static struct clk_regmap c3_pwm_l_div = + C3_PWM_CLK_DIV(pwm_l, PWM_CLK_KL_CTRL, 16); +static struct clk_regmap c3_pwm_l = + C3_PWM_CLK_GATE(pwm_l, PWM_CLK_KL_CTRL, 24); -static struct clk_regmap pwm_m_sel = - AML_PWM_CLK_MUX(pwm_m, PWM_CLK_MN_CTRL, 9); -static struct clk_regmap pwm_m_div = - AML_PWM_CLK_DIV(pwm_m, PWM_CLK_MN_CTRL, 0); -static struct clk_regmap pwm_m = - AML_PWM_CLK_GATE(pwm_m, PWM_CLK_MN_CTRL, 8); +static struct clk_regmap c3_pwm_m_sel = + C3_PWM_CLK_MUX(pwm_m, PWM_CLK_MN_CTRL, 9); +static struct clk_regmap c3_pwm_m_div = + C3_PWM_CLK_DIV(pwm_m, PWM_CLK_MN_CTRL, 0); +static struct clk_regmap c3_pwm_m = + C3_PWM_CLK_GATE(pwm_m, PWM_CLK_MN_CTRL, 8); -static struct clk_regmap pwm_n_sel = - AML_PWM_CLK_MUX(pwm_n, PWM_CLK_MN_CTRL, 25); -static struct clk_regmap pwm_n_div = - AML_PWM_CLK_DIV(pwm_n, PWM_CLK_MN_CTRL, 16); -static struct clk_regmap pwm_n = - AML_PWM_CLK_GATE(pwm_n, PWM_CLK_MN_CTRL, 24); +static struct clk_regmap c3_pwm_n_sel = + C3_PWM_CLK_MUX(pwm_n, PWM_CLK_MN_CTRL, 25); +static struct clk_regmap c3_pwm_n_div = + C3_PWM_CLK_DIV(pwm_n, PWM_CLK_MN_CTRL, 16); +static struct clk_regmap c3_pwm_n = + C3_PWM_CLK_GATE(pwm_n, PWM_CLK_MN_CTRL, 24); -static const struct clk_parent_data spicc_parent_data[] = { +static const struct clk_parent_data c3_spicc_parents[] = { { .fw_name = "oscin" }, { .fw_name = "sysclk" }, { .fw_name = "fdiv4" }, @@ -681,7 +680,7 @@ static const struct clk_parent_data spicc_parent_data[] = { { .fw_name = "gp1" } }; -static struct clk_regmap spicc_a_sel = { +static struct clk_regmap c3_spicc_a_sel = { .data = &(struct clk_regmap_mux_data) { .offset = SPICC_CLK_CTRL, .mask = 0x7, @@ -690,12 +689,12 @@ static struct clk_regmap spicc_a_sel = { .hw.init = &(struct clk_init_data) { .name = "spicc_a_sel", .ops = &clk_regmap_mux_ops, - .parent_data = spicc_parent_data, - .num_parents = ARRAY_SIZE(spicc_parent_data), + .parent_data = c3_spicc_parents, + .num_parents = ARRAY_SIZE(c3_spicc_parents), }, }; -static struct clk_regmap spicc_a_div = { +static struct clk_regmap c3_spicc_a_div = { .data = &(struct clk_regmap_div_data) { .offset = SPICC_CLK_CTRL, .shift = 0, @@ -705,14 +704,14 @@ static struct clk_regmap spicc_a_div = { .name = "spicc_a_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &spicc_a_sel.hw + &c3_spicc_a_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap spicc_a = { +static struct clk_regmap c3_spicc_a = { .data = &(struct clk_regmap_gate_data) { .offset = SPICC_CLK_CTRL, .bit_idx = 6, @@ -721,14 +720,14 @@ static struct clk_regmap spicc_a = { .name = "spicc_a", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &spicc_a_div.hw + &c3_spicc_a_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap spicc_b_sel = { +static struct clk_regmap c3_spicc_b_sel = { .data = &(struct clk_regmap_mux_data) { .offset = SPICC_CLK_CTRL, .mask = 0x7, @@ -737,12 +736,12 @@ static struct clk_regmap spicc_b_sel = { .hw.init = &(struct clk_init_data) { .name = "spicc_b_sel", .ops = &clk_regmap_mux_ops, - .parent_data = spicc_parent_data, - .num_parents = ARRAY_SIZE(spicc_parent_data), + .parent_data = c3_spicc_parents, + .num_parents = ARRAY_SIZE(c3_spicc_parents), }, }; -static struct clk_regmap spicc_b_div = { +static struct clk_regmap c3_spicc_b_div = { .data = &(struct clk_regmap_div_data) { .offset = SPICC_CLK_CTRL, .shift = 16, @@ -752,14 +751,14 @@ static struct clk_regmap spicc_b_div = { .name = "spicc_b_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &spicc_b_sel.hw + &c3_spicc_b_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap spicc_b = { +static struct clk_regmap c3_spicc_b = { .data = &(struct clk_regmap_gate_data) { .offset = SPICC_CLK_CTRL, .bit_idx = 22, @@ -768,14 +767,14 @@ static struct clk_regmap spicc_b = { .name = "spicc_b", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &spicc_b_div.hw + &c3_spicc_b_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data spifc_parent_data[] = { +static const struct clk_parent_data c3_spifc_parents[] = { { .fw_name = "gp0" }, { .fw_name = "fdiv2" }, { .fw_name = "fdiv3" }, @@ -786,7 +785,7 @@ static const struct clk_parent_data spifc_parent_data[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap spifc_sel = { +static struct clk_regmap c3_spifc_sel = { .data = &(struct clk_regmap_mux_data) { .offset = SPIFC_CLK_CTRL, .mask = 0x7, @@ -795,12 +794,12 @@ static struct clk_regmap spifc_sel = { .hw.init = &(struct clk_init_data) { .name = "spifc_sel", .ops = &clk_regmap_mux_ops, - .parent_data = spifc_parent_data, - .num_parents = ARRAY_SIZE(spifc_parent_data), + .parent_data = c3_spifc_parents, + .num_parents = ARRAY_SIZE(c3_spifc_parents), }, }; -static struct clk_regmap spifc_div = { +static struct clk_regmap c3_spifc_div = { .data = &(struct clk_regmap_div_data) { .offset = SPIFC_CLK_CTRL, .shift = 0, @@ -810,14 +809,14 @@ static struct clk_regmap spifc_div = { .name = "spifc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &spifc_sel.hw + &c3_spifc_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap spifc = { +static struct clk_regmap c3_spifc = { .data = &(struct clk_regmap_gate_data) { .offset = SPIFC_CLK_CTRL, .bit_idx = 8, @@ -826,14 +825,14 @@ static struct clk_regmap spifc = { .name = "spifc", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &spifc_div.hw + &c3_spifc_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data emmc_parent_data[] = { +static const struct clk_parent_data c3_sd_emmc_parents[] = { { .fw_name = "oscin" }, { .fw_name = "fdiv2" }, { .fw_name = "fdiv3" }, @@ -844,7 +843,7 @@ static const struct clk_parent_data emmc_parent_data[] = { { .fw_name = "gp0" } }; -static struct clk_regmap sd_emmc_a_sel = { +static struct clk_regmap c3_sd_emmc_a_sel = { .data = &(struct clk_regmap_mux_data) { .offset = SD_EMMC_CLK_CTRL, .mask = 0x7, @@ -853,12 +852,12 @@ static struct clk_regmap sd_emmc_a_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_sel", .ops = &clk_regmap_mux_ops, - .parent_data = emmc_parent_data, - .num_parents = ARRAY_SIZE(emmc_parent_data), + .parent_data = c3_sd_emmc_parents, + .num_parents = ARRAY_SIZE(c3_sd_emmc_parents), }, }; -static struct clk_regmap sd_emmc_a_div = { +static struct clk_regmap c3_sd_emmc_a_div = { .data = &(struct clk_regmap_div_data) { .offset = SD_EMMC_CLK_CTRL, .shift = 0, @@ -868,14 +867,14 @@ static struct clk_regmap sd_emmc_a_div = { .name = "sd_emmc_a_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &sd_emmc_a_sel.hw + &c3_sd_emmc_a_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap sd_emmc_a = { +static struct clk_regmap c3_sd_emmc_a = { .data = &(struct clk_regmap_gate_data) { .offset = SD_EMMC_CLK_CTRL, .bit_idx = 7, @@ -884,14 +883,14 @@ static struct clk_regmap sd_emmc_a = { .name = "sd_emmc_a", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &sd_emmc_a_div.hw + &c3_sd_emmc_a_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap sd_emmc_b_sel = { +static struct clk_regmap c3_sd_emmc_b_sel = { .data = &(struct clk_regmap_mux_data) { .offset = SD_EMMC_CLK_CTRL, .mask = 0x7, @@ -900,12 +899,12 @@ static struct clk_regmap sd_emmc_b_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_sel", .ops = &clk_regmap_mux_ops, - .parent_data = emmc_parent_data, - .num_parents = ARRAY_SIZE(emmc_parent_data), + .parent_data = c3_sd_emmc_parents, + .num_parents = ARRAY_SIZE(c3_sd_emmc_parents), }, }; -static struct clk_regmap sd_emmc_b_div = { +static struct clk_regmap c3_sd_emmc_b_div = { .data = &(struct clk_regmap_div_data) { .offset = SD_EMMC_CLK_CTRL, .shift = 16, @@ -915,14 +914,14 @@ static struct clk_regmap sd_emmc_b_div = { .name = "sd_emmc_b_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &sd_emmc_b_sel.hw + &c3_sd_emmc_b_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap sd_emmc_b = { +static struct clk_regmap c3_sd_emmc_b = { .data = &(struct clk_regmap_gate_data) { .offset = SD_EMMC_CLK_CTRL, .bit_idx = 23, @@ -931,14 +930,14 @@ static struct clk_regmap sd_emmc_b = { .name = "sd_emmc_b", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &sd_emmc_b_div.hw + &c3_sd_emmc_b_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap sd_emmc_c_sel = { +static struct clk_regmap c3_sd_emmc_c_sel = { .data = &(struct clk_regmap_mux_data) { .offset = NAND_CLK_CTRL, .mask = 0x7, @@ -947,12 +946,12 @@ static struct clk_regmap sd_emmc_c_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_sel", .ops = &clk_regmap_mux_ops, - .parent_data = emmc_parent_data, - .num_parents = ARRAY_SIZE(emmc_parent_data), + .parent_data = c3_sd_emmc_parents, + .num_parents = ARRAY_SIZE(c3_sd_emmc_parents), }, }; -static struct clk_regmap sd_emmc_c_div = { +static struct clk_regmap c3_sd_emmc_c_div = { .data = &(struct clk_regmap_div_data) { .offset = NAND_CLK_CTRL, .shift = 0, @@ -962,14 +961,14 @@ static struct clk_regmap sd_emmc_c_div = { .name = "sd_emmc_c_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &sd_emmc_c_sel.hw + &c3_sd_emmc_c_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap sd_emmc_c = { +static struct clk_regmap c3_sd_emmc_c = { .data = &(struct clk_regmap_gate_data) { .offset = NAND_CLK_CTRL, .bit_idx = 7, @@ -978,14 +977,14 @@ static struct clk_regmap sd_emmc_c = { .name = "sd_emmc_c", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &sd_emmc_c_div.hw + &c3_sd_emmc_c_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap ts_div = { +static struct clk_regmap c3_ts_div = { .data = &(struct clk_regmap_div_data) { .offset = TS_CLK_CTRL, .shift = 0, @@ -1001,7 +1000,7 @@ static struct clk_regmap ts_div = { }, }; -static struct clk_regmap ts = { +static struct clk_regmap c3_ts = { .data = &(struct clk_regmap_gate_data) { .offset = TS_CLK_CTRL, .bit_idx = 8, @@ -1010,29 +1009,29 @@ static struct clk_regmap ts = { .name = "ts", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &ts_div.hw + &c3_ts_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data eth_parent = { +static const struct clk_parent_data c3_eth_parents = { .fw_name = "fdiv2", }; -static struct clk_fixed_factor eth_125m_div = { +static struct clk_fixed_factor c3_eth_125m_div = { .mult = 1, .div = 8, .hw.init = &(struct clk_init_data) { .name = "eth_125m_div", .ops = &clk_fixed_factor_ops, - .parent_data = ð_parent, + .parent_data = &c3_eth_parents, .num_parents = 1, }, }; -static struct clk_regmap eth_125m = { +static struct clk_regmap c3_eth_125m = { .data = &(struct clk_regmap_gate_data) { .offset = ETH_CLK_CTRL, .bit_idx = 7, @@ -1041,14 +1040,14 @@ static struct clk_regmap eth_125m = { .name = "eth_125m", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - ð_125m_div.hw + &c3_eth_125m_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap eth_rmii_div = { +static struct clk_regmap c3_eth_rmii_div = { .data = &(struct clk_regmap_div_data) { .offset = ETH_CLK_CTRL, .shift = 0, @@ -1057,12 +1056,12 @@ static struct clk_regmap eth_rmii_div = { .hw.init = &(struct clk_init_data) { .name = "eth_rmii_div", .ops = &clk_regmap_divider_ops, - .parent_data = ð_parent, + .parent_data = &c3_eth_parents, .num_parents = 1, }, }; -static struct clk_regmap eth_rmii = { +static struct clk_regmap c3_eth_rmii = { .data = &(struct clk_regmap_gate_data) { .offset = ETH_CLK_CTRL, .bit_idx = 8, @@ -1071,14 +1070,14 @@ static struct clk_regmap eth_rmii = { .name = "eth_rmii", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - ð_rmii_div.hw + &c3_eth_rmii_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data mipi_dsi_meas_parent_data[] = { +static const struct clk_parent_data c3_mipi_dsi_meas_parents[] = { { .fw_name = "oscin" }, { .fw_name = "fdiv4" }, { .fw_name = "fdiv3" }, @@ -1089,7 +1088,7 @@ static const struct clk_parent_data mipi_dsi_meas_parent_data[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap mipi_dsi_meas_sel = { +static struct clk_regmap c3_mipi_dsi_meas_sel = { .data = &(struct clk_regmap_mux_data) { .offset = VDIN_MEAS_CLK_CTRL, .mask = 0x7, @@ -1098,12 +1097,12 @@ static struct clk_regmap mipi_dsi_meas_sel = { .hw.init = &(struct clk_init_data) { .name = "mipi_dsi_meas_sel", .ops = &clk_regmap_mux_ops, - .parent_data = mipi_dsi_meas_parent_data, - .num_parents = ARRAY_SIZE(mipi_dsi_meas_parent_data), + .parent_data = c3_mipi_dsi_meas_parents, + .num_parents = ARRAY_SIZE(c3_mipi_dsi_meas_parents), }, }; -static struct clk_regmap mipi_dsi_meas_div = { +static struct clk_regmap c3_mipi_dsi_meas_div = { .data = &(struct clk_regmap_div_data) { .offset = VDIN_MEAS_CLK_CTRL, .shift = 12, @@ -1113,14 +1112,14 @@ static struct clk_regmap mipi_dsi_meas_div = { .name = "mipi_dsi_meas_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &mipi_dsi_meas_sel.hw + &c3_mipi_dsi_meas_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap mipi_dsi_meas = { +static struct clk_regmap c3_mipi_dsi_meas = { .data = &(struct clk_regmap_gate_data) { .offset = VDIN_MEAS_CLK_CTRL, .bit_idx = 20, @@ -1129,14 +1128,14 @@ static struct clk_regmap mipi_dsi_meas = { .name = "mipi_dsi_meas", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &mipi_dsi_meas_div.hw + &c3_mipi_dsi_meas_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data dsi_phy_parent_data[] = { +static const struct clk_parent_data c3_dsi_phy_parents[] = { { .fw_name = "gp1" }, { .fw_name = "gp0" }, { .fw_name = "hifi" }, @@ -1147,7 +1146,7 @@ static const struct clk_parent_data dsi_phy_parent_data[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap dsi_phy_sel = { +static struct clk_regmap c3_dsi_phy_sel = { .data = &(struct clk_regmap_mux_data) { .offset = MIPIDSI_PHY_CLK_CTRL, .mask = 0x7, @@ -1156,12 +1155,12 @@ static struct clk_regmap dsi_phy_sel = { .hw.init = &(struct clk_init_data) { .name = "dsi_phy_sel", .ops = &clk_regmap_mux_ops, - .parent_data = dsi_phy_parent_data, - .num_parents = ARRAY_SIZE(dsi_phy_parent_data), + .parent_data = c3_dsi_phy_parents, + .num_parents = ARRAY_SIZE(c3_dsi_phy_parents), }, }; -static struct clk_regmap dsi_phy_div = { +static struct clk_regmap c3_dsi_phy_div = { .data = &(struct clk_regmap_div_data) { .offset = MIPIDSI_PHY_CLK_CTRL, .shift = 0, @@ -1171,14 +1170,14 @@ static struct clk_regmap dsi_phy_div = { .name = "dsi_phy_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &dsi_phy_sel.hw + &c3_dsi_phy_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dsi_phy = { +static struct clk_regmap c3_dsi_phy = { .data = &(struct clk_regmap_gate_data) { .offset = MIPIDSI_PHY_CLK_CTRL, .bit_idx = 8, @@ -1187,14 +1186,14 @@ static struct clk_regmap dsi_phy = { .name = "dsi_phy", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &dsi_phy_div.hw + &c3_dsi_phy_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data vout_mclk_parent_data[] = { +static const struct clk_parent_data c3_vout_mclk_parents[] = { { .fw_name = "fdiv2p5" }, { .fw_name = "fdiv3" }, { .fw_name = "fdiv4" }, @@ -1205,7 +1204,7 @@ static const struct clk_parent_data vout_mclk_parent_data[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap vout_mclk_sel = { +static struct clk_regmap c3_vout_mclk_sel = { .data = &(struct clk_regmap_mux_data) { .offset = VOUTENC_CLK_CTRL, .mask = 0x7, @@ -1214,12 +1213,12 @@ static struct clk_regmap vout_mclk_sel = { .hw.init = &(struct clk_init_data) { .name = "vout_mclk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = vout_mclk_parent_data, - .num_parents = ARRAY_SIZE(vout_mclk_parent_data), + .parent_data = c3_vout_mclk_parents, + .num_parents = ARRAY_SIZE(c3_vout_mclk_parents), }, }; -static struct clk_regmap vout_mclk_div = { +static struct clk_regmap c3_vout_mclk_div = { .data = &(struct clk_regmap_div_data) { .offset = VOUTENC_CLK_CTRL, .shift = 0, @@ -1229,14 +1228,14 @@ static struct clk_regmap vout_mclk_div = { .name = "vout_mclk_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &vout_mclk_sel.hw + &c3_vout_mclk_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap vout_mclk = { +static struct clk_regmap c3_vout_mclk = { .data = &(struct clk_regmap_gate_data) { .offset = VOUTENC_CLK_CTRL, .bit_idx = 8, @@ -1245,14 +1244,14 @@ static struct clk_regmap vout_mclk = { .name = "vout_mclk", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &vout_mclk_div.hw + &c3_vout_mclk_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data vout_enc_parent_data[] = { +static const struct clk_parent_data c3_vout_enc_parents[] = { { .fw_name = "gp1" }, { .fw_name = "fdiv3" }, { .fw_name = "fdiv4" }, @@ -1263,7 +1262,7 @@ static const struct clk_parent_data vout_enc_parent_data[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap vout_enc_sel = { +static struct clk_regmap c3_vout_enc_sel = { .data = &(struct clk_regmap_mux_data) { .offset = VOUTENC_CLK_CTRL, .mask = 0x7, @@ -1272,12 +1271,12 @@ static struct clk_regmap vout_enc_sel = { .hw.init = &(struct clk_init_data) { .name = "vout_enc_sel", .ops = &clk_regmap_mux_ops, - .parent_data = vout_enc_parent_data, - .num_parents = ARRAY_SIZE(vout_enc_parent_data), + .parent_data = c3_vout_enc_parents, + .num_parents = ARRAY_SIZE(c3_vout_enc_parents), }, }; -static struct clk_regmap vout_enc_div = { +static struct clk_regmap c3_vout_enc_div = { .data = &(struct clk_regmap_div_data) { .offset = VOUTENC_CLK_CTRL, .shift = 16, @@ -1287,14 +1286,14 @@ static struct clk_regmap vout_enc_div = { .name = "vout_enc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &vout_enc_sel.hw + &c3_vout_enc_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap vout_enc = { +static struct clk_regmap c3_vout_enc = { .data = &(struct clk_regmap_gate_data) { .offset = VOUTENC_CLK_CTRL, .bit_idx = 24, @@ -1303,14 +1302,14 @@ static struct clk_regmap vout_enc = { .name = "vout_enc", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &vout_enc_div.hw + &c3_vout_enc_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data hcodec_pre_parent_data[] = { +static const struct clk_parent_data c3_hcodec_pre_parents[] = { { .fw_name = "fdiv2p5" }, { .fw_name = "fdiv3" }, { .fw_name = "fdiv4" }, @@ -1321,7 +1320,7 @@ static const struct clk_parent_data hcodec_pre_parent_data[] = { { .fw_name = "oscin" } }; -static struct clk_regmap hcodec_0_sel = { +static struct clk_regmap c3_hcodec_0_sel = { .data = &(struct clk_regmap_mux_data) { .offset = VDEC_CLK_CTRL, .mask = 0x7, @@ -1330,12 +1329,12 @@ static struct clk_regmap hcodec_0_sel = { .hw.init = &(struct clk_init_data) { .name = "hcodec_0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = hcodec_pre_parent_data, - .num_parents = ARRAY_SIZE(hcodec_pre_parent_data), + .parent_data = c3_hcodec_pre_parents, + .num_parents = ARRAY_SIZE(c3_hcodec_pre_parents), }, }; -static struct clk_regmap hcodec_0_div = { +static struct clk_regmap c3_hcodec_0_div = { .data = &(struct clk_regmap_div_data) { .offset = VDEC_CLK_CTRL, .shift = 0, @@ -1345,14 +1344,14 @@ static struct clk_regmap hcodec_0_div = { .name = "hcodec_0_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &hcodec_0_sel.hw + &c3_hcodec_0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap hcodec_0 = { +static struct clk_regmap c3_hcodec_0 = { .data = &(struct clk_regmap_gate_data) { .offset = VDEC_CLK_CTRL, .bit_idx = 8, @@ -1361,14 +1360,14 @@ static struct clk_regmap hcodec_0 = { .name = "hcodec_0", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &hcodec_0_div.hw + &c3_hcodec_0_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap hcodec_1_sel = { +static struct clk_regmap c3_hcodec_1_sel = { .data = &(struct clk_regmap_mux_data) { .offset = VDEC3_CLK_CTRL, .mask = 0x7, @@ -1377,12 +1376,12 @@ static struct clk_regmap hcodec_1_sel = { .hw.init = &(struct clk_init_data) { .name = "hcodec_1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = hcodec_pre_parent_data, - .num_parents = ARRAY_SIZE(hcodec_pre_parent_data), + .parent_data = c3_hcodec_pre_parents, + .num_parents = ARRAY_SIZE(c3_hcodec_pre_parents), }, }; -static struct clk_regmap hcodec_1_div = { +static struct clk_regmap c3_hcodec_1_div = { .data = &(struct clk_regmap_div_data) { .offset = VDEC3_CLK_CTRL, .shift = 0, @@ -1392,14 +1391,14 @@ static struct clk_regmap hcodec_1_div = { .name = "hcodec_1_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &hcodec_1_sel.hw + &c3_hcodec_1_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap hcodec_1 = { +static struct clk_regmap c3_hcodec_1 = { .data = &(struct clk_regmap_gate_data) { .offset = VDEC3_CLK_CTRL, .bit_idx = 8, @@ -1408,19 +1407,19 @@ static struct clk_regmap hcodec_1 = { .name = "hcodec_1", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &hcodec_1_div.hw + &c3_hcodec_1_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data hcodec_parent_data[] = { - { .hw = &hcodec_0.hw }, - { .hw = &hcodec_1.hw } +static const struct clk_parent_data c3_hcodec_parents[] = { + { .hw = &c3_hcodec_0.hw }, + { .hw = &c3_hcodec_1.hw } }; -static struct clk_regmap hcodec = { +static struct clk_regmap c3_hcodec = { .data = &(struct clk_regmap_mux_data) { .offset = VDEC3_CLK_CTRL, .mask = 0x1, @@ -1429,13 +1428,13 @@ static struct clk_regmap hcodec = { .hw.init = &(struct clk_init_data) { .name = "hcodec", .ops = &clk_regmap_mux_ops, - .parent_data = hcodec_parent_data, - .num_parents = ARRAY_SIZE(hcodec_parent_data), + .parent_data = c3_hcodec_parents, + .num_parents = ARRAY_SIZE(c3_hcodec_parents), .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data vc9000e_parent_data[] = { +static const struct clk_parent_data c3_vc9000e_parents[] = { { .fw_name = "oscin" }, { .fw_name = "fdiv4" }, { .fw_name = "fdiv3" }, @@ -1446,7 +1445,7 @@ static const struct clk_parent_data vc9000e_parent_data[] = { { .fw_name = "gp0" } }; -static struct clk_regmap vc9000e_aclk_sel = { +static struct clk_regmap c3_vc9000e_aclk_sel = { .data = &(struct clk_regmap_mux_data) { .offset = VC9000E_CLK_CTRL, .mask = 0x7, @@ -1455,12 +1454,12 @@ static struct clk_regmap vc9000e_aclk_sel = { .hw.init = &(struct clk_init_data) { .name = "vc9000e_aclk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = vc9000e_parent_data, - .num_parents = ARRAY_SIZE(vc9000e_parent_data), + .parent_data = c3_vc9000e_parents, + .num_parents = ARRAY_SIZE(c3_vc9000e_parents), }, }; -static struct clk_regmap vc9000e_aclk_div = { +static struct clk_regmap c3_vc9000e_aclk_div = { .data = &(struct clk_regmap_div_data) { .offset = VC9000E_CLK_CTRL, .shift = 0, @@ -1470,14 +1469,14 @@ static struct clk_regmap vc9000e_aclk_div = { .name = "vc9000e_aclk_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &vc9000e_aclk_sel.hw + &c3_vc9000e_aclk_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap vc9000e_aclk = { +static struct clk_regmap c3_vc9000e_aclk = { .data = &(struct clk_regmap_gate_data) { .offset = VC9000E_CLK_CTRL, .bit_idx = 8, @@ -1486,14 +1485,14 @@ static struct clk_regmap vc9000e_aclk = { .name = "vc9000e_aclk", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &vc9000e_aclk_div.hw + &c3_vc9000e_aclk_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap vc9000e_core_sel = { +static struct clk_regmap c3_vc9000e_core_sel = { .data = &(struct clk_regmap_mux_data) { .offset = VC9000E_CLK_CTRL, .mask = 0x7, @@ -1502,12 +1501,12 @@ static struct clk_regmap vc9000e_core_sel = { .hw.init = &(struct clk_init_data) { .name = "vc9000e_core_sel", .ops = &clk_regmap_mux_ops, - .parent_data = vc9000e_parent_data, - .num_parents = ARRAY_SIZE(vc9000e_parent_data), + .parent_data = c3_vc9000e_parents, + .num_parents = ARRAY_SIZE(c3_vc9000e_parents), }, }; -static struct clk_regmap vc9000e_core_div = { +static struct clk_regmap c3_vc9000e_core_div = { .data = &(struct clk_regmap_div_data) { .offset = VC9000E_CLK_CTRL, .shift = 16, @@ -1517,14 +1516,14 @@ static struct clk_regmap vc9000e_core_div = { .name = "vc9000e_core_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &vc9000e_core_sel.hw + &c3_vc9000e_core_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap vc9000e_core = { +static struct clk_regmap c3_vc9000e_core = { .data = &(struct clk_regmap_gate_data) { .offset = VC9000E_CLK_CTRL, .bit_idx = 24, @@ -1533,14 +1532,14 @@ static struct clk_regmap vc9000e_core = { .name = "vc9000e_core", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &vc9000e_core_div.hw + &c3_vc9000e_core_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data csi_phy_parent_data[] = { +static const struct clk_parent_data c3_csi_phy_parents[] = { { .fw_name = "fdiv2p5" }, { .fw_name = "fdiv3" }, { .fw_name = "fdiv4" }, @@ -1551,7 +1550,7 @@ static const struct clk_parent_data csi_phy_parent_data[] = { { .fw_name = "oscin" } }; -static struct clk_regmap csi_phy0_sel = { +static struct clk_regmap c3_csi_phy0_sel = { .data = &(struct clk_regmap_mux_data) { .offset = ISP0_CLK_CTRL, .mask = 0x7, @@ -1560,12 +1559,12 @@ static struct clk_regmap csi_phy0_sel = { .hw.init = &(struct clk_init_data) { .name = "csi_phy0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = csi_phy_parent_data, - .num_parents = ARRAY_SIZE(csi_phy_parent_data), + .parent_data = c3_csi_phy_parents, + .num_parents = ARRAY_SIZE(c3_csi_phy_parents), }, }; -static struct clk_regmap csi_phy0_div = { +static struct clk_regmap c3_csi_phy0_div = { .data = &(struct clk_regmap_div_data) { .offset = ISP0_CLK_CTRL, .shift = 16, @@ -1575,14 +1574,14 @@ static struct clk_regmap csi_phy0_div = { .name = "csi_phy0_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &csi_phy0_sel.hw + &c3_csi_phy0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap csi_phy0 = { +static struct clk_regmap c3_csi_phy0 = { .data = &(struct clk_regmap_gate_data) { .offset = ISP0_CLK_CTRL, .bit_idx = 24, @@ -1591,14 +1590,14 @@ static struct clk_regmap csi_phy0 = { .name = "csi_phy0", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &csi_phy0_div.hw + &c3_csi_phy0_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data dewarpa_parent_data[] = { +static const struct clk_parent_data c3_dewarpa_parents[] = { { .fw_name = "fdiv2p5" }, { .fw_name = "fdiv3" }, { .fw_name = "fdiv4" }, @@ -1609,7 +1608,7 @@ static const struct clk_parent_data dewarpa_parent_data[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap dewarpa_sel = { +static struct clk_regmap c3_dewarpa_sel = { .data = &(struct clk_regmap_mux_data) { .offset = DEWARPA_CLK_CTRL, .mask = 0x7, @@ -1618,12 +1617,12 @@ static struct clk_regmap dewarpa_sel = { .hw.init = &(struct clk_init_data) { .name = "dewarpa_sel", .ops = &clk_regmap_mux_ops, - .parent_data = dewarpa_parent_data, - .num_parents = ARRAY_SIZE(dewarpa_parent_data), + .parent_data = c3_dewarpa_parents, + .num_parents = ARRAY_SIZE(c3_dewarpa_parents), }, }; -static struct clk_regmap dewarpa_div = { +static struct clk_regmap c3_dewarpa_div = { .data = &(struct clk_regmap_div_data) { .offset = DEWARPA_CLK_CTRL, .shift = 0, @@ -1633,14 +1632,14 @@ static struct clk_regmap dewarpa_div = { .name = "dewarpa_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &dewarpa_sel.hw + &c3_dewarpa_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap dewarpa = { +static struct clk_regmap c3_dewarpa = { .data = &(struct clk_regmap_gate_data) { .offset = DEWARPA_CLK_CTRL, .bit_idx = 8, @@ -1649,14 +1648,14 @@ static struct clk_regmap dewarpa = { .name = "dewarpa", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &dewarpa_div.hw + &c3_dewarpa_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data isp_parent_data[] = { +static const struct clk_parent_data c3_isp_parents[] = { { .fw_name = "fdiv2p5" }, { .fw_name = "fdiv3" }, { .fw_name = "fdiv4" }, @@ -1667,7 +1666,7 @@ static const struct clk_parent_data isp_parent_data[] = { { .fw_name = "oscin" } }; -static struct clk_regmap isp0_sel = { +static struct clk_regmap c3_isp0_sel = { .data = &(struct clk_regmap_mux_data) { .offset = ISP0_CLK_CTRL, .mask = 0x7, @@ -1676,12 +1675,12 @@ static struct clk_regmap isp0_sel = { .hw.init = &(struct clk_init_data) { .name = "isp0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = isp_parent_data, - .num_parents = ARRAY_SIZE(isp_parent_data), + .parent_data = c3_isp_parents, + .num_parents = ARRAY_SIZE(c3_isp_parents), }, }; -static struct clk_regmap isp0_div = { +static struct clk_regmap c3_isp0_div = { .data = &(struct clk_regmap_div_data) { .offset = ISP0_CLK_CTRL, .shift = 0, @@ -1691,14 +1690,14 @@ static struct clk_regmap isp0_div = { .name = "isp0_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &isp0_sel.hw + &c3_isp0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap isp0 = { +static struct clk_regmap c3_isp0 = { .data = &(struct clk_regmap_gate_data) { .offset = ISP0_CLK_CTRL, .bit_idx = 8, @@ -1707,14 +1706,14 @@ static struct clk_regmap isp0 = { .name = "isp0", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &isp0_div.hw + &c3_isp0_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data nna_core_parent_data[] = { +static const struct clk_parent_data c3_nna_core_parents[] = { { .fw_name = "oscin" }, { .fw_name = "fdiv2p5" }, { .fw_name = "fdiv4" }, @@ -1725,7 +1724,7 @@ static const struct clk_parent_data nna_core_parent_data[] = { { .fw_name = "hifi" } }; -static struct clk_regmap nna_core_sel = { +static struct clk_regmap c3_nna_core_sel = { .data = &(struct clk_regmap_mux_data) { .offset = NNA_CLK_CTRL, .mask = 0x7, @@ -1734,12 +1733,12 @@ static struct clk_regmap nna_core_sel = { .hw.init = &(struct clk_init_data) { .name = "nna_core_sel", .ops = &clk_regmap_mux_ops, - .parent_data = nna_core_parent_data, - .num_parents = ARRAY_SIZE(nna_core_parent_data), + .parent_data = c3_nna_core_parents, + .num_parents = ARRAY_SIZE(c3_nna_core_parents), }, }; -static struct clk_regmap nna_core_div = { +static struct clk_regmap c3_nna_core_div = { .data = &(struct clk_regmap_div_data) { .offset = NNA_CLK_CTRL, .shift = 0, @@ -1749,14 +1748,14 @@ static struct clk_regmap nna_core_div = { .name = "nna_core_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &nna_core_sel.hw + &c3_nna_core_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap nna_core = { +static struct clk_regmap c3_nna_core = { .data = &(struct clk_regmap_gate_data) { .offset = NNA_CLK_CTRL, .bit_idx = 8, @@ -1765,14 +1764,14 @@ static struct clk_regmap nna_core = { .name = "nna_core", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &nna_core_div.hw + &c3_nna_core_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data ge2d_parent_data[] = { +static const struct clk_parent_data c3_ge2d_parents[] = { { .fw_name = "oscin" }, { .fw_name = "fdiv2p5" }, { .fw_name = "fdiv3" }, @@ -1780,10 +1779,10 @@ static const struct clk_parent_data ge2d_parent_data[] = { { .fw_name = "hifi" }, { .fw_name = "fdiv5" }, { .fw_name = "gp0" }, - { .hw = &rtc_clk.hw } + { .hw = &c3_rtc_clk.hw } }; -static struct clk_regmap ge2d_sel = { +static struct clk_regmap c3_ge2d_sel = { .data = &(struct clk_regmap_mux_data) { .offset = GE2D_CLK_CTRL, .mask = 0x7, @@ -1792,12 +1791,12 @@ static struct clk_regmap ge2d_sel = { .hw.init = &(struct clk_init_data) { .name = "ge2d_sel", .ops = &clk_regmap_mux_ops, - .parent_data = ge2d_parent_data, - .num_parents = ARRAY_SIZE(ge2d_parent_data), + .parent_data = c3_ge2d_parents, + .num_parents = ARRAY_SIZE(c3_ge2d_parents), }, }; -static struct clk_regmap ge2d_div = { +static struct clk_regmap c3_ge2d_div = { .data = &(struct clk_regmap_div_data) { .offset = GE2D_CLK_CTRL, .shift = 0, @@ -1807,14 +1806,14 @@ static struct clk_regmap ge2d_div = { .name = "ge2d_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &ge2d_sel.hw + &c3_ge2d_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap ge2d = { +static struct clk_regmap c3_ge2d = { .data = &(struct clk_regmap_gate_data) { .offset = GE2D_CLK_CTRL, .bit_idx = 8, @@ -1823,14 +1822,14 @@ static struct clk_regmap ge2d = { .name = "ge2d", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &ge2d_div.hw + &c3_ge2d_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data vapb_parent_data[] = { +static const struct clk_parent_data c3_vapb_parents[] = { { .fw_name = "fdiv2p5" }, { .fw_name = "fdiv3" }, { .fw_name = "fdiv4" }, @@ -1841,7 +1840,7 @@ static const struct clk_parent_data vapb_parent_data[] = { { .fw_name = "oscin" }, }; -static struct clk_regmap vapb_sel = { +static struct clk_regmap c3_vapb_sel = { .data = &(struct clk_regmap_mux_data) { .offset = VAPB_CLK_CTRL, .mask = 0x7, @@ -1850,12 +1849,12 @@ static struct clk_regmap vapb_sel = { .hw.init = &(struct clk_init_data) { .name = "vapb_sel", .ops = &clk_regmap_mux_ops, - .parent_data = vapb_parent_data, - .num_parents = ARRAY_SIZE(vapb_parent_data), + .parent_data = c3_vapb_parents, + .num_parents = ARRAY_SIZE(c3_vapb_parents), }, }; -static struct clk_regmap vapb_div = { +static struct clk_regmap c3_vapb_div = { .data = &(struct clk_regmap_div_data) { .offset = VAPB_CLK_CTRL, .shift = 0, @@ -1865,14 +1864,14 @@ static struct clk_regmap vapb_div = { .name = "vapb_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &vapb_sel.hw + &c3_vapb_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap vapb = { +static struct clk_regmap c3_vapb = { .data = &(struct clk_regmap_gate_data) { .offset = VAPB_CLK_CTRL, .bit_idx = 8, @@ -1881,230 +1880,230 @@ static struct clk_regmap vapb = { .name = "vapb", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &vapb_div.hw + &c3_vapb_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_hw *c3_periphs_hw_clks[] = { - [CLKID_RTC_XTAL_CLKIN] = &rtc_xtal_clkin.hw, - [CLKID_RTC_32K_DIV] = &rtc_32k_div.hw, - [CLKID_RTC_32K_MUX] = &rtc_32k_mux.hw, - [CLKID_RTC_32K] = &rtc_32k.hw, - [CLKID_RTC_CLK] = &rtc_clk.hw, - [CLKID_SYS_RESET_CTRL] = &sys_reset_ctrl.hw, - [CLKID_SYS_PWR_CTRL] = &sys_pwr_ctrl.hw, - [CLKID_SYS_PAD_CTRL] = &sys_pad_ctrl.hw, - [CLKID_SYS_CTRL] = &sys_ctrl.hw, - [CLKID_SYS_TS_PLL] = &sys_ts_pll.hw, - [CLKID_SYS_DEV_ARB] = &sys_dev_arb.hw, - [CLKID_SYS_MMC_PCLK] = &sys_mmc_pclk.hw, - [CLKID_SYS_CPU_CTRL] = &sys_cpu_ctrl.hw, - [CLKID_SYS_JTAG_CTRL] = &sys_jtag_ctrl.hw, - [CLKID_SYS_IR_CTRL] = &sys_ir_ctrl.hw, - [CLKID_SYS_IRQ_CTRL] = &sys_irq_ctrl.hw, - [CLKID_SYS_MSR_CLK] = &sys_msr_clk.hw, - [CLKID_SYS_ROM] = &sys_rom.hw, - [CLKID_SYS_UART_F] = &sys_uart_f.hw, - [CLKID_SYS_CPU_ARB] = &sys_cpu_apb.hw, - [CLKID_SYS_RSA] = &sys_rsa.hw, - [CLKID_SYS_SAR_ADC] = &sys_sar_adc.hw, - [CLKID_SYS_STARTUP] = &sys_startup.hw, - [CLKID_SYS_SECURE] = &sys_secure.hw, - [CLKID_SYS_SPIFC] = &sys_spifc.hw, - [CLKID_SYS_NNA] = &sys_nna.hw, - [CLKID_SYS_ETH_MAC] = &sys_eth_mac.hw, - [CLKID_SYS_GIC] = &sys_gic.hw, - [CLKID_SYS_RAMA] = &sys_rama.hw, - [CLKID_SYS_BIG_NIC] = &sys_big_nic.hw, - [CLKID_SYS_RAMB] = &sys_ramb.hw, - [CLKID_SYS_AUDIO_PCLK] = &sys_audio_pclk.hw, - [CLKID_SYS_PWM_KL] = &sys_pwm_kl.hw, - [CLKID_SYS_PWM_IJ] = &sys_pwm_ij.hw, - [CLKID_SYS_USB] = &sys_usb.hw, - [CLKID_SYS_SD_EMMC_A] = &sys_sd_emmc_a.hw, - [CLKID_SYS_SD_EMMC_C] = &sys_sd_emmc_c.hw, - [CLKID_SYS_PWM_AB] = &sys_pwm_ab.hw, - [CLKID_SYS_PWM_CD] = &sys_pwm_cd.hw, - [CLKID_SYS_PWM_EF] = &sys_pwm_ef.hw, - [CLKID_SYS_PWM_GH] = &sys_pwm_gh.hw, - [CLKID_SYS_SPICC_1] = &sys_spicc_1.hw, - [CLKID_SYS_SPICC_0] = &sys_spicc_0.hw, - [CLKID_SYS_UART_A] = &sys_uart_a.hw, - [CLKID_SYS_UART_B] = &sys_uart_b.hw, - [CLKID_SYS_UART_C] = &sys_uart_c.hw, - [CLKID_SYS_UART_D] = &sys_uart_d.hw, - [CLKID_SYS_UART_E] = &sys_uart_e.hw, - [CLKID_SYS_I2C_M_A] = &sys_i2c_m_a.hw, - [CLKID_SYS_I2C_M_B] = &sys_i2c_m_b.hw, - [CLKID_SYS_I2C_M_C] = &sys_i2c_m_c.hw, - [CLKID_SYS_I2C_M_D] = &sys_i2c_m_d.hw, - [CLKID_SYS_I2S_S_A] = &sys_i2c_s_a.hw, - [CLKID_SYS_RTC] = &sys_rtc.hw, - [CLKID_SYS_GE2D] = &sys_ge2d.hw, - [CLKID_SYS_ISP] = &sys_isp.hw, - [CLKID_SYS_GPV_ISP_NIC] = &sys_gpv_isp_nic.hw, - [CLKID_SYS_GPV_CVE_NIC] = &sys_gpv_cve_nic.hw, - [CLKID_SYS_MIPI_DSI_HOST] = &sys_mipi_dsi_host.hw, - [CLKID_SYS_MIPI_DSI_PHY] = &sys_mipi_dsi_phy.hw, - [CLKID_SYS_ETH_PHY] = &sys_eth_phy.hw, - [CLKID_SYS_ACODEC] = &sys_acodec.hw, - [CLKID_SYS_DWAP] = &sys_dwap.hw, - [CLKID_SYS_DOS] = &sys_dos.hw, - [CLKID_SYS_CVE] = &sys_cve.hw, - [CLKID_SYS_VOUT] = &sys_vout.hw, - [CLKID_SYS_VC9000E] = &sys_vc9000e.hw, - [CLKID_SYS_PWM_MN] = &sys_pwm_mn.hw, - [CLKID_SYS_SD_EMMC_B] = &sys_sd_emmc_b.hw, - [CLKID_AXI_SYS_NIC] = &axi_sys_nic.hw, - [CLKID_AXI_ISP_NIC] = &axi_isp_nic.hw, - [CLKID_AXI_CVE_NIC] = &axi_cve_nic.hw, - [CLKID_AXI_RAMB] = &axi_ramb.hw, - [CLKID_AXI_RAMA] = &axi_rama.hw, - [CLKID_AXI_CPU_DMC] = &axi_cpu_dmc.hw, - [CLKID_AXI_NIC] = &axi_nic.hw, - [CLKID_AXI_DMA] = &axi_dma.hw, - [CLKID_AXI_MUX_NIC] = &axi_mux_nic.hw, - [CLKID_AXI_CVE] = &axi_cve.hw, - [CLKID_AXI_DEV1_DMC] = &axi_dev1_dmc.hw, - [CLKID_AXI_DEV0_DMC] = &axi_dev0_dmc.hw, - [CLKID_AXI_DSP_DMC] = &axi_dsp_dmc.hw, - [CLKID_12_24M_IN] = &clk_12_24m_in.hw, - [CLKID_12M_24M] = &clk_12_24m.hw, - [CLKID_FCLK_25M_DIV] = &fclk_25m_div.hw, - [CLKID_FCLK_25M] = &fclk_25m.hw, - [CLKID_GEN_SEL] = &gen_sel.hw, - [CLKID_GEN_DIV] = &gen_div.hw, - [CLKID_GEN] = &gen.hw, - [CLKID_SARADC_SEL] = &saradc_sel.hw, - [CLKID_SARADC_DIV] = &saradc_div.hw, - [CLKID_SARADC] = &saradc.hw, - [CLKID_PWM_A_SEL] = &pwm_a_sel.hw, - [CLKID_PWM_A_DIV] = &pwm_a_div.hw, - [CLKID_PWM_A] = &pwm_a.hw, - [CLKID_PWM_B_SEL] = &pwm_b_sel.hw, - [CLKID_PWM_B_DIV] = &pwm_b_div.hw, - [CLKID_PWM_B] = &pwm_b.hw, - [CLKID_PWM_C_SEL] = &pwm_c_sel.hw, - [CLKID_PWM_C_DIV] = &pwm_c_div.hw, - [CLKID_PWM_C] = &pwm_c.hw, - [CLKID_PWM_D_SEL] = &pwm_d_sel.hw, - [CLKID_PWM_D_DIV] = &pwm_d_div.hw, - [CLKID_PWM_D] = &pwm_d.hw, - [CLKID_PWM_E_SEL] = &pwm_e_sel.hw, - [CLKID_PWM_E_DIV] = &pwm_e_div.hw, - [CLKID_PWM_E] = &pwm_e.hw, - [CLKID_PWM_F_SEL] = &pwm_f_sel.hw, - [CLKID_PWM_F_DIV] = &pwm_f_div.hw, - [CLKID_PWM_F] = &pwm_f.hw, - [CLKID_PWM_G_SEL] = &pwm_g_sel.hw, - [CLKID_PWM_G_DIV] = &pwm_g_div.hw, - [CLKID_PWM_G] = &pwm_g.hw, - [CLKID_PWM_H_SEL] = &pwm_h_sel.hw, - [CLKID_PWM_H_DIV] = &pwm_h_div.hw, - [CLKID_PWM_H] = &pwm_h.hw, - [CLKID_PWM_I_SEL] = &pwm_i_sel.hw, - [CLKID_PWM_I_DIV] = &pwm_i_div.hw, - [CLKID_PWM_I] = &pwm_i.hw, - [CLKID_PWM_J_SEL] = &pwm_j_sel.hw, - [CLKID_PWM_J_DIV] = &pwm_j_div.hw, - [CLKID_PWM_J] = &pwm_j.hw, - [CLKID_PWM_K_SEL] = &pwm_k_sel.hw, - [CLKID_PWM_K_DIV] = &pwm_k_div.hw, - [CLKID_PWM_K] = &pwm_k.hw, - [CLKID_PWM_L_SEL] = &pwm_l_sel.hw, - [CLKID_PWM_L_DIV] = &pwm_l_div.hw, - [CLKID_PWM_L] = &pwm_l.hw, - [CLKID_PWM_M_SEL] = &pwm_m_sel.hw, - [CLKID_PWM_M_DIV] = &pwm_m_div.hw, - [CLKID_PWM_M] = &pwm_m.hw, - [CLKID_PWM_N_SEL] = &pwm_n_sel.hw, - [CLKID_PWM_N_DIV] = &pwm_n_div.hw, - [CLKID_PWM_N] = &pwm_n.hw, - [CLKID_SPICC_A_SEL] = &spicc_a_sel.hw, - [CLKID_SPICC_A_DIV] = &spicc_a_div.hw, - [CLKID_SPICC_A] = &spicc_a.hw, - [CLKID_SPICC_B_SEL] = &spicc_b_sel.hw, - [CLKID_SPICC_B_DIV] = &spicc_b_div.hw, - [CLKID_SPICC_B] = &spicc_b.hw, - [CLKID_SPIFC_SEL] = &spifc_sel.hw, - [CLKID_SPIFC_DIV] = &spifc_div.hw, - [CLKID_SPIFC] = &spifc.hw, - [CLKID_SD_EMMC_A_SEL] = &sd_emmc_a_sel.hw, - [CLKID_SD_EMMC_A_DIV] = &sd_emmc_a_div.hw, - [CLKID_SD_EMMC_A] = &sd_emmc_a.hw, - [CLKID_SD_EMMC_B_SEL] = &sd_emmc_b_sel.hw, - [CLKID_SD_EMMC_B_DIV] = &sd_emmc_b_div.hw, - [CLKID_SD_EMMC_B] = &sd_emmc_b.hw, - [CLKID_SD_EMMC_C_SEL] = &sd_emmc_c_sel.hw, - [CLKID_SD_EMMC_C_DIV] = &sd_emmc_c_div.hw, - [CLKID_SD_EMMC_C] = &sd_emmc_c.hw, - [CLKID_TS_DIV] = &ts_div.hw, - [CLKID_TS] = &ts.hw, - [CLKID_ETH_125M_DIV] = ð_125m_div.hw, - [CLKID_ETH_125M] = ð_125m.hw, - [CLKID_ETH_RMII_DIV] = ð_rmii_div.hw, - [CLKID_ETH_RMII] = ð_rmii.hw, - [CLKID_MIPI_DSI_MEAS_SEL] = &mipi_dsi_meas_sel.hw, - [CLKID_MIPI_DSI_MEAS_DIV] = &mipi_dsi_meas_div.hw, - [CLKID_MIPI_DSI_MEAS] = &mipi_dsi_meas.hw, - [CLKID_DSI_PHY_SEL] = &dsi_phy_sel.hw, - [CLKID_DSI_PHY_DIV] = &dsi_phy_div.hw, - [CLKID_DSI_PHY] = &dsi_phy.hw, - [CLKID_VOUT_MCLK_SEL] = &vout_mclk_sel.hw, - [CLKID_VOUT_MCLK_DIV] = &vout_mclk_div.hw, - [CLKID_VOUT_MCLK] = &vout_mclk.hw, - [CLKID_VOUT_ENC_SEL] = &vout_enc_sel.hw, - [CLKID_VOUT_ENC_DIV] = &vout_enc_div.hw, - [CLKID_VOUT_ENC] = &vout_enc.hw, - [CLKID_HCODEC_0_SEL] = &hcodec_0_sel.hw, - [CLKID_HCODEC_0_DIV] = &hcodec_0_div.hw, - [CLKID_HCODEC_0] = &hcodec_0.hw, - [CLKID_HCODEC_1_SEL] = &hcodec_1_sel.hw, - [CLKID_HCODEC_1_DIV] = &hcodec_1_div.hw, - [CLKID_HCODEC_1] = &hcodec_1.hw, - [CLKID_HCODEC] = &hcodec.hw, - [CLKID_VC9000E_ACLK_SEL] = &vc9000e_aclk_sel.hw, - [CLKID_VC9000E_ACLK_DIV] = &vc9000e_aclk_div.hw, - [CLKID_VC9000E_ACLK] = &vc9000e_aclk.hw, - [CLKID_VC9000E_CORE_SEL] = &vc9000e_core_sel.hw, - [CLKID_VC9000E_CORE_DIV] = &vc9000e_core_div.hw, - [CLKID_VC9000E_CORE] = &vc9000e_core.hw, - [CLKID_CSI_PHY0_SEL] = &csi_phy0_sel.hw, - [CLKID_CSI_PHY0_DIV] = &csi_phy0_div.hw, - [CLKID_CSI_PHY0] = &csi_phy0.hw, - [CLKID_DEWARPA_SEL] = &dewarpa_sel.hw, - [CLKID_DEWARPA_DIV] = &dewarpa_div.hw, - [CLKID_DEWARPA] = &dewarpa.hw, - [CLKID_ISP0_SEL] = &isp0_sel.hw, - [CLKID_ISP0_DIV] = &isp0_div.hw, - [CLKID_ISP0] = &isp0.hw, - [CLKID_NNA_CORE_SEL] = &nna_core_sel.hw, - [CLKID_NNA_CORE_DIV] = &nna_core_div.hw, - [CLKID_NNA_CORE] = &nna_core.hw, - [CLKID_GE2D_SEL] = &ge2d_sel.hw, - [CLKID_GE2D_DIV] = &ge2d_div.hw, - [CLKID_GE2D] = &ge2d.hw, - [CLKID_VAPB_SEL] = &vapb_sel.hw, - [CLKID_VAPB_DIV] = &vapb_div.hw, - [CLKID_VAPB] = &vapb.hw, +static struct clk_hw *c3_peripherals_hw_clks[] = { + [CLKID_RTC_XTAL_CLKIN] = &c3_rtc_xtal_clkin.hw, + [CLKID_RTC_32K_DIV] = &c3_rtc_32k_div.hw, + [CLKID_RTC_32K_MUX] = &c3_rtc_32k_sel.hw, + [CLKID_RTC_32K] = &c3_rtc_32k.hw, + [CLKID_RTC_CLK] = &c3_rtc_clk.hw, + [CLKID_SYS_RESET_CTRL] = &c3_sys_reset_ctrl.hw, + [CLKID_SYS_PWR_CTRL] = &c3_sys_pwr_ctrl.hw, + [CLKID_SYS_PAD_CTRL] = &c3_sys_pad_ctrl.hw, + [CLKID_SYS_CTRL] = &c3_sys_ctrl.hw, + [CLKID_SYS_TS_PLL] = &c3_sys_ts_pll.hw, + [CLKID_SYS_DEV_ARB] = &c3_sys_dev_arb.hw, + [CLKID_SYS_MMC_PCLK] = &c3_sys_mmc_pclk.hw, + [CLKID_SYS_CPU_CTRL] = &c3_sys_cpu_ctrl.hw, + [CLKID_SYS_JTAG_CTRL] = &c3_sys_jtag_ctrl.hw, + [CLKID_SYS_IR_CTRL] = &c3_sys_ir_ctrl.hw, + [CLKID_SYS_IRQ_CTRL] = &c3_sys_irq_ctrl.hw, + [CLKID_SYS_MSR_CLK] = &c3_sys_msr_clk.hw, + [CLKID_SYS_ROM] = &c3_sys_rom.hw, + [CLKID_SYS_UART_F] = &c3_sys_uart_f.hw, + [CLKID_SYS_CPU_ARB] = &c3_sys_cpu_apb.hw, + [CLKID_SYS_RSA] = &c3_sys_rsa.hw, + [CLKID_SYS_SAR_ADC] = &c3_sys_sar_adc.hw, + [CLKID_SYS_STARTUP] = &c3_sys_startup.hw, + [CLKID_SYS_SECURE] = &c3_sys_secure.hw, + [CLKID_SYS_SPIFC] = &c3_sys_spifc.hw, + [CLKID_SYS_NNA] = &c3_sys_nna.hw, + [CLKID_SYS_ETH_MAC] = &c3_sys_eth_mac.hw, + [CLKID_SYS_GIC] = &c3_sys_gic.hw, + [CLKID_SYS_RAMA] = &c3_sys_rama.hw, + [CLKID_SYS_BIG_NIC] = &c3_sys_big_nic.hw, + [CLKID_SYS_RAMB] = &c3_sys_ramb.hw, + [CLKID_SYS_AUDIO_PCLK] = &c3_sys_audio_pclk.hw, + [CLKID_SYS_PWM_KL] = &c3_sys_pwm_kl.hw, + [CLKID_SYS_PWM_IJ] = &c3_sys_pwm_ij.hw, + [CLKID_SYS_USB] = &c3_sys_usb.hw, + [CLKID_SYS_SD_EMMC_A] = &c3_sys_sd_emmc_a.hw, + [CLKID_SYS_SD_EMMC_C] = &c3_sys_sd_emmc_c.hw, + [CLKID_SYS_PWM_AB] = &c3_sys_pwm_ab.hw, + [CLKID_SYS_PWM_CD] = &c3_sys_pwm_cd.hw, + [CLKID_SYS_PWM_EF] = &c3_sys_pwm_ef.hw, + [CLKID_SYS_PWM_GH] = &c3_sys_pwm_gh.hw, + [CLKID_SYS_SPICC_1] = &c3_sys_spicc_1.hw, + [CLKID_SYS_SPICC_0] = &c3_sys_spicc_0.hw, + [CLKID_SYS_UART_A] = &c3_sys_uart_a.hw, + [CLKID_SYS_UART_B] = &c3_sys_uart_b.hw, + [CLKID_SYS_UART_C] = &c3_sys_uart_c.hw, + [CLKID_SYS_UART_D] = &c3_sys_uart_d.hw, + [CLKID_SYS_UART_E] = &c3_sys_uart_e.hw, + [CLKID_SYS_I2C_M_A] = &c3_sys_i2c_m_a.hw, + [CLKID_SYS_I2C_M_B] = &c3_sys_i2c_m_b.hw, + [CLKID_SYS_I2C_M_C] = &c3_sys_i2c_m_c.hw, + [CLKID_SYS_I2C_M_D] = &c3_sys_i2c_m_d.hw, + [CLKID_SYS_I2S_S_A] = &c3_sys_i2c_s_a.hw, + [CLKID_SYS_RTC] = &c3_sys_rtc.hw, + [CLKID_SYS_GE2D] = &c3_sys_ge2d.hw, + [CLKID_SYS_ISP] = &c3_sys_isp.hw, + [CLKID_SYS_GPV_ISP_NIC] = &c3_sys_gpv_isp_nic.hw, + [CLKID_SYS_GPV_CVE_NIC] = &c3_sys_gpv_cve_nic.hw, + [CLKID_SYS_MIPI_DSI_HOST] = &c3_sys_mipi_dsi_host.hw, + [CLKID_SYS_MIPI_DSI_PHY] = &c3_sys_mipi_dsi_phy.hw, + [CLKID_SYS_ETH_PHY] = &c3_sys_eth_phy.hw, + [CLKID_SYS_ACODEC] = &c3_sys_acodec.hw, + [CLKID_SYS_DWAP] = &c3_sys_dwap.hw, + [CLKID_SYS_DOS] = &c3_sys_dos.hw, + [CLKID_SYS_CVE] = &c3_sys_cve.hw, + [CLKID_SYS_VOUT] = &c3_sys_vout.hw, + [CLKID_SYS_VC9000E] = &c3_sys_vc9000e.hw, + [CLKID_SYS_PWM_MN] = &c3_sys_pwm_mn.hw, + [CLKID_SYS_SD_EMMC_B] = &c3_sys_sd_emmc_b.hw, + [CLKID_AXI_SYS_NIC] = &c3_axi_sys_nic.hw, + [CLKID_AXI_ISP_NIC] = &c3_axi_isp_nic.hw, + [CLKID_AXI_CVE_NIC] = &c3_axi_cve_nic.hw, + [CLKID_AXI_RAMB] = &c3_axi_ramb.hw, + [CLKID_AXI_RAMA] = &c3_axi_rama.hw, + [CLKID_AXI_CPU_DMC] = &c3_axi_cpu_dmc.hw, + [CLKID_AXI_NIC] = &c3_axi_nic.hw, + [CLKID_AXI_DMA] = &c3_axi_dma.hw, + [CLKID_AXI_MUX_NIC] = &c3_axi_mux_nic.hw, + [CLKID_AXI_CVE] = &c3_axi_cve.hw, + [CLKID_AXI_DEV1_DMC] = &c3_axi_dev1_dmc.hw, + [CLKID_AXI_DEV0_DMC] = &c3_axi_dev0_dmc.hw, + [CLKID_AXI_DSP_DMC] = &c3_axi_dsp_dmc.hw, + [CLKID_12_24M_IN] = &c3_clk_12_24m_in.hw, + [CLKID_12M_24M] = &c3_clk_12_24m.hw, + [CLKID_FCLK_25M_DIV] = &c3_fclk_25m_div.hw, + [CLKID_FCLK_25M] = &c3_fclk_25m.hw, + [CLKID_GEN_SEL] = &c3_gen_sel.hw, + [CLKID_GEN_DIV] = &c3_gen_div.hw, + [CLKID_GEN] = &c3_gen.hw, + [CLKID_SARADC_SEL] = &c3_saradc_sel.hw, + [CLKID_SARADC_DIV] = &c3_saradc_div.hw, + [CLKID_SARADC] = &c3_saradc.hw, + [CLKID_PWM_A_SEL] = &c3_pwm_a_sel.hw, + [CLKID_PWM_A_DIV] = &c3_pwm_a_div.hw, + [CLKID_PWM_A] = &c3_pwm_a.hw, + [CLKID_PWM_B_SEL] = &c3_pwm_b_sel.hw, + [CLKID_PWM_B_DIV] = &c3_pwm_b_div.hw, + [CLKID_PWM_B] = &c3_pwm_b.hw, + [CLKID_PWM_C_SEL] = &c3_pwm_c_sel.hw, + [CLKID_PWM_C_DIV] = &c3_pwm_c_div.hw, + [CLKID_PWM_C] = &c3_pwm_c.hw, + [CLKID_PWM_D_SEL] = &c3_pwm_d_sel.hw, + [CLKID_PWM_D_DIV] = &c3_pwm_d_div.hw, + [CLKID_PWM_D] = &c3_pwm_d.hw, + [CLKID_PWM_E_SEL] = &c3_pwm_e_sel.hw, + [CLKID_PWM_E_DIV] = &c3_pwm_e_div.hw, + [CLKID_PWM_E] = &c3_pwm_e.hw, + [CLKID_PWM_F_SEL] = &c3_pwm_f_sel.hw, + [CLKID_PWM_F_DIV] = &c3_pwm_f_div.hw, + [CLKID_PWM_F] = &c3_pwm_f.hw, + [CLKID_PWM_G_SEL] = &c3_pwm_g_sel.hw, + [CLKID_PWM_G_DIV] = &c3_pwm_g_div.hw, + [CLKID_PWM_G] = &c3_pwm_g.hw, + [CLKID_PWM_H_SEL] = &c3_pwm_h_sel.hw, + [CLKID_PWM_H_DIV] = &c3_pwm_h_div.hw, + [CLKID_PWM_H] = &c3_pwm_h.hw, + [CLKID_PWM_I_SEL] = &c3_pwm_i_sel.hw, + [CLKID_PWM_I_DIV] = &c3_pwm_i_div.hw, + [CLKID_PWM_I] = &c3_pwm_i.hw, + [CLKID_PWM_J_SEL] = &c3_pwm_j_sel.hw, + [CLKID_PWM_J_DIV] = &c3_pwm_j_div.hw, + [CLKID_PWM_J] = &c3_pwm_j.hw, + [CLKID_PWM_K_SEL] = &c3_pwm_k_sel.hw, + [CLKID_PWM_K_DIV] = &c3_pwm_k_div.hw, + [CLKID_PWM_K] = &c3_pwm_k.hw, + [CLKID_PWM_L_SEL] = &c3_pwm_l_sel.hw, + [CLKID_PWM_L_DIV] = &c3_pwm_l_div.hw, + [CLKID_PWM_L] = &c3_pwm_l.hw, + [CLKID_PWM_M_SEL] = &c3_pwm_m_sel.hw, + [CLKID_PWM_M_DIV] = &c3_pwm_m_div.hw, + [CLKID_PWM_M] = &c3_pwm_m.hw, + [CLKID_PWM_N_SEL] = &c3_pwm_n_sel.hw, + [CLKID_PWM_N_DIV] = &c3_pwm_n_div.hw, + [CLKID_PWM_N] = &c3_pwm_n.hw, + [CLKID_SPICC_A_SEL] = &c3_spicc_a_sel.hw, + [CLKID_SPICC_A_DIV] = &c3_spicc_a_div.hw, + [CLKID_SPICC_A] = &c3_spicc_a.hw, + [CLKID_SPICC_B_SEL] = &c3_spicc_b_sel.hw, + [CLKID_SPICC_B_DIV] = &c3_spicc_b_div.hw, + [CLKID_SPICC_B] = &c3_spicc_b.hw, + [CLKID_SPIFC_SEL] = &c3_spifc_sel.hw, + [CLKID_SPIFC_DIV] = &c3_spifc_div.hw, + [CLKID_SPIFC] = &c3_spifc.hw, + [CLKID_SD_EMMC_A_SEL] = &c3_sd_emmc_a_sel.hw, + [CLKID_SD_EMMC_A_DIV] = &c3_sd_emmc_a_div.hw, + [CLKID_SD_EMMC_A] = &c3_sd_emmc_a.hw, + [CLKID_SD_EMMC_B_SEL] = &c3_sd_emmc_b_sel.hw, + [CLKID_SD_EMMC_B_DIV] = &c3_sd_emmc_b_div.hw, + [CLKID_SD_EMMC_B] = &c3_sd_emmc_b.hw, + [CLKID_SD_EMMC_C_SEL] = &c3_sd_emmc_c_sel.hw, + [CLKID_SD_EMMC_C_DIV] = &c3_sd_emmc_c_div.hw, + [CLKID_SD_EMMC_C] = &c3_sd_emmc_c.hw, + [CLKID_TS_DIV] = &c3_ts_div.hw, + [CLKID_TS] = &c3_ts.hw, + [CLKID_ETH_125M_DIV] = &c3_eth_125m_div.hw, + [CLKID_ETH_125M] = &c3_eth_125m.hw, + [CLKID_ETH_RMII_DIV] = &c3_eth_rmii_div.hw, + [CLKID_ETH_RMII] = &c3_eth_rmii.hw, + [CLKID_MIPI_DSI_MEAS_SEL] = &c3_mipi_dsi_meas_sel.hw, + [CLKID_MIPI_DSI_MEAS_DIV] = &c3_mipi_dsi_meas_div.hw, + [CLKID_MIPI_DSI_MEAS] = &c3_mipi_dsi_meas.hw, + [CLKID_DSI_PHY_SEL] = &c3_dsi_phy_sel.hw, + [CLKID_DSI_PHY_DIV] = &c3_dsi_phy_div.hw, + [CLKID_DSI_PHY] = &c3_dsi_phy.hw, + [CLKID_VOUT_MCLK_SEL] = &c3_vout_mclk_sel.hw, + [CLKID_VOUT_MCLK_DIV] = &c3_vout_mclk_div.hw, + [CLKID_VOUT_MCLK] = &c3_vout_mclk.hw, + [CLKID_VOUT_ENC_SEL] = &c3_vout_enc_sel.hw, + [CLKID_VOUT_ENC_DIV] = &c3_vout_enc_div.hw, + [CLKID_VOUT_ENC] = &c3_vout_enc.hw, + [CLKID_HCODEC_0_SEL] = &c3_hcodec_0_sel.hw, + [CLKID_HCODEC_0_DIV] = &c3_hcodec_0_div.hw, + [CLKID_HCODEC_0] = &c3_hcodec_0.hw, + [CLKID_HCODEC_1_SEL] = &c3_hcodec_1_sel.hw, + [CLKID_HCODEC_1_DIV] = &c3_hcodec_1_div.hw, + [CLKID_HCODEC_1] = &c3_hcodec_1.hw, + [CLKID_HCODEC] = &c3_hcodec.hw, + [CLKID_VC9000E_ACLK_SEL] = &c3_vc9000e_aclk_sel.hw, + [CLKID_VC9000E_ACLK_DIV] = &c3_vc9000e_aclk_div.hw, + [CLKID_VC9000E_ACLK] = &c3_vc9000e_aclk.hw, + [CLKID_VC9000E_CORE_SEL] = &c3_vc9000e_core_sel.hw, + [CLKID_VC9000E_CORE_DIV] = &c3_vc9000e_core_div.hw, + [CLKID_VC9000E_CORE] = &c3_vc9000e_core.hw, + [CLKID_CSI_PHY0_SEL] = &c3_csi_phy0_sel.hw, + [CLKID_CSI_PHY0_DIV] = &c3_csi_phy0_div.hw, + [CLKID_CSI_PHY0] = &c3_csi_phy0.hw, + [CLKID_DEWARPA_SEL] = &c3_dewarpa_sel.hw, + [CLKID_DEWARPA_DIV] = &c3_dewarpa_div.hw, + [CLKID_DEWARPA] = &c3_dewarpa.hw, + [CLKID_ISP0_SEL] = &c3_isp0_sel.hw, + [CLKID_ISP0_DIV] = &c3_isp0_div.hw, + [CLKID_ISP0] = &c3_isp0.hw, + [CLKID_NNA_CORE_SEL] = &c3_nna_core_sel.hw, + [CLKID_NNA_CORE_DIV] = &c3_nna_core_div.hw, + [CLKID_NNA_CORE] = &c3_nna_core.hw, + [CLKID_GE2D_SEL] = &c3_ge2d_sel.hw, + [CLKID_GE2D_DIV] = &c3_ge2d_div.hw, + [CLKID_GE2D] = &c3_ge2d.hw, + [CLKID_VAPB_SEL] = &c3_vapb_sel.hw, + [CLKID_VAPB_DIV] = &c3_vapb_div.hw, + [CLKID_VAPB] = &c3_vapb.hw, }; -static const struct regmap_config clkc_regmap_config = { +static const struct regmap_config c3_peripherals_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .max_register = NNA_CLK_CTRL, }; -static struct meson_clk_hw_data c3_periphs_clks = { - .hws = c3_periphs_hw_clks, - .num = ARRAY_SIZE(c3_periphs_hw_clks), +static struct meson_clk_hw_data c3_peripherals_clks = { + .hws = c3_peripherals_hw_clks, + .num = ARRAY_SIZE(c3_peripherals_hw_clks), }; -static int c3_peripherals_probe(struct platform_device *pdev) +static int c3_peripherals_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct regmap *regmap; @@ -2115,16 +2114,16 @@ static int c3_peripherals_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config); + regmap = devm_regmap_init_mmio(dev, base, &c3_peripherals_regmap_cfg); if (IS_ERR(regmap)) return PTR_ERR(regmap); - for (clkid = 0; clkid < c3_periphs_clks.num; clkid++) { + for (clkid = 0; clkid < c3_peripherals_clks.num; clkid++) { /* array might be sparse */ - if (!c3_periphs_clks.hws[clkid]) + if (!c3_peripherals_clks.hws[clkid]) continue; - ret = devm_clk_hw_register(dev, c3_periphs_clks.hws[clkid]); + ret = devm_clk_hw_register(dev, c3_peripherals_clks.hws[clkid]); if (ret) { dev_err(dev, "Clock registration failed\n"); return ret; @@ -2132,7 +2131,7 @@ static int c3_peripherals_probe(struct platform_device *pdev) } return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, - &c3_periphs_clks); + &c3_peripherals_clks); } static const struct of_device_id c3_peripherals_clkc_match_table[] = { @@ -2144,14 +2143,14 @@ static const struct of_device_id c3_peripherals_clkc_match_table[] = { MODULE_DEVICE_TABLE(of, c3_peripherals_clkc_match_table); -static struct platform_driver c3_peripherals_driver = { - .probe = c3_peripherals_probe, +static struct platform_driver c3_peripherals_clkc_driver = { + .probe = c3_peripherals_clkc_probe, .driver = { .name = "c3-peripherals-clkc", .of_match_table = c3_peripherals_clkc_match_table, }, }; -module_platform_driver(c3_peripherals_driver); +module_platform_driver(c3_peripherals_clkc_driver); MODULE_DESCRIPTION("Amlogic C3 Peripherals Clock Controller driver"); MODULE_AUTHOR("Chuan Liu "); diff --git a/drivers/clk/meson/c3-pll.c b/drivers/clk/meson/c3-pll.c index 2c5594b8e49a..ccfcd4b5be89 100644 --- a/drivers/clk/meson/c3-pll.c +++ b/drivers/clk/meson/c3-pll.c @@ -34,7 +34,7 @@ #define ANACTRL_MPLL_CTRL3 0x18c #define ANACTRL_MPLL_CTRL4 0x190 -static struct clk_regmap fclk_50m_en = { +static struct clk_regmap c3_fclk_50m_en = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_FIXPLL_CTRL4, .bit_idx = 0, @@ -49,20 +49,20 @@ static struct clk_regmap fclk_50m_en = { }, }; -static struct clk_fixed_factor fclk_50m = { +static struct clk_fixed_factor c3_fclk_50m = { .mult = 1, .div = 40, .hw.init = &(struct clk_init_data) { .name = "fclk_50m", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_50m_en.hw + &c3_fclk_50m_en.hw }, .num_parents = 1, }, }; -static struct clk_fixed_factor fclk_div2_div = { +static struct clk_fixed_factor c3_fclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data) { @@ -75,7 +75,7 @@ static struct clk_fixed_factor fclk_div2_div = { }, }; -static struct clk_regmap fclk_div2 = { +static struct clk_regmap c3_fclk_div2 = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_FIXPLL_CTRL4, .bit_idx = 24, @@ -84,13 +84,13 @@ static struct clk_regmap fclk_div2 = { .name = "fclk_div2", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div2_div.hw + &c3_fclk_div2_div.hw }, .num_parents = 1, }, }; -static struct clk_fixed_factor fclk_div2p5_div = { +static struct clk_fixed_factor c3_fclk_div2p5_div = { .mult = 2, .div = 5, .hw.init = &(struct clk_init_data) { @@ -103,7 +103,7 @@ static struct clk_fixed_factor fclk_div2p5_div = { }, }; -static struct clk_regmap fclk_div2p5 = { +static struct clk_regmap c3_fclk_div2p5 = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_FIXPLL_CTRL4, .bit_idx = 4, @@ -112,13 +112,13 @@ static struct clk_regmap fclk_div2p5 = { .name = "fclk_div2p5", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div2p5_div.hw + &c3_fclk_div2p5_div.hw }, .num_parents = 1, }, }; -static struct clk_fixed_factor fclk_div3_div = { +static struct clk_fixed_factor c3_fclk_div3_div = { .mult = 1, .div = 3, .hw.init = &(struct clk_init_data) { @@ -131,7 +131,7 @@ static struct clk_fixed_factor fclk_div3_div = { }, }; -static struct clk_regmap fclk_div3 = { +static struct clk_regmap c3_fclk_div3 = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_FIXPLL_CTRL4, .bit_idx = 20, @@ -140,13 +140,13 @@ static struct clk_regmap fclk_div3 = { .name = "fclk_div3", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div3_div.hw + &c3_fclk_div3_div.hw }, .num_parents = 1, }, }; -static struct clk_fixed_factor fclk_div4_div = { +static struct clk_fixed_factor c3_fclk_div4_div = { .mult = 1, .div = 4, .hw.init = &(struct clk_init_data) { @@ -159,7 +159,7 @@ static struct clk_fixed_factor fclk_div4_div = { }, }; -static struct clk_regmap fclk_div4 = { +static struct clk_regmap c3_fclk_div4 = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_FIXPLL_CTRL4, .bit_idx = 21, @@ -168,13 +168,13 @@ static struct clk_regmap fclk_div4 = { .name = "fclk_div4", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div4_div.hw + &c3_fclk_div4_div.hw }, .num_parents = 1, }, }; -static struct clk_fixed_factor fclk_div5_div = { +static struct clk_fixed_factor c3_fclk_div5_div = { .mult = 1, .div = 5, .hw.init = &(struct clk_init_data) { @@ -187,7 +187,7 @@ static struct clk_fixed_factor fclk_div5_div = { }, }; -static struct clk_regmap fclk_div5 = { +static struct clk_regmap c3_fclk_div5 = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_FIXPLL_CTRL4, .bit_idx = 22, @@ -196,13 +196,13 @@ static struct clk_regmap fclk_div5 = { .name = "fclk_div5", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div5_div.hw + &c3_fclk_div5_div.hw }, .num_parents = 1, }, }; -static struct clk_fixed_factor fclk_div7_div = { +static struct clk_fixed_factor c3_fclk_div7_div = { .mult = 1, .div = 7, .hw.init = &(struct clk_init_data) { @@ -215,7 +215,7 @@ static struct clk_fixed_factor fclk_div7_div = { }, }; -static struct clk_regmap fclk_div7 = { +static struct clk_regmap c3_fclk_div7 = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_FIXPLL_CTRL4, .bit_idx = 23, @@ -224,13 +224,13 @@ static struct clk_regmap fclk_div7 = { .name = "fclk_div7", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &fclk_div7_div.hw + &c3_fclk_div7_div.hw }, .num_parents = 1, }, }; -static const struct reg_sequence c3_gp0_init_regs[] = { +static const struct reg_sequence c3_gp0_pll_init_regs[] = { { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x0 }, { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x48681c00 }, { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x88770290 }, @@ -243,7 +243,7 @@ static const struct pll_mult_range c3_gp0_pll_mult_range = { .max = 250, }; -static struct clk_regmap gp0_pll_dco = { +static struct clk_regmap c3_gp0_pll_dco = { .data = &(struct meson_clk_pll_data) { .en = { .reg_off = ANACTRL_GP0PLL_CTRL0, @@ -276,8 +276,8 @@ static struct clk_regmap gp0_pll_dco = { .width = 1, }, .range = &c3_gp0_pll_mult_range, - .init_regs = c3_gp0_init_regs, - .init_count = ARRAY_SIZE(c3_gp0_init_regs), + .init_regs = c3_gp0_pll_init_regs, + .init_count = ARRAY_SIZE(c3_gp0_pll_init_regs), }, .hw.init = &(struct clk_init_data) { .name = "gp0_pll_dco", @@ -300,7 +300,7 @@ static const struct clk_div_table c3_gp0_pll_od_table[] = { { /* sentinel */ } }; -static struct clk_regmap gp0_pll = { +static struct clk_regmap c3_gp0_pll = { .data = &(struct clk_regmap_div_data) { .offset = ANACTRL_GP0PLL_CTRL0, .shift = 16, @@ -311,14 +311,14 @@ static struct clk_regmap gp0_pll = { .name = "gp0_pll", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &gp0_pll_dco.hw + &c3_gp0_pll_dco.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct reg_sequence c3_hifi_init_regs[] = { +static const struct reg_sequence c3_hifi_pll_init_regs[] = { { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x0 }, { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 }, { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 }, @@ -326,7 +326,7 @@ static const struct reg_sequence c3_hifi_init_regs[] = { { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x56540000 }, }; -static struct clk_regmap hifi_pll_dco = { +static struct clk_regmap c3_hifi_pll_dco = { .data = &(struct meson_clk_pll_data) { .en = { .reg_off = ANACTRL_HIFIPLL_CTRL0, @@ -359,8 +359,8 @@ static struct clk_regmap hifi_pll_dco = { .width = 1, }, .range = &c3_gp0_pll_mult_range, - .init_regs = c3_hifi_init_regs, - .init_count = ARRAY_SIZE(c3_hifi_init_regs), + .init_regs = c3_hifi_pll_init_regs, + .init_count = ARRAY_SIZE(c3_hifi_pll_init_regs), .frac_max = 100000, }, .hw.init = &(struct clk_init_data) { @@ -373,7 +373,7 @@ static struct clk_regmap hifi_pll_dco = { }, }; -static struct clk_regmap hifi_pll = { +static struct clk_regmap c3_hifi_pll = { .data = &(struct clk_regmap_div_data) { .offset = ANACTRL_HIFIPLL_CTRL0, .shift = 16, @@ -384,14 +384,14 @@ static struct clk_regmap hifi_pll = { .name = "hifi_pll", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &hifi_pll_dco.hw + &c3_hifi_pll_dco.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct reg_sequence c3_mclk_init_regs[] = { +static const struct reg_sequence c3_mclk_pll_init_regs[] = { { .reg = ANACTRL_MPLL_CTRL1, .def = 0x1420500f }, { .reg = ANACTRL_MPLL_CTRL2, .def = 0x00023041 }, { .reg = ANACTRL_MPLL_CTRL3, .def = 0x18180000 }, @@ -403,7 +403,7 @@ static const struct pll_mult_range c3_mclk_pll_mult_range = { .max = 133, }; -static struct clk_regmap mclk_pll_dco = { +static struct clk_regmap c3_mclk_pll_dco = { .data = &(struct meson_clk_pll_data) { .en = { .reg_off = ANACTRL_MPLL_CTRL0, @@ -431,8 +431,8 @@ static struct clk_regmap mclk_pll_dco = { .width = 1, }, .range = &c3_mclk_pll_mult_range, - .init_regs = c3_mclk_init_regs, - .init_count = ARRAY_SIZE(c3_mclk_init_regs), + .init_regs = c3_mclk_pll_init_regs, + .init_count = ARRAY_SIZE(c3_mclk_pll_init_regs), }, .hw.init = &(struct clk_init_data) { .name = "mclk_pll_dco", @@ -444,7 +444,7 @@ static struct clk_regmap mclk_pll_dco = { }, }; -static const struct clk_div_table c3_mpll_od_table[] = { +static const struct clk_div_table c3_mpll_pll_od_table[] = { { 0, 1 }, { 1, 2 }, { 2, 4 }, @@ -453,25 +453,25 @@ static const struct clk_div_table c3_mpll_od_table[] = { { /* sentinel */ } }; -static struct clk_regmap mclk_pll_od = { +static struct clk_regmap c3_mclk_pll_od = { .data = &(struct clk_regmap_div_data) { .offset = ANACTRL_MPLL_CTRL0, .shift = 12, .width = 3, - .table = c3_mpll_od_table, + .table = c3_mpll_pll_od_table, }, .hw.init = &(struct clk_init_data) { .name = "mclk_pll_od", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &mclk_pll_dco.hw }, + &c3_mclk_pll_dco.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; /* both value 0 and 1 gives divide the input rate by one */ -static struct clk_regmap mclk_pll = { +static struct clk_regmap c3_mclk_pll = { .data = &(struct clk_regmap_div_data) { .offset = ANACTRL_MPLL_CTRL4, .shift = 16, @@ -482,20 +482,20 @@ static struct clk_regmap mclk_pll = { .name = "mclk_pll", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &mclk_pll_od.hw + &c3_mclk_pll_od.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const struct clk_parent_data mclk_parent[] = { - { .hw = &mclk_pll.hw }, +static const struct clk_parent_data c3_mclk_parents[] = { + { .hw = &c3_mclk_pll.hw }, { .fw_name = "mclk" }, - { .hw = &fclk_50m.hw } + { .hw = &c3_fclk_50m.hw } }; -static struct clk_regmap mclk0_sel = { +static struct clk_regmap c3_mclk0_sel = { .data = &(struct clk_regmap_mux_data) { .offset = ANACTRL_MPLL_CTRL4, .mask = 0x3, @@ -504,12 +504,12 @@ static struct clk_regmap mclk0_sel = { .hw.init = &(struct clk_init_data) { .name = "mclk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = mclk_parent, - .num_parents = ARRAY_SIZE(mclk_parent), + .parent_data = c3_mclk_parents, + .num_parents = ARRAY_SIZE(c3_mclk_parents), }, }; -static struct clk_regmap mclk0_div_en = { +static struct clk_regmap c3_mclk0_div_en = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_MPLL_CTRL4, .bit_idx = 1, @@ -518,14 +518,14 @@ static struct clk_regmap mclk0_div_en = { .name = "mclk0_div_en", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &mclk0_sel.hw + &c3_mclk0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap mclk0_div = { +static struct clk_regmap c3_mclk0_div = { .data = &(struct clk_regmap_div_data) { .offset = ANACTRL_MPLL_CTRL4, .shift = 2, @@ -535,14 +535,14 @@ static struct clk_regmap mclk0_div = { .name = "mclk0_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &mclk0_div_en.hw + &c3_mclk0_div_en.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap mclk0 = { +static struct clk_regmap c3_mclk0 = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_MPLL_CTRL4, .bit_idx = 0, @@ -551,14 +551,14 @@ static struct clk_regmap mclk0 = { .name = "mclk0", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &mclk0_div.hw + &c3_mclk0_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap mclk1_sel = { +static struct clk_regmap c3_mclk1_sel = { .data = &(struct clk_regmap_mux_data) { .offset = ANACTRL_MPLL_CTRL4, .mask = 0x3, @@ -567,12 +567,12 @@ static struct clk_regmap mclk1_sel = { .hw.init = &(struct clk_init_data) { .name = "mclk1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = mclk_parent, - .num_parents = ARRAY_SIZE(mclk_parent), + .parent_data = c3_mclk_parents, + .num_parents = ARRAY_SIZE(c3_mclk_parents), }, }; -static struct clk_regmap mclk1_div_en = { +static struct clk_regmap c3_mclk1_div_en = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_MPLL_CTRL4, .bit_idx = 9, @@ -581,14 +581,14 @@ static struct clk_regmap mclk1_div_en = { .name = "mclk1_div_en", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &mclk1_sel.hw + &c3_mclk1_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap mclk1_div = { +static struct clk_regmap c3_mclk1_div = { .data = &(struct clk_regmap_div_data) { .offset = ANACTRL_MPLL_CTRL4, .shift = 10, @@ -598,14 +598,14 @@ static struct clk_regmap mclk1_div = { .name = "mclk1_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &mclk1_div_en.hw + &c3_mclk1_div_en.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap mclk1 = { +static struct clk_regmap c3_mclk1 = { .data = &(struct clk_regmap_gate_data) { .offset = ANACTRL_MPLL_CTRL4, .bit_idx = 8, @@ -614,7 +614,7 @@ static struct clk_regmap mclk1 = { .name = "mclk1", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &mclk1_div.hw + &c3_mclk1_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -622,38 +622,38 @@ static struct clk_regmap mclk1 = { }; static struct clk_hw *c3_pll_hw_clks[] = { - [CLKID_FCLK_50M_EN] = &fclk_50m_en.hw, - [CLKID_FCLK_50M] = &fclk_50m.hw, - [CLKID_FCLK_DIV2_DIV] = &fclk_div2_div.hw, - [CLKID_FCLK_DIV2] = &fclk_div2.hw, - [CLKID_FCLK_DIV2P5_DIV] = &fclk_div2p5_div.hw, - [CLKID_FCLK_DIV2P5] = &fclk_div2p5.hw, - [CLKID_FCLK_DIV3_DIV] = &fclk_div3_div.hw, - [CLKID_FCLK_DIV3] = &fclk_div3.hw, - [CLKID_FCLK_DIV4_DIV] = &fclk_div4_div.hw, - [CLKID_FCLK_DIV4] = &fclk_div4.hw, - [CLKID_FCLK_DIV5_DIV] = &fclk_div5_div.hw, - [CLKID_FCLK_DIV5] = &fclk_div5.hw, - [CLKID_FCLK_DIV7_DIV] = &fclk_div7_div.hw, - [CLKID_FCLK_DIV7] = &fclk_div7.hw, - [CLKID_GP0_PLL_DCO] = &gp0_pll_dco.hw, - [CLKID_GP0_PLL] = &gp0_pll.hw, - [CLKID_HIFI_PLL_DCO] = &hifi_pll_dco.hw, - [CLKID_HIFI_PLL] = &hifi_pll.hw, - [CLKID_MCLK_PLL_DCO] = &mclk_pll_dco.hw, - [CLKID_MCLK_PLL_OD] = &mclk_pll_od.hw, - [CLKID_MCLK_PLL] = &mclk_pll.hw, - [CLKID_MCLK0_SEL] = &mclk0_sel.hw, - [CLKID_MCLK0_SEL_EN] = &mclk0_div_en.hw, - [CLKID_MCLK0_DIV] = &mclk0_div.hw, - [CLKID_MCLK0] = &mclk0.hw, - [CLKID_MCLK1_SEL] = &mclk1_sel.hw, - [CLKID_MCLK1_SEL_EN] = &mclk1_div_en.hw, - [CLKID_MCLK1_DIV] = &mclk1_div.hw, - [CLKID_MCLK1] = &mclk1.hw + [CLKID_FCLK_50M_EN] = &c3_fclk_50m_en.hw, + [CLKID_FCLK_50M] = &c3_fclk_50m.hw, + [CLKID_FCLK_DIV2_DIV] = &c3_fclk_div2_div.hw, + [CLKID_FCLK_DIV2] = &c3_fclk_div2.hw, + [CLKID_FCLK_DIV2P5_DIV] = &c3_fclk_div2p5_div.hw, + [CLKID_FCLK_DIV2P5] = &c3_fclk_div2p5.hw, + [CLKID_FCLK_DIV3_DIV] = &c3_fclk_div3_div.hw, + [CLKID_FCLK_DIV3] = &c3_fclk_div3.hw, + [CLKID_FCLK_DIV4_DIV] = &c3_fclk_div4_div.hw, + [CLKID_FCLK_DIV4] = &c3_fclk_div4.hw, + [CLKID_FCLK_DIV5_DIV] = &c3_fclk_div5_div.hw, + [CLKID_FCLK_DIV5] = &c3_fclk_div5.hw, + [CLKID_FCLK_DIV7_DIV] = &c3_fclk_div7_div.hw, + [CLKID_FCLK_DIV7] = &c3_fclk_div7.hw, + [CLKID_GP0_PLL_DCO] = &c3_gp0_pll_dco.hw, + [CLKID_GP0_PLL] = &c3_gp0_pll.hw, + [CLKID_HIFI_PLL_DCO] = &c3_hifi_pll_dco.hw, + [CLKID_HIFI_PLL] = &c3_hifi_pll.hw, + [CLKID_MCLK_PLL_DCO] = &c3_mclk_pll_dco.hw, + [CLKID_MCLK_PLL_OD] = &c3_mclk_pll_od.hw, + [CLKID_MCLK_PLL] = &c3_mclk_pll.hw, + [CLKID_MCLK0_SEL] = &c3_mclk0_sel.hw, + [CLKID_MCLK0_SEL_EN] = &c3_mclk0_div_en.hw, + [CLKID_MCLK0_DIV] = &c3_mclk0_div.hw, + [CLKID_MCLK0] = &c3_mclk0.hw, + [CLKID_MCLK1_SEL] = &c3_mclk1_sel.hw, + [CLKID_MCLK1_SEL_EN] = &c3_mclk1_div_en.hw, + [CLKID_MCLK1_DIV] = &c3_mclk1_div.hw, + [CLKID_MCLK1] = &c3_mclk1.hw }; -static const struct regmap_config clkc_regmap_config = { +static const struct regmap_config c3_pll_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -665,7 +665,7 @@ static struct meson_clk_hw_data c3_pll_clks = { .num = ARRAY_SIZE(c3_pll_hw_clks), }; -static int c3_pll_probe(struct platform_device *pdev) +static int c3_pll_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct regmap *regmap; @@ -676,7 +676,7 @@ static int c3_pll_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config); + regmap = devm_regmap_init_mmio(dev, base, &c3_pll_regmap_cfg); if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -704,14 +704,14 @@ static const struct of_device_id c3_pll_clkc_match_table[] = { }; MODULE_DEVICE_TABLE(of, c3_pll_clkc_match_table); -static struct platform_driver c3_pll_driver = { - .probe = c3_pll_probe, +static struct platform_driver c3_pll_clkc_driver = { + .probe = c3_pll_clkc_probe, .driver = { .name = "c3-pll-clkc", .of_match_table = c3_pll_clkc_match_table, }, }; -module_platform_driver(c3_pll_driver); +module_platform_driver(c3_pll_clkc_driver); MODULE_DESCRIPTION("Amlogic C3 PLL Clock Controller driver"); MODULE_AUTHOR("Chuan Liu "); diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c index 4095a1b2bb80..3eaf1db16f45 100644 --- a/drivers/clk/meson/g12a-aoclk.c +++ b/drivers/clk/meson/g12a-aoclk.c @@ -43,8 +43,8 @@ * bootloader. The goal is to remove this flag at some point. * Actually removing it will require some extensive test to be done safely. */ -#define AXG_AO_GATE(_name, _reg, _bit) \ -static struct clk_regmap g12a_aoclk_##_name = { \ +#define G12A_AO_PCLK(_name, _reg, _bit) \ +static struct clk_regmap g12a_ao_##_name = { \ .data = &(struct clk_regmap_gate_data) { \ .offset = (_reg), \ .bit_idx = (_bit), \ @@ -60,23 +60,24 @@ static struct clk_regmap g12a_aoclk_##_name = { \ }, \ } -AXG_AO_GATE(ahb, AO_CLK_GATE0, 0); -AXG_AO_GATE(ir_in, AO_CLK_GATE0, 1); -AXG_AO_GATE(i2c_m0, AO_CLK_GATE0, 2); -AXG_AO_GATE(i2c_s0, AO_CLK_GATE0, 3); -AXG_AO_GATE(uart, AO_CLK_GATE0, 4); -AXG_AO_GATE(prod_i2c, AO_CLK_GATE0, 5); -AXG_AO_GATE(uart2, AO_CLK_GATE0, 6); -AXG_AO_GATE(ir_out, AO_CLK_GATE0, 7); -AXG_AO_GATE(saradc, AO_CLK_GATE0, 8); -AXG_AO_GATE(mailbox, AO_CLK_GATE0_SP, 0); -AXG_AO_GATE(m3, AO_CLK_GATE0_SP, 1); -AXG_AO_GATE(ahb_sram, AO_CLK_GATE0_SP, 2); -AXG_AO_GATE(rti, AO_CLK_GATE0_SP, 3); -AXG_AO_GATE(m4_fclk, AO_CLK_GATE0_SP, 4); -AXG_AO_GATE(m4_hclk, AO_CLK_GATE0_SP, 5); +G12A_AO_PCLK(ahb, AO_CLK_GATE0, 0); +G12A_AO_PCLK(ir_in, AO_CLK_GATE0, 1); +G12A_AO_PCLK(i2c_m0, AO_CLK_GATE0, 2); +G12A_AO_PCLK(i2c_s0, AO_CLK_GATE0, 3); +G12A_AO_PCLK(uart, AO_CLK_GATE0, 4); +G12A_AO_PCLK(prod_i2c, AO_CLK_GATE0, 5); +G12A_AO_PCLK(uart2, AO_CLK_GATE0, 6); +G12A_AO_PCLK(ir_out, AO_CLK_GATE0, 7); +G12A_AO_PCLK(saradc, AO_CLK_GATE0, 8); -static struct clk_regmap g12a_aoclk_cts_oscin = { +G12A_AO_PCLK(mailbox, AO_CLK_GATE0_SP, 0); +G12A_AO_PCLK(m3, AO_CLK_GATE0_SP, 1); +G12A_AO_PCLK(ahb_sram, AO_CLK_GATE0_SP, 2); +G12A_AO_PCLK(rti, AO_CLK_GATE0_SP, 3); +G12A_AO_PCLK(m4_fclk, AO_CLK_GATE0_SP, 4); +G12A_AO_PCLK(m4_hclk, AO_CLK_GATE0_SP, 5); + +static struct clk_regmap g12a_ao_cts_oscin = { .data = &(struct clk_regmap_gate_data){ .offset = AO_RTI_PWR_CNTL_REG0, .bit_idx = 14, @@ -103,22 +104,22 @@ static const struct meson_clk_dualdiv_param g12a_32k_div_table[] = { /* 32k_by_oscin clock */ -static struct clk_regmap g12a_aoclk_32k_by_oscin_pre = { +static struct clk_regmap g12a_ao_32k_by_oscin_pre = { .data = &(struct clk_regmap_gate_data){ .offset = AO_RTC_ALT_CLK_CNTL0, .bit_idx = 31, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_32k_by_oscin_pre", + .name = "ao_32k_by_oscin_pre", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_aoclk_cts_oscin.hw + &g12a_ao_cts_oscin.hw }, .num_parents = 1, }, }; -static struct clk_regmap g12a_aoclk_32k_by_oscin_div = { +static struct clk_regmap g12a_ao_32k_by_oscin_div = { .data = &(struct meson_clk_dualdiv_data){ .n1 = { .reg_off = AO_RTC_ALT_CLK_CNTL0, @@ -148,16 +149,16 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin_div = { .table = g12a_32k_div_table, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_32k_by_oscin_div", + .name = "ao_32k_by_oscin_div", .ops = &meson_clk_dualdiv_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_aoclk_32k_by_oscin_pre.hw + &g12a_ao_32k_by_oscin_pre.hw }, .num_parents = 1, }, }; -static struct clk_regmap g12a_aoclk_32k_by_oscin_sel = { +static struct clk_regmap g12a_ao_32k_by_oscin_sel = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTC_ALT_CLK_CNTL1, .mask = 0x1, @@ -165,27 +166,27 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin_sel = { .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_32k_by_oscin_sel", + .name = "ao_32k_by_oscin_sel", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_aoclk_32k_by_oscin_div.hw, - &g12a_aoclk_32k_by_oscin_pre.hw, + &g12a_ao_32k_by_oscin_div.hw, + &g12a_ao_32k_by_oscin_pre.hw, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap g12a_aoclk_32k_by_oscin = { +static struct clk_regmap g12a_ao_32k_by_oscin = { .data = &(struct clk_regmap_gate_data){ .offset = AO_RTC_ALT_CLK_CNTL0, .bit_idx = 30, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_32k_by_oscin", + .name = "ao_32k_by_oscin", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_aoclk_32k_by_oscin_sel.hw + &g12a_ao_32k_by_oscin_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -194,22 +195,22 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin = { /* cec clock */ -static struct clk_regmap g12a_aoclk_cec_pre = { +static struct clk_regmap g12a_ao_cec_pre = { .data = &(struct clk_regmap_gate_data){ .offset = AO_CEC_CLK_CNTL_REG0, .bit_idx = 31, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_cec_pre", + .name = "ao_cec_pre", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_aoclk_cts_oscin.hw + &g12a_ao_cts_oscin.hw }, .num_parents = 1, }, }; -static struct clk_regmap g12a_aoclk_cec_div = { +static struct clk_regmap g12a_ao_cec_div = { .data = &(struct meson_clk_dualdiv_data){ .n1 = { .reg_off = AO_CEC_CLK_CNTL_REG0, @@ -239,16 +240,16 @@ static struct clk_regmap g12a_aoclk_cec_div = { .table = g12a_32k_div_table, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_cec_div", + .name = "ao_cec_div", .ops = &meson_clk_dualdiv_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_aoclk_cec_pre.hw + &g12a_ao_cec_pre.hw }, .num_parents = 1, }, }; -static struct clk_regmap g12a_aoclk_cec_sel = { +static struct clk_regmap g12a_ao_cec_sel = { .data = &(struct clk_regmap_mux_data) { .offset = AO_CEC_CLK_CNTL_REG1, .mask = 0x1, @@ -256,34 +257,34 @@ static struct clk_regmap g12a_aoclk_cec_sel = { .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_cec_sel", + .name = "ao_cec_sel", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_aoclk_cec_div.hw, - &g12a_aoclk_cec_pre.hw, + &g12a_ao_cec_div.hw, + &g12a_ao_cec_pre.hw, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap g12a_aoclk_cec = { +static struct clk_regmap g12a_ao_cec = { .data = &(struct clk_regmap_gate_data){ .offset = AO_CEC_CLK_CNTL_REG0, .bit_idx = 30, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_cec", + .name = "ao_cec", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_aoclk_cec_sel.hw + &g12a_ao_cec_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap g12a_aoclk_cts_rtc_oscin = { +static struct clk_regmap g12a_ao_cts_rtc_oscin = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTI_PWR_CNTL_REG0, .mask = 0x1, @@ -291,10 +292,10 @@ static struct clk_regmap g12a_aoclk_cts_rtc_oscin = { .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_cts_rtc_oscin", + .name = "ao_cts_rtc_oscin", .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { - { .hw = &g12a_aoclk_32k_by_oscin.hw }, + { .hw = &g12a_ao_32k_by_oscin.hw }, { .fw_name = "ext-32k-0", }, }, .num_parents = 2, @@ -302,7 +303,7 @@ static struct clk_regmap g12a_aoclk_cts_rtc_oscin = { }, }; -static struct clk_regmap g12a_aoclk_clk81 = { +static struct clk_regmap g12a_ao_clk81 = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTI_PWR_CNTL_REG0, .mask = 0x1, @@ -310,68 +311,74 @@ static struct clk_regmap g12a_aoclk_clk81 = { .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ + /* + * NOTE: this is one of the infamous clock the pwm driver + * can request directly by its global name. It's wrong but + * there is not much we can do about it until the support + * for the old pwm bindings is dropped + */ .name = "g12a_ao_clk81", .ops = &clk_regmap_mux_ro_ops, .parent_data = (const struct clk_parent_data []) { { .fw_name = "mpeg-clk", }, - { .hw = &g12a_aoclk_cts_rtc_oscin.hw }, + { .hw = &g12a_ao_cts_rtc_oscin.hw }, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap g12a_aoclk_saradc_mux = { +static struct clk_regmap g12a_ao_saradc_mux = { .data = &(struct clk_regmap_mux_data) { .offset = AO_SAR_CLK, .mask = 0x3, .shift = 9, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_saradc_mux", + .name = "ao_saradc_mux", .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { { .fw_name = "xtal", }, - { .hw = &g12a_aoclk_clk81.hw }, + { .hw = &g12a_ao_clk81.hw }, }, .num_parents = 2, }, }; -static struct clk_regmap g12a_aoclk_saradc_div = { +static struct clk_regmap g12a_ao_saradc_div = { .data = &(struct clk_regmap_div_data) { .offset = AO_SAR_CLK, .shift = 0, .width = 8, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_saradc_div", + .name = "ao_saradc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_aoclk_saradc_mux.hw + &g12a_ao_saradc_mux.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap g12a_aoclk_saradc_gate = { +static struct clk_regmap g12a_ao_saradc_gate = { .data = &(struct clk_regmap_gate_data) { .offset = AO_SAR_CLK, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "g12a_ao_saradc_gate", + .name = "ao_saradc_gate", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_aoclk_saradc_div.hw + &g12a_ao_saradc_div.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static const unsigned int g12a_aoclk_reset[] = { +static const unsigned int g12a_ao_reset[] = { [RESET_AO_IR_IN] = 16, [RESET_AO_UART] = 17, [RESET_AO_I2C_M] = 18, @@ -381,65 +388,65 @@ static const unsigned int g12a_aoclk_reset[] = { [RESET_AO_IR_OUT] = 23, }; -static struct clk_hw *g12a_aoclk_hw_clks[] = { - [CLKID_AO_AHB] = &g12a_aoclk_ahb.hw, - [CLKID_AO_IR_IN] = &g12a_aoclk_ir_in.hw, - [CLKID_AO_I2C_M0] = &g12a_aoclk_i2c_m0.hw, - [CLKID_AO_I2C_S0] = &g12a_aoclk_i2c_s0.hw, - [CLKID_AO_UART] = &g12a_aoclk_uart.hw, - [CLKID_AO_PROD_I2C] = &g12a_aoclk_prod_i2c.hw, - [CLKID_AO_UART2] = &g12a_aoclk_uart2.hw, - [CLKID_AO_IR_OUT] = &g12a_aoclk_ir_out.hw, - [CLKID_AO_SAR_ADC] = &g12a_aoclk_saradc.hw, - [CLKID_AO_MAILBOX] = &g12a_aoclk_mailbox.hw, - [CLKID_AO_M3] = &g12a_aoclk_m3.hw, - [CLKID_AO_AHB_SRAM] = &g12a_aoclk_ahb_sram.hw, - [CLKID_AO_RTI] = &g12a_aoclk_rti.hw, - [CLKID_AO_M4_FCLK] = &g12a_aoclk_m4_fclk.hw, - [CLKID_AO_M4_HCLK] = &g12a_aoclk_m4_hclk.hw, - [CLKID_AO_CLK81] = &g12a_aoclk_clk81.hw, - [CLKID_AO_SAR_ADC_SEL] = &g12a_aoclk_saradc_mux.hw, - [CLKID_AO_SAR_ADC_DIV] = &g12a_aoclk_saradc_div.hw, - [CLKID_AO_SAR_ADC_CLK] = &g12a_aoclk_saradc_gate.hw, - [CLKID_AO_CTS_OSCIN] = &g12a_aoclk_cts_oscin.hw, - [CLKID_AO_32K_PRE] = &g12a_aoclk_32k_by_oscin_pre.hw, - [CLKID_AO_32K_DIV] = &g12a_aoclk_32k_by_oscin_div.hw, - [CLKID_AO_32K_SEL] = &g12a_aoclk_32k_by_oscin_sel.hw, - [CLKID_AO_32K] = &g12a_aoclk_32k_by_oscin.hw, - [CLKID_AO_CEC_PRE] = &g12a_aoclk_cec_pre.hw, - [CLKID_AO_CEC_DIV] = &g12a_aoclk_cec_div.hw, - [CLKID_AO_CEC_SEL] = &g12a_aoclk_cec_sel.hw, - [CLKID_AO_CEC] = &g12a_aoclk_cec.hw, - [CLKID_AO_CTS_RTC_OSCIN] = &g12a_aoclk_cts_rtc_oscin.hw, +static struct clk_hw *g12a_ao_hw_clks[] = { + [CLKID_AO_AHB] = &g12a_ao_ahb.hw, + [CLKID_AO_IR_IN] = &g12a_ao_ir_in.hw, + [CLKID_AO_I2C_M0] = &g12a_ao_i2c_m0.hw, + [CLKID_AO_I2C_S0] = &g12a_ao_i2c_s0.hw, + [CLKID_AO_UART] = &g12a_ao_uart.hw, + [CLKID_AO_PROD_I2C] = &g12a_ao_prod_i2c.hw, + [CLKID_AO_UART2] = &g12a_ao_uart2.hw, + [CLKID_AO_IR_OUT] = &g12a_ao_ir_out.hw, + [CLKID_AO_SAR_ADC] = &g12a_ao_saradc.hw, + [CLKID_AO_MAILBOX] = &g12a_ao_mailbox.hw, + [CLKID_AO_M3] = &g12a_ao_m3.hw, + [CLKID_AO_AHB_SRAM] = &g12a_ao_ahb_sram.hw, + [CLKID_AO_RTI] = &g12a_ao_rti.hw, + [CLKID_AO_M4_FCLK] = &g12a_ao_m4_fclk.hw, + [CLKID_AO_M4_HCLK] = &g12a_ao_m4_hclk.hw, + [CLKID_AO_CLK81] = &g12a_ao_clk81.hw, + [CLKID_AO_SAR_ADC_SEL] = &g12a_ao_saradc_mux.hw, + [CLKID_AO_SAR_ADC_DIV] = &g12a_ao_saradc_div.hw, + [CLKID_AO_SAR_ADC_CLK] = &g12a_ao_saradc_gate.hw, + [CLKID_AO_CTS_OSCIN] = &g12a_ao_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &g12a_ao_32k_by_oscin_pre.hw, + [CLKID_AO_32K_DIV] = &g12a_ao_32k_by_oscin_div.hw, + [CLKID_AO_32K_SEL] = &g12a_ao_32k_by_oscin_sel.hw, + [CLKID_AO_32K] = &g12a_ao_32k_by_oscin.hw, + [CLKID_AO_CEC_PRE] = &g12a_ao_cec_pre.hw, + [CLKID_AO_CEC_DIV] = &g12a_ao_cec_div.hw, + [CLKID_AO_CEC_SEL] = &g12a_ao_cec_sel.hw, + [CLKID_AO_CEC] = &g12a_ao_cec.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &g12a_ao_cts_rtc_oscin.hw, }; -static const struct meson_aoclk_data g12a_aoclkc_data = { +static const struct meson_aoclk_data g12a_ao_clkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, - .num_reset = ARRAY_SIZE(g12a_aoclk_reset), - .reset = g12a_aoclk_reset, + .num_reset = ARRAY_SIZE(g12a_ao_reset), + .reset = g12a_ao_reset, .hw_clks = { - .hws = g12a_aoclk_hw_clks, - .num = ARRAY_SIZE(g12a_aoclk_hw_clks), + .hws = g12a_ao_hw_clks, + .num = ARRAY_SIZE(g12a_ao_hw_clks), }, }; -static const struct of_device_id g12a_aoclkc_match_table[] = { +static const struct of_device_id g12a_ao_clkc_match_table[] = { { .compatible = "amlogic,meson-g12a-aoclkc", - .data = &g12a_aoclkc_data, + .data = &g12a_ao_clkc_data, }, { } }; -MODULE_DEVICE_TABLE(of, g12a_aoclkc_match_table); +MODULE_DEVICE_TABLE(of, g12a_ao_clkc_match_table); -static struct platform_driver g12a_aoclkc_driver = { +static struct platform_driver g12a_ao_clkc_driver = { .probe = meson_aoclkc_probe, .driver = { .name = "g12a-aoclkc", - .of_match_table = g12a_aoclkc_match_table, + .of_match_table = g12a_ao_clkc_match_table, }, }; -module_platform_driver(g12a_aoclkc_driver); +module_platform_driver(g12a_ao_clkc_driver); MODULE_DESCRIPTION("Amlogic G12A Always-ON Clock Controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 66f0e817e416..7e2c0ce91964 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -386,6 +386,451 @@ static struct clk_fixed_factor g12b_sys1_pll_div16 = { }, }; +static const struct pll_mult_range g12a_gp0_pll_mult_range = { + .min = 125, + .max = 255, +}; + +/* + * Internal gp0 pll emulation configuration parameters + */ +static const struct reg_sequence g12a_gp0_pll_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL1, .def = 0x00000000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0x00000000 }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x48681c00 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0x33771290 }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x39272000 }, + { .reg = HHI_GP0_PLL_CNTL6, .def = 0x56540000 }, +}; + +static struct clk_regmap g12a_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .range = &g12a_gp0_pll_mult_range, + .init_regs = g12a_gp0_pll_init_regs, + .init_count = ARRAY_SIZE(g12a_gp0_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL0, + .shift = 16, + .width = 3, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_gp0_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap sm1_gp1_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_GP1_PLL_CNTL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp1_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + /* This clock feeds the DSU, avoid disabling it */ + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_regmap sm1_gp1_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP1_PLL_CNTL0, + .shift = 16, + .width = 3, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp1_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_gp1_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +/* + * Internal hifi pll emulation configuration parameters + */ +static const struct reg_sequence g12a_hifi_pll_init_regs[] = { + { .reg = HHI_HIFI_PLL_CNTL1, .def = 0x00000000 }, + { .reg = HHI_HIFI_PLL_CNTL2, .def = 0x00000000 }, + { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x6a285c00 }, + { .reg = HHI_HIFI_PLL_CNTL4, .def = 0x65771290 }, + { .reg = HHI_HIFI_PLL_CNTL5, .def = 0x39272000 }, + { .reg = HHI_HIFI_PLL_CNTL6, .def = 0x56540000 }, +}; + +static struct clk_regmap g12a_hifi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_HIFI_PLL_CNTL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .range = &g12a_gp0_pll_mult_range, + .init_regs = g12a_hifi_pll_init_regs, + .init_count = ARRAY_SIZE(g12a_hifi_pll_init_regs), + .flags = CLK_MESON_PLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HIFI_PLL_CNTL0, + .shift = 16, + .width = 2, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hifi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * The Meson G12A PCIE PLL is fined tuned to deliver a very precise + * 100MHz reference clock for the PCIe Analog PHY, and thus requires + * a strict register sequence to enable the PLL. + */ +static const struct reg_sequence g12a_pcie_pll_init_regs[] = { + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x20090496 }, + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x30090496 }, + { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x00000000 }, + { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001100 }, + { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x10058e00 }, + { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x000100c0 }, + { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000048 }, + { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000068, .delay_us = 20 }, + { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x008100c0, .delay_us = 10 }, + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x34090496 }, + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x14090496, .delay_us = 10 }, + { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001000 }, +}; + +/* Keep a single entry table for recalc/round_rate() ops */ +static const struct pll_params_table g12a_pcie_pll_table[] = { + PLL_PARAMS(150, 1), + {0, 0}, +}; + +static struct clk_regmap g12a_pcie_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_PCIE_PLL_CNTL1, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .table = g12a_pcie_pll_table, + .init_regs = g12a_pcie_pll_init_regs, + .init_count = ARRAY_SIZE(g12a_pcie_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco", + .ops = &meson_clk_pcie_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_pcie_pll_dco_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_pcie_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_pcie_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL0, + .shift = 16, + .width = 5, + .flags = CLK_DIVIDER_ROUND_CLOSEST | + CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ALLOW_ZERO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_pcie_pll_dco_div2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor g12a_pcie_pll = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_pll", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_pcie_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_HDMI_PLL_CNTL1, + .shift = 0, + .width = 16, + }, + .l = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 30, + .width = 1, + }, + .rst = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need + * NOCACHE to keep our view of the clock as accurate as possible + */ + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 18, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 20, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_pll_od2.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + static struct clk_fixed_factor g12a_fclk_div2_div = { .mult = 1, .div = 2, @@ -459,8 +904,158 @@ static struct clk_regmap g12a_fclk_div3 = { }, }; + +static struct clk_fixed_factor g12a_fclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 21, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div4_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 22, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div7_div = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div7_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div2p5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div2p5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div2p5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_mpll_50m_div = { + .mult = 1, + .div = 80, + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll_50m = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_FIX_PLL_CNTL3, + .mask = 0x1, + .shift = 5, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_mpll_50m_div.hw }, + }, + .num_parents = 2, + }, +}; + +static struct clk_fixed_factor g12a_mpll_prediv = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + /* Datasheet names this field as "premux0" */ -static struct clk_regmap g12a_cpu_clk_premux0 = { +static struct clk_regmap g12a_cpu_clk_dyn0_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL0, .mask = 0x3, @@ -480,8 +1075,53 @@ static struct clk_regmap g12a_cpu_clk_premux0 = { }, }; +/* Datasheet names this field as "mux0_divn_tcnt" */ +static struct clk_regmap g12a_cpu_clk_dyn0_div = { + .data = &(struct meson_clk_cpu_dyndiv_data){ + .div = { + .reg_off = HHI_SYS_CPU_CLK_CNTL0, + .shift = 4, + .width = 6, + }, + .dyn = { + .reg_off = HHI_SYS_CPU_CLK_CNTL0, + .shift = 26, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0_div", + .ops = &meson_clk_cpu_dyndiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "postmux0" */ +static struct clk_regmap g12a_cpu_clk_dyn0 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 2, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn0_sel.hw, + &g12a_cpu_clk_dyn0_div.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* Datasheet names this field as "premux1" */ -static struct clk_regmap g12a_cpu_clk_premux1 = { +static struct clk_regmap g12a_cpu_clk_dyn1_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL0, .mask = 0x3, @@ -501,53 +1141,8 @@ static struct clk_regmap g12a_cpu_clk_premux1 = { }, }; -/* Datasheet names this field as "mux0_divn_tcnt" */ -static struct clk_regmap g12a_cpu_clk_mux0_div = { - .data = &(struct meson_clk_cpu_dyndiv_data){ - .div = { - .reg_off = HHI_SYS_CPU_CLK_CNTL0, - .shift = 4, - .width = 6, - }, - .dyn = { - .reg_off = HHI_SYS_CPU_CLK_CNTL0, - .shift = 26, - .width = 1, - }, - }, - .hw.init = &(struct clk_init_data){ - .name = "cpu_clk_dyn0_div", - .ops = &meson_clk_cpu_dyndiv_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_cpu_clk_premux0.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -/* Datasheet names this field as "postmux0" */ -static struct clk_regmap g12a_cpu_clk_postmux0 = { - .data = &(struct clk_regmap_mux_data){ - .offset = HHI_SYS_CPU_CLK_CNTL0, - .mask = 0x1, - .shift = 2, - .flags = CLK_MUX_ROUND_CLOSEST, - }, - .hw.init = &(struct clk_init_data){ - .name = "cpu_clk_dyn0", - .ops = &clk_regmap_mux_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_cpu_clk_premux0.hw, - &g12a_cpu_clk_mux0_div.hw, - }, - .num_parents = 2, - .flags = CLK_SET_RATE_PARENT, - }, -}; - /* Datasheet names this field as "Mux1_divn_tcnt" */ -static struct clk_regmap g12a_cpu_clk_mux1_div = { +static struct clk_regmap g12a_cpu_clk_dyn1_div = { .data = &(struct clk_regmap_div_data){ .offset = HHI_SYS_CPU_CLK_CNTL0, .shift = 20, @@ -557,14 +1152,14 @@ static struct clk_regmap g12a_cpu_clk_mux1_div = { .name = "cpu_clk_dyn1_div", .ops = &clk_regmap_divider_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_cpu_clk_premux1.hw + &g12a_cpu_clk_dyn1_sel.hw }, .num_parents = 1, }, }; /* Datasheet names this field as "postmux1" */ -static struct clk_regmap g12a_cpu_clk_postmux1 = { +static struct clk_regmap g12a_cpu_clk_dyn1 = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL0, .mask = 0x1, @@ -574,8 +1169,8 @@ static struct clk_regmap g12a_cpu_clk_postmux1 = { .name = "cpu_clk_dyn1", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_cpu_clk_premux1.hw, - &g12a_cpu_clk_mux1_div.hw, + &g12a_cpu_clk_dyn1_sel.hw, + &g12a_cpu_clk_dyn1_div.hw, }, .num_parents = 2, /* This sub-tree is used a parking clock */ @@ -595,8 +1190,8 @@ static struct clk_regmap g12a_cpu_clk_dyn = { .name = "cpu_clk_dyn", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_cpu_clk_postmux0.hw, - &g12a_cpu_clk_postmux1.hw, + &g12a_cpu_clk_dyn0.hw, + &g12a_cpu_clk_dyn1.hw, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, @@ -644,7 +1239,7 @@ static struct clk_regmap g12b_cpu_clk = { }; /* Datasheet names this field as "premux0" */ -static struct clk_regmap g12b_cpub_clk_premux0 = { +static struct clk_regmap g12b_cpub_clk_dyn0_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPUB_CLK_CNTL, .mask = 0x3, @@ -665,7 +1260,7 @@ static struct clk_regmap g12b_cpub_clk_premux0 = { }; /* Datasheet names this field as "mux0_divn_tcnt" */ -static struct clk_regmap g12b_cpub_clk_mux0_div = { +static struct clk_regmap g12b_cpub_clk_dyn0_div = { .data = &(struct meson_clk_cpu_dyndiv_data){ .div = { .reg_off = HHI_SYS_CPUB_CLK_CNTL, @@ -682,7 +1277,7 @@ static struct clk_regmap g12b_cpub_clk_mux0_div = { .name = "cpub_clk_dyn0_div", .ops = &meson_clk_cpu_dyndiv_ops, .parent_hws = (const struct clk_hw *[]) { - &g12b_cpub_clk_premux0.hw + &g12b_cpub_clk_dyn0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -690,7 +1285,7 @@ static struct clk_regmap g12b_cpub_clk_mux0_div = { }; /* Datasheet names this field as "postmux0" */ -static struct clk_regmap g12b_cpub_clk_postmux0 = { +static struct clk_regmap g12b_cpub_clk_dyn0 = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPUB_CLK_CNTL, .mask = 0x1, @@ -701,8 +1296,8 @@ static struct clk_regmap g12b_cpub_clk_postmux0 = { .name = "cpub_clk_dyn0", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &g12b_cpub_clk_premux0.hw, - &g12b_cpub_clk_mux0_div.hw + &g12b_cpub_clk_dyn0_sel.hw, + &g12b_cpub_clk_dyn0_div.hw }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, @@ -710,7 +1305,7 @@ static struct clk_regmap g12b_cpub_clk_postmux0 = { }; /* Datasheet names this field as "premux1" */ -static struct clk_regmap g12b_cpub_clk_premux1 = { +static struct clk_regmap g12b_cpub_clk_dyn1_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPUB_CLK_CNTL, .mask = 0x3, @@ -731,7 +1326,7 @@ static struct clk_regmap g12b_cpub_clk_premux1 = { }; /* Datasheet names this field as "Mux1_divn_tcnt" */ -static struct clk_regmap g12b_cpub_clk_mux1_div = { +static struct clk_regmap g12b_cpub_clk_dyn1_div = { .data = &(struct clk_regmap_div_data){ .offset = HHI_SYS_CPUB_CLK_CNTL, .shift = 20, @@ -741,14 +1336,14 @@ static struct clk_regmap g12b_cpub_clk_mux1_div = { .name = "cpub_clk_dyn1_div", .ops = &clk_regmap_divider_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &g12b_cpub_clk_premux1.hw + &g12b_cpub_clk_dyn1_sel.hw }, .num_parents = 1, }, }; /* Datasheet names this field as "postmux1" */ -static struct clk_regmap g12b_cpub_clk_postmux1 = { +static struct clk_regmap g12b_cpub_clk_dyn1 = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPUB_CLK_CNTL, .mask = 0x1, @@ -758,8 +1353,8 @@ static struct clk_regmap g12b_cpub_clk_postmux1 = { .name = "cpub_clk_dyn1", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &g12b_cpub_clk_premux1.hw, - &g12b_cpub_clk_mux1_div.hw + &g12b_cpub_clk_dyn1_sel.hw, + &g12b_cpub_clk_dyn1_div.hw }, .num_parents = 2, /* This sub-tree is used a parking clock */ @@ -779,8 +1374,8 @@ static struct clk_regmap g12b_cpub_clk_dyn = { .name = "cpub_clk_dyn", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &g12b_cpub_clk_postmux0.hw, - &g12b_cpub_clk_postmux1.hw + &g12b_cpub_clk_dyn0.hw, + &g12b_cpub_clk_dyn1.hw }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, @@ -807,10 +1402,8 @@ static struct clk_regmap g12b_cpub_clk = { }, }; -static struct clk_regmap sm1_gp1_pll; - /* Datasheet names this field as "premux0" */ -static struct clk_regmap sm1_dsu_clk_premux0 = { +static struct clk_regmap sm1_dsu_clk_dyn0_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL5, .mask = 0x3, @@ -829,8 +1422,43 @@ static struct clk_regmap sm1_dsu_clk_premux0 = { }, }; +/* Datasheet names this field as "Mux0_divn_tcnt" */ +static struct clk_regmap sm1_dsu_clk_dyn0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL5, + .shift = 4, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk_dyn0_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_dsu_clk_dyn0_sel.hw + }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "postmux0" */ +static struct clk_regmap sm1_dsu_clk_dyn0 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL5, + .mask = 0x1, + .shift = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk_dyn0", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_dsu_clk_dyn0_sel.hw, + &sm1_dsu_clk_dyn0_div.hw, + }, + .num_parents = 2, + }, +}; + /* Datasheet names this field as "premux1" */ -static struct clk_regmap sm1_dsu_clk_premux1 = { +static struct clk_regmap sm1_dsu_clk_dyn1_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL5, .mask = 0x3, @@ -849,43 +1477,8 @@ static struct clk_regmap sm1_dsu_clk_premux1 = { }, }; -/* Datasheet names this field as "Mux0_divn_tcnt" */ -static struct clk_regmap sm1_dsu_clk_mux0_div = { - .data = &(struct clk_regmap_div_data){ - .offset = HHI_SYS_CPU_CLK_CNTL5, - .shift = 4, - .width = 6, - }, - .hw.init = &(struct clk_init_data){ - .name = "dsu_clk_dyn0_div", - .ops = &clk_regmap_divider_ro_ops, - .parent_hws = (const struct clk_hw *[]) { - &sm1_dsu_clk_premux0.hw - }, - .num_parents = 1, - }, -}; - -/* Datasheet names this field as "postmux0" */ -static struct clk_regmap sm1_dsu_clk_postmux0 = { - .data = &(struct clk_regmap_mux_data){ - .offset = HHI_SYS_CPU_CLK_CNTL5, - .mask = 0x1, - .shift = 2, - }, - .hw.init = &(struct clk_init_data){ - .name = "dsu_clk_dyn0", - .ops = &clk_regmap_mux_ro_ops, - .parent_hws = (const struct clk_hw *[]) { - &sm1_dsu_clk_premux0.hw, - &sm1_dsu_clk_mux0_div.hw, - }, - .num_parents = 2, - }, -}; - /* Datasheet names this field as "Mux1_divn_tcnt" */ -static struct clk_regmap sm1_dsu_clk_mux1_div = { +static struct clk_regmap sm1_dsu_clk_dyn1_div = { .data = &(struct clk_regmap_div_data){ .offset = HHI_SYS_CPU_CLK_CNTL5, .shift = 20, @@ -895,14 +1488,14 @@ static struct clk_regmap sm1_dsu_clk_mux1_div = { .name = "dsu_clk_dyn1_div", .ops = &clk_regmap_divider_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &sm1_dsu_clk_premux1.hw + &sm1_dsu_clk_dyn1_sel.hw }, .num_parents = 1, }, }; /* Datasheet names this field as "postmux1" */ -static struct clk_regmap sm1_dsu_clk_postmux1 = { +static struct clk_regmap sm1_dsu_clk_dyn1 = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL5, .mask = 0x1, @@ -912,8 +1505,8 @@ static struct clk_regmap sm1_dsu_clk_postmux1 = { .name = "dsu_clk_dyn1", .ops = &clk_regmap_mux_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &sm1_dsu_clk_premux1.hw, - &sm1_dsu_clk_mux1_div.hw, + &sm1_dsu_clk_dyn1_sel.hw, + &sm1_dsu_clk_dyn1_div.hw, }, .num_parents = 2, }, @@ -930,8 +1523,8 @@ static struct clk_regmap sm1_dsu_clk_dyn = { .name = "dsu_clk_dyn", .ops = &clk_regmap_mux_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &sm1_dsu_clk_postmux0.hw, - &sm1_dsu_clk_postmux1.hw, + &sm1_dsu_clk_dyn0.hw, + &sm1_dsu_clk_dyn1.hw, }, .num_parents = 2, }, @@ -1043,7 +1636,7 @@ static struct notifier_block g12a_cpu_clk_mux_nb = { .notifier_call = g12a_cpu_clk_mux_notifier_cb, }; -struct g12a_cpu_clk_postmux_nb_data { +struct g12a_cpu_clk_dyn_nb_data { struct notifier_block nb; struct clk_hw *xtal; struct clk_hw *cpu_clk_dyn; @@ -1052,33 +1645,33 @@ struct g12a_cpu_clk_postmux_nb_data { struct clk_hw *cpu_clk_premux1; }; -static int g12a_cpu_clk_postmux_notifier_cb(struct notifier_block *nb, - unsigned long event, void *data) +static int g12a_cpu_clk_dyn_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) { - struct g12a_cpu_clk_postmux_nb_data *nb_data = - container_of(nb, struct g12a_cpu_clk_postmux_nb_data, nb); + struct g12a_cpu_clk_dyn_nb_data *nb_data = + container_of(nb, struct g12a_cpu_clk_dyn_nb_data, nb); switch (event) { case PRE_RATE_CHANGE: /* - * This notifier means cpu_clk_postmux0 clock will be changed + * This notifier means cpu_clk_dyn0 clock will be changed * to feed cpu_clk, this is the current path : * cpu_clk * \- cpu_clk_dyn - * \- cpu_clk_postmux0 - * \- cpu_clk_muxX_div - * \- cpu_clk_premux0 + * \- cpu_clk_dyn0 + * \- cpu_clk_dyn0_div + * \- cpu_clk_dyn0_sel * \- fclk_div3 or fclk_div2 * OR - * \- cpu_clk_premux0 + * \- cpu_clk_dyn0_sel * \- fclk_div3 or fclk_div2 */ - /* Setup cpu_clk_premux1 to xtal */ + /* Setup cpu_clk_dyn1_sel to xtal */ clk_hw_set_parent(nb_data->cpu_clk_premux1, nb_data->xtal); - /* Setup cpu_clk_postmux1 to bypass divider */ + /* Setup cpu_clk_dyn1 to bypass divider */ clk_hw_set_parent(nb_data->cpu_clk_postmux1, nb_data->cpu_clk_premux1); @@ -1090,8 +1683,8 @@ static int g12a_cpu_clk_postmux_notifier_cb(struct notifier_block *nb, * Now, cpu_clk is 24MHz in the current path : * cpu_clk * \- cpu_clk_dyn - * \- cpu_clk_postmux1 - * \- cpu_clk_premux1 + * \- cpu_clk_dyn1 + * \- cpu_clk_dyn1_sel * \- xtal */ @@ -1101,8 +1694,8 @@ static int g12a_cpu_clk_postmux_notifier_cb(struct notifier_block *nb, case POST_RATE_CHANGE: /* - * The cpu_clk_postmux0 has ben updated, now switch back - * cpu_clk_dyn to cpu_clk_postmux0 and take the changes + * The cpu_clk_dyn0 has ben updated, now switch back + * cpu_clk_dyn to cpu_clk_dyn0 and take the changes * in account. */ @@ -1114,12 +1707,12 @@ static int g12a_cpu_clk_postmux_notifier_cb(struct notifier_block *nb, * new path : * cpu_clk * \- cpu_clk_dyn - * \- cpu_clk_postmux0 - * \- cpu_clk_muxX_div - * \- cpu_clk_premux0 + * \- cpu_clk_dyn0 + * \- cpu_clk_dyn0_div + * \- cpu_clk_dyn0_sel * \- fclk_div3 or fclk_div2 * OR - * \- cpu_clk_premux0 + * \- cpu_clk_dyn0_sel * \- fclk_div3 or fclk_div2 */ @@ -1132,20 +1725,20 @@ static int g12a_cpu_clk_postmux_notifier_cb(struct notifier_block *nb, } } -static struct g12a_cpu_clk_postmux_nb_data g12a_cpu_clk_postmux0_nb_data = { +static struct g12a_cpu_clk_dyn_nb_data g12a_cpu_clk_dyn0_nb_data = { .cpu_clk_dyn = &g12a_cpu_clk_dyn.hw, - .cpu_clk_postmux0 = &g12a_cpu_clk_postmux0.hw, - .cpu_clk_postmux1 = &g12a_cpu_clk_postmux1.hw, - .cpu_clk_premux1 = &g12a_cpu_clk_premux1.hw, - .nb.notifier_call = g12a_cpu_clk_postmux_notifier_cb, + .cpu_clk_postmux0 = &g12a_cpu_clk_dyn0.hw, + .cpu_clk_postmux1 = &g12a_cpu_clk_dyn1.hw, + .cpu_clk_premux1 = &g12a_cpu_clk_dyn1_sel.hw, + .nb.notifier_call = g12a_cpu_clk_dyn_notifier_cb, }; -static struct g12a_cpu_clk_postmux_nb_data g12b_cpub_clk_postmux0_nb_data = { +static struct g12a_cpu_clk_dyn_nb_data g12b_cpub_clk_dyn0_nb_data = { .cpu_clk_dyn = &g12b_cpub_clk_dyn.hw, - .cpu_clk_postmux0 = &g12b_cpub_clk_postmux0.hw, - .cpu_clk_postmux1 = &g12b_cpub_clk_postmux1.hw, - .cpu_clk_premux1 = &g12b_cpub_clk_premux1.hw, - .nb.notifier_call = g12a_cpu_clk_postmux_notifier_cb, + .cpu_clk_postmux0 = &g12b_cpub_clk_dyn0.hw, + .cpu_clk_postmux1 = &g12b_cpub_clk_dyn1.hw, + .cpu_clk_premux1 = &g12b_cpub_clk_dyn1_sel.hw, + .nb.notifier_call = g12a_cpu_clk_dyn_notifier_cb, }; struct g12a_sys_pll_nb_data { @@ -1551,27 +2144,29 @@ static struct clk_fixed_factor g12b_cpub_clk_div8 = { }, }; -static u32 mux_table_cpub[] = { 1, 2, 3, 4, 5, 6, 7 }; +static u32 g12b_cpub_clk_if_parents_val_table[] = { 1, 2, 3, 4, 5, 6, 7 }; +static const struct clk_hw *g12b_cpub_clk_if_parents[] = { + &g12b_cpub_clk_div2.hw, + &g12b_cpub_clk_div3.hw, + &g12b_cpub_clk_div4.hw, + &g12b_cpub_clk_div5.hw, + &g12b_cpub_clk_div6.hw, + &g12b_cpub_clk_div7.hw, + &g12b_cpub_clk_div8.hw, +}; + static struct clk_regmap g12b_cpub_clk_apb_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPUB_CLK_CNTL1, .mask = 7, .shift = 3, - .table = mux_table_cpub, + .table = g12b_cpub_clk_if_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk_apb_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12b_cpub_clk_div2.hw, - &g12b_cpub_clk_div3.hw, - &g12b_cpub_clk_div4.hw, - &g12b_cpub_clk_div5.hw, - &g12b_cpub_clk_div6.hw, - &g12b_cpub_clk_div7.hw, - &g12b_cpub_clk_div8.hw - }, - .num_parents = 7, + .parent_hws = g12b_cpub_clk_if_parents, + .num_parents = ARRAY_SIZE(g12b_cpub_clk_if_parents), }, }; @@ -1600,21 +2195,13 @@ static struct clk_regmap g12b_cpub_clk_atb_sel = { .offset = HHI_SYS_CPUB_CLK_CNTL1, .mask = 7, .shift = 6, - .table = mux_table_cpub, + .table = g12b_cpub_clk_if_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk_atb_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12b_cpub_clk_div2.hw, - &g12b_cpub_clk_div3.hw, - &g12b_cpub_clk_div4.hw, - &g12b_cpub_clk_div5.hw, - &g12b_cpub_clk_div6.hw, - &g12b_cpub_clk_div7.hw, - &g12b_cpub_clk_div8.hw - }, - .num_parents = 7, + .parent_hws = g12b_cpub_clk_if_parents, + .num_parents = ARRAY_SIZE(g12b_cpub_clk_if_parents), }, }; @@ -1643,21 +2230,13 @@ static struct clk_regmap g12b_cpub_clk_axi_sel = { .offset = HHI_SYS_CPUB_CLK_CNTL1, .mask = 7, .shift = 9, - .table = mux_table_cpub, + .table = g12b_cpub_clk_if_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk_axi_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12b_cpub_clk_div2.hw, - &g12b_cpub_clk_div3.hw, - &g12b_cpub_clk_div4.hw, - &g12b_cpub_clk_div5.hw, - &g12b_cpub_clk_div6.hw, - &g12b_cpub_clk_div7.hw, - &g12b_cpub_clk_div8.hw - }, - .num_parents = 7, + .parent_hws = g12b_cpub_clk_if_parents, + .num_parents = ARRAY_SIZE(g12b_cpub_clk_if_parents), }, }; @@ -1686,21 +2265,13 @@ static struct clk_regmap g12b_cpub_clk_trace_sel = { .offset = HHI_SYS_CPUB_CLK_CNTL1, .mask = 7, .shift = 20, - .table = mux_table_cpub, + .table = g12b_cpub_clk_if_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cpub_clk_trace_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12b_cpub_clk_div2.hw, - &g12b_cpub_clk_div3.hw, - &g12b_cpub_clk_div4.hw, - &g12b_cpub_clk_div5.hw, - &g12b_cpub_clk_div6.hw, - &g12b_cpub_clk_div7.hw, - &g12b_cpub_clk_div8.hw - }, - .num_parents = 7, + .parent_hws = g12b_cpub_clk_if_parents, + .num_parents = ARRAY_SIZE(g12b_cpub_clk_if_parents), }, }; @@ -1724,600 +2295,6 @@ static struct clk_regmap g12b_cpub_clk_trace = { }, }; -static const struct pll_mult_range g12a_gp0_pll_mult_range = { - .min = 125, - .max = 255, -}; - -/* - * Internal gp0 pll emulation configuration parameters - */ -static const struct reg_sequence g12a_gp0_init_regs[] = { - { .reg = HHI_GP0_PLL_CNTL1, .def = 0x00000000 }, - { .reg = HHI_GP0_PLL_CNTL2, .def = 0x00000000 }, - { .reg = HHI_GP0_PLL_CNTL3, .def = 0x48681c00 }, - { .reg = HHI_GP0_PLL_CNTL4, .def = 0x33771290 }, - { .reg = HHI_GP0_PLL_CNTL5, .def = 0x39272000 }, - { .reg = HHI_GP0_PLL_CNTL6, .def = 0x56540000 }, -}; - -static struct clk_regmap g12a_gp0_pll_dco = { - .data = &(struct meson_clk_pll_data){ - .en = { - .reg_off = HHI_GP0_PLL_CNTL0, - .shift = 28, - .width = 1, - }, - .m = { - .reg_off = HHI_GP0_PLL_CNTL0, - .shift = 0, - .width = 8, - }, - .n = { - .reg_off = HHI_GP0_PLL_CNTL0, - .shift = 10, - .width = 5, - }, - .frac = { - .reg_off = HHI_GP0_PLL_CNTL1, - .shift = 0, - .width = 17, - }, - .l = { - .reg_off = HHI_GP0_PLL_CNTL0, - .shift = 31, - .width = 1, - }, - .rst = { - .reg_off = HHI_GP0_PLL_CNTL0, - .shift = 29, - .width = 1, - }, - .range = &g12a_gp0_pll_mult_range, - .init_regs = g12a_gp0_init_regs, - .init_count = ARRAY_SIZE(g12a_gp0_init_regs), - }, - .hw.init = &(struct clk_init_data){ - .name = "gp0_pll_dco", - .ops = &meson_clk_pll_ops, - .parent_data = &(const struct clk_parent_data) { - .fw_name = "xtal", - }, - .num_parents = 1, - }, -}; - -static struct clk_regmap g12a_gp0_pll = { - .data = &(struct clk_regmap_div_data){ - .offset = HHI_GP0_PLL_CNTL0, - .shift = 16, - .width = 3, - .flags = (CLK_DIVIDER_POWER_OF_TWO | - CLK_DIVIDER_ROUND_CLOSEST), - }, - .hw.init = &(struct clk_init_data){ - .name = "gp0_pll", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_gp0_pll_dco.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap sm1_gp1_pll_dco = { - .data = &(struct meson_clk_pll_data){ - .en = { - .reg_off = HHI_GP1_PLL_CNTL0, - .shift = 28, - .width = 1, - }, - .m = { - .reg_off = HHI_GP1_PLL_CNTL0, - .shift = 0, - .width = 8, - }, - .n = { - .reg_off = HHI_GP1_PLL_CNTL0, - .shift = 10, - .width = 5, - }, - .frac = { - .reg_off = HHI_GP1_PLL_CNTL1, - .shift = 0, - .width = 17, - }, - .l = { - .reg_off = HHI_GP1_PLL_CNTL0, - .shift = 31, - .width = 1, - }, - .rst = { - .reg_off = HHI_GP1_PLL_CNTL0, - .shift = 29, - .width = 1, - }, - }, - .hw.init = &(struct clk_init_data){ - .name = "gp1_pll_dco", - .ops = &meson_clk_pll_ro_ops, - .parent_data = &(const struct clk_parent_data) { - .fw_name = "xtal", - }, - .num_parents = 1, - /* This clock feeds the DSU, avoid disabling it */ - .flags = CLK_IS_CRITICAL, - }, -}; - -static struct clk_regmap sm1_gp1_pll = { - .data = &(struct clk_regmap_div_data){ - .offset = HHI_GP1_PLL_CNTL0, - .shift = 16, - .width = 3, - .flags = (CLK_DIVIDER_POWER_OF_TWO | - CLK_DIVIDER_ROUND_CLOSEST), - }, - .hw.init = &(struct clk_init_data){ - .name = "gp1_pll", - .ops = &clk_regmap_divider_ro_ops, - .parent_hws = (const struct clk_hw *[]) { - &sm1_gp1_pll_dco.hw - }, - .num_parents = 1, - }, -}; - -/* - * Internal hifi pll emulation configuration parameters - */ -static const struct reg_sequence g12a_hifi_init_regs[] = { - { .reg = HHI_HIFI_PLL_CNTL1, .def = 0x00000000 }, - { .reg = HHI_HIFI_PLL_CNTL2, .def = 0x00000000 }, - { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x6a285c00 }, - { .reg = HHI_HIFI_PLL_CNTL4, .def = 0x65771290 }, - { .reg = HHI_HIFI_PLL_CNTL5, .def = 0x39272000 }, - { .reg = HHI_HIFI_PLL_CNTL6, .def = 0x56540000 }, -}; - -static struct clk_regmap g12a_hifi_pll_dco = { - .data = &(struct meson_clk_pll_data){ - .en = { - .reg_off = HHI_HIFI_PLL_CNTL0, - .shift = 28, - .width = 1, - }, - .m = { - .reg_off = HHI_HIFI_PLL_CNTL0, - .shift = 0, - .width = 8, - }, - .n = { - .reg_off = HHI_HIFI_PLL_CNTL0, - .shift = 10, - .width = 5, - }, - .frac = { - .reg_off = HHI_HIFI_PLL_CNTL1, - .shift = 0, - .width = 17, - }, - .l = { - .reg_off = HHI_HIFI_PLL_CNTL0, - .shift = 31, - .width = 1, - }, - .rst = { - .reg_off = HHI_HIFI_PLL_CNTL0, - .shift = 29, - .width = 1, - }, - .range = &g12a_gp0_pll_mult_range, - .init_regs = g12a_hifi_init_regs, - .init_count = ARRAY_SIZE(g12a_hifi_init_regs), - .flags = CLK_MESON_PLL_ROUND_CLOSEST, - }, - .hw.init = &(struct clk_init_data){ - .name = "hifi_pll_dco", - .ops = &meson_clk_pll_ops, - .parent_data = &(const struct clk_parent_data) { - .fw_name = "xtal", - }, - .num_parents = 1, - }, -}; - -static struct clk_regmap g12a_hifi_pll = { - .data = &(struct clk_regmap_div_data){ - .offset = HHI_HIFI_PLL_CNTL0, - .shift = 16, - .width = 2, - .flags = (CLK_DIVIDER_POWER_OF_TWO | - CLK_DIVIDER_ROUND_CLOSEST), - }, - .hw.init = &(struct clk_init_data){ - .name = "hifi_pll", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_hifi_pll_dco.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -/* - * The Meson G12A PCIE PLL is fined tuned to deliver a very precise - * 100MHz reference clock for the PCIe Analog PHY, and thus requires - * a strict register sequence to enable the PLL. - */ -static const struct reg_sequence g12a_pcie_pll_init_regs[] = { - { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x20090496 }, - { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x30090496 }, - { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x00000000 }, - { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001100 }, - { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x10058e00 }, - { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x000100c0 }, - { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000048 }, - { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000068, .delay_us = 20 }, - { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x008100c0, .delay_us = 10 }, - { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x34090496 }, - { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x14090496, .delay_us = 10 }, - { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001000 }, -}; - -/* Keep a single entry table for recalc/round_rate() ops */ -static const struct pll_params_table g12a_pcie_pll_table[] = { - PLL_PARAMS(150, 1), - {0, 0}, -}; - -static struct clk_regmap g12a_pcie_pll_dco = { - .data = &(struct meson_clk_pll_data){ - .en = { - .reg_off = HHI_PCIE_PLL_CNTL0, - .shift = 28, - .width = 1, - }, - .m = { - .reg_off = HHI_PCIE_PLL_CNTL0, - .shift = 0, - .width = 8, - }, - .n = { - .reg_off = HHI_PCIE_PLL_CNTL0, - .shift = 10, - .width = 5, - }, - .frac = { - .reg_off = HHI_PCIE_PLL_CNTL1, - .shift = 0, - .width = 12, - }, - .l = { - .reg_off = HHI_PCIE_PLL_CNTL0, - .shift = 31, - .width = 1, - }, - .rst = { - .reg_off = HHI_PCIE_PLL_CNTL0, - .shift = 29, - .width = 1, - }, - .table = g12a_pcie_pll_table, - .init_regs = g12a_pcie_pll_init_regs, - .init_count = ARRAY_SIZE(g12a_pcie_pll_init_regs), - }, - .hw.init = &(struct clk_init_data){ - .name = "pcie_pll_dco", - .ops = &meson_clk_pcie_pll_ops, - .parent_data = &(const struct clk_parent_data) { - .fw_name = "xtal", - }, - .num_parents = 1, - }, -}; - -static struct clk_fixed_factor g12a_pcie_pll_dco_div2 = { - .mult = 1, - .div = 2, - .hw.init = &(struct clk_init_data){ - .name = "pcie_pll_dco_div2", - .ops = &clk_fixed_factor_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_pcie_pll_dco.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap g12a_pcie_pll_od = { - .data = &(struct clk_regmap_div_data){ - .offset = HHI_PCIE_PLL_CNTL0, - .shift = 16, - .width = 5, - .flags = CLK_DIVIDER_ROUND_CLOSEST | - CLK_DIVIDER_ONE_BASED | - CLK_DIVIDER_ALLOW_ZERO, - }, - .hw.init = &(struct clk_init_data){ - .name = "pcie_pll_od", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_pcie_pll_dco_div2.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_fixed_factor g12a_pcie_pll = { - .mult = 1, - .div = 2, - .hw.init = &(struct clk_init_data){ - .name = "pcie_pll_pll", - .ops = &clk_fixed_factor_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_pcie_pll_od.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap g12a_hdmi_pll_dco = { - .data = &(struct meson_clk_pll_data){ - .en = { - .reg_off = HHI_HDMI_PLL_CNTL0, - .shift = 28, - .width = 1, - }, - .m = { - .reg_off = HHI_HDMI_PLL_CNTL0, - .shift = 0, - .width = 8, - }, - .n = { - .reg_off = HHI_HDMI_PLL_CNTL0, - .shift = 10, - .width = 5, - }, - .frac = { - .reg_off = HHI_HDMI_PLL_CNTL1, - .shift = 0, - .width = 16, - }, - .l = { - .reg_off = HHI_HDMI_PLL_CNTL0, - .shift = 30, - .width = 1, - }, - .rst = { - .reg_off = HHI_HDMI_PLL_CNTL0, - .shift = 29, - .width = 1, - }, - }, - .hw.init = &(struct clk_init_data){ - .name = "hdmi_pll_dco", - .ops = &meson_clk_pll_ro_ops, - .parent_data = &(const struct clk_parent_data) { - .fw_name = "xtal", - }, - .num_parents = 1, - /* - * Display directly handle hdmi pll registers ATM, we need - * NOCACHE to keep our view of the clock as accurate as possible - */ - .flags = CLK_GET_RATE_NOCACHE, - }, -}; - -static struct clk_regmap g12a_hdmi_pll_od = { - .data = &(struct clk_regmap_div_data){ - .offset = HHI_HDMI_PLL_CNTL0, - .shift = 16, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - }, - .hw.init = &(struct clk_init_data){ - .name = "hdmi_pll_od", - .ops = &clk_regmap_divider_ro_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_hdmi_pll_dco.hw - }, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap g12a_hdmi_pll_od2 = { - .data = &(struct clk_regmap_div_data){ - .offset = HHI_HDMI_PLL_CNTL0, - .shift = 18, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - }, - .hw.init = &(struct clk_init_data){ - .name = "hdmi_pll_od2", - .ops = &clk_regmap_divider_ro_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_hdmi_pll_od.hw - }, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap g12a_hdmi_pll = { - .data = &(struct clk_regmap_div_data){ - .offset = HHI_HDMI_PLL_CNTL0, - .shift = 20, - .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, - }, - .hw.init = &(struct clk_init_data){ - .name = "hdmi_pll", - .ops = &clk_regmap_divider_ro_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_hdmi_pll_od2.hw - }, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_fixed_factor g12a_fclk_div4_div = { - .mult = 1, - .div = 4, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div4_div", - .ops = &clk_fixed_factor_ops, - .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, - .num_parents = 1, - }, -}; - -static struct clk_regmap g12a_fclk_div4 = { - .data = &(struct clk_regmap_gate_data){ - .offset = HHI_FIX_PLL_CNTL1, - .bit_idx = 21, - }, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_fclk_div4_div.hw - }, - .num_parents = 1, - }, -}; - -static struct clk_fixed_factor g12a_fclk_div5_div = { - .mult = 1, - .div = 5, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div5_div", - .ops = &clk_fixed_factor_ops, - .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, - .num_parents = 1, - }, -}; - -static struct clk_regmap g12a_fclk_div5 = { - .data = &(struct clk_regmap_gate_data){ - .offset = HHI_FIX_PLL_CNTL1, - .bit_idx = 22, - }, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_fclk_div5_div.hw - }, - .num_parents = 1, - }, -}; - -static struct clk_fixed_factor g12a_fclk_div7_div = { - .mult = 1, - .div = 7, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div7_div", - .ops = &clk_fixed_factor_ops, - .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, - .num_parents = 1, - }, -}; - -static struct clk_regmap g12a_fclk_div7 = { - .data = &(struct clk_regmap_gate_data){ - .offset = HHI_FIX_PLL_CNTL1, - .bit_idx = 23, - }, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_fclk_div7_div.hw - }, - .num_parents = 1, - }, -}; - -static struct clk_fixed_factor g12a_fclk_div2p5_div = { - .mult = 1, - .div = 5, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div2p5_div", - .ops = &clk_fixed_factor_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_fixed_pll_dco.hw - }, - .num_parents = 1, - }, -}; - -static struct clk_regmap g12a_fclk_div2p5 = { - .data = &(struct clk_regmap_gate_data){ - .offset = HHI_FIX_PLL_CNTL1, - .bit_idx = 25, - }, - .hw.init = &(struct clk_init_data){ - .name = "fclk_div2p5", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_fclk_div2p5_div.hw - }, - .num_parents = 1, - }, -}; - -static struct clk_fixed_factor g12a_mpll_50m_div = { - .mult = 1, - .div = 80, - .hw.init = &(struct clk_init_data){ - .name = "mpll_50m_div", - .ops = &clk_fixed_factor_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_fixed_pll_dco.hw - }, - .num_parents = 1, - }, -}; - -static struct clk_regmap g12a_mpll_50m = { - .data = &(struct clk_regmap_mux_data){ - .offset = HHI_FIX_PLL_CNTL3, - .mask = 0x1, - .shift = 5, - }, - .hw.init = &(struct clk_init_data){ - .name = "mpll_50m", - .ops = &clk_regmap_mux_ro_ops, - .parent_data = (const struct clk_parent_data []) { - { .fw_name = "xtal", }, - { .hw = &g12a_mpll_50m_div.hw }, - }, - .num_parents = 2, - }, -}; - -static struct clk_fixed_factor g12a_mpll_prediv = { - .mult = 1, - .div = 2, - .hw.init = &(struct clk_init_data){ - .name = "mpll_prediv", - .ops = &clk_fixed_factor_ops, - .parent_hws = (const struct clk_hw *[]) { - &g12a_fixed_pll_dco.hw - }, - .num_parents = 1, - }, -}; - static const struct reg_sequence g12a_mpll0_init_regs[] = { { .reg = HHI_MPLL_CNTL2, .def = 0x40000033 }, }; @@ -2530,8 +2507,9 @@ static struct clk_regmap g12a_mpll3 = { }, }; -static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; -static const struct clk_parent_data clk81_parent_data[] = { +/* clk81 is often referred as "mpeg_clk" */ +static u32 g12a_clk81_parents_val_table[] = { 0, 2, 3, 4, 5, 6, 7 }; +static const struct clk_parent_data g12a_clk81_parents[] = { { .fw_name = "xtal", }, { .hw = &g12a_fclk_div7.hw }, { .hw = &g12a_mpll1.hw }, @@ -2541,32 +2519,32 @@ static const struct clk_parent_data clk81_parent_data[] = { { .hw = &g12a_fclk_div5.hw }, }; -static struct clk_regmap g12a_mpeg_clk_sel = { +static struct clk_regmap g12a_clk81_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_MPEG_CLK_CNTL, .mask = 0x7, .shift = 12, - .table = mux_table_clk81, + .table = g12a_clk81_parents_val_table, }, .hw.init = &(struct clk_init_data){ - .name = "mpeg_clk_sel", + .name = "clk81_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_data = clk81_parent_data, - .num_parents = ARRAY_SIZE(clk81_parent_data), + .parent_data = g12a_clk81_parents, + .num_parents = ARRAY_SIZE(g12a_clk81_parents), }, }; -static struct clk_regmap g12a_mpeg_clk_div = { +static struct clk_regmap g12a_clk81_div = { .data = &(struct clk_regmap_div_data){ .offset = HHI_MPEG_CLK_CNTL, .shift = 0, .width = 7, }, .hw.init = &(struct clk_init_data){ - .name = "mpeg_clk_div", + .name = "clk81_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_mpeg_clk_sel.hw + &g12a_clk81_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -2582,14 +2560,14 @@ static struct clk_regmap g12a_clk81 = { .name = "clk81", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &g12a_mpeg_clk_div.hw + &g12a_clk81_div.hw }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), }, }; -static const struct clk_parent_data g12a_sd_emmc_clk0_parent_data[] = { +static const struct clk_parent_data g12a_sd_emmc_clk0_parents[] = { { .fw_name = "xtal", }, { .hw = &g12a_fclk_div2.hw }, { .hw = &g12a_fclk_div3.hw }, @@ -2613,8 +2591,8 @@ static struct clk_regmap g12a_sd_emmc_a_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = g12a_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_data), + .parent_data = g12a_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2662,8 +2640,8 @@ static struct clk_regmap g12a_sd_emmc_b_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = g12a_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_data), + .parent_data = g12a_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2711,8 +2689,8 @@ static struct clk_regmap g12a_sd_emmc_c_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = g12a_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_data), + .parent_data = g12a_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2774,7 +2752,7 @@ static struct clk_regmap g12a_vid_pll_div = { }, }; -static const struct clk_hw *g12a_vid_pll_parent_hws[] = { +static const struct clk_hw *g12a_vid_pll_parents[] = { &g12a_vid_pll_div.hw, &g12a_hdmi_pll.hw, }; @@ -2792,8 +2770,8 @@ static struct clk_regmap g12a_vid_pll_sel = { * bit 18 selects from 2 possible parents: * vid_pll_div or hdmi_pll */ - .parent_hws = g12a_vid_pll_parent_hws, - .num_parents = ARRAY_SIZE(g12a_vid_pll_parent_hws), + .parent_hws = g12a_vid_pll_parents, + .num_parents = ARRAY_SIZE(g12a_vid_pll_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2816,7 +2794,7 @@ static struct clk_regmap g12a_vid_pll = { /* VPU Clock */ -static const struct clk_hw *g12a_vpu_parent_hws[] = { +static const struct clk_hw *g12a_vpu_parents[] = { &g12a_fclk_div3.hw, &g12a_fclk_div4.hw, &g12a_fclk_div5.hw, @@ -2836,8 +2814,8 @@ static struct clk_regmap g12a_vpu_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_vpu_parent_hws, - .num_parents = ARRAY_SIZE(g12a_vpu_parent_hws), + .parent_hws = g12a_vpu_parents, + .num_parents = ARRAY_SIZE(g12a_vpu_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -2880,8 +2858,8 @@ static struct clk_regmap g12a_vpu_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_vpu_parent_hws, - .num_parents = ARRAY_SIZE(g12a_vpu_parent_hws), + .parent_hws = g12a_vpu_parents, + .num_parents = ARRAY_SIZE(g12a_vpu_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -2939,7 +2917,7 @@ static struct clk_regmap g12a_vpu = { /* VDEC clocks */ -static const struct clk_hw *g12a_vdec_parent_hws[] = { +static const struct clk_hw *g12a_vdec_parents[] = { &g12a_fclk_div2p5.hw, &g12a_fclk_div3.hw, &g12a_fclk_div4.hw, @@ -2959,8 +2937,8 @@ static struct clk_regmap g12a_vdec_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_1_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_vdec_parent_hws, - .num_parents = ARRAY_SIZE(g12a_vdec_parent_hws), + .parent_hws = g12a_vdec_parents, + .num_parents = ARRAY_SIZE(g12a_vdec_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -3009,8 +2987,8 @@ static struct clk_regmap g12a_vdec_hevcf_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevcf_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_vdec_parent_hws, - .num_parents = ARRAY_SIZE(g12a_vdec_parent_hws), + .parent_hws = g12a_vdec_parents, + .num_parents = ARRAY_SIZE(g12a_vdec_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -3059,8 +3037,8 @@ static struct clk_regmap g12a_vdec_hevc_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevc_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_vdec_parent_hws, - .num_parents = ARRAY_SIZE(g12a_vdec_parent_hws), + .parent_hws = g12a_vdec_parents, + .num_parents = ARRAY_SIZE(g12a_vdec_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -3101,7 +3079,7 @@ static struct clk_regmap g12a_vdec_hevc = { /* VAPB Clock */ -static const struct clk_hw *g12a_vapb_parent_hws[] = { +static const struct clk_hw *g12a_vapb_parents[] = { &g12a_fclk_div4.hw, &g12a_fclk_div3.hw, &g12a_fclk_div5.hw, @@ -3121,8 +3099,8 @@ static struct clk_regmap g12a_vapb_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vapb_0_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_vapb_parent_hws, - .num_parents = ARRAY_SIZE(g12a_vapb_parent_hws), + .parent_hws = g12a_vapb_parents, + .num_parents = ARRAY_SIZE(g12a_vapb_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -3169,8 +3147,8 @@ static struct clk_regmap g12a_vapb_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vapb_1_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_vapb_parent_hws, - .num_parents = ARRAY_SIZE(g12a_vapb_parent_hws), + .parent_hws = g12a_vapb_parents, + .num_parents = ARRAY_SIZE(g12a_vapb_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -3244,7 +3222,7 @@ static struct clk_regmap g12a_vapb = { }, }; -static const struct clk_hw *g12a_vclk_parent_hws[] = { +static const struct clk_hw *g12a_vclk_parents[] = { &g12a_vid_pll.hw, &g12a_gp0_pll.hw, &g12a_hifi_pll.hw, @@ -3264,8 +3242,8 @@ static struct clk_regmap g12a_vclk_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_vclk_parent_hws, - .num_parents = ARRAY_SIZE(g12a_vclk_parent_hws), + .parent_hws = g12a_vclk_parents, + .num_parents = ARRAY_SIZE(g12a_vclk_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -3279,8 +3257,8 @@ static struct clk_regmap g12a_vclk2_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk2_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_vclk_parent_hws, - .num_parents = ARRAY_SIZE(g12a_vclk_parent_hws), + .parent_hws = g12a_vclk_parents, + .num_parents = ARRAY_SIZE(g12a_vclk_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -3643,8 +3621,8 @@ static struct clk_fixed_factor g12a_vclk2_div12 = { }, }; -static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const struct clk_hw *g12a_cts_parent_hws[] = { +static u32 g12a_cts_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *g12a_cts_parents[] = { &g12a_vclk_div1.hw, &g12a_vclk_div2.hw, &g12a_vclk_div4.hw, @@ -3662,13 +3640,13 @@ static struct clk_regmap g12a_cts_enci_sel = { .offset = HHI_VID_CLK_DIV, .mask = 0xf, .shift = 28, - .table = mux_table_cts_sel, + .table = g12a_cts_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_enci_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_cts_parent_hws, - .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), + .parent_hws = g12a_cts_parents, + .num_parents = ARRAY_SIZE(g12a_cts_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -3678,13 +3656,13 @@ static struct clk_regmap g12a_cts_encp_sel = { .offset = HHI_VID_CLK_DIV, .mask = 0xf, .shift = 20, - .table = mux_table_cts_sel, + .table = g12a_cts_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_encp_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_cts_parent_hws, - .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), + .parent_hws = g12a_cts_parents, + .num_parents = ARRAY_SIZE(g12a_cts_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -3694,13 +3672,13 @@ static struct clk_regmap g12a_cts_encl_sel = { .offset = HHI_VIID_CLK_DIV, .mask = 0xf, .shift = 12, - .table = mux_table_cts_sel, + .table = g12a_cts_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_encl_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_cts_parent_hws, - .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), + .parent_hws = g12a_cts_parents, + .num_parents = ARRAY_SIZE(g12a_cts_parents), .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, }, }; @@ -3710,20 +3688,20 @@ static struct clk_regmap g12a_cts_vdac_sel = { .offset = HHI_VIID_CLK_DIV, .mask = 0xf, .shift = 28, - .table = mux_table_cts_sel, + .table = g12a_cts_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_vdac_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_cts_parent_hws, - .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), + .parent_hws = g12a_cts_parents, + .num_parents = ARRAY_SIZE(g12a_cts_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; /* TOFIX: add support for cts_tcon */ -static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const struct clk_hw *g12a_cts_hdmi_tx_parent_hws[] = { +static u32 g12a_hdmi_tx_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *g12a_hdmi_tx_parents[] = { &g12a_vclk_div1.hw, &g12a_vclk_div2.hw, &g12a_vclk_div4.hw, @@ -3741,13 +3719,13 @@ static struct clk_regmap g12a_hdmi_tx_sel = { .offset = HHI_HDMI_CLK_CNTL, .mask = 0xf, .shift = 16, - .table = mux_table_hdmi_tx_sel, + .table = g12a_hdmi_tx_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "hdmi_tx_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_cts_hdmi_tx_parent_hws, - .num_parents = ARRAY_SIZE(g12a_cts_hdmi_tx_parent_hws), + .parent_hws = g12a_hdmi_tx_parents, + .num_parents = ARRAY_SIZE(g12a_hdmi_tx_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -3834,7 +3812,7 @@ static struct clk_regmap g12a_hdmi_tx = { /* MIPI DSI Host Clocks */ -static const struct clk_hw *g12a_mipi_dsi_pxclk_parent_hws[] = { +static const struct clk_hw *g12a_mipi_dsi_pxclk_parents[] = { &g12a_vid_pll.hw, &g12a_gp0_pll.hw, &g12a_hifi_pll.hw, @@ -3855,8 +3833,8 @@ static struct clk_regmap g12a_mipi_dsi_pxclk_sel = { .hw.init = &(struct clk_init_data){ .name = "mipi_dsi_pxclk_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_mipi_dsi_pxclk_parent_hws, - .num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parent_hws), + .parent_hws = g12a_mipi_dsi_pxclk_parents, + .num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, }, }; @@ -3907,7 +3885,7 @@ static struct clk_regmap g12a_mipi_dsi_pxclk = { /* MIPI ISP Clocks */ -static const struct clk_parent_data g12b_mipi_isp_parent_data[] = { +static const struct clk_parent_data g12b_mipi_isp_parents[] = { { .fw_name = "xtal", }, { .hw = &g12a_gp0_pll.hw }, { .hw = &g12a_hifi_pll.hw }, @@ -3927,8 +3905,8 @@ static struct clk_regmap g12b_mipi_isp_sel = { .hw.init = &(struct clk_init_data){ .name = "mipi_isp_sel", .ops = &clk_regmap_mux_ops, - .parent_data = g12b_mipi_isp_parent_data, - .num_parents = ARRAY_SIZE(g12b_mipi_isp_parent_data), + .parent_data = g12b_mipi_isp_parents, + .num_parents = ARRAY_SIZE(g12b_mipi_isp_parents), }, }; @@ -3967,7 +3945,7 @@ static struct clk_regmap g12b_mipi_isp = { /* HDMI Clocks */ -static const struct clk_parent_data g12a_hdmi_parent_data[] = { +static const struct clk_parent_data g12a_hdmi_parents[] = { { .fw_name = "xtal", }, { .hw = &g12a_fclk_div4.hw }, { .hw = &g12a_fclk_div3.hw }, @@ -3984,8 +3962,8 @@ static struct clk_regmap g12a_hdmi_sel = { .hw.init = &(struct clk_init_data){ .name = "hdmi_sel", .ops = &clk_regmap_mux_ops, - .parent_data = g12a_hdmi_parent_data, - .num_parents = ARRAY_SIZE(g12a_hdmi_parent_data), + .parent_data = g12a_hdmi_parents, + .num_parents = ARRAY_SIZE(g12a_hdmi_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -4025,7 +4003,7 @@ static struct clk_regmap g12a_hdmi = { * mux because it does top-to-bottom updates the each clock tree and * switches to the "inactive" one when CLK_SET_RATE_GATE is set. */ -static const struct clk_parent_data g12a_mali_0_1_parent_data[] = { +static const struct clk_parent_data g12a_mali_parents[] = { { .fw_name = "xtal", }, { .hw = &g12a_gp0_pll.hw }, { .hw = &g12a_hifi_pll.hw }, @@ -4045,8 +4023,8 @@ static struct clk_regmap g12a_mali_0_sel = { .hw.init = &(struct clk_init_data){ .name = "mali_0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = g12a_mali_0_1_parent_data, - .num_parents = 8, + .parent_data = g12a_mali_parents, + .num_parents = ARRAY_SIZE(g12a_mali_parents), /* * Don't request the parent to change the rate because * all GPU frequencies can be derived from the fclk_* @@ -4099,8 +4077,8 @@ static struct clk_regmap g12a_mali_1_sel = { .hw.init = &(struct clk_init_data){ .name = "mali_1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = g12a_mali_0_1_parent_data, - .num_parents = 8, + .parent_data = g12a_mali_parents, + .num_parents = ARRAY_SIZE(g12a_mali_parents), /* * Don't request the parent to change the rate because * all GPU frequencies can be derived from the fclk_* @@ -4144,11 +4122,6 @@ static struct clk_regmap g12a_mali_1 = { }, }; -static const struct clk_hw *g12a_mali_parent_hws[] = { - &g12a_mali_0.hw, - &g12a_mali_1.hw, -}; - static struct clk_regmap g12a_mali = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_MALI_CLK_CNTL, @@ -4158,7 +4131,10 @@ static struct clk_regmap g12a_mali = { .hw.init = &(struct clk_init_data){ .name = "mali", .ops = &clk_regmap_mux_ops, - .parent_hws = g12a_mali_parent_hws, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mali_0.hw, + &g12a_mali_1.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -4197,7 +4173,7 @@ static struct clk_regmap g12a_ts = { /* SPICC SCLK source clock */ -static const struct clk_parent_data spicc_sclk_parent_data[] = { +static const struct clk_parent_data g12a_spicc_sclk_parents[] = { { .fw_name = "xtal", }, { .hw = &g12a_clk81.hw }, { .hw = &g12a_fclk_div4.hw }, @@ -4216,8 +4192,8 @@ static struct clk_regmap g12a_spicc0_sclk_sel = { .hw.init = &(struct clk_init_data){ .name = "spicc0_sclk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = spicc_sclk_parent_data, - .num_parents = ARRAY_SIZE(spicc_sclk_parent_data), + .parent_data = g12a_spicc_sclk_parents, + .num_parents = ARRAY_SIZE(g12a_spicc_sclk_parents), }, }; @@ -4263,8 +4239,8 @@ static struct clk_regmap g12a_spicc1_sclk_sel = { .hw.init = &(struct clk_init_data){ .name = "spicc1_sclk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = spicc_sclk_parent_data, - .num_parents = ARRAY_SIZE(spicc_sclk_parent_data), + .parent_data = g12a_spicc_sclk_parents, + .num_parents = ARRAY_SIZE(g12a_spicc_sclk_parents), }, }; @@ -4303,7 +4279,7 @@ static struct clk_regmap g12a_spicc1_sclk = { /* Neural Network Accelerator source clock */ -static const struct clk_parent_data nna_clk_parent_data[] = { +static const struct clk_parent_data sm1_nna_clk_parents[] = { { .fw_name = "xtal", }, { .hw = &g12a_gp0_pll.hw, }, { .hw = &g12a_hifi_pll.hw, }, @@ -4323,8 +4299,8 @@ static struct clk_regmap sm1_nna_axi_clk_sel = { .hw.init = &(struct clk_init_data){ .name = "nna_axi_clk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = nna_clk_parent_data, - .num_parents = ARRAY_SIZE(nna_clk_parent_data), + .parent_data = sm1_nna_clk_parents, + .num_parents = ARRAY_SIZE(sm1_nna_clk_parents), }, }; @@ -4370,8 +4346,8 @@ static struct clk_regmap sm1_nna_core_clk_sel = { .hw.init = &(struct clk_init_data){ .name = "nna_core_clk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = nna_clk_parent_data, - .num_parents = ARRAY_SIZE(nna_clk_parent_data), + .parent_data = sm1_nna_clk_parents, + .num_parents = ARRAY_SIZE(sm1_nna_clk_parents), }, }; @@ -4408,89 +4384,89 @@ static struct clk_regmap sm1_nna_core_clk = { }, }; -#define MESON_GATE(_name, _reg, _bit) \ +#define G12A_PCLK(_name, _reg, _bit) \ MESON_PCLK(_name, _reg, _bit, &g12a_clk81.hw) -#define MESON_GATE_RO(_name, _reg, _bit) \ +#define G12A_PCLK_RO(_name, _reg, _bit) \ MESON_PCLK_RO(_name, _reg, _bit, &g12a_clk81.hw) /* Everything Else (EE) domain gates */ -static MESON_GATE(g12a_ddr, HHI_GCLK_MPEG0, 0); -static MESON_GATE(g12a_dos, HHI_GCLK_MPEG0, 1); -static MESON_GATE(g12a_audio_locker, HHI_GCLK_MPEG0, 2); -static MESON_GATE(g12a_mipi_dsi_host, HHI_GCLK_MPEG0, 3); -static MESON_GATE(g12a_eth_phy, HHI_GCLK_MPEG0, 4); -static MESON_GATE(g12a_isa, HHI_GCLK_MPEG0, 5); -static MESON_GATE(g12a_pl301, HHI_GCLK_MPEG0, 6); -static MESON_GATE(g12a_periphs, HHI_GCLK_MPEG0, 7); -static MESON_GATE(g12a_spicc_0, HHI_GCLK_MPEG0, 8); -static MESON_GATE(g12a_i2c, HHI_GCLK_MPEG0, 9); -static MESON_GATE(g12a_sana, HHI_GCLK_MPEG0, 10); -static MESON_GATE(g12a_sd, HHI_GCLK_MPEG0, 11); -static MESON_GATE(g12a_rng0, HHI_GCLK_MPEG0, 12); -static MESON_GATE(g12a_uart0, HHI_GCLK_MPEG0, 13); -static MESON_GATE(g12a_spicc_1, HHI_GCLK_MPEG0, 14); -static MESON_GATE(g12a_hiu_reg, HHI_GCLK_MPEG0, 19); -static MESON_GATE(g12a_mipi_dsi_phy, HHI_GCLK_MPEG0, 20); -static MESON_GATE(g12a_assist_misc, HHI_GCLK_MPEG0, 23); -static MESON_GATE(g12a_emmc_a, HHI_GCLK_MPEG0, 24); -static MESON_GATE(g12a_emmc_b, HHI_GCLK_MPEG0, 25); -static MESON_GATE(g12a_emmc_c, HHI_GCLK_MPEG0, 26); -static MESON_GATE(g12a_audio_codec, HHI_GCLK_MPEG0, 28); +static G12A_PCLK(g12a_ddr, HHI_GCLK_MPEG0, 0); +static G12A_PCLK(g12a_dos, HHI_GCLK_MPEG0, 1); +static G12A_PCLK(g12a_audio_locker, HHI_GCLK_MPEG0, 2); +static G12A_PCLK(g12a_mipi_dsi_host, HHI_GCLK_MPEG0, 3); +static G12A_PCLK(g12a_eth_phy, HHI_GCLK_MPEG0, 4); +static G12A_PCLK(g12a_isa, HHI_GCLK_MPEG0, 5); +static G12A_PCLK(g12a_pl301, HHI_GCLK_MPEG0, 6); +static G12A_PCLK(g12a_periphs, HHI_GCLK_MPEG0, 7); +static G12A_PCLK(g12a_spicc_0, HHI_GCLK_MPEG0, 8); +static G12A_PCLK(g12a_i2c, HHI_GCLK_MPEG0, 9); +static G12A_PCLK(g12a_sana, HHI_GCLK_MPEG0, 10); +static G12A_PCLK(g12a_sd, HHI_GCLK_MPEG0, 11); +static G12A_PCLK(g12a_rng0, HHI_GCLK_MPEG0, 12); +static G12A_PCLK(g12a_uart0, HHI_GCLK_MPEG0, 13); +static G12A_PCLK(g12a_spicc_1, HHI_GCLK_MPEG0, 14); +static G12A_PCLK(g12a_hiu_reg, HHI_GCLK_MPEG0, 19); +static G12A_PCLK(g12a_mipi_dsi_phy, HHI_GCLK_MPEG0, 20); +static G12A_PCLK(g12a_assist_misc, HHI_GCLK_MPEG0, 23); +static G12A_PCLK(g12a_emmc_a, HHI_GCLK_MPEG0, 24); +static G12A_PCLK(g12a_emmc_b, HHI_GCLK_MPEG0, 25); +static G12A_PCLK(g12a_emmc_c, HHI_GCLK_MPEG0, 26); +static G12A_PCLK(g12a_audio_codec, HHI_GCLK_MPEG0, 28); -static MESON_GATE(g12a_audio, HHI_GCLK_MPEG1, 0); -static MESON_GATE(g12a_eth_core, HHI_GCLK_MPEG1, 3); -static MESON_GATE(g12a_demux, HHI_GCLK_MPEG1, 4); -static MESON_GATE(g12a_audio_ififo, HHI_GCLK_MPEG1, 11); -static MESON_GATE(g12a_adc, HHI_GCLK_MPEG1, 13); -static MESON_GATE(g12a_uart1, HHI_GCLK_MPEG1, 16); -static MESON_GATE(g12a_g2d, HHI_GCLK_MPEG1, 20); -static MESON_GATE(g12a_reset, HHI_GCLK_MPEG1, 23); -static MESON_GATE(g12a_pcie_comb, HHI_GCLK_MPEG1, 24); -static MESON_GATE(g12a_parser, HHI_GCLK_MPEG1, 25); -static MESON_GATE(g12a_usb_general, HHI_GCLK_MPEG1, 26); -static MESON_GATE(g12a_pcie_phy, HHI_GCLK_MPEG1, 27); -static MESON_GATE(g12a_ahb_arb0, HHI_GCLK_MPEG1, 29); +static G12A_PCLK(g12a_audio, HHI_GCLK_MPEG1, 0); +static G12A_PCLK(g12a_eth_core, HHI_GCLK_MPEG1, 3); +static G12A_PCLK(g12a_demux, HHI_GCLK_MPEG1, 4); +static G12A_PCLK(g12a_audio_ififo, HHI_GCLK_MPEG1, 11); +static G12A_PCLK(g12a_adc, HHI_GCLK_MPEG1, 13); +static G12A_PCLK(g12a_uart1, HHI_GCLK_MPEG1, 16); +static G12A_PCLK(g12a_g2d, HHI_GCLK_MPEG1, 20); +static G12A_PCLK(g12a_reset, HHI_GCLK_MPEG1, 23); +static G12A_PCLK(g12a_pcie_comb, HHI_GCLK_MPEG1, 24); +static G12A_PCLK(g12a_parser, HHI_GCLK_MPEG1, 25); +static G12A_PCLK(g12a_usb_general, HHI_GCLK_MPEG1, 26); +static G12A_PCLK(g12a_pcie_phy, HHI_GCLK_MPEG1, 27); +static G12A_PCLK(g12a_ahb_arb0, HHI_GCLK_MPEG1, 29); -static MESON_GATE(g12a_ahb_data_bus, HHI_GCLK_MPEG2, 1); -static MESON_GATE(g12a_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); -static MESON_GATE(g12a_htx_hdcp22, HHI_GCLK_MPEG2, 3); -static MESON_GATE(g12a_htx_pclk, HHI_GCLK_MPEG2, 4); -static MESON_GATE(g12a_bt656, HHI_GCLK_MPEG2, 6); -static MESON_GATE(g12a_usb1_to_ddr, HHI_GCLK_MPEG2, 8); -static MESON_GATE(g12b_mipi_isp_gate, HHI_GCLK_MPEG2, 17); -static MESON_GATE(g12a_mmc_pclk, HHI_GCLK_MPEG2, 11); -static MESON_GATE(g12a_uart2, HHI_GCLK_MPEG2, 15); -static MESON_GATE(g12a_vpu_intr, HHI_GCLK_MPEG2, 25); -static MESON_GATE(g12b_csi_phy1, HHI_GCLK_MPEG2, 28); -static MESON_GATE(g12b_csi_phy0, HHI_GCLK_MPEG2, 29); -static MESON_GATE(g12a_gic, HHI_GCLK_MPEG2, 30); +static G12A_PCLK(g12a_ahb_data_bus, HHI_GCLK_MPEG2, 1); +static G12A_PCLK(g12a_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static G12A_PCLK(g12a_htx_hdcp22, HHI_GCLK_MPEG2, 3); +static G12A_PCLK(g12a_htx_pclk, HHI_GCLK_MPEG2, 4); +static G12A_PCLK(g12a_bt656, HHI_GCLK_MPEG2, 6); +static G12A_PCLK(g12a_usb1_to_ddr, HHI_GCLK_MPEG2, 8); +static G12A_PCLK(g12b_mipi_isp_gate, HHI_GCLK_MPEG2, 17); +static G12A_PCLK(g12a_mmc_pclk, HHI_GCLK_MPEG2, 11); +static G12A_PCLK(g12a_uart2, HHI_GCLK_MPEG2, 15); +static G12A_PCLK(g12a_vpu_intr, HHI_GCLK_MPEG2, 25); +static G12A_PCLK(g12b_csi_phy1, HHI_GCLK_MPEG2, 28); +static G12A_PCLK(g12b_csi_phy0, HHI_GCLK_MPEG2, 29); +static G12A_PCLK(g12a_gic, HHI_GCLK_MPEG2, 30); -static MESON_GATE(g12a_vclk2_venci0, HHI_GCLK_OTHER, 1); -static MESON_GATE(g12a_vclk2_venci1, HHI_GCLK_OTHER, 2); -static MESON_GATE(g12a_vclk2_vencp0, HHI_GCLK_OTHER, 3); -static MESON_GATE(g12a_vclk2_vencp1, HHI_GCLK_OTHER, 4); -static MESON_GATE(g12a_vclk2_venct0, HHI_GCLK_OTHER, 5); -static MESON_GATE(g12a_vclk2_venct1, HHI_GCLK_OTHER, 6); -static MESON_GATE(g12a_vclk2_other, HHI_GCLK_OTHER, 7); -static MESON_GATE(g12a_vclk2_enci, HHI_GCLK_OTHER, 8); -static MESON_GATE(g12a_vclk2_encp, HHI_GCLK_OTHER, 9); -static MESON_GATE(g12a_dac_clk, HHI_GCLK_OTHER, 10); -static MESON_GATE(g12a_aoclk_gate, HHI_GCLK_OTHER, 14); -static MESON_GATE(g12a_iec958_gate, HHI_GCLK_OTHER, 16); -static MESON_GATE(g12a_enc480p, HHI_GCLK_OTHER, 20); -static MESON_GATE(g12a_rng1, HHI_GCLK_OTHER, 21); -static MESON_GATE(g12a_vclk2_enct, HHI_GCLK_OTHER, 22); -static MESON_GATE(g12a_vclk2_encl, HHI_GCLK_OTHER, 23); -static MESON_GATE(g12a_vclk2_venclmmc, HHI_GCLK_OTHER, 24); -static MESON_GATE(g12a_vclk2_vencl, HHI_GCLK_OTHER, 25); -static MESON_GATE(g12a_vclk2_other1, HHI_GCLK_OTHER, 26); +static G12A_PCLK(g12a_vclk2_venci0, HHI_GCLK_OTHER, 1); +static G12A_PCLK(g12a_vclk2_venci1, HHI_GCLK_OTHER, 2); +static G12A_PCLK(g12a_vclk2_vencp0, HHI_GCLK_OTHER, 3); +static G12A_PCLK(g12a_vclk2_vencp1, HHI_GCLK_OTHER, 4); +static G12A_PCLK(g12a_vclk2_venct0, HHI_GCLK_OTHER, 5); +static G12A_PCLK(g12a_vclk2_venct1, HHI_GCLK_OTHER, 6); +static G12A_PCLK(g12a_vclk2_other, HHI_GCLK_OTHER, 7); +static G12A_PCLK(g12a_vclk2_enci, HHI_GCLK_OTHER, 8); +static G12A_PCLK(g12a_vclk2_encp, HHI_GCLK_OTHER, 9); +static G12A_PCLK(g12a_dac_clk, HHI_GCLK_OTHER, 10); +static G12A_PCLK(g12a_aoclk_gate, HHI_GCLK_OTHER, 14); +static G12A_PCLK(g12a_iec958_gate, HHI_GCLK_OTHER, 16); +static G12A_PCLK(g12a_enc480p, HHI_GCLK_OTHER, 20); +static G12A_PCLK(g12a_rng1, HHI_GCLK_OTHER, 21); +static G12A_PCLK(g12a_vclk2_enct, HHI_GCLK_OTHER, 22); +static G12A_PCLK(g12a_vclk2_encl, HHI_GCLK_OTHER, 23); +static G12A_PCLK(g12a_vclk2_venclmmc, HHI_GCLK_OTHER, 24); +static G12A_PCLK(g12a_vclk2_vencl, HHI_GCLK_OTHER, 25); +static G12A_PCLK(g12a_vclk2_other1, HHI_GCLK_OTHER, 26); -static MESON_GATE_RO(g12a_dma, HHI_GCLK_OTHER2, 0); -static MESON_GATE_RO(g12a_efuse, HHI_GCLK_OTHER2, 1); -static MESON_GATE_RO(g12a_rom_boot, HHI_GCLK_OTHER2, 2); -static MESON_GATE_RO(g12a_reset_sec, HHI_GCLK_OTHER2, 3); -static MESON_GATE_RO(g12a_sec_ahb_apb3, HHI_GCLK_OTHER2, 4); +static G12A_PCLK_RO(g12a_dma, HHI_GCLK_OTHER2, 0); +static G12A_PCLK_RO(g12a_efuse, HHI_GCLK_OTHER2, 1); +static G12A_PCLK_RO(g12a_rom_boot, HHI_GCLK_OTHER2, 2); +static G12A_PCLK_RO(g12a_reset_sec, HHI_GCLK_OTHER2, 3); +static G12A_PCLK_RO(g12a_sec_ahb_apb3, HHI_GCLK_OTHER2, 4); /* Array of all clocks provided by this provider */ static struct clk_hw *g12a_hw_clks[] = { @@ -4503,8 +4479,8 @@ static struct clk_hw *g12a_hw_clks[] = { [CLKID_FCLK_DIV7] = &g12a_fclk_div7.hw, [CLKID_FCLK_DIV2P5] = &g12a_fclk_div2p5.hw, [CLKID_GP0_PLL] = &g12a_gp0_pll.hw, - [CLKID_MPEG_SEL] = &g12a_mpeg_clk_sel.hw, - [CLKID_MPEG_DIV] = &g12a_mpeg_clk_div.hw, + [CLKID_MPEG_SEL] = &g12a_clk81_sel.hw, + [CLKID_MPEG_DIV] = &g12a_clk81_div.hw, [CLKID_CLK81] = &g12a_clk81.hw, [CLKID_MPLL0] = &g12a_mpll0.hw, [CLKID_MPLL1] = &g12a_mpll1.hw, @@ -4676,12 +4652,12 @@ static struct clk_hw *g12a_hw_clks[] = { [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, - [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, - [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_mux0_div.hw, - [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_postmux0.hw, - [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_premux1.hw, - [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_mux1_div.hw, - [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_postmux1.hw, + [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_dyn0_sel.hw, + [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_dyn0_div.hw, + [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_dyn0.hw, + [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_dyn1_sel.hw, + [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_dyn1_div.hw, + [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_dyn1.hw, [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, [CLKID_CPU_CLK] = &g12a_cpu_clk.hw, [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, @@ -4730,8 +4706,8 @@ static struct clk_hw *g12b_hw_clks[] = { [CLKID_FCLK_DIV7] = &g12a_fclk_div7.hw, [CLKID_FCLK_DIV2P5] = &g12a_fclk_div2p5.hw, [CLKID_GP0_PLL] = &g12a_gp0_pll.hw, - [CLKID_MPEG_SEL] = &g12a_mpeg_clk_sel.hw, - [CLKID_MPEG_DIV] = &g12a_mpeg_clk_div.hw, + [CLKID_MPEG_SEL] = &g12a_clk81_sel.hw, + [CLKID_MPEG_DIV] = &g12a_clk81_div.hw, [CLKID_CLK81] = &g12a_clk81.hw, [CLKID_MPLL0] = &g12a_mpll0.hw, [CLKID_MPLL1] = &g12a_mpll1.hw, @@ -4903,12 +4879,12 @@ static struct clk_hw *g12b_hw_clks[] = { [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, - [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, - [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_mux0_div.hw, - [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_postmux0.hw, - [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_premux1.hw, - [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_mux1_div.hw, - [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_postmux1.hw, + [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_dyn0_sel.hw, + [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_dyn0_div.hw, + [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_dyn0.hw, + [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_dyn1_sel.hw, + [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_dyn1_div.hw, + [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_dyn1.hw, [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, [CLKID_CPU_CLK] = &g12b_cpu_clk.hw, [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, @@ -4940,12 +4916,12 @@ static struct clk_hw *g12b_hw_clks[] = { [CLKID_SYS1_PLL] = &g12b_sys1_pll.hw, [CLKID_SYS1_PLL_DIV16_EN] = &g12b_sys1_pll_div16_en.hw, [CLKID_SYS1_PLL_DIV16] = &g12b_sys1_pll_div16.hw, - [CLKID_CPUB_CLK_DYN0_SEL] = &g12b_cpub_clk_premux0.hw, - [CLKID_CPUB_CLK_DYN0_DIV] = &g12b_cpub_clk_mux0_div.hw, - [CLKID_CPUB_CLK_DYN0] = &g12b_cpub_clk_postmux0.hw, - [CLKID_CPUB_CLK_DYN1_SEL] = &g12b_cpub_clk_premux1.hw, - [CLKID_CPUB_CLK_DYN1_DIV] = &g12b_cpub_clk_mux1_div.hw, - [CLKID_CPUB_CLK_DYN1] = &g12b_cpub_clk_postmux1.hw, + [CLKID_CPUB_CLK_DYN0_SEL] = &g12b_cpub_clk_dyn0_sel.hw, + [CLKID_CPUB_CLK_DYN0_DIV] = &g12b_cpub_clk_dyn0_div.hw, + [CLKID_CPUB_CLK_DYN0] = &g12b_cpub_clk_dyn0.hw, + [CLKID_CPUB_CLK_DYN1_SEL] = &g12b_cpub_clk_dyn1.hw, + [CLKID_CPUB_CLK_DYN1_DIV] = &g12b_cpub_clk_dyn1_div.hw, + [CLKID_CPUB_CLK_DYN1] = &g12b_cpub_clk_dyn1.hw, [CLKID_CPUB_CLK_DYN] = &g12b_cpub_clk_dyn.hw, [CLKID_CPUB_CLK] = &g12b_cpub_clk.hw, [CLKID_CPUB_CLK_DIV16_EN] = &g12b_cpub_clk_div16_en.hw, @@ -4998,8 +4974,8 @@ static struct clk_hw *sm1_hw_clks[] = { [CLKID_FCLK_DIV7] = &g12a_fclk_div7.hw, [CLKID_FCLK_DIV2P5] = &g12a_fclk_div2p5.hw, [CLKID_GP0_PLL] = &g12a_gp0_pll.hw, - [CLKID_MPEG_SEL] = &g12a_mpeg_clk_sel.hw, - [CLKID_MPEG_DIV] = &g12a_mpeg_clk_div.hw, + [CLKID_MPEG_SEL] = &g12a_clk81_sel.hw, + [CLKID_MPEG_DIV] = &g12a_clk81_div.hw, [CLKID_CLK81] = &g12a_clk81.hw, [CLKID_MPLL0] = &g12a_mpll0.hw, [CLKID_MPLL1] = &g12a_mpll1.hw, @@ -5171,12 +5147,12 @@ static struct clk_hw *sm1_hw_clks[] = { [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, - [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, - [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_mux0_div.hw, - [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_postmux0.hw, - [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_premux1.hw, - [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_mux1_div.hw, - [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_postmux1.hw, + [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_dyn0_sel.hw, + [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_dyn0_div.hw, + [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_dyn0.hw, + [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_dyn1_sel.hw, + [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_dyn1_div.hw, + [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_dyn1.hw, [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, [CLKID_CPU_CLK] = &g12a_cpu_clk.hw, [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, @@ -5206,12 +5182,12 @@ static struct clk_hw *sm1_hw_clks[] = { [CLKID_TS] = &g12a_ts.hw, [CLKID_GP1_PLL_DCO] = &sm1_gp1_pll_dco.hw, [CLKID_GP1_PLL] = &sm1_gp1_pll.hw, - [CLKID_DSU_CLK_DYN0_SEL] = &sm1_dsu_clk_premux0.hw, - [CLKID_DSU_CLK_DYN0_DIV] = &sm1_dsu_clk_premux1.hw, - [CLKID_DSU_CLK_DYN0] = &sm1_dsu_clk_mux0_div.hw, - [CLKID_DSU_CLK_DYN1_SEL] = &sm1_dsu_clk_postmux0.hw, - [CLKID_DSU_CLK_DYN1_DIV] = &sm1_dsu_clk_mux1_div.hw, - [CLKID_DSU_CLK_DYN1] = &sm1_dsu_clk_postmux1.hw, + [CLKID_DSU_CLK_DYN0_SEL] = &sm1_dsu_clk_dyn0_sel.hw, + [CLKID_DSU_CLK_DYN0_DIV] = &sm1_dsu_clk_dyn0_div.hw, + [CLKID_DSU_CLK_DYN0] = &sm1_dsu_clk_dyn0.hw, + [CLKID_DSU_CLK_DYN1_SEL] = &sm1_dsu_clk_dyn1_sel.hw, + [CLKID_DSU_CLK_DYN1_DIV] = &sm1_dsu_clk_dyn1_div.hw, + [CLKID_DSU_CLK_DYN1] = &sm1_dsu_clk_dyn1.hw, [CLKID_DSU_CLK_DYN] = &sm1_dsu_clk_dyn.hw, [CLKID_DSU_CLK_FINAL] = &sm1_dsu_final_clk.hw, [CLKID_DSU_CLK] = &sm1_dsu_clk.hw, @@ -5241,8 +5217,7 @@ static const struct reg_sequence g12a_init_regs[] = { #define DVFS_CON_ID "dvfs" -static int meson_g12a_dvfs_setup_common(struct device *dev, - struct clk_hw **hws) +static int g12a_dvfs_setup_common(struct device *dev, struct clk_hw **hws) { struct clk *notifier_clk; struct clk_hw *xtal; @@ -5251,13 +5226,13 @@ static int meson_g12a_dvfs_setup_common(struct device *dev, xtal = clk_hw_get_parent_by_index(hws[CLKID_CPU_CLK_DYN1_SEL], 0); /* Setup clock notifier for cpu_clk_postmux0 */ - g12a_cpu_clk_postmux0_nb_data.xtal = xtal; - notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_postmux0.hw, + g12a_cpu_clk_dyn0_nb_data.xtal = xtal; + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_dyn0.hw, DVFS_CON_ID); ret = devm_clk_notifier_register(dev, notifier_clk, - &g12a_cpu_clk_postmux0_nb_data.nb); + &g12a_cpu_clk_dyn0_nb_data.nb); if (ret) { - dev_err(dev, "failed to register the cpu_clk_postmux0 notifier\n"); + dev_err(dev, "failed to register the cpu_clk_dyn0 notifier\n"); return ret; } @@ -5274,7 +5249,7 @@ static int meson_g12a_dvfs_setup_common(struct device *dev, return 0; } -static int meson_g12b_dvfs_setup(struct platform_device *pdev) +static int g12b_dvfs_setup(struct platform_device *pdev) { struct clk_hw **hws = g12b_hw_clks; struct device *dev = &pdev->dev; @@ -5282,7 +5257,7 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) struct clk_hw *xtal; int ret; - ret = meson_g12a_dvfs_setup_common(dev, hws); + ret = g12a_dvfs_setup_common(dev, hws); if (ret) return ret; @@ -5311,18 +5286,19 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) /* Add notifiers for the second CPU cluster */ /* Setup clock notifier for cpub_clk_postmux0 */ - g12b_cpub_clk_postmux0_nb_data.xtal = xtal; - notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_postmux0.hw, + g12b_cpub_clk_dyn0_nb_data.xtal = xtal; + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_dyn0.hw, DVFS_CON_ID); ret = devm_clk_notifier_register(dev, notifier_clk, - &g12b_cpub_clk_postmux0_nb_data.nb); + &g12b_cpub_clk_dyn0_nb_data.nb); if (ret) { - dev_err(dev, "failed to register the cpub_clk_postmux0 notifier\n"); + dev_err(dev, "failed to register the cpub_clk_dyn0 notifier\n"); return ret; } /* Setup clock notifier for cpub_clk_dyn mux */ - notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_dyn.hw, "dvfs"); + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_dyn.hw, + DVFS_CON_ID); ret = devm_clk_notifier_register(dev, notifier_clk, &g12a_cpu_clk_mux_nb); if (ret) { @@ -5351,14 +5327,14 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev) return 0; } -static int meson_g12a_dvfs_setup(struct platform_device *pdev) +static int g12a_dvfs_setup(struct platform_device *pdev) { struct clk_hw **hws = g12a_hw_clks; struct device *dev = &pdev->dev; struct clk *notifier_clk; int ret; - ret = meson_g12a_dvfs_setup_common(dev, hws); + ret = g12a_dvfs_setup_common(dev, hws); if (ret) return ret; @@ -5383,15 +5359,15 @@ static int meson_g12a_dvfs_setup(struct platform_device *pdev) return 0; } -struct meson_g12a_data { +struct g12a_clkc_data { const struct meson_eeclkc_data eeclkc_data; int (*dvfs_setup)(struct platform_device *pdev); }; -static int meson_g12a_probe(struct platform_device *pdev) +static int g12a_clkc_probe(struct platform_device *pdev) { const struct meson_eeclkc_data *eeclkc_data; - const struct meson_g12a_data *g12a_data; + const struct g12a_clkc_data *g12a_data; int ret; eeclkc_data = of_device_get_match_data(&pdev->dev); @@ -5402,7 +5378,7 @@ static int meson_g12a_probe(struct platform_device *pdev) if (ret) return ret; - g12a_data = container_of(eeclkc_data, struct meson_g12a_data, + g12a_data = container_of(eeclkc_data, struct g12a_clkc_data, eeclkc_data); if (g12a_data->dvfs_setup) @@ -5411,7 +5387,7 @@ static int meson_g12a_probe(struct platform_device *pdev) return 0; } -static const struct meson_g12a_data g12a_clkc_data = { +static const struct g12a_clkc_data g12a_clkc_data = { .eeclkc_data = { .hw_clks = { .hws = g12a_hw_clks, @@ -5420,30 +5396,30 @@ static const struct meson_g12a_data g12a_clkc_data = { .init_regs = g12a_init_regs, .init_count = ARRAY_SIZE(g12a_init_regs), }, - .dvfs_setup = meson_g12a_dvfs_setup, + .dvfs_setup = g12a_dvfs_setup, }; -static const struct meson_g12a_data g12b_clkc_data = { +static const struct g12a_clkc_data g12b_clkc_data = { .eeclkc_data = { .hw_clks = { .hws = g12b_hw_clks, .num = ARRAY_SIZE(g12b_hw_clks), }, }, - .dvfs_setup = meson_g12b_dvfs_setup, + .dvfs_setup = g12b_dvfs_setup, }; -static const struct meson_g12a_data sm1_clkc_data = { +static const struct g12a_clkc_data sm1_clkc_data = { .eeclkc_data = { .hw_clks = { .hws = sm1_hw_clks, .num = ARRAY_SIZE(sm1_hw_clks), }, }, - .dvfs_setup = meson_g12a_dvfs_setup, + .dvfs_setup = g12a_dvfs_setup, }; -static const struct of_device_id clkc_match_table[] = { +static const struct of_device_id g12a_clkc_match_table[] = { { .compatible = "amlogic,g12a-clkc", .data = &g12a_clkc_data.eeclkc_data @@ -5458,16 +5434,16 @@ static const struct of_device_id clkc_match_table[] = { }, {} }; -MODULE_DEVICE_TABLE(of, clkc_match_table); +MODULE_DEVICE_TABLE(of, g12a_clkc_match_table); -static struct platform_driver g12a_driver = { - .probe = meson_g12a_probe, +static struct platform_driver g12a_clkc_driver = { + .probe = g12a_clkc_probe, .driver = { .name = "g12a-clkc", - .of_match_table = clkc_match_table, + .of_match_table = g12a_clkc_match_table, }, }; -module_platform_driver(g12a_driver); +module_platform_driver(g12a_clkc_driver); MODULE_DESCRIPTION("Amlogic G12/SM1 Main Clock Controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index f075fbd450f3..11b11fa7791e 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -23,14 +23,14 @@ #define AO_RTC_ALT_CLK_CNTL0 0x94 #define AO_RTC_ALT_CLK_CNTL1 0x98 -#define GXBB_AO_GATE(_name, _bit) \ -static struct clk_regmap _name##_ao = { \ +#define GXBB_AO_PCLK(_name, _bit) \ +static struct clk_regmap gxbb_ao_##_name = { \ .data = &(struct clk_regmap_gate_data) { \ .offset = AO_RTI_GEN_CNTL_REG0, \ .bit_idx = (_bit), \ }, \ .hw.init = &(struct clk_init_data) { \ - .name = #_name "_ao", \ + .name = "gxbb_ao_" #_name, \ .ops = &clk_regmap_gate_ops, \ .parent_data = &(const struct clk_parent_data) { \ .fw_name = "mpeg-clk", \ @@ -40,14 +40,14 @@ static struct clk_regmap _name##_ao = { \ }, \ } -GXBB_AO_GATE(remote, 0); -GXBB_AO_GATE(i2c_master, 1); -GXBB_AO_GATE(i2c_slave, 2); -GXBB_AO_GATE(uart1, 3); -GXBB_AO_GATE(uart2, 5); -GXBB_AO_GATE(ir_blaster, 6); +GXBB_AO_PCLK(remote, 0); +GXBB_AO_PCLK(i2c_master, 1); +GXBB_AO_PCLK(i2c_slave, 2); +GXBB_AO_PCLK(uart1, 3); +GXBB_AO_PCLK(uart2, 5); +GXBB_AO_PCLK(ir_blaster, 6); -static struct clk_regmap ao_cts_oscin = { +static struct clk_regmap gxbb_ao_cts_oscin = { .data = &(struct clk_regmap_gate_data){ .offset = AO_RTI_PWR_CNTL_REG0, .bit_idx = 6, @@ -62,7 +62,7 @@ static struct clk_regmap ao_cts_oscin = { }, }; -static struct clk_regmap ao_32k_pre = { +static struct clk_regmap gxbb_ao_32k_pre = { .data = &(struct clk_regmap_gate_data){ .offset = AO_RTC_ALT_CLK_CNTL0, .bit_idx = 31, @@ -70,7 +70,7 @@ static struct clk_regmap ao_32k_pre = { .hw.init = &(struct clk_init_data){ .name = "ao_32k_pre", .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { &ao_cts_oscin.hw }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_ao_cts_oscin.hw }, .num_parents = 1, }, }; @@ -85,7 +85,7 @@ static const struct meson_clk_dualdiv_param gxbb_32k_div_table[] = { }, {} }; -static struct clk_regmap ao_32k_div = { +static struct clk_regmap gxbb_ao_32k_div = { .data = &(struct meson_clk_dualdiv_data){ .n1 = { .reg_off = AO_RTC_ALT_CLK_CNTL0, @@ -117,12 +117,12 @@ static struct clk_regmap ao_32k_div = { .hw.init = &(struct clk_init_data){ .name = "ao_32k_div", .ops = &meson_clk_dualdiv_ops, - .parent_hws = (const struct clk_hw *[]) { &ao_32k_pre.hw }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_ao_32k_pre.hw }, .num_parents = 1, }, }; -static struct clk_regmap ao_32k_sel = { +static struct clk_regmap gxbb_ao_32k_sel = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTC_ALT_CLK_CNTL1, .mask = 0x1, @@ -133,15 +133,15 @@ static struct clk_regmap ao_32k_sel = { .name = "ao_32k_sel", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &ao_32k_div.hw, - &ao_32k_pre.hw + &gxbb_ao_32k_div.hw, + &gxbb_ao_32k_pre.hw }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap ao_32k = { +static struct clk_regmap gxbb_ao_32k = { .data = &(struct clk_regmap_gate_data){ .offset = AO_RTC_ALT_CLK_CNTL0, .bit_idx = 30, @@ -149,13 +149,13 @@ static struct clk_regmap ao_32k = { .hw.init = &(struct clk_init_data){ .name = "ao_32k", .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { &ao_32k_sel.hw }, + .parent_hws = (const struct clk_hw *[]) { &gxbb_ao_32k_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap ao_cts_rtc_oscin = { +static struct clk_regmap gxbb_ao_cts_rtc_oscin = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTI_PWR_CNTL_REG0, .mask = 0x7, @@ -170,14 +170,14 @@ static struct clk_regmap ao_cts_rtc_oscin = { { .fw_name = "ext-32k-0", }, { .fw_name = "ext-32k-1", }, { .fw_name = "ext-32k-2", }, - { .hw = &ao_32k.hw }, + { .hw = &gxbb_ao_32k.hw }, }, .num_parents = 4, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap ao_clk81 = { +static struct clk_regmap gxbb_ao_clk81 = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTI_PWR_CNTL_REG0, .mask = 0x1, @@ -189,14 +189,14 @@ static struct clk_regmap ao_clk81 = { .ops = &clk_regmap_mux_ro_ops, .parent_data = (const struct clk_parent_data []) { { .fw_name = "mpeg-clk", }, - { .hw = &ao_cts_rtc_oscin.hw }, + { .hw = &gxbb_ao_cts_rtc_oscin.hw }, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap ao_cts_cec = { +static struct clk_regmap gxbb_ao_cts_cec = { .data = &(struct clk_regmap_mux_data) { .offset = AO_CRT_CLK_CNTL1, .mask = 0x1, @@ -221,14 +221,14 @@ static struct clk_regmap ao_cts_cec = { */ .parent_data = (const struct clk_parent_data []) { { .name = "fixme", .index = -1, }, - { .hw = &ao_cts_rtc_oscin.hw }, + { .hw = &gxbb_ao_cts_rtc_oscin.hw }, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static const unsigned int gxbb_aoclk_reset[] = { +static const unsigned int gxbb_ao_reset[] = { [RESET_AO_REMOTE] = 16, [RESET_AO_I2C_MASTER] = 18, [RESET_AO_I2C_SLAVE] = 19, @@ -237,50 +237,50 @@ static const unsigned int gxbb_aoclk_reset[] = { [RESET_AO_IR_BLASTER] = 23, }; -static struct clk_hw *gxbb_aoclk_hw_clks[] = { - [CLKID_AO_REMOTE] = &remote_ao.hw, - [CLKID_AO_I2C_MASTER] = &i2c_master_ao.hw, - [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao.hw, - [CLKID_AO_UART1] = &uart1_ao.hw, - [CLKID_AO_UART2] = &uart2_ao.hw, - [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw, - [CLKID_AO_CEC_32K] = &ao_cts_cec.hw, - [CLKID_AO_CTS_OSCIN] = &ao_cts_oscin.hw, - [CLKID_AO_32K_PRE] = &ao_32k_pre.hw, - [CLKID_AO_32K_DIV] = &ao_32k_div.hw, - [CLKID_AO_32K_SEL] = &ao_32k_sel.hw, - [CLKID_AO_32K] = &ao_32k.hw, - [CLKID_AO_CTS_RTC_OSCIN] = &ao_cts_rtc_oscin.hw, - [CLKID_AO_CLK81] = &ao_clk81.hw, +static struct clk_hw *gxbb_ao_hw_clks[] = { + [CLKID_AO_REMOTE] = &gxbb_ao_remote.hw, + [CLKID_AO_I2C_MASTER] = &gxbb_ao_i2c_master.hw, + [CLKID_AO_I2C_SLAVE] = &gxbb_ao_i2c_slave.hw, + [CLKID_AO_UART1] = &gxbb_ao_uart1.hw, + [CLKID_AO_UART2] = &gxbb_ao_uart2.hw, + [CLKID_AO_IR_BLASTER] = &gxbb_ao_ir_blaster.hw, + [CLKID_AO_CEC_32K] = &gxbb_ao_cts_cec.hw, + [CLKID_AO_CTS_OSCIN] = &gxbb_ao_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &gxbb_ao_32k_pre.hw, + [CLKID_AO_32K_DIV] = &gxbb_ao_32k_div.hw, + [CLKID_AO_32K_SEL] = &gxbb_ao_32k_sel.hw, + [CLKID_AO_32K] = &gxbb_ao_32k.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &gxbb_ao_cts_rtc_oscin.hw, + [CLKID_AO_CLK81] = &gxbb_ao_clk81.hw, }; -static const struct meson_aoclk_data gxbb_aoclkc_data = { +static const struct meson_aoclk_data gxbb_ao_clkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, - .num_reset = ARRAY_SIZE(gxbb_aoclk_reset), - .reset = gxbb_aoclk_reset, + .num_reset = ARRAY_SIZE(gxbb_ao_reset), + .reset = gxbb_ao_reset, .hw_clks = { - .hws = gxbb_aoclk_hw_clks, - .num = ARRAY_SIZE(gxbb_aoclk_hw_clks), + .hws = gxbb_ao_hw_clks, + .num = ARRAY_SIZE(gxbb_ao_hw_clks), }, }; -static const struct of_device_id gxbb_aoclkc_match_table[] = { +static const struct of_device_id gxbb_ao_clkc_match_table[] = { { .compatible = "amlogic,meson-gx-aoclkc", - .data = &gxbb_aoclkc_data, + .data = &gxbb_ao_clkc_data, }, { } }; -MODULE_DEVICE_TABLE(of, gxbb_aoclkc_match_table); +MODULE_DEVICE_TABLE(of, gxbb_ao_clkc_match_table); -static struct platform_driver gxbb_aoclkc_driver = { +static struct platform_driver gxbb_ao_clkc_driver = { .probe = meson_aoclkc_probe, .driver = { .name = "gxbb-aoclkc", - .of_match_table = gxbb_aoclkc_match_table, + .of_match_table = gxbb_ao_clkc_match_table, }, }; -module_platform_driver(gxbb_aoclkc_driver); +module_platform_driver(gxbb_ao_clkc_driver); MODULE_DESCRIPTION("Amlogic GXBB Always-ON Clock Controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 362d1b87ea5b..2ad29c7cd6cf 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -116,70 +116,6 @@ #define HHI_BT656_CLK_CNTL 0x3d4 #define HHI_SAR_CLK_CNTL 0x3d8 -static const struct pll_params_table gxbb_gp0_pll_params_table[] = { - PLL_PARAMS(32, 1), - PLL_PARAMS(33, 1), - PLL_PARAMS(34, 1), - PLL_PARAMS(35, 1), - PLL_PARAMS(36, 1), - PLL_PARAMS(37, 1), - PLL_PARAMS(38, 1), - PLL_PARAMS(39, 1), - PLL_PARAMS(40, 1), - PLL_PARAMS(41, 1), - PLL_PARAMS(42, 1), - PLL_PARAMS(43, 1), - PLL_PARAMS(44, 1), - PLL_PARAMS(45, 1), - PLL_PARAMS(46, 1), - PLL_PARAMS(47, 1), - PLL_PARAMS(48, 1), - PLL_PARAMS(49, 1), - PLL_PARAMS(50, 1), - PLL_PARAMS(51, 1), - PLL_PARAMS(52, 1), - PLL_PARAMS(53, 1), - PLL_PARAMS(54, 1), - PLL_PARAMS(55, 1), - PLL_PARAMS(56, 1), - PLL_PARAMS(57, 1), - PLL_PARAMS(58, 1), - PLL_PARAMS(59, 1), - PLL_PARAMS(60, 1), - PLL_PARAMS(61, 1), - PLL_PARAMS(62, 1), - { /* sentinel */ }, -}; - -static const struct pll_params_table gxl_gp0_pll_params_table[] = { - PLL_PARAMS(42, 1), - PLL_PARAMS(43, 1), - PLL_PARAMS(44, 1), - PLL_PARAMS(45, 1), - PLL_PARAMS(46, 1), - PLL_PARAMS(47, 1), - PLL_PARAMS(48, 1), - PLL_PARAMS(49, 1), - PLL_PARAMS(50, 1), - PLL_PARAMS(51, 1), - PLL_PARAMS(52, 1), - PLL_PARAMS(53, 1), - PLL_PARAMS(54, 1), - PLL_PARAMS(55, 1), - PLL_PARAMS(56, 1), - PLL_PARAMS(57, 1), - PLL_PARAMS(58, 1), - PLL_PARAMS(59, 1), - PLL_PARAMS(60, 1), - PLL_PARAMS(61, 1), - PLL_PARAMS(62, 1), - PLL_PARAMS(63, 1), - PLL_PARAMS(64, 1), - PLL_PARAMS(65, 1), - PLL_PARAMS(66, 1), - { /* sentinel */ }, -}; - static struct clk_regmap gxbb_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { @@ -523,7 +459,42 @@ static struct clk_regmap gxbb_sys_pll = { }, }; -static const struct reg_sequence gxbb_gp0_init_regs[] = { +static const struct pll_params_table gxbb_gp0_pll_params_table[] = { + PLL_PARAMS(32, 1), + PLL_PARAMS(33, 1), + PLL_PARAMS(34, 1), + PLL_PARAMS(35, 1), + PLL_PARAMS(36, 1), + PLL_PARAMS(37, 1), + PLL_PARAMS(38, 1), + PLL_PARAMS(39, 1), + PLL_PARAMS(40, 1), + PLL_PARAMS(41, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + { /* sentinel */ }, +}; + +static const struct reg_sequence gxbb_gp0_pll_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, @@ -557,8 +528,8 @@ static struct clk_regmap gxbb_gp0_pll_dco = { .width = 1, }, .table = gxbb_gp0_pll_params_table, - .init_regs = gxbb_gp0_init_regs, - .init_count = ARRAY_SIZE(gxbb_gp0_init_regs), + .init_regs = gxbb_gp0_pll_init_regs, + .init_count = ARRAY_SIZE(gxbb_gp0_pll_init_regs), }, .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", @@ -570,7 +541,36 @@ static struct clk_regmap gxbb_gp0_pll_dco = { }, }; -static const struct reg_sequence gxl_gp0_init_regs[] = { +static const struct pll_params_table gxl_gp0_pll_params_table[] = { + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(65, 1), + PLL_PARAMS(66, 1), + { /* sentinel */ }, +}; + +static const struct reg_sequence gxl_gp0_pll_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, @@ -611,8 +611,8 @@ static struct clk_regmap gxl_gp0_pll_dco = { .width = 1, }, .table = gxl_gp0_pll_params_table, - .init_regs = gxl_gp0_init_regs, - .init_count = ARRAY_SIZE(gxl_gp0_init_regs), + .init_regs = gxl_gp0_pll_init_regs, + .init_count = ARRAY_SIZE(gxl_gp0_pll_init_regs), }, .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", @@ -972,8 +972,9 @@ static struct clk_regmap gxbb_mpll2 = { }, }; -static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; -static const struct clk_parent_data clk81_parent_data[] = { +/* clk81 is often referred as "mpeg_clk" */ +static u32 clk81_parents_val_table[] = { 0, 2, 3, 4, 5, 6, 7 }; +static const struct clk_parent_data clk81_parents[] = { { .fw_name = "xtal", }, { .hw = &gxbb_fclk_div7.hw }, { .hw = &gxbb_mpll1.hw }, @@ -983,37 +984,37 @@ static const struct clk_parent_data clk81_parent_data[] = { { .hw = &gxbb_fclk_div5.hw }, }; -static struct clk_regmap gxbb_mpeg_clk_sel = { +static struct clk_regmap gxbb_clk81_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_MPEG_CLK_CNTL, .mask = 0x7, .shift = 12, - .table = mux_table_clk81, + .table = clk81_parents_val_table, }, .hw.init = &(struct clk_init_data){ - .name = "mpeg_clk_sel", + .name = "clk81_sel", .ops = &clk_regmap_mux_ro_ops, /* * bits 14:12 selects from 8 possible parents: * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, * fclk_div4, fclk_div3, fclk_div5 */ - .parent_data = clk81_parent_data, - .num_parents = ARRAY_SIZE(clk81_parent_data), + .parent_data = clk81_parents, + .num_parents = ARRAY_SIZE(clk81_parents), }, }; -static struct clk_regmap gxbb_mpeg_clk_div = { +static struct clk_regmap gxbb_clk81_div = { .data = &(struct clk_regmap_div_data){ .offset = HHI_MPEG_CLK_CNTL, .shift = 0, .width = 7, }, .hw.init = &(struct clk_init_data){ - .name = "mpeg_clk_div", + .name = "clk81_div", .ops = &clk_regmap_divider_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &gxbb_mpeg_clk_sel.hw + &gxbb_clk81_sel.hw }, .num_parents = 1, }, @@ -1029,7 +1030,7 @@ static struct clk_regmap gxbb_clk81 = { .name = "clk81", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &gxbb_mpeg_clk_div.hw + &gxbb_clk81_div.hw }, .num_parents = 1, .flags = CLK_IS_CRITICAL, @@ -1094,7 +1095,7 @@ static struct clk_regmap gxbb_sar_adc_clk = { * switches to the "inactive" one when CLK_SET_RATE_GATE is set. */ -static const struct clk_parent_data gxbb_mali_0_1_parent_data[] = { +static const struct clk_parent_data gxbb_mali_parents[] = { { .fw_name = "xtal", }, { .hw = &gxbb_gp0_pll.hw }, { .hw = &gxbb_mpll2.hw }, @@ -1114,8 +1115,8 @@ static struct clk_regmap gxbb_mali_0_sel = { .hw.init = &(struct clk_init_data){ .name = "mali_0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = gxbb_mali_0_1_parent_data, - .num_parents = 8, + .parent_data = gxbb_mali_parents, + .num_parents = ARRAY_SIZE(gxbb_mali_parents), /* * Don't request the parent to change the rate because * all GPU frequencies can be derived from the fclk_* @@ -1168,8 +1169,8 @@ static struct clk_regmap gxbb_mali_1_sel = { .hw.init = &(struct clk_init_data){ .name = "mali_1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = gxbb_mali_0_1_parent_data, - .num_parents = 8, + .parent_data = gxbb_mali_parents, + .num_parents = ARRAY_SIZE(gxbb_mali_parents), /* * Don't request the parent to change the rate because * all GPU frequencies can be derived from the fclk_* @@ -1213,11 +1214,6 @@ static struct clk_regmap gxbb_mali_1 = { }, }; -static const struct clk_hw *gxbb_mali_parent_hws[] = { - &gxbb_mali_0.hw, - &gxbb_mali_1.hw, -}; - static struct clk_regmap gxbb_mali = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_MALI_CLK_CNTL, @@ -1227,29 +1223,35 @@ static struct clk_regmap gxbb_mali = { .hw.init = &(struct clk_init_data){ .name = "mali", .ops = &clk_regmap_mux_ops, - .parent_hws = gxbb_mali_parent_hws, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mali_0.hw, + &gxbb_mali_1.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; +static u32 gxbb_cts_mclk_parents_val_table[] = { 1, 2, 3 }; +static const struct clk_hw *gxbb_cts_mclk_parents[] = { + &gxbb_mpll0.hw, + &gxbb_mpll1.hw, + &gxbb_mpll2.hw, +}; + static struct clk_regmap gxbb_cts_amclk_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_AUD_CLK_CNTL, .mask = 0x3, .shift = 9, - .table = (u32[]){ 1, 2, 3 }, + .table = gxbb_cts_mclk_parents_val_table, .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ .name = "cts_amclk_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = (const struct clk_hw *[]) { - &gxbb_mpll0.hw, - &gxbb_mpll1.hw, - &gxbb_mpll2.hw, - }, - .num_parents = 3, + .parent_hws = gxbb_cts_mclk_parents, + .num_parents = ARRAY_SIZE(gxbb_cts_mclk_parents), }, }; @@ -1292,18 +1294,14 @@ static struct clk_regmap gxbb_cts_mclk_i958_sel = { .offset = HHI_AUD_CLK_CNTL2, .mask = 0x3, .shift = 25, - .table = (u32[]){ 1, 2, 3 }, + .table = gxbb_cts_mclk_parents_val_table, .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = (const struct clk_hw *[]) { - &gxbb_mpll0.hw, - &gxbb_mpll1.hw, - &gxbb_mpll2.hw, - }, - .num_parents = 3, + .parent_hws = gxbb_cts_mclk_parents, + .num_parents = ARRAY_SIZE(gxbb_cts_mclk_parents), }, }; @@ -1368,7 +1366,7 @@ static struct clk_regmap gxbb_cts_i958 = { * This clock does not exist yet in this controller or the AO one */ static u32 gxbb_32k_clk_parents_val_table[] = { 0, 2, 3 }; -static const struct clk_parent_data gxbb_32k_clk_parent_data[] = { +static const struct clk_parent_data gxbb_32k_clk_parents[] = { { .fw_name = "xtal", }, { .hw = &gxbb_fclk_div3.hw }, { .hw = &gxbb_fclk_div5.hw }, @@ -1380,11 +1378,11 @@ static struct clk_regmap gxbb_32k_clk_sel = { .mask = 0x3, .shift = 16, .table = gxbb_32k_clk_parents_val_table, - }, + }, .hw.init = &(struct clk_init_data){ .name = "32k_clk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = gxbb_32k_clk_parent_data, + .parent_data = gxbb_32k_clk_parents, .num_parents = 4, .flags = CLK_SET_RATE_PARENT, }, @@ -1423,7 +1421,7 @@ static struct clk_regmap gxbb_32k_clk = { }, }; -static const struct clk_parent_data gxbb_sd_emmc_clk0_parent_data[] = { +static const struct clk_parent_data gxbb_sd_emmc_clk0_parents[] = { { .fw_name = "xtal", }, { .hw = &gxbb_fclk_div2.hw }, { .hw = &gxbb_fclk_div3.hw }, @@ -1447,8 +1445,8 @@ static struct clk_regmap gxbb_sd_emmc_a_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = gxbb_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_data), + .parent_data = gxbb_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1497,8 +1495,8 @@ static struct clk_regmap gxbb_sd_emmc_b_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = gxbb_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_data), + .parent_data = gxbb_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1547,8 +1545,8 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = gxbb_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_data), + .parent_data = gxbb_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1589,7 +1587,7 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0 = { /* VPU Clock */ -static const struct clk_hw *gxbb_vpu_parent_hws[] = { +static const struct clk_hw *gxbb_vpu_parents[] = { &gxbb_fclk_div4.hw, &gxbb_fclk_div3.hw, &gxbb_fclk_div5.hw, @@ -1609,8 +1607,8 @@ static struct clk_regmap gxbb_vpu_0_sel = { * bits 9:10 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, */ - .parent_hws = gxbb_vpu_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_vpu_parent_hws), + .parent_hws = gxbb_vpu_parents, + .num_parents = ARRAY_SIZE(gxbb_vpu_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1657,8 +1655,8 @@ static struct clk_regmap gxbb_vpu_1_sel = { * bits 25:26 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, */ - .parent_hws = gxbb_vpu_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_vpu_parent_hws), + .parent_hws = gxbb_vpu_parents, + .num_parents = ARRAY_SIZE(gxbb_vpu_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1716,7 +1714,7 @@ static struct clk_regmap gxbb_vpu = { /* VAPB Clock */ -static const struct clk_hw *gxbb_vapb_parent_hws[] = { +static const struct clk_hw *gxbb_vapb_parents[] = { &gxbb_fclk_div4.hw, &gxbb_fclk_div3.hw, &gxbb_fclk_div5.hw, @@ -1736,8 +1734,8 @@ static struct clk_regmap gxbb_vapb_0_sel = { * bits 9:10 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, */ - .parent_hws = gxbb_vapb_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_vapb_parent_hws), + .parent_hws = gxbb_vapb_parents, + .num_parents = ARRAY_SIZE(gxbb_vapb_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1788,8 +1786,8 @@ static struct clk_regmap gxbb_vapb_1_sel = { * bits 25:26 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, */ - .parent_hws = gxbb_vapb_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_vapb_parent_hws), + .parent_hws = gxbb_vapb_parents, + .num_parents = ARRAY_SIZE(gxbb_vapb_parents), .flags = CLK_SET_RATE_NO_REPARENT, }, }; @@ -1897,7 +1895,7 @@ static struct clk_regmap gxbb_vid_pll_div = { }, }; -static const struct clk_parent_data gxbb_vid_pll_parent_data[] = { +static const struct clk_parent_data gxbb_vid_pll_parents[] = { { .hw = &gxbb_vid_pll_div.hw }, /* * Note: @@ -1922,8 +1920,8 @@ static struct clk_regmap gxbb_vid_pll_sel = { * bit 18 selects from 2 possible parents: * vid_pll_div or hdmi_pll */ - .parent_data = gxbb_vid_pll_parent_data, - .num_parents = ARRAY_SIZE(gxbb_vid_pll_parent_data), + .parent_data = gxbb_vid_pll_parents, + .num_parents = ARRAY_SIZE(gxbb_vid_pll_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -1944,7 +1942,7 @@ static struct clk_regmap gxbb_vid_pll = { }, }; -static const struct clk_hw *gxbb_vclk_parent_hws[] = { +static const struct clk_hw *gxbb_vclk_parents[] = { &gxbb_vid_pll.hw, &gxbb_fclk_div4.hw, &gxbb_fclk_div3.hw, @@ -1968,8 +1966,8 @@ static struct clk_regmap gxbb_vclk_sel = { * vid_pll, fclk_div4, fclk_div3, fclk_div5, * vid_pll, fclk_div7, mp1 */ - .parent_hws = gxbb_vclk_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_vclk_parent_hws), + .parent_hws = gxbb_vclk_parents, + .num_parents = ARRAY_SIZE(gxbb_vclk_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -1988,8 +1986,8 @@ static struct clk_regmap gxbb_vclk2_sel = { * vid_pll, fclk_div4, fclk_div3, fclk_div5, * vid_pll, fclk_div7, mp1 */ - .parent_hws = gxbb_vclk_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_vclk_parent_hws), + .parent_hws = gxbb_vclk_parents, + .num_parents = ARRAY_SIZE(gxbb_vclk_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2328,8 +2326,8 @@ static struct clk_fixed_factor gxbb_vclk2_div12 = { }, }; -static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const struct clk_hw *gxbb_cts_parent_hws[] = { +static u32 gxbb_cts_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *gxbb_cts_parents[] = { &gxbb_vclk_div1.hw, &gxbb_vclk_div2.hw, &gxbb_vclk_div4.hw, @@ -2347,13 +2345,13 @@ static struct clk_regmap gxbb_cts_enci_sel = { .offset = HHI_VID_CLK_DIV, .mask = 0xf, .shift = 28, - .table = mux_table_cts_sel, + .table = gxbb_cts_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_enci_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = gxbb_cts_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_cts_parent_hws), + .parent_hws = gxbb_cts_parents, + .num_parents = ARRAY_SIZE(gxbb_cts_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2363,13 +2361,13 @@ static struct clk_regmap gxbb_cts_encp_sel = { .offset = HHI_VID_CLK_DIV, .mask = 0xf, .shift = 20, - .table = mux_table_cts_sel, + .table = gxbb_cts_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_encp_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = gxbb_cts_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_cts_parent_hws), + .parent_hws = gxbb_cts_parents, + .num_parents = ARRAY_SIZE(gxbb_cts_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2379,50 +2377,13 @@ static struct clk_regmap gxbb_cts_vdac_sel = { .offset = HHI_VIID_CLK_DIV, .mask = 0xf, .shift = 28, - .table = mux_table_cts_sel, + .table = gxbb_cts_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_vdac_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = gxbb_cts_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_cts_parent_hws), - .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, - }, -}; - -/* TOFIX: add support for cts_tcon */ -static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const struct clk_hw *gxbb_cts_hdmi_tx_parent_hws[] = { - &gxbb_vclk_div1.hw, - &gxbb_vclk_div2.hw, - &gxbb_vclk_div4.hw, - &gxbb_vclk_div6.hw, - &gxbb_vclk_div12.hw, - &gxbb_vclk2_div1.hw, - &gxbb_vclk2_div2.hw, - &gxbb_vclk2_div4.hw, - &gxbb_vclk2_div6.hw, - &gxbb_vclk2_div12.hw, -}; - -static struct clk_regmap gxbb_hdmi_tx_sel = { - .data = &(struct clk_regmap_mux_data){ - .offset = HHI_HDMI_CLK_CNTL, - .mask = 0xf, - .shift = 16, - .table = mux_table_hdmi_tx_sel, - }, - .hw.init = &(struct clk_init_data){ - .name = "hdmi_tx_sel", - .ops = &clk_regmap_mux_ops, - /* - * bits 31:28 selects from 12 possible parents: - * vclk_div1, vclk_div2, vclk_div4, vclk_div6, vclk_div12 - * vclk2_div1, vclk2_div2, vclk2_div4, vclk2_div6, vclk2_div12, - * cts_tcon - */ - .parent_hws = gxbb_cts_hdmi_tx_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_cts_hdmi_tx_parent_hws), + .parent_hws = gxbb_cts_parents, + .num_parents = ARRAY_SIZE(gxbb_cts_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2475,6 +2436,43 @@ static struct clk_regmap gxbb_cts_vdac = { }, }; +/* TOFIX: add support for cts_tcon */ +static u32 gxbb_hdmi_tx_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *gxbb_hdmi_tx_parents[] = { + &gxbb_vclk_div1.hw, + &gxbb_vclk_div2.hw, + &gxbb_vclk_div4.hw, + &gxbb_vclk_div6.hw, + &gxbb_vclk_div12.hw, + &gxbb_vclk2_div1.hw, + &gxbb_vclk2_div2.hw, + &gxbb_vclk2_div4.hw, + &gxbb_vclk2_div6.hw, + &gxbb_vclk2_div12.hw, +}; + +static struct clk_regmap gxbb_hdmi_tx_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_HDMI_CLK_CNTL, + .mask = 0xf, + .shift = 16, + .table = gxbb_hdmi_tx_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 31:28 selects from 12 possible parents: + * vclk_div1, vclk_div2, vclk_div4, vclk_div6, vclk_div12 + * vclk2_div1, vclk2_div2, vclk2_div4, vclk2_div6, vclk2_div12, + * cts_tcon + */ + .parent_hws = gxbb_hdmi_tx_parents, + .num_parents = ARRAY_SIZE(gxbb_hdmi_tx_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + static struct clk_regmap gxbb_hdmi_tx = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VID_CLK_CNTL2, @@ -2493,7 +2491,7 @@ static struct clk_regmap gxbb_hdmi_tx = { /* HDMI Clocks */ -static const struct clk_parent_data gxbb_hdmi_parent_data[] = { +static const struct clk_parent_data gxbb_hdmi_parents[] = { { .fw_name = "xtal", }, { .hw = &gxbb_fclk_div4.hw }, { .hw = &gxbb_fclk_div3.hw }, @@ -2510,8 +2508,8 @@ static struct clk_regmap gxbb_hdmi_sel = { .hw.init = &(struct clk_init_data){ .name = "hdmi_sel", .ops = &clk_regmap_mux_ops, - .parent_data = gxbb_hdmi_parent_data, - .num_parents = ARRAY_SIZE(gxbb_hdmi_parent_data), + .parent_data = gxbb_hdmi_parents, + .num_parents = ARRAY_SIZE(gxbb_hdmi_parents), .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, }, }; @@ -2547,7 +2545,7 @@ static struct clk_regmap gxbb_hdmi = { /* VDEC clocks */ -static const struct clk_hw *gxbb_vdec_parent_hws[] = { +static const struct clk_hw *gxbb_vdec_parents[] = { &gxbb_fclk_div4.hw, &gxbb_fclk_div3.hw, &gxbb_fclk_div5.hw, @@ -2564,8 +2562,8 @@ static struct clk_regmap gxbb_vdec_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_1_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = gxbb_vdec_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_vdec_parent_hws), + .parent_hws = gxbb_vdec_parents, + .num_parents = ARRAY_SIZE(gxbb_vdec_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2614,8 +2612,8 @@ static struct clk_regmap gxbb_vdec_hevc_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevc_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = gxbb_vdec_parent_hws, - .num_parents = ARRAY_SIZE(gxbb_vdec_parent_hws), + .parent_hws = gxbb_vdec_parents, + .num_parents = ARRAY_SIZE(gxbb_vdec_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2654,9 +2652,8 @@ static struct clk_regmap gxbb_vdec_hevc = { }, }; -static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, - 9, 10, 11, 13, 14, }; -static const struct clk_parent_data gen_clk_parent_data[] = { +static u32 gxbb_gen_clk_parents_val_table[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; +static const struct clk_parent_data gxbb_gen_clk_parents[] = { { .fw_name = "xtal", }, { .hw = &gxbb_vdec_1.hw }, { .hw = &gxbb_vdec_hevc.hw }, @@ -2675,7 +2672,7 @@ static struct clk_regmap gxbb_gen_clk_sel = { .offset = HHI_GEN_CLK_CNTL, .mask = 0xf, .shift = 12, - .table = mux_table_gen_clk, + .table = gxbb_gen_clk_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "gen_clk_sel", @@ -2686,8 +2683,8 @@ static struct clk_regmap gxbb_gen_clk_sel = { * vid_pll, vid2_pll (hevc), mpll0, mpll1, mpll2, fdiv4, * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll */ - .parent_data = gen_clk_parent_data, - .num_parents = ARRAY_SIZE(gen_clk_parent_data), + .parent_data = gxbb_gen_clk_parents, + .num_parents = ARRAY_SIZE(gxbb_gen_clk_parents), }, }; @@ -2724,100 +2721,100 @@ static struct clk_regmap gxbb_gen_clk = { }, }; -#define MESON_GATE(_name, _reg, _bit) \ +#define GXBB_PCLK(_name, _reg, _bit) \ MESON_PCLK(_name, _reg, _bit, &gxbb_clk81.hw) /* Everything Else (EE) domain gates */ -static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); -static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); -static MESON_GATE(gxbb_isa, HHI_GCLK_MPEG0, 5); -static MESON_GATE(gxbb_pl301, HHI_GCLK_MPEG0, 6); -static MESON_GATE(gxbb_periphs, HHI_GCLK_MPEG0, 7); -static MESON_GATE(gxbb_spicc, HHI_GCLK_MPEG0, 8); -static MESON_GATE(gxbb_i2c, HHI_GCLK_MPEG0, 9); -static MESON_GATE(gxbb_sana, HHI_GCLK_MPEG0, 10); -static MESON_GATE(gxbb_smart_card, HHI_GCLK_MPEG0, 11); -static MESON_GATE(gxbb_rng0, HHI_GCLK_MPEG0, 12); -static MESON_GATE(gxbb_uart0, HHI_GCLK_MPEG0, 13); -static MESON_GATE(gxbb_sdhc, HHI_GCLK_MPEG0, 14); -static MESON_GATE(gxbb_stream, HHI_GCLK_MPEG0, 15); -static MESON_GATE(gxbb_async_fifo, HHI_GCLK_MPEG0, 16); -static MESON_GATE(gxbb_sdio, HHI_GCLK_MPEG0, 17); -static MESON_GATE(gxbb_abuf, HHI_GCLK_MPEG0, 18); -static MESON_GATE(gxbb_hiu_iface, HHI_GCLK_MPEG0, 19); -static MESON_GATE(gxbb_assist_misc, HHI_GCLK_MPEG0, 23); -static MESON_GATE(gxbb_emmc_a, HHI_GCLK_MPEG0, 24); -static MESON_GATE(gxbb_emmc_b, HHI_GCLK_MPEG0, 25); -static MESON_GATE(gxbb_emmc_c, HHI_GCLK_MPEG0, 26); -static MESON_GATE(gxl_acodec, HHI_GCLK_MPEG0, 28); -static MESON_GATE(gxbb_spi, HHI_GCLK_MPEG0, 30); +static GXBB_PCLK(gxbb_ddr, HHI_GCLK_MPEG0, 0); +static GXBB_PCLK(gxbb_dos, HHI_GCLK_MPEG0, 1); +static GXBB_PCLK(gxbb_isa, HHI_GCLK_MPEG0, 5); +static GXBB_PCLK(gxbb_pl301, HHI_GCLK_MPEG0, 6); +static GXBB_PCLK(gxbb_periphs, HHI_GCLK_MPEG0, 7); +static GXBB_PCLK(gxbb_spicc, HHI_GCLK_MPEG0, 8); +static GXBB_PCLK(gxbb_i2c, HHI_GCLK_MPEG0, 9); +static GXBB_PCLK(gxbb_sana, HHI_GCLK_MPEG0, 10); +static GXBB_PCLK(gxbb_smart_card, HHI_GCLK_MPEG0, 11); +static GXBB_PCLK(gxbb_rng0, HHI_GCLK_MPEG0, 12); +static GXBB_PCLK(gxbb_uart0, HHI_GCLK_MPEG0, 13); +static GXBB_PCLK(gxbb_sdhc, HHI_GCLK_MPEG0, 14); +static GXBB_PCLK(gxbb_stream, HHI_GCLK_MPEG0, 15); +static GXBB_PCLK(gxbb_async_fifo, HHI_GCLK_MPEG0, 16); +static GXBB_PCLK(gxbb_sdio, HHI_GCLK_MPEG0, 17); +static GXBB_PCLK(gxbb_abuf, HHI_GCLK_MPEG0, 18); +static GXBB_PCLK(gxbb_hiu_iface, HHI_GCLK_MPEG0, 19); +static GXBB_PCLK(gxbb_assist_misc, HHI_GCLK_MPEG0, 23); +static GXBB_PCLK(gxbb_emmc_a, HHI_GCLK_MPEG0, 24); +static GXBB_PCLK(gxbb_emmc_b, HHI_GCLK_MPEG0, 25); +static GXBB_PCLK(gxbb_emmc_c, HHI_GCLK_MPEG0, 26); +static GXBB_PCLK(gxl_acodec, HHI_GCLK_MPEG0, 28); +static GXBB_PCLK(gxbb_spi, HHI_GCLK_MPEG0, 30); -static MESON_GATE(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2); -static MESON_GATE(gxbb_eth, HHI_GCLK_MPEG1, 3); -static MESON_GATE(gxbb_demux, HHI_GCLK_MPEG1, 4); -static MESON_GATE(gxbb_blkmv, HHI_GCLK_MPEG1, 14); -static MESON_GATE(gxbb_aiu, HHI_GCLK_MPEG1, 15); -static MESON_GATE(gxbb_uart1, HHI_GCLK_MPEG1, 16); -static MESON_GATE(gxbb_g2d, HHI_GCLK_MPEG1, 20); -static MESON_GATE(gxbb_usb0, HHI_GCLK_MPEG1, 21); -static MESON_GATE(gxbb_usb1, HHI_GCLK_MPEG1, 22); -static MESON_GATE(gxbb_reset, HHI_GCLK_MPEG1, 23); -static MESON_GATE(gxbb_nand, HHI_GCLK_MPEG1, 24); -static MESON_GATE(gxbb_dos_parser, HHI_GCLK_MPEG1, 25); -static MESON_GATE(gxbb_usb, HHI_GCLK_MPEG1, 26); -static MESON_GATE(gxbb_vdin1, HHI_GCLK_MPEG1, 28); -static MESON_GATE(gxbb_ahb_arb0, HHI_GCLK_MPEG1, 29); -static MESON_GATE(gxbb_efuse, HHI_GCLK_MPEG1, 30); -static MESON_GATE(gxbb_boot_rom, HHI_GCLK_MPEG1, 31); +static GXBB_PCLK(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2); +static GXBB_PCLK(gxbb_eth, HHI_GCLK_MPEG1, 3); +static GXBB_PCLK(gxbb_demux, HHI_GCLK_MPEG1, 4); +static GXBB_PCLK(gxbb_blkmv, HHI_GCLK_MPEG1, 14); +static GXBB_PCLK(gxbb_aiu, HHI_GCLK_MPEG1, 15); +static GXBB_PCLK(gxbb_uart1, HHI_GCLK_MPEG1, 16); +static GXBB_PCLK(gxbb_g2d, HHI_GCLK_MPEG1, 20); +static GXBB_PCLK(gxbb_usb0, HHI_GCLK_MPEG1, 21); +static GXBB_PCLK(gxbb_usb1, HHI_GCLK_MPEG1, 22); +static GXBB_PCLK(gxbb_reset, HHI_GCLK_MPEG1, 23); +static GXBB_PCLK(gxbb_nand, HHI_GCLK_MPEG1, 24); +static GXBB_PCLK(gxbb_dos_parser, HHI_GCLK_MPEG1, 25); +static GXBB_PCLK(gxbb_usb, HHI_GCLK_MPEG1, 26); +static GXBB_PCLK(gxbb_vdin1, HHI_GCLK_MPEG1, 28); +static GXBB_PCLK(gxbb_ahb_arb0, HHI_GCLK_MPEG1, 29); +static GXBB_PCLK(gxbb_efuse, HHI_GCLK_MPEG1, 30); +static GXBB_PCLK(gxbb_boot_rom, HHI_GCLK_MPEG1, 31); -static MESON_GATE(gxbb_ahb_data_bus, HHI_GCLK_MPEG2, 1); -static MESON_GATE(gxbb_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); -static MESON_GATE(gxbb_hdmi_intr_sync, HHI_GCLK_MPEG2, 3); -static MESON_GATE(gxbb_hdmi_pclk, HHI_GCLK_MPEG2, 4); -static MESON_GATE(gxbb_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); -static MESON_GATE(gxbb_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); -static MESON_GATE(gxbb_mmc_pclk, HHI_GCLK_MPEG2, 11); -static MESON_GATE(gxbb_dvin, HHI_GCLK_MPEG2, 12); -static MESON_GATE(gxbb_uart2, HHI_GCLK_MPEG2, 15); -static MESON_GATE(gxbb_sar_adc, HHI_GCLK_MPEG2, 22); -static MESON_GATE(gxbb_vpu_intr, HHI_GCLK_MPEG2, 25); -static MESON_GATE(gxbb_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); -static MESON_GATE(gxbb_clk81_a53, HHI_GCLK_MPEG2, 29); +static GXBB_PCLK(gxbb_ahb_data_bus, HHI_GCLK_MPEG2, 1); +static GXBB_PCLK(gxbb_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static GXBB_PCLK(gxbb_hdmi_intr_sync, HHI_GCLK_MPEG2, 3); +static GXBB_PCLK(gxbb_hdmi_pclk, HHI_GCLK_MPEG2, 4); +static GXBB_PCLK(gxbb_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); +static GXBB_PCLK(gxbb_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); +static GXBB_PCLK(gxbb_mmc_pclk, HHI_GCLK_MPEG2, 11); +static GXBB_PCLK(gxbb_dvin, HHI_GCLK_MPEG2, 12); +static GXBB_PCLK(gxbb_uart2, HHI_GCLK_MPEG2, 15); +static GXBB_PCLK(gxbb_sar_adc, HHI_GCLK_MPEG2, 22); +static GXBB_PCLK(gxbb_vpu_intr, HHI_GCLK_MPEG2, 25); +static GXBB_PCLK(gxbb_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); +static GXBB_PCLK(gxbb_clk81_a53, HHI_GCLK_MPEG2, 29); -static MESON_GATE(gxbb_vclk2_venci0, HHI_GCLK_OTHER, 1); -static MESON_GATE(gxbb_vclk2_venci1, HHI_GCLK_OTHER, 2); -static MESON_GATE(gxbb_vclk2_vencp0, HHI_GCLK_OTHER, 3); -static MESON_GATE(gxbb_vclk2_vencp1, HHI_GCLK_OTHER, 4); -static MESON_GATE(gxbb_gclk_venci_int0, HHI_GCLK_OTHER, 8); -static MESON_GATE(gxbb_gclk_vencp_int, HHI_GCLK_OTHER, 9); -static MESON_GATE(gxbb_dac_clk, HHI_GCLK_OTHER, 10); -static MESON_GATE(gxbb_aoclk_gate, HHI_GCLK_OTHER, 14); -static MESON_GATE(gxbb_iec958_gate, HHI_GCLK_OTHER, 16); -static MESON_GATE(gxbb_enc480p, HHI_GCLK_OTHER, 20); -static MESON_GATE(gxbb_rng1, HHI_GCLK_OTHER, 21); -static MESON_GATE(gxbb_gclk_venci_int1, HHI_GCLK_OTHER, 22); -static MESON_GATE(gxbb_vclk2_venclmcc, HHI_GCLK_OTHER, 24); -static MESON_GATE(gxbb_vclk2_vencl, HHI_GCLK_OTHER, 25); -static MESON_GATE(gxbb_vclk_other, HHI_GCLK_OTHER, 26); -static MESON_GATE(gxbb_edp, HHI_GCLK_OTHER, 31); +static GXBB_PCLK(gxbb_vclk2_venci0, HHI_GCLK_OTHER, 1); +static GXBB_PCLK(gxbb_vclk2_venci1, HHI_GCLK_OTHER, 2); +static GXBB_PCLK(gxbb_vclk2_vencp0, HHI_GCLK_OTHER, 3); +static GXBB_PCLK(gxbb_vclk2_vencp1, HHI_GCLK_OTHER, 4); +static GXBB_PCLK(gxbb_gclk_venci_int0, HHI_GCLK_OTHER, 8); +static GXBB_PCLK(gxbb_gclk_vencp_int, HHI_GCLK_OTHER, 9); +static GXBB_PCLK(gxbb_dac_clk, HHI_GCLK_OTHER, 10); +static GXBB_PCLK(gxbb_aoclk_gate, HHI_GCLK_OTHER, 14); +static GXBB_PCLK(gxbb_iec958_gate, HHI_GCLK_OTHER, 16); +static GXBB_PCLK(gxbb_enc480p, HHI_GCLK_OTHER, 20); +static GXBB_PCLK(gxbb_rng1, HHI_GCLK_OTHER, 21); +static GXBB_PCLK(gxbb_gclk_venci_int1, HHI_GCLK_OTHER, 22); +static GXBB_PCLK(gxbb_vclk2_venclmcc, HHI_GCLK_OTHER, 24); +static GXBB_PCLK(gxbb_vclk2_vencl, HHI_GCLK_OTHER, 25); +static GXBB_PCLK(gxbb_vclk_other, HHI_GCLK_OTHER, 26); +static GXBB_PCLK(gxbb_edp, HHI_GCLK_OTHER, 31); /* Always On (AO) domain gates */ -static MESON_GATE(gxbb_ao_media_cpu, HHI_GCLK_AO, 0); -static MESON_GATE(gxbb_ao_ahb_sram, HHI_GCLK_AO, 1); -static MESON_GATE(gxbb_ao_ahb_bus, HHI_GCLK_AO, 2); -static MESON_GATE(gxbb_ao_iface, HHI_GCLK_AO, 3); -static MESON_GATE(gxbb_ao_i2c, HHI_GCLK_AO, 4); +static GXBB_PCLK(gxbb_ao_media_cpu, HHI_GCLK_AO, 0); +static GXBB_PCLK(gxbb_ao_ahb_sram, HHI_GCLK_AO, 1); +static GXBB_PCLK(gxbb_ao_ahb_bus, HHI_GCLK_AO, 2); +static GXBB_PCLK(gxbb_ao_iface, HHI_GCLK_AO, 3); +static GXBB_PCLK(gxbb_ao_i2c, HHI_GCLK_AO, 4); /* AIU gates */ -static MESON_PCLK(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6, &gxbb_aiu.hw); -static MESON_PCLK(gxbb_iec958, HHI_GCLK_MPEG1, 7, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_i2s_out, HHI_GCLK_MPEG1, 8, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_amclk, HHI_GCLK_MPEG1, 9, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_aififo2, HHI_GCLK_MPEG1, 10, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_mixer, HHI_GCLK_MPEG1, 11, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_adc, HHI_GCLK_MPEG1, 13, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6, &gxbb_aiu.hw); +static MESON_PCLK(gxbb_iec958, HHI_GCLK_MPEG1, 7, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_i2s_out, HHI_GCLK_MPEG1, 8, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_amclk, HHI_GCLK_MPEG1, 9, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_aififo2, HHI_GCLK_MPEG1, 10, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_mixer, HHI_GCLK_MPEG1, 11, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_adc, HHI_GCLK_MPEG1, 13, &gxbb_aiu_glue.hw); /* Array of all clocks provided by this provider */ @@ -2831,8 +2828,8 @@ static struct clk_hw *gxbb_hw_clks[] = { [CLKID_FCLK_DIV5] = &gxbb_fclk_div5.hw, [CLKID_FCLK_DIV7] = &gxbb_fclk_div7.hw, [CLKID_GP0_PLL] = &gxbb_gp0_pll.hw, - [CLKID_MPEG_SEL] = &gxbb_mpeg_clk_sel.hw, - [CLKID_MPEG_DIV] = &gxbb_mpeg_clk_div.hw, + [CLKID_MPEG_SEL] = &gxbb_clk81_sel.hw, + [CLKID_MPEG_DIV] = &gxbb_clk81_div.hw, [CLKID_CLK81] = &gxbb_clk81.hw, [CLKID_MPLL0] = &gxbb_mpll0.hw, [CLKID_MPLL1] = &gxbb_mpll1.hw, @@ -3039,8 +3036,8 @@ static struct clk_hw *gxl_hw_clks[] = { [CLKID_FCLK_DIV5] = &gxbb_fclk_div5.hw, [CLKID_FCLK_DIV7] = &gxbb_fclk_div7.hw, [CLKID_GP0_PLL] = &gxbb_gp0_pll.hw, - [CLKID_MPEG_SEL] = &gxbb_mpeg_clk_sel.hw, - [CLKID_MPEG_DIV] = &gxbb_mpeg_clk_div.hw, + [CLKID_MPEG_SEL] = &gxbb_clk81_sel.hw, + [CLKID_MPEG_DIV] = &gxbb_clk81_div.hw, [CLKID_CLK81] = &gxbb_clk81.hw, [CLKID_MPLL0] = &gxbb_mpll0.hw, [CLKID_MPLL1] = &gxbb_mpll1.hw, @@ -3251,21 +3248,21 @@ static const struct meson_eeclkc_data gxl_clkc_data = { }, }; -static const struct of_device_id clkc_match_table[] = { +static const struct of_device_id gxbb_clkc_match_table[] = { { .compatible = "amlogic,gxbb-clkc", .data = &gxbb_clkc_data }, { .compatible = "amlogic,gxl-clkc", .data = &gxl_clkc_data }, {}, }; -MODULE_DEVICE_TABLE(of, clkc_match_table); +MODULE_DEVICE_TABLE(of, gxbb_clkc_match_table); -static struct platform_driver gxbb_driver = { +static struct platform_driver gxbb_clkc_driver = { .probe = meson_eeclkc_probe, .driver = { .name = "gxbb-clkc", - .of_match_table = clkc_match_table, + .of_match_table = gxbb_clkc_match_table, }, }; -module_platform_driver(gxbb_driver); +module_platform_driver(gxbb_clkc_driver); MODULE_DESCRIPTION("Amlogic GXBB Main Clock Controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/meson/meson8-ddr.c b/drivers/clk/meson/meson8-ddr.c index 1975fc3987e2..6a9efde9b570 100644 --- a/drivers/clk/meson/meson8-ddr.c +++ b/drivers/clk/meson/meson8-ddr.c @@ -12,6 +12,7 @@ #include "clk-regmap.h" #include "clk-pll.h" +#include "meson-clkc-utils.h" #define AM_DDR_PLL_CNTL 0x00 #define AM_DDR_PLL_CNTL1 0x04 @@ -77,15 +78,17 @@ static struct clk_regmap meson8_ddr_pll = { }, }; -static struct clk_hw_onecell_data meson8_ddr_clk_hw_onecell_data = { - .hws = { - [DDR_CLKID_DDR_PLL_DCO] = &meson8_ddr_pll_dco.hw, - [DDR_CLKID_DDR_PLL] = &meson8_ddr_pll.hw, - }, - .num = 2, +static struct clk_hw *meson8_ddr_hw_clks[] = { + [DDR_CLKID_DDR_PLL_DCO] = &meson8_ddr_pll_dco.hw, + [DDR_CLKID_DDR_PLL] = &meson8_ddr_pll.hw, }; -static const struct regmap_config meson8_ddr_clkc_regmap_config = { +static struct meson_clk_hw_data meson8_ddr_clks = { + .hws = meson8_ddr_hw_clks, + .num = ARRAY_SIZE(meson8_ddr_hw_clks), +}; + +static const struct regmap_config meson8_ddr_regmap_cfg = { .reg_bits = 8, .val_bits = 32, .reg_stride = 4, @@ -104,13 +107,13 @@ static int meson8_ddr_clkc_probe(struct platform_device *pdev) return PTR_ERR(base); regmap = devm_regmap_init_mmio(&pdev->dev, base, - &meson8_ddr_clkc_regmap_config); + &meson8_ddr_regmap_cfg); if (IS_ERR(regmap)) return PTR_ERR(regmap); /* Register all clks */ - for (i = 0; i < meson8_ddr_clk_hw_onecell_data.num; i++) { - hw = meson8_ddr_clk_hw_onecell_data.hws[i]; + for (i = 0; i < meson8_ddr_clks.num; i++) { + hw = meson8_ddr_clks.hws[i]; ret = devm_clk_hw_register(&pdev->dev, hw); if (ret) { @@ -119,8 +122,8 @@ static int meson8_ddr_clkc_probe(struct platform_device *pdev) } } - return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get, - &meson8_ddr_clk_hw_onecell_data); + return devm_of_clk_add_hw_provider(&pdev->dev, meson_clk_hw_get, + &meson8_ddr_clks); } static const struct of_device_id meson8_ddr_clkc_match_table[] = { diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 206538326614..446e57d45d8d 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -214,7 +214,7 @@ static const struct reg_sequence meson8b_hdmi_pll_init_regs[] = { { .reg = HHI_VID2_PLL_CNTL2, .def = 0x0430a800 }, }; -static const struct pll_params_table hdmi_pll_params_table[] = { +static const struct pll_params_table meson8b_hdmi_pll_params_table[] = { PLL_PARAMS(40, 1), PLL_PARAMS(42, 1), PLL_PARAMS(44, 1), @@ -267,7 +267,7 @@ static struct clk_regmap meson8b_hdmi_pll_dco = { .shift = 29, .width = 1, }, - .table = hdmi_pll_params_table, + .table = meson8b_hdmi_pll_params_table, .init_regs = meson8b_hdmi_pll_init_regs, .init_count = ARRAY_SIZE(meson8b_hdmi_pll_init_regs), }, @@ -670,16 +670,17 @@ static struct clk_regmap meson8b_mpll2 = { }, }; -static u32 mux_table_clk81[] = { 6, 5, 7 }; -static struct clk_regmap meson8b_mpeg_clk_sel = { +/* clk81 is often referred as "mpeg_clk" */ +static u32 meson8b_clk81_parents_val_table[] = { 6, 5, 7 }; +static struct clk_regmap meson8b_clk81_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_MPEG_CLK_CNTL, .mask = 0x7, .shift = 12, - .table = mux_table_clk81, + .table = meson8b_clk81_parents_val_table, }, .hw.init = &(struct clk_init_data){ - .name = "mpeg_clk_sel", + .name = "clk81_sel", .ops = &clk_regmap_mux_ro_ops, /* * FIXME bits 14:12 selects from 8 possible parents: @@ -695,17 +696,17 @@ static struct clk_regmap meson8b_mpeg_clk_sel = { }, }; -static struct clk_regmap meson8b_mpeg_clk_div = { +static struct clk_regmap meson8b_clk81_div = { .data = &(struct clk_regmap_div_data){ .offset = HHI_MPEG_CLK_CNTL, .shift = 0, .width = 7, }, .hw.init = &(struct clk_init_data){ - .name = "mpeg_clk_div", + .name = "clk81_div", .ops = &clk_regmap_divider_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_mpeg_clk_sel.hw + &meson8b_clk81_sel.hw }, .num_parents = 1, }, @@ -720,7 +721,7 @@ static struct clk_regmap meson8b_clk81 = { .name = "clk81", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_mpeg_clk_div.hw + &meson8b_clk81_div.hw }, .num_parents = 1, .flags = CLK_IS_CRITICAL, @@ -774,7 +775,7 @@ static struct clk_fixed_factor meson8b_cpu_in_div3 = { }, }; -static const struct clk_div_table cpu_scale_table[] = { +static const struct clk_div_table meson8b_cpu_scale_div_table[] = { { .val = 1, .div = 4 }, { .val = 2, .div = 6 }, { .val = 3, .div = 8 }, @@ -791,7 +792,7 @@ static struct clk_regmap meson8b_cpu_scale_div = { .offset = HHI_SYS_CPU_CLK_CNTL1, .shift = 20, .width = 10, - .table = cpu_scale_table, + .table = meson8b_cpu_scale_div_table, .flags = CLK_DIVIDER_ALLOW_ZERO, }, .hw.init = &(struct clk_init_data){ @@ -805,13 +806,13 @@ static struct clk_regmap meson8b_cpu_scale_div = { }, }; -static u32 mux_table_cpu_scale_out_sel[] = { 0, 1, 3 }; +static u32 meson8b_cpu_scale_out_parents_val_table[] = { 0, 1, 3 }; static struct clk_regmap meson8b_cpu_scale_out_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL0, .mask = 0x3, .shift = 2, - .table = mux_table_cpu_scale_out_sel, + .table = meson8b_cpu_scale_out_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cpu_scale_out_sel", @@ -893,13 +894,13 @@ static struct clk_regmap meson8b_nand_clk_div = { }, }; -static struct clk_regmap meson8b_nand_clk_gate = { +static struct clk_regmap meson8b_nand_clk = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_NAND_CLK_CNTL, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "nand_clk_gate", + .name = "nand_clk", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_nand_clk_div.hw @@ -1000,160 +1001,137 @@ static struct clk_fixed_factor meson8b_cpu_clk_div8 = { }, }; -static u32 mux_table_apb[] = { 1, 2, 3, 4, 5, 6, 7 }; -static struct clk_regmap meson8b_apb_clk_sel = { +static u32 meson8b_cpu_if_parents_val_table[] = { 1, 2, 3, 4, 5, 6, 7 }; +static const struct clk_hw *meson8b_cpu_if_parents[] = { + &meson8b_cpu_clk_div2.hw, + &meson8b_cpu_clk_div3.hw, + &meson8b_cpu_clk_div4.hw, + &meson8b_cpu_clk_div5.hw, + &meson8b_cpu_clk_div6.hw, + &meson8b_cpu_clk_div7.hw, + &meson8b_cpu_clk_div8.hw, +}; + +static struct clk_regmap meson8b_apb_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .mask = 0x7, .shift = 3, - .table = mux_table_apb, + .table = meson8b_cpu_if_parents_val_table, }, .hw.init = &(struct clk_init_data){ - .name = "apb_clk_sel", + .name = "apb_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = (const struct clk_hw *[]) { - &meson8b_cpu_clk_div2.hw, - &meson8b_cpu_clk_div3.hw, - &meson8b_cpu_clk_div4.hw, - &meson8b_cpu_clk_div5.hw, - &meson8b_cpu_clk_div6.hw, - &meson8b_cpu_clk_div7.hw, - &meson8b_cpu_clk_div8.hw, - }, - .num_parents = 7, + .parent_hws = meson8b_cpu_if_parents, + .num_parents = ARRAY_SIZE(meson8b_cpu_if_parents), }, }; -static struct clk_regmap meson8b_apb_clk_gate = { +static struct clk_regmap meson8b_apb = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .bit_idx = 16, .flags = CLK_GATE_SET_TO_DISABLE, }, .hw.init = &(struct clk_init_data){ - .name = "apb_clk_dis", + .name = "apb", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_apb_clk_sel.hw + &meson8b_apb_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap meson8b_periph_clk_sel = { +static struct clk_regmap meson8b_periph_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .mask = 0x7, .shift = 6, }, .hw.init = &(struct clk_init_data){ - .name = "periph_clk_sel", + .name = "periph_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = (const struct clk_hw *[]) { - &meson8b_cpu_clk_div2.hw, - &meson8b_cpu_clk_div3.hw, - &meson8b_cpu_clk_div4.hw, - &meson8b_cpu_clk_div5.hw, - &meson8b_cpu_clk_div6.hw, - &meson8b_cpu_clk_div7.hw, - &meson8b_cpu_clk_div8.hw, - }, - .num_parents = 7, + .parent_hws = meson8b_cpu_if_parents, + .num_parents = ARRAY_SIZE(meson8b_cpu_if_parents), }, }; -static struct clk_regmap meson8b_periph_clk_gate = { +static struct clk_regmap meson8b_periph = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .bit_idx = 17, .flags = CLK_GATE_SET_TO_DISABLE, }, .hw.init = &(struct clk_init_data){ - .name = "periph_clk_dis", + .name = "periph", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_periph_clk_sel.hw + &meson8b_periph_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static u32 mux_table_axi[] = { 1, 2, 3, 4, 5, 6, 7 }; -static struct clk_regmap meson8b_axi_clk_sel = { +static struct clk_regmap meson8b_axi_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .mask = 0x7, .shift = 9, - .table = mux_table_axi, + .table = meson8b_cpu_if_parents_val_table, }, .hw.init = &(struct clk_init_data){ - .name = "axi_clk_sel", + .name = "axi_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = (const struct clk_hw *[]) { - &meson8b_cpu_clk_div2.hw, - &meson8b_cpu_clk_div3.hw, - &meson8b_cpu_clk_div4.hw, - &meson8b_cpu_clk_div5.hw, - &meson8b_cpu_clk_div6.hw, - &meson8b_cpu_clk_div7.hw, - &meson8b_cpu_clk_div8.hw, - }, - .num_parents = 7, + .parent_hws = meson8b_cpu_if_parents, + .num_parents = ARRAY_SIZE(meson8b_cpu_if_parents), }, }; -static struct clk_regmap meson8b_axi_clk_gate = { +static struct clk_regmap meson8b_axi = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .bit_idx = 18, .flags = CLK_GATE_SET_TO_DISABLE, }, .hw.init = &(struct clk_init_data){ - .name = "axi_clk_dis", + .name = "axi", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_axi_clk_sel.hw + &meson8b_axi_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap meson8b_l2_dram_clk_sel = { +static struct clk_regmap meson8b_l2_dram_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .mask = 0x7, .shift = 12, }, .hw.init = &(struct clk_init_data){ - .name = "l2_dram_clk_sel", + .name = "l2_dram_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = (const struct clk_hw *[]) { - &meson8b_cpu_clk_div2.hw, - &meson8b_cpu_clk_div3.hw, - &meson8b_cpu_clk_div4.hw, - &meson8b_cpu_clk_div5.hw, - &meson8b_cpu_clk_div6.hw, - &meson8b_cpu_clk_div7.hw, - &meson8b_cpu_clk_div8.hw, - }, - .num_parents = 7, + .parent_hws = meson8b_cpu_if_parents, + .num_parents = ARRAY_SIZE(meson8b_cpu_if_parents), }, }; -static struct clk_regmap meson8b_l2_dram_clk_gate = { +static struct clk_regmap meson8b_l2_dram = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .bit_idx = 19, .flags = CLK_GATE_SET_TO_DISABLE, }, .hw.init = &(struct clk_init_data){ - .name = "l2_dram_clk_dis", + .name = "l2_dram", .ops = &clk_regmap_gate_ro_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_l2_dram_clk_sel.hw + &meson8b_l2_dram_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1286,7 +1264,7 @@ static struct clk_regmap meson8b_vid_pll_final_div = { }, }; -static const struct clk_hw *meson8b_vclk_mux_parent_hws[] = { +static const struct clk_hw *meson8b_vclk_parents[] = { &meson8b_vid_pll_final_div.hw, &meson8b_fclk_div4.hw, &meson8b_fclk_div3.hw, @@ -1305,8 +1283,8 @@ static struct clk_regmap meson8b_vclk_in_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk_in_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vclk_mux_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws), + .parent_hws = meson8b_vclk_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_parents), .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, }, }; @@ -1343,13 +1321,13 @@ static struct clk_regmap meson8b_vclk_en = { }, }; -static struct clk_regmap meson8b_vclk_div1_gate = { +static struct clk_regmap meson8b_vclk_div1 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VID_CLK_CNTL, .bit_idx = 0, }, .hw.init = &(struct clk_init_data){ - .name = "vclk_div1_en", + .name = "vclk_div1", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_en.hw @@ -1363,7 +1341,7 @@ static struct clk_fixed_factor meson8b_vclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "vclk_div2", + .name = "vclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_en.hw @@ -1373,13 +1351,13 @@ static struct clk_fixed_factor meson8b_vclk_div2_div = { } }; -static struct clk_regmap meson8b_vclk_div2_div_gate = { +static struct clk_regmap meson8b_vclk_div2 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VID_CLK_CNTL, .bit_idx = 1, }, .hw.init = &(struct clk_init_data){ - .name = "vclk_div2_en", + .name = "vclk_div2", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_div2_div.hw @@ -1393,7 +1371,7 @@ static struct clk_fixed_factor meson8b_vclk_div4_div = { .mult = 1, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "vclk_div4", + .name = "vclk_div4_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_en.hw @@ -1403,13 +1381,13 @@ static struct clk_fixed_factor meson8b_vclk_div4_div = { } }; -static struct clk_regmap meson8b_vclk_div4_div_gate = { +static struct clk_regmap meson8b_vclk_div4 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VID_CLK_CNTL, .bit_idx = 2, }, .hw.init = &(struct clk_init_data){ - .name = "vclk_div4_en", + .name = "vclk_div4", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_div4_div.hw @@ -1423,7 +1401,7 @@ static struct clk_fixed_factor meson8b_vclk_div6_div = { .mult = 1, .div = 6, .hw.init = &(struct clk_init_data){ - .name = "vclk_div6", + .name = "vclk_div6_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_en.hw @@ -1433,13 +1411,13 @@ static struct clk_fixed_factor meson8b_vclk_div6_div = { } }; -static struct clk_regmap meson8b_vclk_div6_div_gate = { +static struct clk_regmap meson8b_vclk_div6 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VID_CLK_CNTL, .bit_idx = 3, }, .hw.init = &(struct clk_init_data){ - .name = "vclk_div6_en", + .name = "vclk_div6", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_div6_div.hw @@ -1453,7 +1431,7 @@ static struct clk_fixed_factor meson8b_vclk_div12_div = { .mult = 1, .div = 12, .hw.init = &(struct clk_init_data){ - .name = "vclk_div12", + .name = "vclk_div12_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_en.hw @@ -1463,13 +1441,13 @@ static struct clk_fixed_factor meson8b_vclk_div12_div = { } }; -static struct clk_regmap meson8b_vclk_div12_div_gate = { +static struct clk_regmap meson8b_vclk_div12 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VID_CLK_CNTL, .bit_idx = 4, }, .hw.init = &(struct clk_init_data){ - .name = "vclk_div12_en", + .name = "vclk_div12", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_div12_div.hw @@ -1488,13 +1466,13 @@ static struct clk_regmap meson8b_vclk2_in_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk2_in_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vclk_mux_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws), + .parent_hws = meson8b_vclk_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_parents), .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, }, }; -static struct clk_regmap meson8b_vclk2_clk_in_en = { +static struct clk_regmap meson8b_vclk2_in_en = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VIID_CLK_DIV, .bit_idx = 16, @@ -1510,7 +1488,7 @@ static struct clk_regmap meson8b_vclk2_clk_in_en = { }, }; -static struct clk_regmap meson8b_vclk2_clk_en = { +static struct clk_regmap meson8b_vclk2_en = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VIID_CLK_DIV, .bit_idx = 19, @@ -1519,23 +1497,23 @@ static struct clk_regmap meson8b_vclk2_clk_en = { .name = "vclk2_en", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_vclk2_clk_in_en.hw + &meson8b_vclk2_in_en.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap meson8b_vclk2_div1_gate = { +static struct clk_regmap meson8b_vclk2_div1 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VIID_CLK_DIV, .bit_idx = 0, }, .hw.init = &(struct clk_init_data){ - .name = "vclk2_div1_en", + .name = "vclk2_div1", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_vclk2_clk_en.hw + &meson8b_vclk2_en.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1546,23 +1524,23 @@ static struct clk_fixed_factor meson8b_vclk2_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "vclk2_div2", + .name = "vclk2_div2_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_vclk2_clk_en.hw + &meson8b_vclk2_en.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } }; -static struct clk_regmap meson8b_vclk2_div2_div_gate = { +static struct clk_regmap meson8b_vclk2_div2 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VIID_CLK_DIV, .bit_idx = 1, }, .hw.init = &(struct clk_init_data){ - .name = "vclk2_div2_en", + .name = "vclk2_div2", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_div2_div.hw @@ -1576,23 +1554,23 @@ static struct clk_fixed_factor meson8b_vclk2_div4_div = { .mult = 1, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "vclk2_div4", + .name = "vclk2_div4_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_vclk2_clk_en.hw + &meson8b_vclk2_en.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } }; -static struct clk_regmap meson8b_vclk2_div4_div_gate = { +static struct clk_regmap meson8b_vclk2_div4 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VIID_CLK_DIV, .bit_idx = 2, }, .hw.init = &(struct clk_init_data){ - .name = "vclk2_div4_en", + .name = "vclk2_div4", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_div4_div.hw @@ -1606,23 +1584,23 @@ static struct clk_fixed_factor meson8b_vclk2_div6_div = { .mult = 1, .div = 6, .hw.init = &(struct clk_init_data){ - .name = "vclk2_div6", + .name = "vclk2_div6_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_vclk2_clk_en.hw + &meson8b_vclk2_en.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } }; -static struct clk_regmap meson8b_vclk2_div6_div_gate = { +static struct clk_regmap meson8b_vclk2_div6 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VIID_CLK_DIV, .bit_idx = 3, }, .hw.init = &(struct clk_init_data){ - .name = "vclk2_div6_en", + .name = "vclk2_div6", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_div6_div.hw @@ -1636,23 +1614,23 @@ static struct clk_fixed_factor meson8b_vclk2_div12_div = { .mult = 1, .div = 12, .hw.init = &(struct clk_init_data){ - .name = "vclk2_div12", + .name = "vclk2_div12_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &meson8b_vclk2_clk_en.hw + &meson8b_vclk2_en.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, } }; -static struct clk_regmap meson8b_vclk2_div12_div_gate = { +static struct clk_regmap meson8b_vclk2_div12 = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VIID_CLK_DIV, .bit_idx = 4, }, .hw.init = &(struct clk_init_data){ - .name = "vclk2_div12_en", + .name = "vclk2_div12", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_div12_div.hw @@ -1662,12 +1640,12 @@ static struct clk_regmap meson8b_vclk2_div12_div_gate = { }, }; -static const struct clk_hw *meson8b_vclk_enc_mux_parent_hws[] = { - &meson8b_vclk_div1_gate.hw, - &meson8b_vclk_div2_div_gate.hw, - &meson8b_vclk_div4_div_gate.hw, - &meson8b_vclk_div6_div_gate.hw, - &meson8b_vclk_div12_div_gate.hw, +static const struct clk_hw *meson8b_vclk_enc_parents[] = { + &meson8b_vclk_div1.hw, + &meson8b_vclk_div2.hw, + &meson8b_vclk_div4.hw, + &meson8b_vclk_div6.hw, + &meson8b_vclk_div12.hw, }; static struct clk_regmap meson8b_cts_enct_sel = { @@ -1679,8 +1657,8 @@ static struct clk_regmap meson8b_cts_enct_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_enct_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vclk_enc_mux_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1710,8 +1688,8 @@ static struct clk_regmap meson8b_cts_encp_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_encp_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vclk_enc_mux_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1741,8 +1719,8 @@ static struct clk_regmap meson8b_cts_enci_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_enci_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vclk_enc_mux_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1772,8 +1750,8 @@ static struct clk_regmap meson8b_hdmi_tx_pixel_sel = { .hw.init = &(struct clk_init_data){ .name = "hdmi_tx_pixel_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vclk_enc_mux_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1794,14 +1772,6 @@ static struct clk_regmap meson8b_hdmi_tx_pixel = { }, }; -static const struct clk_hw *meson8b_vclk2_enc_mux_parent_hws[] = { - &meson8b_vclk2_div1_gate.hw, - &meson8b_vclk2_div2_div_gate.hw, - &meson8b_vclk2_div4_div_gate.hw, - &meson8b_vclk2_div6_div_gate.hw, - &meson8b_vclk2_div12_div_gate.hw, -}; - static struct clk_regmap meson8b_cts_encl_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_VIID_CLK_DIV, @@ -1811,8 +1781,8 @@ static struct clk_regmap meson8b_cts_encl_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_encl_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vclk2_enc_mux_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parent_hws), + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1842,8 +1812,8 @@ static struct clk_regmap meson8b_cts_vdac0_sel = { .hw.init = &(struct clk_init_data){ .name = "cts_vdac0_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vclk2_enc_mux_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parent_hws), + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1926,7 +1896,8 @@ static struct clk_regmap meson8b_hdmi_sys = { * CLK_SET_RATE_GATE is set. * Meson8 only has mali_0 and no glitch-free mux. */ -static const struct clk_parent_data meson8b_mali_0_1_parent_data[] = { +static u32 meson8b_mali_parents_val_table[] = { 0, 2, 3, 4, 5, 6, 7 }; +static const struct clk_parent_data meson8b_mali_parents[] = { { .fw_name = "xtal", .name = "xtal", .index = -1, }, { .hw = &meson8b_mpll2.hw, }, { .hw = &meson8b_mpll1.hw, }, @@ -1936,20 +1907,18 @@ static const struct clk_parent_data meson8b_mali_0_1_parent_data[] = { { .hw = &meson8b_fclk_div5.hw, }, }; -static u32 meson8b_mali_0_1_mux_table[] = { 0, 2, 3, 4, 5, 6, 7 }; - static struct clk_regmap meson8b_mali_0_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_MALI_CLK_CNTL, .mask = 0x7, .shift = 9, - .table = meson8b_mali_0_1_mux_table, + .table = meson8b_mali_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "mali_0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = meson8b_mali_0_1_parent_data, - .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_data), + .parent_data = meson8b_mali_parents, + .num_parents = ARRAY_SIZE(meson8b_mali_parents), /* * Don't propagate rate changes up because the only changeable * parents are mpll1 and mpll2 but we need those for audio and @@ -1998,13 +1967,13 @@ static struct clk_regmap meson8b_mali_1_sel = { .offset = HHI_MALI_CLK_CNTL, .mask = 0x7, .shift = 25, - .table = meson8b_mali_0_1_mux_table, + .table = meson8b_mali_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "mali_1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = meson8b_mali_0_1_parent_data, - .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_data), + .parent_data = meson8b_mali_parents, + .num_parents = ARRAY_SIZE(meson8b_mali_parents), /* * Don't propagate rate changes up because the only changeable * parents are mpll1 and mpll2 but we need those for audio and @@ -2139,20 +2108,13 @@ static struct clk_regmap meson8m2_gp_pll = { }, }; -static const struct clk_hw *meson8b_vpu_0_1_parent_hws[] = { +static const struct clk_hw *meson8b_vpu_parents[] = { &meson8b_fclk_div4.hw, &meson8b_fclk_div3.hw, &meson8b_fclk_div5.hw, &meson8b_fclk_div7.hw, }; -static const struct clk_hw *mmeson8m2_vpu_0_1_parent_hws[] = { - &meson8b_fclk_div4.hw, - &meson8b_fclk_div3.hw, - &meson8b_fclk_div5.hw, - &meson8m2_gp_pll.hw, -}; - static struct clk_regmap meson8b_vpu_0_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_VPU_CLK_CNTL, @@ -2162,12 +2124,19 @@ static struct clk_regmap meson8b_vpu_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vpu_0_1_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_hws), + .parent_hws = meson8b_vpu_parents, + .num_parents = ARRAY_SIZE(meson8b_vpu_parents), .flags = CLK_SET_RATE_PARENT, }, }; +static const struct clk_hw *mmeson8m2_vpu_parents[] = { + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, + &meson8m2_gp_pll.hw, +}; + static struct clk_regmap meson8m2_vpu_0_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_VPU_CLK_CNTL, @@ -2177,8 +2146,8 @@ static struct clk_regmap meson8m2_vpu_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = mmeson8m2_vpu_0_1_parent_hws, - .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_hws), + .parent_hws = mmeson8m2_vpu_parents, + .num_parents = ARRAY_SIZE(mmeson8m2_vpu_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2233,8 +2202,8 @@ static struct clk_regmap meson8b_vpu_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vpu_0_1_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_hws), + .parent_hws = meson8b_vpu_parents, + .num_parents = ARRAY_SIZE(meson8b_vpu_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2248,8 +2217,8 @@ static struct clk_regmap meson8m2_vpu_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = mmeson8m2_vpu_0_1_parent_hws, - .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_hws), + .parent_hws = mmeson8m2_vpu_parents, + .num_parents = ARRAY_SIZE(mmeson8m2_vpu_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2321,7 +2290,7 @@ static struct clk_regmap meson8b_vpu = { }, }; -static const struct clk_hw *meson8b_vdec_parent_hws[] = { +static const struct clk_hw *meson8b_vdec_parents[] = { &meson8b_fclk_div4.hw, &meson8b_fclk_div3.hw, &meson8b_fclk_div5.hw, @@ -2340,8 +2309,8 @@ static struct clk_regmap meson8b_vdec_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_1_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vdec_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), + .parent_hws = meson8b_vdec_parents, + .num_parents = ARRAY_SIZE(meson8b_vdec_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2443,8 +2412,8 @@ static struct clk_regmap meson8b_vdec_hcodec_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_hcodec_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vdec_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), + .parent_hws = meson8b_vdec_parents, + .num_parents = ARRAY_SIZE(meson8b_vdec_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2493,8 +2462,8 @@ static struct clk_regmap meson8b_vdec_2_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_2_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vdec_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), + .parent_hws = meson8b_vdec_parents, + .num_parents = ARRAY_SIZE(meson8b_vdec_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2543,8 +2512,8 @@ static struct clk_regmap meson8b_vdec_hevc_sel = { .hw.init = &(struct clk_init_data){ .name = "vdec_hevc_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_vdec_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), + .parent_hws = meson8b_vdec_parents, + .num_parents = ARRAY_SIZE(meson8b_vdec_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2603,27 +2572,26 @@ static struct clk_regmap meson8b_vdec_hevc = { }; /* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */ -static const struct clk_hw *meson8b_cts_amclk_parent_hws[] = { +static u32 meson8b_cts_mclk_parents_val_table[] = { 1, 2, 3 }; +static const struct clk_hw *meson8b_cts_mclk_parents[] = { &meson8b_mpll0.hw, &meson8b_mpll1.hw, &meson8b_mpll2.hw }; -static u32 meson8b_cts_amclk_mux_table[] = { 1, 2, 3 }; - static struct clk_regmap meson8b_cts_amclk_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_AUD_CLK_CNTL, .mask = 0x3, .shift = 9, - .table = meson8b_cts_amclk_mux_table, + .table = meson8b_cts_mclk_parents_val_table, .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ .name = "cts_amclk_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_cts_amclk_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_cts_amclk_parent_hws), + .parent_hws = meson8b_cts_mclk_parents, + .num_parents = ARRAY_SIZE(meson8b_cts_mclk_parents), }, }; @@ -2661,28 +2629,19 @@ static struct clk_regmap meson8b_cts_amclk = { }, }; -/* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */ -static const struct clk_hw *meson8b_cts_mclk_i958_parent_hws[] = { - &meson8b_mpll0.hw, - &meson8b_mpll1.hw, - &meson8b_mpll2.hw -}; - -static u32 meson8b_cts_mclk_i958_mux_table[] = { 1, 2, 3 }; - static struct clk_regmap meson8b_cts_mclk_i958_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_AUD_CLK_CNTL2, .mask = 0x3, .shift = 25, - .table = meson8b_cts_mclk_i958_mux_table, + .table = meson8b_cts_mclk_parents_val_table, .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = meson8b_cts_mclk_i958_parent_hws, - .num_parents = ARRAY_SIZE(meson8b_cts_mclk_i958_parent_hws), + .parent_hws = meson8b_cts_mclk_parents, + .num_parents = ARRAY_SIZE(meson8b_cts_mclk_parents), }, }; @@ -2742,113 +2701,114 @@ static struct clk_regmap meson8b_cts_i958 = { }, }; -#define MESON_GATE(_name, _reg, _bit) \ +#define MESON8B_PCLK(_name, _reg, _bit) \ MESON_PCLK(_name, _reg, _bit, &meson8b_clk81.hw) /* Everything Else (EE) domain gates */ -static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); -static MESON_GATE(meson8b_dos, HHI_GCLK_MPEG0, 1); -static MESON_GATE(meson8b_isa, HHI_GCLK_MPEG0, 5); -static MESON_GATE(meson8b_pl301, HHI_GCLK_MPEG0, 6); -static MESON_GATE(meson8b_periphs, HHI_GCLK_MPEG0, 7); -static MESON_GATE(meson8b_spicc, HHI_GCLK_MPEG0, 8); -static MESON_GATE(meson8b_i2c, HHI_GCLK_MPEG0, 9); -static MESON_GATE(meson8b_sar_adc, HHI_GCLK_MPEG0, 10); -static MESON_GATE(meson8b_smart_card, HHI_GCLK_MPEG0, 11); -static MESON_GATE(meson8b_rng0, HHI_GCLK_MPEG0, 12); -static MESON_GATE(meson8b_uart0, HHI_GCLK_MPEG0, 13); -static MESON_GATE(meson8b_sdhc, HHI_GCLK_MPEG0, 14); -static MESON_GATE(meson8b_stream, HHI_GCLK_MPEG0, 15); -static MESON_GATE(meson8b_async_fifo, HHI_GCLK_MPEG0, 16); -static MESON_GATE(meson8b_sdio, HHI_GCLK_MPEG0, 17); -static MESON_GATE(meson8b_abuf, HHI_GCLK_MPEG0, 18); -static MESON_GATE(meson8b_hiu_iface, HHI_GCLK_MPEG0, 19); -static MESON_GATE(meson8b_assist_misc, HHI_GCLK_MPEG0, 23); -static MESON_GATE(meson8b_spi, HHI_GCLK_MPEG0, 30); +static MESON8B_PCLK(meson8b_ddr, HHI_GCLK_MPEG0, 0); +static MESON8B_PCLK(meson8b_dos, HHI_GCLK_MPEG0, 1); +static MESON8B_PCLK(meson8b_isa, HHI_GCLK_MPEG0, 5); +static MESON8B_PCLK(meson8b_pl301, HHI_GCLK_MPEG0, 6); +static MESON8B_PCLK(meson8b_periphs, HHI_GCLK_MPEG0, 7); +static MESON8B_PCLK(meson8b_spicc, HHI_GCLK_MPEG0, 8); +static MESON8B_PCLK(meson8b_i2c, HHI_GCLK_MPEG0, 9); +static MESON8B_PCLK(meson8b_sar_adc, HHI_GCLK_MPEG0, 10); +static MESON8B_PCLK(meson8b_smart_card, HHI_GCLK_MPEG0, 11); +static MESON8B_PCLK(meson8b_rng0, HHI_GCLK_MPEG0, 12); +static MESON8B_PCLK(meson8b_uart0, HHI_GCLK_MPEG0, 13); +static MESON8B_PCLK(meson8b_sdhc, HHI_GCLK_MPEG0, 14); +static MESON8B_PCLK(meson8b_stream, HHI_GCLK_MPEG0, 15); +static MESON8B_PCLK(meson8b_async_fifo, HHI_GCLK_MPEG0, 16); +static MESON8B_PCLK(meson8b_sdio, HHI_GCLK_MPEG0, 17); +static MESON8B_PCLK(meson8b_abuf, HHI_GCLK_MPEG0, 18); +static MESON8B_PCLK(meson8b_hiu_iface, HHI_GCLK_MPEG0, 19); +static MESON8B_PCLK(meson8b_assist_misc, HHI_GCLK_MPEG0, 23); +static MESON8B_PCLK(meson8b_spi, HHI_GCLK_MPEG0, 30); -static MESON_GATE(meson8b_i2s_spdif, HHI_GCLK_MPEG1, 2); -static MESON_GATE(meson8b_eth, HHI_GCLK_MPEG1, 3); -static MESON_GATE(meson8b_demux, HHI_GCLK_MPEG1, 4); -static MESON_GATE(meson8b_blkmv, HHI_GCLK_MPEG1, 14); -static MESON_GATE(meson8b_aiu, HHI_GCLK_MPEG1, 15); -static MESON_GATE(meson8b_uart1, HHI_GCLK_MPEG1, 16); -static MESON_GATE(meson8b_g2d, HHI_GCLK_MPEG1, 20); -static MESON_GATE(meson8b_usb0, HHI_GCLK_MPEG1, 21); -static MESON_GATE(meson8b_usb1, HHI_GCLK_MPEG1, 22); -static MESON_GATE(meson8b_reset, HHI_GCLK_MPEG1, 23); -static MESON_GATE(meson8b_nand, HHI_GCLK_MPEG1, 24); -static MESON_GATE(meson8b_dos_parser, HHI_GCLK_MPEG1, 25); -static MESON_GATE(meson8b_usb, HHI_GCLK_MPEG1, 26); -static MESON_GATE(meson8b_vdin1, HHI_GCLK_MPEG1, 28); -static MESON_GATE(meson8b_ahb_arb0, HHI_GCLK_MPEG1, 29); -static MESON_GATE(meson8b_efuse, HHI_GCLK_MPEG1, 30); -static MESON_GATE(meson8b_boot_rom, HHI_GCLK_MPEG1, 31); +static MESON8B_PCLK(meson8b_i2s_spdif, HHI_GCLK_MPEG1, 2); +static MESON8B_PCLK(meson8b_eth, HHI_GCLK_MPEG1, 3); +static MESON8B_PCLK(meson8b_demux, HHI_GCLK_MPEG1, 4); +static MESON8B_PCLK(meson8b_blkmv, HHI_GCLK_MPEG1, 14); +static MESON8B_PCLK(meson8b_aiu, HHI_GCLK_MPEG1, 15); +static MESON8B_PCLK(meson8b_uart1, HHI_GCLK_MPEG1, 16); +static MESON8B_PCLK(meson8b_g2d, HHI_GCLK_MPEG1, 20); +static MESON8B_PCLK(meson8b_usb0, HHI_GCLK_MPEG1, 21); +static MESON8B_PCLK(meson8b_usb1, HHI_GCLK_MPEG1, 22); +static MESON8B_PCLK(meson8b_reset, HHI_GCLK_MPEG1, 23); +static MESON8B_PCLK(meson8b_nand, HHI_GCLK_MPEG1, 24); +static MESON8B_PCLK(meson8b_dos_parser, HHI_GCLK_MPEG1, 25); +static MESON8B_PCLK(meson8b_usb, HHI_GCLK_MPEG1, 26); +static MESON8B_PCLK(meson8b_vdin1, HHI_GCLK_MPEG1, 28); +static MESON8B_PCLK(meson8b_ahb_arb0, HHI_GCLK_MPEG1, 29); +static MESON8B_PCLK(meson8b_efuse, HHI_GCLK_MPEG1, 30); +static MESON8B_PCLK(meson8b_boot_rom, HHI_GCLK_MPEG1, 31); -static MESON_GATE(meson8b_ahb_data_bus, HHI_GCLK_MPEG2, 1); -static MESON_GATE(meson8b_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); -static MESON_GATE(meson8b_hdmi_intr_sync, HHI_GCLK_MPEG2, 3); -static MESON_GATE(meson8b_hdmi_pclk, HHI_GCLK_MPEG2, 4); -static MESON_GATE(meson8b_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); -static MESON_GATE(meson8b_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); -static MESON_GATE(meson8b_mmc_pclk, HHI_GCLK_MPEG2, 11); -static MESON_GATE(meson8b_dvin, HHI_GCLK_MPEG2, 12); -static MESON_GATE(meson8b_uart2, HHI_GCLK_MPEG2, 15); -static MESON_GATE(meson8b_sana, HHI_GCLK_MPEG2, 22); -static MESON_GATE(meson8b_vpu_intr, HHI_GCLK_MPEG2, 25); -static MESON_GATE(meson8b_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); -static MESON_GATE(meson8b_clk81_a9, HHI_GCLK_MPEG2, 29); +static MESON8B_PCLK(meson8b_ahb_data_bus, HHI_GCLK_MPEG2, 1); +static MESON8B_PCLK(meson8b_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static MESON8B_PCLK(meson8b_hdmi_intr_sync, HHI_GCLK_MPEG2, 3); +static MESON8B_PCLK(meson8b_hdmi_pclk, HHI_GCLK_MPEG2, 4); +static MESON8B_PCLK(meson8b_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); +static MESON8B_PCLK(meson8b_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); +static MESON8B_PCLK(meson8b_mmc_pclk, HHI_GCLK_MPEG2, 11); +static MESON8B_PCLK(meson8b_dvin, HHI_GCLK_MPEG2, 12); +static MESON8B_PCLK(meson8b_uart2, HHI_GCLK_MPEG2, 15); +static MESON8B_PCLK(meson8b_sana, HHI_GCLK_MPEG2, 22); +static MESON8B_PCLK(meson8b_vpu_intr, HHI_GCLK_MPEG2, 25); +static MESON8B_PCLK(meson8b_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); +static MESON8B_PCLK(meson8b_clk81_a9, HHI_GCLK_MPEG2, 29); -static MESON_GATE(meson8b_vclk2_venci0, HHI_GCLK_OTHER, 1); -static MESON_GATE(meson8b_vclk2_venci1, HHI_GCLK_OTHER, 2); -static MESON_GATE(meson8b_vclk2_vencp0, HHI_GCLK_OTHER, 3); -static MESON_GATE(meson8b_vclk2_vencp1, HHI_GCLK_OTHER, 4); -static MESON_GATE(meson8b_gclk_venci_int, HHI_GCLK_OTHER, 8); -static MESON_GATE(meson8b_gclk_vencp_int, HHI_GCLK_OTHER, 9); -static MESON_GATE(meson8b_dac_clk, HHI_GCLK_OTHER, 10); -static MESON_GATE(meson8b_aoclk_gate, HHI_GCLK_OTHER, 14); -static MESON_GATE(meson8b_iec958_gate, HHI_GCLK_OTHER, 16); -static MESON_GATE(meson8b_enc480p, HHI_GCLK_OTHER, 20); -static MESON_GATE(meson8b_rng1, HHI_GCLK_OTHER, 21); -static MESON_GATE(meson8b_gclk_vencl_int, HHI_GCLK_OTHER, 22); -static MESON_GATE(meson8b_vclk2_venclmcc, HHI_GCLK_OTHER, 24); -static MESON_GATE(meson8b_vclk2_vencl, HHI_GCLK_OTHER, 25); -static MESON_GATE(meson8b_vclk2_other, HHI_GCLK_OTHER, 26); -static MESON_GATE(meson8b_edp, HHI_GCLK_OTHER, 31); +static MESON8B_PCLK(meson8b_vclk2_venci0, HHI_GCLK_OTHER, 1); +static MESON8B_PCLK(meson8b_vclk2_venci1, HHI_GCLK_OTHER, 2); +static MESON8B_PCLK(meson8b_vclk2_vencp0, HHI_GCLK_OTHER, 3); +static MESON8B_PCLK(meson8b_vclk2_vencp1, HHI_GCLK_OTHER, 4); +static MESON8B_PCLK(meson8b_gclk_venci_int, HHI_GCLK_OTHER, 8); +static MESON8B_PCLK(meson8b_gclk_vencp_int, HHI_GCLK_OTHER, 9); +static MESON8B_PCLK(meson8b_dac_clk, HHI_GCLK_OTHER, 10); +static MESON8B_PCLK(meson8b_aoclk_gate, HHI_GCLK_OTHER, 14); +static MESON8B_PCLK(meson8b_iec958_gate, HHI_GCLK_OTHER, 16); +static MESON8B_PCLK(meson8b_enc480p, HHI_GCLK_OTHER, 20); +static MESON8B_PCLK(meson8b_rng1, HHI_GCLK_OTHER, 21); +static MESON8B_PCLK(meson8b_gclk_vencl_int, HHI_GCLK_OTHER, 22); +static MESON8B_PCLK(meson8b_vclk2_venclmcc, HHI_GCLK_OTHER, 24); +static MESON8B_PCLK(meson8b_vclk2_vencl, HHI_GCLK_OTHER, 25); +static MESON8B_PCLK(meson8b_vclk2_other, HHI_GCLK_OTHER, 26); +static MESON8B_PCLK(meson8b_edp, HHI_GCLK_OTHER, 31); /* AIU gates */ -#define MESON_AIU_GLUE_GATE(_name, _reg, _bit) \ +static MESON_PCLK(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6, &meson8b_aiu.hw); + +#define MESON_AIU_PCLK(_name, _reg, _bit) \ MESON_PCLK(_name, _reg, _bit, &meson8b_aiu_glue.hw) -static MESON_PCLK(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6, &meson8b_aiu.hw); -static MESON_AIU_GLUE_GATE(meson8b_iec958, HHI_GCLK_MPEG1, 7); -static MESON_AIU_GLUE_GATE(meson8b_i2s_out, HHI_GCLK_MPEG1, 8); -static MESON_AIU_GLUE_GATE(meson8b_amclk, HHI_GCLK_MPEG1, 9); -static MESON_AIU_GLUE_GATE(meson8b_aififo2, HHI_GCLK_MPEG1, 10); -static MESON_AIU_GLUE_GATE(meson8b_mixer, HHI_GCLK_MPEG1, 11); -static MESON_AIU_GLUE_GATE(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12); -static MESON_AIU_GLUE_GATE(meson8b_adc, HHI_GCLK_MPEG1, 13); +static MESON_AIU_PCLK(meson8b_iec958, HHI_GCLK_MPEG1, 7); +static MESON_AIU_PCLK(meson8b_i2s_out, HHI_GCLK_MPEG1, 8); +static MESON_AIU_PCLK(meson8b_amclk, HHI_GCLK_MPEG1, 9); +static MESON_AIU_PCLK(meson8b_aififo2, HHI_GCLK_MPEG1, 10); +static MESON_AIU_PCLK(meson8b_mixer, HHI_GCLK_MPEG1, 11); +static MESON_AIU_PCLK(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12); +static MESON_AIU_PCLK(meson8b_adc, HHI_GCLK_MPEG1, 13); /* Always On (AO) domain gates */ -static MESON_GATE(meson8b_ao_media_cpu, HHI_GCLK_AO, 0); -static MESON_GATE(meson8b_ao_ahb_sram, HHI_GCLK_AO, 1); -static MESON_GATE(meson8b_ao_ahb_bus, HHI_GCLK_AO, 2); -static MESON_GATE(meson8b_ao_iface, HHI_GCLK_AO, 3); +static MESON8B_PCLK(meson8b_ao_media_cpu, HHI_GCLK_AO, 0); +static MESON8B_PCLK(meson8b_ao_ahb_sram, HHI_GCLK_AO, 1); +static MESON8B_PCLK(meson8b_ao_ahb_bus, HHI_GCLK_AO, 2); +static MESON8B_PCLK(meson8b_ao_iface, HHI_GCLK_AO, 3); static struct clk_hw *meson8_hw_clks[] = { - [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, - [CLKID_PLL_VID] = &meson8b_vid_pll.hw, - [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, - [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, - [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, - [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, - [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, - [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, - [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, - [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, - [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, - [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, + [CLKID_PLL_VID] = &meson8b_vid_pll.hw, + [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, + [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, + [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, + [CLKID_MPEG_SEL] = &meson8b_clk81_sel.hw, + [CLKID_MPEG_DIV] = &meson8b_clk81_div.hw, + [CLKID_CLK81] = &meson8b_clk81.hw, [CLKID_DDR] = &meson8b_ddr.hw, [CLKID_DOS] = &meson8b_dos.hw, [CLKID_ISA] = &meson8b_isa.hw, @@ -2945,7 +2905,7 @@ static struct clk_hw *meson8_hw_clks[] = { [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, - [CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw, + [CLKID_NAND_CLK] = &meson8b_nand_clk.hw, [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, [CLKID_HDMI_PLL_DCO] = &meson8b_hdmi_pll_dco.hw, [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, @@ -2956,14 +2916,14 @@ static struct clk_hw *meson8_hw_clks[] = { [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, - [CLKID_APB_SEL] = &meson8b_apb_clk_sel.hw, - [CLKID_APB] = &meson8b_apb_clk_gate.hw, - [CLKID_PERIPH_SEL] = &meson8b_periph_clk_sel.hw, - [CLKID_PERIPH] = &meson8b_periph_clk_gate.hw, - [CLKID_AXI_SEL] = &meson8b_axi_clk_sel.hw, - [CLKID_AXI] = &meson8b_axi_clk_gate.hw, - [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_clk_sel.hw, - [CLKID_L2_DRAM] = &meson8b_l2_dram_clk_gate.hw, + [CLKID_APB_SEL] = &meson8b_apb_sel.hw, + [CLKID_APB] = &meson8b_apb.hw, + [CLKID_PERIPH_SEL] = &meson8b_periph_sel.hw, + [CLKID_PERIPH] = &meson8b_periph.hw, + [CLKID_AXI_SEL] = &meson8b_axi_sel.hw, + [CLKID_AXI] = &meson8b_axi.hw, + [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_sel.hw, + [CLKID_L2_DRAM] = &meson8b_l2_dram.hw, [CLKID_HDMI_PLL_LVDS_OUT] = &meson8b_hdmi_pll_lvds_out.hw, [CLKID_HDMI_PLL_HDMI_OUT] = &meson8b_hdmi_pll_hdmi_out.hw, [CLKID_VID_PLL_IN_SEL] = &meson8b_vid_pll_in_sel.hw, @@ -2974,27 +2934,27 @@ static struct clk_hw *meson8_hw_clks[] = { [CLKID_VCLK_IN_SEL] = &meson8b_vclk_in_sel.hw, [CLKID_VCLK_IN_EN] = &meson8b_vclk_in_en.hw, [CLKID_VCLK_EN] = &meson8b_vclk_en.hw, - [CLKID_VCLK_DIV1] = &meson8b_vclk_div1_gate.hw, + [CLKID_VCLK_DIV1] = &meson8b_vclk_div1.hw, [CLKID_VCLK_DIV2_DIV] = &meson8b_vclk_div2_div.hw, - [CLKID_VCLK_DIV2] = &meson8b_vclk_div2_div_gate.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2.hw, [CLKID_VCLK_DIV4_DIV] = &meson8b_vclk_div4_div.hw, - [CLKID_VCLK_DIV4] = &meson8b_vclk_div4_div_gate.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4.hw, [CLKID_VCLK_DIV6_DIV] = &meson8b_vclk_div6_div.hw, - [CLKID_VCLK_DIV6] = &meson8b_vclk_div6_div_gate.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6.hw, [CLKID_VCLK_DIV12_DIV] = &meson8b_vclk_div12_div.hw, - [CLKID_VCLK_DIV12] = &meson8b_vclk_div12_div_gate.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12.hw, [CLKID_VCLK2_IN_SEL] = &meson8b_vclk2_in_sel.hw, - [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_clk_in_en.hw, - [CLKID_VCLK2_EN] = &meson8b_vclk2_clk_en.hw, - [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1_gate.hw, + [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_in_en.hw, + [CLKID_VCLK2_EN] = &meson8b_vclk2_en.hw, + [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1.hw, [CLKID_VCLK2_DIV2_DIV] = &meson8b_vclk2_div2_div.hw, - [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2_div_gate.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2.hw, [CLKID_VCLK2_DIV4_DIV] = &meson8b_vclk2_div4_div.hw, - [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4_div_gate.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4.hw, [CLKID_VCLK2_DIV6_DIV] = &meson8b_vclk2_div6_div.hw, - [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6_div_gate.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6.hw, [CLKID_VCLK2_DIV12_DIV] = &meson8b_vclk2_div12_div.hw, - [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12_div_gate.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12.hw, [CLKID_CTS_ENCT_SEL] = &meson8b_cts_enct_sel.hw, [CLKID_CTS_ENCT] = &meson8b_cts_enct.hw, [CLKID_CTS_ENCP_SEL] = &meson8b_cts_encp_sel.hw, @@ -3041,18 +3001,18 @@ static struct clk_hw *meson8_hw_clks[] = { }; static struct clk_hw *meson8b_hw_clks[] = { - [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, - [CLKID_PLL_VID] = &meson8b_vid_pll.hw, - [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, - [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, - [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, - [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, - [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, - [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, - [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, - [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, - [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, - [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, + [CLKID_PLL_VID] = &meson8b_vid_pll.hw, + [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, + [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, + [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, + [CLKID_MPEG_SEL] = &meson8b_clk81_sel.hw, + [CLKID_MPEG_DIV] = &meson8b_clk81_div.hw, + [CLKID_CLK81] = &meson8b_clk81.hw, [CLKID_DDR] = &meson8b_ddr.hw, [CLKID_DOS] = &meson8b_dos.hw, [CLKID_ISA] = &meson8b_isa.hw, @@ -3149,7 +3109,7 @@ static struct clk_hw *meson8b_hw_clks[] = { [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, - [CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw, + [CLKID_NAND_CLK] = &meson8b_nand_clk.hw, [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, [CLKID_HDMI_PLL_DCO] = &meson8b_hdmi_pll_dco.hw, [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, @@ -3160,14 +3120,14 @@ static struct clk_hw *meson8b_hw_clks[] = { [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, - [CLKID_APB_SEL] = &meson8b_apb_clk_sel.hw, - [CLKID_APB] = &meson8b_apb_clk_gate.hw, - [CLKID_PERIPH_SEL] = &meson8b_periph_clk_sel.hw, - [CLKID_PERIPH] = &meson8b_periph_clk_gate.hw, - [CLKID_AXI_SEL] = &meson8b_axi_clk_sel.hw, - [CLKID_AXI] = &meson8b_axi_clk_gate.hw, - [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_clk_sel.hw, - [CLKID_L2_DRAM] = &meson8b_l2_dram_clk_gate.hw, + [CLKID_APB_SEL] = &meson8b_apb_sel.hw, + [CLKID_APB] = &meson8b_apb.hw, + [CLKID_PERIPH_SEL] = &meson8b_periph_sel.hw, + [CLKID_PERIPH] = &meson8b_periph.hw, + [CLKID_AXI_SEL] = &meson8b_axi_sel.hw, + [CLKID_AXI] = &meson8b_axi.hw, + [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_sel.hw, + [CLKID_L2_DRAM] = &meson8b_l2_dram.hw, [CLKID_HDMI_PLL_LVDS_OUT] = &meson8b_hdmi_pll_lvds_out.hw, [CLKID_HDMI_PLL_HDMI_OUT] = &meson8b_hdmi_pll_hdmi_out.hw, [CLKID_VID_PLL_IN_SEL] = &meson8b_vid_pll_in_sel.hw, @@ -3178,27 +3138,27 @@ static struct clk_hw *meson8b_hw_clks[] = { [CLKID_VCLK_IN_SEL] = &meson8b_vclk_in_sel.hw, [CLKID_VCLK_IN_EN] = &meson8b_vclk_in_en.hw, [CLKID_VCLK_EN] = &meson8b_vclk_en.hw, - [CLKID_VCLK_DIV1] = &meson8b_vclk_div1_gate.hw, + [CLKID_VCLK_DIV1] = &meson8b_vclk_div1.hw, [CLKID_VCLK_DIV2_DIV] = &meson8b_vclk_div2_div.hw, - [CLKID_VCLK_DIV2] = &meson8b_vclk_div2_div_gate.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2.hw, [CLKID_VCLK_DIV4_DIV] = &meson8b_vclk_div4_div.hw, - [CLKID_VCLK_DIV4] = &meson8b_vclk_div4_div_gate.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4.hw, [CLKID_VCLK_DIV6_DIV] = &meson8b_vclk_div6_div.hw, - [CLKID_VCLK_DIV6] = &meson8b_vclk_div6_div_gate.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6.hw, [CLKID_VCLK_DIV12_DIV] = &meson8b_vclk_div12_div.hw, - [CLKID_VCLK_DIV12] = &meson8b_vclk_div12_div_gate.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12.hw, [CLKID_VCLK2_IN_SEL] = &meson8b_vclk2_in_sel.hw, - [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_clk_in_en.hw, - [CLKID_VCLK2_EN] = &meson8b_vclk2_clk_en.hw, - [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1_gate.hw, + [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_in_en.hw, + [CLKID_VCLK2_EN] = &meson8b_vclk2_en.hw, + [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1.hw, [CLKID_VCLK2_DIV2_DIV] = &meson8b_vclk2_div2_div.hw, - [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2_div_gate.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2.hw, [CLKID_VCLK2_DIV4_DIV] = &meson8b_vclk2_div4_div.hw, - [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4_div_gate.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4.hw, [CLKID_VCLK2_DIV6_DIV] = &meson8b_vclk2_div6_div.hw, - [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6_div_gate.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6.hw, [CLKID_VCLK2_DIV12_DIV] = &meson8b_vclk2_div12_div.hw, - [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12_div_gate.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12.hw, [CLKID_CTS_ENCT_SEL] = &meson8b_cts_enct_sel.hw, [CLKID_CTS_ENCT] = &meson8b_cts_enct.hw, [CLKID_CTS_ENCP_SEL] = &meson8b_cts_encp_sel.hw, @@ -3256,18 +3216,18 @@ static struct clk_hw *meson8b_hw_clks[] = { }; static struct clk_hw *meson8m2_hw_clks[] = { - [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, - [CLKID_PLL_VID] = &meson8b_vid_pll.hw, - [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, - [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, - [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, - [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, - [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, - [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, - [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, - [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, - [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, - [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, + [CLKID_PLL_VID] = &meson8b_vid_pll.hw, + [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, + [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, + [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, + [CLKID_MPEG_SEL] = &meson8b_clk81_sel.hw, + [CLKID_MPEG_DIV] = &meson8b_clk81_div.hw, + [CLKID_CLK81] = &meson8b_clk81.hw, [CLKID_DDR] = &meson8b_ddr.hw, [CLKID_DOS] = &meson8b_dos.hw, [CLKID_ISA] = &meson8b_isa.hw, @@ -3364,7 +3324,7 @@ static struct clk_hw *meson8m2_hw_clks[] = { [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, - [CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw, + [CLKID_NAND_CLK] = &meson8b_nand_clk.hw, [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, [CLKID_HDMI_PLL_DCO] = &meson8b_hdmi_pll_dco.hw, [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, @@ -3375,14 +3335,14 @@ static struct clk_hw *meson8m2_hw_clks[] = { [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, - [CLKID_APB_SEL] = &meson8b_apb_clk_sel.hw, - [CLKID_APB] = &meson8b_apb_clk_gate.hw, - [CLKID_PERIPH_SEL] = &meson8b_periph_clk_sel.hw, - [CLKID_PERIPH] = &meson8b_periph_clk_gate.hw, - [CLKID_AXI_SEL] = &meson8b_axi_clk_sel.hw, - [CLKID_AXI] = &meson8b_axi_clk_gate.hw, - [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_clk_sel.hw, - [CLKID_L2_DRAM] = &meson8b_l2_dram_clk_gate.hw, + [CLKID_APB_SEL] = &meson8b_apb_sel.hw, + [CLKID_APB] = &meson8b_apb.hw, + [CLKID_PERIPH_SEL] = &meson8b_periph_sel.hw, + [CLKID_PERIPH] = &meson8b_periph.hw, + [CLKID_AXI_SEL] = &meson8b_axi_sel.hw, + [CLKID_AXI] = &meson8b_axi.hw, + [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_sel.hw, + [CLKID_L2_DRAM] = &meson8b_l2_dram.hw, [CLKID_HDMI_PLL_LVDS_OUT] = &meson8b_hdmi_pll_lvds_out.hw, [CLKID_HDMI_PLL_HDMI_OUT] = &meson8b_hdmi_pll_hdmi_out.hw, [CLKID_VID_PLL_IN_SEL] = &meson8b_vid_pll_in_sel.hw, @@ -3393,27 +3353,27 @@ static struct clk_hw *meson8m2_hw_clks[] = { [CLKID_VCLK_IN_SEL] = &meson8b_vclk_in_sel.hw, [CLKID_VCLK_IN_EN] = &meson8b_vclk_in_en.hw, [CLKID_VCLK_EN] = &meson8b_vclk_en.hw, - [CLKID_VCLK_DIV1] = &meson8b_vclk_div1_gate.hw, + [CLKID_VCLK_DIV1] = &meson8b_vclk_div1.hw, [CLKID_VCLK_DIV2_DIV] = &meson8b_vclk_div2_div.hw, - [CLKID_VCLK_DIV2] = &meson8b_vclk_div2_div_gate.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2.hw, [CLKID_VCLK_DIV4_DIV] = &meson8b_vclk_div4_div.hw, - [CLKID_VCLK_DIV4] = &meson8b_vclk_div4_div_gate.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4.hw, [CLKID_VCLK_DIV6_DIV] = &meson8b_vclk_div6_div.hw, - [CLKID_VCLK_DIV6] = &meson8b_vclk_div6_div_gate.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6.hw, [CLKID_VCLK_DIV12_DIV] = &meson8b_vclk_div12_div.hw, - [CLKID_VCLK_DIV12] = &meson8b_vclk_div12_div_gate.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12.hw, [CLKID_VCLK2_IN_SEL] = &meson8b_vclk2_in_sel.hw, - [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_clk_in_en.hw, - [CLKID_VCLK2_EN] = &meson8b_vclk2_clk_en.hw, - [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1_gate.hw, + [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_in_en.hw, + [CLKID_VCLK2_EN] = &meson8b_vclk2_en.hw, + [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1.hw, [CLKID_VCLK2_DIV2_DIV] = &meson8b_vclk2_div2_div.hw, - [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2_div_gate.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2.hw, [CLKID_VCLK2_DIV4_DIV] = &meson8b_vclk2_div4_div.hw, - [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4_div_gate.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4.hw, [CLKID_VCLK2_DIV6_DIV] = &meson8b_vclk2_div6_div.hw, - [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6_div_gate.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6.hw, [CLKID_VCLK2_DIV12_DIV] = &meson8b_vclk2_div12_div.hw, - [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12_div_gate.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12.hw, [CLKID_CTS_ENCT_SEL] = &meson8b_cts_enct_sel.hw, [CLKID_CTS_ENCT] = &meson8b_cts_enct.hw, [CLKID_CTS_ENCP_SEL] = &meson8b_cts_encp_sel.hw, diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c index c9400cf54c84..9bcd35f12836 100644 --- a/drivers/clk/meson/s4-peripherals.c +++ b/drivers/clk/meson/s4-peripherals.c @@ -182,8 +182,8 @@ static struct clk_regmap s4_rtc_clk = { }; /* The index 5 is AXI_CLK, which is dedicated to AXI. So skip it. */ -static u32 mux_table_sys_ab_clk_sel[] = { 0, 1, 2, 3, 4, 6, 7 }; -static const struct clk_parent_data sys_ab_clk_parent_data[] = { +static u32 s4_sysclk_parents_val_table[] = { 0, 1, 2, 3, 4, 6, 7 }; +static const struct clk_parent_data s4_sysclk_parents[] = { { .fw_name = "xtal" }, { .fw_name = "fclk_div2" }, { .fw_name = "fclk_div3" }, @@ -205,13 +205,13 @@ static struct clk_regmap s4_sysclk_b_sel = { .offset = CLKCTRL_SYS_CLK_CTRL0, .mask = 0x7, .shift = 26, - .table = mux_table_sys_ab_clk_sel, + .table = s4_sysclk_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "sysclk_b_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_data = sys_ab_clk_parent_data, - .num_parents = ARRAY_SIZE(sys_ab_clk_parent_data), + .parent_data = s4_sysclk_parents, + .num_parents = ARRAY_SIZE(s4_sysclk_parents), }, }; @@ -251,13 +251,13 @@ static struct clk_regmap s4_sysclk_a_sel = { .offset = CLKCTRL_SYS_CLK_CTRL0, .mask = 0x7, .shift = 10, - .table = mux_table_sys_ab_clk_sel, + .table = s4_sysclk_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "sysclk_a_sel", .ops = &clk_regmap_mux_ro_ops, - .parent_data = sys_ab_clk_parent_data, - .num_parents = ARRAY_SIZE(sys_ab_clk_parent_data), + .parent_data = s4_sysclk_parents, + .num_parents = ARRAY_SIZE(s4_sysclk_parents), }, }; @@ -523,24 +523,24 @@ static struct clk_regmap s4_cecb_32k_clkout = { }, }; -static const struct clk_parent_data s4_sc_parent_data[] = { +static const struct clk_parent_data s4_sc_clk_parents[] = { { .fw_name = "fclk_div4" }, { .fw_name = "fclk_div3" }, { .fw_name = "fclk_div5" }, { .fw_name = "xtal", } }; -static struct clk_regmap s4_sc_clk_mux = { +static struct clk_regmap s4_sc_clk_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_SC_CLK_CTRL, .mask = 0x3, .shift = 9, }, .hw.init = &(struct clk_init_data) { - .name = "sc_clk_mux", + .name = "sc_clk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_sc_parent_data, - .num_parents = ARRAY_SIZE(s4_sc_parent_data), + .parent_data = s4_sc_clk_parents, + .num_parents = ARRAY_SIZE(s4_sc_clk_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -555,20 +555,20 @@ static struct clk_regmap s4_sc_clk_div = { .name = "sc_clk_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_sc_clk_mux.hw + &s4_sc_clk_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_sc_clk_gate = { +static struct clk_regmap s4_sc_clk = { .data = &(struct clk_regmap_gate_data){ .offset = CLKCTRL_SC_CLK_CTRL, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "sc_clk_gate", + .name = "sc_clk", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_sc_clk_div.hw @@ -578,13 +578,13 @@ static struct clk_regmap s4_sc_clk_gate = { }, }; -static struct clk_regmap s4_12_24M_clk_gate = { +static struct clk_regmap s4_12_24M = { .data = &(struct clk_regmap_gate_data){ .offset = CLKCTRL_CLK12_24_CTRL, .bit_idx = 11, }, .hw.init = &(struct clk_init_data) { - .name = "12_24m_gate", + .name = "12_24M", .ops = &clk_regmap_gate_ops, .parent_data = (const struct clk_parent_data []) { { .fw_name = "xtal", } @@ -593,32 +593,32 @@ static struct clk_regmap s4_12_24M_clk_gate = { }, }; -static struct clk_fixed_factor s4_12M_clk_div = { +static struct clk_fixed_factor s4_12M_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "12M", + .name = "12M_div", .ops = &clk_fixed_factor_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_12_24M_clk_gate.hw + &s4_12_24M.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_12_24M_clk = { +static struct clk_regmap s4_12_24M_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_CLK12_24_CTRL, .mask = 0x1, .shift = 10, }, .hw.init = &(struct clk_init_data) { - .name = "12_24m", + .name = "12_24M_sel", .ops = &clk_regmap_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_12_24M_clk_gate.hw, - &s4_12M_clk_div.hw, + &s4_12_24M.hw, + &s4_12M_div.hw, }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, @@ -687,7 +687,7 @@ static struct clk_regmap s4_vid_pll = { }, }; -static const struct clk_parent_data s4_vclk_parent_data[] = { +static const struct clk_parent_data s4_vclk_parents[] = { { .hw = &s4_vid_pll.hw }, { .fw_name = "gp0_pll", }, { .fw_name = "hifi_pll", }, @@ -707,8 +707,8 @@ static struct clk_regmap s4_vclk_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_vclk_parent_data, - .num_parents = ARRAY_SIZE(s4_vclk_parent_data), + .parent_data = s4_vclk_parents, + .num_parents = ARRAY_SIZE(s4_vclk_parents), .flags = 0, }, }; @@ -722,8 +722,8 @@ static struct clk_regmap s4_vclk2_sel = { .hw.init = &(struct clk_init_data){ .name = "vclk2_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_vclk_parent_data, - .num_parents = ARRAY_SIZE(s4_vclk_parent_data), + .parent_data = s4_vclk_parents, + .num_parents = ARRAY_SIZE(s4_vclk_parents), .flags = 0, }, }; @@ -1071,8 +1071,8 @@ static struct clk_fixed_factor s4_vclk2_div12 = { }; /* The 5,6,7 indexes corresponds to no real clock, so there are not used. */ -static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const struct clk_hw *s4_cts_parent_hws[] = { +static u32 s4_cts_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *s4_cts_parents[] = { &s4_vclk_div1.hw, &s4_vclk_div2.hw, &s4_vclk_div4.hw, @@ -1090,13 +1090,13 @@ static struct clk_regmap s4_cts_enci_sel = { .offset = CLKCTRL_VID_CLK_DIV, .mask = 0xf, .shift = 28, - .table = mux_table_cts_sel, + .table = s4_cts_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_enci_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = s4_cts_parent_hws, - .num_parents = ARRAY_SIZE(s4_cts_parent_hws), + .parent_hws = s4_cts_parents, + .num_parents = ARRAY_SIZE(s4_cts_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1106,13 +1106,13 @@ static struct clk_regmap s4_cts_encp_sel = { .offset = CLKCTRL_VID_CLK_DIV, .mask = 0xf, .shift = 20, - .table = mux_table_cts_sel, + .table = s4_cts_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_encp_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = s4_cts_parent_hws, - .num_parents = ARRAY_SIZE(s4_cts_parent_hws), + .parent_hws = s4_cts_parents, + .num_parents = ARRAY_SIZE(s4_cts_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1122,20 +1122,20 @@ static struct clk_regmap s4_cts_vdac_sel = { .offset = CLKCTRL_VIID_CLK_DIV, .mask = 0xf, .shift = 28, - .table = mux_table_cts_sel, + .table = s4_cts_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "cts_vdac_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = s4_cts_parent_hws, - .num_parents = ARRAY_SIZE(s4_cts_parent_hws), + .parent_hws = s4_cts_parents, + .num_parents = ARRAY_SIZE(s4_cts_parents), .flags = CLK_SET_RATE_PARENT, }, }; /* The 5,6,7 indexes corresponds to no real clock, so there are not used. */ -static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; -static const struct clk_hw *s4_cts_hdmi_tx_parent_hws[] = { +static u32 s4_hdmi_tx_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *s4_hdmi_tx_parents[] = { &s4_vclk_div1.hw, &s4_vclk_div2.hw, &s4_vclk_div4.hw, @@ -1153,13 +1153,13 @@ static struct clk_regmap s4_hdmi_tx_sel = { .offset = CLKCTRL_HDMI_CLK_CTRL, .mask = 0xf, .shift = 16, - .table = mux_table_hdmi_tx_sel, + .table = s4_hdmi_tx_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "hdmi_tx_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = s4_cts_hdmi_tx_parent_hws, - .num_parents = ARRAY_SIZE(s4_cts_hdmi_tx_parent_hws), + .parent_hws = s4_hdmi_tx_parents, + .num_parents = ARRAY_SIZE(s4_hdmi_tx_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1229,7 +1229,7 @@ static struct clk_regmap s4_hdmi_tx = { }; /* HDMI Clocks */ -static const struct clk_parent_data s4_hdmi_parent_data[] = { +static const struct clk_parent_data s4_hdmi_parents[] = { { .fw_name = "xtal", }, { .fw_name = "fclk_div4", }, { .fw_name = "fclk_div3", }, @@ -1246,8 +1246,8 @@ static struct clk_regmap s4_hdmi_sel = { .hw.init = &(struct clk_init_data){ .name = "hdmi_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_hdmi_parent_data, - .num_parents = ARRAY_SIZE(s4_hdmi_parent_data), + .parent_data = s4_hdmi_parents, + .num_parents = ARRAY_SIZE(s4_hdmi_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1298,7 +1298,7 @@ static struct clk_regmap s4_ts_clk_div = { }, }; -static struct clk_regmap s4_ts_clk_gate = { +static struct clk_regmap s4_ts_clk = { .data = &(struct clk_regmap_gate_data){ .offset = CLKCTRL_TS_CLK_CTRL, .bit_idx = 8, @@ -1320,7 +1320,7 @@ static struct clk_regmap s4_ts_clk_gate = { * mux because it does top-to-bottom updates the each clock tree and * switches to the "inactive" one when CLK_SET_RATE_GATE is set. */ -static const struct clk_parent_data s4_mali_0_1_parent_data[] = { +static const struct clk_parent_data s4_mali_parents[] = { { .fw_name = "xtal", }, { .fw_name = "gp0_pll", }, { .fw_name = "hifi_pll", }, @@ -1340,8 +1340,8 @@ static struct clk_regmap s4_mali_0_sel = { .hw.init = &(struct clk_init_data){ .name = "mali_0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_mali_0_1_parent_data, - .num_parents = ARRAY_SIZE(s4_mali_0_1_parent_data), + .parent_data = s4_mali_parents, + .num_parents = ARRAY_SIZE(s4_mali_parents), /* * Don't request the parent to change the rate because * all GPU frequencies can be derived from the fclk_* @@ -1394,8 +1394,8 @@ static struct clk_regmap s4_mali_1_sel = { .hw.init = &(struct clk_init_data){ .name = "mali_1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_mali_0_1_parent_data, - .num_parents = ARRAY_SIZE(s4_mali_0_1_parent_data), + .parent_data = s4_mali_parents, + .num_parents = ARRAY_SIZE(s4_mali_parents), .flags = 0, }, }; @@ -1433,28 +1433,26 @@ static struct clk_regmap s4_mali_1 = { }, }; -static const struct clk_hw *s4_mali_parent_hws[] = { - &s4_mali_0.hw, - &s4_mali_1.hw -}; - -static struct clk_regmap s4_mali_mux = { +static struct clk_regmap s4_mali_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_MALI_CLK_CTRL, .mask = 1, .shift = 31, }, .hw.init = &(struct clk_init_data){ - .name = "mali", + .name = "mali_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = s4_mali_parent_hws, + .parent_hws = (const struct clk_hw *[]) { + &s4_mali_0.hw, + &s4_mali_1.hw, + }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; /* VDEC clocks */ -static const struct clk_parent_data s4_dec_parent_data[] = { +static const struct clk_parent_data s4_dec_parents[] = { { .fw_name = "fclk_div2p5", }, { .fw_name = "fclk_div3", }, { .fw_name = "fclk_div4", }, @@ -1465,7 +1463,7 @@ static const struct clk_parent_data s4_dec_parent_data[] = { { .fw_name = "xtal", } }; -static struct clk_regmap s4_vdec_p0_mux = { +static struct clk_regmap s4_vdec_p0_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VDEC_CLK_CTRL, .mask = 0x7, @@ -1473,10 +1471,10 @@ static struct clk_regmap s4_vdec_p0_mux = { .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data) { - .name = "vdec_p0_mux", + .name = "vdec_p0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_dec_parent_data, - .num_parents = ARRAY_SIZE(s4_dec_parent_data), + .parent_data = s4_dec_parents, + .num_parents = ARRAY_SIZE(s4_dec_parents), .flags = 0, }, }; @@ -1492,7 +1490,7 @@ static struct clk_regmap s4_vdec_p0_div = { .name = "vdec_p0_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_vdec_p0_mux.hw + &s4_vdec_p0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1515,7 +1513,7 @@ static struct clk_regmap s4_vdec_p0 = { }, }; -static struct clk_regmap s4_vdec_p1_mux = { +static struct clk_regmap s4_vdec_p1_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VDEC3_CLK_CTRL, .mask = 0x7, @@ -1523,10 +1521,10 @@ static struct clk_regmap s4_vdec_p1_mux = { .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data) { - .name = "vdec_p1_mux", + .name = "vdec_p1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_dec_parent_data, - .num_parents = ARRAY_SIZE(s4_dec_parent_data), + .parent_data = s4_dec_parents, + .num_parents = ARRAY_SIZE(s4_dec_parents), .flags = 0, }, }; @@ -1542,7 +1540,7 @@ static struct clk_regmap s4_vdec_p1_div = { .name = "vdec_p1_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_vdec_p1_mux.hw + &s4_vdec_p1_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1565,27 +1563,25 @@ static struct clk_regmap s4_vdec_p1 = { }, }; -static const struct clk_hw *s4_vdec_mux_parent_hws[] = { - &s4_vdec_p0.hw, - &s4_vdec_p1.hw -}; - -static struct clk_regmap s4_vdec_mux = { +static struct clk_regmap s4_vdec_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VDEC3_CLK_CTRL, .mask = 0x1, .shift = 15, }, .hw.init = &(struct clk_init_data) { - .name = "vdec_mux", + .name = "vdec_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = s4_vdec_mux_parent_hws, - .num_parents = ARRAY_SIZE(s4_vdec_mux_parent_hws), + .parent_hws = (const struct clk_hw *[]) { + &s4_vdec_p0.hw, + &s4_vdec_p1.hw, + }, + .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_hevcf_p0_mux = { +static struct clk_regmap s4_hevcf_p0_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VDEC2_CLK_CTRL, .mask = 0x7, @@ -1593,10 +1589,10 @@ static struct clk_regmap s4_hevcf_p0_mux = { .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data) { - .name = "hevcf_p0_mux", + .name = "hevcf_p0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_dec_parent_data, - .num_parents = ARRAY_SIZE(s4_dec_parent_data), + .parent_data = s4_dec_parents, + .num_parents = ARRAY_SIZE(s4_dec_parents), .flags = 0, }, }; @@ -1612,7 +1608,7 @@ static struct clk_regmap s4_hevcf_p0_div = { .name = "hevcf_p0_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_hevcf_p0_mux.hw + &s4_hevcf_p0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1625,7 +1621,7 @@ static struct clk_regmap s4_hevcf_p0 = { .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "hevcf_p0_gate", + .name = "hevcf_p0", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_hevcf_p0_div.hw @@ -1635,7 +1631,7 @@ static struct clk_regmap s4_hevcf_p0 = { }, }; -static struct clk_regmap s4_hevcf_p1_mux = { +static struct clk_regmap s4_hevcf_p1_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VDEC4_CLK_CTRL, .mask = 0x7, @@ -1643,10 +1639,10 @@ static struct clk_regmap s4_hevcf_p1_mux = { .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data) { - .name = "hevcf_p1_mux", + .name = "hevcf_p1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_dec_parent_data, - .num_parents = ARRAY_SIZE(s4_dec_parent_data), + .parent_data = s4_dec_parents, + .num_parents = ARRAY_SIZE(s4_dec_parents), .flags = 0, }, }; @@ -1662,7 +1658,7 @@ static struct clk_regmap s4_hevcf_p1_div = { .name = "hevcf_p1_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_hevcf_p1_mux.hw + &s4_hevcf_p1_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1685,28 +1681,26 @@ static struct clk_regmap s4_hevcf_p1 = { }, }; -static const struct clk_hw *s4_hevcf_mux_parent_hws[] = { - &s4_hevcf_p0.hw, - &s4_hevcf_p1.hw -}; - -static struct clk_regmap s4_hevcf_mux = { +static struct clk_regmap s4_hevcf_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VDEC4_CLK_CTRL, .mask = 0x1, .shift = 15, }, .hw.init = &(struct clk_init_data) { - .name = "hevcf", + .name = "hevcf_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = s4_hevcf_mux_parent_hws, - .num_parents = ARRAY_SIZE(s4_hevcf_mux_parent_hws), + .parent_hws = (const struct clk_hw *[]) { + &s4_hevcf_p0.hw, + &s4_hevcf_p1.hw, + }, + .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; /* VPU Clock */ -static const struct clk_parent_data s4_vpu_parent_data[] = { +static const struct clk_parent_data s4_vpu_parents[] = { { .fw_name = "fclk_div3", }, { .fw_name = "fclk_div4", }, { .fw_name = "fclk_div5", }, @@ -1726,8 +1720,8 @@ static struct clk_regmap s4_vpu_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_vpu_parent_data, - .num_parents = ARRAY_SIZE(s4_vpu_parent_data), + .parent_data = s4_vpu_parents, + .num_parents = ARRAY_SIZE(s4_vpu_parents), .flags = 0, }, }; @@ -1770,8 +1764,8 @@ static struct clk_regmap s4_vpu_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_vpu_parent_data, - .num_parents = ARRAY_SIZE(s4_vpu_parent_data), + .parent_data = s4_vpu_parents, + .num_parents = ARRAY_SIZE(s4_vpu_parents), .flags = 0, }, }; @@ -1823,24 +1817,24 @@ static struct clk_regmap s4_vpu = { }, }; -static const struct clk_parent_data vpu_clkb_tmp_parent_data[] = { +static const struct clk_parent_data vpu_clkb_tmp_parents[] = { { .hw = &s4_vpu.hw }, { .fw_name = "fclk_div4", }, { .fw_name = "fclk_div5", }, { .fw_name = "fclk_div7", } }; -static struct clk_regmap s4_vpu_clkb_tmp_mux = { +static struct clk_regmap s4_vpu_clkb_tmp_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VPU_CLKB_CTRL, .mask = 0x3, .shift = 20, }, .hw.init = &(struct clk_init_data) { - .name = "vpu_clkb_tmp_mux", + .name = "vpu_clkb_tmp_sel", .ops = &clk_regmap_mux_ops, - .parent_data = vpu_clkb_tmp_parent_data, - .num_parents = ARRAY_SIZE(vpu_clkb_tmp_parent_data), + .parent_data = vpu_clkb_tmp_parents, + .num_parents = ARRAY_SIZE(vpu_clkb_tmp_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -1855,7 +1849,7 @@ static struct clk_regmap s4_vpu_clkb_tmp_div = { .name = "vpu_clkb_tmp_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_vpu_clkb_tmp_mux.hw + &s4_vpu_clkb_tmp_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1911,7 +1905,7 @@ static struct clk_regmap s4_vpu_clkb = { }, }; -static const struct clk_parent_data s4_vpu_clkc_parent_data[] = { +static const struct clk_parent_data s4_vpu_clkc_parents[] = { { .fw_name = "fclk_div4", }, { .fw_name = "fclk_div3", }, { .fw_name = "fclk_div5", }, @@ -1922,17 +1916,17 @@ static const struct clk_parent_data s4_vpu_clkc_parent_data[] = { { .fw_name = "gp0_pll", }, }; -static struct clk_regmap s4_vpu_clkc_p0_mux = { +static struct clk_regmap s4_vpu_clkc_p0_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VPU_CLKC_CTRL, .mask = 0x7, .shift = 9, }, .hw.init = &(struct clk_init_data) { - .name = "vpu_clkc_p0_mux", + .name = "vpu_clkc_p0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_vpu_clkc_parent_data, - .num_parents = ARRAY_SIZE(s4_vpu_clkc_parent_data), + .parent_data = s4_vpu_clkc_parents, + .num_parents = ARRAY_SIZE(s4_vpu_clkc_parents), .flags = 0, }, }; @@ -1947,7 +1941,7 @@ static struct clk_regmap s4_vpu_clkc_p0_div = { .name = "vpu_clkc_p0_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_vpu_clkc_p0_mux.hw + &s4_vpu_clkc_p0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1970,17 +1964,17 @@ static struct clk_regmap s4_vpu_clkc_p0 = { }, }; -static struct clk_regmap s4_vpu_clkc_p1_mux = { +static struct clk_regmap s4_vpu_clkc_p1_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VPU_CLKC_CTRL, .mask = 0x7, .shift = 25, }, .hw.init = &(struct clk_init_data) { - .name = "vpu_clkc_p1_mux", + .name = "vpu_clkc_p1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_vpu_clkc_parent_data, - .num_parents = ARRAY_SIZE(s4_vpu_clkc_parent_data), + .parent_data = s4_vpu_clkc_parents, + .num_parents = ARRAY_SIZE(s4_vpu_clkc_parents), .flags = 0, }, }; @@ -1995,7 +1989,7 @@ static struct clk_regmap s4_vpu_clkc_p1_div = { .name = "vpu_clkc_p1_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_vpu_clkc_p1_mux.hw + &s4_vpu_clkc_p1_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -2018,28 +2012,26 @@ static struct clk_regmap s4_vpu_clkc_p1 = { }, }; -static const struct clk_hw *s4_vpu_mux_parent_hws[] = { - &s4_vpu_clkc_p0.hw, - &s4_vpu_clkc_p1.hw -}; - -static struct clk_regmap s4_vpu_clkc_mux = { +static struct clk_regmap s4_vpu_clkc_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VPU_CLKC_CTRL, .mask = 0x1, .shift = 31, }, .hw.init = &(struct clk_init_data) { - .name = "vpu_clkc_mux", + .name = "vpu_clkc_sel", .ops = &clk_regmap_mux_ops, - .parent_hws = s4_vpu_mux_parent_hws, - .num_parents = ARRAY_SIZE(s4_vpu_mux_parent_hws), + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkc_p0.hw, + &s4_vpu_clkc_p1.hw, + }, + .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, }; /* VAPB Clock */ -static const struct clk_parent_data s4_vapb_parent_data[] = { +static const struct clk_parent_data s4_vapb_parents[] = { { .fw_name = "fclk_div4", }, { .fw_name = "fclk_div3", }, { .fw_name = "fclk_div5", }, @@ -2059,8 +2051,8 @@ static struct clk_regmap s4_vapb_0_sel = { .hw.init = &(struct clk_init_data){ .name = "vapb_0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_vapb_parent_data, - .num_parents = ARRAY_SIZE(s4_vapb_parent_data), + .parent_data = s4_vapb_parents, + .num_parents = ARRAY_SIZE(s4_vapb_parents), .flags = 0, }, }; @@ -2107,8 +2099,8 @@ static struct clk_regmap s4_vapb_1_sel = { .hw.init = &(struct clk_init_data){ .name = "vapb_1_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_vapb_parent_data, - .num_parents = ARRAY_SIZE(s4_vapb_parent_data), + .parent_data = s4_vapb_parents, + .num_parents = ARRAY_SIZE(s4_vapb_parents), .flags = 0, }, }; @@ -2164,13 +2156,13 @@ static struct clk_regmap s4_vapb = { }, }; -static struct clk_regmap s4_ge2d_gate = { +static struct clk_regmap s4_ge2d = { .data = &(struct clk_regmap_gate_data){ .offset = CLKCTRL_VAPBCLK_CTRL, .bit_idx = 30, }, .hw.init = &(struct clk_init_data) { - .name = "ge2d_clk", + .name = "ge2d", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_vapb.hw }, .num_parents = 1, @@ -2178,24 +2170,24 @@ static struct clk_regmap s4_ge2d_gate = { }, }; -static const struct clk_parent_data s4_esmclk_parent_data[] = { +static const struct clk_parent_data s4_hdcp22_esmclk_parents[] = { { .fw_name = "fclk_div7", }, { .fw_name = "fclk_div4", }, { .fw_name = "fclk_div3", }, { .fw_name = "fclk_div5", }, }; -static struct clk_regmap s4_hdcp22_esmclk_mux = { +static struct clk_regmap s4_hdcp22_esmclk_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_HDCP22_CTRL, .mask = 0x3, .shift = 9, }, .hw.init = &(struct clk_init_data) { - .name = "hdcp22_esmclk_mux", + .name = "hdcp22_esmclk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_esmclk_parent_data, - .num_parents = ARRAY_SIZE(s4_esmclk_parent_data), + .parent_data = s4_hdcp22_esmclk_parents, + .num_parents = ARRAY_SIZE(s4_hdcp22_esmclk_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2210,20 +2202,20 @@ static struct clk_regmap s4_hdcp22_esmclk_div = { .name = "hdcp22_esmclk_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_hdcp22_esmclk_mux.hw + &s4_hdcp22_esmclk_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_hdcp22_esmclk_gate = { +static struct clk_regmap s4_hdcp22_esmclk = { .data = &(struct clk_regmap_gate_data){ .offset = CLKCTRL_HDCP22_CTRL, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "hdcp22_esmclk_gate", + .name = "hdcp22_esmclk", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_hdcp22_esmclk_div.hw @@ -2233,24 +2225,24 @@ static struct clk_regmap s4_hdcp22_esmclk_gate = { }, }; -static const struct clk_parent_data s4_skpclk_parent_data[] = { +static const struct clk_parent_data s4_hdcp22_skpclk_parents[] = { { .fw_name = "xtal", }, { .fw_name = "fclk_div4", }, { .fw_name = "fclk_div3", }, { .fw_name = "fclk_div5", }, }; -static struct clk_regmap s4_hdcp22_skpclk_mux = { +static struct clk_regmap s4_hdcp22_skpclk_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_HDCP22_CTRL, .mask = 0x3, .shift = 25, }, .hw.init = &(struct clk_init_data) { - .name = "hdcp22_skpclk_mux", + .name = "hdcp22_skpclk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_skpclk_parent_data, - .num_parents = ARRAY_SIZE(s4_skpclk_parent_data), + .parent_data = s4_hdcp22_skpclk_parents, + .num_parents = ARRAY_SIZE(s4_hdcp22_skpclk_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2265,20 +2257,20 @@ static struct clk_regmap s4_hdcp22_skpclk_div = { .name = "hdcp22_skpclk_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_hdcp22_skpclk_mux.hw + &s4_hdcp22_skpclk_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_hdcp22_skpclk_gate = { +static struct clk_regmap s4_hdcp22_skpclk = { .data = &(struct clk_regmap_gate_data){ .offset = CLKCTRL_HDCP22_CTRL, .bit_idx = 24, }, .hw.init = &(struct clk_init_data){ - .name = "hdcp22_skpclk_gate", + .name = "hdcp22_skpclk", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_hdcp22_skpclk_div.hw @@ -2288,7 +2280,7 @@ static struct clk_regmap s4_hdcp22_skpclk_gate = { }, }; -static const struct clk_parent_data s4_vdin_parent_data[] = { +static const struct clk_parent_data s4_vdin_parents[] = { { .fw_name = "xtal", }, { .fw_name = "fclk_div4", }, { .fw_name = "fclk_div3", }, @@ -2296,17 +2288,17 @@ static const struct clk_parent_data s4_vdin_parent_data[] = { { .hw = &s4_vid_pll.hw } }; -static struct clk_regmap s4_vdin_meas_mux = { +static struct clk_regmap s4_vdin_meas_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VDIN_MEAS_CLK_CTRL, .mask = 0x7, .shift = 9, }, .hw.init = &(struct clk_init_data) { - .name = "vdin_meas_mux", + .name = "vdin_meas_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_vdin_parent_data, - .num_parents = ARRAY_SIZE(s4_vdin_parent_data), + .parent_data = s4_vdin_parents, + .num_parents = ARRAY_SIZE(s4_vdin_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2321,20 +2313,20 @@ static struct clk_regmap s4_vdin_meas_div = { .name = "vdin_meas_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_vdin_meas_mux.hw + &s4_vdin_meas_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_vdin_meas_gate = { +static struct clk_regmap s4_vdin_meas = { .data = &(struct clk_regmap_gate_data){ .offset = CLKCTRL_VDIN_MEAS_CLK_CTRL, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "vdin_meas_gate", + .name = "vdin_meas", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_vdin_meas_div.hw @@ -2345,7 +2337,7 @@ static struct clk_regmap s4_vdin_meas_gate = { }; /* EMMC/NAND clock */ -static const struct clk_parent_data s4_sd_emmc_clk0_parent_data[] = { +static const struct clk_parent_data s4_sd_emmc_clk0_parents[] = { { .fw_name = "xtal", }, { .fw_name = "fclk_div2", }, { .fw_name = "fclk_div3", }, @@ -2365,8 +2357,8 @@ static struct clk_regmap s4_sd_emmc_c_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parent_data), + .parent_data = s4_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parents), .flags = 0, }, }; @@ -2413,8 +2405,8 @@ static struct clk_regmap s4_sd_emmc_a_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parent_data), + .parent_data = s4_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parents), .flags = 0, }, }; @@ -2461,8 +2453,8 @@ static struct clk_regmap s4_sd_emmc_b_clk0_sel = { .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_sd_emmc_clk0_parent_data, - .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parent_data), + .parent_data = s4_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parents), .flags = 0, }, }; @@ -2501,7 +2493,7 @@ static struct clk_regmap s4_sd_emmc_b_clk0 = { }; /* SPICC Clock */ -static const struct clk_parent_data s4_spicc_parent_data[] = { +static const struct clk_parent_data s4_spicc_parents[] = { { .fw_name = "xtal", }, { .hw = &s4_sys_clk.hw }, { .fw_name = "fclk_div4", }, @@ -2511,17 +2503,17 @@ static const struct clk_parent_data s4_spicc_parent_data[] = { { .fw_name = "fclk_div7", }, }; -static struct clk_regmap s4_spicc0_mux = { +static struct clk_regmap s4_spicc0_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_SPICC_CLK_CTRL, .mask = 0x7, .shift = 7, }, .hw.init = &(struct clk_init_data) { - .name = "spicc0_mux", + .name = "spicc0_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_spicc_parent_data, - .num_parents = ARRAY_SIZE(s4_spicc_parent_data), + .parent_data = s4_spicc_parents, + .num_parents = ARRAY_SIZE(s4_spicc_parents), .flags = CLK_SET_RATE_PARENT, }, }; @@ -2536,20 +2528,20 @@ static struct clk_regmap s4_spicc0_div = { .name = "spicc0_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_spicc0_mux.hw + &s4_spicc0_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_spicc0_gate = { +static struct clk_regmap s4_spicc0_en = { .data = &(struct clk_regmap_gate_data){ .offset = CLKCTRL_SPICC_CLK_CTRL, .bit_idx = 6, }, .hw.init = &(struct clk_init_data){ - .name = "spicc0", + .name = "spicc0_en", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_spicc0_div.hw @@ -2560,24 +2552,24 @@ static struct clk_regmap s4_spicc0_gate = { }; /* PWM Clock */ -static const struct clk_parent_data s4_pwm_parent_data[] = { +static const struct clk_parent_data s4_pwm_parents[] = { { .fw_name = "xtal", }, { .hw = &s4_vid_pll.hw }, { .fw_name = "fclk_div4", }, { .fw_name = "fclk_div3", }, }; -static struct clk_regmap s4_pwm_a_mux = { +static struct clk_regmap s4_pwm_a_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_PWM_CLK_AB_CTRL, .mask = 0x3, .shift = 9, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_a_mux", + .name = "pwm_a_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parent_data, - .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .parent_data = s4_pwm_parents, + .num_parents = ARRAY_SIZE(s4_pwm_parents), .flags = 0, }, }; @@ -2592,14 +2584,14 @@ static struct clk_regmap s4_pwm_a_div = { .name = "pwm_a_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_a_mux.hw + &s4_pwm_a_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_pwm_a_gate = { +static struct clk_regmap s4_pwm_a = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_PWM_CLK_AB_CTRL, .bit_idx = 8, @@ -2615,17 +2607,17 @@ static struct clk_regmap s4_pwm_a_gate = { }, }; -static struct clk_regmap s4_pwm_b_mux = { +static struct clk_regmap s4_pwm_b_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_PWM_CLK_AB_CTRL, .mask = 0x3, .shift = 25, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_b_mux", + .name = "pwm_b_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parent_data, - .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .parent_data = s4_pwm_parents, + .num_parents = ARRAY_SIZE(s4_pwm_parents), .flags = 0, }, }; @@ -2640,20 +2632,20 @@ static struct clk_regmap s4_pwm_b_div = { .name = "pwm_b_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_b_mux.hw + &s4_pwm_b_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_pwm_b_gate = { +static struct clk_regmap s4_pwm_b = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_PWM_CLK_AB_CTRL, .bit_idx = 24, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_b_gate", + .name = "pwm_b", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_pwm_b_div.hw @@ -2663,7 +2655,7 @@ static struct clk_regmap s4_pwm_b_gate = { }, }; -static struct clk_regmap s4_pwm_c_mux = { +static struct clk_regmap s4_pwm_c_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_PWM_CLK_CD_CTRL, .mask = 0x3, @@ -2672,8 +2664,8 @@ static struct clk_regmap s4_pwm_c_mux = { .hw.init = &(struct clk_init_data){ .name = "pwm_c_mux", .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parent_data, - .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .parent_data = s4_pwm_parents, + .num_parents = ARRAY_SIZE(s4_pwm_parents), .flags = 0, }, }; @@ -2688,19 +2680,19 @@ static struct clk_regmap s4_pwm_c_div = { .name = "pwm_c_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_c_mux.hw + &s4_pwm_c_sel.hw }, .num_parents = 1, }, }; -static struct clk_regmap s4_pwm_c_gate = { +static struct clk_regmap s4_pwm_c = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_PWM_CLK_CD_CTRL, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_c_gate", + .name = "pwm_c", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_pwm_c_div.hw @@ -2710,17 +2702,17 @@ static struct clk_regmap s4_pwm_c_gate = { }, }; -static struct clk_regmap s4_pwm_d_mux = { +static struct clk_regmap s4_pwm_d_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_PWM_CLK_CD_CTRL, .mask = 0x3, .shift = 25, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_d_mux", + .name = "pwm_d_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parent_data, - .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .parent_data = s4_pwm_parents, + .num_parents = ARRAY_SIZE(s4_pwm_parents), .flags = 0, }, }; @@ -2735,20 +2727,20 @@ static struct clk_regmap s4_pwm_d_div = { .name = "pwm_d_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_d_mux.hw + &s4_pwm_d_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_pwm_d_gate = { +static struct clk_regmap s4_pwm_d = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_PWM_CLK_CD_CTRL, .bit_idx = 24, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_d_gate", + .name = "pwm_d", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_pwm_d_div.hw @@ -2758,17 +2750,17 @@ static struct clk_regmap s4_pwm_d_gate = { }, }; -static struct clk_regmap s4_pwm_e_mux = { +static struct clk_regmap s4_pwm_e_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_PWM_CLK_EF_CTRL, .mask = 0x3, .shift = 9, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_e_mux", + .name = "pwm_e_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parent_data, - .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .parent_data = s4_pwm_parents, + .num_parents = ARRAY_SIZE(s4_pwm_parents), .flags = 0, }, }; @@ -2783,20 +2775,20 @@ static struct clk_regmap s4_pwm_e_div = { .name = "pwm_e_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_e_mux.hw + &s4_pwm_e_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_pwm_e_gate = { +static struct clk_regmap s4_pwm_e = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_PWM_CLK_EF_CTRL, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_e_gate", + .name = "pwm_e", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_pwm_e_div.hw @@ -2806,17 +2798,17 @@ static struct clk_regmap s4_pwm_e_gate = { }, }; -static struct clk_regmap s4_pwm_f_mux = { +static struct clk_regmap s4_pwm_f_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_PWM_CLK_EF_CTRL, .mask = 0x3, .shift = 25, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_f_mux", + .name = "pwm_f_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parent_data, - .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .parent_data = s4_pwm_parents, + .num_parents = ARRAY_SIZE(s4_pwm_parents), .flags = 0, }, }; @@ -2831,20 +2823,20 @@ static struct clk_regmap s4_pwm_f_div = { .name = "pwm_f_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_f_mux.hw + &s4_pwm_f_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_pwm_f_gate = { +static struct clk_regmap s4_pwm_f = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_PWM_CLK_EF_CTRL, .bit_idx = 24, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_f_gate", + .name = "pwm_f", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_pwm_f_div.hw @@ -2854,17 +2846,17 @@ static struct clk_regmap s4_pwm_f_gate = { }, }; -static struct clk_regmap s4_pwm_g_mux = { +static struct clk_regmap s4_pwm_g_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_PWM_CLK_GH_CTRL, .mask = 0x3, .shift = 9, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_g_mux", + .name = "pwm_g_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parent_data, - .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .parent_data = s4_pwm_parents, + .num_parents = ARRAY_SIZE(s4_pwm_parents), .flags = 0, }, }; @@ -2879,20 +2871,20 @@ static struct clk_regmap s4_pwm_g_div = { .name = "pwm_g_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_g_mux.hw + &s4_pwm_g_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_pwm_g_gate = { +static struct clk_regmap s4_pwm_g = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_PWM_CLK_GH_CTRL, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_g_gate", + .name = "pwm_g", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_pwm_g_div.hw @@ -2902,17 +2894,17 @@ static struct clk_regmap s4_pwm_g_gate = { }, }; -static struct clk_regmap s4_pwm_h_mux = { +static struct clk_regmap s4_pwm_h_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_PWM_CLK_GH_CTRL, .mask = 0x3, .shift = 25, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_h_mux", + .name = "pwm_h_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parent_data, - .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .parent_data = s4_pwm_parents, + .num_parents = ARRAY_SIZE(s4_pwm_parents), .flags = 0, }, }; @@ -2927,20 +2919,20 @@ static struct clk_regmap s4_pwm_h_div = { .name = "pwm_h_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_h_mux.hw + &s4_pwm_h_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_pwm_h_gate = { +static struct clk_regmap s4_pwm_h = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_PWM_CLK_GH_CTRL, .bit_idx = 24, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_h_gate", + .name = "pwm_h", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_pwm_h_div.hw @@ -2950,17 +2942,17 @@ static struct clk_regmap s4_pwm_h_gate = { }, }; -static struct clk_regmap s4_pwm_i_mux = { +static struct clk_regmap s4_pwm_i_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_PWM_CLK_IJ_CTRL, .mask = 0x3, .shift = 9, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_i_mux", + .name = "pwm_i_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parent_data, - .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .parent_data = s4_pwm_parents, + .num_parents = ARRAY_SIZE(s4_pwm_parents), .flags = 0, }, }; @@ -2975,20 +2967,20 @@ static struct clk_regmap s4_pwm_i_div = { .name = "pwm_i_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_i_mux.hw + &s4_pwm_i_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_pwm_i_gate = { +static struct clk_regmap s4_pwm_i = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_PWM_CLK_IJ_CTRL, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_i_gate", + .name = "pwm_i", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_pwm_i_div.hw @@ -2998,17 +2990,17 @@ static struct clk_regmap s4_pwm_i_gate = { }, }; -static struct clk_regmap s4_pwm_j_mux = { +static struct clk_regmap s4_pwm_j_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_PWM_CLK_IJ_CTRL, .mask = 0x3, .shift = 25, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_j_mux", + .name = "pwm_j_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parent_data, - .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .parent_data = s4_pwm_parents, + .num_parents = ARRAY_SIZE(s4_pwm_parents), .flags = 0, }, }; @@ -3023,20 +3015,20 @@ static struct clk_regmap s4_pwm_j_div = { .name = "pwm_j_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_j_mux.hw + &s4_pwm_j_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_pwm_j_gate = { +static struct clk_regmap s4_pwm_j = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_PWM_CLK_IJ_CTRL, .bit_idx = 24, }, .hw.init = &(struct clk_init_data){ - .name = "pwm_j_gate", + .name = "pwm_j", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_pwm_j_div.hw @@ -3046,14 +3038,14 @@ static struct clk_regmap s4_pwm_j_gate = { }, }; -static struct clk_regmap s4_saradc_mux = { +static struct clk_regmap s4_saradc_sel = { .data = &(struct clk_regmap_mux_data) { .offset = CLKCTRL_SAR_CLK_CTRL, .mask = 0x3, .shift = 9, }, .hw.init = &(struct clk_init_data){ - .name = "saradc_mux", + .name = "saradc_sel", .ops = &clk_regmap_mux_ops, .parent_data = (const struct clk_parent_data []) { { .fw_name = "xtal", }, @@ -3074,20 +3066,20 @@ static struct clk_regmap s4_saradc_div = { .name = "saradc_div", .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { - &s4_saradc_mux.hw + &s4_saradc_sel.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap s4_saradc_gate = { +static struct clk_regmap s4_saradc = { .data = &(struct clk_regmap_gate_data) { .offset = CLKCTRL_SAR_CLK_CTRL, .bit_idx = 8, }, .hw.init = &(struct clk_init_data){ - .name = "saradc_clk", + .name = "saradc", .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &s4_saradc_div.hw @@ -3102,9 +3094,8 @@ static struct clk_regmap s4_saradc_gate = { * corresponding clock sources are not described in the clock tree and internal clock * for debug, so they are skipped. */ -static u32 s4_gen_clk_mux_table[] = { 0, 4, 5, 7, 19, 21, 22, - 23, 24, 25, 26, 27, 28 }; -static const struct clk_parent_data s4_gen_clk_parent_data[] = { +static u32 s4_gen_clk_parents_val_table[] = { 0, 4, 5, 7, 19, 21, 22, 23, 24, 25, 26, 27, 28 }; +static const struct clk_parent_data s4_gen_clk_parents[] = { { .fw_name = "xtal", }, { .hw = &s4_vid_pll.hw }, { .fw_name = "gp0_pll", }, @@ -3125,13 +3116,13 @@ static struct clk_regmap s4_gen_clk_sel = { .offset = CLKCTRL_GEN_CLK_CTRL, .mask = 0x1f, .shift = 12, - .table = s4_gen_clk_mux_table, + .table = s4_gen_clk_parents_val_table, }, .hw.init = &(struct clk_init_data){ .name = "gen_clk_sel", .ops = &clk_regmap_mux_ops, - .parent_data = s4_gen_clk_parent_data, - .num_parents = ARRAY_SIZE(s4_gen_clk_parent_data), + .parent_data = s4_gen_clk_parents, + .num_parents = ARRAY_SIZE(s4_gen_clk_parents), /* * Because the GEN clock can be connected to an external pad * and may be set up directly from the device tree. Don't @@ -3174,61 +3165,64 @@ static struct clk_regmap s4_gen_clk = { }, }; -#define MESON_GATE(_name, _reg, _bit) \ +#define S4_PCLK(_name, _reg, _bit) \ MESON_PCLK(_name, _reg, _bit, &s4_sys_clk.hw) -static MESON_GATE(s4_ddr, CLKCTRL_SYS_CLK_EN0_REG0, 0); -static MESON_GATE(s4_dos, CLKCTRL_SYS_CLK_EN0_REG0, 1); -static MESON_GATE(s4_ethphy, CLKCTRL_SYS_CLK_EN0_REG0, 4); -static MESON_GATE(s4_mali, CLKCTRL_SYS_CLK_EN0_REG0, 6); -static MESON_GATE(s4_aocpu, CLKCTRL_SYS_CLK_EN0_REG0, 13); -static MESON_GATE(s4_aucpu, CLKCTRL_SYS_CLK_EN0_REG0, 14); -static MESON_GATE(s4_cec, CLKCTRL_SYS_CLK_EN0_REG0, 16); -static MESON_GATE(s4_sdemmca, CLKCTRL_SYS_CLK_EN0_REG0, 24); -static MESON_GATE(s4_sdemmcb, CLKCTRL_SYS_CLK_EN0_REG0, 25); -static MESON_GATE(s4_nand, CLKCTRL_SYS_CLK_EN0_REG0, 26); -static MESON_GATE(s4_smartcard, CLKCTRL_SYS_CLK_EN0_REG0, 27); -static MESON_GATE(s4_acodec, CLKCTRL_SYS_CLK_EN0_REG0, 28); -static MESON_GATE(s4_spifc, CLKCTRL_SYS_CLK_EN0_REG0, 29); -static MESON_GATE(s4_msr_clk, CLKCTRL_SYS_CLK_EN0_REG0, 30); -static MESON_GATE(s4_ir_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 31); -static MESON_GATE(s4_audio, CLKCTRL_SYS_CLK_EN0_REG1, 0); -static MESON_GATE(s4_eth, CLKCTRL_SYS_CLK_EN0_REG1, 3); -static MESON_GATE(s4_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 5); -static MESON_GATE(s4_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 6); -static MESON_GATE(s4_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 7); -static MESON_GATE(s4_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 8); -static MESON_GATE(s4_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 9); -static MESON_GATE(s4_aififo, CLKCTRL_SYS_CLK_EN0_REG1, 11); -static MESON_GATE(s4_ts_ddr, CLKCTRL_SYS_CLK_EN0_REG1, 15); -static MESON_GATE(s4_ts_pll, CLKCTRL_SYS_CLK_EN0_REG1, 16); -static MESON_GATE(s4_g2d, CLKCTRL_SYS_CLK_EN0_REG1, 20); -static MESON_GATE(s4_spicc0, CLKCTRL_SYS_CLK_EN0_REG1, 21); -static MESON_GATE(s4_usb, CLKCTRL_SYS_CLK_EN0_REG1, 26); -static MESON_GATE(s4_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 30); -static MESON_GATE(s4_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 31); -static MESON_GATE(s4_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG2, 0); -static MESON_GATE(s4_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG2, 1); -static MESON_GATE(s4_i2c_m_e, CLKCTRL_SYS_CLK_EN0_REG2, 2); -static MESON_GATE(s4_hdmitx_apb, CLKCTRL_SYS_CLK_EN0_REG2, 4); -static MESON_GATE(s4_i2c_s_a, CLKCTRL_SYS_CLK_EN0_REG2, 5); -static MESON_GATE(s4_usb1_to_ddr, CLKCTRL_SYS_CLK_EN0_REG2, 8); -static MESON_GATE(s4_hdcp22, CLKCTRL_SYS_CLK_EN0_REG2, 10); -static MESON_GATE(s4_mmc_apb, CLKCTRL_SYS_CLK_EN0_REG2, 11); -static MESON_GATE(s4_rsa, CLKCTRL_SYS_CLK_EN0_REG2, 18); -static MESON_GATE(s4_cpu_debug, CLKCTRL_SYS_CLK_EN0_REG2, 19); -static MESON_GATE(s4_vpu_intr, CLKCTRL_SYS_CLK_EN0_REG2, 25); -static MESON_GATE(s4_demod, CLKCTRL_SYS_CLK_EN0_REG2, 27); -static MESON_GATE(s4_sar_adc, CLKCTRL_SYS_CLK_EN0_REG2, 28); -static MESON_GATE(s4_gic, CLKCTRL_SYS_CLK_EN0_REG2, 30); -static MESON_GATE(s4_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG3, 7); -static MESON_GATE(s4_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG3, 8); -static MESON_GATE(s4_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG3, 9); -static MESON_GATE(s4_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG3, 10); -static MESON_GATE(s4_pwm_ij, CLKCTRL_SYS_CLK_EN0_REG3, 11); +static S4_PCLK(s4_ddr, CLKCTRL_SYS_CLK_EN0_REG0, 0); +static S4_PCLK(s4_dos, CLKCTRL_SYS_CLK_EN0_REG0, 1); +static S4_PCLK(s4_ethphy, CLKCTRL_SYS_CLK_EN0_REG0, 4); +static S4_PCLK(s4_mali, CLKCTRL_SYS_CLK_EN0_REG0, 6); +static S4_PCLK(s4_aocpu, CLKCTRL_SYS_CLK_EN0_REG0, 13); +static S4_PCLK(s4_aucpu, CLKCTRL_SYS_CLK_EN0_REG0, 14); +static S4_PCLK(s4_cec, CLKCTRL_SYS_CLK_EN0_REG0, 16); +static S4_PCLK(s4_sdemmca, CLKCTRL_SYS_CLK_EN0_REG0, 24); +static S4_PCLK(s4_sdemmcb, CLKCTRL_SYS_CLK_EN0_REG0, 25); +static S4_PCLK(s4_nand, CLKCTRL_SYS_CLK_EN0_REG0, 26); +static S4_PCLK(s4_smartcard, CLKCTRL_SYS_CLK_EN0_REG0, 27); +static S4_PCLK(s4_acodec, CLKCTRL_SYS_CLK_EN0_REG0, 28); +static S4_PCLK(s4_spifc, CLKCTRL_SYS_CLK_EN0_REG0, 29); +static S4_PCLK(s4_msr_clk, CLKCTRL_SYS_CLK_EN0_REG0, 30); +static S4_PCLK(s4_ir_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 31); + +static S4_PCLK(s4_audio, CLKCTRL_SYS_CLK_EN0_REG1, 0); +static S4_PCLK(s4_eth, CLKCTRL_SYS_CLK_EN0_REG1, 3); +static S4_PCLK(s4_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 5); +static S4_PCLK(s4_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 6); +static S4_PCLK(s4_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 7); +static S4_PCLK(s4_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 8); +static S4_PCLK(s4_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 9); +static S4_PCLK(s4_aififo, CLKCTRL_SYS_CLK_EN0_REG1, 11); +static S4_PCLK(s4_ts_ddr, CLKCTRL_SYS_CLK_EN0_REG1, 15); +static S4_PCLK(s4_ts_pll, CLKCTRL_SYS_CLK_EN0_REG1, 16); +static S4_PCLK(s4_g2d, CLKCTRL_SYS_CLK_EN0_REG1, 20); +static S4_PCLK(s4_spicc0, CLKCTRL_SYS_CLK_EN0_REG1, 21); +static S4_PCLK(s4_usb, CLKCTRL_SYS_CLK_EN0_REG1, 26); +static S4_PCLK(s4_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 30); +static S4_PCLK(s4_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 31); + +static S4_PCLK(s4_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG2, 0); +static S4_PCLK(s4_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG2, 1); +static S4_PCLK(s4_i2c_m_e, CLKCTRL_SYS_CLK_EN0_REG2, 2); +static S4_PCLK(s4_hdmitx_apb, CLKCTRL_SYS_CLK_EN0_REG2, 4); +static S4_PCLK(s4_i2c_s_a, CLKCTRL_SYS_CLK_EN0_REG2, 5); +static S4_PCLK(s4_usb1_to_ddr, CLKCTRL_SYS_CLK_EN0_REG2, 8); +static S4_PCLK(s4_hdcp22, CLKCTRL_SYS_CLK_EN0_REG2, 10); +static S4_PCLK(s4_mmc_apb, CLKCTRL_SYS_CLK_EN0_REG2, 11); +static S4_PCLK(s4_rsa, CLKCTRL_SYS_CLK_EN0_REG2, 18); +static S4_PCLK(s4_cpu_debug, CLKCTRL_SYS_CLK_EN0_REG2, 19); +static S4_PCLK(s4_vpu_intr, CLKCTRL_SYS_CLK_EN0_REG2, 25); +static S4_PCLK(s4_demod, CLKCTRL_SYS_CLK_EN0_REG2, 27); +static S4_PCLK(s4_sar_adc, CLKCTRL_SYS_CLK_EN0_REG2, 28); +static S4_PCLK(s4_gic, CLKCTRL_SYS_CLK_EN0_REG2, 30); + +static S4_PCLK(s4_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG3, 7); +static S4_PCLK(s4_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG3, 8); +static S4_PCLK(s4_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG3, 9); +static S4_PCLK(s4_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG3, 10); +static S4_PCLK(s4_pwm_ij, CLKCTRL_SYS_CLK_EN0_REG3, 11); /* Array of all clocks provided by this provider */ -static struct clk_hw *s4_periphs_hw_clks[] = { +static struct clk_hw *s4_peripherals_hw_clks[] = { [CLKID_RTC_32K_CLKIN] = &s4_rtc_32k_by_oscin_clkin.hw, [CLKID_RTC_32K_DIV] = &s4_rtc_32k_by_oscin_div.hw, [CLKID_RTC_32K_SEL] = &s4_rtc_32k_by_oscin_sel.hw, @@ -3251,12 +3245,12 @@ static struct clk_hw *s4_periphs_hw_clks[] = { [CLKID_CECB_32K_SEL_PRE] = &s4_cecb_32k_sel_pre.hw, [CLKID_CECB_32K_SEL] = &s4_cecb_32k_sel.hw, [CLKID_CECB_32K_CLKOUT] = &s4_cecb_32k_clkout.hw, - [CLKID_SC_CLK_SEL] = &s4_sc_clk_mux.hw, + [CLKID_SC_CLK_SEL] = &s4_sc_clk_sel.hw, [CLKID_SC_CLK_DIV] = &s4_sc_clk_div.hw, - [CLKID_SC] = &s4_sc_clk_gate.hw, - [CLKID_12_24M] = &s4_12_24M_clk_gate.hw, - [CLKID_12M_CLK_DIV] = &s4_12M_clk_div.hw, - [CLKID_12_24M_CLK_SEL] = &s4_12_24M_clk.hw, + [CLKID_SC] = &s4_sc_clk.hw, + [CLKID_12_24M] = &s4_12_24M.hw, + [CLKID_12M_CLK_DIV] = &s4_12M_div.hw, + [CLKID_12_24M_CLK_SEL] = &s4_12_24M_sel.hw, [CLKID_VID_PLL_DIV] = &s4_vid_pll_div.hw, [CLKID_VID_PLL_SEL] = &s4_vid_pll_sel.hw, [CLKID_VID_PLL] = &s4_vid_pll.hw, @@ -3298,28 +3292,28 @@ static struct clk_hw *s4_periphs_hw_clks[] = { [CLKID_HDMI_DIV] = &s4_hdmi_div.hw, [CLKID_HDMI] = &s4_hdmi.hw, [CLKID_TS_CLK_DIV] = &s4_ts_clk_div.hw, - [CLKID_TS] = &s4_ts_clk_gate.hw, + [CLKID_TS] = &s4_ts_clk.hw, [CLKID_MALI_0_SEL] = &s4_mali_0_sel.hw, [CLKID_MALI_0_DIV] = &s4_mali_0_div.hw, [CLKID_MALI_0] = &s4_mali_0.hw, [CLKID_MALI_1_SEL] = &s4_mali_1_sel.hw, [CLKID_MALI_1_DIV] = &s4_mali_1_div.hw, [CLKID_MALI_1] = &s4_mali_1.hw, - [CLKID_MALI_SEL] = &s4_mali_mux.hw, - [CLKID_VDEC_P0_SEL] = &s4_vdec_p0_mux.hw, + [CLKID_MALI_SEL] = &s4_mali_sel.hw, + [CLKID_VDEC_P0_SEL] = &s4_vdec_p0_sel.hw, [CLKID_VDEC_P0_DIV] = &s4_vdec_p0_div.hw, [CLKID_VDEC_P0] = &s4_vdec_p0.hw, - [CLKID_VDEC_P1_SEL] = &s4_vdec_p1_mux.hw, + [CLKID_VDEC_P1_SEL] = &s4_vdec_p1_sel.hw, [CLKID_VDEC_P1_DIV] = &s4_vdec_p1_div.hw, [CLKID_VDEC_P1] = &s4_vdec_p1.hw, - [CLKID_VDEC_SEL] = &s4_vdec_mux.hw, - [CLKID_HEVCF_P0_SEL] = &s4_hevcf_p0_mux.hw, + [CLKID_VDEC_SEL] = &s4_vdec_sel.hw, + [CLKID_HEVCF_P0_SEL] = &s4_hevcf_p0_sel.hw, [CLKID_HEVCF_P0_DIV] = &s4_hevcf_p0_div.hw, [CLKID_HEVCF_P0] = &s4_hevcf_p0.hw, - [CLKID_HEVCF_P1_SEL] = &s4_hevcf_p1_mux.hw, + [CLKID_HEVCF_P1_SEL] = &s4_hevcf_p1_sel.hw, [CLKID_HEVCF_P1_DIV] = &s4_hevcf_p1_div.hw, [CLKID_HEVCF_P1] = &s4_hevcf_p1.hw, - [CLKID_HEVCF_SEL] = &s4_hevcf_mux.hw, + [CLKID_HEVCF_SEL] = &s4_hevcf_sel.hw, [CLKID_VPU_0_SEL] = &s4_vpu_0_sel.hw, [CLKID_VPU_0_DIV] = &s4_vpu_0_div.hw, [CLKID_VPU_0] = &s4_vpu_0.hw, @@ -3327,18 +3321,18 @@ static struct clk_hw *s4_periphs_hw_clks[] = { [CLKID_VPU_1_DIV] = &s4_vpu_1_div.hw, [CLKID_VPU_1] = &s4_vpu_1.hw, [CLKID_VPU] = &s4_vpu.hw, - [CLKID_VPU_CLKB_TMP_SEL] = &s4_vpu_clkb_tmp_mux.hw, + [CLKID_VPU_CLKB_TMP_SEL] = &s4_vpu_clkb_tmp_sel.hw, [CLKID_VPU_CLKB_TMP_DIV] = &s4_vpu_clkb_tmp_div.hw, [CLKID_VPU_CLKB_TMP] = &s4_vpu_clkb_tmp.hw, [CLKID_VPU_CLKB_DIV] = &s4_vpu_clkb_div.hw, [CLKID_VPU_CLKB] = &s4_vpu_clkb.hw, - [CLKID_VPU_CLKC_P0_SEL] = &s4_vpu_clkc_p0_mux.hw, + [CLKID_VPU_CLKC_P0_SEL] = &s4_vpu_clkc_p0_sel.hw, [CLKID_VPU_CLKC_P0_DIV] = &s4_vpu_clkc_p0_div.hw, [CLKID_VPU_CLKC_P0] = &s4_vpu_clkc_p0.hw, - [CLKID_VPU_CLKC_P1_SEL] = &s4_vpu_clkc_p1_mux.hw, + [CLKID_VPU_CLKC_P1_SEL] = &s4_vpu_clkc_p1_sel.hw, [CLKID_VPU_CLKC_P1_DIV] = &s4_vpu_clkc_p1_div.hw, [CLKID_VPU_CLKC_P1] = &s4_vpu_clkc_p1.hw, - [CLKID_VPU_CLKC_SEL] = &s4_vpu_clkc_mux.hw, + [CLKID_VPU_CLKC_SEL] = &s4_vpu_clkc_sel.hw, [CLKID_VAPB_0_SEL] = &s4_vapb_0_sel.hw, [CLKID_VAPB_0_DIV] = &s4_vapb_0_div.hw, [CLKID_VAPB_0] = &s4_vapb_0.hw, @@ -3346,10 +3340,10 @@ static struct clk_hw *s4_periphs_hw_clks[] = { [CLKID_VAPB_1_DIV] = &s4_vapb_1_div.hw, [CLKID_VAPB_1] = &s4_vapb_1.hw, [CLKID_VAPB] = &s4_vapb.hw, - [CLKID_GE2D] = &s4_ge2d_gate.hw, - [CLKID_VDIN_MEAS_SEL] = &s4_vdin_meas_mux.hw, + [CLKID_GE2D] = &s4_ge2d.hw, + [CLKID_VDIN_MEAS_SEL] = &s4_vdin_meas_sel.hw, [CLKID_VDIN_MEAS_DIV] = &s4_vdin_meas_div.hw, - [CLKID_VDIN_MEAS] = &s4_vdin_meas_gate.hw, + [CLKID_VDIN_MEAS] = &s4_vdin_meas.hw, [CLKID_SD_EMMC_C_CLK_SEL] = &s4_sd_emmc_c_clk0_sel.hw, [CLKID_SD_EMMC_C_CLK_DIV] = &s4_sd_emmc_c_clk0_div.hw, [CLKID_SD_EMMC_C] = &s4_sd_emmc_c_clk0.hw, @@ -3359,42 +3353,42 @@ static struct clk_hw *s4_periphs_hw_clks[] = { [CLKID_SD_EMMC_B_CLK_SEL] = &s4_sd_emmc_b_clk0_sel.hw, [CLKID_SD_EMMC_B_CLK_DIV] = &s4_sd_emmc_b_clk0_div.hw, [CLKID_SD_EMMC_B] = &s4_sd_emmc_b_clk0.hw, - [CLKID_SPICC0_SEL] = &s4_spicc0_mux.hw, + [CLKID_SPICC0_SEL] = &s4_spicc0_sel.hw, [CLKID_SPICC0_DIV] = &s4_spicc0_div.hw, - [CLKID_SPICC0_EN] = &s4_spicc0_gate.hw, - [CLKID_PWM_A_SEL] = &s4_pwm_a_mux.hw, + [CLKID_SPICC0_EN] = &s4_spicc0_en.hw, + [CLKID_PWM_A_SEL] = &s4_pwm_a_sel.hw, [CLKID_PWM_A_DIV] = &s4_pwm_a_div.hw, - [CLKID_PWM_A] = &s4_pwm_a_gate.hw, - [CLKID_PWM_B_SEL] = &s4_pwm_b_mux.hw, + [CLKID_PWM_A] = &s4_pwm_a.hw, + [CLKID_PWM_B_SEL] = &s4_pwm_b_sel.hw, [CLKID_PWM_B_DIV] = &s4_pwm_b_div.hw, - [CLKID_PWM_B] = &s4_pwm_b_gate.hw, - [CLKID_PWM_C_SEL] = &s4_pwm_c_mux.hw, + [CLKID_PWM_B] = &s4_pwm_b.hw, + [CLKID_PWM_C_SEL] = &s4_pwm_c_sel.hw, [CLKID_PWM_C_DIV] = &s4_pwm_c_div.hw, - [CLKID_PWM_C] = &s4_pwm_c_gate.hw, - [CLKID_PWM_D_SEL] = &s4_pwm_d_mux.hw, + [CLKID_PWM_C] = &s4_pwm_c.hw, + [CLKID_PWM_D_SEL] = &s4_pwm_d_sel.hw, [CLKID_PWM_D_DIV] = &s4_pwm_d_div.hw, - [CLKID_PWM_D] = &s4_pwm_d_gate.hw, - [CLKID_PWM_E_SEL] = &s4_pwm_e_mux.hw, + [CLKID_PWM_D] = &s4_pwm_d.hw, + [CLKID_PWM_E_SEL] = &s4_pwm_e_sel.hw, [CLKID_PWM_E_DIV] = &s4_pwm_e_div.hw, - [CLKID_PWM_E] = &s4_pwm_e_gate.hw, - [CLKID_PWM_F_SEL] = &s4_pwm_f_mux.hw, + [CLKID_PWM_E] = &s4_pwm_e.hw, + [CLKID_PWM_F_SEL] = &s4_pwm_f_sel.hw, [CLKID_PWM_F_DIV] = &s4_pwm_f_div.hw, - [CLKID_PWM_F] = &s4_pwm_f_gate.hw, - [CLKID_PWM_G_SEL] = &s4_pwm_g_mux.hw, + [CLKID_PWM_F] = &s4_pwm_f.hw, + [CLKID_PWM_G_SEL] = &s4_pwm_g_sel.hw, [CLKID_PWM_G_DIV] = &s4_pwm_g_div.hw, - [CLKID_PWM_G] = &s4_pwm_g_gate.hw, - [CLKID_PWM_H_SEL] = &s4_pwm_h_mux.hw, + [CLKID_PWM_G] = &s4_pwm_g.hw, + [CLKID_PWM_H_SEL] = &s4_pwm_h_sel.hw, [CLKID_PWM_H_DIV] = &s4_pwm_h_div.hw, - [CLKID_PWM_H] = &s4_pwm_h_gate.hw, - [CLKID_PWM_I_SEL] = &s4_pwm_i_mux.hw, + [CLKID_PWM_H] = &s4_pwm_h.hw, + [CLKID_PWM_I_SEL] = &s4_pwm_i_sel.hw, [CLKID_PWM_I_DIV] = &s4_pwm_i_div.hw, - [CLKID_PWM_I] = &s4_pwm_i_gate.hw, - [CLKID_PWM_J_SEL] = &s4_pwm_j_mux.hw, + [CLKID_PWM_I] = &s4_pwm_i.hw, + [CLKID_PWM_J_SEL] = &s4_pwm_j_sel.hw, [CLKID_PWM_J_DIV] = &s4_pwm_j_div.hw, - [CLKID_PWM_J] = &s4_pwm_j_gate.hw, - [CLKID_SARADC_SEL] = &s4_saradc_mux.hw, + [CLKID_PWM_J] = &s4_pwm_j.hw, + [CLKID_SARADC_SEL] = &s4_saradc_sel.hw, [CLKID_SARADC_DIV] = &s4_saradc_div.hw, - [CLKID_SARADC] = &s4_saradc_gate.hw, + [CLKID_SARADC] = &s4_saradc.hw, [CLKID_GEN_SEL] = &s4_gen_clk_sel.hw, [CLKID_GEN_DIV] = &s4_gen_clk_div.hw, [CLKID_GEN] = &s4_gen_clk.hw, @@ -3447,27 +3441,27 @@ static struct clk_hw *s4_periphs_hw_clks[] = { [CLKID_PWM_EF] = &s4_pwm_ef.hw, [CLKID_PWM_GH] = &s4_pwm_gh.hw, [CLKID_PWM_IJ] = &s4_pwm_ij.hw, - [CLKID_HDCP22_ESMCLK_SEL] = &s4_hdcp22_esmclk_mux.hw, + [CLKID_HDCP22_ESMCLK_SEL] = &s4_hdcp22_esmclk_sel.hw, [CLKID_HDCP22_ESMCLK_DIV] = &s4_hdcp22_esmclk_div.hw, - [CLKID_HDCP22_ESMCLK] = &s4_hdcp22_esmclk_gate.hw, - [CLKID_HDCP22_SKPCLK_SEL] = &s4_hdcp22_skpclk_mux.hw, + [CLKID_HDCP22_ESMCLK] = &s4_hdcp22_esmclk.hw, + [CLKID_HDCP22_SKPCLK_SEL] = &s4_hdcp22_skpclk_sel.hw, [CLKID_HDCP22_SKPCLK_DIV] = &s4_hdcp22_skpclk_div.hw, - [CLKID_HDCP22_SKPCLK] = &s4_hdcp22_skpclk_gate.hw, + [CLKID_HDCP22_SKPCLK] = &s4_hdcp22_skpclk.hw, }; -static const struct regmap_config clkc_regmap_config = { +static const struct regmap_config s4_peripherals_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .max_register = CLKCTRL_DEMOD_CLK_CTRL, }; -static struct meson_clk_hw_data s4_periphs_clks = { - .hws = s4_periphs_hw_clks, - .num = ARRAY_SIZE(s4_periphs_hw_clks), +static struct meson_clk_hw_data s4_peripherals_clks = { + .hws = s4_peripherals_hw_clks, + .num = ARRAY_SIZE(s4_peripherals_hw_clks), }; -static int meson_s4_periphs_probe(struct platform_device *pdev) +static int s4_peripherals_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct regmap *regmap; @@ -3479,41 +3473,41 @@ static int meson_s4_periphs_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(base), "can't ioremap resource\n"); - regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config); + regmap = devm_regmap_init_mmio(dev, base, &s4_peripherals_regmap_cfg); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "can't init regmap mmio region\n"); - for (i = 0; i < s4_periphs_clks.num; i++) { + for (i = 0; i < s4_peripherals_clks.num; i++) { /* array might be sparse */ - if (!s4_periphs_clks.hws[i]) + if (!s4_peripherals_clks.hws[i]) continue; - ret = devm_clk_hw_register(dev, s4_periphs_clks.hws[i]); + ret = devm_clk_hw_register(dev, s4_peripherals_clks.hws[i]); if (ret) return dev_err_probe(dev, ret, "clock[%d] registration failed\n", i); } - return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, &s4_periphs_clks); + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, &s4_peripherals_clks); } -static const struct of_device_id clkc_match_table[] = { +static const struct of_device_id s4_peripherals_clkc_match_table[] = { { .compatible = "amlogic,s4-peripherals-clkc", }, {} }; -MODULE_DEVICE_TABLE(of, clkc_match_table); +MODULE_DEVICE_TABLE(of, s4_peripherals_clkc_match_table); -static struct platform_driver s4_driver = { - .probe = meson_s4_periphs_probe, +static struct platform_driver s4_peripherals_clkc_driver = { + .probe = s4_peripherals_clkc_probe, .driver = { - .name = "s4-periphs-clkc", - .of_match_table = clkc_match_table, + .name = "s4-peripherals-clkc", + .of_match_table = s4_peripherals_clkc_match_table, }, }; -module_platform_driver(s4_driver); +module_platform_driver(s4_peripherals_clkc_driver); MODULE_DESCRIPTION("Amlogic S4 Peripherals Clock Controller driver"); MODULE_AUTHOR("Yu Tu "); diff --git a/drivers/clk/meson/s4-pll.c b/drivers/clk/meson/s4-pll.c index 3d689d2f003e..6a266bcafd62 100644 --- a/drivers/clk/meson/s4-pll.c +++ b/drivers/clk/meson/s4-pll.c @@ -281,7 +281,7 @@ static const struct pll_mult_range s4_gp0_pll_mult_range = { /* * Internal gp0 pll emulation configuration parameters */ -static const struct reg_sequence s4_gp0_init_regs[] = { +static const struct reg_sequence s4_gp0_pll_init_regs[] = { { .reg = ANACTRL_GP0PLL_CTRL1, .def = 0x00000000 }, { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x00000000 }, { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x48681c00 }, @@ -318,8 +318,8 @@ static struct clk_regmap s4_gp0_pll_dco = { .width = 1, }, .range = &s4_gp0_pll_mult_range, - .init_regs = s4_gp0_init_regs, - .init_count = ARRAY_SIZE(s4_gp0_init_regs), + .init_regs = s4_gp0_pll_init_regs, + .init_count = ARRAY_SIZE(s4_gp0_pll_init_regs), }, .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", @@ -353,7 +353,7 @@ static struct clk_regmap s4_gp0_pll = { /* * Internal hifi pll emulation configuration parameters */ -static const struct reg_sequence s4_hifi_init_regs[] = { +static const struct reg_sequence s4_hifi_pll_init_regs[] = { { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 }, { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 }, { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 }, @@ -394,8 +394,8 @@ static struct clk_regmap s4_hifi_pll_dco = { .width = 1, }, .range = &s4_gp0_pll_mult_range, - .init_regs = s4_hifi_init_regs, - .init_count = ARRAY_SIZE(s4_hifi_init_regs), + .init_regs = s4_hifi_pll_init_regs, + .init_count = ARRAY_SIZE(s4_hifi_pll_init_regs), .frac_max = 100000, .flags = CLK_MESON_PLL_ROUND_CLOSEST, }, @@ -794,11 +794,11 @@ static struct clk_hw *s4_pll_hw_clks[] = { [CLKID_MPLL3] = &s4_mpll3.hw, }; -static const struct reg_sequence s4_init_regs[] = { +static const struct reg_sequence s4_pll_init_regs[] = { { .reg = ANACTRL_MPLL_CTRL0, .def = 0x00000543 }, }; -static const struct regmap_config clkc_regmap_config = { +static const struct regmap_config s4_pll_clkc_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -810,7 +810,7 @@ static struct meson_clk_hw_data s4_pll_clks = { .num = ARRAY_SIZE(s4_pll_hw_clks), }; -static int meson_s4_pll_probe(struct platform_device *pdev) +static int s4_pll_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct regmap *regmap; @@ -822,12 +822,12 @@ static int meson_s4_pll_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(base), "can't ioremap resource\n"); - regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config); + regmap = devm_regmap_init_mmio(dev, base, &s4_pll_clkc_regmap_cfg); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "can't init regmap mmio region\n"); - ret = regmap_multi_reg_write(regmap, s4_init_regs, ARRAY_SIZE(s4_init_regs)); + ret = regmap_multi_reg_write(regmap, s4_pll_init_regs, ARRAY_SIZE(s4_pll_init_regs)); if (ret) return dev_err_probe(dev, ret, "Failed to init registers\n"); @@ -848,22 +848,22 @@ static int meson_s4_pll_probe(struct platform_device *pdev) &s4_pll_clks); } -static const struct of_device_id clkc_match_table[] = { +static const struct of_device_id s4_pll_clkc_match_table[] = { { .compatible = "amlogic,s4-pll-clkc", }, {} }; -MODULE_DEVICE_TABLE(of, clkc_match_table); +MODULE_DEVICE_TABLE(of, s4_pll_clkc_match_table); -static struct platform_driver s4_driver = { - .probe = meson_s4_pll_probe, +static struct platform_driver s4_pll_clkc_driver = { + .probe = s4_pll_clkc_probe, .driver = { .name = "s4-pll-clkc", - .of_match_table = clkc_match_table, + .of_match_table = s4_pll_clkc_match_table, }, }; -module_platform_driver(s4_driver); +module_platform_driver(s4_pll_clkc_driver); MODULE_DESCRIPTION("Amlogic S4 PLL Clock Controller driver"); MODULE_AUTHOR("Yu Tu "); From 6bbf77bb22565332744c74e9806f8fb50402d73e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 20 Aug 2025 11:30:51 +0100 Subject: [PATCH 0508/2711] clk: renesas: r9a09g047: Add GPT clocks and resets Add clock and reset entries for the Renesas RZ/G3E GPT{0,1} IPs. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250820103053.93382-1-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a09g047-cpg.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/renesas/r9a09g047-cpg.c b/drivers/clk/renesas/r9a09g047-cpg.c index 4e8881e0006b..afd09b95fb74 100644 --- a/drivers/clk/renesas/r9a09g047-cpg.c +++ b/drivers/clk/renesas/r9a09g047-cpg.c @@ -198,6 +198,10 @@ static const struct rzv2h_mod_clk r9a09g047_mod_clks[] __initconst = { BUS_MSTOP_NONE), DEF_MOD_CRITICAL("gic_0_gicclk", CLK_PLLDTY_ACPU_DIV4, 1, 3, 0, 19, BUS_MSTOP(3, BIT(5))), + DEF_MOD("gpt_0_pclk_sfr", CLK_PLLCLN_DIV8, 3, 1, 1, 17, + BUS_MSTOP(6, BIT(11))), + DEF_MOD("gpt_1_pclk_sfr", CLK_PLLCLN_DIV8, 3, 2, 1, 18, + BUS_MSTOP(6, BIT(12))), DEF_MOD("wdt_1_clkp", CLK_PLLCLN_DIV16, 4, 13, 2, 13, BUS_MSTOP(1, BIT(0))), DEF_MOD("wdt_1_clk_loco", CLK_QEXTAL, 4, 14, 2, 14, @@ -322,6 +326,10 @@ static const struct rzv2h_reset r9a09g047_resets[] __initconst = { DEF_RST(3, 6, 1, 7), /* ICU_0_PRESETN_I */ DEF_RST(3, 8, 1, 9), /* GIC_0_GICRESET_N */ DEF_RST(3, 9, 1, 10), /* GIC_0_DBG_GICRESET_N */ + DEF_RST(5, 9, 2, 10), /* GPT_0_RST_P_REG */ + DEF_RST(5, 10, 2, 11), /* GPT_0_RST_S_REG */ + DEF_RST(5, 11, 2, 12), /* GPT_1_RST_P_REG */ + DEF_RST(5, 12, 2, 13), /* GPT_1_RST_S_REG */ DEF_RST(7, 6, 3, 7), /* WDT_1_RESET */ DEF_RST(7, 7, 3, 8), /* WDT_2_RESET */ DEF_RST(7, 8, 3, 9), /* WDT_3_RESET */ From 6e29c30d8ddea6109ea7e0b9f17e7841df0794ea Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 19 Jun 2025 15:57:22 -0500 Subject: [PATCH 0509/2711] rpmsg: char: Export alias for RPMSG ID rpmsg-raw from table Module aliases are used by userspace to identify the correct module to load for a detected hardware. The currently supported RPMSG device IDs for this module include "rpmsg-raw", but the module alias is "rpmsg_chrdev". Use the helper macro MODULE_DEVICE_TABLE(rpmsg) to export the correct supported IDs. And while here, to keep backwards compatibility we also add the other ID "rpmsg_chrdev" so that it is also still exported as an alias. This has the side benefit of adding support for some legacy firmware which still uses the original "rpmsg_chrdev" ID. This was the ID used for this driver before it was upstreamed (as reflected by the module alias). Signed-off-by: Andrew Davis Acked-by: Hari Nagalla Tested-by: Hari Nagalla Link: https://lore.kernel.org/r/20250619205722.133827-1-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/rpmsg/rpmsg_char.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index eec7642d2686..96fcdd2d7093 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -522,8 +522,10 @@ static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev) static struct rpmsg_device_id rpmsg_chrdev_id_table[] = { { .name = "rpmsg-raw" }, + { .name = "rpmsg_chrdev" }, { }, }; +MODULE_DEVICE_TABLE(rpmsg, rpmsg_chrdev_id_table); static struct rpmsg_driver rpmsg_chrdev_driver = { .probe = rpmsg_chrdev_probe, @@ -565,6 +567,5 @@ static void rpmsg_chrdev_exit(void) } module_exit(rpmsg_chrdev_exit); -MODULE_ALIAS("rpmsg:rpmsg_chrdev"); MODULE_DESCRIPTION("RPMSG device interface"); MODULE_LICENSE("GPL v2"); From 91812d3843409c235f336f32f1c37ddc790f1e03 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Sun, 24 Aug 2025 01:10:03 -0300 Subject: [PATCH 0510/2711] iio: adc: ad7768-1: use devm_regulator_get_enable_read_voltage() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_regulator_get_enable_read_voltage() function as a standard and concise way of reading the voltage from the regulator and keep the regulator enabled. Replace the regulator descriptor with the direct voltage value in the device struct. Reviewed-by: Nuno Sá Reviewed-by: Marcelo Schmitt Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/20250824041003.9727-1-Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index a27591bbf7df..872c88d0c86c 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -217,7 +217,7 @@ struct ad7768_state { struct spi_device *spi; struct regmap *regmap; struct regmap *regmap24; - struct regulator *vref; + int vref_uv; struct regulator_dev *vcm_rdev; unsigned int vcm_output_sel; struct clk *mclk; @@ -774,7 +774,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, { struct ad7768_state *st = iio_priv(indio_dev); const struct iio_scan_type *scan_type; - int scale_uv, ret, temp; + int ret, temp; scan_type = iio_get_current_scan_type(indio_dev, chan); if (IS_ERR(scan_type)) @@ -795,11 +795,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = regulator_get_voltage(st->vref); - if (scale_uv < 0) - return scale_uv; - - *val = (scale_uv * 2) / 1000; + *val = (st->vref_uv * 2) / 1000; *val2 = scan_type->realbits; return IIO_VAL_FRACTIONAL_LOG2; @@ -1132,13 +1128,6 @@ static const struct iio_trigger_ops ad7768_trigger_ops = { .validate_device = iio_trigger_validate_own_device, }; -static void ad7768_regulator_disable(void *data) -{ - struct ad7768_state *st = data; - - regulator_disable(st->vref); -} - static int ad7768_set_channel_label(struct iio_dev *indio_dev, int num_channels) { @@ -1370,19 +1359,11 @@ static int ad7768_probe(struct spi_device *spi) return dev_err_probe(&spi->dev, PTR_ERR(st->regmap24), "Failed to initialize regmap24"); - st->vref = devm_regulator_get(&spi->dev, "vref"); - if (IS_ERR(st->vref)) - return PTR_ERR(st->vref); - - ret = regulator_enable(st->vref); - if (ret) { - dev_err(&spi->dev, "Failed to enable specified vref supply\n"); - return ret; - } - - ret = devm_add_action_or_reset(&spi->dev, ad7768_regulator_disable, st); - if (ret) - return ret; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, + "Failed to get VREF voltage\n"); + st->vref_uv = ret; st->mclk = devm_clk_get_enabled(&spi->dev, "mclk"); if (IS_ERR(st->mclk)) From 358db735b172d95be85c388a950c9793bfd63e95 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:53:50 +0300 Subject: [PATCH 0511/2711] iio: accel: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250825135401.1765847-2-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel-core.c | 7 ++----- drivers/iio/accel/bmi088-accel-core.c | 3 --- drivers/iio/accel/fxls8962af-core.c | 1 - drivers/iio/accel/kxcjk-1013.c | 4 +--- drivers/iio/accel/kxsd9.c | 3 --- drivers/iio/accel/mma8452.c | 7 ++----- drivers/iio/accel/mma9551_core.c | 5 +---- drivers/iio/accel/msa311.c | 6 ------ 8 files changed, 6 insertions(+), 30 deletions(-) diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index be5fbb0c5d29..3c5d1560b163 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -332,13 +332,10 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) struct device *dev = regmap_get_device(data->regmap); int ret; - if (on) { + if (on) ret = pm_runtime_resume_and_get(dev); - } else { - pm_runtime_mark_last_busy(dev); + else ret = pm_runtime_put_autosuspend(dev); - } - if (ret < 0) { dev_err(dev, "Failed: %s for %d\n", __func__, on); diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c index dea126f993c1..c7da90af0d2d 100644 --- a/drivers/iio/accel/bmi088-accel-core.c +++ b/drivers/iio/accel/bmi088-accel-core.c @@ -375,7 +375,6 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev, return -EINVAL; out_read_raw_pm_put: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -419,7 +418,6 @@ static int bmi088_accel_write_raw(struct iio_dev *indio_dev, return ret; ret = bmi088_accel_set_scale(data, val, val2); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: @@ -428,7 +426,6 @@ static int bmi088_accel_write_raw(struct iio_dev *indio_dev, return ret; ret = bmi088_accel_set_sample_freq(data, val); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; default: diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index b10a30960e1e..8763e91c63d2 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -222,7 +222,6 @@ static int fxls8962af_power_off(struct fxls8962af_data *data) struct device *dev = regmap_get_device(data->regmap); int ret; - pm_runtime_mark_last_busy(dev); ret = pm_runtime_put_autosuspend(dev); if (ret) dev_err(dev, "failed to power off\n"); diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 6aefe8221296..2823ddde4bf2 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -636,10 +636,8 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) if (on) ret = pm_runtime_resume_and_get(&data->client->dev); - else { - pm_runtime_mark_last_busy(&data->client->dev); + else ret = pm_runtime_put_autosuspend(&data->client->dev); - } if (ret < 0) { dev_err(&data->client->dev, "Failed: %s for %d\n", __func__, on); diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index cfc31265cdd0..4717d80fc24a 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -151,7 +151,6 @@ static int kxsd9_write_raw(struct iio_dev *indio_dev, ret = kxsd9_write_scale(indio_dev, val2); } - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); return ret; @@ -199,7 +198,6 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev, } error_ret: - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); return ret; @@ -250,7 +248,6 @@ static int kxsd9_buffer_postdisable(struct iio_dev *indio_dev) { struct kxsd9_state *st = iio_priv(indio_dev); - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); return 0; diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index aba444a980d9..15172ba2972c 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -224,13 +224,10 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on) #ifdef CONFIG_PM int ret; - if (on) { + if (on) ret = pm_runtime_resume_and_get(&client->dev); - } else { - pm_runtime_mark_last_busy(&client->dev); + else ret = pm_runtime_put_autosuspend(&client->dev); - } - if (ret < 0) { dev_err(&client->dev, "failed to change power state to %d\n", on); diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index 3e7d9b79ed0e..2ccb1fb19b96 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -671,11 +671,8 @@ int mma9551_set_power_state(struct i2c_client *client, bool on) if (on) ret = pm_runtime_resume_and_get(&client->dev); - else { - pm_runtime_mark_last_busy(&client->dev); + else ret = pm_runtime_put_autosuspend(&client->dev); - } - if (ret < 0) { dev_err(&client->dev, "failed to change power state to %d\n", on); diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index cded0b3a8559..5eace0de3750 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -607,7 +607,6 @@ static int msa311_read_raw_data(struct iio_dev *indio_dev, err = msa311_get_axis(msa311, chan, &axis); mutex_unlock(&msa311->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); iio_device_release_direct(indio_dev); @@ -741,7 +740,6 @@ static int msa311_write_scale(struct iio_dev *indio_dev, int val, int val2) break; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); if (err) @@ -781,7 +779,6 @@ static int msa311_write_samp_freq(struct iio_dev *indio_dev, int val, int val2) break; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); iio_device_release_direct(indio_dev); @@ -832,7 +829,6 @@ static int msa311_debugfs_reg_access(struct iio_dev *indio_dev, mutex_unlock(&msa311->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); if (err) @@ -855,7 +851,6 @@ static int msa311_buffer_postdisable(struct iio_dev *indio_dev) struct msa311_priv *msa311 = iio_priv(indio_dev); struct device *dev = msa311->dev; - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; @@ -1229,7 +1224,6 @@ static int msa311_probe(struct i2c_client *i2c) if (err) return err; - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); err = devm_iio_device_register(dev, indio_dev); From d5b9423b39dced8ab126679925a6c88fb514a70c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:53:51 +0300 Subject: [PATCH 0512/2711] iio: adc: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Reviewed-by: Linus Walleij Acked-by: Chen-Yu Tsai Link: https://patch.msgid.link/20250825135401.1765847-3-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ab8500-gpadc.c | 1 - drivers/iio/adc/at91-sama5d2_adc.c | 13 +------------ drivers/iio/adc/imx8qxp-adc.c | 2 -- drivers/iio/adc/imx93_adc.c | 1 - drivers/iio/adc/rcar-gyroadc.c | 8 +++----- drivers/iio/adc/rzg2l_adc.c | 2 -- drivers/iio/adc/stm32-adc-core.c | 1 - drivers/iio/adc/stm32-adc.c | 7 ------- drivers/iio/adc/sun4i-gpadc-iio.c | 2 -- drivers/iio/adc/ti-ads1015.c | 6 ++---- drivers/iio/adc/ti-ads1100.c | 1 - drivers/iio/adc/ti-ads1119.c | 2 -- 12 files changed, 6 insertions(+), 40 deletions(-) diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c index f3b057f92310..8eaa1dd6a89b 100644 --- a/drivers/iio/adc/ab8500-gpadc.c +++ b/drivers/iio/adc/ab8500-gpadc.c @@ -607,7 +607,6 @@ static int ab8500_gpadc_read(struct ab8500_gpadc *gpadc, } /* This eventually drops the regulator */ - pm_runtime_mark_last_busy(gpadc->dev); pm_runtime_put_autosuspend(gpadc->dev); return (high_data << 8) | low_data; diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index c3450246730e..b4c36e6a7490 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -896,7 +896,6 @@ static int at91_adc_config_emr(struct at91_adc_state *st, emr |= osr | AT91_SAMA5D2_TRACKX(trackx); at91_adc_writel(st, EMR, emr); - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); st->oversampling_ratio = oversampling_ratio; @@ -971,7 +970,6 @@ static int at91_adc_configure_touch(struct at91_adc_state *st, bool state) AT91_SAMA5D2_IER_PEN | AT91_SAMA5D2_IER_NOPEN); at91_adc_writel(st, TSMR, 0); - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); return 0; } @@ -1142,10 +1140,8 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) at91_adc_configure_trigger_registers(st, state); - if (!state) { - pm_runtime_mark_last_busy(st->dev); + if (!state) pm_runtime_put_autosuspend(st->dev); - } return 0; } @@ -1336,7 +1332,6 @@ static int at91_adc_buffer_prepare(struct iio_dev *indio_dev) at91_adc_writel(st, IER, AT91_SAMA5D2_IER_DRDY); pm_runtime_put: - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); return ret; } @@ -1394,7 +1389,6 @@ static int at91_adc_buffer_postdisable(struct iio_dev *indio_dev) if (st->dma_st.dma_chan) dmaengine_terminate_sync(st->dma_st.dma_chan); - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); return 0; @@ -1603,7 +1597,6 @@ static void at91_adc_setup_samp_freq(struct iio_dev *indio_dev, unsigned freq, mr |= AT91_SAMA5D2_MR_TRACKTIM(tracktim); at91_adc_writel(st, MR, mr); - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u, tracktim=%u\n", @@ -1809,7 +1802,6 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev, at91_adc_readl(st, LCDR); pm_runtime_put: - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); return ret; } @@ -1890,7 +1882,6 @@ static int at91_adc_read_temp(struct iio_dev *indio_dev, restore_config: /* Revert previous settings. */ at91_adc_temp_sensor_configure(st, false); - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); if (ret < 0) return ret; @@ -2465,7 +2456,6 @@ static int at91_adc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "version: %x\n", readl_relaxed(st->base + st->soc_info.platform->layout->VERSION)); - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); return 0; @@ -2567,7 +2557,6 @@ static int at91_adc_resume(struct device *dev) at91_adc_configure_trigger_registers(st, true); } - pm_runtime_mark_last_busy(st->dev); pm_runtime_put_autosuspend(st->dev); return 0; diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c index 427ee9f24408..6fc50394ad90 100644 --- a/drivers/iio/adc/imx8qxp-adc.c +++ b/drivers/iio/adc/imx8qxp-adc.c @@ -229,7 +229,6 @@ static int imx8qxp_adc_read_raw(struct iio_dev *indio_dev, ret = wait_for_completion_interruptible_timeout(&adc->completion, IMX8QXP_ADC_TIMEOUT); - pm_runtime_mark_last_busy(dev); pm_runtime_put_sync_autosuspend(dev); if (ret == 0) { @@ -295,7 +294,6 @@ static int imx8qxp_adc_reg_access(struct iio_dev *indio_dev, unsigned int reg, *readval = readl(adc->regs + reg); - pm_runtime_mark_last_busy(dev); pm_runtime_put_sync_autosuspend(dev); return 0; diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index b865bbc94517..787e80db5de3 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -260,7 +260,6 @@ static int imx93_adc_read_raw(struct iio_dev *indio_dev, mutex_lock(&adc->lock); ret = imx93_adc_read_channel_conversion(adc, chan->channel, val); mutex_unlock(&adc->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_sync_autosuspend(dev); if (ret < 0) return ret; diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index cc326f21d398..3a17b3898bf6 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -163,12 +163,10 @@ static int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on) { struct device *dev = priv->dev; - if (on) { + if (on) return pm_runtime_resume_and_get(dev); - } else { - pm_runtime_mark_last_busy(dev); - return pm_runtime_put_autosuspend(dev); - } + + return pm_runtime_put_autosuspend(dev); } static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c index 9674d48074c9..75c0a96b0ace 100644 --- a/drivers/iio/adc/rzg2l_adc.c +++ b/drivers/iio/adc/rzg2l_adc.c @@ -249,7 +249,6 @@ static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc rzg2l_adc_start_stop(adc, false); rpm_put: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; } @@ -411,7 +410,6 @@ static int rzg2l_adc_hw_init(struct device *dev, struct rzg2l_adc *adc) rzg2l_adc_writel(adc, RZG2L_ADM(3), reg); exit_hw_init: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; } diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 3d800762c5fc..e39a4c0db25e 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -794,7 +794,6 @@ static int stm32_adc_probe(struct platform_device *pdev) goto err_irq_remove; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index b9f93116e114..2d7f88459c7c 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1528,7 +1528,6 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, stm32_adc_conv_irq_disable(adc); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -1564,7 +1563,6 @@ static int stm32_adc_write_raw(struct iio_dev *indio_dev, adc->cfg->set_ovs(indio_dev, idx); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); adc->ovs_idx = idx; @@ -1759,7 +1757,6 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev, adc->num_conv = bitmap_weight(scan_mask, iio_get_masklength(indio_dev)); ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -1808,7 +1805,6 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, else *readval = stm32_adc_readl(adc, reg); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; @@ -1954,7 +1950,6 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) err_clr_trig: stm32_adc_set_trig(indio_dev, NULL); err_pm_put: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -1977,7 +1972,6 @@ static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev) if (stm32_adc_set_trig(indio_dev, NULL)) dev_err(&indio_dev->dev, "Can't clear trigger\n"); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; @@ -2614,7 +2608,6 @@ static int stm32_adc_probe(struct platform_device *pdev) goto err_hw_stop; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); if (IS_ENABLED(CONFIG_DEBUG_FS)) diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index e4bc2e199a07..479115ea50bf 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -244,7 +244,6 @@ static int sun4i_gpadc_read(struct iio_dev *indio_dev, int channel, int *val, *val = info->temp_data; ret = 0; - pm_runtime_mark_last_busy(indio_dev->dev.parent); err: pm_runtime_put_autosuspend(indio_dev->dev.parent); @@ -271,7 +270,6 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val) regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val); - pm_runtime_mark_last_busy(indio_dev->dev.parent); pm_runtime_put_autosuspend(indio_dev->dev.parent); return 0; diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 48549d617e5f..f2a93c63ca14 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -374,12 +374,10 @@ static int ads1015_set_power_state(struct ads1015_data *data, bool on) int ret; struct device *dev = regmap_get_device(data->regmap); - if (on) { + if (on) ret = pm_runtime_resume_and_get(dev); - } else { - pm_runtime_mark_last_busy(dev); + else ret = pm_runtime_put_autosuspend(dev); - } return ret < 0 ? ret : 0; } diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c index b0790e300b18..aa8946063c7d 100644 --- a/drivers/iio/adc/ti-ads1100.c +++ b/drivers/iio/adc/ti-ads1100.c @@ -105,7 +105,6 @@ static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val) ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer)); - pm_runtime_mark_last_busy(&data->client->dev); pm_runtime_put_autosuspend(&data->client->dev); if (ret < 0) { diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c index 2d70b2662f41..c9cedc59cdcd 100644 --- a/drivers/iio/adc/ti-ads1119.c +++ b/drivers/iio/adc/ti-ads1119.c @@ -291,7 +291,6 @@ static int ads1119_single_conversion(struct ads1119_state *st, *val = sign_extend32(sample, chan->scan_type.realbits - 1); ret = IIO_VAL_INT; pdown: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; } @@ -470,7 +469,6 @@ static int ads1119_triggered_buffer_postdisable(struct iio_dev *indio_dev) if (ret) return ret; - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; From 4a0f3759313324205a0476e08b3bd4a0fe3b24f7 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:53:52 +0300 Subject: [PATCH 0513/2711] iio: chemical: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250825135401.1765847-4-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/atlas-sensor.c | 2 -- drivers/iio/chemical/bme680_core.c | 3 --- 2 files changed, 5 deletions(-) diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index 1daaa36f87a9..8bbba85af699 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -425,7 +425,6 @@ static int atlas_buffer_predisable(struct iio_dev *indio_dev) if (ret) return ret; - pm_runtime_mark_last_busy(&data->client->dev); ret = pm_runtime_put_autosuspend(&data->client->dev); if (ret) return ret; @@ -491,7 +490,6 @@ static int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val) ret = regmap_bulk_read(data->regmap, reg, val, sizeof(*val)); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c index 61d446fd456c..70f81c4a96ba 100644 --- a/drivers/iio/chemical/bme680_core.c +++ b/drivers/iio/chemical/bme680_core.c @@ -950,7 +950,6 @@ static int bme680_read_raw(struct iio_dev *indio_dev, return ret; ret = __bme680_read_raw(indio_dev, chan, val, val2, mask); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -1021,7 +1020,6 @@ static int bme680_write_raw(struct iio_dev *indio_dev, return ret; ret = __bme680_write_raw(indio_dev, chan, val, val2, mask); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -1140,7 +1138,6 @@ static int bme680_buffer_postdisable(struct iio_dev *indio_dev) struct bme680_data *data = iio_priv(indio_dev); struct device *dev = regmap_get_device(data->regmap); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; } From 3997872020ff11dc556b9873d458f33d7a649e31 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:53:53 +0300 Subject: [PATCH 0514/2711] iio: common: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250825135401.1765847-5-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 48193937275b..5540e2d28f4a 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -163,7 +163,6 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state) ret = pm_runtime_resume_and_get(&st->pdev->dev); } else { atomic_dec(&st->user_requested_state); - pm_runtime_mark_last_busy(&st->pdev->dev); pm_runtime_use_autosuspend(&st->pdev->dev); ret = pm_runtime_put_autosuspend(&st->pdev->dev); } From 4c0a7ad785f228743c41733fcb200eb799696e71 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:53:55 +0300 Subject: [PATCH 0515/2711] iio: gyro: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Reviewed-by: Linus Walleij Reviewed-by: Rui Miguel Silva Link: https://patch.msgid.link/20250825135401.1765847-7-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/bmg160_core.c | 4 +--- drivers/iio/gyro/fxas21002c_core.c | 2 -- drivers/iio/gyro/mpu3050-core.c | 3 --- drivers/iio/gyro/mpu3050-i2c.c | 1 - 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 781d3e96645f..38394b5f3275 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -309,10 +309,8 @@ static int bmg160_set_power_state(struct bmg160_data *data, bool on) if (on) ret = pm_runtime_get_sync(dev); - else { - pm_runtime_mark_last_busy(dev); + else ret = pm_runtime_put_autosuspend(dev); - } if (ret < 0) { dev_err(dev, "Failed: bmg160_set_power_state for %d\n", on); diff --git a/drivers/iio/gyro/fxas21002c_core.c b/drivers/iio/gyro/fxas21002c_core.c index 754c8a564ba4..a88670207cec 100644 --- a/drivers/iio/gyro/fxas21002c_core.c +++ b/drivers/iio/gyro/fxas21002c_core.c @@ -373,8 +373,6 @@ static int fxas21002c_pm_put(struct fxas21002c_data *data) { struct device *dev = regmap_get_device(data->regmap); - pm_runtime_mark_last_busy(dev); - return pm_runtime_put_autosuspend(dev); } diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index 16553948c5c3..67ae7d1012bc 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -370,7 +370,6 @@ static int mpu3050_read_raw(struct iio_dev *indio_dev, out_read_raw_unlock: mutex_unlock(&mpu3050->lock); - pm_runtime_mark_last_busy(mpu3050->dev); pm_runtime_put_autosuspend(mpu3050->dev); return ret; @@ -662,7 +661,6 @@ static int mpu3050_buffer_postdisable(struct iio_dev *indio_dev) { struct mpu3050 *mpu3050 = iio_priv(indio_dev); - pm_runtime_mark_last_busy(mpu3050->dev); pm_runtime_put_autosuspend(mpu3050->dev); return 0; @@ -976,7 +974,6 @@ static int mpu3050_drdy_trigger_set_state(struct iio_trigger *trig, if (ret) dev_err(mpu3050->dev, "error resetting FIFO\n"); - pm_runtime_mark_last_busy(mpu3050->dev); pm_runtime_put_autosuspend(mpu3050->dev); mpu3050->hw_irq_trigger = false; diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c index 8e284f47242c..092878f2c886 100644 --- a/drivers/iio/gyro/mpu3050-i2c.c +++ b/drivers/iio/gyro/mpu3050-i2c.c @@ -27,7 +27,6 @@ static int mpu3050_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id) { struct mpu3050 *mpu3050 = i2c_mux_priv(mux); - pm_runtime_mark_last_busy(mpu3050->dev); pm_runtime_put_autosuspend(mpu3050->dev); return 0; } From 00a3c4be1bba3c48ea602b62c8fcd58b565e524c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:53:56 +0300 Subject: [PATCH 0516/2711] iio: imu: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250825135401.1765847-8-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c | 5 ----- drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c | 1 - drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c | 5 ----- drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c | 1 - drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 6 ------ drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 1 - drivers/iio/imu/kmx61.c | 6 ++---- 7 files changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 7a28051330b7..48014b61ced3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -315,7 +315,6 @@ static int inv_icm42600_accel_read_sensor(struct iio_dev *indio_dev, ret = -EINVAL; exit: mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; } @@ -567,7 +566,6 @@ static int inv_icm42600_accel_write_scale(struct iio_dev *indio_dev, ret = inv_icm42600_set_accel_conf(st, &conf, NULL); mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -675,7 +673,6 @@ static int inv_icm42600_accel_write_odr(struct iio_dev *indio_dev, out_unlock: mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -727,7 +724,6 @@ static int inv_icm42600_accel_read_offset(struct inv_icm42600_state *st, memcpy(data, st->buffer, sizeof(data)); mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); if (ret) return ret; @@ -865,7 +861,6 @@ static int inv_icm42600_accel_write_offset(struct inv_icm42600_state *st, out_unlock: mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; } diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index ca744aaee542..36d69a0face6 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -430,7 +430,6 @@ out_unlock: if (sleep) msleep(sleep); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index 9ba6f13628e6..8a7cc9127631 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -184,7 +184,6 @@ static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st, ret = -EINVAL; exit: mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; } @@ -283,7 +282,6 @@ static int inv_icm42600_gyro_write_scale(struct iio_dev *indio_dev, ret = inv_icm42600_set_gyro_conf(st, &conf, NULL); mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -378,7 +376,6 @@ static int inv_icm42600_gyro_write_odr(struct iio_dev *indio_dev, out_unlock: mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -430,7 +427,6 @@ static int inv_icm42600_gyro_read_offset(struct inv_icm42600_state *st, memcpy(data, st->buffer, sizeof(data)); mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); if (ret) return ret; @@ -567,7 +563,6 @@ static int inv_icm42600_gyro_write_offset(struct inv_icm42600_state *st, out_unlock: mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; } diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c index 8b15afca498c..684007376178 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c @@ -37,7 +37,6 @@ static int inv_icm42600_temp_read(struct inv_icm42600_state *st, s16 *temp) exit: mutex_unlock(&st->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 39eb516acc73..b2fa1f4957a5 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -735,7 +735,6 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev, break; } - pm_runtime_mark_last_busy(pdev); pm_runtime_put_autosuspend(pdev); return ret; @@ -938,7 +937,6 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, break; } - pm_runtime_mark_last_busy(pdev); pm_runtime_put_autosuspend(pdev); error_write_raw_unlock: mutex_unlock(&st->lock); @@ -1146,14 +1144,12 @@ static int inv_mpu6050_enable_wom(struct inv_mpu6050_state *st, bool en) st->chip_config.wom_en = false; } - pm_runtime_mark_last_busy(pdev); pm_runtime_put_autosuspend(pdev); } return result; error_suspend: - pm_runtime_mark_last_busy(pdev); pm_runtime_put_autosuspend(pdev); return result; } @@ -1249,7 +1245,6 @@ static int inv_mpu6050_write_event_value(struct iio_dev *indio_dev, value = (u64)val * 1000000ULL + (u64)val2; result = inv_mpu6050_set_wom_threshold(st, value, INV_MPU6050_FREQ_DIVIDER(st)); - pm_runtime_mark_last_busy(pdev); pm_runtime_put_autosuspend(pdev); return result; @@ -1357,7 +1352,6 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, if (result) goto fifo_rate_fail_power_off; - pm_runtime_mark_last_busy(pdev); fifo_rate_fail_power_off: pm_runtime_put_autosuspend(pdev); fifo_rate_fail_unlock: diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index 5b1088cc3704..10a473342075 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -194,7 +194,6 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) result = inv_mpu6050_prepare_fifo(st, false); if (result) goto error_power_off; - pm_runtime_mark_last_busy(pdev); pm_runtime_put_autosuspend(pdev); } diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 55c82891e08c..3cd91d8a89ee 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -747,12 +747,10 @@ static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device) data->mag_ps = on; } - if (on) { + if (on) ret = pm_runtime_resume_and_get(&data->client->dev); - } else { - pm_runtime_mark_last_busy(&data->client->dev); + else ret = pm_runtime_put_autosuspend(&data->client->dev); - } if (ret < 0) { dev_err(&data->client->dev, "Failed: kmx61_set_power_state for %d, ret %d\n", From e15f23dd5305d123b571aeee56415d9e90f06ca4 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:53:57 +0300 Subject: [PATCH 0517/2711] iio: light: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20250825135401.1765847-9-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/apds9306.c | 2 -- drivers/iio/light/apds9960.c | 1 - drivers/iio/light/bh1780.c | 1 - drivers/iio/light/gp2ap002.c | 2 -- drivers/iio/light/isl29028.c | 11 +++-------- drivers/iio/light/ltrf216a.c | 1 - drivers/iio/light/pa12203001.c | 11 +++-------- drivers/iio/light/rpr0521.c | 6 ++---- drivers/iio/light/tsl2583.c | 12 +++--------- drivers/iio/light/tsl2591.c | 2 -- drivers/iio/light/us5182d.c | 12 +++--------- drivers/iio/light/vcnl4000.c | 11 +++-------- drivers/iio/light/vcnl4035.c | 11 +++-------- 13 files changed, 20 insertions(+), 63 deletions(-) diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index 5eb33e8e3ad9..389125675caa 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -537,7 +537,6 @@ static int apds9306_read_data(struct apds9306_data *data, int *val, int reg) *val = get_unaligned_le24(&buff); - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); return 0; @@ -1121,7 +1120,6 @@ static int apds9306_write_event_config(struct iio_dev *indio_dev, if (ret) return ret; - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); return 0; diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index b92d0fce5aec..79b202c59a0f 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -495,7 +495,6 @@ static int apds9960_set_power_state(struct apds9960_data *data, bool on) usleep_range(data->als_adc_int_us, APDS9960_MAX_INT_TIME_IN_US); } else { - pm_runtime_mark_last_busy(dev); ret = pm_runtime_put_autosuspend(dev); } diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index c7c877d2fe67..5d3c6d5276ba 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -111,7 +111,6 @@ static int bh1780_read_raw(struct iio_dev *indio_dev, value = bh1780_read_word(bh1780, BH1780_REG_DLOW); if (value < 0) return value; - pm_runtime_mark_last_busy(&bh1780->client->dev); pm_runtime_put_autosuspend(&bh1780->client->dev); *val = value; diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index 42859e5b1089..a0d8a58f2704 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -271,7 +271,6 @@ static int gp2ap002_read_raw(struct iio_dev *indio_dev, } out: - pm_runtime_mark_last_busy(gp2ap002->dev); pm_runtime_put_autosuspend(gp2ap002->dev); return ret; @@ -353,7 +352,6 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev, pm_runtime_get_sync(gp2ap002->dev); gp2ap002->enabled = true; } else { - pm_runtime_mark_last_busy(gp2ap002->dev); pm_runtime_put_autosuspend(gp2ap002->dev); gp2ap002->enabled = false; } diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c index 0e4284823d44..374bccad9119 100644 --- a/drivers/iio/light/isl29028.c +++ b/drivers/iio/light/isl29028.c @@ -336,16 +336,11 @@ static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data) static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on) { struct device *dev = regmap_get_device(chip->regmap); - int ret; - if (on) { - ret = pm_runtime_resume_and_get(dev); - } else { - pm_runtime_mark_last_busy(dev); - ret = pm_runtime_put_autosuspend(dev); - } + if (on) + return pm_runtime_resume_and_get(dev); - return ret; + return pm_runtime_put_autosuspend(dev); } /* Channel IO */ diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c index 61f57a82b872..5f27f754fe1c 100644 --- a/drivers/iio/light/ltrf216a.c +++ b/drivers/iio/light/ltrf216a.c @@ -208,7 +208,6 @@ static int ltrf216a_set_power_state(struct ltrf216a_data *data, bool on) return ret; } } else { - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); } diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c index 8885852bef22..98a1f1624c75 100644 --- a/drivers/iio/light/pa12203001.c +++ b/drivers/iio/light/pa12203001.c @@ -185,15 +185,10 @@ static int pa12203001_set_power_state(struct pa12203001_data *data, bool on, mutex_unlock(&data->lock); } - if (on) { - ret = pm_runtime_resume_and_get(&data->client->dev); + if (on) + return pm_runtime_resume_and_get(&data->client->dev); - } else { - pm_runtime_mark_last_busy(&data->client->dev); - ret = pm_runtime_put_autosuspend(&data->client->dev); - } - - return ret; + return pm_runtime_put_autosuspend(&data->client->dev); err: mutex_unlock(&data->lock); diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index fbd116272921..9341c1d58cbe 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -358,12 +358,10 @@ static int rpr0521_set_power_state(struct rpr0521_data *data, bool on, * Note: If either measurement is re-enabled before _suspend(), * both stay enabled until _suspend(). */ - if (on) { + if (on) ret = pm_runtime_resume_and_get(&data->client->dev); - } else { - pm_runtime_mark_last_busy(&data->client->dev); + else ret = pm_runtime_put_autosuspend(&data->client->dev); - } if (ret < 0) { dev_err(&data->client->dev, "Failed: rpr0521_set_power_state for %d, ret %d\n", diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c index fc3b0c4226be..8801a491de77 100644 --- a/drivers/iio/light/tsl2583.c +++ b/drivers/iio/light/tsl2583.c @@ -641,16 +641,10 @@ static const struct iio_chan_spec tsl2583_channels[] = { static int tsl2583_set_pm_runtime_busy(struct tsl2583_chip *chip, bool on) { - int ret; + if (on) + return pm_runtime_resume_and_get(&chip->client->dev); - if (on) { - ret = pm_runtime_resume_and_get(&chip->client->dev); - } else { - pm_runtime_mark_last_busy(&chip->client->dev); - ret = pm_runtime_put_autosuspend(&chip->client->dev); - } - - return ret; + return pm_runtime_put_autosuspend(&chip->client->dev); } static int tsl2583_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c index 08476f193a44..c5557867ea43 100644 --- a/drivers/iio/light/tsl2591.c +++ b/drivers/iio/light/tsl2591.c @@ -772,7 +772,6 @@ static int tsl2591_read_raw(struct iio_dev *indio_dev, err_unlock: mutex_unlock(&chip->als_mutex); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; @@ -995,7 +994,6 @@ static int tsl2591_write_event_config(struct iio_dev *indio_dev, pm_runtime_get_sync(&client->dev); } else if (!state && chip->events_enabled) { chip->events_enabled = false; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); } diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index 61a0957317a1..d2f5a44892a8 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -361,19 +361,13 @@ static int us5182d_shutdown_en(struct us5182d_data *data, u8 state) static int us5182d_set_power_state(struct us5182d_data *data, bool on) { - int ret; - if (data->power_mode == US5182D_ONESHOT) return 0; - if (on) { - ret = pm_runtime_resume_and_get(&data->client->dev); - } else { - pm_runtime_mark_last_busy(&data->client->dev); - ret = pm_runtime_put_autosuspend(&data->client->dev); - } + if (on) + return pm_runtime_resume_and_get(&data->client->dev); - return ret; + return pm_runtime_put_autosuspend(&data->client->dev); } static int us5182d_read_value(struct us5182d_data *data, diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index cc81a30b7c70..4dbb2294a843 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -576,16 +576,11 @@ static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data) static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on) { struct device *dev = &data->client->dev; - int ret; - if (on) { - ret = pm_runtime_resume_and_get(dev); - } else { - pm_runtime_mark_last_busy(dev); - ret = pm_runtime_put_autosuspend(dev); - } + if (on) + return pm_runtime_resume_and_get(dev); - return ret; + return pm_runtime_put_autosuspend(dev); } static int vcnl4040_read_als_it(struct vcnl4000_data *data, int *val, int *val2) diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 01bc99564f98..963747927425 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -141,17 +141,12 @@ static const struct iio_trigger_ops vcnl4035_trigger_ops = { static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on) { - int ret; struct device *dev = &data->client->dev; - if (on) { - ret = pm_runtime_resume_and_get(dev); - } else { - pm_runtime_mark_last_busy(dev); - ret = pm_runtime_put_autosuspend(dev); - } + if (on) + return pm_runtime_resume_and_get(dev); - return ret; + return pm_runtime_put_autosuspend(dev); } static int vcnl4035_read_info_raw(struct iio_dev *indio_dev, From e3c3e49567ef023733fba150ad72a553127aea64 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:53:58 +0300 Subject: [PATCH 0518/2711] iio: magnetometer: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Also drop checking for errors on pm_runtime_put_autosuspend() in bmc150_magn_set_power_state(). Signed-off-by: Sakari Ailus Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20250825135401.1765847-10-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8974.c | 2 -- drivers/iio/magnetometer/ak8975.c | 1 - drivers/iio/magnetometer/als31300.c | 2 -- drivers/iio/magnetometer/bmc150_magn.c | 13 ++++--------- drivers/iio/magnetometer/tmag5273.c | 2 -- drivers/iio/magnetometer/yamaha-yas530.c | 2 -- 6 files changed, 4 insertions(+), 18 deletions(-) diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 947fe8a475f2..68ece700c7ce 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -583,7 +583,6 @@ static int ak8974_measure_channel(struct ak8974 *ak8974, unsigned long address, *val = (s16)le16_to_cpu(hw_values[address]); out_unlock: mutex_unlock(&ak8974->lock); - pm_runtime_mark_last_busy(&ak8974->i2c->dev); pm_runtime_put_autosuspend(&ak8974->i2c->dev); return ret; @@ -678,7 +677,6 @@ static void ak8974_fill_buffer(struct iio_dev *indio_dev) out_unlock: mutex_unlock(&ak8974->lock); - pm_runtime_mark_last_busy(&ak8974->i2c->dev); pm_runtime_put_autosuspend(&ak8974->i2c->dev); } diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index a1e92b2abffd..3fd0171e5d69 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -775,7 +775,6 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) mutex_unlock(&data->lock); - pm_runtime_mark_last_busy(&data->client->dev); pm_runtime_put_autosuspend(&data->client->dev); /* Swap bytes and convert to valid range. */ diff --git a/drivers/iio/magnetometer/als31300.c b/drivers/iio/magnetometer/als31300.c index 928e1378304c..c083bef53573 100644 --- a/drivers/iio/magnetometer/als31300.c +++ b/drivers/iio/magnetometer/als31300.c @@ -140,7 +140,6 @@ static int als31300_get_measure(struct als31300_data *data, *z = ALS31300_DATA_Z_GET(buf); out: - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); return ret; @@ -401,7 +400,6 @@ static int als31300_probe(struct i2c_client *i2c) pm_runtime_set_autosuspend_delay(dev, 200); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); ret = devm_iio_device_register(dev, indio_dev); diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 761daead5ada..6a73f6e2f1f0 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -257,22 +257,17 @@ static int bmc150_magn_set_power_mode(struct bmc150_magn_data *data, static int bmc150_magn_set_power_state(struct bmc150_magn_data *data, bool on) { -#ifdef CONFIG_PM - int ret; + int ret = 0; - if (on) { + if (on) ret = pm_runtime_resume_and_get(data->dev); - } else { - pm_runtime_mark_last_busy(data->dev); - ret = pm_runtime_put_autosuspend(data->dev); - } - + else + pm_runtime_put_autosuspend(data->dev); if (ret < 0) { dev_err(data->dev, "failed to change power state to %d\n", on); return ret; } -#endif return 0; } diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c index bdb656b031b1..bd3c50157843 100644 --- a/drivers/iio/magnetometer/tmag5273.c +++ b/drivers/iio/magnetometer/tmag5273.c @@ -295,7 +295,6 @@ static int tmag5273_read_raw(struct iio_dev *indio_dev, ret = tmag5273_get_measure(data, &t, &x, &y, &z, &angle, &magnitude); - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); if (ret) @@ -668,7 +667,6 @@ static int tmag5273_probe(struct i2c_client *i2c) indio_dev->channels = tmag5273_channels; indio_dev->num_channels = ARRAY_SIZE(tmag5273_channels); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); ret = devm_iio_device_register(dev, indio_dev); diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 340607111d9a..d49e37edcbed 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -623,7 +623,6 @@ static int yas5xx_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: pm_runtime_get_sync(yas5xx->dev); ret = ci->get_measure(yas5xx, &t, &x, &y, &z); - pm_runtime_mark_last_busy(yas5xx->dev); pm_runtime_put_autosuspend(yas5xx->dev); if (ret) return ret; @@ -664,7 +663,6 @@ static void yas5xx_fill_buffer(struct iio_dev *indio_dev) pm_runtime_get_sync(yas5xx->dev); ret = ci->get_measure(yas5xx, &t, &x, &y, &z); - pm_runtime_mark_last_busy(yas5xx->dev); pm_runtime_put_autosuspend(yas5xx->dev); if (ret) { dev_err(yas5xx->dev, "error refilling buffer\n"); From dfb68a8ebb2e8d9af6e356ae0806bfd8e854ab44 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:53:59 +0300 Subject: [PATCH 0519/2711] iio: pressure: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250825135401.1765847-11-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 5 ----- drivers/iio/pressure/icp10100.c | 1 - drivers/iio/pressure/mpl115.c | 2 -- drivers/iio/pressure/zpa2326.c | 2 -- 4 files changed, 10 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 74505c9ec1a0..b66f3b905055 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -752,7 +752,6 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, pm_runtime_get_sync(data->dev); ret = bmp280_read_raw_impl(indio_dev, chan, val, val2, mask); - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); return ret; @@ -927,7 +926,6 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, pm_runtime_get_sync(data->dev); ret = bmp280_write_raw_impl(indio_dev, chan, val, val2, mask); - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); return ret; @@ -2255,7 +2253,6 @@ static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val, pm_runtime_get_sync(data->dev); ret = bmp580_nvmem_read_impl(priv, offset, val, bytes); - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); return ret; @@ -2330,7 +2327,6 @@ static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val, pm_runtime_get_sync(data->dev); ret = bmp580_nvmem_write_impl(priv, offset, val, bytes); - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); return ret; @@ -3120,7 +3116,6 @@ static int bmp280_buffer_postdisable(struct iio_dev *indio_dev) { struct bmp280_data *data = iio_priv(indio_dev); - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); return 0; diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c index 1951c1cc84cf..3d83d0098a57 100644 --- a/drivers/iio/pressure/icp10100.c +++ b/drivers/iio/pressure/icp10100.c @@ -265,7 +265,6 @@ static int icp10100_get_measures(struct icp10100_state *st, (be16_to_cpu(measures[1]) >> 8); *temperature = be16_to_cpu(measures[2]); - pm_runtime_mark_last_busy(&st->client->dev); error_measure: pm_runtime_put_autosuspend(&st->client->dev); return ret; diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c index 71beb28b7f2c..830a5065c008 100644 --- a/drivers/iio/pressure/mpl115.c +++ b/drivers/iio/pressure/mpl115.c @@ -108,7 +108,6 @@ static int mpl115_read_raw(struct iio_dev *indio_dev, ret = mpl115_comp_pressure(data, val, val2); if (ret < 0) return ret; - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); return IIO_VAL_INT_PLUS_MICRO; @@ -118,7 +117,6 @@ static int mpl115_read_raw(struct iio_dev *indio_dev, ret = mpl115_read_temp(data); if (ret < 0) return ret; - pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); *val = ret >> 6; diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 6eef37c0952d..4923a558a26a 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -697,7 +697,6 @@ static void zpa2326_suspend(struct iio_dev *indio_dev) zpa2326_sleep(indio_dev); - pm_runtime_mark_last_busy(parent); pm_runtime_put_autosuspend(parent); } @@ -708,7 +707,6 @@ static void zpa2326_init_runtime(struct device *parent) pm_runtime_enable(parent); pm_runtime_set_autosuspend_delay(parent, 1000); pm_runtime_use_autosuspend(parent); - pm_runtime_mark_last_busy(parent); pm_runtime_put_autosuspend(parent); } From 4cba0d0d588c1503498c1bbd75ebdfe04caafbc1 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:54:00 +0300 Subject: [PATCH 0520/2711] iio: proximity: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Link: https://patch.msgid.link/20250825135401.1765847-12-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 1 - drivers/iio/proximity/srf04.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 01c013acfda2..21336b8f122a 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -185,7 +185,6 @@ static int lidar_get_measurement(struct lidar_data *data, u16 *reg) } ret = -EIO; } - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c index f9d32f9aba1f..e97f9a20ac7a 100644 --- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -117,10 +117,8 @@ static int srf04_read(struct srf04_data *data) udelay(data->cfg->trigger_pulse_us); gpiod_set_value(data->gpiod_trig, 0); - if (data->gpiod_power) { - pm_runtime_mark_last_busy(data->dev); + if (data->gpiod_power) pm_runtime_put_autosuspend(data->dev); - } /* it should not take more than 20 ms until echo is rising */ ret = wait_for_completion_killable_timeout(&data->rising, HZ/50); From 6c2a7d221f4cd8110646b448d5ebb89db6676472 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Aug 2025 16:54:01 +0300 Subject: [PATCH 0521/2711] iio: temperature: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-reduntant explicit call to pm_runtime_mark_last_busy(). Signed-off-by: Sakari Ailus Acked-by: Crt Mori Link: https://patch.msgid.link/20250825135401.1765847-13-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mlx90614.c | 1 - drivers/iio/temperature/mlx90632.c | 1 - drivers/iio/temperature/mlx90635.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 740018d4b3df..8a44a00bfd5e 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -225,7 +225,6 @@ static void mlx90614_power_put(struct mlx90614_data *data) if (!data->wakeup_gpio) return; - pm_runtime_mark_last_busy(&data->client->dev); pm_runtime_put_autosuspend(&data->client->dev); } #else diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index c4bf5dc2f266..b44f7036c2cc 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -1043,7 +1043,6 @@ static int mlx90632_read_raw(struct iio_dev *indio_dev, } mlx90632_read_raw_pm: - pm_runtime_mark_last_busy(&data->client->dev); pm_runtime_put_autosuspend(&data->client->dev); return ret; } diff --git a/drivers/iio/temperature/mlx90635.c b/drivers/iio/temperature/mlx90635.c index 0ba08504e990..1c8948ca54df 100644 --- a/drivers/iio/temperature/mlx90635.c +++ b/drivers/iio/temperature/mlx90635.c @@ -749,7 +749,6 @@ static int mlx90635_read_raw(struct iio_dev *indio_dev, } mlx90635_read_raw_pm: - pm_runtime_mark_last_busy(&data->client->dev); pm_runtime_put_autosuspend(&data->client->dev); return ret; } From 13bdfb53aa04eeb8022af87288c5bc0a5d13a834 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Mon, 16 Jun 2025 10:56:30 +0200 Subject: [PATCH 0522/2711] x86/sgx: Use ENCLS mnemonic in Current minimum required version of binutils is 2.30, which supports ENCLS instruction mnemonic. Replace the byte-wise specification of ENCLS with this proper mnemonic. No functional change intended. Signed-off-by: Uros Bizjak Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Jarkko Sakkinen Link: https://lore.kernel.org/20250616085716.158942-1-ubizjak@gmail.com --- arch/x86/kernel/cpu/sgx/encls.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/sgx/encls.h b/arch/x86/kernel/cpu/sgx/encls.h index 99004b02e2ed..42a088a337c5 100644 --- a/arch/x86/kernel/cpu/sgx/encls.h +++ b/arch/x86/kernel/cpu/sgx/encls.h @@ -68,7 +68,7 @@ static inline bool encls_failed(int ret) ({ \ int ret; \ asm volatile( \ - "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ + "1: encls\n" \ "2:\n" \ _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_SGX) \ : "=a"(ret) \ @@ -111,8 +111,8 @@ static inline bool encls_failed(int ret) ({ \ int ret; \ asm volatile( \ - "1: .byte 0x0f, 0x01, 0xcf;\n\t" \ - " xor %%eax,%%eax;\n" \ + "1: encls\n\t" \ + "xor %%eax,%%eax\n" \ "2:\n" \ _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_FAULT_SGX) \ : "=a"(ret), "=b"(rbx_out) \ From 1e736f1489563470b58ede3fae5274a624280cf1 Mon Sep 17 00:00:00 2001 From: Alex Mastro Date: Mon, 4 Aug 2025 12:44:31 -0700 Subject: [PATCH 0523/2711] vfio/pci: print vfio-device syspath to fdinfo Print the PCI device syspath to a vfio device's fdinfo. This enables tools to query which device is associated with a given vfio device fd. This results in output like below: $ cat /proc/"$SOME_PID"/fdinfo/"$VFIO_FD" | grep vfio vfio-device-syspath: /sys/devices/pci0000:e0/0000:e0:01.1/0000:e1:00.0/0000:e2:05.0/0000:e8:00.0 Signed-off-by: Alex Mastro Reviewed-by: Amit Machhiwal Tested-by: Amit Machhiwal Link: https://lore.kernel.org/r/20250804-show-fdinfo-v4-1-96b14c5691b3@fb.com Signed-off-by: Alex Williamson --- Documentation/filesystems/proc.rst | 14 ++++++++++++++ drivers/vfio/vfio_main.c | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index 2971551b7235..ed8d23b677ca 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -2166,6 +2166,20 @@ DMA Buffer files where 'size' is the size of the DMA buffer in bytes. 'count' is the file count of the DMA buffer file. 'exp_name' is the name of the DMA buffer exporter. +VFIO Device files +~~~~~~~~~~~~~~~~ + +:: + + pos: 0 + flags: 02000002 + mnt_id: 17 + ino: 5122 + vfio-device-syspath: /sys/devices/pci0000:e0/0000:e0:01.1/0000:e1:00.0/0000:e2:05.0/0000:e8:00.0 + +where 'vfio-device-syspath' is the sysfs path corresponding to the VFIO device +file. + 3.9 /proc//map_files - Information about memory mapped files --------------------------------------------------------------------- This directory contains symbolic links which represent memory mapped files diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 5046cae05222..91a8eae308ea 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1355,6 +1356,22 @@ static int vfio_device_fops_mmap(struct file *filep, struct vm_area_struct *vma) return device->ops->mmap(device, vma); } +#ifdef CONFIG_PROC_FS +static void vfio_device_show_fdinfo(struct seq_file *m, struct file *filep) +{ + char *path; + struct vfio_device_file *df = filep->private_data; + struct vfio_device *device = df->device; + + path = kobject_get_path(&device->dev->kobj, GFP_KERNEL); + if (!path) + return; + + seq_printf(m, "vfio-device-syspath: /sys%s\n", path); + kfree(path); +} +#endif + const struct file_operations vfio_device_fops = { .owner = THIS_MODULE, .open = vfio_device_fops_cdev_open, @@ -1364,6 +1381,9 @@ const struct file_operations vfio_device_fops = { .unlocked_ioctl = vfio_device_fops_unl_ioctl, .compat_ioctl = compat_ptr_ioctl, .mmap = vfio_device_fops_mmap, +#ifdef CONFIG_PROC_FS + .show_fdinfo = vfio_device_show_fdinfo, +#endif }; static struct vfio_device *vfio_device_from_file(struct file *file) From 127d874a7df05b30e937951864b18fb11babff95 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 08:55:30 -0500 Subject: [PATCH 0524/2711] remoteproc: da8xx: Use devm_rproc_alloc() helper Use the device lifecycle managed allocation function. This helps prevent mistakes like freeing out of order in cleanup functions and forgetting to free on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814135532.638040-1-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/da8xx_remoteproc.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 93031f0867d1..47df21bea525 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -276,8 +276,8 @@ static int da8xx_rproc_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "device does not have specific CMA pool\n"); } - rproc = rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, - sizeof(*drproc)); + rproc = devm_rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, + sizeof(*drproc)); if (!rproc) { ret = -ENOMEM; goto free_mem; @@ -294,7 +294,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = da8xx_rproc_get_internal_memories(pdev, drproc); if (ret) - goto free_rproc; + goto free_mem; platform_set_drvdata(pdev, rproc); @@ -304,7 +304,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) rproc); if (ret) { dev_err(dev, "devm_request_threaded_irq error: %d\n", ret); - goto free_rproc; + goto free_mem; } /* @@ -314,7 +314,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) */ ret = reset_control_assert(dsp_reset); if (ret) - goto free_rproc; + goto free_mem; drproc->chipsig = chipsig; drproc->bootreg = bootreg; @@ -325,13 +325,11 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = rproc_add(rproc); if (ret) { dev_err(dev, "rproc_add failed: %d\n", ret); - goto free_rproc; + goto free_mem; } return 0; -free_rproc: - rproc_free(rproc); free_mem: if (dev->of_node) of_reserved_mem_device_release(dev); @@ -352,7 +350,6 @@ static void da8xx_rproc_remove(struct platform_device *pdev) disable_irq(drproc->irq); rproc_del(rproc); - rproc_free(rproc); if (dev->of_node) of_reserved_mem_device_release(dev); } From a214365140cc3009f07d4e14a8b481fd3dc41d31 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 10 Jul 2025 15:15:28 +0300 Subject: [PATCH 0525/2711] rculist: move list_for_each_rcu() to where it belongs The list_for_each_rcu() relies on the rcu_dereference() API which is not provided by the list.h. At the same time list.h is a low-level basic header that must not have dependencies like RCU, besides the fact of the potential circular dependencies in some cases. With all that said, move RCU related API to the rculist.h where it belongs. Signed-off-by: Andy Shevchenko Reviewed-by: Simona Vetter Reviewed-by: "Paul E. McKenney" Signed-off-by: Neeraj Upadhyay (AMD) Signed-off-by: "Paul E. McKenney" --- include/linux/list.h | 10 ---------- include/linux/rculist.h | 10 ++++++++++ kernel/cgroup/dmem.c | 1 + 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/linux/list.h b/include/linux/list.h index e7e28afd28f8..e7bdad9b8618 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -686,16 +686,6 @@ static inline void list_splice_tail_init(struct list_head *list, #define list_for_each(pos, head) \ for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next) -/** - * list_for_each_rcu - Iterate over a list in an RCU-safe fashion - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_rcu(pos, head) \ - for (pos = rcu_dereference((head)->next); \ - !list_is_head(pos, (head)); \ - pos = rcu_dereference(pos->next)) - /** * list_for_each_continue - continue iteration over a list * @pos: the &struct list_head to use as a loop cursor. diff --git a/include/linux/rculist.h b/include/linux/rculist.h index 1b11926ddd47..2abba7552605 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -42,6 +42,16 @@ static inline void INIT_LIST_HEAD_RCU(struct list_head *list) */ #define list_bidir_prev_rcu(list) (*((struct list_head __rcu **)(&(list)->prev))) +/** + * list_for_each_rcu - Iterate over a list in an RCU-safe fashion + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_rcu(pos, head) \ + for (pos = rcu_dereference((head)->next); \ + !list_is_head(pos, (head)); \ + pos = rcu_dereference(pos->next)) + /** * list_tail_rcu - returns the prev pointer of the head of the list * @head: the head of the list diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c index 10b63433f057..e12b946278b6 100644 --- a/kernel/cgroup/dmem.c +++ b/kernel/cgroup/dmem.c @@ -14,6 +14,7 @@ #include #include #include +#include #include struct dmem_cgroup_region { From b4a7b0d2c4485d11d37dec721709660f3967efcf Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:41 -0400 Subject: [PATCH 0526/2711] clk: spacemit: ccu_ddn: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Reviewed-by: Haylen Chu Reviewed-by: Yixun Lan Link: https://lore.kernel.org/r/20250811-clk-for-stephen-round-rate-v1-49-b3bf97b038dc@redhat.com Signed-off-by: Yixun Lan --- drivers/clk/spacemit/ccu_ddn.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/clk/spacemit/ccu_ddn.c b/drivers/clk/spacemit/ccu_ddn.c index be311b045698..02b68ea84db9 100644 --- a/drivers/clk/spacemit/ccu_ddn.c +++ b/drivers/clk/spacemit/ccu_ddn.c @@ -39,13 +39,16 @@ static unsigned long ccu_ddn_calc_best_rate(struct ccu_ddn *ddn, return ccu_ddn_calc_rate(prate, *num, *den); } -static long ccu_ddn_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int ccu_ddn_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct ccu_ddn *ddn = hw_to_ccu_ddn(hw); unsigned long num, den; - return ccu_ddn_calc_best_rate(ddn, rate, *prate, &num, &den); + req->rate = ccu_ddn_calc_best_rate(ddn, req->rate, + req->best_parent_rate, &num, &den); + + return 0; } static unsigned long ccu_ddn_recalc_rate(struct clk_hw *hw, unsigned long prate) @@ -78,6 +81,6 @@ static int ccu_ddn_set_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops spacemit_ccu_ddn_ops = { .recalc_rate = ccu_ddn_recalc_rate, - .round_rate = ccu_ddn_round_rate, + .determine_rate = ccu_ddn_determine_rate, .set_rate = ccu_ddn_set_rate, }; From 56737edda7db58549550776092da12fe03600399 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:42 -0400 Subject: [PATCH 0527/2711] clk: spacemit: ccu_mix: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Reviewed-by: Haylen Chu Reviewed-by: Yixun Lan Link: https://lore.kernel.org/r/20250811-clk-for-stephen-round-rate-v1-50-b3bf97b038dc@redhat.com Signed-off-by: Yixun Lan --- drivers/clk/spacemit/ccu_mix.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/spacemit/ccu_mix.c b/drivers/clk/spacemit/ccu_mix.c index 9b852aa61f78..7b7990875372 100644 --- a/drivers/clk/spacemit/ccu_mix.c +++ b/drivers/clk/spacemit/ccu_mix.c @@ -80,10 +80,12 @@ static int ccu_mix_trigger_fc(struct clk_hw *hw) MIX_FC_TIMEOUT_US); } -static long ccu_factor_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int ccu_factor_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - return ccu_factor_recalc_rate(hw, *prate); + req->rate = ccu_factor_recalc_rate(hw, req->best_parent_rate); + + return 0; } static int ccu_factor_set_rate(struct clk_hw *hw, unsigned long rate, @@ -198,7 +200,7 @@ const struct clk_ops spacemit_ccu_gate_ops = { }; const struct clk_ops spacemit_ccu_factor_ops = { - .round_rate = ccu_factor_round_rate, + .determine_rate = ccu_factor_determine_rate, .recalc_rate = ccu_factor_recalc_rate, .set_rate = ccu_factor_set_rate, }; @@ -220,7 +222,7 @@ const struct clk_ops spacemit_ccu_factor_gate_ops = { .enable = ccu_gate_enable, .is_enabled = ccu_gate_is_enabled, - .round_rate = ccu_factor_round_rate, + .determine_rate = ccu_factor_determine_rate, .recalc_rate = ccu_factor_recalc_rate, .set_rate = ccu_factor_set_rate, }; From d02c71cba7bba453d233a49497412ddbf2d44871 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:43 -0400 Subject: [PATCH 0528/2711] clk: spacemit: ccu_pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney Reviewed-by: Haylen Chu Reviewed-by: Yixun Lan Link: https://lore.kernel.org/r/20250811-clk-for-stephen-round-rate-v1-51-b3bf97b038dc@redhat.com Signed-off-by: Yixun Lan --- drivers/clk/spacemit/ccu_pll.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/clk/spacemit/ccu_pll.c b/drivers/clk/spacemit/ccu_pll.c index 45f540073a65..d92f0dae65a4 100644 --- a/drivers/clk/spacemit/ccu_pll.c +++ b/drivers/clk/spacemit/ccu_pll.c @@ -125,12 +125,14 @@ static unsigned long ccu_pll_recalc_rate(struct clk_hw *hw, return entry ? entry->rate : 0; } -static long ccu_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int ccu_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct ccu_pll *pll = hw_to_ccu_pll(hw); - return ccu_pll_lookup_best_rate(pll, rate)->rate; + req->rate = ccu_pll_lookup_best_rate(pll, req->rate)->rate; + + return 0; } static int ccu_pll_init(struct clk_hw *hw) @@ -152,6 +154,6 @@ const struct clk_ops spacemit_ccu_pll_ops = { .disable = ccu_pll_disable, .set_rate = ccu_pll_set_rate, .recalc_rate = ccu_pll_recalc_rate, - .round_rate = ccu_pll_round_rate, + .determine_rate = ccu_pll_determine_rate, .is_enabled = ccu_pll_is_enabled, }; From b06578497e6f32fa181235f5a64746c7d40259e6 Mon Sep 17 00:00:00 2001 From: Chelsy Ratnawat Date: Sun, 24 Aug 2025 08:13:16 -0700 Subject: [PATCH 0529/2711] thunderbolt: Use string choices helpers Use string_choices.h helpers instead of hard-coded strings. Signed-off-by: Chelsy Ratnawat Signed-off-by: Mika Westerberg --- drivers/thunderbolt/debugfs.c | 3 ++- drivers/thunderbolt/nhi.c | 3 ++- drivers/thunderbolt/usb4.c | 13 +++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c index f8328ca7e22e..46a2a3550be7 100644 --- a/drivers/thunderbolt/debugfs.c +++ b/drivers/thunderbolt/debugfs.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "tb.h" @@ -691,7 +692,7 @@ static int margining_caps_show(struct seq_file *s, void *not_used) seq_printf(s, "0x%08x\n", margining->caps[i]); seq_printf(s, "# software margining: %s\n", - supports_software(margining) ? "yes" : "no"); + str_yes_no(supports_software(margining))); if (supports_hardware(margining)) { seq_puts(s, "# hardware margining: yes\n"); seq_puts(s, "# minimum BER level contour: "); diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index f3a2264e012b..8a38b05d25c5 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "nhi.h" @@ -146,7 +147,7 @@ static void ring_interrupt_active(struct tb_ring *ring, bool active) dev_WARN(&ring->nhi->pdev->dev, "interrupt for %s %d is already %s\n", RING_TYPE(ring), ring->hop, - active ? "enabled" : "disabled"); + str_enabled_disabled(active)); if (active) iowrite32(new, ring->nhi->iobase + reg); diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index fdae76c8f728..e160afadd501 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -9,6 +9,7 @@ #include #include +#include #include #include "sb_regs.h" @@ -172,8 +173,8 @@ void usb4_switch_check_wakes(struct tb_switch *sw) return; tb_sw_dbg(sw, "PCIe wake: %s, USB3 wake: %s\n", - (val & ROUTER_CS_6_WOPS) ? "yes" : "no", - (val & ROUTER_CS_6_WOUS) ? "yes" : "no"); + str_yes_no(val & ROUTER_CS_6_WOPS), + str_yes_no(val & ROUTER_CS_6_WOUS)); wakeup = val & (ROUTER_CS_6_WOPS | ROUTER_CS_6_WOUS); } @@ -191,9 +192,9 @@ void usb4_switch_check_wakes(struct tb_switch *sw) break; tb_port_dbg(port, "USB4 wake: %s, connection wake: %s, disconnection wake: %s\n", - (val & PORT_CS_18_WOU4S) ? "yes" : "no", - (val & PORT_CS_18_WOCS) ? "yes" : "no", - (val & PORT_CS_18_WODS) ? "yes" : "no"); + str_yes_no(val & PORT_CS_18_WOU4S), + str_yes_no(val & PORT_CS_18_WOCS), + str_yes_no(val & PORT_CS_18_WODS)); wakeup_usb4 = val & (PORT_CS_18_WOU4S | PORT_CS_18_WOCS | PORT_CS_18_WODS); @@ -260,7 +261,7 @@ int usb4_switch_setup(struct tb_switch *sw) tbt3 = !(val & ROUTER_CS_6_TNS); tb_sw_dbg(sw, "TBT3 support: %s, xHCI: %s\n", - tbt3 ? "yes" : "no", xhci ? "yes" : "no"); + str_yes_no(tbt3), str_yes_no(xhci)); ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) From b3a333f8ac1645b5f6a9d5f0a33c8523c1cedb94 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 26 Aug 2025 09:17:12 +0100 Subject: [PATCH 0530/2711] USB: serial: oti6858: remove extranenous ; after comment There is a redundant semicolon after a comment, remove it. Signed-off-by: Colin Ian King Signed-off-by: Johan Hovold --- drivers/usb/serial/oti6858.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 24068368892c..bd206cb9cc08 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -106,7 +106,7 @@ struct oti6858_control_pkt { #define PIN_DTR 0x04 /* output pin */ #define PIN_RI 0x02 /* input pin, active low */ #define PIN_DCD 0x01 /* input pin, active low */ - u8 rx_bytes_avail; /* number of bytes in rx buffer */; + u8 rx_bytes_avail; /* number of bytes in rx buffer */ }; #define OTI6858_CTRL_PKT_SIZE sizeof(struct oti6858_control_pkt) From 78b6a991eb6c6f19ed7d0ac91cda3b3b117fda8f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 1 May 2025 16:33:21 +0200 Subject: [PATCH 0531/2711] extcon: adc-jack: Fix wakeup source leaks on device unbind Device can be unbound, so driver must also release memory for the wakeup source. Do not use devm interface, because it would change the order of cleanup. Link: https://lore.kernel.org/lkml/20250501-device-wakeup-leak-extcon-v2-1-7af77802cbea@linaro.org/ Acked-by: MyungJoo Ham Signed-off-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-adc-jack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 46c40d85c2ac..557930394abd 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -164,6 +164,7 @@ static void adc_jack_remove(struct platform_device *pdev) { struct adc_jack_data *data = platform_get_drvdata(pdev); + device_init_wakeup(&pdev->dev, false); free_irq(data->irq, data); cancel_work_sync(&data->handler.work); } From 93ccf3f2f22ceaa975b462156f98527febee4fe5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 1 May 2025 16:33:22 +0200 Subject: [PATCH 0532/2711] extcon: axp288: Fix wakeup source leaks on device unbind Device can be unbound, so driver must also release memory for the wakeup source. Link: https://lore.kernel.org/lkml/20250501-device-wakeup-leak-extcon-v2-2-7af77802cbea@linaro.org/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-axp288.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index d3bcbe839c09..19856dddade6 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -470,7 +470,7 @@ static int axp288_extcon_probe(struct platform_device *pdev) if (ret < 0) return ret; - device_init_wakeup(dev, true); + devm_device_init_wakeup(dev); platform_set_drvdata(pdev, info); return 0; From 6f982d55f8c5d1e9189906a2a352dba8de421f5f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 1 May 2025 16:33:23 +0200 Subject: [PATCH 0533/2711] extcon: fsa9480: Fix wakeup source leaks on device unbind Device can be unbound, so driver must also release memory for the wakeup source. Link: https://lore.kernel.org/lkml/20250501-device-wakeup-leak-extcon-v2-3-7af77802cbea@linaro.org/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-fsa9480.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-fsa9480.c b/drivers/extcon/extcon-fsa9480.c index b11b43171063..a031eb0914a0 100644 --- a/drivers/extcon/extcon-fsa9480.c +++ b/drivers/extcon/extcon-fsa9480.c @@ -317,7 +317,7 @@ static int fsa9480_probe(struct i2c_client *client) return ret; } - device_init_wakeup(info->dev, true); + devm_device_init_wakeup(info->dev); fsa9480_detect_dev(info); return 0; From 369259d5104d613164a8da64848aafe9dc9fa976 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 1 May 2025 16:33:24 +0200 Subject: [PATCH 0534/2711] extcon: qcom-spmi-misc: Fix wakeup source leaks on device unbind Device can be unbound, so driver must also release memory for the wakeup source. Link: https://lore.kernel.org/lkml/20250501-device-wakeup-leak-extcon-v2-4-7af77802cbea@linaro.org/ Reviewed-by: Dmitry Baryshkov Signed-off-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-qcom-spmi-misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c index 53de581a393a..afaba5685c3d 100644 --- a/drivers/extcon/extcon-qcom-spmi-misc.c +++ b/drivers/extcon/extcon-qcom-spmi-misc.c @@ -155,7 +155,7 @@ static int qcom_usb_extcon_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, info); - device_init_wakeup(dev, 1); + devm_device_init_wakeup(dev); /* Perform initial detection */ qcom_usb_extcon_detect_cable(&info->wq_detcable.work); From 16689f33e5addec4a61cd4c102900a154349dc2a Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 08:55:31 -0500 Subject: [PATCH 0535/2711] remoteproc: da8xx: Use devm action to release reserved memory This helps prevent mistakes like freeing out of order in cleanup functions and forgetting to free on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814135532.638040-2-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/da8xx_remoteproc.c | 30 +++++++++++++-------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 47df21bea525..58b4f05283d9 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -233,6 +233,13 @@ static int da8xx_rproc_get_internal_memories(struct platform_device *pdev, return 0; } +static void da8xx_rproc_mem_release(void *data) +{ + struct device *dev = data; + + of_reserved_mem_device_release(dev); +} + static int da8xx_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -274,14 +281,13 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = of_reserved_mem_device_init(dev); if (ret) return dev_err_probe(dev, ret, "device does not have specific CMA pool\n"); + devm_add_action_or_reset(&pdev->dev, da8xx_rproc_mem_release, &pdev->dev); } rproc = devm_rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, sizeof(*drproc)); - if (!rproc) { - ret = -ENOMEM; - goto free_mem; - } + if (!rproc) + return -ENOMEM; /* error recovery is not supported at present */ rproc->recovery_disabled = true; @@ -294,7 +300,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = da8xx_rproc_get_internal_memories(pdev, drproc); if (ret) - goto free_mem; + return ret; platform_set_drvdata(pdev, rproc); @@ -304,7 +310,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) rproc); if (ret) { dev_err(dev, "devm_request_threaded_irq error: %d\n", ret); - goto free_mem; + return ret; } /* @@ -314,7 +320,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) */ ret = reset_control_assert(dsp_reset); if (ret) - goto free_mem; + return ret; drproc->chipsig = chipsig; drproc->bootreg = bootreg; @@ -325,22 +331,16 @@ static int da8xx_rproc_probe(struct platform_device *pdev) ret = rproc_add(rproc); if (ret) { dev_err(dev, "rproc_add failed: %d\n", ret); - goto free_mem; + return ret; } return 0; - -free_mem: - if (dev->of_node) - of_reserved_mem_device_release(dev); - return ret; } static void da8xx_rproc_remove(struct platform_device *pdev) { struct rproc *rproc = platform_get_drvdata(pdev); struct da8xx_rproc *drproc = rproc->priv; - struct device *dev = &pdev->dev; /* * The devm subsystem might end up releasing things before @@ -350,8 +350,6 @@ static void da8xx_rproc_remove(struct platform_device *pdev) disable_irq(drproc->irq); rproc_del(rproc); - if (dev->of_node) - of_reserved_mem_device_release(dev); } static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = { From 7183e39ac915ec047586a755746cae5b79f5f93c Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 08:55:32 -0500 Subject: [PATCH 0536/2711] remoteproc: da8xx: Use devm_rproc_add() helper Use the device lifecycle managed add function. This helps prevent mistakes like deleting out of order in cleanup functions and forgetting to delete on error paths. As this now makes the IRQ free ordered correctly, we can drop that from the remove() callback, which is now empty and can also be removed. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814135532.638040-3-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/da8xx_remoteproc.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 58b4f05283d9..e418a2bf5d2e 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -302,8 +302,6 @@ static int da8xx_rproc_probe(struct platform_device *pdev) if (ret) return ret; - platform_set_drvdata(pdev, rproc); - /* everything the ISR needs is now setup, so hook it up */ ret = devm_request_threaded_irq(dev, irq, da8xx_rproc_callback, handle_event, 0, "da8xx-remoteproc", @@ -328,7 +326,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) drproc->irq_data = irq_data; drproc->irq = irq; - ret = rproc_add(rproc); + ret = devm_rproc_add(dev, rproc); if (ret) { dev_err(dev, "rproc_add failed: %d\n", ret); return ret; @@ -337,21 +335,6 @@ static int da8xx_rproc_probe(struct platform_device *pdev) return 0; } -static void da8xx_rproc_remove(struct platform_device *pdev) -{ - struct rproc *rproc = platform_get_drvdata(pdev); - struct da8xx_rproc *drproc = rproc->priv; - - /* - * The devm subsystem might end up releasing things before - * freeing the irq, thus allowing an interrupt to sneak in while - * the device is being removed. This should prevent that. - */ - disable_irq(drproc->irq); - - rproc_del(rproc); -} - static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = { { .compatible = "ti,da850-dsp", }, { /* sentinel */ }, @@ -360,7 +343,6 @@ MODULE_DEVICE_TABLE(of, davinci_rproc_of_match); static struct platform_driver da8xx_rproc_driver = { .probe = da8xx_rproc_probe, - .remove = da8xx_rproc_remove, .driver = { .name = "davinci-rproc", .of_match_table = of_match_ptr(davinci_rproc_of_match), From 01e4ed11c5d4120a47ffc3b15dd9050e922cde53 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 09:08:31 -0500 Subject: [PATCH 0537/2711] remoteproc: keystone: Use devm action to release reserved memory This helps prevent mistakes like freeing out of order in cleanup functions and forgetting to free on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814140835.651652-1-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/keystone_remoteproc.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 7b41b4547fa8..6fc27e0d7b3d 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -349,6 +349,13 @@ static int keystone_rproc_of_get_dev_syscon(struct platform_device *pdev, return 0; } +static void keystone_rproc_mem_release(void *data) +{ + struct device *dev = data; + + of_reserved_mem_device_release(dev); +} + static int keystone_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -425,8 +432,14 @@ static int keystone_rproc_probe(struct platform_device *pdev) goto disable_clk; } - if (of_reserved_mem_device_init(dev)) + ret = of_reserved_mem_device_init(dev); + if (ret) { dev_warn(dev, "device does not have specific CMA pool\n"); + } else { + ret = devm_add_action_or_reset(dev, keystone_rproc_mem_release, dev); + if (ret) + goto disable_clk; + } /* ensure the DSP is in reset before loading firmware */ ret = reset_control_status(ksproc->reset); @@ -450,7 +463,6 @@ static int keystone_rproc_probe(struct platform_device *pdev) return 0; release_mem: - of_reserved_mem_device_release(dev); gpiod_put(ksproc->kick_gpio); disable_clk: pm_runtime_put_sync(dev); @@ -467,7 +479,6 @@ static void keystone_rproc_remove(struct platform_device *pdev) gpiod_put(ksproc->kick_gpio); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - of_reserved_mem_device_release(&pdev->dev); } static const struct of_device_id keystone_rproc_of_match[] = { From db0427a8a595d0e4880043f9dff8e99c061e5d55 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 09:08:32 -0500 Subject: [PATCH 0538/2711] remoteproc: keystone: Use devm_pm_runtime_enable() helper Use device life-cycle managed runtime enable function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814140835.651652-2-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/keystone_remoteproc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 6fc27e0d7b3d..558678d793b0 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -401,12 +401,13 @@ static int keystone_rproc_probe(struct platform_device *pdev) return PTR_ERR(ksproc->reset); /* enable clock for accessing DSP internal memories */ - pm_runtime_enable(dev); + ret = devm_pm_runtime_enable(dev); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); + ret = pm_runtime_resume_and_get(dev); - if (ret < 0) { - dev_err(dev, "failed to enable clock, status = %d\n", ret); - goto disable_rpm; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to enable clock\n"); ret = keystone_rproc_of_get_memories(pdev, ksproc); if (ret) @@ -466,8 +467,6 @@ release_mem: gpiod_put(ksproc->kick_gpio); disable_clk: pm_runtime_put_sync(dev); -disable_rpm: - pm_runtime_disable(dev); return ret; } @@ -478,7 +477,6 @@ static void keystone_rproc_remove(struct platform_device *pdev) rproc_del(ksproc->rproc); gpiod_put(ksproc->kick_gpio); pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); } static const struct of_device_id keystone_rproc_of_match[] = { From a2ab9cd283ce7daf1b634260a73618733af9d99f Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 09:08:33 -0500 Subject: [PATCH 0539/2711] remoteproc: keystone: Use devm action to call PM runtime put sync This helps prevent mistakes like putting out of order in cleanup functions and forgetting to put sync on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814140835.651652-3-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/keystone_remoteproc.c | 37 ++++++++++++------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 558678d793b0..558b53575890 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -356,6 +356,13 @@ static void keystone_rproc_mem_release(void *data) of_reserved_mem_device_release(dev); } +static void keystone_rproc_pm_runtime_put(void *data) +{ + struct device *dev = data; + + pm_runtime_put_sync(dev); +} + static int keystone_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -409,29 +416,26 @@ static int keystone_rproc_probe(struct platform_device *pdev) if (ret < 0) return dev_err_probe(dev, ret, "failed to enable clock\n"); + ret = devm_add_action_or_reset(dev, keystone_rproc_pm_runtime_put, dev); + if (ret) + return dev_err_probe(dev, ret, "failed to add disable pm devm action\n"); + ret = keystone_rproc_of_get_memories(pdev, ksproc); if (ret) - goto disable_clk; + return ret; ksproc->irq_ring = platform_get_irq_byname(pdev, "vring"); - if (ksproc->irq_ring < 0) { - ret = ksproc->irq_ring; - goto disable_clk; - } + if (ksproc->irq_ring < 0) + return ksproc->irq_ring; ksproc->irq_fault = platform_get_irq_byname(pdev, "exception"); - if (ksproc->irq_fault < 0) { - ret = ksproc->irq_fault; - goto disable_clk; - } + if (ksproc->irq_fault < 0) + return ksproc->irq_fault; ksproc->kick_gpio = gpiod_get(dev, "kick", GPIOD_ASIS); ret = PTR_ERR_OR_ZERO(ksproc->kick_gpio); - if (ret) { - dev_err(dev, "failed to get gpio for virtio kicks, status = %d\n", - ret); - goto disable_clk; - } + if (ret) + return dev_err_probe(dev, ret, "failed to get gpio for virtio kicks\n"); ret = of_reserved_mem_device_init(dev); if (ret) { @@ -439,7 +443,7 @@ static int keystone_rproc_probe(struct platform_device *pdev) } else { ret = devm_add_action_or_reset(dev, keystone_rproc_mem_release, dev); if (ret) - goto disable_clk; + return ret; } /* ensure the DSP is in reset before loading firmware */ @@ -465,8 +469,6 @@ static int keystone_rproc_probe(struct platform_device *pdev) release_mem: gpiod_put(ksproc->kick_gpio); -disable_clk: - pm_runtime_put_sync(dev); return ret; } @@ -476,7 +478,6 @@ static void keystone_rproc_remove(struct platform_device *pdev) rproc_del(ksproc->rproc); gpiod_put(ksproc->kick_gpio); - pm_runtime_put_sync(&pdev->dev); } static const struct of_device_id keystone_rproc_of_match[] = { From 49493852bd80109db5bdc02c2eb86751ec0d4906 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 09:08:34 -0500 Subject: [PATCH 0540/2711] remoteproc: keystone: Use devm_gpiod_get() helper Use device life-cycle managed GPIO get function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814140835.651652-4-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/keystone_remoteproc.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 558b53575890..7826853a00fc 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -432,7 +432,7 @@ static int keystone_rproc_probe(struct platform_device *pdev) if (ksproc->irq_fault < 0) return ksproc->irq_fault; - ksproc->kick_gpio = gpiod_get(dev, "kick", GPIOD_ASIS); + ksproc->kick_gpio = devm_gpiod_get(dev, "kick", GPIOD_ASIS); ret = PTR_ERR_OR_ZERO(ksproc->kick_gpio); if (ret) return dev_err_probe(dev, ret, "failed to get gpio for virtio kicks\n"); @@ -449,27 +449,19 @@ static int keystone_rproc_probe(struct platform_device *pdev) /* ensure the DSP is in reset before loading firmware */ ret = reset_control_status(ksproc->reset); if (ret < 0) { - dev_err(dev, "failed to get reset status, status = %d\n", ret); - goto release_mem; + return dev_err_probe(dev, ret, "failed to get reset status\n"); } else if (ret == 0) { WARN(1, "device is not in reset\n"); keystone_rproc_dsp_reset(ksproc); } ret = rproc_add(rproc); - if (ret) { - dev_err(dev, "failed to add register device with remoteproc core, status = %d\n", - ret); - goto release_mem; - } + if (ret) + return dev_err_probe(dev, ret, "failed to register device with remoteproc core\n"); platform_set_drvdata(pdev, ksproc); return 0; - -release_mem: - gpiod_put(ksproc->kick_gpio); - return ret; } static void keystone_rproc_remove(struct platform_device *pdev) @@ -477,7 +469,6 @@ static void keystone_rproc_remove(struct platform_device *pdev) struct keystone_rproc *ksproc = platform_get_drvdata(pdev); rproc_del(ksproc->rproc); - gpiod_put(ksproc->kick_gpio); } static const struct of_device_id keystone_rproc_of_match[] = { From ac4393af3cb66c371fafc894a14e795f70a7c5e0 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 09:08:35 -0500 Subject: [PATCH 0541/2711] remoteproc: keystone: Use devm_rproc_add() helper Use the device lifecycle managed add function. This helps prevent mistakes like deleting out of order in cleanup functions and forgetting to delete on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814140835.651652-5-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/keystone_remoteproc.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 7826853a00fc..4d6550b48567 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -455,22 +455,13 @@ static int keystone_rproc_probe(struct platform_device *pdev) keystone_rproc_dsp_reset(ksproc); } - ret = rproc_add(rproc); + ret = devm_rproc_add(dev, rproc); if (ret) return dev_err_probe(dev, ret, "failed to register device with remoteproc core\n"); - platform_set_drvdata(pdev, ksproc); - return 0; } -static void keystone_rproc_remove(struct platform_device *pdev) -{ - struct keystone_rproc *ksproc = platform_get_drvdata(pdev); - - rproc_del(ksproc->rproc); -} - static const struct of_device_id keystone_rproc_of_match[] = { { .compatible = "ti,k2hk-dsp", }, { .compatible = "ti,k2l-dsp", }, @@ -482,7 +473,6 @@ MODULE_DEVICE_TABLE(of, keystone_rproc_of_match); static struct platform_driver keystone_rproc_driver = { .probe = keystone_rproc_probe, - .remove = keystone_rproc_remove, .driver = { .name = "keystone-rproc", .of_match_table = keystone_rproc_of_match, From 461edcf73eec57bc0006fbb5209f5012c514c58b Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 10:39:37 -0500 Subject: [PATCH 0542/2711] remoteproc: wkup_m3: Use devm_pm_runtime_enable() helper Use device life-cycle managed runtime enable function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814153940.670564-1-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/wkup_m3_rproc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index d8be21e71721..35c2145b12db 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -148,7 +148,9 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) return -ENODEV; } - pm_runtime_enable(&pdev->dev); + ret = devm_pm_runtime_enable(dev); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); @@ -219,7 +221,6 @@ err_put_rproc: rproc_free(rproc); err: pm_runtime_put_noidle(dev); - pm_runtime_disable(dev); return ret; } @@ -230,7 +231,6 @@ static void wkup_m3_rproc_remove(struct platform_device *pdev) rproc_del(rproc); rproc_free(rproc); pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); } #ifdef CONFIG_PM From 642f8c01e31dd2918e9e655f29846326bf7fad4c Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 10:39:38 -0500 Subject: [PATCH 0543/2711] remoteproc: wkup_m3: Use devm action to call PM runtime put sync This helps prevent mistakes like putting out of order in cleanup functions and forgetting to put sync on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814153940.670564-2-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/wkup_m3_rproc.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 35c2145b12db..2569f041d9ca 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -125,6 +125,13 @@ static const struct of_device_id wkup_m3_rproc_of_match[] = { }; MODULE_DEVICE_TABLE(of, wkup_m3_rproc_of_match); +static void wkup_m3_rproc_pm_runtime_put(void *data) +{ + struct device *dev = data; + + pm_runtime_put_sync(dev); +} + static int wkup_m3_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -152,17 +159,16 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) if (ret < 0) return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); - goto err; - } + if (ret < 0) + return dev_err_probe(dev, ret, "pm_runtime_get_sync() failed\n"); + ret = devm_add_action_or_reset(dev, wkup_m3_rproc_pm_runtime_put, dev); + if (ret) + return dev_err_probe(dev, ret, "failed to add disable pm devm action\n"); rproc = rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops, fw_name, sizeof(*wkupm3)); - if (!rproc) { - ret = -ENOMEM; - goto err; - } + if (!rproc) + return -ENOMEM; rproc->auto_boot = false; rproc->sysfs_read_only = true; @@ -219,8 +225,6 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) err_put_rproc: rproc_free(rproc); -err: - pm_runtime_put_noidle(dev); return ret; } @@ -230,7 +234,6 @@ static void wkup_m3_rproc_remove(struct platform_device *pdev) rproc_del(rproc); rproc_free(rproc); - pm_runtime_put_sync(&pdev->dev); } #ifdef CONFIG_PM From 9b84eec6f3b78795ab57f9c2c808948e12d18bad Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 10:39:39 -0500 Subject: [PATCH 0544/2711] remoteproc: wkup_m3: Use devm_rproc_alloc() helper Use the device lifecycle managed allocation function. This helps prevent mistakes like freeing out of order in cleanup functions and forgetting to free on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814153940.670564-3-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/wkup_m3_rproc.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 2569f041d9ca..30e9ecd75657 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -165,8 +165,8 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "failed to add disable pm devm action\n"); - rproc = rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops, - fw_name, sizeof(*wkupm3)); + rproc = devm_rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops, + fw_name, sizeof(*wkupm3)); if (!rproc) return -ENOMEM; @@ -183,9 +183,7 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) if (!wkupm3->rsts) { if (!(pdata && pdata->deassert_reset && pdata->assert_reset && pdata->reset_name)) { - dev_err(dev, "Platform data missing!\n"); - ret = -ENODEV; - goto err_put_rproc; + return dev_err_probe(dev, -ENODEV, "Platform data missing!\n"); } } @@ -193,12 +191,9 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, mem_names[i]); wkupm3->mem[i].cpu_addr = devm_ioremap_resource(dev, res); - if (IS_ERR(wkupm3->mem[i].cpu_addr)) { - dev_err(&pdev->dev, "devm_ioremap_resource failed for resource %d\n", - i); - ret = PTR_ERR(wkupm3->mem[i].cpu_addr); - goto err_put_rproc; - } + if (IS_ERR(wkupm3->mem[i].cpu_addr)) + return dev_err_probe(dev, PTR_ERR(wkupm3->mem[i].cpu_addr), + "devm_ioremap_resource failed for resource %d\n", i); wkupm3->mem[i].bus_addr = res->start; wkupm3->mem[i].size = resource_size(res); addrp = of_get_address(dev->of_node, i, &size, NULL); @@ -216,16 +211,10 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) dev_set_drvdata(dev, rproc); ret = rproc_add(rproc); - if (ret) { - dev_err(dev, "rproc_add failed\n"); - goto err_put_rproc; - } + if (ret) + return dev_err_probe(dev, ret, "rproc_add failed\n"); return 0; - -err_put_rproc: - rproc_free(rproc); - return ret; } static void wkup_m3_rproc_remove(struct platform_device *pdev) @@ -233,7 +222,6 @@ static void wkup_m3_rproc_remove(struct platform_device *pdev) struct rproc *rproc = platform_get_drvdata(pdev); rproc_del(rproc); - rproc_free(rproc); } #ifdef CONFIG_PM From 3df0bee9c5b94ca9e3e2ff0f4c4e9886eac86055 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 14 Aug 2025 10:39:40 -0500 Subject: [PATCH 0545/2711] remoteproc: wkup_m3: Use devm_rproc_add() helper Use the device lifecycle managed add function. This helps prevent mistakes like deleting out of order in cleanup functions and forgetting to delete on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20250814153940.670564-4-afd@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/wkup_m3_rproc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 30e9ecd75657..2d5bfbefcacc 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -210,20 +210,13 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) dev_set_drvdata(dev, rproc); - ret = rproc_add(rproc); + ret = devm_rproc_add(dev, rproc); if (ret) return dev_err_probe(dev, ret, "rproc_add failed\n"); return 0; } -static void wkup_m3_rproc_remove(struct platform_device *pdev) -{ - struct rproc *rproc = platform_get_drvdata(pdev); - - rproc_del(rproc); -} - #ifdef CONFIG_PM static int wkup_m3_rpm_suspend(struct device *dev) { @@ -242,7 +235,6 @@ static const struct dev_pm_ops wkup_m3_rproc_pm_ops = { static struct platform_driver wkup_m3_rproc_driver = { .probe = wkup_m3_rproc_probe, - .remove = wkup_m3_rproc_remove, .driver = { .name = "wkup_m3_rproc", .of_match_table = wkup_m3_rproc_of_match, From d3fee10e40a938331e2aae34348691136db31304 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Sat, 9 Aug 2025 17:44:47 +0300 Subject: [PATCH 0546/2711] PCI: rcar-host: Pass proper IRQ domain to generic_handle_domain_irq() Starting with commit dd26c1a23fd5 ("PCI: rcar-host: Switch to msi_create_parent_irq_domain()"), the MSI parent IRQ domain is NULL because the object of type struct irq_domain_info passed to: msi_create_parent_irq_domain() -> irq_domain_instantiate()() -> __irq_domain_instantiate() has no reference to the parent IRQ domain. Using msi->domain->parent as an argument for generic_handle_domain_irq() leads to below error: "Unable to handle kernel NULL pointer dereference at virtual address" This error was identified while switching the upcoming RZ/G3S PCIe host controller driver to msi_create_parent_irq_domain() (which was using a similar pattern to handle MSIs (see link section)), but it was not tested on hardware using the pcie-rcar-host controller driver due to lack of hardware. Fixes: dd26c1a23fd5 ("PCI: rcar-host: Switch to msi_create_parent_irq_domain()") Signed-off-by: Claudiu Beznea [mani: reworded subject and description] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Nam Cao Link: https://lore.kernel.org/all/20250704161410.3931884-6-claudiu.beznea.uj@bp.renesas.com Link: https://patch.msgid.link/20250809144447.3939284-1-claudiu.beznea.uj@bp.renesas.com --- drivers/pci/controller/pcie-rcar-host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c index fe288fd770c4..4780e0109e58 100644 --- a/drivers/pci/controller/pcie-rcar-host.c +++ b/drivers/pci/controller/pcie-rcar-host.c @@ -584,7 +584,7 @@ static irqreturn_t rcar_pcie_msi_irq(int irq, void *data) unsigned int index = find_first_bit(®, 32); int ret; - ret = generic_handle_domain_irq(msi->domain->parent, index); + ret = generic_handle_domain_irq(msi->domain, index); if (ret) { /* Unknown MSI, just clear it */ dev_dbg(dev, "unexpected MSI\n"); From 19a9a1ab5c3dce65fff4ac50700117039c23d525 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:32 -0700 Subject: [PATCH 0547/2711] KVM: Rename CONFIG_KVM_PRIVATE_MEM to CONFIG_KVM_GUEST_MEMFD Rename the Kconfig option CONFIG_KVM_PRIVATE_MEM to CONFIG_KVM_GUEST_MEMFD. The original name implied that the feature only supported "private" memory. However, CONFIG_KVM_PRIVATE_MEM enables guest_memfd in general, which is not exclusively for private memory. Subsequent patches in this series will add guest_memfd support for non-CoCo VMs, whose memory is not private. Renaming the Kconfig option to CONFIG_KVM_GUEST_MEMFD more accurately reflects its broader scope as the main Kconfig option for all guest_memfd-backed memory. This provides clearer semantics for the option and avoids confusion as new features are introduced. Reviewed-by: Ira Weiny Reviewed-by: Gavin Shan Reviewed-by: Shivank Garg Reviewed-by: Vlastimil Babka Reviewed-by: Xiaoyao Li Co-developed-by: David Hildenbrand Signed-off-by: David Hildenbrand Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 2 +- include/linux/kvm_host.h | 14 +++++++------- virt/kvm/Kconfig | 8 ++++---- virt/kvm/Makefile.kvm | 2 +- virt/kvm/kvm_main.c | 4 ++-- virt/kvm/kvm_mm.h | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f19a76d3ca0e..7b0f2b3e492d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2276,7 +2276,7 @@ void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level, int tdp_max_root_level, int tdp_huge_page_level); -#ifdef CONFIG_KVM_PRIVATE_MEM +#ifdef CONFIG_KVM_GUEST_MEMFD #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.has_private_mem) #else #define kvm_arch_has_private_mem(kvm) false diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 15656b7fba6c..8cdc0b3cc1b1 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -602,7 +602,7 @@ struct kvm_memory_slot { short id; u16 as_id; -#ifdef CONFIG_KVM_PRIVATE_MEM +#ifdef CONFIG_KVM_GUEST_MEMFD struct { /* * Writes protected by kvm->slots_lock. Acquiring a @@ -720,10 +720,10 @@ static inline int kvm_arch_vcpu_memslots_id(struct kvm_vcpu *vcpu) #endif /* - * Arch code must define kvm_arch_has_private_mem if support for private memory - * is enabled. + * Arch code must define kvm_arch_has_private_mem if support for guest_memfd is + * enabled. */ -#if !defined(kvm_arch_has_private_mem) && !IS_ENABLED(CONFIG_KVM_PRIVATE_MEM) +#if !defined(kvm_arch_has_private_mem) && !IS_ENABLED(CONFIG_KVM_GUEST_MEMFD) static inline bool kvm_arch_has_private_mem(struct kvm *kvm) { return false; @@ -2505,7 +2505,7 @@ bool kvm_arch_post_set_memory_attributes(struct kvm *kvm, static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn) { - return IS_ENABLED(CONFIG_KVM_PRIVATE_MEM) && + return IS_ENABLED(CONFIG_KVM_GUEST_MEMFD) && kvm_get_memory_attributes(kvm, gfn) & KVM_MEMORY_ATTRIBUTE_PRIVATE; } #else @@ -2515,7 +2515,7 @@ static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn) } #endif /* CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES */ -#ifdef CONFIG_KVM_PRIVATE_MEM +#ifdef CONFIG_KVM_GUEST_MEMFD int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot, gfn_t gfn, kvm_pfn_t *pfn, struct page **page, int *max_order); @@ -2528,7 +2528,7 @@ static inline int kvm_gmem_get_pfn(struct kvm *kvm, KVM_BUG_ON(1, kvm); return -EIO; } -#endif /* CONFIG_KVM_PRIVATE_MEM */ +#endif /* CONFIG_KVM_GUEST_MEMFD */ #ifdef CONFIG_HAVE_KVM_ARCH_GMEM_PREPARE int kvm_arch_gmem_prepare(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, int max_order); diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 727b542074e7..e4b400feff94 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -112,19 +112,19 @@ config KVM_GENERIC_MEMORY_ATTRIBUTES depends on KVM_GENERIC_MMU_NOTIFIER bool -config KVM_PRIVATE_MEM +config KVM_GUEST_MEMFD select XARRAY_MULTI bool config KVM_GENERIC_PRIVATE_MEM select KVM_GENERIC_MEMORY_ATTRIBUTES - select KVM_PRIVATE_MEM + select KVM_GUEST_MEMFD bool config HAVE_KVM_ARCH_GMEM_PREPARE bool - depends on KVM_PRIVATE_MEM + depends on KVM_GUEST_MEMFD config HAVE_KVM_ARCH_GMEM_INVALIDATE bool - depends on KVM_PRIVATE_MEM + depends on KVM_GUEST_MEMFD diff --git a/virt/kvm/Makefile.kvm b/virt/kvm/Makefile.kvm index 724c89af78af..d047d4cf58c9 100644 --- a/virt/kvm/Makefile.kvm +++ b/virt/kvm/Makefile.kvm @@ -12,4 +12,4 @@ kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o kvm-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(KVM)/irqchip.o kvm-$(CONFIG_HAVE_KVM_DIRTY_RING) += $(KVM)/dirty_ring.o kvm-$(CONFIG_HAVE_KVM_PFNCACHE) += $(KVM)/pfncache.o -kvm-$(CONFIG_KVM_PRIVATE_MEM) += $(KVM)/guest_memfd.o +kvm-$(CONFIG_KVM_GUEST_MEMFD) += $(KVM)/guest_memfd.o diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 6c07dd423458..25a94eed75fd 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -4915,7 +4915,7 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg) case KVM_CAP_MEMORY_ATTRIBUTES: return kvm_supported_mem_attributes(kvm); #endif -#ifdef CONFIG_KVM_PRIVATE_MEM +#ifdef CONFIG_KVM_GUEST_MEMFD case KVM_CAP_GUEST_MEMFD: return !kvm || kvm_arch_has_private_mem(kvm); #endif @@ -5352,7 +5352,7 @@ static long kvm_vm_ioctl(struct file *filp, case KVM_GET_STATS_FD: r = kvm_vm_ioctl_get_stats_fd(kvm); break; -#ifdef CONFIG_KVM_PRIVATE_MEM +#ifdef CONFIG_KVM_GUEST_MEMFD case KVM_CREATE_GUEST_MEMFD: { struct kvm_create_guest_memfd guest_memfd; diff --git a/virt/kvm/kvm_mm.h b/virt/kvm/kvm_mm.h index acef3f5c582a..31defb08ccba 100644 --- a/virt/kvm/kvm_mm.h +++ b/virt/kvm/kvm_mm.h @@ -67,7 +67,7 @@ static inline void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm, } #endif /* HAVE_KVM_PFNCACHE */ -#ifdef CONFIG_KVM_PRIVATE_MEM +#ifdef CONFIG_KVM_GUEST_MEMFD void kvm_gmem_init(struct module *module); int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args); int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot, @@ -91,6 +91,6 @@ static inline void kvm_gmem_unbind(struct kvm_memory_slot *slot) { WARN_ON_ONCE(1); } -#endif /* CONFIG_KVM_PRIVATE_MEM */ +#endif /* CONFIG_KVM_GUEST_MEMFD */ #endif /* __KVM_MM_H__ */ From 1d95f2d307ec384fd8851c5f189c904dd2ea831a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 29 Jul 2025 15:54:33 -0700 Subject: [PATCH 0548/2711] KVM: x86: Have all vendor neutral sub-configs depend on KVM_X86, not just KVM Make all vendor neutral KVM x86 configs depend on KVM_X86, not just KVM, i.e. gate them on at least one vendor module being enabled and thus on kvm.ko actually being built. Depending on just KVM allows the user to select the configs even though they won't actually take effect, and more importantly, makes it all too easy to create unmet dependencies. E.g. KVM_GENERIC_PRIVATE_MEM can't be selected by KVM_SW_PROTECTED_VM, because the KVM_GENERIC_MMU_NOTIFIER dependency is select by KVM_X86. Hiding all sub-configs when neither KVM_AMD nor KVM_INTEL is selected also helps communicate to the user that nothing "interesting" is going on, e.g. --- Virtualization Kernel-based Virtual Machine (KVM) support < > KVM for Intel (and compatible) processors support < > KVM for AMD processors support Fixes: ea4290d77bda ("KVM: x86: leave kvm.ko out of the build if no vendor module is requested") Reviewed-by: David Hildenbrand Reviewed-by: Xiaoyao Li Signed-off-by: Sean Christopherson Reviewed-by: Fuad Tabba Message-ID: <20250729225455.670324-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 2c86673155c9..9895fc3cd901 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -74,7 +74,7 @@ config KVM_WERROR # FRAME_WARN, i.e. KVM_WERROR=y with KASAN=y requires special tuning. # Building KVM with -Werror and KASAN is still doable via enabling # the kernel-wide WERROR=y. - depends on KVM && ((EXPERT && !KASAN) || WERROR) + depends on KVM_X86 && ((EXPERT && !KASAN) || WERROR) help Add -Werror to the build flags for KVM. @@ -83,7 +83,7 @@ config KVM_WERROR config KVM_SW_PROTECTED_VM bool "Enable support for KVM software-protected VMs" depends on EXPERT - depends on KVM && X86_64 + depends on KVM_X86 && X86_64 help Enable support for KVM software-protected VMs. Currently, software- protected VMs are purely a development and testing vehicle for @@ -169,7 +169,7 @@ config KVM_AMD_SEV config KVM_IOAPIC bool "I/O APIC, PIC, and PIT emulation" default y - depends on KVM + depends on KVM_X86 help Provides support for KVM to emulate an I/O APIC, PIC, and PIT, i.e. for full in-kernel APIC emulation. @@ -179,7 +179,7 @@ config KVM_IOAPIC config KVM_SMM bool "System Management Mode emulation" default y - depends on KVM + depends on KVM_X86 help Provides support for KVM to emulate System Management Mode (SMM) in virtual machines. This can be used by the virtual machine @@ -189,7 +189,7 @@ config KVM_SMM config KVM_HYPERV bool "Support for Microsoft Hyper-V emulation" - depends on KVM + depends on KVM_X86 default y help Provides KVM support for emulating Microsoft Hyper-V. This allows KVM @@ -203,7 +203,7 @@ config KVM_HYPERV config KVM_XEN bool "Support for Xen hypercall interface" - depends on KVM + depends on KVM_X86 help Provides KVM support for the hosting Xen HVM guests and passing Xen hypercalls to userspace. @@ -213,7 +213,7 @@ config KVM_XEN config KVM_PROVE_MMU bool "Prove KVM MMU correctness" depends on DEBUG_KERNEL - depends on KVM + depends on KVM_X86 depends on EXPERT help Enables runtime assertions in KVM's MMU that are too costly to enable @@ -228,7 +228,7 @@ config KVM_EXTERNAL_WRITE_TRACKING config KVM_MAX_NR_VCPUS int "Maximum number of vCPUs per KVM guest" - depends on KVM + depends on KVM_X86 range 1024 4096 default 4096 if MAXSMP default 1024 From b4ff2efb7e780094cf02bff1735b44410d383388 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 29 Jul 2025 15:54:34 -0700 Subject: [PATCH 0549/2711] KVM: x86: Select KVM_GENERIC_PRIVATE_MEM directly from KVM_SW_PROTECTED_VM Now that KVM_SW_PROTECTED_VM doesn't have a hidden dependency on KVM_X86, select KVM_GENERIC_PRIVATE_MEM from within KVM_SW_PROTECTED_VM instead of conditionally selecting it from KVM_X86. No functional change intended. Reviewed-by: Xiaoyao Li Reviewed-by: David Hildenbrand Signed-off-by: Sean Christopherson Reviewed-by: Fuad Tabba Message-ID: <20250729225455.670324-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 9895fc3cd901..402ba00fdf45 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -46,7 +46,6 @@ config KVM_X86 select HAVE_KVM_PM_NOTIFIER if PM select KVM_GENERIC_HARDWARE_ENABLING select KVM_GENERIC_PRE_FAULT_MEMORY - select KVM_GENERIC_PRIVATE_MEM if KVM_SW_PROTECTED_VM select KVM_WERROR if WERROR config KVM @@ -84,6 +83,7 @@ config KVM_SW_PROTECTED_VM bool "Enable support for KVM software-protected VMs" depends on EXPERT depends on KVM_X86 && X86_64 + select KVM_GENERIC_PRIVATE_MEM help Enable support for KVM software-protected VMs. Currently, software- protected VMs are purely a development and testing vehicle for From 924121eebddcc6f062d1d2d20aafebe95f6fc290 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 29 Jul 2025 15:54:35 -0700 Subject: [PATCH 0550/2711] KVM: x86: Select TDX's KVM_GENERIC_xxx dependencies iff CONFIG_KVM_INTEL_TDX=y Select KVM_GENERIC_PRIVATE_MEM and KVM_GENERIC_MEMORY_ATTRIBUTES directly from KVM_INTEL_TDX, i.e. if and only if TDX support is fully enabled in KVM. There is no need to enable KVM's private memory support just because the core kernel's INTEL_TDX_HOST is enabled. Reviewed-by: Xiaoyao Li Reviewed-by: David Hildenbrand Signed-off-by: Sean Christopherson Reviewed-by: Fuad Tabba Message-ID: <20250729225455.670324-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 402ba00fdf45..13ab7265b505 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -95,8 +95,6 @@ config KVM_SW_PROTECTED_VM config KVM_INTEL tristate "KVM for Intel (and compatible) processors support" depends on KVM && IA32_FEAT_CTL - select KVM_GENERIC_PRIVATE_MEM if INTEL_TDX_HOST - select KVM_GENERIC_MEMORY_ATTRIBUTES if INTEL_TDX_HOST help Provides support for KVM on processors equipped with Intel's VT extensions, a.k.a. Virtual Machine Extensions (VMX). @@ -135,6 +133,8 @@ config KVM_INTEL_TDX bool "Intel Trust Domain Extensions (TDX) support" default y depends on INTEL_TDX_HOST + select KVM_GENERIC_PRIVATE_MEM + select KVM_GENERIC_MEMORY_ATTRIBUTES help Provides support for launching Intel Trust Domain Extensions (TDX) confidential VMs on Intel processors. From 36cf63bb5df68836e55e2839f8174b404d47670b Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:36 -0700 Subject: [PATCH 0551/2711] KVM: Rename CONFIG_KVM_GENERIC_PRIVATE_MEM to CONFIG_HAVE_KVM_ARCH_GMEM_POPULATE The original name was vague regarding its functionality. This Kconfig option specifically enables and gates the kvm_gmem_populate() function, which is responsible for populating a GPA range with guest data. The new name, HAVE_KVM_ARCH_GMEM_POPULATE, describes the purpose of the option: to enable arch-specific guest_memfd population mechanisms. It also follows the same pattern as the other HAVE_KVM_ARCH_* configuration options. This improves clarity for developers and ensures the name accurately reflects the functionality it controls, especially as guest_memfd support expands beyond purely "private" memory scenarios. Temporarily keep KVM_GENERIC_PRIVATE_MEM as an x86-only config so as to minimize churn, and to hopefully make it easier to see what features require HAVE_KVM_ARCH_GMEM_POPULATE. On that note, omit GMEM_POPULATE for KVM_X86_SW_PROTECTED_VM, as regular ol' memset() suffices for software-protected VMs. As for KVM_GENERIC_PRIVATE_MEM, a future change will select KVM_GUEST_MEMFD for all 64-bit KVM builds, at which point the intermediate config will become obsolete and can/will be dropped. Reviewed-by: Ira Weiny Reviewed-by: Gavin Shan Reviewed-by: Shivank Garg Reviewed-by: Vlastimil Babka Co-developed-by: David Hildenbrand Signed-off-by: David Hildenbrand Signed-off-by: Fuad Tabba Reviewed-by: Xiaoyao Li Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/Kconfig | 14 ++++++++++---- include/linux/kvm_host.h | 2 +- virt/kvm/Kconfig | 9 ++++----- virt/kvm/guest_memfd.c | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 13ab7265b505..c763446d9b9f 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -79,11 +79,16 @@ config KVM_WERROR If in doubt, say "N". +config KVM_X86_PRIVATE_MEM + select KVM_GENERIC_MEMORY_ATTRIBUTES + select KVM_GUEST_MEMFD + bool + config KVM_SW_PROTECTED_VM bool "Enable support for KVM software-protected VMs" depends on EXPERT depends on KVM_X86 && X86_64 - select KVM_GENERIC_PRIVATE_MEM + select KVM_X86_PRIVATE_MEM help Enable support for KVM software-protected VMs. Currently, software- protected VMs are purely a development and testing vehicle for @@ -133,8 +138,8 @@ config KVM_INTEL_TDX bool "Intel Trust Domain Extensions (TDX) support" default y depends on INTEL_TDX_HOST - select KVM_GENERIC_PRIVATE_MEM - select KVM_GENERIC_MEMORY_ATTRIBUTES + select KVM_X86_PRIVATE_MEM + select HAVE_KVM_ARCH_GMEM_POPULATE help Provides support for launching Intel Trust Domain Extensions (TDX) confidential VMs on Intel processors. @@ -157,9 +162,10 @@ config KVM_AMD_SEV depends on KVM_AMD && X86_64 depends on CRYPTO_DEV_SP_PSP && !(KVM_AMD=y && CRYPTO_DEV_CCP_DD=m) select ARCH_HAS_CC_PLATFORM - select KVM_GENERIC_PRIVATE_MEM + select KVM_X86_PRIVATE_MEM select HAVE_KVM_ARCH_GMEM_PREPARE select HAVE_KVM_ARCH_GMEM_INVALIDATE + select HAVE_KVM_ARCH_GMEM_POPULATE help Provides support for launching encrypted VMs which use Secure Encrypted Virtualization (SEV), Secure Encrypted Virtualization with diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 8cdc0b3cc1b1..ddfb6cfe20a6 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -2534,7 +2534,7 @@ static inline int kvm_gmem_get_pfn(struct kvm *kvm, int kvm_arch_gmem_prepare(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, int max_order); #endif -#ifdef CONFIG_KVM_GENERIC_PRIVATE_MEM +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_POPULATE /** * kvm_gmem_populate() - Populate/prepare a GPA range with guest data * diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index e4b400feff94..1b7d5be0b6c4 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -116,11 +116,6 @@ config KVM_GUEST_MEMFD select XARRAY_MULTI bool -config KVM_GENERIC_PRIVATE_MEM - select KVM_GENERIC_MEMORY_ATTRIBUTES - select KVM_GUEST_MEMFD - bool - config HAVE_KVM_ARCH_GMEM_PREPARE bool depends on KVM_GUEST_MEMFD @@ -128,3 +123,7 @@ config HAVE_KVM_ARCH_GMEM_PREPARE config HAVE_KVM_ARCH_GMEM_INVALIDATE bool depends on KVM_GUEST_MEMFD + +config HAVE_KVM_ARCH_GMEM_POPULATE + bool + depends on KVM_GUEST_MEMFD diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c index 7d85cc33c0bb..b2b50560e80e 100644 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@ -627,7 +627,7 @@ out: } EXPORT_SYMBOL_GPL(kvm_gmem_get_pfn); -#ifdef CONFIG_KVM_GENERIC_PRIVATE_MEM +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_POPULATE long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long npages, kvm_gmem_populate_cb post_populate, void *opaque) { From 923310be23b275f730e8869abc783db6296fc043 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:37 -0700 Subject: [PATCH 0552/2711] KVM: Rename kvm_slot_can_be_private() to kvm_slot_has_gmem() Rename kvm_slot_can_be_private() to kvm_slot_has_gmem() to improve clarity and accurately reflect its purpose. The function kvm_slot_can_be_private() was previously used to check if a given kvm_memory_slot is backed by guest_memfd. However, its name implied that the memory in such a slot was exclusively "private". As guest_memfd support expands to include non-private memory (e.g., shared host mappings), it's important to remove this association. The new name, kvm_slot_has_gmem(), states that the slot is backed by guest_memfd without making assumptions about the memory's privacy attributes. Reviewed-by: Ira Weiny Reviewed-by: Gavin Shan Reviewed-by: Shivank Garg Reviewed-by: Vlastimil Babka Reviewed-by: Xiaoyao Li Co-developed-by: David Hildenbrand Signed-off-by: David Hildenbrand Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-7-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 4 ++-- arch/x86/kvm/svm/sev.c | 4 ++-- include/linux/kvm_host.h | 2 +- virt/kvm/guest_memfd.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 6e838cb6c9e1..fdc2824755ee 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3312,7 +3312,7 @@ static int __kvm_mmu_max_mapping_level(struct kvm *kvm, int kvm_mmu_max_mapping_level(struct kvm *kvm, const struct kvm_memory_slot *slot, gfn_t gfn) { - bool is_private = kvm_slot_can_be_private(slot) && + bool is_private = kvm_slot_has_gmem(slot) && kvm_mem_is_private(kvm, gfn); return __kvm_mmu_max_mapping_level(kvm, slot, gfn, PG_LEVEL_NUM, is_private); @@ -4551,7 +4551,7 @@ static int kvm_mmu_faultin_pfn_private(struct kvm_vcpu *vcpu, { int max_order, r; - if (!kvm_slot_can_be_private(fault->slot)) { + if (!kvm_slot_has_gmem(fault->slot)) { kvm_mmu_prepare_memory_fault_exit(vcpu, fault); return -EFAULT; } diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 0635bd71c10e..966a330dd294 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2361,7 +2361,7 @@ static int snp_launch_update(struct kvm *kvm, struct kvm_sev_cmd *argp) mutex_lock(&kvm->slots_lock); memslot = gfn_to_memslot(kvm, params.gfn_start); - if (!kvm_slot_can_be_private(memslot)) { + if (!kvm_slot_has_gmem(memslot)) { ret = -EINVAL; goto out; } @@ -4715,7 +4715,7 @@ void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) } slot = gfn_to_memslot(kvm, gfn); - if (!kvm_slot_can_be_private(slot)) { + if (!kvm_slot_has_gmem(slot)) { pr_warn_ratelimited("SEV: Unexpected RMP fault, non-private slot for GPA 0x%llx\n", gpa); return; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index ddfb6cfe20a6..4c5e0a898652 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -615,7 +615,7 @@ struct kvm_memory_slot { #endif }; -static inline bool kvm_slot_can_be_private(const struct kvm_memory_slot *slot) +static inline bool kvm_slot_has_gmem(const struct kvm_memory_slot *slot) { return slot && (slot->flags & KVM_MEM_GUEST_MEMFD); } diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c index b2b50560e80e..a99e11b8b77f 100644 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@ -643,7 +643,7 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long return -EINVAL; slot = gfn_to_memslot(kvm, start_gfn); - if (!kvm_slot_can_be_private(slot)) + if (!kvm_slot_has_gmem(slot)) return -EINVAL; file = kvm_gmem_get_file(slot); From 69116e01f6fee030db45d269f28f9c300b8dc9d6 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:38 -0700 Subject: [PATCH 0553/2711] KVM: Fix comments that refer to slots_lock Fix comments so that they refer to slots_lock instead of slots_locks (remove trailing s). Reviewed-by: David Hildenbrand Reviewed-by: Ira Weiny Reviewed-by: Gavin Shan Reviewed-by: Shivank Garg Reviewed-by: Vlastimil Babka Reviewed-by: Xiaoyao Li Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-8-seanjc@google.com> Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 2 +- virt/kvm/kvm_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 4c5e0a898652..5c25b03d3d50 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -860,7 +860,7 @@ struct kvm { struct notifier_block pm_notifier; #endif #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES - /* Protected by slots_locks (for writes) and RCU (for reads) */ + /* Protected by slots_lock (for writes) and RCU (for reads) */ struct xarray mem_attr_array; #endif char stats_id[KVM_STATS_NAME_SIZE]; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 25a94eed75fd..aa86dfd757db 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -331,7 +331,7 @@ void kvm_flush_remote_tlbs_memslot(struct kvm *kvm, * All current use cases for flushing the TLBs for a specific memslot * are related to dirty logging, and many do the TLB flush out of * mmu_lock. The interaction between the various operations on memslot - * must be serialized by slots_locks to ensure the TLB flush from one + * must be serialized by slots_lock to ensure the TLB flush from one * operation is observed by any other operation on the same memslot. */ lockdep_assert_held(&kvm->slots_lock); From 68d189938709a5918d7308eb922c30bcbf16ebb9 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:39 -0700 Subject: [PATCH 0554/2711] KVM: Fix comment that refers to kvm uapi header path The comment that points to the path where the user-visible memslot flags are refers to an outdated path and has a typo. Update the comment to refer to the correct path. Reviewed-by: David Hildenbrand Reviewed-by: Gavin Shan Reviewed-by: Shivank Garg Reviewed-by: Vlastimil Babka Reviewed-by: Xiaoyao Li Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-9-seanjc@google.com> Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 5c25b03d3d50..56ea8c862cfd 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -52,7 +52,7 @@ /* * The bit 16 ~ bit 31 of kvm_userspace_memory_region::flags are internally * used in kvm, other bits are visible for userspace which are defined in - * include/linux/kvm_h. + * include/uapi/linux/kvm.h. */ #define KVM_MEMSLOT_INVALID (1UL << 16) From d1e54dd08f163a9021433020d16a8f8f70ddc41c Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:40 -0700 Subject: [PATCH 0555/2711] KVM: x86: Enable KVM_GUEST_MEMFD for all 64-bit builds Enable KVM_GUEST_MEMFD for all KVM x86 64-bit builds, i.e. for "default" VM types when running on 64-bit KVM. This will allow using guest_memfd to back non-private memory for all VM shapes, by supporting mmap() on guest_memfd. Opportunistically clean up various conditionals that become tautologies once x86 selects KVM_GUEST_MEMFD more broadly. Specifically, because SW protected VMs, SEV, and TDX are all 64-bit only, private memory no longer needs to take explicit dependencies on KVM_GUEST_MEMFD, because it is effectively a prerequisite. Suggested-by: Sean Christopherson Signed-off-by: Fuad Tabba Reviewed-by: Xiaoyao Li Reviewed-by: David Hildenbrand Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-10-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 4 +--- arch/x86/kvm/Kconfig | 12 ++++-------- include/linux/kvm_host.h | 9 ++------- virt/kvm/kvm_main.c | 4 ++-- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 7b0f2b3e492d..50366a1ca192 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2276,10 +2276,8 @@ void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level, int tdp_max_root_level, int tdp_huge_page_level); -#ifdef CONFIG_KVM_GUEST_MEMFD +#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.has_private_mem) -#else -#define kvm_arch_has_private_mem(kvm) false #endif #define kvm_arch_has_readonly_mem(kvm) (!(kvm)->arch.has_protected_state) diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index c763446d9b9f..4e43923656d0 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -47,6 +47,7 @@ config KVM_X86 select KVM_GENERIC_HARDWARE_ENABLING select KVM_GENERIC_PRE_FAULT_MEMORY select KVM_WERROR if WERROR + select KVM_GUEST_MEMFD if X86_64 config KVM tristate "Kernel-based Virtual Machine (KVM) support" @@ -79,16 +80,11 @@ config KVM_WERROR If in doubt, say "N". -config KVM_X86_PRIVATE_MEM - select KVM_GENERIC_MEMORY_ATTRIBUTES - select KVM_GUEST_MEMFD - bool - config KVM_SW_PROTECTED_VM bool "Enable support for KVM software-protected VMs" depends on EXPERT depends on KVM_X86 && X86_64 - select KVM_X86_PRIVATE_MEM + select KVM_GENERIC_MEMORY_ATTRIBUTES help Enable support for KVM software-protected VMs. Currently, software- protected VMs are purely a development and testing vehicle for @@ -138,7 +134,7 @@ config KVM_INTEL_TDX bool "Intel Trust Domain Extensions (TDX) support" default y depends on INTEL_TDX_HOST - select KVM_X86_PRIVATE_MEM + select KVM_GENERIC_MEMORY_ATTRIBUTES select HAVE_KVM_ARCH_GMEM_POPULATE help Provides support for launching Intel Trust Domain Extensions (TDX) @@ -162,7 +158,7 @@ config KVM_AMD_SEV depends on KVM_AMD && X86_64 depends on CRYPTO_DEV_SP_PSP && !(KVM_AMD=y && CRYPTO_DEV_CCP_DD=m) select ARCH_HAS_CC_PLATFORM - select KVM_X86_PRIVATE_MEM + select KVM_GENERIC_MEMORY_ATTRIBUTES select HAVE_KVM_ARCH_GMEM_PREPARE select HAVE_KVM_ARCH_GMEM_INVALIDATE select HAVE_KVM_ARCH_GMEM_POPULATE diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 56ea8c862cfd..4d1c44622056 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -719,11 +719,7 @@ static inline int kvm_arch_vcpu_memslots_id(struct kvm_vcpu *vcpu) } #endif -/* - * Arch code must define kvm_arch_has_private_mem if support for guest_memfd is - * enabled. - */ -#if !defined(kvm_arch_has_private_mem) && !IS_ENABLED(CONFIG_KVM_GUEST_MEMFD) +#ifndef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES static inline bool kvm_arch_has_private_mem(struct kvm *kvm) { return false; @@ -2505,8 +2501,7 @@ bool kvm_arch_post_set_memory_attributes(struct kvm *kvm, static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn) { - return IS_ENABLED(CONFIG_KVM_GUEST_MEMFD) && - kvm_get_memory_attributes(kvm, gfn) & KVM_MEMORY_ATTRIBUTE_PRIVATE; + return kvm_get_memory_attributes(kvm, gfn) & KVM_MEMORY_ATTRIBUTE_PRIVATE; } #else static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index aa86dfd757db..4f57cb92e109 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1588,7 +1588,7 @@ static int check_memory_region_flags(struct kvm *kvm, { u32 valid_flags = KVM_MEM_LOG_DIRTY_PAGES; - if (kvm_arch_has_private_mem(kvm)) + if (IS_ENABLED(CONFIG_KVM_GUEST_MEMFD)) valid_flags |= KVM_MEM_GUEST_MEMFD; /* Dirty logging private memory is not currently supported. */ @@ -4917,7 +4917,7 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg) #endif #ifdef CONFIG_KVM_GUEST_MEMFD case KVM_CAP_GUEST_MEMFD: - return !kvm || kvm_arch_has_private_mem(kvm); + return 1; #endif default: break; From a12578e1477cbfb547256ed8dee6d5142a59cdcd Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:41 -0700 Subject: [PATCH 0556/2711] KVM: guest_memfd: Add plumbing to host to map guest_memfd pages Introduce the core infrastructure to enable host userspace to mmap() guest_memfd-backed memory. This is needed for several evolving KVM use cases: * Non-CoCo VM backing: Allows VMMs like Firecracker to run guests entirely backed by guest_memfd, even for non-CoCo VMs [1]. This provides a unified memory management model and simplifies guest memory handling. * Direct map removal for enhanced security: This is an important step for direct map removal of guest memory [2]. By allowing host userspace to fault in guest_memfd pages directly, we can avoid maintaining host kernel direct maps of guest memory. This provides additional hardening against Spectre-like transient execution attacks by removing a potential attack surface within the kernel. * Future guest_memfd features: This also lays the groundwork for future enhancements to guest_memfd, such as supporting huge pages and enabling in-place sharing of guest memory with the host for CoCo platforms that permit it [3]. Enable the basic mmap and fault handling logic within guest_memfd, but hold off on allow userspace to actually do mmap() until the architecture support is also in place. [1] https://github.com/firecracker-microvm/firecracker/tree/feature/secret-hiding [2] https://lore.kernel.org/linux-mm/cc1bb8e9bc3e1ab637700a4d3defeec95b55060a.camel@amazon.com [3] https://lore.kernel.org/all/c1c9591d-218a-495c-957b-ba356c8f8e09@redhat.com/T/#u Reviewed-by: Gavin Shan Reviewed-by: Shivank Garg Acked-by: David Hildenbrand Co-developed-by: Ackerley Tng Signed-off-by: Ackerley Tng Signed-off-by: Fuad Tabba Reviewed-by: Xiaoyao Li Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-11-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 11 +++++++ include/linux/kvm_host.h | 4 +++ virt/kvm/guest_memfd.c | 70 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 604490b1cb19..33fba801b205 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -13521,6 +13521,16 @@ bool kvm_arch_no_poll(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_arch_no_poll); +#ifdef CONFIG_KVM_GUEST_MEMFD +/* + * KVM doesn't yet support mmap() on guest_memfd for VMs with private memory + * (the private vs. shared tracking needs to be moved into guest_memfd). + */ +bool kvm_arch_supports_gmem_mmap(struct kvm *kvm) +{ + return !kvm_arch_has_private_mem(kvm); +} + #ifdef CONFIG_HAVE_KVM_ARCH_GMEM_PREPARE int kvm_arch_gmem_prepare(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, int max_order) { @@ -13534,6 +13544,7 @@ void kvm_arch_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end) kvm_x86_call(gmem_invalidate)(start, end); } #endif +#endif int kvm_spec_ctrl_test_value(u64 value) { diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 4d1c44622056..26bad600f9fa 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -726,6 +726,10 @@ static inline bool kvm_arch_has_private_mem(struct kvm *kvm) } #endif +#ifdef CONFIG_KVM_GUEST_MEMFD +bool kvm_arch_supports_gmem_mmap(struct kvm *kvm); +#endif + #ifndef kvm_arch_has_readonly_mem static inline bool kvm_arch_has_readonly_mem(struct kvm *kvm) { diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c index a99e11b8b77f..67e7cd7210ef 100644 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@ -312,7 +312,72 @@ static pgoff_t kvm_gmem_get_index(struct kvm_memory_slot *slot, gfn_t gfn) return gfn - slot->base_gfn + slot->gmem.pgoff; } +static bool kvm_gmem_supports_mmap(struct inode *inode) +{ + return false; +} + +static vm_fault_t kvm_gmem_fault_user_mapping(struct vm_fault *vmf) +{ + struct inode *inode = file_inode(vmf->vma->vm_file); + struct folio *folio; + vm_fault_t ret = VM_FAULT_LOCKED; + + if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode)) + return VM_FAULT_SIGBUS; + + folio = kvm_gmem_get_folio(inode, vmf->pgoff); + if (IS_ERR(folio)) { + int err = PTR_ERR(folio); + + if (err == -EAGAIN) + return VM_FAULT_RETRY; + + return vmf_error(err); + } + + if (WARN_ON_ONCE(folio_test_large(folio))) { + ret = VM_FAULT_SIGBUS; + goto out_folio; + } + + if (!folio_test_uptodate(folio)) { + clear_highpage(folio_page(folio, 0)); + kvm_gmem_mark_prepared(folio); + } + + vmf->page = folio_file_page(folio, vmf->pgoff); + +out_folio: + if (ret != VM_FAULT_LOCKED) { + folio_unlock(folio); + folio_put(folio); + } + + return ret; +} + +static const struct vm_operations_struct kvm_gmem_vm_ops = { + .fault = kvm_gmem_fault_user_mapping, +}; + +static int kvm_gmem_mmap(struct file *file, struct vm_area_struct *vma) +{ + if (!kvm_gmem_supports_mmap(file_inode(file))) + return -ENODEV; + + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) != + (VM_SHARED | VM_MAYSHARE)) { + return -EINVAL; + } + + vma->vm_ops = &kvm_gmem_vm_ops; + + return 0; +} + static struct file_operations kvm_gmem_fops = { + .mmap = kvm_gmem_mmap, .open = generic_file_open, .release = kvm_gmem_release, .fallocate = kvm_gmem_fallocate, @@ -391,6 +456,11 @@ static const struct inode_operations kvm_gmem_iops = { .setattr = kvm_gmem_setattr, }; +bool __weak kvm_arch_supports_gmem_mmap(struct kvm *kvm) +{ + return true; +} + static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags) { const char *anon_name = "[kvm-gmem]"; From 576d035e2aef52f8d8d3ce29af556d4c6bd2e0fe Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:42 -0700 Subject: [PATCH 0557/2711] KVM: guest_memfd: Track guest_memfd mmap support in memslot Add a new internal flag, KVM_MEMSLOT_GMEM_ONLY, to the top half of memslot->flags (which makes it strictly for KVM's internal use). This flag tracks when a guest_memfd-backed memory slot supports host userspace mmap operations, which implies that all memory, not just private memory for CoCo VMs, is consumed through guest_memfd: "gmem only". This optimization avoids repeatedly checking the underlying guest_memfd file for mmap support, which would otherwise require taking and releasing a reference on the file for each check. By caching this information directly in the memslot, we reduce overhead and simplify the logic involved in handling guest_memfd-backed pages for host mappings. Reviewed-by: Gavin Shan Reviewed-by: Shivank Garg Reviewed-by: Xiaoyao Li Acked-by: David Hildenbrand Suggested-by: David Hildenbrand Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-12-seanjc@google.com> Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 11 ++++++++++- virt/kvm/guest_memfd.c | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 26bad600f9fa..8b47891adca1 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -54,7 +54,8 @@ * used in kvm, other bits are visible for userspace which are defined in * include/uapi/linux/kvm.h. */ -#define KVM_MEMSLOT_INVALID (1UL << 16) +#define KVM_MEMSLOT_INVALID (1UL << 16) +#define KVM_MEMSLOT_GMEM_ONLY (1UL << 17) /* * Bit 63 of the memslot generation number is an "update in-progress flag", @@ -2490,6 +2491,14 @@ static inline void kvm_prepare_memory_fault_exit(struct kvm_vcpu *vcpu, vcpu->run->memory_fault.flags |= KVM_MEMORY_EXIT_FLAG_PRIVATE; } +static inline bool kvm_memslot_is_gmem_only(const struct kvm_memory_slot *slot) +{ + if (!IS_ENABLED(CONFIG_KVM_GUEST_MEMFD)) + return false; + + return slot->flags & KVM_MEMSLOT_GMEM_ONLY; +} + #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES static inline unsigned long kvm_get_memory_attributes(struct kvm *kvm, gfn_t gfn) { diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c index 67e7cd7210ef..d5b445548af4 100644 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@ -578,6 +578,8 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot, */ WRITE_ONCE(slot->gmem.file, file); slot->gmem.pgoff = start; + if (kvm_gmem_supports_mmap(inode)) + slot->flags |= KVM_MEMSLOT_GMEM_ONLY; xa_store_range(&gmem->bindings, start, end - 1, slot, GFP_KERNEL); filemap_invalidate_unlock(inode->i_mapping); From d6c840adfebca55d4520244c77467bd16b4ea41e Mon Sep 17 00:00:00 2001 From: Ackerley Tng Date: Tue, 29 Jul 2025 15:54:43 -0700 Subject: [PATCH 0558/2711] KVM: x86/mmu: Rename .private_max_mapping_level() to .gmem_max_mapping_level() Rename kvm_x86_ops.private_max_mapping_level() to .gmem_max_mapping_level() in anticipation of extending guest_memfd support to non-private memory. No functional change intended. Reviewed-by: Xiaoyao Li Acked-by: David Hildenbrand Signed-off-by: Ackerley Tng Signed-off-by: Fuad Tabba Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Reviewed-by: Fuad Tabba Message-ID: <20250729225455.670324-13-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm-x86-ops.h | 2 +- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/mmu/mmu.c | 2 +- arch/x86/kvm/svm/sev.c | 2 +- arch/x86/kvm/svm/svm.c | 2 +- arch/x86/kvm/svm/svm.h | 4 ++-- arch/x86/kvm/vmx/main.c | 6 +++--- arch/x86/kvm/vmx/tdx.c | 2 +- arch/x86/kvm/vmx/x86_ops.h | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 18a5c3119e1a..62c3e4de3303 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -145,7 +145,7 @@ KVM_X86_OP_OPTIONAL_RET0(vcpu_get_apicv_inhibit_reasons); KVM_X86_OP_OPTIONAL(get_untagged_addr) KVM_X86_OP_OPTIONAL(alloc_apic_backing_page) KVM_X86_OP_OPTIONAL_RET0(gmem_prepare) -KVM_X86_OP_OPTIONAL_RET0(private_max_mapping_level) +KVM_X86_OP_OPTIONAL_RET0(gmem_max_mapping_level) KVM_X86_OP_OPTIONAL(gmem_invalidate) #undef KVM_X86_OP diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 50366a1ca192..c0a739bf3829 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1922,7 +1922,7 @@ struct kvm_x86_ops { void *(*alloc_apic_backing_page)(struct kvm_vcpu *vcpu); int (*gmem_prepare)(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order); void (*gmem_invalidate)(kvm_pfn_t start, kvm_pfn_t end); - int (*private_max_mapping_level)(struct kvm *kvm, kvm_pfn_t pfn); + int (*gmem_max_mapping_level)(struct kvm *kvm, kvm_pfn_t pfn); }; struct kvm_x86_nested_ops { diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index fdc2824755ee..b735611e8fcd 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4532,7 +4532,7 @@ static u8 kvm_max_private_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, if (max_level == PG_LEVEL_4K) return PG_LEVEL_4K; - req_max_level = kvm_x86_call(private_max_mapping_level)(kvm, pfn); + req_max_level = kvm_x86_call(gmem_max_mapping_level)(kvm, pfn); if (req_max_level) max_level = min(max_level, req_max_level); diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 966a330dd294..b926a053b8cf 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -4943,7 +4943,7 @@ next_pfn: } } -int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) +int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) { int level, rc; bool assigned; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index d9931c6c4bc6..8a66e2e985a4 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5180,7 +5180,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { .gmem_prepare = sev_gmem_prepare, .gmem_invalidate = sev_gmem_invalidate, - .private_max_mapping_level = sev_private_max_mapping_level, + .gmem_max_mapping_level = sev_gmem_max_mapping_level, }; /* diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 58b9d168e0c8..d84a83ae18a1 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -866,7 +866,7 @@ void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code); void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu); int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order); void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end); -int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn); +int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn); struct vmcb_save_area *sev_decrypt_vmsa(struct kvm_vcpu *vcpu); void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa); #else @@ -895,7 +895,7 @@ static inline int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, in return 0; } static inline void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end) {} -static inline int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) +static inline int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) { return 0; } diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c index dbab1c15b0cd..dd7687ef7e2d 100644 --- a/arch/x86/kvm/vmx/main.c +++ b/arch/x86/kvm/vmx/main.c @@ -831,10 +831,10 @@ static int vt_vcpu_mem_enc_ioctl(struct kvm_vcpu *vcpu, void __user *argp) return tdx_vcpu_ioctl(vcpu, argp); } -static int vt_gmem_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) +static int vt_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) { if (is_td(kvm)) - return tdx_gmem_private_max_mapping_level(kvm, pfn); + return tdx_gmem_max_mapping_level(kvm, pfn); return 0; } @@ -1005,7 +1005,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = { .mem_enc_ioctl = vt_op_tdx_only(mem_enc_ioctl), .vcpu_mem_enc_ioctl = vt_op_tdx_only(vcpu_mem_enc_ioctl), - .private_max_mapping_level = vt_op_tdx_only(gmem_private_max_mapping_level) + .gmem_max_mapping_level = vt_op_tdx_only(gmem_max_mapping_level) }; struct kvm_x86_init_ops vt_init_ops __initdata = { diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 66744f5768c8..b444714e8e8a 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -3318,7 +3318,7 @@ int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp) return ret; } -int tdx_gmem_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) +int tdx_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) { return PG_LEVEL_4K; } diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h index 2b3424f638db..6037d1708485 100644 --- a/arch/x86/kvm/vmx/x86_ops.h +++ b/arch/x86/kvm/vmx/x86_ops.h @@ -153,7 +153,7 @@ int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp); void tdx_flush_tlb_current(struct kvm_vcpu *vcpu); void tdx_flush_tlb_all(struct kvm_vcpu *vcpu); void tdx_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level); -int tdx_gmem_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn); +int tdx_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn); #endif #endif /* __KVM_X86_VMX_X86_OPS_H */ From 1c3fdf13703ba6bb006671db72b7a02d2bd58b8b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 29 Jul 2025 15:54:44 -0700 Subject: [PATCH 0559/2711] KVM: x86/mmu: Hoist guest_memfd max level/order helpers "up" in mmu.c Move kvm_max_level_for_order() and kvm_max_private_mapping_level() up in mmu.c so that they can be used by __kvm_mmu_max_mapping_level(). Opportunistically drop the "inline" from kvm_max_level_for_order(). No functional change intended. Reviewed-by: Xiaoyao Li Reviewed-by: Ackerley Tng Signed-off-by: Sean Christopherson Reviewed-by: David Hildenbrand Reviewed-by: Fuad Tabba Message-ID: <20250729225455.670324-14-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 72 +++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index b735611e8fcd..20dd9f64156e 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3285,6 +3285,42 @@ out: return level; } +static u8 kvm_max_level_for_order(int order) +{ + BUILD_BUG_ON(KVM_MAX_HUGEPAGE_LEVEL > PG_LEVEL_1G); + + KVM_MMU_WARN_ON(order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_1G) && + order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_2M) && + order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_4K)); + + if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_1G)) + return PG_LEVEL_1G; + + if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_2M)) + return PG_LEVEL_2M; + + return PG_LEVEL_4K; +} + +static u8 kvm_max_private_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, + u8 max_level, int gmem_order) +{ + u8 req_max_level; + + if (max_level == PG_LEVEL_4K) + return PG_LEVEL_4K; + + max_level = min(kvm_max_level_for_order(gmem_order), max_level); + if (max_level == PG_LEVEL_4K) + return PG_LEVEL_4K; + + req_max_level = kvm_x86_call(gmem_max_mapping_level)(kvm, pfn); + if (req_max_level) + max_level = min(max_level, req_max_level); + + return max_level; +} + static int __kvm_mmu_max_mapping_level(struct kvm *kvm, const struct kvm_memory_slot *slot, gfn_t gfn, int max_level, bool is_private) @@ -4503,42 +4539,6 @@ void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, struct kvm_async_pf *work) vcpu->stat.pf_fixed++; } -static inline u8 kvm_max_level_for_order(int order) -{ - BUILD_BUG_ON(KVM_MAX_HUGEPAGE_LEVEL > PG_LEVEL_1G); - - KVM_MMU_WARN_ON(order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_1G) && - order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_2M) && - order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_4K)); - - if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_1G)) - return PG_LEVEL_1G; - - if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_2M)) - return PG_LEVEL_2M; - - return PG_LEVEL_4K; -} - -static u8 kvm_max_private_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, - u8 max_level, int gmem_order) -{ - u8 req_max_level; - - if (max_level == PG_LEVEL_4K) - return PG_LEVEL_4K; - - max_level = min(kvm_max_level_for_order(gmem_order), max_level); - if (max_level == PG_LEVEL_4K) - return PG_LEVEL_4K; - - req_max_level = kvm_x86_call(gmem_max_mapping_level)(kvm, pfn); - if (req_max_level) - max_level = min(max_level, req_max_level); - - return max_level; -} - static void kvm_mmu_finish_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, int r) { From a3522ac71f5e1c1a9bacee46663d6e83efb9c325 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 29 Jul 2025 15:54:45 -0700 Subject: [PATCH 0560/2711] KVM: x86/mmu: Enforce guest_memfd's max order when recovering hugepages Rework kvm_mmu_max_mapping_level() to provide the plumbing to consult guest_memfd (and relevant vendor code) when recovering hugepages, e.g. after disabling live migration. The flaw has existed since guest_memfd was originally added, but has gone unnoticed due to lack of guest_memfd support for hugepages or dirty logging. Don't actually call into guest_memfd at this time, as it's unclear as to what the API should be. Ideally, KVM would simply use kvm_gmem_get_pfn(), but invoking kvm_gmem_get_pfn() would lead to sleeping in atomic context if guest_memfd needed to allocate memory (mmu_lock is held). Luckily, the path isn't actually reachable, so just add a TODO and WARN to ensure the functionality is added alongisde guest_memfd hugepage support, and punt the guest_memfd API design question to the future. Note, calling kvm_mem_is_private() in the non-fault path is safe, so long as mmu_lock is held, as hugepage recovery operates on shadow-present SPTEs, i.e. calling kvm_mmu_max_mapping_level() with @fault=NULL is mutually exclusive with kvm_vm_set_mem_attributes() changing the PRIVATE attribute of the gfn. Signed-off-by: Sean Christopherson Reviewed-by: David Hildenbrand Reviewed-by: Fuad Tabba Message-ID: <20250729225455.670324-15-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 80 +++++++++++++++++++-------------- arch/x86/kvm/mmu/mmu_internal.h | 2 +- arch/x86/kvm/mmu/tdp_mmu.c | 2 +- 3 files changed, 48 insertions(+), 36 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 20dd9f64156e..61eb9f723675 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3302,31 +3302,54 @@ static u8 kvm_max_level_for_order(int order) return PG_LEVEL_4K; } -static u8 kvm_max_private_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, - u8 max_level, int gmem_order) +static u8 kvm_max_private_mapping_level(struct kvm *kvm, struct kvm_page_fault *fault, + const struct kvm_memory_slot *slot, gfn_t gfn) { - u8 req_max_level; + u8 max_level, coco_level; + kvm_pfn_t pfn; + + /* For faults, use the gmem information that was resolved earlier. */ + if (fault) { + pfn = fault->pfn; + max_level = fault->max_level; + } else { + /* TODO: Call into guest_memfd once hugepages are supported. */ + WARN_ONCE(1, "Get pfn+order from guest_memfd"); + pfn = KVM_PFN_ERR_FAULT; + max_level = PG_LEVEL_4K; + } if (max_level == PG_LEVEL_4K) - return PG_LEVEL_4K; + return max_level; - max_level = min(kvm_max_level_for_order(gmem_order), max_level); - if (max_level == PG_LEVEL_4K) - return PG_LEVEL_4K; - - req_max_level = kvm_x86_call(gmem_max_mapping_level)(kvm, pfn); - if (req_max_level) - max_level = min(max_level, req_max_level); + /* + * CoCo may influence the max mapping level, e.g. due to RMP or S-EPT + * restrictions. A return of '0' means "no additional restrictions", to + * allow for using an optional "ret0" static call. + */ + coco_level = kvm_x86_call(gmem_max_mapping_level)(kvm, pfn); + if (coco_level) + max_level = min(max_level, coco_level); return max_level; } -static int __kvm_mmu_max_mapping_level(struct kvm *kvm, - const struct kvm_memory_slot *slot, - gfn_t gfn, int max_level, bool is_private) +int kvm_mmu_max_mapping_level(struct kvm *kvm, struct kvm_page_fault *fault, + const struct kvm_memory_slot *slot, gfn_t gfn) { struct kvm_lpage_info *linfo; - int host_level; + int host_level, max_level; + bool is_private; + + lockdep_assert_held(&kvm->mmu_lock); + + if (fault) { + max_level = fault->max_level; + is_private = fault->is_private; + } else { + max_level = PG_LEVEL_NUM; + is_private = kvm_mem_is_private(kvm, gfn); + } max_level = min(max_level, max_huge_page_level); for ( ; max_level > PG_LEVEL_4K; max_level--) { @@ -3335,25 +3358,16 @@ static int __kvm_mmu_max_mapping_level(struct kvm *kvm, break; } - if (is_private) - return max_level; - if (max_level == PG_LEVEL_4K) return PG_LEVEL_4K; - host_level = host_pfn_mapping_level(kvm, gfn, slot); + if (is_private) + host_level = kvm_max_private_mapping_level(kvm, fault, slot, gfn); + else + host_level = host_pfn_mapping_level(kvm, gfn, slot); return min(host_level, max_level); } -int kvm_mmu_max_mapping_level(struct kvm *kvm, - const struct kvm_memory_slot *slot, gfn_t gfn) -{ - bool is_private = kvm_slot_has_gmem(slot) && - kvm_mem_is_private(kvm, gfn); - - return __kvm_mmu_max_mapping_level(kvm, slot, gfn, PG_LEVEL_NUM, is_private); -} - void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { struct kvm_memory_slot *slot = fault->slot; @@ -3374,9 +3388,8 @@ void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault * Enforce the iTLB multihit workaround after capturing the requested * level, which will be used to do precise, accurate accounting. */ - fault->req_level = __kvm_mmu_max_mapping_level(vcpu->kvm, slot, - fault->gfn, fault->max_level, - fault->is_private); + fault->req_level = kvm_mmu_max_mapping_level(vcpu->kvm, fault, + fault->slot, fault->gfn); if (fault->req_level == PG_LEVEL_4K || fault->huge_page_disallowed) return; @@ -4564,8 +4577,7 @@ static int kvm_mmu_faultin_pfn_private(struct kvm_vcpu *vcpu, } fault->map_writable = !(fault->slot->flags & KVM_MEM_READONLY); - fault->max_level = kvm_max_private_mapping_level(vcpu->kvm, fault->pfn, - fault->max_level, max_order); + fault->max_level = kvm_max_level_for_order(max_order); return RET_PF_CONTINUE; } @@ -7165,7 +7177,7 @@ restart: * mapping if the indirect sp has level = 1. */ if (sp->role.direct && - sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn)) { + sp->role.level < kvm_mmu_max_mapping_level(kvm, NULL, slot, sp->gfn)) { kvm_zap_one_rmap_spte(kvm, rmap_head, sptep); if (kvm_available_flush_remote_tlbs_range()) diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index 65f3c89d7c5d..b776be783a2f 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -411,7 +411,7 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, return r; } -int kvm_mmu_max_mapping_level(struct kvm *kvm, +int kvm_mmu_max_mapping_level(struct kvm *kvm, struct kvm_page_fault *fault, const struct kvm_memory_slot *slot, gfn_t gfn); void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault); void disallowed_hugepage_adjust(struct kvm_page_fault *fault, u64 spte, int cur_level); diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 7f3d7229b2c1..740cb06accdb 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -1813,7 +1813,7 @@ retry: if (iter.gfn < start || iter.gfn >= end) continue; - max_mapping_level = kvm_mmu_max_mapping_level(kvm, slot, iter.gfn); + max_mapping_level = kvm_mmu_max_mapping_level(kvm, NULL, slot, iter.gfn); if (max_mapping_level < iter.level) continue; From b7d97f69edd488b9755ba2858fe7f33e24566500 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 29 Jul 2025 15:54:46 -0700 Subject: [PATCH 0561/2711] KVM: x86/mmu: Extend guest_memfd's max mapping level to shared mappings Rework kvm_mmu_max_mapping_level() to consult guest_memfd for all mappings, not just private mappings, so that hugepage support plays nice with the upcoming support for backing non-private memory with guest_memfd. In addition to getting the max order from guest_memfd for gmem-only memslots, update TDX's hook to effectively ignore shared mappings, as TDX's restrictions on page size only apply to Secure EPT mappings. Do nothing for SNP, as RMP restrictions apply to both private and shared memory. Suggested-by: Ackerley Tng Signed-off-by: Sean Christopherson Reviewed-by: David Hildenbrand Reviewed-by: Fuad Tabba Reviewed-by: Xiaoyao Li Message-ID: <20250729225455.670324-16-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/mmu/mmu.c | 12 +++++++----- arch/x86/kvm/svm/sev.c | 2 +- arch/x86/kvm/svm/svm.h | 4 ++-- arch/x86/kvm/vmx/main.c | 5 +++-- arch/x86/kvm/vmx/tdx.c | 5 ++++- arch/x86/kvm/vmx/x86_ops.h | 2 +- 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index c0a739bf3829..c56cc54d682a 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1922,7 +1922,7 @@ struct kvm_x86_ops { void *(*alloc_apic_backing_page)(struct kvm_vcpu *vcpu); int (*gmem_prepare)(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order); void (*gmem_invalidate)(kvm_pfn_t start, kvm_pfn_t end); - int (*gmem_max_mapping_level)(struct kvm *kvm, kvm_pfn_t pfn); + int (*gmem_max_mapping_level)(struct kvm *kvm, kvm_pfn_t pfn, bool is_private); }; struct kvm_x86_nested_ops { diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 61eb9f723675..e83d666f32ad 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3302,8 +3302,9 @@ static u8 kvm_max_level_for_order(int order) return PG_LEVEL_4K; } -static u8 kvm_max_private_mapping_level(struct kvm *kvm, struct kvm_page_fault *fault, - const struct kvm_memory_slot *slot, gfn_t gfn) +static u8 kvm_gmem_max_mapping_level(struct kvm *kvm, struct kvm_page_fault *fault, + const struct kvm_memory_slot *slot, gfn_t gfn, + bool is_private) { u8 max_level, coco_level; kvm_pfn_t pfn; @@ -3327,7 +3328,7 @@ static u8 kvm_max_private_mapping_level(struct kvm *kvm, struct kvm_page_fault * * restrictions. A return of '0' means "no additional restrictions", to * allow for using an optional "ret0" static call. */ - coco_level = kvm_x86_call(gmem_max_mapping_level)(kvm, pfn); + coco_level = kvm_x86_call(gmem_max_mapping_level)(kvm, pfn, is_private); if (coco_level) max_level = min(max_level, coco_level); @@ -3361,8 +3362,9 @@ int kvm_mmu_max_mapping_level(struct kvm *kvm, struct kvm_page_fault *fault, if (max_level == PG_LEVEL_4K) return PG_LEVEL_4K; - if (is_private) - host_level = kvm_max_private_mapping_level(kvm, fault, slot, gfn); + if (is_private || kvm_memslot_is_gmem_only(slot)) + host_level = kvm_gmem_max_mapping_level(kvm, fault, slot, gfn, + is_private); else host_level = host_pfn_mapping_level(kvm, gfn, slot); return min(host_level, max_level); diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index b926a053b8cf..5bac4d20aec0 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -4943,7 +4943,7 @@ next_pfn: } } -int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) +int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, bool is_private) { int level, rc; bool assigned; diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index d84a83ae18a1..70df7c6413cf 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -866,7 +866,7 @@ void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code); void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu); int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order); void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end); -int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn); +int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, bool is_private); struct vmcb_save_area *sev_decrypt_vmsa(struct kvm_vcpu *vcpu); void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa); #else @@ -895,7 +895,7 @@ static inline int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, in return 0; } static inline void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end) {} -static inline int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) +static inline int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, bool is_private) { return 0; } diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c index dd7687ef7e2d..bb5f182f6788 100644 --- a/arch/x86/kvm/vmx/main.c +++ b/arch/x86/kvm/vmx/main.c @@ -831,10 +831,11 @@ static int vt_vcpu_mem_enc_ioctl(struct kvm_vcpu *vcpu, void __user *argp) return tdx_vcpu_ioctl(vcpu, argp); } -static int vt_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) +static int vt_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, + bool is_private) { if (is_td(kvm)) - return tdx_gmem_max_mapping_level(kvm, pfn); + return tdx_gmem_max_mapping_level(kvm, pfn, is_private); return 0; } diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index b444714e8e8a..ca9c8ec7dd01 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -3318,8 +3318,11 @@ int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp) return ret; } -int tdx_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn) +int tdx_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, bool is_private) { + if (!is_private) + return 0; + return PG_LEVEL_4K; } diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h index 6037d1708485..4c70f56c57c8 100644 --- a/arch/x86/kvm/vmx/x86_ops.h +++ b/arch/x86/kvm/vmx/x86_ops.h @@ -153,7 +153,7 @@ int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp); void tdx_flush_tlb_current(struct kvm_vcpu *vcpu); void tdx_flush_tlb_all(struct kvm_vcpu *vcpu); void tdx_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level); -int tdx_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn); +int tdx_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, bool is_private); #endif #endif /* __KVM_X86_VMX_X86_OPS_H */ From f029f04ddbec650d9830dbd5dc8c8998d1eef81e Mon Sep 17 00:00:00 2001 From: Ackerley Tng Date: Tue, 29 Jul 2025 15:54:47 -0700 Subject: [PATCH 0562/2711] KVM: x86/mmu: Handle guest page faults for guest_memfd with shared memory Update the KVM MMU fault handler to service guest page faults for memory slots backed by guest_memfd with mmap support. For such slots, the MMU must always fault in pages directly from guest_memfd, bypassing the host's userspace_addr. This ensures that guest_memfd-backed memory is always handled through the guest_memfd specific faulting path, regardless of whether it's for private or non-private (shared) use cases. Additionally, rename kvm_mmu_faultin_pfn_private() to kvm_mmu_faultin_pfn_gmem(), as this function is now used to fault in pages from guest_memfd for both private and non-private memory, accommodating the new use cases. Co-developed-by: David Hildenbrand Signed-off-by: David Hildenbrand Signed-off-by: Ackerley Tng Co-developed-by: Fuad Tabba Signed-off-by: Fuad Tabba [sean: drop the helper] Signed-off-by: Sean Christopherson Reviewed-by: Xiaoyao Li Message-ID: <20250729225455.670324-17-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index e83d666f32ad..56c80588efa0 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4561,8 +4561,8 @@ static void kvm_mmu_finish_page_fault(struct kvm_vcpu *vcpu, r == RET_PF_RETRY, fault->map_writable); } -static int kvm_mmu_faultin_pfn_private(struct kvm_vcpu *vcpu, - struct kvm_page_fault *fault) +static int kvm_mmu_faultin_pfn_gmem(struct kvm_vcpu *vcpu, + struct kvm_page_fault *fault) { int max_order, r; @@ -4589,8 +4589,8 @@ static int __kvm_mmu_faultin_pfn(struct kvm_vcpu *vcpu, { unsigned int foll = fault->write ? FOLL_WRITE : 0; - if (fault->is_private) - return kvm_mmu_faultin_pfn_private(vcpu, fault); + if (fault->is_private || kvm_memslot_is_gmem_only(fault->slot)) + return kvm_mmu_faultin_pfn_gmem(vcpu, fault); foll |= FOLL_NOWAIT; fault->pfn = __kvm_faultin_pfn(fault->slot, fault->gfn, foll, From 638ea79669f8a231c248cf9a13ea12e5dce745bf Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:48 -0700 Subject: [PATCH 0563/2711] KVM: arm64: Refactor user_mem_abort() Refactor user_mem_abort() to improve code clarity and simplify assumptions within the function. Key changes include: * Immediately set force_pte to true at the beginning of the function if logging_active is true. This simplifies the flow and makes the condition for forcing a PTE more explicit. * Remove the misleading comment stating that logging_active is guaranteed to never be true for VM_PFNMAP memslots, as this assertion is not entirely correct. * Extract reusable code blocks into new helper functions: * prepare_mmu_memcache(): Encapsulates the logic for preparing and topping up the MMU page cache. * adjust_nested_fault_perms(): Isolates the adjustments to shadow S2 permissions and the encoding of nested translation levels. * Update min(a, (long)b) to min_t(long, a, b) for better type safety and consistency. * Perform other minor tidying up of the code. These changes primarily aim to simplify user_mem_abort() and make its logic easier to understand and maintain, setting the stage for future modifications. Reviewed-by: Gavin Shan Reviewed-by: Marc Zyngier Reviewed-by: Tao Chan Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-18-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/kvm/mmu.c | 110 +++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 51 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 1c78864767c5..6ed69d309f45 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1477,13 +1477,56 @@ static bool kvm_vma_is_cacheable(struct vm_area_struct *vma) } } +static int prepare_mmu_memcache(struct kvm_vcpu *vcpu, bool topup_memcache, + void **memcache) +{ + int min_pages; + + if (!is_protected_kvm_enabled()) + *memcache = &vcpu->arch.mmu_page_cache; + else + *memcache = &vcpu->arch.pkvm_memcache; + + if (!topup_memcache) + return 0; + + min_pages = kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu); + + if (!is_protected_kvm_enabled()) + return kvm_mmu_topup_memory_cache(*memcache, min_pages); + + return topup_hyp_memcache(*memcache, min_pages); +} + +/* + * Potentially reduce shadow S2 permissions to match the guest's own S2. For + * exec faults, we'd only reach this point if the guest actually allowed it (see + * kvm_s2_handle_perm_fault). + * + * Also encode the level of the original translation in the SW bits of the leaf + * entry as a proxy for the span of that translation. This will be retrieved on + * TLB invalidation from the guest and used to limit the invalidation scope if a + * TTL hint or a range isn't provided. + */ +static void adjust_nested_fault_perms(struct kvm_s2_trans *nested, + enum kvm_pgtable_prot *prot, + bool *writable) +{ + *writable &= kvm_s2_trans_writable(nested); + if (!kvm_s2_trans_readable(nested)) + *prot &= ~KVM_PGTABLE_PROT_R; + + *prot |= kvm_encode_nested_level(nested); +} + static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, struct kvm_s2_trans *nested, struct kvm_memory_slot *memslot, unsigned long hva, bool fault_is_perm) { int ret = 0; - bool write_fault, writable, force_pte = false; + bool topup_memcache; + bool write_fault, writable; bool exec_fault, mte_allowed, is_vma_cacheable; bool s2_force_noncacheable = false, vfio_allow_any_uc = false; unsigned long mmu_seq; @@ -1495,6 +1538,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, gfn_t gfn; kvm_pfn_t pfn; bool logging_active = memslot_is_logging(memslot); + bool force_pte = logging_active; long vma_pagesize, fault_granule; enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R; struct kvm_pgtable *pgt; @@ -1506,17 +1550,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, fault_granule = kvm_vcpu_trap_get_perm_fault_granule(vcpu); write_fault = kvm_is_write_fault(vcpu); exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu); - VM_BUG_ON(write_fault && exec_fault); - - if (fault_is_perm && !write_fault && !exec_fault) { - kvm_err("Unexpected L2 read permission error\n"); - return -EFAULT; - } - - if (!is_protected_kvm_enabled()) - memcache = &vcpu->arch.mmu_page_cache; - else - memcache = &vcpu->arch.pkvm_memcache; + VM_WARN_ON_ONCE(write_fault && exec_fault); /* * Permission faults just need to update the existing leaf entry, @@ -1524,17 +1558,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, * only exception to this is when dirty logging is enabled at runtime * and a write fault needs to collapse a block entry into a table. */ - if (!fault_is_perm || (logging_active && write_fault)) { - int min_pages = kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu); - - if (!is_protected_kvm_enabled()) - ret = kvm_mmu_topup_memory_cache(memcache, min_pages); - else - ret = topup_hyp_memcache(memcache, min_pages); - - if (ret) - return ret; - } + topup_memcache = !fault_is_perm || (logging_active && write_fault); + ret = prepare_mmu_memcache(vcpu, topup_memcache, &memcache); + if (ret) + return ret; /* * Let's check if we will get back a huge page backed by hugetlbfs, or @@ -1548,16 +1575,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, return -EFAULT; } - /* - * logging_active is guaranteed to never be true for VM_PFNMAP - * memslots. - */ - if (logging_active) { - force_pte = true; + if (force_pte) vma_shift = PAGE_SHIFT; - } else { + else vma_shift = get_vma_page_shift(vma, hva); - } switch (vma_shift) { #ifndef __PAGETABLE_PMD_FOLDED @@ -1609,7 +1630,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, max_map_size = PAGE_SIZE; force_pte = (max_map_size == PAGE_SIZE); - vma_pagesize = min(vma_pagesize, (long)max_map_size); + vma_pagesize = min_t(long, vma_pagesize, max_map_size); } /* @@ -1642,7 +1663,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, * Rely on mmap_read_unlock() for an implicit smp_rmb(), which pairs * with the smp_wmb() in kvm_mmu_invalidate_end(). */ - mmu_seq = vcpu->kvm->mmu_invalidate_seq; + mmu_seq = kvm->mmu_invalidate_seq; mmap_read_unlock(current->mm); pfn = __kvm_faultin_pfn(memslot, gfn, write_fault ? FOLL_WRITE : 0, @@ -1698,24 +1719,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (exec_fault && s2_force_noncacheable) return -ENOEXEC; - /* - * Potentially reduce shadow S2 permissions to match the guest's own - * S2. For exec faults, we'd only reach this point if the guest - * actually allowed it (see kvm_s2_handle_perm_fault). - * - * Also encode the level of the original translation in the SW bits - * of the leaf entry as a proxy for the span of that translation. - * This will be retrieved on TLB invalidation from the guest and - * used to limit the invalidation scope if a TTL hint or a range - * isn't provided. - */ - if (nested) { - writable &= kvm_s2_trans_writable(nested); - if (!kvm_s2_trans_readable(nested)) - prot &= ~KVM_PGTABLE_PROT_R; - - prot |= kvm_encode_nested_level(nested); - } + if (nested) + adjust_nested_fault_perms(nested, &prot, &writable); kvm_fault_lock(kvm); pgt = vcpu->arch.hw_mmu->pgt; @@ -1981,6 +1986,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) goto out_unlock; } + VM_WARN_ON_ONCE(kvm_vcpu_trap_is_permission_fault(vcpu) && + !write_fault && !kvm_vcpu_trap_is_exec_fault(vcpu)); + ret = user_mem_abort(vcpu, fault_ipa, nested, memslot, hva, esr_fsc_is_permission_fault(esr)); if (ret == 0) From a7b57e0995927cc5fb8629594e2abf2a6f1000e9 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:49 -0700 Subject: [PATCH 0564/2711] KVM: arm64: Handle guest_memfd-backed guest page faults Add arm64 architecture support for handling guest page faults on memory slots backed by guest_memfd. This change introduces a new function, gmem_abort(), which encapsulates the fault handling logic specific to guest_memfd-backed memory. The kvm_handle_guest_abort() entry point is updated to dispatch to gmem_abort() when a fault occurs on a guest_memfd-backed memory slot (as determined by kvm_slot_has_gmem()). Until guest_memfd gains support for huge pages, the fault granule for these memory regions is restricted to PAGE_SIZE. Reviewed-by: Gavin Shan Reviewed-by: James Houghton Reviewed-by: Marc Zyngier Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-19-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/kvm/mmu.c | 86 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 6ed69d309f45..5d73abc9bebc 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1519,6 +1519,82 @@ static void adjust_nested_fault_perms(struct kvm_s2_trans *nested, *prot |= kvm_encode_nested_level(nested); } +#define KVM_PGTABLE_WALK_MEMABORT_FLAGS (KVM_PGTABLE_WALK_HANDLE_FAULT | KVM_PGTABLE_WALK_SHARED) + +static int gmem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + struct kvm_s2_trans *nested, + struct kvm_memory_slot *memslot, bool is_perm) +{ + bool write_fault, exec_fault, writable; + enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_MEMABORT_FLAGS; + enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R; + struct kvm_pgtable *pgt = vcpu->arch.hw_mmu->pgt; + unsigned long mmu_seq; + struct page *page; + struct kvm *kvm = vcpu->kvm; + void *memcache; + kvm_pfn_t pfn; + gfn_t gfn; + int ret; + + ret = prepare_mmu_memcache(vcpu, true, &memcache); + if (ret) + return ret; + + if (nested) + gfn = kvm_s2_trans_output(nested) >> PAGE_SHIFT; + else + gfn = fault_ipa >> PAGE_SHIFT; + + write_fault = kvm_is_write_fault(vcpu); + exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu); + + VM_WARN_ON_ONCE(write_fault && exec_fault); + + mmu_seq = kvm->mmu_invalidate_seq; + /* Pairs with the smp_wmb() in kvm_mmu_invalidate_end(). */ + smp_rmb(); + + ret = kvm_gmem_get_pfn(kvm, memslot, gfn, &pfn, &page, NULL); + if (ret) { + kvm_prepare_memory_fault_exit(vcpu, fault_ipa, PAGE_SIZE, + write_fault, exec_fault, false); + return ret; + } + + writable = !(memslot->flags & KVM_MEM_READONLY); + + if (nested) + adjust_nested_fault_perms(nested, &prot, &writable); + + if (writable) + prot |= KVM_PGTABLE_PROT_W; + + if (exec_fault || + (cpus_have_final_cap(ARM64_HAS_CACHE_DIC) && + (!nested || kvm_s2_trans_executable(nested)))) + prot |= KVM_PGTABLE_PROT_X; + + kvm_fault_lock(kvm); + if (mmu_invalidate_retry(kvm, mmu_seq)) { + ret = -EAGAIN; + goto out_unlock; + } + + ret = KVM_PGT_FN(kvm_pgtable_stage2_map)(pgt, fault_ipa, PAGE_SIZE, + __pfn_to_phys(pfn), prot, + memcache, flags); + +out_unlock: + kvm_release_faultin_page(kvm, page, !!ret, writable); + kvm_fault_unlock(kvm); + + if (writable && !ret) + mark_page_dirty_in_slot(kvm, memslot, gfn); + + return ret != -EAGAIN ? ret : 0; +} + static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, struct kvm_s2_trans *nested, struct kvm_memory_slot *memslot, unsigned long hva, @@ -1544,7 +1620,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, struct kvm_pgtable *pgt; struct page *page; vm_flags_t vm_flags; - enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_HANDLE_FAULT | KVM_PGTABLE_WALK_SHARED; + enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_MEMABORT_FLAGS; if (fault_is_perm) fault_granule = kvm_vcpu_trap_get_perm_fault_granule(vcpu); @@ -1989,8 +2065,12 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) VM_WARN_ON_ONCE(kvm_vcpu_trap_is_permission_fault(vcpu) && !write_fault && !kvm_vcpu_trap_is_exec_fault(vcpu)); - ret = user_mem_abort(vcpu, fault_ipa, nested, memslot, hva, - esr_fsc_is_permission_fault(esr)); + if (kvm_slot_has_gmem(memslot)) + ret = gmem_abort(vcpu, fault_ipa, nested, memslot, + esr_fsc_is_permission_fault(esr)); + else + ret = user_mem_abort(vcpu, fault_ipa, nested, memslot, hva, + esr_fsc_is_permission_fault(esr)); if (ret == 0) ret = 1; out: From f4e740309ee255a52a60bbc044647a11429250fc Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:50 -0700 Subject: [PATCH 0565/2711] KVM: arm64: nv: Handle VNCR_EL2-triggered faults backed by guest_memfd Handle faults for memslots backed by guest_memfd in arm64 nested virtualization triggered by VNCR_EL2. * Introduce is_gmem output parameter to kvm_translate_vncr(), indicating whether the faulted memory slot is backed by guest_memfd. * Dispatch faults backed by guest_memfd to kvm_gmem_get_pfn(). * Update kvm_handle_vncr_abort() to handle potential guest_memfd errors. Some of the guest_memfd errors need to be handled by userspace instead of attempting to (implicitly) retry by returning to the guest. Suggested-by: Marc Zyngier Reviewed-by: Marc Zyngier Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-20-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/kvm/nested.c | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 153b3e11b115..27ebcae35299 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1172,8 +1172,9 @@ static u64 read_vncr_el2(struct kvm_vcpu *vcpu) return (u64)sign_extend64(__vcpu_sys_reg(vcpu, VNCR_EL2), 48); } -static int kvm_translate_vncr(struct kvm_vcpu *vcpu) +static int kvm_translate_vncr(struct kvm_vcpu *vcpu, bool *is_gmem) { + struct kvm_memory_slot *memslot; bool write_fault, writable; unsigned long mmu_seq; struct vncr_tlb *vt; @@ -1216,10 +1217,25 @@ static int kvm_translate_vncr(struct kvm_vcpu *vcpu) smp_rmb(); gfn = vt->wr.pa >> PAGE_SHIFT; - pfn = kvm_faultin_pfn(vcpu, gfn, write_fault, &writable, &page); - if (is_error_noslot_pfn(pfn) || (write_fault && !writable)) + memslot = gfn_to_memslot(vcpu->kvm, gfn); + if (!memslot) return -EFAULT; + *is_gmem = kvm_slot_has_gmem(memslot); + if (!*is_gmem) { + pfn = __kvm_faultin_pfn(memslot, gfn, write_fault ? FOLL_WRITE : 0, + &writable, &page); + if (is_error_noslot_pfn(pfn) || (write_fault && !writable)) + return -EFAULT; + } else { + ret = kvm_gmem_get_pfn(vcpu->kvm, memslot, gfn, &pfn, &page, NULL); + if (ret) { + kvm_prepare_memory_fault_exit(vcpu, vt->wr.pa, PAGE_SIZE, + write_fault, false, false); + return ret; + } + } + scoped_guard(write_lock, &vcpu->kvm->mmu_lock) { if (mmu_invalidate_retry(vcpu->kvm, mmu_seq)) return -EAGAIN; @@ -1292,23 +1308,36 @@ int kvm_handle_vncr_abort(struct kvm_vcpu *vcpu) if (esr_fsc_is_permission_fault(esr)) { inject_vncr_perm(vcpu); } else if (esr_fsc_is_translation_fault(esr)) { - bool valid; + bool valid, is_gmem = false; int ret; scoped_guard(read_lock, &vcpu->kvm->mmu_lock) valid = kvm_vncr_tlb_lookup(vcpu); if (!valid) - ret = kvm_translate_vncr(vcpu); + ret = kvm_translate_vncr(vcpu, &is_gmem); else ret = -EPERM; switch (ret) { case -EAGAIN: - case -ENOMEM: /* Let's try again... */ break; + case -ENOMEM: + /* + * For guest_memfd, this indicates that it failed to + * create a folio to back the memory. Inform userspace. + */ + if (is_gmem) + return 0; + /* Otherwise, let's try again... */ + break; case -EFAULT: + case -EIO: + case -EHWPOISON: + if (is_gmem) + return 0; + fallthrough; case -EINVAL: case -ENOENT: case -EACCES: From 32e200bd6e4407c31aef0392be041274bfa3f20e Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:51 -0700 Subject: [PATCH 0566/2711] KVM: arm64: Enable support for guest_memfd backed memory Now that the infrastructure is in place, enable guest_memfd for arm64. * Select CONFIG_KVM_GUEST_MEMFD in KVM/arm64 Kconfig. * Enforce KVM_MEMSLOT_GMEM_ONLY for guest_memfd on arm64: Ensure that guest_memfd-backed memory slots on arm64 are only supported if they are intended for shared memory use cases (i.e., kvm_memslot_is_gmem_only() is true). This design reflects the current arm64 KVM ecosystem where guest_memfd is primarily being introduced for VMs that support shared memory. Reviewed-by: James Houghton Reviewed-by: Gavin Shan Reviewed-by: Marc Zyngier Acked-by: David Hildenbrand Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-21-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/kvm/Kconfig | 1 + arch/arm64/kvm/mmu.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 713248f240e0..bff62e75d681 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -37,6 +37,7 @@ menuconfig KVM select HAVE_KVM_VCPU_RUN_PID_CHANGE select SCHED_INFO select GUEST_PERF_EVENTS if PERF_EVENTS + select KVM_GUEST_MEMFD help Support hosting virtualized guest machines. diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 5d73abc9bebc..a36426ccd9b5 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -2302,6 +2302,13 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, if ((new->base_gfn + new->npages) > (kvm_phys_size(&kvm->arch.mmu) >> PAGE_SHIFT)) return -EFAULT; + /* + * Only support guest_memfd backed memslots with mappable memory, since + * there aren't any CoCo VMs that support only private memory on arm64. + */ + if (kvm_slot_has_gmem(new) && !kvm_memslot_is_gmem_only(new)) + return -EINVAL; + hva = new->userspace_addr; reg_end = hva + (new->npages << PAGE_SHIFT); From 3d3a04fad25a6621828518a2abe536142d2c1a7d Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:52 -0700 Subject: [PATCH 0567/2711] KVM: Allow and advertise support for host mmap() on guest_memfd files Now that all the x86 and arm64 plumbing for mmap() on guest_memfd is in place, allow userspace to set GUEST_MEMFD_FLAG_MMAP and advertise support via a new capability, KVM_CAP_GUEST_MEMFD_MMAP. The availability of this capability is determined per architecture, and its enablement for a specific guest_memfd instance is controlled by the GUEST_MEMFD_FLAG_MMAP flag at creation time. Update the KVM API documentation to detail the KVM_CAP_GUEST_MEMFD_MMAP capability, the associated GUEST_MEMFD_FLAG_MMAP, and provide essential information regarding support for mmap in guest_memfd. Reviewed-by: David Hildenbrand Reviewed-by: Gavin Shan Reviewed-by: Shivank Garg Reviewed-by: Xiaoyao Li Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-22-seanjc@google.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 9 +++++++++ include/uapi/linux/kvm.h | 2 ++ virt/kvm/guest_memfd.c | 7 ++++++- virt/kvm/kvm_main.c | 2 ++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 6aa40ee05a4a..c17a87a0a5ac 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6414,6 +6414,15 @@ most one mapping per page, i.e. binding multiple memory regions to a single guest_memfd range is not allowed (any number of memory regions can be bound to a single guest_memfd file, but the bound ranges must not overlap). +When the capability KVM_CAP_GUEST_MEMFD_MMAP is supported, the 'flags' field +supports GUEST_MEMFD_FLAG_MMAP. Setting this flag on guest_memfd creation +enables mmap() and faulting of guest_memfd memory to host userspace. + +When the KVM MMU performs a PFN lookup to service a guest fault and the backing +guest_memfd has the GUEST_MEMFD_FLAG_MMAP set, then the fault will always be +consumed from guest_memfd, regardless of whether it is a shared or a private +fault. + See KVM_SET_USER_MEMORY_REGION2 for additional details. 4.143 KVM_PRE_FAULT_MEMORY diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index f0f0d49d2544..6efa98a57ec1 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -962,6 +962,7 @@ struct kvm_enable_cap { #define KVM_CAP_ARM_EL2_E2H0 241 #define KVM_CAP_RISCV_MP_STATE_RESET 242 #define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243 +#define KVM_CAP_GUEST_MEMFD_MMAP 244 struct kvm_irq_routing_irqchip { __u32 irqchip; @@ -1598,6 +1599,7 @@ struct kvm_memory_attributes { #define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3) #define KVM_CREATE_GUEST_MEMFD _IOWR(KVMIO, 0xd4, struct kvm_create_guest_memfd) +#define GUEST_MEMFD_FLAG_MMAP (1ULL << 0) struct kvm_create_guest_memfd { __u64 size; diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c index d5b445548af4..08a6bc7d25b6 100644 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@ -314,7 +314,9 @@ static pgoff_t kvm_gmem_get_index(struct kvm_memory_slot *slot, gfn_t gfn) static bool kvm_gmem_supports_mmap(struct inode *inode) { - return false; + const u64 flags = (u64)inode->i_private; + + return flags & GUEST_MEMFD_FLAG_MMAP; } static vm_fault_t kvm_gmem_fault_user_mapping(struct vm_fault *vmf) @@ -522,6 +524,9 @@ int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args) u64 flags = args->flags; u64 valid_flags = 0; + if (kvm_arch_supports_gmem_mmap(kvm)) + valid_flags |= GUEST_MEMFD_FLAG_MMAP; + if (flags & ~valid_flags) return -EINVAL; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 4f57cb92e109..18f29ef93543 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -4918,6 +4918,8 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg) #ifdef CONFIG_KVM_GUEST_MEMFD case KVM_CAP_GUEST_MEMFD: return 1; + case KVM_CAP_GUEST_MEMFD_MMAP: + return !kvm || kvm_arch_supports_gmem_mmap(kvm); #endif default: break; From 692f6ecf387aff1596ea1d86be7d333a474b7d56 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:53 -0700 Subject: [PATCH 0568/2711] KVM: selftests: Do not use hardcoded page sizes in guest_memfd test Update the guest_memfd_test selftest to use getpagesize() instead of hardcoded 4KB page size values. Using hardcoded page sizes can cause test failures on architectures or systems configured with larger page sizes, such as arm64 with 64KB pages. By dynamically querying the system's page size, the test becomes more portable and robust across different environments. Additionally, build the guest_memfd_test selftest for arm64. Reviewed-by: David Hildenbrand Reviewed-by: Shivank Garg Reviewed-by: Gavin Shan Suggested-by: Gavin Shan Signed-off-by: Fuad Tabba Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-23-seanjc@google.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/Makefile.kvm | 1 + tools/testing/selftests/kvm/guest_memfd_test.c | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index f6fe7a07a0a2..90f03f00cb04 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -174,6 +174,7 @@ TEST_GEN_PROGS_arm64 += arch_timer TEST_GEN_PROGS_arm64 += coalesced_io_test TEST_GEN_PROGS_arm64 += dirty_log_perf_test TEST_GEN_PROGS_arm64 += get-reg-list +TEST_GEN_PROGS_arm64 += guest_memfd_test TEST_GEN_PROGS_arm64 += memslot_modification_stress_test TEST_GEN_PROGS_arm64 += memslot_perf_test TEST_GEN_PROGS_arm64 += mmu_stress_test diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c index ce687f8d248f..341ba616cf55 100644 --- a/tools/testing/selftests/kvm/guest_memfd_test.c +++ b/tools/testing/selftests/kvm/guest_memfd_test.c @@ -146,24 +146,25 @@ static void test_create_guest_memfd_multiple(struct kvm_vm *vm) { int fd1, fd2, ret; struct stat st1, st2; + size_t page_size = getpagesize(); - fd1 = __vm_create_guest_memfd(vm, 4096, 0); + fd1 = __vm_create_guest_memfd(vm, page_size, 0); TEST_ASSERT(fd1 != -1, "memfd creation should succeed"); ret = fstat(fd1, &st1); TEST_ASSERT(ret != -1, "memfd fstat should succeed"); - TEST_ASSERT(st1.st_size == 4096, "memfd st_size should match requested size"); + TEST_ASSERT(st1.st_size == page_size, "memfd st_size should match requested size"); - fd2 = __vm_create_guest_memfd(vm, 8192, 0); + fd2 = __vm_create_guest_memfd(vm, page_size * 2, 0); TEST_ASSERT(fd2 != -1, "memfd creation should succeed"); ret = fstat(fd2, &st2); TEST_ASSERT(ret != -1, "memfd fstat should succeed"); - TEST_ASSERT(st2.st_size == 8192, "second memfd st_size should match requested size"); + TEST_ASSERT(st2.st_size == page_size * 2, "second memfd st_size should match requested size"); ret = fstat(fd1, &st1); TEST_ASSERT(ret != -1, "memfd fstat should succeed"); - TEST_ASSERT(st1.st_size == 4096, "first memfd st_size should still match requested size"); + TEST_ASSERT(st1.st_size == page_size, "first memfd st_size should still match requested size"); TEST_ASSERT(st1.st_ino != st2.st_ino, "different memfd should have different inode numbers"); close(fd2); From a11d7124b4dd4d78bb7f7257abdb33cb5dd924b8 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 29 Jul 2025 15:54:54 -0700 Subject: [PATCH 0569/2711] KVM: selftests: guest_memfd mmap() test when mmap is supported Expand the guest_memfd selftests to comprehensively test host userspace mmap functionality for guest_memfd-backed memory when supported by the VM type. Introduce new test cases to verify the following: * Successful mmap operations: Ensure that MAP_SHARED mappings succeed when guest_memfd mmap is enabled. * Data integrity: Validate that data written to the mmap'd region is correctly persistent and readable. * fallocate interaction: Test that fallocate(FALLOC_FL_PUNCH_HOLE) correctly zeros out mapped pages. * Out-of-bounds access: Verify that accessing memory beyond the guest_memfd's size correctly triggers a SIGBUS signal. * Unsupported mmap: Confirm that mmap attempts fail as expected when guest_memfd mmap support is not enabled for the specific guest_memfd instance or VM type. * Flag validity: Introduce test_vm_type_gmem_flag_validity() to systematically test that only allowed guest_memfd creation flags are accepted for different VM types (e.g., GUEST_MEMFD_FLAG_MMAP for default VMs, no flags for CoCo VMs). The existing tests for guest_memfd creation (multiple instances, invalid sizes), file read/write, file size, and invalid punch hole operations are integrated into the new test_with_type() framework to allow testing across different VM types. Cc: James Houghton Cc: Gavin Shan Cc: Shivank Garg Co-developed-by: Ackerley Tng Signed-off-by: Ackerley Tng Signed-off-by: Fuad Tabba Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-24-seanjc@google.com> [Fix default vm_types to use BIT() - Paolo] Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/guest_memfd_test.c | 161 +++++++++++++++--- 1 file changed, 139 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c index 341ba616cf55..b88f580b2fd6 100644 --- a/tools/testing/selftests/kvm/guest_memfd_test.c +++ b/tools/testing/selftests/kvm/guest_memfd_test.c @@ -13,6 +13,8 @@ #include #include +#include +#include #include #include #include @@ -34,12 +36,83 @@ static void test_file_read_write(int fd) "pwrite on a guest_mem fd should fail"); } -static void test_mmap(int fd, size_t page_size) +static void test_mmap_supported(int fd, size_t page_size, size_t total_size) +{ + const char val = 0xaa; + char *mem; + size_t i; + int ret; + + mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + TEST_ASSERT(mem == MAP_FAILED, "Copy-on-write not allowed by guest_memfd."); + + mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + TEST_ASSERT(mem != MAP_FAILED, "mmap() for guest_memfd should succeed."); + + memset(mem, val, total_size); + for (i = 0; i < total_size; i++) + TEST_ASSERT_EQ(READ_ONCE(mem[i]), val); + + ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, + page_size); + TEST_ASSERT(!ret, "fallocate the first page should succeed."); + + for (i = 0; i < page_size; i++) + TEST_ASSERT_EQ(READ_ONCE(mem[i]), 0x00); + for (; i < total_size; i++) + TEST_ASSERT_EQ(READ_ONCE(mem[i]), val); + + memset(mem, val, page_size); + for (i = 0; i < total_size; i++) + TEST_ASSERT_EQ(READ_ONCE(mem[i]), val); + + ret = munmap(mem, total_size); + TEST_ASSERT(!ret, "munmap() should succeed."); +} + +static sigjmp_buf jmpbuf; +void fault_sigbus_handler(int signum) +{ + siglongjmp(jmpbuf, 1); +} + +static void test_fault_overflow(int fd, size_t page_size, size_t total_size) +{ + struct sigaction sa_old, sa_new = { + .sa_handler = fault_sigbus_handler, + }; + size_t map_size = total_size * 4; + const char val = 0xaa; + char *mem; + size_t i; + int ret; + + mem = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + TEST_ASSERT(mem != MAP_FAILED, "mmap() for guest_memfd should succeed."); + + sigaction(SIGBUS, &sa_new, &sa_old); + if (sigsetjmp(jmpbuf, 1) == 0) { + memset(mem, 0xaa, map_size); + TEST_ASSERT(false, "memset() should have triggered SIGBUS."); + } + sigaction(SIGBUS, &sa_old, NULL); + + for (i = 0; i < total_size; i++) + TEST_ASSERT_EQ(READ_ONCE(mem[i]), val); + + ret = munmap(mem, map_size); + TEST_ASSERT(!ret, "munmap() should succeed."); +} + +static void test_mmap_not_supported(int fd, size_t page_size, size_t total_size) { char *mem; mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); TEST_ASSERT_EQ(mem, MAP_FAILED); + + mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + TEST_ASSERT_EQ(mem, MAP_FAILED); } static void test_file_size(int fd, size_t page_size, size_t total_size) @@ -120,26 +193,19 @@ static void test_invalid_punch_hole(int fd, size_t page_size, size_t total_size) } } -static void test_create_guest_memfd_invalid(struct kvm_vm *vm) +static void test_create_guest_memfd_invalid_sizes(struct kvm_vm *vm, + uint64_t guest_memfd_flags, + size_t page_size) { - size_t page_size = getpagesize(); - uint64_t flag; size_t size; int fd; for (size = 1; size < page_size; size++) { - fd = __vm_create_guest_memfd(vm, size, 0); - TEST_ASSERT(fd == -1 && errno == EINVAL, + fd = __vm_create_guest_memfd(vm, size, guest_memfd_flags); + TEST_ASSERT(fd < 0 && errno == EINVAL, "guest_memfd() with non-page-aligned page size '0x%lx' should fail with EINVAL", size); } - - for (flag = BIT(0); flag; flag <<= 1) { - fd = __vm_create_guest_memfd(vm, page_size, flag); - TEST_ASSERT(fd == -1 && errno == EINVAL, - "guest_memfd() with flag '0x%lx' should fail with EINVAL", - flag); - } } static void test_create_guest_memfd_multiple(struct kvm_vm *vm) @@ -171,30 +237,81 @@ static void test_create_guest_memfd_multiple(struct kvm_vm *vm) close(fd1); } -int main(int argc, char *argv[]) +static void test_guest_memfd_flags(struct kvm_vm *vm, uint64_t valid_flags) { - size_t page_size; - size_t total_size; + size_t page_size = getpagesize(); + uint64_t flag; int fd; - struct kvm_vm *vm; - TEST_REQUIRE(kvm_has_cap(KVM_CAP_GUEST_MEMFD)); + for (flag = BIT(0); flag; flag <<= 1) { + fd = __vm_create_guest_memfd(vm, page_size, flag); + if (flag & valid_flags) { + TEST_ASSERT(fd >= 0, + "guest_memfd() with flag '0x%lx' should succeed", + flag); + close(fd); + } else { + TEST_ASSERT(fd < 0 && errno == EINVAL, + "guest_memfd() with flag '0x%lx' should fail with EINVAL", + flag); + } + } +} + +static void test_guest_memfd(unsigned long vm_type) +{ + uint64_t flags = 0; + struct kvm_vm *vm; + size_t total_size; + size_t page_size; + int fd; page_size = getpagesize(); total_size = page_size * 4; - vm = vm_create_barebones(); + vm = vm_create_barebones_type(vm_type); + + if (vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_MMAP)) + flags |= GUEST_MEMFD_FLAG_MMAP; - test_create_guest_memfd_invalid(vm); test_create_guest_memfd_multiple(vm); + test_create_guest_memfd_invalid_sizes(vm, flags, page_size); - fd = vm_create_guest_memfd(vm, total_size, 0); + fd = vm_create_guest_memfd(vm, total_size, flags); test_file_read_write(fd); - test_mmap(fd, page_size); + + if (flags & GUEST_MEMFD_FLAG_MMAP) { + test_mmap_supported(fd, page_size, total_size); + test_fault_overflow(fd, page_size, total_size); + } else { + test_mmap_not_supported(fd, page_size, total_size); + } + test_file_size(fd, page_size, total_size); test_fallocate(fd, page_size, total_size); test_invalid_punch_hole(fd, page_size, total_size); + test_guest_memfd_flags(vm, flags); + close(fd); + kvm_vm_free(vm); +} + +int main(int argc, char *argv[]) +{ + unsigned long vm_types, vm_type; + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_GUEST_MEMFD)); + + /* + * Not all architectures support KVM_CAP_VM_TYPES. However, those that + * support guest_memfd have that support for the default VM type. + */ + vm_types = kvm_check_cap(KVM_CAP_VM_TYPES); + if (!vm_types) + vm_types = BIT(VM_TYPE_DEFAULT); + + for_each_set_bit(vm_type, &vm_types, BITS_PER_TYPE(vm_types)) + test_guest_memfd(vm_type); } From 42188667be387867d2bf763d028654cbad046f7b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 29 Jul 2025 15:54:55 -0700 Subject: [PATCH 0570/2711] KVM: selftests: Add guest_memfd testcase to fault-in on !mmap()'d memory Add a guest_memfd testcase to verify that a vCPU can fault-in guest_memfd memory that supports mmap(), but that is not currently mapped into host userspace and/or has a userspace address (in the memslot) that points at something other than the target guest_memfd range. Mapping guest_memfd memory into the guest is supposed to operate completely independently from any userspace mappings. Signed-off-by: Sean Christopherson Message-ID: <20250729225455.670324-25-seanjc@google.com> Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/guest_memfd_test.c | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c index b88f580b2fd6..b3ca6737f304 100644 --- a/tools/testing/selftests/kvm/guest_memfd_test.c +++ b/tools/testing/selftests/kvm/guest_memfd_test.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include "kvm_util.h" #include "test_util.h" +#include "ucall_common.h" static void test_file_read_write(int fd) { @@ -298,6 +300,66 @@ static void test_guest_memfd(unsigned long vm_type) kvm_vm_free(vm); } +static void guest_code(uint8_t *mem, uint64_t size) +{ + size_t i; + + for (i = 0; i < size; i++) + __GUEST_ASSERT(mem[i] == 0xaa, + "Guest expected 0xaa at offset %lu, got 0x%x", i, mem[i]); + + memset(mem, 0xff, size); + GUEST_DONE(); +} + +static void test_guest_memfd_guest(void) +{ + /* + * Skip the first 4gb and slot0. slot0 maps <1gb and is used to back + * the guest's code, stack, and page tables, and low memory contains + * the PCI hole and other MMIO regions that need to be avoided. + */ + const uint64_t gpa = SZ_4G; + const int slot = 1; + + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + uint8_t *mem; + size_t size; + int fd, i; + + if (!kvm_has_cap(KVM_CAP_GUEST_MEMFD_MMAP)) + return; + + vm = __vm_create_shape_with_one_vcpu(VM_SHAPE_DEFAULT, &vcpu, 1, guest_code); + + TEST_ASSERT(vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_MMAP), + "Default VM type should always support guest_memfd mmap()"); + + size = vm->page_size; + fd = vm_create_guest_memfd(vm, size, GUEST_MEMFD_FLAG_MMAP); + vm_set_user_memory_region2(vm, slot, KVM_MEM_GUEST_MEMFD, gpa, size, NULL, fd, 0); + + mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + TEST_ASSERT(mem != MAP_FAILED, "mmap() on guest_memfd failed"); + memset(mem, 0xaa, size); + munmap(mem, size); + + virt_pg_map(vm, gpa, gpa); + vcpu_args_set(vcpu, 2, gpa, size); + vcpu_run(vcpu); + + TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); + + mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + TEST_ASSERT(mem != MAP_FAILED, "mmap() on guest_memfd failed"); + for (i = 0; i < size; i++) + TEST_ASSERT_EQ(mem[i], 0xff); + + close(fd); + kvm_vm_free(vm); +} + int main(int argc, char *argv[]) { unsigned long vm_types, vm_type; @@ -314,4 +376,6 @@ int main(int argc, char *argv[]) for_each_set_bit(vm_type, &vm_types, BITS_PER_TYPE(vm_types)) test_guest_memfd(vm_type); + + test_guest_memfd_guest(); } From 4edc575c5582550d0905f39c5e27f1f1f925fffa Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 18 Aug 2025 16:21:39 +0200 Subject: [PATCH 0571/2711] dt-bindings: PCI: Correct example indentation DTS example in the bindings should be indented with 2- or 4-spaces, so correct a mixture of different styles to keep consistent 4-spaces. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Manivannan Sadhasivam Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250818142138.129327-2-krzysztof.kozlowski@linaro.org --- .../bindings/pci/amd,versal2-mdb-host.yaml | 2 +- .../bindings/pci/qcom,pcie-sa8255p.yaml | 74 +++++++++---------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/amd,versal2-mdb-host.yaml b/Documentation/devicetree/bindings/pci/amd,versal2-mdb-host.yaml index 43dc2585c237..80b28c4212df 100644 --- a/Documentation/devicetree/bindings/pci/amd,versal2-mdb-host.yaml +++ b/Documentation/devicetree/bindings/pci/amd,versal2-mdb-host.yaml @@ -116,6 +116,6 @@ examples: #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; - }; + }; }; }; diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sa8255p.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sa8255p.yaml index ef705a02fcd9..bdddd4f499d1 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sa8255p.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sa8255p.yaml @@ -77,46 +77,46 @@ examples: #size-cells = <2>; pci@1c00000 { - compatible = "qcom,pcie-sa8255p"; - reg = <0x4 0x00000000 0 0x10000000>; - device_type = "pci"; - #address-cells = <3>; - #size-cells = <2>; - ranges = <0x02000000 0x0 0x40100000 0x0 0x40100000 0x0 0x1ff00000>, - <0x43000000 0x4 0x10100000 0x4 0x10100000 0x0 0x40000000>; - bus-range = <0x00 0xff>; - dma-coherent; - linux,pci-domain = <0>; - power-domains = <&scmi5_pd 0>; - iommu-map = <0x0 &pcie_smmu 0x0000 0x1>, - <0x100 &pcie_smmu 0x0001 0x1>; - interrupt-parent = <&intc>; - interrupts = , - , - , - , - , - , - , - ; - interrupt-names = "msi0", "msi1", "msi2", "msi3", - "msi4", "msi5", "msi6", "msi7"; + compatible = "qcom,pcie-sa8255p"; + reg = <0x4 0x00000000 0 0x10000000>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x02000000 0x0 0x40100000 0x0 0x40100000 0x0 0x1ff00000>, + <0x43000000 0x4 0x10100000 0x4 0x10100000 0x0 0x40000000>; + bus-range = <0x00 0xff>; + dma-coherent; + linux,pci-domain = <0>; + power-domains = <&scmi5_pd 0>; + iommu-map = <0x0 &pcie_smmu 0x0000 0x1>, + <0x100 &pcie_smmu 0x0001 0x1>; + interrupt-parent = <&intc>; + interrupts = , + , + , + , + , + , + , + ; + interrupt-names = "msi0", "msi1", "msi2", "msi3", + "msi4", "msi5", "msi6", "msi7"; - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 0x7>; - interrupt-map = <0 0 0 1 &intc GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 2 &intc GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 3 &intc GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 4 &intc GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>; - pcie@0 { - device_type = "pci"; - reg = <0x0 0x0 0x0 0x0 0x0>; - bus-range = <0x01 0xff>; + pcie@0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + bus-range = <0x01 0xff>; - #address-cells = <3>; - #size-cells = <2>; - ranges; + #address-cells = <3>; + #size-cells = <2>; + ranges; }; }; }; From cc8e391067164f45f89b6132a5aaa18c33a0e32b Mon Sep 17 00:00:00 2001 From: Christian Bruel Date: Mon, 4 Aug 2025 19:09:14 +0200 Subject: [PATCH 0572/2711] misc: pci_endpoint_test: Skip IRQ tests if irq is out of range The pci_endpoint_test tests the 32-bit MSI range. However, the device might not have all vectors configured. For example, if msi_interrupts is 8 in the ep function space or if the MSI Multiple Message Capable value is configured as 4 (maximum 16 vectors). In this case, do not attempt to run the test to avoid timeouts and directly return the error value. Signed-off-by: Christian Bruel Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250804170916.3212221-2-christian.bruel@foss.st.com --- drivers/misc/pci_endpoint_test.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index f935175d8bf5..506a2847e5d2 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -436,7 +436,11 @@ static int pci_endpoint_test_msi_irq(struct pci_endpoint_test *test, { struct pci_dev *pdev = test->pdev; u32 val; - int ret; + int irq; + + irq = pci_irq_vector(pdev, msi_num - 1); + if (irq < 0) + return irq; pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, msix ? PCITEST_IRQ_TYPE_MSIX : @@ -450,11 +454,7 @@ static int pci_endpoint_test_msi_irq(struct pci_endpoint_test *test, if (!val) return -ETIMEDOUT; - ret = pci_irq_vector(pdev, msi_num - 1); - if (ret < 0) - return ret; - - if (ret != test->last_irq) + if (irq != test->last_irq) return -EIO; return 0; From 384b1b29481e39aae8eb01240d1edf287c7a4145 Mon Sep 17 00:00:00 2001 From: Christian Bruel Date: Mon, 4 Aug 2025 19:09:15 +0200 Subject: [PATCH 0573/2711] misc: pci_endpoint_test: Cleanup extra 0 initialization Initialization is not needed as memory is already set to 0 by devm_kzalloc. Signed-off-by: Christian Bruel [mani: reworded description] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250804170916.3212221-3-christian.bruel@foss.st.com --- drivers/misc/pci_endpoint_test.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 506a2847e5d2..1c0fd185114f 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -1020,8 +1020,6 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, if (!test) return -ENOMEM; - test->test_reg_bar = 0; - test->alignment = 0; test->pdev = pdev; test->irq_type = PCITEST_IRQ_TYPE_UNDEFINED; From 106fc08b30a2ece49a251b053165a83d41d50fd0 Mon Sep 17 00:00:00 2001 From: Christian Bruel Date: Mon, 4 Aug 2025 19:09:16 +0200 Subject: [PATCH 0574/2711] selftests: pci_endpoint: Skip IRQ test if IRQ is out of range. The pci_endpoint_test tests the entire MSI/MSI-X range, which generates false errors on platforms that do not support the whole range. Skip the test in such cases and report accordingly. Signed-off-by: Christian Bruel [mani: reworded description] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250804170916.3212221-4-christian.bruel@foss.st.com --- tools/testing/selftests/pci_endpoint/pci_endpoint_test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c b/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c index da0db0e7c969..cd9075444c32 100644 --- a/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c +++ b/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c @@ -121,6 +121,8 @@ TEST_F(pci_ep_basic, MSI_TEST) for (i = 1; i <= 32; i++) { pci_ep_ioctl(PCITEST_MSI, i); + if (ret == -EINVAL) + SKIP(return, "MSI%d is disabled", i); EXPECT_FALSE(ret) TH_LOG("Test failed for MSI%d", i); } } @@ -137,6 +139,8 @@ TEST_F(pci_ep_basic, MSIX_TEST) for (i = 1; i <= 2048; i++) { pci_ep_ioctl(PCITEST_MSIX, i); + if (ret == -EINVAL) + SKIP(return, "MSI-X%d is disabled", i); EXPECT_FALSE(ret) TH_LOG("Test failed for MSI-X%d", i); } } From 272dad3f84004079328e8f36b2292e7297460ffd Mon Sep 17 00:00:00 2001 From: Christian Bruel Date: Wed, 20 Aug 2025 09:54:01 +0200 Subject: [PATCH 0575/2711] Documentation: pinctrl: Describe PM helper functions for standard states. Clarify documentation for predefined standard state names 'default', 'init', 'sleep', 'idle' and their associated PM API. Signed-off-by: Christian Bruel Signed-off-by: Manivannan Sadhasivam Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20250820075411.1178729-2-christian.bruel@foss.st.com --- Documentation/driver-api/pin-control.rst | 57 +++++++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/pin-control.rst b/Documentation/driver-api/pin-control.rst index 27ea1236307e..204cc3e162e2 100644 --- a/Documentation/driver-api/pin-control.rst +++ b/Documentation/driver-api/pin-control.rst @@ -1162,8 +1162,55 @@ pinmux core. Pin control requests from drivers ================================= -When a device driver is about to probe the device core will automatically -attempt to issue ``pinctrl_get_select_default()`` on these devices. +When a device driver is about to probe, the device core attaches the +standard states if they are defined in the device tree by calling +``pinctrl_bind_pins()`` on these devices. +Possible standard state names are: "default", "init", "sleep" and "idle". + +- if ``default`` is defined in the device tree, it is selected before + device probe. + +- if ``init`` and ``default`` are defined in the device tree, the "init" + state is selected before the driver probe and the "default" state is + selected after the driver probe. + +- the ``sleep`` and ``idle`` states are for power management and can only + be selected with the PM API bellow. + +PM interfaces +================= +PM runtime suspend/resume might need to execute the same init sequence as +during probe. Since the predefined states are already attached to the +device, the driver can activate these states explicitly with the +following helper functions: + +- ``pinctrl_pm_select_default_state()`` +- ``pinctrl_pm_select_init_state()`` +- ``pinctrl_pm_select_sleep_state()`` +- ``pinctrl_pm_select_idle_state()`` + +For example, if resuming the device depend on certain pinmux states + +.. code-block:: c + + foo_suspend() + { + /* suspend device */ + ... + + pinctrl_pm_select_sleep_state(dev); + } + + foo_resume() + { + pinctrl_pm_select_init_state(dev); + + /* resuming device */ + ... + + pinctrl_pm_select_default_state(dev); + } + This way driver writers do not need to add any of the boilerplate code of the type found below. However when doing fine-grained state selection and not using the "default" state, you may have to do some device driver @@ -1185,6 +1232,12 @@ operation and going to sleep, moving from the ``PINCTRL_STATE_DEFAULT`` to ``PINCTRL_STATE_SLEEP`` at runtime, re-biasing or even re-muxing pins to save current in sleep mode. +Another case is when the pinctrl needs to switch to a certain mode during +probe and then revert to the default state at the end of probe. For example +a PINMUX may need to be configured as a GPIO during probe. In this case, use +``PINCTRL_STATE_INIT`` to switch state before probe, then move to +``PINCTRL_STATE_DEFAULT`` at the end of probe for normal operation. + A driver may request a certain control state to be activated, usually just the default state like this: From 08383cd479f8212fafee2f557b58cfd48818bee0 Mon Sep 17 00:00:00 2001 From: Christian Bruel Date: Wed, 20 Aug 2025 09:54:02 +0200 Subject: [PATCH 0576/2711] pinctrl: Add pinctrl_pm_select_init_state helper function If a platform requires an initial pinctrl state during probing, this helper function provides the client with access to the same initial state. eg: xxx_suspend_noirq ... pinctrl_pm_select_sleep_state xxx resume_noirq pinctrl_pm_select_init_state ... pinctrl_pm_select_default_state Signed-off-by: Christian Bruel Signed-off-by: Manivannan Sadhasivam Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20250820075411.1178729-3-christian.bruel@foss.st.com --- drivers/pinctrl/core.c | 13 +++++++++++++ include/linux/pinctrl/consumer.h | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 73b78d6eac67..c5dbf4e9db84 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1655,6 +1655,19 @@ int pinctrl_pm_select_default_state(struct device *dev) } EXPORT_SYMBOL_GPL(pinctrl_pm_select_default_state); +/** + * pinctrl_pm_select_init_state() - select init pinctrl state for PM + * @dev: device to select init state for + */ +int pinctrl_pm_select_init_state(struct device *dev) +{ + if (!dev->pins) + return 0; + + return pinctrl_select_bound_state(dev, dev->pins->init_state); +} +EXPORT_SYMBOL_GPL(pinctrl_pm_select_init_state); + /** * pinctrl_pm_select_sleep_state() - select sleep pinctrl state for PM * @dev: device to select sleep state for diff --git a/include/linux/pinctrl/consumer.h b/include/linux/pinctrl/consumer.h index 73de70362b98..63ce16191eb9 100644 --- a/include/linux/pinctrl/consumer.h +++ b/include/linux/pinctrl/consumer.h @@ -48,6 +48,7 @@ int pinctrl_select_default_state(struct device *dev); #ifdef CONFIG_PM int pinctrl_pm_select_default_state(struct device *dev); +int pinctrl_pm_select_init_state(struct device *dev); int pinctrl_pm_select_sleep_state(struct device *dev); int pinctrl_pm_select_idle_state(struct device *dev); #else @@ -55,6 +56,10 @@ static inline int pinctrl_pm_select_default_state(struct device *dev) { return 0; } +static inline int pinctrl_pm_select_init_state(struct device *dev) +{ + return 0; +} static inline int pinctrl_pm_select_sleep_state(struct device *dev) { return 0; @@ -143,6 +148,11 @@ static inline int pinctrl_pm_select_default_state(struct device *dev) return 0; } +static inline int pinctrl_pm_select_init_state(struct device *dev) +{ + return 0; +} + static inline int pinctrl_pm_select_sleep_state(struct device *dev) { return 0; From 5ffa3d2f43a487f60e9f6f692aa8e22251446755 Mon Sep 17 00:00:00 2001 From: Christian Bruel Date: Wed, 20 Aug 2025 09:54:03 +0200 Subject: [PATCH 0577/2711] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings Document the bindings for STM32MP25 PCIe Controller configured in root complex mode with one root port. Supports 4 INTx and MSI interrupts from the ARM GICv2m controller. STM32 PCIe may be in a power domain which is the case for the STM32MP25 based boards. Supports WAKE# from wake-gpios Signed-off-by: Christian Bruel Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Acked-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250820075411.1178729-4-christian.bruel@foss.st.com --- .../bindings/pci/st,stm32-pcie-common.yaml | 33 ++++++ .../bindings/pci/st,stm32-pcie-host.yaml | 112 ++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/st,stm32-pcie-common.yaml create mode 100644 Documentation/devicetree/bindings/pci/st,stm32-pcie-host.yaml diff --git a/Documentation/devicetree/bindings/pci/st,stm32-pcie-common.yaml b/Documentation/devicetree/bindings/pci/st,stm32-pcie-common.yaml new file mode 100644 index 000000000000..5adbff259204 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/st,stm32-pcie-common.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/st,stm32-pcie-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STM32MP25 PCIe RC/EP controller + +maintainers: + - Christian Bruel + +description: + STM32MP25 PCIe RC/EP common properties + +properties: + clocks: + maxItems: 1 + description: PCIe system clock + + resets: + maxItems: 1 + + power-domains: + maxItems: 1 + + access-controllers: + maxItems: 1 + +required: + - clocks + - resets + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/pci/st,stm32-pcie-host.yaml b/Documentation/devicetree/bindings/pci/st,stm32-pcie-host.yaml new file mode 100644 index 000000000000..443bfe2cdc98 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/st,stm32-pcie-host.yaml @@ -0,0 +1,112 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/st,stm32-pcie-host.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STM32MP25 PCIe Root Complex + +maintainers: + - Christian Bruel + +description: + PCIe root complex controller based on the Synopsys DesignWare PCIe core. + +allOf: + - $ref: /schemas/pci/snps,dw-pcie.yaml# + - $ref: /schemas/pci/st,stm32-pcie-common.yaml# + +properties: + compatible: + const: st,stm32mp25-pcie-rc + + reg: + items: + - description: Data Bus Interface (DBI) registers. + - description: PCIe configuration registers. + + reg-names: + items: + - const: dbi + - const: config + + msi-parent: + maxItems: 1 + +patternProperties: + '^pcie@[0-2],0$': + type: object + $ref: /schemas/pci/pci-pci-bridge.yaml# + + properties: + reg: + maxItems: 1 + + phys: + maxItems: 1 + + reset-gpios: + description: GPIO controlled connection to PERST# signal + maxItems: 1 + + wake-gpios: + description: GPIO used as WAKE# input signal + maxItems: 1 + + required: + - phys + - ranges + + unevaluatedProperties: false + +required: + - interrupt-map + - interrupt-map-mask + - ranges + - dma-ranges + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + pcie@48400000 { + compatible = "st,stm32mp25-pcie-rc"; + device_type = "pci"; + reg = <0x48400000 0x400000>, + <0x10000000 0x10000>; + reg-names = "dbi", "config"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc 0 0 GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc 0 0 GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc 0 0 GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x00000000 0x10010000 0x0 0x10000>, + <0x02000000 0x0 0x10020000 0x10020000 0x0 0x7fe0000>, + <0x42000000 0x0 0x18000000 0x18000000 0x0 0x8000000>; + dma-ranges = <0x42000000 0x0 0x80000000 0x80000000 0x0 0x80000000>; + clocks = <&rcc CK_BUS_PCIE>; + resets = <&rcc PCIE_R>; + msi-parent = <&v2m0>; + access-controllers = <&rifsc 68>; + power-domains = <&CLUSTER_PD>; + + pcie@0,0 { + device_type = "pci"; + reg = <0x0 0x0 0x0 0x0 0x0>; + phys = <&combophy PHY_TYPE_PCIE>; + wake-gpios = <&gpioh 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + reset-gpios = <&gpioj 8 GPIO_ACTIVE_LOW>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + }; + }; From ffdd27d36265be108827c606c9fbe81a5947547e Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 19 Aug 2025 21:12:33 +0800 Subject: [PATCH 0578/2711] PCI: keystone: Use kcalloc() instead of kzalloc() Replace calls of devm_kzalloc() with devm_kcalloc() in ks_pcie_probe(). As noted in the kernel documentation [1], open-coded multiplication in allocator arguments is discouraged because it can lead to integer overflow. Using devm_kcalloc() provides built-in overflow protection, making the memory allocation safer when calculating the allocation size compared to explicit multiplication. [1]: https://www.kernel.org/doc/html/next/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments Signed-off-by: Qianfeng Rong Signed-off-by: Manivannan Sadhasivam Reviewed-by: Siddharth Vadapalli Link: https://patch.msgid.link/20250819131235.152967-1-rongqianfeng@vivo.com --- drivers/pci/controller/dwc/pci-keystone.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 2b2632e513b5..ac025bbd5bd5 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -1213,11 +1213,11 @@ static int ks_pcie_probe(struct platform_device *pdev) if (ret) num_lanes = 1; - phy = devm_kzalloc(dev, sizeof(*phy) * num_lanes, GFP_KERNEL); + phy = devm_kcalloc(dev, num_lanes, sizeof(*phy), GFP_KERNEL); if (!phy) return -ENOMEM; - link = devm_kzalloc(dev, sizeof(*link) * num_lanes, GFP_KERNEL); + link = devm_kcalloc(dev, num_lanes, sizeof(*link), GFP_KERNEL); if (!link) return -ENOMEM; From 6dd0ca9f2dfaab1bd15895bab16e5496632e53b6 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Tue, 26 Aug 2025 16:32:53 +0530 Subject: [PATCH 0579/2711] dt-bindings: PCI: qcom,pcie-sm8550: Add SM8750 compatible PCIe controller present in SM8750 SoC is backwards compatible with the controller present in SM8550 SoC. Hence, add the compatible with SM8550 fallback. Signed-off-by: Krishna Chaitanya Chundru [mani: reworded description] Signed-off-by: Manivannan Sadhasivam Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250826-pakala-v3-1-721627bd5bb0@oss.qualcomm.com --- Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml index dbce671ba011..38b561e23c1f 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml @@ -22,6 +22,7 @@ properties: - enum: - qcom,sar2130p-pcie - qcom,pcie-sm8650 + - qcom,pcie-sm8750 - const: qcom,pcie-sm8550 reg: From 45df22935bdc6bbddf87f38a57ae7257244cf3cf Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Tue, 26 Aug 2025 16:32:55 +0530 Subject: [PATCH 0580/2711] PCI: qcom: Restrict port parsing only to PCIe bridge child nodes The qcom_pcie_parse_ports() function currently iterates over all available child nodes of the PCIe controller's device tree node. This includes unrelated nodes such as OPP (Operating Performance Points) nodes, which do not contain the expected 'reset' and 'phy' properties. As a result, parsing fails and the driver falls back to the legacy method of parsing the controller node directly. However, this fallback also fails when properties are shifted to the Root Port node, leading to probe failure. Fix this by restricting the parsing logic to only consider child nodes with device_type = "pci", which is the expected and required property for PCIe bridge nodes as per the pci-bus-common.yaml dtschema. Fixes: a2fbecdbbb9d ("PCI: qcom: Add support for parsing the new Root Port binding") Signed-off-by: Krishna Chaitanya Chundru [mani: reworded subject and description] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250826-pakala-v3-3-721627bd5bb0@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-qcom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 294babe1816e..fbed7130d747 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1740,6 +1740,8 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pcie) int ret = -ENOENT; for_each_available_child_of_node_scoped(dev->of_node, of_port) { + if (!of_node_is_type(of_port, "pci")) + continue; ret = qcom_pcie_parse_port(pcie, of_port); if (ret) goto err_port_del; From 1b1d9ca13475cbedf25727ae4b4ead684ae85c03 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 6 Aug 2025 11:03:11 -0600 Subject: [PATCH 0581/2711] vfio/fsl-mc: Mark for removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver has been orphaned for more than a year, mark it for removal. Reviewed-by: Kevin Tian Reviewed-by: Cédric Le Goater Reviewed-by: Jason Gunthorpe Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20250806170314.3768750-2-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- MAINTAINERS | 2 +- drivers/vfio/fsl-mc/Kconfig | 5 ++++- drivers/vfio/fsl-mc/vfio_fsl_mc.c | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index fed6cd812d79..482c18d39f62 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26443,7 +26443,7 @@ F: include/uapi/linux/vfio.h VFIO FSL-MC DRIVER L: kvm@vger.kernel.org -S: Orphan +S: Obsolete F: drivers/vfio/fsl-mc/ VFIO HISILICON PCI DRIVER diff --git a/drivers/vfio/fsl-mc/Kconfig b/drivers/vfio/fsl-mc/Kconfig index 7d1d690348f0..43c145d17971 100644 --- a/drivers/vfio/fsl-mc/Kconfig +++ b/drivers/vfio/fsl-mc/Kconfig @@ -2,9 +2,12 @@ menu "VFIO support for FSL_MC bus devices" depends on FSL_MC_BUS config VFIO_FSL_MC - tristate "VFIO support for QorIQ DPAA2 fsl-mc bus devices" + tristate "VFIO support for QorIQ DPAA2 fsl-mc bus devices (DEPRECATED)" select EVENTFD help + The vfio-fsl-mc driver is deprecated and will be removed in a + future kernel release. + Driver to enable support for the VFIO QorIQ DPAA2 fsl-mc (Management Complex) devices. This is required to passthrough fsl-mc bus devices using the VFIO framework. diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c index f65d91c01f2e..76ccbab0e3d6 100644 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c @@ -537,6 +537,8 @@ static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev) struct device *dev = &mc_dev->dev; int ret; + dev_err_once(dev, "DEPRECATION: vfio-fsl-mc is deprecated and will be removed in a future kernel release\n"); + vdev = vfio_alloc_device(vfio_fsl_mc_device, vdev, dev, &vfio_fsl_mc_ops); if (IS_ERR(vdev)) From 473c3af395c904ad5e10897bf482a92c4f3f3650 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Mon, 18 Aug 2025 16:52:01 +0800 Subject: [PATCH 0582/2711] vfio/pci: drop redundant conversion to bool The result of integer comparison already evaluates to bool. No need for explicit conversion. No functional impact. Signed-off-by: Xichao Zhao Link: https://lore.kernel.org/r/20250818085201.510206-1-zhao.xichao@vivo.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_intrs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 123298a4dc8f..00583909b380 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -677,7 +677,7 @@ static int vfio_pci_set_msi_trigger(struct vfio_pci_core_device *vdev, { struct vfio_pci_irq_ctx *ctx; unsigned int i; - bool msix = (index == VFIO_PCI_MSIX_IRQ_INDEX) ? true : false; + bool msix = (index == VFIO_PCI_MSIX_IRQ_INDEX); if (irq_is(vdev, index) && !count && (flags & VFIO_IRQ_SET_DATA_NONE)) { vfio_msi_disable(vdev, msix); From 767b1ed8b980498978c77dc89497602ae3421af5 Mon Sep 17 00:00:00 2001 From: Morduan Zang Date: Thu, 14 Aug 2025 19:03:58 +0800 Subject: [PATCH 0583/2711] vfio/nvgrace-gpu: fix grammatical error The word "as" in the comment should be replaced with "is", and there is an extra space in the comment. Signed-off-by: Morduan Zang Reviewed-by: Ankit Agrawal Link: https://lore.kernel.org/r/54E1ED6C5A2682C8+20250814110358.285412-1-zhangdandan@uniontech.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/nvgrace-gpu/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c index d95761dcdd58..0adaa6150252 100644 --- a/drivers/vfio/pci/nvgrace-gpu/main.c +++ b/drivers/vfio/pci/nvgrace-gpu/main.c @@ -260,7 +260,7 @@ nvgrace_gpu_ioctl_get_region_info(struct vfio_device *core_vdev, info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); /* * The region memory size may not be power-of-2 aligned. - * Given that the memory as a BAR and may not be + * Given that the memory is a BAR and may not be * aligned, roundup to the next power-of-2. */ info.size = memregion->bar_size; From 292e9ee22b0adad49c9a6f63708988e32c007da6 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:24:48 +0000 Subject: [PATCH 0584/2711] selftests: Create tools/testing/selftests/vfio Create the directory tools/testing/selftests/vfio with a stub Makefile and hook it up to the top-level selftests Makefile. This directory will be used in subsequent commits to host selftests for the VFIO subsystem. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-2-dmatlack@google.com Signed-off-by: Alex Williamson --- MAINTAINERS | 7 +++++++ tools/testing/selftests/Makefile | 1 + tools/testing/selftests/vfio/.gitignore | 7 +++++++ tools/testing/selftests/vfio/Makefile | 2 ++ 4 files changed, 17 insertions(+) create mode 100644 tools/testing/selftests/vfio/.gitignore create mode 100644 tools/testing/selftests/vfio/Makefile diff --git a/MAINTAINERS b/MAINTAINERS index 482c18d39f62..fba915fcb30e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26440,6 +26440,7 @@ F: drivers/vfio/ F: include/linux/vfio.h F: include/linux/vfio_pci_core.h F: include/uapi/linux/vfio.h +F: tools/testing/selftests/vfio/ VFIO FSL-MC DRIVER L: kvm@vger.kernel.org @@ -26504,6 +26505,12 @@ L: qat-linux@intel.com S: Supported F: drivers/vfio/pci/qat/ +VFIO SELFTESTS +M: David Matlack +L: kvm@vger.kernel.org +S: Maintained +F: tools/testing/selftests/vfio/ + VFIO VIRTIO PCI DRIVER M: Yishai Hadas L: kvm@vger.kernel.org diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 030da61dbff3..c4e616183aa5 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -124,6 +124,7 @@ TARGETS += uevent TARGETS += user_events TARGETS += vDSO TARGETS += mm +TARGETS += vfio TARGETS += x86 TARGETS += x86/bugs TARGETS += zram diff --git a/tools/testing/selftests/vfio/.gitignore b/tools/testing/selftests/vfio/.gitignore new file mode 100644 index 000000000000..6d9381d60172 --- /dev/null +++ b/tools/testing/selftests/vfio/.gitignore @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +* +!/**/ +!*.c +!*.h +!*.S +!*.sh diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile new file mode 100644 index 000000000000..2bba39aff5d9 --- /dev/null +++ b/tools/testing/selftests/vfio/Makefile @@ -0,0 +1,2 @@ +CFLAGS = $(KHDR_INCLUDES) +include ../lib.mk From 19faf6fd969c21589b6dd40c35255e4d00d427f8 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:24:49 +0000 Subject: [PATCH 0585/2711] vfio: selftests: Add a helper library for VFIO selftests Add a basic helper library to be used by VFIO selftests. The basic unit of the library is struct vfio_pci_device, which represents a single PCI device that is bound to the vfio-pci driver. The library currently only supports a single device per group and container, and VFIO IOMMU types. The code in this library was heavily based on prior work done by Raghavendra Rao Ananta , and the VFIO_ASSERT*() macros were written by Vipin Sharma . Separate that Makefile rules for building the library into a separate script so that the library can be built by and linked into KVM selftests in a subsequent commit. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-3-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/Makefile | 14 + .../selftests/vfio/lib/include/vfio_util.h | 140 +++++++ tools/testing/selftests/vfio/lib/libvfio.mk | 15 + .../selftests/vfio/lib/vfio_pci_device.c | 365 ++++++++++++++++++ 4 files changed, 534 insertions(+) create mode 100644 tools/testing/selftests/vfio/lib/include/vfio_util.h create mode 100644 tools/testing/selftests/vfio/lib/libvfio.mk create mode 100644 tools/testing/selftests/vfio/lib/vfio_pci_device.c diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile index 2bba39aff5d9..db3e4db1a6dd 100644 --- a/tools/testing/selftests/vfio/Makefile +++ b/tools/testing/selftests/vfio/Makefile @@ -1,2 +1,16 @@ CFLAGS = $(KHDR_INCLUDES) include ../lib.mk +include lib/libvfio.mk + +CFLAGS += -I$(top_srcdir)/tools/include +CFLAGS += -MD +CFLAGS += $(EXTRA_CFLAGS) + +$(TEST_GEN_PROGS): %: %.o $(LIBVFIO_O) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< $(LIBVFIO_O) $(LDLIBS) -o $@ + +TEST_GEN_PROGS_O = $(patsubst %, %.o, $(TEST_GEN_PROGS)) +TEST_DEP_FILES = $(patsubst %.o, %.d, $(TEST_GEN_PROGS_O) $(LIBVFIO_O)) +-include $(TEST_DEP_FILES) + +EXTRA_CLEAN += $(TEST_GEN_PROGS_O) $(TEST_DEP_FILES) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h new file mode 100644 index 000000000000..b7d2bb8c18ba --- /dev/null +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H +#define SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H + +#include +#include +#include +#include + +#include "../../../kselftest.h" + +#define VFIO_LOG_AND_EXIT(...) do { \ + fprintf(stderr, " " __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + exit(KSFT_FAIL); \ +} while (0) + +#define VFIO_ASSERT_OP(_lhs, _rhs, _op, ...) do { \ + typeof(_lhs) __lhs = (_lhs); \ + typeof(_rhs) __rhs = (_rhs); \ + \ + if (__lhs _op __rhs) \ + break; \ + \ + fprintf(stderr, "%s:%u: Assertion Failure\n\n", __FILE__, __LINE__); \ + fprintf(stderr, " Expression: " #_lhs " " #_op " " #_rhs "\n"); \ + fprintf(stderr, " Observed: %#lx %s %#lx\n", \ + (u64)__lhs, #_op, (u64)__rhs); \ + fprintf(stderr, " [errno: %d - %s]\n", errno, strerror(errno)); \ + VFIO_LOG_AND_EXIT(__VA_ARGS__); \ +} while (0) + +#define VFIO_ASSERT_EQ(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, ==, ##__VA_ARGS__) +#define VFIO_ASSERT_NE(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, !=, ##__VA_ARGS__) +#define VFIO_ASSERT_LT(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, <, ##__VA_ARGS__) +#define VFIO_ASSERT_LE(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, <=, ##__VA_ARGS__) +#define VFIO_ASSERT_GT(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, >, ##__VA_ARGS__) +#define VFIO_ASSERT_GE(_a, _b, ...) VFIO_ASSERT_OP(_a, _b, >=, ##__VA_ARGS__) +#define VFIO_ASSERT_TRUE(_a, ...) VFIO_ASSERT_NE(false, (_a), ##__VA_ARGS__) +#define VFIO_ASSERT_FALSE(_a, ...) VFIO_ASSERT_EQ(false, (_a), ##__VA_ARGS__) +#define VFIO_ASSERT_NULL(_a, ...) VFIO_ASSERT_EQ(NULL, _a, ##__VA_ARGS__) +#define VFIO_ASSERT_NOT_NULL(_a, ...) VFIO_ASSERT_NE(NULL, _a, ##__VA_ARGS__) + +#define VFIO_FAIL(_fmt, ...) do { \ + fprintf(stderr, "%s:%u: FAIL\n\n", __FILE__, __LINE__); \ + VFIO_LOG_AND_EXIT(_fmt, ##__VA_ARGS__); \ +} while (0) + +struct vfio_pci_bar { + struct vfio_region_info info; + void *vaddr; +}; + +struct vfio_pci_device { + int fd; + int group_fd; + int container_fd; + + struct vfio_device_info info; + struct vfio_region_info config_space; + struct vfio_pci_bar bars[PCI_STD_NUM_BARS]; + + struct vfio_irq_info msi_info; + struct vfio_irq_info msix_info; + + /* eventfds for MSI and MSI-x interrupts */ + int msi_eventfds[PCI_MSIX_FLAGS_QSIZE + 1]; +}; + +/* + * Return the BDF string of the device that the test should use. + * + * If a BDF string is provided by the user on the command line (as the last + * element of argv[]), then this function will return that and decrement argc + * by 1. + * + * Otherwise this function will attempt to use the environment variable + * $VFIO_SELFTESTS_BDF. + * + * If BDF cannot be determined then the test will exit with KSFT_SKIP. + */ +const char *vfio_selftests_get_bdf(int *argc, char *argv[]); + +struct vfio_pci_device *vfio_pci_device_init(const char *bdf, int iommu_type); +void vfio_pci_device_cleanup(struct vfio_pci_device *device); + +void vfio_pci_dma_map(struct vfio_pci_device *device, u64 iova, u64 size, + void *vaddr); +void vfio_pci_dma_unmap(struct vfio_pci_device *device, u64 iova, u64 size); + +void vfio_pci_config_access(struct vfio_pci_device *device, bool write, + size_t config, size_t size, void *data); + +#define vfio_pci_config_read(_device, _offset, _type) ({ \ + _type __data; \ + vfio_pci_config_access((_device), false, _offset, sizeof(__data), &__data); \ + __data; \ +}) + +#define vfio_pci_config_readb(_d, _o) vfio_pci_config_read(_d, _o, u8) +#define vfio_pci_config_readw(_d, _o) vfio_pci_config_read(_d, _o, u16) +#define vfio_pci_config_readl(_d, _o) vfio_pci_config_read(_d, _o, u32) + +#define vfio_pci_config_write(_device, _offset, _value, _type) do { \ + _type __data = (_value); \ + vfio_pci_config_access((_device), true, _offset, sizeof(_type), &__data); \ +} while (0) + +#define vfio_pci_config_writeb(_d, _o, _v) vfio_pci_config_write(_d, _o, _v, u8) +#define vfio_pci_config_writew(_d, _o, _v) vfio_pci_config_write(_d, _o, _v, u16) +#define vfio_pci_config_writel(_d, _o, _v) vfio_pci_config_write(_d, _o, _v, u32) + +void vfio_pci_irq_enable(struct vfio_pci_device *device, u32 index, + u32 vector, int count); +void vfio_pci_irq_disable(struct vfio_pci_device *device, u32 index); +void vfio_pci_irq_trigger(struct vfio_pci_device *device, u32 index, u32 vector); + +static inline void vfio_pci_msi_enable(struct vfio_pci_device *device, + u32 vector, int count) +{ + vfio_pci_irq_enable(device, VFIO_PCI_MSI_IRQ_INDEX, vector, count); +} + +static inline void vfio_pci_msi_disable(struct vfio_pci_device *device) +{ + vfio_pci_irq_disable(device, VFIO_PCI_MSI_IRQ_INDEX); +} + +static inline void vfio_pci_msix_enable(struct vfio_pci_device *device, + u32 vector, int count) +{ + vfio_pci_irq_enable(device, VFIO_PCI_MSIX_IRQ_INDEX, vector, count); +} + +static inline void vfio_pci_msix_disable(struct vfio_pci_device *device) +{ + vfio_pci_irq_disable(device, VFIO_PCI_MSIX_IRQ_INDEX); +} + +#endif /* SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H */ diff --git a/tools/testing/selftests/vfio/lib/libvfio.mk b/tools/testing/selftests/vfio/lib/libvfio.mk new file mode 100644 index 000000000000..72e55a560eeb --- /dev/null +++ b/tools/testing/selftests/vfio/lib/libvfio.mk @@ -0,0 +1,15 @@ +VFIO_DIR := $(selfdir)/vfio + +LIBVFIO_C := lib/vfio_pci_device.c + +LIBVFIO_O := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBVFIO_C)) + +LIBVFIO_O_DIRS := $(shell dirname $(LIBVFIO_O) | uniq) +$(shell mkdir -p $(LIBVFIO_O_DIRS)) + +CFLAGS += -I$(VFIO_DIR)/lib/include + +$(LIBVFIO_O): $(OUTPUT)/%.o : $(VFIO_DIR)/%.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +EXTRA_CLEAN += $(LIBVFIO_O) diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c new file mode 100644 index 000000000000..76adb1841f16 --- /dev/null +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "../../../kselftest.h" +#include + +#define VFIO_DEV_PATH "/dev/vfio/vfio" +#define PCI_SYSFS_PATH "/sys/bus/pci/devices" + +#define ioctl_assert(_fd, _op, _arg) do { \ + void *__arg = (_arg); \ + int __ret = ioctl((_fd), (_op), (__arg)); \ + VFIO_ASSERT_EQ(__ret, 0, "ioctl(%s, %s, %s) returned %d\n", #_fd, #_op, #_arg, __ret); \ +} while (0) + +static void vfio_pci_irq_set(struct vfio_pci_device *device, + u32 index, u32 vector, u32 count, int *fds) +{ + u8 buf[sizeof(struct vfio_irq_set) + sizeof(int) * count] = {}; + struct vfio_irq_set *irq = (void *)&buf; + int *irq_fds = (void *)&irq->data; + + irq->argsz = sizeof(buf); + irq->flags = VFIO_IRQ_SET_ACTION_TRIGGER; + irq->index = index; + irq->start = vector; + irq->count = count; + + if (count) { + irq->flags |= VFIO_IRQ_SET_DATA_EVENTFD; + memcpy(irq_fds, fds, sizeof(int) * count); + } else { + irq->flags |= VFIO_IRQ_SET_DATA_NONE; + } + + ioctl_assert(device->fd, VFIO_DEVICE_SET_IRQS, irq); +} + +void vfio_pci_irq_trigger(struct vfio_pci_device *device, u32 index, u32 vector) +{ + struct vfio_irq_set irq = { + .argsz = sizeof(irq), + .flags = VFIO_IRQ_SET_ACTION_TRIGGER | VFIO_IRQ_SET_DATA_NONE, + .index = index, + .start = vector, + .count = 1, + }; + + ioctl_assert(device->fd, VFIO_DEVICE_SET_IRQS, &irq); +} + +static void check_supported_irq_index(u32 index) +{ + /* VFIO selftests only supports MSI and MSI-x for now. */ + VFIO_ASSERT_TRUE(index == VFIO_PCI_MSI_IRQ_INDEX || + index == VFIO_PCI_MSIX_IRQ_INDEX, + "Unsupported IRQ index: %u\n", index); +} + +void vfio_pci_irq_enable(struct vfio_pci_device *device, u32 index, u32 vector, + int count) +{ + int i; + + check_supported_irq_index(index); + + for (i = vector; i < vector + count; i++) { + VFIO_ASSERT_LT(device->msi_eventfds[i], 0); + device->msi_eventfds[i] = eventfd(0, 0); + VFIO_ASSERT_GE(device->msi_eventfds[i], 0); + } + + vfio_pci_irq_set(device, index, vector, count, device->msi_eventfds + vector); +} + +void vfio_pci_irq_disable(struct vfio_pci_device *device, u32 index) +{ + int i; + + check_supported_irq_index(index); + + for (i = 0; i < ARRAY_SIZE(device->msi_eventfds); i++) { + if (device->msi_eventfds[i] < 0) + continue; + + VFIO_ASSERT_EQ(close(device->msi_eventfds[i]), 0); + device->msi_eventfds[i] = -1; + } + + vfio_pci_irq_set(device, index, 0, 0, NULL); +} + +static void vfio_pci_irq_get(struct vfio_pci_device *device, u32 index, + struct vfio_irq_info *irq_info) +{ + irq_info->argsz = sizeof(*irq_info); + irq_info->index = index; + + ioctl_assert(device->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info); +} + +void vfio_pci_dma_map(struct vfio_pci_device *device, u64 iova, u64 size, void *vaddr) +{ + struct vfio_iommu_type1_dma_map map = { + .argsz = sizeof(map), + .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE, + .vaddr = (u64)vaddr, + .iova = iova, + .size = size, + }; + + ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &map); +} + +void vfio_pci_dma_unmap(struct vfio_pci_device *device, u64 iova, u64 size) +{ + struct vfio_iommu_type1_dma_unmap unmap = { + .argsz = sizeof(unmap), + .iova = iova, + .size = size, + }; + + ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &unmap); +} + +static void vfio_pci_region_get(struct vfio_pci_device *device, int index, + struct vfio_region_info *info) +{ + memset(info, 0, sizeof(*info)); + + info->argsz = sizeof(*info); + info->index = index; + + ioctl_assert(device->fd, VFIO_DEVICE_GET_REGION_INFO, info); +} + +static void vfio_pci_bar_map(struct vfio_pci_device *device, int index) +{ + struct vfio_pci_bar *bar = &device->bars[index]; + int prot = 0; + + VFIO_ASSERT_LT(index, PCI_STD_NUM_BARS); + VFIO_ASSERT_NULL(bar->vaddr); + VFIO_ASSERT_TRUE(bar->info.flags & VFIO_REGION_INFO_FLAG_MMAP); + + if (bar->info.flags & VFIO_REGION_INFO_FLAG_READ) + prot |= PROT_READ; + if (bar->info.flags & VFIO_REGION_INFO_FLAG_WRITE) + prot |= PROT_WRITE; + + bar->vaddr = mmap(NULL, bar->info.size, prot, MAP_FILE | MAP_SHARED, + device->fd, bar->info.offset); + VFIO_ASSERT_NE(bar->vaddr, MAP_FAILED); +} + +static void vfio_pci_bar_unmap(struct vfio_pci_device *device, int index) +{ + struct vfio_pci_bar *bar = &device->bars[index]; + + VFIO_ASSERT_LT(index, PCI_STD_NUM_BARS); + VFIO_ASSERT_NOT_NULL(bar->vaddr); + + VFIO_ASSERT_EQ(munmap(bar->vaddr, bar->info.size), 0); + bar->vaddr = NULL; +} + +static void vfio_pci_bar_unmap_all(struct vfio_pci_device *device) +{ + int i; + + for (i = 0; i < PCI_STD_NUM_BARS; i++) { + if (device->bars[i].vaddr) + vfio_pci_bar_unmap(device, i); + } +} + +void vfio_pci_config_access(struct vfio_pci_device *device, bool write, + size_t config, size_t size, void *data) +{ + struct vfio_region_info *config_space = &device->config_space; + int ret; + + if (write) + ret = pwrite(device->fd, data, size, config_space->offset + config); + else + ret = pread(device->fd, data, size, config_space->offset + config); + + VFIO_ASSERT_EQ(ret, size, "Failed to %s PCI config space: 0x%lx\n", + write ? "write to" : "read from", config); +} + +static unsigned int vfio_pci_get_group_from_dev(const char *bdf) +{ + char dev_iommu_group_path[PATH_MAX] = {0}; + char sysfs_path[PATH_MAX] = {0}; + unsigned int group; + int ret; + + snprintf(sysfs_path, PATH_MAX, "%s/%s/iommu_group", PCI_SYSFS_PATH, bdf); + + ret = readlink(sysfs_path, dev_iommu_group_path, sizeof(dev_iommu_group_path)); + VFIO_ASSERT_NE(ret, -1, "Failed to get the IOMMU group for device: %s\n", bdf); + + ret = sscanf(basename(dev_iommu_group_path), "%u", &group); + VFIO_ASSERT_EQ(ret, 1, "Failed to get the IOMMU group for device: %s\n", bdf); + + return group; +} + +static void vfio_pci_container_setup(struct vfio_pci_device *device) +{ + int version; + + device->container_fd = open(VFIO_DEV_PATH, O_RDWR); + VFIO_ASSERT_GE(device->container_fd, 0, "open(%s) failed\n", VFIO_DEV_PATH); + + version = ioctl(device->container_fd, VFIO_GET_API_VERSION); + VFIO_ASSERT_EQ(version, VFIO_API_VERSION); +} + +static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf) +{ + struct vfio_group_status group_status = { + .argsz = sizeof(group_status), + }; + char group_path[32]; + int group; + + group = vfio_pci_get_group_from_dev(bdf); + snprintf(group_path, sizeof(group_path), "/dev/vfio/%d", group); + + device->group_fd = open(group_path, O_RDWR); + VFIO_ASSERT_GE(device->group_fd, 0, "open(%s) failed\n", group_path); + + ioctl_assert(device->group_fd, VFIO_GROUP_GET_STATUS, &group_status); + VFIO_ASSERT_TRUE(group_status.flags & VFIO_GROUP_FLAGS_VIABLE); + + ioctl_assert(device->group_fd, VFIO_GROUP_SET_CONTAINER, &device->container_fd); +} + +static void vfio_pci_iommu_setup(struct vfio_pci_device *device, unsigned long iommu_type) +{ + int ret; + + ret = ioctl(device->container_fd, VFIO_CHECK_EXTENSION, iommu_type); + VFIO_ASSERT_GT(ret, 0, "VFIO IOMMU type %lu not supported\n", iommu_type); + + ioctl_assert(device->container_fd, VFIO_SET_IOMMU, (void *)iommu_type); +} + +static void vfio_pci_device_setup(struct vfio_pci_device *device, const char *bdf) +{ + int i; + + device->fd = ioctl(device->group_fd, VFIO_GROUP_GET_DEVICE_FD, bdf); + VFIO_ASSERT_GE(device->fd, 0); + + device->info.argsz = sizeof(device->info); + ioctl_assert(device->fd, VFIO_DEVICE_GET_INFO, &device->info); + + vfio_pci_region_get(device, VFIO_PCI_CONFIG_REGION_INDEX, &device->config_space); + + /* Sanity check VFIO does not advertise mmap for config space */ + VFIO_ASSERT_TRUE(!(device->config_space.flags & VFIO_REGION_INFO_FLAG_MMAP), + "PCI config space should not support mmap()\n"); + + for (i = 0; i < PCI_STD_NUM_BARS; i++) { + struct vfio_pci_bar *bar = device->bars + i; + + vfio_pci_region_get(device, i, &bar->info); + if (bar->info.flags & VFIO_REGION_INFO_FLAG_MMAP) + vfio_pci_bar_map(device, i); + } + + vfio_pci_irq_get(device, VFIO_PCI_MSI_IRQ_INDEX, &device->msi_info); + vfio_pci_irq_get(device, VFIO_PCI_MSIX_IRQ_INDEX, &device->msix_info); + + for (i = 0; i < ARRAY_SIZE(device->msi_eventfds); i++) + device->msi_eventfds[i] = -1; +} + +struct vfio_pci_device *vfio_pci_device_init(const char *bdf, int iommu_type) +{ + struct vfio_pci_device *device; + + device = calloc(1, sizeof(*device)); + VFIO_ASSERT_NOT_NULL(device); + + vfio_pci_container_setup(device); + vfio_pci_group_setup(device, bdf); + vfio_pci_iommu_setup(device, iommu_type); + vfio_pci_device_setup(device, bdf); + + return device; +} + +void vfio_pci_device_cleanup(struct vfio_pci_device *device) +{ + int i; + + vfio_pci_bar_unmap_all(device); + + VFIO_ASSERT_EQ(close(device->fd), 0); + + for (i = 0; i < ARRAY_SIZE(device->msi_eventfds); i++) { + if (device->msi_eventfds[i] < 0) + continue; + + VFIO_ASSERT_EQ(close(device->msi_eventfds[i]), 0); + } + + VFIO_ASSERT_EQ(close(device->group_fd), 0); + VFIO_ASSERT_EQ(close(device->container_fd), 0); + + free(device); +} + +static bool is_bdf(const char *str) +{ + unsigned int s, b, d, f; + int length, count; + + count = sscanf(str, "%4x:%2x:%2x.%2x%n", &s, &b, &d, &f, &length); + return count == 4 && length == strlen(str); +} + +const char *vfio_selftests_get_bdf(int *argc, char *argv[]) +{ + char *bdf; + + if (*argc > 1 && is_bdf(argv[*argc - 1])) + return argv[--(*argc)]; + + bdf = getenv("VFIO_SELFTESTS_BDF"); + if (bdf) { + VFIO_ASSERT_TRUE(is_bdf(bdf), "Invalid BDF: %s\n", bdf); + return bdf; + } + + fprintf(stderr, "Unable to determine which device to use, skipping test.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "To pass the device address via environment variable:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " export VFIO_SELFTESTS_BDF=segment:bus:device.function\n"); + fprintf(stderr, " %s [options]\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "To pass the device address via argv:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " %s [options] segment:bus:device.function\n", argv[0]); + fprintf(stderr, "\n"); + exit(KSFT_SKIP); +} From 16eadd7c1277284cfff5b7071910920a2d008251 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:24:50 +0000 Subject: [PATCH 0586/2711] vfio: selftests: Introduce vfio_pci_device_test Introduce a basic VFIO selftest called vfio_pci_device_test to demonstrate the functionality of the VFIO selftest library and provide some test coverage of basic VFIO operations, including: - Mapping and unmapping DMA - Mapping and unmapping BARs - Enabling, triggering, and disabling MSI and MSI-x - Reading and writing to PCI config space This test should work with most PCI devices, as long as they are bound to vfio-pci. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-4-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/Makefile | 1 + .../selftests/vfio/vfio_pci_device_test.c | 180 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 tools/testing/selftests/vfio/vfio_pci_device_test.c diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile index db3e4db1a6dd..828419537250 100644 --- a/tools/testing/selftests/vfio/Makefile +++ b/tools/testing/selftests/vfio/Makefile @@ -1,4 +1,5 @@ CFLAGS = $(KHDR_INCLUDES) +TEST_GEN_PROGS += vfio_pci_device_test include ../lib.mk include lib/libvfio.mk diff --git a/tools/testing/selftests/vfio/vfio_pci_device_test.c b/tools/testing/selftests/vfio/vfio_pci_device_test.c new file mode 100644 index 000000000000..3e7049b9c8f6 --- /dev/null +++ b/tools/testing/selftests/vfio/vfio_pci_device_test.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "../kselftest_harness.h" + +static const char *device_bdf; + +/* + * Limit the number of MSIs enabled/disabled by the test regardless of the + * number of MSIs the device itself supports, e.g. to avoid hitting IRTE limits. + */ +#define MAX_TEST_MSI 16U + +FIXTURE(vfio_pci_device_test) { + struct vfio_pci_device *device; +}; + +FIXTURE_SETUP(vfio_pci_device_test) +{ + self->device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); +} + +FIXTURE_TEARDOWN(vfio_pci_device_test) +{ + vfio_pci_device_cleanup(self->device); +} + +TEST_F(vfio_pci_device_test, dma_map_unmap) +{ + const u64 size = SZ_2M; + void *mem; + u64 iova; + + mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(mem, MAP_FAILED); + + iova = (u64)mem; + + vfio_pci_dma_map(self->device, iova, size, mem); + printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", mem, size, iova); + vfio_pci_dma_unmap(self->device, iova, size); + + ASSERT_TRUE(!munmap(mem, SZ_2M)); +} + +#define read_pci_id_from_sysfs(_file) ({ \ + char __sysfs_path[PATH_MAX]; \ + char __buf[32]; \ + int __fd; \ + \ + snprintf(__sysfs_path, PATH_MAX, "/sys/bus/pci/devices/%s/%s", device_bdf, _file); \ + ASSERT_GT((__fd = open(__sysfs_path, O_RDONLY)), 0); \ + ASSERT_GT(read(__fd, __buf, ARRAY_SIZE(__buf)), 0); \ + ASSERT_EQ(0, close(__fd)); \ + (u16)strtoul(__buf, NULL, 0); \ +}) + +TEST_F(vfio_pci_device_test, config_space_read_write) +{ + u16 vendor, device; + u16 command; + + /* Check that Vendor and Device match what the kernel reports. */ + vendor = read_pci_id_from_sysfs("vendor"); + device = read_pci_id_from_sysfs("device"); + + ASSERT_EQ(vendor, vfio_pci_config_readw(self->device, PCI_VENDOR_ID)); + ASSERT_EQ(device, vfio_pci_config_readw(self->device, PCI_DEVICE_ID)); + + printf("Vendor: %04x, Device: %04x\n", vendor, device); + + command = vfio_pci_config_readw(self->device, PCI_COMMAND); + ASSERT_FALSE(command & PCI_COMMAND_MASTER); + + vfio_pci_config_writew(self->device, PCI_COMMAND, command | PCI_COMMAND_MASTER); + command = vfio_pci_config_readw(self->device, PCI_COMMAND); + ASSERT_TRUE(command & PCI_COMMAND_MASTER); + printf("Enabled Bus Mastering (command: %04x)\n", command); + + vfio_pci_config_writew(self->device, PCI_COMMAND, command & ~PCI_COMMAND_MASTER); + command = vfio_pci_config_readw(self->device, PCI_COMMAND); + ASSERT_FALSE(command & PCI_COMMAND_MASTER); + printf("Disabled Bus Mastering (command: %04x)\n", command); +} + +TEST_F(vfio_pci_device_test, validate_bars) +{ + struct vfio_pci_bar *bar; + int i; + + for (i = 0; i < PCI_STD_NUM_BARS; i++) { + bar = &self->device->bars[i]; + + if (!(bar->info.flags & VFIO_REGION_INFO_FLAG_MMAP)) { + printf("BAR %d does not support mmap()\n", i); + ASSERT_EQ(NULL, bar->vaddr); + continue; + } + + /* + * BARs that support mmap() should be automatically mapped by + * vfio_pci_device_init(). + */ + ASSERT_NE(NULL, bar->vaddr); + ASSERT_NE(0, bar->info.size); + printf("BAR %d mapped at %p (size 0x%llx)\n", i, bar->vaddr, bar->info.size); + } +} + +FIXTURE(vfio_pci_irq_test) { + struct vfio_pci_device *device; +}; + +FIXTURE_VARIANT(vfio_pci_irq_test) { + int irq_index; +}; + +FIXTURE_VARIANT_ADD(vfio_pci_irq_test, msi) { + .irq_index = VFIO_PCI_MSI_IRQ_INDEX, +}; + +FIXTURE_VARIANT_ADD(vfio_pci_irq_test, msix) { + .irq_index = VFIO_PCI_MSIX_IRQ_INDEX, +}; + +FIXTURE_SETUP(vfio_pci_irq_test) +{ + self->device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); +} + +FIXTURE_TEARDOWN(vfio_pci_irq_test) +{ + vfio_pci_device_cleanup(self->device); +} + +TEST_F(vfio_pci_irq_test, enable_trigger_disable) +{ + bool msix = variant->irq_index == VFIO_PCI_MSIX_IRQ_INDEX; + u32 count; + u64 value; + int i; + + if (msix) + count = self->device->msix_info.count; + else + count = self->device->msi_info.count; + + count = min(count, MAX_TEST_MSI); + + if (!count) + SKIP(return, "MSI%s: not supported\n", msix ? "-x" : ""); + + vfio_pci_irq_enable(self->device, variant->irq_index, 0, count); + printf("MSI%s: enabled %d interrupts\n", msix ? "-x" : "", count); + + for (i = 0; i < count; i++) { + vfio_pci_irq_trigger(self->device, variant->irq_index, i); + ASSERT_EQ(8, read(self->device->msi_eventfds[i], &value, 8)); + ASSERT_EQ(1, value); + } + + vfio_pci_irq_disable(self->device, variant->irq_index); +} + +int main(int argc, char *argv[]) +{ + device_bdf = vfio_selftests_get_bdf(&argc, argv); + return test_harness_run(argc, argv); +} From 790588f06e9ce58c281faeada453f47361bc06b6 Mon Sep 17 00:00:00 2001 From: Josh Hilke Date: Fri, 22 Aug 2025 21:24:51 +0000 Subject: [PATCH 0587/2711] vfio: selftests: Test basic VFIO and IOMMUFD integration Add a vfio test suite which verifies that userspace can bind and unbind devices, allocate I/O address space, and attach a device to an IOMMU domain using the cdev + IOMMUfd VFIO interface. Signed-off-by: Josh Hilke Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-5-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/Makefile | 1 + .../selftests/vfio/vfio_iommufd_setup_test.c | 157 ++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 tools/testing/selftests/vfio/vfio_iommufd_setup_test.c diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile index 828419537250..e4a5d6eadff3 100644 --- a/tools/testing/selftests/vfio/Makefile +++ b/tools/testing/selftests/vfio/Makefile @@ -1,4 +1,5 @@ CFLAGS = $(KHDR_INCLUDES) +TEST_GEN_PROGS += vfio_iommufd_setup_test TEST_GEN_PROGS += vfio_pci_device_test include ../lib.mk include lib/libvfio.mk diff --git a/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c b/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c new file mode 100644 index 000000000000..f45335d9260f --- /dev/null +++ b/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "../kselftest_harness.h" + +static const char iommu_dev_path[] = "/dev/iommu"; +static char cdev_path[PATH_MAX] = { '\0' }; + +static void set_cdev_path(const char *bdf) +{ + char dir_path[PATH_MAX]; + DIR *dir; + struct dirent *entry; + + snprintf(dir_path, sizeof(dir_path), "/sys/bus/pci/devices/%s/vfio-dev/", bdf); + + dir = opendir(dir_path); + assert(dir); + + /* Find the file named "vfio" */ + while ((entry = readdir(dir)) != NULL) { + if (!strncmp("vfio", entry->d_name, 4)) { + snprintf(cdev_path, sizeof(cdev_path), "/dev/vfio/devices/%s", + entry->d_name); + break; + } + } + + assert(strlen(cdev_path) > 0); + + closedir(dir); +} + +static int vfio_device_bind_iommufd_ioctl(int cdev_fd, int iommufd) +{ + struct vfio_device_bind_iommufd bind_args = { + .argsz = sizeof(bind_args), + .iommufd = iommufd, + }; + + return ioctl(cdev_fd, VFIO_DEVICE_BIND_IOMMUFD, &bind_args); +} + +static int vfio_device_get_info_ioctl(int cdev_fd) +{ + struct vfio_device_info info_args = { .argsz = sizeof(info_args) }; + + return ioctl(cdev_fd, VFIO_DEVICE_GET_INFO, &info_args); +} + +static int vfio_device_ioas_alloc_ioctl(int iommufd, struct iommu_ioas_alloc *alloc_args) +{ + *alloc_args = (struct iommu_ioas_alloc){ + .size = sizeof(struct iommu_ioas_alloc), + }; + + return ioctl(iommufd, IOMMU_IOAS_ALLOC, alloc_args); +} + +static int vfio_device_attach_iommufd_pt_ioctl(int cdev_fd, u32 pt_id) +{ + struct vfio_device_attach_iommufd_pt attach_args = { + .argsz = sizeof(attach_args), + .pt_id = pt_id, + }; + + return ioctl(cdev_fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &attach_args); +} + +static int vfio_device_detach_iommufd_pt_ioctl(int cdev_fd) +{ + struct vfio_device_detach_iommufd_pt detach_args = { + .argsz = sizeof(detach_args), + }; + + return ioctl(cdev_fd, VFIO_DEVICE_DETACH_IOMMUFD_PT, &detach_args); +} + +FIXTURE(vfio_cdev) { + int cdev_fd; + int iommufd; +}; + +FIXTURE_SETUP(vfio_cdev) +{ + ASSERT_LE(0, (self->cdev_fd = open(cdev_path, O_RDWR, 0))); + ASSERT_LE(0, (self->iommufd = open(iommu_dev_path, O_RDWR, 0))); +} + +FIXTURE_TEARDOWN(vfio_cdev) +{ + ASSERT_EQ(0, close(self->cdev_fd)); + ASSERT_EQ(0, close(self->iommufd)); +} + +TEST_F(vfio_cdev, bind) +{ + ASSERT_EQ(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, self->iommufd)); + ASSERT_EQ(0, vfio_device_get_info_ioctl(self->cdev_fd)); +} + +TEST_F(vfio_cdev, get_info_without_bind_fails) +{ + ASSERT_NE(0, vfio_device_get_info_ioctl(self->cdev_fd)); +} + +TEST_F(vfio_cdev, bind_bad_iommufd_fails) +{ + ASSERT_NE(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, -2)); +} + +TEST_F(vfio_cdev, repeated_bind_fails) +{ + ASSERT_EQ(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, self->iommufd)); + ASSERT_NE(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, self->iommufd)); +} + +TEST_F(vfio_cdev, attach_detatch_pt) +{ + struct iommu_ioas_alloc alloc_args; + + ASSERT_EQ(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, self->iommufd)); + ASSERT_EQ(0, vfio_device_ioas_alloc_ioctl(self->iommufd, &alloc_args)); + ASSERT_EQ(0, vfio_device_attach_iommufd_pt_ioctl(self->cdev_fd, alloc_args.out_ioas_id)); + ASSERT_EQ(0, vfio_device_detach_iommufd_pt_ioctl(self->cdev_fd)); +} + +TEST_F(vfio_cdev, attach_invalid_pt_fails) +{ + ASSERT_EQ(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, self->iommufd)); + ASSERT_NE(0, vfio_device_attach_iommufd_pt_ioctl(self->cdev_fd, UINT32_MAX)); +} + +int main(int argc, char *argv[]) +{ + const char *device_bdf = vfio_selftests_get_bdf(&argc, argv); + + set_cdev_path(device_bdf); + printf("Using cdev device %s\n", cdev_path); + + return test_harness_run(argc, argv); +} From b477e7bcd25ecb4da91bb52d5f980611cc77d543 Mon Sep 17 00:00:00 2001 From: Josh Hilke Date: Fri, 22 Aug 2025 21:24:52 +0000 Subject: [PATCH 0588/2711] vfio: selftests: Move vfio dma mapping test to their own file Move the dma_map_unmap test from vfio_pci_device_test to a new test: vfio_dma_mapping_test. We are going to add more complex dma mapping tests, so it makes sense to separate this from the vfio pci device test which is more of a sanity check for vfio pci functionality. Signed-off-by: Josh Hilke Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-6-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/Makefile | 1 + .../selftests/vfio/vfio_dma_mapping_test.c | 51 +++++++++++++++++++ .../selftests/vfio/vfio_pci_device_test.c | 18 ------- 3 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 tools/testing/selftests/vfio/vfio_dma_mapping_test.c diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile index e4a5d6eadff3..05c5a585cca6 100644 --- a/tools/testing/selftests/vfio/Makefile +++ b/tools/testing/selftests/vfio/Makefile @@ -1,4 +1,5 @@ CFLAGS = $(KHDR_INCLUDES) +TEST_GEN_PROGS += vfio_dma_mapping_test TEST_GEN_PROGS += vfio_iommufd_setup_test TEST_GEN_PROGS += vfio_pci_device_test include ../lib.mk diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c new file mode 100644 index 000000000000..b56cebbf97eb --- /dev/null +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include + +#include + +#include +#include + +#include + +#include "../kselftest_harness.h" + +static const char *device_bdf; + +FIXTURE(vfio_dma_mapping_test) { + struct vfio_pci_device *device; +}; + +FIXTURE_SETUP(vfio_dma_mapping_test) +{ + self->device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); +} + +FIXTURE_TEARDOWN(vfio_dma_mapping_test) +{ + vfio_pci_device_cleanup(self->device); +} + +TEST_F(vfio_dma_mapping_test, dma_map_unmap) +{ + const u64 size = SZ_2M; + void *mem; + u64 iova; + + mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(mem, MAP_FAILED); + + iova = (u64)mem; + + vfio_pci_dma_map(self->device, iova, size, mem); + printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", mem, size, iova); + vfio_pci_dma_unmap(self->device, iova, size); + + ASSERT_TRUE(!munmap(mem, size)); +} + +int main(int argc, char *argv[]) +{ + device_bdf = vfio_selftests_get_bdf(&argc, argv); + return test_harness_run(argc, argv); +} diff --git a/tools/testing/selftests/vfio/vfio_pci_device_test.c b/tools/testing/selftests/vfio/vfio_pci_device_test.c index 3e7049b9c8f6..a2e41398d184 100644 --- a/tools/testing/selftests/vfio/vfio_pci_device_test.c +++ b/tools/testing/selftests/vfio/vfio_pci_device_test.c @@ -36,24 +36,6 @@ FIXTURE_TEARDOWN(vfio_pci_device_test) vfio_pci_device_cleanup(self->device); } -TEST_F(vfio_pci_device_test, dma_map_unmap) -{ - const u64 size = SZ_2M; - void *mem; - u64 iova; - - mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - ASSERT_NE(mem, MAP_FAILED); - - iova = (u64)mem; - - vfio_pci_dma_map(self->device, iova, size, mem); - printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", mem, size, iova); - vfio_pci_dma_unmap(self->device, iova, size); - - ASSERT_TRUE(!munmap(mem, SZ_2M)); -} - #define read_pci_id_from_sysfs(_file) ({ \ char __sysfs_path[PATH_MAX]; \ char __buf[32]; \ From a0fd0af504f7fe11e2f87e48a1924d7e7f5a0590 Mon Sep 17 00:00:00 2001 From: Josh Hilke Date: Fri, 22 Aug 2025 21:24:53 +0000 Subject: [PATCH 0589/2711] vfio: selftests: Add test to reset vfio device. Add a test to vfio_pci_device_test which resets the device. If reset is not supported by the device, the test is skipped. Signed-off-by: Josh Hilke Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-7-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/lib/include/vfio_util.h | 1 + tools/testing/selftests/vfio/lib/vfio_pci_device.c | 5 +++++ tools/testing/selftests/vfio/vfio_pci_device_test.c | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index b7d2bb8c18ba..234403b442af 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -83,6 +83,7 @@ const char *vfio_selftests_get_bdf(int *argc, char *argv[]); struct vfio_pci_device *vfio_pci_device_init(const char *bdf, int iommu_type); void vfio_pci_device_cleanup(struct vfio_pci_device *device); +void vfio_pci_device_reset(struct vfio_pci_device *device); void vfio_pci_dma_map(struct vfio_pci_device *device, u64 iova, u64 size, void *vaddr); diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index 76adb1841f16..98cce0a6ecd7 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -202,6 +202,11 @@ void vfio_pci_config_access(struct vfio_pci_device *device, bool write, write ? "write to" : "read from", config); } +void vfio_pci_device_reset(struct vfio_pci_device *device) +{ + ioctl_assert(device->fd, VFIO_DEVICE_RESET, NULL); +} + static unsigned int vfio_pci_get_group_from_dev(const char *bdf) { char dev_iommu_group_path[PATH_MAX] = {0}; diff --git a/tools/testing/selftests/vfio/vfio_pci_device_test.c b/tools/testing/selftests/vfio/vfio_pci_device_test.c index a2e41398d184..82e3c947f45d 100644 --- a/tools/testing/selftests/vfio/vfio_pci_device_test.c +++ b/tools/testing/selftests/vfio/vfio_pci_device_test.c @@ -155,6 +155,14 @@ TEST_F(vfio_pci_irq_test, enable_trigger_disable) vfio_pci_irq_disable(self->device, variant->irq_index); } +TEST_F(vfio_pci_device_test, reset) +{ + if (!(self->device->info.flags & VFIO_DEVICE_FLAGS_RESET)) + SKIP(return, "Device does not support reset\n"); + + vfio_pci_device_reset(self->device); +} + int main(int argc, char *argv[]) { device_bdf = vfio_selftests_get_bdf(&argc, argv); From 751f6b5d06c301b329b699ab2089c9dcb7eebc47 Mon Sep 17 00:00:00 2001 From: Josh Hilke Date: Fri, 22 Aug 2025 21:24:54 +0000 Subject: [PATCH 0590/2711] vfio: selftests: Add DMA mapping tests for 2M and 1G HugeTLB Add test coverage of mapping 2M and 1G HugeTLB to vfio_dma_mapping_test using a fixture variant. If there isn't enough HugeTLB memory available for the test, just skip them. Signed-off-by: Josh Hilke [switch from command line option to fixture variant] Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-8-dmatlack@google.com Signed-off-by: Alex Williamson --- .../selftests/vfio/vfio_dma_mapping_test.c | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c index b56cebbf97eb..8f8e6e9e8197 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only -#include - +#include #include +#include +#include +#include #include #include @@ -16,6 +18,25 @@ FIXTURE(vfio_dma_mapping_test) { struct vfio_pci_device *device; }; +FIXTURE_VARIANT(vfio_dma_mapping_test) { + u64 size; + int mmap_flags; +}; + +FIXTURE_VARIANT_ADD(vfio_dma_mapping_test, anonymous) { + .mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE, +}; + +FIXTURE_VARIANT_ADD(vfio_dma_mapping_test, anonymous_hugetlb_2mb) { + .size = SZ_2M, + .mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_2MB, +}; + +FIXTURE_VARIANT_ADD(vfio_dma_mapping_test, anonymous_hugetlb_1gb) { + .size = SZ_1G, + .mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_1GB, +}; + FIXTURE_SETUP(vfio_dma_mapping_test) { self->device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); @@ -28,17 +49,24 @@ FIXTURE_TEARDOWN(vfio_dma_mapping_test) TEST_F(vfio_dma_mapping_test, dma_map_unmap) { - const u64 size = SZ_2M; + const u64 size = variant->size ?: getpagesize(); + const int flags = variant->mmap_flags; void *mem; u64 iova; - mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); - ASSERT_NE(mem, MAP_FAILED); + mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); + + /* Skip the test if there aren't enough HugeTLB pages available. */ + if (flags & MAP_HUGETLB && mem == MAP_FAILED) + SKIP(return, "mmap() failed: %s (%d)\n", strerror(errno), errno); + else + ASSERT_NE(mem, MAP_FAILED); iova = (u64)mem; vfio_pci_dma_map(self->device, iova, size, mem); printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", mem, size, iova); + vfio_pci_dma_unmap(self->device, iova, size); ASSERT_TRUE(!munmap(mem, size)); From 47f861048ef7034a59431020c5916a43378a8c0c Mon Sep 17 00:00:00 2001 From: Josh Hilke Date: Fri, 22 Aug 2025 21:24:55 +0000 Subject: [PATCH 0591/2711] vfio: selftests: Validate 2M/1G HugeTLB are mapped as 2M/1G in IOMMU Update vfio dma mapping test to verify that the IOMMU uses 2M and 1G mappings when 2M and 1G HugeTLB pages are mapped into a device respectively. This validation is done by inspecting the contents of the I/O page tables via /sys/kernel/debug/iommu/intel/. This validation is skipped if that directory is not available (i.e. non-Intel IOMMUs). Signed-off-by: Josh Hilke [reword commit message, refactor code] Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-9-dmatlack@google.com Signed-off-by: Alex Williamson --- .../selftests/vfio/vfio_dma_mapping_test.c | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c index 8f8e6e9e8197..2612f0cabea5 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -14,6 +14,83 @@ static const char *device_bdf; +struct iommu_mapping { + u64 pgd; + u64 p4d; + u64 pud; + u64 pmd; + u64 pte; +}; + +static void parse_next_value(char **line, u64 *value) +{ + char *token; + + token = strtok_r(*line, " \t|\n", line); + if (!token) + return; + + /* Caller verifies `value`. No need to check return value. */ + sscanf(token, "0x%lx", value); +} + +static int intel_iommu_mapping_get(const char *bdf, u64 iova, + struct iommu_mapping *mapping) +{ + char iommu_mapping_path[PATH_MAX], line[PATH_MAX]; + u64 line_iova = -1; + int ret = -ENOENT; + FILE *file; + char *rest; + + snprintf(iommu_mapping_path, sizeof(iommu_mapping_path), + "/sys/kernel/debug/iommu/intel/%s/domain_translation_struct", + bdf); + + printf("Searching for IOVA 0x%lx in %s\n", iova, iommu_mapping_path); + + file = fopen(iommu_mapping_path, "r"); + VFIO_ASSERT_NOT_NULL(file, "fopen(%s) failed", iommu_mapping_path); + + while (fgets(line, sizeof(line), file)) { + rest = line; + + parse_next_value(&rest, &line_iova); + if (line_iova != (iova / getpagesize())) + continue; + + /* + * Ensure each struct field is initialized in case of empty + * page table values. + */ + memset(mapping, 0, sizeof(*mapping)); + parse_next_value(&rest, &mapping->pgd); + parse_next_value(&rest, &mapping->p4d); + parse_next_value(&rest, &mapping->pud); + parse_next_value(&rest, &mapping->pmd); + parse_next_value(&rest, &mapping->pte); + + ret = 0; + break; + } + + fclose(file); + + if (ret) + printf("IOVA not found\n"); + + return ret; +} + +static int iommu_mapping_get(const char *bdf, u64 iova, + struct iommu_mapping *mapping) +{ + if (!access("/sys/kernel/debug/iommu/intel", F_OK)) + return intel_iommu_mapping_get(bdf, iova, mapping); + + return -EOPNOTSUPP; +} + FIXTURE(vfio_dma_mapping_test) { struct vfio_pci_device *device; }; @@ -51,8 +128,10 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) { const u64 size = variant->size ?: getpagesize(); const int flags = variant->mmap_flags; + struct iommu_mapping mapping; void *mem; u64 iova; + int rc; mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); @@ -67,7 +146,39 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) vfio_pci_dma_map(self->device, iova, size, mem); printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", mem, size, iova); + rc = iommu_mapping_get(device_bdf, iova, &mapping); + if (rc == -EOPNOTSUPP) + goto unmap; + + ASSERT_EQ(0, rc); + printf("Found IOMMU mappings for IOVA 0x%lx:\n", iova); + printf("PGD: 0x%016lx\n", mapping.pgd); + printf("P4D: 0x%016lx\n", mapping.p4d); + printf("PUD: 0x%016lx\n", mapping.pud); + printf("PMD: 0x%016lx\n", mapping.pmd); + printf("PTE: 0x%016lx\n", mapping.pte); + + switch (size) { + case SZ_4K: + ASSERT_NE(0, mapping.pte); + break; + case SZ_2M: + ASSERT_EQ(0, mapping.pte); + ASSERT_NE(0, mapping.pmd); + break; + case SZ_1G: + ASSERT_EQ(0, mapping.pte); + ASSERT_EQ(0, mapping.pmd); + ASSERT_NE(0, mapping.pud); + break; + default: + VFIO_FAIL("Unrecognized size: 0x%lx\n", size); + } + +unmap: vfio_pci_dma_unmap(self->device, iova, size); + printf("Unmapped IOVA 0x%lx\n", iova); + ASSERT_NE(0, iommu_mapping_get(device_bdf, iova, &mapping)); ASSERT_TRUE(!munmap(mem, size)); } From 346cd58f1fb588f8ff193d76cf0bb455446ace03 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:24:56 +0000 Subject: [PATCH 0592/2711] vfio: selftests: Keep track of DMA regions mapped into the device Keep track of the list of DMA regions that are mapped into the device using a linked list and a new struct vfio_dma_region and use that to add {__,}to_iova() for converting host virtual addresses into IOVAs. This will be used in a subsequent commit to map multiple DMA regions into a device that are then used by drivers. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-10-dmatlack@google.com Signed-off-by: Alex Williamson --- .../selftests/vfio/lib/include/vfio_util.h | 23 +++++++-- .../selftests/vfio/lib/vfio_pci_device.c | 49 ++++++++++++++++--- .../selftests/vfio/vfio_dma_mapping_test.c | 31 ++++++------ 3 files changed, 79 insertions(+), 24 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index 234403b442af..db08646c2819 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -51,6 +51,17 @@ struct vfio_pci_bar { void *vaddr; }; +typedef u64 iova_t; + +#define INVALID_IOVA UINT64_MAX + +struct vfio_dma_region { + struct list_head link; + void *vaddr; + iova_t iova; + u64 size; +}; + struct vfio_pci_device { int fd; int group_fd; @@ -63,6 +74,8 @@ struct vfio_pci_device { struct vfio_irq_info msi_info; struct vfio_irq_info msix_info; + struct list_head dma_regions; + /* eventfds for MSI and MSI-x interrupts */ int msi_eventfds[PCI_MSIX_FLAGS_QSIZE + 1]; }; @@ -85,9 +98,10 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, int iommu_type); void vfio_pci_device_cleanup(struct vfio_pci_device *device); void vfio_pci_device_reset(struct vfio_pci_device *device); -void vfio_pci_dma_map(struct vfio_pci_device *device, u64 iova, u64 size, - void *vaddr); -void vfio_pci_dma_unmap(struct vfio_pci_device *device, u64 iova, u64 size); +void vfio_pci_dma_map(struct vfio_pci_device *device, + struct vfio_dma_region *region); +void vfio_pci_dma_unmap(struct vfio_pci_device *device, + struct vfio_dma_region *region); void vfio_pci_config_access(struct vfio_pci_device *device, bool write, size_t config, size_t size, void *data); @@ -138,4 +152,7 @@ static inline void vfio_pci_msix_disable(struct vfio_pci_device *device) vfio_pci_irq_disable(device, VFIO_PCI_MSIX_IRQ_INDEX); } +iova_t __to_iova(struct vfio_pci_device *device, void *vaddr); +iova_t to_iova(struct vfio_pci_device *device, void *vaddr); + #endif /* SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H */ diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index 98cce0a6ecd7..36b4b30b75cf 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -26,6 +26,33 @@ VFIO_ASSERT_EQ(__ret, 0, "ioctl(%s, %s, %s) returned %d\n", #_fd, #_op, #_arg, __ret); \ } while (0) +iova_t __to_iova(struct vfio_pci_device *device, void *vaddr) +{ + struct vfio_dma_region *region; + + list_for_each_entry(region, &device->dma_regions, link) { + if (vaddr < region->vaddr) + continue; + + if (vaddr >= region->vaddr + region->size) + continue; + + return region->iova + (vaddr - region->vaddr); + } + + return INVALID_IOVA; +} + +iova_t to_iova(struct vfio_pci_device *device, void *vaddr) +{ + iova_t iova; + + iova = __to_iova(device, vaddr); + VFIO_ASSERT_NE(iova, INVALID_IOVA, "%p is not mapped into device.\n", vaddr); + + return iova; +} + static void vfio_pci_irq_set(struct vfio_pci_device *device, u32 index, u32 vector, u32 count, int *fds) { @@ -112,28 +139,34 @@ static void vfio_pci_irq_get(struct vfio_pci_device *device, u32 index, ioctl_assert(device->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info); } -void vfio_pci_dma_map(struct vfio_pci_device *device, u64 iova, u64 size, void *vaddr) +void vfio_pci_dma_map(struct vfio_pci_device *device, + struct vfio_dma_region *region) { struct vfio_iommu_type1_dma_map map = { .argsz = sizeof(map), .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE, - .vaddr = (u64)vaddr, - .iova = iova, - .size = size, + .vaddr = (u64)region->vaddr, + .iova = region->iova, + .size = region->size, }; ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &map); + + list_add(®ion->link, &device->dma_regions); } -void vfio_pci_dma_unmap(struct vfio_pci_device *device, u64 iova, u64 size) +void vfio_pci_dma_unmap(struct vfio_pci_device *device, + struct vfio_dma_region *region) { struct vfio_iommu_type1_dma_unmap unmap = { .argsz = sizeof(unmap), - .iova = iova, - .size = size, + .iova = region->iova, + .size = region->size, }; ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &unmap); + + list_del(®ion->link); } static void vfio_pci_region_get(struct vfio_pci_device *device, int index, @@ -260,6 +293,8 @@ static void vfio_pci_iommu_setup(struct vfio_pci_device *device, unsigned long i { int ret; + INIT_LIST_HEAD(&device->dma_regions); + ret = ioctl(device->container_fd, VFIO_CHECK_EXTENSION, iommu_type); VFIO_ASSERT_GT(ret, 0, "VFIO IOMMU type %lu not supported\n", iommu_type); diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c index 2612f0cabea5..4578ee6df0e1 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -128,30 +128,32 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) { const u64 size = variant->size ?: getpagesize(); const int flags = variant->mmap_flags; + struct vfio_dma_region region; struct iommu_mapping mapping; - void *mem; - u64 iova; int rc; - mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); + region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); /* Skip the test if there aren't enough HugeTLB pages available. */ - if (flags & MAP_HUGETLB && mem == MAP_FAILED) + if (flags & MAP_HUGETLB && region.vaddr == MAP_FAILED) SKIP(return, "mmap() failed: %s (%d)\n", strerror(errno), errno); else - ASSERT_NE(mem, MAP_FAILED); + ASSERT_NE(region.vaddr, MAP_FAILED); - iova = (u64)mem; + region.iova = (u64)region.vaddr; + region.size = size; - vfio_pci_dma_map(self->device, iova, size, mem); - printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", mem, size, iova); + vfio_pci_dma_map(self->device, ®ion); + printf("Mapped HVA %p (size 0x%lx) at IOVA 0x%lx\n", region.vaddr, size, region.iova); - rc = iommu_mapping_get(device_bdf, iova, &mapping); + ASSERT_EQ(region.iova, to_iova(self->device, region.vaddr)); + + rc = iommu_mapping_get(device_bdf, region.iova, &mapping); if (rc == -EOPNOTSUPP) goto unmap; ASSERT_EQ(0, rc); - printf("Found IOMMU mappings for IOVA 0x%lx:\n", iova); + printf("Found IOMMU mappings for IOVA 0x%lx:\n", region.iova); printf("PGD: 0x%016lx\n", mapping.pgd); printf("P4D: 0x%016lx\n", mapping.p4d); printf("PUD: 0x%016lx\n", mapping.pud); @@ -176,11 +178,12 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) } unmap: - vfio_pci_dma_unmap(self->device, iova, size); - printf("Unmapped IOVA 0x%lx\n", iova); - ASSERT_NE(0, iommu_mapping_get(device_bdf, iova, &mapping)); + vfio_pci_dma_unmap(self->device, ®ion); + printf("Unmapped IOVA 0x%lx\n", region.iova); + ASSERT_EQ(INVALID_IOVA, __to_iova(self->device, region.vaddr)); + ASSERT_NE(0, iommu_mapping_get(device_bdf, region.iova, &mapping)); - ASSERT_TRUE(!munmap(mem, size)); + ASSERT_TRUE(!munmap(region.vaddr, size)); } int main(int argc, char *argv[]) From 924947804f2b9e564efdc814420d21b239df2dd4 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:24:57 +0000 Subject: [PATCH 0593/2711] vfio: selftests: Enable asserting MSI eventfds not firing Make it possible to assert that a given MSI eventfd did _not_ fire by adding a helper to mark an eventfd non-blocking. Demonstrate this in vfio_pci_device_test by asserting the MSI eventfd did not fire before vfio_pci_irq_trigger(). Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-11-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/lib/include/vfio_util.h | 12 ++++++++++++ tools/testing/selftests/vfio/vfio_pci_device_test.c | 10 +++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index db08646c2819..9c928fcc00e2 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -2,6 +2,7 @@ #ifndef SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H #define SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H +#include #include #include #include @@ -130,6 +131,17 @@ void vfio_pci_irq_enable(struct vfio_pci_device *device, u32 index, void vfio_pci_irq_disable(struct vfio_pci_device *device, u32 index); void vfio_pci_irq_trigger(struct vfio_pci_device *device, u32 index, u32 vector); +static inline void fcntl_set_nonblock(int fd) +{ + int r; + + r = fcntl(fd, F_GETFL, 0); + VFIO_ASSERT_NE(r, -1, "F_GETFL failed for fd %d\n", fd); + + r = fcntl(fd, F_SETFL, r | O_NONBLOCK); + VFIO_ASSERT_NE(r, -1, "F_SETFL O_NONBLOCK failed for fd %d\n", fd); +} + static inline void vfio_pci_msi_enable(struct vfio_pci_device *device, u32 vector, int count) { diff --git a/tools/testing/selftests/vfio/vfio_pci_device_test.c b/tools/testing/selftests/vfio/vfio_pci_device_test.c index 82e3c947f45d..1b5c2ff77e3f 100644 --- a/tools/testing/selftests/vfio/vfio_pci_device_test.c +++ b/tools/testing/selftests/vfio/vfio_pci_device_test.c @@ -129,6 +129,7 @@ FIXTURE_TEARDOWN(vfio_pci_irq_test) TEST_F(vfio_pci_irq_test, enable_trigger_disable) { bool msix = variant->irq_index == VFIO_PCI_MSIX_IRQ_INDEX; + int msi_eventfd; u32 count; u64 value; int i; @@ -147,8 +148,15 @@ TEST_F(vfio_pci_irq_test, enable_trigger_disable) printf("MSI%s: enabled %d interrupts\n", msix ? "-x" : "", count); for (i = 0; i < count; i++) { + msi_eventfd = self->device->msi_eventfds[i]; + + fcntl_set_nonblock(msi_eventfd); + ASSERT_EQ(-1, read(msi_eventfd, &value, 8)); + ASSERT_EQ(EAGAIN, errno); + vfio_pci_irq_trigger(self->device, variant->irq_index, i); - ASSERT_EQ(8, read(self->device->msi_eventfds[i], &value, 8)); + + ASSERT_EQ(8, read(msi_eventfd, &value, 8)); ASSERT_EQ(1, value); } From 50d8fe805f75a159551ddb6b04ecdad26ec50221 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:24:58 +0000 Subject: [PATCH 0594/2711] vfio: selftests: Add a helper for matching vendor+device IDs Add a helper function for matching a device against a given vendor and device ID. This will be used in a subsequent commit to match devices against drivers. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-12-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/lib/include/vfio_util.h | 7 +++++++ tools/testing/selftests/vfio/vfio_pci_device_test.c | 4 +--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index 9c928fcc00e2..a51c971004cd 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -167,4 +167,11 @@ static inline void vfio_pci_msix_disable(struct vfio_pci_device *device) iova_t __to_iova(struct vfio_pci_device *device, void *vaddr); iova_t to_iova(struct vfio_pci_device *device, void *vaddr); +static inline bool vfio_pci_device_match(struct vfio_pci_device *device, + u16 vendor_id, u16 device_id) +{ + return (vendor_id == vfio_pci_config_readw(device, PCI_VENDOR_ID)) && + (device_id == vfio_pci_config_readw(device, PCI_DEVICE_ID)); +} + #endif /* SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H */ diff --git a/tools/testing/selftests/vfio/vfio_pci_device_test.c b/tools/testing/selftests/vfio/vfio_pci_device_test.c index 1b5c2ff77e3f..8856205d52a6 100644 --- a/tools/testing/selftests/vfio/vfio_pci_device_test.c +++ b/tools/testing/selftests/vfio/vfio_pci_device_test.c @@ -56,9 +56,7 @@ TEST_F(vfio_pci_device_test, config_space_read_write) /* Check that Vendor and Device match what the kernel reports. */ vendor = read_pci_id_from_sysfs("vendor"); device = read_pci_id_from_sysfs("device"); - - ASSERT_EQ(vendor, vfio_pci_config_readw(self->device, PCI_VENDOR_ID)); - ASSERT_EQ(device, vfio_pci_config_readw(self->device, PCI_DEVICE_ID)); + ASSERT_TRUE(vfio_pci_device_match(self->device, vendor, device)); printf("Vendor: %04x, Device: %04x\n", vendor, device); From 1b197032ac58b9a17350c086fc151390f32080b2 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:24:59 +0000 Subject: [PATCH 0595/2711] vfio: selftests: Add driver framework Add a driver framework to VFIO selftests, so that devices can generate DMA and interrupts in a common way that can be then utilized by tests. This will enable VFIO selftests to exercise real hardware DMA and interrupt paths, without needing any device-specific code in the test itself. Subsequent commits will introduce drivers for specific devices. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-13-dmatlack@google.com Signed-off-by: Alex Williamson --- .../selftests/vfio/lib/include/vfio_util.h | 92 ++++++++++++++ tools/testing/selftests/vfio/lib/libvfio.mk | 1 + .../selftests/vfio/lib/vfio_pci_device.c | 5 + .../selftests/vfio/lib/vfio_pci_driver.c | 116 ++++++++++++++++++ 4 files changed, 214 insertions(+) create mode 100644 tools/testing/selftests/vfio/lib/vfio_pci_driver.c diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index a51c971004cd..a7d05a4299a1 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -63,6 +63,85 @@ struct vfio_dma_region { u64 size; }; +struct vfio_pci_device; + +struct vfio_pci_driver_ops { + const char *name; + + /** + * @probe() - Check if the driver supports the given device. + * + * Return: 0 on success, non-0 on failure. + */ + int (*probe)(struct vfio_pci_device *device); + + /** + * @init() - Initialize the driver for @device. + * + * Must be called after device->driver.region has been initialized. + */ + void (*init)(struct vfio_pci_device *device); + + /** + * remove() - Deinitialize the driver for @device. + */ + void (*remove)(struct vfio_pci_device *device); + + /** + * memcpy_start() - Kick off @count repeated memcpy operations from + * [@src, @src + @size) to [@dst, @dst + @size). + * + * Guarantees: + * - The device will attempt DMA reads on [src, src + size). + * - The device will attempt DMA writes on [dst, dst + size). + * - The device will not generate any interrupts. + * + * memcpy_start() returns immediately, it does not wait for the + * copies to complete. + */ + void (*memcpy_start)(struct vfio_pci_device *device, + iova_t src, iova_t dst, u64 size, u64 count); + + /** + * memcpy_wait() - Wait until the memcpy operations started by + * memcpy_start() have finished. + * + * Guarantees: + * - All in-flight DMAs initiated by memcpy_start() are fully complete + * before memcpy_wait() returns. + * + * Returns non-0 if the driver detects that an error occurred during the + * memcpy, 0 otherwise. + */ + int (*memcpy_wait)(struct vfio_pci_device *device); + + /** + * send_msi() - Make the device send the MSI device->driver.msi. + * + * Guarantees: + * - The device will send the MSI once. + */ + void (*send_msi)(struct vfio_pci_device *device); +}; + +struct vfio_pci_driver { + const struct vfio_pci_driver_ops *ops; + bool initialized; + bool memcpy_in_progress; + + /* Region to be used by the driver (e.g. for in-memory descriptors) */ + struct vfio_dma_region region; + + /* The maximum size that can be passed to memcpy_start(). */ + u64 max_memcpy_size; + + /* The maximum count that can be passed to memcpy_start(). */ + u64 max_memcpy_count; + + /* The MSI vector the device will signal in ops->send_msi(). */ + int msi; +}; + struct vfio_pci_device { int fd; int group_fd; @@ -79,6 +158,8 @@ struct vfio_pci_device { /* eventfds for MSI and MSI-x interrupts */ int msi_eventfds[PCI_MSIX_FLAGS_QSIZE + 1]; + + struct vfio_pci_driver driver; }; /* @@ -174,4 +255,15 @@ static inline bool vfio_pci_device_match(struct vfio_pci_device *device, (device_id == vfio_pci_config_readw(device, PCI_DEVICE_ID)); } +void vfio_pci_driver_probe(struct vfio_pci_device *device); +void vfio_pci_driver_init(struct vfio_pci_device *device); +void vfio_pci_driver_remove(struct vfio_pci_device *device); +int vfio_pci_driver_memcpy(struct vfio_pci_device *device, + iova_t src, iova_t dst, u64 size); +void vfio_pci_driver_memcpy_start(struct vfio_pci_device *device, + iova_t src, iova_t dst, u64 size, + u64 count); +int vfio_pci_driver_memcpy_wait(struct vfio_pci_device *device); +void vfio_pci_driver_send_msi(struct vfio_pci_device *device); + #endif /* SELFTESTS_VFIO_LIB_INCLUDE_VFIO_UTIL_H */ diff --git a/tools/testing/selftests/vfio/lib/libvfio.mk b/tools/testing/selftests/vfio/lib/libvfio.mk index 72e55a560eeb..a3c3bc9a7c00 100644 --- a/tools/testing/selftests/vfio/lib/libvfio.mk +++ b/tools/testing/selftests/vfio/lib/libvfio.mk @@ -1,6 +1,7 @@ VFIO_DIR := $(selfdir)/vfio LIBVFIO_C := lib/vfio_pci_device.c +LIBVFIO_C += lib/vfio_pci_driver.c LIBVFIO_O := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBVFIO_C)) diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index 36b4b30b75cf..d8bb227e869d 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -344,6 +344,8 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, int iommu_type) vfio_pci_iommu_setup(device, iommu_type); vfio_pci_device_setup(device, bdf); + vfio_pci_driver_probe(device); + return device; } @@ -351,6 +353,9 @@ void vfio_pci_device_cleanup(struct vfio_pci_device *device) { int i; + if (device->driver.initialized) + vfio_pci_driver_remove(device); + vfio_pci_bar_unmap_all(device); VFIO_ASSERT_EQ(close(device->fd), 0); diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c new file mode 100644 index 000000000000..c98bd2d31d8a --- /dev/null +++ b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include + +#include "../../../kselftest.h" +#include + +static struct vfio_pci_driver_ops *driver_ops[] = {}; + +void vfio_pci_driver_probe(struct vfio_pci_device *device) +{ + struct vfio_pci_driver_ops *ops; + int i; + + VFIO_ASSERT_NULL(device->driver.ops); + + for (i = 0; i < ARRAY_SIZE(driver_ops); i++) { + ops = driver_ops[i]; + + if (ops->probe(device)) + continue; + + printf("Driver found: %s\n", ops->name); + device->driver.ops = ops; + } +} + +static void vfio_check_driver_op(struct vfio_pci_driver *driver, void *op, + const char *op_name) +{ + VFIO_ASSERT_NOT_NULL(driver->ops); + VFIO_ASSERT_NOT_NULL(op, "Driver has no %s()\n", op_name); + VFIO_ASSERT_EQ(driver->initialized, op != driver->ops->init); + VFIO_ASSERT_EQ(driver->memcpy_in_progress, op == driver->ops->memcpy_wait); +} + +#define VFIO_CHECK_DRIVER_OP(_driver, _op) do { \ + struct vfio_pci_driver *__driver = (_driver); \ + vfio_check_driver_op(__driver, __driver->ops->_op, #_op); \ +} while (0) + +void vfio_pci_driver_init(struct vfio_pci_device *device) +{ + struct vfio_pci_driver *driver = &device->driver; + + VFIO_ASSERT_NOT_NULL(driver->region.vaddr); + VFIO_CHECK_DRIVER_OP(driver, init); + + driver->ops->init(device); + + driver->initialized = true; + + printf("%s: region: vaddr %p, iova 0x%lx, size 0x%lx\n", + driver->ops->name, + driver->region.vaddr, + driver->region.iova, + driver->region.size); + + printf("%s: max_memcpy_size 0x%lx, max_memcpy_count 0x%lx\n", + driver->ops->name, + driver->max_memcpy_size, + driver->max_memcpy_count); +} + +void vfio_pci_driver_remove(struct vfio_pci_device *device) +{ + struct vfio_pci_driver *driver = &device->driver; + + VFIO_CHECK_DRIVER_OP(driver, remove); + + driver->ops->remove(device); + driver->initialized = false; +} + +void vfio_pci_driver_send_msi(struct vfio_pci_device *device) +{ + struct vfio_pci_driver *driver = &device->driver; + + VFIO_CHECK_DRIVER_OP(driver, send_msi); + + driver->ops->send_msi(device); +} + +void vfio_pci_driver_memcpy_start(struct vfio_pci_device *device, + iova_t src, iova_t dst, u64 size, + u64 count) +{ + struct vfio_pci_driver *driver = &device->driver; + + VFIO_ASSERT_LE(size, driver->max_memcpy_size); + VFIO_ASSERT_LE(count, driver->max_memcpy_count); + VFIO_CHECK_DRIVER_OP(driver, memcpy_start); + + driver->ops->memcpy_start(device, src, dst, size, count); + driver->memcpy_in_progress = true; +} + +int vfio_pci_driver_memcpy_wait(struct vfio_pci_device *device) +{ + struct vfio_pci_driver *driver = &device->driver; + int r; + + VFIO_CHECK_DRIVER_OP(driver, memcpy_wait); + + r = driver->ops->memcpy_wait(device); + driver->memcpy_in_progress = false; + + return r; +} + +int vfio_pci_driver_memcpy(struct vfio_pci_device *device, + iova_t src, iova_t dst, u64 size) +{ + vfio_pci_driver_memcpy_start(device, src, dst, size, 1); + + return vfio_pci_driver_memcpy_wait(device); +} From fded8da4bc38df6e1475ac5998934c490b96215d Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:00 +0000 Subject: [PATCH 0596/2711] vfio: sefltests: Add vfio_pci_driver_test Add a new selftest that tests all driver operations. This test serves both as a demonstration of the driver framework, and also as a correctness test for future drivers. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-14-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/Makefile | 1 + .../selftests/vfio/vfio_pci_driver_test.c | 233 ++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 tools/testing/selftests/vfio/vfio_pci_driver_test.c diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile index 05c5a585cca6..ee09c027ade5 100644 --- a/tools/testing/selftests/vfio/Makefile +++ b/tools/testing/selftests/vfio/Makefile @@ -2,6 +2,7 @@ CFLAGS = $(KHDR_INCLUDES) TEST_GEN_PROGS += vfio_dma_mapping_test TEST_GEN_PROGS += vfio_iommufd_setup_test TEST_GEN_PROGS += vfio_pci_device_test +TEST_GEN_PROGS += vfio_pci_driver_test include ../lib.mk include lib/libvfio.mk diff --git a/tools/testing/selftests/vfio/vfio_pci_driver_test.c b/tools/testing/selftests/vfio/vfio_pci_driver_test.c new file mode 100644 index 000000000000..97ed0ff4636d --- /dev/null +++ b/tools/testing/selftests/vfio/vfio_pci_driver_test.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include + +#include +#include + +#include + +#include "../kselftest_harness.h" + +static const char *device_bdf; + +#define ASSERT_NO_MSI(_eventfd) do { \ + u64 __value; \ + \ + ASSERT_EQ(-1, read(_eventfd, &__value, 8)); \ + ASSERT_EQ(EAGAIN, errno); \ +} while (0) + +static void region_setup(struct vfio_pci_device *device, + struct vfio_dma_region *region, u64 size) +{ + const int flags = MAP_SHARED | MAP_ANONYMOUS; + const int prot = PROT_READ | PROT_WRITE; + void *vaddr; + + vaddr = mmap(NULL, size, prot, flags, -1, 0); + VFIO_ASSERT_NE(vaddr, MAP_FAILED); + + region->vaddr = vaddr; + region->iova = (u64)vaddr; + region->size = size; + + vfio_pci_dma_map(device, region); +} + +static void region_teardown(struct vfio_pci_device *device, + struct vfio_dma_region *region) +{ + vfio_pci_dma_unmap(device, region); + VFIO_ASSERT_EQ(munmap(region->vaddr, region->size), 0); +} + +FIXTURE(vfio_pci_driver_test) { + struct vfio_pci_device *device; + struct vfio_dma_region memcpy_region; + void *vaddr; + int msi_fd; + + u64 size; + void *src; + void *dst; + iova_t src_iova; + iova_t dst_iova; + iova_t unmapped_iova; +}; + +FIXTURE_SETUP(vfio_pci_driver_test) +{ + struct vfio_pci_driver *driver; + + self->device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); + + driver = &self->device->driver; + + region_setup(self->device, &self->memcpy_region, SZ_1G); + region_setup(self->device, &driver->region, SZ_2M); + + /* Any IOVA that doesn't overlap memcpy_region and driver->region. */ + self->unmapped_iova = 8UL * SZ_1G; + + vfio_pci_driver_init(self->device); + self->msi_fd = self->device->msi_eventfds[driver->msi]; + + /* + * Use the maximum size supported by the device for memcpy operations, + * slimmed down to fit into the memcpy region (divided by 2 so src and + * dst regions do not overlap). + */ + self->size = self->device->driver.max_memcpy_size; + self->size = min(self->size, self->memcpy_region.size / 2); + + self->src = self->memcpy_region.vaddr; + self->dst = self->src + self->size; + + self->src_iova = to_iova(self->device, self->src); + self->dst_iova = to_iova(self->device, self->dst); +} + +FIXTURE_TEARDOWN(vfio_pci_driver_test) +{ + struct vfio_pci_driver *driver = &self->device->driver; + + vfio_pci_driver_remove(self->device); + + region_teardown(self->device, &self->memcpy_region); + region_teardown(self->device, &driver->region); + + vfio_pci_device_cleanup(self->device); +} + +TEST_F(vfio_pci_driver_test, init_remove) +{ + int i; + + for (i = 0; i < 10; i++) { + vfio_pci_driver_remove(self->device); + vfio_pci_driver_init(self->device); + } +} + +TEST_F(vfio_pci_driver_test, memcpy_success) +{ + fcntl_set_nonblock(self->msi_fd); + + memset(self->src, 'x', self->size); + memset(self->dst, 'y', self->size); + + ASSERT_EQ(0, vfio_pci_driver_memcpy(self->device, + self->src_iova, + self->dst_iova, + self->size)); + + ASSERT_EQ(0, memcmp(self->src, self->dst, self->size)); + ASSERT_NO_MSI(self->msi_fd); +} + +TEST_F(vfio_pci_driver_test, memcpy_from_unmapped_iova) +{ + fcntl_set_nonblock(self->msi_fd); + + /* + * Ignore the return value since not all devices will detect and report + * accesses to unmapped IOVAs as errors. + */ + vfio_pci_driver_memcpy(self->device, self->unmapped_iova, + self->dst_iova, self->size); + + ASSERT_NO_MSI(self->msi_fd); +} + +TEST_F(vfio_pci_driver_test, memcpy_to_unmapped_iova) +{ + fcntl_set_nonblock(self->msi_fd); + + /* + * Ignore the return value since not all devices will detect and report + * accesses to unmapped IOVAs as errors. + */ + vfio_pci_driver_memcpy(self->device, self->src_iova, + self->unmapped_iova, self->size); + + ASSERT_NO_MSI(self->msi_fd); +} + +TEST_F(vfio_pci_driver_test, send_msi) +{ + u64 value; + + vfio_pci_driver_send_msi(self->device); + ASSERT_EQ(8, read(self->msi_fd, &value, 8)); + ASSERT_EQ(1, value); +} + +TEST_F(vfio_pci_driver_test, mix_and_match) +{ + u64 value; + int i; + + for (i = 0; i < 10; i++) { + memset(self->src, 'x', self->size); + memset(self->dst, 'y', self->size); + + ASSERT_EQ(0, vfio_pci_driver_memcpy(self->device, + self->src_iova, + self->dst_iova, + self->size)); + + ASSERT_EQ(0, memcmp(self->src, self->dst, self->size)); + + vfio_pci_driver_memcpy(self->device, + self->unmapped_iova, + self->dst_iova, + self->size); + + vfio_pci_driver_send_msi(self->device); + ASSERT_EQ(8, read(self->msi_fd, &value, 8)); + ASSERT_EQ(1, value); + } +} + +TEST_F_TIMEOUT(vfio_pci_driver_test, memcpy_storm, 60) +{ + struct vfio_pci_driver *driver = &self->device->driver; + u64 total_size; + u64 count; + + fcntl_set_nonblock(self->msi_fd); + + /* + * Perform up to 250GiB worth of DMA reads and writes across several + * memcpy operations. Some devices can support even more but the test + * will take too long. + */ + total_size = 250UL * SZ_1G; + count = min(total_size / self->size, driver->max_memcpy_count); + + printf("Kicking off %lu memcpys of size 0x%lx\n", count, self->size); + vfio_pci_driver_memcpy_start(self->device, + self->src_iova, + self->dst_iova, + self->size, count); + + ASSERT_EQ(0, vfio_pci_driver_memcpy_wait(self->device)); + ASSERT_NO_MSI(self->msi_fd); +} + +int main(int argc, char *argv[]) +{ + struct vfio_pci_device *device; + + device_bdf = vfio_selftests_get_bdf(&argc, argv); + + device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); + if (!device->driver.ops) { + fprintf(stderr, "No driver found for device %s\n", device_bdf); + return KSFT_SKIP; + } + vfio_pci_device_cleanup(device); + + return test_harness_run(argc, argv); +} From 9bf9b185e3ce76c9fddb4c6edb0ec3334b7649df Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:01 +0000 Subject: [PATCH 0597/2711] tools headers: Add stub definition for __iomem Add an empty definition for __iomem so that kernel headers that use __iomem can be imported into tools/include/ with less modifications. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-15-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/include/linux/compiler.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index 33411ca0cc90..f40bd2b04c29 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -138,6 +138,10 @@ # define __force #endif +#ifndef __iomem +# define __iomem +#endif + #ifndef __weak # define __weak __attribute__((weak)) #endif From 1f9c8edd6a7e9b0fd914cfeef8ce075307e8e702 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:02 +0000 Subject: [PATCH 0598/2711] tools headers: Import asm-generic MMIO helpers Import the asm-generic MMIO helper functions from the kernel headers into tools/include/. The top-level include is which then includes the arch-specific , which then includes . This layout is chosen to match the kernel header layout and to appease checkpatch.pl (which warns against including or directly). Changes made when importing: - Add missing includes at the top. - Stub out mmiowb_set_pending(). - Stub out _THIS_IP_. - Stub out log_*_mmio() calls. - Drop the CONFIG_64BIT checks, since tools/include/linux/types.h always defines u64. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-16-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/include/asm-generic/io.h | 482 +++++++++++++++++++++++++++++++++ tools/include/asm/io.h | 7 + tools/include/linux/io.h | 4 +- 3 files changed, 492 insertions(+), 1 deletion(-) create mode 100644 tools/include/asm-generic/io.h create mode 100644 tools/include/asm/io.h diff --git a/tools/include/asm-generic/io.h b/tools/include/asm-generic/io.h new file mode 100644 index 000000000000..e5a0b07ad452 --- /dev/null +++ b/tools/include/asm-generic/io.h @@ -0,0 +1,482 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_ASM_GENERIC_IO_H +#define _TOOLS_ASM_GENERIC_IO_H + +#include +#include + +#include +#include +#include + +#ifndef mmiowb_set_pending +#define mmiowb_set_pending() do { } while (0) +#endif + +#ifndef __io_br +#define __io_br() barrier() +#endif + +/* prevent prefetching of coherent DMA data ahead of a dma-complete */ +#ifndef __io_ar +#ifdef rmb +#define __io_ar(v) rmb() +#else +#define __io_ar(v) barrier() +#endif +#endif + +/* flush writes to coherent DMA data before possibly triggering a DMA read */ +#ifndef __io_bw +#ifdef wmb +#define __io_bw() wmb() +#else +#define __io_bw() barrier() +#endif +#endif + +/* serialize device access against a spin_unlock, usually handled there. */ +#ifndef __io_aw +#define __io_aw() mmiowb_set_pending() +#endif + +#ifndef __io_pbw +#define __io_pbw() __io_bw() +#endif + +#ifndef __io_paw +#define __io_paw() __io_aw() +#endif + +#ifndef __io_pbr +#define __io_pbr() __io_br() +#endif + +#ifndef __io_par +#define __io_par(v) __io_ar(v) +#endif + +#ifndef _THIS_IP_ +#define _THIS_IP_ 0 +#endif + +static inline void log_write_mmio(u64 val, u8 width, volatile void __iomem *addr, + unsigned long caller_addr, unsigned long caller_addr0) {} +static inline void log_post_write_mmio(u64 val, u8 width, volatile void __iomem *addr, + unsigned long caller_addr, unsigned long caller_addr0) {} +static inline void log_read_mmio(u8 width, const volatile void __iomem *addr, + unsigned long caller_addr, unsigned long caller_addr0) {} +static inline void log_post_read_mmio(u64 val, u8 width, const volatile void __iomem *addr, + unsigned long caller_addr, unsigned long caller_addr0) {} + +/* + * __raw_{read,write}{b,w,l,q}() access memory in native endianness. + * + * On some architectures memory mapped IO needs to be accessed differently. + * On the simple architectures, we just read/write the memory location + * directly. + */ + +#ifndef __raw_readb +#define __raw_readb __raw_readb +static inline u8 __raw_readb(const volatile void __iomem *addr) +{ + return *(const volatile u8 __force *)addr; +} +#endif + +#ifndef __raw_readw +#define __raw_readw __raw_readw +static inline u16 __raw_readw(const volatile void __iomem *addr) +{ + return *(const volatile u16 __force *)addr; +} +#endif + +#ifndef __raw_readl +#define __raw_readl __raw_readl +static inline u32 __raw_readl(const volatile void __iomem *addr) +{ + return *(const volatile u32 __force *)addr; +} +#endif + +#ifndef __raw_readq +#define __raw_readq __raw_readq +static inline u64 __raw_readq(const volatile void __iomem *addr) +{ + return *(const volatile u64 __force *)addr; +} +#endif + +#ifndef __raw_writeb +#define __raw_writeb __raw_writeb +static inline void __raw_writeb(u8 value, volatile void __iomem *addr) +{ + *(volatile u8 __force *)addr = value; +} +#endif + +#ifndef __raw_writew +#define __raw_writew __raw_writew +static inline void __raw_writew(u16 value, volatile void __iomem *addr) +{ + *(volatile u16 __force *)addr = value; +} +#endif + +#ifndef __raw_writel +#define __raw_writel __raw_writel +static inline void __raw_writel(u32 value, volatile void __iomem *addr) +{ + *(volatile u32 __force *)addr = value; +} +#endif + +#ifndef __raw_writeq +#define __raw_writeq __raw_writeq +static inline void __raw_writeq(u64 value, volatile void __iomem *addr) +{ + *(volatile u64 __force *)addr = value; +} +#endif + +/* + * {read,write}{b,w,l,q}() access little endian memory and return result in + * native endianness. + */ + +#ifndef readb +#define readb readb +static inline u8 readb(const volatile void __iomem *addr) +{ + u8 val; + + log_read_mmio(8, addr, _THIS_IP_, _RET_IP_); + __io_br(); + val = __raw_readb(addr); + __io_ar(val); + log_post_read_mmio(val, 8, addr, _THIS_IP_, _RET_IP_); + return val; +} +#endif + +#ifndef readw +#define readw readw +static inline u16 readw(const volatile void __iomem *addr) +{ + u16 val; + + log_read_mmio(16, addr, _THIS_IP_, _RET_IP_); + __io_br(); + val = __le16_to_cpu((__le16 __force)__raw_readw(addr)); + __io_ar(val); + log_post_read_mmio(val, 16, addr, _THIS_IP_, _RET_IP_); + return val; +} +#endif + +#ifndef readl +#define readl readl +static inline u32 readl(const volatile void __iomem *addr) +{ + u32 val; + + log_read_mmio(32, addr, _THIS_IP_, _RET_IP_); + __io_br(); + val = __le32_to_cpu((__le32 __force)__raw_readl(addr)); + __io_ar(val); + log_post_read_mmio(val, 32, addr, _THIS_IP_, _RET_IP_); + return val; +} +#endif + +#ifndef readq +#define readq readq +static inline u64 readq(const volatile void __iomem *addr) +{ + u64 val; + + log_read_mmio(64, addr, _THIS_IP_, _RET_IP_); + __io_br(); + val = __le64_to_cpu((__le64 __force)__raw_readq(addr)); + __io_ar(val); + log_post_read_mmio(val, 64, addr, _THIS_IP_, _RET_IP_); + return val; +} +#endif + +#ifndef writeb +#define writeb writeb +static inline void writeb(u8 value, volatile void __iomem *addr) +{ + log_write_mmio(value, 8, addr, _THIS_IP_, _RET_IP_); + __io_bw(); + __raw_writeb(value, addr); + __io_aw(); + log_post_write_mmio(value, 8, addr, _THIS_IP_, _RET_IP_); +} +#endif + +#ifndef writew +#define writew writew +static inline void writew(u16 value, volatile void __iomem *addr) +{ + log_write_mmio(value, 16, addr, _THIS_IP_, _RET_IP_); + __io_bw(); + __raw_writew((u16 __force)cpu_to_le16(value), addr); + __io_aw(); + log_post_write_mmio(value, 16, addr, _THIS_IP_, _RET_IP_); +} +#endif + +#ifndef writel +#define writel writel +static inline void writel(u32 value, volatile void __iomem *addr) +{ + log_write_mmio(value, 32, addr, _THIS_IP_, _RET_IP_); + __io_bw(); + __raw_writel((u32 __force)__cpu_to_le32(value), addr); + __io_aw(); + log_post_write_mmio(value, 32, addr, _THIS_IP_, _RET_IP_); +} +#endif + +#ifndef writeq +#define writeq writeq +static inline void writeq(u64 value, volatile void __iomem *addr) +{ + log_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_); + __io_bw(); + __raw_writeq((u64 __force)__cpu_to_le64(value), addr); + __io_aw(); + log_post_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_); +} +#endif + +/* + * {read,write}{b,w,l,q}_relaxed() are like the regular version, but + * are not guaranteed to provide ordering against spinlocks or memory + * accesses. + */ +#ifndef readb_relaxed +#define readb_relaxed readb_relaxed +static inline u8 readb_relaxed(const volatile void __iomem *addr) +{ + u8 val; + + log_read_mmio(8, addr, _THIS_IP_, _RET_IP_); + val = __raw_readb(addr); + log_post_read_mmio(val, 8, addr, _THIS_IP_, _RET_IP_); + return val; +} +#endif + +#ifndef readw_relaxed +#define readw_relaxed readw_relaxed +static inline u16 readw_relaxed(const volatile void __iomem *addr) +{ + u16 val; + + log_read_mmio(16, addr, _THIS_IP_, _RET_IP_); + val = __le16_to_cpu((__le16 __force)__raw_readw(addr)); + log_post_read_mmio(val, 16, addr, _THIS_IP_, _RET_IP_); + return val; +} +#endif + +#ifndef readl_relaxed +#define readl_relaxed readl_relaxed +static inline u32 readl_relaxed(const volatile void __iomem *addr) +{ + u32 val; + + log_read_mmio(32, addr, _THIS_IP_, _RET_IP_); + val = __le32_to_cpu((__le32 __force)__raw_readl(addr)); + log_post_read_mmio(val, 32, addr, _THIS_IP_, _RET_IP_); + return val; +} +#endif + +#if defined(readq) && !defined(readq_relaxed) +#define readq_relaxed readq_relaxed +static inline u64 readq_relaxed(const volatile void __iomem *addr) +{ + u64 val; + + log_read_mmio(64, addr, _THIS_IP_, _RET_IP_); + val = __le64_to_cpu((__le64 __force)__raw_readq(addr)); + log_post_read_mmio(val, 64, addr, _THIS_IP_, _RET_IP_); + return val; +} +#endif + +#ifndef writeb_relaxed +#define writeb_relaxed writeb_relaxed +static inline void writeb_relaxed(u8 value, volatile void __iomem *addr) +{ + log_write_mmio(value, 8, addr, _THIS_IP_, _RET_IP_); + __raw_writeb(value, addr); + log_post_write_mmio(value, 8, addr, _THIS_IP_, _RET_IP_); +} +#endif + +#ifndef writew_relaxed +#define writew_relaxed writew_relaxed +static inline void writew_relaxed(u16 value, volatile void __iomem *addr) +{ + log_write_mmio(value, 16, addr, _THIS_IP_, _RET_IP_); + __raw_writew((u16 __force)cpu_to_le16(value), addr); + log_post_write_mmio(value, 16, addr, _THIS_IP_, _RET_IP_); +} +#endif + +#ifndef writel_relaxed +#define writel_relaxed writel_relaxed +static inline void writel_relaxed(u32 value, volatile void __iomem *addr) +{ + log_write_mmio(value, 32, addr, _THIS_IP_, _RET_IP_); + __raw_writel((u32 __force)__cpu_to_le32(value), addr); + log_post_write_mmio(value, 32, addr, _THIS_IP_, _RET_IP_); +} +#endif + +#if defined(writeq) && !defined(writeq_relaxed) +#define writeq_relaxed writeq_relaxed +static inline void writeq_relaxed(u64 value, volatile void __iomem *addr) +{ + log_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_); + __raw_writeq((u64 __force)__cpu_to_le64(value), addr); + log_post_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_); +} +#endif + +/* + * {read,write}s{b,w,l,q}() repeatedly access the same memory address in + * native endianness in 8-, 16-, 32- or 64-bit chunks (@count times). + */ +#ifndef readsb +#define readsb readsb +static inline void readsb(const volatile void __iomem *addr, void *buffer, + unsigned int count) +{ + if (count) { + u8 *buf = buffer; + + do { + u8 x = __raw_readb(addr); + *buf++ = x; + } while (--count); + } +} +#endif + +#ifndef readsw +#define readsw readsw +static inline void readsw(const volatile void __iomem *addr, void *buffer, + unsigned int count) +{ + if (count) { + u16 *buf = buffer; + + do { + u16 x = __raw_readw(addr); + *buf++ = x; + } while (--count); + } +} +#endif + +#ifndef readsl +#define readsl readsl +static inline void readsl(const volatile void __iomem *addr, void *buffer, + unsigned int count) +{ + if (count) { + u32 *buf = buffer; + + do { + u32 x = __raw_readl(addr); + *buf++ = x; + } while (--count); + } +} +#endif + +#ifndef readsq +#define readsq readsq +static inline void readsq(const volatile void __iomem *addr, void *buffer, + unsigned int count) +{ + if (count) { + u64 *buf = buffer; + + do { + u64 x = __raw_readq(addr); + *buf++ = x; + } while (--count); + } +} +#endif + +#ifndef writesb +#define writesb writesb +static inline void writesb(volatile void __iomem *addr, const void *buffer, + unsigned int count) +{ + if (count) { + const u8 *buf = buffer; + + do { + __raw_writeb(*buf++, addr); + } while (--count); + } +} +#endif + +#ifndef writesw +#define writesw writesw +static inline void writesw(volatile void __iomem *addr, const void *buffer, + unsigned int count) +{ + if (count) { + const u16 *buf = buffer; + + do { + __raw_writew(*buf++, addr); + } while (--count); + } +} +#endif + +#ifndef writesl +#define writesl writesl +static inline void writesl(volatile void __iomem *addr, const void *buffer, + unsigned int count) +{ + if (count) { + const u32 *buf = buffer; + + do { + __raw_writel(*buf++, addr); + } while (--count); + } +} +#endif + +#ifndef writesq +#define writesq writesq +static inline void writesq(volatile void __iomem *addr, const void *buffer, + unsigned int count) +{ + if (count) { + const u64 *buf = buffer; + + do { + __raw_writeq(*buf++, addr); + } while (--count); + } +} +#endif + +#endif /* _TOOLS_ASM_GENERIC_IO_H */ diff --git a/tools/include/asm/io.h b/tools/include/asm/io.h new file mode 100644 index 000000000000..9ae219b12604 --- /dev/null +++ b/tools/include/asm/io.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_ASM_IO_H +#define _TOOLS_ASM_IO_H + +#include + +#endif /* _TOOLS_ASM_IO_H */ diff --git a/tools/include/linux/io.h b/tools/include/linux/io.h index e129871fe661..4b94b84160b8 100644 --- a/tools/include/linux/io.h +++ b/tools/include/linux/io.h @@ -2,4 +2,6 @@ #ifndef _TOOLS_IO_H #define _TOOLS_IO_H -#endif +#include + +#endif /* _TOOLS_IO_H */ From ce5dc9aa72d9c3d6cb14b3a6aab900124999d8d0 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:03 +0000 Subject: [PATCH 0599/2711] tools headers: Import x86 MMIO helper overrides Import the x86-specific overrides for from the kernel headers into tools/include/. Changes made when importing: - Replace CONFIG_X86_64 with __x86_64__. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-17-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/arch/x86/include/asm/io.h | 75 +++++++++++++++++++++++++++++++++ tools/include/asm/io.h | 4 ++ 2 files changed, 79 insertions(+) create mode 100644 tools/arch/x86/include/asm/io.h diff --git a/tools/arch/x86/include/asm/io.h b/tools/arch/x86/include/asm/io.h new file mode 100644 index 000000000000..4c787a2363de --- /dev/null +++ b/tools/arch/x86/include/asm/io.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_ASM_X86_IO_H +#define _TOOLS_ASM_X86_IO_H + +#include +#include + +#define build_mmio_read(name, size, type, reg, barrier) \ +static inline type name(const volatile void __iomem *addr) \ +{ type ret; asm volatile("mov" size " %1,%0":reg (ret) \ +:"m" (*(volatile type __force *)addr) barrier); return ret; } + +#define build_mmio_write(name, size, type, reg, barrier) \ +static inline void name(type val, volatile void __iomem *addr) \ +{ asm volatile("mov" size " %0,%1": :reg (val), \ +"m" (*(volatile type __force *)addr) barrier); } + +build_mmio_read(readb, "b", unsigned char, "=q", :"memory") +build_mmio_read(readw, "w", unsigned short, "=r", :"memory") +build_mmio_read(readl, "l", unsigned int, "=r", :"memory") + +build_mmio_read(__readb, "b", unsigned char, "=q", ) +build_mmio_read(__readw, "w", unsigned short, "=r", ) +build_mmio_read(__readl, "l", unsigned int, "=r", ) + +build_mmio_write(writeb, "b", unsigned char, "q", :"memory") +build_mmio_write(writew, "w", unsigned short, "r", :"memory") +build_mmio_write(writel, "l", unsigned int, "r", :"memory") + +build_mmio_write(__writeb, "b", unsigned char, "q", ) +build_mmio_write(__writew, "w", unsigned short, "r", ) +build_mmio_write(__writel, "l", unsigned int, "r", ) + +#define readb readb +#define readw readw +#define readl readl +#define readb_relaxed(a) __readb(a) +#define readw_relaxed(a) __readw(a) +#define readl_relaxed(a) __readl(a) +#define __raw_readb __readb +#define __raw_readw __readw +#define __raw_readl __readl + +#define writeb writeb +#define writew writew +#define writel writel +#define writeb_relaxed(v, a) __writeb(v, a) +#define writew_relaxed(v, a) __writew(v, a) +#define writel_relaxed(v, a) __writel(v, a) +#define __raw_writeb __writeb +#define __raw_writew __writew +#define __raw_writel __writel + +#ifdef __x86_64__ + +build_mmio_read(readq, "q", u64, "=r", :"memory") +build_mmio_read(__readq, "q", u64, "=r", ) +build_mmio_write(writeq, "q", u64, "r", :"memory") +build_mmio_write(__writeq, "q", u64, "r", ) + +#define readq_relaxed(a) __readq(a) +#define writeq_relaxed(v, a) __writeq(v, a) + +#define __raw_readq __readq +#define __raw_writeq __writeq + +/* Let people know that we have them */ +#define readq readq +#define writeq writeq + +#endif /* __x86_64__ */ + +#include + +#endif /* _TOOLS_ASM_X86_IO_H */ diff --git a/tools/include/asm/io.h b/tools/include/asm/io.h index 9ae219b12604..eed5066f25c4 100644 --- a/tools/include/asm/io.h +++ b/tools/include/asm/io.h @@ -2,6 +2,10 @@ #ifndef _TOOLS_ASM_IO_H #define _TOOLS_ASM_IO_H +#if defined(__i386__) || defined(__x86_64__) +#include "../../arch/x86/include/asm/io.h" +#else #include +#endif #endif /* _TOOLS_ASM_IO_H */ From dc0e216cf00b74cf61fdc882f8373beb8cdbec5e Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:04 +0000 Subject: [PATCH 0600/2711] tools headers: Add symlink to linux/pci_ids.h Add a symlink to include/linux/pci_ids.h to tools/include/. This will be used by VFIO selftests in subsequent commits to match device and vendor IDs. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-18-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) create mode 120000 tools/include/linux/pci_ids.h diff --git a/tools/include/linux/pci_ids.h b/tools/include/linux/pci_ids.h new file mode 120000 index 000000000000..1c9e88f41261 --- /dev/null +++ b/tools/include/linux/pci_ids.h @@ -0,0 +1 @@ +../../../include/linux/pci_ids.h \ No newline at end of file From b7f086912c1d3ce1e8c2753e0ff329947219d0f6 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:05 +0000 Subject: [PATCH 0601/2711] dmaengine: ioat: Move system_has_dca_enabled() to dma.h Move the function prototype for system_has_dca_enabled() from hw.h to dma.h. This allows hw.h to be included from tools/, which will be used in a subsysequent commit to implement a userspace driver for Intel CBDMA devices in tools/testing/selftests/vfio. No functional change intended. Acked-by: Dave Jiang Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-19-dmatlack@google.com Signed-off-by: Alex Williamson --- drivers/dma/ioat/dma.h | 2 ++ drivers/dma/ioat/hw.h | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h index a180171087a8..12a4a4860a74 100644 --- a/drivers/dma/ioat/dma.h +++ b/drivers/dma/ioat/dma.h @@ -19,6 +19,8 @@ #define IOAT_DMA_DCA_ANY_CPU ~0 +int system_has_dca_enabled(struct pci_dev *pdev); + #define to_ioatdma_device(dev) container_of(dev, struct ioatdma_device, dma_dev) #define to_dev(ioat_chan) (&(ioat_chan)->ioat_dma->pdev->dev) #define to_pdev(ioat_chan) ((ioat_chan)->ioat_dma->pdev) diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h index 79e4e4c09c18..0373c48520c9 100644 --- a/drivers/dma/ioat/hw.h +++ b/drivers/dma/ioat/hw.h @@ -63,9 +63,6 @@ #define IOAT_VER_3_3 0x33 /* Version 3.3 */ #define IOAT_VER_3_4 0x34 /* Version 3.4 */ - -int system_has_dca_enabled(struct pci_dev *pdev); - #define IOAT_DESC_SZ 64 struct ioat_dma_descriptor { From 2223587df5c5e935cc6f973f62a9608eef81bec8 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:06 +0000 Subject: [PATCH 0602/2711] vfio: selftests: Add driver for Intel CBDMA Add a driver for the Intel CBDMA device. This driver is based on and named after the Linux driver for this device (drivers/dma/ioat/) and also based on previous work from Peter Shier . The driver aims to be as simple as possible. It uses a single descriptor to issue DMA operations, and only supports the copy operation. For "DMA storms", the driver kicks off the maximum number of maximum-sized DMA operations. On Skylake server parts, this was 2^16-1 copies of size 2M and lasts about 15 seconds. Create symlinks to drivers/dma/ioat/{hw.h,registers.h} to get access to various macros (e.g. IOAT_CHANCMD_RESET) and struct ioat_dma_descriptor. Cc: Dave Jiang Cc: Dan Williams Acked-by: Dave Jiang Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-20-dmatlack@google.com Signed-off-by: Alex Williamson --- .../selftests/vfio/lib/drivers/ioat/hw.h | 1 + .../selftests/vfio/lib/drivers/ioat/ioat.c | 235 ++++++++++++++++++ .../vfio/lib/drivers/ioat/registers.h | 1 + tools/testing/selftests/vfio/lib/libvfio.mk | 7 + .../selftests/vfio/lib/vfio_pci_driver.c | 10 +- 5 files changed, 253 insertions(+), 1 deletion(-) create mode 120000 tools/testing/selftests/vfio/lib/drivers/ioat/hw.h create mode 100644 tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c create mode 120000 tools/testing/selftests/vfio/lib/drivers/ioat/registers.h diff --git a/tools/testing/selftests/vfio/lib/drivers/ioat/hw.h b/tools/testing/selftests/vfio/lib/drivers/ioat/hw.h new file mode 120000 index 000000000000..8ab52ddd4458 --- /dev/null +++ b/tools/testing/selftests/vfio/lib/drivers/ioat/hw.h @@ -0,0 +1 @@ +../../../../../../../drivers/dma/ioat/hw.h \ No newline at end of file diff --git a/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c b/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c new file mode 100644 index 000000000000..c3b91d9b1f59 --- /dev/null +++ b/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include + +#include +#include +#include +#include + +#include + +#include "hw.h" +#include "registers.h" + +#define IOAT_DMACOUNT_MAX UINT16_MAX + +struct ioat_state { + /* Single descriptor used to issue DMA memcpy operations */ + struct ioat_dma_descriptor desc; + + /* Copy buffers used by ioat_send_msi() to generate an interrupt. */ + u64 send_msi_src; + u64 send_msi_dst; +}; + +static inline struct ioat_state *to_ioat_state(struct vfio_pci_device *device) +{ + return device->driver.region.vaddr; +} + +static inline void *ioat_channel_registers(struct vfio_pci_device *device) +{ + return device->bars[0].vaddr + IOAT_CHANNEL_MMIO_SIZE; +} + +static int ioat_probe(struct vfio_pci_device *device) +{ + u8 version; + int r; + + if (!vfio_pci_device_match(device, PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_IOAT_SKX)) + return -EINVAL; + + VFIO_ASSERT_NOT_NULL(device->bars[0].vaddr); + + version = readb(device->bars[0].vaddr + IOAT_VER_OFFSET); + switch (version) { + case IOAT_VER_3_2: + case IOAT_VER_3_3: + r = 0; + break; + default: + printf("ioat: Unsupported version: 0x%x\n", version); + r = -EINVAL; + } + return r; +} + +static u64 ioat_channel_status(void *bar) +{ + return readq(bar + IOAT_CHANSTS_OFFSET) & IOAT_CHANSTS_STATUS; +} + +static void ioat_clear_errors(struct vfio_pci_device *device) +{ + void *registers = ioat_channel_registers(device); + u32 errors; + + errors = vfio_pci_config_readl(device, IOAT_PCI_CHANERR_INT_OFFSET); + vfio_pci_config_writel(device, IOAT_PCI_CHANERR_INT_OFFSET, errors); + + errors = vfio_pci_config_readl(device, IOAT_PCI_DMAUNCERRSTS_OFFSET); + vfio_pci_config_writel(device, IOAT_PCI_CHANERR_INT_OFFSET, errors); + + errors = readl(registers + IOAT_CHANERR_OFFSET); + writel(errors, registers + IOAT_CHANERR_OFFSET); +} + +static void ioat_reset(struct vfio_pci_device *device) +{ + void *registers = ioat_channel_registers(device); + u32 sleep_ms = 1, attempts = 5000 / sleep_ms; + u8 chancmd; + + ioat_clear_errors(device); + + writeb(IOAT_CHANCMD_RESET, registers + IOAT2_CHANCMD_OFFSET); + + for (;;) { + chancmd = readb(registers + IOAT2_CHANCMD_OFFSET); + if (!(chancmd & IOAT_CHANCMD_RESET)) + break; + + VFIO_ASSERT_GT(--attempts, 0); + usleep(sleep_ms * 1000); + } + + VFIO_ASSERT_EQ(ioat_channel_status(registers), IOAT_CHANSTS_HALTED); +} + +static void ioat_init(struct vfio_pci_device *device) +{ + struct ioat_state *ioat = to_ioat_state(device); + u8 intrctrl; + + VFIO_ASSERT_GE(device->driver.region.size, sizeof(*ioat)); + + vfio_pci_config_writew(device, PCI_COMMAND, + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | + PCI_COMMAND_INTX_DISABLE); + + ioat_reset(device); + + /* Enable the use of MXI-x interrupts for channel interrupts. */ + intrctrl = IOAT_INTRCTRL_MSIX_VECTOR_CONTROL; + writeb(intrctrl, device->bars[0].vaddr + IOAT_INTRCTRL_OFFSET); + + vfio_pci_msix_enable(device, 0, device->msix_info.count); + + device->driver.msi = 0; + device->driver.max_memcpy_size = + 1UL << readb(device->bars[0].vaddr + IOAT_XFERCAP_OFFSET); + device->driver.max_memcpy_count = IOAT_DMACOUNT_MAX; +} + +static void ioat_remove(struct vfio_pci_device *device) +{ + ioat_reset(device); + vfio_pci_msix_disable(device); +} + +static void ioat_handle_error(struct vfio_pci_device *device) +{ + void *registers = ioat_channel_registers(device); + + printf("Error detected during memcpy operation!\n" + " CHANERR: 0x%x\n" + " CHANERR_INT: 0x%x\n" + " DMAUNCERRSTS: 0x%x\n", + readl(registers + IOAT_CHANERR_OFFSET), + vfio_pci_config_readl(device, IOAT_PCI_CHANERR_INT_OFFSET), + vfio_pci_config_readl(device, IOAT_PCI_DMAUNCERRSTS_OFFSET)); + + ioat_reset(device); +} + +static int ioat_memcpy_wait(struct vfio_pci_device *device) +{ + void *registers = ioat_channel_registers(device); + u64 status; + int r = 0; + + /* Wait until all operations complete. */ + for (;;) { + status = ioat_channel_status(registers); + if (status == IOAT_CHANSTS_DONE) + break; + + if (status == IOAT_CHANSTS_HALTED) { + ioat_handle_error(device); + return -1; + } + } + + /* Put the channel into the SUSPENDED state. */ + writeb(IOAT_CHANCMD_SUSPEND, registers + IOAT2_CHANCMD_OFFSET); + for (;;) { + status = ioat_channel_status(registers); + if (status == IOAT_CHANSTS_SUSPENDED) + break; + } + + return r; +} + +static void __ioat_memcpy_start(struct vfio_pci_device *device, + iova_t src, iova_t dst, u64 size, + u16 count, bool interrupt) +{ + void *registers = ioat_channel_registers(device); + struct ioat_state *ioat = to_ioat_state(device); + u64 desc_iova; + u16 chanctrl; + + desc_iova = to_iova(device, &ioat->desc); + ioat->desc = (struct ioat_dma_descriptor) { + .ctl_f.op = IOAT_OP_COPY, + .ctl_f.int_en = interrupt, + .src_addr = src, + .dst_addr = dst, + .size = size, + .next = desc_iova, + }; + + /* Tell the device the address of the descriptor. */ + writeq(desc_iova, registers + IOAT2_CHAINADDR_OFFSET); + + /* (Re)Enable the channel interrupt and abort on any errors */ + chanctrl = IOAT_CHANCTRL_INT_REARM | IOAT_CHANCTRL_ANY_ERR_ABORT_EN; + writew(chanctrl, registers + IOAT_CHANCTRL_OFFSET); + + /* Kick off @count DMA copy operation(s). */ + writew(count, registers + IOAT_CHAN_DMACOUNT_OFFSET); +} + +static void ioat_memcpy_start(struct vfio_pci_device *device, + iova_t src, iova_t dst, u64 size, + u64 count) +{ + __ioat_memcpy_start(device, src, dst, size, count, false); +} + +static void ioat_send_msi(struct vfio_pci_device *device) +{ + struct ioat_state *ioat = to_ioat_state(device); + + __ioat_memcpy_start(device, + to_iova(device, &ioat->send_msi_src), + to_iova(device, &ioat->send_msi_dst), + sizeof(ioat->send_msi_src), 1, true); + + VFIO_ASSERT_EQ(ioat_memcpy_wait(device), 0); +} + +const struct vfio_pci_driver_ops ioat_ops = { + .name = "ioat", + .probe = ioat_probe, + .init = ioat_init, + .remove = ioat_remove, + .memcpy_start = ioat_memcpy_start, + .memcpy_wait = ioat_memcpy_wait, + .send_msi = ioat_send_msi, +}; diff --git a/tools/testing/selftests/vfio/lib/drivers/ioat/registers.h b/tools/testing/selftests/vfio/lib/drivers/ioat/registers.h new file mode 120000 index 000000000000..0b809cfd8fe6 --- /dev/null +++ b/tools/testing/selftests/vfio/lib/drivers/ioat/registers.h @@ -0,0 +1 @@ +../../../../../../../drivers/dma/ioat/registers.h \ No newline at end of file diff --git a/tools/testing/selftests/vfio/lib/libvfio.mk b/tools/testing/selftests/vfio/lib/libvfio.mk index a3c3bc9a7c00..624dc267a879 100644 --- a/tools/testing/selftests/vfio/lib/libvfio.mk +++ b/tools/testing/selftests/vfio/lib/libvfio.mk @@ -1,8 +1,15 @@ +include $(top_srcdir)/scripts/subarch.include +ARCH ?= $(SUBARCH) + VFIO_DIR := $(selfdir)/vfio LIBVFIO_C := lib/vfio_pci_device.c LIBVFIO_C += lib/vfio_pci_driver.c +ifeq ($(ARCH:x86_64=x86),x86) +LIBVFIO_C += lib/drivers/ioat/ioat.c +endif + LIBVFIO_O := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBVFIO_C)) LIBVFIO_O_DIRS := $(shell dirname $(LIBVFIO_O) | uniq) diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c index c98bd2d31d8a..aa47360e47a9 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c @@ -4,7 +4,15 @@ #include "../../../kselftest.h" #include -static struct vfio_pci_driver_ops *driver_ops[] = {}; +#ifdef __x86_64__ +extern struct vfio_pci_driver_ops ioat_ops; +#endif + +static struct vfio_pci_driver_ops *driver_ops[] = { +#ifdef __x86_64__ + &ioat_ops, +#endif +}; void vfio_pci_driver_probe(struct vfio_pci_device *device) { From 3fe305773bbeb2d946b9fb3c1224c8b00d6755ef Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:07 +0000 Subject: [PATCH 0603/2711] tools headers: Import iosubmit_cmds512() Import iosubmit_cmds512() from arch/x86/include/asm/io.h into tools/ so it can be used by VFIO selftests to interact with Intel DSA devices. Also pull in movdir64b() from arch/x86/include/asm/special_insns.h into tools/, which is the underlying instruction used by iosubmit_cmds512(). Changes made when importing: None Acked-by: Vinicius Costa Gomes Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-21-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/arch/x86/include/asm/io.h | 26 +++++++++++++++++++++ tools/arch/x86/include/asm/special_insns.h | 27 ++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 tools/arch/x86/include/asm/special_insns.h diff --git a/tools/arch/x86/include/asm/io.h b/tools/arch/x86/include/asm/io.h index 4c787a2363de..ecad61a3ea52 100644 --- a/tools/arch/x86/include/asm/io.h +++ b/tools/arch/x86/include/asm/io.h @@ -4,6 +4,7 @@ #include #include +#include "special_insns.h" #define build_mmio_read(name, size, type, reg, barrier) \ static inline type name(const volatile void __iomem *addr) \ @@ -72,4 +73,29 @@ build_mmio_write(__writeq, "q", u64, "r", ) #include +/** + * iosubmit_cmds512 - copy data to single MMIO location, in 512-bit units + * @dst: destination, in MMIO space (must be 512-bit aligned) + * @src: source + * @count: number of 512 bits quantities to submit + * + * Submit data from kernel space to MMIO space, in units of 512 bits at a + * time. Order of access is not guaranteed, nor is a memory barrier + * performed afterwards. + * + * Warning: Do not use this helper unless your driver has checked that the CPU + * instruction is supported on the platform. + */ +static inline void iosubmit_cmds512(void __iomem *dst, const void *src, + size_t count) +{ + const u8 *from = src; + const u8 *end = from + count * 64; + + while (from < end) { + movdir64b(dst, from); + from += 64; + } +} + #endif /* _TOOLS_ASM_X86_IO_H */ diff --git a/tools/arch/x86/include/asm/special_insns.h b/tools/arch/x86/include/asm/special_insns.h new file mode 100644 index 000000000000..04af42a99c38 --- /dev/null +++ b/tools/arch/x86/include/asm/special_insns.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TOOLS_ASM_X86_SPECIAL_INSNS_H +#define _TOOLS_ASM_X86_SPECIAL_INSNS_H + +/* The dst parameter must be 64-bytes aligned */ +static inline void movdir64b(void *dst, const void *src) +{ + const struct { char _[64]; } *__src = src; + struct { char _[64]; } *__dst = dst; + + /* + * MOVDIR64B %(rdx), rax. + * + * Both __src and __dst must be memory constraints in order to tell the + * compiler that no other memory accesses should be reordered around + * this one. + * + * Also, both must be supplied as lvalues because this tells + * the compiler what the object is (its size) the instruction accesses. + * I.e., not the pointers but what they point to, thus the deref'ing '*'. + */ + asm volatile(".byte 0x66, 0x0f, 0x38, 0xf8, 0x02" + : "+m" (*__dst) + : "m" (*__src), "a" (__dst), "d" (__src)); +} + +#endif /* _TOOLS_ASM_X86_SPECIAL_INSNS_H */ From 003e6faf2c8ff1670c35622f11ff6211be563a9e Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:08 +0000 Subject: [PATCH 0604/2711] dmaengine: idxd: Allow registers.h to be included from tools/ Allow drivers/dma/idxd/registers.h to be included from userspace in tools/ by adjusting the include path to uapi/linux/idxd.h if __KERNEL__ is not defined. A subsequent commit will use registers.h to implement a userspace driver for Intel DSA devices in tools/testing/selftests/vfio. Acked-by: Vinicius Costa Gomes Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-22-dmatlack@google.com Signed-off-by: Alex Williamson --- drivers/dma/idxd/registers.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h index 9c1c546fe443..02bab136385e 100644 --- a/drivers/dma/idxd/registers.h +++ b/drivers/dma/idxd/registers.h @@ -3,7 +3,11 @@ #ifndef _IDXD_REGISTERS_H_ #define _IDXD_REGISTERS_H_ +#ifdef __KERNEL__ #include +#else +#include +#endif /* PCI Config */ #define PCI_DEVICE_ID_INTEL_DSA_GNRD 0x11fb From 35b05bd96204bc40a2ca8620bad1a5d139c20060 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:09 +0000 Subject: [PATCH 0605/2711] vfio: selftests: Add driver for Intel DSA Add a driver to VFIO selftests for Intel DSA devices. For now the driver only supports up to 32 batches and 1024 copies per batch, which were the limits of the hardware this commit was tested with. This is sufficient to generate 9+ minutes of DMA memcpys at a rate of over 30 GB/s. This should be plenty to stress test VFIO and the IOMMU. The driver does not yet support requesting interrupt handles, as this commit was not tested against hardware that requires it. Cc: Vinicius Costa Gomes Cc: Dave Jiang Acked-by: Vinicius Costa Gomes Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-23-dmatlack@google.com Signed-off-by: Alex Williamson --- .../selftests/vfio/lib/drivers/dsa/dsa.c | 416 ++++++++++++++++++ .../vfio/lib/drivers/dsa/registers.h | 1 + tools/testing/selftests/vfio/lib/libvfio.mk | 1 + .../selftests/vfio/lib/vfio_pci_driver.c | 2 + 4 files changed, 420 insertions(+) create mode 100644 tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c create mode 120000 tools/testing/selftests/vfio/lib/drivers/dsa/registers.h diff --git a/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c b/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c new file mode 100644 index 000000000000..0ca2cbc2a316 --- /dev/null +++ b/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "registers.h" + +/* Vectors 1+ are available for work queue completion interrupts. */ +#define MSIX_VECTOR 1 + +struct dsa_state { + /* Descriptors for copy and batch operations. */ + struct dsa_hw_desc batch[32]; + struct dsa_hw_desc copy[1024]; + + /* Completion records for copy and batch operations. */ + struct dsa_completion_record copy_completion; + struct dsa_completion_record batch_completion; + + /* Cached device registers (and derived data) for easy access */ + union gen_cap_reg gen_cap; + union wq_cap_reg wq_cap; + union group_cap_reg group_cap; + union engine_cap_reg engine_cap; + union offsets_reg table_offsets; + void *wqcfg_table; + void *grpcfg_table; + u64 max_batches; + u64 max_copies_per_batch; + + /* The number of ongoing memcpy operations. */ + u64 memcpy_count; + + /* Buffers used by dsa_send_msi() to generate an interrupt */ + u64 send_msi_src; + u64 send_msi_dst; +}; + +static inline struct dsa_state *to_dsa_state(struct vfio_pci_device *device) +{ + return device->driver.region.vaddr; +} + +static bool dsa_int_handle_request_required(struct vfio_pci_device *device) +{ + void *bar0 = device->bars[0].vaddr; + union gen_cap_reg gen_cap; + u32 cmd_cap; + + gen_cap.bits = readq(bar0 + IDXD_GENCAP_OFFSET); + if (!gen_cap.cmd_cap) + return false; + + cmd_cap = readl(bar0 + IDXD_CMDCAP_OFFSET); + return (cmd_cap >> IDXD_CMD_REQUEST_INT_HANDLE) & 1; +} + +static int dsa_probe(struct vfio_pci_device *device) +{ + if (!vfio_pci_device_match(device, PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_DSA_SPR0)) + return -EINVAL; + + if (dsa_int_handle_request_required(device)) { + printf("Device requires requesting interrupt handles\n"); + return -EINVAL; + } + + return 0; +} + +static void dsa_check_sw_err(struct vfio_pci_device *device) +{ + void *reg = device->bars[0].vaddr + IDXD_SWERR_OFFSET; + union sw_err_reg err = {}; + int i; + + for (i = 0; i < ARRAY_SIZE(err.bits); i++) { + err.bits[i] = readq(reg + offsetof(union sw_err_reg, bits[i])); + + /* No errors */ + if (i == 0 && !err.valid) + return; + } + + fprintf(stderr, "SWERR: 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n", + err.bits[0], err.bits[1], err.bits[2], err.bits[3]); + + fprintf(stderr, " valid: 0x%x\n", err.valid); + fprintf(stderr, " overflow: 0x%x\n", err.overflow); + fprintf(stderr, " desc_valid: 0x%x\n", err.desc_valid); + fprintf(stderr, " wq_idx_valid: 0x%x\n", err.wq_idx_valid); + fprintf(stderr, " batch: 0x%x\n", err.batch); + fprintf(stderr, " fault_rw: 0x%x\n", err.fault_rw); + fprintf(stderr, " priv: 0x%x\n", err.priv); + fprintf(stderr, " error: 0x%x\n", err.error); + fprintf(stderr, " wq_idx: 0x%x\n", err.wq_idx); + fprintf(stderr, " operation: 0x%x\n", err.operation); + fprintf(stderr, " pasid: 0x%x\n", err.pasid); + fprintf(stderr, " batch_idx: 0x%x\n", err.batch_idx); + fprintf(stderr, " invalid_flags: 0x%x\n", err.invalid_flags); + fprintf(stderr, " fault_addr: 0x%lx\n", err.fault_addr); + + VFIO_FAIL("Software Error Detected!\n"); +} + +static void dsa_command(struct vfio_pci_device *device, u32 cmd) +{ + union idxd_command_reg cmd_reg = { .cmd = cmd }; + u32 sleep_ms = 1, attempts = 5000 / sleep_ms; + void *bar0 = device->bars[0].vaddr; + u32 status; + u8 err; + + writel(cmd_reg.bits, bar0 + IDXD_CMD_OFFSET); + + for (;;) { + dsa_check_sw_err(device); + + status = readl(bar0 + IDXD_CMDSTS_OFFSET); + if (!(status & IDXD_CMDSTS_ACTIVE)) + break; + + VFIO_ASSERT_GT(--attempts, 0); + usleep(sleep_ms * 1000); + } + + err = status & IDXD_CMDSTS_ERR_MASK; + VFIO_ASSERT_EQ(err, 0, "Error issuing command 0x%x: 0x%x\n", cmd, err); +} + +static void dsa_wq_init(struct vfio_pci_device *device) +{ + struct dsa_state *dsa = to_dsa_state(device); + union wq_cap_reg wq_cap = dsa->wq_cap; + union wqcfg wqcfg; + u64 wqcfg_size; + int i; + + VFIO_ASSERT_GT((u32)wq_cap.num_wqs, 0); + + wqcfg = (union wqcfg) { + .wq_size = wq_cap.total_wq_size, + .mode = 1, + .priority = 1, + /* + * Disable Address Translation Service (if enabled) so that VFIO + * selftests using this driver can generate I/O page faults. + */ + .wq_ats_disable = wq_cap.wq_ats_support, + .max_xfer_shift = dsa->gen_cap.max_xfer_shift, + .max_batch_shift = dsa->gen_cap.max_batch_shift, + .op_config[0] = BIT(DSA_OPCODE_MEMMOVE) | BIT(DSA_OPCODE_BATCH), + }; + + wqcfg_size = 1UL << (wq_cap.wqcfg_size + IDXD_WQCFG_MIN); + + for (i = 0; i < wqcfg_size / sizeof(wqcfg.bits[0]); i++) + writel(wqcfg.bits[i], dsa->wqcfg_table + offsetof(union wqcfg, bits[i])); +} + +static void dsa_group_init(struct vfio_pci_device *device) +{ + struct dsa_state *dsa = to_dsa_state(device); + union group_cap_reg group_cap = dsa->group_cap; + union engine_cap_reg engine_cap = dsa->engine_cap; + + VFIO_ASSERT_GT((u32)group_cap.num_groups, 0); + VFIO_ASSERT_GT((u32)engine_cap.num_engines, 0); + + /* Assign work queue 0 and engine 0 to group 0 */ + writeq(1, dsa->grpcfg_table + offsetof(struct grpcfg, wqs[0])); + writeq(1, dsa->grpcfg_table + offsetof(struct grpcfg, engines)); +} + +static void dsa_register_cache_init(struct vfio_pci_device *device) +{ + struct dsa_state *dsa = to_dsa_state(device); + void *bar0 = device->bars[0].vaddr; + + dsa->gen_cap.bits = readq(bar0 + IDXD_GENCAP_OFFSET); + dsa->wq_cap.bits = readq(bar0 + IDXD_WQCAP_OFFSET); + dsa->group_cap.bits = readq(bar0 + IDXD_GRPCAP_OFFSET); + dsa->engine_cap.bits = readq(bar0 + IDXD_ENGCAP_OFFSET); + + dsa->table_offsets.bits[0] = readq(bar0 + IDXD_TABLE_OFFSET); + dsa->table_offsets.bits[1] = readq(bar0 + IDXD_TABLE_OFFSET + 8); + + dsa->wqcfg_table = bar0 + dsa->table_offsets.wqcfg * IDXD_TABLE_MULT; + dsa->grpcfg_table = bar0 + dsa->table_offsets.grpcfg * IDXD_TABLE_MULT; + + dsa->max_batches = 1U << (dsa->wq_cap.total_wq_size + IDXD_WQCFG_MIN); + dsa->max_batches = min(dsa->max_batches, ARRAY_SIZE(dsa->batch)); + + dsa->max_copies_per_batch = 1UL << dsa->gen_cap.max_batch_shift; + dsa->max_copies_per_batch = min(dsa->max_copies_per_batch, ARRAY_SIZE(dsa->copy)); +} + +static void dsa_init(struct vfio_pci_device *device) +{ + struct dsa_state *dsa = to_dsa_state(device); + + VFIO_ASSERT_GE(device->driver.region.size, sizeof(*dsa)); + + vfio_pci_config_writew(device, PCI_COMMAND, + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | + PCI_COMMAND_INTX_DISABLE); + + dsa_command(device, IDXD_CMD_RESET_DEVICE); + + dsa_register_cache_init(device); + dsa_wq_init(device); + dsa_group_init(device); + + dsa_command(device, IDXD_CMD_ENABLE_DEVICE); + dsa_command(device, IDXD_CMD_ENABLE_WQ); + + vfio_pci_msix_enable(device, MSIX_VECTOR, 1); + + device->driver.max_memcpy_count = + dsa->max_batches * dsa->max_copies_per_batch; + device->driver.max_memcpy_size = 1UL << dsa->gen_cap.max_xfer_shift; + device->driver.msi = MSIX_VECTOR; +} + +static void dsa_remove(struct vfio_pci_device *device) +{ + dsa_command(device, IDXD_CMD_RESET_DEVICE); + vfio_pci_msix_disable(device); +} + +static int dsa_completion_wait(struct vfio_pci_device *device, + struct dsa_completion_record *completion) +{ + u8 status; + + for (;;) { + dsa_check_sw_err(device); + + status = READ_ONCE(completion->status); + if (status) + break; + + usleep(1000); + } + + if (status == DSA_COMP_SUCCESS) + return 0; + + printf("Error detected during memcpy operation: 0x%x\n", status); + return -1; +} + +static void dsa_copy_desc_init(struct vfio_pci_device *device, + struct dsa_hw_desc *desc, + iova_t src, iova_t dst, u64 size, + bool interrupt) +{ + struct dsa_state *dsa = to_dsa_state(device); + u16 flags; + + flags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR; + + if (interrupt) + flags |= IDXD_OP_FLAG_RCI; + + *desc = (struct dsa_hw_desc) { + .opcode = DSA_OPCODE_MEMMOVE, + .flags = flags, + .priv = 1, + .src_addr = src, + .dst_addr = dst, + .xfer_size = size, + .completion_addr = to_iova(device, &dsa->copy_completion), + .int_handle = interrupt ? MSIX_VECTOR : 0, + }; +} + +static void dsa_batch_desc_init(struct vfio_pci_device *device, + struct dsa_hw_desc *desc, + u64 count) +{ + struct dsa_state *dsa = to_dsa_state(device); + + *desc = (struct dsa_hw_desc) { + .opcode = DSA_OPCODE_BATCH, + .flags = IDXD_OP_FLAG_CRAV, + .priv = 1, + .completion_addr = to_iova(device, &dsa->batch_completion), + .desc_list_addr = to_iova(device, &dsa->copy[0]), + .desc_count = count, + }; +} + +static void dsa_desc_write(struct vfio_pci_device *device, struct dsa_hw_desc *desc) +{ + /* Write the contents (not address) of the 64-byte descriptor to the device. */ + iosubmit_cmds512(device->bars[2].vaddr, desc, 1); +} + +static void dsa_memcpy_one(struct vfio_pci_device *device, + iova_t src, iova_t dst, u64 size, bool interrupt) +{ + struct dsa_state *dsa = to_dsa_state(device); + + memset(&dsa->copy_completion, 0, sizeof(dsa->copy_completion)); + + dsa_copy_desc_init(device, &dsa->copy[0], src, dst, size, interrupt); + dsa_desc_write(device, &dsa->copy[0]); +} + +static void dsa_memcpy_batch(struct vfio_pci_device *device, + iova_t src, iova_t dst, u64 size, u64 count) +{ + struct dsa_state *dsa = to_dsa_state(device); + int i; + + memset(&dsa->batch_completion, 0, sizeof(dsa->batch_completion)); + + for (i = 0; i < ARRAY_SIZE(dsa->copy); i++) { + struct dsa_hw_desc *copy_desc = &dsa->copy[i]; + + dsa_copy_desc_init(device, copy_desc, src, dst, size, false); + + /* Don't request completions for individual copies. */ + copy_desc->flags &= ~IDXD_OP_FLAG_RCR; + } + + for (i = 0; i < ARRAY_SIZE(dsa->batch) && count; i++) { + struct dsa_hw_desc *batch_desc = &dsa->batch[i]; + int nr_copies; + + nr_copies = min(count, dsa->max_copies_per_batch); + count -= nr_copies; + + /* + * Batches must have at least 2 copies, so handle the case where + * there is exactly 1 copy left by doing one less copy in this + * batch and then 2 in the next. + */ + if (count == 1) { + nr_copies--; + count++; + } + + dsa_batch_desc_init(device, batch_desc, nr_copies); + + /* Request a completion for the last batch. */ + if (!count) + batch_desc->flags |= IDXD_OP_FLAG_RCR; + + dsa_desc_write(device, batch_desc); + } + + VFIO_ASSERT_EQ(count, 0, "Failed to start %lu copies.\n", count); +} + +static void dsa_memcpy_start(struct vfio_pci_device *device, + iova_t src, iova_t dst, u64 size, u64 count) +{ + struct dsa_state *dsa = to_dsa_state(device); + + /* DSA devices require at least 2 copies per batch. */ + if (count == 1) + dsa_memcpy_one(device, src, dst, size, false); + else + dsa_memcpy_batch(device, src, dst, size, count); + + dsa->memcpy_count = count; +} + +static int dsa_memcpy_wait(struct vfio_pci_device *device) +{ + struct dsa_state *dsa = to_dsa_state(device); + int r; + + if (dsa->memcpy_count == 1) + r = dsa_completion_wait(device, &dsa->copy_completion); + else + r = dsa_completion_wait(device, &dsa->batch_completion); + + dsa->memcpy_count = 0; + + return r; +} + +static void dsa_send_msi(struct vfio_pci_device *device) +{ + struct dsa_state *dsa = to_dsa_state(device); + + dsa_memcpy_one(device, + to_iova(device, &dsa->send_msi_src), + to_iova(device, &dsa->send_msi_dst), + sizeof(dsa->send_msi_src), true); + + VFIO_ASSERT_EQ(dsa_completion_wait(device, &dsa->copy_completion), 0); +} + +const struct vfio_pci_driver_ops dsa_ops = { + .name = "dsa", + .probe = dsa_probe, + .init = dsa_init, + .remove = dsa_remove, + .memcpy_start = dsa_memcpy_start, + .memcpy_wait = dsa_memcpy_wait, + .send_msi = dsa_send_msi, +}; diff --git a/tools/testing/selftests/vfio/lib/drivers/dsa/registers.h b/tools/testing/selftests/vfio/lib/drivers/dsa/registers.h new file mode 120000 index 000000000000..bde657c3c2af --- /dev/null +++ b/tools/testing/selftests/vfio/lib/drivers/dsa/registers.h @@ -0,0 +1 @@ +../../../../../../../drivers/dma/idxd/registers.h \ No newline at end of file diff --git a/tools/testing/selftests/vfio/lib/libvfio.mk b/tools/testing/selftests/vfio/lib/libvfio.mk index 624dc267a879..5d11c3a89a28 100644 --- a/tools/testing/selftests/vfio/lib/libvfio.mk +++ b/tools/testing/selftests/vfio/lib/libvfio.mk @@ -8,6 +8,7 @@ LIBVFIO_C += lib/vfio_pci_driver.c ifeq ($(ARCH:x86_64=x86),x86) LIBVFIO_C += lib/drivers/ioat/ioat.c +LIBVFIO_C += lib/drivers/dsa/dsa.c endif LIBVFIO_O := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBVFIO_C)) diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c index aa47360e47a9..e5e8723ecb41 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c @@ -5,11 +5,13 @@ #include #ifdef __x86_64__ +extern struct vfio_pci_driver_ops dsa_ops; extern struct vfio_pci_driver_ops ioat_ops; #endif static struct vfio_pci_driver_ops *driver_ops[] = { #ifdef __x86_64__ + &dsa_ops, &ioat_ops, #endif }; From 118e073ef6a3446862ada27bdca2b8a53447f428 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:10 +0000 Subject: [PATCH 0606/2711] vfio: selftests: Move helper to get cdev path to libvfio Move the helper function to get the VFIO cdev path to libvfio so that it can be used in libvfio in a subsequent commit. No functional change intended. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-24-dmatlack@google.com Signed-off-by: Alex Williamson --- .../selftests/vfio/lib/include/vfio_util.h | 1 + .../selftests/vfio/lib/vfio_pci_device.c | 31 +++++++++++++++++ .../selftests/vfio/vfio_iommufd_setup_test.c | 34 ++----------------- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index a7d05a4299a1..05a10417e0d7 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -175,6 +175,7 @@ struct vfio_pci_device { * If BDF cannot be determined then the test will exit with KSFT_SKIP. */ const char *vfio_selftests_get_bdf(int *argc, char *argv[]); +const char *vfio_pci_get_cdev_path(const char *bdf); struct vfio_pci_device *vfio_pci_device_init(const char *bdf, int iommu_type); void vfio_pci_device_cleanup(struct vfio_pci_device *device); diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index d8bb227e869d..d53e2d682c7e 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only +#include #include #include #include @@ -332,6 +333,36 @@ static void vfio_pci_device_setup(struct vfio_pci_device *device, const char *bd device->msi_eventfds[i] = -1; } +const char *vfio_pci_get_cdev_path(const char *bdf) +{ + char dir_path[PATH_MAX]; + struct dirent *entry; + char *cdev_path; + DIR *dir; + + cdev_path = calloc(PATH_MAX, 1); + VFIO_ASSERT_NOT_NULL(cdev_path); + + snprintf(dir_path, sizeof(dir_path), "/sys/bus/pci/devices/%s/vfio-dev/", bdf); + + dir = opendir(dir_path); + VFIO_ASSERT_NOT_NULL(dir, "Failed to open directory %s\n", dir_path); + + while ((entry = readdir(dir)) != NULL) { + /* Find the file that starts with "vfio" */ + if (strncmp("vfio", entry->d_name, 4)) + continue; + + snprintf(cdev_path, PATH_MAX, "/dev/vfio/devices/%s", entry->d_name); + break; + } + + VFIO_ASSERT_NE(cdev_path[0], 0, "Failed to find vfio cdev file.\n"); + VFIO_ASSERT_EQ(closedir(dir), 0); + + return cdev_path; +} + struct vfio_pci_device *vfio_pci_device_init(const char *bdf, int iommu_type) { struct vfio_pci_device *device; diff --git a/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c b/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c index f45335d9260f..3655106b912d 100644 --- a/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c +++ b/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c @@ -1,8 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include -#include -#include - #include #include #include @@ -11,7 +7,6 @@ #include #include -#include #include #include @@ -19,32 +14,7 @@ #include "../kselftest_harness.h" static const char iommu_dev_path[] = "/dev/iommu"; -static char cdev_path[PATH_MAX] = { '\0' }; - -static void set_cdev_path(const char *bdf) -{ - char dir_path[PATH_MAX]; - DIR *dir; - struct dirent *entry; - - snprintf(dir_path, sizeof(dir_path), "/sys/bus/pci/devices/%s/vfio-dev/", bdf); - - dir = opendir(dir_path); - assert(dir); - - /* Find the file named "vfio" */ - while ((entry = readdir(dir)) != NULL) { - if (!strncmp("vfio", entry->d_name, 4)) { - snprintf(cdev_path, sizeof(cdev_path), "/dev/vfio/devices/%s", - entry->d_name); - break; - } - } - - assert(strlen(cdev_path) > 0); - - closedir(dir); -} +static const char *cdev_path; static int vfio_device_bind_iommufd_ioctl(int cdev_fd, int iommufd) { @@ -150,7 +120,7 @@ int main(int argc, char *argv[]) { const char *device_bdf = vfio_selftests_get_bdf(&argc, argv); - set_cdev_path(device_bdf); + cdev_path = vfio_pci_get_cdev_path(device_bdf); printf("Using cdev device %s\n", cdev_path); return test_harness_run(argc, argv); From 5df9bd6205114fac04c0f9539fa23f996e22a439 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:11 +0000 Subject: [PATCH 0607/2711] vfio: selftests: Encapsulate IOMMU mode Encapsulate the "IOMMU mode" a test should use behind a new struct. In the future this will be used to support other types of IOMMUs besides VFIO_TYPE1_IOMMU, and allow users to select the mode on the command line. No functional change intended. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-25-dmatlack@google.com Signed-off-by: Alex Williamson --- .../selftests/vfio/lib/include/vfio_util.h | 12 +++++- .../selftests/vfio/lib/vfio_pci_device.c | 42 ++++++++++++++++--- .../selftests/vfio/vfio_dma_mapping_test.c | 2 +- .../selftests/vfio/vfio_pci_device_test.c | 4 +- .../selftests/vfio/vfio_pci_driver_test.c | 4 +- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index 05a10417e0d7..d50debd84813 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -47,6 +47,12 @@ VFIO_LOG_AND_EXIT(_fmt, ##__VA_ARGS__); \ } while (0) +struct vfio_iommu_mode { + const char *name; + const char *container_path; + unsigned long iommu_type; +}; + struct vfio_pci_bar { struct vfio_region_info info; void *vaddr; @@ -144,6 +150,8 @@ struct vfio_pci_driver { struct vfio_pci_device { int fd; + + const struct vfio_iommu_mode *iommu_mode; int group_fd; int container_fd; @@ -177,7 +185,9 @@ struct vfio_pci_device { const char *vfio_selftests_get_bdf(int *argc, char *argv[]); const char *vfio_pci_get_cdev_path(const char *bdf); -struct vfio_pci_device *vfio_pci_device_init(const char *bdf, int iommu_type); +extern const char *default_iommu_mode; + +struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_mode); void vfio_pci_device_cleanup(struct vfio_pci_device *device); void vfio_pci_device_reset(struct vfio_pci_device *device); diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index d53e2d682c7e..15e5adb770c3 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -18,7 +18,6 @@ #include "../../../kselftest.h" #include -#define VFIO_DEV_PATH "/dev/vfio/vfio" #define PCI_SYSFS_PATH "/sys/bus/pci/devices" #define ioctl_assert(_fd, _op, _arg) do { \ @@ -261,10 +260,11 @@ static unsigned int vfio_pci_get_group_from_dev(const char *bdf) static void vfio_pci_container_setup(struct vfio_pci_device *device) { + const char *path = device->iommu_mode->container_path; int version; - device->container_fd = open(VFIO_DEV_PATH, O_RDWR); - VFIO_ASSERT_GE(device->container_fd, 0, "open(%s) failed\n", VFIO_DEV_PATH); + device->container_fd = open(path, O_RDWR); + VFIO_ASSERT_GE(device->container_fd, 0, "open(%s) failed\n", path); version = ioctl(device->container_fd, VFIO_GET_API_VERSION); VFIO_ASSERT_EQ(version, VFIO_API_VERSION); @@ -290,8 +290,9 @@ static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf ioctl_assert(device->group_fd, VFIO_GROUP_SET_CONTAINER, &device->container_fd); } -static void vfio_pci_iommu_setup(struct vfio_pci_device *device, unsigned long iommu_type) +static void vfio_pci_iommu_setup(struct vfio_pci_device *device) { + unsigned long iommu_type = device->iommu_mode->iommu_type; int ret; INIT_LIST_HEAD(&device->dma_regions); @@ -363,16 +364,45 @@ const char *vfio_pci_get_cdev_path(const char *bdf) return cdev_path; } -struct vfio_pci_device *vfio_pci_device_init(const char *bdf, int iommu_type) +static const struct vfio_iommu_mode iommu_modes[] = { + { + .name = "vfio_type1_iommu", + .container_path = "/dev/vfio/vfio", + .iommu_type = VFIO_TYPE1_IOMMU, + }, +}; + +const char *default_iommu_mode = "vfio_type1_iommu"; + +static const struct vfio_iommu_mode *lookup_iommu_mode(const char *iommu_mode) +{ + int i; + + if (!iommu_mode) + iommu_mode = default_iommu_mode; + + for (i = 0; i < ARRAY_SIZE(iommu_modes); i++) { + if (strcmp(iommu_mode, iommu_modes[i].name)) + continue; + + return &iommu_modes[i]; + } + + VFIO_FAIL("Unrecognized IOMMU mode: %s\n", iommu_mode); +} + +struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_mode) { struct vfio_pci_device *device; device = calloc(1, sizeof(*device)); VFIO_ASSERT_NOT_NULL(device); + device->iommu_mode = lookup_iommu_mode(iommu_mode); + vfio_pci_container_setup(device); vfio_pci_group_setup(device, bdf); - vfio_pci_iommu_setup(device, iommu_type); + vfio_pci_iommu_setup(device); vfio_pci_device_setup(device, bdf); vfio_pci_driver_probe(device); diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c index 4578ee6df0e1..f07bdb602422 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -116,7 +116,7 @@ FIXTURE_VARIANT_ADD(vfio_dma_mapping_test, anonymous_hugetlb_1gb) { FIXTURE_SETUP(vfio_dma_mapping_test) { - self->device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); + self->device = vfio_pci_device_init(device_bdf, default_iommu_mode); } FIXTURE_TEARDOWN(vfio_dma_mapping_test) diff --git a/tools/testing/selftests/vfio/vfio_pci_device_test.c b/tools/testing/selftests/vfio/vfio_pci_device_test.c index 8856205d52a6..7a270698e4d2 100644 --- a/tools/testing/selftests/vfio/vfio_pci_device_test.c +++ b/tools/testing/selftests/vfio/vfio_pci_device_test.c @@ -28,7 +28,7 @@ FIXTURE(vfio_pci_device_test) { FIXTURE_SETUP(vfio_pci_device_test) { - self->device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); + self->device = vfio_pci_device_init(device_bdf, default_iommu_mode); } FIXTURE_TEARDOWN(vfio_pci_device_test) @@ -116,7 +116,7 @@ FIXTURE_VARIANT_ADD(vfio_pci_irq_test, msix) { FIXTURE_SETUP(vfio_pci_irq_test) { - self->device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); + self->device = vfio_pci_device_init(device_bdf, default_iommu_mode); } FIXTURE_TEARDOWN(vfio_pci_irq_test) diff --git a/tools/testing/selftests/vfio/vfio_pci_driver_test.c b/tools/testing/selftests/vfio/vfio_pci_driver_test.c index 97ed0ff4636d..14ec862c0b11 100644 --- a/tools/testing/selftests/vfio/vfio_pci_driver_test.c +++ b/tools/testing/selftests/vfio/vfio_pci_driver_test.c @@ -60,7 +60,7 @@ FIXTURE_SETUP(vfio_pci_driver_test) { struct vfio_pci_driver *driver; - self->device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); + self->device = vfio_pci_device_init(device_bdf, default_iommu_mode); driver = &self->device->driver; @@ -222,7 +222,7 @@ int main(int argc, char *argv[]) device_bdf = vfio_selftests_get_bdf(&argc, argv); - device = vfio_pci_device_init(device_bdf, VFIO_TYPE1_IOMMU); + device = vfio_pci_device_init(device_bdf, default_iommu_mode); if (!device->driver.ops) { fprintf(stderr, "No driver found for device %s\n", device_bdf); return KSFT_SKIP; From 892aff147a545fa7c94d98613093afa84faa25b1 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:12 +0000 Subject: [PATCH 0608/2711] vfio: selftests: Replicate tests across all iommu_modes Automatically replicate vfio_dma_mapping_test and vfio_pci_driver_test across all supported IOMMU modes using fixture variants. Both of these tests exercise DMA mapping to some degree so having automatic coverage across all IOMMU modes will help catch bugs. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-26-dmatlack@google.com Signed-off-by: Alex Williamson --- .../selftests/vfio/lib/include/vfio_util.h | 8 +++++++ .../selftests/vfio/lib/vfio_pci_device.c | 1 + .../selftests/vfio/vfio_dma_mapping_test.c | 24 +++++++++---------- .../selftests/vfio/vfio_pci_driver_test.c | 13 +++++++++- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index d50debd84813..bf0b636a9c0c 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -53,6 +53,14 @@ struct vfio_iommu_mode { unsigned long iommu_type; }; +/* + * Generator for VFIO selftests fixture variants that replicate across all + * possible IOMMU modes. Tests must define FIXTURE_VARIANT_ADD_IOMMU_MODE() + * which should then use FIXTURE_VARIANT_ADD() to create the variant. + */ +#define FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(...) \ +FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1_iommu, ##__VA_ARGS__) + struct vfio_pci_bar { struct vfio_region_info info; void *vaddr; diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index 15e5adb770c3..5c4d008f2a25 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -364,6 +364,7 @@ const char *vfio_pci_get_cdev_path(const char *bdf) return cdev_path; } +/* Reminder: Keep in sync with FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(). */ static const struct vfio_iommu_mode iommu_modes[] = { { .name = "vfio_type1_iommu", diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c index f07bdb602422..b65949c6b846 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -96,27 +96,25 @@ FIXTURE(vfio_dma_mapping_test) { }; FIXTURE_VARIANT(vfio_dma_mapping_test) { + const char *iommu_mode; u64 size; int mmap_flags; }; -FIXTURE_VARIANT_ADD(vfio_dma_mapping_test, anonymous) { - .mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE, -}; +#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode, _name, _size, _mmap_flags) \ +FIXTURE_VARIANT_ADD(vfio_dma_mapping_test, _iommu_mode ## _ ## _name) { \ + .iommu_mode = #_iommu_mode, \ + .size = (_size), \ + .mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE | (_mmap_flags), \ +} -FIXTURE_VARIANT_ADD(vfio_dma_mapping_test, anonymous_hugetlb_2mb) { - .size = SZ_2M, - .mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_2MB, -}; - -FIXTURE_VARIANT_ADD(vfio_dma_mapping_test, anonymous_hugetlb_1gb) { - .size = SZ_1G, - .mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_1GB, -}; +FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous, 0, 0); +FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_2mb, SZ_2M, MAP_HUGETLB | MAP_HUGE_2MB); +FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_1gb, SZ_1G, MAP_HUGETLB | MAP_HUGE_1GB); FIXTURE_SETUP(vfio_dma_mapping_test) { - self->device = vfio_pci_device_init(device_bdf, default_iommu_mode); + self->device = vfio_pci_device_init(device_bdf, variant->iommu_mode); } FIXTURE_TEARDOWN(vfio_dma_mapping_test) diff --git a/tools/testing/selftests/vfio/vfio_pci_driver_test.c b/tools/testing/selftests/vfio/vfio_pci_driver_test.c index 14ec862c0b11..2dbd70b7db62 100644 --- a/tools/testing/selftests/vfio/vfio_pci_driver_test.c +++ b/tools/testing/selftests/vfio/vfio_pci_driver_test.c @@ -56,11 +56,22 @@ FIXTURE(vfio_pci_driver_test) { iova_t unmapped_iova; }; +FIXTURE_VARIANT(vfio_pci_driver_test) { + const char *iommu_mode; +}; + +#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode) \ +FIXTURE_VARIANT_ADD(vfio_pci_driver_test, _iommu_mode) { \ + .iommu_mode = #_iommu_mode, \ +} + +FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(); + FIXTURE_SETUP(vfio_pci_driver_test) { struct vfio_pci_driver *driver; - self->device = vfio_pci_device_init(device_bdf, default_iommu_mode); + self->device = vfio_pci_device_init(device_bdf, variant->iommu_mode); driver = &self->device->driver; From 0969c685ba5b248648533a3313f55a3fd9382a9e Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:13 +0000 Subject: [PATCH 0609/2711] vfio: selftests: Add vfio_type1v2_mode Add a new IOMMU mode for using VFIO_TYPE1v2_IOMMU. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-27-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/lib/include/vfio_util.h | 3 ++- tools/testing/selftests/vfio/lib/vfio_pci_device.c | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index bf0b636a9c0c..981ddc9a52a9 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -59,7 +59,8 @@ struct vfio_iommu_mode { * which should then use FIXTURE_VARIANT_ADD() to create the variant. */ #define FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(...) \ -FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1_iommu, ##__VA_ARGS__) +FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1_iommu, ##__VA_ARGS__); \ +FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1v2_iommu, ##__VA_ARGS__) struct vfio_pci_bar { struct vfio_region_info info; diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index 5c4d008f2a25..cc1b732dd8ba 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -371,6 +371,11 @@ static const struct vfio_iommu_mode iommu_modes[] = { .container_path = "/dev/vfio/vfio", .iommu_type = VFIO_TYPE1_IOMMU, }, + { + .name = "vfio_type1v2_iommu", + .container_path = "/dev/vfio/vfio", + .iommu_type = VFIO_TYPE1v2_IOMMU, + }, }; const char *default_iommu_mode = "vfio_type1_iommu"; From d1a17495bb878542898d7ca4aa8fde29423a8ee0 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:14 +0000 Subject: [PATCH 0610/2711] vfio: selftests: Add iommufd_compat_type1{,v2} modes Add new IOMMU modes for using iommufd in compatibility mode with VFIO_TYPE1_IOMMU and VFIO_TYPE1v2_IOMMU. In these modes, VFIO selftests will open /dev/iommu and treats it as a container FD (as if it had opened /dev/vfio/vfio) and the kernel translates the container ioctls to iommufd calls transparently. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-28-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/lib/include/vfio_util.h | 4 +++- tools/testing/selftests/vfio/lib/vfio_pci_device.c | 10 ++++++++++ tools/testing/selftests/vfio/vfio_dma_mapping_test.c | 12 ++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index 981ddc9a52a9..035ef5b9d678 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -60,7 +60,9 @@ struct vfio_iommu_mode { */ #define FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(...) \ FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1_iommu, ##__VA_ARGS__); \ -FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1v2_iommu, ##__VA_ARGS__) +FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1v2_iommu, ##__VA_ARGS__); \ +FIXTURE_VARIANT_ADD_IOMMU_MODE(iommufd_compat_type1, ##__VA_ARGS__); \ +FIXTURE_VARIANT_ADD_IOMMU_MODE(iommufd_compat_type1v2, ##__VA_ARGS__) struct vfio_pci_bar { struct vfio_region_info info; diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index cc1b732dd8ba..b6fefe2b3ec8 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -376,6 +376,16 @@ static const struct vfio_iommu_mode iommu_modes[] = { .container_path = "/dev/vfio/vfio", .iommu_type = VFIO_TYPE1v2_IOMMU, }, + { + .name = "iommufd_compat_type1", + .container_path = "/dev/iommu", + .iommu_type = VFIO_TYPE1_IOMMU, + }, + { + .name = "iommufd_compat_type1v2", + .container_path = "/dev/iommu", + .iommu_type = VFIO_TYPE1v2_IOMMU, + }, }; const char *default_iommu_mode = "vfio_type1_iommu"; diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c index b65949c6b846..ab19c54a774d 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -128,6 +128,7 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) const int flags = variant->mmap_flags; struct vfio_dma_region region; struct iommu_mapping mapping; + u64 mapping_size = size; int rc; region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); @@ -150,6 +151,13 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) if (rc == -EOPNOTSUPP) goto unmap; + /* + * IOMMUFD compatibility-mode does not support huge mappings when + * using VFIO_TYPE1_IOMMU. + */ + if (!strcmp(variant->iommu_mode, "iommufd_compat_type1")) + mapping_size = SZ_4K; + ASSERT_EQ(0, rc); printf("Found IOMMU mappings for IOVA 0x%lx:\n", region.iova); printf("PGD: 0x%016lx\n", mapping.pgd); @@ -158,7 +166,7 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) printf("PMD: 0x%016lx\n", mapping.pmd); printf("PTE: 0x%016lx\n", mapping.pte); - switch (size) { + switch (mapping_size) { case SZ_4K: ASSERT_NE(0, mapping.pte); break; @@ -172,7 +180,7 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) ASSERT_NE(0, mapping.pud); break; default: - VFIO_FAIL("Unrecognized size: 0x%lx\n", size); + VFIO_FAIL("Unrecognized size: 0x%lx\n", mapping_size); } unmap: From 61cbfe5014cbc17b376b6a9b2087f39f379a6b86 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:15 +0000 Subject: [PATCH 0611/2711] vfio: selftests: Add iommufd mode Add a new IOMMU mode for using iommufd directly. In this mode userspace opens /dev/iommu and binds it to a device FD acquired through /dev/vfio/devices/vfioX. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-29-dmatlack@google.com Signed-off-by: Alex Williamson --- .../selftests/vfio/lib/include/vfio_util.h | 6 +- .../selftests/vfio/lib/vfio_pci_device.c | 181 ++++++++++++++---- 2 files changed, 149 insertions(+), 38 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/testing/selftests/vfio/lib/include/vfio_util.h index 035ef5b9d678..ed31606e01b7 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -62,7 +62,8 @@ struct vfio_iommu_mode { FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1_iommu, ##__VA_ARGS__); \ FIXTURE_VARIANT_ADD_IOMMU_MODE(vfio_type1v2_iommu, ##__VA_ARGS__); \ FIXTURE_VARIANT_ADD_IOMMU_MODE(iommufd_compat_type1, ##__VA_ARGS__); \ -FIXTURE_VARIANT_ADD_IOMMU_MODE(iommufd_compat_type1v2, ##__VA_ARGS__) +FIXTURE_VARIANT_ADD_IOMMU_MODE(iommufd_compat_type1v2, ##__VA_ARGS__); \ +FIXTURE_VARIANT_ADD_IOMMU_MODE(iommufd, ##__VA_ARGS__) struct vfio_pci_bar { struct vfio_region_info info; @@ -166,6 +167,9 @@ struct vfio_pci_device { int group_fd; int container_fd; + int iommufd; + u32 ioas_id; + struct vfio_device_info info; struct vfio_region_info config_space; struct vfio_pci_bar bars[PCI_STD_NUM_BARS]; diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index b6fefe2b3ec8..5d8944a37982 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -10,10 +10,12 @@ #include #include +#include #include #include #include #include +#include #include "../../../kselftest.h" #include @@ -139,32 +141,80 @@ static void vfio_pci_irq_get(struct vfio_pci_device *device, u32 index, ioctl_assert(device->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info); } -void vfio_pci_dma_map(struct vfio_pci_device *device, - struct vfio_dma_region *region) +static void vfio_iommu_dma_map(struct vfio_pci_device *device, + struct vfio_dma_region *region) { - struct vfio_iommu_type1_dma_map map = { - .argsz = sizeof(map), + struct vfio_iommu_type1_dma_map args = { + .argsz = sizeof(args), .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE, .vaddr = (u64)region->vaddr, .iova = region->iova, .size = region->size, }; - ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &map); + ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &args); +} + +static void iommufd_dma_map(struct vfio_pci_device *device, + struct vfio_dma_region *region) +{ + struct iommu_ioas_map args = { + .size = sizeof(args), + .flags = IOMMU_IOAS_MAP_READABLE | + IOMMU_IOAS_MAP_WRITEABLE | + IOMMU_IOAS_MAP_FIXED_IOVA, + .user_va = (u64)region->vaddr, + .iova = region->iova, + .length = region->size, + .ioas_id = device->ioas_id, + }; + + ioctl_assert(device->iommufd, IOMMU_IOAS_MAP, &args); +} + +void vfio_pci_dma_map(struct vfio_pci_device *device, + struct vfio_dma_region *region) +{ + if (device->iommufd) + iommufd_dma_map(device, region); + else + vfio_iommu_dma_map(device, region); list_add(®ion->link, &device->dma_regions); } +static void vfio_iommu_dma_unmap(struct vfio_pci_device *device, + struct vfio_dma_region *region) +{ + struct vfio_iommu_type1_dma_unmap args = { + .argsz = sizeof(args), + .iova = region->iova, + .size = region->size, + }; + + ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &args); +} + +static void iommufd_dma_unmap(struct vfio_pci_device *device, + struct vfio_dma_region *region) +{ + struct iommu_ioas_unmap args = { + .size = sizeof(args), + .iova = region->iova, + .length = region->size, + .ioas_id = device->ioas_id, + }; + + ioctl_assert(device->iommufd, IOMMU_IOAS_UNMAP, &args); +} + void vfio_pci_dma_unmap(struct vfio_pci_device *device, struct vfio_dma_region *region) { - struct vfio_iommu_type1_dma_unmap unmap = { - .argsz = sizeof(unmap), - .iova = region->iova, - .size = region->size, - }; - - ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &unmap); + if (device->iommufd) + iommufd_dma_unmap(device, region); + else + vfio_iommu_dma_unmap(device, region); list_del(®ion->link); } @@ -258,18 +308,6 @@ static unsigned int vfio_pci_get_group_from_dev(const char *bdf) return group; } -static void vfio_pci_container_setup(struct vfio_pci_device *device) -{ - const char *path = device->iommu_mode->container_path; - int version; - - device->container_fd = open(path, O_RDWR); - VFIO_ASSERT_GE(device->container_fd, 0, "open(%s) failed\n", path); - - version = ioctl(device->container_fd, VFIO_GET_API_VERSION); - VFIO_ASSERT_EQ(version, VFIO_API_VERSION); -} - static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf) { struct vfio_group_status group_status = { @@ -290,25 +328,33 @@ static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf ioctl_assert(device->group_fd, VFIO_GROUP_SET_CONTAINER, &device->container_fd); } -static void vfio_pci_iommu_setup(struct vfio_pci_device *device) +static void vfio_pci_container_setup(struct vfio_pci_device *device, const char *bdf) { unsigned long iommu_type = device->iommu_mode->iommu_type; + const char *path = device->iommu_mode->container_path; + int version; int ret; - INIT_LIST_HEAD(&device->dma_regions); + device->container_fd = open(path, O_RDWR); + VFIO_ASSERT_GE(device->container_fd, 0, "open(%s) failed\n", path); + + version = ioctl(device->container_fd, VFIO_GET_API_VERSION); + VFIO_ASSERT_EQ(version, VFIO_API_VERSION, "Unsupported version: %d\n", version); + + vfio_pci_group_setup(device, bdf); ret = ioctl(device->container_fd, VFIO_CHECK_EXTENSION, iommu_type); VFIO_ASSERT_GT(ret, 0, "VFIO IOMMU type %lu not supported\n", iommu_type); ioctl_assert(device->container_fd, VFIO_SET_IOMMU, (void *)iommu_type); -} - -static void vfio_pci_device_setup(struct vfio_pci_device *device, const char *bdf) -{ - int i; device->fd = ioctl(device->group_fd, VFIO_GROUP_GET_DEVICE_FD, bdf); VFIO_ASSERT_GE(device->fd, 0); +} + +static void vfio_pci_device_setup(struct vfio_pci_device *device) +{ + int i; device->info.argsz = sizeof(device->info); ioctl_assert(device->fd, VFIO_DEVICE_GET_INFO, &device->info); @@ -386,6 +432,9 @@ static const struct vfio_iommu_mode iommu_modes[] = { .container_path = "/dev/iommu", .iommu_type = VFIO_TYPE1v2_IOMMU, }, + { + .name = "iommufd", + }, }; const char *default_iommu_mode = "vfio_type1_iommu"; @@ -407,6 +456,57 @@ static const struct vfio_iommu_mode *lookup_iommu_mode(const char *iommu_mode) VFIO_FAIL("Unrecognized IOMMU mode: %s\n", iommu_mode); } +static void vfio_device_bind_iommufd(int device_fd, int iommufd) +{ + struct vfio_device_bind_iommufd args = { + .argsz = sizeof(args), + .iommufd = iommufd, + }; + + ioctl_assert(device_fd, VFIO_DEVICE_BIND_IOMMUFD, &args); +} + +static u32 iommufd_ioas_alloc(int iommufd) +{ + struct iommu_ioas_alloc args = { + .size = sizeof(args), + }; + + ioctl_assert(iommufd, IOMMU_IOAS_ALLOC, &args); + return args.out_ioas_id; +} + +static void vfio_device_attach_iommufd_pt(int device_fd, u32 pt_id) +{ + struct vfio_device_attach_iommufd_pt args = { + .argsz = sizeof(args), + .pt_id = pt_id, + }; + + ioctl_assert(device_fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &args); +} + +static void vfio_pci_iommufd_setup(struct vfio_pci_device *device, const char *bdf) +{ + const char *cdev_path = vfio_pci_get_cdev_path(bdf); + + device->fd = open(cdev_path, O_RDWR); + VFIO_ASSERT_GE(device->fd, 0); + free((void *)cdev_path); + + /* + * Require device->iommufd to be >0 so that a simple non-0 check can be + * used to check if iommufd is enabled. In practice open() will never + * return 0 unless stdin is closed. + */ + device->iommufd = open("/dev/iommu", O_RDWR); + VFIO_ASSERT_GT(device->iommufd, 0); + + vfio_device_bind_iommufd(device->fd, device->iommufd); + device->ioas_id = iommufd_ioas_alloc(device->iommufd); + vfio_device_attach_iommufd_pt(device->fd, device->ioas_id); +} + struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_mode) { struct vfio_pci_device *device; @@ -414,13 +514,16 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, const char *iommu_ device = calloc(1, sizeof(*device)); VFIO_ASSERT_NOT_NULL(device); + INIT_LIST_HEAD(&device->dma_regions); + device->iommu_mode = lookup_iommu_mode(iommu_mode); - vfio_pci_container_setup(device); - vfio_pci_group_setup(device, bdf); - vfio_pci_iommu_setup(device); - vfio_pci_device_setup(device, bdf); + if (device->iommu_mode->container_path) + vfio_pci_container_setup(device, bdf); + else + vfio_pci_iommufd_setup(device, bdf); + vfio_pci_device_setup(device); vfio_pci_driver_probe(device); return device; @@ -444,8 +547,12 @@ void vfio_pci_device_cleanup(struct vfio_pci_device *device) VFIO_ASSERT_EQ(close(device->msi_eventfds[i]), 0); } - VFIO_ASSERT_EQ(close(device->group_fd), 0); - VFIO_ASSERT_EQ(close(device->container_fd), 0); + if (device->iommufd) { + VFIO_ASSERT_EQ(close(device->iommufd), 0); + } else { + VFIO_ASSERT_EQ(close(device->group_fd), 0); + VFIO_ASSERT_EQ(close(device->container_fd), 0); + } free(device); } From 8afcbe20476ad238fd1f331f51d721138eff5172 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:16 +0000 Subject: [PATCH 0612/2711] vfio: selftests: Make iommufd the default iommu_mode Now that VFIO selftests support iommufd, make it the default mode. IOMMUFD is the successor to VFIO_TYPE1{,v2}_IOMMU and all new features are being added there, so it's a slightly better fit as the default mode. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-30-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/lib/vfio_pci_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index 5d8944a37982..0921b2451ba5 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -437,7 +437,7 @@ static const struct vfio_iommu_mode iommu_modes[] = { }, }; -const char *default_iommu_mode = "vfio_type1_iommu"; +const char *default_iommu_mode = "iommufd"; static const struct vfio_iommu_mode *lookup_iommu_mode(const char *iommu_mode) { From fd134b0f2f8ef9b1b7b0cade8cac4ff831619713 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Fri, 22 Aug 2025 21:25:17 +0000 Subject: [PATCH 0613/2711] vfio: selftests: Add a script to help with running VFIO selftests Introduce run.sh, a script to help with running VFIO selftests. The script is intended to be used for both humans manually running VFIO selftests, and to incorporate into test automation where VFIO selftests may run alongside other tests. As such the script aims to be hermetic, returning the system to the state it was before the test started. The script takes as input the BDF of a device to use and a command to run (typically the command would be a VFIO selftest). e.g. $ ./run.sh -d 0000:6a:01.0 ./vfio_pci_device_test or $ ./run.sh -d 0000:6a:01.0 -- ./vfio_pci_device_test The script then handles unbinding device 0000:6a:01.0 from its current driver, binding it to vfio-pci, running the test, unbinding from vfio-pci, and binding back to the original driver. When run.sh runs the provided test, it does so by appending the BDF as the last parameter. For example: $ ./run.sh -d 0000:6a:01.0 -- echo hello Results in the following being printed to stdout: hello 0000:6a:01.0 The script also supports a mode where it can break out into a shell so that multiple tests can be run manually. $ ./run.sh -d 0000:6a:01.0 -s $ echo $VFIO_SELFTESTS_BDF $ ./vfio_pci_device_test $ exit Choosing which device to use is up to the user. In the future this script should be extensible to tests that want to use multiple devices. The script can support accepting -d BDF multiple times and parse them into an array, setup all the devices, pass the list of BDFs to the test, and then cleanup all the devices. Acked-by: Shuah Khan Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250822212518.4156428-31-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/Makefile | 1 + tools/testing/selftests/vfio/run.sh | 109 ++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100755 tools/testing/selftests/vfio/run.sh diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile index ee09c027ade5..324ba0175a33 100644 --- a/tools/testing/selftests/vfio/Makefile +++ b/tools/testing/selftests/vfio/Makefile @@ -3,6 +3,7 @@ TEST_GEN_PROGS += vfio_dma_mapping_test TEST_GEN_PROGS += vfio_iommufd_setup_test TEST_GEN_PROGS += vfio_pci_device_test TEST_GEN_PROGS += vfio_pci_driver_test +TEST_PROGS_EXTENDED := run.sh include ../lib.mk include lib/libvfio.mk diff --git a/tools/testing/selftests/vfio/run.sh b/tools/testing/selftests/vfio/run.sh new file mode 100755 index 000000000000..0476b6d7adc3 --- /dev/null +++ b/tools/testing/selftests/vfio/run.sh @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Global variables initialized in main() and then used during cleanup() when +# the script exits. +declare DEVICE_BDF +declare NEW_DRIVER +declare OLD_DRIVER +declare OLD_NUMVFS +declare DRIVER_OVERRIDE + +function write_to() { + # Unfortunately set -x does not show redirects so use echo to manually + # tell the user what commands are being run. + echo "+ echo \"${2}\" > ${1}" + echo "${2}" > ${1} +} + +function bind() { + write_to /sys/bus/pci/drivers/${2}/bind ${1} +} + +function unbind() { + write_to /sys/bus/pci/drivers/${2}/unbind ${1} +} + +function set_sriov_numvfs() { + write_to /sys/bus/pci/devices/${1}/sriov_numvfs ${2} +} + +function set_driver_override() { + write_to /sys/bus/pci/devices/${1}/driver_override ${2} +} + +function clear_driver_override() { + set_driver_override ${1} "" +} + +function cleanup() { + if [ "${NEW_DRIVER}" ]; then unbind ${DEVICE_BDF} ${NEW_DRIVER} ; fi + if [ "${DRIVER_OVERRIDE}" ]; then clear_driver_override ${DEVICE_BDF} ; fi + if [ "${OLD_DRIVER}" ]; then bind ${DEVICE_BDF} ${OLD_DRIVER} ; fi + if [ "${OLD_NUMVFS}" ]; then set_sriov_numvfs ${DEVICE_BDF} ${OLD_NUMVFS} ; fi +} + +function usage() { + echo "usage: $0 [-d segment:bus:device.function] [-s] [-h] [cmd ...]" >&2 + echo >&2 + echo " -d: The BDF of the device to use for the test (required)" >&2 + echo " -h: Show this help message" >&2 + echo " -s: Drop into a shell rather than running a command" >&2 + echo >&2 + echo " cmd: The command to run and arguments to pass to it." >&2 + echo " Required when not using -s. The SBDF will be " >&2 + echo " appended to the argument list." >&2 + exit 1 +} + +function main() { + local shell + + while getopts "d:hs" opt; do + case $opt in + d) DEVICE_BDF="$OPTARG" ;; + s) shell=true ;; + *) usage ;; + esac + done + + # Shift past all optional arguments. + shift $((OPTIND - 1)) + + # Check that the user passed in the command to run. + [ ! "${shell}" ] && [ $# = 0 ] && usage + + # Check that the user passed in a BDF. + [ "${DEVICE_BDF}" ] || usage + + trap cleanup EXIT + set -e + + test -d /sys/bus/pci/devices/${DEVICE_BDF} + + if [ -f /sys/bus/pci/devices/${DEVICE_BDF}/sriov_numvfs ]; then + OLD_NUMVFS=$(cat /sys/bus/pci/devices/${DEVICE_BDF}/sriov_numvfs) + set_sriov_numvfs ${DEVICE_BDF} 0 + fi + + if [ -L /sys/bus/pci/devices/${DEVICE_BDF}/driver ]; then + OLD_DRIVER=$(basename $(readlink -m /sys/bus/pci/devices/${DEVICE_BDF}/driver)) + unbind ${DEVICE_BDF} ${OLD_DRIVER} + fi + + set_driver_override ${DEVICE_BDF} vfio-pci + DRIVER_OVERRIDE=true + + bind ${DEVICE_BDF} vfio-pci + NEW_DRIVER=vfio-pci + + echo + if [ "${shell}" ]; then + echo "Dropping into ${SHELL} with VFIO_SELFTESTS_BDF=${DEVICE_BDF}" + VFIO_SELFTESTS_BDF=${DEVICE_BDF} ${SHELL} + else + "$@" ${DEVICE_BDF} + fi + echo +} + +main "$@" From fcf9ae9ec9761802b69294d1b3f98d51f14e5175 Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Wed, 27 Aug 2025 15:32:15 +0100 Subject: [PATCH 0614/2711] MAINTAINERS: Update Shameer Kolothum's email address Changed jobs and Huawei email is no longer valid. Also, since I no longer have access to HiSilicon hardware, remove myself from HISILICON PCI DRIVER maintainer entry. Acked-by: Jonathan Cameron Signed-off-by: Shameer Kolothum Link: https://lore.kernel.org/r/20250827143215.2311-1-skolothumtho@nvidia.com Signed-off-by: Alex Williamson --- .mailmap | 1 + MAINTAINERS | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.mailmap b/.mailmap index a124aeed52a2..12caec550f9e 100644 --- a/.mailmap +++ b/.mailmap @@ -705,6 +705,7 @@ Sergey Senozhatsky Sergey Senozhatsky Seth Forshee Shakeel Butt +Shameer Kolothum Shannon Nelson Shannon Nelson Shannon Nelson diff --git a/MAINTAINERS b/MAINTAINERS index fba915fcb30e..839f910bad6b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26449,7 +26449,6 @@ F: drivers/vfio/fsl-mc/ VFIO HISILICON PCI DRIVER M: Longfang Liu -M: Shameer Kolothum L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/pci/hisilicon/ @@ -26478,7 +26477,7 @@ F: drivers/vfio/pci/nvgrace-gpu/ VFIO PCI DEVICE SPECIFIC DRIVERS R: Jason Gunthorpe R: Yishai Hadas -R: Shameer Kolothum +R: Shameer Kolothum R: Kevin Tian L: kvm@vger.kernel.org S: Maintained From ab1d8dda32e9507ca3bfb6b43661aeaa27f7bd82 Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Tue, 26 Aug 2025 10:08:51 +0530 Subject: [PATCH 0615/2711] cdx: don't select CONFIG_GENERIC_MSI_IRQ x86 does not use CONFIG_GENERIC_MSI_IRQ, and trying to enable it anyway results in a build failure: In file included from include/linux/ssb/ssb.h:10, from drivers/ssb/pcihost_wrapper.c:18: include/linux/gpio/driver.h:41:33: error: field 'msiinfo' has incomplete type 41 | msi_alloc_info_t msiinfo; | ^~~~~~~ In file included from include/linux/kvm_host.h:19, from arch/x86/events/intel/core.c:17: include/linux/msi.h:528:33: error: field 'alloc_info' has incomplete type 528 | msi_alloc_info_t alloc_info; Change the driver to actually build without this symbol and remove the incorrect 'select' statements. Fixes: e8b18c11731d ("cdx: Fix missing GENERIC_MSI_IRQ on compile test") Reviewed-by: Robin Murphy Reviewed-by: Nikhil Agarwal Signed-off-by: Arnd Bergmann Signed-off-by: Nipun Gupta Link: https://lore.kernel.org/r/20250826043852.2206008-1-nipun.gupta@amd.com Signed-off-by: Alex Williamson --- drivers/cdx/Kconfig | 1 - drivers/cdx/cdx.c | 4 ++-- drivers/cdx/controller/Kconfig | 1 - drivers/cdx/controller/cdx_controller.c | 3 ++- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/cdx/Kconfig b/drivers/cdx/Kconfig index 3af41f51cf38..1f1e360507d7 100644 --- a/drivers/cdx/Kconfig +++ b/drivers/cdx/Kconfig @@ -8,7 +8,6 @@ config CDX_BUS bool "CDX Bus driver" depends on OF && ARM64 || COMPILE_TEST - select GENERIC_MSI_IRQ help Driver to enable Composable DMA Transfer(CDX) Bus. CDX bus exposes Fabric devices which uses composable DMA IP to the diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index 092306ca2541..3d50f8cd9c0b 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -310,7 +310,7 @@ static int cdx_probe(struct device *dev) * Setup MSI device data so that generic MSI alloc/free can * be used by the device driver. */ - if (cdx->msi_domain) { + if (IS_ENABLED(CONFIG_GENERIC_MSI_IRQ) && cdx->msi_domain) { error = msi_setup_device_data(&cdx_dev->dev); if (error) return error; @@ -833,7 +833,7 @@ int cdx_device_add(struct cdx_dev_params *dev_params) ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (cdx_dev->bus_num & CDX_BUS_NUM_MASK)), cdx_dev->dev_num); - if (cdx->msi_domain) { + if (IS_ENABLED(CONFIG_GENERIC_MSI_IRQ) && cdx->msi_domain) { cdx_dev->num_msi = dev_params->num_msi; dev_set_msi_domain(&cdx_dev->dev, cdx->msi_domain); } diff --git a/drivers/cdx/controller/Kconfig b/drivers/cdx/controller/Kconfig index 0641a4c21e66..a480b62cbd1f 100644 --- a/drivers/cdx/controller/Kconfig +++ b/drivers/cdx/controller/Kconfig @@ -10,7 +10,6 @@ if CDX_BUS config CDX_CONTROLLER tristate "CDX bus controller" depends on HAS_DMA - select GENERIC_MSI_IRQ select REMOTEPROC select RPMSG help diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index fca83141e3e6..5e3fd89b6b56 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -193,7 +193,8 @@ static int xlnx_cdx_probe(struct platform_device *pdev) cdx->ops = &cdx_ops; /* Create MSI domain */ - cdx->msi_domain = cdx_msi_domain_init(&pdev->dev); + if (IS_ENABLED(CONFIG_GENERIC_MSI_IRQ)) + cdx->msi_domain = cdx_msi_domain_init(&pdev->dev); if (!cdx->msi_domain) { ret = dev_err_probe(&pdev->dev, -ENODEV, "cdx_msi_domain_init() failed"); goto cdx_msi_fail; From 9f3acb3d9a1872e2fa36af068ca2e93a8a864089 Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Tue, 26 Aug 2025 10:08:52 +0530 Subject: [PATCH 0616/2711] vfio/cdx: update driver to build without CONFIG_GENERIC_MSI_IRQ Define dummy MSI related APIs in VFIO CDX driver to build the driver without enabling CONFIG_GENERIC_MSI_IRQ flag. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508070308.opy5dIFX-lkp@intel.com/ Reviewed-by: Nikhil Agarwal Reviewed-by: Alex Williamson Signed-off-by: Nipun Gupta Link: https://lore.kernel.org/r/20250826043852.2206008-2-nipun.gupta@amd.com Signed-off-by: Alex Williamson --- drivers/vfio/cdx/Makefile | 6 +++++- drivers/vfio/cdx/private.h | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/cdx/Makefile b/drivers/vfio/cdx/Makefile index df92b320122a..dadbef2419ea 100644 --- a/drivers/vfio/cdx/Makefile +++ b/drivers/vfio/cdx/Makefile @@ -5,4 +5,8 @@ obj-$(CONFIG_VFIO_CDX) += vfio-cdx.o -vfio-cdx-objs := main.o intr.o +vfio-cdx-objs := main.o + +ifdef CONFIG_GENERIC_MSI_IRQ +vfio-cdx-objs += intr.o +endif diff --git a/drivers/vfio/cdx/private.h b/drivers/vfio/cdx/private.h index dc56729b3114..172e48caa3a0 100644 --- a/drivers/vfio/cdx/private.h +++ b/drivers/vfio/cdx/private.h @@ -38,11 +38,25 @@ struct vfio_cdx_device { u8 config_msi; }; +#ifdef CONFIG_GENERIC_MSI_IRQ int vfio_cdx_set_irqs_ioctl(struct vfio_cdx_device *vdev, u32 flags, unsigned int index, unsigned int start, unsigned int count, void *data); void vfio_cdx_irqs_cleanup(struct vfio_cdx_device *vdev); +#else +static int vfio_cdx_set_irqs_ioctl(struct vfio_cdx_device *vdev, + u32 flags, unsigned int index, + unsigned int start, unsigned int count, + void *data) +{ + return -EINVAL; +} + +static void vfio_cdx_irqs_cleanup(struct vfio_cdx_device *vdev) +{ +} +#endif #endif /* VFIO_CDX_PRIVATE_H */ From 39f9be6aba3ae4d6fdd4b8554f1184d054d7a713 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 21 Jul 2025 17:36:07 +0200 Subject: [PATCH 0617/2711] PCI/pwrctrl: Fix device leak at registration Make sure to drop the reference to the pwrctrl device taken by of_find_device_by_node() when registering a PCI device. Fixes: b458ff7e8176 ("PCI/pwrctl: Ensure that pwrctl drivers are probed before PCI client drivers") Signed-off-by: Johan Hovold Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org # v6.13 Link: https://patch.msgid.link/20250721153609.8611-2-johan+linaro@kernel.org --- drivers/pci/bus.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index b77fd30bbfd9..f401e296d15d 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -361,11 +361,15 @@ void pci_bus_add_device(struct pci_dev *dev) * before PCI client drivers. */ pdev = of_find_device_by_node(dn); - if (pdev && of_pci_supply_present(dn)) { - if (!device_link_add(&dev->dev, &pdev->dev, - DL_FLAG_AUTOREMOVE_CONSUMER)) - pci_err(dev, "failed to add device link to power control device %s\n", - pdev->name); + if (pdev) { + if (of_pci_supply_present(dn)) { + if (!device_link_add(&dev->dev, &pdev->dev, + DL_FLAG_AUTOREMOVE_CONSUMER)) { + pci_err(dev, "failed to add device link to power control device %s\n", + pdev->name); + } + } + put_device(&pdev->dev); } if (!dn || of_device_is_available(dn)) From e24bbbe0780262a21fc8619fe99078a5b8d64b18 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 21 Jul 2025 17:36:08 +0200 Subject: [PATCH 0618/2711] PCI/pwrctrl: Fix device and OF node leak at bus scan Make sure to drop the references to the pwrctrl OF node and device taken by of_pci_find_child_device() and of_find_device_by_node() respectively when scanning the bus. Fixes: 957f40d039a9 ("PCI/pwrctrl: Move creation of pwrctrl devices to pci_scan_device()") Signed-off-by: Johan Hovold Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org # v6.15 Link: https://patch.msgid.link/20250721153609.8611-3-johan+linaro@kernel.org --- drivers/pci/probe.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f41128f91ca7..a56dfa1c9b6f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2516,9 +2516,15 @@ static struct platform_device *pci_pwrctrl_create_device(struct pci_bus *bus, in struct device_node *np; np = of_pci_find_child_device(dev_of_node(&bus->dev), devfn); - if (!np || of_find_device_by_node(np)) + if (!np) return NULL; + pdev = of_find_device_by_node(np); + if (pdev) { + put_device(&pdev->dev); + goto err_put_of_node; + } + /* * First check whether the pwrctrl device really needs to be created or * not. This is decided based on at least one of the power supplies @@ -2526,17 +2532,24 @@ static struct platform_device *pci_pwrctrl_create_device(struct pci_bus *bus, in */ if (!of_pci_supply_present(np)) { pr_debug("PCI/pwrctrl: Skipping OF node: %s\n", np->name); - return NULL; + goto err_put_of_node; } /* Now create the pwrctrl device */ pdev = of_platform_device_create(np, NULL, &host->dev); if (!pdev) { pr_err("PCI/pwrctrl: Failed to create pwrctrl device for node: %s\n", np->name); - return NULL; + goto err_put_of_node; } + of_node_put(np); + return pdev; + +err_put_of_node: + of_node_put(np); + + return NULL; } #else static struct platform_device *pci_pwrctrl_create_device(struct pci_bus *bus, int devfn) From dc32e9346b26ba33e84ec3034a1e53a9733700f9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 21 Jul 2025 17:36:09 +0200 Subject: [PATCH 0619/2711] PCI/pwrctrl: Fix device leak at device stop Make sure to drop the reference to the pwrctrl device taken by of_find_device_by_node() when stopping a PCI device. Fixes: 681725afb6b9 ("PCI/pwrctl: Remove pwrctl device without iterating over all children of pwrctl parent") Signed-off-by: Johan Hovold Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org # v6.13 Link: https://patch.msgid.link/20250721153609.8611-4-johan+linaro@kernel.org --- drivers/pci/remove.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 445afdfa6498..16f21edbc29d 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -31,6 +31,8 @@ static void pci_pwrctrl_unregister(struct device *dev) return; of_device_unregister(pdev); + put_device(&pdev->dev); + of_node_clear_flag(np, OF_POPULATED); } From 6633875250b38b18b8638cf01e695de031c71f02 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 27 Aug 2025 15:41:09 +0200 Subject: [PATCH 0620/2711] PCI/AER: Support errors introduced by PCIe r6.0 PCIe r6.0 defined five additional errors in the Uncorrectable Error Status, Mask and Severity Registers (PCIe r7.0 sec 7.8.4.2ff). lspci has been supporting them since commit 144b0911cc0b ("ls-ecaps: extend decode support for more fields for AER CE and UE status"): https://git.kernel.org/pub/scm/utils/pciutils/pciutils.git/commit/?id=144b0911cc0b Amend the AER driver to recognize them as well, instead of logging them as "Unknown Error Bit". Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Kuppuswamy Sathyanarayanan Cc: stable@vger.kernel.org Link: https://patch.msgid.link/21f1875b18d4078c99353378f37dcd6b994f6d4e.1756301211.git.lukas@wunner.de --- drivers/pci/pcie/aer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index e286c197d716..15ed541d2fbe 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -43,7 +43,7 @@ #define AER_ERROR_SOURCES_MAX 128 #define AER_MAX_TYPEOF_COR_ERRS 16 /* as per PCI_ERR_COR_STATUS */ -#define AER_MAX_TYPEOF_UNCOR_ERRS 27 /* as per PCI_ERR_UNCOR_STATUS*/ +#define AER_MAX_TYPEOF_UNCOR_ERRS 32 /* as per PCI_ERR_UNCOR_STATUS*/ struct aer_err_source { u32 status; /* PCI_ERR_ROOT_STATUS */ @@ -525,11 +525,11 @@ static const char *aer_uncorrectable_error_string[] = { "AtomicOpBlocked", /* Bit Position 24 */ "TLPBlockedErr", /* Bit Position 25 */ "PoisonTLPBlocked", /* Bit Position 26 */ - NULL, /* Bit Position 27 */ - NULL, /* Bit Position 28 */ - NULL, /* Bit Position 29 */ - NULL, /* Bit Position 30 */ - NULL, /* Bit Position 31 */ + "DMWrReqBlocked", /* Bit Position 27 */ + "IDECheck", /* Bit Position 28 */ + "MisIDETLP", /* Bit Position 29 */ + "PCRC_CHECK", /* Bit Position 30 */ + "TLPXlatBlocked", /* Bit Position 31 */ }; static const char *aer_agent_string[] = { From fac679df7580979174c90303f004b09cdc6f086f Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Mon, 25 Aug 2025 14:46:42 -0700 Subject: [PATCH 0621/2711] PCI/ACPI: Fix pci_acpi_preserve_config() memory leak pci_acpi_preserve_config() leaks memory by returning early without freeing the ACPI object on success. Fix that by always freeing the obj, which is not needed by the caller. Fixes: 9d7d5db8e78e ("PCI: Move PRESERVE_BOOT_CONFIG _DSM evaluation to pci_register_host_bridge()") Signed-off-by: Nirmoy Das Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250825214642.142135-1-nirmoyd@nvidia.com --- drivers/pci/pci-acpi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index ddb25960ea47..9369377725fa 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -122,6 +122,8 @@ phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) bool pci_acpi_preserve_config(struct pci_host_bridge *host_bridge) { + bool ret = false; + if (ACPI_HANDLE(&host_bridge->dev)) { union acpi_object *obj; @@ -135,11 +137,11 @@ bool pci_acpi_preserve_config(struct pci_host_bridge *host_bridge) 1, DSM_PCI_PRESERVE_BOOT_CONFIG, NULL, ACPI_TYPE_INTEGER); if (obj && obj->integer.value == 0) - return true; + ret = true; ACPI_FREE(obj); } - return false; + return ret; } /* _HPX PCI Setting Record (Type 0); same as _HPP */ From 1e50201d3911507744adf5dafd6e25dbffee3692 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 21 Aug 2025 10:32:40 +0200 Subject: [PATCH 0622/2711] dt-bindings: ata: highbank: Minor whitespace cleanup in example The DTS code coding style expects exactly one space around '=' character. Signed-off-by: Krzysztof Kozlowski Acked-by: Andre Przywara Signed-off-by: Damien Le Moal --- Documentation/devicetree/bindings/ata/sata_highbank.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/ata/sata_highbank.yaml b/Documentation/devicetree/bindings/ata/sata_highbank.yaml index f23f26a8f21c..48bdca0f5577 100644 --- a/Documentation/devicetree/bindings/ata/sata_highbank.yaml +++ b/Documentation/devicetree/bindings/ata/sata_highbank.yaml @@ -85,7 +85,7 @@ examples: dma-coherent; calxeda,port-phys = <&combophy5 0>, <&combophy0 0>, <&combophy0 1>, <&combophy0 2>, <&combophy0 3>; - calxeda,sgpio-gpio =<&gpioh 5 1>, <&gpioh 6 1>, <&gpioh 7 1>; + calxeda,sgpio-gpio = <&gpioh 5 1>, <&gpioh 6 1>, <&gpioh 7 1>; calxeda,led-order = <4 0 1 2 3>; calxeda,tx-atten = <0xff 22 0xff 0xff 23>; calxeda,pre-clocks = <10>; From 692173de3032b22792d21070238a986163fc29ec Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 23 Aug 2025 16:50:21 -0300 Subject: [PATCH 0623/2711] dt-bindings: ata: imx: Document 'target-supply' The 'target-supply' property is used by some i.MX devicetree files. Document it to fix the following dt-schema warning: 'target-supply' does not match any of the regexes: '^pinctrl-[0-9]+$' Signed-off-by: Fabio Estevam Acked-by: Conor Dooley Signed-off-by: Damien Le Moal --- Documentation/devicetree/bindings/ata/imx-sata.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/ata/imx-sata.yaml b/Documentation/devicetree/bindings/ata/imx-sata.yaml index f4eb3550a096..31c43374763a 100644 --- a/Documentation/devicetree/bindings/ata/imx-sata.yaml +++ b/Documentation/devicetree/bindings/ata/imx-sata.yaml @@ -80,6 +80,9 @@ properties: power-domains: maxItems: 1 + target-supply: + description: Power regulator for the SATA target device. + required: - compatible - reg From 54cf44517550d53960d2fc5f85cf55d668c8889d Mon Sep 17 00:00:00 2001 From: Yen-Chi Huang Date: Thu, 28 Aug 2025 13:31:17 +0800 Subject: [PATCH 0624/2711] platform/x86: portwell-ec: Add suspend/resume support for watchdog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Portwell EC does not disable the watchdog during suspend. To avoid unwanted resets, this patch adds suspend and resume callbacks (pwec_suspend() and pwec_resume()) to the driver. The watchdog is stopped in pwec_suspend() and restarted in pwec_resume() if it was active before suspend. Signed-off-by: Yen-Chi Huang Link: https://lore.kernel.org/r/c9cfe602-c279-4aa4-9932-76f47f26556c@portwell.com.tw [ij: removed extra "3"] Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/portwell-ec.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/platform/x86/portwell-ec.c b/drivers/platform/x86/portwell-ec.c index 322f296e9315..d2e91d5c3b3a 100644 --- a/drivers/platform/x86/portwell-ec.c +++ b/drivers/platform/x86/portwell-ec.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -246,9 +247,28 @@ static int pwec_probe(struct platform_device *pdev) return 0; } +static int pwec_suspend(struct device *dev) +{ + if (watchdog_active(&ec_wdt_dev)) + return pwec_wdt_stop(&ec_wdt_dev); + + return 0; +} + +static int pwec_resume(struct device *dev) +{ + if (watchdog_active(&ec_wdt_dev)) + return pwec_wdt_start(&ec_wdt_dev); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(pwec_dev_pm_ops, pwec_suspend, pwec_resume); + static struct platform_driver pwec_driver = { .driver = { .name = "portwell-ec", + .pm = pm_sleep_ptr(&pwec_dev_pm_ops), }, .probe = pwec_probe, }; From c138158e87aaca6da345603a03e5d9e8d90fdd36 Mon Sep 17 00:00:00 2001 From: Xi Pardee Date: Tue, 26 Aug 2025 11:39:42 -0700 Subject: [PATCH 0625/2711] platform/x86/intel/pmc: Add Wildcat Lake support to Intel PMC SSRAM Telemetry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Wildcat Lake support to Intel PMC SSRAM Telemetry driver. Signed-off-by: Xi Pardee Link: https://lore.kernel.org/r/20250826183946.802684-1-xi.pardee@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/pmc/core.h | 3 +++ drivers/platform/x86/intel/pmc/ssram_telemetry.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h index 4a94a4ee031e..160b175ce706 100644 --- a/drivers/platform/x86/intel/pmc/core.h +++ b/drivers/platform/x86/intel/pmc/core.h @@ -306,6 +306,9 @@ enum ppfear_regs { #define PMC_DEVID_PTL_PCDH 0xe37f #define PMC_DEVID_PTL_PCDP 0xe47f +/* WCL */ +#define PMC_DEVID_WCL_PCDN 0x4d7f + /* ARL */ #define PMC_DEVID_ARL_SOCM 0x777f #define PMC_DEVID_ARL_SOCS 0xae7f diff --git a/drivers/platform/x86/intel/pmc/ssram_telemetry.c b/drivers/platform/x86/intel/pmc/ssram_telemetry.c index 93579152188e..03fad9331fc0 100644 --- a/drivers/platform/x86/intel/pmc/ssram_telemetry.c +++ b/drivers/platform/x86/intel/pmc/ssram_telemetry.c @@ -190,6 +190,7 @@ static const struct pci_device_id intel_pmc_ssram_telemetry_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_LNL_SOCM) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_PTL_PCDH) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_PTL_PCDP) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_WCL_PCDN) }, { } }; MODULE_DEVICE_TABLE(pci, intel_pmc_ssram_telemetry_pci_ids); From 1866c3b93989081770e0a59c671a483eb72ea85b Mon Sep 17 00:00:00 2001 From: Xi Pardee Date: Tue, 26 Aug 2025 11:39:43 -0700 Subject: [PATCH 0626/2711] platform/x86/intel/pmc: Add Wildcat Lake support to intel_pmc_core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Wildcat Lake support to intel_pmc_core driver. Signed-off-by: Xi Pardee Link: https://lore.kernel.org/r/20250826183946.802684-2-xi.pardee@linux.intel.com [ij: added #include for BIT()] Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/pmc/Makefile | 2 +- drivers/platform/x86/intel/pmc/core.c | 1 + drivers/platform/x86/intel/pmc/core.h | 8 + drivers/platform/x86/intel/pmc/ptl.c | 6 +- drivers/platform/x86/intel/pmc/wcl.c | 486 ++++++++++++++++++++++++ 5 files changed, 499 insertions(+), 4 deletions(-) create mode 100644 drivers/platform/x86/intel/pmc/wcl.c diff --git a/drivers/platform/x86/intel/pmc/Makefile b/drivers/platform/x86/intel/pmc/Makefile index 5f68c8503a56..bb960c8721d7 100644 --- a/drivers/platform/x86/intel/pmc/Makefile +++ b/drivers/platform/x86/intel/pmc/Makefile @@ -4,7 +4,7 @@ # intel_pmc_core-y := core.o spt.o cnp.o icl.o \ - tgl.o adl.o mtl.o arl.o lnl.o ptl.o + tgl.o adl.o mtl.o arl.o lnl.o ptl.o wcl.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv-y := pltdrv.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core_pltdrv.o diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index 540cd2fb0673..7d55af8e303c 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -1631,6 +1631,7 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = { X86_MATCH_VFM(INTEL_ARROWLAKE_U, &arl_h_pmc_dev), X86_MATCH_VFM(INTEL_LUNARLAKE_M, &lnl_pmc_dev), X86_MATCH_VFM(INTEL_PANTHERLAKE_L, &ptl_pmc_dev), + X86_MATCH_VFM(INTEL_WILDCATLAKE_L, &wcl_pmc_dev), {} }; diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h index 160b175ce706..47101f0dd09c 100644 --- a/drivers/platform/x86/intel/pmc/core.h +++ b/drivers/platform/x86/intel/pmc/core.h @@ -298,6 +298,10 @@ enum ppfear_regs { #define PTL_PMC_LTR_CUR_PLT 0x1C2C #define PTL_PCD_PMC_MMIO_REG_LEN 0x31A8 +/* Wildcat Lake */ +#define WCL_PMC_LTR_RESERVED 0x1B64 +#define WCL_PCD_PMC_MMIO_REG_LEN 0x3178 + /* SSRAM PMC Device ID */ /* LNL */ #define PMC_DEVID_LNL_SOCM 0xa87f @@ -508,6 +512,9 @@ extern const struct pmc_bit_map mtl_socm_vnn_misc_status_map[]; extern const struct pmc_bit_map mtl_socm_signal_status_map[]; extern const struct pmc_reg_map mtl_socm_reg_map; extern const struct pmc_reg_map mtl_ioep_reg_map; +extern const struct pmc_bit_map ptl_pcdp_clocksource_status_map[]; +extern const struct pmc_bit_map ptl_pcdp_vnn_req_status_3_map[]; +extern const struct pmc_bit_map ptl_pcdp_signal_status_map[]; void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev); int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore); @@ -531,6 +538,7 @@ extern struct pmc_dev_info arl_pmc_dev; extern struct pmc_dev_info arl_h_pmc_dev; extern struct pmc_dev_info lnl_pmc_dev; extern struct pmc_dev_info ptl_pmc_dev; +extern struct pmc_dev_info wcl_pmc_dev; void cnl_suspend(struct pmc_dev *pmcdev); int cnl_resume(struct pmc_dev *pmcdev); diff --git a/drivers/platform/x86/intel/pmc/ptl.c b/drivers/platform/x86/intel/pmc/ptl.c index 394515af60d6..1bbec9856867 100644 --- a/drivers/platform/x86/intel/pmc/ptl.c +++ b/drivers/platform/x86/intel/pmc/ptl.c @@ -162,7 +162,7 @@ static const struct pmc_bit_map ptl_pcdp_ltr_show_map[] = { {} }; -static const struct pmc_bit_map ptl_pcdp_clocksource_status_map[] = { +const struct pmc_bit_map ptl_pcdp_clocksource_status_map[] = { {"AON2_OFF_STS", BIT(0), 1}, {"AON3_OFF_STS", BIT(1), 0}, {"AON4_OFF_STS", BIT(2), 1}, @@ -382,7 +382,7 @@ static const struct pmc_bit_map ptl_pcdp_vnn_req_status_2_map[] = { {} }; -static const struct pmc_bit_map ptl_pcdp_vnn_req_status_3_map[] = { +const struct pmc_bit_map ptl_pcdp_vnn_req_status_3_map[] = { {"DTS0_VNN_REQ_STS", BIT(7), 0}, {"GPIOCOM5_VNN_REQ_STS", BIT(11), 1}, {} @@ -421,7 +421,7 @@ static const struct pmc_bit_map ptl_pcdp_vnn_misc_status_map[] = { {} }; -static const struct pmc_bit_map ptl_pcdp_signal_status_map[] = { +const struct pmc_bit_map ptl_pcdp_signal_status_map[] = { {"LSX_Wake0_STS", BIT(0), 0}, {"LSX_Wake1_STS", BIT(1), 0}, {"LSX_Wake2_STS", BIT(2), 0}, diff --git a/drivers/platform/x86/intel/pmc/wcl.c b/drivers/platform/x86/intel/pmc/wcl.c new file mode 100644 index 000000000000..85e90a639e65 --- /dev/null +++ b/drivers/platform/x86/intel/pmc/wcl.c @@ -0,0 +1,486 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This file contains platform specific structure definitions + * and init function used by Wildcat Lake PCH. + * + * Copyright (c) 2025, Intel Corporation. + */ + +#include +#include + +#include "core.h" + +static const struct pmc_bit_map wcl_pcdn_pfear_map[] = { + {"PMC_0", BIT(0)}, + {"FUSE_OSSE", BIT(1)}, + {"ESPISPI", BIT(2)}, + {"XHCI", BIT(3)}, + {"SPA", BIT(4)}, + {"RSVD", BIT(5)}, + {"MPFPW2", BIT(6)}, + {"GBE", BIT(7)}, + + {"SBR16B21", BIT(0)}, + {"SBR16B5", BIT(1)}, + {"SBR8B1", BIT(2)}, + {"SBR8B0", BIT(3)}, + {"P2SB0", BIT(4)}, + {"D2D_DISP_1", BIT(5)}, + {"LPSS", BIT(6)}, + {"LPC", BIT(7)}, + + {"SMB", BIT(0)}, + {"ISH", BIT(1)}, + {"DBG_SBR16B", BIT(2)}, + {"NPK_0", BIT(3)}, + {"D2D_NOC_1", BIT(4)}, + {"FIA_P", BIT(5)}, + {"FUSE", BIT(6)}, + {"DBG_PSF", BIT(7)}, + + {"DISP_PGA1", BIT(0)}, + {"XDCI", BIT(1)}, + {"EXI", BIT(2)}, + {"CSE", BIT(3)}, + {"KVMCC", BIT(4)}, + {"PMT", BIT(5)}, + {"CLINK", BIT(6)}, + {"PTIO", BIT(7)}, + + {"USBR0", BIT(0)}, + {"SBR16B22", BIT(1)}, + {"SMT1", BIT(2)}, + {"MPFPW1", BIT(3)}, + {"SMS2", BIT(4)}, + {"SMS1", BIT(5)}, + {"CSMERTC", BIT(6)}, + {"CSMEPSF", BIT(7)}, + + {"D2D_NOC_0", BIT(0)}, + {"ESE", BIT(1)}, + {"FIACPCB_P", BIT(2)}, + {"RSVD", BIT(3)}, + {"SBR8B2", BIT(4)}, + {"OSSE_SMT1", BIT(5)}, + {"D2D_DISP", BIT(6)}, + {"P2SB1", BIT(7)}, + + {"U3FPW1", BIT(0)}, + {"SBR16B3", BIT(1)}, + {"PSF4", BIT(2)}, + {"CNVI", BIT(3)}, + {"UFSX2", BIT(4)}, + {"ENDBG", BIT(5)}, + {"DBC", BIT(6)}, + {"SBRG", BIT(7)}, + + {"RSVD", BIT(0)}, + {"NPK1", BIT(1)}, + {"SBR16B7", BIT(2)}, + {"SBR16B4", BIT(3)}, + {"FIA_XG", BIT(4)}, + {"PSF6", BIT(5)}, + {"UFSPW1", BIT(6)}, + {"FIA_U", BIT(7)}, + + {"PSF8", BIT(0)}, + {"PSF0", BIT(1)}, + {"RSVD", BIT(2)}, + {"FIACPCB_U", BIT(3)}, + {"TAM", BIT(4)}, + {"SBR16B0", BIT(5)}, + {"TBTLSX", BIT(6)}, + {"THC0", BIT(7)}, + + {"THC1", BIT(0)}, + {"PMC_1", BIT(1)}, + {"FIACPCB_XG", BIT(2)}, + {"TCSS", BIT(3)}, + {"DISP_PGA", BIT(4)}, + {"SBR16B20", BIT(5)}, + {"SBR8B20", BIT(6)}, + {"DBG_SBR", BIT(7)}, + + {"SPC", BIT(0)}, + {"ACE_0", BIT(1)}, + {"ACE_1", BIT(2)}, + {"ACE_2", BIT(3)}, + {"ACE_3", BIT(4)}, + {"ACE_4", BIT(5)}, + {"ACE_5", BIT(6)}, + {"ACE_6", BIT(7)}, + + {"ACE_7", BIT(0)}, + {"ACE_8", BIT(1)}, + {"ACE_9", BIT(2)}, + {"ACE_10", BIT(3)}, + {"SBR16B2", BIT(4)}, + {"SBR8B4", BIT(5)}, + {"OSSE", BIT(6)}, + {"SBR16B1", BIT(7)}, + {} +}; + +static const struct pmc_bit_map *ext_wcl_pcdn_pfear_map[] = { + wcl_pcdn_pfear_map, + NULL +}; + +static const struct pmc_bit_map wcl_pcdn_ltr_show_map[] = { + {"SOUTHPORT_A", CNP_PMC_LTR_SPA}, + {"RSVD", WCL_PMC_LTR_RESERVED}, + {"SATA", CNP_PMC_LTR_SATA}, + {"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE}, + {"XHCI", CNP_PMC_LTR_XHCI}, + {"SOUTHPORT_F", ADL_PMC_LTR_SPF}, + {"ME", CNP_PMC_LTR_ME}, + {"SATA1", CNP_PMC_LTR_EVA}, + {"SOUTHPORT_C", CNP_PMC_LTR_SPC}, + {"HD_AUDIO", CNP_PMC_LTR_AZ}, + {"CNV", CNP_PMC_LTR_CNV}, + {"LPSS", CNP_PMC_LTR_LPSS}, + {"SOUTHPORT_D", CNP_PMC_LTR_SPD}, + {"SOUTHPORT_E", CNP_PMC_LTR_SPE}, + {"SATA2", PTL_PMC_LTR_SATA2}, + {"ESPI", CNP_PMC_LTR_ESPI}, + {"SCC", CNP_PMC_LTR_SCC}, + {"ISH", CNP_PMC_LTR_ISH}, + {"UFSX2", CNP_PMC_LTR_UFSX2}, + {"EMMC", CNP_PMC_LTR_EMMC}, + {"WIGIG", ICL_PMC_LTR_WIGIG}, + {"THC0", TGL_PMC_LTR_THC0}, + {"THC1", TGL_PMC_LTR_THC1}, + {"SOUTHPORT_G", MTL_PMC_LTR_SPG}, + {"ESE", MTL_PMC_LTR_ESE}, + {"IOE_PMC", MTL_PMC_LTR_IOE_PMC}, + {"DMI3", ARL_PMC_LTR_DMI3}, + {"OSSE", LNL_PMC_LTR_OSSE}, + + /* Below two cannot be used for LTR_IGNORE */ + {"CURRENT_PLATFORM", PTL_PMC_LTR_CUR_PLT}, + {"AGGREGATED_SYSTEM", PTL_PMC_LTR_CUR_ASLT}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_power_gating_status_0_map[] = { + {"PMC_PGD0_PG_STS", BIT(0), 0}, + {"FUSE_OSSE_PGD0_PG_STS", BIT(1), 0}, + {"ESPISPI_PGD0_PG_STS", BIT(2), 0}, + {"XHCI_PGD0_PG_STS", BIT(3), 1}, + {"SPA_PGD0_PG_STS", BIT(4), 1}, + {"RSVD_5", BIT(5), 0}, + {"MPFPW2_PGD0_PG_STS", BIT(6), 0}, + {"GBE_PGD0_PG_STS", BIT(7), 1}, + {"SBR16B21_PGD0_PG_STS", BIT(8), 0}, + {"SBR16B5_PGD0_PG_STS", BIT(9), 0}, + {"SBR8B1_PGD0_PG_STS", BIT(10), 0}, + {"SBR8B0_PGD0_PG_STS", BIT(11), 0}, + {"P2SB0_PG_STS", BIT(12), 1}, + {"D2D_DISP_PGD1_PG_STS", BIT(13), 0}, + {"LPSS_PGD0_PG_STS", BIT(14), 1}, + {"LPC_PGD0_PG_STS", BIT(15), 0}, + {"SMB_PGD0_PG_STS", BIT(16), 0}, + {"ISH_PGD0_PG_STS", BIT(17), 0}, + {"DBG_SBR16B_PGD0_PG_STS", BIT(18), 0}, + {"NPK_PGD0_PG_STS", BIT(19), 0}, + {"D2D_NOC_PGD1_PG_STS", BIT(20), 0}, + {"FIA_P_PGD0_PG_STS", BIT(21), 0}, + {"FUSE_PGD0_PG_STS", BIT(22), 0}, + {"DBG_PSF_PGD0_PG_STS", BIT(23), 0}, + {"DISP_PGA1_PGD0_PG_STS", BIT(24), 0}, + {"XDCI_PGD0_PG_STS", BIT(25), 1}, + {"EXI_PGD0_PG_STS", BIT(26), 0}, + {"CSE_PGD0_PG_STS", BIT(27), 1}, + {"KVMCC_PGD0_PG_STS", BIT(28), 1}, + {"PMT_PGD0_PG_STS", BIT(29), 1}, + {"CLINK_PGD0_PG_STS", BIT(30), 1}, + {"PTIO_PGD0_PG_STS", BIT(31), 1}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_power_gating_status_1_map[] = { + {"USBR0_PGD0_PG_STS", BIT(0), 1}, + {"SBR16B22_PGD0_PG_STS", BIT(1), 0}, + {"SMT1_PGD0_PG_STS", BIT(2), 1}, + {"MPFPW1_PGD0_PG_STS", BIT(3), 0}, + {"SMS2_PGD0_PG_STS", BIT(4), 1}, + {"SMS1_PGD0_PG_STS", BIT(5), 1}, + {"CSMERTC_PGD0_PG_STS", BIT(6), 0}, + {"CSMEPSF_PGD0_PG_STS", BIT(7), 0}, + {"D2D_NOC_PGD0_PG_STS", BIT(8), 0}, + {"ESE_PGD0_PG_STS", BIT(9), 1}, + {"FIACPCB_P_PGD0_PG_STS", BIT(10), 0}, + {"SBR8B2_PGD0_PG_STS", BIT(12), 0}, + {"OSSE_SMT1_PGD0_PG_STS", BIT(13), 1}, + {"D2D_DISP_PGD0_PG_STS", BIT(14), 0}, + {"P2SB1_PGD0_PG_STS", BIT(15), 1}, + {"U3FPW1_PGD0_PG_STS", BIT(16), 0}, + {"SBR16B3_PGD0_PG_STS", BIT(17), 0}, + {"PSF4_PGD0_PG_STS", BIT(18), 0}, + {"CNVI_PGD0_PG_STS", BIT(19), 0}, + {"UFSX2_PGD0_PG_STS", BIT(20), 1}, + {"ENDBG_PGD0_PG_STS", BIT(21), 0}, + {"DBC_PGD0_PG_STS", BIT(22), 0}, + {"SBRG_PGD0_PG_STS", BIT(23), 0}, + {"NPK_PGD1_PG_STS", BIT(25), 0}, + {"SBR16B7_PGD0_PG_STS", BIT(26), 0}, + {"SBR16B4_PGD0_PG_STS", BIT(27), 0}, + {"FIA_XG_PSF_PGD0_PG_STS", BIT(28), 0}, + {"PSF6_PGD0_PG_STS", BIT(29), 0}, + {"UFSPW1_PGD0_PG_STS", BIT(30), 0}, + {"FIA_U_PGD0_PG_STS", BIT(31), 0}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_power_gating_status_2_map[] = { + {"PSF8_PGD0_PG_STS", BIT(0), 0}, + {"PSF0_PGD0_PG_STS", BIT(1), 0}, + {"FIACPCB_U_PGD0_PG_STS", BIT(3), 0}, + {"TAM_PGD0_PG_STS", BIT(4), 1}, + {"SBR16B0_PGD0_PG_STS", BIT(5), 0}, + {"TBTLSX_PGD0_PG_STS", BIT(6), 1}, + {"THC0_PGD0_PG_STS", BIT(7), 1}, + {"THC1_PGD0_PG_STS", BIT(8), 1}, + {"PMC_PGD1_PG_STS", BIT(9), 0}, + {"FIACPCB_XG_PGD0_PG_STS", BIT(10), 0}, + {"TCSS_PGD0_PG_STS", BIT(11), 0}, + {"DISP_PGA_PGD0_PG_STS", BIT(12), 0}, + {"SBR8B4_PGD0_PG_STS", BIT(13), 0}, + {"SBR8B20_PGD0_PG_STS", BIT(14), 0}, + {"DBG_PGD0_PG_STS", BIT(15), 0}, + {"SPC_PGD0_PG_STS", BIT(16), 1}, + {"ACE_PGD0_PG_STS", BIT(17), 0}, + {"ACE_PGD1_PG_STS", BIT(18), 0}, + {"ACE_PGD2_PG_STS", BIT(19), 0}, + {"ACE_PGD3_PG_STS", BIT(20), 0}, + {"ACE_PGD4_PG_STS", BIT(21), 0}, + {"ACE_PGD5_PG_STS", BIT(22), 0}, + {"ACE_PGD6_PG_STS", BIT(23), 0}, + {"ACE_PGD7_PG_STS", BIT(24), 0}, + {"ACE_PGD8_PG_STS", BIT(25), 0}, + {"ACE_PGD9_PG_STS", BIT(26), 0}, + {"ACE_PGD10_PG_STS", BIT(27), 0}, + {"SBR16B2_PG_PGD0_PG_STS", BIT(28), 0}, + {"SBR16B20_PGD0_PG_STS", BIT(29), 0}, + {"OSSE_PGD0_PG_STS", BIT(30), 1}, + {"SBR16B1_PGD0_PG_STS", BIT(31), 0}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_d3_status_0_map[] = { + {"LPSS_D3_STS", BIT(3), 1}, + {"XDCI_D3_STS", BIT(4), 1}, + {"XHCI_D3_STS", BIT(5), 1}, + {"SPA_D3_STS", BIT(12), 0}, + {"SPC_D3_STS", BIT(14), 0}, + {"OSSE_D3_STS", BIT(15), 0}, + {"ESPISPI_D3_STS", BIT(18), 0}, + {"PSTH_D3_STS", BIT(21), 0}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_d3_status_1_map[] = { + {"OSSE_SMT1_D3_STS", BIT(16), 0}, + {"GBE_D3_STS", BIT(19), 0}, + {"ITSS_D3_STS", BIT(23), 0}, + {"CNVI_D3_STS", BIT(27), 0}, + {"UFSX2_D3_STS", BIT(28), 0}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_d3_status_2_map[] = { + {"CSMERTC_D3_STS", BIT(1), 0}, + {"ESE_D3_STS", BIT(2), 0}, + {"CSE_D3_STS", BIT(4), 0}, + {"KVMCC_D3_STS", BIT(5), 0}, + {"USBR0_D3_STS", BIT(6), 0}, + {"ISH_D3_STS", BIT(7), 0}, + {"SMT1_D3_STS", BIT(8), 0}, + {"SMT2_D3_STS", BIT(9), 0}, + {"SMT3_D3_STS", BIT(10), 0}, + {"CLINK_D3_STS", BIT(14), 0}, + {"PTIO_D3_STS", BIT(16), 0}, + {"PMT_D3_STS", BIT(17), 0}, + {"SMS1_D3_STS", BIT(18), 0}, + {"SMS2_D3_STS", BIT(19), 0}, + {"OSSE_SMT2_D3_STS", BIT(22), 0}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_d3_status_3_map[] = { + {"THC0_D3_STS", BIT(14), 1}, + {"THC1_D3_STS", BIT(15), 1}, + {"OSSE_SMT3_D3_STS", BIT(16), 0}, + {"ACE_D3_STS", BIT(23), 0}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_vnn_req_status_0_map[] = { + {"LPSS_VNN_REQ_STS", BIT(3), 1}, + {"OSSE_VNN_REQ_STS", BIT(15), 1}, + {"ESPISPI_VNN_REQ_STS", BIT(18), 1}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_vnn_req_status_1_map[] = { + {"NPK_VNN_REQ_STS", BIT(4), 1}, + {"DFXAGG_VNN_REQ_STS", BIT(8), 0}, + {"EXI_VNN_REQ_STS", BIT(9), 1}, + {"OSSE_SMT1_VNN_REQ_STS", BIT(16), 1}, + {"P2D_VNN_REQ_STS", BIT(18), 1}, + {"GBE_VNN_REQ_STS", BIT(19), 1}, + {"SMB_VNN_REQ_STS", BIT(25), 1}, + {"LPC_VNN_REQ_STS", BIT(26), 0}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_vnn_req_status_2_map[] = { + {"CSMERTC_VNN_REQ_STS", BIT(1), 1}, + {"ESE_VNN_REQ_STS", BIT(2), 1}, + {"CSE_VNN_REQ_STS", BIT(4), 1}, + {"ISH_VNN_REQ_STS", BIT(7), 1}, + {"SMT1_VNN_REQ_STS", BIT(8), 1}, + {"CLINK_VNN_REQ_STS", BIT(14), 1}, + {"SMS1_VNN_REQ_STS", BIT(18), 1}, + {"SMS2_VNN_REQ_STS", BIT(19), 1}, + {"GPIOCOM4_VNN_REQ_STS", BIT(20), 1}, + {"GPIOCOM3_VNN_REQ_STS", BIT(21), 1}, + {"GPIOCOM1_VNN_REQ_STS", BIT(23), 1}, + {"GPIOCOM0_VNN_REQ_STS", BIT(24), 1}, + {"DISP_SHIM_VNN_REQ_STS", BIT(31), 1}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_vnn_misc_status_map[] = { + {"CPU_C10_REQ_STS", BIT(0), 0}, + {"TS_OFF_REQ_STS", BIT(1), 0}, + {"PNDE_MET_REQ_STS", BIT(2), 1}, + {"FW_THROTTLE_ALLOWED_REQ_STS", BIT(4), 0}, + {"VNN_SOC_REQ_STS", BIT(6), 1}, + {"ISH_VNNAON_REQ_STS", BIT(7), 0}, + {"D2D_NOC_CFI_QACTIVE_REQ_STS", BIT(8), 1}, + {"D2D_NOC_GPSB_QACTIVE_REQ_STS", BIT(9), 1}, + {"PLT_GREATER_REQ_STS", BIT(11), 1}, + {"ALL_SBR_IDLE_REQ_STS", BIT(12), 0}, + {"PMC_IDLE_FB_OCP_REQ_STS", BIT(13), 0}, + {"PM_SYNC_STATES_REQ_STS", BIT(14), 0}, + {"EA_REQ_STS", BIT(15), 0}, + {"MPHY_CORE_OFF_REQ_STS", BIT(16), 0}, + {"BRK_EV_EN_REQ_STS", BIT(17), 0}, + {"AUTO_DEMO_EN_REQ_STS", BIT(18), 0}, + {"ITSS_CLK_SRC_REQ_STS", BIT(19), 1}, + {"ARC_IDLE_REQ_STS", BIT(21), 0}, + {"FIA_DEEP_PM_REQ_STS", BIT(23), 0}, + {"XDCI_ATTACHED_REQ_STS", BIT(24), 1}, + {"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25), 0}, + {"D2D_DISP_DDI_QACTIVE_REQ_STS", BIT(26), 1}, + {"PRE_WAKE0_REQ_STS", BIT(27), 1}, + {"PRE_WAKE1_REQ_STS", BIT(28), 1}, + {"PRE_WAKE2_REQ_STS", BIT(29), 1}, + {} +}; + +static const struct pmc_bit_map wcl_pcdn_rsc_status_map[] = { + {"Memory", 0, 1}, + {"PSF0", 0, 1}, + {"PSF6", 0, 1}, + {"PSF8", 0, 1}, + {"SAF_CFI_LINK", 0, 1}, + {"SB", 0, 1}, + {} +}; + +static const struct pmc_bit_map *wcl_pcdn_lpm_maps[] = { + ptl_pcdp_clocksource_status_map, + wcl_pcdn_power_gating_status_0_map, + wcl_pcdn_power_gating_status_1_map, + wcl_pcdn_power_gating_status_2_map, + wcl_pcdn_d3_status_0_map, + wcl_pcdn_d3_status_1_map, + wcl_pcdn_d3_status_2_map, + wcl_pcdn_d3_status_3_map, + wcl_pcdn_vnn_req_status_0_map, + wcl_pcdn_vnn_req_status_1_map, + wcl_pcdn_vnn_req_status_2_map, + ptl_pcdp_vnn_req_status_3_map, + wcl_pcdn_vnn_misc_status_map, + ptl_pcdp_signal_status_map, + NULL +}; + +static const struct pmc_bit_map *wcl_pcdn_blk_maps[] = { + wcl_pcdn_power_gating_status_0_map, + wcl_pcdn_power_gating_status_1_map, + wcl_pcdn_power_gating_status_2_map, + wcl_pcdn_rsc_status_map, + wcl_pcdn_vnn_req_status_0_map, + wcl_pcdn_vnn_req_status_1_map, + wcl_pcdn_vnn_req_status_2_map, + ptl_pcdp_vnn_req_status_3_map, + wcl_pcdn_d3_status_0_map, + wcl_pcdn_d3_status_1_map, + wcl_pcdn_d3_status_2_map, + wcl_pcdn_d3_status_3_map, + ptl_pcdp_clocksource_status_map, + wcl_pcdn_vnn_misc_status_map, + ptl_pcdp_signal_status_map, + NULL +}; + +static const struct pmc_reg_map wcl_pcdn_reg_map = { + .pfear_sts = ext_wcl_pcdn_pfear_map, + .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, + .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP, + .ltr_show_sts = wcl_pcdn_ltr_show_map, + .msr_sts = msr_map, + .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET, + .regmap_length = WCL_PCD_PMC_MMIO_REG_LEN, + .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A, + .ppfear_buckets = LNL_PPFEAR_NUM_ENTRIES, + .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET, + .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, + .lpm_num_maps = PTL_LPM_NUM_MAPS, + .ltr_ignore_max = LNL_NUM_IP_IGN_ALLOWED, + .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2, + .etr3_offset = ETR3_OFFSET, + .lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET, + .lpm_priority_offset = MTL_LPM_PRI_OFFSET, + .lpm_en_offset = MTL_LPM_EN_OFFSET, + .lpm_residency_offset = MTL_LPM_RESIDENCY_OFFSET, + .lpm_sts = wcl_pcdn_lpm_maps, + .lpm_status_offset = MTL_LPM_STATUS_OFFSET, + .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET, + .s0ix_blocker_maps = wcl_pcdn_blk_maps, + .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET, +}; + +#define WCL_NPU_PCI_DEV 0xfd3e + +/* + * Set power state of select devices that do not have drivers to D3 + * so that they do not block Package C entry. + */ +static void wcl_d3_fixup(void) +{ + pmc_core_set_device_d3(WCL_NPU_PCI_DEV); +} + +static int wcl_resume(struct pmc_dev *pmcdev) +{ + wcl_d3_fixup(); + return cnl_resume(pmcdev); +} + +static int wcl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info) +{ + wcl_d3_fixup(); + return generic_core_init(pmcdev, pmc_dev_info); +} + +struct pmc_dev_info wcl_pmc_dev = { + .map = &wcl_pcdn_reg_map, + .suspend = cnl_suspend, + .resume = wcl_resume, + .init = wcl_core_init, +}; From 98aadf8e494d2bf66b15d0ef9646ad9fdb6ded15 Mon Sep 17 00:00:00 2001 From: Gladyshev Ilya Date: Wed, 20 Aug 2025 20:41:32 +0300 Subject: [PATCH 0627/2711] platform/x86: Add WMI driver for Redmibook keyboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver implements support for various Fn keys (like Cut) and Xiaomi specific AI button. Reviewed-by: Armin Wolf Signed-off-by: Gladyshev Ilya Link: https://lore.kernel.org/r/20250820174140.41410-1-foxido@foxido.dev [ij: use BIT(8) instead of 0x00000100] Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- MAINTAINERS | 6 ++ drivers/platform/x86/Kconfig | 12 +++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/redmi-wmi.c | 130 +++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 drivers/platform/x86/redmi-wmi.c diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..df1bb6be63f9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21253,6 +21253,12 @@ S: Maintained T: git https://github.com/pkshih/rtw.git F: drivers/net/wireless/realtek/rtw89/ +REDMIBOOK WMI DRIVERS +M: Gladyshev Ilya +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/redmi-wmi.c + REDPINE WIRELESS DRIVER L: linux-wireless@vger.kernel.org S: Orphan diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 6d238e120dce..46e62feeda3c 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -118,6 +118,18 @@ config XIAOMI_WMI To compile this driver as a module, choose M here: the module will be called xiaomi-wmi. +config REDMI_WMI + tristate "Redmibook WMI key driver" + depends on ACPI_WMI + depends on INPUT + select INPUT_SPARSEKMAP + help + Say Y here if you want support for WMI-based hotkey events on + Xiaomi Redmibook devices. + + To compile this driver as a module, choose M here: the module will + be called redmi-wmi. + config GIGABYTE_WMI tristate "Gigabyte WMI temperature driver" depends on ACPI_WMI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index a0c5848513e3..c7db2a88c11a 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_HUAWEI_WMI) += huawei-wmi.o obj-$(CONFIG_MXM_WMI) += mxm-wmi.o obj-$(CONFIG_NVIDIA_WMI_EC_BACKLIGHT) += nvidia-wmi-ec-backlight.o obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o +obj-$(CONFIG_REDMI_WMI) += redmi-wmi.o obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o # Acer diff --git a/drivers/platform/x86/redmi-wmi.c b/drivers/platform/x86/redmi-wmi.c new file mode 100644 index 000000000000..949236b93a32 --- /dev/null +++ b/drivers/platform/x86/redmi-wmi.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +/* WMI driver for Xiaomi Redmibooks */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define WMI_REDMIBOOK_KEYBOARD_EVENT_GUID "46C93E13-EE9B-4262-8488-563BCA757FEF" + +#define AI_KEY_VALUE_MASK BIT(8) + +static const struct key_entry redmi_wmi_keymap[] = { + {KE_KEY, 0x00000201, {KEY_SELECTIVE_SCREENSHOT}}, + {KE_KEY, 0x00000301, {KEY_ALL_APPLICATIONS}}, + {KE_KEY, 0x00001b01, {KEY_SETUP}}, + + /* AI button has code for each position */ + {KE_KEY, 0x00011801, {KEY_ASSISTANT}}, + {KE_KEY, 0x00011901, {KEY_ASSISTANT}}, + + /* Keyboard backlight */ + {KE_IGNORE, 0x00000501, {}}, + {KE_IGNORE, 0x00800501, {}}, + {KE_IGNORE, 0x00050501, {}}, + {KE_IGNORE, 0x000a0501, {}}, + + {KE_END} +}; + +struct redmi_wmi { + struct input_dev *input_dev; + /* Protects the key event sequence */ + struct mutex key_lock; +}; + +static int redmi_wmi_probe(struct wmi_device *wdev, const void *context) +{ + struct redmi_wmi *data; + int err; + + /* Init dev */ + data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + dev_set_drvdata(&wdev->dev, data); + + err = devm_mutex_init(&wdev->dev, &data->key_lock); + if (err) + return err; + + data->input_dev = devm_input_allocate_device(&wdev->dev); + if (!data->input_dev) + return -ENOMEM; + + data->input_dev->name = "Redmibook WMI keys"; + data->input_dev->phys = "wmi/input0"; + + err = sparse_keymap_setup(data->input_dev, redmi_wmi_keymap, NULL); + if (err) + return err; + + return input_register_device(data->input_dev); +} + +static void redmi_wmi_notify(struct wmi_device *wdev, union acpi_object *obj) +{ + struct key_entry *entry; + struct redmi_wmi *data = dev_get_drvdata(&wdev->dev); + bool autorelease = true; + u32 payload; + int value = 1; + + if (obj->type != ACPI_TYPE_BUFFER) { + dev_err(&wdev->dev, "Bad response type %u\n", obj->type); + return; + } + + if (obj->buffer.length < 32) { + dev_err(&wdev->dev, "Invalid buffer length %u\n", obj->buffer.length); + return; + } + + payload = get_unaligned_le32(obj->buffer.pointer); + entry = sparse_keymap_entry_from_scancode(data->input_dev, payload); + + if (!entry) { + dev_dbg(&wdev->dev, "Unknown WMI event with payload %u", payload); + return; + } + + /* AI key quirk */ + if (entry->keycode == KEY_ASSISTANT) { + value = !(payload & AI_KEY_VALUE_MASK); + autorelease = false; + } + + guard(mutex)(&data->key_lock); + sparse_keymap_report_entry(data->input_dev, entry, value, autorelease); +} + +static const struct wmi_device_id redmi_wmi_id_table[] = { + { WMI_REDMIBOOK_KEYBOARD_EVENT_GUID, NULL }, + { } +}; + +static struct wmi_driver redmi_wmi_driver = { + .driver = { + .name = "redmi-wmi", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .id_table = redmi_wmi_id_table, + .probe = redmi_wmi_probe, + .notify = redmi_wmi_notify, + .no_singleton = true, +}; +module_wmi_driver(redmi_wmi_driver); + +MODULE_DEVICE_TABLE(wmi, redmi_wmi_id_table); +MODULE_AUTHOR("Gladyshev Ilya "); +MODULE_DESCRIPTION("Redmibook WMI driver"); +MODULE_LICENSE("GPL"); From faec01b1a4998f3747f55e394409bdcb541af319 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Wed, 20 Aug 2025 16:51:01 +0800 Subject: [PATCH 0628/2711] platform/x86: x86-android-tablets: Remove the use of dev_err_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dev_err_probe() doesn't do anything when error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250820085101.395377-1-zhao.xichao@vivo.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/x86-android-tablets/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index 2a9c47178505..db76ba3abd7b 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -265,8 +265,7 @@ static __init int x86_instantiate_spi_dev(const struct x86_dev_info *dev_info, i spi_devs[idx] = spi_new_device(controller, &board_info); put_device(&controller->dev); if (!spi_devs[idx]) - return dev_err_probe(&controller->dev, -ENOMEM, - "creating SPI-device %d\n", idx); + return -ENOMEM; return 0; } From 6d47b4f08436cb682fb2644e6265a3897fd42a77 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 19 Aug 2025 14:10:34 -0700 Subject: [PATCH 0629/2711] platform/x86/intel-uncore-freq: Fix warning in partitioned system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A partitioned system configured with only one package and one compute die, warning will be generated for duplicate sysfs entry. This typically occurs during the platform bring-up phase. Partitioned systems expose dies, equivalent to TPMI compute domains, through the CPUID. Each partitioned system must contains at least one compute die per partition, resulting in a minimum of two dies per package. Hence the function topology_max_dies_per_package() returns at least two, and the condition "topology_max_dies_per_package() > 1" prevents the creation of a root domain. In this case topology_max_dies_per_package() will return 1 and root domain will be created for partition 0 and a duplicate sysfs warning for partition 1 as both partitions have same package ID. To address this also check for non zero partition in addition to topology_max_dies_per_package() > 1. Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20250819211034.3776284-1-srinivas.pandruvada@linux.intel.com Signed-off-by: Ilpo Järvinen --- .../platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index 6df55c8e16b7..cb4905bad89b 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -633,7 +633,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ auxiliary_set_drvdata(auxdev, tpmi_uncore); - if (topology_max_dies_per_package() > 1) + if (topology_max_dies_per_package() > 1 || plat_info->partition) return 0; tpmi_uncore->root_cluster.root_domain = true; From 55df384148396c0503cfc51a9c7177df6a423843 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 19 Aug 2025 21:51:55 +0800 Subject: [PATCH 0630/2711] platform/x86/intel/pmc: use kcalloc() instead of kzalloc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace devm_kzalloc() with devm_kcalloc() in pmc_core_get_tgl_lpm_reqs(). As noted in the kernel documentation [1], open-coded multiplication in allocator arguments is discouraged because it can lead to integer overflow. Using devm_kcalloc() provides built-in overflow protection, making the memory allocation safer when calculating the allocation size compared to explicit multiplication. [1]: https://www.kernel.org/doc/html/next/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments Signed-off-by: Qianfeng Rong Acked-by: David E. Box Link: https://lore.kernel.org/r/20250819135155.338380-1-rongqianfeng@vivo.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/pmc/tgl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/pmc/tgl.c b/drivers/platform/x86/intel/pmc/tgl.c index 02e731ed3391..fc5b4cacc1c6 100644 --- a/drivers/platform/x86/intel/pmc/tgl.c +++ b/drivers/platform/x86/intel/pmc/tgl.c @@ -273,8 +273,8 @@ void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev) addr = (u32 *)out_obj->buffer.pointer; - lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size * sizeof(u32), - GFP_KERNEL); + lpm_req_regs = devm_kcalloc(&pdev->dev, lpm_size, sizeof(u32), + GFP_KERNEL); if (!lpm_req_regs) goto free_acpi_obj; From ba9eddc43f2f05a99d3f7535c9367845aca35904 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 21:13:44 +0200 Subject: [PATCH 0631/2711] platform/x86: portwell-ec: don't print superfluous errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The watchdog core will handle error messages already. Signed-off-by: Wolfram Sang Reviewed-by: Yen-Chi Huang Tested-by: Yen-Chi Huang Link: https://lore.kernel.org/r/20250813191416.6860-2-wsa+renesas@sang-engineering.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/portwell-ec.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/platform/x86/portwell-ec.c b/drivers/platform/x86/portwell-ec.c index d2e91d5c3b3a..13db9aa485d3 100644 --- a/drivers/platform/x86/portwell-ec.c +++ b/drivers/platform/x86/portwell-ec.c @@ -238,13 +238,7 @@ static int pwec_probe(struct platform_device *pdev) } ec_wdt_dev.parent = &pdev->dev; - ret = devm_watchdog_register_device(&pdev->dev, &ec_wdt_dev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register Portwell EC Watchdog\n"); - return ret; - } - - return 0; + return devm_watchdog_register_device(&pdev->dev, &ec_wdt_dev); } static int pwec_suspend(struct device *dev) From ee1cb9b0e6a80c4f9011e7a9f87e3942a65e6f16 Mon Sep 17 00:00:00 2001 From: Suma Hegde Date: Thu, 7 Aug 2025 11:42:03 +0000 Subject: [PATCH 0632/2711] platform/x86/amd/hsmp: Replace dev_err() with dev_info() for non-fatal errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Failure in metric table initialization and hwmon registration are non-fatal errors. Hence replace them with dev_info(). Signed-off-by: Suma Hegde Link: https://lore.kernel.org/r/20250807114203.982860-1-suma.hegde@amd.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/hsmp/acpi.c | 4 ++-- drivers/platform/x86/amd/hsmp/plat.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c index 54986a752f7d..c2df8b421430 100644 --- a/drivers/platform/x86/amd/hsmp/acpi.c +++ b/drivers/platform/x86/amd/hsmp/acpi.c @@ -495,12 +495,12 @@ static int init_acpi(struct device *dev) if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) { ret = hsmp_get_tbl_dram_base(sock_ind); if (ret) - dev_err(dev, "Failed to init metric table\n"); + dev_info(dev, "Failed to init metric table\n"); } ret = hsmp_create_sensor(dev, sock_ind); if (ret) - dev_err(dev, "Failed to register HSMP sensors with hwmon\n"); + dev_info(dev, "Failed to register HSMP sensors with hwmon\n"); dev_set_drvdata(dev, &hsmp_pdev->sock[sock_ind]); diff --git a/drivers/platform/x86/amd/hsmp/plat.c b/drivers/platform/x86/amd/hsmp/plat.c index 22f50b6235d6..e07f68575055 100644 --- a/drivers/platform/x86/amd/hsmp/plat.c +++ b/drivers/platform/x86/amd/hsmp/plat.c @@ -189,13 +189,13 @@ static int init_platform_device(struct device *dev) if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) { ret = hsmp_get_tbl_dram_base(i); if (ret) - dev_err(dev, "Failed to init metric table\n"); + dev_info(dev, "Failed to init metric table\n"); } /* Register with hwmon interface for reporting power */ ret = hsmp_create_sensor(dev, i); if (ret) - dev_err(dev, "Failed to register HSMP sensors with hwmon\n"); + dev_info(dev, "Failed to register HSMP sensors with hwmon\n"); } return 0; From 3ea299d3dccdb8554057d0a87552e7673baea95d Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 11 Aug 2025 09:40:40 +0200 Subject: [PATCH 0633/2711] mtd: nand: qpic-common: remove a bunch of unused defines A bunch of definitions in the 'nand-qpic-common.h' header became unused after the conversion of the 'qcom_nandc' and 'spi-qpic-snand' drivers to use the FIELD_PREP() macro, so remove those. No functional changes. Signed-off-by: Gabor Juhos Signed-off-by: Miquel Raynal --- include/linux/mtd/nand-qpic-common.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h index 4e694b1aabbd..e8201d1b7cf9 100644 --- a/include/linux/mtd/nand-qpic-common.h +++ b/include/linux/mtd/nand-qpic-common.h @@ -71,14 +71,10 @@ /* NAND_DEVn_CFG0 bits */ #define DISABLE_STATUS_AFTER_WRITE BIT(4) -#define CW_PER_PAGE 6 #define CW_PER_PAGE_MASK GENMASK(8, 6) -#define UD_SIZE_BYTES 9 #define UD_SIZE_BYTES_MASK GENMASK(18, 9) #define ECC_PARITY_SIZE_BYTES_RS GENMASK(22, 19) -#define SPARE_SIZE_BYTES 23 #define SPARE_SIZE_BYTES_MASK GENMASK(26, 23) -#define NUM_ADDR_CYCLES 27 #define NUM_ADDR_CYCLES_MASK GENMASK(29, 27) #define STATUS_BFR_READ BIT(30) #define SET_RD_MODE_AFTER_STATUS BIT(31) @@ -86,26 +82,20 @@ /* NAND_DEVn_CFG0 bits */ #define DEV0_CFG1_ECC_DISABLE BIT(0) #define WIDE_FLASH BIT(1) -#define NAND_RECOVERY_CYCLES 2 #define NAND_RECOVERY_CYCLES_MASK GENMASK(4, 2) #define CS_ACTIVE_BSY BIT(5) -#define BAD_BLOCK_BYTE_NUM 6 #define BAD_BLOCK_BYTE_NUM_MASK GENMASK(15, 6) #define BAD_BLOCK_IN_SPARE_AREA BIT(16) -#define WR_RD_BSY_GAP 17 #define WR_RD_BSY_GAP_MASK GENMASK(22, 17) #define ENABLE_BCH_ECC BIT(27) /* NAND_DEV0_ECC_CFG bits */ #define ECC_CFG_ECC_DISABLE BIT(0) #define ECC_SW_RESET BIT(1) -#define ECC_MODE 4 #define ECC_MODE_MASK GENMASK(5, 4) #define ECC_MODE_4BIT 0 #define ECC_MODE_8BIT 1 -#define ECC_PARITY_SIZE_BYTES_BCH 8 #define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8) -#define ECC_NUM_DATA_BYTES 16 #define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16) #define ECC_FORCE_CLK_OPEN BIT(30) @@ -120,7 +110,6 @@ #define SEQ_READ_START_VLD BIT(4) /* NAND_EBI2_ECC_BUF_CFG bits */ -#define NUM_STEPS 0 #define NUM_STEPS_MASK GENMASK(9, 0) /* NAND_ERASED_CW_DETECT_CFG bits */ @@ -141,11 +130,8 @@ #define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED) /* NAND_READ_LOCATION_n bits */ -#define READ_LOCATION_OFFSET 0 #define READ_LOCATION_OFFSET_MASK GENMASK(9, 0) -#define READ_LOCATION_SIZE 16 #define READ_LOCATION_SIZE_MASK GENMASK(25, 16) -#define READ_LOCATION_LAST 31 #define READ_LOCATION_LAST_MASK BIT(31) /* Version Mask */ From 5b5dc7db5a8dc2c221526acf81b323ec1f972d0f Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 11 Aug 2025 10:30:42 +0200 Subject: [PATCH 0634/2711] mtd: nand: qpic_common: use {cmd,data}_sgl_nitems for sg_init_table() Since commit ddaad4ad774d ("mtd: nand: qpic_common: prevent out of bounds access of BAM arrays"), the {cmd,data}_sgl_nitems members in the 'bam_transaction' structure are containing the number of elements in the cmd/data scatter-gather lists. Change the qcom_clear_bam_transaction() function to use these numbers while reinitializing the sg lists instead of recomputing the number of elements to make it less error prone. Signed-off-by: Gabor Juhos Acked-by: Konrad Dybcio Signed-off-by: Miquel Raynal --- drivers/mtd/nand/qpic_common.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/qpic_common.c b/drivers/mtd/nand/qpic_common.c index 8e604cc22ca3..db6c46a6fe01 100644 --- a/drivers/mtd/nand/qpic_common.c +++ b/drivers/mtd/nand/qpic_common.c @@ -89,10 +89,8 @@ void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc) memset(&bam_txn->bam_positions, 0, sizeof(bam_txn->bam_positions)); bam_txn->last_data_desc = NULL; - sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * - QPIC_PER_CW_CMD_SGL); - sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage * - QPIC_PER_CW_DATA_SGL); + sg_init_table(bam_txn->cmd_sgl, bam_txn->cmd_sgl_nitems); + sg_init_table(bam_txn->data_sgl, bam_txn->data_sgl_nitems); reinit_completion(&bam_txn->txn_done); } From 49b9254217048068ae1011619db60a6de5edf7e2 Mon Sep 17 00:00:00 2001 From: Teng Wu Date: Mon, 18 Aug 2025 21:52:27 +0800 Subject: [PATCH 0635/2711] mtd: spinand: gigadevice: Add continuous read support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GD5F1GM9 supports a high-speed Continuous Read (CR) mode which allows the entire memory array to be read out by a single read command without re-issuing the 13h “Page Read to Cache” command for every page. Datasheet summary Feature register B0[3] (NR bit) 1 = Normal Read (default) 0 = Continuous Read (CR) ECC status register 7Ch Normal read: bits [3:0] → ECC status of last page Continuous read: bits [7:4] → accumulated max bit-flips over the whole sequential read operation. Datasheet: https://github.com/WT-886/DATASHEET/blob/main/GD5F1GM9-v1.0.pdf Signed-off-by: Teng Wu Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/gigadevice.c | 107 +++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c index 93e40431dbe2..72ad36c9a126 100644 --- a/drivers/mtd/nand/spi/gigadevice.c +++ b/drivers/mtd/nand/spi/gigadevice.c @@ -4,6 +4,7 @@ * Chuanhong Guo */ +#include #include #include #include @@ -23,6 +24,18 @@ #define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS (1 << 4) #define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4) +/* Feature bit definitions */ +#define GD_FEATURE_NR BIT(3) /* Normal Read(1=normal,0=continuous) */ +#define GD_FEATURE_CRDC BIT(2) /* Continuous Read Dummy */ + +/* ECC status extraction helpers */ +#define GD_ECCSR_LAST_PAGE(eccsr) FIELD_GET(GENMASK(3, 0), eccsr) +#define GD_ECCSR_ACCUMULATED(eccsr) FIELD_GET(GENMASK(7, 4), eccsr) + +struct gigadevice_priv { + bool continuous_read; +}; + static SPINAND_OP_VARIANTS(read_cache_variants, SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0), SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), @@ -63,6 +76,74 @@ static SPINAND_OP_VARIANTS(update_cache_variants, SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); +static int gd5fxgm9_get_eccsr(struct spinand_device *spinand, u8 *eccsr) +{ + struct gigadevice_priv *priv = spinand->priv; + struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_DUMMY(1, 1), + SPI_MEM_OP_DATA_IN(1, eccsr, 1)); + int ret; + + ret = spi_mem_exec_op(spinand->spimem, &op); + if (ret) + return ret; + + if (priv->continuous_read) + *eccsr = GD_ECCSR_ACCUMULATED(*eccsr); + else + *eccsr = GD_ECCSR_LAST_PAGE(*eccsr); + + return 0; +} + +static int gd5fxgm9_ecc_get_status(struct spinand_device *spinand, u8 status) +{ + struct nand_device *nand = spinand_to_nand(spinand); + u8 eccsr; + int ret; + + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + + case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS: + ret = gd5fxgm9_get_eccsr(spinand, spinand->scratchbuf); + if (ret) + return nanddev_get_ecc_conf(nand)->strength; + + eccsr = *spinand->scratchbuf; + if (WARN_ON(!eccsr || eccsr > nanddev_get_ecc_conf(nand)->strength)) + return nanddev_get_ecc_conf(nand)->strength; + + return eccsr; + + case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS: + return 8; + + case STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + + default: + return -EINVAL; + } +} + +static int gd5fxgm9_set_continuous_read(struct spinand_device *spinand, bool enable) +{ + struct gigadevice_priv *priv = spinand->priv; + int ret; + + ret = spinand_upd_cfg(spinand, GD_FEATURE_NR, + enable ? 0 : GD_FEATURE_NR); + if (ret) + return ret; + + priv->continuous_read = enable; + + return 0; +} + static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) { @@ -542,7 +623,8 @@ static const struct spinand_info gigadevice_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, - gd5fxgq4uexxg_ecc_get_status)), + gd5fxgm9_ecc_get_status), + SPINAND_CONT_READ(gd5fxgm9_set_continuous_read)), SPINAND_INFO("GD5F1GM9RExxG", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81, 0x01), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), @@ -552,10 +634,31 @@ static const struct spinand_info gigadevice_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, - gd5fxgq4uexxg_ecc_get_status)), + gd5fxgm9_ecc_get_status), + SPINAND_CONT_READ(gd5fxgm9_set_continuous_read)), }; +static int gd5fxgm9_spinand_init(struct spinand_device *spinand) +{ + struct gigadevice_priv *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spinand->priv = priv; + + return 0; +} + +static void gd5fxgm9_spinand_cleanup(struct spinand_device *spinand) +{ + kfree(spinand->priv); +} + static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { + .init = gd5fxgm9_spinand_init, + .cleanup = gd5fxgm9_spinand_cleanup, }; const struct spinand_manufacturer gigadevice_spinand_manufacturer = { From 5f284dc15ca8695d0394414045ac64616a3b0e69 Mon Sep 17 00:00:00 2001 From: Tianling Shen Date: Mon, 25 Aug 2025 01:00:13 +0800 Subject: [PATCH 0636/2711] mtd: spinand: add support for FudanMicro FM25S01A Add support for FudanMicro FM25S01A SPI NAND. Datasheet: http://eng.fmsh.com/nvm/FM25S01A_ds_eng.pdf Signed-off-by: Tianling Shen Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/Makefile | 2 +- drivers/mtd/nand/spi/core.c | 1 + drivers/mtd/nand/spi/fmsh.c | 74 +++++++++++++++++++++++++++++++++++ include/linux/mtd/spinand.h | 1 + 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/nand/spi/fmsh.c diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index 258da42451a4..6d3d203df048 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 spinand-objs := core.o otp.o -spinand-objs += alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o +spinand-objs += alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o spinand-objs += micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index b0898990b2a5..ea47028d021a 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1184,6 +1184,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { &alliancememory_spinand_manufacturer, &ato_spinand_manufacturer, &esmt_c8_spinand_manufacturer, + &fmsh_spinand_manufacturer, &foresee_spinand_manufacturer, &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, diff --git a/drivers/mtd/nand/spi/fmsh.c b/drivers/mtd/nand/spi/fmsh.c new file mode 100644 index 000000000000..8b2097bfc771 --- /dev/null +++ b/drivers/mtd/nand/spi/fmsh.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + * + * Author: Dingqiang Lin + */ + +#include +#include +#include + +#define SPINAND_MFR_FMSH 0xA1 + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); + +static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + return -ERANGE; +} + +static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + region->offset = 2; + region->length = 62; + + return 0; +} + +static const struct mtd_ooblayout_ops fm25s01a_ooblayout = { + .ecc = fm25s01a_ooblayout_ecc, + .free = fm25s01a_ooblayout_free, +}; + +static const struct spinand_info fmsh_spinand_table[] = { + SPINAND_INFO("FM25S01A", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)), +}; + +static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer fmsh_spinand_manufacturer = { + .id = SPINAND_MFR_FMSH, + .name = "Fudan Micro", + .chips = fmsh_spinand_table, + .nchips = ARRAY_SIZE(fmsh_spinand_table), + .ops = &fmsh_spinand_manuf_ops, +}; diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 27a45bdab7ec..927c10d78769 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -355,6 +355,7 @@ struct spinand_manufacturer { extern const struct spinand_manufacturer alliancememory_spinand_manufacturer; extern const struct spinand_manufacturer ato_spinand_manufacturer; extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; +extern const struct spinand_manufacturer fmsh_spinand_manufacturer; extern const struct spinand_manufacturer foresee_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer; From f06ba25ec54a3157c5b636483586f152f4478b9a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:24 -0700 Subject: [PATCH 0637/2711] perf annotate: Rename to __hist_entry__tui_annotate() There are three different but similar functions for annotation on TUI. Rename it to __hist_entry__tui_annotate() and make sure it passes 'he'. It's not used for now but it'll be needed for later use. Also remove map_symbol__tui_annotate() which was a simple wrapper. Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 40 +++++++++++++++++++++++-------- tools/perf/ui/browsers/hists.c | 2 +- tools/perf/util/annotate.h | 12 ---------- tools/perf/util/hist.h | 12 ++++++---- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 183902dac042..4d5cbb86cbb6 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -12,6 +12,7 @@ #include "../../util/symbol.h" #include "../../util/evsel.h" #include "../../util/evlist.h" +#include "../../util/thread.h" #include #include #include @@ -27,10 +28,18 @@ struct annotate_browser { struct rb_node *curr_hot; struct annotation_line *selection; struct arch *arch; + /* + * perf top can delete hist_entry anytime. Callers should make sure + * its lifetime. + */ + struct hist_entry *he; bool searching_backwards; char search_bf[128]; }; +/* A copy of target hist_entry for perf top. */ +static struct hist_entry annotate_he; + static inline struct annotation *browser__annotation(struct ui_browser *browser) { struct map_symbol *ms = browser->priv; @@ -557,7 +566,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, target_ms.map = ms->map; target_ms.sym = dl->ops.target.sym; annotation__unlock(notes); - symbol__tui_annotate(&target_ms, evsel, hbt); + __hist_entry__tui_annotate(browser->he, &target_ms, evsel, hbt); sym_title(ms->sym, ms->map, title, sizeof(title), annotate_opts.percent_type); ui_browser__show_title(&browser->b, title); return true; @@ -1032,12 +1041,6 @@ out: return key; } -int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt) -{ - return symbol__tui_annotate(ms, evsel, hbt); -} - int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, struct hist_browser_timer *hbt) { @@ -1046,11 +1049,12 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, SLang_init_tty(0, 0, 0); SLtty_set_suspend_state(true); - return map_symbol__tui_annotate(&he->ms, evsel, hbt); + return __hist_entry__tui_annotate(he, &he->ms, evsel, hbt); } -int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt) +int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms, + struct evsel *evsel, + struct hist_browser_timer *hbt) { struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); @@ -1064,6 +1068,7 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, .priv = ms, .use_navkeypressed = true, }, + .he = he, }; struct dso *dso; int ret = -1, err; @@ -1093,6 +1098,16 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, } } + /* Copy necessary information when it's called from perf top */ + if (hbt != NULL && he != &annotate_he) { + annotate_he.hists = he->hists; + annotate_he.thread = thread__get(he->thread); + annotate_he.cpumode = he->cpumode; + map_symbol__copy(&annotate_he.ms, ms); + + browser.he = &annotate_he; + } + ui_helpline__push("Press ESC to exit"); browser.b.width = notes->src->widths.max_line_len; @@ -1108,5 +1123,10 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, if (not_annotated && !notes->src->tried_source) annotated_source__purge(notes->src); + if (hbt != NULL && he != &annotate_he) { + thread__zput(annotate_he.thread); + map_symbol__exit(&annotate_he.ms); + } + return ret; } diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index d9d3fb44477a..487c0b08c003 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2484,8 +2484,8 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) else evsel = hists_to_evsel(browser->hists); - err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); he = hist_browser__selected_entry(browser); + err = __hist_entry__tui_annotate(he, &act->ms, evsel, browser->hbt); /* * offer option to annotate the other branch source or target * (if they exists) when returning from annotate diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8b5131d257b0..0f640e487174 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -471,18 +471,6 @@ int hist_entry__annotate_printf(struct hist_entry *he, struct evsel *evsel); int hist_entry__tty_annotate(struct hist_entry *he, struct evsel *evsel); int hist_entry__tty_annotate2(struct hist_entry *he, struct evsel *evsel); -#ifdef HAVE_SLANG_SUPPORT -int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt); -#else -static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unused, - struct evsel *evsel __maybe_unused, - struct hist_browser_timer *hbt __maybe_unused) -{ - return 0; -} -#endif - void annotation_options__init(void); void annotation_options__exit(void); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 70438d03ca9c..c64005278687 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -713,8 +713,9 @@ struct block_hist { #include "../ui/keysyms.h" void attr_to_script(char *buf, struct perf_event_attr *attr); -int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt); +int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms, + struct evsel *evsel, + struct hist_browser_timer *hbt); int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, struct hist_browser_timer *hbt); @@ -742,9 +743,10 @@ int evlist__tui_browse_hists(struct evlist *evlist __maybe_unused, { return 0; } -static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused, - struct evsel *evsel __maybe_unused, - struct hist_browser_timer *hbt __maybe_unused) +static inline int __hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, + struct map_symbol *ms __maybe_unused, + struct evsel *evsel __maybe_unused, + struct hist_browser_timer *hbt __maybe_unused) { return 0; } From 4e3c9dc8b80e3d78be0055ef4ea5111427eab7f7 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:25 -0700 Subject: [PATCH 0638/2711] perf annotate: Remove annotation_print_data.start The start field is to control whether the output shows full address or offset from the function start. But actually it can be changed dynamically in annotation__toggle_full_addr(). The informaiton should be available through struct annotation. Let's use it directly. Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0dd475a744b6..b699e14102b0 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -770,7 +770,6 @@ struct annotation_print_data { struct evsel *evsel; struct arch *arch; struct debuginfo *dbg; - u64 start; int addr_fmt_width; }; @@ -845,7 +844,7 @@ annotation_line__print(struct annotation_line *al, struct annotation_print_data printf(" : "); - disasm_line__print(dl, apd->start, apd->addr_fmt_width); + disasm_line__print(dl, notes->src->start, apd->addr_fmt_width); if (opts->code_with_type && apd->dbg) { struct annotated_data_type *data_type; @@ -1230,7 +1229,6 @@ int hist_entry__annotate_printf(struct hist_entry *he, struct evsel *evsel) struct annotation_print_data apd = { .he = he, .evsel = evsel, - .start = map__rip_2objdump(map, sym->start), }; int printed = 2, queue_len = 0; int more = 0; @@ -1267,7 +1265,7 @@ int hist_entry__annotate_printf(struct hist_entry *he, struct evsel *evsel) symbol__annotate_hits(sym, evsel); apd.addr_fmt_width = annotated_source__addr_fmt_width(¬es->src->source, - apd.start); + notes->src->start); evsel__get_arch(evsel, &apd.arch); apd.dbg = debuginfo__new(filename); From 05a706b157acccc4b2c4063a63dbe38c130cd3fa Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:26 -0700 Subject: [PATCH 0639/2711] perf annotate: Remove __annotation_line__write() Get rid of the internal function and convert function arguments into local variables if they are used more than once. Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 42 +++++++++++++++----------------------- tools/perf/util/annotate.h | 2 +- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b699e14102b0..7929f108e35b 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1933,24 +1933,26 @@ err: return -ENOMEM; } -static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, - bool first_line, bool current_entry, bool change_color, int width, - void *obj, unsigned int percent_type, - int (*obj__set_color)(void *obj, int color), - void (*obj__set_percent_color)(void *obj, double percent, bool current), - int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), - void (*obj__printf)(void *obj, const char *fmt, ...), - void (*obj__write_graph)(void *obj, int graph)) - +void annotation_line__write(struct annotation_line *al, struct annotation *notes, + const struct annotation_write_ops *wops) { - double percent_max = annotation_line__max_percent(al, percent_type); - int pcnt_width = annotation__pcnt_width(notes), - cycles_width = annotation__cycles_width(notes); + bool current_entry = wops->current_entry; + bool change_color = wops->change_color; + double percent_max = annotation_line__max_percent(al, annotate_opts.percent_type); + int width = wops->width; + int pcnt_width = annotation__pcnt_width(notes); + int cycles_width = annotation__cycles_width(notes); bool show_title = false; char bf[256]; int printed; + void *obj = wops->obj; + int (*obj__set_color)(void *obj, int color) = wops->set_color; + void (*obj__set_percent_color)(void *obj, double percent, bool current) = wops->set_percent_color; + int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current) = wops->set_jumps_percent_color; + void (*obj__printf)(void *obj, const char *fmt, ...) = wops->printf; + void (*obj__write_graph)(void *obj, int graph) = wops->write_graph; - if (first_line && (al->offset == -1 || percent_max == 0.0)) { + if (wops->first_line && (al->offset == -1 || percent_max == 0.0)) { if (notes->branch && al->cycles) { if (al->cycles->ipc == 0.0 && al->cycles->avg == 0) show_title = true; @@ -1964,7 +1966,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati for (i = 0; i < al->data_nr; i++) { double percent; - percent = annotation_data__percent(&al->data[i], percent_type); + percent = annotation_data__percent(&al->data[i], + annotate_opts.percent_type); obj__set_percent_color(obj, percent, current_entry); if (symbol_conf.show_total_period) { @@ -2113,17 +2116,6 @@ print_addr: } -void annotation_line__write(struct annotation_line *al, struct annotation *notes, - struct annotation_write_ops *wops) -{ - __annotation_line__write(al, notes, wops->first_line, wops->current_entry, - wops->change_color, wops->width, wops->obj, - annotate_opts.percent_type, - wops->set_color, wops->set_percent_color, - wops->set_jumps_percent_color, wops->printf, - wops->write_graph); -} - int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, struct arch **parch) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 0f640e487174..2e28a24fa13a 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -200,7 +200,7 @@ struct annotation_write_ops { }; void annotation_line__write(struct annotation_line *al, struct annotation *notes, - struct annotation_write_ops *ops); + const struct annotation_write_ops *ops); int __annotation__scnprintf_samples_period(struct annotation *notes, char *bf, size_t size, From d94d5eb54f9cf21411ad18fa2c7b6082437aa6c5 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:27 -0700 Subject: [PATCH 0640/2711] perf annotate: Pass annotation_print_data to annotation_line__write() It will be used for data type display later. Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Link: https://lore.kernel.org/r/20250816031635.25318-5-namhyung@kernel.org Cc: Peter Zijlstra Cc: Adrian Hunter Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Ingo Molnar Cc: Kan Liang Cc: LKML Cc: linux-perf-users@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 13 ++++++++++-- tools/perf/util/annotate.c | 33 ++++++++++++++++++------------- tools/perf/util/annotate.h | 15 ++++++++++++-- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 4d5cbb86cbb6..3e8b111e3f12 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -33,6 +33,8 @@ struct annotate_browser { * its lifetime. */ struct hist_entry *he; + struct debuginfo *dbg; + struct evsel *evsel; bool searching_backwards; char search_bf[128]; }; @@ -116,12 +118,18 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int .printf = annotate_browser__printf, .write_graph = annotate_browser__write_graph, }; + struct annotation_print_data apd = { + .he = ab->he, + .arch = ab->arch, + .evsel = ab->evsel, + .dbg = ab->dbg, + }; /* The scroll bar isn't being used */ if (!browser->navkeypressed) ops.width += 1; - annotation_line__write(al, notes, &ops); + annotation_line__write(al, notes, &ops, &apd); if (ops.current_entry) ab->selection = al; @@ -984,7 +992,7 @@ show_sup_ins: continue; } case 'P': - map_symbol__annotation_dump(ms, evsel); + map_symbol__annotation_dump(ms, evsel, browser->he); continue; case 't': if (symbol_conf.show_total_period) { @@ -1069,6 +1077,7 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms, .use_navkeypressed = true, }, .he = he, + .evsel = evsel, }; struct dso *dso; int ret = -1, err; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7929f108e35b..2544d83a52a0 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -765,14 +765,6 @@ __hist_entry__get_data_type(struct hist_entry *he, struct arch *arch, struct debuginfo *dbg, struct disasm_line *dl, int *type_offset); -struct annotation_print_data { - struct hist_entry *he; - struct evsel *evsel; - struct arch *arch; - struct debuginfo *dbg; - int addr_fmt_width; -}; - static int annotation_line__print(struct annotation_line *al, struct annotation_print_data *apd, struct annotation_options *opts, int printed, @@ -1355,7 +1347,8 @@ static void FILE__write_graph(void *fp, int graph) fputs(s, fp); } -static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) +static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, + struct annotation_print_data *apd) { struct annotation *notes = symbol__annotation(sym); struct annotation_write_ops wops = { @@ -1372,7 +1365,7 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) list_for_each_entry(al, ¬es->src->source, node) { if (annotation_line__filter(al)) continue; - annotation_line__write(al, notes, &wops); + annotation_line__write(al, notes, &wops, apd); fputc('\n', fp); wops.first_line = false; } @@ -1380,13 +1373,18 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) return 0; } -int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel) +int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, + struct hist_entry *he) { const char *ev_name = evsel__name(evsel); char buf[1024]; char *filename; int err = -1; FILE *fp; + struct annotation_print_data apd = { + .he = he, + .evsel = evsel, + }; if (asprintf(&filename, "%s.annotation", ms->sym->name) < 0) return -1; @@ -1402,7 +1400,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel) fprintf(fp, "%s() %s\nEvent: %s\n\n", ms->sym->name, dso__long_name(map__dso(ms->map)), ev_name); - symbol__annotate_fprintf2(ms->sym, fp); + symbol__annotate_fprintf2(ms->sym, fp, &apd); fclose(fp); err = 0; @@ -1654,6 +1652,10 @@ int hist_entry__tty_annotate2(struct hist_entry *he, struct evsel *evsel) struct symbol *sym = ms->sym; struct rb_root source_line = RB_ROOT; struct hists *hists = evsel__hists(evsel); + struct annotation_print_data apd = { + .he = he, + .evsel = evsel, + }; char buf[1024]; int err; @@ -1676,7 +1678,7 @@ int hist_entry__tty_annotate2(struct hist_entry *he, struct evsel *evsel) hists__scnprintf_title(hists, buf, sizeof(buf)); fprintf(stdout, "%s, [percent: %s]\n%s() %s\n", buf, percent_type_str(annotate_opts.percent_type), sym->name, dso__long_name(dso)); - symbol__annotate_fprintf2(sym, stdout); + symbol__annotate_fprintf2(sym, stdout, &apd); annotated_source__purge(symbol__annotation(sym)->src); @@ -1934,7 +1936,8 @@ err: } void annotation_line__write(struct annotation_line *al, struct annotation *notes, - const struct annotation_write_ops *wops) + const struct annotation_write_ops *wops, + struct annotation_print_data *apd) { bool current_entry = wops->current_entry; bool change_color = wops->change_color; @@ -2112,6 +2115,8 @@ print_addr: disasm_line__write(disasm_line(al), notes, obj, bf, sizeof(bf), obj__printf, obj__write_graph); obj__printf(obj, "%-*s", width - pcnt_width - cycles_width - 3 - printed, bf); + + (void)apd; } } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 2e28a24fa13a..86e858f5bf17 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -199,8 +199,18 @@ struct annotation_write_ops { void (*write_graph)(void *obj, int graph); }; +struct annotation_print_data { + struct hist_entry *he; + struct evsel *evsel; + struct arch *arch; + struct debuginfo *dbg; + /* It'll be set in hist_entry__annotate_printf() */ + int addr_fmt_width; +}; + void annotation_line__write(struct annotation_line *al, struct annotation *notes, - const struct annotation_write_ops *ops); + const struct annotation_write_ops *ops, + struct annotation_print_data *apd); int __annotation__scnprintf_samples_period(struct annotation *notes, char *bf, size_t size, @@ -463,7 +473,8 @@ void symbol__annotate_zero_histogram(struct symbol *sym, struct evsel *evsel); void symbol__annotate_decay_histogram(struct symbol *sym, struct evsel *evsel); void annotated_source__purge(struct annotated_source *as); -int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel); +int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, + struct hist_entry *he); bool ui__has_annotation(void); From 7736a6fba05837d178caa3c0ced55da77377a7e6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:28 -0700 Subject: [PATCH 0641/2711] perf annotate: Simplify width calculation in annotation_line__write() The width is updated after each part is printed. It can skip the output processing if the total printed size is bigger than the width. No function changes intended. Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-6-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 2544d83a52a0..6389292ad8f9 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1993,6 +1993,7 @@ void annotation_line__write(struct annotation_line *al, struct annotation *notes symbol_conf.show_nr_samples ? "Samples" : "Percent"); } } + width -= pcnt_width; if (notes->branch) { if (al->cycles && al->cycles->ipc) @@ -2056,11 +2057,13 @@ void annotation_line__write(struct annotation_line *al, struct annotation *notes obj__printf(obj, "%*s", ANNOTATION__AVG_IPC_WIDTH, bf); } } + width -= cycles_width; obj__printf(obj, " "); + width -= 1; if (!*al->line) - obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " "); + obj__printf(obj, "%-*s", width, " "); else if (al->offset == -1) { if (al->line_nr && annotate_opts.show_linenr) printed = scnprintf(bf, sizeof(bf), "%-*d ", @@ -2069,7 +2072,8 @@ void annotation_line__write(struct annotation_line *al, struct annotation *notes printed = scnprintf(bf, sizeof(bf), "%-*s ", notes->src->widths.addr, " "); obj__printf(obj, bf); - obj__printf(obj, "%-*s", width - printed - pcnt_width - cycles_width + 1, al->line); + width -= printed; + obj__printf(obj, "%-*s", width, al->line); } else { u64 addr = al->offset; int color = -1; @@ -2112,9 +2116,11 @@ print_addr: if (change_color) obj__set_color(obj, color); + width -= printed; + disasm_line__write(disasm_line(al), notes, obj, bf, sizeof(bf), obj__printf, obj__write_graph); - obj__printf(obj, "%-*s", width - pcnt_width - cycles_width - 3 - printed, bf); + obj__printf(obj, "%-*s", width, bf); (void)apd; } From e38ea8c41edda61d7b86c94ff052474d0fe5bf9a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:29 -0700 Subject: [PATCH 0642/2711] perf annotate: Return printed number from disasm_line__write() Like other print functions, make disasm_line__write() return the number of printed characters. It'll be used to skip unnecessary operations when the screen is full. Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-7-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 6389292ad8f9..698bc4f559e8 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1743,7 +1743,7 @@ static double annotation_line__max_percent(struct annotation_line *al, return percent_max; } -static void disasm_line__write(struct disasm_line *dl, struct annotation *notes, +static int disasm_line__write(struct disasm_line *dl, struct annotation *notes, void *obj, char *bf, size_t size, void (*obj__printf)(void *obj, const char *fmt, ...), void (*obj__write_graph)(void *obj, int graph)) @@ -1771,8 +1771,8 @@ call_like: obj__printf(obj, " "); } - disasm_line__scnprintf(dl, bf, size, !annotate_opts.use_offset, - notes->src->widths.max_ins_name); + return disasm_line__scnprintf(dl, bf, size, !annotate_opts.use_offset, + notes->src->widths.max_ins_name) + 2; } static void ipc_coverage_string(char *bf, int size, struct annotation *notes) From 7dbe89ca3d5496a3232349f9a7edfba6f9061c4c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:30 -0700 Subject: [PATCH 0643/2711] perf annotate: Add --code-with-type support for TUI Until now, the --code-with-type option is available only on stdio. But it was an artifical limitation because of an implemention issue. Implement the same logic in annotation_line__write() for stdio2/TUI and remove the limitation and update the man page. Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-8-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-annotate.txt | 1 - tools/perf/builtin-annotate.c | 5 --- tools/perf/ui/browsers/annotate.c | 6 +++ tools/perf/util/annotate.c | 47 ++++++++++++++++++++-- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index 46090c5b42b4..547f1a268018 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -170,7 +170,6 @@ include::itrace.txt[] --code-with-type:: Show data type info in code annotation (for memory instructions only). - Currently it only works with --stdio option. SEE ALSO diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5d57d2913f3d..646f43b0f7c4 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -917,11 +917,6 @@ int cmd_annotate(int argc, const char **argv) symbol_conf.annotate_data_sample = true; } else if (annotate_opts.code_with_type) { symbol_conf.annotate_data_member = true; - - if (!annotate.use_stdio) { - pr_err("--code-with-type only works with --stdio.\n"); - goto out_delete; - } } setup_browser(true); diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 3e8b111e3f12..e5b35336f0d3 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -4,6 +4,7 @@ #include "../ui.h" #include "../../util/annotate.h" #include "../../util/debug.h" +#include "../../util/debuginfo.h" #include "../../util/dso.h" #include "../../util/hist.h" #include "../../util/sort.h" @@ -1119,6 +1120,9 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms, ui_helpline__push("Press ESC to exit"); + if (annotate_opts.code_with_type) + browser.dbg = debuginfo__new(dso__long_name(dso)); + browser.b.width = notes->src->widths.max_line_len; browser.b.nr_entries = notes->src->nr_entries; browser.b.entries = ¬es->src->source; @@ -1129,6 +1133,8 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms, ret = annotate_browser__run(&browser, evsel, hbt); + if (annotate_opts.code_with_type) + debuginfo__delete(browser.dbg); if (not_annotated && !notes->src->tried_source) annotated_source__purge(notes->src); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 698bc4f559e8..99e976d25449 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1362,6 +1362,11 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, }; struct annotation_line *al; + if (annotate_opts.code_with_type) { + evsel__get_arch(apd->evsel, &apd->arch); + apd->dbg = debuginfo__new(dso__long_name(map__dso(apd->he->ms.map))); + } + list_for_each_entry(al, ¬es->src->source, node) { if (annotation_line__filter(al)) continue; @@ -1370,6 +1375,9 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, wops.first_line = false; } + if (annotate_opts.code_with_type) + debuginfo__delete(apd->dbg); + return 0; } @@ -1935,6 +1943,36 @@ err: return -ENOMEM; } +static int disasm_line__snprint_type_info(struct disasm_line *dl, + char *buf, int len, + struct annotation_print_data *apd) +{ + struct annotated_data_type *data_type; + char member[256]; + int offset = 0; + int printed; + + scnprintf(buf, len, " "); + + if (!annotate_opts.code_with_type || apd->dbg == NULL) + return 1; + + data_type = __hist_entry__get_data_type(apd->he, apd->arch, apd->dbg, dl, &offset); + if (data_type == NULL || data_type == NO_TYPE) + return 1; + + printed = scnprintf(buf, len, "\t\t# data-type: %s", data_type->self.type_name); + + if (data_type != &stackop_type && data_type != &canary_type && len > printed) + printed += scnprintf(buf + printed, len - printed, " +%#x", offset); + + if (annotated_data_type__get_member_name(data_type, member, sizeof(member), offset) && + len > printed) { + printed += scnprintf(buf + printed, len - printed, " (%s)", member); + } + return printed; +} + void annotation_line__write(struct annotation_line *al, struct annotation *notes, const struct annotation_write_ops *wops, struct annotation_print_data *apd) @@ -2118,11 +2156,14 @@ print_addr: width -= printed; - disasm_line__write(disasm_line(al), notes, obj, bf, sizeof(bf), obj__printf, obj__write_graph); + printed = disasm_line__write(disasm_line(al), notes, obj, bf, sizeof(bf), + obj__printf, obj__write_graph); + obj__printf(obj, "%s", bf); + width -= printed; + + disasm_line__snprint_type_info(disasm_line(al), bf, sizeof(bf), apd); obj__printf(obj, "%-*s", width, bf); - - (void)apd; } } From 1d4374afd000baa59aadb067f195d0fae9bd7f11 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:31 -0700 Subject: [PATCH 0644/2711] perf annotate: Add 'T' hot key to toggle data type display Support data type display with a key press so that users can toggle the output dynamically on TUI. Also display "[Type]" in the title line if it's enabled. Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-9-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index e5b35336f0d3..dfe869c20e35 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -533,9 +533,10 @@ static void ui_browser__init_asm_mode(struct ui_browser *browser) static int sym_title(struct symbol *sym, struct map *map, char *title, size_t sz, int percent_type) { - return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, + return snprintf(title, sz, "%s %s [Percent: %s] %s", sym->name, dso__long_name(map__dso(map)), - percent_type_str(percent_type)); + percent_type_str(percent_type), + annotate_opts.code_with_type ? "[Type]" : ""); } /* @@ -909,7 +910,8 @@ static int annotate_browser__run(struct annotate_browser *browser, "b Toggle percent base [period/hits]\n" "B Branch counter abbr list (Optional)\n" "? Search string backwards\n" - "f Toggle showing offsets to full address\n"); + "f Toggle showing offsets to full address\n" + "T Toggle data type display\n"); continue; case 'r': script_browse(NULL, NULL); @@ -1029,6 +1031,12 @@ show_sup_ins: case 'f': annotation__toggle_full_addr(notes, ms); continue; + case 'T': + annotate_opts.code_with_type ^= 1; + if (browser->dbg == NULL) + browser->dbg = debuginfo__new(dso__long_name(map__dso(ms->map))); + annotate_browser__show(&browser->b, title, help); + continue; case K_LEFT: case '<': case '>': @@ -1133,8 +1141,7 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms, ret = annotate_browser__run(&browser, evsel, hbt); - if (annotate_opts.code_with_type) - debuginfo__delete(browser.dbg); + debuginfo__delete(browser.dbg); if (not_annotated && !notes->src->tried_source) annotated_source__purge(notes->src); From 644bbe59af3d04a0d3b78e8048a35ba68c0dbafd Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:32 -0700 Subject: [PATCH 0645/2711] perf annotate: Show warning when debuginfo is not available When user requests data-type annotation but no DWARF info is available, show a warning message about it. Warning: DWARF debuginfo not found. Data-type in this DSO will not be displayed. Please make sure to have debug information. Press any key... Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-10-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 17 +++++++++++++++++ tools/perf/util/dso.h | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index dfe869c20e35..e3e7004f3225 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -812,6 +812,20 @@ static int annotate__scnprintf_title(struct hists *hists, char *bf, size_t size) return printed; } +static void annotate_browser__debuginfo_warning(struct annotate_browser *browser) +{ + struct map_symbol *ms = browser->b.priv; + struct dso *dso = map__dso(ms->map); + + if (browser->dbg == NULL && annotate_opts.code_with_type && + !dso__debuginfo_warned(dso)) { + ui__warning("DWARF debuginfo not found.\n\n" + "Data-type in this DSO will not be displayed.\n" + "Please make sure to have debug information."); + dso__set_debuginfo_warned(dso); + } +} + static int annotate_browser__run(struct annotate_browser *browser, struct evsel *evsel, struct hist_browser_timer *hbt) @@ -842,6 +856,8 @@ static int annotate_browser__run(struct annotate_browser *browser, annotation_br_cntr_abbr_list(&br_cntr_text, evsel, false); + annotate_browser__debuginfo_warning(browser); + while (1) { key = ui_browser__run(&browser->b, delay_secs); @@ -1036,6 +1052,7 @@ show_sup_ins: if (browser->dbg == NULL) browser->dbg = debuginfo__new(dso__long_name(map__dso(ms->map))); annotate_browser__show(&browser->b, title, help); + annotate_browser__debuginfo_warning(browser); continue; case K_LEFT: case '<': diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 3457d713d3c5..7df1673f08d3 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -299,6 +299,7 @@ DECLARE_RC_STRUCT(dso) { u8 hit:1; u8 annotate_warned:1; u8 auxtrace_warned:1; + u8 debuginfo_warned:1; u8 short_name_allocated:1; u8 long_name_allocated:1; u8 is_64_bit:1; @@ -362,6 +363,16 @@ static inline void dso__set_annotate_warned(struct dso *dso) RC_CHK_ACCESS(dso)->annotate_warned = 1; } +static inline bool dso__debuginfo_warned(const struct dso *dso) +{ + return RC_CHK_ACCESS(dso)->debuginfo_warned; +} + +static inline void dso__set_debuginfo_warned(struct dso *dso) +{ + RC_CHK_ACCESS(dso)->debuginfo_warned = 1; +} + static inline bool dso__auxtrace_warned(const struct dso *dso) { return RC_CHK_ACCESS(dso)->auxtrace_warned; From d69f56545ed53342204136b66b4d10ba80103d14 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:33 -0700 Subject: [PATCH 0646/2711] perf annotate: Hide data-type for stack operation and canary It's mostly unnecessary to print when it has no actual type information like in the stack operations and canary. Let's have them if -v option is given. Before: $ perf annotate --code-with-type ... : 0 0xd640 <_dl_relocate_object>: 0.00 : 0: endbr64 0.00 : 4: pushq %rbp # data-type: (stack operation) 0.00 : 5: movq %rsp, %rbp 0.00 : 8: pushq %r15 # data-type: (stack operation) 0.00 : a: pushq %r14 # data-type: (stack operation) 0.00 : c: pushq %r13 # data-type: (stack operation) 0.00 : e: pushq %r12 # data-type: (stack operation) 0.00 : 10: pushq %rbx # data-type: (stack operation) 0.00 : 11: subq $0xf8, %rsp ... 0.00 : d4: testl %eax, %eax 0.00 : d6: jne 0xf424 0.00 : dc: movq 0xf0(%r14), %rbx # data-type: struct link_map +0xf0 0.00 : e3: testq %rbx, %rbx 0.00 : e6: jne 0xf2dd 0.00 : ec: cmpq $0, 0xf8(%r14) # data-type: struct link_map +0xf8 ... After: : 0 0xd640 <_dl_relocate_object>: 0.00 : 0: endbr64 0.00 : 4: pushq %rbp 0.00 : 5: movq %rsp, %rbp 0.00 : 8: pushq %r15 0.00 : a: pushq %r14 0.00 : c: pushq %r13 0.00 : e: pushq %r12 0.00 : 10: pushq %rbx 0.00 : 11: subq $0xf8, %rsp ... 0.00 : d4: testl %eax, %eax 0.00 : d6: jne 0xf424 0.00 : dc: movq 0xf0(%r14), %rbx # data-type: struct link_map +0xf0 0.00 : e3: testq %rbx, %rbx 0.00 : e6: jne 0xf2dd 0.00 : ec: cmpq $0, 0xf8(%r14) # data-type: struct link_map +0xf8 ... Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-11-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 99e976d25449..ea68b32da7ce 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -765,6 +765,17 @@ __hist_entry__get_data_type(struct hist_entry *he, struct arch *arch, struct debuginfo *dbg, struct disasm_line *dl, int *type_offset); +static bool needs_type_info(struct annotated_data_type *data_type) +{ + if (data_type == NULL || data_type == NO_TYPE) + return false; + + if (verbose) + return true; + + return (data_type != &stackop_type) && (data_type != &canary_type); +} + static int annotation_line__print(struct annotation_line *al, struct annotation_print_data *apd, struct annotation_options *opts, int printed, @@ -844,7 +855,7 @@ annotation_line__print(struct annotation_line *al, struct annotation_print_data data_type = __hist_entry__get_data_type(apd->he, apd->arch, apd->dbg, dl, &offset); - if (data_type && data_type != NO_TYPE) { + if (needs_type_info(data_type)) { char buf[4096]; printf("\t\t# data-type: %s", @@ -1958,7 +1969,7 @@ static int disasm_line__snprint_type_info(struct disasm_line *dl, return 1; data_type = __hist_entry__get_data_type(apd->he, apd->arch, apd->dbg, dl, &offset); - if (data_type == NULL || data_type == NO_TYPE) + if (!needs_type_info(data_type)) return 1; printed = scnprintf(buf, len, "\t\t# data-type: %s", data_type->self.type_name); From 53a61a6ca279165dd51f4e3bb5f8b11544915138 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:34 -0700 Subject: [PATCH 0647/2711] perf annotate: Add dso__debuginfo() helper It'd be great if it can get the correct debug information using DSO build-Id not just the path name. Instead of adding new callsites of debuginfo__new(), let's add dso__debuginfo() which can hide the access using the pathname and help the future conversion. Suggested-by: Ian Rogers Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-12-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 4 ++-- tools/perf/util/annotate.c | 6 +++--- tools/perf/util/dso.h | 10 ++++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index e3e7004f3225..9aa3c1ba22f5 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -1050,7 +1050,7 @@ show_sup_ins: case 'T': annotate_opts.code_with_type ^= 1; if (browser->dbg == NULL) - browser->dbg = debuginfo__new(dso__long_name(map__dso(ms->map))); + browser->dbg = dso__debuginfo(map__dso(ms->map)); annotate_browser__show(&browser->b, title, help); annotate_browser__debuginfo_warning(browser); continue; @@ -1146,7 +1146,7 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms, ui_helpline__push("Press ESC to exit"); if (annotate_opts.code_with_type) - browser.dbg = debuginfo__new(dso__long_name(dso)); + browser.dbg = dso__debuginfo(dso); browser.b.width = notes->src->widths.max_line_len; browser.b.nr_entries = notes->src->nr_entries; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ea68b32da7ce..bea3457a0063 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1270,7 +1270,7 @@ int hist_entry__annotate_printf(struct hist_entry *he, struct evsel *evsel) apd.addr_fmt_width = annotated_source__addr_fmt_width(¬es->src->source, notes->src->start); evsel__get_arch(evsel, &apd.arch); - apd.dbg = debuginfo__new(filename); + apd.dbg = dso__debuginfo(dso); list_for_each_entry(pos, ¬es->src->source, node) { int err; @@ -1375,7 +1375,7 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, if (annotate_opts.code_with_type) { evsel__get_arch(apd->evsel, &apd->arch); - apd->dbg = debuginfo__new(dso__long_name(map__dso(apd->he->ms.map))); + apd->dbg = dso__debuginfo(map__dso(apd->he->ms.map)); } list_for_each_entry(al, ¬es->src->source, node) { @@ -2882,7 +2882,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) di_cache.dso = dso__get(map__dso(ms->map)); debuginfo__delete(di_cache.dbg); - di_cache.dbg = debuginfo__new(dso__long_name(di_cache.dso)); + di_cache.dbg = dso__debuginfo(di_cache.dso); } if (di_cache.dbg == NULL) { diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 7df1673f08d3..fd8e95de77f7 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -10,6 +10,7 @@ #include #include #include "build-id.h" +#include "debuginfo.h" #include "mutex.h" #include @@ -914,4 +915,13 @@ u64 dso__findnew_global_type(struct dso *dso, u64 addr, u64 offset); bool perf_pid_map_tid(const char *dso_name, int *tid); bool is_perf_pid_map_name(const char *dso_name); +/* + * In the future, we may get debuginfo using build-ID (w/o path). + * Add this helper is for the smooth conversion. + */ +static inline struct debuginfo *dso__debuginfo(struct dso *dso) +{ + return debuginfo__new(dso__long_name(dso)); +} + #endif /* __PERF_DSO */ From f2543da14dc2b9bee337f1f9466ab3fedae1cd84 Mon Sep 17 00:00:00 2001 From: Erick Karanja Date: Thu, 28 Aug 2025 12:35:55 +0300 Subject: [PATCH 0648/2711] PCI: switchtec: Replace manual locks with guard Replace lock/unlock pairs with guards to simplify and tidy up the code. Generated-by: Coccinelle SmPL Signed-off-by: Erick Karanja Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe Link: https://patch.msgid.link/20250828093556.810911-1-karanja99erick@gmail.com --- drivers/pci/switch/switchtec.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index b14dfab04d84..5ff84fb8fb0f 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -269,10 +269,9 @@ static void mrpc_event_work(struct work_struct *work) dev_dbg(&stdev->dev, "%s\n", __func__); - mutex_lock(&stdev->mrpc_mutex); + guard(mutex)(&stdev->mrpc_mutex); cancel_delayed_work(&stdev->mrpc_timeout); mrpc_complete_cmd(stdev); - mutex_unlock(&stdev->mrpc_mutex); } static void mrpc_error_complete_cmd(struct switchtec_dev *stdev) @@ -1322,19 +1321,19 @@ static void stdev_kill(struct switchtec_dev *stdev) cancel_delayed_work_sync(&stdev->mrpc_timeout); /* Mark the hardware as unavailable and complete all completions */ - mutex_lock(&stdev->mrpc_mutex); - stdev->alive = false; + scoped_guard (mutex, &stdev->mrpc_mutex) { + stdev->alive = false; + + /* Wake up and kill any users waiting on an MRPC request */ + list_for_each_entry_safe(stuser, tmpuser, &stdev->mrpc_queue, list) { + stuser->cmd_done = true; + wake_up_interruptible(&stuser->cmd_comp); + list_del_init(&stuser->list); + stuser_put(stuser); + } - /* Wake up and kill any users waiting on an MRPC request */ - list_for_each_entry_safe(stuser, tmpuser, &stdev->mrpc_queue, list) { - stuser->cmd_done = true; - wake_up_interruptible(&stuser->cmd_comp); - list_del_init(&stuser->list); - stuser_put(stuser); } - mutex_unlock(&stdev->mrpc_mutex); - /* Wake up any users waiting on event_wq */ wake_up_interruptible(&stdev->event_wq); } From 57a48a2619c5f99d48748f9c34db510efe5ee7c9 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 28 Jul 2025 10:36:56 +0800 Subject: [PATCH 0649/2711] dt-bindings: PCI: ti,am65: Extend for use with PVU The Peripheral Virtualization Unit (PVU) on the AM65 SoC is capable of restricting DMA from PCIe devices to specific regions of host memory. Add the optional property "memory-regions" to point to such regions of memory when PVU is used. Since the PVU deals with system physical addresses, utilizing the PVU with PCIe devices also requires setting up the VMAP registers to map the Requester ID of the PCIe device to the CBA Virtual ID, which in turn is mapped to the system physical address. Hence, describe the VMAP registers which are optional unless the PVU shall be used for PCIe. Signed-off-by: Jan Kiszka Signed-off-by: Li Hua Qian [mani: Expanded PVU in description] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250728023701.116963-3-huaqian.li@siemens.com --- .../bindings/pci/ti,am65-pci-host.yaml | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/ti,am65-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,am65-pci-host.yaml index 0a9d10532cc8..98f6c7f1b1a6 100644 --- a/Documentation/devicetree/bindings/pci/ti,am65-pci-host.yaml +++ b/Documentation/devicetree/bindings/pci/ti,am65-pci-host.yaml @@ -20,14 +20,18 @@ properties: - ti,keystone-pcie reg: - maxItems: 4 + minItems: 4 + maxItems: 6 reg-names: + minItems: 4 items: - const: app - const: dbics - const: config - const: atu + - const: vmap_lp + - const: vmap_hp interrupts: maxItems: 1 @@ -69,6 +73,15 @@ properties: items: pattern: '^pcie-phy[0-1]$' + memory-region: + maxItems: 1 + description: | + phandle to a restricted DMA pool to be used for all devices behind + this controller. The regions should be defined according to + reserved-memory/shared-dma-pool.yaml. + Note that enforcement via the PVU will only be available to + ti,am654-pcie-rc devices. + required: - compatible - reg @@ -89,6 +102,13 @@ then: - power-domains - msi-map - num-viewport +else: + properties: + reg: + maxItems: 4 + + reg-names: + maxItems: 4 unevaluatedProperties: false @@ -104,8 +124,10 @@ examples: reg = <0x5500000 0x1000>, <0x5501000 0x1000>, <0x10000000 0x2000>, - <0x5506000 0x1000>; - reg-names = "app", "dbics", "config", "atu"; + <0x5506000 0x1000>, + <0x2900000 0x1000>, + <0x2908000 0x1000>; + reg-names = "app", "dbics", "config", "atu", "vmap_lp", "vmap_hp"; power-domains = <&k3_pds 120 TI_SCI_PD_EXCLUSIVE>; #address-cells = <3>; #size-cells = <2>; From 03e073bc4dbc3d64ce0beb21fbe793ae7787e062 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Thu, 28 Aug 2025 18:58:14 +0000 Subject: [PATCH 0650/2711] vfio: selftests: Fix .gitignore for already tracked files Fix the rules in tools/testing/selftests/vfio/.gitignore to not ignore some already tracked files (.gitignore, Makefile, lib/libvfio.mk). This change should be a no-op, since these files are already tracked by git and thus git will not ignore updates to them even though they match the ignore rules in the VFIO selftests .gitignore file. However, they do generate warnings with W=1, as reported by the kernel test robot. $ KBUILD_EXTRA_WARN=1 scripts/misc-check tools/testing/selftests/vfio/.gitignore: warning: ignored by one of the .gitignore files tools/testing/selftests/vfio/Makefile: warning: ignored by one of the .gitignore files tools/testing/selftests/vfio/lib/libvfio.mk: warning: ignored by one of the .gitignore files Fix this by explicitly un-ignoring the tracked files. Fixes: 292e9ee22b0a ("selftests: Create tools/testing/selftests/vfio") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508280918.rFRyiLEU-lkp@intel.com/ Signed-off-by: David Matlack Link: https://lore.kernel.org/r/20250828185815.382215-1-dmatlack@google.com Signed-off-by: Alex Williamson --- tools/testing/selftests/vfio/.gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/testing/selftests/vfio/.gitignore b/tools/testing/selftests/vfio/.gitignore index 6d9381d60172..7fadc19d3bca 100644 --- a/tools/testing/selftests/vfio/.gitignore +++ b/tools/testing/selftests/vfio/.gitignore @@ -5,3 +5,6 @@ !*.h !*.S !*.sh +!*.mk +!.gitignore +!Makefile From e27f158cf1e98d9a541282ef4b36dfa4427bf361 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:14:57 +0200 Subject: [PATCH 0651/2711] peci: remove unneeded 'fast_io' parameter in regmap_config When using MMIO with regmap, fast_io is implied. No need to set it again. Signed-off-by: Wolfram Sang Reviewed-by: Paul Menzel Link: https://lore.kernel.org/r/20250813161517.4746-12-wsa+renesas@sang-engineering.com Signed-off-by: Iwona Winiarska --- drivers/peci/controller/peci-npcm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/peci/controller/peci-npcm.c b/drivers/peci/controller/peci-npcm.c index c77591ca583d..931868991241 100644 --- a/drivers/peci/controller/peci-npcm.c +++ b/drivers/peci/controller/peci-npcm.c @@ -221,7 +221,6 @@ static const struct regmap_config npcm_peci_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = NPCM_PECI_MAX_REG, - .fast_io = true, }; static const struct peci_controller_ops npcm_ops = { From 12d7b0f093d39daccb2a4eab0ebc0b3abb08c7f8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 29 Jul 2025 12:21:41 +0100 Subject: [PATCH 0652/2711] mips/octeon/smp: Remove space before newline There is an extraneous space before a newline in a pr_info message. Remove it. Signed-off-by: Colin Ian King Signed-off-by: Thomas Bogendoerfer --- arch/mips/cavium-octeon/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index 08ea2cde1eb5..054e331b3202 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -334,7 +334,7 @@ static void octeon_cpu_die(unsigned int cpu) new_mask = *p; } - pr_info("Reset core %d. Available Coremask = 0x%x \n", coreid, new_mask); + pr_info("Reset core %d. Available Coremask = 0x%x\n", coreid, new_mask); mb(); cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid); cvmx_write_csr(CVMX_CIU_PP_RST, 0); From 2433961962be8b8ff32058763339b818128e8ff0 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 24 Aug 2025 21:52:37 +0200 Subject: [PATCH 0653/2711] remoteproc: k3: Correctly release some resources allocated in k3_rproc_request_mbox() If an error occurs after a successful k3_rproc_request_mbox() call, mbox_free_channel() should be called to avoid a leak. Such a call is missing in the error handling path of k3_dsp_rproc_probe(). It is also missing both in the error handling path of k3_m4_rproc_probe() and in the (in-existent) corresponding remove function. Switch to managed resources to avoid these leaks and simplify the code. Remove the now unneeded mbox_free_channel(). Signed-off-by: Christophe JAILLET Reviewed-by: Beleswar Padhi Tested-by: Beleswar Padhi Link: https://lore.kernel.org/r/df853ede72e9972c464415990b196289680e6acb.1756065142.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mathieu Poirier --- drivers/remoteproc/ti_k3_common.c | 12 ++++++++++++ drivers/remoteproc/ti_k3_dsp_remoteproc.c | 2 -- drivers/remoteproc/ti_k3_r5_remoteproc.c | 2 -- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/remoteproc/ti_k3_common.c b/drivers/remoteproc/ti_k3_common.c index 8266e11914af..56b71652e449 100644 --- a/drivers/remoteproc/ti_k3_common.c +++ b/drivers/remoteproc/ti_k3_common.c @@ -155,11 +155,19 @@ int k3_rproc_release(struct k3_rproc *kproc) } EXPORT_SYMBOL_GPL(k3_rproc_release); +static void k3_rproc_free_channel(void *data) +{ + struct k3_rproc *kproc = data; + + mbox_free_channel(kproc->mbox); +} + int k3_rproc_request_mbox(struct rproc *rproc) { struct k3_rproc *kproc = rproc->priv; struct mbox_client *client = &kproc->client; struct device *dev = kproc->dev; + int ret; client->dev = dev; client->tx_done = NULL; @@ -172,6 +180,10 @@ int k3_rproc_request_mbox(struct rproc *rproc) return dev_err_probe(dev, PTR_ERR(kproc->mbox), "mbox_request_channel failed\n"); + ret = devm_add_action_or_reset(dev, k3_rproc_free_channel, kproc); + if (ret) + return ret; + return 0; } EXPORT_SYMBOL_GPL(k3_rproc_request_mbox); diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c index 7a72933bd403..d6ceea6dc920 100644 --- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c +++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c @@ -175,8 +175,6 @@ static void k3_dsp_rproc_remove(struct platform_device *pdev) if (ret) dev_err(dev, "failed to detach proc (%pe)\n", ERR_PTR(ret)); } - - mbox_free_channel(kproc->mbox); } static const struct k3_rproc_mem_data c66_mems[] = { diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index ca5ff280d2dc..04f23295ffc1 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -1206,8 +1206,6 @@ static void k3_r5_cluster_rproc_exit(void *data) return; } } - - mbox_free_channel(kproc->mbox); } } From 214ae22e6d4f774f053a8f7d32bd6a9874447b06 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 27 Aug 2025 13:13:52 +0300 Subject: [PATCH 0654/2711] rpmsg: core: Drop dev_pm_domain_detach() call Starting with commit f99508074e78 ("PM: domains: Detach on device_unbind_cleanup()"), there is no longer a need to call dev_pm_domain_detach() in the bus remove function. The device_unbind_cleanup() function now handles this to avoid invoking devres cleanup handlers while the PM domain is powered off, which could otherwise lead to failures as described in the above-mentioned commit. Drop the explicit dev_pm_domain_detach() call and rely instead on the flags passed to dev_pm_domain_attach() to power off the domain. Signed-off-by: Claudiu Beznea Reviewed-by: Ulf Hansson Link: https://lore.kernel.org/r/20250827101352.927542-1-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Mathieu Poirier --- drivers/rpmsg/rpmsg_core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index bece5e635ee9..5d661681a9b6 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -479,7 +479,8 @@ static int rpmsg_dev_probe(struct device *dev) struct rpmsg_endpoint *ept = NULL; int err; - err = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON); + err = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON | + PD_FLAG_DETACH_POWER_OFF); if (err) goto out; @@ -538,8 +539,6 @@ static void rpmsg_dev_remove(struct device *dev) if (rpdrv->remove) rpdrv->remove(rpdev); - dev_pm_domain_detach(dev, true); - if (rpdev->ept) rpmsg_destroy_ept(rpdev->ept); } From 093458c58f830d0a713fab0de037df5f0ce24fef Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 28 Aug 2025 14:36:24 -0600 Subject: [PATCH 0655/2711] docs: proc.rst: Fix VFIO Device title formatting Title underline is one character too short. Cc: Alex Mastro Cc: Jonathan Corbet Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/all/20250828123035.2f0c74e7@canb.auug.org.au Fixes: 1e736f148956 ("vfio/pci: print vfio-device syspath to fdinfo") Reviewed-by: Bagas Sanjaya Link: https://lore.kernel.org/r/20250828203629.283418-1-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- Documentation/filesystems/proc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index ed8d23b677ca..ff09f668cdeb 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -2167,7 +2167,7 @@ where 'size' is the size of the DMA buffer in bytes. 'count' is the file count o the DMA buffer file. 'exp_name' is the name of the DMA buffer exporter. VFIO Device files -~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~ :: From 05e75ac35ee9e38f96bbfebf1830ec2cace2e7f8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Aug 2025 15:54:29 +0200 Subject: [PATCH 0656/2711] efi: Explain OVMF acronym in OVMF_DEBUG_LOG help text People not very intimate with EFI may not know the meaning of the OVMF acronym. Write it in full, to help users with making good decisions when configuring their kernels. Fixes: f393a761763c5427 ("efi: add ovmf debug log driver") Signed-off-by: Geert Uytterhoeven Reviewed-by: Richard Lyu Acked-by: Gerd Hoffmann Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/Kconfig | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index d528c94c5859..29e0729299f5 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -267,9 +267,10 @@ config OVMF_DEBUG_LOG bool "Expose OVMF firmware debug log via sysfs" depends on EFI help - Recent OVMF versions (edk2-stable202508 + newer) can write - their debug log to a memory buffer. This driver exposes the - log content via sysfs (/sys/firmware/efi/ovmf_debug_log). + Recent versions of the Open Virtual Machine Firmware + (edk2-stable202508 + newer) can write their debug log to a memory + buffer. This driver exposes the log content via sysfs + (/sys/firmware/efi/ovmf_debug_log). config UNACCEPTED_MEMORY bool From 21050b589fb00997256c4ecaeee0cb0e46f30891 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 29 Jul 2025 13:52:13 -0700 Subject: [PATCH 0657/2711] MIPS: BMIPS: Properly define memory controller compatible With the DT binding updated with 501be7cecec9 ("dt-bindings: memory-controller: Define fallback compatible") we need to define a proper compatible string for the memory controller node(s). Signed-off-by: Florian Fainelli Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/brcm/bcm7346.dtsi | 3 ++- arch/mips/boot/dts/brcm/bcm7360.dtsi | 3 ++- arch/mips/boot/dts/brcm/bcm7362.dtsi | 3 ++- arch/mips/boot/dts/brcm/bcm7425.dtsi | 6 ++++-- arch/mips/boot/dts/brcm/bcm7435.dtsi | 6 ++++-- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/arch/mips/boot/dts/brcm/bcm7346.dtsi b/arch/mips/boot/dts/brcm/bcm7346.dtsi index 2afa0dada575..9d6f97e02ff9 100644 --- a/arch/mips/boot/dts/brcm/bcm7346.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7346.dtsi @@ -531,7 +531,8 @@ }; memc-ddr@2000 { - compatible = "brcm,brcmstb-memc-ddr"; + compatible = "brcm,brcmstb-memc-ddr-rev-a.0.0", + "brcm,brcmstb-memc-ddr"; reg = <0x2000 0x300>; }; diff --git a/arch/mips/boot/dts/brcm/bcm7360.dtsi b/arch/mips/boot/dts/brcm/bcm7360.dtsi index a57cacea91cf..a7f60f059e50 100644 --- a/arch/mips/boot/dts/brcm/bcm7360.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7360.dtsi @@ -450,7 +450,8 @@ }; memc-ddr@2000 { - compatible = "brcm,brcmstb-memc-ddr"; + compatible = "brcm,brcmstb-memc-ddr-rev-a.0.0", + "brcm,brcmstb-memc-ddr"; reg = <0x2000 0x300>; }; diff --git a/arch/mips/boot/dts/brcm/bcm7362.dtsi b/arch/mips/boot/dts/brcm/bcm7362.dtsi index 728b9e9f84b8..2d483cbf254f 100644 --- a/arch/mips/boot/dts/brcm/bcm7362.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7362.dtsi @@ -446,7 +446,8 @@ }; memc-ddr@2000 { - compatible = "brcm,brcmstb-memc-ddr"; + compatible = "brcm,brcmstb-memc-ddr-rev-a.0.0", + "brcm,brcmstb-memc-ddr"; reg = <0x2000 0x300>; }; diff --git a/arch/mips/boot/dts/brcm/bcm7425.dtsi b/arch/mips/boot/dts/brcm/bcm7425.dtsi index 62588c53d356..c3bb020ff2b5 100644 --- a/arch/mips/boot/dts/brcm/bcm7425.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7425.dtsi @@ -542,7 +542,8 @@ }; memc-ddr@2000 { - compatible = "brcm,brcmstb-memc-ddr"; + compatible = "brcm,brcmstb-memc-ddr-rev-a.0.0", + "brcm,brcmstb-memc-ddr"; reg = <0x2000 0x300>; }; @@ -569,7 +570,8 @@ }; memc-ddr@2000 { - compatible = "brcm,brcmstb-memc-ddr"; + compatible = "brcm,brcmstb-memc-ddr-rev-a.0.0", + "brcm,brcmstb-memc-ddr"; reg = <0x2000 0x300>; }; diff --git a/arch/mips/boot/dts/brcm/bcm7435.dtsi b/arch/mips/boot/dts/brcm/bcm7435.dtsi index cfdf9804e126..60cfa4074cce 100644 --- a/arch/mips/boot/dts/brcm/bcm7435.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7435.dtsi @@ -558,7 +558,8 @@ }; memc-ddr@2000 { - compatible = "brcm,brcmstb-memc-ddr"; + compatible = "brcm,brcmstb-memc-ddr-rev-a.0.0", + "brcm,brcmstb-memc-ddr"; reg = <0x2000 0x300>; }; @@ -585,7 +586,8 @@ }; memc-ddr@2000 { - compatible = "brcm,brcmstb-memc-ddr"; + compatible = "brcm,brcmstb-memc-ddr-rev-a.0.0", + "brcm,brcmstb-memc-ddr"; reg = <0x2000 0x300>; }; From 157f9533f9ffb5d9544515dcfe54e0901d9aa615 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 4 Aug 2025 08:56:29 +0200 Subject: [PATCH 0658/2711] mips: Replace __ASSEMBLY__ with __ASSEMBLER__ in the mips headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the GCC and Clang compilers already define __ASSEMBLER__ automatically when compiling assembler code, __ASSEMBLY__ is a macro that only gets defined by the Makefiles in the kernel. Defining such a macro was necessary in the early days of the kernel, since GCC only started providing __ASSEMBLER__ since version 3.0 in 2000 (see https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=f8f769ea4e69 ). However, having two macros can be very confusing nowadays for the developers when switching between userspace and kernelspace coding, or when dealing with uapi headers that should use __ASSEMBLER__ instead. So let's now standardize on the __ASSEMBLER__ macro that is provided by the compilers. This is almost a completely mechanical patch (done with a simple "sed -i" statement), with just one comment tweaked manually in arch/mips/include/asm/cpu.h (that was missing some underscores). Cc: Thomas Bogendoerfer Cc: linux-mips@vger.kernel.org Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Maciej W. Rozycki Signed-off-by: Thomas Huth Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/addrspace.h | 4 +-- arch/mips/include/asm/asm-eva.h | 6 ++-- arch/mips/include/asm/asm.h | 8 ++--- arch/mips/include/asm/bmips.h | 4 +-- arch/mips/include/asm/cpu.h | 4 +-- arch/mips/include/asm/dec/ecc.h | 2 +- arch/mips/include/asm/dec/interrupts.h | 4 +-- arch/mips/include/asm/dec/kn01.h | 2 +- arch/mips/include/asm/dec/kn02.h | 2 +- arch/mips/include/asm/dec/kn02xa.h | 2 +- arch/mips/include/asm/eva.h | 4 +-- arch/mips/include/asm/ftrace.h | 8 ++--- arch/mips/include/asm/hazards.h | 4 +-- arch/mips/include/asm/irqflags.h | 4 +-- arch/mips/include/asm/jazz.h | 16 ++++----- arch/mips/include/asm/jump_label.h | 4 +-- arch/mips/include/asm/linkage.h | 2 +- arch/mips/include/asm/mach-generic/spaces.h | 4 +-- arch/mips/include/asm/mips-boards/bonito64.h | 4 +-- arch/mips/include/asm/mipsmtregs.h | 6 ++-- arch/mips/include/asm/mipsregs.h | 6 ++-- arch/mips/include/asm/msa.h | 4 +-- arch/mips/include/asm/pci/bridge.h | 4 +-- arch/mips/include/asm/pm.h | 6 ++-- arch/mips/include/asm/prefetch.h | 2 +- arch/mips/include/asm/regdef.h | 4 +-- arch/mips/include/asm/sibyte/board.h | 4 +-- arch/mips/include/asm/sibyte/sb1250.h | 2 +- arch/mips/include/asm/sibyte/sb1250_defs.h | 6 ++-- arch/mips/include/asm/smp-cps.h | 6 ++-- arch/mips/include/asm/sn/addrs.h | 18 +++++----- arch/mips/include/asm/sn/gda.h | 4 +-- arch/mips/include/asm/sn/kldir.h | 4 +-- arch/mips/include/asm/sn/klkernvars.h | 4 +-- arch/mips/include/asm/sn/launch.h | 4 +-- arch/mips/include/asm/sn/nmi.h | 8 ++--- arch/mips/include/asm/sn/sn0/addrs.h | 14 ++++---- arch/mips/include/asm/sn/sn0/hub.h | 2 +- arch/mips/include/asm/sn/sn0/hubio.h | 36 ++++++++++---------- arch/mips/include/asm/sn/sn0/hubmd.h | 4 +-- arch/mips/include/asm/sn/sn0/hubni.h | 6 ++-- arch/mips/include/asm/sn/sn0/hubpi.h | 4 +-- arch/mips/include/asm/sn/types.h | 2 +- arch/mips/include/asm/sync.h | 2 +- arch/mips/include/asm/thread_info.h | 4 +-- arch/mips/include/asm/unistd.h | 4 +-- arch/mips/include/asm/vdso/gettimeofday.h | 4 +-- arch/mips/include/asm/vdso/processor.h | 4 +-- arch/mips/include/asm/vdso/vdso.h | 4 +-- arch/mips/include/asm/vdso/vsyscall.h | 4 +-- arch/mips/include/asm/xtalk/xtalk.h | 4 +-- arch/mips/include/asm/xtalk/xwidget.h | 4 +-- drivers/soc/bcm/brcmstb/pm/pm.h | 2 +- 53 files changed, 142 insertions(+), 142 deletions(-) diff --git a/arch/mips/include/asm/addrspace.h b/arch/mips/include/asm/addrspace.h index 7e9ef01cb182..e2354e9b0ee2 100644 --- a/arch/mips/include/asm/addrspace.h +++ b/arch/mips/include/asm/addrspace.h @@ -15,7 +15,7 @@ /* * Configure language */ -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #define _ATYPE_ #define _ATYPE32_ #define _ATYPE64_ @@ -34,7 +34,7 @@ /* * 32-bit MIPS address spaces */ -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #define _ACAST32_ #define _ACAST64_ #else diff --git a/arch/mips/include/asm/asm-eva.h b/arch/mips/include/asm/asm-eva.h index e327ebc76753..220431d00ee9 100644 --- a/arch/mips/include/asm/asm-eva.h +++ b/arch/mips/include/asm/asm-eva.h @@ -10,7 +10,7 @@ #ifndef __ASM_ASM_EVA_H #define __ASM_ASM_EVA_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* Kernel variants */ @@ -99,7 +99,7 @@ #endif /* CONFIG_EVA */ -#else /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ #define kernel_cache(op, base) cache op, base #define kernel_pref(hint, base) pref hint, base @@ -185,6 +185,6 @@ #endif /* CONFIG_EVA */ -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_ASM_EVA_H */ diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h index 87ff609b53fe..0ed19ffed076 100644 --- a/arch/mips/include/asm/asm.h +++ b/arch/mips/include/asm/asm.h @@ -37,7 +37,7 @@ #define CFI_SECTIONS #endif -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ /* * LEAF - declare leaf routine */ @@ -123,7 +123,7 @@ symbol = value #define ASM_PRINT(string) #endif -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ /* * Stack alignment @@ -228,7 +228,7 @@ symbol = value #define LONG_INS ins #define LONG_EXT ext -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #define LONG .word #endif #define LONGSIZE 4 @@ -257,7 +257,7 @@ symbol = value #define LONG_INS dins #define LONG_EXT dext -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #define LONG .dword #endif #define LONGSIZE 8 diff --git a/arch/mips/include/asm/bmips.h b/arch/mips/include/asm/bmips.h index 3a1cdfddb987..0eee81be9e2b 100644 --- a/arch/mips/include/asm/bmips.h +++ b/arch/mips/include/asm/bmips.h @@ -42,7 +42,7 @@ #define ZSCM_REG_BASE 0x97000000 -#if !defined(__ASSEMBLY__) +#if !defined(__ASSEMBLER__) #include #include @@ -124,6 +124,6 @@ static inline void bmips_write_zscm_reg(unsigned int offset, unsigned long data) barrier(); } -#endif /* !defined(__ASSEMBLY__) */ +#endif /* !defined(__ASSEMBLER__) */ #endif /* _ASM_BMIPS_H */ diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index ecb9854cb432..32cf5496006e 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -288,7 +288,7 @@ #define FPIR_IMP_NONE 0x0000 -#if !defined(__ASSEMBLY__) +#if !defined(__ASSEMBLER__) enum cpu_type_enum { CPU_UNKNOWN, @@ -329,7 +329,7 @@ enum cpu_type_enum { CPU_LAST }; -#endif /* !__ASSEMBLY */ +#endif /* !__ASSEMBLER__ */ /* * ISA Level encodings diff --git a/arch/mips/include/asm/dec/ecc.h b/arch/mips/include/asm/dec/ecc.h index c3a3f71f1a54..dbc39643c31c 100644 --- a/arch/mips/include/asm/dec/ecc.h +++ b/arch/mips/include/asm/dec/ecc.h @@ -37,7 +37,7 @@ #define KN0X_ESR_SYNLO (0x7f<<0) /* syndrome from ECC logic */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include diff --git a/arch/mips/include/asm/dec/interrupts.h b/arch/mips/include/asm/dec/interrupts.h index e10d341067c8..c1cd36c04b6c 100644 --- a/arch/mips/include/asm/dec/interrupts.h +++ b/arch/mips/include/asm/dec/interrupts.h @@ -95,7 +95,7 @@ #define DEC_CPU_IRQ_ALL (0xff << CAUSEB_IP) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * Interrupt table structures to hide differences between systems. @@ -121,6 +121,6 @@ extern void cpu_all_int(void); extern void dec_intr_unimplemented(void); extern void asic_intr_unimplemented(void); -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/mips/include/asm/dec/kn01.h b/arch/mips/include/asm/dec/kn01.h index 88d9ffd74258..6c074b93a7db 100644 --- a/arch/mips/include/asm/dec/kn01.h +++ b/arch/mips/include/asm/dec/kn01.h @@ -71,7 +71,7 @@ #define KN01_CSR_LEDS (0xff<<0) /* ~diagnostic LEDs (w/o) */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include diff --git a/arch/mips/include/asm/dec/kn02.h b/arch/mips/include/asm/dec/kn02.h index 93430b5f4724..9fea17020079 100644 --- a/arch/mips/include/asm/dec/kn02.h +++ b/arch/mips/include/asm/dec/kn02.h @@ -80,7 +80,7 @@ #define KN02_IRQ_ALL 0xff -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include diff --git a/arch/mips/include/asm/dec/kn02xa.h b/arch/mips/include/asm/dec/kn02xa.h index b56b4577f6ef..3580d78b906f 100644 --- a/arch/mips/include/asm/dec/kn02xa.h +++ b/arch/mips/include/asm/dec/kn02xa.h @@ -70,7 +70,7 @@ #define KN02XA_EAR_RES_0 (0x3<<0) /* unused */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include diff --git a/arch/mips/include/asm/eva.h b/arch/mips/include/asm/eva.h index a3d1807f227c..c7b39f38634b 100644 --- a/arch/mips/include/asm/eva.h +++ b/arch/mips/include/asm/eva.h @@ -13,7 +13,7 @@ #include -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #ifdef CONFIG_EVA @@ -38,6 +38,6 @@ platform_eva_init #endif /* CONFIG_EVA */ -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h index b41fc1044668..7d557f03188f 100644 --- a/arch/mips/include/asm/ftrace.h +++ b/arch/mips/include/asm/ftrace.h @@ -15,7 +15,7 @@ #define MCOUNT_ADDR ((unsigned long)(_mcount)) #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ extern void _mcount(void); #define mcount _mcount @@ -89,11 +89,11 @@ struct dyn_arch_ftrace { void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra, unsigned long fp); -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* CONFIG_FUNCTION_TRACER */ #ifdef CONFIG_FTRACE_SYSCALLS -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * Some syscall entry functions on mips start with "__sys_" (fork and clone, * for instance). We should also match the sys_ variant with those. @@ -105,6 +105,6 @@ static inline bool arch_syscall_match_sym_name(const char *sym, return !strcmp(sym, name) || (!strncmp(sym, "__sys_", 6) && !strcmp(sym + 6, name + 4)); } -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* CONFIG_FTRACE_SYSCALLS */ #endif /* _ASM_MIPS_FTRACE_H */ diff --git a/arch/mips/include/asm/hazards.h b/arch/mips/include/asm/hazards.h index cb16be93b048..a084b3b3bc81 100644 --- a/arch/mips/include/asm/hazards.h +++ b/arch/mips/include/asm/hazards.h @@ -301,7 +301,7 @@ do { \ #endif -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #define _ssnop ___ssnop #define _ehb ___ehb @@ -417,6 +417,6 @@ do { \ */ extern void mips_ihb(void); -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* _ASM_HAZARDS_H */ diff --git a/arch/mips/include/asm/irqflags.h b/arch/mips/include/asm/irqflags.h index f5b8300f4573..70e5b05fd88b 100644 --- a/arch/mips/include/asm/irqflags.h +++ b/arch/mips/include/asm/irqflags.h @@ -11,7 +11,7 @@ #ifndef _ASM_IRQFLAGS_H #define _ASM_IRQFLAGS_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -142,7 +142,7 @@ static inline int arch_irqs_disabled(void) return arch_irqs_disabled_flags(arch_local_save_flags()); } -#endif /* #ifndef __ASSEMBLY__ */ +#endif /* #ifndef __ASSEMBLER__ */ /* * Do the CPU's IRQ-state tracing from assembly code. diff --git a/arch/mips/include/asm/jazz.h b/arch/mips/include/asm/jazz.h index a61970d01a81..9356e87dd64b 100644 --- a/arch/mips/include/asm/jazz.h +++ b/arch/mips/include/asm/jazz.h @@ -70,7 +70,7 @@ #define LED_E 0x9e #define LED_F 0x8e -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static __inline__ void pica_set_led(unsigned int bits) { @@ -79,7 +79,7 @@ static __inline__ void pica_set_led(unsigned int bits) *led_register = bits; } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * Base address of the Sonic Ethernet adapter in Jazz machines. @@ -100,7 +100,7 @@ static __inline__ void pica_set_led(unsigned int bits) #define JAZZ_KEYBOARD_DATA 0xe0005000 #define JAZZ_KEYBOARD_COMMAND 0xe0005001 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef struct { unsigned char data; @@ -121,7 +121,7 @@ typedef struct { */ #define keyboard_hardware jazz_keyboard_hardware -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * i8042 keyboard controller for most other Mips machines. @@ -154,7 +154,7 @@ typedef struct { /* * DRAM configuration register */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #ifdef __MIPSEL__ typedef struct { unsigned int bank2 : 3; @@ -174,7 +174,7 @@ typedef struct { unsigned int bank2 : 3; } dram_configuration; #endif -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define PICA_DRAM_CONFIG 0xe00fffe0 @@ -260,7 +260,7 @@ typedef struct { /* * Access the R4030 DMA and I/O Controller */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static inline void r4030_delay(void) { @@ -299,7 +299,7 @@ static inline void r4030_write_reg32(unsigned long addr, unsigned val) r4030_delay(); } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define JAZZ_FDC_BASE 0xe0003000 #define JAZZ_RTC_BASE 0xe0004000 diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h index ff5d388502d4..c1508f88e03e 100644 --- a/arch/mips/include/asm/jump_label.h +++ b/arch/mips/include/asm/jump_label.h @@ -10,7 +10,7 @@ #define arch_jump_label_transform_static arch_jump_label_transform -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -76,5 +76,5 @@ struct jump_entry { jump_label_t key; }; -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* _ASM_MIPS_JUMP_LABEL_H */ diff --git a/arch/mips/include/asm/linkage.h b/arch/mips/include/asm/linkage.h index 1829c2b6da6c..fd44ba754f1a 100644 --- a/arch/mips/include/asm/linkage.h +++ b/arch/mips/include/asm/linkage.h @@ -2,7 +2,7 @@ #ifndef __ASM_LINKAGE_H #define __ASM_LINKAGE_H -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #include #endif diff --git a/arch/mips/include/asm/mach-generic/spaces.h b/arch/mips/include/asm/mach-generic/spaces.h index f8783d339fb0..6332b6cbf7ee 100644 --- a/arch/mips/include/asm/mach-generic/spaces.h +++ b/arch/mips/include/asm/mach-generic/spaces.h @@ -21,13 +21,13 @@ /* * This gives the physical RAM offset. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ # if defined(CONFIG_MIPS_AUTO_PFN_OFFSET) # define PHYS_OFFSET ((unsigned long)PFN_PHYS(ARCH_PFN_OFFSET)) # elif !defined(PHYS_OFFSET) # define PHYS_OFFSET _AC(0, UL) # endif -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #ifdef CONFIG_32BIT #define CAC_BASE _AC(0x80000000, UL) diff --git a/arch/mips/include/asm/mips-boards/bonito64.h b/arch/mips/include/asm/mips-boards/bonito64.h index 31a31fe78d77..74c5fc0fc6c0 100644 --- a/arch/mips/include/asm/mips-boards/bonito64.h +++ b/arch/mips/include/asm/mips-boards/bonito64.h @@ -21,7 +21,7 @@ #ifndef _ASM_MIPS_BOARDS_BONITO64_H #define _ASM_MIPS_BOARDS_BONITO64_H -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ /* offsets from base register */ #define BONITO(x) (x) @@ -36,7 +36,7 @@ extern unsigned long _pcictrl_bonito_pcicfg; #define BONITO(x) *(volatile u32 *)(_pcictrl_bonito + (x)) -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #define BONITO_BOOT_BASE 0x1fc00000 diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h index b1ee3c48e84b..cab7582010e8 100644 --- a/arch/mips/include/asm/mipsmtregs.h +++ b/arch/mips/include/asm/mipsmtregs.h @@ -10,7 +10,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * C macros @@ -176,7 +176,7 @@ /* TCHalt */ #define TCHALT_H (_ULCAST_(1)) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static inline unsigned core_nvpes(void) { @@ -469,6 +469,6 @@ do { \ __BUILD_SET_C0(mvpcontrol) -#endif /* Not __ASSEMBLY__ */ +#endif /* Not __ASSEMBLER__ */ #endif diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index c025558754d5..f799c0d723da 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -32,7 +32,7 @@ /* * Configure language */ -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #define _ULCAST_ #define _U64CAST_ #else @@ -1346,7 +1346,7 @@ #define FPU_CSR_RD 0x3 /* towards -Infinity */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * Macros for handling the ISA mode bit for MIPS16 and microMIPS. @@ -3095,6 +3095,6 @@ static inline unsigned int get_ebase_cpunum(void) return read_c0_ebase() & MIPS_EBASE_CPUNUM; } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* _ASM_MIPSREGS_H */ diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h index 236a49ee2e3e..c6077f5fa4b1 100644 --- a/arch/mips/include/asm/msa.h +++ b/arch/mips/include/asm/msa.h @@ -8,7 +8,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -218,7 +218,7 @@ __BUILD_MSA_CTL_REG(request, 5) __BUILD_MSA_CTL_REG(map, 6) __BUILD_MSA_CTL_REG(unmap, 7) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define MSA_IR 0 #define MSA_CSR 1 diff --git a/arch/mips/include/asm/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h index 9c476a0400e0..eaeafccd82c7 100644 --- a/arch/mips/include/asm/pci/bridge.h +++ b/arch/mips/include/asm/pci/bridge.h @@ -43,7 +43,7 @@ * Bridge address map */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define ATE_V 0x01 #define ATE_CO 0x02 @@ -288,7 +288,7 @@ struct bridge_err_cmdword { }; #define berr_field berr_un.berr_st -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * The values of these macros can and should be crosschecked diff --git a/arch/mips/include/asm/pm.h b/arch/mips/include/asm/pm.h index 7ecd4dfe3846..52f3d64c5f34 100644 --- a/arch/mips/include/asm/pm.h +++ b/arch/mips/include/asm/pm.h @@ -8,7 +8,7 @@ #ifndef __ASM_PM_H #define __ASM_PM_H -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #include #include @@ -130,7 +130,7 @@ RESUME_RESTORE_REGS_RETURN .endm -#else /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ /** * struct mips_static_suspend_state - Core saved CPU state across S2R. @@ -150,6 +150,6 @@ struct mips_static_suspend_state { unsigned long sp; }; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __ASM_PM_HELPERS_H */ diff --git a/arch/mips/include/asm/prefetch.h b/arch/mips/include/asm/prefetch.h index a56594f360ee..4bd359fa3d97 100644 --- a/arch/mips/include/asm/prefetch.h +++ b/arch/mips/include/asm/prefetch.h @@ -42,7 +42,7 @@ #define Pref_WriteBackInvalidate 25 #define Pref_PrepareForStore 30 -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ .macro __pref hint addr #ifdef CONFIG_CPU_HAS_PREFETCH diff --git a/arch/mips/include/asm/regdef.h b/arch/mips/include/asm/regdef.h index 236051364f78..dd0b558c9767 100644 --- a/arch/mips/include/asm/regdef.h +++ b/arch/mips/include/asm/regdef.h @@ -103,7 +103,7 @@ #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 */ -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #if _MIPS_SIM == _MIPS_SIM_ABI32 /* @@ -192,6 +192,6 @@ #define ra $31 /* return address */ #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 */ -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* _ASM_REGDEF_H */ diff --git a/arch/mips/include/asm/sibyte/board.h b/arch/mips/include/asm/sibyte/board.h index 03463faa4244..d29c1c013dc5 100644 --- a/arch/mips/include/asm/sibyte/board.h +++ b/arch/mips/include/asm/sibyte/board.h @@ -19,7 +19,7 @@ #include #endif -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #ifdef LEDS_PHYS #define setleds(t0, t1, c0, c1, c2, c3) \ @@ -46,6 +46,6 @@ extern void setleds(char *str); #define setleds(s) do { } while (0) #endif /* LEDS_PHYS */ -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* _SIBYTE_BOARD_H */ diff --git a/arch/mips/include/asm/sibyte/sb1250.h b/arch/mips/include/asm/sibyte/sb1250.h index 495b31925ed7..de4b352256c8 100644 --- a/arch/mips/include/asm/sibyte/sb1250.h +++ b/arch/mips/include/asm/sibyte/sb1250.h @@ -19,7 +19,7 @@ #define SB1250_DUART_MINOR_BASE 64 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include diff --git a/arch/mips/include/asm/sibyte/sb1250_defs.h b/arch/mips/include/asm/sibyte/sb1250_defs.h index 68cd7c0b37ea..98cbb65cce0a 100644 --- a/arch/mips/include/asm/sibyte/sb1250_defs.h +++ b/arch/mips/include/asm/sibyte/sb1250_defs.h @@ -199,7 +199,7 @@ * Note: you'll need to define uint32_t and uint64_t in your headers. */ -#if !defined(__ASSEMBLY__) +#if !defined(__ASSEMBLER__) #define _SB_MAKE64(x) ((uint64_t)(x)) #define _SB_MAKE32(x) ((uint32_t)(x)) #else @@ -238,9 +238,9 @@ */ -#if defined(__mips64) && !defined(__ASSEMBLY__) +#if defined(__mips64) && !defined(__ASSEMBLER__) #define SBWRITECSR(csr, val) *((volatile uint64_t *) PHYS_TO_K1(csr)) = (val) #define SBREADCSR(csr) (*((volatile uint64_t *) PHYS_TO_K1(csr))) -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/mips/include/asm/smp-cps.h b/arch/mips/include/asm/smp-cps.h index 88cfae5d22c8..63620abbd067 100644 --- a/arch/mips/include/asm/smp-cps.h +++ b/arch/mips/include/asm/smp-cps.h @@ -9,7 +9,7 @@ #define CPS_ENTRY_PATCH_INSNS 6 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct vpe_boot_config { unsigned long pc; @@ -55,9 +55,9 @@ static inline bool mips_cps_smp_in_use(void) { return false; } #endif /* !CONFIG_MIPS_CPS */ -#else /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ .extern mips_cps_bootcfg; -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __MIPS_ASM_SMP_CPS_H__ */ diff --git a/arch/mips/include/asm/sn/addrs.h b/arch/mips/include/asm/sn/addrs.h index 837d23e24976..7c675fecbf9a 100644 --- a/arch/mips/include/asm/sn/addrs.h +++ b/arch/mips/include/asm/sn/addrs.h @@ -10,10 +10,10 @@ #define _ASM_SN_ADDRS_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #include #include @@ -25,15 +25,15 @@ #endif -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define UINT64_CAST (unsigned long) -#else /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ #define UINT64_CAST -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #define NASID_GET_META(_n) ((_n) >> NASID_LOCAL_BITS) @@ -254,7 +254,7 @@ #define LOCAL_HUB_ADDR(_x) (IALIAS_BASE + (_x)) #define REMOTE_HUB_ADDR(_n, _x) ((NODE_SWIN_BASE(_n, 1) + 0x800000 + (_x))) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define LOCAL_HUB_PTR(_x) ((u64 *)LOCAL_HUB_ADDR((_x))) #define REMOTE_HUB_PTR(_n, _x) ((u64 *)REMOTE_HUB_ADDR((_n), (_x))) @@ -265,7 +265,7 @@ #define REMOTE_HUB_S(_n, _r, _d) __raw_writeq((_d), \ REMOTE_HUB_PTR((_n), (_r))) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * Software structure locations -- permanently fixed @@ -315,7 +315,7 @@ #define KLI_KERN_XP 8 #define KLI_KERN_PARTID 9 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define KLD_BASE(nasid) ((kldir_ent_t *) KLDIR_ADDR(nasid)) #define KLD_LAUNCH(nasid) (KLD_BASE(nasid) + KLI_LAUNCH) @@ -371,7 +371,7 @@ #define KERN_VARS_ADDR(nasid) KLD_KERN_VARS(nasid)->pointer #define KERN_VARS_SIZE(nasid) KLD_KERN_VARS(nasid)->size -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* _ASM_SN_ADDRS_H */ diff --git a/arch/mips/include/asm/sn/gda.h b/arch/mips/include/asm/sn/gda.h index 5b8c96d5b587..d8fd80137206 100644 --- a/arch/mips/include/asm/sn/gda.h +++ b/arch/mips/include/asm/sn/gda.h @@ -39,7 +39,7 @@ #define G_PARTIDOFF 40 #define G_TABLEOFF 128 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef struct gda { u32 g_magic; /* GDA magic number */ @@ -63,7 +63,7 @@ typedef struct gda { #define GDA ((gda_t*) GDA_ADDR(get_nasid())) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * Define: PART_GDA_VERSION * Purpose: Define the minimum version of the GDA required, lower diff --git a/arch/mips/include/asm/sn/kldir.h b/arch/mips/include/asm/sn/kldir.h index 245f59bf3845..f394b1e0c956 100644 --- a/arch/mips/include/asm/sn/kldir.h +++ b/arch/mips/include/asm/sn/kldir.h @@ -15,7 +15,7 @@ #define KLDIR_ENT_SIZE 0x40 #define KLDIR_MAX_ENTRIES (0x400 / 0x40) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef struct kldir_ent_s { u64 magic; /* Indicates validity of entry */ off_t offset; /* Offset from start of node space */ @@ -27,7 +27,7 @@ typedef struct kldir_ent_s { /* NOTE: These 16 bytes are used in the Partition KLDIR entry to store partition info. Refer to klpart.h for this. */ } kldir_ent_t; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #ifdef CONFIG_SGI_IP27 #include diff --git a/arch/mips/include/asm/sn/klkernvars.h b/arch/mips/include/asm/sn/klkernvars.h index ea6b21795163..bb7a6c36f6e7 100644 --- a/arch/mips/include/asm/sn/klkernvars.h +++ b/arch/mips/include/asm/sn/klkernvars.h @@ -12,7 +12,7 @@ #define KV_MAGIC 0x5f4b565f -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -24,6 +24,6 @@ typedef struct kern_vars_s { unsigned long kv_rw_baseaddr; } kern_vars_t; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __ASM_SN_KLKERNVARS_H */ diff --git a/arch/mips/include/asm/sn/launch.h b/arch/mips/include/asm/sn/launch.h index 04226d8d30c4..ce95187362e7 100644 --- a/arch/mips/include/asm/sn/launch.h +++ b/arch/mips/include/asm/sn/launch.h @@ -59,7 +59,7 @@ * clears the BUSY flag after control is returned to it. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef int launch_state_t; typedef void (*launch_proc_t)(u64 call_parm); @@ -101,6 +101,6 @@ typedef struct launch_s { #define LAUNCH_FLASH (*(void (*)(void)) \ IP27PROM_FLASHLEDS) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* _ASM_SN_LAUNCH_H */ diff --git a/arch/mips/include/asm/sn/nmi.h b/arch/mips/include/asm/sn/nmi.h index 12ac210f12a1..eff51606bbce 100644 --- a/arch/mips/include/asm/sn/nmi.h +++ b/arch/mips/include/asm/sn/nmi.h @@ -48,7 +48,7 @@ * */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef struct nmi_s { volatile unsigned long magic; /* Magic number */ @@ -59,13 +59,13 @@ typedef struct nmi_s { volatile unsigned long gmaster; /* Flag true only on global master*/ } nmi_t; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* Following definitions are needed both in the prom & the kernel * to identify the format of the nmi cpu register save area in the * low memory on each node. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct reg_struct { unsigned long gpr[32]; @@ -78,7 +78,7 @@ struct reg_struct { unsigned long nmi_sr; }; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* These are the assembly language offsets into the reg_struct structure */ diff --git a/arch/mips/include/asm/sn/sn0/addrs.h b/arch/mips/include/asm/sn/sn0/addrs.h index f13df84edfdd..a28158a91ecf 100644 --- a/arch/mips/include/asm/sn/sn0/addrs.h +++ b/arch/mips/include/asm/sn/sn0/addrs.h @@ -84,15 +84,15 @@ #define NASID_GET(_pa) (int) ((UINT64_CAST (_pa) >> \ NASID_SHFT) & NASID_BITMASK) -#if !defined(__ASSEMBLY__) +#if !defined(__ASSEMBLER__) #define NODE_SWIN_BASE(nasid, widget) \ ((widget == 0) ? NODE_BWIN_BASE((nasid), SWIN0_BIGWIN) \ : RAW_NODE_SWIN_BASE(nasid, widget)) -#else /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ #define NODE_SWIN_BASE(nasid, widget) \ (NODE_IO_BASE(nasid) + (UINT64_CAST(widget) << SWIN_SIZE_BITS)) -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ /* * The following definitions pertain to the IO special address @@ -139,11 +139,11 @@ /* Turn on sable logging for the processors whose bits are set. */ #define SABLE_LOG_TRIGGER(_map) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define KERN_NMI_ADDR(nasid, slice) \ TO_NODE_UNCAC((nasid), IP27_NMI_KREGS_OFFSET + \ (IP27_NMI_KREGS_CPU_SIZE * (slice))) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #ifdef PROM @@ -248,7 +248,7 @@ #define KL_UART_DATA LOCAL_HUB_ADDR(MD_UREG0_1) /* UART data reg */ #define KL_I2C_REG MD_UREG0_0 /* I2C reg */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* Address 0x400 to 0x1000 ualias points to cache error eframe + misc * CACHE_ERR_SP_PTR could either contain an address to the stack, or @@ -266,7 +266,7 @@ #define CACHE_ERR_SP (CACHE_ERR_SP_PTR - 16) #define CACHE_ERR_AREA_SIZE (ARCS_SPB_OFFSET - CACHE_ERR_EFRAME) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define _ARCSPROM diff --git a/arch/mips/include/asm/sn/sn0/hub.h b/arch/mips/include/asm/sn/sn0/hub.h index c84adde36d41..916394319af5 100644 --- a/arch/mips/include/asm/sn/sn0/hub.h +++ b/arch/mips/include/asm/sn/sn0/hub.h @@ -37,7 +37,7 @@ #define UATTR_MSPEC 2 #define UATTR_UNCAC 3 -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ /* * Returns the local nasid into res. */ diff --git a/arch/mips/include/asm/sn/sn0/hubio.h b/arch/mips/include/asm/sn/sn0/hubio.h index 57ece90f8cf1..c489426f8f9e 100644 --- a/arch/mips/include/asm/sn/sn0/hubio.h +++ b/arch/mips/include/asm/sn/sn0/hubio.h @@ -169,7 +169,7 @@ /* * The IO LLP control status register and widget control register */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef union hubii_wid_u { u64 wid_reg_value; @@ -292,7 +292,7 @@ typedef union io_perf_cnt { } perf_cnt_bits; } io_perf_cnt_t; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define LNK_STAT_WORKING 0x2 @@ -440,7 +440,7 @@ typedef union io_perf_cnt { /* * Fields in CRB Register A */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef union icrba_u { u64 reg_value; struct { @@ -486,7 +486,7 @@ typedef union h1_icrba_u { #define ICRBN_A_CERR_SHFT 54 #define ICRBN_A_ERR_MASK 0x3ff -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define IIO_ICRB_ADDR_SHFT 2 /* Shift to get proper address */ @@ -509,7 +509,7 @@ typedef union h1_icrba_u { /* * Fields in CRB Register B */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef union icrbb_u { u64 reg_value; struct { @@ -608,7 +608,7 @@ typedef union h1_icrbb_u { #define b_imsg icrbb_field_s.imsg #define b_initiator icrbb_field_s.initiator -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * values for field xtsize @@ -666,7 +666,7 @@ typedef union h1_icrbb_u { * Fields in CRB Register C */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef union icrbc_s { u64 reg_value; @@ -698,13 +698,13 @@ typedef union icrbc_s { #define c_barrop icrbc_field_s.barrop #define c_doresp icrbc_field_s.doresp #define c_gbr icrbc_field_s.gbr -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * Fields in CRB Register D */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef union icrbd_s { u64 reg_value; struct { @@ -737,7 +737,7 @@ typedef union hubii_ifdr_u { } hi_ifdr_fields; } hubii_ifdr_t; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * Hardware designed names for the BTE control registers. @@ -784,7 +784,7 @@ typedef union hubii_ifdr_u { * IO PIO Read Table Entry format */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef union iprte_a { u64 entry; @@ -806,7 +806,7 @@ typedef union iprte_a { #define iprte_init iprte_fields.initiator #define iprte_addr iprte_fields.addr -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define IPRTE_ADDRSHFT 3 @@ -814,7 +814,7 @@ typedef union iprte_a { * Hub IIO PRB Register format. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * Note: Fields bnakctr, anakctr, xtalkctrmode, ovflow fields are * "Status" fields, and should only be used in case of clean up after errors. @@ -846,7 +846,7 @@ typedef union iprb_u { #define iprb_anakctr iprb_fields_s.anakctr #define iprb_xtalkctr iprb_fields_s.xtalkctr -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * values for mode field in iprb_t. @@ -861,7 +861,7 @@ typedef union iprb_u { /* * IO CRB entry C_A to E_A : Partial (cache) CRBS */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef union icrbp_a { u64 ip_reg; /* the entire register value */ struct { @@ -895,7 +895,7 @@ typedef union icrbp_a { } ip_fmt; } icrbp_a_t; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * A couple of defines to go with the above structure. @@ -903,7 +903,7 @@ typedef union icrbp_a { #define ICRBP_A_CERR_SHFT 54 #define ICRBP_A_ERR_MASK 0x3ff -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef union hubii_idsr { u64 iin_reg; struct { @@ -917,7 +917,7 @@ typedef union hubii_idsr { level : 7; } iin_fmt; } hubii_idsr_t; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* * IO BTE Length/Status (IIO_IBLS) register bit field definitions diff --git a/arch/mips/include/asm/sn/sn0/hubmd.h b/arch/mips/include/asm/sn/sn0/hubmd.h index 305d002be182..97d9cbbf9f4c 100644 --- a/arch/mips/include/asm/sn/sn0/hubmd.h +++ b/arch/mips/include/asm/sn/sn0/hubmd.h @@ -423,7 +423,7 @@ * Operations on page migration threshold register */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * LED register macros @@ -735,7 +735,7 @@ typedef union md_perf_cnt { } md_perf_cnt_t; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define DIR_ERROR_VALID_MASK 0xe000000000000000 diff --git a/arch/mips/include/asm/sn/sn0/hubni.h b/arch/mips/include/asm/sn/sn0/hubni.h index b8253142cb83..4830bae723e4 100644 --- a/arch/mips/include/asm/sn/sn0/hubni.h +++ b/arch/mips/include/asm/sn/sn0/hubni.h @@ -11,7 +11,7 @@ #ifndef _ASM_SGI_SN0_HUBNI_H #define _ASM_SGI_SN0_HUBNI_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #endif @@ -226,7 +226,7 @@ #define NLT_EXIT_PORT_MASK (UINT64_CAST 0xf) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef union hubni_port_error_u { u64 nipe_reg_value; @@ -258,6 +258,6 @@ static inline int get_region_shift(void) return NASID_TO_COARSEREG_SHFT; } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* _ASM_SGI_SN0_HUBNI_H */ diff --git a/arch/mips/include/asm/sn/sn0/hubpi.h b/arch/mips/include/asm/sn/sn0/hubpi.h index 7b83655913c5..a4fe0feeef0c 100644 --- a/arch/mips/include/asm/sn/sn0/hubpi.h +++ b/arch/mips/include/asm/sn/sn0/hubpi.h @@ -306,7 +306,7 @@ #define ERR_STACK_SIZE_BYTES(_sz) \ ((_sz) ? (PI_MIN_STACK_SIZE << ((_sz) - 1)) : 0) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * format of error stack and error status registers. */ @@ -359,7 +359,7 @@ typedef union pi_err_stat1 { typedef u64 rtc_time_t; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* Bits in PI_SYSAD_ERRCHK_EN */ diff --git a/arch/mips/include/asm/sn/types.h b/arch/mips/include/asm/sn/types.h index 451ba1ee41ad..53d04c04d6f5 100644 --- a/arch/mips/include/asm/sn/types.h +++ b/arch/mips/include/asm/sn/types.h @@ -11,7 +11,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef unsigned long cpuid_t; typedef signed short nasid_t; /* node id in numa-as-id space */ diff --git a/arch/mips/include/asm/sync.h b/arch/mips/include/asm/sync.h index 44c04a82d0b7..d7873e8d7e6f 100644 --- a/arch/mips/include/asm/sync.h +++ b/arch/mips/include/asm/sync.h @@ -193,7 +193,7 @@ * Preprocessor magic to expand macros used as arguments before we insert them * into assembly code. */ -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ # define ___SYNC(type, reason, else) \ ____SYNC(type, reason, else) #else diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index b9d76e8ac5a2..2707dad260dd 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -11,7 +11,7 @@ #ifdef __KERNEL__ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -73,7 +73,7 @@ static inline struct thread_info *current_thread_info(void) register unsigned long current_stack_pointer __asm__("sp"); #endif -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ /* thread information allocation */ #if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_32BIT) diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h index ba83d3fb0a84..6a974b990f4b 100644 --- a/arch/mips/include/asm/unistd.h +++ b/arch/mips/include/asm/unistd.h @@ -29,7 +29,7 @@ #define NR_syscalls (__NR_O32_Linux + __NR_O32_Linux_syscalls) #endif -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_OLD_READDIR @@ -62,6 +62,6 @@ /* whitelists for checksyscalls */ #define __IGNORE_fadvise64_64 -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* _ASM_UNISTD_H */ diff --git a/arch/mips/include/asm/vdso/gettimeofday.h b/arch/mips/include/asm/vdso/gettimeofday.h index fd32baa30e17..32d2d173fdc0 100644 --- a/arch/mips/include/asm/vdso/gettimeofday.h +++ b/arch/mips/include/asm/vdso/gettimeofday.h @@ -11,7 +11,7 @@ #ifndef __ASM_VDSO_GETTIMEOFDAY_H #define __ASM_VDSO_GETTIMEOFDAY_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -215,6 +215,6 @@ static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data( } #define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __ASM_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/mips/include/asm/vdso/processor.h b/arch/mips/include/asm/vdso/processor.h index 511c95d735e6..05cdb366dc21 100644 --- a/arch/mips/include/asm/vdso/processor.h +++ b/arch/mips/include/asm/vdso/processor.h @@ -5,7 +5,7 @@ #ifndef __ASM_VDSO_PROCESSOR_H #define __ASM_VDSO_PROCESSOR_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #ifdef CONFIG_CPU_LOONGSON64 /* @@ -22,6 +22,6 @@ #define cpu_relax() barrier() #endif -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __ASM_VDSO_PROCESSOR_H */ diff --git a/arch/mips/include/asm/vdso/vdso.h b/arch/mips/include/asm/vdso/vdso.h index acd0efcd3d93..6889e0f2e5db 100644 --- a/arch/mips/include/asm/vdso/vdso.h +++ b/arch/mips/include/asm/vdso/vdso.h @@ -9,7 +9,7 @@ #define __VDSO_PAGES 4 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -69,4 +69,4 @@ static inline void __iomem *get_gic(const struct vdso_time_data *data) #endif /* CONFIG_CLKSRC_MIPS_GIC */ -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ diff --git a/arch/mips/include/asm/vdso/vsyscall.h b/arch/mips/include/asm/vdso/vsyscall.h index 2b1debb62dee..0f061a9babd1 100644 --- a/arch/mips/include/asm/vdso/vsyscall.h +++ b/arch/mips/include/asm/vdso/vsyscall.h @@ -4,13 +4,13 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include /* The asm-generic header needs to be included after the definitions above */ #include -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __ASM_VDSO_VSYSCALL_H */ diff --git a/arch/mips/include/asm/xtalk/xtalk.h b/arch/mips/include/asm/xtalk/xtalk.h index 680e7efebbaf..dfe6a3fce65a 100644 --- a/arch/mips/include/asm/xtalk/xtalk.h +++ b/arch/mips/include/asm/xtalk/xtalk.h @@ -12,7 +12,7 @@ #ifndef _ASM_XTALK_XTALK_H #define _ASM_XTALK_XTALK_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * User-level device driver visible types */ @@ -47,6 +47,6 @@ typedef struct xtalk_piomap_s *xtalk_piomap_t; #define XIO_PORT(x) ((xwidgetnum_t)(((x)&XIO_PORT_BITS) >> XIO_PORT_SHIFT)) #define XIO_PACK(p, o) ((((uint64_t)(p))<mfg_num == XWIDGET_MFG_NUM_NONE) || \ ((hwid1)->mfg_num == (hwid2)->mfg_num))) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* _ASM_XTALK_XWIDGET_H */ diff --git a/drivers/soc/bcm/brcmstb/pm/pm.h b/drivers/soc/bcm/brcmstb/pm/pm.h index 94a380470a2f..17f7a06a7a83 100644 --- a/drivers/soc/bcm/brcmstb/pm/pm.h +++ b/drivers/soc/bcm/brcmstb/pm/pm.h @@ -60,7 +60,7 @@ PM_DEEP_STANDBY | \ PM_PLL_PWRDOWN | PM_PWR_DOWN) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #ifndef CONFIG_MIPS extern const unsigned long brcmstb_pm_do_s2_sz; From dba4380504923b9c21d391bc9a3e699d3ba2bab6 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sun, 10 Aug 2025 18:30:23 -0400 Subject: [PATCH 0659/2711] MIPS: Alchemy: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch appended to the "under-the-cut" portion of the patch. Note that prior to running Coccinelle, alchemy_clk_aux_roundr() was renamed to alchemy_clk_aux_round_rate(). A few minor style cleanups were also done by hand. Signed-off-by: Brian Masney Tested-by: Manuel Lauss Signed-off-by: Thomas Bogendoerfer --- arch/mips/alchemy/common/clock.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index 6c8996e20a7d..551b0d21d9dc 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -211,30 +211,34 @@ static int alchemy_clk_aux_setr(struct clk_hw *hw, return 0; } -static long alchemy_clk_aux_roundr(struct clk_hw *hw, - unsigned long rate, - unsigned long *parent_rate) +static int alchemy_clk_aux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct alchemy_auxpll_clk *a = to_auxpll_clk(hw); unsigned long mult; - if (!rate || !*parent_rate) - return 0; + if (!req->rate || !req->best_parent_rate) { + req->rate = 0; - mult = rate / (*parent_rate); + return 0; + } + + mult = req->rate / req->best_parent_rate; if (mult && (mult < 7)) mult = 7; if (mult > a->maxmult) mult = a->maxmult; - return (*parent_rate) * mult; + req->rate = req->best_parent_rate * mult; + + return 0; } static const struct clk_ops alchemy_clkops_aux = { .recalc_rate = alchemy_clk_aux_recalc, .set_rate = alchemy_clk_aux_setr, - .round_rate = alchemy_clk_aux_roundr, + .determine_rate = alchemy_clk_aux_determine_rate, }; static struct clk __init *alchemy_clk_setup_aux(const char *parent_name, From 1ea149fb5b068c1b7490451d967216ff554628af Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Mon, 11 Aug 2025 11:20:36 +0200 Subject: [PATCH 0660/2711] dt-bindings: mips: cpu: Add MIPS 34Kc Core Document MIPS 34Kc device tree bindings. It is used in the Realtek RTL930x SoC. Signed-off-by: Aleksander Jan Bajkowski Acked-by: Conor Dooley Signed-off-by: Thomas Bogendoerfer --- Documentation/devicetree/bindings/mips/cpus.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mips/cpus.yaml b/Documentation/devicetree/bindings/mips/cpus.yaml index 471373ad0cfb..d3677f53f142 100644 --- a/Documentation/devicetree/bindings/mips/cpus.yaml +++ b/Documentation/devicetree/bindings/mips/cpus.yaml @@ -33,6 +33,7 @@ properties: - mips,mips1004Kc - mips,mips24KEc - mips,mips24Kc + - mips,mips34Kc - mips,mips4KEc - mips,mips4Kc - mips,mips74Kc From e8dee66c37085dc9858eb8608bc783c2900e50e7 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Mon, 11 Aug 2025 13:58:15 +0200 Subject: [PATCH 0661/2711] mips: lantiq: danube: add missing properties to cpu node This fixes the following warnings: arch/mips/boot/dts/lantiq/danube_easy50712.dtb: cpus: '#address-cells' is a required property from schema $id: http://devicetree.org/schemas/cpus.yaml# arch/mips/boot/dts/lantiq/danube_easy50712.dtb: cpus: '#size-cells' is a required property from schema $id: http://devicetree.org/schemas/cpus.yaml# arch/mips/boot/dts/lantiq/danube_easy50712.dtb: cpu@0 (mips,mips24Kc): 'reg' is a required property from schema $id: http://devicetree.org/schemas/mips/cpus.yaml# Signed-off-by: Aleksander Jan Bajkowski Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/lantiq/danube.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/boot/dts/lantiq/danube.dtsi b/arch/mips/boot/dts/lantiq/danube.dtsi index 7a7ba66aa534..0a942bc09143 100644 --- a/arch/mips/boot/dts/lantiq/danube.dtsi +++ b/arch/mips/boot/dts/lantiq/danube.dtsi @@ -5,8 +5,12 @@ compatible = "lantiq,xway", "lantiq,danube"; cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { compatible = "mips,mips24Kc"; + reg = <0>; }; }; From d66949a1875352d2ddd52b144333288952a9e36f Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Mon, 11 Aug 2025 15:34:13 +0200 Subject: [PATCH 0662/2711] mips: lantiq: danube: add missing device_type in pci node This fixes the following warning: arch/mips/boot/dts/lantiq/danube_easy50712.dtb: pci@e105400 (lantiq,pci-xway): 'device_type' is a required property from schema $id: http://devicetree.org/schemas/pci/pci-bus-common.yaml# Signed-off-by: Aleksander Jan Bajkowski Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/lantiq/danube.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/boot/dts/lantiq/danube.dtsi b/arch/mips/boot/dts/lantiq/danube.dtsi index 0a942bc09143..650400bd5725 100644 --- a/arch/mips/boot/dts/lantiq/danube.dtsi +++ b/arch/mips/boot/dts/lantiq/danube.dtsi @@ -104,6 +104,8 @@ 0x1000000 0 0x00000000 0xae00000 0 0x200000>; /* io space */ reg = <0x7000000 0x8000 /* config space */ 0xe105400 0x400>; /* pci bridge */ + + device_type = "pci"; }; }; }; From cb96fd880ef78500b34d10fa76ddd3fa070287d6 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Tue, 12 Aug 2025 16:06:04 +0200 Subject: [PATCH 0663/2711] mips: lantiq: danube: add model to EASY50712 dts This fixes the following warning: arch/mips/boot/dts/lantiq/danube_easy50712.dtb: / (lantiq,xway): 'model' is a required property from schema $id: http://devicetree.org/schemas/root-node.yaml# Signed-off-by: Aleksander Jan Bajkowski Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/lantiq/danube_easy50712.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/boot/dts/lantiq/danube_easy50712.dts b/arch/mips/boot/dts/lantiq/danube_easy50712.dts index c4d7aa5753b0..ab70028dbefc 100644 --- a/arch/mips/boot/dts/lantiq/danube_easy50712.dts +++ b/arch/mips/boot/dts/lantiq/danube_easy50712.dts @@ -4,6 +4,8 @@ /include/ "danube.dtsi" / { + model = "Intel EASY50712"; + chosen { bootargs = "console=ttyLTQ0,115200 init=/etc/preinit"; }; From e5a6d4a23acfe56749c7543ef55c54b8b903616b Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 Aug 2025 20:37:11 +0200 Subject: [PATCH 0664/2711] MIPS: sgi-ip22: Replace deprecated strcpy() in plat_mem_setup() strcpy() is deprecated; use strscpy() instead. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Justin Stitt Signed-off-by: Thomas Bogendoerfer --- arch/mips/sgi-ip22/ip22-setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c index e06a818fe792..f083b25be13b 100644 --- a/arch/mips/sgi-ip22/ip22-setup.c +++ b/arch/mips/sgi-ip22/ip22-setup.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -65,7 +66,7 @@ void __init plat_mem_setup(void) static char options[8] __initdata; char *baud = ArcGetEnvironmentVariable("dbaud"); if (baud) - strcpy(options, baud); + strscpy(options, baud); add_preferred_console("ttyS", *(ctype + 1) == '2' ? 1 : 0, baud ? options : NULL); } else if (!ctype || *ctype != 'g') { From 5cd39d00c257ea01eeab4ad36c0d4474e143655e Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 Aug 2025 20:37:12 +0200 Subject: [PATCH 0665/2711] MIPS: sgi-ip32: Replace deprecated strcpy() in plat_mem_setup() strcpy() is deprecated; use strscpy() instead. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Signed-off-by: Thomas Bogendoerfer --- arch/mips/sgi-ip32/ip32-setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c index aeb0805aae57..c2ebc4bbd866 100644 --- a/arch/mips/sgi-ip32/ip32-setup.c +++ b/arch/mips/sgi-ip32/ip32-setup.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -90,7 +91,7 @@ void __init plat_mem_setup(void) static char options[8] __initdata; char *baud = ArcGetEnvironmentVariable("dbaud"); if (baud) - strcpy(options, baud); + strscpy(options, baud); add_preferred_console("ttyS", *(con + 1) == '2' ? 1 : 0, baud ? options : NULL); } From 5861bb3ea24c8c7ab1d619b59b777a4c56777142 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 Aug 2025 20:37:13 +0200 Subject: [PATCH 0666/2711] MIPS: sni: Replace deprecated strcpy() in sni_console_setup() strcpy() is deprecated; use strscpy() instead. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Justin Stitt Signed-off-by: Thomas Bogendoerfer --- arch/mips/sni/setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 03cb69937258..fc7da12284f5 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef CONFIG_FW_ARC #include @@ -80,7 +81,7 @@ static void __init sni_console_setup(void) break; } if (baud) - strcpy(options, baud); + strscpy(options, baud); if (strncmp(cdev, "tty552", 6) == 0) add_preferred_console("ttyS", port, baud ? options : NULL); From 19b32dbba0c7f4ab2fb7349676ffcb40a70be0fa Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 Aug 2025 20:37:14 +0200 Subject: [PATCH 0667/2711] MIPS: txx9: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Geert Uytterhoeven Signed-off-by: Thomas Bogendoerfer --- arch/mips/txx9/generic/setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 5dc867ea2c69..03f8a3a95637 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -200,7 +200,7 @@ static void __init preprocess_cmdline(void) static char cmdline[COMMAND_LINE_SIZE] __initdata; char *s; - strcpy(cmdline, arcs_cmdline); + strscpy(cmdline, arcs_cmdline); s = cmdline; arcs_cmdline[0] = '\0'; while (s && *s) { @@ -270,7 +270,7 @@ void __init prom_init(void) preprocess_cmdline(); select_board(); - strcpy(txx9_system_type, txx9_board_vec->system); + strscpy(txx9_system_type, txx9_board_vec->system); txx9_board_vec->prom_init(); } From 267ac0a800121dd450d0ed6cdbba9a8712b48c59 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 Aug 2025 20:37:15 +0200 Subject: [PATCH 0668/2711] MIPS: arc: Replace deprecated strcpy() with memcpy() strcpy() is deprecated; use memcpy() instead. Use pr_debug() instead of printk(KERN_DEBUG) to silence a checkpatch warning. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Signed-off-by: Thomas Bogendoerfer --- arch/mips/fw/arc/cmdline.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/arch/mips/fw/arc/cmdline.c b/arch/mips/fw/arc/cmdline.c index 155c5e911723..86b0e377b713 100644 --- a/arch/mips/fw/arc/cmdline.c +++ b/arch/mips/fw/arc/cmdline.c @@ -42,12 +42,13 @@ static char __init *move_firmware_args(int argc, LONG *argv, char *cp) { char *s; int actr, i; + size_t len; actr = 1; /* Always ignore argv[0] */ while (actr < argc) { - for(i = 0; i < ARRAY_SIZE(used_arc); i++) { - int len = strlen(used_arc[i][0]); + for (i = 0; i < ARRAY_SIZE(used_arc); i++) { + len = strlen(used_arc[i][0]); if (!strncmp(prom_argv(actr), used_arc[i][0], len)) { /* Ok, we want it. First append the replacement... */ @@ -57,8 +58,9 @@ static char __init *move_firmware_args(int argc, LONG *argv, char *cp) s = strchr(prom_argv(actr), '='); if (s) { s++; - strcpy(cp, s); - cp += strlen(s); + len = strlen(s); + memcpy(cp, s, len + 1); + cp += len; } *cp++ = ' '; break; @@ -74,6 +76,7 @@ void __init prom_init_cmdline(int argc, LONG *argv) { char *cp; int actr, i; + size_t len; actr = 1; /* Always ignore argv[0] */ @@ -86,14 +89,15 @@ void __init prom_init_cmdline(int argc, LONG *argv) while (actr < argc) { for (i = 0; i < ARRAY_SIZE(ignored); i++) { - int len = strlen(ignored[i]); - + len = strlen(ignored[i]); if (!strncmp(prom_argv(actr), ignored[i], len)) goto pic_cont; } + /* Ok, we want it. */ - strcpy(cp, prom_argv(actr)); - cp += strlen(prom_argv(actr)); + len = strlen(prom_argv(actr)); + memcpy(cp, prom_argv(actr), len + 1); + cp += len; *cp++ = ' '; pic_cont: @@ -105,6 +109,6 @@ void __init prom_init_cmdline(int argc, LONG *argv) *cp = '\0'; #ifdef DEBUG_CMDLINE - printk(KERN_DEBUG "prom cmdline: %s\n", arcs_cmdline); + pr_debug("prom cmdline: %s\n", arcs_cmdline); #endif } From 2c7c8cf656b2712ece061346848664ab5ace72c6 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 Aug 2025 20:37:16 +0200 Subject: [PATCH 0669/2711] MIPS: octeon: Replace memset(0) + deprecated strcpy() with strscpy_pad() Replace memset(0) followed by the deprecated strcpy() with strscpy_pad() to improve octeon_fdt_set_phy(). This avoids zeroing the memory before copying the string and ensures the destination buffer is only written to once, simplifying the code and improving efficiency. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Justin Stitt Signed-off-by: Thomas Bogendoerfer --- arch/mips/cavium-octeon/octeon-platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index 5e1dd4e6e82f..47677b5d7ed0 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -538,8 +539,7 @@ static void __init octeon_fdt_set_phy(int eth, int phy_addr) if (octeon_has_88e1145()) { fdt_nop_property(initial_boot_params, phy, "marvell,reg-init"); - memset(new_name, 0, sizeof(new_name)); - strcpy(new_name, "marvell,88e1145"); + strscpy_pad(new_name, "marvell,88e1145"); p = fdt_getprop(initial_boot_params, phy, "compatible", ¤t_len); if (p && current_len >= strlen(new_name)) From e34b690f58da12c4301932bb3cf9857879b2396f Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 Aug 2025 20:37:17 +0200 Subject: [PATCH 0670/2711] MIPS: octeon: Replace deprecated strcpy() in octeon_model_get_string_buffer() strcpy() is deprecated; use strscpy() instead. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Signed-off-by: Thomas Bogendoerfer --- .../cavium-octeon/executive/octeon-model.c | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/octeon-model.c b/arch/mips/cavium-octeon/executive/octeon-model.c index 657dbad9644e..98996cc0857e 100644 --- a/arch/mips/cavium-octeon/executive/octeon-model.c +++ b/arch/mips/cavium-octeon/executive/octeon-model.c @@ -25,6 +25,7 @@ * Contact Cavium Networks for more information ***********************license end**************************************/ +#include #include enum octeon_feature_bits __octeon_feature_bits __read_mostly; @@ -208,16 +209,16 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, */ switch (chip_id & 0xf) { case 0: - strcpy(pass, "1.X"); + strscpy(pass, "1.X"); break; case 1: - strcpy(pass, "2.X"); + strscpy(pass, "2.X"); break; case 3: - strcpy(pass, "3.X"); + strscpy(pass, "3.X"); break; default: - strcpy(pass, "X.X"); + strscpy(pass, "X.X"); break; } break; @@ -232,13 +233,13 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, */ switch (chip_id & 0xf) { case 0: - strcpy(pass, "1.0"); + strscpy(pass, "1.0"); break; case 2: - strcpy(pass, "1.1"); + strscpy(pass, "1.1"); break; default: - strcpy(pass, "X.X"); + strscpy(pass, "X.X"); break; } break; @@ -253,13 +254,13 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, */ switch (chip_id & 0xf) { case 0: - strcpy(pass, "1.0"); + strscpy(pass, "1.0"); break; case 2: - strcpy(pass, "1.1"); + strscpy(pass, "1.1"); break; default: - strcpy(pass, "X.X"); + strscpy(pass, "X.X"); break; } break; @@ -273,16 +274,16 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, if ((chip_id & 0xFF) < 0x8) { switch (chip_id & 0x3) { case 0: - strcpy(pass, "1.0"); + strscpy(pass, "1.0"); break; case 1: - strcpy(pass, "1.1"); + strscpy(pass, "1.1"); break; case 3: - strcpy(pass, "1.2"); + strscpy(pass, "1.2"); break; default: - strcpy(pass, "1.X"); + strscpy(pass, "1.X"); break; } } @@ -447,7 +448,7 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, default: family = "XX"; core_model = "XX"; - strcpy(pass, "X.X"); + strscpy(pass, "X.X"); suffix = "XXX"; break; } From 6a1e6bf933b6216cc3eb731a14cd519c189d3a04 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 Aug 2025 20:37:18 +0200 Subject: [PATCH 0671/2711] MIPS: generic: Replace deprecated strcpy() in ocelot_detect() strcpy() is deprecated; use strscpy() instead. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Signed-off-by: Thomas Bogendoerfer --- arch/mips/generic/board-ocelot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/generic/board-ocelot.c b/arch/mips/generic/board-ocelot.c index 7115410acb4f..59a0fb243582 100644 --- a/arch/mips/generic/board-ocelot.c +++ b/arch/mips/generic/board-ocelot.c @@ -4,6 +4,7 @@ * * Copyright (c) 2017 Microsemi Corporation */ +#include #include #include @@ -41,7 +42,7 @@ static __init bool ocelot_detect(void) if (prom_argc > 1 && strlen(prom_argv[1]) > 0) /* ignore all built-in args if any f/w args given */ - strcpy(arcs_cmdline, prom_argv[1]); + strscpy(arcs_cmdline, prom_argv[1]); } return true; From b7c1ee2dfe03c106a391cdbcba8d41e23c4b1bcb Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 19 Aug 2025 12:23:19 +0200 Subject: [PATCH 0672/2711] MIPS: Loongson64: Replace deprecated strcpy() with strscpy_pad() strcpy() is deprecated; use strscpy_pad() instead. strscpy_pad() already copies the source strings and zero-pads the tail of the destination buffers, making the explicit initializations to zero redundant. Remove them to ensure the buffers are only written to once. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Signed-off-by: Thomas Bogendoerfer --- arch/mips/loongson64/boardinfo.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/mips/loongson64/boardinfo.c b/arch/mips/loongson64/boardinfo.c index 8bb275c93ac0..827ab94b98b3 100644 --- a/arch/mips/loongson64/boardinfo.c +++ b/arch/mips/loongson64/boardinfo.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include static ssize_t boardinfo_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - char board_manufacturer[64] = {0}; + char board_manufacturer[64]; char *tmp_board_manufacturer = board_manufacturer; - char bios_vendor[64] = {0}; + char bios_vendor[64]; char *tmp_bios_vendor = bios_vendor; - strcpy(board_manufacturer, eboard->name); - strcpy(bios_vendor, einter->description); + strscpy_pad(board_manufacturer, eboard->name); + strscpy_pad(bios_vendor, einter->description); return sprintf(buf, "Board Info\n" From 51f96bff04b05ee0683471fa33b11cce414e4b56 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 19 Aug 2025 12:24:17 +0200 Subject: [PATCH 0673/2711] MIPS: RB532: Replace deprecated strcpy() with memcpy() and strscpy() strcpy() is deprecated; use memcpy() and strscpy() instead. Add the local variable 'size_t len' to keep track of the string lengths and prefer memcpy() over strscpy() when we use the string length to advance the 'cp' pointer. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Signed-off-by: Thomas Bogendoerfer --- arch/mips/rb532/prom.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/arch/mips/rb532/prom.c b/arch/mips/rb532/prom.c index b88e89ec5894..8c370eb180ef 100644 --- a/arch/mips/rb532/prom.c +++ b/arch/mips/rb532/prom.c @@ -53,6 +53,7 @@ static void __init prom_setup_cmdline(void) int prom_argc; char **prom_argv; int i; + size_t len; prom_argc = fw_arg0; prom_argv = (char **) fw_arg1; @@ -82,20 +83,20 @@ static void __init prom_setup_cmdline(void) mips_machtype = MACH_MIKROTIK_RB532; } - strcpy(cp, prom_argv[i]); - cp += strlen(prom_argv[i]); + len = strlen(prom_argv[i]); + memcpy(cp, prom_argv[i], len + 1); + cp += len; } *(cp++) = ' '; - i = strlen(arcs_cmdline); - if (i > 0) { + len = strlen(arcs_cmdline); + if (len > 0) { *(cp++) = ' '; - strcpy(cp, arcs_cmdline); - cp += strlen(arcs_cmdline); + memcpy(cp, arcs_cmdline, len + 1); + cp += len; } cmd_line[COMMAND_LINE_SIZE - 1] = '\0'; - - strcpy(arcs_cmdline, cmd_line); + strscpy(arcs_cmdline, cmd_line); } void __init prom_init(void) From b0d04fe6a633ada2c7bc1b5ddd011cbd85961868 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Fri, 15 Aug 2025 14:12:23 +0200 Subject: [PATCH 0674/2711] mips: lantiq: xway: sysctrl: rename stp clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bindig requires a node name matching ‘^gpio@[0-9a-f]+$’. This patch changes the clock name from “stp” to “gpio”. Signed-off-by: Aleksander Jan Bajkowski Signed-off-by: Thomas Bogendoerfer --- arch/mips/lantiq/xway/sysctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 6031a0272d87..d9aa80afdf9d 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -485,7 +485,7 @@ void __init ltq_soc_init(void) /* add our generic xway clocks */ clkdev_add_pmu("10000000.fpi", NULL, 0, 0, PMU_FPI); clkdev_add_pmu("1e100a00.gptu", NULL, 1, 0, PMU_GPT); - clkdev_add_pmu("1e100bb0.stp", NULL, 1, 0, PMU_STP); + clkdev_add_pmu("1e100bb0.gpio", NULL, 1, 0, PMU_STP); clkdev_add_pmu("1e100c00.serial", NULL, 0, 0, PMU_ASC1); clkdev_add_pmu("1e104100.dma", NULL, 1, 0, PMU_DMA); clkdev_add_pmu("1e100800.spi", NULL, 1, 0, PMU_SPI); From 2b9706ce84be9cb26be03e1ad2e43ec8bc3986be Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Fri, 15 Aug 2025 14:12:24 +0200 Subject: [PATCH 0675/2711] mips: lantiq: danube: rename stp node on EASY50712 reference board This fixes the following warning: arch/mips/boot/dts/lantiq/danube_easy50712.dtb: stp@e100bb0 (lantiq,gpio-stp-xway): $nodename:0: 'stp@e100bb0' does not match '^gpio@[0-9a-f]+$' from schema $id: http://devicetree.org/schemas/gpio/gpio-stp-xway.yaml# Signed-off-by: Aleksander Jan Bajkowski Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/lantiq/danube_easy50712.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/boot/dts/lantiq/danube_easy50712.dts b/arch/mips/boot/dts/lantiq/danube_easy50712.dts index ab70028dbefc..c9f7886f57b8 100644 --- a/arch/mips/boot/dts/lantiq/danube_easy50712.dts +++ b/arch/mips/boot/dts/lantiq/danube_easy50712.dts @@ -96,7 +96,7 @@ lantiq,tx-burst-length = <4>; }; - stp0: stp@e100bb0 { + stp0: gpio@e100bb0 { #gpio-cells = <2>; compatible = "lantiq,gpio-stp-xway"; gpio-controller; From cfbb794c62291cd8249def0d10cae922b717b53e Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 16 Jul 2025 19:25:10 +0800 Subject: [PATCH 0676/2711] dt-bindings: mips: loongson: Add LS1B-DEMO and CQ-T300B Document two Loongson-1 boards: - loongson,ls1b-demo: a board based on Loongson-1B - loongson,cq-t300b: a board based on Loongson-1C Acked-by: Krzysztof Kozlowski Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- Documentation/devicetree/bindings/mips/loongson/devices.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/mips/loongson/devices.yaml b/Documentation/devicetree/bindings/mips/loongson/devices.yaml index 099e40e1482d..ca66bc49c2d6 100644 --- a/Documentation/devicetree/bindings/mips/loongson/devices.yaml +++ b/Documentation/devicetree/bindings/mips/loongson/devices.yaml @@ -40,6 +40,7 @@ properties: - description: LS1B based boards items: - enum: + - loongson,ls1b-demo - loongson,lsgz-1b-dev - const: loongson,ls1b @@ -47,6 +48,7 @@ properties: items: - enum: - loongmasses,smartloong-1c + - loongson,cq-t300b - const: loongson,ls1c additionalProperties: true From 6428fcf27f0248b076b381408c98102f88564926 Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 16 Jul 2025 19:25:11 +0800 Subject: [PATCH 0677/2711] MIPS: dts: loongson: Add LS1B-DEMO board Add a device tree for LS1B-DEMO board, supporting CPU, clock, INTC, UART, Ethernet, GPIO, USB host, RTC, watchdog, DMA, NAND, and AC97. Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- MAINTAINERS | 1 + arch/mips/boot/dts/Makefile | 1 + arch/mips/boot/dts/loongson/Makefile | 2 + arch/mips/boot/dts/loongson/loongson1.dtsi | 136 ++++++++++++++ arch/mips/boot/dts/loongson/loongson1b.dtsi | 198 ++++++++++++++++++++ arch/mips/boot/dts/loongson/ls1b-demo.dts | 125 ++++++++++++ 6 files changed, 463 insertions(+) create mode 100644 arch/mips/boot/dts/loongson/loongson1.dtsi create mode 100644 arch/mips/boot/dts/loongson/loongson1b.dtsi create mode 100644 arch/mips/boot/dts/loongson/ls1b-demo.dts diff --git a/MAINTAINERS b/MAINTAINERS index fed6cd812d79..d72eb564e6ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17016,6 +17016,7 @@ M: Keguang Zhang L: linux-mips@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/*/loongson,ls1*.yaml +F: arch/mips/boot/dts/loongson/loongson1* F: arch/mips/include/asm/mach-loongson32/ F: arch/mips/loongson32/ F: drivers/*/*loongson1* diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile index 7375c6ced82b..6d9dbe945541 100644 --- a/arch/mips/boot/dts/Makefile +++ b/arch/mips/boot/dts/Makefile @@ -8,6 +8,7 @@ subdir-$(CONFIG_FIT_IMAGE_FDT_BOSTON) += img subdir-$(CONFIG_MACH_INGENIC) += ingenic subdir-$(CONFIG_LANTIQ) += lantiq subdir-$(CONFIG_MACH_LOONGSON64) += loongson +subdir-$(CONFIG_MACH_LOONGSON32) += loongson subdir-$(CONFIG_SOC_VCOREIII) += mscc subdir-$(CONFIG_MIPS_MALTA) += mti subdir-$(CONFIG_LEGACY_BOARD_SEAD3) += mti diff --git a/arch/mips/boot/dts/loongson/Makefile b/arch/mips/boot/dts/loongson/Makefile index 5e3ab984d70f..88b87c94c545 100644 --- a/arch/mips/boot/dts/loongson/Makefile +++ b/arch/mips/boot/dts/loongson/Makefile @@ -5,3 +5,5 @@ dtb-$(CONFIG_MACH_LOONGSON64) += loongson64c_4core_rs780e.dtb dtb-$(CONFIG_MACH_LOONGSON64) += loongson64c_8core_rs780e.dtb dtb-$(CONFIG_MACH_LOONGSON64) += loongson64g_4core_ls7a.dtb dtb-$(CONFIG_MACH_LOONGSON64) += loongson64v_4core_virtio.dtb + +dtb-$(CONFIG_MACH_LOONGSON32) += ls1b-demo.dtb diff --git a/arch/mips/boot/dts/loongson/loongson1.dtsi b/arch/mips/boot/dts/loongson/loongson1.dtsi new file mode 100644 index 000000000000..5ba5a5d131ba --- /dev/null +++ b/arch/mips/boot/dts/loongson/loongson1.dtsi @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023-2025 Keguang Zhang + */ + +/dts-v1/; + +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + xtal: clock { + compatible = "fixed-clock"; + clock-output-names = "xtal"; + #clock-cells = <0>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + reg = <0>; + device_type = "cpu"; + clocks = <&clkc LS1X_CLKID_CPU>; + #clock-cells = <1>; + }; + }; + + cpu_intc: interrupt-controller { + compatible = "mti,cpu-interrupt-controller"; + interrupt-controller; + #interrupt-cells = <1>; + #address-cells = <0>; + }; + + soc: bus@1fd00000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1fd00000 0x130000>; + + intc0: interrupt-controller@1040 { + compatible = "loongson,ls1x-intc"; + reg = <0x1040 0x18>; + interrupt-controller; + interrupt-parent = <&cpu_intc>; + interrupts = <2>; + #interrupt-cells = <2>; + }; + + intc1: interrupt-controller@1058 { + compatible = "loongson,ls1x-intc"; + reg = <0x1058 0x18>; + interrupt-controller; + interrupt-parent = <&cpu_intc>; + interrupts = <3>; + #interrupt-cells = <2>; + }; + + intc2: interrupt-controller@1070 { + compatible = "loongson,ls1x-intc"; + reg = <0x1070 0x18>; + interrupt-controller; + interrupt-parent = <&cpu_intc>; + interrupts = <4>; + #interrupt-cells = <2>; + }; + + intc3: interrupt-controller@1088 { + compatible = "loongson,ls1x-intc"; + reg = <0x1088 0x18>; + interrupt-controller; + interrupt-parent = <&cpu_intc>; + interrupts = <5>; + #interrupt-cells = <2>; + }; + + gpio0: gpio@10c0 { + compatible = "loongson,ls1x-gpio"; + reg = <0x10c0 0x4>; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio1: gpio@10c4 { + compatible = "loongson,ls1x-gpio"; + reg = <0x10c4 0x4>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + apb: bus@1fe40000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1fe40000 0xc0000>; + + uart0: serial@0 { + compatible = "ns16550a"; + reg = <0x0 0x8>; + clocks = <&clkc LS1X_CLKID_APB>; + interrupt-parent = <&intc0>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + uart1: serial@4000 { + compatible = "ns16550a"; + reg = <0x4000 0x8>; + clocks = <&clkc LS1X_CLKID_APB>; + interrupt-parent = <&intc0>; + status = "disabled"; + }; + + uart2: serial@8000 { + compatible = "ns16550a"; + reg = <0x8000 0x8>; + clocks = <&clkc LS1X_CLKID_APB>; + interrupt-parent = <&intc0>; + status = "disabled"; + }; + + uart3: serial@c000 { + compatible = "ns16550a"; + reg = <0xc000 0x8>; + clocks = <&clkc LS1X_CLKID_APB>; + interrupt-parent = <&intc0>; + status = "disabled"; + }; + }; +}; diff --git a/arch/mips/boot/dts/loongson/loongson1b.dtsi b/arch/mips/boot/dts/loongson/loongson1b.dtsi new file mode 100644 index 000000000000..776d272b0f43 --- /dev/null +++ b/arch/mips/boot/dts/loongson/loongson1b.dtsi @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023-2025 Keguang Zhang + */ + +/dts-v1/; +#include "loongson1.dtsi" + +/ { + cpu_opp_table: opp-table { + compatible = "operating-points-v2"; + opp-shared; + + opp-44000000 { + opp-hz = /bits/ 64 <44000000>; + }; + opp-47142000 { + opp-hz = /bits/ 64 <47142000>; + }; + opp-50769000 { + opp-hz = /bits/ 64 <50769000>; + }; + opp-55000000 { + opp-hz = /bits/ 64 <55000000>; + }; + opp-60000000 { + opp-hz = /bits/ 64 <60000000>; + }; + opp-66000000 { + opp-hz = /bits/ 64 <66000000>; + }; + opp-73333000 { + opp-hz = /bits/ 64 <73333000>; + }; + opp-82500000 { + opp-hz = /bits/ 64 <82500000>; + }; + opp-94285000 { + opp-hz = /bits/ 64 <94285000>; + }; + opp-110000000 { + opp-hz = /bits/ 64 <110000000>; + }; + opp-132000000 { + opp-hz = /bits/ 64 <132000000>; + }; + opp-165000000 { + opp-hz = /bits/ 64 <165000000>; + }; + opp-220000000 { + opp-hz = /bits/ 64 <220000000>; + }; + }; + + clkc: clock-controller@1fe78030 { + compatible = "loongson,ls1b-clk"; + reg = <0x1fe78030 0x8>; + clocks = <&xtal>; + #clock-cells = <1>; + }; +}; + +&soc { + syscon: syscon@420 { + compatible = "loongson,ls1b-syscon", "syscon"; + reg = <0x420 0x8>; + }; + + dma: dma-controller@1160 { + compatible = "loongson,ls1b-apbdma"; + reg = <0x1160 0x4>; + interrupt-parent = <&intc0>; + interrupts = <13 IRQ_TYPE_EDGE_RISING>, + <14 IRQ_TYPE_EDGE_RISING>, + <15 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ch0", "ch1", "ch2"; + #dma-cells = <1>; + }; + + ehci: usb@100000 { + compatible = "generic-ehci"; + reg = <0x100000 0x100>; + interrupt-parent = <&intc1>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + ohci: usb@108000 { + compatible = "generic-ohci"; + reg = <0x108000 0x100>; + interrupt-parent = <&intc1>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + gmac0: ethernet@110000 { + compatible = "loongson,ls1b-gmac", "snps,dwmac-3.50a"; + reg = <0x110000 0x10000>; + clocks = <&clkc LS1X_CLKID_AHB>; + clock-names = "stmmaceth"; + interrupt-parent = <&intc1>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + loongson,ls1-syscon = <&syscon>; + snps,pbl = <1>; + status = "disabled"; + }; + + gmac1: ethernet@120000 { + compatible = "loongson,ls1b-gmac", "snps,dwmac-3.50a"; + reg = <0x120000 0x10000>; + clocks = <&clkc LS1X_CLKID_AHB>; + clock-names = "stmmaceth"; + interrupt-parent = <&intc1>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + loongson,ls1-syscon = <&syscon>; + snps,pbl = <1>; + status = "disabled"; + }; +}; + +&apb { + clocksource: timer@1c030 { + compatible = "loongson,ls1b-pwmtimer"; + reg = <0x1c030 0x10>; + clocks = <&clkc LS1X_CLKID_APB>; + interrupt-parent = <&intc0>; + interrupts = <20 IRQ_TYPE_LEVEL_HIGH>; + }; + + watchdog: watchdog@1c060 { + compatible = "loongson,ls1b-wdt"; + reg = <0x1c060 0xc>; + clocks = <&clkc LS1X_CLKID_APB>; + status = "disabled"; + }; + + rtc: rtc@24000 { + compatible = "loongson,ls1b-rtc"; + reg = <0x24000 0x78>; + interrupt-parent = <&intc0>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + ac97: audio-controller@34000 { + compatible = "loongson,ls1b-ac97"; + reg = <0x34000 0x60>, <0x32420 0x4>, <0x34c4c 0x4>; + reg-names = "ac97", "audio-tx", "audio-rx"; + dmas = <&dma 1>, <&dma 2>; + dma-names = "tx", "rx"; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + nand: nand-controller@38000 { + compatible = "loongson,ls1b-nand-controller"; + reg = <0x38000 0x24>, <0x38040 0x4>; + reg-names = "nand", "nand-dma"; + dmas = <&dma 0>; + dma-names = "rxtx"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + nand@0 { + reg = <0>; + label = "ls1x-nand"; + nand-use-soft-ecc-engine; + nand-ecc-algo = "hamming"; + }; + }; +}; + +&cpu0 { + operating-points-v2 = <&cpu_opp_table>; +}; + +&gpio0 { + ngpios = <31>; +}; + +&gpio1 { + ngpios = <30>; +}; + +&uart1 { + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; +}; + +&uart2 { + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; +}; + +&uart3 { + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; +}; diff --git a/arch/mips/boot/dts/loongson/ls1b-demo.dts b/arch/mips/boot/dts/loongson/ls1b-demo.dts new file mode 100644 index 000000000000..13f8b102e100 --- /dev/null +++ b/arch/mips/boot/dts/loongson/ls1b-demo.dts @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023-2025 Keguang Zhang + */ + +/dts-v1/; + +#include + +#include "loongson1b.dtsi" + +/ { + compatible = "loongson,ls1b-demo", "loongson,ls1b"; + model = "LS1B-DEMO Board"; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x10000000>; + }; + + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + gpio0 = &gpio0; + gpio1 = &gpio1; + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:38400n8"; + }; + + codec: audio-codec { + compatible = "realtek,alc203"; + #sound-dai-cells = <0>; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "ls1b-alc203"; + simple-audio-card,format = "ac97"; + simple-audio-card,widgets = + "Speaker", "Line Out Jack", + "Headphone", "Headphone Jack", + "Microphone", "Microphone Jack"; + simple-audio-card,routing = + "Line Out Jack", "TX", + "Headphone Jack", "TX", + "RX", "Microphone Jack"; + + simple-audio-card,cpu { + sound-dai = <&ac97>; + }; + + simple-audio-card,codec { + sound-dai = <&codec>; + }; + }; +}; + +&xtal { + clock-frequency = <33000000>; +}; + +&gmac0 { + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + reg = <0x0>; + }; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "kernel"; + reg = <0x0 0x1000000>; + }; + + partition@1000000 { + label = "rootfs"; + reg = <0x1000000 0x7000000>; + }; + }; + }; +}; + +&ac97 { + status = "okay"; +}; + +&ehci { + status = "okay"; +}; + +&ohci { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; From 9c607077294a25bd597cfcfb3f832707b5b88426 Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 16 Jul 2025 19:25:12 +0800 Subject: [PATCH 0678/2711] MIPS: dts: loongson: Add LSGZ_1B_DEV board Add a device tree for LSGZ_1B_DEV board. Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/loongson/Makefile | 1 + arch/mips/boot/dts/loongson/lsgz_1b_dev.dts | 162 ++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 arch/mips/boot/dts/loongson/lsgz_1b_dev.dts diff --git a/arch/mips/boot/dts/loongson/Makefile b/arch/mips/boot/dts/loongson/Makefile index 88b87c94c545..1130efa12768 100644 --- a/arch/mips/boot/dts/loongson/Makefile +++ b/arch/mips/boot/dts/loongson/Makefile @@ -7,3 +7,4 @@ dtb-$(CONFIG_MACH_LOONGSON64) += loongson64g_4core_ls7a.dtb dtb-$(CONFIG_MACH_LOONGSON64) += loongson64v_4core_virtio.dtb dtb-$(CONFIG_MACH_LOONGSON32) += ls1b-demo.dtb +dtb-$(CONFIG_MACH_LOONGSON32) += lsgz_1b_dev.dtb diff --git a/arch/mips/boot/dts/loongson/lsgz_1b_dev.dts b/arch/mips/boot/dts/loongson/lsgz_1b_dev.dts new file mode 100644 index 000000000000..94ec151c0a94 --- /dev/null +++ b/arch/mips/boot/dts/loongson/lsgz_1b_dev.dts @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023-2025 Keguang Zhang + */ + +/dts-v1/; + +#include + +#include "loongson1b.dtsi" + +/ { + compatible = "loongson,lsgz-1b-dev", "loongson,ls1b"; + model = "LSGZ_1B_DEV Board"; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x4000000>; + }; + + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + gpio0 = &gpio0; + gpio1 = &gpio1; + serial0 = &uart2; + serial1 = &uart3; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + led9 { + label = "led9"; + gpios = <&gpio1 6 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + + led6 { + label = "led6"; + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + linux,default-trigger = "nand-disk"; + }; + }; + + codec: audio-codec { + compatible = "realtek,alc203"; + #sound-dai-cells = <0>; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "ls1b-alc655"; + simple-audio-card,format = "ac97"; + simple-audio-card,widgets = + "Speaker", "Line Out Jack", + "Line", "Line In Jack", + "Microphone", "Microphone Jack"; + simple-audio-card,routing = + "Line Out Jack", "TX", + "RX", "Line In Jack", + "RX", "Microphone Jack"; + + simple-audio-card,cpu { + sound-dai = <&ac97>; + }; + + simple-audio-card,codec { + sound-dai = <&codec>; + }; + }; +}; + +&xtal { + clock-frequency = <33000000>; +}; + +&gmac0 { + phy-handle = <&phy0>; + phy-mode = "mii"; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + + phy0: ethernet-phy@0 { + reg = <0x0>; + }; + }; +}; + +&gmac1 { + phy-handle = <&phy1>; + phy-mode = "mii"; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + phy1: ethernet-phy@0 { + reg = <0x0>; + }; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "kernel"; + reg = <0x0 0x1000000>; + }; + + partition@1000000 { + label = "rootfs"; + reg = <0x1000000 0x7000000>; + }; + }; + }; +}; + +&ac97 { + status = "okay"; +}; + +&ehci { + status = "okay"; +}; + +&ohci { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; From cf4b382a92f4fea09f5987e5757b4979fd255cb2 Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 16 Jul 2025 19:25:13 +0800 Subject: [PATCH 0679/2711] MIPS: dts: loongson: Add Smartloong-1C board Add a device tree for Smartloong-1C board, supporting CPU, clock, INTC, UART, Ethernet, GPIO, USB host, RTC, watchdog, DMA, and NAND. Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/loongson/Makefile | 1 + arch/mips/boot/dts/loongson/loongson1c.dtsi | 141 ++++++++++++++++++ arch/mips/boot/dts/loongson/smartloong-1c.dts | 110 ++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 arch/mips/boot/dts/loongson/loongson1c.dtsi create mode 100644 arch/mips/boot/dts/loongson/smartloong-1c.dts diff --git a/arch/mips/boot/dts/loongson/Makefile b/arch/mips/boot/dts/loongson/Makefile index 1130efa12768..de4570380c3e 100644 --- a/arch/mips/boot/dts/loongson/Makefile +++ b/arch/mips/boot/dts/loongson/Makefile @@ -8,3 +8,4 @@ dtb-$(CONFIG_MACH_LOONGSON64) += loongson64v_4core_virtio.dtb dtb-$(CONFIG_MACH_LOONGSON32) += ls1b-demo.dtb dtb-$(CONFIG_MACH_LOONGSON32) += lsgz_1b_dev.dtb +dtb-$(CONFIG_MACH_LOONGSON32) += smartloong-1c.dtb diff --git a/arch/mips/boot/dts/loongson/loongson1c.dtsi b/arch/mips/boot/dts/loongson/loongson1c.dtsi new file mode 100644 index 000000000000..5e80c6a657af --- /dev/null +++ b/arch/mips/boot/dts/loongson/loongson1c.dtsi @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023-2025 Keguang Zhang + */ + +/dts-v1/; +#include "loongson1.dtsi" + +/ { + clkc: clock-controller@1fe78030 { + compatible = "loongson,ls1c-clk"; + reg = <0x1fe78030 0x8>; + clocks = <&xtal>; + #clock-cells = <1>; + }; +}; + +&soc { + syscon: syscon@420 { + compatible = "loongson,ls1c-syscon", "syscon"; + reg = <0x420 0x8>; + }; + + intc4: interrupt-controller@10a0 { + compatible = "loongson,ls1x-intc"; + reg = <0x10a0 0x18>; + interrupt-controller; + interrupt-parent = <&cpu_intc>; + interrupts = <6>; + #interrupt-cells = <2>; + }; + + gpio2: gpio@10c8 { + compatible = "loongson,ls1x-gpio"; + reg = <0x10c8 0x4>; + gpio-controller; + ngpios = <32>; + #gpio-cells = <2>; + }; + + gpio3: gpio@10cc { + compatible = "loongson,ls1x-gpio"; + reg = <0x10cc 0x4>; + gpio-controller; + ngpios = <32>; + #gpio-cells = <2>; + }; + + dma: dma-controller@1160 { + compatible = "loongson,ls1c-apbdma", "loongson,ls1b-apbdma"; + reg = <0x1160 0x4>; + interrupt-parent = <&intc0>; + interrupts = <13 IRQ_TYPE_EDGE_RISING>, + <14 IRQ_TYPE_EDGE_RISING>, + <15 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ch0", "ch1", "ch2"; + #dma-cells = <1>; + }; + + emac: ethernet@110000 { + compatible = "loongson,ls1c-emac", "snps,dwmac-3.50a"; + reg = <0x110000 0x10000>; + clocks = <&clkc LS1X_CLKID_AHB>; + clock-names = "stmmaceth"; + interrupt-parent = <&intc1>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + loongson,ls1-syscon = <&syscon>; + snps,pbl = <1>; + status = "disabled"; + }; + + ehci: usb@120000 { + compatible = "generic-ehci"; + reg = <0x120000 0x100>; + interrupt-parent = <&intc1>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + ohci: usb@128000 { + compatible = "generic-ohci"; + reg = <0x128000 0x100>; + interrupt-parent = <&intc1>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; +}; + +&apb { + watchdog: watchdog@1c060 { + compatible = "loongson,ls1c-wdt"; + reg = <0x1c060 0xc>; + clocks = <&clkc LS1X_CLKID_APB>; + status = "disabled"; + }; + + rtc: rtc@24000 { + compatible = "loongson,ls1c-rtc"; + reg = <0x24000 0x78>; + status = "disabled"; + }; + + nand: nand-controller@38000 { + compatible = "loongson,ls1c-nand-controller"; + reg = <0x38000 0x24>, <0x38040 0x4>; + reg-names = "nand", "nand-dma"; + dmas = <&dma 0>; + dma-names = "rxtx"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + nand@0 { + reg = <0>; + label = "ls1x-nand"; + nand-use-soft-ecc-engine; + nand-ecc-algo = "hamming"; + }; + }; +}; + +&gpio0 { + ngpios = <32>; +}; + +&gpio1 { + ngpios = <32>; +}; + +&uart1 { + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; +}; + +&uart2 { + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; +}; + +&uart3 { + interrupts = <29 IRQ_TYPE_LEVEL_HIGH>; +}; diff --git a/arch/mips/boot/dts/loongson/smartloong-1c.dts b/arch/mips/boot/dts/loongson/smartloong-1c.dts new file mode 100644 index 000000000000..e6c6c2f00c42 --- /dev/null +++ b/arch/mips/boot/dts/loongson/smartloong-1c.dts @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023-2025 Keguang Zhang + */ + +/dts-v1/; + +#include + +#include "loongson1c.dtsi" + +/ { + compatible = "loongmasses,smartloong-1c", "loongson,ls1c"; + model = "Smartloong-1C Board"; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x4000000>; + }; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + serial0 = &uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + led0 { + label = "led0"; + gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + + led1 { + label = "led1"; + gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; + linux,default-trigger = "nand-disk"; + }; + }; +}; + +&xtal { + clock-frequency = <24000000>; +}; + +&emac { + phy-handle = <&phy0>; + phy-mode = "rmii"; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@13 { + reg = <0x13>; + }; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "kernel"; + reg = <0x0 0x1000000>; + }; + + partition@1000000 { + label = "rootfs"; + reg = <0x1000000 0x7000000>; + }; + }; + }; +}; + +&ehci { + status = "okay"; +}; + +&ohci { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; From 11741215e287454bd4c6e9a4872790a1a2c0e0ae Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 16 Jul 2025 19:25:14 +0800 Subject: [PATCH 0680/2711] MIPS: dts: loongson: Add CQ-T300B board Add a device tree for CQ-T300B board. Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/loongson/Makefile | 1 + arch/mips/boot/dts/loongson/cq-t300b.dts | 110 +++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 arch/mips/boot/dts/loongson/cq-t300b.dts diff --git a/arch/mips/boot/dts/loongson/Makefile b/arch/mips/boot/dts/loongson/Makefile index de4570380c3e..e8f76e7ac303 100644 --- a/arch/mips/boot/dts/loongson/Makefile +++ b/arch/mips/boot/dts/loongson/Makefile @@ -6,6 +6,7 @@ dtb-$(CONFIG_MACH_LOONGSON64) += loongson64c_8core_rs780e.dtb dtb-$(CONFIG_MACH_LOONGSON64) += loongson64g_4core_ls7a.dtb dtb-$(CONFIG_MACH_LOONGSON64) += loongson64v_4core_virtio.dtb +dtb-$(CONFIG_MACH_LOONGSON32) += cq-t300b.dtb dtb-$(CONFIG_MACH_LOONGSON32) += ls1b-demo.dtb dtb-$(CONFIG_MACH_LOONGSON32) += lsgz_1b_dev.dtb dtb-$(CONFIG_MACH_LOONGSON32) += smartloong-1c.dtb diff --git a/arch/mips/boot/dts/loongson/cq-t300b.dts b/arch/mips/boot/dts/loongson/cq-t300b.dts new file mode 100644 index 000000000000..5244fab2496d --- /dev/null +++ b/arch/mips/boot/dts/loongson/cq-t300b.dts @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023-2025 Keguang Zhang + */ + +/dts-v1/; + +#include + +#include "loongson1c.dtsi" + +/ { + compatible = "loongson,cq-t300b", "loongson,ls1c"; + model = "CQ-T300B Board"; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x8000000>; + }; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + serial0 = &uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + led0 { + label = "led0"; + gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + + led1 { + label = "led1"; + gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; + linux,default-trigger = "nand-disk"; + }; + }; +}; + +&xtal { + clock-frequency = <24000000>; +}; + +&emac { + phy-handle = <&phy0>; + phy-mode = "rmii"; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@13 { + reg = <0x13>; + }; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "kernel"; + reg = <0x0 0x1000000>; + }; + + partition@1000000 { + label = "rootfs"; + reg = <0x1000000 0x3f000000>; + }; + }; + }; +}; + +&ehci { + status = "okay"; +}; + +&ohci { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; From ec7c2a107a59a60079eff3308e791a3441231f2e Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 16 Jul 2025 19:25:15 +0800 Subject: [PATCH 0681/2711] MIPS: loongson: Add built-in DTB support Since the current bootloader for Loongson-1 does not support FDT, introduce CONFIG_BUILTIN_DTB_NAME to enable a built-in DTB. Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/loongson/Makefile | 5 +++++ arch/mips/loongson32/Kconfig | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/arch/mips/boot/dts/loongson/Makefile b/arch/mips/boot/dts/loongson/Makefile index e8f76e7ac303..8ee12504d353 100644 --- a/arch/mips/boot/dts/loongson/Makefile +++ b/arch/mips/boot/dts/loongson/Makefile @@ -1,4 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 + +ifneq ($(CONFIG_BUILTIN_DTB_NAME),) +dtb-y := $(addsuffix .dtb, $(CONFIG_BUILTIN_DTB_NAME)) +else dtb-$(CONFIG_MACH_LOONGSON64) += loongson64_2core_2k1000.dtb dtb-$(CONFIG_MACH_LOONGSON64) += loongson64c_4core_ls7a.dtb dtb-$(CONFIG_MACH_LOONGSON64) += loongson64c_4core_rs780e.dtb @@ -10,3 +14,4 @@ dtb-$(CONFIG_MACH_LOONGSON32) += cq-t300b.dtb dtb-$(CONFIG_MACH_LOONGSON32) += ls1b-demo.dtb dtb-$(CONFIG_MACH_LOONGSON32) += lsgz_1b_dev.dtb dtb-$(CONFIG_MACH_LOONGSON32) += smartloong-1c.dtb +endif diff --git a/arch/mips/loongson32/Kconfig b/arch/mips/loongson32/Kconfig index a7c500959577..52e925309f15 100644 --- a/arch/mips/loongson32/Kconfig +++ b/arch/mips/loongson32/Kconfig @@ -36,3 +36,11 @@ config LOONGSON1_LS1C endchoice endif # MACH_LOONGSON32 + +config BUILTIN_DTB_NAME + string "Source file for built-in DTB" + depends on BUILTIN_DTB + help + Base name (without suffix, relative to arch/mips/boot/dts/loongson) + for the DTS file that will be used to produce the DTB linked into + the kernel. From 85c4354076ca2f84f6473073005174905880e998 Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 16 Jul 2025 19:25:16 +0800 Subject: [PATCH 0682/2711] MIPS: loongson32: Switch to generic core The generic MIPS core is fully compatible with Loongson-1 SoCs, so migrate Loongson-1 to it. Main changes are: - Merge CPU_LOONGSON1B and CPU_LOONGSON1C into a unified CPU_LOONGSON32, as both are based on the GS232 core. - Consolidate LOONGSON1_LS1B and LOONGSON1_LS1C Kconfig options into MACH_LOONGSON32. - Enable MACH_GENERIC_CORE and remove the legacy custom implementation. - Remove all Loongson-1 platform devices and associated code, which are now obsolete due to Device Tree support. - Misc cleanup. Partially based on earlier work by Jiaxun Yang. Link: https://lore.kernel.org/all/20190411121915.8040-4-jiaxun.yang@flygoat.com/ Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- MAINTAINERS | 1 - arch/mips/Kconfig | 64 ++-- arch/mips/include/asm/cpu-type.h | 3 +- arch/mips/include/asm/mach-loongson32/irq.h | 107 ------- .../include/asm/mach-loongson32/loongson1.h | 50 --- .../include/asm/mach-loongson32/platform.h | 23 -- .../include/asm/mach-loongson32/regs-mux.h | 124 -------- arch/mips/loongson32/Kconfig | 37 --- arch/mips/loongson32/Makefile | 17 -- arch/mips/loongson32/Platform | 1 - arch/mips/loongson32/common/Makefile | 6 - arch/mips/loongson32/common/irq.c | 191 ------------ arch/mips/loongson32/common/platform.c | 285 ------------------ arch/mips/loongson32/common/prom.c | 42 --- arch/mips/loongson32/common/setup.c | 26 -- arch/mips/loongson32/common/time.c | 23 -- arch/mips/loongson32/ls1b/Makefile | 6 - arch/mips/loongson32/ls1b/board.c | 55 ---- arch/mips/loongson32/ls1c/Makefile | 6 - arch/mips/loongson32/ls1c/board.c | 23 -- 20 files changed, 33 insertions(+), 1057 deletions(-) delete mode 100644 arch/mips/include/asm/mach-loongson32/irq.h delete mode 100644 arch/mips/include/asm/mach-loongson32/loongson1.h delete mode 100644 arch/mips/include/asm/mach-loongson32/platform.h delete mode 100644 arch/mips/include/asm/mach-loongson32/regs-mux.h delete mode 100644 arch/mips/loongson32/common/Makefile delete mode 100644 arch/mips/loongson32/common/irq.c delete mode 100644 arch/mips/loongson32/common/platform.c delete mode 100644 arch/mips/loongson32/common/prom.c delete mode 100644 arch/mips/loongson32/common/setup.c delete mode 100644 arch/mips/loongson32/common/time.c delete mode 100644 arch/mips/loongson32/ls1b/Makefile delete mode 100644 arch/mips/loongson32/ls1b/board.c delete mode 100644 arch/mips/loongson32/ls1c/Makefile delete mode 100644 arch/mips/loongson32/ls1c/board.c diff --git a/MAINTAINERS b/MAINTAINERS index d72eb564e6ba..b5e33faf2a3f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17017,7 +17017,6 @@ L: linux-mips@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/*/loongson,ls1*.yaml F: arch/mips/boot/dts/loongson/loongson1* -F: arch/mips/include/asm/mach-loongson32/ F: arch/mips/loongson32/ F: drivers/*/*loongson1* F: drivers/mtd/nand/raw/loongson1-nand-controller.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index caf508f6e9ec..4142896c7c3d 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -480,6 +480,23 @@ config LANTIQ config MACH_LOONGSON32 bool "Loongson 32-bit family of machines" + select MACH_GENERIC_CORE + select USE_OF + select BUILTIN_DTB + select BOOT_ELF32 + select CEVT_R4K + select CSRC_R4K + select COMMON_CLK + select DMA_NONCOHERENT + select GENERIC_IRQ_SHOW_LEVEL + select IRQ_MIPS_CPU + select LS1X_IRQ + select SYS_HAS_CPU_LOONGSON32 + select SYS_HAS_EARLY_PRINTK + select USE_GENERIC_EARLY_PRINTK_8250 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_HIGHMEM select SYS_SUPPORTS_ZBOOT help This enables support for the Loongson-1 family of machines. @@ -1386,25 +1403,20 @@ config CPU_LOONGSON2F have a similar programming interface with FPGA northbridge used in Loongson2E. -config CPU_LOONGSON1B - bool "Loongson 1B" - depends on SYS_HAS_CPU_LOONGSON1B - select CPU_LOONGSON32 +config CPU_LOONGSON32 + bool "Loongson 32-bit CPU" + depends on SYS_HAS_CPU_LOONGSON32 + select CPU_MIPS32 + select CPU_MIPSR2 + select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + select CPU_SUPPORTS_CPUFREQ select LEDS_GPIO_REGISTER help - The Loongson 1B is a 32-bit SoC, which implements the MIPS32 - Release 1 instruction set and part of the MIPS32 Release 2 - instruction set. - -config CPU_LOONGSON1C - bool "Loongson 1C" - depends on SYS_HAS_CPU_LOONGSON1C - select CPU_LOONGSON32 - select LEDS_GPIO_REGISTER - help - The Loongson 1C is a 32-bit SoC, which implements the MIPS32 - Release 1 instruction set and part of the MIPS32 Release 2 - instruction set. + The Loongson GS232 microarchitecture implements the MIPS32 Release 1 + instruction set and part of the MIPS32 Release 2 instruction set. config CPU_MIPS32_R1 bool "MIPS32 Release 1" @@ -1839,15 +1851,6 @@ config CPU_LOONGSON2EF select CPU_SUPPORTS_HUGEPAGES select RTC_MC146818_LIB -config CPU_LOONGSON32 - bool - select CPU_MIPS32 - select CPU_MIPSR2 - select CPU_HAS_PREFETCH - select CPU_SUPPORTS_32BIT_KERNEL - select CPU_SUPPORTS_HIGHMEM - select CPU_SUPPORTS_CPUFREQ - config CPU_BMIPS32_3300 select SMP_UP if SMP bool @@ -1885,10 +1888,7 @@ config SYS_HAS_CPU_LOONGSON2F select CPU_SUPPORTS_CPUFREQ select CPU_SUPPORTS_ADDRWINCFG if 64BIT -config SYS_HAS_CPU_LOONGSON1B - bool - -config SYS_HAS_CPU_LOONGSON1C +config SYS_HAS_CPU_LOONGSON32 bool config SYS_HAS_CPU_MIPS32_R1 @@ -2999,8 +2999,8 @@ choice prompt "Kernel command line type" depends on !CMDLINE_OVERRIDE default MIPS_CMDLINE_FROM_DTB if USE_OF && !ATH79 && !MACH_INGENIC && \ - !MACH_LOONGSON64 && !MIPS_MALTA && \ - !CAVIUM_OCTEON_SOC + !MACH_LOONGSON64 && !MACH_LOONGSON32 && \ + !MIPS_MALTA && !CAVIUM_OCTEON_SOC default MIPS_CMDLINE_FROM_BOOTLOADER config MIPS_CMDLINE_FROM_DTB diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h index a4a66bd93748..fd37a44a2f19 100644 --- a/arch/mips/include/asm/cpu-type.h +++ b/arch/mips/include/asm/cpu-type.h @@ -24,8 +24,7 @@ static inline int __pure __get_cpu_type(const int cpu_type) case CPU_LOONGSON64: #endif -#if defined(CONFIG_SYS_HAS_CPU_LOONGSON1B) || \ - defined(CONFIG_SYS_HAS_CPU_LOONGSON1C) +#ifdef CONFIG_SYS_HAS_CPU_LOONGSON32 case CPU_LOONGSON32: #endif diff --git a/arch/mips/include/asm/mach-loongson32/irq.h b/arch/mips/include/asm/mach-loongson32/irq.h deleted file mode 100644 index 6115f025ba21..000000000000 --- a/arch/mips/include/asm/mach-loongson32/irq.h +++ /dev/null @@ -1,107 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (c) 2011 Zhang, Keguang - * - * IRQ mappings for Loongson 1 - */ - -#ifndef __ASM_MACH_LOONGSON32_IRQ_H -#define __ASM_MACH_LOONGSON32_IRQ_H - -/* - * CPU core Interrupt Numbers - */ -#define MIPS_CPU_IRQ_BASE 0 -#define MIPS_CPU_IRQ(x) (MIPS_CPU_IRQ_BASE + (x)) - -#define SOFTINT0_IRQ MIPS_CPU_IRQ(0) -#define SOFTINT1_IRQ MIPS_CPU_IRQ(1) -#define INT0_IRQ MIPS_CPU_IRQ(2) -#define INT1_IRQ MIPS_CPU_IRQ(3) -#define INT2_IRQ MIPS_CPU_IRQ(4) -#define INT3_IRQ MIPS_CPU_IRQ(5) -#define INT4_IRQ MIPS_CPU_IRQ(6) -#define TIMER_IRQ MIPS_CPU_IRQ(7) /* cpu timer */ - -#define MIPS_CPU_IRQS (MIPS_CPU_IRQ(7) + 1 - MIPS_CPU_IRQ_BASE) - -/* - * INT0~3 Interrupt Numbers - */ -#define LS1X_IRQ_BASE MIPS_CPU_IRQS -#define LS1X_IRQ(n, x) (LS1X_IRQ_BASE + (n << 5) + (x)) - -#define LS1X_UART0_IRQ LS1X_IRQ(0, 2) -#if defined(CONFIG_LOONGSON1_LS1B) -#define LS1X_UART1_IRQ LS1X_IRQ(0, 3) -#define LS1X_UART2_IRQ LS1X_IRQ(0, 4) -#define LS1X_UART3_IRQ LS1X_IRQ(0, 5) -#elif defined(CONFIG_LOONGSON1_LS1C) -#define LS1X_UART1_IRQ LS1X_IRQ(0, 4) -#define LS1X_UART2_IRQ LS1X_IRQ(0, 5) -#endif -#define LS1X_CAN0_IRQ LS1X_IRQ(0, 6) -#define LS1X_CAN1_IRQ LS1X_IRQ(0, 7) -#define LS1X_SPI0_IRQ LS1X_IRQ(0, 8) -#define LS1X_SPI1_IRQ LS1X_IRQ(0, 9) -#define LS1X_AC97_IRQ LS1X_IRQ(0, 10) -#define LS1X_DMA0_IRQ LS1X_IRQ(0, 13) -#define LS1X_DMA1_IRQ LS1X_IRQ(0, 14) -#define LS1X_DMA2_IRQ LS1X_IRQ(0, 15) -#if defined(CONFIG_LOONGSON1_LS1C) -#define LS1X_NAND_IRQ LS1X_IRQ(0, 16) -#endif -#define LS1X_PWM0_IRQ LS1X_IRQ(0, 17) -#define LS1X_PWM1_IRQ LS1X_IRQ(0, 18) -#define LS1X_PWM2_IRQ LS1X_IRQ(0, 19) -#define LS1X_PWM3_IRQ LS1X_IRQ(0, 20) -#define LS1X_RTC_INT0_IRQ LS1X_IRQ(0, 21) -#define LS1X_RTC_INT1_IRQ LS1X_IRQ(0, 22) -#define LS1X_RTC_INT2_IRQ LS1X_IRQ(0, 23) -#if defined(CONFIG_LOONGSON1_LS1B) -#define LS1X_TOY_INT0_IRQ LS1X_IRQ(0, 24) -#define LS1X_TOY_INT1_IRQ LS1X_IRQ(0, 25) -#define LS1X_TOY_INT2_IRQ LS1X_IRQ(0, 26) -#define LS1X_RTC_TICK_IRQ LS1X_IRQ(0, 27) -#define LS1X_TOY_TICK_IRQ LS1X_IRQ(0, 28) -#define LS1X_UART4_IRQ LS1X_IRQ(0, 29) -#define LS1X_UART5_IRQ LS1X_IRQ(0, 30) -#elif defined(CONFIG_LOONGSON1_LS1C) -#define LS1X_UART3_IRQ LS1X_IRQ(0, 29) -#define LS1X_ADC_IRQ LS1X_IRQ(0, 30) -#define LS1X_SDIO_IRQ LS1X_IRQ(0, 31) -#endif - -#define LS1X_EHCI_IRQ LS1X_IRQ(1, 0) -#define LS1X_OHCI_IRQ LS1X_IRQ(1, 1) -#if defined(CONFIG_LOONGSON1_LS1B) -#define LS1X_GMAC0_IRQ LS1X_IRQ(1, 2) -#define LS1X_GMAC1_IRQ LS1X_IRQ(1, 3) -#elif defined(CONFIG_LOONGSON1_LS1C) -#define LS1X_OTG_IRQ LS1X_IRQ(1, 2) -#define LS1X_GMAC0_IRQ LS1X_IRQ(1, 3) -#define LS1X_CAM_IRQ LS1X_IRQ(1, 4) -#define LS1X_UART4_IRQ LS1X_IRQ(1, 5) -#define LS1X_UART5_IRQ LS1X_IRQ(1, 6) -#define LS1X_UART6_IRQ LS1X_IRQ(1, 7) -#define LS1X_UART7_IRQ LS1X_IRQ(1, 8) -#define LS1X_UART8_IRQ LS1X_IRQ(1, 9) -#define LS1X_UART9_IRQ LS1X_IRQ(1, 13) -#define LS1X_UART10_IRQ LS1X_IRQ(1, 14) -#define LS1X_UART11_IRQ LS1X_IRQ(1, 15) -#define LS1X_I2C0_IRQ LS1X_IRQ(1, 17) -#define LS1X_I2C1_IRQ LS1X_IRQ(1, 18) -#define LS1X_I2C2_IRQ LS1X_IRQ(1, 19) -#endif - -#if defined(CONFIG_LOONGSON1_LS1B) -#define INTN 4 -#elif defined(CONFIG_LOONGSON1_LS1C) -#define INTN 5 -#endif - -#define LS1X_IRQS (LS1X_IRQ(INTN, 31) + 1 - LS1X_IRQ_BASE) - -#define NR_IRQS (MIPS_CPU_IRQS + LS1X_IRQS) - -#endif /* __ASM_MACH_LOONGSON32_IRQ_H */ diff --git a/arch/mips/include/asm/mach-loongson32/loongson1.h b/arch/mips/include/asm/mach-loongson32/loongson1.h deleted file mode 100644 index 84f45461c832..000000000000 --- a/arch/mips/include/asm/mach-loongson32/loongson1.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (c) 2011 Zhang, Keguang - * - * Register mappings for Loongson 1 - */ - -#ifndef __ASM_MACH_LOONGSON32_LOONGSON1_H -#define __ASM_MACH_LOONGSON32_LOONGSON1_H - -#if defined(CONFIG_LOONGSON1_LS1B) -#define DEFAULT_MEMSIZE 64 /* If no memsize provided */ -#elif defined(CONFIG_LOONGSON1_LS1C) -#define DEFAULT_MEMSIZE 32 -#endif - -/* Loongson 1 Register Bases */ -#define LS1X_MUX_BASE 0x1fd00420 -#define LS1X_INTC_BASE 0x1fd01040 -#define LS1X_GPIO0_BASE 0x1fd010c0 -#define LS1X_GPIO1_BASE 0x1fd010c4 -#define LS1X_DMAC_BASE 0x1fd01160 -#define LS1X_CBUS_BASE 0x1fd011c0 -#define LS1X_EHCI_BASE 0x1fe00000 -#define LS1X_OHCI_BASE 0x1fe08000 -#define LS1X_GMAC0_BASE 0x1fe10000 -#define LS1X_GMAC1_BASE 0x1fe20000 - -#define LS1X_UART0_BASE 0x1fe40000 -#define LS1X_UART1_BASE 0x1fe44000 -#define LS1X_UART2_BASE 0x1fe48000 -#define LS1X_UART3_BASE 0x1fe4c000 -#define LS1X_CAN0_BASE 0x1fe50000 -#define LS1X_CAN1_BASE 0x1fe54000 -#define LS1X_I2C0_BASE 0x1fe58000 -#define LS1X_I2C1_BASE 0x1fe68000 -#define LS1X_I2C2_BASE 0x1fe70000 -#define LS1X_PWM0_BASE 0x1fe5c000 -#define LS1X_PWM1_BASE 0x1fe5c010 -#define LS1X_PWM2_BASE 0x1fe5c020 -#define LS1X_PWM3_BASE 0x1fe5c030 -#define LS1X_WDT_BASE 0x1fe5c060 -#define LS1X_RTC_BASE 0x1fe64000 -#define LS1X_AC97_BASE 0x1fe74000 -#define LS1X_NAND_BASE 0x1fe78000 -#define LS1X_CLK_BASE 0x1fe78030 - -#include - -#endif /* __ASM_MACH_LOONGSON32_LOONGSON1_H */ diff --git a/arch/mips/include/asm/mach-loongson32/platform.h b/arch/mips/include/asm/mach-loongson32/platform.h deleted file mode 100644 index f74292b13bc3..000000000000 --- a/arch/mips/include/asm/mach-loongson32/platform.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (c) 2011 Zhang, Keguang - */ - -#ifndef __ASM_MACH_LOONGSON32_PLATFORM_H -#define __ASM_MACH_LOONGSON32_PLATFORM_H - -#include - -extern struct platform_device ls1x_uart_pdev; -extern struct platform_device ls1x_eth0_pdev; -extern struct platform_device ls1x_eth1_pdev; -extern struct platform_device ls1x_ehci_pdev; -extern struct platform_device ls1x_gpio0_pdev; -extern struct platform_device ls1x_gpio1_pdev; -extern struct platform_device ls1x_rtc_pdev; -extern struct platform_device ls1x_wdt_pdev; - -void __init ls1x_rtc_set_extclk(struct platform_device *pdev); -void __init ls1x_serial_set_uartclk(struct platform_device *pdev); - -#endif /* __ASM_MACH_LOONGSON32_PLATFORM_H */ diff --git a/arch/mips/include/asm/mach-loongson32/regs-mux.h b/arch/mips/include/asm/mach-loongson32/regs-mux.h deleted file mode 100644 index 95788a4f03a0..000000000000 --- a/arch/mips/include/asm/mach-loongson32/regs-mux.h +++ /dev/null @@ -1,124 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (c) 2014 Zhang, Keguang - * - * Loongson 1 MUX Register Definitions. - */ - -#ifndef __ASM_MACH_LOONGSON32_REGS_MUX_H -#define __ASM_MACH_LOONGSON32_REGS_MUX_H - -#define LS1X_MUX_REG(x) \ - ((void __iomem *)KSEG1ADDR(LS1X_MUX_BASE + (x))) - -#define LS1X_MUX_CTRL0 LS1X_MUX_REG(0x0) -#define LS1X_MUX_CTRL1 LS1X_MUX_REG(0x4) - -#if defined(CONFIG_LOONGSON1_LS1B) -/* MUX CTRL0 Register Bits */ -#define UART0_USE_PWM23 BIT(28) -#define UART0_USE_PWM01 BIT(27) -#define UART1_USE_LCD0_5_6_11 BIT(26) -#define I2C2_USE_CAN1 BIT(25) -#define I2C1_USE_CAN0 BIT(24) -#define NAND3_USE_UART5 BIT(23) -#define NAND3_USE_UART4 BIT(22) -#define NAND3_USE_UART1_DAT BIT(21) -#define NAND3_USE_UART1_CTS BIT(20) -#define NAND3_USE_PWM23 BIT(19) -#define NAND3_USE_PWM01 BIT(18) -#define NAND2_USE_UART5 BIT(17) -#define NAND2_USE_UART4 BIT(16) -#define NAND2_USE_UART1_DAT BIT(15) -#define NAND2_USE_UART1_CTS BIT(14) -#define NAND2_USE_PWM23 BIT(13) -#define NAND2_USE_PWM01 BIT(12) -#define NAND1_USE_UART5 BIT(11) -#define NAND1_USE_UART4 BIT(10) -#define NAND1_USE_UART1_DAT BIT(9) -#define NAND1_USE_UART1_CTS BIT(8) -#define NAND1_USE_PWM23 BIT(7) -#define NAND1_USE_PWM01 BIT(6) -#define GMAC1_USE_UART1 BIT(4) -#define GMAC1_USE_UART0 BIT(3) -#define LCD_USE_UART0_DAT BIT(2) -#define LCD_USE_UART15 BIT(1) -#define LCD_USE_UART0 BIT(0) - -/* MUX CTRL1 Register Bits */ -#define USB_RESET BIT(31) -#define SPI1_CS_USE_PWM01 BIT(24) -#define SPI1_USE_CAN BIT(23) -#define DISABLE_DDR_CONFSPACE BIT(20) -#define DDR32TO16EN BIT(16) -#define GMAC1_SHUT BIT(13) -#define GMAC0_SHUT BIT(12) -#define USB_SHUT BIT(11) -#define UART1_3_USE_CAN1 BIT(5) -#define UART1_2_USE_CAN0 BIT(4) -#define GMAC1_USE_TXCLK BIT(3) -#define GMAC0_USE_TXCLK BIT(2) -#define GMAC1_USE_PWM23 BIT(1) -#define GMAC0_USE_PWM01 BIT(0) - -#elif defined(CONFIG_LOONGSON1_LS1C) - -/* SHUT_CTRL Register Bits */ -#define UART_SPLIT GENMASK(31, 30) -#define OUTPUT_CLK GENMASK(29, 26) -#define ADC_SHUT BIT(25) -#define SDIO_SHUT BIT(24) -#define DMA2_SHUT BIT(23) -#define DMA1_SHUT BIT(22) -#define DMA0_SHUT BIT(21) -#define SPI1_SHUT BIT(20) -#define SPI0_SHUT BIT(19) -#define I2C2_SHUT BIT(18) -#define I2C1_SHUT BIT(17) -#define I2C0_SHUT BIT(16) -#define AC97_SHUT BIT(15) -#define I2S_SHUT BIT(14) -#define UART3_SHUT BIT(13) -#define UART2_SHUT BIT(12) -#define UART1_SHUT BIT(11) -#define UART0_SHUT BIT(10) -#define CAN1_SHUT BIT(9) -#define CAN0_SHUT BIT(8) -#define ECC_SHUT BIT(7) -#define GMAC_SHUT BIT(6) -#define USBHOST_SHUT BIT(5) -#define USBOTG_SHUT BIT(4) -#define SDRAM_SHUT BIT(3) -#define SRAM_SHUT BIT(2) -#define CAM_SHUT BIT(1) -#define LCD_SHUT BIT(0) - -#define UART_SPLIT_SHIFT 30 -#define OUTPUT_CLK_SHIFT 26 - -/* MISC_CTRL Register Bits */ -#define USBHOST_RSTN BIT(31) -#define PHY_INTF_SELI GENMASK(30, 28) -#define AC97_EN BIT(25) -#define SDIO_DMA_EN GENMASK(24, 23) -#define ADC_DMA_EN BIT(22) -#define SDIO_USE_SPI1 BIT(17) -#define SDIO_USE_SPI0 BIT(16) -#define SRAM_CTRL GENMASK(15, 0) - -#define PHY_INTF_SELI_SHIFT 28 -#define SDIO_DMA_EN_SHIFT 23 -#define SRAM_CTRL_SHIFT 0 - -#define LS1X_CBUS_REG(n, x) \ - ((void __iomem *)KSEG1ADDR(LS1X_CBUS_BASE + (n * 0x04) + (x))) - -#define LS1X_CBUS_FIRST(n) LS1X_CBUS_REG(n, 0x00) -#define LS1X_CBUS_SECOND(n) LS1X_CBUS_REG(n, 0x10) -#define LS1X_CBUS_THIRD(n) LS1X_CBUS_REG(n, 0x20) -#define LS1X_CBUS_FOURTHT(n) LS1X_CBUS_REG(n, 0x30) -#define LS1X_CBUS_FIFTHT(n) LS1X_CBUS_REG(n, 0x40) - -#endif - -#endif /* __ASM_MACH_LOONGSON32_REGS_MUX_H */ diff --git a/arch/mips/loongson32/Kconfig b/arch/mips/loongson32/Kconfig index 52e925309f15..461d518b0033 100644 --- a/arch/mips/loongson32/Kconfig +++ b/arch/mips/loongson32/Kconfig @@ -1,41 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -if MACH_LOONGSON32 - -choice - prompt "Machine Type" - -config LOONGSON1_LS1B - bool "Loongson LS1B board" - select CEVT_R4K if !MIPS_EXTERNAL_TIMER - select CSRC_R4K if !MIPS_EXTERNAL_TIMER - select SYS_HAS_CPU_LOONGSON1B - select DMA_NONCOHERENT - select BOOT_ELF32 - select IRQ_MIPS_CPU - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_LITTLE_ENDIAN - select SYS_SUPPORTS_HIGHMEM - select SYS_HAS_EARLY_PRINTK - select USE_GENERIC_EARLY_PRINTK_8250 - select COMMON_CLK - -config LOONGSON1_LS1C - bool "Loongson LS1C board" - select CEVT_R4K if !MIPS_EXTERNAL_TIMER - select CSRC_R4K if !MIPS_EXTERNAL_TIMER - select SYS_HAS_CPU_LOONGSON1C - select DMA_NONCOHERENT - select BOOT_ELF32 - select IRQ_MIPS_CPU - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_LITTLE_ENDIAN - select SYS_SUPPORTS_HIGHMEM - select SYS_HAS_EARLY_PRINTK - select USE_GENERIC_EARLY_PRINTK_8250 - select COMMON_CLK -endchoice - -endif # MACH_LOONGSON32 config BUILTIN_DTB_NAME string "Source file for built-in DTB" diff --git a/arch/mips/loongson32/Makefile b/arch/mips/loongson32/Makefile index ba10954b4b21..a4e40e534e6a 100644 --- a/arch/mips/loongson32/Makefile +++ b/arch/mips/loongson32/Makefile @@ -1,18 +1 @@ # SPDX-License-Identifier: GPL-2.0-only -# -# Common code for all Loongson 1 based systems -# - -obj-$(CONFIG_MACH_LOONGSON32) += common/ - -# -# Loongson LS1B board -# - -obj-$(CONFIG_LOONGSON1_LS1B) += ls1b/ - -# -# Loongson LS1C board -# - -obj-$(CONFIG_LOONGSON1_LS1C) += ls1c/ diff --git a/arch/mips/loongson32/Platform b/arch/mips/loongson32/Platform index 3b9673e7a2fa..67fd07450488 100644 --- a/arch/mips/loongson32/Platform +++ b/arch/mips/loongson32/Platform @@ -1,3 +1,2 @@ cflags-$(CONFIG_CPU_LOONGSON32) += -march=mips32r2 -Wa,--trap -cflags-$(CONFIG_MACH_LOONGSON32) += -I$(srctree)/arch/mips/include/asm/mach-loongson32 load-$(CONFIG_CPU_LOONGSON32) += 0xffffffff80200000 diff --git a/arch/mips/loongson32/common/Makefile b/arch/mips/loongson32/common/Makefile deleted file mode 100644 index f3950d308187..000000000000 --- a/arch/mips/loongson32/common/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for common code of loongson1 based machines. -# - -obj-y += time.o irq.o platform.o prom.o setup.o diff --git a/arch/mips/loongson32/common/irq.c b/arch/mips/loongson32/common/irq.c deleted file mode 100644 index 9a50070f74f7..000000000000 --- a/arch/mips/loongson32/common/irq.c +++ /dev/null @@ -1,191 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2011 Zhang, Keguang - */ - -#include -#include -#include - -#include -#include - -#define LS1X_INTC_REG(n, x) \ - ((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x))) - -#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0) -#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4) -#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8) -#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc) -#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10) -#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14) - -static void ls1x_irq_ack(struct irq_data *d) -{ - unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; - unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; - - __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) - | (1 << bit), LS1X_INTC_INTCLR(n)); -} - -static void ls1x_irq_mask(struct irq_data *d) -{ - unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; - unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; - - __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) - & ~(1 << bit), LS1X_INTC_INTIEN(n)); -} - -static void ls1x_irq_mask_ack(struct irq_data *d) -{ - unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; - unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; - - __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) - & ~(1 << bit), LS1X_INTC_INTIEN(n)); - __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) - | (1 << bit), LS1X_INTC_INTCLR(n)); -} - -static void ls1x_irq_unmask(struct irq_data *d) -{ - unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; - unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; - - __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) - | (1 << bit), LS1X_INTC_INTIEN(n)); -} - -static int ls1x_irq_settype(struct irq_data *d, unsigned int type) -{ - unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; - unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; - - switch (type) { - case IRQ_TYPE_LEVEL_HIGH: - __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) - | (1 << bit), LS1X_INTC_INTPOL(n)); - __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) - & ~(1 << bit), LS1X_INTC_INTEDGE(n)); - break; - case IRQ_TYPE_LEVEL_LOW: - __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) - & ~(1 << bit), LS1X_INTC_INTPOL(n)); - __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) - & ~(1 << bit), LS1X_INTC_INTEDGE(n)); - break; - case IRQ_TYPE_EDGE_RISING: - __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) - | (1 << bit), LS1X_INTC_INTPOL(n)); - __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) - | (1 << bit), LS1X_INTC_INTEDGE(n)); - break; - case IRQ_TYPE_EDGE_FALLING: - __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) - & ~(1 << bit), LS1X_INTC_INTPOL(n)); - __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) - | (1 << bit), LS1X_INTC_INTEDGE(n)); - break; - case IRQ_TYPE_EDGE_BOTH: - __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) - & ~(1 << bit), LS1X_INTC_INTPOL(n)); - __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) - | (1 << bit), LS1X_INTC_INTEDGE(n)); - break; - case IRQ_TYPE_NONE: - break; - default: - return -EINVAL; - } - - return 0; -} - -static struct irq_chip ls1x_irq_chip = { - .name = "LS1X-INTC", - .irq_ack = ls1x_irq_ack, - .irq_mask = ls1x_irq_mask, - .irq_mask_ack = ls1x_irq_mask_ack, - .irq_unmask = ls1x_irq_unmask, - .irq_set_type = ls1x_irq_settype, -}; - -static void ls1x_irq_dispatch(int n) -{ - u32 int_status, irq; - - /* Get pending sources, masked by current enables */ - int_status = __raw_readl(LS1X_INTC_INTISR(n)) & - __raw_readl(LS1X_INTC_INTIEN(n)); - - if (int_status) { - irq = LS1X_IRQ(n, __ffs(int_status)); - do_IRQ(irq); - } -} - -asmlinkage void plat_irq_dispatch(void) -{ - unsigned int pending; - - pending = read_c0_cause() & read_c0_status() & ST0_IM; - - if (pending & CAUSEF_IP7) - do_IRQ(TIMER_IRQ); - else if (pending & CAUSEF_IP2) - ls1x_irq_dispatch(0); /* INT0 */ - else if (pending & CAUSEF_IP3) - ls1x_irq_dispatch(1); /* INT1 */ - else if (pending & CAUSEF_IP4) - ls1x_irq_dispatch(2); /* INT2 */ - else if (pending & CAUSEF_IP5) - ls1x_irq_dispatch(3); /* INT3 */ - else if (pending & CAUSEF_IP6) - ls1x_irq_dispatch(4); /* INT4 */ - else - spurious_interrupt(); - -} - -static void __init ls1x_irq_init(int base) -{ - int n; - - /* Disable interrupts and clear pending, - * setup all IRQs as high level triggered - */ - for (n = 0; n < INTN; n++) { - __raw_writel(0x0, LS1X_INTC_INTIEN(n)); - __raw_writel(0xffffffff, LS1X_INTC_INTCLR(n)); - __raw_writel(0xffffffff, LS1X_INTC_INTPOL(n)); - /* set DMA0, DMA1 and DMA2 to edge trigger */ - __raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n)); - } - - - for (n = base; n < NR_IRQS; n++) { - irq_set_chip_and_handler(n, &ls1x_irq_chip, - handle_level_irq); - } - - if (request_irq(INT0_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL)) - pr_err("Failed to request irq %d (cascade)\n", INT0_IRQ); - if (request_irq(INT1_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL)) - pr_err("Failed to request irq %d (cascade)\n", INT1_IRQ); - if (request_irq(INT2_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL)) - pr_err("Failed to request irq %d (cascade)\n", INT2_IRQ); - if (request_irq(INT3_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL)) - pr_err("Failed to request irq %d (cascade)\n", INT3_IRQ); -#if defined(CONFIG_LOONGSON1_LS1C) - if (request_irq(INT4_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL)) - pr_err("Failed to request irq %d (cascade)\n", INT4_IRQ); -#endif -} - -void __init arch_init_irq(void) -{ - mips_cpu_irq_init(); - ls1x_irq_init(LS1X_IRQ_BASE); -} diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c deleted file mode 100644 index 623eb4bc7b41..000000000000 --- a/arch/mips/loongson32/common/platform.c +++ /dev/null @@ -1,285 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2011-2016 Zhang, Keguang - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* 8250/16550 compatible UART */ -#define LS1X_UART(_id) \ - { \ - .mapbase = LS1X_UART ## _id ## _BASE, \ - .irq = LS1X_UART ## _id ## _IRQ, \ - .iotype = UPIO_MEM, \ - .flags = UPF_IOREMAP | UPF_FIXED_TYPE, \ - .type = PORT_16550A, \ - } - -static struct plat_serial8250_port ls1x_serial8250_pdata[] = { - LS1X_UART(0), - LS1X_UART(1), - LS1X_UART(2), - LS1X_UART(3), - {}, -}; - -struct platform_device ls1x_uart_pdev = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = ls1x_serial8250_pdata, - }, -}; - -void __init ls1x_serial_set_uartclk(struct platform_device *pdev) -{ - struct clk *clk; - struct plat_serial8250_port *p; - - clk = clk_get(&pdev->dev, pdev->name); - if (IS_ERR(clk)) { - pr_err("unable to get %s clock, err=%ld", - pdev->name, PTR_ERR(clk)); - return; - } - clk_prepare_enable(clk); - - for (p = pdev->dev.platform_data; p->flags != 0; ++p) - p->uartclk = clk_get_rate(clk); -} - -/* Synopsys Ethernet GMAC */ -static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = { - .phy_mask = 0, -}; - -static struct stmmac_dma_cfg ls1x_eth_dma_cfg = { - .pbl = 1, -}; - -int ls1x_eth_mux_init(struct platform_device *pdev, void *priv) -{ - struct plat_stmmacenet_data *plat_dat = NULL; - u32 val; - - val = __raw_readl(LS1X_MUX_CTRL1); - -#if defined(CONFIG_LOONGSON1_LS1B) - plat_dat = dev_get_platdata(&pdev->dev); - if (plat_dat->bus_id) { - __raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 | - GMAC1_USE_UART0, LS1X_MUX_CTRL0); - switch (plat_dat->phy_interface) { - case PHY_INTERFACE_MODE_RGMII: - val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23); - break; - case PHY_INTERFACE_MODE_MII: - val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23); - break; - default: - pr_err("unsupported mii mode %d\n", - plat_dat->phy_interface); - return -ENOTSUPP; - } - val &= ~GMAC1_SHUT; - } else { - switch (plat_dat->phy_interface) { - case PHY_INTERFACE_MODE_RGMII: - val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01); - break; - case PHY_INTERFACE_MODE_MII: - val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01); - break; - default: - pr_err("unsupported mii mode %d\n", - plat_dat->phy_interface); - return -ENOTSUPP; - } - val &= ~GMAC0_SHUT; - } - __raw_writel(val, LS1X_MUX_CTRL1); -#elif defined(CONFIG_LOONGSON1_LS1C) - plat_dat = dev_get_platdata(&pdev->dev); - - val &= ~PHY_INTF_SELI; - if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII) - val |= 0x4 << PHY_INTF_SELI_SHIFT; - __raw_writel(val, LS1X_MUX_CTRL1); - - val = __raw_readl(LS1X_MUX_CTRL0); - __raw_writel(val & (~GMAC_SHUT), LS1X_MUX_CTRL0); -#endif - - return 0; -} - -static struct plat_stmmacenet_data ls1x_eth0_pdata = { - .bus_id = 0, - .phy_addr = -1, -#if defined(CONFIG_LOONGSON1_LS1B) - .phy_interface = PHY_INTERFACE_MODE_MII, -#elif defined(CONFIG_LOONGSON1_LS1C) - .phy_interface = PHY_INTERFACE_MODE_RMII, -#endif - .mdio_bus_data = &ls1x_mdio_bus_data, - .dma_cfg = &ls1x_eth_dma_cfg, - .has_gmac = 1, - .tx_coe = 1, - .rx_queues_to_use = 1, - .tx_queues_to_use = 1, - .init = ls1x_eth_mux_init, -}; - -static struct resource ls1x_eth0_resources[] = { - [0] = { - .start = LS1X_GMAC0_BASE, - .end = LS1X_GMAC0_BASE + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .name = "macirq", - .start = LS1X_GMAC0_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device ls1x_eth0_pdev = { - .name = "stmmaceth", - .id = 0, - .num_resources = ARRAY_SIZE(ls1x_eth0_resources), - .resource = ls1x_eth0_resources, - .dev = { - .platform_data = &ls1x_eth0_pdata, - }, -}; - -#ifdef CONFIG_LOONGSON1_LS1B -static struct plat_stmmacenet_data ls1x_eth1_pdata = { - .bus_id = 1, - .phy_addr = -1, - .phy_interface = PHY_INTERFACE_MODE_MII, - .mdio_bus_data = &ls1x_mdio_bus_data, - .dma_cfg = &ls1x_eth_dma_cfg, - .has_gmac = 1, - .tx_coe = 1, - .rx_queues_to_use = 1, - .tx_queues_to_use = 1, - .init = ls1x_eth_mux_init, -}; - -static struct resource ls1x_eth1_resources[] = { - [0] = { - .start = LS1X_GMAC1_BASE, - .end = LS1X_GMAC1_BASE + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .name = "macirq", - .start = LS1X_GMAC1_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device ls1x_eth1_pdev = { - .name = "stmmaceth", - .id = 1, - .num_resources = ARRAY_SIZE(ls1x_eth1_resources), - .resource = ls1x_eth1_resources, - .dev = { - .platform_data = &ls1x_eth1_pdata, - }, -}; -#endif /* CONFIG_LOONGSON1_LS1B */ - -/* GPIO */ -static struct resource ls1x_gpio0_resources[] = { - [0] = { - .start = LS1X_GPIO0_BASE, - .end = LS1X_GPIO0_BASE + SZ_4 - 1, - .flags = IORESOURCE_MEM, - }, -}; - -struct platform_device ls1x_gpio0_pdev = { - .name = "ls1x-gpio", - .id = 0, - .num_resources = ARRAY_SIZE(ls1x_gpio0_resources), - .resource = ls1x_gpio0_resources, -}; - -static struct resource ls1x_gpio1_resources[] = { - [0] = { - .start = LS1X_GPIO1_BASE, - .end = LS1X_GPIO1_BASE + SZ_4 - 1, - .flags = IORESOURCE_MEM, - }, -}; - -struct platform_device ls1x_gpio1_pdev = { - .name = "ls1x-gpio", - .id = 1, - .num_resources = ARRAY_SIZE(ls1x_gpio1_resources), - .resource = ls1x_gpio1_resources, -}; - -/* USB EHCI */ -static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32); - -static struct resource ls1x_ehci_resources[] = { - [0] = { - .start = LS1X_EHCI_BASE, - .end = LS1X_EHCI_BASE + SZ_32K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = LS1X_EHCI_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct usb_ehci_pdata ls1x_ehci_pdata = { -}; - -struct platform_device ls1x_ehci_pdev = { - .name = "ehci-platform", - .id = -1, - .num_resources = ARRAY_SIZE(ls1x_ehci_resources), - .resource = ls1x_ehci_resources, - .dev = { - .dma_mask = &ls1x_ehci_dmamask, - .platform_data = &ls1x_ehci_pdata, - }, -}; - -/* Real Time Clock */ -struct platform_device ls1x_rtc_pdev = { - .name = "ls1x-rtc", - .id = -1, -}; - -/* Watchdog */ -static struct resource ls1x_wdt_resources[] = { - { - .start = LS1X_WDT_BASE, - .end = LS1X_WDT_BASE + SZ_16 - 1, - .flags = IORESOURCE_MEM, - }, -}; - -struct platform_device ls1x_wdt_pdev = { - .name = "ls1x-wdt", - .id = -1, - .num_resources = ARRAY_SIZE(ls1x_wdt_resources), - .resource = ls1x_wdt_resources, -}; diff --git a/arch/mips/loongson32/common/prom.c b/arch/mips/loongson32/common/prom.c deleted file mode 100644 index fc580a22748e..000000000000 --- a/arch/mips/loongson32/common/prom.c +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2011 Zhang, Keguang - * - * Modified from arch/mips/pnx833x/common/prom.c. - */ - -#include -#include -#include -#include -#include - -#include - -unsigned long memsize; - -void __init prom_init(void) -{ - void __iomem *uart_base; - - fw_init_cmdline(); - - memsize = fw_getenvl("memsize"); - if(!memsize) - memsize = DEFAULT_MEMSIZE; - - if (strstr(arcs_cmdline, "console=ttyS3")) - uart_base = ioremap(LS1X_UART3_BASE, 0x0f); - else if (strstr(arcs_cmdline, "console=ttyS2")) - uart_base = ioremap(LS1X_UART2_BASE, 0x0f); - else if (strstr(arcs_cmdline, "console=ttyS1")) - uart_base = ioremap(LS1X_UART1_BASE, 0x0f); - else - uart_base = ioremap(LS1X_UART0_BASE, 0x0f); - setup_8250_early_printk_port((unsigned long)uart_base, 0, 0); -} - -void __init plat_mem_setup(void) -{ - memblock_add(0x0, (memsize << 20)); -} diff --git a/arch/mips/loongson32/common/setup.c b/arch/mips/loongson32/common/setup.c deleted file mode 100644 index 4733fe037176..000000000000 --- a/arch/mips/loongson32/common/setup.c +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2011 Zhang, Keguang - */ - -#include -#include -#include -#include -#include - -const char *get_system_type(void) -{ - unsigned int processor_id = (¤t_cpu_data)->processor_id; - - switch (processor_id & PRID_REV_MASK) { - case PRID_REV_LOONGSON1B: -#if defined(CONFIG_LOONGSON1_LS1B) - return "LOONGSON LS1B"; -#elif defined(CONFIG_LOONGSON1_LS1C) - return "LOONGSON LS1C"; -#endif - default: - return "LOONGSON (unknown)"; - } -} diff --git a/arch/mips/loongson32/common/time.c b/arch/mips/loongson32/common/time.c deleted file mode 100644 index 74ad2b17918d..000000000000 --- a/arch/mips/loongson32/common/time.c +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2014 Zhang, Keguang - */ - -#include -#include -#include - -void __init plat_time_init(void) -{ - struct clk *clk = NULL; - - /* initialize LS1X clocks */ - of_clk_init(NULL); - - /* setup mips r4k timer */ - clk = clk_get(NULL, "cpu_clk"); - if (IS_ERR(clk)) - panic("unable to get cpu clock, err=%ld", PTR_ERR(clk)); - - mips_hpt_frequency = clk_get_rate(clk) / 2; -} diff --git a/arch/mips/loongson32/ls1b/Makefile b/arch/mips/loongson32/ls1b/Makefile deleted file mode 100644 index 33c574dc0f7f..000000000000 --- a/arch/mips/loongson32/ls1b/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for loongson1B based machines. -# - -obj-y += board.o diff --git a/arch/mips/loongson32/ls1b/board.c b/arch/mips/loongson32/ls1b/board.c deleted file mode 100644 index fe115bdcb22c..000000000000 --- a/arch/mips/loongson32/ls1b/board.c +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2011-2016 Zhang, Keguang - */ - -#include -#include -#include - -#include -#include - -static const struct gpio_led ls1x_gpio_leds[] __initconst = { - { - .name = "LED9", - .default_trigger = "heartbeat", - .gpio = 38, - .active_low = 1, - .default_state = LEDS_GPIO_DEFSTATE_OFF, - }, { - .name = "LED6", - .default_trigger = "nand-disk", - .gpio = 39, - .active_low = 1, - .default_state = LEDS_GPIO_DEFSTATE_OFF, - }, -}; - -static const struct gpio_led_platform_data ls1x_led_pdata __initconst = { - .num_leds = ARRAY_SIZE(ls1x_gpio_leds), - .leds = ls1x_gpio_leds, -}; - -static struct platform_device *ls1b_platform_devices[] __initdata = { - &ls1x_uart_pdev, - &ls1x_eth0_pdev, - &ls1x_eth1_pdev, - &ls1x_ehci_pdev, - &ls1x_gpio0_pdev, - &ls1x_gpio1_pdev, - &ls1x_rtc_pdev, - &ls1x_wdt_pdev, -}; - -static int __init ls1b_platform_init(void) -{ - ls1x_serial_set_uartclk(&ls1x_uart_pdev); - - gpio_led_register_device(-1, &ls1x_led_pdata); - - return platform_add_devices(ls1b_platform_devices, - ARRAY_SIZE(ls1b_platform_devices)); -} - -arch_initcall(ls1b_platform_init); diff --git a/arch/mips/loongson32/ls1c/Makefile b/arch/mips/loongson32/ls1c/Makefile deleted file mode 100644 index 1cf3aa264d55..000000000000 --- a/arch/mips/loongson32/ls1c/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for loongson1C based machines. -# - -obj-y += board.o diff --git a/arch/mips/loongson32/ls1c/board.c b/arch/mips/loongson32/ls1c/board.c deleted file mode 100644 index 9dcfe9de55b0..000000000000 --- a/arch/mips/loongson32/ls1c/board.c +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2016 Yang Ling - */ - -#include - -static struct platform_device *ls1c_platform_devices[] __initdata = { - &ls1x_uart_pdev, - &ls1x_eth0_pdev, - &ls1x_rtc_pdev, - &ls1x_wdt_pdev, -}; - -static int __init ls1c_platform_init(void) -{ - ls1x_serial_set_uartclk(&ls1x_uart_pdev); - - return platform_add_devices(ls1c_platform_devices, - ARRAY_SIZE(ls1c_platform_devices)); -} - -arch_initcall(ls1c_platform_init); From 2d18f2343e44317697c5623fb387c90914c377da Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 16 Jul 2025 19:25:17 +0800 Subject: [PATCH 0683/2711] MIPS: Unify Loongson1 PRID_REV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LS1B and LS1C share the same PRID value, so unify them into a single definition: PRID_REV_LOONGSON1. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/cpu.h | 3 +-- arch/mips/kernel/cpu-probe.c | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 32cf5496006e..0fd9f9bbd21f 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -248,8 +248,7 @@ #define PRID_REV_VR4181A 0x0070 /* Same as VR4122 */ #define PRID_REV_VR4130 0x0080 #define PRID_REV_34K_V1_0_2 0x0022 -#define PRID_REV_LOONGSON1B 0x0020 -#define PRID_REV_LOONGSON1C 0x0020 /* Same as Loongson-1B */ +#define PRID_REV_LOONGSON1 0x0020 #define PRID_REV_LOONGSON2E 0x0002 #define PRID_REV_LOONGSON2F 0x0003 #define PRID_REV_LOONGSON2K_R1_0 0x0000 diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 04dc9ab55524..1e49e05ac8b1 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -1288,14 +1288,14 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) set_cpu_asid_mask(c, MIPS_ENTRYHI_ASID); c->writecombine = _CACHE_UNCACHED_ACCELERATED; break; - case PRID_IMP_LOONGSON_32: /* Loongson-1 */ + case PRID_IMP_LOONGSON_32: decode_configs(c); c->cputype = CPU_LOONGSON32; switch (c->processor_id & PRID_REV_MASK) { - case PRID_REV_LOONGSON1B: - __cpu_name[cpu] = "Loongson 1B"; + case PRID_REV_LOONGSON1: + __cpu_name[cpu] = "ICT Loongson-1"; break; } From ad79935dbc227fad7172dc50970ee579ff21a91e Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 16 Jul 2025 19:25:18 +0800 Subject: [PATCH 0684/2711] MIPS: configs: Consolidate Loongson1 defconfigs Unify loongson{1b,1c}_defconfig into a single loongson1_defconfig. Enable the following options by default: - CONFIG_SERIAL_OF_PLATFORM - CONFIG_RTC_DRV_LOONGSON - CONFIG_LOONGSON1_APB_DMA - CONFIG_MTD_NAND_LOONGSON1 - CONFIG_SND_LOONGSON1_AC97 Also disable unnecessary options. Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- MAINTAINERS | 1 + ...ongson1b_defconfig => loongson1_defconfig} | 94 +++++++++++--- arch/mips/configs/loongson1c_defconfig | 121 ------------------ 3 files changed, 78 insertions(+), 138 deletions(-) rename arch/mips/configs/{loongson1b_defconfig => loongson1_defconfig} (51%) delete mode 100644 arch/mips/configs/loongson1c_defconfig diff --git a/MAINTAINERS b/MAINTAINERS index b5e33faf2a3f..c6e6c9035d9b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17017,6 +17017,7 @@ L: linux-mips@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/*/loongson,ls1*.yaml F: arch/mips/boot/dts/loongson/loongson1* +F: arch/mips/configs/loongson1_defconfig F: arch/mips/loongson32/ F: drivers/*/*loongson1* F: drivers/mtd/nand/raw/loongson1-nand-controller.c diff --git a/arch/mips/configs/loongson1b_defconfig b/arch/mips/configs/loongson1_defconfig similarity index 51% rename from arch/mips/configs/loongson1b_defconfig rename to arch/mips/configs/loongson1_defconfig index 68207b31dc20..81acae6f61c8 100644 --- a/arch/mips/configs/loongson1b_defconfig +++ b/arch/mips/configs/loongson1_defconfig @@ -1,7 +1,6 @@ # CONFIG_LOCALVERSION_AUTO is not set CONFIG_KERNEL_XZ=y CONFIG_SYSVIPC=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y @@ -12,15 +11,16 @@ CONFIG_NAMESPACES=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y -# CONFIG_COMPAT_BRK is not set CONFIG_MACH_LOONGSON32=y -# CONFIG_SECCOMP is not set # CONFIG_SUSPEND is not set +# CONFIG_SECCOMP is not set +# CONFIG_GCC_PLUGINS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y -# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLOCK_LEGACY_AUTOLOAD is not set # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_COMPAT_BRK is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -31,6 +31,7 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_DIAG is not set # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set +# CONFIG_ETHTOOL_NETLINK is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set @@ -38,32 +39,75 @@ CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_NAND_LOONGSON1=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_SCSI=m # CONFIG_SCSI_PROC_FS is not set CONFIG_BLK_DEV_SD=m +# CONFIG_BLK_DEV_BSG is not set # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ASIX is not set # CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_DAVICOM is not set +# CONFIG_NET_VENDOR_ENGLEDER is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_FUNGIBLE is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_HUAWEI is not set # CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_LITEX is not set # CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_META is not set # CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MICROSOFT is not set +# CONFIG_NET_VENDOR_NI is not set # CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set # CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set CONFIG_STMMAC_ETH=y +# CONFIG_DWMAC_GENERIC is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VERTEXCOM is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WANGXUN is not set # CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +CONFIG_DAVICOM_PHY=y +CONFIG_REALTEK_PHY=y +# CONFIG_USB_NET_DRIVERS is not set # CONFIG_WLAN is not set CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_SERIO is not set +# CONFIG_VT_CONSOLE is not set CONFIG_VT_HW_CONSOLE_BINDING=y CONFIG_LEGACY_PTY_COUNT=8 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set +# CONFIG_PTP_1588_CLOCK is not set CONFIG_GPIOLIB=y CONFIG_GPIO_LOONGSON1=y # CONFIG_HWMON is not set @@ -71,7 +115,15 @@ CONFIG_WATCHDOG=y CONFIG_WATCHDOG_NOWAYOUT=y CONFIG_WATCHDOG_SYSFS=y CONFIG_LOONGSON1_WDT=y -# CONFIG_VGA_CONSOLE is not set +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_MIPS is not set +# CONFIG_SND_USB is not set +CONFIG_SND_SOC=y +CONFIG_SND_LOONGSON1_AC97=y +CONFIG_SND_SIMPLE_CARD=y CONFIG_HID_GENERIC=m CONFIG_USB_HID=m CONFIG_USB=y @@ -86,17 +138,20 @@ CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_MTD=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_LOONGSON1=y +# CONFIG_RTC_NVMEM is not set +CONFIG_RTC_DRV_LOONGSON=y +CONFIG_DMADEVICES=y +CONFIG_LOONGSON1_APB_DMA=y +# CONFIG_VIRTIO_MENU is not set +# CONFIG_VHOST_MENU is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set # CONFIG_IOMMU_SUPPORT is not set -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y +# CONFIG_NVMEM is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y # CONFIG_DNOTIFY is not set CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y @@ -105,16 +160,21 @@ CONFIG_TMPFS_POSIX_ACL=y CONFIG_UBIFS_FS=y CONFIG_UBIFS_FS_ADVANCED_COMPR=y CONFIG_UBIFS_ATIME_SUPPORT=y +# CONFIG_UBIFS_FS_SECURITY is not set CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_ISO8859_1=m -# CONFIG_CRYPTO_ECHAINIV is not set # CONFIG_CRYPTO_HW is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_ARM64 is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_RISCV is not set CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_MISC is not set CONFIG_MAGIC_SYSRQ=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_DEBUG_PREEMPT is not set # CONFIG_FTRACE is not set # CONFIG_EARLY_PRINTK is not set diff --git a/arch/mips/configs/loongson1c_defconfig b/arch/mips/configs/loongson1c_defconfig deleted file mode 100644 index c3910a9dee9e..000000000000 --- a/arch/mips/configs/loongson1c_defconfig +++ /dev/null @@ -1,121 +0,0 @@ -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_KERNEL_XZ=y -CONFIG_SYSVIPC=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_PREEMPT=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=16 -CONFIG_NAMESPACES=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_EXPERT=y -CONFIG_PERF_EVENTS=y -# CONFIG_COMPAT_BRK is not set -CONFIG_MACH_LOONGSON32=y -CONFIG_LOONGSON1_LS1C=y -# CONFIG_SECCOMP is not set -# CONFIG_SUSPEND is not set -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODVERSIONS=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_SYN_COOKIES=y -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -# CONFIG_WIRELESS is not set -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -# CONFIG_STANDALONE is not set -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_RAW_NAND=y -CONFIG_MTD_UBI=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_SCSI=m -# CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=m -# CONFIG_SCSI_LOWLEVEL is not set -CONFIG_NETDEVICES=y -# CONFIG_NET_VENDOR_BROADCOM is not set -# CONFIG_NET_VENDOR_INTEL is not set -# CONFIG_NET_VENDOR_MARVELL is not set -# CONFIG_NET_VENDOR_MICREL is not set -# CONFIG_NET_VENDOR_NATSEMI is not set -# CONFIG_NET_VENDOR_SEEQ is not set -# CONFIG_NET_VENDOR_SMSC is not set -CONFIG_STMMAC_ETH=y -# CONFIG_NET_VENDOR_WIZNET is not set -# CONFIG_WLAN is not set -CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_LEGACY_PTY_COUNT=8 -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_HW_RANDOM is not set -CONFIG_GPIOLIB=y -CONFIG_GPIO_LOONGSON1=y -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -CONFIG_WATCHDOG_SYSFS=y -CONFIG_LOONGSON1_WDT=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_HID_GENERIC=m -CONFIG_USB_HID=m -CONFIG_USB=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_EHCI_HCD=y -# CONFIG_USB_EHCI_TT_NEWSCHED is not set -CONFIG_USB_EHCI_HCD_PLATFORM=y -CONFIG_USB_STORAGE=m -CONFIG_USB_SERIAL=m -CONFIG_USB_SERIAL_PL2303=m -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_GPIO=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_LOONGSON1=y -# CONFIG_IOMMU_SUPPORT is not set -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y -# CONFIG_DNOTIFY is not set -CONFIG_VFAT_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_UBIFS_FS=y -CONFIG_UBIFS_FS_ADVANCED_COMPR=y -CONFIG_UBIFS_ATIME_SUPPORT=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_NLS_CODEPAGE_437=m -CONFIG_NLS_ISO8859_1=m -# CONFIG_CRYPTO_ECHAINIV is not set -# CONFIG_CRYPTO_HW is not set -CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_FS=y -CONFIG_MAGIC_SYSRQ=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_DEBUG_PREEMPT is not set -# CONFIG_FTRACE is not set -# CONFIG_EARLY_PRINTK is not set From 9aa7e045f4af7d33684f00214a6f74e506426546 Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Mon, 18 Aug 2025 21:24:17 +0800 Subject: [PATCH 0685/2711] crypto: jitter - Mark intermediary memory as clean This is not a leak! The stack memroy is hashed and fed into the entropy pool. We can't recover the original kernel memory from it. Reported-by: syzbot+e8bcd7ee3db6cb5cb875@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=e8bcd7ee3db6cb5cb875 Signed-off-by: Edward Adam Davis Signed-off-by: Herbert Xu --- crypto/jitterentropy-kcapi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c index 1266eb790708..a53de7affe8d 100644 --- a/crypto/jitterentropy-kcapi.c +++ b/crypto/jitterentropy-kcapi.c @@ -117,6 +117,7 @@ int jent_hash_time(void *hash_state, __u64 time, u8 *addtl, pr_warn_ratelimited("Unexpected digest size\n"); return -EINVAL; } + kmsan_unpoison_memory(intermediary, sizeof(intermediary)); /* * This loop fills a buffer which is injected into the entropy pool. From 01834444d972163b305a7f81e6bfba6315dced09 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 18 Aug 2025 15:47:40 -0700 Subject: [PATCH 0686/2711] crypto: arm64/aes - use SHA-256 library instead of crypto_shash In essiv_cbc_set_key(), just use the SHA-256 library instead of crypto_shash. This is simpler and also slightly faster. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- arch/arm64/crypto/Kconfig | 1 + arch/arm64/crypto/aes-glue.c | 21 +-------------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig index 3bb5b513d5ae..91f3093eee6a 100644 --- a/arch/arm64/crypto/Kconfig +++ b/arch/arm64/crypto/Kconfig @@ -71,6 +71,7 @@ config CRYPTO_POLYVAL_ARM64_CE config CRYPTO_AES_ARM64 tristate "Ciphers: AES, modes: ECB, CBC, CTR, CTS, XCTR, XTS" select CRYPTO_AES + select CRYPTO_LIB_SHA256 help Block ciphers: AES cipher algorithms (FIPS-197) Length-preserving ciphers: AES with ECB, CBC, CTR, CTS, diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c index 81560f722b9d..5e207ff34482 100644 --- a/arch/arm64/crypto/aes-glue.c +++ b/arch/arm64/crypto/aes-glue.c @@ -122,7 +122,6 @@ struct crypto_aes_xts_ctx { struct crypto_aes_essiv_cbc_ctx { struct crypto_aes_ctx key1; struct crypto_aes_ctx __aligned(8) key2; - struct crypto_shash *hash; }; struct mac_tfm_ctx { @@ -171,7 +170,7 @@ static int __maybe_unused essiv_cbc_set_key(struct crypto_skcipher *tfm, if (ret) return ret; - crypto_shash_tfm_digest(ctx->hash, in_key, key_len, digest); + sha256(in_key, key_len, digest); return aes_expandkey(&ctx->key2, digest, sizeof(digest)); } @@ -388,22 +387,6 @@ static int cts_cbc_decrypt(struct skcipher_request *req) return skcipher_walk_done(&walk, 0); } -static int __maybe_unused essiv_cbc_init_tfm(struct crypto_skcipher *tfm) -{ - struct crypto_aes_essiv_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); - - ctx->hash = crypto_alloc_shash("sha256", 0, 0); - - return PTR_ERR_OR_ZERO(ctx->hash); -} - -static void __maybe_unused essiv_cbc_exit_tfm(struct crypto_skcipher *tfm) -{ - struct crypto_aes_essiv_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); - - crypto_free_shash(ctx->hash); -} - static int __maybe_unused essiv_cbc_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); @@ -793,8 +776,6 @@ static struct skcipher_alg aes_algs[] = { { .setkey = essiv_cbc_set_key, .encrypt = essiv_cbc_encrypt, .decrypt = essiv_cbc_decrypt, - .init = essiv_cbc_init_tfm, - .exit = essiv_cbc_exit_tfm, } }; static int cbcmac_setkey(struct crypto_shash *tfm, const u8 *in_key, From 97d37c0a4477c857f2ddf42b5fe9e4a78ab9db85 Mon Sep 17 00:00:00 2001 From: T Pratham Date: Wed, 20 Aug 2025 14:42:26 +0530 Subject: [PATCH 0687/2711] dt-bindings: crypto: Add binding for TI DTHE V2 Add DT binding for Texas Instruments DTHE V2 cryptography engine. DTHE V2 is introduced as a part of TI AM62L SoC and can currently be only found in it. Signed-off-by: T Pratham Reviewed-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- .../bindings/crypto/ti,am62l-dthev2.yaml | 50 +++++++++++++++++++ MAINTAINERS | 6 +++ 2 files changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/crypto/ti,am62l-dthev2.yaml diff --git a/Documentation/devicetree/bindings/crypto/ti,am62l-dthev2.yaml b/Documentation/devicetree/bindings/crypto/ti,am62l-dthev2.yaml new file mode 100644 index 000000000000..5486bfeb2fe8 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/ti,am62l-dthev2.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/crypto/ti,am62l-dthev2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: K3 SoC DTHE V2 crypto module + +maintainers: + - T Pratham + +properties: + compatible: + enum: + - ti,am62l-dthev2 + + reg: + maxItems: 1 + + dmas: + items: + - description: AES Engine RX DMA Channel + - description: AES Engine TX DMA Channel + - description: SHA Engine TX DMA Channel + + dma-names: + items: + - const: rx + - const: tx1 + - const: tx2 + +required: + - compatible + - reg + - dmas + - dma-names + +additionalProperties: false + +examples: + - | + crypto@40800000 { + compatible = "ti,am62l-dthev2"; + reg = <0x40800000 0x10000>; + + dmas = <&main_bcdma 0 0 0x4700 0>, + <&main_bcdma 0 0 0xc701 0>, + <&main_bcdma 0 0 0xc700 0>; + dma-names = "rx", "tx1", "tx2"; + }; diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..0f5bb8ad7653 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25169,6 +25169,12 @@ S: Odd Fixes F: drivers/clk/ti/ F: include/linux/clk/ti.h +TI DATA TRANSFORM AND HASHING ENGINE (DTHE) V2 CRYPTO DRIVER +M: T Pratham +L: linux-crypto@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/crypto/ti,am62l-dthev2.yaml + TI DAVINCI MACHINE SUPPORT M: Bartosz Golaszewski L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) From 52f641bc63a46657b1d72d902fcee30ab1233c7b Mon Sep 17 00:00:00 2001 From: T Pratham Date: Wed, 20 Aug 2025 14:42:27 +0530 Subject: [PATCH 0688/2711] crypto: ti - Add driver for DTHE V2 AES Engine (ECB, CBC) Add support for ECB and CBC modes in the AES Engine of the DTHE V2 hardware cryptography engine. Signed-off-by: T Pratham Signed-off-by: Herbert Xu --- MAINTAINERS | 1 + drivers/crypto/Kconfig | 1 + drivers/crypto/Makefile | 1 + drivers/crypto/ti/Kconfig | 14 + drivers/crypto/ti/Makefile | 3 + drivers/crypto/ti/dthev2-aes.c | 411 ++++++++++++++++++++++++++++++ drivers/crypto/ti/dthev2-common.c | 217 ++++++++++++++++ drivers/crypto/ti/dthev2-common.h | 101 ++++++++ 8 files changed, 749 insertions(+) create mode 100644 drivers/crypto/ti/Kconfig create mode 100644 drivers/crypto/ti/Makefile create mode 100644 drivers/crypto/ti/dthev2-aes.c create mode 100644 drivers/crypto/ti/dthev2-common.c create mode 100644 drivers/crypto/ti/dthev2-common.h diff --git a/MAINTAINERS b/MAINTAINERS index 0f5bb8ad7653..ca728cc24169 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25174,6 +25174,7 @@ M: T Pratham L: linux-crypto@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/crypto/ti,am62l-dthev2.yaml +F: drivers/crypto/ti/ TI DAVINCI MACHINE SUPPORT M: Bartosz Golaszewski diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 04b4c43b6bae..f056ec58c96e 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -863,5 +863,6 @@ config CRYPTO_DEV_SA2UL source "drivers/crypto/aspeed/Kconfig" source "drivers/crypto/starfive/Kconfig" source "drivers/crypto/inside-secure/eip93/Kconfig" +source "drivers/crypto/ti/Kconfig" endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 22eadcc8f4a2..c0e8d4acc37c 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ obj-y += intel/ obj-y += starfive/ obj-y += cavium/ +obj-$(CONFIG_ARCH_K3) += ti/ diff --git a/drivers/crypto/ti/Kconfig b/drivers/crypto/ti/Kconfig new file mode 100644 index 000000000000..38d22cab05a9 --- /dev/null +++ b/drivers/crypto/ti/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only +config CRYPTO_DEV_TI_DTHEV2 + tristate "Support for TI DTHE V2 cryptography engine" + depends on CRYPTO && CRYPTO_HW && ARCH_K3 + select CRYPTO_ENGINE + select CRYPTO_SKCIPHER + select CRYPTO_ECB + select CRYPTO_CBC + help + This enables support for the TI DTHE V2 hw cryptography engine + which can be found on TI K3 SOCs. Selecting this enables use + of hardware offloading for cryptographic algorithms on + these devices, providing enhanced resistance against side-channel + attacks. diff --git a/drivers/crypto/ti/Makefile b/drivers/crypto/ti/Makefile new file mode 100644 index 000000000000..b883078f203d --- /dev/null +++ b/drivers/crypto/ti/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_CRYPTO_DEV_TI_DTHEV2) += dthev2.o +dthev2-objs := dthev2-common.o dthev2-aes.o diff --git a/drivers/crypto/ti/dthev2-aes.c b/drivers/crypto/ti/dthev2-aes.c new file mode 100644 index 000000000000..0431a36d8c4a --- /dev/null +++ b/drivers/crypto/ti/dthev2-aes.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * K3 DTHE V2 crypto accelerator driver + * + * Copyright (C) Texas Instruments 2025 - https://www.ti.com + * Author: T Pratham + */ + +#include +#include +#include +#include +#include +#include + +#include "dthev2-common.h" + +#include +#include +#include +#include +#include + +/* Registers */ + +// AES Engine +#define DTHE_P_AES_BASE 0x7000 +#define DTHE_P_AES_KEY1_0 0x0038 +#define DTHE_P_AES_KEY1_1 0x003C +#define DTHE_P_AES_KEY1_2 0x0030 +#define DTHE_P_AES_KEY1_3 0x0034 +#define DTHE_P_AES_KEY1_4 0x0028 +#define DTHE_P_AES_KEY1_5 0x002C +#define DTHE_P_AES_KEY1_6 0x0020 +#define DTHE_P_AES_KEY1_7 0x0024 +#define DTHE_P_AES_IV_IN_0 0x0040 +#define DTHE_P_AES_IV_IN_1 0x0044 +#define DTHE_P_AES_IV_IN_2 0x0048 +#define DTHE_P_AES_IV_IN_3 0x004C +#define DTHE_P_AES_CTRL 0x0050 +#define DTHE_P_AES_C_LENGTH_0 0x0054 +#define DTHE_P_AES_C_LENGTH_1 0x0058 +#define DTHE_P_AES_AUTH_LENGTH 0x005C +#define DTHE_P_AES_DATA_IN_OUT 0x0060 + +#define DTHE_P_AES_SYSCONFIG 0x0084 +#define DTHE_P_AES_IRQSTATUS 0x008C +#define DTHE_P_AES_IRQENABLE 0x0090 + +/* Register write values and macros */ + +enum aes_ctrl_mode_masks { + AES_CTRL_ECB_MASK = 0x00, + AES_CTRL_CBC_MASK = BIT(5), +}; + +#define DTHE_AES_CTRL_MODE_CLEAR_MASK ~GENMASK(28, 5) + +#define DTHE_AES_CTRL_DIR_ENC BIT(2) + +#define DTHE_AES_CTRL_KEYSIZE_16B BIT(3) +#define DTHE_AES_CTRL_KEYSIZE_24B BIT(4) +#define DTHE_AES_CTRL_KEYSIZE_32B (BIT(3) | BIT(4)) + +#define DTHE_AES_CTRL_SAVE_CTX_SET BIT(29) + +#define DTHE_AES_CTRL_OUTPUT_READY BIT_MASK(0) +#define DTHE_AES_CTRL_INPUT_READY BIT_MASK(1) +#define DTHE_AES_CTRL_SAVED_CTX_READY BIT_MASK(30) +#define DTHE_AES_CTRL_CTX_READY BIT_MASK(31) + +#define DTHE_AES_SYSCONFIG_DMA_DATA_IN_OUT_EN GENMASK(6, 5) +#define DTHE_AES_IRQENABLE_EN_ALL GENMASK(3, 0) + +/* Misc */ +#define AES_IV_SIZE AES_BLOCK_SIZE +#define AES_BLOCK_WORDS (AES_BLOCK_SIZE / sizeof(u32)) +#define AES_IV_WORDS AES_BLOCK_WORDS + +static int dthe_cipher_init_tfm(struct crypto_skcipher *tfm) +{ + struct dthe_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); + struct dthe_data *dev_data = dthe_get_dev(ctx); + + ctx->dev_data = dev_data; + ctx->keylen = 0; + + return 0; +} + +static int dthe_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) +{ + struct dthe_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); + + if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && keylen != AES_KEYSIZE_256) + return -EINVAL; + + ctx->keylen = keylen; + memcpy(ctx->key, key, keylen); + + return 0; +} + +static int dthe_aes_ecb_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) +{ + struct dthe_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); + + ctx->aes_mode = DTHE_AES_ECB; + + return dthe_aes_setkey(tfm, key, keylen); +} + +static int dthe_aes_cbc_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) +{ + struct dthe_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); + + ctx->aes_mode = DTHE_AES_CBC; + + return dthe_aes_setkey(tfm, key, keylen); +} + +static void dthe_aes_set_ctrl_key(struct dthe_tfm_ctx *ctx, + struct dthe_aes_req_ctx *rctx, + u32 *iv_in) +{ + struct dthe_data *dev_data = dthe_get_dev(ctx); + void __iomem *aes_base_reg = dev_data->regs + DTHE_P_AES_BASE; + u32 ctrl_val = 0; + + writel_relaxed(ctx->key[0], aes_base_reg + DTHE_P_AES_KEY1_0); + writel_relaxed(ctx->key[1], aes_base_reg + DTHE_P_AES_KEY1_1); + writel_relaxed(ctx->key[2], aes_base_reg + DTHE_P_AES_KEY1_2); + writel_relaxed(ctx->key[3], aes_base_reg + DTHE_P_AES_KEY1_3); + + if (ctx->keylen > AES_KEYSIZE_128) { + writel_relaxed(ctx->key[4], aes_base_reg + DTHE_P_AES_KEY1_4); + writel_relaxed(ctx->key[5], aes_base_reg + DTHE_P_AES_KEY1_5); + } + if (ctx->keylen == AES_KEYSIZE_256) { + writel_relaxed(ctx->key[6], aes_base_reg + DTHE_P_AES_KEY1_6); + writel_relaxed(ctx->key[7], aes_base_reg + DTHE_P_AES_KEY1_7); + } + + if (rctx->enc) + ctrl_val |= DTHE_AES_CTRL_DIR_ENC; + + if (ctx->keylen == AES_KEYSIZE_128) + ctrl_val |= DTHE_AES_CTRL_KEYSIZE_16B; + else if (ctx->keylen == AES_KEYSIZE_192) + ctrl_val |= DTHE_AES_CTRL_KEYSIZE_24B; + else + ctrl_val |= DTHE_AES_CTRL_KEYSIZE_32B; + + // Write AES mode + ctrl_val &= DTHE_AES_CTRL_MODE_CLEAR_MASK; + switch (ctx->aes_mode) { + case DTHE_AES_ECB: + ctrl_val |= AES_CTRL_ECB_MASK; + break; + case DTHE_AES_CBC: + ctrl_val |= AES_CTRL_CBC_MASK; + break; + } + + if (iv_in) { + ctrl_val |= DTHE_AES_CTRL_SAVE_CTX_SET; + for (int i = 0; i < AES_IV_WORDS; ++i) + writel_relaxed(iv_in[i], + aes_base_reg + DTHE_P_AES_IV_IN_0 + (DTHE_REG_SIZE * i)); + } + + writel_relaxed(ctrl_val, aes_base_reg + DTHE_P_AES_CTRL); +} + +static void dthe_aes_dma_in_callback(void *data) +{ + struct skcipher_request *req = (struct skcipher_request *)data; + struct dthe_aes_req_ctx *rctx = skcipher_request_ctx(req); + + complete(&rctx->aes_compl); +} + +static int dthe_aes_run(struct crypto_engine *engine, void *areq) +{ + struct skcipher_request *req = container_of(areq, struct skcipher_request, base); + struct dthe_tfm_ctx *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); + struct dthe_data *dev_data = dthe_get_dev(ctx); + struct dthe_aes_req_ctx *rctx = skcipher_request_ctx(req); + + unsigned int len = req->cryptlen; + struct scatterlist *src = req->src; + struct scatterlist *dst = req->dst; + + int src_nents = sg_nents_for_len(src, len); + int dst_nents; + + int src_mapped_nents; + int dst_mapped_nents; + + bool diff_dst; + enum dma_data_direction src_dir, dst_dir; + + struct device *tx_dev, *rx_dev; + struct dma_async_tx_descriptor *desc_in, *desc_out; + + int ret; + + void __iomem *aes_base_reg = dev_data->regs + DTHE_P_AES_BASE; + + u32 aes_irqenable_val = readl_relaxed(aes_base_reg + DTHE_P_AES_IRQENABLE); + u32 aes_sysconfig_val = readl_relaxed(aes_base_reg + DTHE_P_AES_SYSCONFIG); + + aes_sysconfig_val |= DTHE_AES_SYSCONFIG_DMA_DATA_IN_OUT_EN; + writel_relaxed(aes_sysconfig_val, aes_base_reg + DTHE_P_AES_SYSCONFIG); + + aes_irqenable_val |= DTHE_AES_IRQENABLE_EN_ALL; + writel_relaxed(aes_irqenable_val, aes_base_reg + DTHE_P_AES_IRQENABLE); + + if (src == dst) { + diff_dst = false; + src_dir = DMA_BIDIRECTIONAL; + dst_dir = DMA_BIDIRECTIONAL; + } else { + diff_dst = true; + src_dir = DMA_TO_DEVICE; + dst_dir = DMA_FROM_DEVICE; + } + + tx_dev = dmaengine_get_dma_device(dev_data->dma_aes_tx); + rx_dev = dmaengine_get_dma_device(dev_data->dma_aes_rx); + + src_mapped_nents = dma_map_sg(tx_dev, src, src_nents, src_dir); + if (src_mapped_nents == 0) { + ret = -EINVAL; + goto aes_err; + } + + if (!diff_dst) { + dst_nents = src_nents; + dst_mapped_nents = src_mapped_nents; + } else { + dst_nents = sg_nents_for_len(dst, len); + dst_mapped_nents = dma_map_sg(rx_dev, dst, dst_nents, dst_dir); + if (dst_mapped_nents == 0) { + dma_unmap_sg(tx_dev, src, src_nents, src_dir); + ret = -EINVAL; + goto aes_err; + } + } + + desc_in = dmaengine_prep_slave_sg(dev_data->dma_aes_rx, dst, dst_mapped_nents, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_in) { + dev_err(dev_data->dev, "IN prep_slave_sg() failed\n"); + ret = -EINVAL; + goto aes_prep_err; + } + + desc_out = dmaengine_prep_slave_sg(dev_data->dma_aes_tx, src, src_mapped_nents, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_out) { + dev_err(dev_data->dev, "OUT prep_slave_sg() failed\n"); + ret = -EINVAL; + goto aes_prep_err; + } + + desc_in->callback = dthe_aes_dma_in_callback; + desc_in->callback_param = req; + + init_completion(&rctx->aes_compl); + + if (ctx->aes_mode == DTHE_AES_ECB) + dthe_aes_set_ctrl_key(ctx, rctx, NULL); + else + dthe_aes_set_ctrl_key(ctx, rctx, (u32 *)req->iv); + + writel_relaxed(lower_32_bits(req->cryptlen), aes_base_reg + DTHE_P_AES_C_LENGTH_0); + writel_relaxed(upper_32_bits(req->cryptlen), aes_base_reg + DTHE_P_AES_C_LENGTH_1); + + dmaengine_submit(desc_in); + dmaengine_submit(desc_out); + + dma_async_issue_pending(dev_data->dma_aes_rx); + dma_async_issue_pending(dev_data->dma_aes_tx); + + // Need to do a timeout to ensure finalise gets called if DMA callback fails for any reason + ret = wait_for_completion_timeout(&rctx->aes_compl, msecs_to_jiffies(DTHE_DMA_TIMEOUT_MS)); + if (!ret) { + ret = -ETIMEDOUT; + dmaengine_terminate_sync(dev_data->dma_aes_rx); + dmaengine_terminate_sync(dev_data->dma_aes_tx); + + for (int i = 0; i < AES_BLOCK_WORDS; ++i) + readl_relaxed(aes_base_reg + DTHE_P_AES_DATA_IN_OUT + (DTHE_REG_SIZE * i)); + } else { + ret = 0; + } + + // For modes other than ECB, read IV_OUT + if (ctx->aes_mode != DTHE_AES_ECB) { + u32 *iv_out = (u32 *)req->iv; + + for (int i = 0; i < AES_IV_WORDS; ++i) + iv_out[i] = readl_relaxed(aes_base_reg + + DTHE_P_AES_IV_IN_0 + + (DTHE_REG_SIZE * i)); + } + +aes_prep_err: + dma_unmap_sg(tx_dev, src, src_nents, src_dir); + if (dst_dir != DMA_BIDIRECTIONAL) + dma_unmap_sg(rx_dev, dst, dst_nents, dst_dir); + +aes_err: + local_bh_disable(); + crypto_finalize_skcipher_request(dev_data->engine, req, ret); + local_bh_enable(); + return ret; +} + +static int dthe_aes_crypt(struct skcipher_request *req) +{ + struct dthe_tfm_ctx *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); + struct dthe_data *dev_data = dthe_get_dev(ctx); + struct crypto_engine *engine; + + /* + * If data is not a multiple of AES_BLOCK_SIZE, need to return -EINVAL + * If data length input is zero, no need to do any operation. + */ + if (req->cryptlen % AES_BLOCK_SIZE) + return -EINVAL; + + if (req->cryptlen == 0) + return 0; + + engine = dev_data->engine; + return crypto_transfer_skcipher_request_to_engine(engine, req); +} + +static int dthe_aes_encrypt(struct skcipher_request *req) +{ + struct dthe_aes_req_ctx *rctx = skcipher_request_ctx(req); + + rctx->enc = 1; + return dthe_aes_crypt(req); +} + +static int dthe_aes_decrypt(struct skcipher_request *req) +{ + struct dthe_aes_req_ctx *rctx = skcipher_request_ctx(req); + + rctx->enc = 0; + return dthe_aes_crypt(req); +} + +static struct skcipher_engine_alg cipher_algs[] = { + { + .base.init = dthe_cipher_init_tfm, + .base.setkey = dthe_aes_ecb_setkey, + .base.encrypt = dthe_aes_encrypt, + .base.decrypt = dthe_aes_decrypt, + .base.min_keysize = AES_MIN_KEY_SIZE, + .base.max_keysize = AES_MAX_KEY_SIZE, + .base.base = { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-dthev2", + .cra_priority = 299, + .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_alignmask = AES_BLOCK_SIZE - 1, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct dthe_tfm_ctx), + .cra_reqsize = sizeof(struct dthe_aes_req_ctx), + .cra_module = THIS_MODULE, + }, + .op.do_one_request = dthe_aes_run, + }, /* ECB AES */ + { + .base.init = dthe_cipher_init_tfm, + .base.setkey = dthe_aes_cbc_setkey, + .base.encrypt = dthe_aes_encrypt, + .base.decrypt = dthe_aes_decrypt, + .base.min_keysize = AES_MIN_KEY_SIZE, + .base.max_keysize = AES_MAX_KEY_SIZE, + .base.ivsize = AES_IV_SIZE, + .base.base = { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-dthev2", + .cra_priority = 299, + .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_alignmask = AES_BLOCK_SIZE - 1, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct dthe_tfm_ctx), + .cra_reqsize = sizeof(struct dthe_aes_req_ctx), + .cra_module = THIS_MODULE, + }, + .op.do_one_request = dthe_aes_run, + } /* CBC AES */ +}; + +int dthe_register_aes_algs(void) +{ + return crypto_engine_register_skciphers(cipher_algs, ARRAY_SIZE(cipher_algs)); +} + +void dthe_unregister_aes_algs(void) +{ + crypto_engine_unregister_skciphers(cipher_algs, ARRAY_SIZE(cipher_algs)); +} diff --git a/drivers/crypto/ti/dthev2-common.c b/drivers/crypto/ti/dthev2-common.c new file mode 100644 index 000000000000..c39d37933b9e --- /dev/null +++ b/drivers/crypto/ti/dthev2-common.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * K3 DTHE V2 crypto accelerator driver + * + * Copyright (C) Texas Instruments 2025 - https://www.ti.com + * Author: T Pratham + */ + +#include +#include +#include +#include +#include + +#include "dthev2-common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "dthev2" + +static struct dthe_list dthe_dev_list = { + .dev_list = LIST_HEAD_INIT(dthe_dev_list.dev_list), + .lock = __SPIN_LOCK_UNLOCKED(dthe_dev_list.lock), +}; + +struct dthe_data *dthe_get_dev(struct dthe_tfm_ctx *ctx) +{ + struct dthe_data *dev_data; + + if (ctx->dev_data) + return ctx->dev_data; + + spin_lock_bh(&dthe_dev_list.lock); + dev_data = list_first_entry(&dthe_dev_list.dev_list, struct dthe_data, list); + if (dev_data) + list_move_tail(&dev_data->list, &dthe_dev_list.dev_list); + spin_unlock_bh(&dthe_dev_list.lock); + + return dev_data; +} + +static int dthe_dma_init(struct dthe_data *dev_data) +{ + int ret; + struct dma_slave_config cfg; + + dev_data->dma_aes_rx = NULL; + dev_data->dma_aes_tx = NULL; + dev_data->dma_sha_tx = NULL; + + dev_data->dma_aes_rx = dma_request_chan(dev_data->dev, "rx"); + if (IS_ERR(dev_data->dma_aes_rx)) { + return dev_err_probe(dev_data->dev, PTR_ERR(dev_data->dma_aes_rx), + "Unable to request rx DMA channel\n"); + } + + dev_data->dma_aes_tx = dma_request_chan(dev_data->dev, "tx1"); + if (IS_ERR(dev_data->dma_aes_tx)) { + ret = dev_err_probe(dev_data->dev, PTR_ERR(dev_data->dma_aes_tx), + "Unable to request tx1 DMA channel\n"); + goto err_dma_aes_tx; + } + + dev_data->dma_sha_tx = dma_request_chan(dev_data->dev, "tx2"); + if (IS_ERR(dev_data->dma_sha_tx)) { + ret = dev_err_probe(dev_data->dev, PTR_ERR(dev_data->dma_sha_tx), + "Unable to request tx2 DMA channel\n"); + goto err_dma_sha_tx; + } + + memzero_explicit(&cfg, sizeof(cfg)); + + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.src_maxburst = 4; + + ret = dmaengine_slave_config(dev_data->dma_aes_rx, &cfg); + if (ret) { + dev_err(dev_data->dev, "Can't configure IN dmaengine slave: %d\n", ret); + goto err_dma_config; + } + + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_maxburst = 4; + + ret = dmaengine_slave_config(dev_data->dma_aes_tx, &cfg); + if (ret) { + dev_err(dev_data->dev, "Can't configure OUT dmaengine slave: %d\n", ret); + goto err_dma_config; + } + + return 0; + +err_dma_config: + dma_release_channel(dev_data->dma_sha_tx); +err_dma_sha_tx: + dma_release_channel(dev_data->dma_aes_tx); +err_dma_aes_tx: + dma_release_channel(dev_data->dma_aes_rx); + + return ret; +} + +static int dthe_register_algs(void) +{ + return dthe_register_aes_algs(); +} + +static void dthe_unregister_algs(void) +{ + dthe_unregister_aes_algs(); +} + +static int dthe_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dthe_data *dev_data; + int ret; + + dev_data = devm_kzalloc(dev, sizeof(*dev_data), GFP_KERNEL); + if (!dev_data) + return -ENOMEM; + + dev_data->dev = dev; + dev_data->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev_data->regs)) + return PTR_ERR(dev_data->regs); + + platform_set_drvdata(pdev, dev_data); + + spin_lock(&dthe_dev_list.lock); + list_add(&dev_data->list, &dthe_dev_list.dev_list); + spin_unlock(&dthe_dev_list.lock); + + ret = dthe_dma_init(dev_data); + if (ret) + goto probe_dma_err; + + dev_data->engine = crypto_engine_alloc_init(dev, 1); + if (!dev_data->engine) { + ret = -ENOMEM; + goto probe_engine_err; + } + + ret = crypto_engine_start(dev_data->engine); + if (ret) { + dev_err(dev, "Failed to start crypto engine\n"); + goto probe_engine_start_err; + } + + ret = dthe_register_algs(); + if (ret) { + dev_err(dev, "Failed to register algs\n"); + goto probe_engine_start_err; + } + + return 0; + +probe_engine_start_err: + crypto_engine_exit(dev_data->engine); +probe_engine_err: + dma_release_channel(dev_data->dma_aes_rx); + dma_release_channel(dev_data->dma_aes_tx); + dma_release_channel(dev_data->dma_sha_tx); +probe_dma_err: + spin_lock(&dthe_dev_list.lock); + list_del(&dev_data->list); + spin_unlock(&dthe_dev_list.lock); + + return ret; +} + +static void dthe_remove(struct platform_device *pdev) +{ + struct dthe_data *dev_data = platform_get_drvdata(pdev); + + spin_lock(&dthe_dev_list.lock); + list_del(&dev_data->list); + spin_unlock(&dthe_dev_list.lock); + + dthe_unregister_algs(); + + crypto_engine_exit(dev_data->engine); + + dma_release_channel(dev_data->dma_aes_rx); + dma_release_channel(dev_data->dma_aes_tx); + dma_release_channel(dev_data->dma_sha_tx); +} + +static const struct of_device_id dthe_of_match[] = { + { .compatible = "ti,am62l-dthev2", }, + {}, +}; +MODULE_DEVICE_TABLE(of, dthe_of_match); + +static struct platform_driver dthe_driver = { + .probe = dthe_probe, + .remove = dthe_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = dthe_of_match, + }, +}; + +module_platform_driver(dthe_driver); + +MODULE_AUTHOR("T Pratham "); +MODULE_DESCRIPTION("Texas Instruments DTHE V2 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/crypto/ti/dthev2-common.h b/drivers/crypto/ti/dthev2-common.h new file mode 100644 index 000000000000..68c94acda8aa --- /dev/null +++ b/drivers/crypto/ti/dthev2-common.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * K3 DTHE V2 crypto accelerator driver + * + * Copyright (C) Texas Instruments 2025 - https://www.ti.com + * Author: T Pratham + */ + +#ifndef __TI_DTHEV2_H__ +#define __TI_DTHEV2_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define DTHE_REG_SIZE 4 +#define DTHE_DMA_TIMEOUT_MS 2000 + +enum dthe_aes_mode { + DTHE_AES_ECB = 0, + DTHE_AES_CBC, +}; + +/* Driver specific struct definitions */ + +/** + * struct dthe_data - DTHE_V2 driver instance data + * @dev: Device pointer + * @regs: Base address of the register space + * @list: list node for dev + * @engine: Crypto engine instance + * @dma_aes_rx: AES Rx DMA Channel + * @dma_aes_tx: AES Tx DMA Channel + * @dma_sha_tx: SHA Tx DMA Channel + */ +struct dthe_data { + struct device *dev; + void __iomem *regs; + struct list_head list; + struct crypto_engine *engine; + + struct dma_chan *dma_aes_rx; + struct dma_chan *dma_aes_tx; + + struct dma_chan *dma_sha_tx; +}; + +/** + * struct dthe_list - device data list head + * @dev_list: linked list head + * @lock: Spinlock protecting accesses to the list + */ +struct dthe_list { + struct list_head dev_list; + spinlock_t lock; +}; + +/** + * struct dthe_tfm_ctx - Transform ctx struct containing ctx for all sub-components of DTHE V2 + * @dev_data: Device data struct pointer + * @keylen: AES key length + * @key: AES key + * @aes_mode: AES mode + */ +struct dthe_tfm_ctx { + struct dthe_data *dev_data; + unsigned int keylen; + u32 key[AES_KEYSIZE_256 / sizeof(u32)]; + enum dthe_aes_mode aes_mode; +}; + +/** + * struct dthe_aes_req_ctx - AES engine req ctx struct + * @enc: flag indicating encryption or decryption operation + * @aes_compl: Completion variable for use in manual completion in case of DMA callback failure + */ +struct dthe_aes_req_ctx { + int enc; + struct completion aes_compl; +}; + +/* Struct definitions end */ + +struct dthe_data *dthe_get_dev(struct dthe_tfm_ctx *ctx); + +int dthe_register_aes_algs(void); +void dthe_unregister_aes_algs(void); + +#endif From ce136503bd9fed595fe0ba6dcae0f5f0f8cec7e3 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Wed, 20 Aug 2025 20:37:02 +0800 Subject: [PATCH 0689/2711] crypto: jh7110 - Remove the use of dev_err_probe() Logging messages that show some type of "out of memory" error are generally unnecessary as there is a generic message and a stack dump done by the memory subsystem. These messages generally increase kernel size without much added value[1]. The dev_err_probe() doesn't do anything when error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. [1]: https://lore.kernel.org/lkml/1402419340.30479.18.camel@joe-AO725/ Signed-off-by: Liao Yuanhong Signed-off-by: Herbert Xu --- drivers/crypto/starfive/jh7110-aes.c | 12 ++++-------- drivers/crypto/starfive/jh7110-hash.c | 3 +-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c index 86a1a1fa9f8f..426b24889af8 100644 --- a/drivers/crypto/starfive/jh7110-aes.c +++ b/drivers/crypto/starfive/jh7110-aes.c @@ -511,8 +511,7 @@ static int starfive_aes_map_sg(struct starfive_cryp_dev *cryp, stsg = sg_next(stsg), dtsg = sg_next(dtsg)) { src_nents = dma_map_sg(cryp->dev, stsg, 1, DMA_BIDIRECTIONAL); if (src_nents == 0) - return dev_err_probe(cryp->dev, -ENOMEM, - "dma_map_sg error\n"); + return -ENOMEM; dst_nents = src_nents; len = min(sg_dma_len(stsg), remain); @@ -528,13 +527,11 @@ static int starfive_aes_map_sg(struct starfive_cryp_dev *cryp, for (stsg = src, dtsg = dst;;) { src_nents = dma_map_sg(cryp->dev, stsg, 1, DMA_TO_DEVICE); if (src_nents == 0) - return dev_err_probe(cryp->dev, -ENOMEM, - "dma_map_sg src error\n"); + return -ENOMEM; dst_nents = dma_map_sg(cryp->dev, dtsg, 1, DMA_FROM_DEVICE); if (dst_nents == 0) - return dev_err_probe(cryp->dev, -ENOMEM, - "dma_map_sg dst error\n"); + return -ENOMEM; len = min(sg_dma_len(stsg), sg_dma_len(dtsg)); len = min(len, remain); @@ -669,8 +666,7 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq if (cryp->assoclen) { rctx->adata = kzalloc(cryp->assoclen + AES_BLOCK_SIZE, GFP_KERNEL); if (!rctx->adata) - return dev_err_probe(cryp->dev, -ENOMEM, - "Failed to alloc memory for adata"); + return -ENOMEM; if (sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, cryp->assoclen), rctx->adata, cryp->assoclen) != cryp->assoclen) diff --git a/drivers/crypto/starfive/jh7110-hash.c b/drivers/crypto/starfive/jh7110-hash.c index 6cfe0238f615..e6839c7bfb73 100644 --- a/drivers/crypto/starfive/jh7110-hash.c +++ b/drivers/crypto/starfive/jh7110-hash.c @@ -229,8 +229,7 @@ static int starfive_hash_one_request(struct crypto_engine *engine, void *areq) for_each_sg(rctx->in_sg, tsg, rctx->in_sg_len, i) { src_nents = dma_map_sg(cryp->dev, tsg, 1, DMA_TO_DEVICE); if (src_nents == 0) - return dev_err_probe(cryp->dev, -ENOMEM, - "dma_map_sg error\n"); + return -ENOMEM; ret = starfive_hash_dma_xfer(cryp, tsg); dma_unmap_sg(cryp->dev, tsg, 1, DMA_TO_DEVICE); From 8595bcb09b05a6c712c35f03ef701e7785895b51 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Wed, 20 Aug 2025 20:37:52 +0800 Subject: [PATCH 0690/2711] crypto: tegra - Remove the use of dev_err_probe() Logging messages that show some type of "out of memory" error are generally unnecessary as there is a generic message and a stack dump done by the memory subsystem. These messages generally increase kernel size without much added value[1]. The dev_err_probe() doesn't do anything when error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. [1]: https://lore.kernel.org/lkml/1402419340.30479.18.camel@joe-AO725/ Signed-off-by: Liao Yuanhong Signed-off-by: Herbert Xu --- drivers/crypto/tegra/tegra-se-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/tegra/tegra-se-main.c b/drivers/crypto/tegra/tegra-se-main.c index 1c94f1de0546..7237f14eaf5a 100644 --- a/drivers/crypto/tegra/tegra-se-main.c +++ b/drivers/crypto/tegra/tegra-se-main.c @@ -310,7 +310,7 @@ static int tegra_se_probe(struct platform_device *pdev) se->engine = crypto_engine_alloc_init(dev, 0); if (!se->engine) - return dev_err_probe(dev, -ENOMEM, "failed to init crypto engine\n"); + return -ENOMEM; ret = crypto_engine_start(se->engine); if (ret) { From 5cd459ebaae05651eccf04e5969953d1180d9dd2 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Wed, 20 Aug 2025 20:39:23 +0800 Subject: [PATCH 0691/2711] hwrng: cn10k - Remove the use of dev_err_probe() Logging messages that show some type of "out of memory" error are generally unnecessary as there is a generic message and a stack dump done by the memory subsystem. These messages generally increase kernel size without much added value[1]. The dev_err_probe() doesn't do anything when error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. [1]: https://lore.kernel.org/lkml/1402419340.30479.18.camel@joe-AO725/ Signed-off-by: Liao Yuanhong Signed-off-by: Herbert Xu --- drivers/char/hw_random/cn10k-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hw_random/cn10k-rng.c b/drivers/char/hw_random/cn10k-rng.c index 31935316a160..3b4e78182e14 100644 --- a/drivers/char/hw_random/cn10k-rng.c +++ b/drivers/char/hw_random/cn10k-rng.c @@ -188,7 +188,7 @@ static int cn10k_rng_probe(struct pci_dev *pdev, const struct pci_device_id *id) rng->reg_base = pcim_iomap(pdev, 0, 0); if (!rng->reg_base) - return dev_err_probe(&pdev->dev, -ENOMEM, "Error while mapping CSRs, exiting\n"); + return -ENOMEM; rng->ops.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "cn10k-rng-%s", dev_name(&pdev->dev)); From d4e081510471e79171c4e0a11f6cb608e49bc082 Mon Sep 17 00:00:00 2001 From: Chenghai Huang Date: Thu, 21 Aug 2025 09:38:04 +0800 Subject: [PATCH 0692/2711] crypto: hisilicon/zip - remove unnecessary validation for high-performance mode configurations When configuring the high-performance mode register, there is no need to verify whether the register has been successfully enabled, as there is no possibility of a write failure for this register. Fixes: a9864bae1806 ("crypto: hisilicon/zip - add zip comp high perf mode configuration") Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/zip/zip_main.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index d8ba23b7cc7d..fb7b19927dd3 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -448,10 +448,9 @@ bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg) return false; } -static int hisi_zip_set_high_perf(struct hisi_qm *qm) +static void hisi_zip_set_high_perf(struct hisi_qm *qm) { u32 val; - int ret; val = readl_relaxed(qm->io_base + HZIP_HIGH_PERF_OFFSET); if (perf_mode == HZIP_HIGH_COMP_PERF) @@ -461,13 +460,6 @@ static int hisi_zip_set_high_perf(struct hisi_qm *qm) /* Set perf mode */ writel(val, qm->io_base + HZIP_HIGH_PERF_OFFSET); - ret = readl_relaxed_poll_timeout(qm->io_base + HZIP_HIGH_PERF_OFFSET, - val, val == perf_mode, HZIP_DELAY_1_US, - HZIP_POLL_TIMEOUT_US); - if (ret) - pci_err(qm->pdev, "failed to set perf mode\n"); - - return ret; } static void hisi_zip_open_sva_prefetch(struct hisi_qm *qm) @@ -1251,9 +1243,7 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) if (ret) return ret; - ret = hisi_zip_set_high_perf(qm); - if (ret) - return ret; + hisi_zip_set_high_perf(qm); hisi_zip_open_sva_prefetch(qm); hisi_qm_dev_err_init(qm); From 0dcd21443d9308ed88909d35aa0490c3fc680a47 Mon Sep 17 00:00:00 2001 From: Chenghai Huang Date: Thu, 21 Aug 2025 09:38:05 +0800 Subject: [PATCH 0693/2711] crypto: hisilicon - re-enable address prefetch after device resuming When the device resumes from a suspended state, it will revert to its initial state and requires re-enabling. Currently, the address prefetch function is not re-enabled after device resuming. Move the address prefetch enable to the initialization process. In this way, the address prefetch can be enabled when the device resumes by calling the initialization process. Fixes: 607c191b371d ("crypto: hisilicon - support runtime PM for accelerator device") Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 3 +- drivers/crypto/hisilicon/qm.c | 3 - drivers/crypto/hisilicon/sec2/sec_main.c | 80 +++++++++++------------ drivers/crypto/hisilicon/zip/zip_main.c | 5 +- 4 files changed, 43 insertions(+), 48 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index f5b47e5ff48a..34f84978180f 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -721,6 +721,7 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) /* Config data buffer pasid needed by Kunpeng 920 */ hpre_config_pasid(qm); + hpre_open_sva_prefetch(qm); hpre_enable_clock_gate(qm); @@ -1450,8 +1451,6 @@ static int hpre_pf_probe_init(struct hpre *hpre) if (ret) return ret; - hpre_open_sva_prefetch(qm); - hisi_qm_dev_err_init(qm); ret = hpre_show_last_regs_init(qm); if (ret) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 2e4ee7ecfdfb..a5cc0ccd94f1 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -4447,9 +4447,6 @@ static void qm_restart_prepare(struct hisi_qm *qm) { u32 value; - if (qm->err_ini->open_sva_prefetch) - qm->err_ini->open_sva_prefetch(qm); - if (qm->ver >= QM_HW_V3) return; diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 72cf48d1f3ab..ddb20f380b54 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -464,6 +464,45 @@ static void sec_set_endian(struct hisi_qm *qm) writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG); } +static void sec_close_sva_prefetch(struct hisi_qm *qm) +{ + u32 val; + int ret; + + if (!test_bit(QM_SUPPORT_SVA_PREFETCH, &qm->caps)) + return; + + val = readl_relaxed(qm->io_base + SEC_PREFETCH_CFG); + val |= SEC_PREFETCH_DISABLE; + writel(val, qm->io_base + SEC_PREFETCH_CFG); + + ret = readl_relaxed_poll_timeout(qm->io_base + SEC_SVA_TRANS, + val, !(val & SEC_SVA_DISABLE_READY), + SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US); + if (ret) + pci_err(qm->pdev, "failed to close sva prefetch\n"); +} + +static void sec_open_sva_prefetch(struct hisi_qm *qm) +{ + u32 val; + int ret; + + if (!test_bit(QM_SUPPORT_SVA_PREFETCH, &qm->caps)) + return; + + /* Enable prefetch */ + val = readl_relaxed(qm->io_base + SEC_PREFETCH_CFG); + val &= SEC_PREFETCH_ENABLE; + writel(val, qm->io_base + SEC_PREFETCH_CFG); + + ret = readl_relaxed_poll_timeout(qm->io_base + SEC_PREFETCH_CFG, + val, !(val & SEC_PREFETCH_DISABLE), + SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US); + if (ret) + pci_err(qm->pdev, "failed to open sva prefetch\n"); +} + static void sec_engine_sva_config(struct hisi_qm *qm) { u32 reg; @@ -497,45 +536,7 @@ static void sec_engine_sva_config(struct hisi_qm *qm) writel_relaxed(reg, qm->io_base + SEC_INTERFACE_USER_CTRL1_REG); } -} - -static void sec_open_sva_prefetch(struct hisi_qm *qm) -{ - u32 val; - int ret; - - if (!test_bit(QM_SUPPORT_SVA_PREFETCH, &qm->caps)) - return; - - /* Enable prefetch */ - val = readl_relaxed(qm->io_base + SEC_PREFETCH_CFG); - val &= SEC_PREFETCH_ENABLE; - writel(val, qm->io_base + SEC_PREFETCH_CFG); - - ret = readl_relaxed_poll_timeout(qm->io_base + SEC_PREFETCH_CFG, - val, !(val & SEC_PREFETCH_DISABLE), - SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US); - if (ret) - pci_err(qm->pdev, "failed to open sva prefetch\n"); -} - -static void sec_close_sva_prefetch(struct hisi_qm *qm) -{ - u32 val; - int ret; - - if (!test_bit(QM_SUPPORT_SVA_PREFETCH, &qm->caps)) - return; - - val = readl_relaxed(qm->io_base + SEC_PREFETCH_CFG); - val |= SEC_PREFETCH_DISABLE; - writel(val, qm->io_base + SEC_PREFETCH_CFG); - - ret = readl_relaxed_poll_timeout(qm->io_base + SEC_SVA_TRANS, - val, !(val & SEC_SVA_DISABLE_READY), - SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US); - if (ret) - pci_err(qm->pdev, "failed to close sva prefetch\n"); + sec_open_sva_prefetch(qm); } static void sec_enable_clock_gate(struct hisi_qm *qm) @@ -1152,7 +1153,6 @@ static int sec_pf_probe_init(struct sec_dev *sec) if (ret) return ret; - sec_open_sva_prefetch(qm); hisi_qm_dev_err_init(qm); sec_debug_regs_clear(qm); ret = sec_show_last_regs_init(qm); diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index fb7b19927dd3..480fa590664a 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -557,6 +557,7 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) writel(AXUSER_BASE, base + HZIP_DATA_WUSER_32_63); writel(AXUSER_BASE, base + HZIP_SGL_RUSER_32_63); } + hisi_zip_open_sva_prefetch(qm); /* let's open all compression/decompression cores */ @@ -572,6 +573,7 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) CQC_CACHE_WB_ENABLE | FIELD_PREP(SQC_CACHE_WB_THRD, 1) | FIELD_PREP(CQC_CACHE_WB_THRD, 1), base + QM_CACHE_CTL); + hisi_zip_set_high_perf(qm); hisi_zip_enable_clock_gate(qm); return hisi_dae_set_user_domain(qm); @@ -1243,9 +1245,6 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) if (ret) return ret; - hisi_zip_set_high_perf(qm); - - hisi_zip_open_sva_prefetch(qm); hisi_qm_dev_err_init(qm); hisi_zip_debug_regs_clear(qm); From 1f9128f121a872f27251be60ccccfd98c136d72e Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Thu, 21 Aug 2025 09:38:06 +0800 Subject: [PATCH 0694/2711] crypto: hisilicon - check the sva module status while enabling or disabling address prefetch After enabling address prefetch, check the sva module status. If all previous prefetch requests from the sva module are not completed, then disable the address prefetch to ensure normal execution of new task operations. After disabling address prefetch, check if all requests from the sva module have been completed. Fixes: a5c164b195a8 ("crypto: hisilicon/qm - support address prefetching") Signed-off-by: Weili Qian Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 83 ++++++++++++++++------ drivers/crypto/hisilicon/sec2/sec_main.c | 48 ++++++++++++- drivers/crypto/hisilicon/zip/zip_main.c | 85 ++++++++++++++++++----- 3 files changed, 177 insertions(+), 39 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 34f84978180f..7b60e89015bd 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -78,6 +78,11 @@ #define HPRE_PREFETCH_ENABLE (~(BIT(0) | BIT(30))) #define HPRE_PREFETCH_DISABLE BIT(30) #define HPRE_SVA_DISABLE_READY (BIT(4) | BIT(8)) +#define HPRE_SVA_PREFTCH_DFX4 0x301144 +#define HPRE_WAIT_SVA_READY 500000 +#define HPRE_READ_SVA_STATUS_TIMES 3 +#define HPRE_WAIT_US_MIN 10 +#define HPRE_WAIT_US_MAX 20 /* clock gate */ #define HPRE_CLKGATE_CTL 0x301a10 @@ -466,6 +471,33 @@ struct hisi_qp *hpre_create_qp(u8 type) return NULL; } +static int hpre_wait_sva_ready(struct hisi_qm *qm) +{ + u32 val, try_times = 0; + u8 count = 0; + + /* + * Read the register value every 10-20us. If the value is 0 for three + * consecutive times, the SVA module is ready. + */ + do { + val = readl(qm->io_base + HPRE_SVA_PREFTCH_DFX4); + if (val) + count = 0; + else if (++count == HPRE_READ_SVA_STATUS_TIMES) + break; + + usleep_range(HPRE_WAIT_US_MIN, HPRE_WAIT_US_MAX); + } while (++try_times < HPRE_WAIT_SVA_READY); + + if (try_times == HPRE_WAIT_SVA_READY) { + pci_err(qm->pdev, "failed to wait sva prefetch ready\n"); + return -ETIMEDOUT; + } + + return 0; +} + static void hpre_config_pasid(struct hisi_qm *qm) { u32 val1, val2; @@ -563,27 +595,6 @@ static void disable_flr_of_bme(struct hisi_qm *qm) writel(PEH_AXUSER_CFG_ENABLE, qm->io_base + QM_PEH_AXUSER_CFG_ENABLE); } -static void hpre_open_sva_prefetch(struct hisi_qm *qm) -{ - u32 val; - int ret; - - if (!test_bit(QM_SUPPORT_SVA_PREFETCH, &qm->caps)) - return; - - /* Enable prefetch */ - val = readl_relaxed(qm->io_base + HPRE_PREFETCH_CFG); - val &= HPRE_PREFETCH_ENABLE; - writel(val, qm->io_base + HPRE_PREFETCH_CFG); - - ret = readl_relaxed_poll_timeout(qm->io_base + HPRE_PREFETCH_CFG, - val, !(val & HPRE_PREFETCH_DISABLE), - HPRE_REG_RD_INTVRL_US, - HPRE_REG_RD_TMOUT_US); - if (ret) - pci_err(qm->pdev, "failed to open sva prefetch\n"); -} - static void hpre_close_sva_prefetch(struct hisi_qm *qm) { u32 val; @@ -602,6 +613,36 @@ static void hpre_close_sva_prefetch(struct hisi_qm *qm) HPRE_REG_RD_TMOUT_US); if (ret) pci_err(qm->pdev, "failed to close sva prefetch\n"); + + (void)hpre_wait_sva_ready(qm); +} + +static void hpre_open_sva_prefetch(struct hisi_qm *qm) +{ + u32 val; + int ret; + + if (!test_bit(QM_SUPPORT_SVA_PREFETCH, &qm->caps)) + return; + + /* Enable prefetch */ + val = readl_relaxed(qm->io_base + HPRE_PREFETCH_CFG); + val &= HPRE_PREFETCH_ENABLE; + writel(val, qm->io_base + HPRE_PREFETCH_CFG); + + ret = readl_relaxed_poll_timeout(qm->io_base + HPRE_PREFETCH_CFG, + val, !(val & HPRE_PREFETCH_DISABLE), + HPRE_REG_RD_INTVRL_US, + HPRE_REG_RD_TMOUT_US); + if (ret) { + pci_err(qm->pdev, "failed to open sva prefetch\n"); + hpre_close_sva_prefetch(qm); + return; + } + + ret = hpre_wait_sva_ready(qm); + if (ret) + hpre_close_sva_prefetch(qm); } static void hpre_enable_clock_gate(struct hisi_qm *qm) diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index ddb20f380b54..348f1f52956d 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -93,6 +93,16 @@ #define SEC_PREFETCH_ENABLE (~(BIT(0) | BIT(1) | BIT(11))) #define SEC_PREFETCH_DISABLE BIT(1) #define SEC_SVA_DISABLE_READY (BIT(7) | BIT(11)) +#define SEC_SVA_PREFETCH_INFO 0x301ED4 +#define SEC_SVA_STALL_NUM GENMASK(23, 8) +#define SEC_SVA_PREFETCH_NUM GENMASK(2, 0) +#define SEC_WAIT_SVA_READY 500000 +#define SEC_READ_SVA_STATUS_TIMES 3 +#define SEC_WAIT_US_MIN 10 +#define SEC_WAIT_US_MAX 20 +#define SEC_WAIT_QP_US_MIN 1000 +#define SEC_WAIT_QP_US_MAX 2000 +#define SEC_MAX_WAIT_TIMES 2000 #define SEC_DELAY_10_US 10 #define SEC_POLL_TIMEOUT_US 1000 @@ -464,6 +474,33 @@ static void sec_set_endian(struct hisi_qm *qm) writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG); } +static int sec_wait_sva_ready(struct hisi_qm *qm, __u32 offset, __u32 mask) +{ + u32 val, try_times = 0; + u8 count = 0; + + /* + * Read the register value every 10-20us. If the value is 0 for three + * consecutive times, the SVA module is ready. + */ + do { + val = readl(qm->io_base + offset); + if (val & mask) + count = 0; + else if (++count == SEC_READ_SVA_STATUS_TIMES) + break; + + usleep_range(SEC_WAIT_US_MIN, SEC_WAIT_US_MAX); + } while (++try_times < SEC_WAIT_SVA_READY); + + if (try_times == SEC_WAIT_SVA_READY) { + pci_err(qm->pdev, "failed to wait sva prefetch ready\n"); + return -ETIMEDOUT; + } + + return 0; +} + static void sec_close_sva_prefetch(struct hisi_qm *qm) { u32 val; @@ -481,6 +518,8 @@ static void sec_close_sva_prefetch(struct hisi_qm *qm) SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US); if (ret) pci_err(qm->pdev, "failed to close sva prefetch\n"); + + (void)sec_wait_sva_ready(qm, SEC_SVA_PREFETCH_INFO, SEC_SVA_STALL_NUM); } static void sec_open_sva_prefetch(struct hisi_qm *qm) @@ -499,8 +538,15 @@ static void sec_open_sva_prefetch(struct hisi_qm *qm) ret = readl_relaxed_poll_timeout(qm->io_base + SEC_PREFETCH_CFG, val, !(val & SEC_PREFETCH_DISABLE), SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US); - if (ret) + if (ret) { pci_err(qm->pdev, "failed to open sva prefetch\n"); + sec_close_sva_prefetch(qm); + return; + } + + ret = sec_wait_sva_ready(qm, SEC_SVA_TRANS, SEC_SVA_PREFETCH_NUM); + if (ret) + sec_close_sva_prefetch(qm); } static void sec_engine_sva_config(struct hisi_qm *qm) diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 480fa590664a..341c4564e21a 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -95,10 +95,16 @@ #define HZIP_PREFETCH_ENABLE (~(BIT(26) | BIT(17) | BIT(0))) #define HZIP_SVA_PREFETCH_DISABLE BIT(26) #define HZIP_SVA_DISABLE_READY (BIT(26) | BIT(30)) +#define HZIP_SVA_PREFETCH_NUM GENMASK(18, 16) +#define HZIP_SVA_STALL_NUM GENMASK(15, 0) #define HZIP_SHAPER_RATE_COMPRESS 750 #define HZIP_SHAPER_RATE_DECOMPRESS 140 -#define HZIP_DELAY_1_US 1 -#define HZIP_POLL_TIMEOUT_US 1000 +#define HZIP_DELAY_1_US 1 +#define HZIP_POLL_TIMEOUT_US 1000 +#define HZIP_WAIT_SVA_READY 500000 +#define HZIP_READ_SVA_STATUS_TIMES 3 +#define HZIP_WAIT_US_MIN 10 +#define HZIP_WAIT_US_MAX 20 /* clock gating */ #define HZIP_PEH_CFG_AUTO_GATE 0x3011A8 @@ -462,24 +468,31 @@ static void hisi_zip_set_high_perf(struct hisi_qm *qm) writel(val, qm->io_base + HZIP_HIGH_PERF_OFFSET); } -static void hisi_zip_open_sva_prefetch(struct hisi_qm *qm) +static int hisi_zip_wait_sva_ready(struct hisi_qm *qm, __u32 offset, __u32 mask) { - u32 val; - int ret; + u32 val, try_times = 0; + u8 count = 0; - if (!test_bit(QM_SUPPORT_SVA_PREFETCH, &qm->caps)) - return; + /* + * Read the register value every 10-20us. If the value is 0 for three + * consecutive times, the SVA module is ready. + */ + do { + val = readl(qm->io_base + offset); + if (val & mask) + count = 0; + else if (++count == HZIP_READ_SVA_STATUS_TIMES) + break; - /* Enable prefetch */ - val = readl_relaxed(qm->io_base + HZIP_PREFETCH_CFG); - val &= HZIP_PREFETCH_ENABLE; - writel(val, qm->io_base + HZIP_PREFETCH_CFG); + usleep_range(HZIP_WAIT_US_MIN, HZIP_WAIT_US_MAX); + } while (++try_times < HZIP_WAIT_SVA_READY); - ret = readl_relaxed_poll_timeout(qm->io_base + HZIP_PREFETCH_CFG, - val, !(val & HZIP_SVA_PREFETCH_DISABLE), - HZIP_DELAY_1_US, HZIP_POLL_TIMEOUT_US); - if (ret) - pci_err(qm->pdev, "failed to open sva prefetch\n"); + if (try_times == HZIP_WAIT_SVA_READY) { + pci_err(qm->pdev, "failed to wait sva prefetch ready\n"); + return -ETIMEDOUT; + } + + return 0; } static void hisi_zip_close_sva_prefetch(struct hisi_qm *qm) @@ -499,6 +512,35 @@ static void hisi_zip_close_sva_prefetch(struct hisi_qm *qm) HZIP_DELAY_1_US, HZIP_POLL_TIMEOUT_US); if (ret) pci_err(qm->pdev, "failed to close sva prefetch\n"); + + (void)hisi_zip_wait_sva_ready(qm, HZIP_SVA_TRANS, HZIP_SVA_STALL_NUM); +} + +static void hisi_zip_open_sva_prefetch(struct hisi_qm *qm) +{ + u32 val; + int ret; + + if (!test_bit(QM_SUPPORT_SVA_PREFETCH, &qm->caps)) + return; + + /* Enable prefetch */ + val = readl_relaxed(qm->io_base + HZIP_PREFETCH_CFG); + val &= HZIP_PREFETCH_ENABLE; + writel(val, qm->io_base + HZIP_PREFETCH_CFG); + + ret = readl_relaxed_poll_timeout(qm->io_base + HZIP_PREFETCH_CFG, + val, !(val & HZIP_SVA_PREFETCH_DISABLE), + HZIP_DELAY_1_US, HZIP_POLL_TIMEOUT_US); + if (ret) { + pci_err(qm->pdev, "failed to open sva prefetch\n"); + hisi_zip_close_sva_prefetch(qm); + return; + } + + ret = hisi_zip_wait_sva_ready(qm, HZIP_SVA_TRANS, HZIP_SVA_PREFETCH_NUM); + if (ret) + hisi_zip_close_sva_prefetch(qm); } static void hisi_zip_enable_clock_gate(struct hisi_qm *qm) @@ -522,6 +564,7 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) void __iomem *base = qm->io_base; u32 dcomp_bm, comp_bm; u32 zip_core_en; + int ret; /* qm user domain */ writel(AXUSER_BASE, base + QM_ARUSER_M_CFG_1); @@ -576,7 +619,15 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) hisi_zip_set_high_perf(qm); hisi_zip_enable_clock_gate(qm); - return hisi_dae_set_user_domain(qm); + ret = hisi_dae_set_user_domain(qm); + if (ret) + goto close_sva_prefetch; + + return 0; + +close_sva_prefetch: + hisi_zip_close_sva_prefetch(qm); + return ret; } static void hisi_zip_master_ooo_ctrl(struct hisi_qm *qm, bool enable) From 6a2c9164b52e6bc134127fd543461fdef95cc8ec Mon Sep 17 00:00:00 2001 From: Zhushuai Yin Date: Thu, 21 Aug 2025 09:38:07 +0800 Subject: [PATCH 0695/2711] crypto: hisilicon/qm - check whether the input function and PF are on the same device Function rate limiting is set through physical function driver. Users configure by providing function information and rate limit values. Before configuration, it is necessary to check whether the provided function and PF belong to the same device. Fixes: 22d7a6c39cab ("crypto: hisilicon/qm - add pci bdf number check") Signed-off-by: Zhushuai Yin Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index a5cc0ccd94f1..2f96c673b60a 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -3826,6 +3826,10 @@ static ssize_t qm_get_qos_value(struct hisi_qm *qm, const char *buf, } pdev = container_of(dev, struct pci_dev, dev); + if (pci_physfn(pdev) != qm->pdev) { + pci_err(qm->pdev, "the pdev input does not match the pf!\n"); + return -EINVAL; + } *fun_index = pdev->devfn; From 9228facb308157ac0bdd264b873187896f7a9c7a Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Thu, 21 Aug 2025 09:38:08 +0800 Subject: [PATCH 0696/2711] crypto: hisilicon/qm - request reserved interrupt for virtual function The device interrupt vector 3 is an error interrupt for physical function and a reserved interrupt for virtual function. However, the driver has not registered the reserved interrupt for virtual function. When allocating interrupts, the number of interrupts is allocated based on powers of two, which includes this interrupt. When the system enables GICv4 and the virtual function passthrough to the virtual machine, releasing the interrupt in the driver triggers a warning. The WARNING report is: WARNING: CPU: 62 PID: 14889 at arch/arm64/kvm/vgic/vgic-its.c:852 its_free_ite+0x94/0xb4 Therefore, register a reserved interrupt for VF and set the IRQF_NO_AUTOEN flag to avoid that warning. Fixes: 3536cc55cada ("crypto: hisilicon/qm - support get device irq information from hardware registers") Signed-off-by: Weili Qian Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 38 +++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 2f96c673b60a..102aff9ea19a 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -4732,6 +4732,15 @@ flr_done: } EXPORT_SYMBOL_GPL(hisi_qm_reset_done); +static irqreturn_t qm_rsvd_irq(int irq, void *data) +{ + struct hisi_qm *qm = data; + + dev_info(&qm->pdev->dev, "Reserved interrupt, ignore!\n"); + + return IRQ_HANDLED; +} + static irqreturn_t qm_abnormal_irq(int irq, void *data) { struct hisi_qm *qm = data; @@ -5015,7 +5024,7 @@ static void qm_unregister_abnormal_irq(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; u32 irq_vector, val; - if (qm->fun_type == QM_HW_VF) + if (qm->fun_type == QM_HW_VF && qm->ver < QM_HW_V3) return; val = qm->cap_tables.qm_cap_table[QM_ABNORMAL_IRQ].cap_val; @@ -5032,17 +5041,28 @@ static int qm_register_abnormal_irq(struct hisi_qm *qm) u32 irq_vector, val; int ret; - if (qm->fun_type == QM_HW_VF) - return 0; - val = qm->cap_tables.qm_cap_table[QM_ABNORMAL_IRQ].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) return 0; - irq_vector = val & QM_IRQ_VECTOR_MASK; + + /* For VF, this is a reserved interrupt in V3 version. */ + if (qm->fun_type == QM_HW_VF) { + if (qm->ver < QM_HW_V3) + return 0; + + ret = request_irq(pci_irq_vector(pdev, irq_vector), qm_rsvd_irq, + IRQF_NO_AUTOEN, qm->dev_name, qm); + if (ret) { + dev_err(&pdev->dev, "failed to request reserved irq, ret = %d!\n", ret); + return ret; + } + return 0; + } + ret = request_irq(pci_irq_vector(pdev, irq_vector), qm_abnormal_irq, 0, qm->dev_name, qm); if (ret) - dev_err(&qm->pdev->dev, "failed to request abnormal irq, ret = %d", ret); + dev_err(&qm->pdev->dev, "failed to request abnormal irq, ret = %d!\n", ret); return ret; } @@ -5408,6 +5428,12 @@ static int hisi_qm_pci_init(struct hisi_qm *qm) pci_set_master(pdev); num_vec = qm_get_irq_num(qm); + if (!num_vec) { + dev_err(dev, "Device irq num is zero!\n"); + ret = -EINVAL; + goto err_get_pci_res; + } + num_vec = roundup_pow_of_two(num_vec); ret = pci_alloc_irq_vectors(pdev, num_vec, num_vec, PCI_IRQ_MSI); if (ret < 0) { dev_err(dev, "Failed to enable MSI vectors!\n"); From dcd2d5fda2bb3898eca9380c13da1f346de1df6f Mon Sep 17 00:00:00 2001 From: Chenghai Huang Date: Thu, 21 Aug 2025 09:38:09 +0800 Subject: [PATCH 0697/2711] crypto: hisilicon/zip - enable literal length in stream mode compression In stream mode, the hardware needs to combine the length of the previous literal to calculate the length of the current literal. Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/zip/zip_main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 341c4564e21a..8c64f145173f 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -117,6 +117,9 @@ /* zip comp high performance */ #define HZIP_HIGH_PERF_OFFSET 0x301208 +#define HZIP_LIT_LEN_EN_OFFSET 0x301204 +#define HZIP_LIT_LEN_EN_EN BIT(4) + enum { HZIP_HIGH_COMP_RATE, HZIP_HIGH_COMP_PERF, @@ -454,6 +457,20 @@ bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg) return false; } +static void hisi_zip_literal_set(struct hisi_qm *qm) +{ + u32 val; + + if (qm->ver < QM_HW_V3) + return; + + val = readl_relaxed(qm->io_base + HZIP_LIT_LEN_EN_OFFSET); + val &= ~HZIP_LIT_LEN_EN_EN; + + /* enable literal length in stream mode compression */ + writel(val, qm->io_base + HZIP_LIT_LEN_EN_OFFSET); +} + static void hisi_zip_set_high_perf(struct hisi_qm *qm) { u32 val; @@ -617,6 +634,7 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) FIELD_PREP(CQC_CACHE_WB_THRD, 1), base + QM_CACHE_CTL); hisi_zip_set_high_perf(qm); + hisi_zip_literal_set(qm); hisi_zip_enable_clock_gate(qm); ret = hisi_dae_set_user_domain(qm); From 4c634b6b3c77bba237ee64bca172e73f9cee0cb2 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 21 Aug 2025 22:20:26 +0800 Subject: [PATCH 0698/2711] crypto: qat - use kcalloc() in qat_uclo_map_objs_from_mof() As noted in the kernel documentation [1], open-coded multiplication in allocator arguments is discouraged because it can lead to integer overflow. Use kcalloc() to gain built-in overflow protection, making memory allocation safer when calculating allocation size compared to explicit multiplication. Similarly, use size_add() instead of explicit addition for 'uobj_chunk_num + sobj_chunk_num'. Link: https://www.kernel.org/doc/html/next/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments #1 Signed-off-by: Qianfeng Rong Reviewed-by: Andy Shevchenko Acked-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/qat_uclo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/intel/qat/qat_common/qat_uclo.c b/drivers/crypto/intel/qat/qat_common/qat_uclo.c index 21d652a1c8ef..18c3e4416dc5 100644 --- a/drivers/crypto/intel/qat/qat_common/qat_uclo.c +++ b/drivers/crypto/intel/qat/qat_common/qat_uclo.c @@ -1900,7 +1900,7 @@ static int qat_uclo_map_objs_from_mof(struct icp_qat_mof_handle *mobj_handle) if (sobj_hdr) sobj_chunk_num = sobj_hdr->num_chunks; - mobj_hdr = kzalloc((uobj_chunk_num + sobj_chunk_num) * + mobj_hdr = kcalloc(size_add(uobj_chunk_num, sobj_chunk_num), sizeof(*mobj_hdr), GFP_KERNEL); if (!mobj_hdr) return -ENOMEM; From 41eab2a95950682cdc9c5e60cb3457e29f186540 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 21 Aug 2025 22:27:31 +0800 Subject: [PATCH 0699/2711] crypto: hisilicon - use kcalloc() instead of kzalloc() As noted in the kernel documentation [1], open-coded multiplication in allocator arguments is discouraged because it can lead to integer overflow. Use devm_kcalloc() to gain built-in overflow protection, making memory allocation safer when calculating allocation size compared to explicit multiplication. Link: https://www.kernel.org/doc/html/next/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments #1 Signed-off-by: Qianfeng Rong Reviewed-by: Longfang Liu Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 2 +- drivers/crypto/hisilicon/sec2/sec_main.c | 2 +- drivers/crypto/hisilicon/zip/zip_main.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 7b60e89015bd..f437f361a2c9 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -1213,7 +1213,7 @@ static int hpre_pre_store_cap_reg(struct hisi_qm *qm) size_t i, size; size = ARRAY_SIZE(hpre_cap_query_info); - hpre_cap = devm_kzalloc(dev, sizeof(*hpre_cap) * size, GFP_KERNEL); + hpre_cap = devm_kcalloc(dev, size, sizeof(*hpre_cap), GFP_KERNEL); if (!hpre_cap) return -ENOMEM; diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 348f1f52956d..bdb2d52ee1b6 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -1215,7 +1215,7 @@ static int sec_pre_store_cap_reg(struct hisi_qm *qm) size_t i, size; size = ARRAY_SIZE(sec_cap_query_info); - sec_cap = devm_kzalloc(&pdev->dev, sizeof(*sec_cap) * size, GFP_KERNEL); + sec_cap = devm_kcalloc(&pdev->dev, size, sizeof(*sec_cap), GFP_KERNEL); if (!sec_cap) return -ENOMEM; diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 8c64f145173f..fcb72d5cf592 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -1331,7 +1331,7 @@ static int zip_pre_store_cap_reg(struct hisi_qm *qm) size_t i, size; size = ARRAY_SIZE(zip_cap_query_info); - zip_cap = devm_kzalloc(&pdev->dev, sizeof(*zip_cap) * size, GFP_KERNEL); + zip_cap = devm_kcalloc(&pdev->dev, size, sizeof(*zip_cap), GFP_KERNEL); if (!zip_cap) return -ENOMEM; From a52bdee13ed77f02dfd902baeb0eae876846672e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 28 Aug 2025 16:54:52 -0500 Subject: [PATCH 0700/2711] dt-bindings: iio: adc: adi,ad7124: fix clocks properties Use correct clocks properties for the AD7124 family of ADCs. These ADCs have an internal clock along with an optional external clock that can be connected to the CLK pin. This pin can be wired up 3 ways: 1. Not connected - the internal clock is used. 2. Connected to an external clock (input) - the external clock is used. 3. Connected to the CLK pin on another ADC (output) - the internal clock is used on one and the other is configured for an external clock. The new bindings describe these 3 cases by picking one of the following: 1. Omit both clocks and #clock-cells properties. 2. Include only the clocks property with a phandle to the external clock. 3. Include only the #clock-cells property on the ADC providing the output. The clock-names property is now deprecated and should not be used. The MCLK signal that it refers to is an internal counter in the ADC and therefore does not make sense as a devicetree property as it can't be connected to anything external to the ADC. Since there is only one possible external clock, the clock-names property is not needed anyway. Based on the implementation of the Linux driver, it looks like the "mclk" clock was basically being used as a control to select the power mode of the ADC, which is not something that should be done in the devicetree. Reviewed-by: Rob Herring (Arm) Signed-off-by: David Lechner Link: https://patch.msgid.link/20250828-iio-adc-ad7124-proper-clock-support-v3-1-0b317b4605e5@baylibre.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7124.yaml | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml index 4dd5395730c1..2e3f84db6193 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml @@ -28,12 +28,21 @@ properties: clocks: maxItems: 1 - description: phandle to the master clock (mclk) + description: Optional external clock connected to the CLK pin. clock-names: + deprecated: true + description: + MCLK is an internal counter in the ADC. Do not use this property. items: - const: mclk + '#clock-cells': + description: + The CLK pin can be used as an output. When that is the case, include + this property. + const: 0 + interrupts: description: IRQ line for the ADC maxItems: 1 @@ -67,10 +76,14 @@ properties: required: - compatible - reg - - clocks - - clock-names - interrupts +# Can't have both clock input and output at the same time. +not: + required: + - '#clock-cells' + - clocks + patternProperties: "^channel@([0-9]|1[0-5])$": $ref: adc.yaml @@ -136,8 +149,6 @@ examples: interrupt-parent = <&gpio>; rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>; refin1-supply = <&adc_vref>; - clocks = <&ad7124_mclk>; - clock-names = "mclk"; #address-cells = <1>; #size-cells = <0>; From aead8e4cc04612f74c7277de137cc995df280829 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 28 Aug 2025 16:54:53 -0500 Subject: [PATCH 0701/2711] iio: adc: ad7124: do not require mclk Make the "mclk" clock optional in the ad7124 driver. The MCLK is an internal counter on the ADC, so it is not something that should be coming from the devicetree. However, existing users may be using this to essentially select the power mode of the ADC from the devicetree. In order to not break those users, we have to keep the existing "mclk" handling, but now it is optional. Now, when the "mclk" clock is omitted from the devicetree, the driver will default to the full power mode. Support for an external clock and dynamic power mode switching can be added later if needed. Signed-off-by: David Lechner Link: https://patch.msgid.link/20250828-iio-adc-ad7124-proper-clock-support-v3-2-0b317b4605e5@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 62 ++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 4481a4ca7ac3..934437bda97b 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -174,7 +174,6 @@ struct ad7124_state { struct ad_sigma_delta sd; struct ad7124_channel *channels; struct regulator *vref[4]; - struct clk *mclk; unsigned int adc_control; unsigned int num_channels; struct mutex cfgs_lock; /* lock for configs access */ @@ -254,7 +253,9 @@ static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel { unsigned int fclk, odr_sel_bits; - fclk = clk_get_rate(st->mclk); + fclk = ad7124_master_clk_freq_hz[FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE, + st->adc_control)]; + /* * FS[10:0] = fCLK / (fADC x 32) where: * fADC is the output data rate @@ -1111,21 +1112,50 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, static int ad7124_setup(struct ad7124_state *st) { struct device *dev = &st->sd.spi->dev; - unsigned int fclk, power_mode; + unsigned int power_mode; + struct clk *mclk; int i, ret; - fclk = clk_get_rate(st->mclk); - if (!fclk) - return dev_err_probe(dev, -EINVAL, "Failed to get mclk rate\n"); + /* + * Always use full power mode for max performance. If needed, the driver + * could be adapted to use a dynamic power mode based on the requested + * output data rate. + */ + power_mode = AD7124_ADC_CONTROL_POWER_MODE_FULL; - /* The power mode changes the master clock frequency */ - power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz, - ARRAY_SIZE(ad7124_master_clk_freq_hz), - fclk); - if (fclk != ad7124_master_clk_freq_hz[power_mode]) { - ret = clk_set_rate(st->mclk, fclk); - if (ret) - return dev_err_probe(dev, ret, "Failed to set mclk rate\n"); + /* + * This "mclk" business is needed for backwards compatibility with old + * devicetrees that specified a fake clock named "mclk" to select the + * power mode. + */ + mclk = devm_clk_get_optional_enabled(dev, "mclk"); + if (IS_ERR(mclk)) + return dev_err_probe(dev, PTR_ERR(mclk), "Failed to get mclk\n"); + + if (mclk) { + unsigned long mclk_hz; + + mclk_hz = clk_get_rate(mclk); + if (!mclk_hz) + return dev_err_probe(dev, -EINVAL, + "Failed to get mclk rate\n"); + + /* + * This logic is a bit backwards, which is why it is only here + * for backwards compatibility. The driver should be able to set + * the power mode as it sees fit and the f_clk/mclk rate should + * be dynamic accordingly. But here, we are selecting a fixed + * power mode based on the given "mclk" rate. + */ + power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz, + ARRAY_SIZE(ad7124_master_clk_freq_hz), mclk_hz); + + if (mclk_hz != ad7124_master_clk_freq_hz[power_mode]) { + ret = clk_set_rate(mclk, mclk_hz); + if (ret) + return dev_err_probe(dev, ret, + "Failed to set mclk rate\n"); + } } /* Set the power mode */ @@ -1303,10 +1333,6 @@ static int ad7124_probe(struct spi_device *spi) return ret; } - st->mclk = devm_clk_get_enabled(&spi->dev, "mclk"); - if (IS_ERR(st->mclk)) - return dev_err_probe(dev, PTR_ERR(st->mclk), "Failed to get mclk\n"); - ret = ad7124_soft_reset(st); if (ret < 0) return ret; From ed231e253ff23214712c8884165b4eb8a441f573 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 28 Aug 2025 16:54:54 -0500 Subject: [PATCH 0702/2711] iio: adc: ad7124: add external clock support Add support for an external clock source to the AD7124 ADC driver. Previously, the driver only supported using the internal clock and had bad devicetree bindings that used a fake clock to essentially select the power mode. This is preserved for backwards compatibility. If the clock is not named "mclk", then we know that the devicetree is using the correct bindings and we can configure the chip to use an external clock source rather than internal. Also drop a redundant comment when configuring the register fields instead of adding more. Signed-off-by: David Lechner Link: https://patch.msgid.link/20250828-iio-adc-ad7124-proper-clock-support-v3-3-0b317b4605e5@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 83 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 7 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 934437bda97b..1a9a8d6f1943 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,11 @@ #define AD7124_STATUS_POR_FLAG BIT(4) /* AD7124_ADC_CONTROL */ +#define AD7124_ADC_CONTROL_CLK_SEL GENMASK(1, 0) +#define AD7124_ADC_CONTROL_CLK_SEL_INT 0 +#define AD7124_ADC_CONTROL_CLK_SEL_INT_OUT 1 +#define AD7124_ADC_CONTROL_CLK_SEL_EXT 2 +#define AD7124_ADC_CONTROL_CLK_SEL_EXT_DIV4 3 #define AD7124_ADC_CONTROL_MODE GENMASK(5, 2) #define AD7124_ADC_CONTROL_MODE_CONTINUOUS 0 #define AD7124_ADC_CONTROL_MODE_SINGLE 1 @@ -92,6 +98,8 @@ #define AD7124_MAX_CONFIGS 8 #define AD7124_MAX_CHANNELS 16 +#define AD7124_INT_CLK_HZ 614400 + /* AD7124 input sources */ enum ad7124_ref_sel { @@ -120,9 +128,9 @@ static const unsigned int ad7124_reg_size[] = { }; static const int ad7124_master_clk_freq_hz[3] = { - [AD7124_LOW_POWER] = 76800, - [AD7124_MID_POWER] = 153600, - [AD7124_FULL_POWER] = 614400, + [AD7124_LOW_POWER] = AD7124_INT_CLK_HZ / 8, + [AD7124_MID_POWER] = AD7124_INT_CLK_HZ / 4, + [AD7124_FULL_POWER] = AD7124_INT_CLK_HZ, }; static const char * const ad7124_ref_names[] = { @@ -174,6 +182,7 @@ struct ad7124_state { struct ad_sigma_delta sd; struct ad7124_channel *channels; struct regulator *vref[4]; + u32 clk_hz; unsigned int adc_control; unsigned int num_channels; struct mutex cfgs_lock; /* lock for configs access */ @@ -249,12 +258,33 @@ static int ad7124_set_mode(struct ad_sigma_delta *sd, return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control); } +static u32 ad7124_get_fclk_hz(struct ad7124_state *st) +{ + enum ad7124_power_mode power_mode; + u32 fclk_hz; + + power_mode = FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE, st->adc_control); + fclk_hz = st->clk_hz; + + switch (power_mode) { + case AD7124_LOW_POWER: + fclk_hz /= 8; + break; + case AD7124_MID_POWER: + fclk_hz /= 4; + break; + default: + break; + } + + return fclk_hz; +} + static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, unsigned int odr) { unsigned int fclk, odr_sel_bits; - fclk = ad7124_master_clk_freq_hz[FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE, - st->adc_control)]; + fclk = ad7124_get_fclk_hz(st); /* * FS[10:0] = fCLK / (fADC x 32) where: @@ -1112,7 +1142,7 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, static int ad7124_setup(struct ad7124_state *st) { struct device *dev = &st->sd.spi->dev; - unsigned int power_mode; + unsigned int power_mode, clk_sel; struct clk *mclk; int i, ret; @@ -1156,9 +1186,48 @@ static int ad7124_setup(struct ad7124_state *st) return dev_err_probe(dev, ret, "Failed to set mclk rate\n"); } + + clk_sel = AD7124_ADC_CONTROL_CLK_SEL_INT; + st->clk_hz = AD7124_INT_CLK_HZ; + } else { + struct clk *clk; + + clk = devm_clk_get_optional_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "Failed to get external clock\n"); + + if (clk) { + unsigned long clk_hz; + + clk_hz = clk_get_rate(clk); + if (!clk_hz) + return dev_err_probe(dev, -EINVAL, + "Failed to get external clock rate\n"); + + /* + * The external clock may be 4x the nominal clock rate, + * in which case the ADC needs to be configured to + * divide it by 4. Using MEGA is a bit arbitrary, but + * the expected clock rates are either 614.4 kHz or + * 2.4576 MHz, so this should work. + */ + if (clk_hz > (1 * HZ_PER_MHZ)) { + clk_sel = AD7124_ADC_CONTROL_CLK_SEL_EXT_DIV4; + st->clk_hz = clk_hz / 4; + } else { + clk_sel = AD7124_ADC_CONTROL_CLK_SEL_EXT; + st->clk_hz = clk_hz; + } + } else { + clk_sel = AD7124_ADC_CONTROL_CLK_SEL_INT; + st->clk_hz = AD7124_INT_CLK_HZ; + } } - /* Set the power mode */ + st->adc_control &= ~AD7124_ADC_CONTROL_CLK_SEL; + st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_CLK_SEL, clk_sel); + st->adc_control &= ~AD7124_ADC_CONTROL_POWER_MODE; st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_POWER_MODE, power_mode); From dfbbee0907fb30a1dd31ff1a84e1bd34bd824369 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 28 Aug 2025 16:54:55 -0500 Subject: [PATCH 0703/2711] iio: adc: ad7124: add clock output support Add support for the AD7124's internal clock output. If the #clock-cells property is present, turn on the internal clock output during probe. If both the clocks and #clock-names properties are present (not allowed by devicetree bindings), assume that an external clock is being used so that we don't accidentally have two outputs fighting each other. Signed-off-by: David Lechner Link: https://patch.msgid.link/20250828-iio-adc-ad7124-proper-clock-support-v3-4-0b317b4605e5@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 1a9a8d6f1943..d5bb0faf9111 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -6,7 +6,9 @@ */ #include #include +#include #include +#include #include #include #include @@ -18,6 +20,7 @@ #include #include #include +#include #include #include @@ -1189,6 +1192,36 @@ static int ad7124_setup(struct ad7124_state *st) clk_sel = AD7124_ADC_CONTROL_CLK_SEL_INT; st->clk_hz = AD7124_INT_CLK_HZ; + } else if (!device_property_present(dev, "clocks") && + device_property_present(dev, "#clock-cells")) { +#ifdef CONFIG_COMMON_CLK + struct clk_hw *clk_hw; + + const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%pfwP-clk", + dev_fwnode(dev)); + if (!name) + return -ENOMEM; + + clk_hw = devm_clk_hw_register_fixed_rate(dev, name, NULL, 0, + AD7124_INT_CLK_HZ); + if (IS_ERR(clk_hw)) + return dev_err_probe(dev, PTR_ERR(clk_hw), + "Failed to register clock provider\n"); + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + clk_hw); + if (ret) + return dev_err_probe(dev, ret, + "Failed to add clock provider\n"); +#endif + + /* + * Treat the clock as always on. This way we don't have to deal + * with someone trying to enable/disable the clock while we are + * reading samples. + */ + clk_sel = AD7124_ADC_CONTROL_CLK_SEL_INT_OUT; + st->clk_hz = AD7124_INT_CLK_HZ; } else { struct clk *clk; From 7c873e3f04fd3e245890ddfde261f83d6aaa9ddb Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 28 Aug 2025 17:06:17 +0300 Subject: [PATCH 0704/2711] iio: dac: Remove redundant pm_runtime_mark_last_busy() calls pm_runtime_put_autosuspend(), pm_runtime_put_sync_autosuspend(), pm_runtime_autosuspend() and pm_request_autosuspend() now include a call to pm_runtime_mark_last_busy(). Remove the now-redundant explicit call to pm_runtime_mark_last_busy(). Also clean up error handling in stm32_dac_set_enable_state(). Signed-off-by: Sakari Ailus Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250828140617.3193288-1-sakari.ailus@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/stm32-dac.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index 344388338d9b..b860e18d52a1 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -82,9 +82,11 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch, ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en); mutex_unlock(&dac->lock); - if (ret < 0) { + if (ret) { dev_err(&indio_dev->dev, "%s failed\n", str_enable_disable(en)); - goto err_put_pm; + if (enable) + pm_runtime_put_autosuspend(dev); + return ret; } /* @@ -95,20 +97,10 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch, if (en && dac->common->hfsel) udelay(1); - if (!enable) { - pm_runtime_mark_last_busy(dev); + if (!enable) pm_runtime_put_autosuspend(dev); - } return 0; - -err_put_pm: - if (enable) { - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - } - - return ret; } static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val) @@ -349,7 +341,6 @@ static int stm32_dac_probe(struct platform_device *pdev) if (ret) goto err_pm_put; - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; From 19b50ab02eddbbd87ec2f0ad4a5bc93ac1c9b82d Mon Sep 17 00:00:00 2001 From: Denzeel Oliva Date: Sat, 30 Aug 2025 16:28:38 +0000 Subject: [PATCH 0705/2711] clk: samsung: exynos990: Use PLL_CON0 for PLL parent muxes Parent select bits for shared PLLs are in PLL_CON0, not PLL_CON3. Using the wrong register leads to incorrect parent selection and rates. Fixes: bdd03ebf721f ("clk: samsung: Introduce Exynos990 clock controller driver") Signed-off-by: Denzeel Oliva Cc: Link: https://lore.kernel.org/r/20250830-fix-cmu-top-v5-1-7c62f608309e@gmail.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-exynos990.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos990.c b/drivers/clk/samsung/clk-exynos990.c index 8d3f193d2b4d..12e98bf5005a 100644 --- a/drivers/clk/samsung/clk-exynos990.c +++ b/drivers/clk/samsung/clk-exynos990.c @@ -239,12 +239,19 @@ static const unsigned long top_clk_regs[] __initconst = { PLL_LOCKTIME_PLL_SHARED2, PLL_LOCKTIME_PLL_SHARED3, PLL_LOCKTIME_PLL_SHARED4, + PLL_CON0_PLL_G3D, PLL_CON3_PLL_G3D, + PLL_CON0_PLL_MMC, PLL_CON3_PLL_MMC, + PLL_CON0_PLL_SHARED0, PLL_CON3_PLL_SHARED0, + PLL_CON0_PLL_SHARED1, PLL_CON3_PLL_SHARED1, + PLL_CON0_PLL_SHARED2, PLL_CON3_PLL_SHARED2, + PLL_CON0_PLL_SHARED3, PLL_CON3_PLL_SHARED3, + PLL_CON0_PLL_SHARED4, PLL_CON3_PLL_SHARED4, CLK_CON_MUX_MUX_CLKCMU_APM_BUS, CLK_CON_MUX_MUX_CLKCMU_AUD_CPU, @@ -689,13 +696,13 @@ PNAME(mout_cmu_vra_bus_p) = { "dout_cmu_shared0_div3", static const struct samsung_mux_clock top_mux_clks[] __initconst = { MUX(CLK_MOUT_PLL_SHARED0, "mout_pll_shared0", mout_pll_shared0_p, - PLL_CON3_PLL_SHARED0, 4, 1), + PLL_CON0_PLL_SHARED0, 4, 1), MUX(CLK_MOUT_PLL_SHARED1, "mout_pll_shared1", mout_pll_shared1_p, - PLL_CON3_PLL_SHARED1, 4, 1), + PLL_CON0_PLL_SHARED1, 4, 1), MUX(CLK_MOUT_PLL_SHARED2, "mout_pll_shared2", mout_pll_shared2_p, - PLL_CON3_PLL_SHARED2, 4, 1), + PLL_CON0_PLL_SHARED2, 4, 1), MUX(CLK_MOUT_PLL_SHARED3, "mout_pll_shared3", mout_pll_shared3_p, - PLL_CON3_PLL_SHARED3, 4, 1), + PLL_CON0_PLL_SHARED3, 4, 1), MUX(CLK_MOUT_PLL_SHARED4, "mout_pll_shared4", mout_pll_shared4_p, PLL_CON0_PLL_SHARED4, 4, 1), MUX(CLK_MOUT_PLL_MMC, "mout_pll_mmc", mout_pll_mmc_p, From ce2eb09b430ddf9d7c9d685bdd81de011bccd4ad Mon Sep 17 00:00:00 2001 From: Denzeel Oliva Date: Sat, 30 Aug 2025 16:28:39 +0000 Subject: [PATCH 0706/2711] clk: samsung: exynos990: Fix CMU_TOP mux/div bit widths Correct several mux/div widths (DSP_BUS, G2D_MSCL, HSI0 USBDP_DEBUG, HSI1 UFS_EMBD, APM_BUS, CPUCL0_DBG_BUS, DPU) to match hardware. Fixes: bdd03ebf721f ("clk: samsung: Introduce Exynos990 clock controller driver") Signed-off-by: Denzeel Oliva Cc: Link: https://lore.kernel.org/r/20250830-fix-cmu-top-v5-2-7c62f608309e@gmail.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-exynos990.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos990.c b/drivers/clk/samsung/clk-exynos990.c index 12e98bf5005a..385f1d972667 100644 --- a/drivers/clk/samsung/clk-exynos990.c +++ b/drivers/clk/samsung/clk-exynos990.c @@ -766,11 +766,11 @@ static const struct samsung_mux_clock top_mux_clks[] __initconst = { MUX(CLK_MOUT_CMU_DPU_ALT, "mout_cmu_dpu_alt", mout_cmu_dpu_alt_p, CLK_CON_MUX_MUX_CLKCMU_DPU_ALT, 0, 2), MUX(CLK_MOUT_CMU_DSP_BUS, "mout_cmu_dsp_bus", - mout_cmu_dsp_bus_p, CLK_CON_MUX_MUX_CLKCMU_DSP_BUS, 0, 2), + mout_cmu_dsp_bus_p, CLK_CON_MUX_MUX_CLKCMU_DSP_BUS, 0, 3), MUX(CLK_MOUT_CMU_G2D_G2D, "mout_cmu_g2d_g2d", mout_cmu_g2d_g2d_p, CLK_CON_MUX_MUX_CLKCMU_G2D_G2D, 0, 2), MUX(CLK_MOUT_CMU_G2D_MSCL, "mout_cmu_g2d_mscl", - mout_cmu_g2d_mscl_p, CLK_CON_MUX_MUX_CLKCMU_G2D_MSCL, 0, 1), + mout_cmu_g2d_mscl_p, CLK_CON_MUX_MUX_CLKCMU_G2D_MSCL, 0, 2), MUX(CLK_MOUT_CMU_HPM, "mout_cmu_hpm", mout_cmu_hpm_p, CLK_CON_MUX_MUX_CLKCMU_HPM, 0, 2), MUX(CLK_MOUT_CMU_HSI0_BUS, "mout_cmu_hsi0_bus", @@ -782,7 +782,7 @@ static const struct samsung_mux_clock top_mux_clks[] __initconst = { 0, 2), MUX(CLK_MOUT_CMU_HSI0_USBDP_DEBUG, "mout_cmu_hsi0_usbdp_debug", mout_cmu_hsi0_usbdp_debug_p, - CLK_CON_MUX_MUX_CLKCMU_HSI0_USBDP_DEBUG, 0, 2), + CLK_CON_MUX_MUX_CLKCMU_HSI0_USBDP_DEBUG, 0, 1), MUX(CLK_MOUT_CMU_HSI1_BUS, "mout_cmu_hsi1_bus", mout_cmu_hsi1_bus_p, CLK_CON_MUX_MUX_CLKCMU_HSI1_BUS, 0, 3), MUX(CLK_MOUT_CMU_HSI1_MMC_CARD, "mout_cmu_hsi1_mmc_card", @@ -795,7 +795,7 @@ static const struct samsung_mux_clock top_mux_clks[] __initconst = { 0, 2), MUX(CLK_MOUT_CMU_HSI1_UFS_EMBD, "mout_cmu_hsi1_ufs_embd", mout_cmu_hsi1_ufs_embd_p, CLK_CON_MUX_MUX_CLKCMU_HSI1_UFS_EMBD, - 0, 1), + 0, 2), MUX(CLK_MOUT_CMU_HSI2_BUS, "mout_cmu_hsi2_bus", mout_cmu_hsi2_bus_p, CLK_CON_MUX_MUX_CLKCMU_HSI2_BUS, 0, 1), MUX(CLK_MOUT_CMU_HSI2_PCIE, "mout_cmu_hsi2_pcie", @@ -869,7 +869,7 @@ static const struct samsung_div_clock top_div_clks[] __initconst = { CLK_CON_DIV_PLL_SHARED4_DIV4, 0, 1), DIV(CLK_DOUT_CMU_APM_BUS, "dout_cmu_apm_bus", "gout_cmu_apm_bus", - CLK_CON_DIV_CLKCMU_APM_BUS, 0, 3), + CLK_CON_DIV_CLKCMU_APM_BUS, 0, 2), DIV(CLK_DOUT_CMU_AUD_CPU, "dout_cmu_aud_cpu", "gout_cmu_aud_cpu", CLK_CON_DIV_CLKCMU_AUD_CPU, 0, 3), DIV(CLK_DOUT_CMU_BUS0_BUS, "dout_cmu_bus0_bus", "gout_cmu_bus0_bus", @@ -894,9 +894,9 @@ static const struct samsung_div_clock top_div_clks[] __initconst = { CLK_CON_DIV_CLKCMU_CMU_BOOST, 0, 2), DIV(CLK_DOUT_CMU_CORE_BUS, "dout_cmu_core_bus", "gout_cmu_core_bus", CLK_CON_DIV_CLKCMU_CORE_BUS, 0, 4), - DIV(CLK_DOUT_CMU_CPUCL0_DBG_BUS, "dout_cmu_cpucl0_debug", + DIV(CLK_DOUT_CMU_CPUCL0_DBG_BUS, "dout_cmu_cpucl0_dbg_bus", "gout_cmu_cpucl0_dbg_bus", CLK_CON_DIV_CLKCMU_CPUCL0_DBG_BUS, - 0, 3), + 0, 4), DIV(CLK_DOUT_CMU_CPUCL0_SWITCH, "dout_cmu_cpucl0_switch", "gout_cmu_cpucl0_switch", CLK_CON_DIV_CLKCMU_CPUCL0_SWITCH, 0, 3), DIV(CLK_DOUT_CMU_CPUCL1_SWITCH, "dout_cmu_cpucl1_switch", @@ -986,8 +986,8 @@ static const struct samsung_div_clock top_div_clks[] __initconst = { CLK_CON_DIV_CLKCMU_TNR_BUS, 0, 4), DIV(CLK_DOUT_CMU_VRA_BUS, "dout_cmu_vra_bus", "gout_cmu_vra_bus", CLK_CON_DIV_CLKCMU_VRA_BUS, 0, 4), - DIV(CLK_DOUT_CMU_DPU, "dout_cmu_clkcmu_dpu", "gout_cmu_dpu", - CLK_CON_DIV_DIV_CLKCMU_DPU, 0, 4), + DIV(CLK_DOUT_CMU_DPU, "dout_cmu_dpu", "gout_cmu_dpu", + CLK_CON_DIV_DIV_CLKCMU_DPU, 0, 3), }; static const struct samsung_gate_clock top_gate_clks[] __initconst = { From a66dabcd2cb8389fd73cab8896fd727fa2ea8d8b Mon Sep 17 00:00:00 2001 From: Denzeel Oliva Date: Sat, 30 Aug 2025 16:28:40 +0000 Subject: [PATCH 0707/2711] clk: samsung: exynos990: Replace bogus divs with fixed-factor clocks HSI1/2 PCIe and HSI0 USBDP debug outputs are fixed divide-by-8. OTP also uses 1/8 from oscclk. Replace incorrect div clocks with fixed-factor clocks to reflect hardware. Fixes: bdd03ebf721f ("clk: samsung: Introduce Exynos990 clock controller driver") Signed-off-by: Denzeel Oliva Cc: Link: https://lore.kernel.org/r/20250830-fix-cmu-top-v5-3-7c62f608309e@gmail.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-exynos990.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos990.c b/drivers/clk/samsung/clk-exynos990.c index 385f1d972667..8571c225d090 100644 --- a/drivers/clk/samsung/clk-exynos990.c +++ b/drivers/clk/samsung/clk-exynos990.c @@ -931,16 +931,11 @@ static const struct samsung_div_clock top_div_clks[] __initconst = { CLK_CON_DIV_CLKCMU_HSI0_DPGTC, 0, 3), DIV(CLK_DOUT_CMU_HSI0_USB31DRD, "dout_cmu_hsi0_usb31drd", "gout_cmu_hsi0_usb31drd", CLK_CON_DIV_CLKCMU_HSI0_USB31DRD, 0, 4), - DIV(CLK_DOUT_CMU_HSI0_USBDP_DEBUG, "dout_cmu_hsi0_usbdp_debug", - "gout_cmu_hsi0_usbdp_debug", CLK_CON_DIV_CLKCMU_HSI0_USBDP_DEBUG, - 0, 4), DIV(CLK_DOUT_CMU_HSI1_BUS, "dout_cmu_hsi1_bus", "gout_cmu_hsi1_bus", CLK_CON_DIV_CLKCMU_HSI1_BUS, 0, 3), DIV(CLK_DOUT_CMU_HSI1_MMC_CARD, "dout_cmu_hsi1_mmc_card", "gout_cmu_hsi1_mmc_card", CLK_CON_DIV_CLKCMU_HSI1_MMC_CARD, 0, 9), - DIV(CLK_DOUT_CMU_HSI1_PCIE, "dout_cmu_hsi1_pcie", "gout_cmu_hsi1_pcie", - CLK_CON_DIV_CLKCMU_HSI1_PCIE, 0, 7), DIV(CLK_DOUT_CMU_HSI1_UFS_CARD, "dout_cmu_hsi1_ufs_card", "gout_cmu_hsi1_ufs_card", CLK_CON_DIV_CLKCMU_HSI1_UFS_CARD, 0, 3), @@ -949,8 +944,6 @@ static const struct samsung_div_clock top_div_clks[] __initconst = { 0, 3), DIV(CLK_DOUT_CMU_HSI2_BUS, "dout_cmu_hsi2_bus", "gout_cmu_hsi2_bus", CLK_CON_DIV_CLKCMU_HSI2_BUS, 0, 4), - DIV(CLK_DOUT_CMU_HSI2_PCIE, "dout_cmu_hsi2_pcie", "gout_cmu_hsi2_pcie", - CLK_CON_DIV_CLKCMU_HSI2_PCIE, 0, 7), DIV(CLK_DOUT_CMU_IPP_BUS, "dout_cmu_ipp_bus", "gout_cmu_ipp_bus", CLK_CON_DIV_CLKCMU_IPP_BUS, 0, 4), DIV(CLK_DOUT_CMU_ITP_BUS, "dout_cmu_itp_bus", "gout_cmu_itp_bus", @@ -990,6 +983,16 @@ static const struct samsung_div_clock top_div_clks[] __initconst = { CLK_CON_DIV_DIV_CLKCMU_DPU, 0, 3), }; +static const struct samsung_fixed_factor_clock cmu_top_ffactor[] __initconst = { + FFACTOR(CLK_DOUT_CMU_HSI1_PCIE, "dout_cmu_hsi1_pcie", + "gout_cmu_hsi1_pcie", 1, 8, 0), + FFACTOR(CLK_DOUT_CMU_OTP, "dout_cmu_otp", "oscclk", 1, 8, 0), + FFACTOR(CLK_DOUT_CMU_HSI0_USBDP_DEBUG, "dout_cmu_hsi0_usbdp_debug", + "gout_cmu_hsi0_usbdp_debug", 1, 8, 0), + FFACTOR(CLK_DOUT_CMU_HSI2_PCIE, "dout_cmu_hsi2_pcie", + "gout_cmu_hsi2_pcie", 1, 8, 0), +}; + static const struct samsung_gate_clock top_gate_clks[] __initconst = { GATE(CLK_GOUT_CMU_APM_BUS, "gout_cmu_apm_bus", "mout_cmu_apm_bus", CLK_CON_GAT_GATE_CLKCMU_APM_BUS, 21, CLK_IGNORE_UNUSED, 0), @@ -1133,6 +1136,8 @@ static const struct samsung_cmu_info top_cmu_info __initconst = { .nr_mux_clks = ARRAY_SIZE(top_mux_clks), .div_clks = top_div_clks, .nr_div_clks = ARRAY_SIZE(top_div_clks), + .fixed_factor_clks = cmu_top_ffactor, + .nr_fixed_factor_clks = ARRAY_SIZE(cmu_top_ffactor), .gate_clks = top_gate_clks, .nr_gate_clks = ARRAY_SIZE(top_gate_clks), .nr_clk_ids = CLKS_NR_TOP, From 76f1e2ee545b3165e1e24293b59414699118266a Mon Sep 17 00:00:00 2001 From: Denzeel Oliva Date: Sat, 30 Aug 2025 16:28:41 +0000 Subject: [PATCH 0708/2711] dt-bindings: clock: exynos990: Extend clocks IDs Add missing clock definitions for DPU and CMUREF. Acked-by: Rob Herring (Arm) Signed-off-by: Denzeel Oliva Link: https://lore.kernel.org/r/20250830-fix-cmu-top-v5-4-7c62f608309e@gmail.com Signed-off-by: Krzysztof Kozlowski --- include/dt-bindings/clock/samsung,exynos990.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/dt-bindings/clock/samsung,exynos990.h b/include/dt-bindings/clock/samsung,exynos990.h index 6b9df09d2822..c5c79e078f2f 100644 --- a/include/dt-bindings/clock/samsung,exynos990.h +++ b/include/dt-bindings/clock/samsung,exynos990.h @@ -208,6 +208,10 @@ #define CLK_GOUT_CMU_SSP_BUS 197 #define CLK_GOUT_CMU_TNR_BUS 198 #define CLK_GOUT_CMU_VRA_BUS 199 +#define CLK_MOUT_CMU_CMUREF 200 +#define CLK_MOUT_CMU_DPU_BUS 201 +#define CLK_MOUT_CMU_CLK_CMUREF 202 +#define CLK_DOUT_CMU_CLK_CMUREF 203 /* CMU_HSI0 */ #define CLK_MOUT_HSI0_BUS_USER 1 From 8c82bb53669b1e82435b5a00a170b7c079940b82 Mon Sep 17 00:00:00 2001 From: Denzeel Oliva Date: Sat, 30 Aug 2025 16:28:42 +0000 Subject: [PATCH 0709/2711] clk: samsung: exynos990: Add DPU_BUS and CMUREF mux/div and update CLKS_NR_TOP Add DPU_BUS and CMUREF mux/div, wire their registers and parents, and update CLKS_NR_TOP. These use the new IDs appended to the bindings to avoid ABI changes. Signed-off-by: Denzeel Oliva Link: https://lore.kernel.org/r/20250830-fix-cmu-top-v5-5-7c62f608309e@gmail.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-exynos990.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-exynos990.c b/drivers/clk/samsung/clk-exynos990.c index 8571c225d090..91736b15c4b4 100644 --- a/drivers/clk/samsung/clk-exynos990.c +++ b/drivers/clk/samsung/clk-exynos990.c @@ -17,7 +17,7 @@ #include "clk-pll.h" /* NOTE: Must be equal to the last clock ID increased by one */ -#define CLKS_NR_TOP (CLK_GOUT_CMU_VRA_BUS + 1) +#define CLKS_NR_TOP (CLK_DOUT_CMU_CLK_CMUREF + 1) #define CLKS_NR_HSI0 (CLK_GOUT_HSI0_XIU_D_HSI0_ACLK + 1) #define CLKS_NR_PERIS (CLK_GOUT_PERIS_OTP_CON_TOP_OSCCLK + 1) @@ -45,6 +45,7 @@ #define PLL_CON3_PLL_SHARED3 0x024c #define PLL_CON0_PLL_SHARED4 0x0280 #define PLL_CON3_PLL_SHARED4 0x028c +#define CLK_CON_MUX_CLKCMU_DPU_BUS 0x1000 #define CLK_CON_MUX_MUX_CLKCMU_APM_BUS 0x1004 #define CLK_CON_MUX_MUX_CLKCMU_AUD_CPU 0x1008 #define CLK_CON_MUX_MUX_CLKCMU_BUS0_BUS 0x100c @@ -103,6 +104,8 @@ #define CLK_CON_MUX_MUX_CLKCMU_SSP_BUS 0x10e0 #define CLK_CON_MUX_MUX_CLKCMU_TNR_BUS 0x10e4 #define CLK_CON_MUX_MUX_CLKCMU_VRA_BUS 0x10e8 +#define CLK_CON_MUX_MUX_CLK_CMU_CMUREF 0x10f0 +#define CLK_CON_MUX_MUX_CMU_CMUREF 0x10f4 #define CLK_CON_DIV_CLKCMU_APM_BUS 0x1800 #define CLK_CON_DIV_CLKCMU_AUD_CPU 0x1804 #define CLK_CON_DIV_CLKCMU_BUS0_BUS 0x1808 @@ -162,6 +165,7 @@ #define CLK_CON_DIV_CLKCMU_VRA_BUS 0x18e0 #define CLK_CON_DIV_DIV_CLKCMU_DPU 0x18e8 #define CLK_CON_DIV_DIV_CLKCMU_DPU_ALT 0x18ec +#define CLK_CON_DIV_DIV_CLK_CMU_CMUREF 0x18f0 #define CLK_CON_DIV_PLL_SHARED0_DIV2 0x18f4 #define CLK_CON_DIV_PLL_SHARED0_DIV3 0x18f8 #define CLK_CON_DIV_PLL_SHARED0_DIV4 0x18fc @@ -253,6 +257,7 @@ static const unsigned long top_clk_regs[] __initconst = { PLL_CON3_PLL_SHARED3, PLL_CON0_PLL_SHARED4, PLL_CON3_PLL_SHARED4, + CLK_CON_MUX_CLKCMU_DPU_BUS, CLK_CON_MUX_MUX_CLKCMU_APM_BUS, CLK_CON_MUX_MUX_CLKCMU_AUD_CPU, CLK_CON_MUX_MUX_CLKCMU_BUS0_BUS, @@ -311,6 +316,8 @@ static const unsigned long top_clk_regs[] __initconst = { CLK_CON_MUX_MUX_CLKCMU_SSP_BUS, CLK_CON_MUX_MUX_CLKCMU_TNR_BUS, CLK_CON_MUX_MUX_CLKCMU_VRA_BUS, + CLK_CON_MUX_MUX_CLK_CMU_CMUREF, + CLK_CON_MUX_MUX_CMU_CMUREF, CLK_CON_DIV_CLKCMU_APM_BUS, CLK_CON_DIV_CLKCMU_AUD_CPU, CLK_CON_DIV_CLKCMU_BUS0_BUS, @@ -370,6 +377,7 @@ static const unsigned long top_clk_regs[] __initconst = { CLK_CON_DIV_CLKCMU_VRA_BUS, CLK_CON_DIV_DIV_CLKCMU_DPU, CLK_CON_DIV_DIV_CLKCMU_DPU_ALT, + CLK_CON_DIV_DIV_CLK_CMU_CMUREF, CLK_CON_DIV_PLL_SHARED0_DIV2, CLK_CON_DIV_PLL_SHARED0_DIV3, CLK_CON_DIV_PLL_SHARED0_DIV4, @@ -465,6 +473,8 @@ PNAME(mout_pll_shared3_p) = { "oscclk", "fout_shared3_pll" }; PNAME(mout_pll_shared4_p) = { "oscclk", "fout_shared4_pll" }; PNAME(mout_pll_mmc_p) = { "oscclk", "fout_mmc_pll" }; PNAME(mout_pll_g3d_p) = { "oscclk", "fout_g3d_pll" }; +PNAME(mout_cmu_dpu_bus_p) = { "dout_cmu_dpu", + "dout_cmu_dpu_alt" }; PNAME(mout_cmu_apm_bus_p) = { "dout_cmu_shared0_div2", "dout_cmu_shared2_div2" }; PNAME(mout_cmu_aud_cpu_p) = { "dout_cmu_shared0_div2", @@ -679,6 +689,12 @@ PNAME(mout_cmu_vra_bus_p) = { "dout_cmu_shared0_div3", "dout_cmu_shared4_div2", "dout_cmu_shared0_div4", "dout_cmu_shared4_div3" }; +PNAME(mout_cmu_cmuref_p) = { "oscclk", + "dout_cmu_clk_cmuref" }; +PNAME(mout_cmu_clk_cmuref_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "oscclk" }; /* * Register name to clock name mangling strategy used in this file @@ -709,6 +725,8 @@ static const struct samsung_mux_clock top_mux_clks[] __initconst = { PLL_CON0_PLL_MMC, 4, 1), MUX(CLK_MOUT_PLL_G3D, "mout_pll_g3d", mout_pll_g3d_p, PLL_CON0_PLL_G3D, 4, 1), + MUX(CLK_MOUT_CMU_DPU_BUS, "mout_cmu_dpu_bus", + mout_cmu_dpu_bus_p, CLK_CON_MUX_CLKCMU_DPU_BUS, 0, 1), MUX(CLK_MOUT_CMU_APM_BUS, "mout_cmu_apm_bus", mout_cmu_apm_bus_p, CLK_CON_MUX_MUX_CLKCMU_APM_BUS, 0, 1), MUX(CLK_MOUT_CMU_AUD_CPU, "mout_cmu_aud_cpu", @@ -837,6 +855,10 @@ static const struct samsung_mux_clock top_mux_clks[] __initconst = { mout_cmu_tnr_bus_p, CLK_CON_MUX_MUX_CLKCMU_TNR_BUS, 0, 3), MUX(CLK_MOUT_CMU_VRA_BUS, "mout_cmu_vra_bus", mout_cmu_vra_bus_p, CLK_CON_MUX_MUX_CLKCMU_VRA_BUS, 0, 2), + MUX(CLK_MOUT_CMU_CMUREF, "mout_cmu_cmuref", + mout_cmu_cmuref_p, CLK_CON_MUX_MUX_CMU_CMUREF, 0, 1), + MUX(CLK_MOUT_CMU_CLK_CMUREF, "mout_cmu_clk_cmuref", + mout_cmu_clk_cmuref_p, CLK_CON_MUX_MUX_CLK_CMU_CMUREF, 0, 2), }; static const struct samsung_div_clock top_div_clks[] __initconst = { @@ -981,6 +1003,10 @@ static const struct samsung_div_clock top_div_clks[] __initconst = { CLK_CON_DIV_CLKCMU_VRA_BUS, 0, 4), DIV(CLK_DOUT_CMU_DPU, "dout_cmu_dpu", "gout_cmu_dpu", CLK_CON_DIV_DIV_CLKCMU_DPU, 0, 3), + DIV(CLK_DOUT_CMU_DPU_ALT, "dout_cmu_dpu_alt", "gout_cmu_dpu_bus", + CLK_CON_DIV_DIV_CLKCMU_DPU_ALT, 0, 4), + DIV(CLK_DOUT_CMU_CLK_CMUREF, "dout_cmu_clk_cmuref", "mout_cmu_clk_cmuref", + CLK_CON_DIV_DIV_CLK_CMU_CMUREF, 0, 2), }; static const struct samsung_fixed_factor_clock cmu_top_ffactor[] __initconst = { From 25fb0ea986dc10e05f3f4b43cabde4d1853a1fd7 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 21 Aug 2025 12:02:21 +0200 Subject: [PATCH 0710/2711] w1: matrox: Remove some deadcode in matrox_w1_remove() The .remove function can only be called if the .probe() succeeds. So there is no need to keep track of a successful probe in 'found'. Simplify code accordingly. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/458641ad2d7a7adf30a03e70038304f0e6a81ff4.1755770484.git.christophe.jaillet@wanadoo.fr Signed-off-by: Krzysztof Kozlowski --- drivers/w1/masters/matrox_w1.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index 2852cd2dc67c..146fa7c6e74e 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c @@ -47,7 +47,6 @@ struct matrox_device { unsigned long phys_addr; void __iomem *virt_addr; - unsigned long found; struct w1_bus_master *bus_master; }; @@ -158,8 +157,6 @@ static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent pci_set_drvdata(pdev, dev); - dev->found = 1; - dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n"); return 0; @@ -176,10 +173,9 @@ static void matrox_w1_remove(struct pci_dev *pdev) { struct matrox_device *dev = pci_get_drvdata(pdev); - if (dev->found) { - w1_remove_master_device(dev->bus_master); - iounmap(dev->virt_addr); - } + w1_remove_master_device(dev->bus_master); + iounmap(dev->virt_addr); + kfree(dev); } From d54d99d034093fd3a357593d9757584868537748 Mon Sep 17 00:00:00 2001 From: Ioana Risteiu Date: Tue, 26 Aug 2025 01:13:49 +0300 Subject: [PATCH 0711/2711] iio: adc: adi-axi-adc: add axi_adc_num_lanes_set Assign num_lanes_set in the adi_axi_adc_ops to axi_adc_num_lanes_set() to support setting number of lanes used by AXI ADC. This operation is included in the generic structure because the number of lanes is a configurable parameter of the generic AXI ADC IP core, not specific to a device. Reviewed-by: Andy Shevchenko Signed-off-by: Ioana Risteiu Link: https://patch.msgid.link/20250825221355.6214-2-Ioana.Risteiu@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/adi-axi-adc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index eb42e29960e4..14fa4238c2b9 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -618,6 +618,7 @@ static const struct iio_backend_ops adi_axi_adc_ops = { .chan_status = axi_adc_chan_status, .interface_type_get = axi_adc_interface_type_get, .oversampling_ratio_set = axi_adc_oversampling_ratio_set, + .num_lanes_set = axi_adc_num_lanes_set, .debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access), .debugfs_print_chan_status = iio_backend_debugfs_ptr(axi_adc_debugfs_print_chan_status), }; From a9ee71011a5347dd77887e2c5c2f87f01acd3efb Mon Sep 17 00:00:00 2001 From: Ioana Risteiu Date: Tue, 26 Aug 2025 01:13:50 +0300 Subject: [PATCH 0712/2711] dt-bindings: iio: adc: add IIO backend support Add the generic io-backends property to the AD7779 binding to enable support for the IIO backend framework. Also add the adi,num-lanes property to set the number of lanes used by AD7779. Reviewed-by: Rob Herring (Arm) Reviewed-by: Krzysztof Kozlowski Signed-off-by: Ioana Risteiu Link: https://patch.msgid.link/20250825221355.6214-3-Ioana.Risteiu@analog.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7779.yaml | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml index 044f92f39cfa..ba3f7b2bd6cf 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml @@ -80,11 +80,36 @@ properties: reset-gpios: maxItems: 1 + io-backends: + maxItems: 1 + + adi,num-lanes: + description: + Number of lanes on which the data is sent on the output when the data + output interface is used. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 4] + default: 4 + required: - compatible - reg - clocks - - interrupts + +allOf: + - if: + not: + required: + - io-backends + then: + properties: + adi,num-lanes: false + +oneOf: + - required: + - interrupts + - required: + - io-backends unevaluatedProperties: false @@ -107,4 +132,21 @@ examples: clocks = <&adc_clk>; }; }; + + - | + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad7779"; + reg = <0>; + start-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio0 93 GPIO_ACTIVE_LOW>; + clocks = <&adc_clk>; + io-backends = <&iio_backend>; + adi,num-lanes = <4>; + }; + }; ... From 2ca33c502b630a748f91a59b5ebb5cda6d9fc8b9 Mon Sep 17 00:00:00 2001 From: Ioana Risteiu Date: Tue, 26 Aug 2025 01:13:51 +0300 Subject: [PATCH 0713/2711] iio: adc: extract setup function without backend Refactor probe function by moving the initialization specific to communication without iio-backend into a separate setup function. The purpose of this modification is better code organization. No functional changes intended. Reviewed-by: Andy Shevchenko Signed-off-by: Ioana Risteiu Link: https://patch.msgid.link/20250825221355.6214-4-Ioana.Risteiu@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7779.c | 86 +++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c index 845adc510239..4e6fa6370593 100644 --- a/drivers/iio/adc/ad7779.c +++ b/drivers/iio/adc/ad7779.c @@ -752,6 +752,51 @@ static int ad7779_conf(struct ad7779_state *st, struct gpio_desc *start_gpio) return 0; } +static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev *indio_dev) +{ + int ret; + struct device *dev = &st->spi->dev; + + indio_dev->info = &ad7779_info; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = ARRAY_SIZE(ad7779_channels); + + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad7779_trigger_ops; + + iio_trigger_set_drvdata(st->trig, st); + + ret = devm_request_irq(dev, st->spi->irq, iio_trigger_generic_data_rdy_poll, + IRQF_ONESHOT | IRQF_NO_AUTOEN, indio_dev->name, + st->trig); + if (ret) + return dev_err_probe(dev, ret, "request IRQ %d failed\n", + st->spi->irq); + + ret = devm_iio_trigger_register(dev, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + init_completion(&st->completion); + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + &ad7779_trigger_handler, + &ad7779_buffer_setup_ops); + if (ret) + return ret; + + return ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT, + AD7779_DCLK_CLK_DIV_MSK, + FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 7)); +} + static int ad7779_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -760,9 +805,6 @@ static int ad7779_probe(struct spi_device *spi) struct device *dev = &spi->dev; int ret = -EINVAL; - if (!spi->irq) - return dev_err_probe(dev, ret, "DRDY irq not present\n"); - indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -804,45 +846,9 @@ static int ad7779_probe(struct spi_device *spi) return ret; indio_dev->name = st->chip_info->name; - indio_dev->info = &ad7779_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = st->chip_info->channels; - indio_dev->num_channels = ARRAY_SIZE(ad7779_channels); - st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, - iio_device_id(indio_dev)); - if (!st->trig) - return -ENOMEM; - - st->trig->ops = &ad7779_trigger_ops; - - iio_trigger_set_drvdata(st->trig, st); - - ret = devm_request_irq(dev, spi->irq, iio_trigger_generic_data_rdy_poll, - IRQF_ONESHOT | IRQF_NO_AUTOEN, indio_dev->name, - st->trig); - if (ret) - return dev_err_probe(dev, ret, "request IRQ %d failed\n", - st->spi->irq); - - ret = devm_iio_trigger_register(dev, st->trig); - if (ret) - return ret; - - indio_dev->trig = iio_trigger_get(st->trig); - - init_completion(&st->completion); - - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, - &iio_pollfunc_store_time, - &ad7779_trigger_handler, - &ad7779_buffer_setup_ops); - if (ret) - return ret; - - ret = ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT, - AD7779_DCLK_CLK_DIV_MSK, - FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 7)); + ret = ad7779_setup_without_backend(st, indio_dev); if (ret) return ret; From 80770fccb7f60b0bc795852c154273e511f296a0 Mon Sep 17 00:00:00 2001 From: Hakyeong Kim Date: Mon, 25 Aug 2025 17:14:28 +0530 Subject: [PATCH 0714/2711] clk: samsung: Add clock PLL support for ARTPEC-8 SoC Add below clock PLL support for Axis ARTPEC-8 SoC platform: - pll_1017x: Integer PLL with mid frequency FVCO (950 to 2400 MHz) This is used in ARTPEC-8 SoC for shared PLL - pll_1031x: Integer/Fractional PLL with mid frequency FVCO (600 to 1200 MHz) This is used in ARTPEC-8 SoC for Audio PLL FOUT calculation for pll_1017x and pll_1031x: FOUT = (MDIV x FIN)/(PDIV x 2^SDIV) for integer PLL FOUT = (((MDIV + KDIV)/65536) x FIN)/(PDIV x 2^SDIV) for fractional PLL Signed-off-by: Hakyeong Kim Signed-off-by: SeonGu Kang Signed-off-by: Ravi Patel Link: https://lore.kernel.org/r/20250825114436.46882-3-ravi.patel@samsung.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-pll.c | 128 +++++++++++++++++++++++++++++++++- drivers/clk/samsung/clk-pll.h | 2 + 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 3c04a0388ff9..7bea7be1d7e4 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -278,7 +278,7 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, } /* Set PLL lock time. */ - if (pll->type == pll_142xx) + if (pll->type == pll_142xx || pll->type == pll_1017x) writel_relaxed(rate->pdiv * PLL142XX_LOCK_FACTOR, pll->lock_reg); else @@ -1330,6 +1330,125 @@ static const struct clk_ops samsung_pll531x_clk_ops = { .recalc_rate = samsung_pll531x_recalc_rate, }; +/* + * PLL1031x Clock Type + */ +#define PLL1031X_LOCK_FACTOR (500) + +#define PLL1031X_MDIV_MASK (0x3ff) +#define PLL1031X_PDIV_MASK (0x3f) +#define PLL1031X_SDIV_MASK (0x7) +#define PLL1031X_MDIV_SHIFT (16) +#define PLL1031X_PDIV_SHIFT (8) +#define PLL1031X_SDIV_SHIFT (0) + +#define PLL1031X_KDIV_MASK (0xffff) +#define PLL1031X_KDIV_SHIFT (0) +#define PLL1031X_MFR_MASK (0x3f) +#define PLL1031X_MRR_MASK (0x1f) +#define PLL1031X_MFR_SHIFT (16) +#define PLL1031X_MRR_SHIFT (24) + +static unsigned long samsung_pll1031x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con3; + u64 fvco = parent_rate; + + pll_con0 = readl_relaxed(pll->con_reg); + pll_con3 = readl_relaxed(pll->con_reg + 0xc); + mdiv = (pll_con0 >> PLL1031X_MDIV_SHIFT) & PLL1031X_MDIV_MASK; + pdiv = (pll_con0 >> PLL1031X_PDIV_SHIFT) & PLL1031X_PDIV_MASK; + sdiv = (pll_con0 >> PLL1031X_SDIV_SHIFT) & PLL1031X_SDIV_MASK; + kdiv = (pll_con3 & PLL1031X_KDIV_MASK); + + fvco *= (mdiv << PLL1031X_MDIV_SHIFT) + kdiv; + do_div(fvco, (pdiv << sdiv)); + fvco >>= PLL1031X_MDIV_SHIFT; + + return (unsigned long)fvco; +} + +static bool samsung_pll1031x_mpk_change(u32 pll_con0, u32 pll_con3, + const struct samsung_pll_rate_table *rate) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_con0 >> PLL1031X_MDIV_SHIFT) & PLL1031X_MDIV_MASK; + old_pdiv = (pll_con0 >> PLL1031X_PDIV_SHIFT) & PLL1031X_PDIV_MASK; + old_kdiv = (pll_con3 >> PLL1031X_KDIV_SHIFT) & PLL1031X_KDIV_MASK; + + return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv || + old_kdiv != rate->kdiv); +} + +static int samsung_pll1031x_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + const struct samsung_pll_rate_table *rate; + u32 con0, con3; + + /* Get required rate settings from table */ + rate = samsung_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + + con0 = readl_relaxed(pll->con_reg); + con3 = readl_relaxed(pll->con_reg + 0xc); + + if (!(samsung_pll1031x_mpk_change(con0, con3, rate))) { + /* If only s change, change just s value only */ + con0 &= ~(PLL1031X_SDIV_MASK << PLL1031X_SDIV_SHIFT); + con0 |= rate->sdiv << PLL1031X_SDIV_SHIFT; + writel_relaxed(con0, pll->con_reg); + + return 0; + } + + /* Set PLL lock time. */ + writel_relaxed(rate->pdiv * PLL1031X_LOCK_FACTOR, pll->lock_reg); + + /* Set PLL M, P, and S values. */ + con0 &= ~((PLL1031X_MDIV_MASK << PLL1031X_MDIV_SHIFT) | + (PLL1031X_PDIV_MASK << PLL1031X_PDIV_SHIFT) | + (PLL1031X_SDIV_MASK << PLL1031X_SDIV_SHIFT)); + + con0 |= (rate->mdiv << PLL1031X_MDIV_SHIFT) | + (rate->pdiv << PLL1031X_PDIV_SHIFT) | + (rate->sdiv << PLL1031X_SDIV_SHIFT); + + /* Set PLL K, MFR and MRR values. */ + con3 = readl_relaxed(pll->con_reg + 0xc); + con3 &= ~((PLL1031X_KDIV_MASK << PLL1031X_KDIV_SHIFT) | + (PLL1031X_MFR_MASK << PLL1031X_MFR_SHIFT) | + (PLL1031X_MRR_MASK << PLL1031X_MRR_SHIFT)); + con3 |= (rate->kdiv << PLL1031X_KDIV_SHIFT) | + (rate->mfr << PLL1031X_MFR_SHIFT) | + (rate->mrr << PLL1031X_MRR_SHIFT); + + /* Write configuration to PLL */ + writel_relaxed(con0, pll->con_reg); + writel_relaxed(con3, pll->con_reg + 0xc); + + /* Wait for PLL lock if the PLL is enabled */ + return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); +} + +static const struct clk_ops samsung_pll1031x_clk_ops = { + .recalc_rate = samsung_pll1031x_recalc_rate, + .determine_rate = samsung_pll_determine_rate, + .set_rate = samsung_pll1031x_set_rate, +}; + +static const struct clk_ops samsung_pll1031x_clk_min_ops = { + .recalc_rate = samsung_pll1031x_recalc_rate, +}; + static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, const struct samsung_pll_clock *pll_clk) { @@ -1378,6 +1497,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, case pll_1451x: case pll_1452x: case pll_142xx: + case pll_1017x: pll->enable_offs = PLL35XX_ENABLE_SHIFT; pll->lock_offs = PLL35XX_LOCK_STAT_SHIFT; if (!pll->rate_table) @@ -1473,6 +1593,12 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, case pll_4311: init.ops = &samsung_pll531x_clk_ops; break; + case pll_1031x: + if (!pll->rate_table) + init.ops = &samsung_pll1031x_clk_min_ops; + else + init.ops = &samsung_pll1031x_clk_ops; + break; default: pr_warn("%s: Unknown pll type for pll clk %s\n", __func__, pll_clk->name); diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index e9a5f8e0e0a3..6c8bb7f26da5 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -49,6 +49,8 @@ enum samsung_pll_type { pll_0718x, pll_0732x, pll_4311, + pll_1017x, + pll_1031x, }; #define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \ From bd5336e3f7040f300b01702215b45e6267a400cc Mon Sep 17 00:00:00 2001 From: Hakyeong Kim Date: Mon, 25 Aug 2025 17:14:29 +0530 Subject: [PATCH 0715/2711] clk: samsung: artpec-8: Add initial clock support for ARTPEC-8 SoC Add initial clock support for Axis ARTPEC-8 SoC which is required for enabling basic clock management. Add clock support for below CMU (Clock Management Unit) blocks in ARTPEC-8 SoC: - CMU_CMU - CMU_BUS - CMU_CORE - CMU_CPUCL - CMU_FSYS - CMU_IMEM - CMU_PERI Signed-off-by: Hakyeong Kim Signed-off-by: Varada Pavani Signed-off-by: SeonGu Kang Signed-off-by: Ravi Patel Link: https://lore.kernel.org/r/20250825114436.46882-4-ravi.patel@samsung.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/Makefile | 1 + drivers/clk/samsung/clk-artpec8.c | 1044 +++++++++++++++++++++++++++++ 2 files changed, 1045 insertions(+) create mode 100644 drivers/clk/samsung/clk-artpec8.c diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index b77fe288e4bb..ef464f434740 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_EXYNOS_5260_COMMON_CLK) += clk-exynos5260.o obj-$(CONFIG_EXYNOS_5410_COMMON_CLK) += clk-exynos5410.o obj-$(CONFIG_EXYNOS_5420_COMMON_CLK) += clk-exynos5420.o obj-$(CONFIG_EXYNOS_5420_COMMON_CLK) += clk-exynos5-subcmu.o +obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-artpec8.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o obj-$(CONFIG_EXYNOS_CLKOUT) += clk-exynos-clkout.o diff --git a/drivers/clk/samsung/clk-artpec8.c b/drivers/clk/samsung/clk-artpec8.c new file mode 100644 index 000000000000..0ea7c8b58674 --- /dev/null +++ b/drivers/clk/samsung/clk-artpec8.c @@ -0,0 +1,1044 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd. + * https://www.samsung.com + * Copyright (c) 2025 Axis Communications AB. + * https://www.axis.com + * + * Common Clock Framework support for ARTPEC-8 SoC. + */ + +#include +#include +#include + +#include "clk.h" +#include "clk-exynos-arm64.h" + +/* NOTE: Must be equal to the last clock ID increased by one */ +#define CMU_CMU_NR_CLK (CLK_DOUT_CMU_VPP_CORE + 1) +#define CMU_BUS_NR_CLK (CLK_DOUT_BUS_PCLK + 1) +#define CMU_CORE_NR_CLK (CLK_DOUT_CORE_PCLK + 1) +#define CMU_CPUCL_NR_CLK (CLK_GOUT_CPUCL_CSSYS_IPCLKPORT_ATCLK + 1) +#define CMU_FSYS_NR_CLK (CLK_GOUT_FSYS_QSPI_IPCLKPORT_SSI_CLK + 1) +#define CMU_IMEM_NR_CLK (CLK_GOUT_IMEM_PCLK_TMU0_APBIF + 1) +#define CMU_PERI_NR_CLK (CLK_GOUT_PERI_DMA4DSIM_IPCLKPORT_CLK_AXI_CLK + 1) + +/* Register Offset definitions for CMU_CMU (0x12400000) */ +#define PLL_LOCKTIME_PLL_AUDIO 0x0000 +#define PLL_LOCKTIME_PLL_SHARED0 0x0004 +#define PLL_LOCKTIME_PLL_SHARED1 0x0008 +#define PLL_CON0_PLL_AUDIO 0x0100 +#define PLL_CON0_PLL_SHARED0 0x0120 +#define PLL_CON0_PLL_SHARED1 0x0140 +#define CLK_CON_MUX_CLKCMU_2D 0x1000 +#define CLK_CON_MUX_CLKCMU_3D 0x1004 +#define CLK_CON_MUX_CLKCMU_BUS 0x1008 +#define CLK_CON_MUX_CLKCMU_BUS_DLP 0x100c +#define CLK_CON_MUX_CLKCMU_CDC_CORE 0x1010 +#define CLK_CON_MUX_CLKCMU_FSYS_SCAN0 0x1014 +#define CLK_CON_MUX_CLKCMU_FSYS_SCAN1 0x1018 +#define CLK_CON_MUX_CLKCMU_IMEM_JPEG 0x101c +#define CLK_CON_MUX_CLKCMU_PERI_DISP 0x1020 +#define CLK_CON_MUX_CLKCMU_CORE_BUS 0x1024 +#define CLK_CON_MUX_CLKCMU_CORE_DLP 0x1028 +#define CLK_CON_MUX_CLKCMU_CPUCL_SWITCH 0x1030 +#define CLK_CON_MUX_CLKCMU_DLP_CORE 0x1034 +#define CLK_CON_MUX_CLKCMU_FSYS_BUS 0x1038 +#define CLK_CON_MUX_CLKCMU_FSYS_IP 0x103c +#define CLK_CON_MUX_CLKCMU_IMEM_ACLK 0x1054 +#define CLK_CON_MUX_CLKCMU_MIF_BUSP 0x1080 +#define CLK_CON_MUX_CLKCMU_MIF_SWITCH 0x1084 +#define CLK_CON_MUX_CLKCMU_PERI_IP 0x1088 +#define CLK_CON_MUX_CLKCMU_RSP_CORE 0x108c +#define CLK_CON_MUX_CLKCMU_TRFM_CORE 0x1090 +#define CLK_CON_MUX_CLKCMU_VCA_ACE 0x1094 +#define CLK_CON_MUX_CLKCMU_VCA_OD 0x1098 +#define CLK_CON_MUX_CLKCMU_VIO_CORE 0x109c +#define CLK_CON_MUX_CLKCMU_VIP0_CORE 0x10a0 +#define CLK_CON_MUX_CLKCMU_VIP1_CORE 0x10a4 +#define CLK_CON_MUX_CLKCMU_VPP_CORE 0x10a8 + +#define CLK_CON_DIV_CLKCMU_BUS 0x1800 +#define CLK_CON_DIV_CLKCMU_BUS_DLP 0x1804 +#define CLK_CON_DIV_CLKCMU_CDC_CORE 0x1808 +#define CLK_CON_DIV_CLKCMU_FSYS_SCAN0 0x180c +#define CLK_CON_DIV_CLKCMU_FSYS_SCAN1 0x1810 +#define CLK_CON_DIV_CLKCMU_IMEM_JPEG 0x1814 +#define CLK_CON_DIV_CLKCMU_MIF_SWITCH 0x1818 +#define CLK_CON_DIV_CLKCMU_CORE_DLP 0x181c +#define CLK_CON_DIV_CLKCMU_CORE_MAIN 0x1820 +#define CLK_CON_DIV_CLKCMU_PERI_DISP 0x1824 +#define CLK_CON_DIV_CLKCMU_CPUCL_SWITCH 0x1828 +#define CLK_CON_DIV_CLKCMU_DLP_CORE 0x182c +#define CLK_CON_DIV_CLKCMU_FSYS_BUS 0x1830 +#define CLK_CON_DIV_CLKCMU_FSYS_IP 0x1834 +#define CLK_CON_DIV_CLKCMU_VIO_AUDIO 0x1838 +#define CLK_CON_DIV_CLKCMU_GPU_2D 0x1848 +#define CLK_CON_DIV_CLKCMU_GPU_3D 0x184c +#define CLK_CON_DIV_CLKCMU_IMEM_ACLK 0x1854 +#define CLK_CON_DIV_CLKCMU_MIF_BUSP 0x1884 +#define CLK_CON_DIV_CLKCMU_PERI_AUDIO 0x1890 +#define CLK_CON_DIV_CLKCMU_PERI_IP 0x1894 +#define CLK_CON_DIV_CLKCMU_RSP_CORE 0x1898 +#define CLK_CON_DIV_CLKCMU_TRFM_CORE 0x189c +#define CLK_CON_DIV_CLKCMU_VCA_ACE 0x18a0 +#define CLK_CON_DIV_CLKCMU_VCA_OD 0x18a4 +#define CLK_CON_DIV_CLKCMU_VIO_CORE 0x18ac +#define CLK_CON_DIV_CLKCMU_VIP0_CORE 0x18b0 +#define CLK_CON_DIV_CLKCMU_VIP1_CORE 0x18b4 +#define CLK_CON_DIV_CLKCMU_VPP_CORE 0x18b8 +#define CLK_CON_DIV_PLL_SHARED0_DIV2 0x18bc +#define CLK_CON_DIV_PLL_SHARED0_DIV3 0x18c0 +#define CLK_CON_DIV_PLL_SHARED0_DIV4 0x18c4 +#define CLK_CON_DIV_PLL_SHARED1_DIV2 0x18c8 +#define CLK_CON_DIV_PLL_SHARED1_DIV3 0x18cc +#define CLK_CON_DIV_PLL_SHARED1_DIV4 0x18d0 + +static const unsigned long cmu_cmu_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_AUDIO, + PLL_LOCKTIME_PLL_SHARED0, + PLL_LOCKTIME_PLL_SHARED1, + PLL_CON0_PLL_AUDIO, + PLL_CON0_PLL_SHARED0, + PLL_CON0_PLL_SHARED1, + CLK_CON_MUX_CLKCMU_2D, + CLK_CON_MUX_CLKCMU_3D, + CLK_CON_MUX_CLKCMU_BUS, + CLK_CON_MUX_CLKCMU_BUS_DLP, + CLK_CON_MUX_CLKCMU_CDC_CORE, + CLK_CON_MUX_CLKCMU_FSYS_SCAN0, + CLK_CON_MUX_CLKCMU_FSYS_SCAN1, + CLK_CON_MUX_CLKCMU_IMEM_JPEG, + CLK_CON_MUX_CLKCMU_PERI_DISP, + CLK_CON_MUX_CLKCMU_CORE_BUS, + CLK_CON_MUX_CLKCMU_CORE_DLP, + CLK_CON_MUX_CLKCMU_CPUCL_SWITCH, + CLK_CON_MUX_CLKCMU_DLP_CORE, + CLK_CON_MUX_CLKCMU_FSYS_BUS, + CLK_CON_MUX_CLKCMU_FSYS_IP, + CLK_CON_MUX_CLKCMU_IMEM_ACLK, + CLK_CON_MUX_CLKCMU_MIF_BUSP, + CLK_CON_MUX_CLKCMU_MIF_SWITCH, + CLK_CON_MUX_CLKCMU_PERI_IP, + CLK_CON_MUX_CLKCMU_RSP_CORE, + CLK_CON_MUX_CLKCMU_TRFM_CORE, + CLK_CON_MUX_CLKCMU_VCA_ACE, + CLK_CON_MUX_CLKCMU_VCA_OD, + CLK_CON_MUX_CLKCMU_VIO_CORE, + CLK_CON_MUX_CLKCMU_VIP0_CORE, + CLK_CON_MUX_CLKCMU_VIP1_CORE, + CLK_CON_MUX_CLKCMU_VPP_CORE, + CLK_CON_DIV_CLKCMU_BUS, + CLK_CON_DIV_CLKCMU_BUS_DLP, + CLK_CON_DIV_CLKCMU_CDC_CORE, + CLK_CON_DIV_CLKCMU_FSYS_SCAN0, + CLK_CON_DIV_CLKCMU_FSYS_SCAN1, + CLK_CON_DIV_CLKCMU_IMEM_JPEG, + CLK_CON_DIV_CLKCMU_MIF_SWITCH, + CLK_CON_DIV_CLKCMU_CORE_DLP, + CLK_CON_DIV_CLKCMU_CORE_MAIN, + CLK_CON_DIV_CLKCMU_PERI_DISP, + CLK_CON_DIV_CLKCMU_CPUCL_SWITCH, + CLK_CON_DIV_CLKCMU_DLP_CORE, + CLK_CON_DIV_CLKCMU_FSYS_BUS, + CLK_CON_DIV_CLKCMU_FSYS_IP, + CLK_CON_DIV_CLKCMU_VIO_AUDIO, + CLK_CON_DIV_CLKCMU_GPU_2D, + CLK_CON_DIV_CLKCMU_GPU_3D, + CLK_CON_DIV_CLKCMU_IMEM_ACLK, + CLK_CON_DIV_CLKCMU_MIF_BUSP, + CLK_CON_DIV_CLKCMU_PERI_AUDIO, + CLK_CON_DIV_CLKCMU_PERI_IP, + CLK_CON_DIV_CLKCMU_RSP_CORE, + CLK_CON_DIV_CLKCMU_TRFM_CORE, + CLK_CON_DIV_CLKCMU_VCA_ACE, + CLK_CON_DIV_CLKCMU_VCA_OD, + CLK_CON_DIV_CLKCMU_VIO_CORE, + CLK_CON_DIV_CLKCMU_VIP0_CORE, + CLK_CON_DIV_CLKCMU_VIP1_CORE, + CLK_CON_DIV_CLKCMU_VPP_CORE, + CLK_CON_DIV_PLL_SHARED0_DIV2, + CLK_CON_DIV_PLL_SHARED0_DIV3, + CLK_CON_DIV_PLL_SHARED0_DIV4, + CLK_CON_DIV_PLL_SHARED1_DIV2, + CLK_CON_DIV_PLL_SHARED1_DIV3, + CLK_CON_DIV_PLL_SHARED1_DIV4, +}; + +static const struct samsung_pll_rate_table artpec8_pll_audio_rates[] __initconst = { + PLL_36XX_RATE(25 * MHZ, 589823913U, 47, 1, 1, 12184), + PLL_36XX_RATE(25 * MHZ, 393215942U, 47, 3, 0, 12184), + PLL_36XX_RATE(25 * MHZ, 294911956U, 47, 1, 2, 12184), + PLL_36XX_RATE(25 * MHZ, 100000000U, 32, 2, 2, 0), + PLL_36XX_RATE(25 * MHZ, 98303985U, 47, 3, 2, 12184), + PLL_36XX_RATE(25 * MHZ, 49151992U, 47, 3, 3, 12184), +}; + +static const struct samsung_pll_clock cmu_cmu_pll_clks[] __initconst = { + PLL(pll_1017x, CLK_FOUT_SHARED0_PLL, "fout_pll_shared0", "fin_pll", + PLL_LOCKTIME_PLL_SHARED0, PLL_CON0_PLL_SHARED0, NULL), + PLL(pll_1017x, CLK_FOUT_SHARED1_PLL, "fout_pll_shared1", "fin_pll", + PLL_LOCKTIME_PLL_SHARED1, PLL_CON0_PLL_SHARED1, NULL), + PLL(pll_1031x, CLK_FOUT_AUDIO_PLL, "fout_pll_audio", "fin_pll", + PLL_LOCKTIME_PLL_AUDIO, PLL_CON0_PLL_AUDIO, artpec8_pll_audio_rates), +}; + +PNAME(mout_clkcmu_bus_bus_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div3", + "dout_pll_shared1_div3", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_bus_dlp_p) = { "dout_pll_shared0_div2", "dout_pll_shared0_div4", + "dout_pll_shared1_div2", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_core_bus_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div3", + "dout_pll_shared0_div4", "dout_pll_shared1_div3" }; +PNAME(mout_clkcmu_core_dlp_p) = { "dout_pll_shared0_div2", "dout_pll_shared1_div2", + "dout_pll_shared0_div3", "dout_pll_shared1_div3" }; +PNAME(mout_clkcmu_cpucl_switch_p) = { "dout_pll_shared0_div2", "dout_pll_shared1_div2", + "dout_pll_shared0_div3", "dout_pll_shared1_div3" }; +PNAME(mout_clkcmu_fsys_bus_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div2", + "dout_pll_shared1_div4", "dout_pll_shared1_div3" }; +PNAME(mout_clkcmu_fsys_ip_p) = { "dout_pll_shared0_div2", "dout_pll_shared1_div3", + "dout_pll_shared1_div2", "dout_pll_shared0_div3" }; +PNAME(mout_clkcmu_fsys_scan0_p) = { "dout_pll_shared0_div4", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_fsys_scan1_p) = { "dout_pll_shared0_div4", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_imem_imem_p) = { "dout_pll_shared1_div4", "dout_pll_shared0_div3", + "dout_pll_shared1_div3", "dout_pll_shared1_div2" }; +PNAME(mout_clkcmu_imem_jpeg_p) = { "dout_pll_shared0_div2", "dout_pll_shared0_div3", + "dout_pll_shared1_div2", "dout_pll_shared1_div3" }; +PNAME(mout_clkcmu_cdc_core_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div3", + "dout_pll_shared1_div3", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_dlp_core_p) = { "dout_pll_shared0_div2", "dout_pll_shared1_div2", + "dout_pll_shared0_div3", "dout_pll_shared1_div3" }; +PNAME(mout_clkcmu_3d_p) = { "dout_pll_shared0_div2", "dout_pll_shared1_div2", + "dout_pll_shared0_div3", "dout_pll_shared1_div3" }; +PNAME(mout_clkcmu_2d_p) = { "dout_pll_shared0_div2", "dout_pll_shared1_div2", + "dout_pll_shared0_div3", "dout_pll_shared1_div3" }; +PNAME(mout_clkcmu_mif_switch_p) = { "dout_pll_shared0", "dout_pll_shared1", + "dout_pll_shared0_div2", "dout_pll_shared0_div3" }; +PNAME(mout_clkcmu_mif_busp_p) = { "dout_pll_shared0_div3", "dout_pll_shared1_div4", + "dout_pll_shared0_div4", "dout_pll_shared0_div2" }; +PNAME(mout_clkcmu_peri_disp_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div2", + "dout_pll_shared1_div4", "dout_pll_shared1_div3" }; +PNAME(mout_clkcmu_peri_ip_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div4", + "dout_pll_shared1_div4", "dout_pll_shared0_div2" }; +PNAME(mout_clkcmu_rsp_core_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div3", + "dout_pll_shared1_div3", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_trfm_core_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div3", + "dout_pll_shared1_div3", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_vca_ace_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div3", + "dout_pll_shared1_div3", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_vca_od_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div3", + "dout_pll_shared1_div3", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_vio_core_p) = { "dout_pll_shared0_div3", "dout_pll_shared0_div2", + "dout_pll_shared1_div2", "dout_pll_shared1_div3" }; +PNAME(mout_clkcmu_vip0_core_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div3", + "dout_pll_shared1_div3", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_vip1_core_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div3", + "dout_pll_shared1_div3", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_vpp_core_p) = { "dout_pll_shared1_div2", "dout_pll_shared0_div3", + "dout_pll_shared1_div3", "dout_pll_shared1_div4" }; +PNAME(mout_clkcmu_pll_shared0_p) = { "fin_pll", "fout_pll_shared0" }; +PNAME(mout_clkcmu_pll_shared1_p) = { "fin_pll", "fout_pll_shared1" }; +PNAME(mout_clkcmu_pll_audio_p) = { "fin_pll", "fout_pll_audio" }; + +static const struct samsung_fixed_factor_clock cmu_fixed_factor_clks[] __initconst = { + FFACTOR(CLK_DOUT_CMU_OTP, "dout_clkcmu_otp", "fin_pll", 1, 8, 0), +}; + +static const struct samsung_mux_clock cmu_cmu_mux_clks[] __initconst = { + MUX(0, "mout_clkcmu_pll_shared0", mout_clkcmu_pll_shared0_p, PLL_CON0_PLL_SHARED0, 4, 1), + MUX(0, "mout_clkcmu_pll_shared1", mout_clkcmu_pll_shared1_p, PLL_CON0_PLL_SHARED1, 4, 1), + MUX(0, "mout_clkcmu_pll_audio", mout_clkcmu_pll_audio_p, PLL_CON0_PLL_AUDIO, 4, 1), + MUX(0, "mout_clkcmu_bus_bus", mout_clkcmu_bus_bus_p, CLK_CON_MUX_CLKCMU_BUS, 0, 2), + MUX(0, "mout_clkcmu_bus_dlp", mout_clkcmu_bus_dlp_p, CLK_CON_MUX_CLKCMU_BUS_DLP, 0, 2), + MUX(0, "mout_clkcmu_core_bus", mout_clkcmu_core_bus_p, CLK_CON_MUX_CLKCMU_CORE_BUS, 0, 2), + MUX(0, "mout_clkcmu_core_dlp", mout_clkcmu_core_dlp_p, CLK_CON_MUX_CLKCMU_CORE_DLP, 0, 2), + MUX(0, "mout_clkcmu_cpucl_switch", mout_clkcmu_cpucl_switch_p, + CLK_CON_MUX_CLKCMU_CPUCL_SWITCH, 0, 3), + MUX(0, "mout_clkcmu_fsys_bus", mout_clkcmu_fsys_bus_p, CLK_CON_MUX_CLKCMU_FSYS_BUS, 0, 2), + MUX(0, "mout_clkcmu_fsys_ip", mout_clkcmu_fsys_ip_p, CLK_CON_MUX_CLKCMU_FSYS_IP, 0, 2), + MUX(0, "mout_clkcmu_fsys_scan0", mout_clkcmu_fsys_scan0_p, + CLK_CON_MUX_CLKCMU_FSYS_SCAN0, 0, 1), + MUX(0, "mout_clkcmu_fsys_scan1", mout_clkcmu_fsys_scan1_p, + CLK_CON_MUX_CLKCMU_FSYS_SCAN1, 0, 1), + MUX(0, "mout_clkcmu_imem_imem", mout_clkcmu_imem_imem_p, + CLK_CON_MUX_CLKCMU_IMEM_ACLK, 0, 2), + MUX(0, "mout_clkcmu_imem_jpeg", mout_clkcmu_imem_jpeg_p, + CLK_CON_MUX_CLKCMU_IMEM_JPEG, 0, 2), + nMUX(0, "mout_clkcmu_cdc_core", mout_clkcmu_cdc_core_p, CLK_CON_MUX_CLKCMU_CDC_CORE, 0, 2), + nMUX(0, "mout_clkcmu_dlp_core", mout_clkcmu_dlp_core_p, CLK_CON_MUX_CLKCMU_DLP_CORE, 0, 2), + MUX(0, "mout_clkcmu_3d", mout_clkcmu_3d_p, CLK_CON_MUX_CLKCMU_3D, 0, 2), + MUX(0, "mout_clkcmu_2d", mout_clkcmu_2d_p, CLK_CON_MUX_CLKCMU_2D, 0, 2), + MUX(0, "mout_clkcmu_mif_switch", mout_clkcmu_mif_switch_p, + CLK_CON_MUX_CLKCMU_MIF_SWITCH, 0, 2), + MUX(0, "mout_clkcmu_mif_busp", mout_clkcmu_mif_busp_p, CLK_CON_MUX_CLKCMU_MIF_BUSP, 0, 2), + MUX(0, "mout_clkcmu_peri_disp", mout_clkcmu_peri_disp_p, + CLK_CON_MUX_CLKCMU_PERI_DISP, 0, 2), + MUX(0, "mout_clkcmu_peri_ip", mout_clkcmu_peri_ip_p, CLK_CON_MUX_CLKCMU_PERI_IP, 0, 2), + MUX(0, "mout_clkcmu_rsp_core", mout_clkcmu_rsp_core_p, CLK_CON_MUX_CLKCMU_RSP_CORE, 0, 2), + nMUX(0, "mout_clkcmu_trfm_core", mout_clkcmu_trfm_core_p, + CLK_CON_MUX_CLKCMU_TRFM_CORE, 0, 2), + MUX(0, "mout_clkcmu_vca_ace", mout_clkcmu_vca_ace_p, CLK_CON_MUX_CLKCMU_VCA_ACE, 0, 2), + MUX(0, "mout_clkcmu_vca_od", mout_clkcmu_vca_od_p, CLK_CON_MUX_CLKCMU_VCA_OD, 0, 2), + MUX(0, "mout_clkcmu_vio_core", mout_clkcmu_vio_core_p, CLK_CON_MUX_CLKCMU_VIO_CORE, 0, 2), + nMUX(0, "mout_clkcmu_vip0_core", mout_clkcmu_vip0_core_p, + CLK_CON_MUX_CLKCMU_VIP0_CORE, 0, 2), + nMUX(0, "mout_clkcmu_vip1_core", mout_clkcmu_vip1_core_p, + CLK_CON_MUX_CLKCMU_VIP1_CORE, 0, 2), + nMUX(0, "mout_clkcmu_vpp_core", mout_clkcmu_vpp_core_p, CLK_CON_MUX_CLKCMU_VPP_CORE, 0, 2), +}; + +static const struct samsung_div_clock cmu_cmu_div_clks[] __initconst = { + DIV(CLK_DOUT_SHARED0_DIV2, "dout_pll_shared0_div2", + "mout_clkcmu_pll_shared0", CLK_CON_DIV_PLL_SHARED0_DIV2, 0, 1), + DIV(CLK_DOUT_SHARED0_DIV3, "dout_pll_shared0_div3", + "mout_clkcmu_pll_shared0", CLK_CON_DIV_PLL_SHARED0_DIV3, 0, 2), + DIV(CLK_DOUT_SHARED0_DIV4, "dout_pll_shared0_div4", + "dout_pll_shared0_div2", CLK_CON_DIV_PLL_SHARED0_DIV4, 0, 1), + DIV(CLK_DOUT_SHARED1_DIV2, "dout_pll_shared1_div2", + "mout_clkcmu_pll_shared1", CLK_CON_DIV_PLL_SHARED1_DIV2, 0, 1), + DIV(CLK_DOUT_SHARED1_DIV3, "dout_pll_shared1_div3", + "mout_clkcmu_pll_shared1", CLK_CON_DIV_PLL_SHARED1_DIV3, 0, 2), + DIV(CLK_DOUT_SHARED1_DIV4, "dout_pll_shared1_div4", + "dout_pll_shared1_div2", CLK_CON_DIV_PLL_SHARED1_DIV4, 0, 1), + DIV(CLK_DOUT_CMU_BUS, "dout_clkcmu_bus", + "mout_clkcmu_bus_bus", CLK_CON_DIV_CLKCMU_BUS, 0, 4), + DIV(CLK_DOUT_CMU_BUS_DLP, "dout_clkcmu_bus_dlp", + "mout_clkcmu_bus_dlp", CLK_CON_DIV_CLKCMU_BUS_DLP, 0, 4), + DIV(CLK_DOUT_CMU_CORE_MAIN, "dout_clkcmu_core_main", + "mout_clkcmu_core_bus", CLK_CON_DIV_CLKCMU_CORE_MAIN, 0, 4), + DIV(CLK_DOUT_CMU_CORE_DLP, "dout_clkcmu_core_dlp", + "mout_clkcmu_core_dlp", CLK_CON_DIV_CLKCMU_CORE_DLP, 0, 4), + DIV(CLK_DOUT_CMU_CPUCL_SWITCH, "dout_clkcmu_cpucl_switch", + "mout_clkcmu_cpucl_switch", CLK_CON_DIV_CLKCMU_CPUCL_SWITCH, 0, 3), + DIV(CLK_DOUT_CMU_FSYS_BUS, "dout_clkcmu_fsys_bus", + "mout_clkcmu_fsys_bus", CLK_CON_DIV_CLKCMU_FSYS_BUS, 0, 4), + DIV(CLK_DOUT_CMU_FSYS_IP, "dout_clkcmu_fsys_ip", + "mout_clkcmu_fsys_ip", CLK_CON_DIV_CLKCMU_FSYS_IP, 0, 9), + DIV(CLK_DOUT_CMU_FSYS_SCAN0, "dout_clkcmu_fsys_scan0", + "mout_clkcmu_fsys_scan0", CLK_CON_DIV_CLKCMU_FSYS_SCAN0, 0, 4), + DIV(CLK_DOUT_CMU_FSYS_SCAN1, "dout_clkcmu_fsys_scan1", + "mout_clkcmu_fsys_scan1", CLK_CON_DIV_CLKCMU_FSYS_SCAN1, 0, 4), + DIV(CLK_DOUT_CMU_IMEM_ACLK, "dout_clkcmu_imem_aclk", + "mout_clkcmu_imem_imem", CLK_CON_DIV_CLKCMU_IMEM_ACLK, 0, 4), + DIV(CLK_DOUT_CMU_IMEM_JPEG, "dout_clkcmu_imem_jpeg", + "mout_clkcmu_imem_jpeg", CLK_CON_DIV_CLKCMU_IMEM_JPEG, 0, 4), + DIV_F(CLK_DOUT_CMU_CDC_CORE, "dout_clkcmu_cdc_core", + "mout_clkcmu_cdc_core", CLK_CON_DIV_CLKCMU_CDC_CORE, 0, 4, CLK_SET_RATE_PARENT, 0), + DIV_F(CLK_DOUT_CMU_DLP_CORE, "dout_clkcmu_dlp_core", + "mout_clkcmu_dlp_core", CLK_CON_DIV_CLKCMU_DLP_CORE, 0, 4, CLK_SET_RATE_PARENT, 0), + DIV(CLK_DOUT_CMU_GPU_3D, "dout_clkcmu_gpu_3d", + "mout_clkcmu_3d", CLK_CON_DIV_CLKCMU_GPU_3D, 0, 3), + DIV(CLK_DOUT_CMU_GPU_2D, "dout_clkcmu_gpu_2d", + "mout_clkcmu_2d", CLK_CON_DIV_CLKCMU_GPU_2D, 0, 4), + DIV(CLK_DOUT_CMU_MIF_SWITCH, "dout_clkcmu_mif_switch", + "mout_clkcmu_mif_switch", CLK_CON_DIV_CLKCMU_MIF_SWITCH, 0, 4), + DIV(CLK_DOUT_CMU_MIF_BUSP, "dout_clkcmu_mif_busp", + "mout_clkcmu_mif_busp", CLK_CON_DIV_CLKCMU_MIF_BUSP, 0, 3), + DIV(CLK_DOUT_CMU_PERI_DISP, "dout_clkcmu_peri_disp", + "mout_clkcmu_peri_disp", CLK_CON_DIV_CLKCMU_PERI_DISP, 0, 4), + DIV(CLK_DOUT_CMU_PERI_IP, "dout_clkcmu_peri_ip", + "mout_clkcmu_peri_ip", CLK_CON_DIV_CLKCMU_PERI_IP, 0, 4), + DIV(CLK_DOUT_CMU_PERI_AUDIO, "dout_clkcmu_peri_audio", + "mout_clkcmu_pll_audio", CLK_CON_DIV_CLKCMU_PERI_AUDIO, 0, 4), + DIV(CLK_DOUT_CMU_RSP_CORE, "dout_clkcmu_rsp_core", + "mout_clkcmu_rsp_core", CLK_CON_DIV_CLKCMU_RSP_CORE, 0, 4), + DIV_F(CLK_DOUT_CMU_TRFM_CORE, "dout_clkcmu_trfm_core", + "mout_clkcmu_trfm_core", CLK_CON_DIV_CLKCMU_TRFM_CORE, 0, 4, CLK_SET_RATE_PARENT, 0), + DIV(CLK_DOUT_CMU_VCA_ACE, "dout_clkcmu_vca_ace", + "mout_clkcmu_vca_ace", CLK_CON_DIV_CLKCMU_VCA_ACE, 0, 4), + DIV(CLK_DOUT_CMU_VCA_OD, "dout_clkcmu_vca_od", + "mout_clkcmu_vca_od", CLK_CON_DIV_CLKCMU_VCA_OD, 0, 4), + DIV(CLK_DOUT_CMU_VIO_CORE, "dout_clkcmu_vio_core", + "mout_clkcmu_vio_core", CLK_CON_DIV_CLKCMU_VIO_CORE, 0, 4), + DIV(CLK_DOUT_CMU_VIO_AUDIO, "dout_clkcmu_vio_audio", + "mout_clkcmu_pll_audio", CLK_CON_DIV_CLKCMU_VIO_AUDIO, 0, 4), + DIV_F(CLK_DOUT_CMU_VIP0_CORE, "dout_clkcmu_vip0_core", + "mout_clkcmu_vip0_core", CLK_CON_DIV_CLKCMU_VIP0_CORE, 0, 4, CLK_SET_RATE_PARENT, 0), + DIV_F(CLK_DOUT_CMU_VIP1_CORE, "dout_clkcmu_vip1_core", + "mout_clkcmu_vip1_core", CLK_CON_DIV_CLKCMU_VIP1_CORE, 0, 4, CLK_SET_RATE_PARENT, 0), + DIV_F(CLK_DOUT_CMU_VPP_CORE, "dout_clkcmu_vpp_core", + "mout_clkcmu_vpp_core", CLK_CON_DIV_CLKCMU_VPP_CORE, 0, 4, CLK_SET_RATE_PARENT, 0), +}; + +static const struct samsung_cmu_info cmu_cmu_info __initconst = { + .pll_clks = cmu_cmu_pll_clks, + .nr_pll_clks = ARRAY_SIZE(cmu_cmu_pll_clks), + .fixed_factor_clks = cmu_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(cmu_fixed_factor_clks), + .mux_clks = cmu_cmu_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cmu_cmu_mux_clks), + .div_clks = cmu_cmu_div_clks, + .nr_div_clks = ARRAY_SIZE(cmu_cmu_div_clks), + .nr_clk_ids = CMU_CMU_NR_CLK, + .clk_regs = cmu_cmu_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cmu_cmu_clk_regs), +}; + +/* Register Offset definitions for CMU_BUS (0x12c10000) */ +#define PLL_CON0_MUX_CLK_BUS_ACLK_USER 0x0100 +#define PLL_CON0_MUX_CLK_BUS_DLP_USER 0x0120 +#define CLK_CON_DIV_CLK_BUS_PCLK 0x1800 + +static const unsigned long cmu_bus_clk_regs[] __initconst = { + PLL_CON0_MUX_CLK_BUS_ACLK_USER, + PLL_CON0_MUX_CLK_BUS_DLP_USER, + CLK_CON_DIV_CLK_BUS_PCLK, +}; + +PNAME(mout_clk_bus_aclk_user_p) = { "fin_pll", "dout_clkcmu_bus" }; +PNAME(mout_clk_bus_dlp_user_p) = { "fin_pll", "dout_clkcmu_bus_dlp" }; + +static const struct samsung_mux_clock cmu_bus_mux_clks[] __initconst = { + MUX(CLK_MOUT_BUS_ACLK_USER, "mout_clk_bus_aclk_user", + mout_clk_bus_aclk_user_p, PLL_CON0_MUX_CLK_BUS_ACLK_USER, 4, 1), + MUX(CLK_MOUT_BUS_DLP_USER, "mout_clk_bus_dlp_user", + mout_clk_bus_dlp_user_p, PLL_CON0_MUX_CLK_BUS_DLP_USER, 4, 1), +}; + +static const struct samsung_div_clock cmu_bus_div_clks[] __initconst = { + DIV(CLK_DOUT_BUS_PCLK, "dout_clk_bus_pclk", "mout_clk_bus_aclk_user", + CLK_CON_DIV_CLK_BUS_PCLK, 0, 4), +}; + +static const struct samsung_cmu_info cmu_bus_info __initconst = { + .mux_clks = cmu_bus_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cmu_bus_mux_clks), + .div_clks = cmu_bus_div_clks, + .nr_div_clks = ARRAY_SIZE(cmu_bus_div_clks), + .nr_clk_ids = CMU_BUS_NR_CLK, + .clk_regs = cmu_bus_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cmu_bus_clk_regs), +}; + +/* Register Offset definitions for CMU_CORE (0x12410000) */ +#define PLL_CON0_MUX_CLK_CORE_ACLK_USER 0x0100 +#define PLL_CON0_MUX_CLK_CORE_DLP_USER 0x0120 +#define CLK_CON_DIV_CLK_CORE_PCLK 0x1800 + +static const unsigned long cmu_core_clk_regs[] __initconst = { + PLL_CON0_MUX_CLK_CORE_ACLK_USER, + PLL_CON0_MUX_CLK_CORE_DLP_USER, + CLK_CON_DIV_CLK_CORE_PCLK, +}; + +PNAME(mout_clk_core_aclk_user_p) = { "fin_pll", "dout_clkcmu_core_main" }; +PNAME(mout_clk_core_dlp_user_p) = { "fin_pll", "dout_clkcmu_core_dlp" }; + +static const struct samsung_mux_clock cmu_core_mux_clks[] __initconst = { + MUX(CLK_MOUT_CORE_ACLK_USER, "mout_clk_core_aclk_user", + mout_clk_core_aclk_user_p, PLL_CON0_MUX_CLK_CORE_ACLK_USER, 4, 1), + MUX(CLK_MOUT_CORE_DLP_USER, "mout_clk_core_dlp_user", + mout_clk_core_dlp_user_p, PLL_CON0_MUX_CLK_CORE_DLP_USER, 4, 1), +}; + +static const struct samsung_div_clock cmu_core_div_clks[] __initconst = { + DIV(CLK_DOUT_CORE_PCLK, "dout_clk_core_pclk", + "mout_clk_core_aclk_user", CLK_CON_DIV_CLK_CORE_PCLK, 0, 4), +}; + +static const struct samsung_cmu_info cmu_core_info __initconst = { + .mux_clks = cmu_core_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cmu_core_mux_clks), + .div_clks = cmu_core_div_clks, + .nr_div_clks = ARRAY_SIZE(cmu_core_div_clks), + .nr_clk_ids = CMU_CORE_NR_CLK, + .clk_regs = cmu_core_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cmu_core_clk_regs), +}; + +/* Register Offset definitions for CMU_CPUCL (0x11410000) */ +#define PLL_LOCKTIME_PLL_CPUCL 0x0000 +#define PLL_CON0_MUX_CLKCMU_CPUCL_SWITCH_USER 0x0120 +#define PLL_CON0_PLL_CPUCL 0x0140 +#define CLK_CON_MUX_CLK_CPUCL_PLL 0x1000 +#define CLK_CON_DIV_CLK_CLUSTER_ACLK 0x1800 +#define CLK_CON_DIV_CLK_CLUSTER_CNTCLK 0x1804 +#define CLK_CON_DIV_CLK_CLUSTER_PCLKDBG 0x1808 +#define CLK_CON_DIV_CLK_CPUCL_CMUREF 0x180c +#define CLK_CON_DIV_CLK_CPUCL_PCLK 0x1814 +#define CLK_CON_DIV_CLK_CLUSTER_ATCLK 0x1818 +#define CLK_CON_DIV_CLK_CPUCL_DBG 0x181c +#define CLK_CON_DIV_CLK_CPUCL_PCLKDBG 0x1820 +#define CLK_CON_GAT_CLK_CLUSTER_CPU 0x2008 +#define CLK_CON_GAT_CLK_CPUCL_SHORTSTOP 0x200c +#define CLK_CON_DMYQCH_CON_CSSYS_QCH 0x3008 + +static const unsigned long cmu_cpucl_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_CPUCL, + PLL_CON0_MUX_CLKCMU_CPUCL_SWITCH_USER, + PLL_CON0_PLL_CPUCL, + CLK_CON_MUX_CLK_CPUCL_PLL, + CLK_CON_DIV_CLK_CLUSTER_ACLK, + CLK_CON_DIV_CLK_CLUSTER_CNTCLK, + CLK_CON_DIV_CLK_CLUSTER_PCLKDBG, + CLK_CON_DIV_CLK_CPUCL_CMUREF, + CLK_CON_DIV_CLK_CPUCL_PCLK, + CLK_CON_DIV_CLK_CLUSTER_ATCLK, + CLK_CON_DIV_CLK_CPUCL_DBG, + CLK_CON_DIV_CLK_CPUCL_PCLKDBG, + CLK_CON_GAT_CLK_CLUSTER_CPU, + CLK_CON_GAT_CLK_CPUCL_SHORTSTOP, + CLK_CON_DMYQCH_CON_CSSYS_QCH, +}; + +static const struct samsung_pll_clock cmu_cpucl_pll_clks[] __initconst = { + PLL(pll_1017x, CLK_FOUT_CPUCL_PLL, "fout_pll_cpucl", "fin_pll", + PLL_LOCKTIME_PLL_CPUCL, PLL_CON0_PLL_CPUCL, NULL), +}; + +PNAME(mout_clkcmu_cpucl_switch_user_p) = { "fin_pll", "dout_clkcmu_cpucl_switch" }; +PNAME(mout_pll_cpucl_p) = { "fin_pll", "fout_pll_cpucl" }; +PNAME(mout_clk_cpucl_pll_p) = { "mout_pll_cpucl", "mout_clkcmu_cpucl_switch_user" }; + +static const struct samsung_mux_clock cmu_cpucl_mux_clks[] __initconst = { + MUX_F(0, "mout_pll_cpucl", mout_pll_cpucl_p, PLL_CON0_PLL_CPUCL, 4, 1, + CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0), + MUX(CLK_MOUT_CPUCL_SWITCH_USER, "mout_clkcmu_cpucl_switch_user", + mout_clkcmu_cpucl_switch_user_p, PLL_CON0_MUX_CLKCMU_CPUCL_SWITCH_USER, 4, 1), + MUX_F(CLK_MOUT_CPUCL_PLL, "mout_clk_cpucl_pll", mout_clk_cpucl_pll_p, + CLK_CON_MUX_CLK_CPUCL_PLL, 0, 1, CLK_SET_RATE_PARENT, 0), +}; + +static const struct samsung_fixed_factor_clock cpucl_ffactor_clks[] __initconst = { + FFACTOR(CLK_DOUT_CPUCL_CPU, "dout_clk_cpucl_cpu", + "mout_clk_cpucl_pll", 1, 1, CLK_SET_RATE_PARENT), +}; + +static const struct samsung_div_clock cmu_cpucl_div_clks[] __initconst = { + DIV(CLK_DOUT_CPUCL_CLUSTER_ACLK, "dout_clk_cluster_aclk", + "dout_clk_cpucl_cpu", CLK_CON_DIV_CLK_CLUSTER_ACLK, 0, 4), + DIV(CLK_DOUT_CPUCL_CLUSTER_PCLKDBG, "dout_clk_cluster_pclkdbg", + "dout_clk_cpucl_cpu", CLK_CON_DIV_CLK_CLUSTER_PCLKDBG, 0, 4), + DIV(CLK_DOUT_CPUCL_CLUSTER_CNTCLK, "dout_clk_cluster_cntclk", + "dout_clk_cpucl_cpu", CLK_CON_DIV_CLK_CLUSTER_CNTCLK, 0, 4), + DIV(CLK_DOUT_CPUCL_CLUSTER_ATCLK, "dout_clk_cluster_atclk", + "dout_clk_cpucl_cpu", CLK_CON_DIV_CLK_CLUSTER_ATCLK, 0, 4), + DIV(CLK_DOUT_CPUCL_PCLK, "dout_clk_cpucl_pclk", + "dout_clk_cpucl_cpu", CLK_CON_DIV_CLK_CPUCL_PCLK, 0, 4), + DIV(CLK_DOUT_CPUCL_CMUREF, "dout_clk_cpucl_cmuref", + "dout_clk_cpucl_cpu", CLK_CON_DIV_CLK_CPUCL_CMUREF, 0, 3), + DIV(CLK_DOUT_CPUCL_DBG, "dout_clk_cpucl_dbg", + "dout_clk_cpucl_cpu", CLK_CON_DIV_CLK_CPUCL_DBG, 0, 4), + DIV(CLK_DOUT_CPUCL_PCLKDBG, "dout_clk_cpucl_pclkdbg", + "dout_clk_cpucl_dbg", CLK_CON_DIV_CLK_CPUCL_PCLKDBG, 0, 4), +}; + +static const struct samsung_gate_clock cmu_cpucl_gate_clks[] __initconst = { + GATE(CLK_GOUT_CPUCL_CLUSTER_CPU, "clk_con_gat_clk_cluster_cpu", + "clk_con_gat_clk_cpucl_shortstop", CLK_CON_GAT_CLK_CLUSTER_CPU, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_CPUCL_SHORTSTOP, "clk_con_gat_clk_cpucl_shortstop", + "dout_clk_cpucl_cpu", CLK_CON_GAT_CLK_CPUCL_SHORTSTOP, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_CPUCL_CSSYS_IPCLKPORT_PCLKDBG, "cssys_ipclkport_pclkdbg", + "dout_clk_cpucl_pclkdbg", CLK_CON_DMYQCH_CON_CSSYS_QCH, 1, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_CPUCL_CSSYS_IPCLKPORT_ATCLK, "cssys_ipclkport_atclk", + "dout_clk_cpucl_dbg", CLK_CON_DMYQCH_CON_CSSYS_QCH, 1, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), +}; + +static const struct samsung_cmu_info cmu_cpucl_info __initconst = { + .pll_clks = cmu_cpucl_pll_clks, + .nr_pll_clks = ARRAY_SIZE(cmu_cpucl_pll_clks), + .fixed_factor_clks = cpucl_ffactor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(cpucl_ffactor_clks), + .mux_clks = cmu_cpucl_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cmu_cpucl_mux_clks), + .div_clks = cmu_cpucl_div_clks, + .nr_div_clks = ARRAY_SIZE(cmu_cpucl_div_clks), + .gate_clks = cmu_cpucl_gate_clks, + .nr_gate_clks = ARRAY_SIZE(cmu_cpucl_gate_clks), + .nr_clk_ids = CMU_CPUCL_NR_CLK, + .clk_regs = cmu_cpucl_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cmu_cpucl_clk_regs), +}; + +/* Register Offset definitions for CMU_FSYS (0x16c10000) */ +#define PLL_LOCKTIME_PLL_FSYS 0x0004 +#define PLL_CON0_MUX_CLK_FSYS_BUS_USER 0x0120 +#define PLL_CON0_MUX_CLK_FSYS_MMC_USER 0x0140 +#define PLL_CON0_MUX_CLK_FSYS_SCAN0_USER 0x0160 +#define PLL_CON0_MUX_CLK_FSYS_SCAN1_USER 0x0180 +#define PLL_CON0_PLL_FSYS 0x01c0 +#define CLK_CON_DIV_CLK_FSYS_ADC 0x1804 +#define CLK_CON_DIV_CLK_FSYS_BUS300 0x1808 +#define CLK_CON_DIV_CLK_FSYS_BUS_QSPI 0x180c +#define CLK_CON_DIV_CLK_FSYS_EQOS_25 0x1810 +#define CLK_CON_DIV_CLK_FSYS_EQOS_2P5 0x1814 +#define CLK_CON_DIV_CLK_FSYS_EQOS_500 0x1818 +#define CLK_CON_DIV_CLK_FSYS_EQOS_INT125 0x181c +#define CLK_CON_DIV_CLK_FSYS_MMC_CARD0 0x1820 +#define CLK_CON_DIV_CLK_FSYS_MMC_CARD1 0x1824 +#define CLK_CON_DIV_CLK_FSYS_OTP_MEM 0x1828 +#define CLK_CON_DIV_CLK_FSYS_PCIE_PHY_REFCLK_SYSPLL 0x182c +#define CLK_CON_DIV_CLK_FSYS_QSPI 0x1830 +#define CLK_CON_DIV_CLK_FSYS_SCLK_UART 0x1834 +#define CLK_CON_DIV_CLK_FSYS_SFMC_NAND 0x1838 +#define CLK_CON_DIV_SCAN_CLK_FSYS_125 0x183c +#define CLK_CON_DIV_SCAN_CLK_FSYS_MMC 0x1840 +#define CLK_CON_DIV_SCAN_CLK_FSYS_PCIE_PIPE 0x1844 +#define CLK_CON_FSYS_I2C0_IPCLKPORT_I_PCLK 0x2044 +#define CLK_CON_FSYS_I2C1_IPCLKPORT_I_PCLK 0x2048 +#define CLK_CON_FSYS_UART0_IPCLKPORT_I_PCLK 0x204c +#define CLK_CON_FSYS_UART0_IPCLKPORT_I_SCLK_UART 0x2050 +#define CLK_CON_MMC0_IPCLKPORT_I_ACLK 0x2070 +#define CLK_CON_MMC1_IPCLKPORT_I_ACLK 0x2078 +#define CLK_CON_DWC_PCIE_CTL_INST_0_DBI_ACLK_UG 0x208c +#define CLK_CON_DWC_PCIE_CTL_INST_0_MSTR_ACLK_UG 0x2090 +#define CLK_CON_DWC_PCIE_CTL_INST_0_SLV_ACLK_UG 0x2094 +#define CLK_CON_PWM_IPCLKPORT_I_PCLK_S0 0x20a0 +#define CLK_CON_USB20DRD_IPCLKPORT_ACLK_PHYCTRL_20 0x20bc +#define CLK_CON_USB20DRD_IPCLKPORT_BUS_CLK_EARLY 0x20c0 +#define CLK_CON_XHB_AHBBR_IPCLKPORT_CLK 0x20c4 +#define CLK_CON_XHB_USB_IPCLKPORT_CLK 0x20cc +#define CLK_CON_BUS_P_FSYS_IPCLKPORT_QSPICLK 0x201c +#define CLK_CON_DMYQCH_CON_EQOS_TOP_QCH 0x3008 +#define CLK_CON_DMYQCH_CON_MMC0_QCH 0x300c +#define CLK_CON_DMYQCH_CON_MMC1_QCH 0x3010 +#define CLK_CON_DMYQCH_CON_PCIE_TOP_QCH 0x3018 +#define CLK_CON_DMYQCH_CON_PCIE_TOP_QCH_REF 0x301c +#define CLK_CON_DMYQCH_CON_QSPI_QCH 0x3020 +#define CLK_CON_DMYQCH_CON_SFMC_QCH 0x3024 + +static const unsigned long cmu_fsys_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_FSYS, + PLL_CON0_MUX_CLK_FSYS_BUS_USER, + PLL_CON0_MUX_CLK_FSYS_MMC_USER, + PLL_CON0_MUX_CLK_FSYS_SCAN0_USER, + PLL_CON0_MUX_CLK_FSYS_SCAN1_USER, + PLL_CON0_PLL_FSYS, + CLK_CON_DIV_CLK_FSYS_ADC, + CLK_CON_DIV_CLK_FSYS_BUS300, + CLK_CON_DIV_CLK_FSYS_BUS_QSPI, + CLK_CON_DIV_CLK_FSYS_EQOS_25, + CLK_CON_DIV_CLK_FSYS_EQOS_2P5, + CLK_CON_DIV_CLK_FSYS_EQOS_500, + CLK_CON_DIV_CLK_FSYS_EQOS_INT125, + CLK_CON_DIV_CLK_FSYS_MMC_CARD0, + CLK_CON_DIV_CLK_FSYS_MMC_CARD1, + CLK_CON_DIV_CLK_FSYS_OTP_MEM, + CLK_CON_DIV_CLK_FSYS_PCIE_PHY_REFCLK_SYSPLL, + CLK_CON_DIV_CLK_FSYS_QSPI, + CLK_CON_DIV_CLK_FSYS_SCLK_UART, + CLK_CON_DIV_CLK_FSYS_SFMC_NAND, + CLK_CON_DIV_SCAN_CLK_FSYS_125, + CLK_CON_DIV_SCAN_CLK_FSYS_MMC, + CLK_CON_DIV_SCAN_CLK_FSYS_PCIE_PIPE, + CLK_CON_FSYS_I2C0_IPCLKPORT_I_PCLK, + CLK_CON_FSYS_I2C1_IPCLKPORT_I_PCLK, + CLK_CON_FSYS_UART0_IPCLKPORT_I_PCLK, + CLK_CON_FSYS_UART0_IPCLKPORT_I_SCLK_UART, + CLK_CON_MMC0_IPCLKPORT_I_ACLK, + CLK_CON_MMC1_IPCLKPORT_I_ACLK, + CLK_CON_DWC_PCIE_CTL_INST_0_DBI_ACLK_UG, + CLK_CON_DWC_PCIE_CTL_INST_0_MSTR_ACLK_UG, + CLK_CON_DWC_PCIE_CTL_INST_0_SLV_ACLK_UG, + CLK_CON_PWM_IPCLKPORT_I_PCLK_S0, + CLK_CON_USB20DRD_IPCLKPORT_ACLK_PHYCTRL_20, + CLK_CON_USB20DRD_IPCLKPORT_BUS_CLK_EARLY, + CLK_CON_XHB_AHBBR_IPCLKPORT_CLK, + CLK_CON_XHB_USB_IPCLKPORT_CLK, + CLK_CON_BUS_P_FSYS_IPCLKPORT_QSPICLK, + CLK_CON_DMYQCH_CON_EQOS_TOP_QCH, + CLK_CON_DMYQCH_CON_MMC0_QCH, + CLK_CON_DMYQCH_CON_MMC1_QCH, + CLK_CON_DMYQCH_CON_PCIE_TOP_QCH, + CLK_CON_DMYQCH_CON_PCIE_TOP_QCH_REF, + CLK_CON_DMYQCH_CON_QSPI_QCH, + CLK_CON_DMYQCH_CON_SFMC_QCH, +}; + +static const struct samsung_pll_clock cmu_fsys_pll_clks[] __initconst = { + PLL(pll_1017x, CLK_FOUT_FSYS_PLL, "fout_pll_fsys", "fin_pll", + PLL_LOCKTIME_PLL_FSYS, PLL_CON0_PLL_FSYS, NULL), +}; + +PNAME(mout_fsys_scan0_user_p) = { "fin_pll", "dout_clkcmu_fsys_scan0" }; +PNAME(mout_fsys_scan1_user_p) = { "fin_pll", "dout_clkcmu_fsys_scan1" }; +PNAME(mout_fsys_bus_user_p) = { "fin_pll", "dout_clkcmu_fsys_bus" }; +PNAME(mout_fsys_mmc_user_p) = { "fin_pll", "dout_clkcmu_fsys_ip" }; +PNAME(mout_fsys_pll_fsys_p) = { "fin_pll", "fout_pll_fsys" }; + +static const struct samsung_mux_clock cmu_fsys_mux_clks[] __initconst = { + MUX(0, "mout_clk_pll_fsys", mout_fsys_pll_fsys_p, PLL_CON0_PLL_FSYS, 4, 1), + MUX(CLK_MOUT_FSYS_SCAN0_USER, "mout_fsys_scan0_user", + mout_fsys_scan0_user_p, PLL_CON0_MUX_CLK_FSYS_SCAN0_USER, 4, 1), + MUX(CLK_MOUT_FSYS_SCAN1_USER, "mout_fsys_scan1_user", + mout_fsys_scan1_user_p, PLL_CON0_MUX_CLK_FSYS_SCAN1_USER, 4, 1), + MUX(CLK_MOUT_FSYS_BUS_USER, "mout_fsys_bus_user", + mout_fsys_bus_user_p, PLL_CON0_MUX_CLK_FSYS_BUS_USER, 4, 1), + MUX(CLK_MOUT_FSYS_MMC_USER, "mout_fsys_mmc_user", + mout_fsys_mmc_user_p, PLL_CON0_MUX_CLK_FSYS_MMC_USER, 4, 1), +}; + +static const struct samsung_div_clock cmu_fsys_div_clks[] __initconst = { + DIV(CLK_DOUT_FSYS_PCIE_PIPE, "dout_fsys_pcie_pipe", "mout_clk_pll_fsys", + CLK_CON_DIV_SCAN_CLK_FSYS_PCIE_PIPE, 0, 4), + DIV(CLK_DOUT_FSYS_ADC, "dout_fsys_adc", "mout_clk_pll_fsys", + CLK_CON_DIV_CLK_FSYS_ADC, 0, 7), + DIV(CLK_DOUT_FSYS_PCIE_PHY_REFCLK_SYSPLL, "dout_fsys_pcie_phy_refclk_syspll", + "mout_clk_pll_fsys", CLK_CON_DIV_CLK_FSYS_PCIE_PHY_REFCLK_SYSPLL, 0, 8), + DIV(CLK_DOUT_FSYS_QSPI, "dout_fsys_qspi", "mout_fsys_mmc_user", + CLK_CON_DIV_CLK_FSYS_QSPI, 0, 4), + DIV(CLK_DOUT_FSYS_EQOS_INT125, "dout_fsys_eqos_int125", "mout_clk_pll_fsys", + CLK_CON_DIV_CLK_FSYS_EQOS_INT125, 0, 4), + DIV(CLK_DOUT_FSYS_OTP_MEM, "dout_fsys_otp_mem", "fin_pll", + CLK_CON_DIV_CLK_FSYS_OTP_MEM, 0, 9), + DIV(CLK_DOUT_FSYS_SCLK_UART, "dout_fsys_sclk_uart", "mout_clk_pll_fsys", + CLK_CON_DIV_CLK_FSYS_SCLK_UART, 0, 10), + DIV(CLK_DOUT_FSYS_SFMC_NAND, "dout_fsys_sfmc_nand", "mout_fsys_mmc_user", + CLK_CON_DIV_CLK_FSYS_SFMC_NAND, 0, 4), + DIV(CLK_DOUT_SCAN_CLK_FSYS_125, "dout_scan_clk_fsys_125", "mout_clk_pll_fsys", + CLK_CON_DIV_SCAN_CLK_FSYS_125, 0, 4), + DIV(CLK_DOUT_FSYS_SCAN_CLK_MMC, "dout_scan_clk_fsys_mmc", "fout_pll_fsys", + CLK_CON_DIV_SCAN_CLK_FSYS_MMC, 0, 4), + DIV(CLK_DOUT_FSYS_EQOS_25, "dout_fsys_eqos_25", "dout_fsys_eqos_int125", + CLK_CON_DIV_CLK_FSYS_EQOS_25, 0, 4), + DIV_F(CLK_DOUT_FSYS_EQOS_2p5, "dout_fsys_eqos_2p5", "dout_fsys_eqos_25", + CLK_CON_DIV_CLK_FSYS_EQOS_2P5, 0, 4, CLK_SET_RATE_PARENT, 0), + DIV(0, "dout_fsys_eqos_500", "mout_clk_pll_fsys", + CLK_CON_DIV_CLK_FSYS_EQOS_500, 0, 4), + DIV(CLK_DOUT_FSYS_BUS300, "dout_fsys_bus300", "mout_fsys_bus_user", + CLK_CON_DIV_CLK_FSYS_BUS300, 0, 4), + DIV(CLK_DOUT_FSYS_BUS_QSPI, "dout_fsys_bus_qspi", "mout_fsys_mmc_user", + CLK_CON_DIV_CLK_FSYS_BUS_QSPI, 0, 4), + DIV(CLK_DOUT_FSYS_MMC_CARD0, "dout_fsys_mmc_card0", "mout_fsys_mmc_user", + CLK_CON_DIV_CLK_FSYS_MMC_CARD0, 0, 10), + DIV(CLK_DOUT_FSYS_MMC_CARD1, "dout_fsys_mmc_card1", "mout_fsys_mmc_user", + CLK_CON_DIV_CLK_FSYS_MMC_CARD1, 0, 10), +}; + +static const struct samsung_gate_clock cmu_fsys_gate_clks[] __initconst = { + GATE(CLK_GOUT_FSYS_PCIE_PHY_REFCLK_IN, "pcie_sub_ctrl_inst_0_phy_refclk_in", + "dout_fsys_pcie_phy_refclk_syspll", CLK_CON_DMYQCH_CON_PCIE_TOP_QCH_REF, 1, + CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS_EQOS_TOP_IPCLKPORT_I_RGMII_TXCLK_2P5, + "eqos_top_ipclkport_i_rgmii_txclk_2p5", + "dout_fsys_eqos_2p5", CLK_CON_DMYQCH_CON_EQOS_TOP_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS_EQOS_TOP_IPCLKPORT_ACLK_I, "eqos_top_ipclkport_aclk_i", + "dout_fsys_bus300", CLK_CON_DMYQCH_CON_EQOS_TOP_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS_EQOS_TOP_IPCLKPORT_CLK_CSR_I, "eqos_top_ipclkport_clk_csr_i", + "dout_fsys_bus300", CLK_CON_DMYQCH_CON_EQOS_TOP_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS_PIPE_PAL_INST_0_I_APB_PCLK, "pipe_pal_inst_0_i_apb_pclk", + "dout_fsys_bus300", CLK_CON_DMYQCH_CON_PCIE_TOP_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS_QSPI_IPCLKPORT_HCLK, "qspi_ipclkport_hclk", + "dout_fsys_bus_qspi", CLK_CON_DMYQCH_CON_QSPI_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS_QSPI_IPCLKPORT_SSI_CLK, "qspi_ipclkport_ssi_clk", + "dout_fsys_qspi", CLK_CON_DMYQCH_CON_QSPI_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS_MMC0_IPCLKPORT_SDCLKIN, "mmc0_ipclkport_sdclkin", + "dout_fsys_mmc_card0", CLK_CON_DMYQCH_CON_MMC0_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS_MMC1_IPCLKPORT_SDCLKIN, "mmc1_ipclkport_sdclkin", + "dout_fsys_mmc_card1", CLK_CON_DMYQCH_CON_MMC1_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS_SFMC_IPCLKPORT_I_ACLK_NAND, "sfmc_ipclkport_i_aclk_nand", + "dout_fsys_sfmc_nand", CLK_CON_DMYQCH_CON_SFMC_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS_UART0_SCLK_UART, "uart0_sclk", "dout_fsys_sclk_uart", + CLK_CON_FSYS_UART0_IPCLKPORT_I_SCLK_UART, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_DWC_PCIE_CTL_INST_0_MSTR_ACLK_UG, "dwc_pcie_ctl_inst_0_mstr_aclk_ug", + "mout_fsys_bus_user", CLK_CON_DWC_PCIE_CTL_INST_0_MSTR_ACLK_UG, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_DWC_PCIE_CTL_INXT_0_SLV_ACLK_UG, "dwc_pcie_ctl_inst_0_slv_aclk_ug", + "mout_fsys_bus_user", CLK_CON_DWC_PCIE_CTL_INST_0_SLV_ACLK_UG, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_I2C0_IPCLKPORT_I_PCLK, "fsys_i2c0_ipclkport_i_pclk", "dout_fsys_bus300", + CLK_CON_FSYS_I2C0_IPCLKPORT_I_PCLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_I2C1_IPCLKPORT_I_PCLK, "fsys_i2c1_ipclkport_i_pclk", "dout_fsys_bus300", + CLK_CON_FSYS_I2C1_IPCLKPORT_I_PCLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_UART0_PCLK, "uart0_pclk", "dout_fsys_bus300", + CLK_CON_FSYS_UART0_IPCLKPORT_I_PCLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_MMC0_IPCLKPORT_I_ACLK, "mmc0_ipclkport_i_aclk", "dout_fsys_bus300", + CLK_CON_MMC0_IPCLKPORT_I_ACLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_MMC1_IPCLKPORT_I_ACLK, "mmc1_ipclkport_i_aclk", "dout_fsys_bus300", + CLK_CON_MMC1_IPCLKPORT_I_ACLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_DWC_PCIE_CTL_INST_0_DBI_ACLK_UG, "dwc_pcie_ctl_inst_0_dbi_aclk_ug", + "dout_fsys_bus300", CLK_CON_DWC_PCIE_CTL_INST_0_DBI_ACLK_UG, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_PWM_IPCLKPORT_I_PCLK_S0, "pwm_ipclkport_i_pclk_s0", "dout_fsys_bus300", + CLK_CON_PWM_IPCLKPORT_I_PCLK_S0, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_USB20DRD_IPCLKPORT_ACLK_PHYCTRL_20, "usb20drd_ipclkport_aclk_phyctrl_20", + "dout_fsys_bus300", CLK_CON_USB20DRD_IPCLKPORT_ACLK_PHYCTRL_20, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_USB20DRD_IPCLKPORT_BUS_CLK_EARLY, "usb20drd_ipclkport_bus_clk_early", + "dout_fsys_bus300", CLK_CON_USB20DRD_IPCLKPORT_BUS_CLK_EARLY, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_XHB_AHBBR_IPCLKPORT_CLK, "xhb_ahbbr_ipclkport_clk", "dout_fsys_bus300", + CLK_CON_XHB_AHBBR_IPCLKPORT_CLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_XHB_USB_IPCLKPORT_CLK, "xhb_usb_ipclkport_clk", "dout_fsys_bus300", + CLK_CON_XHB_USB_IPCLKPORT_CLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS_BUS_QSPI, "bus_p_fsys_ipclkport_qspiclk", "dout_fsys_bus_qspi", + CLK_CON_BUS_P_FSYS_IPCLKPORT_QSPICLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), +}; + +static const struct samsung_cmu_info cmu_fsys_info __initconst = { + .pll_clks = cmu_fsys_pll_clks, + .nr_pll_clks = ARRAY_SIZE(cmu_fsys_pll_clks), + .mux_clks = cmu_fsys_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cmu_fsys_mux_clks), + .div_clks = cmu_fsys_div_clks, + .nr_div_clks = ARRAY_SIZE(cmu_fsys_div_clks), + .gate_clks = cmu_fsys_gate_clks, + .nr_gate_clks = ARRAY_SIZE(cmu_fsys_gate_clks), + .nr_clk_ids = CMU_FSYS_NR_CLK, + .clk_regs = cmu_fsys_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cmu_fsys_clk_regs), +}; + +/* Register Offset definitions for CMU_IMEM (0x10010000) */ +#define PLL_CON0_MUX_CLK_IMEM_ACLK_USER 0x0100 +#define PLL_CON0_MUX_CLK_IMEM_JPEG_USER 0x0120 +#define CLK_CON_MUX_CLK_IMEM_GIC_CA53 0x1000 +#define CLK_CON_MUX_CLK_IMEM_GIC_CA5 0x1008 +#define CLK_CON_MCT_IPCLKPORT_PCLK 0x2038 +#define CLK_CON_SFRIF_TMU_IMEM_IPCLKPORT_PCLK 0x2044 + +static const unsigned long cmu_imem_clk_regs[] __initconst = { + PLL_CON0_MUX_CLK_IMEM_ACLK_USER, + PLL_CON0_MUX_CLK_IMEM_JPEG_USER, + CLK_CON_MUX_CLK_IMEM_GIC_CA53, + CLK_CON_MUX_CLK_IMEM_GIC_CA5, + CLK_CON_MCT_IPCLKPORT_PCLK, + CLK_CON_SFRIF_TMU_IMEM_IPCLKPORT_PCLK, +}; + +PNAME(mout_imem_aclk_user_p) = { "fin_pll", "dout_clkcmu_imem_aclk" }; +PNAME(mout_imem_gic_ca53_p) = { "mout_imem_aclk_user", "fin_pll" }; +PNAME(mout_imem_gic_ca5_p) = { "mout_imem_aclk_user", "fin_pll" }; +PNAME(mout_imem_jpeg_user_p) = { "fin_pll", "dout_clkcmu_imem_jpeg" }; + +static const struct samsung_mux_clock cmu_imem_mux_clks[] __initconst = { + MUX(CLK_MOUT_IMEM_ACLK_USER, "mout_imem_aclk_user", + mout_imem_aclk_user_p, PLL_CON0_MUX_CLK_IMEM_ACLK_USER, 4, 1), + MUX(CLK_MOUT_IMEM_GIC_CA53, "mout_imem_gic_ca53", + mout_imem_gic_ca53_p, CLK_CON_MUX_CLK_IMEM_GIC_CA53, 0, 1), + MUX(CLK_MOUT_IMEM_GIC_CA5, "mout_imem_gic_ca5", + mout_imem_gic_ca5_p, CLK_CON_MUX_CLK_IMEM_GIC_CA5, 0, 1), + MUX(CLK_MOUT_IMEM_JPEG_USER, "mout_imem_jpeg_user", + mout_imem_jpeg_user_p, PLL_CON0_MUX_CLK_IMEM_JPEG_USER, 4, 1), +}; + +static const struct samsung_gate_clock cmu_imem_gate_clks[] __initconst = { + GATE(CLK_GOUT_IMEM_MCT_PCLK, "mct_pclk", "mout_imem_aclk_user", + CLK_CON_MCT_IPCLKPORT_PCLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_IMEM_PCLK_TMU0_APBIF, "sfrif_tmu_imem_ipclkport_pclk", "mout_imem_aclk_user", + CLK_CON_SFRIF_TMU_IMEM_IPCLKPORT_PCLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), +}; + +static const struct samsung_cmu_info cmu_imem_info __initconst = { + .mux_clks = cmu_imem_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cmu_imem_mux_clks), + .gate_clks = cmu_imem_gate_clks, + .nr_gate_clks = ARRAY_SIZE(cmu_imem_gate_clks), + .nr_clk_ids = CMU_IMEM_NR_CLK, + .clk_regs = cmu_imem_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cmu_imem_clk_regs), +}; + +static void __init artpec8_clk_cmu_imem_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &cmu_imem_info); +} + +CLK_OF_DECLARE(artpec8_clk_cmu_imem, "axis,artpec8-cmu-imem", artpec8_clk_cmu_imem_init); + +/* Register Offset definitions for CMU_PERI (0x16410000) */ +#define PLL_CON0_MUX_CLK_PERI_AUDIO_USER 0x0100 +#define PLL_CON0_MUX_CLK_PERI_DISP_USER 0x0120 +#define PLL_CON0_MUX_CLK_PERI_IP_USER 0x0140 +#define CLK_CON_MUX_CLK_PERI_I2S0 0x1000 +#define CLK_CON_MUX_CLK_PERI_I2S1 0x1004 +#define CLK_CON_DIV_CLK_PERI_DSIM 0x1800 +#define CLK_CON_DIV_CLK_PERI_I2S0 0x1804 +#define CLK_CON_DIV_CLK_PERI_I2S1 0x1808 +#define CLK_CON_DIV_CLK_PERI_PCLK 0x180c +#define CLK_CON_DIV_CLK_PERI_SPI 0x1810 +#define CLK_CON_DIV_CLK_PERI_UART1 0x1814 +#define CLK_CON_DIV_CLK_PERI_UART2 0x1818 +#define CLK_CON_APB_ASYNC_DSIM_IPCLKPORT_PCLKS 0x2004 +#define CLK_CON_PERI_I2C2_IPCLKPORT_I_PCLK 0x2030 +#define CLK_CON_PERI_I2C3_IPCLKPORT_I_PCLK 0x2034 +#define CLK_CON_PERI_SPI0_IPCLKPORT_I_PCLK 0x2048 +#define CLK_CON_PERI_SPI0_IPCLKPORT_I_SCLK_SPI 0x204c +#define CLK_CON_PERI_UART1_IPCLKPORT_I_PCLK 0x2050 +#define CLK_CON_PERI_UART1_IPCLKPORT_I_SCLK_UART 0x2054 +#define CLK_CON_PERI_UART2_IPCLKPORT_I_PCLK 0x2058 +#define CLK_CON_PERI_UART2_IPCLKPORT_I_SCLK_UART 0x205c +#define CLK_CON_DMYQCH_CON_AUDIO_OUT_QCH 0x3000 +#define CLK_CON_DMYQCH_CON_DMA4DSIM_QCH 0x3004 +#define CLK_CON_DMYQCH_CON_PERI_I2SSC0_QCH 0x3008 +#define CLK_CON_DMYQCH_CON_PERI_I2SSC1_QCH 0x300c + +static const unsigned long cmu_peri_clk_regs[] __initconst = { + PLL_CON0_MUX_CLK_PERI_AUDIO_USER, + PLL_CON0_MUX_CLK_PERI_DISP_USER, + PLL_CON0_MUX_CLK_PERI_IP_USER, + CLK_CON_MUX_CLK_PERI_I2S0, + CLK_CON_MUX_CLK_PERI_I2S1, + CLK_CON_DIV_CLK_PERI_DSIM, + CLK_CON_DIV_CLK_PERI_I2S0, + CLK_CON_DIV_CLK_PERI_I2S1, + CLK_CON_DIV_CLK_PERI_PCLK, + CLK_CON_DIV_CLK_PERI_SPI, + CLK_CON_DIV_CLK_PERI_UART1, + CLK_CON_DIV_CLK_PERI_UART2, + CLK_CON_APB_ASYNC_DSIM_IPCLKPORT_PCLKS, + CLK_CON_PERI_I2C2_IPCLKPORT_I_PCLK, + CLK_CON_PERI_I2C3_IPCLKPORT_I_PCLK, + CLK_CON_PERI_SPI0_IPCLKPORT_I_PCLK, + CLK_CON_PERI_SPI0_IPCLKPORT_I_SCLK_SPI, + CLK_CON_PERI_UART1_IPCLKPORT_I_PCLK, + CLK_CON_PERI_UART1_IPCLKPORT_I_SCLK_UART, + CLK_CON_PERI_UART2_IPCLKPORT_I_PCLK, + CLK_CON_PERI_UART2_IPCLKPORT_I_SCLK_UART, + CLK_CON_DMYQCH_CON_AUDIO_OUT_QCH, + CLK_CON_DMYQCH_CON_DMA4DSIM_QCH, + CLK_CON_DMYQCH_CON_PERI_I2SSC0_QCH, + CLK_CON_DMYQCH_CON_PERI_I2SSC1_QCH, +}; + +static const struct samsung_fixed_rate_clock peri_fixed_clks[] __initconst = { + FRATE(0, "clk_peri_audio", NULL, 0, 100000000), +}; + +PNAME(mout_peri_ip_user_p) = { "fin_pll", "dout_clkcmu_peri_ip" }; +PNAME(mout_peri_audio_user_p) = { "fin_pll", "dout_clkcmu_peri_audio" }; +PNAME(mout_peri_disp_user_p) = { "fin_pll", "dout_clkcmu_peri_disp" }; +PNAME(mout_peri_i2s0_p) = { "dout_peri_i2s0", "clk_peri_audio" }; +PNAME(mout_peri_i2s1_p) = { "dout_peri_i2s1", "clk_peri_audio" }; + +static const struct samsung_mux_clock cmu_peri_mux_clks[] __initconst = { + MUX(CLK_MOUT_PERI_IP_USER, "mout_peri_ip_user", mout_peri_ip_user_p, + PLL_CON0_MUX_CLK_PERI_IP_USER, 4, 1), + MUX(CLK_MOUT_PERI_AUDIO_USER, "mout_peri_audio_user", + mout_peri_audio_user_p, PLL_CON0_MUX_CLK_PERI_AUDIO_USER, 4, 1), + MUX(CLK_MOUT_PERI_DISP_USER, "mout_peri_disp_user", mout_peri_disp_user_p, + PLL_CON0_MUX_CLK_PERI_DISP_USER, 4, 1), + MUX(CLK_MOUT_PERI_I2S0, "mout_peri_i2s0", mout_peri_i2s0_p, + CLK_CON_MUX_CLK_PERI_I2S0, 0, 1), + MUX(CLK_MOUT_PERI_I2S1, "mout_peri_i2s1", mout_peri_i2s1_p, + CLK_CON_MUX_CLK_PERI_I2S1, 0, 1), +}; + +static const struct samsung_div_clock cmu_peri_div_clks[] __initconst = { + DIV(CLK_DOUT_PERI_SPI, "dout_peri_spi", "mout_peri_ip_user", + CLK_CON_DIV_CLK_PERI_SPI, 0, 10), + DIV(CLK_DOUT_PERI_UART1, "dout_peri_uart1", "mout_peri_ip_user", + CLK_CON_DIV_CLK_PERI_UART1, 0, 10), + DIV(CLK_DOUT_PERI_UART2, "dout_peri_uart2", "mout_peri_ip_user", + CLK_CON_DIV_CLK_PERI_UART2, 0, 10), + DIV(CLK_DOUT_PERI_PCLK, "dout_peri_pclk", "mout_peri_ip_user", + CLK_CON_DIV_CLK_PERI_PCLK, 0, 4), + DIV(CLK_DOUT_PERI_I2S0, "dout_peri_i2s0", "mout_peri_audio_user", + CLK_CON_DIV_CLK_PERI_I2S0, 0, 4), + DIV(CLK_DOUT_PERI_I2S1, "dout_peri_i2s1", "mout_peri_audio_user", + CLK_CON_DIV_CLK_PERI_I2S1, 0, 4), + DIV(CLK_DOUT_PERI_DSIM, "dout_peri_dsim", "mout_peri_disp_user", + CLK_CON_DIV_CLK_PERI_DSIM, 0, 4), +}; + +static const struct samsung_gate_clock cmu_peri_gate_clks[] __initconst = { + GATE(CLK_GOUT_PERI_DMA4DSIM_IPCLKPORT_CLK_APB_CLK, "dma4dsim_ipclkport_clk_apb_clk", + "dout_peri_pclk", CLK_CON_DMYQCH_CON_DMA4DSIM_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_PERI_I2SSC0_IPCLKPORT_CLK_HST, "i2ssc0_ipclkport_clk_hst", "dout_peri_pclk", + CLK_CON_DMYQCH_CON_PERI_I2SSC0_QCH, 1, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_PERI_I2SSC1_IPCLKPORT_CLK_HST, "i2ssc1_ipclkport_clk_hst", "dout_peri_pclk", + CLK_CON_DMYQCH_CON_PERI_I2SSC1_QCH, 1, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_PERI_AUDIO_OUT_IPCLKPORT_CLK, "audio_out_ipclkport_clk", + "mout_peri_audio_user", CLK_CON_DMYQCH_CON_AUDIO_OUT_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_PERI_I2SSC0_IPCLKPORT_CLK, "peri_i2ssc0_ipclkport_clk", "mout_peri_i2s0", + CLK_CON_DMYQCH_CON_PERI_I2SSC0_QCH, 1, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_PERI_I2SSC1_IPCLKPORT_CLK, "peri_i2ssc1_ipclkport_clk", "mout_peri_i2s1", + CLK_CON_DMYQCH_CON_PERI_I2SSC1_QCH, 1, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_PERI_DMA4DSIM_IPCLKPORT_CLK_AXI_CLK, "dma4dsim_ipclkport_clk_axi_clk", + "mout_peri_disp_user", CLK_CON_DMYQCH_CON_DMA4DSIM_QCH, 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_PERI_SPI0_SCLK_SPI, "peri_spi0_ipclkport_i_sclk_spi", "dout_peri_spi", + CLK_CON_PERI_SPI0_IPCLKPORT_I_SCLK_SPI, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERI_UART1_SCLK_UART, "uart1_sclk", "dout_peri_uart1", + CLK_CON_PERI_UART1_IPCLKPORT_I_SCLK_UART, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERI_UART2_SCLK_UART, "uart2_sclk", "dout_peri_uart2", + CLK_CON_PERI_UART2_IPCLKPORT_I_SCLK_UART, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERI_APB_ASYNC_DSIM_IPCLKPORT_PCLKS, "apb_async_dsim_ipclkport_pclks", + "dout_peri_pclk", CLK_CON_APB_ASYNC_DSIM_IPCLKPORT_PCLKS, 21, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERI_I2C2_IPCLKPORT_I_PCLK, "peri_i2c2_ipclkport_i_pclk", "dout_peri_pclk", + CLK_CON_PERI_I2C2_IPCLKPORT_I_PCLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERI_I2C3_IPCLKPORT_I_PCLK, "peri_i2c3_ipclkport_i_pclk", "dout_peri_pclk", + CLK_CON_PERI_I2C3_IPCLKPORT_I_PCLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERI_SPI0_PCLK, "peri_spi0_ipclkport_i_pclk", "dout_peri_pclk", + CLK_CON_PERI_SPI0_IPCLKPORT_I_PCLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERI_UART1_PCLK, "uart1_pclk", "dout_peri_pclk", + CLK_CON_PERI_UART1_IPCLKPORT_I_PCLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERI_UART2_PCLK, "uart2_pclk", "dout_peri_pclk", + CLK_CON_PERI_UART2_IPCLKPORT_I_PCLK, 21, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0), +}; + +static const struct samsung_cmu_info cmu_peri_info __initconst = { + .mux_clks = cmu_peri_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cmu_peri_mux_clks), + .div_clks = cmu_peri_div_clks, + .nr_div_clks = ARRAY_SIZE(cmu_peri_div_clks), + .gate_clks = cmu_peri_gate_clks, + .nr_gate_clks = ARRAY_SIZE(cmu_peri_gate_clks), + .fixed_clks = peri_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(peri_fixed_clks), + .nr_clk_ids = CMU_PERI_NR_CLK, + .clk_regs = cmu_peri_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cmu_peri_clk_regs), +}; + +/** + * artpec8_cmu_probe - Probe function for ARTPEC platform clocks + * @pdev: Pointer to platform device + * + * Configure clock hierarchy for clock domains of ARTPEC platform + */ +static int __init artpec8_cmu_probe(struct platform_device *pdev) +{ + const struct samsung_cmu_info *info; + struct device *dev = &pdev->dev; + + info = of_device_get_match_data(dev); + exynos_arm64_register_cmu(dev, dev->of_node, info); + + return 0; +} + +static const struct of_device_id artpec8_cmu_of_match[] = { + { + .compatible = "axis,artpec8-cmu-cmu", + .data = &cmu_cmu_info, + }, { + .compatible = "axis,artpec8-cmu-bus", + .data = &cmu_bus_info, + }, { + .compatible = "axis,artpec8-cmu-core", + .data = &cmu_core_info, + }, { + .compatible = "axis,artpec8-cmu-cpucl", + .data = &cmu_cpucl_info, + }, { + .compatible = "axis,artpec8-cmu-fsys", + .data = &cmu_fsys_info, + }, { + .compatible = "axis,artpec8-cmu-peri", + .data = &cmu_peri_info, + }, { + }, +}; + +static struct platform_driver artpec8_cmu_driver __refdata = { + .driver = { + .name = "artpec8-cmu", + .of_match_table = artpec8_cmu_of_match, + .suppress_bind_attrs = true, + }, + .probe = artpec8_cmu_probe, +}; + +static int __init artpec8_cmu_init(void) +{ + return platform_driver_register(&artpec8_cmu_driver); +} +core_initcall(artpec8_cmu_init); From 33d7ecbf69aa7dd4145e3b77962bcb8759eede3d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 29 Aug 2025 12:25:42 +0100 Subject: [PATCH 0716/2711] iio: frequency: adf4350: Fix prescaler usage. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADF4350/1 features a programmable dual-modulus prescaler of 4/5 or 8/9. When set to 4/5, the maximum RF frequency allowed is 3 GHz. Therefore, when operating the ADF4351 above 3 GHz, this must be set to 8/9. In this context not the RF output frequency is meant - it's the VCO frequency. Therefore move the prescaler selection after we derived the VCO frequency from the desired RF output frequency. This BUG may have caused PLL lock instabilities when operating the VCO at the very high range close to 4.4 GHz. Fixes: e31166f0fd48 ("iio: frequency: New driver for Analog Devices ADF4350/ADF4351 Wideband Synthesizers") Signed-off-by: Michael Hennerich Signed-off-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250829-adf4350-fix-v2-1-0bf543ba797d@analog.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/adf4350.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 47f1c7e9efa9..475a7a653bfb 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -149,6 +149,19 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq) if (freq > ADF4350_MAX_OUT_FREQ || freq < st->min_out_freq) return -EINVAL; + st->r4_rf_div_sel = 0; + + /* + * !\TODO: The below computation is making sure we get a power of 2 + * shift (st->r4_rf_div_sel) so that freq becomes higher or equal to + * ADF4350_MIN_VCO_FREQ. This might be simplified with fls()/fls_long() + * and friends. + */ + while (freq < ADF4350_MIN_VCO_FREQ) { + freq <<= 1; + st->r4_rf_div_sel++; + } + if (freq > ADF4350_MAX_FREQ_45_PRESC) { prescaler = ADF4350_REG1_PRESCALER; mdiv = 75; @@ -157,13 +170,6 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq) mdiv = 23; } - st->r4_rf_div_sel = 0; - - while (freq < ADF4350_MIN_VCO_FREQ) { - freq <<= 1; - st->r4_rf_div_sel++; - } - /* * Allow a predefined reference division factor * if not set, compute our own From 1d8fdabe19267338f29b58f968499e5b55e6a3b6 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 29 Aug 2025 12:25:43 +0100 Subject: [PATCH 0717/2711] iio: frequency: adf4350: Fix ADF4350_REG3_12BIT_CLKDIV_MODE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clk div bits (2 bits wide) do not start in bit 16 but in bit 15. Fix it accordingly. Fixes: e31166f0fd48 ("iio: frequency: New driver for Analog Devices ADF4350/ADF4351 Wideband Synthesizers") Signed-off-by: Michael Hennerich Signed-off-by: Nuno Sá Link: https://patch.msgid.link/20250829-adf4350-fix-v2-2-0bf543ba797d@analog.com Cc: Signed-off-by: Jonathan Cameron --- include/linux/iio/frequency/adf4350.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/iio/frequency/adf4350.h b/include/linux/iio/frequency/adf4350.h index de45cf2ee1e4..ce2086f97e3f 100644 --- a/include/linux/iio/frequency/adf4350.h +++ b/include/linux/iio/frequency/adf4350.h @@ -51,7 +51,7 @@ /* REG3 Bit Definitions */ #define ADF4350_REG3_12BIT_CLKDIV(x) ((x) << 3) -#define ADF4350_REG3_12BIT_CLKDIV_MODE(x) ((x) << 16) +#define ADF4350_REG3_12BIT_CLKDIV_MODE(x) ((x) << 15) #define ADF4350_REG3_12BIT_CSR_EN (1 << 18) #define ADF4351_REG3_CHARGE_CANCELLATION_EN (1 << 21) #define ADF4351_REG3_ANTI_BACKLASH_3ns_EN (1 << 22) From 5d5f08fd0cd970184376bee07d59f635c8403f63 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Fri, 29 Aug 2025 16:30:15 +0800 Subject: [PATCH 0718/2711] xtensa: simdisk: add input size check in proc_write_simdisk A malicious user could pass an arbitrarily bad value to memdup_user_nul(), potentially causing kernel crash. This follows the same pattern as commit ee76746387f6 ("netdevsim: prevent bad user input in nsim_dev_health_break_write()") Fixes: b6c7e873daf7 ("xtensa: ISS: add host file-based simulated disk") Fixes: 16e5c1fc3604 ("convert a bunch of open-coded instances of memdup_user_nul()") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Message-Id: <20250829083015.1992751-1-linmq006@gmail.com> Signed-off-by: Max Filippov --- arch/xtensa/platforms/iss/simdisk.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c index 6ed009318d24..3cafc8feddee 100644 --- a/arch/xtensa/platforms/iss/simdisk.c +++ b/arch/xtensa/platforms/iss/simdisk.c @@ -231,10 +231,14 @@ static ssize_t proc_read_simdisk(struct file *file, char __user *buf, static ssize_t proc_write_simdisk(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - char *tmp = memdup_user_nul(buf, count); + char *tmp; struct simdisk *dev = pde_data(file_inode(file)); int err; + if (count == 0 || count > PAGE_SIZE) + return -EINVAL; + + tmp = memdup_user_nul(buf, count); if (IS_ERR(tmp)) return PTR_ERR(tmp); From 0c4916aadb8df892399eec99f775655c31049195 Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Sat, 30 Aug 2025 12:33:52 +0530 Subject: [PATCH 0719/2711] phy: qcom-qmp-ufs: Add regulator load voting for UFS QMP PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On certain SoCs, power regulators are shared between the QMP UFS PHY and other IP blocks. To ensure proper operation, the regulator framework must be informed of the UFS PHY's load requirements. This is essential because the regulator's operating mode—whether Low Power or High Power—depends on the maximum expected load at any given time, which the regulator driver needs to manage accordingly. To support this, replace devm_regulator_bulk_get() with devm_regulator_bulk_get_const() and inline the qmp_ufs_vreg_init() function. additionally replace the array of regulator names with a bulk regulator data structure, and utilize the init_load_uA field provided by the regulator framework. This ensures that regulator_set_load() is automatically invoked before the first enable operation. Reviewed-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Signed-off-by: Nitin Rawat Link: https://lore.kernel.org/r/20250830070353.2694-2-nitin.rawat@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 29 +++++++------------------ 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 9c69c77d10c8..aaa88ca0ef07 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -1107,7 +1107,7 @@ struct qmp_phy_cfg { const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY]; /* regulators to be requested */ - const char * const *vreg_list; + const struct regulator_bulk_data *vreg_list; int num_vregs; /* array of registers with different offsets */ @@ -1164,9 +1164,10 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) readl(base + offset); } -/* list of regulators */ -static const char * const qmp_phy_vreg_l[] = { - "vdda-phy", "vdda-pll", +/* Default regulator bulk data (no load used) */ +static const struct regulator_bulk_data qmp_phy_vreg_l[] = { + { .supply = "vdda-phy" }, + { .supply = "vdda-pll" }, }; static const struct qmp_ufs_offsets qmp_ufs_offsets = { @@ -1890,22 +1891,6 @@ static const struct phy_ops qcom_qmp_ufs_phy_ops = { .owner = THIS_MODULE, }; -static int qmp_ufs_vreg_init(struct qmp_ufs *qmp) -{ - const struct qmp_phy_cfg *cfg = qmp->cfg; - struct device *dev = qmp->dev; - int num = cfg->num_vregs; - int i; - - qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); - if (!qmp->vregs) - return -ENOMEM; - - for (i = 0; i < num; i++) - qmp->vregs[i].supply = cfg->vreg_list[i]; - - return devm_regulator_bulk_get(dev, num, qmp->vregs); -} static int qmp_ufs_clk_init(struct qmp_ufs *qmp) { @@ -2068,7 +2053,9 @@ static int qmp_ufs_probe(struct platform_device *pdev) if (ret) return ret; - ret = qmp_ufs_vreg_init(qmp); + ret = devm_regulator_bulk_get_const(dev, qmp->cfg->num_vregs, + qmp->cfg->vreg_list, + &qmp->vregs); if (ret) return ret; From df4beac9da5f162770c8563d11cda327d748c20b Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Sat, 30 Aug 2025 12:33:53 +0530 Subject: [PATCH 0720/2711] phy: qcom-qmp-ufs: Add PHY and PLL regulator load Add phy and pll regulator load voting support for all supported platforms by introducing dedicated regulator bulk data arrays with their load values. This ensures stable operation and proper power management for these platforms where regulators are shared between the QMP UFS PHY and other IP blocks by setting appropriate regulator load currents during PHY operations. Signed-off-by: Nitin Rawat Acked-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20250830070353.2694-3-nitin.rawat@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 138 ++++++++++++++++++------ 1 file changed, 104 insertions(+), 34 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index aaa88ca0ef07..8a280433a42b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -1164,10 +1164,80 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) readl(base + offset); } -/* Default regulator bulk data (no load used) */ -static const struct regulator_bulk_data qmp_phy_vreg_l[] = { - { .supply = "vdda-phy" }, - { .supply = "vdda-pll" }, +/* Regulator bulk data with load values for specific configurations */ +static const struct regulator_bulk_data msm8996_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 51400 }, + { .supply = "vdda-pll", .init_load_uA = 14600 }, +}; + +static const struct regulator_bulk_data sa8775p_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 137000 }, + { .supply = "vdda-pll", .init_load_uA = 18300 }, +}; + +static const struct regulator_bulk_data sc7280_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 97500 }, + { .supply = "vdda-pll", .init_load_uA = 18400 }, +}; + +static const struct regulator_bulk_data sc8280xp_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 85700 }, + { .supply = "vdda-pll", .init_load_uA = 18300 }, +}; + +static const struct regulator_bulk_data sdm845_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 51400 }, + { .supply = "vdda-pll", .init_load_uA = 14600 }, +}; + +static const struct regulator_bulk_data sm6115_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 51400 }, + { .supply = "vdda-pll", .init_load_uA = 14200 }, +}; + +static const struct regulator_bulk_data sm7150_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 62900 }, + { .supply = "vdda-pll", .init_load_uA = 18300 }, +}; + +static const struct regulator_bulk_data sm8150_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 90200 }, + { .supply = "vdda-pll", .init_load_uA = 19000 }, +}; + +static const struct regulator_bulk_data sm8250_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 89900 }, + { .supply = "vdda-pll", .init_load_uA = 18800 }, +}; + +static const struct regulator_bulk_data sm8350_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 91600 }, + { .supply = "vdda-pll", .init_load_uA = 19000 }, +}; + +static const struct regulator_bulk_data sm8450_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 173000 }, + { .supply = "vdda-pll", .init_load_uA = 24900 }, +}; + +static const struct regulator_bulk_data sm8475_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 213030 }, + { .supply = "vdda-pll", .init_load_uA = 18340 }, +}; + +static const struct regulator_bulk_data sm8550_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 188000 }, + { .supply = "vdda-pll", .init_load_uA = 18300 }, +}; + +static const struct regulator_bulk_data sm8650_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 205000 }, + { .supply = "vdda-pll", .init_load_uA = 17500 }, +}; + +static const struct regulator_bulk_data sm8750_ufsphy_vreg_l[] = { + { .supply = "vdda-phy", .init_load_uA = 213000 }, + { .supply = "vdda-pll", .init_load_uA = 18300 }, }; static const struct qmp_ufs_offsets qmp_ufs_offsets = { @@ -1203,8 +1273,8 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = { .rx_num = ARRAY_SIZE(msm8996_ufsphy_rx), }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = msm8996_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(msm8996_ufsphy_vreg_l), .regs = ufsphy_v2_regs_layout, @@ -1240,8 +1310,8 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sa8775p_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sa8775p_ufsphy_vreg_l), .regs = ufsphy_v5_regs_layout, }; @@ -1274,8 +1344,8 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sc7280_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sc7280_ufsphy_vreg_l), .regs = ufsphy_v4_regs_layout, }; @@ -1308,8 +1378,8 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sc8280xp_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sc8280xp_ufsphy_vreg_l), .regs = ufsphy_v5_regs_layout, }; @@ -1333,8 +1403,8 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .serdes = sdm845_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sdm845_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sdm845_ufsphy_vreg_l), .regs = ufsphy_v3_regs_layout, .no_pcs_sw_reset = true, @@ -1360,8 +1430,8 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { .serdes = sm6115_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm6115_ufsphy_hs_b_serdes), }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm6115_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm6115_ufsphy_vreg_l), .regs = ufsphy_v2_regs_layout, .no_pcs_sw_reset = true, @@ -1387,8 +1457,8 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = { .serdes = sdm845_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm7150_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm7150_ufsphy_vreg_l), .regs = ufsphy_v3_regs_layout, .no_pcs_sw_reset = true, @@ -1423,8 +1493,8 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8150_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8150_ufsphy_vreg_l), .regs = ufsphy_v4_regs_layout, }; @@ -1457,8 +1527,8 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8250_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8250_ufsphy_vreg_l), .regs = ufsphy_v4_regs_layout, }; @@ -1491,8 +1561,8 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8350_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8350_ufsphy_vreg_l), .regs = ufsphy_v5_regs_layout, }; @@ -1525,8 +1595,8 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8450_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8450_ufsphy_vreg_l), .regs = ufsphy_v5_regs_layout, }; @@ -1561,8 +1631,8 @@ static const struct qmp_phy_cfg sm8475_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8475_ufsphy_g4_pcs), .max_gear = UFS_HS_G4, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8475_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8475_ufsphy_vreg_l), .regs = ufsphy_v6_regs_layout, }; @@ -1606,8 +1676,8 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = { .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g5_pcs), .max_gear = UFS_HS_G5, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8550_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8550_ufsphy_vreg_l), .regs = ufsphy_v6_regs_layout, }; @@ -1638,8 +1708,8 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = { .max_gear = UFS_HS_G5, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8650_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8650_ufsphy_vreg_l), .regs = ufsphy_v6_regs_layout, }; @@ -1676,8 +1746,8 @@ static const struct qmp_phy_cfg sm8750_ufsphy_cfg = { .max_gear = UFS_HS_G5, }, - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .vreg_list = sm8750_ufsphy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8750_ufsphy_vreg_l), .regs = ufsphy_v6_regs_layout, }; From da938e39a81642748db3ec2385e8a53fe03d9bd1 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Thu, 28 Aug 2025 20:23:55 +0800 Subject: [PATCH 0721/2711] phy: hisilicon: Remove redundant ternary operators Remove redundant ternary operators to clean up the code. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250828122401.17441-2-liaoyuanhong@vivo.com Signed-off-by: Vinod Koul --- drivers/phy/hisilicon/phy-histb-combphy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/hisilicon/phy-histb-combphy.c b/drivers/phy/hisilicon/phy-histb-combphy.c index 7436dcae3981..9dd0bd00b4e4 100644 --- a/drivers/phy/hisilicon/phy-histb-combphy.c +++ b/drivers/phy/hisilicon/phy-histb-combphy.c @@ -73,7 +73,7 @@ static void nano_register_write(struct histb_combphy_priv *priv, static int is_mode_fixed(struct histb_combphy_mode *mode) { - return (mode->fixed != PHY_NONE) ? true : false; + return mode->fixed != PHY_NONE; } static int histb_combphy_set_mode(struct histb_combphy_priv *priv) From e7ec351347b6325f872b9059453c9c9bf22c159c Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Thu, 28 Aug 2025 20:23:56 +0800 Subject: [PATCH 0722/2711] phy: renesas: rcar-gen3-usb2: Remove redundant ternary operators Remove redundant ternary operators to clean up the code. Signed-off-by: Liao Yuanhong Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/20250828122401.17441-3-liaoyuanhong@vivo.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 7b4a6e8b7508..bab2d4dce5b3 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -306,7 +306,7 @@ static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) } if (!ch->uses_otg_pins) - return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; + return ch->dr_mode != USB_DR_MODE_HOST; if (ch->phy_data->no_adp_ctrl) return !!(readl(ch->base + USB2_LINECTRL1) & USB2_LINECTRL1_USB2_IDMON); From 0c5375b06060fa40a8f8ce2e926bde125fdf6c3b Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Thu, 28 Aug 2025 20:23:57 +0800 Subject: [PATCH 0723/2711] phy: rockchip: usbdp: Remove redundant ternary operators Remove redundant ternary operators to clean up the code. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250828122401.17441-4-liaoyuanhong@vivo.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-usbdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index 010e9d2d6fac..fba35510d88c 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -666,7 +666,7 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw, goto unlock_ret; } - udphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false; + udphy->flip = orien == TYPEC_ORIENTATION_REVERSE; rk_udphy_set_typec_default_mapping(udphy); rk_udphy_usb_bvalid_enable(udphy, true); From 616fe247bdce4e3a23e3ded4b3be951001ed8039 Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Tue, 26 Aug 2025 16:22:54 +0530 Subject: [PATCH 0724/2711] phy: qcom: m31-eusb2: Fix the error log while enabling clock While enabling clock, we incorrectly log 'ref clk' as 'cfg ahb clk' Fix this since the devicetree bindings mentions it as ref clock. Signed-off-by: Prashanth K Link: https://lore.kernel.org/r/20250826105254.3758803-1-prashanth.k@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-m31-eusb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c index bf32572566c4..0a0d2d9fc846 100644 --- a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c @@ -196,7 +196,7 @@ static int m31eusb2_phy_init(struct phy *uphy) ret = clk_prepare_enable(phy->clk); if (ret) { - dev_err(&uphy->dev, "failed to enable cfg ahb clock, %d\n", ret); + dev_err(&uphy->dev, "failed to enable ref clock, %d\n", ret); goto disable_repeater; } From 9bef84d30f1f724191270044a7d045bfc9d6ad97 Mon Sep 17 00:00:00 2001 From: Josua Mayer Date: Tue, 26 Aug 2025 20:32:03 +0200 Subject: [PATCH 0725/2711] phy: lynx-28g: check return value when calling lynx_28g_pll_get The lynx_28g_pll_get function may return NULL when called with an unsupported submode argument. This function is only called from the lynx_28g_lane_set_{10gbaser,sgmii} functions, and lynx_28g_set_mode checks available modes before setting a protocol. NXP vendor kernel based on v6.6.52 however is missing any checks and connecting a 2.5/5gbase-t ethernet phy can cause null pointer dereference [1]. Check return value at every invocation and abort in the unlikely error case. Further print a warning message the first time lynx_28g_pll_get returns null, to catch this case should it occur after future changes. [1] [ 127.019924] fsl_dpaa2_eth dpni.4 eth5: dpmac_set_protocol(2500base-x) = -ENOTSUPP [ 127.027451] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000014 [ 127.036245] Mem abort info: [ 127.039044] ESR = 0x0000000096000004 [ 127.042794] EC = 0x25: DABT (current EL), IL = 32 bits [ 127.048107] SET = 0, FnV = 0 [ 127.051161] EA = 0, S1PTW = 0 [ 127.054301] FSC = 0x04: level 0 translation fault [ 127.059179] Data abort info: [ 127.062059] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 [ 127.067547] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 127.072596] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 127.077907] user pgtable: 4k pages, 48-bit VAs, pgdp=00000020816c9000 [ 127.084344] [0000000000000014] pgd=0000000000000000, p4d=0000000000000000 [ 127.091133] Internal error: Oops: 0000000096000004 [#1] PREEMPT SMP [ 127.097390] Modules linked in: cfg80211 rfkill fsl_jr_uio caam_jr dpaa2_caam caamkeyblob_desc crypto_engine caamhash_desc onboard_usb_hub caamalg_desc crct10dif_ce libdes caam error at24 rtc_ds1307 rtc_fsl_ftm_alarm nvmem_layerscape_sfp layerscape_edac_mod dm_mod nfnetlink ip_tables [ 127.122436] CPU: 5 PID: 96 Comm: kworker/u35:0 Not tainted 6.6.52-g3578ef896722 #10 [ 127.130083] Hardware name: SolidRun LX2162A Clearfog (DT) [ 127.135470] Workqueue: events_power_efficient phylink_resolve [ 127.141219] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 127.148170] pc : lynx_28g_set_lane_mode+0x300/0x818 [ 127.153041] lr : lynx_28g_set_lane_mode+0x2fc/0x818 [ 127.157909] sp : ffff8000806f3b80 [ 127.161212] x29: ffff8000806f3b80 x28: 0000000000000000 x27: 0000000000000000 [ 127.168340] x26: ffff29d6c11f3098 x25: 0000000000000000 x24: 0000000000000000 [ 127.175467] x23: ffff29d6c11f31f0 x22: ffff29d6c11f3080 x21: 0000000000000001 [ 127.182595] x20: ffff29d6c11f4c00 x19: 0000000000000000 x18: 0000000000000006 [ 127.189722] x17: 4f4e452d203d2029 x16: 782d657361623030 x15: 3532286c6f636f74 [ 127.196849] x14: 6f72705f7465735f x13: ffffd7a8ff991cc0 x12: 0000000000000acb [ 127.203976] x11: 0000000000000399 x10: ffffd7a8ff9e9cc0 x9 : 0000000000000000 [ 127.211104] x8 : 0000000000000000 x7 : 0000000000000000 x6 : ffff29d6c11f3080 [ 127.218231] x5 : 0000000000000000 x4 : 0000000040800030 x3 : 000000000000034c [ 127.225358] x2 : ffff29d6c11f3080 x1 : 000000000000034c x0 : 0000000000000000 [ 127.232486] Call trace: [ 127.234921] lynx_28g_set_lane_mode+0x300/0x818 [ 127.239443] lynx_28g_set_mode+0x12c/0x148 [ 127.243529] phy_set_mode_ext+0x5c/0xa8 [ 127.247356] lynx_pcs_config+0x64/0x294 [ 127.251184] phylink_major_config+0x184/0x49c [ 127.255532] phylink_resolve+0x2a0/0x5d8 [ 127.259446] process_one_work+0x138/0x248 [ 127.263448] worker_thread+0x320/0x438 [ 127.267187] kthread+0x114/0x118 [ 127.270406] ret_from_fork+0x10/0x20 [ 127.273973] Code: 2a1303e1 aa0603e0 97fffd3b aa0003e5 (b9401400) [ 127.280055] ---[ end trace 0000000000000000 ]--- Signed-off-by: Josua Mayer Link: https://lore.kernel.org/r/20250826-lynx-28g-nullptr-v1-1-e4de0098f822@solid-run.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index f7994e8983c8..c20d2636c5e9 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -188,6 +188,10 @@ static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv, return pll; } + /* no pll supports requested mode, either caller forgot to check + * lynx_28g_supports_lane_mode, or this is a bug. + */ + dev_WARN_ONCE(priv->dev, 1, "no pll for interface %s\n", phy_modes(intf)); return NULL; } @@ -276,8 +280,12 @@ static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane) lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK); lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK); - /* Switch to the PLL that works with this interface type */ + /* Find the PLL that works with this interface type */ pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII); + if (unlikely(pll == NULL)) + return; + + /* Switch to the PLL that works with this interface type */ lynx_28g_lane_set_pll(lane, pll); /* Choose the portion of clock net to be used on this lane */ @@ -312,8 +320,12 @@ static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane) lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK); lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK); - /* Switch to the PLL that works with this interface type */ + /* Find the PLL that works with this interface type */ pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER); + if (unlikely(pll == NULL)) + return; + + /* Switch to the PLL that works with this interface type */ lynx_28g_lane_set_pll(lane, pll); /* Choose the portion of clock net to be used on this lane */ From 8a9e097def55391273d3042b32350ded1ec83e04 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sat, 30 Aug 2025 18:06:37 +0800 Subject: [PATCH 0726/2711] mtd: rawnand: pl353: Use int type to store negative error codes Change the 'ret' variable from u32 to int in pl35x_nand_probe() to store negative error codes or zero; Storing the negative error codes in unsigned type, doesn't cause an issue at runtime but can be confusing. Additionally, assigning negative error codes to unsigned type may trigger a GCC warning when the -Wsign-conversion flag is enabled. No effect on runtime. Signed-off-by: Qianfeng Rong Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/pl35x-nand-controller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c index 09440ed4652e..37e92b86bf26 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -1137,7 +1137,7 @@ static int pl35x_nand_probe(struct platform_device *pdev) struct device *smc_dev = pdev->dev.parent; struct amba_device *smc_amba = to_amba_device(smc_dev); struct pl35x_nandc *nfc; - u32 ret; + int ret; nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL); if (!nfc) From 773b9202de0127444fc8802a611a19637b7fa12f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 30 Aug 2025 19:01:09 +0200 Subject: [PATCH 0727/2711] mtd: rawnand: s3c2410: Drop S3C2410 support Samsung S3C24xx family of SoCs was removed from the Linux kernel in the commit 61b7f8920b17 ("ARM: s3c: remove all s3c24xx support"), in January 2023. There are no in-kernel users of its compatibles and platform IDs. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/s3c2410.c | 38 ---------------------------------- 1 file changed, 38 deletions(-) diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c index 229f2e87d56e..33130d75c5ba 100644 --- a/drivers/mtd/nand/raw/s3c2410.c +++ b/drivers/mtd/nand/raw/s3c2410.c @@ -169,18 +169,6 @@ struct s3c24XX_nand_devtype_data { enum s3c_cpu_type type; }; -static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = { - .type = TYPE_S3C2410, -}; - -static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = { - .type = TYPE_S3C2412, -}; - -static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = { - .type = TYPE_S3C2440, -}; - /* conversion functions */ static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd) @@ -944,22 +932,6 @@ static const struct nand_controller_ops s3c24xx_nand_controller_ops = { .setup_interface = s3c2410_nand_setup_interface, }; -static const struct of_device_id s3c24xx_nand_dt_ids[] = { - { - .compatible = "samsung,s3c2410-nand", - .data = &s3c2410_nand_devtype_data, - }, { - /* also compatible with s3c6400 */ - .compatible = "samsung,s3c2412-nand", - .data = &s3c2412_nand_devtype_data, - }, { - .compatible = "samsung,s3c2440-nand", - .data = &s3c2440_nand_devtype_data, - }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids); - static int s3c24xx_nand_probe_dt(struct platform_device *pdev) { const struct s3c24XX_nand_devtype_data *devtype_data; @@ -1194,15 +1166,6 @@ static int s3c24xx_nand_resume(struct platform_device *dev) static const struct platform_device_id s3c24xx_driver_ids[] = { { - .name = "s3c2410-nand", - .driver_data = TYPE_S3C2410, - }, { - .name = "s3c2440-nand", - .driver_data = TYPE_S3C2440, - }, { - .name = "s3c2412-nand", - .driver_data = TYPE_S3C2412, - }, { .name = "s3c6400-nand", .driver_data = TYPE_S3C2412, /* compatible with 2412 */ }, @@ -1219,7 +1182,6 @@ static struct platform_driver s3c24xx_nand_driver = { .id_table = s3c24xx_driver_ids, .driver = { .name = "s3c24xx-nand", - .of_match_table = s3c24xx_nand_dt_ids, }, }; From f156b23df6a84efb2f6686156be94d4988568954 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Tue, 8 Jul 2025 17:16:45 +0800 Subject: [PATCH 0728/2711] mtd: spi-nor: core: avoid odd length/address reads on 8D-8D-8D mode On Octal DTR capable flashes like Micron Xcella reads cannot start or end at an odd address in Octal DTR mode. Extra bytes need to be read at the start or end to make sure both the start address and length remain even. To avoid allocating too much extra memory, thereby putting unnecessary memory pressure on the system, the temporary buffer containing the extra padding bytes is capped at PAGE_SIZE bytes. The rest of the 2-byte aligned part should be read directly in the main buffer. Signed-off-by: Pratyush Yadav Reviewed-by: Michael Walle Signed-off-by: Luke Wang Signed-off-by: Pratyush Yadav Link: https://lore.kernel.org/r/20250708091646.292-1-ziniu.wang_1@nxp.com --- drivers/mtd/spi-nor/core.c | 76 +++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index ac4b960101cc..1b594f720b6c 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2014,6 +2014,76 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor) return info; } +/* + * On Octal DTR capable flashes, reads cannot start or end at an odd + * address in Octal DTR mode. Extra bytes need to be read at the start + * or end to make sure both the start address and length remain even. + */ +static int spi_nor_octal_dtr_read(struct spi_nor *nor, loff_t from, size_t len, + u_char *buf) +{ + u_char *tmp_buf; + size_t tmp_len; + loff_t start, end; + int ret, bytes_read; + + if (IS_ALIGNED(from, 2) && IS_ALIGNED(len, 2)) + return spi_nor_read_data(nor, from, len, buf); + else if (IS_ALIGNED(from, 2) && len > PAGE_SIZE) + return spi_nor_read_data(nor, from, round_down(len, PAGE_SIZE), + buf); + + tmp_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!tmp_buf) + return -ENOMEM; + + start = round_down(from, 2); + end = round_up(from + len, 2); + + /* + * Avoid allocating too much memory. The requested read length might be + * quite large. Allocating a buffer just as large (slightly bigger, in + * fact) would put unnecessary memory pressure on the system. + * + * For example if the read is from 3 to 1M, then this will read from 2 + * to 4098. The reads from 4098 to 1M will then not need a temporary + * buffer so they can proceed as normal. + */ + tmp_len = min_t(size_t, end - start, PAGE_SIZE); + + ret = spi_nor_read_data(nor, start, tmp_len, tmp_buf); + if (ret == 0) { + ret = -EIO; + goto out; + } + if (ret < 0) + goto out; + + /* + * More bytes are read than actually requested, but that number can't be + * reported to the calling function or it will confuse its calculations. + * Calculate how many of the _requested_ bytes were read. + */ + bytes_read = ret; + + if (from != start) + ret -= from - start; + + /* + * Only account for extra bytes at the end if they were actually read. + * For example, if the total length was truncated because of temporary + * buffer size limit then the adjustment for the extra bytes at the end + * is not needed. + */ + if (start + bytes_read == end) + ret -= end - (from + len); + + memcpy(buf, tmp_buf + (from - start), ret); +out: + kfree(tmp_buf); + return ret; +} + static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -2031,7 +2101,11 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, while (len) { loff_t addr = from; - ret = spi_nor_read_data(nor, addr, len, buf); + if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) + ret = spi_nor_octal_dtr_read(nor, addr, len, buf); + else + ret = spi_nor_read_data(nor, addr, len, buf); + if (ret == 0) { /* We shouldn't see 0-length reads */ ret = -EIO; From 17926cd770ec837ed27d9856cf07f2da8dda4131 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Tue, 8 Jul 2025 17:16:46 +0800 Subject: [PATCH 0729/2711] mtd: spi-nor: core: avoid odd length/address writes in 8D-8D-8D mode On Octal DTR capable flashes like Micron Xcella the writes cannot start or end at an odd address in Octal DTR mode. Extra 0xff bytes need to be appended or prepended to make sure the start address and end address are even. 0xff is used because on NOR flashes a program operation can only flip bits from 1 to 0, not the other way round. 0 to 1 flip needs to happen via erases. Signed-off-by: Pratyush Yadav Reviewed-by: Michael Walle Signed-off-by: Luke Wang Signed-off-by: Pratyush Yadav Link: https://lore.kernel.org/r/20250708091646.292-2-ziniu.wang_1@nxp.com --- drivers/mtd/spi-nor/core.c | 69 +++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 1b594f720b6c..20ea80450f22 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2128,6 +2128,68 @@ read_err: return ret; } +/* + * On Octal DTR capable flashes, writes cannot start or end at an odd address + * in Octal DTR mode. Extra 0xff bytes need to be appended or prepended to + * make sure the start address and end address are even. 0xff is used because + * on NOR flashes a program operation can only flip bits from 1 to 0, not the + * other way round. 0 to 1 flip needs to happen via erases. + */ +static int spi_nor_octal_dtr_write(struct spi_nor *nor, loff_t to, size_t len, + const u8 *buf) +{ + u8 *tmp_buf; + size_t bytes_written; + loff_t start, end; + int ret; + + if (IS_ALIGNED(to, 2) && IS_ALIGNED(len, 2)) + return spi_nor_write_data(nor, to, len, buf); + + tmp_buf = kmalloc(nor->params->page_size, GFP_KERNEL); + if (!tmp_buf) + return -ENOMEM; + + memset(tmp_buf, 0xff, nor->params->page_size); + + start = round_down(to, 2); + end = round_up(to + len, 2); + + memcpy(tmp_buf + (to - start), buf, len); + + ret = spi_nor_write_data(nor, start, end - start, tmp_buf); + if (ret == 0) { + ret = -EIO; + goto out; + } + if (ret < 0) + goto out; + + /* + * More bytes are written than actually requested, but that number can't + * be reported to the calling function or it will confuse its + * calculations. Calculate how many of the _requested_ bytes were + * written. + */ + bytes_written = ret; + + if (to != start) + ret -= to - start; + + /* + * Only account for extra bytes at the end if they were actually + * written. For example, if for some reason the controller could only + * complete a partial write then the adjustment for the extra bytes at + * the end is not needed. + */ + if (start + bytes_written == end) + ret -= end - (to + len); + +out: + kfree(tmp_buf); + return ret; +} + /* * Write an address range to the nor chip. Data must be written in * FLASH_PAGESIZE chunks. The address range may be any size provided @@ -2164,7 +2226,12 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, goto write_err; } - ret = spi_nor_write_data(nor, addr, page_remain, buf + i); + if (nor->write_proto == SNOR_PROTO_8_8_8_DTR) + ret = spi_nor_octal_dtr_write(nor, addr, page_remain, + buf + i); + else + ret = spi_nor_write_data(nor, addr, page_remain, + buf + i); spi_nor_unlock_device(nor); if (ret < 0) goto write_err; From 9a7f144e18dc5f037d85a0f0d99524a574331098 Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Mon, 1 Sep 2025 17:33:55 +0530 Subject: [PATCH 0730/2711] PCI: j721e: Fix module autoloading Commit a2790bf81f0f ("PCI: j721e: Add support to build as a loadable module") added support to build the driver as a loadable module. However, it did not add MODULE_DEVICE_TABLE() which is required for autoloading the driver based on device table when it is built as a loadable module. Fix it by adding MODULE_DEVICE_TABLE. Fixes: a2790bf81f0f ("PCI: j721e: Add support to build as a loadable module") Signed-off-by: Siddharth Vadapalli [mani: reworded description] Signed-off-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250901120359.3410774-1-s-vadapalli@ti.com --- drivers/pci/controller/cadence/pci-j721e.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c index 6c93f39d0288..cfca13a4c840 100644 --- a/drivers/pci/controller/cadence/pci-j721e.c +++ b/drivers/pci/controller/cadence/pci-j721e.c @@ -440,6 +440,7 @@ static const struct of_device_id of_j721e_pcie_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, of_j721e_pcie_match); static int j721e_pcie_probe(struct platform_device *pdev) { From 3d13e378d465e8ae0be1697005342055b07eaf11 Mon Sep 17 00:00:00 2001 From: Maud Spierings Date: Fri, 22 Aug 2025 11:20:05 +0200 Subject: [PATCH 0731/2711] dt-bindings: phy: ti,tcan104x-can: Document TI TCAN1051 TCAN1051-Q1 Automotive Fault Protected CAN Transceiver with CAN FD It is pretty much identical to the TCAN1042, add the compatible with fallback on the TCAN1042. Signed-off-by: Maud Spierings Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250822-can_phy3-v1-1-73b3ba1690ee@gocontroll.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml index 4a8c3829d85d..138923ffedfe 100644 --- a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml +++ b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml @@ -18,6 +18,7 @@ properties: - items: - enum: - microchip,ata6561 + - ti,tcan1051 - const: ti,tcan1042 - enum: - ti,tcan1042 From 356590cd61cf89e2420d5628e35b6e73c6b6a770 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 21 Aug 2025 16:59:57 +0100 Subject: [PATCH 0732/2711] phy: renesas: rcar-gen3-usb2: Fix ID check logic with VBUS valid The existing ID detection logic returned false when both IDDIG and VBUSVALID were set, which caused incorrect role determination in some cases. The condition: !(device && !vbus_valid) did not properly reflect the intended relationship between IDDIG and VBUSVALID signals. Update the logic to: return vbus_valid ? device : !device; This ensures that when VBUS is valid, the role follows the IDDIG value, and when VBUS is not valid, the role is inverted, matching the expected OTG behavior. Fixes: b725741f1c21 ("phy: renesas: rcar-gen3-usb2: Add support for RZ/T2H SoC") Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20250821155957.1088337-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index bab2d4dce5b3..3f6b480e1092 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -302,7 +302,7 @@ static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) device = !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); vbus_valid = !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_VBUSVALID); - return !(device && !vbus_valid); + return vbus_valid ? device : !device; } if (!ch->uses_otg_pins) From 969bf687c12cd9f64ed9368f0c7429445de7c10b Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 27 Aug 2025 13:15:06 +0300 Subject: [PATCH 0733/2711] soundwire: bus: Drop dev_pm_domain_detach() call Starting with commit f99508074e78 ("PM: domains: Detach on device_unbind_cleanup()"), there is no longer a need to call dev_pm_domain_detach() in the bus remove function. The device_unbind_cleanup() function now handles this to avoid invoking devres cleanup handlers while the PM domain is powered off, which could otherwise lead to failures as described in the above-mentioned commit. Drop the explicit dev_pm_domain_detach() call and rely instead on the flags passed to dev_pm_domain_attach() to power off the domain. Signed-off-by: Claudiu Beznea Reviewed-by: Ulf Hansson Link: https://lore.kernel.org/r/20250827101506.927787-1-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus_type.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index bc1e653080d9..91e70cb46fb5 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -114,7 +114,6 @@ static int sdw_drv_probe(struct device *dev) ret = drv->probe(slave, id); if (ret) { - dev_pm_domain_detach(dev, false); ida_free(&slave->bus->slave_ida, slave->index); return ret; } @@ -180,8 +179,6 @@ static int sdw_drv_remove(struct device *dev) if (drv->remove) ret = drv->remove(slave); - dev_pm_domain_detach(dev, false); - ida_free(&slave->bus->slave_ida, slave->index); return ret; From 88f5d2a477ec64b12e83b488407490bb4a9298f8 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Thu, 14 Aug 2025 22:24:28 +0800 Subject: [PATCH 0734/2711] soundwire: Use min() to improve code Use min() to reduce the code in qcom_swrm_xfer_msg() and improve its readability. Signed-off-by: Qianfeng Rong Link: https://lore.kernel.org/r/20250814142428.282639-1-rongqianfeng@vivo.com Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index bd2b293b44f2..5b3078220189 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -924,10 +924,7 @@ static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus, if (msg->flags == SDW_MSG_FLAG_READ) { for (i = 0; i < msg->len;) { - if ((msg->len - i) < QCOM_SWRM_MAX_RD_LEN) - len = msg->len - i; - else - len = QCOM_SWRM_MAX_RD_LEN; + len = min(msg->len - i, QCOM_SWRM_MAX_RD_LEN); ret = qcom_swrm_cmd_fifo_rd_cmd(ctrl, msg->dev_num, msg->addr + i, len, From f9381ece76de999a2065d5b4fdd87fa17883978c Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Mon, 1 Sep 2025 21:57:25 +0800 Subject: [PATCH 0735/2711] iio: dac: ad5360: use int type to store negative error codes Change the 'ret' variable in ad5360_update_ctrl() from unsigned int to int, as it needs to store either negative error codes or zero returned by ad5360_write_unlocked(). Fixes: a3e2940c24d3 ("staging:iio:dac: Add AD5360 driver") Signed-off-by: Qianfeng Rong Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250901135726.17601-2-rongqianfeng@vivo.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5360.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index a57b0a093112..8271849b1c83 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -262,7 +262,7 @@ static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set, unsigned int clr) { struct ad5360_state *st = iio_priv(indio_dev); - unsigned int ret; + int ret; mutex_lock(&st->lock); From 3379c900320954d768ed9903691fb2520926bbe3 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Mon, 1 Sep 2025 21:57:26 +0800 Subject: [PATCH 0736/2711] iio: dac: ad5421: use int type to store negative error codes Change the 'ret' variable in ad5421_update_ctrl() from unsigned int to int, as it needs to store either negative error codes or zero returned by ad5421_write_unlocked(). Fixes: 5691b23489db ("staging:iio:dac: Add AD5421 driver") Signed-off-by: Qianfeng Rong Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250901135726.17601-3-rongqianfeng@vivo.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5421.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 1462ee640b16..d9d7031c4432 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -186,7 +186,7 @@ static int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set, unsigned int clr) { struct ad5421_state *st = iio_priv(indio_dev); - unsigned int ret; + int ret; mutex_lock(&st->lock); From 981d4978ff09d13690739663b3cd71ad8bb5ad94 Mon Sep 17 00:00:00 2001 From: Chelsy Ratnawat Date: Sat, 30 Aug 2025 06:26:33 -0700 Subject: [PATCH 0737/2711] dmaengine: Replace zero-length array with flexible-array Documentation/process/deprecated.rst suggests that zero-length and one-element arrays are deprecated, flexible-array members should be used instead. Signed-off-by: Chelsy Ratnawat Link: https://lore.kernel.org/r/20250830132633.1803300-1-chelsyratnawat2001@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 02a85d6f1bea..ed9e56de5a9b 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -256,7 +256,7 @@ struct sdma_script_start_addrs { /* End of v3 array */ union { s32 v3_end; s32 mcu_2_zqspi_addr; }; /* End of v4 array */ - s32 v4_end[0]; + s32 v4_end[]; }; /* From d9a3e9929452780df16f3414f0d59b5f69d058cf Mon Sep 17 00:00:00 2001 From: Thomas Andreatta Date: Wed, 27 Aug 2025 17:24:43 +0200 Subject: [PATCH 0738/2711] dmaengine: sh: setup_xref error handling This patch modifies the type of setup_xref from void to int and handles errors since the function can fail. `setup_xref` now returns the (eventual) error from `dmae_set_dmars`|`dmae_set_chcr`, while `shdma_tx_submit` handles the result, removing the chunks from the queue and marking PM as idle in case of an error. Signed-off-by: Thomas Andreatta Link: https://lore.kernel.org/r/20250827152442.90962-1-thomas.andreatta2000@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma-base.c | 25 +++++++++++++++++++------ drivers/dma/sh/shdmac.c | 17 +++++++++++++---- include/linux/shdma-base.h | 2 +- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 6b4fce453c85..834741adadaa 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -129,12 +129,25 @@ static dma_cookie_t shdma_tx_submit(struct dma_async_tx_descriptor *tx) const struct shdma_ops *ops = sdev->ops; dev_dbg(schan->dev, "Bring up channel %d\n", schan->id); - /* - * TODO: .xfer_setup() might fail on some platforms. - * Make it int then, on error remove chunks from the - * queue again - */ - ops->setup_xfer(schan, schan->slave_id); + + ret = ops->setup_xfer(schan, schan->slave_id); + if (ret < 0) { + dev_err(schan->dev, "setup_xfer failed: %d\n", ret); + + /* Remove chunks from the queue and mark them as idle */ + list_for_each_entry_safe(chunk, c, &schan->ld_queue, node) { + if (chunk->cookie == cookie) { + chunk->mark = DESC_IDLE; + list_move(&chunk->node, &schan->ld_free); + } + } + + schan->pm_state = SHDMA_PM_ESTABLISHED; + ret = pm_runtime_put(schan->dev); + + spin_unlock_irq(&schan->chan_lock); + return ret; + } if (schan->pm_state == SHDMA_PM_PENDING) shdma_chan_xfer_ld_queue(schan); diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index 093e449e19ee..603e15102e45 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -300,21 +300,30 @@ static bool sh_dmae_channel_busy(struct shdma_chan *schan) return dmae_is_busy(sh_chan); } -static void sh_dmae_setup_xfer(struct shdma_chan *schan, - int slave_id) +static int sh_dmae_setup_xfer(struct shdma_chan *schan, int slave_id) { struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan, shdma_chan); + int ret = 0; if (slave_id >= 0) { const struct sh_dmae_slave_config *cfg = sh_chan->config; - dmae_set_dmars(sh_chan, cfg->mid_rid); - dmae_set_chcr(sh_chan, cfg->chcr); + ret = dmae_set_dmars(sh_chan, cfg->mid_rid); + if (ret < 0) + goto END; + + ret = dmae_set_chcr(sh_chan, cfg->chcr); + if (ret < 0) + goto END; + } else { dmae_init(sh_chan); } + +END: + return ret; } /* diff --git a/include/linux/shdma-base.h b/include/linux/shdma-base.h index 6dfd05ef5c2d..03ba4dab2ef7 100644 --- a/include/linux/shdma-base.h +++ b/include/linux/shdma-base.h @@ -96,7 +96,7 @@ struct shdma_ops { int (*desc_setup)(struct shdma_chan *, struct shdma_desc *, dma_addr_t, dma_addr_t, size_t *); int (*set_slave)(struct shdma_chan *, int, dma_addr_t, bool); - void (*setup_xfer)(struct shdma_chan *, int); + int (*setup_xfer)(struct shdma_chan *, int); void (*start_xfer)(struct shdma_chan *, struct shdma_desc *); struct shdma_desc *(*embedded_desc)(void *, int); bool (*chan_irq)(struct shdma_chan *, int); From 38433a6fdfb75d12a90ffff262705e1ecfe88556 Mon Sep 17 00:00:00 2001 From: Folker Schwesinger Date: Tue, 26 Aug 2025 20:21:10 +0200 Subject: [PATCH 0739/2711] dmaengine: xilinx_dma: Support descriptor setup from dma_vecs The DMAEngine provides an interface for obtaining DMA transaction descriptors from an array of scatter gather buffers represented by struct dma_vec. This interface is used in the DMABUF API of the IIO framework [1][2]. To enable DMABUF support through the IIO framework for the Xilinx DMA, implement callback .device_prep_peripheral_dma_vec() of struct dma_device in the driver. [1]: 7a86d469983a ("iio: buffer-dmaengine: Support new DMABUF based userspace API") [2]: 5878853fc938 ("dmaengine: Add API function dmaengine_prep_peripheral_dma_vec()") Signed-off-by: Folker Schwesinger Reviewed-by: Suraj Gupta Reviewed-by: Radhey Shyam Pandey Link: https://lore.kernel.org/r/DCCKQLKOZC06.2H6LJ8RJQJNV2@folker-schwesinger.de Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dma.c | 94 +++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index a34d8f0ceed8..fabff602065f 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -2172,6 +2172,99 @@ error: return NULL; } +/** + * xilinx_dma_prep_peripheral_dma_vec - prepare descriptors for a DMA_SLAVE + * transaction from DMA vectors + * @dchan: DMA channel + * @vecs: Array of DMA vectors that should be transferred + * @nb: number of entries in @vecs + * @direction: DMA direction + * @flags: transfer ack flags + * + * Return: Async transaction descriptor on success and NULL on failure + */ +static struct dma_async_tx_descriptor *xilinx_dma_prep_peripheral_dma_vec( + struct dma_chan *dchan, const struct dma_vec *vecs, size_t nb, + enum dma_transfer_direction direction, unsigned long flags) +{ + struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); + struct xilinx_dma_tx_descriptor *desc; + struct xilinx_axidma_tx_segment *segment, *head, *prev = NULL; + size_t copy; + size_t sg_used; + unsigned int i; + + if (!is_slave_direction(direction) || direction != chan->direction) + return NULL; + + desc = xilinx_dma_alloc_tx_descriptor(chan); + if (!desc) + return NULL; + + dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); + desc->async_tx.tx_submit = xilinx_dma_tx_submit; + + /* Build transactions using information from DMA vectors */ + for (i = 0; i < nb; i++) { + sg_used = 0; + + /* Loop until the entire dma_vec entry is used */ + while (sg_used < vecs[i].len) { + struct xilinx_axidma_desc_hw *hw; + + /* Get a free segment */ + segment = xilinx_axidma_alloc_tx_segment(chan); + if (!segment) + goto error; + + /* + * Calculate the maximum number of bytes to transfer, + * making sure it is less than the hw limit + */ + copy = xilinx_dma_calc_copysize(chan, vecs[i].len, + sg_used); + hw = &segment->hw; + + /* Fill in the descriptor */ + xilinx_axidma_buf(chan, hw, vecs[i].addr, sg_used, 0); + hw->control = copy; + + if (prev) + prev->hw.next_desc = segment->phys; + + prev = segment; + sg_used += copy; + + /* + * Insert the segment into the descriptor segments + * list. + */ + list_add_tail(&segment->node, &desc->segments); + } + } + + head = list_first_entry(&desc->segments, struct xilinx_axidma_tx_segment, node); + desc->async_tx.phys = head->phys; + + /* For the last DMA_MEM_TO_DEV transfer, set EOP */ + if (chan->direction == DMA_MEM_TO_DEV) { + segment->hw.control |= XILINX_DMA_BD_SOP; + segment = list_last_entry(&desc->segments, + struct xilinx_axidma_tx_segment, + node); + segment->hw.control |= XILINX_DMA_BD_EOP; + } + + if (chan->xdev->has_axistream_connected) + desc->async_tx.metadata_ops = &xilinx_dma_metadata_ops; + + return &desc->async_tx; + +error: + xilinx_dma_free_tx_descriptor(chan, desc); + return NULL; +} + /** * xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction * @dchan: DMA channel @@ -3180,6 +3273,7 @@ static int xilinx_dma_probe(struct platform_device *pdev) xdev->common.device_config = xilinx_dma_device_config; if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { dma_cap_set(DMA_CYCLIC, xdev->common.cap_mask); + xdev->common.device_prep_peripheral_dma_vec = xilinx_dma_prep_peripheral_dma_vec; xdev->common.device_prep_slave_sg = xilinx_dma_prep_slave_sg; xdev->common.device_prep_dma_cyclic = xilinx_dma_prep_dma_cyclic; From 7ea95d55e63176899eb96f7aaa34a5646f501b2c Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Tue, 26 Aug 2025 11:07:38 -0500 Subject: [PATCH 0740/2711] dmaengine: Fix dma_async_tx_descriptor->tx_submit documentation Commit 790fb9956eea ("linux/dmaengine.h: fix a few kernel-doc warnings") inserted new documentation for @desc_free in the middle of @tx_submit's description. Put @tx_submit's description back together, matching the indentation style of the rest of the documentation for dma_async_tx_descriptor. Fixes: 790fb9956eea ("linux/dmaengine.h: fix a few kernel-doc warnings") Reviewed-by: Dave Jiang Signed-off-by: Nathan Lynch Link: https://lore.kernel.org/r/20250826-dma_async_tx_desc-tx_submit-doc-fix-v1-1-18a4b51697db@amd.com Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 6de7c05d6bd8..99efe2b9b4ea 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -594,9 +594,9 @@ struct dma_descriptor_metadata_ops { * @phys: physical address of the descriptor * @chan: target channel for this operation * @tx_submit: accept the descriptor, assign ordered cookie and mark the + * descriptor pending. To be pushed on .issue_pending() call * @desc_free: driver's callback function to free a resusable descriptor * after completion - * descriptor pending. To be pushed on .issue_pending() call * @callback: routine to call after this operation is complete * @callback_result: error result from a DMA transaction * @callback_param: general parameter to pass to the callback routine From d5df661c9c76cb36d90527349ac6197a4baf2aba Mon Sep 17 00:00:00 2001 From: Abin Joseph Date: Mon, 25 Aug 2025 18:34:23 +0530 Subject: [PATCH 0741/2711] dt-bindings: dmaengine: xilinx_dma: Remove DMA client properties Remove DMA client section mentioned in the dt-bindings as it is not required to document client bindings in dmaengine bindings. Signed-off-by: Abin Joseph Signed-off-by: Radhey Shyam Pandey Acked-by: Rob Herring Signed-off-by: Abin Joseph Link: https://lore.kernel.org/r/20250825130423.5739-1-abin.joseph@amd.com Signed-off-by: Vinod Koul --- .../bindings/dma/xilinx/xilinx_dma.txt | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt index 590d1948f202..b567107270cb 100644 --- a/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt +++ b/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt @@ -109,26 +109,3 @@ axi_vdma_0: axivdma@40030000 { xlnx,datawidth = <0x40>; } ; } ; - - -* DMA client - -Required properties: -- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs, - where Channel ID is '0' for write/tx and '1' for read/rx - channel. For MCMDA, MM2S channel(write/tx) ID start from - '0' and is in [0-15] range. S2MM channel(read/rx) ID start - from '16' and is in [16-31] range. These channels ID are - fixed irrespective of IP configuration. - -- dma-names: a list of DMA channel names, one per "dmas" entry - -Example: -++++++++ - -vdmatest_0: vdmatest@0 { - compatible ="xlnx,axi-vdma-test-1.00.a"; - dmas = <&axi_vdma_0 0 - &axi_vdma_0 1>; - dma-names = "vdma0", "vdma1"; -} ; From 39ce725e621b256188550492b4b53fb02bfc872e Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Fri, 22 Aug 2025 11:06:27 +0800 Subject: [PATCH 0742/2711] dt-bindings: dma: Add SpacemiT K1 PDMA controller Add device tree binding documentation for the SpacemiT K1 PDMA controller. Signed-off-by: Guodong Xu Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250822-working_dma_0701_v2-v5-1-f5c0eda734cc@riscstar.com Signed-off-by: Vinod Koul --- .../bindings/dma/spacemit,k1-pdma.yaml | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml diff --git a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml new file mode 100644 index 000000000000..ec06235baf5c --- /dev/null +++ b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/spacemit,k1-pdma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SpacemiT K1 PDMA Controller + +maintainers: + - Guodong Xu + +allOf: + - $ref: dma-controller.yaml# + +properties: + compatible: + const: spacemit,k1-pdma + + reg: + maxItems: 1 + + interrupts: + description: Shared interrupt for all DMA channels + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + dma-channels: + maximum: 16 + + '#dma-cells': + const: 1 + description: + The DMA request number for the peripheral device. + +required: + - compatible + - reg + - interrupts + - clocks + - resets + - dma-channels + - '#dma-cells' + +unevaluatedProperties: false + +examples: + - | + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + dma-controller@d4000000 { + compatible = "spacemit,k1-pdma"; + reg = <0x0 0xd4000000 0x0 0x4000>; + interrupts = <72>; + clocks = <&syscon_apmu CLK_DMA>; + resets = <&syscon_apmu RESET_DMA>; + dma-channels = <16>; + #dma-cells = <1>; + }; + }; From e73a9a13c99c5a55abfdb8c273651509be1eb5bb Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Fri, 22 Aug 2025 11:06:28 +0800 Subject: [PATCH 0743/2711] dmaengine: mmp_pdma: Add clock support Add support for retrieving and enabling an optional clock during mmp_pdma_probe(). It is optional because in Marvell devices such as "marvell,pdma-1.0" the clocks property is not a required property. But in SpacemiT K1 PDMA, "spacemit,k1-pdma" as the dt binding schema file stated, clocks is required. Signed-off-by: Guodong Xu Link: https://lore.kernel.org/r/20250822-working_dma_0701_v2-v5-2-f5c0eda734cc@riscstar.com Signed-off-by: Vinod Koul --- drivers/dma/mmp_pdma.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index a95d31103d30..4a6dbf558237 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -1019,6 +1020,7 @@ static int mmp_pdma_probe(struct platform_device *op) { struct mmp_pdma_device *pdev; struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev); + struct clk *clk; int i, ret, irq = 0; int dma_channels = 0, irq_num = 0; const enum dma_slave_buswidth widths = @@ -1037,6 +1039,10 @@ static int mmp_pdma_probe(struct platform_device *op) if (IS_ERR(pdev->base)) return PTR_ERR(pdev->base); + clk = devm_clk_get_optional_enabled(pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + if (pdev->dev->of_node) { /* Parse new and deprecated dma-channels properties */ if (of_property_read_u32(pdev->dev->of_node, "dma-channels", From fc72462bc6107b8babda05cad5bf8f7daf8bec20 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Fri, 22 Aug 2025 11:06:29 +0800 Subject: [PATCH 0744/2711] dmaengine: mmp_pdma: Add reset controller support Add support to acquire and deassert an optional hardware reset controller during mmp_pdma_probe(). It is optional because in Marvell devices such as "marvell,pdma-1.0" the resets property is not a required property. But in SpacemiT K1 PDMA, "spacemit,k1-pdma" as the dt binding schema file stated, resets is required. Signed-off-by: Guodong Xu Link: https://lore.kernel.org/r/20250822-working_dma_0701_v2-v5-3-f5c0eda734cc@riscstar.com Signed-off-by: Vinod Koul --- drivers/dma/mmp_pdma.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 4a6dbf558237..fe627efeaff0 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -1021,6 +1022,7 @@ static int mmp_pdma_probe(struct platform_device *op) struct mmp_pdma_device *pdev; struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev); struct clk *clk; + struct reset_control *rst; int i, ret, irq = 0; int dma_channels = 0, irq_num = 0; const enum dma_slave_buswidth widths = @@ -1043,6 +1045,11 @@ static int mmp_pdma_probe(struct platform_device *op) if (IS_ERR(clk)) return PTR_ERR(clk); + rst = devm_reset_control_get_optional_exclusive_deasserted(pdev->dev, + NULL); + if (IS_ERR(rst)) + return PTR_ERR(rst); + if (pdev->dev->of_node) { /* Parse new and deprecated dma-channels properties */ if (of_property_read_u32(pdev->dev->of_node, "dma-channels", From 35e40bf761fcb24b1355d6a8d48b5b10683fe1a3 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Fri, 22 Aug 2025 11:06:30 +0800 Subject: [PATCH 0745/2711] dmaengine: mmp_pdma: Add operations structure for controller abstraction Introduce mmp_pdma_ops structure to abstract 32-bit addressing operations and enable support for different controller variants. This prepares for adding 64-bit addressing support. The ops structure includes: - Hardware register operations (read/write DDADR, DSADR, DTADR) - Descriptor memory operations (manipulate descriptor structs) - Controller configuration (run bits, DMA mask) Convert existing 32-bit operations to use the new abstraction layer while maintaining backward compatibility. Cc: Dan Carpenter Signed-off-by: Guodong Xu Link: https://lore.kernel.org/r/20250822-working_dma_0701_v2-v5-4-f5c0eda734cc@riscstar.com Signed-off-by: Vinod Koul --- drivers/dma/mmp_pdma.c | 199 +++++++++++++++++++++++++++++++++-------- 1 file changed, 162 insertions(+), 37 deletions(-) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index fe627efeaff0..38d1a4cdfd0e 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -25,7 +25,7 @@ #define DCSR 0x0000 #define DALGN 0x00a0 #define DINT 0x00f0 -#define DDADR 0x0200 +#define DDADR(n) (0x0200 + ((n) << 4)) #define DSADR(n) (0x0204 + ((n) << 4)) #define DTADR(n) (0x0208 + ((n) << 4)) #define DCMD 0x020c @@ -120,12 +120,55 @@ struct mmp_pdma_phy { struct mmp_pdma_chan *vchan; }; +/** + * struct mmp_pdma_ops - Operations for the MMP PDMA controller + * + * Hardware Register Operations (read/write hardware registers): + * @write_next_addr: Function to program address of next descriptor into + * DDADR/DDADRH + * @read_src_addr: Function to read the source address from DSADR/DSADRH + * @read_dst_addr: Function to read the destination address from DTADR/DTADRH + * + * Descriptor Memory Operations (manipulate descriptor structs in memory): + * @set_desc_next_addr: Function to set next descriptor address in descriptor + * @set_desc_src_addr: Function to set the source address in descriptor + * @set_desc_dst_addr: Function to set the destination address in descriptor + * @get_desc_src_addr: Function to get the source address from descriptor + * @get_desc_dst_addr: Function to get the destination address from descriptor + * + * Controller Configuration: + * @run_bits: Control bits in DCSR register for channel start/stop + * @dma_mask: DMA addressing capability of controller. 0 to use OF/platform + * settings, or explicit mask like DMA_BIT_MASK(32/64) + */ +struct mmp_pdma_ops { + /* Hardware Register Operations */ + void (*write_next_addr)(struct mmp_pdma_phy *phy, dma_addr_t addr); + u64 (*read_src_addr)(struct mmp_pdma_phy *phy); + u64 (*read_dst_addr)(struct mmp_pdma_phy *phy); + + /* Descriptor Memory Operations */ + void (*set_desc_next_addr)(struct mmp_pdma_desc_hw *desc, + dma_addr_t addr); + void (*set_desc_src_addr)(struct mmp_pdma_desc_hw *desc, + dma_addr_t addr); + void (*set_desc_dst_addr)(struct mmp_pdma_desc_hw *desc, + dma_addr_t addr); + u64 (*get_desc_src_addr)(const struct mmp_pdma_desc_hw *desc); + u64 (*get_desc_dst_addr)(const struct mmp_pdma_desc_hw *desc); + + /* Controller Configuration */ + u32 run_bits; + u64 dma_mask; +}; + struct mmp_pdma_device { int dma_channels; void __iomem *base; struct device *dev; struct dma_device device; struct mmp_pdma_phy *phy; + const struct mmp_pdma_ops *ops; spinlock_t phy_lock; /* protect alloc/free phy channels */ }; @@ -138,24 +181,61 @@ struct mmp_pdma_device { #define to_mmp_pdma_dev(dmadev) \ container_of(dmadev, struct mmp_pdma_device, device) -static int mmp_pdma_config_write(struct dma_chan *dchan, - struct dma_slave_config *cfg, - enum dma_transfer_direction direction); - -static void set_desc(struct mmp_pdma_phy *phy, dma_addr_t addr) +/* For 32-bit PDMA */ +static void write_next_addr_32(struct mmp_pdma_phy *phy, dma_addr_t addr) { - u32 reg = (phy->idx << 4) + DDADR; - - writel(addr, phy->base + reg); + writel(addr, phy->base + DDADR(phy->idx)); } +static u64 read_src_addr_32(struct mmp_pdma_phy *phy) +{ + return readl(phy->base + DSADR(phy->idx)); +} + +static u64 read_dst_addr_32(struct mmp_pdma_phy *phy) +{ + return readl(phy->base + DTADR(phy->idx)); +} + +static void set_desc_next_addr_32(struct mmp_pdma_desc_hw *desc, dma_addr_t addr) +{ + desc->ddadr = addr; +} + +static void set_desc_src_addr_32(struct mmp_pdma_desc_hw *desc, dma_addr_t addr) +{ + desc->dsadr = addr; +} + +static void set_desc_dst_addr_32(struct mmp_pdma_desc_hw *desc, dma_addr_t addr) +{ + desc->dtadr = addr; +} + +static u64 get_desc_src_addr_32(const struct mmp_pdma_desc_hw *desc) +{ + return desc->dsadr; +} + +static u64 get_desc_dst_addr_32(const struct mmp_pdma_desc_hw *desc) +{ + return desc->dtadr; +} + +static int mmp_pdma_config_write(struct dma_chan *dchan, + struct dma_slave_config *cfg, + enum dma_transfer_direction direction); + static void enable_chan(struct mmp_pdma_phy *phy) { u32 reg, dalgn; + struct mmp_pdma_device *pdev; if (!phy->vchan) return; + pdev = to_mmp_pdma_dev(phy->vchan->chan.device); + reg = DRCMR(phy->vchan->drcmr); writel(DRCMR_MAPVLD | phy->idx, phy->base + reg); @@ -167,18 +247,29 @@ static void enable_chan(struct mmp_pdma_phy *phy) writel(dalgn, phy->base + DALGN); reg = (phy->idx << 2) + DCSR; - writel(readl(phy->base + reg) | DCSR_RUN, phy->base + reg); + writel(readl(phy->base + reg) | pdev->ops->run_bits, + phy->base + reg); } static void disable_chan(struct mmp_pdma_phy *phy) { - u32 reg; + u32 reg, dcsr; if (!phy) return; reg = (phy->idx << 2) + DCSR; - writel(readl(phy->base + reg) & ~DCSR_RUN, phy->base + reg); + dcsr = readl(phy->base + reg); + + if (phy->vchan) { + struct mmp_pdma_device *pdev; + + pdev = to_mmp_pdma_dev(phy->vchan->chan.device); + writel(dcsr & ~pdev->ops->run_bits, phy->base + reg); + } else { + /* If no vchan, just clear the RUN bit */ + writel(dcsr & ~DCSR_RUN, phy->base + reg); + } } static int clear_chan_irq(struct mmp_pdma_phy *phy) @@ -297,6 +388,7 @@ static void mmp_pdma_free_phy(struct mmp_pdma_chan *pchan) static void start_pending_queue(struct mmp_pdma_chan *chan) { struct mmp_pdma_desc_sw *desc; + struct mmp_pdma_device *pdev = to_mmp_pdma_dev(chan->chan.device); /* still in running, irq will start the pending list */ if (!chan->idle) { @@ -331,7 +423,7 @@ static void start_pending_queue(struct mmp_pdma_chan *chan) * Program the descriptor's address into the DMA controller, * then start the DMA transaction */ - set_desc(chan->phy, desc->async_tx.phys); + pdev->ops->write_next_addr(chan->phy, desc->async_tx.phys); enable_chan(chan->phy); chan->idle = false; } @@ -447,15 +539,14 @@ mmp_pdma_prep_memcpy(struct dma_chan *dchan, size_t len, unsigned long flags) { struct mmp_pdma_chan *chan; + struct mmp_pdma_device *pdev; struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new; size_t copy = 0; - if (!dchan) - return NULL; - - if (!len) + if (!dchan || !len) return NULL; + pdev = to_mmp_pdma_dev(dchan->device); chan = to_mmp_pdma_chan(dchan); chan->byte_align = false; @@ -478,13 +569,14 @@ mmp_pdma_prep_memcpy(struct dma_chan *dchan, chan->byte_align = true; new->desc.dcmd = chan->dcmd | (DCMD_LENGTH & copy); - new->desc.dsadr = dma_src; - new->desc.dtadr = dma_dst; + pdev->ops->set_desc_src_addr(&new->desc, dma_src); + pdev->ops->set_desc_dst_addr(&new->desc, dma_dst); if (!first) first = new; else - prev->desc.ddadr = new->async_tx.phys; + pdev->ops->set_desc_next_addr(&prev->desc, + new->async_tx.phys); new->async_tx.cookie = 0; async_tx_ack(&new->async_tx); @@ -528,6 +620,7 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, unsigned long flags, void *context) { struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan); + struct mmp_pdma_device *pdev = to_mmp_pdma_dev(dchan->device); struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new = NULL; size_t len, avail; struct scatterlist *sg; @@ -559,17 +652,18 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, new->desc.dcmd = chan->dcmd | (DCMD_LENGTH & len); if (dir == DMA_MEM_TO_DEV) { - new->desc.dsadr = addr; + pdev->ops->set_desc_src_addr(&new->desc, addr); new->desc.dtadr = chan->dev_addr; } else { new->desc.dsadr = chan->dev_addr; - new->desc.dtadr = addr; + pdev->ops->set_desc_dst_addr(&new->desc, addr); } if (!first) first = new; else - prev->desc.ddadr = new->async_tx.phys; + pdev->ops->set_desc_next_addr(&prev->desc, + new->async_tx.phys); new->async_tx.cookie = 0; async_tx_ack(&new->async_tx); @@ -609,12 +703,15 @@ mmp_pdma_prep_dma_cyclic(struct dma_chan *dchan, unsigned long flags) { struct mmp_pdma_chan *chan; + struct mmp_pdma_device *pdev; struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new; dma_addr_t dma_src, dma_dst; if (!dchan || !len || !period_len) return NULL; + pdev = to_mmp_pdma_dev(dchan->device); + /* the buffer length must be a multiple of period_len */ if (len % period_len != 0) return NULL; @@ -651,13 +748,14 @@ mmp_pdma_prep_dma_cyclic(struct dma_chan *dchan, new->desc.dcmd = (chan->dcmd | DCMD_ENDIRQEN | (DCMD_LENGTH & period_len)); - new->desc.dsadr = dma_src; - new->desc.dtadr = dma_dst; + pdev->ops->set_desc_src_addr(&new->desc, dma_src); + pdev->ops->set_desc_dst_addr(&new->desc, dma_dst); if (!first) first = new; else - prev->desc.ddadr = new->async_tx.phys; + pdev->ops->set_desc_next_addr(&prev->desc, + new->async_tx.phys); new->async_tx.cookie = 0; async_tx_ack(&new->async_tx); @@ -678,7 +776,7 @@ mmp_pdma_prep_dma_cyclic(struct dma_chan *dchan, first->async_tx.cookie = -EBUSY; /* make the cyclic link */ - new->desc.ddadr = first->async_tx.phys; + pdev->ops->set_desc_next_addr(&new->desc, first->async_tx.phys); chan->cyclic_first = first; return &first->async_tx; @@ -764,7 +862,9 @@ static unsigned int mmp_pdma_residue(struct mmp_pdma_chan *chan, dma_cookie_t cookie) { struct mmp_pdma_desc_sw *sw; - u32 curr, residue = 0; + struct mmp_pdma_device *pdev = to_mmp_pdma_dev(chan->chan.device); + u64 curr; + u32 residue = 0; bool passed = false; bool cyclic = chan->cyclic_first != NULL; @@ -776,17 +876,18 @@ static unsigned int mmp_pdma_residue(struct mmp_pdma_chan *chan, return 0; if (chan->dir == DMA_DEV_TO_MEM) - curr = readl(chan->phy->base + DTADR(chan->phy->idx)); + curr = pdev->ops->read_dst_addr(chan->phy); else - curr = readl(chan->phy->base + DSADR(chan->phy->idx)); + curr = pdev->ops->read_src_addr(chan->phy); list_for_each_entry(sw, &chan->chain_running, node) { - u32 start, end, len; + u64 start, end; + u32 len; if (chan->dir == DMA_DEV_TO_MEM) - start = sw->desc.dtadr; + start = pdev->ops->get_desc_dst_addr(&sw->desc); else - start = sw->desc.dsadr; + start = pdev->ops->get_desc_src_addr(&sw->desc); len = sw->desc.dcmd & DCMD_LENGTH; end = start + len; @@ -802,7 +903,7 @@ static unsigned int mmp_pdma_residue(struct mmp_pdma_chan *chan, if (passed) { residue += len; } else if (curr >= start && curr <= end) { - residue += end - curr; + residue += (u32)(end - curr); passed = true; } @@ -996,9 +1097,26 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq) return 0; } +static const struct mmp_pdma_ops marvell_pdma_v1_ops = { + .write_next_addr = write_next_addr_32, + .read_src_addr = read_src_addr_32, + .read_dst_addr = read_dst_addr_32, + .set_desc_next_addr = set_desc_next_addr_32, + .set_desc_src_addr = set_desc_src_addr_32, + .set_desc_dst_addr = set_desc_dst_addr_32, + .get_desc_src_addr = get_desc_src_addr_32, + .get_desc_dst_addr = get_desc_dst_addr_32, + .run_bits = (DCSR_RUN), + .dma_mask = 0, /* let OF/platform set DMA mask */ +}; + static const struct of_device_id mmp_pdma_dt_ids[] = { - { .compatible = "marvell,pdma-1.0", }, - {} + { + .compatible = "marvell,pdma-1.0", + .data = &marvell_pdma_v1_ops + }, { + /* sentinel */ + } }; MODULE_DEVICE_TABLE(of, mmp_pdma_dt_ids); @@ -1050,6 +1168,10 @@ static int mmp_pdma_probe(struct platform_device *op) if (IS_ERR(rst)) return PTR_ERR(rst); + pdev->ops = of_device_get_match_data(&op->dev); + if (!pdev->ops) + return -ENODEV; + if (pdev->dev->of_node) { /* Parse new and deprecated dma-channels properties */ if (of_property_read_u32(pdev->dev->of_node, "dma-channels", @@ -1111,7 +1233,10 @@ static int mmp_pdma_probe(struct platform_device *op) pdev->device.directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM); pdev->device.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; - if (pdev->dev->coherent_dma_mask) + /* Set DMA mask based on ops->dma_mask, or OF/platform */ + if (pdev->ops->dma_mask) + dma_set_mask(pdev->dev, pdev->ops->dma_mask); + else if (pdev->dev->coherent_dma_mask) dma_set_mask(pdev->dev, pdev->dev->coherent_dma_mask); else dma_set_mask(pdev->dev, DMA_BIT_MASK(64)); From 5cfe585d8624f7482505183dd0e4c534b061e822 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Fri, 22 Aug 2025 11:06:31 +0800 Subject: [PATCH 0746/2711] dmaengine: mmp_pdma: Add SpacemiT K1 PDMA support with 64-bit addressing Add support for SpacemiT K1 PDMA controller which features 64-bit addressing capabilities. The SpacemiT K1 PDMA extends the descriptor format with additional 32-bit words for high address bits, enabling access to memory beyond 4GB boundaries. The new spacemit_k1_pdma_ops provides necessary 64-bit address handling functions and k1 specific controller configurations. Key changes: - Add ARCH_SPACEMIT dependency to Kconfig - Define new high 32-bit address registers (DDADRH, DSADRH, DTADRH) - Add DCSR_LPAEEN bit for Long Physical Address Extension Enable - Implement 64-bit operations for SpacemiT K1 PDMA Signed-off-by: Guodong Xu Link: https://lore.kernel.org/r/20250822-working_dma_0701_v2-v5-5-f5c0eda734cc@riscstar.com Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- drivers/dma/mmp_pdma.c | 81 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 05c7c7d9e5a4..b8a74b1798ba 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -450,7 +450,7 @@ config MILBEAUT_XDMAC config MMP_PDMA tristate "MMP PDMA support" - depends on ARCH_MMP || ARCH_PXA || COMPILE_TEST + depends on ARCH_MMP || ARCH_PXA || ARCH_SPACEMIT || COMPILE_TEST select DMA_ENGINE help Support the MMP PDMA engine for PXA and MMP platform. diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 38d1a4cdfd0e..d07229a74886 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -28,6 +28,9 @@ #define DDADR(n) (0x0200 + ((n) << 4)) #define DSADR(n) (0x0204 + ((n) << 4)) #define DTADR(n) (0x0208 + ((n) << 4)) +#define DDADRH(n) (0x0300 + ((n) << 4)) +#define DSADRH(n) (0x0304 + ((n) << 4)) +#define DTADRH(n) (0x0308 + ((n) << 4)) #define DCMD 0x020c #define DCSR_RUN BIT(31) /* Run Bit (read / write) */ @@ -44,6 +47,7 @@ #define DCSR_EORSTOPEN BIT(26) /* STOP on an EOR */ #define DCSR_SETCMPST BIT(25) /* Set Descriptor Compare Status */ #define DCSR_CLRCMPST BIT(24) /* Clear Descriptor Compare Status */ +#define DCSR_LPAEEN BIT(21) /* Long Physical Address Extension Enable */ #define DCSR_CMPST BIT(10) /* The Descriptor Compare Status */ #define DCSR_EORINTR BIT(9) /* The end of Receive */ @@ -76,6 +80,16 @@ struct mmp_pdma_desc_hw { u32 dsadr; /* DSADR value for the current transfer */ u32 dtadr; /* DTADR value for the current transfer */ u32 dcmd; /* DCMD value for the current transfer */ + /* + * The following 32-bit words are only used in the 64-bit, ie. + * LPAE (Long Physical Address Extension) mode. + * They are used to specify the high 32 bits of the descriptor's + * addresses. + */ + u32 ddadrh; /* High 32-bit of DDADR */ + u32 dsadrh; /* High 32-bit of DSADR */ + u32 dtadrh; /* High 32-bit of DTADR */ + u32 rsvd; /* reserved */ } __aligned(32); struct mmp_pdma_desc_sw { @@ -222,6 +236,57 @@ static u64 get_desc_dst_addr_32(const struct mmp_pdma_desc_hw *desc) return desc->dtadr; } +/* For 64-bit PDMA */ +static void write_next_addr_64(struct mmp_pdma_phy *phy, dma_addr_t addr) +{ + writel(lower_32_bits(addr), phy->base + DDADR(phy->idx)); + writel(upper_32_bits(addr), phy->base + DDADRH(phy->idx)); +} + +static u64 read_src_addr_64(struct mmp_pdma_phy *phy) +{ + u32 low = readl(phy->base + DSADR(phy->idx)); + u32 high = readl(phy->base + DSADRH(phy->idx)); + + return ((u64)high << 32) | low; +} + +static u64 read_dst_addr_64(struct mmp_pdma_phy *phy) +{ + u32 low = readl(phy->base + DTADR(phy->idx)); + u32 high = readl(phy->base + DTADRH(phy->idx)); + + return ((u64)high << 32) | low; +} + +static void set_desc_next_addr_64(struct mmp_pdma_desc_hw *desc, dma_addr_t addr) +{ + desc->ddadr = lower_32_bits(addr); + desc->ddadrh = upper_32_bits(addr); +} + +static void set_desc_src_addr_64(struct mmp_pdma_desc_hw *desc, dma_addr_t addr) +{ + desc->dsadr = lower_32_bits(addr); + desc->dsadrh = upper_32_bits(addr); +} + +static void set_desc_dst_addr_64(struct mmp_pdma_desc_hw *desc, dma_addr_t addr) +{ + desc->dtadr = lower_32_bits(addr); + desc->dtadrh = upper_32_bits(addr); +} + +static u64 get_desc_src_addr_64(const struct mmp_pdma_desc_hw *desc) +{ + return ((u64)desc->dsadrh << 32) | desc->dsadr; +} + +static u64 get_desc_dst_addr_64(const struct mmp_pdma_desc_hw *desc) +{ + return ((u64)desc->dtadrh << 32) | desc->dtadr; +} + static int mmp_pdma_config_write(struct dma_chan *dchan, struct dma_slave_config *cfg, enum dma_transfer_direction direction); @@ -1110,10 +1175,26 @@ static const struct mmp_pdma_ops marvell_pdma_v1_ops = { .dma_mask = 0, /* let OF/platform set DMA mask */ }; +static const struct mmp_pdma_ops spacemit_k1_pdma_ops = { + .write_next_addr = write_next_addr_64, + .read_src_addr = read_src_addr_64, + .read_dst_addr = read_dst_addr_64, + .set_desc_next_addr = set_desc_next_addr_64, + .set_desc_src_addr = set_desc_src_addr_64, + .set_desc_dst_addr = set_desc_dst_addr_64, + .get_desc_src_addr = get_desc_src_addr_64, + .get_desc_dst_addr = get_desc_dst_addr_64, + .run_bits = (DCSR_RUN | DCSR_LPAEEN), + .dma_mask = DMA_BIT_MASK(64), /* force 64-bit DMA addr capability */ +}; + static const struct of_device_id mmp_pdma_dt_ids[] = { { .compatible = "marvell,pdma-1.0", .data = &marvell_pdma_v1_ops + }, { + .compatible = "spacemit,k1-pdma", + .data = &spacemit_k1_pdma_ops }, { /* sentinel */ } From a33e3b667d2f004fdfae6b442bd4676f6c510abb Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Thu, 21 Aug 2025 15:09:42 -0700 Subject: [PATCH 0747/2711] dmaengine: mv_xor: match alloc_wc and free_wc dma_alloc_wc is used but not dma_free_wc. Signed-off-by: Rosen Penev Link: https://lore.kernel.org/r/20250821220942.10578-1-rosenp@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/mv_xor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 1fdcb0f5c9e7..5e8386296046 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1013,7 +1013,7 @@ static int mv_xor_channel_remove(struct mv_xor_chan *mv_chan) dma_async_device_unregister(&mv_chan->dmadev); - dma_free_coherent(dev, MV_XOR_POOL_SIZE, + dma_free_wc(dev, MV_XOR_POOL_SIZE, mv_chan->dma_desc_pool_virt, mv_chan->dma_desc_pool); dma_unmap_single(dev, mv_chan->dummy_src_addr, MV_XOR_MIN_BYTE_COUNT, DMA_FROM_DEVICE); @@ -1163,7 +1163,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev, err_free_irq: free_irq(mv_chan->irq, mv_chan); err_free_dma: - dma_free_coherent(&pdev->dev, MV_XOR_POOL_SIZE, + dma_free_wc(&pdev->dev, MV_XOR_POOL_SIZE, mv_chan->dma_desc_pool_virt, mv_chan->dma_desc_pool); err_unmap_dst: dma_unmap_single(dma_dev->dev, mv_chan->dummy_dst_addr, From 5e742de97c806a4048418237ef1283e7d71eaf4b Mon Sep 17 00:00:00 2001 From: Devendra K Verma Date: Thu, 21 Aug 2025 17:45:05 +0530 Subject: [PATCH 0748/2711] dmaengine: dw-edma: Set status for callback_result DMA Engine has support for the callback_result which provides the status of the request and the residue. This helps in determining the correct status of the request and in efficient resource management of the request. The 'callback_result' method is preferred over the deprecated 'callback' method. Signed-off-by: Devendra K Verma Link: https://lore.kernel.org/r/20250821121505.318179-1-devverma@amd.com Signed-off-by: Vinod Koul --- drivers/dma/dw-edma/dw-edma-core.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index b43255f914f3..8e5f7defa6b6 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -584,6 +584,25 @@ dw_edma_device_prep_interleaved_dma(struct dma_chan *dchan, return dw_edma_device_transfer(&xfer); } +static void dw_hdma_set_callback_result(struct virt_dma_desc *vd, + enum dmaengine_tx_result result) +{ + u32 residue = 0; + struct dw_edma_desc *desc; + struct dmaengine_result *res; + + if (!vd->tx.callback_result) + return; + + desc = vd2dw_edma_desc(vd); + if (desc) + residue = desc->alloc_sz - desc->xfer_sz; + + res = &vd->tx_result; + res->result = result; + res->residue = residue; +} + static void dw_edma_done_interrupt(struct dw_edma_chan *chan) { struct dw_edma_desc *desc; @@ -597,6 +616,8 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan) case EDMA_REQ_NONE: desc = vd2dw_edma_desc(vd); if (!desc->chunks_alloc) { + dw_hdma_set_callback_result(vd, + DMA_TRANS_NOERROR); list_del(&vd->node); vchan_cookie_complete(vd); } @@ -633,6 +654,7 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan) spin_lock_irqsave(&chan->vc.lock, flags); vd = vchan_next_desc(&chan->vc); if (vd) { + dw_hdma_set_callback_result(vd, DMA_TRANS_ABORTED); list_del(&vd->node); vchan_cookie_complete(vd); } From cc0bacac6de7763a038550cf43cb94634d8be9cd Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Fri, 1 Aug 2025 10:48:22 +0200 Subject: [PATCH 0749/2711] dt-bindings: dma: rz-dmac: Document RZ/G3E family of SoCs The DMAC block on the RZ/G3E SoC is identical to the one found on the RZ/V2H(P) SoC. No driver changes are required, as `renesas,r9a09g057-dmac` will be used as a fallback compatible string on the RZ/G3E SoC. Signed-off-by: Tommaso Merciai Acked-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20250801084825.471011-3-tommaso.merciai.xr@bp.renesas.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml index 92b12762c472..f891cfcc48c7 100644 --- a/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml @@ -21,6 +21,11 @@ properties: - renesas,r9a08g045-dmac # RZ/G3S - const: renesas,rz-dmac + - items: + - enum: + - renesas,r9a09g047-dmac # RZ/G3E + - const: renesas,r9a09g057-dmac + - const: renesas,r9a09g057-dmac # RZ/V2H(P) reg: From 52c0164b2526bce7013fca193e076f6d9eec9c95 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 9 Jun 2025 11:19:05 +0100 Subject: [PATCH 0750/2711] coresight: trbe: Add ISB after TRBLIMITR write DEN0154 states that hardware will be allowed to ignore writes to TRB* registers while the trace buffer is enabled. Add an ISB to ensure that it's disabled before clearing the other registers. This is purely defensive because it's expected that arm_trbe_disable() would be called before teardown which has the required ISB. Fixes: a2b579c41fe9 ("coresight: trbe: Remove redundant disable call") Signed-off-by: James Clark Reviewed-by: Yeoreum Yun Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250609-james-cs-trblimitr-isb-v1-1-3a2aa4ee6770@linaro.org --- drivers/hwtracing/coresight/coresight-trbe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c index 8267dd1a2130..10f3fb401edf 100644 --- a/drivers/hwtracing/coresight/coresight-trbe.c +++ b/drivers/hwtracing/coresight/coresight-trbe.c @@ -257,6 +257,7 @@ static void trbe_drain_and_disable_local(struct trbe_cpudata *cpudata) static void trbe_reset_local(struct trbe_cpudata *cpudata) { write_sysreg_s(0, SYS_TRBLIMITR_EL1); + isb(); trbe_drain_buffer(); write_sysreg_s(0, SYS_TRBPTR_EL1); write_sysreg_s(0, SYS_TRBBASER_EL1); From 08d24e076d0fb9f90522ef69bf6cdae06e0919de Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 7 Jul 2025 10:55:27 +0100 Subject: [PATCH 0751/2711] coresight: Fix missing include for FIELD_GET Include the header for FIELD_GET which is only sometimes transitively included on some configs and kernel releases. Reported-by: Linux Kernel Functional Testing Closes: https://lists.linaro.org/archives/list/lkft-triage@lists.linaro.org/thread/6GKMK52PPRJVEYMEUHJP6BXF4CJAXOFL/ Fixes: a4e65842e114 ("coresight: Only check bottom two claim bits") Signed-off-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250707-james-coresight-bitfield-include-v1-1-aa0f4220ecfd@linaro.org --- drivers/hwtracing/coresight/coresight-core.c | 1 + drivers/hwtracing/coresight/coresight-etm4x-core.c | 1 + drivers/hwtracing/coresight/coresight-etm4x-sysfs.c | 1 + drivers/hwtracing/coresight/ultrasoc-smb.h | 1 + 4 files changed, 4 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index fa758cc21827..c2db94f2ab23 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -3,6 +3,7 @@ * Copyright (c) 2012, The Linux Foundation. All rights reserved. */ +#include #include #include #include diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 42e5d37403ad..cbea200489c8 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index ab251865b893..e9eeea6240d5 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -4,6 +4,7 @@ * Author: Mathieu Poirier */ +#include #include #include #include diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.h b/drivers/hwtracing/coresight/ultrasoc-smb.h index c4c111275627..323f0ccb6878 100644 --- a/drivers/hwtracing/coresight/ultrasoc-smb.h +++ b/drivers/hwtracing/coresight/ultrasoc-smb.h @@ -7,6 +7,7 @@ #ifndef _ULTRASOC_SMB_H #define _ULTRASOC_SMB_H +#include #include #include From 12d9a9dd9d8a4f1968073e7f34515896d1e22b78 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Mon, 30 Jun 2025 18:26:19 +0800 Subject: [PATCH 0752/2711] coresight: Only register perf symlink for sinks with alloc_buffer Ensure that etm_perf_add_symlink_sink() is only called for devices that implement the alloc_buffer operation. This prevents invalid symlink creation for dummy sinks that do not implement alloc_buffer. Without this check, perf may attempt to use a dummy sink that lacks alloc_buffer operationsu to initialise perf's ring buffer, leading to runtime failures. Fixes: 9d3ba0b6c0569 ("Coresight: Add coresight dummy driver") Signed-off-by: Yuanfang Zhang Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250630-etm_perf_sink-v1-1-e4a7211f9ad7@quicinc.com --- drivers/hwtracing/coresight/coresight-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index c2db94f2ab23..1accd7cbd54b 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1375,8 +1375,9 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) goto out_unlock; } - if (csdev->type == CORESIGHT_DEV_TYPE_SINK || - csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) { + if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || + csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && + sink_ops(csdev)->alloc_buffer) { ret = etm_perf_add_symlink_sink(csdev); if (ret) { From 9ba5502136eea6f3c95ab3c84220916fac89d844 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 3 Jul 2025 13:35:33 -0500 Subject: [PATCH 0753/2711] hwtracing: coresight: Use of_reserved_mem_region_to_resource() for "memory-region" Use the newly added of_reserved_mem_region_to_resource() function to handle "memory-region" properties. Signed-off-by: Rob Herring (Arm) Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250703183534.2075569-1-robh@kernel.org --- .../hwtracing/coresight/coresight-tmc-core.c | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 88afb16bb6be..be964656be93 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -634,25 +635,14 @@ static int of_tmc_get_reserved_resource_by_name(struct device *dev, const char *name, struct resource *res) { - int index, rc = -ENODEV; - struct device_node *node; + int rc = -ENODEV; - if (!is_of_node(dev->fwnode)) - return -ENODEV; - - index = of_property_match_string(dev->of_node, "memory-region-names", - name); - if (index < 0) + rc = of_reserved_mem_region_to_resource_byname(dev->of_node, name, res); + if (rc < 0) return rc; - node = of_parse_phandle(dev->of_node, "memory-region", index); - if (!node) - return rc; - - if (!of_address_to_resource(node, 0, res) && - res->start != 0 && resource_size(res) != 0) - rc = 0; - of_node_put(node); + if (res->start == 0 || resource_size(res) == 0) + rc = -ENODEV; return rc; } From 3252ee432e58871f81be211e5ef9630fc51e341f Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Wed, 11 Jun 2025 15:44:01 +0100 Subject: [PATCH 0754/2711] coresight: stm: Remove redundant NULL checks container_of() cannot return NULL, so the checks for NULL pointers are unnecessary and can be safely removed. As a result, this commit silences the following smatch warnings: coresight-stm.c:345 stm_generic_link() warn: can 'drvdata' even be NULL? coresight-stm.c:356 stm_generic_unlink() warn: can 'drvdata' even be NULL? coresight-stm.c:387 stm_generic_set_options() warn: can 'drvdata' even be NULL? coresight-stm.c:422 stm_generic_packet() warn: can 'drvdata' even be NULL? Signed-off-by: Leo Yan Reviewed-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250611-arm_cs_fix_smatch_warning_v1-v1-1-02a66c69b604@arm.com --- drivers/hwtracing/coresight/coresight-stm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index e45c6c7204b4..464b0c85c3f7 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -342,7 +342,7 @@ static int stm_generic_link(struct stm_data *stm_data, { struct stm_drvdata *drvdata = container_of(stm_data, struct stm_drvdata, stm); - if (!drvdata || !drvdata->csdev) + if (!drvdata->csdev) return -EINVAL; return coresight_enable_sysfs(drvdata->csdev); @@ -353,7 +353,7 @@ static void stm_generic_unlink(struct stm_data *stm_data, { struct stm_drvdata *drvdata = container_of(stm_data, struct stm_drvdata, stm); - if (!drvdata || !drvdata->csdev) + if (!drvdata->csdev) return; coresight_disable_sysfs(drvdata->csdev); @@ -384,7 +384,7 @@ static long stm_generic_set_options(struct stm_data *stm_data, { struct stm_drvdata *drvdata = container_of(stm_data, struct stm_drvdata, stm); - if (!(drvdata && coresight_get_mode(drvdata->csdev))) + if (!coresight_get_mode(drvdata->csdev)) return -EINVAL; if (channel >= drvdata->numsp) @@ -419,7 +419,7 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, struct stm_drvdata, stm); unsigned int stm_flags; - if (!(drvdata && coresight_get_mode(drvdata->csdev))) + if (!coresight_get_mode(drvdata->csdev)) return -EACCES; if (channel >= drvdata->numsp) From fd4ed47e9d6f7ab140fc2f060884c6d430fefca0 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Wed, 11 Jun 2025 15:44:02 +0100 Subject: [PATCH 0755/2711] coresight: perf: Use %px for printing pointers Use "%px" to print a pointer, which is better than casting the pointer to unsigned long and printing it with the "%lx" specifier. Note, the printing format will be updated as 64-bit value: # cat /sys/devices/cs_etm/sinks/trbe0 0x000000003744496a This commit dismisses the following smatch warnings: coresight-etm-perf.c:854 etm_perf_sink_name_show() warn: argument 4 to %lx specifier is cast from pointer coresight-etm-perf.c:946 etm_perf_cscfg_event_show() warn: argument 4 to %lx specifier is cast from pointer Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250611-arm_cs_fix_smatch_warning_v1-v1-2-02a66c69b604@arm.com --- drivers/hwtracing/coresight/coresight-etm-perf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index f1551c08ecb2..f677c08233ba 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -851,7 +851,7 @@ static ssize_t etm_perf_sink_name_show(struct device *dev, struct dev_ext_attribute *ea; ea = container_of(dattr, struct dev_ext_attribute, attr); - return scnprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)(ea->var)); + return scnprintf(buf, PAGE_SIZE, "0x%px\n", ea->var); } static struct dev_ext_attribute * @@ -943,7 +943,7 @@ static ssize_t etm_perf_cscfg_event_show(struct device *dev, struct dev_ext_attribute *ea; ea = container_of(dattr, struct dev_ext_attribute, attr); - return scnprintf(buf, PAGE_SIZE, "configid=0x%lx\n", (unsigned long)(ea->var)); + return scnprintf(buf, PAGE_SIZE, "configid=0x%px\n", ea->var); } int etm_perf_add_symlink_cscfg(struct device *dev, struct cscfg_config_desc *config_desc) From 931c93119d7228f0fd08dc8dfc229d438aacfc11 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Thu, 10 Jul 2025 13:27:20 +0800 Subject: [PATCH 0756/2711] dt-bindings: arm: Add device Trace Network On Chip definition Add a new coresight-tnoc.yaml file to describe the bindings required to define Trace Network On Chip (TNOC) in device trees. TNOC is an integration hierarchy which is a hardware component that integrates the functionalities of TPDA and funnels. It collects trace form subsystems and transfers to coresight sink. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Yuanfang Zhang Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250710-trace-noc-v11-1-f849075c40b8@quicinc.com --- .../bindings/arm/qcom,coresight-tnoc.yaml | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/qcom,coresight-tnoc.yaml diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tnoc.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tnoc.yaml new file mode 100644 index 000000000000..9d1c93a9ade3 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tnoc.yaml @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/qcom,coresight-tnoc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Trace Network On Chip - TNOC + +maintainers: + - Yuanfang Zhang + +description: > + The Trace Network On Chip (TNOC) is an integration hierarchy hardware + component that integrates the functionalities of TPDA and funnels. + + It sits in the different subsystem of SOC and aggregates the trace and + transports it to Aggregation TNOC or to coresight trace sink eventually. + TNOC embeds bridges for all the interfaces APB, ATB, TPDA and NTS (Narrow + Time Stamp). + + TNOC can take inputs from different trace sources i.e. ATB, TPDM. + + Note this binding is specifically intended for Aggregator TNOC instances. + +# Need a custom select here or 'arm,primecell' will match on lots of nodes +select: + properties: + compatible: + contains: + enum: + - qcom,coresight-tnoc + required: + - compatible + +properties: + $nodename: + pattern: "^tn(@[0-9a-f]+)$" + + compatible: + items: + - const: qcom,coresight-tnoc + - const: arm,primecell + + reg: + maxItems: 1 + + clock-names: + items: + - const: apb_pclk + + clocks: + items: + - description: APB register access clock + + in-ports: + $ref: /schemas/graph.yaml#/properties/ports + + patternProperties: + '^port(@[0-9a-f]{1,2})?$': + description: Input connections from CoreSight Trace Bus + $ref: /schemas/graph.yaml#/properties/port + + out-ports: + $ref: /schemas/graph.yaml#/properties/ports + additionalProperties: false + + properties: + port: + description: + Output connection to CoreSight Trace Bus + $ref: /schemas/graph.yaml#/properties/port + +required: + - compatible + - reg + - clocks + - clock-names + - in-ports + - out-ports + +additionalProperties: false + +examples: + - | + tn@109ab000 { + compatible = "qcom,coresight-tnoc", "arm,primecell"; + reg = <0x109ab000 0x4200>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tn_ag_in_tpdm_gcc: endpoint { + remote-endpoint = <&tpdm_gcc_out_tn_ag>; + }; + }; + }; + + out-ports { + port { + tn_ag_out_funnel_in1: endpoint { + remote-endpoint = <&funnel_in1_in_tn_ag>; + }; + }; + }; + }; +... From e54a52a28a362cb3a88d7996558f547666ee79e7 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Thu, 10 Jul 2025 13:27:21 +0800 Subject: [PATCH 0757/2711] coresight: add coresight Trace Network On Chip driver Add a driver to support Coresight device Trace Network On Chip (TNOC), which is an integration hierarchy integrating functionalities of TPDA and funnels. It aggregates the trace and transports to coresight trace bus. Compared to current configuration, it has the following advantages: 1. Reduce wires between subsystems. 2. Continue cleaning the infrastructure. 3. Reduce Data overhead by transporting raw data from source to target. +------------------------+ +-------------------------+ | Video Subsystem | |Video Subsystem | | +-------------+ | | +------------+ | | | Video TPDM | | | | Video TPDM | | | +-------------+ | | +------------+ | | | | | | | | v | | v | | +---------------+ | | +-----------+ | | | Video funnel | | | |Video TNOC | | | +---------------+ | | +-----------+ | +------------|-----------+ +------------|------------+ | | v-----+ | +--------------------|---------+ | | Multimedia v | | | Subsystem +--------+ | | | | TPDA | | v | +----|---+ | +---------------------+ | | | | Aggregator TNOC | | | | +----------|----------+ | +-- | | | | | | | | | | | +------v-----+ | | | | Funnel | | | | +------------+ | | +----------------|-------------+ | | | v v +--------------------+ +------------------+ | Coresight Sink | | Coresight Sink | +--------------------+ +------------------+ Current Configuration TNOC Reviewed-by: Leo Yan Signed-off-by: Yuanfang Zhang Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250710-trace-noc-v11-2-f849075c40b8@quicinc.com --- drivers/hwtracing/coresight/Kconfig | 12 + drivers/hwtracing/coresight/Makefile | 1 + drivers/hwtracing/coresight/coresight-tnoc.c | 242 +++++++++++++++++++ 3 files changed, 255 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-tnoc.c diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index f064e3d172b3..6a4239ebb582 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -268,4 +268,16 @@ config CORESIGHT_KUNIT_TESTS Enable Coresight unit tests. Only useful for development and not intended for production. +config CORESIGHT_TNOC + tristate "Coresight Trace Network On Chip driver" + help + This driver provides support for Trace Network On Chip (TNOC) component. + TNOC is an interconnect used to collect traces from various subsystems + and transport to a coresight trace sink. It sits in the different + tiles of SOC and aggregates the trace local to the tile and transports + it another tile or to coresight trace sink eventually. + + To compile this driver as a module, choose M here: the module will be + called coresight-tnoc. + endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 4e7cc3c5bf99..ab16d06783a5 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \ coresight-replicator.o +obj-$(CONFIG_CORESIGHT_TNOC) += coresight-tnoc.o obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm3x-y := coresight-etm3x-core.o coresight-etm-cp14.o \ coresight-etm3x-sysfs.o diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c new file mode 100644 index 000000000000..0e4164707eea --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-tnoc.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include + #include + #include + #include + #include + #include + #include + #include + +#include "coresight-priv.h" +#include "coresight-trace-id.h" + +#define TRACE_NOC_CTRL 0x008 +#define TRACE_NOC_XLD 0x010 +#define TRACE_NOC_FREQVAL 0x018 +#define TRACE_NOC_SYNCR 0x020 + +/* Enable generation of output ATB traffic.*/ +#define TRACE_NOC_CTRL_PORTEN BIT(0) +/* Sets the type of issued ATB FLAG packets.*/ +#define TRACE_NOC_CTRL_FLAGTYPE BIT(7) +/* Sets the type of issued ATB FREQ packet*/ +#define TRACE_NOC_CTRL_FREQTYPE BIT(8) + +#define TRACE_NOC_SYNC_INTERVAL 0xFFFF + +/* + * struct trace_noc_drvdata - specifics associated to a trace noc component + * @base: memory mapped base address for this component. + * @dev: device node for trace_noc_drvdata. + * @csdev: component vitals needed by the framework. + * @spinlock: serialize enable/disable operation. + * @atid: id for the trace packet. + */ +struct trace_noc_drvdata { + void __iomem *base; + struct device *dev; + struct coresight_device *csdev; + spinlock_t spinlock; + u32 atid; +}; + +DEFINE_CORESIGHT_DEVLIST(trace_noc_devs, "traceNoc"); + +static void trace_noc_enable_hw(struct trace_noc_drvdata *drvdata) +{ + u32 val; + + /* Set ATID */ + writel_relaxed(drvdata->atid, drvdata->base + TRACE_NOC_XLD); + + /* Set the data word count between 'SYNC' packets */ + writel_relaxed(TRACE_NOC_SYNC_INTERVAL, drvdata->base + TRACE_NOC_SYNCR); + + /* Set the Control register: + * - Set the FLAG packets to 'FLAG' packets + * - Set the FREQ packets to 'FREQ_TS' packets + * - Enable generation of output ATB traffic + */ + + val = readl_relaxed(drvdata->base + TRACE_NOC_CTRL); + + val &= ~TRACE_NOC_CTRL_FLAGTYPE; + val |= TRACE_NOC_CTRL_FREQTYPE; + val |= TRACE_NOC_CTRL_PORTEN; + + writel(val, drvdata->base + TRACE_NOC_CTRL); +} + +static int trace_noc_enable(struct coresight_device *csdev, struct coresight_connection *inport, + struct coresight_connection *outport) +{ + struct trace_noc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + scoped_guard(spinlock, &drvdata->spinlock) { + if (csdev->refcnt == 0) + trace_noc_enable_hw(drvdata); + + csdev->refcnt++; + } + + dev_dbg(drvdata->dev, "Trace NOC is enabled\n"); + return 0; +} + +static void trace_noc_disable(struct coresight_device *csdev, struct coresight_connection *inport, + struct coresight_connection *outport) +{ + struct trace_noc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + scoped_guard(spinlock, &drvdata->spinlock) { + if (--csdev->refcnt == 0) + writel(0x0, drvdata->base + TRACE_NOC_CTRL); + } + dev_dbg(drvdata->dev, "Trace NOC is disabled\n"); +} + +static int trace_noc_id(struct coresight_device *csdev, __maybe_unused enum cs_mode mode, + __maybe_unused struct coresight_device *sink) +{ + struct trace_noc_drvdata *drvdata; + + drvdata = dev_get_drvdata(csdev->dev.parent); + + return drvdata->atid; +} + +static const struct coresight_ops_link trace_noc_link_ops = { + .enable = trace_noc_enable, + .disable = trace_noc_disable, +}; + +static const struct coresight_ops trace_noc_cs_ops = { + .trace_id = trace_noc_id, + .link_ops = &trace_noc_link_ops, +}; + +static int trace_noc_init_default_data(struct trace_noc_drvdata *drvdata) +{ + int atid; + + atid = coresight_trace_id_get_system_id(); + if (atid < 0) + return atid; + + drvdata->atid = atid; + + return 0; +} + +static ssize_t traceid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long val; + struct trace_noc_drvdata *drvdata = dev_get_drvdata(dev->parent); + + val = drvdata->atid; + return sprintf(buf, "%#lx\n", val); +} +static DEVICE_ATTR_RO(traceid); + +static struct attribute *coresight_tnoc_attrs[] = { + &dev_attr_traceid.attr, + NULL, +}; + +static const struct attribute_group coresight_tnoc_group = { + .attrs = coresight_tnoc_attrs, +}; + +static const struct attribute_group *coresight_tnoc_groups[] = { + &coresight_tnoc_group, + NULL, +}; + +static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id) +{ + struct device *dev = &adev->dev; + struct coresight_platform_data *pdata; + struct trace_noc_drvdata *drvdata; + struct coresight_desc desc = { 0 }; + int ret; + + desc.name = coresight_alloc_device_name(&trace_noc_devs, dev); + if (!desc.name) + return -ENOMEM; + + pdata = coresight_get_platform_data(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + adev->dev.platform_data = pdata; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->dev = &adev->dev; + dev_set_drvdata(dev, drvdata); + + drvdata->base = devm_ioremap_resource(dev, &adev->res); + if (!drvdata->base) + return -ENOMEM; + + spin_lock_init(&drvdata->spinlock); + + ret = trace_noc_init_default_data(drvdata); + if (ret) + return ret; + + desc.ops = &trace_noc_cs_ops; + desc.type = CORESIGHT_DEV_TYPE_LINK; + desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG; + desc.pdata = adev->dev.platform_data; + desc.dev = &adev->dev; + desc.access = CSDEV_ACCESS_IOMEM(drvdata->base); + desc.groups = coresight_tnoc_groups; + drvdata->csdev = coresight_register(&desc); + if (IS_ERR(drvdata->csdev)) { + coresight_trace_id_put_system_id(drvdata->atid); + return PTR_ERR(drvdata->csdev); + } + pm_runtime_put(&adev->dev); + + return 0; +} + +static void trace_noc_remove(struct amba_device *adev) +{ + struct trace_noc_drvdata *drvdata = dev_get_drvdata(&adev->dev); + + coresight_unregister(drvdata->csdev); + coresight_trace_id_put_system_id(drvdata->atid); +} + +static struct amba_id trace_noc_ids[] = { + { + .id = 0x000f0c00, + .mask = 0x00ffff00, + }, + {}, +}; +MODULE_DEVICE_TABLE(amba, trace_noc_ids); + +static struct amba_driver trace_noc_driver = { + .drv = { + .name = "coresight-trace-noc", + .suppress_bind_attrs = true, + }, + .probe = trace_noc_probe, + .remove = trace_noc_remove, + .id_table = trace_noc_ids, +}; + +module_amba_driver(trace_noc_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Trace NOC driver"); From 6186e80a7440e0f9f45de6275b7f495ea11bd72c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 30 Aug 2025 19:01:10 +0200 Subject: [PATCH 0758/2711] dt-bindings: mtd samsung-s3c2410: Drop S3C2410 support Samsung S3C24xx family of SoCs was removed from the Linux kernel in the commit 61b7f8920b17 ("ARM: s3c: remove all s3c24xx support"), in January 2023. There are no in-kernel users of its compatibles. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Signed-off-by: Miquel Raynal --- .../bindings/mtd/samsung-s3c2410.txt | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt diff --git a/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt deleted file mode 100644 index 635455350660..000000000000 --- a/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt +++ /dev/null @@ -1,56 +0,0 @@ -* Samsung S3C2410 and compatible NAND flash controller - -Required properties: -- compatible : The possible values are: - "samsung,s3c2410-nand" - "samsung,s3c2412-nand" - "samsung,s3c2440-nand" -- reg : register's location and length. -- #address-cells, #size-cells : see nand-controller.yaml -- clocks : phandle to the nand controller clock -- clock-names : must contain "nand" - -Optional child nodes: -Child nodes representing the available nand chips. - -Optional child properties: -- nand-ecc-mode : see nand-controller.yaml -- nand-on-flash-bbt : see nand-controller.yaml - -Each child device node may optionally contain a 'partitions' sub-node, -which further contains sub-nodes describing the flash partition mapping. -See mtd.yaml for more detail. - -Example: - -nand-controller@4e000000 { - compatible = "samsung,s3c2440-nand"; - reg = <0x4e000000 0x40>; - - #address-cells = <1>; - #size-cells = <0>; - - clocks = <&clocks HCLK_NAND>; - clock-names = "nand"; - - nand { - nand-ecc-mode = "soft"; - nand-on-flash-bbt; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "u-boot"; - reg = <0 0x040000>; - }; - - partition@40000 { - label = "kernel"; - reg = <0x040000 0x500000>; - }; - }; - }; -}; From c9f62564252c21d739a5003e9b2d6ad0828aa7bd Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 30 Aug 2025 19:01:11 +0200 Subject: [PATCH 0759/2711] mtd: rawnand: s3c2410: Drop driver (no actual S3C64xx user) The s3c2410 NAND driver still supports S3C64xx platform, which in general is supported in the kernel. There are however no references of "s3c6400-nand" platform device ID or "s3c24xx-nand" driver, thus this driver cannot be instantiated for S3C64xx platform and is basically unused. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/Kconfig | 26 - drivers/mtd/nand/raw/Makefile | 1 - drivers/mtd/nand/raw/s3c2410.c | 1192 ----------------- .../linux/platform_data/mtd-nand-s3c2410.h | 70 - 4 files changed, 1289 deletions(-) delete mode 100644 drivers/mtd/nand/raw/s3c2410.c delete mode 100644 include/linux/platform_data/mtd-nand-s3c2410.h diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 4b99d9c422c3..f053806333c3 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -77,32 +77,6 @@ config MTD_NAND_NDFC help NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs -config MTD_NAND_S3C2410 - tristate "Samsung S3C NAND controller" - depends on ARCH_S3C64XX - help - This enables the NAND flash controller on the S3C24xx and S3C64xx - SoCs - - No board specific support is done by this driver, each board - must advertise a platform_device for the driver to attach. - -config MTD_NAND_S3C2410_DEBUG - bool "Samsung S3C NAND controller debug" - depends on MTD_NAND_S3C2410 - help - Enable debugging of the S3C NAND driver - -config MTD_NAND_S3C2410_CLKSTOP - bool "Samsung S3C NAND IDLE clock stop" - depends on MTD_NAND_S3C2410 - default n - help - Stop the clock to the NAND controller when there is no chip - selected to save power. This will mean there is a small delay - when the is NAND chip selected or released, but will save - approximately 5mA of power when there is nothing happening. - config MTD_NAND_SHARPSL tristate "Sharp SL Series (C7xx + others) NAND controller" depends on ARCH_PXA || COMPILE_TEST diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 711d043ad4f8..363cd18eaf16 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_MTD_NAND_DENALI) += denali.o obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o -obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c deleted file mode 100644 index 33130d75c5ba..000000000000 --- a/drivers/mtd/nand/raw/s3c2410.c +++ /dev/null @@ -1,1192 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright © 2004-2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * Samsung S3C2410/S3C2440/S3C2412 NAND driver -*/ - -#define pr_fmt(fmt) "nand-s3c2410: " fmt - -#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG -#define DEBUG -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#define S3C2410_NFREG(x) (x) - -#define S3C2410_NFCONF S3C2410_NFREG(0x00) -#define S3C2410_NFCMD S3C2410_NFREG(0x04) -#define S3C2410_NFADDR S3C2410_NFREG(0x08) -#define S3C2410_NFDATA S3C2410_NFREG(0x0C) -#define S3C2410_NFSTAT S3C2410_NFREG(0x10) -#define S3C2410_NFECC S3C2410_NFREG(0x14) -#define S3C2440_NFCONT S3C2410_NFREG(0x04) -#define S3C2440_NFCMD S3C2410_NFREG(0x08) -#define S3C2440_NFADDR S3C2410_NFREG(0x0C) -#define S3C2440_NFDATA S3C2410_NFREG(0x10) -#define S3C2440_NFSTAT S3C2410_NFREG(0x20) -#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) -#define S3C2412_NFSTAT S3C2410_NFREG(0x28) -#define S3C2412_NFMECC0 S3C2410_NFREG(0x34) -#define S3C2410_NFCONF_EN (1<<15) -#define S3C2410_NFCONF_INITECC (1<<12) -#define S3C2410_NFCONF_nFCE (1<<11) -#define S3C2410_NFCONF_TACLS(x) ((x)<<8) -#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) -#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) -#define S3C2410_NFSTAT_BUSY (1<<0) -#define S3C2440_NFCONF_TACLS(x) ((x)<<12) -#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8) -#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4) -#define S3C2440_NFCONT_INITECC (1<<4) -#define S3C2440_NFCONT_nFCE (1<<1) -#define S3C2440_NFCONT_ENABLE (1<<0) -#define S3C2440_NFSTAT_READY (1<<0) -#define S3C2412_NFCONF_NANDBOOT (1<<31) -#define S3C2412_NFCONT_INIT_MAIN_ECC (1<<5) -#define S3C2412_NFCONT_nFCE0 (1<<1) -#define S3C2412_NFSTAT_READY (1<<0) - -/* new oob placement block for use with hardware ecc generation - */ -static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - if (section) - return -ERANGE; - - oobregion->offset = 0; - oobregion->length = 3; - - return 0; -} - -static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - if (section) - return -ERANGE; - - oobregion->offset = 8; - oobregion->length = 8; - - return 0; -} - -static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = { - .ecc = s3c2410_ooblayout_ecc, - .free = s3c2410_ooblayout_free, -}; - -/* controller and mtd information */ - -struct s3c2410_nand_info; - -/** - * struct s3c2410_nand_mtd - driver MTD structure - * @chip: The NAND chip information. - * @set: The platform information supplied for this set of NAND chips. - * @info: Link back to the hardware information. -*/ -struct s3c2410_nand_mtd { - struct nand_chip chip; - struct s3c2410_nand_set *set; - struct s3c2410_nand_info *info; -}; - -enum s3c_cpu_type { - TYPE_S3C2410, - TYPE_S3C2412, - TYPE_S3C2440, -}; - -enum s3c_nand_clk_state { - CLOCK_DISABLE = 0, - CLOCK_ENABLE, - CLOCK_SUSPEND, -}; - -/* overview of the s3c2410 nand state */ - -/** - * struct s3c2410_nand_info - NAND controller state. - * @controller: Base controller structure. - * @mtds: An array of MTD instances on this controller. - * @platform: The platform data for this board. - * @device: The platform device we bound to. - * @clk: The clock resource for this controller. - * @regs: The area mapped for the hardware registers. - * @sel_reg: Pointer to the register controlling the NAND selection. - * @sel_bit: The bit in @sel_reg to select the NAND chip. - * @mtd_count: The number of MTDs created from this controller. - * @save_sel: The contents of @sel_reg to be saved over suspend. - * @clk_rate: The clock rate from @clk. - * @clk_state: The current clock state. - * @cpu_type: The exact type of this controller. - */ -struct s3c2410_nand_info { - /* mtd info */ - struct nand_controller controller; - struct s3c2410_nand_mtd *mtds; - struct s3c2410_platform_nand *platform; - - /* device info */ - struct device *device; - struct clk *clk; - void __iomem *regs; - void __iomem *sel_reg; - int sel_bit; - int mtd_count; - unsigned long save_sel; - unsigned long clk_rate; - enum s3c_nand_clk_state clk_state; - - enum s3c_cpu_type cpu_type; -}; - -struct s3c24XX_nand_devtype_data { - enum s3c_cpu_type type; -}; - -/* conversion functions */ - -static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd) -{ - return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd, - chip); -} - -static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd) -{ - return s3c2410_nand_mtd_toours(mtd)->info; -} - -static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev) -{ - return platform_get_drvdata(dev); -} - -static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev) -{ - return dev_get_platdata(&dev->dev); -} - -static inline int allow_clk_suspend(struct s3c2410_nand_info *info) -{ -#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP - return 1; -#else - return 0; -#endif -} - -/** - * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock. - * @info: The controller instance. - * @new_state: State to which clock should be set. - */ -static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info, - enum s3c_nand_clk_state new_state) -{ - if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND) - return; - - if (info->clk_state == CLOCK_ENABLE) { - if (new_state != CLOCK_ENABLE) - clk_disable_unprepare(info->clk); - } else { - if (new_state == CLOCK_ENABLE) - clk_prepare_enable(info->clk); - } - - info->clk_state = new_state; -} - -/* timing calculations */ - -#define NS_IN_KHZ 1000000 - -/** - * s3c_nand_calc_rate - calculate timing data. - * @wanted: The cycle time in nanoseconds. - * @clk: The clock rate in kHz. - * @max: The maximum divider value. - * - * Calculate the timing value from the given parameters. - */ -static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) -{ - int result; - - result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ); - - pr_debug("result %d from %ld, %d\n", result, clk, wanted); - - if (result > max) { - pr_err("%d ns is too big for current clock rate %ld\n", - wanted, clk); - return -1; - } - - if (result < 1) - result = 1; - - return result; -} - -#define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk)) - -/* controller setup */ - -/** - * s3c2410_nand_setrate - setup controller timing information. - * @info: The controller instance. - * - * Given the information supplied by the platform, calculate and set - * the necessary timing registers in the hardware to generate the - * necessary timing cycles to the hardware. - */ -static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) -{ - struct s3c2410_platform_nand *plat = info->platform; - int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; - int tacls, twrph0, twrph1; - unsigned long clkrate = clk_get_rate(info->clk); - unsigned long set, cfg, mask; - unsigned long flags; - - /* calculate the timing information for the controller */ - - info->clk_rate = clkrate; - clkrate /= 1000; /* turn clock into kHz for ease of use */ - - if (plat != NULL) { - tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max); - twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8); - twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8); - } else { - /* default timings */ - tacls = tacls_max; - twrph0 = 8; - twrph1 = 8; - } - - if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { - dev_err(info->device, "cannot get suitable timings\n"); - return -EINVAL; - } - - dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", - tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), - twrph1, to_ns(twrph1, clkrate)); - - switch (info->cpu_type) { - case TYPE_S3C2410: - mask = (S3C2410_NFCONF_TACLS(3) | - S3C2410_NFCONF_TWRPH0(7) | - S3C2410_NFCONF_TWRPH1(7)); - set = S3C2410_NFCONF_EN; - set |= S3C2410_NFCONF_TACLS(tacls - 1); - set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); - set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); - break; - - case TYPE_S3C2440: - case TYPE_S3C2412: - mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) | - S3C2440_NFCONF_TWRPH0(7) | - S3C2440_NFCONF_TWRPH1(7)); - - set = S3C2440_NFCONF_TACLS(tacls - 1); - set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); - set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); - break; - - default: - BUG(); - } - - local_irq_save(flags); - - cfg = readl(info->regs + S3C2410_NFCONF); - cfg &= ~mask; - cfg |= set; - writel(cfg, info->regs + S3C2410_NFCONF); - - local_irq_restore(flags); - - dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); - - return 0; -} - -/** - * s3c2410_nand_inithw - basic hardware initialisation - * @info: The hardware state. - * - * Do the basic initialisation of the hardware, using s3c2410_nand_setrate() - * to setup the hardware access speeds and set the controller to be enabled. -*/ -static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) -{ - int ret; - - ret = s3c2410_nand_setrate(info); - if (ret < 0) - return ret; - - switch (info->cpu_type) { - case TYPE_S3C2410: - default: - break; - - case TYPE_S3C2440: - case TYPE_S3C2412: - /* enable the controller and de-assert nFCE */ - - writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); - } - - return 0; -} - -/** - * s3c2410_nand_select_chip - select the given nand chip - * @this: NAND chip object. - * @chip: The chip number. - * - * This is called by the MTD layer to either select a given chip for the - * @mtd instance, or to indicate that the access has finished and the - * chip can be de-selected. - * - * The routine ensures that the nFCE line is correctly setup, and any - * platform specific selection code is called to route nFCE to the specific - * chip. - */ -static void s3c2410_nand_select_chip(struct nand_chip *this, int chip) -{ - struct s3c2410_nand_info *info; - struct s3c2410_nand_mtd *nmtd; - unsigned long cur; - - nmtd = nand_get_controller_data(this); - info = nmtd->info; - - if (chip != -1) - s3c2410_nand_clk_set_state(info, CLOCK_ENABLE); - - cur = readl(info->sel_reg); - - if (chip == -1) { - cur |= info->sel_bit; - } else { - if (nmtd->set != NULL && chip > nmtd->set->nr_chips) { - dev_err(info->device, "invalid chip %d\n", chip); - return; - } - - if (info->platform != NULL) { - if (info->platform->select_chip != NULL) - (info->platform->select_chip) (nmtd->set, chip); - } - - cur &= ~info->sel_bit; - } - - writel(cur, info->sel_reg); - - if (chip == -1) - s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); -} - -/* s3c2410_nand_hwcontrol - * - * Issue command and address cycles to the chip -*/ - -static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd, - unsigned int ctrl) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - writeb(cmd, info->regs + S3C2410_NFCMD); - else - writeb(cmd, info->regs + S3C2410_NFADDR); -} - -/* command and control functions */ - -static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd, - unsigned int ctrl) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - writeb(cmd, info->regs + S3C2440_NFCMD); - else - writeb(cmd, info->regs + S3C2440_NFADDR); -} - -/* s3c2410_nand_devready() - * - * returns 0 if the nand is busy, 1 if it is ready -*/ - -static int s3c2410_nand_devready(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; -} - -static int s3c2440_nand_devready(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; -} - -static int s3c2412_nand_devready(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY; -} - -/* ECC handling functions */ - -static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - unsigned int diff0, diff1, diff2; - unsigned int bit, byte; - - pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc); - - diff0 = read_ecc[0] ^ calc_ecc[0]; - diff1 = read_ecc[1] ^ calc_ecc[1]; - diff2 = read_ecc[2] ^ calc_ecc[2]; - - pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n", - __func__, 3, read_ecc, 3, calc_ecc, - diff0, diff1, diff2); - - if (diff0 == 0 && diff1 == 0 && diff2 == 0) - return 0; /* ECC is ok */ - - /* sometimes people do not think about using the ECC, so check - * to see if we have an 0xff,0xff,0xff read ECC and then ignore - * the error, on the assumption that this is an un-eccd page. - */ - if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff - && info->platform->ignore_unset_ecc) - return 0; - - /* Can we correct this ECC (ie, one row and column change). - * Note, this is similar to the 256 error code on smartmedia */ - - if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 && - ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 && - ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) { - /* calculate the bit position of the error */ - - bit = ((diff2 >> 3) & 1) | - ((diff2 >> 4) & 2) | - ((diff2 >> 5) & 4); - - /* calculate the byte position of the error */ - - byte = ((diff2 << 7) & 0x100) | - ((diff1 << 0) & 0x80) | - ((diff1 << 1) & 0x40) | - ((diff1 << 2) & 0x20) | - ((diff1 << 3) & 0x10) | - ((diff0 >> 4) & 0x08) | - ((diff0 >> 3) & 0x04) | - ((diff0 >> 2) & 0x02) | - ((diff0 >> 1) & 0x01); - - dev_dbg(info->device, "correcting error bit %d, byte %d\n", - bit, byte); - - dat[byte] ^= (1 << bit); - return 1; - } - - /* if there is only one bit difference in the ECC, then - * one of only a row or column parity has changed, which - * means the error is most probably in the ECC itself */ - - diff0 |= (diff1 << 8); - diff0 |= (diff2 << 16); - - /* equal to "(diff0 & ~(1 << __ffs(diff0)))" */ - if ((diff0 & (diff0 - 1)) == 0) - return 1; - - return -1; -} - -/* ECC functions - * - * These allow the s3c2410 and s3c2440 to use the controller's ECC - * generator block to ECC the data as it passes through] -*/ - -static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode) -{ - struct s3c2410_nand_info *info; - unsigned long ctrl; - - info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip)); - ctrl = readl(info->regs + S3C2410_NFCONF); - ctrl |= S3C2410_NFCONF_INITECC; - writel(ctrl, info->regs + S3C2410_NFCONF); -} - -static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode) -{ - struct s3c2410_nand_info *info; - unsigned long ctrl; - - info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip)); - ctrl = readl(info->regs + S3C2440_NFCONT); - writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC, - info->regs + S3C2440_NFCONT); -} - -static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode) -{ - struct s3c2410_nand_info *info; - unsigned long ctrl; - - info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip)); - ctrl = readl(info->regs + S3C2440_NFCONT); - writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT); -} - -static int s3c2410_nand_calculate_ecc(struct nand_chip *chip, - const u_char *dat, u_char *ecc_code) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - - ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0); - ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1); - ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2); - - pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code); - - return 0; -} - -static int s3c2412_nand_calculate_ecc(struct nand_chip *chip, - const u_char *dat, u_char *ecc_code) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - unsigned long ecc = readl(info->regs + S3C2412_NFMECC0); - - ecc_code[0] = ecc; - ecc_code[1] = ecc >> 8; - ecc_code[2] = ecc >> 16; - - pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code); - - return 0; -} - -static int s3c2440_nand_calculate_ecc(struct nand_chip *chip, - const u_char *dat, u_char *ecc_code) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - unsigned long ecc = readl(info->regs + S3C2440_NFMECC0); - - ecc_code[0] = ecc; - ecc_code[1] = ecc >> 8; - ecc_code[2] = ecc >> 16; - - pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff); - - return 0; -} - -/* over-ride the standard functions for a little more speed. We can - * use read/write block to move the data buffers to/from the controller -*/ - -static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len) -{ - readsb(this->legacy.IO_ADDR_R, buf, len); -} - -static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len) -{ - struct mtd_info *mtd = nand_to_mtd(this); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - - readsl(info->regs + S3C2440_NFDATA, buf, len >> 2); - - /* cleanup if we've got less than a word to do */ - if (len & 3) { - buf += len & ~3; - - for (; len & 3; len--) - *buf++ = readb(info->regs + S3C2440_NFDATA); - } -} - -static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf, - int len) -{ - writesb(this->legacy.IO_ADDR_W, buf, len); -} - -static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf, - int len) -{ - struct mtd_info *mtd = nand_to_mtd(this); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - - writesl(info->regs + S3C2440_NFDATA, buf, len >> 2); - - /* cleanup any fractional write */ - if (len & 3) { - buf += len & ~3; - - for (; len & 3; len--, buf++) - writeb(*buf, info->regs + S3C2440_NFDATA); - } -} - -/* device management functions */ - -static void s3c24xx_nand_remove(struct platform_device *pdev) -{ - struct s3c2410_nand_info *info = to_nand_info(pdev); - - if (info == NULL) - return; - - /* Release all our mtds and their partitions, then go through - * freeing the resources used - */ - - if (info->mtds != NULL) { - struct s3c2410_nand_mtd *ptr = info->mtds; - int mtdno; - - for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) { - pr_debug("releasing mtd %d (%p)\n", mtdno, ptr); - WARN_ON(mtd_device_unregister(nand_to_mtd(&ptr->chip))); - nand_cleanup(&ptr->chip); - } - } - - /* free the common resources */ - - if (!IS_ERR(info->clk)) - s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); -} - -static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, - struct s3c2410_nand_mtd *mtd, - struct s3c2410_nand_set *set) -{ - if (set) { - struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip); - - mtdinfo->name = set->name; - - return mtd_device_register(mtdinfo, set->partitions, - set->nr_partitions); - } - - return -ENODEV; -} - -static int s3c2410_nand_setup_interface(struct nand_chip *chip, int csline, - const struct nand_interface_config *conf) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - struct s3c2410_platform_nand *pdata = info->platform; - const struct nand_sdr_timings *timings; - int tacls; - - timings = nand_get_sdr_timings(conf); - if (IS_ERR(timings)) - return -ENOTSUPP; - - tacls = timings->tCLS_min - timings->tWP_min; - if (tacls < 0) - tacls = 0; - - pdata->tacls = DIV_ROUND_UP(tacls, 1000); - pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000); - pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000); - - return s3c2410_nand_setrate(info); -} - -/** - * s3c2410_nand_init_chip - initialise a single instance of an chip - * @info: The base NAND controller the chip is on. - * @nmtd: The new controller MTD instance to fill in. - * @set: The information passed from the board specific platform data. - * - * Initialise the given @nmtd from the information in @info and @set. This - * readies the structure for use with the MTD layer functions by ensuring - * all pointers are setup and the necessary control routines selected. - */ -static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, - struct s3c2410_nand_mtd *nmtd, - struct s3c2410_nand_set *set) -{ - struct device_node *np = info->device->of_node; - struct nand_chip *chip = &nmtd->chip; - void __iomem *regs = info->regs; - - nand_set_flash_node(chip, set->of_node); - - chip->legacy.write_buf = s3c2410_nand_write_buf; - chip->legacy.read_buf = s3c2410_nand_read_buf; - chip->legacy.select_chip = s3c2410_nand_select_chip; - chip->legacy.chip_delay = 50; - nand_set_controller_data(chip, nmtd); - chip->options = set->options; - chip->controller = &info->controller; - - /* - * let's keep behavior unchanged for legacy boards booting via pdata and - * auto-detect timings only when booting with a device tree. - */ - if (!np) - chip->options |= NAND_KEEP_TIMINGS; - - switch (info->cpu_type) { - case TYPE_S3C2410: - chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA; - info->sel_reg = regs + S3C2410_NFCONF; - info->sel_bit = S3C2410_NFCONF_nFCE; - chip->legacy.cmd_ctrl = s3c2410_nand_hwcontrol; - chip->legacy.dev_ready = s3c2410_nand_devready; - break; - - case TYPE_S3C2440: - chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA; - info->sel_reg = regs + S3C2440_NFCONT; - info->sel_bit = S3C2440_NFCONT_nFCE; - chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol; - chip->legacy.dev_ready = s3c2440_nand_devready; - chip->legacy.read_buf = s3c2440_nand_read_buf; - chip->legacy.write_buf = s3c2440_nand_write_buf; - break; - - case TYPE_S3C2412: - chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA; - info->sel_reg = regs + S3C2440_NFCONT; - info->sel_bit = S3C2412_NFCONT_nFCE0; - chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol; - chip->legacy.dev_ready = s3c2412_nand_devready; - - if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT) - dev_info(info->device, "System booted from NAND\n"); - - break; - } - - chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W; - - nmtd->info = info; - nmtd->set = set; - - chip->ecc.engine_type = info->platform->engine_type; - - /* - * If you use u-boot BBT creation code, specifying this flag will - * let the kernel fish out the BBT from the NAND. - */ - if (set->flash_bbt) - chip->bbt_options |= NAND_BBT_USE_FLASH; -} - -/** - * s3c2410_nand_attach_chip - Init the ECC engine after NAND scan - * @chip: The NAND chip - * - * This hook is called by the core after the identification of the NAND chip, - * once the relevant per-chip information is up to date.. This call ensure that - * we update the internal state accordingly. - * - * The internal state is currently limited to the ECC state information. -*/ -static int s3c2410_nand_attach_chip(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - - switch (chip->ecc.engine_type) { - - case NAND_ECC_ENGINE_TYPE_NONE: - dev_info(info->device, "ECC disabled\n"); - break; - - case NAND_ECC_ENGINE_TYPE_SOFT: - /* - * This driver expects Hamming based ECC when engine_type is set - * to NAND_ECC_ENGINE_TYPE_SOFT. Force ecc.algo to - * NAND_ECC_ALGO_HAMMING to avoid adding an extra ecc_algo field - * to s3c2410_platform_nand. - */ - chip->ecc.algo = NAND_ECC_ALGO_HAMMING; - dev_info(info->device, "soft ECC\n"); - break; - - case NAND_ECC_ENGINE_TYPE_ON_HOST: - chip->ecc.calculate = s3c2410_nand_calculate_ecc; - chip->ecc.correct = s3c2410_nand_correct_data; - chip->ecc.strength = 1; - - switch (info->cpu_type) { - case TYPE_S3C2410: - chip->ecc.hwctl = s3c2410_nand_enable_hwecc; - chip->ecc.calculate = s3c2410_nand_calculate_ecc; - break; - - case TYPE_S3C2412: - chip->ecc.hwctl = s3c2412_nand_enable_hwecc; - chip->ecc.calculate = s3c2412_nand_calculate_ecc; - break; - - case TYPE_S3C2440: - chip->ecc.hwctl = s3c2440_nand_enable_hwecc; - chip->ecc.calculate = s3c2440_nand_calculate_ecc; - break; - } - - dev_dbg(info->device, "chip %p => page shift %d\n", - chip, chip->page_shift); - - /* change the behaviour depending on whether we are using - * the large or small page nand device */ - if (chip->page_shift > 10) { - chip->ecc.size = 256; - chip->ecc.bytes = 3; - } else { - chip->ecc.size = 512; - chip->ecc.bytes = 3; - mtd_set_ooblayout(nand_to_mtd(chip), - &s3c2410_ooblayout_ops); - } - - dev_info(info->device, "hardware ECC\n"); - break; - - default: - dev_err(info->device, "invalid ECC mode!\n"); - return -EINVAL; - } - - if (chip->bbt_options & NAND_BBT_USE_FLASH) - chip->options |= NAND_SKIP_BBTSCAN; - - return 0; -} - -static const struct nand_controller_ops s3c24xx_nand_controller_ops = { - .attach_chip = s3c2410_nand_attach_chip, - .setup_interface = s3c2410_nand_setup_interface, -}; - -static int s3c24xx_nand_probe_dt(struct platform_device *pdev) -{ - const struct s3c24XX_nand_devtype_data *devtype_data; - struct s3c2410_platform_nand *pdata; - struct s3c2410_nand_info *info = platform_get_drvdata(pdev); - struct device_node *np = pdev->dev.of_node, *child; - struct s3c2410_nand_set *sets; - - devtype_data = of_device_get_match_data(&pdev->dev); - if (!devtype_data) - return -ENODEV; - - info->cpu_type = devtype_data->type; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - pdev->dev.platform_data = pdata; - - pdata->nr_sets = of_get_child_count(np); - if (!pdata->nr_sets) - return 0; - - sets = devm_kcalloc(&pdev->dev, pdata->nr_sets, sizeof(*sets), - GFP_KERNEL); - if (!sets) - return -ENOMEM; - - pdata->sets = sets; - - for_each_available_child_of_node(np, child) { - sets->name = (char *)child->name; - sets->of_node = child; - sets->nr_chips = 1; - - of_node_get(child); - - sets++; - } - - return 0; -} - -static int s3c24xx_nand_probe_pdata(struct platform_device *pdev) -{ - struct s3c2410_nand_info *info = platform_get_drvdata(pdev); - - info->cpu_type = platform_get_device_id(pdev)->driver_data; - - return 0; -} - -/* s3c24xx_nand_probe - * - * called by device layer when it finds a device matching - * one our driver can handled. This code checks to see if - * it can allocate all necessary resources then calls the - * nand layer to look for devices -*/ -static int s3c24xx_nand_probe(struct platform_device *pdev) -{ - struct s3c2410_platform_nand *plat; - struct s3c2410_nand_info *info; - struct s3c2410_nand_mtd *nmtd; - struct s3c2410_nand_set *sets; - struct resource *res; - int err = 0; - int size; - int nr_sets; - int setno; - - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); - if (info == NULL) { - err = -ENOMEM; - goto exit_error; - } - - platform_set_drvdata(pdev, info); - - nand_controller_init(&info->controller); - info->controller.ops = &s3c24xx_nand_controller_ops; - - /* get the clock source and enable it */ - - info->clk = devm_clk_get(&pdev->dev, "nand"); - if (IS_ERR(info->clk)) { - dev_err(&pdev->dev, "failed to get clock\n"); - err = -ENOENT; - goto exit_error; - } - - s3c2410_nand_clk_set_state(info, CLOCK_ENABLE); - - if (pdev->dev.of_node) - err = s3c24xx_nand_probe_dt(pdev); - else - err = s3c24xx_nand_probe_pdata(pdev); - - if (err) - goto exit_error; - - plat = to_nand_plat(pdev); - - /* allocate and map the resource */ - - /* currently we assume we have the one resource */ - res = pdev->resource; - size = resource_size(res); - - info->device = &pdev->dev; - info->platform = plat; - - info->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(info->regs)) { - err = PTR_ERR(info->regs); - goto exit_error; - } - - dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs); - - if (!plat->sets || plat->nr_sets < 1) { - err = -EINVAL; - goto exit_error; - } - - sets = plat->sets; - nr_sets = plat->nr_sets; - - info->mtd_count = nr_sets; - - /* allocate our information */ - - size = nr_sets * sizeof(*info->mtds); - info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (info->mtds == NULL) { - err = -ENOMEM; - goto exit_error; - } - - /* initialise all possible chips */ - - nmtd = info->mtds; - - for (setno = 0; setno < nr_sets; setno++, nmtd++, sets++) { - struct mtd_info *mtd = nand_to_mtd(&nmtd->chip); - - pr_debug("initialising set %d (%p, info %p)\n", - setno, nmtd, info); - - mtd->dev.parent = &pdev->dev; - s3c2410_nand_init_chip(info, nmtd, sets); - - err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1); - if (err) - goto exit_error; - - s3c2410_nand_add_partition(info, nmtd, sets); - } - - /* initialise the hardware */ - err = s3c2410_nand_inithw(info); - if (err != 0) - goto exit_error; - - if (allow_clk_suspend(info)) { - dev_info(&pdev->dev, "clock idle support enabled\n"); - s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); - } - - return 0; - - exit_error: - s3c24xx_nand_remove(pdev); - - if (err == 0) - err = -EINVAL; - return err; -} - -/* PM Support */ -#ifdef CONFIG_PM - -static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm) -{ - struct s3c2410_nand_info *info = platform_get_drvdata(dev); - - if (info) { - info->save_sel = readl(info->sel_reg); - - /* For the moment, we must ensure nFCE is high during - * the time we are suspended. This really should be - * handled by suspending the MTDs we are using, but - * that is currently not the case. */ - - writel(info->save_sel | info->sel_bit, info->sel_reg); - - s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); - } - - return 0; -} - -static int s3c24xx_nand_resume(struct platform_device *dev) -{ - struct s3c2410_nand_info *info = platform_get_drvdata(dev); - unsigned long sel; - - if (info) { - s3c2410_nand_clk_set_state(info, CLOCK_ENABLE); - s3c2410_nand_inithw(info); - - /* Restore the state of the nFCE line. */ - - sel = readl(info->sel_reg); - sel &= ~info->sel_bit; - sel |= info->save_sel & info->sel_bit; - writel(sel, info->sel_reg); - - s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); - } - - return 0; -} - -#else -#define s3c24xx_nand_suspend NULL -#define s3c24xx_nand_resume NULL -#endif - -/* driver device registration */ - -static const struct platform_device_id s3c24xx_driver_ids[] = { - { - .name = "s3c6400-nand", - .driver_data = TYPE_S3C2412, /* compatible with 2412 */ - }, - { } -}; - -MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); - -static struct platform_driver s3c24xx_nand_driver = { - .probe = s3c24xx_nand_probe, - .remove = s3c24xx_nand_remove, - .suspend = s3c24xx_nand_suspend, - .resume = s3c24xx_nand_resume, - .id_table = s3c24xx_driver_ids, - .driver = { - .name = "s3c24xx-nand", - }, -}; - -module_platform_driver(s3c24xx_nand_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ben Dooks "); -MODULE_DESCRIPTION("S3C24XX MTD NAND driver"); diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h deleted file mode 100644 index 25390fc3e795..000000000000 --- a/include/linux/platform_data/mtd-nand-s3c2410.h +++ /dev/null @@ -1,70 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2004 Simtec Electronics - * Ben Dooks - * - * S3C2410 - NAND device controller platform_device info -*/ - -#ifndef __MTD_NAND_S3C2410_H -#define __MTD_NAND_S3C2410_H - -#include - -/** - * struct s3c2410_nand_set - define a set of one or more nand chips - * @flash_bbt: Openmoko u-boot can create a Bad Block Table - * Setting this flag will allow the kernel to - * look for it at boot time and also skip the NAND - * scan. - * @options: Default value to set into 'struct nand_chip' options. - * @nr_chips: Number of chips in this set - * @nr_partitions: Number of partitions pointed to by @partitions - * @name: Name of set (optional) - * @nr_map: Map for low-layer logical to physical chip numbers (option) - * @partitions: The mtd partition list - * - * define a set of one or more nand chips registered with an unique mtd. Also - * allows to pass flag to the underlying NAND layer. 'disable_ecc' will trigger - * a warning at boot time. - */ -struct s3c2410_nand_set { - unsigned int flash_bbt:1; - - unsigned int options; - int nr_chips; - int nr_partitions; - char *name; - int *nr_map; - struct mtd_partition *partitions; - struct device_node *of_node; -}; - -struct s3c2410_platform_nand { - /* timing information for controller, all times in nanoseconds */ - - int tacls; /* time for active CLE/ALE to nWE/nOE */ - int twrph0; /* active time for nWE/nOE */ - int twrph1; /* time for release CLE/ALE from nWE/nOE inactive */ - - unsigned int ignore_unset_ecc:1; - - enum nand_ecc_engine_type engine_type; - - int nr_sets; - struct s3c2410_nand_set *sets; - - void (*select_chip)(struct s3c2410_nand_set *, - int chip); -}; - -/** - * s3c_nand_set_platdata() - register NAND platform data. - * @nand: The NAND platform data to register with s3c_device_nand. - * - * This function copies the given NAND platform data, @nand and registers - * it with the s3c_device_nand. This allows @nand to be __initdata. -*/ -extern void s3c_nand_set_platdata(struct s3c2410_platform_nand *nand); - -#endif /*__MTD_NAND_S3C2410_H */ From 1086237f0a91c7e70eede1bc83ce54f521db64b0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Aug 2025 20:16:35 -0700 Subject: [PATCH 0760/2711] perf annotate: Use a hashmap to save type data It can slowdown annotation browser if objdump is processing large DWARF data. Let's add a hashmap to save the data type info for each line. Note that this is needed for TUI only because stdio only processes each line once. TUI will display the same line whenever it refreshes the screen. Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250816031635.25318-13-namhyung@kernel.org [ Add lines around an if block and use zfree() in one case, acked by Namhyung ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 34 ++++++++++++++++++++++++++++++- tools/perf/util/annotate.c | 29 ++++++++++++++++++++++++-- tools/perf/util/annotate.h | 2 ++ 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 9aa3c1ba22f5..b770a8d4623e 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -6,6 +6,7 @@ #include "../../util/debug.h" #include "../../util/debuginfo.h" #include "../../util/dso.h" +#include "../../util/hashmap.h" #include "../../util/hist.h" #include "../../util/sort.h" #include "../../util/map.h" @@ -15,6 +16,7 @@ #include "../../util/evlist.h" #include "../../util/thread.h" #include +#include #include #include #include @@ -36,6 +38,7 @@ struct annotate_browser { struct hist_entry *he; struct debuginfo *dbg; struct evsel *evsel; + struct hashmap *type_hash; bool searching_backwards; char search_bf[128]; }; @@ -43,6 +46,16 @@ struct annotate_browser { /* A copy of target hist_entry for perf top. */ static struct hist_entry annotate_he; +static size_t type_hash(long key, void *ctx __maybe_unused) +{ + return key; +} + +static bool type_equal(long key1, long key2, void *ctx __maybe_unused) +{ + return key1 == key2; +} + static inline struct annotation *browser__annotation(struct ui_browser *browser) { struct map_symbol *ms = browser->priv; @@ -130,6 +143,9 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int if (!browser->navkeypressed) ops.width += 1; + if (!IS_ERR_OR_NULL(ab->type_hash)) + apd.type_hash = ab->type_hash; + annotation_line__write(al, notes, &ops, &apd); if (ops.current_entry) @@ -1051,6 +1067,10 @@ show_sup_ins: annotate_opts.code_with_type ^= 1; if (browser->dbg == NULL) browser->dbg = dso__debuginfo(map__dso(ms->map)); + if (browser->type_hash == NULL) { + browser->type_hash = hashmap__new(type_hash, type_equal, + /*ctx=*/NULL); + } annotate_browser__show(&browser->b, title, help); annotate_browser__debuginfo_warning(browser); continue; @@ -1145,8 +1165,10 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms, ui_helpline__push("Press ESC to exit"); - if (annotate_opts.code_with_type) + if (annotate_opts.code_with_type) { browser.dbg = dso__debuginfo(dso); + browser.type_hash = hashmap__new(type_hash, type_equal, /*ctx=*/NULL); + } browser.b.width = notes->src->widths.max_line_len; browser.b.nr_entries = notes->src->nr_entries; @@ -1159,6 +1181,16 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms, ret = annotate_browser__run(&browser, evsel, hbt); debuginfo__delete(browser.dbg); + + if (!IS_ERR_OR_NULL(browser.type_hash)) { + struct hashmap_entry *cur; + size_t bkt; + + hashmap__for_each_entry(browser.type_hash, cur, bkt) + zfree(&cur->pvalue); + hashmap__free(browser.type_hash); + } + if (not_annotated && !notes->src->tried_source) annotated_source__purge(notes->src); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index bea3457a0063..c9b220d9f924 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1954,11 +1954,17 @@ err: return -ENOMEM; } +struct type_hash_entry { + struct annotated_data_type *type; + int offset; +}; + static int disasm_line__snprint_type_info(struct disasm_line *dl, char *buf, int len, struct annotation_print_data *apd) { - struct annotated_data_type *data_type; + struct annotated_data_type *data_type = NULL; + struct type_hash_entry *entry = NULL; char member[256]; int offset = 0; int printed; @@ -1968,7 +1974,26 @@ static int disasm_line__snprint_type_info(struct disasm_line *dl, if (!annotate_opts.code_with_type || apd->dbg == NULL) return 1; - data_type = __hist_entry__get_data_type(apd->he, apd->arch, apd->dbg, dl, &offset); + if (apd->type_hash) { + hashmap__find(apd->type_hash, dl->al.offset, &entry); + if (entry != NULL) { + data_type = entry->type; + offset = entry->offset; + } + } + + if (data_type == NULL) + data_type = __hist_entry__get_data_type(apd->he, apd->arch, apd->dbg, dl, &offset); + + if (apd->type_hash && entry == NULL) { + entry = malloc(sizeof(*entry)); + if (entry != NULL) { + entry->type = data_type; + entry->offset = offset; + hashmap__add(apd->type_hash, dl->al.offset, entry); + } + } + if (!needs_type_info(data_type)) return 1; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 86e858f5bf17..eaf6c8aa7f47 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -204,6 +204,8 @@ struct annotation_print_data { struct evsel *evsel; struct arch *arch; struct debuginfo *dbg; + /* save data type info keyed by al->offset */ + struct hashmap *type_hash; /* It'll be set in hist_entry__annotate_printf() */ int addr_fmt_width; }; From 65128868bb3b0621d2d8e71f19852675a064b373 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 15:29:04 -0700 Subject: [PATCH 0761/2711] mm/memory_hotplug: Update comment for hotplug memory callback priorities Add clarification to comment for memory hotplug callback ordering as the current comment does not provide clear language on which callback happens first. Acked-by: David Hildenbrand Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250829222907.1290912-2-dave.jiang@intel.com Signed-off-by: Dave Jiang --- include/linux/memory.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/memory.h b/include/linux/memory.h index 40eb70ccb09d..1305102688d0 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -115,8 +115,8 @@ struct notifier_block; struct mem_section; /* - * Priorities for the hotplug memory callback routines (stored in decreasing - * order in the callback chain) + * Priorities for the hotplug memory callback routines. Invoked from + * high to low. Higher priorities correspond to higher numbers. */ #define DEFAULT_CALLBACK_PRI 0 #define SLAB_CALLBACK_PRI 1 From b57fc652ca24ada3b0c888327f9944ed21559286 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 15:29:05 -0700 Subject: [PATCH 0762/2711] drivers/base/node: Add a helper function node_update_perf_attrs() Add helper function node_update_perf_attrs() to allow update of node access coordinates computed by an external agent such as CXL. The helper allows updating of coordinates after the attribute being created by HMAT. Acked-by: David Hildenbrand Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250829222907.1290912-3-dave.jiang@intel.com Signed-off-by: Dave Jiang --- drivers/base/node.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/node.h | 8 ++++++++ 2 files changed, 46 insertions(+) diff --git a/drivers/base/node.c b/drivers/base/node.c index 3399594136b2..db18a1c32637 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -248,6 +248,44 @@ void node_set_perf_attrs(unsigned int nid, struct access_coordinate *coord, } EXPORT_SYMBOL_GPL(node_set_perf_attrs); +/** + * node_update_perf_attrs - Update the performance values for given access class + * @nid: Node identifier to be updated + * @coord: Heterogeneous memory performance coordinates + * @access: The access class for the given attributes + */ +void node_update_perf_attrs(unsigned int nid, struct access_coordinate *coord, + enum access_coordinate_class access) +{ + struct node_access_nodes *access_node; + struct node *node; + int i; + + if (WARN_ON_ONCE(!node_online(nid))) + return; + + node = node_devices[nid]; + list_for_each_entry(access_node, &node->access_list, list_node) { + if (access_node->access != access) + continue; + + access_node->coord = *coord; + for (i = 0; access_attrs[i]; i++) { + sysfs_notify(&access_node->dev.kobj, + NULL, access_attrs[i]->name); + } + break; + } + + /* When setting CPU access coordinates, update mempolicy */ + if (access != ACCESS_COORDINATE_CPU) + return; + + if (mempolicy_set_node_perf(nid, coord)) + pr_info("failed to set mempolicy attrs for node %d\n", nid); +} +EXPORT_SYMBOL_GPL(node_update_perf_attrs); + /** * struct node_cache_info - Internal tracking for memory node caches * @dev: Device represeting the cache level diff --git a/include/linux/node.h b/include/linux/node.h index 2c7529335b21..866e3323f1fd 100644 --- a/include/linux/node.h +++ b/include/linux/node.h @@ -85,6 +85,8 @@ struct node_cache_attrs { void node_add_cache(unsigned int nid, struct node_cache_attrs *cache_attrs); void node_set_perf_attrs(unsigned int nid, struct access_coordinate *coord, enum access_coordinate_class access); +void node_update_perf_attrs(unsigned int nid, struct access_coordinate *coord, + enum access_coordinate_class access); #else static inline void node_add_cache(unsigned int nid, struct node_cache_attrs *cache_attrs) @@ -96,6 +98,12 @@ static inline void node_set_perf_attrs(unsigned int nid, enum access_coordinate_class access) { } + +static inline void node_update_perf_attrs(unsigned int nid, + struct access_coordinate *coord, + enum access_coordinate_class access) +{ +} #endif struct node { From 2e454fb8056df6da4bba7d89a57bf60e217463c0 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 15:29:06 -0700 Subject: [PATCH 0763/2711] cxl, acpi/hmat: Update CXL access coordinates directly instead of through HMAT The current implementation of CXL memory hotplug notifier gets called before the HMAT memory hotplug notifier. The CXL driver calculates the access coordinates (bandwidth and latency values) for the CXL end to end path (i.e. CPU to endpoint). When the CXL region is onlined, the CXL memory hotplug notifier writes the access coordinates to the HMAT target structs. Then the HMAT memory hotplug notifier is called and it creates the access coordinates for the node sysfs attributes. During testing on an Intel platform, it was found that although the newly calculated coordinates were pushed to sysfs, the sysfs attributes for the access coordinates showed up with the wrong initiator. The system has 4 nodes (0, 1, 2, 3) where node 0 and 1 are CPU nodes and node 2 and 3 are CXL nodes. The expectation is that node 2 would show up as a target to node 0: /sys/devices/system/node/node2/access0/initiators/node0 However it was observed that node 2 showed up as a target under node 1: /sys/devices/system/node/node2/access0/initiators/node1 The original intent of the 'ext_updated' flag in HMAT handling code was to stop HMAT memory hotplug callback from clobbering the access coordinates after CXL has injected its calculated coordinates and replaced the generic target access coordinates provided by the HMAT table in the HMAT target structs. However the flag is hacky at best and blocks the updates from other CXL regions that are onlined in the same node later on. Remove the 'ext_updated' flag usage and just update the access coordinates for the nodes directly without touching HMAT target data. The hotplug memory callback ordering is changed. Instead of changing CXL, move HMAT back so there's room for the levels rather than have CXL share the same level as SLAB_CALLBACK_PRI. The change will resulting in the CXL callback to be executed after the HMAT callback. With the change, the CXL hotplug memory notifier runs after the HMAT callback. The HMAT callback will create the node sysfs attributes for access coordinates. The CXL callback will write the access coordinates to the now created node sysfs attributes directly and will not pollute the HMAT target values. A nodemask is introduced to keep track if a node has been updated and prevents further updates. Fixes: 067353a46d8c ("cxl/region: Add memory hotplug notifier for cxl region") Cc: stable@vger.kernel.org Tested-by: Marc Herbert Reviewed-by: Dan Williams Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250829222907.1290912-4-dave.jiang@intel.com Signed-off-by: Dave Jiang --- drivers/acpi/numa/hmat.c | 6 ------ drivers/cxl/core/cdat.c | 5 ----- drivers/cxl/core/core.h | 1 - drivers/cxl/core/region.c | 20 ++++++++++++-------- include/linux/memory.h | 2 +- 5 files changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index 4958301f5417..5d32490dc4ab 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -74,7 +74,6 @@ struct memory_target { struct node_cache_attrs cache_attrs; u8 gen_port_device_handle[ACPI_SRAT_DEVICE_HANDLE_SIZE]; bool registered; - bool ext_updated; /* externally updated */ }; struct memory_initiator { @@ -391,7 +390,6 @@ int hmat_update_target_coordinates(int nid, struct access_coordinate *coord, coord->read_bandwidth, access); hmat_update_target_access(target, ACPI_HMAT_WRITE_BANDWIDTH, coord->write_bandwidth, access); - target->ext_updated = true; return 0; } @@ -773,10 +771,6 @@ static void hmat_update_target_attrs(struct memory_target *target, u32 best = 0; int i; - /* Don't update if an external agent has changed the data. */ - if (target->ext_updated) - return; - /* Don't update for generic port if there's no device handle */ if ((access == NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL || access == NODE_ACCESS_CLASS_GENPORT_SINK_CPU) && diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index c0af645425f4..c891fd618cfd 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -1081,8 +1081,3 @@ int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, { return hmat_update_target_coordinates(nid, &cxlr->coord[access], access); } - -bool cxl_need_node_perf_attrs_update(int nid) -{ - return !acpi_node_backed_by_real_pxm(nid); -} diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 2669f251d677..a253d308f3c9 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -139,7 +139,6 @@ long cxl_pci_get_latency(struct pci_dev *pdev); int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c); int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, enum access_coordinate_class access); -bool cxl_need_node_perf_attrs_update(int nid); int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port, struct access_coordinate *c); diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 71cc42d05248..0ed95cbc5d5b 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -30,6 +30,12 @@ * 3. Decoder targets */ +/* + * nodemask that sets per node when the access_coordinates for the node has + * been updated by the CXL memory hotplug notifier. + */ +static nodemask_t nodemask_region_seen = NODE_MASK_NONE; + static struct cxl_region *to_cxl_region(struct device *dev); #define __ACCESS_ATTR_RO(_level, _name) { \ @@ -2442,14 +2448,8 @@ static bool cxl_region_update_coordinates(struct cxl_region *cxlr, int nid) for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) { if (cxlr->coord[i].read_bandwidth) { - rc = 0; - if (cxl_need_node_perf_attrs_update(nid)) - node_set_perf_attrs(nid, &cxlr->coord[i], i); - else - rc = cxl_update_hmat_access_coordinates(nid, cxlr, i); - - if (rc == 0) - cset++; + node_update_perf_attrs(nid, &cxlr->coord[i], i); + cset++; } } @@ -2487,6 +2487,10 @@ static int cxl_region_perf_attrs_callback(struct notifier_block *nb, if (nid != region_nid) return NOTIFY_DONE; + /* No action needed if node bit already set */ + if (node_test_and_set(nid, nodemask_region_seen)) + return NOTIFY_DONE; + if (!cxl_region_update_coordinates(cxlr, nid)) return NOTIFY_DONE; diff --git a/include/linux/memory.h b/include/linux/memory.h index 1305102688d0..0b755d1ef1ec 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -120,8 +120,8 @@ struct mem_section; */ #define DEFAULT_CALLBACK_PRI 0 #define SLAB_CALLBACK_PRI 1 -#define HMAT_CALLBACK_PRI 2 #define CXL_CALLBACK_PRI 5 +#define HMAT_CALLBACK_PRI 6 #define MM_COMPUTE_BATCH_PRI 10 #define CPUSET_CALLBACK_PRI 10 #define MEMTIER_HOTPLUG_PRI 100 From e99ecbc4c89adf551cccbbc00b5cb08c50969af6 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 15:29:07 -0700 Subject: [PATCH 0764/2711] acpi/hmat: Remove now unused hmat_update_target_coordinates() Remove deadcode since CXL no longer calls hmat_update_target_coordinates(). Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250829222907.1290912-5-dave.jiang@intel.com Signed-off-by: Dave Jiang --- drivers/acpi/numa/hmat.c | 28 ---------------------------- drivers/cxl/core/cdat.c | 6 ------ drivers/cxl/core/core.h | 2 -- include/linux/acpi.h | 12 ------------ 4 files changed, 48 deletions(-) diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index 5d32490dc4ab..5a36d57289b4 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -367,34 +367,6 @@ static void hmat_update_target_access(struct memory_target *target, } } -int hmat_update_target_coordinates(int nid, struct access_coordinate *coord, - enum access_coordinate_class access) -{ - struct memory_target *target; - int pxm; - - if (nid == NUMA_NO_NODE) - return -EINVAL; - - pxm = node_to_pxm(nid); - guard(mutex)(&target_lock); - target = find_mem_target(pxm); - if (!target) - return -ENODEV; - - hmat_update_target_access(target, ACPI_HMAT_READ_LATENCY, - coord->read_latency, access); - hmat_update_target_access(target, ACPI_HMAT_WRITE_LATENCY, - coord->write_latency, access); - hmat_update_target_access(target, ACPI_HMAT_READ_BANDWIDTH, - coord->read_bandwidth, access); - hmat_update_target_access(target, ACPI_HMAT_WRITE_BANDWIDTH, - coord->write_bandwidth, access); - - return 0; -} -EXPORT_SYMBOL_GPL(hmat_update_target_coordinates); - static __init void hmat_add_locality(struct acpi_hmat_locality *hmat_loc) { struct memory_locality *loc; diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index c891fd618cfd..bca1ec279651 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -1075,9 +1075,3 @@ void cxl_region_perf_data_calculate(struct cxl_region *cxlr, cxlr->coord[i].write_bandwidth += perf->coord[i].write_bandwidth; } } - -int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, - enum access_coordinate_class access) -{ - return hmat_update_target_coordinates(nid, &cxlr->coord[access], access); -} diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index a253d308f3c9..0476c3b648de 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -137,8 +137,6 @@ enum cxl_poison_trace_type { long cxl_pci_get_latency(struct pci_dev *pdev); int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c); -int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, - enum access_coordinate_class access); int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port, struct access_coordinate *c); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 1c5bb1e887cd..5ff5d99f6ead 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1595,18 +1595,6 @@ static inline void acpi_use_parent_companion(struct device *dev) ACPI_COMPANION_SET(dev, ACPI_COMPANION(dev->parent)); } -#ifdef CONFIG_ACPI_HMAT -int hmat_update_target_coordinates(int nid, struct access_coordinate *coord, - enum access_coordinate_class access); -#else -static inline int hmat_update_target_coordinates(int nid, - struct access_coordinate *coord, - enum access_coordinate_class access) -{ - return -EOPNOTSUPP; -} -#endif - #ifdef CONFIG_ACPI_NUMA bool acpi_node_backed_by_real_pxm(int nid); #else From 72243ced3d861f99368ad2edcdce4d71c7108d16 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 30 Aug 2025 10:53:26 +0200 Subject: [PATCH 0765/2711] dt-bindings: input: tsc2007: use comma in filename Use comma between vendor-prefix and chip name as it is common. Signed-off-by: Andreas Kemnade Fixes: 45601c66b5dd ("dt-bindings: input: touchscreen: convert tsc2007.txt to yaml format") Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250830085326.36120-1-akemnade@kernel.org Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/{ti.tsc2007.yaml => ti,tsc2007.yaml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Documentation/devicetree/bindings/input/touchscreen/{ti.tsc2007.yaml => ti,tsc2007.yaml} (96%) diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti.tsc2007.yaml b/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2007.yaml similarity index 96% rename from Documentation/devicetree/bindings/input/touchscreen/ti.tsc2007.yaml rename to Documentation/devicetree/bindings/input/touchscreen/ti,tsc2007.yaml index 8bb4bc7df4fa..a73d110272fa 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/ti.tsc2007.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2007.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/input/touchscreen/ti.tsc2007.yaml# +$id: http://devicetree.org/schemas/input/touchscreen/ti,tsc2007.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments tsc2007 touchscreen controller From 4a76a0a889cef284327f265f97edc4ff2f3e11cc Mon Sep 17 00:00:00 2001 From: WeiHao Li Date: Sun, 31 Aug 2025 18:48:51 +0800 Subject: [PATCH 0766/2711] dt-bindings: clock: rk3368: Add SCLK_MIPIDSI_24M Add a clock id for mipi dsi reference clock, mipi dsi node used it. Signed-off-by: WeiHao Li Acked-by: "Rob Herring (Arm)" Link: https://lore.kernel.org/r/20250831104855.45883-4-cn.liweihao@gmail.com Signed-off-by: Heiko Stuebner --- include/dt-bindings/clock/rk3368-cru.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/rk3368-cru.h b/include/dt-bindings/clock/rk3368-cru.h index ebae3cbf8192..b951e2906948 100644 --- a/include/dt-bindings/clock/rk3368-cru.h +++ b/include/dt-bindings/clock/rk3368-cru.h @@ -72,6 +72,7 @@ #define SCLK_SFC 126 #define SCLK_MAC 127 #define SCLK_MACREF_OUT 128 +#define SCLK_MIPIDSI_24M 129 #define SCLK_TIMER10 133 #define SCLK_TIMER11 134 #define SCLK_TIMER12 135 From 77111b2c22ef5b368da5c833175b6f7806b39ccb Mon Sep 17 00:00:00 2001 From: WeiHao Li Date: Sun, 31 Aug 2025 18:48:52 +0800 Subject: [PATCH 0767/2711] clk: rockchip: rk3368: use clock ids for SCLK_MIPIDSI_24M Export the clocks via the newly added clock-ids. Signed-off-by: WeiHao Li Link: https://lore.kernel.org/r/20250831104855.45883-5-cn.liweihao@gmail.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3368.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c index 04391e4e2874..95e6996adbae 100644 --- a/drivers/clk/rockchip/clk-rk3368.c +++ b/drivers/clk/rockchip/clk-rk3368.c @@ -526,7 +526,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(3), 1, GFLAGS), - GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3368_CLKGATE_CON(4), 14, GFLAGS), + GATE(SCLK_MIPIDSI_24M, "sclk_mipidsi_24m", "xin24m", 0, RK3368_CLKGATE_CON(4), 14, GFLAGS), /* * Clock-Architecture Diagram 4 From c1b52451b604b7700419a48cf2f146ebacd9af57 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 22 Aug 2025 18:32:45 -0300 Subject: [PATCH 0768/2711] dt-bindings: input: touchscreen: tsc2007: Document 'wakeup-source' The 'wakeup-source' property is used by many devicetree files and is also supported by the tsc2007_core driver. Document it to avoid the following dt-schema warning: 'wakeup-source' does not match any of the regexes: '^pinctrl-[0-9]+$' Signed-off-by: Fabio Estevam Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250822213245.125901-1-festevam@gmail.com Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/ti,tsc2007.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2007.yaml b/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2007.yaml index a73d110272fa..a595df3ea802 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2007.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2007.yaml @@ -26,6 +26,8 @@ properties: pendown-gpio: true + wakeup-source: true + ti,max-rt: $ref: /schemas/types.yaml#/definitions/uint32 description: maximum pressure. From b0e109a24213b051f53b4ff0fded5c458c2d62b2 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Wed, 3 Sep 2025 06:52:50 -0700 Subject: [PATCH 0769/2711] Input: tsc2007 - change warning to debug message if pen GPIO is not defined Since pen GPIO request is optional, there is no reason to throw dev_warn if such GPIO is not defined. Signed-off-by: Svyatoslav Ryhel Link: https://lore.kernel.org/r/20250824091927.105121-2-clamor95@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 5252301686ec..9fda83acccb1 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -253,7 +253,7 @@ static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts) if (ts->gpiod) ts->get_pendown_state = tsc2007_get_pendown_state_gpio; else - dev_warn(dev, "Pen down GPIO is not specified in properties\n"); + dev_dbg(dev, "Pen down GPIO is not specified in properties\n"); return 0; } From d504bbda8ca689585bdf663514a187dd3c9f0226 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Wed, 3 Sep 2025 06:53:24 -0700 Subject: [PATCH 0770/2711] Input: tsc2007 - make interrupt optional In case tsc2007 is used as an ADC sensor there will be no interrupt provided at all, so set up an interrupt only if one is present. Signed-off-by: Svyatoslav Ryhel Link: https://lore.kernel.org/r/20250824091927.105121-3-clamor95@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007_core.c | 28 ++++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 9fda83acccb1..05e00a084c88 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -177,7 +177,8 @@ static void tsc2007_stop(struct tsc2007 *ts) mb(); wake_up(&ts->wait); - disable_irq(ts->irq); + if (ts->irq) + disable_irq(ts->irq); } static int tsc2007_open(struct input_dev *input_dev) @@ -188,7 +189,8 @@ static int tsc2007_open(struct input_dev *input_dev) ts->stopped = false; mb(); - enable_irq(ts->irq); + if (ts->irq) + enable_irq(ts->irq); /* Prepare for touch readings - power down ADC and enable PENIRQ */ err = tsc2007_xfer(ts, PWRDOWN); @@ -361,17 +363,19 @@ static int tsc2007_probe(struct i2c_client *client) pdata->init_platform_hw(); } - err = devm_request_threaded_irq(&client->dev, ts->irq, - NULL, tsc2007_soft_irq, - IRQF_ONESHOT, - client->dev.driver->name, ts); - if (err) { - dev_err(&client->dev, "Failed to request irq %d: %d\n", - ts->irq, err); - return err; - } + if (ts->irq) { + err = devm_request_threaded_irq(&client->dev, ts->irq, + NULL, tsc2007_soft_irq, + IRQF_ONESHOT, + client->dev.driver->name, ts); + if (err) { + dev_err(&client->dev, "Failed to request irq %d: %d\n", + ts->irq, err); + return err; + } - tsc2007_stop(ts); + tsc2007_stop(ts); + } /* power down the chip (TSC2007_SETUP does not ACK on I2C) */ err = tsc2007_xfer(ts, PWRDOWN); From 9a12e2fb3f517d5bd72efa565a8e591e6fff311c Mon Sep 17 00:00:00 2001 From: Johannes Kirchmair Date: Wed, 29 Jan 2025 14:51:20 +0100 Subject: [PATCH 0771/2711] Input: tsc2007 - prevent overflow in pressure calculation The touch resistance calculation in the tsc2007 driver is prone to overflow if (z2 - z1) is large and also x is reasonably big. This overflow results in the driver emitting input events when very little touch pressure is applied. In these events the x and y coordinates can be substantially off. Avoid the overflow by using u64 when calculating resistance value. Signed-off-by: Johannes Kirchmair Link: https://lore.kernel.org/r/20250129-fix_tsc_calculation_overflow-v2-1-9e51333496ad@skidata.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007_core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 05e00a084c88..948935de894b 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -68,7 +69,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc) { - u32 rt = 0; + u64 rt = 0; /* range filtering */ if (tc->x == MAX_12BIT) @@ -79,11 +80,13 @@ u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc) rt = tc->z2 - tc->z1; rt *= tc->x; rt *= tsc->x_plate_ohms; - rt /= tc->z1; + rt = div_u64(rt, tc->z1); rt = (rt + 2047) >> 12; } - return rt; + if (rt > U32_MAX) + return U32_MAX; + return (u32) rt; } bool tsc2007_is_pen_down(struct tsc2007 *ts) From 78d853512d6f979cf0cc41566e4f6cd82995ff34 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 21 Aug 2025 09:38:15 -0700 Subject: [PATCH 0772/2711] perf disasm: Avoid undefined behavior in incrementing NULL Incrementing NULL is undefined behavior and triggers ubsan during the perf annotate test. Split a compound statement over two lines to avoid this. Fixes: 98f69a573c668a18 ("perf annotate: Split out util/disasm.c") Reviewed-by: Collin Funk Reviewed-by: James Clark Reviewed-by: Kuan-Wei Chiu Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Blake Jones Cc: Chun-Tse Shao Cc: Howard Chu Cc: Ingo Molnar Cc: Jan Polensky Cc: Jiri Olsa Cc: Kan Liang Cc: Li Huafei Cc: Mark Rutland Cc: Nam Cao Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steinar H. Gunderson Cc: Thomas Gleixner Link: https://lore.kernel.org/r/20250821163820.1132977-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/disasm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index b1e4919d016f..e257bd918c89 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -390,13 +390,16 @@ static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_s * skip over possible up to 2 operands to get to address, e.g.: * tbnz w0, #26, ffff0000083cd190 */ - if (c++ != NULL) { + if (c != NULL) { + c++; ops->target.addr = strtoull(c, NULL, 16); if (!ops->target.addr) { c = strchr(c, ','); c = validate_comma(c, ops); - if (c++ != NULL) + if (c != NULL) { + c++; ops->target.addr = strtoull(c, NULL, 16); + } } } else { ops->target.addr = strtoull(ops->raw, NULL, 16); From 4bd5bd8dbd41a208fb73afb65bda6f38e2b5a637 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 21 Aug 2025 09:38:16 -0700 Subject: [PATCH 0773/2711] perf test trace_btf_enum: Skip if permissions are insufficient Modify test behavior to skip if BPF calls fail with "Operation not permitted". Fixes: d66763fed30f0bd8 ("perf test trace_btf_enum: Add regression test for the BTF augmentation of enums in 'perf trace'") Reviewed-by: James Clark Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Blake Jones Cc: Chun-Tse Shao Cc: Collin Funk Cc: Howard Chu Cc: Ingo Molnar Cc: Jan Polensky Cc: Jiri Olsa Cc: Kan Liang Cc: Li Huafei Cc: Mark Rutland Cc: Nam Cao Cc: Peter Zijlstra Cc: Steinar H. Gunderson Cc: Thomas Gleixner Link: https://lore.kernel.org/r/20250821163820.1132977-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/trace_btf_enum.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/perf/tests/shell/trace_btf_enum.sh b/tools/perf/tests/shell/trace_btf_enum.sh index 572001d75d78..03e9f680a4a6 100755 --- a/tools/perf/tests/shell/trace_btf_enum.sh +++ b/tools/perf/tests/shell/trace_btf_enum.sh @@ -23,6 +23,14 @@ check_vmlinux() { fi } +check_permissions() { + if perf trace -e $syscall $TESTPROG 2>&1 | grep -q "Operation not permitted" + then + echo "trace+enum test [Skipped permissions]" + err=2 + fi +} + trace_landlock() { echo "Tracing syscall ${syscall}" @@ -56,6 +64,9 @@ trace_non_syscall() { } check_vmlinux +if [ $err = 0 ]; then + check_permissions +fi if [ $err = 0 ]; then trace_landlock From 2354479026d726954ff86ce82f4b649637319661 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 21 Aug 2025 09:38:17 -0700 Subject: [PATCH 0774/2711] perf evsel: Avoid container_of on a NULL leader An evsel should typically have a leader of itself, however, in tests like 'Sample parsing' a NULL leader may occur and the container_of will return a corrupt pointer. Avoid this with an explicit NULL test. Fixes: fba7c86601e2e42d ("libperf: Move 'leader' from tools/perf to perf_evsel::leader") Reviewed-by: James Clark Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Blake Jones Cc: Chun-Tse Shao Cc: Collin Funk Cc: Howard Chu Cc: Ingo Molnar Cc: Jan Polensky Cc: Jiri Olsa Cc: Kan Liang Cc: Li Huafei Cc: Mark Rutland Cc: Nam Cao Cc: Peter Zijlstra Cc: Steinar H. Gunderson Cc: Thomas Gleixner Link: https://lore.kernel.org/r/20250821163820.1132977-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d264c143b592..496f42434327 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -3935,6 +3935,8 @@ bool evsel__is_hybrid(const struct evsel *evsel) struct evsel *evsel__leader(const struct evsel *evsel) { + if (evsel->core.leader == NULL) + return NULL; return container_of(evsel->core.leader, struct evsel, core); } From 8b93f8933d37591d17c59fd71b18fc61966d9515 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 21 Aug 2025 09:38:18 -0700 Subject: [PATCH 0775/2711] perf test shell lock_contention: Extra debug diagnostics In test_record_concurrent, as stderr is sent to /dev/null, error messages are hidden. Change this to gather the error messages and dump them on failure. Some minor sh->bash changes to add some more diagnostics in trap_cleanup. Reviewed-by: James Clark Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Blake Jones Cc: Chun-Tse Shao Cc: Collin Funk Cc: Howard Chu Cc: Ingo Molnar Cc: Jan Polensky Cc: Jiri Olsa Cc: Kan Liang Cc: Li Huafei Cc: Mark Rutland Cc: Nam Cao Cc: Peter Zijlstra Cc: Steinar H. Gunderson Cc: Thomas Gleixner Link: https://lore.kernel.org/r/20250821163820.1132977-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/lock_contention.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/lock_contention.sh b/tools/perf/tests/shell/lock_contention.sh index d33d9e4392b0..7248a74ca2a3 100755 --- a/tools/perf/tests/shell/lock_contention.sh +++ b/tools/perf/tests/shell/lock_contention.sh @@ -7,14 +7,17 @@ set -e err=0 perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) result=$(mktemp /tmp/__perf_test.result.XXXXX) +errout=$(mktemp /tmp/__perf_test.errout.XXXXX) cleanup() { rm -f ${perfdata} rm -f ${result} + rm -f ${errout} trap - EXIT TERM INT } trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" cleanup exit ${err} } @@ -75,10 +78,12 @@ test_bpf() test_record_concurrent() { echo "Testing perf lock record and perf lock contention at the same time" - perf lock record -o- -- perf bench sched messaging -p 2> /dev/null | \ + perf lock record -o- -- perf bench sched messaging -p 2> ${errout} | \ perf lock contention -i- -E 1 -q 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)" + cat ${errout} + cat ${result} err=1 exit fi From b39c915a4f365cce6bdc0e538ed95d31823aea8f Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 21 Aug 2025 09:38:19 -0700 Subject: [PATCH 0776/2711] libperf event: Ensure tracing data is multiple of 8 sized Perf's synthetic-events.c will ensure 8-byte alignment of tracing data, writing it after a perf_record_header_tracing_data event. Add padding to struct perf_record_header_tracing_data to make it 16-byte rather than 12-byte sized. Fixes: 055c67ed39887c55 ("perf tools: Move event synthesizing routines to separate .c file") Reviewed-by: James Clark Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Blake Jones Cc: Chun-Tse Shao Cc: Collin Funk Cc: Howard Chu Cc: Ingo Molnar Cc: Jan Polensky Cc: Jiri Olsa Cc: Kan Liang Cc: Li Huafei Cc: Mark Rutland Cc: Nam Cao Cc: Peter Zijlstra Cc: Steinar H. Gunderson Cc: Thomas Gleixner Link: https://lore.kernel.org/r/20250821163820.1132977-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/perf/include/perf/event.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h index 6608f1e3701b..aa1e91c97a22 100644 --- a/tools/lib/perf/include/perf/event.h +++ b/tools/lib/perf/include/perf/event.h @@ -291,6 +291,7 @@ struct perf_record_header_event_type { struct perf_record_header_tracing_data { struct perf_event_header header; __u32 size; + __u32 pad; }; #define PERF_RECORD_MISC_BUILD_ID_SIZE (1 << 15) From c3befab83441afdc631524f4c507bb713aa44bd7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:31 -0700 Subject: [PATCH 0777/2711] perf python: Add more exceptions on error paths Returning NULL will cause the python interpreter to fail but not report an error. If none wants to be returned then Py_None needs returning. Set the error for the cases returning NULL so that more meaningful interpreter behavior is had. Reviewed-by: Howard Chu Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index ea77bea0306f..d47cbc1c2257 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -485,13 +485,19 @@ static PyObject *pyrf_event__new(const union perf_event *event) if ((event->header.type < PERF_RECORD_MMAP || event->header.type > PERF_RECORD_SAMPLE) && !(event->header.type == PERF_RECORD_SWITCH || - event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)) + event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)) { + PyErr_Format(PyExc_TypeError, "Unexpected header type %u", + event->header.type); return NULL; + } // FIXME this better be dynamic or we need to parse everything // before calling perf_mmap__consume(), including tracepoint fields. - if (sizeof(pevent->event) < event->header.size) + if (sizeof(pevent->event) < event->header.size) { + PyErr_Format(PyExc_TypeError, "Unexpected event size: %zd < %u", + sizeof(pevent->event), event->header.size); return NULL; + } ptype = pyrf_event__type[event->header.type]; pevent = PyObject_New(struct pyrf_event, ptype); @@ -1209,8 +1215,10 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, return NULL; md = get_md(evlist, cpu); - if (!md) + if (!md) { + PyErr_Format(PyExc_TypeError, "Unknown CPU '%d'", cpu); return NULL; + } if (perf_mmap__read_init(&md->core) < 0) goto end; From 6bdf8a5669d00bdd6ab97cb184e7178615b68df8 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:32 -0700 Subject: [PATCH 0778/2711] perf python: Improve the tracepoint function if no libtraceevent The tracepoint function just returns the tracepoint id, this doesn't require libtraceevent which is only used for parsing the event format data. Implement the function using the id function in tp_pmu. No current code in perf is using this, the previous code migrated to perf.parse_events, but it feels good to have less ifdef HAVE_LIBTRACEEVENT. Reviewed-by: Howard Chu Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index d47cbc1c2257..127934af4828 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -18,6 +18,7 @@ #include "record.h" #include "strbuf.h" #include "thread_map.h" +#include "tp_pmu.h" #include "trace-event.h" #include "metricgroup.h" #include "mmap.h" @@ -1554,10 +1555,6 @@ static const struct perf_constant perf__constants[] = { static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel, PyObject *args, PyObject *kwargs) { -#ifndef HAVE_LIBTRACEEVENT - return NULL; -#else - struct tep_event *tp_format; static char *kwlist[] = { "sys", "name", NULL }; char *sys = NULL; char *name = NULL; @@ -1566,12 +1563,7 @@ static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel, &sys, &name)) return NULL; - tp_format = trace_event__tp_format(sys, name); - if (IS_ERR(tp_format)) - return PyLong_FromLong(-1); - - return PyLong_FromLong(tp_format->id); -#endif // HAVE_LIBTRACEEVENT + return PyLong_FromLong(tp_pmu__id(sys, name)); } static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel) From 7f1f71a164ade85939dbe6022c5d305e1b1b56fd Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:33 -0700 Subject: [PATCH 0779/2711] perf python: Add basic PMU abstraction and pmus sequence Add an ability to iterate over PMUs and a basic PMU type then can just show the PMU's name. An example usage: ``` $ python Python 3.12.9 (main, Feb 5 2025, 01:31:18) [GCC 14.2.0] on linux >>> import perf >>> list(perf.pmus()) [pmu(cpu), pmu(breakpoint), pmu(cstate_core), pmu(cstate_pkg), pmu(hwmon_acpitz), pmu(hwmon_ac), pmu(hwmon_bat0), pmu(hwmon_coretemp), pmu(hwmon_iwlwifi_1), pmu(hwmon_nvme), pmu(hwmon_thinkpad), pmu(hwmon_ucsi_source_psy_usbc000_0), pmu(hwmon_ucsi_source_psy_usbc000_0), pmu(i915), pmu(intel_bts), pmu(intel_pt), pmu(kprobe), pmu(msr), pmu(power), pmu(software), pmu(tool), pmu(tracepoint), pmu(uncore_arb), pmu(uncore_cbox_0), pmu(uncore_cbox_1), pmu(uncore_cbox_2), pmu(uncore_cbox_3), pmu(uncore_cbox_4), pmu(uncore_cbox_5), pmu(uncore_cbox_6), pmu(uncore_cbox_7), pmu(uncore_clock), pmu(uncore_imc_free_running_0), pmu(uncore_imc_free_running_1), pmu(uprobe)] ``` Committer testing: One has to set PYTHONPATH to the build directory beforehand: $ export PYTHONPATH=/tmp/build/perf-tools-next/python/ $ python Python 3.13.7 (main, Aug 14 2025, 00:00:00) [GCC 15.2.1 20250808 (Red Hat 15.2.1-1)] on linux >>> import perf >>> list(perf.pmus()) [pmu(cpu), pmu(amd_df), pmu(amd_iommu_0), pmu(amd_l3), pmu(amd_umc_0), pmu(breakpoint), pmu(hwmon_amdgpu), pmu(hwmon_amdgpu), pmu(hwmon_k10temp), pmu(hwmon_nvme), pmu(hwmon_r8169_0_e00_00), pmu(ibs_fetch), pmu(ibs_op), pmu(kprobe), pmu(msr), pmu(power), pmu(power_core), pmu(software), pmu(tool), pmu(tracepoint), pmu(uprobe)] >>> Reviewed-by: Howard Chu Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 140 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 127934af4828..6f9728d365ae 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -649,6 +649,138 @@ static int pyrf_thread_map__setup_types(void) return PyType_Ready(&pyrf_thread_map__type); } +/** + * A python wrapper for perf_pmus that are globally owned by the pmus.c code. + */ +struct pyrf_pmu { + PyObject_HEAD + + struct perf_pmu *pmu; +}; + +static void pyrf_pmu__delete(struct pyrf_pmu *ppmu) +{ + Py_TYPE(ppmu)->tp_free((PyObject *)ppmu); +} + +static PyObject *pyrf_pmu__name(PyObject *self) +{ + struct pyrf_pmu *ppmu = (void *)self; + + return PyUnicode_FromString(ppmu->pmu->name); +} + +static PyObject *pyrf_pmu__repr(PyObject *self) +{ + struct pyrf_pmu *ppmu = (void *)self; + + return PyUnicode_FromFormat("pmu(%s)", ppmu->pmu->name); +} + +static const char pyrf_pmu__doc[] = PyDoc_STR("perf Performance Monitoring Unit (PMU) object."); + +static PyMethodDef pyrf_pmu__methods[] = { + { + .ml_name = "name", + .ml_meth = (PyCFunction)pyrf_pmu__name, + .ml_flags = METH_NOARGS, + .ml_doc = PyDoc_STR("Name of the PMU including suffixes.") + }, + { .ml_name = NULL, } +}; + +/** The python type for a perf.pmu. */ +static PyTypeObject pyrf_pmu__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.pmu", + .tp_basicsize = sizeof(struct pyrf_pmu), + .tp_dealloc = (destructor)pyrf_pmu__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = pyrf_pmu__doc, + .tp_methods = pyrf_pmu__methods, + .tp_str = pyrf_pmu__name, + .tp_repr = pyrf_pmu__repr, +}; + +static int pyrf_pmu__setup_types(void) +{ + pyrf_pmu__type.tp_new = PyType_GenericNew; + return PyType_Ready(&pyrf_pmu__type); +} + + +/** A python iterator for pmus that has no equivalent in the C code. */ +struct pyrf_pmu_iterator { + PyObject_HEAD + struct perf_pmu *pmu; +}; + +static void pyrf_pmu_iterator__dealloc(struct pyrf_pmu_iterator *self) +{ + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject *pyrf_pmu_iterator__new(PyTypeObject *type, PyObject *args __maybe_unused, + PyObject *kwds __maybe_unused) +{ + struct pyrf_pmu_iterator *itr = (void *)type->tp_alloc(type, 0); + + if (itr != NULL) + itr->pmu = perf_pmus__scan(/*pmu=*/NULL); + + return (PyObject *) itr; +} + +static PyObject *pyrf_pmu_iterator__iter(PyObject *self) +{ + Py_INCREF(self); + return self; +} + +static PyObject *pyrf_pmu_iterator__iternext(PyObject *self) +{ + struct pyrf_pmu_iterator *itr = (void *)self; + struct pyrf_pmu *ppmu; + + if (itr->pmu == NULL) { + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } + // Create object to return. + ppmu = PyObject_New(struct pyrf_pmu, &pyrf_pmu__type); + if (ppmu) { + ppmu->pmu = itr->pmu; + // Advance iterator. + itr->pmu = perf_pmus__scan(itr->pmu); + } + return (PyObject *)ppmu; +} + +/** The python type for the PMU iterator. */ +static PyTypeObject pyrf_pmu_iterator__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "pmus.iterator", + .tp_doc = "Iterator for the pmus string sequence.", + .tp_basicsize = sizeof(struct pyrf_pmu_iterator), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = pyrf_pmu_iterator__new, + .tp_dealloc = (destructor) pyrf_pmu_iterator__dealloc, + .tp_iter = pyrf_pmu_iterator__iter, + .tp_iternext = pyrf_pmu_iterator__iternext, +}; + +static int pyrf_pmu_iterator__setup_types(void) +{ + return PyType_Ready(&pyrf_pmu_iterator__type); +} + +static PyObject *pyrf__pmus(PyObject *self, PyObject *args) +{ + // Calling the class creates an instance of the iterator. + return PyObject_CallObject((PyObject *) &pyrf_pmu_iterator__type, /*args=*/NULL); +} + struct pyrf_counts_values { PyObject_HEAD @@ -1701,6 +1833,12 @@ static PyMethodDef perf__methods[] = { .ml_flags = METH_VARARGS, .ml_doc = PyDoc_STR("Parse a string of events and return an evlist.") }, + { + .ml_name = "pmus", + .ml_meth = (PyCFunction) pyrf__pmus, + .ml_flags = METH_NOARGS, + .ml_doc = PyDoc_STR("Returns a sequence of pmus.") + }, { .ml_name = NULL, } }; @@ -1728,6 +1866,8 @@ PyMODINIT_FUNC PyInit_perf(void) pyrf_evsel__setup_types() < 0 || pyrf_thread_map__setup_types() < 0 || pyrf_cpu_map__setup_types() < 0 || + pyrf_pmu_iterator__setup_types() < 0 || + pyrf_pmu__setup_types() < 0 || pyrf_counts_values__setup_types() < 0) return module; From 2f20df570e39ccedbf7374a46ae3893705e88d36 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:34 -0700 Subject: [PATCH 0780/2711] perf python: Add function returning dictionary of all events on a PMU Allow all events on a PMU to be gathered, similar to how perf list gathers event information. An example usage: ``` $ python Python 3.12.9 (main, Feb 5 2025, 01:31:18) [GCC 14.2.0] on linux >>> import perf >>> for pmu in perf.pmus(): ... print(pmu.events()) ... [{'name': 'mem_load_retired.l3_hit', 'desc': 'Retired load instructions... ``` Reviewed-by: Howard Chu Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 71 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 6f9728d365ae..cf1128435022 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -670,6 +670,71 @@ static PyObject *pyrf_pmu__name(PyObject *self) return PyUnicode_FromString(ppmu->pmu->name); } +static bool add_to_dict(PyObject *dict, const char *key, const char *value) +{ + PyObject *pkey, *pvalue; + bool ret; + + if (value == NULL) + return true; + + pkey = PyUnicode_FromString(key); + pvalue = PyUnicode_FromString(value); + + ret = pkey && pvalue && PyDict_SetItem(dict, pkey, pvalue) == 0; + Py_XDECREF(pkey); + Py_XDECREF(pvalue); + return ret; +} + +static int pyrf_pmu__events_cb(void *state, struct pmu_event_info *info) +{ + PyObject *py_list = state; + PyObject *dict = PyDict_New(); + + if (!dict) + return -ENOMEM; + + if (!add_to_dict(dict, "name", info->name) || + !add_to_dict(dict, "alias", info->alias) || + !add_to_dict(dict, "scale_unit", info->scale_unit) || + !add_to_dict(dict, "desc", info->desc) || + !add_to_dict(dict, "long_desc", info->long_desc) || + !add_to_dict(dict, "encoding_desc", info->encoding_desc) || + !add_to_dict(dict, "topic", info->topic) || + !add_to_dict(dict, "event_type_desc", info->event_type_desc) || + !add_to_dict(dict, "str", info->str) || + !add_to_dict(dict, "deprecated", info->deprecated ? "deprecated" : NULL) || + PyList_Append(py_list, dict) != 0) { + Py_DECREF(dict); + return -ENOMEM; + } + Py_DECREF(dict); + return 0; +} + +static PyObject *pyrf_pmu__events(PyObject *self) +{ + struct pyrf_pmu *ppmu = (void *)self; + PyObject *py_list = PyList_New(0); + int ret; + + if (!py_list) + return NULL; + + ret = perf_pmu__for_each_event(ppmu->pmu, + /*skip_duplicate_pmus=*/false, + py_list, + pyrf_pmu__events_cb); + if (ret) { + Py_DECREF(py_list); + errno = -ret; + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return py_list; +} + static PyObject *pyrf_pmu__repr(PyObject *self) { struct pyrf_pmu *ppmu = (void *)self; @@ -680,6 +745,12 @@ static PyObject *pyrf_pmu__repr(PyObject *self) static const char pyrf_pmu__doc[] = PyDoc_STR("perf Performance Monitoring Unit (PMU) object."); static PyMethodDef pyrf_pmu__methods[] = { + { + .ml_name = "events", + .ml_meth = (PyCFunction)pyrf_pmu__events, + .ml_flags = METH_NOARGS, + .ml_doc = PyDoc_STR("Returns a sequence of events encoded as a dictionaries.") + }, { .ml_name = "name", .ml_meth = (PyCFunction)pyrf_pmu__name, From 83e5b8f9bf2edfa1aac0d09d994792da594fec56 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:35 -0700 Subject: [PATCH 0781/2711] perf ilist: Add new python ilist command The perf ilist command is a textual app [1] similar to perf list. In the top-left pane a tree of PMUs is displayed. Selecting a PMU expands the events within it. Selecting an event displays the `perf list` style event information in the top-right pane. When an event is selected it is opened and the counters on each CPU the event is for are periodically read. The bottom of the screen contains a scrollable set of sparklines showing the events in total and on each CPU. Scrolling below the sparklines shows the same data as raw counts. The sparklines are small graphs where the height of the bar is in relation to maximum of the other counts in the graph. By default the counts are read with an interval of 0.1 seconds (10 times per second). A -I/--interval command line option allows the interval to be changed. The oldest read counts are dropped when the counts fill the line causing the sparkline to move from right to left. A search box can be pulled up with the 's' key. 'n' and 'p' iterate through the search results. As some PMUs have hundreds of events a 'c' key will collapse the events in the current PMU to make navigating the PMUs easier. [1] https://textual.textualize.io/ Committer testing: This needs a bit more polishing, to test it I had to go thru some hops: $ python ilist python: can't open file '/home/acme/git/perf-tools-next/ilist': [Errno 2] No such file or directory $ $ python tools/perf/python/ilist.py Traceback (most recent call last): File "/home/acme/git/perf-tools-next/tools/perf/python/ilist.py", line 8, in from textual import on ModuleNotFoundError: No module named 'textual' $ $ sudo dnf install textual Updating and loading repositories: Repositories loaded. Failed to resolve the transaction: No match for argument: textual You can try to add to command line: --skip-unavailable to skip unavailable packages $ After some searching I installed the 'python3-textual' and it starts, allowing traversing the various pmus and events, see descriptions on the upper right side and a view of the events on the lower half of the screen. Interesting for quickly iterating thru the available events. Reviewed-by: Howard Chu Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/python/ilist.py | 385 +++++++++++++++++++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100755 tools/perf/python/ilist.py diff --git a/tools/perf/python/ilist.py b/tools/perf/python/ilist.py new file mode 100755 index 000000000000..22c70a8b31f3 --- /dev/null +++ b/tools/perf/python/ilist.py @@ -0,0 +1,385 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +"""Interactive perf list.""" + +import argparse +from typing import Any, Dict, Optional, Tuple +import perf +from textual import on +from textual.app import App, ComposeResult +from textual.binding import Binding +from textual.containers import Horizontal, HorizontalGroup, Vertical, VerticalScroll +from textual.command import SearchIcon +from textual.screen import ModalScreen +from textual.widgets import Button, Footer, Header, Input, Label, Sparkline, Static, Tree +from textual.widgets.tree import TreeNode + + +class ErrorScreen(ModalScreen[bool]): + """Pop up dialog for errors.""" + + CSS = """ + ErrorScreen { + align: center middle; + } + """ + + def __init__(self, error: str): + self.error = error + super().__init__() + + def compose(self) -> ComposeResult: + yield Button(f"Error: {self.error}", variant="primary", id="error") + + def on_button_pressed(self, event: Button.Pressed) -> None: + self.dismiss(True) + + +class SearchScreen(ModalScreen[str]): + """Pop up dialog for search.""" + + CSS = """ + SearchScreen Horizontal { + align: center middle; + margin-top: 1; + } + SearchScreen Input { + width: 1fr; + } + """ + + def compose(self) -> ComposeResult: + yield Horizontal(SearchIcon(), Input(placeholder="Event name")) + + def on_input_submitted(self, event: Input.Submitted) -> None: + """Handle the user pressing Enter in the input field.""" + self.dismiss(event.value) + + +class Counter(HorizontalGroup): + """Two labels for a CPU and its counter value.""" + + CSS = """ + Label { + gutter: 1; + } + """ + + def __init__(self, cpu: int) -> None: + self.cpu = cpu + super().__init__() + + def compose(self) -> ComposeResult: + label = f"cpu{self.cpu}" if self.cpu >= 0 else "total" + yield Label(label + " ") + yield Label("0", id=f"counter_{label}") + + +class CounterSparkline(HorizontalGroup): + """A Sparkline for a performance counter.""" + + def __init__(self, cpu: int) -> None: + self.cpu = cpu + super().__init__() + + def compose(self) -> ComposeResult: + label = f"cpu{self.cpu}" if self.cpu >= 0 else "total" + yield Label(label) + yield Sparkline([], summary_function=max, id=f"sparkline_{label}") + + +class IListApp(App): + TITLE = "Interactive Perf List" + + BINDINGS = [ + Binding(key="s", action="search", description="Search", + tooltip="Search events and PMUs"), + Binding(key="n", action="next", description="Next", + tooltip="Next search result or item"), + Binding(key="p", action="prev", description="Previous", + tooltip="Previous search result or item"), + Binding(key="c", action="collapse", description="Collapse", + tooltip="Collapse the current PMU"), + Binding(key="^q", action="quit", description="Quit", + tooltip="Quit the app"), + ] + + CSS = """ + /* Make the 'total' sparkline a different color. */ + #sparkline_total > .sparkline--min-color { + color: $accent; + } + #sparkline_total > .sparkline--max-color { + color: $accent 30%; + } + /* + * Make the active_search initially not displayed with the text in + * the middle of the line. + */ + #active_search { + display: none; + width: 100%; + text-align: center; + } + """ + + def __init__(self, interval: float) -> None: + self.interval = interval + self.evlist = None + self.search_results: list[TreeNode[str]] = [] + self.cur_search_result: TreeNode[str] | None = None + super().__init__() + + def expand_and_select(self, node: TreeNode[Any]) -> None: + """Expand select a node in the tree.""" + if node.parent: + node.parent.expand() + if node.parent.parent: + node.parent.parent.expand() + node.expand() + node.tree.select_node(node) + node.tree.scroll_to_node(node) + + def set_searched_tree_node(self, previous: bool) -> None: + """Set the cur_search_result node to either the next or previous.""" + l = len(self.search_results) + + if l < 1: + tree: Tree[str] = self.query_one("#pmus", Tree) + if previous: + tree.action_cursor_up() + else: + tree.action_cursor_down() + return + + if self.cur_search_result: + idx = self.search_results.index(self.cur_search_result) + if previous: + idx = idx - 1 if idx > 0 else l - 1 + else: + idx = idx + 1 if idx < l - 1 else 0 + else: + idx = l - 1 if previous else 0 + + node = self.search_results[idx] + if node == self.cur_search_result: + return + + self.cur_search_result = node + self.expand_and_select(node) + + def action_search(self) -> None: + """Search was chosen.""" + def set_initial_focus(event: str | None) -> None: + """Sets the focus after the SearchScreen is dismissed.""" + + search_label = self.query_one("#active_search", Label) + search_label.display = True if event else False + if not event: + return + event = event.lower() + search_label.update(f'Searching for events matching "{event}"') + + tree: Tree[str] = self.query_one("#pmus", Tree) + + def find_search_results(event: str, node: TreeNode[str], + cursor_seen: bool = False, + match_after_cursor: Optional[TreeNode[str]] = None + ) -> Tuple[bool, Optional[TreeNode[str]]]: + """Find nodes that match the search remembering the one after the cursor.""" + if not cursor_seen and node == tree.cursor_node: + cursor_seen = True + if node.data and event in node.data: + if cursor_seen and not match_after_cursor: + match_after_cursor = node + self.search_results.append(node) + + if node.children: + for child in node.children: + (cursor_seen, match_after_cursor) = \ + find_search_results(event, child, cursor_seen, match_after_cursor) + return (cursor_seen, match_after_cursor) + + self.search_results.clear() + (_, self.cur_search_result) = find_search_results(event, tree.root) + if len(self.search_results) < 1: + self.push_screen(ErrorScreen(f"Failed to find pmu/event {event}")) + search_label.display = False + elif self.cur_search_result: + self.expand_and_select(self.cur_search_result) + else: + self.set_searched_tree_node(previous=False) + + self.push_screen(SearchScreen(), set_initial_focus) + + def action_next(self) -> None: + """Next was chosen.""" + self.set_searched_tree_node(previous=False) + + def action_prev(self) -> None: + """Previous was chosen.""" + self.set_searched_tree_node(previous=True) + + def action_collapse(self) -> None: + """Collapse the potentially large number of events under a PMU.""" + tree: Tree[str] = self.query_one("#pmus", Tree) + node = tree.cursor_node + if node and node.parent and node.parent.parent: + node.parent.collapse_all() + node.tree.scroll_to_node(node.parent) + + def update_counts(self) -> None: + """Called every interval to update counts.""" + if not self.evlist: + return + + def update_count(cpu: int, count: int): + # Update the raw count display. + counter: Label = self.query(f"#counter_cpu{cpu}" if cpu >= 0 else "#counter_total") + if not counter: + return + counter = counter.first(Label) + counter.update(str(count)) + + # Update the sparkline. + line: Sparkline = self.query(f"#sparkline_cpu{cpu}" if cpu >= 0 else "#sparkline_total") + if not line: + return + line = line.first(Sparkline) + # If there are more events than the width, remove the front event. + if len(line.data) > line.size.width: + line.data.pop(0) + line.data.append(count) + line.mutate_reactive(Sparkline.data) + + # Update the total and each CPU counts, assume there's just 1 evsel. + total = 0 + self.evlist.disable() + for evsel in self.evlist: + for cpu in evsel.cpus(): + aggr = 0 + for thread in evsel.threads(): + counts = evsel.read(cpu, thread) + aggr += counts.val + update_count(cpu, aggr) + total += aggr + update_count(-1, total) + self.evlist.enable() + + def on_mount(self) -> None: + """When App starts set up periodic event updating.""" + self.update_counts() + self.set_interval(self.interval, self.update_counts) + + def set_pmu_and_event(self, pmu: str, event: str) -> None: + """Updates the event/description and starts the counters.""" + # Remove previous event information. + if self.evlist: + self.evlist.disable() + self.evlist.close() + lines = self.query(CounterSparkline) + for line in lines: + line.remove() + lines = self.query(Counter) + for line in lines: + line.remove() + + def pmu_event_description(pmu: str, event: str) -> str: + """Find and format event description for {pmu}/{event}/.""" + def get_info(info: Dict[str, str], key: str): + return (info[key] + "\n") if key in info else "" + + for p in perf.pmus(): + if p.name() != pmu: + continue + for info in p.events(): + if "name" not in info or info["name"] != event: + continue + + desc = get_info(info, "topic") + desc += get_info(info, "event_type_desc") + desc += get_info(info, "desc") + desc += get_info(info, "long_desc") + desc += get_info(info, "encoding_desc") + return desc + return "description" + + # Parse event, update event text and description. + full_name = event if event.startswith(pmu) or ':' in event else f"{pmu}/{event}/" + self.query_one("#event_name", Label).update(full_name) + self.query_one("#event_description", Static).update(pmu_event_description(pmu, event)) + + # Open the event. + try: + self.evlist = perf.parse_events(full_name) + if self.evlist: + self.evlist.open() + self.evlist.enable() + except: + self.evlist = None + + if not self.evlist: + self.push_screen(ErrorScreen(f"Failed to open {full_name}")) + return + + # Add spark lines for all the CPUs. Note, must be done after + # open so that the evlist CPUs have been computed by propagate + # maps. + lines = self.query_one("#lines") + line = CounterSparkline(cpu=-1) + lines.mount(line) + for cpu in self.evlist.all_cpus(): + line = CounterSparkline(cpu) + lines.mount(line) + line = Counter(cpu=-1) + lines.mount(line) + for cpu in self.evlist.all_cpus(): + line = Counter(cpu) + lines.mount(line) + + def compose(self) -> ComposeResult: + """Draws the app.""" + def pmu_event_tree() -> Tree: + """Create tree of PMUs with events under.""" + tree: Tree[str] = Tree("PMUs", id="pmus") + tree.root.expand() + for pmu in perf.pmus(): + pmu_name = pmu.name().lower() + pmu_node = tree.root.add(pmu_name, data=pmu_name) + try: + for event in sorted(pmu.events(), key=lambda x: x["name"]): + if "name" in event: + e = event["name"].lower() + if "alias" in event: + pmu_node.add_leaf(f'{e} ({event["alias"]})', data=e) + else: + pmu_node.add_leaf(e, data=e) + except: + # Reading events may fail with EPERM, ignore. + pass + return tree + + yield Header(id="header") + yield Horizontal(Vertical(pmu_event_tree(), id="events"), + Vertical(Label("event name", id="event_name"), + Static("description", markup=False, id="event_description"), + )) + yield Label(id="active_search") + yield VerticalScroll(id="lines") + yield Footer(id="footer") + + @on(Tree.NodeSelected) + def on_tree_node_selected(self, event: Tree.NodeSelected[str]) -> None: + """Called when a tree node is selected, selecting the event.""" + if event.node.parent and event.node.parent.parent: + assert event.node.parent.data is not None + assert event.node.data is not None + self.set_pmu_and_event(event.node.parent.data, event.node.data) + + +if __name__ == "__main__": + ap = argparse.ArgumentParser() + ap.add_argument('-I', '--interval', help="Counter update interval in seconds", default=0.1) + args = ap.parse_args() + app = IListApp(float(args.interval)) + app.run() From d0550be70f7ab84dfeff0db163a6bb924f70e2cb Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:36 -0700 Subject: [PATCH 0782/2711] perf python: Add parse_metrics function Add parse_metrics function that takes a string of metrics and/or metric groups and returns the evlist containing the events and metrics. For example: ``` >>> import perf >>> perf.parse_metrics("TopdownL1") evlist([cpu/TOPDOWN.SLOTS/,cpu/topdown-retiring/,cpu/topdown-fe-bound/, cpu/topdown-be-bound/,cpu/topdown-bad-spec/,cpu/INT_MISC.CLEARS_COUNT/, cpu/INT_MISC.UOP_DROPPING/]) ``` Reviewed-by: Howard Chu Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index cf1128435022..48308ed4e1c7 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -1891,6 +1891,40 @@ static PyObject *pyrf__parse_events(PyObject *self, PyObject *args) return result; } +static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) +{ + const char *input; + struct evlist evlist = {}; + PyObject *result; + PyObject *pcpus = NULL, *pthreads = NULL; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; + int ret; + + if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads)) + return NULL; + + threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL; + cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL; + + evlist__init(&evlist, cpus, threads); + ret = metricgroup__parse_groups(&evlist, /*pmu=*/"all", input, + /*metric_no_group=*/ false, + /*metric_no_merge=*/ false, + /*metric_no_threshold=*/ true, + /*user_requested_cpu_list=*/ NULL, + /*system_wide=*/true, + /*hardware_aware_grouping=*/ false); + if (ret) { + errno = -ret; + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + result = pyrf_evlist__from_evlist(&evlist); + evlist__exit(&evlist); + return result; +} + static PyMethodDef perf__methods[] = { { .ml_name = "tracepoint", @@ -1904,6 +1938,13 @@ static PyMethodDef perf__methods[] = { .ml_flags = METH_VARARGS, .ml_doc = PyDoc_STR("Parse a string of events and return an evlist.") }, + { + .ml_name = "parse_metrics", + .ml_meth = (PyCFunction) pyrf__parse_metrics, + .ml_flags = METH_VARARGS, + .ml_doc = PyDoc_STR( + "Parse a string of metics or metric groups and return an evlist.") + }, { .ml_name = "pmus", .ml_meth = (PyCFunction) pyrf__pmus, From 5ffa0246db5adb7839f9506c83554efd069c9142 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:37 -0700 Subject: [PATCH 0783/2711] perf python: Add evlist metrics function The function returns a list of the names of metrics within the evlist. For example: ``` >>> import perf >>> perf.parse_metrics("TopdownL1").metrics() ['tma_bad_speculation', 'tma_frontend_bound', 'tma_backend_bound', 'tma_retiring'] ``` Reviewed-by: Howard Chu Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-8-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 48308ed4e1c7..31089f8e5519 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -1303,6 +1303,33 @@ static PyObject *pyrf_evlist__all_cpus(struct pyrf_evlist *pevlist) return (PyObject *)pcpu_map; } +static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist) +{ + PyObject *list = PyList_New(/*len=*/0); + struct rb_node *node; + + if (!list) + return NULL; + + for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node; + node = rb_next(node)) { + struct metric_event *me = container_of(node, struct metric_event, nd); + struct list_head *pos; + + list_for_each(pos, &me->head) { + struct metric_expr *expr = container_of(pos, struct metric_expr, nd); + PyObject *str = PyUnicode_FromString(expr->metric_name); + + if (!str || PyList_Append(list, str) != 0) { + Py_DECREF(list); + return NULL; + } + Py_DECREF(str); + } + } + return list; +} + static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { @@ -1531,6 +1558,12 @@ static PyMethodDef pyrf_evlist__methods[] = { .ml_flags = METH_NOARGS, .ml_doc = PyDoc_STR("CPU map union of all evsel CPU maps.") }, + { + .ml_name = "metrics", + .ml_meth = (PyCFunction)pyrf_evlist__metrics, + .ml_flags = METH_NOARGS, + .ml_doc = PyDoc_STR("List of metric names within the evlist.") + }, { .ml_name = "mmap", .ml_meth = (PyCFunction)pyrf_evlist__mmap, From 064647d61c28ab16d3f6a98e30685694198551ac Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:38 -0700 Subject: [PATCH 0784/2711] perf python: Add evlist compute_metric MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a compute_metric function that computes a metric double value for a given evlist, metric name, CPU and thread. For example: ``` >>> import perf >>> x = perf.parse_metrics("TopdownL1") >>> x.open() >>> x.enable() >>> x.disable() >>> x.metrics() ['tma_bad_speculation', 'tma_frontend_bound', 'tma_backend_bound', 'tma_retiring'] >>> x.compute_metric('tma_bad_speculation', 0, -1) 0.08605342847131037 ``` Committer notes: Initialize thread_idx and cpu_idx to zero as albeit them not possibly coming out unitialized from the loop as mexp would be not NULL only if they were initialized, some older compilers don't notice that and error with: GEN /tmp/build/perf/python/perf.cpython-36m-x86_64-linux-gnu.so /git/perf-6.17.0-rc3/tools/perf/util/python.c: In function ‘pyrf_evlist__compute_metric’: /git/perf-6.17.0-rc3/tools/perf/util/python.c:1363:3: error: ‘thread_idx’ may be used uninitialized in this function [-Werror=maybe-uninitialized] evsel__read_counter(metric_events[i], cpu_idx, thread_idx); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /git/perf-6.17.0-rc3/tools/perf/util/python.c:1389:41: note: ‘thread_idx’ was declared here int ret, cpu = 0, cpu_idx, thread = 0, thread_idx; ^~~~~~~~~~ /git/perf-6.17.0-rc3/tools/perf/util/python.c:1363:3: error: ‘cpu_idx’ may be used uninitialized in this function [-Werror=maybe-uninitialized] evsel__read_counter(metric_events[i], cpu_idx, thread_idx); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /git/perf-6.17.0-rc3/tools/perf/util/python.c:1389:20: note: ‘cpu_idx’ was declared here int ret, cpu = 0, cpu_idx, thread = 0, thread_idx; ^~~~~~~ /git/perf-6.17.0-rc3/tools/perf/util/python.c: At top level: cc1: error: unrecognized command line option ‘-Wno-cast-function-type’ [-Werror] cc1: all warnings being treated as errors error: command 'gcc' failed with exit status 1 cp: cannot stat '/tmp/build/perf/python_ext_build/lib/perf*.so': No such file or directory Reviewed-by: Howard Chu Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-9-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 125 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 31089f8e5519..ad8a5446ae48 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -14,6 +14,7 @@ #include "evlist.h" #include "evsel.h" #include "event.h" +#include "expr.h" #include "print_binary.h" #include "record.h" #include "strbuf.h" @@ -1330,6 +1331,124 @@ static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist) return list; } +static int prepare_metric(const struct metric_expr *mexp, + const struct evsel *evsel, + struct expr_parse_ctx *pctx, + int cpu_idx, int thread_idx) +{ + struct evsel * const *metric_events = mexp->metric_events; + struct metric_ref *metric_refs = mexp->metric_refs; + + for (int i = 0; metric_events[i]; i++) { + char *n = strdup(evsel__metric_id(metric_events[i])); + double val, ena, run; + int source_count = evsel__source_count(metric_events[i]); + int ret; + struct perf_counts_values *old_count, *new_count; + + if (!n) + return -ENOMEM; + + if (source_count == 0) + source_count = 1; + + ret = evsel__ensure_counts(metric_events[i]); + if (ret) + return ret; + + /* Set up pointers to the old and newly read counter values. */ + old_count = perf_counts(metric_events[i]->prev_raw_counts, cpu_idx, thread_idx); + new_count = perf_counts(metric_events[i]->counts, cpu_idx, thread_idx); + /* Update the value in metric_events[i]->counts. */ + evsel__read_counter(metric_events[i], cpu_idx, thread_idx); + + val = new_count->val - old_count->val; + ena = new_count->ena - old_count->ena; + run = new_count->run - old_count->run; + + if (ena != run && run != 0) + val = val * ena / run; + ret = expr__add_id_val_source_count(pctx, n, val, source_count); + if (ret) + return ret; + } + + for (int i = 0; metric_refs && metric_refs[i].metric_name; i++) { + int ret = expr__add_ref(pctx, &metric_refs[i]); + + if (ret) + return ret; + } + + return 0; +} + +static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist, + PyObject *args, PyObject *kwargs) +{ + int ret, cpu = 0, cpu_idx = 0, thread = 0, thread_idx = 0; + const char *metric; + struct rb_node *node; + struct metric_expr *mexp = NULL; + struct expr_parse_ctx *pctx; + double result = 0; + + if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread)) + return NULL; + + for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); + mexp == NULL && node; + node = rb_next(node)) { + struct metric_event *me = container_of(node, struct metric_event, nd); + struct list_head *pos; + + list_for_each(pos, &me->head) { + struct metric_expr *e = container_of(pos, struct metric_expr, nd); + + if (strcmp(e->metric_name, metric)) + continue; + + if (e->metric_events[0] == NULL) + continue; + + cpu_idx = perf_cpu_map__idx(e->metric_events[0]->core.cpus, + (struct perf_cpu){.cpu = cpu}); + if (cpu_idx < 0) + continue; + + thread_idx = perf_thread_map__idx(e->metric_events[0]->core.threads, + thread); + if (thread_idx < 0) + continue; + + mexp = e; + break; + } + } + if (!mexp) { + PyErr_Format(PyExc_TypeError, "Unknown metric '%s' for CPU '%d' and thread '%d'", + metric, cpu, thread); + return NULL; + } + + pctx = expr__ctx_new(); + if (!pctx) + return PyErr_NoMemory(); + + ret = prepare_metric(mexp, mexp->metric_events[0], pctx, cpu_idx, thread_idx); + if (ret) { + expr__ctx_free(pctx); + errno = -ret; + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if (expr__parse(&result, pctx, mexp->metric_expr)) + result = 0.0; + + expr__ctx_free(pctx); + return PyFloat_FromDouble(result); +} + static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { @@ -1564,6 +1683,12 @@ static PyMethodDef pyrf_evlist__methods[] = { .ml_flags = METH_NOARGS, .ml_doc = PyDoc_STR("List of metric names within the evlist.") }, + { + .ml_name = "compute_metric", + .ml_meth = (PyCFunction)pyrf_evlist__compute_metric, + .ml_flags = METH_VARARGS | METH_KEYWORDS, + .ml_doc = PyDoc_STR("compute metric for given name, cpu and thread") + }, { .ml_name = "mmap", .ml_meth = (PyCFunction)pyrf_evlist__mmap, From 47b3e95728eb4104adca3d4a0ec018fcaa738b82 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:39 -0700 Subject: [PATCH 0785/2711] perf python: Add metrics function The metrics function returns a list dictionaries describing metrics as strings mapping to strings, except for metric groups that are a string mapping to a list of strings. For example: ``` >>> import perf >>> perf.metrics()[0] {'MetricGroup': ['Power'], 'MetricName': 'C10_Pkg_Residency', 'PMU': 'default_core', 'MetricExpr': 'cstate_pkg@c10\\-residency@ / TSC', 'ScaleUnit': '100%', 'BriefDescription': 'C10 residency percent per package'} ``` Reviewed-by: Howard Chu Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-10-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 86 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index ad8a5446ae48..47178404802f 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -2083,7 +2083,93 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) return result; } +static PyObject *pyrf__metrics_groups(const struct pmu_metric *pm) +{ + PyObject *groups = PyList_New(/*len=*/0); + const char *mg = pm->metric_group; + + if (!groups) + return NULL; + + while (mg) { + PyObject *val = NULL; + const char *sep = strchr(mg, ';'); + size_t len = sep ? (size_t)(sep - mg) : strlen(mg); + + if (len > 0) { + val = PyUnicode_FromStringAndSize(mg, len); + if (val) + PyList_Append(groups, val); + + Py_XDECREF(val); + } + mg = sep ? sep + 1 : NULL; + } + return groups; +} + +static int pyrf__metrics_cb(const struct pmu_metric *pm, + const struct pmu_metrics_table *table __maybe_unused, + void *vdata) +{ + PyObject *py_list = vdata; + PyObject *dict = PyDict_New(); + PyObject *key = dict ? PyUnicode_FromString("MetricGroup") : NULL; + PyObject *value = key ? pyrf__metrics_groups(pm) : NULL; + + if (!value || PyDict_SetItem(dict, key, value) != 0) { + Py_XDECREF(key); + Py_XDECREF(value); + Py_XDECREF(dict); + return -ENOMEM; + } + + if (!add_to_dict(dict, "MetricName", pm->metric_name) || + !add_to_dict(dict, "PMU", pm->pmu) || + !add_to_dict(dict, "MetricExpr", pm->metric_expr) || + !add_to_dict(dict, "MetricThreshold", pm->metric_threshold) || + !add_to_dict(dict, "ScaleUnit", pm->unit) || + !add_to_dict(dict, "Compat", pm->compat) || + !add_to_dict(dict, "BriefDescription", pm->desc) || + !add_to_dict(dict, "PublicDescription", pm->long_desc) || + PyList_Append(py_list, dict) != 0) { + Py_DECREF(dict); + return -ENOMEM; + } + Py_DECREF(dict); + return 0; +} + +static PyObject *pyrf__metrics(PyObject *self, PyObject *args) +{ + const struct pmu_metrics_table *table = pmu_metrics_table__find(); + PyObject *list = PyList_New(/*len=*/0); + int ret; + + if (!list) + return NULL; + + ret = pmu_metrics_table__for_each_metric(table, pyrf__metrics_cb, list); + if (!ret) + ret = pmu_for_each_sys_metric(pyrf__metrics_cb, list); + + if (ret) { + Py_DECREF(list); + errno = -ret; + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return list; +} + static PyMethodDef perf__methods[] = { + { + .ml_name = "metrics", + .ml_meth = (PyCFunction) pyrf__metrics, + .ml_flags = METH_NOARGS, + .ml_doc = PyDoc_STR( + "Returns a list of metrics represented as string values in dictionaries.") + }, { .ml_name = "tracepoint", .ml_meth = (PyCFunction) pyrf__tracepoint, From a3f4104daa9f4399c295f1269d54491baf60f9be Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:40 -0700 Subject: [PATCH 0786/2711] perf ilist: Add support for metrics Change tree nodes to having a value of either Metric or PmuEvent, these values have the ability to match searches, be parsed to create evlists and to give a value per CPU and per thread to display. Use perf.metrics to generate a tree of metrics. Most metrics are placed under their metric group, if the metric group name ends with '_group' then the metric group is placed next to the associated metric. Reviewed-by: Howard Chu Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-11-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/python/ilist.py | 226 +++++++++++++++++++++++++++---------- 1 file changed, 168 insertions(+), 58 deletions(-) diff --git a/tools/perf/python/ilist.py b/tools/perf/python/ilist.py index 22c70a8b31f3..9d6465c60df3 100755 --- a/tools/perf/python/ilist.py +++ b/tools/perf/python/ilist.py @@ -2,19 +2,121 @@ # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) """Interactive perf list.""" +from abc import ABC, abstractmethod import argparse +from dataclasses import dataclass +import math from typing import Any, Dict, Optional, Tuple import perf from textual import on from textual.app import App, ComposeResult from textual.binding import Binding from textual.containers import Horizontal, HorizontalGroup, Vertical, VerticalScroll +from textual.css.query import NoMatches from textual.command import SearchIcon from textual.screen import ModalScreen from textual.widgets import Button, Footer, Header, Input, Label, Sparkline, Static, Tree from textual.widgets.tree import TreeNode +def get_info(info: Dict[str, str], key: str): + return (info[key] + "\n") if key in info else "" + + +class TreeValue(ABC): + """Abstraction for the data of value in the tree.""" + + @abstractmethod + def name(self) -> str: + pass + + @abstractmethod + def description(self) -> str: + pass + + @abstractmethod + def matches(self, query: str) -> bool: + pass + + @abstractmethod + def parse(self) -> perf.evlist: + pass + + @abstractmethod + def value(self, evlist: perf.evlist, evsel: perf.evsel, cpu: int, thread: int) -> float: + pass + + +@dataclass +class Metric(TreeValue): + """A metric in the tree.""" + metric_name: str + + def name(self) -> str: + return self.metric_name + + def description(self) -> str: + """Find and format metric description.""" + for metric in perf.metrics(): + if metric["MetricName"] != self.metric_name: + continue + desc = get_info(metric, "BriefDescription") + desc += get_info(metric, "PublicDescription") + desc += get_info(metric, "MetricExpr") + desc += get_info(metric, "MetricThreshold") + return desc + return "description" + + def matches(self, query: str) -> bool: + return query in self.metric_name + + def parse(self) -> perf.evlist: + return perf.parse_metrics(self.metric_name) + + def value(self, evlist: perf.evlist, evsel: perf.evsel, cpu: int, thread: int) -> float: + val = evlist.compute_metric(self.metric_name, cpu, thread) + return 0 if math.isnan(val) else val + + +@dataclass +class PmuEvent(TreeValue): + """A PMU and event within the tree.""" + pmu: str + event: str + + def name(self) -> str: + if self.event.startswith(self.pmu) or ':' in self.event: + return self.event + else: + return f"{self.pmu}/{self.event}/" + + def description(self) -> str: + """Find and format event description for {pmu}/{event}/.""" + for p in perf.pmus(): + if p.name() != self.pmu: + continue + for info in p.events(): + if "name" not in info or info["name"] != self.event: + continue + + desc = get_info(info, "topic") + desc += get_info(info, "event_type_desc") + desc += get_info(info, "desc") + desc += get_info(info, "long_desc") + desc += get_info(info, "encoding_desc") + return desc + return "description" + + def matches(self, query: str) -> bool: + return query in self.pmu or query in self.event + + def parse(self) -> perf.evlist: + return perf.parse_events(self.name()) + + def value(self, evlist: perf.evlist, evsel: perf.evsel, cpu: int, thread: int) -> float: + return evsel.read(cpu, thread).val + + class ErrorScreen(ModalScreen[bool]): """Pop up dialog for errors.""" @@ -126,8 +228,9 @@ class IListApp(App): def __init__(self, interval: float) -> None: self.interval = interval self.evlist = None - self.search_results: list[TreeNode[str]] = [] - self.cur_search_result: TreeNode[str] | None = None + self.selected: Optional[TreeValue] = None + self.search_results: list[TreeNode[TreeValue]] = [] + self.cur_search_result: TreeNode[TreeValue] | None = None super().__init__() def expand_and_select(self, node: TreeNode[Any]) -> None: @@ -145,7 +248,7 @@ class IListApp(App): l = len(self.search_results) if l < 1: - tree: Tree[str] = self.query_one("#pmus", Tree) + tree: Tree[TreeValue] = self.query_one("#root", Tree) if previous: tree.action_cursor_up() else: @@ -180,7 +283,7 @@ class IListApp(App): event = event.lower() search_label.update(f'Searching for events matching "{event}"') - tree: Tree[str] = self.query_one("#pmus", Tree) + tree: Tree[str] = self.query_one("#root", Tree) def find_search_results(event: str, node: TreeNode[str], cursor_seen: bool = False, @@ -189,7 +292,7 @@ class IListApp(App): """Find nodes that match the search remembering the one after the cursor.""" if not cursor_seen and node == tree.cursor_node: cursor_seen = True - if node.data and event in node.data: + if node.data and node.data.matches(event): if cursor_seen and not match_after_cursor: match_after_cursor = node self.search_results.append(node) @@ -203,7 +306,7 @@ class IListApp(App): self.search_results.clear() (_, self.cur_search_result) = find_search_results(event, tree.root) if len(self.search_results) < 1: - self.push_screen(ErrorScreen(f"Failed to find pmu/event {event}")) + self.push_screen(ErrorScreen(f"Failed to find pmu/event or metric {event}")) search_label.display = False elif self.cur_search_result: self.expand_and_select(self.cur_search_result) @@ -221,16 +324,16 @@ class IListApp(App): self.set_searched_tree_node(previous=True) def action_collapse(self) -> None: - """Collapse the potentially large number of events under a PMU.""" - tree: Tree[str] = self.query_one("#pmus", Tree) + """Collapse the part of the tree currently on.""" + tree: Tree[str] = self.query_one("#root", Tree) node = tree.cursor_node - if node and node.parent and node.parent.parent: + if node and node.parent: node.parent.collapse_all() node.tree.scroll_to_node(node.parent) def update_counts(self) -> None: """Called every interval to update counts.""" - if not self.evlist: + if not self.selected or not self.evlist: return def update_count(cpu: int, count: int): @@ -259,8 +362,7 @@ class IListApp(App): for cpu in evsel.cpus(): aggr = 0 for thread in evsel.threads(): - counts = evsel.read(cpu, thread) - aggr += counts.val + aggr += self.selected.value(self.evlist, evsel, cpu, thread) update_count(cpu, aggr) total += aggr update_count(-1, total) @@ -271,47 +373,37 @@ class IListApp(App): self.update_counts() self.set_interval(self.interval, self.update_counts) - def set_pmu_and_event(self, pmu: str, event: str) -> None: + def set_selected(self, value: TreeValue) -> None: """Updates the event/description and starts the counters.""" + try: + label_name = self.query_one("#event_name", Label) + event_description = self.query_one("#event_description", Static) + lines = self.query_one("#lines") + except NoMatches: + # A race with rendering, ignore the update as we can't + # mount the assumed output widgets. + return + + self.selected = value + # Remove previous event information. if self.evlist: self.evlist.disable() self.evlist.close() - lines = self.query(CounterSparkline) - for line in lines: - line.remove() - lines = self.query(Counter) - for line in lines: + old_lines = self.query(CounterSparkline) + for line in old_lines: line.remove() + old_counters = self.query(Counter) + for counter in old_counters: + counter.remove() - def pmu_event_description(pmu: str, event: str) -> str: - """Find and format event description for {pmu}/{event}/.""" - def get_info(info: Dict[str, str], key: str): - return (info[key] + "\n") if key in info else "" - - for p in perf.pmus(): - if p.name() != pmu: - continue - for info in p.events(): - if "name" not in info or info["name"] != event: - continue - - desc = get_info(info, "topic") - desc += get_info(info, "event_type_desc") - desc += get_info(info, "desc") - desc += get_info(info, "long_desc") - desc += get_info(info, "encoding_desc") - return desc - return "description" - - # Parse event, update event text and description. - full_name = event if event.startswith(pmu) or ':' in event else f"{pmu}/{event}/" - self.query_one("#event_name", Label).update(full_name) - self.query_one("#event_description", Static).update(pmu_event_description(pmu, event)) + # Update event/metric text and description. + label_name.update(value.name()) + event_description.update(value.description()) # Open the event. try: - self.evlist = perf.parse_events(full_name) + self.evlist = value.parse() if self.evlist: self.evlist.open() self.evlist.enable() @@ -319,13 +411,12 @@ class IListApp(App): self.evlist = None if not self.evlist: - self.push_screen(ErrorScreen(f"Failed to open {full_name}")) + self.push_screen(ErrorScreen(f"Failed to open {value.name()}")) return # Add spark lines for all the CPUs. Note, must be done after # open so that the evlist CPUs have been computed by propagate # maps. - lines = self.query_one("#lines") line = CounterSparkline(cpu=-1) lines.mount(line) for cpu in self.evlist.all_cpus(): @@ -339,28 +430,49 @@ class IListApp(App): def compose(self) -> ComposeResult: """Draws the app.""" - def pmu_event_tree() -> Tree: - """Create tree of PMUs with events under.""" - tree: Tree[str] = Tree("PMUs", id="pmus") - tree.root.expand() + def metric_event_tree() -> Tree: + """Create tree of PMUs and metricgroups with events or metrics under.""" + tree: Tree[TreeValue] = Tree("Root", id="root") + pmus = tree.root.add("PMUs") for pmu in perf.pmus(): pmu_name = pmu.name().lower() - pmu_node = tree.root.add(pmu_name, data=pmu_name) + pmu_node = pmus.add(pmu_name) try: for event in sorted(pmu.events(), key=lambda x: x["name"]): if "name" in event: e = event["name"].lower() if "alias" in event: - pmu_node.add_leaf(f'{e} ({event["alias"]})', data=e) + pmu_node.add_leaf(f'{e} ({event["alias"]})', + data=PmuEvent(pmu_name, e)) else: - pmu_node.add_leaf(e, data=e) + pmu_node.add_leaf(e, data=PmuEvent(pmu_name, e)) except: # Reading events may fail with EPERM, ignore. pass + metrics = tree.root.add("Metrics") + groups = set() + for metric in perf.metrics(): + groups.update(metric["MetricGroup"]) + + def add_metrics_to_tree(node: TreeNode[TreeValue], parent: str): + for metric in sorted(perf.metrics(), key=lambda x: x["MetricName"]): + if parent in metric["MetricGroup"]: + name = metric["MetricName"] + node.add_leaf(name, data=Metric(name)) + child_group_name = f'{name}_group' + if child_group_name in groups: + add_metrics_to_tree(node.add(child_group_name), child_group_name) + + for group in sorted(groups): + if group.endswith('_group'): + continue + add_metrics_to_tree(metrics.add(group), group) + + tree.root.expand() return tree yield Header(id="header") - yield Horizontal(Vertical(pmu_event_tree(), id="events"), + yield Horizontal(Vertical(metric_event_tree(), id="events"), Vertical(Label("event name", id="event_name"), Static("description", markup=False, id="event_description"), )) @@ -369,12 +481,10 @@ class IListApp(App): yield Footer(id="footer") @on(Tree.NodeSelected) - def on_tree_node_selected(self, event: Tree.NodeSelected[str]) -> None: + def on_tree_node_selected(self, event: Tree.NodeSelected[TreeValue]) -> None: """Called when a tree node is selected, selecting the event.""" - if event.node.parent and event.node.parent.parent: - assert event.node.parent.data is not None - assert event.node.data is not None - self.set_pmu_and_event(event.node.parent.data, event.node.data) + if event.node.data: + self.set_selected(event.node.data) if __name__ == "__main__": From 9105df0185ea3a89e6651985e829897a8d3a94ae Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 18:39:41 -0700 Subject: [PATCH 0787/2711] perf tp_pmu: Remove unnecessary check The "if" condition is also part of the "while" condition, remove the "if" to reduce the amount of code. Reported-by: Howard Chu Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Chun-Tse Shao Cc: Collin Funk Cc: Dr. David Alan Gilbert Cc: Gautam Menghani Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Thomas Richter Cc: Tiezhu Yang Cc: Weilin Wang Cc: Xu Yang Link: https://lore.kernel.org/r/20250819013941.209033-12-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/tp_pmu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/util/tp_pmu.c b/tools/perf/util/tp_pmu.c index e7534a973247..eddb9807131a 100644 --- a/tools/perf/util/tp_pmu.c +++ b/tools/perf/util/tp_pmu.c @@ -88,8 +88,6 @@ int tp_pmu__for_each_tp_sys(void *state, tp_sys_callback cb) continue; ret = cb(state, events_ent->d_name); - if (ret) - break; } close(events_dir.dirfd); return ret; From 414bf79debdce9bb682b4f23f87ea97568afa67b Mon Sep 17 00:00:00 2001 From: Zecheng Li Date: Mon, 25 Aug 2025 19:54:03 +0000 Subject: [PATCH 0788/2711] perf dwarf-aux: Use signed variable types in match_var_offset match_var_offset() compares address offsets to determine if an access falls within a variable's bounds. The offsets involved for those relative to base registers from DW_OP_breg can be negative. The current implementation uses unsigned types (u64) for these offsets, which rejects almost all negative values. Change the signature of match_var_offset() to use signed types (s64). This ensures correct behavior when addr_offset or addr_type are negative. Reviewed-by: Namhyung Kim Signed-off-by: Zecheng Li Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Xu Liu Link: https://lore.kernel.org/r/20250825195412.223077-2-zecheng@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 559c953ca172..920054425578 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1388,18 +1388,19 @@ struct find_var_data { #define DWARF_OP_DIRECT_REGS 32 static bool match_var_offset(Dwarf_Die *die_mem, struct find_var_data *data, - u64 addr_offset, u64 addr_type, bool is_pointer) + s64 addr_offset, s64 addr_type, bool is_pointer) { Dwarf_Die type_die; Dwarf_Word size; + s64 offset = addr_offset - addr_type; - if (addr_offset == addr_type) { + if (offset == 0) { /* Update offset relative to the start of the variable */ data->offset = 0; return true; } - if (addr_offset < addr_type) + if (offset < 0) return false; if (die_get_real_type(die_mem, &type_die) == NULL) @@ -1414,11 +1415,11 @@ static bool match_var_offset(Dwarf_Die *die_mem, struct find_var_data *data, if (dwarf_aggregate_size(&type_die, &size) < 0) return false; - if (addr_offset >= addr_type + size) + if ((u64)offset >= size) return false; /* Update offset relative to the start of the variable */ - data->offset = addr_offset - addr_type; + data->offset = offset; return true; } From e1a8805e5d263453ad76a4f50ab3b1c18ea07560 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Tue, 19 Aug 2025 08:04:08 -0700 Subject: [PATCH 0789/2711] PCI: tegra: Fix devm_kcalloc() argument order for port->phys allocation Fix incorrect argument order in devm_kcalloc() when allocating port->phys. The original call used sizeof(phy) as the number of elements and port->lanes as the element size, which is reversed. While this happens to produce the correct total allocation size with current pointer size and lane counts, the argument order is wrong. Fixes: 6fe7c187e026 ("PCI: tegra: Support per-lane PHYs") Signed-off-by: Alok Tiwari [mani: added Fixes tag] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250819150436.3105973-1-alok.a.tiwari@oracle.com --- drivers/pci/controller/pci-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index 467ddc701adc..bb88767a3797 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -1344,7 +1344,7 @@ static int tegra_pcie_port_get_phys(struct tegra_pcie_port *port) unsigned int i; int err; - port->phys = devm_kcalloc(dev, sizeof(phy), port->lanes, GFP_KERNEL); + port->phys = devm_kcalloc(dev, port->lanes, sizeof(phy), GFP_KERNEL); if (!port->phys) return -ENOMEM; From 54dbd2a8e974b900b18639e75f62702a4334ddc0 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 3 Sep 2025 14:52:56 +0300 Subject: [PATCH 0790/2711] PCI/P2PDMA: Reduce scope of pci_has_p2pmem() pci_has_p2pmem() is not used outside of p2pdma.c, and there is no need to export it for use by modules. Signed-off-by: Leon Romanovsky Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe Link: https://patch.msgid.link/d40f3f1decf54c9236bc38b48a6aae612a5c182f.1756900291.git.leon@kernel.org --- drivers/pci/p2pdma.c | 3 +-- include/linux/pci-p2pdma.h | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 1cb5e423eed4..78e108e47254 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -738,7 +738,7 @@ EXPORT_SYMBOL_GPL(pci_p2pdma_distance_many); * pci_has_p2pmem - check if a given PCI device has published any p2pmem * @pdev: PCI device to check */ -bool pci_has_p2pmem(struct pci_dev *pdev) +static bool pci_has_p2pmem(struct pci_dev *pdev) { struct pci_p2pdma *p2pdma; bool res; @@ -750,7 +750,6 @@ bool pci_has_p2pmem(struct pci_dev *pdev) return res; } -EXPORT_SYMBOL_GPL(pci_has_p2pmem); /** * pci_p2pmem_find_many - find a peer-to-peer DMA memory device compatible with diff --git a/include/linux/pci-p2pdma.h b/include/linux/pci-p2pdma.h index 075c20b161d9..951f81a38f3a 100644 --- a/include/linux/pci-p2pdma.h +++ b/include/linux/pci-p2pdma.h @@ -21,7 +21,6 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size, u64 offset); int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients, int num_clients, bool verbose); -bool pci_has_p2pmem(struct pci_dev *pdev); struct pci_dev *pci_p2pmem_find_many(struct device **clients, int num_clients); void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size); void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size); @@ -45,10 +44,6 @@ static inline int pci_p2pdma_distance_many(struct pci_dev *provider, { return -1; } -static inline bool pci_has_p2pmem(struct pci_dev *pdev) -{ - return false; -} static inline struct pci_dev *pci_p2pmem_find_many(struct device **clients, int num_clients) { From 781c118c3ece2b546c6c41f617cccb36cb9534f1 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 29 Aug 2025 13:28:03 +0530 Subject: [PATCH 0791/2711] dt-bindings: clock: Add DISPCC and reset controller for GLYMUR SoC Add the device tree bindings for the display clock controller which are required on Qualcomm Glymur SoC. Signed-off-by: Taniya Das Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250829-glymur-disp-clock-controllers-v1-1-0ce6fabd837c@oss.qualcomm.com [bjorn: Dropped unnecessary include in DT example] Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,glymur-dispcc.yaml | 98 +++++++++++++++ .../dt-bindings/clock/qcom,glymur-dispcc.h | 114 ++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,glymur-dispcc.yaml create mode 100644 include/dt-bindings/clock/qcom,glymur-dispcc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,glymur-dispcc.yaml b/Documentation/devicetree/bindings/clock/qcom,glymur-dispcc.yaml new file mode 100644 index 000000000000..45f027c70e03 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,glymur-dispcc.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,glymur-dispcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display Clock & Reset Controller on GLYMUR + +maintainers: + - Taniya Das + +description: | + Qualcomm display clock control module which supports the clocks, resets and + power domains for the MDSS instances on GLYMUR SoC. + + See also: + include/dt-bindings/clock/qcom,dispcc-glymur.h + +properties: + compatible: + enum: + - qcom,glymur-dispcc + + clocks: + items: + - description: Board CXO clock + - description: Board sleep clock + - description: DisplayPort 0 link clock + - description: DisplayPort 0 VCO div clock + - description: DisplayPort 1 link clock + - description: DisplayPort 1 VCO div clock + - description: DisplayPort 2 link clock + - description: DisplayPort 2 VCO div clock + - description: DisplayPort 3 link clock + - description: DisplayPort 3 VCO div clock + - description: DSI 0 PLL byte clock + - description: DSI 0 PLL DSI clock + - description: DSI 1 PLL byte clock + - description: DSI 1 PLL DSI clock + - description: Standalone PHY 0 PLL link clock + - description: Standalone PHY 0 VCO div clock + - description: Standalone PHY 1 PLL link clock + - description: Standalone PHY 1 VCO div clock + + power-domains: + description: + A phandle and PM domain specifier for the MMCX power domain. + maxItems: 1 + + required-opps: + description: + A phandle to an OPP node describing required MMCX performance point. + maxItems: 1 + +required: + - compatible + - clocks + - power-domains + - '#power-domain-cells' + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + clock-controller@af00000 { + compatible = "qcom,glymur-dispcc"; + reg = <0x0af00000 0x20000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&sleep_clk>, + <&mdss_dp_phy0 0>, + <&mdss_dp_phy0 1>, + <&mdss_dp_phy1 0>, + <&mdss_dp_phy1 1>, + <&mdss_dp_phy2 0>, + <&mdss_dp_phy2 1>, + <&mdss_dp_phy3 0>, + <&mdss_dp_phy3 1>, + <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>, + <&mdss_dsi1_phy 0>, + <&mdss_dsi1_phy 1>, + <&mdss_phy0_link 0>, + <&mdss_phy0_vco_div 0>, + <&mdss_phy1_link 1>, + <&mdss_phy1_vco_div 1>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + required-opps = <&rpmhpd_opp_low_svs>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/include/dt-bindings/clock/qcom,glymur-dispcc.h b/include/dt-bindings/clock/qcom,glymur-dispcc.h new file mode 100644 index 000000000000..a845d76defe2 --- /dev/null +++ b/include/dt-bindings/clock/qcom,glymur-dispcc.h @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_GLYMUR_H +#define _DT_BINDINGS_CLK_QCOM_DISP_CC_GLYMUR_H + +/* DISP_CC clocks */ +#define DISP_CC_ESYNC0_CLK 0 +#define DISP_CC_ESYNC0_CLK_SRC 1 +#define DISP_CC_ESYNC1_CLK 2 +#define DISP_CC_ESYNC1_CLK_SRC 3 +#define DISP_CC_MDSS_ACCU_SHIFT_CLK 4 +#define DISP_CC_MDSS_AHB1_CLK 5 +#define DISP_CC_MDSS_AHB_CLK 6 +#define DISP_CC_MDSS_AHB_CLK_SRC 7 +#define DISP_CC_MDSS_BYTE0_CLK 8 +#define DISP_CC_MDSS_BYTE0_CLK_SRC 9 +#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 10 +#define DISP_CC_MDSS_BYTE0_INTF_CLK 11 +#define DISP_CC_MDSS_BYTE1_CLK 12 +#define DISP_CC_MDSS_BYTE1_CLK_SRC 13 +#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 14 +#define DISP_CC_MDSS_BYTE1_INTF_CLK 15 +#define DISP_CC_MDSS_DPTX0_AUX_CLK 16 +#define DISP_CC_MDSS_DPTX0_AUX_CLK_SRC 17 +#define DISP_CC_MDSS_DPTX0_LINK_CLK 18 +#define DISP_CC_MDSS_DPTX0_LINK_CLK_SRC 19 +#define DISP_CC_MDSS_DPTX0_LINK_DIV_CLK_SRC 20 +#define DISP_CC_MDSS_DPTX0_LINK_DPIN_CLK 21 +#define DISP_CC_MDSS_DPTX0_LINK_DPIN_DIV_CLK_SRC 22 +#define DISP_CC_MDSS_DPTX0_LINK_INTF_CLK 23 +#define DISP_CC_MDSS_DPTX0_PIXEL0_CLK 24 +#define DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC 25 +#define DISP_CC_MDSS_DPTX0_PIXEL1_CLK 26 +#define DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC 27 +#define DISP_CC_MDSS_DPTX0_USB_ROUTER_LINK_INTF_CLK 28 +#define DISP_CC_MDSS_DPTX1_AUX_CLK 29 +#define DISP_CC_MDSS_DPTX1_AUX_CLK_SRC 30 +#define DISP_CC_MDSS_DPTX1_LINK_CLK 31 +#define DISP_CC_MDSS_DPTX1_LINK_CLK_SRC 32 +#define DISP_CC_MDSS_DPTX1_LINK_DIV_CLK_SRC 33 +#define DISP_CC_MDSS_DPTX1_LINK_DPIN_CLK 34 +#define DISP_CC_MDSS_DPTX1_LINK_DPIN_DIV_CLK_SRC 35 +#define DISP_CC_MDSS_DPTX1_LINK_INTF_CLK 36 +#define DISP_CC_MDSS_DPTX1_PIXEL0_CLK 37 +#define DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC 38 +#define DISP_CC_MDSS_DPTX1_PIXEL1_CLK 39 +#define DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC 40 +#define DISP_CC_MDSS_DPTX1_USB_ROUTER_LINK_INTF_CLK 41 +#define DISP_CC_MDSS_DPTX2_AUX_CLK 42 +#define DISP_CC_MDSS_DPTX2_AUX_CLK_SRC 43 +#define DISP_CC_MDSS_DPTX2_LINK_CLK 44 +#define DISP_CC_MDSS_DPTX2_LINK_CLK_SRC 45 +#define DISP_CC_MDSS_DPTX2_LINK_DIV_CLK_SRC 46 +#define DISP_CC_MDSS_DPTX2_LINK_DPIN_CLK 47 +#define DISP_CC_MDSS_DPTX2_LINK_DPIN_DIV_CLK_SRC 48 +#define DISP_CC_MDSS_DPTX2_LINK_INTF_CLK 49 +#define DISP_CC_MDSS_DPTX2_PIXEL0_CLK 50 +#define DISP_CC_MDSS_DPTX2_PIXEL0_CLK_SRC 51 +#define DISP_CC_MDSS_DPTX2_PIXEL1_CLK 52 +#define DISP_CC_MDSS_DPTX2_PIXEL1_CLK_SRC 53 +#define DISP_CC_MDSS_DPTX2_USB_ROUTER_LINK_INTF_CLK 54 +#define DISP_CC_MDSS_DPTX3_AUX_CLK 55 +#define DISP_CC_MDSS_DPTX3_AUX_CLK_SRC 56 +#define DISP_CC_MDSS_DPTX3_LINK_CLK 57 +#define DISP_CC_MDSS_DPTX3_LINK_CLK_SRC 58 +#define DISP_CC_MDSS_DPTX3_LINK_DIV_CLK_SRC 59 +#define DISP_CC_MDSS_DPTX3_LINK_DPIN_CLK 60 +#define DISP_CC_MDSS_DPTX3_LINK_DPIN_DIV_CLK_SRC 61 +#define DISP_CC_MDSS_DPTX3_LINK_INTF_CLK 62 +#define DISP_CC_MDSS_DPTX3_PIXEL0_CLK 63 +#define DISP_CC_MDSS_DPTX3_PIXEL0_CLK_SRC 64 +#define DISP_CC_MDSS_ESC0_CLK 65 +#define DISP_CC_MDSS_ESC0_CLK_SRC 66 +#define DISP_CC_MDSS_ESC1_CLK 67 +#define DISP_CC_MDSS_ESC1_CLK_SRC 68 +#define DISP_CC_MDSS_MDP1_CLK 69 +#define DISP_CC_MDSS_MDP_CLK 70 +#define DISP_CC_MDSS_MDP_CLK_SRC 71 +#define DISP_CC_MDSS_MDP_LUT1_CLK 72 +#define DISP_CC_MDSS_MDP_LUT_CLK 73 +#define DISP_CC_MDSS_NON_GDSC_AHB_CLK 74 +#define DISP_CC_MDSS_PCLK0_CLK 75 +#define DISP_CC_MDSS_PCLK0_CLK_SRC 76 +#define DISP_CC_MDSS_PCLK1_CLK 77 +#define DISP_CC_MDSS_PCLK1_CLK_SRC 78 +#define DISP_CC_MDSS_PCLK2_CLK 79 +#define DISP_CC_MDSS_PCLK2_CLK_SRC 80 +#define DISP_CC_MDSS_RSCC_AHB_CLK 81 +#define DISP_CC_MDSS_RSCC_VSYNC_CLK 82 +#define DISP_CC_MDSS_VSYNC1_CLK 83 +#define DISP_CC_MDSS_VSYNC_CLK 84 +#define DISP_CC_MDSS_VSYNC_CLK_SRC 85 +#define DISP_CC_OSC_CLK 86 +#define DISP_CC_OSC_CLK_SRC 87 +#define DISP_CC_PLL0 88 +#define DISP_CC_PLL1 89 +#define DISP_CC_SLEEP_CLK 90 +#define DISP_CC_SLEEP_CLK_SRC 91 +#define DISP_CC_XO_CLK 92 +#define DISP_CC_XO_CLK_SRC 93 + +/* DISP_CC power domains */ +#define DISP_CC_MDSS_CORE_GDSC 0 +#define DISP_CC_MDSS_CORE_INT2_GDSC 1 + +/* DISP_CC resets */ +#define DISP_CC_MDSS_CORE_BCR 0 +#define DISP_CC_MDSS_CORE_INT2_BCR 1 +#define DISP_CC_MDSS_RSCC_BCR 2 + +#endif From b4d15211c4086a8a6d670cdba9649112fed67f86 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 29 Aug 2025 13:28:04 +0530 Subject: [PATCH 0792/2711] clk: qcom: dispcc-glymur: Add support for Display Clock Controller Add driver for Display clock controller (DISPCC) on Qualcomm Glymur SoC. This would enable the display sw driver to enable/disable/request for the display clocks. Signed-off-by: Taniya Das Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250829-glymur-disp-clock-controllers-v1-2-0ce6fabd837c@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 10 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/dispcc-glymur.c | 1982 ++++++++++++++++++++++++++++++ 3 files changed, 1993 insertions(+) create mode 100644 drivers/clk/qcom/dispcc-glymur.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index aeb6197d7c90..b1cd2fec226a 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -19,6 +19,16 @@ menuconfig COMMON_CLK_QCOM if COMMON_CLK_QCOM +config CLK_GLYMUR_DISPCC + tristate "GLYMUR Display Clock Controller" + depends on ARM64 || COMPILE_TEST + select CLK_GLYMUR_GCC + help + Support for the display clock controllers on Qualcomm + Technologies, Inc. GLYMUR devices. + Say Y if you want to support display devices and functionality such as + splash screen. + config CLK_X1E80100_CAMCC tristate "X1E80100 Camera Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 98de55eb6402..064b4f2064d6 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -21,6 +21,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o +obj-$(CONFIG_CLK_GLYMUR_DISPCC) += dispcc-glymur.o obj-$(CONFIG_CLK_X1E80100_CAMCC) += camcc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_DISPCC) += dispcc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_GCC) += gcc-x1e80100.o diff --git a/drivers/clk/qcom/dispcc-glymur.c b/drivers/clk/qcom/dispcc-glymur.c new file mode 100644 index 000000000000..d755b41cf458 --- /dev/null +++ b/drivers/clk/qcom/dispcc-glymur.c @@ -0,0 +1,1982 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_SLEEP_CLK, + DT_DP0_PHY_PLL_LINK_CLK, + DT_DP0_PHY_PLL_VCO_DIV_CLK, + DT_DP1_PHY_PLL_LINK_CLK, + DT_DP1_PHY_PLL_VCO_DIV_CLK, + DT_DP2_PHY_PLL_LINK_CLK, + DT_DP2_PHY_PLL_VCO_DIV_CLK, + DT_DP3_PHY_PLL_LINK_CLK, + DT_DP3_PHY_PLL_VCO_DIV_CLK, + DT_DSI0_PHY_PLL_OUT_BYTECLK, + DT_DSI0_PHY_PLL_OUT_DSICLK, + DT_DSI1_PHY_PLL_OUT_BYTECLK, + DT_DSI1_PHY_PLL_OUT_DSICLK, + DT_STANDALONE_PHY_PLL0_LINK_CLK, + DT_STANDALONE_PHY_PLL0_VCO_DIV_CLK, + DT_STANDALONE_PHY_PLL1_LINK_CLK, + DT_STANDALONE_PHY_PLL1_VCO_DIV_CLK, +}; + +enum { + P_BI_TCXO, + P_SLEEP_CLK, + P_DISP_CC_PLL0_OUT_MAIN, + P_DISP_CC_PLL1_OUT_EVEN, + P_DISP_CC_PLL1_OUT_MAIN, + P_DP0_PHY_PLL_LINK_CLK, + P_DP0_PHY_PLL_VCO_DIV_CLK, + P_DP1_PHY_PLL_LINK_CLK, + P_DP1_PHY_PLL_VCO_DIV_CLK, + P_DP2_PHY_PLL_LINK_CLK, + P_DP2_PHY_PLL_VCO_DIV_CLK, + P_DP3_PHY_PLL_LINK_CLK, + P_DP3_PHY_PLL_VCO_DIV_CLK, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_STANDALONE_PHY_PLL0_LINK_CLK, + P_STANDALONE_PHY_PLL0_VCO_DIV_CLK, + P_STANDALONE_PHY_PLL1_LINK_CLK, + P_STANDALONE_PHY_PLL1_VCO_DIV_CLK, +}; + +static const struct pll_vco taycan_eko_t_vco[] = { + { 249600000, 2500000000, 0 }, +}; + +/* 257.142858 MHz Configuration */ +static const struct alpha_pll_config disp_cc_pll0_config = { + .l = 0xd, + .alpha = 0x6492, + .config_ctl_val = 0x25c400e7, + .config_ctl_hi_val = 0x0a8060e0, + .config_ctl_hi1_val = 0xf51dea20, + .user_ctl_val = 0x00000008, + .user_ctl_hi_val = 0x00000002, +}; + +static struct clk_alpha_pll disp_cc_pll0 = { + .offset = 0x0, + .config = &disp_cc_pll0_config, + .vco_table = taycan_eko_t_vco, + .num_vco = ARRAY_SIZE(taycan_eko_t_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_taycan_eko_t_ops, + }, + }, +}; + +/* 600.0 MHz Configuration */ +static const struct alpha_pll_config disp_cc_pll1_config = { + .l = 0x1f, + .alpha = 0x4000, + .config_ctl_val = 0x25c400e7, + .config_ctl_hi_val = 0x0a8060e0, + .config_ctl_hi1_val = 0xf51dea20, + .user_ctl_val = 0x00000008, + .user_ctl_hi_val = 0x00000002, +}; + +static struct clk_alpha_pll disp_cc_pll1 = { + .offset = 0x1000, + .config = &disp_cc_pll1_config, + .vco_table = taycan_eko_t_vco, + .num_vco = ARRAY_SIZE(taycan_eko_t_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_pll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_taycan_eko_t_ops, + }, + }, +}; + +static const struct parent_map disp_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_STANDALONE_PHY_PLL0_VCO_DIV_CLK, 1 }, + { P_DP0_PHY_PLL_VCO_DIV_CLK, 2 }, + { P_DP3_PHY_PLL_VCO_DIV_CLK, 3 }, + { P_DP1_PHY_PLL_VCO_DIV_CLK, 4 }, + { P_STANDALONE_PHY_PLL1_VCO_DIV_CLK, 5 }, + { P_DP2_PHY_PLL_VCO_DIV_CLK, 6 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .index = DT_STANDALONE_PHY_PLL0_VCO_DIV_CLK }, + { .index = DT_DP0_PHY_PLL_VCO_DIV_CLK }, + { .index = DT_DP3_PHY_PLL_VCO_DIV_CLK }, + { .index = DT_DP1_PHY_PLL_VCO_DIV_CLK }, + { .index = DT_STANDALONE_PHY_PLL1_VCO_DIV_CLK }, + { .index = DT_DP2_PHY_PLL_VCO_DIV_CLK }, +}; + +static const struct parent_map disp_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map disp_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 3 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DSI0_PHY_PLL_OUT_DSICLK }, + { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK }, + { .index = DT_DSI1_PHY_PLL_OUT_DSICLK }, + { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK }, +}; + +static const struct parent_map disp_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_DP0_PHY_PLL_LINK_CLK, 1 }, + { P_DP1_PHY_PLL_LINK_CLK, 2 }, + { P_DP2_PHY_PLL_LINK_CLK, 3 }, + { P_DP3_PHY_PLL_LINK_CLK, 4 }, + { P_STANDALONE_PHY_PLL1_LINK_CLK, 5 }, + { P_STANDALONE_PHY_PLL0_LINK_CLK, 6 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DP0_PHY_PLL_LINK_CLK }, + { .index = DT_DP1_PHY_PLL_LINK_CLK }, + { .index = DT_DP2_PHY_PLL_LINK_CLK }, + { .index = DT_DP3_PHY_PLL_LINK_CLK }, + { .index = DT_STANDALONE_PHY_PLL1_LINK_CLK }, + { .index = DT_STANDALONE_PHY_PLL0_LINK_CLK }, +}; + +static const struct parent_map disp_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 3 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DSI0_PHY_PLL_OUT_DSICLK }, + { .index = DT_DSI1_PHY_PLL_OUT_DSICLK }, +}; + +static const struct parent_map disp_cc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK }, + { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK }, +}; + +static const struct parent_map disp_cc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_DISP_CC_PLL1_OUT_MAIN, 4 }, + { P_DISP_CC_PLL1_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &disp_cc_pll1.clkr.hw }, + { .hw = &disp_cc_pll1.clkr.hw }, +}; + +static const struct parent_map disp_cc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_DISP_CC_PLL0_OUT_MAIN, 1 }, + { P_DISP_CC_PLL1_OUT_MAIN, 4 }, + { P_DISP_CC_PLL1_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_7[] = { + { .index = DT_BI_TCXO }, + { .hw = &disp_cc_pll0.clkr.hw }, + { .hw = &disp_cc_pll1.clkr.hw }, + { .hw = &disp_cc_pll1.clkr.hw }, +}; + +static const struct parent_map disp_cc_parent_map_8[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_8[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map disp_cc_parent_map_9[] = { + { P_SLEEP_CLK, 0 }, +}; + +static const struct clk_parent_data disp_cc_parent_data_9[] = { + { .index = DT_SLEEP_CLK }, +}; + +static const struct freq_tbl ftbl_disp_cc_esync0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_esync0_clk_src = { + .cmd_rcgr = 0x80c0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_4, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_esync0_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_esync1_clk_src = { + .cmd_rcgr = 0x80d8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_4, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_esync1_clk_src", + .parent_data = disp_cc_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(37500000, P_DISP_CC_PLL1_OUT_MAIN, 16, 0, 0), + F(75000000, P_DISP_CC_PLL1_OUT_MAIN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = { + .cmd_rcgr = 0x8360, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_6, + .freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src, + .hw_clk_ctrl = true, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_ahb_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { + .cmd_rcgr = 0x8180, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte0_clk_src", + .parent_data = disp_cc_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = { + .cmd_rcgr = 0x819c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte1_clk_src", + .parent_data = disp_cc_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = { + .cmd_rcgr = 0x8234, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_aux_clk_src", + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = { + .cmd_rcgr = 0x81e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx0_pixel0_clk_src = { + .cmd_rcgr = 0x8204, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_pixel0_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx0_pixel1_clk_src = { + .cmd_rcgr = 0x821c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_pixel1_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { + .cmd_rcgr = 0x8298, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_aux_clk_src", + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = { + .cmd_rcgr = 0x827c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx1_pixel0_clk_src = { + .cmd_rcgr = 0x824c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_pixel0_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx1_pixel1_clk_src = { + .cmd_rcgr = 0x8264, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_pixel1_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx2_aux_clk_src = { + .cmd_rcgr = 0x82fc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_aux_clk_src", + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = { + .cmd_rcgr = 0x82b0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx2_pixel0_clk_src = { + .cmd_rcgr = 0x82cc, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_pixel0_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx2_pixel1_clk_src = { + .cmd_rcgr = 0x82e4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_pixel1_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx3_aux_clk_src = { + .cmd_rcgr = 0x8348, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_aux_clk_src", + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = { + .cmd_rcgr = 0x832c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dptx3_pixel0_clk_src = { + .cmd_rcgr = 0x8314, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_pixel0_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { + .cmd_rcgr = 0x81b8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_5, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_esc0_clk_src", + .parent_data = disp_cc_parent_data_5, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = { + .cmd_rcgr = 0x81d0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_5, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_esc1_clk_src", + .parent_data = disp_cc_parent_data_5, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(85714286, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(100000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(150000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(156000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(205000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(337000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(417000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(532000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(600000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(660000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(717000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = { + .cmd_rcgr = 0x8150, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_7, + .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src, + .hw_clk_ctrl = true, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_mdp_clk_src", + .parent_data = disp_cc_parent_data_7, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .cmd_rcgr = 0x8108, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .cmd_rcgr = 0x8120, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_pclk2_clk_src = { + .cmd_rcgr = 0x8138, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_pclk2_clk_src", + .parent_data = disp_cc_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .cmd_rcgr = 0x8168, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_vsync_clk_src", + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_osc_clk_src = { + .cmd_rcgr = 0x80f0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_8, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_osc_clk_src", + .parent_data = disp_cc_parent_data_8, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_sleep_clk_src = { + .cmd_rcgr = 0xe064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_9, + .freq_tbl = ftbl_disp_cc_sleep_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_sleep_clk_src", + .parent_data = disp_cc_parent_data_9, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_xo_clk_src = { + .cmd_rcgr = 0xe044, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_esync0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_xo_clk_src", + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + .reg = 0x8198, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { + .reg = 0x81b4, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx0_link_div_clk_src = { + .reg = 0x8200, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx0_link_dpin_div_clk_src = { + .reg = 0x838c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_dpin_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx1_link_div_clk_src = { + .reg = 0x8294, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx1_link_dpin_div_clk_src = { + .reg = 0x8390, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_dpin_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx2_link_div_clk_src = { + .reg = 0x82c8, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx2_link_dpin_div_clk_src = { + .reg = 0x8394, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_dpin_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx3_link_div_clk_src = { + .reg = 0x8344, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_dptx3_link_dpin_div_clk_src = { + .reg = 0x8398, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_dpin_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch disp_cc_esync0_clk = { + .halt_reg = 0x80b8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80b8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_esync0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_esync0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_esync1_clk = { + .halt_reg = 0x80bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80bc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_esync1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_esync1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_accu_shift_clk = { + .halt_reg = 0xe060, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xe060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_accu_shift_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_ahb1_clk = { + .halt_reg = 0xa028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_ahb1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_ahb_clk = { + .halt_reg = 0x80b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte0_clk = { + .halt_reg = 0x8034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte0_intf_clk = { + .halt_reg = 0x8038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte0_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte1_clk = { + .halt_reg = 0x803c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x803c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte1_intf_clk = { + .halt_reg = 0x8040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_byte1_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_byte1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_aux_clk = { + .halt_reg = 0x8064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_link_clk = { + .halt_reg = 0x804c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x804c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_link_dpin_clk = { + .halt_reg = 0x837c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x837c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_dpin_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_dpin_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_link_intf_clk = { + .halt_reg = 0x8054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_pixel0_clk = { + .halt_reg = 0x805c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x805c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_pixel1_clk = { + .halt_reg = 0x8060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_pixel1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx0_usb_router_link_intf_clk = { + .halt_reg = 0x8050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_usb_router_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_aux_clk = { + .halt_reg = 0x8080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_link_clk = { + .halt_reg = 0x8070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_link_dpin_clk = { + .halt_reg = 0x8380, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8380, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_dpin_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_dpin_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_link_intf_clk = { + .halt_reg = 0x8078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_pixel0_clk = { + .halt_reg = 0x8068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_pixel1_clk = { + .halt_reg = 0x806c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x806c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_pixel1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx1_usb_router_link_intf_clk = { + .halt_reg = 0x8074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_usb_router_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_aux_clk = { + .halt_reg = 0x8098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8098, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_link_clk = { + .halt_reg = 0x808c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x808c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_link_dpin_clk = { + .halt_reg = 0x8384, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8384, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_dpin_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_link_dpin_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_link_intf_clk = { + .halt_reg = 0x8090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_pixel0_clk = { + .halt_reg = 0x8084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_pixel1_clk = { + .halt_reg = 0x8088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_pixel1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx2_usb_router_link_intf_clk = { + .halt_reg = 0x8378, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8378, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_usb_router_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx2_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx3_aux_clk = { + .halt_reg = 0x80a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80a8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx3_link_clk = { + .halt_reg = 0x80a0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80a0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx3_link_dpin_clk = { + .halt_reg = 0x8388, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8388, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_dpin_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_link_dpin_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx3_link_intf_clk = { + .halt_reg = 0x80a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dptx3_pixel0_clk = { + .halt_reg = 0x809c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x809c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_dptx3_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_esc0_clk = { + .halt_reg = 0x8044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_esc0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_esc0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_esc1_clk = { + .halt_reg = 0x8048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_esc1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_esc1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp1_clk = { + .halt_reg = 0xa004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_mdp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_clk = { + .halt_reg = 0x8010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_mdp_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_lut1_clk = { + .halt_reg = 0xa014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xa014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_mdp_lut1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_lut_clk = { + .halt_reg = 0x8020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_mdp_lut_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk = { + .halt_reg = 0xc004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xc004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_non_gdsc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_pclk0_clk = { + .halt_reg = 0x8004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_pclk0_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_pclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_pclk1_clk = { + .halt_reg = 0x8008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_pclk1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_pclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_pclk2_clk = { + .halt_reg = 0x800c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x800c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_pclk2_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_pclk2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rscc_ahb_clk = { + .halt_reg = 0xc00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_rscc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rscc_vsync_clk = { + .halt_reg = 0xc008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_rscc_vsync_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_vsync1_clk = { + .halt_reg = 0xa024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_vsync1_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_vsync_clk = { + .halt_reg = 0x8030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_mdss_vsync_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_osc_clk = { + .halt_reg = 0x80b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80b4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "disp_cc_osc_clk", + .parent_hws = (const struct clk_hw*[]) { + &disp_cc_osc_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc disp_cc_mdss_core_gdsc = { + .gdscr = 0x9000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "disp_cc_mdss_core_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = HW_CTRL | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc disp_cc_mdss_core_int2_gdsc = { + .gdscr = 0xb000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "disp_cc_mdss_core_int2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = HW_CTRL | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *disp_cc_glymur_clocks[] = { + [DISP_CC_ESYNC0_CLK] = &disp_cc_esync0_clk.clkr, + [DISP_CC_ESYNC0_CLK_SRC] = &disp_cc_esync0_clk_src.clkr, + [DISP_CC_ESYNC1_CLK] = &disp_cc_esync1_clk.clkr, + [DISP_CC_ESYNC1_CLK_SRC] = &disp_cc_esync1_clk_src.clkr, + [DISP_CC_MDSS_ACCU_SHIFT_CLK] = &disp_cc_mdss_accu_shift_clk.clkr, + [DISP_CC_MDSS_AHB1_CLK] = &disp_cc_mdss_ahb1_clk.clkr, + [DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr, + [DISP_CC_MDSS_AHB_CLK_SRC] = &disp_cc_mdss_ahb_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr, + [DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &disp_cc_mdss_byte0_div_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr, + [DISP_CC_MDSS_BYTE1_CLK] = &disp_cc_mdss_byte1_clk.clkr, + [DISP_CC_MDSS_BYTE1_CLK_SRC] = &disp_cc_mdss_byte1_clk_src.clkr, + [DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] = &disp_cc_mdss_byte1_div_clk_src.clkr, + [DISP_CC_MDSS_BYTE1_INTF_CLK] = &disp_cc_mdss_byte1_intf_clk.clkr, + [DISP_CC_MDSS_DPTX0_AUX_CLK] = &disp_cc_mdss_dptx0_aux_clk.clkr, + [DISP_CC_MDSS_DPTX0_AUX_CLK_SRC] = &disp_cc_mdss_dptx0_aux_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_LINK_CLK] = &disp_cc_mdss_dptx0_link_clk.clkr, + [DISP_CC_MDSS_DPTX0_LINK_CLK_SRC] = &disp_cc_mdss_dptx0_link_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx0_link_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_LINK_DPIN_CLK] = &disp_cc_mdss_dptx0_link_dpin_clk.clkr, + [DISP_CC_MDSS_DPTX0_LINK_DPIN_DIV_CLK_SRC] = &disp_cc_mdss_dptx0_link_dpin_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_LINK_INTF_CLK] = &disp_cc_mdss_dptx0_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX0_PIXEL0_CLK] = &disp_cc_mdss_dptx0_pixel0_clk.clkr, + [DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx0_pixel0_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_PIXEL1_CLK] = &disp_cc_mdss_dptx0_pixel1_clk.clkr, + [DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx0_pixel1_clk_src.clkr, + [DISP_CC_MDSS_DPTX0_USB_ROUTER_LINK_INTF_CLK] = + &disp_cc_mdss_dptx0_usb_router_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX1_AUX_CLK] = &disp_cc_mdss_dptx1_aux_clk.clkr, + [DISP_CC_MDSS_DPTX1_AUX_CLK_SRC] = &disp_cc_mdss_dptx1_aux_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_LINK_CLK] = &disp_cc_mdss_dptx1_link_clk.clkr, + [DISP_CC_MDSS_DPTX1_LINK_CLK_SRC] = &disp_cc_mdss_dptx1_link_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx1_link_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_LINK_DPIN_CLK] = &disp_cc_mdss_dptx1_link_dpin_clk.clkr, + [DISP_CC_MDSS_DPTX1_LINK_DPIN_DIV_CLK_SRC] = &disp_cc_mdss_dptx1_link_dpin_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_LINK_INTF_CLK] = &disp_cc_mdss_dptx1_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX1_PIXEL0_CLK] = &disp_cc_mdss_dptx1_pixel0_clk.clkr, + [DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx1_pixel0_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_PIXEL1_CLK] = &disp_cc_mdss_dptx1_pixel1_clk.clkr, + [DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx1_pixel1_clk_src.clkr, + [DISP_CC_MDSS_DPTX1_USB_ROUTER_LINK_INTF_CLK] = + &disp_cc_mdss_dptx1_usb_router_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX2_AUX_CLK] = &disp_cc_mdss_dptx2_aux_clk.clkr, + [DISP_CC_MDSS_DPTX2_AUX_CLK_SRC] = &disp_cc_mdss_dptx2_aux_clk_src.clkr, + [DISP_CC_MDSS_DPTX2_LINK_CLK] = &disp_cc_mdss_dptx2_link_clk.clkr, + [DISP_CC_MDSS_DPTX2_LINK_CLK_SRC] = &disp_cc_mdss_dptx2_link_clk_src.clkr, + [DISP_CC_MDSS_DPTX2_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx2_link_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX2_LINK_DPIN_CLK] = &disp_cc_mdss_dptx2_link_dpin_clk.clkr, + [DISP_CC_MDSS_DPTX2_LINK_DPIN_DIV_CLK_SRC] = &disp_cc_mdss_dptx2_link_dpin_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX2_LINK_INTF_CLK] = &disp_cc_mdss_dptx2_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX2_PIXEL0_CLK] = &disp_cc_mdss_dptx2_pixel0_clk.clkr, + [DISP_CC_MDSS_DPTX2_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx2_pixel0_clk_src.clkr, + [DISP_CC_MDSS_DPTX2_PIXEL1_CLK] = &disp_cc_mdss_dptx2_pixel1_clk.clkr, + [DISP_CC_MDSS_DPTX2_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx2_pixel1_clk_src.clkr, + [DISP_CC_MDSS_DPTX2_USB_ROUTER_LINK_INTF_CLK] = + &disp_cc_mdss_dptx2_usb_router_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX3_AUX_CLK] = &disp_cc_mdss_dptx3_aux_clk.clkr, + [DISP_CC_MDSS_DPTX3_AUX_CLK_SRC] = &disp_cc_mdss_dptx3_aux_clk_src.clkr, + [DISP_CC_MDSS_DPTX3_LINK_CLK] = &disp_cc_mdss_dptx3_link_clk.clkr, + [DISP_CC_MDSS_DPTX3_LINK_CLK_SRC] = &disp_cc_mdss_dptx3_link_clk_src.clkr, + [DISP_CC_MDSS_DPTX3_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx3_link_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX3_LINK_DPIN_CLK] = &disp_cc_mdss_dptx3_link_dpin_clk.clkr, + [DISP_CC_MDSS_DPTX3_LINK_DPIN_DIV_CLK_SRC] = &disp_cc_mdss_dptx3_link_dpin_div_clk_src.clkr, + [DISP_CC_MDSS_DPTX3_LINK_INTF_CLK] = &disp_cc_mdss_dptx3_link_intf_clk.clkr, + [DISP_CC_MDSS_DPTX3_PIXEL0_CLK] = &disp_cc_mdss_dptx3_pixel0_clk.clkr, + [DISP_CC_MDSS_DPTX3_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx3_pixel0_clk_src.clkr, + [DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr, + [DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr, + [DISP_CC_MDSS_ESC1_CLK] = &disp_cc_mdss_esc1_clk.clkr, + [DISP_CC_MDSS_ESC1_CLK_SRC] = &disp_cc_mdss_esc1_clk_src.clkr, + [DISP_CC_MDSS_MDP1_CLK] = &disp_cc_mdss_mdp1_clk.clkr, + [DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr, + [DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr, + [DISP_CC_MDSS_MDP_LUT1_CLK] = &disp_cc_mdss_mdp_lut1_clk.clkr, + [DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr, + [DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &disp_cc_mdss_non_gdsc_ahb_clk.clkr, + [DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr, + [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr, + [DISP_CC_MDSS_PCLK1_CLK] = &disp_cc_mdss_pclk1_clk.clkr, + [DISP_CC_MDSS_PCLK1_CLK_SRC] = &disp_cc_mdss_pclk1_clk_src.clkr, + [DISP_CC_MDSS_PCLK2_CLK] = &disp_cc_mdss_pclk2_clk.clkr, + [DISP_CC_MDSS_PCLK2_CLK_SRC] = &disp_cc_mdss_pclk2_clk_src.clkr, + [DISP_CC_MDSS_RSCC_AHB_CLK] = &disp_cc_mdss_rscc_ahb_clk.clkr, + [DISP_CC_MDSS_RSCC_VSYNC_CLK] = &disp_cc_mdss_rscc_vsync_clk.clkr, + [DISP_CC_MDSS_VSYNC1_CLK] = &disp_cc_mdss_vsync1_clk.clkr, + [DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr, + [DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr, + [DISP_CC_OSC_CLK] = &disp_cc_osc_clk.clkr, + [DISP_CC_OSC_CLK_SRC] = &disp_cc_osc_clk_src.clkr, + [DISP_CC_PLL0] = &disp_cc_pll0.clkr, + [DISP_CC_PLL1] = &disp_cc_pll1.clkr, + [DISP_CC_SLEEP_CLK_SRC] = &disp_cc_sleep_clk_src.clkr, + [DISP_CC_XO_CLK_SRC] = &disp_cc_xo_clk_src.clkr, +}; + +static struct gdsc *disp_cc_glymur_gdscs[] = { + [DISP_CC_MDSS_CORE_GDSC] = &disp_cc_mdss_core_gdsc, + [DISP_CC_MDSS_CORE_INT2_GDSC] = &disp_cc_mdss_core_int2_gdsc, +}; + +static const struct qcom_reset_map disp_cc_glymur_resets[] = { + [DISP_CC_MDSS_CORE_BCR] = { 0x8000 }, + [DISP_CC_MDSS_CORE_INT2_BCR] = { 0xa000 }, + [DISP_CC_MDSS_RSCC_BCR] = { 0xc000 }, +}; + +static struct clk_alpha_pll *disp_cc_glymur_plls[] = { + &disp_cc_pll0, + &disp_cc_pll1, +}; + +static u32 disp_cc_glymur_critical_cbcrs[] = { + 0xe07c, /* DISP_CC_SLEEP_CLK */ + 0xe05c, /* DISP_CC_XO_CLK */ +}; + +static const struct regmap_config disp_cc_glymur_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x11014, + .fast_io = true, +}; + +static struct qcom_cc_driver_data disp_cc_glymur_driver_data = { + .alpha_plls = disp_cc_glymur_plls, + .num_alpha_plls = ARRAY_SIZE(disp_cc_glymur_plls), + .clk_cbcrs = disp_cc_glymur_critical_cbcrs, + .num_clk_cbcrs = ARRAY_SIZE(disp_cc_glymur_critical_cbcrs), +}; + +static struct qcom_cc_desc disp_cc_glymur_desc = { + .config = &disp_cc_glymur_regmap_config, + .clks = disp_cc_glymur_clocks, + .num_clks = ARRAY_SIZE(disp_cc_glymur_clocks), + .resets = disp_cc_glymur_resets, + .num_resets = ARRAY_SIZE(disp_cc_glymur_resets), + .gdscs = disp_cc_glymur_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_glymur_gdscs), + .use_rpm = true, + .driver_data = &disp_cc_glymur_driver_data, +}; + +static const struct of_device_id disp_cc_glymur_match_table[] = { + { .compatible = "qcom,glymur-dispcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, disp_cc_glymur_match_table); + +static int disp_cc_glymur_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &disp_cc_glymur_desc); +} + +static struct platform_driver disp_cc_glymur_driver = { + .probe = disp_cc_glymur_probe, + .driver = { + .name = "dispcc-glymur", + .of_match_table = disp_cc_glymur_match_table, + }, +}; + +module_platform_driver(disp_cc_glymur_driver); + +MODULE_DESCRIPTION("QTI DISPCC GLYMUR Driver"); +MODULE_LICENSE("GPL"); From f9b007a96a89567372a77cbddd24d5ca4be71523 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 25 Aug 2025 23:49:08 +0530 Subject: [PATCH 0793/2711] dt-bindings: clock: qcom-rpmhcc: Add support for Glymur SoCs Add bindings and update documentation compatible for RPMh clock controller on Glymur SoC. Reviewed-by: Krzysztof Kozlowski Reviewed-by: Bjorn Andersson Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/20250825-glymur-clock-controller-v5-v5-1-01b8c8681bcd@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml index a4414ba0b287..78fa05726685 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml @@ -17,6 +17,7 @@ description: | properties: compatible: enum: + - qcom,glymur-rpmh-clk - qcom,milos-rpmh-clk - qcom,qcs615-rpmh-clk - qcom,qdu1000-rpmh-clk From ae5b84788e5a7876a67f64761b7265529cb5a39a Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 25 Aug 2025 23:49:09 +0530 Subject: [PATCH 0794/2711] dt-bindings: clock: qcom: Document the Glymur SoC TCSR Clock Controller The Glymur SoC TCSR block provides CLKREF clocks for EDP, PCIe and USB. Add this to the TCSR clock controller binding together with identifiers for the clocks. Reviewed-by: Krzysztof Kozlowski Reviewed-by: Bjorn Andersson Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/20250825-glymur-clock-controller-v5-v5-2-01b8c8681bcd@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,sm8550-tcsr.yaml | 3 +++ include/dt-bindings/clock/qcom,glymur-tcsr.h | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 include/dt-bindings/clock/qcom,glymur-tcsr.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml index 2ed7d59722fc..2c992b3437f2 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml @@ -8,12 +8,14 @@ title: Qualcomm TCSR Clock Controller on SM8550 maintainers: - Bjorn Andersson + - Taniya Das description: | Qualcomm TCSR clock control module provides the clocks, resets and power domains on SM8550 See also: + - include/dt-bindings/clock/qcom,glymur-tcsr.h - include/dt-bindings/clock/qcom,sm8550-tcsr.h - include/dt-bindings/clock/qcom,sm8650-tcsr.h - include/dt-bindings/clock/qcom,sm8750-tcsr.h @@ -22,6 +24,7 @@ properties: compatible: items: - enum: + - qcom,glymur-tcsr - qcom,milos-tcsr - qcom,sar2130p-tcsr - qcom,sm8550-tcsr diff --git a/include/dt-bindings/clock/qcom,glymur-tcsr.h b/include/dt-bindings/clock/qcom,glymur-tcsr.h new file mode 100644 index 000000000000..72614226b113 --- /dev/null +++ b/include/dt-bindings/clock/qcom,glymur-tcsr.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_TCSR_CC_GLYMUR_H +#define _DT_BINDINGS_CLK_QCOM_TCSR_CC_GLYMUR_H + +/* TCSR_CC clocks */ +#define TCSR_EDP_CLKREF_EN 0 +#define TCSR_PCIE_1_CLKREF_EN 1 +#define TCSR_PCIE_2_CLKREF_EN 2 +#define TCSR_PCIE_3_CLKREF_EN 3 +#define TCSR_PCIE_4_CLKREF_EN 4 +#define TCSR_USB2_1_CLKREF_EN 5 +#define TCSR_USB2_2_CLKREF_EN 6 +#define TCSR_USB2_3_CLKREF_EN 7 +#define TCSR_USB2_4_CLKREF_EN 8 +#define TCSR_USB3_0_CLKREF_EN 9 +#define TCSR_USB3_1_CLKREF_EN 10 +#define TCSR_USB4_1_CLKREF_EN 11 +#define TCSR_USB4_2_CLKREF_EN 12 + +#endif From 2c1d6ce4f3da622773a7a6be570e4dfbf2cefbb7 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 25 Aug 2025 23:49:10 +0530 Subject: [PATCH 0795/2711] clk: qcom: Add TCSR clock driver for Glymur SoC Add a clock driver for the TCSR clock controller found on Glymur SoC, which provides refclks for PCIE, USB, and UFS subsystems. Reviewed-by: Dmitry Baryshkov Reviewed-by: Abel Vesa Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/20250825-glymur-clock-controller-v5-v5-3-01b8c8681bcd@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 8 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/tcsrcc-glymur.c | 313 +++++++++++++++++++++++++++++++ 3 files changed, 322 insertions(+) create mode 100644 drivers/clk/qcom/tcsrcc-glymur.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index b1cd2fec226a..384749a30a4a 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -29,6 +29,14 @@ config CLK_GLYMUR_DISPCC Say Y if you want to support display devices and functionality such as splash screen. +config CLK_GLYMUR_TCSRCC + tristate "GLYMUR TCSR Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the TCSR clock controller on GLYMUR devices. + Say Y if you want to use peripheral devices such as USB/PCIe/EDP. + config CLK_X1E80100_CAMCC tristate "X1E80100 Camera Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 064b4f2064d6..b0dde56a0dc2 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o obj-$(CONFIG_CLK_GLYMUR_DISPCC) += dispcc-glymur.o +obj-$(CONFIG_CLK_GLYMUR_TCSRCC) += tcsrcc-glymur.o obj-$(CONFIG_CLK_X1E80100_CAMCC) += camcc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_DISPCC) += dispcc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_GCC) += gcc-x1e80100.o diff --git a/drivers/clk/qcom/tcsrcc-glymur.c b/drivers/clk/qcom/tcsrcc-glymur.c new file mode 100644 index 000000000000..c1f8b6d10b7f --- /dev/null +++ b/drivers/clk/qcom/tcsrcc-glymur.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO_PAD, +}; + +static struct clk_branch tcsr_edp_clkref_en = { + .halt_reg = 0x1c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_edp_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_pcie_1_clkref_en = { + .halt_reg = 0x4, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_pcie_1_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_pcie_2_clkref_en = { + .halt_reg = 0x8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_pcie_2_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_pcie_3_clkref_en = { + .halt_reg = 0x10, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x10, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_pcie_3_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_pcie_4_clkref_en = { + .halt_reg = 0x14, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x14, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_pcie_4_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb2_1_clkref_en = { + .halt_reg = 0x28, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x28, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_usb2_1_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb2_2_clkref_en = { + .halt_reg = 0x2c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x2c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_usb2_2_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb2_3_clkref_en = { + .halt_reg = 0x30, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x30, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_usb2_3_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb2_4_clkref_en = { + .halt_reg = 0x44, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x44, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_usb2_4_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb3_0_clkref_en = { + .halt_reg = 0x20, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x20, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_usb3_0_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb3_1_clkref_en = { + .halt_reg = 0x24, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x24, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_usb3_1_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb4_1_clkref_en = { + .halt_reg = 0x0, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_usb4_1_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch tcsr_usb4_2_clkref_en = { + .halt_reg = 0x18, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x18, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "tcsr_usb4_2_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *tcsr_cc_glymur_clocks[] = { + [TCSR_EDP_CLKREF_EN] = &tcsr_edp_clkref_en.clkr, + [TCSR_PCIE_1_CLKREF_EN] = &tcsr_pcie_1_clkref_en.clkr, + [TCSR_PCIE_2_CLKREF_EN] = &tcsr_pcie_2_clkref_en.clkr, + [TCSR_PCIE_3_CLKREF_EN] = &tcsr_pcie_3_clkref_en.clkr, + [TCSR_PCIE_4_CLKREF_EN] = &tcsr_pcie_4_clkref_en.clkr, + [TCSR_USB2_1_CLKREF_EN] = &tcsr_usb2_1_clkref_en.clkr, + [TCSR_USB2_2_CLKREF_EN] = &tcsr_usb2_2_clkref_en.clkr, + [TCSR_USB2_3_CLKREF_EN] = &tcsr_usb2_3_clkref_en.clkr, + [TCSR_USB2_4_CLKREF_EN] = &tcsr_usb2_4_clkref_en.clkr, + [TCSR_USB3_0_CLKREF_EN] = &tcsr_usb3_0_clkref_en.clkr, + [TCSR_USB3_1_CLKREF_EN] = &tcsr_usb3_1_clkref_en.clkr, + [TCSR_USB4_1_CLKREF_EN] = &tcsr_usb4_1_clkref_en.clkr, + [TCSR_USB4_2_CLKREF_EN] = &tcsr_usb4_2_clkref_en.clkr, +}; + +static const struct regmap_config tcsr_cc_glymur_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x44, + .fast_io = true, +}; + +static const struct qcom_cc_desc tcsr_cc_glymur_desc = { + .config = &tcsr_cc_glymur_regmap_config, + .clks = tcsr_cc_glymur_clocks, + .num_clks = ARRAY_SIZE(tcsr_cc_glymur_clocks), +}; + +static const struct of_device_id tcsr_cc_glymur_match_table[] = { + { .compatible = "qcom,glymur-tcsr" }, + { } +}; +MODULE_DEVICE_TABLE(of, tcsr_cc_glymur_match_table); + +static int tcsr_cc_glymur_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &tcsr_cc_glymur_desc); +} + +static struct platform_driver tcsr_cc_glymur_driver = { + .probe = tcsr_cc_glymur_probe, + .driver = { + .name = "tcsrcc-glymur", + .of_match_table = tcsr_cc_glymur_match_table, + }, +}; + +static int __init tcsr_cc_glymur_init(void) +{ + return platform_driver_register(&tcsr_cc_glymur_driver); +} +subsys_initcall(tcsr_cc_glymur_init); + +static void __exit tcsr_cc_glymur_exit(void) +{ + platform_driver_unregister(&tcsr_cc_glymur_driver); +} +module_exit(tcsr_cc_glymur_exit); + +MODULE_DESCRIPTION("QTI TCSRCC GLYMUR Driver"); +MODULE_LICENSE("GPL"); From ebcb9db98bdab8b7490421355e6705e964b99675 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 25 Aug 2025 23:49:11 +0530 Subject: [PATCH 0796/2711] clk: qcom: rpmh: Add support for Glymur rpmh clocks Add RPMH clock support for the Glymur SoC to allow enable/disable of the clocks. Reviewed-by: Dmitry Baryshkov Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/20250825-glymur-clock-controller-v5-v5-4-01b8c8681bcd@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-rpmh.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 5103a464d86d..63c38cb47bc4 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -390,6 +390,11 @@ DEFINE_CLK_RPMH_VRM(clk7, _a4, "clka7", 4); DEFINE_CLK_RPMH_VRM(div_clk1, _div2, "divclka1", 2); +DEFINE_CLK_RPMH_VRM(clk3, _a, "C3A_E0", 1); +DEFINE_CLK_RPMH_VRM(clk4, _a, "C4A_E0", 1); +DEFINE_CLK_RPMH_VRM(clk5, _a, "C5A_E0", 1); +DEFINE_CLK_RPMH_VRM(clk8, _a, "C8A_E0", 1); + DEFINE_CLK_RPMH_BCM(ce, "CE0"); DEFINE_CLK_RPMH_BCM(hwkm, "HK0"); DEFINE_CLK_RPMH_BCM(ipa, "IP0"); @@ -879,6 +884,22 @@ static const struct clk_rpmh_desc clk_rpmh_sm8750 = { .clka_optional = true, }; +static struct clk_hw *glymur_rpmh_clocks[] = { + [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw, + [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw, + [RPMH_RF_CLK3] = &clk_rpmh_clk3_a.hw, + [RPMH_RF_CLK3_A] = &clk_rpmh_clk3_a_ao.hw, + [RPMH_RF_CLK4] = &clk_rpmh_clk4_a.hw, + [RPMH_RF_CLK4_A] = &clk_rpmh_clk4_a_ao.hw, + [RPMH_RF_CLK5] = &clk_rpmh_clk5_a.hw, + [RPMH_RF_CLK5_A] = &clk_rpmh_clk5_a_ao.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_glymur = { + .clks = glymur_rpmh_clocks, + .num_clks = ARRAY_SIZE(glymur_rpmh_clocks), +}; + static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec, void *data) { @@ -968,6 +989,7 @@ static int clk_rpmh_probe(struct platform_device *pdev) } static const struct of_device_id clk_rpmh_match_table[] = { + { .compatible = "qcom,glymur-rpmh-clk", .data = &clk_rpmh_glymur}, { .compatible = "qcom,milos-rpmh-clk", .data = &clk_rpmh_milos}, { .compatible = "qcom,qcs615-rpmh-clk", .data = &clk_rpmh_qcs615}, { .compatible = "qcom,qdu1000-rpmh-clk", .data = &clk_rpmh_qdu1000}, From 2c7a7fe4ec3fc6eddd25b013b6210dbf1f98e5fc Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 25 Aug 2025 23:49:12 +0530 Subject: [PATCH 0797/2711] clk: qcom: clk-alpha-pll: Add support for Taycan EKO_T PLL Add clock operations and register offsets to enable control of the Taycan EKO_T PLL, allowing for proper configuration and management of the PLL. Reviewed-by: Dmitry Baryshkov Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/20250825-glymur-clock-controller-v5-v5-5-01b8c8681bcd@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-alpha-pll.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index ff41aeab0ab9..0903a05b18cc 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -29,6 +29,7 @@ enum { CLK_ALPHA_PLL_TYPE_LUCID_OLE, CLK_ALPHA_PLL_TYPE_PONGO_ELU, CLK_ALPHA_PLL_TYPE_TAYCAN_ELU, + CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T = CLK_ALPHA_PLL_TYPE_TAYCAN_ELU, CLK_ALPHA_PLL_TYPE_RIVIAN_EVO, CLK_ALPHA_PLL_TYPE_DEFAULT_EVO, CLK_ALPHA_PLL_TYPE_BRAMMO_EVO, @@ -192,14 +193,17 @@ extern const struct clk_ops clk_alpha_pll_zonda_ops; extern const struct clk_ops clk_alpha_pll_lucid_evo_ops; #define clk_alpha_pll_taycan_elu_ops clk_alpha_pll_lucid_evo_ops +#define clk_alpha_pll_taycan_eko_t_ops clk_alpha_pll_lucid_evo_ops extern const struct clk_ops clk_alpha_pll_reset_lucid_evo_ops; #define clk_alpha_pll_reset_lucid_ole_ops clk_alpha_pll_reset_lucid_evo_ops extern const struct clk_ops clk_alpha_pll_fixed_lucid_evo_ops; #define clk_alpha_pll_fixed_lucid_ole_ops clk_alpha_pll_fixed_lucid_evo_ops #define clk_alpha_pll_fixed_taycan_elu_ops clk_alpha_pll_fixed_lucid_evo_ops +#define clk_alpha_pll_fixed_taycan_eko_t_ops clk_alpha_pll_fixed_lucid_evo_ops extern const struct clk_ops clk_alpha_pll_postdiv_lucid_evo_ops; #define clk_alpha_pll_postdiv_lucid_ole_ops clk_alpha_pll_postdiv_lucid_evo_ops #define clk_alpha_pll_postdiv_taycan_elu_ops clk_alpha_pll_postdiv_lucid_evo_ops +#define clk_alpha_pll_postdiv_taycan_eko_t_ops clk_alpha_pll_postdiv_lucid_evo_ops extern const struct clk_ops clk_alpha_pll_pongo_elu_ops; extern const struct clk_ops clk_alpha_pll_rivian_evo_ops; @@ -233,6 +237,8 @@ void clk_pongo_elu_pll_configure(struct clk_alpha_pll *pll, struct regmap *regma const struct alpha_pll_config *config); #define clk_taycan_elu_pll_configure(pll, regmap, config) \ clk_lucid_evo_pll_configure(pll, regmap, config) +#define clk_taycan_eko_t_pll_configure(pll, regmap, config) \ + clk_lucid_evo_pll_configure(pll, regmap, config) void clk_rivian_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); From ee2d967030fee156ceb2de80ef63ddeb80d60779 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 25 Aug 2025 23:49:13 +0530 Subject: [PATCH 0798/2711] dt-bindings: clock: qcom: document the Glymur Global Clock Controller Add device tree bindings for global clock controller on Glymur SoC. Signed-off-by: Taniya Das Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250825-glymur-clock-controller-v5-v5-6-01b8c8681bcd@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,glymur-gcc.yaml | 121 ++++ include/dt-bindings/clock/qcom,glymur-gcc.h | 578 ++++++++++++++++++ 2 files changed, 699 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,glymur-gcc.yaml create mode 100644 include/dt-bindings/clock/qcom,glymur-gcc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,glymur-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,glymur-gcc.yaml new file mode 100644 index 000000000000..b05b0e6c4483 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,glymur-gcc.yaml @@ -0,0 +1,121 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,glymur-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on Glymur SoC + +maintainers: + - Taniya Das + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on Glymur SoC. + + See also: include/dt-bindings/clock/qcom,glymur-gcc.h + +properties: + compatible: + const: qcom,glymur-gcc + + clocks: + items: + - description: Board XO source + - description: Board XO_A source + - description: Sleep clock source + - description: USB 0 Phy DP0 GMUX clock source + - description: USB 0 Phy DP1 GMUX clock source + - description: USB 0 Phy PCIE PIPEGMUX clock source + - description: USB 0 Phy PIPEGMUX clock source + - description: USB 0 Phy SYS PCIE PIPEGMUX clock source + - description: USB 1 Phy DP0 GMUX 2 clock source + - description: USB 1 Phy DP1 GMUX 2 clock source + - description: USB 1 Phy PCIE PIPEGMUX clock source + - description: USB 1 Phy PIPEGMUX clock source + - description: USB 1 Phy SYS PCIE PIPEGMUX clock source + - description: USB 2 Phy DP0 GMUX 2 clock source + - description: USB 2 Phy DP1 GMUX 2 clock source + - description: USB 2 Phy PCIE PIPEGMUX clock source + - description: USB 2 Phy PIPEGMUX clock source + - description: USB 2 Phy SYS PCIE PIPEGMUX clock source + - description: PCIe 3a pipe clock + - description: PCIe 3b pipe clock + - description: PCIe 4 pipe clock + - description: PCIe 5 pipe clock + - description: PCIe 6 pipe clock + - description: QUSB4 0 PHY RX 0 clock source + - description: QUSB4 0 PHY RX 1 clock source + - description: QUSB4 1 PHY RX 0 clock source + - description: QUSB4 1 PHY RX 1 clock source + - description: QUSB4 2 PHY RX 0 clock source + - description: QUSB4 2 PHY RX 1 clock source + - description: UFS PHY RX Symbol 0 clock source + - description: UFS PHY RX Symbol 1 clock source + - description: UFS PHY TX Symbol 0 clock source + - description: USB3 PHY 0 pipe clock source + - description: USB3 PHY 1 pipe clock source + - description: USB3 PHY 2 pipe clock source + - description: USB3 UNI PHY pipe 0 clock source + - description: USB3 UNI PHY pipe 1 clock source + - description: USB4 PHY 0 pcie pipe clock source + - description: USB4 PHY 0 Max pipe clock source + - description: USB4 PHY 1 pcie pipe clock source + - description: USB4 PHY 1 Max pipe clock source + - description: USB4 PHY 2 pcie pipe clock source + - description: USB4 PHY 2 Max pipe clock source + +required: + - compatible + - clocks + - '#power-domain-cells' + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,glymur-gcc"; + reg = <0x100000 0x1f9000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>, + <&usb_0_phy_dp0_gmux>, + <&usb_0_phy_dp1_gmux>, + <&usb_0_phy_pcie_pipegmux>, + <&usb_0_phy_pipegmux>, + <&usb_0_phy_sys_pcie_pipegmux>, + <&usb_1_phy_dp0_gmux_2>, + <&usb_1_phy_dp1_gmux_2>, + <&usb_1_phy_pcie_pipegmux>, + <&usb_1_phy_pipegmux>, + <&usb_1_phy_sys_pcie_pipegmux>, + <&usb_2_phy_dp0_gmux 2>, + <&usb_2_phy_dp1_gmux 2>, + <&usb_2_phy_pcie_pipegmux>, + <&usb_2_phy_pipegmux>, + <&usb_2_phy_sys_pcie_pipegmux>, + <&pcie_3a_pipe>, <&pcie_3b_pipe>, + <&pcie_4_pipe>, <&pcie_5_pipe>, + <&pcie_6_pipe>, + <&qusb4_0_phy_rx_0>, <&qusb4_0_phy_rx_1>, + <&qusb4_1_phy_rx_0>, <&qusb4_1_phy_rx_1>, + <&qusb4_2_phy_rx_0>, <&qusb4_2_phy_rx_1>, + <&ufs_phy_rx_symbol_0>, <&ufs_phy_rx_symbol_1>, + <&ufs_phy_tx_symbol_0>, + <&usb3_phy_0_pipe>, <&usb3_phy_1_pipe>, + <&usb3_phy_2_pipe>, + <&usb3_uni_phy_pipe_0>, <&usb3_uni_phy_pipe_1>, + <&usb4_phy_0_pcie_pipe>, <&usb4_phy_0_max_pipe>, + <&usb4_phy_1_pcie_pipe>, <&usb4_phy_1_max_pipe>, + <&usb4_phy_2_pcie_pipe>, <&usb4_phy_2_max_pipe>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + +... diff --git a/include/dt-bindings/clock/qcom,glymur-gcc.h b/include/dt-bindings/clock/qcom,glymur-gcc.h new file mode 100644 index 000000000000..10c12b8c51c3 --- /dev/null +++ b/include/dt-bindings/clock/qcom,glymur-gcc.h @@ -0,0 +1,578 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_GCC_GLYMUR_H +#define _DT_BINDINGS_CLK_QCOM_GCC_GLYMUR_H + +/* GCC clocks */ +#define GCC_GPLL0 0 +#define GCC_GPLL0_OUT_EVEN 1 +#define GCC_GPLL1 2 +#define GCC_GPLL14 3 +#define GCC_GPLL14_OUT_EVEN 4 +#define GCC_GPLL4 5 +#define GCC_GPLL5 6 +#define GCC_GPLL7 7 +#define GCC_GPLL8 8 +#define GCC_GPLL9 9 +#define GCC_AGGRE_NOC_PCIE_3A_WEST_SF_AXI_CLK 10 +#define GCC_AGGRE_NOC_PCIE_3B_WEST_SF_AXI_CLK 11 +#define GCC_AGGRE_NOC_PCIE_4_WEST_SF_AXI_CLK 12 +#define GCC_AGGRE_NOC_PCIE_5_EAST_SF_AXI_CLK 13 +#define GCC_AGGRE_NOC_PCIE_6_WEST_SF_AXI_CLK 14 +#define GCC_AGGRE_UFS_PHY_AXI_CLK 15 +#define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK 16 +#define GCC_AGGRE_USB2_PRIM_AXI_CLK 17 +#define GCC_AGGRE_USB3_MP_AXI_CLK 18 +#define GCC_AGGRE_USB3_PRIM_AXI_CLK 19 +#define GCC_AGGRE_USB3_SEC_AXI_CLK 20 +#define GCC_AGGRE_USB3_TERT_AXI_CLK 21 +#define GCC_AGGRE_USB4_0_AXI_CLK 22 +#define GCC_AGGRE_USB4_1_AXI_CLK 23 +#define GCC_AGGRE_USB4_2_AXI_CLK 24 +#define GCC_AV1E_AHB_CLK 25 +#define GCC_AV1E_AXI_CLK 26 +#define GCC_AV1E_XO_CLK 27 +#define GCC_BOOT_ROM_AHB_CLK 28 +#define GCC_CAMERA_AHB_CLK 29 +#define GCC_CAMERA_HF_AXI_CLK 30 +#define GCC_CAMERA_SF_AXI_CLK 31 +#define GCC_CAMERA_XO_CLK 32 +#define GCC_CFG_NOC_PCIE_ANOC_AHB_CLK 33 +#define GCC_CFG_NOC_PCIE_ANOC_SOUTH_AHB_CLK 34 +#define GCC_CFG_NOC_USB2_PRIM_AXI_CLK 35 +#define GCC_CFG_NOC_USB3_MP_AXI_CLK 36 +#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 37 +#define GCC_CFG_NOC_USB3_SEC_AXI_CLK 38 +#define GCC_CFG_NOC_USB3_TERT_AXI_CLK 39 +#define GCC_CFG_NOC_USB_ANOC_AHB_CLK 40 +#define GCC_CFG_NOC_USB_ANOC_SOUTH_AHB_CLK 41 +#define GCC_DISP_AHB_CLK 42 +#define GCC_DISP_HF_AXI_CLK 43 +#define GCC_EVA_AHB_CLK 44 +#define GCC_EVA_AXI0_CLK 45 +#define GCC_EVA_AXI0C_CLK 46 +#define GCC_EVA_XO_CLK 47 +#define GCC_GP1_CLK 48 +#define GCC_GP1_CLK_SRC 49 +#define GCC_GP2_CLK 50 +#define GCC_GP2_CLK_SRC 51 +#define GCC_GP3_CLK 52 +#define GCC_GP3_CLK_SRC 53 +#define GCC_GPU_CFG_AHB_CLK 54 +#define GCC_GPU_GEMNOC_GFX_CLK 55 +#define GCC_GPU_GPLL0_CLK_SRC 56 +#define GCC_GPU_GPLL0_DIV_CLK_SRC 57 +#define GCC_PCIE_0_AUX_CLK 58 +#define GCC_PCIE_0_AUX_CLK_SRC 59 +#define GCC_PCIE_0_CFG_AHB_CLK 60 +#define GCC_PCIE_0_MSTR_AXI_CLK 61 +#define GCC_PCIE_0_PHY_RCHNG_CLK 62 +#define GCC_PCIE_0_PHY_RCHNG_CLK_SRC 63 +#define GCC_PCIE_0_PIPE_CLK 64 +#define GCC_PCIE_0_SLV_AXI_CLK 65 +#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 66 +#define GCC_PCIE_1_AUX_CLK 67 +#define GCC_PCIE_1_AUX_CLK_SRC 68 +#define GCC_PCIE_1_CFG_AHB_CLK 69 +#define GCC_PCIE_1_MSTR_AXI_CLK 70 +#define GCC_PCIE_1_PHY_RCHNG_CLK 71 +#define GCC_PCIE_1_PHY_RCHNG_CLK_SRC 72 +#define GCC_PCIE_1_PIPE_CLK 73 +#define GCC_PCIE_1_SLV_AXI_CLK 74 +#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 75 +#define GCC_PCIE_2_AUX_CLK 76 +#define GCC_PCIE_2_AUX_CLK_SRC 77 +#define GCC_PCIE_2_CFG_AHB_CLK 78 +#define GCC_PCIE_2_MSTR_AXI_CLK 79 +#define GCC_PCIE_2_PHY_RCHNG_CLK 80 +#define GCC_PCIE_2_PHY_RCHNG_CLK_SRC 81 +#define GCC_PCIE_2_PIPE_CLK 82 +#define GCC_PCIE_2_SLV_AXI_CLK 83 +#define GCC_PCIE_2_SLV_Q2A_AXI_CLK 84 +#define GCC_PCIE_3A_AUX_CLK 85 +#define GCC_PCIE_3A_AUX_CLK_SRC 86 +#define GCC_PCIE_3A_CFG_AHB_CLK 87 +#define GCC_PCIE_3A_MSTR_AXI_CLK 88 +#define GCC_PCIE_3A_PHY_RCHNG_CLK 89 +#define GCC_PCIE_3A_PHY_RCHNG_CLK_SRC 90 +#define GCC_PCIE_3A_PIPE_CLK 91 +#define GCC_PCIE_3A_PIPE_CLK_SRC 92 +#define GCC_PCIE_3A_SLV_AXI_CLK 93 +#define GCC_PCIE_3A_SLV_Q2A_AXI_CLK 94 +#define GCC_PCIE_3B_AUX_CLK 95 +#define GCC_PCIE_3B_AUX_CLK_SRC 96 +#define GCC_PCIE_3B_CFG_AHB_CLK 97 +#define GCC_PCIE_3B_MSTR_AXI_CLK 98 +#define GCC_PCIE_3B_PHY_RCHNG_CLK 99 +#define GCC_PCIE_3B_PHY_RCHNG_CLK_SRC 100 +#define GCC_PCIE_3B_PIPE_CLK 101 +#define GCC_PCIE_3B_PIPE_CLK_SRC 102 +#define GCC_PCIE_3B_PIPE_DIV2_CLK 103 +#define GCC_PCIE_3B_PIPE_DIV_CLK_SRC 104 +#define GCC_PCIE_3B_SLV_AXI_CLK 105 +#define GCC_PCIE_3B_SLV_Q2A_AXI_CLK 106 +#define GCC_PCIE_4_AUX_CLK 107 +#define GCC_PCIE_4_AUX_CLK_SRC 108 +#define GCC_PCIE_4_CFG_AHB_CLK 109 +#define GCC_PCIE_4_MSTR_AXI_CLK 110 +#define GCC_PCIE_4_PHY_RCHNG_CLK 111 +#define GCC_PCIE_4_PHY_RCHNG_CLK_SRC 112 +#define GCC_PCIE_4_PIPE_CLK 113 +#define GCC_PCIE_4_PIPE_CLK_SRC 114 +#define GCC_PCIE_4_PIPE_DIV2_CLK 115 +#define GCC_PCIE_4_PIPE_DIV_CLK_SRC 116 +#define GCC_PCIE_4_SLV_AXI_CLK 117 +#define GCC_PCIE_4_SLV_Q2A_AXI_CLK 118 +#define GCC_PCIE_5_AUX_CLK 119 +#define GCC_PCIE_5_AUX_CLK_SRC 120 +#define GCC_PCIE_5_CFG_AHB_CLK 121 +#define GCC_PCIE_5_MSTR_AXI_CLK 122 +#define GCC_PCIE_5_PHY_RCHNG_CLK 123 +#define GCC_PCIE_5_PHY_RCHNG_CLK_SRC 124 +#define GCC_PCIE_5_PIPE_CLK 125 +#define GCC_PCIE_5_PIPE_CLK_SRC 126 +#define GCC_PCIE_5_PIPE_DIV2_CLK 127 +#define GCC_PCIE_5_PIPE_DIV_CLK_SRC 128 +#define GCC_PCIE_5_SLV_AXI_CLK 129 +#define GCC_PCIE_5_SLV_Q2A_AXI_CLK 130 +#define GCC_PCIE_6_AUX_CLK 131 +#define GCC_PCIE_6_AUX_CLK_SRC 132 +#define GCC_PCIE_6_CFG_AHB_CLK 133 +#define GCC_PCIE_6_MSTR_AXI_CLK 134 +#define GCC_PCIE_6_PHY_RCHNG_CLK 135 +#define GCC_PCIE_6_PHY_RCHNG_CLK_SRC 136 +#define GCC_PCIE_6_PIPE_CLK 137 +#define GCC_PCIE_6_PIPE_CLK_SRC 138 +#define GCC_PCIE_6_PIPE_DIV2_CLK 139 +#define GCC_PCIE_6_PIPE_DIV_CLK_SRC 140 +#define GCC_PCIE_6_SLV_AXI_CLK 141 +#define GCC_PCIE_6_SLV_Q2A_AXI_CLK 142 +#define GCC_PCIE_NOC_PWRCTL_CLK 143 +#define GCC_PCIE_NOC_QOSGEN_EXTREF_CLK 144 +#define GCC_PCIE_NOC_SF_CENTER_CLK 145 +#define GCC_PCIE_NOC_SLAVE_SF_EAST_CLK 146 +#define GCC_PCIE_NOC_SLAVE_SF_WEST_CLK 147 +#define GCC_PCIE_NOC_TSCTR_CLK 148 +#define GCC_PCIE_PHY_3A_AUX_CLK 149 +#define GCC_PCIE_PHY_3A_AUX_CLK_SRC 150 +#define GCC_PCIE_PHY_3B_AUX_CLK 151 +#define GCC_PCIE_PHY_3B_AUX_CLK_SRC 152 +#define GCC_PCIE_PHY_4_AUX_CLK 153 +#define GCC_PCIE_PHY_4_AUX_CLK_SRC 154 +#define GCC_PCIE_PHY_5_AUX_CLK 155 +#define GCC_PCIE_PHY_5_AUX_CLK_SRC 156 +#define GCC_PCIE_PHY_6_AUX_CLK 157 +#define GCC_PCIE_PHY_6_AUX_CLK_SRC 158 +#define GCC_PCIE_RSCC_CFG_AHB_CLK 159 +#define GCC_PCIE_RSCC_XO_CLK 160 +#define GCC_PDM2_CLK 161 +#define GCC_PDM2_CLK_SRC 162 +#define GCC_PDM_AHB_CLK 163 +#define GCC_PDM_XO4_CLK 164 +#define GCC_QMIP_AV1E_AHB_CLK 165 +#define GCC_QMIP_CAMERA_CMD_AHB_CLK 166 +#define GCC_QMIP_CAMERA_NRT_AHB_CLK 167 +#define GCC_QMIP_CAMERA_RT_AHB_CLK 168 +#define GCC_QMIP_GPU_AHB_CLK 169 +#define GCC_QMIP_PCIE_3A_AHB_CLK 170 +#define GCC_QMIP_PCIE_3B_AHB_CLK 171 +#define GCC_QMIP_PCIE_4_AHB_CLK 172 +#define GCC_QMIP_PCIE_5_AHB_CLK 173 +#define GCC_QMIP_PCIE_6_AHB_CLK 174 +#define GCC_QMIP_VIDEO_CV_CPU_AHB_CLK 175 +#define GCC_QMIP_VIDEO_CVP_AHB_CLK 176 +#define GCC_QMIP_VIDEO_V_CPU_AHB_CLK 177 +#define GCC_QMIP_VIDEO_VCODEC1_AHB_CLK 178 +#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 179 +#define GCC_QUPV3_OOB_CORE_2X_CLK 180 +#define GCC_QUPV3_OOB_CORE_CLK 181 +#define GCC_QUPV3_OOB_M_AHB_CLK 182 +#define GCC_QUPV3_OOB_QSPI_S0_CLK 183 +#define GCC_QUPV3_OOB_QSPI_S0_CLK_SRC 184 +#define GCC_QUPV3_OOB_QSPI_S1_CLK 185 +#define GCC_QUPV3_OOB_QSPI_S1_CLK_SRC 186 +#define GCC_QUPV3_OOB_S0_CLK 187 +#define GCC_QUPV3_OOB_S0_CLK_SRC 188 +#define GCC_QUPV3_OOB_S1_CLK 189 +#define GCC_QUPV3_OOB_S1_CLK_SRC 190 +#define GCC_QUPV3_OOB_S_AHB_CLK 191 +#define GCC_QUPV3_OOB_TCXO_CLK 192 +#define GCC_QUPV3_WRAP0_CORE_2X_CLK 193 +#define GCC_QUPV3_WRAP0_CORE_CLK 194 +#define GCC_QUPV3_WRAP0_QSPI_S2_CLK 195 +#define GCC_QUPV3_WRAP0_QSPI_S2_CLK_SRC 196 +#define GCC_QUPV3_WRAP0_QSPI_S3_CLK 197 +#define GCC_QUPV3_WRAP0_QSPI_S3_CLK_SRC 198 +#define GCC_QUPV3_WRAP0_QSPI_S6_CLK 199 +#define GCC_QUPV3_WRAP0_QSPI_S6_CLK_SRC 200 +#define GCC_QUPV3_WRAP0_S0_CLK 201 +#define GCC_QUPV3_WRAP0_S0_CLK_SRC 202 +#define GCC_QUPV3_WRAP0_S1_CLK 203 +#define GCC_QUPV3_WRAP0_S1_CLK_SRC 204 +#define GCC_QUPV3_WRAP0_S2_CLK 205 +#define GCC_QUPV3_WRAP0_S2_CLK_SRC 206 +#define GCC_QUPV3_WRAP0_S3_CLK 207 +#define GCC_QUPV3_WRAP0_S3_CLK_SRC 208 +#define GCC_QUPV3_WRAP0_S4_CLK 209 +#define GCC_QUPV3_WRAP0_S4_CLK_SRC 210 +#define GCC_QUPV3_WRAP0_S5_CLK 211 +#define GCC_QUPV3_WRAP0_S5_CLK_SRC 212 +#define GCC_QUPV3_WRAP0_S6_CLK 213 +#define GCC_QUPV3_WRAP0_S6_CLK_SRC 214 +#define GCC_QUPV3_WRAP0_S7_CLK 215 +#define GCC_QUPV3_WRAP0_S7_CLK_SRC 216 +#define GCC_QUPV3_WRAP1_CORE_2X_CLK 217 +#define GCC_QUPV3_WRAP1_CORE_CLK 218 +#define GCC_QUPV3_WRAP1_QSPI_S2_CLK 219 +#define GCC_QUPV3_WRAP1_QSPI_S2_CLK_SRC 220 +#define GCC_QUPV3_WRAP1_QSPI_S3_CLK 221 +#define GCC_QUPV3_WRAP1_QSPI_S3_CLK_SRC 222 +#define GCC_QUPV3_WRAP1_QSPI_S6_CLK 223 +#define GCC_QUPV3_WRAP1_QSPI_S6_CLK_SRC 224 +#define GCC_QUPV3_WRAP1_S0_CLK 225 +#define GCC_QUPV3_WRAP1_S0_CLK_SRC 226 +#define GCC_QUPV3_WRAP1_S1_CLK 227 +#define GCC_QUPV3_WRAP1_S1_CLK_SRC 228 +#define GCC_QUPV3_WRAP1_S2_CLK 229 +#define GCC_QUPV3_WRAP1_S2_CLK_SRC 230 +#define GCC_QUPV3_WRAP1_S3_CLK 231 +#define GCC_QUPV3_WRAP1_S3_CLK_SRC 232 +#define GCC_QUPV3_WRAP1_S4_CLK 233 +#define GCC_QUPV3_WRAP1_S4_CLK_SRC 234 +#define GCC_QUPV3_WRAP1_S5_CLK 235 +#define GCC_QUPV3_WRAP1_S5_CLK_SRC 236 +#define GCC_QUPV3_WRAP1_S6_CLK 237 +#define GCC_QUPV3_WRAP1_S6_CLK_SRC 238 +#define GCC_QUPV3_WRAP1_S7_CLK 239 +#define GCC_QUPV3_WRAP1_S7_CLK_SRC 240 +#define GCC_QUPV3_WRAP2_CORE_2X_CLK 241 +#define GCC_QUPV3_WRAP2_CORE_CLK 242 +#define GCC_QUPV3_WRAP2_QSPI_S2_CLK 243 +#define GCC_QUPV3_WRAP2_QSPI_S2_CLK_SRC 244 +#define GCC_QUPV3_WRAP2_QSPI_S3_CLK 245 +#define GCC_QUPV3_WRAP2_QSPI_S3_CLK_SRC 246 +#define GCC_QUPV3_WRAP2_QSPI_S6_CLK 247 +#define GCC_QUPV3_WRAP2_QSPI_S6_CLK_SRC 248 +#define GCC_QUPV3_WRAP2_S0_CLK 249 +#define GCC_QUPV3_WRAP2_S0_CLK_SRC 250 +#define GCC_QUPV3_WRAP2_S1_CLK 251 +#define GCC_QUPV3_WRAP2_S1_CLK_SRC 252 +#define GCC_QUPV3_WRAP2_S2_CLK 253 +#define GCC_QUPV3_WRAP2_S2_CLK_SRC 254 +#define GCC_QUPV3_WRAP2_S3_CLK 255 +#define GCC_QUPV3_WRAP2_S3_CLK_SRC 256 +#define GCC_QUPV3_WRAP2_S4_CLK 257 +#define GCC_QUPV3_WRAP2_S4_CLK_SRC 258 +#define GCC_QUPV3_WRAP2_S5_CLK 259 +#define GCC_QUPV3_WRAP2_S5_CLK_SRC 260 +#define GCC_QUPV3_WRAP2_S6_CLK 261 +#define GCC_QUPV3_WRAP2_S6_CLK_SRC 262 +#define GCC_QUPV3_WRAP2_S7_CLK 263 +#define GCC_QUPV3_WRAP2_S7_CLK_SRC 264 +#define GCC_QUPV3_WRAP_0_M_AHB_CLK 265 +#define GCC_QUPV3_WRAP_0_S_AHB_CLK 266 +#define GCC_QUPV3_WRAP_1_M_AHB_CLK 267 +#define GCC_QUPV3_WRAP_1_S_AHB_CLK 268 +#define GCC_QUPV3_WRAP_2_M_AHB_CLK 269 +#define GCC_QUPV3_WRAP_2_S_AHB_CLK 270 +#define GCC_SDCC2_AHB_CLK 271 +#define GCC_SDCC2_APPS_CLK 272 +#define GCC_SDCC2_APPS_CLK_SRC 273 +#define GCC_SDCC4_AHB_CLK 274 +#define GCC_SDCC4_APPS_CLK 275 +#define GCC_SDCC4_APPS_CLK_SRC 276 +#define GCC_UFS_PHY_AHB_CLK 277 +#define GCC_UFS_PHY_AXI_CLK 278 +#define GCC_UFS_PHY_AXI_CLK_SRC 279 +#define GCC_UFS_PHY_AXI_HW_CTL_CLK 280 +#define GCC_UFS_PHY_ICE_CORE_CLK 281 +#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 282 +#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 283 +#define GCC_UFS_PHY_PHY_AUX_CLK 284 +#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 285 +#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 286 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 287 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC 288 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 289 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC 290 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 291 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC 292 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK 293 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 294 +#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 295 +#define GCC_USB20_MASTER_CLK 296 +#define GCC_USB20_MASTER_CLK_SRC 297 +#define GCC_USB20_MOCK_UTMI_CLK 298 +#define GCC_USB20_MOCK_UTMI_CLK_SRC 299 +#define GCC_USB20_MOCK_UTMI_POSTDIV_CLK_SRC 300 +#define GCC_USB20_SLEEP_CLK 301 +#define GCC_USB30_MP_MASTER_CLK 302 +#define GCC_USB30_MP_MASTER_CLK_SRC 303 +#define GCC_USB30_MP_MOCK_UTMI_CLK 304 +#define GCC_USB30_MP_MOCK_UTMI_CLK_SRC 305 +#define GCC_USB30_MP_MOCK_UTMI_POSTDIV_CLK_SRC 306 +#define GCC_USB30_MP_SLEEP_CLK 307 +#define GCC_USB30_PRIM_MASTER_CLK 308 +#define GCC_USB30_PRIM_MASTER_CLK_SRC 309 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK 310 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 311 +#define GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC 312 +#define GCC_USB30_PRIM_SLEEP_CLK 313 +#define GCC_USB30_SEC_MASTER_CLK 314 +#define GCC_USB30_SEC_MASTER_CLK_SRC 315 +#define GCC_USB30_SEC_MOCK_UTMI_CLK 316 +#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 317 +#define GCC_USB30_SEC_MOCK_UTMI_POSTDIV_CLK_SRC 318 +#define GCC_USB30_SEC_SLEEP_CLK 319 +#define GCC_USB30_TERT_MASTER_CLK 320 +#define GCC_USB30_TERT_MASTER_CLK_SRC 321 +#define GCC_USB30_TERT_MOCK_UTMI_CLK 322 +#define GCC_USB30_TERT_MOCK_UTMI_CLK_SRC 323 +#define GCC_USB30_TERT_MOCK_UTMI_POSTDIV_CLK_SRC 324 +#define GCC_USB30_TERT_SLEEP_CLK 325 +#define GCC_USB34_PRIM_PHY_PIPE_CLK_SRC 326 +#define GCC_USB34_SEC_PHY_PIPE_CLK_SRC 327 +#define GCC_USB34_TERT_PHY_PIPE_CLK_SRC 328 +#define GCC_USB3_MP_PHY_AUX_CLK 329 +#define GCC_USB3_MP_PHY_AUX_CLK_SRC 330 +#define GCC_USB3_MP_PHY_COM_AUX_CLK 331 +#define GCC_USB3_MP_PHY_PIPE_0_CLK 332 +#define GCC_USB3_MP_PHY_PIPE_0_CLK_SRC 333 +#define GCC_USB3_MP_PHY_PIPE_1_CLK 334 +#define GCC_USB3_MP_PHY_PIPE_1_CLK_SRC 335 +#define GCC_USB3_PRIM_PHY_AUX_CLK 336 +#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 337 +#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 338 +#define GCC_USB3_PRIM_PHY_PIPE_CLK 339 +#define GCC_USB3_PRIM_PHY_PIPE_CLK_SRC 340 +#define GCC_USB3_SEC_PHY_AUX_CLK 341 +#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 342 +#define GCC_USB3_SEC_PHY_COM_AUX_CLK 343 +#define GCC_USB3_SEC_PHY_PIPE_CLK 344 +#define GCC_USB3_SEC_PHY_PIPE_CLK_SRC 345 +#define GCC_USB3_TERT_PHY_AUX_CLK 346 +#define GCC_USB3_TERT_PHY_AUX_CLK_SRC 347 +#define GCC_USB3_TERT_PHY_COM_AUX_CLK 348 +#define GCC_USB3_TERT_PHY_PIPE_CLK 349 +#define GCC_USB3_TERT_PHY_PIPE_CLK_SRC 350 +#define GCC_USB4_0_CFG_AHB_CLK 351 +#define GCC_USB4_0_DP0_CLK 352 +#define GCC_USB4_0_DP1_CLK 353 +#define GCC_USB4_0_MASTER_CLK 354 +#define GCC_USB4_0_MASTER_CLK_SRC 355 +#define GCC_USB4_0_PHY_DP0_CLK_SRC 356 +#define GCC_USB4_0_PHY_DP0_GMUX_CLK_SRC 357 +#define GCC_USB4_0_PHY_DP1_CLK_SRC 358 +#define GCC_USB4_0_PHY_DP1_GMUX_CLK_SRC 359 +#define GCC_USB4_0_PHY_P2RR2P_PIPE_CLK 360 +#define GCC_USB4_0_PHY_P2RR2P_PIPE_CLK_SRC 361 +#define GCC_USB4_0_PHY_PCIE_PIPE_CLK 362 +#define GCC_USB4_0_PHY_PCIE_PIPE_CLK_SRC 363 +#define GCC_USB4_0_PHY_PCIE_PIPE_MUX_CLK_SRC 364 +#define GCC_USB4_0_PHY_PCIE_PIPEGMUX_CLK_SRC 365 +#define GCC_USB4_0_PHY_PIPEGMUX_CLK_SRC 366 +#define GCC_USB4_0_PHY_RX0_CLK 367 +#define GCC_USB4_0_PHY_RX0_CLK_SRC 368 +#define GCC_USB4_0_PHY_RX1_CLK 369 +#define GCC_USB4_0_PHY_RX1_CLK_SRC 370 +#define GCC_USB4_0_PHY_SYS_CLK_SRC 371 +#define GCC_USB4_0_PHY_SYS_PIPEGMUX_CLK_SRC 372 +#define GCC_USB4_0_PHY_USB_PIPE_CLK 373 +#define GCC_USB4_0_SB_IF_CLK 374 +#define GCC_USB4_0_SB_IF_CLK_SRC 375 +#define GCC_USB4_0_SYS_CLK 376 +#define GCC_USB4_0_TMU_CLK 377 +#define GCC_USB4_0_TMU_CLK_SRC 378 +#define GCC_USB4_0_UC_HRR_CLK 379 +#define GCC_USB4_1_CFG_AHB_CLK 380 +#define GCC_USB4_1_DP0_CLK 381 +#define GCC_USB4_1_DP1_CLK 382 +#define GCC_USB4_1_MASTER_CLK 383 +#define GCC_USB4_1_MASTER_CLK_SRC 384 +#define GCC_USB4_1_PHY_DP0_CLK_SRC 385 +#define GCC_USB4_1_PHY_DP0_GMUX_2_CLK_SRC 386 +#define GCC_USB4_1_PHY_DP1_CLK_SRC 387 +#define GCC_USB4_1_PHY_DP1_GMUX_2_CLK_SRC 388 +#define GCC_USB4_1_PHY_P2RR2P_PIPE_CLK 389 +#define GCC_USB4_1_PHY_P2RR2P_PIPE_CLK_SRC 390 +#define GCC_USB4_1_PHY_PCIE_PIPE_CLK 391 +#define GCC_USB4_1_PHY_PCIE_PIPE_CLK_SRC 392 +#define GCC_USB4_1_PHY_PCIE_PIPE_MUX_CLK_SRC 393 +#define GCC_USB4_1_PHY_PCIE_PIPEGMUX_CLK_SRC 394 +#define GCC_USB4_1_PHY_PIPEGMUX_CLK_SRC 395 +#define GCC_USB4_1_PHY_PLL_PIPE_CLK_SRC 396 +#define GCC_USB4_1_PHY_RX0_CLK 397 +#define GCC_USB4_1_PHY_RX0_CLK_SRC 398 +#define GCC_USB4_1_PHY_RX1_CLK 399 +#define GCC_USB4_1_PHY_RX1_CLK_SRC 400 +#define GCC_USB4_1_PHY_SYS_CLK_SRC 401 +#define GCC_USB4_1_PHY_SYS_PIPEGMUX_CLK_SRC 402 +#define GCC_USB4_1_PHY_USB_PIPE_CLK 403 +#define GCC_USB4_1_SB_IF_CLK 404 +#define GCC_USB4_1_SB_IF_CLK_SRC 405 +#define GCC_USB4_1_SYS_CLK 406 +#define GCC_USB4_1_TMU_CLK 407 +#define GCC_USB4_1_TMU_CLK_SRC 408 +#define GCC_USB4_1_UC_HRR_CLK 409 +#define GCC_USB4_2_CFG_AHB_CLK 410 +#define GCC_USB4_2_DP0_CLK 411 +#define GCC_USB4_2_DP1_CLK 412 +#define GCC_USB4_2_MASTER_CLK 413 +#define GCC_USB4_2_MASTER_CLK_SRC 414 +#define GCC_USB4_2_PHY_DP0_CLK_SRC 415 +#define GCC_USB4_2_PHY_DP0_GMUX_CLK_SRC 416 +#define GCC_USB4_2_PHY_DP1_CLK_SRC 417 +#define GCC_USB4_2_PHY_DP1_GMUX_CLK_SRC 418 +#define GCC_USB4_2_PHY_P2RR2P_PIPE_CLK 419 +#define GCC_USB4_2_PHY_P2RR2P_PIPE_CLK_SRC 420 +#define GCC_USB4_2_PHY_PCIE_PIPE_CLK 421 +#define GCC_USB4_2_PHY_PCIE_PIPE_CLK_SRC 422 +#define GCC_USB4_2_PHY_PCIE_PIPE_MUX_CLK_SRC 423 +#define GCC_USB4_2_PHY_PCIE_PIPEGMUX_CLK_SRC 424 +#define GCC_USB4_2_PHY_PIPEGMUX_CLK_SRC 425 +#define GCC_USB4_2_PHY_RX0_CLK 426 +#define GCC_USB4_2_PHY_RX0_CLK_SRC 427 +#define GCC_USB4_2_PHY_RX1_CLK 428 +#define GCC_USB4_2_PHY_RX1_CLK_SRC 429 +#define GCC_USB4_2_PHY_SYS_CLK_SRC 430 +#define GCC_USB4_2_PHY_SYS_PIPEGMUX_CLK_SRC 431 +#define GCC_USB4_2_PHY_USB_PIPE_CLK 432 +#define GCC_USB4_2_SB_IF_CLK 433 +#define GCC_USB4_2_SB_IF_CLK_SRC 434 +#define GCC_USB4_2_SYS_CLK 435 +#define GCC_USB4_2_TMU_CLK 436 +#define GCC_USB4_2_TMU_CLK_SRC 437 +#define GCC_USB4_2_UC_HRR_CLK 438 +#define GCC_VIDEO_AHB_CLK 439 +#define GCC_VIDEO_AXI0_CLK 440 +#define GCC_VIDEO_AXI0C_CLK 441 +#define GCC_VIDEO_AXI1_CLK 442 +#define GCC_VIDEO_XO_CLK 443 + +/* GCC power domains */ +#define GCC_PCIE_0_TUNNEL_GDSC 0 +#define GCC_PCIE_1_TUNNEL_GDSC 1 +#define GCC_PCIE_2_TUNNEL_GDSC 2 +#define GCC_PCIE_3A_GDSC 3 +#define GCC_PCIE_3A_PHY_GDSC 4 +#define GCC_PCIE_3B_GDSC 5 +#define GCC_PCIE_3B_PHY_GDSC 6 +#define GCC_PCIE_4_GDSC 7 +#define GCC_PCIE_4_PHY_GDSC 8 +#define GCC_PCIE_5_GDSC 9 +#define GCC_PCIE_5_PHY_GDSC 10 +#define GCC_PCIE_6_GDSC 11 +#define GCC_PCIE_6_PHY_GDSC 12 +#define GCC_UFS_PHY_GDSC 13 +#define GCC_USB20_PRIM_GDSC 14 +#define GCC_USB30_MP_GDSC 15 +#define GCC_USB30_PRIM_GDSC 16 +#define GCC_USB30_SEC_GDSC 17 +#define GCC_USB30_TERT_GDSC 18 +#define GCC_USB3_MP_SS0_PHY_GDSC 19 +#define GCC_USB3_MP_SS1_PHY_GDSC 20 +#define GCC_USB4_0_GDSC 21 +#define GCC_USB4_1_GDSC 22 +#define GCC_USB4_2_GDSC 23 +#define GCC_USB_0_PHY_GDSC 24 +#define GCC_USB_1_PHY_GDSC 25 +#define GCC_USB_2_PHY_GDSC 26 + +/* GCC resets */ +#define GCC_AV1E_BCR 0 +#define GCC_CAMERA_BCR 1 +#define GCC_DISPLAY_BCR 2 +#define GCC_EVA_BCR 3 +#define GCC_GPU_BCR 4 +#define GCC_PCIE_0_LINK_DOWN_BCR 5 +#define GCC_PCIE_0_NOCSR_COM_PHY_BCR 6 +#define GCC_PCIE_0_PHY_BCR 7 +#define GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR 8 +#define GCC_PCIE_0_TUNNEL_BCR 9 +#define GCC_PCIE_1_LINK_DOWN_BCR 10 +#define GCC_PCIE_1_NOCSR_COM_PHY_BCR 11 +#define GCC_PCIE_1_PHY_BCR 12 +#define GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR 13 +#define GCC_PCIE_1_TUNNEL_BCR 14 +#define GCC_PCIE_2_LINK_DOWN_BCR 15 +#define GCC_PCIE_2_NOCSR_COM_PHY_BCR 16 +#define GCC_PCIE_2_PHY_BCR 17 +#define GCC_PCIE_2_PHY_NOCSR_COM_PHY_BCR 18 +#define GCC_PCIE_2_TUNNEL_BCR 19 +#define GCC_PCIE_3A_BCR 20 +#define GCC_PCIE_3A_LINK_DOWN_BCR 21 +#define GCC_PCIE_3A_NOCSR_COM_PHY_BCR 22 +#define GCC_PCIE_3A_PHY_BCR 23 +#define GCC_PCIE_3A_PHY_NOCSR_COM_PHY_BCR 24 +#define GCC_PCIE_3B_BCR 25 +#define GCC_PCIE_3B_LINK_DOWN_BCR 26 +#define GCC_PCIE_3B_NOCSR_COM_PHY_BCR 27 +#define GCC_PCIE_3B_PHY_BCR 28 +#define GCC_PCIE_3B_PHY_NOCSR_COM_PHY_BCR 29 +#define GCC_PCIE_4_BCR 30 +#define GCC_PCIE_4_LINK_DOWN_BCR 31 +#define GCC_PCIE_4_NOCSR_COM_PHY_BCR 32 +#define GCC_PCIE_4_PHY_BCR 33 +#define GCC_PCIE_4_PHY_NOCSR_COM_PHY_BCR 34 +#define GCC_PCIE_5_BCR 35 +#define GCC_PCIE_5_LINK_DOWN_BCR 36 +#define GCC_PCIE_5_NOCSR_COM_PHY_BCR 37 +#define GCC_PCIE_5_PHY_BCR 38 +#define GCC_PCIE_5_PHY_NOCSR_COM_PHY_BCR 39 +#define GCC_PCIE_6_BCR 40 +#define GCC_PCIE_6_LINK_DOWN_BCR 41 +#define GCC_PCIE_6_NOCSR_COM_PHY_BCR 42 +#define GCC_PCIE_6_PHY_BCR 43 +#define GCC_PCIE_6_PHY_NOCSR_COM_PHY_BCR 44 +#define GCC_PCIE_NOC_BCR 45 +#define GCC_PCIE_PHY_BCR 46 +#define GCC_PCIE_PHY_CFG_AHB_BCR 47 +#define GCC_PCIE_PHY_COM_BCR 48 +#define GCC_PCIE_RSCC_BCR 49 +#define GCC_PDM_BCR 50 +#define GCC_QUPV3_WRAPPER_0_BCR 51 +#define GCC_QUPV3_WRAPPER_1_BCR 52 +#define GCC_QUPV3_WRAPPER_2_BCR 53 +#define GCC_QUPV3_WRAPPER_OOB_BCR 54 +#define GCC_QUSB2PHY_HS0_MP_BCR 55 +#define GCC_QUSB2PHY_HS1_MP_BCR 56 +#define GCC_QUSB2PHY_PRIM_BCR 57 +#define GCC_QUSB2PHY_SEC_BCR 58 +#define GCC_QUSB2PHY_TERT_BCR 59 +#define GCC_QUSB2PHY_USB20_HS_BCR 60 +#define GCC_SDCC2_BCR 61 +#define GCC_SDCC4_BCR 62 +#define GCC_TCSR_PCIE_BCR 63 +#define GCC_UFS_PHY_BCR 64 +#define GCC_USB20_PRIM_BCR 65 +#define GCC_USB30_MP_BCR 66 +#define GCC_USB30_PRIM_BCR 67 +#define GCC_USB30_SEC_BCR 68 +#define GCC_USB30_TERT_BCR 69 +#define GCC_USB3_MP_SS0_PHY_BCR 70 +#define GCC_USB3_MP_SS1_PHY_BCR 71 +#define GCC_USB3_PHY_PRIM_BCR 72 +#define GCC_USB3_PHY_SEC_BCR 73 +#define GCC_USB3_PHY_TERT_BCR 74 +#define GCC_USB3_UNIPHY_MP0_BCR 75 +#define GCC_USB3_UNIPHY_MP1_BCR 76 +#define GCC_USB3PHY_PHY_PRIM_BCR 77 +#define GCC_USB3PHY_PHY_SEC_BCR 78 +#define GCC_USB3PHY_PHY_TERT_BCR 79 +#define GCC_USB3UNIPHY_PHY_MP0_BCR 80 +#define GCC_USB3UNIPHY_PHY_MP1_BCR 81 +#define GCC_USB4_0_BCR 82 +#define GCC_USB4_0_DP0_PHY_PRIM_BCR 83 +#define GCC_USB4_1_BCR 84 +#define GCC_USB4_2_BCR 85 +#define GCC_USB_0_PHY_BCR 86 +#define GCC_USB_1_PHY_BCR 87 +#define GCC_USB_2_PHY_BCR 88 +#define GCC_VIDEO_AXI0_CLK_ARES 89 +#define GCC_VIDEO_AXI1_CLK_ARES 90 +#define GCC_VIDEO_BCR 91 + +#endif From efe504300a1705b71a69382ade4dbe44bea9d457 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 25 Aug 2025 23:49:14 +0530 Subject: [PATCH 0799/2711] clk: qcom: gcc: Add support for Global Clock Controller Add support for Global clock controller for Glymur SoC which would enable the consumers to enable/disable the required clocks. Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Signed-off-by: Taniya Das Link: https://lore.kernel.org/r/20250825-glymur-clock-controller-v5-v5-7-01b8c8681bcd@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-glymur.c | 8616 +++++++++++++++++++++++++++++++++ 3 files changed, 8626 insertions(+) create mode 100644 drivers/clk/qcom/gcc-glymur.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 384749a30a4a..1dbb254de8be 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -29,6 +29,15 @@ config CLK_GLYMUR_DISPCC Say Y if you want to support display devices and functionality such as splash screen. +config CLK_GLYMUR_GCC + tristate "GLYMUR Global Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the global clock controller on GLYMUR devices. + Say Y if you want to use peripheral devices such as UART, SPI, + I2C, USB, UFS, SDCC, etc. + config CLK_GLYMUR_TCSRCC tristate "GLYMUR TCSR Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index b0dde56a0dc2..8051d481c439 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o obj-$(CONFIG_CLK_GLYMUR_DISPCC) += dispcc-glymur.o +obj-$(CONFIG_CLK_GLYMUR_GCC) += gcc-glymur.o obj-$(CONFIG_CLK_GLYMUR_TCSRCC) += tcsrcc-glymur.o obj-$(CONFIG_CLK_X1E80100_CAMCC) += camcc-x1e80100.o obj-$(CONFIG_CLK_X1E80100_DISPCC) += dispcc-x1e80100.o diff --git a/drivers/clk/qcom/gcc-glymur.c b/drivers/clk/qcom/gcc-glymur.c new file mode 100644 index 000000000000..62059120f972 --- /dev/null +++ b/drivers/clk/qcom/gcc-glymur.c @@ -0,0 +1,8616 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, + DT_GCC_USB4_0_PHY_DP0_GMUX_CLK_SRC, + DT_GCC_USB4_0_PHY_DP1_GMUX_CLK_SRC, + DT_GCC_USB4_0_PHY_PCIE_PIPEGMUX_CLK_SRC, + DT_GCC_USB4_0_PHY_PIPEGMUX_CLK_SRC, + DT_GCC_USB4_0_PHY_SYS_PIPEGMUX_CLK_SRC, + DT_GCC_USB4_1_PHY_DP0_GMUX_2_CLK_SRC, + DT_GCC_USB4_1_PHY_DP1_GMUX_2_CLK_SRC, + DT_GCC_USB4_1_PHY_PCIE_PIPEGMUX_CLK_SRC, + DT_GCC_USB4_1_PHY_PIPEGMUX_CLK_SRC, + DT_GCC_USB4_1_PHY_SYS_PIPEGMUX_CLK_SRC, + DT_GCC_USB4_2_PHY_DP0_GMUX_CLK_SRC, + DT_GCC_USB4_2_PHY_DP1_GMUX_CLK_SRC, + DT_GCC_USB4_2_PHY_PCIE_PIPEGMUX_CLK_SRC, + DT_GCC_USB4_2_PHY_PIPEGMUX_CLK_SRC, + DT_GCC_USB4_2_PHY_SYS_PIPEGMUX_CLK_SRC, + DT_PCIE_3A_PIPE_CLK, + DT_PCIE_3B_PIPE_CLK, + DT_PCIE_4_PIPE_CLK, + DT_PCIE_5_PIPE_CLK, + DT_PCIE_6_PIPE_CLK, + DT_QUSB4PHY_0_GCC_USB4_RX0_CLK, + DT_QUSB4PHY_0_GCC_USB4_RX1_CLK, + DT_QUSB4PHY_1_GCC_USB4_RX0_CLK, + DT_QUSB4PHY_1_GCC_USB4_RX1_CLK, + DT_QUSB4PHY_2_GCC_USB4_RX0_CLK, + DT_QUSB4PHY_2_GCC_USB4_RX1_CLK, + DT_UFS_PHY_RX_SYMBOL_0_CLK, + DT_UFS_PHY_RX_SYMBOL_1_CLK, + DT_UFS_PHY_TX_SYMBOL_0_CLK, + DT_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE_CLK, + DT_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE_CLK, + DT_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE_CLK, + DT_USB3_UNI_PHY_MP_GCC_USB30_PIPE_0_CLK, + DT_USB3_UNI_PHY_MP_GCC_USB30_PIPE_1_CLK, + DT_USB4_0_PHY_GCC_USB4_PCIE_PIPE_CLK, + DT_USB4_0_PHY_GCC_USB4RTR_MAX_PIPE_CLK, + DT_USB4_1_PHY_GCC_USB4_PCIE_PIPE_CLK, + DT_USB4_1_PHY_GCC_USB4RTR_MAX_PIPE_CLK, + DT_USB4_2_PHY_GCC_USB4_PCIE_PIPE_CLK, + DT_USB4_2_PHY_GCC_USB4RTR_MAX_PIPE_CLK, +}; + +enum { + P_BI_TCXO, + P_GCC_GPLL0_OUT_EVEN, + P_GCC_GPLL0_OUT_MAIN, + P_GCC_GPLL14_OUT_EVEN, + P_GCC_GPLL14_OUT_MAIN, + P_GCC_GPLL1_OUT_MAIN, + P_GCC_GPLL4_OUT_MAIN, + P_GCC_GPLL5_OUT_MAIN, + P_GCC_GPLL7_OUT_MAIN, + P_GCC_GPLL8_OUT_MAIN, + P_GCC_GPLL9_OUT_MAIN, + P_GCC_USB3_PRIM_PHY_PIPE_CLK_SRC, + P_GCC_USB3_SEC_PHY_PIPE_CLK_SRC, + P_GCC_USB3_TERT_PHY_PIPE_CLK_SRC, + P_GCC_USB4_0_PHY_DP0_GMUX_CLK_SRC, + P_GCC_USB4_0_PHY_DP1_GMUX_CLK_SRC, + P_GCC_USB4_0_PHY_PCIE_PIPEGMUX_CLK_SRC, + P_GCC_USB4_0_PHY_PIPEGMUX_CLK_SRC, + P_GCC_USB4_0_PHY_SYS_PIPEGMUX_CLK_SRC, + P_GCC_USB4_1_PHY_DP0_GMUX_2_CLK_SRC, + P_GCC_USB4_1_PHY_DP1_GMUX_2_CLK_SRC, + P_GCC_USB4_1_PHY_PCIE_PIPEGMUX_CLK_SRC, + P_GCC_USB4_1_PHY_PIPEGMUX_CLK_SRC, + P_GCC_USB4_1_PHY_PLL_PIPE_CLK_SRC, + P_GCC_USB4_1_PHY_SYS_PIPEGMUX_CLK_SRC, + P_GCC_USB4_2_PHY_DP0_GMUX_CLK_SRC, + P_GCC_USB4_2_PHY_DP1_GMUX_CLK_SRC, + P_GCC_USB4_2_PHY_PCIE_PIPEGMUX_CLK_SRC, + P_GCC_USB4_2_PHY_PIPEGMUX_CLK_SRC, + P_GCC_USB4_2_PHY_SYS_PIPEGMUX_CLK_SRC, + P_PCIE_3A_PIPE_CLK, + P_PCIE_3B_PIPE_CLK, + P_PCIE_4_PIPE_CLK, + P_PCIE_5_PIPE_CLK, + P_PCIE_6_PIPE_CLK, + P_QUSB4PHY_0_GCC_USB4_RX0_CLK, + P_QUSB4PHY_0_GCC_USB4_RX1_CLK, + P_QUSB4PHY_1_GCC_USB4_RX0_CLK, + P_QUSB4PHY_1_GCC_USB4_RX1_CLK, + P_QUSB4PHY_2_GCC_USB4_RX0_CLK, + P_QUSB4PHY_2_GCC_USB4_RX1_CLK, + P_SLEEP_CLK, + P_UFS_PHY_RX_SYMBOL_0_CLK, + P_UFS_PHY_RX_SYMBOL_1_CLK, + P_UFS_PHY_TX_SYMBOL_0_CLK, + P_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE_CLK, + P_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE_CLK, + P_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE_CLK, + P_USB3_UNI_PHY_MP_GCC_USB30_PIPE_0_CLK, + P_USB3_UNI_PHY_MP_GCC_USB30_PIPE_1_CLK, + P_USB4_0_PHY_GCC_USB4_PCIE_PIPE_CLK, + P_USB4_0_PHY_GCC_USB4RTR_MAX_PIPE_CLK, + P_USB4_1_PHY_GCC_USB4_PCIE_PIPE_CLK, + P_USB4_1_PHY_GCC_USB4RTR_MAX_PIPE_CLK, + P_USB4_2_PHY_GCC_USB4_PCIE_PIPE_CLK, + P_USB4_2_PHY_GCC_USB4RTR_MAX_PIPE_CLK, +}; + +static struct clk_alpha_pll gcc_gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x62040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 10, + .post_div_table = post_div_table_gcc_gpll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_taycan_eko_t_ops, + }, +}; + +static struct clk_alpha_pll gcc_gpll1 = { + .offset = 0x1000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x62040, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll14 = { + .offset = 0xe000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x62040, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll14", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gcc_gpll14_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gcc_gpll14_out_even = { + .offset = 0xe000, + .post_div_shift = 10, + .post_div_table = post_div_table_gcc_gpll14_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll14_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll14_out_even", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll14.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_taycan_eko_t_ops, + }, +}; + +static struct clk_alpha_pll gcc_gpll4 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x62040, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll5 = { + .offset = 0x5000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x62040, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll5", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll7 = { + .offset = 0x7000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x62040, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll7", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll8 = { + .offset = 0x8000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x62040, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll8", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll9 = { + .offset = 0x9000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .enable_reg = 0x62040, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll9", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_taycan_eko_t_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src; +static struct clk_regmap_mux gcc_usb3_sec_phy_pipe_clk_src; +static struct clk_regmap_mux gcc_usb3_tert_phy_pipe_clk_src; + +static struct clk_rcg2 gcc_usb4_1_phy_pll_pipe_clk_src; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL1_OUT_MAIN, 4 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll1.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL1_OUT_MAIN, 4 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll1.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data gcc_parent_data_5[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL14_OUT_MAIN, 1 }, + { P_GCC_GPLL14_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_7[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll14.clkr.hw }, + { .hw = &gcc_gpll14_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_8[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll4.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_9[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL8_OUT_MAIN, 2 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_9[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll8.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_10[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_11[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_GCC_GPLL8_OUT_MAIN, 3 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_11[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, + { .hw = &gcc_gpll8.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_17[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL9_OUT_MAIN, 2 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_17[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll9.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_18[] = { + { P_UFS_PHY_RX_SYMBOL_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_18[] = { + { .index = DT_UFS_PHY_RX_SYMBOL_0_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_19[] = { + { P_UFS_PHY_RX_SYMBOL_1_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_19[] = { + { .index = DT_UFS_PHY_RX_SYMBOL_1_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_20[] = { + { P_UFS_PHY_TX_SYMBOL_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_20[] = { + { .index = DT_UFS_PHY_TX_SYMBOL_0_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_21[] = { + { P_GCC_USB3_PRIM_PHY_PIPE_CLK_SRC, 0 }, + { P_USB4_0_PHY_GCC_USB4RTR_MAX_PIPE_CLK, 1 }, + { P_GCC_USB4_0_PHY_PIPEGMUX_CLK_SRC, 3 }, +}; + +static const struct clk_parent_data gcc_parent_data_21[] = { + { .hw = &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw }, + { .index = DT_USB4_0_PHY_GCC_USB4RTR_MAX_PIPE_CLK }, + { .index = DT_GCC_USB4_0_PHY_PIPEGMUX_CLK_SRC }, +}; + +static const struct parent_map gcc_parent_map_22[] = { + { P_GCC_USB3_SEC_PHY_PIPE_CLK_SRC, 0 }, + { P_USB4_1_PHY_GCC_USB4RTR_MAX_PIPE_CLK, 1 }, + { P_GCC_USB4_1_PHY_PLL_PIPE_CLK_SRC, 2 }, + { P_GCC_USB4_1_PHY_PIPEGMUX_CLK_SRC, 3 }, +}; + +static const struct clk_parent_data gcc_parent_data_22[] = { + { .hw = &gcc_usb3_sec_phy_pipe_clk_src.clkr.hw }, + { .index = DT_USB4_1_PHY_GCC_USB4RTR_MAX_PIPE_CLK }, + { .hw = &gcc_usb4_1_phy_pll_pipe_clk_src.clkr.hw }, + { .index = DT_GCC_USB4_1_PHY_PIPEGMUX_CLK_SRC }, +}; + +static const struct parent_map gcc_parent_map_23[] = { + { P_GCC_USB3_TERT_PHY_PIPE_CLK_SRC, 0 }, + { P_USB4_2_PHY_GCC_USB4RTR_MAX_PIPE_CLK, 1 }, + { P_GCC_USB4_2_PHY_PIPEGMUX_CLK_SRC, 3 }, +}; + +static const struct clk_parent_data gcc_parent_data_23[] = { + { .hw = &gcc_usb3_tert_phy_pipe_clk_src.clkr.hw }, + { .index = DT_USB4_2_PHY_GCC_USB4RTR_MAX_PIPE_CLK }, + { .index = DT_GCC_USB4_2_PHY_PIPEGMUX_CLK_SRC }, +}; + +static const struct parent_map gcc_parent_map_24[] = { + { P_USB3_UNI_PHY_MP_GCC_USB30_PIPE_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_24[] = { + { .index = DT_USB3_UNI_PHY_MP_GCC_USB30_PIPE_0_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_25[] = { + { P_USB3_UNI_PHY_MP_GCC_USB30_PIPE_1_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_25[] = { + { .index = DT_USB3_UNI_PHY_MP_GCC_USB30_PIPE_1_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_26[] = { + { P_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_26[] = { + { .index = DT_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_27[] = { + { P_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_27[] = { + { .index = DT_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_28[] = { + { P_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_28[] = { + { .index = DT_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_29[] = { + { P_GCC_USB4_0_PHY_DP0_GMUX_CLK_SRC, 0 }, + { P_USB4_0_PHY_GCC_USB4RTR_MAX_PIPE_CLK, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_29[] = { + { .index = DT_GCC_USB4_0_PHY_DP0_GMUX_CLK_SRC }, + { .index = DT_USB4_0_PHY_GCC_USB4RTR_MAX_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_30[] = { + { P_GCC_USB4_0_PHY_DP1_GMUX_CLK_SRC, 0 }, + { P_USB4_0_PHY_GCC_USB4RTR_MAX_PIPE_CLK, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_30[] = { + { .index = DT_GCC_USB4_0_PHY_DP1_GMUX_CLK_SRC }, + { .index = DT_USB4_0_PHY_GCC_USB4RTR_MAX_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_31[] = { + { P_USB4_0_PHY_GCC_USB4_PCIE_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_31[] = { + { .index = DT_USB4_0_PHY_GCC_USB4_PCIE_PIPE_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_32[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_32[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_33[] = { + { P_GCC_USB4_0_PHY_PCIE_PIPEGMUX_CLK_SRC, 0 }, + { P_USB4_0_PHY_GCC_USB4_PCIE_PIPE_CLK, 1 }, +}; + +static const struct clk_parent_data gcc_parent_data_33[] = { + { .index = DT_GCC_USB4_0_PHY_PCIE_PIPEGMUX_CLK_SRC }, + { .index = DT_USB4_0_PHY_GCC_USB4_PCIE_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_34[] = { + { P_QUSB4PHY_0_GCC_USB4_RX0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_34[] = { + { .index = DT_QUSB4PHY_0_GCC_USB4_RX0_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_35[] = { + { P_QUSB4PHY_0_GCC_USB4_RX1_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_35[] = { + { .index = DT_QUSB4PHY_0_GCC_USB4_RX1_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_36[] = { + { P_GCC_USB4_0_PHY_SYS_PIPEGMUX_CLK_SRC, 0 }, + { P_USB4_0_PHY_GCC_USB4_PCIE_PIPE_CLK, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_36[] = { + { .index = DT_GCC_USB4_0_PHY_SYS_PIPEGMUX_CLK_SRC }, + { .index = DT_USB4_0_PHY_GCC_USB4_PCIE_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_37[] = { + { P_GCC_USB4_1_PHY_DP0_GMUX_2_CLK_SRC, 0 }, + { P_USB4_1_PHY_GCC_USB4RTR_MAX_PIPE_CLK, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_37[] = { + { .index = DT_GCC_USB4_1_PHY_DP0_GMUX_2_CLK_SRC }, + { .index = DT_USB4_1_PHY_GCC_USB4RTR_MAX_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_38[] = { + { P_GCC_USB4_1_PHY_DP1_GMUX_2_CLK_SRC, 0 }, + { P_USB4_1_PHY_GCC_USB4RTR_MAX_PIPE_CLK, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_38[] = { + { .index = DT_GCC_USB4_1_PHY_DP1_GMUX_2_CLK_SRC }, + { .index = DT_USB4_1_PHY_GCC_USB4RTR_MAX_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_39[] = { + { P_USB4_1_PHY_GCC_USB4_PCIE_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_39[] = { + { .index = DT_USB4_1_PHY_GCC_USB4_PCIE_PIPE_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_40[] = { + { P_GCC_USB4_1_PHY_PCIE_PIPEGMUX_CLK_SRC, 0 }, + { P_USB4_1_PHY_GCC_USB4_PCIE_PIPE_CLK, 1 }, +}; + +static const struct clk_parent_data gcc_parent_data_40[] = { + { .index = DT_GCC_USB4_1_PHY_PCIE_PIPEGMUX_CLK_SRC }, + { .index = DT_USB4_1_PHY_GCC_USB4_PCIE_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_41[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL5_OUT_MAIN, 3 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_41[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll5.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_42[] = { + { P_QUSB4PHY_1_GCC_USB4_RX0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_42[] = { + { .index = DT_QUSB4PHY_1_GCC_USB4_RX0_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_43[] = { + { P_QUSB4PHY_1_GCC_USB4_RX1_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_43[] = { + { .index = DT_QUSB4PHY_1_GCC_USB4_RX1_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_44[] = { + { P_GCC_USB4_1_PHY_SYS_PIPEGMUX_CLK_SRC, 0 }, + { P_USB4_1_PHY_GCC_USB4_PCIE_PIPE_CLK, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_44[] = { + { .index = DT_GCC_USB4_1_PHY_SYS_PIPEGMUX_CLK_SRC }, + { .index = DT_USB4_1_PHY_GCC_USB4_PCIE_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_45[] = { + { P_GCC_USB4_2_PHY_DP0_GMUX_CLK_SRC, 0 }, + { P_USB4_2_PHY_GCC_USB4RTR_MAX_PIPE_CLK, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_45[] = { + { .index = DT_GCC_USB4_2_PHY_DP0_GMUX_CLK_SRC }, + { .index = DT_USB4_2_PHY_GCC_USB4RTR_MAX_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_46[] = { + { P_GCC_USB4_2_PHY_DP1_GMUX_CLK_SRC, 0 }, + { P_USB4_2_PHY_GCC_USB4RTR_MAX_PIPE_CLK, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_46[] = { + { .index = DT_GCC_USB4_2_PHY_DP1_GMUX_CLK_SRC }, + { .index = DT_USB4_2_PHY_GCC_USB4RTR_MAX_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_47[] = { + { P_USB4_2_PHY_GCC_USB4_PCIE_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_47[] = { + { .index = DT_USB4_2_PHY_GCC_USB4_PCIE_PIPE_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_48[] = { + { P_GCC_USB4_2_PHY_PCIE_PIPEGMUX_CLK_SRC, 0 }, + { P_USB4_2_PHY_GCC_USB4_PCIE_PIPE_CLK, 1 }, +}; + +static const struct clk_parent_data gcc_parent_data_48[] = { + { .index = DT_GCC_USB4_2_PHY_PCIE_PIPEGMUX_CLK_SRC }, + { .index = DT_USB4_2_PHY_GCC_USB4_PCIE_PIPE_CLK }, +}; + +static const struct parent_map gcc_parent_map_49[] = { + { P_QUSB4PHY_2_GCC_USB4_RX0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_49[] = { + { .index = DT_QUSB4PHY_2_GCC_USB4_RX0_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_50[] = { + { P_QUSB4PHY_2_GCC_USB4_RX1_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_50[] = { + { .index = DT_QUSB4PHY_2_GCC_USB4_RX1_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_51[] = { + { P_GCC_USB4_2_PHY_SYS_PIPEGMUX_CLK_SRC, 0 }, + { P_USB4_2_PHY_GCC_USB4_PCIE_PIPE_CLK, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_51[] = { + { .index = DT_GCC_USB4_2_PHY_SYS_PIPEGMUX_CLK_SRC }, + { .index = DT_USB4_2_PHY_GCC_USB4_PCIE_PIPE_CLK }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_3a_pipe_clk_src = { + .reg = 0xdc088, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3a_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_3A_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_3b_pipe_clk_src = { + .reg = 0x941b4, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_3B_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_4_pipe_clk_src = { + .reg = 0x881a4, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_4_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_5_pipe_clk_src = { + .reg = 0xc309c, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_5_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_6_pipe_clk_src = { + .reg = 0x8a1a4, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_6_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_0_clk_src = { + .reg = 0x7706c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_18, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk_src", + .parent_data = gcc_parent_data_18, + .num_parents = ARRAY_SIZE(gcc_parent_data_18), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_1_clk_src = { + .reg = 0x770f0, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_19, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk_src", + .parent_data = gcc_parent_data_19, + .num_parents = ARRAY_SIZE(gcc_parent_data_19), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_tx_symbol_0_clk_src = { + .reg = 0x7705c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_20, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk_src", + .parent_data = gcc_parent_data_20, + .num_parents = ARRAY_SIZE(gcc_parent_data_20), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb34_prim_phy_pipe_clk_src = { + .reg = 0x2b0b8, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_21, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb34_prim_phy_pipe_clk_src", + .parent_data = gcc_parent_data_21, + .num_parents = ARRAY_SIZE(gcc_parent_data_21), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb34_sec_phy_pipe_clk_src = { + .reg = 0x2d0c4, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_22, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb34_sec_phy_pipe_clk_src", + .parent_data = gcc_parent_data_22, + .num_parents = ARRAY_SIZE(gcc_parent_data_22), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb34_tert_phy_pipe_clk_src = { + .reg = 0xe00bc, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_23, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb34_tert_phy_pipe_clk_src", + .parent_data = gcc_parent_data_23, + .num_parents = ARRAY_SIZE(gcc_parent_data_23), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_mp_phy_pipe_0_clk_src = { + .reg = 0x9a07c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_24, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_pipe_0_clk_src", + .parent_data = gcc_parent_data_24, + .num_parents = ARRAY_SIZE(gcc_parent_data_24), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_mp_phy_pipe_1_clk_src = { + .reg = 0x9a084, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_25, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_pipe_1_clk_src", + .parent_data = gcc_parent_data_25, + .num_parents = ARRAY_SIZE(gcc_parent_data_25), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = { + .reg = 0x3f08c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_26, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk_src", + .parent_data = gcc_parent_data_26, + .num_parents = ARRAY_SIZE(gcc_parent_data_26), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_sec_phy_pipe_clk_src = { + .reg = 0xe207c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_27, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_sec_phy_pipe_clk_src", + .parent_data = gcc_parent_data_27, + .num_parents = ARRAY_SIZE(gcc_parent_data_27), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_tert_phy_pipe_clk_src = { + .reg = 0xe107c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_28, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_pipe_clk_src", + .parent_data = gcc_parent_data_28, + .num_parents = ARRAY_SIZE(gcc_parent_data_28), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_0_phy_dp0_clk_src = { + .reg = 0x2b080, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_29, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_dp0_clk_src", + .parent_data = gcc_parent_data_29, + .num_parents = ARRAY_SIZE(gcc_parent_data_29), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_0_phy_dp1_clk_src = { + .reg = 0x2b134, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_30, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_dp1_clk_src", + .parent_data = gcc_parent_data_30, + .num_parents = ARRAY_SIZE(gcc_parent_data_30), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_0_phy_p2rr2p_pipe_clk_src = { + .reg = 0x2b0f0, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_31, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_p2rr2p_pipe_clk_src", + .parent_data = gcc_parent_data_31, + .num_parents = ARRAY_SIZE(gcc_parent_data_31), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_0_phy_pcie_pipe_mux_clk_src = { + .reg = 0x2b120, + .shift = 0, + .width = 1, + .parent_map = gcc_parent_map_33, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_pcie_pipe_mux_clk_src", + .parent_data = gcc_parent_data_33, + .num_parents = ARRAY_SIZE(gcc_parent_data_33), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_0_phy_rx0_clk_src = { + .reg = 0x2b0c0, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_34, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_rx0_clk_src", + .parent_data = gcc_parent_data_34, + .num_parents = ARRAY_SIZE(gcc_parent_data_34), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_0_phy_rx1_clk_src = { + .reg = 0x2b0d4, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_35, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_rx1_clk_src", + .parent_data = gcc_parent_data_35, + .num_parents = ARRAY_SIZE(gcc_parent_data_35), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_0_phy_sys_clk_src = { + .reg = 0x2b100, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_36, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_sys_clk_src", + .parent_data = gcc_parent_data_36, + .num_parents = ARRAY_SIZE(gcc_parent_data_36), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_1_phy_dp0_clk_src = { + .reg = 0x2d08c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_37, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_dp0_clk_src", + .parent_data = gcc_parent_data_37, + .num_parents = ARRAY_SIZE(gcc_parent_data_37), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_1_phy_dp1_clk_src = { + .reg = 0x2d154, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_38, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_dp1_clk_src", + .parent_data = gcc_parent_data_38, + .num_parents = ARRAY_SIZE(gcc_parent_data_38), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_1_phy_p2rr2p_pipe_clk_src = { + .reg = 0x2d114, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_39, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_p2rr2p_pipe_clk_src", + .parent_data = gcc_parent_data_39, + .num_parents = ARRAY_SIZE(gcc_parent_data_39), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_1_phy_pcie_pipe_mux_clk_src = { + .reg = 0x2d140, + .shift = 0, + .width = 1, + .parent_map = gcc_parent_map_40, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_pcie_pipe_mux_clk_src", + .parent_data = gcc_parent_data_40, + .num_parents = ARRAY_SIZE(gcc_parent_data_40), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_1_phy_rx0_clk_src = { + .reg = 0x2d0e4, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_42, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_rx0_clk_src", + .parent_data = gcc_parent_data_42, + .num_parents = ARRAY_SIZE(gcc_parent_data_42), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_1_phy_rx1_clk_src = { + .reg = 0x2d0f8, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_43, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_rx1_clk_src", + .parent_data = gcc_parent_data_43, + .num_parents = ARRAY_SIZE(gcc_parent_data_43), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_1_phy_sys_clk_src = { + .reg = 0x2d124, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_44, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_sys_clk_src", + .parent_data = gcc_parent_data_44, + .num_parents = ARRAY_SIZE(gcc_parent_data_44), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_2_phy_dp0_clk_src = { + .reg = 0xe0084, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_45, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_dp0_clk_src", + .parent_data = gcc_parent_data_45, + .num_parents = ARRAY_SIZE(gcc_parent_data_45), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_2_phy_dp1_clk_src = { + .reg = 0xe013c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_46, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_dp1_clk_src", + .parent_data = gcc_parent_data_46, + .num_parents = ARRAY_SIZE(gcc_parent_data_46), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_2_phy_p2rr2p_pipe_clk_src = { + .reg = 0xe00f4, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_47, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_p2rr2p_pipe_clk_src", + .parent_data = gcc_parent_data_47, + .num_parents = ARRAY_SIZE(gcc_parent_data_47), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_2_phy_pcie_pipe_mux_clk_src = { + .reg = 0xe0124, + .shift = 0, + .width = 1, + .parent_map = gcc_parent_map_48, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_pcie_pipe_mux_clk_src", + .parent_data = gcc_parent_data_48, + .num_parents = ARRAY_SIZE(gcc_parent_data_48), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_2_phy_rx0_clk_src = { + .reg = 0xe00c4, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_49, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_rx0_clk_src", + .parent_data = gcc_parent_data_49, + .num_parents = ARRAY_SIZE(gcc_parent_data_49), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_2_phy_rx1_clk_src = { + .reg = 0xe00d8, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_50, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_rx1_clk_src", + .parent_data = gcc_parent_data_50, + .num_parents = ARRAY_SIZE(gcc_parent_data_50), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb4_2_phy_sys_clk_src = { + .reg = 0xe0104, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_51, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_sys_clk_src", + .parent_data = gcc_parent_data_51, + .num_parents = ARRAY_SIZE(gcc_parent_data_51), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x64004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x92004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x93004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { + .cmd_rcgr = 0xc8168, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = { + .cmd_rcgr = 0xc803c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { + .cmd_rcgr = 0x2e168, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = { + .cmd_rcgr = 0x2e03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_2_aux_clk_src = { + .cmd_rcgr = 0xc0168, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_2_phy_rchng_clk_src = { + .cmd_rcgr = 0xc003c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_3a_aux_clk_src = { + .cmd_rcgr = 0xdc08c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3a_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_3a_phy_rchng_clk_src = { + .cmd_rcgr = 0xdc070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3a_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_3b_aux_clk_src = { + .cmd_rcgr = 0x941b8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_3b_phy_rchng_clk_src = { + .cmd_rcgr = 0x94088, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_4_aux_clk_src = { + .cmd_rcgr = 0x881a8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_4_phy_rchng_clk_src = { + .cmd_rcgr = 0x88078, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_5_aux_clk_src = { + .cmd_rcgr = 0xc30a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_5_phy_rchng_clk_src = { + .cmd_rcgr = 0xc3084, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_6_aux_clk_src = { + .cmd_rcgr = 0x8a1a8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_6_phy_rchng_clk_src = { + .cmd_rcgr = 0x8a078, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_phy_3a_aux_clk_src = { + .cmd_rcgr = 0x6c01c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_phy_3a_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_phy_3b_aux_clk_src = { + .cmd_rcgr = 0x7501c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_phy_3b_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_phy_4_aux_clk_src = { + .cmd_rcgr = 0xd3018, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_phy_4_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_phy_5_aux_clk_src = { + .cmd_rcgr = 0xd2018, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_phy_5_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_phy_6_aux_clk_src = { + .cmd_rcgr = 0xd4018, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_phy_6_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x33010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_oob_qspi_s0_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_oob_qspi_s0_clk_src_init = { + .name = "gcc_qupv3_oob_qspi_s0_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_oob_qspi_s0_clk_src = { + .cmd_rcgr = 0xe7044, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_oob_qspi_s0_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_oob_qspi_s1_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_oob_qspi_s1_clk_src_init = { + .name = "gcc_qupv3_oob_qspi_s1_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_oob_qspi_s1_clk_src = { + .cmd_rcgr = 0xe7170, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_oob_qspi_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_qspi_s2_clk_src_init = { + .name = "gcc_qupv3_wrap0_qspi_s2_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_qspi_s2_clk_src = { + .cmd_rcgr = 0x287a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_qspi_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_qspi_s3_clk_src_init = { + .name = "gcc_qupv3_wrap0_qspi_s3_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_qspi_s3_clk_src = { + .cmd_rcgr = 0x288d0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_qspi_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_qspi_s6_clk_src_init = { + .name = "gcc_qupv3_wrap0_qspi_s6_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_qspi_s6_clk_src = { + .cmd_rcgr = 0x2866c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_qspi_s6_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = { + .name = "gcc_qupv3_wrap0_s0_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { + .cmd_rcgr = 0x28014, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = { + .name = "gcc_qupv3_wrap0_s1_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { + .cmd_rcgr = 0x28150, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s4_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = { + .name = "gcc_qupv3_wrap0_s4_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { + .cmd_rcgr = 0x282b4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = { + .name = "gcc_qupv3_wrap0_s5_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = { + .cmd_rcgr = 0x283f0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s7_clk_src_init = { + .name = "gcc_qupv3_wrap0_s7_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = { + .cmd_rcgr = 0x28540, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_qspi_s2_clk_src_init = { + .name = "gcc_qupv3_wrap1_qspi_s2_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_qspi_s2_clk_src = { + .cmd_rcgr = 0xb37a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_qspi_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_qspi_s3_clk_src_init = { + .name = "gcc_qupv3_wrap1_qspi_s3_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_qspi_s3_clk_src = { + .cmd_rcgr = 0xb38d0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_qspi_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_qspi_s6_clk_src_init = { + .name = "gcc_qupv3_wrap1_qspi_s6_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_qspi_s6_clk_src = { + .cmd_rcgr = 0xb366c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_qspi_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = { + .name = "gcc_qupv3_wrap1_s0_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0xb3014, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = { + .name = "gcc_qupv3_wrap1_s1_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0xb3150, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = { + .name = "gcc_qupv3_wrap1_s4_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0xb32b4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = { + .name = "gcc_qupv3_wrap1_s5_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { + .cmd_rcgr = 0xb33f0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = { + .name = "gcc_qupv3_wrap1_s7_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { + .cmd_rcgr = 0xb3540, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_qspi_s2_clk_src_init = { + .name = "gcc_qupv3_wrap2_qspi_s2_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_qspi_s2_clk_src = { + .cmd_rcgr = 0xb47a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_qspi_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_qspi_s3_clk_src_init = { + .name = "gcc_qupv3_wrap2_qspi_s3_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_qspi_s3_clk_src = { + .cmd_rcgr = 0xb48d0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_qspi_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_qspi_s6_clk_src_init = { + .name = "gcc_qupv3_wrap2_qspi_s6_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_qspi_s6_clk_src = { + .cmd_rcgr = 0xb466c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_oob_qspi_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_qspi_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = { + .name = "gcc_qupv3_wrap2_s0_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = { + .cmd_rcgr = 0xb4014, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = { + .name = "gcc_qupv3_wrap2_s1_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = { + .cmd_rcgr = 0xb4150, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = { + .name = "gcc_qupv3_wrap2_s4_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = { + .cmd_rcgr = 0xb42b4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s5_clk_src_init = { + .name = "gcc_qupv3_wrap2_s5_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = { + .cmd_rcgr = 0xb43f0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s7_clk_src_init = { + .name = "gcc_qupv3_wrap2_s7_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s7_clk_src = { + .cmd_rcgr = 0xb4540, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s7_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .cmd_rcgr = 0xb001c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_17, + .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_17, + .num_parents = ARRAY_SIZE(gcc_parent_data_17), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_MAIN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .cmd_rcgr = 0xdf01c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { + .cmd_rcgr = 0x77038, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .cmd_rcgr = 0x77090, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .cmd_rcgr = 0x770c4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { + .cmd_rcgr = 0x770a8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb20_master_clk_src[] = { + F(60000000, P_GCC_GPLL14_OUT_MAIN, 10, 0, 0), + F(120000000, P_GCC_GPLL14_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb20_master_clk_src = { + .cmd_rcgr = 0xbc030, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gcc_usb20_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_master_clk_src", + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb20_mock_utmi_clk_src = { + .cmd_rcgr = 0xbc048, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_mock_utmi_clk_src", + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_mp_master_clk_src[] = { + F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0), + F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_mp_master_clk_src = { + .cmd_rcgr = 0x9a03c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_mp_mock_utmi_clk_src = { + .cmd_rcgr = 0x9a054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { + .cmd_rcgr = 0x3f04c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0x3f064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_sec_master_clk_src = { + .cmd_rcgr = 0xe203c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_sec_mock_utmi_clk_src = { + .cmd_rcgr = 0xe2054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_tert_master_clk_src = { + .cmd_rcgr = 0xe103c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_tert_mock_utmi_clk_src = { + .cmd_rcgr = 0xe1054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_mp_phy_aux_clk_src = { + .cmd_rcgr = 0x9a088, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_8, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_aux_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0x3f090, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_8, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_sec_phy_aux_clk_src = { + .cmd_rcgr = 0xe2080, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_8, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_sec_phy_aux_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_tert_phy_aux_clk_src = { + .cmd_rcgr = 0xe1080, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_8, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_aux_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb4_0_master_clk_src[] = { + F(85714286, P_GCC_GPLL0_OUT_EVEN, 3.5, 0, 0), + F(177666750, P_GCC_GPLL8_OUT_MAIN, 4, 0, 0), + F(355333500, P_GCC_GPLL8_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb4_0_master_clk_src = { + .cmd_rcgr = 0x2b02c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_gcc_usb4_0_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_master_clk_src", + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(125000000, P_GCC_GPLL7_OUT_MAIN, 4, 0, 0), + F(250000000, P_GCC_GPLL7_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb4_0_phy_pcie_pipe_clk_src = { + .cmd_rcgr = 0x2b104, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_32, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_pcie_pipe_clk_src", + .parent_data = gcc_parent_data_32, + .num_parents = ARRAY_SIZE(gcc_parent_data_32), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_0_sb_if_clk_src = { + .cmd_rcgr = 0x2b0a0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_sb_if_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_0_tmu_clk_src = { + .cmd_rcgr = 0x2b084, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_10, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_tmu_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_master_clk_src = { + .cmd_rcgr = 0x2d02c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_gcc_usb4_0_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_master_clk_src", + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb4_1_phy_pcie_pipe_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(177666750, P_GCC_GPLL8_OUT_MAIN, 4, 0, 0), + F(355333500, P_GCC_GPLL8_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb4_1_phy_pcie_pipe_clk_src = { + .cmd_rcgr = 0x2d128, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_11, + .freq_tbl = ftbl_gcc_usb4_1_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_pcie_pipe_clk_src", + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb4_1_phy_pll_pipe_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(311000000, P_GCC_GPLL5_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb4_1_phy_pll_pipe_clk_src = { + .cmd_rcgr = 0x2d0c8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_41, + .freq_tbl = ftbl_gcc_usb4_1_phy_pll_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_pll_pipe_clk_src", + .parent_data = gcc_parent_data_41, + .num_parents = ARRAY_SIZE(gcc_parent_data_41), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_sb_if_clk_src = { + .cmd_rcgr = 0x2d0ac, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_sb_if_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_tmu_clk_src = { + .cmd_rcgr = 0x2d090, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_10, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_tmu_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_master_clk_src = { + .cmd_rcgr = 0xe002c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_gcc_usb4_0_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_master_clk_src", + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_phy_pcie_pipe_clk_src = { + .cmd_rcgr = 0xe0108, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_11, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_pcie_pipe_clk_src", + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_sb_if_clk_src = { + .cmd_rcgr = 0xe00a4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_sb_if_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_tmu_clk_src = { + .cmd_rcgr = 0xe0088, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_10, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_tmu_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_no_init_park_ops, + }, +}; + +static struct clk_regmap_div gcc_pcie_3b_pipe_div_clk_src = { + .reg = 0x94070, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3b_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_pcie_4_pipe_div_clk_src = { + .reg = 0x88060, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_pcie_5_pipe_div_clk_src = { + .reg = 0xc306c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_pcie_6_pipe_div_clk_src = { + .reg = 0x8a060, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_oob_s0_clk_src = { + .reg = 0xe7024, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_s0_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_oob_qspi_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_oob_s1_clk_src = { + .reg = 0xe7038, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_s1_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_oob_qspi_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap0_s2_clk_src = { + .reg = 0x2828c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s2_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_qspi_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap0_s3_clk_src = { + .reg = 0x282a0, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s3_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_qspi_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap0_s6_clk_src = { + .reg = 0x2852c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s6_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_qspi_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap1_s2_clk_src = { + .reg = 0xb328c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap1_s3_clk_src = { + .reg = 0xb32a0, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s3_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap1_s6_clk_src = { + .reg = 0xb352c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s6_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap2_s2_clk_src = { + .reg = 0xb428c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s2_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_qspi_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap2_s3_clk_src = { + .reg = 0xb42a0, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s3_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_qspi_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap2_s6_clk_src = { + .reg = 0xb452c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s6_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_qspi_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb20_mock_utmi_postdiv_clk_src = { + .reg = 0xbc174, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_mp_mock_utmi_postdiv_clk_src = { + .reg = 0x9a06c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = { + .reg = 0x3f07c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_sec_mock_utmi_postdiv_clk_src = { + .reg = 0xe206c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_sec_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_tert_mock_utmi_postdiv_clk_src = { + .reg = 0xe106c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_3a_west_sf_axi_clk = { + .halt_reg = 0xdc0bc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_pcie_3a_west_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_3b_west_sf_axi_clk = { + .halt_reg = 0x941ec, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_pcie_3b_west_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_4_west_sf_axi_clk = { + .halt_reg = 0x881d0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_pcie_4_west_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_5_east_sf_axi_clk = { + .halt_reg = 0xc30d0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_pcie_5_east_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_6_west_sf_axi_clk = { + .halt_reg = 0x8a1d0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_pcie_6_west_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { + .halt_reg = 0x77000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb2_prim_axi_clk = { + .halt_reg = 0xbc17c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xbc17c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xbc17c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb2_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_mp_axi_clk = { + .halt_reg = 0x9a004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9a004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9a004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_mp_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { + .halt_reg = 0x3f00c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3f00c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3f00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_sec_axi_clk = { + .halt_reg = 0xe2004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xe2004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe2004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_sec_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_sec_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_tert_axi_clk = { + .halt_reg = 0xe1004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xe1004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe1004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_tert_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb4_0_axi_clk = { + .halt_reg = 0x2b000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb4_0_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb4_1_axi_clk = { + .halt_reg = 0x2d000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb4_1_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb4_2_axi_clk = { + .halt_reg = 0xe0000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xe0000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe0000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb4_2_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_av1e_ahb_clk = { + .halt_reg = 0x9b02c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9b02c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9b02c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_av1e_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_av1e_axi_clk = { + .halt_reg = 0x9b030, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x9b030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9b030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_av1e_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_av1e_xo_clk = { + .halt_reg = 0x9b044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9b044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_av1e_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x34038, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x34038, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_hf_axi_clk = { + .halt_reg = 0x26014, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x26014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_sf_axi_clk = { + .halt_reg = 0x26028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x26028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_ahb_clk = { + .halt_reg = 0x82004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x82004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_south_ahb_clk = { + .halt_reg = 0xba2ec, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba2ec, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_south_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb2_prim_axi_clk = { + .halt_reg = 0xbc178, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xbc178, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xbc178, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb2_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_mp_axi_clk = { + .halt_reg = 0x9a000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9a000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9a000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_mp_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = { + .halt_reg = 0x3f000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3f000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3f000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_sec_axi_clk = { + .halt_reg = 0xe2000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xe2000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe2000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_sec_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_sec_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_tert_axi_clk = { + .halt_reg = 0xe1000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xe1000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe1000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_tert_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb_anoc_ahb_clk = { + .halt_reg = 0x3f004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3f004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb_anoc_south_ahb_clk = { + .halt_reg = 0x3f008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3f008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb_anoc_south_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0x27008, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x27008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_disp_hf_axi_clk", + .ops = &clk_branch2_ops, + .flags = CLK_IS_CRITICAL, + }, + }, +}; + +static struct clk_branch gcc_eva_ahb_clk = { + .halt_reg = 0x9b004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9b004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9b004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_eva_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eva_axi0_clk = { + .halt_reg = 0x9b008, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x9b008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9b008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_eva_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eva_axi0c_clk = { + .halt_reg = 0x9b01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9b01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9b01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_eva_axi0c_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eva_xo_clk = { + .halt_reg = 0x9b024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9b024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_eva_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x64000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x64000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x92000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x92000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x93000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x93000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gemnoc_gfx_clk = { + .halt_reg = 0x71010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gemnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_clk_src = { + .halt_reg = 0x71024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_div_clk_src = { + .halt_reg = 0x7102c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7102c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62038, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0_out_even.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0xc8018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { + .halt_reg = 0xba4a8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba4a8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .halt_reg = 0xba498, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0xba498, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_phy_rchng_clk = { + .halt_reg = 0xc8038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0xc8028, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_phy_pcie_pipe_mux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0xba488, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba488, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = { + .halt_reg = 0xba484, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_aux_clk = { + .halt_reg = 0x2e018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_cfg_ahb_clk = { + .halt_reg = 0xba480, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba480, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_mstr_axi_clk = { + .halt_reg = 0xba470, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0xba470, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_phy_rchng_clk = { + .halt_reg = 0x2e038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_pipe_clk = { + .halt_reg = 0x2e028, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_phy_pcie_pipe_mux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_axi_clk = { + .halt_reg = 0xba460, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba460, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_q2a_axi_clk = { + .halt_reg = 0xba45c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_aux_clk = { + .halt_reg = 0xc0018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_2_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_cfg_ahb_clk = { + .halt_reg = 0xba4d0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba4d0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_mstr_axi_clk = { + .halt_reg = 0xba4c0, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0xba4c0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_phy_rchng_clk = { + .halt_reg = 0xc0038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_2_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_pipe_clk = { + .halt_reg = 0xc0028, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_phy_pcie_pipe_mux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_slv_axi_clk = { + .halt_reg = 0xba4b0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba4b0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_slv_q2a_axi_clk = { + .halt_reg = 0xba4ac, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3a_aux_clk = { + .halt_reg = 0xdc04c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xdc04c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3a_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3a_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3a_cfg_ahb_clk = { + .halt_reg = 0xba4f0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba4f0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3a_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3a_mstr_axi_clk = { + .halt_reg = 0xdc038, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0xdc038, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3a_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3a_phy_rchng_clk = { + .halt_reg = 0xdc06c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xdc06c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3a_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3a_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3a_pipe_clk = { + .halt_reg = 0xdc05c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0xdc05c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3a_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3a_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3a_slv_axi_clk = { + .halt_reg = 0xdc024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xdc024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3a_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3a_slv_q2a_axi_clk = { + .halt_reg = 0xdc01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xdc01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3a_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3b_aux_clk = { + .halt_reg = 0x94050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3b_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3b_cfg_ahb_clk = { + .halt_reg = 0xba4f4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba4f4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3b_mstr_axi_clk = { + .halt_reg = 0x94038, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x94038, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3b_phy_rchng_clk = { + .halt_reg = 0x94084, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3b_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3b_pipe_clk = { + .halt_reg = 0x94060, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3b_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3b_pipe_div2_clk = { + .halt_reg = 0x94074, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_pipe_div2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3b_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3b_slv_axi_clk = { + .halt_reg = 0x94024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x94024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3b_slv_q2a_axi_clk = { + .halt_reg = 0x9401c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3b_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_aux_clk = { + .halt_reg = 0x88040, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_cfg_ahb_clk = { + .halt_reg = 0xba4fc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba4fc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_mstr_axi_clk = { + .halt_reg = 0x88030, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x88030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_phy_rchng_clk = { + .halt_reg = 0x88074, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_pipe_clk = { + .halt_reg = 0x88050, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_pipe_div2_clk = { + .halt_reg = 0x88064, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_pipe_div2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_slv_axi_clk = { + .halt_reg = 0x88020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x88020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_slv_q2a_axi_clk = { + .halt_reg = 0x8801c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_aux_clk = { + .halt_reg = 0xc304c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_cfg_ahb_clk = { + .halt_reg = 0xba4f8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba4f8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_mstr_axi_clk = { + .halt_reg = 0xc3038, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0xc3038, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_phy_rchng_clk = { + .halt_reg = 0xc3080, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_pipe_clk = { + .halt_reg = 0xc305c, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_pipe_div2_clk = { + .halt_reg = 0xc3070, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_pipe_div2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_slv_axi_clk = { + .halt_reg = 0xc3024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc3024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_slv_q2a_axi_clk = { + .halt_reg = 0xc301c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6_aux_clk = { + .halt_reg = 0x8a040, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6_cfg_ahb_clk = { + .halt_reg = 0xba500, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba500, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6_mstr_axi_clk = { + .halt_reg = 0x8a030, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x8a030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6_phy_rchng_clk = { + .halt_reg = 0x8a074, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6_pipe_clk = { + .halt_reg = 0x8a050, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6_pipe_div2_clk = { + .halt_reg = 0x8a064, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_pipe_div2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6_slv_axi_clk = { + .halt_reg = 0x8a020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8a020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6_slv_q2a_axi_clk = { + .halt_reg = 0x8a01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_noc_pwrctl_clk = { + .halt_reg = 0xba2ac, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_noc_pwrctl_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_noc_qosgen_extref_clk = { + .halt_reg = 0xba2a8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_noc_qosgen_extref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_noc_sf_center_clk = { + .halt_reg = 0xba2b0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba2b0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_noc_sf_center_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_noc_slave_sf_east_clk = { + .halt_reg = 0xba2b8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba2b8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_noc_slave_sf_east_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_noc_slave_sf_west_clk = { + .halt_reg = 0xba2c0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba2c0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_noc_slave_sf_west_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_noc_tsctr_clk = { + .halt_reg = 0xba2a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba2a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_noc_tsctr_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_phy_3a_aux_clk = { + .halt_reg = 0x6c038, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6c038, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_phy_3a_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_phy_3a_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_phy_3b_aux_clk = { + .halt_reg = 0x75034, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_phy_3b_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_phy_3b_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_phy_4_aux_clk = { + .halt_reg = 0xd3030, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_phy_4_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_phy_4_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_phy_5_aux_clk = { + .halt_reg = 0xd2030, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_phy_5_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_phy_5_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_phy_6_aux_clk = { + .halt_reg = 0xd4030, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_phy_6_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_phy_6_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_rscc_cfg_ahb_clk = { + .halt_reg = 0xb8004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xb8004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62038, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_rscc_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_rscc_xo_clk = { + .halt_reg = 0xb8008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62038, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_rscc_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x3300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3300c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pdm2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x33004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x33004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x33004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x33008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_av1e_ahb_clk = { + .halt_reg = 0x9b048, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9b048, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9b048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_av1e_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_cmd_ahb_clk = { + .halt_reg = 0x26010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x26010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_cmd_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = { + .halt_reg = 0x26008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x26008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_nrt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_rt_ahb_clk = { + .halt_reg = 0x2600c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2600c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2600c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_rt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_gpu_ahb_clk = { + .halt_reg = 0x71008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_gpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_pcie_3a_ahb_clk = { + .halt_reg = 0xdc018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xdc018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_pcie_3a_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_pcie_3b_ahb_clk = { + .halt_reg = 0x94018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x94018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62028, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_pcie_3b_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_pcie_4_ahb_clk = { + .halt_reg = 0x88018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x88018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_pcie_4_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_pcie_5_ahb_clk = { + .halt_reg = 0xc3018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc3018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_pcie_5_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_pcie_6_ahb_clk = { + .halt_reg = 0x8a018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8a018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62030, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_pcie_6_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cv_cpu_ahb_clk = { + .halt_reg = 0x32018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cv_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cvp_ahb_clk = { + .halt_reg = 0x32008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cvp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_v_cpu_ahb_clk = { + .halt_reg = 0x32014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_v_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec1_ahb_clk = { + .halt_reg = 0x32010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_vcodec1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = { + .halt_reg = 0x3200c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3200c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3200c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_vcodec_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_oob_core_2x_clk = { + .halt_reg = 0xc5040, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_oob_core_clk = { + .halt_reg = 0xc502c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_oob_m_ahb_clk = { + .halt_reg = 0xe7004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xe7004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe7004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_oob_qspi_s0_clk = { + .halt_reg = 0xe7040, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_qspi_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_oob_qspi_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_oob_qspi_s1_clk = { + .halt_reg = 0xe729c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_qspi_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_oob_qspi_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_oob_s0_clk = { + .halt_reg = 0xe7014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_oob_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_oob_s1_clk = { + .halt_reg = 0xe7028, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_oob_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_oob_s_ahb_clk = { + .halt_reg = 0xc5028, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc5028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_oob_tcxo_clk = { + .halt_reg = 0xe703c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_oob_tcxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = { + .halt_reg = 0xc5448, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_clk = { + .halt_reg = 0xc5434, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_qspi_s2_clk = { + .halt_reg = 0x2879c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_qspi_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_qspi_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_qspi_s3_clk = { + .halt_reg = 0x288cc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_qspi_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_qspi_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_qspi_s6_clk = { + .halt_reg = 0x28798, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_qspi_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_qspi_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s0_clk = { + .halt_reg = 0x28004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s1_clk = { + .halt_reg = 0x28140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s2_clk = { + .halt_reg = 0x2827c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s3_clk = { + .halt_reg = 0x28290, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s4_clk = { + .halt_reg = 0x282a4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s5_clk = { + .halt_reg = 0x283e0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s6_clk = { + .halt_reg = 0x2851c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s7_clk = { + .halt_reg = 0x28530, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = { + .halt_reg = 0xc5198, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_clk = { + .halt_reg = 0xc5184, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_qspi_s2_clk = { + .halt_reg = 0xb379c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_qspi_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_qspi_s3_clk = { + .halt_reg = 0xb38cc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_qspi_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_qspi_s6_clk = { + .halt_reg = 0xb3798, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_qspi_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s0_clk = { + .halt_reg = 0xb3004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s1_clk = { + .halt_reg = 0xb3140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s2_clk = { + .halt_reg = 0xb327c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s3_clk = { + .halt_reg = 0xb3290, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s4_clk = { + .halt_reg = 0xb32a4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s5_clk = { + .halt_reg = 0xb33e0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s6_clk = { + .halt_reg = 0xb351c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s7_clk = { + .halt_reg = 0xb3530, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_core_2x_clk = { + .halt_reg = 0xc52f0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_core_clk = { + .halt_reg = 0xc52dc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_qspi_s2_clk = { + .halt_reg = 0xb479c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_qspi_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_qspi_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_qspi_s3_clk = { + .halt_reg = 0xb48cc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_qspi_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_qspi_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_qspi_s6_clk = { + .halt_reg = 0xb4798, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_qspi_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_qspi_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s0_clk = { + .halt_reg = 0xb4004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s1_clk = { + .halt_reg = 0xb4140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s2_clk = { + .halt_reg = 0xb427c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s3_clk = { + .halt_reg = 0xb4290, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s4_clk = { + .halt_reg = 0xb42a4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s5_clk = { + .halt_reg = 0xb43e0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s6_clk = { + .halt_reg = 0xb451c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s7_clk = { + .halt_reg = 0xb4530, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = { + .halt_reg = 0xc542c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc542c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_0_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = { + .halt_reg = 0xc5430, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc5430, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62020, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_0_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = { + .halt_reg = 0xc517c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc517c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = { + .halt_reg = 0xc5180, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc5180, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_m_ahb_clk = { + .halt_reg = 0xc52d4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc52d4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_s_ahb_clk = { + .halt_reg = 0xc52d8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc52d8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0xb0014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0xb0004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_ahb_clk = { + .halt_reg = 0xdf014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xdf014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_apps_clk = { + .halt_reg = 0xdf004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xdf004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc4_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ahb_clk = { + .halt_reg = 0xba504, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba504, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xba504, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_axi_clk = { + .halt_reg = 0x7701c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7701c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7701c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ice_core_clk = { + .halt_reg = 0x77080, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77080, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_phy_aux_clk = { + .halt_reg = 0x770c0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770c0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { + .halt_reg = 0x77034, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x77034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { + .halt_reg = 0x770dc, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x770dc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { + .halt_reg = 0x77030, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x77030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_clk = { + .halt_reg = 0x77070, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77070, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_unipro_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb20_master_clk = { + .halt_reg = 0xbc018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xbc018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb20_mock_utmi_clk = { + .halt_reg = 0xbc02c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xbc02c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb20_sleep_clk = { + .halt_reg = 0xbc028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xbc028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mp_master_clk = { + .halt_reg = 0x9a024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9a024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mp_mock_utmi_clk = { + .halt_reg = 0x9a038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9a038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mp_sleep_clk = { + .halt_reg = 0x9a034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9a034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_master_clk = { + .halt_reg = 0x3f030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3f030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_mock_utmi_clk = { + .halt_reg = 0x3f048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3f048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_sleep_clk = { + .halt_reg = 0x3f044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3f044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sec_master_clk = { + .halt_reg = 0xe2024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe2024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_sec_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sec_mock_utmi_clk = { + .halt_reg = 0xe2038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe2038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sec_sleep_clk = { + .halt_reg = 0xe2034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe2034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_sec_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_tert_master_clk = { + .halt_reg = 0xe1024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe1024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_tert_mock_utmi_clk = { + .halt_reg = 0xe1038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe1038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_tert_sleep_clk = { + .halt_reg = 0xe1034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe1034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_aux_clk = { + .halt_reg = 0x9a070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9a070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_mp_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_com_aux_clk = { + .halt_reg = 0x9a074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9a074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_mp_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_pipe_0_clk = { + .halt_reg = 0x9a078, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x9a078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_pipe_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_mp_phy_pipe_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_pipe_1_clk = { + .halt_reg = 0x9a080, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x9a080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_pipe_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_mp_phy_pipe_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_aux_clk = { + .halt_reg = 0x3f080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3f080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = { + .halt_reg = 0x3f084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3f084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_pipe_clk = { + .halt_reg = 0x3f088, + .halt_check = BRANCH_HALT_DELAY, + .hwcg_reg = 0x3f088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3f088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb34_prim_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sec_phy_aux_clk = { + .halt_reg = 0xe2070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe2070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_sec_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_sec_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sec_phy_com_aux_clk = { + .halt_reg = 0xe2074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe2074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_sec_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_sec_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sec_phy_pipe_clk = { + .halt_reg = 0xe2078, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xe2078, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe2078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_sec_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb34_sec_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_tert_phy_aux_clk = { + .halt_reg = 0xe1070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe1070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_tert_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_tert_phy_com_aux_clk = { + .halt_reg = 0xe1074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe1074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_tert_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_tert_phy_pipe_clk = { + .halt_reg = 0xe1078, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xe1078, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe1078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb34_tert_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_cfg_ahb_clk = { + .halt_reg = 0xba450, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba450, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xba450, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_dp0_clk = { + .halt_reg = 0x2b070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_dp0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_phy_dp0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_dp1_clk = { + .halt_reg = 0x2b124, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b124, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_dp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_phy_dp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_master_clk = { + .halt_reg = 0x2b01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_p2rr2p_pipe_clk = { + .halt_reg = 0x2b0f4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b0f4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_p2rr2p_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_phy_p2rr2p_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_pcie_pipe_clk = { + .halt_reg = 0x2b04c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_pcie_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_phy_pcie_pipe_mux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_rx0_clk = { + .halt_reg = 0x2b0c4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b0c4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_rx0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_phy_rx0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_rx1_clk = { + .halt_reg = 0x2b0d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b0d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_rx1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_phy_rx1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_usb_pipe_clk = { + .halt_reg = 0x2b0bc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b0bc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b0bc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_usb_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb34_prim_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_sb_if_clk = { + .halt_reg = 0x2b048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_sb_if_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_sb_if_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_sys_clk = { + .halt_reg = 0x2b05c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b05c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_sys_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_phy_sys_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_tmu_clk = { + .halt_reg = 0x2b09c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b09c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b09c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_tmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_tmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_uc_hrr_clk = { + .halt_reg = 0x2b06c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b06c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_uc_hrr_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_phy_sys_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_cfg_ahb_clk = { + .halt_reg = 0xba454, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba454, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xba454, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_dp0_clk = { + .halt_reg = 0x2d07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d07c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_dp0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_phy_dp0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_dp1_clk = { + .halt_reg = 0x2d144, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d144, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_dp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_phy_dp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_master_clk = { + .halt_reg = 0x2d01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_p2rr2p_pipe_clk = { + .halt_reg = 0x2d118, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d118, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_p2rr2p_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_phy_p2rr2p_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_pcie_pipe_clk = { + .halt_reg = 0x2d04c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_pcie_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_phy_pcie_pipe_mux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_rx0_clk = { + .halt_reg = 0x2d0e8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d0e8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_rx0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_phy_rx0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_rx1_clk = { + .halt_reg = 0x2d0fc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d0fc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_rx1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_phy_rx1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_usb_pipe_clk = { + .halt_reg = 0x2d0e0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d0e0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d0e0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_usb_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb34_sec_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_sb_if_clk = { + .halt_reg = 0x2d048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_sb_if_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_sb_if_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_sys_clk = { + .halt_reg = 0x2d05c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d05c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_sys_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_phy_sys_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_tmu_clk = { + .halt_reg = 0x2d0a8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d0a8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d0a8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_tmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_tmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_uc_hrr_clk = { + .halt_reg = 0x2d06c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d06c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_uc_hrr_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_phy_sys_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_cfg_ahb_clk = { + .halt_reg = 0xba458, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xba458, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xba458, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_dp0_clk = { + .halt_reg = 0xe0070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe0070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_dp0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_phy_dp0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_dp1_clk = { + .halt_reg = 0xe0128, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe0128, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_dp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_phy_dp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_master_clk = { + .halt_reg = 0xe001c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe001c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_p2rr2p_pipe_clk = { + .halt_reg = 0xe00f8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe00f8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_p2rr2p_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_phy_p2rr2p_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_pcie_pipe_clk = { + .halt_reg = 0xe004c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_pcie_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_phy_pcie_pipe_mux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_rx0_clk = { + .halt_reg = 0xe00c8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe00c8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_rx0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_phy_rx0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_rx1_clk = { + .halt_reg = 0xe00dc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe00dc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_rx1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_phy_rx1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_usb_pipe_clk = { + .halt_reg = 0xe00c0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xe00c0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe00c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_usb_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb34_tert_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_sb_if_clk = { + .halt_reg = 0xe0048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe0048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_sb_if_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_sb_if_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_sys_clk = { + .halt_reg = 0xe005c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe005c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_sys_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_phy_sys_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_tmu_clk = { + .halt_reg = 0xe00a0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xe00a0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe00a0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_tmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_tmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_uc_hrr_clk = { + .halt_reg = 0xe006c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe006c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_uc_hrr_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_phy_sys_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi0_clk = { + .halt_reg = 0x3201c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x3201c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3201c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi0c_clk = { + .halt_reg = 0x32030, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi0c_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi1_clk = { + .halt_reg = 0x32044, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32044, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gcc_pcie_0_tunnel_gdsc = { + .gdscr = 0xc8004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_0_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_1_tunnel_gdsc = { + .gdscr = 0x2e004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_1_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_2_tunnel_gdsc = { + .gdscr = 0xc0004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_2_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_3a_gdsc = { + .gdscr = 0xdc004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_3a_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_3a_phy_gdsc = { + .gdscr = 0x6c004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_3a_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_3b_gdsc = { + .gdscr = 0x94004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_3b_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_3b_phy_gdsc = { + .gdscr = 0x75004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_3b_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_4_gdsc = { + .gdscr = 0x88004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_4_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_4_phy_gdsc = { + .gdscr = 0xd3004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_4_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_5_gdsc = { + .gdscr = 0xc3004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_5_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_5_phy_gdsc = { + .gdscr = 0xd2004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_5_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_6_gdsc = { + .gdscr = 0x8a004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_6_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_6_phy_gdsc = { + .gdscr = 0xd4004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_6_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_ufs_phy_gdsc = { + .gdscr = 0x77008, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb20_prim_gdsc = { + .gdscr = 0xbc004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb20_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_mp_gdsc = { + .gdscr = 0x9a010, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_mp_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_prim_gdsc = { + .gdscr = 0x3f01c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_sec_gdsc = { + .gdscr = 0xe2010, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_sec_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_tert_gdsc = { + .gdscr = 0xe1010, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_tert_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb3_mp_ss0_phy_gdsc = { + .gdscr = 0x5400c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb3_mp_ss0_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb3_mp_ss1_phy_gdsc = { + .gdscr = 0x5402c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb3_mp_ss1_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb4_0_gdsc = { + .gdscr = 0x2b008, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb4_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb4_1_gdsc = { + .gdscr = 0x2d008, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb4_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb4_2_gdsc = { + .gdscr = 0xe0008, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb4_2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb_0_phy_gdsc = { + .gdscr = 0xdb024, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb_0_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb_1_phy_gdsc = { + .gdscr = 0x2c024, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb_1_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb_2_phy_gdsc = { + .gdscr = 0xbe024, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb_2_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *gcc_glymur_clocks[] = { + [GCC_AGGRE_NOC_PCIE_3A_WEST_SF_AXI_CLK] = &gcc_aggre_noc_pcie_3a_west_sf_axi_clk.clkr, + [GCC_AGGRE_NOC_PCIE_3B_WEST_SF_AXI_CLK] = &gcc_aggre_noc_pcie_3b_west_sf_axi_clk.clkr, + [GCC_AGGRE_NOC_PCIE_4_WEST_SF_AXI_CLK] = &gcc_aggre_noc_pcie_4_west_sf_axi_clk.clkr, + [GCC_AGGRE_NOC_PCIE_5_EAST_SF_AXI_CLK] = &gcc_aggre_noc_pcie_5_east_sf_axi_clk.clkr, + [GCC_AGGRE_NOC_PCIE_6_WEST_SF_AXI_CLK] = &gcc_aggre_noc_pcie_6_west_sf_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_USB2_PRIM_AXI_CLK] = &gcc_aggre_usb2_prim_axi_clk.clkr, + [GCC_AGGRE_USB3_MP_AXI_CLK] = &gcc_aggre_usb3_mp_axi_clk.clkr, + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, + [GCC_AGGRE_USB3_SEC_AXI_CLK] = &gcc_aggre_usb3_sec_axi_clk.clkr, + [GCC_AGGRE_USB3_TERT_AXI_CLK] = &gcc_aggre_usb3_tert_axi_clk.clkr, + [GCC_AGGRE_USB4_0_AXI_CLK] = &gcc_aggre_usb4_0_axi_clk.clkr, + [GCC_AGGRE_USB4_1_AXI_CLK] = &gcc_aggre_usb4_1_axi_clk.clkr, + [GCC_AGGRE_USB4_2_AXI_CLK] = &gcc_aggre_usb4_2_axi_clk.clkr, + [GCC_AV1E_AHB_CLK] = &gcc_av1e_ahb_clk.clkr, + [GCC_AV1E_AXI_CLK] = &gcc_av1e_axi_clk.clkr, + [GCC_AV1E_XO_CLK] = &gcc_av1e_xo_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr, + [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_SOUTH_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_south_ahb_clk.clkr, + [GCC_CFG_NOC_USB2_PRIM_AXI_CLK] = &gcc_cfg_noc_usb2_prim_axi_clk.clkr, + [GCC_CFG_NOC_USB3_MP_AXI_CLK] = &gcc_cfg_noc_usb3_mp_axi_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = &gcc_cfg_noc_usb3_sec_axi_clk.clkr, + [GCC_CFG_NOC_USB3_TERT_AXI_CLK] = &gcc_cfg_noc_usb3_tert_axi_clk.clkr, + [GCC_CFG_NOC_USB_ANOC_AHB_CLK] = &gcc_cfg_noc_usb_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_USB_ANOC_SOUTH_AHB_CLK] = &gcc_cfg_noc_usb_anoc_south_ahb_clk.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr, + [GCC_EVA_AHB_CLK] = &gcc_eva_ahb_clk.clkr, + [GCC_EVA_AXI0_CLK] = &gcc_eva_axi0_clk.clkr, + [GCC_EVA_AXI0C_CLK] = &gcc_eva_axi0c_clk.clkr, + [GCC_EVA_XO_CLK] = &gcc_eva_xo_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr, + [GCC_GPLL0] = &gcc_gpll0.clkr, + [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr, + [GCC_GPLL1] = &gcc_gpll1.clkr, + [GCC_GPLL14] = &gcc_gpll14.clkr, + [GCC_GPLL14_OUT_EVEN] = &gcc_gpll14_out_even.clkr, + [GCC_GPLL4] = &gcc_gpll4.clkr, + [GCC_GPLL5] = &gcc_gpll5.clkr, + [GCC_GPLL7] = &gcc_gpll7.clkr, + [GCC_GPLL8] = &gcc_gpll8.clkr, + [GCC_GPLL9] = &gcc_gpll9.clkr, + [GCC_GPU_GEMNOC_GFX_CLK] = &gcc_gpu_gemnoc_gfx_clk.clkr, + [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr, + [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr, + [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, + [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr, + [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr, + [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK] = &gcc_pcie_0_phy_rchng_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr, + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr, + [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr, + [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr, + [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr, + [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr, + [GCC_PCIE_1_PHY_RCHNG_CLK] = &gcc_pcie_1_phy_rchng_clk.clkr, + [GCC_PCIE_1_PHY_RCHNG_CLK_SRC] = &gcc_pcie_1_phy_rchng_clk_src.clkr, + [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr, + [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr, + [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = &gcc_pcie_1_slv_q2a_axi_clk.clkr, + [GCC_PCIE_2_AUX_CLK] = &gcc_pcie_2_aux_clk.clkr, + [GCC_PCIE_2_AUX_CLK_SRC] = &gcc_pcie_2_aux_clk_src.clkr, + [GCC_PCIE_2_CFG_AHB_CLK] = &gcc_pcie_2_cfg_ahb_clk.clkr, + [GCC_PCIE_2_MSTR_AXI_CLK] = &gcc_pcie_2_mstr_axi_clk.clkr, + [GCC_PCIE_2_PHY_RCHNG_CLK] = &gcc_pcie_2_phy_rchng_clk.clkr, + [GCC_PCIE_2_PHY_RCHNG_CLK_SRC] = &gcc_pcie_2_phy_rchng_clk_src.clkr, + [GCC_PCIE_2_PIPE_CLK] = &gcc_pcie_2_pipe_clk.clkr, + [GCC_PCIE_2_SLV_AXI_CLK] = &gcc_pcie_2_slv_axi_clk.clkr, + [GCC_PCIE_2_SLV_Q2A_AXI_CLK] = &gcc_pcie_2_slv_q2a_axi_clk.clkr, + [GCC_PCIE_3A_AUX_CLK] = &gcc_pcie_3a_aux_clk.clkr, + [GCC_PCIE_3A_AUX_CLK_SRC] = &gcc_pcie_3a_aux_clk_src.clkr, + [GCC_PCIE_3A_CFG_AHB_CLK] = &gcc_pcie_3a_cfg_ahb_clk.clkr, + [GCC_PCIE_3A_MSTR_AXI_CLK] = &gcc_pcie_3a_mstr_axi_clk.clkr, + [GCC_PCIE_3A_PHY_RCHNG_CLK] = &gcc_pcie_3a_phy_rchng_clk.clkr, + [GCC_PCIE_3A_PHY_RCHNG_CLK_SRC] = &gcc_pcie_3a_phy_rchng_clk_src.clkr, + [GCC_PCIE_3A_PIPE_CLK] = &gcc_pcie_3a_pipe_clk.clkr, + [GCC_PCIE_3A_PIPE_CLK_SRC] = &gcc_pcie_3a_pipe_clk_src.clkr, + [GCC_PCIE_3A_SLV_AXI_CLK] = &gcc_pcie_3a_slv_axi_clk.clkr, + [GCC_PCIE_3A_SLV_Q2A_AXI_CLK] = &gcc_pcie_3a_slv_q2a_axi_clk.clkr, + [GCC_PCIE_3B_AUX_CLK] = &gcc_pcie_3b_aux_clk.clkr, + [GCC_PCIE_3B_AUX_CLK_SRC] = &gcc_pcie_3b_aux_clk_src.clkr, + [GCC_PCIE_3B_CFG_AHB_CLK] = &gcc_pcie_3b_cfg_ahb_clk.clkr, + [GCC_PCIE_3B_MSTR_AXI_CLK] = &gcc_pcie_3b_mstr_axi_clk.clkr, + [GCC_PCIE_3B_PHY_RCHNG_CLK] = &gcc_pcie_3b_phy_rchng_clk.clkr, + [GCC_PCIE_3B_PHY_RCHNG_CLK_SRC] = &gcc_pcie_3b_phy_rchng_clk_src.clkr, + [GCC_PCIE_3B_PIPE_CLK] = &gcc_pcie_3b_pipe_clk.clkr, + [GCC_PCIE_3B_PIPE_CLK_SRC] = &gcc_pcie_3b_pipe_clk_src.clkr, + [GCC_PCIE_3B_PIPE_DIV2_CLK] = &gcc_pcie_3b_pipe_div2_clk.clkr, + [GCC_PCIE_3B_PIPE_DIV_CLK_SRC] = &gcc_pcie_3b_pipe_div_clk_src.clkr, + [GCC_PCIE_3B_SLV_AXI_CLK] = &gcc_pcie_3b_slv_axi_clk.clkr, + [GCC_PCIE_3B_SLV_Q2A_AXI_CLK] = &gcc_pcie_3b_slv_q2a_axi_clk.clkr, + [GCC_PCIE_4_AUX_CLK] = &gcc_pcie_4_aux_clk.clkr, + [GCC_PCIE_4_AUX_CLK_SRC] = &gcc_pcie_4_aux_clk_src.clkr, + [GCC_PCIE_4_CFG_AHB_CLK] = &gcc_pcie_4_cfg_ahb_clk.clkr, + [GCC_PCIE_4_MSTR_AXI_CLK] = &gcc_pcie_4_mstr_axi_clk.clkr, + [GCC_PCIE_4_PHY_RCHNG_CLK] = &gcc_pcie_4_phy_rchng_clk.clkr, + [GCC_PCIE_4_PHY_RCHNG_CLK_SRC] = &gcc_pcie_4_phy_rchng_clk_src.clkr, + [GCC_PCIE_4_PIPE_CLK] = &gcc_pcie_4_pipe_clk.clkr, + [GCC_PCIE_4_PIPE_CLK_SRC] = &gcc_pcie_4_pipe_clk_src.clkr, + [GCC_PCIE_4_PIPE_DIV2_CLK] = &gcc_pcie_4_pipe_div2_clk.clkr, + [GCC_PCIE_4_PIPE_DIV_CLK_SRC] = &gcc_pcie_4_pipe_div_clk_src.clkr, + [GCC_PCIE_4_SLV_AXI_CLK] = &gcc_pcie_4_slv_axi_clk.clkr, + [GCC_PCIE_4_SLV_Q2A_AXI_CLK] = &gcc_pcie_4_slv_q2a_axi_clk.clkr, + [GCC_PCIE_5_AUX_CLK] = &gcc_pcie_5_aux_clk.clkr, + [GCC_PCIE_5_AUX_CLK_SRC] = &gcc_pcie_5_aux_clk_src.clkr, + [GCC_PCIE_5_CFG_AHB_CLK] = &gcc_pcie_5_cfg_ahb_clk.clkr, + [GCC_PCIE_5_MSTR_AXI_CLK] = &gcc_pcie_5_mstr_axi_clk.clkr, + [GCC_PCIE_5_PHY_RCHNG_CLK] = &gcc_pcie_5_phy_rchng_clk.clkr, + [GCC_PCIE_5_PHY_RCHNG_CLK_SRC] = &gcc_pcie_5_phy_rchng_clk_src.clkr, + [GCC_PCIE_5_PIPE_CLK] = &gcc_pcie_5_pipe_clk.clkr, + [GCC_PCIE_5_PIPE_CLK_SRC] = &gcc_pcie_5_pipe_clk_src.clkr, + [GCC_PCIE_5_PIPE_DIV2_CLK] = &gcc_pcie_5_pipe_div2_clk.clkr, + [GCC_PCIE_5_PIPE_DIV_CLK_SRC] = &gcc_pcie_5_pipe_div_clk_src.clkr, + [GCC_PCIE_5_SLV_AXI_CLK] = &gcc_pcie_5_slv_axi_clk.clkr, + [GCC_PCIE_5_SLV_Q2A_AXI_CLK] = &gcc_pcie_5_slv_q2a_axi_clk.clkr, + [GCC_PCIE_6_AUX_CLK] = &gcc_pcie_6_aux_clk.clkr, + [GCC_PCIE_6_AUX_CLK_SRC] = &gcc_pcie_6_aux_clk_src.clkr, + [GCC_PCIE_6_CFG_AHB_CLK] = &gcc_pcie_6_cfg_ahb_clk.clkr, + [GCC_PCIE_6_MSTR_AXI_CLK] = &gcc_pcie_6_mstr_axi_clk.clkr, + [GCC_PCIE_6_PHY_RCHNG_CLK] = &gcc_pcie_6_phy_rchng_clk.clkr, + [GCC_PCIE_6_PHY_RCHNG_CLK_SRC] = &gcc_pcie_6_phy_rchng_clk_src.clkr, + [GCC_PCIE_6_PIPE_CLK] = &gcc_pcie_6_pipe_clk.clkr, + [GCC_PCIE_6_PIPE_CLK_SRC] = &gcc_pcie_6_pipe_clk_src.clkr, + [GCC_PCIE_6_PIPE_DIV2_CLK] = &gcc_pcie_6_pipe_div2_clk.clkr, + [GCC_PCIE_6_PIPE_DIV_CLK_SRC] = &gcc_pcie_6_pipe_div_clk_src.clkr, + [GCC_PCIE_6_SLV_AXI_CLK] = &gcc_pcie_6_slv_axi_clk.clkr, + [GCC_PCIE_6_SLV_Q2A_AXI_CLK] = &gcc_pcie_6_slv_q2a_axi_clk.clkr, + [GCC_PCIE_NOC_PWRCTL_CLK] = &gcc_pcie_noc_pwrctl_clk.clkr, + [GCC_PCIE_NOC_QOSGEN_EXTREF_CLK] = &gcc_pcie_noc_qosgen_extref_clk.clkr, + [GCC_PCIE_NOC_SF_CENTER_CLK] = &gcc_pcie_noc_sf_center_clk.clkr, + [GCC_PCIE_NOC_SLAVE_SF_EAST_CLK] = &gcc_pcie_noc_slave_sf_east_clk.clkr, + [GCC_PCIE_NOC_SLAVE_SF_WEST_CLK] = &gcc_pcie_noc_slave_sf_west_clk.clkr, + [GCC_PCIE_NOC_TSCTR_CLK] = &gcc_pcie_noc_tsctr_clk.clkr, + [GCC_PCIE_PHY_3A_AUX_CLK] = &gcc_pcie_phy_3a_aux_clk.clkr, + [GCC_PCIE_PHY_3A_AUX_CLK_SRC] = &gcc_pcie_phy_3a_aux_clk_src.clkr, + [GCC_PCIE_PHY_3B_AUX_CLK] = &gcc_pcie_phy_3b_aux_clk.clkr, + [GCC_PCIE_PHY_3B_AUX_CLK_SRC] = &gcc_pcie_phy_3b_aux_clk_src.clkr, + [GCC_PCIE_PHY_4_AUX_CLK] = &gcc_pcie_phy_4_aux_clk.clkr, + [GCC_PCIE_PHY_4_AUX_CLK_SRC] = &gcc_pcie_phy_4_aux_clk_src.clkr, + [GCC_PCIE_PHY_5_AUX_CLK] = &gcc_pcie_phy_5_aux_clk.clkr, + [GCC_PCIE_PHY_5_AUX_CLK_SRC] = &gcc_pcie_phy_5_aux_clk_src.clkr, + [GCC_PCIE_PHY_6_AUX_CLK] = &gcc_pcie_phy_6_aux_clk.clkr, + [GCC_PCIE_PHY_6_AUX_CLK_SRC] = &gcc_pcie_phy_6_aux_clk_src.clkr, + [GCC_PCIE_RSCC_CFG_AHB_CLK] = &gcc_pcie_rscc_cfg_ahb_clk.clkr, + [GCC_PCIE_RSCC_XO_CLK] = &gcc_pcie_rscc_xo_clk.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr, + [GCC_QMIP_AV1E_AHB_CLK] = &gcc_qmip_av1e_ahb_clk.clkr, + [GCC_QMIP_CAMERA_CMD_AHB_CLK] = &gcc_qmip_camera_cmd_ahb_clk.clkr, + [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr, + [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr, + [GCC_QMIP_GPU_AHB_CLK] = &gcc_qmip_gpu_ahb_clk.clkr, + [GCC_QMIP_PCIE_3A_AHB_CLK] = &gcc_qmip_pcie_3a_ahb_clk.clkr, + [GCC_QMIP_PCIE_3B_AHB_CLK] = &gcc_qmip_pcie_3b_ahb_clk.clkr, + [GCC_QMIP_PCIE_4_AHB_CLK] = &gcc_qmip_pcie_4_ahb_clk.clkr, + [GCC_QMIP_PCIE_5_AHB_CLK] = &gcc_qmip_pcie_5_ahb_clk.clkr, + [GCC_QMIP_PCIE_6_AHB_CLK] = &gcc_qmip_pcie_6_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CV_CPU_AHB_CLK] = &gcc_qmip_video_cv_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr, + [GCC_QMIP_VIDEO_V_CPU_AHB_CLK] = &gcc_qmip_video_v_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC1_AHB_CLK] = &gcc_qmip_video_vcodec1_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr, + [GCC_QUPV3_OOB_CORE_2X_CLK] = &gcc_qupv3_oob_core_2x_clk.clkr, + [GCC_QUPV3_OOB_CORE_CLK] = &gcc_qupv3_oob_core_clk.clkr, + [GCC_QUPV3_OOB_M_AHB_CLK] = &gcc_qupv3_oob_m_ahb_clk.clkr, + [GCC_QUPV3_OOB_QSPI_S0_CLK] = &gcc_qupv3_oob_qspi_s0_clk.clkr, + [GCC_QUPV3_OOB_QSPI_S0_CLK_SRC] = &gcc_qupv3_oob_qspi_s0_clk_src.clkr, + [GCC_QUPV3_OOB_QSPI_S1_CLK] = &gcc_qupv3_oob_qspi_s1_clk.clkr, + [GCC_QUPV3_OOB_QSPI_S1_CLK_SRC] = &gcc_qupv3_oob_qspi_s1_clk_src.clkr, + [GCC_QUPV3_OOB_S0_CLK] = &gcc_qupv3_oob_s0_clk.clkr, + [GCC_QUPV3_OOB_S0_CLK_SRC] = &gcc_qupv3_oob_s0_clk_src.clkr, + [GCC_QUPV3_OOB_S1_CLK] = &gcc_qupv3_oob_s1_clk.clkr, + [GCC_QUPV3_OOB_S1_CLK_SRC] = &gcc_qupv3_oob_s1_clk_src.clkr, + [GCC_QUPV3_OOB_S_AHB_CLK] = &gcc_qupv3_oob_s_ahb_clk.clkr, + [GCC_QUPV3_OOB_TCXO_CLK] = &gcc_qupv3_oob_tcxo_clk.clkr, + [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr, + [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr, + [GCC_QUPV3_WRAP0_QSPI_S2_CLK] = &gcc_qupv3_wrap0_qspi_s2_clk.clkr, + [GCC_QUPV3_WRAP0_QSPI_S2_CLK_SRC] = &gcc_qupv3_wrap0_qspi_s2_clk_src.clkr, + [GCC_QUPV3_WRAP0_QSPI_S3_CLK] = &gcc_qupv3_wrap0_qspi_s3_clk.clkr, + [GCC_QUPV3_WRAP0_QSPI_S3_CLK_SRC] = &gcc_qupv3_wrap0_qspi_s3_clk_src.clkr, + [GCC_QUPV3_WRAP0_QSPI_S6_CLK] = &gcc_qupv3_wrap0_qspi_s6_clk.clkr, + [GCC_QUPV3_WRAP0_QSPI_S6_CLK_SRC] = &gcc_qupv3_wrap0_qspi_s6_clk_src.clkr, + [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr, + [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr, + [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr, + [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr, + [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr, + [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr, + [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr, + [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr, + [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr, + [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr, + [GCC_QUPV3_WRAP0_S5_CLK] = &gcc_qupv3_wrap0_s5_clk.clkr, + [GCC_QUPV3_WRAP0_S5_CLK_SRC] = &gcc_qupv3_wrap0_s5_clk_src.clkr, + [GCC_QUPV3_WRAP0_S6_CLK] = &gcc_qupv3_wrap0_s6_clk.clkr, + [GCC_QUPV3_WRAP0_S6_CLK_SRC] = &gcc_qupv3_wrap0_s6_clk_src.clkr, + [GCC_QUPV3_WRAP0_S7_CLK] = &gcc_qupv3_wrap0_s7_clk.clkr, + [GCC_QUPV3_WRAP0_S7_CLK_SRC] = &gcc_qupv3_wrap0_s7_clk_src.clkr, + [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr, + [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_S2_CLK] = &gcc_qupv3_wrap1_qspi_s2_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_S2_CLK_SRC] = &gcc_qupv3_wrap1_qspi_s2_clk_src.clkr, + [GCC_QUPV3_WRAP1_QSPI_S3_CLK] = &gcc_qupv3_wrap1_qspi_s3_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_S3_CLK_SRC] = &gcc_qupv3_wrap1_qspi_s3_clk_src.clkr, + [GCC_QUPV3_WRAP1_QSPI_S6_CLK] = &gcc_qupv3_wrap1_qspi_s6_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_S6_CLK_SRC] = &gcc_qupv3_wrap1_qspi_s6_clk_src.clkr, + [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr, + [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr, + [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr, + [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr, + [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr, + [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr, + [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr, + [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr, + [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr, + [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr, + [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr, + [GCC_QUPV3_WRAP1_S6_CLK] = &gcc_qupv3_wrap1_s6_clk.clkr, + [GCC_QUPV3_WRAP1_S6_CLK_SRC] = &gcc_qupv3_wrap1_s6_clk_src.clkr, + [GCC_QUPV3_WRAP1_S7_CLK] = &gcc_qupv3_wrap1_s7_clk.clkr, + [GCC_QUPV3_WRAP1_S7_CLK_SRC] = &gcc_qupv3_wrap1_s7_clk_src.clkr, + [GCC_QUPV3_WRAP2_CORE_2X_CLK] = &gcc_qupv3_wrap2_core_2x_clk.clkr, + [GCC_QUPV3_WRAP2_CORE_CLK] = &gcc_qupv3_wrap2_core_clk.clkr, + [GCC_QUPV3_WRAP2_QSPI_S2_CLK] = &gcc_qupv3_wrap2_qspi_s2_clk.clkr, + [GCC_QUPV3_WRAP2_QSPI_S2_CLK_SRC] = &gcc_qupv3_wrap2_qspi_s2_clk_src.clkr, + [GCC_QUPV3_WRAP2_QSPI_S3_CLK] = &gcc_qupv3_wrap2_qspi_s3_clk.clkr, + [GCC_QUPV3_WRAP2_QSPI_S3_CLK_SRC] = &gcc_qupv3_wrap2_qspi_s3_clk_src.clkr, + [GCC_QUPV3_WRAP2_QSPI_S6_CLK] = &gcc_qupv3_wrap2_qspi_s6_clk.clkr, + [GCC_QUPV3_WRAP2_QSPI_S6_CLK_SRC] = &gcc_qupv3_wrap2_qspi_s6_clk_src.clkr, + [GCC_QUPV3_WRAP2_S0_CLK] = &gcc_qupv3_wrap2_s0_clk.clkr, + [GCC_QUPV3_WRAP2_S0_CLK_SRC] = &gcc_qupv3_wrap2_s0_clk_src.clkr, + [GCC_QUPV3_WRAP2_S1_CLK] = &gcc_qupv3_wrap2_s1_clk.clkr, + [GCC_QUPV3_WRAP2_S1_CLK_SRC] = &gcc_qupv3_wrap2_s1_clk_src.clkr, + [GCC_QUPV3_WRAP2_S2_CLK] = &gcc_qupv3_wrap2_s2_clk.clkr, + [GCC_QUPV3_WRAP2_S2_CLK_SRC] = &gcc_qupv3_wrap2_s2_clk_src.clkr, + [GCC_QUPV3_WRAP2_S3_CLK] = &gcc_qupv3_wrap2_s3_clk.clkr, + [GCC_QUPV3_WRAP2_S3_CLK_SRC] = &gcc_qupv3_wrap2_s3_clk_src.clkr, + [GCC_QUPV3_WRAP2_S4_CLK] = &gcc_qupv3_wrap2_s4_clk.clkr, + [GCC_QUPV3_WRAP2_S4_CLK_SRC] = &gcc_qupv3_wrap2_s4_clk_src.clkr, + [GCC_QUPV3_WRAP2_S5_CLK] = &gcc_qupv3_wrap2_s5_clk.clkr, + [GCC_QUPV3_WRAP2_S5_CLK_SRC] = &gcc_qupv3_wrap2_s5_clk_src.clkr, + [GCC_QUPV3_WRAP2_S6_CLK] = &gcc_qupv3_wrap2_s6_clk.clkr, + [GCC_QUPV3_WRAP2_S6_CLK_SRC] = &gcc_qupv3_wrap2_s6_clk_src.clkr, + [GCC_QUPV3_WRAP2_S7_CLK] = &gcc_qupv3_wrap2_s7_clk.clkr, + [GCC_QUPV3_WRAP2_S7_CLK_SRC] = &gcc_qupv3_wrap2_s7_clk_src.clkr, + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_M_AHB_CLK] = &gcc_qupv3_wrap_2_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_S_AHB_CLK] = &gcc_qupv3_wrap_2_s_ahb_clk.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr, + [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr, + [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr, + [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr, + [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr, + [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr, + [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_rx_symbol_0_clk_src.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC] = &gcc_ufs_phy_rx_symbol_1_clk_src.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_tx_symbol_0_clk_src.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_core_clk_src.clkr, + [GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr, + [GCC_USB20_MASTER_CLK_SRC] = &gcc_usb20_master_clk_src.clkr, + [GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr, + [GCC_USB20_MOCK_UTMI_CLK_SRC] = &gcc_usb20_mock_utmi_clk_src.clkr, + [GCC_USB20_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb20_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr, + [GCC_USB30_MP_MASTER_CLK] = &gcc_usb30_mp_master_clk.clkr, + [GCC_USB30_MP_MASTER_CLK_SRC] = &gcc_usb30_mp_master_clk_src.clkr, + [GCC_USB30_MP_MOCK_UTMI_CLK] = &gcc_usb30_mp_mock_utmi_clk.clkr, + [GCC_USB30_MP_MOCK_UTMI_CLK_SRC] = &gcc_usb30_mp_mock_utmi_clk_src.clkr, + [GCC_USB30_MP_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_mp_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_MP_SLEEP_CLK] = &gcc_usb30_mp_sleep_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr, + [GCC_USB30_SEC_MASTER_CLK] = &gcc_usb30_sec_master_clk.clkr, + [GCC_USB30_SEC_MASTER_CLK_SRC] = &gcc_usb30_sec_master_clk_src.clkr, + [GCC_USB30_SEC_MOCK_UTMI_CLK] = &gcc_usb30_sec_mock_utmi_clk.clkr, + [GCC_USB30_SEC_MOCK_UTMI_CLK_SRC] = &gcc_usb30_sec_mock_utmi_clk_src.clkr, + [GCC_USB30_SEC_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_SEC_SLEEP_CLK] = &gcc_usb30_sec_sleep_clk.clkr, + [GCC_USB30_TERT_MASTER_CLK] = &gcc_usb30_tert_master_clk.clkr, + [GCC_USB30_TERT_MASTER_CLK_SRC] = &gcc_usb30_tert_master_clk_src.clkr, + [GCC_USB30_TERT_MOCK_UTMI_CLK] = &gcc_usb30_tert_mock_utmi_clk.clkr, + [GCC_USB30_TERT_MOCK_UTMI_CLK_SRC] = &gcc_usb30_tert_mock_utmi_clk_src.clkr, + [GCC_USB30_TERT_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_tert_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_TERT_SLEEP_CLK] = &gcc_usb30_tert_sleep_clk.clkr, + [GCC_USB34_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb34_prim_phy_pipe_clk_src.clkr, + [GCC_USB34_SEC_PHY_PIPE_CLK_SRC] = &gcc_usb34_sec_phy_pipe_clk_src.clkr, + [GCC_USB34_TERT_PHY_PIPE_CLK_SRC] = &gcc_usb34_tert_phy_pipe_clk_src.clkr, + [GCC_USB3_MP_PHY_AUX_CLK] = &gcc_usb3_mp_phy_aux_clk.clkr, + [GCC_USB3_MP_PHY_AUX_CLK_SRC] = &gcc_usb3_mp_phy_aux_clk_src.clkr, + [GCC_USB3_MP_PHY_COM_AUX_CLK] = &gcc_usb3_mp_phy_com_aux_clk.clkr, + [GCC_USB3_MP_PHY_PIPE_0_CLK] = &gcc_usb3_mp_phy_pipe_0_clk.clkr, + [GCC_USB3_MP_PHY_PIPE_0_CLK_SRC] = &gcc_usb3_mp_phy_pipe_0_clk_src.clkr, + [GCC_USB3_MP_PHY_PIPE_1_CLK] = &gcc_usb3_mp_phy_pipe_1_clk.clkr, + [GCC_USB3_MP_PHY_PIPE_1_CLK_SRC] = &gcc_usb3_mp_phy_pipe_1_clk_src.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr, + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr, + [GCC_USB3_SEC_PHY_AUX_CLK] = &gcc_usb3_sec_phy_aux_clk.clkr, + [GCC_USB3_SEC_PHY_AUX_CLK_SRC] = &gcc_usb3_sec_phy_aux_clk_src.clkr, + [GCC_USB3_SEC_PHY_COM_AUX_CLK] = &gcc_usb3_sec_phy_com_aux_clk.clkr, + [GCC_USB3_SEC_PHY_PIPE_CLK] = &gcc_usb3_sec_phy_pipe_clk.clkr, + [GCC_USB3_SEC_PHY_PIPE_CLK_SRC] = &gcc_usb3_sec_phy_pipe_clk_src.clkr, + [GCC_USB3_TERT_PHY_AUX_CLK] = &gcc_usb3_tert_phy_aux_clk.clkr, + [GCC_USB3_TERT_PHY_AUX_CLK_SRC] = &gcc_usb3_tert_phy_aux_clk_src.clkr, + [GCC_USB3_TERT_PHY_COM_AUX_CLK] = &gcc_usb3_tert_phy_com_aux_clk.clkr, + [GCC_USB3_TERT_PHY_PIPE_CLK] = &gcc_usb3_tert_phy_pipe_clk.clkr, + [GCC_USB3_TERT_PHY_PIPE_CLK_SRC] = &gcc_usb3_tert_phy_pipe_clk_src.clkr, + [GCC_USB4_0_CFG_AHB_CLK] = &gcc_usb4_0_cfg_ahb_clk.clkr, + [GCC_USB4_0_DP0_CLK] = &gcc_usb4_0_dp0_clk.clkr, + [GCC_USB4_0_DP1_CLK] = &gcc_usb4_0_dp1_clk.clkr, + [GCC_USB4_0_MASTER_CLK] = &gcc_usb4_0_master_clk.clkr, + [GCC_USB4_0_MASTER_CLK_SRC] = &gcc_usb4_0_master_clk_src.clkr, + [GCC_USB4_0_PHY_DP0_CLK_SRC] = &gcc_usb4_0_phy_dp0_clk_src.clkr, + [GCC_USB4_0_PHY_DP1_CLK_SRC] = &gcc_usb4_0_phy_dp1_clk_src.clkr, + [GCC_USB4_0_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_0_phy_p2rr2p_pipe_clk.clkr, + [GCC_USB4_0_PHY_P2RR2P_PIPE_CLK_SRC] = &gcc_usb4_0_phy_p2rr2p_pipe_clk_src.clkr, + [GCC_USB4_0_PHY_PCIE_PIPE_CLK] = &gcc_usb4_0_phy_pcie_pipe_clk.clkr, + [GCC_USB4_0_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_0_phy_pcie_pipe_clk_src.clkr, + [GCC_USB4_0_PHY_PCIE_PIPE_MUX_CLK_SRC] = &gcc_usb4_0_phy_pcie_pipe_mux_clk_src.clkr, + [GCC_USB4_0_PHY_RX0_CLK] = &gcc_usb4_0_phy_rx0_clk.clkr, + [GCC_USB4_0_PHY_RX0_CLK_SRC] = &gcc_usb4_0_phy_rx0_clk_src.clkr, + [GCC_USB4_0_PHY_RX1_CLK] = &gcc_usb4_0_phy_rx1_clk.clkr, + [GCC_USB4_0_PHY_RX1_CLK_SRC] = &gcc_usb4_0_phy_rx1_clk_src.clkr, + [GCC_USB4_0_PHY_SYS_CLK_SRC] = &gcc_usb4_0_phy_sys_clk_src.clkr, + [GCC_USB4_0_PHY_USB_PIPE_CLK] = &gcc_usb4_0_phy_usb_pipe_clk.clkr, + [GCC_USB4_0_SB_IF_CLK] = &gcc_usb4_0_sb_if_clk.clkr, + [GCC_USB4_0_SB_IF_CLK_SRC] = &gcc_usb4_0_sb_if_clk_src.clkr, + [GCC_USB4_0_SYS_CLK] = &gcc_usb4_0_sys_clk.clkr, + [GCC_USB4_0_TMU_CLK] = &gcc_usb4_0_tmu_clk.clkr, + [GCC_USB4_0_TMU_CLK_SRC] = &gcc_usb4_0_tmu_clk_src.clkr, + [GCC_USB4_0_UC_HRR_CLK] = &gcc_usb4_0_uc_hrr_clk.clkr, + [GCC_USB4_1_CFG_AHB_CLK] = &gcc_usb4_1_cfg_ahb_clk.clkr, + [GCC_USB4_1_DP0_CLK] = &gcc_usb4_1_dp0_clk.clkr, + [GCC_USB4_1_DP1_CLK] = &gcc_usb4_1_dp1_clk.clkr, + [GCC_USB4_1_MASTER_CLK] = &gcc_usb4_1_master_clk.clkr, + [GCC_USB4_1_MASTER_CLK_SRC] = &gcc_usb4_1_master_clk_src.clkr, + [GCC_USB4_1_PHY_DP0_CLK_SRC] = &gcc_usb4_1_phy_dp0_clk_src.clkr, + [GCC_USB4_1_PHY_DP1_CLK_SRC] = &gcc_usb4_1_phy_dp1_clk_src.clkr, + [GCC_USB4_1_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_1_phy_p2rr2p_pipe_clk.clkr, + [GCC_USB4_1_PHY_P2RR2P_PIPE_CLK_SRC] = &gcc_usb4_1_phy_p2rr2p_pipe_clk_src.clkr, + [GCC_USB4_1_PHY_PCIE_PIPE_CLK] = &gcc_usb4_1_phy_pcie_pipe_clk.clkr, + [GCC_USB4_1_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_1_phy_pcie_pipe_clk_src.clkr, + [GCC_USB4_1_PHY_PCIE_PIPE_MUX_CLK_SRC] = &gcc_usb4_1_phy_pcie_pipe_mux_clk_src.clkr, + [GCC_USB4_1_PHY_PLL_PIPE_CLK_SRC] = &gcc_usb4_1_phy_pll_pipe_clk_src.clkr, + [GCC_USB4_1_PHY_RX0_CLK] = &gcc_usb4_1_phy_rx0_clk.clkr, + [GCC_USB4_1_PHY_RX0_CLK_SRC] = &gcc_usb4_1_phy_rx0_clk_src.clkr, + [GCC_USB4_1_PHY_RX1_CLK] = &gcc_usb4_1_phy_rx1_clk.clkr, + [GCC_USB4_1_PHY_RX1_CLK_SRC] = &gcc_usb4_1_phy_rx1_clk_src.clkr, + [GCC_USB4_1_PHY_SYS_CLK_SRC] = &gcc_usb4_1_phy_sys_clk_src.clkr, + [GCC_USB4_1_PHY_USB_PIPE_CLK] = &gcc_usb4_1_phy_usb_pipe_clk.clkr, + [GCC_USB4_1_SB_IF_CLK] = &gcc_usb4_1_sb_if_clk.clkr, + [GCC_USB4_1_SB_IF_CLK_SRC] = &gcc_usb4_1_sb_if_clk_src.clkr, + [GCC_USB4_1_SYS_CLK] = &gcc_usb4_1_sys_clk.clkr, + [GCC_USB4_1_TMU_CLK] = &gcc_usb4_1_tmu_clk.clkr, + [GCC_USB4_1_TMU_CLK_SRC] = &gcc_usb4_1_tmu_clk_src.clkr, + [GCC_USB4_1_UC_HRR_CLK] = &gcc_usb4_1_uc_hrr_clk.clkr, + [GCC_USB4_2_CFG_AHB_CLK] = &gcc_usb4_2_cfg_ahb_clk.clkr, + [GCC_USB4_2_DP0_CLK] = &gcc_usb4_2_dp0_clk.clkr, + [GCC_USB4_2_DP1_CLK] = &gcc_usb4_2_dp1_clk.clkr, + [GCC_USB4_2_MASTER_CLK] = &gcc_usb4_2_master_clk.clkr, + [GCC_USB4_2_MASTER_CLK_SRC] = &gcc_usb4_2_master_clk_src.clkr, + [GCC_USB4_2_PHY_DP0_CLK_SRC] = &gcc_usb4_2_phy_dp0_clk_src.clkr, + [GCC_USB4_2_PHY_DP1_CLK_SRC] = &gcc_usb4_2_phy_dp1_clk_src.clkr, + [GCC_USB4_2_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_2_phy_p2rr2p_pipe_clk.clkr, + [GCC_USB4_2_PHY_P2RR2P_PIPE_CLK_SRC] = &gcc_usb4_2_phy_p2rr2p_pipe_clk_src.clkr, + [GCC_USB4_2_PHY_PCIE_PIPE_CLK] = &gcc_usb4_2_phy_pcie_pipe_clk.clkr, + [GCC_USB4_2_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_2_phy_pcie_pipe_clk_src.clkr, + [GCC_USB4_2_PHY_PCIE_PIPE_MUX_CLK_SRC] = &gcc_usb4_2_phy_pcie_pipe_mux_clk_src.clkr, + [GCC_USB4_2_PHY_RX0_CLK] = &gcc_usb4_2_phy_rx0_clk.clkr, + [GCC_USB4_2_PHY_RX0_CLK_SRC] = &gcc_usb4_2_phy_rx0_clk_src.clkr, + [GCC_USB4_2_PHY_RX1_CLK] = &gcc_usb4_2_phy_rx1_clk.clkr, + [GCC_USB4_2_PHY_RX1_CLK_SRC] = &gcc_usb4_2_phy_rx1_clk_src.clkr, + [GCC_USB4_2_PHY_SYS_CLK_SRC] = &gcc_usb4_2_phy_sys_clk_src.clkr, + [GCC_USB4_2_PHY_USB_PIPE_CLK] = &gcc_usb4_2_phy_usb_pipe_clk.clkr, + [GCC_USB4_2_SB_IF_CLK] = &gcc_usb4_2_sb_if_clk.clkr, + [GCC_USB4_2_SB_IF_CLK_SRC] = &gcc_usb4_2_sb_if_clk_src.clkr, + [GCC_USB4_2_SYS_CLK] = &gcc_usb4_2_sys_clk.clkr, + [GCC_USB4_2_TMU_CLK] = &gcc_usb4_2_tmu_clk.clkr, + [GCC_USB4_2_TMU_CLK_SRC] = &gcc_usb4_2_tmu_clk_src.clkr, + [GCC_USB4_2_UC_HRR_CLK] = &gcc_usb4_2_uc_hrr_clk.clkr, + [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, + [GCC_VIDEO_AXI0C_CLK] = &gcc_video_axi0c_clk.clkr, + [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, +}; + +static struct gdsc *gcc_glymur_gdscs[] = { + [GCC_PCIE_0_TUNNEL_GDSC] = &gcc_pcie_0_tunnel_gdsc, + [GCC_PCIE_1_TUNNEL_GDSC] = &gcc_pcie_1_tunnel_gdsc, + [GCC_PCIE_2_TUNNEL_GDSC] = &gcc_pcie_2_tunnel_gdsc, + [GCC_PCIE_3A_GDSC] = &gcc_pcie_3a_gdsc, + [GCC_PCIE_3A_PHY_GDSC] = &gcc_pcie_3a_phy_gdsc, + [GCC_PCIE_3B_GDSC] = &gcc_pcie_3b_gdsc, + [GCC_PCIE_3B_PHY_GDSC] = &gcc_pcie_3b_phy_gdsc, + [GCC_PCIE_4_GDSC] = &gcc_pcie_4_gdsc, + [GCC_PCIE_4_PHY_GDSC] = &gcc_pcie_4_phy_gdsc, + [GCC_PCIE_5_GDSC] = &gcc_pcie_5_gdsc, + [GCC_PCIE_5_PHY_GDSC] = &gcc_pcie_5_phy_gdsc, + [GCC_PCIE_6_GDSC] = &gcc_pcie_6_gdsc, + [GCC_PCIE_6_PHY_GDSC] = &gcc_pcie_6_phy_gdsc, + [GCC_UFS_PHY_GDSC] = &gcc_ufs_phy_gdsc, + [GCC_USB20_PRIM_GDSC] = &gcc_usb20_prim_gdsc, + [GCC_USB30_MP_GDSC] = &gcc_usb30_mp_gdsc, + [GCC_USB30_PRIM_GDSC] = &gcc_usb30_prim_gdsc, + [GCC_USB30_SEC_GDSC] = &gcc_usb30_sec_gdsc, + [GCC_USB30_TERT_GDSC] = &gcc_usb30_tert_gdsc, + [GCC_USB3_MP_SS0_PHY_GDSC] = &gcc_usb3_mp_ss0_phy_gdsc, + [GCC_USB3_MP_SS1_PHY_GDSC] = &gcc_usb3_mp_ss1_phy_gdsc, + [GCC_USB4_0_GDSC] = &gcc_usb4_0_gdsc, + [GCC_USB4_1_GDSC] = &gcc_usb4_1_gdsc, + [GCC_USB4_2_GDSC] = &gcc_usb4_2_gdsc, + [GCC_USB_0_PHY_GDSC] = &gcc_usb_0_phy_gdsc, + [GCC_USB_1_PHY_GDSC] = &gcc_usb_1_phy_gdsc, + [GCC_USB_2_PHY_GDSC] = &gcc_usb_2_phy_gdsc, +}; + +static const struct qcom_reset_map gcc_glymur_resets[] = { + [GCC_AV1E_BCR] = { 0x9b028 }, + [GCC_CAMERA_BCR] = { 0x26000 }, + [GCC_DISPLAY_BCR] = { 0x27000 }, + [GCC_EVA_BCR] = { 0x9b000 }, + [GCC_GPU_BCR] = { 0x71000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0xbc2d0 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0xbc2dc }, + [GCC_PCIE_0_PHY_BCR] = { 0xbc2d8 }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0xbc2e0 }, + [GCC_PCIE_0_TUNNEL_BCR] = { 0xc8000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x7f018 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x7f024 }, + [GCC_PCIE_1_PHY_BCR] = { 0x7f020 }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x7f028 }, + [GCC_PCIE_1_TUNNEL_BCR] = { 0x2e000 }, + [GCC_PCIE_2_LINK_DOWN_BCR] = { 0x281d0 }, + [GCC_PCIE_2_NOCSR_COM_PHY_BCR] = { 0x281dc }, + [GCC_PCIE_2_PHY_BCR] = { 0x281d8 }, + [GCC_PCIE_2_PHY_NOCSR_COM_PHY_BCR] = { 0x281e0 }, + [GCC_PCIE_2_TUNNEL_BCR] = { 0xc0000 }, + [GCC_PCIE_3A_BCR] = { 0xdc000 }, + [GCC_PCIE_3A_LINK_DOWN_BCR] = { 0x7b0a0 }, + [GCC_PCIE_3A_NOCSR_COM_PHY_BCR] = { 0x7b0ac }, + [GCC_PCIE_3A_PHY_BCR] = { 0x6c000 }, + [GCC_PCIE_3A_PHY_NOCSR_COM_PHY_BCR] = { 0x7b0b0 }, + [GCC_PCIE_3B_BCR] = { 0x94000 }, + [GCC_PCIE_3B_LINK_DOWN_BCR] = { 0x7a0c0 }, + [GCC_PCIE_3B_NOCSR_COM_PHY_BCR] = { 0x7a0cc }, + [GCC_PCIE_3B_PHY_BCR] = { 0x75000 }, + [GCC_PCIE_3B_PHY_NOCSR_COM_PHY_BCR] = { 0x7a0c8 }, + [GCC_PCIE_4_BCR] = { 0x88000 }, + [GCC_PCIE_4_LINK_DOWN_BCR] = { 0x980c0 }, + [GCC_PCIE_4_NOCSR_COM_PHY_BCR] = { 0x980cc }, + [GCC_PCIE_4_PHY_BCR] = { 0xd3000 }, + [GCC_PCIE_4_PHY_NOCSR_COM_PHY_BCR] = { 0x980d0 }, + [GCC_PCIE_5_BCR] = { 0xc3000 }, + [GCC_PCIE_5_LINK_DOWN_BCR] = { 0x850c0 }, + [GCC_PCIE_5_NOCSR_COM_PHY_BCR] = { 0x850cc }, + [GCC_PCIE_5_PHY_BCR] = { 0xd2000 }, + [GCC_PCIE_5_PHY_NOCSR_COM_PHY_BCR] = { 0x850d0 }, + [GCC_PCIE_6_BCR] = { 0x8a000 }, + [GCC_PCIE_6_LINK_DOWN_BCR] = { 0x3a0b0 }, + [GCC_PCIE_6_NOCSR_COM_PHY_BCR] = { 0x3a0bc }, + [GCC_PCIE_6_PHY_BCR] = { 0xd4000 }, + [GCC_PCIE_6_PHY_NOCSR_COM_PHY_BCR] = { 0x3a0c0 }, + [GCC_PCIE_NOC_BCR] = { 0xba294 }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x7f00c }, + [GCC_PCIE_PHY_COM_BCR] = { 0x7f010 }, + [GCC_PCIE_RSCC_BCR] = { 0xb8000 }, + [GCC_PDM_BCR] = { 0x33000 }, + [GCC_QUPV3_WRAPPER_0_BCR] = { 0x28000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0xb3000 }, + [GCC_QUPV3_WRAPPER_2_BCR] = { 0xb4000 }, + [GCC_QUPV3_WRAPPER_OOB_BCR] = { 0xe7000 }, + [GCC_QUSB2PHY_HS0_MP_BCR] = { 0xca000 }, + [GCC_QUSB2PHY_HS1_MP_BCR] = { 0xe6000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0xad024 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0xae000 }, + [GCC_QUSB2PHY_TERT_BCR] = { 0xc9000 }, + [GCC_QUSB2PHY_USB20_HS_BCR] = { 0xe9000 }, + [GCC_SDCC2_BCR] = { 0xb0000 }, + [GCC_SDCC4_BCR] = { 0xdf000 }, + [GCC_TCSR_PCIE_BCR] = { 0x281e4 }, + [GCC_UFS_PHY_BCR] = { 0x77004 }, + [GCC_USB20_PRIM_BCR] = { 0xbc000 }, + [GCC_USB30_MP_BCR] = { 0x9a00c }, + [GCC_USB30_PRIM_BCR] = { 0x3f018 }, + [GCC_USB30_SEC_BCR] = { 0xe200c }, + [GCC_USB30_TERT_BCR] = { 0xe100c }, + [GCC_USB3_MP_SS0_PHY_BCR] = { 0x54008 }, + [GCC_USB3_MP_SS1_PHY_BCR] = { 0x54028 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0xdb000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x2c000 }, + [GCC_USB3_PHY_TERT_BCR] = { 0xbe000 }, + [GCC_USB3_UNIPHY_MP0_BCR] = { 0x54000 }, + [GCC_USB3_UNIPHY_MP1_BCR] = { 0x54020 }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0xdb004 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x2c004 }, + [GCC_USB3PHY_PHY_TERT_BCR] = { 0xbe004 }, + [GCC_USB3UNIPHY_PHY_MP0_BCR] = { 0x54004 }, + [GCC_USB3UNIPHY_PHY_MP1_BCR] = { 0x54024 }, + [GCC_USB4_0_BCR] = { 0x2b004 }, + [GCC_USB4_0_DP0_PHY_PRIM_BCR] = { 0xdb010 }, + [GCC_USB4_1_BCR] = { 0x2d004 }, + [GCC_USB4_2_BCR] = { 0xe0004 }, + [GCC_USB_0_PHY_BCR] = { 0xdb020 }, + [GCC_USB_1_PHY_BCR] = { 0x2c020 }, + [GCC_USB_2_PHY_BCR] = { 0xbe020 }, + [GCC_VIDEO_AXI0_CLK_ARES] = { 0x3201c, 2 }, + [GCC_VIDEO_AXI1_CLK_ARES] = { 0x32044, 2 }, + [GCC_VIDEO_BCR] = { 0x32000 }, +}; + +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { + DEFINE_RCG_DFS(gcc_qupv3_oob_qspi_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_oob_qspi_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_qspi_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_qspi_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_qspi_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_qspi_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_qspi_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_qspi_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_qspi_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_qspi_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_qspi_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap2_s7_clk_src), +}; + +static u32 gcc_glymur_critical_cbcrs[] = { + 0x26004, /* GCC_CAMERA_AHB_CLK */ + 0x26040, /* GCC_CAMERA_XO_CLK */ + 0x27004, /* GCC_DISP_AHB_CLK */ + 0x71004, /* GCC_GPU_CFG_AHB_CLK */ + 0x32004, /* GCC_VIDEO_AHB_CLK */ + 0x32058, /* GCC_VIDEO_XO_CLK */ +}; + +static const struct regmap_config gcc_glymur_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1f8ff0, + .fast_io = true, +}; + +static void clk_glymur_regs_configure(struct device *dev, struct regmap *regmap) +{ + /* FORCE_MEM_CORE_ON for ufs phy ice core clocks */ + qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true); +} + +static struct qcom_cc_driver_data gcc_glymur_driver_data = { + .clk_cbcrs = gcc_glymur_critical_cbcrs, + .num_clk_cbcrs = ARRAY_SIZE(gcc_glymur_critical_cbcrs), + .dfs_rcgs = gcc_dfs_clocks, + .num_dfs_rcgs = ARRAY_SIZE(gcc_dfs_clocks), + .clk_regs_configure = clk_glymur_regs_configure, +}; + +static const struct qcom_cc_desc gcc_glymur_desc = { + .config = &gcc_glymur_regmap_config, + .clks = gcc_glymur_clocks, + .num_clks = ARRAY_SIZE(gcc_glymur_clocks), + .resets = gcc_glymur_resets, + .num_resets = ARRAY_SIZE(gcc_glymur_resets), + .gdscs = gcc_glymur_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_glymur_gdscs), + .driver_data = &gcc_glymur_driver_data, +}; + +static const struct of_device_id gcc_glymur_match_table[] = { + { .compatible = "qcom,glymur-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_glymur_match_table); + +static int gcc_glymur_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &gcc_glymur_desc); +} + +static struct platform_driver gcc_glymur_driver = { + .probe = gcc_glymur_probe, + .driver = { + .name = "gcc-glymur", + .of_match_table = gcc_glymur_match_table, + }, +}; + +static int __init gcc_glymur_init(void) +{ + return platform_driver_register(&gcc_glymur_driver); +} +subsys_initcall(gcc_glymur_init); + +static void __exit gcc_glymur_exit(void) +{ + platform_driver_unregister(&gcc_glymur_driver); +} +module_exit(gcc_glymur_exit); + +MODULE_DESCRIPTION("QTI GCC GLYMUR Driver"); +MODULE_LICENSE("GPL"); From 0dcfb6fcdd085bbfcdfdcf64a7d4a75c63c108af Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 4 Sep 2025 08:19:53 +0100 Subject: [PATCH 0800/2711] dt-bindings: clock: renesas,r9a09g077/87: Add Ethernet clock IDs Add clock definitions for Ethernet (ETCLK A-E) to both R9A09G077 and R9A09G087 SoCs. These definitions are required for describing Ethernet devices in DT. Signed-off-by: Lad Prabhakar Acked-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250904071954.3176806-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h | 5 +++++ include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h b/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h index 0c2ce81a8744..2a805e06487b 100644 --- a/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h +++ b/include/dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h @@ -26,5 +26,10 @@ #define R9A09G077_CLK_PCLKL 14 #define R9A09G077_SDHI_CLKHS 15 #define R9A09G077_USB_CLK 16 +#define R9A09G077_ETCLKA 17 +#define R9A09G077_ETCLKB 18 +#define R9A09G077_ETCLKC 19 +#define R9A09G077_ETCLKD 20 +#define R9A09G077_ETCLKE 21 #endif /* __DT_BINDINGS_CLOCK_RENESAS_R9A09G077_CPG_H__ */ diff --git a/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h b/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h index 70ee883f2386..09da0ad33be6 100644 --- a/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h +++ b/include/dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h @@ -26,5 +26,10 @@ #define R9A09G087_CLK_PCLKL 14 #define R9A09G087_SDHI_CLKHS 15 #define R9A09G087_USB_CLK 16 +#define R9A09G087_ETCLKA 17 +#define R9A09G087_ETCLKB 18 +#define R9A09G087_ETCLKC 19 +#define R9A09G087_ETCLKD 20 +#define R9A09G087_ETCLKE 21 #endif /* __DT_BINDINGS_CLOCK_RENESAS_R9A09G087_CPG_H__ */ From 341b0f1b6cba5f4f317f4bb51efa8e9f566ac8e3 Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Wed, 3 Sep 2025 10:27:50 +0200 Subject: [PATCH 0801/2711] clk: renesas: rzg2l: Simplify rzg2l_cpg_assert() and rzg2l_cpg_deassert() Combine common code from rzg2l_cpg_assert() and rzg2l_cpg_deassert() into a new __rzg2l_cpg_assert() helper to avoid code duplication. This reduces maintenance effort and improves code clarity. Reviewed-by: Geert Uytterhoeven Signed-off-by: Tommaso Merciai Link: https://lore.kernel.org/20250903082757.115778-2-tommaso.merciai.xr@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 44 +++++++++++---------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index b508823f9723..e0e1bebd9895 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -1638,8 +1638,8 @@ fail: #define rcdev_to_priv(x) container_of(x, struct rzg2l_cpg_priv, rcdev) -static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev, - unsigned long id) +static int __rzg2l_cpg_assert(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) { struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); const struct rzg2l_cpg_info *info = priv->info; @@ -1647,9 +1647,13 @@ static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev, u32 mask = BIT(info->resets[id].bit); s8 monbit = info->resets[id].monbit; u32 value = mask << 16; + int ret; - dev_dbg(rcdev->dev, "assert id:%ld offset:0x%x\n", id, CLK_RST_R(reg)); + dev_dbg(rcdev->dev, "%s id:%ld offset:0x%x\n", + assert ? "assert" : "deassert", id, CLK_RST_R(reg)); + if (!assert) + value |= mask; writel(value, priv->base + CLK_RST_R(reg)); if (info->has_clk_mon_regs) { @@ -1664,37 +1668,19 @@ static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev, } return readl_poll_timeout_atomic(priv->base + reg, value, - value & mask, 10, 200); + assert == !!(value & mask), 10, 200); +} + +static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return __rzg2l_cpg_assert(rcdev, id, true); } static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev, unsigned long id) { - struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); - const struct rzg2l_cpg_info *info = priv->info; - unsigned int reg = info->resets[id].off; - u32 mask = BIT(info->resets[id].bit); - s8 monbit = info->resets[id].monbit; - u32 value = (mask << 16) | mask; - - dev_dbg(rcdev->dev, "deassert id:%ld offset:0x%x\n", id, - CLK_RST_R(reg)); - - writel(value, priv->base + CLK_RST_R(reg)); - - if (info->has_clk_mon_regs) { - reg = CLK_MRST_R(reg); - } else if (monbit >= 0) { - reg = CPG_RST_MON; - mask = BIT(monbit); - } else { - /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ - udelay(35); - return 0; - } - - return readl_poll_timeout_atomic(priv->base + reg, value, - !(value & mask), 10, 200); + return __rzg2l_cpg_assert(rcdev, id, false); } static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev, From f8c5f0dc77d86da36bcbf0684c6747a2937cc3cd Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Wed, 3 Sep 2025 10:27:51 +0200 Subject: [PATCH 0802/2711] clk: renesas: rzg2l: Re-assert reset on deassert timeout Prevent issues during reset deassertion by re-asserting the reset if a timeout occurs when trying to deassert. This ensures the reset line is in a known state and improves reliability for hardware that may not immediately clear the reset monitor bit. Reviewed-by: Geert Uytterhoeven Signed-off-by: Tommaso Merciai Link: https://lore.kernel.org/20250903082757.115778-3-tommaso.merciai.xr@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index e0e1bebd9895..07909e80bae2 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -1667,8 +1667,14 @@ static int __rzg2l_cpg_assert(struct reset_controller_dev *rcdev, return 0; } - return readl_poll_timeout_atomic(priv->base + reg, value, - assert == !!(value & mask), 10, 200); + ret = readl_poll_timeout_atomic(priv->base + reg, value, + assert == !!(value & mask), 10, 200); + if (ret && !assert) { + value = mask << 16; + writel(value, priv->base + CLK_RST_R(info->resets[id].off)); + } + + return ret; } static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev, From f8c002165ca27d95d3d15e865dd0a47c0a1b14dd Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Wed, 3 Sep 2025 10:27:52 +0200 Subject: [PATCH 0803/2711] clk: renesas: rzv2h: Re-assert reset on deassert timeout Prevent issues during reset deassertion by re-asserting the reset if a timeout occurs when trying to deassert. This ensures the reset line is in a known state and improves reliability for hardware that may not immediately clear the reset monitor bit. Reviewed-by: Geert Uytterhoeven Signed-off-by: Tommaso Merciai Link: https://lore.kernel.org/20250903082757.115778-4-tommaso.merciai.xr@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzv2h-cpg.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c index 58ccbae0f904..35c5ff38e231 100644 --- a/drivers/clk/renesas/rzv2h-cpg.c +++ b/drivers/clk/renesas/rzv2h-cpg.c @@ -854,6 +854,7 @@ static int __rzv2h_cpg_assert(struct reset_controller_dev *rcdev, u32 mask = BIT(priv->resets[id].reset_bit); u8 monbit = priv->resets[id].mon_bit; u32 value = mask << 16; + int ret; dev_dbg(rcdev->dev, "%s id:%ld offset:0x%x\n", assert ? "assert" : "deassert", id, reg); @@ -865,9 +866,15 @@ static int __rzv2h_cpg_assert(struct reset_controller_dev *rcdev, reg = GET_RST_MON_OFFSET(priv->resets[id].mon_index); mask = BIT(monbit); - return readl_poll_timeout_atomic(priv->base + reg, value, - assert ? (value & mask) : !(value & mask), - 10, 200); + ret = readl_poll_timeout_atomic(priv->base + reg, value, + assert ? (value & mask) : !(value & mask), + 10, 200); + if (ret && !assert) { + value = mask << 16; + writel(value, priv->base + GET_RST_OFFSET(priv->resets[id].reset_index)); + } + + return ret; } static int rzv2h_cpg_assert(struct reset_controller_dev *rcdev, From 08eea73dcf608ac7c794550a0ac7303c1ef1f68a Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Wed, 3 Sep 2025 10:27:53 +0200 Subject: [PATCH 0804/2711] clk: renesas: rzv2h: Simplify polling condition in __rzv2h_cpg_assert() Replace the ternary operator with a direct boolean comparison to improve code readability and maintainability. The logic remains unchanged. Signed-off-by: Tommaso Merciai Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250903082757.115778-5-tommaso.merciai.xr@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzv2h-cpg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c index 35c5ff38e231..2197d1d2453a 100644 --- a/drivers/clk/renesas/rzv2h-cpg.c +++ b/drivers/clk/renesas/rzv2h-cpg.c @@ -867,8 +867,7 @@ static int __rzv2h_cpg_assert(struct reset_controller_dev *rcdev, mask = BIT(monbit); ret = readl_poll_timeout_atomic(priv->base + reg, value, - assert ? (value & mask) : !(value & mask), - 10, 200); + assert == !!(value & mask), 10, 200); if (ret && !assert) { value = mask << 16; writel(value, priv->base + GET_RST_OFFSET(priv->resets[id].reset_index)); From 09e3a0467375fe7bb19c66eaf5ad3edfd90ea16c Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 4 Sep 2025 08:19:54 +0100 Subject: [PATCH 0805/2711] clk: renesas: r9a09g077: Add Ethernet Subsystem core and module clocks Add module and core clocks used by Ethernet Subsystem (Ethernet_SS), Ethernet MAC (GMAC), Ethernet Switch (ETHSW). Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20250904071954.3176806-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a09g077-cpg.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r9a09g077-cpg.c b/drivers/clk/renesas/r9a09g077-cpg.c index 1fdd764f9b91..af3ef6d58c87 100644 --- a/drivers/clk/renesas/r9a09g077-cpg.c +++ b/drivers/clk/renesas/r9a09g077-cpg.c @@ -72,7 +72,7 @@ enum rzt2h_clk_types { enum clk_ids { /* Core Clock Outputs exported to DT */ - LAST_DT_CORE_CLK = R9A09G077_USB_CLK, + LAST_DT_CORE_CLK = R9A09G077_ETCLKE, /* External Input Clocks */ CLK_EXTAL, @@ -166,11 +166,18 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = { DEF_DIV("CA55S", R9A09G077_CLK_CA55S, CLK_SEL_CLK_PLL0, DIVCA55S, dtable_1_2), DEF_FIXED("PCLKGPTL", R9A09G077_CLK_PCLKGPTL, CLK_SEL_CLK_PLL1, 2, 1), + DEF_FIXED("PCLKH", R9A09G077_CLK_PCLKH, CLK_SEL_CLK_PLL1, 4, 1), DEF_FIXED("PCLKM", R9A09G077_CLK_PCLKM, CLK_SEL_CLK_PLL1, 8, 1), DEF_FIXED("PCLKL", R9A09G077_CLK_PCLKL, CLK_SEL_CLK_PLL1, 16, 1), + DEF_FIXED("PCLKAH", R9A09G077_CLK_PCLKAH, CLK_PLL4D1, 6, 1), DEF_FIXED("PCLKAM", R9A09G077_CLK_PCLKAM, CLK_PLL4D1, 12, 1), DEF_FIXED("SDHI_CLKHS", R9A09G077_SDHI_CLKHS, CLK_SEL_CLK_PLL2, 1, 1), DEF_FIXED("USB_CLK", R9A09G077_USB_CLK, CLK_PLL4D1, 48, 1), + DEF_FIXED("ETCLKA", R9A09G077_ETCLKA, CLK_SEL_CLK_PLL1, 5, 1), + DEF_FIXED("ETCLKB", R9A09G077_ETCLKB, CLK_SEL_CLK_PLL1, 8, 1), + DEF_FIXED("ETCLKC", R9A09G077_ETCLKC, CLK_SEL_CLK_PLL1, 10, 1), + DEF_FIXED("ETCLKD", R9A09G077_ETCLKD, CLK_SEL_CLK_PLL1, 20, 1), + DEF_FIXED("ETCLKE", R9A09G077_ETCLKE, CLK_SEL_CLK_PLL1, 40, 1), }; static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = { @@ -181,7 +188,12 @@ static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = { DEF_MOD("sci4fck", 12, CLK_SCI4ASYNC), DEF_MOD("iic0", 100, R9A09G077_CLK_PCLKL), DEF_MOD("iic1", 101, R9A09G077_CLK_PCLKL), + DEF_MOD("gmac0", 400, R9A09G077_CLK_PCLKM), + DEF_MOD("ethsw", 401, R9A09G077_CLK_PCLKM), + DEF_MOD("ethss", 403, R9A09G077_CLK_PCLKM), DEF_MOD("usb", 408, R9A09G077_CLK_PCLKAM), + DEF_MOD("gmac1", 416, R9A09G077_CLK_PCLKAM), + DEF_MOD("gmac2", 417, R9A09G077_CLK_PCLKAM), DEF_MOD("sci5fck", 600, CLK_SCI5ASYNC), DEF_MOD("iic2", 601, R9A09G077_CLK_PCLKL), DEF_MOD("sdhi0", 1212, R9A09G077_CLK_PCLKAM), From c778f7ac13d5e94db821cf8e1078aa318cc15460 Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Wed, 3 Sep 2025 13:38:12 -0400 Subject: [PATCH 0806/2711] platform/x86: think-lmi: Add certificate GUID structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a certificate GUID structure to make it easier to add different options for other platforms that need different GUIDs. Suggested-by: Ilpo Järvinen Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20250903173824.1472244-2-mpearson-lenovo@squebb.ca Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/lenovo/think-lmi.c | 29 +++++++++++++++++-------- drivers/platform/x86/lenovo/think-lmi.h | 13 +++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/lenovo/think-lmi.c b/drivers/platform/x86/lenovo/think-lmi.c index 0992b41b6221..de287987f20c 100644 --- a/drivers/platform/x86/lenovo/think-lmi.c +++ b/drivers/platform/x86/lenovo/think-lmi.c @@ -177,6 +177,16 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support"); #define TLMI_CERT_SVC BIT(7) /* Admin Certificate Based */ #define TLMI_CERT_SMC BIT(8) /* System Certificate Based */ +static const struct tlmi_cert_guids thinkpad_cert_guid = { + .thumbprint = LENOVO_CERT_THUMBPRINT_GUID, + .set_bios_setting = LENOVO_SET_BIOS_SETTING_CERT_GUID, + .save_bios_setting = LENOVO_SAVE_BIOS_SETTING_CERT_GUID, + .cert_to_password = LENOVO_CERT_TO_PASSWORD_GUID, + .clear_bios_cert = LENOVO_CLEAR_BIOS_CERT_GUID, + .update_bios_cert = LENOVO_UPDATE_BIOS_CERT_GUID, + .set_bios_cert = LENOVO_SET_BIOS_CERT_GUID, +}; + static const struct tlmi_err_codes tlmi_errs[] = { {"Success", 0}, {"Not Supported", -EOPNOTSUPP}, @@ -668,7 +678,7 @@ static ssize_t cert_thumbprint(char *buf, const char *arg, int count) const union acpi_object *obj; acpi_status status; - status = wmi_evaluate_method(LENOVO_CERT_THUMBPRINT_GUID, 0, 0, &input, &output); + status = wmi_evaluate_method(tlmi_priv.cert_guid->thumbprint, 0, 0, &input, &output); if (ACPI_FAILURE(status)) { kfree(output.pointer); return -EIO; @@ -751,7 +761,7 @@ static ssize_t cert_to_password_store(struct kobject *kobj, kfree_sensitive(passwd); return -ENOMEM; } - ret = tlmi_simple_call(LENOVO_CERT_TO_PASSWORD_GUID, auth_str); + ret = tlmi_simple_call(tlmi_priv.cert_guid->cert_to_password, auth_str); kfree(auth_str); kfree_sensitive(passwd); @@ -774,7 +784,7 @@ static ssize_t certificate_store(struct kobject *kobj, char *auth_str, *new_cert; const char *serial; char *signature; - char *guid; + const char *guid; int ret; if (!capable(CAP_SYS_ADMIN)) @@ -797,7 +807,7 @@ static ssize_t certificate_store(struct kobject *kobj, if (!auth_str) return -ENOMEM; - ret = tlmi_simple_call(LENOVO_CLEAR_BIOS_CERT_GUID, auth_str); + ret = tlmi_simple_call(tlmi_priv.cert_guid->clear_bios_cert, auth_str); kfree(auth_str); return ret ?: count; @@ -834,7 +844,7 @@ static ssize_t certificate_store(struct kobject *kobj, kfree(new_cert); return -EACCES; } - guid = LENOVO_UPDATE_BIOS_CERT_GUID; + guid = tlmi_priv.cert_guid->update_bios_cert; /* Format: 'Certificate,Signature' */ auth_str = cert_command(setting, new_cert, signature); } else { @@ -845,7 +855,7 @@ static ssize_t certificate_store(struct kobject *kobj, kfree(new_cert); return -EACCES; } - guid = LENOVO_SET_BIOS_CERT_GUID; + guid = tlmi_priv.cert_guid->set_bios_cert; /* Format: 'Certificate, password' */ auth_str = cert_command(setting, new_cert, setting->password); } @@ -1071,13 +1081,13 @@ static ssize_t current_value_store(struct kobject *kobj, goto out; } - ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTING_CERT_GUID, set_str); + ret = tlmi_simple_call(tlmi_priv.cert_guid->set_bios_setting, set_str); if (ret) goto out; if (tlmi_priv.save_mode == TLMI_SAVE_BULK) tlmi_priv.save_required = true; else - ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID, + ret = tlmi_simple_call(tlmi_priv.cert_guid->save_bios_setting, tlmi_priv.pwd_admin->save_signature); } else if (tlmi_priv.opcode_support) { /* @@ -1282,7 +1292,7 @@ static ssize_t save_settings_store(struct kobject *kobj, struct kobj_attribute * ret = -EINVAL; goto out; } - ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID, + ret = tlmi_simple_call(tlmi_priv.cert_guid->save_bios_setting, tlmi_priv.pwd_admin->save_signature); if (ret) goto out; @@ -1728,6 +1738,7 @@ static int tlmi_analyze(struct wmi_device *wdev) } if (tlmi_priv.certificate_support) { + tlmi_priv.cert_guid = &thinkpad_cert_guid; tlmi_priv.pwd_admin->cert_installed = tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SVC; tlmi_priv.pwd_system->cert_installed = diff --git a/drivers/platform/x86/lenovo/think-lmi.h b/drivers/platform/x86/lenovo/think-lmi.h index 9b014644d316..59aa03c3f846 100644 --- a/drivers/platform/x86/lenovo/think-lmi.h +++ b/drivers/platform/x86/lenovo/think-lmi.h @@ -41,6 +41,17 @@ enum save_mode { TLMI_SAVE_SAVE, }; +/* GUIDs can differ between platforms */ +struct tlmi_cert_guids { + const char *thumbprint; + const char *set_bios_setting; + const char *save_bios_setting; + const char *cert_to_password; + const char *clear_bios_cert; + const char *update_bios_cert; + const char *set_bios_cert; +}; + /* password configuration details */ #define TLMI_PWDCFG_MODE_LEGACY 0 #define TLMI_PWDCFG_MODE_PASSWORD 1 @@ -121,6 +132,8 @@ struct think_lmi { struct tlmi_pwd_setting *pwd_system; struct tlmi_pwd_setting *pwd_hdd; struct tlmi_pwd_setting *pwd_nvme; + + const struct tlmi_cert_guids *cert_guid; }; #endif /* !_THINK_LMI_H_ */ From 07b93b747cb713478991388b3d55c3ce9267e037 Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Wed, 3 Sep 2025 13:38:13 -0400 Subject: [PATCH 0807/2711] platform/x86: think-lmi: Certificate support for ThinkCenter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ThinkCenter platforms use a different set of GUIDs along with some differences in implementation details for their support of certificate based authentication. Update the think-lmi driver to work correctly on these platforms. Tested on M75q Gen 5. Signed-off-by: Kean Ren Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20250903173824.1472244-3-mpearson-lenovo@squebb.ca Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/lenovo/think-lmi.c | 56 +++++++++++++++++++++---- drivers/platform/x86/lenovo/think-lmi.h | 1 + 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/drivers/platform/x86/lenovo/think-lmi.c b/drivers/platform/x86/lenovo/think-lmi.c index de287987f20c..f2bef523d6ce 100644 --- a/drivers/platform/x86/lenovo/think-lmi.c +++ b/drivers/platform/x86/lenovo/think-lmi.c @@ -119,6 +119,7 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support"); * You must reboot the computer before the changes will take effect. */ #define LENOVO_SET_BIOS_CERT_GUID "26861C9F-47E9-44C4-BD8B-DFE7FA2610FE" +#define LENOVO_TC_SET_BIOS_CERT_GUID "955aaf7d-8bc4-4f04-90aa-97469512f167" /* * Name: UpdateBiosCert @@ -128,6 +129,7 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support"); * You must reboot the computer before the changes will take effect. */ #define LENOVO_UPDATE_BIOS_CERT_GUID "9AA3180A-9750-41F7-B9F7-D5D3B1BAC3CE" +#define LENOVO_TC_UPDATE_BIOS_CERT_GUID "5f5bbbb2-c72f-4fb8-8129-228eef4fdbed" /* * Name: ClearBiosCert @@ -137,6 +139,8 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support"); * You must reboot the computer before the changes will take effect. */ #define LENOVO_CLEAR_BIOS_CERT_GUID "B2BC39A7-78DD-4D71-B059-A510DEC44890" +#define LENOVO_TC_CLEAR_BIOS_CERT_GUID "97849cb6-cb44-42d1-a750-26a596a9eec4" + /* * Name: CertToPassword * Description: Switch from certificate to password authentication. @@ -145,6 +149,7 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support"); * You must reboot the computer before the changes will take effect. */ #define LENOVO_CERT_TO_PASSWORD_GUID "0DE8590D-5510-4044-9621-77C227F5A70D" +#define LENOVO_TC_CERT_TO_PASSWORD_GUID "ef65480d-38c9-420d-b700-ab3d6c8ebaca" /* * Name: SetBiosSettingCert @@ -153,6 +158,7 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support"); * Format: "Item,Value,Signature" */ #define LENOVO_SET_BIOS_SETTING_CERT_GUID "34A008CC-D205-4B62-9E67-31DFA8B90003" +#define LENOVO_TC_SET_BIOS_SETTING_CERT_GUID "19ecba3b-b318-4192-a89b-43d94bc60cea" /* * Name: SaveBiosSettingCert @@ -161,6 +167,7 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support"); * Format: "Signature" */ #define LENOVO_SAVE_BIOS_SETTING_CERT_GUID "C050FB9D-DF5F-4606-B066-9EFC401B2551" +#define LENOVO_TC_SAVE_BIOS_SETTING_CERT_GUID "0afaf46f-7cca-450a-b455-a826a0bf1af5" /* * Name: CertThumbprint @@ -187,6 +194,16 @@ static const struct tlmi_cert_guids thinkpad_cert_guid = { .set_bios_cert = LENOVO_SET_BIOS_CERT_GUID, }; +static const struct tlmi_cert_guids thinkcenter_cert_guid = { + .thumbprint = NULL, + .set_bios_setting = LENOVO_TC_SET_BIOS_SETTING_CERT_GUID, + .save_bios_setting = LENOVO_TC_SAVE_BIOS_SETTING_CERT_GUID, + .cert_to_password = LENOVO_TC_CERT_TO_PASSWORD_GUID, + .clear_bios_cert = LENOVO_TC_CLEAR_BIOS_CERT_GUID, + .update_bios_cert = LENOVO_TC_UPDATE_BIOS_CERT_GUID, + .set_bios_cert = LENOVO_TC_SET_BIOS_CERT_GUID, +}; + static const struct tlmi_err_codes tlmi_errs[] = { {"Success", 0}, {"Not Supported", -EOPNOTSUPP}, @@ -678,6 +695,9 @@ static ssize_t cert_thumbprint(char *buf, const char *arg, int count) const union acpi_object *obj; acpi_status status; + if (!tlmi_priv.cert_guid->thumbprint) + return -EOPNOTSUPP; + status = wmi_evaluate_method(tlmi_priv.cert_guid->thumbprint, 0, 0, &input, &output); if (ACPI_FAILURE(status)) { kfree(output.pointer); @@ -856,8 +876,16 @@ static ssize_t certificate_store(struct kobject *kobj, return -EACCES; } guid = tlmi_priv.cert_guid->set_bios_cert; - /* Format: 'Certificate, password' */ - auth_str = cert_command(setting, new_cert, setting->password); + if (tlmi_priv.thinkcenter_mode) { + /* Format: 'Certificate, password, encoding, kbdlang' */ + auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s,%s", new_cert, + setting->password, + encoding_options[setting->encoding], + setting->kbdlang); + } else { + /* Format: 'Certificate, password' */ + auth_str = cert_command(setting, new_cert, setting->password); + } } kfree(new_cert); if (!auth_str) @@ -1593,6 +1621,15 @@ static int tlmi_analyze(struct wmi_device *wdev) wmi_has_guid(LENOVO_SAVE_BIOS_SETTING_CERT_GUID)) tlmi_priv.certificate_support = true; + /* ThinkCenter uses different GUIDs for certificate support */ + if (wmi_has_guid(LENOVO_TC_SET_BIOS_CERT_GUID) && + wmi_has_guid(LENOVO_TC_SET_BIOS_SETTING_CERT_GUID) && + wmi_has_guid(LENOVO_TC_SAVE_BIOS_SETTING_CERT_GUID)) { + tlmi_priv.certificate_support = true; + tlmi_priv.thinkcenter_mode = true; + pr_info("ThinkCenter modified support being used\n"); + } + /* * Try to find the number of valid settings of this machine * and use it to create sysfs attributes. @@ -1738,11 +1775,16 @@ static int tlmi_analyze(struct wmi_device *wdev) } if (tlmi_priv.certificate_support) { - tlmi_priv.cert_guid = &thinkpad_cert_guid; - tlmi_priv.pwd_admin->cert_installed = - tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SVC; - tlmi_priv.pwd_system->cert_installed = - tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SMC; + if (tlmi_priv.thinkcenter_mode) { + tlmi_priv.cert_guid = &thinkcenter_cert_guid; + tlmi_priv.pwd_admin->cert_installed = tlmi_priv.pwdcfg.core.password_mode; + } else { + tlmi_priv.cert_guid = &thinkpad_cert_guid; + tlmi_priv.pwd_admin->cert_installed = + tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SVC; + tlmi_priv.pwd_system->cert_installed = + tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SMC; + } } return 0; diff --git a/drivers/platform/x86/lenovo/think-lmi.h b/drivers/platform/x86/lenovo/think-lmi.h index 59aa03c3f846..017644323d46 100644 --- a/drivers/platform/x86/lenovo/think-lmi.h +++ b/drivers/platform/x86/lenovo/think-lmi.h @@ -120,6 +120,7 @@ struct think_lmi { enum save_mode save_mode; bool save_required; bool reboot_required; + bool thinkcenter_mode; struct tlmi_attr_setting *setting[TLMI_SETTINGS_COUNT]; struct device *class_dev; From a0d6959c345d89d811288a718e3f6b145dcadc8c Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Wed, 3 Sep 2025 13:38:14 -0400 Subject: [PATCH 0808/2711] platform/x86: think-lmi: Add extra TC BIOS error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add extra error messages that are used by ThinkCenter platforms. Signed-off-by: Kean Ren Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20250903173824.1472244-4-mpearson-lenovo@squebb.ca Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/lenovo/think-lmi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/platform/x86/lenovo/think-lmi.c b/drivers/platform/x86/lenovo/think-lmi.c index f2bef523d6ce..540b472b1bf3 100644 --- a/drivers/platform/x86/lenovo/think-lmi.c +++ b/drivers/platform/x86/lenovo/think-lmi.c @@ -206,10 +206,21 @@ static const struct tlmi_cert_guids thinkcenter_cert_guid = { static const struct tlmi_err_codes tlmi_errs[] = { {"Success", 0}, + {"Set Certificate operation was successful.", 0}, {"Not Supported", -EOPNOTSUPP}, {"Invalid Parameter", -EINVAL}, {"Access Denied", -EACCES}, {"System Busy", -EBUSY}, + {"Set Certificate operation failed with status:Invalid Parameter.", -EINVAL}, + {"Set Certificate operation failed with status:Invalid certificate type.", -EINVAL}, + {"Set Certificate operation failed with status:Invalid password format.", -EINVAL}, + {"Set Certificate operation failed with status:Password retry count exceeded.", -EACCES}, + {"Set Certificate operation failed with status:Password Invalid.", -EACCES}, + {"Set Certificate operation failed with status:Operation aborted.", -EBUSY}, + {"Set Certificate operation failed with status:No free slots to write.", -ENOSPC}, + {"Set Certificate operation failed with status:Certificate not found.", -EEXIST}, + {"Set Certificate operation failed with status:Internal error.", -EFAULT}, + {"Set Certificate operation failed with status:Certificate too large.", -EFBIG}, }; static const char * const encoding_options[] = { From a191224186ec16a4cb1775b2a647ea91f5c139e1 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 3 Sep 2025 12:11:54 -0700 Subject: [PATCH 0809/2711] platform/x86/intel-uncore-freq: Present unique domain ID per package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In partitioned systems, the domain ID is unique in the partition and a package can have multiple partitions. Some user-space tools, such as turbostat, assume the domain ID is unique per package. These tools map CPU power domains, which are unique to a package. However, this approach does not work in partitioned systems. There is no architectural definition of "partition" to present to user space. To support these tools, set the domain_id to be unique per package. For compute die IDs, uniqueness can be achieved using the platform info cdie_mask, mirroring the behavior observed in non-partitioned systems. For IO dies, which lack a direct CPU relationship, any unique logical ID can be assigned. Here domain IDs for IO dies are configured after all compute domain IDs. During the probe, keep the index of the next IO domain ID after the last IO domain ID of the current partition. Since CPU packages are symmetric, partition information is same for all packages. The Intel Speed Select driver has already implemented a similar change to make the domain ID unique, with compute dies listed first, followed by I/O dies. Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20250903191154.1081159-1-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../uncore-frequency/uncore-frequency-tpmi.c | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index cb4905bad89b..8007ad7c88da 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -369,6 +369,77 @@ static void uncore_set_agent_type(struct tpmi_uncore_cluster_info *cluster_info) cluster_info->uncore_data.agent_type_mask = FIELD_GET(UNCORE_AGENT_TYPES, status); } +#define MAX_PARTITIONS 2 + +/* IO domain ID start index for a partition */ +static u8 io_die_start[MAX_PARTITIONS]; + +/* Next IO domain ID index after the current partition IO die IDs */ +static u8 io_die_index_next; + +/* Lock to protect io_die_start, io_die_index_next */ +static DEFINE_MUTEX(domain_lock); + +static void set_domain_id(int id, int num_resources, + struct oobmsm_plat_info *plat_info, + struct tpmi_uncore_cluster_info *cluster_info) +{ + u8 part_io_index, cdie_range, pkg_io_index, max_dies; + + if (plat_info->partition >= MAX_PARTITIONS) { + cluster_info->uncore_data.domain_id = id; + return; + } + + if (cluster_info->uncore_data.agent_type_mask & AGENT_TYPE_CORE) { + cluster_info->uncore_data.domain_id = cluster_info->cdie_id; + return; + } + + /* Unlikely but cdie_mask may have holes, so take range */ + cdie_range = fls(plat_info->cdie_mask) - ffs(plat_info->cdie_mask) + 1; + max_dies = topology_max_dies_per_package(); + + /* + * If the CPU doesn't enumerate dies, then use current cdie range + * as the max. + */ + if (cdie_range > max_dies) + max_dies = cdie_range; + + guard(mutex)(&domain_lock); + + if (!io_die_index_next) + io_die_index_next = max_dies; + + if (!io_die_start[plat_info->partition]) { + io_die_start[plat_info->partition] = io_die_index_next; + /* + * number of IO dies = num_resources - cdie_range. Hence + * next partition io_die_index_next is set after IO dies + * in the current partition. + */ + io_die_index_next += (num_resources - cdie_range); + } + + /* + * Index from IO die start within the partition: + * This is the first valid domain after the cdies. + * For example the current resource index 5 and cdies end at + * index 3 (cdie_cnt = 4). Then the IO only index 5 - 4 = 1. + */ + part_io_index = id - cdie_range; + + /* + * Add to the IO die start index for this partition in this package + * to make unique in the package. + */ + pkg_io_index = io_die_start[plat_info->partition] + part_io_index; + + /* Assign this to domain ID */ + cluster_info->uncore_data.domain_id = pkg_io_index; +} + /* Callback for sysfs read for TPMI uncore values. Called under mutex locks. */ static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncore_index index) { @@ -605,11 +676,12 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ cluster_info->uncore_data.package_id = pkg; /* There are no dies like Cascade Lake */ cluster_info->uncore_data.die_id = 0; - cluster_info->uncore_data.domain_id = i; cluster_info->uncore_data.cluster_id = j; set_cdie_id(i, cluster_info, plat_info); + set_domain_id(i, num_resources, plat_info, cluster_info); + cluster_info->uncore_root = tpmi_uncore; if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >= UNCORE_ELC_SUPPORTED_VERSION) From f490253809c8dab4af62e787f5a3ac3d22aa869c Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Thu, 28 Aug 2025 20:26:48 +0800 Subject: [PATCH 0810/2711] platform/x86/amd/pmf: Remove redundant ternary operators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For ternary operators in the form of "a ? true : false", if 'a' itself returns a boolean result, the ternary operator can be omitted. Remove redundant ternary operators to clean up the code. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250828122649.39574-1-liaoyuanhong@vivo.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/pmf/sps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c index 49e14ca94a9e..c28f3c5744c2 100644 --- a/drivers/platform/x86/amd/pmf/sps.c +++ b/drivers/platform/x86/amd/pmf/sps.c @@ -283,7 +283,7 @@ int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf) bool is_pprof_balanced(struct amd_pmf_dev *pmf) { - return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false; + return pmf->current_profile == PLATFORM_PROFILE_BALANCED; } static int amd_pmf_profile_get(struct device *dev, From d923b9682e12bb63b8a1353110e67869a9bd0ba8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 20 Aug 2025 14:48:22 +0200 Subject: [PATCH 0811/2711] clk: qcom: milos: Constify 'struct qcom_cc_desc' 'struct qcom_cc_desc' is passed to qcom_cc_map() and qcom_cc_really_probe() only as pointer to const, so make the memory const for safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250820124821.149141-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/camcc-milos.c | 2 +- drivers/clk/qcom/dispcc-milos.c | 2 +- drivers/clk/qcom/videocc-milos.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/qcom/camcc-milos.c b/drivers/clk/qcom/camcc-milos.c index 75bd939f7dd1..0077c9c9249f 100644 --- a/drivers/clk/qcom/camcc-milos.c +++ b/drivers/clk/qcom/camcc-milos.c @@ -2124,7 +2124,7 @@ static struct qcom_cc_driver_data cam_cc_milos_driver_data = { .num_clk_cbcrs = ARRAY_SIZE(cam_cc_milos_critical_cbcrs), }; -static struct qcom_cc_desc cam_cc_milos_desc = { +static const struct qcom_cc_desc cam_cc_milos_desc = { .config = &cam_cc_milos_regmap_config, .clks = cam_cc_milos_clocks, .num_clks = ARRAY_SIZE(cam_cc_milos_clocks), diff --git a/drivers/clk/qcom/dispcc-milos.c b/drivers/clk/qcom/dispcc-milos.c index 602d3a498d33..95b6dd89d9ae 100644 --- a/drivers/clk/qcom/dispcc-milos.c +++ b/drivers/clk/qcom/dispcc-milos.c @@ -937,7 +937,7 @@ static struct qcom_cc_driver_data disp_cc_milos_driver_data = { .clk_regs_configure = disp_cc_milos_clk_regs_configure, }; -static struct qcom_cc_desc disp_cc_milos_desc = { +static const struct qcom_cc_desc disp_cc_milos_desc = { .config = &disp_cc_milos_regmap_config, .clks = disp_cc_milos_clocks, .num_clks = ARRAY_SIZE(disp_cc_milos_clocks), diff --git a/drivers/clk/qcom/videocc-milos.c b/drivers/clk/qcom/videocc-milos.c index 998301e0ba88..acc9df295d4f 100644 --- a/drivers/clk/qcom/videocc-milos.c +++ b/drivers/clk/qcom/videocc-milos.c @@ -366,7 +366,7 @@ static struct qcom_cc_driver_data video_cc_milos_driver_data = { .num_clk_cbcrs = ARRAY_SIZE(video_cc_milos_critical_cbcrs), }; -static struct qcom_cc_desc video_cc_milos_desc = { +static const struct qcom_cc_desc video_cc_milos_desc = { .config = &video_cc_milos_regmap_config, .clks = video_cc_milos_clocks, .num_clks = ARRAY_SIZE(video_cc_milos_clocks), From 0e56e3369b60506ac030546c8a63a1aef153d486 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 28 Aug 2025 20:38:21 -0400 Subject: [PATCH 0812/2711] clk: qcom: alpha-pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Note that prior to running the Coccinelle, clk_alpha_pll_postdiv_round_ro_rate() was renamed to clk_alpha_pll_postdiv_ro_round_rate(). Reviewed-by: Konrad Dybcio Signed-off-by: Brian Masney Link: https://lore.kernel.org/r/20250828-clk-round-rate-v2-v1-2-b97ec8ba6cc4@redhat.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-alpha-pll.c | 136 +++++++++++++++++-------------- 1 file changed, 77 insertions(+), 59 deletions(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 81a1ce42285f..6aeba40358c1 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -849,22 +849,25 @@ static int clk_alpha_pll_hwfsm_set_rate(struct clk_hw *hw, unsigned long rate, clk_alpha_pll_hwfsm_is_enabled); } -static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_alpha_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 l, alpha_width = pll_alpha_width(pll); u64 a; unsigned long min_freq, max_freq; - rate = alpha_pll_round_rate(rate, *prate, &l, &a, alpha_width); - if (!pll->vco_table || alpha_pll_find_vco(pll, rate)) - return rate; + req->rate = alpha_pll_round_rate(req->rate, req->best_parent_rate, &l, + &a, alpha_width); + if (!pll->vco_table || alpha_pll_find_vco(pll, req->rate)) + return 0; min_freq = pll->vco_table[0].min_freq; max_freq = pll->vco_table[pll->num_vco - 1].max_freq; - return clamp(rate, min_freq, max_freq); + req->rate = clamp(req->rate, min_freq, max_freq); + + return 0; } void clk_huayra_2290_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, @@ -1048,12 +1051,15 @@ static int alpha_pll_huayra_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static long alpha_pll_huayra_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int alpha_pll_huayra_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u32 l, a; - return alpha_huayra_pll_round_rate(rate, *prate, &l, &a); + req->rate = alpha_huayra_pll_round_rate(req->rate, + req->best_parent_rate, &l, &a); + + return 0; } static int trion_pll_is_enabled(struct clk_alpha_pll *pll, @@ -1175,7 +1181,7 @@ const struct clk_ops clk_alpha_pll_ops = { .disable = clk_alpha_pll_disable, .is_enabled = clk_alpha_pll_is_enabled, .recalc_rate = clk_alpha_pll_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = clk_alpha_pll_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_ops); @@ -1185,7 +1191,7 @@ const struct clk_ops clk_alpha_pll_huayra_ops = { .disable = clk_alpha_pll_disable, .is_enabled = clk_alpha_pll_is_enabled, .recalc_rate = alpha_pll_huayra_recalc_rate, - .round_rate = alpha_pll_huayra_round_rate, + .determine_rate = alpha_pll_huayra_determine_rate, .set_rate = alpha_pll_huayra_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_huayra_ops); @@ -1195,7 +1201,7 @@ const struct clk_ops clk_alpha_pll_hwfsm_ops = { .disable = clk_alpha_pll_hwfsm_disable, .is_enabled = clk_alpha_pll_hwfsm_is_enabled, .recalc_rate = clk_alpha_pll_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = clk_alpha_pll_hwfsm_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops); @@ -1205,7 +1211,7 @@ const struct clk_ops clk_alpha_pll_fixed_trion_ops = { .disable = clk_trion_pll_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = clk_trion_pll_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_trion_ops); @@ -1240,9 +1246,8 @@ static const struct clk_div_table clk_alpha_2bit_div_table[] = { { } }; -static long -clk_alpha_pll_postdiv_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_alpha_pll_postdiv_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); const struct clk_div_table *table; @@ -1252,13 +1257,15 @@ clk_alpha_pll_postdiv_round_rate(struct clk_hw *hw, unsigned long rate, else table = clk_alpha_div_table; - return divider_round_rate(hw, rate, prate, table, - pll->width, CLK_DIVIDER_POWER_OF_TWO); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + table, pll->width, + CLK_DIVIDER_POWER_OF_TWO); + + return 0; } -static long -clk_alpha_pll_postdiv_round_ro_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_alpha_pll_postdiv_ro_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); u32 ctl, div; @@ -1270,9 +1277,12 @@ clk_alpha_pll_postdiv_round_ro_rate(struct clk_hw *hw, unsigned long rate, div = 1 << fls(ctl); if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) - *prate = clk_hw_round_rate(clk_hw_get_parent(hw), div * rate); + req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), + div * req->rate); - return DIV_ROUND_UP_ULL((u64)*prate, div); + req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div); + + return 0; } static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, @@ -1291,13 +1301,13 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops clk_alpha_pll_postdiv_ops = { .recalc_rate = clk_alpha_pll_postdiv_recalc_rate, - .round_rate = clk_alpha_pll_postdiv_round_rate, + .determine_rate = clk_alpha_pll_postdiv_determine_rate, .set_rate = clk_alpha_pll_postdiv_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_ops); const struct clk_ops clk_alpha_pll_postdiv_ro_ops = { - .round_rate = clk_alpha_pll_postdiv_round_ro_rate, + .determine_rate = clk_alpha_pll_postdiv_ro_determine_rate, .recalc_rate = clk_alpha_pll_postdiv_recalc_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_ro_ops); @@ -1542,7 +1552,7 @@ const struct clk_ops clk_alpha_pll_fabia_ops = { .is_enabled = clk_alpha_pll_is_enabled, .set_rate = alpha_pll_fabia_set_rate, .recalc_rate = alpha_pll_fabia_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_fabia_ops); @@ -1551,7 +1561,7 @@ const struct clk_ops clk_alpha_pll_fixed_fabia_ops = { .disable = alpha_pll_fabia_disable, .is_enabled = clk_alpha_pll_is_enabled, .recalc_rate = alpha_pll_fabia_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_fabia_ops); @@ -1602,14 +1612,16 @@ clk_trion_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return (parent_rate / div); } -static long -clk_trion_pll_postdiv_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_trion_pll_postdiv_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); - return divider_round_rate(hw, rate, prate, pll->post_div_table, - pll->width, CLK_DIVIDER_ROUND_CLOSEST); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + pll->post_div_table, + pll->width, CLK_DIVIDER_ROUND_CLOSEST); + + return 0; }; static int @@ -1635,18 +1647,21 @@ clk_trion_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops clk_alpha_pll_postdiv_trion_ops = { .recalc_rate = clk_trion_pll_postdiv_recalc_rate, - .round_rate = clk_trion_pll_postdiv_round_rate, + .determine_rate = clk_trion_pll_postdiv_determine_rate, .set_rate = clk_trion_pll_postdiv_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_trion_ops); -static long clk_alpha_pll_postdiv_fabia_round_rate(struct clk_hw *hw, - unsigned long rate, unsigned long *prate) +static int clk_alpha_pll_postdiv_fabia_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); - return divider_round_rate(hw, rate, prate, pll->post_div_table, - pll->width, CLK_DIVIDER_ROUND_CLOSEST); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + pll->post_div_table, + pll->width, CLK_DIVIDER_ROUND_CLOSEST); + + return 0; } static int clk_alpha_pll_postdiv_fabia_set_rate(struct clk_hw *hw, @@ -1681,7 +1696,7 @@ static int clk_alpha_pll_postdiv_fabia_set_rate(struct clk_hw *hw, const struct clk_ops clk_alpha_pll_postdiv_fabia_ops = { .recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate, - .round_rate = clk_alpha_pll_postdiv_fabia_round_rate, + .determine_rate = clk_alpha_pll_postdiv_fabia_determine_rate, .set_rate = clk_alpha_pll_postdiv_fabia_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops); @@ -1833,7 +1848,7 @@ const struct clk_ops clk_alpha_pll_trion_ops = { .disable = clk_trion_pll_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = clk_trion_pll_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = alpha_pll_trion_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_trion_ops); @@ -1844,14 +1859,14 @@ const struct clk_ops clk_alpha_pll_lucid_ops = { .disable = clk_trion_pll_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = clk_trion_pll_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = alpha_pll_trion_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_ops); const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = { .recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate, - .round_rate = clk_alpha_pll_postdiv_fabia_round_rate, + .determine_rate = clk_alpha_pll_postdiv_fabia_determine_rate, .set_rate = clk_alpha_pll_postdiv_fabia_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_lucid_ops); @@ -1903,7 +1918,7 @@ const struct clk_ops clk_alpha_pll_agera_ops = { .disable = clk_alpha_pll_disable, .is_enabled = clk_alpha_pll_is_enabled, .recalc_rate = alpha_pll_fabia_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = clk_alpha_pll_agera_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_agera_ops); @@ -2119,7 +2134,7 @@ const struct clk_ops clk_alpha_pll_lucid_5lpe_ops = { .disable = alpha_pll_lucid_5lpe_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = clk_trion_pll_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = alpha_pll_lucid_5lpe_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_5lpe_ops); @@ -2129,13 +2144,13 @@ const struct clk_ops clk_alpha_pll_fixed_lucid_5lpe_ops = { .disable = alpha_pll_lucid_5lpe_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = clk_trion_pll_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_lucid_5lpe_ops); const struct clk_ops clk_alpha_pll_postdiv_lucid_5lpe_ops = { .recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate, - .round_rate = clk_alpha_pll_postdiv_fabia_round_rate, + .determine_rate = clk_alpha_pll_postdiv_fabia_determine_rate, .set_rate = clk_lucid_5lpe_pll_postdiv_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_lucid_5lpe_ops); @@ -2304,7 +2319,7 @@ const struct clk_ops clk_alpha_pll_zonda_ops = { .disable = clk_zonda_pll_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = clk_trion_pll_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = clk_zonda_pll_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_zonda_ops); @@ -2529,13 +2544,13 @@ const struct clk_ops clk_alpha_pll_fixed_lucid_evo_ops = { .disable = alpha_pll_lucid_evo_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = alpha_pll_lucid_evo_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_lucid_evo_ops); const struct clk_ops clk_alpha_pll_postdiv_lucid_evo_ops = { .recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate, - .round_rate = clk_alpha_pll_postdiv_fabia_round_rate, + .determine_rate = clk_alpha_pll_postdiv_fabia_determine_rate, .set_rate = clk_lucid_evo_pll_postdiv_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_lucid_evo_ops); @@ -2546,7 +2561,7 @@ const struct clk_ops clk_alpha_pll_lucid_evo_ops = { .disable = alpha_pll_lucid_evo_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = alpha_pll_lucid_evo_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = alpha_pll_lucid_5lpe_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_evo_ops); @@ -2557,7 +2572,7 @@ const struct clk_ops clk_alpha_pll_reset_lucid_evo_ops = { .disable = alpha_pll_reset_lucid_evo_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = alpha_pll_lucid_evo_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = alpha_pll_lucid_5lpe_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_reset_lucid_evo_ops); @@ -2732,22 +2747,25 @@ static unsigned long clk_rivian_evo_pll_recalc_rate(struct clk_hw *hw, return parent_rate * l; } -static long clk_rivian_evo_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_rivian_evo_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); unsigned long min_freq, max_freq; u32 l; u64 a; - rate = alpha_pll_round_rate(rate, *prate, &l, &a, 0); - if (!pll->vco_table || alpha_pll_find_vco(pll, rate)) - return rate; + req->rate = alpha_pll_round_rate(req->rate, req->best_parent_rate, &l, + &a, 0); + if (!pll->vco_table || alpha_pll_find_vco(pll, req->rate)) + return 0; min_freq = pll->vco_table[0].min_freq; max_freq = pll->vco_table[pll->num_vco - 1].max_freq; - return clamp(rate, min_freq, max_freq); + req->rate = clamp(req->rate, min_freq, max_freq); + + return 0; } const struct clk_ops clk_alpha_pll_rivian_evo_ops = { @@ -2755,7 +2773,7 @@ const struct clk_ops clk_alpha_pll_rivian_evo_ops = { .disable = alpha_pll_lucid_5lpe_disable, .is_enabled = clk_trion_pll_is_enabled, .recalc_rate = clk_rivian_evo_pll_recalc_rate, - .round_rate = clk_rivian_evo_pll_round_rate, + .determine_rate = clk_rivian_evo_pll_determine_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_rivian_evo_ops); @@ -2964,7 +2982,7 @@ const struct clk_ops clk_alpha_pll_regera_ops = { .disable = clk_zonda_pll_disable, .is_enabled = clk_alpha_pll_is_enabled, .recalc_rate = clk_trion_pll_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = clk_zonda_pll_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_regera_ops); @@ -3169,7 +3187,7 @@ const struct clk_ops clk_alpha_pll_slew_ops = { .enable = clk_alpha_pll_slew_enable, .disable = clk_alpha_pll_disable, .recalc_rate = clk_alpha_pll_recalc_rate, - .round_rate = clk_alpha_pll_round_rate, + .determine_rate = clk_alpha_pll_determine_rate, .set_rate = clk_alpha_pll_slew_set_rate, }; EXPORT_SYMBOL(clk_alpha_pll_slew_ops); From 1e50f5c9965252ed6657b8692cd7366784d60616 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 2 Sep 2025 09:33:36 +0300 Subject: [PATCH 0813/2711] clk: qcom: common: Fix NULL vs IS_ERR() check in qcom_cc_icc_register() The devm_clk_hw_get_clk() function doesn't return NULL, it returns error pointers. Update the checking to match. Fixes: 8737ec830ee3 ("clk: qcom: common: Add interconnect clocks support") Signed-off-by: Dan Carpenter Reviewed-by: Imran Shaik Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/aLaPwL2gFS85WsfD@stanley.mountain Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index 37c3008e6c1b..121591886774 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -277,8 +277,8 @@ static int qcom_cc_icc_register(struct device *dev, icd[i].slave_id = desc->icc_hws[i].slave_id; hws = &desc->clks[desc->icc_hws[i].clk_id]->hw; icd[i].clk = devm_clk_hw_get_clk(dev, hws, "icc"); - if (!icd[i].clk) - return dev_err_probe(dev, -ENOENT, + if (IS_ERR(icd[i].clk)) + return dev_err_probe(dev, PTR_ERR(icd[i].clk), "(%d) clock entry is null\n", i); icd[i].name = clk_hw_get_name(hws); } From 9524f95c4042545ee8fc3191b9b89c61a1aca6fb Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Tue, 2 Sep 2025 14:17:54 +0200 Subject: [PATCH 0814/2711] clk: qcom: Select the intended config in QCS_DISPCC_615 Commit 9b47105f5434 ("clk: qcom: dispcc-qcs615: Add QCS615 display clock controller driver") adds the config QCS_DISPCC_615, which selects the non-existing config QCM_GCC_615. Probably, this is just a three-letter abbreviation mix-up here, though. There is a config named QCS_GCC_615, and the related config QCS_CAMCC_615 selects that config. Fix the typo and use the intended config name in the select command. Fixes: 9b47105f5434 ("clk: qcom: dispcc-qcs615: Add QCS615 display clock controller driver") Signed-off-by: Lukas Bulwahn Reviewed-by: Imran Shaik Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250902121754.277452-1-lukas.bulwahn@redhat.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 1dbb254de8be..580a64754f1d 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -531,7 +531,7 @@ config QCM_DISPCC_2290 config QCS_DISPCC_615 tristate "QCS615 Display Clock Controller" - select QCM_GCC_615 + select QCS_GCC_615 help Support for the display clock controller on Qualcomm Technologies, Inc QCS615 devices. From 4d32c1f66a768dd281edadbd244dce1c63c0899d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20Cz=C3=A9m=C3=A1n?= Date: Wed, 3 Sep 2025 23:08:21 +0200 Subject: [PATCH 0815/2711] dt-bindings: clock: qcom: Add MSM8937 Global Clock Controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add device tree bindings for the global clock controller on Qualcomm MSM8937 platform. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Barnabás Czémán Link: https://lore.kernel.org/r/20250903-msm8937-v9-1-a097c91c5801@mainlining.org Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,gcc-msm8953.yaml | 11 ++++++++--- include/dt-bindings/clock/qcom,gcc-msm8917.h | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml index fe1f5f3ed992..f2e37f439d28 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-msm8953.yaml @@ -9,16 +9,21 @@ title: Qualcomm Global Clock & Reset Controller on MSM8953 maintainers: - Adam Skladowski - Sireesh Kodali + - Barnabas Czeman description: | Qualcomm global clock control module provides the clocks, resets and power - domains on MSM8953. + domains on MSM8937 or MSM8953. - See also: include/dt-bindings/clock/qcom,gcc-msm8953.h + See also:: + include/dt-bindings/clock/qcom,gcc-msm8917.h + include/dt-bindings/clock/qcom,gcc-msm8953.h properties: compatible: - const: qcom,gcc-msm8953 + enum: + - qcom,gcc-msm8937 + - qcom,gcc-msm8953 clocks: items: diff --git a/include/dt-bindings/clock/qcom,gcc-msm8917.h b/include/dt-bindings/clock/qcom,gcc-msm8917.h index 4b421e7414b5..4e3897b3669d 100644 --- a/include/dt-bindings/clock/qcom,gcc-msm8917.h +++ b/include/dt-bindings/clock/qcom,gcc-msm8917.h @@ -170,6 +170,23 @@ #define VFE1_CLK_SRC 163 #define VSYNC_CLK_SRC 164 #define GPLL0_SLEEP_CLK_SRC 165 +/* Addtional MSM8937-specific clocks */ +#define MSM8937_BLSP1_QUP1_I2C_APPS_CLK_SRC 166 +#define MSM8937_BLSP1_QUP1_SPI_APPS_CLK_SRC 167 +#define MSM8937_BLSP2_QUP4_I2C_APPS_CLK_SRC 168 +#define MSM8937_BLSP2_QUP4_SPI_APPS_CLK_SRC 169 +#define MSM8937_BYTE1_CLK_SRC 170 +#define MSM8937_ESC1_CLK_SRC 171 +#define MSM8937_PCLK1_CLK_SRC 172 +#define MSM8937_GCC_BLSP1_QUP1_I2C_APPS_CLK 173 +#define MSM8937_GCC_BLSP1_QUP1_SPI_APPS_CLK 174 +#define MSM8937_GCC_BLSP2_QUP4_I2C_APPS_CLK 175 +#define MSM8937_GCC_BLSP2_QUP4_SPI_APPS_CLK 176 +#define MSM8937_GCC_MDSS_BYTE1_CLK 177 +#define MSM8937_GCC_MDSS_ESC1_CLK 178 +#define MSM8937_GCC_MDSS_PCLK1_CLK 179 +#define MSM8937_GCC_OXILI_AON_CLK 180 +#define MSM8937_GCC_OXILI_TIMER_CLK 181 /* GCC block resets */ #define GCC_CAMSS_MICRO_BCR 0 @@ -187,5 +204,7 @@ #define VENUS_GDSC 5 #define VFE0_GDSC 6 #define VFE1_GDSC 7 +/* Additional MSM8937-specific GDSCs */ +#define MSM8937_OXILI_CX_GDSC 8 #endif From 6be1f55f33f615c3cafee96bc514a74a9fa43885 Mon Sep 17 00:00:00 2001 From: Daniil Titov Date: Wed, 3 Sep 2025 23:08:22 +0200 Subject: [PATCH 0816/2711] clk: qcom: gcc: Add support for Global Clock controller found on MSM8937 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modify existing MSM8917 driver to support MSM8937 SoC. Override frequencies which are different in this chip. Register all the clocks to the framework for the clients to be able to request for them. Add new variant of GDSC for new chip. Signed-off-by: Daniil Titov Reviewed-by: Dmitry Baryshkov Signed-off-by: Barnabás Czémán Link: https://lore.kernel.org/r/20250903-msm8937-v9-2-a097c91c5801@mainlining.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 6 +- drivers/clk/qcom/gcc-msm8917.c | 617 ++++++++++++++++++++++++++++++++- 2 files changed, 616 insertions(+), 7 deletions(-) diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 580a64754f1d..78a303842613 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -359,12 +359,12 @@ config MSM_GCC_8916 SD/eMMC, display, graphics, camera etc. config MSM_GCC_8917 - tristate "MSM8917/QM215 Global Clock Controller" + tristate "MSM89(17/37)/QM215 Global Clock Controller" depends on ARM64 || COMPILE_TEST select QCOM_GDSC help - Support for the global clock controller on msm8917 and qm215 - devices. + Support for the global clock controller on msm8917, msm8937 + and qm215 devices. Say Y if you want to use devices such as UART, SPI i2c, USB, SD/eMMC, display, graphics, camera etc. diff --git a/drivers/clk/qcom/gcc-msm8917.c b/drivers/clk/qcom/gcc-msm8917.c index 3e2a2ae2ee6e..0a1aa623cd49 100644 --- a/drivers/clk/qcom/gcc-msm8917.c +++ b/drivers/clk/qcom/gcc-msm8917.c @@ -37,6 +37,8 @@ enum { DT_SLEEP_CLK, DT_DSI0PLL, DT_DSI0PLL_BYTE, + DT_DSI1PLL, + DT_DSI1PLL_BYTE, }; enum { @@ -48,6 +50,8 @@ enum { P_GPLL6, P_DSI0PLL, P_DSI0PLL_BYTE, + P_DSI1PLL, + P_DSI1PLL_BYTE, }; static struct clk_alpha_pll gpll0_sleep_clk_src = { @@ -102,7 +106,11 @@ static const struct pll_vco gpll3_p_vco[] = { { 700000000, 1400000000, 0 }, }; -static const struct alpha_pll_config gpll3_early_config = { +static const struct pll_vco gpll3_p_vco_msm8937[] = { + { 525000000, 1066000000, 0 }, +}; + +static struct alpha_pll_config gpll3_early_config = { .l = 63, .config_ctl_val = 0x4001055b, .early_output_mask = 0, @@ -273,6 +281,19 @@ static const struct freq_tbl ftbl_blsp_i2c_apps_clk_src[] = { { } }; +static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x0200c, + .hid_width = 5, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup1_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + }, +}; + static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = { .cmd_rcgr = 0x03000, .hid_width = 5, @@ -351,6 +372,19 @@ static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = { } }; +static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = { + .cmd_rcgr = 0x18000, + .hid_width = 5, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp2_qup4_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + }, +}; + static const struct freq_tbl ftbl_blsp_spi_apps_clk_src[] = { F(960000, P_XO, 10, 1, 2), F(4800000, P_XO, 4, 0, 0), @@ -362,6 +396,20 @@ static const struct freq_tbl ftbl_blsp_spi_apps_clk_src[] = { { } }; +static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x02024, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup1_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + }, +}; + static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = { .cmd_rcgr = 0x03014, .hid_width = 5, @@ -446,6 +494,20 @@ static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = { } }; +static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = { + .cmd_rcgr = 0x18024, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp2_qup4_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + }, +}; + static const struct freq_tbl ftbl_blsp_uart_apps_clk_src[] = { F(3686400, P_GPLL0, 1, 72, 15625), F(7372800, P_GPLL0, 1, 144, 15625), @@ -525,11 +587,19 @@ static struct clk_rcg2 blsp2_uart2_apps_clk_src = { static const struct parent_map gcc_byte0_map[] = { { P_XO, 0 }, { P_DSI0PLL_BYTE, 1 }, + { P_DSI1PLL_BYTE, 3 }, +}; + +static const struct parent_map gcc_byte1_map[] = { + { P_XO, 0 }, + { P_DSI0PLL_BYTE, 3 }, + { P_DSI1PLL_BYTE, 1 }, }; static const struct clk_parent_data gcc_byte_data[] = { { .index = DT_XO }, { .index = DT_DSI0PLL_BYTE }, + { .index = DT_DSI1PLL_BYTE }, }; static struct clk_rcg2 byte0_clk_src = { @@ -545,6 +615,19 @@ static struct clk_rcg2 byte0_clk_src = { } }; +static struct clk_rcg2 byte1_clk_src = { + .cmd_rcgr = 0x4d0b0, + .hid_width = 5, + .parent_map = gcc_byte1_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "byte1_clk_src", + .parent_data = gcc_byte_data, + .num_parents = ARRAY_SIZE(gcc_byte_data), + .ops = &clk_byte2_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static const struct freq_tbl ftbl_camss_gp_clk_src[] = { F(100000000, P_GPLL0, 8, 0, 0), F(160000000, P_GPLL0, 5, 0, 0), @@ -642,6 +725,17 @@ static const struct freq_tbl ftbl_cpp_clk_src[] = { { } }; +static const struct freq_tbl ftbl_cpp_clk_src_msm8937[] = { + F(133330000, P_GPLL0, 6, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(200000000, P_GPLL0, 5, 0, 0), + F(266666667, P_GPLL0, 3, 0, 0), + F(308570000, P_GPLL6, 3.5, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), + F(360000000, P_GPLL6, 3, 0, 0), + { } +}; + static struct clk_rcg2 cpp_clk_src = { .cmd_rcgr = 0x58018, .hid_width = 5, @@ -655,6 +749,13 @@ static struct clk_rcg2 cpp_clk_src = { } }; +static struct clk_init_data vcodec0_clk_src_init_msm8937 = { + .name = "vcodec0_clk_src", + .parent_data = gcc_cpp_data, + .num_parents = ARRAY_SIZE(gcc_cpp_data), + .ops = &clk_rcg2_ops, +}; + static const struct freq_tbl ftbl_crypto_clk_src[] = { F(50000000, P_GPLL0, 16, 0, 0), F(80000000, P_GPLL0, 10, 0, 0), @@ -730,6 +831,13 @@ static const struct freq_tbl ftbl_csi_phytimer_clk_src[] = { { } }; +static const struct freq_tbl ftbl_csi_phytimer_clk_src_msm8937[] = { + F(100000000, P_GPLL0, 8, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + { } +}; + static struct clk_rcg2 csi0phytimer_clk_src = { .cmd_rcgr = 0x4e000, .hid_width = 5, @@ -774,6 +882,19 @@ static struct clk_rcg2 esc0_clk_src = { } }; +static struct clk_rcg2 esc1_clk_src = { + .cmd_rcgr = 0x4d0a8, + .hid_width = 5, + .freq_tbl = ftbl_esc0_1_clk_src, + .parent_map = gcc_xo_gpll0_out_aux_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "esc1_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + }, +}; + static const struct parent_map gcc_gfx3d_map[] = { { P_XO, 0 }, { P_GPLL0, 1 }, @@ -817,6 +938,25 @@ static const struct freq_tbl ftbl_gfx3d_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gfx3d_clk_src_msm8937[] = { + F(19200000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0, 16, 0, 0), + F(80000000, P_GPLL0, 10, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(216000000, P_GPLL6, 5, 0, 0), + F(228570000, P_GPLL0, 3.5, 0, 0), + F(240000000, P_GPLL6, 4.5, 0, 0), + F(266670000, P_GPLL0, 3, 0, 0), + F(300000000, P_GPLL3, 1, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), + F(375000000, P_GPLL3, 1, 0, 0), + F(400000000, P_GPLL0, 2, 0, 0), + F(450000000, P_GPLL3, 1, 0, 0), + { } +}; + static struct clk_rcg2 gfx3d_clk_src = { .cmd_rcgr = 0x59000, .hid_width = 5, @@ -973,21 +1113,29 @@ static struct clk_rcg2 mdp_clk_src = { } }; -static const struct parent_map gcc_pclk_map[] = { +static const struct parent_map gcc_pclk0_map[] = { { P_XO, 0 }, { P_DSI0PLL, 1 }, + { P_DSI1PLL, 3 }, +}; + +static const struct parent_map gcc_pclk1_map[] = { + { P_XO, 0 }, + { P_DSI0PLL, 3 }, + { P_DSI1PLL, 1 }, }; static const struct clk_parent_data gcc_pclk_data[] = { { .index = DT_XO }, { .index = DT_DSI0PLL }, + { .index = DT_DSI1PLL }, }; static struct clk_rcg2 pclk0_clk_src = { .cmd_rcgr = 0x4d000, .hid_width = 5, .mnd_width = 8, - .parent_map = gcc_pclk_map, + .parent_map = gcc_pclk0_map, .clkr.hw.init = &(struct clk_init_data) { .name = "pclk0_clk_src", .parent_data = gcc_pclk_data, @@ -997,6 +1145,20 @@ static struct clk_rcg2 pclk0_clk_src = { } }; +static struct clk_rcg2 pclk1_clk_src = { + .cmd_rcgr = 0x4d0b8, + .hid_width = 5, + .mnd_width = 8, + .parent_map = gcc_pclk1_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pclk1_clk_src", + .parent_data = gcc_pclk_data, + .num_parents = ARRAY_SIZE(gcc_pclk_data), + .ops = &clk_pixel_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static const struct freq_tbl ftbl_pdm2_clk_src[] = { F(64000000, P_GPLL0, 12.5, 0, 0), { } @@ -1108,6 +1270,14 @@ static const struct freq_tbl ftbl_usb_hs_system_clk_src[] = { { } }; +static const struct freq_tbl ftbl_usb_hs_system_clk_src_msm8937[] = { + F(57142857, P_GPLL0, 14, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(133333333, P_GPLL0, 6, 0, 0), + F(177777778, P_GPLL0, 4.5, 0, 0), + { } +}; + static struct clk_rcg2 usb_hs_system_clk_src = { .cmd_rcgr = 0x41010, .hid_width = 5, @@ -1132,6 +1302,15 @@ static const struct freq_tbl ftbl_vcodec0_clk_src[] = { { } }; +static const struct freq_tbl ftbl_vcodec0_clk_src_msm8937[] = { + F(166150000, P_GPLL6, 6.5, 0, 0), + F(240000000, P_GPLL6, 4.5, 0, 0), + F(308571428, P_GPLL6, 3.5, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), + F(360000000, P_GPLL6, 3, 0, 0), + { } +}; + static struct clk_rcg2 vcodec0_clk_src = { .cmd_rcgr = 0x4c000, .hid_width = 5, @@ -1160,6 +1339,23 @@ static const struct freq_tbl ftbl_vfe_clk_src[] = { { } }; +static const struct freq_tbl ftbl_vfe_clk_src_msm8937[] = { + F(50000000, P_GPLL0, 16, 0, 0), + F(80000000, P_GPLL0, 10, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(133333333, P_GPLL0, 6, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(177777778, P_GPLL0, 4.5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(266666667, P_GPLL0, 3, 0, 0), + F(308571428, P_GPLL6, 3.5, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), + F(360000000, P_GPLL6, 3, 0, 0), + F(400000000, P_GPLL0, 2, 0, 0), + F(432000000, P_GPLL6, 2.5, 0, 0), + { } +}; + static struct clk_rcg2 vfe0_clk_src = { .cmd_rcgr = 0x58000, .hid_width = 5, @@ -1269,6 +1465,24 @@ static struct clk_branch gcc_blsp2_ahb_clk = { } }; +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { + .halt_reg = 0x02008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x02008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp1_qup1_i2c_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { .halt_reg = 0x03010, .halt_check = BRANCH_HALT, @@ -1377,6 +1591,42 @@ static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = { } }; +static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = { + .halt_reg = 0x18020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x18020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp2_qup4_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp2_qup4_i2c_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { + .halt_reg = 0x02004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x02004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp1_qup1_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { .halt_reg = 0x0300c, .halt_check = BRANCH_HALT, @@ -1485,6 +1735,24 @@ static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = { } }; +static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = { + .halt_reg = 0x1801c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1801c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp2_qup4_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp2_qup4_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + static struct clk_branch gcc_blsp1_uart1_apps_clk = { .halt_reg = 0x0203c, .halt_check = BRANCH_HALT, @@ -2521,6 +2789,24 @@ static struct clk_branch gcc_mdss_byte0_clk = { } }; +static struct clk_branch gcc_mdss_byte1_clk = { + .halt_reg = 0x4d0a0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d0a0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_byte1_clk", + .parent_hws = (const struct clk_hw*[]){ + &byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + static struct clk_branch gcc_mdss_esc0_clk = { .halt_reg = 0x4d098, .halt_check = BRANCH_HALT, @@ -2539,6 +2825,24 @@ static struct clk_branch gcc_mdss_esc0_clk = { } }; +static struct clk_branch gcc_mdss_esc1_clk = { + .halt_reg = 0x4d09c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d09c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_esc1_clk", + .parent_hws = (const struct clk_hw*[]){ + &esc1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + static struct clk_branch gcc_mdss_mdp_clk = { .halt_reg = 0x4d088, .halt_check = BRANCH_HALT, @@ -2575,6 +2879,24 @@ static struct clk_branch gcc_mdss_pclk0_clk = { } }; +static struct clk_branch gcc_mdss_pclk1_clk = { + .halt_reg = 0x4d0a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d0a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_pclk1_clk", + .parent_hws = (const struct clk_hw*[]){ + &pclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + static struct clk_branch gcc_mdss_vsync_clk = { .halt_reg = 0x4d090, .halt_check = BRANCH_HALT, @@ -2632,6 +2954,24 @@ static struct clk_branch gcc_oxili_ahb_clk = { } }; +static struct clk_branch gcc_oxili_aon_clk = { + .halt_reg = 0x5904c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5904c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_oxili_aon_clk", + .parent_hws = (const struct clk_hw*[]){ + &gfx3d_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + static struct clk_branch gcc_oxili_gfx3d_clk = { .halt_reg = 0x59020, .halt_check = BRANCH_HALT, @@ -2650,6 +2990,19 @@ static struct clk_branch gcc_oxili_gfx3d_clk = { } }; +static struct clk_branch gcc_oxili_timer_clk = { + .halt_reg = 0x59040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x59040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_oxili_timer_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_pdm2_clk = { .halt_reg = 0x4400c, .halt_check = BRANCH_HALT, @@ -3027,6 +3380,28 @@ static struct gdsc oxili_gx_gdsc = { .flags = CLAMP_IO, }; +static struct gdsc oxili_gx_gdsc_msm8937 = { + .gdscr = 0x5901c, + .clamp_io_ctrl = 0x5b00c, + .cxcs = (unsigned int []){ 0x59000 }, + .cxc_count = 1, + .pd = { + .name = "oxili_gx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO, +}; + +static struct gdsc oxili_cx_gdsc = { + .gdscr = 0x59044, + .cxcs = (unsigned int []){ 0x59020 }, + .cxc_count = 1, + .pd = { + .name = "oxili_cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct gdsc cpp_gdsc = { .gdscr = 0x58078, .cxcs = (unsigned int []){ 0x5803c, 0x58064 }, @@ -3207,6 +3582,188 @@ static struct clk_regmap *gcc_msm8917_clocks[] = { [GCC_VFE_TBU_CLK] = &gcc_vfe_tbu_clk.clkr, }; +static struct clk_regmap *gcc_msm8937_clocks[] = { + [GPLL0] = &gpll0.clkr, + [GPLL0_EARLY] = &gpll0_early.clkr, + [GPLL0_SLEEP_CLK_SRC] = &gpll0_sleep_clk_src.clkr, + [GPLL3] = &gpll3.clkr, + [GPLL3_EARLY] = &gpll3_early.clkr, + [GPLL4] = &gpll4.clkr, + [GPLL4_EARLY] = &gpll4_early.clkr, + [GPLL6] = &gpll6, + [GPLL6_EARLY] = &gpll6_early.clkr, + [APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr, + [MSM8937_BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, + [MSM8937_BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr, + [BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr, + [BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr, + [BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr, + [BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr, + [BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr, + [BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr, + [BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr, + [BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr, + [BLSP2_QUP1_I2C_APPS_CLK_SRC] = &blsp2_qup1_i2c_apps_clk_src.clkr, + [BLSP2_QUP1_SPI_APPS_CLK_SRC] = &blsp2_qup1_spi_apps_clk_src.clkr, + [BLSP2_QUP2_I2C_APPS_CLK_SRC] = &blsp2_qup2_i2c_apps_clk_src.clkr, + [BLSP2_QUP2_SPI_APPS_CLK_SRC] = &blsp2_qup2_spi_apps_clk_src.clkr, + [BLSP2_QUP3_I2C_APPS_CLK_SRC] = &blsp2_qup3_i2c_apps_clk_src.clkr, + [BLSP2_QUP3_SPI_APPS_CLK_SRC] = &blsp2_qup3_spi_apps_clk_src.clkr, + [MSM8937_BLSP2_QUP4_I2C_APPS_CLK_SRC] = &blsp2_qup4_i2c_apps_clk_src.clkr, + [MSM8937_BLSP2_QUP4_SPI_APPS_CLK_SRC] = &blsp2_qup4_spi_apps_clk_src.clkr, + [BLSP2_UART1_APPS_CLK_SRC] = &blsp2_uart1_apps_clk_src.clkr, + [BLSP2_UART2_APPS_CLK_SRC] = &blsp2_uart2_apps_clk_src.clkr, + [BYTE0_CLK_SRC] = &byte0_clk_src.clkr, + [MSM8937_BYTE1_CLK_SRC] = &byte1_clk_src.clkr, + [CAMSS_GP0_CLK_SRC] = &camss_gp0_clk_src.clkr, + [CAMSS_GP1_CLK_SRC] = &camss_gp1_clk_src.clkr, + [CAMSS_TOP_AHB_CLK_SRC] = &camss_top_ahb_clk_src.clkr, + [CCI_CLK_SRC] = &cci_clk_src.clkr, + [CPP_CLK_SRC] = &cpp_clk_src.clkr, + [CRYPTO_CLK_SRC] = &crypto_clk_src.clkr, + [CSI0PHYTIMER_CLK_SRC] = &csi0phytimer_clk_src.clkr, + [CSI0_CLK_SRC] = &csi0_clk_src.clkr, + [CSI1PHYTIMER_CLK_SRC] = &csi1phytimer_clk_src.clkr, + [CSI1_CLK_SRC] = &csi1_clk_src.clkr, + [CSI2_CLK_SRC] = &csi2_clk_src.clkr, + [ESC0_CLK_SRC] = &esc0_clk_src.clkr, + [MSM8937_ESC1_CLK_SRC] = &esc1_clk_src.clkr, + [GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr, + [GP1_CLK_SRC] = &gp1_clk_src.clkr, + [GP2_CLK_SRC] = &gp2_clk_src.clkr, + [GP3_CLK_SRC] = &gp3_clk_src.clkr, + [JPEG0_CLK_SRC] = &jpeg0_clk_src.clkr, + [MCLK0_CLK_SRC] = &mclk0_clk_src.clkr, + [MCLK1_CLK_SRC] = &mclk1_clk_src.clkr, + [MCLK2_CLK_SRC] = &mclk2_clk_src.clkr, + [MDP_CLK_SRC] = &mdp_clk_src.clkr, + [PCLK0_CLK_SRC] = &pclk0_clk_src.clkr, + [MSM8937_PCLK1_CLK_SRC] = &pclk1_clk_src.clkr, + [PDM2_CLK_SRC] = &pdm2_clk_src.clkr, + [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr, + [SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr, + [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr, + [USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr, + [VCODEC0_CLK_SRC] = &vcodec0_clk_src.clkr, + [VFE0_CLK_SRC] = &vfe0_clk_src.clkr, + [VFE1_CLK_SRC] = &vfe1_clk_src.clkr, + [VSYNC_CLK_SRC] = &vsync_clk_src.clkr, + [GCC_APSS_TCU_CLK] = &gcc_apss_tcu_clk.clkr, + [GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr, + [GCC_BIMC_GPU_CLK] = &gcc_bimc_gpu_clk.clkr, + [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, + [MSM8937_GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr, + [MSM8937_GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, + [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, + [GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr, + [GCC_BLSP2_QUP1_I2C_APPS_CLK] = &gcc_blsp2_qup1_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP1_SPI_APPS_CLK] = &gcc_blsp2_qup1_spi_apps_clk.clkr, + [GCC_BLSP2_QUP2_I2C_APPS_CLK] = &gcc_blsp2_qup2_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP2_SPI_APPS_CLK] = &gcc_blsp2_qup2_spi_apps_clk.clkr, + [GCC_BLSP2_QUP3_I2C_APPS_CLK] = &gcc_blsp2_qup3_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP3_SPI_APPS_CLK] = &gcc_blsp2_qup3_spi_apps_clk.clkr, + [MSM8937_GCC_BLSP2_QUP4_I2C_APPS_CLK] = &gcc_blsp2_qup4_i2c_apps_clk.clkr, + [MSM8937_GCC_BLSP2_QUP4_SPI_APPS_CLK] = &gcc_blsp2_qup4_spi_apps_clk.clkr, + [GCC_BLSP2_UART1_APPS_CLK] = &gcc_blsp2_uart1_apps_clk.clkr, + [GCC_BLSP2_UART2_APPS_CLK] = &gcc_blsp2_uart2_apps_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CAMSS_AHB_CLK] = &gcc_camss_ahb_clk.clkr, + [GCC_CAMSS_CCI_AHB_CLK] = &gcc_camss_cci_ahb_clk.clkr, + [GCC_CAMSS_CCI_CLK] = &gcc_camss_cci_clk.clkr, + [GCC_CAMSS_CPP_AHB_CLK] = &gcc_camss_cpp_ahb_clk.clkr, + [GCC_CAMSS_CPP_CLK] = &gcc_camss_cpp_clk.clkr, + [GCC_CAMSS_CSI0PHYTIMER_CLK] = &gcc_camss_csi0phytimer_clk.clkr, + [GCC_CAMSS_CSI0PHY_CLK] = &gcc_camss_csi0phy_clk.clkr, + [GCC_CAMSS_CSI0PIX_CLK] = &gcc_camss_csi0pix_clk.clkr, + [GCC_CAMSS_CSI0RDI_CLK] = &gcc_camss_csi0rdi_clk.clkr, + [GCC_CAMSS_CSI0_AHB_CLK] = &gcc_camss_csi0_ahb_clk.clkr, + [GCC_CAMSS_CSI0_CLK] = &gcc_camss_csi0_clk.clkr, + [GCC_CAMSS_CSI1PHYTIMER_CLK] = &gcc_camss_csi1phytimer_clk.clkr, + [GCC_CAMSS_CSI1PHY_CLK] = &gcc_camss_csi1phy_clk.clkr, + [GCC_CAMSS_CSI1PIX_CLK] = &gcc_camss_csi1pix_clk.clkr, + [GCC_CAMSS_CSI1RDI_CLK] = &gcc_camss_csi1rdi_clk.clkr, + [GCC_CAMSS_CSI1_AHB_CLK] = &gcc_camss_csi1_ahb_clk.clkr, + [GCC_CAMSS_CSI1_CLK] = &gcc_camss_csi1_clk.clkr, + [GCC_CAMSS_CSI2PHY_CLK] = &gcc_camss_csi2phy_clk.clkr, + [GCC_CAMSS_CSI2PIX_CLK] = &gcc_camss_csi2pix_clk.clkr, + [GCC_CAMSS_CSI2RDI_CLK] = &gcc_camss_csi2rdi_clk.clkr, + [GCC_CAMSS_CSI2_AHB_CLK] = &gcc_camss_csi2_ahb_clk.clkr, + [GCC_CAMSS_CSI2_CLK] = &gcc_camss_csi2_clk.clkr, + [GCC_CAMSS_CSI_VFE0_CLK] = &gcc_camss_csi_vfe0_clk.clkr, + [GCC_CAMSS_CSI_VFE1_CLK] = &gcc_camss_csi_vfe1_clk.clkr, + [GCC_CAMSS_GP0_CLK] = &gcc_camss_gp0_clk.clkr, + [GCC_CAMSS_GP1_CLK] = &gcc_camss_gp1_clk.clkr, + [GCC_CAMSS_ISPIF_AHB_CLK] = &gcc_camss_ispif_ahb_clk.clkr, + [GCC_CAMSS_JPEG0_CLK] = &gcc_camss_jpeg0_clk.clkr, + [GCC_CAMSS_JPEG_AHB_CLK] = &gcc_camss_jpeg_ahb_clk.clkr, + [GCC_CAMSS_JPEG_AXI_CLK] = &gcc_camss_jpeg_axi_clk.clkr, + [GCC_CAMSS_MCLK0_CLK] = &gcc_camss_mclk0_clk.clkr, + [GCC_CAMSS_MCLK1_CLK] = &gcc_camss_mclk1_clk.clkr, + [GCC_CAMSS_MCLK2_CLK] = &gcc_camss_mclk2_clk.clkr, + [GCC_CAMSS_MICRO_AHB_CLK] = &gcc_camss_micro_ahb_clk.clkr, + [GCC_CAMSS_TOP_AHB_CLK] = &gcc_camss_top_ahb_clk.clkr, + [GCC_CAMSS_VFE0_AHB_CLK] = &gcc_camss_vfe0_ahb_clk.clkr, + [GCC_CAMSS_VFE0_AXI_CLK] = &gcc_camss_vfe0_axi_clk.clkr, + [GCC_CAMSS_VFE0_CLK] = &gcc_camss_vfe0_clk.clkr, + [GCC_CAMSS_VFE1_AHB_CLK] = &gcc_camss_vfe1_ahb_clk.clkr, + [GCC_CAMSS_VFE1_AXI_CLK] = &gcc_camss_vfe1_axi_clk.clkr, + [GCC_CAMSS_VFE1_CLK] = &gcc_camss_vfe1_clk.clkr, + [GCC_CPP_TBU_CLK] = &gcc_cpp_tbu_clk.clkr, + [GCC_CRYPTO_AHB_CLK] = &gcc_crypto_ahb_clk.clkr, + [GCC_CRYPTO_AXI_CLK] = &gcc_crypto_axi_clk.clkr, + [GCC_CRYPTO_CLK] = &gcc_crypto_clk.clkr, + [GCC_DCC_CLK] = &gcc_dcc_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_JPEG_TBU_CLK] = &gcc_jpeg_tbu_clk.clkr, + [GCC_MDP_TBU_CLK] = &gcc_mdp_tbu_clk.clkr, + [GCC_MDSS_AHB_CLK] = &gcc_mdss_ahb_clk.clkr, + [GCC_MDSS_AXI_CLK] = &gcc_mdss_axi_clk.clkr, + [GCC_MDSS_BYTE0_CLK] = &gcc_mdss_byte0_clk.clkr, + [MSM8937_GCC_MDSS_BYTE1_CLK] = &gcc_mdss_byte1_clk.clkr, + [GCC_MDSS_ESC0_CLK] = &gcc_mdss_esc0_clk.clkr, + [MSM8937_GCC_MDSS_ESC1_CLK] = &gcc_mdss_esc1_clk.clkr, + [GCC_MDSS_MDP_CLK] = &gcc_mdss_mdp_clk.clkr, + [GCC_MDSS_PCLK0_CLK] = &gcc_mdss_pclk0_clk.clkr, + [MSM8937_GCC_MDSS_PCLK1_CLK] = &gcc_mdss_pclk1_clk.clkr, + [GCC_MDSS_VSYNC_CLK] = &gcc_mdss_vsync_clk.clkr, + [GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr, + [GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr, + [GCC_OXILI_AHB_CLK] = &gcc_oxili_ahb_clk.clkr, + [MSM8937_GCC_OXILI_AON_CLK] = &gcc_oxili_aon_clk.clkr, + [GCC_OXILI_GFX3D_CLK] = &gcc_oxili_gfx3d_clk.clkr, + [MSM8937_GCC_OXILI_TIMER_CLK] = &gcc_oxili_timer_clk.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, + [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SMMU_CFG_CLK] = &gcc_smmu_cfg_clk.clkr, + [GCC_USB2A_PHY_SLEEP_CLK] = &gcc_usb2a_phy_sleep_clk.clkr, + [GCC_USB_HS_AHB_CLK] = &gcc_usb_hs_ahb_clk.clkr, + [GCC_USB_HS_PHY_CFG_AHB_CLK] = &gcc_usb_hs_phy_cfg_ahb_clk.clkr, + [GCC_USB_HS_SYSTEM_CLK] = &gcc_usb_hs_system_clk.clkr, + [GCC_VENUS0_AHB_CLK] = &gcc_venus0_ahb_clk.clkr, + [GCC_VENUS0_AXI_CLK] = &gcc_venus0_axi_clk.clkr, + [GCC_VENUS0_CORE0_VCODEC0_CLK] = &gcc_venus0_core0_vcodec0_clk.clkr, + [GCC_VENUS0_VCODEC0_CLK] = &gcc_venus0_vcodec0_clk.clkr, + [GCC_VENUS_TBU_CLK] = &gcc_venus_tbu_clk.clkr, + [GCC_VFE1_TBU_CLK] = &gcc_vfe1_tbu_clk.clkr, + [GCC_VFE_TBU_CLK] = &gcc_vfe_tbu_clk.clkr, +}; + static const struct qcom_reset_map gcc_msm8917_resets[] = { [GCC_CAMSS_MICRO_BCR] = { 0x56008 }, [GCC_MSS_BCR] = { 0x71000 }, @@ -3234,6 +3791,18 @@ static struct gdsc *gcc_msm8917_gdscs[] = { [VFE1_GDSC] = &vfe1_gdsc, }; +static struct gdsc *gcc_msm8937_gdscs[] = { + [CPP_GDSC] = &cpp_gdsc, + [JPEG_GDSC] = &jpeg_gdsc, + [MDSS_GDSC] = &mdss_gdsc, + [OXILI_GX_GDSC] = &oxili_gx_gdsc_msm8937, + [MSM8937_OXILI_CX_GDSC] = &oxili_cx_gdsc, + [VENUS_CORE0_GDSC] = &venus_core0_gdsc, + [VENUS_GDSC] = &venus_gdsc, + [VFE0_GDSC] = &vfe0_gdsc, + [VFE1_GDSC] = &vfe1_gdsc, +}; + static const struct qcom_cc_desc gcc_msm8917_desc = { .config = &gcc_msm8917_regmap_config, .clks = gcc_msm8917_clocks, @@ -3254,6 +3823,41 @@ static const struct qcom_cc_desc gcc_qm215_desc = { .num_gdscs = ARRAY_SIZE(gcc_msm8917_gdscs), }; +static const struct qcom_cc_desc gcc_msm8937_desc = { + .config = &gcc_msm8917_regmap_config, + .clks = gcc_msm8937_clocks, + .num_clks = ARRAY_SIZE(gcc_msm8937_clocks), + .resets = gcc_msm8917_resets, + .num_resets = ARRAY_SIZE(gcc_msm8917_resets), + .gdscs = gcc_msm8937_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_msm8937_gdscs), +}; + +static void msm8937_clock_override(void) +{ + /* GPLL3 750MHz configuration */ + gpll3_early_config.l = 47; + gpll3_early.vco_table = gpll3_p_vco_msm8937; + gpll3_early.num_vco = ARRAY_SIZE(gpll3_p_vco_msm8937); + + /* + * Set below clocks for use specific msm8937 parent map. + */ + vcodec0_clk_src.parent_map = gcc_cpp_map; + vcodec0_clk_src.clkr.hw.init = &vcodec0_clk_src_init_msm8937; + + /* + * Set below clocks for use specific msm8937 freq table. + */ + vfe0_clk_src.freq_tbl = ftbl_vfe_clk_src_msm8937; + vfe1_clk_src.freq_tbl = ftbl_vfe_clk_src_msm8937; + cpp_clk_src.freq_tbl = ftbl_cpp_clk_src_msm8937; + vcodec0_clk_src.freq_tbl = ftbl_vcodec0_clk_src_msm8937; + csi0phytimer_clk_src.freq_tbl = ftbl_csi_phytimer_clk_src_msm8937; + csi1phytimer_clk_src.freq_tbl = ftbl_csi_phytimer_clk_src_msm8937; + usb_hs_system_clk_src.freq_tbl = ftbl_usb_hs_system_clk_src_msm8937; +} + static int gcc_msm8917_probe(struct platform_device *pdev) { struct regmap *regmap; @@ -3261,8 +3865,12 @@ static int gcc_msm8917_probe(struct platform_device *pdev) gcc_desc = of_device_get_match_data(&pdev->dev); - if (gcc_desc == &gcc_qm215_desc) + if (gcc_desc == &gcc_qm215_desc) { gfx3d_clk_src.parent_map = gcc_gfx3d_map_qm215; + } else if (gcc_desc == &gcc_msm8937_desc) { + msm8937_clock_override(); + gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_msm8937; + } regmap = qcom_cc_map(pdev, gcc_desc); if (IS_ERR(regmap)) @@ -3276,6 +3884,7 @@ static int gcc_msm8917_probe(struct platform_device *pdev) static const struct of_device_id gcc_msm8917_match_table[] = { { .compatible = "qcom,gcc-msm8917", .data = &gcc_msm8917_desc }, { .compatible = "qcom,gcc-qm215", .data = &gcc_qm215_desc }, + { .compatible = "qcom,gcc-msm8937", .data = &gcc_msm8937_desc }, {}, }; MODULE_DEVICE_TABLE(of, gcc_msm8917_match_table); From eb9bc162775cabfc4cf2b37cb0d3c2c2bf4c4b54 Mon Sep 17 00:00:00 2001 From: Denzeel Oliva Date: Sun, 31 Aug 2025 12:13:14 +0000 Subject: [PATCH 0817/2711] dt-bindings: clock: exynos990: Add LHS_ACEL clock ID for HSI0 block Add the missing LHS_ACEL clock ID for the HSI0 block. This clock is required for proper USB operation, as without it, USB connections fail with errors like device descriptor read timeouts and address response issues. Signed-off-by: Denzeel Oliva Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250831-usb-v2-1-00b9c0559733@gmail.com Signed-off-by: Krzysztof Kozlowski --- include/dt-bindings/clock/samsung,exynos990.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/samsung,exynos990.h b/include/dt-bindings/clock/samsung,exynos990.h index c5c79e078f2f..c60f15503d5b 100644 --- a/include/dt-bindings/clock/samsung,exynos990.h +++ b/include/dt-bindings/clock/samsung,exynos990.h @@ -236,6 +236,7 @@ #define CLK_GOUT_HSI0_VGEN_LITE_HSI0_CLK 20 #define CLK_GOUT_HSI0_CMU_HSI0_PCLK 21 #define CLK_GOUT_HSI0_XIU_D_HSI0_ACLK 22 +#define CLK_GOUT_HSI0_LHS_ACEL_D_HSI0_CLK 23 /* CMU_PERIS */ #define CLK_MOUT_PERIS_BUS_USER 1 From d0563d320b6014a8d56170253fe0aec524658b9f Mon Sep 17 00:00:00 2001 From: Denzeel Oliva Date: Sun, 31 Aug 2025 12:13:15 +0000 Subject: [PATCH 0818/2711] clk: samsung: exynos990: Add LHS_ACEL gate clock for HSI0 and update CLK_NR_TOP Add the LHS_ACEL gate clock to the HSI0 clock controller. This clock is critical for USB functionality and mark it as critical to keep it enabled. Update CLK_NR_TOP to include the new clock. Signed-off-by: Denzeel Oliva Link: https://lore.kernel.org/r/20250831-usb-v2-2-00b9c0559733@gmail.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-exynos990.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-exynos990.c b/drivers/clk/samsung/clk-exynos990.c index 91736b15c4b4..7884354d612c 100644 --- a/drivers/clk/samsung/clk-exynos990.c +++ b/drivers/clk/samsung/clk-exynos990.c @@ -18,7 +18,7 @@ /* NOTE: Must be equal to the last clock ID increased by one */ #define CLKS_NR_TOP (CLK_DOUT_CMU_CLK_CMUREF + 1) -#define CLKS_NR_HSI0 (CLK_GOUT_HSI0_XIU_D_HSI0_ACLK + 1) +#define CLKS_NR_HSI0 (CLK_GOUT_HSI0_LHS_ACEL_D_HSI0_CLK + 1) #define CLKS_NR_PERIS (CLK_GOUT_PERIS_OTP_CON_TOP_OSCCLK + 1) /* ---- CMU_TOP ------------------------------------------------------------- */ @@ -1332,6 +1332,10 @@ static const struct samsung_gate_clock hsi0_gate_clks[] __initconst = { "gout_hsi0_xiu_d_hsi0_aclk", "mout_hsi0_bus_user", CLK_CON_GAT_GOUT_BLK_HSI0_UID_XIU_D_HSI0_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_HSI0_LHS_ACEL_D_HSI0_CLK, + "gout_hsi0_lhs_acel_d_hsi0_clk", "mout_hsi0_bus_user", + CLK_CON_GAT_GOUT_BLK_HSI0_UID_LHS_ACEL_D_HSI0_IPCLKPORT_I_CLK, + 21, CLK_IS_CRITICAL, 0), }; static const struct samsung_cmu_info hsi0_cmu_info __initconst = { From f00a5dc81744250e7a3f843adfe12d7883282c56 Mon Sep 17 00:00:00 2001 From: Denzeel Oliva Date: Sun, 31 Aug 2025 12:13:16 +0000 Subject: [PATCH 0819/2711] clk: samsung: exynos990: Add missing USB clock registers to HSI0 These registers are required for proper USB operation and were omitted in the initial clock controller setup. Signed-off-by: Denzeel Oliva Link: https://lore.kernel.org/r/20250831-usb-v2-3-00b9c0559733@gmail.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-exynos990.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/samsung/clk-exynos990.c b/drivers/clk/samsung/clk-exynos990.c index 7884354d612c..47a1e0850c30 100644 --- a/drivers/clk/samsung/clk-exynos990.c +++ b/drivers/clk/samsung/clk-exynos990.c @@ -1224,6 +1224,8 @@ static const unsigned long hsi0_clk_regs[] __initconst = { CLK_CON_GAT_GOUT_BLK_HSI0_UID_SYSMMU_USB_IPCLKPORT_CLK_S2, CLK_CON_GAT_GOUT_BLK_HSI0_UID_SYSREG_HSI0_IPCLKPORT_PCLK, CLK_CON_GAT_GOUT_BLK_HSI0_UID_USB31DRD_IPCLKPORT_ACLK_PHYCTRL, + CLK_CON_GAT_GOUT_BLK_HSI0_UID_USB31DRD_IPCLKPORT_I_USB31DRD_REF_CLK_40, + CLK_CON_GAT_GOUT_BLK_HSI0_UID_USB31DRD_IPCLKPORT_I_USBDPPHY_REF_SOC_PLL, CLK_CON_GAT_GOUT_BLK_HSI0_UID_USB31DRD_IPCLKPORT_I_USBDPPHY_SCL_APB_PCLK, CLK_CON_GAT_GOUT_BLK_HSI0_UID_USB31DRD_IPCLKPORT_I_USBPCS_APB_CLK, CLK_CON_GAT_GOUT_BLK_HSI0_UID_USB31DRD_IPCLKPORT_BUS_CLK_EARLY, From 0fec357ad073e555e7553dbc0d32278b0aaa2179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duje=20Mihanovi=C4=87?= Date: Sun, 24 Aug 2025 18:12:05 +0200 Subject: [PATCH 0820/2711] dt-bindings: input: touchscreen: imagis: add missing minItems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The binding currently expects exactly 5 keycodes, which matches the chip's theoretical maximum but probably not the number of touch keys on any phone using the IST3032C. Add a minItems value of 2 to prevent dt-validate complaints. Also add another example to make sure the linux,keycodes property is checked. Signed-off-by: Duje Mihanović Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250824-imagis-minitems-v1-1-cea9db55e87f@dujemihanovic.xyz Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/imagis,ist3038c.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml index bd8ede3a4ad8..0ef79343bf9a 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml @@ -35,6 +35,7 @@ properties: linux,keycodes: description: Keycodes for the touch keys + minItems: 2 maxItems: 5 touchscreen-size-x: true @@ -87,5 +88,22 @@ examples: touchscreen-inverted-y; }; }; + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + touchscreen@50 { + compatible = "imagis,ist3032c"; + reg = <0x50>; + interrupt-parent = <&gpio>; + interrupts = <72 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&ldo2>; + touchscreen-size-x = <480>; + touchscreen-size-y = <800>; + linux,keycodes = , ; + }; + }; ... From c8ab5e888bb6721e6e084881e6e24ef2678832c3 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Mon, 1 Sep 2025 09:44:52 +0200 Subject: [PATCH 0821/2711] PCI/AER: Print TLP Log for errors introduced since PCIe r1.1 When reporting an error, the AER driver prints the TLP Header / Prefix Log only for errors enumerated in the AER_LOG_TLP_MASKS macro. The macro was never amended since its introduction in 2006 with commit 6c2b374d7485 ("PCI-Express AER implemetation: AER core and aerdriver"). At the time, PCIe r1.1 was the latest spec revision. Amend the macro with errors defined since then to avoid omitting the TLP Header / Prefix Log for newer errors. The order of the errors in AER_LOG_TLP_MASKS follows PCIe r1.1 sec 6.2.7 rather than 7.10.2, because only the former documents for which errors a TLP Header / Prefix is logged. Retain this order. The section number is still 6.2.7 in today's PCIe r7.0. For Completion Timeouts, the TLP Header / Prefix is only logged if the Completion Timeout Prefix / Header Log Capable bit is set in the AER Capabilities and Control register. Introduce a tlp_header_logged() helper to check whether the TLP Header / Prefix Log is populated and use it in the two places which currently match against AER_LOG_TLP_MASKS directly. For Uncorrectable Internal Errors, logging of the TLP Header / Prefix is optional per PCIe r7.0 sec 6.2.7. If needed, drivers could indicate through a flag whether devices are capable and tlp_header_logged() could then check that flag. pcitools introduced macros for newer errors with commit 144b0911cc0b ("ls-ecaps: extend decode support for more fields for AER CE and UE status"): https://git.kernel.org/pub/scm/utils/pciutils/pciutils.git/commit/?id=144b0911cc0b Unfortunately some of those macros are overly long: PCI_ERR_UNC_POISONED_TLP_EGRESS PCI_ERR_UNC_DMWR_REQ_EGRESS_BLOCKED PCI_ERR_UNC_IDE_CHECK PCI_ERR_UNC_MISR_IDE_TLP PCI_ERR_UNC_PCRC_CHECK PCI_ERR_UNC_TLP_XLAT_EGRESS_BLOCKED This seems unsuitable for , so shorten to: PCI_ERR_UNC_POISON_BLK PCI_ERR_UNC_DMWR_BLK PCI_ERR_UNC_IDE_CHECK PCI_ERR_UNC_MISR_IDE PCI_ERR_UNC_PCRC_CHECK PCI_ERR_UNC_XLAT_BLK Note that some of the existing macros in do not match exactly with pcitools (e.g. PCI_ERR_UNC_SDES versus PCI_ERR_UNC_SURPDN), so it does not seem mandatory for them to be identical. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/5f707caf1260bd8f15012bb032f7da9a9b898aba.1756712066.git.lukas@wunner.de --- drivers/pci/pcie/aer.c | 30 +++++++++++++++++++++++++++--- include/uapi/linux/pci_regs.h | 7 +++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 15ed541d2fbe..62c74b5f99ae 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -96,11 +96,21 @@ struct aer_info { }; #define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \ + PCI_ERR_UNC_POISON_BLK | \ PCI_ERR_UNC_ECRC| \ PCI_ERR_UNC_UNSUP| \ PCI_ERR_UNC_COMP_ABORT| \ PCI_ERR_UNC_UNX_COMP| \ - PCI_ERR_UNC_MALF_TLP) + PCI_ERR_UNC_ACSV | \ + PCI_ERR_UNC_MCBTLP | \ + PCI_ERR_UNC_ATOMEG | \ + PCI_ERR_UNC_DMWR_BLK | \ + PCI_ERR_UNC_XLAT_BLK | \ + PCI_ERR_UNC_TLPPRE | \ + PCI_ERR_UNC_MALF_TLP | \ + PCI_ERR_UNC_IDE_CHECK | \ + PCI_ERR_UNC_MISR_IDE | \ + PCI_ERR_UNC_PCRC_CHECK) #define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \ PCI_EXP_RTCTL_SENFEE| \ @@ -796,6 +806,20 @@ static int aer_ratelimit(struct pci_dev *dev, unsigned int severity) } } +static bool tlp_header_logged(u32 status, u32 capctl) +{ + /* Errors for which a header is always logged (PCIe r7.0 sec 6.2.7) */ + if (status & AER_LOG_TLP_MASKS) + return true; + + /* Completion Timeout header is only logged on capable devices */ + if (status & PCI_ERR_UNC_COMP_TIME && + capctl & PCI_ERR_CAP_COMP_TIME_LOG) + return true; + + return false; +} + static void __aer_print_error(struct pci_dev *dev, struct aer_err_info *info) { const char **strings; @@ -910,7 +934,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, status = aer->uncor_status; mask = aer->uncor_mask; info.level = KERN_ERR; - tlp_header_valid = status & AER_LOG_TLP_MASKS; + tlp_header_valid = tlp_header_logged(status, aer->cap_control); } info.status = status; @@ -1401,7 +1425,7 @@ int aer_get_device_error_info(struct aer_err_info *info, int i) pci_read_config_dword(dev, aer + PCI_ERR_CAP, &aercc); info->first_error = PCI_ERR_CAP_FEP(aercc); - if (info->status & AER_LOG_TLP_MASKS) { + if (tlp_header_logged(info->status, aercc)) { info->tlp_header_valid = 1; pcie_read_tlp_log(dev, aer + PCI_ERR_HEADER_LOG, aer + PCI_ERR_PREFIX_LOG, diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index f5b17745de60..ae1f52e8d515 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -776,6 +776,12 @@ #define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC blocked TLP */ #define PCI_ERR_UNC_ATOMEG 0x01000000 /* Atomic egress blocked */ #define PCI_ERR_UNC_TLPPRE 0x02000000 /* TLP prefix blocked */ +#define PCI_ERR_UNC_POISON_BLK 0x04000000 /* Poisoned TLP Egress Blocked */ +#define PCI_ERR_UNC_DMWR_BLK 0x08000000 /* DMWr Request Egress Blocked */ +#define PCI_ERR_UNC_IDE_CHECK 0x10000000 /* IDE Check Failed */ +#define PCI_ERR_UNC_MISR_IDE 0x20000000 /* Misrouted IDE TLP */ +#define PCI_ERR_UNC_PCRC_CHECK 0x40000000 /* PCRC Check Failed */ +#define PCI_ERR_UNC_XLAT_BLK 0x80000000 /* TLP Translation Egress Blocked */ #define PCI_ERR_UNCOR_MASK 0x08 /* Uncorrectable Error Mask */ /* Same bits as above */ #define PCI_ERR_UNCOR_SEVER 0x0c /* Uncorrectable Error Severity */ @@ -798,6 +804,7 @@ #define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ #define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ #define PCI_ERR_CAP_PREFIX_LOG_PRESENT 0x00000800 /* TLP Prefix Log Present */ +#define PCI_ERR_CAP_COMP_TIME_LOG 0x00001000 /* Completion Timeout Prefix/Header Log Capable */ #define PCI_ERR_CAP_TLP_LOG_FLIT 0x00040000 /* TLP was logged in Flit Mode */ #define PCI_ERR_CAP_TLP_LOG_SIZE 0x00f80000 /* Logged TLP Size (only in Flit mode) */ #define PCI_ERR_HEADER_LOG 0x1c /* Header Log Register (16 bytes) */ From e256a6602aa0914ff8a40724505ef2a5314a6e8e Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:26 +0200 Subject: [PATCH 0822/2711] clk: amlogic: drop meson-clkcee What is being done by the Amlogic clock controller registration helper for EE controllers could benefit other controllers. As such, having a specific module for this makes little sense. Move the helper function to clkc-utils and rename it to describe what it does, registering syscon based controller, instead of what it serves. Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-1-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/Kconfig | 13 +++--- drivers/clk/meson/Makefile | 1 - drivers/clk/meson/axg.c | 6 +-- drivers/clk/meson/g12a.c | 28 ++++++------- drivers/clk/meson/gxbb.c | 8 ++-- drivers/clk/meson/meson-clkc-utils.c | 50 ++++++++++++++++++++++- drivers/clk/meson/meson-clkc-utils.h | 10 +++++ drivers/clk/meson/meson-eeclk.c | 60 ---------------------------- drivers/clk/meson/meson-eeclk.h | 24 ----------- 9 files changed, 85 insertions(+), 115 deletions(-) delete mode 100644 drivers/clk/meson/meson-eeclk.c delete mode 100644 drivers/clk/meson/meson-eeclk.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 7197d23543b8..71481607a6d5 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -36,6 +36,8 @@ config COMMON_CLK_MESON_VCLK select COMMON_CLK_MESON_REGMAP config COMMON_CLK_MESON_CLKC_UTILS + select REGMAP + select MFD_SYSCON tristate config COMMON_CLK_MESON_AO_CLKC @@ -44,11 +46,6 @@ config COMMON_CLK_MESON_AO_CLKC select COMMON_CLK_MESON_CLKC_UTILS select RESET_CONTROLLER -config COMMON_CLK_MESON_EE_CLKC - tristate - select COMMON_CLK_MESON_REGMAP - select COMMON_CLK_MESON_CLKC_UTILS - config COMMON_CLK_MESON_CPU_DYNDIV tristate select COMMON_CLK_MESON_REGMAP @@ -73,12 +70,12 @@ config COMMON_CLK_GXBB depends on ARM64 default ARCH_MESON select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS select COMMON_CLK_MESON_DUALDIV select COMMON_CLK_MESON_VID_PLL_DIV select COMMON_CLK_MESON_MPLL select COMMON_CLK_MESON_PLL select COMMON_CLK_MESON_AO_CLKC - select COMMON_CLK_MESON_EE_CLKC select MFD_SYSCON help Support for the clock controller on AmLogic S905 devices, aka gxbb. @@ -89,11 +86,11 @@ config COMMON_CLK_AXG depends on ARM64 default ARCH_MESON select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS select COMMON_CLK_MESON_DUALDIV select COMMON_CLK_MESON_MPLL select COMMON_CLK_MESON_PLL select COMMON_CLK_MESON_AO_CLKC - select COMMON_CLK_MESON_EE_CLKC select MFD_SYSCON help Support for the clock controller on AmLogic A113D devices, aka axg. @@ -167,11 +164,11 @@ config COMMON_CLK_G12A depends on ARM64 default ARCH_MESON select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS select COMMON_CLK_MESON_DUALDIV select COMMON_CLK_MESON_MPLL select COMMON_CLK_MESON_PLL select COMMON_CLK_MESON_AO_CLKC - select COMMON_CLK_MESON_EE_CLKC select COMMON_CLK_MESON_CPU_DYNDIV select COMMON_CLK_MESON_VID_PLL_DIV select COMMON_CLK_MESON_VCLK diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index bc56a47931c1..c6998e752c68 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_COMMON_CLK_MESON_CLKC_UTILS) += meson-clkc-utils.o obj-$(CONFIG_COMMON_CLK_MESON_AO_CLKC) += meson-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON_CPU_DYNDIV) += clk-cpu-dyndiv.o obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o -obj-$(CONFIG_COMMON_CLK_MESON_EE_CLKC) += meson-eeclk.o obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 7273178d33f7..021bc7658f7f 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -18,7 +18,7 @@ #include "clk-regmap.h" #include "clk-pll.h" #include "clk-mpll.h" -#include "meson-eeclk.h" +#include "meson-clkc-utils.h" #include @@ -2110,7 +2110,7 @@ static struct clk_hw *axg_hw_clks[] = { [CLKID_VDIN_MEAS] = &axg_vdin_meas.hw, }; -static const struct meson_eeclkc_data axg_clkc_data = { +static const struct meson_clkc_data axg_clkc_data = { .hw_clks = { .hws = axg_hw_clks, .num = ARRAY_SIZE(axg_hw_clks), @@ -2124,7 +2124,7 @@ static const struct of_device_id axg_clkc_match_table[] = { MODULE_DEVICE_TABLE(of, axg_clkc_match_table); static struct platform_driver axg_clkc_driver = { - .probe = meson_eeclkc_probe, + .probe = meson_clkc_syscon_probe, .driver = { .name = "axg-clkc", .of_match_table = axg_clkc_match_table, diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 7e2c0ce91964..c06a4b678b27 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -23,7 +23,7 @@ #include "clk-cpu-dyndiv.h" #include "vid-pll-div.h" #include "vclk.h" -#include "meson-eeclk.h" +#include "meson-clkc-utils.h" #include @@ -5360,26 +5360,26 @@ static int g12a_dvfs_setup(struct platform_device *pdev) } struct g12a_clkc_data { - const struct meson_eeclkc_data eeclkc_data; + const struct meson_clkc_data clkc_data; int (*dvfs_setup)(struct platform_device *pdev); }; static int g12a_clkc_probe(struct platform_device *pdev) { - const struct meson_eeclkc_data *eeclkc_data; + const struct meson_clkc_data *clkc_data; const struct g12a_clkc_data *g12a_data; int ret; - eeclkc_data = of_device_get_match_data(&pdev->dev); - if (!eeclkc_data) + clkc_data = of_device_get_match_data(&pdev->dev); + if (!clkc_data) return -EINVAL; - ret = meson_eeclkc_probe(pdev); + ret = meson_clkc_syscon_probe(pdev); if (ret) return ret; - g12a_data = container_of(eeclkc_data, struct g12a_clkc_data, - eeclkc_data); + g12a_data = container_of(clkc_data, struct g12a_clkc_data, + clkc_data); if (g12a_data->dvfs_setup) return g12a_data->dvfs_setup(pdev); @@ -5388,7 +5388,7 @@ static int g12a_clkc_probe(struct platform_device *pdev) } static const struct g12a_clkc_data g12a_clkc_data = { - .eeclkc_data = { + .clkc_data = { .hw_clks = { .hws = g12a_hw_clks, .num = ARRAY_SIZE(g12a_hw_clks), @@ -5400,7 +5400,7 @@ static const struct g12a_clkc_data g12a_clkc_data = { }; static const struct g12a_clkc_data g12b_clkc_data = { - .eeclkc_data = { + .clkc_data = { .hw_clks = { .hws = g12b_hw_clks, .num = ARRAY_SIZE(g12b_hw_clks), @@ -5410,7 +5410,7 @@ static const struct g12a_clkc_data g12b_clkc_data = { }; static const struct g12a_clkc_data sm1_clkc_data = { - .eeclkc_data = { + .clkc_data = { .hw_clks = { .hws = sm1_hw_clks, .num = ARRAY_SIZE(sm1_hw_clks), @@ -5422,15 +5422,15 @@ static const struct g12a_clkc_data sm1_clkc_data = { static const struct of_device_id g12a_clkc_match_table[] = { { .compatible = "amlogic,g12a-clkc", - .data = &g12a_clkc_data.eeclkc_data + .data = &g12a_clkc_data.clkc_data }, { .compatible = "amlogic,g12b-clkc", - .data = &g12b_clkc_data.eeclkc_data + .data = &g12b_clkc_data.clkc_data }, { .compatible = "amlogic,sm1-clkc", - .data = &sm1_clkc_data.eeclkc_data + .data = &sm1_clkc_data.clkc_data }, {} }; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 2ad29c7cd6cf..608c2cd34a45 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -13,7 +13,7 @@ #include "clk-regmap.h" #include "clk-pll.h" #include "clk-mpll.h" -#include "meson-eeclk.h" +#include "meson-clkc-utils.h" #include "vid-pll-div.h" #include @@ -3234,14 +3234,14 @@ static struct clk_hw *gxl_hw_clks[] = { [CLKID_ACODEC] = &gxl_acodec.hw, }; -static const struct meson_eeclkc_data gxbb_clkc_data = { +static const struct meson_clkc_data gxbb_clkc_data = { .hw_clks = { .hws = gxbb_hw_clks, .num = ARRAY_SIZE(gxbb_hw_clks), }, }; -static const struct meson_eeclkc_data gxl_clkc_data = { +static const struct meson_clkc_data gxl_clkc_data = { .hw_clks = { .hws = gxl_hw_clks, .num = ARRAY_SIZE(gxl_hw_clks), @@ -3256,7 +3256,7 @@ static const struct of_device_id gxbb_clkc_match_table[] = { MODULE_DEVICE_TABLE(of, gxbb_clkc_match_table); static struct platform_driver gxbb_clkc_driver = { - .probe = meson_eeclkc_probe, + .probe = meson_clkc_syscon_probe, .driver = { .name = "gxbb-clkc", .of_match_table = gxbb_clkc_match_table, diff --git a/drivers/clk/meson/meson-clkc-utils.c b/drivers/clk/meson/meson-clkc-utils.c index 6937d1482719..49f562d0f203 100644 --- a/drivers/clk/meson/meson-clkc-utils.c +++ b/drivers/clk/meson/meson-clkc-utils.c @@ -3,9 +3,13 @@ * Copyright (c) 2023 Neil Armstrong */ -#include #include +#include #include +#include +#include +#include + #include "meson-clkc-utils.h" struct clk_hw *meson_clk_hw_get(struct of_phandle_args *clkspec, void *clk_hw_data) @@ -22,6 +26,50 @@ struct clk_hw *meson_clk_hw_get(struct of_phandle_args *clkspec, void *clk_hw_da } EXPORT_SYMBOL_NS_GPL(meson_clk_hw_get, "CLK_MESON"); +int meson_clkc_syscon_probe(struct platform_device *pdev) +{ + const struct meson_clkc_data *data; + struct device *dev = &pdev->dev; + struct device_node *np; + struct regmap *map; + struct clk_hw *hw; + int ret, i; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + np = of_get_parent(dev->of_node); + map = syscon_node_to_regmap(np); + of_node_put(np); + if (IS_ERR(map)) { + dev_err(dev, + "failed to get parent syscon regmap\n"); + return PTR_ERR(map); + } + + if (data->init_count) + regmap_multi_reg_write(map, data->init_regs, data->init_count); + + for (i = 0; i < data->hw_clks.num; i++) { + hw = data->hw_clks.hws[i]; + + /* array might be sparse */ + if (!hw) + continue; + + ret = devm_clk_hw_register(dev, hw); + if (ret) { + dev_err(dev, "registering %s clock failed\n", + hw->init->name); + return ret; + } + } + + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks); +} +EXPORT_SYMBOL_NS_GPL(meson_clkc_syscon_probe, "CLK_MESON"); + MODULE_DESCRIPTION("Amlogic Clock Controller Utilities"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/meson-clkc-utils.h b/drivers/clk/meson/meson-clkc-utils.h index fe6f40728949..26cd47544302 100644 --- a/drivers/clk/meson/meson-clkc-utils.h +++ b/drivers/clk/meson/meson-clkc-utils.h @@ -9,6 +9,8 @@ #include #include +struct platform_device; + struct meson_clk_hw_data { struct clk_hw **hws; unsigned int num; @@ -16,4 +18,12 @@ struct meson_clk_hw_data { struct clk_hw *meson_clk_hw_get(struct of_phandle_args *clkspec, void *clk_hw_data); +struct meson_clkc_data { + const struct reg_sequence *init_regs; + unsigned int init_count; + struct meson_clk_hw_data hw_clks; +}; + +int meson_clkc_syscon_probe(struct platform_device *pdev); + #endif diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c deleted file mode 100644 index 6236bf970d79..000000000000 --- a/drivers/clk/meson/meson-eeclk.c +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2019 BayLibre, SAS. - * Author: Jerome Brunet - */ - -#include -#include -#include -#include -#include -#include - -#include "clk-regmap.h" -#include "meson-eeclk.h" - -int meson_eeclkc_probe(struct platform_device *pdev) -{ - const struct meson_eeclkc_data *data; - struct device *dev = &pdev->dev; - struct device_node *np; - struct regmap *map; - int ret, i; - - data = of_device_get_match_data(dev); - if (!data) - return -EINVAL; - - /* Get the hhi system controller node */ - np = of_get_parent(dev->of_node); - map = syscon_node_to_regmap(np); - of_node_put(np); - if (IS_ERR(map)) { - dev_err(dev, - "failed to get HHI regmap\n"); - return PTR_ERR(map); - } - - if (data->init_count) - regmap_multi_reg_write(map, data->init_regs, data->init_count); - - for (i = 0; i < data->hw_clks.num; i++) { - /* array might be sparse */ - if (!data->hw_clks.hws[i]) - continue; - - ret = devm_clk_hw_register(dev, data->hw_clks.hws[i]); - if (ret) { - dev_err(dev, "Clock registration failed\n"); - return ret; - } - } - - return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks); -} -EXPORT_SYMBOL_NS_GPL(meson_eeclkc_probe, "CLK_MESON"); - -MODULE_DESCRIPTION("Amlogic Main Clock Controller Helpers"); -MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/meson-eeclk.h b/drivers/clk/meson/meson-eeclk.h deleted file mode 100644 index 6a81d67b46b2..000000000000 --- a/drivers/clk/meson/meson-eeclk.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2019 BayLibre, SAS. - * Author: Jerome Brunet - */ - -#ifndef __MESON_CLKC_H -#define __MESON_CLKC_H - -#include -#include "clk-regmap.h" -#include "meson-clkc-utils.h" - -struct platform_device; - -struct meson_eeclkc_data { - const struct reg_sequence *init_regs; - unsigned int init_count; - struct meson_clk_hw_data hw_clks; -}; - -int meson_eeclkc_probe(struct platform_device *pdev); - -#endif /* __MESON_CLKC_H */ From 480197ceece792b887a6f3361080a030eb8e4846 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:27 +0200 Subject: [PATCH 0823/2711] clk: amlogic: add probe helper for mmio based controllers Add a 2nd probe function helper for mmio based controllers, which are getting the memory region from a resource instead of a syscon. Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-2-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/meson-clkc-utils.c | 62 ++++++++++++++++++++++------ drivers/clk/meson/meson-clkc-utils.h | 1 + 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/drivers/clk/meson/meson-clkc-utils.c b/drivers/clk/meson/meson-clkc-utils.c index 49f562d0f203..870f50548e26 100644 --- a/drivers/clk/meson/meson-clkc-utils.c +++ b/drivers/clk/meson/meson-clkc-utils.c @@ -26,12 +26,9 @@ struct clk_hw *meson_clk_hw_get(struct of_phandle_args *clkspec, void *clk_hw_da } EXPORT_SYMBOL_NS_GPL(meson_clk_hw_get, "CLK_MESON"); -int meson_clkc_syscon_probe(struct platform_device *pdev) +static int meson_clkc_init(struct device *dev, struct regmap *map) { const struct meson_clkc_data *data; - struct device *dev = &pdev->dev; - struct device_node *np; - struct regmap *map; struct clk_hw *hw; int ret, i; @@ -39,15 +36,6 @@ int meson_clkc_syscon_probe(struct platform_device *pdev) if (!data) return -EINVAL; - np = of_get_parent(dev->of_node); - map = syscon_node_to_regmap(np); - of_node_put(np); - if (IS_ERR(map)) { - dev_err(dev, - "failed to get parent syscon regmap\n"); - return PTR_ERR(map); - } - if (data->init_count) regmap_multi_reg_write(map, data->init_regs, data->init_count); @@ -68,8 +56,56 @@ int meson_clkc_syscon_probe(struct platform_device *pdev) return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks); } + +int meson_clkc_syscon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np; + struct regmap *map; + + np = of_get_parent(dev->of_node); + map = syscon_node_to_regmap(np); + of_node_put(np); + if (IS_ERR(map)) { + dev_err(dev, "failed to get parent syscon regmap\n"); + return PTR_ERR(map); + } + + return meson_clkc_init(dev, map); +} EXPORT_SYMBOL_NS_GPL(meson_clkc_syscon_probe, "CLK_MESON"); +int meson_clkc_mmio_probe(struct platform_device *pdev) +{ + const struct meson_clkc_data *data; + struct device *dev = &pdev->dev; + struct resource *res; + void __iomem *base; + struct regmap *map; + struct regmap_config regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + }; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap_cfg.max_register = resource_size(res) - regmap_cfg.reg_stride; + + map = devm_regmap_init_mmio(dev, base, ®map_cfg); + if (IS_ERR(map)) + return PTR_ERR(map); + + return meson_clkc_init(dev, map); +} +EXPORT_SYMBOL_NS_GPL(meson_clkc_mmio_probe, "CLK_MESON"); + MODULE_DESCRIPTION("Amlogic Clock Controller Utilities"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/meson-clkc-utils.h b/drivers/clk/meson/meson-clkc-utils.h index 26cd47544302..b45f85f630d7 100644 --- a/drivers/clk/meson/meson-clkc-utils.h +++ b/drivers/clk/meson/meson-clkc-utils.h @@ -25,5 +25,6 @@ struct meson_clkc_data { }; int meson_clkc_syscon_probe(struct platform_device *pdev); +int meson_clkc_mmio_probe(struct platform_device *pdev); #endif From d7c001bd76b7f7e6c05f615d472b5daadc87b434 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:28 +0200 Subject: [PATCH 0824/2711] clk: amlogic: use probe helper in mmio based controllers Factorize the probe function of the mmio based amlogic clock controllers using the newly introduced probe helper. This removes a fair amount of duplicated code. Reviewed-by: Chuan Liu Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-3-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/a1-peripherals.c | 50 ++++++-------------------- drivers/clk/meson/a1-pll.c | 52 ++++++--------------------- drivers/clk/meson/c3-peripherals.c | 49 ++++--------------------- drivers/clk/meson/c3-pll.c | 49 ++++--------------------- drivers/clk/meson/meson8-ddr.c | 57 +++++++---------------------- drivers/clk/meson/s4-peripherals.c | 49 ++++--------------------- drivers/clk/meson/s4-pll.c | 58 +++++------------------------- 7 files changed, 63 insertions(+), 301 deletions(-) diff --git a/drivers/clk/meson/a1-peripherals.c b/drivers/clk/meson/a1-peripherals.c index 9e352dba5477..b2feb8fe4775 100644 --- a/drivers/clk/meson/a1-peripherals.c +++ b/drivers/clk/meson/a1-peripherals.c @@ -2057,54 +2057,24 @@ static struct clk_hw *a1_peripherals_hw_clks[] = { [CLKID_DMC_SEL2] = &a1_dmc_sel2.hw, }; -static const struct regmap_config a1_peripherals_regmap_cfg = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = DMC_CLK_CTRL, +static const struct meson_clkc_data a1_peripherals_clkc_data = { + .hw_clks = { + .hws = a1_peripherals_hw_clks, + .num = ARRAY_SIZE(a1_peripherals_hw_clks), + }, }; -static struct meson_clk_hw_data a1_peripherals_clks = { - .hws = a1_peripherals_hw_clks, - .num = ARRAY_SIZE(a1_peripherals_hw_clks), -}; - -static int a1_peripherals_clkc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - void __iomem *base; - struct regmap *map; - int clkid, err; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return dev_err_probe(dev, PTR_ERR(base), - "can't ioremap resource\n"); - - map = devm_regmap_init_mmio(dev, base, &a1_peripherals_regmap_cfg); - if (IS_ERR(map)) - return dev_err_probe(dev, PTR_ERR(map), - "can't init regmap mmio region\n"); - - for (clkid = 0; clkid < a1_peripherals_clks.num; clkid++) { - err = devm_clk_hw_register(dev, a1_peripherals_clks.hws[clkid]); - if (err) - return dev_err_probe(dev, err, - "clock[%d] registration failed\n", - clkid); - } - - return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, &a1_peripherals_clks); -} - static const struct of_device_id a1_peripherals_clkc_match_table[] = { - { .compatible = "amlogic,a1-peripherals-clkc", }, + { + .compatible = "amlogic,a1-peripherals-clkc", + .data = &a1_peripherals_clkc_data, + }, {} }; MODULE_DEVICE_TABLE(of, a1_peripherals_clkc_match_table); static struct platform_driver a1_peripherals_clkc_driver = { - .probe = a1_peripherals_clkc_probe, + .probe = meson_clkc_mmio_probe, .driver = { .name = "a1-peripherals-clkc", .of_match_table = a1_peripherals_clkc_match_table, diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c index 79ef4cbe9553..1f82e9c7c14e 100644 --- a/drivers/clk/meson/a1-pll.c +++ b/drivers/clk/meson/a1-pll.c @@ -295,56 +295,24 @@ static struct clk_hw *a1_pll_hw_clks[] = { [CLKID_HIFI_PLL] = &a1_hifi_pll.hw, }; -static const struct regmap_config a1_pll_regmap_cfg = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = ANACTRL_HIFIPLL_STS, +static const struct meson_clkc_data a1_pll_clkc_data = { + .hw_clks = { + .hws = a1_pll_hw_clks, + .num = ARRAY_SIZE(a1_pll_hw_clks), + }, }; -static struct meson_clk_hw_data a1_pll_clks = { - .hws = a1_pll_hw_clks, - .num = ARRAY_SIZE(a1_pll_hw_clks), -}; - -static int a1_pll_clkc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - void __iomem *base; - struct regmap *map; - int clkid, err; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return dev_err_probe(dev, PTR_ERR(base), - "can't ioremap resource\n"); - - map = devm_regmap_init_mmio(dev, base, &a1_pll_regmap_cfg); - if (IS_ERR(map)) - return dev_err_probe(dev, PTR_ERR(map), - "can't init regmap mmio region\n"); - - /* Register clocks */ - for (clkid = 0; clkid < a1_pll_clks.num; clkid++) { - err = devm_clk_hw_register(dev, a1_pll_clks.hws[clkid]); - if (err) - return dev_err_probe(dev, err, - "clock[%d] registration failed\n", - clkid); - } - - return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, - &a1_pll_clks); -} - static const struct of_device_id a1_pll_clkc_match_table[] = { - { .compatible = "amlogic,a1-pll-clkc", }, + { + .compatible = "amlogic,a1-pll-clkc", + .data = &a1_pll_clkc_data, + }, {} }; MODULE_DEVICE_TABLE(of, a1_pll_clkc_match_table); static struct platform_driver a1_pll_clkc_driver = { - .probe = a1_pll_clkc_probe, + .probe = meson_clkc_mmio_probe, .driver = { .name = "a1-pll-clkc", .of_match_table = a1_pll_clkc_match_table, diff --git a/drivers/clk/meson/c3-peripherals.c b/drivers/clk/meson/c3-peripherals.c index a09cb1435ab1..e9c1ef99be13 100644 --- a/drivers/clk/meson/c3-peripherals.c +++ b/drivers/clk/meson/c3-peripherals.c @@ -2091,52 +2091,17 @@ static struct clk_hw *c3_peripherals_hw_clks[] = { [CLKID_VAPB] = &c3_vapb.hw, }; -static const struct regmap_config c3_peripherals_regmap_cfg = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = NNA_CLK_CTRL, +static const struct meson_clkc_data c3_peripherals_clkc_data = { + .hw_clks = { + .hws = c3_peripherals_hw_clks, + .num = ARRAY_SIZE(c3_peripherals_hw_clks), + }, }; -static struct meson_clk_hw_data c3_peripherals_clks = { - .hws = c3_peripherals_hw_clks, - .num = ARRAY_SIZE(c3_peripherals_hw_clks), -}; - -static int c3_peripherals_clkc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct regmap *regmap; - void __iomem *base; - int clkid, ret; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &c3_peripherals_regmap_cfg); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - for (clkid = 0; clkid < c3_peripherals_clks.num; clkid++) { - /* array might be sparse */ - if (!c3_peripherals_clks.hws[clkid]) - continue; - - ret = devm_clk_hw_register(dev, c3_peripherals_clks.hws[clkid]); - if (ret) { - dev_err(dev, "Clock registration failed\n"); - return ret; - } - } - - return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, - &c3_peripherals_clks); -} - static const struct of_device_id c3_peripherals_clkc_match_table[] = { { .compatible = "amlogic,c3-peripherals-clkc", + .data = &c3_peripherals_clkc_data, }, { /* sentinel */ } }; @@ -2144,7 +2109,7 @@ static const struct of_device_id c3_peripherals_clkc_match_table[] = { MODULE_DEVICE_TABLE(of, c3_peripherals_clkc_match_table); static struct platform_driver c3_peripherals_clkc_driver = { - .probe = c3_peripherals_clkc_probe, + .probe = meson_clkc_mmio_probe, .driver = { .name = "c3-peripherals-clkc", .of_match_table = c3_peripherals_clkc_match_table, diff --git a/drivers/clk/meson/c3-pll.c b/drivers/clk/meson/c3-pll.c index ccfcd4b5be89..dd047d17488c 100644 --- a/drivers/clk/meson/c3-pll.c +++ b/drivers/clk/meson/c3-pll.c @@ -653,59 +653,24 @@ static struct clk_hw *c3_pll_hw_clks[] = { [CLKID_MCLK1] = &c3_mclk1.hw }; -static const struct regmap_config c3_pll_regmap_cfg = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = ANACTRL_MPLL_CTRL4, +static const struct meson_clkc_data c3_pll_clkc_data = { + .hw_clks = { + .hws = c3_pll_hw_clks, + .num = ARRAY_SIZE(c3_pll_hw_clks), + }, }; -static struct meson_clk_hw_data c3_pll_clks = { - .hws = c3_pll_hw_clks, - .num = ARRAY_SIZE(c3_pll_hw_clks), -}; - -static int c3_pll_clkc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct regmap *regmap; - void __iomem *base; - int clkid, ret; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &c3_pll_regmap_cfg); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - for (clkid = 0; clkid < c3_pll_clks.num; clkid++) { - /* array might be sparse */ - if (!c3_pll_clks.hws[clkid]) - continue; - - ret = devm_clk_hw_register(dev, c3_pll_clks.hws[clkid]); - if (ret) { - dev_err(dev, "Clock registration failed\n"); - return ret; - } - } - - return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, - &c3_pll_clks); -} - static const struct of_device_id c3_pll_clkc_match_table[] = { { .compatible = "amlogic,c3-pll-clkc", + .data = &c3_pll_clkc_data, }, {} }; MODULE_DEVICE_TABLE(of, c3_pll_clkc_match_table); static struct platform_driver c3_pll_clkc_driver = { - .probe = c3_pll_clkc_probe, + .probe = meson_clkc_mmio_probe, .driver = { .name = "c3-pll-clkc", .of_match_table = c3_pll_clkc_match_table, diff --git a/drivers/clk/meson/meson8-ddr.c b/drivers/clk/meson/meson8-ddr.c index 6a9efde9b570..0f93774f7371 100644 --- a/drivers/clk/meson/meson8-ddr.c +++ b/drivers/clk/meson/meson8-ddr.c @@ -83,57 +83,26 @@ static struct clk_hw *meson8_ddr_hw_clks[] = { [DDR_CLKID_DDR_PLL] = &meson8_ddr_pll.hw, }; -static struct meson_clk_hw_data meson8_ddr_clks = { - .hws = meson8_ddr_hw_clks, - .num = ARRAY_SIZE(meson8_ddr_hw_clks), +static const struct meson_clkc_data meson8_ddr_clkc_data = { + .hw_clks = { + .hws = meson8_ddr_hw_clks, + .num = ARRAY_SIZE(meson8_ddr_hw_clks), + }, }; -static const struct regmap_config meson8_ddr_regmap_cfg = { - .reg_bits = 8, - .val_bits = 32, - .reg_stride = 4, - .max_register = DDR_CLK_STS, -}; - -static int meson8_ddr_clkc_probe(struct platform_device *pdev) -{ - struct regmap *regmap; - void __iomem *base; - struct clk_hw *hw; - int ret, i; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(&pdev->dev, base, - &meson8_ddr_regmap_cfg); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - /* Register all clks */ - for (i = 0; i < meson8_ddr_clks.num; i++) { - hw = meson8_ddr_clks.hws[i]; - - ret = devm_clk_hw_register(&pdev->dev, hw); - if (ret) { - dev_err(&pdev->dev, "Clock registration failed\n"); - return ret; - } - } - - return devm_of_clk_add_hw_provider(&pdev->dev, meson_clk_hw_get, - &meson8_ddr_clks); -} - static const struct of_device_id meson8_ddr_clkc_match_table[] = { - { .compatible = "amlogic,meson8-ddr-clkc" }, - { .compatible = "amlogic,meson8b-ddr-clkc" }, + { + .compatible = "amlogic,meson8-ddr-clkc", + .data = &meson8_ddr_clkc_data, + }, { + .compatible = "amlogic,meson8b-ddr-clkc", + .data = &meson8_ddr_clkc_data, + }, { /* sentinel */ } }; static struct platform_driver meson8_ddr_clkc_driver = { - .probe = meson8_ddr_clkc_probe, + .probe = meson_clkc_mmio_probe, .driver = { .name = "meson8-ddr-clkc", .of_match_table = meson8_ddr_clkc_match_table, diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c index 9bcd35f12836..fc1500df926d 100644 --- a/drivers/clk/meson/s4-peripherals.c +++ b/drivers/clk/meson/s4-peripherals.c @@ -3449,59 +3449,24 @@ static struct clk_hw *s4_peripherals_hw_clks[] = { [CLKID_HDCP22_SKPCLK] = &s4_hdcp22_skpclk.hw, }; -static const struct regmap_config s4_peripherals_regmap_cfg = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = CLKCTRL_DEMOD_CLK_CTRL, +static const struct meson_clkc_data s4_peripherals_clkc_data = { + .hw_clks = { + .hws = s4_peripherals_hw_clks, + .num = ARRAY_SIZE(s4_peripherals_hw_clks), + }, }; -static struct meson_clk_hw_data s4_peripherals_clks = { - .hws = s4_peripherals_hw_clks, - .num = ARRAY_SIZE(s4_peripherals_hw_clks), -}; - -static int s4_peripherals_clkc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct regmap *regmap; - void __iomem *base; - int ret, i; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return dev_err_probe(dev, PTR_ERR(base), - "can't ioremap resource\n"); - - regmap = devm_regmap_init_mmio(dev, base, &s4_peripherals_regmap_cfg); - if (IS_ERR(regmap)) - return dev_err_probe(dev, PTR_ERR(regmap), - "can't init regmap mmio region\n"); - - for (i = 0; i < s4_peripherals_clks.num; i++) { - /* array might be sparse */ - if (!s4_peripherals_clks.hws[i]) - continue; - - ret = devm_clk_hw_register(dev, s4_peripherals_clks.hws[i]); - if (ret) - return dev_err_probe(dev, ret, - "clock[%d] registration failed\n", i); - } - - return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, &s4_peripherals_clks); -} - static const struct of_device_id s4_peripherals_clkc_match_table[] = { { .compatible = "amlogic,s4-peripherals-clkc", + .data = &s4_peripherals_clkc_data, }, {} }; MODULE_DEVICE_TABLE(of, s4_peripherals_clkc_match_table); static struct platform_driver s4_peripherals_clkc_driver = { - .probe = s4_peripherals_clkc_probe, + .probe = meson_clkc_mmio_probe, .driver = { .name = "s4-peripherals-clkc", .of_match_table = s4_peripherals_clkc_match_table, diff --git a/drivers/clk/meson/s4-pll.c b/drivers/clk/meson/s4-pll.c index 6a266bcafd62..56ce6f566e53 100644 --- a/drivers/clk/meson/s4-pll.c +++ b/drivers/clk/meson/s4-pll.c @@ -798,66 +798,26 @@ static const struct reg_sequence s4_pll_init_regs[] = { { .reg = ANACTRL_MPLL_CTRL0, .def = 0x00000543 }, }; -static const struct regmap_config s4_pll_clkc_regmap_cfg = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = ANACTRL_HDMIPLL_CTRL0, +static const struct meson_clkc_data s4_pll_clkc_data = { + .hw_clks = { + .hws = s4_pll_hw_clks, + .num = ARRAY_SIZE(s4_pll_hw_clks), + }, + .init_regs = s4_pll_init_regs, + .init_count = ARRAY_SIZE(s4_pll_init_regs), }; -static struct meson_clk_hw_data s4_pll_clks = { - .hws = s4_pll_hw_clks, - .num = ARRAY_SIZE(s4_pll_hw_clks), -}; - -static int s4_pll_clkc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct regmap *regmap; - void __iomem *base; - int ret, i; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return dev_err_probe(dev, PTR_ERR(base), - "can't ioremap resource\n"); - - regmap = devm_regmap_init_mmio(dev, base, &s4_pll_clkc_regmap_cfg); - if (IS_ERR(regmap)) - return dev_err_probe(dev, PTR_ERR(regmap), - "can't init regmap mmio region\n"); - - ret = regmap_multi_reg_write(regmap, s4_pll_init_regs, ARRAY_SIZE(s4_pll_init_regs)); - if (ret) - return dev_err_probe(dev, ret, - "Failed to init registers\n"); - - /* Register clocks */ - for (i = 0; i < s4_pll_clks.num; i++) { - /* array might be sparse */ - if (!s4_pll_clks.hws[i]) - continue; - - ret = devm_clk_hw_register(dev, s4_pll_clks.hws[i]); - if (ret) - return dev_err_probe(dev, ret, - "clock[%d] registration failed\n", i); - } - - return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, - &s4_pll_clks); -} - static const struct of_device_id s4_pll_clkc_match_table[] = { { .compatible = "amlogic,s4-pll-clkc", + .data = &s4_pll_clkc_data, }, {} }; MODULE_DEVICE_TABLE(of, s4_pll_clkc_match_table); static struct platform_driver s4_pll_clkc_driver = { - .probe = s4_pll_clkc_probe, + .probe = meson_clkc_mmio_probe, .driver = { .name = "s4-pll-clkc", .of_match_table = s4_pll_clkc_match_table, From 2aeeb649ead230c37415891c89bade3a8ad9eb0b Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:29 +0200 Subject: [PATCH 0825/2711] clk: amlogic: aoclk: use clkc-utils syscon probe The clock related part of aoclk probe function duplicates what the clkc-utils syscon helper does. Factorize this to have a single path to maintain. Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-4-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg-aoclk.c | 10 ++++++---- drivers/clk/meson/g12a-aoclk.c | 10 ++++++---- drivers/clk/meson/gxbb-aoclk.c | 10 ++++++---- drivers/clk/meson/meson-aoclk.c | 32 ++++++++++++++------------------ drivers/clk/meson/meson-aoclk.h | 2 +- 5 files changed, 33 insertions(+), 31 deletions(-) diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index a0c58dc8e950..efc33fd18c19 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -300,16 +300,18 @@ static const struct meson_aoclk_data axg_ao_clkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(axg_ao_reset), .reset = axg_ao_reset, - .hw_clks = { - .hws = axg_ao_hw_clks, - .num = ARRAY_SIZE(axg_ao_hw_clks), + .clkc_data = { + .hw_clks = { + .hws = axg_ao_hw_clks, + .num = ARRAY_SIZE(axg_ao_hw_clks), + }, }, }; static const struct of_device_id axg_ao_clkc_match_table[] = { { .compatible = "amlogic,meson-axg-aoclkc", - .data = &axg_ao_clkc_data, + .data = &axg_ao_clkc_data.clkc_data, }, { } }; diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c index 3eaf1db16f45..872a7b800bb8 100644 --- a/drivers/clk/meson/g12a-aoclk.c +++ b/drivers/clk/meson/g12a-aoclk.c @@ -424,16 +424,18 @@ static const struct meson_aoclk_data g12a_ao_clkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(g12a_ao_reset), .reset = g12a_ao_reset, - .hw_clks = { - .hws = g12a_ao_hw_clks, - .num = ARRAY_SIZE(g12a_ao_hw_clks), + .clkc_data = { + .hw_clks = { + .hws = g12a_ao_hw_clks, + .num = ARRAY_SIZE(g12a_ao_hw_clks), + }, }, }; static const struct of_device_id g12a_ao_clkc_match_table[] = { { .compatible = "amlogic,meson-g12a-aoclkc", - .data = &g12a_ao_clkc_data, + .data = &g12a_ao_clkc_data.clkc_data, }, { } }; diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 11b11fa7791e..ce8d2e9e0717 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -258,16 +258,18 @@ static const struct meson_aoclk_data gxbb_ao_clkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(gxbb_ao_reset), .reset = gxbb_ao_reset, - .hw_clks = { - .hws = gxbb_ao_hw_clks, - .num = ARRAY_SIZE(gxbb_ao_hw_clks), + .clkc_data = { + .hw_clks = { + .hws = gxbb_ao_hw_clks, + .num = ARRAY_SIZE(gxbb_ao_hw_clks), + }, }, }; static const struct of_device_id gxbb_ao_clkc_match_table[] = { { .compatible = "amlogic,meson-gx-aoclkc", - .data = &gxbb_ao_clkc_data, + .data = &gxbb_ao_clkc_data.clkc_data, }, { } }; diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c index 894c02fda072..8f6bdea18119 100644 --- a/drivers/clk/meson/meson-aoclk.c +++ b/drivers/clk/meson/meson-aoclk.c @@ -37,15 +37,23 @@ static const struct reset_control_ops meson_aoclk_reset_ops = { int meson_aoclkc_probe(struct platform_device *pdev) { struct meson_aoclk_reset_controller *rstc; - struct meson_aoclk_data *data; + const struct meson_clkc_data *clkc_data; + const struct meson_aoclk_data *data; struct device *dev = &pdev->dev; struct device_node *np; struct regmap *regmap; - int ret, clkid; + int ret; - data = (struct meson_aoclk_data *) of_device_get_match_data(dev); - if (!data) - return -ENODEV; + clkc_data = of_device_get_match_data(dev); + if (!clkc_data) + return -EINVAL; + + ret = meson_clkc_syscon_probe(pdev); + if (ret) + return ret; + + data = container_of(clkc_data, struct meson_aoclk_data, + clkc_data); rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL); if (!rstc) @@ -71,19 +79,7 @@ int meson_aoclkc_probe(struct platform_device *pdev) return ret; } - /* Register all clks */ - for (clkid = 0; clkid < data->hw_clks.num; clkid++) { - if (!data->hw_clks.hws[clkid]) - continue; - - ret = devm_clk_hw_register(dev, data->hw_clks.hws[clkid]); - if (ret) { - dev_err(dev, "Clock registration failed\n"); - return ret; - } - } - - return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks); + return 0; } EXPORT_SYMBOL_NS_GPL(meson_aoclkc_probe, "CLK_MESON"); diff --git a/drivers/clk/meson/meson-aoclk.h b/drivers/clk/meson/meson-aoclk.h index ea5fc61308af..2c83e73d3a77 100644 --- a/drivers/clk/meson/meson-aoclk.h +++ b/drivers/clk/meson/meson-aoclk.h @@ -20,10 +20,10 @@ #include "meson-clkc-utils.h" struct meson_aoclk_data { + const struct meson_clkc_data clkc_data; const unsigned int reset_reg; const int num_reset; const unsigned int *reset; - struct meson_clk_hw_data hw_clks; }; struct meson_aoclk_reset_controller { From 32ee5475f7e34fbd6539998a4e5f9bd05486672e Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:30 +0200 Subject: [PATCH 0826/2711] clk: amlogic: move PCLK definition to clkc-utils clk-regmap was always meant to stay generic, without any amlogic specifics. The hope was that it could move out of the amlogic directory one day. Even if this may actually not become true, it should remain generic. Move the amlogic peripheral clock definition out of clk-regmap header. Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-5-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/clk-regmap.h | 20 -------------------- drivers/clk/meson/meson-clkc-utils.h | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/clk/meson/clk-regmap.h b/drivers/clk/meson/clk-regmap.h index f8cac2df5755..8e5c39b023e1 100644 --- a/drivers/clk/meson/clk-regmap.h +++ b/drivers/clk/meson/clk-regmap.h @@ -118,24 +118,4 @@ clk_get_regmap_mux_data(struct clk_regmap *clk) extern const struct clk_ops clk_regmap_mux_ops; extern const struct clk_ops clk_regmap_mux_ro_ops; -#define __MESON_PCLK(_name, _reg, _bit, _ops, _pname) \ -struct clk_regmap _name = { \ - .data = &(struct clk_regmap_gate_data){ \ - .offset = (_reg), \ - .bit_idx = (_bit), \ - }, \ - .hw.init = &(struct clk_init_data) { \ - .name = #_name, \ - .ops = _ops, \ - .parent_hws = (const struct clk_hw *[]) { _pname }, \ - .num_parents = 1, \ - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ - }, \ -} - -#define MESON_PCLK(_name, _reg, _bit, _pname) \ - __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ops, _pname) - -#define MESON_PCLK_RO(_name, _reg, _bit, _pname) \ - __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pname) #endif /* __CLK_REGMAP_H */ diff --git a/drivers/clk/meson/meson-clkc-utils.h b/drivers/clk/meson/meson-clkc-utils.h index b45f85f630d7..0c228a6723bb 100644 --- a/drivers/clk/meson/meson-clkc-utils.h +++ b/drivers/clk/meson/meson-clkc-utils.h @@ -27,4 +27,25 @@ struct meson_clkc_data { int meson_clkc_syscon_probe(struct platform_device *pdev); int meson_clkc_mmio_probe(struct platform_device *pdev); +#define __MESON_PCLK(_name, _reg, _bit, _ops, _pname) \ +struct clk_regmap _name = { \ + .data = &(struct clk_regmap_gate_data) { \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = _ops, \ + .parent_hws = (const struct clk_hw *[]) { _pname }, \ + .num_parents = 1, \ + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + }, \ +} + +#define MESON_PCLK(_name, _reg, _bit, _pname) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ops, _pname) + +#define MESON_PCLK_RO(_name, _reg, _bit, _pname) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pname) + #endif From cf03071b7c3f1537dba21a64bcd1559b5201a156 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:31 +0200 Subject: [PATCH 0827/2711] clk: amlogic: drop CLK_SET_RATE_PARENT from peripheral clocks On Amlogic SoCs, the rate of a peripheral clock should not be changed, let alone the rate of the parent PLL. These clocks are meant to be used as provided by the parent PLL. Changing the rate would be dangerous and would likely break a lot of devices running from the same PLL. Don't propagate any rate change request that may come from these clocks and drop the corresponding flag. Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-6-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/meson-clkc-utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/meson/meson-clkc-utils.h b/drivers/clk/meson/meson-clkc-utils.h index 0c228a6723bb..3e1fb7efe6da 100644 --- a/drivers/clk/meson/meson-clkc-utils.h +++ b/drivers/clk/meson/meson-clkc-utils.h @@ -38,7 +38,7 @@ struct clk_regmap _name = { \ .ops = _ops, \ .parent_hws = (const struct clk_hw *[]) { _pname }, \ .num_parents = 1, \ - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + .flags = CLK_IGNORE_UNUSED, \ }, \ } From c3f369363a138638edd33a6f2fa97b6770a97c96 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:32 +0200 Subject: [PATCH 0828/2711] clk: amlogic: pclk explicitly use CLK_IGNORE_UNUSED Every usage of CLK_IGNORE_UNUSED should be explicitly motivated and documented. However, the PCLK macros used by most Amlogic platforms are adding that flag systematically. Because of this, all pclks are marked with CLK_IGNORE_UNUSED, without any form of distinction or motivation. This may have been fine in the early days of CCF but it is not anymore. Just removing the flag is not an option at this stage since it could cause regression on existing platforms. Instead, drop the flag from the macro definition and add it to the each clock definition, for the existing clocks. This makes quite a nasty change but it will make it a lot easier for people to contribute to fixing the problem, clock by clock. It will also prevent new platform from being added with a silent use of the flag. Reviewed-by: Chuan Liu Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-7-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/a1-peripherals.c | 119 ++++++++++-------- drivers/clk/meson/axg-aoclk.c | 18 +-- drivers/clk/meson/axg.c | 104 +++++++++------- drivers/clk/meson/g12a-aoclk.c | 49 ++++---- drivers/clk/meson/g12a.c | 164 ++++++++++++------------ drivers/clk/meson/gxbb-aoclk.c | 16 +-- drivers/clk/meson/gxbb.c | 180 ++++++++++++++------------- drivers/clk/meson/meson-clkc-utils.h | 12 +- drivers/clk/meson/meson8b.c | 175 ++++++++++++++------------ drivers/clk/meson/s4-peripherals.c | 111 +++++++++-------- 10 files changed, 504 insertions(+), 444 deletions(-) diff --git a/drivers/clk/meson/a1-peripherals.c b/drivers/clk/meson/a1-peripherals.c index b2feb8fe4775..a7bd3822df18 100644 --- a/drivers/clk/meson/a1-peripherals.c +++ b/drivers/clk/meson/a1-peripherals.c @@ -1840,64 +1840,73 @@ static struct clk_regmap a1_cecb_32k_out = { }, }; -#define A1_PCLK(_name, _reg, _bit) \ - MESON_PCLK(a1_##_name, _reg, _bit, &a1_sys.hw) +#define A1_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(a1_##_name, _reg, _bit, &a1_sys.hw, _flags) -static A1_PCLK(clktree, SYS_CLK_EN0, 0); -static A1_PCLK(reset_ctrl, SYS_CLK_EN0, 1); -static A1_PCLK(analog_ctrl, SYS_CLK_EN0, 2); -static A1_PCLK(pwr_ctrl, SYS_CLK_EN0, 3); -static A1_PCLK(pad_ctrl, SYS_CLK_EN0, 4); -static A1_PCLK(sys_ctrl, SYS_CLK_EN0, 5); -static A1_PCLK(temp_sensor, SYS_CLK_EN0, 6); -static A1_PCLK(am2axi_dev, SYS_CLK_EN0, 7); -static A1_PCLK(spicc_b, SYS_CLK_EN0, 8); -static A1_PCLK(spicc_a, SYS_CLK_EN0, 9); -static A1_PCLK(msr, SYS_CLK_EN0, 10); -static A1_PCLK(audio, SYS_CLK_EN0, 11); -static A1_PCLK(jtag_ctrl, SYS_CLK_EN0, 12); -static A1_PCLK(saradc_en, SYS_CLK_EN0, 13); -static A1_PCLK(pwm_ef, SYS_CLK_EN0, 14); -static A1_PCLK(pwm_cd, SYS_CLK_EN0, 15); -static A1_PCLK(pwm_ab, SYS_CLK_EN0, 16); -static A1_PCLK(cec, SYS_CLK_EN0, 17); -static A1_PCLK(i2c_s, SYS_CLK_EN0, 18); -static A1_PCLK(ir_ctrl, SYS_CLK_EN0, 19); -static A1_PCLK(i2c_m_d, SYS_CLK_EN0, 20); -static A1_PCLK(i2c_m_c, SYS_CLK_EN0, 21); -static A1_PCLK(i2c_m_b, SYS_CLK_EN0, 22); -static A1_PCLK(i2c_m_a, SYS_CLK_EN0, 23); -static A1_PCLK(acodec, SYS_CLK_EN0, 24); -static A1_PCLK(otp, SYS_CLK_EN0, 25); -static A1_PCLK(sd_emmc_a, SYS_CLK_EN0, 26); -static A1_PCLK(usb_phy, SYS_CLK_EN0, 27); -static A1_PCLK(usb_ctrl, SYS_CLK_EN0, 28); -static A1_PCLK(sys_dspb, SYS_CLK_EN0, 29); -static A1_PCLK(sys_dspa, SYS_CLK_EN0, 30); -static A1_PCLK(dma, SYS_CLK_EN0, 31); +/* + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static A1_PCLK(clktree, SYS_CLK_EN0, 0, CLK_IGNORE_UNUSED); +static A1_PCLK(reset_ctrl, SYS_CLK_EN0, 1, CLK_IGNORE_UNUSED); +static A1_PCLK(analog_ctrl, SYS_CLK_EN0, 2, CLK_IGNORE_UNUSED); +static A1_PCLK(pwr_ctrl, SYS_CLK_EN0, 3, CLK_IGNORE_UNUSED); +static A1_PCLK(pad_ctrl, SYS_CLK_EN0, 4, CLK_IGNORE_UNUSED); +static A1_PCLK(sys_ctrl, SYS_CLK_EN0, 5, CLK_IGNORE_UNUSED); +static A1_PCLK(temp_sensor, SYS_CLK_EN0, 6, CLK_IGNORE_UNUSED); +static A1_PCLK(am2axi_dev, SYS_CLK_EN0, 7, CLK_IGNORE_UNUSED); +static A1_PCLK(spicc_b, SYS_CLK_EN0, 8, CLK_IGNORE_UNUSED); +static A1_PCLK(spicc_a, SYS_CLK_EN0, 9, CLK_IGNORE_UNUSED); +static A1_PCLK(msr, SYS_CLK_EN0, 10, CLK_IGNORE_UNUSED); +static A1_PCLK(audio, SYS_CLK_EN0, 11, CLK_IGNORE_UNUSED); +static A1_PCLK(jtag_ctrl, SYS_CLK_EN0, 12, CLK_IGNORE_UNUSED); +static A1_PCLK(saradc_en, SYS_CLK_EN0, 13, CLK_IGNORE_UNUSED); +static A1_PCLK(pwm_ef, SYS_CLK_EN0, 14, CLK_IGNORE_UNUSED); +static A1_PCLK(pwm_cd, SYS_CLK_EN0, 15, CLK_IGNORE_UNUSED); +static A1_PCLK(pwm_ab, SYS_CLK_EN0, 16, CLK_IGNORE_UNUSED); +static A1_PCLK(cec, SYS_CLK_EN0, 17, CLK_IGNORE_UNUSED); +static A1_PCLK(i2c_s, SYS_CLK_EN0, 18, CLK_IGNORE_UNUSED); +static A1_PCLK(ir_ctrl, SYS_CLK_EN0, 19, CLK_IGNORE_UNUSED); +static A1_PCLK(i2c_m_d, SYS_CLK_EN0, 20, CLK_IGNORE_UNUSED); +static A1_PCLK(i2c_m_c, SYS_CLK_EN0, 21, CLK_IGNORE_UNUSED); +static A1_PCLK(i2c_m_b, SYS_CLK_EN0, 22, CLK_IGNORE_UNUSED); +static A1_PCLK(i2c_m_a, SYS_CLK_EN0, 23, CLK_IGNORE_UNUSED); +static A1_PCLK(acodec, SYS_CLK_EN0, 24, CLK_IGNORE_UNUSED); +static A1_PCLK(otp, SYS_CLK_EN0, 25, CLK_IGNORE_UNUSED); +static A1_PCLK(sd_emmc_a, SYS_CLK_EN0, 26, CLK_IGNORE_UNUSED); +static A1_PCLK(usb_phy, SYS_CLK_EN0, 27, CLK_IGNORE_UNUSED); +static A1_PCLK(usb_ctrl, SYS_CLK_EN0, 28, CLK_IGNORE_UNUSED); +static A1_PCLK(sys_dspb, SYS_CLK_EN0, 29, CLK_IGNORE_UNUSED); +static A1_PCLK(sys_dspa, SYS_CLK_EN0, 30, CLK_IGNORE_UNUSED); +static A1_PCLK(dma, SYS_CLK_EN0, 31, CLK_IGNORE_UNUSED); -static A1_PCLK(irq_ctrl, SYS_CLK_EN1, 0); -static A1_PCLK(nic, SYS_CLK_EN1, 1); -static A1_PCLK(gic, SYS_CLK_EN1, 2); -static A1_PCLK(uart_c, SYS_CLK_EN1, 3); -static A1_PCLK(uart_b, SYS_CLK_EN1, 4); -static A1_PCLK(uart_a, SYS_CLK_EN1, 5); -static A1_PCLK(sys_psram, SYS_CLK_EN1, 6); -static A1_PCLK(rsa, SYS_CLK_EN1, 8); -static A1_PCLK(coresight, SYS_CLK_EN1, 9); +static A1_PCLK(irq_ctrl, SYS_CLK_EN1, 0, CLK_IGNORE_UNUSED); +static A1_PCLK(nic, SYS_CLK_EN1, 1, CLK_IGNORE_UNUSED); +static A1_PCLK(gic, SYS_CLK_EN1, 2, CLK_IGNORE_UNUSED); +static A1_PCLK(uart_c, SYS_CLK_EN1, 3, CLK_IGNORE_UNUSED); +static A1_PCLK(uart_b, SYS_CLK_EN1, 4, CLK_IGNORE_UNUSED); +static A1_PCLK(uart_a, SYS_CLK_EN1, 5, CLK_IGNORE_UNUSED); +static A1_PCLK(sys_psram, SYS_CLK_EN1, 6, CLK_IGNORE_UNUSED); +static A1_PCLK(rsa, SYS_CLK_EN1, 8, CLK_IGNORE_UNUSED); +static A1_PCLK(coresight, SYS_CLK_EN1, 9, CLK_IGNORE_UNUSED); -static A1_PCLK(am2axi_vad, AXI_CLK_EN, 0); -static A1_PCLK(audio_vad, AXI_CLK_EN, 1); -static A1_PCLK(axi_dmc, AXI_CLK_EN, 3); -static A1_PCLK(axi_psram, AXI_CLK_EN, 4); -static A1_PCLK(ramb, AXI_CLK_EN, 5); -static A1_PCLK(rama, AXI_CLK_EN, 6); -static A1_PCLK(axi_spifc, AXI_CLK_EN, 7); -static A1_PCLK(axi_nic, AXI_CLK_EN, 8); -static A1_PCLK(axi_dma, AXI_CLK_EN, 9); -static A1_PCLK(cpu_ctrl, AXI_CLK_EN, 10); -static A1_PCLK(rom, AXI_CLK_EN, 11); -static A1_PCLK(prod_i2c, AXI_CLK_EN, 12); +static A1_PCLK(am2axi_vad, AXI_CLK_EN, 0, CLK_IGNORE_UNUSED); +static A1_PCLK(audio_vad, AXI_CLK_EN, 1, CLK_IGNORE_UNUSED); +static A1_PCLK(axi_dmc, AXI_CLK_EN, 3, CLK_IGNORE_UNUSED); +static A1_PCLK(axi_psram, AXI_CLK_EN, 4, CLK_IGNORE_UNUSED); +static A1_PCLK(ramb, AXI_CLK_EN, 5, CLK_IGNORE_UNUSED); +static A1_PCLK(rama, AXI_CLK_EN, 6, CLK_IGNORE_UNUSED); +static A1_PCLK(axi_spifc, AXI_CLK_EN, 7, CLK_IGNORE_UNUSED); +static A1_PCLK(axi_nic, AXI_CLK_EN, 8, CLK_IGNORE_UNUSED); +static A1_PCLK(axi_dma, AXI_CLK_EN, 9, CLK_IGNORE_UNUSED); +static A1_PCLK(cpu_ctrl, AXI_CLK_EN, 10, CLK_IGNORE_UNUSED); +static A1_PCLK(rom, AXI_CLK_EN, 11, CLK_IGNORE_UNUSED); +static A1_PCLK(prod_i2c, AXI_CLK_EN, 12, CLK_IGNORE_UNUSED); /* Array of all clocks registered by this provider */ static struct clk_hw *a1_peripherals_hw_clks[] = { diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index efc33fd18c19..74c2f51424f1 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -34,7 +34,7 @@ #define AO_RTC_ALT_CLK_CNTL0 0x94 #define AO_RTC_ALT_CLK_CNTL1 0x98 -#define AXG_AO_GATE(_name, _bit) \ +#define AXG_AO_GATE(_name, _bit, _flags) \ static struct clk_regmap axg_ao_##_name = { \ .data = &(struct clk_regmap_gate_data) { \ .offset = (AO_RTI_GEN_CNTL_REG0), \ @@ -47,17 +47,17 @@ static struct clk_regmap axg_ao_##_name = { \ .fw_name = "mpeg-clk", \ }, \ .num_parents = 1, \ - .flags = CLK_IGNORE_UNUSED, \ + .flags = (_flags), \ }, \ } -AXG_AO_GATE(remote, 0); -AXG_AO_GATE(i2c_master, 1); -AXG_AO_GATE(i2c_slave, 2); -AXG_AO_GATE(uart1, 3); -AXG_AO_GATE(uart2, 5); -AXG_AO_GATE(ir_blaster, 6); -AXG_AO_GATE(saradc, 7); +AXG_AO_GATE(remote, 0, CLK_IGNORE_UNUSED); +AXG_AO_GATE(i2c_master, 1, CLK_IGNORE_UNUSED); +AXG_AO_GATE(i2c_slave, 2, CLK_IGNORE_UNUSED); +AXG_AO_GATE(uart1, 3, CLK_IGNORE_UNUSED); +AXG_AO_GATE(uart2, 5, CLK_IGNORE_UNUSED); +AXG_AO_GATE(ir_blaster, 6, CLK_IGNORE_UNUSED); +AXG_AO_GATE(saradc, 7, CLK_IGNORE_UNUSED); static struct clk_regmap axg_ao_cts_oscin = { .data = &(struct clk_regmap_gate_data){ diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 021bc7658f7f..fd9a7a362a1b 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -1915,59 +1915,69 @@ static struct clk_regmap axg_gen_clk = { }, }; -#define AXG_PCLK(_name, _reg, _bit) \ - MESON_PCLK(axg_##_name, _reg, _bit, &axg_clk81.hw) +#define AXG_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(axg_##_name, _reg, _bit, &axg_clk81.hw, _flags) -/* Everything Else (EE) domain gates */ -static AXG_PCLK(ddr, HHI_GCLK_MPEG0, 0); -static AXG_PCLK(audio_locker, HHI_GCLK_MPEG0, 2); -static AXG_PCLK(mipi_dsi_host, HHI_GCLK_MPEG0, 3); -static AXG_PCLK(isa, HHI_GCLK_MPEG0, 5); -static AXG_PCLK(pl301, HHI_GCLK_MPEG0, 6); -static AXG_PCLK(periphs, HHI_GCLK_MPEG0, 7); -static AXG_PCLK(spicc_0, HHI_GCLK_MPEG0, 8); -static AXG_PCLK(i2c, HHI_GCLK_MPEG0, 9); -static AXG_PCLK(rng0, HHI_GCLK_MPEG0, 12); -static AXG_PCLK(uart0, HHI_GCLK_MPEG0, 13); -static AXG_PCLK(mipi_dsi_phy, HHI_GCLK_MPEG0, 14); -static AXG_PCLK(spicc_1, HHI_GCLK_MPEG0, 15); -static AXG_PCLK(pcie_a, HHI_GCLK_MPEG0, 16); -static AXG_PCLK(pcie_b, HHI_GCLK_MPEG0, 17); -static AXG_PCLK(hiu_reg, HHI_GCLK_MPEG0, 19); -static AXG_PCLK(assist_misc, HHI_GCLK_MPEG0, 23); -static AXG_PCLK(emmc_b, HHI_GCLK_MPEG0, 25); -static AXG_PCLK(emmc_c, HHI_GCLK_MPEG0, 26); -static AXG_PCLK(dma, HHI_GCLK_MPEG0, 27); -static AXG_PCLK(spi, HHI_GCLK_MPEG0, 30); +/* + * Everything Else (EE) domain gates + * + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static AXG_PCLK(ddr, HHI_GCLK_MPEG0, 0, CLK_IGNORE_UNUSED); +static AXG_PCLK(audio_locker, HHI_GCLK_MPEG0, 2, CLK_IGNORE_UNUSED); +static AXG_PCLK(mipi_dsi_host, HHI_GCLK_MPEG0, 3, CLK_IGNORE_UNUSED); +static AXG_PCLK(isa, HHI_GCLK_MPEG0, 5, CLK_IGNORE_UNUSED); +static AXG_PCLK(pl301, HHI_GCLK_MPEG0, 6, CLK_IGNORE_UNUSED); +static AXG_PCLK(periphs, HHI_GCLK_MPEG0, 7, CLK_IGNORE_UNUSED); +static AXG_PCLK(spicc_0, HHI_GCLK_MPEG0, 8, CLK_IGNORE_UNUSED); +static AXG_PCLK(i2c, HHI_GCLK_MPEG0, 9, CLK_IGNORE_UNUSED); +static AXG_PCLK(rng0, HHI_GCLK_MPEG0, 12, CLK_IGNORE_UNUSED); +static AXG_PCLK(uart0, HHI_GCLK_MPEG0, 13, CLK_IGNORE_UNUSED); +static AXG_PCLK(mipi_dsi_phy, HHI_GCLK_MPEG0, 14, CLK_IGNORE_UNUSED); +static AXG_PCLK(spicc_1, HHI_GCLK_MPEG0, 15, CLK_IGNORE_UNUSED); +static AXG_PCLK(pcie_a, HHI_GCLK_MPEG0, 16, CLK_IGNORE_UNUSED); +static AXG_PCLK(pcie_b, HHI_GCLK_MPEG0, 17, CLK_IGNORE_UNUSED); +static AXG_PCLK(hiu_reg, HHI_GCLK_MPEG0, 19, CLK_IGNORE_UNUSED); +static AXG_PCLK(assist_misc, HHI_GCLK_MPEG0, 23, CLK_IGNORE_UNUSED); +static AXG_PCLK(emmc_b, HHI_GCLK_MPEG0, 25, CLK_IGNORE_UNUSED); +static AXG_PCLK(emmc_c, HHI_GCLK_MPEG0, 26, CLK_IGNORE_UNUSED); +static AXG_PCLK(dma, HHI_GCLK_MPEG0, 27, CLK_IGNORE_UNUSED); +static AXG_PCLK(spi, HHI_GCLK_MPEG0, 30, CLK_IGNORE_UNUSED); -static AXG_PCLK(audio, HHI_GCLK_MPEG1, 0); -static AXG_PCLK(eth_core, HHI_GCLK_MPEG1, 3); -static AXG_PCLK(uart1, HHI_GCLK_MPEG1, 16); -static AXG_PCLK(g2d, HHI_GCLK_MPEG1, 20); -static AXG_PCLK(usb0, HHI_GCLK_MPEG1, 21); -static AXG_PCLK(usb1, HHI_GCLK_MPEG1, 22); -static AXG_PCLK(reset, HHI_GCLK_MPEG1, 23); -static AXG_PCLK(usb_general, HHI_GCLK_MPEG1, 26); -static AXG_PCLK(ahb_arb0, HHI_GCLK_MPEG1, 29); -static AXG_PCLK(efuse, HHI_GCLK_MPEG1, 30); -static AXG_PCLK(boot_rom, HHI_GCLK_MPEG1, 31); +static AXG_PCLK(audio, HHI_GCLK_MPEG1, 0, CLK_IGNORE_UNUSED); +static AXG_PCLK(eth_core, HHI_GCLK_MPEG1, 3, CLK_IGNORE_UNUSED); +static AXG_PCLK(uart1, HHI_GCLK_MPEG1, 16, CLK_IGNORE_UNUSED); +static AXG_PCLK(g2d, HHI_GCLK_MPEG1, 20, CLK_IGNORE_UNUSED); +static AXG_PCLK(usb0, HHI_GCLK_MPEG1, 21, CLK_IGNORE_UNUSED); +static AXG_PCLK(usb1, HHI_GCLK_MPEG1, 22, CLK_IGNORE_UNUSED); +static AXG_PCLK(reset, HHI_GCLK_MPEG1, 23, CLK_IGNORE_UNUSED); +static AXG_PCLK(usb_general, HHI_GCLK_MPEG1, 26, CLK_IGNORE_UNUSED); +static AXG_PCLK(ahb_arb0, HHI_GCLK_MPEG1, 29, CLK_IGNORE_UNUSED); +static AXG_PCLK(efuse, HHI_GCLK_MPEG1, 30, CLK_IGNORE_UNUSED); +static AXG_PCLK(boot_rom, HHI_GCLK_MPEG1, 31, CLK_IGNORE_UNUSED); -static AXG_PCLK(ahb_data_bus, HHI_GCLK_MPEG2, 1); -static AXG_PCLK(ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); -static AXG_PCLK(usb1_to_ddr, HHI_GCLK_MPEG2, 8); -static AXG_PCLK(usb0_to_ddr, HHI_GCLK_MPEG2, 9); -static AXG_PCLK(mmc_pclk, HHI_GCLK_MPEG2, 11); -static AXG_PCLK(vpu_intr, HHI_GCLK_MPEG2, 25); -static AXG_PCLK(sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); -static AXG_PCLK(gic, HHI_GCLK_MPEG2, 30); +static AXG_PCLK(ahb_data_bus, HHI_GCLK_MPEG2, 1, CLK_IGNORE_UNUSED); +static AXG_PCLK(ahb_ctrl_bus, HHI_GCLK_MPEG2, 2, CLK_IGNORE_UNUSED); +static AXG_PCLK(usb1_to_ddr, HHI_GCLK_MPEG2, 8, CLK_IGNORE_UNUSED); +static AXG_PCLK(usb0_to_ddr, HHI_GCLK_MPEG2, 9, CLK_IGNORE_UNUSED); +static AXG_PCLK(mmc_pclk, HHI_GCLK_MPEG2, 11, CLK_IGNORE_UNUSED); +static AXG_PCLK(vpu_intr, HHI_GCLK_MPEG2, 25, CLK_IGNORE_UNUSED); +static AXG_PCLK(sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26, CLK_IGNORE_UNUSED); +static AXG_PCLK(gic, HHI_GCLK_MPEG2, 30, CLK_IGNORE_UNUSED); /* Always On (AO) domain gates */ -static AXG_PCLK(ao_media_cpu, HHI_GCLK_AO, 0); -static AXG_PCLK(ao_ahb_sram, HHI_GCLK_AO, 1); -static AXG_PCLK(ao_ahb_bus, HHI_GCLK_AO, 2); -static AXG_PCLK(ao_iface, HHI_GCLK_AO, 3); -static AXG_PCLK(ao_i2c, HHI_GCLK_AO, 4); +static AXG_PCLK(ao_media_cpu, HHI_GCLK_AO, 0, CLK_IGNORE_UNUSED); +static AXG_PCLK(ao_ahb_sram, HHI_GCLK_AO, 1, CLK_IGNORE_UNUSED); +static AXG_PCLK(ao_ahb_bus, HHI_GCLK_AO, 2, CLK_IGNORE_UNUSED); +static AXG_PCLK(ao_iface, HHI_GCLK_AO, 3, CLK_IGNORE_UNUSED); +static AXG_PCLK(ao_i2c, HHI_GCLK_AO, 4, CLK_IGNORE_UNUSED); /* Array of all clocks provided by this provider */ diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c index 872a7b800bb8..45e4df393feb 100644 --- a/drivers/clk/meson/g12a-aoclk.c +++ b/drivers/clk/meson/g12a-aoclk.c @@ -37,13 +37,7 @@ #define AO_RTC_ALT_CLK_CNTL0 0x94 #define AO_RTC_ALT_CLK_CNTL1 0x98 -/* - * Like every other peripheral clock gate in Amlogic Clock drivers, - * we are using CLK_IGNORE_UNUSED here, so we keep the state of the - * bootloader. The goal is to remove this flag at some point. - * Actually removing it will require some extensive test to be done safely. - */ -#define G12A_AO_PCLK(_name, _reg, _bit) \ +#define G12A_AO_PCLK(_name, _reg, _bit, _flags) \ static struct clk_regmap g12a_ao_##_name = { \ .data = &(struct clk_regmap_gate_data) { \ .offset = (_reg), \ @@ -56,26 +50,35 @@ static struct clk_regmap g12a_ao_##_name = { \ .fw_name = "mpeg-clk", \ }, \ .num_parents = 1, \ - .flags = CLK_IGNORE_UNUSED, \ + .flags = (_flags), \ }, \ } -G12A_AO_PCLK(ahb, AO_CLK_GATE0, 0); -G12A_AO_PCLK(ir_in, AO_CLK_GATE0, 1); -G12A_AO_PCLK(i2c_m0, AO_CLK_GATE0, 2); -G12A_AO_PCLK(i2c_s0, AO_CLK_GATE0, 3); -G12A_AO_PCLK(uart, AO_CLK_GATE0, 4); -G12A_AO_PCLK(prod_i2c, AO_CLK_GATE0, 5); -G12A_AO_PCLK(uart2, AO_CLK_GATE0, 6); -G12A_AO_PCLK(ir_out, AO_CLK_GATE0, 7); -G12A_AO_PCLK(saradc, AO_CLK_GATE0, 8); +/* + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +G12A_AO_PCLK(ahb, AO_CLK_GATE0, 0, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(ir_in, AO_CLK_GATE0, 1, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(i2c_m0, AO_CLK_GATE0, 2, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(i2c_s0, AO_CLK_GATE0, 3, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(uart, AO_CLK_GATE0, 4, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(prod_i2c, AO_CLK_GATE0, 5, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(uart2, AO_CLK_GATE0, 6, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(ir_out, AO_CLK_GATE0, 7, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(saradc, AO_CLK_GATE0, 8, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(mailbox, AO_CLK_GATE0_SP, 0); -G12A_AO_PCLK(m3, AO_CLK_GATE0_SP, 1); -G12A_AO_PCLK(ahb_sram, AO_CLK_GATE0_SP, 2); -G12A_AO_PCLK(rti, AO_CLK_GATE0_SP, 3); -G12A_AO_PCLK(m4_fclk, AO_CLK_GATE0_SP, 4); -G12A_AO_PCLK(m4_hclk, AO_CLK_GATE0_SP, 5); +G12A_AO_PCLK(mailbox, AO_CLK_GATE0_SP, 0, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(m3, AO_CLK_GATE0_SP, 1, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(ahb_sram, AO_CLK_GATE0_SP, 2, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(rti, AO_CLK_GATE0_SP, 3, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(m4_fclk, AO_CLK_GATE0_SP, 4, CLK_IGNORE_UNUSED); +G12A_AO_PCLK(m4_hclk, AO_CLK_GATE0_SP, 5, CLK_IGNORE_UNUSED); static struct clk_regmap g12a_ao_cts_oscin = { .data = &(struct clk_regmap_gate_data){ diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index c06a4b678b27..bfa8815647ae 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -4384,89 +4384,99 @@ static struct clk_regmap sm1_nna_core_clk = { }, }; -#define G12A_PCLK(_name, _reg, _bit) \ - MESON_PCLK(_name, _reg, _bit, &g12a_clk81.hw) +#define G12A_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(_name, _reg, _bit, &g12a_clk81.hw, _flags) -#define G12A_PCLK_RO(_name, _reg, _bit) \ - MESON_PCLK_RO(_name, _reg, _bit, &g12a_clk81.hw) +#define G12A_PCLK_RO(_name, _reg, _bit, _flags) \ + MESON_PCLK_RO(_name, _reg, _bit, &g12a_clk81.hw, _flags) -/* Everything Else (EE) domain gates */ -static G12A_PCLK(g12a_ddr, HHI_GCLK_MPEG0, 0); -static G12A_PCLK(g12a_dos, HHI_GCLK_MPEG0, 1); -static G12A_PCLK(g12a_audio_locker, HHI_GCLK_MPEG0, 2); -static G12A_PCLK(g12a_mipi_dsi_host, HHI_GCLK_MPEG0, 3); -static G12A_PCLK(g12a_eth_phy, HHI_GCLK_MPEG0, 4); -static G12A_PCLK(g12a_isa, HHI_GCLK_MPEG0, 5); -static G12A_PCLK(g12a_pl301, HHI_GCLK_MPEG0, 6); -static G12A_PCLK(g12a_periphs, HHI_GCLK_MPEG0, 7); -static G12A_PCLK(g12a_spicc_0, HHI_GCLK_MPEG0, 8); -static G12A_PCLK(g12a_i2c, HHI_GCLK_MPEG0, 9); -static G12A_PCLK(g12a_sana, HHI_GCLK_MPEG0, 10); -static G12A_PCLK(g12a_sd, HHI_GCLK_MPEG0, 11); -static G12A_PCLK(g12a_rng0, HHI_GCLK_MPEG0, 12); -static G12A_PCLK(g12a_uart0, HHI_GCLK_MPEG0, 13); -static G12A_PCLK(g12a_spicc_1, HHI_GCLK_MPEG0, 14); -static G12A_PCLK(g12a_hiu_reg, HHI_GCLK_MPEG0, 19); -static G12A_PCLK(g12a_mipi_dsi_phy, HHI_GCLK_MPEG0, 20); -static G12A_PCLK(g12a_assist_misc, HHI_GCLK_MPEG0, 23); -static G12A_PCLK(g12a_emmc_a, HHI_GCLK_MPEG0, 24); -static G12A_PCLK(g12a_emmc_b, HHI_GCLK_MPEG0, 25); -static G12A_PCLK(g12a_emmc_c, HHI_GCLK_MPEG0, 26); -static G12A_PCLK(g12a_audio_codec, HHI_GCLK_MPEG0, 28); +/* + * Everything Else (EE) domain gates + * + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static G12A_PCLK(g12a_ddr, HHI_GCLK_MPEG0, 0, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_dos, HHI_GCLK_MPEG0, 1, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_audio_locker, HHI_GCLK_MPEG0, 2, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_mipi_dsi_host, HHI_GCLK_MPEG0, 3, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_eth_phy, HHI_GCLK_MPEG0, 4, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_isa, HHI_GCLK_MPEG0, 5, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_pl301, HHI_GCLK_MPEG0, 6, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_periphs, HHI_GCLK_MPEG0, 7, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_spicc_0, HHI_GCLK_MPEG0, 8, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_i2c, HHI_GCLK_MPEG0, 9, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_sana, HHI_GCLK_MPEG0, 10, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_sd, HHI_GCLK_MPEG0, 11, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_rng0, HHI_GCLK_MPEG0, 12, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_uart0, HHI_GCLK_MPEG0, 13, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_spicc_1, HHI_GCLK_MPEG0, 14, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_hiu_reg, HHI_GCLK_MPEG0, 19, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_mipi_dsi_phy, HHI_GCLK_MPEG0, 20, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_assist_misc, HHI_GCLK_MPEG0, 23, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_emmc_a, HHI_GCLK_MPEG0, 24, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_emmc_b, HHI_GCLK_MPEG0, 25, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_emmc_c, HHI_GCLK_MPEG0, 26, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_audio_codec, HHI_GCLK_MPEG0, 28, CLK_IGNORE_UNUSED); -static G12A_PCLK(g12a_audio, HHI_GCLK_MPEG1, 0); -static G12A_PCLK(g12a_eth_core, HHI_GCLK_MPEG1, 3); -static G12A_PCLK(g12a_demux, HHI_GCLK_MPEG1, 4); -static G12A_PCLK(g12a_audio_ififo, HHI_GCLK_MPEG1, 11); -static G12A_PCLK(g12a_adc, HHI_GCLK_MPEG1, 13); -static G12A_PCLK(g12a_uart1, HHI_GCLK_MPEG1, 16); -static G12A_PCLK(g12a_g2d, HHI_GCLK_MPEG1, 20); -static G12A_PCLK(g12a_reset, HHI_GCLK_MPEG1, 23); -static G12A_PCLK(g12a_pcie_comb, HHI_GCLK_MPEG1, 24); -static G12A_PCLK(g12a_parser, HHI_GCLK_MPEG1, 25); -static G12A_PCLK(g12a_usb_general, HHI_GCLK_MPEG1, 26); -static G12A_PCLK(g12a_pcie_phy, HHI_GCLK_MPEG1, 27); -static G12A_PCLK(g12a_ahb_arb0, HHI_GCLK_MPEG1, 29); +static G12A_PCLK(g12a_audio, HHI_GCLK_MPEG1, 0, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_eth_core, HHI_GCLK_MPEG1, 3, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_demux, HHI_GCLK_MPEG1, 4, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_audio_ififo, HHI_GCLK_MPEG1, 11, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_adc, HHI_GCLK_MPEG1, 13, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_uart1, HHI_GCLK_MPEG1, 16, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_g2d, HHI_GCLK_MPEG1, 20, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_reset, HHI_GCLK_MPEG1, 23, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_pcie_comb, HHI_GCLK_MPEG1, 24, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_parser, HHI_GCLK_MPEG1, 25, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_usb_general, HHI_GCLK_MPEG1, 26, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_pcie_phy, HHI_GCLK_MPEG1, 27, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_ahb_arb0, HHI_GCLK_MPEG1, 29, CLK_IGNORE_UNUSED); -static G12A_PCLK(g12a_ahb_data_bus, HHI_GCLK_MPEG2, 1); -static G12A_PCLK(g12a_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); -static G12A_PCLK(g12a_htx_hdcp22, HHI_GCLK_MPEG2, 3); -static G12A_PCLK(g12a_htx_pclk, HHI_GCLK_MPEG2, 4); -static G12A_PCLK(g12a_bt656, HHI_GCLK_MPEG2, 6); -static G12A_PCLK(g12a_usb1_to_ddr, HHI_GCLK_MPEG2, 8); -static G12A_PCLK(g12b_mipi_isp_gate, HHI_GCLK_MPEG2, 17); -static G12A_PCLK(g12a_mmc_pclk, HHI_GCLK_MPEG2, 11); -static G12A_PCLK(g12a_uart2, HHI_GCLK_MPEG2, 15); -static G12A_PCLK(g12a_vpu_intr, HHI_GCLK_MPEG2, 25); -static G12A_PCLK(g12b_csi_phy1, HHI_GCLK_MPEG2, 28); -static G12A_PCLK(g12b_csi_phy0, HHI_GCLK_MPEG2, 29); -static G12A_PCLK(g12a_gic, HHI_GCLK_MPEG2, 30); +static G12A_PCLK(g12a_ahb_data_bus, HHI_GCLK_MPEG2, 1, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_htx_hdcp22, HHI_GCLK_MPEG2, 3, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_htx_pclk, HHI_GCLK_MPEG2, 4, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_bt656, HHI_GCLK_MPEG2, 6, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_usb1_to_ddr, HHI_GCLK_MPEG2, 8, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12b_mipi_isp_gate, HHI_GCLK_MPEG2, 17, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_mmc_pclk, HHI_GCLK_MPEG2, 11, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_uart2, HHI_GCLK_MPEG2, 15, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vpu_intr, HHI_GCLK_MPEG2, 25, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12b_csi_phy1, HHI_GCLK_MPEG2, 28, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12b_csi_phy0, HHI_GCLK_MPEG2, 29, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_gic, HHI_GCLK_MPEG2, 30, CLK_IGNORE_UNUSED); -static G12A_PCLK(g12a_vclk2_venci0, HHI_GCLK_OTHER, 1); -static G12A_PCLK(g12a_vclk2_venci1, HHI_GCLK_OTHER, 2); -static G12A_PCLK(g12a_vclk2_vencp0, HHI_GCLK_OTHER, 3); -static G12A_PCLK(g12a_vclk2_vencp1, HHI_GCLK_OTHER, 4); -static G12A_PCLK(g12a_vclk2_venct0, HHI_GCLK_OTHER, 5); -static G12A_PCLK(g12a_vclk2_venct1, HHI_GCLK_OTHER, 6); -static G12A_PCLK(g12a_vclk2_other, HHI_GCLK_OTHER, 7); -static G12A_PCLK(g12a_vclk2_enci, HHI_GCLK_OTHER, 8); -static G12A_PCLK(g12a_vclk2_encp, HHI_GCLK_OTHER, 9); -static G12A_PCLK(g12a_dac_clk, HHI_GCLK_OTHER, 10); -static G12A_PCLK(g12a_aoclk_gate, HHI_GCLK_OTHER, 14); -static G12A_PCLK(g12a_iec958_gate, HHI_GCLK_OTHER, 16); -static G12A_PCLK(g12a_enc480p, HHI_GCLK_OTHER, 20); -static G12A_PCLK(g12a_rng1, HHI_GCLK_OTHER, 21); -static G12A_PCLK(g12a_vclk2_enct, HHI_GCLK_OTHER, 22); -static G12A_PCLK(g12a_vclk2_encl, HHI_GCLK_OTHER, 23); -static G12A_PCLK(g12a_vclk2_venclmmc, HHI_GCLK_OTHER, 24); -static G12A_PCLK(g12a_vclk2_vencl, HHI_GCLK_OTHER, 25); -static G12A_PCLK(g12a_vclk2_other1, HHI_GCLK_OTHER, 26); +static G12A_PCLK(g12a_vclk2_venci0, HHI_GCLK_OTHER, 1, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_venci1, HHI_GCLK_OTHER, 2, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_vencp0, HHI_GCLK_OTHER, 3, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_vencp1, HHI_GCLK_OTHER, 4, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_venct0, HHI_GCLK_OTHER, 5, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_venct1, HHI_GCLK_OTHER, 6, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_other, HHI_GCLK_OTHER, 7, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_enci, HHI_GCLK_OTHER, 8, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_encp, HHI_GCLK_OTHER, 9, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_dac_clk, HHI_GCLK_OTHER, 10, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_aoclk_gate, HHI_GCLK_OTHER, 14, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_iec958_gate, HHI_GCLK_OTHER, 16, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_enc480p, HHI_GCLK_OTHER, 20, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_rng1, HHI_GCLK_OTHER, 21, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_enct, HHI_GCLK_OTHER, 22, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_encl, HHI_GCLK_OTHER, 23, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_venclmmc, HHI_GCLK_OTHER, 24, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_vencl, HHI_GCLK_OTHER, 25, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_other1, HHI_GCLK_OTHER, 26, CLK_IGNORE_UNUSED); -static G12A_PCLK_RO(g12a_dma, HHI_GCLK_OTHER2, 0); -static G12A_PCLK_RO(g12a_efuse, HHI_GCLK_OTHER2, 1); -static G12A_PCLK_RO(g12a_rom_boot, HHI_GCLK_OTHER2, 2); -static G12A_PCLK_RO(g12a_reset_sec, HHI_GCLK_OTHER2, 3); -static G12A_PCLK_RO(g12a_sec_ahb_apb3, HHI_GCLK_OTHER2, 4); +static G12A_PCLK_RO(g12a_dma, HHI_GCLK_OTHER2, 0, 0); +static G12A_PCLK_RO(g12a_efuse, HHI_GCLK_OTHER2, 1, 0); +static G12A_PCLK_RO(g12a_rom_boot, HHI_GCLK_OTHER2, 2, 0); +static G12A_PCLK_RO(g12a_reset_sec, HHI_GCLK_OTHER2, 3, 0); +static G12A_PCLK_RO(g12a_sec_ahb_apb3, HHI_GCLK_OTHER2, 4, 0); /* Array of all clocks provided by this provider */ static struct clk_hw *g12a_hw_clks[] = { diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index ce8d2e9e0717..2bf45fd7fe4b 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -23,7 +23,7 @@ #define AO_RTC_ALT_CLK_CNTL0 0x94 #define AO_RTC_ALT_CLK_CNTL1 0x98 -#define GXBB_AO_PCLK(_name, _bit) \ +#define GXBB_AO_PCLK(_name, _bit, _flags) \ static struct clk_regmap gxbb_ao_##_name = { \ .data = &(struct clk_regmap_gate_data) { \ .offset = AO_RTI_GEN_CNTL_REG0, \ @@ -36,16 +36,16 @@ static struct clk_regmap gxbb_ao_##_name = { \ .fw_name = "mpeg-clk", \ }, \ .num_parents = 1, \ - .flags = CLK_IGNORE_UNUSED, \ + .flags = (_flags), \ }, \ } -GXBB_AO_PCLK(remote, 0); -GXBB_AO_PCLK(i2c_master, 1); -GXBB_AO_PCLK(i2c_slave, 2); -GXBB_AO_PCLK(uart1, 3); -GXBB_AO_PCLK(uart2, 5); -GXBB_AO_PCLK(ir_blaster, 6); +GXBB_AO_PCLK(remote, 0, CLK_IGNORE_UNUSED); +GXBB_AO_PCLK(i2c_master, 1, CLK_IGNORE_UNUSED); +GXBB_AO_PCLK(i2c_slave, 2, CLK_IGNORE_UNUSED); +GXBB_AO_PCLK(uart1, 3, CLK_IGNORE_UNUSED); +GXBB_AO_PCLK(uart2, 5, CLK_IGNORE_UNUSED); +GXBB_AO_PCLK(ir_blaster, 6, CLK_IGNORE_UNUSED); static struct clk_regmap gxbb_ao_cts_oscin = { .data = &(struct clk_regmap_gate_data){ diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 608c2cd34a45..ccc1490a0928 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -2721,100 +2721,110 @@ static struct clk_regmap gxbb_gen_clk = { }, }; -#define GXBB_PCLK(_name, _reg, _bit) \ - MESON_PCLK(_name, _reg, _bit, &gxbb_clk81.hw) +#define GXBB_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(_name, _reg, _bit, &gxbb_clk81.hw, _flags) -/* Everything Else (EE) domain gates */ -static GXBB_PCLK(gxbb_ddr, HHI_GCLK_MPEG0, 0); -static GXBB_PCLK(gxbb_dos, HHI_GCLK_MPEG0, 1); -static GXBB_PCLK(gxbb_isa, HHI_GCLK_MPEG0, 5); -static GXBB_PCLK(gxbb_pl301, HHI_GCLK_MPEG0, 6); -static GXBB_PCLK(gxbb_periphs, HHI_GCLK_MPEG0, 7); -static GXBB_PCLK(gxbb_spicc, HHI_GCLK_MPEG0, 8); -static GXBB_PCLK(gxbb_i2c, HHI_GCLK_MPEG0, 9); -static GXBB_PCLK(gxbb_sana, HHI_GCLK_MPEG0, 10); -static GXBB_PCLK(gxbb_smart_card, HHI_GCLK_MPEG0, 11); -static GXBB_PCLK(gxbb_rng0, HHI_GCLK_MPEG0, 12); -static GXBB_PCLK(gxbb_uart0, HHI_GCLK_MPEG0, 13); -static GXBB_PCLK(gxbb_sdhc, HHI_GCLK_MPEG0, 14); -static GXBB_PCLK(gxbb_stream, HHI_GCLK_MPEG0, 15); -static GXBB_PCLK(gxbb_async_fifo, HHI_GCLK_MPEG0, 16); -static GXBB_PCLK(gxbb_sdio, HHI_GCLK_MPEG0, 17); -static GXBB_PCLK(gxbb_abuf, HHI_GCLK_MPEG0, 18); -static GXBB_PCLK(gxbb_hiu_iface, HHI_GCLK_MPEG0, 19); -static GXBB_PCLK(gxbb_assist_misc, HHI_GCLK_MPEG0, 23); -static GXBB_PCLK(gxbb_emmc_a, HHI_GCLK_MPEG0, 24); -static GXBB_PCLK(gxbb_emmc_b, HHI_GCLK_MPEG0, 25); -static GXBB_PCLK(gxbb_emmc_c, HHI_GCLK_MPEG0, 26); -static GXBB_PCLK(gxl_acodec, HHI_GCLK_MPEG0, 28); -static GXBB_PCLK(gxbb_spi, HHI_GCLK_MPEG0, 30); +/* + * Everything Else (EE) domain gates + * + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static GXBB_PCLK(gxbb_ddr, HHI_GCLK_MPEG0, 0, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_dos, HHI_GCLK_MPEG0, 1, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_isa, HHI_GCLK_MPEG0, 5, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_pl301, HHI_GCLK_MPEG0, 6, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_periphs, HHI_GCLK_MPEG0, 7, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_spicc, HHI_GCLK_MPEG0, 8, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_i2c, HHI_GCLK_MPEG0, 9, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_sana, HHI_GCLK_MPEG0, 10, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_smart_card, HHI_GCLK_MPEG0, 11, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_rng0, HHI_GCLK_MPEG0, 12, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_uart0, HHI_GCLK_MPEG0, 13, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_sdhc, HHI_GCLK_MPEG0, 14, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_stream, HHI_GCLK_MPEG0, 15, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_async_fifo, HHI_GCLK_MPEG0, 16, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_sdio, HHI_GCLK_MPEG0, 17, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_abuf, HHI_GCLK_MPEG0, 18, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_hiu_iface, HHI_GCLK_MPEG0, 19, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_assist_misc, HHI_GCLK_MPEG0, 23, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_emmc_a, HHI_GCLK_MPEG0, 24, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_emmc_b, HHI_GCLK_MPEG0, 25, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_emmc_c, HHI_GCLK_MPEG0, 26, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxl_acodec, HHI_GCLK_MPEG0, 28, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_spi, HHI_GCLK_MPEG0, 30, CLK_IGNORE_UNUSED); -static GXBB_PCLK(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2); -static GXBB_PCLK(gxbb_eth, HHI_GCLK_MPEG1, 3); -static GXBB_PCLK(gxbb_demux, HHI_GCLK_MPEG1, 4); -static GXBB_PCLK(gxbb_blkmv, HHI_GCLK_MPEG1, 14); -static GXBB_PCLK(gxbb_aiu, HHI_GCLK_MPEG1, 15); -static GXBB_PCLK(gxbb_uart1, HHI_GCLK_MPEG1, 16); -static GXBB_PCLK(gxbb_g2d, HHI_GCLK_MPEG1, 20); -static GXBB_PCLK(gxbb_usb0, HHI_GCLK_MPEG1, 21); -static GXBB_PCLK(gxbb_usb1, HHI_GCLK_MPEG1, 22); -static GXBB_PCLK(gxbb_reset, HHI_GCLK_MPEG1, 23); -static GXBB_PCLK(gxbb_nand, HHI_GCLK_MPEG1, 24); -static GXBB_PCLK(gxbb_dos_parser, HHI_GCLK_MPEG1, 25); -static GXBB_PCLK(gxbb_usb, HHI_GCLK_MPEG1, 26); -static GXBB_PCLK(gxbb_vdin1, HHI_GCLK_MPEG1, 28); -static GXBB_PCLK(gxbb_ahb_arb0, HHI_GCLK_MPEG1, 29); -static GXBB_PCLK(gxbb_efuse, HHI_GCLK_MPEG1, 30); -static GXBB_PCLK(gxbb_boot_rom, HHI_GCLK_MPEG1, 31); +static GXBB_PCLK(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_eth, HHI_GCLK_MPEG1, 3, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_demux, HHI_GCLK_MPEG1, 4, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_blkmv, HHI_GCLK_MPEG1, 14, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_aiu, HHI_GCLK_MPEG1, 15, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_uart1, HHI_GCLK_MPEG1, 16, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_g2d, HHI_GCLK_MPEG1, 20, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_usb0, HHI_GCLK_MPEG1, 21, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_usb1, HHI_GCLK_MPEG1, 22, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_reset, HHI_GCLK_MPEG1, 23, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_nand, HHI_GCLK_MPEG1, 24, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_dos_parser, HHI_GCLK_MPEG1, 25, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_usb, HHI_GCLK_MPEG1, 26, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vdin1, HHI_GCLK_MPEG1, 28, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ahb_arb0, HHI_GCLK_MPEG1, 29, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_efuse, HHI_GCLK_MPEG1, 30, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_boot_rom, HHI_GCLK_MPEG1, 31, CLK_IGNORE_UNUSED); -static GXBB_PCLK(gxbb_ahb_data_bus, HHI_GCLK_MPEG2, 1); -static GXBB_PCLK(gxbb_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); -static GXBB_PCLK(gxbb_hdmi_intr_sync, HHI_GCLK_MPEG2, 3); -static GXBB_PCLK(gxbb_hdmi_pclk, HHI_GCLK_MPEG2, 4); -static GXBB_PCLK(gxbb_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); -static GXBB_PCLK(gxbb_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); -static GXBB_PCLK(gxbb_mmc_pclk, HHI_GCLK_MPEG2, 11); -static GXBB_PCLK(gxbb_dvin, HHI_GCLK_MPEG2, 12); -static GXBB_PCLK(gxbb_uart2, HHI_GCLK_MPEG2, 15); -static GXBB_PCLK(gxbb_sar_adc, HHI_GCLK_MPEG2, 22); -static GXBB_PCLK(gxbb_vpu_intr, HHI_GCLK_MPEG2, 25); -static GXBB_PCLK(gxbb_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); -static GXBB_PCLK(gxbb_clk81_a53, HHI_GCLK_MPEG2, 29); +static GXBB_PCLK(gxbb_ahb_data_bus, HHI_GCLK_MPEG2, 1, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_hdmi_intr_sync, HHI_GCLK_MPEG2, 3, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_hdmi_pclk, HHI_GCLK_MPEG2, 4, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_mmc_pclk, HHI_GCLK_MPEG2, 11, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_dvin, HHI_GCLK_MPEG2, 12, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_uart2, HHI_GCLK_MPEG2, 15, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_sar_adc, HHI_GCLK_MPEG2, 22, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vpu_intr, HHI_GCLK_MPEG2, 25, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_clk81_a53, HHI_GCLK_MPEG2, 29, CLK_IGNORE_UNUSED); -static GXBB_PCLK(gxbb_vclk2_venci0, HHI_GCLK_OTHER, 1); -static GXBB_PCLK(gxbb_vclk2_venci1, HHI_GCLK_OTHER, 2); -static GXBB_PCLK(gxbb_vclk2_vencp0, HHI_GCLK_OTHER, 3); -static GXBB_PCLK(gxbb_vclk2_vencp1, HHI_GCLK_OTHER, 4); -static GXBB_PCLK(gxbb_gclk_venci_int0, HHI_GCLK_OTHER, 8); -static GXBB_PCLK(gxbb_gclk_vencp_int, HHI_GCLK_OTHER, 9); -static GXBB_PCLK(gxbb_dac_clk, HHI_GCLK_OTHER, 10); -static GXBB_PCLK(gxbb_aoclk_gate, HHI_GCLK_OTHER, 14); -static GXBB_PCLK(gxbb_iec958_gate, HHI_GCLK_OTHER, 16); -static GXBB_PCLK(gxbb_enc480p, HHI_GCLK_OTHER, 20); -static GXBB_PCLK(gxbb_rng1, HHI_GCLK_OTHER, 21); -static GXBB_PCLK(gxbb_gclk_venci_int1, HHI_GCLK_OTHER, 22); -static GXBB_PCLK(gxbb_vclk2_venclmcc, HHI_GCLK_OTHER, 24); -static GXBB_PCLK(gxbb_vclk2_vencl, HHI_GCLK_OTHER, 25); -static GXBB_PCLK(gxbb_vclk_other, HHI_GCLK_OTHER, 26); -static GXBB_PCLK(gxbb_edp, HHI_GCLK_OTHER, 31); +static GXBB_PCLK(gxbb_vclk2_venci0, HHI_GCLK_OTHER, 1, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk2_venci1, HHI_GCLK_OTHER, 2, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk2_vencp0, HHI_GCLK_OTHER, 3, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk2_vencp1, HHI_GCLK_OTHER, 4, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_gclk_venci_int0, HHI_GCLK_OTHER, 8, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_gclk_vencp_int, HHI_GCLK_OTHER, 9, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_dac_clk, HHI_GCLK_OTHER, 10, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_aoclk_gate, HHI_GCLK_OTHER, 14, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_iec958_gate, HHI_GCLK_OTHER, 16, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_enc480p, HHI_GCLK_OTHER, 20, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_rng1, HHI_GCLK_OTHER, 21, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_gclk_venci_int1, HHI_GCLK_OTHER, 22, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk2_venclmcc, HHI_GCLK_OTHER, 24, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk2_vencl, HHI_GCLK_OTHER, 25, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk_other, HHI_GCLK_OTHER, 26, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_edp, HHI_GCLK_OTHER, 31, CLK_IGNORE_UNUSED); /* Always On (AO) domain gates */ -static GXBB_PCLK(gxbb_ao_media_cpu, HHI_GCLK_AO, 0); -static GXBB_PCLK(gxbb_ao_ahb_sram, HHI_GCLK_AO, 1); -static GXBB_PCLK(gxbb_ao_ahb_bus, HHI_GCLK_AO, 2); -static GXBB_PCLK(gxbb_ao_iface, HHI_GCLK_AO, 3); -static GXBB_PCLK(gxbb_ao_i2c, HHI_GCLK_AO, 4); +static GXBB_PCLK(gxbb_ao_media_cpu, HHI_GCLK_AO, 0, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ao_ahb_sram, HHI_GCLK_AO, 1, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ao_ahb_bus, HHI_GCLK_AO, 2, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ao_iface, HHI_GCLK_AO, 3, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ao_i2c, HHI_GCLK_AO, 4, CLK_IGNORE_UNUSED); /* AIU gates */ -static MESON_PCLK(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6, &gxbb_aiu.hw); -static MESON_PCLK(gxbb_iec958, HHI_GCLK_MPEG1, 7, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_i2s_out, HHI_GCLK_MPEG1, 8, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_amclk, HHI_GCLK_MPEG1, 9, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_aififo2, HHI_GCLK_MPEG1, 10, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_mixer, HHI_GCLK_MPEG1, 11, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12, &gxbb_aiu_glue.hw); -static MESON_PCLK(gxbb_adc, HHI_GCLK_MPEG1, 13, &gxbb_aiu_glue.hw); +static MESON_PCLK(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6, &gxbb_aiu.hw, CLK_IGNORE_UNUSED); +static MESON_PCLK(gxbb_iec958, HHI_GCLK_MPEG1, 7, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); +static MESON_PCLK(gxbb_i2s_out, HHI_GCLK_MPEG1, 8, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); +static MESON_PCLK(gxbb_amclk, HHI_GCLK_MPEG1, 9, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); +static MESON_PCLK(gxbb_aififo2, HHI_GCLK_MPEG1, 10, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); +static MESON_PCLK(gxbb_mixer, HHI_GCLK_MPEG1, 11, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); +static MESON_PCLK(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); +static MESON_PCLK(gxbb_adc, HHI_GCLK_MPEG1, 13, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); /* Array of all clocks provided by this provider */ diff --git a/drivers/clk/meson/meson-clkc-utils.h b/drivers/clk/meson/meson-clkc-utils.h index 3e1fb7efe6da..03e38992c4c7 100644 --- a/drivers/clk/meson/meson-clkc-utils.h +++ b/drivers/clk/meson/meson-clkc-utils.h @@ -27,7 +27,7 @@ struct meson_clkc_data { int meson_clkc_syscon_probe(struct platform_device *pdev); int meson_clkc_mmio_probe(struct platform_device *pdev); -#define __MESON_PCLK(_name, _reg, _bit, _ops, _pname) \ +#define __MESON_PCLK(_name, _reg, _bit, _ops, _pname, _flags) \ struct clk_regmap _name = { \ .data = &(struct clk_regmap_gate_data) { \ .offset = (_reg), \ @@ -38,14 +38,14 @@ struct clk_regmap _name = { \ .ops = _ops, \ .parent_hws = (const struct clk_hw *[]) { _pname }, \ .num_parents = 1, \ - .flags = CLK_IGNORE_UNUSED, \ + .flags = (_flags), \ }, \ } -#define MESON_PCLK(_name, _reg, _bit, _pname) \ - __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ops, _pname) +#define MESON_PCLK(_name, _reg, _bit, _pname, _flags) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ops, _pname, _flags) -#define MESON_PCLK_RO(_name, _reg, _bit, _pname) \ - __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pname) +#define MESON_PCLK_RO(_name, _reg, _bit, _pname, _flags) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pname, _flags) #endif diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 446e57d45d8d..a16ebbbf664c 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -2701,100 +2701,109 @@ static struct clk_regmap meson8b_cts_i958 = { }, }; -#define MESON8B_PCLK(_name, _reg, _bit) \ - MESON_PCLK(_name, _reg, _bit, &meson8b_clk81.hw) +#define MESON8B_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(_name, _reg, _bit, &meson8b_clk81.hw, _flags) -/* Everything Else (EE) domain gates */ +/* + * Everything Else (EE) domain gates + * + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static MESON8B_PCLK(meson8b_ddr, HHI_GCLK_MPEG0, 0, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_dos, HHI_GCLK_MPEG0, 1, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_isa, HHI_GCLK_MPEG0, 5, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_pl301, HHI_GCLK_MPEG0, 6, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_periphs, HHI_GCLK_MPEG0, 7, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_spicc, HHI_GCLK_MPEG0, 8, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_i2c, HHI_GCLK_MPEG0, 9, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_sar_adc, HHI_GCLK_MPEG0, 10, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_smart_card, HHI_GCLK_MPEG0, 11, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_rng0, HHI_GCLK_MPEG0, 12, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_uart0, HHI_GCLK_MPEG0, 13, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_sdhc, HHI_GCLK_MPEG0, 14, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_stream, HHI_GCLK_MPEG0, 15, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_async_fifo, HHI_GCLK_MPEG0, 16, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_sdio, HHI_GCLK_MPEG0, 17, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_abuf, HHI_GCLK_MPEG0, 18, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_hiu_iface, HHI_GCLK_MPEG0, 19, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_assist_misc, HHI_GCLK_MPEG0, 23, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_spi, HHI_GCLK_MPEG0, 30, CLK_IGNORE_UNUSED); -static MESON8B_PCLK(meson8b_ddr, HHI_GCLK_MPEG0, 0); -static MESON8B_PCLK(meson8b_dos, HHI_GCLK_MPEG0, 1); -static MESON8B_PCLK(meson8b_isa, HHI_GCLK_MPEG0, 5); -static MESON8B_PCLK(meson8b_pl301, HHI_GCLK_MPEG0, 6); -static MESON8B_PCLK(meson8b_periphs, HHI_GCLK_MPEG0, 7); -static MESON8B_PCLK(meson8b_spicc, HHI_GCLK_MPEG0, 8); -static MESON8B_PCLK(meson8b_i2c, HHI_GCLK_MPEG0, 9); -static MESON8B_PCLK(meson8b_sar_adc, HHI_GCLK_MPEG0, 10); -static MESON8B_PCLK(meson8b_smart_card, HHI_GCLK_MPEG0, 11); -static MESON8B_PCLK(meson8b_rng0, HHI_GCLK_MPEG0, 12); -static MESON8B_PCLK(meson8b_uart0, HHI_GCLK_MPEG0, 13); -static MESON8B_PCLK(meson8b_sdhc, HHI_GCLK_MPEG0, 14); -static MESON8B_PCLK(meson8b_stream, HHI_GCLK_MPEG0, 15); -static MESON8B_PCLK(meson8b_async_fifo, HHI_GCLK_MPEG0, 16); -static MESON8B_PCLK(meson8b_sdio, HHI_GCLK_MPEG0, 17); -static MESON8B_PCLK(meson8b_abuf, HHI_GCLK_MPEG0, 18); -static MESON8B_PCLK(meson8b_hiu_iface, HHI_GCLK_MPEG0, 19); -static MESON8B_PCLK(meson8b_assist_misc, HHI_GCLK_MPEG0, 23); -static MESON8B_PCLK(meson8b_spi, HHI_GCLK_MPEG0, 30); +static MESON8B_PCLK(meson8b_i2s_spdif, HHI_GCLK_MPEG1, 2, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_eth, HHI_GCLK_MPEG1, 3, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_demux, HHI_GCLK_MPEG1, 4, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_blkmv, HHI_GCLK_MPEG1, 14, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_aiu, HHI_GCLK_MPEG1, 15, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_uart1, HHI_GCLK_MPEG1, 16, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_g2d, HHI_GCLK_MPEG1, 20, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_usb0, HHI_GCLK_MPEG1, 21, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_usb1, HHI_GCLK_MPEG1, 22, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_reset, HHI_GCLK_MPEG1, 23, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_nand, HHI_GCLK_MPEG1, 24, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_dos_parser, HHI_GCLK_MPEG1, 25, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_usb, HHI_GCLK_MPEG1, 26, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vdin1, HHI_GCLK_MPEG1, 28, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_ahb_arb0, HHI_GCLK_MPEG1, 29, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_efuse, HHI_GCLK_MPEG1, 30, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_boot_rom, HHI_GCLK_MPEG1, 31, CLK_IGNORE_UNUSED); -static MESON8B_PCLK(meson8b_i2s_spdif, HHI_GCLK_MPEG1, 2); -static MESON8B_PCLK(meson8b_eth, HHI_GCLK_MPEG1, 3); -static MESON8B_PCLK(meson8b_demux, HHI_GCLK_MPEG1, 4); -static MESON8B_PCLK(meson8b_blkmv, HHI_GCLK_MPEG1, 14); -static MESON8B_PCLK(meson8b_aiu, HHI_GCLK_MPEG1, 15); -static MESON8B_PCLK(meson8b_uart1, HHI_GCLK_MPEG1, 16); -static MESON8B_PCLK(meson8b_g2d, HHI_GCLK_MPEG1, 20); -static MESON8B_PCLK(meson8b_usb0, HHI_GCLK_MPEG1, 21); -static MESON8B_PCLK(meson8b_usb1, HHI_GCLK_MPEG1, 22); -static MESON8B_PCLK(meson8b_reset, HHI_GCLK_MPEG1, 23); -static MESON8B_PCLK(meson8b_nand, HHI_GCLK_MPEG1, 24); -static MESON8B_PCLK(meson8b_dos_parser, HHI_GCLK_MPEG1, 25); -static MESON8B_PCLK(meson8b_usb, HHI_GCLK_MPEG1, 26); -static MESON8B_PCLK(meson8b_vdin1, HHI_GCLK_MPEG1, 28); -static MESON8B_PCLK(meson8b_ahb_arb0, HHI_GCLK_MPEG1, 29); -static MESON8B_PCLK(meson8b_efuse, HHI_GCLK_MPEG1, 30); -static MESON8B_PCLK(meson8b_boot_rom, HHI_GCLK_MPEG1, 31); +static MESON8B_PCLK(meson8b_ahb_data_bus, HHI_GCLK_MPEG2, 1, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_hdmi_intr_sync, HHI_GCLK_MPEG2, 3, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_hdmi_pclk, HHI_GCLK_MPEG2, 4, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_mmc_pclk, HHI_GCLK_MPEG2, 11, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_dvin, HHI_GCLK_MPEG2, 12, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_uart2, HHI_GCLK_MPEG2, 15, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_sana, HHI_GCLK_MPEG2, 22, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vpu_intr, HHI_GCLK_MPEG2, 25, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_clk81_a9, HHI_GCLK_MPEG2, 29, CLK_IGNORE_UNUSED); -static MESON8B_PCLK(meson8b_ahb_data_bus, HHI_GCLK_MPEG2, 1); -static MESON8B_PCLK(meson8b_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); -static MESON8B_PCLK(meson8b_hdmi_intr_sync, HHI_GCLK_MPEG2, 3); -static MESON8B_PCLK(meson8b_hdmi_pclk, HHI_GCLK_MPEG2, 4); -static MESON8B_PCLK(meson8b_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); -static MESON8B_PCLK(meson8b_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); -static MESON8B_PCLK(meson8b_mmc_pclk, HHI_GCLK_MPEG2, 11); -static MESON8B_PCLK(meson8b_dvin, HHI_GCLK_MPEG2, 12); -static MESON8B_PCLK(meson8b_uart2, HHI_GCLK_MPEG2, 15); -static MESON8B_PCLK(meson8b_sana, HHI_GCLK_MPEG2, 22); -static MESON8B_PCLK(meson8b_vpu_intr, HHI_GCLK_MPEG2, 25); -static MESON8B_PCLK(meson8b_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); -static MESON8B_PCLK(meson8b_clk81_a9, HHI_GCLK_MPEG2, 29); - -static MESON8B_PCLK(meson8b_vclk2_venci0, HHI_GCLK_OTHER, 1); -static MESON8B_PCLK(meson8b_vclk2_venci1, HHI_GCLK_OTHER, 2); -static MESON8B_PCLK(meson8b_vclk2_vencp0, HHI_GCLK_OTHER, 3); -static MESON8B_PCLK(meson8b_vclk2_vencp1, HHI_GCLK_OTHER, 4); -static MESON8B_PCLK(meson8b_gclk_venci_int, HHI_GCLK_OTHER, 8); -static MESON8B_PCLK(meson8b_gclk_vencp_int, HHI_GCLK_OTHER, 9); -static MESON8B_PCLK(meson8b_dac_clk, HHI_GCLK_OTHER, 10); -static MESON8B_PCLK(meson8b_aoclk_gate, HHI_GCLK_OTHER, 14); -static MESON8B_PCLK(meson8b_iec958_gate, HHI_GCLK_OTHER, 16); -static MESON8B_PCLK(meson8b_enc480p, HHI_GCLK_OTHER, 20); -static MESON8B_PCLK(meson8b_rng1, HHI_GCLK_OTHER, 21); -static MESON8B_PCLK(meson8b_gclk_vencl_int, HHI_GCLK_OTHER, 22); -static MESON8B_PCLK(meson8b_vclk2_venclmcc, HHI_GCLK_OTHER, 24); -static MESON8B_PCLK(meson8b_vclk2_vencl, HHI_GCLK_OTHER, 25); -static MESON8B_PCLK(meson8b_vclk2_other, HHI_GCLK_OTHER, 26); -static MESON8B_PCLK(meson8b_edp, HHI_GCLK_OTHER, 31); +static MESON8B_PCLK(meson8b_vclk2_venci0, HHI_GCLK_OTHER, 1, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_venci1, HHI_GCLK_OTHER, 2, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_vencp0, HHI_GCLK_OTHER, 3, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_vencp1, HHI_GCLK_OTHER, 4, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_gclk_venci_int, HHI_GCLK_OTHER, 8, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_gclk_vencp_int, HHI_GCLK_OTHER, 9, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_dac_clk, HHI_GCLK_OTHER, 10, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_aoclk_gate, HHI_GCLK_OTHER, 14, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_iec958_gate, HHI_GCLK_OTHER, 16, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_enc480p, HHI_GCLK_OTHER, 20, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_rng1, HHI_GCLK_OTHER, 21, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_gclk_vencl_int, HHI_GCLK_OTHER, 22, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_venclmcc, HHI_GCLK_OTHER, 24, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_vencl, HHI_GCLK_OTHER, 25, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_other, HHI_GCLK_OTHER, 26, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_edp, HHI_GCLK_OTHER, 31, CLK_IGNORE_UNUSED); /* AIU gates */ -static MESON_PCLK(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6, &meson8b_aiu.hw); +static MESON_PCLK(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6, &meson8b_aiu.hw, CLK_IGNORE_UNUSED); -#define MESON_AIU_PCLK(_name, _reg, _bit) \ - MESON_PCLK(_name, _reg, _bit, &meson8b_aiu_glue.hw) +#define MESON_AIU_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(_name, _reg, _bit, &meson8b_aiu_glue.hw, _flags) -static MESON_AIU_PCLK(meson8b_iec958, HHI_GCLK_MPEG1, 7); -static MESON_AIU_PCLK(meson8b_i2s_out, HHI_GCLK_MPEG1, 8); -static MESON_AIU_PCLK(meson8b_amclk, HHI_GCLK_MPEG1, 9); -static MESON_AIU_PCLK(meson8b_aififo2, HHI_GCLK_MPEG1, 10); -static MESON_AIU_PCLK(meson8b_mixer, HHI_GCLK_MPEG1, 11); -static MESON_AIU_PCLK(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12); -static MESON_AIU_PCLK(meson8b_adc, HHI_GCLK_MPEG1, 13); +static MESON_AIU_PCLK(meson8b_iec958, HHI_GCLK_MPEG1, 7, CLK_IGNORE_UNUSED); +static MESON_AIU_PCLK(meson8b_i2s_out, HHI_GCLK_MPEG1, 8, CLK_IGNORE_UNUSED); +static MESON_AIU_PCLK(meson8b_amclk, HHI_GCLK_MPEG1, 9, CLK_IGNORE_UNUSED); +static MESON_AIU_PCLK(meson8b_aififo2, HHI_GCLK_MPEG1, 10, CLK_IGNORE_UNUSED); +static MESON_AIU_PCLK(meson8b_mixer, HHI_GCLK_MPEG1, 11, CLK_IGNORE_UNUSED); +static MESON_AIU_PCLK(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12, CLK_IGNORE_UNUSED); +static MESON_AIU_PCLK(meson8b_adc, HHI_GCLK_MPEG1, 13, CLK_IGNORE_UNUSED); /* Always On (AO) domain gates */ -static MESON8B_PCLK(meson8b_ao_media_cpu, HHI_GCLK_AO, 0); -static MESON8B_PCLK(meson8b_ao_ahb_sram, HHI_GCLK_AO, 1); -static MESON8B_PCLK(meson8b_ao_ahb_bus, HHI_GCLK_AO, 2); -static MESON8B_PCLK(meson8b_ao_iface, HHI_GCLK_AO, 3); +static MESON8B_PCLK(meson8b_ao_media_cpu, HHI_GCLK_AO, 0, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_ao_ahb_sram, HHI_GCLK_AO, 1, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_ao_ahb_bus, HHI_GCLK_AO, 2, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_ao_iface, HHI_GCLK_AO, 3, CLK_IGNORE_UNUSED); static struct clk_hw *meson8_hw_clks[] = { [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c index fc1500df926d..23b51d84d8de 100644 --- a/drivers/clk/meson/s4-peripherals.c +++ b/drivers/clk/meson/s4-peripherals.c @@ -3165,61 +3165,70 @@ static struct clk_regmap s4_gen_clk = { }, }; -#define S4_PCLK(_name, _reg, _bit) \ - MESON_PCLK(_name, _reg, _bit, &s4_sys_clk.hw) +#define S4_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(_name, _reg, _bit, &s4_sys_clk.hw, _flags) -static S4_PCLK(s4_ddr, CLKCTRL_SYS_CLK_EN0_REG0, 0); -static S4_PCLK(s4_dos, CLKCTRL_SYS_CLK_EN0_REG0, 1); -static S4_PCLK(s4_ethphy, CLKCTRL_SYS_CLK_EN0_REG0, 4); -static S4_PCLK(s4_mali, CLKCTRL_SYS_CLK_EN0_REG0, 6); -static S4_PCLK(s4_aocpu, CLKCTRL_SYS_CLK_EN0_REG0, 13); -static S4_PCLK(s4_aucpu, CLKCTRL_SYS_CLK_EN0_REG0, 14); -static S4_PCLK(s4_cec, CLKCTRL_SYS_CLK_EN0_REG0, 16); -static S4_PCLK(s4_sdemmca, CLKCTRL_SYS_CLK_EN0_REG0, 24); -static S4_PCLK(s4_sdemmcb, CLKCTRL_SYS_CLK_EN0_REG0, 25); -static S4_PCLK(s4_nand, CLKCTRL_SYS_CLK_EN0_REG0, 26); -static S4_PCLK(s4_smartcard, CLKCTRL_SYS_CLK_EN0_REG0, 27); -static S4_PCLK(s4_acodec, CLKCTRL_SYS_CLK_EN0_REG0, 28); -static S4_PCLK(s4_spifc, CLKCTRL_SYS_CLK_EN0_REG0, 29); -static S4_PCLK(s4_msr_clk, CLKCTRL_SYS_CLK_EN0_REG0, 30); -static S4_PCLK(s4_ir_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 31); +/* + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static S4_PCLK(s4_ddr, CLKCTRL_SYS_CLK_EN0_REG0, 0, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_dos, CLKCTRL_SYS_CLK_EN0_REG0, 1, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_ethphy, CLKCTRL_SYS_CLK_EN0_REG0, 4, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_mali, CLKCTRL_SYS_CLK_EN0_REG0, 6, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_aocpu, CLKCTRL_SYS_CLK_EN0_REG0, 13, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_aucpu, CLKCTRL_SYS_CLK_EN0_REG0, 14, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_cec, CLKCTRL_SYS_CLK_EN0_REG0, 16, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_sdemmca, CLKCTRL_SYS_CLK_EN0_REG0, 24, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_sdemmcb, CLKCTRL_SYS_CLK_EN0_REG0, 25, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_nand, CLKCTRL_SYS_CLK_EN0_REG0, 26, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_smartcard, CLKCTRL_SYS_CLK_EN0_REG0, 27, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_acodec, CLKCTRL_SYS_CLK_EN0_REG0, 28, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_spifc, CLKCTRL_SYS_CLK_EN0_REG0, 29, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_msr_clk, CLKCTRL_SYS_CLK_EN0_REG0, 30, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_ir_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 31, CLK_IGNORE_UNUSED); -static S4_PCLK(s4_audio, CLKCTRL_SYS_CLK_EN0_REG1, 0); -static S4_PCLK(s4_eth, CLKCTRL_SYS_CLK_EN0_REG1, 3); -static S4_PCLK(s4_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 5); -static S4_PCLK(s4_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 6); -static S4_PCLK(s4_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 7); -static S4_PCLK(s4_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 8); -static S4_PCLK(s4_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 9); -static S4_PCLK(s4_aififo, CLKCTRL_SYS_CLK_EN0_REG1, 11); -static S4_PCLK(s4_ts_ddr, CLKCTRL_SYS_CLK_EN0_REG1, 15); -static S4_PCLK(s4_ts_pll, CLKCTRL_SYS_CLK_EN0_REG1, 16); -static S4_PCLK(s4_g2d, CLKCTRL_SYS_CLK_EN0_REG1, 20); -static S4_PCLK(s4_spicc0, CLKCTRL_SYS_CLK_EN0_REG1, 21); -static S4_PCLK(s4_usb, CLKCTRL_SYS_CLK_EN0_REG1, 26); -static S4_PCLK(s4_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 30); -static S4_PCLK(s4_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 31); +static S4_PCLK(s4_audio, CLKCTRL_SYS_CLK_EN0_REG1, 0, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_eth, CLKCTRL_SYS_CLK_EN0_REG1, 3, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 5, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 6, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 7, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 8, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 9, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_aififo, CLKCTRL_SYS_CLK_EN0_REG1, 11, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_ts_ddr, CLKCTRL_SYS_CLK_EN0_REG1, 15, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_ts_pll, CLKCTRL_SYS_CLK_EN0_REG1, 16, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_g2d, CLKCTRL_SYS_CLK_EN0_REG1, 20, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_spicc0, CLKCTRL_SYS_CLK_EN0_REG1, 21, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_usb, CLKCTRL_SYS_CLK_EN0_REG1, 26, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 30, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 31, CLK_IGNORE_UNUSED); -static S4_PCLK(s4_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG2, 0); -static S4_PCLK(s4_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG2, 1); -static S4_PCLK(s4_i2c_m_e, CLKCTRL_SYS_CLK_EN0_REG2, 2); -static S4_PCLK(s4_hdmitx_apb, CLKCTRL_SYS_CLK_EN0_REG2, 4); -static S4_PCLK(s4_i2c_s_a, CLKCTRL_SYS_CLK_EN0_REG2, 5); -static S4_PCLK(s4_usb1_to_ddr, CLKCTRL_SYS_CLK_EN0_REG2, 8); -static S4_PCLK(s4_hdcp22, CLKCTRL_SYS_CLK_EN0_REG2, 10); -static S4_PCLK(s4_mmc_apb, CLKCTRL_SYS_CLK_EN0_REG2, 11); -static S4_PCLK(s4_rsa, CLKCTRL_SYS_CLK_EN0_REG2, 18); -static S4_PCLK(s4_cpu_debug, CLKCTRL_SYS_CLK_EN0_REG2, 19); -static S4_PCLK(s4_vpu_intr, CLKCTRL_SYS_CLK_EN0_REG2, 25); -static S4_PCLK(s4_demod, CLKCTRL_SYS_CLK_EN0_REG2, 27); -static S4_PCLK(s4_sar_adc, CLKCTRL_SYS_CLK_EN0_REG2, 28); -static S4_PCLK(s4_gic, CLKCTRL_SYS_CLK_EN0_REG2, 30); +static S4_PCLK(s4_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG2, 0, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG2, 1, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_i2c_m_e, CLKCTRL_SYS_CLK_EN0_REG2, 2, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_hdmitx_apb, CLKCTRL_SYS_CLK_EN0_REG2, 4, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_i2c_s_a, CLKCTRL_SYS_CLK_EN0_REG2, 5, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_usb1_to_ddr, CLKCTRL_SYS_CLK_EN0_REG2, 8, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_hdcp22, CLKCTRL_SYS_CLK_EN0_REG2, 10, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_mmc_apb, CLKCTRL_SYS_CLK_EN0_REG2, 11, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_rsa, CLKCTRL_SYS_CLK_EN0_REG2, 18, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_cpu_debug, CLKCTRL_SYS_CLK_EN0_REG2, 19, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_vpu_intr, CLKCTRL_SYS_CLK_EN0_REG2, 25, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_demod, CLKCTRL_SYS_CLK_EN0_REG2, 27, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_sar_adc, CLKCTRL_SYS_CLK_EN0_REG2, 28, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_gic, CLKCTRL_SYS_CLK_EN0_REG2, 30, CLK_IGNORE_UNUSED); -static S4_PCLK(s4_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG3, 7); -static S4_PCLK(s4_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG3, 8); -static S4_PCLK(s4_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG3, 9); -static S4_PCLK(s4_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG3, 10); -static S4_PCLK(s4_pwm_ij, CLKCTRL_SYS_CLK_EN0_REG3, 11); +static S4_PCLK(s4_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG3, 7, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG3, 8, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG3, 9, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG3, 10, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_pwm_ij, CLKCTRL_SYS_CLK_EN0_REG3, 11, CLK_IGNORE_UNUSED); /* Array of all clocks provided by this provider */ static struct clk_hw *s4_peripherals_hw_clks[] = { From aaee6f3bce3fe11ecdb7357a4b5a620205c4ecea Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:33 +0200 Subject: [PATCH 0829/2711] clk: amlogic: introduce a common pclk definition All Amlogic peripheral clocks are more or less the same. The only thing that differs is the parent data. Adapt the common pclk definition so it takes clk_parent_data and can be used by all controllers. Reviewed-by: Chuan Liu Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-8-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/a1-peripherals.c | 4 +++- drivers/clk/meson/axg.c | 4 +++- drivers/clk/meson/g12a.c | 6 ++++-- drivers/clk/meson/gxbb.c | 26 +++++++++++++++++--------- drivers/clk/meson/meson-clkc-utils.h | 12 ++++++------ drivers/clk/meson/meson8b.c | 27 ++++++++++++++++----------- drivers/clk/meson/s4-peripherals.c | 4 +++- 7 files changed, 52 insertions(+), 31 deletions(-) diff --git a/drivers/clk/meson/a1-peripherals.c b/drivers/clk/meson/a1-peripherals.c index a7bd3822df18..5e0d58c01405 100644 --- a/drivers/clk/meson/a1-peripherals.c +++ b/drivers/clk/meson/a1-peripherals.c @@ -1840,8 +1840,10 @@ static struct clk_regmap a1_cecb_32k_out = { }, }; +static const struct clk_parent_data a1_pclk_parents = { .hw = &a1_sys.hw }; + #define A1_PCLK(_name, _reg, _bit, _flags) \ - MESON_PCLK(a1_##_name, _reg, _bit, &a1_sys.hw, _flags) + MESON_PCLK(a1_##_name, _reg, _bit, &a1_pclk_parents, _flags) /* * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index fd9a7a362a1b..0a25c649ef1d 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -1915,8 +1915,10 @@ static struct clk_regmap axg_gen_clk = { }, }; +static const struct clk_parent_data axg_pclk_parents = { .hw = &axg_clk81.hw }; + #define AXG_PCLK(_name, _reg, _bit, _flags) \ - MESON_PCLK(axg_##_name, _reg, _bit, &axg_clk81.hw, _flags) + MESON_PCLK(axg_##_name, _reg, _bit, &axg_pclk_parents, _flags) /* * Everything Else (EE) domain gates diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index bfa8815647ae..348aff4fae68 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -4384,11 +4384,13 @@ static struct clk_regmap sm1_nna_core_clk = { }, }; +static const struct clk_parent_data g12a_pclk_parents = { .hw = &g12a_clk81.hw }; + #define G12A_PCLK(_name, _reg, _bit, _flags) \ - MESON_PCLK(_name, _reg, _bit, &g12a_clk81.hw, _flags) + MESON_PCLK(_name, _reg, _bit, &g12a_pclk_parents, _flags) #define G12A_PCLK_RO(_name, _reg, _bit, _flags) \ - MESON_PCLK_RO(_name, _reg, _bit, &g12a_clk81.hw, _flags) + MESON_PCLK_RO(_name, _reg, _bit, &g12a_pclk_parents, _flags) /* * Everything Else (EE) domain gates diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index ccc1490a0928..5a229c4ffae1 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -2721,8 +2721,10 @@ static struct clk_regmap gxbb_gen_clk = { }, }; +static const struct clk_parent_data gxbb_pclk_parents = { .hw = &gxbb_clk81.hw }; + #define GXBB_PCLK(_name, _reg, _bit, _flags) \ - MESON_PCLK(_name, _reg, _bit, &gxbb_clk81.hw, _flags) + MESON_PCLK(_name, _reg, _bit, &gxbb_pclk_parents, _flags) /* * Everything Else (EE) domain gates @@ -2817,14 +2819,20 @@ static GXBB_PCLK(gxbb_ao_iface, HHI_GCLK_AO, 3, CLK_IGNORE_UNUSED); static GXBB_PCLK(gxbb_ao_i2c, HHI_GCLK_AO, 4, CLK_IGNORE_UNUSED); /* AIU gates */ -static MESON_PCLK(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6, &gxbb_aiu.hw, CLK_IGNORE_UNUSED); -static MESON_PCLK(gxbb_iec958, HHI_GCLK_MPEG1, 7, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); -static MESON_PCLK(gxbb_i2s_out, HHI_GCLK_MPEG1, 8, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); -static MESON_PCLK(gxbb_amclk, HHI_GCLK_MPEG1, 9, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); -static MESON_PCLK(gxbb_aififo2, HHI_GCLK_MPEG1, 10, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); -static MESON_PCLK(gxbb_mixer, HHI_GCLK_MPEG1, 11, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); -static MESON_PCLK(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); -static MESON_PCLK(gxbb_adc, HHI_GCLK_MPEG1, 13, &gxbb_aiu_glue.hw, CLK_IGNORE_UNUSED); +static const struct clk_parent_data gxbb_aiu_glue_parents = { .hw = &gxbb_aiu.hw }; +static MESON_PCLK(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6, &gxbb_aiu_glue_parents, CLK_IGNORE_UNUSED); + +static const struct clk_parent_data gxbb_aiu_pclk_parents = { .hw = &gxbb_aiu_glue.hw }; +#define GXBB_AIU_PCLK(_name, _bit, _flags) \ + MESON_PCLK(_name, HHI_GCLK_MPEG1, _bit, &gxbb_aiu_pclk_parents, _flags) + +static GXBB_AIU_PCLK(gxbb_iec958, 7, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_i2s_out, 8, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_amclk, 9, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_aififo2, 10, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_mixer, 11, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_mixer_iface, 12, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_adc, 13, CLK_IGNORE_UNUSED); /* Array of all clocks provided by this provider */ diff --git a/drivers/clk/meson/meson-clkc-utils.h b/drivers/clk/meson/meson-clkc-utils.h index 03e38992c4c7..95d9f85f7ca2 100644 --- a/drivers/clk/meson/meson-clkc-utils.h +++ b/drivers/clk/meson/meson-clkc-utils.h @@ -27,7 +27,7 @@ struct meson_clkc_data { int meson_clkc_syscon_probe(struct platform_device *pdev); int meson_clkc_mmio_probe(struct platform_device *pdev); -#define __MESON_PCLK(_name, _reg, _bit, _ops, _pname, _flags) \ +#define __MESON_PCLK(_name, _reg, _bit, _ops, _pdata, _flags) \ struct clk_regmap _name = { \ .data = &(struct clk_regmap_gate_data) { \ .offset = (_reg), \ @@ -36,16 +36,16 @@ struct clk_regmap _name = { \ .hw.init = &(struct clk_init_data) { \ .name = #_name, \ .ops = _ops, \ - .parent_hws = (const struct clk_hw *[]) { _pname }, \ + .parent_data = (_pdata), \ .num_parents = 1, \ .flags = (_flags), \ }, \ } -#define MESON_PCLK(_name, _reg, _bit, _pname, _flags) \ - __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ops, _pname, _flags) +#define MESON_PCLK(_name, _reg, _bit, _pdata, _flags) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ops, _pdata, _flags) -#define MESON_PCLK_RO(_name, _reg, _bit, _pname, _flags) \ - __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pname, _flags) +#define MESON_PCLK_RO(_name, _reg, _bit, _pdata, _flags) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pdata, _flags) #endif diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index a16ebbbf664c..95d0b9cbd904 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -2701,8 +2701,10 @@ static struct clk_regmap meson8b_cts_i958 = { }, }; +static const struct clk_parent_data meson8b_pclk_parents = { .hw = &meson8b_clk81.hw }; + #define MESON8B_PCLK(_name, _reg, _bit, _flags) \ - MESON_PCLK(_name, _reg, _bit, &meson8b_clk81.hw, _flags) + MESON_PCLK(_name, _reg, _bit, &meson8b_pclk_parents, _flags) /* * Everything Else (EE) domain gates @@ -2785,18 +2787,21 @@ static MESON8B_PCLK(meson8b_vclk2_other, HHI_GCLK_OTHER, 26, CLK_IGNORE_UNUSED); static MESON8B_PCLK(meson8b_edp, HHI_GCLK_OTHER, 31, CLK_IGNORE_UNUSED); /* AIU gates */ -static MESON_PCLK(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6, &meson8b_aiu.hw, CLK_IGNORE_UNUSED); +static const struct clk_parent_data meson8b_aiu_glue_parents = { .hw = &meson8b_aiu.hw }; +static MESON_PCLK(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6, + &meson8b_aiu_glue_parents, CLK_IGNORE_UNUSED); -#define MESON_AIU_PCLK(_name, _reg, _bit, _flags) \ - MESON_PCLK(_name, _reg, _bit, &meson8b_aiu_glue.hw, _flags) +static const struct clk_parent_data meson8b_aiu_pclk_parents = { .hw = &meson8b_aiu_glue.hw }; +#define MESON8B_AIU_PCLK(_name, _bit, _flags) \ + MESON_PCLK(_name, HHI_GCLK_MPEG1, _bit, &meson8b_aiu_pclk_parents, _flags) -static MESON_AIU_PCLK(meson8b_iec958, HHI_GCLK_MPEG1, 7, CLK_IGNORE_UNUSED); -static MESON_AIU_PCLK(meson8b_i2s_out, HHI_GCLK_MPEG1, 8, CLK_IGNORE_UNUSED); -static MESON_AIU_PCLK(meson8b_amclk, HHI_GCLK_MPEG1, 9, CLK_IGNORE_UNUSED); -static MESON_AIU_PCLK(meson8b_aififo2, HHI_GCLK_MPEG1, 10, CLK_IGNORE_UNUSED); -static MESON_AIU_PCLK(meson8b_mixer, HHI_GCLK_MPEG1, 11, CLK_IGNORE_UNUSED); -static MESON_AIU_PCLK(meson8b_mixer_iface, HHI_GCLK_MPEG1, 12, CLK_IGNORE_UNUSED); -static MESON_AIU_PCLK(meson8b_adc, HHI_GCLK_MPEG1, 13, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_iec958, 7, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_i2s_out, 8, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_amclk, 9, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_aififo2, 10, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_mixer, 11, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_mixer_iface, 12, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_adc, 13, CLK_IGNORE_UNUSED); /* Always On (AO) domain gates */ diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c index 23b51d84d8de..3e048e645b08 100644 --- a/drivers/clk/meson/s4-peripherals.c +++ b/drivers/clk/meson/s4-peripherals.c @@ -3165,8 +3165,10 @@ static struct clk_regmap s4_gen_clk = { }, }; +static const struct clk_parent_data s4_pclk_parents = { .hw = &s4_sys_clk.hw }; + #define S4_PCLK(_name, _reg, _bit, _flags) \ - MESON_PCLK(_name, _reg, _bit, &s4_sys_clk.hw, _flags) + MESON_PCLK(_name, _reg, _bit, &s4_pclk_parents, _flags) /* * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons From b7358d14f176a5508d6330dc967b4ce3a5b08684 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:34 +0200 Subject: [PATCH 0830/2711] clk: amlogic: use the common pclk definition Replace marcros defining pclks with the common one, reducing code duplication. Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-9-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg-aoclk.c | 35 +++++++-------------- drivers/clk/meson/c3-peripherals.c | 34 ++++++-------------- drivers/clk/meson/g12a-aoclk.c | 50 ++++++++++++------------------ drivers/clk/meson/gxbb-aoclk.c | 33 +++++++------------- 4 files changed, 51 insertions(+), 101 deletions(-) diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index 74c2f51424f1..902fbd34039c 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -34,30 +34,19 @@ #define AO_RTC_ALT_CLK_CNTL0 0x94 #define AO_RTC_ALT_CLK_CNTL1 0x98 -#define AXG_AO_GATE(_name, _bit, _flags) \ -static struct clk_regmap axg_ao_##_name = { \ - .data = &(struct clk_regmap_gate_data) { \ - .offset = (AO_RTI_GEN_CNTL_REG0), \ - .bit_idx = (_bit), \ - }, \ - .hw.init = &(struct clk_init_data) { \ - .name = "axg_ao_" #_name, \ - .ops = &clk_regmap_gate_ops, \ - .parent_data = &(const struct clk_parent_data) { \ - .fw_name = "mpeg-clk", \ - }, \ - .num_parents = 1, \ - .flags = (_flags), \ - }, \ -} +static const struct clk_parent_data axg_ao_pclk_parents = { .fw_name = "mpeg-clk" }; -AXG_AO_GATE(remote, 0, CLK_IGNORE_UNUSED); -AXG_AO_GATE(i2c_master, 1, CLK_IGNORE_UNUSED); -AXG_AO_GATE(i2c_slave, 2, CLK_IGNORE_UNUSED); -AXG_AO_GATE(uart1, 3, CLK_IGNORE_UNUSED); -AXG_AO_GATE(uart2, 5, CLK_IGNORE_UNUSED); -AXG_AO_GATE(ir_blaster, 6, CLK_IGNORE_UNUSED); -AXG_AO_GATE(saradc, 7, CLK_IGNORE_UNUSED); +#define AXG_AO_GATE(_name, _bit, _flags) \ + MESON_PCLK(axg_ao_##_name, AO_RTI_GEN_CNTL_REG0, _bit, \ + &axg_ao_pclk_parents, _flags) + +static AXG_AO_GATE(remote, 0, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(i2c_master, 1, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(i2c_slave, 2, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(uart1, 3, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(uart2, 5, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(ir_blaster, 6, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(saradc, 7, CLK_IGNORE_UNUSED); static struct clk_regmap axg_ao_cts_oscin = { .data = &(struct clk_regmap_gate_data){ diff --git a/drivers/clk/meson/c3-peripherals.c b/drivers/clk/meson/c3-peripherals.c index e9c1ef99be13..02c9820cd986 100644 --- a/drivers/clk/meson/c3-peripherals.c +++ b/drivers/clk/meson/c3-peripherals.c @@ -164,30 +164,13 @@ static struct clk_regmap c3_rtc_clk = { }, }; -#define C3_PCLK(_name, _reg, _bit, _fw_name, _ops, _flags) \ -struct clk_regmap c3_##_name = { \ - .data = &(struct clk_regmap_gate_data){ \ - .offset = (_reg), \ - .bit_idx = (_bit), \ - }, \ - .hw.init = &(struct clk_init_data) { \ - .name = "c3_" #_name, \ - .ops = _ops, \ - .parent_data = &(const struct clk_parent_data) { \ - .fw_name = (_fw_name), \ - }, \ - .num_parents = 1, \ - .flags = (_flags), \ - }, \ -} +static const struct clk_parent_data c3_sys_pclk_parents = { .fw_name = "sysclk" }; -#define C3_SYS_PCLK(_name, _reg, _bit, _flags) \ - C3_PCLK(_name, _reg, _bit, "sysclk", \ - &clk_regmap_gate_ops, _flags) +#define C3_SYS_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(c3_##_name, _reg, _bit, &c3_sys_pclk_parents, _flags) -#define C3_SYS_PCLK_RO(_name, _reg, _bit) \ - C3_PCLK(_name, _reg, _bit, "sysclk", \ - &clk_regmap_gate_ro_ops, 0) +#define C3_SYS_PCLK_RO(_name, _reg, _bit) \ + MESON_PCLK_RO(c3_##_name, _reg, _bit, &c3_sys_pclk_parents, 0) static C3_SYS_PCLK(sys_reset_ctrl, SYS_CLK_EN0_REG0, 1, 0); static C3_SYS_PCLK(sys_pwr_ctrl, SYS_CLK_EN0_REG0, 3, 0); @@ -290,9 +273,10 @@ static C3_SYS_PCLK(sys_vc9000e, SYS_CLK_EN0_REG2, 2, 0); static C3_SYS_PCLK(sys_pwm_mn, SYS_CLK_EN0_REG2, 3, 0); static C3_SYS_PCLK(sys_sd_emmc_b, SYS_CLK_EN0_REG2, 4, 0); -#define C3_AXI_PCLK(_name, _reg, _bit, _flags) \ - C3_PCLK(_name, _reg, _bit, "axiclk", \ - &clk_regmap_gate_ops, _flags) +static const struct clk_parent_data c3_axi_pclk_parents = { .fw_name = "axiclk" }; + +#define C3_AXI_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(c3_##_name, _reg, _bit, &c3_axi_pclk_parents, _flags) /* * NOTE: axi_sys_nic provides the clock to the AXI bus of the system NIC. After diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c index 45e4df393feb..96981da271fa 100644 --- a/drivers/clk/meson/g12a-aoclk.c +++ b/drivers/clk/meson/g12a-aoclk.c @@ -37,22 +37,10 @@ #define AO_RTC_ALT_CLK_CNTL0 0x94 #define AO_RTC_ALT_CLK_CNTL1 0x98 -#define G12A_AO_PCLK(_name, _reg, _bit, _flags) \ -static struct clk_regmap g12a_ao_##_name = { \ - .data = &(struct clk_regmap_gate_data) { \ - .offset = (_reg), \ - .bit_idx = (_bit), \ - }, \ - .hw.init = &(struct clk_init_data) { \ - .name = "g12a_ao_" #_name, \ - .ops = &clk_regmap_gate_ops, \ - .parent_data = &(const struct clk_parent_data) { \ - .fw_name = "mpeg-clk", \ - }, \ - .num_parents = 1, \ - .flags = (_flags), \ - }, \ -} +static const struct clk_parent_data g12a_ao_pclk_parents = { .fw_name = "mpeg-clk" }; + +#define G12A_AO_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(g12a_ao_##_name, _reg, _bit, &g12a_ao_pclk_parents, _flags) /* * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons @@ -63,22 +51,22 @@ static struct clk_regmap g12a_ao_##_name = { \ * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable * for a particular clock. */ -G12A_AO_PCLK(ahb, AO_CLK_GATE0, 0, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(ir_in, AO_CLK_GATE0, 1, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(i2c_m0, AO_CLK_GATE0, 2, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(i2c_s0, AO_CLK_GATE0, 3, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(uart, AO_CLK_GATE0, 4, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(prod_i2c, AO_CLK_GATE0, 5, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(uart2, AO_CLK_GATE0, 6, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(ir_out, AO_CLK_GATE0, 7, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(saradc, AO_CLK_GATE0, 8, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(ahb, AO_CLK_GATE0, 0, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(ir_in, AO_CLK_GATE0, 1, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(i2c_m0, AO_CLK_GATE0, 2, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(i2c_s0, AO_CLK_GATE0, 3, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(uart, AO_CLK_GATE0, 4, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(prod_i2c, AO_CLK_GATE0, 5, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(uart2, AO_CLK_GATE0, 6, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(ir_out, AO_CLK_GATE0, 7, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(saradc, AO_CLK_GATE0, 8, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(mailbox, AO_CLK_GATE0_SP, 0, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(m3, AO_CLK_GATE0_SP, 1, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(ahb_sram, AO_CLK_GATE0_SP, 2, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(rti, AO_CLK_GATE0_SP, 3, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(m4_fclk, AO_CLK_GATE0_SP, 4, CLK_IGNORE_UNUSED); -G12A_AO_PCLK(m4_hclk, AO_CLK_GATE0_SP, 5, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(mailbox, AO_CLK_GATE0_SP, 0, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(m3, AO_CLK_GATE0_SP, 1, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(ahb_sram, AO_CLK_GATE0_SP, 2, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(rti, AO_CLK_GATE0_SP, 3, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(m4_fclk, AO_CLK_GATE0_SP, 4, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(m4_hclk, AO_CLK_GATE0_SP, 5, CLK_IGNORE_UNUSED); static struct clk_regmap g12a_ao_cts_oscin = { .data = &(struct clk_regmap_gate_data){ diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 2bf45fd7fe4b..c7dfb3a06cb5 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -23,29 +23,18 @@ #define AO_RTC_ALT_CLK_CNTL0 0x94 #define AO_RTC_ALT_CLK_CNTL1 0x98 -#define GXBB_AO_PCLK(_name, _bit, _flags) \ -static struct clk_regmap gxbb_ao_##_name = { \ - .data = &(struct clk_regmap_gate_data) { \ - .offset = AO_RTI_GEN_CNTL_REG0, \ - .bit_idx = (_bit), \ - }, \ - .hw.init = &(struct clk_init_data) { \ - .name = "gxbb_ao_" #_name, \ - .ops = &clk_regmap_gate_ops, \ - .parent_data = &(const struct clk_parent_data) { \ - .fw_name = "mpeg-clk", \ - }, \ - .num_parents = 1, \ - .flags = (_flags), \ - }, \ -} +static const struct clk_parent_data gxbb_ao_pclk_parents = { .fw_name = "mpeg-clk" }; -GXBB_AO_PCLK(remote, 0, CLK_IGNORE_UNUSED); -GXBB_AO_PCLK(i2c_master, 1, CLK_IGNORE_UNUSED); -GXBB_AO_PCLK(i2c_slave, 2, CLK_IGNORE_UNUSED); -GXBB_AO_PCLK(uart1, 3, CLK_IGNORE_UNUSED); -GXBB_AO_PCLK(uart2, 5, CLK_IGNORE_UNUSED); -GXBB_AO_PCLK(ir_blaster, 6, CLK_IGNORE_UNUSED); +#define GXBB_AO_PCLK(_name, _bit, _flags) \ + MESON_PCLK(gxbb_ao_##_name, AO_RTI_GEN_CNTL_REG0, _bit, \ + &gxbb_ao_pclk_parents, _flags) + +static GXBB_AO_PCLK(remote, 0, CLK_IGNORE_UNUSED); +static GXBB_AO_PCLK(i2c_master, 1, CLK_IGNORE_UNUSED); +static GXBB_AO_PCLK(i2c_slave, 2, CLK_IGNORE_UNUSED); +static GXBB_AO_PCLK(uart1, 3, CLK_IGNORE_UNUSED); +static GXBB_AO_PCLK(uart2, 5, CLK_IGNORE_UNUSED); +static GXBB_AO_PCLK(ir_blaster, 6, CLK_IGNORE_UNUSED); static struct clk_regmap gxbb_ao_cts_oscin = { .data = &(struct clk_regmap_gate_data){ From 955e18baeb933096f417ac01d6781380d7c8a374 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:35 +0200 Subject: [PATCH 0831/2711] clk: amlogic: add composite clock helpers Device composite clocks tend to reproduce the usual sel/div/gate arrangement. Add macros to help define simple composite clocks in the system. The idea is _not_ to replace all instances of mux, div or gate with those macros. It is rather to use it for recurring and/or simple composite clocks, reducing controller verbosity where it makes sense. This should help reviews focus on the tricky parts. Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-10-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/meson-clkc-utils.h | 57 ++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/drivers/clk/meson/meson-clkc-utils.h b/drivers/clk/meson/meson-clkc-utils.h index 95d9f85f7ca2..ddadf14b4923 100644 --- a/drivers/clk/meson/meson-clkc-utils.h +++ b/drivers/clk/meson/meson-clkc-utils.h @@ -48,4 +48,61 @@ struct clk_regmap _name = { \ #define MESON_PCLK_RO(_name, _reg, _bit, _pdata, _flags) \ __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pdata, _flags) +/* Helpers for the usual sel/div/gate composite clocks */ +#define MESON_COMP_SEL(_prefix, _name, _reg, _shift, _mask, _pdata, \ + _table, _dflags, _iflags) \ +struct clk_regmap _prefix##_name##_sel = { \ + .data = &(struct clk_regmap_mux_data) { \ + .offset = (_reg), \ + .mask = (_mask), \ + .shift = (_shift), \ + .flags = (_dflags), \ + .table = (_table), \ + }, \ + .hw.init = &(struct clk_init_data){ \ + .name = #_name "_sel", \ + .ops = &clk_regmap_mux_ops, \ + .parent_data = _pdata, \ + .num_parents = ARRAY_SIZE(_pdata), \ + .flags = (_iflags), \ + }, \ +} + +#define MESON_COMP_DIV(_prefix, _name, _reg, _shift, _width, \ + _dflags, _iflags) \ +struct clk_regmap _prefix##_name##_div = { \ + .data = &(struct clk_regmap_div_data) { \ + .offset = (_reg), \ + .shift = (_shift), \ + .width = (_width), \ + .flags = (_dflags), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name "_div", \ + .ops = &clk_regmap_divider_ops, \ + .parent_hws = (const struct clk_hw *[]) { \ + &_prefix##_name##_sel.hw \ + }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + +#define MESON_COMP_GATE(_prefix, _name, _reg, _bit, _iflags) \ +struct clk_regmap _prefix##_name = { \ + .data = &(struct clk_regmap_gate_data) { \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &clk_regmap_gate_ops, \ + .parent_hws = (const struct clk_hw *[]) { \ + &_prefix##_name##_div.hw \ + }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + #endif From 9bada5ff4bf7a057d40ae49eab5d9081535b5f3c Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:36 +0200 Subject: [PATCH 0832/2711] clk: amlogic: align s4 and c3 pwm clock descriptions s4 and c3 follow exactly the same structure when it comes to PWM clocks but differ in the way these clocks are described, for no obvious reason. Align the description of the pwm clocks of these SoCs with the composite clock helpers. Reviewed-by: Chuan Liu Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-11-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/c3-peripherals.c | 178 +++------- drivers/clk/meson/s4-peripherals.c | 508 +++-------------------------- 2 files changed, 90 insertions(+), 596 deletions(-) diff --git a/drivers/clk/meson/c3-peripherals.c b/drivers/clk/meson/c3-peripherals.c index 02c9820cd986..fd35f9b79947 100644 --- a/drivers/clk/meson/c3-peripherals.c +++ b/drivers/clk/meson/c3-peripherals.c @@ -48,6 +48,15 @@ #define SPIFC_CLK_CTRL 0x1a0 #define NNA_CLK_CTRL 0x220 +#define C3_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \ + MESON_COMP_SEL(c3_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0) + +#define C3_COMP_DIV(_name, _reg, _shift, _width) \ + MESON_COMP_DIV(c3_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT) + +#define C3_COMP_GATE(_name, _reg, _bit) \ + MESON_COMP_GATE(c3_, _name, _reg, _bit, CLK_SET_RATE_PARENT) + static struct clk_regmap c3_rtc_xtal_clkin = { .data = &(struct clk_regmap_gate_data) { .offset = RTC_BY_OSCIN_CTRL0, @@ -512,146 +521,61 @@ static const struct clk_parent_data c3_pwm_parents[] = { { .fw_name = "fdiv3" } }; -#define C3_PWM_CLK_MUX(_name, _reg, _shift) { \ - .data = &(struct clk_regmap_mux_data) { \ - .offset = _reg, \ - .mask = 0x3, \ - .shift = _shift, \ - }, \ - .hw.init = &(struct clk_init_data) { \ - .name = #_name "_sel", \ - .ops = &clk_regmap_mux_ops, \ - .parent_data = c3_pwm_parents, \ - .num_parents = ARRAY_SIZE(c3_pwm_parents), \ - }, \ -} +static C3_COMP_SEL(pwm_a, PWM_CLK_AB_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_a, PWM_CLK_AB_CTRL, 0, 8); +static C3_COMP_GATE(pwm_a, PWM_CLK_AB_CTRL, 8); -#define C3_PWM_CLK_DIV(_name, _reg, _shift) { \ - .data = &(struct clk_regmap_div_data) { \ - .offset = _reg, \ - .shift = _shift, \ - .width = 8, \ - }, \ - .hw.init = &(struct clk_init_data) { \ - .name = #_name "_div", \ - .ops = &clk_regmap_divider_ops, \ - .parent_names = (const char *[]) { #_name "_sel" },\ - .num_parents = 1, \ - .flags = CLK_SET_RATE_PARENT, \ - }, \ -} +static C3_COMP_SEL(pwm_b, PWM_CLK_AB_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_b, PWM_CLK_AB_CTRL, 16, 8); +static C3_COMP_GATE(pwm_b, PWM_CLK_AB_CTRL, 24); -#define C3_PWM_CLK_GATE(_name, _reg, _bit) { \ - .data = &(struct clk_regmap_gate_data) { \ - .offset = _reg, \ - .bit_idx = _bit, \ - }, \ - .hw.init = &(struct clk_init_data) { \ - .name = #_name, \ - .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]) { #_name "_div" },\ - .num_parents = 1, \ - .flags = CLK_SET_RATE_PARENT, \ - }, \ -} +static C3_COMP_SEL(pwm_c, PWM_CLK_CD_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_c, PWM_CLK_CD_CTRL, 0, 8); +static C3_COMP_GATE(pwm_c, PWM_CLK_CD_CTRL, 8); -static struct clk_regmap c3_pwm_a_sel = - C3_PWM_CLK_MUX(pwm_a, PWM_CLK_AB_CTRL, 9); -static struct clk_regmap c3_pwm_a_div = - C3_PWM_CLK_DIV(pwm_a, PWM_CLK_AB_CTRL, 0); -static struct clk_regmap c3_pwm_a = - C3_PWM_CLK_GATE(pwm_a, PWM_CLK_AB_CTRL, 8); +static C3_COMP_SEL(pwm_d, PWM_CLK_CD_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_d, PWM_CLK_CD_CTRL, 16, 8); +static C3_COMP_GATE(pwm_d, PWM_CLK_CD_CTRL, 24); -static struct clk_regmap c3_pwm_b_sel = - C3_PWM_CLK_MUX(pwm_b, PWM_CLK_AB_CTRL, 25); -static struct clk_regmap c3_pwm_b_div = - C3_PWM_CLK_DIV(pwm_b, PWM_CLK_AB_CTRL, 16); -static struct clk_regmap c3_pwm_b = - C3_PWM_CLK_GATE(pwm_b, PWM_CLK_AB_CTRL, 24); +static C3_COMP_SEL(pwm_e, PWM_CLK_EF_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_e, PWM_CLK_EF_CTRL, 0, 8); +static C3_COMP_GATE(pwm_e, PWM_CLK_EF_CTRL, 8); -static struct clk_regmap c3_pwm_c_sel = - C3_PWM_CLK_MUX(pwm_c, PWM_CLK_CD_CTRL, 9); -static struct clk_regmap c3_pwm_c_div = - C3_PWM_CLK_DIV(pwm_c, PWM_CLK_CD_CTRL, 0); -static struct clk_regmap c3_pwm_c = - C3_PWM_CLK_GATE(pwm_c, PWM_CLK_CD_CTRL, 8); +static C3_COMP_SEL(pwm_f, PWM_CLK_EF_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_f, PWM_CLK_EF_CTRL, 16, 8); +static C3_COMP_GATE(pwm_f, PWM_CLK_EF_CTRL, 24); -static struct clk_regmap c3_pwm_d_sel = - C3_PWM_CLK_MUX(pwm_d, PWM_CLK_CD_CTRL, 25); -static struct clk_regmap c3_pwm_d_div = - C3_PWM_CLK_DIV(pwm_d, PWM_CLK_CD_CTRL, 16); -static struct clk_regmap c3_pwm_d = - C3_PWM_CLK_GATE(pwm_d, PWM_CLK_CD_CTRL, 24); +static C3_COMP_SEL(pwm_g, PWM_CLK_GH_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_g, PWM_CLK_GH_CTRL, 0, 8); +static C3_COMP_GATE(pwm_g, PWM_CLK_GH_CTRL, 8); -static struct clk_regmap c3_pwm_e_sel = - C3_PWM_CLK_MUX(pwm_e, PWM_CLK_EF_CTRL, 9); -static struct clk_regmap c3_pwm_e_div = - C3_PWM_CLK_DIV(pwm_e, PWM_CLK_EF_CTRL, 0); -static struct clk_regmap c3_pwm_e = - C3_PWM_CLK_GATE(pwm_e, PWM_CLK_EF_CTRL, 8); +static C3_COMP_SEL(pwm_h, PWM_CLK_GH_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_h, PWM_CLK_GH_CTRL, 16, 8); +static C3_COMP_GATE(pwm_h, PWM_CLK_GH_CTRL, 24); -static struct clk_regmap c3_pwm_f_sel = - C3_PWM_CLK_MUX(pwm_f, PWM_CLK_EF_CTRL, 25); -static struct clk_regmap c3_pwm_f_div = - C3_PWM_CLK_DIV(pwm_f, PWM_CLK_EF_CTRL, 16); -static struct clk_regmap c3_pwm_f = - C3_PWM_CLK_GATE(pwm_f, PWM_CLK_EF_CTRL, 24); +static C3_COMP_SEL(pwm_i, PWM_CLK_IJ_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_i, PWM_CLK_IJ_CTRL, 0, 8); +static C3_COMP_GATE(pwm_i, PWM_CLK_IJ_CTRL, 8); -static struct clk_regmap c3_pwm_g_sel = - C3_PWM_CLK_MUX(pwm_g, PWM_CLK_GH_CTRL, 9); -static struct clk_regmap c3_pwm_g_div = - C3_PWM_CLK_DIV(pwm_g, PWM_CLK_GH_CTRL, 0); -static struct clk_regmap c3_pwm_g = - C3_PWM_CLK_GATE(pwm_g, PWM_CLK_GH_CTRL, 8); +static C3_COMP_SEL(pwm_j, PWM_CLK_IJ_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_j, PWM_CLK_IJ_CTRL, 16, 8); +static C3_COMP_GATE(pwm_j, PWM_CLK_IJ_CTRL, 24); -static struct clk_regmap c3_pwm_h_sel = - C3_PWM_CLK_MUX(pwm_h, PWM_CLK_GH_CTRL, 25); -static struct clk_regmap c3_pwm_h_div = - C3_PWM_CLK_DIV(pwm_h, PWM_CLK_GH_CTRL, 16); -static struct clk_regmap c3_pwm_h = - C3_PWM_CLK_GATE(pwm_h, PWM_CLK_GH_CTRL, 24); +static C3_COMP_SEL(pwm_k, PWM_CLK_KL_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_k, PWM_CLK_KL_CTRL, 0, 8); +static C3_COMP_GATE(pwm_k, PWM_CLK_KL_CTRL, 8); -static struct clk_regmap c3_pwm_i_sel = - C3_PWM_CLK_MUX(pwm_i, PWM_CLK_IJ_CTRL, 9); -static struct clk_regmap c3_pwm_i_div = - C3_PWM_CLK_DIV(pwm_i, PWM_CLK_IJ_CTRL, 0); -static struct clk_regmap c3_pwm_i = - C3_PWM_CLK_GATE(pwm_i, PWM_CLK_IJ_CTRL, 8); +static C3_COMP_SEL(pwm_l, PWM_CLK_KL_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_l, PWM_CLK_KL_CTRL, 16, 8); +static C3_COMP_GATE(pwm_l, PWM_CLK_KL_CTRL, 24); -static struct clk_regmap c3_pwm_j_sel = - C3_PWM_CLK_MUX(pwm_j, PWM_CLK_IJ_CTRL, 25); -static struct clk_regmap c3_pwm_j_div = - C3_PWM_CLK_DIV(pwm_j, PWM_CLK_IJ_CTRL, 16); -static struct clk_regmap c3_pwm_j = - C3_PWM_CLK_GATE(pwm_j, PWM_CLK_IJ_CTRL, 24); +static C3_COMP_SEL(pwm_m, PWM_CLK_MN_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_m, PWM_CLK_MN_CTRL, 0, 8); +static C3_COMP_GATE(pwm_m, PWM_CLK_MN_CTRL, 8); -static struct clk_regmap c3_pwm_k_sel = - C3_PWM_CLK_MUX(pwm_k, PWM_CLK_KL_CTRL, 9); -static struct clk_regmap c3_pwm_k_div = - C3_PWM_CLK_DIV(pwm_k, PWM_CLK_KL_CTRL, 0); -static struct clk_regmap c3_pwm_k = - C3_PWM_CLK_GATE(pwm_k, PWM_CLK_KL_CTRL, 8); - -static struct clk_regmap c3_pwm_l_sel = - C3_PWM_CLK_MUX(pwm_l, PWM_CLK_KL_CTRL, 25); -static struct clk_regmap c3_pwm_l_div = - C3_PWM_CLK_DIV(pwm_l, PWM_CLK_KL_CTRL, 16); -static struct clk_regmap c3_pwm_l = - C3_PWM_CLK_GATE(pwm_l, PWM_CLK_KL_CTRL, 24); - -static struct clk_regmap c3_pwm_m_sel = - C3_PWM_CLK_MUX(pwm_m, PWM_CLK_MN_CTRL, 9); -static struct clk_regmap c3_pwm_m_div = - C3_PWM_CLK_DIV(pwm_m, PWM_CLK_MN_CTRL, 0); -static struct clk_regmap c3_pwm_m = - C3_PWM_CLK_GATE(pwm_m, PWM_CLK_MN_CTRL, 8); - -static struct clk_regmap c3_pwm_n_sel = - C3_PWM_CLK_MUX(pwm_n, PWM_CLK_MN_CTRL, 25); -static struct clk_regmap c3_pwm_n_div = - C3_PWM_CLK_DIV(pwm_n, PWM_CLK_MN_CTRL, 16); -static struct clk_regmap c3_pwm_n = - C3_PWM_CLK_GATE(pwm_n, PWM_CLK_MN_CTRL, 24); +static C3_COMP_SEL(pwm_n, PWM_CLK_MN_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_n, PWM_CLK_MN_CTRL, 16, 8); +static C3_COMP_GATE(pwm_n, PWM_CLK_MN_CTRL, 24); static const struct clk_parent_data c3_spicc_parents[] = { { .fw_name = "oscin" }, diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c index 3e048e645b08..6d69b132d1e1 100644 --- a/drivers/clk/meson/s4-peripherals.c +++ b/drivers/clk/meson/s4-peripherals.c @@ -62,6 +62,15 @@ #define CLKCTRL_PWM_CLK_IJ_CTRL 0x190 #define CLKCTRL_DEMOD_CLK_CTRL 0x200 +#define S4_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \ + MESON_COMP_SEL(s4_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0) + +#define S4_COMP_DIV(_name, _reg, _shift, _width) \ + MESON_COMP_DIV(s4_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT) + +#define S4_COMP_GATE(_name, _reg, _bit) \ + MESON_COMP_GATE(s4_, _name, _reg, _bit, CLK_SET_RATE_PARENT) + static struct clk_regmap s4_rtc_32k_by_oscin_clkin = { .data = &(struct clk_regmap_gate_data){ .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0, @@ -2559,484 +2568,45 @@ static const struct clk_parent_data s4_pwm_parents[] = { { .fw_name = "fclk_div3", }, }; -static struct clk_regmap s4_pwm_a_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = CLKCTRL_PWM_CLK_AB_CTRL, - .mask = 0x3, - .shift = 9, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_a_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parents, - .num_parents = ARRAY_SIZE(s4_pwm_parents), - .flags = 0, - }, -}; +static S4_COMP_SEL(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 9, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 0, 8); +static S4_COMP_GATE(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 8); -static struct clk_regmap s4_pwm_a_div = { - .data = &(struct clk_regmap_div_data) { - .offset = CLKCTRL_PWM_CLK_AB_CTRL, - .shift = 0, - .width = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_a_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_a_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static S4_COMP_SEL(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 25, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 16, 8); +static S4_COMP_GATE(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 24); -static struct clk_regmap s4_pwm_a = { - .data = &(struct clk_regmap_gate_data) { - .offset = CLKCTRL_PWM_CLK_AB_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_a_gate", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_a_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static S4_COMP_SEL(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 9, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 0, 8); +static S4_COMP_GATE(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 8); -static struct clk_regmap s4_pwm_b_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = CLKCTRL_PWM_CLK_AB_CTRL, - .mask = 0x3, - .shift = 25, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_b_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parents, - .num_parents = ARRAY_SIZE(s4_pwm_parents), - .flags = 0, - }, -}; +static S4_COMP_SEL(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 25, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 16, 8); +static S4_COMP_GATE(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 24); -static struct clk_regmap s4_pwm_b_div = { - .data = &(struct clk_regmap_div_data) { - .offset = CLKCTRL_PWM_CLK_AB_CTRL, - .shift = 16, - .width = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_b_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_b_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static S4_COMP_SEL(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 9, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 0, 8); +static S4_COMP_GATE(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 8); -static struct clk_regmap s4_pwm_b = { - .data = &(struct clk_regmap_gate_data) { - .offset = CLKCTRL_PWM_CLK_AB_CTRL, - .bit_idx = 24, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_b", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_b_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static S4_COMP_SEL(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 25, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 16, 8); +static S4_COMP_GATE(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 24); -static struct clk_regmap s4_pwm_c_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = CLKCTRL_PWM_CLK_CD_CTRL, - .mask = 0x3, - .shift = 9, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_c_mux", - .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parents, - .num_parents = ARRAY_SIZE(s4_pwm_parents), - .flags = 0, - }, -}; +static S4_COMP_SEL(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 9, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 0, 8); +static S4_COMP_GATE(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 8); -static struct clk_regmap s4_pwm_c_div = { - .data = &(struct clk_regmap_div_data) { - .offset = CLKCTRL_PWM_CLK_CD_CTRL, - .shift = 0, - .width = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_c_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_c_sel.hw - }, - .num_parents = 1, - }, -}; +static S4_COMP_SEL(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 25, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 16, 8); +static S4_COMP_GATE(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 24); -static struct clk_regmap s4_pwm_c = { - .data = &(struct clk_regmap_gate_data) { - .offset = CLKCTRL_PWM_CLK_CD_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_c", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_c_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static S4_COMP_SEL(pwm_i, CLKCTRL_PWM_CLK_IJ_CTRL, 9, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_i, CLKCTRL_PWM_CLK_IJ_CTRL, 0, 8); +static S4_COMP_GATE(pwm_i, CLKCTRL_PWM_CLK_IJ_CTRL, 8); -static struct clk_regmap s4_pwm_d_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = CLKCTRL_PWM_CLK_CD_CTRL, - .mask = 0x3, - .shift = 25, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_d_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parents, - .num_parents = ARRAY_SIZE(s4_pwm_parents), - .flags = 0, - }, -}; - -static struct clk_regmap s4_pwm_d_div = { - .data = &(struct clk_regmap_div_data) { - .offset = CLKCTRL_PWM_CLK_CD_CTRL, - .shift = 16, - .width = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_d_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_d_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_d = { - .data = &(struct clk_regmap_gate_data) { - .offset = CLKCTRL_PWM_CLK_CD_CTRL, - .bit_idx = 24, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_d", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_d_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_e_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = CLKCTRL_PWM_CLK_EF_CTRL, - .mask = 0x3, - .shift = 9, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_e_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parents, - .num_parents = ARRAY_SIZE(s4_pwm_parents), - .flags = 0, - }, -}; - -static struct clk_regmap s4_pwm_e_div = { - .data = &(struct clk_regmap_div_data) { - .offset = CLKCTRL_PWM_CLK_EF_CTRL, - .shift = 0, - .width = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_e_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_e_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_e = { - .data = &(struct clk_regmap_gate_data) { - .offset = CLKCTRL_PWM_CLK_EF_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_e", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_e_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_f_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = CLKCTRL_PWM_CLK_EF_CTRL, - .mask = 0x3, - .shift = 25, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_f_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parents, - .num_parents = ARRAY_SIZE(s4_pwm_parents), - .flags = 0, - }, -}; - -static struct clk_regmap s4_pwm_f_div = { - .data = &(struct clk_regmap_div_data) { - .offset = CLKCTRL_PWM_CLK_EF_CTRL, - .shift = 16, - .width = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_f_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_f_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_f = { - .data = &(struct clk_regmap_gate_data) { - .offset = CLKCTRL_PWM_CLK_EF_CTRL, - .bit_idx = 24, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_f", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_f_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_g_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = CLKCTRL_PWM_CLK_GH_CTRL, - .mask = 0x3, - .shift = 9, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_g_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parents, - .num_parents = ARRAY_SIZE(s4_pwm_parents), - .flags = 0, - }, -}; - -static struct clk_regmap s4_pwm_g_div = { - .data = &(struct clk_regmap_div_data) { - .offset = CLKCTRL_PWM_CLK_GH_CTRL, - .shift = 0, - .width = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_g_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_g_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_g = { - .data = &(struct clk_regmap_gate_data) { - .offset = CLKCTRL_PWM_CLK_GH_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_g", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_g_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_h_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = CLKCTRL_PWM_CLK_GH_CTRL, - .mask = 0x3, - .shift = 25, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_h_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parents, - .num_parents = ARRAY_SIZE(s4_pwm_parents), - .flags = 0, - }, -}; - -static struct clk_regmap s4_pwm_h_div = { - .data = &(struct clk_regmap_div_data) { - .offset = CLKCTRL_PWM_CLK_GH_CTRL, - .shift = 16, - .width = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_h_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_h_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_h = { - .data = &(struct clk_regmap_gate_data) { - .offset = CLKCTRL_PWM_CLK_GH_CTRL, - .bit_idx = 24, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_h", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_h_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_i_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = CLKCTRL_PWM_CLK_IJ_CTRL, - .mask = 0x3, - .shift = 9, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_i_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parents, - .num_parents = ARRAY_SIZE(s4_pwm_parents), - .flags = 0, - }, -}; - -static struct clk_regmap s4_pwm_i_div = { - .data = &(struct clk_regmap_div_data) { - .offset = CLKCTRL_PWM_CLK_IJ_CTRL, - .shift = 0, - .width = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_i_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_i_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_i = { - .data = &(struct clk_regmap_gate_data) { - .offset = CLKCTRL_PWM_CLK_IJ_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_i", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_i_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_j_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = CLKCTRL_PWM_CLK_IJ_CTRL, - .mask = 0x3, - .shift = 25, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_j_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = s4_pwm_parents, - .num_parents = ARRAY_SIZE(s4_pwm_parents), - .flags = 0, - }, -}; - -static struct clk_regmap s4_pwm_j_div = { - .data = &(struct clk_regmap_div_data) { - .offset = CLKCTRL_PWM_CLK_IJ_CTRL, - .shift = 16, - .width = 8, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_j_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_j_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap s4_pwm_j = { - .data = &(struct clk_regmap_gate_data) { - .offset = CLKCTRL_PWM_CLK_IJ_CTRL, - .bit_idx = 24, - }, - .hw.init = &(struct clk_init_data){ - .name = "pwm_j", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &s4_pwm_j_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static S4_COMP_SEL(pwm_j, CLKCTRL_PWM_CLK_IJ_CTRL, 25, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_j, CLKCTRL_PWM_CLK_IJ_CTRL, 16, 8); +static S4_COMP_GATE(pwm_j, CLKCTRL_PWM_CLK_IJ_CTRL, 24); static struct clk_regmap s4_saradc_sel = { .data = &(struct clk_regmap_mux_data) { From 01f3a6d1d59b8e25a6de243b0d73075cf0415eaf Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 25 Aug 2025 16:26:37 +0200 Subject: [PATCH 0833/2711] clk: amlogic: c3-peripherals: use helper for basic composite clocks Use the composite clock helpers to define simple composite clocks of the c3-peripherals clock controller. This reduces the verbosity of the controller code on these very simple parts, making maintenance simpler. Reviewed-by: Chuan Liu Link: https://lore.kernel.org/r/20250825-meson-clk-cleanup-24-v2-12-0f402f01e117@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/c3-peripherals.c | 1029 ++-------------------------- 1 file changed, 63 insertions(+), 966 deletions(-) diff --git a/drivers/clk/meson/c3-peripherals.c b/drivers/clk/meson/c3-peripherals.c index fd35f9b79947..b158756cfee4 100644 --- a/drivers/clk/meson/c3-peripherals.c +++ b/drivers/clk/meson/c3-peripherals.c @@ -467,52 +467,9 @@ static const struct clk_parent_data c3_saradc_parents[] = { { .fw_name = "sysclk" } }; -static struct clk_regmap c3_saradc_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = SAR_CLK_CTRL0, - .mask = 0x1, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "saradc_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_saradc_parents, - .num_parents = ARRAY_SIZE(c3_saradc_parents), - }, -}; - -static struct clk_regmap c3_saradc_div = { - .data = &(struct clk_regmap_div_data) { - .offset = SAR_CLK_CTRL0, - .shift = 0, - .width = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "saradc_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_saradc_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_saradc = { - .data = &(struct clk_regmap_gate_data) { - .offset = SAR_CLK_CTRL0, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "saradc", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_saradc_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(saradc, SAR_CLK_CTRL0, 9, 0x1, c3_saradc_parents); +static C3_COMP_DIV(saradc, SAR_CLK_CTRL0, 0, 8); +static C3_COMP_GATE(saradc, SAR_CLK_CTRL0, 8); static const struct clk_parent_data c3_pwm_parents[] = { { .fw_name = "oscin" }, @@ -588,99 +545,13 @@ static const struct clk_parent_data c3_spicc_parents[] = { { .fw_name = "gp1" } }; -static struct clk_regmap c3_spicc_a_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = SPICC_CLK_CTRL, - .mask = 0x7, - .shift = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "spicc_a_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_spicc_parents, - .num_parents = ARRAY_SIZE(c3_spicc_parents), - }, -}; +static C3_COMP_SEL(spicc_a, SPICC_CLK_CTRL, 7, 0x7, c3_spicc_parents); +static C3_COMP_DIV(spicc_a, SPICC_CLK_CTRL, 0, 6); +static C3_COMP_GATE(spicc_a, SPICC_CLK_CTRL, 6); -static struct clk_regmap c3_spicc_a_div = { - .data = &(struct clk_regmap_div_data) { - .offset = SPICC_CLK_CTRL, - .shift = 0, - .width = 6, - }, - .hw.init = &(struct clk_init_data) { - .name = "spicc_a_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_spicc_a_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_spicc_a = { - .data = &(struct clk_regmap_gate_data) { - .offset = SPICC_CLK_CTRL, - .bit_idx = 6, - }, - .hw.init = &(struct clk_init_data) { - .name = "spicc_a", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_spicc_a_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_spicc_b_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = SPICC_CLK_CTRL, - .mask = 0x7, - .shift = 23, - }, - .hw.init = &(struct clk_init_data) { - .name = "spicc_b_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_spicc_parents, - .num_parents = ARRAY_SIZE(c3_spicc_parents), - }, -}; - -static struct clk_regmap c3_spicc_b_div = { - .data = &(struct clk_regmap_div_data) { - .offset = SPICC_CLK_CTRL, - .shift = 16, - .width = 6, - }, - .hw.init = &(struct clk_init_data) { - .name = "spicc_b_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_spicc_b_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_spicc_b = { - .data = &(struct clk_regmap_gate_data) { - .offset = SPICC_CLK_CTRL, - .bit_idx = 22, - }, - .hw.init = &(struct clk_init_data) { - .name = "spicc_b", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_spicc_b_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(spicc_b, SPICC_CLK_CTRL, 23, 0x7, c3_spicc_parents); +static C3_COMP_DIV(spicc_b, SPICC_CLK_CTRL, 16, 6); +static C3_COMP_GATE(spicc_b, SPICC_CLK_CTRL, 22); static const struct clk_parent_data c3_spifc_parents[] = { { .fw_name = "gp0" }, @@ -693,52 +564,9 @@ static const struct clk_parent_data c3_spifc_parents[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap c3_spifc_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = SPIFC_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "spifc_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_spifc_parents, - .num_parents = ARRAY_SIZE(c3_spifc_parents), - }, -}; - -static struct clk_regmap c3_spifc_div = { - .data = &(struct clk_regmap_div_data) { - .offset = SPIFC_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "spifc_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_spifc_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_spifc = { - .data = &(struct clk_regmap_gate_data) { - .offset = SPIFC_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "spifc", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_spifc_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(spifc, SPIFC_CLK_CTRL, 9, 0x7, c3_spifc_parents); +static C3_COMP_DIV(spifc, SPIFC_CLK_CTRL, 0, 7); +static C3_COMP_GATE(spifc, SPIFC_CLK_CTRL, 8); static const struct clk_parent_data c3_sd_emmc_parents[] = { { .fw_name = "oscin" }, @@ -751,146 +579,17 @@ static const struct clk_parent_data c3_sd_emmc_parents[] = { { .fw_name = "gp0" } }; -static struct clk_regmap c3_sd_emmc_a_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = SD_EMMC_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "sd_emmc_a_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_sd_emmc_parents, - .num_parents = ARRAY_SIZE(c3_sd_emmc_parents), - }, -}; +static C3_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL, 9, 0x7, c3_sd_emmc_parents); +static C3_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL, 0, 7); +static C3_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL, 7); -static struct clk_regmap c3_sd_emmc_a_div = { - .data = &(struct clk_regmap_div_data) { - .offset = SD_EMMC_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "sd_emmc_a_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_sd_emmc_a_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL, 25, 0x7, c3_sd_emmc_parents); +static C3_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL, 16, 7); +static C3_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL, 23); -static struct clk_regmap c3_sd_emmc_a = { - .data = &(struct clk_regmap_gate_data) { - .offset = SD_EMMC_CLK_CTRL, - .bit_idx = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "sd_emmc_a", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_sd_emmc_a_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_sd_emmc_b_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = SD_EMMC_CLK_CTRL, - .mask = 0x7, - .shift = 25, - }, - .hw.init = &(struct clk_init_data) { - .name = "sd_emmc_b_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_sd_emmc_parents, - .num_parents = ARRAY_SIZE(c3_sd_emmc_parents), - }, -}; - -static struct clk_regmap c3_sd_emmc_b_div = { - .data = &(struct clk_regmap_div_data) { - .offset = SD_EMMC_CLK_CTRL, - .shift = 16, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "sd_emmc_b_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_sd_emmc_b_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_sd_emmc_b = { - .data = &(struct clk_regmap_gate_data) { - .offset = SD_EMMC_CLK_CTRL, - .bit_idx = 23, - }, - .hw.init = &(struct clk_init_data) { - .name = "sd_emmc_b", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_sd_emmc_b_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_sd_emmc_c_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = NAND_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "sd_emmc_c_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_sd_emmc_parents, - .num_parents = ARRAY_SIZE(c3_sd_emmc_parents), - }, -}; - -static struct clk_regmap c3_sd_emmc_c_div = { - .data = &(struct clk_regmap_div_data) { - .offset = NAND_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "sd_emmc_c_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_sd_emmc_c_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_sd_emmc_c = { - .data = &(struct clk_regmap_gate_data) { - .offset = NAND_CLK_CTRL, - .bit_idx = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "sd_emmc_c", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_sd_emmc_c_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(sd_emmc_c, NAND_CLK_CTRL, 9, 0x7, c3_sd_emmc_parents); +static C3_COMP_DIV(sd_emmc_c, NAND_CLK_CTRL, 0, 7); +static C3_COMP_GATE(sd_emmc_c, NAND_CLK_CTRL, 7); static struct clk_regmap c3_ts_div = { .data = &(struct clk_regmap_div_data) { @@ -996,52 +695,9 @@ static const struct clk_parent_data c3_mipi_dsi_meas_parents[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap c3_mipi_dsi_meas_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = VDIN_MEAS_CLK_CTRL, - .mask = 0x7, - .shift = 21, - }, - .hw.init = &(struct clk_init_data) { - .name = "mipi_dsi_meas_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_mipi_dsi_meas_parents, - .num_parents = ARRAY_SIZE(c3_mipi_dsi_meas_parents), - }, -}; - -static struct clk_regmap c3_mipi_dsi_meas_div = { - .data = &(struct clk_regmap_div_data) { - .offset = VDIN_MEAS_CLK_CTRL, - .shift = 12, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "mipi_dsi_meas_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_mipi_dsi_meas_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_mipi_dsi_meas = { - .data = &(struct clk_regmap_gate_data) { - .offset = VDIN_MEAS_CLK_CTRL, - .bit_idx = 20, - }, - .hw.init = &(struct clk_init_data) { - .name = "mipi_dsi_meas", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_mipi_dsi_meas_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(mipi_dsi_meas, VDIN_MEAS_CLK_CTRL, 21, 0x7, c3_mipi_dsi_meas_parents); +static C3_COMP_DIV(mipi_dsi_meas, VDIN_MEAS_CLK_CTRL, 12, 7); +static C3_COMP_GATE(mipi_dsi_meas, VDIN_MEAS_CLK_CTRL, 20); static const struct clk_parent_data c3_dsi_phy_parents[] = { { .fw_name = "gp1" }, @@ -1054,52 +710,9 @@ static const struct clk_parent_data c3_dsi_phy_parents[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap c3_dsi_phy_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = MIPIDSI_PHY_CLK_CTRL, - .mask = 0x7, - .shift = 12, - }, - .hw.init = &(struct clk_init_data) { - .name = "dsi_phy_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_dsi_phy_parents, - .num_parents = ARRAY_SIZE(c3_dsi_phy_parents), - }, -}; - -static struct clk_regmap c3_dsi_phy_div = { - .data = &(struct clk_regmap_div_data) { - .offset = MIPIDSI_PHY_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "dsi_phy_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_dsi_phy_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_dsi_phy = { - .data = &(struct clk_regmap_gate_data) { - .offset = MIPIDSI_PHY_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "dsi_phy", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_dsi_phy_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(dsi_phy, MIPIDSI_PHY_CLK_CTRL, 12, 0x7, c3_dsi_phy_parents); +static C3_COMP_DIV(dsi_phy, MIPIDSI_PHY_CLK_CTRL, 0, 7); +static C3_COMP_GATE(dsi_phy, MIPIDSI_PHY_CLK_CTRL, 8); static const struct clk_parent_data c3_vout_mclk_parents[] = { { .fw_name = "fdiv2p5" }, @@ -1112,52 +725,9 @@ static const struct clk_parent_data c3_vout_mclk_parents[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap c3_vout_mclk_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = VOUTENC_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "vout_mclk_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_vout_mclk_parents, - .num_parents = ARRAY_SIZE(c3_vout_mclk_parents), - }, -}; - -static struct clk_regmap c3_vout_mclk_div = { - .data = &(struct clk_regmap_div_data) { - .offset = VOUTENC_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "vout_mclk_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_vout_mclk_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_vout_mclk = { - .data = &(struct clk_regmap_gate_data) { - .offset = VOUTENC_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "vout_mclk", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_vout_mclk_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(vout_mclk, VOUTENC_CLK_CTRL, 9, 0x7, c3_vout_mclk_parents); +static C3_COMP_DIV(vout_mclk, VOUTENC_CLK_CTRL, 0, 7); +static C3_COMP_GATE(vout_mclk, VOUTENC_CLK_CTRL, 8); static const struct clk_parent_data c3_vout_enc_parents[] = { { .fw_name = "gp1" }, @@ -1170,52 +740,9 @@ static const struct clk_parent_data c3_vout_enc_parents[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap c3_vout_enc_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = VOUTENC_CLK_CTRL, - .mask = 0x7, - .shift = 25, - }, - .hw.init = &(struct clk_init_data) { - .name = "vout_enc_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_vout_enc_parents, - .num_parents = ARRAY_SIZE(c3_vout_enc_parents), - }, -}; - -static struct clk_regmap c3_vout_enc_div = { - .data = &(struct clk_regmap_div_data) { - .offset = VOUTENC_CLK_CTRL, - .shift = 16, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "vout_enc_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_vout_enc_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_vout_enc = { - .data = &(struct clk_regmap_gate_data) { - .offset = VOUTENC_CLK_CTRL, - .bit_idx = 24, - }, - .hw.init = &(struct clk_init_data) { - .name = "vout_enc", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_vout_enc_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(vout_enc, VOUTENC_CLK_CTRL, 25, 0x7, c3_vout_enc_parents); +static C3_COMP_DIV(vout_enc, VOUTENC_CLK_CTRL, 16, 7); +static C3_COMP_GATE(vout_enc, VOUTENC_CLK_CTRL, 24); static const struct clk_parent_data c3_hcodec_pre_parents[] = { { .fw_name = "fdiv2p5" }, @@ -1228,99 +755,13 @@ static const struct clk_parent_data c3_hcodec_pre_parents[] = { { .fw_name = "oscin" } }; -static struct clk_regmap c3_hcodec_0_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = VDEC_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "hcodec_0_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_hcodec_pre_parents, - .num_parents = ARRAY_SIZE(c3_hcodec_pre_parents), - }, -}; +static C3_COMP_SEL(hcodec_0, VDEC_CLK_CTRL, 9, 0x7, c3_hcodec_pre_parents); +static C3_COMP_DIV(hcodec_0, VDEC_CLK_CTRL, 0, 7); +static C3_COMP_GATE(hcodec_0, VDEC_CLK_CTRL, 8); -static struct clk_regmap c3_hcodec_0_div = { - .data = &(struct clk_regmap_div_data) { - .offset = VDEC_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "hcodec_0_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_hcodec_0_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_hcodec_0 = { - .data = &(struct clk_regmap_gate_data) { - .offset = VDEC_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "hcodec_0", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_hcodec_0_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_hcodec_1_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = VDEC3_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "hcodec_1_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_hcodec_pre_parents, - .num_parents = ARRAY_SIZE(c3_hcodec_pre_parents), - }, -}; - -static struct clk_regmap c3_hcodec_1_div = { - .data = &(struct clk_regmap_div_data) { - .offset = VDEC3_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "hcodec_1_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_hcodec_1_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_hcodec_1 = { - .data = &(struct clk_regmap_gate_data) { - .offset = VDEC3_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "hcodec_1", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_hcodec_1_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(hcodec_1, VDEC3_CLK_CTRL, 9, 0x7, c3_hcodec_pre_parents); +static C3_COMP_DIV(hcodec_1, VDEC3_CLK_CTRL, 0, 7); +static C3_COMP_GATE(hcodec_1, VDEC3_CLK_CTRL, 8); static const struct clk_parent_data c3_hcodec_parents[] = { { .hw = &c3_hcodec_0.hw }, @@ -1353,99 +794,13 @@ static const struct clk_parent_data c3_vc9000e_parents[] = { { .fw_name = "gp0" } }; -static struct clk_regmap c3_vc9000e_aclk_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = VC9000E_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "vc9000e_aclk_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_vc9000e_parents, - .num_parents = ARRAY_SIZE(c3_vc9000e_parents), - }, -}; +static C3_COMP_SEL(vc9000e_aclk, VC9000E_CLK_CTRL, 9, 0x7, c3_vc9000e_parents); +static C3_COMP_DIV(vc9000e_aclk, VC9000E_CLK_CTRL, 0, 7); +static C3_COMP_GATE(vc9000e_aclk, VC9000E_CLK_CTRL, 8); -static struct clk_regmap c3_vc9000e_aclk_div = { - .data = &(struct clk_regmap_div_data) { - .offset = VC9000E_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "vc9000e_aclk_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_vc9000e_aclk_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_vc9000e_aclk = { - .data = &(struct clk_regmap_gate_data) { - .offset = VC9000E_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "vc9000e_aclk", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_vc9000e_aclk_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_vc9000e_core_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = VC9000E_CLK_CTRL, - .mask = 0x7, - .shift = 25, - }, - .hw.init = &(struct clk_init_data) { - .name = "vc9000e_core_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_vc9000e_parents, - .num_parents = ARRAY_SIZE(c3_vc9000e_parents), - }, -}; - -static struct clk_regmap c3_vc9000e_core_div = { - .data = &(struct clk_regmap_div_data) { - .offset = VC9000E_CLK_CTRL, - .shift = 16, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "vc9000e_core_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_vc9000e_core_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_vc9000e_core = { - .data = &(struct clk_regmap_gate_data) { - .offset = VC9000E_CLK_CTRL, - .bit_idx = 24, - }, - .hw.init = &(struct clk_init_data) { - .name = "vc9000e_core", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_vc9000e_core_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(vc9000e_core, VC9000E_CLK_CTRL, 25, 0x7, c3_vc9000e_parents); +static C3_COMP_DIV(vc9000e_core, VC9000E_CLK_CTRL, 16, 7); +static C3_COMP_GATE(vc9000e_core, VC9000E_CLK_CTRL, 24); static const struct clk_parent_data c3_csi_phy_parents[] = { { .fw_name = "fdiv2p5" }, @@ -1458,52 +813,9 @@ static const struct clk_parent_data c3_csi_phy_parents[] = { { .fw_name = "oscin" } }; -static struct clk_regmap c3_csi_phy0_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = ISP0_CLK_CTRL, - .mask = 0x7, - .shift = 25, - }, - .hw.init = &(struct clk_init_data) { - .name = "csi_phy0_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_csi_phy_parents, - .num_parents = ARRAY_SIZE(c3_csi_phy_parents), - }, -}; - -static struct clk_regmap c3_csi_phy0_div = { - .data = &(struct clk_regmap_div_data) { - .offset = ISP0_CLK_CTRL, - .shift = 16, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "csi_phy0_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_csi_phy0_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_csi_phy0 = { - .data = &(struct clk_regmap_gate_data) { - .offset = ISP0_CLK_CTRL, - .bit_idx = 24, - }, - .hw.init = &(struct clk_init_data) { - .name = "csi_phy0", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_csi_phy0_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(csi_phy0, ISP0_CLK_CTRL, 25, 0x7, c3_csi_phy_parents); +static C3_COMP_DIV(csi_phy0, ISP0_CLK_CTRL, 16, 7); +static C3_COMP_GATE(csi_phy0, ISP0_CLK_CTRL, 24); static const struct clk_parent_data c3_dewarpa_parents[] = { { .fw_name = "fdiv2p5" }, @@ -1516,52 +828,9 @@ static const struct clk_parent_data c3_dewarpa_parents[] = { { .fw_name = "fdiv7" } }; -static struct clk_regmap c3_dewarpa_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = DEWARPA_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "dewarpa_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_dewarpa_parents, - .num_parents = ARRAY_SIZE(c3_dewarpa_parents), - }, -}; - -static struct clk_regmap c3_dewarpa_div = { - .data = &(struct clk_regmap_div_data) { - .offset = DEWARPA_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "dewarpa_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_dewarpa_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_dewarpa = { - .data = &(struct clk_regmap_gate_data) { - .offset = DEWARPA_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "dewarpa", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_dewarpa_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(dewarpa, DEWARPA_CLK_CTRL, 9, 0x7, c3_dewarpa_parents); +static C3_COMP_DIV(dewarpa, DEWARPA_CLK_CTRL, 0, 7); +static C3_COMP_GATE(dewarpa, DEWARPA_CLK_CTRL, 8); static const struct clk_parent_data c3_isp_parents[] = { { .fw_name = "fdiv2p5" }, @@ -1574,52 +843,9 @@ static const struct clk_parent_data c3_isp_parents[] = { { .fw_name = "oscin" } }; -static struct clk_regmap c3_isp0_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = ISP0_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "isp0_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_isp_parents, - .num_parents = ARRAY_SIZE(c3_isp_parents), - }, -}; - -static struct clk_regmap c3_isp0_div = { - .data = &(struct clk_regmap_div_data) { - .offset = ISP0_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "isp0_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_isp0_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_isp0 = { - .data = &(struct clk_regmap_gate_data) { - .offset = ISP0_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "isp0", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_isp0_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(isp0, ISP0_CLK_CTRL, 9, 0x7, c3_isp_parents); +static C3_COMP_DIV(isp0, ISP0_CLK_CTRL, 0, 7); +static C3_COMP_GATE(isp0, ISP0_CLK_CTRL, 8); static const struct clk_parent_data c3_nna_core_parents[] = { { .fw_name = "oscin" }, @@ -1632,52 +858,9 @@ static const struct clk_parent_data c3_nna_core_parents[] = { { .fw_name = "hifi" } }; -static struct clk_regmap c3_nna_core_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = NNA_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "nna_core_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_nna_core_parents, - .num_parents = ARRAY_SIZE(c3_nna_core_parents), - }, -}; - -static struct clk_regmap c3_nna_core_div = { - .data = &(struct clk_regmap_div_data) { - .offset = NNA_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "nna_core_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_nna_core_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_nna_core = { - .data = &(struct clk_regmap_gate_data) { - .offset = NNA_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "nna_core", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_nna_core_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(nna_core, NNA_CLK_CTRL, 9, 0x7, c3_nna_core_parents); +static C3_COMP_DIV(nna_core, NNA_CLK_CTRL, 0, 7); +static C3_COMP_GATE(nna_core, NNA_CLK_CTRL, 8); static const struct clk_parent_data c3_ge2d_parents[] = { { .fw_name = "oscin" }, @@ -1690,52 +873,9 @@ static const struct clk_parent_data c3_ge2d_parents[] = { { .hw = &c3_rtc_clk.hw } }; -static struct clk_regmap c3_ge2d_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = GE2D_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "ge2d_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_ge2d_parents, - .num_parents = ARRAY_SIZE(c3_ge2d_parents), - }, -}; - -static struct clk_regmap c3_ge2d_div = { - .data = &(struct clk_regmap_div_data) { - .offset = GE2D_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "ge2d_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_ge2d_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_ge2d = { - .data = &(struct clk_regmap_gate_data) { - .offset = GE2D_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "ge2d", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_ge2d_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(ge2d, GE2D_CLK_CTRL, 9, 0x7, c3_ge2d_parents); +static C3_COMP_DIV(ge2d, GE2D_CLK_CTRL, 0, 7); +static C3_COMP_GATE(ge2d, GE2D_CLK_CTRL, 8); static const struct clk_parent_data c3_vapb_parents[] = { { .fw_name = "fdiv2p5" }, @@ -1748,52 +888,9 @@ static const struct clk_parent_data c3_vapb_parents[] = { { .fw_name = "oscin" }, }; -static struct clk_regmap c3_vapb_sel = { - .data = &(struct clk_regmap_mux_data) { - .offset = VAPB_CLK_CTRL, - .mask = 0x7, - .shift = 9, - }, - .hw.init = &(struct clk_init_data) { - .name = "vapb_sel", - .ops = &clk_regmap_mux_ops, - .parent_data = c3_vapb_parents, - .num_parents = ARRAY_SIZE(c3_vapb_parents), - }, -}; - -static struct clk_regmap c3_vapb_div = { - .data = &(struct clk_regmap_div_data) { - .offset = VAPB_CLK_CTRL, - .shift = 0, - .width = 7, - }, - .hw.init = &(struct clk_init_data) { - .name = "vapb_div", - .ops = &clk_regmap_divider_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_vapb_sel.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_regmap c3_vapb = { - .data = &(struct clk_regmap_gate_data) { - .offset = VAPB_CLK_CTRL, - .bit_idx = 8, - }, - .hw.init = &(struct clk_init_data) { - .name = "vapb", - .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { - &c3_vapb_div.hw - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - }, -}; +static C3_COMP_SEL(vapb, VAPB_CLK_CTRL, 9, 0x7, c3_vapb_parents); +static C3_COMP_DIV(vapb, VAPB_CLK_CTRL, 0, 7); +static C3_COMP_GATE(vapb, VAPB_CLK_CTRL, 8); static struct clk_hw *c3_peripherals_hw_clks[] = { [CLKID_RTC_XTAL_CLKIN] = &c3_rtc_xtal_clkin.hw, From 37bf0f4e39de9b53bc6f8d3702b021e2c6b5bae3 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Thu, 4 Sep 2025 14:52:23 +0800 Subject: [PATCH 0834/2711] PCI: qcom: Add equalization settings for 8.0 GT/s and 32.0 GT/s Add lane equalization setting for 8.0 GT/s and 32.0 GT/s to enhance link stability and avoid AER Correctable Errors reported on some platforms (eg. SA8775P). 8.0 GT/s, 16.0 GT/s and 32.0 GT/s require the same equalization setting. This setting is programmed into a group of shadow registers, which can be switched to configure equalization for different speeds by writing 00b, 01b and 10b to `RATE_SHADOW_SEL`. Hence, program equalization registers in a loop using link speed as index, so that equalization setting can be programmed for 8.0 GT/s, 16.0 GT/s and 32.0 GT/s. Fixes: 489f14be0e0a ("arm64: dts: qcom: sa8775p: Add pcie0 and pcie1 nodes") Co-developed-by: Qiang Yu Signed-off-by: Qiang Yu Signed-off-by: Ziyue Zhang [mani: wrapped the warning to fit 100 columns, used post-increment for loop] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250904065225.1762793-2-ziyue.zhang@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-designware.h | 1 - drivers/pci/controller/dwc/pcie-qcom-common.c | 58 +++++++++++-------- drivers/pci/controller/dwc/pcie-qcom-common.h | 2 +- drivers/pci/controller/dwc/pcie-qcom-ep.c | 6 +- drivers/pci/controller/dwc/pcie-qcom.c | 6 +- 5 files changed, 41 insertions(+), 32 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 00f52d472dcd..cc71a2d90cd4 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -123,7 +123,6 @@ #define GEN3_RELATED_OFF_GEN3_EQ_DISABLE BIT(16) #define GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT 24 #define GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK GENMASK(25, 24) -#define GEN3_RELATED_OFF_RATE_SHADOW_SEL_16_0GT 0x1 #define GEN3_EQ_CONTROL_OFF 0x8A8 #define GEN3_EQ_CONTROL_OFF_FB_MODE GENMASK(3, 0) diff --git a/drivers/pci/controller/dwc/pcie-qcom-common.c b/drivers/pci/controller/dwc/pcie-qcom-common.c index 3aad19b56da8..0c6f4514f922 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-common.c +++ b/drivers/pci/controller/dwc/pcie-qcom-common.c @@ -8,9 +8,11 @@ #include "pcie-designware.h" #include "pcie-qcom-common.h" -void qcom_pcie_common_set_16gt_equalization(struct dw_pcie *pci) +void qcom_pcie_common_set_equalization(struct dw_pcie *pci) { + struct device *dev = pci->dev; u32 reg; + u16 speed; /* * GEN3_RELATED_OFF register is repurposed to apply equalization @@ -19,32 +21,40 @@ void qcom_pcie_common_set_16gt_equalization(struct dw_pcie *pci) * determines the data rate for which these equalization settings are * applied. */ - reg = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); - reg &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; - reg &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK; - reg |= FIELD_PREP(GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK, - GEN3_RELATED_OFF_RATE_SHADOW_SEL_16_0GT); - dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, reg); - reg = dw_pcie_readl_dbi(pci, GEN3_EQ_FB_MODE_DIR_CHANGE_OFF); - reg &= ~(GEN3_EQ_FMDC_T_MIN_PHASE23 | - GEN3_EQ_FMDC_N_EVALS | - GEN3_EQ_FMDC_MAX_PRE_CUSROR_DELTA | - GEN3_EQ_FMDC_MAX_POST_CUSROR_DELTA); - reg |= FIELD_PREP(GEN3_EQ_FMDC_T_MIN_PHASE23, 0x1) | - FIELD_PREP(GEN3_EQ_FMDC_N_EVALS, 0xd) | - FIELD_PREP(GEN3_EQ_FMDC_MAX_PRE_CUSROR_DELTA, 0x5) | - FIELD_PREP(GEN3_EQ_FMDC_MAX_POST_CUSROR_DELTA, 0x5); - dw_pcie_writel_dbi(pci, GEN3_EQ_FB_MODE_DIR_CHANGE_OFF, reg); + for (speed = PCIE_SPEED_8_0GT; speed <= pcie_link_speed[pci->max_link_speed]; speed++) { + if (speed > PCIE_SPEED_32_0GT) { + dev_warn(dev, "Skipped equalization settings for unsupported data rate\n"); + break; + } - reg = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF); - reg &= ~(GEN3_EQ_CONTROL_OFF_FB_MODE | - GEN3_EQ_CONTROL_OFF_PHASE23_EXIT_MODE | - GEN3_EQ_CONTROL_OFF_FOM_INC_INITIAL_EVAL | - GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC); - dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, reg); + reg = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); + reg &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; + reg &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK; + reg |= FIELD_PREP(GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK, + speed - PCIE_SPEED_8_0GT); + dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, reg); + + reg = dw_pcie_readl_dbi(pci, GEN3_EQ_FB_MODE_DIR_CHANGE_OFF); + reg &= ~(GEN3_EQ_FMDC_T_MIN_PHASE23 | + GEN3_EQ_FMDC_N_EVALS | + GEN3_EQ_FMDC_MAX_PRE_CUSROR_DELTA | + GEN3_EQ_FMDC_MAX_POST_CUSROR_DELTA); + reg |= FIELD_PREP(GEN3_EQ_FMDC_T_MIN_PHASE23, 0x1) | + FIELD_PREP(GEN3_EQ_FMDC_N_EVALS, 0xd) | + FIELD_PREP(GEN3_EQ_FMDC_MAX_PRE_CUSROR_DELTA, 0x5) | + FIELD_PREP(GEN3_EQ_FMDC_MAX_POST_CUSROR_DELTA, 0x5); + dw_pcie_writel_dbi(pci, GEN3_EQ_FB_MODE_DIR_CHANGE_OFF, reg); + + reg = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF); + reg &= ~(GEN3_EQ_CONTROL_OFF_FB_MODE | + GEN3_EQ_CONTROL_OFF_PHASE23_EXIT_MODE | + GEN3_EQ_CONTROL_OFF_FOM_INC_INITIAL_EVAL | + GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC); + dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, reg); + } } -EXPORT_SYMBOL_GPL(qcom_pcie_common_set_16gt_equalization); +EXPORT_SYMBOL_GPL(qcom_pcie_common_set_equalization); void qcom_pcie_common_set_16gt_lane_margining(struct dw_pcie *pci) { diff --git a/drivers/pci/controller/dwc/pcie-qcom-common.h b/drivers/pci/controller/dwc/pcie-qcom-common.h index 7d88d29e4766..7f5ca2fd9a72 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-common.h +++ b/drivers/pci/controller/dwc/pcie-qcom-common.h @@ -8,7 +8,7 @@ struct dw_pcie; -void qcom_pcie_common_set_16gt_equalization(struct dw_pcie *pci); +void qcom_pcie_common_set_equalization(struct dw_pcie *pci); void qcom_pcie_common_set_16gt_lane_margining(struct dw_pcie *pci); #endif diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index bf7c6ac0f3e3..aaf060bf39d4 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -511,10 +511,10 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) goto err_disable_resources; } - if (pcie_link_speed[pci->max_link_speed] == PCIE_SPEED_16_0GT) { - qcom_pcie_common_set_16gt_equalization(pci); + qcom_pcie_common_set_equalization(pci); + + if (pcie_link_speed[pci->max_link_speed] == PCIE_SPEED_16_0GT) qcom_pcie_common_set_16gt_lane_margining(pci); - } /* * The physical address of the MMIO region which is exposed as the BAR diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index fbed7130d747..a93740ae602f 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -322,10 +322,10 @@ static int qcom_pcie_start_link(struct dw_pcie *pci) { struct qcom_pcie *pcie = to_qcom_pcie(pci); - if (pcie_link_speed[pci->max_link_speed] == PCIE_SPEED_16_0GT) { - qcom_pcie_common_set_16gt_equalization(pci); + qcom_pcie_common_set_equalization(pci); + + if (pcie_link_speed[pci->max_link_speed] == PCIE_SPEED_16_0GT) qcom_pcie_common_set_16gt_lane_margining(pci); - } /* Enable Link Training state machine */ if (pcie->cfg->ops->ltssm_enable) From ea5fbbc15906abdef174c88cecfec4b2a0c748b9 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Thu, 4 Sep 2025 14:52:24 +0800 Subject: [PATCH 0835/2711] PCI: qcom: Fix macro typo for CURSOR Correct a typo in the macro names GEN3_EQ_FMDC_MAX_PRE_CURSOR_DELTA and GEN3_EQ_FMDC_MAX_POST_CURSOR_DELTA. Signed-off-by: Ziyue Zhang [mani: reworded description] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20250904065225.1762793-3-ziyue.zhang@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-designware.h | 4 ++-- drivers/pci/controller/dwc/pcie-qcom-common.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index cc71a2d90cd4..2418214730e4 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -133,8 +133,8 @@ #define GEN3_EQ_FB_MODE_DIR_CHANGE_OFF 0x8AC #define GEN3_EQ_FMDC_T_MIN_PHASE23 GENMASK(4, 0) #define GEN3_EQ_FMDC_N_EVALS GENMASK(9, 5) -#define GEN3_EQ_FMDC_MAX_PRE_CUSROR_DELTA GENMASK(13, 10) -#define GEN3_EQ_FMDC_MAX_POST_CUSROR_DELTA GENMASK(17, 14) +#define GEN3_EQ_FMDC_MAX_PRE_CURSOR_DELTA GENMASK(13, 10) +#define GEN3_EQ_FMDC_MAX_POST_CURSOR_DELTA GENMASK(17, 14) #define PCIE_PORT_MULTI_LANE_CTRL 0x8C0 #define PORT_MLTI_UPCFG_SUPPORT BIT(7) diff --git a/drivers/pci/controller/dwc/pcie-qcom-common.c b/drivers/pci/controller/dwc/pcie-qcom-common.c index 0c6f4514f922..01c5387e53bf 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-common.c +++ b/drivers/pci/controller/dwc/pcie-qcom-common.c @@ -38,12 +38,12 @@ void qcom_pcie_common_set_equalization(struct dw_pcie *pci) reg = dw_pcie_readl_dbi(pci, GEN3_EQ_FB_MODE_DIR_CHANGE_OFF); reg &= ~(GEN3_EQ_FMDC_T_MIN_PHASE23 | GEN3_EQ_FMDC_N_EVALS | - GEN3_EQ_FMDC_MAX_PRE_CUSROR_DELTA | - GEN3_EQ_FMDC_MAX_POST_CUSROR_DELTA); + GEN3_EQ_FMDC_MAX_PRE_CURSOR_DELTA | + GEN3_EQ_FMDC_MAX_POST_CURSOR_DELTA); reg |= FIELD_PREP(GEN3_EQ_FMDC_T_MIN_PHASE23, 0x1) | FIELD_PREP(GEN3_EQ_FMDC_N_EVALS, 0xd) | - FIELD_PREP(GEN3_EQ_FMDC_MAX_PRE_CUSROR_DELTA, 0x5) | - FIELD_PREP(GEN3_EQ_FMDC_MAX_POST_CUSROR_DELTA, 0x5); + FIELD_PREP(GEN3_EQ_FMDC_MAX_PRE_CURSOR_DELTA, 0x5) | + FIELD_PREP(GEN3_EQ_FMDC_MAX_POST_CURSOR_DELTA, 0x5); dw_pcie_writel_dbi(pci, GEN3_EQ_FB_MODE_DIR_CHANGE_OFF, reg); reg = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF); From c221cbf8dc547eb8489152ac62ef103fede99545 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 20 Aug 2025 10:23:28 +0800 Subject: [PATCH 0836/2711] PCI: imx6: Enable the Vaux supply if available When the 3.3Vaux supply is present, fetch it at the probe time and keep it enabled for the entire PCIe controller lifecycle so that the link can enter L2 state and the devices can signal wakeup using either Beacon or WAKE# mechanisms. Signed-off-by: Richard Zhu [mani: reworded the subject, description and error message] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Link: https://patch.msgid.link/20250820022328.2143374-1-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 80e48746bbaf..db51e382a7cf 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1745,6 +1745,10 @@ static int imx_pcie_probe(struct platform_device *pdev) pci->max_link_speed = 1; of_property_read_u32(node, "fsl,max-link-speed", &pci->max_link_speed); + ret = devm_regulator_get_enable_optional(&pdev->dev, "vpcie3v3aux"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to enable Vaux supply\n"); + imx_pcie->vpcie = devm_regulator_get_optional(&pdev->dev, "vpcie"); if (IS_ERR(imx_pcie->vpcie)) { if (PTR_ERR(imx_pcie->vpcie) != -ENODEV) From 038c7dc66e2744e5df57163b8f957745ae10d23e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 3 Sep 2025 20:46:40 -0700 Subject: [PATCH 0837/2711] compiler_types.h: Move __nocfi out of compiler-specific header Prepare for GCC KCFI support and move the __nocfi attribute from compiler-clang.h to compiler_types.h. This was already gated by CONFIG_CFI_CLANG, so this remains safe for non-KCFI GCC builds. Signed-off-by: Kees Cook Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Nathan Chancellor Link: https://lore.kernel.org/r/20250904034656.3670313-1-kees@kernel.org --- include/linux/compiler-clang.h | 5 ----- include/linux/compiler_types.h | 4 +++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index fa4ffe037bc7..7a4568e421dc 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -96,11 +96,6 @@ # define __noscs __attribute__((__no_sanitize__("shadow-call-stack"))) #endif -#if __has_feature(kcfi) -/* Disable CFI checking inside a function. */ -#define __nocfi __attribute__((__no_sanitize__("kcfi"))) -#endif - /* * Turn individual warnings and errors on and off locally, depending * on version. diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 16755431fc11..a910f9fa5341 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -432,7 +432,9 @@ struct ftrace_likely_data { # define __noscs #endif -#ifndef __nocfi +#if defined(CONFIG_CFI_CLANG) +# define __nocfi __attribute__((__no_sanitize__("kcfi"))) +#else # define __nocfi #endif From 628a15e0536abb7658cd243553312d3f65c0aff2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 3 Sep 2025 20:46:41 -0700 Subject: [PATCH 0838/2711] x86/traps: Clarify KCFI instruction layout Just a nit-picky change to the KCFI indirect call check instruction documentation. The addl offset isn't always -4 (it depends on patchable function entry configuration). Signed-off-by: Kees Cook Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20250904034656.3670313-2-kees@kernel.org --- arch/x86/kernel/cfi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c index 77086cf565ec..638eb5c933e0 100644 --- a/arch/x86/kernel/cfi.c +++ b/arch/x86/kernel/cfi.c @@ -27,7 +27,7 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, * for indirect call checks: * *   movl -, %r10d ; 6 bytes - * addl -4(%reg), %r10d ; 4 bytes + * addl -(%reg), %r10d; 4 bytes * je .Ltmp1 ; 2 bytes * ud2 ; <- regs->ip * .Ltmp1: From 24452d9ef17502965021ce5df30f4e184245a5ac Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 3 Sep 2025 20:46:42 -0700 Subject: [PATCH 0839/2711] x86/cfi: Document the "cfi=" bootparam options The kernel-parameters.txt didn't have a section for the cfi= options. Add it. Signed-off-by: Kees Cook Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Nathan Chancellor Link: https://lore.kernel.org/r/20250904034656.3670313-3-kees@kernel.org --- Documentation/admin-guide/kernel-parameters.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 747a55abf494..8bbffbb334ab 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -608,6 +608,23 @@ ccw_timeout_log [S390] See Documentation/arch/s390/common_io.rst for details. + cfi= [X86-64] Set Control Flow Integrity checking features + when CONFIG_FINEIBT is enabled. + Format: feature[,feature...] + Default: auto + + auto: Use FineIBT if IBT available, otherwise kCFI. + Under FineIBT, enable "paranoid" mode when + FRED is not available. + off: Turn off CFI checking. + kcfi: Use kCFI (disable FineIBT). + fineibt: Use FineIBT (even if IBT not available). + norand: Do not re-randomize CFI hashes. + paranoid: Add caller hash checking under FineIBT. + bhi: Enable register poisoning to stop speculation + across FineIBT. (Disabled by default.) + warn: Do not enforce CFI checking: warn only. + cgroup_disable= [KNL] Disable a particular controller or optional feature Format: {name of the controller(s) or feature(s) to disable} The effects of cgroup_disable=foo are: From 9f303a35d1df27cdc7b895b077985b0e1c4473c2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 3 Sep 2025 20:46:43 -0700 Subject: [PATCH 0840/2711] x86/cfi: Standardize on common "CFI:" prefix for CFI reports Use a regular "CFI:" prefix for CFI reports during alternatives setup, including reporting when nothing has happened (i.e. CONFIG_FINEIBT=n). Signed-off-by: Kees Cook Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Nathan Chancellor Link: https://lore.kernel.org/r/20250904034656.3670313-4-kees@kernel.org --- arch/x86/kernel/alternative.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 7bde68247b5f..d8f4ac95b4df 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -1266,26 +1266,26 @@ static __init int cfi_parse_cmdline(char *str) } else if (!strcmp(str, "norand")) { cfi_rand = false; } else if (!strcmp(str, "warn")) { - pr_alert("CFI mismatch non-fatal!\n"); + pr_alert("CFI: mismatch non-fatal!\n"); cfi_warn = true; } else if (!strcmp(str, "paranoid")) { if (cfi_mode == CFI_FINEIBT) { cfi_paranoid = true; } else { - pr_err("Ignoring paranoid; depends on fineibt.\n"); + pr_err("CFI: ignoring paranoid; depends on fineibt.\n"); } } else if (!strcmp(str, "bhi")) { #ifdef CONFIG_FINEIBT_BHI if (cfi_mode == CFI_FINEIBT) { cfi_bhi = true; } else { - pr_err("Ignoring bhi; depends on fineibt.\n"); + pr_err("CFI: ignoring bhi; depends on fineibt.\n"); } #else - pr_err("Ignoring bhi; depends on FINEIBT_BHI=y.\n"); + pr_err("CFI: ignoring bhi; depends on FINEIBT_BHI=y.\n"); #endif } else { - pr_err("Ignoring unknown cfi option (%s).", str); + pr_err("CFI: Ignoring unknown option (%s).", str); } str = next; @@ -1757,7 +1757,7 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, switch (cfi_mode) { case CFI_OFF: if (builtin) - pr_info("Disabling CFI\n"); + pr_info("CFI: disabled\n"); return; case CFI_KCFI: @@ -1766,7 +1766,8 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, goto err; if (builtin) - pr_info("Using kCFI\n"); + pr_info("CFI: Using %sretpoline kCFI\n", + cfi_rand ? "rehashed " : ""); return; case CFI_FINEIBT: @@ -2005,6 +2006,8 @@ bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type) static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, s32 *start_cfi, s32 *end_cfi, bool builtin) { + if (IS_ENABLED(CONFIG_CFI) && builtin) + pr_info("CFI: Using standard kCFI\n"); } #ifdef CONFIG_X86_KERNEL_IBT From 026211c40b055485b4c65c10d644a92864623225 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 3 Sep 2025 20:46:44 -0700 Subject: [PATCH 0841/2711] x86/cfi: Add "debug" option to "cfi=" bootparam Add "debug" option for "cfi=" bootparam to get details on early CFI initialization steps so future Kees can find breakage easier. Signed-off-by: Kees Cook Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20250904034656.3670313-5-kees@kernel.org --- Documentation/admin-guide/kernel-parameters.txt | 1 + arch/x86/kernel/alternative.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 8bbffbb334ab..c8337d0e6ba3 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -624,6 +624,7 @@ bhi: Enable register poisoning to stop speculation across FineIBT. (Disabled by default.) warn: Do not enforce CFI checking: warn only. + debug: Report CFI initialization details. cgroup_disable= [KNL] Disable a particular controller or optional feature Format: {name of the controller(s) or feature(s) to disable} diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index d8f4ac95b4df..7d4a992dadc3 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -1177,6 +1177,7 @@ void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { } #endif enum cfi_mode cfi_mode __ro_after_init = __CFI_DEFAULT; +static bool cfi_debug __ro_after_init; #ifdef CONFIG_FINEIBT_BHI bool cfi_bhi __ro_after_init = false; @@ -1259,6 +1260,8 @@ static __init int cfi_parse_cmdline(char *str) } else if (!strcmp(str, "off")) { cfi_mode = CFI_OFF; cfi_rand = false; + } else if (!strcmp(str, "debug")) { + cfi_debug = true; } else if (!strcmp(str, "kcfi")) { cfi_mode = CFI_KCFI; } else if (!strcmp(str, "fineibt")) { @@ -1707,6 +1710,8 @@ static int cfi_rewrite_callers(s32 *start, s32 *end) return 0; } +#define pr_cfi_debug(X...) if (cfi_debug) pr_info(X) + static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, s32 *start_cfi, s32 *end_cfi, bool builtin) { @@ -1734,6 +1739,7 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, * rewrite them. This disables all CFI. If this succeeds but any of the * later stages fails, we're without CFI. */ + pr_cfi_debug("CFI: disabling all indirect call checking\n"); ret = cfi_disable_callers(start_retpoline, end_retpoline); if (ret) goto err; @@ -1744,14 +1750,19 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, cfi_bpf_hash = cfi_rehash(cfi_bpf_hash); cfi_bpf_subprog_hash = cfi_rehash(cfi_bpf_subprog_hash); } + pr_cfi_debug("CFI: cfi_seed: 0x%08x\n", cfi_seed); + pr_cfi_debug("CFI: rehashing all preambles\n"); ret = cfi_rand_preamble(start_cfi, end_cfi); if (ret) goto err; + pr_cfi_debug("CFI: rehashing all indirect calls\n"); ret = cfi_rand_callers(start_retpoline, end_retpoline); if (ret) goto err; + } else { + pr_cfi_debug("CFI: rehashing disabled\n"); } switch (cfi_mode) { @@ -1761,6 +1772,7 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, return; case CFI_KCFI: + pr_cfi_debug("CFI: re-enabling all indirect call checking\n"); ret = cfi_enable_callers(start_retpoline, end_retpoline); if (ret) goto err; @@ -1771,17 +1783,20 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, return; case CFI_FINEIBT: + pr_cfi_debug("CFI: adding FineIBT to all preambles\n"); /* place the FineIBT preamble at func()-16 */ ret = cfi_rewrite_preamble(start_cfi, end_cfi); if (ret) goto err; /* rewrite the callers to target func()-16 */ + pr_cfi_debug("CFI: rewriting indirect call sites to use FineIBT\n"); ret = cfi_rewrite_callers(start_retpoline, end_retpoline); if (ret) goto err; /* now that nobody targets func()+0, remove ENDBR there */ + pr_cfi_debug("CFI: removing old endbr insns\n"); cfi_rewrite_endbr(start_cfi, end_cfi); if (builtin) { @@ -2324,6 +2339,7 @@ void __init alternative_instructions(void) __apply_fineibt(__retpoline_sites, __retpoline_sites_end, __cfi_sites, __cfi_sites_end, true); + cfi_debug = false; /* * Rewrite the retpolines, must be done before alternatives since From 0b815825b1b0bd6762ca028e9b6631b002efb7ca Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 3 Sep 2025 20:46:45 -0700 Subject: [PATCH 0842/2711] x86/cfi: Remove __noinitretpoline and __noretpoline Commit 66f793099a63 ("x86/retpoline: Avoid retpolines for built-in __init functions") disabled retpolines in __init sections (__noinitretpoline) as a precaution against potential issues with retpolines in early boot, but it has not been a problem in practice (i.e. see Clang below). Commit 87358710c1fb ("x86/retpoline: Support retpoline builds with Clang") narrowed this to only GCC, as Clang doesn't have per-function control over retpoline emission. As such, Clang has been booting with retpolines in __init since retpoline support was introduced. Clang KCFI has been instrumenting __init since CFI was introduced. With the introduction of KCFI for GCC, KCFI instrumentation with retpolines disabled means that objtool does not construct .retpoline_sites section entries for the non-retpoline KCFI calls. At boot, the KCFI rehashing code, via __apply_fineibt(), misses all __init KCFI calls (since they are not retpolines), resulting in immediate hash mismatches: all preambles are rehashed (via .cfi_sites) and none of the __init call sites are rehashed. Remove __noinitretpoline since it provides no meaningful utility and creates problems with CFI. Additionally remove __noretpoline since it is now unused. Alternatively, cfi_rand_callers() could walk the .kcfi_traps section which is exactly the list of KCFI instrumentation sites. But it seems better to have as few differences in common instruction sequences between compilers as possible, so better to remove the special handling of retpolines in __init for GCC. Signed-off-by: Kees Cook Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20250904034656.3670313-6-kees@kernel.org --- include/linux/compiler-gcc.h | 4 ---- include/linux/init.h | 8 -------- 2 files changed, 12 deletions(-) diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 5d07c469b571..5de824a0b3d7 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -35,10 +35,6 @@ (typeof(ptr)) (__ptr + (off)); \ }) -#ifdef CONFIG_MITIGATION_RETPOLINE -#define __noretpoline __attribute__((__indirect_branch__("keep"))) -#endif - #if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__) #define __latent_entropy __attribute__((latent_entropy)) #endif diff --git a/include/linux/init.h b/include/linux/init.h index a60d32d227ee..17c1bc712e23 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -7,13 +7,6 @@ #include #include -/* Built-in __init functions needn't be compiled with retpoline */ -#if defined(__noretpoline) && !defined(MODULE) -#define __noinitretpoline __noretpoline -#else -#define __noinitretpoline -#endif - /* These macros are used to mark some functions or * initialized data (doesn't apply to uninitialized data) * as `initialization' functions. The kernel can take this @@ -50,7 +43,6 @@ /* These are for everybody (although not all archs will actually discard it in modules) */ #define __init __section(".init.text") __cold __latent_entropy \ - __noinitretpoline \ __no_kstack_erase #define __initdata __section(".init.data") #define __initconst __section(".init.rodata") From 85a2d4a890dce3cfc9c14aa91afc3dd7af8e3bf5 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 1 Sep 2025 12:49:58 +0200 Subject: [PATCH 0843/2711] x86,ibt: Use UDB instead of 0xEA A while ago [0] FineIBT started using the 0xEA instruction to raise #UD. All existing parts will generate #UD in 64bit mode on that instruction. However; Intel/AMD have not blessed using this instruction, it is on their 'reserved' opcode list for future use. Peter Anvin worked the committees and got use of 0xD6 blessed, it shall be called UDB (per the next SDM or so), and it being a single byte instruction is easy to slip into a single byte immediate -- as is done by this very patch. Reworking the FineIBT code to use UDB wasn't entirely trivial. Notably the FineIBT-BHI1 case ran out of bytes. In order to condense the encoding some it was required to move the hash register from R10D to EAX (thanks hpa!). Per the x86_64 ABI, RAX is used to pass the number of vector registers for vararg function calls -- something that should not happen in the kernel. More so, the kernel is built with -mskip-rax-setup, which should leave RAX completely unused, allowing its re-use. [ For BPF; while the bpf2bpf tail-call uses RAX in its calling convention, that does not use CFI and is unaffected. Only the 'regular' C->BPF transition is covered by CFI. ] The ENDBR poison value is changed from 'OSP NOP3' to 'NOPL -42(%RAX)', this is basically NOP4 but with UDB as its immediate. As such it is still a non-standard NOP value unique to prior ENDBR sites, but now also provides UDB. Per Agner Fog's optimization guide, Jcc is assumed not-taken. That is, the expected path should be the fallthrough case for improved throughput. Since the preamble now relies on the ENDBR poison to provide UDB, the code is changed to write the poison right along with the initial preamble -- this is possible because the ITS mitigation already disabled IBT over rewriting the CFI scheme. The scheme in detail: Preamble: FineIBT FineIBT-BHI1 FineIBT-BHI __cfi_\func: __cfi_\func: __cfi_\func: endbr endbr endbr subl $0x12345678, %eax subl $0x12345678, %eax subl $0x12345678, %eax jne.d32,np \func+3 cmovne %rax, %rdi cs cs call __bhi_args_N jne.d8,np \func+3 \func: \func: \func: nopl -42(%rax) nopl -42(%rax) nopl -42(%rax) Notably there are 7 bytes available after the SUBL; this enables the BHI1 case to fit without the nasty overlapping case it had previously. The !BHI case uses Jcc.d32,np to consume all 7 bytes without the need for an additional NOP, while the BHI case uses CS padding to align the CALL with the end of the preamble such that it returns to \func+0. Caller: FineIBT Paranoid-FineIBT fineibt_caller: fineibt_caller: mov $0x12345678, %eax mov $0x12345678, %eax lea -10(%r11), %r11 cmp -0x11(%r11), %eax nop5 cs lea -0x10(%r11), %r11 retpoline: retpoline: cs call __x86_indirect_thunk_r11 jne fineibt_caller+0xd call *%r11 nop Notably this is before apply_retpolines() which will fix up the retpoline call -- since all parts with IBT also have eIBRS (lets ignore ITS). Typically the retpoline site is rewritten (when still intact) into: call *%r11 nop3 [0] 06926c6cdb95 ("x86/ibt: Optimize the FineIBT instruction sequence") Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20250901191307.GI4067720@noisy.programming.kicks-ass.net --- arch/x86/include/asm/bug.h | 9 +- arch/x86/include/asm/cfi.h | 14 +-- arch/x86/include/asm/ibt.h | 10 +- arch/x86/kernel/alternative.c | 217 +++++++++++++++++++--------------- arch/x86/kernel/traps.c | 8 +- arch/x86/lib/bhi.S | 58 ++++----- arch/x86/lib/retpoline.S | 4 +- arch/x86/net/bpf_jit_comp.c | 6 +- 8 files changed, 178 insertions(+), 148 deletions(-) diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h index 20fcb8507ad1..880ca15073ed 100644 --- a/arch/x86/include/asm/bug.h +++ b/arch/x86/include/asm/bug.h @@ -5,14 +5,19 @@ #include #include #include +#include /* * Despite that some emulators terminate on UD2, we use it for WARN(). */ -#define ASM_UD2 ".byte 0x0f, 0x0b" +#define ASM_UD2 _ASM_BYTES(0x0f, 0x0b) #define INSN_UD2 0x0b0f #define LEN_UD2 2 +#define ASM_UDB _ASM_BYTES(0xd6) +#define INSN_UDB 0xd6 +#define LEN_UDB 1 + /* * In clang we have UD1s reporting UBSAN failures on X86, 64 and 32bit. */ @@ -26,7 +31,7 @@ #define BUG_UD2 0xfffe #define BUG_UD1 0xfffd #define BUG_UD1_UBSAN 0xfffc -#define BUG_EA 0xffea +#define BUG_UDB 0xffd6 #define BUG_LOCK 0xfff0 #ifdef CONFIG_GENERIC_BUG diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h index 1751f1eb95ef..3fcfdd996962 100644 --- a/arch/x86/include/asm/cfi.h +++ b/arch/x86/include/asm/cfi.h @@ -71,12 +71,10 @@ * * __cfi_foo: * endbr64 - * subl 0x12345678, %r10d - * jz foo - * ud2 - * nop + * subl 0x12345678, %eax + * jne.32,pn foo+3 * foo: - * osp nop3 # was endbr64 + * nopl -42(%rax) # was endbr64 * ... code here ... * ret * @@ -86,9 +84,9 @@ * indirect caller: * lea foo(%rip), %r11 * ... - * movl $0x12345678, %r10d - * subl $16, %r11 - * nop4 + * movl $0x12345678, %eax + * lea -0x10(%r11), %r11 + * nop5 * call *%r11 * */ diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h index 28d845257303..5e45d6424722 100644 --- a/arch/x86/include/asm/ibt.h +++ b/arch/x86/include/asm/ibt.h @@ -59,10 +59,10 @@ static __always_inline __attribute_const__ u32 gen_endbr(void) static __always_inline __attribute_const__ u32 gen_endbr_poison(void) { /* - * 4 byte NOP that isn't NOP4 (in fact it is OSP NOP3), such that it - * will be unique to (former) ENDBR sites. + * 4 byte NOP that isn't NOP4, such that it will be unique to (former) + * ENDBR sites. Additionally it carries UDB as immediate. */ - return 0x001f0f66; /* osp nopl (%rax) */ + return 0xd6401f0f; /* nopl -42(%rax) */ } static inline bool __is_endbr(u32 val) @@ -70,10 +70,6 @@ static inline bool __is_endbr(u32 val) if (val == gen_endbr_poison()) return true; - /* See cfi_fineibt_bhi_preamble() */ - if (IS_ENABLED(CONFIG_FINEIBT_BHI) && val == 0x001f0ff5) - return true; - val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */ return val == gen_endbr(); } diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 7d4a992dadc3..3d6a88443616 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -147,10 +147,10 @@ static void *its_init_thunk(void *thunk, int reg) /* * When ITS uses indirect branch thunk the fineibt_paranoid * caller sequence doesn't fit in the caller site. So put the - * remaining part of the sequence ( + JNE) into the ITS + * remaining part of the sequence (UDB + JNE) into the ITS * thunk. */ - bytes[i++] = 0xea; /* invalid instruction */ + bytes[i++] = 0xd6; /* UDB */ bytes[i++] = 0x75; /* JNE */ bytes[i++] = 0xfd; @@ -163,7 +163,7 @@ static void *its_init_thunk(void *thunk, int reg) reg -= 8; } bytes[i++] = 0xff; - bytes[i++] = 0xe0 + reg; /* jmp *reg */ + bytes[i++] = 0xe0 + reg; /* JMP *reg */ bytes[i++] = 0xcc; return thunk + offset; @@ -970,7 +970,7 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) case JMP32_INSN_OPCODE: /* Check for cfi_paranoid + ITS */ dest = addr + insn.length + insn.immediate.value; - if (dest[-1] == 0xea && (dest[0] & 0xf0) == 0x70) { + if (dest[-1] == 0xd6 && (dest[0] & 0xf0) == 0x70) { WARN_ON_ONCE(cfi_mode != CFI_FINEIBT); continue; } @@ -1303,9 +1303,8 @@ early_param("cfi", cfi_parse_cmdline); * * __cfi_\func: __cfi_\func: * movl $0x12345678,%eax // 5 endbr64 // 4 - * nop subl $0x12345678,%r10d // 7 - * nop jne __cfi_\func+6 // 2 - * nop nop3 // 3 + * nop subl $0x12345678,%eax // 5 + * nop jne.d32,pn \func+3 // 7 * nop * nop * nop @@ -1314,34 +1313,45 @@ early_param("cfi", cfi_parse_cmdline); * nop * nop * nop + * nop + * \func: \func: + * endbr64 nopl -42(%rax) * * * caller: caller: - * movl $(-0x12345678),%r10d // 6 movl $0x12345678,%r10d // 6 + * movl $(-0x12345678),%r10d // 6 movl $0x12345678,%eax // 5 * addl $-15(%r11),%r10d // 4 lea -0x10(%r11),%r11 // 4 - * je 1f // 2 nop4 // 4 + * je 1f // 2 nop5 // 5 * ud2 // 2 * 1: cs call __x86_indirect_thunk_r11 // 6 call *%r11; nop3; // 6 * + * + * Notably, the FineIBT sequences are crafted such that branches are presumed + * non-taken. This is based on Agner Fog's optimization manual, which states: + * + * "Make conditional jumps most often not taken: The efficiency and throughput + * for not-taken branches is better than for taken branches on most + * processors. Therefore, it is good to place the most frequent branch first" */ /* * : * 0: f3 0f 1e fa endbr64 - * 4: 41 81 78 56 34 12 sub $0x12345678, %r10d - * b: 75 f9 jne 6 - * d: 0f 1f 00 nopl (%rax) + * 4: 2d 78 56 34 12 sub $0x12345678, %eax + * 9: 2e 0f 85 03 00 00 00 jne,pn 13 + * 10: 0f 1f 40 d6 nopl -0x2a(%rax) * - * Note that the JNE target is the 0xEA byte inside the SUB, this decodes as - * (bad) on x86_64 and raises #UD. + * Note that the JNE target is the 0xD6 byte inside the NOPL, this decodes as + * UDB on x86_64 and raises #UD. */ asm( ".pushsection .rodata \n" "fineibt_preamble_start: \n" " endbr64 \n" - " subl $0x12345678, %r10d \n" + " subl $0x12345678, %eax \n" "fineibt_preamble_bhi: \n" - " jne fineibt_preamble_start+6 \n" - ASM_NOP3 + " cs jne.d32 fineibt_preamble_start+0x13 \n" + "#fineibt_func: \n" + " nopl -42(%rax) \n" "fineibt_preamble_end: \n" ".popsection\n" ); @@ -1352,20 +1362,20 @@ extern u8 fineibt_preamble_end[]; #define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start) #define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start) -#define fineibt_preamble_ud 6 -#define fineibt_preamble_hash 7 +#define fineibt_preamble_ud 0x13 +#define fineibt_preamble_hash 5 /* * : - * 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d - * 6: 4d 8d 5b f0 lea -0x10(%r11), %r11 - * a: 0f 1f 40 00 nopl 0x0(%rax) + * 0: b8 78 56 34 12 mov $0x12345678, %eax + * 5: 4d 8d 5b f0 lea -0x10(%r11), %r11 + * 9: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) */ asm( ".pushsection .rodata \n" "fineibt_caller_start: \n" - " movl $0x12345678, %r10d \n" + " movl $0x12345678, %eax \n" " lea -0x10(%r11), %r11 \n" - ASM_NOP4 + ASM_NOP5 "fineibt_caller_end: \n" ".popsection \n" ); @@ -1374,7 +1384,7 @@ extern u8 fineibt_caller_start[]; extern u8 fineibt_caller_end[]; #define fineibt_caller_size (fineibt_caller_end - fineibt_caller_start) -#define fineibt_caller_hash 2 +#define fineibt_caller_hash 1 #define fineibt_caller_jmp (fineibt_caller_size - 2) @@ -1391,9 +1401,9 @@ extern u8 fineibt_caller_end[]; * of adding a load. * * : - * 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d - * 6: 45 3b 53 f7 cmp -0x9(%r11), %r10d - * a: 4d 8d 5b lea -0x10(%r11), %r11 + * 0: b8 78 56 34 12 mov $0x12345678, %eax + * 5: 41 3b 43 f5 cmp -0x11(%r11), %eax + * 9: 2e 4d 8d 5b cs lea -0x10(%r11), %r11 * e: 75 fd jne d * 10: 41 ff d3 call *%r11 * 13: 90 nop @@ -1405,9 +1415,10 @@ extern u8 fineibt_caller_end[]; */ asm( ".pushsection .rodata \n" "fineibt_paranoid_start: \n" - " movl $0x12345678, %r10d \n" - " cmpl -9(%r11), %r10d \n" - " lea -0x10(%r11), %r11 \n" + " mov $0x12345678, %eax \n" + " cmpl -11(%r11), %eax \n" + " cs lea -0x10(%r11), %r11 \n" + "#fineibt_caller_size: \n" " jne fineibt_paranoid_start+0xd \n" "fineibt_paranoid_ind: \n" " call *%r11 \n" @@ -1523,51 +1534,67 @@ static int cfi_rand_preamble(s32 *start, s32 *end) return 0; } +/* + * Inline the bhi-arity 1 case: + * + * __cfi_foo: + * 0: f3 0f 1e fa endbr64 + * 4: 2d 78 56 34 12 sub $0x12345678, %eax + * 9: 49 0f 45 fa cmovne %rax, %rdi + * d: 2e 75 03 jne,pn foo+0x3 + * + * foo: + * 10: 0f 1f 40 nopl -42(%rax) + * + * Notably, this scheme is incompatible with permissive CFI + * because the CMOVcc is unconditional and RDI will have been + * clobbered. + */ +asm( ".pushsection .rodata \n" + "fineibt_bhi1_start: \n" + " cmovne %rax, %rdi \n" + " cs jne fineibt_bhi1_func + 0x3 \n" + "fineibt_bhi1_func: \n" + " nopl -42(%rax) \n" + "fineibt_bhi1_end: \n" + ".popsection \n" +); + +extern u8 fineibt_bhi1_start[]; +extern u8 fineibt_bhi1_end[]; + +#define fineibt_bhi1_size (fineibt_bhi1_end - fineibt_bhi1_start) + static void cfi_fineibt_bhi_preamble(void *addr, int arity) { + u8 bytes[MAX_INSN_SIZE]; + if (!arity) return; if (!cfi_warn && arity == 1) { - /* - * Crazy scheme to allow arity-1 inline: - * - * __cfi_foo: - * 0: f3 0f 1e fa endbr64 - * 4: 41 81 78 56 34 12 sub 0x12345678, %r10d - * b: 49 0f 45 fa cmovne %r10, %rdi - * f: 75 f5 jne __cfi_foo+6 - * 11: 0f 1f 00 nopl (%rax) - * - * Code that direct calls to foo()+0, decodes the tail end as: - * - * foo: - * 0: f5 cmc - * 1: 0f 1f 00 nopl (%rax) - * - * which clobbers CF, but does not affect anything ABI - * wise. - * - * Notably, this scheme is incompatible with permissive CFI - * because the CMOVcc is unconditional and RDI will have been - * clobbered. - */ - const u8 magic[9] = { - 0x49, 0x0f, 0x45, 0xfa, - 0x75, 0xf5, - BYTES_NOP3, - }; - - text_poke_early(addr + fineibt_preamble_bhi, magic, 9); - + text_poke_early(addr + fineibt_preamble_bhi, + fineibt_bhi1_start, fineibt_bhi1_size); return; } - text_poke_early(addr + fineibt_preamble_bhi, - text_gen_insn(CALL_INSN_OPCODE, - addr + fineibt_preamble_bhi, - __bhi_args[arity]), - CALL_INSN_SIZE); + /* + * Replace the bytes at fineibt_preamble_bhi with a CALL instruction + * that lines up exactly with the end of the preamble, such that the + * return address will be foo+0. + * + * __cfi_foo: + * 0: f3 0f 1e fa endbr64 + * 4: 2d 78 56 34 12 sub $0x12345678, %eax + * 9: 2e 2e e8 DD DD DD DD cs cs call __bhi_args[arity] + */ + bytes[0] = 0x2e; + bytes[1] = 0x2e; + __text_gen_insn(bytes + 2, CALL_INSN_OPCODE, + addr + fineibt_preamble_bhi + 2, + __bhi_args[arity], CALL_INSN_SIZE); + + text_poke_early(addr + fineibt_preamble_bhi, bytes, 7); } static int cfi_rewrite_preamble(s32 *start, s32 *end) @@ -1658,8 +1685,6 @@ static int cfi_rewrite_callers(s32 *start, s32 *end) { s32 *s; - BUG_ON(fineibt_paranoid_size != 20); - for (s = start; s < end; s++) { void *addr = (void *)s + *s; struct insn insn; @@ -1712,13 +1737,18 @@ static int cfi_rewrite_callers(s32 *start, s32 *end) #define pr_cfi_debug(X...) if (cfi_debug) pr_info(X) +#define FINEIBT_WARN(_f, _v) \ + WARN_ONCE((_f) != (_v), "FineIBT: " #_f " %ld != %d\n", _f, _v) + static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, s32 *start_cfi, s32 *end_cfi, bool builtin) { int ret; - if (WARN_ONCE(fineibt_preamble_size != 16, - "FineIBT preamble wrong size: %ld", fineibt_preamble_size)) + if (FINEIBT_WARN(fineibt_preamble_size, 20) || + FINEIBT_WARN(fineibt_preamble_bhi + fineibt_bhi1_size, 20) || + FINEIBT_WARN(fineibt_caller_size, 14) || + FINEIBT_WARN(fineibt_paranoid_size, 20)) return; if (cfi_mode == CFI_AUTO) { @@ -1839,11 +1869,11 @@ static void poison_cfi(void *addr) /* * __cfi_\func: - * osp nopl (%rax) - * subl $0, %r10d - * jz 1f - * ud2 - * 1: nop + * nopl -42(%rax) + * sub $0, %eax + * jne \func+3 + * \func: + * nopl -42(%rax) */ poison_endbr(addr); poison_hash(addr + fineibt_preamble_hash); @@ -1869,12 +1899,14 @@ static void poison_cfi(void *addr) } } +#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE) + /* - * When regs->ip points to a 0xEA byte in the FineIBT preamble, + * When regs->ip points to a 0xD6 byte in the FineIBT preamble, * return true and fill out target and type. * * We check the preamble by checking for the ENDBR instruction relative to the - * 0xEA instruction. + * UDB instruction. */ static bool decode_fineibt_preamble(struct pt_regs *regs, unsigned long *target, u32 *type) { @@ -1884,10 +1916,10 @@ static bool decode_fineibt_preamble(struct pt_regs *regs, unsigned long *target, if (!exact_endbr((void *)addr)) return false; - *target = addr + fineibt_preamble_size; + *target = addr + fineibt_prefix_size; __get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault); - *type = (u32)regs->r10 + hash; + *type = (u32)regs->ax + hash; /* * Since regs->ip points to the middle of an instruction; it cannot @@ -1925,12 +1957,12 @@ static bool decode_fineibt_bhi(struct pt_regs *regs, unsigned long *target, u32 __get_kernel_nofault(&addr, regs->sp, unsigned long, Efault); *target = addr; - addr -= fineibt_preamble_size; + addr -= fineibt_prefix_size; if (!exact_endbr((void *)addr)) return false; __get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault); - *type = (u32)regs->r10 + hash; + *type = (u32)regs->ax + hash; /* * The UD2 sites are constructed with a RET immediately following, @@ -1947,7 +1979,7 @@ static bool is_paranoid_thunk(unsigned long addr) u32 thunk; __get_kernel_nofault(&thunk, (u32 *)addr, u32, Efault); - return (thunk & 0x00FFFFFF) == 0xfd75ea; + return (thunk & 0x00FFFFFF) == 0xfd75d6; Efault: return false; @@ -1955,8 +1987,7 @@ Efault: /* * regs->ip points to a LOCK Jcc.d8 instruction from the fineibt_paranoid_start[] - * sequence, or to an invalid instruction (0xea) + Jcc.d8 for cfi_paranoid + ITS - * thunk. + * sequence, or to UDB + Jcc.d8 for cfi_paranoid + ITS thunk. */ static bool decode_fineibt_paranoid(struct pt_regs *regs, unsigned long *target, u32 *type) { @@ -1966,8 +1997,8 @@ static bool decode_fineibt_paranoid(struct pt_regs *regs, unsigned long *target, return false; if (is_cfi_trap(addr + fineibt_caller_size - LEN_UD2)) { - *target = regs->r11 + fineibt_preamble_size; - *type = regs->r10; + *target = regs->r11 + fineibt_prefix_size; + *type = regs->ax; /* * Since the trapping instruction is the exact, but LOCK prefixed, @@ -1979,14 +2010,14 @@ static bool decode_fineibt_paranoid(struct pt_regs *regs, unsigned long *target, /* * The cfi_paranoid + ITS thunk combination results in: * - * 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d - * 6: 45 3b 53 f7 cmp -0x9(%r11), %r10d - * a: 4d 8d 5b f0 lea -0x10(%r11), %r11 + * 0: b8 78 56 34 12 mov $0x12345678, %eax + * 5: 41 3b 43 f7 cmp -11(%r11), %eax + * a: 2e 3d 8d 5b f0 cs lea -0x10(%r11), %r11 * e: 2e e8 XX XX XX XX cs call __x86_indirect_paranoid_thunk_r11 * * Where the paranoid_thunk looks like: * - * 1d: (bad) + * 1d: udb * __x86_indirect_paranoid_thunk_r11: * 1e: 75 fd jne 1d * __x86_indirect_its_thunk_r11: @@ -1995,8 +2026,8 @@ static bool decode_fineibt_paranoid(struct pt_regs *regs, unsigned long *target, * */ if (is_paranoid_thunk(regs->ip)) { - *target = regs->r11 + fineibt_preamble_size; - *type = regs->r10; + *target = regs->r11 + fineibt_prefix_size; + *type = regs->ax; regs->ip = *target; return true; diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 36354b470590..6b22611e69cc 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -97,7 +97,7 @@ __always_inline int is_valid_bugaddr(unsigned long addr) * Check for UD1 or UD2, accounting for Address Size Override Prefixes. * If it's a UD1, further decode to determine its use: * - * FineIBT: ea (bad) + * FineIBT: d6 udb * FineIBT: f0 75 f9 lock jne . - 6 * UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax * UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax @@ -130,9 +130,9 @@ __always_inline int decode_bug(unsigned long addr, s32 *imm, int *len) WARN_ON_ONCE(!lock); return BUG_LOCK; - case 0xea: + case 0xd6: *len = addr - start; - return BUG_EA; + return BUG_UDB; case OPCODE_ESCAPE: break; @@ -341,7 +341,7 @@ static noinstr bool handle_bug(struct pt_regs *regs) } fallthrough; - case BUG_EA: + case BUG_UDB: case BUG_LOCK: if (handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) { handled = true; diff --git a/arch/x86/lib/bhi.S b/arch/x86/lib/bhi.S index 58891681261b..aad1e5839202 100644 --- a/arch/x86/lib/bhi.S +++ b/arch/x86/lib/bhi.S @@ -5,7 +5,7 @@ #include /* - * Notably, the FineIBT preamble calling these will have ZF set and r10 zero. + * Notably, the FineIBT preamble calling these will have ZF set and eax zero. * * The very last element is in fact larger than 32 bytes, but since its the * last element, this does not matter, @@ -36,7 +36,7 @@ SYM_INNER_LABEL(__bhi_args_1, SYM_L_LOCAL) ANNOTATE_NOENDBR UNWIND_HINT_FUNC jne .Lud_1 - cmovne %r10, %rdi + cmovne %rax, %rdi ANNOTATE_UNRET_SAFE ret int3 @@ -53,8 +53,8 @@ SYM_INNER_LABEL(__bhi_args_2, SYM_L_LOCAL) ANNOTATE_NOENDBR UNWIND_HINT_FUNC jne .Lud_1 - cmovne %r10, %rdi - cmovne %r10, %rsi + cmovne %rax, %rdi + cmovne %rax, %rsi ANNOTATE_UNRET_SAFE ret int3 @@ -64,9 +64,9 @@ SYM_INNER_LABEL(__bhi_args_3, SYM_L_LOCAL) ANNOTATE_NOENDBR UNWIND_HINT_FUNC jne .Lud_1 - cmovne %r10, %rdi - cmovne %r10, %rsi - cmovne %r10, %rdx + cmovne %rax, %rdi + cmovne %rax, %rsi + cmovne %rax, %rdx ANNOTATE_UNRET_SAFE ret int3 @@ -76,10 +76,10 @@ SYM_INNER_LABEL(__bhi_args_4, SYM_L_LOCAL) ANNOTATE_NOENDBR UNWIND_HINT_FUNC jne .Lud_2 - cmovne %r10, %rdi - cmovne %r10, %rsi - cmovne %r10, %rdx - cmovne %r10, %rcx + cmovne %rax, %rdi + cmovne %rax, %rsi + cmovne %rax, %rdx + cmovne %rax, %rcx ANNOTATE_UNRET_SAFE ret int3 @@ -89,11 +89,11 @@ SYM_INNER_LABEL(__bhi_args_5, SYM_L_LOCAL) ANNOTATE_NOENDBR UNWIND_HINT_FUNC jne .Lud_2 - cmovne %r10, %rdi - cmovne %r10, %rsi - cmovne %r10, %rdx - cmovne %r10, %rcx - cmovne %r10, %r8 + cmovne %rax, %rdi + cmovne %rax, %rsi + cmovne %rax, %rdx + cmovne %rax, %rcx + cmovne %rax, %r8 ANNOTATE_UNRET_SAFE ret int3 @@ -110,12 +110,12 @@ SYM_INNER_LABEL(__bhi_args_6, SYM_L_LOCAL) ANNOTATE_NOENDBR UNWIND_HINT_FUNC jne .Lud_2 - cmovne %r10, %rdi - cmovne %r10, %rsi - cmovne %r10, %rdx - cmovne %r10, %rcx - cmovne %r10, %r8 - cmovne %r10, %r9 + cmovne %rax, %rdi + cmovne %rax, %rsi + cmovne %rax, %rdx + cmovne %rax, %rcx + cmovne %rax, %r8 + cmovne %rax, %r9 ANNOTATE_UNRET_SAFE ret int3 @@ -125,13 +125,13 @@ SYM_INNER_LABEL(__bhi_args_7, SYM_L_LOCAL) ANNOTATE_NOENDBR UNWIND_HINT_FUNC jne .Lud_2 - cmovne %r10, %rdi - cmovne %r10, %rsi - cmovne %r10, %rdx - cmovne %r10, %rcx - cmovne %r10, %r8 - cmovne %r10, %r9 - cmovne %r10, %rsp + cmovne %rax, %rdi + cmovne %rax, %rsi + cmovne %rax, %rdx + cmovne %rax, %rcx + cmovne %rax, %r8 + cmovne %rax, %r9 + cmovne %rax, %rsp ANNOTATE_UNRET_SAFE ret int3 diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S index d78d769a02bd..24b7aca454ec 100644 --- a/arch/x86/lib/retpoline.S +++ b/arch/x86/lib/retpoline.S @@ -373,10 +373,10 @@ SYM_FUNC_END(call_depth_return_thunk) .macro ITS_THUNK reg /* - * If CFI paranoid is used then the ITS thunk starts with opcodes (0xea; jne 1b) + * If CFI paranoid is used then the ITS thunk starts with opcodes (1: udb; jne 1b) * that complete the fineibt_paranoid caller sequence. */ -1: .byte 0xea +1: ASM_UDB SYM_INNER_LABEL(__x86_indirect_paranoid_thunk_\reg, SYM_L_GLOBAL) UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 7e3fca164620..5178ef1aa5c7 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -419,12 +419,12 @@ static void emit_fineibt(u8 **pprog, u8 *ip, u32 hash, int arity) u8 *prog = *pprog; EMIT_ENDBR(); - EMIT3_off32(0x41, 0x81, 0xea, hash); /* subl $hash, %r10d */ + EMIT1_off32(0x2d, hash); /* subl $hash, %eax */ if (cfi_bhi) { + EMIT2(0x2e, 0x2e); /* cs cs */ emit_call(&prog, __bhi_args[arity], ip + 11); } else { - EMIT2(0x75, 0xf9); /* jne.d8 .-7 */ - EMIT3(0x0f, 0x1f, 0x00); /* nop3 */ + EMIT3_off32(0x2e, 0x0f, 0x85, 3); /* jne.d32,pn 3 */ } EMIT_ENDBR_POISON(); From 4a1e02b15ac174c3c6d5e358e67c4ba980e7b336 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 2 Sep 2025 11:20:35 +0200 Subject: [PATCH 0844/2711] x86,retpoline: Optimize patch_retpoline() Currently the very common retpoline: "CS CALL __x86_indirect_thunk_r11" is transformed into "CALL *R11; NOP3" for eIBRS/BHI_NO parts. Similarly, paranoid fineibt has: "CALL *R11; NOP". Recognise that CS stuffing can avoid the extra NOP. However, due to prefix decode penalties, make sure to not emit too many CS prefixes. Notably: "CS CALL __x86_indirect_thunk_rax" must not become "CS CS CS CS CALL *RAX". Prefix decode penalties are typically many more cycles than decoding an extra NOP. Additionally, if the retpoline is a tail-call, the "JMP *%\reg" should be followed by INT3 for straight-line-speculation mitigation, since emit_indirect() now has a length argument, move this into emit_indirect() such that other users (paranoid-fineibt) also do this. Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20250902104627.GM4068168@noisy.programming.kicks-ass.net --- arch/x86/kernel/alternative.c | 42 ++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 3d6a88443616..69fb818df2ee 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -713,20 +713,33 @@ static inline bool is_jcc32(struct insn *insn) #if defined(CONFIG_MITIGATION_RETPOLINE) && defined(CONFIG_OBJTOOL) /* - * CALL/JMP *%\reg + * [CS]{,3} CALL/JMP *%\reg [INT3]* */ -static int emit_indirect(int op, int reg, u8 *bytes) +static int emit_indirect(int op, int reg, u8 *bytes, int len) { + int cs = 0, bp = 0; int i = 0; u8 modrm; + /* + * Set @len to the excess bytes after writing the instruction. + */ + len -= 2 + (reg >= 8); + WARN_ON_ONCE(len < 0); + switch (op) { case CALL_INSN_OPCODE: modrm = 0x10; /* Reg = 2; CALL r/m */ + /* + * Additional NOP is better than prefix decode penalty. + */ + if (len <= 3) + cs = len; break; case JMP32_INSN_OPCODE: modrm = 0x20; /* Reg = 4; JMP r/m */ + bp = len; break; default: @@ -734,6 +747,9 @@ static int emit_indirect(int op, int reg, u8 *bytes) return -1; } + while (cs--) + bytes[i++] = 0x2e; /* CS-prefix */ + if (reg >= 8) { bytes[i++] = 0x41; /* REX.B prefix */ reg -= 8; @@ -745,6 +761,9 @@ static int emit_indirect(int op, int reg, u8 *bytes) bytes[i++] = 0xff; /* opcode */ bytes[i++] = modrm; + while (bp--) + bytes[i++] = 0xcc; /* INT3 */ + return i; } @@ -918,20 +937,11 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes) return emit_its_trampoline(addr, insn, reg, bytes); #endif - ret = emit_indirect(op, reg, bytes + i); + ret = emit_indirect(op, reg, bytes + i, insn->length - i); if (ret < 0) return ret; i += ret; - /* - * The compiler is supposed to EMIT an INT3 after every unconditional - * JMP instruction due to AMD BTC. However, if the compiler is too old - * or MITIGATION_SLS isn't enabled, we still need an INT3 after - * indirect JMPs even on Intel. - */ - if (op == JMP32_INSN_OPCODE && i < insn->length) - bytes[i++] = INT3_INSN_OPCODE; - for (; i < insn->length;) bytes[i++] = BYTES_NOP1; @@ -1421,8 +1431,7 @@ asm( ".pushsection .rodata \n" "#fineibt_caller_size: \n" " jne fineibt_paranoid_start+0xd \n" "fineibt_paranoid_ind: \n" - " call *%r11 \n" - " nop \n" + " cs call *%r11 \n" "fineibt_paranoid_end: \n" ".popsection \n" ); @@ -1724,8 +1733,9 @@ static int cfi_rewrite_callers(s32 *start, s32 *end) emit_paranoid_trampoline(addr + fineibt_caller_size, &insn, 11, bytes + fineibt_caller_size); } else { - ret = emit_indirect(op, 11, bytes + fineibt_paranoid_ind); - if (WARN_ON_ONCE(ret != 3)) + int len = fineibt_paranoid_size - fineibt_paranoid_ind; + ret = emit_indirect(op, 11, bytes + fineibt_paranoid_ind, len); + if (WARN_ON_ONCE(ret != len)) continue; } From 3ff7ce84e18151578352c2b28320824b42df114b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 4 Sep 2025 10:09:04 +0100 Subject: [PATCH 0845/2711] perf python: Fix spelling mistake "metics" -> "metrics" There is a spelling mistake in a Python doc string. Fix it. Fixes: d0550be70f7ab84d ("perf python: Add parse_metrics function") Reviewed-by: Ian Rogers Signed-off-by: Colin Ian King Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: kernel-janitors@vger.kernel.org Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250904090904.2782814-1-colin.i.king@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 47178404802f..779fe1280a56 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -2187,7 +2187,7 @@ static PyMethodDef perf__methods[] = { .ml_meth = (PyCFunction) pyrf__parse_metrics, .ml_flags = METH_VARARGS, .ml_doc = PyDoc_STR( - "Parse a string of metics or metric groups and return an evlist.") + "Parse a string of metrics or metric groups and return an evlist.") }, { .ml_name = "pmus", From 1a461a62fb422db9cf870a4f184885cc69873b7f Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:03:57 -0700 Subject: [PATCH 0846/2711] perf parse-events: Handle fake PMUs in CPU terms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Parsing of PMU event table metrics with fake PMUs" will test metrics on machines/models that may be missing a PMU, in such a case the fake_pmu should be used to avoid errors. Metrics that get the cpumask from a different PMU, such as "tsc/cpu=cpu_atom/", also need to be resilient in this test. The parse_events_state fake_pmu is set when missing PMUs should be ignored. So that it can be queried, pass it to the config term functions, as well as to get_config_cpu, then ignore failures when fake_pmu is set. Some minor code refactoring to cut down on the indent and remove some redundant checks. Fixes: bd741d80dc65922c ("perf parse-events: Allow the cpu term to be a PMU or CPU range") Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: linux-actions@lists.infradead.org Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Weilin Wang Link: https://lore.kernel.org/r/20250818190416.145274-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 116 +++++++++++++++++---------------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 8282ddf68b98..0026cff4d69e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -126,7 +126,8 @@ static char *get_config_name(const struct parse_events_terms *head_terms) return get_config_str(head_terms, PARSE_EVENTS__TERM_TYPE_NAME); } -static struct perf_cpu_map *get_config_cpu(const struct parse_events_terms *head_terms) +static struct perf_cpu_map *get_config_cpu(const struct parse_events_terms *head_terms, + bool fake_pmu) { struct parse_events_term *term; struct perf_cpu_map *cpus = NULL; @@ -135,24 +136,33 @@ static struct perf_cpu_map *get_config_cpu(const struct parse_events_terms *head return NULL; list_for_each_entry(term, &head_terms->terms, list) { - if (term->type_term == PARSE_EVENTS__TERM_TYPE_CPU) { - struct perf_cpu_map *term_cpus; + struct perf_cpu_map *term_cpus; - if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { - term_cpus = perf_cpu_map__new_int(term->val.num); + if (term->type_term != PARSE_EVENTS__TERM_TYPE_CPU) + continue; + + if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { + term_cpus = perf_cpu_map__new_int(term->val.num); + } else { + struct perf_pmu *pmu = perf_pmus__find(term->val.str); + + if (pmu) { + term_cpus = pmu->is_core && perf_cpu_map__is_empty(pmu->cpus) + ? cpu_map__online() + : perf_cpu_map__get(pmu->cpus); } else { - struct perf_pmu *pmu = perf_pmus__find(term->val.str); - - if (pmu && perf_cpu_map__is_empty(pmu->cpus)) - term_cpus = pmu->is_core ? cpu_map__online() : NULL; - else if (pmu) - term_cpus = perf_cpu_map__get(pmu->cpus); - else - term_cpus = perf_cpu_map__new(term->val.str); + term_cpus = perf_cpu_map__new(term->val.str); + if (!term_cpus && fake_pmu) { + /* + * Assume the PMU string makes sense on a different + * machine and fake a value with all online CPUs. + */ + term_cpus = cpu_map__online(); + } } - perf_cpu_map__merge(&cpus, term_cpus); - perf_cpu_map__put(term_cpus); } + perf_cpu_map__merge(&cpus, term_cpus); + perf_cpu_map__put(term_cpus); } return cpus; @@ -369,13 +379,13 @@ static int parse_aliases(const char *str, const char *const names[][EVSEL__MAX_A typedef int config_term_func_t(struct perf_event_attr *attr, struct parse_events_term *term, - struct parse_events_error *err); + struct parse_events_state *parse_state); static int config_term_common(struct perf_event_attr *attr, struct parse_events_term *term, - struct parse_events_error *err); + struct parse_events_state *parse_state); static int config_attr(struct perf_event_attr *attr, const struct parse_events_terms *head, - struct parse_events_error *err, + struct parse_events_state *parse_state, config_term_func_t config_term); /** @@ -471,7 +481,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name, bool found_supported = false; const char *config_name = get_config_name(parsed_terms); const char *metric_id = get_config_metric_id(parsed_terms); - struct perf_cpu_map *cpus = get_config_cpu(parsed_terms); + struct perf_cpu_map *cpus = get_config_cpu(parsed_terms, parse_state->fake_pmu); int ret = 0; struct evsel *first_wildcard_match = NULL; @@ -514,8 +524,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name, found_supported = true; if (parsed_terms) { - if (config_attr(&attr, parsed_terms, parse_state->error, - config_term_common)) { + if (config_attr(&attr, parsed_terms, parse_state, config_term_common)) { ret = -EINVAL; goto out_err; } @@ -767,8 +776,7 @@ int parse_events_add_breakpoint(struct parse_events_state *parse_state, attr.sample_period = 1; if (head_config) { - if (config_attr(&attr, head_config, parse_state->error, - config_term_common)) + if (config_attr(&attr, head_config, parse_state, config_term_common)) return -EINVAL; if (get_config_terms(head_config, &config_terms)) @@ -903,12 +911,12 @@ void parse_events__shrink_config_terms(void) static int config_term_common(struct perf_event_attr *attr, struct parse_events_term *term, - struct parse_events_error *err) + struct parse_events_state *parse_state) { -#define CHECK_TYPE_VAL(type) \ -do { \ - if (check_type_val(term, err, PARSE_EVENTS__TERM_TYPE_ ## type)) \ - return -EINVAL; \ +#define CHECK_TYPE_VAL(type) \ +do { \ + if (check_type_val(term, parse_state->error, PARSE_EVENTS__TERM_TYPE_ ## type)) \ + return -EINVAL; \ } while (0) switch (term->type_term) { @@ -939,7 +947,7 @@ do { \ if (strcmp(term->val.str, "no") && parse_branch_str(term->val.str, &attr->branch_sample_type)) { - parse_events_error__handle(err, term->err_val, + parse_events_error__handle(parse_state->error, term->err_val, strdup("invalid branch sample type"), NULL); return -EINVAL; @@ -948,7 +956,7 @@ do { \ case PARSE_EVENTS__TERM_TYPE_TIME: CHECK_TYPE_VAL(NUM); if (term->val.num > 1) { - parse_events_error__handle(err, term->err_val, + parse_events_error__handle(parse_state->error, term->err_val, strdup("expected 0 or 1"), NULL); return -EINVAL; @@ -990,7 +998,7 @@ do { \ case PARSE_EVENTS__TERM_TYPE_PERCORE: CHECK_TYPE_VAL(NUM); if ((unsigned int)term->val.num > 1) { - parse_events_error__handle(err, term->err_val, + parse_events_error__handle(parse_state->error, term->err_val, strdup("expected 0 or 1"), NULL); return -EINVAL; @@ -1005,7 +1013,7 @@ do { \ case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: CHECK_TYPE_VAL(NUM); if (term->val.num > UINT_MAX) { - parse_events_error__handle(err, term->err_val, + parse_events_error__handle(parse_state->error, term->err_val, strdup("too big"), NULL); return -EINVAL; @@ -1016,7 +1024,7 @@ do { \ if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { if (term->val.num >= (u64)cpu__max_present_cpu().cpu) { - parse_events_error__handle(err, term->err_val, + parse_events_error__handle(parse_state->error, term->err_val, strdup("too big"), /*help=*/NULL); return -EINVAL; @@ -1028,8 +1036,8 @@ do { \ break; map = perf_cpu_map__new(term->val.str); - if (!map) { - parse_events_error__handle(err, term->err_val, + if (!map && !parse_state->fake_pmu) { + parse_events_error__handle(parse_state->error, term->err_val, strdup("not a valid PMU or CPU number"), /*help=*/NULL); return -EINVAL; @@ -1042,7 +1050,7 @@ do { \ case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE: case PARSE_EVENTS__TERM_TYPE_HARDWARE: default: - parse_events_error__handle(err, term->err_term, + parse_events_error__handle(parse_state->error, term->err_term, strdup(parse_events__term_type_str(term->type_term)), parse_events_formats_error_string(NULL)); return -EINVAL; @@ -1057,7 +1065,7 @@ do { \ * if an invalid config term is provided for legacy events * (for example, instructions/badterm/...), which is confusing. */ - if (!config_term_avail(term->type_term, err)) + if (!config_term_avail(term->type_term, parse_state->error)) return -EINVAL; return 0; #undef CHECK_TYPE_VAL @@ -1065,7 +1073,7 @@ do { \ static int config_term_pmu(struct perf_event_attr *attr, struct parse_events_term *term, - struct parse_events_error *err) + struct parse_events_state *parse_state) { if (term->type_term == PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE) { struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type); @@ -1074,7 +1082,7 @@ static int config_term_pmu(struct perf_event_attr *attr, char *err_str; if (asprintf(&err_str, "Failed to find PMU for type %d", attr->type) >= 0) - parse_events_error__handle(err, term->err_term, + parse_events_error__handle(parse_state->error, term->err_term, err_str, /*help=*/NULL); return -EINVAL; } @@ -1100,7 +1108,7 @@ static int config_term_pmu(struct perf_event_attr *attr, char *err_str; if (asprintf(&err_str, "Failed to find PMU for type %d", attr->type) >= 0) - parse_events_error__handle(err, term->err_term, + parse_events_error__handle(parse_state->error, term->err_term, err_str, /*help=*/NULL); return -EINVAL; } @@ -1128,12 +1136,12 @@ static int config_term_pmu(struct perf_event_attr *attr, */ return 0; } - return config_term_common(attr, term, err); + return config_term_common(attr, term, parse_state); } static int config_term_tracepoint(struct perf_event_attr *attr, struct parse_events_term *term, - struct parse_events_error *err) + struct parse_events_state *parse_state) { switch (term->type_term) { case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: @@ -1147,7 +1155,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr, case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: case PARSE_EVENTS__TERM_TYPE_AUX_ACTION: case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: - return config_term_common(attr, term, err); + return config_term_common(attr, term, parse_state); case PARSE_EVENTS__TERM_TYPE_USER: case PARSE_EVENTS__TERM_TYPE_CONFIG: case PARSE_EVENTS__TERM_TYPE_CONFIG1: @@ -1166,12 +1174,10 @@ static int config_term_tracepoint(struct perf_event_attr *attr, case PARSE_EVENTS__TERM_TYPE_HARDWARE: case PARSE_EVENTS__TERM_TYPE_CPU: default: - if (err) { - parse_events_error__handle(err, term->err_term, + parse_events_error__handle(parse_state->error, term->err_term, strdup(parse_events__term_type_str(term->type_term)), strdup("valid terms: call-graph,stack-size\n") ); - } return -EINVAL; } @@ -1180,13 +1186,13 @@ static int config_term_tracepoint(struct perf_event_attr *attr, static int config_attr(struct perf_event_attr *attr, const struct parse_events_terms *head, - struct parse_events_error *err, + struct parse_events_state *parse_state, config_term_func_t config_term) { struct parse_events_term *term; list_for_each_entry(term, &head->terms, list) - if (config_term(attr, term, err)) + if (config_term(attr, term, parse_state)) return -EINVAL; return 0; @@ -1378,8 +1384,7 @@ int parse_events_add_tracepoint(struct parse_events_state *parse_state, if (head_config) { struct perf_event_attr attr; - if (config_attr(&attr, head_config, err, - config_term_tracepoint)) + if (config_attr(&attr, head_config, parse_state, config_term_tracepoint)) return -EINVAL; } @@ -1408,8 +1413,7 @@ static int __parse_events_add_numeric(struct parse_events_state *parse_state, } if (head_config) { - if (config_attr(&attr, head_config, parse_state->error, - config_term_common)) + if (config_attr(&attr, head_config, parse_state, config_term_common)) return -EINVAL; if (get_config_terms(head_config, &config_terms)) @@ -1418,7 +1422,7 @@ static int __parse_events_add_numeric(struct parse_events_state *parse_state, name = get_config_name(head_config); metric_id = get_config_metric_id(head_config); - cpus = get_config_cpu(head_config); + cpus = get_config_cpu(head_config, parse_state->fake_pmu); ret = __add_event(list, &parse_state->idx, &attr, /*init_attr*/true, name, metric_id, pmu, &config_terms, first_wildcard_match, cpus, /*alternate_hw_config=*/PERF_COUNT_HW_MAX) ? 0 : -ENOMEM; @@ -1531,7 +1535,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, fix_raw(&parsed_terms, pmu); /* Configure attr/terms with a known PMU, this will set hardcoded terms. */ - if (config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) { + if (config_attr(&attr, &parsed_terms, parse_state, config_term_pmu)) { parse_events_terms__exit(&parsed_terms); return -EINVAL; } @@ -1555,7 +1559,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, /* Configure attr/terms again if an alias was expanded. */ if (alias_rewrote_terms && - config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) { + config_attr(&attr, &parsed_terms, parse_state, config_term_pmu)) { parse_events_terms__exit(&parsed_terms); return -EINVAL; } @@ -1583,7 +1587,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, return -EINVAL; } - term_cpu = get_config_cpu(&parsed_terms); + term_cpu = get_config_cpu(&parsed_terms, parse_state->fake_pmu); evsel = __add_event(list, &parse_state->idx, &attr, /*init_attr=*/true, get_config_name(&parsed_terms), get_config_metric_id(&parsed_terms), pmu, From 1b728c54fed1e46109c6c8ab8cd866f7577e775f Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:03:58 -0700 Subject: [PATCH 0847/2711] perf vendor events: Update alderlake events/metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update events from v1.31 to v1.33. Update metrics from TMA 5.0 to 5.1. The event updates come from: https://github.com/intel/perfmon/commit/c504da6cb00e52067206166d2049a0c11af3b650 https://github.com/intel/perfmon/commit/4c18312c1a22eb564f5dbc94b187b59e4383a56a Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/alderlake/adl-metrics.json | 114 ++++++------ .../pmu-events/arch/x86/alderlake/cache.json | 99 +++++------ .../arch/x86/alderlake/floating-point.json | 28 ++- .../arch/x86/alderlake/frontend.json | 42 +++-- .../pmu-events/arch/x86/alderlake/memory.json | 12 +- .../pmu-events/arch/x86/alderlake/other.json | 8 +- .../arch/x86/alderlake/pipeline.json | 163 +++++++----------- .../x86/alderlake/uncore-interconnect.json | 2 - .../arch/x86/alderlake/virtual-memory.json | 40 ++--- .../arch/x86/alderlaken/adln-metrics.json | 20 +-- .../x86/alderlaken/uncore-interconnect.json | 2 - tools/perf/pmu-events/arch/x86/mapfile.csv | 4 +- 12 files changed, 236 insertions(+), 298 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json b/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json index 377dfecd96bd..cae7c0cf02f2 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json @@ -1,56 +1,56 @@ [ { "BriefDescription": "C10 residency percent per package", - "MetricExpr": "cstate_pkg@c10\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c10\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C10_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C8 residency percent per package", - "MetricExpr": "cstate_pkg@c8\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c8\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C8_Pkg_Residency", "ScaleUnit": "100%" @@ -552,7 +552,7 @@ }, { "BriefDescription": "Average CPU Utilization", - "MetricExpr": "cpu_atom@CPU_CLK_UNHALTED.REF_TSC@ / TSC", + "MetricExpr": "cpu_atom@CPU_CLK_UNHALTED.REF_TSC@ / msr@tsc\\,cpu=cpu_atom@", "MetricName": "tma_info_system_cpu_utilization", "Unit": "cpu_atom" }, @@ -751,7 +751,7 @@ { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-be\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-be\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BvOB;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", "MetricThreshold": "tma_backend_bound > 0.2", @@ -789,24 +789,6 @@ "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)", "Unit": "cpu_core" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", - "Unit": "cpu_core" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency", - "Unit": "cpu_core" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", @@ -816,9 +798,27 @@ "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: ", "Unit": "cpu_core" }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency", + "Unit": "cpu_core" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20", @@ -826,7 +826,7 @@ }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * ((1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + cpu_core@RS.EMPTY_RESOURCE@ / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricExpr": "100 * ((1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + cpu_core@RS.EMPTY_RESOURCE@ / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -862,7 +862,7 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -879,7 +879,7 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU has wasted due to Branch Misprediction", - "MetricExpr": "cpu_core@topdown\\-br\\-mispredict@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-br\\-mispredict@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BadSpec;BrMispredicts;BvMP;TmaL2;TopdownL2;tma_L2_group;tma_bad_speculation_group;tma_issueBM", "MetricName": "tma_branch_mispredicts", "MetricThreshold": "tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15", @@ -992,7 +992,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(25 * tma_info_system_core_frequency * (cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@ * (cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ / (cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ + cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD@))) + 24 * tma_info_system_core_frequency * cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS@) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;DataSharing;LockCont;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_contested_accesses", @@ -1109,7 +1108,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1238,7 +1237,7 @@ }, { "BriefDescription": "This metric represents fraction of slots where the CPU was retiring heavy-weight operations -- instructions that require two or more uops or micro-coded sequences", - "MetricExpr": "cpu_core@topdown\\-heavy\\-ops@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-heavy\\-ops@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Retire;TmaL2;TopdownL2;tma_L2_group;tma_retiring_group", "MetricName": "tma_heavy_operations", "MetricThreshold": "tma_heavy_operations > 0.1", @@ -1851,7 +1850,7 @@ "Unit": "cpu_core" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "cpu_core@UOPS_EXECUTED.THREAD@ / (cpu_core@UOPS_EXECUTED.CORE_CYCLES_GE_1@ / 2 if #SMT_on else cpu_core@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute", @@ -1912,7 +1911,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc\\,cpu=cpu_core@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency", "Unit": "cpu_core" @@ -1926,7 +1925,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.REF_TSC@ / TSC", + "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.REF_TSC@ / msr@tsc\\,cpu=cpu_core@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized", "Unit": "cpu_core" @@ -1936,7 +1935,7 @@ "MetricExpr": "64 * (UNC_ARB_TRK_REQUESTS.ALL + UNC_ARB_COH_TRK_REQUESTS.ALL) / 1e6 / tma_info_system_time / 1e3", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full", + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full", "Unit": "cpu_core" }, { @@ -1980,7 +1979,6 @@ }, { "BriefDescription": "Average latency of data read request to external memory (in nanoseconds)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(UNC_ARB_TRK_OCCUPANCY.RD + UNC_ARB_DAT_OCCUPANCY.RD) / UNC_ARB_TRK_REQUESTS.RD", "MetricGroup": "Mem;MemoryLat;SoC", "MetricName": "tma_info_system_mem_read_latency", @@ -2031,6 +2029,13 @@ "MetricName": "tma_info_system_turbo_utilization", "Unit": "cpu_core" }, + { + "BriefDescription": "Measured Average Uncore Frequency for the SoC [GHz]", + "MetricExpr": "tma_info_system_socket_clks / 1e9 / tma_info_system_time", + "MetricGroup": "SoC", + "MetricName": "tma_info_system_uncore_frequency", + "Unit": "cpu_core" + }, { "BriefDescription": "Per-Logical Processor actual clocks when the Logical Processor is active.", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.THREAD@", @@ -2150,12 +2155,12 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", "MetricExpr": "min(2 * (cpu_core@MEM_INST_RETIRED.ALL_LOADS@ - cpu_core@MEM_LOAD_RETIRED.FB_HIT@ - cpu_core@MEM_LOAD_RETIRED.L1_MISS@) * 20 / 100, max(cpu_core@CYCLE_ACTIVITY.CYCLES_MEM_ANY@ - cpu_core@MEMORY_ACTIVITY.CYCLES_L1D_MISS@, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2171,7 +2176,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles with demand load accesses that hit the L2 cache under unloaded scenarios (possibly L2 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "3 * tma_info_system_core_frequency * cpu_core@MEM_LOAD_RETIRED.L2_HIT@ * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "MemoryLat;TopdownL4;tma_L4_group;tma_l2_bound_group", "MetricName": "tma_l2_hit_latency", @@ -2192,12 +2196,11 @@ }, { "BriefDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "9 * tma_info_system_core_frequency * (cpu_core@MEM_LOAD_RETIRED.L3_HIT@ * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2279,6 +2282,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(16 * max(0, cpu_core@MEM_INST_RETIRED.LOCK_LOADS@ - cpu_core@L2_RQSTS.ALL_RFO@) + cpu_core@MEM_INST_RETIRED.LOCK_LOADS@ / cpu_core@MEM_INST_RETIRED.ALL_STORES@ * (10 * cpu_core@L2_RQSTS.RFO_HIT@ + min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO@))) / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -2314,7 +2318,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2324,13 +2328,13 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%", "Unit": "cpu_core" }, { "BriefDescription": "This metric represents fraction of slots the Memory subsystem within the Backend was a bottleneck", - "MetricExpr": "cpu_core@topdown\\-mem\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-mem\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Backend;TmaL2;TopdownL2;tma_L2_group;tma_backend_bound_group", "MetricName": "tma_memory_bound", "MetricThreshold": "tma_memory_bound > 0.2 & tma_backend_bound > 0.2", @@ -2341,7 +2345,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to LFENCE Instructions.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * cpu_core@MISC2_RETIRED.LFENCE@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_memory_fence", @@ -2400,7 +2403,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "max(cpu_core@IDQ.MS_CYCLES_ANY@, cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@ / (cpu_core@UOPS_RETIRED.SLOTS@ / cpu_core@UOPS_ISSUED.ANY@)) / tma_info_core_core_clks / 2", + "MetricExpr": "max(cpu_core@IDQ.MS_CYCLES_ANY@, cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@ / (cpu_core@UOPS_RETIRED.SLOTS@ / cpu_core@UOPS_ISSUED.ANY@)) / tma_info_core_core_clks / 2.4", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -2439,6 +2442,7 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_light_operations - (tma_fp_arith + tma_int_operations + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", @@ -2507,6 +2511,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "((tma_ports_utilized_0 * tma_info_thread_clks + (cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ + tma_retiring * cpu_core@EXE_ACTIVITY.2_3_PORTS_UTIL@)) / tma_info_thread_clks if cpu_core@ARITH.DIV_ACTIVE@ < cpu_core@CYCLE_ACTIVITY.STALLS_TOTAL@ - cpu_core@EXE_ACTIVITY.BOUND_ON_LOADS@ else (cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ + tma_retiring * cpu_core@EXE_ACTIVITY.2_3_PORTS_UTIL@) / tma_info_thread_clks)", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", @@ -2517,6 +2522,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "(cpu_core@EXE_ACTIVITY.EXE_BOUND_0_PORTS@ + max(cpu_core@RS.EMPTY_RESOURCE@ - cpu_core@RESOURCE_STALLS.SCOREBOARD@, 0)) / tma_info_thread_clks * (cpu_core@CYCLE_ACTIVITY.STALLS_TOTAL@ - cpu_core@EXE_ACTIVITY.BOUND_ON_LOADS@) / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", @@ -2527,6 +2533,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", @@ -2537,7 +2544,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@EXE_ACTIVITY.2_PORTS_UTIL@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", @@ -2548,7 +2554,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 3 or more uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@UOPS_EXECUTED.CYCLES_GE_3@ / tma_info_thread_clks", "MetricGroup": "BvCB;PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_3m", @@ -2560,7 +2565,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-retiring@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-retiring@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -2591,7 +2596,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to PAUSE Instructions", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.PAUSE@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_slow_pause", @@ -2626,7 +2630,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%", "Unit": "cpu_core" }, diff --git a/tools/perf/pmu-events/arch/x86/alderlake/cache.json b/tools/perf/pmu-events/arch/x86/alderlake/cache.json index 5461576dafc7..6a56c9ad8e43 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/cache.json @@ -4,7 +4,6 @@ "Counter": "0,1,2,3", "EventCode": "0x51", "EventName": "L1D.HWPF_MISS", - "PublicDescription": "L1D.HWPF_MISS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20", "Unit": "cpu_core" @@ -14,7 +13,7 @@ "Counter": "0,1,2,3", "EventCode": "0x51", "EventName": "L1D.REPLACEMENT", - "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace. Available PDIST counters: 0", + "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -24,7 +23,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.FB_FULL", - "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -36,7 +35,7 @@ "EdgeDetect": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.FB_FULL_PERIODS", - "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -47,7 +46,6 @@ "Deprecated": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.L2_STALL", - "PublicDescription": "This event is deprecated. Refer to new event L1D_PEND_MISS.L2_STALLS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x4", "Unit": "cpu_core" @@ -57,7 +55,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.L2_STALLS", - "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x4", "Unit": "cpu_core" @@ -67,7 +65,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.PENDING", - "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type. Available PDIST counters: 0", + "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -78,7 +76,7 @@ "CounterMask": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.PENDING_CYCLES", - "PublicDescription": "Counts duration of L1D miss outstanding in cycles. Available PDIST counters: 0", + "PublicDescription": "Counts duration of L1D miss outstanding in cycles.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -88,7 +86,7 @@ "Counter": "0,1,2,3", "EventCode": "0x25", "EventName": "L2_LINES_IN.ALL", - "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects. Available PDIST counters: 0", + "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects.", "SampleAfterValue": "100003", "UMask": "0x1f", "Unit": "cpu_core" @@ -98,7 +96,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.NON_SILENT", - "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3 Available PDIST counters: 0", + "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3", "SampleAfterValue": "200003", "UMask": "0x2", "Unit": "cpu_core" @@ -108,7 +106,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.SILENT", - "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event. Available PDIST counters: 0", + "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event.", "SampleAfterValue": "200003", "UMask": "0x1", "Unit": "cpu_core" @@ -118,7 +116,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.USELESS_HWPF", - "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache Available PDIST counters: 0", + "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache", "SampleAfterValue": "200003", "UMask": "0x4", "Unit": "cpu_core" @@ -137,7 +135,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.ALL", - "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES]", "SampleAfterValue": "200003", "UMask": "0xff", "Unit": "cpu_core" @@ -167,7 +165,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.MISS", - "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS] Available PDIST counters: 0", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS]", "SampleAfterValue": "200003", "UMask": "0x3f", "Unit": "cpu_core" @@ -177,7 +175,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_CODE_RD", - "PublicDescription": "Counts the total number of L2 code requests. Available PDIST counters: 0", + "PublicDescription": "Counts the total number of L2 code requests.", "SampleAfterValue": "200003", "UMask": "0xe4", "Unit": "cpu_core" @@ -187,7 +185,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_DATA_RD", - "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once. Available PDIST counters: 0", + "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once.", "SampleAfterValue": "200003", "UMask": "0xe1", "Unit": "cpu_core" @@ -197,7 +195,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_MISS", - "PublicDescription": "Counts demand requests that miss L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts demand requests that miss L2 cache.", "SampleAfterValue": "200003", "UMask": "0x27", "Unit": "cpu_core" @@ -207,7 +205,6 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_HWPF", - "PublicDescription": "L2_RQSTS.ALL_HWPF Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0xf0", "Unit": "cpu_core" @@ -217,7 +214,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_RFO", - "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches. Available PDIST counters: 0", + "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches.", "SampleAfterValue": "200003", "UMask": "0xe2", "Unit": "cpu_core" @@ -227,7 +224,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.CODE_RD_HIT", - "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads. Available PDIST counters: 0", + "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads.", "SampleAfterValue": "200003", "UMask": "0xc4", "Unit": "cpu_core" @@ -237,7 +234,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.CODE_RD_MISS", - "PublicDescription": "Counts L2 cache misses when fetching instructions. Available PDIST counters: 0", + "PublicDescription": "Counts L2 cache misses when fetching instructions.", "SampleAfterValue": "200003", "UMask": "0x24", "Unit": "cpu_core" @@ -247,7 +244,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.DEMAND_DATA_RD_HIT", - "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache.", "SampleAfterValue": "200003", "UMask": "0xc1", "Unit": "cpu_core" @@ -257,7 +254,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS", - "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once. Available PDIST counters: 0", + "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once.", "SampleAfterValue": "200003", "UMask": "0x21", "Unit": "cpu_core" @@ -267,7 +264,6 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.HWPF_MISS", - "PublicDescription": "L2_RQSTS.HWPF_MISS Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x30", "Unit": "cpu_core" @@ -277,7 +273,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.MISS", - "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS] Available PDIST counters: 0", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS]", "SampleAfterValue": "200003", "UMask": "0x3f", "Unit": "cpu_core" @@ -287,7 +283,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.REFERENCES", - "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL]", "SampleAfterValue": "200003", "UMask": "0xff", "Unit": "cpu_core" @@ -297,7 +293,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.RFO_HIT", - "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache.", "SampleAfterValue": "200003", "UMask": "0xc2", "Unit": "cpu_core" @@ -307,7 +303,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.RFO_MISS", - "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache.", "SampleAfterValue": "200003", "UMask": "0x22", "Unit": "cpu_core" @@ -317,7 +313,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.SWPF_HIT", - "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full. Available PDIST counters: 0", + "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full.", "SampleAfterValue": "200003", "UMask": "0xc8", "Unit": "cpu_core" @@ -327,7 +323,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.SWPF_MISS", - "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full. Available PDIST counters: 0", + "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full.", "SampleAfterValue": "200003", "UMask": "0x28", "Unit": "cpu_core" @@ -337,7 +333,7 @@ "Counter": "0,1,2,3", "EventCode": "0x23", "EventName": "L2_TRANS.L2_WB", - "PublicDescription": "Counts L2 writebacks that access L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts L2 writebacks that access L2 cache.", "SampleAfterValue": "200003", "UMask": "0x40", "Unit": "cpu_core" @@ -357,7 +353,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.MISS", - "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3. Available PDIST counters: 0", + "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", "SampleAfterValue": "100003", "UMask": "0x41", "Unit": "cpu_core" @@ -377,7 +373,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.REFERENCE", - "PublicDescription": "Counts core-originated cacheable requests to the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3. Available PDIST counters: 0", + "PublicDescription": "Counts core-originated cacheable requests to the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", "SampleAfterValue": "100003", "UMask": "0x4f", "Unit": "cpu_core" @@ -552,7 +548,7 @@ "Counter": "0,1,2,3", "EventCode": "0x43", "EventName": "MEM_LOAD_COMPLETED.L1_MISS_ANY", - "PublicDescription": "Number of completed demand load requests that missed the L1 data cache including shadow misses (FB hits, merge to an ongoing L1D miss) Available PDIST counters: 0", + "PublicDescription": "Number of completed demand load requests that missed the L1 data cache including shadow misses (FB hits, merge to an ongoing L1D miss)", "SampleAfterValue": "1000003", "UMask": "0xfd", "Unit": "cpu_core" @@ -853,7 +849,6 @@ "Counter": "0,1,2,3", "EventCode": "0x44", "EventName": "MEM_STORE_RETIRED.L2_HIT", - "PublicDescription": "MEM_STORE_RETIRED.L2_HIT Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x1", "Unit": "cpu_core" @@ -1050,7 +1045,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe5", "EventName": "MEM_UOP_RETIRED.ANY", - "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses Available PDIST counters: 0", + "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses", "SampleAfterValue": "1000003", "UMask": "0x3", "Unit": "cpu_core" @@ -1372,7 +1367,6 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.ALL_REQUESTS", - "PublicDescription": "OFFCORE_REQUESTS.ALL_REQUESTS Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x80", "Unit": "cpu_core" @@ -1382,7 +1376,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DATA_RD", - "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type. Available PDIST counters: 0", + "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -1392,7 +1386,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_CODE_RD", - "PublicDescription": "Counts both cacheable and non-cacheable code read requests. Available PDIST counters: 0", + "PublicDescription": "Counts both cacheable and non-cacheable code read requests.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -1402,7 +1396,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_DATA_RD", - "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore. Available PDIST counters: 0", + "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -1412,7 +1406,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_RFO", - "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM. Available PDIST counters: 0", + "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -1424,7 +1418,6 @@ "Errata": "ADL038", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD", - "PublicDescription": "This event is deprecated. Refer to new event OFFCORE_REQUESTS_OUTSTANDING.DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -1436,7 +1429,6 @@ "Errata": "ADL038", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD", - "PublicDescription": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -1447,7 +1439,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_CODE_RD", - "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1458,7 +1450,6 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", - "PublicDescription": "Cycles where at least 1 outstanding demand data read request is pending. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1469,7 +1460,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO", - "PublicDescription": "Counts the number of offcore outstanding demand rfo Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding demand rfo Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x4", "Unit": "cpu_core" @@ -1480,7 +1471,6 @@ "Errata": "ADL038", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD", - "PublicDescription": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -1490,7 +1480,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_CODE_RD", - "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1500,7 +1490,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD", - "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor. Available PDIST counters: 0", + "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1510,7 +1500,7 @@ "Counter": "0,1,2,3", "EventCode": "0x2c", "EventName": "SQ_MISC.BUS_LOCK", - "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory. Available PDIST counters: 0", + "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -1520,7 +1510,6 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.ANY", - "PublicDescription": "Counts the number of PREFETCHNTA, PREFETCHW, PREFETCHT0, PREFETCHT1 or PREFETCHT2 instructions executed. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0xf", "Unit": "cpu_core" @@ -1530,7 +1519,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.NTA", - "PublicDescription": "Counts the number of PREFETCHNTA instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHNTA instructions executed.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -1540,7 +1529,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.PREFETCHW", - "PublicDescription": "Counts the number of PREFETCHW instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHW instructions executed.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -1550,7 +1539,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.T0", - "PublicDescription": "Counts the number of PREFETCHT0 instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHT0 instructions executed.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -1560,7 +1549,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.T1_T2", - "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/alderlake/floating-point.json b/tools/perf/pmu-events/arch/x86/alderlake/floating-point.json index d01f1b163ed8..62fd70f220e5 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/floating-point.json @@ -14,7 +14,6 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.FPDIV_ACTIVE", - "PublicDescription": "ARITH.FPDIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -33,7 +32,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.FP", - "PublicDescription": "Counts all microcode Floating Point assists. Available PDIST counters: 0", + "PublicDescription": "Counts all microcode Floating Point assists.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -43,7 +42,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.SSE_AVX_MIX", - "PublicDescription": "ASSISTS.SSE_AVX_MIX Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -53,7 +51,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_0", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -63,7 +60,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_1", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -73,7 +69,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_5", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -83,7 +78,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V0", - "PublicDescription": "FP_ARITH_DISPATCHED.V0 [This event is alias to FP_ARITH_DISPATCHED.PORT_0] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -93,7 +87,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V1", - "PublicDescription": "FP_ARITH_DISPATCHED.V1 [This event is alias to FP_ARITH_DISPATCHED.PORT_1] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -103,7 +96,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V2", - "PublicDescription": "FP_ARITH_DISPATCHED.V2 [This event is alias to FP_ARITH_DISPATCHED.PORT_5] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -113,7 +105,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -123,7 +115,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -133,7 +125,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -143,7 +135,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -153,7 +145,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.4_FLOPS", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x18", "Unit": "cpu_core" @@ -163,7 +155,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR", - "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "1000003", "UMask": "0x3", "Unit": "cpu_core" @@ -173,7 +165,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -183,7 +175,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_SINGLE", - "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -193,7 +185,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.VECTOR", - "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "1000003", "UMask": "0xfc", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/alderlake/frontend.json b/tools/perf/pmu-events/arch/x86/alderlake/frontend.json index dae3174a74fb..ff3b30c2619a 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/frontend.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/frontend.json @@ -14,7 +14,7 @@ "Counter": "0,1,2,3", "EventCode": "0x60", "EventName": "BACLEARS.ANY", - "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0", + "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -24,7 +24,7 @@ "Counter": "0,1,2,3", "EventCode": "0x87", "EventName": "DECODE.LCP", - "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk. Available PDIST counters: 0", + "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk.", "SampleAfterValue": "500009", "UMask": "0x1", "Unit": "cpu_core" @@ -34,7 +34,6 @@ "Counter": "0,1,2,3", "EventCode": "0x87", "EventName": "DECODE.MS_BUSY", - "PublicDescription": "Cycles the Microcode Sequencer is busy. Available PDIST counters: 0", "SampleAfterValue": "500009", "UMask": "0x2", "Unit": "cpu_core" @@ -44,7 +43,7 @@ "Counter": "0,1,2,3", "EventCode": "0x61", "EventName": "DSB2MITE_SWITCHES.PENALTY_CYCLES", - "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE. Available PDIST counters: 0", + "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -302,7 +301,7 @@ "Counter": "0,1,2,3", "EventCode": "0x80", "EventName": "ICACHE_DATA.STALLS", - "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity.", "SampleAfterValue": "500009", "UMask": "0x4", "Unit": "cpu_core" @@ -314,7 +313,6 @@ "EdgeDetect": "1", "EventCode": "0x80", "EventName": "ICACHE_DATA.STALL_PERIODS", - "PublicDescription": "ICACHE_DATA.STALL_PERIODS Available PDIST counters: 0", "SampleAfterValue": "500009", "UMask": "0x4", "Unit": "cpu_core" @@ -324,7 +322,7 @@ "Counter": "0,1,2,3", "EventCode": "0x83", "EventName": "ICACHE_TAG.STALLS", - "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss.", "SampleAfterValue": "200003", "UMask": "0x4", "Unit": "cpu_core" @@ -335,7 +333,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_ANY", - "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -346,7 +344,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ. Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -356,7 +354,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.DSB_UOPS", - "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -367,7 +365,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.MITE_CYCLES_ANY", - "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -378,7 +376,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.MITE_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -388,7 +386,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.MITE_UOPS", - "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -399,7 +397,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.MS_CYCLES_ANY", - "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE.", "SampleAfterValue": "2000003", "UMask": "0x20", "Unit": "cpu_core" @@ -411,7 +409,7 @@ "EdgeDetect": "1", "EventCode": "0x79", "EventName": "IDQ.MS_SWITCHES", - "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer. Available PDIST counters: 0", + "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer.", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -421,7 +419,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.MS_UOPS", - "PublicDescription": "Counts the total number of uops delivered by the Microcode Sequencer (MS). Available PDIST counters: 0", + "PublicDescription": "Counts the total number of uops delivered by the Microcode Sequencer (MS).", "SampleAfterValue": "1000003", "UMask": "0x20", "Unit": "cpu_core" @@ -431,7 +429,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CORE", - "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -442,7 +440,7 @@ "CounterMask": "6", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE", - "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -454,7 +452,7 @@ "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CYCLES_FE_WAS_OK", "Invert": "1", - "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK]", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -464,7 +462,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CORE", - "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -475,7 +473,7 @@ "CounterMask": "6", "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE", - "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -487,7 +485,7 @@ "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK", "Invert": "1", - "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK]", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/alderlake/memory.json b/tools/perf/pmu-events/arch/x86/alderlake/memory.json index 07f5786bdbc0..a0260d5b8619 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/memory.json @@ -5,7 +5,6 @@ "CounterMask": "6", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L3_MISS", - "PublicDescription": "Execution stalls while L3 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x6", "Unit": "cpu_core" @@ -79,7 +78,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", - "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture Available PDIST counters: 0", + "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -90,7 +89,6 @@ "CounterMask": "2", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.CYCLES_L1D_MISS", - "PublicDescription": "Cycles while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -101,7 +99,6 @@ "CounterMask": "3", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L1D_MISS", - "PublicDescription": "Execution stalls while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x3", "Unit": "cpu_core" @@ -112,7 +109,7 @@ "CounterMask": "5", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L2_MISS", - "PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock). Available PDIST counters: 0", + "PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_core" @@ -123,7 +120,7 @@ "CounterMask": "9", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L3_MISS", - "PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock). Available PDIST counters: 0", + "PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).", "SampleAfterValue": "1000003", "UMask": "0x9", "Unit": "cpu_core" @@ -417,7 +414,6 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "Counts demand data read requests that miss the L3 cache. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -427,7 +423,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache. Available PDIST counters: 0", + "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache.", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/alderlake/other.json b/tools/perf/pmu-events/arch/x86/alderlake/other.json index 5f64138edfe4..af46cde26b54 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/other.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/other.json @@ -4,7 +4,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.HARDWARE", - "PublicDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events. This includes, but not limited to, assists at EXE or MEM uop writeback like AVX* load/store/gather/scatter (non-FP GSSE-assist ) , assists generated by ROB like PEBS and RTIT, Uncore trap, RAR (Remote Action Request) and CET (Control flow Enforcement Technology) assists. the event also counts for Machine Ordering count. Available PDIST counters: 0", + "PublicDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events. This includes, but not limited to, assists at EXE or MEM uop writeback like AVX* load/store/gather/scatter (non-FP GSSE-assist ) , assists generated by ROB like PEBS and RTIT, Uncore trap, RAR (Remote Action Request) and CET (Control flow Enforcement Technology) assists. the event also counts for Machine Ordering count.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -14,7 +14,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.PAGE_FAULT", - "PublicDescription": "ASSISTS.PAGE_FAULT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -24,7 +23,6 @@ "Counter": "0,1,2,3", "EventCode": "0x28", "EventName": "CORE_POWER.LICENSE_1", - "PublicDescription": "CORE_POWER.LICENSE_1 Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x2", "Unit": "cpu_core" @@ -34,7 +32,6 @@ "Counter": "0,1,2,3", "EventCode": "0x28", "EventName": "CORE_POWER.LICENSE_2", - "PublicDescription": "CORE_POWER.LICENSE_2 Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x4", "Unit": "cpu_core" @@ -44,7 +41,6 @@ "Counter": "0,1,2,3", "EventCode": "0x28", "EventName": "CORE_POWER.LICENSE_3", - "PublicDescription": "CORE_POWER.LICENSE_3 Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x8", "Unit": "cpu_core" @@ -113,7 +109,7 @@ "CounterMask": "1", "EventCode": "0x2d", "EventName": "XQ.FULL_CYCLES", - "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache). Available PDIST counters: 0", + "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache).", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/alderlake/pipeline.json b/tools/perf/pmu-events/arch/x86/alderlake/pipeline.json index 48ef2a8cc49a..33d1f39e441f 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/pipeline.json @@ -6,7 +6,6 @@ "Deprecated": "1", "EventCode": "0xb0", "EventName": "ARITH.DIVIDER_ACTIVE", - "PublicDescription": "This event is deprecated. Refer to new event ARITH.DIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x9", "Unit": "cpu_core" @@ -27,7 +26,7 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.DIV_ACTIVE", - "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations.", "SampleAfterValue": "1000003", "UMask": "0x9", "Unit": "cpu_core" @@ -57,7 +56,6 @@ "Deprecated": "1", "EventCode": "0xb0", "EventName": "ARITH.FP_DIVIDER_ACTIVE", - "PublicDescription": "This event is deprecated. Refer to new event ARITH.FPDIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -78,7 +76,6 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.IDIV_ACTIVE", - "PublicDescription": "This event counts the cycles the integer divider is busy. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -108,7 +105,6 @@ "Deprecated": "1", "EventCode": "0xb0", "EventName": "ARITH.INT_DIVIDER_ACTIVE", - "PublicDescription": "This event is deprecated. Refer to new event ARITH.IDIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -118,7 +114,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.ANY", - "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists. Available PDIST counters: 0", + "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists.", "SampleAfterValue": "100003", "UMask": "0x1b", "Unit": "cpu_core" @@ -549,7 +545,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C01", - "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" @@ -559,7 +555,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C02", - "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", "SampleAfterValue": "2000003", "UMask": "0x20", "Unit": "cpu_core" @@ -569,7 +565,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C0_WAIT", - "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction.", "SampleAfterValue": "2000003", "UMask": "0x70", "Unit": "cpu_core" @@ -597,7 +593,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.DISTRIBUTED", - "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread. Available PDIST counters: 0", + "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -607,7 +603,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE", - "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted. Available PDIST counters: 0", + "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted.", "SampleAfterValue": "25003", "UMask": "0x2", "Unit": "cpu_core" @@ -617,7 +613,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.PAUSE", - "PublicDescription": "CPU_CLK_UNHALTED.PAUSE Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x40", "Unit": "cpu_core" @@ -629,7 +624,6 @@ "EdgeDetect": "1", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.PAUSE_INST", - "PublicDescription": "CPU_CLK_UNHALTED.PAUSE_INST Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x40", "Unit": "cpu_core" @@ -649,7 +643,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_DISTRIBUTED", - "PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread. Available PDIST counters: 0", + "PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -687,7 +681,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_TSC_P", - "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case. Available PDIST counters: 0", + "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -724,7 +718,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.THREAD_P", - "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time. Available PDIST counters: 0", + "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time.", "SampleAfterValue": "2000003", "Unit": "cpu_core" }, @@ -734,7 +728,6 @@ "CounterMask": "8", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L1D_MISS", - "PublicDescription": "Cycles while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -745,7 +738,6 @@ "CounterMask": "1", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L2_MISS", - "PublicDescription": "Cycles while L2 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -756,7 +748,6 @@ "CounterMask": "16", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_MEM_ANY", - "PublicDescription": "Cycles while memory subsystem has an outstanding load. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -767,7 +758,6 @@ "CounterMask": "12", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L1D_MISS", - "PublicDescription": "Execution stalls while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0xc", "Unit": "cpu_core" @@ -778,7 +768,6 @@ "CounterMask": "5", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L2_MISS", - "PublicDescription": "Execution stalls while L2 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_core" @@ -789,7 +778,6 @@ "CounterMask": "4", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_TOTAL", - "PublicDescription": "Total execution stalls. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x4", "Unit": "cpu_core" @@ -799,7 +787,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.1_PORTS_UTIL", - "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -809,7 +797,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.2_3_PORTS_UTIL", - "PublicDescription": "Cycles total of 2 or 3 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0xc", "Unit": "cpu_core" @@ -819,7 +806,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.2_PORTS_UTIL", - "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -829,7 +816,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.3_PORTS_UTIL", - "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -839,7 +826,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.4_PORTS_UTIL", - "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" @@ -850,7 +837,6 @@ "CounterMask": "5", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.BOUND_ON_LOADS", - "PublicDescription": "Execution stalls while memory subsystem has an outstanding load. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x21", "Unit": "cpu_core" @@ -861,7 +847,7 @@ "CounterMask": "2", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.BOUND_ON_STORES", - "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall.", "SampleAfterValue": "1000003", "UMask": "0x40", "Unit": "cpu_core" @@ -871,7 +857,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.EXE_BOUND_0_PORTS", - "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load. Available PDIST counters: 0", + "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load.", "SampleAfterValue": "1000003", "UMask": "0x80", "Unit": "cpu_core" @@ -881,7 +867,7 @@ "Counter": "0,1,2,3", "EventCode": "0x75", "EventName": "INST_DECODED.DECODERS", - "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions. Available PDIST counters: 0", + "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -927,7 +913,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.MACRO_FUSED", - "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" @@ -937,7 +922,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.NOP", - "PublicDescription": "Counts all retired NOP or ENDBR32/64 instructions Available PDIST counters: 0", + "PublicDescription": "Counts all retired NOP or ENDBR32/64 instructions", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -956,7 +941,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -968,7 +953,7 @@ "EdgeDetect": "1", "EventCode": "0xad", "EventName": "INT_MISC.CLEARS_COUNT", - "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears Available PDIST counters: 0", + "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears", "SampleAfterValue": "500009", "UMask": "0x1", "Unit": "cpu_core" @@ -978,7 +963,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.CLEAR_RESTEER_CYCLES", - "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path. Available PDIST counters: 0", + "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", "SampleAfterValue": "500009", "UMask": "0x80", "Unit": "cpu_core" @@ -988,7 +973,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.RECOVERY_CYCLES", - "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event. Available PDIST counters: 0", + "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event.", "SampleAfterValue": "500009", "UMask": "0x1", "Unit": "cpu_core" @@ -1000,7 +985,6 @@ "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES", "MSRIndex": "0x3F7", "MSRValue": "0x7", - "PublicDescription": "Bubble cycles of BAClear (Unknown Branch). Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x40", "Unit": "cpu_core" @@ -1010,7 +994,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.UOP_DROPPING", - "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons Available PDIST counters: 0", + "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -1020,7 +1004,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.128BIT", - "PublicDescription": "INT_VEC_RETIRED.128BIT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x13", "Unit": "cpu_core" @@ -1030,7 +1013,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.256BIT", - "PublicDescription": "INT_VEC_RETIRED.256BIT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0xac", "Unit": "cpu_core" @@ -1040,7 +1022,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.ADD_128", - "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions. Available PDIST counters: 0", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions.", "SampleAfterValue": "1000003", "UMask": "0x3", "Unit": "cpu_core" @@ -1050,7 +1032,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.ADD_256", - "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions. Available PDIST counters: 0", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions.", "SampleAfterValue": "1000003", "UMask": "0xc", "Unit": "cpu_core" @@ -1060,7 +1042,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.MUL_256", - "PublicDescription": "INT_VEC_RETIRED.MUL_256 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x80", "Unit": "cpu_core" @@ -1070,7 +1051,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.SHUFFLES", - "PublicDescription": "INT_VEC_RETIRED.SHUFFLES Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x40", "Unit": "cpu_core" @@ -1080,7 +1060,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.VNNI_128", - "PublicDescription": "INT_VEC_RETIRED.VNNI_128 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -1090,7 +1069,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.VNNI_256", - "PublicDescription": "INT_VEC_RETIRED.VNNI_256 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20", "Unit": "cpu_core" @@ -1119,7 +1097,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.ADDRESS_ALIAS", - "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -1138,7 +1116,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.NO_SR", - "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", "SampleAfterValue": "100003", "UMask": "0x88", "Unit": "cpu_core" @@ -1148,7 +1126,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.STORE_FORWARD", - "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide.", "SampleAfterValue": "100003", "UMask": "0x82", "Unit": "cpu_core" @@ -1158,7 +1136,7 @@ "Counter": "0,1,2,3", "EventCode": "0x4c", "EventName": "LOAD_HIT_PREFETCH.SWPF", - "PublicDescription": "Counts all software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions. Available PDIST counters: 0", + "PublicDescription": "Counts all software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -1169,7 +1147,7 @@ "CounterMask": "1", "EventCode": "0xa8", "EventName": "LSD.CYCLES_ACTIVE", - "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector). Available PDIST counters: 0", + "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector).", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1180,7 +1158,7 @@ "CounterMask": "6", "EventCode": "0xa8", "EventName": "LSD.CYCLES_OK", - "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector). Available PDIST counters: 0", + "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector).", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1190,7 +1168,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa8", "EventName": "LSD.UOPS", - "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector).", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1202,7 +1180,7 @@ "EdgeDetect": "1", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.COUNT", - "PublicDescription": "Counts the number of machine clears (nukes) of any type. Available PDIST counters: 0", + "PublicDescription": "Counts the number of machine clears (nukes) of any type.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -1258,7 +1236,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.SMC", - "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear. Available PDIST counters: 0", + "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -1268,7 +1246,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe0", "EventName": "MISC2_RETIRED.LFENCE", - "PublicDescription": "number of LFENCE retired instructions Available PDIST counters: 0", + "PublicDescription": "number of LFENCE retired instructions", "SampleAfterValue": "400009", "UMask": "0x20", "Unit": "cpu_core" @@ -1288,7 +1266,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcc", "EventName": "MISC_RETIRED.LBR_INSERTS", - "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT. Available PDIST counters: 0", + "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT.", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -1298,7 +1276,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa2", "EventName": "RESOURCE_STALLS.SB", - "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end. Available PDIST counters: 0", + "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -1308,7 +1286,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa2", "EventName": "RESOURCE_STALLS.SCOREBOARD", - "PublicDescription": "Counts cycles where the pipeline is stalled due to serializing operations. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -1318,7 +1295,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa5", "EventName": "RS.EMPTY", - "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses) Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses)", "SampleAfterValue": "1000003", "UMask": "0x7", "Unit": "cpu_core" @@ -1331,7 +1308,7 @@ "EventCode": "0xa5", "EventName": "RS.EMPTY_COUNT", "Invert": "1", - "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events) Available PDIST counters: 0", + "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events)", "SampleAfterValue": "100003", "UMask": "0x7", "Unit": "cpu_core" @@ -1341,7 +1318,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa5", "EventName": "RS.EMPTY_RESOURCE", - "PublicDescription": "Cycles when Reservation Station (RS) is empty due to a resource in the back-end Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1355,7 +1331,6 @@ "EventCode": "0xa5", "EventName": "RS_EMPTY.COUNT", "Invert": "1", - "PublicDescription": "This event is deprecated. Refer to new event RS.EMPTY_COUNT Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x7", "Unit": "cpu_core" @@ -1366,7 +1341,6 @@ "Deprecated": "1", "EventCode": "0xa5", "EventName": "RS_EMPTY.CYCLES", - "PublicDescription": "This event is deprecated. Refer to new event RS.EMPTY Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x7", "Unit": "cpu_core" @@ -1395,7 +1369,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.BACKEND_BOUND_SLOTS", - "PublicDescription": "Number of slots in TMA method where no micro-operations were being issued from front-end to back-end of the machine due to lack of back-end resources. Available PDIST counters: 0", + "PublicDescription": "Number of slots in TMA method where no micro-operations were being issued from front-end to back-end of the machine due to lack of back-end resources.", "SampleAfterValue": "10000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1405,7 +1379,7 @@ "Counter": "0", "EventCode": "0xa4", "EventName": "TOPDOWN.BAD_SPEC_SLOTS", - "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations. Available PDIST counters: 0", + "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations.", "SampleAfterValue": "10000003", "UMask": "0x4", "Unit": "cpu_core" @@ -1415,7 +1389,7 @@ "Counter": "0", "EventCode": "0xa4", "EventName": "TOPDOWN.BR_MISPREDICT_SLOTS", - "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction. Available PDIST counters: 0", + "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction.", "SampleAfterValue": "10000003", "UMask": "0x8", "Unit": "cpu_core" @@ -1425,7 +1399,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.MEMORY_BOUND_SLOTS", - "PublicDescription": "TOPDOWN.MEMORY_BOUND_SLOTS Available PDIST counters: 0", "SampleAfterValue": "10000003", "UMask": "0x10", "Unit": "cpu_core" @@ -1444,7 +1417,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.SLOTS_P", - "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core. Available PDIST counters: 0", + "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core.", "SampleAfterValue": "10000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1661,7 +1634,6 @@ "Counter": "0,1,2,3", "EventCode": "0x76", "EventName": "UOPS_DECODED.DEC0_UOPS", - "PublicDescription": "UOPS_DECODED.DEC0_UOPS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1671,7 +1643,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_0", - "PublicDescription": "Number of uops dispatch to execution port 0. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 0.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1681,7 +1653,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_1", - "PublicDescription": "Number of uops dispatch to execution port 1. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 1.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1691,7 +1663,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_2_3_10", - "PublicDescription": "Number of uops dispatch to execution ports 2, 3 and 10 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 2, 3 and 10", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -1701,7 +1673,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_4_9", - "PublicDescription": "Number of uops dispatch to execution ports 4 and 9 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 4 and 9", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" @@ -1711,7 +1683,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_5_11", - "PublicDescription": "Number of uops dispatch to execution ports 5 and 11 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 5 and 11", "SampleAfterValue": "2000003", "UMask": "0x20", "Unit": "cpu_core" @@ -1721,7 +1693,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_6", - "PublicDescription": "Number of uops dispatch to execution port 6. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 6.", "SampleAfterValue": "2000003", "UMask": "0x40", "Unit": "cpu_core" @@ -1731,7 +1703,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_7_8", - "PublicDescription": "Number of uops dispatch to execution ports 7 and 8. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 7 and 8.", "SampleAfterValue": "2000003", "UMask": "0x80", "Unit": "cpu_core" @@ -1742,7 +1714,7 @@ "CounterMask": "1", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_1", - "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1753,7 +1725,7 @@ "CounterMask": "2", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_2", - "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1764,7 +1736,7 @@ "CounterMask": "3", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_3", - "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1775,7 +1747,7 @@ "CounterMask": "4", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_4", - "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1786,7 +1758,7 @@ "CounterMask": "1", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_1", - "PublicDescription": "Cycles where at least 1 uop was executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 1 uop was executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1797,7 +1769,7 @@ "CounterMask": "2", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_2", - "PublicDescription": "Cycles where at least 2 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 2 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1808,7 +1780,7 @@ "CounterMask": "3", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_3", - "PublicDescription": "Cycles where at least 3 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 3 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1819,7 +1791,7 @@ "CounterMask": "4", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_4", - "PublicDescription": "Cycles where at least 4 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 4 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1831,7 +1803,7 @@ "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.STALLS", "Invert": "1", - "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1844,7 +1816,6 @@ "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.STALL_CYCLES", "Invert": "1", - "PublicDescription": "This event is deprecated. Refer to new event UOPS_EXECUTED.STALLS Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1854,7 +1825,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.THREAD", - "PublicDescription": "Counts the number of uops to be executed per-thread each cycle. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1864,7 +1834,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.X87", - "PublicDescription": "Counts the number of x87 uops executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of x87 uops executed.", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" @@ -1883,7 +1853,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xae", "EventName": "UOPS_ISSUED.ANY", - "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS).", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1894,7 +1864,6 @@ "CounterMask": "1", "EventCode": "0xae", "EventName": "UOPS_ISSUED.CYCLES", - "PublicDescription": "UOPS_ISSUED.CYCLES Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1913,7 +1882,7 @@ "CounterMask": "1", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.CYCLES", - "PublicDescription": "Counts cycles where at least one uop has retired. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where at least one uop has retired.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1923,7 +1892,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.HEAVY", - "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count. Available PDIST counters: 0", + "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1954,7 +1923,6 @@ "EventName": "UOPS_RETIRED.MS", "MSRIndex": "0x3F7", "MSRValue": "0x8", - "PublicDescription": "UOPS_RETIRED.MS Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -1964,7 +1932,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.SLOTS", - "PublicDescription": "Counts the retirement slots used each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the retirement slots used each cycle.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1976,7 +1944,7 @@ "EventCode": "0xc2", "EventName": "UOPS_RETIRED.STALLS", "Invert": "1", - "PublicDescription": "This event counts cycles without actually retired uops. Available PDIST counters: 0", + "PublicDescription": "This event counts cycles without actually retired uops.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1989,7 +1957,6 @@ "EventCode": "0xc2", "EventName": "UOPS_RETIRED.STALL_CYCLES", "Invert": "1", - "PublicDescription": "This event is deprecated. Refer to new event UOPS_RETIRED.STALLS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/alderlake/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/alderlake/uncore-interconnect.json index 7c0779c74154..b5604c7534e1 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/uncore-interconnect.json @@ -65,7 +65,6 @@ "Counter": "0,1", "EventCode": "0x81", "EventName": "UNC_ARB_REQ_TRK_REQUEST.DRD", - "Experimental": "1", "PerPkg": "1", "UMask": "0x2", "Unit": "ARB" @@ -103,7 +102,6 @@ "Counter": "0,1", "EventCode": "0x81", "EventName": "UNC_ARB_TRK_REQUESTS.RD", - "Experimental": "1", "PerPkg": "1", "UMask": "0x2", "Unit": "ARB" diff --git a/tools/perf/pmu-events/arch/x86/alderlake/virtual-memory.json b/tools/perf/pmu-events/arch/x86/alderlake/virtual-memory.json index ffbbd08acc68..132ce48af6d9 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/virtual-memory.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/virtual-memory.json @@ -4,7 +4,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.STLB_HIT", - "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB).", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -15,7 +15,7 @@ "CounterMask": "1", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -35,7 +35,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe", "Unit": "cpu_core" @@ -45,7 +45,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_1G", - "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -55,7 +55,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -65,7 +65,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -75,7 +75,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -85,7 +85,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.STLB_HIT", - "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB).", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -96,7 +96,7 @@ "CounterMask": "1", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -116,7 +116,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe", "Unit": "cpu_core" @@ -126,7 +126,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_1G", - "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -136,7 +136,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -146,7 +146,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -156,7 +156,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -184,7 +184,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.STLB_HIT", - "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB).", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -195,7 +195,7 @@ "CounterMask": "1", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -215,7 +215,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe", "Unit": "cpu_core" @@ -225,7 +225,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -235,7 +235,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -245,7 +245,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json b/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json index ce93648043ef..0f72c9192df6 100644 --- a/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json +++ b/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json @@ -1,56 +1,56 @@ [ { "BriefDescription": "C10 residency percent per package", - "MetricExpr": "cstate_pkg@c10\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c10\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C10_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C8 residency percent per package", - "MetricExpr": "cstate_pkg@c8\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c8\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C8_Pkg_Residency", "ScaleUnit": "100%" @@ -460,12 +460,12 @@ }, { "BriefDescription": "Average CPU Utilization", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricName": "tma_info_system_cpu_utilization" }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "cpu@CPU_CLK_UNHALTED.CORE_P@k / CPU_CLK_UNHALTED.CORE", + "MetricExpr": "CPU_CLK_UNHALTED.CORE_P:k / CPU_CLK_UNHALTED.CORE", "MetricGroup": "Summary", "MetricName": "tma_info_system_kernel_utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/alderlaken/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/alderlaken/uncore-interconnect.json index 7c0779c74154..b5604c7534e1 100644 --- a/tools/perf/pmu-events/arch/x86/alderlaken/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/alderlaken/uncore-interconnect.json @@ -65,7 +65,6 @@ "Counter": "0,1", "EventCode": "0x81", "EventName": "UNC_ARB_REQ_TRK_REQUEST.DRD", - "Experimental": "1", "PerPkg": "1", "UMask": "0x2", "Unit": "ARB" @@ -103,7 +102,6 @@ "Counter": "0,1", "EventCode": "0x81", "EventName": "UNC_ARB_TRK_REQUESTS.RD", - "Experimental": "1", "PerPkg": "1", "UMask": "0x2", "Unit": "ARB" diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 354ce241500b..d0a17905c74e 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -1,6 +1,6 @@ Family-model,Version,Filename,EventType -GenuineIntel-6-(97|9A|B7|BA|BF),v1.31,alderlake,core -GenuineIntel-6-BE,v1.31,alderlaken,core +GenuineIntel-6-(97|9A|B7|BA|BF),v1.33,alderlake,core +GenuineIntel-6-BE,v1.33,alderlaken,core GenuineIntel-6-C[56],v1.09,arrowlake,core GenuineIntel-6-(1C|26|27|35|36),v5,bonnell,core GenuineIntel-6-(3D|47),v30,broadwell,core From 3f7f743ec4891d36804103ee81027bcd49b4db4d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:03:59 -0700 Subject: [PATCH 0848/2711] perf vendor events: Update arrowlake events/metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update events from v1.09 to v1.12. Update metrics from TMA 5.0 to 5.1. The event updates come from: https://github.com/intel/perfmon/commit/d5b1d2e9ee89035198ab7752e0378acba86907b6 https://github.com/intel/perfmon/commit/b9c162b7c98874321af36a411ee3c2194ea9afeb Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/arrowlake/arl-metrics.json | 186 +++++++++++------- .../pmu-events/arch/x86/arrowlake/cache.json | 122 ++++++++---- .../arch/x86/arrowlake/frontend.json | 40 ++-- .../pmu-events/arch/x86/arrowlake/memory.json | 22 +-- .../arch/x86/arrowlake/pipeline.json | 94 +++++---- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 6 files changed, 285 insertions(+), 181 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/arl-metrics.json b/tools/perf/pmu-events/arch/x86/arrowlake/arl-metrics.json index b22a02450e6c..4f1f77404943 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/arl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/arl-metrics.json @@ -1,56 +1,56 @@ [ { "BriefDescription": "C10 residency percent per package", - "MetricExpr": "cstate_pkg@c10\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c10\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C10_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C8 residency percent per package", - "MetricExpr": "cstate_pkg@c8\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c8\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C8_Pkg_Residency", "ScaleUnit": "100%" @@ -567,7 +567,7 @@ }, { "BriefDescription": "Average CPU Utilization", - "MetricExpr": "cpu_atom@CPU_CLK_UNHALTED.REF_TSC@ / TSC", + "MetricExpr": "cpu_atom@CPU_CLK_UNHALTED.REF_TSC@ / msr@tsc\\,cpu=cpu_atom@", "MetricName": "tma_info_system_cpu_utilization", "Unit": "cpu_atom" }, @@ -774,7 +774,7 @@ { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-be\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-be\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BvOB;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", "MetricThreshold": "tma_backend_bound > 0.2", @@ -786,7 +786,7 @@ { "BriefDescription": "This category represents fraction of slots wasted due to incorrect speculations", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-bad\\-spec@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-bad\\-spec@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_bad_speculation", "MetricThreshold": "tma_bad_speculation > 0.15", @@ -812,24 +812,6 @@ "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)", "Unit": "cpu_core" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", - "Unit": "cpu_core" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_capacity / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency", - "Unit": "cpu_core" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", @@ -839,9 +821,27 @@ "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: ", "Unit": "cpu_core" }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_capacity / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency", + "Unit": "cpu_core" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20", @@ -849,7 +849,7 @@ }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * ((1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + cpu_core@RS.EMPTY_RESOURCE@ / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_microcode_sequencer + tma_few_uops_instructions) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricExpr": "100 * ((1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + cpu_core@RS.EMPTY_RESOURCE@ / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_microcode_sequencer + tma_few_uops_instructions) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -858,7 +858,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -885,7 +885,7 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -902,7 +902,7 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU has wasted due to Branch Misprediction", - "MetricExpr": "cpu_core@topdown\\-br\\-mispredict@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-br\\-mispredict@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BadSpec;BrMispredicts;BvMP;TmaL2;TopdownL2;tma_L2_group;tma_bad_speculation_group;tma_issueBM", "MetricName": "tma_branch_mispredicts", "MetricThreshold": "tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15", @@ -1042,7 +1042,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS@R, 24 * tma_info_system_core_frequency) + cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_HITM@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_HITM@R, 25 * tma_info_system_core_frequency)) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;DataSharing;LockCont;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_contested_accesses", @@ -1095,7 +1094,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to DSB (decoded uop cache) fetch pipeline", - "MetricExpr": "(cpu_core@IDQ.DSB_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ + cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", + "MetricExpr": "(cpu_core@IDQ.DSB_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / 2 + cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", "MetricGroup": "DSB;FetchBW;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_dsb", "MetricThreshold": "tma_dsb > 0.15 & tma_fetch_bandwidth > 0.2", @@ -1149,7 +1148,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1166,7 +1165,7 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU was stalled due to Frontend latency issues", - "MetricExpr": "cpu_core@topdown\\-fetch\\-lat@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-fetch\\-lat@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Frontend;TmaL2;TopdownL2;tma_L2_group;tma_frontend_bound_group", "MetricName": "tma_fetch_latency", "MetricThreshold": "tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15", @@ -1216,7 +1215,7 @@ }, { "BriefDescription": "This metric approximates arithmetic floating-point (FP) scalar uops fraction the CPU has retired", - "MetricExpr": "cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Compute;Flops;TopdownL4;tma_L4_group;tma_fp_arith_group;tma_issue2P", "MetricName": "tma_fp_scalar", "MetricThreshold": "tma_fp_scalar > 0.1 & (tma_fp_arith > 0.2 & tma_light_operations > 0.6)", @@ -1226,7 +1225,7 @@ }, { "BriefDescription": "This metric approximates arithmetic floating-point (FP) vector uops fraction the CPU has retired aggregated across all vector widths", - "MetricExpr": "cpu_core@FP_ARITH_INST_RETIRED.VECTOR@ / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "cpu_core@FP_ARITH_OPS_RETIRED.VECTOR@ / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Compute;Flops;TopdownL4;tma_L4_group;tma_fp_arith_group;tma_issue2P", "MetricName": "tma_fp_vector", "MetricThreshold": "tma_fp_vector > 0.1 & (tma_fp_arith > 0.2 & tma_light_operations > 0.6)", @@ -1236,7 +1235,7 @@ }, { "BriefDescription": "This metric approximates arithmetic FP vector uops fraction the CPU has retired for 128-bit wide vectors", - "MetricExpr": "(cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE@) / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "(cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_SINGLE@) / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Compute;Flops;TopdownL5;tma_L5_group;tma_fp_vector_group;tma_issue2P", "MetricName": "tma_fp_vector_128b", "MetricThreshold": "tma_fp_vector_128b > 0.1 & (tma_fp_vector > 0.1 & (tma_fp_arith > 0.2 & tma_light_operations > 0.6))", @@ -1246,7 +1245,7 @@ }, { "BriefDescription": "This metric approximates arithmetic FP vector uops fraction the CPU has retired for 256-bit wide vectors", - "MetricExpr": "cpu_core@FP_ARITH_INST_RETIRED.VECTOR\\,umask\\=0x30@ / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "cpu_core@FP_ARITH_OPS_RETIRED.VECTOR\\,umask\\=0x30@ / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Compute;Flops;TopdownL5;tma_L5_group;tma_fp_vector_group;tma_issue2P", "MetricName": "tma_fp_vector_256b", "MetricThreshold": "tma_fp_vector_256b > 0.1 & (tma_fp_vector > 0.1 & (tma_fp_arith > 0.2 & tma_light_operations > 0.6))", @@ -1257,7 +1256,7 @@ { "BriefDescription": "This category represents fraction of slots where the processor's Frontend undersupplies its Backend", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-fe\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-fe\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BvFB;BvIO;Default;PGO;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_frontend_bound", "MetricThreshold": "tma_frontend_bound > 0.15", @@ -1278,7 +1277,7 @@ }, { "BriefDescription": "This metric represents fraction of slots where the CPU was retiring heavy-weight operations -- instructions that require two or more uops or micro-coded sequences", - "MetricExpr": "cpu_core@topdown\\-heavy\\-ops@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-heavy\\-ops@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Retire;TmaL2;TopdownL2;tma_L2_group;tma_retiring_group", "MetricName": "tma_heavy_operations", "MetricThreshold": "tma_heavy_operations > 0.1", @@ -1456,7 +1455,7 @@ }, { "BriefDescription": "Floating Point Operations Per Cycle", - "MetricExpr": "(cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_INST_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@) / tma_info_thread_clks", + "MetricExpr": "(cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_OPS_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_OPS_RETIRED.256B_PACKED_SINGLE@) / tma_info_thread_clks", "MetricGroup": "Flops;Ret", "MetricName": "tma_info_core_flopc", "Unit": "cpu_core" @@ -1597,7 +1596,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic instruction (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ + cpu_core@FP_ARITH_INST_RETIRED.VECTOR@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ + cpu_core@FP_ARITH_OPS_RETIRED.VECTOR@)", "MetricGroup": "Flops;InsType", "MetricName": "tma_info_inst_mix_iparith", "MetricThreshold": "tma_info_inst_mix_iparith < 10", @@ -1606,7 +1605,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic AVX/SSE 128-bit instruction (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_SINGLE@)", "MetricGroup": "Flops;FpVector;InsType", "MetricName": "tma_info_inst_mix_iparith_avx128", "MetricThreshold": "tma_info_inst_mix_iparith_avx128 < 10", @@ -1615,7 +1614,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic AVX* 256-bit instruction (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_OPS_RETIRED.256B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_OPS_RETIRED.256B_PACKED_SINGLE@)", "MetricGroup": "Flops;FpVector;InsType", "MetricName": "tma_info_inst_mix_iparith_avx256", "MetricThreshold": "tma_info_inst_mix_iparith_avx256 < 10", @@ -1624,7 +1623,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic Scalar Double-Precision instruction (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@FP_ARITH_INST_RETIRED.SCALAR_DOUBLE@", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@FP_ARITH_OPS_RETIRED.SCALAR_DOUBLE@", "MetricGroup": "Flops;FpScalar;InsType", "MetricName": "tma_info_inst_mix_iparith_scalar_dp", "MetricThreshold": "tma_info_inst_mix_iparith_scalar_dp < 10", @@ -1633,7 +1632,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic Scalar Single-Precision instruction (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@FP_ARITH_INST_RETIRED.SCALAR_SINGLE@", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@FP_ARITH_OPS_RETIRED.SCALAR_SINGLE@", "MetricGroup": "Flops;FpScalar;InsType", "MetricName": "tma_info_inst_mix_iparith_scalar_sp", "MetricThreshold": "tma_info_inst_mix_iparith_scalar_sp < 10", @@ -1658,7 +1657,7 @@ }, { "BriefDescription": "Instructions per Floating Point (FP) Operation (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_INST_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_OPS_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_OPS_RETIRED.256B_PACKED_SINGLE@)", "MetricGroup": "Flops;InsType", "MetricName": "tma_info_inst_mix_ipflop", "MetricThreshold": "tma_info_inst_mix_ipflop < 10", @@ -1713,7 +1712,7 @@ }, { "BriefDescription": "Average per-thread data fill bandwidth to the L1 data cache [GB / sec]", - "MetricExpr": "64 * cpu_core@L1D.REPLACEMENT@ / 1e9 / tma_info_system_time", + "MetricExpr": "64 * cpu_core@L1D.L1_REPLACEMENT@ / 1e9 / tma_info_system_time", "MetricGroup": "Mem;MemoryBW", "MetricName": "tma_info_memory_l1d_cache_fill_bw", "Unit": "cpu_core" @@ -1725,6 +1724,13 @@ "MetricName": "tma_info_memory_l1dl0_cache_fill_bw", "Unit": "cpu_core" }, + { + "BriefDescription": "L0 cache true misses per kilo instruction for retired demand loads", + "MetricExpr": "1e3 * (cpu_core@MEM_LOAD_RETIRED.L1_MISS@ + cpu_core@MEM_LOAD_RETIRED.L1_HIT_L1@) / cpu_core@INST_RETIRED.ANY@", + "MetricGroup": "CacheHits;Mem", + "MetricName": "tma_info_memory_l1dl0_mpki", + "Unit": "cpu_core" + }, { "BriefDescription": "L1 cache true misses per kilo instruction for retired demand loads", "MetricExpr": "1e3 * cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / cpu_core@INST_RETIRED.ANY@", @@ -1940,6 +1946,13 @@ "MetricName": "tma_info_pipeline_fetch_mite", "Unit": "cpu_core" }, + { + "BriefDescription": "Average number of uops fetched from MS per cycle", + "MetricExpr": "cpu_core@IDQ.MS_UOPS@ / cpu_core@IDQ.MS_UOPS\\,cmask\\=1@", + "MetricGroup": "Fed;FetchLat;MicroSeq", + "MetricName": "tma_info_pipeline_fetch_ms", + "Unit": "cpu_core" + }, { "BriefDescription": "Instructions per a microcode Assist invocation", "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@ASSISTS.ANY@", @@ -1974,7 +1987,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc\\,cpu=cpu_core@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency", "Unit": "cpu_core" @@ -1988,14 +2001,22 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.REF_TSC@ / TSC", + "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.REF_TSC@ / msr@tsc\\,cpu=cpu_core@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized", "Unit": "cpu_core" }, + { + "BriefDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]", + "MetricExpr": "32 * UNC_M_TOTAL_DATA / 1e9 / tma_info_system_time", + "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", + "MetricName": "tma_info_system_dram_bw_use", + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full", + "Unit": "cpu_core" + }, { "BriefDescription": "Giga Floating Point Operations Per Second", - "MetricExpr": "(cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_INST_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@) / 1e9 / tma_info_system_time", + "MetricExpr": "(cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_OPS_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_OPS_RETIRED.256B_PACKED_SINGLE@) / 1e9 / tma_info_system_time", "MetricGroup": "Cor;Flops;HPC", "MetricName": "tma_info_system_gflops", "PublicDescription": "Giga Floating Point Operations Per Second. Aggregate across all supported options of: FP precisions, scalar and vector instructions, vector-width", @@ -2061,6 +2082,13 @@ "MetricName": "tma_info_system_turbo_utilization", "Unit": "cpu_core" }, + { + "BriefDescription": "Measured Average Uncore Frequency for the SoC [GHz]", + "MetricExpr": "tma_info_system_socket_clks / 1e9 / tma_info_system_time", + "MetricGroup": "SoC", + "MetricName": "tma_info_system_uncore_frequency", + "Unit": "cpu_core" + }, { "BriefDescription": "Per-Logical Processor actual clocks when the Logical Processor is active.", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.THREAD@", @@ -2182,12 +2210,12 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", - "MetricExpr": "4 * cpu_core@DEPENDENT_LOADS.ANY@ / tma_info_thread_clks", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "MetricExpr": "4 * cpu_core@DEPENDENT_LOADS.ANY\\,cmask\\=1@ / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2203,7 +2231,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles with demand load accesses that hit the L2 cache under unloaded scenarios (possibly L2 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_core@MEM_LOAD_RETIRED.L2_HIT@ * min(cpu_core@MEM_LOAD_RETIRED.L2_HIT@R, 3 * tma_info_system_core_frequency) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "MemoryLat;TopdownL4;tma_L4_group;tma_l2_bound_group", "MetricName": "tma_l2_hit_latency", @@ -2224,12 +2251,11 @@ }, { "BriefDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_core@MEM_LOAD_RETIRED.L3_HIT@ * min(cpu_core@MEM_LOAD_RETIRED.L3_HIT@R, 9 * tma_info_system_core_frequency) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2311,6 +2337,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_core@MEM_INST_RETIRED.LOCK_LOADS@ * cpu_core@MEM_INST_RETIRED.LOCK_LOADS@R / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -2321,7 +2348,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to LSD (Loop Stream Detector) unit", - "MetricExpr": "cpu_core@LSD.UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@LSD.UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / tma_info_thread_clks / 2", "MetricGroup": "FetchBW;LSD;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_lsd", "MetricThreshold": "tma_lsd > 0.15 & tma_fetch_bandwidth > 0.2", @@ -2346,7 +2373,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2356,13 +2383,13 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%", "Unit": "cpu_core" }, { "BriefDescription": "This metric represents fraction of slots the Memory subsystem within the Backend was a bottleneck", - "MetricExpr": "cpu_core@topdown\\-mem\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-mem\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Backend;TmaL2;TopdownL2;tma_L2_group;tma_backend_bound_group", "MetricName": "tma_memory_bound", "MetricThreshold": "tma_memory_bound > 0.2 & tma_backend_bound > 0.2", @@ -2373,7 +2400,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to LFENCE Instructions.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * cpu_core@MISC2_RETIRED.LFENCE@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_memory_fence", @@ -2412,7 +2438,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the MITE pipeline (the legacy decode pipeline)", - "MetricExpr": "(cpu_core@IDQ.MITE_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / 2 + cpu_core@IDQ.MITE_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", + "MetricExpr": "(cpu_core@IDQ.MITE_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / 2 + cpu_core@IDQ.MITE_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", "MetricGroup": "DSBmiss;FetchBW;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_mite", "MetricThreshold": "tma_mite > 0.1 & tma_fetch_bandwidth > 0.2", @@ -2432,7 +2458,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "cpu_core@IDQ.MS_CYCLES_ANY@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@IDQ.MS_CYCLES_ANY@ / tma_info_thread_clks / 1.8", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -2471,7 +2497,8 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", - "MetricExpr": "max(0, tma_light_operations - (tma_x87_use + (cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ + cpu_core@FP_ARITH_INST_RETIRED.VECTOR@) / (tma_retiring * tma_info_thread_slots) + (cpu_core@INT_VEC_RETIRED.ADD_128@ + cpu_core@INT_VEC_RETIRED.VNNI_128@ + cpu_core@INT_VEC_RETIRED.ADD_256@ + cpu_core@INT_VEC_RETIRED.MUL_256@ + cpu_core@INT_VEC_RETIRED.VNNI_256@) / (tma_retiring * tma_info_thread_slots) + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "max(0, tma_light_operations - (tma_x87_use + (cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ + cpu_core@FP_ARITH_OPS_RETIRED.VECTOR@) / (tma_retiring * tma_info_thread_slots) + (cpu_core@INT_VEC_RETIRED.ADD_128@ + cpu_core@INT_VEC_RETIRED.VNNI_128@ + cpu_core@INT_VEC_RETIRED.ADD_256@ + cpu_core@INT_VEC_RETIRED.MUL_256@ + cpu_core@INT_VEC_RETIRED.VNNI_256@) / (tma_retiring * tma_info_thread_slots) + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", "MetricThreshold": "tma_other_light_ops > 0.3 & tma_light_operations > 0.6", @@ -2509,6 +2536,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "((cpu_core@EXE_ACTIVITY.EXE_BOUND_0_PORTS@ + (cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ + tma_retiring * cpu_core@EXE_ACTIVITY.2_3_PORTS_UTIL@)) / tma_info_thread_clks if cpu_core@ARITH.DIV_ACTIVE@ < cpu_core@CYCLE_ACTIVITY.STALLS_TOTAL@ - cpu_core@EXE_ACTIVITY.BOUND_ON_LOADS@ else (cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ + tma_retiring * cpu_core@EXE_ACTIVITY.2_3_PORTS_UTIL@) / tma_info_thread_clks)", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", @@ -2519,6 +2547,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "cpu_core@EXE_ACTIVITY.EXE_BOUND_0_PORTS@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", @@ -2529,6 +2558,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", @@ -2539,7 +2569,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@EXE_ACTIVITY.2_PORTS_UTIL@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", @@ -2550,7 +2579,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 3 or more uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@UOPS_EXECUTED.CYCLES_GE_3@ / tma_info_thread_clks", "MetricGroup": "BvCB;PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_3m", @@ -2571,7 +2599,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-retiring@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-retiring@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -2586,7 +2614,7 @@ "MetricGroup": "BvIO;PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group;tma_issueSO", "MetricName": "tma_serializing_operation", "MetricThreshold": "tma_serializing_operation > 0.1 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2)", - "PublicDescription": "This metric represents fraction of cycles the CPU issue-pipeline was stalled due to serializing operations. Instructions like CPUID; WRMSR or LFENCE serialize the out-of-order execution which may limit performance. Sample with: RESOURCE_STALLS.SCOREBOARD. Related metrics: tma_ms_switches", + "PublicDescription": "This metric represents fraction of cycles the CPU issue-pipeline was stalled due to serializing operations. Instructions like CPUID; WRMSR or LFENCE serialize the out-of-order execution which may limit performance. Sample with: PARTIAL_RAT_STALLS.SCOREBOARD. Related metrics: tma_ms_switches", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2602,7 +2630,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to PAUSE Instructions", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.PAUSE@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_slow_pause", @@ -2637,7 +2664,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2651,6 +2678,15 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, + { + "BriefDescription": "This metric estimates clocks wasted due to loads blocked due to unknown store address (did not do memory disambiguation) or due to unknown store data", + "MetricExpr": "7 * cpu_core@LD_BLOCKS.STORE_EARLY\\,cmask\\=1@ / tma_info_thread_clks", + "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", + "MetricName": "tma_store_early_blk", + "MetricThreshold": "tma_store_early_blk > 0.2", + "ScaleUnit": "100%", + "Unit": "cpu_core" + }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", "MetricExpr": "13 * cpu_core@LD_BLOCKS.STORE_FORWARD@ / tma_info_thread_clks", diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/cache.json b/tools/perf/pmu-events/arch/x86/arrowlake/cache.json index 91929d8bcf47..f5168b55a6f4 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/cache.json @@ -28,6 +28,16 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Cachelines replaced into the L1 d-cache. Successful replacements only (not blocked) and exclude WB-miss case", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x51", + "EventName": "L1D.L1_REPLACEMENT", + "PublicDescription": "Counts cachelines replaced into the L1 d-cache.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, { "BriefDescription": "Cachelines replaced into the L0 and L1 d-cache. Successful replacements only (not blocked) and exclude WB-miss case", "Counter": "0,1,2,3,4,5,6,7,8,9", @@ -540,7 +550,7 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.ALL_LOADS", - "PublicDescription": "Counts Instructions with at least one architecturally visible load retired. Available PDIST counters: 0", + "PublicDescription": "Counts Instructions with at least one architecturally visible load retired. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x81", "Unit": "cpu_core" @@ -551,7 +561,7 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.ALL_STORES", - "PublicDescription": "Counts all retired store instructions. Available PDIST counters: 0", + "PublicDescription": "Counts all retired store instructions. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x82", "Unit": "cpu_core" @@ -561,7 +571,7 @@ "Counter": "0,1,2,3", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.ALL_SWPF", - "PublicDescription": "Counts all retired software prefetch instructions. Available PDIST counters: 0", + "PublicDescription": "Counts all retired software prefetch instructions. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x84", "Unit": "cpu_core" @@ -572,7 +582,7 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.ANY", - "PublicDescription": "Counts all retired memory instructions - loads and stores. Available PDIST counters: 0", + "PublicDescription": "Counts all retired memory instructions - loads and stores. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x87", "Unit": "cpu_core" @@ -583,7 +593,7 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.LOCK_LOADS", - "PublicDescription": "Counts retired load instructions with locked access. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with locked access. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x21", "Unit": "cpu_core" @@ -594,7 +604,7 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.SPLIT_LOADS", - "PublicDescription": "Counts retired load instructions that split across a cacheline boundary. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions that split across a cacheline boundary. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x41", "Unit": "cpu_core" @@ -605,18 +615,29 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.SPLIT_STORES", - "PublicDescription": "Counts retired store instructions that split across a cacheline boundary. Available PDIST counters: 0", + "PublicDescription": "Counts retired store instructions that split across a cacheline boundary. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x42", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired instructions that hit the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_HIT_ANY", + "PublicDescription": "Number of retired instructions with a clean hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0xf", + "Unit": "cpu_core" + }, { "BriefDescription": "Retired load instructions that hit the STLB.", "Counter": "0,1,2,3", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.STLB_HIT_LOADS", - "PublicDescription": "Number of retired load instructions with a clean hit in the 2nd-level TLB (STLB). Available PDIST counters: 0", + "PublicDescription": "Number of retired load instructions with a clean hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x9", "Unit": "cpu_core" @@ -627,18 +648,39 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.STLB_HIT_STORES", - "PublicDescription": "Number of retired store instructions that hit in the 2nd-level TLB (STLB). Available PDIST counters: 0", + "PublicDescription": "Number of retired store instructions that hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0xa", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired SWPF instructions that hit the STLB.", + "Counter": "0,1,2,3", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_HIT_SWPF", + "PublicDescription": "Number of retired SWPF instructions that hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0xc", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that miss the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_MISS_ANY", + "PublicDescription": "Retired instructions that miss the STLB. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x17", + "Unit": "cpu_core" + }, { "BriefDescription": "Retired load instructions that miss the STLB.", "Counter": "0,1,2,3", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.STLB_MISS_LOADS", - "PublicDescription": "Number of retired load instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0", + "PublicDescription": "Number of retired load instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x11", "Unit": "cpu_core" @@ -649,18 +691,28 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.STLB_MISS_STORES", - "PublicDescription": "Number of retired store instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0", + "PublicDescription": "Number of retired store instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x12", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired SWPF instructions that miss the STLB.", + "Counter": "0,1,2,3", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_MISS_SWPF", + "PublicDescription": "Number of retired SWPF instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x14", + "Unit": "cpu_core" + }, { "BriefDescription": "Retired load instructions whose data sources were a cross-core Snoop hits and forwards data from an in on-package core cache (induced by NI$)", "Counter": "0,1,2,3", "Data_LA": "1", "EventCode": "0xd2", "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD", - "PublicDescription": "Counts retired load instructions whose data sources were a cross-core Snoop hits and forwards data from an in on-package core cache (induced by NI$) Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions whose data sources were a cross-core Snoop hits and forwards data from an in on-package core cache (induced by NI$) Available PDIST counters: 0,1", "SampleAfterValue": "20011", "UMask": "0x10", "Unit": "cpu_core" @@ -671,7 +723,7 @@ "Data_LA": "1", "EventCode": "0xd2", "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_HITM", - "PublicDescription": "Counts retired load instructions whose data sources were HitM responses from shared L3, Hit-with-FWD is normally excluded. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions whose data sources were HitM responses from shared L3, Hit-with-FWD is normally excluded. Available PDIST counters: 0,1", "SampleAfterValue": "20011", "UMask": "0x4", "Unit": "cpu_core" @@ -682,7 +734,7 @@ "Data_LA": "1", "EventCode": "0xd2", "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS", - "PublicDescription": "Counts the retired load instructions whose data sources were L3 hit and cross-core snoop missed in on-pkg core cache. Available PDIST counters: 0", + "PublicDescription": "Counts the retired load instructions whose data sources were L3 hit and cross-core snoop missed in on-pkg core cache. Available PDIST counters: 0,1", "SampleAfterValue": "20011", "UMask": "0x1", "Unit": "cpu_core" @@ -693,7 +745,7 @@ "Data_LA": "1", "EventCode": "0xd2", "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD", - "PublicDescription": "Counts retired load instructions whose data sources were L3 and cross-core snoop hits in on-pkg core cache. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions whose data sources were L3 and cross-core snoop hits in on-pkg core cache. Available PDIST counters: 0,1", "SampleAfterValue": "20011", "UMask": "0x2", "Unit": "cpu_core" @@ -704,7 +756,7 @@ "Data_LA": "1", "EventCode": "0xd4", "EventName": "MEM_LOAD_MISC_RETIRED.UC", - "PublicDescription": "Retired instructions with at least one load to uncacheable memory-type, or at least one cache-line split locked access (Bus Lock). Available PDIST counters: 0", + "PublicDescription": "Retired instructions with at least one load to uncacheable memory-type, or at least one cache-line split locked access (Bus Lock). Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x4", "Unit": "cpu_core" @@ -715,7 +767,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.FB_HIT", - "PublicDescription": "Counts retired load instructions with at least one uop was load missed in L1 but hit FB (Fill Buffers) due to preceding miss to the same cache line with data not ready. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop was load missed in L1 but hit FB (Fill Buffers) due to preceding miss to the same cache line with data not ready. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x40", "Unit": "cpu_core" @@ -726,7 +778,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L1_HIT", - "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x101", "Unit": "cpu_core" @@ -737,7 +789,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L1_HIT_L0", - "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 0 of the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 0 of the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -747,7 +799,7 @@ "Counter": "0,1,2,3", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L1_HIT_L1", - "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 1 of the L1 data cache. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 1 of the L1 data cache. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "Unit": "cpu_core" }, @@ -757,7 +809,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L1_MISS", - "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L1 cache. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L1 cache. Available PDIST counters: 0,1", "SampleAfterValue": "200003", "UMask": "0x8", "Unit": "cpu_core" @@ -768,7 +820,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L2_HIT", - "PublicDescription": "Counts retired load instructions with L2 cache hits as data sources. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with L2 cache hits as data sources. Available PDIST counters: 0,1", "SampleAfterValue": "200003", "UMask": "0x2", "Unit": "cpu_core" @@ -779,7 +831,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L2_MISS", - "PublicDescription": "Counts retired load instructions missed L2 cache as data sources. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions missed L2 cache as data sources. Available PDIST counters: 0,1", "SampleAfterValue": "100021", "UMask": "0x10", "Unit": "cpu_core" @@ -790,7 +842,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L3_HIT", - "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L3 cache. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L3 cache. Available PDIST counters: 0,1", "SampleAfterValue": "100021", "UMask": "0x4", "Unit": "cpu_core" @@ -801,7 +853,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L3_MISS", - "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L3 cache. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L3 cache. Available PDIST counters: 0,1", "SampleAfterValue": "50021", "UMask": "0x20", "Unit": "cpu_core" @@ -1029,7 +1081,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_1024", @@ -1053,7 +1105,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_128", @@ -1077,7 +1129,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_16", @@ -1089,7 +1141,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_2048", @@ -1113,7 +1165,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_256", @@ -1137,7 +1189,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_32", @@ -1161,7 +1213,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_4", @@ -1185,7 +1237,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_512", @@ -1209,7 +1261,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_64", @@ -1233,7 +1285,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_8", diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/frontend.json b/tools/perf/pmu-events/arch/x86/arrowlake/frontend.json index 56cf1ec63200..db2ef84ca041 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/frontend.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/frontend.json @@ -81,7 +81,7 @@ "EventName": "FRONTEND_RETIRED.ANY_ANT", "MSRIndex": "0x3F7", "MSRValue": "0x9", - "PublicDescription": "Always Not Taken (ANT) conditional retired branches (no BTB entry and not mispredicted) Available PDIST counters: 0", + "PublicDescription": "Always Not Taken (ANT) conditional retired branches (no BTB entry and not mispredicted) Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -93,7 +93,7 @@ "EventName": "FRONTEND_RETIRED.ANY_DSB_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x1", - "PublicDescription": "Counts retired Instructions that experienced DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Available PDIST counters: 0", + "PublicDescription": "Counts retired Instructions that experienced DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -179,7 +179,7 @@ "EventName": "FRONTEND_RETIRED.DSB_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x11", - "PublicDescription": "Number of retired Instructions that experienced a critical DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Critical means stalls were exposed to the back-end as a result of the DSB miss. Available PDIST counters: 0", + "PublicDescription": "Number of retired Instructions that experienced a critical DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Critical means stalls were exposed to the back-end as a result of the DSB miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -218,7 +218,7 @@ "EventName": "FRONTEND_RETIRED.ITLB_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x14", - "PublicDescription": "Counts retired Instructions that experienced iTLB (Instruction TLB) true miss. Available PDIST counters: 0", + "PublicDescription": "Counts retired Instructions that experienced iTLB (Instruction TLB) true miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -239,7 +239,7 @@ "EventName": "FRONTEND_RETIRED.L1I_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x12", - "PublicDescription": "Counts retired Instructions who experienced Instruction L1 Cache true miss. Available PDIST counters: 0", + "PublicDescription": "Counts retired Instructions who experienced Instruction L1 Cache true miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -251,7 +251,7 @@ "EventName": "FRONTEND_RETIRED.L2_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x13", - "PublicDescription": "Counts retired Instructions who experienced Instruction L2 Cache true miss. Available PDIST counters: 0", + "PublicDescription": "Counts retired Instructions who experienced Instruction L2 Cache true miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -263,7 +263,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_128", "MSRIndex": "0x3F7", "MSRValue": "0x608006", - "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -275,7 +275,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_16", "MSRIndex": "0x3F7", "MSRValue": "0x601006", - "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 16 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 16 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -287,7 +287,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_2", "MSRIndex": "0x3F7", "MSRValue": "0x600206", - "PublicDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of at least 2 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of at least 2 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -299,7 +299,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_256", "MSRIndex": "0x3F7", "MSRValue": "0x610006", - "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -311,7 +311,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_2_BUBBLES_GE_1", "MSRIndex": "0x3F7", "MSRValue": "0x100206", - "PublicDescription": "Counts retired instructions that are delivered to the back-end after the front-end had at least 1 bubble-slot for a period of 2 cycles. A bubble-slot is an empty issue-pipeline slot while there was no RAT stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after the front-end had at least 1 bubble-slot for a period of 2 cycles. A bubble-slot is an empty issue-pipeline slot while there was no RAT stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -323,7 +323,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_32", "MSRIndex": "0x3F7", "MSRValue": "0x602006", - "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 32 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 32 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -335,7 +335,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_4", "MSRIndex": "0x3F7", "MSRValue": "0x600406", - "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -347,7 +347,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_512", "MSRIndex": "0x3F7", "MSRValue": "0x620006", - "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -359,7 +359,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_64", "MSRIndex": "0x3F7", "MSRValue": "0x604006", - "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -371,7 +371,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_8", "MSRIndex": "0x3F7", "MSRValue": "0x600806", - "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 8 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 8 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -383,7 +383,7 @@ "EventName": "FRONTEND_RETIRED.MISP_ANT", "MSRIndex": "0x3F7", "MSRValue": "0x9", - "PublicDescription": "ANT retired branches that got just mispredicted Available PDIST counters: 0", + "PublicDescription": "ANT retired branches that got just mispredicted Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x2", "Unit": "cpu_core" @@ -395,7 +395,7 @@ "EventName": "FRONTEND_RETIRED.MS_FLOWS", "MSRIndex": "0x3F7", "MSRValue": "0x8", - "PublicDescription": "Counts flows delivered by the Microcode Sequencer Available PDIST counters: 0", + "PublicDescription": "Counts flows delivered by the Microcode Sequencer Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -443,7 +443,7 @@ "EventName": "FRONTEND_RETIRED.STLB_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x15", - "PublicDescription": "Counts retired Instructions that experienced STLB (2nd level TLB) true miss. Available PDIST counters: 0", + "PublicDescription": "Counts retired Instructions that experienced STLB (2nd level TLB) true miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -455,7 +455,7 @@ "EventName": "FRONTEND_RETIRED.UNKNOWN_BRANCH", "MSRIndex": "0x3F7", "MSRValue": "0x17", - "PublicDescription": "Number retired branch instructions that caused the front-end to be resteered when it finds the instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0", + "PublicDescription": "Number retired branch instructions that caused the front-end to be resteered when it finds the instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/memory.json b/tools/perf/pmu-events/arch/x86/arrowlake/memory.json index fb8d4ac69bda..1e6360347c0f 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/memory.json @@ -163,7 +163,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_1024", "MSRIndex": "0x3F6", "MSRValue": "0x400", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "53", "UMask": "0x1", "Unit": "cpu_core" @@ -176,7 +176,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_128", "MSRIndex": "0x3F6", "MSRValue": "0x80", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "1009", "UMask": "0x1", "Unit": "cpu_core" @@ -189,7 +189,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_16", "MSRIndex": "0x3F6", "MSRValue": "0x10", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "20011", "UMask": "0x1", "Unit": "cpu_core" @@ -202,7 +202,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_2048", "MSRIndex": "0x3F6", "MSRValue": "0x800", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "23", "UMask": "0x1", "Unit": "cpu_core" @@ -215,7 +215,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_256", "MSRIndex": "0x3F6", "MSRValue": "0x100", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "503", "UMask": "0x1", "Unit": "cpu_core" @@ -228,7 +228,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_32", "MSRIndex": "0x3F6", "MSRValue": "0x20", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "100007", "UMask": "0x1", "Unit": "cpu_core" @@ -241,7 +241,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_4", "MSRIndex": "0x3F6", "MSRValue": "0x4", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -254,7 +254,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_512", "MSRIndex": "0x3F6", "MSRValue": "0x200", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "101", "UMask": "0x1", "Unit": "cpu_core" @@ -267,7 +267,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_64", "MSRIndex": "0x3F6", "MSRValue": "0x40", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "2003", "UMask": "0x1", "Unit": "cpu_core" @@ -280,7 +280,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_8", "MSRIndex": "0x3F6", "MSRValue": "0x8", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "50021", "UMask": "0x1", "Unit": "cpu_core" @@ -291,7 +291,7 @@ "Data_LA": "1", "EventCode": "0xcd", "EventName": "MEM_TRANS_RETIRED.STORE_SAMPLE", - "PublicDescription": "Counts Retired memory accesses with at least 1 store operation. This PEBS event is the precisely-distributed (PDist) trigger covering all stores uops for sampling by the PEBS Store Latency Facility. The facility is described in Intel SDM Volume 3 section 19.9.8 Available PDIST counters: 0", + "PublicDescription": "Counts Retired memory accesses with at least 1 store operation. This PEBS event is the precisely-distributed (PDist) trigger covering all stores uops for sampling by the PEBS Store Latency Facility. The facility is described in Intel SDM Volume 3 section 19.9.8 Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json b/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json index 18a22368b99b..0651e2c4561e 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/pipeline.json @@ -74,13 +74,14 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.ALL_BRANCHES", - "PublicDescription": "Counts all branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts all branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "Unit": "cpu_core" }, { "BriefDescription": "Counts the total number of branch instructions retired for all branch types.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "ARL010, ARL011", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.ALL_BRANCHES", "PublicDescription": "Counts the total number of instructions in which the instruction pointer (IP) of the processor is resteered due to a branch instruction and the branch instruction successfully retires. All branch type instructions are accounted for.", @@ -101,7 +102,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND", - "PublicDescription": "Counts conditional branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x111", "Unit": "cpu_core" @@ -109,6 +110,7 @@ { "BriefDescription": "Counts the number of retired JCC (Jump on Conditional Code) branch instructions retired, includes both taken and not taken branches.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "ARL011", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND", "SampleAfterValue": "200003", @@ -120,7 +122,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND_NTAKEN", - "PublicDescription": "Counts not taken branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts not taken branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x10", "Unit": "cpu_core" @@ -139,7 +141,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND_TAKEN", - "PublicDescription": "Counts taken conditional branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x101", "Unit": "cpu_core" @@ -158,7 +160,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND_TAKEN_BWD", - "PublicDescription": "Counts taken backward conditional branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken backward conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x1", "Unit": "cpu_core" @@ -168,7 +170,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND_TAKEN_FWD", - "PublicDescription": "Counts taken forward conditional branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken forward conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x102", "Unit": "cpu_core" @@ -187,7 +189,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.FAR_BRANCH", - "PublicDescription": "Counts far branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts far branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x40", "Unit": "cpu_core" @@ -195,6 +197,7 @@ { "BriefDescription": "Counts the number of far branch instructions retired, includes far jump, far call and return, and interrupt call and return.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "ARL011", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.FAR_BRANCH", "SampleAfterValue": "200003", @@ -215,7 +218,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.INDIRECT", - "PublicDescription": "Counts near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0", + "PublicDescription": "Counts near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x80", "Unit": "cpu_core" @@ -223,6 +226,7 @@ { "BriefDescription": "Counts the number of near indirect JMP and near indirect CALL branch instructions retired.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "ARL011", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.INDIRECT", "SampleAfterValue": "200003", @@ -241,6 +245,7 @@ { "BriefDescription": "Counts the number of near indirect CALL branch instructions retired.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "ARL011", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.INDIRECT_CALL", "SampleAfterValue": "200003", @@ -270,7 +275,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_CALL", - "PublicDescription": "Counts both direct and indirect near call instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts both direct and indirect near call instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x2", "Unit": "cpu_core" @@ -278,6 +283,7 @@ { "BriefDescription": "Counts the number of near CALL branch instructions retired.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "ARL010, ARL011", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_CALL", "SampleAfterValue": "200003", @@ -298,7 +304,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_RETURN", - "PublicDescription": "Counts return instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts return instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x8", "Unit": "cpu_core" @@ -317,7 +323,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_TAKEN", - "PublicDescription": "Counts taken branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x20", "Unit": "cpu_core" @@ -325,6 +331,7 @@ { "BriefDescription": "Counts the number of near taken branch instructions retired.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "ARL011", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_TAKEN", "SampleAfterValue": "200003", @@ -372,7 +379,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.ALL_BRANCHES", - "PublicDescription": "Counts all the retired branch instructions that were mispredicted by the processor. A branch misprediction occurs when the processor incorrectly predicts the destination of the branch. When the misprediction is discovered at execution, all the instructions executed in the wrong (speculative) path must be discarded, and the processor must start fetching from the correct path. Available PDIST counters: 0", + "PublicDescription": "Counts all the retired branch instructions that were mispredicted by the processor. A branch misprediction occurs when the processor incorrectly predicts the destination of the branch. When the misprediction is discovered at execution, all the instructions executed in the wrong (speculative) path must be discarded, and the processor must start fetching from the correct path. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "Unit": "cpu_core" }, @@ -390,7 +397,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.ALL_BRANCHES_COST", - "PublicDescription": "All mispredicted branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "All mispredicted branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x44", "Unit": "cpu_core" @@ -409,7 +416,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND", - "PublicDescription": "Counts mispredicted conditional branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts mispredicted conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x111", "Unit": "cpu_core" @@ -428,7 +435,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_COST", - "PublicDescription": "Mispredicted conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x151", "Unit": "cpu_core" @@ -438,7 +445,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_NTAKEN", - "PublicDescription": "Counts the number of conditional branch instructions retired that were mispredicted and the branch direction was not taken. Available PDIST counters: 0", + "PublicDescription": "Counts the number of conditional branch instructions retired that were mispredicted and the branch direction was not taken. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x10", "Unit": "cpu_core" @@ -448,7 +455,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_NTAKEN_COST", - "PublicDescription": "Mispredicted non-taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted non-taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x50", "Unit": "cpu_core" @@ -467,7 +474,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN", - "PublicDescription": "Counts taken conditional mispredicted branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x101", "Unit": "cpu_core" @@ -486,7 +493,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN_BWD", - "PublicDescription": "Counts taken backward conditional mispredicted branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken backward conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x1", "Unit": "cpu_core" @@ -496,7 +503,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN_BWD_COST", - "PublicDescription": "number of branch instructions retired that were mispredicted and taken backward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "number of branch instructions retired that were mispredicted and taken backward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x8001", "Unit": "cpu_core" @@ -506,7 +513,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN_COST", - "PublicDescription": "Mispredicted taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x141", "Unit": "cpu_core" @@ -516,7 +523,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD", - "PublicDescription": "Counts taken forward conditional mispredicted branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken forward conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "Unit": "cpu_core" }, @@ -525,7 +532,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD_COST", - "PublicDescription": "number of branch instructions retired that were mispredicted and taken forward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "number of branch instructions retired that were mispredicted and taken forward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x8002", "Unit": "cpu_core" @@ -544,7 +551,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.INDIRECT", - "PublicDescription": "Counts miss-predicted near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0", + "PublicDescription": "Counts miss-predicted near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x80", "Unit": "cpu_core" @@ -572,7 +579,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.INDIRECT_CALL", - "PublicDescription": "Counts retired mispredicted indirect (near taken) CALL instructions, including both register and memory indirect. Available PDIST counters: 0", + "PublicDescription": "Counts retired mispredicted indirect (near taken) CALL instructions, including both register and memory indirect. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x2", "Unit": "cpu_core" @@ -591,7 +598,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.INDIRECT_CALL_COST", - "PublicDescription": "Mispredicted indirect CALL retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted indirect CALL retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x42", "Unit": "cpu_core" @@ -601,7 +608,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.INDIRECT_COST", - "PublicDescription": "Mispredicted near indirect branch instructions retired (excluding returns). This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted near indirect branch instructions retired (excluding returns). This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0xc0", "Unit": "cpu_core" @@ -620,7 +627,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.NEAR_TAKEN", - "PublicDescription": "Counts number of near branch instructions retired that were mispredicted and taken. Available PDIST counters: 0", + "PublicDescription": "Counts number of near branch instructions retired that were mispredicted and taken. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x20", "Unit": "cpu_core" @@ -639,7 +646,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.NEAR_TAKEN_COST", - "PublicDescription": "Mispredicted taken near branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted taken near branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x60", "Unit": "cpu_core" @@ -649,7 +656,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.RET", - "PublicDescription": "This is a non-precise version (that is, does not use PEBS) of the event that counts mispredicted return instructions retired. Available PDIST counters: 0", + "PublicDescription": "This is a non-precise version (that is, does not use PEBS) of the event that counts mispredicted return instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x8", "Unit": "cpu_core" @@ -677,7 +684,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.RET_COST", - "PublicDescription": "Mispredicted ret instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted ret instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x48", "Unit": "cpu_core" @@ -1046,7 +1053,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.ANY_P", - "PublicDescription": "Counts the number of X86 instructions retired - an Architectural PerfMon event. Counting continues during hardware interrupts, traps, and inside interrupt handlers. Notes: INST_RETIRED.ANY is counted by a designated fixed counter freeing up programmable counters to count other events. INST_RETIRED.ANY_P is counted by a programmable counter. Available PDIST counters: 0", + "PublicDescription": "Counts the number of X86 instructions retired - an Architectural PerfMon event. Counting continues during hardware interrupts, traps, and inside interrupt handlers. Notes: INST_RETIRED.ANY is counted by a designated fixed counter freeing up programmable counters to count other events. INST_RETIRED.ANY_P is counted by a programmable counter. Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "Unit": "cpu_core" }, @@ -1063,7 +1070,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.BR_FUSED", - "PublicDescription": "retired macro-fused uops when there is a branch in the macro-fused pair (the two instructions that got macro-fused count once in this pmon) Available PDIST counters: 0", + "PublicDescription": "retired macro-fused uops when there is a branch in the macro-fused pair (the two instructions that got macro-fused count once in this pmon) Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -1073,7 +1080,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.MACRO_FUSED", - "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0", + "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "UMask": "0x30", "Unit": "cpu_core" @@ -1083,7 +1090,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.NOP", - "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions Available PDIST counters: 0", + "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1102,7 +1109,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -1348,6 +1355,15 @@ "UMask": "0x88", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts the number of times a load got early blocked due to preceding store operation with unknown address or unknown data. Excluding in-line (immediate) wakeups", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.STORE_EARLY", + "SampleAfterValue": "100003", + "UMask": "0xa1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of occurrences a retired load gets blocked because its address partially overlaps with an older store (size mismatch) - unknown_sta/bad_forward", "Counter": "0,1,2,3,4,5,6,7", @@ -1563,7 +1579,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xe4", "EventName": "MISC_RETIRED.LBR_INSERTS", - "PublicDescription": "LBR record is inserted Available PDIST counters: 0", + "PublicDescription": "LBR record is inserted Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1929,7 +1945,7 @@ }, { "BriefDescription": "Fixed Counter: Counts the number of retirement slots not consumed due to front end stalls.", - "Counter": "37", + "Counter": "Fixed counter 5", "EventName": "TOPDOWN_FE_BOUND.ALL", "SampleAfterValue": "1000003", "UMask": "0x6", @@ -2126,7 +2142,7 @@ }, { "BriefDescription": "Fixed Counter: Counts the number of consumed retirement slots.", - "Counter": "38", + "Counter": "Fixed counter 6", "EventName": "TOPDOWN_RETIRING.ALL", "SampleAfterValue": "1000003", "UMask": "0x7", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index d0a17905c74e..12017f568606 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -1,7 +1,7 @@ Family-model,Version,Filename,EventType GenuineIntel-6-(97|9A|B7|BA|BF),v1.33,alderlake,core GenuineIntel-6-BE,v1.33,alderlaken,core -GenuineIntel-6-C[56],v1.09,arrowlake,core +GenuineIntel-6-C[56],v1.12,arrowlake,core GenuineIntel-6-(1C|26|27|35|36),v5,bonnell,core GenuineIntel-6-(3D|47),v30,broadwell,core GenuineIntel-6-56,v12,broadwellde,core From e50ae144a7b77ac2d66fd3cac9d60edd7dcd00d9 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:00 -0700 Subject: [PATCH 0849/2711] perf vendor events: Update broadwell metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/broadwell/bdw-metrics.json | 30 ++++++++--------- .../arch/x86/broadwellde/bdwde-metrics.json | 30 ++++++++--------- .../arch/x86/broadwellx/bdx-metrics.json | 33 +++++++++---------- 3 files changed, 42 insertions(+), 51 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json b/tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json index 89750117a7f6..1d8e910f5961 100644 --- a/tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json +++ b/tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -80,7 +80,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_0 + UOPS_DISPATCHED_PORT.PORT_1 + UOPS_DISPATCHED_PORT.PORT_5 + UOPS_DISPATCHED_PORT.PORT_6) / tma_info_thread_slots", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_alu_op_utilization", @@ -98,7 +97,6 @@ }, { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "1 - (tma_frontend_bound + tma_bad_speculation + tma_retiring)", "MetricGroup": "BvOB;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", @@ -139,7 +137,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU retired uops originated from CISC (complex instruction set computer) instruction", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "max(0, tma_microcode_sequencer - tma_assists)", "MetricGroup": "TopdownL4;tma_L4_group;tma_microcode_sequencer_group", "MetricName": "tma_cisc", @@ -640,7 +637,7 @@ "MetricThreshold": "tma_info_memory_tlb_page_walks_utilization > 0.5" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -653,7 +650,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -665,7 +662,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -854,7 +851,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_2 + UOPS_DISPATCHED_PORT.PORT_3 + UOPS_DISPATCHED_PORT.PORT_7 - UOPS_DISPATCHED_PORT.PORT_4) / (2 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", @@ -1032,7 +1028,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else (CYCLE_ACTIVITY.STALLS_TOTAL - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks)", + "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else CYCLE_ACTIVITY.STALLS_TOTAL - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", "MetricThreshold": "tma_ports_utilized_0 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1041,7 +1037,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else (UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", "MetricThreshold": "tma_ports_utilized_1 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1050,7 +1046,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else (UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC - UOPS_EXECUTED.CYCLES_GE_3_UOPS_EXEC) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC - UOPS_EXECUTED.CYCLES_GE_3_UOPS_EXEC) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", "MetricThreshold": "tma_ports_utilized_2 > 0.15 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", diff --git a/tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json b/tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json index 81175f0f2603..a5e408ca46a7 100644 --- a/tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json +++ b/tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -80,7 +80,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_0 + UOPS_DISPATCHED_PORT.PORT_1 + UOPS_DISPATCHED_PORT.PORT_5 + UOPS_DISPATCHED_PORT.PORT_6) / tma_info_thread_slots", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_alu_op_utilization", @@ -98,7 +97,6 @@ }, { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "1 - (tma_frontend_bound + tma_bad_speculation + tma_retiring)", "MetricGroup": "BvOB;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", @@ -139,7 +137,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU retired uops originated from CISC (complex instruction set computer) instruction", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "max(0, tma_microcode_sequencer - tma_assists)", "MetricGroup": "TopdownL4;tma_L4_group;tma_microcode_sequencer_group", "MetricName": "tma_cisc", @@ -632,7 +629,7 @@ "MetricThreshold": "tma_info_memory_tlb_page_walks_utilization > 0.5" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -645,7 +642,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -657,7 +654,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -846,7 +843,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_2 + UOPS_DISPATCHED_PORT.PORT_3 + UOPS_DISPATCHED_PORT.PORT_7 - UOPS_DISPATCHED_PORT.PORT_4) / (2 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", @@ -1021,7 +1017,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else (CYCLE_ACTIVITY.STALLS_TOTAL - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks)", + "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else CYCLE_ACTIVITY.STALLS_TOTAL - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", "MetricThreshold": "tma_ports_utilized_0 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1030,7 +1026,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else (UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", "MetricThreshold": "tma_ports_utilized_1 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1039,7 +1035,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else (UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC - UOPS_EXECUTED.CYCLES_GE_3_UOPS_EXEC) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC - UOPS_EXECUTED.CYCLES_GE_3_UOPS_EXEC) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", "MetricThreshold": "tma_ports_utilized_2 > 0.15 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", diff --git a/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json b/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json index 5d06a3f72be2..5b83b040060c 100644 --- a/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -282,7 +282,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_0 + UOPS_DISPATCHED_PORT.PORT_1 + UOPS_DISPATCHED_PORT.PORT_5 + UOPS_DISPATCHED_PORT.PORT_6) / tma_info_thread_slots", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_alu_op_utilization", @@ -300,7 +299,6 @@ }, { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "1 - (tma_frontend_bound + tma_bad_speculation + tma_retiring)", "MetricGroup": "BvOB;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", @@ -341,7 +339,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU retired uops originated from CISC (complex instruction set computer) instruction", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "max(0, tma_microcode_sequencer - tma_assists)", "MetricGroup": "TopdownL4;tma_L4_group;tma_microcode_sequencer_group", "MetricName": "tma_cisc", @@ -842,7 +839,7 @@ "MetricThreshold": "tma_info_memory_tlb_page_walks_utilization > 0.5" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -855,7 +852,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -867,7 +864,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -907,6 +904,7 @@ }, { "BriefDescription": "Average number of parallel data read requests to external memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "UNC_C_TOR_OCCUPANCY.MISS_OPCODE@filter_opc\\=0x182@ / UNC_C_TOR_OCCUPANCY.MISS_OPCODE@filter_opc\\=0x182\\,thresh\\=1@", "MetricGroup": "Mem;MemoryBW;SoC", "MetricName": "tma_info_system_mem_parallel_reads", @@ -1076,7 +1074,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_2 + UOPS_DISPATCHED_PORT.PORT_3 + UOPS_DISPATCHED_PORT.PORT_7 - UOPS_DISPATCHED_PORT.PORT_4) / (2 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", @@ -1086,6 +1083,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from local memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "200 * (MEM_LOAD_UOPS_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_UOPS_RETIRED.HIT_LFB / (MEM_LOAD_UOPS_RETIRED.L2_HIT + MEM_LOAD_UOPS_RETIRED.L3_HIT + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HITM + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_MISS + MEM_LOAD_UOPS_L3_MISS_RETIRED.LOCAL_DRAM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_DRAM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_HITM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_FWD))) / tma_info_thread_clks", "MetricGroup": "Server;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_local_mem", @@ -1263,7 +1261,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else (CYCLE_ACTIVITY.STALLS_TOTAL - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks)", + "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else CYCLE_ACTIVITY.STALLS_TOTAL - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", "MetricThreshold": "tma_ports_utilized_0 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1272,7 +1270,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else (UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", "MetricThreshold": "tma_ports_utilized_1 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1281,7 +1279,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else (UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC - UOPS_EXECUTED.CYCLES_GE_3_UOPS_EXEC) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC - UOPS_EXECUTED.CYCLES_GE_3_UOPS_EXEC) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", "MetricThreshold": "tma_ports_utilized_2 > 0.15 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1308,6 +1306,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "310 * (MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_UOPS_RETIRED.HIT_LFB / (MEM_LOAD_UOPS_RETIRED.L2_HIT + MEM_LOAD_UOPS_RETIRED.L3_HIT + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HITM + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_MISS + MEM_LOAD_UOPS_L3_MISS_RETIRED.LOCAL_DRAM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_DRAM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_HITM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_FWD))) / tma_info_thread_clks", "MetricGroup": "Server;Snoop;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_remote_mem", From 96e1aba56505e91f222ef2c9a07d71e08ea48e23 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:01 -0700 Subject: [PATCH 0850/2711] perf vendor events: Update cascadelakex metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/cascadelakex/clx-metrics.json | 143 +++++++++++++----- 1 file changed, 102 insertions(+), 41 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json b/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json index 6485b565acbc..2e50a91b6728 100644 --- a/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -319,6 +319,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_0 + UOPS_DISPATCHED_PORT.PORT_1 + UOPS_DISPATCHED_PORT.PORT_5 + UOPS_DISPATCHED_PORT.PORT_6) / tma_info_thread_slots", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_alu_op_utilization", @@ -356,6 +357,7 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch related bottlenecks by large code footprint programs (i-side cache; TLB and BTB misses)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_fetch_latency * (tma_itlb_misses + tma_icache_misses + tma_unknown_branches) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)", "MetricGroup": "BigFootprint;BvBC;Fed;Frontend;IcMiss;MemoryTLB", "MetricName": "tma_bottleneck_big_code", @@ -369,32 +371,36 @@ "MetricThreshold": "tma_bottleneck_branching_overhead > 5", "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", "MetricGroup": "BvCB;Cor;tma_issueComp", "MetricName": "tma_bottleneck_compute_bound_est", "MetricThreshold": "tma_bottleneck_compute_bound_est > 20", "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: " }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * (10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts)) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", @@ -402,6 +408,7 @@ }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * (10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts)) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", @@ -410,7 +417,8 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)))", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -418,7 +426,8 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", "MetricThreshold": "tma_bottleneck_memory_synchronization > 10", @@ -426,6 +435,7 @@ }, { "BriefDescription": "Total pipeline cost of Branch Misprediction related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * (tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Bad;BadSpec;BrMispredicts;BvMP;tma_issueBM", "MetricName": "tma_bottleneck_mispredictions", @@ -434,7 +444,8 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -442,6 +453,7 @@ }, { "BriefDescription": "Total pipeline cost of \"useful operations\" - the portion of Retiring category not covered by Branching_Overhead nor Irregular_Overhead.", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_retiring - (BR_INST_RETIRED.ALL_BRANCHES + 2 * BR_INST_RETIRED.NEAR_CALL + INST_RETIRED.NOP) / tma_info_thread_slots - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "BvUW;Ret", "MetricName": "tma_bottleneck_useful_work", @@ -469,6 +481,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU retired uops originated from CISC (complex instruction set computer) instruction", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_microcode_sequencer - tma_assists)", "MetricGroup": "TopdownL4;tma_L4_group;tma_microcode_sequencer_group", "MetricName": "tma_cisc", @@ -538,6 +551,15 @@ "PublicDescription": "This metric represents fraction of slots where Core non-memory issues were of a bottleneck. Shortage in hardware compute resources; or dependencies in software's instructions are both categorized under Core Bound. Hence it may indicate the machine ran out of an out-of-order resource; certain execution units are overloaded or dependencies in program's data- or instruction-flow are limiting the performance (e.g. FP-chained long-latency arithmetic operations).", "ScaleUnit": "100%" }, + { + "BriefDescription": "This metric roughly estimates (based on idle latencies) how often the CPU was stalled on accesses to external CXL Memory by loads (e.g", + "MetricExpr": "(((1 - ((19 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + 10 * (MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS))) / (19 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + 10 * (MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + (25 * (MEM_LOAD_RETIRED.LOCAL_PMM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) if #has_pmem > 0 else 0) + 33 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_PMM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) if #has_pmem > 0 else 0))) if #has_pmem > 0 else 1)) * (CYCLE_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks + (CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS) / tma_info_thread_clks - tma_l2_bound) if 1e6 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_PMM + MEM_LOAD_RETIRED.LOCAL_PMM) > MEM_LOAD_RETIRED.L1_MISS else 0) if #has_pmem > 0 else 0)", + "MetricGroup": "MemoryBound;Server;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", + "MetricName": "tma_cxl_mem_bound", + "MetricThreshold": "tma_cxl_mem_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", + "PublicDescription": "This metric roughly estimates (based on idle latencies) how often the CPU was stalled on accesses to external CXL Memory by loads (e.g. 3D-Xpoint (Crystal Ridge, a.k.a. IXP) memory, PMM - Persistent Memory Module [from CLX to SPR] or any other CXL Type3 Memory [EMR onwards]).", + "ScaleUnit": "100%" + }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", "MetricConstraint": "NO_GROUP_EVENTS", @@ -569,7 +591,7 @@ { "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", "MetricConstraint": "NO_GROUP_EVENTS", - "MetricExpr": "CYCLE_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks + (CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS) / tma_info_thread_clks - tma_l2_bound", + "MetricExpr": "(CYCLE_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks + (CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS) / tma_info_thread_clks - tma_l2_bound - tma_cxl_mem_bound if #has_pmem > 0 else CYCLE_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks + (CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS) / tma_info_thread_clks - tma_l2_bound)", "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_dram_bound", "MetricThreshold": "tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", @@ -630,7 +652,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%" }, { @@ -693,7 +715,6 @@ }, { "BriefDescription": "This metric approximates arithmetic floating-point (FP) vector uops fraction the CPU has retired aggregated across all vector widths", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE\\,umask\\=0xfc@ / UOPS_RETIRED.RETIRE_SLOTS", "MetricGroup": "Compute;Flops;TopdownL4;tma_L4_group;tma_fp_arith_group;tma_issue2P", "MetricName": "tma_fp_vector", @@ -768,6 +789,7 @@ }, { "BriefDescription": "Branch Misprediction Cost: Cycles representing fraction of TMA slots wasted per non-speculative branch misprediction (retired JEClear)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_bottleneck_mispredictions * tma_info_thread_slots / 4 / BR_MISP_RETIRED.ALL_BRANCHES / 100", "MetricGroup": "Bad;BrMispredicts;tma_issueBM", "MetricName": "tma_info_bad_spec_branch_misprediction_cost", @@ -803,6 +825,7 @@ }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) hits - subset of the Instruction_Fetch_BW Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound * (tma_fetch_bandwidth / (tma_fetch_bandwidth + tma_fetch_latency)) * (tma_dsb / (tma_dsb + tma_mite)))", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_botlnk_l2_dsb_bandwidth", @@ -820,6 +843,7 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -961,7 +985,6 @@ }, { "BriefDescription": "Instructions per FP Arithmetic instruction (lower number means higher occurrence rate)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "INST_RETIRED.ANY / (FP_ARITH_INST_RETIRED.SCALAR + cpu@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE\\,umask\\=0xfc@)", "MetricGroup": "Flops;InsType", "MetricName": "tma_info_inst_mix_iparith", @@ -1249,7 +1272,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1266,6 +1289,12 @@ "MetricGroup": "Fed;FetchBW", "MetricName": "tma_info_pipeline_fetch_mite" }, + { + "BriefDescription": "Average number of uops fetched from MS per cycle", + "MetricExpr": "IDQ.MS_UOPS / cpu@IDQ.MS_UOPS\\,cmask\\=1@", + "MetricGroup": "Fed;FetchLat;MicroSeq", + "MetricName": "tma_info_pipeline_fetch_ms" + }, { "BriefDescription": "Instructions per a microcode Assist invocation", "MetricExpr": "INST_RETIRED.ANY / (FP_ASSIST.ANY + OTHER_ASSISTS.ANY)", @@ -1282,7 +1311,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -1294,16 +1323,28 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, + { + "BriefDescription": "Average 3DXP Memory Bandwidth Use for reads [GB / sec]", + "MetricExpr": "(64 * UNC_M_PMM_RPQ_INSERTS / 1e9 / tma_info_system_time if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryBW;Server;SoC", + "MetricName": "tma_info_system_cxl_mem_read_bw" + }, + { + "BriefDescription": "Average 3DXP Memory Bandwidth Use for Writes [GB / sec]", + "MetricExpr": "(64 * UNC_M_PMM_WPQ_INSERTS / 1e9 / tma_info_system_time if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryBW;Server;SoC", + "MetricName": "tma_info_system_cxl_mem_write_bw" + }, { "BriefDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]", "MetricExpr": "64 * (UNC_M_CAS_COUNT.RD + UNC_M_CAS_COUNT.WR) / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1361,6 +1402,13 @@ "MetricName": "tma_info_system_mem_parallel_reads", "PublicDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches" }, + { + "BriefDescription": "Average latency of data read request to external 3D X-Point memory [in nanoseconds]", + "MetricExpr": "(1e9 * (UNC_M_PMM_RPQ_OCCUPANCY.ALL / UNC_M_PMM_RPQ_INSERTS) / imc_0@event\\=0x0@ if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryLat;Server;SoC", + "MetricName": "tma_info_system_mem_pmm_read_latency", + "PublicDescription": "Average latency of data read request to external 3D X-Point memory [in nanoseconds]. Accounts for demand loads and L1/L2 data-read prefetches" + }, { "BriefDescription": "Average latency of data read request to external memory (in nanoseconds)", "MetricExpr": "1e9 * (UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD / UNC_CHA_TOR_INSERTS.IA_MISS_DRD) / (tma_info_system_socket_clks / tma_info_system_time)", @@ -1499,12 +1547,13 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "min(2 * (MEM_INST_RETIRED.ALL_LOADS - MEM_LOAD_RETIRED.FB_HIT - MEM_LOAD_RETIRED.L1_MISS) * 20 / 100, max(CYCLE_ACTIVITY.CYCLES_MEM_ANY - CYCLE_ACTIVITY.CYCLES_L1D_MISS, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%" }, { @@ -1541,7 +1590,7 @@ "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, { @@ -1565,6 +1614,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_2 + UOPS_DISPATCHED_PORT.PORT_3 + UOPS_DISPATCHED_PORT.PORT_7 - UOPS_DISPATCHED_PORT.PORT_4) / (2 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", @@ -1591,6 +1641,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 1 GB pages for data load accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_load_stlb_miss * DTLB_LOAD_MISSES.WALK_COMPLETED_1G / (DTLB_LOAD_MISSES.WALK_COMPLETED_4K + DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M + DTLB_LOAD_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_load_stlb_miss_group", "MetricName": "tma_load_stlb_miss_1g", @@ -1599,6 +1650,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 2 or 4 MB pages for data load accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_load_stlb_miss * DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M / (DTLB_LOAD_MISSES.WALK_COMPLETED_4K + DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M + DTLB_LOAD_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_load_stlb_miss_group", "MetricName": "tma_load_stlb_miss_2m", @@ -1607,6 +1659,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 4 KB pages for data load accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_load_stlb_miss * DTLB_LOAD_MISSES.WALK_COMPLETED_4K / (DTLB_LOAD_MISSES.WALK_COMPLETED_4K + DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M + DTLB_LOAD_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_load_stlb_miss_group", "MetricName": "tma_load_stlb_miss_4k", @@ -1624,6 +1677,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(12 * max(0, MEM_INST_RETIRED.LOCK_LOADS - L2_RQSTS.ALL_RFO) + MEM_INST_RETIRED.LOCK_LOADS / MEM_INST_RETIRED.ALL_STORES * (11 * L2_RQSTS.RFO_HIT + min(CPU_CLK_UNHALTED.THREAD, OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO))) / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -1648,7 +1702,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%" }, { @@ -1657,7 +1711,7 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, { @@ -1681,7 +1735,6 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU was retiring uops fetched by the Microcode Sequencer (MS) unit", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / UOPS_ISSUED.ANY * IDQ.MS_UOPS / tma_info_thread_slots", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_heavy_operations_group;tma_issueMC;tma_issueMS", "MetricName": "tma_microcode_sequencer", @@ -1691,6 +1744,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to Branch Resteers as a result of Branch Misprediction at execution stage", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "BR_MISP_RETIRED.ALL_BRANCHES / (BR_MISP_RETIRED.ALL_BRANCHES + MACHINE_CLEARS.COUNT) * INT_MISC.CLEAR_RESTEER_CYCLES / tma_info_thread_clks", "MetricGroup": "BadSpec;BrMispredicts;BvMP;TopdownL4;tma_L4_group;tma_branch_resteers_group;tma_issueBM", "MetricName": "tma_mispredicts_resteers", @@ -1745,6 +1799,7 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_light_operations - (tma_fp_arith + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", @@ -1754,6 +1809,7 @@ }, { "BriefDescription": "This metric estimates fraction of slots the CPU was stalled due to other cases of misprediction (non-retired x86 branches or other types).", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(tma_branch_mispredicts * (1 - BR_MISP_RETIRED.ALL_BRANCHES / (INT_MISC.CLEARS_COUNT - MACHINE_CLEARS.COUNT)), 0.0001)", "MetricGroup": "BrMispredicts;BvIO;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_other_mispredicts", @@ -1762,6 +1818,7 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU has wasted due to Nukes (Machine Clears) not related to memory ordering.", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(tma_machine_clears * (1 - MACHINE_CLEARS.MEMORY_ORDERING / MACHINE_CLEARS.COUNT), 0.0001)", "MetricGroup": "BvIO;Machine_Clears;TopdownL3;tma_L3_group;tma_machine_clears_group", "MetricName": "tma_other_nukes", @@ -1842,6 +1899,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "((tma_ports_utilized_0 * tma_info_thread_clks + (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL)) / tma_info_thread_clks if ARITH.DIVIDER_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY else (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL) / tma_info_thread_clks)", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", @@ -1956,7 +2014,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%" }, { @@ -2013,6 +2071,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 1 GB pages for data store accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_store_stlb_miss * DTLB_STORE_MISSES.WALK_COMPLETED_1G / (DTLB_STORE_MISSES.WALK_COMPLETED_4K + DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M + DTLB_STORE_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_store_stlb_miss_group", "MetricName": "tma_store_stlb_miss_1g", @@ -2021,6 +2080,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 2 or 4 MB pages for data store accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_store_stlb_miss * DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M / (DTLB_STORE_MISSES.WALK_COMPLETED_4K + DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M + DTLB_STORE_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_store_stlb_miss_group", "MetricName": "tma_store_stlb_miss_2m", @@ -2029,6 +2089,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 4 KB pages for data store accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_store_stlb_miss * DTLB_STORE_MISSES.WALK_COMPLETED_4K / (DTLB_STORE_MISSES.WALK_COMPLETED_4K + DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M + DTLB_STORE_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_store_stlb_miss_group", "MetricName": "tma_store_stlb_miss_4k", From d9a6bb9e359e6f816c746fc8d6aa0999f4594a0c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:02 -0700 Subject: [PATCH 0851/2711] perf vendor events: Update emeraldrapids events/metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update events from v1.14 to v1.16. Update metrics from TMA 5.0 to 5.1. The event updates come from: https://github.com/intel/perfmon/commit/9020e49e790349f86141a1f6ef6f009f189a0f48 https://github.com/intel/perfmon/commit/a0567b56185fea4b968391aae344e9d8ed9782d8 Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/emeraldrapids/cache.json | 100 +++++------ .../arch/x86/emeraldrapids/emr-metrics.json | 135 ++++++++------ .../x86/emeraldrapids/floating-point.json | 43 ++--- .../arch/x86/emeraldrapids/frontend.json | 42 +++-- .../arch/x86/emeraldrapids/memory.json | 30 ++-- .../arch/x86/emeraldrapids/other.json | 28 ++- .../arch/x86/emeraldrapids/pipeline.json | 167 +++++++----------- .../arch/x86/emeraldrapids/uncore-memory.json | 82 +++++++++ .../x86/emeraldrapids/virtual-memory.json | 40 ++--- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 10 files changed, 365 insertions(+), 304 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json index 10bdb193c16f..e96f938587bb 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json @@ -4,7 +4,6 @@ "Counter": "0,1,2,3", "EventCode": "0x51", "EventName": "L1D.HWPF_MISS", - "PublicDescription": "L1D.HWPF_MISS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -13,7 +12,7 @@ "Counter": "0,1,2,3", "EventCode": "0x51", "EventName": "L1D.REPLACEMENT", - "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace. Available PDIST counters: 0", + "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -22,7 +21,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.FB_FULL", - "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -33,7 +32,7 @@ "EdgeDetect": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.FB_FULL_PERIODS", - "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -43,7 +42,6 @@ "Deprecated": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.L2_STALL", - "PublicDescription": "This event is deprecated. Refer to new event L1D_PEND_MISS.L2_STALLS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -52,7 +50,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.L2_STALLS", - "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -61,7 +59,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.PENDING", - "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type. Available PDIST counters: 0", + "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -71,7 +69,7 @@ "CounterMask": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.PENDING_CYCLES", - "PublicDescription": "Counts duration of L1D miss outstanding in cycles. Available PDIST counters: 0", + "PublicDescription": "Counts duration of L1D miss outstanding in cycles.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -80,7 +78,7 @@ "Counter": "0,1,2,3", "EventCode": "0x25", "EventName": "L2_LINES_IN.ALL", - "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects. Available PDIST counters: 0", + "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects.", "SampleAfterValue": "100003", "UMask": "0x1f" }, @@ -89,7 +87,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.NON_SILENT", - "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3 Available PDIST counters: 0", + "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3", "SampleAfterValue": "200003", "UMask": "0x2" }, @@ -98,7 +96,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.SILENT", - "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event. Available PDIST counters: 0", + "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event.", "SampleAfterValue": "200003", "UMask": "0x1" }, @@ -107,7 +105,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.USELESS_HWPF", - "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache Available PDIST counters: 0", + "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache", "SampleAfterValue": "200003", "UMask": "0x4" }, @@ -116,7 +114,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.ALL", - "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES]", "SampleAfterValue": "200003", "UMask": "0xff" }, @@ -125,7 +123,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.MISS", - "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS] Available PDIST counters: 0", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS]", "SampleAfterValue": "200003", "UMask": "0x3f" }, @@ -134,7 +132,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_CODE_RD", - "PublicDescription": "Counts the total number of L2 code requests. Available PDIST counters: 0", + "PublicDescription": "Counts the total number of L2 code requests.", "SampleAfterValue": "200003", "UMask": "0xe4" }, @@ -143,7 +141,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_DATA_RD", - "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once. Available PDIST counters: 0", + "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once.", "SampleAfterValue": "200003", "UMask": "0xe1" }, @@ -152,7 +150,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_MISS", - "PublicDescription": "Counts demand requests that miss L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts demand requests that miss L2 cache.", "SampleAfterValue": "200003", "UMask": "0x27" }, @@ -161,7 +159,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_REFERENCES", - "PublicDescription": "Counts demand requests to L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts demand requests to L2 cache.", "SampleAfterValue": "200003", "UMask": "0xe7" }, @@ -170,7 +168,6 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_HWPF", - "PublicDescription": "L2_RQSTS.ALL_HWPF Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0xf0" }, @@ -179,7 +176,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_RFO", - "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches. Available PDIST counters: 0", + "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches.", "SampleAfterValue": "200003", "UMask": "0xe2" }, @@ -188,7 +185,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.CODE_RD_HIT", - "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads. Available PDIST counters: 0", + "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads.", "SampleAfterValue": "200003", "UMask": "0xc4" }, @@ -197,7 +194,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.CODE_RD_MISS", - "PublicDescription": "Counts L2 cache misses when fetching instructions. Available PDIST counters: 0", + "PublicDescription": "Counts L2 cache misses when fetching instructions.", "SampleAfterValue": "200003", "UMask": "0x24" }, @@ -206,7 +203,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.DEMAND_DATA_RD_HIT", - "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache.", "SampleAfterValue": "200003", "UMask": "0xc1" }, @@ -215,7 +212,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS", - "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once. Available PDIST counters: 0", + "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once.", "SampleAfterValue": "200003", "UMask": "0x21" }, @@ -224,7 +221,6 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.HWPF_MISS", - "PublicDescription": "L2_RQSTS.HWPF_MISS Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x30" }, @@ -233,7 +229,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.MISS", - "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS] Available PDIST counters: 0", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS]", "SampleAfterValue": "200003", "UMask": "0x3f" }, @@ -242,7 +238,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.REFERENCES", - "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL]", "SampleAfterValue": "200003", "UMask": "0xff" }, @@ -251,7 +247,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.RFO_HIT", - "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache.", "SampleAfterValue": "200003", "UMask": "0xc2" }, @@ -260,7 +256,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.RFO_MISS", - "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache.", "SampleAfterValue": "200003", "UMask": "0x22" }, @@ -269,7 +265,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.SWPF_HIT", - "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full. Available PDIST counters: 0", + "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full.", "SampleAfterValue": "200003", "UMask": "0xc8" }, @@ -278,7 +274,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.SWPF_MISS", - "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full. Available PDIST counters: 0", + "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full.", "SampleAfterValue": "200003", "UMask": "0x28" }, @@ -287,7 +283,7 @@ "Counter": "0,1,2,3", "EventCode": "0x23", "EventName": "L2_TRANS.L2_WB", - "PublicDescription": "Counts L2 writebacks that access L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts L2 writebacks that access L2 cache.", "SampleAfterValue": "200003", "UMask": "0x40" }, @@ -296,7 +292,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.MISS", - "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3. Available PDIST counters: 0", + "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", "SampleAfterValue": "100003", "UMask": "0x41" }, @@ -305,7 +301,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.REFERENCE", - "PublicDescription": "Counts core-originated cacheable requests to the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3. Available PDIST counters: 0", + "PublicDescription": "Counts core-originated cacheable requests to the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", "SampleAfterValue": "100003", "UMask": "0x4f" }, @@ -394,7 +390,7 @@ "Counter": "0,1,2,3", "EventCode": "0x43", "EventName": "MEM_LOAD_COMPLETED.L1_MISS_ANY", - "PublicDescription": "Number of completed demand load requests that missed the L1 data cache including shadow misses (FB hits, merge to an ongoing L1D miss) Available PDIST counters: 0", + "PublicDescription": "Number of completed demand load requests that missed the L1 data cache including shadow misses (FB hits, merge to an ongoing L1D miss)", "SampleAfterValue": "1000003", "UMask": "0xfd" }, @@ -563,7 +559,6 @@ "Counter": "0,1,2,3", "EventCode": "0x44", "EventName": "MEM_STORE_RETIRED.L2_HIT", - "PublicDescription": "MEM_STORE_RETIRED.L2_HIT Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x1" }, @@ -572,7 +567,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe5", "EventName": "MEM_UOP_RETIRED.ANY", - "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses Available PDIST counters: 0", + "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -999,7 +994,6 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.ALL_REQUESTS", - "PublicDescription": "OFFCORE_REQUESTS.ALL_REQUESTS Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -1008,7 +1002,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DATA_RD", - "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type. Available PDIST counters: 0", + "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -1017,7 +1011,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_CODE_RD", - "PublicDescription": "Counts both cacheable and non-cacheable code read requests. Available PDIST counters: 0", + "PublicDescription": "Counts both cacheable and non-cacheable code read requests.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -1026,7 +1020,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_DATA_RD", - "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore. Available PDIST counters: 0", + "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -1035,7 +1029,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_RFO", - "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM. Available PDIST counters: 0", + "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -1045,7 +1039,6 @@ "Deprecated": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD", - "PublicDescription": "This event is deprecated. Refer to new event OFFCORE_REQUESTS_OUTSTANDING.DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -1055,7 +1048,6 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD", - "PublicDescription": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -1065,7 +1057,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_CODE_RD", - "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1075,7 +1067,6 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", - "PublicDescription": "Cycles where at least 1 outstanding demand data read request is pending. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1085,7 +1076,6 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO", - "PublicDescription": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -1094,7 +1084,6 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD", - "PublicDescription": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -1103,7 +1092,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_CODE_RD", - "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1112,7 +1101,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD", - "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor. Available PDIST counters: 0", + "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -1121,7 +1110,7 @@ "Counter": "0,1,2,3", "EventCode": "0x2c", "EventName": "SQ_MISC.BUS_LOCK", - "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory. Available PDIST counters: 0", + "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -1130,7 +1119,6 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.ANY", - "PublicDescription": "Counts the number of PREFETCHNTA, PREFETCHW, PREFETCHT0, PREFETCHT1 or PREFETCHT2 instructions executed. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0xf" }, @@ -1139,7 +1127,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.NTA", - "PublicDescription": "Counts the number of PREFETCHNTA instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHNTA instructions executed.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -1148,7 +1136,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.PREFETCHW", - "PublicDescription": "Counts the number of PREFETCHW instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHW instructions executed.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -1157,7 +1145,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.T0", - "PublicDescription": "Counts the number of PREFETCHT0 instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHT0 instructions executed.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -1166,7 +1154,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.T1_T2", - "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed.", "SampleAfterValue": "100003", "UMask": "0x4" } diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json index 34e1cbcd722c..af0a7dd81e93 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json @@ -1,28 +1,28 @@ [ { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" @@ -78,6 +78,12 @@ "MetricName": "io_bandwidth_read", "ScaleUnit": "1MB/s" }, + { + "BriefDescription": "Bandwidth of inbound IO reads that are initiated by end device controllers that are requesting memory from the CPU and miss the L3 cache", + "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_MISS_PCIRDCUR * 64 / 1e6 / duration_time", + "MetricName": "io_bandwidth_read_l3_miss", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Bandwidth of IO reads that are initiated by end device controllers that are requesting memory from the local CPU socket", "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_LOCAL * 64 / 1e6 / duration_time", @@ -96,6 +102,12 @@ "MetricName": "io_bandwidth_write", "ScaleUnit": "1MB/s" }, + { + "BriefDescription": "Bandwidth of inbound IO writes that are initiated by end device controllers that are writing memory to the CPU", + "MetricExpr": "(UNC_CHA_TOR_INSERTS.IO_MISS_ITOM + UNC_CHA_TOR_INSERTS.IO_MISS_ITOMCACHENEAR) * 64 / 1e6 / duration_time", + "MetricName": "io_bandwidth_write_l3_miss", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Bandwidth of IO writes that are initiated by end device controllers that are writing memory to the local CPU socket", "MetricExpr": "(UNC_CHA_TOR_INSERTS.IO_ITOM_LOCAL + UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR_LOCAL) * 64 / 1e6 / duration_time", @@ -111,19 +123,19 @@ { "BriefDescription": "Percentage of inbound full cacheline writes initiated by end device controllers that miss the L3 cache", "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_MISS_ITOM / UNC_CHA_TOR_INSERTS.IO_ITOM", - "MetricName": "io_percent_of_inbound_full_writes_that_miss_l3", + "MetricName": "io_full_write_l3_miss", "ScaleUnit": "100%" }, { "BriefDescription": "Percentage of inbound partial cacheline writes initiated by end device controllers that miss the L3 cache", "MetricExpr": "(UNC_CHA_TOR_INSERTS.IO_MISS_ITOMCACHENEAR + UNC_CHA_TOR_INSERTS.IO_MISS_RFO) / (UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR + UNC_CHA_TOR_INSERTS.IO_RFO)", - "MetricName": "io_percent_of_inbound_partial_writes_that_miss_l3", + "MetricName": "io_partial_write_l3_miss", "ScaleUnit": "100%" }, { "BriefDescription": "Percentage of inbound reads initiated by end device controllers that miss the L3 cache", "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_MISS_PCIRDCUR / UNC_CHA_TOR_INSERTS.IO_PCIRDCUR", - "MetricName": "io_percent_of_inbound_reads_that_miss_l3", + "MetricName": "io_read_l3_miss", "ScaleUnit": "100%" }, { @@ -335,7 +347,7 @@ { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BvOB;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", "MetricThreshold": "tma_backend_bound > 0.2", @@ -369,22 +381,6 @@ "MetricThreshold": "tma_bottleneck_branching_overhead > 5", "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * tma_amx_busy / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", @@ -393,16 +389,32 @@ "MetricThreshold": "tma_bottleneck_compute_bound_est > 20", "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: " }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + 0 / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + 0 / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20" }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * ((1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + RS.EMPTY_RESOURCE / tma_info_thread_clks * tma_ports_utilized_0) / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricExpr": "100 * ((1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + RS.EMPTY_RESOURCE / tma_info_thread_clks * tma_ports_utilized_0) / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -434,7 +446,7 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -450,7 +462,7 @@ { "BriefDescription": "This metric represents fraction of slots the CPU has wasted due to Branch Misprediction", "DefaultMetricgroupName": "TopdownL2", - "MetricExpr": "topdown\\-br\\-mispredict / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-br\\-mispredict / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BadSpec;BrMispredicts;BvMP;Default;TmaL2;TopdownL2;tma_L2_group;tma_bad_speculation_group;tma_issueBM", "MetricName": "tma_branch_mispredicts", "MetricThreshold": "tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15", @@ -551,7 +563,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(76.6 * tma_info_system_core_frequency * (MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD * (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM / (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM + OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD))) + 74.6 * tma_info_system_core_frequency * MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;DataSharing;LockCont;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_contested_accesses", @@ -658,7 +669,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%" }, { @@ -786,7 +797,7 @@ { "BriefDescription": "This metric represents fraction of slots where the CPU was retiring heavy-weight operations -- instructions that require two or more uops or micro-coded sequences", "DefaultMetricgroupName": "TopdownL2", - "MetricExpr": "topdown\\-heavy\\-ops / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-heavy\\-ops / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "Default;Retire;TmaL2;TopdownL2;tma_L2_group;tma_retiring_group", "MetricName": "tma_heavy_operations", "MetricThreshold": "tma_heavy_operations > 0.1", @@ -1297,19 +1308,19 @@ { "BriefDescription": "Off-core accesses per kilo instruction for modified write requests", "MetricExpr": "1e3 * OCR.MODIFIED_WRITE.ANY_RESPONSE / tma_info_inst_mix_instructions", - "MetricGroup": "Offcore", + "MetricGroup": "Offcore;Server", "MetricName": "tma_info_memory_mix_offcore_mwrite_any_pki" }, { "BriefDescription": "Off-core accesses per kilo instruction for reads-to-core requests (speculative; including in-core HW prefetches)", "MetricExpr": "1e3 * OCR.READS_TO_CORE.ANY_RESPONSE / tma_info_inst_mix_instructions", - "MetricGroup": "CacheHits;Offcore", + "MetricGroup": "CacheHits;Offcore;Server", "MetricName": "tma_info_memory_mix_offcore_read_any_pki" }, { "BriefDescription": "L3 cache misses per kilo instruction for reads-to-core requests (speculative; including in-core HW prefetches)", "MetricExpr": "1e3 * OCR.READS_TO_CORE.L3_MISS / tma_info_inst_mix_instructions", - "MetricGroup": "Offcore", + "MetricGroup": "Offcore;Server", "MetricName": "tma_info_memory_mix_offcore_read_l3m_pki" }, { @@ -1335,21 +1346,21 @@ { "BriefDescription": "Average DRAM BW for Reads-to-Core (R2C) covering for memory attached to local- and remote-socket", "MetricExpr": "64 * OCR.READS_TO_CORE.DRAM / 1e9 / tma_info_system_time", - "MetricGroup": "HPC;Mem;MemoryBW;SoC", + "MetricGroup": "HPC;Mem;MemoryBW;Offcore;Server", "MetricName": "tma_info_memory_soc_r2c_dram_bw", "PublicDescription": "Average DRAM BW for Reads-to-Core (R2C) covering for memory attached to local- and remote-socket. See R2C_Offcore_BW." }, { "BriefDescription": "Average L3-cache miss BW for Reads-to-Core (R2C)", "MetricExpr": "64 * OCR.READS_TO_CORE.L3_MISS / 1e9 / tma_info_system_time", - "MetricGroup": "HPC;Mem;MemoryBW;SoC", + "MetricGroup": "HPC;Mem;MemoryBW;Offcore;Server", "MetricName": "tma_info_memory_soc_r2c_l3m_bw", "PublicDescription": "Average L3-cache miss BW for Reads-to-Core (R2C). This covering going to DRAM or other memory off-chip memory tears. See R2C_Offcore_BW." }, { "BriefDescription": "Average Off-core access BW for Reads-to-Core (R2C)", "MetricExpr": "64 * OCR.READS_TO_CORE.ANY_RESPONSE / 1e9 / tma_info_system_time", - "MetricGroup": "HPC;Mem;MemoryBW;SoC", + "MetricGroup": "HPC;Mem;MemoryBW;Offcore;Server", "MetricName": "tma_info_memory_soc_r2c_offcore_bw", "PublicDescription": "Average Off-core access BW for Reads-to-Core (R2C). R2C account for demand or prefetch load/RFO/code access that fill data into the Core caches." }, @@ -1379,7 +1390,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1426,7 +1437,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -1438,16 +1449,28 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, + { + "BriefDescription": "Average 3DXP Memory Bandwidth Use for reads [GB / sec]", + "MetricExpr": "(64 * UNC_M_PMM_RPQ_INSERTS / 1e9 / tma_info_system_time if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryBW;Server;SoC", + "MetricName": "tma_info_system_cxl_mem_read_bw" + }, + { + "BriefDescription": "Average 3DXP Memory Bandwidth Use for Writes [GB / sec]", + "MetricExpr": "(64 * UNC_M_PMM_WPQ_INSERTS / 1e9 / tma_info_system_time if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryBW;Server;SoC", + "MetricName": "tma_info_system_cxl_mem_write_bw" + }, { "BriefDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]", "MetricExpr": "64 * (UNC_M_CAS_COUNT.RD + UNC_M_CAS_COUNT.WR) / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1513,7 +1536,6 @@ }, { "BriefDescription": "Average latency of data read request to external memory (in nanoseconds)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "1e9 * (UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD / UNC_CHA_TOR_INSERTS.IA_MISS_DRD) / (tma_info_system_socket_clks / tma_info_system_time)", "MetricGroup": "Mem;MemoryLat;SoC", "MetricName": "tma_info_system_mem_read_latency", @@ -1674,12 +1696,12 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", "MetricExpr": "min(2 * (MEM_INST_RETIRED.ALL_LOADS - MEM_LOAD_RETIRED.FB_HIT - MEM_LOAD_RETIRED.L1_MISS) * 20 / 100, max(CYCLE_ACTIVITY.CYCLES_MEM_ANY - MEMORY_ACTIVITY.CYCLES_L1D_MISS, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%" }, { @@ -1693,7 +1715,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles with demand load accesses that hit the L2 cache under unloaded scenarios (possibly L2 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "4.4 * tma_info_system_core_frequency * MEM_LOAD_RETIRED.L2_HIT * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "MemoryLat;TopdownL4;tma_L4_group;tma_l2_bound_group", "MetricName": "tma_l2_hit_latency", @@ -1712,12 +1733,11 @@ }, { "BriefDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "32.6 * tma_info_system_core_frequency * (MEM_LOAD_RETIRED.L3_HIT * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, { @@ -1800,6 +1820,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(16 * max(0, MEM_INST_RETIRED.LOCK_LOADS - L2_RQSTS.ALL_RFO) + MEM_INST_RETIRED.LOCK_LOADS / MEM_INST_RETIRED.ALL_STORES * (10 * L2_RQSTS.RFO_HIT + min(CPU_CLK_UNHALTED.THREAD, OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO))) / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -1832,7 +1853,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%" }, { @@ -1841,13 +1862,13 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, { "BriefDescription": "This metric represents fraction of slots the Memory subsystem within the Backend was a bottleneck", "DefaultMetricgroupName": "TopdownL2", - "MetricExpr": "topdown\\-mem\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-mem\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "Backend;Default;TmaL2;TopdownL2;tma_L2_group;tma_backend_bound_group", "MetricName": "tma_memory_bound", "MetricThreshold": "tma_memory_bound > 0.2 & tma_backend_bound > 0.2", @@ -1857,7 +1878,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to LFENCE Instructions.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * MISC2_RETIRED.LFENCE / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_memory_fence", @@ -1910,7 +1930,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "max(IDQ.MS_CYCLES_ANY, cpu@UOPS_RETIRED.MS\\,cmask\\=1@ / (UOPS_RETIRED.SLOTS / UOPS_ISSUED.ANY)) / tma_info_core_core_clks / 2", + "MetricExpr": "max(IDQ.MS_CYCLES_ANY, cpu@UOPS_RETIRED.MS\\,cmask\\=1@ / (UOPS_RETIRED.SLOTS / UOPS_ISSUED.ANY)) / tma_info_core_core_clks / 2.4", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -1945,6 +1965,7 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_light_operations - (tma_fp_arith + tma_int_operations + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", @@ -2006,6 +2027,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "((tma_ports_utilized_0 * tma_info_thread_clks + (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_3_PORTS_UTIL)) / tma_info_thread_clks if ARITH.DIV_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - EXE_ACTIVITY.BOUND_ON_LOADS else (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_3_PORTS_UTIL) / tma_info_thread_clks)", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", @@ -2015,6 +2037,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "(EXE_ACTIVITY.EXE_BOUND_0_PORTS + max(RS.EMPTY_RESOURCE - RESOURCE_STALLS.SCOREBOARD, 0)) / tma_info_thread_clks * (CYCLE_ACTIVITY.STALLS_TOTAL - EXE_ACTIVITY.BOUND_ON_LOADS) / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", @@ -2024,6 +2047,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "EXE_ACTIVITY.1_PORTS_UTIL / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", @@ -2033,7 +2057,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "EXE_ACTIVITY.2_PORTS_UTIL / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", @@ -2043,7 +2066,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 3 or more uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "UOPS_EXECUTED.CYCLES_GE_3 / tma_info_thread_clks", "MetricGroup": "BvCB;PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_3m", @@ -2072,7 +2094,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -2100,7 +2122,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to PAUSE Instructions", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "CPU_CLK_UNHALTED.PAUSE / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_slow_pause", @@ -2132,7 +2153,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%" }, { diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/floating-point.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/floating-point.json index 8c9207750c82..bc475e163227 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/floating-point.json @@ -5,7 +5,6 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.FPDIV_ACTIVE", - "PublicDescription": "ARITH.FPDIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -14,7 +13,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.FP", - "PublicDescription": "Counts all microcode Floating Point assists. Available PDIST counters: 0", + "PublicDescription": "Counts all microcode Floating Point assists.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -23,7 +22,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.SSE_AVX_MIX", - "PublicDescription": "ASSISTS.SSE_AVX_MIX Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -32,7 +30,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_0", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -41,7 +38,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_1", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -50,7 +46,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_5", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -59,7 +54,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V0", - "PublicDescription": "FP_ARITH_DISPATCHED.V0 [This event is alias to FP_ARITH_DISPATCHED.PORT_0] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -68,7 +62,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V1", - "PublicDescription": "FP_ARITH_DISPATCHED.V1 [This event is alias to FP_ARITH_DISPATCHED.PORT_1] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -77,7 +70,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V2", - "PublicDescription": "FP_ARITH_DISPATCHED.V2 [This event is alias to FP_ARITH_DISPATCHED.PORT_5] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -86,7 +78,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -95,7 +87,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -104,7 +96,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -113,7 +105,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -122,7 +114,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.4_FLOPS", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x18" }, @@ -131,7 +123,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x40" }, @@ -140,7 +132,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -149,7 +141,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.8_FLOPS", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision and 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision and double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RSQRT14 RCP RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision and 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision and double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RSQRT14 RCP RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x60" }, @@ -158,7 +150,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR", - "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -167,7 +159,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -176,7 +168,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_SINGLE", - "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -185,7 +177,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.VECTOR", - "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "1000003", "UMask": "0xfc" }, @@ -194,7 +186,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.128B_PACKED_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.128B_PACKED_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -203,7 +194,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.256B_PACKED_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.256B_PACKED_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -212,7 +202,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.512B_PACKED_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.512B_PACKED_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -221,7 +210,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.COMPLEX_SCALAR_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.COMPLEX_SCALAR_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -230,7 +218,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.SCALAR", - "PublicDescription": "FP_ARITH_INST_RETIRED2.SCALAR Available PDIST counters: 0", + "PublicDescription": "FP_ARITH_INST_RETIRED2.SCALAR", "SampleAfterValue": "100003", "UMask": "0x3" }, @@ -239,7 +227,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.SCALAR_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.SCALAR_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -248,7 +235,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.VECTOR", - "PublicDescription": "FP_ARITH_INST_RETIRED2.VECTOR Available PDIST counters: 0", + "PublicDescription": "FP_ARITH_INST_RETIRED2.VECTOR", "SampleAfterValue": "100003", "UMask": "0x1c" } diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/frontend.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/frontend.json index 9fe9d62b867a..793c486ffabe 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/frontend.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/frontend.json @@ -4,7 +4,7 @@ "Counter": "0,1,2,3", "EventCode": "0x60", "EventName": "BACLEARS.ANY", - "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0", + "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -13,7 +13,7 @@ "Counter": "0,1,2,3", "EventCode": "0x87", "EventName": "DECODE.LCP", - "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk. Available PDIST counters: 0", + "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk.", "SampleAfterValue": "500009", "UMask": "0x1" }, @@ -22,7 +22,6 @@ "Counter": "0,1,2,3", "EventCode": "0x87", "EventName": "DECODE.MS_BUSY", - "PublicDescription": "Cycles the Microcode Sequencer is busy. Available PDIST counters: 0", "SampleAfterValue": "500009", "UMask": "0x2" }, @@ -31,7 +30,7 @@ "Counter": "0,1,2,3", "EventCode": "0x61", "EventName": "DSB2MITE_SWITCHES.PENALTY_CYCLES", - "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE. Available PDIST counters: 0", + "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -249,7 +248,7 @@ "Counter": "0,1,2,3", "EventCode": "0x80", "EventName": "ICACHE_DATA.STALLS", - "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity.", "SampleAfterValue": "500009", "UMask": "0x4" }, @@ -260,7 +259,6 @@ "EdgeDetect": "1", "EventCode": "0x80", "EventName": "ICACHE_DATA.STALL_PERIODS", - "PublicDescription": "ICACHE_DATA.STALL_PERIODS Available PDIST counters: 0", "SampleAfterValue": "500009", "UMask": "0x4" }, @@ -269,7 +267,7 @@ "Counter": "0,1,2,3", "EventCode": "0x83", "EventName": "ICACHE_TAG.STALLS", - "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss.", "SampleAfterValue": "200003", "UMask": "0x4" }, @@ -279,7 +277,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_ANY", - "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -289,7 +287,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ. Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -298,7 +296,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.DSB_UOPS", - "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -308,7 +306,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.MITE_CYCLES_ANY", - "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -318,7 +316,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.MITE_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -327,7 +325,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.MITE_UOPS", - "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -337,7 +335,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.MS_CYCLES_ANY", - "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE.", "SampleAfterValue": "2000003", "UMask": "0x20" }, @@ -348,7 +346,7 @@ "EdgeDetect": "1", "EventCode": "0x79", "EventName": "IDQ.MS_SWITCHES", - "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer. Available PDIST counters: 0", + "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -357,7 +355,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.MS_UOPS", - "PublicDescription": "Counts the total number of uops delivered by the Microcode Sequencer (MS). Available PDIST counters: 0", + "PublicDescription": "Counts the total number of uops delivered by the Microcode Sequencer (MS).", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -366,7 +364,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CORE", - "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -376,7 +374,7 @@ "CounterMask": "6", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE", - "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -387,7 +385,7 @@ "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CYCLES_FE_WAS_OK", "Invert": "1", - "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -396,7 +394,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CORE", - "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -406,7 +404,7 @@ "CounterMask": "6", "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE", - "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -417,7 +415,7 @@ "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK", "Invert": "1", - "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK]", "SampleAfterValue": "1000003", "UMask": "0x1" } diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/memory.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/memory.json index 7c3f9b76d367..5e6c1f05c981 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/memory.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/memory.json @@ -5,7 +5,6 @@ "CounterMask": "6", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L3_MISS", - "PublicDescription": "Execution stalls while L3 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x6" }, @@ -14,7 +13,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", - "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture Available PDIST counters: 0", + "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -24,7 +23,6 @@ "CounterMask": "2", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.CYCLES_L1D_MISS", - "PublicDescription": "Cycles while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -34,7 +32,6 @@ "CounterMask": "3", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L1D_MISS", - "PublicDescription": "Execution stalls while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -44,7 +41,7 @@ "CounterMask": "5", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L2_MISS", - "PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock). Available PDIST counters: 0", + "PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).", "SampleAfterValue": "1000003", "UMask": "0x5" }, @@ -54,7 +51,7 @@ "CounterMask": "9", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L3_MISS", - "PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock). Available PDIST counters: 0", + "PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).", "SampleAfterValue": "1000003", "UMask": "0x9" }, @@ -478,7 +475,6 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "Counts demand data read requests that miss the L3 cache. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -487,7 +483,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache. Available PDIST counters: 0", + "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -505,7 +501,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_EVENTS", - "PublicDescription": "Counts the number of times an RTM execution aborted due to none of the previous 3 categories (e.g. interrupt). Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to none of the previous 3 categories (e.g. interrupt).", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -514,7 +510,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_MEM", - "PublicDescription": "Counts the number of times an RTM execution aborted due to various memory events (e.g. read/write capacity and conflicts). Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to various memory events (e.g. read/write capacity and conflicts).", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -523,7 +519,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_MEMTYPE", - "PublicDescription": "Counts the number of times an RTM execution aborted due to incompatible memory type. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to incompatible memory type.", "SampleAfterValue": "100003", "UMask": "0x40" }, @@ -532,7 +528,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_UNFRIENDLY", - "PublicDescription": "Counts the number of times an RTM execution aborted due to HLE-unfriendly instructions. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to HLE-unfriendly instructions.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -541,7 +537,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.COMMIT", - "PublicDescription": "Counts the number of times RTM commit succeeded. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times RTM commit succeeded.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -550,7 +546,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.START", - "PublicDescription": "Counts the number of times we entered an RTM region. Does not count nested transactions. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times we entered an RTM region. Does not count nested transactions.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -559,7 +555,7 @@ "Counter": "0,1,2,3", "EventCode": "0x54", "EventName": "TX_MEM.ABORT_CAPACITY_READ", - "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional reads Available PDIST counters: 0", + "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional reads", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -568,7 +564,7 @@ "Counter": "0,1,2,3", "EventCode": "0x54", "EventName": "TX_MEM.ABORT_CAPACITY_WRITE", - "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional writes. Available PDIST counters: 0", + "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional writes.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -577,7 +573,7 @@ "Counter": "0,1,2,3", "EventCode": "0x54", "EventName": "TX_MEM.ABORT_CONFLICT", - "PublicDescription": "Counts the number of times a TSX line had a cache conflict. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times a TSX line had a cache conflict.", "SampleAfterValue": "100003", "UMask": "0x1" } diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/other.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/other.json index a58d65556609..21f49f609ed4 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/other.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/other.json @@ -4,10 +4,34 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.PAGE_FAULT", - "PublicDescription": "ASSISTS.PAGE_FAULT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, + { + "BriefDescription": "HW_INTERRUPTS.MASKED", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.MASKED", + "SampleAfterValue": "100003", + "UMask": "0x2" + }, + { + "BriefDescription": "HW_INTERRUPTS.PENDING_AND_MASKED", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.PENDING_AND_MASKED", + "SampleAfterValue": "100003", + "UMask": "0x4" + }, + { + "BriefDescription": "Number of hardware interrupts received by the processor.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.RECEIVED", + "PublicDescription": "Counts the number of hardware interruptions received by the processor.", + "SampleAfterValue": "203", + "UMask": "0x1" + }, { "BriefDescription": "Counts streaming stores that have any type of response.", "Counter": "0,1,2,3", @@ -25,7 +49,7 @@ "CounterMask": "1", "EventCode": "0x2d", "EventName": "XQ.FULL_CYCLES", - "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache). Available PDIST counters: 0", + "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache).", "SampleAfterValue": "1000003", "UMask": "0x1" } diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json index 48bec483b49a..1fa7957956df 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json @@ -6,7 +6,6 @@ "Deprecated": "1", "EventCode": "0xb0", "EventName": "ARITH.DIVIDER_ACTIVE", - "PublicDescription": "This event is deprecated. Refer to new event ARITH.DIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x9" }, @@ -16,7 +15,7 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.DIV_ACTIVE", - "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations.", "SampleAfterValue": "1000003", "UMask": "0x9" }, @@ -27,7 +26,6 @@ "Deprecated": "1", "EventCode": "0xb0", "EventName": "ARITH.FP_DIVIDER_ACTIVE", - "PublicDescription": "This event is deprecated. Refer to new event ARITH.FPDIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -37,7 +35,6 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.IDIV_ACTIVE", - "PublicDescription": "This event counts the cycles the integer divider is busy. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -48,7 +45,6 @@ "Deprecated": "1", "EventCode": "0xb0", "EventName": "ARITH.INT_DIVIDER_ACTIVE", - "PublicDescription": "This event is deprecated. Refer to new event ARITH.IDIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -57,7 +53,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.ANY", - "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists. Available PDIST counters: 0", + "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists.", "SampleAfterValue": "100003", "UMask": "0x1b" }, @@ -217,7 +213,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C01", - "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -226,7 +222,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C02", - "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", "SampleAfterValue": "2000003", "UMask": "0x20" }, @@ -235,7 +231,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C0_WAIT", - "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction.", "SampleAfterValue": "2000003", "UMask": "0x70" }, @@ -244,7 +240,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.DISTRIBUTED", - "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread. Available PDIST counters: 0", + "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -253,7 +249,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE", - "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted. Available PDIST counters: 0", + "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted.", "SampleAfterValue": "25003", "UMask": "0x2" }, @@ -262,7 +258,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.PAUSE", - "PublicDescription": "CPU_CLK_UNHALTED.PAUSE Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x40" }, @@ -273,7 +268,6 @@ "EdgeDetect": "1", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.PAUSE_INST", - "PublicDescription": "CPU_CLK_UNHALTED.PAUSE_INST Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x40" }, @@ -282,7 +276,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_DISTRIBUTED", - "PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread. Available PDIST counters: 0", + "PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -299,7 +293,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_TSC_P", - "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case. Available PDIST counters: 0", + "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -316,7 +310,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.THREAD_P", - "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time. Available PDIST counters: 0", + "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time.", "SampleAfterValue": "2000003" }, { @@ -325,7 +319,6 @@ "CounterMask": "8", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L1D_MISS", - "PublicDescription": "Cycles while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -335,7 +328,6 @@ "CounterMask": "1", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L2_MISS", - "PublicDescription": "Cycles while L2 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -345,7 +337,6 @@ "CounterMask": "16", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_MEM_ANY", - "PublicDescription": "Cycles while memory subsystem has an outstanding load. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -355,7 +346,6 @@ "CounterMask": "12", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L1D_MISS", - "PublicDescription": "Execution stalls while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0xc" }, @@ -365,7 +355,6 @@ "CounterMask": "5", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L2_MISS", - "PublicDescription": "Execution stalls while L2 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x5" }, @@ -375,7 +364,6 @@ "CounterMask": "4", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_TOTAL", - "PublicDescription": "Total execution stalls. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -384,7 +372,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb7", "EventName": "EXE.AMX_BUSY", - "PublicDescription": "Counts the cycles where the AMX (Advance Matrix Extension) unit is busy performing an operation. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -393,7 +380,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.1_PORTS_UTIL", - "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -402,7 +389,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.2_3_PORTS_UTIL", - "PublicDescription": "Cycles total of 2 or 3 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0xc" }, @@ -411,7 +397,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.2_PORTS_UTIL", - "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -420,7 +406,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.3_PORTS_UTIL", - "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -429,7 +415,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.4_PORTS_UTIL", - "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -439,7 +425,6 @@ "CounterMask": "5", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.BOUND_ON_LOADS", - "PublicDescription": "Execution stalls while memory subsystem has an outstanding load. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x21" }, @@ -449,7 +434,7 @@ "CounterMask": "2", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.BOUND_ON_STORES", - "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall.", "SampleAfterValue": "1000003", "UMask": "0x40" }, @@ -458,7 +443,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.EXE_BOUND_0_PORTS", - "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load. Available PDIST counters: 0", + "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load.", "SampleAfterValue": "1000003", "UMask": "0x80" }, @@ -467,7 +452,7 @@ "Counter": "0,1,2,3", "EventCode": "0x75", "EventName": "INST_DECODED.DECODERS", - "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions. Available PDIST counters: 0", + "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -492,7 +477,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.MACRO_FUSED", - "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -501,7 +485,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.NOP", - "PublicDescription": "Counts all retired NOP or ENDBR32/64 instructions Available PDIST counters: 0", + "PublicDescription": "Counts all retired NOP or ENDBR32/64 instructions", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -518,7 +502,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -529,7 +513,7 @@ "EdgeDetect": "1", "EventCode": "0xad", "EventName": "INT_MISC.CLEARS_COUNT", - "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears Available PDIST counters: 0", + "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears", "SampleAfterValue": "500009", "UMask": "0x1" }, @@ -538,7 +522,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.CLEAR_RESTEER_CYCLES", - "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path. Available PDIST counters: 0", + "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", "SampleAfterValue": "500009", "UMask": "0x80" }, @@ -547,7 +531,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.MBA_STALLS", - "PublicDescription": "INT_MISC.MBA_STALLS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -556,7 +539,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.RECOVERY_CYCLES", - "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event. Available PDIST counters: 0", + "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event.", "SampleAfterValue": "500009", "UMask": "0x1" }, @@ -567,7 +550,6 @@ "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES", "MSRIndex": "0x3F7", "MSRValue": "0x7", - "PublicDescription": "Bubble cycles of BAClear (Unknown Branch). Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x40" }, @@ -576,7 +558,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.UOP_DROPPING", - "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons Available PDIST counters: 0", + "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -585,7 +567,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.128BIT", - "PublicDescription": "INT_VEC_RETIRED.128BIT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x13" }, @@ -594,7 +575,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.256BIT", - "PublicDescription": "INT_VEC_RETIRED.256BIT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0xac" }, @@ -603,7 +583,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.ADD_128", - "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions. Available PDIST counters: 0", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions.", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -612,7 +592,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.ADD_256", - "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions. Available PDIST counters: 0", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions.", "SampleAfterValue": "1000003", "UMask": "0xc" }, @@ -621,7 +601,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.MUL_256", - "PublicDescription": "INT_VEC_RETIRED.MUL_256 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x80" }, @@ -630,7 +609,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.SHUFFLES", - "PublicDescription": "INT_VEC_RETIRED.SHUFFLES Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x40" }, @@ -639,7 +617,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.VNNI_128", - "PublicDescription": "INT_VEC_RETIRED.VNNI_128 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -648,7 +625,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.VNNI_256", - "PublicDescription": "INT_VEC_RETIRED.VNNI_256 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -657,7 +633,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.ADDRESS_ALIAS", - "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -666,7 +642,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.NO_SR", - "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", "SampleAfterValue": "100003", "UMask": "0x88" }, @@ -675,7 +651,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.STORE_FORWARD", - "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide.", "SampleAfterValue": "100003", "UMask": "0x82" }, @@ -684,7 +660,7 @@ "Counter": "0,1,2,3", "EventCode": "0x4c", "EventName": "LOAD_HIT_PREFETCH.SWPF", - "PublicDescription": "Counts all software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions. Available PDIST counters: 0", + "PublicDescription": "Counts all software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -694,7 +670,7 @@ "CounterMask": "1", "EventCode": "0xa8", "EventName": "LSD.CYCLES_ACTIVE", - "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector). Available PDIST counters: 0", + "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -704,7 +680,7 @@ "CounterMask": "6", "EventCode": "0xa8", "EventName": "LSD.CYCLES_OK", - "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector). Available PDIST counters: 0", + "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -713,7 +689,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa8", "EventName": "LSD.UOPS", - "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -724,7 +700,7 @@ "EdgeDetect": "1", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.COUNT", - "PublicDescription": "Counts the number of machine clears (nukes) of any type. Available PDIST counters: 0", + "PublicDescription": "Counts the number of machine clears (nukes) of any type.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -733,7 +709,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.SMC", - "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear. Available PDIST counters: 0", + "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -742,7 +718,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe0", "EventName": "MISC2_RETIRED.LFENCE", - "PublicDescription": "number of LFENCE retired instructions Available PDIST counters: 0", + "PublicDescription": "number of LFENCE retired instructions", "SampleAfterValue": "400009", "UMask": "0x20" }, @@ -751,7 +727,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcc", "EventName": "MISC_RETIRED.LBR_INSERTS", - "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT. Available PDIST counters: 0", + "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -760,7 +736,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa2", "EventName": "RESOURCE_STALLS.SB", - "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end. Available PDIST counters: 0", + "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -769,7 +745,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa2", "EventName": "RESOURCE_STALLS.SCOREBOARD", - "PublicDescription": "Counts cycles where the pipeline is stalled due to serializing operations. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -778,7 +753,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa5", "EventName": "RS.EMPTY", - "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses) Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses)", "SampleAfterValue": "1000003", "UMask": "0x7" }, @@ -790,7 +765,7 @@ "EventCode": "0xa5", "EventName": "RS.EMPTY_COUNT", "Invert": "1", - "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events) Available PDIST counters: 0", + "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events)", "SampleAfterValue": "100003", "UMask": "0x7" }, @@ -799,7 +774,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa5", "EventName": "RS.EMPTY_RESOURCE", - "PublicDescription": "Cycles when Reservation Station (RS) is empty due to a resource in the back-end Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -812,7 +786,6 @@ "EventCode": "0xa5", "EventName": "RS_EMPTY.COUNT", "Invert": "1", - "PublicDescription": "This event is deprecated. Refer to new event RS.EMPTY_COUNT Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x7" }, @@ -822,7 +795,6 @@ "Deprecated": "1", "EventCode": "0xa5", "EventName": "RS_EMPTY.CYCLES", - "PublicDescription": "This event is deprecated. Refer to new event RS.EMPTY Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x7" }, @@ -831,7 +803,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.BACKEND_BOUND_SLOTS", - "PublicDescription": "Number of slots in TMA method where no micro-operations were being issued from front-end to back-end of the machine due to lack of back-end resources. Available PDIST counters: 0", + "PublicDescription": "Number of slots in TMA method where no micro-operations were being issued from front-end to back-end of the machine due to lack of back-end resources.", "SampleAfterValue": "10000003", "UMask": "0x2" }, @@ -840,7 +812,7 @@ "Counter": "0", "EventCode": "0xa4", "EventName": "TOPDOWN.BAD_SPEC_SLOTS", - "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations. Available PDIST counters: 0", + "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations.", "SampleAfterValue": "10000003", "UMask": "0x4" }, @@ -849,7 +821,7 @@ "Counter": "0", "EventCode": "0xa4", "EventName": "TOPDOWN.BR_MISPREDICT_SLOTS", - "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction. Available PDIST counters: 0", + "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction.", "SampleAfterValue": "10000003", "UMask": "0x8" }, @@ -858,7 +830,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.MEMORY_BOUND_SLOTS", - "PublicDescription": "TOPDOWN.MEMORY_BOUND_SLOTS Available PDIST counters: 0", "SampleAfterValue": "10000003", "UMask": "0x10" }, @@ -875,7 +846,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.SLOTS_P", - "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core. Available PDIST counters: 0", + "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core.", "SampleAfterValue": "10000003", "UMask": "0x1" }, @@ -884,7 +855,6 @@ "Counter": "0,1,2,3", "EventCode": "0x76", "EventName": "UOPS_DECODED.DEC0_UOPS", - "PublicDescription": "UOPS_DECODED.DEC0_UOPS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -893,7 +863,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_0", - "PublicDescription": "Number of uops dispatch to execution port 0. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 0.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -902,7 +872,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_1", - "PublicDescription": "Number of uops dispatch to execution port 1. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 1.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -911,7 +881,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_2_3_10", - "PublicDescription": "Number of uops dispatch to execution ports 2, 3 and 10 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 2, 3 and 10", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -920,7 +890,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_4_9", - "PublicDescription": "Number of uops dispatch to execution ports 4 and 9 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 4 and 9", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -929,7 +899,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_5_11", - "PublicDescription": "Number of uops dispatch to execution ports 5 and 11 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 5 and 11", "SampleAfterValue": "2000003", "UMask": "0x20" }, @@ -938,7 +908,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_6", - "PublicDescription": "Number of uops dispatch to execution port 6. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 6.", "SampleAfterValue": "2000003", "UMask": "0x40" }, @@ -947,7 +917,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_7_8", - "PublicDescription": "Number of uops dispatch to execution ports 7 and 8. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 7 and 8.", "SampleAfterValue": "2000003", "UMask": "0x80" }, @@ -956,7 +926,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE", - "PublicDescription": "Counts the number of uops executed from any thread. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops executed from any thread.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -966,7 +936,7 @@ "CounterMask": "1", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_1", - "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -976,7 +946,7 @@ "CounterMask": "2", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_2", - "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -986,7 +956,7 @@ "CounterMask": "3", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_3", - "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -996,7 +966,7 @@ "CounterMask": "4", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_4", - "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -1006,7 +976,7 @@ "CounterMask": "1", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_1", - "PublicDescription": "Cycles where at least 1 uop was executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 1 uop was executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1016,7 +986,7 @@ "CounterMask": "2", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_2", - "PublicDescription": "Cycles where at least 2 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 2 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1026,7 +996,7 @@ "CounterMask": "3", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_3", - "PublicDescription": "Cycles where at least 3 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 3 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1036,7 +1006,7 @@ "CounterMask": "4", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_4", - "PublicDescription": "Cycles where at least 4 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 4 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1047,7 +1017,7 @@ "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.STALLS", "Invert": "1", - "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1059,7 +1029,6 @@ "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.STALL_CYCLES", "Invert": "1", - "PublicDescription": "This event is deprecated. Refer to new event UOPS_EXECUTED.STALLS Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1068,7 +1037,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.THREAD", - "PublicDescription": "Counts the number of uops to be executed per-thread each cycle. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1077,7 +1045,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.X87", - "PublicDescription": "Counts the number of x87 uops executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of x87 uops executed.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -1086,7 +1054,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xae", "EventName": "UOPS_ISSUED.ANY", - "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1096,7 +1064,6 @@ "CounterMask": "1", "EventCode": "0xae", "EventName": "UOPS_ISSUED.CYCLES", - "PublicDescription": "UOPS_ISSUED.CYCLES Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1106,7 +1073,7 @@ "CounterMask": "1", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.CYCLES", - "PublicDescription": "Counts cycles where at least one uop has retired. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where at least one uop has retired.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1115,7 +1082,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.HEAVY", - "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count. Available PDIST counters: 0", + "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1126,7 +1093,6 @@ "EventName": "UOPS_RETIRED.MS", "MSRIndex": "0x3F7", "MSRValue": "0x8", - "PublicDescription": "UOPS_RETIRED.MS Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -1135,7 +1101,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.SLOTS", - "PublicDescription": "Counts the retirement slots used each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the retirement slots used each cycle.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -1146,7 +1112,7 @@ "EventCode": "0xc2", "EventName": "UOPS_RETIRED.STALLS", "Invert": "1", - "PublicDescription": "This event counts cycles without actually retired uops. Available PDIST counters: 0", + "PublicDescription": "This event counts cycles without actually retired uops.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1158,7 +1124,6 @@ "EventCode": "0xc2", "EventName": "UOPS_RETIRED.STALL_CYCLES", "Invert": "1", - "PublicDescription": "This event is deprecated. Refer to new event UOPS_RETIRED.STALLS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x2" } diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-memory.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-memory.json index 68be01dad7c9..90f61c9511fc 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-memory.json @@ -2769,6 +2769,88 @@ "UMask": "0x3", "Unit": "iMC" }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.HIGH", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Number of DRAM Refreshes Issued : Counts the number of refreshes issued.", + "UMask": "0x24", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.HIGH_ALL", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x24", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.HIGH_PCH0", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x4", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.HIGH_PCH1", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x20", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.PANIC", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Number of DRAM Refreshes Issued : Counts the number of refreshes issued.", + "UMask": "0x12", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.PANIC_ALL", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x12", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.PANIC_PCH0", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x2", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.PANIC_PCH1", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x10", + "Unit": "iMC" + }, { "BriefDescription": "ECC Correctable Errors", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/virtual-memory.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/virtual-memory.json index 3d3f88600e26..609a9549cbf3 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/virtual-memory.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/virtual-memory.json @@ -4,7 +4,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.STLB_HIT", - "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB).", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -14,7 +14,7 @@ "CounterMask": "1", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -23,7 +23,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe" }, @@ -32,7 +32,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_1G", - "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -41,7 +41,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -50,7 +50,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -59,7 +59,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -68,7 +68,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.STLB_HIT", - "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB).", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -78,7 +78,7 @@ "CounterMask": "1", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -87,7 +87,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe" }, @@ -96,7 +96,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_1G", - "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -105,7 +105,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -114,7 +114,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -123,7 +123,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -132,7 +132,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.STLB_HIT", - "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB).", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -142,7 +142,7 @@ "CounterMask": "1", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -151,7 +151,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe" }, @@ -160,7 +160,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -169,7 +169,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -178,7 +178,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10" } diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 12017f568606..e3ac2dede20a 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -9,7 +9,7 @@ GenuineIntel-6-4F,v23,broadwellx,core GenuineIntel-6-55-[56789ABCDEF],v1.25,cascadelakex,core GenuineIntel-6-DD,v1.00,clearwaterforest,core GenuineIntel-6-9[6C],v1.05,elkhartlake,core -GenuineIntel-6-CF,v1.14,emeraldrapids,core +GenuineIntel-6-CF,v1.16,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core GenuineIntel-6-B6,v1.09,grandridge,core From d5a638022a010a480ec2ac308bcabc68eb1b6d62 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:03 -0700 Subject: [PATCH 0852/2711] perf vendor events: Update grandridge metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-8-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/grandridge/grr-metrics.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/grandridge/grr-metrics.json b/tools/perf/pmu-events/arch/x86/grandridge/grr-metrics.json index 878b1caf12de..a0d637a24c1b 100644 --- a/tools/perf/pmu-events/arch/x86/grandridge/grr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/grandridge/grr-metrics.json @@ -1,56 +1,56 @@ [ { "BriefDescription": "C10 residency percent per package", - "MetricExpr": "cstate_pkg@c10\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c10\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C10_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C8 residency percent per package", - "MetricExpr": "cstate_pkg@c8\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c8\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C8_Pkg_Residency", "ScaleUnit": "100%" @@ -633,7 +633,7 @@ }, { "BriefDescription": "Average CPU Utilization", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricName": "tma_info_system_cpu_utilization" }, { @@ -645,7 +645,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "cpu@CPU_CLK_UNHALTED.CORE_P@k / CPU_CLK_UNHALTED.CORE", + "MetricExpr": "CPU_CLK_UNHALTED.CORE_P:k / CPU_CLK_UNHALTED.CORE", "MetricGroup": "Summary", "MetricName": "tma_info_system_kernel_utilization" }, From 0e08908841999354e86e85a38d3ad268a59924b2 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:04 -0700 Subject: [PATCH 0853/2711] perf vendor events: Update graniterapids events/metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update events from v1.10 to v1.12. Update metrics from TMA 5.0 to 5.1. The event updates come from: https://github.com/intel/perfmon/commit/1684fa543fd45970759bb72dc3fc00c2ef87c0e8 Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-9-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/graniterapids/cache.json | 227 +++++++++++++----- .../x86/graniterapids/floating-point.json | 43 ++-- .../arch/x86/graniterapids/frontend.json | 42 ++-- .../arch/x86/graniterapids/gnr-metrics.json | 135 ++++++----- .../arch/x86/graniterapids/memory.json | 33 ++- .../arch/x86/graniterapids/other.json | 30 ++- .../arch/x86/graniterapids/pipeline.json | 167 ++++++------- .../arch/x86/graniterapids/uncore-io.json | 1 - .../arch/x86/graniterapids/uncore-memory.json | 31 --- .../x86/graniterapids/virtual-memory.json | 40 +-- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 11 files changed, 413 insertions(+), 338 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/cache.json b/tools/perf/pmu-events/arch/x86/graniterapids/cache.json index dbdeade6fe6f..7edb73583b07 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/cache.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/cache.json @@ -4,7 +4,6 @@ "Counter": "0,1,2,3", "EventCode": "0x51", "EventName": "L1D.HWPF_MISS", - "PublicDescription": "L1D.HWPF_MISS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -13,7 +12,7 @@ "Counter": "0,1,2,3", "EventCode": "0x51", "EventName": "L1D.REPLACEMENT", - "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace. Available PDIST counters: 0", + "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -22,7 +21,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.FB_FULL", - "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -33,7 +32,7 @@ "EdgeDetect": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.FB_FULL_PERIODS", - "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -42,7 +41,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.L2_STALLS", - "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -51,7 +50,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.PENDING", - "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type. Available PDIST counters: 0", + "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -61,7 +60,7 @@ "CounterMask": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.PENDING_CYCLES", - "PublicDescription": "Counts duration of L1D miss outstanding in cycles. Available PDIST counters: 0", + "PublicDescription": "Counts duration of L1D miss outstanding in cycles.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -70,7 +69,7 @@ "Counter": "0,1,2,3", "EventCode": "0x25", "EventName": "L2_LINES_IN.ALL", - "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects. Available PDIST counters: 0", + "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects.", "SampleAfterValue": "100003", "UMask": "0x1f" }, @@ -79,7 +78,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.NON_SILENT", - "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3 Available PDIST counters: 0", + "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3", "SampleAfterValue": "200003", "UMask": "0x2" }, @@ -88,7 +87,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.SILENT", - "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event. Available PDIST counters: 0", + "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event.", "SampleAfterValue": "200003", "UMask": "0x1" }, @@ -97,7 +96,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.USELESS_HWPF", - "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache Available PDIST counters: 0", + "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache", "SampleAfterValue": "200003", "UMask": "0x4" }, @@ -106,7 +105,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.ALL", - "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES]", "SampleAfterValue": "200003", "UMask": "0xff" }, @@ -115,7 +114,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.HIT", - "PublicDescription": "Counts all requests that hit L2 cache. [This event is alias to L2_RQSTS.HIT] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that hit L2 cache. [This event is alias to L2_RQSTS.HIT]", "SampleAfterValue": "200003", "UMask": "0xdf" }, @@ -124,7 +123,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.MISS", - "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS] Available PDIST counters: 0", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS]", "SampleAfterValue": "200003", "UMask": "0x3f" }, @@ -133,7 +132,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_CODE_RD", - "PublicDescription": "Counts the total number of L2 code requests. Available PDIST counters: 0", + "PublicDescription": "Counts the total number of L2 code requests.", "SampleAfterValue": "200003", "UMask": "0xe4" }, @@ -142,7 +141,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_DATA_RD", - "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once. Available PDIST counters: 0", + "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once.", "SampleAfterValue": "200003", "UMask": "0xe1" }, @@ -151,7 +150,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_MISS", - "PublicDescription": "Counts demand requests that miss L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts demand requests that miss L2 cache.", "SampleAfterValue": "200003", "UMask": "0x27" }, @@ -160,7 +159,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_REFERENCES", - "PublicDescription": "Counts demand requests to L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts demand requests to L2 cache.", "SampleAfterValue": "200003", "UMask": "0xe7" }, @@ -169,7 +168,6 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_HWPF", - "PublicDescription": "L2_RQSTS.ALL_HWPF Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0xf0" }, @@ -178,7 +176,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_RFO", - "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches. Available PDIST counters: 0", + "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches.", "SampleAfterValue": "200003", "UMask": "0xe2" }, @@ -187,7 +185,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.CODE_RD_HIT", - "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads. Available PDIST counters: 0", + "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads.", "SampleAfterValue": "200003", "UMask": "0xc4" }, @@ -196,7 +194,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.CODE_RD_MISS", - "PublicDescription": "Counts L2 cache misses when fetching instructions. Available PDIST counters: 0", + "PublicDescription": "Counts L2 cache misses when fetching instructions.", "SampleAfterValue": "200003", "UMask": "0x24" }, @@ -205,7 +203,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.DEMAND_DATA_RD_HIT", - "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache.", "SampleAfterValue": "200003", "UMask": "0xc1" }, @@ -214,7 +212,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS", - "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once. Available PDIST counters: 0", + "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once.", "SampleAfterValue": "200003", "UMask": "0x21" }, @@ -223,7 +221,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.HIT", - "PublicDescription": "Counts all requests that hit L2 cache. [This event is alias to L2_REQUEST.HIT] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that hit L2 cache. [This event is alias to L2_REQUEST.HIT]", "SampleAfterValue": "200003", "UMask": "0xdf" }, @@ -232,7 +230,6 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.HWPF_MISS", - "PublicDescription": "L2_RQSTS.HWPF_MISS Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x30" }, @@ -241,7 +238,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.MISS", - "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS] Available PDIST counters: 0", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS]", "SampleAfterValue": "200003", "UMask": "0x3f" }, @@ -250,7 +247,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.REFERENCES", - "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL]", "SampleAfterValue": "200003", "UMask": "0xff" }, @@ -259,7 +256,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.RFO_HIT", - "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache.", "SampleAfterValue": "200003", "UMask": "0xc2" }, @@ -268,7 +265,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.RFO_MISS", - "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache.", "SampleAfterValue": "200003", "UMask": "0x22" }, @@ -277,7 +274,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.SWPF_HIT", - "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full. Available PDIST counters: 0", + "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full.", "SampleAfterValue": "200003", "UMask": "0xc8" }, @@ -286,7 +283,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.SWPF_MISS", - "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full. Available PDIST counters: 0", + "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full.", "SampleAfterValue": "200003", "UMask": "0x28" }, @@ -295,7 +292,7 @@ "Counter": "0,1,2,3", "EventCode": "0x23", "EventName": "L2_TRANS.L2_WB", - "PublicDescription": "Counts L2 writebacks that access L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts L2 writebacks that access L2 cache.", "SampleAfterValue": "200003", "UMask": "0x40" }, @@ -304,7 +301,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.MISS", - "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3. Available PDIST counters: 0", + "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", "SampleAfterValue": "100003", "UMask": "0x41" }, @@ -313,7 +310,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.REFERENCE", - "PublicDescription": "Counts core-originated cacheable requests to the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3. Available PDIST counters: 0", + "PublicDescription": "Counts core-originated cacheable requests to the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", "SampleAfterValue": "100003", "UMask": "0x4f" }, @@ -437,7 +434,7 @@ "Counter": "0,1,2,3", "EventCode": "0x43", "EventName": "MEM_LOAD_COMPLETED.L1_MISS_ANY", - "PublicDescription": "Number of completed demand load requests that missed the L1 data cache including shadow misses (FB hits, merge to an ongoing L1D miss) Available PDIST counters: 0", + "PublicDescription": "Number of completed demand load requests that missed the L1 data cache including shadow misses (FB hits, merge to an ongoing L1D miss)", "SampleAfterValue": "1000003", "UMask": "0xfd" }, @@ -503,6 +500,15 @@ "SampleAfterValue": "100007", "UMask": "0x1" }, + { + "BriefDescription": "Retired load instructions with remote cxl mem as the data source where the data request missed all caches.", + "Counter": "0,1,2,3", + "EventCode": "0xd3", + "EventName": "MEM_LOAD_L3_MISS_RETIRED.REMOTE_CXL_MEM", + "PublicDescription": "Counts retired load instructions with remote cxl mem as the data source and the data request missed L3. Available PDIST counters: 0", + "SampleAfterValue": "100007", + "UMask": "0x10" + }, { "BriefDescription": "MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM", "Counter": "0,1,2,3", @@ -628,12 +634,21 @@ "SampleAfterValue": "50021", "UMask": "0x20" }, + { + "BriefDescription": "Retired load instructions with local cxl mem as the data source where the data request missed all caches.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.LOCAL_CXL_MEM", + "PublicDescription": "Counts retired load instructions with local cxl mem as the data source and the data request missed L3. Available PDIST counters: 0", + "SampleAfterValue": "1000003", + "UMask": "0x80" + }, { "BriefDescription": "MEM_STORE_RETIRED.L2_HIT", "Counter": "0,1,2,3", "EventCode": "0x44", "EventName": "MEM_STORE_RETIRED.L2_HIT", - "PublicDescription": "MEM_STORE_RETIRED.L2_HIT Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x1" }, @@ -642,7 +657,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe5", "EventName": "MEM_UOP_RETIRED.ANY", - "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses Available PDIST counters: 0", + "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -690,6 +705,17 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "Counts demand data reads that were supplied by CXL MEM (Type 2 or Type 3).", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_DATA_RD.CXL_MEM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x703C00001", + "PublicDescription": "Counts demand data reads that were supplied by CXL MEM (Type 2 or Type 3). Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts demand data reads that hit in the L3 or were snooped from another core's caches on the same socket.", "Counter": "0,1,2,3", @@ -734,6 +760,17 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "Counts demand data reads that were supplied by CXL MEM (Type 2 and Type 3) attached to local socket.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_DATA_RD.LOCAL_CXL_MEM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x700C00001", + "PublicDescription": "Counts demand data reads that were supplied by CXL MEM (Type 2 and Type 3) attached to local socket. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts demand data reads that were supplied by a cache on a remote socket where a snoop hit a modified line in another core's caches which forwarded the data.", "Counter": "0,1,2,3", @@ -756,6 +793,17 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "Counts demand data reads that were supplied by CXL MEM (Type 2 or Type 3) attached to another socket.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_DATA_RD.REMOTE_CXL_MEM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x703000001", + "PublicDescription": "Counts demand data reads that were supplied by CXL MEM (Type 2 or Type 3) attached to another socket. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts demand data reads that hit a modified line in a distant L3 Cache or were snooped from a distant core's L1/L2 caches on this socket when the system is in SNC (sub-NUMA cluster) mode.", "Counter": "0,1,2,3", @@ -789,6 +837,17 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by CXL MEM (Type 2 or Type 3).", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_RFO.CXL_MEM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x703C00002", + "PublicDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by CXL MEM (Type 2 or Type 3). Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that hit in the L3 or were snooped from another core's caches on the same socket.", "Counter": "0,1,2,3", @@ -811,6 +870,28 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by CXL MEM (Type 2 and Type 3) attached to local socket.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_RFO.LOCAL_CXL_MEM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x700C00002", + "PublicDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by CXL MEM (Type 2 and Type 3) attached to local socket. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, + { + "BriefDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by CXL MEM (Type 2 or Type 3) attached to another socket.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_RFO.REMOTE_CXL_MEM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x703000002", + "PublicDescription": "Counts demand reads for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by CXL MEM (Type 2 or Type 3) attached to another socket. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts writebacks of modified cachelines and streaming stores that have any type of response.", "Counter": "0,1,2,3", @@ -833,6 +914,17 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by CXL MEM (Type 2 or Type 3).", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.READS_TO_CORE.CXL_MEM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x703C04477", + "PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by CXL MEM (Type 2 or Type 3). Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that hit in the L3 or were snooped from another core's caches on the same socket.", "Counter": "0,1,2,3", @@ -855,6 +947,17 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by CXL MEM (Type 2 and Type 3) attached to local socket.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.READS_TO_CORE.LOCAL_CXL_MEM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x700C04477", + "PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by CXL MEM (Type 2 and Type 3) attached to local socket. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were not supplied by the local socket's L1, L2, or L3 caches and were supplied by a remote socket.", "Counter": "0,1,2,3", @@ -899,6 +1002,17 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by CXL MEM (Type 2 or Type 3) attached to another socket.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.READS_TO_CORE.REMOTE_CXL_MEM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x703004477", + "PublicDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that were supplied by CXL MEM (Type 2 or Type 3) attached to another socket. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts all (cacheable) data read, code read and RFO requests including demands and prefetches to the core caches (L1 or L2) that hit a modified line in a distant L3 Cache or were snooped from a distant core's L1/L2 caches on this socket when the system is in SNC (sub-NUMA cluster) mode.", "Counter": "0,1,2,3", @@ -937,7 +1051,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.ALL_REQUESTS", - "PublicDescription": "Counts memory transactions reached the super queue including requests initiated by the core, all L3 prefetches, page walks, etc.. Available PDIST counters: 0", + "PublicDescription": "Counts memory transactions reached the super queue including requests initiated by the core, all L3 prefetches, page walks, etc..", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -946,7 +1060,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DATA_RD", - "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type. Available PDIST counters: 0", + "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -955,7 +1069,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_CODE_RD", - "PublicDescription": "Counts both cacheable and Non-Cacheable code read requests. Available PDIST counters: 0", + "PublicDescription": "Counts both cacheable and Non-Cacheable code read requests.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -964,7 +1078,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_DATA_RD", - "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore. Available PDIST counters: 0", + "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -973,7 +1087,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_RFO", - "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM. Available PDIST counters: 0", + "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -982,7 +1096,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.MEM_UC", - "PublicDescription": "This event counts noncacheable memory data read transactions. Available PDIST counters: 0", + "PublicDescription": "This event counts noncacheable memory data read transactions.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -992,7 +1106,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD", - "PublicDescription": "Counts cycles when offcore outstanding cacheable Core Data Read transactions are present in the super queue. A transaction is considered to be in the Offcore outstanding state between L2 miss and transaction completion sent to requestor (SQ de-allocation). See corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when offcore outstanding cacheable Core Data Read transactions are present in the super queue. A transaction is considered to be in the Offcore outstanding state between L2 miss and transaction completion sent to requestor (SQ de-allocation). See corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -1002,7 +1116,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_CODE_RD", - "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1012,7 +1126,6 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", - "PublicDescription": "Cycles where at least 1 outstanding demand data read request is pending. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1022,7 +1135,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO", - "PublicDescription": "Counts the number of offcore outstanding demand rfo Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding demand rfo Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -1031,7 +1144,6 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD", - "PublicDescription": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -1040,7 +1152,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_CODE_RD", - "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1049,7 +1161,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD", - "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor. Available PDIST counters: 0", + "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -1058,7 +1170,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_RFO", - "PublicDescription": "Counts the number of off-core outstanding read-for-ownership (RFO) store transactions every cycle. An RFO transaction is considered to be in the Off-core outstanding state between L2 cache miss and transaction completion. Available PDIST counters: 0", + "PublicDescription": "Counts the number of off-core outstanding read-for-ownership (RFO) store transactions every cycle. An RFO transaction is considered to be in the Off-core outstanding state between L2 cache miss and transaction completion.", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -1067,7 +1179,7 @@ "Counter": "0,1,2,3", "EventCode": "0x2c", "EventName": "SQ_MISC.BUS_LOCK", - "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory. Available PDIST counters: 0", + "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -1076,7 +1188,6 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.ANY", - "PublicDescription": "Counts the number of PREFETCHNTA, PREFETCHW, PREFETCHT0, PREFETCHT1 or PREFETCHT2 instructions executed. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0xf" }, @@ -1085,7 +1196,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.NTA", - "PublicDescription": "Counts the number of PREFETCHNTA instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHNTA instructions executed.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -1094,7 +1205,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.PREFETCHW", - "PublicDescription": "Counts the number of PREFETCHW instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHW instructions executed.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -1103,7 +1214,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.T0", - "PublicDescription": "Counts the number of PREFETCHT0 instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHT0 instructions executed.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -1112,7 +1223,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.T1_T2", - "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed.", "SampleAfterValue": "100003", "UMask": "0x4" } diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/floating-point.json b/tools/perf/pmu-events/arch/x86/graniterapids/floating-point.json index 1832dd952f66..59789eee060c 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/floating-point.json @@ -5,7 +5,6 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.FPDIV_ACTIVE", - "PublicDescription": "This event counts the cycles the floating point divider is busy. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -14,7 +13,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.FP", - "PublicDescription": "Counts all microcode Floating Point assists. Available PDIST counters: 0", + "PublicDescription": "Counts all microcode Floating Point assists.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -23,7 +22,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.SSE_AVX_MIX", - "PublicDescription": "ASSISTS.SSE_AVX_MIX Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -32,7 +30,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_0", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -41,7 +38,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_1", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -50,7 +46,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_5", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -59,7 +54,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V0", - "PublicDescription": "FP_ARITH_DISPATCHED.V0 [This event is alias to FP_ARITH_DISPATCHED.PORT_0] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -68,7 +62,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V1", - "PublicDescription": "FP_ARITH_DISPATCHED.V1 [This event is alias to FP_ARITH_DISPATCHED.PORT_1] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -77,7 +70,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V2", - "PublicDescription": "FP_ARITH_DISPATCHED.V2 [This event is alias to FP_ARITH_DISPATCHED.PORT_5] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -86,7 +78,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -95,7 +87,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -104,7 +96,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -113,7 +105,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -122,7 +114,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.4_FLOPS", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x18" }, @@ -131,7 +123,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x40" }, @@ -140,7 +132,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -149,7 +141,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.8_FLOPS", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision and 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision and double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RSQRT14 RCP RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision and 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision and double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RSQRT14 RCP RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x60" }, @@ -158,7 +150,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR", - "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -167,7 +159,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -176,7 +168,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_SINGLE", - "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -185,7 +177,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.VECTOR", - "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "1000003", "UMask": "0xfc" }, @@ -194,7 +186,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.128B_PACKED_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.128B_PACKED_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -203,7 +194,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.256B_PACKED_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.256B_PACKED_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -212,7 +202,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.512B_PACKED_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.512B_PACKED_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -221,7 +210,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.COMPLEX_SCALAR_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.COMPLEX_SCALAR_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -230,7 +218,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.SCALAR", - "PublicDescription": "FP_ARITH_INST_RETIRED2.SCALAR Available PDIST counters: 0", + "PublicDescription": "FP_ARITH_INST_RETIRED2.SCALAR", "SampleAfterValue": "100003", "UMask": "0x3" }, @@ -239,7 +227,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.SCALAR_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.SCALAR_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -248,7 +235,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.VECTOR", - "PublicDescription": "FP_ARITH_INST_RETIRED2.VECTOR Available PDIST counters: 0", + "PublicDescription": "FP_ARITH_INST_RETIRED2.VECTOR", "SampleAfterValue": "100003", "UMask": "0x1c" } diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/frontend.json b/tools/perf/pmu-events/arch/x86/graniterapids/frontend.json index b7cd92fbecd5..d580d305c926 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/frontend.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/frontend.json @@ -4,7 +4,7 @@ "Counter": "0,1,2,3", "EventCode": "0x60", "EventName": "BACLEARS.ANY", - "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0", + "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -13,7 +13,7 @@ "Counter": "0,1,2,3", "EventCode": "0x87", "EventName": "DECODE.LCP", - "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk. Available PDIST counters: 0", + "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk.", "SampleAfterValue": "500009", "UMask": "0x1" }, @@ -22,7 +22,6 @@ "Counter": "0,1,2,3", "EventCode": "0x87", "EventName": "DECODE.MS_BUSY", - "PublicDescription": "Cycles the Microcode Sequencer is busy. Available PDIST counters: 0", "SampleAfterValue": "500009", "UMask": "0x2" }, @@ -31,7 +30,7 @@ "Counter": "0,1,2,3", "EventCode": "0x61", "EventName": "DSB2MITE_SWITCHES.PENALTY_CYCLES", - "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE. Available PDIST counters: 0", + "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -303,7 +302,7 @@ "Counter": "0,1,2,3", "EventCode": "0x80", "EventName": "ICACHE_DATA.STALLS", - "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity.", "SampleAfterValue": "500009", "UMask": "0x4" }, @@ -314,7 +313,6 @@ "EdgeDetect": "1", "EventCode": "0x80", "EventName": "ICACHE_DATA.STALL_PERIODS", - "PublicDescription": "ICACHE_DATA.STALL_PERIODS Available PDIST counters: 0", "SampleAfterValue": "500009", "UMask": "0x4" }, @@ -323,7 +321,7 @@ "Counter": "0,1,2,3", "EventCode": "0x83", "EventName": "ICACHE_TAG.STALLS", - "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss.", "SampleAfterValue": "200003", "UMask": "0x4" }, @@ -333,7 +331,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_ANY", - "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -343,7 +341,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ. Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -352,7 +350,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.DSB_UOPS", - "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -362,7 +360,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.MITE_CYCLES_ANY", - "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -372,7 +370,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.MITE_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -381,7 +379,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.MITE_UOPS", - "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -391,7 +389,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.MS_CYCLES_ANY", - "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE.", "SampleAfterValue": "2000003", "UMask": "0x20" }, @@ -402,7 +400,7 @@ "EdgeDetect": "1", "EventCode": "0x79", "EventName": "IDQ.MS_SWITCHES", - "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer. Available PDIST counters: 0", + "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -411,7 +409,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.MS_UOPS", - "PublicDescription": "Counts the number of uops initiated by MITE or Decode Stream Buffer (DSB) and delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Counting includes uops that may 'bypass' the IDQ. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops initiated by MITE or Decode Stream Buffer (DSB) and delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Counting includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -420,7 +418,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CORE", - "PublicDescription": "This event counts a subset of the Topdown Slots event that when no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations. The count may be distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Frontend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method. Available PDIST counters: 0", + "PublicDescription": "This event counts a subset of the Topdown Slots event that when no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations. The count may be distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Frontend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -430,7 +428,7 @@ "CounterMask": "6", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE", - "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -441,7 +439,7 @@ "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CYCLES_FE_WAS_OK", "Invert": "1", - "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -450,7 +448,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CORE", - "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -460,7 +458,7 @@ "CounterMask": "6", "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE", - "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -471,7 +469,7 @@ "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK", "Invert": "1", - "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK]", "SampleAfterValue": "1000003", "UMask": "0x1" } diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/gnr-metrics.json b/tools/perf/pmu-events/arch/x86/graniterapids/gnr-metrics.json index 9a620e1b8de8..cc3c834ca286 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/gnr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/gnr-metrics.json @@ -1,28 +1,28 @@ [ { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" @@ -381,7 +381,7 @@ { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BvOB;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", "MetricThreshold": "tma_backend_bound > 0.2", @@ -415,22 +415,6 @@ "MetricThreshold": "tma_bottleneck_branching_overhead > 5", "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * tma_amx_busy / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", @@ -439,16 +423,32 @@ "MetricThreshold": "tma_bottleneck_compute_bound_est > 20", "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: " }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + 0 / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20" }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * ((1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + RS.EMPTY_RESOURCE / tma_info_thread_clks * tma_ports_utilized_0) / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricExpr": "100 * ((1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + RS.EMPTY_RESOURCE / tma_info_thread_clks * tma_ports_utilized_0) / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -456,7 +456,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -464,7 +464,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", "MetricThreshold": "tma_bottleneck_memory_synchronization > 10", @@ -480,7 +480,7 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -496,7 +496,7 @@ { "BriefDescription": "This metric represents fraction of slots the CPU has wasted due to Branch Misprediction", "DefaultMetricgroupName": "TopdownL2", - "MetricExpr": "topdown\\-br\\-mispredict / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-br\\-mispredict / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BadSpec;BrMispredicts;BvMP;Default;TmaL2;TopdownL2;tma_L2_group;tma_bad_speculation_group;tma_issueBM", "MetricName": "tma_branch_mispredicts", "MetricThreshold": "tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15", @@ -613,7 +613,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS * min(MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS:R, 74.6 * tma_info_system_core_frequency) + MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD * min(MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD:R, 76.6 * tma_info_system_core_frequency) * (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM / (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM + OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD))) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;DataSharing;LockCont;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_contested_accesses", @@ -632,6 +631,15 @@ "PublicDescription": "This metric represents fraction of slots where Core non-memory issues were of a bottleneck. Shortage in hardware compute resources; or dependencies in software's instructions are both categorized under Core Bound. Hence it may indicate the machine ran out of an out-of-order resource; certain execution units are overloaded or dependencies in program's data- or instruction-flow are limiting the performance (e.g. FP-chained long-latency arithmetic operations).", "ScaleUnit": "100%" }, + { + "BriefDescription": "This metric roughly estimates (based on idle latencies) how often the CPU was stalled on accesses to external CXL Memory by loads (e.g", + "MetricExpr": "(((1 - ((19 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + 10 * (MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS))) / (19 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + 10 * (MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + (25 * (MEM_LOAD_RETIRED.LOCAL_CXL_MEM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) if #has_pmem > 0 else 0) + 33 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_CXL_MEM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) if #has_pmem > 0 else 0))) if #has_pmem > 0 else 1)) * (MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks) if 1e6 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_CXL_MEM + MEM_LOAD_RETIRED.LOCAL_CXL_MEM) > MEM_LOAD_RETIRED.L1_MISS else 0) if #has_pmem > 0 else 0)", + "MetricGroup": "MemoryBound;Server;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", + "MetricName": "tma_cxl_mem_bound", + "MetricThreshold": "tma_cxl_mem_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", + "PublicDescription": "This metric roughly estimates (based on idle latencies) how often the CPU was stalled on accesses to external CXL Memory by loads (e.g. 3D-Xpoint (Crystal Ridge, a.k.a. IXP) memory, PMM - Persistent Memory Module [from CLX to SPR] or any other CXL Type3 Memory [EMR onwards]).", + "ScaleUnit": "100%" + }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", "MetricConstraint": "NO_GROUP_EVENTS", @@ -662,7 +670,7 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", - "MetricExpr": "MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks", + "MetricExpr": "(MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks - tma_cxl_mem_bound if #has_pmem > 0 else MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks)", "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_dram_bound", "MetricThreshold": "tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", @@ -720,7 +728,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%" }, { @@ -848,7 +856,7 @@ { "BriefDescription": "This metric represents fraction of slots where the CPU was retiring heavy-weight operations -- instructions that require two or more uops or micro-coded sequences", "DefaultMetricgroupName": "TopdownL2", - "MetricExpr": "topdown\\-heavy\\-ops / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-heavy\\-ops / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "Default;Retire;TmaL2;TopdownL2;tma_L2_group;tma_retiring_group", "MetricName": "tma_heavy_operations", "MetricThreshold": "tma_heavy_operations > 0.1", @@ -1395,19 +1403,19 @@ { "BriefDescription": "Off-core accesses per kilo instruction for modified write requests", "MetricExpr": "1e3 * OCR.MODIFIED_WRITE.ANY_RESPONSE / tma_info_inst_mix_instructions", - "MetricGroup": "Offcore", + "MetricGroup": "Offcore;Server", "MetricName": "tma_info_memory_mix_offcore_mwrite_any_pki" }, { "BriefDescription": "Off-core accesses per kilo instruction for reads-to-core requests (speculative; including in-core HW prefetches)", "MetricExpr": "1e3 * OCR.READS_TO_CORE.ANY_RESPONSE / tma_info_inst_mix_instructions", - "MetricGroup": "CacheHits;Offcore", + "MetricGroup": "CacheHits;Offcore;Server", "MetricName": "tma_info_memory_mix_offcore_read_any_pki" }, { "BriefDescription": "L3 cache misses per kilo instruction for reads-to-core requests (speculative; including in-core HW prefetches)", "MetricExpr": "1e3 * OCR.READS_TO_CORE.L3_MISS / tma_info_inst_mix_instructions", - "MetricGroup": "Offcore", + "MetricGroup": "Offcore;Server", "MetricName": "tma_info_memory_mix_offcore_read_l3m_pki" }, { @@ -1433,21 +1441,21 @@ { "BriefDescription": "Average DRAM BW for Reads-to-Core (R2C) covering for memory attached to local- and remote-socket", "MetricExpr": "64 * OCR.READS_TO_CORE.DRAM / 1e9 / tma_info_system_time", - "MetricGroup": "HPC;Mem;MemoryBW;SoC", + "MetricGroup": "HPC;Mem;MemoryBW;Offcore;Server", "MetricName": "tma_info_memory_soc_r2c_dram_bw", "PublicDescription": "Average DRAM BW for Reads-to-Core (R2C) covering for memory attached to local- and remote-socket. See R2C_Offcore_BW." }, { "BriefDescription": "Average L3-cache miss BW for Reads-to-Core (R2C)", "MetricExpr": "64 * OCR.READS_TO_CORE.L3_MISS / 1e9 / tma_info_system_time", - "MetricGroup": "HPC;Mem;MemoryBW;SoC", + "MetricGroup": "HPC;Mem;MemoryBW;Offcore;Server", "MetricName": "tma_info_memory_soc_r2c_l3m_bw", "PublicDescription": "Average L3-cache miss BW for Reads-to-Core (R2C). This covering going to DRAM or other memory off-chip memory tears. See R2C_Offcore_BW." }, { "BriefDescription": "Average Off-core access BW for Reads-to-Core (R2C)", "MetricExpr": "64 * OCR.READS_TO_CORE.ANY_RESPONSE / 1e9 / tma_info_system_time", - "MetricGroup": "HPC;Mem;MemoryBW;SoC", + "MetricGroup": "HPC;Mem;MemoryBW;Offcore;Server", "MetricName": "tma_info_memory_soc_r2c_offcore_bw", "PublicDescription": "Average Off-core access BW for Reads-to-Core (R2C). R2C account for demand or prefetch load/RFO/code access that fill data into the Core caches." }, @@ -1491,7 +1499,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1538,7 +1546,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -1550,16 +1558,28 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, + { + "BriefDescription": "Average 3DXP Memory Bandwidth Use for reads [GB / sec]", + "MetricExpr": "(64 * UNC_CXLCM_RxC_PACK_BUF_INSERTS.MEM_DATA / 1e9 / tma_info_system_time if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryBW;Server;SoC", + "MetricName": "tma_info_system_cxl_mem_read_bw" + }, + { + "BriefDescription": "Average 3DXP Memory Bandwidth Use for Writes [GB / sec]", + "MetricExpr": "(64 * UNC_CXLDP_TxC_AGF_INSERTS.M2S_DATA / 1e9 / tma_info_system_time if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryBW;Server;SoC", + "MetricName": "tma_info_system_cxl_mem_write_bw" + }, { "BriefDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]", "MetricExpr": "64 * (UNC_M_CAS_COUNT_SCH0.RD + UNC_M_CAS_COUNT_SCH1.RD + UNC_M_CAS_COUNT_SCH0.WR + UNC_M_CAS_COUNT_SCH1.WR) / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1771,12 +1791,12 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", "MetricExpr": "min(2 * (MEM_INST_RETIRED.ALL_LOADS - MEM_LOAD_RETIRED.FB_HIT - MEM_LOAD_RETIRED.L1_MISS) * 20 / 100, max(CYCLE_ACTIVITY.CYCLES_MEM_ANY - MEMORY_ACTIVITY.CYCLES_L1D_MISS, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%" }, { @@ -1790,7 +1810,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles with demand load accesses that hit the L2 cache under unloaded scenarios (possibly L2 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "MEM_LOAD_RETIRED.L2_HIT * min(MEM_LOAD_RETIRED.L2_HIT:R, 4.4 * tma_info_system_core_frequency) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "MemoryLat;TopdownL4;tma_L4_group;tma_l2_bound_group", "MetricName": "tma_l2_hit_latency", @@ -1809,12 +1828,11 @@ }, { "BriefDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "MEM_LOAD_RETIRED.L3_HIT * min(MEM_LOAD_RETIRED.L3_HIT:R, 32.6 * tma_info_system_core_frequency) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, { @@ -1897,6 +1915,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "MEM_INST_RETIRED.LOCK_LOADS * MEM_INST_RETIRED.LOCK_LOADS:R / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -1929,7 +1948,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%" }, { @@ -1938,13 +1957,13 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, { "BriefDescription": "This metric represents fraction of slots the Memory subsystem within the Backend was a bottleneck", "DefaultMetricgroupName": "TopdownL2", - "MetricExpr": "topdown\\-mem\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-mem\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "Backend;Default;TmaL2;TopdownL2;tma_L2_group;tma_backend_bound_group", "MetricName": "tma_memory_bound", "MetricThreshold": "tma_memory_bound > 0.2 & tma_backend_bound > 0.2", @@ -1954,7 +1973,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to LFENCE Instructions.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * MISC2_RETIRED.LFENCE / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_memory_fence", @@ -2007,7 +2025,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "max(IDQ.MS_CYCLES_ANY, cpu@UOPS_RETIRED.MS\\,cmask\\=1@ / (UOPS_RETIRED.SLOTS / UOPS_ISSUED.ANY)) / tma_info_core_core_clks / 2", + "MetricExpr": "max(IDQ.MS_CYCLES_ANY, cpu@UOPS_RETIRED.MS\\,cmask\\=1@ / (UOPS_RETIRED.SLOTS / UOPS_ISSUED.ANY)) / tma_info_core_core_clks / 2.4", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -2042,6 +2060,7 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_light_operations - (tma_fp_arith + tma_int_operations + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", @@ -2103,6 +2122,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "((tma_ports_utilized_0 * tma_info_thread_clks + (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_3_PORTS_UTIL)) / tma_info_thread_clks if ARITH.DIV_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - EXE_ACTIVITY.BOUND_ON_LOADS else (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_3_PORTS_UTIL) / tma_info_thread_clks)", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", @@ -2112,6 +2132,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "max(EXE_ACTIVITY.EXE_BOUND_0_PORTS - RESOURCE_STALLS.SCOREBOARD, 0) / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", @@ -2121,6 +2142,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "EXE_ACTIVITY.1_PORTS_UTIL / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", @@ -2130,7 +2152,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "EXE_ACTIVITY.2_PORTS_UTIL / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", @@ -2140,7 +2161,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 3 or more uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "UOPS_EXECUTED.CYCLES_GE_3 / tma_info_thread_clks", "MetricGroup": "BvCB;PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_3m", @@ -2150,7 +2170,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote cache in other sockets including synchronizations issues", - "MetricExpr": "(MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM:R + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD:R) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", + "MetricExpr": "(MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * PEBS + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * PEBS) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "Offcore;Server;Snoop;TopdownL5;tma_L5_group;tma_issueSyncxn;tma_mem_latency_group", "MetricName": "tma_remote_cache", "MetricThreshold": "tma_remote_cache > 0.05 & (tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", @@ -2159,7 +2179,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote memory", - "MetricExpr": "MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM:R * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", + "MetricExpr": "MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * PEBS * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "Server;Snoop;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_remote_mem", "MetricThreshold": "tma_remote_mem > 0.1 & (tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", @@ -2177,7 +2197,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -2205,7 +2225,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to PAUSE Instructions", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "CPU_CLK_UNHALTED.PAUSE / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_slow_pause", @@ -2237,7 +2256,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%" }, { diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/memory.json b/tools/perf/pmu-events/arch/x86/graniterapids/memory.json index 4db39f304c2c..96f40390becf 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/memory.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/memory.json @@ -5,7 +5,6 @@ "CounterMask": "2", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L3_MISS", - "PublicDescription": "Cycles while L3 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -15,7 +14,6 @@ "CounterMask": "6", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L3_MISS", - "PublicDescription": "Execution stalls while L3 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x6" }, @@ -24,7 +22,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", - "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture Available PDIST counters: 0", + "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -34,7 +32,6 @@ "CounterMask": "2", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.CYCLES_L1D_MISS", - "PublicDescription": "Cycles while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -44,7 +41,6 @@ "CounterMask": "3", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L1D_MISS", - "PublicDescription": "Execution stalls while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -54,7 +50,7 @@ "CounterMask": "5", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L2_MISS", - "PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock). Available PDIST counters: 0", + "PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).", "SampleAfterValue": "1000003", "UMask": "0x5" }, @@ -64,7 +60,7 @@ "CounterMask": "9", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L3_MISS", - "PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock). Available PDIST counters: 0", + "PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).", "SampleAfterValue": "1000003", "UMask": "0x9" }, @@ -412,7 +408,6 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "Counts demand data read requests that miss the L3 cache. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -422,7 +417,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "Cycles with at least 1 Demand Data Read requests who miss L3 cache in the superQ. Available PDIST counters: 0", + "PublicDescription": "Cycles with at least 1 Demand Data Read requests who miss L3 cache in the superQ.", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -431,7 +426,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache. Available PDIST counters: 0", + "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -449,7 +444,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_EVENTS", - "PublicDescription": "Counts the number of times an RTM execution aborted due to none of the previous 3 categories (e.g. interrupt). Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to none of the previous 3 categories (e.g. interrupt).", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -458,7 +453,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_MEM", - "PublicDescription": "Counts the number of times an RTM execution aborted due to various memory events (e.g. read/write capacity and conflicts). Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to various memory events (e.g. read/write capacity and conflicts).", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -467,7 +462,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_MEMTYPE", - "PublicDescription": "Counts the number of times an RTM execution aborted due to incompatible memory type. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to incompatible memory type.", "SampleAfterValue": "100003", "UMask": "0x40" }, @@ -476,7 +471,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_UNFRIENDLY", - "PublicDescription": "Counts the number of times an RTM execution aborted due to HLE-unfriendly instructions. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to HLE-unfriendly instructions.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -485,7 +480,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.COMMIT", - "PublicDescription": "Counts the number of times RTM commit succeeded. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times RTM commit succeeded.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -494,7 +489,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.START", - "PublicDescription": "Counts the number of times we entered an RTM region. Does not count nested transactions. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times we entered an RTM region. Does not count nested transactions.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -503,7 +498,7 @@ "Counter": "0,1,2,3", "EventCode": "0x54", "EventName": "TX_MEM.ABORT_CAPACITY_READ", - "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional reads Available PDIST counters: 0", + "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional reads", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -512,7 +507,7 @@ "Counter": "0,1,2,3", "EventCode": "0x54", "EventName": "TX_MEM.ABORT_CAPACITY_WRITE", - "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional writes. Available PDIST counters: 0", + "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional writes.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -521,7 +516,7 @@ "Counter": "0,1,2,3", "EventCode": "0x54", "EventName": "TX_MEM.ABORT_CONFLICT", - "PublicDescription": "Counts the number of times a TSX line had a cache conflict. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times a TSX line had a cache conflict.", "SampleAfterValue": "100003", "UMask": "0x1" } diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/other.json b/tools/perf/pmu-events/arch/x86/graniterapids/other.json index 8b7aa4caec46..c0747750b1a8 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/other.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/other.json @@ -4,7 +4,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.HARDWARE", - "PublicDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events. This includes, but not limited to, assists at EXE or MEM uop writeback like AVX* load/store/gather/scatter (non-FP GSSE-assist ) , assists generated by ROB like PEBS and RTIT, Uncore trap, RAR (Remote Action Request) and CET (Control flow Enforcement Technology) assists. the event also counts for Machine Ordering count. Available PDIST counters: 0", + "PublicDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events. This includes, but not limited to, assists at EXE or MEM uop writeback like AVX* load/store/gather/scatter (non-FP GSSE-assist ) , assists generated by ROB like PEBS and RTIT, Uncore trap, RAR (Remote Action Request) and CET (Control flow Enforcement Technology) assists. the event also counts for Machine Ordering count.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -13,10 +13,34 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.PAGE_FAULT", - "PublicDescription": "ASSISTS.PAGE_FAULT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, + { + "BriefDescription": "HW_INTERRUPTS.MASKED", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.MASKED", + "SampleAfterValue": "100003", + "UMask": "0x2" + }, + { + "BriefDescription": "HW_INTERRUPTS.PENDING_AND_MASKED", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.PENDING_AND_MASKED", + "SampleAfterValue": "100003", + "UMask": "0x4" + }, + { + "BriefDescription": "Number of hardware interrupts received by the processor.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.RECEIVED", + "PublicDescription": "Counts the number of hardware interruptions received by the processor.", + "SampleAfterValue": "203", + "UMask": "0x1" + }, { "BriefDescription": "Counts streaming stores that have any type of response.", "Counter": "0,1,2,3", @@ -34,7 +58,7 @@ "CounterMask": "1", "EventCode": "0x2d", "EventName": "XQ.FULL_CYCLES", - "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache). Available PDIST counters: 0", + "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache).", "SampleAfterValue": "1000003", "UMask": "0x1" } diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/pipeline.json b/tools/perf/pmu-events/arch/x86/graniterapids/pipeline.json index 27af3bd6bacf..0fef8fd61974 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/pipeline.json @@ -5,7 +5,7 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.DIV_ACTIVE", - "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations.", "SampleAfterValue": "1000003", "UMask": "0x9" }, @@ -15,7 +15,6 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.IDIV_ACTIVE", - "PublicDescription": "This event counts the cycles the integer divider is busy. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -24,7 +23,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.ANY", - "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists. Available PDIST counters: 0", + "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists.", "SampleAfterValue": "100003", "UMask": "0x1b" }, @@ -271,7 +270,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C01", - "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -280,7 +279,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C02", - "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", "SampleAfterValue": "2000003", "UMask": "0x20" }, @@ -289,7 +288,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C0_WAIT", - "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction.", "SampleAfterValue": "2000003", "UMask": "0x70" }, @@ -298,7 +297,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.DISTRIBUTED", - "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread. Available PDIST counters: 0", + "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -307,7 +306,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE", - "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted. Available PDIST counters: 0", + "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted.", "SampleAfterValue": "25003", "UMask": "0x2" }, @@ -316,7 +315,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.PAUSE", - "PublicDescription": "CPU_CLK_UNHALTED.PAUSE Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x40" }, @@ -327,7 +325,6 @@ "EdgeDetect": "1", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.PAUSE_INST", - "PublicDescription": "CPU_CLK_UNHALTED.PAUSE_INST Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x40" }, @@ -336,7 +333,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_DISTRIBUTED", - "PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread. Available PDIST counters: 0", + "PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -344,7 +341,7 @@ "BriefDescription": "Reference cycles when the core is not in halt state.", "Counter": "Fixed counter 2", "EventName": "CPU_CLK_UNHALTED.REF_TSC", - "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case. Available PDIST counters: 0", + "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.", "SampleAfterValue": "2000003", "UMask": "0x3" }, @@ -353,7 +350,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_TSC_P", - "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case. Available PDIST counters: 0", + "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -361,7 +358,7 @@ "BriefDescription": "Core cycles when the thread is not in halt state", "Counter": "Fixed counter 1", "EventName": "CPU_CLK_UNHALTED.THREAD", - "PublicDescription": "Counts the number of core cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events. Available PDIST counters: 0", + "PublicDescription": "Counts the number of core cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -370,7 +367,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.THREAD_P", - "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time. Available PDIST counters: 0", + "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time.", "SampleAfterValue": "2000003" }, { @@ -379,7 +376,6 @@ "CounterMask": "8", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L1D_MISS", - "PublicDescription": "Cycles while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -389,7 +385,6 @@ "CounterMask": "1", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L2_MISS", - "PublicDescription": "Cycles while L2 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -399,7 +394,6 @@ "CounterMask": "16", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_MEM_ANY", - "PublicDescription": "Cycles while memory subsystem has an outstanding load. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -409,7 +403,6 @@ "CounterMask": "12", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L1D_MISS", - "PublicDescription": "Execution stalls while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0xc" }, @@ -419,7 +412,6 @@ "CounterMask": "5", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L2_MISS", - "PublicDescription": "Execution stalls while L2 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x5" }, @@ -429,7 +421,6 @@ "CounterMask": "4", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_TOTAL", - "PublicDescription": "Total execution stalls. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -438,7 +429,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb7", "EventName": "EXE.AMX_BUSY", - "PublicDescription": "Counts the cycles where the AMX (Advance Matrix Extension) unit is busy performing an operation. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -447,7 +437,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.1_PORTS_UTIL", - "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -456,7 +446,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.2_3_PORTS_UTIL", - "PublicDescription": "Cycles total of 2 or 3 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0xc" }, @@ -465,7 +454,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.2_PORTS_UTIL", - "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -474,7 +463,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.3_PORTS_UTIL", - "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -483,7 +472,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.4_PORTS_UTIL", - "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -493,7 +482,6 @@ "CounterMask": "5", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.BOUND_ON_LOADS", - "PublicDescription": "Execution stalls while memory subsystem has an outstanding load. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x21" }, @@ -503,7 +491,7 @@ "CounterMask": "2", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.BOUND_ON_STORES", - "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall.", "SampleAfterValue": "1000003", "UMask": "0x40" }, @@ -512,7 +500,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.EXE_BOUND_0_PORTS", - "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load. Available PDIST counters: 0", + "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load.", "SampleAfterValue": "1000003", "UMask": "0x80" }, @@ -521,7 +509,7 @@ "Counter": "0,1,2,3", "EventCode": "0x75", "EventName": "INST_DECODED.DECODERS", - "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions. Available PDIST counters: 0", + "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -546,7 +534,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.MACRO_FUSED", - "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -555,7 +542,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.NOP", - "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions Available PDIST counters: 0", + "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -572,7 +559,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -583,7 +570,7 @@ "EdgeDetect": "1", "EventCode": "0xad", "EventName": "INT_MISC.CLEARS_COUNT", - "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears Available PDIST counters: 0", + "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears", "SampleAfterValue": "500009", "UMask": "0x1" }, @@ -592,7 +579,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.CLEAR_RESTEER_CYCLES", - "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path. Available PDIST counters: 0", + "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", "SampleAfterValue": "500009", "UMask": "0x80" }, @@ -601,7 +588,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.MBA_STALLS", - "PublicDescription": "INT_MISC.MBA_STALLS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -610,7 +596,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.RECOVERY_CYCLES", - "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event. Available PDIST counters: 0", + "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event.", "SampleAfterValue": "500009", "UMask": "0x1" }, @@ -621,7 +607,6 @@ "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES", "MSRIndex": "0x3F7", "MSRValue": "0x7", - "PublicDescription": "Bubble cycles of BAClear (Unknown Branch). Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x40" }, @@ -630,7 +615,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.UOP_DROPPING", - "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons Available PDIST counters: 0", + "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -639,7 +624,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.128BIT", - "PublicDescription": "INT_VEC_RETIRED.128BIT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x13" }, @@ -648,7 +632,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.256BIT", - "PublicDescription": "INT_VEC_RETIRED.256BIT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0xac" }, @@ -657,7 +640,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.ADD_128", - "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions. Available PDIST counters: 0", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions.", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -666,7 +649,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.ADD_256", - "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions. Available PDIST counters: 0", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions.", "SampleAfterValue": "1000003", "UMask": "0xc" }, @@ -675,7 +658,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.MUL_256", - "PublicDescription": "INT_VEC_RETIRED.MUL_256 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x80" }, @@ -684,7 +666,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.SHUFFLES", - "PublicDescription": "INT_VEC_RETIRED.SHUFFLES Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x40" }, @@ -693,7 +674,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.VNNI_128", - "PublicDescription": "INT_VEC_RETIRED.VNNI_128 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -702,7 +682,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.VNNI_256", - "PublicDescription": "INT_VEC_RETIRED.VNNI_256 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -711,7 +690,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.ADDRESS_ALIAS", - "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -720,7 +699,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.NO_SR", - "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", "SampleAfterValue": "100003", "UMask": "0x88" }, @@ -729,7 +708,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.STORE_FORWARD", - "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide.", "SampleAfterValue": "100003", "UMask": "0x82" }, @@ -738,7 +717,7 @@ "Counter": "0,1,2,3", "EventCode": "0x4c", "EventName": "LOAD_HIT_PREFETCH.SWPF", - "PublicDescription": "Counts all software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions. Available PDIST counters: 0", + "PublicDescription": "Counts all software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -748,7 +727,7 @@ "CounterMask": "1", "EventCode": "0xa8", "EventName": "LSD.CYCLES_ACTIVE", - "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector). Available PDIST counters: 0", + "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -758,7 +737,7 @@ "CounterMask": "6", "EventCode": "0xa8", "EventName": "LSD.CYCLES_OK", - "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector). Available PDIST counters: 0", + "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -767,7 +746,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa8", "EventName": "LSD.UOPS", - "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -778,7 +757,7 @@ "EdgeDetect": "1", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.COUNT", - "PublicDescription": "Counts the number of machine clears (nukes) of any type. Available PDIST counters: 0", + "PublicDescription": "Counts the number of machine clears (nukes) of any type.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -787,7 +766,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.SMC", - "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear. Available PDIST counters: 0", + "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -796,7 +775,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe0", "EventName": "MISC2_RETIRED.LFENCE", - "PublicDescription": "number of LFENCE retired instructions Available PDIST counters: 0", + "PublicDescription": "number of LFENCE retired instructions", "SampleAfterValue": "400009", "UMask": "0x20" }, @@ -805,7 +784,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcc", "EventName": "MISC_RETIRED.LBR_INSERTS", - "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT. Available PDIST counters: 0", + "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -814,7 +793,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa2", "EventName": "RESOURCE_STALLS.SB", - "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end. Available PDIST counters: 0", + "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -823,7 +802,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa2", "EventName": "RESOURCE_STALLS.SCOREBOARD", - "PublicDescription": "Counts cycles where the pipeline is stalled due to serializing operations. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -832,7 +810,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa5", "EventName": "RS.EMPTY", - "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses) Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses)", "SampleAfterValue": "1000003", "UMask": "0x7" }, @@ -844,7 +822,7 @@ "EventCode": "0xa5", "EventName": "RS.EMPTY_COUNT", "Invert": "1", - "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events) Available PDIST counters: 0", + "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events)", "SampleAfterValue": "100003", "UMask": "0x7" }, @@ -853,7 +831,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa5", "EventName": "RS.EMPTY_RESOURCE", - "PublicDescription": "Cycles when RS was empty and a resource allocation stall is asserted Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -862,7 +839,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.BACKEND_BOUND_SLOTS", - "PublicDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Backend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method. Available PDIST counters: 0", + "PublicDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Backend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "10000003", "UMask": "0x2" }, @@ -871,7 +848,7 @@ "Counter": "0", "EventCode": "0xa4", "EventName": "TOPDOWN.BAD_SPEC_SLOTS", - "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations. Available PDIST counters: 0", + "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations.", "SampleAfterValue": "10000003", "UMask": "0x4" }, @@ -880,7 +857,7 @@ "Counter": "0", "EventCode": "0xa4", "EventName": "TOPDOWN.BR_MISPREDICT_SLOTS", - "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction. Available PDIST counters: 0", + "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction.", "SampleAfterValue": "10000003", "UMask": "0x8" }, @@ -889,7 +866,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.MEMORY_BOUND_SLOTS", - "PublicDescription": "TOPDOWN.MEMORY_BOUND_SLOTS Available PDIST counters: 0", "SampleAfterValue": "10000003", "UMask": "0x10" }, @@ -897,7 +873,7 @@ "BriefDescription": "TMA slots available for an unhalted logical processor. Fixed counter - architectural event", "Counter": "Fixed counter 3", "EventName": "TOPDOWN.SLOTS", - "PublicDescription": "Number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method (TMA). The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core. Software can use this event as the denominator for the top-level metrics of the TMA method. This architectural event is counted on a designated fixed counter (Fixed Counter 3). Available PDIST counters: 0", + "PublicDescription": "Number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method (TMA). The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core. Software can use this event as the denominator for the top-level metrics of the TMA method. This architectural event is counted on a designated fixed counter (Fixed Counter 3).", "SampleAfterValue": "10000003", "UMask": "0x4" }, @@ -906,7 +882,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.SLOTS_P", - "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core. Available PDIST counters: 0", + "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core.", "SampleAfterValue": "10000003", "UMask": "0x1" }, @@ -915,7 +891,7 @@ "Counter": "0,1,2,3", "EventCode": "0x76", "EventName": "UOPS_DECODED.DEC0_UOPS", - "PublicDescription": "This event counts the number of not dec-by-all uops decoded by decoder 0. Available PDIST counters: 0", + "PublicDescription": "This event counts the number of not dec-by-all uops decoded by decoder 0.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -924,7 +900,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_0", - "PublicDescription": "Number of uops dispatch to execution port 0. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 0.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -933,7 +909,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_1", - "PublicDescription": "Number of uops dispatch to execution port 1. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 1.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -942,7 +918,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_2_3_10", - "PublicDescription": "Number of uops dispatch to execution ports 2, 3 and 10 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 2, 3 and 10", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -951,7 +927,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_4_9", - "PublicDescription": "Number of uops dispatch to execution ports 4 and 9 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 4 and 9", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -960,7 +936,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_5_11", - "PublicDescription": "Number of uops dispatch to execution ports 5 and 11 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 5 and 11", "SampleAfterValue": "2000003", "UMask": "0x20" }, @@ -969,7 +945,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_6", - "PublicDescription": "Number of uops dispatch to execution port 6. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 6.", "SampleAfterValue": "2000003", "UMask": "0x40" }, @@ -978,7 +954,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_7_8", - "PublicDescription": "Number of uops dispatch to execution ports 7 and 8. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 7 and 8.", "SampleAfterValue": "2000003", "UMask": "0x80" }, @@ -987,7 +963,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE", - "PublicDescription": "Counts the number of uops executed from any thread. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops executed from any thread.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -997,7 +973,7 @@ "CounterMask": "1", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_1", - "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -1007,7 +983,7 @@ "CounterMask": "2", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_2", - "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -1017,7 +993,7 @@ "CounterMask": "3", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_3", - "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -1027,7 +1003,7 @@ "CounterMask": "4", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_4", - "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -1037,7 +1013,7 @@ "CounterMask": "1", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_1", - "PublicDescription": "Cycles where at least 1 uop was executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 1 uop was executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1047,7 +1023,7 @@ "CounterMask": "2", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_2", - "PublicDescription": "Cycles where at least 2 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 2 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1057,7 +1033,7 @@ "CounterMask": "3", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_3", - "PublicDescription": "Cycles where at least 3 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 3 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1067,7 +1043,7 @@ "CounterMask": "4", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_4", - "PublicDescription": "Cycles where at least 4 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 4 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1078,7 +1054,7 @@ "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.STALLS", "Invert": "1", - "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1087,7 +1063,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.THREAD", - "PublicDescription": "Counts the number of uops to be executed per-thread each cycle. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1096,7 +1071,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.X87", - "PublicDescription": "Counts the number of x87 uops executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of x87 uops executed.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -1105,7 +1080,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xae", "EventName": "UOPS_ISSUED.ANY", - "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1115,7 +1090,6 @@ "CounterMask": "1", "EventCode": "0xae", "EventName": "UOPS_ISSUED.CYCLES", - "PublicDescription": "UOPS_ISSUED.CYCLES Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1125,7 +1099,7 @@ "CounterMask": "1", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.CYCLES", - "PublicDescription": "Counts cycles where at least one uop has retired. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where at least one uop has retired.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1134,7 +1108,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.HEAVY", - "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count. Available PDIST counters: 0", + "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1145,7 +1119,6 @@ "EventName": "UOPS_RETIRED.MS", "MSRIndex": "0x3F7", "MSRValue": "0x8", - "PublicDescription": "UOPS_RETIRED.MS Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -1154,7 +1127,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.SLOTS", - "PublicDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric. Software can use this event as the numerator for the Retiring metric (or top-level category) of the Top-down Microarchitecture Analysis method. Available PDIST counters: 0", + "PublicDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric. Software can use this event as the numerator for the Retiring metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -1165,7 +1138,7 @@ "EventCode": "0xc2", "EventName": "UOPS_RETIRED.STALLS", "Invert": "1", - "PublicDescription": "This event counts cycles without actually retired uops. Available PDIST counters: 0", + "PublicDescription": "This event counts cycles without actually retired uops.", "SampleAfterValue": "1000003", "UMask": "0x2" } diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-io.json b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-io.json index f4f956966e16..2ea2637df3fb 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-io.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-io.json @@ -1321,7 +1321,6 @@ "FCMask": "0x01", "PerPkg": "1", "PortMask": "0x0FF", - "PublicDescription": "-", "UMask": "0x4", "Unit": "IIO" }, diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json index b991f6e1afbe..9d385be59e3d 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json @@ -195,7 +195,6 @@ "EventName": "UNC_M_MR4_2XREF_CYCLES.SCH0_DIMM0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -206,7 +205,6 @@ "EventName": "UNC_M_MR4_2XREF_CYCLES.SCH0_DIMM1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -217,7 +215,6 @@ "EventName": "UNC_M_MR4_2XREF_CYCLES.SCH1_DIMM0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x4", "Unit": "IMC" }, @@ -228,7 +225,6 @@ "EventName": "UNC_M_MR4_2XREF_CYCLES.SCH1_DIMM1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x8", "Unit": "IMC" }, @@ -239,7 +235,6 @@ "EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH0_DIMM0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -250,7 +245,6 @@ "EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH0_DIMM1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -261,7 +255,6 @@ "EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH1_DIMM0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x4", "Unit": "IMC" }, @@ -272,7 +265,6 @@ "EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH1_DIMM1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x8", "Unit": "IMC" }, @@ -283,7 +275,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -294,7 +285,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -305,7 +295,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK2", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x4", "Unit": "IMC" }, @@ -316,7 +305,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK3", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x8", "Unit": "IMC" }, @@ -327,7 +315,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x10", "Unit": "IMC" }, @@ -338,7 +325,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x20", "Unit": "IMC" }, @@ -349,7 +335,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK2", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x40", "Unit": "IMC" }, @@ -360,7 +345,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK3", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x80", "Unit": "IMC" }, @@ -371,7 +355,6 @@ "EventName": "UNC_M_POWER_CHANNEL_PPD_CYCLES", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "Unit": "IMC" }, { @@ -381,7 +364,6 @@ "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES.SLOT0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -392,7 +374,6 @@ "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES.SLOT1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -423,7 +404,6 @@ "EventName": "UNC_M_POWER_THROTTLE_CYCLES.MR4BLKEN", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x8", "Unit": "IMC" }, @@ -434,7 +414,6 @@ "EventName": "UNC_M_POWER_THROTTLE_CYCLES.RAPLBLK", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x4", "Unit": "IMC" }, @@ -615,7 +594,6 @@ "EventName": "UNC_M_SELF_REFRESH.ENTER_SUCCESS", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "UNC_M_SELF_REFRESH.ENTER_SUCCESS", "UMask": "0x2", "Unit": "IMC" }, @@ -626,7 +604,6 @@ "EventName": "UNC_M_SELF_REFRESH.ENTER_SUCCESS_CYCLES", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -637,7 +614,6 @@ "EventName": "UNC_M_THROTTLE_CRIT_CYCLES.SLOT0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -648,7 +624,6 @@ "EventName": "UNC_M_THROTTLE_CRIT_CYCLES.SLOT1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -659,7 +634,6 @@ "EventName": "UNC_M_THROTTLE_HIGH_CYCLES.SLOT0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -670,7 +644,6 @@ "EventName": "UNC_M_THROTTLE_HIGH_CYCLES.SLOT1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -681,7 +654,6 @@ "EventName": "UNC_M_THROTTLE_LOW_CYCLES.SLOT0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -692,7 +664,6 @@ "EventName": "UNC_M_THROTTLE_LOW_CYCLES.SLOT1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -703,7 +674,6 @@ "EventName": "UNC_M_THROTTLE_MID_CYCLES.SLOT0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -714,7 +684,6 @@ "EventName": "UNC_M_THROTTLE_MID_CYCLES.SLOT1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/virtual-memory.json b/tools/perf/pmu-events/arch/x86/graniterapids/virtual-memory.json index 3d3f88600e26..609a9549cbf3 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/virtual-memory.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/virtual-memory.json @@ -4,7 +4,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.STLB_HIT", - "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB).", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -14,7 +14,7 @@ "CounterMask": "1", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -23,7 +23,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe" }, @@ -32,7 +32,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_1G", - "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -41,7 +41,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -50,7 +50,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -59,7 +59,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -68,7 +68,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.STLB_HIT", - "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB).", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -78,7 +78,7 @@ "CounterMask": "1", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -87,7 +87,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe" }, @@ -96,7 +96,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_1G", - "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -105,7 +105,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -114,7 +114,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -123,7 +123,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -132,7 +132,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.STLB_HIT", - "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB).", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -142,7 +142,7 @@ "CounterMask": "1", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -151,7 +151,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe" }, @@ -160,7 +160,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -169,7 +169,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -178,7 +178,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10" } diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index e3ac2dede20a..2d7a9fa055dd 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -13,7 +13,7 @@ GenuineIntel-6-CF,v1.16,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core GenuineIntel-6-B6,v1.09,grandridge,core -GenuineIntel-6-A[DE],v1.10,graniterapids,core +GenuineIntel-6-A[DE],v1.12,graniterapids,core GenuineIntel-6-(3C|45|46),v36,haswell,core GenuineIntel-6-3F,v29,haswellx,core GenuineIntel-6-7[DE],v1.24,icelake,core From 7fcaead09f74bacfbf9433a9b843b8f93f83e3c7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:05 -0700 Subject: [PATCH 0854/2711] perf vendor events: Update haswell metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-10-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/haswell/hsw-metrics.json | 32 ++++++++--------- .../arch/x86/haswellx/hsx-metrics.json | 35 +++++++++---------- 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json b/tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json index b26ea70a3628..aebd82ced1cf 100644 --- a/tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json +++ b/tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -80,7 +80,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_0 + UOPS_DISPATCHED_PORT.PORT_1 + UOPS_DISPATCHED_PORT.PORT_5 + UOPS_DISPATCHED_PORT.PORT_6) / tma_info_thread_slots", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_alu_op_utilization", @@ -98,7 +97,6 @@ }, { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "1 - (tma_frontend_bound + tma_bad_speculation + tma_retiring)", "MetricGroup": "BvOB;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", @@ -139,7 +137,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU retired uops originated from CISC (complex instruction set computer) instruction", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "max(0, tma_microcode_sequencer - tma_assists)", "MetricGroup": "TopdownL4;tma_L4_group;tma_microcode_sequencer_group", "MetricName": "tma_cisc", @@ -509,7 +506,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -521,7 +518,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -696,7 +693,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_2 + UOPS_DISPATCHED_PORT.PORT_3 + UOPS_DISPATCHED_PORT.PORT_7 - UOPS_DISPATCHED_PORT.PORT_4) / (2 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", @@ -746,7 +742,7 @@ { "BriefDescription": "This metric represents fraction of slots the Memory subsystem within the Backend was a bottleneck", "MetricConstraint": "NO_GROUP_EVENTS", - "MetricExpr": "((min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.STALLS_LDM_PENDING) + RESOURCE_STALLS.SB) / (min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@)) / 2 - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB) if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB) * tma_backend_bound", + "MetricExpr": "(min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.STALLS_LDM_PENDING) + RESOURCE_STALLS.SB) / (min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@)) / 2 - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB) * tma_backend_bound", "MetricGroup": "Backend;TmaL2;TopdownL2;tma_L2_group;tma_backend_bound_group", "MetricName": "tma_memory_bound", "MetricThreshold": "tma_memory_bound > 0.2 & tma_backend_bound > 0.2", @@ -856,7 +852,7 @@ { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", "MetricConstraint": "NO_GROUP_EVENTS", - "MetricExpr": "(min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@)) / 2 - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB - RESOURCE_STALLS.SB - min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.STALLS_LDM_PENDING)) / tma_info_thread_clks", + "MetricExpr": "((min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@)) / 2 - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB) - RESOURCE_STALLS.SB - min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.STALLS_LDM_PENDING)) / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", "MetricThreshold": "tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2)", @@ -865,7 +861,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else (min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks)", + "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", "MetricThreshold": "tma_ports_utilized_0 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -874,7 +870,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", "MetricThreshold": "tma_ports_utilized_1 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -883,7 +879,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else (cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", "MetricThreshold": "tma_ports_utilized_2 > 0.15 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", diff --git a/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json b/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json index 8245a98ad4b9..b8845f8a28b9 100644 --- a/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -282,7 +282,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_0 + UOPS_DISPATCHED_PORT.PORT_1 + UOPS_DISPATCHED_PORT.PORT_5 + UOPS_DISPATCHED_PORT.PORT_6) / tma_info_thread_slots", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_alu_op_utilization", @@ -300,7 +299,6 @@ }, { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "1 - (tma_frontend_bound + tma_bad_speculation + tma_retiring)", "MetricGroup": "BvOB;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", @@ -341,7 +339,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU retired uops originated from CISC (complex instruction set computer) instruction", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "max(0, tma_microcode_sequencer - tma_assists)", "MetricGroup": "TopdownL4;tma_L4_group;tma_microcode_sequencer_group", "MetricName": "tma_cisc", @@ -711,7 +708,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -723,7 +720,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -756,6 +753,7 @@ }, { "BriefDescription": "Average number of parallel data read requests to external memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "UNC_C_TOR_OCCUPANCY.MISS_OPCODE@filter_opc\\=0x182@ / UNC_C_TOR_OCCUPANCY.MISS_OPCODE@filter_opc\\=0x182\\,thresh\\=1@", "MetricGroup": "Mem;MemoryBW;SoC", "MetricName": "tma_info_system_mem_parallel_reads", @@ -918,7 +916,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_2 + UOPS_DISPATCHED_PORT.PORT_3 + UOPS_DISPATCHED_PORT.PORT_7 - UOPS_DISPATCHED_PORT.PORT_4) / (2 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", @@ -928,6 +925,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from local memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "200 * (MEM_LOAD_UOPS_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_UOPS_RETIRED.HIT_LFB / (MEM_LOAD_UOPS_RETIRED.L2_HIT + MEM_LOAD_UOPS_RETIRED.L3_HIT + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HITM + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_MISS + MEM_LOAD_UOPS_L3_MISS_RETIRED.LOCAL_DRAM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_DRAM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_HITM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_FWD))) / tma_info_thread_clks", "MetricGroup": "Server;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_local_mem", @@ -977,7 +975,7 @@ { "BriefDescription": "This metric represents fraction of slots the Memory subsystem within the Backend was a bottleneck", "MetricConstraint": "NO_GROUP_EVENTS", - "MetricExpr": "((min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.STALLS_LDM_PENDING) + RESOURCE_STALLS.SB) / (min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@)) / 2 - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB) if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB) * tma_backend_bound", + "MetricExpr": "(min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.STALLS_LDM_PENDING) + RESOURCE_STALLS.SB) / (min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@)) / 2 - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB) * tma_backend_bound", "MetricGroup": "Backend;TmaL2;TopdownL2;tma_L2_group;tma_backend_bound_group", "MetricName": "tma_memory_bound", "MetricThreshold": "tma_memory_bound > 0.2 & tma_backend_bound > 0.2", @@ -1087,7 +1085,7 @@ { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", "MetricConstraint": "NO_GROUP_EVENTS", - "MetricExpr": "(min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@)) / 2 - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB - RESOURCE_STALLS.SB - min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.STALLS_LDM_PENDING)) / tma_info_thread_clks", + "MetricExpr": "((min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@)) / 2 - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) + cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - (cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@ if tma_info_thread_ipc > 1.8 else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0) + RESOURCE_STALLS.SB) - RESOURCE_STALLS.SB - min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.STALLS_LDM_PENDING)) / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", "MetricThreshold": "tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2)", @@ -1096,7 +1094,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else (min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks)", + "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", "MetricThreshold": "tma_ports_utilized_0 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1105,7 +1103,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", "MetricThreshold": "tma_ports_utilized_1 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1114,7 +1112,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else (cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", "MetricThreshold": "tma_ports_utilized_2 > 0.15 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1141,6 +1139,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "310 * (MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_UOPS_RETIRED.HIT_LFB / (MEM_LOAD_UOPS_RETIRED.L2_HIT + MEM_LOAD_UOPS_RETIRED.L3_HIT + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HITM + MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_MISS + MEM_LOAD_UOPS_L3_MISS_RETIRED.LOCAL_DRAM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_DRAM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_HITM + MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_FWD))) / tma_info_thread_clks", "MetricGroup": "Server;Snoop;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_remote_mem", From 55b3a5a7a7d124980289a8fcbe8878975b683574 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:06 -0700 Subject: [PATCH 0855/2711] perf vendor events: Update icelake metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-11-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/icelake/icl-metrics.json | 104 +++++++----- .../arch/x86/icelakex/icx-metrics.json | 159 +++++++++++++----- 2 files changed, 175 insertions(+), 88 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/icelake/icl-metrics.json b/tools/perf/pmu-events/arch/x86/icelake/icl-metrics.json index c5bfdb2f288b..cf9ed3edb694 100644 --- a/tools/perf/pmu-events/arch/x86/icelake/icl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/icelake/icl-metrics.json @@ -1,63 +1,63 @@ [ { "BriefDescription": "C10 residency percent per package", - "MetricExpr": "cstate_pkg@c10\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c10\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C10_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C8 residency percent per package", - "MetricExpr": "cstate_pkg@c8\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c8\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C8_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C9 residency percent per package", - "MetricExpr": "cstate_pkg@c9\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c9\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C9_Pkg_Residency", "ScaleUnit": "100%" @@ -85,7 +85,6 @@ }, { "BriefDescription": "This metric estimates how often memory load accesses were aliased by preceding stores (in program order) with a 4K address offset", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_4k_aliasing", @@ -134,6 +133,7 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch related bottlenecks by large code footprint programs (i-side cache; TLB and BTB misses)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_fetch_latency * (tma_itlb_misses + tma_icache_misses + tma_unknown_branches) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)", "MetricGroup": "BigFootprint;BvBC;Fed;Frontend;IcMiss;MemoryTLB", "MetricName": "tma_bottleneck_big_code", @@ -147,40 +147,45 @@ "MetricThreshold": "tma_bottleneck_branching_overhead > 5", "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", "MetricGroup": "BvCB;Cor;tma_issueComp", "MetricName": "tma_bottleneck_compute_bound_est", "MetricThreshold": "tma_bottleneck_compute_bound_est > 20", "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: " }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20" }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -188,6 +193,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", @@ -196,6 +202,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", @@ -204,6 +211,7 @@ }, { "BriefDescription": "Total pipeline cost of Branch Misprediction related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * (tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Bad;BadSpec;BrMispredicts;BvMP;tma_issueBM", "MetricName": "tma_bottleneck_mispredictions", @@ -212,7 +220,8 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -220,6 +229,7 @@ }, { "BriefDescription": "Total pipeline cost of \"useful operations\" - the portion of Retiring category not covered by Branching_Overhead nor Irregular_Overhead.", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_retiring - (BR_INST_RETIRED.ALL_BRANCHES + 2 * BR_INST_RETIRED.NEAR_CALL + INST_RETIRED.NOP) / tma_info_thread_slots - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "BvUW;Ret", "MetricName": "tma_bottleneck_useful_work", @@ -427,7 +437,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%" }, { @@ -619,6 +629,7 @@ }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) hits - subset of the Instruction_Fetch_BW Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound * (tma_fetch_bandwidth / (tma_fetch_bandwidth + tma_fetch_latency)) * (tma_dsb / (tma_dsb + tma_lsd + tma_mite + tma_ms)))", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_botlnk_l2_dsb_bandwidth", @@ -1068,7 +1079,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1091,6 +1102,12 @@ "MetricGroup": "Fed;FetchBW", "MetricName": "tma_info_pipeline_fetch_mite" }, + { + "BriefDescription": "Average number of uops fetched from MS per cycle", + "MetricExpr": "IDQ.MS_UOPS / cpu@IDQ.MS_UOPS\\,cmask\\=1@", + "MetricGroup": "Fed;FetchLat;MicroSeq", + "MetricName": "tma_info_pipeline_fetch_ms" + }, { "BriefDescription": "Instructions per a microcode Assist invocation", "MetricExpr": "INST_RETIRED.ANY / ASSISTS.ANY", @@ -1107,7 +1124,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -1119,7 +1136,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -1128,7 +1145,7 @@ "MetricExpr": "64 * (UNC_ARB_TRK_REQUESTS.ALL + UNC_ARB_COH_TRK_REQUESTS.ALL) / 1e6 / tma_info_system_time / 1e3", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1296,12 +1313,12 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", "MetricExpr": "min(2 * (MEM_INST_RETIRED.ALL_LOADS - MEM_LOAD_RETIRED.FB_HIT - MEM_LOAD_RETIRED.L1_MISS) * 20 / 100, max(CYCLE_ACTIVITY.CYCLES_MEM_ANY - CYCLE_ACTIVITY.CYCLES_L1D_MISS, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%" }, { @@ -1325,7 +1342,6 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(CYCLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS) / tma_info_thread_clks", "MetricGroup": "CacheHits;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -1339,7 +1355,7 @@ "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, { @@ -1445,7 +1461,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%" }, { @@ -1454,7 +1470,7 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, { @@ -1522,7 +1538,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "cpu@IDQ.MS_UOPS\\,cmask\\=1@ / tma_info_core_core_clks / 2", + "MetricExpr": "cpu@IDQ.MS_UOPS\\,cmask\\=1@ / tma_info_core_core_clks / 3.3", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -1656,7 +1672,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -1693,7 +1709,6 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -1707,7 +1722,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%" }, { @@ -1721,7 +1736,6 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * LD_BLOCKS.STORE_FORWARD / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", diff --git a/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json b/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json index a886a0cfee07..f58eec2a1788 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json @@ -1,28 +1,28 @@ [ { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" @@ -78,6 +78,12 @@ "MetricName": "io_bandwidth_read", "ScaleUnit": "1MB/s" }, + { + "BriefDescription": "Bandwidth of inbound IO reads that are initiated by end device controllers that are requesting memory from the CPU and miss the L3 cache", + "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_MISS_PCIRDCUR * 64 / 1e6 / duration_time", + "MetricName": "io_bandwidth_read_l3_miss", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Bandwidth of IO reads that are initiated by end device controllers that are requesting memory from the local CPU socket", "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_LOCAL * 64 / 1e6 / duration_time", @@ -96,6 +102,12 @@ "MetricName": "io_bandwidth_write", "ScaleUnit": "1MB/s" }, + { + "BriefDescription": "Bandwidth of inbound IO writes that are initiated by end device controllers that are writing memory to the CPU", + "MetricExpr": "(UNC_CHA_TOR_INSERTS.IO_MISS_ITOM + UNC_CHA_TOR_INSERTS.IO_MISS_ITOMCACHENEAR) * 64 / 1e6 / duration_time", + "MetricName": "io_bandwidth_write_l3_miss", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Bandwidth of IO writes that are initiated by end device controllers that are writing memory to the local CPU socket", "MetricExpr": "(UNC_CHA_TOR_INSERTS.IO_ITOM_LOCAL + UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR_LOCAL) * 64 / 1e6 / duration_time", @@ -108,6 +120,24 @@ "MetricName": "io_bandwidth_write_remote", "ScaleUnit": "1MB/s" }, + { + "BriefDescription": "The percent of inbound full cache line writes initiated by IO that miss the L3 cache", + "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_MISS_ITOM / UNC_CHA_TOR_INSERTS.IO_ITOM", + "MetricName": "io_full_write_l3_miss", + "ScaleUnit": "100%" + }, + { + "BriefDescription": "The percent of inbound partial writes initiated by IO that miss the L3 cache", + "MetricExpr": "(UNC_CHA_TOR_INSERTS.IO_MISS_ITOMCACHENEAR + UNC_CHA_TOR_INSERTS.IO_MISS_RFO) / (UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR + UNC_CHA_TOR_INSERTS.IO_RFO)", + "MetricName": "io_partial_write_l3_miss", + "ScaleUnit": "100%" + }, + { + "BriefDescription": "The percent of inbound reads initiated by IO that miss the L3 cache", + "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_MISS_PCIRDCUR / UNC_CHA_TOR_INSERTS.IO_PCIRDCUR", + "MetricName": "io_read_l3_miss", + "ScaleUnit": "100%" + }, { "BriefDescription": "Ratio of number of completed page walks (for 2 megabyte and 4 megabyte page sizes) caused by a code fetch to the total number of completed instructions", "MetricExpr": "ITLB_MISSES.WALK_COMPLETED_2M_4M / INST_RETIRED.ANY", @@ -331,7 +361,6 @@ }, { "BriefDescription": "This metric estimates how often memory load accesses were aliased by preceding stores (in program order) with a 4K address offset", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_4k_aliasing", @@ -380,6 +409,7 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch related bottlenecks by large code footprint programs (i-side cache; TLB and BTB misses)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_fetch_latency * (tma_itlb_misses + tma_icache_misses + tma_unknown_branches) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)", "MetricGroup": "BigFootprint;BvBC;Fed;Frontend;IcMiss;MemoryTLB", "MetricName": "tma_bottleneck_big_code", @@ -393,40 +423,45 @@ "MetricThreshold": "tma_bottleneck_branching_overhead > 5", "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", "MetricGroup": "BvCB;Cor;tma_issueComp", "MetricName": "tma_bottleneck_compute_bound_est", "MetricThreshold": "tma_bottleneck_compute_bound_est > 20", "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: " }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20" }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -434,7 +469,8 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -442,7 +478,8 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", "MetricThreshold": "tma_bottleneck_memory_synchronization > 10", @@ -450,6 +487,7 @@ }, { "BriefDescription": "Total pipeline cost of Branch Misprediction related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * (tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Bad;BadSpec;BrMispredicts;BvMP;tma_issueBM", "MetricName": "tma_bottleneck_mispredictions", @@ -458,7 +496,8 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -466,6 +505,7 @@ }, { "BriefDescription": "Total pipeline cost of \"useful operations\" - the portion of Retiring category not covered by Branching_Overhead nor Irregular_Overhead.", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_retiring - (BR_INST_RETIRED.ALL_BRANCHES + 2 * BR_INST_RETIRED.NEAR_CALL + INST_RETIRED.NOP) / tma_info_thread_slots - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "BvUW;Ret", "MetricName": "tma_bottleneck_useful_work", @@ -584,6 +624,15 @@ "PublicDescription": "This metric represents fraction of slots where Core non-memory issues were of a bottleneck. Shortage in hardware compute resources; or dependencies in software's instructions are both categorized under Core Bound. Hence it may indicate the machine ran out of an out-of-order resource; certain execution units are overloaded or dependencies in program's data- or instruction-flow are limiting the performance (e.g. FP-chained long-latency arithmetic operations).", "ScaleUnit": "100%" }, + { + "BriefDescription": "This metric roughly estimates (based on idle latencies) how often the CPU was stalled on accesses to external CXL Memory by loads (e.g", + "MetricExpr": "(((1 - ((19 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + 10 * (MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS))) / (19 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + 10 * (MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + (25 * (MEM_LOAD_RETIRED.LOCAL_PMM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) if #has_pmem > 0 else 0) + 33 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_PMM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) if #has_pmem > 0 else 0))) if #has_pmem > 0 else 1)) * (CYCLE_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks + (CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS) / tma_info_thread_clks - tma_l2_bound) if 1e6 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_PMM + MEM_LOAD_RETIRED.LOCAL_PMM) > MEM_LOAD_RETIRED.L1_MISS else 0) if #has_pmem > 0 else 0)", + "MetricGroup": "MemoryBound;Server;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", + "MetricName": "tma_cxl_mem_bound", + "MetricThreshold": "tma_cxl_mem_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", + "PublicDescription": "This metric roughly estimates (based on idle latencies) how often the CPU was stalled on accesses to external CXL Memory by loads (e.g. 3D-Xpoint (Crystal Ridge, a.k.a. IXP) memory, PMM - Persistent Memory Module [from CLX to SPR] or any other CXL Type3 Memory [EMR onwards]).", + "ScaleUnit": "100%" + }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", "MetricConstraint": "NO_GROUP_EVENTS", @@ -615,7 +664,7 @@ { "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", "MetricConstraint": "NO_GROUP_EVENTS", - "MetricExpr": "CYCLE_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks + (CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS) / tma_info_thread_clks - tma_l2_bound", + "MetricExpr": "(CYCLE_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks + (CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS) / tma_info_thread_clks - tma_l2_bound - tma_cxl_mem_bound if #has_pmem > 0 else CYCLE_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks + (CYCLE_ACTIVITY.STALLS_L1D_MISS - CYCLE_ACTIVITY.STALLS_L2_MISS) / tma_info_thread_clks - tma_l2_bound)", "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_dram_bound", "MetricThreshold": "tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", @@ -673,7 +722,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%" }, { @@ -865,6 +914,7 @@ }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) hits - subset of the Instruction_Fetch_BW Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound * (tma_fetch_bandwidth / (tma_fetch_bandwidth + tma_fetch_latency)) * (tma_dsb / (tma_dsb + tma_mite + tma_ms)))", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_botlnk_l2_dsb_bandwidth", @@ -1320,7 +1370,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1337,6 +1387,12 @@ "MetricGroup": "Fed;FetchBW", "MetricName": "tma_info_pipeline_fetch_mite" }, + { + "BriefDescription": "Average number of uops fetched from MS per cycle", + "MetricExpr": "IDQ.MS_UOPS / cpu@IDQ.MS_UOPS\\,cmask\\=1@", + "MetricGroup": "Fed;FetchLat;MicroSeq", + "MetricName": "tma_info_pipeline_fetch_ms" + }, { "BriefDescription": "Instructions per a microcode Assist invocation", "MetricExpr": "INST_RETIRED.ANY / ASSISTS.ANY", @@ -1353,7 +1409,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -1365,16 +1421,28 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, + { + "BriefDescription": "Average 3DXP Memory Bandwidth Use for reads [GB / sec]", + "MetricExpr": "(64 * UNC_M_PMM_RPQ_INSERTS / 1e9 / tma_info_system_time if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryBW;Server;SoC", + "MetricName": "tma_info_system_cxl_mem_read_bw" + }, + { + "BriefDescription": "Average 3DXP Memory Bandwidth Use for Writes [GB / sec]", + "MetricExpr": "(64 * UNC_M_PMM_WPQ_INSERTS / 1e9 / tma_info_system_time if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryBW;Server;SoC", + "MetricName": "tma_info_system_cxl_mem_write_bw" + }, { "BriefDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]", "MetricExpr": "64 * (UNC_M_CAS_COUNT.RD + UNC_M_CAS_COUNT.WR) / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1433,11 +1501,19 @@ }, { "BriefDescription": "Average number of parallel data read requests to external memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD / UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD@thresh\\=1@", "MetricGroup": "Mem;MemoryBW;SoC", "MetricName": "tma_info_system_mem_parallel_reads", "PublicDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches" }, + { + "BriefDescription": "Average latency of data read request to external 3D X-Point memory [in nanoseconds]", + "MetricExpr": "(1e9 * (UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD_PMM / UNC_CHA_TOR_INSERTS.IA_MISS_DRD_PMM) / cha_0@event\\=0x0@ if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryLat;Server;SoC", + "MetricName": "tma_info_system_mem_pmm_read_latency", + "PublicDescription": "Average latency of data read request to external 3D X-Point memory [in nanoseconds]. Accounts for demand loads and L1/L2 data-read prefetches" + }, { "BriefDescription": "Average latency of data read request to external memory (in nanoseconds)", "MetricExpr": "1e9 * (UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD / UNC_CHA_TOR_INSERTS.IA_MISS_DRD) / (tma_info_system_socket_clks / tma_info_system_time)", @@ -1590,12 +1666,12 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", "MetricExpr": "min(2 * (MEM_INST_RETIRED.ALL_LOADS - MEM_LOAD_RETIRED.FB_HIT - MEM_LOAD_RETIRED.L1_MISS) * 20 / 100, max(CYCLE_ACTIVITY.CYCLES_MEM_ANY - CYCLE_ACTIVITY.CYCLES_L1D_MISS, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%" }, { @@ -1619,7 +1695,6 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(CYCLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS) / tma_info_thread_clks", "MetricGroup": "CacheHits;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -1633,7 +1708,7 @@ "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, { @@ -1739,7 +1814,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%" }, { @@ -1748,7 +1823,7 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, { @@ -1816,7 +1891,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "cpu@IDQ.MS_UOPS\\,cmask\\=1@ / tma_info_core_core_clks / 2", + "MetricExpr": "cpu@IDQ.MS_UOPS\\,cmask\\=1@ / tma_info_core_core_clks / 3.3", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -1968,7 +2043,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -2005,7 +2080,6 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -2019,7 +2093,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%" }, { @@ -2033,7 +2107,6 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * LD_BLOCKS.STORE_FORWARD / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", From 48a194efa00730a88044f8df300cf8bbfa891449 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:07 -0700 Subject: [PATCH 0856/2711] perf vendor events: Update ivybridge/ivytown metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-12-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/ivybridge/ivb-metrics.json | 30 ++++++++--------- .../arch/x86/ivytown/ivt-metrics.json | 33 +++++++++---------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json b/tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json index de651ff9f846..969cb519eec1 100644 --- a/tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json +++ b/tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -80,7 +80,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_0 + UOPS_DISPATCHED_PORT.PORT_1 + UOPS_DISPATCHED_PORT.PORT_5) / (3 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_alu_op_utilization", @@ -98,7 +97,6 @@ }, { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "1 - (tma_frontend_bound + tma_bad_speculation + tma_retiring)", "MetricGroup": "BvOB;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", @@ -139,7 +137,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU retired uops originated from CISC (complex instruction set computer) instruction", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "max(0, tma_microcode_sequencer - tma_assists)", "MetricGroup": "TopdownL4;tma_L4_group;tma_microcode_sequencer_group", "MetricName": "tma_cisc", @@ -561,7 +558,7 @@ "MetricThreshold": "tma_info_memory_tlb_page_walks_utilization > 0.5" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -574,7 +571,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -586,7 +583,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -775,7 +772,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_2 + UOPS_DISPATCHED_PORT.PORT_3 - UOPS_DISPATCHED_PORT.PORT_4) / (2 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", @@ -926,7 +922,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else (min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks)", + "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", "MetricThreshold": "tma_ports_utilized_0 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -935,7 +931,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else (UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", "MetricThreshold": "tma_ports_utilized_1 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -944,7 +940,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else (UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC - UOPS_EXECUTED.CYCLES_GE_3_UOPS_EXEC) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC - UOPS_EXECUTED.CYCLES_GE_3_UOPS_EXEC) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", "MetricThreshold": "tma_ports_utilized_2 > 0.15 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", diff --git a/tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json b/tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json index 714d5e6d21e7..1cdd197ac883 100644 --- a/tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json +++ b/tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -80,7 +80,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_0 + UOPS_DISPATCHED_PORT.PORT_1 + UOPS_DISPATCHED_PORT.PORT_5) / (3 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_alu_op_utilization", @@ -98,7 +97,6 @@ }, { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "1 - (tma_frontend_bound + tma_bad_speculation + tma_retiring)", "MetricGroup": "BvOB;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", @@ -139,7 +137,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU retired uops originated from CISC (complex instruction set computer) instruction", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "max(0, tma_microcode_sequencer - tma_assists)", "MetricGroup": "TopdownL4;tma_L4_group;tma_microcode_sequencer_group", "MetricName": "tma_cisc", @@ -561,7 +558,7 @@ "MetricThreshold": "tma_info_memory_tlb_page_walks_utilization > 0.5" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -574,7 +571,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -586,7 +583,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -626,6 +623,7 @@ }, { "BriefDescription": "Average number of parallel data read requests to external memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "UNC_C_TOR_OCCUPANCY.MISS_OPCODE@filter_opc\\=0x182@ / UNC_C_TOR_OCCUPANCY.MISS_OPCODE@filter_opc\\=0x182\\,thresh\\=1@", "MetricGroup": "Mem;MemoryBW;SoC", "MetricName": "tma_info_system_mem_parallel_reads", @@ -795,7 +793,6 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_2 + UOPS_DISPATCHED_PORT.PORT_3 - UOPS_DISPATCHED_PORT.PORT_4) / (2 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", @@ -805,6 +802,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from local memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "200 * (MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_UOPS_RETIRED.HIT_LFB / (MEM_LOAD_UOPS_RETIRED.L2_HIT + MEM_LOAD_UOPS_RETIRED.LLC_HIT + MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT + MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM + MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS + MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM + MEM_LOAD_UOPS_LLC_MISS_RETIRED.REMOTE_DRAM + MEM_LOAD_UOPS_LLC_MISS_RETIRED.REMOTE_HITM + MEM_LOAD_UOPS_LLC_MISS_RETIRED.REMOTE_FWD))) / tma_info_thread_clks", "MetricGroup": "Server;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_local_mem", @@ -955,7 +953,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else (min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks)", + "MetricExpr": "(cpu@UOPS_EXECUTED.CORE\\,inv\\,cmask\\=1@ / 2 if #SMT_on else min(CPU_CLK_UNHALTED.THREAD, CYCLE_ACTIVITY.CYCLES_NO_EXECUTE) - (RS_EVENTS.EMPTY_CYCLES if tma_fetch_latency > 0.1 else 0)) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", "MetricThreshold": "tma_ports_utilized_0 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -964,7 +962,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else (UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@) / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC - UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", "MetricThreshold": "tma_ports_utilized_1 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -973,7 +971,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else (UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC - UOPS_EXECUTED.CYCLES_GE_3_UOPS_EXEC) / tma_info_core_core_clks)", + "MetricExpr": "((cpu@UOPS_EXECUTED.CORE\\,cmask\\=2@ - cpu@UOPS_EXECUTED.CORE\\,cmask\\=3@) / 2 if #SMT_on else UOPS_EXECUTED.CYCLES_GE_2_UOPS_EXEC - UOPS_EXECUTED.CYCLES_GE_3_UOPS_EXEC) / tma_info_core_core_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", "MetricThreshold": "tma_ports_utilized_2 > 0.15 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -1000,6 +998,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling loads from remote memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "310 * (MEM_LOAD_UOPS_LLC_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_UOPS_RETIRED.HIT_LFB / (MEM_LOAD_UOPS_RETIRED.L2_HIT + MEM_LOAD_UOPS_RETIRED.LLC_HIT + MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT + MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM + MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS + MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM + MEM_LOAD_UOPS_LLC_MISS_RETIRED.REMOTE_DRAM + MEM_LOAD_UOPS_LLC_MISS_RETIRED.REMOTE_HITM + MEM_LOAD_UOPS_LLC_MISS_RETIRED.REMOTE_FWD))) / tma_info_thread_clks", "MetricGroup": "Server;Snoop;TopdownL5;tma_L5_group;tma_mem_latency_group", "MetricName": "tma_remote_mem", From 3fdb4ffe6505a8fd79be61bbd001413227964d97 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:08 -0700 Subject: [PATCH 0857/2711] perf vendor events: Update jaketown metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-13-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/jaketown/jkt-metrics.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json b/tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json index 6f636ea0f216..250c73b21385 100644 --- a/tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json +++ b/tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -71,7 +71,6 @@ }, { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "1 - (tma_frontend_bound + tma_bad_speculation + tma_retiring)", "MetricGroup": "BvOB;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", @@ -296,7 +295,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -308,7 +307,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -348,6 +347,7 @@ }, { "BriefDescription": "Average number of parallel data read requests to external memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "UNC_C_TOR_OCCUPANCY.MISS_OPCODE@filter_opc\\=0x182@ / UNC_C_TOR_OCCUPANCY.MISS_OPCODE@filter_opc\\=0x182\\,thresh\\=1@", "MetricGroup": "Mem;MemoryBW;SoC", "MetricName": "tma_info_system_mem_parallel_reads", From 4a0ca7230d91171cf24470be135263165f83b9ed Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:09 -0700 Subject: [PATCH 0858/2711] perf vendor events: Update lunarlake events/metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update events from v1.14 to v1.17. Update metrics from TMA 5.0 to 5.1. The event updates come from: https://github.com/intel/perfmon/commit/6bdcbce3e9df30ae02bd0ea51fd73bf51ee8aff4 https://github.com/intel/perfmon/commit/1684fa543fd45970759bb72dc3fc00c2ef87c0e8 Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-14-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/x86/lunarlake/cache.json | 104 ++++++-- .../arch/x86/lunarlake/frontend.json | 40 ++-- .../arch/x86/lunarlake/lnl-metrics.json | 222 ++++++++++-------- .../pmu-events/arch/x86/lunarlake/memory.json | 22 +- .../arch/x86/lunarlake/pipeline.json | 85 ++++--- .../x86/lunarlake/uncore-interconnect.json | 10 + .../arch/x86/lunarlake/uncore-memory.json | 8 + tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 8 files changed, 297 insertions(+), 196 deletions(-) create mode 100644 tools/perf/pmu-events/arch/x86/lunarlake/uncore-interconnect.json diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/cache.json b/tools/perf/pmu-events/arch/x86/lunarlake/cache.json index ff37d49611c3..29bcb847178f 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/cache.json @@ -28,6 +28,16 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Cachelines replaced into the L1 d-cache. Successful replacements only (not blocked) and exclude WB-miss case", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x51", + "EventName": "L1D.L1_REPLACEMENT", + "PublicDescription": "Counts cachelines replaced into the L1 d-cache.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, { "BriefDescription": "Cachelines replaced into the L0 and L1 d-cache. Successful replacements only (not blocked) and exclude WB-miss case", "Counter": "0,1,2,3,4,5,6,7,8,9", @@ -592,7 +602,7 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.ALL_LOADS", - "PublicDescription": "Counts Instructions with at least one architecturally visible load retired. Available PDIST counters: 0", + "PublicDescription": "Counts Instructions with at least one architecturally visible load retired. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x81", "Unit": "cpu_core" @@ -603,7 +613,7 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.ALL_STORES", - "PublicDescription": "Counts all retired store instructions. Available PDIST counters: 0", + "PublicDescription": "Counts all retired store instructions. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x82", "Unit": "cpu_core" @@ -613,7 +623,7 @@ "Counter": "0,1,2,3", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.ALL_SWPF", - "PublicDescription": "Counts all retired software prefetch instructions. Available PDIST counters: 0", + "PublicDescription": "Counts all retired software prefetch instructions. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x84", "Unit": "cpu_core" @@ -624,7 +634,7 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.ANY", - "PublicDescription": "Counts all retired memory instructions - loads and stores. Available PDIST counters: 0", + "PublicDescription": "Counts all retired memory instructions - loads and stores. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x87", "Unit": "cpu_core" @@ -635,7 +645,7 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.LOCK_LOADS", - "PublicDescription": "Counts retired load instructions with locked access. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with locked access. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x21", "Unit": "cpu_core" @@ -646,7 +656,7 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.SPLIT_LOADS", - "PublicDescription": "Counts retired load instructions that split across a cacheline boundary. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions that split across a cacheline boundary. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x41", "Unit": "cpu_core" @@ -657,18 +667,29 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.SPLIT_STORES", - "PublicDescription": "Counts retired store instructions that split across a cacheline boundary. Available PDIST counters: 0", + "PublicDescription": "Counts retired store instructions that split across a cacheline boundary. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x42", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired instructions that hit the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_HIT_ANY", + "PublicDescription": "Number of retired instructions with a clean hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0xf", + "Unit": "cpu_core" + }, { "BriefDescription": "Retired load instructions that hit the STLB.", "Counter": "0,1,2,3", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.STLB_HIT_LOADS", - "PublicDescription": "Number of retired load instructions with a clean hit in the 2nd-level TLB (STLB). Available PDIST counters: 0", + "PublicDescription": "Number of retired load instructions with a clean hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x9", "Unit": "cpu_core" @@ -679,18 +700,39 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.STLB_HIT_STORES", - "PublicDescription": "Number of retired store instructions that hit in the 2nd-level TLB (STLB). Available PDIST counters: 0", + "PublicDescription": "Number of retired store instructions that hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0xa", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired SWPF instructions that hit the STLB.", + "Counter": "0,1,2,3", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_HIT_SWPF", + "PublicDescription": "Number of retired SWPF instructions that hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0xc", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that miss the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_MISS_ANY", + "PublicDescription": "Retired instructions that miss the STLB. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x17", + "Unit": "cpu_core" + }, { "BriefDescription": "Retired load instructions that miss the STLB.", "Counter": "0,1,2,3", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.STLB_MISS_LOADS", - "PublicDescription": "Number of retired load instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0", + "PublicDescription": "Number of retired load instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x11", "Unit": "cpu_core" @@ -701,18 +743,28 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.STLB_MISS_STORES", - "PublicDescription": "Number of retired store instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0", + "PublicDescription": "Number of retired store instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x12", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired SWPF instructions that miss the STLB.", + "Counter": "0,1,2,3", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_MISS_SWPF", + "PublicDescription": "Number of retired SWPF instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x14", + "Unit": "cpu_core" + }, { "BriefDescription": "Retired load instructions whose data sources were a cross-core Snoop hits and forwards data from an in on-package core cache (induced by NI$)", "Counter": "0,1,2,3", "Data_LA": "1", "EventCode": "0xd2", "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD", - "PublicDescription": "Counts retired load instructions whose data sources were a cross-core Snoop hits and forwards data from an in on-package core cache (induced by NI$) Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions whose data sources were a cross-core Snoop hits and forwards data from an in on-package core cache (induced by NI$) Available PDIST counters: 0,1", "SampleAfterValue": "20011", "UMask": "0x10", "Unit": "cpu_core" @@ -723,7 +775,7 @@ "Data_LA": "1", "EventCode": "0xd2", "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_HITM", - "PublicDescription": "Counts retired load instructions whose data sources were HitM responses from shared L3, Hit-with-FWD is normally excluded. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions whose data sources were HitM responses from shared L3, Hit-with-FWD is normally excluded. Available PDIST counters: 0,1", "SampleAfterValue": "20011", "UMask": "0x4", "Unit": "cpu_core" @@ -734,7 +786,7 @@ "Data_LA": "1", "EventCode": "0xd2", "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS", - "PublicDescription": "Counts the retired load instructions whose data sources were L3 hit and cross-core snoop missed in on-pkg core cache. Available PDIST counters: 0", + "PublicDescription": "Counts the retired load instructions whose data sources were L3 hit and cross-core snoop missed in on-pkg core cache. Available PDIST counters: 0,1", "SampleAfterValue": "20011", "UMask": "0x1", "Unit": "cpu_core" @@ -745,7 +797,7 @@ "Data_LA": "1", "EventCode": "0xd2", "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD", - "PublicDescription": "Counts retired load instructions whose data sources were L3 and cross-core snoop hits in on-pkg core cache. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions whose data sources were L3 and cross-core snoop hits in on-pkg core cache. Available PDIST counters: 0,1", "SampleAfterValue": "20011", "UMask": "0x2", "Unit": "cpu_core" @@ -756,7 +808,7 @@ "Data_LA": "1", "EventCode": "0xd3", "EventName": "MEM_LOAD_L3_MISS_RETIRED.MEMSIDE_CACHE", - "PublicDescription": "Retired load instructions which data source is memory side cache. Available PDIST counters: 0", + "PublicDescription": "Retired load instructions which data source is memory side cache. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "Unit": "cpu_core" }, @@ -766,7 +818,7 @@ "Data_LA": "1", "EventCode": "0xd4", "EventName": "MEM_LOAD_MISC_RETIRED.UC", - "PublicDescription": "Retired instructions with at least one load to uncacheable memory-type, or at least one cache-line split locked access (Bus Lock). Available PDIST counters: 0", + "PublicDescription": "Retired instructions with at least one load to uncacheable memory-type, or at least one cache-line split locked access (Bus Lock). Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x4", "Unit": "cpu_core" @@ -777,7 +829,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.FB_HIT", - "PublicDescription": "Counts retired load instructions with at least one uop was load missed in L1 but hit FB (Fill Buffers) due to preceding miss to the same cache line with data not ready. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop was load missed in L1 but hit FB (Fill Buffers) due to preceding miss to the same cache line with data not ready. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x40", "Unit": "cpu_core" @@ -788,7 +840,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L1_HIT", - "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x101", "Unit": "cpu_core" @@ -799,7 +851,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L1_HIT_L0", - "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 0 of the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 0 of the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -809,7 +861,7 @@ "Counter": "0,1,2,3", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L1_HIT_L1", - "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 1 of the L1 data cache. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 1 of the L1 data cache. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "Unit": "cpu_core" }, @@ -819,7 +871,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L1_MISS", - "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L1 cache. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L1 cache. Available PDIST counters: 0,1", "SampleAfterValue": "200003", "UMask": "0x8", "Unit": "cpu_core" @@ -830,7 +882,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L2_HIT", - "PublicDescription": "Counts retired load instructions with L2 cache hits as data sources. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with L2 cache hits as data sources. Available PDIST counters: 0,1", "SampleAfterValue": "200003", "UMask": "0x2", "Unit": "cpu_core" @@ -841,7 +893,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L2_MISS", - "PublicDescription": "Counts retired load instructions missed L2 cache as data sources. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions missed L2 cache as data sources. Available PDIST counters: 0,1", "SampleAfterValue": "100021", "UMask": "0x10", "Unit": "cpu_core" @@ -852,7 +904,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L3_HIT", - "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L3 cache. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L3 cache. Available PDIST counters: 0,1", "SampleAfterValue": "100021", "UMask": "0x4", "Unit": "cpu_core" @@ -863,7 +915,7 @@ "Data_LA": "1", "EventCode": "0xd1", "EventName": "MEM_LOAD_RETIRED.L3_MISS", - "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L3 cache. Available PDIST counters: 0", + "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L3 cache. Available PDIST counters: 0,1", "SampleAfterValue": "50021", "UMask": "0x20", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/frontend.json b/tools/perf/pmu-events/arch/x86/lunarlake/frontend.json index e2facc4086e9..b21d602e9f1a 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/frontend.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/frontend.json @@ -108,7 +108,7 @@ "EventName": "FRONTEND_RETIRED.ANY_ANT", "MSRIndex": "0x3F7", "MSRValue": "0x9", - "PublicDescription": "Always Not Taken (ANT) conditional retired branches (no BTB entry and not mispredicted) Available PDIST counters: 0", + "PublicDescription": "Always Not Taken (ANT) conditional retired branches (no BTB entry and not mispredicted) Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -120,7 +120,7 @@ "EventName": "FRONTEND_RETIRED.ANY_DSB_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x1", - "PublicDescription": "Counts retired Instructions that experienced DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Available PDIST counters: 0", + "PublicDescription": "Counts retired Instructions that experienced DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -169,7 +169,7 @@ "EventName": "FRONTEND_RETIRED.DSB_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x11", - "PublicDescription": "Number of retired Instructions that experienced a critical DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Critical means stalls were exposed to the back-end as a result of the DSB miss. Available PDIST counters: 0", + "PublicDescription": "Number of retired Instructions that experienced a critical DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Critical means stalls were exposed to the back-end as a result of the DSB miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -199,7 +199,7 @@ "EventName": "FRONTEND_RETIRED.ITLB_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x14", - "PublicDescription": "Counts retired Instructions that experienced iTLB (Instruction TLB) true miss. Available PDIST counters: 0", + "PublicDescription": "Counts retired Instructions that experienced iTLB (Instruction TLB) true miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -211,7 +211,7 @@ "EventName": "FRONTEND_RETIRED.L1I_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x12", - "PublicDescription": "Counts retired Instructions who experienced Instruction L1 Cache true miss. Available PDIST counters: 0", + "PublicDescription": "Counts retired Instructions who experienced Instruction L1 Cache true miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -223,7 +223,7 @@ "EventName": "FRONTEND_RETIRED.L2_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x13", - "PublicDescription": "Counts retired Instructions who experienced Instruction L2 Cache true miss. Available PDIST counters: 0", + "PublicDescription": "Counts retired Instructions who experienced Instruction L2 Cache true miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -235,7 +235,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_128", "MSRIndex": "0x3F7", "MSRValue": "0x608006", - "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -247,7 +247,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_16", "MSRIndex": "0x3F7", "MSRValue": "0x601006", - "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 16 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 16 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -259,7 +259,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_2", "MSRIndex": "0x3F7", "MSRValue": "0x600206", - "PublicDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of at least 2 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of at least 2 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -271,7 +271,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_256", "MSRIndex": "0x3F7", "MSRValue": "0x610006", - "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -283,7 +283,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_2_BUBBLES_GE_1", "MSRIndex": "0x3F7", "MSRValue": "0x100206", - "PublicDescription": "Counts retired instructions that are delivered to the back-end after the front-end had at least 1 bubble-slot for a period of 2 cycles. A bubble-slot is an empty issue-pipeline slot while there was no RAT stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after the front-end had at least 1 bubble-slot for a period of 2 cycles. A bubble-slot is an empty issue-pipeline slot while there was no RAT stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -295,7 +295,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_32", "MSRIndex": "0x3F7", "MSRValue": "0x602006", - "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 32 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 32 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -307,7 +307,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_4", "MSRIndex": "0x3F7", "MSRValue": "0x600406", - "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -319,7 +319,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_512", "MSRIndex": "0x3F7", "MSRValue": "0x620006", - "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -331,7 +331,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_64", "MSRIndex": "0x3F7", "MSRValue": "0x604006", - "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -343,7 +343,7 @@ "EventName": "FRONTEND_RETIRED.LATENCY_GE_8", "MSRIndex": "0x3F7", "MSRValue": "0x600806", - "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 8 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 8 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -355,7 +355,7 @@ "EventName": "FRONTEND_RETIRED.MISP_ANT", "MSRIndex": "0x3F7", "MSRValue": "0x9", - "PublicDescription": "ANT retired branches that got just mispredicted Available PDIST counters: 0", + "PublicDescription": "ANT retired branches that got just mispredicted Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x2", "Unit": "cpu_core" @@ -367,7 +367,7 @@ "EventName": "FRONTEND_RETIRED.MS_FLOWS", "MSRIndex": "0x3F7", "MSRValue": "0x8", - "PublicDescription": "Counts flows delivered by the Microcode Sequencer Available PDIST counters: 0", + "PublicDescription": "Counts flows delivered by the Microcode Sequencer Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -397,7 +397,7 @@ "EventName": "FRONTEND_RETIRED.STLB_MISS", "MSRIndex": "0x3F7", "MSRValue": "0x15", - "PublicDescription": "Counts retired Instructions that experienced STLB (2nd level TLB) true miss. Available PDIST counters: 0", + "PublicDescription": "Counts retired Instructions that experienced STLB (2nd level TLB) true miss. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" @@ -409,7 +409,7 @@ "EventName": "FRONTEND_RETIRED.UNKNOWN_BRANCH", "MSRIndex": "0x3F7", "MSRValue": "0x17", - "PublicDescription": "Number retired branch instructions that caused the front-end to be resteered when it finds the instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0", + "PublicDescription": "Number retired branch instructions that caused the front-end to be resteered when it finds the instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x3", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/lnl-metrics.json b/tools/perf/pmu-events/arch/x86/lunarlake/lnl-metrics.json index 3c740962e63e..06390a72110d 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/lnl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/lnl-metrics.json @@ -1,74 +1,46 @@ [ { "BriefDescription": "C10 residency percent per package", - "MetricExpr": "cstate_pkg@c10\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c10\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C10_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, - { - "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", - "MetricGroup": "Power", - "MetricName": "C3_Pkg_Residency", - "ScaleUnit": "100%" - }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, - { - "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", - "MetricGroup": "Power", - "MetricName": "C7_Pkg_Residency", - "ScaleUnit": "100%" - }, - { - "BriefDescription": "C8 residency percent per package", - "MetricExpr": "cstate_pkg@c8\\-residency@ / TSC", - "MetricGroup": "Power", - "MetricName": "C8_Pkg_Residency", - "ScaleUnit": "100%" - }, - { - "BriefDescription": "C9 residency percent per package", - "MetricExpr": "cstate_pkg@c9\\-residency@ / TSC", - "MetricGroup": "Power", - "MetricName": "C9_Pkg_Residency", - "ScaleUnit": "100%" - }, { "BriefDescription": "Percentage of cycles spent in System Management Interrupts.", "MetricExpr": "((msr@aperf@ - cycles) / msr@aperf@ if msr@smi@ > 0 else 0)", @@ -555,7 +527,7 @@ }, { "BriefDescription": "Average CPU Utilization", - "MetricExpr": "cpu_atom@CPU_CLK_UNHALTED.REF_TSC@ / TSC", + "MetricExpr": "cpu_atom@CPU_CLK_UNHALTED.REF_TSC@ / msr@tsc\\,cpu=cpu_atom@", "MetricName": "tma_info_system_cpu_utilization", "Unit": "cpu_atom" }, @@ -724,6 +696,13 @@ "ScaleUnit": "100%", "Unit": "cpu_atom" }, + { + "BriefDescription": "Uncore frequency per die [GHZ]", + "MetricExpr": "tma_info_system_socket_clks / #num_dies / duration_time / 1e9", + "MetricGroup": "SoC", + "MetricName": "UNCORE_FREQ", + "Unit": "cpu_core" + }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", "MetricExpr": "cpu_core@UOPS_DISPATCHED.ALU@ / (6 * tma_info_thread_clks)", @@ -755,7 +734,7 @@ { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-be\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-be\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BvOB;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", "MetricThreshold": "tma_backend_bound > 0.2", @@ -767,7 +746,7 @@ { "BriefDescription": "This category represents fraction of slots wasted due to incorrect speculations", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-bad\\-spec@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-bad\\-spec@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_bad_speculation", "MetricThreshold": "tma_bad_speculation > 0.15", @@ -793,24 +772,6 @@ "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)", "Unit": "cpu_core" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", - "Unit": "cpu_core" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_capacity / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency", - "Unit": "cpu_core" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", @@ -820,9 +781,27 @@ "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: ", "Unit": "cpu_core" }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_capacity / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency", + "Unit": "cpu_core" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20", @@ -830,7 +809,7 @@ }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * ((1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + cpu_core@RS.EMPTY_RESOURCE@ / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_microcode_sequencer + tma_few_uops_instructions) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricExpr": "100 * ((1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + cpu_core@RS.EMPTY_RESOURCE@ / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_microcode_sequencer + tma_few_uops_instructions) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -839,7 +818,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / (tma_dtlb_load + tma_fb_full + tma_l1_latency_capacity + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_early_blk + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -866,7 +845,7 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -883,7 +862,7 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU has wasted due to Branch Misprediction", - "MetricExpr": "cpu_core@topdown\\-br\\-mispredict@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-br\\-mispredict@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BadSpec;BrMispredicts;BvMP;TmaL2;TopdownL2;tma_L2_group;tma_bad_speculation_group;tma_issueBM", "MetricName": "tma_branch_mispredicts", "MetricThreshold": "tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15", @@ -1023,7 +1002,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS@R, 24 * tma_info_system_core_frequency) + cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_HITM@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_HITM@R, 25 * tma_info_system_core_frequency)) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;DataSharing;LockCont;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_contested_accesses", @@ -1076,7 +1054,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to DSB (decoded uop cache) fetch pipeline", - "MetricExpr": "(cpu_core@IDQ.DSB_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ + cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", + "MetricExpr": "(cpu_core@IDQ.DSB_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / 2 + cpu_core@IDQ.DSB_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", "MetricGroup": "DSB;FetchBW;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_dsb", "MetricThreshold": "tma_dsb > 0.15 & tma_fetch_bandwidth > 0.2", @@ -1130,7 +1108,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1147,7 +1125,7 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU was stalled due to Frontend latency issues", - "MetricExpr": "cpu_core@topdown\\-fetch\\-lat@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-fetch\\-lat@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Frontend;TmaL2;TopdownL2;tma_L2_group;tma_frontend_bound_group", "MetricName": "tma_fetch_latency", "MetricThreshold": "tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15", @@ -1197,7 +1175,7 @@ }, { "BriefDescription": "This metric approximates arithmetic floating-point (FP) scalar uops fraction the CPU has retired", - "MetricExpr": "cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Compute;Flops;TopdownL4;tma_L4_group;tma_fp_arith_group;tma_issue2P", "MetricName": "tma_fp_scalar", "MetricThreshold": "tma_fp_scalar > 0.1 & (tma_fp_arith > 0.2 & tma_light_operations > 0.6)", @@ -1207,7 +1185,7 @@ }, { "BriefDescription": "This metric approximates arithmetic floating-point (FP) vector uops fraction the CPU has retired aggregated across all vector widths", - "MetricExpr": "cpu_core@FP_ARITH_INST_RETIRED.VECTOR@ / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "cpu_core@FP_ARITH_OPS_RETIRED.VECTOR@ / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Compute;Flops;TopdownL4;tma_L4_group;tma_fp_arith_group;tma_issue2P", "MetricName": "tma_fp_vector", "MetricThreshold": "tma_fp_vector > 0.1 & (tma_fp_arith > 0.2 & tma_light_operations > 0.6)", @@ -1217,7 +1195,7 @@ }, { "BriefDescription": "This metric approximates arithmetic FP vector uops fraction the CPU has retired for 128-bit wide vectors", - "MetricExpr": "(cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE@) / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "(cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_SINGLE@) / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Compute;Flops;TopdownL5;tma_L5_group;tma_fp_vector_group;tma_issue2P", "MetricName": "tma_fp_vector_128b", "MetricThreshold": "tma_fp_vector_128b > 0.1 & (tma_fp_vector > 0.1 & (tma_fp_arith > 0.2 & tma_light_operations > 0.6))", @@ -1227,7 +1205,7 @@ }, { "BriefDescription": "This metric approximates arithmetic FP vector uops fraction the CPU has retired for 256-bit wide vectors", - "MetricExpr": "cpu_core@FP_ARITH_INST_RETIRED.VECTOR\\,umask\\=0x30@ / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "cpu_core@FP_ARITH_OPS_RETIRED.VECTOR\\,umask\\=0x30@ / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Compute;Flops;TopdownL5;tma_L5_group;tma_fp_vector_group;tma_issue2P", "MetricName": "tma_fp_vector_256b", "MetricThreshold": "tma_fp_vector_256b > 0.1 & (tma_fp_vector > 0.1 & (tma_fp_arith > 0.2 & tma_light_operations > 0.6))", @@ -1238,7 +1216,7 @@ { "BriefDescription": "This category represents fraction of slots where the processor's Frontend undersupplies its Backend", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-fe\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-fe\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BvFB;BvIO;Default;PGO;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_frontend_bound", "MetricThreshold": "tma_frontend_bound > 0.15", @@ -1259,7 +1237,7 @@ }, { "BriefDescription": "This metric represents fraction of slots where the CPU was retiring heavy-weight operations -- instructions that require two or more uops or micro-coded sequences", - "MetricExpr": "cpu_core@topdown\\-heavy\\-ops@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-heavy\\-ops@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Retire;TmaL2;TopdownL2;tma_L2_group;tma_retiring_group", "MetricName": "tma_heavy_operations", "MetricThreshold": "tma_heavy_operations > 0.1", @@ -1437,7 +1415,7 @@ }, { "BriefDescription": "Floating Point Operations Per Cycle", - "MetricExpr": "(cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_INST_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@) / tma_info_thread_clks", + "MetricExpr": "(cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_OPS_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_OPS_RETIRED.256B_PACKED_SINGLE@) / tma_info_thread_clks", "MetricGroup": "Flops;Ret", "MetricName": "tma_info_core_flopc", "Unit": "cpu_core" @@ -1578,7 +1556,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic instruction (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ + cpu_core@FP_ARITH_INST_RETIRED.VECTOR@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ + cpu_core@FP_ARITH_OPS_RETIRED.VECTOR@)", "MetricGroup": "Flops;InsType", "MetricName": "tma_info_inst_mix_iparith", "MetricThreshold": "tma_info_inst_mix_iparith < 10", @@ -1587,7 +1565,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic AVX/SSE 128-bit instruction (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_SINGLE@)", "MetricGroup": "Flops;FpVector;InsType", "MetricName": "tma_info_inst_mix_iparith_avx128", "MetricThreshold": "tma_info_inst_mix_iparith_avx128 < 10", @@ -1596,7 +1574,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic AVX* 256-bit instruction (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_OPS_RETIRED.256B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_OPS_RETIRED.256B_PACKED_SINGLE@)", "MetricGroup": "Flops;FpVector;InsType", "MetricName": "tma_info_inst_mix_iparith_avx256", "MetricThreshold": "tma_info_inst_mix_iparith_avx256 < 10", @@ -1605,7 +1583,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic Scalar Double-Precision instruction (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@FP_ARITH_INST_RETIRED.SCALAR_DOUBLE@", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@FP_ARITH_OPS_RETIRED.SCALAR_DOUBLE@", "MetricGroup": "Flops;FpScalar;InsType", "MetricName": "tma_info_inst_mix_iparith_scalar_dp", "MetricThreshold": "tma_info_inst_mix_iparith_scalar_dp < 10", @@ -1614,7 +1592,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic Scalar Single-Precision instruction (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@FP_ARITH_INST_RETIRED.SCALAR_SINGLE@", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@FP_ARITH_OPS_RETIRED.SCALAR_SINGLE@", "MetricGroup": "Flops;FpScalar;InsType", "MetricName": "tma_info_inst_mix_iparith_scalar_sp", "MetricThreshold": "tma_info_inst_mix_iparith_scalar_sp < 10", @@ -1639,7 +1617,7 @@ }, { "BriefDescription": "Instructions per Floating Point (FP) Operation (lower number means higher occurrence rate)", - "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_INST_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_OPS_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_OPS_RETIRED.256B_PACKED_SINGLE@)", "MetricGroup": "Flops;InsType", "MetricName": "tma_info_inst_mix_ipflop", "MetricThreshold": "tma_info_inst_mix_ipflop < 10", @@ -1694,7 +1672,7 @@ }, { "BriefDescription": "Average per-thread data fill bandwidth to the L1 data cache [GB / sec]", - "MetricExpr": "64 * cpu_core@L1D.REPLACEMENT@ / 1e9 / tma_info_system_time", + "MetricExpr": "64 * cpu_core@L1D.L1_REPLACEMENT@ / 1e9 / tma_info_system_time", "MetricGroup": "Mem;MemoryBW", "MetricName": "tma_info_memory_l1d_cache_fill_bw", "Unit": "cpu_core" @@ -1706,6 +1684,13 @@ "MetricName": "tma_info_memory_l1dl0_cache_fill_bw", "Unit": "cpu_core" }, + { + "BriefDescription": "L0 cache true misses per kilo instruction for retired demand loads", + "MetricExpr": "1e3 * (cpu_core@MEM_LOAD_RETIRED.L1_MISS@ + cpu_core@MEM_LOAD_RETIRED.L1_HIT_L1@) / cpu_core@INST_RETIRED.ANY@", + "MetricGroup": "CacheHits;Mem", + "MetricName": "tma_info_memory_l1dl0_mpki", + "Unit": "cpu_core" + }, { "BriefDescription": "L1 cache true misses per kilo instruction for retired demand loads", "MetricExpr": "1e3 * cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / cpu_core@INST_RETIRED.ANY@", @@ -1921,6 +1906,13 @@ "MetricName": "tma_info_pipeline_fetch_mite", "Unit": "cpu_core" }, + { + "BriefDescription": "Average number of uops fetched from MS per cycle", + "MetricExpr": "cpu_core@IDQ.MS_UOPS@ / cpu_core@IDQ.MS_UOPS\\,cmask\\=1@", + "MetricGroup": "Fed;FetchLat;MicroSeq", + "MetricName": "tma_info_pipeline_fetch_ms", + "Unit": "cpu_core" + }, { "BriefDescription": "Instructions per a microcode Assist invocation", "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@ASSISTS.ANY@", @@ -1955,7 +1947,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc\\,cpu=cpu_core@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency", "Unit": "cpu_core" @@ -1969,14 +1961,22 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.REF_TSC@ / TSC", + "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.REF_TSC@ / msr@tsc\\,cpu=cpu_core@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized", "Unit": "cpu_core" }, + { + "BriefDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]", + "MetricExpr": "32 * UNC_M_TOTAL_DATA / 1e9 / tma_info_system_time", + "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", + "MetricName": "tma_info_system_dram_bw_use", + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full", + "Unit": "cpu_core" + }, { "BriefDescription": "Giga Floating Point Operations Per Second", - "MetricExpr": "(cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_INST_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@) / 1e9 / tma_info_system_time", + "MetricExpr": "(cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ + 2 * cpu_core@FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE@ + 4 * cpu_core@FP_ARITH_OPS_RETIRED.4_FLOPS@ + 8 * cpu_core@FP_ARITH_OPS_RETIRED.256B_PACKED_SINGLE@) / 1e9 / tma_info_system_time", "MetricGroup": "Cor;Flops;HPC", "MetricName": "tma_info_system_gflops", "PublicDescription": "Giga Floating Point Operations Per Second. Aggregate across all supported options of: FP precisions, scalar and vector instructions, vector-width", @@ -2020,6 +2020,13 @@ "MetricName": "tma_info_system_power", "Unit": "cpu_core" }, + { + "BriefDescription": "Socket actual clocks when any core is active on that socket", + "MetricExpr": "UNC_CLOCK.SOCKET", + "MetricGroup": "SoC", + "MetricName": "tma_info_system_socket_clks", + "Unit": "cpu_core" + }, { "BriefDescription": "Run duration time in seconds", "MetricExpr": "duration_time", @@ -2035,6 +2042,13 @@ "MetricName": "tma_info_system_turbo_utilization", "Unit": "cpu_core" }, + { + "BriefDescription": "Measured Average Uncore Frequency for the SoC [GHz]", + "MetricExpr": "tma_info_system_socket_clks / 1e9 / tma_info_system_time", + "MetricGroup": "SoC", + "MetricName": "tma_info_system_uncore_frequency", + "Unit": "cpu_core" + }, { "BriefDescription": "Per-Logical Processor actual clocks when the Logical Processor is active.", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.THREAD@", @@ -2156,12 +2170,12 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", - "MetricExpr": "4 * cpu_core@DEPENDENT_LOADS.ANY@ / tma_info_thread_clks", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "MetricExpr": "4 * cpu_core@DEPENDENT_LOADS.ANY\\,cmask\\=1@ / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_UOPS_RETIRED.L1_HIT_PS", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_UOPS_RETIRED.L1_HIT_PS", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2177,7 +2191,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles with demand load accesses that hit the L2 cache under unloaded scenarios (possibly L2 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_core@MEM_LOAD_RETIRED.L2_HIT@ * min(cpu_core@MEM_LOAD_RETIRED.L2_HIT@R, 3 * tma_info_system_core_frequency) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "MemoryLat;TopdownL4;tma_L4_group;tma_l2_bound_group", "MetricName": "tma_l2_hit_latency", @@ -2198,12 +2211,11 @@ }, { "BriefDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_core@MEM_LOAD_RETIRED.L3_HIT@ * min(cpu_core@MEM_LOAD_RETIRED.L3_HIT@R, 9 * tma_info_system_core_frequency) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2285,6 +2297,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_core@MEM_INST_RETIRED.LOCK_LOADS@ * cpu_core@MEM_INST_RETIRED.LOCK_LOADS@R / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -2295,7 +2308,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to LSD (Loop Stream Detector) unit", - "MetricExpr": "cpu_core@LSD.UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@LSD.UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / tma_info_thread_clks / 2", "MetricGroup": "FetchBW;LSD;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_lsd", "MetricThreshold": "tma_lsd > 0.15 & tma_fetch_bandwidth > 0.2", @@ -2320,7 +2333,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2330,13 +2343,13 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%", "Unit": "cpu_core" }, { "BriefDescription": "This metric represents fraction of slots the Memory subsystem within the Backend was a bottleneck", - "MetricExpr": "cpu_core@topdown\\-mem\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-mem\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Backend;TmaL2;TopdownL2;tma_L2_group;tma_backend_bound_group", "MetricName": "tma_memory_bound", "MetricThreshold": "tma_memory_bound > 0.2 & tma_backend_bound > 0.2", @@ -2347,7 +2360,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to LFENCE Instructions.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * cpu_core@MISC2_RETIRED.LFENCE@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_memory_fence", @@ -2386,7 +2398,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the MITE pipeline (the legacy decode pipeline)", - "MetricExpr": "(cpu_core@IDQ.MITE_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / 2 + cpu_core@IDQ.MITE_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", + "MetricExpr": "(cpu_core@IDQ.MITE_UOPS\\,cmask\\=0x8\\,inv\\=0x1@ / 2 + cpu_core@IDQ.MITE_UOPS@ / (cpu_core@IDQ.DSB_UOPS@ + cpu_core@IDQ.MITE_UOPS@) * (cpu_core@IDQ_BUBBLES.STARVATION_CYCLES@ - cpu_core@IDQ_BUBBLES.FETCH_LATENCY@)) / tma_info_thread_clks", "MetricGroup": "DSBmiss;FetchBW;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_mite", "MetricThreshold": "tma_mite > 0.1 & tma_fetch_bandwidth > 0.2", @@ -2406,7 +2418,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "cpu_core@IDQ.MS_CYCLES_ANY@ / tma_info_thread_clks", + "MetricExpr": "cpu_core@IDQ.MS_CYCLES_ANY@ / tma_info_thread_clks / 1.8", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -2445,7 +2457,8 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", - "MetricExpr": "max(0, tma_light_operations - (tma_x87_use + (cpu_core@FP_ARITH_INST_RETIRED.SCALAR@ + cpu_core@FP_ARITH_INST_RETIRED.VECTOR@) / (tma_retiring * tma_info_thread_slots) + (cpu_core@INT_VEC_RETIRED.ADD_128@ + cpu_core@INT_VEC_RETIRED.VNNI_128@ + cpu_core@INT_VEC_RETIRED.ADD_256@ + cpu_core@INT_VEC_RETIRED.MUL_256@ + cpu_core@INT_VEC_RETIRED.VNNI_256@) / (tma_retiring * tma_info_thread_slots) + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "max(0, tma_light_operations - (tma_x87_use + (cpu_core@FP_ARITH_OPS_RETIRED.SCALAR@ + cpu_core@FP_ARITH_OPS_RETIRED.VECTOR@) / (tma_retiring * tma_info_thread_slots) + (cpu_core@INT_VEC_RETIRED.ADD_128@ + cpu_core@INT_VEC_RETIRED.VNNI_128@ + cpu_core@INT_VEC_RETIRED.ADD_256@ + cpu_core@INT_VEC_RETIRED.MUL_256@ + cpu_core@INT_VEC_RETIRED.VNNI_256@) / (tma_retiring * tma_info_thread_slots) + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", "MetricThreshold": "tma_other_light_ops > 0.3 & tma_light_operations > 0.6", @@ -2483,6 +2496,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "((cpu_core@EXE_ACTIVITY.EXE_BOUND_0_PORTS@ + (cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ + tma_retiring * cpu_core@EXE_ACTIVITY.2_3_PORTS_UTIL@)) / tma_info_thread_clks if cpu_core@ARITH.DIV_ACTIVE@ < cpu_core@CYCLE_ACTIVITY.STALLS_TOTAL@ - cpu_core@EXE_ACTIVITY.BOUND_ON_LOADS@ else (cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ + tma_retiring * cpu_core@EXE_ACTIVITY.2_3_PORTS_UTIL@) / tma_info_thread_clks)", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", @@ -2493,6 +2507,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "cpu_core@EXE_ACTIVITY.EXE_BOUND_0_PORTS@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", @@ -2503,6 +2518,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", @@ -2513,7 +2529,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@EXE_ACTIVITY.2_PORTS_UTIL@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", @@ -2524,7 +2539,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 3 or more uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@UOPS_EXECUTED.CYCLES_GE_3@ / tma_info_thread_clks", "MetricGroup": "BvCB;PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_3m", @@ -2545,7 +2559,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-retiring@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-retiring@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -2576,7 +2590,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to PAUSE Instructions", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.PAUSE@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_slow_pause", @@ -2611,7 +2624,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2625,6 +2638,15 @@ "ScaleUnit": "100%", "Unit": "cpu_core" }, + { + "BriefDescription": "This metric estimates clocks wasted due to loads blocked due to unknown store address (did not do memory disambiguation) or due to unknown store data", + "MetricExpr": "7 * cpu_core@LD_BLOCKS.STORE_EARLY\\,cmask\\=1@ / tma_info_thread_clks", + "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", + "MetricName": "tma_store_early_blk", + "MetricThreshold": "tma_store_early_blk > 0.2", + "ScaleUnit": "100%", + "Unit": "cpu_core" + }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", "MetricExpr": "13 * cpu_core@LD_BLOCKS.STORE_FORWARD@ / tma_info_thread_clks", diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/memory.json b/tools/perf/pmu-events/arch/x86/lunarlake/memory.json index 8021a1c7dd3b..25021cb76f61 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/memory.json @@ -163,7 +163,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_1024", "MSRIndex": "0x3F6", "MSRValue": "0x400", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "53", "UMask": "0x1", "Unit": "cpu_core" @@ -176,7 +176,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_128", "MSRIndex": "0x3F6", "MSRValue": "0x80", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "1009", "UMask": "0x1", "Unit": "cpu_core" @@ -189,7 +189,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_16", "MSRIndex": "0x3F6", "MSRValue": "0x10", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "20011", "UMask": "0x1", "Unit": "cpu_core" @@ -202,7 +202,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_2048", "MSRIndex": "0x3F6", "MSRValue": "0x800", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "23", "UMask": "0x1", "Unit": "cpu_core" @@ -215,7 +215,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_256", "MSRIndex": "0x3F6", "MSRValue": "0x100", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "503", "UMask": "0x1", "Unit": "cpu_core" @@ -228,7 +228,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_32", "MSRIndex": "0x3F6", "MSRValue": "0x20", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "100007", "UMask": "0x1", "Unit": "cpu_core" @@ -241,7 +241,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_4", "MSRIndex": "0x3F6", "MSRValue": "0x4", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -254,7 +254,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_512", "MSRIndex": "0x3F6", "MSRValue": "0x200", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "101", "UMask": "0x1", "Unit": "cpu_core" @@ -267,7 +267,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_64", "MSRIndex": "0x3F6", "MSRValue": "0x40", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "2003", "UMask": "0x1", "Unit": "cpu_core" @@ -280,7 +280,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_8", "MSRIndex": "0x3F6", "MSRValue": "0x8", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles. Reported latency may be longer than just the memory latency.", "SampleAfterValue": "50021", "UMask": "0x1", "Unit": "cpu_core" @@ -291,7 +291,7 @@ "Data_LA": "1", "EventCode": "0xcd", "EventName": "MEM_TRANS_RETIRED.STORE_SAMPLE", - "PublicDescription": "Counts Retired memory accesses with at least 1 store operation. This PEBS event is the precisely-distributed (PDist) trigger covering all stores uops for sampling by the PEBS Store Latency Facility. The facility is described in Intel SDM Volume 3 section 19.9.8 Available PDIST counters: 0", + "PublicDescription": "Counts Retired memory accesses with at least 1 store operation. This PEBS event is the precisely-distributed (PDist) trigger covering all stores uops for sampling by the PEBS Store Latency Facility. The facility is described in Intel SDM Volume 3 section 19.9.8 Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json b/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json index 6ac410510628..cdaa01e9a57d 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json @@ -110,7 +110,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.ALL_BRANCHES", - "PublicDescription": "Counts all branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts all branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "Unit": "cpu_core" }, @@ -128,7 +128,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND", - "PublicDescription": "Counts conditional branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x111", "Unit": "cpu_core" @@ -147,7 +147,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND_NTAKEN", - "PublicDescription": "Counts not taken branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts not taken branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x10", "Unit": "cpu_core" @@ -166,7 +166,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND_TAKEN", - "PublicDescription": "Counts taken conditional branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x101", "Unit": "cpu_core" @@ -176,7 +176,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND_TAKEN_BWD", - "PublicDescription": "Counts taken backward conditional branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken backward conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x1", "Unit": "cpu_core" @@ -186,7 +186,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND_TAKEN_FWD", - "PublicDescription": "Counts taken forward conditional branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken forward conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x102", "Unit": "cpu_core" @@ -205,7 +205,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.FAR_BRANCH", - "PublicDescription": "Counts far branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts far branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x40", "Unit": "cpu_core" @@ -224,7 +224,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.INDIRECT", - "PublicDescription": "Counts near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0", + "PublicDescription": "Counts near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x80", "Unit": "cpu_core" @@ -261,7 +261,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_CALL", - "PublicDescription": "Counts both direct and indirect near call instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts both direct and indirect near call instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x2", "Unit": "cpu_core" @@ -280,13 +280,13 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_RETURN", - "PublicDescription": "Counts return instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts return instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x8", "Unit": "cpu_core" }, { - "BriefDescription": "Counts the number of taken branch instructions retired", + "BriefDescription": "Counts the number of near taken branch instructions retired", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_TAKEN", @@ -299,7 +299,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_TAKEN", - "PublicDescription": "Counts taken branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x20", "Unit": "cpu_core" @@ -327,7 +327,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.ALL_BRANCHES", - "PublicDescription": "Counts all the retired branch instructions that were mispredicted by the processor. A branch misprediction occurs when the processor incorrectly predicts the destination of the branch. When the misprediction is discovered at execution, all the instructions executed in the wrong (speculative) path must be discarded, and the processor must start fetching from the correct path. Available PDIST counters: 0", + "PublicDescription": "Counts all the retired branch instructions that were mispredicted by the processor. A branch misprediction occurs when the processor incorrectly predicts the destination of the branch. When the misprediction is discovered at execution, all the instructions executed in the wrong (speculative) path must be discarded, and the processor must start fetching from the correct path. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "Unit": "cpu_core" }, @@ -336,7 +336,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.ALL_BRANCHES_COST", - "PublicDescription": "All mispredicted branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "All mispredicted branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x44", "Unit": "cpu_core" @@ -355,7 +355,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND", - "PublicDescription": "Counts mispredicted conditional branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts mispredicted conditional branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x111", "Unit": "cpu_core" @@ -365,7 +365,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_COST", - "PublicDescription": "Mispredicted conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x151", "Unit": "cpu_core" @@ -384,7 +384,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_NTAKEN", - "PublicDescription": "Counts the number of conditional branch instructions retired that were mispredicted and the branch direction was not taken. Available PDIST counters: 0", + "PublicDescription": "Counts the number of conditional branch instructions retired that were mispredicted and the branch direction was not taken. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x10", "Unit": "cpu_core" @@ -394,7 +394,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_NTAKEN_COST", - "PublicDescription": "Mispredicted non-taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted non-taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x50", "Unit": "cpu_core" @@ -413,7 +413,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN", - "PublicDescription": "Counts taken conditional mispredicted branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x101", "Unit": "cpu_core" @@ -423,7 +423,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN_BWD", - "PublicDescription": "Counts taken backward conditional mispredicted branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken backward conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x1", "Unit": "cpu_core" @@ -433,7 +433,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN_BWD_COST", - "PublicDescription": "number of branch instructions retired that were mispredicted and taken backward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "number of branch instructions retired that were mispredicted and taken backward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x8001", "Unit": "cpu_core" @@ -443,7 +443,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN_COST", - "PublicDescription": "Mispredicted taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x141", "Unit": "cpu_core" @@ -453,7 +453,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD", - "PublicDescription": "Counts taken forward conditional mispredicted branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts taken forward conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "Unit": "cpu_core" }, @@ -462,7 +462,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD_COST", - "PublicDescription": "number of branch instructions retired that were mispredicted and taken forward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "number of branch instructions retired that were mispredicted and taken forward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x8002", "Unit": "cpu_core" @@ -481,7 +481,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.INDIRECT", - "PublicDescription": "Counts miss-predicted near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0", + "PublicDescription": "Counts miss-predicted near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x80", "Unit": "cpu_core" @@ -500,7 +500,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.INDIRECT_CALL", - "PublicDescription": "Counts retired mispredicted indirect (near taken) CALL instructions, including both register and memory indirect. Available PDIST counters: 0", + "PublicDescription": "Counts retired mispredicted indirect (near taken) CALL instructions, including both register and memory indirect. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x2", "Unit": "cpu_core" @@ -510,7 +510,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.INDIRECT_CALL_COST", - "PublicDescription": "Mispredicted indirect CALL retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted indirect CALL retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x42", "Unit": "cpu_core" @@ -520,7 +520,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.INDIRECT_COST", - "PublicDescription": "Mispredicted near indirect branch instructions retired (excluding returns). This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted near indirect branch instructions retired (excluding returns). This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0xc0", "Unit": "cpu_core" @@ -548,7 +548,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.NEAR_TAKEN", - "PublicDescription": "Counts number of near branch instructions retired that were mispredicted and taken. Available PDIST counters: 0", + "PublicDescription": "Counts number of near branch instructions retired that were mispredicted and taken. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x20", "Unit": "cpu_core" @@ -558,7 +558,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.NEAR_TAKEN_COST", - "PublicDescription": "Mispredicted taken near branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted taken near branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "UMask": "0x60", "Unit": "cpu_core" @@ -568,7 +568,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.RET", - "PublicDescription": "This is a non-precise version (that is, does not use PEBS) of the event that counts mispredicted return instructions retired. Available PDIST counters: 0", + "PublicDescription": "This is a non-precise version (that is, does not use PEBS) of the event that counts mispredicted return instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x8", "Unit": "cpu_core" @@ -587,7 +587,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.RET_COST", - "PublicDescription": "Mispredicted ret instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0", + "PublicDescription": "Mispredicted ret instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x48", "Unit": "cpu_core" @@ -906,7 +906,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.ANY_P", - "PublicDescription": "Counts the number of X86 instructions retired - an Architectural PerfMon event. Counting continues during hardware interrupts, traps, and inside interrupt handlers. Notes: INST_RETIRED.ANY is counted by a designated fixed counter freeing up programmable counters to count other events. INST_RETIRED.ANY_P is counted by a programmable counter. Available PDIST counters: 0", + "PublicDescription": "Counts the number of X86 instructions retired - an Architectural PerfMon event. Counting continues during hardware interrupts, traps, and inside interrupt handlers. Notes: INST_RETIRED.ANY is counted by a designated fixed counter freeing up programmable counters to count other events. INST_RETIRED.ANY_P is counted by a programmable counter. Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "Unit": "cpu_core" }, @@ -915,7 +915,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.BR_FUSED", - "PublicDescription": "retired macro-fused uops when there is a branch in the macro-fused pair (the two instructions that got macro-fused count once in this pmon) Available PDIST counters: 0", + "PublicDescription": "retired macro-fused uops when there is a branch in the macro-fused pair (the two instructions that got macro-fused count once in this pmon) Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -925,7 +925,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.MACRO_FUSED", - "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0", + "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "UMask": "0x30", "Unit": "cpu_core" @@ -935,7 +935,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.NOP", - "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions Available PDIST counters: 0", + "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -954,7 +954,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -1227,6 +1227,15 @@ "UMask": "0x88", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts the number of times a load got early blocked due to preceding store operation with unknown address or unknown data. Excluding in-line (immediate) wakeups", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.STORE_EARLY", + "SampleAfterValue": "100003", + "UMask": "0xa1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of occurrences a retired load gets blocked because its address partially overlaps with an older store (size mismatch) - unknown_sta/bad_forward", "Counter": "0,1,2,3,4,5,6,7", @@ -1451,7 +1460,7 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xe4", "EventName": "MISC_RETIRED.LBR_INSERTS", - "PublicDescription": "LBR record is inserted Available PDIST counters: 0", + "PublicDescription": "LBR record is inserted Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/lunarlake/uncore-interconnect.json new file mode 100644 index 000000000000..69ef928d57f6 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/lunarlake/uncore-interconnect.json @@ -0,0 +1,10 @@ +[ + { + "BriefDescription": "This 48-bit fixed counter counts the UCLK cycles.", + "Counter": "FIXED", + "EventCode": "0xff", + "EventName": "UNC_CLOCK.SOCKET", + "PerPkg": "1", + "Unit": "SANTA" + } +] diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/uncore-memory.json b/tools/perf/pmu-events/arch/x86/lunarlake/uncore-memory.json index 7d63580302de..63c4aa2791e4 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/uncore-memory.json @@ -32,5 +32,13 @@ "Experimental": "1", "PerPkg": "1", "Unit": "iMC" + }, + { + "BriefDescription": "Total number of read and write byte transfers to/from DRAM, in 32B chunk, per DDR channel. Counter increments by 1 after sending or receiving 32B chunk data.", + "Counter": "0,1,2,3,4", + "EventCode": "0x3C", + "EventName": "UNC_M_TOTAL_DATA", + "PerPkg": "1", + "Unit": "iMC" } ] diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 2d7a9fa055dd..894a3f485a4a 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -22,7 +22,7 @@ GenuineIntel-6-3A,v24,ivybridge,core GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core GenuineIntel-6-(57|85),v16,knightslanding,core -GenuineIntel-6-BD,v1.14,lunarlake,core +GenuineIntel-6-BD,v1.17,lunarlake,core GenuineIntel-6-(AA|AC|B5),v1.14,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core From 59050cb8972dd146641c69db54dee6fd36a84e34 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:10 -0700 Subject: [PATCH 0859/2711] perf vendor events: Update meteorlake events/metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update events from v1.14 to v1.16. Update metrics from TMA 5.0 to 5.1. The event updates come from: https://github.com/intel/perfmon/commit/c3e91c6e6b39429c57001d4942667f380efe8ea9 Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-15-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../pmu-events/arch/x86/meteorlake/cache.json | 129 ++++++------- .../arch/x86/meteorlake/floating-point.json | 28 +-- .../arch/x86/meteorlake/frontend.json | 42 ++--- .../arch/x86/meteorlake/memory.json | 15 +- .../arch/x86/meteorlake/mtl-metrics.json | 113 ++++++------ .../pmu-events/arch/x86/meteorlake/other.json | 5 +- .../arch/x86/meteorlake/pipeline.json | 173 ++++++++---------- .../arch/x86/meteorlake/virtual-memory.json | 40 ++-- 9 files changed, 256 insertions(+), 291 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 894a3f485a4a..f8bf16d30602 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -23,7 +23,7 @@ GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core GenuineIntel-6-(57|85),v16,knightslanding,core GenuineIntel-6-BD,v1.17,lunarlake,core -GenuineIntel-6-(AA|AC|B5),v1.14,meteorlake,core +GenuineIntel-6-(AA|AC|B5),v1.16,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core GenuineIntel-6-CC,v1.00,pantherlake,core diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/cache.json b/tools/perf/pmu-events/arch/x86/meteorlake/cache.json index 82b115183924..f1d8db284a02 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/cache.json @@ -14,7 +14,6 @@ "Counter": "0,1,2,3", "EventCode": "0x51", "EventName": "L1D.HWPF_MISS", - "PublicDescription": "L1D.HWPF_MISS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20", "Unit": "cpu_core" @@ -24,7 +23,7 @@ "Counter": "0,1,2,3", "EventCode": "0x51", "EventName": "L1D.REPLACEMENT", - "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace. Available PDIST counters: 0", + "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -34,7 +33,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.FB_FULL", - "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -46,7 +45,7 @@ "EdgeDetect": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.FB_FULL_PERIODS", - "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -56,7 +55,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.L2_STALLS", - "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x4", "Unit": "cpu_core" @@ -66,7 +65,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.PENDING", - "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type. Available PDIST counters: 0", + "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -77,7 +76,7 @@ "CounterMask": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.PENDING_CYCLES", - "PublicDescription": "Counts duration of L1D miss outstanding in cycles. Available PDIST counters: 0", + "PublicDescription": "Counts duration of L1D miss outstanding in cycles.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -87,7 +86,7 @@ "Counter": "0,1,2,3", "EventCode": "0x25", "EventName": "L2_LINES_IN.ALL", - "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects. Available PDIST counters: 0", + "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects.", "SampleAfterValue": "100003", "UMask": "0x1f", "Unit": "cpu_core" @@ -147,7 +146,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.NON_SILENT", - "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3 Available PDIST counters: 0", + "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3", "SampleAfterValue": "200003", "UMask": "0x2", "Unit": "cpu_core" @@ -167,7 +166,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.SILENT", - "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event. Available PDIST counters: 0", + "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event.", "SampleAfterValue": "200003", "UMask": "0x1", "Unit": "cpu_core" @@ -177,7 +176,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.USELESS_HWPF", - "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache Available PDIST counters: 0", + "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache", "SampleAfterValue": "200003", "UMask": "0x4", "Unit": "cpu_core" @@ -187,7 +186,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.ALL", - "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES]", "SampleAfterValue": "200003", "UMask": "0xff", "Unit": "cpu_core" @@ -206,7 +205,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.HIT", - "PublicDescription": "Counts all requests that hit L2 cache. [This event is alias to L2_RQSTS.HIT] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that hit L2 cache. [This event is alias to L2_RQSTS.HIT]", "SampleAfterValue": "200003", "UMask": "0xdf", "Unit": "cpu_core" @@ -225,7 +224,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.MISS", - "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS] Available PDIST counters: 0", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS]", "SampleAfterValue": "200003", "UMask": "0x3f", "Unit": "cpu_core" @@ -244,7 +243,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_CODE_RD", - "PublicDescription": "Counts the total number of L2 code requests. Available PDIST counters: 0", + "PublicDescription": "Counts the total number of L2 code requests.", "SampleAfterValue": "200003", "UMask": "0xe4", "Unit": "cpu_core" @@ -254,7 +253,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_DATA_RD", - "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once. Available PDIST counters: 0", + "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once.", "SampleAfterValue": "200003", "UMask": "0xe1", "Unit": "cpu_core" @@ -264,7 +263,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_MISS", - "PublicDescription": "Counts demand requests that miss L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts demand requests that miss L2 cache.", "SampleAfterValue": "200003", "UMask": "0x27", "Unit": "cpu_core" @@ -274,7 +273,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_REFERENCES", - "PublicDescription": "Counts demand requests to L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts demand requests to L2 cache.", "SampleAfterValue": "200003", "UMask": "0xe7", "Unit": "cpu_core" @@ -284,7 +283,6 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_HWPF", - "PublicDescription": "L2_RQSTS.ALL_HWPF Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0xf0", "Unit": "cpu_core" @@ -294,7 +292,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_RFO", - "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches. Available PDIST counters: 0", + "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches.", "SampleAfterValue": "200003", "UMask": "0xe2", "Unit": "cpu_core" @@ -304,7 +302,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.CODE_RD_HIT", - "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads. Available PDIST counters: 0", + "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads.", "SampleAfterValue": "200003", "UMask": "0xc4", "Unit": "cpu_core" @@ -314,7 +312,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.CODE_RD_MISS", - "PublicDescription": "Counts L2 cache misses when fetching instructions. Available PDIST counters: 0", + "PublicDescription": "Counts L2 cache misses when fetching instructions.", "SampleAfterValue": "200003", "UMask": "0x24", "Unit": "cpu_core" @@ -324,7 +322,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.DEMAND_DATA_RD_HIT", - "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache.", "SampleAfterValue": "200003", "UMask": "0xc1", "Unit": "cpu_core" @@ -334,7 +332,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS", - "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once. Available PDIST counters: 0", + "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once.", "SampleAfterValue": "200003", "UMask": "0x21", "Unit": "cpu_core" @@ -344,7 +342,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.HIT", - "PublicDescription": "Counts all requests that hit L2 cache. [This event is alias to L2_REQUEST.HIT] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that hit L2 cache. [This event is alias to L2_REQUEST.HIT]", "SampleAfterValue": "200003", "UMask": "0xdf", "Unit": "cpu_core" @@ -354,7 +352,6 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.HWPF_MISS", - "PublicDescription": "L2_RQSTS.HWPF_MISS Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x30", "Unit": "cpu_core" @@ -364,7 +361,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.MISS", - "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS] Available PDIST counters: 0", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS]", "SampleAfterValue": "200003", "UMask": "0x3f", "Unit": "cpu_core" @@ -374,7 +371,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.REFERENCES", - "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL]", "SampleAfterValue": "200003", "UMask": "0xff", "Unit": "cpu_core" @@ -384,7 +381,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.RFO_HIT", - "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache.", "SampleAfterValue": "200003", "UMask": "0xc2", "Unit": "cpu_core" @@ -394,7 +391,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.RFO_MISS", - "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache.", "SampleAfterValue": "200003", "UMask": "0x22", "Unit": "cpu_core" @@ -404,7 +401,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.SWPF_HIT", - "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full. Available PDIST counters: 0", + "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full.", "SampleAfterValue": "200003", "UMask": "0xc8", "Unit": "cpu_core" @@ -414,7 +411,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.SWPF_MISS", - "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full. Available PDIST counters: 0", + "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full.", "SampleAfterValue": "200003", "UMask": "0x28", "Unit": "cpu_core" @@ -424,7 +421,7 @@ "Counter": "0,1,2,3", "EventCode": "0x23", "EventName": "L2_TRANS.L2_WB", - "PublicDescription": "Counts L2 writebacks that access L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts L2 writebacks that access L2 cache.", "SampleAfterValue": "200003", "UMask": "0x40", "Unit": "cpu_core" @@ -434,7 +431,7 @@ "Counter": "0,1,2,3", "EventCode": "0x42", "EventName": "LOCK_CYCLES.CACHE_LOCK_DURATION", - "PublicDescription": "This event counts the number of cycles when the L1D is locked. It is a superset of the 0x1 mask (BUS_LOCK_CLOCKS.BUS_LOCK_DURATION). Available PDIST counters: 0", + "PublicDescription": "This event counts the number of cycles when the L1D is locked. It is a superset of the 0x1 mask (BUS_LOCK_CLOCKS.BUS_LOCK_DURATION).", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -454,7 +451,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.MISS", - "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3. Available PDIST counters: 0", + "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", "SampleAfterValue": "100003", "UMask": "0x41", "Unit": "cpu_core" @@ -474,7 +471,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.REFERENCE", - "PublicDescription": "Counts core-originated cacheable requests to the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3. Available PDIST counters: 0", + "PublicDescription": "Counts core-originated cacheable requests to the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", "SampleAfterValue": "100003", "UMask": "0x4f", "Unit": "cpu_core" @@ -695,7 +692,7 @@ "Counter": "0,1,2,3", "EventCode": "0x43", "EventName": "MEM_LOAD_COMPLETED.L1_MISS_ANY", - "PublicDescription": "Number of completed demand load requests that missed the L1 data cache including shadow misses (FB hits, merge to an ongoing L1D miss) Available PDIST counters: 0", + "PublicDescription": "Number of completed demand load requests that missed the L1 data cache including shadow misses (FB hits, merge to an ongoing L1D miss)", "SampleAfterValue": "1000003", "UMask": "0xfd", "Unit": "cpu_core" @@ -947,7 +944,6 @@ "Counter": "0,1,2,3", "EventCode": "0x44", "EventName": "MEM_STORE_RETIRED.L2_HIT", - "PublicDescription": "MEM_STORE_RETIRED.L2_HIT Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x1", "Unit": "cpu_core" @@ -974,7 +970,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_1024", @@ -986,7 +982,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_128", @@ -998,7 +994,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_16", @@ -1010,7 +1006,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_2048", @@ -1022,7 +1018,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_256", @@ -1034,7 +1030,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_32", @@ -1046,7 +1042,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_4", @@ -1058,7 +1054,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_512", @@ -1070,7 +1066,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_64", @@ -1082,7 +1078,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_8", @@ -1177,7 +1173,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe5", "EventName": "MEM_UOP_RETIRED.ANY", - "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses Available PDIST counters: 0", + "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses", "SampleAfterValue": "1000003", "UMask": "0x3", "Unit": "cpu_core" @@ -1403,7 +1399,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.ALL_REQUESTS", - "PublicDescription": "Counts memory transactions reached the super queue including requests initiated by the core, all L3 prefetches, page walks, etc.. Available PDIST counters: 0", + "PublicDescription": "Counts memory transactions reached the super queue including requests initiated by the core, all L3 prefetches, page walks, etc..", "SampleAfterValue": "100003", "UMask": "0x80", "Unit": "cpu_core" @@ -1413,7 +1409,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DATA_RD", - "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type. Available PDIST counters: 0", + "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -1423,7 +1419,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_CODE_RD", - "PublicDescription": "Counts both cacheable and Non-Cacheable code read requests. Available PDIST counters: 0", + "PublicDescription": "Counts both cacheable and Non-Cacheable code read requests.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -1433,7 +1429,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_DATA_RD", - "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore. Available PDIST counters: 0", + "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -1443,7 +1439,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_RFO", - "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM. Available PDIST counters: 0", + "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -1454,7 +1450,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD", - "PublicDescription": "Counts cycles when offcore outstanding cacheable Core Data Read transactions are present in the super queue. A transaction is considered to be in the Offcore outstanding state between L2 miss and transaction completion sent to requestor (SQ de-allocation). See corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when offcore outstanding cacheable Core Data Read transactions are present in the super queue. A transaction is considered to be in the Offcore outstanding state between L2 miss and transaction completion sent to requestor (SQ de-allocation). See corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -1465,7 +1461,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_CODE_RD", - "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1476,7 +1472,6 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", - "PublicDescription": "Cycles where at least 1 outstanding demand data read request is pending. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1487,7 +1482,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO", - "PublicDescription": "Counts the number of offcore outstanding demand rfo Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding demand rfo Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x4", "Unit": "cpu_core" @@ -1497,7 +1492,6 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD", - "PublicDescription": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -1507,7 +1501,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_CODE_RD", - "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1517,7 +1511,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD", - "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor. Available PDIST counters: 0", + "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1527,7 +1521,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_RFO", - "PublicDescription": "Counts the number of off-core outstanding read-for-ownership (RFO) store transactions every cycle. An RFO transaction is considered to be in the Off-core outstanding state between L2 cache miss and transaction completion. Available PDIST counters: 0", + "PublicDescription": "Counts the number of off-core outstanding read-for-ownership (RFO) store transactions every cycle. An RFO transaction is considered to be in the Off-core outstanding state between L2 cache miss and transaction completion.", "SampleAfterValue": "1000003", "UMask": "0x4", "Unit": "cpu_core" @@ -1537,7 +1531,7 @@ "Counter": "0,1,2,3", "EventCode": "0x2c", "EventName": "SQ_MISC.BUS_LOCK", - "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory. Available PDIST counters: 0", + "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -1547,7 +1541,6 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.ANY", - "PublicDescription": "Counts the number of PREFETCHNTA, PREFETCHW, PREFETCHT0, PREFETCHT1 or PREFETCHT2 instructions executed. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0xf", "Unit": "cpu_core" @@ -1557,7 +1550,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.NTA", - "PublicDescription": "Counts the number of PREFETCHNTA instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHNTA instructions executed.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -1567,7 +1560,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.PREFETCHW", - "PublicDescription": "Counts the number of PREFETCHW instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHW instructions executed.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -1577,7 +1570,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.T0", - "PublicDescription": "Counts the number of PREFETCHT0 instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHT0 instructions executed.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -1587,7 +1580,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.T1_T2", - "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/floating-point.json b/tools/perf/pmu-events/arch/x86/meteorlake/floating-point.json index ae9778aa755b..28dc5e06ee31 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/floating-point.json @@ -15,7 +15,6 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.FPDIV_ACTIVE", - "PublicDescription": "This event counts the cycles the floating point divider is busy. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -25,7 +24,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.FP", - "PublicDescription": "Counts all microcode Floating Point assists. Available PDIST counters: 0", + "PublicDescription": "Counts all microcode Floating Point assists.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -35,7 +34,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.SSE_AVX_MIX", - "PublicDescription": "ASSISTS.SSE_AVX_MIX Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -45,7 +43,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_0", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -55,7 +52,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_1", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -65,7 +61,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_5", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -75,7 +70,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V0", - "PublicDescription": "FP_ARITH_DISPATCHED.V0 [This event is alias to FP_ARITH_DISPATCHED.PORT_0] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -85,7 +79,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V1", - "PublicDescription": "FP_ARITH_DISPATCHED.V1 [This event is alias to FP_ARITH_DISPATCHED.PORT_1] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -95,7 +88,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V2", - "PublicDescription": "FP_ARITH_DISPATCHED.V2 [This event is alias to FP_ARITH_DISPATCHED.PORT_5] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -105,7 +97,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -115,7 +107,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -125,7 +117,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -135,7 +127,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -145,7 +137,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.4_FLOPS", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x18", "Unit": "cpu_core" @@ -155,7 +147,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR", - "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "1000003", "UMask": "0x3", "Unit": "cpu_core" @@ -165,7 +157,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -175,7 +167,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_SINGLE", - "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -185,7 +177,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.VECTOR", - "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "1000003", "UMask": "0xfc", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json b/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json index 82727022efb6..6484834b1127 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json @@ -14,7 +14,7 @@ "Counter": "0,1,2,3", "EventCode": "0x60", "EventName": "BACLEARS.ANY", - "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0", + "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -24,7 +24,7 @@ "Counter": "0,1,2,3", "EventCode": "0x87", "EventName": "DECODE.LCP", - "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk. Available PDIST counters: 0", + "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk.", "SampleAfterValue": "500009", "UMask": "0x1", "Unit": "cpu_core" @@ -34,7 +34,6 @@ "Counter": "0,1,2,3", "EventCode": "0x87", "EventName": "DECODE.MS_BUSY", - "PublicDescription": "Cycles the Microcode Sequencer is busy. Available PDIST counters: 0", "SampleAfterValue": "500009", "UMask": "0x2", "Unit": "cpu_core" @@ -44,7 +43,7 @@ "Counter": "0,1,2,3", "EventCode": "0x61", "EventName": "DSB2MITE_SWITCHES.PENALTY_CYCLES", - "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE. Available PDIST counters: 0", + "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -405,7 +404,7 @@ "Counter": "0,1,2,3", "EventCode": "0x80", "EventName": "ICACHE_DATA.STALLS", - "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity.", "SampleAfterValue": "500009", "UMask": "0x4", "Unit": "cpu_core" @@ -417,7 +416,6 @@ "EdgeDetect": "1", "EventCode": "0x80", "EventName": "ICACHE_DATA.STALL_PERIODS", - "PublicDescription": "ICACHE_DATA.STALL_PERIODS Available PDIST counters: 0", "SampleAfterValue": "500009", "UMask": "0x4", "Unit": "cpu_core" @@ -427,7 +425,7 @@ "Counter": "0,1,2,3", "EventCode": "0x83", "EventName": "ICACHE_TAG.STALLS", - "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss.", "SampleAfterValue": "200003", "UMask": "0x4", "Unit": "cpu_core" @@ -438,7 +436,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_ANY", - "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -449,7 +447,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ. Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -459,7 +457,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.DSB_UOPS", - "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -470,7 +468,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.MITE_CYCLES_ANY", - "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -481,7 +479,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.MITE_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -491,7 +489,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.MITE_UOPS", - "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -502,7 +500,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.MS_CYCLES_ANY", - "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE.", "SampleAfterValue": "2000003", "UMask": "0x20", "Unit": "cpu_core" @@ -514,7 +512,7 @@ "EdgeDetect": "1", "EventCode": "0x79", "EventName": "IDQ.MS_SWITCHES", - "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer. Available PDIST counters: 0", + "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer.", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -524,7 +522,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.MS_UOPS", - "PublicDescription": "Counts the number of uops initiated by MITE or Decode Stream Buffer (DSB) and delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Counting includes uops that may 'bypass' the IDQ. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops initiated by MITE or Decode Stream Buffer (DSB) and delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Counting includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "1000003", "UMask": "0x20", "Unit": "cpu_core" @@ -534,7 +532,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CORE", - "PublicDescription": "This event counts a subset of the Topdown Slots event that when no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations. The count may be distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Frontend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method. Available PDIST counters: 0", + "PublicDescription": "This event counts a subset of the Topdown Slots event that when no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations. The count may be distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Frontend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -545,7 +543,7 @@ "CounterMask": "6", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE", - "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -557,7 +555,7 @@ "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CYCLES_FE_WAS_OK", "Invert": "1", - "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK]", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -567,7 +565,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CORE", - "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -578,7 +576,7 @@ "CounterMask": "6", "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE", - "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -590,7 +588,7 @@ "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK", "Invert": "1", - "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK]", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/memory.json b/tools/perf/pmu-events/arch/x86/meteorlake/memory.json index 17b94f810d5a..f0cbeda4d5ca 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/memory.json @@ -5,7 +5,6 @@ "CounterMask": "2", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L3_MISS", - "PublicDescription": "Cycles while L3 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -16,7 +15,6 @@ "CounterMask": "6", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L3_MISS", - "PublicDescription": "Execution stalls while L3 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x6", "Unit": "cpu_core" @@ -90,7 +88,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", - "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture Available PDIST counters: 0", + "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -101,7 +99,6 @@ "CounterMask": "2", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.CYCLES_L1D_MISS", - "PublicDescription": "Cycles while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -112,7 +109,6 @@ "CounterMask": "3", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L1D_MISS", - "PublicDescription": "Execution stalls while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x3", "Unit": "cpu_core" @@ -123,7 +119,7 @@ "CounterMask": "5", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L2_MISS", - "PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock). Available PDIST counters: 0", + "PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_core" @@ -134,7 +130,7 @@ "CounterMask": "9", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L3_MISS", - "PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock). Available PDIST counters: 0", + "PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).", "SampleAfterValue": "1000003", "UMask": "0x9", "Unit": "cpu_core" @@ -411,7 +407,6 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "Counts demand data read requests that miss the L3 cache. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -422,7 +417,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "Cycles with at least 1 Demand Data Read requests who miss L3 cache in the superQ. Available PDIST counters: 0", + "PublicDescription": "Cycles with at least 1 Demand Data Read requests who miss L3 cache in the superQ.", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -432,7 +427,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache. Available PDIST counters: 0", + "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache.", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/mtl-metrics.json b/tools/perf/pmu-events/arch/x86/meteorlake/mtl-metrics.json index 0088be169f9b..948c16a1f95b 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/mtl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/mtl-metrics.json @@ -1,56 +1,56 @@ [ { "BriefDescription": "C10 residency percent per package", - "MetricExpr": "cstate_pkg@c10\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c10\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C10_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C8 residency percent per package", - "MetricExpr": "cstate_pkg@c8\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c8\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C8_Pkg_Residency", "ScaleUnit": "100%" @@ -541,7 +541,7 @@ }, { "BriefDescription": "Average CPU Utilization", - "MetricExpr": "cpu_atom@CPU_CLK_UNHALTED.REF_TSC@ / TSC", + "MetricExpr": "cpu_atom@CPU_CLK_UNHALTED.REF_TSC@ / msr@tsc\\,cpu=cpu_atom@", "MetricName": "tma_info_system_cpu_utilization", "Unit": "cpu_atom" }, @@ -748,7 +748,7 @@ { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-be\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-be\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BvOB;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", "MetricThreshold": "tma_backend_bound > 0.2", @@ -786,24 +786,6 @@ "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)", "Unit": "cpu_core" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", - "Unit": "cpu_core" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency", - "Unit": "cpu_core" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", @@ -813,9 +795,27 @@ "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: ", "Unit": "cpu_core" }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency", + "Unit": "cpu_core" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20", @@ -823,7 +823,7 @@ }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * ((1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + cpu_core@RS.EMPTY_RESOURCE@ / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricExpr": "100 * ((1 - cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + cpu_core@RS.EMPTY_RESOURCE@ / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -859,7 +859,7 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -876,7 +876,7 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU has wasted due to Branch Misprediction", - "MetricExpr": "cpu_core@topdown\\-br\\-mispredict@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-br\\-mispredict@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BadSpec;BrMispredicts;BvMP;TmaL2;TopdownL2;tma_L2_group;tma_bad_speculation_group;tma_issueBM", "MetricName": "tma_branch_mispredicts", "MetricThreshold": "tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15", @@ -1007,7 +1007,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS@R, 24 * tma_info_system_core_frequency) + cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@ * min(cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@R, 25 * tma_info_system_core_frequency) * (cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ / (cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ + cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD@))) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;DataSharing;LockCont;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_contested_accesses", @@ -1124,7 +1123,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -1253,7 +1252,7 @@ }, { "BriefDescription": "This metric represents fraction of slots where the CPU was retiring heavy-weight operations -- instructions that require two or more uops or micro-coded sequences", - "MetricExpr": "cpu_core@topdown\\-heavy\\-ops@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-heavy\\-ops@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Retire;TmaL2;TopdownL2;tma_L2_group;tma_retiring_group", "MetricName": "tma_heavy_operations", "MetricThreshold": "tma_heavy_operations > 0.1", @@ -1923,7 +1922,7 @@ "Unit": "cpu_core" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "cpu_core@UOPS_EXECUTED.THREAD@ / (cpu_core@UOPS_EXECUTED.CORE_CYCLES_GE_1@ / 2 if #SMT_on else cpu_core@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute", @@ -1984,7 +1983,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc\\,cpu=cpu_core@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency", "Unit": "cpu_core" @@ -1998,7 +1997,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.REF_TSC@ / TSC", + "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.REF_TSC@ / msr@tsc\\,cpu=cpu_core@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized", "Unit": "cpu_core" @@ -2008,7 +2007,7 @@ "MetricExpr": "64 * (UNC_HAC_ARB_TRK_REQUESTS.ALL + UNC_HAC_ARB_COH_TRK_REQUESTS.ALL) / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full", + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full", "Unit": "cpu_core" }, { @@ -2094,6 +2093,13 @@ "MetricName": "tma_info_system_turbo_utilization", "Unit": "cpu_core" }, + { + "BriefDescription": "Measured Average Uncore Frequency for the SoC [GHz]", + "MetricExpr": "tma_info_system_socket_clks / 1e9 / tma_info_system_time", + "MetricGroup": "SoC", + "MetricName": "tma_info_system_uncore_frequency", + "Unit": "cpu_core" + }, { "BriefDescription": "Per-Logical Processor actual clocks when the Logical Processor is active.", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.THREAD@", @@ -2213,12 +2219,12 @@ "Unit": "cpu_core" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", "MetricExpr": "min(2 * (cpu_core@MEM_INST_RETIRED.ALL_LOADS@ - cpu_core@MEM_LOAD_RETIRED.FB_HIT@ - cpu_core@MEM_LOAD_RETIRED.L1_MISS@) * 20 / 100, max(cpu_core@CYCLE_ACTIVITY.CYCLES_MEM_ANY@ - cpu_core@MEMORY_ACTIVITY.CYCLES_L1D_MISS@, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2234,7 +2240,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles with demand load accesses that hit the L2 cache under unloaded scenarios (possibly L2 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_core@MEM_LOAD_RETIRED.L2_HIT@ * min(cpu_core@MEM_LOAD_RETIRED.L2_HIT@R, 3 * tma_info_system_core_frequency) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "MemoryLat;TopdownL4;tma_L4_group;tma_l2_bound_group", "MetricName": "tma_l2_hit_latency", @@ -2255,12 +2260,11 @@ }, { "BriefDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_core@MEM_LOAD_RETIRED.L3_HIT@ * min(cpu_core@MEM_LOAD_RETIRED.L3_HIT@R, 9 * tma_info_system_core_frequency) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2342,6 +2346,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_core@MEM_INST_RETIRED.LOCK_LOADS@ * cpu_core@MEM_INST_RETIRED.LOCK_LOADS@R / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -2377,7 +2382,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%", "Unit": "cpu_core" }, @@ -2387,13 +2392,13 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%", "Unit": "cpu_core" }, { "BriefDescription": "This metric represents fraction of slots the Memory subsystem within the Backend was a bottleneck", - "MetricExpr": "cpu_core@topdown\\-mem\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-mem\\-bound@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "Backend;TmaL2;TopdownL2;tma_L2_group;tma_backend_bound_group", "MetricName": "tma_memory_bound", "MetricThreshold": "tma_memory_bound > 0.2 & tma_backend_bound > 0.2", @@ -2404,7 +2409,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to LFENCE Instructions.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * cpu_core@MISC2_RETIRED.LFENCE@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_memory_fence", @@ -2463,7 +2467,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "max(cpu_core@IDQ.MS_CYCLES_ANY@, cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@ / (cpu_core@UOPS_RETIRED.SLOTS@ / cpu_core@UOPS_ISSUED.ANY@)) / tma_info_core_core_clks / 2", + "MetricExpr": "max(cpu_core@IDQ.MS_CYCLES_ANY@, cpu_core@UOPS_RETIRED.MS\\,cmask\\=1@ / (cpu_core@UOPS_RETIRED.SLOTS@ / cpu_core@UOPS_ISSUED.ANY@)) / tma_info_core_core_clks / 2.4", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -2502,6 +2506,7 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_light_operations - (tma_fp_arith + tma_int_operations + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", @@ -2570,6 +2575,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "((tma_ports_utilized_0 * tma_info_thread_clks + (cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ + tma_retiring * cpu_core@EXE_ACTIVITY.2_3_PORTS_UTIL@)) / tma_info_thread_clks if cpu_core@ARITH.DIV_ACTIVE@ < cpu_core@CYCLE_ACTIVITY.STALLS_TOTAL@ - cpu_core@EXE_ACTIVITY.BOUND_ON_LOADS@ else (cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ + tma_retiring * cpu_core@EXE_ACTIVITY.2_3_PORTS_UTIL@) / tma_info_thread_clks)", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", @@ -2580,6 +2586,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "max(cpu_core@EXE_ACTIVITY.EXE_BOUND_0_PORTS@ - cpu_core@RESOURCE_STALLS.SCOREBOARD@, 0) / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", @@ -2590,6 +2597,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", @@ -2600,7 +2608,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@EXE_ACTIVITY.2_PORTS_UTIL@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", @@ -2611,7 +2618,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 3 or more uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@UOPS_EXECUTED.CYCLES_GE_3@ / tma_info_thread_clks", "MetricGroup": "BvCB;PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_3m", @@ -2632,7 +2638,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "cpu_core@topdown\\-retiring@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@) + 0 * tma_info_thread_slots", + "MetricExpr": "cpu_core@topdown\\-retiring@ / (cpu_core@topdown\\-fe\\-bound@ + cpu_core@topdown\\-bad\\-spec@ + cpu_core@topdown\\-retiring@ + cpu_core@topdown\\-be\\-bound@)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -2663,7 +2669,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to PAUSE Instructions", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.PAUSE@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_slow_pause", @@ -2698,7 +2703,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%", "Unit": "cpu_core" }, diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/other.json b/tools/perf/pmu-events/arch/x86/meteorlake/other.json index cb21bb933617..8320ffd83c51 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/other.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/other.json @@ -4,7 +4,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.HARDWARE", - "PublicDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events. This includes, but not limited to, assists at EXE or MEM uop writeback like AVX* load/store/gather/scatter (non-FP GSSE-assist ) , assists generated by ROB like PEBS and RTIT, Uncore trap, RAR (Remote Action Request) and CET (Control flow Enforcement Technology) assists. the event also counts for Machine Ordering count. Available PDIST counters: 0", + "PublicDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events. This includes, but not limited to, assists at EXE or MEM uop writeback like AVX* load/store/gather/scatter (non-FP GSSE-assist ) , assists generated by ROB like PEBS and RTIT, Uncore trap, RAR (Remote Action Request) and CET (Control flow Enforcement Technology) assists. the event also counts for Machine Ordering count.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -14,7 +14,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.PAGE_FAULT", - "PublicDescription": "ASSISTS.PAGE_FAULT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -83,7 +82,7 @@ "CounterMask": "1", "EventCode": "0x2d", "EventName": "XQ.FULL_CYCLES", - "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache). Available PDIST counters: 0", + "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache).", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json b/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json index 22b25708e799..bfdaabe9377d 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json @@ -15,7 +15,7 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.DIV_ACTIVE", - "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations.", "SampleAfterValue": "1000003", "UMask": "0x9", "Unit": "cpu_core" @@ -26,7 +26,6 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.IDIV_ACTIVE", - "PublicDescription": "This event counts the cycles the integer divider is busy. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -36,7 +35,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.ANY", - "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists. Available PDIST counters: 0", + "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists.", "SampleAfterValue": "100003", "UMask": "0x1b", "Unit": "cpu_core" @@ -44,6 +43,7 @@ { "BriefDescription": "Counts the total number of branch instructions retired for all branch types.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "MTL012, MTL013", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.ALL_BRANCHES", "PublicDescription": "Counts the total number of instructions in which the instruction pointer (IP) of the processor is resteered due to a branch instruction and the branch instruction successfully retires. All branch type instructions are accounted for.", @@ -62,6 +62,7 @@ { "BriefDescription": "Counts the number of retired JCC (Jump on Conditional Code) branch instructions retired, includes both taken and not taken branches.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "MTL013", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.COND", "SampleAfterValue": "200003", @@ -110,6 +111,7 @@ { "BriefDescription": "Counts the number of far branch instructions retired, includes far jump, far call and return, and interrupt call and return.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "MTL013", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.FAR_BRANCH", "SampleAfterValue": "200003", @@ -129,6 +131,7 @@ { "BriefDescription": "Counts the number of near indirect JMP and near indirect CALL branch instructions retired.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "MTL013", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.INDIRECT", "SampleAfterValue": "200003", @@ -148,6 +151,7 @@ { "BriefDescription": "Counts the number of near indirect CALL branch instructions retired.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "MTL013", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.INDIRECT_CALL", "SampleAfterValue": "200003", @@ -167,6 +171,7 @@ "BriefDescription": "This event is deprecated. Refer to new event BR_INST_RETIRED.INDIRECT_CALL", "Counter": "0,1,2,3,4,5,6,7", "Deprecated": "1", + "Errata": "MTL013", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.IND_CALL", "SampleAfterValue": "200003", @@ -176,6 +181,7 @@ { "BriefDescription": "Counts the number of near CALL branch instructions retired.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "MTL012, MTL013", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_CALL", "SampleAfterValue": "200003", @@ -214,6 +220,7 @@ { "BriefDescription": "Counts the number of near taken branch instructions retired.", "Counter": "0,1,2,3,4,5,6,7", + "Errata": "MTL013", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.NEAR_TAKEN", "SampleAfterValue": "200003", @@ -484,7 +491,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C01", - "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" @@ -494,7 +501,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C02", - "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", "SampleAfterValue": "2000003", "UMask": "0x20", "Unit": "cpu_core" @@ -504,7 +511,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C0_WAIT", - "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction.", "SampleAfterValue": "2000003", "UMask": "0x70", "Unit": "cpu_core" @@ -530,7 +537,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.DISTRIBUTED", - "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread. Available PDIST counters: 0", + "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -540,7 +547,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE", - "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted. Available PDIST counters: 0", + "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted.", "SampleAfterValue": "25003", "UMask": "0x2", "Unit": "cpu_core" @@ -550,7 +557,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.PAUSE", - "PublicDescription": "CPU_CLK_UNHALTED.PAUSE Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x40", "Unit": "cpu_core" @@ -562,7 +568,6 @@ "EdgeDetect": "1", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.PAUSE_INST", - "PublicDescription": "CPU_CLK_UNHALTED.PAUSE_INST Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x40", "Unit": "cpu_core" @@ -572,7 +577,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_DISTRIBUTED", - "PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread. Available PDIST counters: 0", + "PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -589,7 +594,7 @@ "BriefDescription": "Reference cycles when the core is not in halt state.", "Counter": "Fixed counter 2", "EventName": "CPU_CLK_UNHALTED.REF_TSC", - "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case. Available PDIST counters: 0", + "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.", "SampleAfterValue": "2000003", "UMask": "0x3", "Unit": "cpu_core" @@ -609,7 +614,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_TSC_P", - "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case. Available PDIST counters: 0", + "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -626,7 +631,7 @@ "BriefDescription": "Core cycles when the thread is not in halt state", "Counter": "Fixed counter 1", "EventName": "CPU_CLK_UNHALTED.THREAD", - "PublicDescription": "Counts the number of core cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events. Available PDIST counters: 0", + "PublicDescription": "Counts the number of core cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -644,7 +649,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.THREAD_P", - "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time. Available PDIST counters: 0", + "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time.", "SampleAfterValue": "2000003", "Unit": "cpu_core" }, @@ -654,7 +659,6 @@ "CounterMask": "8", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L1D_MISS", - "PublicDescription": "Cycles while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8", "Unit": "cpu_core" @@ -665,7 +669,6 @@ "CounterMask": "1", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L2_MISS", - "PublicDescription": "Cycles while L2 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -676,7 +679,6 @@ "CounterMask": "16", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_MEM_ANY", - "PublicDescription": "Cycles while memory subsystem has an outstanding load. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -687,7 +689,6 @@ "CounterMask": "12", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L1D_MISS", - "PublicDescription": "Execution stalls while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0xc", "Unit": "cpu_core" @@ -698,7 +699,6 @@ "CounterMask": "5", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L2_MISS", - "PublicDescription": "Execution stalls while L2 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_core" @@ -709,7 +709,6 @@ "CounterMask": "4", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_TOTAL", - "PublicDescription": "Total execution stalls. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x4", "Unit": "cpu_core" @@ -719,7 +718,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.1_PORTS_UTIL", - "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -729,7 +728,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.2_3_PORTS_UTIL", - "PublicDescription": "Cycles total of 2 or 3 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0xc", "Unit": "cpu_core" @@ -739,7 +737,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.2_PORTS_UTIL", - "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -749,7 +747,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.3_PORTS_UTIL", - "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -759,7 +757,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.4_PORTS_UTIL", - "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" @@ -770,7 +768,6 @@ "CounterMask": "5", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.BOUND_ON_LOADS", - "PublicDescription": "Execution stalls while memory subsystem has an outstanding load. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x21", "Unit": "cpu_core" @@ -781,7 +778,7 @@ "CounterMask": "2", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.BOUND_ON_STORES", - "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall.", "SampleAfterValue": "1000003", "UMask": "0x40", "Unit": "cpu_core" @@ -791,7 +788,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.EXE_BOUND_0_PORTS", - "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load. Available PDIST counters: 0", + "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load.", "SampleAfterValue": "1000003", "UMask": "0x80", "Unit": "cpu_core" @@ -801,7 +798,7 @@ "Counter": "0,1,2,3", "EventCode": "0x75", "EventName": "INST_DECODED.DECODERS", - "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions. Available PDIST counters: 0", + "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -846,7 +843,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.MACRO_FUSED", - "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" @@ -856,7 +852,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.NOP", - "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions Available PDIST counters: 0", + "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -875,7 +871,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -887,7 +883,7 @@ "EdgeDetect": "1", "EventCode": "0xad", "EventName": "INT_MISC.CLEARS_COUNT", - "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears Available PDIST counters: 0", + "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears", "SampleAfterValue": "500009", "UMask": "0x1", "Unit": "cpu_core" @@ -897,7 +893,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.CLEAR_RESTEER_CYCLES", - "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path. Available PDIST counters: 0", + "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", "SampleAfterValue": "500009", "UMask": "0x80", "Unit": "cpu_core" @@ -907,7 +903,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.RECOVERY_CYCLES", - "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event. Available PDIST counters: 0", + "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event.", "SampleAfterValue": "500009", "UMask": "0x1", "Unit": "cpu_core" @@ -919,7 +915,6 @@ "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES", "MSRIndex": "0x3F7", "MSRValue": "0x7", - "PublicDescription": "Bubble cycles of BAClear (Unknown Branch). Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x40", "Unit": "cpu_core" @@ -929,7 +924,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.UOP_DROPPING", - "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons Available PDIST counters: 0", + "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -939,7 +934,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.128BIT", - "PublicDescription": "INT_VEC_RETIRED.128BIT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x13", "Unit": "cpu_core" @@ -949,7 +943,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.256BIT", - "PublicDescription": "INT_VEC_RETIRED.256BIT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0xac", "Unit": "cpu_core" @@ -959,7 +952,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.ADD_128", - "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions. Available PDIST counters: 0", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions.", "SampleAfterValue": "1000003", "UMask": "0x3", "Unit": "cpu_core" @@ -969,7 +962,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.ADD_256", - "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions. Available PDIST counters: 0", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions.", "SampleAfterValue": "1000003", "UMask": "0xc", "Unit": "cpu_core" @@ -979,7 +972,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.MUL_256", - "PublicDescription": "INT_VEC_RETIRED.MUL_256 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x80", "Unit": "cpu_core" @@ -989,7 +981,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.SHUFFLES", - "PublicDescription": "INT_VEC_RETIRED.SHUFFLES Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x40", "Unit": "cpu_core" @@ -999,7 +990,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.VNNI_128", - "PublicDescription": "INT_VEC_RETIRED.VNNI_128 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10", "Unit": "cpu_core" @@ -1009,7 +999,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.VNNI_256", - "PublicDescription": "INT_VEC_RETIRED.VNNI_256 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20", "Unit": "cpu_core" @@ -1028,7 +1017,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.ADDRESS_ALIAS", - "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -1047,7 +1036,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.NO_SR", - "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", "SampleAfterValue": "100003", "UMask": "0x88", "Unit": "cpu_core" @@ -1066,7 +1055,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.STORE_FORWARD", - "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide.", "SampleAfterValue": "100003", "UMask": "0x82", "Unit": "cpu_core" @@ -1076,7 +1065,7 @@ "Counter": "0,1,2,3", "EventCode": "0x4c", "EventName": "LOAD_HIT_PREFETCH.SWPF", - "PublicDescription": "Counts all software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions. Available PDIST counters: 0", + "PublicDescription": "Counts all software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -1087,7 +1076,7 @@ "CounterMask": "1", "EventCode": "0xa8", "EventName": "LSD.CYCLES_ACTIVE", - "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector). Available PDIST counters: 0", + "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector).", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1098,7 +1087,7 @@ "CounterMask": "6", "EventCode": "0xa8", "EventName": "LSD.CYCLES_OK", - "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector). Available PDIST counters: 0", + "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector).", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1108,7 +1097,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa8", "EventName": "LSD.UOPS", - "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector).", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1128,7 +1117,7 @@ "EdgeDetect": "1", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.COUNT", - "PublicDescription": "Counts the number of machine clears (nukes) of any type. Available PDIST counters: 0", + "PublicDescription": "Counts the number of machine clears (nukes) of any type.", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -1184,7 +1173,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.SMC", - "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear. Available PDIST counters: 0", + "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -1194,7 +1183,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe0", "EventName": "MISC2_RETIRED.LFENCE", - "PublicDescription": "number of LFENCE retired instructions Available PDIST counters: 0", + "PublicDescription": "number of LFENCE retired instructions", "SampleAfterValue": "400009", "UMask": "0x20", "Unit": "cpu_core" @@ -1213,7 +1202,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcc", "EventName": "MISC_RETIRED.LBR_INSERTS", - "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT. Available PDIST counters: 0", + "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT.", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -1223,7 +1212,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa2", "EventName": "RESOURCE_STALLS.SB", - "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end. Available PDIST counters: 0", + "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -1233,7 +1222,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa2", "EventName": "RESOURCE_STALLS.SCOREBOARD", - "PublicDescription": "Counts cycles where the pipeline is stalled due to serializing operations. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -1243,7 +1231,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa5", "EventName": "RS.EMPTY", - "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses) Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses)", "SampleAfterValue": "1000003", "UMask": "0x7", "Unit": "cpu_core" @@ -1256,7 +1244,7 @@ "EventCode": "0xa5", "EventName": "RS.EMPTY_COUNT", "Invert": "1", - "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events) Available PDIST counters: 0", + "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events)", "SampleAfterValue": "100003", "UMask": "0x7", "Unit": "cpu_core" @@ -1266,7 +1254,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa5", "EventName": "RS.EMPTY_RESOURCE", - "PublicDescription": "Cycles when RS was empty and a resource allocation stall is asserted Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1285,7 +1272,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.BACKEND_BOUND_SLOTS", - "PublicDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Backend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method. Available PDIST counters: 0", + "PublicDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Backend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "10000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1295,7 +1282,7 @@ "Counter": "0", "EventCode": "0xa4", "EventName": "TOPDOWN.BAD_SPEC_SLOTS", - "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations. Available PDIST counters: 0", + "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations.", "SampleAfterValue": "10000003", "UMask": "0x4", "Unit": "cpu_core" @@ -1305,7 +1292,7 @@ "Counter": "0", "EventCode": "0xa4", "EventName": "TOPDOWN.BR_MISPREDICT_SLOTS", - "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction. Available PDIST counters: 0", + "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction.", "SampleAfterValue": "10000003", "UMask": "0x8", "Unit": "cpu_core" @@ -1315,7 +1302,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.MEMORY_BOUND_SLOTS", - "PublicDescription": "TOPDOWN.MEMORY_BOUND_SLOTS Available PDIST counters: 0", "SampleAfterValue": "10000003", "UMask": "0x10", "Unit": "cpu_core" @@ -1324,7 +1310,7 @@ "BriefDescription": "TMA slots available for an unhalted logical processor. Fixed counter - architectural event", "Counter": "Fixed counter 3", "EventName": "TOPDOWN.SLOTS", - "PublicDescription": "Number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method (TMA). The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core. Software can use this event as the denominator for the top-level metrics of the TMA method. This architectural event is counted on a designated fixed counter (Fixed Counter 3). Available PDIST counters: 0", + "PublicDescription": "Number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method (TMA). The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core. Software can use this event as the denominator for the top-level metrics of the TMA method. This architectural event is counted on a designated fixed counter (Fixed Counter 3).", "SampleAfterValue": "10000003", "UMask": "0x4", "Unit": "cpu_core" @@ -1334,7 +1320,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.SLOTS_P", - "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core. Available PDIST counters: 0", + "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core.", "SampleAfterValue": "10000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1591,7 +1577,7 @@ "Counter": "0,1,2,3", "EventCode": "0x76", "EventName": "UOPS_DECODED.DEC0_UOPS", - "PublicDescription": "This event counts the number of not dec-by-all uops decoded by decoder 0. Available PDIST counters: 0", + "PublicDescription": "This event counts the number of not dec-by-all uops decoded by decoder 0.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1601,7 +1587,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_0", - "PublicDescription": "Number of uops dispatch to execution port 0. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 0.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1611,7 +1597,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_1", - "PublicDescription": "Number of uops dispatch to execution port 1. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 1.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1621,7 +1607,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_2_3_10", - "PublicDescription": "Number of uops dispatch to execution ports 2, 3 and 10 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 2, 3 and 10", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -1631,7 +1617,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_4_9", - "PublicDescription": "Number of uops dispatch to execution ports 4 and 9 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 4 and 9", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" @@ -1641,7 +1627,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_5_11", - "PublicDescription": "Number of uops dispatch to execution ports 5 and 11 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 5 and 11", "SampleAfterValue": "2000003", "UMask": "0x20", "Unit": "cpu_core" @@ -1651,7 +1637,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_6", - "PublicDescription": "Number of uops dispatch to execution port 6. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 6.", "SampleAfterValue": "2000003", "UMask": "0x40", "Unit": "cpu_core" @@ -1661,7 +1647,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_7_8", - "PublicDescription": "Number of uops dispatch to execution ports 7 and 8. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 7 and 8.", "SampleAfterValue": "2000003", "UMask": "0x80", "Unit": "cpu_core" @@ -1671,7 +1657,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE", - "PublicDescription": "Counts the number of uops executed from any thread. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops executed from any thread.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1682,7 +1668,7 @@ "CounterMask": "1", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_1", - "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1693,7 +1679,7 @@ "CounterMask": "2", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_2", - "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1704,7 +1690,7 @@ "CounterMask": "3", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_3", - "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1715,7 +1701,7 @@ "CounterMask": "4", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_4", - "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1726,7 +1712,7 @@ "CounterMask": "1", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_1", - "PublicDescription": "Cycles where at least 1 uop was executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 1 uop was executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1737,7 +1723,7 @@ "CounterMask": "2", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_2", - "PublicDescription": "Cycles where at least 2 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 2 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1748,7 +1734,7 @@ "CounterMask": "3", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_3", - "PublicDescription": "Cycles where at least 3 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 3 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1759,7 +1745,7 @@ "CounterMask": "4", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_4", - "PublicDescription": "Cycles where at least 4 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 4 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1771,7 +1757,7 @@ "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.STALLS", "Invert": "1", - "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1781,7 +1767,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.THREAD", - "PublicDescription": "Counts the number of uops to be executed per-thread each cycle. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1791,7 +1776,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.X87", - "PublicDescription": "Counts the number of x87 uops executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of x87 uops executed.", "SampleAfterValue": "2000003", "UMask": "0x10", "Unit": "cpu_core" @@ -1810,7 +1795,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xae", "EventName": "UOPS_ISSUED.ANY", - "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS).", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1821,7 +1806,6 @@ "CounterMask": "1", "EventCode": "0xae", "EventName": "UOPS_ISSUED.CYCLES", - "PublicDescription": "UOPS_ISSUED.CYCLES Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1840,7 +1824,7 @@ "CounterMask": "1", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.CYCLES", - "PublicDescription": "Counts cycles where at least one uop has retired. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where at least one uop has retired.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1850,7 +1834,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.HEAVY", - "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count. Available PDIST counters: 0", + "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count.", "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_core" @@ -1880,7 +1864,6 @@ "EventName": "UOPS_RETIRED.MS", "MSRIndex": "0x3F7", "MSRValue": "0x8", - "PublicDescription": "UOPS_RETIRED.MS Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4", "Unit": "cpu_core" @@ -1890,7 +1873,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.SLOTS", - "PublicDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric. Software can use this event as the numerator for the Retiring metric (or top-level category) of the Top-down Microarchitecture Analysis method. Available PDIST counters: 0", + "PublicDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric. Software can use this event as the numerator for the Retiring metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1902,7 +1885,7 @@ "EventCode": "0xc2", "EventName": "UOPS_RETIRED.STALLS", "Invert": "1", - "PublicDescription": "This event counts cycles without actually retired uops. Available PDIST counters: 0", + "PublicDescription": "This event counts cycles without actually retired uops.", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/virtual-memory.json b/tools/perf/pmu-events/arch/x86/meteorlake/virtual-memory.json index f300129e9e2d..305b96b26a4e 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/virtual-memory.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/virtual-memory.json @@ -13,7 +13,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.STLB_HIT", - "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB).", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -24,7 +24,7 @@ "CounterMask": "1", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -43,7 +43,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe", "Unit": "cpu_core" @@ -53,7 +53,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_1G", - "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -73,7 +73,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -93,7 +93,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -113,7 +113,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -132,7 +132,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.STLB_HIT", - "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB).", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -143,7 +143,7 @@ "CounterMask": "1", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -162,7 +162,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe", "Unit": "cpu_core" @@ -172,7 +172,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_1G", - "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x8", "Unit": "cpu_core" @@ -192,7 +192,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -212,7 +212,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -232,7 +232,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -260,7 +260,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.STLB_HIT", - "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB).", "SampleAfterValue": "100003", "UMask": "0x20", "Unit": "cpu_core" @@ -271,7 +271,7 @@ "CounterMask": "1", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" @@ -291,7 +291,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe", "Unit": "cpu_core" @@ -311,7 +311,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4", "Unit": "cpu_core" @@ -331,7 +331,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2", "Unit": "cpu_core" @@ -351,7 +351,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" From 6826aa4ffaef2a084a5036453c4295a110860827 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:11 -0700 Subject: [PATCH 0860/2711] perf vendor events: Update rocketlake metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-16-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/rocketlake/rkl-metrics.json | 105 ++++++++++-------- 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json b/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json index 71737a1a1997..79dc34157481 100644 --- a/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json @@ -1,63 +1,63 @@ [ { "BriefDescription": "C10 residency percent per package", - "MetricExpr": "cstate_pkg@c10\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c10\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C10_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C8 residency percent per package", - "MetricExpr": "cstate_pkg@c8\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c8\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C8_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C9 residency percent per package", - "MetricExpr": "cstate_pkg@c9\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c9\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C9_Pkg_Residency", "ScaleUnit": "100%" @@ -85,7 +85,6 @@ }, { "BriefDescription": "This metric estimates how often memory load accesses were aliased by preceding stores (in program order) with a 4K address offset", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_4k_aliasing", @@ -134,6 +133,7 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch related bottlenecks by large code footprint programs (i-side cache; TLB and BTB misses)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_fetch_latency * (tma_itlb_misses + tma_icache_misses + tma_unknown_branches) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)", "MetricGroup": "BigFootprint;BvBC;Fed;Frontend;IcMiss;MemoryTLB", "MetricName": "tma_bottleneck_big_code", @@ -147,40 +147,45 @@ "MetricThreshold": "tma_bottleneck_branching_overhead > 5", "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", "MetricGroup": "BvCB;Cor;tma_issueComp", "MetricName": "tma_bottleneck_compute_bound_est", "MetricThreshold": "tma_bottleneck_compute_bound_est > 20", "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: " }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20" }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -188,6 +193,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", @@ -196,6 +202,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", @@ -204,6 +211,7 @@ }, { "BriefDescription": "Total pipeline cost of Branch Misprediction related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * (tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Bad;BadSpec;BrMispredicts;BvMP;tma_issueBM", "MetricName": "tma_bottleneck_mispredictions", @@ -212,7 +220,8 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -220,6 +229,7 @@ }, { "BriefDescription": "Total pipeline cost of \"useful operations\" - the portion of Retiring category not covered by Branching_Overhead nor Irregular_Overhead.", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_retiring - (BR_INST_RETIRED.ALL_BRANCHES + 2 * BR_INST_RETIRED.NEAR_CALL + INST_RETIRED.NOP) / tma_info_thread_slots - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "BvUW;Ret", "MetricName": "tma_bottleneck_useful_work", @@ -427,7 +437,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%" }, { @@ -619,6 +629,7 @@ }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) hits - subset of the Instruction_Fetch_BW Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound * (tma_fetch_bandwidth / (tma_fetch_bandwidth + tma_fetch_latency)) * (tma_dsb / (tma_dsb + tma_lsd + tma_mite + tma_ms)))", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_botlnk_l2_dsb_bandwidth", @@ -1074,7 +1085,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1097,6 +1108,12 @@ "MetricGroup": "Fed;FetchBW", "MetricName": "tma_info_pipeline_fetch_mite" }, + { + "BriefDescription": "Average number of uops fetched from MS per cycle", + "MetricExpr": "IDQ.MS_UOPS / cpu@IDQ.MS_UOPS\\,cmask\\=1@", + "MetricGroup": "Fed;FetchLat;MicroSeq", + "MetricName": "tma_info_pipeline_fetch_ms" + }, { "BriefDescription": "Instructions per a microcode Assist invocation", "MetricExpr": "INST_RETIRED.ANY / ASSISTS.ANY", @@ -1113,7 +1130,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -1125,7 +1142,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -1134,7 +1151,7 @@ "MetricExpr": "64 * (UNC_ARB_TRK_REQUESTS.ALL + UNC_ARB_COH_TRK_REQUESTS.ALL) / 1e6 / tma_info_system_time / 1e3", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1165,6 +1182,7 @@ }, { "BriefDescription": "Average number of parallel data read requests to external memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "UNC_ARB_DAT_OCCUPANCY.RD / UNC_ARB_DAT_OCCUPANCY.RD@cmask\\=1@", "MetricGroup": "Mem;MemoryBW;SoC", "MetricName": "tma_info_system_mem_parallel_reads", @@ -1316,12 +1334,12 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", "MetricExpr": "min(2 * (MEM_INST_RETIRED.ALL_LOADS - MEM_LOAD_RETIRED.FB_HIT - MEM_LOAD_RETIRED.L1_MISS) * 20 / 100, max(CYCLE_ACTIVITY.CYCLES_MEM_ANY - CYCLE_ACTIVITY.CYCLES_L1D_MISS, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%" }, { @@ -1345,7 +1363,6 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(CYCLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS) / tma_info_thread_clks", "MetricGroup": "CacheHits;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -1359,7 +1376,7 @@ "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, { @@ -1465,7 +1482,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%" }, { @@ -1474,7 +1491,7 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, { @@ -1542,7 +1559,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "cpu@IDQ.MS_UOPS\\,cmask\\=1@ / tma_info_core_core_clks / 2", + "MetricExpr": "cpu@IDQ.MS_UOPS\\,cmask\\=1@ / tma_info_core_core_clks / 3.3", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -1676,7 +1693,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -1713,7 +1730,6 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -1727,7 +1743,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%" }, { @@ -1741,7 +1757,6 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * LD_BLOCKS.STORE_FORWARD / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", From 8d824b469d3272af00b01305d6adba86e2a03a1a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:12 -0700 Subject: [PATCH 0861/2711] perf vendor events: Update sandybridge metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-17-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/sandybridge/snb-metrics.json | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json b/tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json index 823d8b7c4224..d40761903429 100644 --- a/tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json +++ b/tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -71,7 +71,6 @@ }, { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "1 - (tma_frontend_bound + tma_bad_speculation + tma_retiring)", "MetricGroup": "BvOB;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", @@ -296,7 +295,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -308,7 +307,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, From 26f4b26f76bd468d5cf36219b5c7d3802be08462 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:13 -0700 Subject: [PATCH 0862/2711] perf vendor events: Update sapphirerapids events/metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update events from v1.28 to v1.30. Update metrics from TMA 5.0 to 5.1. The event updates come from: https://github.com/intel/perfmon/commit/c6a01e651c7be0dbc7a0e92ea915bb3c7e5970da https://github.com/intel/perfmon/commit/8b3a5b3f8ebf3cc48e29e3b65ecccb37f6fc3e81 Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-18-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../arch/x86/sapphirerapids/cache.json | 100 +++++------ .../x86/sapphirerapids/floating-point.json | 43 ++--- .../arch/x86/sapphirerapids/frontend.json | 42 +++-- .../arch/x86/sapphirerapids/memory.json | 30 ++-- .../arch/x86/sapphirerapids/other.json | 28 ++- .../arch/x86/sapphirerapids/pipeline.json | 167 +++++++----------- .../arch/x86/sapphirerapids/spr-metrics.json | 157 +++++++++------- .../x86/sapphirerapids/uncore-memory.json | 82 +++++++++ .../x86/sapphirerapids/virtual-memory.json | 40 ++--- 10 files changed, 384 insertions(+), 307 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index f8bf16d30602..d9daab4d8461 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -29,7 +29,7 @@ GenuineIntel-6-2E,v4,nehalemex,core GenuineIntel-6-CC,v1.00,pantherlake,core GenuineIntel-6-A7,v1.04,rocketlake,core GenuineIntel-6-2A,v19,sandybridge,core -GenuineIntel-6-8F,v1.28,sapphirerapids,core +GenuineIntel-6-8F,v1.30,sapphirerapids,core GenuineIntel-6-AF,v1.11,sierraforest,core GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v59,skylake,core diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json index 21db53f9e9d6..a30af5140e6c 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json @@ -4,7 +4,6 @@ "Counter": "0,1,2,3", "EventCode": "0x51", "EventName": "L1D.HWPF_MISS", - "PublicDescription": "L1D.HWPF_MISS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -13,7 +12,7 @@ "Counter": "0,1,2,3", "EventCode": "0x51", "EventName": "L1D.REPLACEMENT", - "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace. Available PDIST counters: 0", + "PublicDescription": "Counts L1D data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -22,7 +21,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.FB_FULL", - "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -33,7 +32,7 @@ "EdgeDetect": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.FB_FULL_PERIODS", - "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of phases a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -43,7 +42,6 @@ "Deprecated": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.L2_STALL", - "PublicDescription": "This event is deprecated. Refer to new event L1D_PEND_MISS.L2_STALLS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -52,7 +50,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.L2_STALLS", - "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses. Available PDIST counters: 0", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -61,7 +59,7 @@ "Counter": "0,1,2,3", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.PENDING", - "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type. Available PDIST counters: 0", + "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -71,7 +69,7 @@ "CounterMask": "1", "EventCode": "0x48", "EventName": "L1D_PEND_MISS.PENDING_CYCLES", - "PublicDescription": "Counts duration of L1D miss outstanding in cycles. Available PDIST counters: 0", + "PublicDescription": "Counts duration of L1D miss outstanding in cycles.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -80,7 +78,7 @@ "Counter": "0,1,2,3", "EventCode": "0x25", "EventName": "L2_LINES_IN.ALL", - "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects. Available PDIST counters: 0", + "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects.", "SampleAfterValue": "100003", "UMask": "0x1f" }, @@ -89,7 +87,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.NON_SILENT", - "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3 Available PDIST counters: 0", + "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3", "SampleAfterValue": "200003", "UMask": "0x2" }, @@ -98,7 +96,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.SILENT", - "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event. Available PDIST counters: 0", + "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event.", "SampleAfterValue": "200003", "UMask": "0x1" }, @@ -107,7 +105,7 @@ "Counter": "0,1,2,3", "EventCode": "0x26", "EventName": "L2_LINES_OUT.USELESS_HWPF", - "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache Available PDIST counters: 0", + "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache", "SampleAfterValue": "200003", "UMask": "0x4" }, @@ -116,7 +114,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.ALL", - "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES]", "SampleAfterValue": "200003", "UMask": "0xff" }, @@ -125,7 +123,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_REQUEST.MISS", - "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS] Available PDIST counters: 0", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS]", "SampleAfterValue": "200003", "UMask": "0x3f" }, @@ -134,7 +132,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_CODE_RD", - "PublicDescription": "Counts the total number of L2 code requests. Available PDIST counters: 0", + "PublicDescription": "Counts the total number of L2 code requests.", "SampleAfterValue": "200003", "UMask": "0xe4" }, @@ -143,7 +141,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_DATA_RD", - "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once. Available PDIST counters: 0", + "PublicDescription": "Counts Demand Data Read requests accessing the L2 cache. These requests may hit or miss L2 cache. True-miss exclude misses that were merged with ongoing L2 misses. An access is counted once.", "SampleAfterValue": "200003", "UMask": "0xe1" }, @@ -152,7 +150,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_MISS", - "PublicDescription": "Counts demand requests that miss L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts demand requests that miss L2 cache.", "SampleAfterValue": "200003", "UMask": "0x27" }, @@ -161,7 +159,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_DEMAND_REFERENCES", - "PublicDescription": "Counts demand requests to L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts demand requests to L2 cache.", "SampleAfterValue": "200003", "UMask": "0xe7" }, @@ -170,7 +168,6 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_HWPF", - "PublicDescription": "L2_RQSTS.ALL_HWPF Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0xf0" }, @@ -179,7 +176,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.ALL_RFO", - "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches. Available PDIST counters: 0", + "PublicDescription": "Counts the total number of RFO (read for ownership) requests to L2 cache. L2 RFO requests include both L1D demand RFO misses as well as L1D RFO prefetches.", "SampleAfterValue": "200003", "UMask": "0xe2" }, @@ -188,7 +185,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.CODE_RD_HIT", - "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads. Available PDIST counters: 0", + "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads.", "SampleAfterValue": "200003", "UMask": "0xc4" }, @@ -197,7 +194,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.CODE_RD_MISS", - "PublicDescription": "Counts L2 cache misses when fetching instructions. Available PDIST counters: 0", + "PublicDescription": "Counts L2 cache misses when fetching instructions.", "SampleAfterValue": "200003", "UMask": "0x24" }, @@ -206,7 +203,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.DEMAND_DATA_RD_HIT", - "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache.", "SampleAfterValue": "200003", "UMask": "0xc1" }, @@ -215,7 +212,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS", - "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once. Available PDIST counters: 0", + "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once.", "SampleAfterValue": "200003", "UMask": "0x21" }, @@ -224,7 +221,6 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.HWPF_MISS", - "PublicDescription": "L2_RQSTS.HWPF_MISS Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x30" }, @@ -233,7 +229,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.MISS", - "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS] Available PDIST counters: 0", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS]", "SampleAfterValue": "200003", "UMask": "0x3f" }, @@ -242,7 +238,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.REFERENCES", - "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL] Available PDIST counters: 0", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL]", "SampleAfterValue": "200003", "UMask": "0xff" }, @@ -251,7 +247,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.RFO_HIT", - "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache.", "SampleAfterValue": "200003", "UMask": "0xc2" }, @@ -260,7 +256,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.RFO_MISS", - "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache.", "SampleAfterValue": "200003", "UMask": "0x22" }, @@ -269,7 +265,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.SWPF_HIT", - "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full. Available PDIST counters: 0", + "PublicDescription": "Counts Software prefetch requests that hit the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full.", "SampleAfterValue": "200003", "UMask": "0xc8" }, @@ -278,7 +274,7 @@ "Counter": "0,1,2,3", "EventCode": "0x24", "EventName": "L2_RQSTS.SWPF_MISS", - "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full. Available PDIST counters: 0", + "PublicDescription": "Counts Software prefetch requests that miss the L2 cache. Accounts for PREFETCHNTA and PREFETCHT0/1/2 instructions when FB is not full.", "SampleAfterValue": "200003", "UMask": "0x28" }, @@ -287,7 +283,7 @@ "Counter": "0,1,2,3", "EventCode": "0x23", "EventName": "L2_TRANS.L2_WB", - "PublicDescription": "Counts L2 writebacks that access L2 cache. Available PDIST counters: 0", + "PublicDescription": "Counts L2 writebacks that access L2 cache.", "SampleAfterValue": "200003", "UMask": "0x40" }, @@ -296,7 +292,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.MISS", - "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3. Available PDIST counters: 0", + "PublicDescription": "Counts core-originated cacheable requests that miss the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", "SampleAfterValue": "100003", "UMask": "0x41" }, @@ -305,7 +301,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.REFERENCE", - "PublicDescription": "Counts core-originated cacheable requests to the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3. Available PDIST counters: 0", + "PublicDescription": "Counts core-originated cacheable requests to the L3 cache (Longest Latency cache). Requests include data and code reads, Reads-for-Ownership (RFOs), speculative accesses and hardware prefetches to the L1 and L2. It does not include hardware prefetches to the L3, and may not count other types of requests to the L3.", "SampleAfterValue": "100003", "UMask": "0x4f" }, @@ -394,7 +390,7 @@ "Counter": "0,1,2,3", "EventCode": "0x43", "EventName": "MEM_LOAD_COMPLETED.L1_MISS_ANY", - "PublicDescription": "Number of completed demand load requests that missed the L1 data cache including shadow misses (FB hits, merge to an ongoing L1D miss) Available PDIST counters: 0", + "PublicDescription": "Number of completed demand load requests that missed the L1 data cache including shadow misses (FB hits, merge to an ongoing L1D miss)", "SampleAfterValue": "1000003", "UMask": "0xfd" }, @@ -582,7 +578,6 @@ "Counter": "0,1,2,3", "EventCode": "0x44", "EventName": "MEM_STORE_RETIRED.L2_HIT", - "PublicDescription": "MEM_STORE_RETIRED.L2_HIT Available PDIST counters: 0", "SampleAfterValue": "200003", "UMask": "0x1" }, @@ -591,7 +586,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe5", "EventName": "MEM_UOP_RETIRED.ANY", - "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses Available PDIST counters: 0", + "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -1073,7 +1068,6 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.ALL_REQUESTS", - "PublicDescription": "OFFCORE_REQUESTS.ALL_REQUESTS Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -1082,7 +1076,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DATA_RD", - "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type. Available PDIST counters: 0", + "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -1091,7 +1085,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_CODE_RD", - "PublicDescription": "Counts both cacheable and non-cacheable code read requests. Available PDIST counters: 0", + "PublicDescription": "Counts both cacheable and non-cacheable code read requests.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -1100,7 +1094,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_DATA_RD", - "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore. Available PDIST counters: 0", + "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -1109,7 +1103,7 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.DEMAND_RFO", - "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM. Available PDIST counters: 0", + "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -1119,7 +1113,6 @@ "Deprecated": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD", - "PublicDescription": "This event is deprecated. Refer to new event OFFCORE_REQUESTS_OUTSTANDING.DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -1129,7 +1122,6 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD", - "PublicDescription": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -1139,7 +1131,7 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_CODE_RD", - "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1149,7 +1141,6 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", - "PublicDescription": "Cycles where at least 1 outstanding demand data read request is pending. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1159,7 +1150,6 @@ "CounterMask": "1", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO", - "PublicDescription": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -1168,7 +1158,6 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD", - "PublicDescription": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -1177,7 +1166,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_CODE_RD", - "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS. Available PDIST counters: 0", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1186,7 +1175,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD", - "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor. Available PDIST counters: 0", + "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor.", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -1195,7 +1184,7 @@ "Counter": "0,1,2,3", "EventCode": "0x2c", "EventName": "SQ_MISC.BUS_LOCK", - "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory. Available PDIST counters: 0", + "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -1204,7 +1193,6 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.ANY", - "PublicDescription": "Counts the number of PREFETCHNTA, PREFETCHW, PREFETCHT0, PREFETCHT1 or PREFETCHT2 instructions executed. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0xf" }, @@ -1213,7 +1201,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.NTA", - "PublicDescription": "Counts the number of PREFETCHNTA instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHNTA instructions executed.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -1222,7 +1210,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.PREFETCHW", - "PublicDescription": "Counts the number of PREFETCHW instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHW instructions executed.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -1231,7 +1219,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.T0", - "PublicDescription": "Counts the number of PREFETCHT0 instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHT0 instructions executed.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -1240,7 +1228,7 @@ "Counter": "0,1,2,3", "EventCode": "0x40", "EventName": "SW_PREFETCH_ACCESS.T1_T2", - "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed.", "SampleAfterValue": "100003", "UMask": "0x4" } diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/floating-point.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/floating-point.json index 8c9207750c82..bc475e163227 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/floating-point.json @@ -5,7 +5,6 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.FPDIV_ACTIVE", - "PublicDescription": "ARITH.FPDIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -14,7 +13,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.FP", - "PublicDescription": "Counts all microcode Floating Point assists. Available PDIST counters: 0", + "PublicDescription": "Counts all microcode Floating Point assists.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -23,7 +22,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.SSE_AVX_MIX", - "PublicDescription": "ASSISTS.SSE_AVX_MIX Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -32,7 +30,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_0", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -41,7 +38,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_1", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -50,7 +46,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_5", - "PublicDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -59,7 +54,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V0", - "PublicDescription": "FP_ARITH_DISPATCHED.V0 [This event is alias to FP_ARITH_DISPATCHED.PORT_0] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -68,7 +62,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V1", - "PublicDescription": "FP_ARITH_DISPATCHED.V1 [This event is alias to FP_ARITH_DISPATCHED.PORT_1] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -77,7 +70,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.V2", - "PublicDescription": "FP_ARITH_DISPATCHED.V2 [This event is alias to FP_ARITH_DISPATCHED.PORT_5] Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -86,7 +78,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -95,7 +87,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -104,7 +96,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -113,7 +105,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -122,7 +114,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.4_FLOPS", - "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x18" }, @@ -131,7 +123,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x40" }, @@ -140,7 +132,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE", - "PublicDescription": "Number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 512-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 16 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT14 RCP14 FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -149,7 +141,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.8_FLOPS", - "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision and 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision and double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RSQRT14 RCP RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision and 512-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision and double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RSQRT14 RCP RCP14 DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x60" }, @@ -158,7 +150,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR", - "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -167,7 +159,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_DOUBLE", - "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -176,7 +168,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.SCALAR_SINGLE", - "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -185,7 +177,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc7", "EventName": "FP_ARITH_INST_RETIRED.VECTOR", - "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events. Available PDIST counters: 0", + "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", "SampleAfterValue": "1000003", "UMask": "0xfc" }, @@ -194,7 +186,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.128B_PACKED_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.128B_PACKED_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -203,7 +194,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.256B_PACKED_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.256B_PACKED_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -212,7 +202,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.512B_PACKED_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.512B_PACKED_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -221,7 +210,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.COMPLEX_SCALAR_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.COMPLEX_SCALAR_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -230,7 +218,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.SCALAR", - "PublicDescription": "FP_ARITH_INST_RETIRED2.SCALAR Available PDIST counters: 0", + "PublicDescription": "FP_ARITH_INST_RETIRED2.SCALAR", "SampleAfterValue": "100003", "UMask": "0x3" }, @@ -239,7 +227,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.SCALAR_HALF", - "PublicDescription": "FP_ARITH_INST_RETIRED2.SCALAR_HALF Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -248,7 +235,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcf", "EventName": "FP_ARITH_INST_RETIRED2.VECTOR", - "PublicDescription": "FP_ARITH_INST_RETIRED2.VECTOR Available PDIST counters: 0", + "PublicDescription": "FP_ARITH_INST_RETIRED2.VECTOR", "SampleAfterValue": "100003", "UMask": "0x1c" } diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/frontend.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/frontend.json index 9fe9d62b867a..793c486ffabe 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/frontend.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/frontend.json @@ -4,7 +4,7 @@ "Counter": "0,1,2,3", "EventCode": "0x60", "EventName": "BACLEARS.ANY", - "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0", + "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -13,7 +13,7 @@ "Counter": "0,1,2,3", "EventCode": "0x87", "EventName": "DECODE.LCP", - "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk. Available PDIST counters: 0", + "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk.", "SampleAfterValue": "500009", "UMask": "0x1" }, @@ -22,7 +22,6 @@ "Counter": "0,1,2,3", "EventCode": "0x87", "EventName": "DECODE.MS_BUSY", - "PublicDescription": "Cycles the Microcode Sequencer is busy. Available PDIST counters: 0", "SampleAfterValue": "500009", "UMask": "0x2" }, @@ -31,7 +30,7 @@ "Counter": "0,1,2,3", "EventCode": "0x61", "EventName": "DSB2MITE_SWITCHES.PENALTY_CYCLES", - "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE. Available PDIST counters: 0", + "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -249,7 +248,7 @@ "Counter": "0,1,2,3", "EventCode": "0x80", "EventName": "ICACHE_DATA.STALLS", - "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity.", "SampleAfterValue": "500009", "UMask": "0x4" }, @@ -260,7 +259,6 @@ "EdgeDetect": "1", "EventCode": "0x80", "EventName": "ICACHE_DATA.STALL_PERIODS", - "PublicDescription": "ICACHE_DATA.STALL_PERIODS Available PDIST counters: 0", "SampleAfterValue": "500009", "UMask": "0x4" }, @@ -269,7 +267,7 @@ "Counter": "0,1,2,3", "EventCode": "0x83", "EventName": "ICACHE_TAG.STALLS", - "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss.", "SampleAfterValue": "200003", "UMask": "0x4" }, @@ -279,7 +277,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_ANY", - "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -289,7 +287,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ. Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -298,7 +296,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.DSB_UOPS", - "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -308,7 +306,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.MITE_CYCLES_ANY", - "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -318,7 +316,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.MITE_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -327,7 +325,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.MITE_UOPS", - "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB).", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -337,7 +335,7 @@ "CounterMask": "1", "EventCode": "0x79", "EventName": "IDQ.MS_CYCLES_ANY", - "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE.", "SampleAfterValue": "2000003", "UMask": "0x20" }, @@ -348,7 +346,7 @@ "EdgeDetect": "1", "EventCode": "0x79", "EventName": "IDQ.MS_SWITCHES", - "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer. Available PDIST counters: 0", + "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -357,7 +355,7 @@ "Counter": "0,1,2,3", "EventCode": "0x79", "EventName": "IDQ.MS_UOPS", - "PublicDescription": "Counts the total number of uops delivered by the Microcode Sequencer (MS). Available PDIST counters: 0", + "PublicDescription": "Counts the total number of uops delivered by the Microcode Sequencer (MS).", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -366,7 +364,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CORE", - "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -376,7 +374,7 @@ "CounterMask": "6", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE", - "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -387,7 +385,7 @@ "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CYCLES_FE_WAS_OK", "Invert": "1", - "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -396,7 +394,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CORE", - "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops not delivered to by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -406,7 +404,7 @@ "CounterMask": "6", "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE", - "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_0_UOPS_DELIV.CORE]", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -417,7 +415,7 @@ "EventCode": "0x9c", "EventName": "IDQ_UOPS_NOT_DELIVERED.CYCLES_FE_WAS_OK", "Invert": "1", - "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK] Available PDIST counters: 0", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls. This event counts for one SMT thread in a given cycle. [This event is alias to IDQ_BUBBLES.CYCLES_FE_WAS_OK]", "SampleAfterValue": "1000003", "UMask": "0x1" } diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/memory.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/memory.json index 7c3f9b76d367..5e6c1f05c981 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/memory.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/memory.json @@ -5,7 +5,6 @@ "CounterMask": "6", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L3_MISS", - "PublicDescription": "Execution stalls while L3 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x6" }, @@ -14,7 +13,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", - "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture Available PDIST counters: 0", + "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -24,7 +23,6 @@ "CounterMask": "2", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.CYCLES_L1D_MISS", - "PublicDescription": "Cycles while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -34,7 +32,6 @@ "CounterMask": "3", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L1D_MISS", - "PublicDescription": "Execution stalls while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -44,7 +41,7 @@ "CounterMask": "5", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L2_MISS", - "PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock). Available PDIST counters: 0", + "PublicDescription": "Execution stalls while L2 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).", "SampleAfterValue": "1000003", "UMask": "0x5" }, @@ -54,7 +51,7 @@ "CounterMask": "9", "EventCode": "0x47", "EventName": "MEMORY_ACTIVITY.STALLS_L3_MISS", - "PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock). Available PDIST counters: 0", + "PublicDescription": "Execution stalls while L3 cache miss demand cacheable load request is outstanding (will not count for uncacheable demand requests e.g. bus lock).", "SampleAfterValue": "1000003", "UMask": "0x9" }, @@ -478,7 +475,6 @@ "Counter": "0,1,2,3", "EventCode": "0x21", "EventName": "OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "Counts demand data read requests that miss the L3 cache. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -487,7 +483,7 @@ "Counter": "0,1,2,3", "EventCode": "0x20", "EventName": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD", - "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache. Available PDIST counters: 0", + "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -505,7 +501,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_EVENTS", - "PublicDescription": "Counts the number of times an RTM execution aborted due to none of the previous 3 categories (e.g. interrupt). Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to none of the previous 3 categories (e.g. interrupt).", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -514,7 +510,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_MEM", - "PublicDescription": "Counts the number of times an RTM execution aborted due to various memory events (e.g. read/write capacity and conflicts). Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to various memory events (e.g. read/write capacity and conflicts).", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -523,7 +519,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_MEMTYPE", - "PublicDescription": "Counts the number of times an RTM execution aborted due to incompatible memory type. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to incompatible memory type.", "SampleAfterValue": "100003", "UMask": "0x40" }, @@ -532,7 +528,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED_UNFRIENDLY", - "PublicDescription": "Counts the number of times an RTM execution aborted due to HLE-unfriendly instructions. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times an RTM execution aborted due to HLE-unfriendly instructions.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -541,7 +537,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.COMMIT", - "PublicDescription": "Counts the number of times RTM commit succeeded. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times RTM commit succeeded.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -550,7 +546,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc9", "EventName": "RTM_RETIRED.START", - "PublicDescription": "Counts the number of times we entered an RTM region. Does not count nested transactions. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times we entered an RTM region. Does not count nested transactions.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -559,7 +555,7 @@ "Counter": "0,1,2,3", "EventCode": "0x54", "EventName": "TX_MEM.ABORT_CAPACITY_READ", - "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional reads Available PDIST counters: 0", + "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional reads", "SampleAfterValue": "100003", "UMask": "0x80" }, @@ -568,7 +564,7 @@ "Counter": "0,1,2,3", "EventCode": "0x54", "EventName": "TX_MEM.ABORT_CAPACITY_WRITE", - "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional writes. Available PDIST counters: 0", + "PublicDescription": "Speculatively counts the number of Transactional Synchronization Extensions (TSX) aborts due to a data capacity limitation for transactional writes.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -577,7 +573,7 @@ "Counter": "0,1,2,3", "EventCode": "0x54", "EventName": "TX_MEM.ABORT_CONFLICT", - "PublicDescription": "Counts the number of times a TSX line had a cache conflict. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times a TSX line had a cache conflict.", "SampleAfterValue": "100003", "UMask": "0x1" } diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/other.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/other.json index a58d65556609..21f49f609ed4 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/other.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/other.json @@ -4,10 +4,34 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.PAGE_FAULT", - "PublicDescription": "ASSISTS.PAGE_FAULT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, + { + "BriefDescription": "HW_INTERRUPTS.MASKED", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.MASKED", + "SampleAfterValue": "100003", + "UMask": "0x2" + }, + { + "BriefDescription": "HW_INTERRUPTS.PENDING_AND_MASKED", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.PENDING_AND_MASKED", + "SampleAfterValue": "100003", + "UMask": "0x4" + }, + { + "BriefDescription": "Number of hardware interrupts received by the processor.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xcb", + "EventName": "HW_INTERRUPTS.RECEIVED", + "PublicDescription": "Counts the number of hardware interruptions received by the processor.", + "SampleAfterValue": "203", + "UMask": "0x1" + }, { "BriefDescription": "Counts streaming stores that have any type of response.", "Counter": "0,1,2,3", @@ -25,7 +49,7 @@ "CounterMask": "1", "EventCode": "0x2d", "EventName": "XQ.FULL_CYCLES", - "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache). Available PDIST counters: 0", + "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache).", "SampleAfterValue": "1000003", "UMask": "0x1" } diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json index 48bec483b49a..1fa7957956df 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json @@ -6,7 +6,6 @@ "Deprecated": "1", "EventCode": "0xb0", "EventName": "ARITH.DIVIDER_ACTIVE", - "PublicDescription": "This event is deprecated. Refer to new event ARITH.DIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x9" }, @@ -16,7 +15,7 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.DIV_ACTIVE", - "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations.", "SampleAfterValue": "1000003", "UMask": "0x9" }, @@ -27,7 +26,6 @@ "Deprecated": "1", "EventCode": "0xb0", "EventName": "ARITH.FP_DIVIDER_ACTIVE", - "PublicDescription": "This event is deprecated. Refer to new event ARITH.FPDIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -37,7 +35,6 @@ "CounterMask": "1", "EventCode": "0xb0", "EventName": "ARITH.IDIV_ACTIVE", - "PublicDescription": "This event counts the cycles the integer divider is busy. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -48,7 +45,6 @@ "Deprecated": "1", "EventCode": "0xb0", "EventName": "ARITH.INT_DIVIDER_ACTIVE", - "PublicDescription": "This event is deprecated. Refer to new event ARITH.IDIV_ACTIVE Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -57,7 +53,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc1", "EventName": "ASSISTS.ANY", - "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists. Available PDIST counters: 0", + "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists.", "SampleAfterValue": "100003", "UMask": "0x1b" }, @@ -217,7 +213,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C01", - "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -226,7 +222,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C02", - "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", "SampleAfterValue": "2000003", "UMask": "0x20" }, @@ -235,7 +231,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.C0_WAIT", - "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction. Available PDIST counters: 0", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction.", "SampleAfterValue": "2000003", "UMask": "0x70" }, @@ -244,7 +240,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.DISTRIBUTED", - "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread. Available PDIST counters: 0", + "PublicDescription": "This event distributes cycle counts between active hyperthreads, i.e., those in C0. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If all other hyperthreads are inactive (or disabled or do not exist), all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -253,7 +249,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE", - "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted. Available PDIST counters: 0", + "PublicDescription": "Counts Core crystal clock cycles when current thread is unhalted and the other thread is halted.", "SampleAfterValue": "25003", "UMask": "0x2" }, @@ -262,7 +258,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.PAUSE", - "PublicDescription": "CPU_CLK_UNHALTED.PAUSE Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x40" }, @@ -273,7 +268,6 @@ "EdgeDetect": "1", "EventCode": "0xec", "EventName": "CPU_CLK_UNHALTED.PAUSE_INST", - "PublicDescription": "CPU_CLK_UNHALTED.PAUSE_INST Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x40" }, @@ -282,7 +276,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_DISTRIBUTED", - "PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread. Available PDIST counters: 0", + "PublicDescription": "This event distributes Core crystal clock cycle counts between active hyperthreads, i.e., those in C0 sleep-state. A hyperthread becomes inactive when it executes the HLT or MWAIT instructions. If one thread is active in a core, all counts are attributed to this hyperthread. To obtain the full count when the Core is active, sum the counts from each hyperthread.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -299,7 +293,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_TSC_P", - "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case. Available PDIST counters: 0", + "PublicDescription": "Counts the number of reference cycles when the core is not in a halt state. The core enters the halt state when it is running the HLT instruction or the MWAIT instruction. This event is not affected by core frequency changes (for example, P states, TM2 transitions) but has the same incrementing frequency as the time stamp counter. This event can approximate elapsed time while the core was not in a halt state. It is counted on a dedicated fixed counter, leaving the four (eight when Hyperthreading is disabled) programmable counters available for other events. Note: On all current platforms this event stops counting during 'throttling (TM)' states duty off periods the processor is 'halted'. The counter update is done at a lower clock rate then the core clock the overflow status bit for this counter may appear 'sticky'. After the counter has overflowed and software clears the overflow status bit and resets the counter to less than MAX. The reset value to the counter is not clocked immediately so the overflow status bit will flip 'high (1)' and generate another PMI (if enabled) after which the reset value gets clocked into the counter. Therefore, software will get the interrupt, read the overflow status bit '1 for bit 34 while the counter value is less than MAX. Software should ignore this case.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -316,7 +310,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.THREAD_P", - "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time. Available PDIST counters: 0", + "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time.", "SampleAfterValue": "2000003" }, { @@ -325,7 +319,6 @@ "CounterMask": "8", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L1D_MISS", - "PublicDescription": "Cycles while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x8" }, @@ -335,7 +328,6 @@ "CounterMask": "1", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_L2_MISS", - "PublicDescription": "Cycles while L2 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -345,7 +337,6 @@ "CounterMask": "16", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.CYCLES_MEM_ANY", - "PublicDescription": "Cycles while memory subsystem has an outstanding load. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -355,7 +346,6 @@ "CounterMask": "12", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L1D_MISS", - "PublicDescription": "Execution stalls while L1 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0xc" }, @@ -365,7 +355,6 @@ "CounterMask": "5", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_L2_MISS", - "PublicDescription": "Execution stalls while L2 cache miss demand load is outstanding. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x5" }, @@ -375,7 +364,6 @@ "CounterMask": "4", "EventCode": "0xa3", "EventName": "CYCLE_ACTIVITY.STALLS_TOTAL", - "PublicDescription": "Total execution stalls. Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x4" }, @@ -384,7 +372,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb7", "EventName": "EXE.AMX_BUSY", - "PublicDescription": "Counts the cycles where the AMX (Advance Matrix Extension) unit is busy performing an operation. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -393,7 +380,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.1_PORTS_UTIL", - "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -402,7 +389,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.2_3_PORTS_UTIL", - "PublicDescription": "Cycles total of 2 or 3 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0xc" }, @@ -411,7 +397,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.2_PORTS_UTIL", - "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -420,7 +406,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.3_PORTS_UTIL", - "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -429,7 +415,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.4_PORTS_UTIL", - "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty. Available PDIST counters: 0", + "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -439,7 +425,6 @@ "CounterMask": "5", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.BOUND_ON_LOADS", - "PublicDescription": "Execution stalls while memory subsystem has an outstanding load. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x21" }, @@ -449,7 +434,7 @@ "CounterMask": "2", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.BOUND_ON_STORES", - "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall.", "SampleAfterValue": "1000003", "UMask": "0x40" }, @@ -458,7 +443,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa6", "EventName": "EXE_ACTIVITY.EXE_BOUND_0_PORTS", - "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load. Available PDIST counters: 0", + "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load.", "SampleAfterValue": "1000003", "UMask": "0x80" }, @@ -467,7 +452,7 @@ "Counter": "0,1,2,3", "EventCode": "0x75", "EventName": "INST_DECODED.DECODERS", - "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions. Available PDIST counters: 0", + "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -492,7 +477,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.MACRO_FUSED", - "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -501,7 +485,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.NOP", - "PublicDescription": "Counts all retired NOP or ENDBR32/64 instructions Available PDIST counters: 0", + "PublicDescription": "Counts all retired NOP or ENDBR32/64 instructions", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -518,7 +502,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", - "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", "SampleAfterValue": "2000003", "UMask": "0x8" }, @@ -529,7 +513,7 @@ "EdgeDetect": "1", "EventCode": "0xad", "EventName": "INT_MISC.CLEARS_COUNT", - "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears Available PDIST counters: 0", + "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears", "SampleAfterValue": "500009", "UMask": "0x1" }, @@ -538,7 +522,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.CLEAR_RESTEER_CYCLES", - "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path. Available PDIST counters: 0", + "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", "SampleAfterValue": "500009", "UMask": "0x80" }, @@ -547,7 +531,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.MBA_STALLS", - "PublicDescription": "INT_MISC.MBA_STALLS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -556,7 +539,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.RECOVERY_CYCLES", - "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event. Available PDIST counters: 0", + "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event.", "SampleAfterValue": "500009", "UMask": "0x1" }, @@ -567,7 +550,6 @@ "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES", "MSRIndex": "0x3F7", "MSRValue": "0x7", - "PublicDescription": "Bubble cycles of BAClear (Unknown Branch). Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x40" }, @@ -576,7 +558,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xad", "EventName": "INT_MISC.UOP_DROPPING", - "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons Available PDIST counters: 0", + "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -585,7 +567,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.128BIT", - "PublicDescription": "INT_VEC_RETIRED.128BIT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x13" }, @@ -594,7 +575,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.256BIT", - "PublicDescription": "INT_VEC_RETIRED.256BIT Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0xac" }, @@ -603,7 +583,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.ADD_128", - "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions. Available PDIST counters: 0", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions.", "SampleAfterValue": "1000003", "UMask": "0x3" }, @@ -612,7 +592,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.ADD_256", - "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions. Available PDIST counters: 0", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions.", "SampleAfterValue": "1000003", "UMask": "0xc" }, @@ -621,7 +601,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.MUL_256", - "PublicDescription": "INT_VEC_RETIRED.MUL_256 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x80" }, @@ -630,7 +609,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.SHUFFLES", - "PublicDescription": "INT_VEC_RETIRED.SHUFFLES Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x40" }, @@ -639,7 +617,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.VNNI_128", - "PublicDescription": "INT_VEC_RETIRED.VNNI_128 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x10" }, @@ -648,7 +625,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe7", "EventName": "INT_VEC_RETIRED.VNNI_256", - "PublicDescription": "INT_VEC_RETIRED.VNNI_256 Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x20" }, @@ -657,7 +633,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.ADDRESS_ALIAS", - "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -666,7 +642,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.NO_SR", - "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", "SampleAfterValue": "100003", "UMask": "0x88" }, @@ -675,7 +651,7 @@ "Counter": "0,1,2,3", "EventCode": "0x03", "EventName": "LD_BLOCKS.STORE_FORWARD", - "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide. Available PDIST counters: 0", + "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide.", "SampleAfterValue": "100003", "UMask": "0x82" }, @@ -684,7 +660,7 @@ "Counter": "0,1,2,3", "EventCode": "0x4c", "EventName": "LOAD_HIT_PREFETCH.SWPF", - "PublicDescription": "Counts all software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions. Available PDIST counters: 0", + "PublicDescription": "Counts all software-prefetch load dispatches that hit the fill buffer (FB) allocated for the software prefetch. It can also be incremented by some lock instructions. So it should only be used with profiling so that the locks can be excluded by ASM (Assembly File) inspection of the nearby instructions.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -694,7 +670,7 @@ "CounterMask": "1", "EventCode": "0xa8", "EventName": "LSD.CYCLES_ACTIVE", - "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector). Available PDIST counters: 0", + "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -704,7 +680,7 @@ "CounterMask": "6", "EventCode": "0xa8", "EventName": "LSD.CYCLES_OK", - "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector). Available PDIST counters: 0", + "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -713,7 +689,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa8", "EventName": "LSD.UOPS", - "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -724,7 +700,7 @@ "EdgeDetect": "1", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.COUNT", - "PublicDescription": "Counts the number of machine clears (nukes) of any type. Available PDIST counters: 0", + "PublicDescription": "Counts the number of machine clears (nukes) of any type.", "SampleAfterValue": "100003", "UMask": "0x1" }, @@ -733,7 +709,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc3", "EventName": "MACHINE_CLEARS.SMC", - "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear. Available PDIST counters: 0", + "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -742,7 +718,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe0", "EventName": "MISC2_RETIRED.LFENCE", - "PublicDescription": "number of LFENCE retired instructions Available PDIST counters: 0", + "PublicDescription": "number of LFENCE retired instructions", "SampleAfterValue": "400009", "UMask": "0x20" }, @@ -751,7 +727,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xcc", "EventName": "MISC_RETIRED.LBR_INSERTS", - "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT. Available PDIST counters: 0", + "PublicDescription": "Increments when an entry is added to the Last Branch Record (LBR) array (or removed from the array in case of RETURNs in call stack mode). The event requires LBR enable via IA32_DEBUGCTL MSR and branch type selection via MSR_LBR_SELECT.", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -760,7 +736,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa2", "EventName": "RESOURCE_STALLS.SB", - "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end. Available PDIST counters: 0", + "PublicDescription": "Counts allocation stall cycles caused by the store buffer (SB) being full. This counts cycles that the pipeline back-end blocked uop delivery from the front-end.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -769,7 +745,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa2", "EventName": "RESOURCE_STALLS.SCOREBOARD", - "PublicDescription": "Counts cycles where the pipeline is stalled due to serializing operations. Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -778,7 +753,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa5", "EventName": "RS.EMPTY", - "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses) Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses)", "SampleAfterValue": "1000003", "UMask": "0x7" }, @@ -790,7 +765,7 @@ "EventCode": "0xa5", "EventName": "RS.EMPTY_COUNT", "Invert": "1", - "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events) Available PDIST counters: 0", + "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events)", "SampleAfterValue": "100003", "UMask": "0x7" }, @@ -799,7 +774,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa5", "EventName": "RS.EMPTY_RESOURCE", - "PublicDescription": "Cycles when Reservation Station (RS) is empty due to a resource in the back-end Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -812,7 +786,6 @@ "EventCode": "0xa5", "EventName": "RS_EMPTY.COUNT", "Invert": "1", - "PublicDescription": "This event is deprecated. Refer to new event RS.EMPTY_COUNT Available PDIST counters: 0", "SampleAfterValue": "100003", "UMask": "0x7" }, @@ -822,7 +795,6 @@ "Deprecated": "1", "EventCode": "0xa5", "EventName": "RS_EMPTY.CYCLES", - "PublicDescription": "This event is deprecated. Refer to new event RS.EMPTY Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x7" }, @@ -831,7 +803,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.BACKEND_BOUND_SLOTS", - "PublicDescription": "Number of slots in TMA method where no micro-operations were being issued from front-end to back-end of the machine due to lack of back-end resources. Available PDIST counters: 0", + "PublicDescription": "Number of slots in TMA method where no micro-operations were being issued from front-end to back-end of the machine due to lack of back-end resources.", "SampleAfterValue": "10000003", "UMask": "0x2" }, @@ -840,7 +812,7 @@ "Counter": "0", "EventCode": "0xa4", "EventName": "TOPDOWN.BAD_SPEC_SLOTS", - "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations. Available PDIST counters: 0", + "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations.", "SampleAfterValue": "10000003", "UMask": "0x4" }, @@ -849,7 +821,7 @@ "Counter": "0", "EventCode": "0xa4", "EventName": "TOPDOWN.BR_MISPREDICT_SLOTS", - "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction. Available PDIST counters: 0", + "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction.", "SampleAfterValue": "10000003", "UMask": "0x8" }, @@ -858,7 +830,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.MEMORY_BOUND_SLOTS", - "PublicDescription": "TOPDOWN.MEMORY_BOUND_SLOTS Available PDIST counters: 0", "SampleAfterValue": "10000003", "UMask": "0x10" }, @@ -875,7 +846,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xa4", "EventName": "TOPDOWN.SLOTS_P", - "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core. Available PDIST counters: 0", + "PublicDescription": "Counts the number of available slots for an unhalted logical processor. The event increments by machine-width of the narrowest pipeline as employed by the Top-down Microarchitecture Analysis method. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core.", "SampleAfterValue": "10000003", "UMask": "0x1" }, @@ -884,7 +855,6 @@ "Counter": "0,1,2,3", "EventCode": "0x76", "EventName": "UOPS_DECODED.DEC0_UOPS", - "PublicDescription": "UOPS_DECODED.DEC0_UOPS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x1" }, @@ -893,7 +863,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_0", - "PublicDescription": "Number of uops dispatch to execution port 0. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 0.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -902,7 +872,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_1", - "PublicDescription": "Number of uops dispatch to execution port 1. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 1.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -911,7 +881,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_2_3_10", - "PublicDescription": "Number of uops dispatch to execution ports 2, 3 and 10 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 2, 3 and 10", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -920,7 +890,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_4_9", - "PublicDescription": "Number of uops dispatch to execution ports 4 and 9 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 4 and 9", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -929,7 +899,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_5_11", - "PublicDescription": "Number of uops dispatch to execution ports 5 and 11 Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 5 and 11", "SampleAfterValue": "2000003", "UMask": "0x20" }, @@ -938,7 +908,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_6", - "PublicDescription": "Number of uops dispatch to execution port 6. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution port 6.", "SampleAfterValue": "2000003", "UMask": "0x40" }, @@ -947,7 +917,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb2", "EventName": "UOPS_DISPATCHED.PORT_7_8", - "PublicDescription": "Number of uops dispatch to execution ports 7 and 8. Available PDIST counters: 0", + "PublicDescription": "Number of uops dispatch to execution ports 7 and 8.", "SampleAfterValue": "2000003", "UMask": "0x80" }, @@ -956,7 +926,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE", - "PublicDescription": "Counts the number of uops executed from any thread. Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops executed from any thread.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -966,7 +936,7 @@ "CounterMask": "1", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_1", - "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 1 micro-op is executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -976,7 +946,7 @@ "CounterMask": "2", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_2", - "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 2 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -986,7 +956,7 @@ "CounterMask": "3", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_3", - "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 3 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -996,7 +966,7 @@ "CounterMask": "4", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CORE_CYCLES_GE_4", - "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least 4 micro-ops are executed from any thread on physical core.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -1006,7 +976,7 @@ "CounterMask": "1", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_1", - "PublicDescription": "Cycles where at least 1 uop was executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 1 uop was executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1016,7 +986,7 @@ "CounterMask": "2", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_2", - "PublicDescription": "Cycles where at least 2 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 2 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1026,7 +996,7 @@ "CounterMask": "3", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_3", - "PublicDescription": "Cycles where at least 3 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 3 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1036,7 +1006,7 @@ "CounterMask": "4", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.CYCLES_GE_4", - "PublicDescription": "Cycles where at least 4 uops were executed per-thread. Available PDIST counters: 0", + "PublicDescription": "Cycles where at least 4 uops were executed per-thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1047,7 +1017,7 @@ "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.STALLS", "Invert": "1", - "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread. Available PDIST counters: 0", + "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1059,7 +1029,6 @@ "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.STALL_CYCLES", "Invert": "1", - "PublicDescription": "This event is deprecated. Refer to new event UOPS_EXECUTED.STALLS Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1068,7 +1037,6 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.THREAD", - "PublicDescription": "Counts the number of uops to be executed per-thread each cycle. Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1077,7 +1045,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xb1", "EventName": "UOPS_EXECUTED.X87", - "PublicDescription": "Counts the number of x87 uops executed. Available PDIST counters: 0", + "PublicDescription": "Counts the number of x87 uops executed.", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -1086,7 +1054,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xae", "EventName": "UOPS_ISSUED.ANY", - "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS). Available PDIST counters: 0", + "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS).", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1096,7 +1064,6 @@ "CounterMask": "1", "EventCode": "0xae", "EventName": "UOPS_ISSUED.CYCLES", - "PublicDescription": "UOPS_ISSUED.CYCLES Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1106,7 +1073,7 @@ "CounterMask": "1", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.CYCLES", - "PublicDescription": "Counts cycles where at least one uop has retired. Available PDIST counters: 0", + "PublicDescription": "Counts cycles where at least one uop has retired.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1115,7 +1082,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.HEAVY", - "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count. Available PDIST counters: 0", + "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -1126,7 +1093,6 @@ "EventName": "UOPS_RETIRED.MS", "MSRIndex": "0x3F7", "MSRValue": "0x8", - "PublicDescription": "UOPS_RETIRED.MS Available PDIST counters: 0", "SampleAfterValue": "2000003", "UMask": "0x4" }, @@ -1135,7 +1101,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.SLOTS", - "PublicDescription": "Counts the retirement slots used each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the retirement slots used each cycle.", "SampleAfterValue": "2000003", "UMask": "0x2" }, @@ -1146,7 +1112,7 @@ "EventCode": "0xc2", "EventName": "UOPS_RETIRED.STALLS", "Invert": "1", - "PublicDescription": "This event counts cycles without actually retired uops. Available PDIST counters: 0", + "PublicDescription": "This event counts cycles without actually retired uops.", "SampleAfterValue": "1000003", "UMask": "0x2" }, @@ -1158,7 +1124,6 @@ "EventCode": "0xc2", "EventName": "UOPS_RETIRED.STALL_CYCLES", "Invert": "1", - "PublicDescription": "This event is deprecated. Refer to new event UOPS_RETIRED.STALLS Available PDIST counters: 0", "SampleAfterValue": "1000003", "UMask": "0x2" } diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json index fe3f288be10e..8a18d6e01ef4 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json @@ -1,28 +1,28 @@ [ { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" @@ -90,6 +90,12 @@ "MetricName": "io_bandwidth_read", "ScaleUnit": "1MB/s" }, + { + "BriefDescription": "Bandwidth of inbound IO reads that are initiated by end device controllers that are requesting memory from the CPU and miss the L3 cache", + "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_MISS_PCIRDCUR * 64 / 1e6 / duration_time", + "MetricName": "io_bandwidth_read_l3_miss", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Bandwidth of IO reads that are initiated by end device controllers that are requesting memory from the local CPU socket", "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_LOCAL * 64 / 1e6 / duration_time", @@ -108,6 +114,12 @@ "MetricName": "io_bandwidth_write", "ScaleUnit": "1MB/s" }, + { + "BriefDescription": "Bandwidth of inbound IO writes that are initiated by end device controllers that are writing memory to the CPU", + "MetricExpr": "(UNC_CHA_TOR_INSERTS.IO_MISS_ITOM + UNC_CHA_TOR_INSERTS.IO_MISS_ITOMCACHENEAR) * 64 / 1e6 / duration_time", + "MetricName": "io_bandwidth_write_l3_miss", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Bandwidth of IO writes that are initiated by end device controllers that are writing memory to the local CPU socket", "MetricExpr": "(UNC_CHA_TOR_INSERTS.IO_ITOM_LOCAL + UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR_LOCAL) * 64 / 1e6 / duration_time", @@ -123,19 +135,19 @@ { "BriefDescription": "Percentage of inbound full cacheline writes initiated by end device controllers that miss the L3 cache", "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_MISS_ITOM / UNC_CHA_TOR_INSERTS.IO_ITOM", - "MetricName": "io_percent_of_inbound_full_writes_that_miss_l3", + "MetricName": "io_full_write_l3_miss", "ScaleUnit": "100%" }, { "BriefDescription": "Percentage of inbound partial cacheline writes initiated by end device controllers that miss the L3 cache", "MetricExpr": "(UNC_CHA_TOR_INSERTS.IO_MISS_ITOMCACHENEAR + UNC_CHA_TOR_INSERTS.IO_MISS_RFO) / (UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR + UNC_CHA_TOR_INSERTS.IO_RFO)", - "MetricName": "io_percent_of_inbound_partial_writes_that_miss_l3", + "MetricName": "io_partial_write_l3_miss", "ScaleUnit": "100%" }, { "BriefDescription": "Percentage of inbound reads initiated by end device controllers that miss the L3 cache", "MetricExpr": "UNC_CHA_TOR_INSERTS.IO_MISS_PCIRDCUR / UNC_CHA_TOR_INSERTS.IO_PCIRDCUR", - "MetricName": "io_percent_of_inbound_reads_that_miss_l3", + "MetricName": "io_read_l3_miss", "ScaleUnit": "100%" }, { @@ -395,7 +407,7 @@ { "BriefDescription": "This category represents fraction of slots where no uops are being delivered due to a lack of required resources for accepting new uops in the Backend", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BvOB;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", "MetricThreshold": "tma_backend_bound > 0.2", @@ -429,22 +441,6 @@ "MetricThreshold": "tma_bottleneck_branching_overhead > 5", "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * tma_amx_busy / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", @@ -453,16 +449,32 @@ "MetricThreshold": "tma_bottleneck_compute_bound_est > 20", "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: " }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - (1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20" }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * ((1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + RS.EMPTY_RESOURCE / tma_info_thread_clks * tma_ports_utilized_0) / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricExpr": "100 * ((1 - INST_RETIRED.REP_ITERATION / cpu@UOPS_RETIRED.MS\\,cmask\\=1@) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * tma_other_mispredicts / tma_branch_mispredicts) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + RS.EMPTY_RESOURCE / tma_info_thread_clks * tma_ports_utilized_0) / (tma_amx_busy + tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -470,7 +482,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", "MetricThreshold": "tma_bottleneck_memory_data_tlbs > 20", @@ -478,7 +490,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_cxl_mem_bound + tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", "MetricThreshold": "tma_bottleneck_memory_synchronization > 10", @@ -494,7 +506,7 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -510,7 +522,7 @@ { "BriefDescription": "This metric represents fraction of slots the CPU has wasted due to Branch Misprediction", "DefaultMetricgroupName": "TopdownL2", - "MetricExpr": "topdown\\-br\\-mispredict / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-br\\-mispredict / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BadSpec;BrMispredicts;BvMP;Default;TmaL2;TopdownL2;tma_L2_group;tma_bad_speculation_group;tma_issueBM", "MetricName": "tma_branch_mispredicts", "MetricThreshold": "tma_branch_mispredicts > 0.1 & tma_bad_speculation > 0.15", @@ -611,7 +623,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(76.6 * tma_info_system_core_frequency * (MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD * (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM / (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM + OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD))) + 74.6 * tma_info_system_core_frequency * MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "BvMS;DataSharing;LockCont;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_contested_accesses", @@ -630,6 +641,15 @@ "PublicDescription": "This metric represents fraction of slots where Core non-memory issues were of a bottleneck. Shortage in hardware compute resources; or dependencies in software's instructions are both categorized under Core Bound. Hence it may indicate the machine ran out of an out-of-order resource; certain execution units are overloaded or dependencies in program's data- or instruction-flow are limiting the performance (e.g. FP-chained long-latency arithmetic operations).", "ScaleUnit": "100%" }, + { + "BriefDescription": "This metric roughly estimates (based on idle latencies) how often the CPU was stalled on accesses to external CXL Memory by loads (e.g", + "MetricExpr": "(((1 - ((19 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + 10 * (MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS))) / (19 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + 10 * (MEM_LOAD_L3_MISS_RETIRED.LOCAL_DRAM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_FWD * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) + MEM_LOAD_L3_MISS_RETIRED.REMOTE_HITM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS)) + (25 * (MEM_LOAD_RETIRED.LOCAL_PMM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) if #has_pmem > 0 else 0) + 33 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_PMM * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS) if #has_pmem > 0 else 0))) if #has_pmem > 0 else 1)) * (MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks) if 1e6 * (MEM_LOAD_L3_MISS_RETIRED.REMOTE_PMM + MEM_LOAD_RETIRED.LOCAL_PMM) > MEM_LOAD_RETIRED.L1_MISS else 0) if #has_pmem > 0 else 0)", + "MetricGroup": "MemoryBound;Server;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", + "MetricName": "tma_cxl_mem_bound", + "MetricThreshold": "tma_cxl_mem_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", + "PublicDescription": "This metric roughly estimates (based on idle latencies) how often the CPU was stalled on accesses to external CXL Memory by loads (e.g. 3D-Xpoint (Crystal Ridge, a.k.a. IXP) memory, PMM - Persistent Memory Module [from CLX to SPR] or any other CXL Type3 Memory [EMR onwards]).", + "ScaleUnit": "100%" + }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", "MetricConstraint": "NO_GROUP_EVENTS", @@ -660,7 +680,7 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", - "MetricExpr": "MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks", + "MetricExpr": "(MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks - tma_cxl_mem_bound if #has_pmem > 0 else MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks)", "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_dram_bound", "MetricThreshold": "tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", @@ -718,7 +738,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%" }, { @@ -846,7 +866,7 @@ { "BriefDescription": "This metric represents fraction of slots where the CPU was retiring heavy-weight operations -- instructions that require two or more uops or micro-coded sequences", "DefaultMetricgroupName": "TopdownL2", - "MetricExpr": "topdown\\-heavy\\-ops / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-heavy\\-ops / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "Default;Retire;TmaL2;TopdownL2;tma_L2_group;tma_retiring_group", "MetricName": "tma_heavy_operations", "MetricThreshold": "tma_heavy_operations > 0.1", @@ -1357,19 +1377,19 @@ { "BriefDescription": "Off-core accesses per kilo instruction for modified write requests", "MetricExpr": "1e3 * OCR.MODIFIED_WRITE.ANY_RESPONSE / tma_info_inst_mix_instructions", - "MetricGroup": "Offcore", + "MetricGroup": "Offcore;Server", "MetricName": "tma_info_memory_mix_offcore_mwrite_any_pki" }, { "BriefDescription": "Off-core accesses per kilo instruction for reads-to-core requests (speculative; including in-core HW prefetches)", "MetricExpr": "1e3 * OCR.READS_TO_CORE.ANY_RESPONSE / tma_info_inst_mix_instructions", - "MetricGroup": "CacheHits;Offcore", + "MetricGroup": "CacheHits;Offcore;Server", "MetricName": "tma_info_memory_mix_offcore_read_any_pki" }, { "BriefDescription": "L3 cache misses per kilo instruction for reads-to-core requests (speculative; including in-core HW prefetches)", "MetricExpr": "1e3 * OCR.READS_TO_CORE.L3_MISS / tma_info_inst_mix_instructions", - "MetricGroup": "Offcore", + "MetricGroup": "Offcore;Server", "MetricName": "tma_info_memory_mix_offcore_read_l3m_pki" }, { @@ -1395,21 +1415,21 @@ { "BriefDescription": "Average DRAM BW for Reads-to-Core (R2C) covering for memory attached to local- and remote-socket", "MetricExpr": "64 * OCR.READS_TO_CORE.DRAM / 1e9 / tma_info_system_time", - "MetricGroup": "HPC;Mem;MemoryBW;SoC", + "MetricGroup": "HPC;Mem;MemoryBW;Offcore;Server", "MetricName": "tma_info_memory_soc_r2c_dram_bw", "PublicDescription": "Average DRAM BW for Reads-to-Core (R2C) covering for memory attached to local- and remote-socket. See R2C_Offcore_BW." }, { "BriefDescription": "Average L3-cache miss BW for Reads-to-Core (R2C)", "MetricExpr": "64 * OCR.READS_TO_CORE.L3_MISS / 1e9 / tma_info_system_time", - "MetricGroup": "HPC;Mem;MemoryBW;SoC", + "MetricGroup": "HPC;Mem;MemoryBW;Offcore;Server", "MetricName": "tma_info_memory_soc_r2c_l3m_bw", "PublicDescription": "Average L3-cache miss BW for Reads-to-Core (R2C). This covering going to DRAM or other memory off-chip memory tears. See R2C_Offcore_BW." }, { "BriefDescription": "Average Off-core access BW for Reads-to-Core (R2C)", "MetricExpr": "64 * OCR.READS_TO_CORE.ANY_RESPONSE / 1e9 / tma_info_system_time", - "MetricGroup": "HPC;Mem;MemoryBW;SoC", + "MetricGroup": "HPC;Mem;MemoryBW;Offcore;Server", "MetricName": "tma_info_memory_soc_r2c_offcore_bw", "PublicDescription": "Average Off-core access BW for Reads-to-Core (R2C). R2C account for demand or prefetch load/RFO/code access that fill data into the Core caches." }, @@ -1439,7 +1459,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1486,7 +1506,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -1498,16 +1518,28 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, + { + "BriefDescription": "Average 3DXP Memory Bandwidth Use for reads [GB / sec]", + "MetricExpr": "(64 * UNC_M_PMM_RPQ_INSERTS / 1e9 / tma_info_system_time if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryBW;Server;SoC", + "MetricName": "tma_info_system_cxl_mem_read_bw" + }, + { + "BriefDescription": "Average 3DXP Memory Bandwidth Use for Writes [GB / sec]", + "MetricExpr": "(64 * UNC_M_PMM_WPQ_INSERTS / 1e9 / tma_info_system_time if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryBW;Server;SoC", + "MetricName": "tma_info_system_cxl_mem_write_bw" + }, { "BriefDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]", "MetricExpr": "64 * (UNC_M_CAS_COUNT.RD + UNC_M_CAS_COUNT.WR) / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1571,9 +1603,15 @@ "MetricName": "tma_info_system_mem_parallel_reads", "PublicDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches" }, + { + "BriefDescription": "Average latency of data read request to external 3D X-Point memory [in nanoseconds]", + "MetricExpr": "(1e9 * (UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD_PMM / UNC_CHA_TOR_INSERTS.IA_MISS_DRD_PMM) / uncore_cha_0@event\\=0x1@ if #has_pmem > 0 else 0)", + "MetricGroup": "MemOffcore;MemoryLat;Server;SoC", + "MetricName": "tma_info_system_mem_pmm_read_latency", + "PublicDescription": "Average latency of data read request to external 3D X-Point memory [in nanoseconds]. Accounts for demand loads and L1/L2 data-read prefetches" + }, { "BriefDescription": "Average latency of data read request to external memory (in nanoseconds)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "1e9 * (UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD / UNC_CHA_TOR_INSERTS.IA_MISS_DRD) / (tma_info_system_socket_clks / tma_info_system_time)", "MetricGroup": "Mem;MemoryLat;SoC", "MetricName": "tma_info_system_mem_read_latency", @@ -1734,12 +1772,12 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", "MetricExpr": "min(2 * (MEM_INST_RETIRED.ALL_LOADS - MEM_LOAD_RETIRED.FB_HIT - MEM_LOAD_RETIRED.L1_MISS) * 20 / 100, max(CYCLE_ACTIVITY.CYCLES_MEM_ANY - MEMORY_ACTIVITY.CYCLES_L1D_MISS, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%" }, { @@ -1753,7 +1791,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles with demand load accesses that hit the L2 cache under unloaded scenarios (possibly L2 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "4.4 * tma_info_system_core_frequency * MEM_LOAD_RETIRED.L2_HIT * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "MemoryLat;TopdownL4;tma_L4_group;tma_l2_bound_group", "MetricName": "tma_l2_hit_latency", @@ -1772,12 +1809,11 @@ }, { "BriefDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "32.6 * tma_info_system_core_frequency * (MEM_LOAD_RETIRED.L3_HIT * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, { @@ -1860,6 +1896,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(16 * max(0, MEM_INST_RETIRED.LOCK_LOADS - L2_RQSTS.ALL_RFO) + MEM_INST_RETIRED.LOCK_LOADS / MEM_INST_RETIRED.ALL_STORES * (10 * L2_RQSTS.RFO_HIT + min(CPU_CLK_UNHALTED.THREAD, OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO))) / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -1892,7 +1929,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%" }, { @@ -1901,13 +1938,13 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, { "BriefDescription": "This metric represents fraction of slots the Memory subsystem within the Backend was a bottleneck", "DefaultMetricgroupName": "TopdownL2", - "MetricExpr": "topdown\\-mem\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-mem\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "Backend;Default;TmaL2;TopdownL2;tma_L2_group;tma_backend_bound_group", "MetricName": "tma_memory_bound", "MetricThreshold": "tma_memory_bound > 0.2 & tma_backend_bound > 0.2", @@ -1917,7 +1954,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to LFENCE Instructions.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * MISC2_RETIRED.LFENCE / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_memory_fence", @@ -1970,7 +2006,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "max(IDQ.MS_CYCLES_ANY, cpu@UOPS_RETIRED.MS\\,cmask\\=1@ / (UOPS_RETIRED.SLOTS / UOPS_ISSUED.ANY)) / tma_info_core_core_clks / 2", + "MetricExpr": "max(IDQ.MS_CYCLES_ANY, cpu@UOPS_RETIRED.MS\\,cmask\\=1@ / (UOPS_RETIRED.SLOTS / UOPS_ISSUED.ANY)) / tma_info_core_core_clks / 2.4", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -2005,6 +2041,7 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_light_operations - (tma_fp_arith + tma_int_operations + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", @@ -2066,6 +2103,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "((tma_ports_utilized_0 * tma_info_thread_clks + (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_3_PORTS_UTIL)) / tma_info_thread_clks if ARITH.DIV_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - EXE_ACTIVITY.BOUND_ON_LOADS else (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_3_PORTS_UTIL) / tma_info_thread_clks)", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", @@ -2075,6 +2113,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed no uops on any execution port (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "(EXE_ACTIVITY.EXE_BOUND_0_PORTS + max(RS.EMPTY_RESOURCE - RESOURCE_STALLS.SCOREBOARD, 0)) / tma_info_thread_clks * (CYCLE_ACTIVITY.STALLS_TOTAL - EXE_ACTIVITY.BOUND_ON_LOADS) / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_0", @@ -2084,6 +2123,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_THRESHOLD_AND_NMI", "MetricExpr": "EXE_ACTIVITY.1_PORTS_UTIL / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", @@ -2093,7 +2133,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "EXE_ACTIVITY.2_PORTS_UTIL / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", @@ -2103,7 +2142,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 3 or more uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "UOPS_EXECUTED.CYCLES_GE_3 / tma_info_thread_clks", "MetricGroup": "BvCB;PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_3m", @@ -2132,7 +2170,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -2160,7 +2198,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to PAUSE Instructions", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "CPU_CLK_UNHALTED.PAUSE / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_serializing_operation_group", "MetricName": "tma_slow_pause", @@ -2192,7 +2229,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%" }, { diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-memory.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-memory.json index 68be01dad7c9..90f61c9511fc 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-memory.json @@ -2769,6 +2769,88 @@ "UMask": "0x3", "Unit": "iMC" }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.HIGH", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Number of DRAM Refreshes Issued : Counts the number of refreshes issued.", + "UMask": "0x24", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.HIGH_ALL", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x24", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.HIGH_PCH0", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x4", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.HIGH_PCH1", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x20", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.PANIC", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Number of DRAM Refreshes Issued : Counts the number of refreshes issued.", + "UMask": "0x12", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.PANIC_ALL", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x12", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.PANIC_PCH0", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x2", + "Unit": "iMC" + }, + { + "BriefDescription": "Number of DRAM Refreshes Issued", + "Counter": "0,1,2,3", + "EventCode": "0x45", + "EventName": "UNC_M_DRAM_REFRESH.PANIC_PCH1", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x10", + "Unit": "iMC" + }, { "BriefDescription": "ECC Correctable Errors", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/virtual-memory.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/virtual-memory.json index 3d3f88600e26..609a9549cbf3 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/virtual-memory.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/virtual-memory.json @@ -4,7 +4,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.STLB_HIT", - "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB).", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -14,7 +14,7 @@ "CounterMask": "1", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -23,7 +23,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data loads. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe" }, @@ -32,7 +32,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_1G", - "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -41,7 +41,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -50,7 +50,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -59,7 +59,7 @@ "Counter": "0,1,2,3", "EventCode": "0x12", "EventName": "DTLB_LOAD_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -68,7 +68,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.STLB_HIT", - "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB).", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -78,7 +78,7 @@ "CounterMask": "1", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -87,7 +87,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by demand data stores. This implies it missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe" }, @@ -96,7 +96,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_1G", - "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x8" }, @@ -105,7 +105,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -114,7 +114,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -123,7 +123,7 @@ "Counter": "0,1,2,3", "EventCode": "0x13", "EventName": "DTLB_STORE_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -132,7 +132,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.STLB_HIT", - "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB). Available PDIST counters: 0", + "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB).", "SampleAfterValue": "100003", "UMask": "0x20" }, @@ -142,7 +142,7 @@ "CounterMask": "1", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_ACTIVE", - "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request. Available PDIST counters: 0", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request.", "SampleAfterValue": "100003", "UMask": "0x10" }, @@ -151,7 +151,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED", - "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (all page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0xe" }, @@ -160,7 +160,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M", - "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x4" }, @@ -169,7 +169,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_COMPLETED_4K", - "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault. Available PDIST counters: 0", + "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", "SampleAfterValue": "100003", "UMask": "0x2" }, @@ -178,7 +178,7 @@ "Counter": "0,1,2,3", "EventCode": "0x11", "EventName": "ITLB_MISSES.WALK_PENDING", - "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle. Available PDIST counters: 0", + "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle.", "SampleAfterValue": "100003", "UMask": "0x10" } From f1980de60459a372301e673fa3185e2ee3c61c1f Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:14 -0700 Subject: [PATCH 0863/2711] perf vendor events: Update sierraforest metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-19-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/sierraforest/srf-metrics.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/sierraforest/srf-metrics.json b/tools/perf/pmu-events/arch/x86/sierraforest/srf-metrics.json index b9f3c611d87b..ca2c55917e55 100644 --- a/tools/perf/pmu-events/arch/x86/sierraforest/srf-metrics.json +++ b/tools/perf/pmu-events/arch/x86/sierraforest/srf-metrics.json @@ -1,56 +1,56 @@ [ { "BriefDescription": "C10 residency percent per package", - "MetricExpr": "cstate_pkg@c10\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c10\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C10_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C1 residency percent per core", - "MetricExpr": "cstate_core@c1\\-residency@ / TSC", + "MetricExpr": "cstate_core@c1\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C1_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C8 residency percent per package", - "MetricExpr": "cstate_pkg@c8\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c8\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C8_Pkg_Residency", "ScaleUnit": "100%" @@ -735,7 +735,7 @@ }, { "BriefDescription": "Average CPU Utilization", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricName": "tma_info_system_cpu_utilization" }, { @@ -747,7 +747,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "cpu@CPU_CLK_UNHALTED.CORE_P@k / CPU_CLK_UNHALTED.CORE", + "MetricExpr": "CPU_CLK_UNHALTED.CORE_P:k / CPU_CLK_UNHALTED.CORE", "MetricGroup": "Summary", "MetricName": "tma_info_system_kernel_utilization" }, From 94ce35cdb626733f0473615fd6337b9bdc44ea84 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:15 -0700 Subject: [PATCH 0864/2711] perf vendor events: Update skylake metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-20-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/skylake/skl-metrics.json | 109 ++++++++++++------ .../arch/x86/skylakex/skx-metrics.json | 109 ++++++++++++------ 2 files changed, 142 insertions(+), 76 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json b/tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json index 2d3a037e88b5..707bd8790ed2 100644 --- a/tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -80,6 +80,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_0 + UOPS_DISPATCHED_PORT.PORT_1 + UOPS_DISPATCHED_PORT.PORT_5 + UOPS_DISPATCHED_PORT.PORT_6) / tma_info_thread_slots", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_alu_op_utilization", @@ -117,6 +118,7 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch related bottlenecks by large code footprint programs (i-side cache; TLB and BTB misses)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_fetch_latency * (tma_itlb_misses + tma_icache_misses + tma_unknown_branches) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)", "MetricGroup": "BigFootprint;BvBC;Fed;Frontend;IcMiss;MemoryTLB", "MetricName": "tma_bottleneck_big_code", @@ -130,32 +132,36 @@ "MetricThreshold": "tma_bottleneck_branching_overhead > 5", "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", "MetricGroup": "BvCB;Cor;tma_issueComp", "MetricName": "tma_bottleneck_compute_bound_est", "MetricThreshold": "tma_bottleneck_compute_bound_est > 20", "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: " }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * (10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts)) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", @@ -163,6 +169,7 @@ }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * (10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts)) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", @@ -171,6 +178,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", @@ -179,6 +187,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", @@ -187,6 +196,7 @@ }, { "BriefDescription": "Total pipeline cost of Branch Misprediction related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * (tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Bad;BadSpec;BrMispredicts;BvMP;tma_issueBM", "MetricName": "tma_bottleneck_mispredictions", @@ -195,7 +205,8 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -203,6 +214,7 @@ }, { "BriefDescription": "Total pipeline cost of \"useful operations\" - the portion of Retiring category not covered by Branching_Overhead nor Irregular_Overhead.", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_retiring - (BR_INST_RETIRED.ALL_BRANCHES + 2 * BR_INST_RETIRED.NEAR_CALL + INST_RETIRED.NOP) / tma_info_thread_slots - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "BvUW;Ret", "MetricName": "tma_bottleneck_useful_work", @@ -230,6 +242,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU retired uops originated from CISC (complex instruction set computer) instruction", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_microcode_sequencer - tma_assists)", "MetricGroup": "TopdownL4;tma_L4_group;tma_microcode_sequencer_group", "MetricName": "tma_cisc", @@ -391,7 +404,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%" }, { @@ -454,7 +467,6 @@ }, { "BriefDescription": "This metric approximates arithmetic floating-point (FP) vector uops fraction the CPU has retired aggregated across all vector widths", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "FP_ARITH_INST_RETIRED.VECTOR / UOPS_RETIRED.RETIRE_SLOTS", "MetricGroup": "Compute;Flops;TopdownL4;tma_L4_group;tma_fp_arith_group;tma_issue2P", "MetricName": "tma_fp_vector", @@ -520,6 +532,7 @@ }, { "BriefDescription": "Branch Misprediction Cost: Cycles representing fraction of TMA slots wasted per non-speculative branch misprediction (retired JEClear)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_bottleneck_mispredictions * tma_info_thread_slots / 4 / BR_MISP_RETIRED.ALL_BRANCHES / 100", "MetricGroup": "Bad;BrMispredicts;tma_issueBM", "MetricName": "tma_info_bad_spec_branch_misprediction_cost", @@ -555,6 +568,7 @@ }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) hits - subset of the Instruction_Fetch_BW Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound * (tma_fetch_bandwidth / (tma_fetch_bandwidth + tma_fetch_latency)) * (tma_dsb / (tma_dsb + tma_mite)))", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_botlnk_l2_dsb_bandwidth", @@ -572,6 +586,7 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -713,7 +728,6 @@ }, { "BriefDescription": "Instructions per FP Arithmetic instruction (lower number means higher occurrence rate)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "INST_RETIRED.ANY / (FP_ARITH_INST_RETIRED.SCALAR + FP_ARITH_INST_RETIRED.VECTOR)", "MetricGroup": "Flops;InsType", "MetricName": "tma_info_inst_mix_iparith", @@ -975,7 +989,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -992,6 +1006,12 @@ "MetricGroup": "Fed;FetchBW", "MetricName": "tma_info_pipeline_fetch_mite" }, + { + "BriefDescription": "Average number of uops fetched from MS per cycle", + "MetricExpr": "IDQ.MS_UOPS / cpu@IDQ.MS_UOPS\\,cmask\\=1@", + "MetricGroup": "Fed;FetchLat;MicroSeq", + "MetricName": "tma_info_pipeline_fetch_ms" + }, { "BriefDescription": "Instructions per a microcode Assist invocation", "MetricExpr": "INST_RETIRED.ANY / (FP_ASSIST.ANY + OTHER_ASSISTS.ANY)", @@ -1008,7 +1028,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -1020,7 +1040,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -1029,7 +1049,7 @@ "MetricExpr": "64 * (UNC_ARB_TRK_REQUESTS.ALL + UNC_ARB_COH_TRK_REQUESTS.ALL) / 1e6 / tma_info_system_time / 1e3", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1175,12 +1195,13 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "min(2 * (MEM_INST_RETIRED.ALL_LOADS - MEM_LOAD_RETIRED.FB_HIT - MEM_LOAD_RETIRED.L1_MISS) * 20 / 100, max(CYCLE_ACTIVITY.CYCLES_MEM_ANY - CYCLE_ACTIVITY.CYCLES_L1D_MISS, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%" }, { @@ -1217,7 +1238,7 @@ "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, { @@ -1241,6 +1262,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_2 + UOPS_DISPATCHED_PORT.PORT_3 + UOPS_DISPATCHED_PORT.PORT_7 - UOPS_DISPATCHED_PORT.PORT_4) / (2 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", @@ -1267,6 +1289,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 1 GB pages for data load accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_load_stlb_miss * DTLB_LOAD_MISSES.WALK_COMPLETED_1G / (DTLB_LOAD_MISSES.WALK_COMPLETED_4K + DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M + DTLB_LOAD_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_load_stlb_miss_group", "MetricName": "tma_load_stlb_miss_1g", @@ -1275,6 +1298,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 2 or 4 MB pages for data load accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_load_stlb_miss * DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M / (DTLB_LOAD_MISSES.WALK_COMPLETED_4K + DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M + DTLB_LOAD_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_load_stlb_miss_group", "MetricName": "tma_load_stlb_miss_2m", @@ -1283,6 +1307,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 4 KB pages for data load accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_load_stlb_miss * DTLB_LOAD_MISSES.WALK_COMPLETED_4K / (DTLB_LOAD_MISSES.WALK_COMPLETED_4K + DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M + DTLB_LOAD_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_load_stlb_miss_group", "MetricName": "tma_load_stlb_miss_4k", @@ -1291,6 +1316,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(12 * max(0, MEM_INST_RETIRED.LOCK_LOADS - L2_RQSTS.ALL_RFO) + MEM_INST_RETIRED.LOCK_LOADS / MEM_INST_RETIRED.ALL_STORES * (9 * L2_RQSTS.RFO_HIT + min(CPU_CLK_UNHALTED.THREAD, OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO))) / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -1315,7 +1341,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%" }, { @@ -1324,7 +1350,7 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, { @@ -1348,7 +1374,6 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU was retiring uops fetched by the Microcode Sequencer (MS) unit", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / UOPS_ISSUED.ANY * IDQ.MS_UOPS / tma_info_thread_slots", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_heavy_operations_group;tma_issueMC;tma_issueMS", "MetricName": "tma_microcode_sequencer", @@ -1358,6 +1383,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to Branch Resteers as a result of Branch Misprediction at execution stage", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "BR_MISP_RETIRED.ALL_BRANCHES / (BR_MISP_RETIRED.ALL_BRANCHES + MACHINE_CLEARS.COUNT) * INT_MISC.CLEAR_RESTEER_CYCLES / tma_info_thread_clks", "MetricGroup": "BadSpec;BrMispredicts;BvMP;TopdownL4;tma_L4_group;tma_branch_resteers_group;tma_issueBM", "MetricName": "tma_mispredicts_resteers", @@ -1412,6 +1438,7 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_light_operations - (tma_fp_arith + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", @@ -1421,6 +1448,7 @@ }, { "BriefDescription": "This metric estimates fraction of slots the CPU was stalled due to other cases of misprediction (non-retired x86 branches or other types).", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(tma_branch_mispredicts * (1 - BR_MISP_RETIRED.ALL_BRANCHES / (INT_MISC.CLEARS_COUNT - MACHINE_CLEARS.COUNT)), 0.0001)", "MetricGroup": "BrMispredicts;BvIO;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_other_mispredicts", @@ -1429,6 +1457,7 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU has wasted due to Nukes (Machine Clears) not related to memory ordering.", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(tma_machine_clears * (1 - MACHINE_CLEARS.MEMORY_ORDERING / MACHINE_CLEARS.COUNT), 0.0001)", "MetricGroup": "BvIO;Machine_Clears;TopdownL3;tma_L3_group;tma_machine_clears_group", "MetricName": "tma_other_nukes", @@ -1509,6 +1538,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "((tma_ports_utilized_0 * tma_info_thread_clks + (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL)) / tma_info_thread_clks if ARITH.DIVIDER_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY else (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL) / tma_info_thread_clks)", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", @@ -1595,7 +1625,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%" }, { @@ -1652,6 +1682,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 1 GB pages for data store accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_store_stlb_miss * DTLB_STORE_MISSES.WALK_COMPLETED_1G / (DTLB_STORE_MISSES.WALK_COMPLETED_4K + DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M + DTLB_STORE_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_store_stlb_miss_group", "MetricName": "tma_store_stlb_miss_1g", @@ -1660,6 +1691,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 2 or 4 MB pages for data store accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_store_stlb_miss * DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M / (DTLB_STORE_MISSES.WALK_COMPLETED_4K + DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M + DTLB_STORE_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_store_stlb_miss_group", "MetricName": "tma_store_stlb_miss_2m", @@ -1668,6 +1700,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 4 KB pages for data store accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_store_stlb_miss * DTLB_STORE_MISSES.WALK_COMPLETED_4K / (DTLB_STORE_MISSES.WALK_COMPLETED_4K + DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M + DTLB_STORE_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_store_stlb_miss_group", "MetricName": "tma_store_stlb_miss_4k", diff --git a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json b/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json index 7cc7b076c3e2..56c2caaafef4 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json @@ -1,49 +1,49 @@ [ { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per core", - "MetricExpr": "cstate_core@c3\\-residency@ / TSC", + "MetricExpr": "cstate_core@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" @@ -301,6 +301,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_0 + UOPS_DISPATCHED_PORT.PORT_1 + UOPS_DISPATCHED_PORT.PORT_5 + UOPS_DISPATCHED_PORT.PORT_6) / tma_info_thread_slots", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_alu_op_utilization", @@ -338,6 +339,7 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch related bottlenecks by large code footprint programs (i-side cache; TLB and BTB misses)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_fetch_latency * (tma_itlb_misses + tma_icache_misses + tma_unknown_branches) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)", "MetricGroup": "BigFootprint;BvBC;Fed;Frontend;IcMiss;MemoryTLB", "MetricName": "tma_bottleneck_big_code", @@ -351,32 +353,36 @@ "MetricThreshold": "tma_bottleneck_branching_overhead > 5", "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", "MetricGroup": "BvCB;Cor;tma_issueComp", "MetricName": "tma_bottleneck_compute_bound_est", "MetricThreshold": "tma_bottleneck_compute_bound_est > 20", "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: " }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * (10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts)) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", @@ -384,6 +390,7 @@ }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + tma_mispredicts_resteers * (10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts)) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", @@ -392,6 +399,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", @@ -400,6 +408,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) * tma_remote_cache / (tma_local_mem + tma_remote_cache + tma_remote_mem) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", @@ -408,6 +417,7 @@ }, { "BriefDescription": "Total pipeline cost of Branch Misprediction related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * (tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Bad;BadSpec;BrMispredicts;BvMP;tma_issueBM", "MetricName": "tma_bottleneck_mispredictions", @@ -416,7 +426,8 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -424,6 +435,7 @@ }, { "BriefDescription": "Total pipeline cost of \"useful operations\" - the portion of Retiring category not covered by Branching_Overhead nor Irregular_Overhead.", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_retiring - (BR_INST_RETIRED.ALL_BRANCHES + 2 * BR_INST_RETIRED.NEAR_CALL + INST_RETIRED.NOP) / tma_info_thread_slots - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "BvUW;Ret", "MetricName": "tma_bottleneck_useful_work", @@ -451,6 +463,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU retired uops originated from CISC (complex instruction set computer) instruction", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_microcode_sequencer - tma_assists)", "MetricGroup": "TopdownL4;tma_L4_group;tma_microcode_sequencer_group", "MetricName": "tma_cisc", @@ -612,7 +625,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%" }, { @@ -675,7 +688,6 @@ }, { "BriefDescription": "This metric approximates arithmetic floating-point (FP) vector uops fraction the CPU has retired aggregated across all vector widths", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE\\,umask\\=0xfc@ / UOPS_RETIRED.RETIRE_SLOTS", "MetricGroup": "Compute;Flops;TopdownL4;tma_L4_group;tma_fp_arith_group;tma_issue2P", "MetricName": "tma_fp_vector", @@ -750,6 +762,7 @@ }, { "BriefDescription": "Branch Misprediction Cost: Cycles representing fraction of TMA slots wasted per non-speculative branch misprediction (retired JEClear)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_bottleneck_mispredictions * tma_info_thread_slots / 4 / BR_MISP_RETIRED.ALL_BRANCHES / 100", "MetricGroup": "Bad;BrMispredicts;tma_issueBM", "MetricName": "tma_info_bad_spec_branch_misprediction_cost", @@ -785,6 +798,7 @@ }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) hits - subset of the Instruction_Fetch_BW Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound * (tma_fetch_bandwidth / (tma_fetch_bandwidth + tma_fetch_latency)) * (tma_dsb / (tma_dsb + tma_mite)))", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_botlnk_l2_dsb_bandwidth", @@ -802,6 +816,7 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -943,7 +958,6 @@ }, { "BriefDescription": "Instructions per FP Arithmetic instruction (lower number means higher occurrence rate)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "INST_RETIRED.ANY / (FP_ARITH_INST_RETIRED.SCALAR + cpu@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE\\,umask\\=0xfc@)", "MetricGroup": "Flops;InsType", "MetricName": "tma_info_inst_mix_iparith", @@ -1225,7 +1239,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1242,6 +1256,12 @@ "MetricGroup": "Fed;FetchBW", "MetricName": "tma_info_pipeline_fetch_mite" }, + { + "BriefDescription": "Average number of uops fetched from MS per cycle", + "MetricExpr": "IDQ.MS_UOPS / cpu@IDQ.MS_UOPS\\,cmask\\=1@", + "MetricGroup": "Fed;FetchLat;MicroSeq", + "MetricName": "tma_info_pipeline_fetch_ms" + }, { "BriefDescription": "Instructions per a microcode Assist invocation", "MetricExpr": "INST_RETIRED.ANY / (FP_ASSIST.ANY + OTHER_ASSISTS.ANY)", @@ -1258,7 +1278,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -1270,7 +1290,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -1279,7 +1299,7 @@ "MetricExpr": "64 * (UNC_M_CAS_COUNT.RD + UNC_M_CAS_COUNT.WR) / 1e9 / tma_info_system_time", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1475,12 +1495,13 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "min(2 * (MEM_INST_RETIRED.ALL_LOADS - MEM_LOAD_RETIRED.FB_HIT - MEM_LOAD_RETIRED.L1_MISS) * 20 / 100, max(CYCLE_ACTIVITY.CYCLES_MEM_ANY - CYCLE_ACTIVITY.CYCLES_L1D_MISS, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%" }, { @@ -1517,7 +1538,7 @@ "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, { @@ -1541,6 +1562,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(UOPS_DISPATCHED_PORT.PORT_2 + UOPS_DISPATCHED_PORT.PORT_3 + UOPS_DISPATCHED_PORT.PORT_7 - UOPS_DISPATCHED_PORT.PORT_4) / (2 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", @@ -1567,6 +1589,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 1 GB pages for data load accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_load_stlb_miss * DTLB_LOAD_MISSES.WALK_COMPLETED_1G / (DTLB_LOAD_MISSES.WALK_COMPLETED_4K + DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M + DTLB_LOAD_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_load_stlb_miss_group", "MetricName": "tma_load_stlb_miss_1g", @@ -1575,6 +1598,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 2 or 4 MB pages for data load accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_load_stlb_miss * DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M / (DTLB_LOAD_MISSES.WALK_COMPLETED_4K + DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M + DTLB_LOAD_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_load_stlb_miss_group", "MetricName": "tma_load_stlb_miss_2m", @@ -1583,6 +1607,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 4 KB pages for data load accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_load_stlb_miss * DTLB_LOAD_MISSES.WALK_COMPLETED_4K / (DTLB_LOAD_MISSES.WALK_COMPLETED_4K + DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M + DTLB_LOAD_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_load_stlb_miss_group", "MetricName": "tma_load_stlb_miss_4k", @@ -1600,6 +1625,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(12 * max(0, MEM_INST_RETIRED.LOCK_LOADS - L2_RQSTS.ALL_RFO) + MEM_INST_RETIRED.LOCK_LOADS / MEM_INST_RETIRED.ALL_STORES * (11 * L2_RQSTS.RFO_HIT + min(CPU_CLK_UNHALTED.THREAD, OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO))) / tma_info_thread_clks", "MetricGroup": "LockCont;Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -1624,7 +1650,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%" }, { @@ -1633,7 +1659,7 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, { @@ -1657,7 +1683,6 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU was retiring uops fetched by the Microcode Sequencer (MS) unit", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / UOPS_ISSUED.ANY * IDQ.MS_UOPS / tma_info_thread_slots", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_heavy_operations_group;tma_issueMC;tma_issueMS", "MetricName": "tma_microcode_sequencer", @@ -1667,6 +1692,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to Branch Resteers as a result of Branch Misprediction at execution stage", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "BR_MISP_RETIRED.ALL_BRANCHES / (BR_MISP_RETIRED.ALL_BRANCHES + MACHINE_CLEARS.COUNT) * INT_MISC.CLEAR_RESTEER_CYCLES / tma_info_thread_clks", "MetricGroup": "BadSpec;BrMispredicts;BvMP;TopdownL4;tma_L4_group;tma_branch_resteers_group;tma_issueBM", "MetricName": "tma_mispredicts_resteers", @@ -1721,6 +1747,7 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_light_operations - (tma_fp_arith + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", @@ -1730,6 +1757,7 @@ }, { "BriefDescription": "This metric estimates fraction of slots the CPU was stalled due to other cases of misprediction (non-retired x86 branches or other types).", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(tma_branch_mispredicts * (1 - BR_MISP_RETIRED.ALL_BRANCHES / (INT_MISC.CLEARS_COUNT - MACHINE_CLEARS.COUNT)), 0.0001)", "MetricGroup": "BrMispredicts;BvIO;TopdownL3;tma_L3_group;tma_branch_mispredicts_group", "MetricName": "tma_other_mispredicts", @@ -1738,6 +1766,7 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU has wasted due to Nukes (Machine Clears) not related to memory ordering.", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(tma_machine_clears * (1 - MACHINE_CLEARS.MEMORY_ORDERING / MACHINE_CLEARS.COUNT), 0.0001)", "MetricGroup": "BvIO;Machine_Clears;TopdownL3;tma_L3_group;tma_machine_clears_group", "MetricName": "tma_other_nukes", @@ -1818,6 +1847,7 @@ }, { "BriefDescription": "This metric estimates fraction of cycles the CPU performance was potentially limited due to Core computation issues (non divider-related)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "((tma_ports_utilized_0 * tma_info_thread_clks + (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL)) / tma_info_thread_clks if ARITH.DIVIDER_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY else (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL) / tma_info_thread_clks)", "MetricGroup": "PortsUtil;TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_ports_utilization", @@ -1923,7 +1953,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%" }, { @@ -1980,6 +2010,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 1 GB pages for data store accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_store_stlb_miss * DTLB_STORE_MISSES.WALK_COMPLETED_1G / (DTLB_STORE_MISSES.WALK_COMPLETED_4K + DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M + DTLB_STORE_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_store_stlb_miss_group", "MetricName": "tma_store_stlb_miss_1g", @@ -1988,6 +2019,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 2 or 4 MB pages for data store accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_store_stlb_miss * DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M / (DTLB_STORE_MISSES.WALK_COMPLETED_4K + DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M + DTLB_STORE_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_store_stlb_miss_group", "MetricName": "tma_store_stlb_miss_2m", @@ -1996,6 +2028,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles to walk the memory paging structures to cache translation of 4 KB pages for data store accesses.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "tma_store_stlb_miss * DTLB_STORE_MISSES.WALK_COMPLETED_4K / (DTLB_STORE_MISSES.WALK_COMPLETED_4K + DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M + DTLB_STORE_MISSES.WALK_COMPLETED_1G)", "MetricGroup": "MemoryTLB;TopdownL6;tma_L6_group;tma_store_stlb_miss_group", "MetricName": "tma_store_stlb_miss_4k", From 75a7b9d29215c5aa813b9620f3c56817918f9f8c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 18 Aug 2025 12:04:16 -0700 Subject: [PATCH 0865/2711] perf vendor events: Update tigerlake metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update metrics from TMA 5.0 to 5.1. Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Weilin Wang Cc: linux-actions@lists.infradead.org Link: https://lore.kernel.org/r/20250818190416.145274-21-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/tigerlake/tgl-metrics.json | 105 ++++++++++-------- 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/tigerlake/tgl-metrics.json b/tools/perf/pmu-events/arch/x86/tigerlake/tgl-metrics.json index 2db7a70f7a07..908da985c594 100644 --- a/tools/perf/pmu-events/arch/x86/tigerlake/tgl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/tigerlake/tgl-metrics.json @@ -1,63 +1,63 @@ [ { "BriefDescription": "C10 residency percent per package", - "MetricExpr": "cstate_pkg@c10\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c10\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C10_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C2 residency percent per package", - "MetricExpr": "cstate_pkg@c2\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c2\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C2_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C3 residency percent per package", - "MetricExpr": "cstate_pkg@c3\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c3\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C3_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per core", - "MetricExpr": "cstate_core@c6\\-residency@ / TSC", + "MetricExpr": "cstate_core@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C6 residency percent per package", - "MetricExpr": "cstate_pkg@c6\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c6\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per core", - "MetricExpr": "cstate_core@c7\\-residency@ / TSC", + "MetricExpr": "cstate_core@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Core_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C7 residency percent per package", - "MetricExpr": "cstate_pkg@c7\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c7\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C7_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C8 residency percent per package", - "MetricExpr": "cstate_pkg@c8\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c8\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C8_Pkg_Residency", "ScaleUnit": "100%" }, { "BriefDescription": "C9 residency percent per package", - "MetricExpr": "cstate_pkg@c9\\-residency@ / TSC", + "MetricExpr": "cstate_pkg@c9\\-residency@ / msr@tsc@", "MetricGroup": "Power", "MetricName": "C9_Pkg_Residency", "ScaleUnit": "100%" @@ -85,7 +85,6 @@ }, { "BriefDescription": "This metric estimates how often memory load accesses were aliased by preceding stores (in program order) with a 4K address offset", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_4k_aliasing", @@ -134,6 +133,7 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch related bottlenecks by large code footprint programs (i-side cache; TLB and BTB misses)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_fetch_latency * (tma_itlb_misses + tma_icache_misses + tma_unknown_branches) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)", "MetricGroup": "BigFootprint;BvBC;Fed;Frontend;IcMiss;MemoryTLB", "MetricName": "tma_bottleneck_big_code", @@ -147,40 +147,45 @@ "MetricThreshold": "tma_bottleneck_branching_overhead > 5", "PublicDescription": "Total pipeline cost of instructions used for program control-flow - a subset of the Retiring category in TMA. Examples include function calls; loops and alignments. (A lower bound)" }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", - "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", - "MetricName": "tma_bottleneck_cache_memory_bandwidth", - "MetricThreshold": "tma_bottleneck_cache_memory_bandwidth > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" - }, - { - "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", - "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", - "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", - "MetricName": "tma_bottleneck_cache_memory_latency", - "MetricThreshold": "tma_bottleneck_cache_memory_latency > 20", - "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" - }, { "BriefDescription": "Total pipeline cost when the execution is compute-bound - an estimation", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_core_bound * tma_divider / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_core_bound * (tma_ports_utilization / (tma_divider + tma_ports_utilization + tma_serializing_operation)) * (tma_ports_utilized_3m / (tma_ports_utilized_0 + tma_ports_utilized_1 + tma_ports_utilized_2 + tma_ports_utilized_3m)))", "MetricGroup": "BvCB;Cor;tma_issueComp", "MetricName": "tma_bottleneck_compute_bound_est", "MetricThreshold": "tma_bottleneck_compute_bound_est > 20", "PublicDescription": "Total pipeline cost when the execution is compute-bound - an estimation. Covers Core Bound when High ILP as well as when long-latency execution units are busy. Related metrics: " }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)))", + "MetricGroup": "BvMB;Mem;MemoryBW;Offcore;tma_issueBW", + "MetricName": "tma_bottleneck_data_cache_memory_bandwidth", + "MetricThreshold": "tma_bottleneck_data_cache_memory_bandwidth > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Bandwidth related bottlenecks. Related metrics: tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full" + }, + { + "BriefDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_memory_bound * tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_l1_latency_dependency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_lock_latency / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_loads / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_split_stores / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_store_latency / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", + "MetricGroup": "BvML;Mem;MemoryLat;Offcore;tma_issueLat", + "MetricName": "tma_bottleneck_data_cache_memory_latency", + "MetricThreshold": "tma_bottleneck_data_cache_memory_latency > 20", + "PublicDescription": "Total pipeline cost of external Memory- or Cache-Latency related bottlenecks. Related metrics: tma_l3_hit_latency, tma_mem_latency" + }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks (when the front-end could not sustain operations delivery to the back-end)", - "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms))) - tma_bottleneck_big_code", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_frontend_bound - (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms)) - tma_bottleneck_big_code", "MetricGroup": "BvFB;Fed;FetchBW;Frontend", "MetricName": "tma_bottleneck_instruction_fetch_bw", "MetricThreshold": "tma_bottleneck_instruction_fetch_bw > 20" }, { "BriefDescription": "Total pipeline cost of irregular execution (e.g", - "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_ms / (tma_dsb + tma_lsd + tma_mite + tma_ms)) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 * (tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * (tma_fetch_latency * (tma_ms_switches + tma_branch_resteers * (tma_clears_resteers + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_mispredicts_resteers) / (tma_clears_resteers + tma_mispredicts_resteers + tma_unknown_branches)) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_ms) + 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts * tma_branch_mispredicts + tma_machine_clears * tma_other_nukes / tma_other_nukes + tma_core_bound * (tma_serializing_operation + tma_core_bound * RS_EVENTS.EMPTY_CYCLES / tma_info_thread_clks * tma_ports_utilized_0) / (tma_divider + tma_ports_utilization + tma_serializing_operation) + tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "Bad;BvIO;Cor;Ret;tma_issueMS", "MetricName": "tma_bottleneck_irregular_overhead", "MetricThreshold": "tma_bottleneck_irregular_overhead > 10", @@ -188,6 +193,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_load / max(tma_l1_bound, tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_l1_latency_dependency + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_memory_bound * (tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound)) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "BvMT;Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_bottleneck_memory_data_tlbs", @@ -196,6 +202,7 @@ }, { "BriefDescription": "Total pipeline cost of Memory Synchronization related bottlenecks (data transfers and coherency updates across processors)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_memory_bound * (tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_contested_accesses + tma_data_sharing) / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * tma_false_sharing / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores - tma_store_latency)) + tma_machine_clears * (1 - tma_other_nukes / tma_other_nukes))", "MetricGroup": "BvMS;LockCont;Mem;Offcore;tma_issueSyncxn", "MetricName": "tma_bottleneck_memory_synchronization", @@ -204,6 +211,7 @@ }, { "BriefDescription": "Total pipeline cost of Branch Misprediction related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (1 - 10 * tma_microcode_sequencer * tma_other_mispredicts / tma_branch_mispredicts) * (tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Bad;BadSpec;BrMispredicts;BvMP;tma_issueBM", "MetricName": "tma_bottleneck_mispredictions", @@ -212,7 +220,8 @@ }, { "BriefDescription": "Total pipeline cost of remaining bottlenecks in the back-end", - "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_cache_memory_bandwidth + tma_bottleneck_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", + "MetricConstraint": "NO_GROUP_EVENTS", + "MetricExpr": "100 - (tma_bottleneck_big_code + tma_bottleneck_instruction_fetch_bw + tma_bottleneck_mispredictions + tma_bottleneck_data_cache_memory_bandwidth + tma_bottleneck_data_cache_memory_latency + tma_bottleneck_memory_data_tlbs + tma_bottleneck_memory_synchronization + tma_bottleneck_compute_bound_est + tma_bottleneck_irregular_overhead + tma_bottleneck_branching_overhead + tma_bottleneck_useful_work)", "MetricGroup": "BvOB;Cor;Offcore", "MetricName": "tma_bottleneck_other_bottlenecks", "MetricThreshold": "tma_bottleneck_other_bottlenecks > 20", @@ -220,6 +229,7 @@ }, { "BriefDescription": "Total pipeline cost of \"useful operations\" - the portion of Retiring category not covered by Branching_Overhead nor Irregular_Overhead.", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_retiring - (BR_INST_RETIRED.ALL_BRANCHES + 2 * BR_INST_RETIRED.NEAR_CALL + INST_RETIRED.NOP) / tma_info_thread_slots - tma_microcode_sequencer / (tma_few_uops_instructions + tma_microcode_sequencer) * (tma_assists / tma_microcode_sequencer) * tma_heavy_operations)", "MetricGroup": "BvUW;Ret", "MetricName": "tma_bottleneck_useful_work", @@ -427,7 +437,7 @@ "MetricGroup": "BvMB;MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", - "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", + "PublicDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed. The higher the metric value; the deeper the memory hierarchy level the misses are satisfied from (metric values >1 are valid). Often it hints on approaching bandwidth limits (to L2 cache; L3 cache or external memory). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_info_system_dram_bw_use, tma_mem_bandwidth, tma_sq_full, tma_store_latency, tma_streaming_stores", "ScaleUnit": "100%" }, { @@ -619,6 +629,7 @@ }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) hits - subset of the Instruction_Fetch_BW Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound * (tma_fetch_bandwidth / (tma_fetch_bandwidth + tma_fetch_latency)) * (tma_dsb / (tma_dsb + tma_lsd + tma_mite + tma_ms)))", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_botlnk_l2_dsb_bandwidth", @@ -1074,7 +1085,7 @@ "MetricName": "tma_info_memory_tlb_store_stlb_mpki" }, { - "BriefDescription": "", + "BriefDescription": "Mem;Backend;CacheHits", "MetricExpr": "UOPS_EXECUTED.THREAD / (UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2 if #SMT_on else cpu@UOPS_EXECUTED.THREAD\\,cmask\\=1@)", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute" @@ -1097,6 +1108,12 @@ "MetricGroup": "Fed;FetchBW", "MetricName": "tma_info_pipeline_fetch_mite" }, + { + "BriefDescription": "Average number of uops fetched from MS per cycle", + "MetricExpr": "IDQ.MS_UOPS / cpu@IDQ.MS_UOPS\\,cmask\\=1@", + "MetricGroup": "Fed;FetchLat;MicroSeq", + "MetricName": "tma_info_pipeline_fetch_ms" + }, { "BriefDescription": "Instructions per a microcode Assist invocation", "MetricExpr": "INST_RETIRED.ANY / ASSISTS.ANY", @@ -1113,7 +1130,7 @@ }, { "BriefDescription": "Measured Average Core Frequency for unhalted processors [GHz]", - "MetricExpr": "tma_info_system_turbo_utilization * TSC / 1e9 / tma_info_system_time", + "MetricExpr": "tma_info_system_turbo_utilization * msr@tsc@ / 1e9 / tma_info_system_time", "MetricGroup": "Power;Summary", "MetricName": "tma_info_system_core_frequency" }, @@ -1125,7 +1142,7 @@ }, { "BriefDescription": "Average number of utilized CPUs", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@", "MetricGroup": "Summary", "MetricName": "tma_info_system_cpus_utilized" }, @@ -1134,7 +1151,7 @@ "MetricExpr": "64 * (UNC_ARB_TRK_REQUESTS.ALL + UNC_ARB_COH_TRK_REQUESTS.ALL) / 1e6 / tma_info_system_time / 1e3", "MetricGroup": "HPC;MemOffcore;MemoryBW;SoC;tma_issueBW", "MetricName": "tma_info_system_dram_bw_use", - "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" + "PublicDescription": "Average external Memory Bandwidth Use for reads and writes [GB / sec]. Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_mem_bandwidth, tma_sq_full" }, { "BriefDescription": "Giga Floating Point Operations Per Second", @@ -1165,6 +1182,7 @@ }, { "BriefDescription": "Average number of parallel data read requests to external memory", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "UNC_ARB_DAT_OCCUPANCY.RD / UNC_ARB_DAT_OCCUPANCY.RD@cmask\\=1@", "MetricGroup": "Mem;MemoryBW;SoC", "MetricName": "tma_info_system_mem_parallel_reads", @@ -1316,12 +1334,12 @@ "ScaleUnit": "100%" }, { - "BriefDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", + "BriefDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache", "MetricExpr": "min(2 * (MEM_INST_RETIRED.ALL_LOADS - MEM_LOAD_RETIRED.FB_HIT - MEM_LOAD_RETIRED.L1_MISS) * 20 / 100, max(CYCLE_ACTIVITY.CYCLES_MEM_ANY - CYCLE_ACTIVITY.CYCLES_L1D_MISS, 0)) / tma_info_thread_clks", "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_l1_latency_dependency", "MetricThreshold": "tma_l1_latency_dependency > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "This metric ([SKL+] roughly; [LNL]) estimates fraction of cycles with demand load accesses that hit the L1D cache. The short latency of the L1D cache may be exposed in pointer-chasing memory access patterns as an example. Sample with: MEM_LOAD_RETIRED.L1_HIT", "ScaleUnit": "100%" }, { @@ -1345,7 +1363,6 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(CYCLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS) / tma_info_thread_clks", "MetricGroup": "CacheHits;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -1359,7 +1376,7 @@ "MetricGroup": "BvML;MemoryLat;TopdownL4;tma_L4_group;tma_issueLat;tma_l3_bound_group", "MetricName": "tma_l3_hit_latency", "MetricThreshold": "tma_l3_hit_latency > 0.1 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_cache_memory_latency, tma_mem_latency", + "PublicDescription": "This metric estimates fraction of cycles with demand load accesses that hit the L3 cache under unloaded scenarios (possibly L3 latency limited). Avoiding private cache misses (i.e. L2 misses/L3 hits) will improve the latency; reduce contention with sibling physical cores and increase performance. Note the value of this node may overlap with its siblings. Sample with: MEM_LOAD_RETIRED.L3_HIT_PS. Related metrics: tma_bottleneck_data_cache_memory_latency, tma_mem_latency", "ScaleUnit": "100%" }, { @@ -1465,7 +1482,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueBW", "MetricName": "tma_mem_bandwidth", "MetricThreshold": "tma_mem_bandwidth > 0.2 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", + "PublicDescription": "This metric estimates fraction of cycles where the core's performance was likely hurt due to approaching bandwidth limits of external memory - DRAM ([SPR-HBM] and/or HBM). The underlying heuristic assumes that a similar off-core traffic is generated by all IA cores. This metric does not aggregate non-data-read requests by this logical processor; requests from other IA Logical Processors/Physical Cores/sockets; or other non-IA devices like GPU; hence the maximum external memory bandwidth limits may or may not be approached when this metric is flagged (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_sq_full", "ScaleUnit": "100%" }, { @@ -1474,7 +1491,7 @@ "MetricGroup": "BvML;MemoryLat;Offcore;TopdownL4;tma_L4_group;tma_dram_bound_group;tma_issueLat", "MetricName": "tma_mem_latency", "MetricThreshold": "tma_mem_latency > 0.1 & (tma_dram_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_cache_memory_latency, tma_l3_hit_latency", + "PublicDescription": "This metric estimates fraction of cycles where the performance was likely hurt due to latency from external memory - DRAM ([SPR-HBM] and/or HBM). This metric does not aggregate requests from other Logical Processors/Physical Cores/sockets (see Uncore counters for that). Related metrics: tma_bottleneck_data_cache_memory_latency, tma_l3_hit_latency", "ScaleUnit": "100%" }, { @@ -1542,7 +1559,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles in which CPU was likely limited due to the Microcode Sequencer (MS) unit - see Microcode_Sequencer node for details.", - "MetricExpr": "cpu@IDQ.MS_UOPS\\,cmask\\=1@ / tma_info_core_core_clks / 2", + "MetricExpr": "cpu@IDQ.MS_UOPS\\,cmask\\=1@ / tma_info_core_core_clks / 3.3", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_ms", "MetricThreshold": "tma_ms > 0.05 & tma_fetch_bandwidth > 0.2", @@ -1676,7 +1693,7 @@ { "BriefDescription": "This category represents fraction of slots utilized by useful work i.e. issued uops that eventually get retired", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 0 * tma_info_thread_slots", + "MetricExpr": "topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)", "MetricGroup": "BvUW;Default;TmaL1;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.7 | tma_heavy_operations > 0.1", @@ -1713,7 +1730,6 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -1727,7 +1743,7 @@ "MetricGroup": "BvMB;MemoryBW;Offcore;TopdownL4;tma_L4_group;tma_issueBW;tma_l3_bound_group", "MetricName": "tma_sq_full", "MetricThreshold": "tma_sq_full > 0.3 & (tma_l3_bound > 0.05 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", - "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", + "PublicDescription": "This metric measures fraction of cycles where the Super Queue (SQ) was full taking into account all request-types and both hardware SMT threads (Logical Processors). Related metrics: tma_bottleneck_data_cache_memory_bandwidth, tma_fb_full, tma_info_system_dram_bw_use, tma_mem_bandwidth", "ScaleUnit": "100%" }, { @@ -1741,7 +1757,6 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * LD_BLOCKS.STORE_FORWARD / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", From 376358bb9770e5313d22d8784511497096cdb75f Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Tue, 19 Aug 2025 10:00:13 +0800 Subject: [PATCH 0866/2711] bus: mhi: host: pci_generic: Add support for all Foxconn T99W696 SKU variants Since there are too many variants available for Foxconn T99W696 modem, and they all share the same configuration, use PCI_ANY_ID as the subsystem device ID to match each possible SKUs and support all of them. Signed-off-by: Slark Xiao [mani: reworded subject/description and dropped the fixes tag] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250819020013.122162-1-slark_xiao@163.com --- drivers/bus/mhi/host/pci_generic.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 4edb5bb476ba..4564e2528775 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -917,20 +917,8 @@ static const struct pci_device_id mhi_pci_id_table[] = { /* Telit FE990A */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x1c5d, 0x2015), .driver_data = (kernel_ulong_t) &mhi_telit_fe990a_info }, - /* Foxconn T99W696.01, Lenovo Generic SKU */ - { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe142), - .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info }, - /* Foxconn T99W696.02, Lenovo X1 Carbon SKU */ - { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe143), - .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info }, - /* Foxconn T99W696.03, Lenovo X1 2in1 SKU */ - { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe144), - .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info }, - /* Foxconn T99W696.04, Lenovo PRC SKU */ - { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe145), - .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info }, - /* Foxconn T99W696.00, Foxconn SKU */ - { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe146), + /* Foxconn T99W696, all variants */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, PCI_ANY_ID), .driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info }, { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308), .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, From 744b02f62634b64345d05a8a3f145d56469313b4 Mon Sep 17 00:00:00 2001 From: Kai Huang Date: Mon, 1 Sep 2025 18:09:24 +0200 Subject: [PATCH 0867/2711] x86/kexec: Consolidate relocate_kernel() function parameters During kexec, the kernel jumps to the new kernel in relocate_kernel(), which is implemented in assembly and both 32-bit and 64-bit have their own version. Currently, for both 32-bit and 64-bit, the last two parameters of the relocate_kernel() are both 'unsigned int' but actually they only convey a boolean, i.e., one bit information. The 'unsigned int' has enough space to carry two bits information therefore there's no need to pass the two booleans in two separate 'unsigned int'. Consolidate the last two function parameters of relocate_kernel() into a single 'unsigned int' and pass flags instead. Only consolidate the 64-bit version albeit the similar optimization can be done for the 32-bit version too. Don't bother changing the 32-bit version while it is working (since assembly code change is required). Signed-off-by: Kai Huang Signed-off-by: Paolo Bonzini Signed-off-by: Dave Hansen Reviewed-by: Tom Lendacky Reviewed-by: Borislav Petkov (AMD) Reviewed-by: David Woodhouse Link: https://lore.kernel.org/all/20250901160930.1785244-2-pbonzini%40redhat.com --- arch/x86/include/asm/kexec.h | 12 ++++++++++-- arch/x86/kernel/machine_kexec_64.c | 22 +++++++++++++--------- arch/x86/kernel/relocate_kernel_64.S | 25 +++++++++++++++---------- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h index f2ad77929d6e..12cebbcdb6c8 100644 --- a/arch/x86/include/asm/kexec.h +++ b/arch/x86/include/asm/kexec.h @@ -13,6 +13,15 @@ # define KEXEC_DEBUG_EXC_HANDLER_SIZE 6 /* PUSHI, PUSHI, 2-byte JMP */ #endif +#ifdef CONFIG_X86_64 + +#include + +#define RELOC_KERNEL_PRESERVE_CONTEXT BIT(0) +#define RELOC_KERNEL_HOST_MEM_ENC_ACTIVE BIT(1) + +#endif + # define KEXEC_CONTROL_PAGE_SIZE 4096 # define KEXEC_CONTROL_CODE_MAX_SIZE 2048 @@ -121,8 +130,7 @@ typedef unsigned long relocate_kernel_fn(unsigned long indirection_page, unsigned long pa_control_page, unsigned long start_address, - unsigned int preserve_context, - unsigned int host_mem_enc_active); + unsigned int flags); #endif extern relocate_kernel_fn relocate_kernel; #define ARCH_HAS_KIMAGE_ARCH diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 697fb99406e6..5cda8d8d8b13 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -384,16 +384,10 @@ void __nocfi machine_kexec(struct kimage *image) { unsigned long reloc_start = (unsigned long)__relocate_kernel_start; relocate_kernel_fn *relocate_kernel_ptr; - unsigned int host_mem_enc_active; + unsigned int relocate_kernel_flags; int save_ftrace_enabled; void *control_page; - /* - * This must be done before load_segments() since if call depth tracking - * is used then GS must be valid to make any function calls. - */ - host_mem_enc_active = cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT); - #ifdef CONFIG_KEXEC_JUMP if (image->preserve_context) save_processor_state(); @@ -427,6 +421,17 @@ void __nocfi machine_kexec(struct kimage *image) */ relocate_kernel_ptr = control_page + (unsigned long)relocate_kernel - reloc_start; + relocate_kernel_flags = 0; + if (image->preserve_context) + relocate_kernel_flags |= RELOC_KERNEL_PRESERVE_CONTEXT; + + /* + * This must be done before load_segments() since if call depth tracking + * is used then GS must be valid to make any function calls. + */ + if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) + relocate_kernel_flags |= RELOC_KERNEL_HOST_MEM_ENC_ACTIVE; + /* * The segment registers are funny things, they have both a * visible and an invisible part. Whenever the visible part is @@ -443,8 +448,7 @@ void __nocfi machine_kexec(struct kimage *image) image->start = relocate_kernel_ptr((unsigned long)image->head, virt_to_phys(control_page), image->start, - image->preserve_context, - host_mem_enc_active); + relocate_kernel_flags); #ifdef CONFIG_KEXEC_JUMP if (image->preserve_context) diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S index ea604f4d0b52..26e945f85d19 100644 --- a/arch/x86/kernel/relocate_kernel_64.S +++ b/arch/x86/kernel/relocate_kernel_64.S @@ -66,8 +66,7 @@ SYM_CODE_START_NOALIGN(relocate_kernel) * %rdi indirection_page * %rsi pa_control_page * %rdx start address - * %rcx preserve_context - * %r8 host_mem_enc_active + * %rcx flags: RELOC_KERNEL_* */ /* Save the CPU context, used for jumping back */ @@ -111,7 +110,7 @@ SYM_CODE_START_NOALIGN(relocate_kernel) /* save indirection list for jumping back */ movq %rdi, pa_backup_pages_map(%rip) - /* Save the preserve_context to %r11 as swap_pages clobbers %rcx. */ + /* Save the flags to %r11 as swap_pages clobbers %rcx. */ movq %rcx, %r11 /* setup a new stack at the end of the physical control page */ @@ -129,9 +128,8 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) /* * %rdi indirection page * %rdx start address - * %r8 host_mem_enc_active * %r9 page table page - * %r11 preserve_context + * %r11 flags: RELOC_KERNEL_* * %r13 original CR4 when relocate_kernel() was invoked */ @@ -204,7 +202,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) * entries that will conflict with the now unencrypted memory * used by kexec. Flush the caches before copying the kernel. */ - testq %r8, %r8 + testb $RELOC_KERNEL_HOST_MEM_ENC_ACTIVE, %r11b jz .Lsme_off wbinvd .Lsme_off: @@ -220,7 +218,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) movq %cr3, %rax movq %rax, %cr3 - testq %r11, %r11 /* preserve_context */ + testb $RELOC_KERNEL_PRESERVE_CONTEXT, %r11b jnz .Lrelocate /* @@ -273,7 +271,13 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) ANNOTATE_NOENDBR andq $PAGE_MASK, %r8 lea PAGE_SIZE(%r8), %rsp - movl $1, %r11d /* Ensure preserve_context flag is set */ + /* + * Ensure RELOC_KERNEL_PRESERVE_CONTEXT flag is set so that + * swap_pages() can swap pages correctly. Note all other + * RELOC_KERNEL_* flags passed to relocate_kernel() are not + * restored. + */ + movl $RELOC_KERNEL_PRESERVE_CONTEXT, %r11d call swap_pages movq kexec_va_control_page(%rip), %rax 0: addq $virtual_mapped - 0b, %rax @@ -321,7 +325,7 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages) UNWIND_HINT_END_OF_STACK /* * %rdi indirection page - * %r11 preserve_context + * %r11 flags: RELOC_KERNEL_* */ movq %rdi, %rcx /* Put the indirection_page in %rcx */ xorl %edi, %edi @@ -357,7 +361,8 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages) movq %rdi, %rdx /* Save destination page to %rdx */ movq %rsi, %rax /* Save source page to %rax */ - testq %r11, %r11 /* Only actually swap for ::preserve_context */ + /* Only actually swap for ::preserve_context */ + testb $RELOC_KERNEL_PRESERVE_CONTEXT, %r11b jz .Lnoswap /* copy source page to swap page */ From 83214a775f33bc9d61c2c284f2ace3f854a4cddb Mon Sep 17 00:00:00 2001 From: Kai Huang Date: Mon, 1 Sep 2025 18:09:25 +0200 Subject: [PATCH 0868/2711] x86/sme: Use percpu boolean to control WBINVD during kexec TL;DR: Prepare to unify how TDX and SME do cache flushing during kexec by making a percpu boolean control whether to do the WBINVD. -- Background -- On SME platforms, dirty cacheline aliases with and without encryption bit can coexist, and the CPU can flush them back to memory in random order. During kexec, the caches must be flushed before jumping to the new kernel otherwise the dirty cachelines could silently corrupt the memory used by the new kernel due to different encryption property. TDX also needs a cache flush during kexec for the same reason. It would be good to have a generic way to flush the cache instead of scattering checks for each feature all around. When SME is enabled, the kernel basically encrypts all memory including the kernel itself and a simple memory write from the kernel could dirty cachelines. Currently, the kernel uses WBINVD to flush the cache for SME during kexec in two places: 1) the one in stop_this_cpu() for all remote CPUs when the kexec-ing CPU stops them; 2) the one in the relocate_kernel() where the kexec-ing CPU jumps to the new kernel. -- Solution -- Unlike SME, TDX can only dirty cachelines when it is used (i.e., when SEAMCALLs are performed). Since there are no more SEAMCALLs after the aforementioned WBINVDs, leverage this for TDX. To unify the approach for SME and TDX, use a percpu boolean to indicate the cache may be in an incoherent state and needs flushing during kexec, and set the boolean for SME. TDX can then leverage it. While SME could use a global flag (since it's enabled at early boot and enabled on all CPUs), the percpu flag fits TDX better: The percpu flag can be set when a CPU makes a SEAMCALL, and cleared when another WBINVD on the CPU obviates the need for a kexec-time WBINVD. Saving kexec-time WBINVD is valuable, because there is an existing race[*] where kexec could proceed while another CPU is active. WBINVD could make this race worse, so it's worth skipping it when possible. -- Side effect to SME -- Today the first WBINVD in the stop_this_cpu() is performed when SME is *supported* by the platform, and the second WBINVD is done in relocate_kernel() when SME is *activated* by the kernel. Make things simple by changing to do the second WBINVD when the platform supports SME. This allows the kernel to simply turn on this percpu boolean when bringing up a CPU by checking whether the platform supports SME. No other functional change intended. [*] The aforementioned race: During kexec native_stop_other_cpus() is called to stop all remote CPUs before jumping to the new kernel. native_stop_other_cpus() firstly sends normal REBOOT vector IPIs to stop remote CPUs and waits them to stop. If that times out, it sends NMI to stop the CPUs that are still alive. The race happens when native_stop_other_cpus() has to send NMIs and could potentially result in the system hang (for more information please see [1]). Signed-off-by: Kai Huang Signed-off-by: Paolo Bonzini Signed-off-by: Dave Hansen Reviewed-by: Tom Lendacky Reviewed-by: Borislav Petkov (AMD) Tested-by: Tom Lendacky Link: https://lore.kernel.org/kvm/b963fcd60abe26c7ec5dc20b42f1a2ebbcc72397.1750934177.git.kai.huang@intel.com/ [1] Link: https://lore.kernel.org/all/20250901160930.1785244-3-pbonzini%40redhat.com --- arch/x86/include/asm/kexec.h | 4 ++-- arch/x86/include/asm/processor.h | 2 ++ arch/x86/kernel/cpu/amd.c | 17 +++++++++++++++++ arch/x86/kernel/machine_kexec_64.c | 14 ++++++++++---- arch/x86/kernel/process.c | 24 +++++++++++------------- arch/x86/kernel/relocate_kernel_64.S | 13 ++++++++++--- 6 files changed, 52 insertions(+), 22 deletions(-) diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h index 12cebbcdb6c8..5cfb27f26583 100644 --- a/arch/x86/include/asm/kexec.h +++ b/arch/x86/include/asm/kexec.h @@ -17,8 +17,8 @@ #include -#define RELOC_KERNEL_PRESERVE_CONTEXT BIT(0) -#define RELOC_KERNEL_HOST_MEM_ENC_ACTIVE BIT(1) +#define RELOC_KERNEL_PRESERVE_CONTEXT BIT(0) +#define RELOC_KERNEL_CACHE_INCOHERENT BIT(1) #endif diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index bde58f6510ac..a24c7805acdb 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -731,6 +731,8 @@ void __noreturn stop_this_cpu(void *dummy); void microcode_check(struct cpuinfo_x86 *prev_info); void store_cpu_caps(struct cpuinfo_x86 *info); +DECLARE_PER_CPU(bool, cache_state_incoherent); + enum l1tf_mitigations { L1TF_MITIGATION_OFF, L1TF_MITIGATION_AUTO, diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index a5ece6ebe8a7..66a682be4a1a 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -545,6 +545,23 @@ static void early_detect_mem_encrypt(struct cpuinfo_x86 *c) { u64 msr; + /* + * Mark using WBINVD is needed during kexec on processors that + * support SME. This provides support for performing a successful + * kexec when going from SME inactive to SME active (or vice-versa). + * + * The cache must be cleared so that if there are entries with the + * same physical address, both with and without the encryption bit, + * they don't race each other when flushed and potentially end up + * with the wrong entry being committed to memory. + * + * Test the CPUID bit directly because with mem_encrypt=off the + * BSP will clear the X86_FEATURE_SME bit and the APs will not + * see it set after that. + */ + if (c->extended_cpuid_level >= 0x8000001f && (cpuid_eax(0x8000001f) & BIT(0))) + __this_cpu_write(cache_state_incoherent, true); + /* * BIOS support is required for SME and SEV. * For SME: If BIOS has enabled SME then adjust x86_phys_bits by diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 5cda8d8d8b13..dfb91091f451 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef CONFIG_ACPI /* @@ -426,11 +427,11 @@ void __nocfi machine_kexec(struct kimage *image) relocate_kernel_flags |= RELOC_KERNEL_PRESERVE_CONTEXT; /* - * This must be done before load_segments() since if call depth tracking - * is used then GS must be valid to make any function calls. + * This must be done before load_segments() since it resets + * GS to 0 and percpu data needs the correct GS to work. */ - if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) - relocate_kernel_flags |= RELOC_KERNEL_HOST_MEM_ENC_ACTIVE; + if (this_cpu_read(cache_state_incoherent)) + relocate_kernel_flags |= RELOC_KERNEL_CACHE_INCOHERENT; /* * The segment registers are funny things, they have both a @@ -441,6 +442,11 @@ void __nocfi machine_kexec(struct kimage *image) * * Take advantage of this here by force loading the segments, * before the GDT is zapped with an invalid value. + * + * load_segments() resets GS to 0. Don't make any function call + * after here since call depth tracking uses percpu variables to + * operate (relocate_kernel() is explicitly ignored by call depth + * tracking). */ load_segments(); diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 1b7960cf6eb0..f2bbbeef5477 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -88,6 +88,16 @@ EXPORT_PER_CPU_SYMBOL(cpu_tss_rw); DEFINE_PER_CPU(bool, __tss_limit_invalid); EXPORT_PER_CPU_SYMBOL_GPL(__tss_limit_invalid); +/* + * The cache may be in an incoherent state and needs flushing during kexec. + * E.g., on SME/TDX platforms, dirty cacheline aliases with and without + * encryption bit(s) can coexist and the cache needs to be flushed before + * booting to the new kernel to avoid the silent memory corruption due to + * dirty cachelines with different encryption property being written back + * to the memory. + */ +DEFINE_PER_CPU(bool, cache_state_incoherent); + /* * this gets called so that we can store lazy state into memory and copy the * current task into the new thread. @@ -827,19 +837,7 @@ void __noreturn stop_this_cpu(void *dummy) disable_local_APIC(); mcheck_cpu_clear(c); - /* - * Use wbinvd on processors that support SME. This provides support - * for performing a successful kexec when going from SME inactive - * to SME active (or vice-versa). The cache must be cleared so that - * if there are entries with the same physical address, both with and - * without the encryption bit, they don't race each other when flushed - * and potentially end up with the wrong entry being committed to - * memory. - * - * Test the CPUID bit directly because the machine might've cleared - * X86_FEATURE_SME due to cmdline options. - */ - if (c->extended_cpuid_level >= 0x8000001f && (cpuid_eax(0x8000001f) & BIT(0))) + if (this_cpu_read(cache_state_incoherent)) wbinvd(); /* diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S index 26e945f85d19..11e20bb13aca 100644 --- a/arch/x86/kernel/relocate_kernel_64.S +++ b/arch/x86/kernel/relocate_kernel_64.S @@ -198,14 +198,21 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) movq %r9, %cr3 /* + * If the memory cache is in incoherent state, e.g., due to + * memory encryption, do WBINVD to flush cache. + * * If SME is active, there could be old encrypted cache line * entries that will conflict with the now unencrypted memory * used by kexec. Flush the caches before copying the kernel. + * + * Note SME sets this flag to true when the platform supports + * SME, so the WBINVD is performed even SME is not activated + * by the kernel. But this has no harm. */ - testb $RELOC_KERNEL_HOST_MEM_ENC_ACTIVE, %r11b - jz .Lsme_off + testb $RELOC_KERNEL_CACHE_INCOHERENT, %r11b + jz .Lnowbinvd wbinvd -.Lsme_off: +.Lnowbinvd: call swap_pages From 10df8607bf1a22249d21859f56eeb61e9a033313 Mon Sep 17 00:00:00 2001 From: Kai Huang Date: Mon, 1 Sep 2025 18:09:26 +0200 Subject: [PATCH 0869/2711] x86/virt/tdx: Mark memory cache state incoherent when making SEAMCALL On TDX platforms, dirty cacheline aliases with and without encryption bits can coexist, and the cpu can flush them back to memory in random order. During kexec, the caches must be flushed before jumping to the new kernel otherwise the dirty cachelines could silently corrupt the memory used by the new kernel due to different encryption property. A percpu boolean is used to mark whether the cache of a given CPU may be in an incoherent state, and the kexec performs WBINVD on the CPUs with that boolean turned on. For TDX, only the TDX module or the TDX guests can generate dirty cachelines of TDX private memory, i.e., they are only generated when the kernel does a SEAMCALL. Set that boolean when the kernel does SEAMCALL so that kexec can flush the cache correctly. The kernel provides both the __seamcall*() assembly functions and the seamcall*() wrapper ones which additionally handle running out of entropy error in a loop. Most of the SEAMCALLs are called using the seamcall*(), except TDH.VP.ENTER and TDH.PHYMEM.PAGE.RDMD which are called using __seamcall*() variant directly. To cover the two special cases, add a new __seamcall_dirty_cache() helper which only sets the percpu boolean and calls the __seamcall*(), and change the special cases to use the new helper. To cover all other SEAMCALLs, change seamcall*() to call the new helper. For the SEAMCALLs invoked via seamcall*(), they can be made from both task context and IRQ disabled context. Given SEAMCALL is just a lengthy instruction (e.g., thousands of cycles) from kernel's point of view and preempt_{disable|enable}() is cheap compared to it, just unconditionally disable preemption during setting the boolean and making SEAMCALL. Signed-off-by: Kai Huang Signed-off-by: Paolo Bonzini Signed-off-by: Dave Hansen Reviewed-by: Chao Gao Reviewed-by: Rick Edgecombe Tested-by: Farrah Chen Link: https://lore.kernel.org/all/20250901160930.1785244-4-pbonzini%40redhat.com --- arch/x86/include/asm/tdx.h | 25 ++++++++++++++++++++++++- arch/x86/virt/vmx/tdx/tdx.c | 4 ++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 57b46f05ff97..c178360c1fb1 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -102,10 +102,31 @@ u64 __seamcall_ret(u64 fn, struct tdx_module_args *args); u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args); void tdx_init(void); +#include #include +#include typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args); +static __always_inline u64 __seamcall_dirty_cache(sc_func_t func, u64 fn, + struct tdx_module_args *args) +{ + lockdep_assert_preemption_disabled(); + + /* + * SEAMCALLs are made to the TDX module and can generate dirty + * cachelines of TDX private memory. Mark cache state incoherent + * so that the cache can be flushed during kexec. + * + * This needs to be done before actually making the SEAMCALL, + * because kexec-ing CPU could send NMI to stop remote CPUs, + * in which case even disabling IRQ won't help here. + */ + this_cpu_write(cache_state_incoherent, true); + + return func(fn, args); +} + static __always_inline u64 sc_retry(sc_func_t func, u64 fn, struct tdx_module_args *args) { @@ -113,7 +134,9 @@ static __always_inline u64 sc_retry(sc_func_t func, u64 fn, u64 ret; do { - ret = func(fn, args); + preempt_disable(); + ret = __seamcall_dirty_cache(func, fn, args); + preempt_enable(); } while (ret == TDX_RND_NO_ENTROPY && --retry); return ret; diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 823850399bb7..2abf53ed59c8 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -1268,7 +1268,7 @@ static bool paddr_is_tdx_private(unsigned long phys) return false; /* Get page type from the TDX module */ - sret = __seamcall_ret(TDH_PHYMEM_PAGE_RDMD, &args); + sret = __seamcall_dirty_cache(__seamcall_ret, TDH_PHYMEM_PAGE_RDMD, &args); /* * The SEAMCALL will not return success unless there is a @@ -1524,7 +1524,7 @@ noinstr __flatten u64 tdh_vp_enter(struct tdx_vp *td, struct tdx_module_args *ar { args->rcx = tdx_tdvpr_pa(td); - return __seamcall_saved_ret(TDH_VP_ENTER, args); + return __seamcall_dirty_cache(__seamcall_saved_ret, TDH_VP_ENTER, args); } EXPORT_SYMBOL_GPL(tdh_vp_enter); From b18651f70ce0e45d52b9e66d9065b831b3f30784 Mon Sep 17 00:00:00 2001 From: Kai Huang Date: Mon, 1 Sep 2025 18:09:27 +0200 Subject: [PATCH 0870/2711] x86/kexec: Disable kexec/kdump on platforms with TDX partial write erratum Some early TDX-capable platforms have an erratum: A kernel partial write (a write transaction of less than cacheline lands at memory controller) to TDX private memory poisons that memory, and a subsequent read triggers a machine check. On those platforms, the old kernel must reset TDX private memory before jumping to the new kernel, otherwise the new kernel may see unexpected machine check. Currently the kernel doesn't track which page is a TDX private page. For simplicity just fail kexec/kdump for those platforms. Leverage the existing machine_kexec_prepare() to fail kexec/kdump by adding the check of the presence of the TDX erratum (which is only checked for if the kernel is built with TDX host support). This rejects kexec/kdump when the kernel is loading the kexec/kdump kernel image. The alternative is to reject kexec/kdump when the kernel is jumping to the new kernel. But for kexec this requires adding a new check (e.g., arch_kexec_allowed()) in the common code to fail kernel_kexec() at early stage. Kdump (crash_kexec()) needs similar check, but it's hard to justify because crash_kexec() is not supposed to abort. It's feasible to further relax this limitation, i.e., only fail kexec when TDX is actually enabled by the kernel. But this is still a half measure compared to resetting TDX private memory so just do the simplest thing for now. The impact to userspace is the users will get an error when loading the kexec/kdump kernel image: kexec_load failed: Operation not supported This might be confusing to the users, thus also print the reason in the dmesg: [..] kexec: Not allowed on platform with tdx_pw_mce bug. Signed-off-by: Kai Huang Signed-off-by: Paolo Bonzini Signed-off-by: Dave Hansen Reviewed-by: Rick Edgecombe Reviewed-by: Binbin Wu Tested-by: Farrah Chen Link: https://lore.kernel.org/all/20250901160930.1785244-5-pbonzini%40redhat.com --- arch/x86/kernel/machine_kexec_64.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index dfb91091f451..15088d14904f 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -347,6 +347,22 @@ int machine_kexec_prepare(struct kimage *image) unsigned long reloc_end = (unsigned long)__relocate_kernel_end; int result; + /* + * Some early TDX-capable platforms have an erratum. A kernel + * partial write (a write transaction of less than cacheline + * lands at memory controller) to TDX private memory poisons that + * memory, and a subsequent read triggers a machine check. + * + * On those platforms the old kernel must reset TDX private + * memory before jumping to the new kernel otherwise the new + * kernel may see unexpected machine check. For simplicity + * just fail kexec/kdump on those platforms. + */ + if (boot_cpu_has_bug(X86_BUG_TDX_PW_MCE)) { + pr_info_once("Not allowed on platform with tdx_pw_mce bug\n"); + return -EOPNOTSUPP; + } + /* Setup the identity mapped 64bit page table */ result = init_pgtable(image, __pa(control_page)); if (result) From 80804847269eba880dc8c1bc64d70082692f72cd Mon Sep 17 00:00:00 2001 From: Kai Huang Date: Mon, 1 Sep 2025 18:09:28 +0200 Subject: [PATCH 0871/2711] x86/virt/tdx: Remove the !KEXEC_CORE dependency During kexec it is now guaranteed that all dirty cachelines of TDX private memory are flushed before jumping to the new kernel. The TDX private memory from the old kernel will remain as TDX private memory in the new kernel, but it is OK because kernel read/write to TDX private memory will never cause machine check, except on the platforms with the TDX partial write erratum, which has already been handled. It is safe to allow kexec to work together with TDX now. Remove the !KEXEC_CORE dependency. Signed-off-by: Kai Huang Signed-off-by: Paolo Bonzini Signed-off-by: Dave Hansen Reviewed-by: Rick Edgecombe Tested-by: Farrah Chen Link: https://lore.kernel.org/all/20250901160930.1785244-6-pbonzini%40redhat.com --- arch/x86/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 58d890fe2100..e2cbfb021bc6 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1896,7 +1896,6 @@ config INTEL_TDX_HOST depends on X86_X2APIC select ARCH_KEEP_MEMBLOCK depends on CONTIG_ALLOC - depends on !KEXEC_CORE depends on X86_MCE help Intel Trust Domain Extensions (TDX) protects guest VMs from malicious From 5f9b5bd0c82925e4a71c5790a37b3142fec946d4 Mon Sep 17 00:00:00 2001 From: Kai Huang Date: Mon, 1 Sep 2025 18:09:29 +0200 Subject: [PATCH 0872/2711] x86/virt/tdx: Update the kexec section in the TDX documentation TDX host kernel now supports kexec/kdump. Update the documentation to reflect that. Opportunistically, remove the parentheses in "Kexec()" and move this section under the "Erratum" section because the updated "Kexec" section now refers to that erratum. Signed-off-by: Kai Huang Signed-off-by: Paolo Bonzini Signed-off-by: Dave Hansen Reviewed-by: Rick Edgecombe Tested-by: Farrah Chen Link: https://lore.kernel.org/all/20250901160930.1785244-7-pbonzini%40redhat.com --- Documentation/arch/x86/tdx.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/arch/x86/tdx.rst b/Documentation/arch/x86/tdx.rst index 719043cd8b46..61670e7df2f7 100644 --- a/Documentation/arch/x86/tdx.rst +++ b/Documentation/arch/x86/tdx.rst @@ -142,13 +142,6 @@ but depends on the BIOS to behave correctly. Note TDX works with CPU logical online/offline, thus the kernel still allows to offline logical CPU and online it again. -Kexec() -~~~~~~~ - -TDX host support currently lacks the ability to handle kexec. For -simplicity only one of them can be enabled in the Kconfig. This will be -fixed in the future. - Erratum ~~~~~~~ @@ -171,6 +164,13 @@ If the platform has such erratum, the kernel prints additional message in machine check handler to tell user the machine check may be caused by kernel bug on TDX private memory. +Kexec +~~~~~~~ + +Currently kexec doesn't work on the TDX platforms with the aforementioned +erratum. It fails when loading the kexec kernel image. Otherwise it +works normally. + Interaction vs S3 and deeper states ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 61221d07e815008ba758995d79fd442b5217f51a Mon Sep 17 00:00:00 2001 From: Kai Huang Date: Mon, 1 Sep 2025 18:09:30 +0200 Subject: [PATCH 0873/2711] KVM/TDX: Explicitly do WBINVD when no more TDX SEAMCALLs On TDX platforms, during kexec, the kernel needs to make sure there are no dirty cachelines of TDX private memory before booting to the new kernel to avoid silent memory corruption to the new kernel. To do this, the kernel has a percpu boolean to indicate whether the cache of a CPU may be in incoherent state. During kexec, namely in stop_this_cpu(), the kernel does WBINVD if that percpu boolean is true. TDX turns on that percpu boolean on a CPU when the kernel does SEAMCALL, Thus making sure the cache will be flushed during kexec. However, kexec has a race condition that, while remaining extremely rare, would be more likely in the presence of a relatively long operation such as WBINVD. In particular, the kexec-ing CPU invokes native_stop_other_cpus() to stop all remote CPUs before booting to the new kernel. native_stop_other_cpus() then sends a REBOOT vector IPI to remote CPUs and waits for them to stop; if that times out, it also sends NMIs to the still-alive CPUs and waits again for them to stop. If the race happens, kexec proceeds before all CPUs have processed the NMI and stopped[1], and the system hangs. But after tdx_disable_virtualization_cpu(), no more TDX activity can happen on this cpu. When kexec is enabled, flush the cache explicitly at that point; this moves the WBINVD to an earlier stage than stop_this_cpus(), avoiding a possibly lengthy operation at a time where it could cause this race. [1] https://lore.kernel.org/kvm/b963fcd60abe26c7ec5dc20b42f1a2ebbcc72397.1750934177.git.kai.huang@intel.com/ [Make the new function a stub for !CONFIG_KEXEC_CORE. - Paolo] Signed-off-by: Kai Huang Signed-off-by: Paolo Bonzini Signed-off-by: Dave Hansen Acked-by: Paolo Bonzini Tested-by: Farrah Chen Link: https://lore.kernel.org/all/20250901160930.1785244-8-pbonzini%40redhat.com --- arch/x86/include/asm/tdx.h | 6 ++++++ arch/x86/kvm/vmx/tdx.c | 10 ++++++++++ arch/x86/virt/vmx/tdx/tdx.c | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index c178360c1fb1..6120461bd5ff 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -228,5 +228,11 @@ static inline const char *tdx_dump_mce_info(struct mce *m) { return NULL; } static inline const struct tdx_sys_info *tdx_get_sysinfo(void) { return NULL; } #endif /* CONFIG_INTEL_TDX_HOST */ +#ifdef CONFIG_KEXEC_CORE +void tdx_cpu_flush_cache_for_kexec(void); +#else +static inline void tdx_cpu_flush_cache_for_kexec(void) { } +#endif + #endif /* !__ASSEMBLER__ */ #endif /* _ASM_X86_TDX_H */ diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index f457b2e578b2..04b6d332c1af 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -423,6 +423,16 @@ void tdx_disable_virtualization_cpu(void) tdx_flush_vp(&arg); } local_irq_restore(flags); + + /* + * Flush cache now if kexec is possible: this is necessary to avoid + * having dirty private memory cachelines when the new kernel boots, + * but WBINVD is a relatively expensive operation and doing it during + * kexec can exacerbate races in native_stop_other_cpus(). Do it + * now, since this is a safe moment and there is going to be no more + * TDX activity on this CPU from this point on. + */ + tdx_cpu_flush_cache_for_kexec(); } #define TDX_SEAMCALL_RETRIES 10000 diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 2abf53ed59c8..330b560313af 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -1872,3 +1872,22 @@ u64 tdh_phymem_page_wbinvd_hkid(u64 hkid, struct page *page) return seamcall(TDH_PHYMEM_PAGE_WBINVD, &args); } EXPORT_SYMBOL_GPL(tdh_phymem_page_wbinvd_hkid); + +#ifdef CONFIG_KEXEC_CORE +void tdx_cpu_flush_cache_for_kexec(void) +{ + lockdep_assert_preemption_disabled(); + + if (!this_cpu_read(cache_state_incoherent)) + return; + + /* + * Private memory cachelines need to be clean at the time of + * kexec. Write them back now, as the caller promises that + * there should be no more SEAMCALLs on this CPU. + */ + wbinvd(); + this_cpu_write(cache_state_incoherent, false); +} +EXPORT_SYMBOL_GPL(tdx_cpu_flush_cache_for_kexec); +#endif From 9de9040ffc6a3c616a0b4c13c7d4d1c2778cb6ee Mon Sep 17 00:00:00 2001 From: Mounika Botcha Date: Mon, 25 Aug 2025 12:46:58 +0530 Subject: [PATCH 0874/2711] dt-bindings: crypto: Add node for True Random Number Generator Add TRNG node compatible string and reg properities. Signed-off-by: Mounika Botcha Signed-off-by: Harsh Jain Reviewed-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- .../bindings/crypto/xlnx,versal-trng.yaml | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/crypto/xlnx,versal-trng.yaml diff --git a/Documentation/devicetree/bindings/crypto/xlnx,versal-trng.yaml b/Documentation/devicetree/bindings/crypto/xlnx,versal-trng.yaml new file mode 100644 index 000000000000..9dfb0b0ab5c8 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/xlnx,versal-trng.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/crypto/xlnx,versal-trng.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx Versal True Random Number Generator Hardware Accelerator + +maintainers: + - Harsh Jain + - Mounika Botcha + +description: + The Versal True Random Number Generator consists of Ring Oscillators as + entropy source and a deterministic CTR_DRBG random bit generator (DRBG). + +properties: + compatible: + const: xlnx,versal-trng + + reg: + maxItems: 1 + +required: + - reg + +additionalProperties: false + +examples: + - | + rng@f1230000 { + compatible = "xlnx,versal-trng"; + reg = <0xf1230000 0x1000>; + }; +... From 8979744aca8096ee5072798dfc1181606919b35d Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Mon, 25 Aug 2025 12:46:59 +0530 Subject: [PATCH 0875/2711] crypto: xilinx - Add TRNG driver for Versal Add True Random Number Generator(TRNG) driver for Versal platform. Co-developed-by: Mounika Botcha Signed-off-by: Mounika Botcha Signed-off-by: Harsh Jain Signed-off-by: Herbert Xu --- MAINTAINERS | 6 + drivers/crypto/Kconfig | 12 + drivers/crypto/xilinx/Makefile | 1 + drivers/crypto/xilinx/xilinx-trng.c | 405 ++++++++++++++++++++++++++++ 4 files changed, 424 insertions(+) create mode 100644 drivers/crypto/xilinx/xilinx-trng.c diff --git a/MAINTAINERS b/MAINTAINERS index ca728cc24169..c34429333fd8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27609,6 +27609,12 @@ F: Documentation/misc-devices/xilinx_sdfec.rst F: drivers/misc/xilinx_sdfec.c F: include/uapi/misc/xilinx_sdfec.h +XILINX TRNG DRIVER +M: Mounika Botcha +M: Harsh Jain +S: Maintained +F: drivers/crypto/xilinx/xilinx-trng.c + XILINX UARTLITE SERIAL DRIVER M: Peter Korsgaard L: linux-serial@vger.kernel.org diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index f056ec58c96e..657035cfe940 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -725,6 +725,18 @@ config CRYPTO_DEV_TEGRA Select this to enable Tegra Security Engine which accelerates various AES encryption/decryption and HASH algorithms. +config CRYPTO_DEV_XILINX_TRNG + tristate "Support for Xilinx True Random Generator" + depends on ZYNQMP_FIRMWARE || COMPILE_TEST + select CRYPTO_RNG + select HW_RANDOM + help + Xilinx Versal SoC driver provides kernel-side support for True Random Number + Generator and Pseudo random Number in CTR_DRBG mode as defined in NIST SP800-90A. + + To compile this driver as a module, choose M here: the module + will be called xilinx-trng. + config CRYPTO_DEV_ZYNQMP_AES tristate "Support for Xilinx ZynqMP AES hw accelerator" depends on ZYNQMP_FIRMWARE || COMPILE_TEST diff --git a/drivers/crypto/xilinx/Makefile b/drivers/crypto/xilinx/Makefile index 730feff5b5f2..9b51636ef75e 100644 --- a/drivers/crypto/xilinx/Makefile +++ b/drivers/crypto/xilinx/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_CRYPTO_DEV_XILINX_TRNG) += xilinx-trng.o obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_AES) += zynqmp-aes-gcm.o obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_SHA3) += zynqmp-sha.o diff --git a/drivers/crypto/xilinx/xilinx-trng.c b/drivers/crypto/xilinx/xilinx-trng.c new file mode 100644 index 000000000000..4e4700d68127 --- /dev/null +++ b/drivers/crypto/xilinx/xilinx-trng.c @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Versal True Random Number Generator driver + * Copyright (c) 2024 - 2025 Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* TRNG Registers Offsets */ +#define TRNG_STATUS_OFFSET 0x4U +#define TRNG_CTRL_OFFSET 0x8U +#define TRNG_EXT_SEED_OFFSET 0x40U +#define TRNG_PER_STRNG_OFFSET 0x80U +#define TRNG_CORE_OUTPUT_OFFSET 0xC0U +#define TRNG_RESET_OFFSET 0xD0U +#define TRNG_OSC_EN_OFFSET 0xD4U + +/* Mask values */ +#define TRNG_RESET_VAL_MASK BIT(0) +#define TRNG_OSC_EN_VAL_MASK BIT(0) +#define TRNG_CTRL_PRNGSRST_MASK BIT(0) +#define TRNG_CTRL_EUMODE_MASK BIT(8) +#define TRNG_CTRL_TRSSEN_MASK BIT(2) +#define TRNG_CTRL_PRNGSTART_MASK BIT(5) +#define TRNG_CTRL_PRNGXS_MASK BIT(3) +#define TRNG_CTRL_PRNGMODE_MASK BIT(7) +#define TRNG_STATUS_DONE_MASK BIT(0) +#define TRNG_STATUS_QCNT_MASK GENMASK(11, 9) +#define TRNG_STATUS_QCNT_16_BYTES 0x800 + +/* Sizes in bytes */ +#define TRNG_SEED_LEN_BYTES 48U +#define TRNG_ENTROPY_SEED_LEN_BYTES 64U +#define TRNG_SEC_STRENGTH_SHIFT 5U +#define TRNG_SEC_STRENGTH_BYTES BIT(TRNG_SEC_STRENGTH_SHIFT) +#define TRNG_BYTES_PER_REG 4U +#define TRNG_RESET_DELAY 10 +#define TRNG_NUM_INIT_REGS 12U +#define TRNG_READ_4_WORD 4 +#define TRNG_DATA_READ_DELAY 8000 + +struct xilinx_rng { + void __iomem *rng_base; + struct device *dev; + struct mutex lock; /* Protect access to TRNG device */ + struct hwrng trng; +}; + +struct xilinx_rng_ctx { + struct xilinx_rng *rng; +}; + +static struct xilinx_rng *xilinx_rng_dev; + +static void xtrng_readwrite32(void __iomem *addr, u32 mask, u8 value) +{ + u32 val; + + val = ioread32(addr); + val = (val & (~mask)) | (mask & value); + iowrite32(val, addr); +} + +static void xtrng_trng_reset(void __iomem *addr) +{ + xtrng_readwrite32(addr + TRNG_RESET_OFFSET, TRNG_RESET_VAL_MASK, TRNG_RESET_VAL_MASK); + udelay(TRNG_RESET_DELAY); + xtrng_readwrite32(addr + TRNG_RESET_OFFSET, TRNG_RESET_VAL_MASK, 0); +} + +static void xtrng_hold_reset(void __iomem *addr) +{ + xtrng_readwrite32(addr + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK, + TRNG_CTRL_PRNGSRST_MASK); + iowrite32(TRNG_RESET_VAL_MASK, addr + TRNG_RESET_OFFSET); + udelay(TRNG_RESET_DELAY); +} + +static void xtrng_softreset(struct xilinx_rng *rng) +{ + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK, + TRNG_CTRL_PRNGSRST_MASK); + udelay(TRNG_RESET_DELAY); + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSRST_MASK, 0); +} + +/* Return no. of bytes read */ +static size_t xtrng_readblock32(void __iomem *rng_base, __be32 *buf, int blocks32, bool wait) +{ + int read = 0, ret; + int timeout = 1; + int i, idx; + u32 val; + + if (wait) + timeout = TRNG_DATA_READ_DELAY; + + for (i = 0; i < (blocks32 * 2); i++) { + /* TRNG core generate data in 16 bytes. Read twice to complete 32 bytes read */ + ret = readl_poll_timeout(rng_base + TRNG_STATUS_OFFSET, val, + (val & TRNG_STATUS_QCNT_MASK) == + TRNG_STATUS_QCNT_16_BYTES, !!wait, timeout); + if (ret) + break; + + for (idx = 0; idx < TRNG_READ_4_WORD; idx++) { + *(buf + read) = cpu_to_be32(ioread32(rng_base + TRNG_CORE_OUTPUT_OFFSET)); + read += 1; + } + } + return read * 4; +} + +static int xtrng_collect_random_data(struct xilinx_rng *rng, u8 *rand_gen_buf, + int no_of_random_bytes, bool wait) +{ + u8 randbuf[TRNG_SEC_STRENGTH_BYTES]; + int byteleft, blocks, count = 0; + int ret; + + byteleft = no_of_random_bytes & (TRNG_SEC_STRENGTH_BYTES - 1); + blocks = no_of_random_bytes >> TRNG_SEC_STRENGTH_SHIFT; + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK, + TRNG_CTRL_PRNGSTART_MASK); + if (blocks) { + ret = xtrng_readblock32(rng->rng_base, (__be32 *)rand_gen_buf, blocks, wait); + if (!ret) + return 0; + count += ret; + } + + if (byteleft) { + ret = xtrng_readblock32(rng->rng_base, (__be32 *)randbuf, 1, wait); + if (!ret) + return count; + memcpy(rand_gen_buf + (blocks * TRNG_SEC_STRENGTH_BYTES), randbuf, byteleft); + count += byteleft; + } + + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, + TRNG_CTRL_PRNGMODE_MASK | TRNG_CTRL_PRNGSTART_MASK, 0U); + + return count; +} + +static void xtrng_write_multiple_registers(void __iomem *base_addr, u32 *values, size_t n) +{ + void __iomem *reg_addr; + size_t i; + + /* Write seed value into EXTERNAL_SEED Registers in big endian format */ + for (i = 0; i < n; i++) { + reg_addr = (base_addr + ((n - 1 - i) * TRNG_BYTES_PER_REG)); + iowrite32((u32 __force)(cpu_to_be32(values[i])), reg_addr); + } +} + +static void xtrng_enable_entropy(struct xilinx_rng *rng) +{ + iowrite32(TRNG_OSC_EN_VAL_MASK, rng->rng_base + TRNG_OSC_EN_OFFSET); + xtrng_softreset(rng); + iowrite32(TRNG_CTRL_EUMODE_MASK | TRNG_CTRL_TRSSEN_MASK, rng->rng_base + TRNG_CTRL_OFFSET); +} + +static int xtrng_reseed_internal(struct xilinx_rng *rng) +{ + u8 entropy[TRNG_ENTROPY_SEED_LEN_BYTES]; + u32 val; + int ret; + + memset(entropy, 0, sizeof(entropy)); + xtrng_enable_entropy(rng); + + /* collect random data to use it as entropy (input for DF) */ + ret = xtrng_collect_random_data(rng, entropy, TRNG_SEED_LEN_BYTES, true); + if (ret != TRNG_SEED_LEN_BYTES) + return -EINVAL; + + xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET, + (u32 *)entropy, TRNG_NUM_INIT_REGS); + /* select reseed operation */ + iowrite32(TRNG_CTRL_PRNGXS_MASK, rng->rng_base + TRNG_CTRL_OFFSET); + + /* Start the reseed operation with above configuration and wait for STATUS.Done bit to be + * set. Monitor STATUS.CERTF bit, if set indicates SP800-90B entropy health test has failed. + */ + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK, + TRNG_CTRL_PRNGSTART_MASK); + + ret = readl_poll_timeout(rng->rng_base + TRNG_STATUS_OFFSET, val, + (val & TRNG_STATUS_DONE_MASK) == TRNG_STATUS_DONE_MASK, + 1U, 15000U); + if (ret) + return ret; + + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, TRNG_CTRL_PRNGSTART_MASK, 0U); + + return 0; +} + +static int xtrng_random_bytes_generate(struct xilinx_rng *rng, u8 *rand_buf_ptr, + u32 rand_buf_size, int wait) +{ + int nbytes; + int ret; + + xtrng_readwrite32(rng->rng_base + TRNG_CTRL_OFFSET, + TRNG_CTRL_PRNGMODE_MASK | TRNG_CTRL_PRNGXS_MASK, + TRNG_CTRL_PRNGMODE_MASK | TRNG_CTRL_PRNGXS_MASK); + nbytes = xtrng_collect_random_data(rng, rand_buf_ptr, rand_buf_size, wait); + + ret = xtrng_reseed_internal(rng); + if (ret) { + dev_err(rng->dev, "Re-seed fail\n"); + return ret; + } + + return nbytes; +} + +static int xtrng_trng_generate(struct crypto_rng *tfm, const u8 *src, u32 slen, + u8 *dst, u32 dlen) +{ + struct xilinx_rng_ctx *ctx = crypto_rng_ctx(tfm); + int ret; + + mutex_lock(&ctx->rng->lock); + ret = xtrng_random_bytes_generate(ctx->rng, dst, dlen, true); + mutex_unlock(&ctx->rng->lock); + + return ret < 0 ? ret : 0; +} + +static int xtrng_trng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) +{ + return 0; +} + +static int xtrng_trng_init(struct crypto_tfm *rtfm) +{ + struct xilinx_rng_ctx *ctx = crypto_tfm_ctx(rtfm); + + ctx->rng = xilinx_rng_dev; + + return 0; +} + +static struct rng_alg xtrng_trng_alg = { + .generate = xtrng_trng_generate, + .seed = xtrng_trng_seed, + .seedsize = 0, + .base = { + .cra_name = "stdrng", + .cra_driver_name = "xilinx-trng", + .cra_priority = 300, + .cra_ctxsize = sizeof(struct xilinx_rng_ctx), + .cra_module = THIS_MODULE, + .cra_init = xtrng_trng_init, + }, +}; + +static int xtrng_hwrng_trng_read(struct hwrng *hwrng, void *data, size_t max, bool wait) +{ + u8 buf[TRNG_SEC_STRENGTH_BYTES]; + struct xilinx_rng *rng; + int ret = -EINVAL, i = 0; + + rng = container_of(hwrng, struct xilinx_rng, trng); + /* Return in case wait not set and lock not available. */ + if (!mutex_trylock(&rng->lock) && !wait) + return 0; + else if (!mutex_is_locked(&rng->lock) && wait) + mutex_lock(&rng->lock); + + while (i < max) { + ret = xtrng_random_bytes_generate(rng, buf, TRNG_SEC_STRENGTH_BYTES, wait); + if (ret < 0) + break; + + memcpy(data + i, buf, min_t(int, ret, (max - i))); + i += min_t(int, ret, (max - i)); + } + mutex_unlock(&rng->lock); + + return ret; +} + +static int xtrng_hwrng_register(struct hwrng *trng) +{ + int ret; + + trng->name = "Xilinx Versal Crypto Engine TRNG"; + trng->read = xtrng_hwrng_trng_read; + + ret = hwrng_register(trng); + if (ret) + pr_err("Fail to register the TRNG\n"); + + return ret; +} + +static void xtrng_hwrng_unregister(struct hwrng *trng) +{ + hwrng_unregister(trng); +} + +static int xtrng_probe(struct platform_device *pdev) +{ + struct xilinx_rng *rng; + int ret; + + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); + if (!rng) + return -ENOMEM; + + rng->dev = &pdev->dev; + rng->rng_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rng->rng_base)) { + dev_err(&pdev->dev, "Failed to map resource %ld\n", PTR_ERR(rng->rng_base)); + return PTR_ERR(rng->rng_base); + } + + xtrng_trng_reset(rng->rng_base); + ret = xtrng_reseed_internal(rng); + if (ret) { + dev_err(&pdev->dev, "TRNG Seed fail\n"); + return ret; + } + + xilinx_rng_dev = rng; + mutex_init(&rng->lock); + ret = crypto_register_rng(&xtrng_trng_alg); + if (ret) { + dev_err(&pdev->dev, "Crypto Random device registration failed: %d\n", ret); + return ret; + } + ret = xtrng_hwrng_register(&rng->trng); + if (ret) { + dev_err(&pdev->dev, "HWRNG device registration failed: %d\n", ret); + goto crypto_rng_free; + } + platform_set_drvdata(pdev, rng); + + return 0; + +crypto_rng_free: + crypto_unregister_rng(&xtrng_trng_alg); + + return ret; +} + +static void xtrng_remove(struct platform_device *pdev) +{ + struct xilinx_rng *rng; + u32 zero[TRNG_NUM_INIT_REGS] = { }; + + rng = platform_get_drvdata(pdev); + xtrng_hwrng_unregister(&rng->trng); + crypto_unregister_rng(&xtrng_trng_alg); + xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET, zero, + TRNG_NUM_INIT_REGS); + xtrng_write_multiple_registers(rng->rng_base + TRNG_PER_STRNG_OFFSET, zero, + TRNG_NUM_INIT_REGS); + xtrng_hold_reset(rng->rng_base); + xilinx_rng_dev = NULL; +} + +static const struct of_device_id xtrng_of_match[] = { + { .compatible = "xlnx,versal-trng", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, xtrng_of_match); + +static struct platform_driver xtrng_driver = { + .driver = { + .name = "xlnx,versal-trng", + .of_match_table = xtrng_of_match, + }, + .probe = xtrng_probe, + .remove = xtrng_remove, +}; + +module_platform_driver(xtrng_driver); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harsh Jain "); +MODULE_AUTHOR("Mounika Botcha "); +MODULE_DESCRIPTION("True Random Number Generator Driver"); From ab315f7288b75c289cf4a81d18d6b21e13022364 Mon Sep 17 00:00:00 2001 From: Zhang Enpei Date: Wed, 27 Aug 2025 15:52:36 +0800 Subject: [PATCH 0876/2711] crypto: caam - switch to use devm_kmemdup_array() Use devm_kmemdup_array() to avoid multiplication or possible overflows. Signed-off-by: Zhang Enpei Signed-off-by: Herbert Xu --- drivers/crypto/caam/ctrl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index a93be395c878..ca4f6eb53b9f 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -592,9 +592,9 @@ static int init_clocks(struct device *dev, const struct caam_imx_data *data) int ret; ctrlpriv->num_clks = data->num_clks; - ctrlpriv->clks = devm_kmemdup(dev, data->clks, - data->num_clks * sizeof(data->clks[0]), - GFP_KERNEL); + ctrlpriv->clks = devm_kmemdup_array(dev, data->clks, + data->num_clks, sizeof(*data->clks), + GFP_KERNEL); if (!ctrlpriv->clks) return -ENOMEM; From 1544344563376b2a2ae2af5af1db00d6410c18e0 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Fri, 29 Aug 2025 15:28:44 +0800 Subject: [PATCH 0877/2711] rhashtable: Use __always_inline instead of inline Sometimes, the compiler is not clever enough to inline the rhashtable_lookup() for us, even if the "obj_cmpfn" and "key_len" in params is const. This can introduce more overhead. Therefore, use __always_inline for the rhashtable. Signed-off-by: Menglong Dong Signed-off-by: Herbert Xu --- include/linux/rhashtable.h | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h index 6c85b28ea30b..e740157f3cd7 100644 --- a/include/linux/rhashtable.h +++ b/include/linux/rhashtable.h @@ -122,7 +122,7 @@ static inline unsigned int rht_bucket_index(const struct bucket_table *tbl, return hash & (tbl->size - 1); } -static inline unsigned int rht_key_get_hash(struct rhashtable *ht, +static __always_inline unsigned int rht_key_get_hash(struct rhashtable *ht, const void *key, const struct rhashtable_params params, unsigned int hash_rnd) { @@ -152,7 +152,7 @@ static inline unsigned int rht_key_get_hash(struct rhashtable *ht, return hash; } -static inline unsigned int rht_key_hashfn( +static __always_inline unsigned int rht_key_hashfn( struct rhashtable *ht, const struct bucket_table *tbl, const void *key, const struct rhashtable_params params) { @@ -161,7 +161,7 @@ static inline unsigned int rht_key_hashfn( return rht_bucket_index(tbl, hash); } -static inline unsigned int rht_head_hashfn( +static __always_inline unsigned int rht_head_hashfn( struct rhashtable *ht, const struct bucket_table *tbl, const struct rhash_head *he, const struct rhashtable_params params) { @@ -586,7 +586,7 @@ static inline int rhashtable_compare(struct rhashtable_compare_arg *arg, } /* Internal function, do not use. */ -static inline struct rhash_head *__rhashtable_lookup( +static __always_inline struct rhash_head *__rhashtable_lookup( struct rhashtable *ht, const void *key, const struct rhashtable_params params) { @@ -639,7 +639,7 @@ restart: * * Returns the first entry on which the compare function returned true. */ -static inline void *rhashtable_lookup( +static __always_inline void *rhashtable_lookup( struct rhashtable *ht, const void *key, const struct rhashtable_params params) { @@ -662,7 +662,7 @@ static inline void *rhashtable_lookup( * * Returns the first entry on which the compare function returned true. */ -static inline void *rhashtable_lookup_fast( +static __always_inline void *rhashtable_lookup_fast( struct rhashtable *ht, const void *key, const struct rhashtable_params params) { @@ -689,7 +689,7 @@ static inline void *rhashtable_lookup_fast( * * Returns the list of entries that match the given key. */ -static inline struct rhlist_head *rhltable_lookup( +static __always_inline struct rhlist_head *rhltable_lookup( struct rhltable *hlt, const void *key, const struct rhashtable_params params) { @@ -702,7 +702,7 @@ static inline struct rhlist_head *rhltable_lookup( * function returns the existing element already in hashes if there is a clash, * otherwise it returns an error via ERR_PTR(). */ -static inline void *__rhashtable_insert_fast( +static __always_inline void *__rhashtable_insert_fast( struct rhashtable *ht, const void *key, struct rhash_head *obj, const struct rhashtable_params params, bool rhlist) { @@ -825,7 +825,7 @@ out_unlock: * Will trigger an automatic deferred table resizing if residency in the * table grows beyond 70%. */ -static inline int rhashtable_insert_fast( +static __always_inline int rhashtable_insert_fast( struct rhashtable *ht, struct rhash_head *obj, const struct rhashtable_params params) { @@ -854,7 +854,7 @@ static inline int rhashtable_insert_fast( * Will trigger an automatic deferred table resizing if residency in the * table grows beyond 70%. */ -static inline int rhltable_insert_key( +static __always_inline int rhltable_insert_key( struct rhltable *hlt, const void *key, struct rhlist_head *list, const struct rhashtable_params params) { @@ -877,7 +877,7 @@ static inline int rhltable_insert_key( * Will trigger an automatic deferred table resizing if residency in the * table grows beyond 70%. */ -static inline int rhltable_insert( +static __always_inline int rhltable_insert( struct rhltable *hlt, struct rhlist_head *list, const struct rhashtable_params params) { @@ -902,7 +902,7 @@ static inline int rhltable_insert( * Will trigger an automatic deferred table resizing if residency in the * table grows beyond 70%. */ -static inline int rhashtable_lookup_insert_fast( +static __always_inline int rhashtable_lookup_insert_fast( struct rhashtable *ht, struct rhash_head *obj, const struct rhashtable_params params) { @@ -929,7 +929,7 @@ static inline int rhashtable_lookup_insert_fast( * object if it exists, NULL if it did not and the insertion was successful, * and an ERR_PTR otherwise. */ -static inline void *rhashtable_lookup_get_insert_fast( +static __always_inline void *rhashtable_lookup_get_insert_fast( struct rhashtable *ht, struct rhash_head *obj, const struct rhashtable_params params) { @@ -956,7 +956,7 @@ static inline void *rhashtable_lookup_get_insert_fast( * * Returns zero on success. */ -static inline int rhashtable_lookup_insert_key( +static __always_inline int rhashtable_lookup_insert_key( struct rhashtable *ht, const void *key, struct rhash_head *obj, const struct rhashtable_params params) { @@ -982,7 +982,7 @@ static inline int rhashtable_lookup_insert_key( * object if it exists, NULL if it does not and the insertion was successful, * and an ERR_PTR otherwise. */ -static inline void *rhashtable_lookup_get_insert_key( +static __always_inline void *rhashtable_lookup_get_insert_key( struct rhashtable *ht, const void *key, struct rhash_head *obj, const struct rhashtable_params params) { @@ -992,7 +992,7 @@ static inline void *rhashtable_lookup_get_insert_key( } /* Internal function, please use rhashtable_remove_fast() instead */ -static inline int __rhashtable_remove_fast_one( +static __always_inline int __rhashtable_remove_fast_one( struct rhashtable *ht, struct bucket_table *tbl, struct rhash_head *obj, const struct rhashtable_params params, bool rhlist) @@ -1074,7 +1074,7 @@ unlocked: } /* Internal function, please use rhashtable_remove_fast() instead */ -static inline int __rhashtable_remove_fast( +static __always_inline int __rhashtable_remove_fast( struct rhashtable *ht, struct rhash_head *obj, const struct rhashtable_params params, bool rhlist) { @@ -1115,7 +1115,7 @@ static inline int __rhashtable_remove_fast( * * Returns zero on success, -ENOENT if the entry could not be found. */ -static inline int rhashtable_remove_fast( +static __always_inline int rhashtable_remove_fast( struct rhashtable *ht, struct rhash_head *obj, const struct rhashtable_params params) { @@ -1137,7 +1137,7 @@ static inline int rhashtable_remove_fast( * * Returns zero on success, -ENOENT if the entry could not be found. */ -static inline int rhltable_remove( +static __always_inline int rhltable_remove( struct rhltable *hlt, struct rhlist_head *list, const struct rhashtable_params params) { @@ -1145,7 +1145,7 @@ static inline int rhltable_remove( } /* Internal function, please use rhashtable_replace_fast() instead */ -static inline int __rhashtable_replace_fast( +static __always_inline int __rhashtable_replace_fast( struct rhashtable *ht, struct bucket_table *tbl, struct rhash_head *obj_old, struct rhash_head *obj_new, const struct rhashtable_params params) @@ -1208,7 +1208,7 @@ unlocked: * Returns zero on success, -ENOENT if the entry could not be found, * -EINVAL if hash is not the same for the old and new objects. */ -static inline int rhashtable_replace_fast( +static __always_inline int rhashtable_replace_fast( struct rhashtable *ht, struct rhash_head *obj_old, struct rhash_head *obj_new, const struct rhashtable_params params) From 56e6f77ebd31250757ffbdcbd9baa78ab27895a8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 30 Aug 2025 16:39:15 +0800 Subject: [PATCH 0878/2711] crypto: hisilicon/sec2 - Fix false-positive warning of uninitialised qp_ctx Fix the false-positive warning of qp_ctx being unitialised in sec_request_init. The value of ctx_q_num defaults to 2 and is guaranteed to be non-zero. Thus qp_ctx is always initialised. However, the compiler is not aware of this constraint on ctx_q_num. Restructure the loop so that it is obvious to the compiler that ctx_q_num cannot be zero. Signed-off-by: Herbert Xu Reviewed-by: Longfang Liu Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/sec2/sec_crypto.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c index d044ded0f290..31590d01139a 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -1944,14 +1944,12 @@ static void sec_request_uninit(struct sec_req *req) static int sec_request_init(struct sec_ctx *ctx, struct sec_req *req) { struct sec_qp_ctx *qp_ctx; - int i; + int i = 0; - for (i = 0; i < ctx->sec->ctx_q_num; i++) { + do { qp_ctx = &ctx->qp_ctx[i]; req->req_id = sec_alloc_req_id(req, qp_ctx); - if (req->req_id >= 0) - break; - } + } while (req->req_id < 0 && ++i < ctx->sec->ctx_q_num); req->qp_ctx = qp_ctx; req->backlog = &qp_ctx->backlog; From 35c5097f737a164b3afe23d07698db95061f0db8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 30 Aug 2025 16:52:12 +0800 Subject: [PATCH 0879/2711] crypto: ti - Enable compile testing for dthev2 Allow ti dthev2 driver to be compile-tested. Signed-off-by: Herbert Xu Acked-by: T Pratham Signed-off-by: Herbert Xu --- drivers/crypto/Makefile | 2 +- drivers/crypto/ti/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index c0e8d4acc37c..170e10b18f9b 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -48,4 +48,4 @@ obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ obj-y += intel/ obj-y += starfive/ obj-y += cavium/ -obj-$(CONFIG_ARCH_K3) += ti/ +obj-y += ti/ diff --git a/drivers/crypto/ti/Kconfig b/drivers/crypto/ti/Kconfig index 38d22cab05a9..d4f91c1e0cb5 100644 --- a/drivers/crypto/ti/Kconfig +++ b/drivers/crypto/ti/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config CRYPTO_DEV_TI_DTHEV2 tristate "Support for TI DTHE V2 cryptography engine" - depends on CRYPTO && CRYPTO_HW && ARCH_K3 + depends on ARCH_K3 || COMPILE_TEST select CRYPTO_ENGINE select CRYPTO_SKCIPHER select CRYPTO_ECB From cf79ed6aacd3f7486972efda15a7d03d03ac274e Mon Sep 17 00:00:00 2001 From: Chenghai Huang Date: Sat, 30 Aug 2025 18:27:56 +0800 Subject: [PATCH 0880/2711] crypto: hisilicon/zip - add lz4 and lz77_only to algorithm sysfs The current hisilicon zip supports the new algorithms lz77_only and lz4. To enable user space to recognize the new algorithm support, add lz77_only and lz4 to the sysfs. Users can now use the new algorithms through uacce. Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/zip/zip_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index fcb72d5cf592..62cd090e13af 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -80,6 +80,7 @@ #define HZIP_ALG_GZIP_BIT GENMASK(3, 2) #define HZIP_ALG_DEFLATE_BIT GENMASK(5, 4) #define HZIP_ALG_LZ77_BIT GENMASK(7, 6) +#define HZIP_ALG_LZ4_BIT GENMASK(9, 8) #define HZIP_BUF_SIZE 22 #define HZIP_SQE_MASK_OFFSET 64 @@ -150,6 +151,12 @@ static const struct qm_dev_alg zip_dev_algs[] = { { }, { .alg_msk = HZIP_ALG_LZ77_BIT, .alg = "lz77_zstd\n", + }, { + .alg_msk = HZIP_ALG_LZ77_BIT, + .alg = "lz77_only\n", + }, { + .alg_msk = HZIP_ALG_LZ4_BIT, + .alg = "lz4\n", }, }; From 886d6981208263b55a1eb8b39c5d00db1544b9bb Mon Sep 17 00:00:00 2001 From: Zhushuai Yin Date: Sat, 30 Aug 2025 18:27:57 +0800 Subject: [PATCH 0881/2711] crypto: hisilicon/zip - add hashjoin, gather, and UDMA data move features The new version of the hisilicon zip driver supports the hash join and gather features, as well as the data move feature (UDMA), including data copying and memory initialization functions.These features are registered to the uacce subsystem. Signed-off-by: Zhushuai Yin Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 29 +++++++++++++++++++------ drivers/crypto/hisilicon/zip/dae_main.c | 11 ++++++++-- include/linux/hisi_acc_qm.h | 1 + include/uapi/misc/uacce/hisi_qm.h | 1 + 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 102aff9ea19a..98099117bb38 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -2742,6 +2742,27 @@ static void qm_remove_uacce(struct hisi_qm *qm) } } +static void qm_uacce_api_ver_init(struct hisi_qm *qm) +{ + struct uacce_device *uacce = qm->uacce; + + switch (qm->ver) { + case QM_HW_V1: + uacce->api_ver = HISI_QM_API_VER_BASE; + break; + case QM_HW_V2: + uacce->api_ver = HISI_QM_API_VER2_BASE; + break; + case QM_HW_V3: + case QM_HW_V4: + uacce->api_ver = HISI_QM_API_VER3_BASE; + break; + default: + uacce->api_ver = HISI_QM_API_VER5_BASE; + break; + } +} + static int qm_alloc_uacce(struct hisi_qm *qm) { struct pci_dev *pdev = qm->pdev; @@ -2775,13 +2796,6 @@ static int qm_alloc_uacce(struct hisi_qm *qm) uacce->is_vf = pdev->is_virtfn; uacce->priv = qm; - if (qm->ver == QM_HW_V1) - uacce->api_ver = HISI_QM_API_VER_BASE; - else if (qm->ver == QM_HW_V2) - uacce->api_ver = HISI_QM_API_VER2_BASE; - else - uacce->api_ver = HISI_QM_API_VER3_BASE; - if (qm->ver == QM_HW_V1) mmio_page_nr = QM_DOORBELL_PAGE_NR; else if (!test_bit(QM_SUPPORT_DB_ISOLATION, &qm->caps)) @@ -2801,6 +2815,7 @@ static int qm_alloc_uacce(struct hisi_qm *qm) uacce->qf_pg_num[UACCE_QFRT_DUS] = dus_page_nr; qm->uacce = uacce; + qm_uacce_api_ver_init(qm); INIT_LIST_HEAD(&qm->isolate_data.qm_hw_errs); mutex_init(&qm->isolate_data.isolate_lock); diff --git a/drivers/crypto/hisilicon/zip/dae_main.c b/drivers/crypto/hisilicon/zip/dae_main.c index 6f22e4c36e49..4c5481c77436 100644 --- a/drivers/crypto/hisilicon/zip/dae_main.c +++ b/drivers/crypto/hisilicon/zip/dae_main.c @@ -15,6 +15,7 @@ #define DAE_REG_RD_TMOUT_US USEC_PER_SEC #define DAE_ALG_NAME "hashagg" +#define DAE_V5_ALG_NAME "hashagg\nudma\nhashjoin\ngather" /* error */ #define DAE_AXI_CFG_OFFSET 0x331000 @@ -82,6 +83,7 @@ int hisi_dae_set_user_domain(struct hisi_qm *qm) int hisi_dae_set_alg(struct hisi_qm *qm) { + const char *alg_name; size_t len; if (!dae_is_support(qm)) @@ -90,9 +92,14 @@ int hisi_dae_set_alg(struct hisi_qm *qm) if (!qm->uacce) return 0; + if (qm->ver >= QM_HW_V5) + alg_name = DAE_V5_ALG_NAME; + else + alg_name = DAE_ALG_NAME; + len = strlen(qm->uacce->algs); /* A line break may be required */ - if (len + strlen(DAE_ALG_NAME) + 1 >= QM_DEV_ALG_MAX_LEN) { + if (len + strlen(alg_name) + 1 >= QM_DEV_ALG_MAX_LEN) { pci_err(qm->pdev, "algorithm name is too long!\n"); return -EINVAL; } @@ -100,7 +107,7 @@ int hisi_dae_set_alg(struct hisi_qm *qm) if (len) strcat((char *)qm->uacce->algs, "\n"); - strcat((char *)qm->uacce->algs, DAE_ALG_NAME); + strcat((char *)qm->uacce->algs, alg_name); return 0; } diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index 0c4c84b8c3be..f2254ddc327c 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -125,6 +125,7 @@ enum qm_hw_ver { QM_HW_V2 = 0x21, QM_HW_V3 = 0x30, QM_HW_V4 = 0x50, + QM_HW_V5 = 0x51, }; enum qm_fun_type { diff --git a/include/uapi/misc/uacce/hisi_qm.h b/include/uapi/misc/uacce/hisi_qm.h index 3e66dbc2f323..10504b48eabf 100644 --- a/include/uapi/misc/uacce/hisi_qm.h +++ b/include/uapi/misc/uacce/hisi_qm.h @@ -31,6 +31,7 @@ struct hisi_qp_info { #define HISI_QM_API_VER_BASE "hisi_qm_v1" #define HISI_QM_API_VER2_BASE "hisi_qm_v2" #define HISI_QM_API_VER3_BASE "hisi_qm_v3" +#define HISI_QM_API_VER5_BASE "hisi_qm_v5" /* UACCE_CMD_QM_SET_QP_CTX: Set qp algorithm type */ #define UACCE_CMD_QM_SET_QP_CTX _IOWR('H', 10, struct hisi_qp_ctx) From 06cb58b310ea38a8135827f726157df59a95376e Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 22 Aug 2025 08:42:32 +0000 Subject: [PATCH 0882/2711] rust: iov: add iov_iter abstractions for ITER_SOURCE This adds abstractions for the iov_iter type in the case where data_source is ITER_SOURCE. This will make Rust implementations of fops->write_iter possible. This series only has support for using existing IO vectors created by C code. Additional abstractions will be needed to support the creation of IO vectors in Rust code. These abstractions make the assumption that `struct iov_iter` does not have internal self-references, which implies that it is valid to move it between different local variables. Reviewed-by: Andreas Hindborg Reviewed-by: Danilo Krummrich Signed-off-by: Alice Ryhl Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250822-iov-iter-v5-1-6ce4819c2977@google.com --- rust/kernel/iov.rs | 171 +++++++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 2 files changed, 172 insertions(+) create mode 100644 rust/kernel/iov.rs diff --git a/rust/kernel/iov.rs b/rust/kernel/iov.rs new file mode 100644 index 000000000000..01f4b90ff8b4 --- /dev/null +++ b/rust/kernel/iov.rs @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! IO vectors. +//! +//! C headers: [`include/linux/iov_iter.h`](srctree/include/linux/iov_iter.h), +//! [`include/linux/uio.h`](srctree/include/linux/uio.h) + +use crate::{ + alloc::{Allocator, Flags}, + bindings, + prelude::*, + types::Opaque, +}; +use core::{marker::PhantomData, mem::MaybeUninit, ptr, slice}; + +const ITER_SOURCE: bool = bindings::ITER_SOURCE != 0; + +/// An IO vector that acts as a source of data. +/// +/// The data may come from many different sources. This includes both things in kernel-space and +/// reading from userspace. It's not necessarily the case that the data source is immutable, so +/// rewinding the IO vector to read the same data twice is not guaranteed to result in the same +/// bytes. It's also possible that the data source is mapped in a thread-local manner using e.g. +/// `kmap_local_page()`, so this type is not `Send` to ensure that the mapping is read from the +/// right context in that scenario. +/// +/// # Invariants +/// +/// Must hold a valid `struct iov_iter` with `data_source` set to `ITER_SOURCE`. For the duration +/// of `'data`, it must be safe to read from this IO vector using the standard C methods for this +/// purpose. +#[repr(transparent)] +pub struct IovIterSource<'data> { + iov: Opaque, + /// Represent to the type system that this value contains a pointer to readable data it does + /// not own. + _source: PhantomData<&'data [u8]>, +} + +impl<'data> IovIterSource<'data> { + /// Obtain an `IovIterSource` from a raw pointer. + /// + /// # Safety + /// + /// * The referenced `struct iov_iter` must be valid and must only be accessed through the + /// returned reference for the duration of `'iov`. + /// * The referenced `struct iov_iter` must have `data_source` set to `ITER_SOURCE`. + /// * For the duration of `'data`, it must be safe to read from this IO vector using the + /// standard C methods for this purpose. + #[track_caller] + #[inline] + pub unsafe fn from_raw<'iov>(ptr: *mut bindings::iov_iter) -> &'iov mut IovIterSource<'data> { + // SAFETY: The caller ensures that `ptr` is valid. + let data_source = unsafe { (*ptr).data_source }; + assert_eq!(data_source, ITER_SOURCE); + + // SAFETY: The caller ensures the type invariants for the right durations, and + // `IovIterSource` is layout compatible with `struct iov_iter`. + unsafe { &mut *ptr.cast::>() } + } + + /// Access this as a raw `struct iov_iter`. + #[inline] + pub fn as_raw(&mut self) -> *mut bindings::iov_iter { + self.iov.get() + } + + /// Returns the number of bytes available in this IO vector. + /// + /// Note that this may overestimate the number of bytes. For example, reading from userspace + /// memory could fail with `EFAULT`, which will be treated as the end of the IO vector. + #[inline] + pub fn len(&self) -> usize { + // SAFETY: We have shared access to this IO vector, so we can read its `count` field. + unsafe { + (*self.iov.get()) + .__bindgen_anon_1 + .__bindgen_anon_1 + .as_ref() + .count + } + } + + /// Returns whether there are any bytes left in this IO vector. + /// + /// This may return `true` even if there are no more bytes available. For example, reading from + /// userspace memory could fail with `EFAULT`, which will be treated as the end of the IO vector. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Advance this IO vector by `bytes` bytes. + /// + /// If `bytes` is larger than the size of this IO vector, it is advanced to the end. + #[inline] + pub fn advance(&mut self, bytes: usize) { + // SAFETY: By the type invariants, `self.iov` is a valid IO vector. + unsafe { bindings::iov_iter_advance(self.as_raw(), bytes) }; + } + + /// Advance this IO vector backwards by `bytes` bytes. + /// + /// # Safety + /// + /// The IO vector must not be reverted to before its beginning. + #[inline] + pub unsafe fn revert(&mut self, bytes: usize) { + // SAFETY: By the type invariants, `self.iov` is a valid IO vector, and the caller + // ensures that `bytes` is in bounds. + unsafe { bindings::iov_iter_revert(self.as_raw(), bytes) }; + } + + /// Read data from this IO vector. + /// + /// Returns the number of bytes that have been copied. + #[inline] + pub fn copy_from_iter(&mut self, out: &mut [u8]) -> usize { + // SAFETY: `Self::copy_from_iter_raw` guarantees that it will not write any uninitialized + // bytes in the provided buffer, so `out` is still a valid `u8` slice after this call. + let out = unsafe { &mut *(ptr::from_mut(out) as *mut [MaybeUninit]) }; + + self.copy_from_iter_raw(out).len() + } + + /// Read data from this IO vector and append it to a vector. + /// + /// Returns the number of bytes that have been copied. + #[inline] + pub fn copy_from_iter_vec( + &mut self, + out: &mut Vec, + flags: Flags, + ) -> Result { + out.reserve(self.len(), flags)?; + let len = self.copy_from_iter_raw(out.spare_capacity_mut()).len(); + // SAFETY: + // - `len` is the length of a subslice of the spare capacity, so `len` is at most the + // length of the spare capacity. + // - `Self::copy_from_iter_raw` guarantees that the first `len` bytes of the spare capacity + // have been initialized. + unsafe { out.inc_len(len) }; + Ok(len) + } + + /// Read data from this IO vector into potentially uninitialized memory. + /// + /// Returns the sub-slice of the output that has been initialized. If the returned slice is + /// shorter than the input buffer, then the entire IO vector has been read. + /// + /// This will never write uninitialized bytes to the provided buffer. + #[inline] + pub fn copy_from_iter_raw(&mut self, out: &mut [MaybeUninit]) -> &mut [u8] { + let capacity = out.len(); + let out = out.as_mut_ptr().cast::(); + + // GUARANTEES: The C API guarantees that it does not write uninitialized bytes to the + // provided buffer. + // SAFETY: + // * By the type invariants, it is still valid to read from this IO vector. + // * `out` is valid for writing for `capacity` bytes because it comes from a slice of + // that length. + let len = unsafe { bindings::_copy_from_iter(out.cast(), capacity, self.as_raw()) }; + + // SAFETY: The underlying C api guarantees that initialized bytes have been written to the + // first `len` bytes of the spare capacity. + unsafe { slice::from_raw_parts_mut(out, len) } + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index ed53169e795c..99dbb7b2812e 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -92,6 +92,7 @@ pub mod fs; pub mod init; pub mod io; pub mod ioctl; +pub mod iov; pub mod jump_label; #[cfg(CONFIG_KUNIT)] pub mod kunit; From ce2e0829241ab96af9c8a12b511debc5e3188934 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 22 Aug 2025 08:42:33 +0000 Subject: [PATCH 0883/2711] rust: iov: add iov_iter abstractions for ITER_DEST This adds abstractions for the iov_iter type in the case where data_source is ITER_DEST. This will make Rust implementations of fops->read_iter possible. This series only has support for using existing IO vectors created by C code. Additional abstractions will be needed to support the creation of IO vectors in Rust code. These abstractions make the assumption that `struct iov_iter` does not have internal self-references, which implies that it is valid to move it between different local variables. This patch adds an IovIterDest struct that is very similar to the IovIterSource from the previous patch. However, as the methods on the two structs have very little overlap (just getting the length and advance/revert), I do not think it is worth it to try and deduplicate this logic. Reviewed-by: Andreas Hindborg Reviewed-by: Danilo Krummrich Signed-off-by: Alice Ryhl Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250822-iov-iter-v5-2-6ce4819c2977@google.com --- rust/kernel/iov.rs | 143 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/rust/kernel/iov.rs b/rust/kernel/iov.rs index 01f4b90ff8b4..43bae8923c46 100644 --- a/rust/kernel/iov.rs +++ b/rust/kernel/iov.rs @@ -16,6 +16,15 @@ use crate::{ use core::{marker::PhantomData, mem::MaybeUninit, ptr, slice}; const ITER_SOURCE: bool = bindings::ITER_SOURCE != 0; +const ITER_DEST: bool = bindings::ITER_DEST != 0; + +// Compile-time assertion for the above constants. +const _: () = { + build_assert!( + ITER_SOURCE != ITER_DEST, + "ITER_DEST and ITER_SOURCE should be different." + ); +}; /// An IO vector that acts as a source of data. /// @@ -169,3 +178,137 @@ impl<'data> IovIterSource<'data> { unsafe { slice::from_raw_parts_mut(out, len) } } } + +/// An IO vector that acts as a destination for data. +/// +/// IO vectors support many different types of destinations. This includes both buffers in +/// kernel-space and writing to userspace. It's possible that the destination buffer is mapped in a +/// thread-local manner using e.g. `kmap_local_page()`, so this type is not `Send` to ensure that +/// the mapping is written to the right context in that scenario. +/// +/// # Invariants +/// +/// Must hold a valid `struct iov_iter` with `data_source` set to `ITER_DEST`. For the duration of +/// `'data`, it must be safe to write to this IO vector using the standard C methods for this +/// purpose. +#[repr(transparent)] +pub struct IovIterDest<'data> { + iov: Opaque, + /// Represent to the type system that this value contains a pointer to writable data it does + /// not own. + _source: PhantomData<&'data mut [u8]>, +} + +impl<'data> IovIterDest<'data> { + /// Obtain an `IovIterDest` from a raw pointer. + /// + /// # Safety + /// + /// * The referenced `struct iov_iter` must be valid and must only be accessed through the + /// returned reference for the duration of `'iov`. + /// * The referenced `struct iov_iter` must have `data_source` set to `ITER_DEST`. + /// * For the duration of `'data`, it must be safe to write to this IO vector using the + /// standard C methods for this purpose. + #[track_caller] + #[inline] + pub unsafe fn from_raw<'iov>(ptr: *mut bindings::iov_iter) -> &'iov mut IovIterDest<'data> { + // SAFETY: The caller ensures that `ptr` is valid. + let data_source = unsafe { (*ptr).data_source }; + assert_eq!(data_source, ITER_DEST); + + // SAFETY: The caller ensures the type invariants for the right durations, and + // `IovIterSource` is layout compatible with `struct iov_iter`. + unsafe { &mut *ptr.cast::>() } + } + + /// Access this as a raw `struct iov_iter`. + #[inline] + pub fn as_raw(&mut self) -> *mut bindings::iov_iter { + self.iov.get() + } + + /// Returns the number of bytes available in this IO vector. + /// + /// Note that this may overestimate the number of bytes. For example, reading from userspace + /// memory could fail with EFAULT, which will be treated as the end of the IO vector. + #[inline] + pub fn len(&self) -> usize { + // SAFETY: We have shared access to this IO vector, so we can read its `count` field. + unsafe { + (*self.iov.get()) + .__bindgen_anon_1 + .__bindgen_anon_1 + .as_ref() + .count + } + } + + /// Returns whether there are any bytes left in this IO vector. + /// + /// This may return `true` even if there are no more bytes available. For example, reading from + /// userspace memory could fail with EFAULT, which will be treated as the end of the IO vector. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Advance this IO vector by `bytes` bytes. + /// + /// If `bytes` is larger than the size of this IO vector, it is advanced to the end. + #[inline] + pub fn advance(&mut self, bytes: usize) { + // SAFETY: By the type invariants, `self.iov` is a valid IO vector. + unsafe { bindings::iov_iter_advance(self.as_raw(), bytes) }; + } + + /// Advance this IO vector backwards by `bytes` bytes. + /// + /// # Safety + /// + /// The IO vector must not be reverted to before its beginning. + #[inline] + pub unsafe fn revert(&mut self, bytes: usize) { + // SAFETY: By the type invariants, `self.iov` is a valid IO vector, and the caller + // ensures that `bytes` is in bounds. + unsafe { bindings::iov_iter_revert(self.as_raw(), bytes) }; + } + + /// Write data to this IO vector. + /// + /// Returns the number of bytes that were written. If this is shorter than the provided slice, + /// then no more bytes can be written. + #[inline] + pub fn copy_to_iter(&mut self, input: &[u8]) -> usize { + // SAFETY: + // * By the type invariants, it is still valid to write to this IO vector. + // * `input` is valid for `input.len()` bytes. + unsafe { bindings::_copy_to_iter(input.as_ptr().cast(), input.len(), self.as_raw()) } + } + + /// Utility for implementing `read_iter` given the full contents of the file. + /// + /// The full contents of the file being read from is represented by `contents`. This call will + /// write the appropriate sub-slice of `contents` and update the file position in `ppos` so + /// that the file will appear to contain `contents` even if takes multiple reads to read the + /// entire file. + #[inline] + pub fn simple_read_from_buffer(&mut self, ppos: &mut i64, contents: &[u8]) -> Result { + if *ppos < 0 { + return Err(EINVAL); + } + let Ok(pos) = usize::try_from(*ppos) else { + return Ok(0); + }; + if pos >= contents.len() { + return Ok(0); + } + + // BOUNDS: We just checked that `pos < contents.len()` above. + let num_written = self.copy_to_iter(&contents[pos..]); + + // OVERFLOW: `pos+num_written <= contents.len() <= isize::MAX <= i64::MAX`. + *ppos = (pos + num_written) as i64; + + Ok(num_written) + } +} From 5e15de179a204ce26623d8468283ac04a0dc672f Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 22 Aug 2025 08:42:34 +0000 Subject: [PATCH 0884/2711] rust: fs: add Kiocb struct This adds a very simple Kiocb struct that lets you access the inner file's private data and the file position. For now, nothing else is supported. Cc: Christian Brauner Reviewed-by: Andreas Hindborg Signed-off-by: Alice Ryhl Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250822-iov-iter-v5-3-6ce4819c2977@google.com --- rust/kernel/fs.rs | 3 ++ rust/kernel/fs/kiocb.rs | 68 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 rust/kernel/fs/kiocb.rs diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 0121b38c59e6..6ba6bdf143cb 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -6,3 +6,6 @@ pub mod file; pub use self::file::{File, LocalFile}; + +mod kiocb; +pub use self::kiocb::Kiocb; diff --git a/rust/kernel/fs/kiocb.rs b/rust/kernel/fs/kiocb.rs new file mode 100644 index 000000000000..84c936cd69b0 --- /dev/null +++ b/rust/kernel/fs/kiocb.rs @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Kernel IO callbacks. +//! +//! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h) + +use core::marker::PhantomData; +use core::ptr::NonNull; +use kernel::types::ForeignOwnable; + +/// Wrapper for the kernel's `struct kiocb`. +/// +/// Currently this abstractions is incomplete and is essentially just a tuple containing a +/// reference to a file and a file position. +/// +/// The type `T` represents the filesystem or driver specific data associated with the file. +/// +/// # Invariants +/// +/// `inner` points at a valid `struct kiocb` whose file has the type `T` as its private data. +pub struct Kiocb<'a, T> { + inner: NonNull, + _phantom: PhantomData<&'a T>, +} + +impl<'a, T: ForeignOwnable> Kiocb<'a, T> { + /// Create a `Kiocb` from a raw pointer. + /// + /// # Safety + /// + /// The pointer must reference a valid `struct kiocb` for the duration of `'a`. The private + /// data of the file must be `T`. + pub unsafe fn from_raw(kiocb: *mut bindings::kiocb) -> Self { + Self { + // SAFETY: If a pointer is valid it is not null. + inner: unsafe { NonNull::new_unchecked(kiocb) }, + _phantom: PhantomData, + } + } + + /// Access the underlying `struct kiocb` directly. + pub fn as_raw(&self) -> *mut bindings::kiocb { + self.inner.as_ptr() + } + + /// Get the filesystem or driver specific data associated with the file. + pub fn file(&self) -> ::Borrowed<'a> { + // SAFETY: We have shared access to this kiocb and hence the underlying file, so we can + // read the file's private data. + let private = unsafe { (*(*self.as_raw()).ki_filp).private_data }; + // SAFETY: The kiocb has shared access to the private data. + unsafe { ::borrow(private) } + } + + /// Gets the current value of `ki_pos`. + pub fn ki_pos(&self) -> i64 { + // SAFETY: We have shared access to the kiocb, so we can read its `ki_pos` field. + unsafe { (*self.as_raw()).ki_pos } + } + + /// Gets a mutable reference to the `ki_pos` field. + pub fn ki_pos_mut(&mut self) -> &mut i64 { + // SAFETY: We have exclusive access to the kiocb, so we can write to `ki_pos`. + unsafe { &mut (*self.as_raw()).ki_pos } + } +} From 39c2745b37dac18c6604083f26caea3fd7e4c50b Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 22 Aug 2025 08:42:35 +0000 Subject: [PATCH 0885/2711] rust: miscdevice: Provide additional abstractions for iov_iter and kiocb structures These will be used for the read_iter() and write_iter() callbacks, which are now the preferred back-ends for when a user operates on a char device with read() and write() respectively. Co-developed-by: Lee Jones Signed-off-by: Lee Jones Reviewed-by: Andreas Hindborg Signed-off-by: Alice Ryhl Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250822-iov-iter-v5-4-6ce4819c2977@google.com --- rust/kernel/miscdevice.rs | 63 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index 6373fe183b27..35630fc63875 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -13,7 +13,8 @@ use crate::{ device::Device, error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR}, ffi::{c_int, c_long, c_uint, c_ulong}, - fs::File, + fs::{File, Kiocb}, + iov::{IovIterDest, IovIterSource}, mm::virt::VmaNew, prelude::*, seq_file::SeqFile, @@ -141,6 +142,16 @@ pub trait MiscDevice: Sized { build_error!(VTABLE_DEFAULT_ERROR) } + /// Read from this miscdevice. + fn read_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIterDest<'_>) -> Result { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Write to this miscdevice. + fn write_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIterSource<'_>) -> Result { + build_error!(VTABLE_DEFAULT_ERROR) + } + /// Handler for ioctls. /// /// The `cmd` argument is usually manipulated using the utilities in [`kernel::ioctl`]. @@ -245,6 +256,46 @@ impl MiscdeviceVTable { 0 } + /// # Safety + /// + /// `kiocb` must be correspond to a valid file that is associated with a + /// `MiscDeviceRegistration`. `iter` must be a valid `struct iov_iter` for writing. + unsafe extern "C" fn read_iter( + kiocb: *mut bindings::kiocb, + iter: *mut bindings::iov_iter, + ) -> isize { + // SAFETY: The caller provides a valid `struct kiocb` associated with a + // `MiscDeviceRegistration` file. + let kiocb = unsafe { Kiocb::from_raw(kiocb) }; + // SAFETY: This is a valid `struct iov_iter` for writing. + let iov = unsafe { IovIterDest::from_raw(iter) }; + + match T::read_iter(kiocb, iov) { + Ok(res) => res as isize, + Err(err) => err.to_errno() as isize, + } + } + + /// # Safety + /// + /// `kiocb` must be correspond to a valid file that is associated with a + /// `MiscDeviceRegistration`. `iter` must be a valid `struct iov_iter` for writing. + unsafe extern "C" fn write_iter( + kiocb: *mut bindings::kiocb, + iter: *mut bindings::iov_iter, + ) -> isize { + // SAFETY: The caller provides a valid `struct kiocb` associated with a + // `MiscDeviceRegistration` file. + let kiocb = unsafe { Kiocb::from_raw(kiocb) }; + // SAFETY: This is a valid `struct iov_iter` for reading. + let iov = unsafe { IovIterSource::from_raw(iter) }; + + match T::write_iter(kiocb, iov) { + Ok(res) => res as isize, + Err(err) => err.to_errno() as isize, + } + } + /// # Safety /// /// `file` must be a valid file that is associated with a `MiscDeviceRegistration`. @@ -341,6 +392,16 @@ impl MiscdeviceVTable { open: Some(Self::open), release: Some(Self::release), mmap: if T::HAS_MMAP { Some(Self::mmap) } else { None }, + read_iter: if T::HAS_READ_ITER { + Some(Self::read_iter) + } else { + None + }, + write_iter: if T::HAS_WRITE_ITER { + Some(Self::write_iter) + } else { + None + }, unlocked_ioctl: if T::HAS_IOCTL { Some(Self::ioctl) } else { From e5b0d7da941a7dc1ced09d57b967fdc124f510f8 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 22 Aug 2025 08:42:36 +0000 Subject: [PATCH 0886/2711] samples: rust_misc_device: Expand the sample to support read()ing from userspace A userland application can now operate on the char device with read() in order to consume a locally held buffer. Memory for the buffer is to be provisioned and the buffer populated in its subsequently provided write() counterpart. Signed-off-by: Lee Jones Reviewed-by: Andreas Hindborg Co-developed-by: Alice Ryhl Signed-off-by: Alice Ryhl Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250822-iov-iter-v5-5-6ce4819c2977@google.com --- samples/rust/rust_misc_device.rs | 36 ++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_device.rs index e7ab77448f75..9e4005e33796 100644 --- a/samples/rust/rust_misc_device.rs +++ b/samples/rust/rust_misc_device.rs @@ -100,8 +100,9 @@ use core::pin::Pin; use kernel::{ c_str, device::Device, - fs::File, + fs::{File, Kiocb}, ioctl::{_IO, _IOC_SIZE, _IOR, _IOW}, + iov::{IovIterDest, IovIterSource}, miscdevice::{MiscDevice, MiscDeviceOptions, MiscDeviceRegistration}, new_mutex, prelude::*, @@ -144,6 +145,7 @@ impl kernel::InPlaceModule for RustMiscDeviceModule { struct Inner { value: i32, + buffer: KVVec, } #[pin_data(PinnedDrop)] @@ -165,7 +167,10 @@ impl MiscDevice for RustMiscDevice { KBox::try_pin_init( try_pin_init! { RustMiscDevice { - inner <- new_mutex!( Inner{ value: 0_i32 } ), + inner <- new_mutex!(Inner { + value: 0_i32, + buffer: KVVec::new(), + }), dev: dev, } }, @@ -173,6 +178,33 @@ impl MiscDevice for RustMiscDevice { ) } + fn read_iter(mut kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIterDest<'_>) -> Result { + let me = kiocb.file(); + dev_info!(me.dev, "Reading from Rust Misc Device Sample\n"); + + let inner = me.inner.lock(); + // Read the buffer contents, taking the file position into account. + let read = iov.simple_read_from_buffer(kiocb.ki_pos_mut(), &inner.buffer)?; + + Ok(read) + } + + fn write_iter(mut kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIterSource<'_>) -> Result { + let me = kiocb.file(); + dev_info!(me.dev, "Writing to Rust Misc Device Sample\n"); + + let mut inner = me.inner.lock(); + + // Replace buffer contents. + inner.buffer.clear(); + let len = iov.copy_from_iter_vec(&mut inner.buffer, GFP_KERNEL)?; + + // Set position to zero so that future `read` calls will see the new contents. + *kiocb.ki_pos_mut() = 0; + + Ok(len) + } + fn ioctl(me: Pin<&RustMiscDevice>, _file: &File, cmd: u32, arg: usize) -> Result { dev_info!(me.dev, "IOCTLing Rust Misc Device Sample\n"); From 91709d2ce5cdf568b42fcc33473929843ed95cd3 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sat, 30 Aug 2025 13:04:20 +0200 Subject: [PATCH 0887/2711] usb: ucsi: stm32: Use min() to improve ucsi_stm32g0_fw_cb() Use min() to improve ucsi_stm32g0_fw_cb() and avoid calculating 'end - data' twice. Signed-off-by: Thorsten Blum Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20250830110426.10007-2-thorsten.blum@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_stm32g0.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index 57ef7d83a412..838ac0185082 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -523,11 +524,7 @@ static void ucsi_stm32g0_fw_cb(const struct firmware *fw, void *context) data = fw->data; end = fw->data + fw->size; while (data < end) { - if ((end - data) < STM32G0_I2C_BL_SZ) - size = end - data; - else - size = STM32G0_I2C_BL_SZ; - + size = min(end - data, STM32G0_I2C_BL_SZ); ret = ucsi_stm32g0_bl_write(g0->ucsi, addr, data, size); if (ret) { dev_err(g0->dev, "Write failed %d\n", ret); From 43ae982cd0ec7fb6fea40fabef2c872e6f9b213d Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 29 Aug 2025 19:37:12 +0200 Subject: [PATCH 0888/2711] usb: usblp: Use min_t() to improve usblp_read() Use min_t() to improve usblp_read() and avoid calculating 'avail - usblp->readcount' twice. Use min_t(ssize_t,,) instead of min() to avoid a signedness error. Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250829173713.56222-1-thorsten.blum@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index acbefccbdb2a..a7a1d38b6bef 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -871,7 +872,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo goto done; } - count = len < avail - usblp->readcount ? len : avail - usblp->readcount; + count = min_t(ssize_t, len, avail - usblp->readcount); if (count != 0 && copy_to_user(buffer, usblp->readbuf + usblp->readcount, count)) { count = -EFAULT; From 811ee632b1f7e543ccaf61d7c241e73c386a6eb2 Mon Sep 17 00:00:00 2001 From: Petr Vorel Date: Fri, 29 Aug 2025 18:17:08 +0200 Subject: [PATCH 0889/2711] usb: misc: Update link to EHSET pdf doc Obviously file on the website was renamed. Signed-off-by: Petr Vorel Link: https://lore.kernel.org/r/20250829161708.106813-1-petr.vorel@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 9bf8fc6247ba..26eaae32f738 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -232,8 +232,8 @@ config USB_EHSET_TEST_FIXTURE VID/PID pairs. This driver then initiates a corresponding test mode on the downstream port to which the test fixture is attached. - See for more - information. + See + for more information. config USB_ISIGHTFW tristate "iSight firmware loading support" From 5195edb359855d9a6460f19b7c3915a8611fceed Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 28 Aug 2025 18:26:24 +0200 Subject: [PATCH 0890/2711] usb: storage: realtek_cr: Simplify residue calculation in rts51x_bulk_transport() Simplify the calculation of 'residue' in rts51x_bulk_transport() and avoid unnecessarily reassigning 'residue' to itself. Acked-by: Alan Stern Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250828162623.4840-3-thorsten.blum@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/realtek_cr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index cb5bbb19060e..3cc243956fd4 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -260,8 +260,8 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun, * try to compute the actual residue, based on how much data * was really transferred and what the device tells us */ - if (residue) - residue = residue < buf_len ? residue : buf_len; + if (residue > buf_len) + residue = buf_len; if (act_len) *act_len = buf_len - residue; From b570b346ddd727c4b41743a6a2f49e7217c5317f Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Fri, 22 Aug 2025 17:22:24 +0800 Subject: [PATCH 0891/2711] usb: phy: twl6030: Fix incorrect type for ret In the twl6030_usb_probe(), the variable ret is declared as a u32 type. However, since ret may receive -ENODEV when accepting the return value of omap_usb2_set_comparator().Therefore, its type should be changed to int. Fixes: 0e98de67bacba ("usb: otg: make twl6030_usb as a comparator driver to omap_usb2") Signed-off-by: Xichao Zhao Link: https://lore.kernel.org/r/20250822092224.30645-1-zhao.xichao@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-twl6030-usb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 49d79c1257f3..8c09db750bfd 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -328,9 +328,8 @@ static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled) static int twl6030_usb_probe(struct platform_device *pdev) { - u32 ret; struct twl6030_usb *twl; - int status, err; + int status, err, ret; struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; From 55f4ac8f93f4281134dfcf47de7b4588bb6074f2 Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Fri, 22 Aug 2025 17:23:45 +0800 Subject: [PATCH 0892/2711] usb: dwc3: Add trace event for dwc3_set_prtcap Changes to the port capability can be indirectly observed by tracing register writes to DWC3_GCTL. However, this requires interpreting the raw value, which is neither intuitive nor precise for debugging. Monitoring these mode changes is essential for resolving issues related to USB role switching and enumeration. Introduce a dedicated trace event to provide a human-readable log when the port capability is configured. Signed-off-by: Kuen-Han Tsai Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20250822092411.173519-1-khtsai@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 1 + drivers/usb/dwc3/debug.h | 18 ++++++++++++++++++ drivers/usb/dwc3/trace.h | 17 +++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 8002c23a5a02..370fc524a468 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -156,6 +156,7 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy) dwc3_writel(dwc->regs, DWC3_GCTL, reg); dwc->current_dr_role = mode; + trace_dwc3_set_prtcap(mode); } static void __dwc3_set_mode(struct work_struct *work) diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 09d703852a92..6e1cdcdce7cc 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -13,6 +13,24 @@ #include "core.h" +/** + * dwc3_mode_string - returns mode name + * @mode: GCTL.PrtCapDir value + */ +static inline const char *dwc3_mode_string(u32 mode) +{ + switch (mode) { + case DWC3_GCTL_PRTCAP_HOST: + return "host"; + case DWC3_GCTL_PRTCAP_DEVICE: + return "device"; + case DWC3_GCTL_PRTCAP_OTG: + return "otg"; + default: + return "UNKNOWN"; + } +} + /** * dwc3_gadget_ep_cmd_string - returns endpoint command string * @cmd: command code diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index bdeb1aaf65d8..b6ba984bafcd 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -19,6 +19,23 @@ #include "core.h" #include "debug.h" +DECLARE_EVENT_CLASS(dwc3_log_set_prtcap, + TP_PROTO(u32 mode), + TP_ARGS(mode), + TP_STRUCT__entry( + __field(u32, mode) + ), + TP_fast_assign( + __entry->mode = mode; + ), + TP_printk("mode %s", dwc3_mode_string(__entry->mode)) +); + +DEFINE_EVENT(dwc3_log_set_prtcap, dwc3_set_prtcap, + TP_PROTO(u32 mode), + TP_ARGS(mode) +); + DECLARE_EVENT_CLASS(dwc3_log_io, TP_PROTO(void *base, u32 offset, u32 value), TP_ARGS(base, offset, value), From 4c9860fbe66177fddb8b7161d6809110d3960a6e Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Fri, 22 Aug 2025 17:23:46 +0800 Subject: [PATCH 0893/2711] usb: dwc3: Refactor dwc3_mode_show Use dwc3_mode_string as the single source of truth for mode-to-string conversion. Signed-off-by: Kuen-Han Tsai Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20250822092411.173519-2-khtsai@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/debugfs.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index ebf03468fac4..d18bf5e32cc8 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -402,6 +402,7 @@ static int dwc3_mode_show(struct seq_file *s, void *unused) struct dwc3 *dwc = s->private; unsigned long flags; u32 reg; + u32 mode; int ret; ret = pm_runtime_resume_and_get(dwc->dev); @@ -412,18 +413,15 @@ static int dwc3_mode_show(struct seq_file *s, void *unused) reg = dwc3_readl(dwc->regs, DWC3_GCTL); spin_unlock_irqrestore(&dwc->lock, flags); - switch (DWC3_GCTL_PRTCAP(reg)) { + mode = DWC3_GCTL_PRTCAP(reg); + switch (mode) { case DWC3_GCTL_PRTCAP_HOST: - seq_puts(s, "host\n"); - break; case DWC3_GCTL_PRTCAP_DEVICE: - seq_puts(s, "device\n"); - break; case DWC3_GCTL_PRTCAP_OTG: - seq_puts(s, "otg\n"); + seq_printf(s, "%s\n", dwc3_mode_string(mode)); break; default: - seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg)); + seq_printf(s, "UNKNOWN %08x\n", mode); } pm_runtime_put_sync(dwc->dev); From c79bf528738c0e98e0744f7a63c27fab35c93b43 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 20 Aug 2025 14:11:01 +0200 Subject: [PATCH 0894/2711] dt-bindings: usb: IXP4xx UDC bindings This adds device tree bindings for the IXP4xx USB Device Controller (UDC). Signed-off-by: Linus Walleij Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250820-ixp4xx-udc-bindings-v1-1-640f29140164@linaro.org Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/intel,ixp4xx-udc.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/intel,ixp4xx-udc.yaml diff --git a/Documentation/devicetree/bindings/usb/intel,ixp4xx-udc.yaml b/Documentation/devicetree/bindings/usb/intel,ixp4xx-udc.yaml new file mode 100644 index 000000000000..4ed602746897 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/intel,ixp4xx-udc.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/intel,ixp4xx-udc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Intel IXP4xx SoC USB Device Controller (UDC) + +description: The IXP4xx SoCs has a full-speed USB Device + Controller with 16 endpoints and a built-in transceiver. + +maintainers: + - Linus Walleij + +properties: + compatible: + const: intel,ixp4xx-udc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + usb@c800b000 { + compatible = "intel,ixp4xx-udc"; + reg = <0xc800b000 0x1000>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>; + }; From 7d3f780122bee082f035aeb6a3cf073dc77dbd1f Mon Sep 17 00:00:00 2001 From: Jihed Chaibi Date: Sun, 24 Aug 2025 13:23:37 +0200 Subject: [PATCH 0895/2711] usb: dt-bindings: ti,twl4030-usb: convert to DT schema Convert the legacy TXT binding for the TWL4030 USB module to the modern YAML DT schema format. This adds formal validation and improves documentation using a conditional schema. Remove the twl4030 section from the obsolete .txt binding file Signed-off-by: Jihed Chaibi Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250824112338.64953-2-jihed.chaibi.dev@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/ti,twl4030-usb.yaml | 74 +++++++++++++++++++ .../devicetree/bindings/usb/twlxxxx-usb.txt | 22 ------ 2 files changed, 74 insertions(+), 22 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/ti,twl4030-usb.yaml diff --git a/Documentation/devicetree/bindings/usb/ti,twl4030-usb.yaml b/Documentation/devicetree/bindings/usb/ti,twl4030-usb.yaml new file mode 100644 index 000000000000..6ef337507425 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ti,twl4030-usb.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/ti,twl4030-usb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TWL4030 USB PHY and Comparator + +maintainers: + - Peter Ujfalusi + +description: + Bindings for the USB PHY and comparator module found within the + TWL4030 family of companion chips. If a sibling node is compatible with + "ti,twl4030-bci", the driver for that node will query this device for + USB power status. + +properties: + compatible: + const: ti,twl4030-usb + + interrupts: + minItems: 1 + items: + - description: OTG interrupt number for ID events. + - description: USB interrupt number for VBUS events. + + usb1v5-supply: + description: Phandle to the vusb1v5 regulator. + + usb1v8-supply: + description: Phandle to the vusb1v8 regulator. + + usb3v1-supply: + description: Phandle to the vusb3v1 regulator. + + usb_mode: + description: | + The mode used by the PHY to connect to the controller: + 1: ULPI mode + 2: CEA2011_3PIN mode + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2] + + '#phy-cells': + const: 0 + +required: + - compatible + - interrupts + - usb1v5-supply + - usb1v8-supply + - usb3v1-supply + - usb_mode + +additionalProperties: false + +examples: + - | + #include + + usb-phy { + compatible = "ti,twl4030-usb"; + + interrupts = <10 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gic>; + + usb1v5-supply = <®_vusb1v5>; + usb1v8-supply = <®_vusb1v8>; + usb3v1-supply = <®_vusb3v1>; + usb_mode = <1>; + + #phy-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt index 17327a296110..7194c9504b28 100644 --- a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt +++ b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt @@ -19,25 +19,3 @@ Board specific device node entry &twl6030-usb { usb-supply = <&vusb>; }; - -TWL4030 USB PHY AND COMPARATOR - - compatible : Should be "ti,twl4030-usb" - - interrupts : The interrupt numbers to the cpu should be specified. First - interrupt number is the otg interrupt number that raises ID interrupts - and VBUS interrupts. The second interrupt number is optional. - - -supply : phandle to the regulator device tree node. - should be vusb1v5, vusb1v8 and vusb3v1 - - usb_mode : The mode used by the phy to connect to the controller. "1" - specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode. - -If a sibling node is compatible "ti,twl4030-bci", then it will find -this device and query it for USB power status. - -twl4030-usb { - compatible = "ti,twl4030-usb"; - interrupts = < 10 4 >; - usb1v5-supply = <&vusb1v5>; - usb1v8-supply = <&vusb1v8>; - usb3v1-supply = <&vusb3v1>; - usb_mode = <1>; -}; From 1daa7f57b85038eb3a4e6220a9623557a759758c Mon Sep 17 00:00:00 2001 From: Jihed Chaibi Date: Sun, 24 Aug 2025 13:23:38 +0200 Subject: [PATCH 0896/2711] usb: dt-bindings: ti,twl6030-usb: convert to DT schema Convert the legacy TXT binding for the TWL6030 USB module to the modern YAML DT schema format. This adds formal validation and improves documentation using a conditional schema. The legacy twlxxxx-usb.txt file is no longer needed and is removed. Signed-off-by: Jihed Chaibi Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250824112338.64953-3-jihed.chaibi.dev@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/ti,twl6030-usb.yaml | 48 +++++++++++++++++++ .../devicetree/bindings/usb/twlxxxx-usb.txt | 21 -------- 2 files changed, 48 insertions(+), 21 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/ti,twl6030-usb.yaml delete mode 100644 Documentation/devicetree/bindings/usb/twlxxxx-usb.txt diff --git a/Documentation/devicetree/bindings/usb/ti,twl6030-usb.yaml b/Documentation/devicetree/bindings/usb/ti,twl6030-usb.yaml new file mode 100644 index 000000000000..33b6da50660a --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ti,twl6030-usb.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/ti,twl6030-usb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TWL6030 USB Comparator + +maintainers: + - Peter Ujfalusi + +description: + Bindings for the USB comparator module found within the TWL6030 + family of companion chips. + +properties: + compatible: + const: ti,twl6030-usb + + interrupts: + items: + - description: OTG for ID events in host mode + - description: USB device mode for VBUS events + + usb-supply: + description: + Phandle to the VUSB regulator. For TWL6030, this should be the 'vusb' + regulator. For TWL6032 subclass, it should be the 'ldousb' regulator. + +required: + - compatible + - interrupts + - usb-supply + +additionalProperties: false + +examples: + - | + #include + + usb { + compatible = "ti,twl6030-usb"; + + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>, <10 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gic>; + + usb-supply = <®_vusb>; + }; diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt deleted file mode 100644 index 7194c9504b28..000000000000 --- a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt +++ /dev/null @@ -1,21 +0,0 @@ -USB COMPARATOR OF TWL CHIPS - -TWL6030 USB COMPARATOR - - compatible : Should be "ti,twl6030-usb" - - interrupts : Two interrupt numbers to the cpu should be specified. First - interrupt number is the otg interrupt number that raises ID interrupts when - the controller has to act as host and the second interrupt number is the - usb interrupt number that raises VBUS interrupts when the controller has to - act as device - - usb-supply : phandle to the regulator device tree node. It should be vusb - if it is twl6030 or ldousb if it is twl6032 subclass. - -twl6030-usb { - compatible = "ti,twl6030-usb"; - interrupts = < 4 10 >; -}; - -Board specific device node entry -&twl6030-usb { - usb-supply = <&vusb>; -}; From 0d7395046bb3e412975bf20bb08b41f34c1cd5da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Gon=C3=A7alves?= Date: Mon, 25 Aug 2025 04:17:39 +0000 Subject: [PATCH 0897/2711] tools/usb/usbip: fix spelling mistakes in usbipd.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct two occurences of 'seperate' typos on comments in lines 399 and 520. Signed-off-by: Eric Gonçalves Link: https://lore.kernel.org/r/20250825041739.8117-1-ghatto404@gmail.com Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/src/usbipd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c index 48398a78e88a..3e22b651c754 100644 --- a/tools/usb/usbip/src/usbipd.c +++ b/tools/usb/usbip/src/usbipd.c @@ -396,7 +396,7 @@ static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[], usbip_net_set_reuseaddr(sock); usbip_net_set_nodelay(sock); - /* We use seperate sockets for IPv4 and IPv6 + /* We use separate sockets for IPv4 and IPv6 * (see do_standalone_mode()) */ usbip_net_set_v6only(sock); @@ -517,7 +517,7 @@ static int do_standalone_mode(int daemonize, int ipv4, int ipv6) /* * To suppress warnings on systems with bindv6only disabled - * (default), we use seperate sockets for IPv6 and IPv4 and set + * (default), we use separate sockets for IPv6 and IPv4 and set * IPV6_V6ONLY on the IPv6 sockets. */ if (ipv4 && ipv6) From ab96716991f3b7634566bc000d69a66b8b2ecc15 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 25 Aug 2025 14:49:00 +0200 Subject: [PATCH 0898/2711] usb: musb: dsps: use platform_get_irq_byname_optional() for vbus IRQ The vbus IRQ is optional, so no error message should be printed if it is not available. Signed-off-by: Matthias Schiffer Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20250825124901.2190539-1-alexander.stein@ew.tq-group.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_dsps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 12f587ab8511..a08ce96c08d3 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -839,7 +839,7 @@ static int dsps_setup_optional_vbus_irq(struct platform_device *pdev, { int error; - glue->vbus_irq = platform_get_irq_byname(pdev, "vbus"); + glue->vbus_irq = platform_get_irq_byname_optional(pdev, "vbus"); if (glue->vbus_irq == -EPROBE_DEFER) return -EPROBE_DEFER; From e271cc0d25015f4be6c88bd7731444644eb352c2 Mon Sep 17 00:00:00 2001 From: William Wu Date: Fri, 22 Aug 2025 11:36:09 +0800 Subject: [PATCH 0899/2711] usb: gadget: configfs: Correctly set use_os_string at bind Once the use_os_string flag is set to true for some functions (e.g. adb/mtp) which need to response the OS string, and then if we re-bind the ConfigFS gadget to use the other functions (e.g. hid) which should not to response the OS string, however, because the use_os_string flag is still true, so the usb gadget response the OS string descriptor incorrectly, this can cause the USB device to be unrecognizable on the Windows system. An example of this as follows: echo 1 > os_desc/use ln -s functions/ffs.adb configs/b.1/function0 start adbd echo "" > UDC #succeed stop adbd rm configs/b.1/function0 echo 0 > os_desc/use ln -s functions/hid.gs0 configs/b.1/function0 echo "" > UDC #fail to connect on Windows This patch sets the use_os_string flag to false at bind if the functions not support OS Descriptors. Signed-off-by: William Wu Fixes: 87213d388e92 ("usb: gadget: configfs: OS String support") Link: https://lore.kernel.org/r/1755833769-25434-1-git-send-email-william.wu@rock-chips.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/configfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index f94ea196ce54..6bcac85c5550 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1750,6 +1750,8 @@ static int configfs_composite_bind(struct usb_gadget *gadget, cdev->use_os_string = true; cdev->b_vendor_code = gi->b_vendor_code; memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN); + } else { + cdev->use_os_string = false; } if (gadget_is_otg(gadget) && !otg_desc[0]) { From ed6f727c575b1eb8136e744acfd5e7306c9548f6 Mon Sep 17 00:00:00 2001 From: William Wu Date: Tue, 26 Aug 2025 18:28:07 +0800 Subject: [PATCH 0900/2711] usb: gadget: f_hid: Fix zero length packet transfer Set the hid req->zero flag of ep0/in_ep to true by default, then the UDC drivers can transfer a zero length packet at the end if the hid transfer with size divisible to EPs max packet size according to the USB 2.0 spec. Signed-off-by: William Wu Link: https://lore.kernel.org/r/1756204087-26111-1-git-send-email-william.wu@rock-chips.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_hid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 8e1d1e884050..307ea563af95 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -511,7 +511,7 @@ try_again: } req->status = 0; - req->zero = 0; + req->zero = 1; req->length = count; req->complete = f_hidg_req_complete; req->context = hidg; @@ -967,7 +967,7 @@ stall: return -EOPNOTSUPP; respond: - req->zero = 0; + req->zero = 1; req->length = length; status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); if (status < 0) From dc60a1cd7a76f2945159a461768010b8154ac8f8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 31 Aug 2025 14:22:23 +0200 Subject: [PATCH 0901/2711] usb: ohci: s3c2410: Drop support for S3C2410 systems Samsung S3C24xx family of SoCs was removed the Linux kernel in the commit 61b7f8920b17 ("ARM: s3c: remove all s3c24xx support"), in January 2023. There are no in-kernel users of remaining S3C24xx compatibles. The driver (named s3c2410) is still being used via platform code for S3C64xx platforms. Signed-off-by: Krzysztof Kozlowski Acked-by: Alan Stern Link: https://lore.kernel.org/r/20250831122222.50332-3-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-s3c2410.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 66d970854357..e623e24d3f8e 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -448,13 +448,6 @@ static const struct dev_pm_ops ohci_hcd_s3c2410_pm_ops = { .resume = ohci_hcd_s3c2410_drv_resume, }; -static const struct of_device_id ohci_hcd_s3c2410_dt_ids[] = { - { .compatible = "samsung,s3c2410-ohci" }, - { /* sentinel */ } -}; - -MODULE_DEVICE_TABLE(of, ohci_hcd_s3c2410_dt_ids); - static struct platform_driver ohci_hcd_s3c2410_driver = { .probe = ohci_hcd_s3c2410_probe, .remove = ohci_hcd_s3c2410_remove, @@ -462,7 +455,6 @@ static struct platform_driver ohci_hcd_s3c2410_driver = { .driver = { .name = "s3c2410-ohci", .pm = &ohci_hcd_s3c2410_pm_ops, - .of_match_table = ohci_hcd_s3c2410_dt_ids, }, }; From 771713aeaca19b4dfb47595bea514859f55747b9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 31 Aug 2025 14:22:24 +0200 Subject: [PATCH 0902/2711] dt-bindings: usb: s3c2410-usb: Drop entirely S3C2410 Samsung S3C24xx family of SoCs was removed the Linux kernel in the commit 61b7f8920b17 ("ARM: s3c: remove all s3c24xx support"), in January 2023. There are no in-kernel users of remaining S3C24xx compatibles. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250831122222.50332-4-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/s3c2410-usb.txt | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 Documentation/devicetree/bindings/usb/s3c2410-usb.txt diff --git a/Documentation/devicetree/bindings/usb/s3c2410-usb.txt b/Documentation/devicetree/bindings/usb/s3c2410-usb.txt deleted file mode 100644 index 26c85afd0b53..000000000000 --- a/Documentation/devicetree/bindings/usb/s3c2410-usb.txt +++ /dev/null @@ -1,22 +0,0 @@ -Samsung S3C2410 and compatible SoC USB controller - -OHCI - -Required properties: - - compatible: should be "samsung,s3c2410-ohci" for USB host controller - - reg: address and length of the controller memory mapped region - - interrupts: interrupt number for the USB OHCI controller - - clocks: Should reference the bus and host clocks - - clock-names: Should contain two strings - "usb-bus-host" for the USB bus clock - "usb-host" for the USB host clock - -Example: - -usb0: ohci@49000000 { - compatible = "samsung,s3c2410-ohci"; - reg = <0x49000000 0x100>; - interrupts = <0 0 26 3>; - clocks = <&clocks UCLK>, <&clocks HCLK_USBH>; - clock-names = "usb-bus-host", "usb-host"; -}; From ea32cd911368e32eb770c9078158467845c82b9a Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 26 Aug 2025 07:45:07 +0800 Subject: [PATCH 0903/2711] dt-bindings: usb: usb251xb: support usage case without I2C control Currently, the usb251xb assumes i2c control, but from HW point of view, the hub supports usage case without any i2c control, I.E we only want the gpio controls, for example the following dt node: usb-hub { compatible = "microchip,usb2512b"; reset-gpios = <&porta 8 GPIO_ACTIVE_LOW>; }; Modify the dt-binding of usb2512b to support this usage case, and add the usage example to the examples section. Signed-off-by: Jisheng Zhang Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250825234509.1041-2-jszhang@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/usb251xb.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/usb251xb.yaml b/Documentation/devicetree/bindings/usb/usb251xb.yaml index ac5b99710332..0329a6aaaa92 100644 --- a/Documentation/devicetree/bindings/usb/usb251xb.yaml +++ b/Documentation/devicetree/bindings/usb/usb251xb.yaml @@ -240,7 +240,6 @@ additionalProperties: false required: - compatible - - reg examples: - | @@ -269,3 +268,11 @@ examples: swap-dx-lanes = <1 2>; }; }; + + - | + #include + usb-hub { + /* I2C is not connected */ + compatible = "microchip,usb2512b"; + reset-gpios = <&porta 8 GPIO_ACTIVE_LOW>; + }; From 22fbedf9d9c2d219339620a95a0611c9ddfc397b Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 26 Aug 2025 07:45:08 +0800 Subject: [PATCH 0904/2711] usb: usb251xb: use modern PM macros Use the modern PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use __maybe_unused. Signed-off-by: Jisheng Zhang Reviewed-by: Richard Leitner Link: https://lore.kernel.org/r/20250825234509.1041-3-jszhang@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usb251xb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index 4fb453ca5450..cb2f946de42c 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -698,7 +698,7 @@ static int usb251xb_i2c_probe(struct i2c_client *i2c) return usb251xb_probe(hub); } -static int __maybe_unused usb251xb_suspend(struct device *dev) +static int usb251xb_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct usb251xb *hub = i2c_get_clientdata(client); @@ -706,7 +706,7 @@ static int __maybe_unused usb251xb_suspend(struct device *dev) return regulator_disable(hub->vdd); } -static int __maybe_unused usb251xb_resume(struct device *dev) +static int usb251xb_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct usb251xb *hub = i2c_get_clientdata(client); @@ -719,7 +719,7 @@ static int __maybe_unused usb251xb_resume(struct device *dev) return usb251xb_connect(hub); } -static SIMPLE_DEV_PM_OPS(usb251xb_pm_ops, usb251xb_suspend, usb251xb_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(usb251xb_pm_ops, usb251xb_suspend, usb251xb_resume); static const struct i2c_device_id usb251xb_id[] = { { "usb2422" }, @@ -739,7 +739,7 @@ static struct i2c_driver usb251xb_i2c_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = usb251xb_of_match, - .pm = &usb251xb_pm_ops, + .pm = pm_sleep_ptr(&usb251xb_pm_ops), }, .probe = usb251xb_i2c_probe, .id_table = usb251xb_id, From 2cf8ecd0ae650c1f0e551326bb7f060abf1560d3 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 26 Aug 2025 07:45:09 +0800 Subject: [PATCH 0905/2711] usb: usb251xb: support usage case without I2C control Currently, the usb251xb assumes i2c control. But from HW point of view, the hub supports usage case without any i2c, we only want the gpio controls. Refactor the code so that register writes for configuration are only performed if the device has a i2c_client provided and also register as a platform driver. This allows the driver to be used to manage GPIO based control of the device. Signed-off-by: Jisheng Zhang Link: https://lore.kernel.org/r/20250825234509.1041-4-jszhang@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usb251xb.c | 108 +++++++++++++++++++++++++++++++----- 1 file changed, 95 insertions(+), 13 deletions(-) diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index cb2f946de42c..7c0778631bea 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -242,15 +243,19 @@ static int usb251xb_check_dev_children(struct device *dev, void *child) static int usb251x_check_gpio_chip(struct usb251xb *hub) { struct gpio_chip *gc = gpiod_to_chip(hub->gpio_reset); - struct i2c_adapter *adap = hub->i2c->adapter; + struct i2c_adapter *adap; int ret; + if (!hub->i2c) + return 0; + if (!hub->gpio_reset) return 0; if (!gc) return -EINVAL; + adap = hub->i2c->adapter; ret = usb251xb_check_dev_children(&adap->dev, gc->parent); if (ret) { dev_err(hub->dev, "Reset GPIO chip is at the same i2c-bus\n"); @@ -271,7 +276,8 @@ static void usb251xb_reset(struct usb251xb *hub) if (!hub->gpio_reset) return; - i2c_lock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); + if (hub->i2c) + i2c_lock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); gpiod_set_value_cansleep(hub->gpio_reset, 1); usleep_range(1, 10); /* >=1us RESET_N asserted */ @@ -280,7 +286,8 @@ static void usb251xb_reset(struct usb251xb *hub) /* wait for hub recovery/stabilization */ usleep_range(500, 750); /* >=500us after RESET_N deasserted */ - i2c_unlock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); + if (hub->i2c) + i2c_unlock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); } static int usb251xb_connect(struct usb251xb *hub) @@ -289,6 +296,12 @@ static int usb251xb_connect(struct usb251xb *hub) int err, i; char i2c_wb[USB251XB_I2C_REG_SZ]; + if (!hub->i2c) { + usb251xb_reset(hub); + dev_info(dev, "hub is put in default configuration.\n"); + return 0; + } + memset(i2c_wb, 0, USB251XB_I2C_REG_SZ); if (hub->skip_config) { @@ -698,18 +711,13 @@ static int usb251xb_i2c_probe(struct i2c_client *i2c) return usb251xb_probe(hub); } -static int usb251xb_suspend(struct device *dev) +static int usb251xb_suspend(struct usb251xb *hub) { - struct i2c_client *client = to_i2c_client(dev); - struct usb251xb *hub = i2c_get_clientdata(client); - return regulator_disable(hub->vdd); } -static int usb251xb_resume(struct device *dev) +static int usb251xb_resume(struct usb251xb *hub) { - struct i2c_client *client = to_i2c_client(dev); - struct usb251xb *hub = i2c_get_clientdata(client); int err; err = regulator_enable(hub->vdd); @@ -719,7 +727,23 @@ static int usb251xb_resume(struct device *dev) return usb251xb_connect(hub); } -static DEFINE_SIMPLE_DEV_PM_OPS(usb251xb_pm_ops, usb251xb_suspend, usb251xb_resume); +static int usb251xb_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb251xb *hub = i2c_get_clientdata(client); + + return usb251xb_suspend(hub); +} + +static int usb251xb_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb251xb *hub = i2c_get_clientdata(client); + + return usb251xb_resume(hub); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(usb251xb_i2c_pm_ops, usb251xb_i2c_suspend, usb251xb_i2c_resume); static const struct i2c_device_id usb251xb_id[] = { { "usb2422" }, @@ -739,13 +763,71 @@ static struct i2c_driver usb251xb_i2c_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = usb251xb_of_match, - .pm = pm_sleep_ptr(&usb251xb_pm_ops), + .pm = pm_sleep_ptr(&usb251xb_i2c_pm_ops), }, .probe = usb251xb_i2c_probe, .id_table = usb251xb_id, }; -module_i2c_driver(usb251xb_i2c_driver); +static int usb251xb_plat_probe(struct platform_device *pdev) +{ + struct usb251xb *hub; + + hub = devm_kzalloc(&pdev->dev, sizeof(*hub), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + platform_set_drvdata(pdev, hub); + hub->dev = &pdev->dev; + + return usb251xb_probe(hub); +} + +static int usb251xb_plat_suspend(struct device *dev) +{ + return usb251xb_suspend(dev_get_drvdata(dev)); +} + +static int usb251xb_plat_resume(struct device *dev) +{ + return usb251xb_resume(dev_get_drvdata(dev)); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(usb251xb_plat_pm_ops, usb251xb_plat_suspend, usb251xb_plat_resume); + +static struct platform_driver usb251xb_plat_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = usb251xb_of_match, + .pm = pm_sleep_ptr(&usb251xb_plat_pm_ops), + }, + .probe = usb251xb_plat_probe, +}; + +static int __init usb251xb_init(void) +{ + int err; + + err = i2c_add_driver(&usb251xb_i2c_driver); + if (err) + return err; + + err = platform_driver_register(&usb251xb_plat_driver); + if (err) { + i2c_del_driver(&usb251xb_i2c_driver); + return err; + } + + return 0; +} +module_init(usb251xb_init); + +static void __exit usb251xb_exit(void) +{ + platform_driver_unregister(&usb251xb_plat_driver); + i2c_del_driver(&usb251xb_i2c_driver); +} +module_exit(usb251xb_exit); MODULE_AUTHOR("Richard Leitner "); MODULE_DESCRIPTION("USB251x/xBi USB 2.0 Hub Controller Driver"); From 56429b4a37e710429e20a4f8dc85e96fcbb9f4b7 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 28 Aug 2025 21:55:53 -0400 Subject: [PATCH 0906/2711] cdns2: Remove unused tracepoints Tracepoints that are defined take up around 5K each, even if they are not used. If they are defined and not used, then they waste memory for unused code. Soon unused tracepoints will cause warnings. Remove the unused tracepoints of the cdns2 subsystem. They are: cdns2_ep0_enqueue cdns2_ep0_set_config cdns2_ep_queue cdns2_iso_out_ep_disable cdns2_lpm cdns2_mapped_request cdns2_map_request cdns2_may_wakeup Signed-off-by: Steven Rostedt (Google) Link: https://lore.kernel.org/r/20250829015649.885512884@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/cdns2/cdns2-trace.h | 69 ---------------------- 1 file changed, 69 deletions(-) diff --git a/drivers/usb/gadget/udc/cdns2/cdns2-trace.h b/drivers/usb/gadget/udc/cdns2/cdns2-trace.h index ade1752956b1..f4df0e2ff853 100644 --- a/drivers/usb/gadget/udc/cdns2/cdns2-trace.h +++ b/drivers/usb/gadget/udc/cdns2/cdns2-trace.h @@ -47,16 +47,6 @@ DEFINE_EVENT(cdns2_log_enable_disable, cdns2_pullup, TP_ARGS(set) ); -DEFINE_EVENT(cdns2_log_enable_disable, cdns2_lpm, - TP_PROTO(int set), - TP_ARGS(set) -); - -DEFINE_EVENT(cdns2_log_enable_disable, cdns2_may_wakeup, - TP_PROTO(int set), - TP_ARGS(set) -); - DECLARE_EVENT_CLASS(cdns2_log_simple, TP_PROTO(char *msg), TP_ARGS(msg), @@ -79,11 +69,6 @@ DEFINE_EVENT(cdns2_log_simple, cdns2_ep0_status_stage, TP_ARGS(msg) ); -DEFINE_EVENT(cdns2_log_simple, cdns2_ep0_set_config, - TP_PROTO(char *msg), - TP_ARGS(msg) -); - DEFINE_EVENT(cdns2_log_simple, cdns2_ep0_setup, TP_PROTO(char *msg), TP_ARGS(msg) @@ -340,11 +325,6 @@ DEFINE_EVENT(cdns2_log_request, cdns2_free_request, TP_ARGS(preq) ); -DEFINE_EVENT(cdns2_log_request, cdns2_ep_queue, - TP_PROTO(struct cdns2_request *preq), - TP_ARGS(preq) -); - DEFINE_EVENT(cdns2_log_request, cdns2_request_dequeue, TP_PROTO(struct cdns2_request *preq), TP_ARGS(preq) @@ -355,50 +335,6 @@ DEFINE_EVENT(cdns2_log_request, cdns2_request_giveback, TP_ARGS(preq) ); -TRACE_EVENT(cdns2_ep0_enqueue, - TP_PROTO(struct cdns2_device *dev_priv, struct usb_request *request), - TP_ARGS(dev_priv, request), - TP_STRUCT__entry( - __field(int, dir) - __field(int, length) - ), - TP_fast_assign( - __entry->dir = dev_priv->eps[0].dir; - __entry->length = request->length; - ), - TP_printk("Queue to ep0%s length: %u", __entry->dir ? "in" : "out", - __entry->length) -); - -DECLARE_EVENT_CLASS(cdns2_log_map_request, - TP_PROTO(struct cdns2_request *priv_req), - TP_ARGS(priv_req), - TP_STRUCT__entry( - __string(name, priv_req->pep->name) - __field(struct usb_request *, req) - __field(void *, buf) - __field(dma_addr_t, dma) - ), - TP_fast_assign( - __assign_str(name); - __entry->req = &priv_req->request; - __entry->buf = priv_req->request.buf; - __entry->dma = priv_req->request.dma; - ), - TP_printk("%s: req: %p, req buf %p, dma %p", - __get_str(name), __entry->req, __entry->buf, &__entry->dma - ) -); - -DEFINE_EVENT(cdns2_log_map_request, cdns2_map_request, - TP_PROTO(struct cdns2_request *req), - TP_ARGS(req) -); -DEFINE_EVENT(cdns2_log_map_request, cdns2_mapped_request, - TP_PROTO(struct cdns2_request *req), - TP_ARGS(req) -); - DECLARE_EVENT_CLASS(cdns2_log_trb, TP_PROTO(struct cdns2_endpoint *pep, struct cdns2_trb *trb), TP_ARGS(pep, trb), @@ -507,11 +443,6 @@ DEFINE_EVENT(cdns2_log_ep, cdns2_gadget_ep_disable, TP_ARGS(pep) ); -DEFINE_EVENT(cdns2_log_ep, cdns2_iso_out_ep_disable, - TP_PROTO(struct cdns2_endpoint *pep), - TP_ARGS(pep) -); - DEFINE_EVENT(cdns2_log_ep, cdns2_ep_busy_try_halt_again, TP_PROTO(struct cdns2_endpoint *pep), TP_ARGS(pep) From 1c15b2f88127d5980747f2f62beb6e1f6e62f883 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 28 Aug 2025 21:55:54 -0400 Subject: [PATCH 0907/2711] cdns3: Remove unused tracepoints Tracepoints that are defined take up around 5K each, even if they are not used. If they are defined and not used, then they waste memory for unused code. Soon unused tracepoints will cause warnings. Remove the unused tracepoints of the cdns3 subsystem. They are: cdns3_mapped_request cdns3_map_request cdns3_stream_transfer_split cdns3_stream_transfer_split_next_part Signed-off-by: Steven Rostedt (Google) Acked-by: Peter Chen Link: https://lore.kernel.org/r/20250829015650.053498355@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdns3-trace.h | 61 --------------------------------- 1 file changed, 61 deletions(-) diff --git a/drivers/usb/cdns3/cdns3-trace.h b/drivers/usb/cdns3/cdns3-trace.h index c4e542f1b9b7..21a6a2ce7a3d 100644 --- a/drivers/usb/cdns3/cdns3-trace.h +++ b/drivers/usb/cdns3/cdns3-trace.h @@ -283,39 +283,6 @@ TRACE_EVENT(cdns3_ep0_queue, __entry->length) ); -DECLARE_EVENT_CLASS(cdns3_stream_split_transfer_len, - TP_PROTO(struct cdns3_request *req), - TP_ARGS(req), - TP_STRUCT__entry( - __string(name, req->priv_ep->name) - __field(struct cdns3_request *, req) - __field(unsigned int, length) - __field(unsigned int, actual) - __field(unsigned int, stream_id) - ), - TP_fast_assign( - __assign_str(name); - __entry->req = req; - __entry->actual = req->request.length; - __entry->length = req->request.actual; - __entry->stream_id = req->request.stream_id; - ), - TP_printk("%s: req: %p,request length: %u actual length: %u SID: %u", - __get_str(name), __entry->req, __entry->length, - __entry->actual, __entry->stream_id) -); - -DEFINE_EVENT(cdns3_stream_split_transfer_len, cdns3_stream_transfer_split, - TP_PROTO(struct cdns3_request *req), - TP_ARGS(req) -); - -DEFINE_EVENT(cdns3_stream_split_transfer_len, - cdns3_stream_transfer_split_next_part, - TP_PROTO(struct cdns3_request *req), - TP_ARGS(req) -); - DECLARE_EVENT_CLASS(cdns3_log_aligned_request, TP_PROTO(struct cdns3_request *priv_req), TP_ARGS(priv_req), @@ -354,34 +321,6 @@ DEFINE_EVENT(cdns3_log_aligned_request, cdns3_prepare_aligned_request, TP_ARGS(req) ); -DECLARE_EVENT_CLASS(cdns3_log_map_request, - TP_PROTO(struct cdns3_request *priv_req), - TP_ARGS(priv_req), - TP_STRUCT__entry( - __string(name, priv_req->priv_ep->name) - __field(struct usb_request *, req) - __field(void *, buf) - __field(dma_addr_t, dma) - ), - TP_fast_assign( - __assign_str(name); - __entry->req = &priv_req->request; - __entry->buf = priv_req->request.buf; - __entry->dma = priv_req->request.dma; - ), - TP_printk("%s: req: %p, req buf %p, dma %p", - __get_str(name), __entry->req, __entry->buf, &__entry->dma - ) -); -DEFINE_EVENT(cdns3_log_map_request, cdns3_map_request, - TP_PROTO(struct cdns3_request *req), - TP_ARGS(req) -); -DEFINE_EVENT(cdns3_log_map_request, cdns3_mapped_request, - TP_PROTO(struct cdns3_request *req), - TP_ARGS(req) -); - DECLARE_EVENT_CLASS(cdns3_log_trb, TP_PROTO(struct cdns3_endpoint *priv_ep, struct cdns3_trb *trb), TP_ARGS(priv_ep, trb), From 9d4552da0ae8f056313cc290c0f493f59c6f7eef Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 28 Aug 2025 21:55:55 -0400 Subject: [PATCH 0908/2711] cdnsp: Remove unused tracepoints Tracepoints that are defined take up around 5K each, even if they are not used. If they are defined and not used, then they waste memory for unused code. Soon unused tracepoints will cause warnings. Remove the unused tracepoints of the cdnsp subsystem. They are: cdnsp_defered_event cdnsp_ep0_halted cdnsp_free_priv_device cdnsp_handle_cmd_flush_ep Signed-off-by: Steven Rostedt (Google) Acked-by: Peter Chen Link: https://lore.kernel.org/r/20250829015650.224063821@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdnsp-trace.h | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/drivers/usb/cdns3/cdnsp-trace.h b/drivers/usb/cdns3/cdnsp-trace.h index f2bcf77a5d0a..9b33a736c3de 100644 --- a/drivers/usb/cdns3/cdnsp-trace.h +++ b/drivers/usb/cdns3/cdnsp-trace.h @@ -178,11 +178,6 @@ DEFINE_EVENT(cdnsp_log_simple, cdnsp_ep0_set_config, TP_ARGS(msg) ); -DEFINE_EVENT(cdnsp_log_simple, cdnsp_ep0_halted, - TP_PROTO(char *msg), - TP_ARGS(msg) -); - DEFINE_EVENT(cdnsp_log_simple, cdnsp_ep_halt, TP_PROTO(char *msg), TP_ARGS(msg) @@ -399,11 +394,6 @@ DEFINE_EVENT(cdnsp_log_trb, cdnsp_cmd_timeout, TP_ARGS(ring, trb) ); -DEFINE_EVENT(cdnsp_log_trb, cdnsp_defered_event, - TP_PROTO(struct cdnsp_ring *ring, struct cdnsp_generic_trb *trb), - TP_ARGS(ring, trb) -); - DECLARE_EVENT_CLASS(cdnsp_log_pdev, TP_PROTO(struct cdnsp_device *pdev), TP_ARGS(pdev), @@ -433,16 +423,6 @@ DEFINE_EVENT(cdnsp_log_pdev, cdnsp_alloc_priv_device, TP_ARGS(vdev) ); -DEFINE_EVENT(cdnsp_log_pdev, cdnsp_free_priv_device, - TP_PROTO(struct cdnsp_device *vdev), - TP_ARGS(vdev) -); - -DEFINE_EVENT(cdnsp_log_pdev, cdnsp_setup_device, - TP_PROTO(struct cdnsp_device *vdev), - TP_ARGS(vdev) -); - DEFINE_EVENT(cdnsp_log_pdev, cdnsp_setup_addressable_priv_device, TP_PROTO(struct cdnsp_device *vdev), TP_ARGS(vdev) @@ -575,11 +555,6 @@ DEFINE_EVENT(cdnsp_log_ep_ctx, cdnsp_handle_cmd_stop_ep, TP_ARGS(ctx) ); -DEFINE_EVENT(cdnsp_log_ep_ctx, cdnsp_handle_cmd_flush_ep, - TP_PROTO(struct cdnsp_ep_ctx *ctx), - TP_ARGS(ctx) -); - DEFINE_EVENT(cdnsp_log_ep_ctx, cdnsp_handle_cmd_set_deq_ep, TP_PROTO(struct cdnsp_ep_ctx *ctx), TP_ARGS(ctx) From 1c208fd306f296a663d1edcced57bd8ef113eb74 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Tue, 2 Sep 2025 21:27:19 +0800 Subject: [PATCH 0909/2711] usb: host: xhci-tegra: Remove redundant ternary operators For ternary operators in the form of "a ? true : false", if 'a' itself returns a boolean result, the ternary operator can be omitted. Remove redundant ternary operators to clean up the code. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250902132720.85504-1-liaoyuanhong@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 0c7af44d4dae..460effa0e11e 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1482,7 +1482,7 @@ static int tegra_xhci_id_notify(struct notifier_block *nb, tegra->otg_usb2_port = tegra_xusb_get_usb2_port(tegra, usbphy); - tegra->host_mode = (usbphy->last_event == USB_EVENT_ID) ? true : false; + tegra->host_mode = usbphy->last_event == USB_EVENT_ID; schedule_work(&tegra->id_work); From e9c206324eeb213957a567a9d066bdeb355c7491 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 3 Sep 2025 22:16:13 +0800 Subject: [PATCH 0910/2711] usb: cdns3: cdnsp-pci: remove redundant pci_disable_device() call The cdnsp-pci driver uses pcim_enable_device() to enable a PCI device, which means the device will be automatically disabled on driver detach through the managed device framework. The manual pci_disable_device() call in the error path is therefore redundant. Found via static anlaysis and this is similar to commit 99ca0b57e49f ("thermal: intel: int340x: processor: Fix warning during module unload"). Fixes: 3d82904559f4 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Link: https://lore.kernel.org/r/20250903141613.2535472-1-linmq006@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdnsp-pci.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c index 8c361b8394e9..5e7b88ca8b96 100644 --- a/drivers/usb/cdns3/cdnsp-pci.c +++ b/drivers/usb/cdns3/cdnsp-pci.c @@ -85,7 +85,7 @@ static int cdnsp_pci_probe(struct pci_dev *pdev, cdnsp = kzalloc(sizeof(*cdnsp), GFP_KERNEL); if (!cdnsp) { ret = -ENOMEM; - goto disable_pci; + goto put_pci; } } @@ -168,9 +168,6 @@ free_cdnsp: if (!pci_is_enabled(func)) kfree(cdnsp); -disable_pci: - pci_disable_device(pdev); - put_pci: pci_dev_put(func); From 87c5ff5615dc0a37167e8faf3adeeddc6f1344a3 Mon Sep 17 00:00:00 2001 From: Chen Yufeng Date: Fri, 5 Sep 2025 17:48:42 +0800 Subject: [PATCH 0911/2711] usb: cdns3: gadget: Use-after-free during failed initialization and exit of cdnsp gadget In the __cdnsp_gadget_init() and cdnsp_gadget_exit() functions, the gadget structure (pdev->gadget) was freed before its endpoints. The endpoints are linked via the ep_list in the gadget structure. Freeing the gadget first leaves dangling pointers in the endpoint list. When the endpoints are subsequently freed, this results in a use-after-free. Fix: By separating the usb_del_gadget_udc() operation into distinct "del" and "put" steps, cdnsp_gadget_free_endpoints() can be executed prior to the final release of the gadget structure with usb_put_gadget(). A patch similar to bb9c74a5bd14("usb: dwc3: gadget: Free gadget structure only after freeing endpoints"). Signed-off-by: Chen Yufeng Link: https://lore.kernel.org/r/20250905094842.1232-1-chenyufeng@iie.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdnsp-gadget.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c index 55f95f41b3b4..0252560cbc80 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.c +++ b/drivers/usb/cdns3/cdnsp-gadget.c @@ -1976,7 +1976,10 @@ static int __cdnsp_gadget_init(struct cdns *cdns) return 0; del_gadget: - usb_del_gadget_udc(&pdev->gadget); + usb_del_gadget(&pdev->gadget); + cdnsp_gadget_free_endpoints(pdev); + usb_put_gadget(&pdev->gadget); + goto halt_pdev; free_endpoints: cdnsp_gadget_free_endpoints(pdev); halt_pdev: @@ -1998,8 +2001,9 @@ static void cdnsp_gadget_exit(struct cdns *cdns) devm_free_irq(pdev->dev, cdns->dev_irq, pdev); pm_runtime_mark_last_busy(cdns->dev); pm_runtime_put_autosuspend(cdns->dev); - usb_del_gadget_udc(&pdev->gadget); + usb_del_gadget(&pdev->gadget); cdnsp_gadget_free_endpoints(pdev); + usb_put_gadget(&pdev->gadget); cdnsp_mem_cleanup(pdev); kfree(pdev); cdns->gadget_dev = NULL; From 1bc28f015a19a10b7a305fc561c1143c34a1e04a Mon Sep 17 00:00:00 2001 From: Venkat Jayaraman Date: Fri, 5 Sep 2025 11:44:01 -0700 Subject: [PATCH 0912/2711] usb: typec: ucsi: Add check for UCSI version "Power Reading" bit is introduced in UCSI v2.1 and so limit the check for that bit only if version supported is 2.1 or above. Fixes: c851b71fd6cd ("usb: typec: ucsi: Add support for READ_POWER_LEVEL command") Signed-off-by: Venkat Jayaraman Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20250905184401.3222530-1-venkat.jayaraman@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 0d6b0cf5a7cd..3f568f790f39 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1293,7 +1293,8 @@ static void ucsi_handle_connector_change(struct work_struct *work) if (change & UCSI_CONSTAT_BC_CHANGE) ucsi_port_psy_changed(con); - if (UCSI_CONSTAT(con, PWR_READING_READY_V2_1)) { + if (con->ucsi->version >= UCSI_VERSION_2_1 && + UCSI_CONSTAT(con, PWR_READING_READY_V2_1)) { curr_scale = UCSI_CONSTAT(con, CURRENT_SCALE_V2_1); volt_scale = UCSI_CONSTAT(con, VOLTAGE_SCALE_V2_1); From 970076537efd847c6f74ba9ed888b9cdbf71206e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 20 Aug 2025 17:38:16 +0300 Subject: [PATCH 0913/2711] usb: core: Use le16_to_cpu() to read __le16 value in usb_parse_endpoint() wMaxPacketSize field in struct usb_endpoint_descriptor is an __le16, use le16_to_cpu() to read it. Signed-off-by: Sakari Ailus Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250820143824.551777-2-sakari.ailus@linux.intel.com --- drivers/usb/core/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 42468bbeffd2..cda595b4014f 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -507,7 +507,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, } /* Parse a possible eUSB2 periodic endpoint companion descriptor */ - if (bcdUSB == 0x0220 && d->wMaxPacketSize == 0 && + if (bcdUSB == 0x0220 && !le16_to_cpu(d->wMaxPacketSize) && (usb_endpoint_xfer_isoc(d) || usb_endpoint_xfer_int(d))) usb_parse_eusb2_isoc_endpoint_companion(ddev, cfgno, inum, asnum, endpoint, buffer, size); From 030ab58b075c04b5286d2787860373dcc30020c6 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 20 Aug 2025 17:38:17 +0300 Subject: [PATCH 0914/2711] usb: core: Parse eUSB2 companion descriptors for high speed devices only Check that a device is a high-speed one before proceeding to parse the eUSB2 isochronous endpoint companion descriptors. Signed-off-by: Sakari Ailus Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250820143824.551777-3-sakari.ailus@linux.intel.com --- drivers/usb/core/config.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index cda595b4014f..29fcbd6de482 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -507,7 +507,8 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, } /* Parse a possible eUSB2 periodic endpoint companion descriptor */ - if (bcdUSB == 0x0220 && !le16_to_cpu(d->wMaxPacketSize) && + if (udev->speed == USB_SPEED_HIGH && bcdUSB == 0x0220 && + !le16_to_cpu(d->wMaxPacketSize) && (usb_endpoint_xfer_isoc(d) || usb_endpoint_xfer_int(d))) usb_parse_eusb2_isoc_endpoint_companion(ddev, cfgno, inum, asnum, endpoint, buffer, size); From 53d76c6866a0362320b837dd292db4befcac31ba Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 20 Aug 2025 17:38:18 +0300 Subject: [PATCH 0915/2711] usb: core: eUSB2 companion descriptor is for isoc IN endpoints only The eUSB2 isochronous double bandwidth endpoint descriptor is allowed for the isochronous IN endpoints, according to the ECN. Do not parse these descriptors if they are found in interrupt or OUT endpoints. Signed-off-by: Sakari Ailus Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250820143824.551777-4-sakari.ailus@linux.intel.com --- drivers/usb/core/config.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 29fcbd6de482..baf5bc844b6f 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -508,8 +508,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, /* Parse a possible eUSB2 periodic endpoint companion descriptor */ if (udev->speed == USB_SPEED_HIGH && bcdUSB == 0x0220 && - !le16_to_cpu(d->wMaxPacketSize) && - (usb_endpoint_xfer_isoc(d) || usb_endpoint_xfer_int(d))) + !le16_to_cpu(d->wMaxPacketSize) && usb_endpoint_is_isoc_in(d)) usb_parse_eusb2_isoc_endpoint_companion(ddev, cfgno, inum, asnum, endpoint, buffer, size); From 20f988320d2718ef28b1f0635acc88c12a216d29 Mon Sep 17 00:00:00 2001 From: "Rai, Amardeep" Date: Wed, 20 Aug 2025 17:38:19 +0300 Subject: [PATCH 0916/2711] usb: core: Add a function to get USB version independent periodic payload Add usb_endpoint_max_periodic_payload() to obtain maximum payload bytes in a service interval for isochronous and interrupt endpoints in a USB version independent way. Signed-off-by: Rai, Amardeep Signed-off-by: Mathias Nyman Co-developed-by: Sakari Ailus Signed-off-by: Sakari Ailus Reviewed-by: Hans de Goede Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250820143824.551777-5-sakari.ailus@linux.intel.com --- drivers/usb/core/usb.c | 29 +++++++++++++++++++++++++++++ include/linux/usb.h | 3 +++ 2 files changed, 32 insertions(+) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index fca7735fc660..ca9ff6ad8e73 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1110,6 +1110,35 @@ void usb_free_noncoherent(struct usb_device *dev, size_t size, } EXPORT_SYMBOL_GPL(usb_free_noncoherent); +/** + * usb_endpoint_max_periodic_payload - Get maximum payload bytes per service + * interval + * @udev: The USB device + * @ep: The endpoint + * + * Returns: the maximum number of bytes isochronous or interrupt endpoint @ep + * can transfer during a service interval, or 0 for other endpoints. + */ +u32 usb_endpoint_max_periodic_payload(struct usb_device *udev, + const struct usb_host_endpoint *ep) +{ + if (!usb_endpoint_xfer_isoc(&ep->desc) && + !usb_endpoint_xfer_int(&ep->desc)) + return 0; + + switch (udev->speed) { + case USB_SPEED_SUPER_PLUS: + if (USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) + return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval); + fallthrough; + case USB_SPEED_SUPER: + return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); + default: + return usb_endpoint_maxp(&ep->desc) * usb_endpoint_maxp_mult(&ep->desc); + } +} +EXPORT_SYMBOL_GPL(usb_endpoint_max_periodic_payload); + /* * Notifications of device and interface registration */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 9d662c6abb4d..e9cf2786d8bd 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -2039,6 +2039,9 @@ static inline u16 usb_maxpacket(struct usb_device *udev, int pipe) return usb_endpoint_maxp(&ep->desc); } +u32 usb_endpoint_max_periodic_payload(struct usb_device *udev, + const struct usb_host_endpoint *ep); + /* translate USB error codes to codes user space understands */ static inline int usb_translate_errors(int error_code) { From 24b8762e05ed8203dc0b76b62c802aadd487e9aa Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 20 Aug 2025 17:38:20 +0300 Subject: [PATCH 0917/2711] usb: xhci: Use usb_endpoint_max_periodic_payload() Use the newly added usb_endpoint_max_periodic_payload() to obtain the maximum number of bytes to transfer during a service interval for isochronous and interrupt endpoints. This will replace the xhci-specific xhci_get_max_esit_payload() which is removed as redundant. Signed-off-by: Sakari Ailus Reviewed-by: Mathias Nyman Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250820143824.551777-6-sakari.ailus@linux.intel.com --- drivers/usb/host/xhci-mem.c | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 07289333a1e8..d2c04811191f 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1378,36 +1378,6 @@ static u32 xhci_get_endpoint_type(struct usb_host_endpoint *ep) return 0; } -/* Return the maximum endpoint service interval time (ESIT) payload. - * Basically, this is the maxpacket size, multiplied by the burst size - * and mult size. - */ -static u32 xhci_get_max_esit_payload(struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - int max_burst; - int max_packet; - - /* Only applies for interrupt or isochronous endpoints */ - if (usb_endpoint_xfer_control(&ep->desc) || - usb_endpoint_xfer_bulk(&ep->desc)) - return 0; - - /* SuperSpeedPlus Isoc ep sending over 48k per esit */ - if ((udev->speed >= USB_SPEED_SUPER_PLUS) && - USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) - return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval); - - /* SuperSpeed or SuperSpeedPlus Isoc ep with less than 48k per esit */ - if (udev->speed >= USB_SPEED_SUPER) - return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); - - max_packet = usb_endpoint_maxp(&ep->desc); - max_burst = usb_endpoint_maxp_mult(&ep->desc); - /* A 0 in max burst means 1 transfer per ESIT */ - return max_packet * max_burst; -} - /* Set up an endpoint with one ring segment. Do not allocate stream rings. * Drivers will have to call usb_alloc_streams() to do that. */ @@ -1445,7 +1415,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, * have no clue on scatter gather list entry size. For Isoc and Int, * set it to max available. See xHCI 1.1 spec 4.14.1.1 for details. */ - max_esit_payload = xhci_get_max_esit_payload(udev, ep); + max_esit_payload = usb_endpoint_max_periodic_payload(udev, ep); interval = xhci_get_endpoint_interval(udev, ep); /* Periodic endpoint bInterval limit quirk */ From d6725169a9bbcb5bd1dd14b2891b874614c59f52 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 20 Aug 2025 17:38:21 +0300 Subject: [PATCH 0918/2711] usb: core: Introduce usb_endpoint_is_hs_isoc_double() Introduce usb_endpoint_is_hs_isoc_double() tell whether an endpoint conforms to USB 2.0 Isochronous Double IN Bandwidth ECN. Signed-off-by: Sakari Ailus Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250820143824.551777-7-sakari.ailus@linux.intel.com --- drivers/usb/core/usb.c | 19 +++++++++++++++++++ include/linux/usb.h | 3 +++ 2 files changed, 22 insertions(+) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index ca9ff6ad8e73..939dc4aafb89 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1139,6 +1139,25 @@ u32 usb_endpoint_max_periodic_payload(struct usb_device *udev, } EXPORT_SYMBOL_GPL(usb_endpoint_max_periodic_payload); +/** + * usb_endpoint_is_hs_isoc_double - Tell whether an endpoint uses USB 2 + * Isochronous Double IN Bandwidth + * @udev: The USB device + * @ep: The endpoint + * + * Returns: true if an endpoint @ep conforms to USB 2 Isochronous Double IN + * Bandwidth ECN, false otherwise. + */ +bool usb_endpoint_is_hs_isoc_double(struct usb_device *udev, + const struct usb_host_endpoint *ep) +{ + return ep->eusb2_isoc_ep_comp.bDescriptorType && + le16_to_cpu(udev->descriptor.bcdUSB) == 0x220 && + usb_endpoint_is_isoc_in(&ep->desc) && + !le16_to_cpu(ep->desc.wMaxPacketSize); +} +EXPORT_SYMBOL_GPL(usb_endpoint_is_hs_isoc_double); + /* * Notifications of device and interface registration */ diff --git a/include/linux/usb.h b/include/linux/usb.h index e9cf2786d8bd..70ef00c42d22 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -2042,6 +2042,9 @@ static inline u16 usb_maxpacket(struct usb_device *udev, int pipe) u32 usb_endpoint_max_periodic_payload(struct usb_device *udev, const struct usb_host_endpoint *ep); +bool usb_endpoint_is_hs_isoc_double(struct usb_device *udev, + const struct usb_host_endpoint *ep); + /* translate USB error codes to codes user space understands */ static inline int usb_translate_errors(int error_code) { From 0c670dc882d31f0423f18899c0e594547b55b76d Mon Sep 17 00:00:00 2001 From: "Rai, Amardeep" Date: Wed, 20 Aug 2025 17:38:22 +0300 Subject: [PATCH 0919/2711] usb: xhci: Add host support for eUSB2 double isochronous bandwidth devices Detect eUSB2 double isoc bw capable hosts and devices, and set the proper xhci endpoint context values such as 'Mult', 'Max Burst Size', and 'Max ESIT Payload' to enable the double isochronous bandwidth endpoints. Intel xHC uses the endpoint context 'Mult' field for eUSB2 isoc endpoints even if hosts supporting Large ESIT Payload Capability should normally ignore the mult field. Signed-off-by: Rai, Amardeep Co-developed-by: Kannappan R Signed-off-by: Kannappan R Reviewed-by: Sakari Ailus Co-developed-by: Mathias Nyman Signed-off-by: Mathias Nyman Co-developed-by: Sakari Ailus Signed-off-by: Sakari Ailus Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250820143824.551777-8-sakari.ailus@linux.intel.com --- drivers/usb/host/xhci-caps.h | 2 ++ drivers/usb/host/xhci-mem.c | 53 +++++++++++++++++++++++++++--------- drivers/usb/host/xhci-ring.c | 6 ++-- drivers/usb/host/xhci.c | 16 ++++++++++- drivers/usb/host/xhci.h | 2 ++ 5 files changed, 62 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/xhci-caps.h b/drivers/usb/host/xhci-caps.h index 4b8ff4815644..89bc83e4f1eb 100644 --- a/drivers/usb/host/xhci-caps.h +++ b/drivers/usb/host/xhci-caps.h @@ -89,3 +89,5 @@ #define HCC2_GSC(p) ((p) & (1 << 8)) /* true: HC support Virtualization Based Trusted I/O Capability */ #define HCC2_VTC(p) ((p) & (1 << 9)) +/* true: HC support Double BW on a eUSB2 HS ISOC EP */ +#define HCC2_EUSB2_DIC(p) ((p) & (1 << 11)) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d2c04811191f..78ddcc6761ac 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1330,18 +1330,33 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev, return interval; } -/* The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps. +/* + * xHCs without LEC use the "Mult" field in the endpoint context for SuperSpeed + * isoc eps, and High speed isoc eps that support bandwidth doubling. Standard * High speed endpoint descriptors can define "the number of additional * transaction opportunities per microframe", but that goes in the Max Burst * endpoint context field. */ -static u32 xhci_get_endpoint_mult(struct usb_device *udev, - struct usb_host_endpoint *ep) +static u32 xhci_get_endpoint_mult(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_host_endpoint *ep) { - if (udev->speed < USB_SPEED_SUPER || - !usb_endpoint_xfer_isoc(&ep->desc)) - return 0; - return ep->ss_ep_comp.bmAttributes; + bool lec; + + /* xHCI 1.1 with LEC set does not use mult field, except intel eUSB2 */ + lec = xhci->hci_version > 0x100 && HCC2_LEC(xhci->hcc_params2); + + /* eUSB2 double isoc bw devices are the only USB2 devices using mult */ + if (usb_endpoint_is_hs_isoc_double(udev, ep) && + (!lec || xhci->quirks & XHCI_INTEL_HOST)) + return 1; + + /* SuperSpeed isoc transfers on hosts without LEC uses mult field */ + if (udev->speed >= USB_SPEED_SUPER && + usb_endpoint_xfer_isoc(&ep->desc) && !lec) + return ep->ss_ep_comp.bmAttributes; + + return 0; } static u32 xhci_get_endpoint_max_burst(struct usb_device *udev, @@ -1353,8 +1368,16 @@ static u32 xhci_get_endpoint_max_burst(struct usb_device *udev, if (udev->speed == USB_SPEED_HIGH && (usb_endpoint_xfer_isoc(&ep->desc) || - usb_endpoint_xfer_int(&ep->desc))) + usb_endpoint_xfer_int(&ep->desc))) { + /* + * USB 2 Isochronous Double IN Bandwidth ECN uses fixed burst + * size and max packets bits 12:11 are invalid. + */ + if (usb_endpoint_is_hs_isoc_double(udev, ep)) + return 2; + return usb_endpoint_maxp_mult(&ep->desc) - 1; + } return 0; } @@ -1409,6 +1432,13 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, ring_type = usb_endpoint_type(&ep->desc); + /* Ensure host supports double isoc bandwidth for eUSB2 devices */ + if (usb_endpoint_is_hs_isoc_double(udev, ep) && + !HCC2_EUSB2_DIC(xhci->hcc_params2)) { + dev_dbg(&udev->dev, "Double Isoc Bandwidth not supported by xhci\n"); + return -EINVAL; + } + /* * Get values to fill the endpoint context, mostly from ep descriptor. * The average TRB buffer lengt for bulk endpoints is unclear as we @@ -1432,8 +1462,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, } } - mult = xhci_get_endpoint_mult(udev, ep); - max_packet = usb_endpoint_maxp(&ep->desc); + mult = xhci_get_endpoint_mult(xhci, udev, ep); + max_packet = xhci_usb_endpoint_maxp(udev, ep); max_burst = xhci_get_endpoint_max_burst(udev, ep); avg_trb_len = max_esit_payload; @@ -1454,9 +1484,6 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, /* xHCI 1.0 and 1.1 indicates that ctrl ep avg TRB Length should be 8 */ if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100) avg_trb_len = 8; - /* xhci 1.1 with LEC support doesn't use mult field, use RsvdZ */ - if ((xhci->hci_version > 0x100) && HCC2_LEC(xhci->hcc_params2)) - mult = 0; /* Set up the endpoint ring */ virt_dev->eps[ep_index].new_ring = diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ecd757d482c5..ed2fa2c15535 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3545,7 +3545,7 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, if ((xhci->quirks & XHCI_MTK_HOST) && (xhci->hci_version < 0x100)) trb_buff_len = 0; - maxp = usb_endpoint_maxp(&urb->ep->desc); + maxp = xhci_usb_endpoint_maxp(urb->dev, urb->ep); total_packet_count = DIV_ROUND_UP(td_total_len, maxp); /* Queueing functions don't count the current TRB into transferred */ @@ -3562,7 +3562,7 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len, u32 new_buff_len; size_t len; - max_pkt = usb_endpoint_maxp(&urb->ep->desc); + max_pkt = xhci_usb_endpoint_maxp(urb->dev, urb->ep); unalign = (enqd_len + *trb_buff_len) % max_pkt; /* we got lucky, last normal TRB data on segment is packet aligned */ @@ -4133,7 +4133,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, addr = start_addr + urb->iso_frame_desc[i].offset; td_len = urb->iso_frame_desc[i].length; td_remain_len = td_len; - max_pkt = usb_endpoint_maxp(&urb->ep->desc); + max_pkt = xhci_usb_endpoint_maxp(urb->dev, urb->ep); total_pkt_count = DIV_ROUND_UP(td_len, max_pkt); /* A zero-length transfer still involves at least one packet. */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 47151ca527bf..e193d4dc414c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1334,7 +1334,7 @@ static bool xhci_urb_temp_buffer_required(struct usb_hcd *hcd, struct scatterlist *tail_sg; tail_sg = urb->sg; - max_pkt = usb_endpoint_maxp(&urb->ep->desc); + max_pkt = xhci_usb_endpoint_maxp(urb->dev, urb->ep); if (!urb->num_sgs) return ret; @@ -2922,6 +2922,20 @@ out: } EXPORT_SYMBOL_GPL(xhci_stop_endpoint_sync); +/* + * xhci_usb_endpoint_maxp - get endpoint max packet size + * @host_ep: USB host endpoint to be checked + * + * Returns max packet from the correct descriptor + */ +int xhci_usb_endpoint_maxp(struct usb_device *udev, + struct usb_host_endpoint *host_ep) +{ + if (usb_endpoint_is_hs_isoc_double(udev, host_ep)) + return le16_to_cpu(host_ep->eusb2_isoc_ep_comp.wMaxPacketSize); + return usb_endpoint_maxp(&host_ep->desc); +} + /* Issue a configure endpoint command or evaluate context command * and wait for it to finish. */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a20f4e7cd43a..2721f700c022 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1957,6 +1957,8 @@ void xhci_update_erst_dequeue(struct xhci_hcd *xhci, struct xhci_interrupter *ir, bool clear_ehb); void xhci_add_interrupter(struct xhci_hcd *xhci, unsigned int intr_num); +int xhci_usb_endpoint_maxp(struct usb_device *udev, + struct usb_host_endpoint *host_ep); /* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port, From 0666a012d25051d6d2b4e6b2c893e2f074b87d91 Mon Sep 17 00:00:00 2001 From: "Rai, Amardeep" Date: Wed, 20 Aug 2025 17:38:23 +0300 Subject: [PATCH 0920/2711] usb: core: support eUSB2 double bandwidth large isoc URB frames eUSB2 double isochronous in bandwidth devices support up to 6 transactions per microframe, and thus doubles the total bytes possible to receive per microframe. Support larger URB isoc frame sizes for eUSB2 double isoc in endpoints. Also usb_endpoint_maxp() returns a natural number so there's no need to assume it could be < 0. Signed-off-by: Rai, Amardeep Reviewed-by: Sakari Ailus Signed-off-by: Mathias Nyman Co-developed-by: Sakari Ailus Signed-off-by: Sakari Ailus Acked-by: Alan Stern Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250820143824.551777-9-sakari.ailus@linux.intel.com --- drivers/usb/core/urb.c | 14 ++++++++++---- drivers/usb/core/usb.c | 2 ++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 7a76d5a62db1..ff8df16cca35 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -372,6 +372,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) struct usb_host_endpoint *ep; int is_out; unsigned int allowed; + bool is_eusb2_isoch_double; if (!urb || !urb->complete) return -EINVAL; @@ -434,7 +435,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) return -ENODEV; max = usb_endpoint_maxp(&ep->desc); - if (max <= 0) { + is_eusb2_isoch_double = usb_endpoint_is_hs_isoc_double(dev, ep); + if (!max && !is_eusb2_isoch_double) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", usb_endpoint_num(&ep->desc), is_out ? "out" : "in", @@ -467,9 +469,13 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) max = le32_to_cpu(isoc_ep_comp->dwBytesPerInterval); } - /* "high bandwidth" mode, 1-3 packets/uframe? */ - if (dev->speed == USB_SPEED_HIGH) - max *= usb_endpoint_maxp_mult(&ep->desc); + /* High speed, 1-3 packets/uframe, max 6 for eUSB2 double bw */ + if (dev->speed == USB_SPEED_HIGH) { + if (is_eusb2_isoch_double) + max = le32_to_cpu(ep->eusb2_isoc_ep_comp.dwBytesPerInterval); + else + max *= usb_endpoint_maxp_mult(&ep->desc); + } if (urb->number_of_packets <= 0) return -EINVAL; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 939dc4aafb89..b88b6271cb30 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1134,6 +1134,8 @@ u32 usb_endpoint_max_periodic_payload(struct usb_device *udev, case USB_SPEED_SUPER: return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); default: + if (usb_endpoint_is_hs_isoc_double(udev, ep)) + return le32_to_cpu(ep->eusb2_isoc_ep_comp.dwBytesPerInterval); return usb_endpoint_maxp(&ep->desc) * usb_endpoint_maxp_mult(&ep->desc); } } From 0aa0b0326cc5642e97af968d21cbd8836368b707 Mon Sep 17 00:00:00 2001 From: Tao Q Tao Date: Wed, 20 Aug 2025 17:38:24 +0300 Subject: [PATCH 0921/2711] media: uvcvideo: eUSB2 double isochronous bandwidth support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use usb_endpoint_max_esit_payload() from the USB framework to find the maximum bytes per interval for the endpoint. Consequently this adds eUSB2 isochronous mode and SuperSpeedPlus Isochronous Endpoint Companion support where larger payloads within a service interval are possible. Co-developed-by: Amardeep Rai Signed-off-by: Amardeep Rai Signed-off-by: Tao Q Tao Signed-off-by: Mathias Nyman Co-developed-by: Sakari Ailus Signed-off-by: Sakari Ailus Reviewed-by: Ilpo Järvinen Reviewed-by: Laurent Pinchart Reviewed-by: Ricardo Ribalda Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250820143824.551777-10-sakari.ailus@linux.intel.com --- drivers/media/usb/uvc/uvc_driver.c | 4 ++-- drivers/media/usb/uvc/uvc_video.c | 24 +++--------------------- drivers/media/usb/uvc/uvcvideo.h | 4 +--- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 775bede0d93d..d06ca79ae2d9 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -539,7 +539,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, unsigned int nformats = 0, nframes = 0, nintervals = 0; unsigned int size, i, n, p; u32 *interval; - u16 psize; + u32 psize; int ret = -EINVAL; if (intf->cur_altsetting->desc.bInterfaceSubClass @@ -775,7 +775,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, streaming->header.bEndpointAddress); if (ep == NULL) continue; - psize = uvc_endpoint_max_bpi(dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(dev->udev, ep); if (psize > streaming->maxpsize) streaming->maxpsize = psize; } diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index a5013a7fbca4..1a0cc937de9b 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1869,24 +1869,6 @@ static void uvc_video_stop_transfer(struct uvc_streaming *stream, uvc_free_urb_buffers(stream); } -/* - * Compute the maximum number of bytes per interval for an endpoint. - */ -u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep) -{ - u16 psize; - - switch (dev->speed) { - case USB_SPEED_SUPER: - case USB_SPEED_SUPER_PLUS: - return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); - default: - psize = usb_endpoint_maxp(&ep->desc); - psize *= usb_endpoint_maxp_mult(&ep->desc); - return psize; - } -} - /* * Initialize isochronous URBs and allocate transfer buffers. The packet size * is given by the endpoint. @@ -1897,10 +1879,10 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, struct urb *urb; struct uvc_urb *uvc_urb; unsigned int npackets, i; - u16 psize; + u32 psize; u32 size; - psize = uvc_endpoint_max_bpi(stream->dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(stream->dev->udev, ep); size = stream->ctrl.dwMaxVideoFrameSize; npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags); @@ -2043,7 +2025,7 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, continue; /* Check if the bandwidth is high enough. */ - psize = uvc_endpoint_max_bpi(stream->dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(stream->dev->udev, ep); if (psize >= bandwidth && psize < best_psize) { altsetting = alts->desc.bAlternateSetting; best_psize = psize; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 757254fc4fe9..ac19ca721f29 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -456,7 +456,7 @@ struct uvc_streaming { struct usb_interface *intf; int intfnum; - u16 maxpsize; + u32 maxpsize; struct uvc_streaming_header header; enum v4l2_buf_type type; @@ -798,8 +798,6 @@ void uvc_ctrl_cleanup_fh(struct uvc_fh *handle); /* Utility functions */ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, u8 epaddr); -u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep); - /* Quirks support */ void uvc_video_decode_isight(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, From 6f9871b3e8c31953978db552c730a7e017e51d19 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Tue, 2 Sep 2025 21:26:08 +0800 Subject: [PATCH 0922/2711] usb: gadget: tegra-xudc: Remove redundant ternary operators For ternary operators in the form of "a ? true : false", if 'a' itself returns a boolean result, the ternary operator can be omitted. Remove redundant ternary operators to clean up the code. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250902132613.84876-1-liaoyuanhong@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/tegra-xudc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 1d3085cc9d22..0c38fc37b6e6 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -812,8 +812,7 @@ static void tegra_xudc_update_data_role(struct tegra_xudc *xudc, return; } - xudc->device_mode = (usbphy->last_event == USB_EVENT_VBUS) ? true : - false; + xudc->device_mode = usbphy->last_event == USB_EVENT_VBUS; phy_index = tegra_xudc_get_phy_index(xudc, usbphy); dev_dbg(xudc->dev, "%s(): current phy index is %d\n", __func__, From 18656ee86fe898932fdfbe5db4a92330ac95fa23 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader Date: Fri, 22 Aug 2025 11:56:13 +0200 Subject: [PATCH 0923/2711] serial: 8250_core: fix coding style issue Fix a coding style issue in 8250_core.c: - Remove redundant NULL initialization of a global pointer Signed-off-by: Osama Abdelkader Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/20250822095614.18108-1-osama.abdelkader@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 7d931693b311..bfa421ab3253 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -302,7 +302,7 @@ static void univ8250_release_irq(struct uart_8250_port *up) serial_unlink_irq_chain(up); } -const struct uart_ops *univ8250_port_base_ops = NULL; +const struct uart_ops *univ8250_port_base_ops; struct uart_ops univ8250_port_ops; static const struct uart_8250_ops univ8250_driver_ops = { From cc4d900d0d6d8dd5c41832a93ff3cfa629a78f9a Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Fri, 22 Aug 2025 16:19:23 +0200 Subject: [PATCH 0924/2711] serial: stm32: allow selecting console when the driver is module Console can be enabled on the UART compile as module. Change dependency to allow console mode when the driver is built as module. Fixes: 48a6092fb41fa ("serial: stm32-usart: Add STM32 USART Driver") Cc: stable@vger.kernel.org Signed-off-by: Raphael Gallais-Pou Link: https://lore.kernel.org/r/20250822141923.61133-1-raphael.gallais-pou@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index e661f5951f55..1e27a822c1cb 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1420,7 +1420,7 @@ config SERIAL_STM32 config SERIAL_STM32_CONSOLE bool "Support for console on STM32" - depends on SERIAL_STM32=y + depends on SERIAL_STM32 select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON From 23743ba64709a9c137c1b928f8b8e00d846af9cc Mon Sep 17 00:00:00 2001 From: Calixte Pernot Date: Mon, 25 Aug 2025 14:56:09 +0200 Subject: [PATCH 0925/2711] vt: add support for smput/rmput escape codes Support "\e[?1049h" and "\e[?1049l" escape codes. This patch allows programs to enter and leave alternate screens. This feature is widely available in graphical terminal emulators and mostly used by fullscreen terminal-based user interfaces such as text editors. Most editors such as vim and nano assume this escape code in not supported and will not try to print the escape sequence if TERM=linux. To try out this patch, run `TERM=xterm-256color vim` inside a VT. Signed-off-by: Calixte Pernot Link: https://lore.kernel.org/r/20250825125607.2478-3-calixte.pernot@grenoble-inp.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 58 ++++++++++++++++++++++++++++++++++ include/linux/console_struct.h | 3 ++ 2 files changed, 61 insertions(+) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 869261141535..3f80e98e5c51 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -141,6 +141,7 @@ static const struct consw *con_driver_map[MAX_NR_CONSOLES]; static int con_open(struct tty_struct *, struct file *); static void vc_init(struct vc_data *vc, int do_clear); static void gotoxy(struct vc_data *vc, int new_x, int new_y); +static void restore_cur(struct vc_data *vc); static void save_cur(struct vc_data *vc); static void reset_terminal(struct vc_data *vc, int do_clear); static void con_flush_chars(struct tty_struct *tty); @@ -1341,6 +1342,10 @@ struct vc_data *vc_deallocate(unsigned int currcons) kfree(vc->vc_screenbuf); vc_cons[currcons].d = NULL; } + if (vc->vc_saved_screen != NULL) { + kfree(vc->vc_saved_screen); + vc->vc_saved_screen = NULL; + } return vc; } @@ -1875,6 +1880,45 @@ static int get_bracketed_paste(struct tty_struct *tty) return vc->vc_bracketed_paste; } +/* console_lock is held */ +static void enter_alt_screen(struct vc_data *vc) +{ + unsigned int size = vc->vc_rows * vc->vc_cols * 2; + + if (vc->vc_saved_screen != NULL) + return; /* Already inside an alt-screen */ + vc->vc_saved_screen = kmemdup((u16 *)vc->vc_origin, size, GFP_KERNEL); + if (vc->vc_saved_screen == NULL) + return; + vc->vc_saved_rows = vc->vc_rows; + vc->vc_saved_cols = vc->vc_cols; + save_cur(vc); + /* clear entire screen */ + csi_J(vc, CSI_J_FULL); +} + +/* console_lock is held */ +static void leave_alt_screen(struct vc_data *vc) +{ + unsigned int rows = min(vc->vc_saved_rows, vc->vc_rows); + unsigned int cols = min(vc->vc_saved_cols, vc->vc_cols); + u16 *src, *dest; + + if (vc->vc_saved_screen == NULL) + return; /* Not inside an alt-screen */ + for (unsigned int r = 0; r < rows; r++) { + src = vc->vc_saved_screen + r * vc->vc_saved_cols; + dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols; + memcpy(dest, src, 2 * cols); + } + restore_cur(vc); + /* Update the entire screen */ + if (con_should_update(vc)) + do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); + kfree(vc->vc_saved_screen); + vc->vc_saved_screen = NULL; +} + enum { CSI_DEC_hl_CURSOR_KEYS = 1, /* CKM: cursor keys send ^[Ox/^[[x */ CSI_DEC_hl_132_COLUMNS = 3, /* COLM: 80/132 mode switch */ @@ -1885,6 +1929,7 @@ enum { CSI_DEC_hl_MOUSE_X10 = 9, CSI_DEC_hl_SHOW_CURSOR = 25, /* TCEM */ CSI_DEC_hl_MOUSE_VT200 = 1000, + CSI_DEC_hl_ALT_SCREEN = 1049, CSI_DEC_hl_BRACKETED_PASTE = 2004, }; @@ -1941,6 +1986,12 @@ static void csi_DEC_hl(struct vc_data *vc, bool on_off) case CSI_DEC_hl_BRACKETED_PASTE: vc->vc_bracketed_paste = on_off; break; + case CSI_DEC_hl_ALT_SCREEN: + if (on_off) + enter_alt_screen(vc); + else + leave_alt_screen(vc); + break; } } @@ -2179,6 +2230,13 @@ static void reset_terminal(struct vc_data *vc, int do_clear) vc->vc_deccm = global_cursor_default; vc->vc_decim = 0; + if (vc->vc_saved_screen != NULL) { + kfree(vc->vc_saved_screen); + vc->vc_saved_screen = NULL; + vc->vc_saved_rows = 0; + vc->vc_saved_cols = 0; + } + vt_reset_keyboard(vc->vc_num); vc->vc_cursor_type = cur_default; diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index 59b4fec5f254..13b35637bd5a 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -159,6 +159,9 @@ struct vc_data { struct uni_pagedict *uni_pagedict; struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */ u32 **vc_uni_lines; /* unicode screen content */ + u16 *vc_saved_screen; + unsigned int vc_saved_cols; + unsigned int vc_saved_rows; /* additional information is in vt_kern.h */ }; From aa1020f5cb50ca856fabbd24f6ee40a10aeae89b Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Wed, 27 Aug 2025 10:45:14 +0800 Subject: [PATCH 0926/2711] serial: sc16is7xx: drop redundant conversion to bool The result of integer comparison already evaluates to bool. No need for explicit conversion. Signed-off-by: Xichao Zhao Link: https://lore.kernel.org/r/20250827024514.76149-1-zhao.xichao@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 3f38fba8f6ea..11744306b1de 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -626,7 +626,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, { struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); unsigned int lsr = 0, bytes_read, i; - bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false; + bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC); u8 ch, flag; if (unlikely(rxlen >= sizeof(one->buf))) { From e3fa89f3a768a9c61cf1bfe86b939ab5f36a9744 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 27 Aug 2025 13:17:47 +0300 Subject: [PATCH 0927/2711] serdev: Drop dev_pm_domain_detach() call Starting with commit f99508074e78 ("PM: domains: Detach on device_unbind_cleanup()"), there is no longer a need to call dev_pm_domain_detach() in the bus remove function. The device_unbind_cleanup() function now handles this to avoid invoking devres cleanup handlers while the PM domain is powered off, which could otherwise lead to failures as described in the above-mentioned commit. Drop the explicit dev_pm_domain_detach() call and rely instead on the flags passed to dev_pm_domain_attach() to power off the domain. Signed-off-by: Claudiu Beznea Reviewed-by: Ulf Hansson Link: https://lore.kernel.org/r/20250827101747.928265-1-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index d16c207a1a9b..b33e708cb245 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -399,15 +399,12 @@ static int serdev_drv_probe(struct device *dev) const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver); int ret; - ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON); + ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON | + PD_FLAG_DETACH_POWER_OFF); if (ret) return ret; - ret = sdrv->probe(to_serdev_device(dev)); - if (ret) - dev_pm_domain_detach(dev, true); - - return ret; + return sdrv->probe(to_serdev_device(dev)); } static void serdev_drv_remove(struct device *dev) @@ -415,8 +412,6 @@ static void serdev_drv_remove(struct device *dev) const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver); if (sdrv->remove) sdrv->remove(to_serdev_device(dev)); - - dev_pm_domain_detach(dev, true); } static const struct bus_type serdev_bus_type = { From 94fcae6cb1c1dec20a5bd0e324b23057fa4eae09 Mon Sep 17 00:00:00 2001 From: Zong Jiang Date: Wed, 27 Aug 2025 20:03:19 +0800 Subject: [PATCH 0928/2711] serial: qcom-geni: Fix off-by-one error in ida_alloc_range() The ida_alloc_range() function expects an inclusive range, meaning both the start and end values are valid allocation targets. Passing nr_ports as the upper bound allows allocation of an ID equal to nr_ports, which is out of bounds when used as an index into the port array. Fix this by subtracting 1 from nr_ports in both calls to ida_alloc_range(), ensuring the allocated ID stays within the valid range [start, nr_ports - 1]. This prevents potential out-of-bounds access when the allocated ID is used as an index. Fixes: 9391ab1ed9b3 ("serial: qcom-geni: Make UART port count configurable via Kconfig") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202508180815.R2nDyajs-lkp@intel.com/ Signed-off-by: Zong Jiang Link: https://lore.kernel.org/r/20250827120319.1682835-1-quic_zongjian@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 9c7b1cea7cfe..0b474d349531 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -271,9 +271,11 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console, int max_alias_num = of_alias_get_highest_id("serial"); if (line < 0 || line >= nr_ports) - line = ida_alloc_range(&port_ida, max_alias_num + 1, nr_ports, GFP_KERNEL); + line = ida_alloc_range(&port_ida, max_alias_num + 1, + nr_ports - 1, GFP_KERNEL); else - line = ida_alloc_range(&port_ida, line, nr_ports, GFP_KERNEL); + line = ida_alloc_range(&port_ida, line, + nr_ports - 1, GFP_KERNEL); if (line < 0) return ERR_PTR(-ENXIO); From 3cf0b3c243e56bc43be560617416c1d9f301f44c Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Wed, 27 Aug 2025 15:26:56 +0300 Subject: [PATCH 0929/2711] tty: n_gsm: Don't block input queue by waiting MSC Currently gsm_queue() processes incoming frames and when opening a DLC channel it calls gsm_dlci_open() which calls gsm_modem_update(). If basic mode is used it calls gsm_modem_upd_via_msc() and it cannot block the input queue by waiting the response to come into the same input queue. Instead allow sending Modem Status Command without waiting for remote end to respond. Define a new function gsm_modem_send_initial_msc() for this purpose. As MSC is only valid for basic encoding, it does not do anything for advanced or when convergence layer type 2 is used. Fixes: 48473802506d ("tty: n_gsm: fix missing update of modem controls after DLCI open") Signed-off-by: Seppo Takalo Link: https://lore.kernel.org/r/20250827123221.1148666-1-seppo.takalo@nordicsemi.no Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 7fc535452c0b..553d8c70352b 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -461,6 +461,7 @@ static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg); static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr); static void gsmld_write_trigger(struct gsm_mux *gsm); static void gsmld_write_task(struct work_struct *work); +static int gsm_modem_send_initial_msc(struct gsm_dlci *dlci); /** * gsm_fcs_add - update FCS @@ -2174,7 +2175,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) pr_debug("DLCI %d goes open.\n", dlci->addr); /* Send current modem state */ if (dlci->addr) { - gsm_modem_update(dlci, 0); + gsm_modem_send_initial_msc(dlci); } else { /* Start keep-alive control */ gsm->ka_num = 0; @@ -4161,6 +4162,28 @@ static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk) return gsm_control_wait(dlci->gsm, ctrl); } +/** + * gsm_modem_send_initial_msc - Send initial modem status message + * + * @dlci channel + * + * Send an initial MSC message after DLCI open to set the initial + * modem status lines. This is only done for basic mode. + * Does not wait for a response as we cannot block the input queue + * processing. + */ +static int gsm_modem_send_initial_msc(struct gsm_dlci *dlci) +{ + u8 modembits[2]; + + if (dlci->adaption != 1 || dlci->gsm->encoding != GSM_BASIC_OPT) + return 0; + + modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */ + modembits[1] = (gsm_encode_modem(dlci) << 1) | EA; + return gsm_control_command(dlci->gsm, CMD_MSC, (const u8 *)&modembits, 2); +} + /** * gsm_modem_update - send modem status line state * @dlci: channel From 5a66087107b80ac4e58a94f37d9b8d12e22b4071 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 22 Aug 2025 12:42:08 +0200 Subject: [PATCH 0930/2711] m68k: make HPDCA and HPAPCI bools The only user -- 8250_hp300 -- tests for CONFIG_HPDCA and CONFIG_HPAPCI. It does not test for *_MODULE variants. That means that if someone sets the configs to =m, the code is not compiled at all. There is actually no point having these as tristate. Switch them to bool. Signed-off-by: Jiri Slaby (SUSE) Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Link: https://lore.kernel.org/r/20250822104208.751191-1-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/m68k/Kconfig.devices | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/m68k/Kconfig.devices b/arch/m68k/Kconfig.devices index e6e3efac1840..e277f1bd2de1 100644 --- a/arch/m68k/Kconfig.devices +++ b/arch/m68k/Kconfig.devices @@ -105,14 +105,14 @@ config AMIGA_BUILTIN_SERIAL To compile this driver as a module, choose M here. config HPDCA - tristate "HP DCA serial support" + bool "HP DCA serial support" depends on DIO && SERIAL_8250 help If you want to use the internal "DCA" serial ports on an HP300 machine, say Y here. config HPAPCI - tristate "HP APCI serial support" + bool "HP APCI serial support" depends on HP300 && SERIAL_8250 help If you want to use the internal "APCI" serial ports on an HP400 From fc6a5b540c02d1ec624e4599f45a17f2941a5c00 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Wed, 3 Sep 2025 12:01:36 +0530 Subject: [PATCH 0931/2711] serial: qcom-geni: Add DFS clock mode support to GENI UART driver GENI UART driver currently supports only non-DFS (Dynamic Frequency Scaling) mode for source frequency selection. However, to operate correctly in DFS mode, the GENI SCLK register must be programmed with the appropriate DFS index. Failing to do so can result in incorrect frequency selection Add support for Dynamic Frequency Scaling (DFS) mode in the GENI UART driver by configuring the GENI_CLK_SEL register with the appropriate DFS index. This ensures correct frequency selection when operating in DFS mode. Replace the UART driver-specific logic for clock selection with the GENI common driver function to obtain the desired frequency and corresponding clock index. This improves maintainability and consistency across GENI-based drivers. Signed-off-by: Viken Dadhaniya Link: https://lore.kernel.org/r/20250903063136.3015237-1-viken.dadhaniya@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 92 ++++++--------------------- 1 file changed, 21 insertions(+), 71 deletions(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 0b474d349531..0fdda3a1e70b 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1,5 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. +/* + * Copyright (c) 2017-2018, The Linux foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ /* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */ #define __DISABLE_TRACE_MMIO__ @@ -1242,75 +1245,15 @@ static int qcom_geni_serial_startup(struct uart_port *uport) return 0; } -static unsigned long find_clk_rate_in_tol(struct clk *clk, unsigned int desired_clk, - unsigned int *clk_div, unsigned int percent_tol) -{ - unsigned long freq; - unsigned long div, maxdiv; - u64 mult; - unsigned long offset, abs_tol, achieved; - - abs_tol = div_u64((u64)desired_clk * percent_tol, 100); - maxdiv = CLK_DIV_MSK >> CLK_DIV_SHFT; - div = 1; - while (div <= maxdiv) { - mult = (u64)div * desired_clk; - if (mult != (unsigned long)mult) - break; - - offset = div * abs_tol; - freq = clk_round_rate(clk, mult - offset); - - /* Can only get lower if we're done */ - if (freq < mult - offset) - break; - - /* - * Re-calculate div in case rounding skipped rates but we - * ended up at a good one, then check for a match. - */ - div = DIV_ROUND_CLOSEST(freq, desired_clk); - achieved = DIV_ROUND_CLOSEST(freq, div); - if (achieved <= desired_clk + abs_tol && - achieved >= desired_clk - abs_tol) { - *clk_div = div; - return freq; - } - - div = DIV_ROUND_UP(freq, desired_clk); - } - - return 0; -} - -static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud, - unsigned int sampling_rate, unsigned int *clk_div) -{ - unsigned long ser_clk; - unsigned long desired_clk; - - desired_clk = baud * sampling_rate; - if (!desired_clk) - return 0; - - /* - * try to find a clock rate within 2% tolerance, then within 5% - */ - ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 2); - if (!ser_clk) - ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 5); - - return ser_clk; -} - static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud) { struct qcom_geni_serial_port *port = to_dev_port(uport); unsigned long clk_rate; - unsigned int avg_bw_core; + unsigned int avg_bw_core, clk_idx; unsigned int clk_div; u32 ver, sampling_rate; u32 ser_clk_cfg; + int ret; sampling_rate = UART_OVERSAMPLING; /* Sampling rate is halved for IP versions >= 2.5 */ @@ -1318,17 +1261,22 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud) if (ver >= QUP_SE_VERSION_2_5) sampling_rate /= 2; - clk_rate = get_clk_div_rate(port->se.clk, baud, - sampling_rate, &clk_div); - if (!clk_rate) { - dev_err(port->se.dev, - "Couldn't find suitable clock rate for %u\n", - baud * sampling_rate); + ret = geni_se_clk_freq_match(&port->se, baud * sampling_rate, &clk_idx, &clk_rate, false); + if (ret) { + dev_err(port->se.dev, "Failed to find src clk for baud rate: %d ret: %d\n", + baud, ret); + return ret; + } + + clk_div = DIV_ROUND_UP(clk_rate, baud * sampling_rate); + /* Check if calculated divider exceeds maximum allowed value */ + if (clk_div > (CLK_DIV_MSK >> CLK_DIV_SHFT)) { + dev_err(port->se.dev, "Calculated clock divider %u exceeds maximum\n", clk_div); return -EINVAL; } - dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n", - baud * sampling_rate, clk_rate, clk_div); + dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n, clk_idx = %u\n", + baud * sampling_rate, clk_rate, clk_div, clk_idx); uport->uartclk = clk_rate; port->clk_rate = clk_rate; @@ -1348,6 +1296,8 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud) writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); + /* Configure clock selection register with the selected clock index */ + writel(clk_idx & CLK_SEL_MSK, uport->membase + SE_GENI_CLK_SEL); return 0; } From 45747017928c7e6ef71f3a09c5610b7026357162 Mon Sep 17 00:00:00 2001 From: Wang Liang Date: Thu, 4 Sep 2025 10:33:45 +0800 Subject: [PATCH 0932/2711] vt: remove redundant check on vc_mode in con_font_set() Previous commit edab558feba1 ("vt: sort out locking for font handling") move the vc_mode check into console_lock protect, but forget to remove the old check in con_font_set(). Just remove the redundant check. Signed-off-by: Wang Liang Link: https://lore.kernel.org/r/20250904023345.13731-1-wangliang74@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 3f80e98e5c51..1d9abcfac4c9 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4885,8 +4885,6 @@ static int con_font_set(struct vc_data *vc, const struct console_font_op *op) int size; unsigned int vpitch = op->op == KD_FONT_OP_SET_TALL ? op->height : 32; - if (vc->vc_mode != KD_TEXT) - return -EINVAL; if (!op->data) return -EINVAL; if (op->charcount > max_font_glyphs) From da7e8b3823962b13e713d4891e136a261ed8e6a2 Mon Sep 17 00:00:00 2001 From: Zizhi Wo Date: Thu, 4 Sep 2025 10:39:55 +0800 Subject: [PATCH 0933/2711] tty/vt: Add missing return value for VT_RESIZE in vt_ioctl() In vt_ioctl(), the handler for VT_RESIZE always returns 0, which prevents users from detecting errors. Add the missing return value so that errors can be properly reported to users like vt_resizex(). Signed-off-by: Zizhi Wo Link: https://lore.kernel.org/r/20250904023955.3892120-1-wozizhi@huaweicloud.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt_ioctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index c9f11c4bd9fe..28993a3d0acb 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -908,7 +908,9 @@ int vt_ioctl(struct tty_struct *tty, if (vc) { /* FIXME: review v tty lock */ - __vc_resize(vc_cons[i].d, cc, ll, true); + ret = __vc_resize(vc_cons[i].d, cc, ll, true); + if (ret) + return ret; } } break; From b601e1f41edd4667062aa7cccb4e5199814979a3 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Fri, 5 Sep 2025 17:13:21 +0800 Subject: [PATCH 0934/2711] tty: remove redundant condition checks Remove redundant condition checks and replace else if with else. Signed-off-by: Xichao Zhao Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20250905091321.437476-1-zhao.xichao@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_console.c | 2 +- drivers/tty/serial/msm_serial.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index cd1f657f782d..fffc30b9ea54 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -184,7 +184,7 @@ static void hvc_console_print(struct console *co, const char *b, hvc_console_flush(cons_ops[index], vtermnos[index]); } - } else if (r > 0) { + } else { i -= r; if (i > 0) memmove(c, c+r, i); diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 3449945493ce..2e999cb9c974 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1102,7 +1102,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud, if (result == baud) break; - } else if (entry->divisor > divisor) { + } else { old = target; target = clk_round_rate(msm_port->clk, old + 1); /* From 91180c6662774cb8f9b69b9bdde0b57babbe14b0 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Tue, 19 Aug 2025 21:11:54 +0800 Subject: [PATCH 0935/2711] staging: gpib: tnt4882: Remove redundant header files The header file is already included on line 12, outside of the #ifdef CONFIG_GPIB_PCMCIA block. It does not need to be included again inside the #ifdef CONFIG_GPIB_PCMCIA block. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250819131203.152724-1-liaoyuanhong@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/gpib/tnt4882/tnt4882_gpib.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/gpib/tnt4882/tnt4882_gpib.c b/drivers/staging/gpib/tnt4882/tnt4882_gpib.c index 29c6884e01fd..c03a976b7380 100644 --- a/drivers/staging/gpib/tnt4882/tnt4882_gpib.c +++ b/drivers/staging/gpib/tnt4882/tnt4882_gpib.c @@ -1522,7 +1522,6 @@ static void __exit tnt4882_exit_module(void) #include #include #include -#include #include #include From 994626b97ec35bb09a5c1a19a62ddfa7643781b7 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:08 +0200 Subject: [PATCH 0936/2711] staging: rtl8723bs: remove bPseudoTest from EFUSE_ShadowMapUpdate The function EFUSE_ShadowMapUpdate is always called with bPseudoTest set to false. Remove the pPseudoTest parameter and replace its usage in the function with false to reduce code complexity. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-2-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 6 +++--- drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c | 4 ++-- drivers/staging/rtl8723bs/include/rtw_efuse.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 208373113a62..d28298fa2853 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -386,17 +386,17 @@ static void efuse_ShadowRead4Byte(struct adapter *padapter, u16 Offset, u32 *Val * 11/13/2008 MHC Create Version 0. * */ -void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType, bool bPseudoTest) +void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); u16 mapLen = 0; - EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, bPseudoTest); + EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); if (pEEPROM->bautoload_fail_flag) memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); else - Efuse_ReadAllMap(padapter, efuseType, pEEPROM->efuse_eeprom_data, bPseudoTest); + Efuse_ReadAllMap(padapter, efuseType, pEEPROM->efuse_eeprom_data, false); /* PlatformMoveMemory((void *)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], */ /* void *)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen); */ diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 1608bc71bd71..4a0423182f9e 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -1438,12 +1438,12 @@ void Hal_InitPGData(struct adapter *padapter, u8 *PROMContent) if (!pEEPROM->bautoload_fail_flag) { /* autoload OK. */ if (!pEEPROM->EepromOrEfuse) { /* Read EFUSE real map to shadow. */ - EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false); + EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI); memcpy((void *)PROMContent, (void *)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_8723B); } } else {/* autoload fail */ if (!pEEPROM->EepromOrEfuse) - EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false); + EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI); memcpy((void *)PROMContent, (void *)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_8723B); } } diff --git a/drivers/staging/rtl8723bs/include/rtw_efuse.h b/drivers/staging/rtl8723bs/include/rtw_efuse.h index 669565fa1c69..7bc8de3af1f9 100644 --- a/drivers/staging/rtl8723bs/include/rtw_efuse.h +++ b/drivers/staging/rtl8723bs/include/rtw_efuse.h @@ -98,7 +98,7 @@ u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudo void Efuse_PowerSwitch(struct adapter *padapter, u8 bWrite, u8 PwrState); u8 EFUSE_Read1Byte(struct adapter *padapter, u16 Address); -void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType, bool bPseudoTest); +void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType); void EFUSE_ShadowRead(struct adapter *padapter, u8 Type, u16 Offset, u32 *Value); void Rtw_Hal_ReadMACAddrFromFile(struct adapter *padapter); u32 Rtw_Hal_readPGDataFromConfigFile(struct adapter *padapter); From fc7ae37d81c5343e38397cf3937a61f451999d6b Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:09 +0200 Subject: [PATCH 0937/2711] staging: rtl8723bs: make Efuse_ReadAllMap static Make the function Efuse_ReadAllMap static and remove its unnecessary forawrd declaration. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-3-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index d28298fa2853..2c0dc55fb20e 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -303,13 +303,7 @@ u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoT * 11/11/2008 MHC Create Version 0. * */ -void -Efuse_ReadAllMap( - struct adapter *padapter, - u8 efuseType, - u8 *Efuse, - bool bPseudoTest); -void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse, bool bPseudoTest) +static void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse, bool bPseudoTest) { u16 mapLen = 0; From e8605159aec9bc2f272555f9bd9c4bf077dd9d15 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:10 +0200 Subject: [PATCH 0938/2711] staging: rtl8723bs: remove bPseudoTest from Efuse_ReadAllMap The function Efuse_ReadAllMap is always called with bPseudoTest set to false. Remove the pPseudoTest parameter and replace its usage in the function with false to reduce code complexity. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-4-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 2c0dc55fb20e..e865f83c0967 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -303,15 +303,15 @@ u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoT * 11/11/2008 MHC Create Version 0. * */ -static void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse, bool bPseudoTest) +static void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse) { u16 mapLen = 0; Efuse_PowerSwitch(padapter, false, true); - EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, bPseudoTest); + EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); - efuse_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse, bPseudoTest); + efuse_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse, false); Efuse_PowerSwitch(padapter, false, false); } @@ -390,7 +390,7 @@ void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType) if (pEEPROM->bautoload_fail_flag) memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); else - Efuse_ReadAllMap(padapter, efuseType, pEEPROM->efuse_eeprom_data, false); + Efuse_ReadAllMap(padapter, efuseType, pEEPROM->efuse_eeprom_data); /* PlatformMoveMemory((void *)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], */ /* void *)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen); */ From 14fd39484787336f8b1e160e98b723bba78cbe8c Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:11 +0200 Subject: [PATCH 0939/2711] staging: rtl8723bs: remove wrapper efuse_ReadEFuse The function efuse_ReadEFuse is just a wrapper around Hal_ReadEFuse. Remove the wrapper and use Hal_ReadEFuse directly. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-5-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 42 +--------------------- 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index e865f83c0967..1079e2bc3287 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -97,46 +97,6 @@ Efuse_CalculateWordCnts(u8 word_en) return word_cnts; } -/* */ -/* Description: */ -/* 1. Execute E-Fuse read byte operation according as map offset and */ -/* save to E-Fuse table. */ -/* 2. Referred from SD1 Richard. */ -/* */ -/* Assumption: */ -/* 1. Boot from E-Fuse and successfully auto-load. */ -/* 2. PASSIVE_LEVEL (USB interface) */ -/* */ -/* Created by Roger, 2008.10.21. */ -/* */ -/* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */ -/* 2. Add efuse utilization collect. */ -/* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */ -/* write addr must be after sec5. */ -/* */ - -void -efuse_ReadEFuse( - struct adapter *Adapter, - u8 efuseType, - u16 _offset, - u16 _size_byte, - u8 *pbuf, -bool bPseudoTest - ); -void -efuse_ReadEFuse( - struct adapter *Adapter, - u8 efuseType, - u16 _offset, - u16 _size_byte, - u8 *pbuf, -bool bPseudoTest - ) -{ - Hal_ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); -} - void EFUSE_GetEfuseDefinition( struct adapter *padapter, @@ -311,7 +271,7 @@ static void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse) EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); - efuse_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse, false); + Hal_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse, false); Efuse_PowerSwitch(padapter, false, false); } From 0124378e9ed4fd17b6070e18cf90326d7533eec0 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:12 +0200 Subject: [PATCH 0940/2711] staging: rtl8723bs: remove bPseudoTest from Hal_ReadEFuse The function Hal_ReadEFuse is always called with bPseudoTest set to false. Remove the pPseudoTest parameter and replace its usage in the function with false to reduce code complexity. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-6-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 2 +- drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c | 7 +++---- drivers/staging/rtl8723bs/include/hal_intf.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 1079e2bc3287..388d885c938f 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -271,7 +271,7 @@ static void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse) EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); - Hal_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse, false); + Hal_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse); Efuse_PowerSwitch(padapter, false, false); } diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 4a0423182f9e..002648a8fd81 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -883,14 +883,13 @@ void Hal_ReadEFuse( u8 efuseType, u16 _offset, u16 _size_byte, - u8 *pbuf, - bool bPseudoTest + u8 *pbuf ) { if (efuseType == EFUSE_WIFI) - hal_ReadEFuse_WiFi(padapter, _offset, _size_byte, pbuf, bPseudoTest); + hal_ReadEFuse_WiFi(padapter, _offset, _size_byte, pbuf, false); else - hal_ReadEFuse_BT(padapter, _offset, _size_byte, pbuf, bPseudoTest); + hal_ReadEFuse_BT(padapter, _offset, _size_byte, pbuf, false); } static u16 hal_EfuseGetCurrentSize_WiFi( diff --git a/drivers/staging/rtl8723bs/include/hal_intf.h b/drivers/staging/rtl8723bs/include/hal_intf.h index 67d51e55bd44..2e97a918445c 100644 --- a/drivers/staging/rtl8723bs/include/hal_intf.h +++ b/drivers/staging/rtl8723bs/include/hal_intf.h @@ -267,7 +267,7 @@ void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_level); void rtl8723b_SetBeaconRelatedRegisters(struct adapter *padapter); void Hal_EfusePowerSwitch(struct adapter *padapter, u8 bWrite, u8 PwrState); void Hal_ReadEFuse(struct adapter *padapter, u8 efuseType, u16 _offset, - u16 _size_byte, u8 *pbuf, bool bPseudoTest); + u16 _size_byte, u8 *pbuf); void Hal_GetEfuseDefinition(struct adapter *padapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest); u16 Hal_EfuseGetCurrentSize(struct adapter *padapter, u8 efuseType, bool bPseudoTest); From 0de319271c798f40d1fc26eaaee2a2d5aa1b4f3f Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:13 +0200 Subject: [PATCH 0941/2711] staging: rtl8723bs: remove bPseudoTest from hal_ReadEFuse_WiFi The function hal_ReadEFuse_WiFi is always called with bPseudoTest set to false. Remove the pPseudoTest parameter, replace its usage in the function with false, and reomve resulting dead code to reduce code complexity. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-7-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../staging/rtl8723bs/hal/rtl8723b_hal_init.c | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 002648a8fd81..c40d447c04d2 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -669,14 +669,9 @@ static void hal_ReadEFuse_WiFi( struct adapter *padapter, u16 _offset, u16 _size_byte, - u8 *pbuf, - bool bPseudoTest + u8 *pbuf ) { -#ifdef HAL_EFUSE_MEMORY - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; -#endif u8 *efuseTbl = NULL; u16 eFuse_Addr = 0; u8 offset, wden; @@ -698,10 +693,10 @@ static void hal_ReadEFuse_WiFi( memset(efuseTbl, 0xFF, EFUSE_MAX_MAP_LEN); /* switch bank back to bank 0 for later BT and wifi use. */ - hal_EfuseSwitchToBank(padapter, 0, bPseudoTest); + hal_EfuseSwitchToBank(padapter, 0, false); while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { - efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest); + efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, false); if (efuseHeader == 0xFF) break; @@ -709,7 +704,7 @@ static void hal_ReadEFuse_WiFi( if (EXT_HEADER(efuseHeader)) { /* extended header */ offset = GET_HDR_OFFSET_2_0(efuseHeader); - efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest); + efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr, false); if (ALL_WORDS_DISABLED(efuseExtHdr)) continue; @@ -728,10 +723,10 @@ static void hal_ReadEFuse_WiFi( for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { /* Check word enable condition in the section */ if (!(wden & (0x01<fakeEfuseUsedBytes = used; -#else - fakeEfuseUsedBytes = used; -#endif - } else { - rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&used); - rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_USAGE, (u8 *)&efuse_usage); - } + + rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&used); + rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_USAGE, (u8 *)&efuse_usage); kfree(efuseTbl); } @@ -887,7 +875,7 @@ void Hal_ReadEFuse( ) { if (efuseType == EFUSE_WIFI) - hal_ReadEFuse_WiFi(padapter, _offset, _size_byte, pbuf, false); + hal_ReadEFuse_WiFi(padapter, _offset, _size_byte, pbuf); else hal_ReadEFuse_BT(padapter, _offset, _size_byte, pbuf, false); } From 3d589e3b27a50a7bf2245eb0837eafb2d132af69 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:14 +0200 Subject: [PATCH 0942/2711] staging: rtl8723bs: remove bPseudoTest from hal_ReadEFuse_BT The function hal_ReadEFuse_BT is always called with bPseudoTest set to false. Remove the pPseudoTest parameter, replace its usage in the function with false, and reomve resulting dead code to reduce code complexity. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-8-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../staging/rtl8723bs/hal/rtl8723b_hal_init.c | 38 +++++++------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index c40d447c04d2..fe6a3dd84aca 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -755,14 +755,9 @@ static void hal_ReadEFuse_BT( struct adapter *padapter, u16 _offset, u16 _size_byte, - u8 *pbuf, - bool bPseudoTest + u8 *pbuf ) { -#ifdef HAL_EFUSE_MEMORY - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; -#endif u8 *efuseTbl; u8 bank; u16 eFuse_Addr; @@ -785,16 +780,16 @@ static void hal_ReadEFuse_BT( /* 0xff will be efuse default value instead of 0x00. */ memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN); - EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total, bPseudoTest); + EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total, false); for (bank = 1; bank < 3; bank++) { /* 8723b Max bake 0~2 */ - if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) + if (hal_EfuseSwitchToBank(padapter, bank, false) == false) goto exit; eFuse_Addr = 0; while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { - efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest); + efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, false); if (efuseHeader == 0xFF) break; @@ -802,7 +797,7 @@ static void hal_ReadEFuse_BT( if (EXT_HEADER(efuseHeader)) { /* extended header */ offset = GET_HDR_OFFSET_2_0(efuseHeader); - efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest); + efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr, false); if (ALL_WORDS_DISABLED(efuseExtHdr)) continue; @@ -820,10 +815,10 @@ static void hal_ReadEFuse_BT( for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { /* Check word enable condition in the section */ if (!(wden & (0x01<fakeBTEfuseUsedBytes = used; -#else - fakeBTEfuseUsedBytes = used; -#endif - } else { - rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&used); - rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BT_USAGE, (u8 *)&efuse_usage); - } + + rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&used); + rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BT_USAGE, (u8 *)&efuse_usage); exit: kfree(efuseTbl); @@ -877,7 +865,7 @@ void Hal_ReadEFuse( if (efuseType == EFUSE_WIFI) hal_ReadEFuse_WiFi(padapter, _offset, _size_byte, pbuf); else - hal_ReadEFuse_BT(padapter, _offset, _size_byte, pbuf, false); + hal_ReadEFuse_BT(padapter, _offset, _size_byte, pbuf); } static u16 hal_EfuseGetCurrentSize_WiFi( From b907ae0baf83c2b1c24e3ba894bd961e686c45a2 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:15 +0200 Subject: [PATCH 0943/2711] staging: rtl8723bs: remove wrapper EFUSE_GetEfuseDefinition The function EFUSE_GetEfuseDefinition is just a wrapper around Hal_GetEfuseDefinition. Remove the wrapper and use Hal_GetEfuseDefinition directly. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-9-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 18 +++--------------- .../staging/rtl8723bs/hal/rtl8723b_hal_init.c | 10 +++++----- drivers/staging/rtl8723bs/include/rtw_efuse.h | 1 - 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 388d885c938f..25ec7278b815 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -97,18 +97,6 @@ Efuse_CalculateWordCnts(u8 word_en) return word_cnts; } -void -EFUSE_GetEfuseDefinition( - struct adapter *padapter, - u8 efuseType, - u8 type, - void *pOut, - bool bPseudoTest - ) -{ - Hal_GetEfuseDefinition(padapter, efuseType, type, pOut, bPseudoTest); -} - /*----------------------------------------------------------------------------- * Function: EFUSE_Read1Byte * @@ -135,7 +123,7 @@ u16 Address) u32 k = 0; u16 contentLen = 0; - EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false); + Hal_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false); if (Address < contentLen) {/* E-fuse 512Byte */ /* Write E-fuse Register address bit0~7 */ @@ -269,7 +257,7 @@ static void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse) Efuse_PowerSwitch(padapter, false, true); - EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); + Hal_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); Hal_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse); @@ -345,7 +333,7 @@ void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType) struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); u16 mapLen = 0; - EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); + Hal_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); if (pEEPROM->bautoload_fail_flag) memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index fe6a3dd84aca..5355bb80b676 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -741,7 +741,7 @@ static void hal_ReadEFuse_WiFi( pbuf[i] = efuseTbl[_offset+i]; /* Calculate Efuse utilization */ - EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total, false); + Hal_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total, false); used = eFuse_Addr - 1; efuse_usage = (u8)((used*100)/total); @@ -780,7 +780,7 @@ static void hal_ReadEFuse_BT( /* 0xff will be efuse default value instead of 0x00. */ memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN); - EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total, false); + Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total, false); for (bank = 1; bank < 3; bank++) { /* 8723b Max bake 0~2 */ if (hal_EfuseSwitchToBank(padapter, bank, false) == false) @@ -843,7 +843,7 @@ static void hal_ReadEFuse_BT( /* */ /* Calculate Efuse utilization. */ /* */ - EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total, false); + Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total, false); used = (EFUSE_BT_REAL_BANK_CONTENT_LEN*(bank-1)) + eFuse_Addr - 1; efuse_usage = (u8)((used*100)/total); @@ -952,7 +952,7 @@ static u16 hal_EfuseGetCurrentSize_WiFi( error: /* report max size to prevent write efuse */ - EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_addr, bPseudoTest); + Hal_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_addr, bPseudoTest); exit: @@ -984,7 +984,7 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) efuse_addr = (u16)((btusedbytes%EFUSE_BT_REAL_BANK_CONTENT_LEN)); startBank = (u8)(1+(btusedbytes/EFUSE_BT_REAL_BANK_CONTENT_LEN)); - EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &retU2, bPseudoTest); + Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &retU2, bPseudoTest); for (bank = startBank; bank < 3; bank++) { if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) diff --git a/drivers/staging/rtl8723bs/include/rtw_efuse.h b/drivers/staging/rtl8723bs/include/rtw_efuse.h index 7bc8de3af1f9..a5c338c67245 100644 --- a/drivers/staging/rtl8723bs/include/rtw_efuse.h +++ b/drivers/staging/rtl8723bs/include/rtw_efuse.h @@ -91,7 +91,6 @@ extern u8 fakeBTEfuseModifiedMap[]; /*------------------------Export global variable----------------------------*/ u8 Efuse_CalculateWordCnts(u8 word_en); -void EFUSE_GetEfuseDefinition(struct adapter *padapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest); u8 efuse_OneByteRead(struct adapter *padapter, u16 addr, u8 *data, bool bPseudoTest); u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoTest); From 254c268bf1d3e9e3b640e29a71e285a511ba7ffc Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:16 +0200 Subject: [PATCH 0944/2711] staging: rtl8723bs: remove bPseudoTest from Hal_GetEfuseDefinition The bPseudoTEst parameter is not used in Hal_GetEfuseDefinition. Remove the unused parameter and adjust the function calls. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-10-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 6 +++--- drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c | 13 ++++++------- drivers/staging/rtl8723bs/include/hal_intf.h | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 25ec7278b815..9d065721c28a 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -123,7 +123,7 @@ u16 Address) u32 k = 0; u16 contentLen = 0; - Hal_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false); + Hal_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen); if (Address < contentLen) {/* E-fuse 512Byte */ /* Write E-fuse Register address bit0~7 */ @@ -257,7 +257,7 @@ static void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse) Efuse_PowerSwitch(padapter, false, true); - Hal_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); + Hal_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen); Hal_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse); @@ -333,7 +333,7 @@ void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType) struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); u16 mapLen = 0; - Hal_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); + Hal_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen); if (pEEPROM->bautoload_fail_flag) memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 5355bb80b676..af61730cff14 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -494,8 +494,7 @@ void Hal_GetEfuseDefinition( struct adapter *padapter, u8 efuseType, u8 type, - void *pOut, - bool bPseudoTest + void *pOut ) { switch (type) { @@ -741,7 +740,7 @@ static void hal_ReadEFuse_WiFi( pbuf[i] = efuseTbl[_offset+i]; /* Calculate Efuse utilization */ - Hal_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total, false); + Hal_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total); used = eFuse_Addr - 1; efuse_usage = (u8)((used*100)/total); @@ -780,7 +779,7 @@ static void hal_ReadEFuse_BT( /* 0xff will be efuse default value instead of 0x00. */ memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN); - Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total, false); + Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total); for (bank = 1; bank < 3; bank++) { /* 8723b Max bake 0~2 */ if (hal_EfuseSwitchToBank(padapter, bank, false) == false) @@ -843,7 +842,7 @@ static void hal_ReadEFuse_BT( /* */ /* Calculate Efuse utilization. */ /* */ - Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total, false); + Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total); used = (EFUSE_BT_REAL_BANK_CONTENT_LEN*(bank-1)) + eFuse_Addr - 1; efuse_usage = (u8)((used*100)/total); @@ -952,7 +951,7 @@ static u16 hal_EfuseGetCurrentSize_WiFi( error: /* report max size to prevent write efuse */ - Hal_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_addr, bPseudoTest); + Hal_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_addr); exit: @@ -984,7 +983,7 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) efuse_addr = (u16)((btusedbytes%EFUSE_BT_REAL_BANK_CONTENT_LEN)); startBank = (u8)(1+(btusedbytes/EFUSE_BT_REAL_BANK_CONTENT_LEN)); - Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &retU2, bPseudoTest); + Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &retU2); for (bank = startBank; bank < 3; bank++) { if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) diff --git a/drivers/staging/rtl8723bs/include/hal_intf.h b/drivers/staging/rtl8723bs/include/hal_intf.h index 2e97a918445c..fbf0b01780ea 100644 --- a/drivers/staging/rtl8723bs/include/hal_intf.h +++ b/drivers/staging/rtl8723bs/include/hal_intf.h @@ -269,7 +269,7 @@ void Hal_EfusePowerSwitch(struct adapter *padapter, u8 bWrite, u8 PwrState); void Hal_ReadEFuse(struct adapter *padapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf); void Hal_GetEfuseDefinition(struct adapter *padapter, u8 efuseType, u8 type, - void *pOut, bool bPseudoTest); + void *pOut); u16 Hal_EfuseGetCurrentSize(struct adapter *padapter, u8 efuseType, bool bPseudoTest); void hal_notch_filter_8723b(struct adapter *adapter, bool enable); #endif /* __HAL_INTF_H__ */ From 127fae1d910f0cc58af1327a7009dd766820ef98 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:17 +0200 Subject: [PATCH 0945/2711] staging: rtl8723bs: remove Hal_EfuseGetCurrentSize The function Hal_EfuseGetCurrentSize is not used in the driver code, remove it to get rid of dead code. As Hal_EfuseGetCurrentSize is the only caller of hal_EfuseGetCurrentSize_WiFi and hal_EfuseGetCurrentSize_BT we can remove these two functions as well. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-11-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../staging/rtl8723bs/hal/rtl8723b_hal_init.c | 184 ------------------ drivers/staging/rtl8723bs/include/hal_intf.h | 1 - 2 files changed, 185 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index af61730cff14..0679f77e3498 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -867,190 +867,6 @@ void Hal_ReadEFuse( hal_ReadEFuse_BT(padapter, _offset, _size_byte, pbuf); } -static u16 hal_EfuseGetCurrentSize_WiFi( - struct adapter *padapter, bool bPseudoTest -) -{ -#ifdef HAL_EFUSE_MEMORY - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; -#endif - u16 efuse_addr = 0; - u16 start_addr = 0; /* for debug */ - u8 hworden = 0; - u8 efuse_data, word_cnts = 0; - u32 count = 0; /* for debug */ - - - if (bPseudoTest) { -#ifdef HAL_EFUSE_MEMORY - efuse_addr = (u16)pEfuseHal->fakeEfuseUsedBytes; -#else - efuse_addr = (u16)fakeEfuseUsedBytes; -#endif - } else - rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); - - start_addr = efuse_addr; - - /* switch bank back to bank 0 for later BT and wifi use. */ - hal_EfuseSwitchToBank(padapter, 0, bPseudoTest); - - count = 0; - while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { - if (efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest) == false) - goto error; - - if (efuse_data == 0xFF) - break; - - if ((start_addr != 0) && (efuse_addr == start_addr)) { - count++; - - efuse_data = 0xFF; - if (count < 4) { - /* try again! */ - - if (count > 2) { - /* try again form address 0 */ - efuse_addr = 0; - start_addr = 0; - } - - continue; - } - - goto error; - } - - if (EXT_HEADER(efuse_data)) { - efuse_addr++; - efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest); - if (ALL_WORDS_DISABLED(efuse_data)) - continue; - - hworden = efuse_data & 0x0F; - } else { - hworden = efuse_data & 0x0F; - } - - word_cnts = Efuse_CalculateWordCnts(hworden); - efuse_addr += (word_cnts*2)+1; - } - - if (bPseudoTest) { -#ifdef HAL_EFUSE_MEMORY - pEfuseHal->fakeEfuseUsedBytes = efuse_addr; -#else - fakeEfuseUsedBytes = efuse_addr; -#endif - } else - rtw_hal_set_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); - - goto exit; - -error: - /* report max size to prevent write efuse */ - Hal_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_addr); - -exit: - - return efuse_addr; -} - -static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) -{ -#ifdef HAL_EFUSE_MEMORY - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; -#endif - u16 btusedbytes; - u16 efuse_addr; - u8 bank, startBank; - u8 hworden = 0; - u8 efuse_data, word_cnts = 0; - u16 retU2 = 0; - - if (bPseudoTest) { -#ifdef HAL_EFUSE_MEMORY - btusedbytes = pEfuseHal->fakeBTEfuseUsedBytes; -#else - btusedbytes = fakeBTEfuseUsedBytes; -#endif - } else - rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&btusedbytes); - - efuse_addr = (u16)((btusedbytes%EFUSE_BT_REAL_BANK_CONTENT_LEN)); - startBank = (u8)(1+(btusedbytes/EFUSE_BT_REAL_BANK_CONTENT_LEN)); - - Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &retU2); - - for (bank = startBank; bank < 3; bank++) { - if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == false) - /* bank = EFUSE_MAX_BANK; */ - break; - - /* only when bank is switched we have to reset the efuse_addr. */ - if (bank != startBank) - efuse_addr = 0; - - while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { - if (efuse_OneByteRead(padapter, efuse_addr, - &efuse_data, bPseudoTest) == false) - /* bank = EFUSE_MAX_BANK; */ - break; - - if (efuse_data == 0xFF) - break; - - if (EXT_HEADER(efuse_data)) { - efuse_addr++; - efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest); - - if (ALL_WORDS_DISABLED(efuse_data)) { - efuse_addr++; - continue; - } - - hworden = efuse_data & 0x0F; - } else { - hworden = efuse_data & 0x0F; - } - - word_cnts = Efuse_CalculateWordCnts(hworden); - /* read next header */ - efuse_addr += (word_cnts*2)+1; - } - - /* Check if we need to check next bank efuse */ - if (efuse_addr < retU2) - break; /* don't need to check next bank. */ - } - - retU2 = ((bank-1)*EFUSE_BT_REAL_BANK_CONTENT_LEN)+efuse_addr; - if (bPseudoTest) { - pEfuseHal->fakeBTEfuseUsedBytes = retU2; - } else { - pEfuseHal->BTEfuseUsedBytes = retU2; - } - - return retU2; -} - -u16 Hal_EfuseGetCurrentSize( - struct adapter *padapter, u8 efuseType, bool bPseudoTest -) -{ - u16 ret = 0; - - if (efuseType == EFUSE_WIFI) - ret = hal_EfuseGetCurrentSize_WiFi(padapter, bPseudoTest); - else - ret = hal_EfuseGetCurrentSize_BT(padapter, bPseudoTest); - - return ret; -} - static struct hal_version ReadChipVersion8723B(struct adapter *padapter) { u32 value32; diff --git a/drivers/staging/rtl8723bs/include/hal_intf.h b/drivers/staging/rtl8723bs/include/hal_intf.h index fbf0b01780ea..4fe48cccb889 100644 --- a/drivers/staging/rtl8723bs/include/hal_intf.h +++ b/drivers/staging/rtl8723bs/include/hal_intf.h @@ -270,6 +270,5 @@ void Hal_ReadEFuse(struct adapter *padapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf); void Hal_GetEfuseDefinition(struct adapter *padapter, u8 efuseType, u8 type, void *pOut); -u16 Hal_EfuseGetCurrentSize(struct adapter *padapter, u8 efuseType, bool bPseudoTest); void hal_notch_filter_8723b(struct adapter *adapter, bool enable); #endif /* __HAL_INTF_H__ */ From 4d170e2c0d6896f25d09eddb25e9f72da544d99f Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:18 +0200 Subject: [PATCH 0946/2711] staging: rtl8723bs: remove bPseudoTest from hal_EfuseSwitchToBank The function hal_EfuseSwitchToBank is always called with bPseudoTest set to false. Remove the pPseudoTest parameter and reomve resulting dead code to reduce code complexity. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-12-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../staging/rtl8723bs/hal/rtl8723b_hal_init.c | 62 +++++++------------ 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 0679f77e3498..014d94894de9 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -445,47 +445,33 @@ void rtl8723b_InitializeFirmwareVars(struct adapter *padapter) /* Efuse related code */ /* */ static u8 hal_EfuseSwitchToBank( - struct adapter *padapter, u8 bank, bool bPseudoTest + struct adapter *padapter, u8 bank ) { u8 bRet = false; u32 value32 = 0; -#ifdef HAL_EFUSE_MEMORY - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; -#endif - - if (bPseudoTest) { -#ifdef HAL_EFUSE_MEMORY - pEfuseHal->fakeEfuseBank = bank; -#else - fakeEfuseBank = bank; -#endif - bRet = true; - } else { - value32 = rtw_read32(padapter, EFUSE_TEST); - bRet = true; - switch (bank) { - case 0: - value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); - break; - case 1: - value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_0); - break; - case 2: - value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_1); - break; - case 3: - value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_2); - break; - default: - value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); - bRet = false; - break; - } - rtw_write32(padapter, EFUSE_TEST, value32); + value32 = rtw_read32(padapter, EFUSE_TEST); + bRet = true; + switch (bank) { + case 0: + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); + break; + case 1: + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_0); + break; + case 2: + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_1); + break; + case 3: + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_2); + break; + default: + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); + bRet = false; + break; } + rtw_write32(padapter, EFUSE_TEST, value32); return bRet; } @@ -692,7 +678,7 @@ static void hal_ReadEFuse_WiFi( memset(efuseTbl, 0xFF, EFUSE_MAX_MAP_LEN); /* switch bank back to bank 0 for later BT and wifi use. */ - hal_EfuseSwitchToBank(padapter, 0, false); + hal_EfuseSwitchToBank(padapter, 0); while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, false); @@ -782,7 +768,7 @@ static void hal_ReadEFuse_BT( Hal_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total); for (bank = 1; bank < 3; bank++) { /* 8723b Max bake 0~2 */ - if (hal_EfuseSwitchToBank(padapter, bank, false) == false) + if (hal_EfuseSwitchToBank(padapter, bank) == false) goto exit; eFuse_Addr = 0; @@ -833,7 +819,7 @@ static void hal_ReadEFuse_BT( } /* switch bank back to bank 0 for later BT and wifi use. */ - hal_EfuseSwitchToBank(padapter, 0, false); + hal_EfuseSwitchToBank(padapter, 0); /* Copy from Efuse map to output pointer memory!!! */ for (i = 0; i < _size_byte; i++) From 4558ec57bfa03b51438696bc971bd0559b759899 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:19 +0200 Subject: [PATCH 0947/2711] staging: rtl8723bs: clean up variable initializations After previous cleanup patches the variable initializations in hal_EfuseSwitchToBank are messed up a little, but were left as-is to make reviewing easier. For example bRet is initialized to false and immediately set to true. This patch cleans up the variable initializations. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-13-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 014d94894de9..ab30d2598825 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -448,11 +448,9 @@ static u8 hal_EfuseSwitchToBank( struct adapter *padapter, u8 bank ) { - u8 bRet = false; - u32 value32 = 0; + u8 bRet = true; + u32 value32 = rtw_read32(padapter, EFUSE_TEST); - value32 = rtw_read32(padapter, EFUSE_TEST); - bRet = true; switch (bank) { case 0: value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); From ca6e514b8a3f8b1258ec0ce04c219049a2ca4b9b Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 23 Aug 2025 14:43:20 +0200 Subject: [PATCH 0948/2711] staging: rtl8723bs: remove bPseudoTest from efuse_OneByteRead The function efuse_OneByteRead is always called with bPseudoTest set to false. Remove the pPseudoTest parameter and reomve resulting dead code to reduce code complexity. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-14-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 18 +----------------- .../staging/rtl8723bs/hal/rtl8723b_hal_init.c | 18 +++++++++--------- drivers/staging/rtl8723bs/include/rtw_efuse.h | 2 +- 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 9d065721c28a..c4542e00c730 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -29,18 +29,6 @@ u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; #define REG_EFUSE_CTRL 0x0030 #define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ -static bool -Efuse_Read1ByteFromFakeContent(u16 Offset, u8 *Value) -{ - if (Offset >= EFUSE_MAX_HW_SIZE) - return false; - if (fakeEfuseBank == 0) - *Value = fakeEfuseContent[Offset]; - else - *Value = fakeBTEfuseContent[fakeEfuseBank - 1][Offset]; - return true; -} - static bool Efuse_Write1ByteToFakeContent(u16 Offset, u8 Value) { @@ -158,16 +146,12 @@ u8 efuse_OneByteRead( struct adapter *padapter, u16 addr, -u8 *data, -bool bPseudoTest) +u8 *data) { u32 tmpidx = 0; u8 bResult; u8 readbyte; - if (bPseudoTest) - return Efuse_Read1ByteFromFakeContent(addr, data); - /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ /* PHY_SetMacReg(padapter, 0x34, BIT11, 0); */ diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index ab30d2598825..94492743ea34 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -679,7 +679,7 @@ static void hal_ReadEFuse_WiFi( hal_EfuseSwitchToBank(padapter, 0); while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { - efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, false); + efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader); if (efuseHeader == 0xFF) break; @@ -687,7 +687,7 @@ static void hal_ReadEFuse_WiFi( if (EXT_HEADER(efuseHeader)) { /* extended header */ offset = GET_HDR_OFFSET_2_0(efuseHeader); - efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr, false); + efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr); if (ALL_WORDS_DISABLED(efuseExtHdr)) continue; @@ -706,10 +706,10 @@ static void hal_ReadEFuse_WiFi( for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { /* Check word enable condition in the section */ if (!(wden & (0x01< Date: Sat, 23 Aug 2025 14:43:21 +0200 Subject: [PATCH 0949/2711] staging: rtl8723bs: remove efuse_OneByteWrite The function efuse_OneByteWrite is not used. Remove it and remove related dead code, namely the function Efuse_Write1ByteToFakeContent. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250823124321.485910-15-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 48 ------------------- drivers/staging/rtl8723bs/include/rtw_efuse.h | 1 - 2 files changed, 49 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index c4542e00c730..e39032b45c35 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -29,18 +29,6 @@ u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; #define REG_EFUSE_CTRL 0x0030 #define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ -static bool -Efuse_Write1ByteToFakeContent(u16 Offset, u8 Value) -{ - if (Offset >= EFUSE_MAX_HW_SIZE) - return false; - if (fakeEfuseBank == 0) - fakeEfuseContent[Offset] = Value; - else - fakeBTEfuseContent[fakeEfuseBank - 1][Offset] = Value; - return true; -} - /*----------------------------------------------------------------------------- * Function: Efuse_PowerSwitch * @@ -183,42 +171,6 @@ u8 *data) return bResult; } -/* 11/16/2008 MH Write one byte to reald Efuse. */ -u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoTest) -{ - u8 tmpidx = 0; - u8 bResult = false; - - if (bPseudoTest) - return Efuse_Write1ByteToFakeContent(addr, data); - - /* -----------------e-fuse reg ctrl --------------------------------- */ - /* address */ - - /* <20130227, Kordan> 8192E MP chip A-cut had better not set 0x34[11] until B-Cut. */ - - /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ - /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ - /* PHY_SetMacReg(padapter, 0x34, BIT11, 1); */ - rtw_write16(padapter, 0x34, rtw_read16(padapter, 0x34) | (BIT11)); - rtw_write32(padapter, EFUSE_CTRL, 0x90600000 | ((addr << 8 | data))); - - while ((0x80 & rtw_read8(padapter, EFUSE_CTRL + 3)) && (tmpidx < 100)) { - mdelay(1); - tmpidx++; - } - - if (tmpidx < 100) - bResult = true; - else - bResult = false; - - /* disable Efuse program enable */ - PHY_SetMacReg(padapter, EFUSE_TEST, BIT(11), 0); - - return bResult; -} - /*----------------------------------------------------------------------------- * Function: Efuse_ReadAllMap * diff --git a/drivers/staging/rtl8723bs/include/rtw_efuse.h b/drivers/staging/rtl8723bs/include/rtw_efuse.h index 1cee7a8eedf2..5251ecc855d7 100644 --- a/drivers/staging/rtl8723bs/include/rtw_efuse.h +++ b/drivers/staging/rtl8723bs/include/rtw_efuse.h @@ -92,7 +92,6 @@ extern u8 fakeBTEfuseModifiedMap[]; u8 Efuse_CalculateWordCnts(u8 word_en); u8 efuse_OneByteRead(struct adapter *padapter, u16 addr, u8 *data); -u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoTest); void Efuse_PowerSwitch(struct adapter *padapter, u8 bWrite, u8 PwrState); From 0149f27d1a248f013fe36d29bc391c303e853ee0 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:06 +0200 Subject: [PATCH 0950/2711] staging: rtl8723bs: remove wrapper rtw_init_recv_timer The function rtw_init_recv_timer in os_dep/recv_linux.c is jsut a wrapper around timer_setup. Use timer_setup directly and remove the wrapper to reduce code in the os_dep directory. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-2-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_sta_mgt.c | 4 +++- drivers/staging/rtl8723bs/include/recv_osdep.h | 3 --- drivers/staging/rtl8723bs/os_dep/recv_linux.c | 7 ------- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c index 4d51e6993ca2..d1f6030799cb 100644 --- a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c @@ -247,7 +247,9 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) INIT_LIST_HEAD(&preorder_ctrl->pending_recvframe_queue.queue); spin_lock_init(&preorder_ctrl->pending_recvframe_queue.lock); - rtw_init_recv_timer(preorder_ctrl); + /* init recv timer */ + timer_setup(&preorder_ctrl->reordering_ctrl_timer, + rtw_reordering_ctrl_timeout_handler, 0); } /* init for DM */ diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h index 83330ea98fbf..ea0b58aa0ba0 100644 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ b/drivers/staging/rtl8723bs/include/recv_osdep.h @@ -34,7 +34,4 @@ void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *pre struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata); void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib); -void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl); - - #endif /* */ diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index 98d3e4777210..a507a29686bd 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -216,10 +216,3 @@ _recv_indicatepkt_drop: return _FAIL; } - -void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl) -{ - timer_setup(&preorder_ctrl->reordering_ctrl_timer, - rtw_reordering_ctrl_timeout_handler, 0); - -} From f97151eb17dcdc8d7a27e05f2ec8c55bbb16c7a9 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:07 +0200 Subject: [PATCH 0951/2711] staging: rtl8723bs: move rtw_recv_indicatepkt to rtw_recv.c Move the function rtw_recv_indicatepkt from os_dep/recv_linux.c to core/rtw_recv.c to reduce code in the os_dep directory. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-3-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_recv.c | 37 +++++++++++++++++++ .../staging/rtl8723bs/include/recv_osdep.h | 1 - drivers/staging/rtl8723bs/os_dep/recv_linux.c | 37 ------------------- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 8ae527b6e0d6..bc34cac8dabe 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -1725,6 +1725,43 @@ static void recv_indicatepkts_pkt_loss_cnt(struct debug_priv *pdbgpriv, u64 prev } +static int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame) +{ + struct recv_priv *precvpriv; + struct __queue *pfree_recv_queue; + struct sk_buff *skb; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + + precvpriv = &(padapter->recvpriv); + pfree_recv_queue = &(precvpriv->free_recv_queue); + + skb = precv_frame->u.hdr.pkt; + if (!skb) + goto _recv_indicatepkt_drop; + + skb->data = precv_frame->u.hdr.rx_data; + + skb_set_tail_pointer(skb, precv_frame->u.hdr.len); + + skb->len = precv_frame->u.hdr.len; + + rtw_os_recv_indicate_pkt(padapter, skb, pattrib); + + /* pointers to NULL before rtw_free_recvframe() */ + precv_frame->u.hdr.pkt = NULL; + + rtw_free_recvframe(precv_frame, pfree_recv_queue); + + return _SUCCESS; + +_recv_indicatepkt_drop: + + /* enqueue back to free_recv_queue */ + rtw_free_recvframe(precv_frame, pfree_recv_queue); + + return _FAIL; +} + static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced) { struct list_head *phead, *plist; diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h index ea0b58aa0ba0..f31c87b21206 100644 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ b/drivers/staging/rtl8723bs/include/recv_osdep.h @@ -13,7 +13,6 @@ extern void _rtw_free_recv_priv(struct recv_priv *precvpriv); extern s32 rtw_recv_entry(union recv_frame *precv_frame); -extern int rtw_recv_indicatepkt(struct adapter *adapter, union recv_frame *precv_frame); extern void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *preturnedpkt); extern void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup); diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index a507a29686bd..ae396ccfd830 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -179,40 +179,3 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) memset(&wrqu, 0x00, sizeof(wrqu)); wrqu.data.length = sizeof(ev); } - -int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame) -{ - struct recv_priv *precvpriv; - struct __queue *pfree_recv_queue; - struct sk_buff *skb; - struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - - precvpriv = &(padapter->recvpriv); - pfree_recv_queue = &(precvpriv->free_recv_queue); - - skb = precv_frame->u.hdr.pkt; - if (!skb) - goto _recv_indicatepkt_drop; - - skb->data = precv_frame->u.hdr.rx_data; - - skb_set_tail_pointer(skb, precv_frame->u.hdr.len); - - skb->len = precv_frame->u.hdr.len; - - rtw_os_recv_indicate_pkt(padapter, skb, pattrib); - - /* pointers to NULL before rtw_free_recvframe() */ - precv_frame->u.hdr.pkt = NULL; - - rtw_free_recvframe(precv_frame, pfree_recv_queue); - - return _SUCCESS; - -_recv_indicatepkt_drop: - - /* enqueue back to free_recv_queue */ - rtw_free_recvframe(precv_frame, pfree_recv_queue); - - return _FAIL; -} From 9766096c1e0552ebe664865f16b7de61f4e8014f Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:08 +0200 Subject: [PATCH 0952/2711] staging: rtl8723bs: move rtw_handle_tkip_mic_err to rtw_recv.c Move the function rtw_handle_tkip_mic_err from os_dep/recv_linux.c to core/rtw_recv.c to reduce code in the os_dep directory. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-4-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_recv.c | 44 +++++++++++++++++++ .../staging/rtl8723bs/include/recv_osdep.h | 2 - drivers/staging/rtl8723bs/os_dep/recv_linux.c | 44 ------------------- 3 files changed, 44 insertions(+), 46 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index bc34cac8dabe..b043e3d1cd82 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -294,6 +294,50 @@ struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue) } +static void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) +{ + enum nl80211_key_type key_type = 0; + union iwreq_data wrqu; + struct iw_michaelmicfailure ev; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + unsigned long cur_time = 0; + + if (psecuritypriv->last_mic_err_time == 0) { + psecuritypriv->last_mic_err_time = jiffies; + } else { + cur_time = jiffies; + + if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) { + psecuritypriv->btkip_countermeasure = true; + psecuritypriv->last_mic_err_time = 0; + psecuritypriv->btkip_countermeasure_time = cur_time; + } else { + psecuritypriv->last_mic_err_time = jiffies; + } + } + + if (bgroup) + key_type |= NL80211_KEYTYPE_GROUP; + else + key_type |= NL80211_KEYTYPE_PAIRWISE; + + cfg80211_michael_mic_failure(padapter->pnetdev, (u8 *)&pmlmepriv->assoc_bssid[0], key_type, -1, + NULL, GFP_ATOMIC); + + memset(&ev, 0x00, sizeof(ev)); + if (bgroup) + ev.flags |= IW_MICFAILURE_GROUP; + else + ev.flags |= IW_MICFAILURE_PAIRWISE; + + ev.src_addr.sa_family = ARPHRD_ETHER; + memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + + memset(&wrqu, 0x00, sizeof(wrqu)); + wrqu.data.length = sizeof(ev); +} + static signed int recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe) { diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h index f31c87b21206..91fb275cbcaf 100644 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ b/drivers/staging/rtl8723bs/include/recv_osdep.h @@ -15,8 +15,6 @@ extern void _rtw_free_recv_priv(struct recv_priv *precvpriv); extern s32 rtw_recv_entry(union recv_frame *precv_frame); extern void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *preturnedpkt); -extern void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup); - int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); void rtw_free_recv_priv(struct recv_priv *precvpriv); diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index ae396ccfd830..72fd86e03b5c 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -135,47 +135,3 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, str rtw_netif_rx(padapter->pnetdev, pkt); } } - -void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) -{ - enum nl80211_key_type key_type = 0; - union iwreq_data wrqu; - struct iw_michaelmicfailure ev; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct security_priv *psecuritypriv = &padapter->securitypriv; - unsigned long cur_time = 0; - - if (psecuritypriv->last_mic_err_time == 0) { - psecuritypriv->last_mic_err_time = jiffies; - } else { - cur_time = jiffies; - - if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) { - psecuritypriv->btkip_countermeasure = true; - psecuritypriv->last_mic_err_time = 0; - psecuritypriv->btkip_countermeasure_time = cur_time; - } else { - psecuritypriv->last_mic_err_time = jiffies; - } - } - - if (bgroup) - key_type |= NL80211_KEYTYPE_GROUP; - else - key_type |= NL80211_KEYTYPE_PAIRWISE; - - cfg80211_michael_mic_failure(padapter->pnetdev, (u8 *)&pmlmepriv->assoc_bssid[0], key_type, -1, - NULL, GFP_ATOMIC); - - memset(&ev, 0x00, sizeof(ev)); - if (bgroup) - ev.flags |= IW_MICFAILURE_GROUP; - else - ev.flags |= IW_MICFAILURE_PAIRWISE; - - ev.src_addr.sa_family = ARPHRD_ETHER; - memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0], ETH_ALEN); - - memset(&wrqu, 0x00, sizeof(wrqu)); - wrqu.data.length = sizeof(ev); -} From d91ccaaf09a2131d20ac02b2c4d00c7025bd6d97 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:09 +0200 Subject: [PATCH 0953/2711] staging: rtl8723bs: merge rtw_os_free_recvframe into rtw_recv.c Merge the functionality of rtw_os_free_recvframe in os_dep/recv_linux.c into rtw_free_recvframe in core/rtw_recv.c to reduce code in the os_dep directory. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-5-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_recv.c | 6 ++++-- drivers/staging/rtl8723bs/include/recv_osdep.h | 4 ---- drivers/staging/rtl8723bs/os_dep/recv_linux.c | 9 --------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index b043e3d1cd82..2b054525b3fd 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -147,8 +147,10 @@ int rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_ struct adapter *padapter = precvframe->u.hdr.adapter; struct recv_priv *precvpriv = &padapter->recvpriv; - rtw_os_free_recvframe(precvframe); - + if (precvframe->u.hdr.pkt) { + dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */ + precvframe->u.hdr.pkt = NULL; + } spin_lock_bh(&pfree_recv_queue->lock); diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h index 91fb275cbcaf..51b52d6b0367 100644 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ b/drivers/staging/rtl8723bs/include/recv_osdep.h @@ -22,10 +22,6 @@ void rtw_free_recv_priv(struct recv_priv *precvpriv); void rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe); void rtw_os_recv_resource_free(struct recv_priv *precvpriv); - -void rtw_os_free_recvframe(union recv_frame *precvframe); - - void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf); struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata); diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index 72fd86e03b5c..c5819c3c59d8 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -9,15 +9,6 @@ #include #include -void rtw_os_free_recvframe(union recv_frame *precvframe) -{ - if (precvframe->u.hdr.pkt) { - dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */ - - precvframe->u.hdr.pkt = NULL; - } -} - /* alloc os related resource in union recv_frame */ void rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe) { From aec747851b73828a84fc8d6a7c02743bbb51ffd9 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:10 +0200 Subject: [PATCH 0954/2711] staging: rtl8723bs: merge rtw_os_recv_resource_alloc into rtw_recv.c Merge the functionality of rtw_os_recv_resource_alloc into _rtw_init_recv_priv to reduce code in the os_dep directory. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-6-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_recv.c | 3 ++- drivers/staging/rtl8723bs/include/recv_osdep.h | 1 - drivers/staging/rtl8723bs/os_dep/recv_linux.c | 6 ------ 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 2b054525b3fd..fcc28d4556c5 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -66,7 +66,8 @@ signed int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *pada list_add_tail(&(precvframe->u.list), &(precvpriv->free_recv_queue.queue)); - rtw_os_recv_resource_alloc(padapter, precvframe); + precvframe->u.hdr.pkt_newalloc = NULL; + precvframe->u.hdr.pkt = NULL; precvframe->u.hdr.len = 0; diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h index 51b52d6b0367..763ddef4ad90 100644 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ b/drivers/staging/rtl8723bs/include/recv_osdep.h @@ -19,7 +19,6 @@ int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); void rtw_free_recv_priv(struct recv_priv *precvpriv); -void rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe); void rtw_os_recv_resource_free(struct recv_priv *precvpriv); void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf); diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index c5819c3c59d8..ccd00f8bee7e 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -9,12 +9,6 @@ #include #include -/* alloc os related resource in union recv_frame */ -void rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe) -{ - precvframe->u.hdr.pkt_newalloc = precvframe->u.hdr.pkt = NULL; -} - /* free os related resource in union recv_frame */ void rtw_os_recv_resource_free(struct recv_priv *precvpriv) { From 0ae5ca4fb6150c7f61849436eb53493a2dd69c9b Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:11 +0200 Subject: [PATCH 0955/2711] staging: rtl8723bs: merge rtw_os_recv_resource_free into rtw_recv.c Merge the functionality of rtw_os_recv_resource_free in os_dep/recv_linux.c into _rtw_free_recv_priv in core/rtw_recv.c to reduce code in the os_dep directory. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-7-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_recv.c | 13 ++++++++++++- drivers/staging/rtl8723bs/include/recv_osdep.h | 3 --- drivers/staging/rtl8723bs/os_dep/recv_linux.c | 18 ------------------ 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index fcc28d4556c5..cda51aab752d 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -91,11 +91,22 @@ exit: void _rtw_free_recv_priv(struct recv_priv *precvpriv) { + signed int i; + union recv_frame *precvframe; struct adapter *padapter = precvpriv->adapter; rtw_free_uc_swdec_pending_queue(padapter); - rtw_os_recv_resource_free(precvpriv); + precvframe = (union recv_frame *)precvpriv->precv_frame_buf; + + for (i = 0; i < NR_RECVFRAME; i++) { + if (precvframe->u.hdr.pkt) { + /* free skb by driver */ + dev_kfree_skb_any(precvframe->u.hdr.pkt); + precvframe->u.hdr.pkt = NULL; + } + precvframe++; + } vfree(precvpriv->pallocated_frame_buf); diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h index 763ddef4ad90..9b3f4e8293ee 100644 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ b/drivers/staging/rtl8723bs/include/recv_osdep.h @@ -18,9 +18,6 @@ extern void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *pretu int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); void rtw_free_recv_priv(struct recv_priv *precvpriv); - -void rtw_os_recv_resource_free(struct recv_priv *precvpriv); - void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf); struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata); diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index ccd00f8bee7e..c71e0c762f4f 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -9,24 +9,6 @@ #include #include -/* free os related resource in union recv_frame */ -void rtw_os_recv_resource_free(struct recv_priv *precvpriv) -{ - signed int i; - union recv_frame *precvframe; - - precvframe = (union recv_frame *) precvpriv->precv_frame_buf; - - for (i = 0; i < NR_RECVFRAME; i++) { - if (precvframe->u.hdr.pkt) { - /* free skb by driver */ - dev_kfree_skb_any(precvframe->u.hdr.pkt); - precvframe->u.hdr.pkt = NULL; - } - precvframe++; - } -} - /* free os related resource in struct recv_buf */ void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf) { From 10bcaf9ccce11823089cf11cca54100f0f6bdfae Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:12 +0200 Subject: [PATCH 0956/2711] staging: rtl8723bs: merge rtw_os_recvbuf_resource_free into rtl8723bs_recv.c Merge rtw_os_recvbuf_resource_free into rtl8723bs_init_recv_priv and into rtl8723bs_free_recv_priv to reduce code in the os_dep directory. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-8-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c | 6 ++++-- drivers/staging/rtl8723bs/include/recv_osdep.h | 2 -- drivers/staging/rtl8723bs/os_dep/recv_linux.c | 7 ------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c index 28c914ec2604..399edfbf8ec6 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c @@ -431,7 +431,8 @@ initbuferror: precvpriv->free_recv_buf_queue_cnt = 0; for (i = 0; i < n ; i++) { list_del_init(&precvbuf->list); - rtw_os_recvbuf_resource_free(padapter, precvbuf); + if (precvbuf->pskb) + dev_kfree_skb_any(precvbuf->pskb); precvbuf++; } precvpriv->precv_buf = NULL; @@ -467,7 +468,8 @@ void rtl8723bs_free_recv_priv(struct adapter *padapter) precvpriv->free_recv_buf_queue_cnt = 0; for (i = 0; i < NR_RECVBUFF; i++) { list_del_init(&precvbuf->list); - rtw_os_recvbuf_resource_free(padapter, precvbuf); + if (precvbuf->pskb) + dev_kfree_skb_any(precvbuf->pskb); precvbuf++; } precvpriv->precv_buf = NULL; diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h index 9b3f4e8293ee..227e172bf1c3 100644 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ b/drivers/staging/rtl8723bs/include/recv_osdep.h @@ -18,8 +18,6 @@ extern void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *pretu int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); void rtw_free_recv_priv(struct recv_priv *precvpriv); -void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf); - struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata); void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib); diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index c71e0c762f4f..ebe169507dc8 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -9,13 +9,6 @@ #include #include -/* free os related resource in struct recv_buf */ -void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf) -{ - if (precvbuf->pskb) - dev_kfree_skb_any(precvbuf->pskb); -} - struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata) { u16 eth_type; From f44d85d5a2e0518289dde7d8f95312207c4998bc Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:13 +0200 Subject: [PATCH 0957/2711] staging: rtl8723bs: move rtw_os_alloc_msdu_pkt to rtw_recv.c Move the function rtw_os_alloc_msdu_pkt from os_dep/recv_linux.c to core/rtw_recv.c to reduce code in the os_dep directory. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-9-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_recv.c | 40 +++++++++++++++++++ .../staging/rtl8723bs/include/recv_osdep.h | 1 - drivers/staging/rtl8723bs/os_dep/recv_linux.c | 40 ------------------- 3 files changed, 40 insertions(+), 41 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index cda51aab752d..4947099d8595 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -1622,6 +1622,46 @@ static signed int wlanhdr_to_ethhdr(union recv_frame *precvframe) return _SUCCESS; } +static struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata) +{ + u16 eth_type; + struct sk_buff *sub_skb; + struct rx_pkt_attrib *pattrib; + + pattrib = &prframe->u.hdr.attrib; + + sub_skb = rtw_skb_alloc(nSubframe_Length + 12); + if (!sub_skb) + return NULL; + + skb_reserve(sub_skb, 12); + skb_put_data(sub_skb, (pdata + ETH_HLEN), nSubframe_Length); + + eth_type = get_unaligned_be16(&sub_skb->data[6]); + + if (sub_skb->len >= 8 && + ((!memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) && + eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || + !memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE))) { + /* + * remove RFC1042 or Bridge-Tunnel encapsulation and replace + * EtherType + */ + skb_pull(sub_skb, SNAP_SIZE); + memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); + } else { + __be16 len; + /* Leave Ethernet header part of hdr and full payload */ + len = htons(sub_skb->len); + memcpy(skb_push(sub_skb, 2), &len, 2); + memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); + } + + return sub_skb; +} + static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) { int a_len, padding_len; diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h index 227e172bf1c3..1e332ea63207 100644 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ b/drivers/staging/rtl8723bs/include/recv_osdep.h @@ -18,7 +18,6 @@ extern void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *pretu int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); void rtw_free_recv_priv(struct recv_priv *precvpriv); -struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata); void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib); #endif /* */ diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index ebe169507dc8..4d3a42f6f9ad 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -9,46 +9,6 @@ #include #include -struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata) -{ - u16 eth_type; - struct sk_buff *sub_skb; - struct rx_pkt_attrib *pattrib; - - pattrib = &prframe->u.hdr.attrib; - - sub_skb = rtw_skb_alloc(nSubframe_Length + 12); - if (!sub_skb) - return NULL; - - skb_reserve(sub_skb, 12); - skb_put_data(sub_skb, (pdata + ETH_HLEN), nSubframe_Length); - - eth_type = get_unaligned_be16(&sub_skb->data[6]); - - if (sub_skb->len >= 8 && - ((!memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) && - eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || - !memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE))) { - /* - * remove RFC1042 or Bridge-Tunnel encapsulation and replace - * EtherType - */ - skb_pull(sub_skb, SNAP_SIZE); - memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); - memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); - } else { - __be16 len; - /* Leave Ethernet header part of hdr and full payload */ - len = htons(sub_skb->len); - memcpy(skb_push(sub_skb, 2), &len, 2); - memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); - memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); - } - - return sub_skb; -} - void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; From b870844cd0c9aac60edffd6be08218ffd5afd6fc Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:14 +0200 Subject: [PATCH 0958/2711] staging: rtl8723bs: rename rtw_os_alloc_msdu_pkt Rename rtw_os_alloc_msdu_pkt to rtw_alloc_msdu_pkt as the _os_ indicates operating system dependent code which is unnecessary for in-tree linux kernel code. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-10-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 4947099d8595..a8b388822719 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -1622,7 +1622,7 @@ static signed int wlanhdr_to_ethhdr(union recv_frame *precvframe) return _SUCCESS; } -static struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata) +static struct sk_buff *rtw_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata) { u16 eth_type; struct sk_buff *sub_skb; @@ -1691,7 +1691,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) if (a_len < ETH_HLEN + nSubframe_Length) break; - sub_pkt = rtw_os_alloc_msdu_pkt(prframe, nSubframe_Length, pdata); + sub_pkt = rtw_alloc_msdu_pkt(prframe, nSubframe_Length, pdata); if (!sub_pkt) break; From cc18433094733778a07b9dfebc86c9ec4f86d477 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:15 +0200 Subject: [PATCH 0959/2711] staging: rtl8723bs: move rtw_os_recv_indicate_pkt to rtw_recv.c Move the function rtw_os_recv_indicate_pkt from os_dep/recv_linux.c to core/rtw_recv.c to reduce code in the os_dep directory. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-11-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_recv.c | 47 +++++++++++++++++++ .../staging/rtl8723bs/include/recv_osdep.h | 2 - drivers/staging/rtl8723bs/os_dep/recv_linux.c | 45 ------------------ 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index a8b388822719..924a0c415a1e 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -1662,6 +1662,53 @@ static struct sk_buff *rtw_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubfra return sub_skb; } +static void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + /* Indicate the packets to upper layer */ + if (pkt) { + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { + struct sk_buff *pskb2 = NULL; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + int bmcast = is_multicast_ether_addr(pattrib->dst); + + if (memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN)) { + if (bmcast) { + psta = rtw_get_bcmc_stainfo(padapter); + pskb2 = skb_clone(pkt, GFP_ATOMIC); + } else { + psta = rtw_get_stainfo(pstapriv, pattrib->dst); + } + + if (psta) { + struct net_device *pnetdev = (struct net_device *)padapter->pnetdev; + /* skb->ip_summed = CHECKSUM_NONE; */ + pkt->dev = pnetdev; + skb_set_queue_mapping(pkt, rtw_recv_select_queue(pkt)); + + _rtw_xmit_entry(pkt, pnetdev); + + if (bmcast && pskb2) + pkt = pskb2; + else + return; + } + } else { + /* to APself */ + } + } + + pkt->protocol = eth_type_trans(pkt, padapter->pnetdev); + pkt->dev = padapter->pnetdev; + + pkt->ip_summed = CHECKSUM_NONE; + + rtw_netif_rx(padapter->pnetdev, pkt); + } +} + static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) { int a_len, padding_len; diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h index 1e332ea63207..20ce25132700 100644 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ b/drivers/staging/rtl8723bs/include/recv_osdep.h @@ -18,6 +18,4 @@ extern void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *pretu int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); void rtw_free_recv_priv(struct recv_priv *precvpriv); -void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib); - #endif /* */ diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index 4d3a42f6f9ad..193725cc60bc 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -9,49 +9,4 @@ #include #include -void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib) -{ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - /* Indicate the packets to upper layer */ - if (pkt) { - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { - struct sk_buff *pskb2 = NULL; - struct sta_info *psta = NULL; - struct sta_priv *pstapriv = &padapter->stapriv; - int bmcast = is_multicast_ether_addr(pattrib->dst); - - if (memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN)) { - if (bmcast) { - psta = rtw_get_bcmc_stainfo(padapter); - pskb2 = skb_clone(pkt, GFP_ATOMIC); - } else { - psta = rtw_get_stainfo(pstapriv, pattrib->dst); - } - - if (psta) { - struct net_device *pnetdev = (struct net_device *)padapter->pnetdev; - /* skb->ip_summed = CHECKSUM_NONE; */ - pkt->dev = pnetdev; - skb_set_queue_mapping(pkt, rtw_recv_select_queue(pkt)); - - _rtw_xmit_entry(pkt, pnetdev); - - if (bmcast && pskb2) - pkt = pskb2; - else - return; - } - } else { - /* to APself */ - } - } - - pkt->protocol = eth_type_trans(pkt, padapter->pnetdev); - pkt->dev = padapter->pnetdev; - - pkt->ip_summed = CHECKSUM_NONE; - - rtw_netif_rx(padapter->pnetdev, pkt); - } -} From 1d7e13c8b7dbfa581ed06088201f22fb9d1216ab Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:16 +0200 Subject: [PATCH 0960/2711] staging: rtl8723bs: rename rtw_os_recv_indicate_pkt Rename rtw_os_recv_indicate_pkt to rtw_recv_indicate_pkt as the _os_ indicates operating system dependent code which is unnecessary for in-tree linux kernel code. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-12-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_recv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 924a0c415a1e..e893cb6fa273 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -1662,7 +1662,7 @@ static struct sk_buff *rtw_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubfra return sub_skb; } -static void rtw_os_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib) +static void rtw_recv_indicate_pkt(struct adapter *padapter, struct sk_buff *pkt, struct rx_pkt_attrib *pattrib) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -1771,7 +1771,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe) /* Indicate the packets to upper layer */ if (sub_pkt) - rtw_os_recv_indicate_pkt(padapter, sub_pkt, &prframe->u.hdr.attrib); + rtw_recv_indicate_pkt(padapter, sub_pkt, &prframe->u.hdr.attrib); } prframe->u.hdr.len = 0; @@ -1890,7 +1890,7 @@ static int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *prec skb->len = precv_frame->u.hdr.len; - rtw_os_recv_indicate_pkt(padapter, skb, pattrib); + rtw_recv_indicate_pkt(padapter, skb, pattrib); /* pointers to NULL before rtw_free_recvframe() */ precv_frame->u.hdr.pkt = NULL; From 6009d6fd826d70849e2a0f0a288dbc37b28345d5 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:17 +0200 Subject: [PATCH 0961/2711] staging: rtl8723bs: remove os_dep/recv_linux.c After previous patches the file os_dep/recv_linux.c is empty now and we can remove it. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-13-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/Makefile | 1 - drivers/staging/rtl8723bs/os_dep/recv_linux.c | 12 ------------ 2 files changed, 13 deletions(-) delete mode 100644 drivers/staging/rtl8723bs/os_dep/recv_linux.c diff --git a/drivers/staging/rtl8723bs/Makefile b/drivers/staging/rtl8723bs/Makefile index 19c0525ec3e0..1768b8123f03 100644 --- a/drivers/staging/rtl8723bs/Makefile +++ b/drivers/staging/rtl8723bs/Makefile @@ -50,7 +50,6 @@ r8723bs-y = \ os_dep/ioctl_cfg80211.o \ os_dep/osdep_service.o \ os_dep/os_intfs.o \ - os_dep/recv_linux.o \ os_dep/sdio_intf.o \ os_dep/sdio_ops_linux.o \ os_dep/wifi_regd.o \ diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c deleted file mode 100644 index 193725cc60bc..000000000000 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * - * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#include -#include -#include -#include - - From 533656d39ffd2468266de5e28bc2c340c230b66d Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 22 Aug 2025 15:54:18 +0200 Subject: [PATCH 0962/2711] staging: rtl8723bs: remove include/recv_osdep.h Move still needed function prototypes defined in the recv_osdep.h header to rtw_recv.h and remove the now obsolete recv_osdep.h. Signed-off-by: Michael Straube Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20250822135418.118115-14-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/include/drv_types.h | 1 - .../staging/rtl8723bs/include/recv_osdep.h | 21 ------------------- drivers/staging/rtl8723bs/include/rtw_recv.h | 4 ++++ 3 files changed, 4 insertions(+), 22 deletions(-) delete mode 100644 drivers/staging/rtl8723bs/include/recv_osdep.h diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h index f1c16ddacc83..dd9018aa4ee5 100644 --- a/drivers/staging/rtl8723bs/include/drv_types.h +++ b/drivers/staging/rtl8723bs/include/drv_types.h @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h deleted file mode 100644 index 20ce25132700..000000000000 --- a/drivers/staging/rtl8723bs/include/recv_osdep.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RECV_OSDEP_H_ -#define __RECV_OSDEP_H_ - - -extern signed int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); -extern void _rtw_free_recv_priv(struct recv_priv *precvpriv); - - -extern s32 rtw_recv_entry(union recv_frame *precv_frame); -extern void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *preturnedpkt); - -int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); -void rtw_free_recv_priv(struct recv_priv *precvpriv); - -#endif /* */ diff --git a/drivers/staging/rtl8723bs/include/rtw_recv.h b/drivers/staging/rtl8723bs/include/rtw_recv.h index aa9f9d5ecd01..8e45871f07f0 100644 --- a/drivers/staging/rtl8723bs/include/rtw_recv.h +++ b/drivers/staging/rtl8723bs/include/rtw_recv.h @@ -342,6 +342,10 @@ struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue); void rtw_reordering_ctrl_timeout_handler(struct timer_list *t); +signed int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); +void _rtw_free_recv_priv(struct recv_priv *precvpriv); +s32 rtw_recv_entry(union recv_frame *precv_frame); + static inline u8 *get_rxmem(union recv_frame *precvframe) { /* always return rx_head... */ From 9d78ee44a9d717db66156f40856f201c8618f2b0 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Tue, 26 Aug 2025 20:32:01 +0800 Subject: [PATCH 0963/2711] staging: gpib: use int type to store negative error codes The "ret" variable is used to store the return from bb_write() returns either zero on success or negative error codes on failure. Storing the error codes in size_t which is an unsigned long, doesn't cause an issue at runtime but it's ugly as pants. Change "ret" from size_t to int type. No effect on runtime. Signed-off-by: Qianfeng Rong Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20250826123208.300145-1-rongqianfeng@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/gpib/gpio/gpib_bitbang.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/gpib/gpio/gpib_bitbang.c b/drivers/staging/gpib/gpio/gpib_bitbang.c index 22a55f3f794d..374cd61355e9 100644 --- a/drivers/staging/gpib/gpio/gpib_bitbang.c +++ b/drivers/staging/gpib/gpio/gpib_bitbang.c @@ -726,7 +726,7 @@ static irqreturn_t bb_SRQ_interrupt(int irq, void *arg) static int bb_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written) { - size_t ret; + int ret; struct bb_priv *priv = board->private_data; int i; From 0bbf8fb9e3e624d44b536de71a93f995b7edc7a5 Mon Sep 17 00:00:00 2001 From: yingche Date: Fri, 29 Aug 2025 12:09:06 +0800 Subject: [PATCH 0964/2711] staging: rtl8723bs: fix fortify warnings by using struct_group Fix fortify_memcpy_chk warnings in rtw_BIP_verify() and rtw_mgmt_xmitframe_coalesce() functions by using struct_group to access consecutive address fields. Changed memcpy calls to use &hdr->addrs instead of hdr->addr1 when copying 18 bytes (addr1 + addr2 + addr3). This resolves 'detected read beyond size of field' warnings by using the proper struct_group mechanism as suggested by the compiler. Signed-off-by: yingche Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20250829040906.895221-1-zxcv2569763104@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_security.c | 2 +- drivers/staging/rtl8723bs/core/rtw_xmit.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index 8367fd15c6b1..3d99d045f4b6 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -1363,7 +1363,7 @@ u32 rtw_BIP_verify(struct adapter *padapter, u8 *precvframe) ClearPwrMgt(BIP_AAD); ClearMData(BIP_AAD); /* conscruct AAD, copy address 1 to address 3 */ - memcpy(BIP_AAD+2, pwlanhdr->addr1, 18); + memcpy(BIP_AAD + 2, &pwlanhdr->addrs, sizeof(pwlanhdr->addrs)); if (omac1_aes_128(padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey , BIP_AAD, ori_len, mic)) diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index 8c6841f078b4..21690857fd62 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -1209,7 +1209,7 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, s ClearPwrMgt(BIP_AAD); ClearMData(BIP_AAD); /* conscruct AAD, copy address 1 to address 3 */ - memcpy(BIP_AAD+2, pwlanhdr->addr1, 18); + memcpy(BIP_AAD + 2, &pwlanhdr->addrs, sizeof(pwlanhdr->addrs)); /* copy management fram body */ memcpy(BIP_AAD+BIP_AAD_SIZE, MGMT_body, frame_body_len); /* calculate mic */ From 5ff310ce43b8750e605ded5f81d7c258c9719923 Mon Sep 17 00:00:00 2001 From: Mohammed GUERMOUD Date: Fri, 29 Aug 2025 18:02:53 +0100 Subject: [PATCH 0965/2711] staging: octeon: Clean up dead code in ethernet-tx.c Remove multiple blocks of non-functional code disabled via '#if 0'. The removed code was a placeholder for incomplete hardware offload features, as indicated by `FIXME` comments. Remove this dead code to simplify the driver. Signed-off-by: Mohammed GUERMOUD Link: https://lore.kernel.org/r/20250829170253.16737-1-mohammed.guermoud@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/octeon/ethernet-tx.c | 40 ---------------------------- 1 file changed, 40 deletions(-) diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 261f8dbdc382..c659b69bac24 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -574,42 +574,14 @@ netdev_tx_t cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) if (skb->protocol == htons(ETH_P_IP)) { work->word2.s.ip_offset = 14; -#if 0 - work->word2.s.vlan_valid = 0; /* FIXME */ - work->word2.s.vlan_cfi = 0; /* FIXME */ - work->word2.s.vlan_id = 0; /* FIXME */ - work->word2.s.dec_ipcomp = 0; /* FIXME */ -#endif work->word2.s.tcp_or_udp = (ip_hdr(skb)->protocol == IPPROTO_TCP) || (ip_hdr(skb)->protocol == IPPROTO_UDP); -#if 0 - /* FIXME */ - work->word2.s.dec_ipsec = 0; - /* We only support IPv4 right now */ - work->word2.s.is_v6 = 0; - /* Hardware would set to zero */ - work->word2.s.software = 0; - /* No error, packet is internal */ - work->word2.s.L4_error = 0; -#endif work->word2.s.is_frag = !((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == cpu_to_be16(1 << 14))); -#if 0 - /* Assume Linux is sending a good packet */ - work->word2.s.IP_exc = 0; -#endif work->word2.s.is_bcast = (skb->pkt_type == PACKET_BROADCAST); work->word2.s.is_mcast = (skb->pkt_type == PACKET_MULTICAST); -#if 0 - /* This is an IP packet */ - work->word2.s.not_IP = 0; - /* No error, packet is internal */ - work->word2.s.rcv_error = 0; - /* No error, packet is internal */ - work->word2.s.err_code = 0; -#endif /* * When copying the data, include 4 bytes of the @@ -619,12 +591,6 @@ netdev_tx_t cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) memcpy(work->packet_data, skb->data + 10, sizeof(work->packet_data)); } else { -#if 0 - work->word2.snoip.vlan_valid = 0; /* FIXME */ - work->word2.snoip.vlan_cfi = 0; /* FIXME */ - work->word2.snoip.vlan_id = 0; /* FIXME */ - work->word2.snoip.software = 0; /* Hardware would set to zero */ -#endif work->word2.snoip.is_rarp = skb->protocol == htons(ETH_P_RARP); work->word2.snoip.is_arp = skb->protocol == htons(ETH_P_ARP); work->word2.snoip.is_bcast = @@ -632,12 +598,6 @@ netdev_tx_t cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) work->word2.snoip.is_mcast = (skb->pkt_type == PACKET_MULTICAST); work->word2.snoip.not_IP = 1; /* IP was done up above */ -#if 0 - /* No error, packet is internal */ - work->word2.snoip.rcv_error = 0; - /* No error, packet is internal */ - work->word2.snoip.err_code = 0; -#endif memcpy(work->packet_data, skb->data, sizeof(work->packet_data)); } From 009798ff04f752a5d820c9341f1d2269672393f9 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sun, 24 Aug 2025 11:58:27 +0200 Subject: [PATCH 0966/2711] staging: rtl8723bs: remove wrapper Efuse_PowerSwitch The function Efuse_PowerSwitch is just a wrapper around Hal_EfusePowerSwitch. Remove the wrapper and use Hal_EfusePowerSwitch directly. Signed-off-by: Michael Straube Tested-by: Philipp Hortmann # Trendbook Next 14 Link: https://lore.kernel.org/r/20250824095830.79233-2-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 31 ++----------------- .../staging/rtl8723bs/hal/rtl8723b_hal_init.c | 4 +-- drivers/staging/rtl8723bs/include/rtw_efuse.h | 2 -- 3 files changed, 4 insertions(+), 33 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index e39032b45c35..f0c705ccdbdc 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -29,33 +29,6 @@ u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; #define REG_EFUSE_CTRL 0x0030 #define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ -/*----------------------------------------------------------------------------- - * Function: Efuse_PowerSwitch - * - * Overview: When we want to enable write operation, we should change to - * pwr on state. When we stop write, we should switch to 500k mode - * and disable LDO 2.5V. - * - * Input: NONE - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - * When Who Remark - * 11/17/2008 MHC Create Version 0. - * - */ -void -Efuse_PowerSwitch( -struct adapter *padapter, -u8 bWrite, -u8 PwrState) -{ - Hal_EfusePowerSwitch(padapter, bWrite, PwrState); -} - /* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ u8 Efuse_CalculateWordCnts(u8 word_en) @@ -191,13 +164,13 @@ static void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse) { u16 mapLen = 0; - Efuse_PowerSwitch(padapter, false, true); + Hal_EfusePowerSwitch(padapter, false, true); Hal_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen); Hal_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse); - Efuse_PowerSwitch(padapter, false, false); + Hal_EfusePowerSwitch(padapter, false, false); } /*----------------------------------------------------------------------------- diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 94492743ea34..66ba3bcd22e4 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -1474,9 +1474,9 @@ void Hal_EfuseParsePackageType_8723B( u8 package; u8 efuseContent; - Efuse_PowerSwitch(padapter, false, true); + Hal_EfusePowerSwitch(padapter, false, true); efuse_OneByteRead(padapter, 0x1FB, &efuseContent); - Efuse_PowerSwitch(padapter, false, false); + Hal_EfusePowerSwitch(padapter, false, false); package = efuseContent & 0x7; switch (package) { diff --git a/drivers/staging/rtl8723bs/include/rtw_efuse.h b/drivers/staging/rtl8723bs/include/rtw_efuse.h index 5251ecc855d7..904369705ed7 100644 --- a/drivers/staging/rtl8723bs/include/rtw_efuse.h +++ b/drivers/staging/rtl8723bs/include/rtw_efuse.h @@ -93,8 +93,6 @@ extern u8 fakeBTEfuseModifiedMap[]; u8 Efuse_CalculateWordCnts(u8 word_en); u8 efuse_OneByteRead(struct adapter *padapter, u16 addr, u8 *data); -void Efuse_PowerSwitch(struct adapter *padapter, u8 bWrite, u8 PwrState); - u8 EFUSE_Read1Byte(struct adapter *padapter, u16 Address); void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType); void EFUSE_ShadowRead(struct adapter *padapter, u8 Type, u16 Offset, u32 *Value); From 236faa3b92d33652233bce1136e043703a71d1d6 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sun, 24 Aug 2025 11:58:28 +0200 Subject: [PATCH 0967/2711] staging: rtl8723bs: remove bWrite from Hal_EfusePowerSwitch The function Hal_EfusePowerSwitch is always called with bWrite set to false. Remove the pWrite parameter and reomve resulting dead code to reduce code complexity. Signed-off-by: Michael Straube Tested-by: Philipp Hortmann # Trendbook Next 14 Link: https://lore.kernel.org/r/20250824095830.79233-3-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 4 +-- .../staging/rtl8723bs/hal/rtl8723b_hal_init.c | 25 +++---------------- drivers/staging/rtl8723bs/include/hal_intf.h | 2 +- 3 files changed, 6 insertions(+), 25 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index f0c705ccdbdc..d5c53b614f61 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -164,13 +164,13 @@ static void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse) { u16 mapLen = 0; - Hal_EfusePowerSwitch(padapter, false, true); + Hal_EfusePowerSwitch(padapter, true); Hal_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen); Hal_ReadEFuse(padapter, efuseType, 0, mapLen, Efuse); - Hal_EfusePowerSwitch(padapter, false, false); + Hal_EfusePowerSwitch(padapter, false); } /*----------------------------------------------------------------------------- diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 66ba3bcd22e4..36680ecb5897 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -568,8 +568,6 @@ void Hal_GetEfuseDefinition( } } -#define VOLTAGE_V25 0x03 - /* */ /* The following is for compile ok */ /* That should be merged with the original in the future */ @@ -578,7 +576,7 @@ void Hal_GetEfuseDefinition( #define REG_EFUSE_ACCESS_8723 0x00CF /* Efuse access protection for RTL8723 */ void Hal_EfusePowerSwitch( - struct adapter *padapter, u8 bWrite, u8 PwrState + struct adapter *padapter, u8 PwrState ) { u8 tempval; @@ -626,25 +624,8 @@ void Hal_EfusePowerSwitch( tmpV16 |= (LOADER_CLK_EN | ANA8M); rtw_write16(padapter, REG_SYS_CLKR, tmpV16); } - - if (bWrite) { - /* Enable LDO 2.5V before read/write action */ - tempval = rtw_read8(padapter, EFUSE_TEST+3); - tempval &= 0x0F; - tempval |= (VOLTAGE_V25 << 4); - rtw_write8(padapter, EFUSE_TEST+3, (tempval | 0x80)); - - /* rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); */ - } } else { rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); - - if (bWrite) { - /* Disable LDO 2.5V after read/write action */ - tempval = rtw_read8(padapter, EFUSE_TEST+3); - rtw_write8(padapter, EFUSE_TEST+3, (tempval & 0x7F)); - } - } } @@ -1474,9 +1455,9 @@ void Hal_EfuseParsePackageType_8723B( u8 package; u8 efuseContent; - Hal_EfusePowerSwitch(padapter, false, true); + Hal_EfusePowerSwitch(padapter, true); efuse_OneByteRead(padapter, 0x1FB, &efuseContent); - Hal_EfusePowerSwitch(padapter, false, false); + Hal_EfusePowerSwitch(padapter, false); package = efuseContent & 0x7; switch (package) { diff --git a/drivers/staging/rtl8723bs/include/hal_intf.h b/drivers/staging/rtl8723bs/include/hal_intf.h index 4fe48cccb889..2fa2382ad5f3 100644 --- a/drivers/staging/rtl8723bs/include/hal_intf.h +++ b/drivers/staging/rtl8723bs/include/hal_intf.h @@ -265,7 +265,7 @@ u8 GetHalDefVar8723BSDIO(struct adapter *Adapter, enum hal_def_variable eVariabl u8 SetHalDefVar8723BSDIO(struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue); void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_level); void rtl8723b_SetBeaconRelatedRegisters(struct adapter *padapter); -void Hal_EfusePowerSwitch(struct adapter *padapter, u8 bWrite, u8 PwrState); +void Hal_EfusePowerSwitch(struct adapter *padapter, u8 PwrState); void Hal_ReadEFuse(struct adapter *padapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf); void Hal_GetEfuseDefinition(struct adapter *padapter, u8 efuseType, u8 type, From 5cea88cab622f444a581ebd35664198bbbb1f4e6 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sun, 24 Aug 2025 11:58:29 +0200 Subject: [PATCH 0968/2711] staging: rtl8723bs: remove REG_EFUSE_ACCESS_8723 and EFUSE_ACCESS_ON_8723 The macros REG_EFUSE_ACCESS_8723 and EFUSE_ACCESS_ON_8723 are redundant, both are already defined in header files without the _8723 suffix. Remove them and use the marcos from the header files. rtl8723b_hal.h:138: #define EFUSE_ACCESS_ON 0x69 /* For RTL8723 only. */ hal_com_reg.h:35: #define REG_EFUSE_ACCESS 0x00CF /* Efuse access protection for RTL8723 */ Signed-off-by: Michael Straube Tested-by: Philipp Hortmann # Trendbook Next 14 Link: https://lore.kernel.org/r/20250824095830.79233-4-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 36680ecb5897..45cd2291f83d 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -568,13 +568,6 @@ void Hal_GetEfuseDefinition( } } -/* */ -/* The following is for compile ok */ -/* That should be merged with the original in the future */ -/* */ -#define EFUSE_ACCESS_ON_8723 0x69 /* For RTL8723 only. */ -#define REG_EFUSE_ACCESS_8723 0x00CF /* Efuse access protection for RTL8723 */ - void Hal_EfusePowerSwitch( struct adapter *padapter, u8 PwrState ) @@ -609,7 +602,7 @@ void Hal_EfusePowerSwitch( } while (1); } - rtw_write8(padapter, REG_EFUSE_ACCESS_8723, EFUSE_ACCESS_ON_8723); + rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); /* Reset: 0x0000h[28], default valid */ tmpV16 = rtw_read16(padapter, REG_SYS_FUNC_EN); From 7cce3d7bce7ff48ae21f367e4bc0fe851c65f103 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sun, 24 Aug 2025 11:58:30 +0200 Subject: [PATCH 0969/2711] staging: rtl8723bs: Hal_EfuseParseAntennaDiversity_8723B is empty The function Hal_EfuseParseAntennaDiversity_8723B is empty, remove it. Signed-off-by: Michael Straube Tested-by: Philipp Hortmann # Trendbook Next 14 Link: https://lore.kernel.org/r/20250824095830.79233-5-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c | 8 -------- drivers/staging/rtl8723bs/hal/sdio_halinit.c | 1 - drivers/staging/rtl8723bs/include/rtl8723b_hal.h | 2 -- 3 files changed, 11 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 45cd2291f83d..18244adad9e0 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -1511,14 +1511,6 @@ void Hal_EfuseParseCustomerID_8723B( pHalData->EEPROMCustomerID = 0; } -void Hal_EfuseParseAntennaDiversity_8723B( - struct adapter *padapter, - u8 *hwinfo, - bool AutoLoadFail -) -{ -} - void Hal_EfuseParseXtal_8723B( struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail ) diff --git a/drivers/staging/rtl8723bs/hal/sdio_halinit.c b/drivers/staging/rtl8723bs/hal/sdio_halinit.c index 73561a63401e..7fcb874d0eb3 100644 --- a/drivers/staging/rtl8723bs/hal/sdio_halinit.c +++ b/drivers/staging/rtl8723bs/hal/sdio_halinit.c @@ -1071,7 +1071,6 @@ static void _ReadEfuseInfo8723BS(struct adapter *padapter) Hal_EfuseParseChnlPlan_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); Hal_EfuseParseXtal_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); Hal_EfuseParseThermalMeter_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); - Hal_EfuseParseAntennaDiversity_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); Hal_EfuseParseCustomerID_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); Hal_EfuseParseVoltage_8723B(padapter, hwinfo, pEEPROM->bautoload_fail_flag); diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_hal.h b/drivers/staging/rtl8723bs/include/rtl8723b_hal.h index 40ff96d3cf74..2ed1fc8549ec 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_hal.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_hal.h @@ -210,8 +210,6 @@ void Hal_EfuseParseChnlPlan_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); void Hal_EfuseParseCustomerID_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); -void Hal_EfuseParseAntennaDiversity_8723B(struct adapter *padapter, u8 *hwinfo, - bool AutoLoadFail); void Hal_EfuseParseXtal_8723B(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail); void Hal_EfuseParseThermalMeter_8723B(struct adapter *padapter, u8 *hwinfo, From 511d7a35a438d5c37b9870fd4a0acab72b1aaf3e Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 19 Aug 2025 20:58:17 +0200 Subject: [PATCH 0970/2711] uio: Constify struct pci_device_id 'struct pci_device_id' is not modified in these drivers. Constifying this structure moves some data to a read-only section, so increases overall security. On a x86_64, with allmodconfig, as an example: Before: ====== text data bss dec hex filename 4073 1336 0 5409 1521 drivers/uio/uio_cif.o After: ===== text data bss dec hex filename 4233 1176 0 5409 1521 drivers/uio/uio_cif.o Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/114791f85f0f81531ca2169721eac4911dbe0865.1755629302.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_aec.c | 2 +- drivers/uio/uio_cif.c | 2 +- drivers/uio/uio_netx.c | 2 +- drivers/uio/uio_sercos3.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/uio/uio_aec.c b/drivers/uio/uio_aec.c index 8c164e51ff9e..dafcc5f44f24 100644 --- a/drivers/uio/uio_aec.c +++ b/drivers/uio/uio_aec.c @@ -33,7 +33,7 @@ #define MAILBOX 0x0F -static struct pci_device_id ids[] = { +static const struct pci_device_id ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AEC, PCI_DEVICE_ID_AEC_VITCLTC), }, { 0, } }; diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c index 1cc3b8b5a345..4e4b589ddef1 100644 --- a/drivers/uio/uio_cif.c +++ b/drivers/uio/uio_cif.c @@ -105,7 +105,7 @@ static void hilscher_pci_remove(struct pci_dev *dev) iounmap(info->mem[0].internal_addr); } -static struct pci_device_id hilscher_pci_ids[] = { +static const struct pci_device_id hilscher_pci_ids[] = { { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9030, diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c index a1a58802c793..18917b2ac04c 100644 --- a/drivers/uio/uio_netx.c +++ b/drivers/uio/uio_netx.c @@ -127,7 +127,7 @@ static void netx_pci_remove(struct pci_dev *dev) iounmap(info->mem[0].internal_addr); } -static struct pci_device_id netx_pci_ids[] = { +static const struct pci_device_id netx_pci_ids[] = { { .vendor = PCI_VENDOR_ID_HILSCHER, .device = PCI_DEVICE_ID_HILSCHER_NETX, diff --git a/drivers/uio/uio_sercos3.c b/drivers/uio/uio_sercos3.c index b93a5f8f4cba..12afc2fa1a0b 100644 --- a/drivers/uio/uio_sercos3.c +++ b/drivers/uio/uio_sercos3.c @@ -191,7 +191,7 @@ static void sercos3_pci_remove(struct pci_dev *dev) } } -static struct pci_device_id sercos3_pci_ids[] = { +static const struct pci_device_id sercos3_pci_ids[] = { { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9030, From 47625846727b82e4a05f14d988fc5efa2c1d882f Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Tue, 26 Aug 2025 18:34:40 +0800 Subject: [PATCH 0971/2711] uio: uio_pdrv_genirq: Remove MODULE_DEVICE_TABLE The struct of_device_id list here is filled in at load time since commit 05c3e0bb5629 ("UIO: allow binding uio_pdrv_genirq.c to devices using command line option"). However, this does not work with MODULE_DEVICE_TABLE, which generates an alias at build time. In this case, it generates the aliases "of:N*T*" and "of:N*T*C*", which matches *any* OF device node, which is obviously not intended. It confuses userspace into loading this module for any OF device, and confuses anyone trying to resolve an OF modalias. Remove this broken MODULE_DEVICE_TABLE. Suggested-by: Emily Fixes: 05c3e0bb5629 ("UIO: allow binding uio_pdrv_genirq.c to devices using command line option") Signed-off-by: Vivian Wang Link: https://lore.kernel.org/r/20250826-uio-no-modalias-v2-1-495afa9e8a5b@iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_pdrv_genirq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 2ec7d25e8264..633ab6b91671 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -276,7 +276,6 @@ static struct of_device_id uio_of_genirq_match[] = { { /* This is filled with module_parm */ }, { /* Sentinel */ }, }; -MODULE_DEVICE_TABLE(of, uio_of_genirq_match); module_param_string(of_id, uio_of_genirq_match[0].compatible, 128, 0); MODULE_PARM_DESC(of_id, "Openfirmware id of the device to be handled by uio"); #endif From 6a84240fffb5d20c8ae04757ef6a50eb5487ccae Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 4 Sep 2025 17:20:44 +0200 Subject: [PATCH 0972/2711] uio: uio_dmem_genirq: Remove dummy PM handling Since commit 63d00be69348fda4 ("PM: runtime: Allow unassigned ->runtime_suspend|resume callbacks"), unassigned .runtime_{suspend,resume}() callbacks are treated the same as dummy callbacks that just return zero. As the Runtime PM callbacks were the only driver-specific PM handling, all PM handling can be removed. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/121921f66a2baa125ea62be9436e8b5b12a4ad4d.1756999182.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_dmem_genirq.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index 31aa75110ba5..41c18ec62a45 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -297,28 +297,6 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev) return devm_uio_register_device(&pdev->dev, priv->uioinfo); } -static int uio_dmem_genirq_runtime_nop(struct device *dev) -{ - /* Runtime PM callback shared between ->runtime_suspend() - * and ->runtime_resume(). Simply returns success. - * - * In this driver pm_runtime_get_sync() and pm_runtime_put_sync() - * are used at open() and release() time. This allows the - * Runtime PM code to turn off power to the device while the - * device is unused, ie before open() and after release(). - * - * This Runtime PM callback does not need to save or restore - * any registers since user space is responsbile for hardware - * register reinitialization after open(). - */ - return 0; -} - -static const struct dev_pm_ops uio_dmem_genirq_dev_pm_ops = { - .runtime_suspend = uio_dmem_genirq_runtime_nop, - .runtime_resume = uio_dmem_genirq_runtime_nop, -}; - #ifdef CONFIG_OF static const struct of_device_id uio_of_genirq_match[] = { { /* empty for now */ }, @@ -330,7 +308,6 @@ static struct platform_driver uio_dmem_genirq = { .probe = uio_dmem_genirq_probe, .driver = { .name = DRIVER_NAME, - .pm = &uio_dmem_genirq_dev_pm_ops, .of_match_table = of_match_ptr(uio_of_genirq_match), }, }; From ffe64881395b0a1cd395473312da0c9d2604a2e4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 4 Sep 2025 17:21:12 +0200 Subject: [PATCH 0973/2711] uio: uio_pdrv_genirq: Remove dummy PM handling Since commit 63d00be69348fda4 ("PM: runtime: Allow unassigned ->runtime_suspend|resume callbacks"), unassigned .runtime_{suspend,resume}() callbacks are treated the same as dummy callbacks that just return zero. As the Runtime PM callbacks were the only driver-specific PM handling, all PM handling can be removed. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/a5495b6068dd4e40ae7e0fb66b067fd5b5c210b2.1756999260.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_pdrv_genirq.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 633ab6b91671..0a1885d1b2e3 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -249,28 +249,6 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) return ret; } -static int uio_pdrv_genirq_runtime_nop(struct device *dev) -{ - /* Runtime PM callback shared between ->runtime_suspend() - * and ->runtime_resume(). Simply returns success. - * - * In this driver pm_runtime_get_sync() and pm_runtime_put_sync() - * are used at open() and release() time. This allows the - * Runtime PM code to turn off power to the device while the - * device is unused, ie before open() and after release(). - * - * This Runtime PM callback does not need to save or restore - * any registers since user space is responsbile for hardware - * register reinitialization after open(). - */ - return 0; -} - -static const struct dev_pm_ops uio_pdrv_genirq_dev_pm_ops = { - .runtime_suspend = uio_pdrv_genirq_runtime_nop, - .runtime_resume = uio_pdrv_genirq_runtime_nop, -}; - #ifdef CONFIG_OF static struct of_device_id uio_of_genirq_match[] = { { /* This is filled with module_parm */ }, @@ -284,7 +262,6 @@ static struct platform_driver uio_pdrv_genirq = { .probe = uio_pdrv_genirq_probe, .driver = { .name = DRIVER_NAME, - .pm = &uio_pdrv_genirq_dev_pm_ops, .of_match_table = of_match_ptr(uio_of_genirq_match), }, }; From b15b7d2a1b09ef5428a8db260251897405a19496 Mon Sep 17 00:00:00 2001 From: Naman Jain Date: Thu, 28 Aug 2025 10:12:00 +0530 Subject: [PATCH 0974/2711] uio_hv_generic: Let userspace take care of interrupt mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the logic to set interrupt mask by default in uio_hv_generic driver as the interrupt mask value is supposed to be controlled completely by the user space. If the mask bit gets changed by the driver, concurrently with user mode operating on the ring, the mask bit may be set when it is supposed to be clear, and the user-mode driver will miss an interrupt which will cause a hang. For eg- when the driver sets inbound ring buffer interrupt mask to 1, the host does not interrupt the guest on the UIO VMBus channel. However, setting the mask does not prevent the host from putting a message in the inbound ring buffer. So let’s assume that happens, the host puts a message into the ring buffer but does not interrupt. Subsequently, the user space code in the guest sets the inbound ring buffer interrupt mask to 0, saying “Hey, I’m ready for interrupts”. User space code then calls pread() to wait for an interrupt. Then one of two things happens: * The host never sends another message. So the pread() waits forever. * The host does send another message. But because there’s already a message in the ring buffer, it doesn’t generate an interrupt. This is the correct behavior, because the host should only send an interrupt when the inbound ring buffer transitions from empty to not-empty. Adding an additional message to a ring buffer that is not empty is not supposed to generate an interrupt on the guest. Since the guest is waiting in pread() and not removing messages from the ring buffer, the pread() waits forever. This could be easily reproduced in hv_fcopy_uio_daemon if we delay setting interrupt mask to 0. Similarly if hv_uio_channel_cb() sets the interrupt_mask to 1, there’s a race condition. Once user space empties the inbound ring buffer, but before user space sets interrupt_mask to 0, the host could put another message in the ring buffer but it wouldn’t interrupt. Then the next pread() would hang. Fix these by removing all instances where interrupt_mask is changed, while keeping the one in set_event() unchanged to enable userspace control the interrupt mask by writing 0/1 to /dev/uioX. Fixes: 95096f2fbd10 ("uio-hv-generic: new userspace i/o driver for VMBus") Suggested-by: John Starks Signed-off-by: Naman Jain Cc: stable@vger.kernel.org Reviewed-by: Michael Kelley Reviewed-by: Long Li Reviewed-by: Tianyu Lan Tested-by: Tianyu Lan Link: https://lore.kernel.org/r/20250828044200.492030-1-namjain@linux.microsoft.com Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index f19efad4d6f8..3f8e2e27697f 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -111,7 +111,6 @@ static void hv_uio_channel_cb(void *context) struct hv_device *hv_dev; struct hv_uio_private_data *pdata; - chan->inbound.ring_buffer->interrupt_mask = 1; virt_mb(); /* @@ -183,8 +182,6 @@ hv_uio_new_channel(struct vmbus_channel *new_sc) return; } - /* Disable interrupts on sub channel */ - new_sc->inbound.ring_buffer->interrupt_mask = 1; set_channel_read_mode(new_sc, HV_CALL_ISR); ret = hv_create_ring_sysfs(new_sc, hv_uio_ring_mmap); if (ret) { @@ -227,9 +224,7 @@ hv_uio_open(struct uio_info *info, struct inode *inode) ret = vmbus_connect_ring(dev->channel, hv_uio_channel_cb, dev->channel); - if (ret == 0) - dev->channel->inbound.ring_buffer->interrupt_mask = 1; - else + if (ret) atomic_dec(&pdata->refcnt); return ret; From b009c1dbfc9854ca4460553170ddb6508fe7dafc Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Thu, 21 Aug 2025 16:18:04 +0800 Subject: [PATCH 0975/2711] misc: eeprom/m24lr: Remove unneeded semicolon Remove unnecessary semicolons reported by Coccinelle/coccicheck and the semantic patch at scripts/coccinelle/misc/semicolon.cocci. Signed-off-by: Chen Ni Reviewed-by: Abd-Alrhman Masalkhi Link: https://lore.kernel.org/r/20250821081804.3168680-1-nichen@iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/m24lr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/eeprom/m24lr.c b/drivers/misc/eeprom/m24lr.c index 0e37f74881ce..7a9fd45a8e46 100644 --- a/drivers/misc/eeprom/m24lr.c +++ b/drivers/misc/eeprom/m24lr.c @@ -350,7 +350,7 @@ static ssize_t m24lr_read_reg_le(struct m24lr *m24lr, u64 *val, break; default: return -EINVAL; - }; + } return 0; } From 534c702c3c234665ca2fe426a9fbb12281e55d55 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Fri, 15 Aug 2025 11:58:36 +0200 Subject: [PATCH 0976/2711] dt-bindings: eeprom: at25: use "size" for FRAMs without device ID Not all FRAM chips have a device ID and implement the corresponding read command. Thus the memory size, which is contained in the device ID, cannot be detected and has to be set manually as it is done for EEPROMs. Link: https://lore.kernel.org/all/20250401133148.38330-1-m.heidelberg@cab.de/ Signed-off-by: Markus Heidelberg Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250815095839.4219-2-m.heidelberg@cab.de Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/eeprom/at25.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/eeprom/at25.yaml b/Documentation/devicetree/bindings/eeprom/at25.yaml index c31e5e719525..00e0f07b44f8 100644 --- a/Documentation/devicetree/bindings/eeprom/at25.yaml +++ b/Documentation/devicetree/bindings/eeprom/at25.yaml @@ -56,6 +56,7 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 description: Total eeprom size in bytes. + Also used for FRAMs without device ID where the size cannot be detected. address-width: $ref: /schemas/types.yaml#/definitions/uint32 @@ -146,4 +147,11 @@ examples: reg = <1>; spi-max-frequency = <40000000>; }; + + fram@2 { + compatible = "cypress,fm25", "atmel,at25"; + reg = <2>; + spi-max-frequency = <20000000>; + size = <2048>; + }; }; From 1b434ed000cd474f074e62e8ab876f87449bb4ac Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Fri, 15 Aug 2025 11:58:37 +0200 Subject: [PATCH 0977/2711] eeprom: at25: support Cypress FRAMs without device ID Not all FRAM chips have a device ID and implement the corresponding read command. For such chips this led to the following error on module loading: at25 spi2.0: Error: no Cypress FRAM (id 00) The device ID contains the memory size, so devices without this ID are supported now by setting the size manually in Devicetree using the "size" property. Tested with FM25L16B and "size = <2048>;": at25 spi2.0: 2 KByte fm25 fram, pagesize 4096 According to Infineon/Cypress datasheets, these FRAMs have a device ID: FM25V01A FM25V02A FM25V05 FM25V10 FM25V20A FM25VN10 but these do not: FM25040B FM25640B FM25C160B FM25CL64B FM25L04B FM25L16B FM25W256 So all "FM25V*" FRAMs and only these have a device ID. The letter after "FM25" (V/C/L/W) only describes the voltage range, though. Link: https://lore.kernel.org/all/20250401133148.38330-1-m.heidelberg@cab.de/ Signed-off-by: Markus Heidelberg Reviewed-by: Alexander Sverdlin Link: https://lore.kernel.org/r/20250815095839.4219-3-m.heidelberg@cab.de Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/at25.c | 67 ++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 2d0492867054..c90150f72836 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -379,37 +379,49 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip) struct at25_data *at25 = container_of(chip, struct at25_data, chip); u8 sernum[FM25_SN_LEN]; u8 id[FM25_ID_LEN]; + u32 val; int i; strscpy(chip->name, "fm25", sizeof(chip->name)); - /* Get ID of chip */ - fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN); - /* There are inside-out FRAM variations, detect them and reverse the ID bytes */ - if (id[6] == 0x7f && id[2] == 0xc2) - for (i = 0; i < ARRAY_SIZE(id) / 2; i++) { - u8 tmp = id[i]; - int j = ARRAY_SIZE(id) - i - 1; + if (!device_property_read_u32(dev, "size", &val)) { + chip->byte_len = val; + } else { + /* Get ID of chip */ + fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN); + /* There are inside-out FRAM variations, detect them and reverse the ID bytes */ + if (id[6] == 0x7f && id[2] == 0xc2) + for (i = 0; i < ARRAY_SIZE(id) / 2; i++) { + u8 tmp = id[i]; + int j = ARRAY_SIZE(id) - i - 1; - id[i] = id[j]; - id[j] = tmp; + id[i] = id[j]; + id[j] = tmp; + } + if (id[6] != 0xc2) { + dev_err(dev, "Error: no Cypress FRAM (id %02x)\n", id[6]); + return -ENODEV; } - if (id[6] != 0xc2) { - dev_err(dev, "Error: no Cypress FRAM (id %02x)\n", id[6]); - return -ENODEV; - } - switch (id[7]) { - case 0x21 ... 0x26: - chip->byte_len = BIT(id[7] - 0x21 + 4) * 1024; - break; - case 0x2a ... 0x30: - /* CY15B116QN ... CY15B116QN */ - chip->byte_len = BIT(((id[7] >> 1) & 0xf) + 13); - break; - default: - dev_err(dev, "Error: unsupported size (id %02x)\n", id[7]); - return -ENODEV; + switch (id[7]) { + case 0x21 ... 0x26: + chip->byte_len = BIT(id[7] - 0x21 + 4) * 1024; + break; + case 0x2a ... 0x30: + /* CY15B116QN ... CY15B116QN */ + chip->byte_len = BIT(((id[7] >> 1) & 0xf) + 13); + break; + default: + dev_err(dev, "Error: unsupported size (id %02x)\n", id[7]); + return -ENODEV; + } + + if (id[8]) { + fm25_aux_read(at25, sernum, FM25_RDSN, FM25_SN_LEN); + /* Swap byte order */ + for (i = 0; i < FM25_SN_LEN; i++) + at25->sernum[i] = sernum[FM25_SN_LEN - 1 - i]; + } } if (chip->byte_len > 64 * 1024) @@ -417,13 +429,6 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip) else chip->flags |= EE_ADDR2; - if (id[8]) { - fm25_aux_read(at25, sernum, FM25_RDSN, FM25_SN_LEN); - /* Swap byte order */ - for (i = 0; i < FM25_SN_LEN; i++) - at25->sernum[i] = sernum[FM25_SN_LEN - 1 - i]; - } - chip->page_size = PAGE_SIZE; return 0; } From dfb962e214788aa5f6dfe9f2bd4a482294533e3e Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Fri, 15 Aug 2025 11:58:38 +0200 Subject: [PATCH 0978/2711] eeprom: at25: make FRAM device ID error message more precise The error description would be wrong in case the "size" Devicetree property is missing for an FRAM without device ID. Signed-off-by: Markus Heidelberg Reviewed-by: Alexander Sverdlin Link: https://lore.kernel.org/r/20250815095839.4219-4-m.heidelberg@cab.de Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/at25.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index c90150f72836..e2868f7bdb03 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -399,7 +399,7 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip) id[j] = tmp; } if (id[6] != 0xc2) { - dev_err(dev, "Error: no Cypress FRAM (id %02x)\n", id[6]); + dev_err(dev, "Error: no Cypress FRAM with device ID (manufacturer ID bank 7: %02x)\n", id[6]); return -ENODEV; } From d8959245329917f93a6345fd6eef828c646600fb Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 20 Aug 2025 12:21:09 +0200 Subject: [PATCH 0979/2711] dw-xdata: Use str_write_read() in dw_xdata_start() and dw_xdata_perf() Remove hard-coded strings by using the str_write_read() helper function and silence the following two Coccinelle/coccicheck warnings reported by string_choices.cocci: opportunity for str_write_read(write) opportunity for str_write_read(write) Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250820102108.760382-2-thorsten.blum@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/misc/dw-xdata-pcie.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/misc/dw-xdata-pcie.c b/drivers/misc/dw-xdata-pcie.c index efd0ca8cc925..a604c0e9c038 100644 --- a/drivers/misc/dw-xdata-pcie.c +++ b/drivers/misc/dw-xdata-pcie.c @@ -16,6 +16,7 @@ #include #include #include +#include #define DW_XDATA_DRIVER_NAME "dw-xdata-pcie" @@ -132,7 +133,7 @@ static void dw_xdata_start(struct dw_xdata *dw, bool write) if (!(status & STATUS_DONE)) dev_dbg(dev, "xData: started %s direction\n", - write ? "write" : "read"); + str_write_read(write)); } static void dw_xdata_perf_meas(struct dw_xdata *dw, u64 *data, bool write) @@ -195,7 +196,7 @@ static void dw_xdata_perf(struct dw_xdata *dw, u64 *rate, bool write) mutex_unlock(&dw->mutex); dev_dbg(dev, "xData: time=%llu us, %s=%llu MB/s\n", - diff, write ? "write" : "read", *rate); + diff, str_write_read(write), *rate); } static struct dw_xdata *misc_dev_to_dw(struct miscdevice *misc_dev) From 2828c318b3c124a370e2e8844a927734b8b49faf Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 20 Aug 2025 12:27:34 +0200 Subject: [PATCH 0980/2711] misc: ad525x_dpot: Use str_enabled_disabled() in sysfs_show_reg() Remove hard-coded strings by using the str_enabled_disabled() helper function and silence the following Coccinelle/coccicheck warning reported by string_choices.cocci: opportunity for str_enabled_disabled(..) Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250820102734.760844-2-thorsten.blum@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ad525x_dpot.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 756ef6912b5a..04683b981e54 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -73,6 +73,7 @@ #include #include #include +#include #include "ad525x_dpot.h" @@ -418,10 +419,8 @@ static ssize_t sysfs_show_reg(struct device *dev, s32 value; if (reg & DPOT_ADDR_OTP_EN) - return sprintf(buf, "%s\n", - test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask) ? - "enabled" : "disabled"); - + return sprintf(buf, "%s\n", str_enabled_disabled( + test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask))); mutex_lock(&data->update_lock); value = dpot_read(data, reg); From 53d2bf583c6b6326d751d0f0dceba76109dfb0f9 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 19 Aug 2025 20:17:49 +0800 Subject: [PATCH 0981/2711] siox: bus-gpio: Remove the use of dev_err_probe() The dev_err_probe() doesn't do anything when error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao Acked-by: Thorsten Scherer Link: https://lore.kernel.org/r/20250819121749.613584-1-zhao.xichao@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/siox/siox-bus-gpio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/siox/siox-bus-gpio.c b/drivers/siox/siox-bus-gpio.c index d6f936464063..413d5f92311c 100644 --- a/drivers/siox/siox-bus-gpio.c +++ b/drivers/siox/siox-bus-gpio.c @@ -93,8 +93,7 @@ static int siox_gpio_probe(struct platform_device *pdev) smaster = devm_siox_master_alloc(dev, sizeof(*ddata)); if (!smaster) - return dev_err_probe(dev, -ENOMEM, - "failed to allocate siox master\n"); + return -ENOMEM; platform_set_drvdata(pdev, smaster); ddata = siox_master_get_devdata(smaster); From 6b26053819dccc664120e07c56f107fb6f72f3fa Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 2 Sep 2025 12:37:12 +0100 Subject: [PATCH 0982/2711] misc: genwqe: Fix incorrect cmd field being reported in error There is a dev_err message that is reporting the value of cmd->asiv_length when it should be reporting cmd->asv_length instead. Fix this. Fixes: eaf4722d4645 ("GenWQE Character device and DDCB queue") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20250902113712.2624743-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_ddcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c index 500b1feaf1f6..fd7d5cd50d39 100644 --- a/drivers/misc/genwqe/card_ddcb.c +++ b/drivers/misc/genwqe/card_ddcb.c @@ -923,7 +923,7 @@ int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd, } if (cmd->asv_length > DDCB_ASV_LENGTH) { dev_err(&pci_dev->dev, "[%s] err: wrong asv_length of %d\n", - __func__, cmd->asiv_length); + __func__, cmd->asv_length); return -EINVAL; } rc = __genwqe_enqueue_ddcb(cd, req, f_flags); From 656a48c49a4a8a3685538dfaa2f37831b8213461 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 3 Sep 2025 22:23:51 +0200 Subject: [PATCH 0983/2711] char/adi: Remove redundant less-than-zero check in adi_write() The function parameter 'size_t count' is unsigned and cannot be less than zero. Remove the redundant condition. Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250903202350.182446-2-thorsten.blum@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/char/adi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/adi.c b/drivers/char/adi.c index f9bec10a6064..4312b0cc391c 100644 --- a/drivers/char/adi.c +++ b/drivers/char/adi.c @@ -131,7 +131,7 @@ static ssize_t adi_write(struct file *file, const char __user *buf, ssize_t ret; int i; - if (count <= 0) + if (count == 0) return -EINVAL; ver_buf_sz = min_t(size_t, count, MAX_BUF_SZ); From b0531cdba5029f897da5156815e3bdafe1e9b88d Mon Sep 17 00:00:00 2001 From: Wang Liang Date: Sat, 30 Aug 2025 15:50:23 +0800 Subject: [PATCH 0984/2711] pps: fix warning in pps_register_cdev when register device fail Similar to previous commit 2a934fdb01db ("media: v4l2-dev: fix error handling in __video_register_device()"), the release hook should be set before device_register(). Otherwise, when device_register() return error and put_device() try to callback the release function, the below warning may happen. ------------[ cut here ]------------ WARNING: CPU: 1 PID: 4760 at drivers/base/core.c:2567 device_release+0x1bd/0x240 drivers/base/core.c:2567 Modules linked in: CPU: 1 UID: 0 PID: 4760 Comm: syz.4.914 Not tainted 6.17.0-rc3+ #1 NONE RIP: 0010:device_release+0x1bd/0x240 drivers/base/core.c:2567 Call Trace: kobject_cleanup+0x136/0x410 lib/kobject.c:689 kobject_release lib/kobject.c:720 [inline] kref_put include/linux/kref.h:65 [inline] kobject_put+0xe9/0x130 lib/kobject.c:737 put_device+0x24/0x30 drivers/base/core.c:3797 pps_register_cdev+0x2da/0x370 drivers/pps/pps.c:402 pps_register_source+0x2f6/0x480 drivers/pps/kapi.c:108 pps_tty_open+0x190/0x310 drivers/pps/clients/pps-ldisc.c:57 tty_ldisc_open+0xa7/0x120 drivers/tty/tty_ldisc.c:432 tty_set_ldisc+0x333/0x780 drivers/tty/tty_ldisc.c:563 tiocsetd drivers/tty/tty_io.c:2429 [inline] tty_ioctl+0x5d1/0x1700 drivers/tty/tty_io.c:2728 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:598 [inline] __se_sys_ioctl fs/ioctl.c:584 [inline] __x64_sys_ioctl+0x194/0x210 fs/ioctl.c:584 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x5f/0x2a0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x76/0x7e Before commit c79a39dc8d06 ("pps: Fix a use-after-free"), pps_register_cdev() call device_create() to create pps->dev, which will init dev->release to device_create_release(). Now the comment is outdated, just remove it. Thanks for the reminder from Calvin Owens, 'kfree_pps' should be removed in pps_register_source() to avoid a double free in the failure case. Link: https://lore.kernel.org/all/20250827065010.3208525-1-wangliang74@huawei.com/ Fixes: c79a39dc8d06 ("pps: Fix a use-after-free") Signed-off-by: Wang Liang Reviewed-By: Calvin Owens Link: https://lore.kernel.org/r/20250830075023.3498174-1-wangliang74@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/pps/kapi.c | 5 +---- drivers/pps/pps.c | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index 92d1b62ea239..e9389876229e 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -109,16 +109,13 @@ struct pps_device *pps_register_source(struct pps_source_info *info, if (err < 0) { pr_err("%s: unable to create char device\n", info->name); - goto kfree_pps; + goto pps_register_source_exit; } dev_dbg(&pps->dev, "new PPS source %s\n", info->name); return pps; -kfree_pps: - kfree(pps); - pps_register_source_exit: pr_err("%s: unable to register source\n", info->name); diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 9463232af8d2..c6b8b6478276 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -374,6 +374,7 @@ int pps_register_cdev(struct pps_device *pps) pps->info.name); err = -EBUSY; } + kfree(pps); goto out_unlock; } pps->id = err; @@ -383,13 +384,11 @@ int pps_register_cdev(struct pps_device *pps) pps->dev.devt = MKDEV(pps_major, pps->id); dev_set_drvdata(&pps->dev, pps); dev_set_name(&pps->dev, "pps%d", pps->id); + pps->dev.release = pps_device_destruct; err = device_register(&pps->dev); if (err) goto free_idr; - /* Override the release function with our own */ - pps->dev.release = pps_device_destruct; - pr_debug("source %s got cdev (%d:%d)\n", pps->info.name, pps_major, pps->id); From 5f8f84e286f11af4c954c14a57daffc80a1c3510 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 29 Aug 2025 11:14:41 +0200 Subject: [PATCH 0985/2711] drivers/misc/amd-sbi/Kconfig: select REGMAP_I2C MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without CONFIG_REGMAP, rmi-i2c.c fails to build because struct regmap_config is not defined: drivers/misc/amd-sbi/rmi-i2c.c: In function ‘sbrmi_i2c_probe’: drivers/misc/amd-sbi/rmi-i2c.c:57:16: error: variable ‘sbrmi_i2c_regmap_config’ has initializer but incomplete type 57 | struct regmap_config sbrmi_i2c_regmap_config = { | ^~~~~~~~~~~~~ Additionally, CONFIG_REGMAP_I2C is needed for devm_regmap_init_i2c(): ld: drivers/misc/amd-sbi/rmi-i2c.o: in function `sbrmi_i2c_probe': drivers/misc/amd-sbi/rmi-i2c.c:69:(.text+0x1c0): undefined reference to `__devm_regmap_init_i2c' Fixes: 013f7e7131bd ("misc: amd-sbi: Use regmap subsystem") Cc: stable@vger.kernel.org Signed-off-by: Max Kellermann Tested-by: Akshay Gupta Reviewed-by: Akshay Gupta Link: https://lore.kernel.org/r/20250829091442.1112106-1-max.kellermann@ionos.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/amd-sbi/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/amd-sbi/Kconfig b/drivers/misc/amd-sbi/Kconfig index 4840831c84ca..4aae0733d0fc 100644 --- a/drivers/misc/amd-sbi/Kconfig +++ b/drivers/misc/amd-sbi/Kconfig @@ -2,6 +2,7 @@ config AMD_SBRMI_I2C tristate "AMD side band RMI support" depends on I2C + select REGMAP_I2C help Side band RMI over I2C support for AMD out of band management. From 0c82fd9609a1e4bf1db84b0fd56bc3b2773da179 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 5 Sep 2025 12:32:44 +0200 Subject: [PATCH 0986/2711] ibmasm: Replace kzalloc() + copy_from_user() with memdup_user_nul() Replace kzalloc() followed by copy_from_user() with memdup_user_nul() to improve and simplify remote_settings_file_write(). No functional changes intended. Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250905103247.423840-2-thorsten.blum@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ibmasm/ibmasmfs.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index c44de892a61e..2d5c1df82732 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -525,15 +525,9 @@ static ssize_t remote_settings_file_write(struct file *file, const char __user * if (*offset != 0) return 0; - buff = kzalloc (count + 1, GFP_KERNEL); - if (!buff) - return -ENOMEM; - - - if (copy_from_user(buff, ubuff, count)) { - kfree(buff); - return -EFAULT; - } + buff = memdup_user_nul(ubuff, count); + if (IS_ERR(buff)) + return PTR_ERR(buff); value = simple_strtoul(buff, NULL, 10); writel(value, address); From 618f571af67a876ce23a1dc4eb08e152fcf0d709 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 4 Sep 2025 13:15:41 -0400 Subject: [PATCH 0987/2711] dt-bindings: input: exc3000: move eeti,egalax_ts from egalax-ts.txt to eeti,exc3000.yaml Remove legacy binding egalax-ts.txt file. And add compatible string eeti,egalax_ts and wakeup-gpios to eeti,exc3000.yaml. "eeti,egalax_ts" is general compatible string, which is not preferred. But it is compatible with old devices (older than 10 years) and existing driver in drivers/input/touchscreen/egalax_ts.c. Allow address 0x4 for eeti,egalax_ts. Don't require touchscreen-size-x(y) for eeti,egalax_ts. Keep the same restriction for existing compatible string. Fix below DTB_CHECKS warnings: arch/arm/boot/dts/nxp/imx/imx6dl-gw52xx.dtb: /soc/bus@2100000/i2c@21a8000/egalax_ts@4: failed to match any schema with compatible: ['eeti,egalax_ts'] Signed-off-by: Frank Li Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250904171543.517650-1-Frank.Li@nxp.com Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/eeti,exc3000.yaml | 30 +++++++++++++++---- .../bindings/input/touchscreen/egalax-ts.txt | 18 ----------- 2 files changed, 24 insertions(+), 24 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/egalax-ts.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml b/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml index 1c7ae05a8c15..d19b07d4cfd4 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml @@ -9,25 +9,25 @@ title: EETI EXC3000 series touchscreen controller maintainers: - Dmitry Torokhov -allOf: - - $ref: touchscreen.yaml# - properties: compatible: oneOf: - const: eeti,exc3000 - const: eeti,exc80h60 - const: eeti,exc80h84 + - const: eeti,egalax_ts # Do NOT use for new binding - items: - enum: - eeti,exc81w32 - const: eeti,exc80h84 reg: - const: 0x2a + enum: [0x4, 0x2a] interrupts: maxItems: 1 reset-gpios: maxItems: 1 + wakeup-gpios: + maxItems: 1 vdd-supply: description: Power supply regulator for the chip touchscreen-size-x: true @@ -40,11 +40,29 @@ required: - compatible - reg - interrupts - - touchscreen-size-x - - touchscreen-size-y additionalProperties: false +allOf: + - $ref: touchscreen.yaml# + + - if: + properties: + compatible: + not: + contains: + const: eeti,egalax_ts + then: + properties: + reg: + const: 0x2a + + wakeup-gpios: false + + required: + - touchscreen-size-x + - touchscreen-size-y + examples: - | #include "dt-bindings/interrupt-controller/irq.h" diff --git a/Documentation/devicetree/bindings/input/touchscreen/egalax-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/egalax-ts.txt deleted file mode 100644 index ebbe93810574..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/egalax-ts.txt +++ /dev/null @@ -1,18 +0,0 @@ -* EETI eGalax Multiple Touch Controller - -Required properties: -- compatible: must be "eeti,egalax_ts" -- reg: i2c slave address -- interrupts: touch controller interrupt -- wakeup-gpios: the gpio pin to be used for waking up the controller - and also used as irq pin - -Example: - - touchscreen@4 { - compatible = "eeti,egalax_ts"; - reg = <0x04>; - interrupt-parent = <&gpio1>; - interrupts = <9 IRQ_TYPE_LEVEL_LOW>; - wakeup-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; - }; From 3cc08f9181156585baff92b1a3bba76fb4b14f4b Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 4 Sep 2025 15:17:28 -0400 Subject: [PATCH 0988/2711] dt-bindings: input: convert semtech,sx8654 to yaml format Convert sx8654.txt to yaml format. Signed-off-by: Frank Li Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250904191731.528145-1-Frank.Li@nxp.com Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/semtech,sx8654.yaml | 52 +++++++++++++++++++ .../bindings/input/touchscreen/sx8654.txt | 23 -------- 2 files changed, 52 insertions(+), 23 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/sx8654.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml b/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml new file mode 100644 index 000000000000..b2554064b688 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/semtech,sx8654.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Semtech SX8654 I2C Touchscreen Controller + +maintainers: + - Frank Li + +properties: + compatible: + enum: + - semtech,sx8650 + - semtech,sx8654 + - semtech,sx8655 + - semtech,sx8656 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@48 { + compatible = "semtech,sx8654"; + reg = <0x48>; + interrupt-parent = <&gpio6>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt deleted file mode 100644 index 0ebe6dd043c7..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt +++ /dev/null @@ -1,23 +0,0 @@ -* Semtech SX8654 I2C Touchscreen Controller - -Required properties: -- compatible: must be one of the following, depending on the model: - "semtech,sx8650" - "semtech,sx8654" - "semtech,sx8655" - "semtech,sx8656" -- reg: i2c slave address -- interrupts: touch controller interrupt - -Optional properties: - - reset-gpios: GPIO specification for the NRST input - -Example: - - sx8654@48 { - compatible = "semtech,sx8654"; - reg = <0x48>; - interrupt-parent = <&gpio6>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; - reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>; - }; From 20f2044bae1187f58863c7aa3d07dfc6ba50afec Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 21 Aug 2025 15:59:14 +0100 Subject: [PATCH 0989/2711] comedi: Add new driver for ADLink PCI-7250 series The ADLink PCI-7250, LPCI-7250, and LPCIe-7250 are PCI/PCIe boards with 8 relay outputs and 8 isolated digital inputs. Add a new Comedi driver "adl_pci7250" to support them. It is possible to add up to three PCI-7251 plug-in modules to the PCI-7250, with 8 relay outputs and 8 isolated digital inputs per plug-in module. We cannot reliably detect whether the modules are fitted without changing their state. It is harmless to assume the modules are fitted; they just won't do anything, so the driver allows all 32 relay outputs to be written (and their initial state to be read), and all 32 digital inputs to be read. The LPCI-7250 and LPCIe-7250 are low-profile boards that do not support the plug-in modules, but except for a newer variant of the LPCIe-7250, they cannot be distinguished from the full-height boards by their PCI IDs. For the newer variant of the LPCIe-7250, we can assume that there are no plug-in modules fitted and limit the number of channels accordingly. This newer variant of the LPCIe-7250 uses memory-mapped registers, whereas all the other boards use port-mapped registers. I have tested the PCI-7250. The new variant of the LPCIe-7250 has been tested in an out-of-tree version of the Comedi drivers by someone else. Tested-by: Ian Abbott # PCI-7250 only Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20250821145914.10445-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/Kconfig | 9 ++ drivers/comedi/drivers/Makefile | 1 + drivers/comedi/drivers/adl_pci7250.c | 220 +++++++++++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 drivers/comedi/drivers/adl_pci7250.c diff --git a/drivers/comedi/Kconfig b/drivers/comedi/Kconfig index 93c68a40a17b..6dcc2567de6d 100644 --- a/drivers/comedi/Kconfig +++ b/drivers/comedi/Kconfig @@ -705,6 +705,15 @@ config COMEDI_ADL_PCI6208 To compile this driver as a module, choose M here: the module will be called adl_pci6208. +config COMEDI_ADL_PCI7250 + tristate "ADLink PCI-7250 support" + help + Enable support for ADLink PCI-7250/LPCI-7250/LPCIe-7250 relay output + and isolated digital input boards. + + To compile this driver as a module, choose M here: the module will be + called adl_pci7250. + config COMEDI_ADL_PCI7X3X tristate "ADLink PCI-723X/743X isolated digital i/o board support" depends on HAS_IOPORT diff --git a/drivers/comedi/drivers/Makefile b/drivers/comedi/drivers/Makefile index b24ac00cab73..7b99a431330d 100644 --- a/drivers/comedi/drivers/Makefile +++ b/drivers/comedi/drivers/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_COMEDI_ADDI_APCI_3120) += addi_apci_3120.o obj-$(CONFIG_COMEDI_ADDI_APCI_3501) += addi_apci_3501.o obj-$(CONFIG_COMEDI_ADDI_APCI_3XXX) += addi_apci_3xxx.o obj-$(CONFIG_COMEDI_ADL_PCI6208) += adl_pci6208.o +obj-$(CONFIG_COMEDI_ADL_PCI7250) += adl_pci7250.o obj-$(CONFIG_COMEDI_ADL_PCI7X3X) += adl_pci7x3x.o obj-$(CONFIG_COMEDI_ADL_PCI8164) += adl_pci8164.o obj-$(CONFIG_COMEDI_ADL_PCI9111) += adl_pci9111.o diff --git a/drivers/comedi/drivers/adl_pci7250.c b/drivers/comedi/drivers/adl_pci7250.c new file mode 100644 index 000000000000..78c85a402435 --- /dev/null +++ b/drivers/comedi/drivers/adl_pci7250.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * adl_pci7250.c + * + * Comedi driver for ADLink PCI-7250 series cards. + * + * Copyright (C) 2015, 2025 Ian Abbott + */ + +/* + * Driver: adl_pci7250 + * Description: Driver for the ADLINK PCI-7250 relay output & digital input card + * Devices: [ADLINK] PCI-7250 (adl_pci7250) LPCI-7250 LPCIe-7250 + * Author: Ian Abbott + * Status: works + * Updated: Mon, 02 Jun 2025 13:54:11 +0100 + * + * The driver assumes that 3 PCI-7251 modules are fitted to the PCI-7250, + * giving 32 channels of relay outputs and 32 channels of isolated digital + * inputs. That is also the case for the LPCI-7250 and older LPCIe-7250 + * cards although they do not physically support the PCI-7251 modules. + * Newer LPCIe-7250 cards have a different PCI subsystem device ID, so + * set the number of channels to 8 for these cards. + * + * Not fitting the PCI-7251 modules shouldn't do any harm, but the extra + * inputs and relay outputs won't work! + * + * Configuration Options: not applicable, uses PCI auto config + */ + +#include +#include + +static unsigned char adl_pci7250_read8(struct comedi_device *dev, + unsigned int offset) +{ +#ifdef CONFIG_HAS_IOPORT + if (!dev->mmio) + return inb(dev->iobase + offset); +#endif + return readb(dev->mmio + offset); +} + +static void adl_pci7250_write8(struct comedi_device *dev, unsigned int offset, + unsigned char val) +{ +#ifdef CONFIG_HAS_IOPORT + if (!dev->mmio) { + outb(val, dev->iobase + offset); + return; + } +#endif + writeb(val, dev->mmio + offset); +} + +static int adl_pci7250_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int mask = comedi_dio_update_state(s, data); + + if (mask) { + unsigned int state = s->state; + unsigned int i; + + for (i = 0; i * 8 < s->n_chan; i++) { + if ((mask & 0xffu) != 0) { + /* write relay data to even offset registers */ + adl_pci7250_write8(dev, i * 2, state & 0xffu); + } + state >>= 8; + mask >>= 8; + } + } + + data[1] = s->state; + + return 2; +} + +static int adl_pci7250_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int value = 0; + unsigned int i; + + for (i = 0; i * 8 < s->n_chan; i++) { + /* read DI value from odd offset registers */ + value |= (unsigned int)adl_pci7250_read8(dev, i * 2 + 1) << + (i * 8); + } + + data[1] = value; + + return 2; +} + +static int pci7250_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct comedi_subdevice *s; + unsigned int max_chans; + unsigned int i; + int ret; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + if (pci_resource_len(pcidev, 2) < 8) + return -ENXIO; + + /* + * Newer LPCIe-7250 boards use MMIO. Older LPCIe-7250, LPCI-7250, and + * PCI-7250 boards use Port I/O. + */ + if (pci_resource_flags(pcidev, 2) & IORESOURCE_MEM) { + dev->mmio = pci_ioremap_bar(pcidev, 2); + if (!dev->mmio) + return -ENOMEM; + } else if (IS_ENABLED(CONFIG_HAS_IOPORT)) { + dev->iobase = pci_resource_start(pcidev, 2); + } else { + dev_err(dev->class_dev, + "error! need I/O port support\n"); + return -ENXIO; + } + + if (pcidev->subsystem_device == 0x7000) { + /* + * This is a newer LPCIe-7250 variant and cannot possibly + * have PCI-7251 modules fitted, so limit the number of + * channels to 8. + */ + max_chans = 8; + } else { + /* + * It is unknown whether the board is a PCI-7250, an LPCI-7250, + * or an older LPCIe-7250 variant, so treat it as a PCI-7250 + * and assume it can have PCI-7251 modules fitted to increase + * the number of channels to a maximum of 32. + */ + max_chans = 32; + } + + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; + + /* Relay digital output. */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = max_chans; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = adl_pci7250_do_insn_bits; + /* Read initial state of relays from the even offset registers. */ + s->state = 0; + for (i = 0; i * 8 < max_chans; i++) { + s->state |= (unsigned int)adl_pci7250_read8(dev, i * 2) << + (i * 8); + } + + /* Isolated digital input. */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = max_chans; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = adl_pci7250_di_insn_bits; + + return 0; +} + +static struct comedi_driver adl_pci7250_driver = { + .driver_name = "adl_pci7250", + .module = THIS_MODULE, + .auto_attach = pci7250_auto_attach, + .detach = comedi_pci_detach, +}; + +static int adl_pci7250_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &adl_pci7250_driver, + id->driver_data); +} + +static const struct pci_device_id adl_pci7250_pci_table[] = { +#ifdef CONFIG_HAS_IOPORT + { PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + 0x9999, 0x7250) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADLINK, 0x7250, + 0x9999, 0x7250) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADLINK, 0x7250, + PCI_VENDOR_ID_ADLINK, 0x7250) }, +#endif + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADLINK, 0x7250, + PCI_VENDOR_ID_ADLINK, 0x7000) }, /* newer LPCIe-7250 */ + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adl_pci7250_pci_table); + +static struct pci_driver adl_pci7250_pci_driver = { + .name = "adl_pci7250", + .id_table = adl_pci7250_pci_table, + .probe = adl_pci7250_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(adl_pci7250_driver, adl_pci7250_pci_driver); + +MODULE_AUTHOR("Comedi https://www.comedi.org"); +MODULE_DESCRIPTION("Comedi driver for ADLink PCI-7250 series boards"); +MODULE_LICENSE("GPL"); From 7328815c5fb0b5bc39dc5c981b18c0008786ab82 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 4 Sep 2025 16:06:37 -0400 Subject: [PATCH 0990/2711] dt-bindings: input: convert max11801-ts to yaml format Convert max11801-ts to yaml format. Signed-off-by: Frank Li Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250904200641.531897-1-Frank.Li@nxp.com Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/max11801-ts.txt | 17 ------- .../input/touchscreen/maxim,max11801.yaml | 46 +++++++++++++++++++ 2 files changed, 46 insertions(+), 17 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/max11801-ts.txt create mode 100644 Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml diff --git a/Documentation/devicetree/bindings/input/touchscreen/max11801-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/max11801-ts.txt deleted file mode 100644 index 05e982c3454e..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/max11801-ts.txt +++ /dev/null @@ -1,17 +0,0 @@ -* MAXI MAX11801 Resistive touch screen controller with i2c interface - -Required properties: -- compatible: must be "maxim,max11801" -- reg: i2c slave address -- interrupts: touch controller interrupt - -Example: - -&i2c1 { - max11801: touchscreen@48 { - compatible = "maxim,max11801"; - reg = <0x48>; - interrupt-parent = <&gpio3>; - interrupts = <31 IRQ_TYPE_EDGE_FALLING>; - }; -}; diff --git a/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml b/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml new file mode 100644 index 000000000000..4f528d220199 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/maxim,max11801.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MAXI MAX11801 Resistive touch screen controller with i2c interface + +maintainers: + - Frank Li + +properties: + compatible: + const: maxim,max11801 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +allOf: + - $ref: touchscreen.yaml + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@48 { + compatible = "maxim,max11801"; + reg = <0x48>; + interrupt-parent = <&gpio3>; + interrupts = <31 IRQ_TYPE_EDGE_FALLING>; + }; + }; From f3ebb77fce24b5573e7accc2ba593ae55bded1d9 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 4 Sep 2025 21:57:04 +0200 Subject: [PATCH 0991/2711] dt-bindings: input: touchscreen: goodix: Drop 'interrupts' requirement Since commit 409fe0cea366 ("Input: goodix - add support for polling mode") the interrupts property is optional, since at least the Linux kernel driver supports also polling mode. Signed-off-by: Marek Vasut Acked-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20250904195727.168152-1-marek.vasut+renesas@mailbox.org Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/touchscreen/goodix.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.yaml b/Documentation/devicetree/bindings/input/touchscreen/goodix.yaml index eb4992f708b7..a96137c6f063 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/goodix.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/goodix.yaml @@ -62,7 +62,6 @@ additionalProperties: false required: - compatible - reg - - interrupts examples: - | From ceda408c0d1d41094ad125332c6fb1d488e61c0c Mon Sep 17 00:00:00 2001 From: Xion Wang Date: Wed, 27 Aug 2025 10:41:00 +0800 Subject: [PATCH 0992/2711] misc: remove ineffective WARN_ON() check from misc_deregister() The WARN_ON(list_empty(&misc->list)) in misc_deregister() does not catch any practical error conditions: - For statically allocated miscdevice structures, the list pointers are zero-initialized, so list_empty() returns false, not true. - After list_del(), the pointers are set to LIST_POISON1 and LIST_POISON2, so repeated deregistration also fails to trigger the check. Signed-off-by: Xion Wang Link: https://lore.kernel.org/r/20250827024201.21407-2-xion.wang@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/char/misc.c b/drivers/char/misc.c index a0aae0fc7926..69e8ce02e099 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -283,9 +283,6 @@ EXPORT_SYMBOL(misc_register); void misc_deregister(struct miscdevice *misc) { - if (WARN_ON(list_empty(&misc->list))) - return; - mutex_lock(&misc_mtx); list_del(&misc->list); device_destroy(&misc_class, MKDEV(MISC_MAJOR, misc->minor)); From e28022873c0d051e980c4145f1965cab5504b498 Mon Sep 17 00:00:00 2001 From: Xion Wang Date: Thu, 4 Sep 2025 14:37:04 +0800 Subject: [PATCH 0993/2711] char: Use list_del_init() in misc_deregister() to reinitialize list pointer Currently, misc_deregister() uses list_del() to remove the device from the list. After list_del(), the list pointers are set to LIST_POISON1 and LIST_POISON2, which may help catch use-after-free bugs, but does not reset the list head. If misc_deregister() is called more than once on the same device, list_empty() will not return true, and list_del() may be called again, leading to undefined behavior. Replace list_del() with list_del_init() to reinitialize the list head after deletion. This makes the code more robust against double deregistration and allows safe usage of list_empty() on the miscdevice after deregistration. [ Note, this seems to keep broken out-of-tree drivers from doing foolish things. While this does not matter for any in-kernel drivers, external drivers could use a bit of help to show them they shouldn't be doing stuff like re-registering misc devices - gregkh ] Signed-off-by: Xion Wang Link: https://lore.kernel.org/r/20250904063714.28925-2-xion.wang@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 69e8ce02e099..726516fb0a3b 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -284,7 +284,7 @@ EXPORT_SYMBOL(misc_register); void misc_deregister(struct miscdevice *misc) { mutex_lock(&misc_mtx); - list_del(&misc->list); + list_del_init(&misc->list); device_destroy(&misc_class, MKDEV(MISC_MAJOR, misc->minor)); misc_minor_free(misc->minor); if (misc->minor > MISC_DYNAMIC_MINOR) From 76254bc489d39dae9a3427f0984fe64213d20548 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Tue, 2 Sep 2025 16:49:33 +0800 Subject: [PATCH 0994/2711] cdx: Fix device node reference leak in cdx_msi_domain_init Add missing of_node_put() call to release the device node reference obtained via of_parse_phandle(). Fixes: 0e439ba38e61 ("cdx: add MSI support for CDX bus") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Acked-by: Nipun Gupta Link: https://lore.kernel.org/r/20250902084933.2418264-1-linmq006@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/cdx_msi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cdx/cdx_msi.c b/drivers/cdx/cdx_msi.c index 3388a5d1462c..91b95422b263 100644 --- a/drivers/cdx/cdx_msi.c +++ b/drivers/cdx/cdx_msi.c @@ -174,6 +174,7 @@ struct irq_domain *cdx_msi_domain_init(struct device *dev) } parent = irq_find_matching_fwnode(of_fwnode_handle(parent_node), DOMAIN_BUS_NEXUS); + of_node_put(parent_node); if (!parent || !msi_get_domain_info(parent)) { dev_err(dev, "unable to locate ITS domain\n"); return NULL; From 7704e6be4ed2835832c445807cdcb2d56d8a8430 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 26 Aug 2025 15:56:17 +0300 Subject: [PATCH 0995/2711] mei: hook mei_device on class device mei_device lifetime was managed by devm procedure of parent device. But such memory is freed on device_del. Mei_device object is used by client object that may be alive after parent device is removed. It may lead to use-after-free if discrete graphics driver unloads mei_gsc auxiliary device while user-space holds open handle to mei character device. Connect mei_device structure lifteme to mei class device lifetime by adding mei_device free to class device remove callback. Move exising parent device pointer to separate field in mei_device to avoid misuse. Allocate character device dynamically and allow to control its own lifetime as it may outlive mei_device structure while character device closes after parent device is removed from the system. Leave power management on parent device as we overwrite pci runtime pm procedure and user-space is expecting it there. Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14201 Signed-off-by: Alexander Usyskin Link: https://lore.kernel.org/r/20250826125617.1166546-1-alexander.usyskin@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus-fixup.c | 6 +- drivers/misc/mei/bus.c | 24 ++++--- drivers/misc/mei/client.c | 82 +++++++++++----------- drivers/misc/mei/client.h | 6 +- drivers/misc/mei/dma-ring.c | 8 +-- drivers/misc/mei/gsc-me.c | 16 ++--- drivers/misc/mei/hbm.c | 121 +++++++++++++++----------------- drivers/misc/mei/hw-me.c | 100 +++++++++++++------------- drivers/misc/mei/hw-txe.c | 60 ++++++++-------- drivers/misc/mei/init.c | 47 ++++++------- drivers/misc/mei/interrupt.c | 45 ++++++------ drivers/misc/mei/main.c | 82 +++++++++++++++------- drivers/misc/mei/mei_dev.h | 12 ++-- drivers/misc/mei/pci-me.c | 20 +++--- drivers/misc/mei/pci-txe.c | 4 +- drivers/misc/mei/platform-vsc.c | 26 +++---- 16 files changed, 343 insertions(+), 316 deletions(-) diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 90dba20b2de7..e6a1d3534663 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -386,7 +386,7 @@ static int mei_nfc_if_version(struct mei_cl *cl, ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(cmd), 0, MEI_CL_IO_TX_BLOCKING); if (ret < 0) { - dev_err(bus->dev, "Could not send IF version cmd ret = %d\n", ret); + dev_err(&bus->dev, "Could not send IF version cmd ret = %d\n", ret); return ret; } @@ -401,14 +401,14 @@ static int mei_nfc_if_version(struct mei_cl *cl, bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, &vtag, 0, 0); if (bytes_recv < 0 || (size_t)bytes_recv < if_version_length) { - dev_err(bus->dev, "Could not read IF version ret = %d\n", bytes_recv); + dev_err(&bus->dev, "Could not read IF version ret = %d\n", bytes_recv); ret = -EIO; goto err; } memcpy(ver, reply->data, sizeof(*ver)); - dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n", + dev_info(&bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n", ver->fw_ivn, ver->vendor_id, ver->radio_type); err: diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 5cc3ad07d5be..6c8ec5c0d359 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -637,7 +637,7 @@ EXPORT_SYMBOL_GPL(mei_cldev_enabled); */ static bool mei_cl_bus_module_get(struct mei_cl_device *cldev) { - return try_module_get(cldev->bus->dev->driver->owner); + return try_module_get(cldev->bus->parent->driver->owner); } /** @@ -647,7 +647,7 @@ static bool mei_cl_bus_module_get(struct mei_cl_device *cldev) */ static void mei_cl_bus_module_put(struct mei_cl_device *cldev) { - module_put(cldev->bus->dev->driver->owner); + module_put(cldev->bus->parent->driver->owner); } /** @@ -1285,16 +1285,20 @@ static const struct bus_type mei_cl_bus_type = { static struct mei_device *mei_dev_bus_get(struct mei_device *bus) { - if (bus) - get_device(bus->dev); + if (bus) { + get_device(&bus->dev); + get_device(bus->parent); + } return bus; } static void mei_dev_bus_put(struct mei_device *bus) { - if (bus) - put_device(bus->dev); + if (bus) { + put_device(bus->parent); + put_device(&bus->dev); + } } static void mei_cl_bus_dev_release(struct device *dev) @@ -1328,7 +1332,7 @@ static const struct device_type mei_cl_device_type = { static inline void mei_cl_bus_set_name(struct mei_cl_device *cldev) { dev_set_name(&cldev->dev, "%s-%pUl", - dev_name(cldev->bus->dev), + dev_name(cldev->bus->parent), mei_me_cl_uuid(cldev->me_cl)); } @@ -1357,7 +1361,7 @@ static struct mei_cl_device *mei_cl_bus_dev_alloc(struct mei_device *bus, } device_initialize(&cldev->dev); - cldev->dev.parent = bus->dev; + cldev->dev.parent = bus->parent; cldev->dev.bus = &mei_cl_bus_type; cldev->dev.type = &mei_cl_device_type; cldev->bus = mei_dev_bus_get(bus); @@ -1492,7 +1496,7 @@ static void mei_cl_bus_dev_init(struct mei_device *bus, WARN_ON(!mutex_is_locked(&bus->cl_bus_lock)); - dev_dbg(bus->dev, "initializing %pUl", mei_me_cl_uuid(me_cl)); + dev_dbg(&bus->dev, "initializing %pUl", mei_me_cl_uuid(me_cl)); if (me_cl->bus_added) return; @@ -1543,7 +1547,7 @@ static void mei_cl_bus_rescan(struct mei_device *bus) } mutex_unlock(&bus->cl_bus_lock); - dev_dbg(bus->dev, "rescan end"); + dev_dbg(&bus->dev, "rescan end"); } void mei_cl_bus_rescan_work(struct work_struct *work) diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 3db07d2a881f..159e8b841564 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -262,7 +262,7 @@ void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid) { struct mei_me_client *me_cl; - dev_dbg(dev->dev, "remove %pUl\n", uuid); + dev_dbg(&dev->dev, "remove %pUl\n", uuid); down_write(&dev->me_clients_rwsem); me_cl = __mei_me_cl_by_uuid(dev, uuid); @@ -635,12 +635,12 @@ int mei_cl_link(struct mei_cl *cl) id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX); if (id >= MEI_CLIENTS_MAX) { - dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX); + dev_err(&dev->dev, "id exceeded %d", MEI_CLIENTS_MAX); return -EMFILE; } if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { - dev_err(dev->dev, "open_handle_count exceeded %d", + dev_err(&dev->dev, "open_handle_count exceeded %d", MEI_MAX_OPEN_HANDLE_COUNT); return -EMFILE; } @@ -709,9 +709,9 @@ void mei_host_client_init(struct mei_device *dev) schedule_work(&dev->bus_rescan_work); - pm_runtime_mark_last_busy(dev->dev); - dev_dbg(dev->dev, "rpm: autosuspend\n"); - pm_request_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + dev_dbg(&dev->dev, "rpm: autosuspend\n"); + pm_request_autosuspend(dev->parent); } /** @@ -724,12 +724,12 @@ bool mei_hbuf_acquire(struct mei_device *dev) { if (mei_pg_state(dev) == MEI_PG_ON || mei_pg_in_transition(dev)) { - dev_dbg(dev->dev, "device is in pg\n"); + dev_dbg(&dev->dev, "device is in pg\n"); return false; } if (!dev->hbuf_is_ready) { - dev_dbg(dev->dev, "hbuf is not ready\n"); + dev_dbg(&dev->dev, "hbuf is not ready\n"); return false; } @@ -981,9 +981,9 @@ int mei_cl_disconnect(struct mei_cl *cl) return 0; } - rets = pm_runtime_get(dev->dev); + rets = pm_runtime_get(dev->parent); if (rets < 0 && rets != -EINPROGRESS) { - pm_runtime_put_noidle(dev->dev); + pm_runtime_put_noidle(dev->parent); cl_err(dev, cl, "rpm: get failed %d\n", rets); return rets; } @@ -991,8 +991,8 @@ int mei_cl_disconnect(struct mei_cl *cl) rets = __mei_cl_disconnect(cl); cl_dbg(dev, cl, "rpm: autosuspend\n"); - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + pm_runtime_put_autosuspend(dev->parent); return rets; } @@ -1118,9 +1118,9 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, goto nortpm; } - rets = pm_runtime_get(dev->dev); + rets = pm_runtime_get(dev->parent); if (rets < 0 && rets != -EINPROGRESS) { - pm_runtime_put_noidle(dev->dev); + pm_runtime_put_noidle(dev->parent); cl_err(dev, cl, "rpm: get failed %d\n", rets); goto nortpm; } @@ -1167,8 +1167,8 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, rets = cl->status; out: cl_dbg(dev, cl, "rpm: autosuspend\n"); - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + pm_runtime_put_autosuspend(dev->parent); mei_io_cb_free(cb); @@ -1517,9 +1517,9 @@ int mei_cl_notify_request(struct mei_cl *cl, if (!mei_cl_is_connected(cl)) return -ENODEV; - rets = pm_runtime_get(dev->dev); + rets = pm_runtime_get(dev->parent); if (rets < 0 && rets != -EINPROGRESS) { - pm_runtime_put_noidle(dev->dev); + pm_runtime_put_noidle(dev->parent); cl_err(dev, cl, "rpm: get failed %d\n", rets); return rets; } @@ -1554,8 +1554,8 @@ int mei_cl_notify_request(struct mei_cl *cl, out: cl_dbg(dev, cl, "rpm: autosuspend\n"); - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + pm_runtime_put_autosuspend(dev->parent); mei_io_cb_free(cb); return rets; @@ -1683,9 +1683,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp) mei_cl_set_read_by_fp(cl, fp); - rets = pm_runtime_get(dev->dev); + rets = pm_runtime_get(dev->parent); if (rets < 0 && rets != -EINPROGRESS) { - pm_runtime_put_noidle(dev->dev); + pm_runtime_put_noidle(dev->parent); cl_err(dev, cl, "rpm: get failed %d\n", rets); goto nortpm; } @@ -1702,8 +1702,8 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp) out: cl_dbg(dev, cl, "rpm: autosuspend\n"); - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + pm_runtime_put_autosuspend(dev->parent); nortpm: if (rets) mei_io_cb_free(cb); @@ -1972,9 +1972,9 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, unsigned long time blocking = cb->blocking; data = buf->data; - rets = pm_runtime_get(dev->dev); + rets = pm_runtime_get(dev->parent); if (rets < 0 && rets != -EINPROGRESS) { - pm_runtime_put_noidle(dev->dev); + pm_runtime_put_noidle(dev->parent); cl_err(dev, cl, "rpm: get failed %zd\n", rets); goto free; } @@ -2092,8 +2092,8 @@ out: rets = buf_len; err: cl_dbg(dev, cl, "rpm: autosuspend\n"); - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + pm_runtime_put_autosuspend(dev->parent); free: mei_io_cb_free(cb); @@ -2119,8 +2119,8 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb) if (waitqueue_active(&cl->tx_wait)) { wake_up_interruptible(&cl->tx_wait); } else { - pm_runtime_mark_last_busy(dev->dev); - pm_request_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + pm_request_autosuspend(dev->parent); } break; @@ -2251,7 +2251,7 @@ int mei_cl_irq_dma_unmap(struct mei_cl *cl, struct mei_cl_cb *cb, static int mei_cl_dma_alloc(struct mei_cl *cl, u8 buf_id, size_t size) { - cl->dma.vaddr = dmam_alloc_coherent(cl->dev->dev, size, + cl->dma.vaddr = dmam_alloc_coherent(&cl->dev->dev, size, &cl->dma.daddr, GFP_KERNEL); if (!cl->dma.vaddr) return -ENOMEM; @@ -2265,7 +2265,7 @@ static int mei_cl_dma_alloc(struct mei_cl *cl, u8 buf_id, size_t size) static void mei_cl_dma_free(struct mei_cl *cl) { cl->dma.buffer_id = 0; - dmam_free_coherent(cl->dev->dev, + dmam_free_coherent(&cl->dev->dev, cl->dma.size, cl->dma.vaddr, cl->dma.daddr); cl->dma.size = 0; cl->dma.vaddr = NULL; @@ -2321,16 +2321,16 @@ int mei_cl_dma_alloc_and_map(struct mei_cl *cl, const struct file *fp, return -EPROTO; } - rets = pm_runtime_get(dev->dev); + rets = pm_runtime_get(dev->parent); if (rets < 0 && rets != -EINPROGRESS) { - pm_runtime_put_noidle(dev->dev); + pm_runtime_put_noidle(dev->parent); cl_err(dev, cl, "rpm: get failed %d\n", rets); return rets; } rets = mei_cl_dma_alloc(cl, buffer_id, size); if (rets) { - pm_runtime_put_noidle(dev->dev); + pm_runtime_put_noidle(dev->parent); return rets; } @@ -2366,8 +2366,8 @@ out: mei_cl_dma_free(cl); cl_dbg(dev, cl, "rpm: autosuspend\n"); - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + pm_runtime_put_autosuspend(dev->parent); mei_io_cb_free(cb); return rets; @@ -2406,9 +2406,9 @@ int mei_cl_dma_unmap(struct mei_cl *cl, const struct file *fp) if (!cl->dma_mapped) return -EPROTO; - rets = pm_runtime_get(dev->dev); + rets = pm_runtime_get(dev->parent); if (rets < 0 && rets != -EINPROGRESS) { - pm_runtime_put_noidle(dev->dev); + pm_runtime_put_noidle(dev->parent); cl_err(dev, cl, "rpm: get failed %d\n", rets); return rets; } @@ -2444,8 +2444,8 @@ int mei_cl_dma_unmap(struct mei_cl *cl, const struct file *fp) mei_cl_dma_free(cl); out: cl_dbg(dev, cl, "rpm: autosuspend\n"); - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + pm_runtime_put_autosuspend(dev->parent); mei_io_cb_free(cb); return rets; diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 01ed26a148c4..031114478bcb 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -275,12 +275,12 @@ int mei_cl_dma_unmap(struct mei_cl *cl, const struct file *fp); #define MEI_CL_PRM(cl) (cl)->host_client_id, mei_cl_me_id(cl) #define cl_dbg(dev, cl, format, arg...) \ - dev_dbg((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) + dev_dbg(&(dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) #define cl_warn(dev, cl, format, arg...) \ - dev_warn((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) + dev_warn(&(dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) #define cl_err(dev, cl, format, arg...) \ - dev_err((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) + dev_err(&(dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) #endif /* _MEI_CLIENT_H_ */ diff --git a/drivers/misc/mei/dma-ring.c b/drivers/misc/mei/dma-ring.c index 651e77ef82bd..6277c4a5b0fd 100644 --- a/drivers/misc/mei/dma-ring.c +++ b/drivers/misc/mei/dma-ring.c @@ -30,7 +30,7 @@ static int mei_dmam_dscr_alloc(struct mei_device *dev, if (dscr->vaddr) return 0; - dscr->vaddr = dmam_alloc_coherent(dev->dev, dscr->size, &dscr->daddr, + dscr->vaddr = dmam_alloc_coherent(dev->parent, dscr->size, &dscr->daddr, GFP_KERNEL); if (!dscr->vaddr) return -ENOMEM; @@ -50,7 +50,7 @@ static void mei_dmam_dscr_free(struct mei_device *dev, if (!dscr->vaddr) return; - dmam_free_coherent(dev->dev, dscr->size, dscr->vaddr, dscr->daddr); + dmam_free_coherent(dev->parent, dscr->size, dscr->vaddr, dscr->daddr); dscr->vaddr = NULL; } @@ -177,7 +177,7 @@ void mei_dma_ring_read(struct mei_device *dev, unsigned char *buf, u32 len) if (WARN_ON(!ctrl)) return; - dev_dbg(dev->dev, "reading from dma %u bytes\n", len); + dev_dbg(&dev->dev, "reading from dma %u bytes\n", len); if (!len) return; @@ -254,7 +254,7 @@ void mei_dma_ring_write(struct mei_device *dev, unsigned char *buf, u32 len) if (WARN_ON(!ctrl)) return; - dev_dbg(dev->dev, "writing to dma %u bytes\n", len); + dev_dbg(&dev->dev, "writing to dma %u bytes\n", len); hbuf_depth = mei_dma_ring_hbuf_depth(dev); wr_idx = READ_ONCE(ctrl->hbuf_wr_idx) & (hbuf_depth - 1); slots = mei_data2slots(len); diff --git a/drivers/misc/mei/gsc-me.c b/drivers/misc/mei/gsc-me.c index 5a8c26c3df13..f147258e7c28 100644 --- a/drivers/misc/mei/gsc-me.c +++ b/drivers/misc/mei/gsc-me.c @@ -106,11 +106,15 @@ static int mei_gsc_probe(struct auxiliary_device *aux_dev, } } + ret = mei_register(dev, device); + if (ret) + goto deinterrupt; + pm_runtime_get_noresume(device); pm_runtime_set_active(device); pm_runtime_enable(device); - /* Continue to char device setup in spite of firmware handshake failure. + /* Continue in spite of firmware handshake failure. * In order to provide access to the firmware status registers to the user * space via sysfs. */ @@ -120,18 +124,12 @@ static int mei_gsc_probe(struct auxiliary_device *aux_dev, pm_runtime_set_autosuspend_delay(device, MEI_GSC_RPM_TIMEOUT); pm_runtime_use_autosuspend(device); - ret = mei_register(dev, device); - if (ret) - goto register_err; - pm_runtime_put_noidle(device); return 0; -register_err: - mei_stop(dev); +deinterrupt: if (!mei_me_hw_use_polling(hw)) devm_free_irq(device, hw->irq, dev); - err: dev_err(device, "probe failed: %d\n", ret); dev_set_drvdata(device, NULL); @@ -252,7 +250,7 @@ static int __maybe_unused mei_gsc_pm_runtime_resume(struct device *device) irq_ret = mei_me_irq_thread_handler(1, dev); if (irq_ret != IRQ_HANDLED) - dev_err(dev->dev, "thread handler fail %d\n", irq_ret); + dev_err(&dev->dev, "thread handler fail %d\n", irq_ret); return 0; } diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 4fe9a2752d43..ccd9df5d1c7d 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -239,7 +239,7 @@ int mei_hbm_start_wait(struct mei_device *dev) if (ret == 0 && (dev->hbm_state <= MEI_HBM_STARTING)) { dev->hbm_state = MEI_HBM_IDLE; - dev_err(dev->dev, "waiting for mei start failed\n"); + dev_err(&dev->dev, "waiting for mei start failed\n"); return -ETIME; } return 0; @@ -271,8 +271,7 @@ int mei_hbm_start_req(struct mei_device *dev) dev->hbm_state = MEI_HBM_IDLE; ret = mei_hbm_write_message(dev, &mei_hdr, &req); if (ret) { - dev_err(dev->dev, "version message write failed: ret = %d\n", - ret); + dev_err(&dev->dev, "version message write failed: ret = %d\n", ret); return ret; } @@ -312,8 +311,7 @@ static int mei_hbm_dma_setup_req(struct mei_device *dev) ret = mei_hbm_write_message(dev, &mei_hdr, &req); if (ret) { - dev_err(dev->dev, "dma setup request write failed: ret = %d.\n", - ret); + dev_err(&dev->dev, "dma setup request write failed: ret = %d.\n", ret); return ret; } @@ -351,8 +349,7 @@ static int mei_hbm_capabilities_req(struct mei_device *dev) ret = mei_hbm_write_message(dev, &mei_hdr, &req); if (ret) { - dev_err(dev->dev, - "capabilities request write failed: ret = %d.\n", ret); + dev_err(&dev->dev, "capabilities request write failed: ret = %d.\n", ret); return ret; } @@ -386,8 +383,7 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev) ret = mei_hbm_write_message(dev, &mei_hdr, &req); if (ret) { - dev_err(dev->dev, "enumeration request write failed: ret = %d.\n", - ret); + dev_err(&dev->dev, "enumeration request write failed: ret = %d.\n", ret); return ret; } dev->hbm_state = MEI_HBM_ENUM_CLIENTS; @@ -443,7 +439,7 @@ static int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status) struct hbm_add_client_response resp; int ret; - dev_dbg(dev->dev, "adding client response\n"); + dev_dbg(&dev->dev, "adding client response\n"); mei_hbm_hdr(&mei_hdr, sizeof(resp)); @@ -454,8 +450,7 @@ static int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status) ret = mei_hbm_write_message(dev, &mei_hdr, &resp); if (ret) - dev_err(dev->dev, "add client response write failed: ret = %d\n", - ret); + dev_err(&dev->dev, "add client response write failed: ret = %d\n", ret); return ret; } @@ -752,7 +747,7 @@ static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx) ret = mei_hbm_write_message(dev, &mei_hdr, &req); if (ret) { - dev_err(dev->dev, "properties request write failed: ret = %d\n", + dev_err(&dev->dev, "properties request write failed: ret = %d\n", ret); return ret; } @@ -788,7 +783,7 @@ int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd) ret = mei_hbm_write_message(dev, &mei_hdr, &req); if (ret) - dev_err(dev->dev, "power gate command write failed.\n"); + dev_err(&dev->dev, "power gate command write failed.\n"); return ret; } EXPORT_SYMBOL_GPL(mei_hbm_pg); @@ -847,7 +842,7 @@ static int mei_hbm_add_single_tx_flow_ctrl_creds(struct mei_device *dev, me_cl = mei_me_cl_by_id(dev, fctrl->me_addr); if (!me_cl) { - dev_err(dev->dev, "no such me client %d\n", fctrl->me_addr); + dev_err(&dev->dev, "no such me client %d\n", fctrl->me_addr); return -ENOENT; } @@ -857,7 +852,7 @@ static int mei_hbm_add_single_tx_flow_ctrl_creds(struct mei_device *dev, } me_cl->tx_flow_ctrl_creds++; - dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n", + dev_dbg(&dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n", fctrl->me_addr, me_cl->tx_flow_ctrl_creds); rets = 0; @@ -1085,7 +1080,7 @@ static int mei_hbm_pg_enter_res(struct mei_device *dev) { if (mei_pg_state(dev) != MEI_PG_OFF || dev->pg_event != MEI_PG_EVENT_WAIT) { - dev_err(dev->dev, "hbm: pg entry response: state mismatch [%s, %d]\n", + dev_err(&dev->dev, "hbm: pg entry response: state mismatch [%s, %d]\n", mei_pg_state_str(mei_pg_state(dev)), dev->pg_event); return -EPROTO; } @@ -1103,7 +1098,7 @@ static int mei_hbm_pg_enter_res(struct mei_device *dev) */ void mei_hbm_pg_resume(struct mei_device *dev) { - pm_request_resume(dev->dev); + pm_request_resume(dev->parent); } EXPORT_SYMBOL_GPL(mei_hbm_pg_resume); @@ -1119,7 +1114,7 @@ static int mei_hbm_pg_exit_res(struct mei_device *dev) if (mei_pg_state(dev) != MEI_PG_ON || (dev->pg_event != MEI_PG_EVENT_WAIT && dev->pg_event != MEI_PG_EVENT_IDLE)) { - dev_err(dev->dev, "hbm: pg exit response: state mismatch [%s, %d]\n", + dev_err(&dev->dev, "hbm: pg exit response: state mismatch [%s, %d]\n", mei_pg_state_str(mei_pg_state(dev)), dev->pg_event); return -EPROTO; } @@ -1276,19 +1271,19 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) * hbm is put to idle during system reset */ if (dev->hbm_state == MEI_HBM_IDLE) { - dev_dbg(dev->dev, "hbm: state is idle ignore spurious messages\n"); + dev_dbg(&dev->dev, "hbm: state is idle ignore spurious messages\n"); return 0; } switch (mei_msg->hbm_cmd) { case HOST_START_RES_CMD: - dev_dbg(dev->dev, "hbm: start: response message received.\n"); + dev_dbg(&dev->dev, "hbm: start: response message received.\n"); dev->init_clients_timer = 0; version_res = (struct hbm_host_version_response *)mei_msg; - dev_dbg(dev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n", + dev_dbg(&dev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n", HBM_MAJOR_VERSION, HBM_MINOR_VERSION, version_res->me_max_version.major_version, version_res->me_max_version.minor_version); @@ -1304,11 +1299,11 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) } if (!mei_hbm_version_is_supported(dev)) { - dev_warn(dev->dev, "hbm: start: version mismatch - stopping the driver.\n"); + dev_warn(&dev->dev, "hbm: start: version mismatch - stopping the driver.\n"); dev->hbm_state = MEI_HBM_STOPPED; if (mei_hbm_stop_req(dev)) { - dev_err(dev->dev, "hbm: start: failed to send stop request\n"); + dev_err(&dev->dev, "hbm: start: failed to send stop request\n"); return -EIO; } break; @@ -1320,10 +1315,10 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) dev->hbm_state != MEI_HBM_STARTING) { if (dev->dev_state == MEI_DEV_POWER_DOWN || dev->dev_state == MEI_DEV_POWERING_DOWN) { - dev_dbg(dev->dev, "hbm: start: on shutdown, ignoring\n"); + dev_dbg(&dev->dev, "hbm: start: on shutdown, ignoring\n"); return 0; } - dev_err(dev->dev, "hbm: start: state mismatch, [%d, %d]\n", + dev_err(&dev->dev, "hbm: start: state mismatch, [%d, %d]\n", dev->dev_state, dev->hbm_state); return -EPROTO; } @@ -1337,7 +1332,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) if (dev->hbm_f_dr_supported) { if (mei_dmam_ring_alloc(dev)) - dev_info(dev->dev, "running w/o dma ring\n"); + dev_info(&dev->dev, "running w/o dma ring\n"); if (mei_dma_ring_is_allocated(dev)) { if (mei_hbm_dma_setup_req(dev)) return -EIO; @@ -1357,7 +1352,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) break; case MEI_HBM_CAPABILITIES_RES_CMD: - dev_dbg(dev->dev, "hbm: capabilities response: message received.\n"); + dev_dbg(&dev->dev, "hbm: capabilities response: message received.\n"); dev->init_clients_timer = 0; @@ -1365,10 +1360,10 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) dev->hbm_state != MEI_HBM_CAP_SETUP) { if (dev->dev_state == MEI_DEV_POWER_DOWN || dev->dev_state == MEI_DEV_POWERING_DOWN) { - dev_dbg(dev->dev, "hbm: capabilities response: on shutdown, ignoring\n"); + dev_dbg(&dev->dev, "hbm: capabilities response: on shutdown, ignoring\n"); return 0; } - dev_err(dev->dev, "hbm: capabilities response: state mismatch, [%d, %d]\n", + dev_err(&dev->dev, "hbm: capabilities response: state mismatch, [%d, %d]\n", dev->dev_state, dev->hbm_state); return -EPROTO; } @@ -1384,7 +1379,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) if (dev->hbm_f_dr_supported) { if (mei_dmam_ring_alloc(dev)) - dev_info(dev->dev, "running w/o dma ring\n"); + dev_info(&dev->dev, "running w/o dma ring\n"); if (mei_dma_ring_is_allocated(dev)) { if (mei_hbm_dma_setup_req(dev)) return -EIO; @@ -1400,7 +1395,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) break; case MEI_HBM_DMA_SETUP_RES_CMD: - dev_dbg(dev->dev, "hbm: dma setup response: message received.\n"); + dev_dbg(&dev->dev, "hbm: dma setup response: message received.\n"); dev->init_clients_timer = 0; @@ -1408,10 +1403,10 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) dev->hbm_state != MEI_HBM_DR_SETUP) { if (dev->dev_state == MEI_DEV_POWER_DOWN || dev->dev_state == MEI_DEV_POWERING_DOWN) { - dev_dbg(dev->dev, "hbm: dma setup response: on shutdown, ignoring\n"); + dev_dbg(&dev->dev, "hbm: dma setup response: on shutdown, ignoring\n"); return 0; } - dev_err(dev->dev, "hbm: dma setup response: state mismatch, [%d, %d]\n", + dev_err(&dev->dev, "hbm: dma setup response: state mismatch, [%d, %d]\n", dev->dev_state, dev->hbm_state); return -EPROTO; } @@ -1422,9 +1417,9 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) u8 status = dma_setup_res->status; if (status == MEI_HBMS_NOT_ALLOWED) { - dev_dbg(dev->dev, "hbm: dma setup not allowed\n"); + dev_dbg(&dev->dev, "hbm: dma setup not allowed\n"); } else { - dev_info(dev->dev, "hbm: dma setup response: failure = %d %s\n", + dev_info(&dev->dev, "hbm: dma setup response: failure = %d %s\n", status, mei_hbm_status_str(status)); } @@ -1437,38 +1432,38 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) break; case CLIENT_CONNECT_RES_CMD: - dev_dbg(dev->dev, "hbm: client connect response: message received.\n"); + dev_dbg(&dev->dev, "hbm: client connect response: message received.\n"); mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_CONNECT); break; case CLIENT_DISCONNECT_RES_CMD: - dev_dbg(dev->dev, "hbm: client disconnect response: message received.\n"); + dev_dbg(&dev->dev, "hbm: client disconnect response: message received.\n"); mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_DISCONNECT); break; case MEI_FLOW_CONTROL_CMD: - dev_dbg(dev->dev, "hbm: client flow control response: message received.\n"); + dev_dbg(&dev->dev, "hbm: client flow control response: message received.\n"); fctrl = (struct hbm_flow_control *)mei_msg; mei_hbm_cl_tx_flow_ctrl_creds_res(dev, fctrl); break; case MEI_PG_ISOLATION_ENTRY_RES_CMD: - dev_dbg(dev->dev, "hbm: power gate isolation entry response received\n"); + dev_dbg(&dev->dev, "hbm: power gate isolation entry response received\n"); ret = mei_hbm_pg_enter_res(dev); if (ret) return ret; break; case MEI_PG_ISOLATION_EXIT_REQ_CMD: - dev_dbg(dev->dev, "hbm: power gate isolation exit request received\n"); + dev_dbg(&dev->dev, "hbm: power gate isolation exit request received\n"); ret = mei_hbm_pg_exit_res(dev); if (ret) return ret; break; case HOST_CLIENT_PROPERTIES_RES_CMD: - dev_dbg(dev->dev, "hbm: properties response: message received.\n"); + dev_dbg(&dev->dev, "hbm: properties response: message received.\n"); dev->init_clients_timer = 0; @@ -1476,10 +1471,10 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) { if (dev->dev_state == MEI_DEV_POWER_DOWN || dev->dev_state == MEI_DEV_POWERING_DOWN) { - dev_dbg(dev->dev, "hbm: properties response: on shutdown, ignoring\n"); + dev_dbg(&dev->dev, "hbm: properties response: on shutdown, ignoring\n"); return 0; } - dev_err(dev->dev, "hbm: properties response: state mismatch, [%d, %d]\n", + dev_err(&dev->dev, "hbm: properties response: state mismatch, [%d, %d]\n", dev->dev_state, dev->hbm_state); return -EPROTO; } @@ -1487,10 +1482,10 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) props_res = (struct hbm_props_response *)mei_msg; if (props_res->status == MEI_HBMS_CLIENT_NOT_FOUND) { - dev_dbg(dev->dev, "hbm: properties response: %d CLIENT_NOT_FOUND\n", + dev_dbg(&dev->dev, "hbm: properties response: %d CLIENT_NOT_FOUND\n", props_res->me_addr); } else if (props_res->status) { - dev_err(dev->dev, "hbm: properties response: wrong status = %d %s\n", + dev_err(&dev->dev, "hbm: properties response: wrong status = %d %s\n", props_res->status, mei_hbm_status_str(props_res->status)); return -EPROTO; @@ -1505,7 +1500,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) break; case HOST_ENUM_RES_CMD: - dev_dbg(dev->dev, "hbm: enumeration response: message received\n"); + dev_dbg(&dev->dev, "hbm: enumeration response: message received\n"); dev->init_clients_timer = 0; @@ -1519,10 +1514,10 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) dev->hbm_state != MEI_HBM_ENUM_CLIENTS) { if (dev->dev_state == MEI_DEV_POWER_DOWN || dev->dev_state == MEI_DEV_POWERING_DOWN) { - dev_dbg(dev->dev, "hbm: enumeration response: on shutdown, ignoring\n"); + dev_dbg(&dev->dev, "hbm: enumeration response: on shutdown, ignoring\n"); return 0; } - dev_err(dev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n", + dev_err(&dev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n", dev->dev_state, dev->hbm_state); return -EPROTO; } @@ -1536,77 +1531,77 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) break; case HOST_STOP_RES_CMD: - dev_dbg(dev->dev, "hbm: stop response: message received\n"); + dev_dbg(&dev->dev, "hbm: stop response: message received\n"); dev->init_clients_timer = 0; if (dev->hbm_state != MEI_HBM_STOPPED) { - dev_err(dev->dev, "hbm: stop response: state mismatch, [%d, %d]\n", + dev_err(&dev->dev, "hbm: stop response: state mismatch, [%d, %d]\n", dev->dev_state, dev->hbm_state); return -EPROTO; } mei_set_devstate(dev, MEI_DEV_POWER_DOWN); - dev_info(dev->dev, "hbm: stop response: resetting.\n"); + dev_info(&dev->dev, "hbm: stop response: resetting.\n"); /* force the reset */ return -EPROTO; case CLIENT_DISCONNECT_REQ_CMD: - dev_dbg(dev->dev, "hbm: disconnect request: message received\n"); + dev_dbg(&dev->dev, "hbm: disconnect request: message received\n"); disconnect_req = (struct hbm_client_connect_request *)mei_msg; mei_hbm_fw_disconnect_req(dev, disconnect_req); break; case ME_STOP_REQ_CMD: - dev_dbg(dev->dev, "hbm: stop request: message received\n"); + dev_dbg(&dev->dev, "hbm: stop request: message received\n"); dev->hbm_state = MEI_HBM_STOPPED; if (mei_hbm_stop_req(dev)) { - dev_err(dev->dev, "hbm: stop request: failed to send stop request\n"); + dev_err(&dev->dev, "hbm: stop request: failed to send stop request\n"); return -EIO; } break; case MEI_HBM_ADD_CLIENT_REQ_CMD: - dev_dbg(dev->dev, "hbm: add client request received\n"); + dev_dbg(&dev->dev, "hbm: add client request received\n"); /* * after the host receives the enum_resp * message clients may be added or removed */ if (dev->hbm_state <= MEI_HBM_ENUM_CLIENTS || dev->hbm_state >= MEI_HBM_STOPPED) { - dev_err(dev->dev, "hbm: add client: state mismatch, [%d, %d]\n", + dev_err(&dev->dev, "hbm: add client: state mismatch, [%d, %d]\n", dev->dev_state, dev->hbm_state); return -EPROTO; } add_cl_req = (struct hbm_add_client_request *)mei_msg; ret = mei_hbm_fw_add_cl_req(dev, add_cl_req); if (ret) { - dev_err(dev->dev, "hbm: add client: failed to send response %d\n", + dev_err(&dev->dev, "hbm: add client: failed to send response %d\n", ret); return -EIO; } - dev_dbg(dev->dev, "hbm: add client request processed\n"); + dev_dbg(&dev->dev, "hbm: add client request processed\n"); break; case MEI_HBM_NOTIFY_RES_CMD: - dev_dbg(dev->dev, "hbm: notify response received\n"); + dev_dbg(&dev->dev, "hbm: notify response received\n"); mei_hbm_cl_res(dev, cl_cmd, notify_res_to_fop(cl_cmd)); break; case MEI_HBM_NOTIFICATION_CMD: - dev_dbg(dev->dev, "hbm: notification\n"); + dev_dbg(&dev->dev, "hbm: notification\n"); mei_hbm_cl_notify(dev, cl_cmd); break; case MEI_HBM_CLIENT_DMA_MAP_RES_CMD: - dev_dbg(dev->dev, "hbm: client dma map response: message received.\n"); + dev_dbg(&dev->dev, "hbm: client dma map response: message received.\n"); client_dma_res = (struct hbm_client_dma_response *)mei_msg; mei_hbm_cl_dma_map_res(dev, client_dma_res); break; case MEI_HBM_CLIENT_DMA_UNMAP_RES_CMD: - dev_dbg(dev->dev, "hbm: client dma unmap response: message received.\n"); + dev_dbg(&dev->dev, "hbm: client dma unmap response: message received.\n"); client_dma_res = (struct hbm_client_dma_response *)mei_msg; mei_hbm_cl_dma_unmap_res(dev, client_dma_res); break; diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index d11a0740b47c..346633ebc6e6 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -84,7 +84,7 @@ static inline u32 mei_me_mecsr_read(const struct mei_device *dev) u32 reg; reg = mei_me_reg_read(to_me_hw(dev), ME_CSR_HA); - trace_mei_reg_read(dev->dev, "ME_CSR_HA", ME_CSR_HA, reg); + trace_mei_reg_read(&dev->dev, "ME_CSR_HA", ME_CSR_HA, reg); return reg; } @@ -101,7 +101,7 @@ static inline u32 mei_hcsr_read(const struct mei_device *dev) u32 reg; reg = mei_me_reg_read(to_me_hw(dev), H_CSR); - trace_mei_reg_read(dev->dev, "H_CSR", H_CSR, reg); + trace_mei_reg_read(&dev->dev, "H_CSR", H_CSR, reg); return reg; } @@ -114,7 +114,7 @@ static inline u32 mei_hcsr_read(const struct mei_device *dev) */ static inline void mei_hcsr_write(struct mei_device *dev, u32 reg) { - trace_mei_reg_write(dev->dev, "H_CSR", H_CSR, reg); + trace_mei_reg_write(&dev->dev, "H_CSR", H_CSR, reg); mei_me_reg_write(to_me_hw(dev), H_CSR, reg); } @@ -156,7 +156,7 @@ static inline u32 mei_me_d0i3c_read(const struct mei_device *dev) u32 reg; reg = mei_me_reg_read(to_me_hw(dev), H_D0I3C); - trace_mei_reg_read(dev->dev, "H_D0I3C", H_D0I3C, reg); + trace_mei_reg_read(&dev->dev, "H_D0I3C", H_D0I3C, reg); return reg; } @@ -169,7 +169,7 @@ static inline u32 mei_me_d0i3c_read(const struct mei_device *dev) */ static inline void mei_me_d0i3c_write(struct mei_device *dev, u32 reg) { - trace_mei_reg_write(dev->dev, "H_D0I3C", H_D0I3C, reg); + trace_mei_reg_write(&dev->dev, "H_D0I3C", H_D0I3C, reg); mei_me_reg_write(to_me_hw(dev), H_D0I3C, reg); } @@ -189,7 +189,7 @@ static int mei_me_trc_status(struct mei_device *dev, u32 *trc) return -EOPNOTSUPP; *trc = mei_me_reg_read(hw, ME_TRC); - trace_mei_reg_read(dev->dev, "ME_TRC", ME_TRC, *trc); + trace_mei_reg_read(&dev->dev, "ME_TRC", ME_TRC, *trc); return 0; } @@ -217,7 +217,7 @@ static int mei_me_fw_status(struct mei_device *dev, for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) { ret = hw->read_fws(dev, fw_src->status[i], &fw_status->status[i]); - trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HFS_X", + trace_mei_pci_cfg_read(&dev->dev, "PCI_CFG_HFS_X", fw_src->status[i], fw_status->status[i]); if (ret) @@ -251,7 +251,7 @@ static int mei_me_hw_config(struct mei_device *dev) reg = 0; hw->read_fws(dev, PCI_CFG_HFS_1, ®); - trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HFS_1", PCI_CFG_HFS_1, reg); + trace_mei_pci_cfg_read(&dev->dev, "PCI_CFG_HFS_1", PCI_CFG_HFS_1, reg); hw->d0i3_supported = ((reg & PCI_CFG_HFS_1_D0I3_MSK) == PCI_CFG_HFS_1_D0I3_MSK); @@ -447,7 +447,7 @@ static void mei_gsc_pxp_check(struct mei_device *dev) return; hw->read_fws(dev, PCI_CFG_HFS_5, &fwsts5); - trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HFS_5", PCI_CFG_HFS_5, fwsts5); + trace_mei_pci_cfg_read(&dev->dev, "PCI_CFG_HFS_5", PCI_CFG_HFS_5, fwsts5); if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) { if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_DEFAULT) @@ -460,10 +460,10 @@ static void mei_gsc_pxp_check(struct mei_device *dev) return; if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) { - dev_dbg(dev->dev, "pxp mode is ready 0x%08x\n", fwsts5); + dev_dbg(&dev->dev, "pxp mode is ready 0x%08x\n", fwsts5); dev->pxp_mode = MEI_DEV_PXP_READY; } else { - dev_dbg(dev->dev, "pxp mode is not ready 0x%08x\n", fwsts5); + dev_dbg(&dev->dev, "pxp mode is not ready 0x%08x\n", fwsts5); } } @@ -482,7 +482,7 @@ static int mei_me_hw_ready_wait(struct mei_device *dev) dev->timeouts.hw_ready); mutex_lock(&dev->device_lock); if (!dev->recvd_hw_ready) { - dev_err(dev->dev, "wait hw ready failed\n"); + dev_err(&dev->dev, "wait hw ready failed\n"); return -ETIME; } @@ -516,12 +516,12 @@ static void mei_me_check_fw_reset(struct mei_device *dev) fw_pm_event != PCI_CFG_HFS_2_PM_CM_RESET_ERROR) goto end; } else { - dev_err(dev->dev, "failed to read firmware status: %d\n", ret); + dev_err(&dev->dev, "failed to read firmware status: %d\n", ret); } } mei_fw_status2str(&dev->saved_fw_status, fw_sts_str, sizeof(fw_sts_str)); - dev_warn(dev->dev, "unexpected reset: fw_pm_event = 0x%x, dev_state = %u fw status = %s\n", + dev_warn(&dev->dev, "unexpected reset: fw_pm_event = 0x%x, dev_state = %u fw status = %s\n", fw_pm_event, dev->saved_dev_state, fw_sts_str); end: @@ -544,7 +544,7 @@ static int mei_me_hw_start(struct mei_device *dev) mei_me_check_fw_reset(dev); if (ret) return ret; - dev_dbg(dev->dev, "hw is ready\n"); + dev_dbg(&dev->dev, "hw is ready\n"); mei_me_host_set_ready(dev); return ret; @@ -644,14 +644,14 @@ static int mei_me_hbuf_write(struct mei_device *dev, return -EINVAL; if (!data && data_len) { - dev_err(dev->dev, "wrong parameters null data with data_len = %zu\n", data_len); + dev_err(&dev->dev, "wrong parameters null data with data_len = %zu\n", data_len); return -EINVAL; } - dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM((struct mei_msg_hdr *)hdr)); + dev_dbg(&dev->dev, MEI_HDR_FMT, MEI_HDR_PRM((struct mei_msg_hdr *)hdr)); empty_slots = mei_hbuf_empty_slots(dev); - dev_dbg(dev->dev, "empty slots = %d.\n", empty_slots); + dev_dbg(&dev->dev, "empty slots = %d.\n", empty_slots); if (empty_slots < 0) return -EOVERFLOW; @@ -706,7 +706,7 @@ static int mei_me_count_full_read_slots(struct mei_device *dev) if (filled_slots > buffer_depth) return -EOVERFLOW; - dev_dbg(dev->dev, "filled_slots =%08x\n", filled_slots); + dev_dbg(&dev->dev, "filled_slots =%08x\n", filled_slots); return (int)filled_slots; } @@ -748,11 +748,11 @@ static void mei_me_pg_set(struct mei_device *dev) u32 reg; reg = mei_me_reg_read(hw, H_HPG_CSR); - trace_mei_reg_read(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); + trace_mei_reg_read(&dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); reg |= H_HPG_CSR_PGI; - trace_mei_reg_write(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); + trace_mei_reg_write(&dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); mei_me_reg_write(hw, H_HPG_CSR, reg); } @@ -767,13 +767,13 @@ static void mei_me_pg_unset(struct mei_device *dev) u32 reg; reg = mei_me_reg_read(hw, H_HPG_CSR); - trace_mei_reg_read(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); + trace_mei_reg_read(&dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); WARN(!(reg & H_HPG_CSR_PGI), "PGI is not set\n"); reg |= H_HPG_CSR_PGIHEXR; - trace_mei_reg_write(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); + trace_mei_reg_write(&dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); mei_me_reg_write(hw, H_HPG_CSR, reg); } @@ -905,7 +905,7 @@ static bool mei_me_pg_is_enabled(struct mei_device *dev) return true; notsupported: - dev_dbg(dev->dev, "pg: not supported: d0i3 = %d HGP = %d hbm version %d.%d ?= %d.%d\n", + dev_dbg(&dev->dev, "pg: not supported: d0i3 = %d HGP = %d hbm version %d.%d ?= %d.%d\n", hw->d0i3_supported, !!(reg & ME_PGIC_HRA), dev->version.major_version, @@ -974,7 +974,7 @@ static int mei_me_d0i3_enter_sync(struct mei_device *dev) reg = mei_me_d0i3c_read(dev); if (reg & H_D0I3C_I3) { /* we are in d0i3, nothing to do */ - dev_dbg(dev->dev, "d0i3 set not needed\n"); + dev_dbg(&dev->dev, "d0i3 set not needed\n"); ret = 0; goto on; } @@ -1003,7 +1003,7 @@ static int mei_me_d0i3_enter_sync(struct mei_device *dev) reg = mei_me_d0i3_set(dev, true); if (!(reg & H_D0I3C_CIP)) { - dev_dbg(dev->dev, "d0i3 enter wait not needed\n"); + dev_dbg(&dev->dev, "d0i3 enter wait not needed\n"); ret = 0; goto on; } @@ -1027,7 +1027,7 @@ on: hw->pg_state = MEI_PG_ON; out: dev->pg_event = MEI_PG_EVENT_IDLE; - dev_dbg(dev->dev, "d0i3 enter ret = %d\n", ret); + dev_dbg(&dev->dev, "d0i3 enter ret = %d\n", ret); return ret; } @@ -1049,7 +1049,7 @@ static int mei_me_d0i3_enter(struct mei_device *dev) reg = mei_me_d0i3c_read(dev); if (reg & H_D0I3C_I3) { /* we are in d0i3, nothing to do */ - dev_dbg(dev->dev, "already d0i3 : set not needed\n"); + dev_dbg(&dev->dev, "already d0i3 : set not needed\n"); goto on; } @@ -1057,7 +1057,7 @@ static int mei_me_d0i3_enter(struct mei_device *dev) on: hw->pg_state = MEI_PG_ON; dev->pg_event = MEI_PG_EVENT_IDLE; - dev_dbg(dev->dev, "d0i3 enter\n"); + dev_dbg(&dev->dev, "d0i3 enter\n"); return 0; } @@ -1079,14 +1079,14 @@ static int mei_me_d0i3_exit_sync(struct mei_device *dev) reg = mei_me_d0i3c_read(dev); if (!(reg & H_D0I3C_I3)) { /* we are not in d0i3, nothing to do */ - dev_dbg(dev->dev, "d0i3 exit not needed\n"); + dev_dbg(&dev->dev, "d0i3 exit not needed\n"); ret = 0; goto off; } reg = mei_me_d0i3_unset(dev); if (!(reg & H_D0I3C_CIP)) { - dev_dbg(dev->dev, "d0i3 exit wait not needed\n"); + dev_dbg(&dev->dev, "d0i3 exit wait not needed\n"); ret = 0; goto off; } @@ -1111,7 +1111,7 @@ off: out: dev->pg_event = MEI_PG_EVENT_IDLE; - dev_dbg(dev->dev, "d0i3 exit ret = %d\n", ret); + dev_dbg(&dev->dev, "d0i3 exit ret = %d\n", ret); return ret; } @@ -1154,7 +1154,7 @@ static void mei_me_d0i3_intr(struct mei_device *dev, u32 intr_source) * force H_RDY because it could be * wiped off during PG */ - dev_dbg(dev->dev, "d0i3 set host ready\n"); + dev_dbg(&dev->dev, "d0i3 set host ready\n"); mei_me_host_set_ready(dev); } } else { @@ -1170,7 +1170,7 @@ static void mei_me_d0i3_intr(struct mei_device *dev, u32 intr_source) * we got here because of HW initiated exit from D0i3. * Start runtime pm resume sequence to exit low power state. */ - dev_dbg(dev->dev, "d0i3 want resume\n"); + dev_dbg(&dev->dev, "d0i3 want resume\n"); mei_hbm_pg_resume(dev); } } @@ -1250,7 +1250,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) } } - pm_runtime_set_active(dev->dev); + pm_runtime_set_active(dev->parent); hcsr = mei_hcsr_read(dev); /* H_RST may be found lit before reset is started, @@ -1259,7 +1259,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) * we need to clean H_RST bit to start a successful reset sequence. */ if ((hcsr & H_RST) == H_RST) { - dev_warn(dev->dev, "H_RST is set = 0x%08X", hcsr); + dev_warn(&dev->dev, "H_RST is set = 0x%08X", hcsr); hcsr &= ~H_RST; mei_hcsr_set(dev, hcsr); hcsr = mei_hcsr_read(dev); @@ -1280,10 +1280,10 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) hcsr = mei_hcsr_read(dev); if ((hcsr & H_RST) == 0) - dev_warn(dev->dev, "H_RST is not set = 0x%08X", hcsr); + dev_warn(&dev->dev, "H_RST is not set = 0x%08X", hcsr); if ((hcsr & H_RDY) == H_RDY) - dev_warn(dev->dev, "H_RDY is not cleared 0x%08X", hcsr); + dev_warn(&dev->dev, "H_RDY is not cleared 0x%08X", hcsr); if (!intr_enable) { mei_me_hw_reset_release(dev); @@ -1313,7 +1313,7 @@ irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id) if (!me_intr_src(hcsr)) return IRQ_NONE; - dev_dbg(dev->dev, "interrupt source 0x%08X\n", me_intr_src(hcsr)); + dev_dbg(&dev->dev, "interrupt source 0x%08X\n", me_intr_src(hcsr)); /* disable interrupts on device */ me_intr_disable(dev, hcsr); @@ -1339,7 +1339,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) u32 hcsr; int rets = 0; - dev_dbg(dev->dev, "function called after ISR to handle the interrupt processing.\n"); + dev_dbg(&dev->dev, "function called after ISR to handle the interrupt processing.\n"); /* initialize our complete list */ mutex_lock(&dev->device_lock); @@ -1351,10 +1351,10 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) /* check if ME wants a reset */ if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { if (kind_is_gsc(dev) || kind_is_gscfi(dev)) { - dev_dbg(dev->dev, "FW not ready: resetting: dev_state = %d\n", + dev_dbg(&dev->dev, "FW not ready: resetting: dev_state = %d\n", dev->dev_state); } else { - dev_warn(dev->dev, "FW not ready: resetting: dev_state = %d\n", + dev_warn(&dev->dev, "FW not ready: resetting: dev_state = %d\n", dev->dev_state); } if (dev->dev_state == MEI_DEV_POWERING_DOWN || @@ -1373,18 +1373,18 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) /* check if we need to start the dev */ if (!mei_host_is_ready(dev)) { if (mei_hw_is_ready(dev)) { - dev_dbg(dev->dev, "we need to start the dev.\n"); + dev_dbg(&dev->dev, "we need to start the dev.\n"); dev->recvd_hw_ready = true; wake_up(&dev->wait_hw_ready); } else { - dev_dbg(dev->dev, "Spurious Interrupt\n"); + dev_dbg(&dev->dev, "Spurious Interrupt\n"); } goto end; } /* check slots available for reading */ slots = mei_count_full_read_slots(dev); while (slots > 0) { - dev_dbg(dev->dev, "slots to read = %08x\n", slots); + dev_dbg(&dev->dev, "slots to read = %08x\n", slots); rets = mei_irq_read_handler(dev, &cmpl_list, &slots); /* There is a race between ME write and interrupt delivery: * Not all data is always available immediately after the @@ -1394,7 +1394,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) break; if (rets) { - dev_err(dev->dev, "mei_irq_read_handler ret = %d, state = %d.\n", + dev_err(&dev->dev, "mei_irq_read_handler ret = %d, state = %d.\n", rets, dev->dev_state); if (dev->dev_state != MEI_DEV_RESETTING && dev->dev_state != MEI_DEV_DISABLED && @@ -1421,7 +1421,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) mei_irq_compl_handler(dev, &cmpl_list); end: - dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets); + dev_dbg(&dev->dev, "interrupt thread end ret = %d\n", rets); mei_me_intr_enable(dev); mutex_unlock(&dev->device_lock); return IRQ_HANDLED; @@ -1453,7 +1453,7 @@ int mei_me_polling_thread(void *_dev) irqreturn_t irq_ret; long polling_timeout = MEI_POLLING_TIMEOUT_ACTIVE; - dev_dbg(dev->dev, "kernel thread is running\n"); + dev_dbg(&dev->dev, "kernel thread is running\n"); while (!kthread_should_stop()) { struct mei_me_hw *hw = to_me_hw(dev); u32 hcsr; @@ -1470,7 +1470,7 @@ int mei_me_polling_thread(void *_dev) polling_timeout = MEI_POLLING_TIMEOUT_ACTIVE; irq_ret = mei_me_irq_thread_handler(1, dev); if (irq_ret != IRQ_HANDLED) - dev_err(dev->dev, "irq_ret %d\n", irq_ret); + dev_err(&dev->dev, "irq_ret %d\n", irq_ret); } else { /* * Increase timeout by MEI_POLLING_TIMEOUT_ACTIVE @@ -1804,7 +1804,7 @@ struct mei_device *mei_me_dev_init(struct device *parent, struct mei_me_hw *hw; int i; - dev = devm_kzalloc(parent, sizeof(*dev) + sizeof(*hw), GFP_KERNEL); + dev = kzalloc(sizeof(*dev) + sizeof(*hw), GFP_KERNEL); if (!dev) return NULL; diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c index e9476f9ae25d..e4688c391027 100644 --- a/drivers/misc/mei/hw-txe.c +++ b/drivers/misc/mei/hw-txe.c @@ -160,7 +160,7 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req) struct mei_txe_hw *hw = to_txe_hw(dev); bool do_req = hw->aliveness != req; - dev_dbg(dev->dev, "Aliveness current=%d request=%d\n", + dev_dbg(&dev->dev, "Aliveness current=%d request=%d\n", hw->aliveness, req); if (do_req) { dev->pg_event = MEI_PG_EVENT_WAIT; @@ -227,7 +227,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected) hw->aliveness = mei_txe_aliveness_get(dev); if (hw->aliveness == expected) { dev->pg_event = MEI_PG_EVENT_IDLE; - dev_dbg(dev->dev, "aliveness settled after %lld usecs\n", + dev_dbg(&dev->dev, "aliveness settled after %lld usecs\n", ktime_to_us(ktime_sub(ktime_get(), start))); return 0; } @@ -235,7 +235,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected) } while (ktime_before(ktime_get(), stop)); dev->pg_event = MEI_PG_EVENT_IDLE; - dev_err(dev->dev, "aliveness timed out\n"); + dev_err(&dev->dev, "aliveness timed out\n"); return -ETIME; } @@ -270,10 +270,10 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected) ret = hw->aliveness == expected ? 0 : -ETIME; if (ret) - dev_warn(dev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n", + dev_warn(&dev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n", err, hw->aliveness, dev->pg_event); else - dev_dbg(dev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n", + dev_dbg(&dev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n", jiffies_to_msecs(timeout - err), hw->aliveness, dev->pg_event); @@ -438,7 +438,7 @@ static void mei_txe_intr_enable(struct mei_device *dev) */ static void mei_txe_synchronize_irq(struct mei_device *dev) { - struct pci_dev *pdev = to_pci_dev(dev->dev); + struct pci_dev *pdev = to_pci_dev(dev->parent); synchronize_irq(pdev->irq); } @@ -464,7 +464,7 @@ static bool mei_txe_pending_interrupts(struct mei_device *dev) TXE_INTR_OUT_DB)); if (ret) { - dev_dbg(dev->dev, + dev_dbg(&dev->dev, "Pending Interrupts InReady=%01d Readiness=%01d, Aliveness=%01d, OutDoor=%01d\n", !!(hw->intr_cause & TXE_INTR_IN_READY), !!(hw->intr_cause & TXE_INTR_READINESS), @@ -612,7 +612,7 @@ static int mei_txe_readiness_wait(struct mei_device *dev) msecs_to_jiffies(SEC_RESET_WAIT_TIMEOUT)); mutex_lock(&dev->device_lock); if (!dev->recvd_hw_ready) { - dev_err(dev->dev, "wait for readiness failed\n"); + dev_err(&dev->dev, "wait for readiness failed\n"); return -ETIME; } @@ -638,7 +638,7 @@ static int mei_txe_fw_status(struct mei_device *dev, struct mei_fw_status *fw_status) { const struct mei_fw_status *fw_src = &mei_txe_fw_sts; - struct pci_dev *pdev = to_pci_dev(dev->dev); + struct pci_dev *pdev = to_pci_dev(dev->parent); int ret; int i; @@ -649,7 +649,7 @@ static int mei_txe_fw_status(struct mei_device *dev, for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) { ret = pci_read_config_dword(pdev, fw_src->status[i], &fw_status->status[i]); - trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HSF_X", + trace_mei_pci_cfg_read(&dev->dev, "PCI_CFG_HSF_X", fw_src->status[i], fw_status->status[i]); if (ret) @@ -677,7 +677,7 @@ static int mei_txe_hw_config(struct mei_device *dev) hw->aliveness = mei_txe_aliveness_get(dev); hw->readiness = mei_txe_readiness_get(dev); - dev_dbg(dev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n", + dev_dbg(&dev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n", hw->aliveness, hw->readiness); return 0; @@ -708,7 +708,7 @@ static int mei_txe_write(struct mei_device *dev, if (WARN_ON(!hdr || !data || hdr_len & 0x3)) return -EINVAL; - dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM((struct mei_msg_hdr *)hdr)); + dev_dbg(&dev->dev, MEI_HDR_FMT, MEI_HDR_PRM((struct mei_msg_hdr *)hdr)); dw_cnt = mei_data2slots(hdr_len + data_len); if (dw_cnt > slots) @@ -724,7 +724,7 @@ static int mei_txe_write(struct mei_device *dev, char fw_sts_str[MEI_FW_STATUS_STR_SZ]; mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ); - dev_err(dev->dev, "Input is not ready %s\n", fw_sts_str); + dev_err(&dev->dev, "Input is not ready %s\n", fw_sts_str); return -EAGAIN; } @@ -828,13 +828,13 @@ static int mei_txe_read(struct mei_device *dev, reg_buf = (u32 *)buf; rem = len & 0x3; - dev_dbg(dev->dev, "buffer-length = %lu buf[0]0x%08X\n", + dev_dbg(&dev->dev, "buffer-length = %lu buf[0]0x%08X\n", len, mei_txe_out_data_read(dev, 0)); for (i = 0; i < len / MEI_SLOT_SIZE; i++) { /* skip header: index starts from 1 */ reg = mei_txe_out_data_read(dev, i + 1); - dev_dbg(dev->dev, "buf[%d] = 0x%08X\n", i, reg); + dev_dbg(&dev->dev, "buf[%d] = 0x%08X\n", i, reg); *reg_buf++ = reg; } @@ -879,7 +879,7 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable) */ if (aliveness_req != hw->aliveness) if (mei_txe_aliveness_poll(dev, aliveness_req) < 0) { - dev_err(dev->dev, "wait for aliveness settle failed ... bailing out\n"); + dev_err(&dev->dev, "wait for aliveness settle failed ... bailing out\n"); return -EIO; } @@ -889,7 +889,7 @@ static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable) if (aliveness_req) { mei_txe_aliveness_set(dev, 0); if (mei_txe_aliveness_poll(dev, 0) < 0) { - dev_err(dev->dev, "wait for aliveness failed ... bailing out\n"); + dev_err(&dev->dev, "wait for aliveness failed ... bailing out\n"); return -EIO; } } @@ -921,7 +921,7 @@ static int mei_txe_hw_start(struct mei_device *dev) ret = mei_txe_readiness_wait(dev); if (ret < 0) { - dev_err(dev->dev, "waiting for readiness failed\n"); + dev_err(&dev->dev, "waiting for readiness failed\n"); return ret; } @@ -937,11 +937,11 @@ static int mei_txe_hw_start(struct mei_device *dev) ret = mei_txe_aliveness_set_sync(dev, 1); if (ret < 0) { - dev_err(dev->dev, "wait for aliveness failed ... bailing out\n"); + dev_err(&dev->dev, "wait for aliveness failed ... bailing out\n"); return ret; } - pm_runtime_set_active(dev->dev); + pm_runtime_set_active(dev->parent); /* enable input ready interrupts: * SEC_IPC_HOST_INT_MASK.IPC_INPUT_READY_INT_MASK @@ -1049,7 +1049,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) s32 slots; int rets = 0; - dev_dbg(dev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n", + dev_dbg(&dev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n", mei_txe_br_reg_read(hw, HHISR_REG), mei_txe_br_reg_read(hw, HISR_REG), mei_txe_sec_reg_read_silent(hw, SEC_IPC_HOST_INT_STATUS_REG)); @@ -1059,7 +1059,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) mutex_lock(&dev->device_lock); INIT_LIST_HEAD(&cmpl_list); - if (pci_dev_msi_enabled(to_pci_dev(dev->dev))) + if (pci_dev_msi_enabled(to_pci_dev(dev->parent))) mei_txe_check_and_ack_intrs(dev, true); /* show irq events */ @@ -1073,17 +1073,17 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) * or TXE driver resetting the HECI interface. */ if (test_and_clear_bit(TXE_INTR_READINESS_BIT, &hw->intr_cause)) { - dev_dbg(dev->dev, "Readiness Interrupt was received...\n"); + dev_dbg(&dev->dev, "Readiness Interrupt was received...\n"); /* Check if SeC is going through reset */ if (mei_txe_readiness_is_sec_rdy(hw->readiness)) { - dev_dbg(dev->dev, "we need to start the dev.\n"); + dev_dbg(&dev->dev, "we need to start the dev.\n"); dev->recvd_hw_ready = true; } else { dev->recvd_hw_ready = false; if (dev->dev_state != MEI_DEV_RESETTING) { - dev_warn(dev->dev, "FW not ready: resetting.\n"); + dev_warn(&dev->dev, "FW not ready: resetting.\n"); schedule_work(&dev->reset_work); goto end; @@ -1100,7 +1100,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) if (test_and_clear_bit(TXE_INTR_ALIVENESS_BIT, &hw->intr_cause)) { /* Clear the interrupt cause */ - dev_dbg(dev->dev, + dev_dbg(&dev->dev, "Aliveness Interrupt: Status: %d\n", hw->aliveness); dev->pg_event = MEI_PG_EVENT_RECEIVED; if (waitqueue_active(&hw->wait_aliveness_resp)) @@ -1118,7 +1118,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) if (rets && (dev->dev_state != MEI_DEV_RESETTING && dev->dev_state != MEI_DEV_POWER_DOWN)) { - dev_err(dev->dev, + dev_err(&dev->dev, "mei_irq_read_handler ret = %d.\n", rets); schedule_work(&dev->reset_work); @@ -1136,7 +1136,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) dev->hbuf_is_ready = mei_hbuf_is_ready(dev); rets = mei_irq_write_handler(dev, &cmpl_list); if (rets && rets != -EMSGSIZE) - dev_err(dev->dev, "mei_irq_write_handler ret = %d.\n", + dev_err(&dev->dev, "mei_irq_write_handler ret = %d.\n", rets); dev->hbuf_is_ready = mei_hbuf_is_ready(dev); } @@ -1144,7 +1144,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) mei_irq_compl_handler(dev, &cmpl_list); end: - dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets); + dev_dbg(&dev->dev, "interrupt thread end ret = %d\n", rets); mutex_unlock(&dev->device_lock); @@ -1197,7 +1197,7 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev) struct mei_device *dev; struct mei_txe_hw *hw; - dev = devm_kzalloc(&pdev->dev, sizeof(*dev) + sizeof(*hw), GFP_KERNEL); + dev = kzalloc(sizeof(*dev) + sizeof(*hw), GFP_KERNEL); if (!dev) return NULL; diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 8ef2b1df8ac7..4d1d5423b612 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -96,7 +96,7 @@ static void mei_save_fw_status(struct mei_device *dev) ret = mei_fw_status(dev, &fw_status); if (ret) { - dev_err(dev->dev, "failed to read firmware status: %d\n", ret); + dev_err(&dev->dev, "failed to read firmware status: %d\n", ret); return; } @@ -126,11 +126,11 @@ int mei_reset(struct mei_device *dev) mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ); if (kind_is_gsc(dev) || kind_is_gscfi(dev)) { - dev_dbg(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", + dev_dbg(&dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", mei_dev_state_str(state), fw_sts_str); mei_save_fw_status(dev); } else { - dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", + dev_warn(&dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", mei_dev_state_str(state), fw_sts_str); } } @@ -150,7 +150,7 @@ int mei_reset(struct mei_device *dev) dev->reset_count++; if (dev->reset_count > MEI_MAX_CONSEC_RESET) { - dev_err(dev->dev, "reset: reached maximal consecutive resets: disabling the device\n"); + dev_err(&dev->dev, "reset: reached maximal consecutive resets: disabling the device\n"); mei_set_devstate(dev, MEI_DEV_DISABLED); return -ENODEV; } @@ -170,12 +170,12 @@ int mei_reset(struct mei_device *dev) memset(dev->rd_msg_hdr, 0, sizeof(dev->rd_msg_hdr)); if (ret) { - dev_err(dev->dev, "hw_reset failed ret = %d\n", ret); + dev_err(&dev->dev, "hw_reset failed ret = %d\n", ret); return ret; } if (state == MEI_DEV_POWER_DOWN) { - dev_dbg(dev->dev, "powering down: end of reset\n"); + dev_dbg(&dev->dev, "powering down: end of reset\n"); mei_set_devstate(dev, MEI_DEV_DISABLED); return 0; } @@ -185,21 +185,21 @@ int mei_reset(struct mei_device *dev) char fw_sts_str[MEI_FW_STATUS_STR_SZ]; mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ); - dev_err(dev->dev, "hw_start failed ret = %d fw status = %s\n", ret, fw_sts_str); + dev_err(&dev->dev, "hw_start failed ret = %d fw status = %s\n", ret, fw_sts_str); return ret; } if (dev->dev_state != MEI_DEV_RESETTING) { - dev_dbg(dev->dev, "wrong state = %d on link start\n", dev->dev_state); + dev_dbg(&dev->dev, "wrong state = %d on link start\n", dev->dev_state); return 0; } - dev_dbg(dev->dev, "link is established start sending messages.\n"); + dev_dbg(&dev->dev, "link is established start sending messages.\n"); mei_set_devstate(dev, MEI_DEV_INIT_CLIENTS); ret = mei_hbm_start_req(dev); if (ret) { - dev_err(dev->dev, "hbm_start failed ret = %d\n", ret); + dev_err(&dev->dev, "hbm_start failed ret = %d\n", ret); mei_set_devstate(dev, MEI_DEV_RESETTING); return ret; } @@ -228,7 +228,7 @@ int mei_start(struct mei_device *dev) if (ret) goto err; - dev_dbg(dev->dev, "reset in start the mei device.\n"); + dev_dbg(&dev->dev, "reset in start the mei device.\n"); dev->reset_count = 0; do { @@ -236,27 +236,27 @@ int mei_start(struct mei_device *dev) ret = mei_reset(dev); if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) { - dev_err(dev->dev, "reset failed ret = %d", ret); + dev_err(&dev->dev, "reset failed ret = %d", ret); goto err; } } while (ret); if (mei_hbm_start_wait(dev)) { - dev_err(dev->dev, "HBM haven't started"); + dev_err(&dev->dev, "HBM haven't started"); goto err; } if (!mei_hbm_version_is_supported(dev)) { - dev_dbg(dev->dev, "MEI start failed.\n"); + dev_dbg(&dev->dev, "MEI start failed.\n"); goto err; } - dev_dbg(dev->dev, "link layer has been established.\n"); + dev_dbg(&dev->dev, "link layer has been established.\n"); mutex_unlock(&dev->device_lock); return 0; err: - dev_err(dev->dev, "link layer initialization failed.\n"); + dev_err(&dev->dev, "link layer initialization failed.\n"); mei_set_devstate(dev, MEI_DEV_DISABLED); mutex_unlock(&dev->device_lock); return -ENODEV; @@ -284,7 +284,7 @@ int mei_restart(struct mei_device *dev) mutex_unlock(&dev->device_lock); if (err == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) { - dev_err(dev->dev, "device disabled = %d\n", err); + dev_err(&dev->dev, "device disabled = %d\n", err); return -ENODEV; } @@ -313,7 +313,7 @@ static void mei_reset_work(struct work_struct *work) mutex_unlock(&dev->device_lock); if (dev->dev_state == MEI_DEV_DISABLED) { - dev_err(dev->dev, "device disabled = %d\n", ret); + dev_err(&dev->dev, "device disabled = %d\n", ret); return; } @@ -324,7 +324,7 @@ static void mei_reset_work(struct work_struct *work) void mei_stop(struct mei_device *dev) { - dev_dbg(dev->dev, "stopping the device.\n"); + dev_dbg(&dev->dev, "stopping the device.\n"); mutex_lock(&dev->device_lock); mei_set_devstate(dev, MEI_DEV_POWERING_DOWN); @@ -365,7 +365,7 @@ bool mei_write_is_idle(struct mei_device *dev) list_empty(&dev->write_list) && list_empty(&dev->write_waiting_list)); - dev_dbg(dev->dev, "write pg: is idle[%d] state=%s ctrl=%01d write=%01d wwait=%01d\n", + dev_dbg(&dev->dev, "write pg: is idle[%d] state=%s ctrl=%01d write=%01d wwait=%01d\n", idle, mei_dev_state_str(dev->dev_state), list_empty(&dev->ctrl_wr_list), @@ -380,12 +380,12 @@ EXPORT_SYMBOL_GPL(mei_write_is_idle); * mei_device_init - initialize mei_device structure * * @dev: the mei device - * @device: the device structure + * @parent: the parent device * @slow_fw: configure longer timeouts as FW is slow * @hw_ops: hw operations */ void mei_device_init(struct mei_device *dev, - struct device *device, + struct device *parent, bool slow_fw, const struct mei_hw_ops *hw_ops) { @@ -426,7 +426,7 @@ void mei_device_init(struct mei_device *dev, dev->pg_event = MEI_PG_EVENT_IDLE; dev->ops = hw_ops; - dev->dev = device; + dev->parent = parent; dev->timeouts.hw_ready = mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT); dev->timeouts.connect = MEI_CONNECT_TIMEOUT; @@ -444,4 +444,3 @@ void mei_device_init(struct mei_device *dev, } } EXPORT_SYMBOL_GPL(mei_device_init); - diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index d472f6bbe767..3aa66b6b0d36 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -76,7 +76,7 @@ static void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr, * that length fits into rd_msg_buf */ mei_read_slots(dev, dev->rd_msg_buf, discard_len); - dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", + dev_dbg(&dev->dev, "discarding message " MEI_HDR_FMT "\n", MEI_HDR_PRM(hdr)); } @@ -229,8 +229,8 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl, cl_dbg(dev, cl, "completed read length = %zu\n", cb->buf_idx); list_move_tail(&cb->list, cmpl_list); } else { - pm_runtime_mark_last_busy(dev->dev); - pm_request_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + pm_request_autosuspend(dev->parent); } return 0; @@ -310,8 +310,8 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, return ret; } - pm_runtime_mark_last_busy(dev->dev); - pm_request_autosuspend(dev->dev); + pm_runtime_mark_last_busy(dev->parent); + pm_request_autosuspend(dev->parent); list_move_tail(&cb->list, &cl->rd_pending); @@ -373,21 +373,21 @@ int mei_irq_read_handler(struct mei_device *dev, dev->rd_msg_hdr[0] = mei_read_hdr(dev); dev->rd_msg_hdr_count = 1; (*slots)--; - dev_dbg(dev->dev, "slots =%08x.\n", *slots); + dev_dbg(&dev->dev, "slots =%08x.\n", *slots); ret = hdr_is_valid(dev->rd_msg_hdr[0]); if (ret) { - dev_err(dev->dev, "corrupted message header 0x%08X\n", + dev_err(&dev->dev, "corrupted message header 0x%08X\n", dev->rd_msg_hdr[0]); goto end; } } mei_hdr = (struct mei_msg_hdr *)dev->rd_msg_hdr; - dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); + dev_dbg(&dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); if (mei_slots2data(*slots) < mei_hdr->length) { - dev_err(dev->dev, "less data available than length=%08x.\n", + dev_err(&dev->dev, "less data available than length=%08x.\n", *slots); /* we can't read the message */ ret = -ENODATA; @@ -402,18 +402,18 @@ int mei_irq_read_handler(struct mei_device *dev, dev->rd_msg_hdr[1] = mei_read_hdr(dev); dev->rd_msg_hdr_count++; (*slots)--; - dev_dbg(dev->dev, "extended header is %08x\n", dev->rd_msg_hdr[1]); + dev_dbg(&dev->dev, "extended header is %08x\n", dev->rd_msg_hdr[1]); } meta_hdr = ((struct mei_ext_meta_hdr *)&dev->rd_msg_hdr[1]); if (check_add_overflow((u32)sizeof(*meta_hdr), mei_slots2data(meta_hdr->size), &hdr_size_ext)) { - dev_err(dev->dev, "extended message size too big %d\n", + dev_err(&dev->dev, "extended message size too big %d\n", meta_hdr->size); return -EBADMSG; } if (hdr_size_left < hdr_size_ext) { - dev_err(dev->dev, "corrupted message header len %d\n", + dev_err(&dev->dev, "corrupted message header len %d\n", mei_hdr->length); return -EBADMSG; } @@ -422,7 +422,7 @@ int mei_irq_read_handler(struct mei_device *dev, ext_hdr_end = meta_hdr->size + 2; for (i = dev->rd_msg_hdr_count; i < ext_hdr_end; i++) { dev->rd_msg_hdr[i] = mei_read_hdr(dev); - dev_dbg(dev->dev, "extended header %d is %08x\n", i, + dev_dbg(&dev->dev, "extended header %d is %08x\n", i, dev->rd_msg_hdr[i]); dev->rd_msg_hdr_count++; (*slots)--; @@ -431,7 +431,7 @@ int mei_irq_read_handler(struct mei_device *dev, if (mei_hdr->dma_ring) { if (hdr_size_left != sizeof(dev->rd_msg_hdr[ext_hdr_end])) { - dev_err(dev->dev, "corrupted message header len %d\n", + dev_err(&dev->dev, "corrupted message header len %d\n", mei_hdr->length); return -EBADMSG; } @@ -446,8 +446,7 @@ int mei_irq_read_handler(struct mei_device *dev, if (hdr_is_hbm(mei_hdr)) { ret = mei_hbm_dispatch(dev, mei_hdr); if (ret) { - dev_dbg(dev->dev, "mei_hbm_dispatch failed ret = %d\n", - ret); + dev_dbg(&dev->dev, "mei_hbm_dispatch failed ret = %d\n", ret); goto end; } goto reset_slots; @@ -474,7 +473,7 @@ int mei_irq_read_handler(struct mei_device *dev, ret = 0; goto reset_slots; } - dev_err(dev->dev, "no destination client found 0x%08X\n", dev->rd_msg_hdr[0]); + dev_err(&dev->dev, "no destination client found 0x%08X\n", dev->rd_msg_hdr[0]); ret = -EBADMSG; goto end; @@ -485,7 +484,7 @@ reset_slots: *slots = mei_count_full_read_slots(dev); if (*slots == -EOVERFLOW) { /* overflow - reset */ - dev_err(dev->dev, "resetting due to slots overflow.\n"); + dev_err(&dev->dev, "resetting due to slots overflow.\n"); /* set the event since message has been read */ ret = -ERANGE; goto end; @@ -525,7 +524,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list) return -EMSGSIZE; /* complete all waiting for write CB */ - dev_dbg(dev->dev, "complete all waiting for write cb.\n"); + dev_dbg(&dev->dev, "complete all waiting for write cb.\n"); list_for_each_entry_safe(cb, next, &dev->write_waiting_list, list) { cl = cb->cl; @@ -537,7 +536,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list) } /* complete control write list CB */ - dev_dbg(dev->dev, "complete control write list cb.\n"); + dev_dbg(&dev->dev, "complete control write list cb.\n"); list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list, list) { cl = cb->cl; switch (cb->fop_type) { @@ -591,7 +590,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list) } /* complete write list CB */ - dev_dbg(dev->dev, "complete write list cb.\n"); + dev_dbg(&dev->dev, "complete write list cb.\n"); list_for_each_entry_safe(cb, next, &dev->write_list, list) { cl = cb->cl; ret = mei_cl_irq_write(cl, cb, cmpl_list); @@ -656,7 +655,7 @@ void mei_timer(struct work_struct *work) if (dev->init_clients_timer) { if (--dev->init_clients_timer == 0) { - dev_err(dev->dev, "timer: init clients timeout hbm_state = %d.\n", + dev_err(&dev->dev, "timer: init clients timeout hbm_state = %d.\n", dev->hbm_state); mei_reset(dev); goto out; @@ -672,7 +671,7 @@ void mei_timer(struct work_struct *work) list_for_each_entry(cl, &dev->file_list, link) { if (cl->timer_count) { if (--cl->timer_count == 0) { - dev_err(dev->dev, "timer: connect/disconnect timeout.\n"); + dev_err(&dev->dev, "timer: connect/disconnect timeout.\n"); mei_connect_timeout(cl); goto out; } diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 8a149a15b861..f37f9b8b1f51 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -51,12 +51,15 @@ static int mei_open(struct inode *inode, struct file *file) int err; - dev = container_of(inode->i_cdev, struct mei_device, cdev); + dev = idr_find(&mei_idr, iminor(inode)); + if (!dev) + return -ENODEV; + get_device(&dev->dev); mutex_lock(&dev->device_lock); if (dev->dev_state != MEI_DEV_ENABLED) { - dev_dbg(dev->dev, "dev_state != MEI_ENABLED dev_state = %s\n", + dev_dbg(&dev->dev, "dev_state != MEI_ENABLED dev_state = %s\n", mei_dev_state_str(dev->dev_state)); err = -ENODEV; goto err_unlock; @@ -77,6 +80,7 @@ static int mei_open(struct inode *inode, struct file *file) err_unlock: mutex_unlock(&dev->device_lock); + put_device(&dev->dev); return err; } @@ -152,6 +156,7 @@ out: file->private_data = NULL; mutex_unlock(&dev->device_lock); + put_device(&dev->dev); return rets; } @@ -477,7 +482,7 @@ static int mei_vt_support_check(struct mei_device *dev, const uuid_le *uuid) me_cl = mei_me_cl_by_uuid(dev, uuid); if (!me_cl) { - dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n", + dev_dbg(&dev->dev, "Cannot connect to FW Client UUID = %pUl\n", uuid); return -ENOTTY; } @@ -1115,7 +1120,10 @@ void mei_set_devstate(struct mei_device *dev, enum mei_dev_state state) dev->dev_state = state; - clsdev = class_find_device_by_devt(&mei_class, dev->cdev.dev); + if (!dev->cdev) + return; + + clsdev = class_find_device_by_devt(&mei_class, dev->cdev->dev); if (clsdev) { sysfs_notify(&clsdev->kobj, NULL, "dev_state"); put_device(clsdev); @@ -1191,7 +1199,7 @@ static int mei_minor_get(struct mei_device *dev) if (ret >= 0) dev->minor = ret; else if (ret == -ENOSPC) - dev_err(dev->dev, "too many mei devices\n"); + dev_err(&dev->dev, "too many mei devices\n"); mutex_unlock(&mei_minor_lock); return ret; @@ -1209,9 +1217,13 @@ static void mei_minor_free(struct mei_device *dev) mutex_unlock(&mei_minor_lock); } +static void mei_device_release(struct device *dev) +{ + kfree(dev_get_drvdata(dev)); +} + int mei_register(struct mei_device *dev, struct device *parent) { - struct device *clsdev; /* class device */ int ret, devno; ret = mei_minor_get(dev); @@ -1220,35 +1232,53 @@ int mei_register(struct mei_device *dev, struct device *parent) /* Fill in the data structures */ devno = MKDEV(MAJOR(mei_devt), dev->minor); - cdev_init(&dev->cdev, &mei_fops); - dev->cdev.owner = parent->driver->owner; + + device_initialize(&dev->dev); + dev->dev.devt = devno; + dev->dev.class = &mei_class; + dev->dev.parent = parent; + dev->dev.groups = mei_groups; + dev->dev.release = mei_device_release; + dev_set_drvdata(&dev->dev, dev); + + dev->cdev = cdev_alloc(); + if (!dev->cdev) { + ret = -ENOMEM; + goto err; + } + dev->cdev->ops = &mei_fops; + dev->cdev->owner = parent->driver->owner; + cdev_set_parent(dev->cdev, &dev->dev.kobj); /* Add the device */ - ret = cdev_add(&dev->cdev, devno, 1); + ret = cdev_add(dev->cdev, devno, 1); if (ret) { - dev_err(parent, "unable to add device %d:%d\n", + dev_err(parent, "unable to add cdev for device %d:%d\n", MAJOR(mei_devt), dev->minor); - goto err_dev_add; + goto err_del_cdev; } - clsdev = device_create_with_groups(&mei_class, parent, devno, - dev, mei_groups, - "mei%d", dev->minor); - - if (IS_ERR(clsdev)) { - dev_err(parent, "unable to create device %d:%d\n", - MAJOR(mei_devt), dev->minor); - ret = PTR_ERR(clsdev); - goto err_dev_create; + ret = dev_set_name(&dev->dev, "mei%d", dev->minor); + if (ret) { + dev_err(parent, "unable to set name to device %d:%d ret = %d\n", + MAJOR(mei_devt), dev->minor, ret); + goto err_del_cdev; } - mei_dbgfs_register(dev, dev_name(clsdev)); + ret = device_add(&dev->dev); + if (ret) { + dev_err(parent, "unable to add device %d:%d ret = %d\n", + MAJOR(mei_devt), dev->minor, ret); + goto err_del_cdev; + } + + mei_dbgfs_register(dev, dev_name(&dev->dev)); return 0; -err_dev_create: - cdev_del(&dev->cdev); -err_dev_add: +err_del_cdev: + cdev_del(dev->cdev); +err: mei_minor_free(dev); return ret; } @@ -1258,8 +1288,8 @@ void mei_deregister(struct mei_device *dev) { int devno; - devno = dev->cdev.dev; - cdev_del(&dev->cdev); + devno = dev->cdev->dev; + cdev_del(dev->cdev); mei_dbgfs_deregister(dev); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 37d7fb15cad7..4ab2b9100fd4 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -470,8 +470,9 @@ struct mei_dev_timeouts { /** * struct mei_device - MEI private device struct * - * @dev : device on a bus - * @cdev : character device + * @parent : device on a bus + * @dev : device object + * @cdev : character device pointer * @minor : minor number allocated for device * * @write_list : write pending list @@ -556,8 +557,9 @@ struct mei_dev_timeouts { * @hw : hw specific data */ struct mei_device { - struct device *dev; - struct cdev cdev; + struct device *parent; + struct device dev; + struct cdev *cdev; int minor; struct list_head write_list; @@ -703,7 +705,7 @@ static inline u32 mei_slots2data(int slots) * mei init function prototypes */ void mei_device_init(struct mei_device *dev, - struct device *device, + struct device *parent, bool slow_fw, const struct mei_hw_ops *hw_ops); int mei_reset(struct mei_device *dev); diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 3f9c60b579ae..b108a7c22388 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -143,7 +143,7 @@ static inline void mei_me_unset_pm_domain(struct mei_device *dev) {} static int mei_me_read_fws(const struct mei_device *dev, int where, u32 *val) { - struct pci_dev *pdev = to_pci_dev(dev->dev); + struct pci_dev *pdev = to_pci_dev(dev->parent); return pci_read_config_dword(pdev, where, val); } @@ -238,19 +238,19 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto end; } + err = mei_register(dev, &pdev->dev); + if (err) + goto release_irq; + if (mei_start(dev)) { dev_err(&pdev->dev, "init hw failure.\n"); err = -ENODEV; - goto release_irq; + goto deregister; } pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_ME_RPM_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); - err = mei_register(dev, &pdev->dev); - if (err) - goto stop; - pci_set_drvdata(pdev, dev); /* @@ -280,8 +280,8 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; -stop: - mei_stop(dev); +deregister: + mei_deregister(dev); release_irq: mei_cancel_work(dev); mei_disable_interrupts(dev); @@ -475,7 +475,7 @@ static int mei_me_pm_runtime_resume(struct device *device) */ static inline void mei_me_set_pm_domain(struct mei_device *dev) { - struct pci_dev *pdev = to_pci_dev(dev->dev); + struct pci_dev *pdev = to_pci_dev(dev->parent); if (pdev->dev.bus && pdev->dev.bus->pm) { dev->pg_domain.ops = *pdev->dev.bus->pm; @@ -496,7 +496,7 @@ static inline void mei_me_set_pm_domain(struct mei_device *dev) static inline void mei_me_unset_pm_domain(struct mei_device *dev) { /* stop using pm callbacks if any */ - dev_pm_domain_set(dev->dev, NULL); + dev_pm_domain_set(dev->parent, NULL); } static const struct dev_pm_ops mei_me_pm_ops = { diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c index 2a584104ba38..c9eb5c5393e4 100644 --- a/drivers/misc/mei/pci-txe.c +++ b/drivers/misc/mei/pci-txe.c @@ -321,7 +321,7 @@ static int mei_txe_pm_runtime_resume(struct device *device) */ static inline void mei_txe_set_pm_domain(struct mei_device *dev) { - struct pci_dev *pdev = to_pci_dev(dev->dev); + struct pci_dev *pdev = to_pci_dev(dev->parent); if (pdev->dev.bus && pdev->dev.bus->pm) { dev->pg_domain.ops = *pdev->dev.bus->pm; @@ -342,7 +342,7 @@ static inline void mei_txe_set_pm_domain(struct mei_device *dev) static inline void mei_txe_unset_pm_domain(struct mei_device *dev) { /* stop using pm callbacks if any */ - dev_pm_domain_set(dev->dev, NULL); + dev_pm_domain_set(dev->parent, NULL); } static const struct dev_pm_ops mei_txe_pm_ops = { diff --git a/drivers/misc/mei/platform-vsc.c b/drivers/misc/mei/platform-vsc.c index b2b5a20ae3fa..288e7b72e942 100644 --- a/drivers/misc/mei/platform-vsc.c +++ b/drivers/misc/mei/platform-vsc.c @@ -152,7 +152,7 @@ static int mei_vsc_hw_start(struct mei_device *mei_dev) MEI_VSC_POLL_TIMEOUT_US, true, hw, &buf, sizeof(buf)); if (ret) { - dev_err(mei_dev->dev, "wait fw ready failed: %d\n", ret); + dev_err(&mei_dev->dev, "wait fw ready failed: %d\n", ret); return ret; } @@ -259,7 +259,7 @@ static int mei_vsc_hw_reset(struct mei_device *mei_dev, bool intr_enable) if (!intr_enable) return 0; - return vsc_tp_init(hw->tp, mei_dev->dev); + return vsc_tp_init(hw->tp, mei_dev->parent); } static const struct mei_hw_ops mei_vsc_hw_ops = { @@ -325,7 +325,7 @@ static void mei_vsc_event_cb(void *context) mei_dev->hbuf_is_ready = mei_hbuf_is_ready(mei_dev); ret = mei_irq_write_handler(mei_dev, &cmpl_list); if (ret) - dev_err(mei_dev->dev, "dispatch write request failed: %d\n", ret); + dev_err(&mei_dev->dev, "dispatch write request failed: %d\n", ret); mei_dev->hbuf_is_ready = mei_hbuf_is_ready(mei_dev); mei_irq_compl_handler(mei_dev, &cmpl_list); @@ -343,12 +343,12 @@ static int mei_vsc_probe(struct platform_device *pdev) if (!tp) return dev_err_probe(dev, -ENODEV, "no platform data\n"); - mei_dev = devm_kzalloc(dev, size_add(sizeof(*mei_dev), sizeof(*hw)), - GFP_KERNEL); + mei_dev = kzalloc(size_add(sizeof(*mei_dev), sizeof(*hw)), GFP_KERNEL); if (!mei_dev) return -ENOMEM; mei_device_init(mei_dev, dev, false, &mei_vsc_hw_ops); + mei_dev->fw_f_fw_ver_supported = 0; mei_dev->kind = "ivsc"; @@ -360,22 +360,22 @@ static int mei_vsc_probe(struct platform_device *pdev) vsc_tp_register_event_cb(tp, mei_vsc_event_cb, mei_dev); + ret = mei_register(mei_dev, dev); + if (ret) + goto err_dereg; + ret = mei_start(mei_dev); if (ret) { dev_err_probe(dev, ret, "init hw failed\n"); goto err_cancel; } - ret = mei_register(mei_dev, dev); - if (ret) - goto err_stop; - - pm_runtime_enable(mei_dev->dev); + pm_runtime_enable(mei_dev->parent); return 0; -err_stop: - mei_stop(mei_dev); +err_dereg: + mei_deregister(mei_dev); err_cancel: mei_cancel_work(mei_dev); @@ -392,7 +392,7 @@ static void mei_vsc_remove(struct platform_device *pdev) struct mei_device *mei_dev = platform_get_drvdata(pdev); struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev); - pm_runtime_disable(mei_dev->dev); + pm_runtime_disable(mei_dev->parent); mei_stop(mei_dev); From 43bd82eb33b2ac33232724a8ddb9e07cde492328 Mon Sep 17 00:00:00 2001 From: Denzeel Oliva Date: Thu, 4 Sep 2025 14:07:11 +0000 Subject: [PATCH 0996/2711] dt-bindings: clock: exynos990: Add PERIC0 and PERIC1 clock units Add clock management unit bindings for PERIC0 and PERIC1 blocks which provide clocks for USI, I2C and UART peripherals. Signed-off-by: Denzeel Oliva Signed-off-by: Krzysztof Kozlowski --- .../clock/samsung,exynos990-clock.yaml | 24 +++ include/dt-bindings/clock/samsung,exynos990.h | 176 ++++++++++++++++++ 2 files changed, 200 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/samsung,exynos990-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynos990-clock.yaml index c15cc1752b02..5cd2d80b8ed6 100644 --- a/Documentation/devicetree/bindings/clock/samsung,exynos990-clock.yaml +++ b/Documentation/devicetree/bindings/clock/samsung,exynos990-clock.yaml @@ -30,6 +30,8 @@ description: | properties: compatible: enum: + - samsung,exynos990-cmu-peric1 + - samsung,exynos990-cmu-peric0 - samsung,exynos990-cmu-hsi0 - samsung,exynos990-cmu-peris - samsung,exynos990-cmu-top @@ -56,6 +58,28 @@ required: - reg allOf: + - if: + properties: + compatible: + contains: + enum: + - samsung,exynos990-cmu-peric1 + - samsung,exynos990-cmu-peric0 + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: Connectivity Peripheral 0/1 bus clock (from CMU_TOP) + - description: Connectivity Peripheral 0/1 IP clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: bus + - const: ip + - if: properties: compatible: diff --git a/include/dt-bindings/clock/samsung,exynos990.h b/include/dt-bindings/clock/samsung,exynos990.h index c60f15503d5b..47540307cb52 100644 --- a/include/dt-bindings/clock/samsung,exynos990.h +++ b/include/dt-bindings/clock/samsung,exynos990.h @@ -238,6 +238,182 @@ #define CLK_GOUT_HSI0_XIU_D_HSI0_ACLK 22 #define CLK_GOUT_HSI0_LHS_ACEL_D_HSI0_CLK 23 +/* CMU_PERIC0 */ +#define CLK_MOUT_PERIC0_BUS_USER 1 +#define CLK_MOUT_PERIC0_UART_DBG 2 +#define CLK_MOUT_PERIC0_USI00_USI_USER 3 +#define CLK_MOUT_PERIC0_USI01_USI_USER 4 +#define CLK_MOUT_PERIC0_USI02_USI_USER 5 +#define CLK_MOUT_PERIC0_USI03_USI_USER 6 +#define CLK_MOUT_PERIC0_USI04_USI_USER 7 +#define CLK_MOUT_PERIC0_USI05_USI_USER 8 +#define CLK_MOUT_PERIC0_USI13_USI_USER 9 +#define CLK_MOUT_PERIC0_USI14_USI_USER 10 +#define CLK_MOUT_PERIC0_USI15_USI_USER 11 +#define CLK_MOUT_PERIC0_USI_I2C_USER 12 +#define CLK_DOUT_PERIC0_UART_DBG 13 +#define CLK_DOUT_PERIC0_USI00_USI 14 +#define CLK_DOUT_PERIC0_USI01_USI 15 +#define CLK_DOUT_PERIC0_USI02_USI 16 +#define CLK_DOUT_PERIC0_USI03_USI 17 +#define CLK_DOUT_PERIC0_USI04_USI 18 +#define CLK_DOUT_PERIC0_USI05_USI 19 +#define CLK_DOUT_PERIC0_USI13_USI 20 +#define CLK_DOUT_PERIC0_USI14_USI 21 +#define CLK_DOUT_PERIC0_USI15_USI 22 +#define CLK_DOUT_PERIC0_USI_I2C 23 +#define CLK_GOUT_PERIC0_CMU_PCLK 24 +#define CLK_GOUT_PERIC0_OSCCLK_CLK 25 +#define CLK_GOUT_PERIC0_D_TZPC_PCLK 26 +#define CLK_GOUT_PERIC0_GPIO_PCLK 27 +#define CLK_GOUT_PERIC0_LHM_AXI_P_CLK 28 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_10 29 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_11 30 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_12 31 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_13 32 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_14 33 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_15 34 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_4 35 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_5 36 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_6 37 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_7 38 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_8 39 +#define CLK_GOUT_PERIC0_TOP0_IPCLK_9 40 +#define CLK_GOUT_PERIC0_TOP0_PCLK_10 41 +#define CLK_GOUT_PERIC0_TOP0_PCLK_11 42 +#define CLK_GOUT_PERIC0_TOP0_PCLK_12 43 +#define CLK_GOUT_PERIC0_TOP0_PCLK_13 44 +#define CLK_GOUT_PERIC0_TOP0_PCLK_14 45 +#define CLK_GOUT_PERIC0_TOP0_PCLK_15 46 +#define CLK_GOUT_PERIC0_TOP0_PCLK_4 47 +#define CLK_GOUT_PERIC0_TOP0_PCLK_5 48 +#define CLK_GOUT_PERIC0_TOP0_PCLK_6 49 +#define CLK_GOUT_PERIC0_TOP0_PCLK_7 50 +#define CLK_GOUT_PERIC0_TOP0_PCLK_8 51 +#define CLK_GOUT_PERIC0_TOP0_PCLK_9 52 +#define CLK_GOUT_PERIC0_TOP1_IPCLK_0 53 +#define CLK_GOUT_PERIC0_TOP1_IPCLK_3 54 +#define CLK_GOUT_PERIC0_TOP1_IPCLK_4 55 +#define CLK_GOUT_PERIC0_TOP1_IPCLK_5 56 +#define CLK_GOUT_PERIC0_TOP1_IPCLK_6 57 +#define CLK_GOUT_PERIC0_TOP1_IPCLK_7 58 +#define CLK_GOUT_PERIC0_TOP1_IPCLK_8 59 +#define CLK_GOUT_PERIC0_TOP1_PCLK_0 60 +#define CLK_GOUT_PERIC0_TOP1_PCLK_15 61 +#define CLK_GOUT_PERIC0_TOP1_PCLK_3 62 +#define CLK_GOUT_PERIC0_TOP1_PCLK_4 63 +#define CLK_GOUT_PERIC0_TOP1_PCLK_5 64 +#define CLK_GOUT_PERIC0_TOP1_PCLK_6 65 +#define CLK_GOUT_PERIC0_TOP1_PCLK_7 66 +#define CLK_GOUT_PERIC0_TOP1_PCLK_8 67 +#define CLK_GOUT_PERIC0_BUSP_CLK 68 +#define CLK_GOUT_PERIC0_UART_DBG_CLK 69 +#define CLK_GOUT_PERIC0_USI00_USI_CLK 70 +#define CLK_GOUT_PERIC0_USI01_USI_CLK 71 +#define CLK_GOUT_PERIC0_USI02_USI_CLK 72 +#define CLK_GOUT_PERIC0_USI03_USI_CLK 73 +#define CLK_GOUT_PERIC0_USI04_USI_CLK 74 +#define CLK_GOUT_PERIC0_USI05_USI_CLK 75 +#define CLK_GOUT_PERIC0_USI13_USI_CLK 76 +#define CLK_GOUT_PERIC0_USI14_USI_CLK 77 +#define CLK_GOUT_PERIC0_USI15_USI_CLK 78 +#define CLK_GOUT_PERIC0_USI_I2C_CLK 79 +#define CLK_GOUT_PERIC0_SYSREG_PCLK 80 + +/* CMU_PERIC1 */ +#define CLK_MOUT_PERIC1_BUS_USER 1 +#define CLK_MOUT_PERIC1_UART_BT_USER 2 +#define CLK_MOUT_PERIC1_USI06_USI_USER 3 +#define CLK_MOUT_PERIC1_USI07_USI_USER 4 +#define CLK_MOUT_PERIC1_USI08_USI_USER 5 +#define CLK_MOUT_PERIC1_USI09_USI_USER 6 +#define CLK_MOUT_PERIC1_USI10_USI_USER 7 +#define CLK_MOUT_PERIC1_USI11_USI_USER 8 +#define CLK_MOUT_PERIC1_USI12_USI_USER 9 +#define CLK_MOUT_PERIC1_USI18_USI_USER 10 +#define CLK_MOUT_PERIC1_USI16_USI_USER 11 +#define CLK_MOUT_PERIC1_USI17_USI_USER 12 +#define CLK_MOUT_PERIC1_USI_I2C_USER 13 +#define CLK_DOUT_PERIC1_UART_BT 14 +#define CLK_DOUT_PERIC1_USI06_USI 15 +#define CLK_DOUT_PERIC1_USI07_USI 16 +#define CLK_DOUT_PERIC1_USI08_USI 17 +#define CLK_DOUT_PERIC1_USI18_USI 18 +#define CLK_DOUT_PERIC1_USI12_USI 19 +#define CLK_DOUT_PERIC1_USI09_USI 20 +#define CLK_DOUT_PERIC1_USI10_USI 21 +#define CLK_DOUT_PERIC1_USI11_USI 22 +#define CLK_DOUT_PERIC1_USI16_USI 23 +#define CLK_DOUT_PERIC1_USI17_USI 24 +#define CLK_DOUT_PERIC1_USI_I2C 25 +#define CLK_GOUT_PERIC1_CMU_PCLK 26 +#define CLK_GOUT_PERIC1_UART_BT_CLK 27 +#define CLK_GOUT_PERIC1_USI12_USI_CLK 28 +#define CLK_GOUT_PERIC1_USI18_USI_CLK 29 +#define CLK_GOUT_PERIC1_D_TZPC_PCLK 30 +#define CLK_GOUT_PERIC1_GPIO_PCLK 31 +#define CLK_GOUT_PERIC1_LHM_AXI_P_CSIS_CLK 32 +#define CLK_GOUT_PERIC1_LHM_AXI_P_CLK 33 +#define CLK_GOUT_PERIC1_TOP0_IPCLK_10 34 +#define CLK_GOUT_PERIC1_TOP0_IPCLK_11 35 +#define CLK_GOUT_PERIC1_TOP0_IPCLK_12 36 +#define CLK_GOUT_PERIC1_TOP0_IPCLK_13 37 +#define CLK_GOUT_PERIC1_TOP0_IPCLK_14 38 +#define CLK_GOUT_PERIC1_TOP0_IPCLK_15 39 +#define CLK_GOUT_PERIC1_TOP0_IPCLK_4 40 +#define CLK_GOUT_PERIC1_TOP0_PCLK_10 41 +#define CLK_GOUT_PERIC1_TOP0_PCLK_11 42 +#define CLK_GOUT_PERIC1_TOP0_PCLK_12 43 +#define CLK_GOUT_PERIC1_TOP0_PCLK_13 44 +#define CLK_GOUT_PERIC1_TOP0_PCLK_14 45 +#define CLK_GOUT_PERIC1_TOP0_PCLK_15 46 +#define CLK_GOUT_PERIC1_TOP0_PCLK_4 47 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_0 48 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_1 49 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_10 50 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_12 51 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_13 52 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_14 53 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_15 54 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_2 55 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_3 56 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_4 57 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_5 58 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_6 59 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_7 60 +#define CLK_GOUT_PERIC1_TOP1_IPCLK_9 61 +#define CLK_GOUT_PERIC1_TOP1_PCLK_0 62 +#define CLK_GOUT_PERIC1_TOP1_PCLK_1 63 +#define CLK_GOUT_PERIC1_TOP1_PCLK_10 64 +#define CLK_GOUT_PERIC1_TOP1_PCLK_12 65 +#define CLK_GOUT_PERIC1_TOP1_PCLK_13 66 +#define CLK_GOUT_PERIC1_TOP1_PCLK_14 67 +#define CLK_GOUT_PERIC1_TOP1_PCLK_15 68 +#define CLK_GOUT_PERIC1_TOP1_PCLK_2 69 +#define CLK_GOUT_PERIC1_TOP1_PCLK_3 70 +#define CLK_GOUT_PERIC1_TOP1_PCLK_4 71 +#define CLK_GOUT_PERIC1_TOP1_PCLK_5 72 +#define CLK_GOUT_PERIC1_TOP1_PCLK_6 73 +#define CLK_GOUT_PERIC1_TOP1_PCLK_7 74 +#define CLK_GOUT_PERIC1_TOP1_PCLK_9 75 +#define CLK_GOUT_PERIC1_BUSP_CLK 76 +#define CLK_GOUT_PERIC1_OSCCLK_CLK 77 +#define CLK_GOUT_PERIC1_USI06_USI_CLK 78 +#define CLK_GOUT_PERIC1_USI07_USI_CLK 79 +#define CLK_GOUT_PERIC1_USI08_USI_CLK 80 +#define CLK_GOUT_PERIC1_USI09_USI_CLK 81 +#define CLK_GOUT_PERIC1_USI10_USI_CLK 82 +#define CLK_GOUT_PERIC1_USI11_USI_CLK 83 +#define CLK_GOUT_PERIC1_USI16_USI_CLK 84 +#define CLK_GOUT_PERIC1_USI17_USI_CLK 85 +#define CLK_GOUT_PERIC1_USI_I2C_CLK 86 +#define CLK_GOUT_PERIC1_SYSREG_PCLK 87 +#define CLK_GOUT_PERIC1_USI16_I3C_PCLK 88 +#define CLK_GOUT_PERIC1_USI16_I3C_SCLK 89 +#define CLK_GOUT_PERIC1_USI17_I3C_PCLK 90 +#define CLK_GOUT_PERIC1_USI17_I3C_SCLK 91 +#define CLK_GOUT_PERIC1_XIU_P_ACLK 92 + /* CMU_PERIS */ #define CLK_MOUT_PERIS_BUS_USER 1 #define CLK_MOUT_PERIS_CLK_PERIS_GIC 2 From b3b314ef13e46dce1cdd97a856bd0250dac8feb9 Mon Sep 17 00:00:00 2001 From: Denzeel Oliva Date: Thu, 4 Sep 2025 14:07:13 +0000 Subject: [PATCH 0997/2711] clk: samsung: exynos990: Add PERIC0 and PERIC1 clock support Add clock controller support for Peripheral Connectivity 0 and 1 blocks. These provide clocks for USI, I2C and UART peripherals. Some clocks need to be marked as critical to prevent system hang when disabled. Signed-off-by: Denzeel Oliva Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-exynos990.c | 1152 +++++++++++++++++++++++++++ 1 file changed, 1152 insertions(+) diff --git a/drivers/clk/samsung/clk-exynos990.c b/drivers/clk/samsung/clk-exynos990.c index 47a1e0850c30..6277dd557fab 100644 --- a/drivers/clk/samsung/clk-exynos990.c +++ b/drivers/clk/samsung/clk-exynos990.c @@ -19,6 +19,8 @@ /* NOTE: Must be equal to the last clock ID increased by one */ #define CLKS_NR_TOP (CLK_DOUT_CMU_CLK_CMUREF + 1) #define CLKS_NR_HSI0 (CLK_GOUT_HSI0_LHS_ACEL_D_HSI0_CLK + 1) +#define CLKS_NR_PERIC0 (CLK_GOUT_PERIC0_SYSREG_PCLK + 1) +#define CLKS_NR_PERIC1 (CLK_GOUT_PERIC1_XIU_P_ACLK + 1) #define CLKS_NR_PERIS (CLK_GOUT_PERIS_OTP_CON_TOP_OSCCLK + 1) /* ---- CMU_TOP ------------------------------------------------------------- */ @@ -1351,6 +1353,1150 @@ static const struct samsung_cmu_info hsi0_cmu_info __initconst = { .clk_name = "bus", }; +/* ---- CMU_PERIC0 --------------------------------------------------------- */ + +/* Register Offset definitions for CMU_PERIC0 (0x10400000) */ +#define PLL_CON0_MUX_CLKCMU_PERIC0_BUS_USER 0x0600 +#define PLL_CON1_MUX_CLKCMU_PERIC0_BUS_USER 0x0604 +#define PLL_CON0_MUX_CLKCMU_PERIC0_UART_DBG 0x0610 +#define PLL_CON1_MUX_CLKCMU_PERIC0_UART_DBG 0x0614 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI00_USI_USER 0x0620 +#define PLL_CON1_MUX_CLKCMU_PERIC0_USI00_USI_USER 0x0624 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI01_USI_USER 0x0630 +#define PLL_CON1_MUX_CLKCMU_PERIC0_USI01_USI_USER 0x0634 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI02_USI_USER 0x0640 +#define PLL_CON1_MUX_CLKCMU_PERIC0_USI02_USI_USER 0x0644 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI03_USI_USER 0x0650 +#define PLL_CON1_MUX_CLKCMU_PERIC0_USI03_USI_USER 0x0654 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI04_USI_USER 0x0660 +#define PLL_CON1_MUX_CLKCMU_PERIC0_USI04_USI_USER 0x0664 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI05_USI_USER 0x0670 +#define PLL_CON1_MUX_CLKCMU_PERIC0_USI05_USI_USER 0x0674 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI13_USI_USER 0x0680 +#define PLL_CON1_MUX_CLKCMU_PERIC0_USI13_USI_USER 0x0684 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI14_USI_USER 0x0690 +#define PLL_CON1_MUX_CLKCMU_PERIC0_USI14_USI_USER 0x0694 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI15_USI_USER 0x06a0 +#define PLL_CON1_MUX_CLKCMU_PERIC0_USI15_USI_USER 0x06a4 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI_I2C_USER 0x06b0 +#define PLL_CON1_MUX_CLKCMU_PERIC0_USI_I2C_USER 0x06b4 +#define CLK_CON_DIV_DIV_CLK_PERIC0_UART_DBG 0x1800 +#define CLK_CON_DIV_DIV_CLK_PERIC0_USI00_USI 0x1804 +#define CLK_CON_DIV_DIV_CLK_PERIC0_USI01_USI 0x1808 +#define CLK_CON_DIV_DIV_CLK_PERIC0_USI02_USI 0x180c +#define CLK_CON_DIV_DIV_CLK_PERIC0_USI03_USI 0x1810 +#define CLK_CON_DIV_DIV_CLK_PERIC0_USI04_USI 0x1814 +#define CLK_CON_DIV_DIV_CLK_PERIC0_USI05_USI 0x1818 +#define CLK_CON_DIV_DIV_CLK_PERIC0_USI13_USI 0x181c +#define CLK_CON_DIV_DIV_CLK_PERIC0_USI14_USI 0x1820 +#define CLK_CON_DIV_DIV_CLK_PERIC0_USI15_USI 0x1824 +#define CLK_CON_DIV_DIV_CLK_PERIC0_USI_I2C 0x1828 +#define CLK_CON_GAT_CLK_BLK_PERIC0_UID_PERIC0_CMU_PERIC0_IPCLKPORT_PCLK 0x2004 +#define CLK_CON_GAT_CLK_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_OSCCLK_IPCLKPORT_CLK 0x2008 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_D_TZPC_PERIC0_IPCLKPORT_PCLK 0x200c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_GPIO_PERIC0_IPCLKPORT_PCLK 0x2010 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_LHM_AXI_P_PERIC0_IPCLKPORT_I_CLK 0x2014 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_10 0x2018 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_11 0x201c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_12 0x2020 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_13 0x2024 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_14 0x2028 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_15 0x202c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_4 0x2030 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_5 0x2034 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_6 0x2038 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_7 0x203c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_8 0x2040 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_9 0x2044 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_10 0x2048 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_11 0x204c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_12 0x2050 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_13 0x2054 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_14 0x2058 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_15 0x205c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_4 0x2060 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_5 0x2064 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_6 0x2068 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_7 0x206c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_8 0x2070 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_9 0x2074 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_0 0x2078 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_3 0x207c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_4 0x2080 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_5 0x2084 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_6 0x2088 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_7 0x208c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_8 0x2090 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_0 0x2094 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_15 0x2098 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_3 0x209c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_4 0x20a0 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_5 0x20a4 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_6 0x20a8 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_7 0x20ac +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_8 0x20b0 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_BUSP_IPCLKPORT_CLK 0x20b4 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_UART_DBG_IPCLKPORT_CLK 0x20b8 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI00_USI_IPCLKPORT_CLK 0x20bc +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI01_USI_IPCLKPORT_CLK 0x20c0 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI02_USI_IPCLKPORT_CLK 0x20c4 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI03_USI_IPCLKPORT_CLK 0x20c8 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI04_USI_IPCLKPORT_CLK 0x20cc +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI05_USI_IPCLKPORT_CLK 0x20d0 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI13_USI_IPCLKPORT_CLK 0x20d4 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI14_USI_IPCLKPORT_CLK 0x20d8 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI15_USI_IPCLKPORT_CLK 0x20dc +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI_I2C_IPCLKPORT_CLK 0x20e0 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_SYSREG_PERIC0_IPCLKPORT_PCLK 0x20e4 + +static const unsigned long peric0_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_PERIC0_BUS_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_BUS_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_UART_DBG, + PLL_CON1_MUX_CLKCMU_PERIC0_UART_DBG, + PLL_CON0_MUX_CLKCMU_PERIC0_USI00_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_USI00_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI01_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_USI01_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI02_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_USI02_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI03_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_USI03_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI04_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_USI04_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI05_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_USI05_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI13_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_USI13_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI14_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_USI14_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI15_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_USI15_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI_I2C_USER, + PLL_CON1_MUX_CLKCMU_PERIC0_USI_I2C_USER, + CLK_CON_DIV_DIV_CLK_PERIC0_UART_DBG, + CLK_CON_DIV_DIV_CLK_PERIC0_USI00_USI, + CLK_CON_DIV_DIV_CLK_PERIC0_USI01_USI, + CLK_CON_DIV_DIV_CLK_PERIC0_USI02_USI, + CLK_CON_DIV_DIV_CLK_PERIC0_USI03_USI, + CLK_CON_DIV_DIV_CLK_PERIC0_USI04_USI, + CLK_CON_DIV_DIV_CLK_PERIC0_USI05_USI, + CLK_CON_DIV_DIV_CLK_PERIC0_USI13_USI, + CLK_CON_DIV_DIV_CLK_PERIC0_USI14_USI, + CLK_CON_DIV_DIV_CLK_PERIC0_USI15_USI, + CLK_CON_DIV_DIV_CLK_PERIC0_USI_I2C, + CLK_CON_GAT_CLK_BLK_PERIC0_UID_PERIC0_CMU_PERIC0_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_OSCCLK_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_D_TZPC_PERIC0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_GPIO_PERIC0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_LHM_AXI_P_PERIC0_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_10, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_11, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_12, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_13, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_14, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_15, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_4, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_5, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_6, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_7, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_8, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_9, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_10, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_11, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_12, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_13, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_14, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_15, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_4, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_5, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_6, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_7, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_8, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_9, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_0, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_3, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_4, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_5, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_6, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_7, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_8, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_0, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_15, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_3, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_4, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_5, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_6, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_7, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_8, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_BUSP_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_UART_DBG_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI00_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI01_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI02_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI03_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI04_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI05_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI13_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI14_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI15_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI_I2C_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_SYSREG_PERIC0_IPCLKPORT_PCLK, +}; + +/* Parent clock list for CMU_PERIC0 muxes */ +PNAME(mout_peric0_bus_user_p) = { "oscclk", "dout_cmu_peric0_bus" }; +PNAME(mout_peric0_uart_dbg_p) = { "oscclk", "dout_cmu_peric0_ip" }; +PNAME(mout_peric0_usi00_user_p) = { "oscclk", "dout_cmu_peric0_ip" }; +PNAME(mout_peric0_usi01_user_p) = { "oscclk", "dout_cmu_peric0_ip" }; +PNAME(mout_peric0_usi02_user_p) = { "oscclk", "dout_cmu_peric0_ip" }; +PNAME(mout_peric0_usi03_user_p) = { "oscclk", "dout_cmu_peric0_ip" }; +PNAME(mout_peric0_usi04_user_p) = { "oscclk", "dout_cmu_peric0_ip" }; +PNAME(mout_peric0_usi05_user_p) = { "oscclk", "dout_cmu_peric0_ip" }; +PNAME(mout_peric0_usi13_user_p) = { "oscclk", "dout_cmu_peric0_ip" }; +PNAME(mout_peric0_usi14_user_p) = { "oscclk", "dout_cmu_peric0_ip" }; +PNAME(mout_peric0_usi15_user_p) = { "oscclk", "dout_cmu_peric0_ip" }; +PNAME(mout_peric0_usi_i2c_user_p) = { "oscclk", "dout_cmu_peric0_ip" }; + +static const struct samsung_mux_clock peric0_mux_clks[] __initconst = { + MUX(CLK_MOUT_PERIC0_BUS_USER, "mout_peric0_bus_user", + mout_peric0_bus_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_BUS_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_UART_DBG, "mout_peric0_uart_dbg", + mout_peric0_uart_dbg_p, PLL_CON0_MUX_CLKCMU_PERIC0_UART_DBG, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI00_USI_USER, "mout_peric0_usi00_usi_user", + mout_peric0_usi00_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI00_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI01_USI_USER, "mout_peric0_usi01_usi_user", + mout_peric0_usi01_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI01_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI02_USI_USER, "mout_peric0_usi02_usi_user", + mout_peric0_usi02_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI02_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI03_USI_USER, "mout_peric0_usi03_usi_user", + mout_peric0_usi03_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI03_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI04_USI_USER, "mout_peric0_usi04_usi_user", + mout_peric0_usi04_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI04_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI05_USI_USER, "mout_peric0_usi05_usi_user", + mout_peric0_usi05_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI05_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI13_USI_USER, "mout_peric0_usi13_usi_user", + mout_peric0_usi13_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI13_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI14_USI_USER, "mout_peric0_usi14_usi_user", + mout_peric0_usi14_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI14_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI15_USI_USER, "mout_peric0_usi15_usi_user", + mout_peric0_usi15_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI15_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI_I2C_USER, "mout_peric0_usi_i2c_user", + mout_peric0_usi_i2c_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI_I2C_USER, + 4, 1), +}; + +static const struct samsung_div_clock peric0_div_clks[] __initconst = { + DIV(CLK_DOUT_PERIC0_UART_DBG, "dout_peric0_uart_dbg", + "mout_peric0_uart_dbg", + CLK_CON_DIV_DIV_CLK_PERIC0_UART_DBG, + 0, 4), + DIV(CLK_DOUT_PERIC0_USI00_USI, "dout_peric0_usi00_usi", + "mout_peric0_usi00_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC0_USI00_USI, + 0, 4), + DIV(CLK_DOUT_PERIC0_USI01_USI, "dout_peric0_usi01_usi", + "mout_peric0_usi01_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC0_USI01_USI, + 0, 4), + DIV(CLK_DOUT_PERIC0_USI02_USI, "dout_peric0_usi02_usi", + "mout_peric0_usi02_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC0_USI02_USI, + 0, 4), + DIV(CLK_DOUT_PERIC0_USI03_USI, "dout_peric0_usi03_usi", + "mout_peric0_usi03_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC0_USI03_USI, + 0, 4), + DIV(CLK_DOUT_PERIC0_USI04_USI, "dout_peric0_usi04_usi", + "mout_peric0_usi04_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC0_USI04_USI, + 0, 4), + DIV(CLK_DOUT_PERIC0_USI05_USI, "dout_peric0_usi05_usi", + "mout_peric0_usi05_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC0_USI05_USI, + 0, 4), + DIV(CLK_DOUT_PERIC0_USI13_USI, "dout_peric0_usi13_usi", + "mout_peric0_usi13_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC0_USI13_USI, + 0, 4), + DIV(CLK_DOUT_PERIC0_USI14_USI, "dout_peric0_usi14_usi", + "mout_peric0_usi14_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC0_USI14_USI, + 0, 4), + DIV(CLK_DOUT_PERIC0_USI15_USI, "dout_peric0_usi15_usi", + "mout_peric0_usi15_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC0_USI15_USI, + 0, 4), + DIV(CLK_DOUT_PERIC0_USI_I2C, "dout_peric0_usi_i2c", + "mout_peric0_usi_i2c_user", + CLK_CON_DIV_DIV_CLK_PERIC0_USI_I2C, + 0, 4), +}; + +static const struct samsung_gate_clock peric0_gate_clks[] __initconst = { + GATE(CLK_GOUT_PERIC0_CMU_PCLK, "gout_peric0_cmu_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_CLK_BLK_PERIC0_UID_PERIC0_CMU_PERIC0_IPCLKPORT_PCLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC0_OSCCLK_CLK, "gout_peric0_oscclk_clk", + "oscclk", + CLK_CON_GAT_CLK_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_OSCCLK_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_D_TZPC_PCLK, "gout_peric0_d_tpzc_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_D_TZPC_PERIC0_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_GPIO_PCLK, "gout_peric0_gpio_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_GPIO_PERIC0_IPCLKPORT_PCLK, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_PERIC0_LHM_AXI_P_CLK, "gout_peric0_lhm_axi_p_clk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_LHM_AXI_P_PERIC0_IPCLKPORT_I_CLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_10, "gout_peric0_top0_ipclk_10", + "dout_peric0_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_10, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_11, "gout_peric0_top0_ipclk_11", + "dout_peric0_usi03_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_11, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_12, "gout_peric0_top0_ipclk_12", + "dout_peric0_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_12, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_13, "gout_peric0_top0_ipclk_13", + "dout_peric0_usi04_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_13, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_14, "gout_peric0_top0_ipclk_14", + "dout_peric0_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_14, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_15, "gout_peric0_top0_ipclk_15", + "dout_peric0_usi05_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_15, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_4, "gout_peric0_top0_ipclk_4", + "dout_peric0_uart_dbg", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_4, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_5, "gout_peric0_top0_ipclk_5", + "dout_peric0_usi00_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_5, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_6, "gout_peric0_top0_ipclk_6", + "dout_peric0_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_6, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_7, "gout_peric0_top0_ipclk_7", + "dout_peric0_usi01_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_7, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_8, "gout_peric0_top0_ipclk_8", + "dout_peric0_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_8, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_IPCLK_9, "gout_peric0_top0_ipclk_9", + "dout_peric0_usi02_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_IPCLK_9, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_10, "gout_peric0_top0_pclk_10", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_10, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_11, "gout_peric0_top0_pclk_11", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_11, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_12, "gout_peric0_top0_pclk_12", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_12, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_13, "gout_peric0_top0_pclk_13", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_13, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_14, "gout_peric0_top0_pclk_14", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_14, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_15, "gout_peric0_top0_pclk_15", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_15, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_4, "gout_peric0_top0_pclk_4", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_4, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_5, "gout_peric0_top0_pclk_5", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_5, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_6, "gout_peric0_top0_pclk_6", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_6, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_7, "gout_peric0_top0_pclk_7", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_7, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_8, "gout_peric0_top0_pclk_8", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_8, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP0_PCLK_9, "gout_peric0_top0_pclk_9", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP0_IPCLKPORT_PCLK_9, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_IPCLK_0, "gout_peric0_top1_ipclk_0", + "dout_peric0_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_0, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_IPCLK_3, "gout_peric0_top1_ipclk_3", + "dout_peric0_usi13_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_3, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_IPCLK_4, "gout_peric0_top1_ipclk_4", + "dout_peric0_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_4, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_IPCLK_5, "gout_peric0_top1_ipclk_5", + "dout_peric0_usi14_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_5, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_IPCLK_6, "gout_peric0_top1_ipclk_6", + "dout_peric0_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_6, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_IPCLK_7, "gout_peric0_top1_ipclk_7", + "dout_peric0_usi15_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_7, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_IPCLK_8, "gout_peric0_top1_ipclk_8", + "dout_peric0_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_IPCLK_8, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_PCLK_0, "gout_peric0_top1_pclk_0", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_0, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_PCLK_15, "gout_peric0_top1_pclk_15", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_15, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_PCLK_3, "gout_peric0_top1_pclk_3", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_3, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_PCLK_4, "gout_peric0_top1_pclk_4", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_4, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_PCLK_5, "gout_peric0_top1_pclk_5", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_5, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_PCLK_6, "gout_peric0_top1_pclk_6", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_6, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_PCLK_7, "gout_peric0_top1_pclk_7", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_7, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_TOP1_PCLK_8, "gout_peric0_top1_pclk_8", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PERIC0_TOP1_IPCLKPORT_PCLK_8, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_BUSP_CLK, "gout_peric0_busp_clk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_BUSP_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_UART_DBG_CLK, "gout_peric0_uart_dbg_clk", + "dout_peric0_uart_dbg", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_UART_DBG_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI00_USI_CLK, "gout_peric0_usi00_usi_clk", + "dout_peric0_usi00_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI00_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI01_USI_CLK, "gout_peric0_usi01_usi_clk", + "dout_peric0_usi01_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI01_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI02_USI_CLK, "gout_peric0_usi02_usi_clk", + "dout_peric0_usi02_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI02_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI03_USI_CLK, "gout_peric0_usi03_usi_clk", + "dout_peric0_usi03_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI03_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI04_USI_CLK, "gout_peric0_usi04_usi_clk", + "dout_peric0_usi04_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI04_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI05_USI_CLK, "gout_peric0_usi05_usi_clk", + "dout_peric0_usi05_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI05_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI13_USI_CLK, "gout_peric0_usi13_usi_clk", + "dout_peric0_usi13_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI13_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI14_USI_CLK, "gout_peric0_usi14_usi_clk", + "dout_peric0_usi14_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI14_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI15_USI_CLK, "gout_peric0_usi15_usi_clk", + "dout_peric0_usi15_usi", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI15_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI_I2C_CLK, "gout_peric0_usi_i2c_clk", + "dout_peric0_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_USI_I2C_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_SYSREG_PCLK, "gout_peric0_sysreg_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_SYSREG_PERIC0_IPCLKPORT_PCLK, + 21, 0, 0) +}; + +static const struct samsung_cmu_info peric0_cmu_info __initconst = { + .mux_clks = peric0_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peric0_mux_clks), + .div_clks = peric0_div_clks, + .nr_div_clks = ARRAY_SIZE(peric0_div_clks), + .gate_clks = peric0_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peric0_gate_clks), + .nr_clk_ids = CLKS_NR_PERIC0, + .clk_regs = peric0_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peric0_clk_regs), + .clk_name = "bus", +}; + +/* ---- CMU_PERIC1 --------------------------------------------------------- */ + +/* Register Offset definitions for CMU_PERIC1 (0x10700000) */ +#define PLL_CON0_MUX_CLKCMU_PERIC1_BUS_USER 0x0600 +#define PLL_CON1_MUX_CLKCMU_PERIC1_BUS_USER 0x0604 +#define PLL_CON0_MUX_CLKCMU_PERIC1_UART_BT_USER 0x0610 +#define PLL_CON1_MUX_CLKCMU_PERIC1_UART_BT_USER 0x0614 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI06_USI_USER 0x0620 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI06_USI_USER 0x0624 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI07_USI_USER 0x0630 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI07_USI_USER 0x0634 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI08_USI_USER 0x0640 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI08_USI_USER 0x0644 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI09_USI_USER 0x0650 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI09_USI_USER 0x0654 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI10_USI_USER 0x0660 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI10_USI_USER 0x0664 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI11_USI_USER 0x0670 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI11_USI_USER 0x0674 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI12_USI_USER 0x0680 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI12_USI_USER 0x0684 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI16_USI_USER 0x0690 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI16_USI_USER 0x0694 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI17_USI_USER 0x06a0 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI17_USI_USER 0x06a4 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI18_USI_USER 0x06b0 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI18_USI_USER 0x06b4 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI_I2C_USER 0x06c0 +#define PLL_CON1_MUX_CLKCMU_PERIC1_USI_I2C_USER 0x06c4 +#define CLK_CON_DIV_DIV_CLK_PERIC1_UART_BT 0x1800 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI06_USI 0x1804 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI07_USI 0x1808 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI08_USI 0x180c +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI09_USI 0x1810 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI10_USI 0x1814 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI11_USI 0x1818 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI12_USI 0x181c +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI16_USI 0x1820 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI17_USI 0x1824 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI18_USI 0x1828 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI_I2C 0x182c +#define CLK_CON_GAT_CLK_BLK_PERIC1_UID_PERIC1_CMU_PERIC1_IPCLKPORT_PCLK 0x2004 +#define CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_UART_BT_IPCLKPORT_CLK 0x2008 +#define CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI12_USI_IPCLKPORT_CLK 0x200c +#define CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI18_USI_IPCLKPORT_CLK 0x2010 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_D_TZPC_PERIC1_IPCLKPORT_PCLK 0x2014 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_GPIO_PERIC1_IPCLKPORT_PCLK 0x2018 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_LHM_AXI_P_CSISPERIC1_IPCLKPORT_I_CLK 0x201c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_LHM_AXI_P_PERIC1_IPCLKPORT_I_CLK 0x2020 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_10 0x2024 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_11 0x2028 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_12 0x202c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_13 0x2030 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_14 0x2034 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_15 0x2038 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_4 0x203c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_10 0x2040 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_11 0x2044 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_12 0x2048 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_13 0x204c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_14 0x2050 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_15 0x2054 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_4 0x2058 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_0 0x205c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_1 0x2060 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_10 0x2064 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_12 0x206c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_13 0x2070 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_14 0x2074 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_15 0x2078 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_2 0x207c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_3 0x2080 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_4 0x2084 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_5 0x2088 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_6 0x208c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_7 0x2090 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_9 0x2098 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_0 0x209c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_1 0x20a0 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_10 0x20a4 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_12 0x20ac +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_13 0x20b0 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_14 0x20b4 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_15 0x20b8 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_2 0x20bc +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_3 0x20c0 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_4 0x20c4 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_5 0x20c8 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_6 0x20cc +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_7 0x20d0 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_9 0x20d8 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_BUSP_IPCLKPORT_CLK 0x20dc +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_OSCCLK_IPCLKPORT_CLK 0x20e0 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI06_USI_IPCLKPORT_CLK 0x20e4 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI07_USI_IPCLKPORT_CLK 0x20e8 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI08_USI_IPCLKPORT_CLK 0x20ec +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI09_USI_IPCLKPORT_CLK 0x20f0 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI10_USI_IPCLKPORT_CLK 0x20f4 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI11_USI_IPCLKPORT_CLK 0x20f8 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI16_USI_IPCLKPORT_CLK 0x20fc +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI17_USI_IPCLKPORT_CLK 0x2100 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI_I2C_IPCLKPORT_CLK 0x2104 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SYSREG_PERIC1_IPCLKPORT_PCLK 0x2108 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI16_I3C_IPCLKPORT_I_PCLK 0x210c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI16_I3C_IPCLKPORT_I_SCLK 0x2110 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI17_I3C_IPCLKPORT_I_PCLK 0x2114 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI17_I3C_IPCLKPORT_I_SCLK 0x2118 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_XIU_P_PERIC1_IPCLKPORT_ACLK 0x211c + +static const unsigned long peric1_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_PERIC1_BUS_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_BUS_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_UART_BT_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_UART_BT_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI06_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI06_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI07_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI07_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI08_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI08_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI09_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI09_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI10_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI10_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI11_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI11_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI12_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI12_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI16_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI16_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI17_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI17_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI18_USI_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI18_USI_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI_I2C_USER, + PLL_CON1_MUX_CLKCMU_PERIC1_USI_I2C_USER, + CLK_CON_DIV_DIV_CLK_PERIC1_UART_BT, + CLK_CON_DIV_DIV_CLK_PERIC1_USI06_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI07_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI08_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI09_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI10_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI11_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI12_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI16_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI17_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI18_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI_I2C, + CLK_CON_GAT_CLK_BLK_PERIC1_UID_PERIC1_CMU_PERIC1_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_UART_BT_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI12_USI_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI18_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_D_TZPC_PERIC1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_GPIO_PERIC1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_LHM_AXI_P_CSISPERIC1_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_LHM_AXI_P_PERIC1_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_10, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_11, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_12, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_13, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_14, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_15, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_4, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_10, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_11, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_12, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_13, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_14, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_15, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_4, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_0, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_1, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_10, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_12, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_13, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_14, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_15, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_2, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_3, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_4, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_5, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_6, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_7, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_9, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_0, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_1, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_10, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_12, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_13, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_14, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_15, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_2, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_3, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_4, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_5, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_6, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_7, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_9, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_BUSP_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_OSCCLK_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI06_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI07_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI08_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI09_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI10_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI11_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI16_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI17_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI_I2C_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SYSREG_PERIC1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI16_I3C_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI16_I3C_IPCLKPORT_I_SCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI17_I3C_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI17_I3C_IPCLKPORT_I_SCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_XIU_P_PERIC1_IPCLKPORT_ACLK, +}; + +/* Parent clock list for CMU_PERIC1 muxes */ +PNAME(mout_peric1_bus_user_p) = { "oscclk", "dout_cmu_peric1_bus" }; +PNAME(mout_peric1_uart_bt_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi06_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi07_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi08_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi09_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi10_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi11_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi12_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi18_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi16_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi17_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; +PNAME(mout_peric1_usi_i2c_user_p) = { "oscclk", "dout_cmu_peric1_ip" }; + +static const struct samsung_mux_clock peric1_mux_clks[] __initconst = { + MUX(CLK_MOUT_PERIC1_BUS_USER, "mout_peric1_bus_user", + mout_peric1_bus_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_BUS_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_UART_BT_USER, "mout_peric1_uart_bt_user", + mout_peric1_uart_bt_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_UART_BT_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI06_USI_USER, "mout_peric1_usi06_usi_user", + mout_peric1_usi06_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI06_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI07_USI_USER, "mout_peric1_usi07_usi_user", + mout_peric1_usi07_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI07_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI08_USI_USER, "mout_peric1_usi08_usi_user", + mout_peric1_usi08_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI08_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI09_USI_USER, "mout_peric1_usi09_usi_user", + mout_peric1_usi09_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI09_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI10_USI_USER, "mout_peric1_usi10_usi_user", + mout_peric1_usi10_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI10_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI11_USI_USER, "mout_peric1_usi11_usi_user", + mout_peric1_usi11_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI11_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI12_USI_USER, "mout_peric1_usi12_usi_user", + mout_peric1_usi12_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI12_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI18_USI_USER, "mout_peric1_usi18_usi_user", + mout_peric1_usi18_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI18_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI16_USI_USER, "mout_peric1_usi16_usi_user", + mout_peric1_usi16_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI16_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI17_USI_USER, "mout_peric1_usi17_usi_user", + mout_peric1_usi17_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI17_USI_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI_I2C_USER, "mout_peric1_usi_i2c_user", + mout_peric1_usi_i2c_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI_I2C_USER, + 4, 1), +}; + +static const struct samsung_div_clock peric1_div_clks[] __initconst = { + DIV(CLK_DOUT_PERIC1_UART_BT, "dout_peric1_uart_bt", + "mout_peric1_uart_bt_user", + CLK_CON_DIV_DIV_CLK_PERIC1_UART_BT, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI06_USI, "dout_peric1_usi06_usi", + "mout_peric1_usi06_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI06_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI07_USI, "dout_peric1_usi07_usi", + "mout_peric1_usi07_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI07_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI08_USI, "dout_peric1_usi08_usi", + "mout_peric1_usi08_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI08_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI18_USI, "dout_peric1_usi18_usi", + "mout_peric1_usi18_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI18_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI12_USI, "dout_peric1_usi12_usi", + "mout_peric1_usi12_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI12_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI09_USI, "dout_peric1_usi09_usi", + "mout_peric1_usi09_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI09_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI10_USI, "dout_peric1_usi10_usi", + "mout_peric1_usi10_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI10_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI11_USI, "dout_peric1_usi11_usi", + "mout_peric1_usi11_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI11_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI16_USI, "dout_peric1_usi16_usi", + "mout_peric1_usi16_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI16_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI17_USI, "dout_peric1_usi17_usi", + "mout_peric1_usi17_usi_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI17_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI_I2C, "dout_peric1_usi_i2c", + "mout_peric1_usi_i2c_user", + CLK_CON_DIV_DIV_CLK_PERIC1_USI_I2C, + 0, 4), +}; + +static const struct samsung_gate_clock peric1_gate_clks[] __initconst = { + GATE(CLK_GOUT_PERIC1_CMU_PCLK, "gout_peric1_cmu_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_CLK_BLK_PERIC1_UID_PERIC1_CMU_PERIC1_IPCLKPORT_PCLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC1_UART_BT_CLK, "gout_peric1_uart_bt_clk", + "dout_peric1_uart_bt", + CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_UART_BT_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI12_USI_CLK, "gout_peric1_usi12_usi_clk", + "dout_peric1_usi12_usi", + CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI12_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI18_USI_CLK, "gout_peric1_usi18_usi_clk", + "dout_peric1_usi18_usi", + CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI18_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_D_TZPC_PCLK, "gout_peric1_d_tzpc_pclk", + "dout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_D_TZPC_PERIC1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_GPIO_PCLK, "gout_peric1_gpio_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_GPIO_PERIC1_IPCLKPORT_PCLK, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_PERIC1_LHM_AXI_P_CSIS_CLK, "gout_peric1_lhm_axi_p_csis_clk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_LHM_AXI_P_CSISPERIC1_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_LHM_AXI_P_CLK, "gout_peric1_lhm_axi_p_clk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_LHM_AXI_P_PERIC1_IPCLKPORT_I_CLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC1_TOP0_IPCLK_10, "gout_peric1_top0_ipclk_10", + "dout_peric1_usi06_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_10, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_IPCLK_11, "gout_peric1_top0_ipclk_11", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_11, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_IPCLK_12, "gout_peric1_top0_ipclk_12", + "dout_peric1_usi07_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_12, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_IPCLK_13, "gout_peric1_top0_ipclk_13", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_13, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_IPCLK_14, "gout_peric1_top0_ipclk_14", + "dout_peric1_usi08_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_14, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_IPCLK_15, "gout_peric1_top0_ipclk_15", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_15, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_IPCLK_4, "gout_peric1_top0_ipclk_4", + "dout_peric1_uart_bt", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_IPCLK_4, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_PCLK_10, "gout_peric1_top0_pclk_10", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_10, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_PCLK_11, "gout_peric1_top0_pclk_11", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_11, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_PCLK_12, "gout_peric1_top0_pclk_12", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_12, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_PCLK_13, "gout_peric1_top0_pclk_13", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_13, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_PCLK_14, "gout_peric1_top0_pclk_14", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_14, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_PCLK_15, "gout_peric1_top0_pclk_15", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_15, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP0_PCLK_4, "gout_peric1_top0_pclk_4", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP0_IPCLKPORT_PCLK_4, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_0, "gout_peric1_top1_ipclk_0", + "dout_peric1_usi09_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_0, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_1, "gout_peric1_top1_ipclk_1", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_1, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_10, "gout_peric1_top1_ipclk_10", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_10, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_12, "gout_peric1_top1_ipclk_12", + "dout_peric1_usi12_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_12, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_13, "gout_peric1_top1_ipclk_13", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_13, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_14, "gout_peric1_top1_ipclk_14", + "dout_peric1_usi18_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_14, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_15, "gout_peric1_top1_ipclk_15", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_15, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_2, "gout_peric1_top1_ipclk_2", + "dout_peric1_usi10_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_2, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_3, "gout_peric1_top1_ipclk_3", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_3, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_4, "gout_peric1_top1_ipclk_4", + "dout_peric1_usi11_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_4, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_5, "gout_peric1_top1_ipclk_5", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_5, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_6, "gout_peric1_top1_ipclk_6", + "dout_peric1_usi16_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_6, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_7, "gout_peric1_top1_ipclk_7", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_7, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_IPCLK_9, "gout_peric1_top1_ipclk_9", + "dout_peric1_usi17_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_IPCLK_9, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_0, "gout_peric1_top1_pclk_0", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_0, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_1, "gout_peric1_top1_pclk_1", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_1, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_10, "gout_peric1_top1_pclk_10", + "dout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_10, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_12, "gout_peric1_top1_pclk_12", + "dout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_12, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_13, "gout_peric1_top1_pclk_13", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_13, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_14, "gout_peric1_top1_pclk_14", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_14, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_15, "gout_peric1_top1_pclk_15", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_15, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_2, "gout_peric1_top1_pclk_2", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_2, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_3, "gout_peric1_top1_pclk_3", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_3, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_4, "gout_peric1_top1_pclk_4", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_4, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_5, "gout_peric1_top1_pclk_5", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_5, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_6, "gout_peric1_top1_pclk_6", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_6, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_7, "gout_peric1_top1_pclk_7", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_7, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_TOP1_PCLK_9, "gout_peric1_top1_pclk_9", + "dout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PERIC1_TOP1_IPCLKPORT_PCLK_9, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_BUSP_CLK, "gout_peric1_busp_clk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_BUSP_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_OSCCLK_CLK, "gout_peric1_oscclk_clk", + "oscclk", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_OSCCLK_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI06_USI_CLK, "gout_peric1_usi06_usi_clk", + "dout_peric1_usi06_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI06_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI07_USI_CLK, "gout_peric1_usi07_usi_clk", + "dout_peric1_usi07_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI07_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI08_USI_CLK, "gout_peric1_usi08_usi_clk", + "dout_peric1_usi08_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI08_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI09_USI_CLK, "gout_peric1_usi09_usi_clk", + "dout_peric1_usi09_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI09_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI10_USI_CLK, "gout_peric1_usi10_usi_clk", + "dout_peric1_usi10_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI10_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI11_USI_CLK, "gout_peric1_usi11_usi_clk", + "dout_peric1_usi11_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI11_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI16_USI_CLK, "gout_peric1_usi16_usi_clk", + "dout_peric1_usi16_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI16_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI17_USI_CLK, "gout_peric1_usi17_usi_clk", + "dout_peric1_usi17_usi", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI17_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI_I2C_CLK, "gout_peric1_usi_i2c_clk", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_USI_I2C_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SYSREG_PCLK, "gout_peric1_sysreg_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SYSREG_PERIC1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI16_I3C_PCLK, "gout_peric1_usi16_i3c_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI16_I3C_IPCLKPORT_I_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI16_I3C_SCLK, "gout_peric1_usi16_i3c_sclk", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI16_I3C_IPCLKPORT_I_SCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI17_I3C_PCLK, "gout_peric1_usi17_i3c_pclk", + "dout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI17_I3C_IPCLKPORT_I_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI17_I3C_SCLK, "gout_peric1_usi17_i3c_sclk", + "dout_peric1_usi_i2c", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI17_I3C_IPCLKPORT_I_SCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_XIU_P_ACLK, "gout_peric1_xiu_p_aclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_XIU_P_PERIC1_IPCLKPORT_ACLK, + 21, CLK_IGNORE_UNUSED, 0), +}; + +static const struct samsung_cmu_info peric1_cmu_info __initconst = { + .mux_clks = peric1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peric1_mux_clks), + .div_clks = peric1_div_clks, + .nr_div_clks = ARRAY_SIZE(peric1_div_clks), + .gate_clks = peric1_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peric1_gate_clks), + .nr_clk_ids = CLKS_NR_PERIC1, + .clk_regs = peric1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peric1_clk_regs), + .clk_name = "bus", +}; + /* ---- CMU_PERIS ----------------------------------------------------------- */ /* Register Offset definitions for CMU_PERIS (0x10020000) */ @@ -1544,6 +2690,12 @@ static const struct of_device_id exynos990_cmu_of_match[] = { { .compatible = "samsung,exynos990-cmu-hsi0", .data = &hsi0_cmu_info, + }, { + .compatible = "samsung,exynos990-cmu-peric0", + .data = &peric0_cmu_info, + }, { + .compatible = "samsung,exynos990-cmu-peric1", + .data = &peric1_cmu_info, }, { }, }; From 6b72fd170592ad3fb14cadfa973908e5d63d27c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Fri, 23 May 2025 12:19:30 +0200 Subject: [PATCH 0998/2711] RISC-V: KVM: add support for FWFT SBI extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add basic infrastructure to support the FWFT extension in KVM. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Reviewed-by: Atish Patra Link: https://lore.kernel.org/r/20250523101932.1594077-14-cleger@rivosinc.com Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_host.h | 4 + arch/riscv/include/asm/kvm_vcpu_sbi.h | 1 + arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h | 29 +++ arch/riscv/include/uapi/asm/kvm.h | 1 + arch/riscv/kvm/Makefile | 1 + arch/riscv/kvm/vcpu_sbi.c | 4 + arch/riscv/kvm/vcpu_sbi_fwft.c | 216 +++++++++++++++++++++ 7 files changed, 256 insertions(+) create mode 100644 arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h create mode 100644 arch/riscv/kvm/vcpu_sbi_fwft.c diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index d71d3299a335..4d794573e3db 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -263,6 +264,9 @@ struct kvm_vcpu_arch { /* Performance monitoring context */ struct kvm_pmu pmu_context; + /* Firmware feature SBI extension context */ + struct kvm_sbi_fwft fwft_context; + /* 'static' configurations which are set only once */ struct kvm_vcpu_config cfg; diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h index d678fd7e5973..766031e80960 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h @@ -102,6 +102,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_susp; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta; +extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor; diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h b/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h new file mode 100644 index 000000000000..9ba841355758 --- /dev/null +++ b/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Rivos Inc. + * + * Authors: + * Clément Léger + */ + +#ifndef __KVM_VCPU_RISCV_FWFT_H +#define __KVM_VCPU_RISCV_FWFT_H + +#include + +struct kvm_sbi_fwft_feature; + +struct kvm_sbi_fwft_config { + const struct kvm_sbi_fwft_feature *feature; + bool supported; + unsigned long flags; +}; + +/* FWFT data structure per vcpu */ +struct kvm_sbi_fwft { + struct kvm_sbi_fwft_config *configs; +}; + +#define vcpu_to_fwft(vcpu) (&(vcpu)->arch.fwft_context) + +#endif /* !__KVM_VCPU_RISCV_FWFT_H */ diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index ef27d4289da1..a5ca0f4ce2d3 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -205,6 +205,7 @@ enum KVM_RISCV_SBI_EXT_ID { KVM_RISCV_SBI_EXT_DBCN, KVM_RISCV_SBI_EXT_STA, KVM_RISCV_SBI_EXT_SUSP, + KVM_RISCV_SBI_EXT_FWFT, KVM_RISCV_SBI_EXT_MAX, }; diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile index 4b199dc3e58b..07197395750e 100644 --- a/arch/riscv/kvm/Makefile +++ b/arch/riscv/kvm/Makefile @@ -27,6 +27,7 @@ kvm-y += vcpu_onereg.o kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o kvm-y += vcpu_sbi.o kvm-y += vcpu_sbi_base.o +kvm-y += vcpu_sbi_fwft.o kvm-y += vcpu_sbi_hsm.o kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_sbi_pmu.o kvm-y += vcpu_sbi_replace.o diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index a56c4959f9ad..01a93f4fdb16 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -78,6 +78,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = { .ext_idx = KVM_RISCV_SBI_EXT_STA, .ext_ptr = &vcpu_sbi_ext_sta, }, + { + .ext_idx = KVM_RISCV_SBI_EXT_FWFT, + .ext_ptr = &vcpu_sbi_ext_fwft, + }, { .ext_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL, .ext_ptr = &vcpu_sbi_ext_experimental, diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c new file mode 100644 index 000000000000..b0f66c7bf010 --- /dev/null +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025 Rivos Inc. + * + * Authors: + * Clément Léger + */ + +#include +#include +#include +#include +#include +#include +#include + +struct kvm_sbi_fwft_feature { + /** + * @id: Feature ID + */ + enum sbi_fwft_feature_t id; + + /** + * @supported: Check if the feature is supported on the vcpu + * + * This callback is optional, if not provided the feature is assumed to + * be supported + */ + bool (*supported)(struct kvm_vcpu *vcpu); + + /** + * @set: Set the feature value + * + * Return SBI_SUCCESS on success or an SBI error (SBI_ERR_*) + * + * This callback is mandatory + */ + long (*set)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long value); + + /** + * @get: Get the feature current value + * + * Return SBI_SUCCESS on success or an SBI error (SBI_ERR_*) + * + * This callback is mandatory + */ + long (*get)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long *value); +}; + +static const enum sbi_fwft_feature_t kvm_fwft_defined_features[] = { + SBI_FWFT_MISALIGNED_EXC_DELEG, + SBI_FWFT_LANDING_PAD, + SBI_FWFT_SHADOW_STACK, + SBI_FWFT_DOUBLE_TRAP, + SBI_FWFT_PTE_AD_HW_UPDATING, + SBI_FWFT_POINTER_MASKING_PMLEN, +}; + +static bool kvm_fwft_is_defined_feature(enum sbi_fwft_feature_t feature) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(kvm_fwft_defined_features); i++) { + if (kvm_fwft_defined_features[i] == feature) + return true; + } + + return false; +} + +static const struct kvm_sbi_fwft_feature features[] = { +}; + +static struct kvm_sbi_fwft_config * +kvm_sbi_fwft_get_config(struct kvm_vcpu *vcpu, enum sbi_fwft_feature_t feature) +{ + int i; + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + + for (i = 0; i < ARRAY_SIZE(features); i++) { + if (fwft->configs[i].feature->id == feature) + return &fwft->configs[i]; + } + + return NULL; +} + +static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature, + struct kvm_sbi_fwft_config **conf) +{ + struct kvm_sbi_fwft_config *tconf; + + tconf = kvm_sbi_fwft_get_config(vcpu, feature); + if (!tconf) { + if (kvm_fwft_is_defined_feature(feature)) + return SBI_ERR_NOT_SUPPORTED; + + return SBI_ERR_DENIED; + } + + if (!tconf->supported) + return SBI_ERR_NOT_SUPPORTED; + + *conf = tconf; + + return SBI_SUCCESS; +} + +static int kvm_sbi_fwft_set(struct kvm_vcpu *vcpu, u32 feature, + unsigned long value, unsigned long flags) +{ + int ret; + struct kvm_sbi_fwft_config *conf; + + ret = kvm_fwft_get_feature(vcpu, feature, &conf); + if (ret) + return ret; + + if ((flags & ~SBI_FWFT_SET_FLAG_LOCK) != 0) + return SBI_ERR_INVALID_PARAM; + + if (conf->flags & SBI_FWFT_SET_FLAG_LOCK) + return SBI_ERR_DENIED_LOCKED; + + conf->flags = flags; + + return conf->feature->set(vcpu, conf, value); +} + +static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, unsigned long feature, + unsigned long *value) +{ + int ret; + struct kvm_sbi_fwft_config *conf; + + ret = kvm_fwft_get_feature(vcpu, feature, &conf); + if (ret) + return ret; + + return conf->feature->get(vcpu, conf, value); +} + +static int kvm_sbi_ext_fwft_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_vcpu_sbi_return *retdata) +{ + int ret; + struct kvm_cpu_context *cp = &vcpu->arch.guest_context; + unsigned long funcid = cp->a6; + + switch (funcid) { + case SBI_EXT_FWFT_SET: + ret = kvm_sbi_fwft_set(vcpu, cp->a0, cp->a1, cp->a2); + break; + case SBI_EXT_FWFT_GET: + ret = kvm_sbi_fwft_get(vcpu, cp->a0, &retdata->out_val); + break; + default: + ret = SBI_ERR_NOT_SUPPORTED; + break; + } + + retdata->err_val = ret; + + return 0; +} + +static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu) +{ + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + const struct kvm_sbi_fwft_feature *feature; + struct kvm_sbi_fwft_config *conf; + int i; + + fwft->configs = kcalloc(ARRAY_SIZE(features), sizeof(struct kvm_sbi_fwft_config), + GFP_KERNEL); + if (!fwft->configs) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(features); i++) { + feature = &features[i]; + conf = &fwft->configs[i]; + if (feature->supported) + conf->supported = feature->supported(vcpu); + else + conf->supported = true; + + conf->feature = feature; + } + + return 0; +} + +static void kvm_sbi_ext_fwft_deinit(struct kvm_vcpu *vcpu) +{ + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + + kfree(fwft->configs); +} + +static void kvm_sbi_ext_fwft_reset(struct kvm_vcpu *vcpu) +{ + int i; + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + + for (i = 0; i < ARRAY_SIZE(features); i++) + fwft->configs[i].flags = 0; +} + +const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft = { + .extid_start = SBI_EXT_FWFT, + .extid_end = SBI_EXT_FWFT, + .handler = kvm_sbi_ext_fwft_handler, + .init = kvm_sbi_ext_fwft_init, + .deinit = kvm_sbi_ext_fwft_deinit, + .reset = kvm_sbi_ext_fwft_reset, +}; From bb053f816a8bcb0a9135fc4cc611b1cab3d82201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Fri, 23 May 2025 12:19:31 +0200 Subject: [PATCH 0999/2711] RISC-V: KVM: add support for SBI_FWFT_MISALIGNED_DELEG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SBI_FWFT_MISALIGNED_DELEG needs hedeleg to be modified to delegate misaligned load/store exceptions. Save and restore it during CPU load/put. Signed-off-by: Clément Léger Reviewed-by: Deepak Gupta Reviewed-by: Andrew Jones Reviewed-by: Atish Patra Link: https://lore.kernel.org/r/20250523101932.1594077-15-cleger@rivosinc.com Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_sbi_fwft.c | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c index b0f66c7bf010..6770c043bbcb 100644 --- a/arch/riscv/kvm/vcpu_sbi_fwft.c +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c @@ -14,6 +14,8 @@ #include #include +#define MIS_DELEG (BIT_ULL(EXC_LOAD_MISALIGNED) | BIT_ULL(EXC_STORE_MISALIGNED)) + struct kvm_sbi_fwft_feature { /** * @id: Feature ID @@ -68,7 +70,46 @@ static bool kvm_fwft_is_defined_feature(enum sbi_fwft_feature_t feature) return false; } +static bool kvm_sbi_fwft_misaligned_delegation_supported(struct kvm_vcpu *vcpu) +{ + return misaligned_traps_can_delegate(); +} + +static long kvm_sbi_fwft_set_misaligned_delegation(struct kvm_vcpu *vcpu, + struct kvm_sbi_fwft_config *conf, + unsigned long value) +{ + struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; + + if (value == 1) { + cfg->hedeleg |= MIS_DELEG; + csr_set(CSR_HEDELEG, MIS_DELEG); + } else if (value == 0) { + cfg->hedeleg &= ~MIS_DELEG; + csr_clear(CSR_HEDELEG, MIS_DELEG); + } else { + return SBI_ERR_INVALID_PARAM; + } + + return SBI_SUCCESS; +} + +static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu, + struct kvm_sbi_fwft_config *conf, + unsigned long *value) +{ + *value = (csr_read(CSR_HEDELEG) & MIS_DELEG) == MIS_DELEG; + + return SBI_SUCCESS; +} + static const struct kvm_sbi_fwft_feature features[] = { + { + .id = SBI_FWFT_MISALIGNED_EXC_DELEG, + .supported = kvm_sbi_fwft_misaligned_delegation_supported, + .set = kvm_sbi_fwft_set_misaligned_delegation, + .get = kvm_sbi_fwft_get_misaligned_delegation, + }, }; static struct kvm_sbi_fwft_config * From ce47f81925ed73f9d27b1a01f07afdb031949c68 Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Wed, 13 Aug 2025 07:53:50 +0200 Subject: [PATCH 1000/2711] PCI: hv: Remove unused parameter of hv_msi_free() The 'info' parameter of hv_msi_free() is unused. Delete it. Signed-off-by: Nam Cao Signed-off-by: Manivannan Sadhasivam Acked-by: Wei Liu --- drivers/pci/controller/pci-hyperv.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index d2b7e8ea710b..146b43981b27 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1680,7 +1680,6 @@ static void hv_int_desc_free(struct hv_pci_dev *hpdev, /** * hv_msi_free() - Free the MSI. * @domain: The interrupt domain pointer - * @info: Extra MSI-related context * @irq: Identifies the IRQ. * * The Hyper-V parent partition and hypervisor are tracking the @@ -1688,8 +1687,7 @@ static void hv_int_desc_free(struct hv_pci_dev *hpdev, * table up to date. This callback sends a message that frees * the IRT entry and related tracking nonsense. */ -static void hv_msi_free(struct irq_domain *domain, struct msi_domain_info *info, - unsigned int irq) +static void hv_msi_free(struct irq_domain *domain, unsigned int irq) { struct hv_pcibus_device *hbus; struct hv_pci_dev *hpdev; @@ -2181,10 +2179,8 @@ static int hv_pcie_domain_alloc(struct irq_domain *d, unsigned int virq, unsigne static void hv_pcie_domain_free(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs) { - struct msi_domain_info *info = d->host_data; - for (int i = 0; i < nr_irqs; i++) - hv_msi_free(d, info, virq + i); + hv_msi_free(d, virq + i); irq_domain_free_irqs_top(d, virq, nr_irqs); } From 92bac7d4de9c07933f6b76d8f1c7f8240f911f4f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 9 May 2025 09:17:04 +0200 Subject: [PATCH 1001/2711] extcon: adc-jack: Cleanup wakeup source only if it was enabled Driver in the probe enables wakeup source conditionally, so the cleanup path should do the same - do not release the wakeup source memory if it was not allocated. Link: https://lore.kernel.org/lkml/20250509071703.39442-2-krzysztof.kozlowski@linaro.org/ Reported-by: Christophe JAILLET Closes: https://lore.kernel.org/r/22aaebb7-553b-4571-8a43-58a523241082@wanadoo.fr/ Fixes: 78b6a991eb6c ("extcon: adc-jack: Fix wakeup source leaks on device unbind") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-adc-jack.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 557930394abd..7e3c9f38297b 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -164,7 +164,8 @@ static void adc_jack_remove(struct platform_device *pdev) { struct adc_jack_data *data = platform_get_drvdata(pdev); - device_init_wakeup(&pdev->dev, false); + if (data->wakeup_source) + device_init_wakeup(&pdev->dev, false); free_irq(data->irq, data); cancel_work_sync(&data->handler.work); } From de33ea612a36f8415579298899fd0b6c28a45c80 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 6 May 2025 10:32:15 +0300 Subject: [PATCH 1002/2711] dt-bindings: extcon: Document Maxim MAX14526 MUIC Add bindings for Maxim MAX14526 MicroUSB Integrated Circuit. Link: https://lore.kernel.org/lkml/20250506073216.43059-2-clamor95@gmail.com/ Signed-off-by: Svyatoslav Ryhel Reviewed-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- .../bindings/extcon/maxim,max14526.yaml | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Documentation/devicetree/bindings/extcon/maxim,max14526.yaml diff --git a/Documentation/devicetree/bindings/extcon/maxim,max14526.yaml b/Documentation/devicetree/bindings/extcon/maxim,max14526.yaml new file mode 100644 index 000000000000..7eb5918df1c2 --- /dev/null +++ b/Documentation/devicetree/bindings/extcon/maxim,max14526.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/extcon/maxim,max14526.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX14526 MicroUSB Integrated Circuit (MUIC) + +maintainers: + - Svyatoslav Ryhel + +properties: + compatible: + const: maxim,max14526 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + connector: + $ref: /schemas/connector/usb-connector.yaml# + + port: + $ref: /schemas/graph.yaml#/properties/port + +required: + - compatible + - reg + - interrupts + - connector + - port + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + muic@44 { + compatible = "maxim,max14526"; + reg = <0x44>; + + interrupt-parent = <&gpio>; + interrupts = <72 IRQ_TYPE_EDGE_FALLING>; + + connector { + compatible = "usb-b-connector"; + label = "micro-USB"; + type = "micro"; + }; + + port { + #address-cells = <1>; + #size-cells = <0>; + + muic_to_charger: endpoint@0 { + reg = <0>; + remote-endpoint = <&charger_input>; + }; + + muic_to_usb: endpoint@1 { + reg = <1>; + remote-endpoint = <&usb_input>; + }; + + muic_to_mhl: endpoint@2 { + reg = <2>; + remote-endpoint = <&mhl_input>; + }; + }; + }; + }; +... From 145af3ddd1cda5c8399c27fe529150aa53b2fcb9 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 6 May 2025 10:32:16 +0300 Subject: [PATCH 1003/2711] extcon: Add basic support for Maxim MAX14526 MUIC The MAX14526 is designed to simplify interface requirements on portable devices by multiplexing common inputs (USB, UART, Microphone, Stereo Audio and Composite Video) on a single micro/mini USB connector. The USB input supports Hi-Speed USB and the audio/video inputs feature negative rail signal operation allowing simple DC coupled accessories. These device allow a single micro/mini USB port to support all the common interfaces on Cellular phones and portable media players over the same external lines. Link: https://lore.kernel.org/lkml/20250506073216.43059-3-clamor95@gmail.com/ Signed-off-by: Svyatoslav Ryhel Signed-off-by: Chanwoo Choi --- drivers/extcon/Kconfig | 12 ++ drivers/extcon/Makefile | 1 + drivers/extcon/extcon-max14526.c | 302 +++++++++++++++++++++++++++++++ 3 files changed, 315 insertions(+) create mode 100644 drivers/extcon/extcon-max14526.c diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index a6f6d467aacf..1096afc0b5bb 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -134,6 +134,18 @@ config EXTCON_MAX8997 Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory detector and switch. +config EXTCON_MAX14526 + tristate "Maxim MAX14526 EXTCON Support" + select IRQ_DOMAIN + select REGMAP_I2C + help + If you say yes here you get support for the Maxim MAX14526 + MUIC device. The MAX14526 MUIC is a USB port accessory + detector and switch. The MAX14526 is designed to simplify + interface requirements on portable devices by multiplexing + common inputs (USB, UART, Microphone, Stereo Audio and + Composite Video) on a single micro/mini USB connector. + config EXTCON_PALMAS tristate "Palmas USB EXTCON support" depends on MFD_PALMAS diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 0d6d23faf748..6482f2bfd661 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o obj-$(CONFIG_EXTCON_MAX77843) += extcon-max77843.o obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o +obj-$(CONFIG_EXTCON_MAX14526) += extcon-max14526.o obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o obj-$(CONFIG_EXTCON_PTN5150) += extcon-ptn5150.o obj-$(CONFIG_EXTCON_QCOM_SPMI_MISC) += extcon-qcom-spmi-misc.o diff --git a/drivers/extcon/extcon-max14526.c b/drivers/extcon/extcon-max14526.c new file mode 100644 index 000000000000..93cb1d9a1044 --- /dev/null +++ b/drivers/extcon/extcon-max14526.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* I2C addresses of MUIC internal registers */ +#define MAX14526_DEVICE_ID 0x00 +#define MAX14526_ID 0x02 + +/* CONTROL_1 register masks */ +#define MAX14526_CONTROL_1 0x01 +#define ID_2P2 BIT(6) +#define ID_620 BIT(5) +#define ID_200 BIT(4) +#define VLDO BIT(3) +#define SEMREN BIT(2) +#define ADC_EN BIT(1) +#define CP_EN BIT(0) + +/* CONTROL_2 register masks */ +#define MAX14526_CONTROL_2 0x02 +#define INTPOL BIT(7) +#define INT_EN BIT(6) +#define MIC_LP BIT(5) +#define CP_AUD BIT(4) +#define CHG_TYPE BIT(1) +#define USB_DET_DIS BIT(0) + +/* SW_CONTROL register masks */ +#define MAX14526_SW_CONTROL 0x03 +#define SW_DATA 0x00 +#define SW_UART 0x01 +#define SW_AUDIO 0x02 +#define SW_OPEN 0x07 + +/* INT_STATUS register masks */ +#define MAX14526_INT_STAT 0x04 +#define CHGDET BIT(7) +#define MR_COMP BIT(6) +#define SENDEND BIT(5) +#define V_VBUS BIT(4) + +/* STATUS register masks */ +#define MAX14526_STATUS 0x05 +#define CPORT BIT(7) +#define CHPORT BIT(6) +#define C1COMP BIT(0) + +enum max14526_idno_resistance { + MAX14526_GND, + MAX14526_24KOHM, + MAX14526_56KOHM, + MAX14526_100KOHM, + MAX14526_130KOHM, + MAX14526_180KOHM, + MAX14526_240KOHM, + MAX14526_330KOHM, + MAX14526_430KOHM, + MAX14526_620KOHM, + MAX14526_910KOHM, + MAX14526_OPEN +}; + +enum max14526_field_idx { + VENDOR_ID, CHIP_REV, /* DEVID */ + DM, DP, /* SW_CONTROL */ + MAX14526_N_REGMAP_FIELDS +}; + +static const struct reg_field max14526_reg_field[MAX14526_N_REGMAP_FIELDS] = { + [VENDOR_ID] = REG_FIELD(MAX14526_DEVICE_ID, 4, 7), + [CHIP_REV] = REG_FIELD(MAX14526_DEVICE_ID, 0, 3), + [DM] = REG_FIELD(MAX14526_SW_CONTROL, 0, 2), + [DP] = REG_FIELD(MAX14526_SW_CONTROL, 3, 5), +}; + +struct max14526_data { + struct i2c_client *client; + struct extcon_dev *edev; + + struct regmap *regmap; + struct regmap_field *rfield[MAX14526_N_REGMAP_FIELDS]; + + int last_state; + int cable; +}; + +enum max14526_muic_modes { + MAX14526_OTG = MAX14526_GND, /* no power */ + MAX14526_MHL = MAX14526_56KOHM, /* no power */ + MAX14526_OTG_Y = MAX14526_GND | V_VBUS, + MAX14526_MHL_CHG = MAX14526_GND | V_VBUS | CHGDET, + MAX14526_NONE = MAX14526_OPEN, + MAX14526_USB = MAX14526_OPEN | V_VBUS, + MAX14526_CHG = MAX14526_OPEN | V_VBUS | CHGDET, +}; + +static const unsigned int max14526_extcon_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_CHG_USB_FAST, + EXTCON_DISP_MHL, + EXTCON_NONE, +}; + +static int max14526_ap_usb_mode(struct max14526_data *priv) +{ + struct device *dev = &priv->client->dev; + int ret; + + /* Enable USB Path */ + ret = regmap_field_write(priv->rfield[DM], SW_DATA); + if (ret) + return ret; + + ret = regmap_field_write(priv->rfield[DP], SW_DATA); + if (ret) + return ret; + + /* Enable 200K, Charger Pump and ADC */ + ret = regmap_write(priv->regmap, MAX14526_CONTROL_1, + ID_200 | ADC_EN | CP_EN); + if (ret) + return ret; + + dev_dbg(dev, "AP USB mode set\n"); + + return 0; +} + +static irqreturn_t max14526_interrupt(int irq, void *dev_id) +{ + struct max14526_data *priv = dev_id; + struct device *dev = &priv->client->dev; + int state, ret; + + /* + * Upon an MUIC IRQ (MUIC_INT_N falls), wait at least 70ms + * before reading INT_STAT and STATUS. After the reads, + * MUIC_INT_N returns to high (but the INT_STAT and STATUS + * contents will be held). + */ + msleep(100); + + ret = regmap_read(priv->regmap, MAX14526_INT_STAT, &state); + if (ret) + dev_err(dev, "failed to read MUIC state %d\n", ret); + + if (state == priv->last_state) + return IRQ_HANDLED; + + /* Detach previous device */ + extcon_set_state_sync(priv->edev, priv->cable, false); + + switch (state) { + case MAX14526_USB: + priv->cable = EXTCON_USB; + break; + + case MAX14526_CHG: + priv->cable = EXTCON_CHG_USB_FAST; + break; + + case MAX14526_OTG: + case MAX14526_OTG_Y: + priv->cable = EXTCON_USB_HOST; + break; + + case MAX14526_MHL: + case MAX14526_MHL_CHG: + priv->cable = EXTCON_DISP_MHL; + break; + + case MAX14526_NONE: + default: + priv->cable = EXTCON_NONE; + break; + } + + extcon_set_state_sync(priv->edev, priv->cable, true); + + priv->last_state = state; + + return IRQ_HANDLED; +} + +static const struct regmap_config max14526_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX14526_STATUS, +}; + +static int max14526_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct max14526_data *priv; + int ret, dev_id, rev, i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->client = client; + i2c_set_clientdata(client, priv); + + priv->regmap = devm_regmap_init_i2c(client, &max14526_regmap_config); + if (IS_ERR(priv->regmap)) + return dev_err_probe(dev, PTR_ERR(priv->regmap), "cannot allocate regmap\n"); + + for (i = 0; i < MAX14526_N_REGMAP_FIELDS; i++) { + priv->rfield[i] = devm_regmap_field_alloc(dev, priv->regmap, + max14526_reg_field[i]); + if (IS_ERR(priv->rfield[i])) + return dev_err_probe(dev, PTR_ERR(priv->rfield[i]), + "cannot allocate regmap field\n"); + } + + /* Detect if MUIC version is supported */ + ret = regmap_field_read(priv->rfield[VENDOR_ID], &dev_id); + if (ret) + return dev_err_probe(dev, ret, "failed to read MUIC ID\n"); + + regmap_field_read(priv->rfield[CHIP_REV], &rev); + + if (dev_id == MAX14526_ID) + dev_info(dev, "detected MAX14526 MUIC with id 0x%x, rev 0x%x\n", dev_id, rev); + else + dev_err_probe(dev, -EINVAL, "MUIC vendor id 0x%X is not recognized\n", dev_id); + + priv->edev = devm_extcon_dev_allocate(dev, max14526_extcon_cable); + if (IS_ERR(priv->edev)) + return dev_err_probe(dev, (IS_ERR(priv->edev)), + "failed to allocate extcon device\n"); + + ret = devm_extcon_dev_register(dev, priv->edev); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to register extcon device\n"); + + ret = max14526_ap_usb_mode(priv); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to set AP USB mode\n"); + + regmap_write_bits(priv->regmap, MAX14526_CONTROL_2, INT_EN, INT_EN); + regmap_write_bits(priv->regmap, MAX14526_CONTROL_2, USB_DET_DIS, (u32)~USB_DET_DIS); + + ret = devm_request_threaded_irq(dev, client->irq, NULL, &max14526_interrupt, + IRQF_ONESHOT | IRQF_SHARED, client->name, priv); + if (ret) + return dev_err_probe(dev, ret, "failed to register IRQ\n"); + + irq_wake_thread(client->irq, priv); + + return 0; +} + +static int max14526_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max14526_data *priv = i2c_get_clientdata(client); + + irq_wake_thread(client->irq, priv); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(max14526_pm_ops, NULL, max14526_resume); + +static const struct of_device_id max14526_match[] = { + { .compatible = "maxim,max14526" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, max14526_match); + +static const struct i2c_device_id max14526_id[] = { + { "max14526" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max14526_id); + +static struct i2c_driver max14526_driver = { + .driver = { + .name = "max14526", + .of_match_table = max14526_match, + .pm = &max14526_pm_ops, + }, + .probe = max14526_probe, + .id_table = max14526_id, +}; +module_i2c_driver(max14526_driver); + +MODULE_AUTHOR("Svyatoslav Ryhel "); +MODULE_DESCRIPTION("MAX14526 extcon driver to support MUIC"); +MODULE_LICENSE("GPL"); From 67c74613f29610b59875a4aae513202db3afe300 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 13 May 2025 14:02:51 -0700 Subject: [PATCH 1004/2711] extcon: max14526: avoid defined but not used warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SIMPLE_PM_DEV_OPS() is deprecated according to . Use DEFINE_SIMPLE_PM_DEV_OPS() instead. This avoids a build warning when CONFIG_PM is not enabled: drivers/extcon/extcon-max14526.c:265:12: warning: ‘max14526_resume’ defined but not used [-Wunused-function] 265 | static int max14526_resume(struct device *dev) Fixes: 145af3ddd1cd ("extcon: Add basic support for Maxim MAX14526 MUIC") Signed-off-by: Randy Dunlap Link: https://lore.kernel.org/lkml/20250513210252.1139749-1-rdunlap@infradead.org/ Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max14526.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-max14526.c b/drivers/extcon/extcon-max14526.c index 93cb1d9a1044..3750a5c20612 100644 --- a/drivers/extcon/extcon-max14526.c +++ b/drivers/extcon/extcon-max14526.c @@ -272,7 +272,7 @@ static int max14526_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(max14526_pm_ops, NULL, max14526_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(max14526_pm_ops, NULL, max14526_resume); static const struct of_device_id max14526_match[] = { { .compatible = "maxim,max14526" }, From 531f47fd35f4ead8c76d584ef8c546b4cd9cb3b7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 15 May 2025 16:48:03 -0700 Subject: [PATCH 1005/2711] extcon: max14526: depends on I2C to prevent build warning/errors Make EXTCON_MAX14526 depend on I2C to address a kconfig warning and subsequent build errors: WARNING: unmet direct dependencies detected for REGMAP_I2C Depends on [m]: I2C [=m] Selected by [y]: - EXTCON_MAX14526 [=y] && EXTCON [=y] ld: vmlinux.o: in function `max14526_driver_init': extcon-max14526.c:(.init.text+0x77b0e): undefined reference to `i2c_register_driver' ld: vmlinux.o: in function `max14526_driver_exit': extcon-max14526.c:(.exit.text+0x467c): undefined reference to `i2c_del_driver' Fixes: 145af3ddd1cd ("extcon: Add basic support for Maxim MAX14526 MUIC") Signed-off-by: Randy Dunlap Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20250515234803.1385375-1-rdunlap@infradead.org/ --- drivers/extcon/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 1096afc0b5bb..aec46bf03302 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -136,6 +136,7 @@ config EXTCON_MAX8997 config EXTCON_MAX14526 tristate "Maxim MAX14526 EXTCON Support" + depends on I2C select IRQ_DOMAIN select REGMAP_I2C help From 958bb5a2794b2090593bd7a064e0c2f53dfa20cf Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Sun, 17 Aug 2025 10:52:04 +0200 Subject: [PATCH 1006/2711] dt-bindings: extcon: rt8973a: Convert DT bindings to YAML Convert the device tree bindings for Richtek RT8973A MUIC to the YAML format. No functional changes. Signed-off-by: Artur Weber Reviewed-by: Rob Herring (Arm) Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20250817-rt8973a-dt-bindings-yaml-v1-1-150eb4599dc9@gmail.com/ --- .../bindings/extcon/extcon-rt8973a.txt | 23 --------- .../bindings/extcon/richtek,rt8973a-muic.yaml | 49 +++++++++++++++++++ 2 files changed, 49 insertions(+), 23 deletions(-) delete mode 100644 Documentation/devicetree/bindings/extcon/extcon-rt8973a.txt create mode 100644 Documentation/devicetree/bindings/extcon/richtek,rt8973a-muic.yaml diff --git a/Documentation/devicetree/bindings/extcon/extcon-rt8973a.txt b/Documentation/devicetree/bindings/extcon/extcon-rt8973a.txt deleted file mode 100644 index cfcf455ad4de..000000000000 --- a/Documentation/devicetree/bindings/extcon/extcon-rt8973a.txt +++ /dev/null @@ -1,23 +0,0 @@ - -* Richtek RT8973A - Micro USB Switch device - -The Richtek RT8973A is Micro USB Switch with OVP and I2C interface. The RT8973A -is a USB port accessory detector and switch that is optimized to protect low -voltage system from abnormal high input voltage (up to 28V) and supports high -speed USB operation. Also, RT8973A support 'auto-configuration' mode. -If auto-configuration mode is enabled, RT8973A would control internal h/w patch -for USB D-/D+ switching. - -Required properties: -- compatible: Should be "richtek,rt8973a-muic" -- reg: Specifies the I2C slave address of the MUIC block. It should be 0x14 -- interrupts: Interrupt specifiers for detection interrupt sources. - -Example: - - rt8973a@14 { - compatible = "richtek,rt8973a-muic"; - interrupt-parent = <&gpx1>; - interrupts = <5 0>; - reg = <0x14>; - }; diff --git a/Documentation/devicetree/bindings/extcon/richtek,rt8973a-muic.yaml b/Documentation/devicetree/bindings/extcon/richtek,rt8973a-muic.yaml new file mode 100644 index 000000000000..f9e0d816c025 --- /dev/null +++ b/Documentation/devicetree/bindings/extcon/richtek,rt8973a-muic.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/extcon/richtek,rt8973a-muic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Richtek RT8973A MUIC + +maintainers: + - Chanwoo Choi + +description: + The Richtek RT8973A is Micro USB Switch with OVP and I2C interface. The RT8973A + is a USB port accessory detector and switch that is optimized to protect low + voltage system from abnormal high input voltage (up to 28V) and supports high + speed USB operation. Also, RT8973A support 'auto-configuration' mode. + If auto-configuration mode is enabled, RT8973A would control internal h/w patch + for USB D-/D+ switching. + +properties: + compatible: + const: richtek,rt8973a-muic + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + usb-switch@14 { + compatible = "richtek,rt8973a-muic"; + reg = <0x14>; + interrupt-parent = <&gpio>; + interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + }; + }; From 94d885eb8ffe15b3eb4abe92e03d852fce8ba81f Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Thu, 4 Sep 2025 22:41:44 +0200 Subject: [PATCH 1007/2711] dt-bindings: extcon: linux,extcon-usb-gpio: GPIO must be provided Without providing either ID or VBUS GPIO the driver is not able to operate. Original text binding says: "Either one of id-gpio or vbus-gpio must be present." Fixes: 79a31ce03f41 ("dt-bindings: extcon: convert extcon-usb-gpio.txt to yaml format") Acked-by: Conor Dooley Signed-off-by: David Heidelberg Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20250904-yaml-extcon-usb-gpio-v2-1-a5c4afa496c3@ixit.cz/ --- .../devicetree/bindings/extcon/linux,extcon-usb-gpio.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/extcon/linux,extcon-usb-gpio.yaml b/Documentation/devicetree/bindings/extcon/linux,extcon-usb-gpio.yaml index 8856107bdd33..8f29d333602b 100644 --- a/Documentation/devicetree/bindings/extcon/linux,extcon-usb-gpio.yaml +++ b/Documentation/devicetree/bindings/extcon/linux,extcon-usb-gpio.yaml @@ -25,6 +25,12 @@ properties: required: - compatible +anyOf: + - required: + - id-gpios + - required: + - vbus-gpios + additionalProperties: false examples: From e81783899d7d19cad567b68e115fcb37880e427b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 8 Sep 2025 11:05:16 +0200 Subject: [PATCH 1008/2711] Revert "m68k: make HPDCA and HPAPCI bools" This reverts commit 5a66087107b80ac4e58a94f37d9b8d12e22b4071. m68k patches shouldn't go through the tty tree without the m68k maintainer acking them first. Cc: Jiri Slaby (SUSE) Reported-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- arch/m68k/Kconfig.devices | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/m68k/Kconfig.devices b/arch/m68k/Kconfig.devices index e277f1bd2de1..e6e3efac1840 100644 --- a/arch/m68k/Kconfig.devices +++ b/arch/m68k/Kconfig.devices @@ -105,14 +105,14 @@ config AMIGA_BUILTIN_SERIAL To compile this driver as a module, choose M here. config HPDCA - bool "HP DCA serial support" + tristate "HP DCA serial support" depends on DIO && SERIAL_8250 help If you want to use the internal "DCA" serial ports on an HP300 machine, say Y here. config HPAPCI - bool "HP APCI serial support" + tristate "HP APCI serial support" depends on HP300 && SERIAL_8250 help If you want to use the internal "APCI" serial ports on an HP400 From 352ccf890a3e91f58bc32503f9afdc161bc2c34a Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 4 Sep 2025 13:39:27 +0200 Subject: [PATCH 1009/2711] KVM: s390: improve interrupt cpu for wakeup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns out that picking an idle CPU for floating interrupts has some negative side effects. The guest will keep the IO workload on its CPU and rather use an IPI from the interrupt CPU instead of moving workload. For example a guest with 2 vCPUs and 1 fio process might run that fio on vcpu1. If after diag500 both vCPUs are idle then vcpu0 is woken up. The guest will then do an IPI from vcpu0 to vcpu1. So lets change the heuristics and prefer the last CPU that went to sleep. This one is likely still in halt polling and can be woken up quickly. This patch shows significant improvements in terms of bandwidth or cpu consumption for fio and uperf workloads and seems to be a net win. Link: https://lore.kernel.org/linux-s390/20250904113927.119306-1-borntraeger@linux.ibm.com/ Reviewed-by: Christoph Schlameuß Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 2 +- arch/s390/kvm/interrupt.c | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index f870d09515cc..95d15416c39d 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -356,7 +356,7 @@ struct kvm_s390_float_interrupt { int counters[FIRQ_MAX_COUNT]; struct kvm_s390_mchk_info mchk; struct kvm_s390_ext_info srv_signal; - int next_rr_cpu; + int last_sleep_cpu; struct mutex ais_lock; u8 simm; u8 nimm; diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 60c360c18690..b8e6f82e92c3 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -1322,6 +1322,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 4, "enabled wait: %llu ns", sltime); no_timer: kvm_vcpu_srcu_read_unlock(vcpu); + vcpu->kvm->arch.float_int.last_sleep_cpu = vcpu->vcpu_idx; kvm_vcpu_halt(vcpu); vcpu->valid_wakeup = false; __unset_cpu_idle(vcpu); @@ -1948,18 +1949,15 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type) if (!online_vcpus) return; - /* find idle VCPUs first, then round robin */ - sigcpu = find_first_bit(kvm->arch.idle_mask, online_vcpus); - if (sigcpu == online_vcpus) { - do { - sigcpu = kvm->arch.float_int.next_rr_cpu++; - kvm->arch.float_int.next_rr_cpu %= online_vcpus; - /* avoid endless loops if all vcpus are stopped */ - if (nr_tries++ >= online_vcpus) - return; - } while (is_vcpu_stopped(kvm_get_vcpu(kvm, sigcpu))); + for (sigcpu = kvm->arch.float_int.last_sleep_cpu; ; sigcpu++) { + sigcpu %= online_vcpus; + dst_vcpu = kvm_get_vcpu(kvm, sigcpu); + if (!is_vcpu_stopped(dst_vcpu)) + break; + /* avoid endless loops if all vcpus are stopped */ + if (nr_tries++ >= online_vcpus) + return; } - dst_vcpu = kvm_get_vcpu(kvm, sigcpu); /* make the VCPU drop out of the SIE, or wake it up if sleeping */ switch (type) { From b5a5a16e37c004052e9181de5cff0638d44a4b9b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 7 Sep 2025 12:09:09 +0200 Subject: [PATCH 1010/2711] platform/x86: xiaomi-wmi: Use devm_mutex_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_mutex_init() instead of hand-writing it. This saves some LoC, improves readability and saves some space in the generated .o file. Before: ====== text data bss dec hex filename 3520 1112 64 4696 1258 drivers/platform/x86/xiaomi-wmi.o After: ===== text data bss dec hex filename 3069 1040 64 4173 104d drivers/platform/x86/xiaomi-wmi.o Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/bb5d7a57e11eb580f610276a351a01a993341fb8.1757239732.git.christophe.jaillet@wanadoo.fr Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/xiaomi-wmi.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/platform/x86/xiaomi-wmi.c b/drivers/platform/x86/xiaomi-wmi.c index cbed29ca502a..b892007b9863 100644 --- a/drivers/platform/x86/xiaomi-wmi.c +++ b/drivers/platform/x86/xiaomi-wmi.c @@ -26,13 +26,6 @@ struct xiaomi_wmi { unsigned int key_code; }; -static void xiaomi_mutex_destroy(void *data) -{ - struct mutex *lock = data; - - mutex_destroy(lock); -} - static int xiaomi_wmi_probe(struct wmi_device *wdev, const void *context) { struct xiaomi_wmi *data; @@ -46,8 +39,7 @@ static int xiaomi_wmi_probe(struct wmi_device *wdev, const void *context) return -ENOMEM; dev_set_drvdata(&wdev->dev, data); - mutex_init(&data->key_lock); - ret = devm_add_action_or_reset(&wdev->dev, xiaomi_mutex_destroy, &data->key_lock); + ret = devm_mutex_init(&wdev->dev, &data->key_lock); if (ret < 0) return ret; From c4f8b11bacd562f38c85f4f81a0a4426b267df70 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 7 Sep 2025 15:32:26 +0200 Subject: [PATCH 1011/2711] platform/x86: quickstart: Use devm_mutex_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_mutex_init() instead of hand-writing it. This saves some LoC, improves readability and saves some space in the generated .o file. Before: ====== text data bss dec hex filename 7607 2616 64 10287 282f drivers/platform/x86/quickstart.o After: ===== text data bss dec hex filename 7301 2544 64 9909 26b5 drivers/platform/x86/quickstart.o Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/530b930c981c436c172c0308b348d4ae4ef72800.1757251867.git.christophe.jaillet@wanadoo.fr Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/quickstart.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/platform/x86/quickstart.c b/drivers/platform/x86/quickstart.c index c332c7cdaff5..acb58518be37 100644 --- a/drivers/platform/x86/quickstart.c +++ b/drivers/platform/x86/quickstart.c @@ -154,13 +154,6 @@ static void quickstart_notify_remove(void *context) acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, quickstart_notify); } -static void quickstart_mutex_destroy(void *data) -{ - struct mutex *lock = data; - - mutex_destroy(lock); -} - static int quickstart_probe(struct platform_device *pdev) { struct quickstart_data *data; @@ -179,8 +172,7 @@ static int quickstart_probe(struct platform_device *pdev) data->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, data); - mutex_init(&data->input_lock); - ret = devm_add_action_or_reset(&pdev->dev, quickstart_mutex_destroy, &data->input_lock); + ret = devm_mutex_init(&pdev->dev, &data->input_lock); if (ret < 0) return ret; From 882569dca6646eb3294ec048d76f9bfea1f3348f Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Wed, 20 Aug 2025 16:52:00 +0800 Subject: [PATCH 1012/2711] PCI: plda: Remove dev_err_probe() when the errno is -ENOMEM The dev_err_probe() doesn't do anything when error is '-ENOMEM'. Therefore, remove the useless call to dev_err_probe(), and just return the value instead. Signed-off-by: Xichao Zhao [mani: reworded the subject] Signed-off-by: Manivannan Sadhasivam --- drivers/pci/controller/plda/pcie-plda-host.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c index 8e2db2e5b64b..3c2f68383010 100644 --- a/drivers/pci/controller/plda/pcie-plda-host.c +++ b/drivers/pci/controller/plda/pcie-plda-host.c @@ -599,8 +599,7 @@ int plda_pcie_host_init(struct plda_pcie_rp *port, struct pci_ops *ops, bridge = devm_pci_alloc_host_bridge(dev, 0); if (!bridge) - return dev_err_probe(dev, -ENOMEM, - "failed to alloc bridge\n"); + return -ENOMEM; if (port->host_ops && port->host_ops->host_init) { ret = port->host_ops->host_init(port); From f842d3313ba179d4005096357289c7ad09cec575 Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Mon, 8 Sep 2025 17:38:27 +0530 Subject: [PATCH 1013/2711] PCI: j721e: Fix programming sequence of "strap" settings The Cadence PCIe Controller integrated in the TI K3 SoCs supports both Root-Complex and Endpoint modes of operation. The Glue Layer allows "strapping" the Mode of operation of the Controller, the Link Speed and the Link Width. This is enabled by programming the "PCIEn_CTRL" register (n corresponds to the PCIe instance) within the CTRL_MMR memory-mapped register space. The "reset-values" of the registers are also different depending on the mode of operation. Since the PCIe Controller latches onto the "reset-values" immediately after being powered on, if the Glue Layer configuration is not done while the PCIe Controller is off, it will result in the PCIe Controller latching onto the wrong "reset-values". In practice, this will show up as a wrong representation of the PCIe Controller's capability structures in the PCIe Configuration Space. Some such capabilities which are supported by the PCIe Controller in the Root-Complex mode but are incorrectly latched onto as being unsupported are: - Link Bandwidth Notification - Alternate Routing ID (ARI) Forwarding Support - Next capability offset within Advanced Error Reporting (AER) capability Fix this by powering off the PCIe Controller before programming the "strap" settings and powering it on after that. The runtime PM APIs namely pm_runtime_put_sync() and pm_runtime_get_sync() will decrement and increment the usage counter respectively, causing GENPD to power off and power on the PCIe Controller. Fixes: f3e25911a430 ("PCI: j721e: Add TI J721E PCIe driver") Signed-off-by: Siddharth Vadapalli Signed-off-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250908120828.1471776-1-s-vadapalli@ti.com --- drivers/pci/controller/cadence/pci-j721e.c | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c index cfca13a4c840..5a9ae33e2b93 100644 --- a/drivers/pci/controller/cadence/pci-j721e.c +++ b/drivers/pci/controller/cadence/pci-j721e.c @@ -284,6 +284,25 @@ static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie) if (!ret) offset = args.args[0]; + /* + * The PCIe Controller's registers have different "reset-values" + * depending on the "strap" settings programmed into the PCIEn_CTRL + * register within the CTRL_MMR memory-mapped register space. + * The registers latch onto a "reset-value" based on the "strap" + * settings sampled after the PCIe Controller is powered on. + * To ensure that the "reset-values" are sampled accurately, power + * off the PCIe Controller before programming the "strap" settings + * and power it on after that. The runtime PM APIs namely + * pm_runtime_put_sync() and pm_runtime_get_sync() will decrement and + * increment the usage counter respectively, causing GENPD to power off + * and power on the PCIe Controller. + */ + ret = pm_runtime_put_sync(dev); + if (ret < 0) { + dev_err(dev, "Failed to power off PCIe Controller\n"); + return ret; + } + ret = j721e_pcie_set_mode(pcie, syscon, offset); if (ret < 0) { dev_err(dev, "Failed to set pci mode\n"); @@ -302,6 +321,12 @@ static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie) return ret; } + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "Failed to power on PCIe Controller\n"); + return ret; + } + /* Enable ACSPCIE refclk output if the optional property exists */ syscon = syscon_regmap_lookup_by_phandle_optional(node, "ti,syscon-acspcie-proxy-ctrl"); From d0856a6dff57f95cc5d2d74e50880f01697d0cc4 Mon Sep 17 00:00:00 2001 From: Adam Xue Date: Fri, 5 Sep 2025 10:41:18 -0700 Subject: [PATCH 1014/2711] bus: mhi: host: Do not use uninitialized 'dev' pointer in mhi_init_irq_setup() In mhi_init_irq_setup, the device pointer used for dev_err() was not initialized. Use the pointer from mhi_cntrl instead. Fixes: b0fc0167f254 ("bus: mhi: core: Allow shared IRQ for event rings") Fixes: 3000f85b8f47 ("bus: mhi: core: Add support for basic PM operations") Signed-off-by: Adam Xue [mani: reworded subject/description and CCed stable] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Krishna Chaitanya Chundru Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250905174118.38512-1-zxue@semtech.com --- drivers/bus/mhi/host/init.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c index 7f72aab38ce9..099be8dd1900 100644 --- a/drivers/bus/mhi/host/init.c +++ b/drivers/bus/mhi/host/init.c @@ -194,7 +194,6 @@ static void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl) static int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl) { struct mhi_event *mhi_event = mhi_cntrl->mhi_event; - struct device *dev = &mhi_cntrl->mhi_dev->dev; unsigned long irq_flags = IRQF_SHARED | IRQF_NO_SUSPEND; int i, ret; @@ -221,7 +220,7 @@ static int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl) continue; if (mhi_event->irq >= mhi_cntrl->nr_irqs) { - dev_err(dev, "irq %d not available for event ring\n", + dev_err(mhi_cntrl->cntrl_dev, "irq %d not available for event ring\n", mhi_event->irq); ret = -EINVAL; goto error_request; @@ -232,7 +231,7 @@ static int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl) irq_flags, "mhi", mhi_event); if (ret) { - dev_err(dev, "Error requesting irq:%d for ev:%d\n", + dev_err(mhi_cntrl->cntrl_dev, "Error requesting irq:%d for ev:%d\n", mhi_cntrl->irq[mhi_event->irq], i); goto error_request; } From 53e49cbece39dec1c8668aae721a47a1155edb4a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 17 Aug 2025 14:53:13 -0700 Subject: [PATCH 1015/2711] Input: pxa27x-keypad - replace uint32_t with u32 u32 is preferred way to refer to unsigned 32 bit values in the kernel, use it instead of uint32_t. Link: https://lore.kernel.org/r/20250817215316.1872689-1-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pxa27x_keypad.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 38ec619aa359..6df69516413c 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -108,8 +108,8 @@ struct pxa27x_keypad { unsigned int row_shift; /* state row bits of each column scan */ - uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS]; - uint32_t direct_key_state; + u32 matrix_key_state[MAX_MATRIX_KEY_COLS]; + u32 direct_key_state; unsigned int direct_key_mask; }; @@ -410,8 +410,8 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; struct input_dev *input_dev = keypad->input_dev; int row, col, num_keys_pressed = 0; - uint32_t new_state[MAX_MATRIX_KEY_COLS]; - uint32_t kpas = keypad_readl(KPAS); + u32 new_state[MAX_MATRIX_KEY_COLS]; + u32 kpas = keypad_readl(KPAS); num_keys_pressed = KPAS_MUKP(kpas); @@ -434,10 +434,10 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) } if (num_keys_pressed > 1) { - uint32_t kpasmkp0 = keypad_readl(KPASMKP0); - uint32_t kpasmkp1 = keypad_readl(KPASMKP1); - uint32_t kpasmkp2 = keypad_readl(KPASMKP2); - uint32_t kpasmkp3 = keypad_readl(KPASMKP3); + u32 kpasmkp0 = keypad_readl(KPASMKP0); + u32 kpasmkp1 = keypad_readl(KPASMKP1); + u32 kpasmkp2 = keypad_readl(KPASMKP2); + u32 kpasmkp3 = keypad_readl(KPASMKP3); new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK; new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK; @@ -450,7 +450,7 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) } scan: for (col = 0; col < pdata->matrix_key_cols; col++) { - uint32_t bits_changed; + u32 bits_changed; int code; bits_changed = keypad->matrix_key_state[col] ^ new_state[col]; @@ -474,7 +474,7 @@ scan: #define DEFAULT_KPREC (0x007f007f) -static inline int rotary_delta(uint32_t kprec) +static inline int rotary_delta(u32 kprec) { if (kprec & KPREC_OF0) return (kprec & 0xff) + 0x7f; @@ -511,7 +511,7 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta) static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad) { const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - uint32_t kprec; + u32 kprec; /* read and reset to default count value */ kprec = keypad_readl(KPREC); @@ -529,7 +529,7 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; struct input_dev *input_dev = keypad->input_dev; unsigned int new_state; - uint32_t kpdk, bits_changed; + u32 kpdk, bits_changed; int i; kpdk = keypad_readl(KPDK); From 770f82c649502692c74bf13b933cbec9309091bc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 17 Aug 2025 14:53:14 -0700 Subject: [PATCH 1016/2711] Input: pxa27x-keypad - use BIT, GENMASK, FIELD_GET, etc Instead of using explicit binary values for masks and shifts to do bit operations use appropriate macros. Link: https://lore.kernel.org/r/20250817215316.1872689-2-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pxa27x_keypad.c | 110 ++++++++++++++----------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 6df69516413c..e6f6adb56de4 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -12,7 +12,8 @@ * on some suggestions by Nicolas Pitre . */ - +#include +#include #include #include #include @@ -30,62 +31,71 @@ /* * Keypad Controller registers */ -#define KPC 0x0000 /* Keypad Control register */ -#define KPDK 0x0008 /* Keypad Direct Key register */ -#define KPREC 0x0010 /* Keypad Rotary Encoder register */ -#define KPMK 0x0018 /* Keypad Matrix Key register */ -#define KPAS 0x0020 /* Keypad Automatic Scan register */ +#define KPC 0x0000 /* Keypad Control register */ +#define KPDK 0x0008 /* Keypad Direct Key register */ +#define KPREC 0x0010 /* Keypad Rotary Encoder register */ +#define KPMK 0x0018 /* Keypad Matrix Key register */ +#define KPAS 0x0020 /* Keypad Automatic Scan register */ /* Keypad Automatic Scan Multiple Key Presser register 0-3 */ -#define KPASMKP0 0x0028 -#define KPASMKP1 0x0030 -#define KPASMKP2 0x0038 -#define KPASMKP3 0x0040 -#define KPKDI 0x0048 +#define KPASMKP0 0x0028 +#define KPASMKP1 0x0030 +#define KPASMKP2 0x0038 +#define KPASMKP3 0x0040 +#define KPKDI 0x0048 /* bit definitions */ -#define KPC_MKRN(n) ((((n) - 1) & 0x7) << 26) /* matrix key row number */ -#define KPC_MKCN(n) ((((n) - 1) & 0x7) << 23) /* matrix key column number */ -#define KPC_DKN(n) ((((n) - 1) & 0x7) << 6) /* direct key number */ +#define KPC_MKRN_MASK GENMASK(28, 26) +#define KPC_MKCN_MASK GENMASK(25, 23) +#define KPC_DKN_MASK GENMASK(8, 6) +#define KPC_MKRN(n) FIELD_PREP(KPC_MKRN_MASK, (n) - 1) +#define KPC_MKCN(n) FIELD_PREP(KPC_MKCN_MASK, (n) - 1) +#define KPC_DKN(n) FIELD_PREP(KPC_DKN_MASK, (n) - 1) -#define KPC_AS (0x1 << 30) /* Automatic Scan bit */ -#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */ -#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */ -#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */ +#define KPC_AS BIT(30) /* Automatic Scan bit */ +#define KPC_ASACT BIT(29) /* Automatic Scan on Activity */ +#define KPC_MI BIT(22) /* Matrix interrupt bit */ +#define KPC_IMKP BIT(21) /* Ignore Multiple Key Press */ -#define KPC_MS(n) (0x1 << (13 + (n))) /* Matrix scan line 'n' */ -#define KPC_MS_ALL (0xff << 13) +#define KPC_MS(n) BIT(13 + (n)) /* Matrix scan line 'n' */ +#define KPC_MS_ALL GENMASK(20, 13) -#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */ -#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */ -#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */ -#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */ -#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */ -#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */ -#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */ -#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */ -#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */ +#define KPC_ME BIT(12) /* Matrix Keypad Enable */ +#define KPC_MIE BIT(11) /* Matrix Interrupt Enable */ +#define KPC_DK_DEB_SEL BIT(9) /* Direct Keypad Debounce Select */ +#define KPC_DI BIT(5) /* Direct key interrupt bit */ +#define KPC_RE_ZERO_DEB BIT(4) /* Rotary Encoder Zero Debounce */ +#define KPC_REE1 BIT(3) /* Rotary Encoder1 Enable */ +#define KPC_REE0 BIT(2) /* Rotary Encoder0 Enable */ +#define KPC_DE BIT(1) /* Direct Keypad Enable */ +#define KPC_DIE BIT(0) /* Direct Keypad interrupt Enable */ -#define KPDK_DKP (0x1 << 31) -#define KPDK_DK(n) ((n) & 0xff) +#define KPDK_DKP BIT(31) +#define KPDK_DK_MASK GENMASK(7, 0) +#define KPDK_DK(n) FIELD_GET(KPDK_DK_MASK, n) -#define KPREC_OF1 (0x1 << 31) -#define kPREC_UF1 (0x1 << 30) -#define KPREC_OF0 (0x1 << 15) -#define KPREC_UF0 (0x1 << 14) +#define KPREC_OF1 BIT(31) +#define KPREC_UF1 BIT(30) +#define KPREC_OF0 BIT(15) +#define KPREC_UF0 BIT(14) -#define KPREC_RECOUNT0(n) ((n) & 0xff) -#define KPREC_RECOUNT1(n) (((n) >> 16) & 0xff) +#define KPREC_RECOUNT0_MASK GENMASK(7, 0) +#define KPREC_RECOUNT1_MASK GENMASK(23, 16) +#define KPREC_RECOUNT0(n) FIELD_GET(KPREC_RECOUNT0_MASK, n) +#define KPREC_RECOUNT1(n) FIELD_GET(KPREC_RECOUNT1_MASK, n) -#define KPMK_MKP (0x1 << 31) -#define KPAS_SO (0x1 << 31) -#define KPASMKPx_SO (0x1 << 31) +#define KPMK_MKP BIT(31) +#define KPAS_SO BIT(31) +#define KPASMKPx_SO BIT(31) -#define KPAS_MUKP(n) (((n) >> 26) & 0x1f) -#define KPAS_RP(n) (((n) >> 4) & 0xf) -#define KPAS_CP(n) ((n) & 0xf) +#define KPAS_MUKP_MASK GENMASK(30, 26) +#define KPAS_RP_MASK GENMASK(7, 4) +#define KPAS_CP_MASK GENMASK(3, 0) +#define KPAS_MUKP(n) FIELD_GET(KPAS_MUKP_MASK, n) +#define KPAS_RP(n) FIELD_GET(KPAS_RP_MASK, n) +#define KPAS_CP(n) FIELD_GET(KPAS_CP_MASK, n) -#define KPASMKP_MKC_MASK (0xff) +#define KPASMKP_MKC_MASK GENMASK(7, 0) #define keypad_readl(off) __raw_readl(keypad->mmio_base + (off)) #define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off)) @@ -429,7 +439,7 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) row >= pdata->matrix_key_rows) goto scan; - new_state[col] = (1 << row); + new_state[col] = BIT(row); goto scan; } @@ -458,14 +468,14 @@ scan: continue; for (row = 0; row < pdata->matrix_key_rows; row++) { - if ((bits_changed & (1 << row)) == 0) + if ((bits_changed & BIT(row)) == 0) continue; code = MATRIX_SCAN_CODE(row, col, keypad->row_shift); input_event(input_dev, EV_MSC, MSC_SCAN, code); input_report_key(input_dev, keypad->keycodes[code], - new_state[col] & (1 << row)); + new_state[col] & BIT(row)); } } input_sync(input_dev); @@ -552,12 +562,12 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) return; for (i = 0; i < pdata->direct_key_num; i++) { - if (bits_changed & (1 << i)) { + if (bits_changed & BIT(i)) { int code = MAX_MATRIX_KEY_NUM + i; input_event(input_dev, EV_MSC, MSC_SCAN, code); input_report_key(input_dev, keypad->keycodes[code], - new_state & (1 << i)); + new_state & BIT(i)); } } input_sync(input_dev); @@ -627,7 +637,7 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) if (pdata->direct_key_mask) keypad->direct_key_mask = pdata->direct_key_mask; else - keypad->direct_key_mask = ((1 << direct_key_num) - 1) & ~mask; + keypad->direct_key_mask = GENMASK(direct_key_num - 1, 0) & ~mask; /* enable direct key */ if (direct_key_num) From ca734f54b346db170be20ff3382bc3da8eb65904 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 17 Aug 2025 14:53:15 -0700 Subject: [PATCH 1017/2711] Input: pxa27x-keypad - drop support for platform data There are no in-kernel users of pxa27x_keypad_platform_data in the kernel, and the driver supports configuration via device tree, so drop support of static platform data and move properties parsing from OF-specific methods to generic ones. Link: https://lore.kernel.org/r/20250817215316.1872689-3-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pxa27x_keypad.c | 374 +++++++------------- include/linux/platform_data/keypad-pxa27x.h | 73 ---- 2 files changed, 119 insertions(+), 328 deletions(-) delete mode 100644 include/linux/platform_data/keypad-pxa27x.h diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index e6f6adb56de4..4519eecb317b 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -21,13 +21,13 @@ #include #include #include +#include #include #include #include #include #include -#include /* * Keypad Controller registers */ @@ -100,54 +100,69 @@ #define keypad_readl(off) __raw_readl(keypad->mmio_base + (off)) #define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off)) +#define MAX_MATRIX_KEY_ROWS 8 +#define MAX_MATRIX_KEY_COLS 8 +#define MAX_DIRECT_KEY_NUM 8 +#define MAX_ROTARY_ENCODERS 2 + #define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS) #define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM) -struct pxa27x_keypad { - const struct pxa27x_keypad_platform_data *pdata; +struct pxa27x_keypad_rotary { + unsigned short *key_codes; + int rel_code; + bool enabled; +}; +struct pxa27x_keypad { struct clk *clk; struct input_dev *input_dev; void __iomem *mmio_base; int irq; - unsigned short keycodes[MAX_KEYPAD_KEYS]; - int rotary_rel_code[2]; - + unsigned int matrix_key_rows; + unsigned int matrix_key_cols; unsigned int row_shift; + unsigned int direct_key_num; + unsigned int direct_key_mask; + bool direct_key_low_active; + + /* key debounce interval */ + unsigned int debounce_interval; + + unsigned short keycodes[MAX_KEYPAD_KEYS]; + /* state row bits of each column scan */ u32 matrix_key_state[MAX_MATRIX_KEY_COLS]; u32 direct_key_state; - unsigned int direct_key_mask; + struct pxa27x_keypad_rotary rotary[MAX_ROTARY_ENCODERS]; }; -#ifdef CONFIG_OF -static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad, - struct pxa27x_keypad_platform_data *pdata) +static int pxa27x_keypad_matrix_key_parse(struct pxa27x_keypad *keypad) { struct input_dev *input_dev = keypad->input_dev; struct device *dev = input_dev->dev.parent; - u32 rows, cols; int error; - error = matrix_keypad_parse_properties(dev, &rows, &cols); + error = matrix_keypad_parse_properties(dev, &keypad->matrix_key_rows, + &keypad->matrix_key_cols); if (error) return error; - if (rows > MAX_MATRIX_KEY_ROWS || cols > MAX_MATRIX_KEY_COLS) { + if (keypad->matrix_key_rows > MAX_MATRIX_KEY_ROWS || + keypad->matrix_key_cols > MAX_MATRIX_KEY_COLS) { dev_err(dev, "rows or cols exceeds maximum value\n"); return -EINVAL; } - pdata->matrix_key_rows = rows; - pdata->matrix_key_cols = cols; + keypad->row_shift = get_count_order(keypad->matrix_key_cols); error = matrix_keypad_build_keymap(NULL, NULL, - pdata->matrix_key_rows, - pdata->matrix_key_cols, + keypad->matrix_key_rows, + keypad->matrix_key_cols, keypad->keycodes, input_dev); if (error) return error; @@ -155,20 +170,17 @@ static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad, return 0; } -static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad, - struct pxa27x_keypad_platform_data *pdata) +static int pxa27x_keypad_direct_key_parse(struct pxa27x_keypad *keypad) { struct input_dev *input_dev = keypad->input_dev; struct device *dev = input_dev->dev.parent; - struct device_node *np = dev->of_node; - const __be16 *prop; unsigned short code; - unsigned int proplen, size; + int count; int i; int error; - error = of_property_read_u32(np, "marvell,direct-key-count", - &pdata->direct_key_num); + error = device_property_read_u32(dev, "marvell,direct-key-count", + &keypad->direct_key_num); if (error) { /* * If do not have marvel,direct-key-count defined, @@ -177,151 +189,121 @@ static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad, return error == -EINVAL ? 0 : error; } - error = of_property_read_u32(np, "marvell,direct-key-mask", - &pdata->direct_key_mask); + error = device_property_read_u32(dev, "marvell,direct-key-mask", + &keypad->direct_key_mask); if (error) { if (error != -EINVAL) return error; /* * If marvell,direct-key-mask is not defined, driver will use - * default value. Default value is set when configure the keypad. + * a default value based on number of direct keys set up. + * The default value is calculated in pxa27x_keypad_config(). */ - pdata->direct_key_mask = 0; + keypad->direct_key_mask = 0; } - pdata->direct_key_low_active = of_property_read_bool(np, - "marvell,direct-key-low-active"); + keypad->direct_key_low_active = + device_property_read_bool(dev, "marvell,direct-key-low-active"); - prop = of_get_property(np, "marvell,direct-key-map", &proplen); - if (!prop) + count = device_property_count_u16(dev, "marvell,direct-key-map"); + if (count <= 0 || count > MAX_DIRECT_KEY_NUM) return -EINVAL; - if (proplen % sizeof(u16)) - return -EINVAL; + error = device_property_read_u16_array(dev, "marvell,direct-key-map", + &keypad->keycodes[MAX_MATRIX_KEY_NUM], + count); - size = proplen / sizeof(u16); - - /* Only MAX_DIRECT_KEY_NUM is accepted.*/ - if (size > MAX_DIRECT_KEY_NUM) - return -EINVAL; - - for (i = 0; i < size; i++) { - code = be16_to_cpup(prop + i); - keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = code; + for (i = 0; i < count; i++) { + code = keypad->keycodes[MAX_MATRIX_KEY_NUM + i]; __set_bit(code, input_dev->keybit); } return 0; } -static int pxa27x_keypad_rotary_parse_dt(struct pxa27x_keypad *keypad, - struct pxa27x_keypad_platform_data *pdata) +static int pxa27x_keypad_rotary_parse(struct pxa27x_keypad *keypad) { - const __be32 *prop; - int i, relkey_ret; - unsigned int code, proplen; - const char *rotaryname[2] = { - "marvell,rotary0", "marvell,rotary1"}; - const char relkeyname[] = {"marvell,rotary-rel-key"}; + static const char * const rotaryname[] = { "marvell,rotary0", "marvell,rotary1" }; struct input_dev *input_dev = keypad->input_dev; struct device *dev = input_dev->dev.parent; - struct device_node *np = dev->of_node; + struct pxa27x_keypad_rotary *encoder; + unsigned int code; + int i; + int error; - relkey_ret = of_property_read_u32(np, relkeyname, &code); - /* if can read correct rotary key-code, we do not need this. */ - if (relkey_ret == 0) { - unsigned short relcode; + error = device_property_read_u32(dev, "marvell,rotary-rel-key", &code); + if (!error) { + for (i = 0; i < MAX_ROTARY_ENCODERS; i++, code >>= 16) { + encoder = &keypad->rotary[i]; + encoder->enabled = true; + encoder->rel_code = code & 0xffff; + input_set_capability(input_dev, EV_REL, encoder->rel_code); + } - /* rotary0 taks lower half, rotary1 taks upper half. */ - relcode = code & 0xffff; - pdata->rotary0_rel_code = (code & 0xffff); - __set_bit(relcode, input_dev->relbit); - - relcode = code >> 16; - pdata->rotary1_rel_code = relcode; - __set_bit(relcode, input_dev->relbit); + return 0; } - for (i = 0; i < 2; i++) { - prop = of_get_property(np, rotaryname[i], &proplen); + for (i = 0; i < MAX_ROTARY_ENCODERS; i++) { + encoder = &keypad->rotary[i]; + /* * If the prop is not set, it means keypad does not need * initialize the rotaryX. */ - if (!prop) + if (!device_property_present(dev, rotaryname[i])) continue; - code = be32_to_cpup(prop); + error = device_property_read_u32(dev, rotaryname[i], &code); + if (error) + return error; + /* * Not all up/down key code are valid. * Now we depends on direct-rel-code. */ - if ((!(code & 0xffff) || !(code >> 16)) && relkey_ret) { - return relkey_ret; - } else { - unsigned int n = MAX_MATRIX_KEY_NUM + (i << 1); - unsigned short keycode; + if (!(code & 0xffff) || !(code >> 16)) + return -EINVAL; - keycode = code & 0xffff; - keypad->keycodes[n] = keycode; - __set_bit(keycode, input_dev->keybit); + encoder->enabled = true; + encoder->rel_code = -1; + encoder->key_codes = &keypad->keycodes[MAX_MATRIX_KEY_NUM + i * 2]; + encoder->key_codes[0] = code & 0xffff; + encoder->key_codes[1] = code >> 16; - keycode = code >> 16; - keypad->keycodes[n + 1] = keycode; - __set_bit(keycode, input_dev->keybit); - - if (i == 0) - pdata->rotary0_rel_code = -1; - else - pdata->rotary1_rel_code = -1; - } - if (i == 0) - pdata->enable_rotary0 = 1; - else - pdata->enable_rotary1 = 1; + input_set_capability(input_dev, EV_KEY, encoder->key_codes[0]); + input_set_capability(input_dev, EV_KEY, encoder->key_codes[1]); } - keypad->rotary_rel_code[0] = pdata->rotary0_rel_code; - keypad->rotary_rel_code[1] = pdata->rotary1_rel_code; - return 0; } -static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) +static int pxa27x_keypad_parse_properties(struct pxa27x_keypad *keypad) { struct input_dev *input_dev = keypad->input_dev; struct device *dev = input_dev->dev.parent; - struct device_node *np = dev->of_node; - struct pxa27x_keypad_platform_data *pdata; int error; - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(dev, "failed to allocate memory for pdata\n"); - return -ENOMEM; - } - - error = pxa27x_keypad_matrix_key_parse_dt(keypad, pdata); + error = pxa27x_keypad_matrix_key_parse(keypad); if (error) { dev_err(dev, "failed to parse matrix key\n"); return error; } - error = pxa27x_keypad_direct_key_parse_dt(keypad, pdata); + error = pxa27x_keypad_direct_key_parse(keypad); if (error) { dev_err(dev, "failed to parse direct key\n"); return error; } - error = pxa27x_keypad_rotary_parse_dt(keypad, pdata); + error = pxa27x_keypad_rotary_parse(keypad); if (error) { dev_err(dev, "failed to parse rotary key\n"); return error; } - error = of_property_read_u32(np, "marvell,debounce-interval", - &pdata->debounce_interval); + error = device_property_read_u32(dev, "marvell,debounce-interval", + &keypad->debounce_interval); if (error) { dev_err(dev, "failed to parse debounce-interval\n"); return error; @@ -333,91 +315,11 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) */ input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); - keypad->pdata = pdata; - return 0; -} - -#else - -static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) -{ - dev_info(keypad->input_dev->dev.parent, "missing platform data\n"); - - return -EINVAL; -} - -#endif - -static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) -{ - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - struct input_dev *input_dev = keypad->input_dev; - unsigned short keycode; - int i; - int error; - - error = matrix_keypad_build_keymap(pdata->matrix_keymap_data, NULL, - pdata->matrix_key_rows, - pdata->matrix_key_cols, - keypad->keycodes, input_dev); - if (error) - return error; - - /* - * The keycodes may not only include matrix keys but also the direct - * or rotary keys. - */ - input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); - - /* For direct keys. */ - for (i = 0; i < pdata->direct_key_num; i++) { - keycode = pdata->direct_key_map[i]; - keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode; - __set_bit(keycode, input_dev->keybit); - } - - if (pdata->enable_rotary0) { - if (pdata->rotary0_up_key && pdata->rotary0_down_key) { - keycode = pdata->rotary0_up_key; - keypad->keycodes[MAX_MATRIX_KEY_NUM + 0] = keycode; - __set_bit(keycode, input_dev->keybit); - - keycode = pdata->rotary0_down_key; - keypad->keycodes[MAX_MATRIX_KEY_NUM + 1] = keycode; - __set_bit(keycode, input_dev->keybit); - - keypad->rotary_rel_code[0] = -1; - } else { - keypad->rotary_rel_code[0] = pdata->rotary0_rel_code; - __set_bit(pdata->rotary0_rel_code, input_dev->relbit); - } - } - - if (pdata->enable_rotary1) { - if (pdata->rotary1_up_key && pdata->rotary1_down_key) { - keycode = pdata->rotary1_up_key; - keypad->keycodes[MAX_MATRIX_KEY_NUM + 2] = keycode; - __set_bit(keycode, input_dev->keybit); - - keycode = pdata->rotary1_down_key; - keypad->keycodes[MAX_MATRIX_KEY_NUM + 3] = keycode; - __set_bit(keycode, input_dev->keybit); - - keypad->rotary_rel_code[1] = -1; - } else { - keypad->rotary_rel_code[1] = pdata->rotary1_rel_code; - __set_bit(pdata->rotary1_rel_code, input_dev->relbit); - } - } - - __clear_bit(KEY_RESERVED, input_dev->keybit); - return 0; } static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) { - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; struct input_dev *input_dev = keypad->input_dev; int row, col, num_keys_pressed = 0; u32 new_state[MAX_MATRIX_KEY_COLS]; @@ -435,8 +337,8 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) row = KPAS_RP(kpas); /* if invalid row/col, treat as no key pressed */ - if (col >= pdata->matrix_key_cols || - row >= pdata->matrix_key_rows) + if (col >= keypad->matrix_key_cols || + row >= keypad->matrix_key_rows) goto scan; new_state[col] = BIT(row); @@ -459,7 +361,7 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK; } scan: - for (col = 0; col < pdata->matrix_key_cols; col++) { + for (col = 0; col < keypad->matrix_key_cols; col++) { u32 bits_changed; int code; @@ -467,7 +369,7 @@ scan: if (bits_changed == 0) continue; - for (row = 0; row < pdata->matrix_key_rows; row++) { + for (row = 0; row < keypad->matrix_key_rows; row++) { if ((bits_changed & BIT(row)) == 0) continue; @@ -496,14 +398,16 @@ static inline int rotary_delta(u32 kprec) static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta) { + struct pxa27x_keypad_rotary *encoder = &keypad->rotary[r]; struct input_dev *dev = keypad->input_dev; - if (delta == 0) + if (!encoder->enabled || delta == 0) return; - if (keypad->rotary_rel_code[r] == -1) { - int code = MAX_MATRIX_KEY_NUM + 2 * r + (delta > 0 ? 0 : 1); - unsigned char keycode = keypad->keycodes[code]; + if (encoder->rel_code == -1) { + int idx = delta > 0 ? 0 : 1; + int code = MAX_MATRIX_KEY_NUM + 2 * r + idx; + unsigned char keycode = encoder->key_codes[idx]; /* simulate a press-n-release */ input_event(dev, EV_MSC, MSC_SCAN, code); @@ -513,30 +417,28 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta) input_report_key(dev, keycode, 0); input_sync(dev); } else { - input_report_rel(dev, keypad->rotary_rel_code[r], delta); + input_report_rel(dev, encoder->rel_code, delta); input_sync(dev); } } static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad) { - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; u32 kprec; + int i; /* read and reset to default count value */ kprec = keypad_readl(KPREC); keypad_writel(KPREC, DEFAULT_KPREC); - if (pdata->enable_rotary0) + for (i = 0; i < MAX_ROTARY_ENCODERS; i++) { report_rotary_event(keypad, 0, rotary_delta(kprec)); - - if (pdata->enable_rotary1) - report_rotary_event(keypad, 1, rotary_delta(kprec >> 16)); + kprec >>= 16; + } } static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) { - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; struct input_dev *input_dev = keypad->input_dev; unsigned int new_state; u32 kpdk, bits_changed; @@ -544,14 +446,14 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) kpdk = keypad_readl(KPDK); - if (pdata->enable_rotary0 || pdata->enable_rotary1) + if (keypad->rotary[0].enabled || keypad->rotary[1].enabled) pxa27x_keypad_scan_rotary(keypad); /* * The KPDR_DK only output the key pin level, so it relates to board, * and low level may be active. */ - if (pdata->direct_key_low_active) + if (keypad->direct_key_low_active) new_state = ~KPDK_DK(kpdk) & keypad->direct_key_mask; else new_state = KPDK_DK(kpdk) & keypad->direct_key_mask; @@ -561,7 +463,7 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) if (bits_changed == 0) return; - for (i = 0; i < pdata->direct_key_num; i++) { + for (i = 0; i < keypad->direct_key_num; i++) { if (bits_changed & BIT(i)) { int code = MAX_MATRIX_KEY_NUM + i; @@ -574,21 +476,11 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) keypad->direct_key_state = new_state; } -static void clear_wakeup_event(struct pxa27x_keypad *keypad) -{ - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - - if (pdata->clear_wakeup_event) - (pdata->clear_wakeup_event)(); -} - static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) { struct pxa27x_keypad *keypad = dev_id; unsigned long kpc = keypad_readl(KPC); - clear_wakeup_event(keypad); - if (kpc & KPC_DI) pxa27x_keypad_scan_direct(keypad); @@ -600,7 +492,6 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) { - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; unsigned int mask = 0, direct_key_num = 0; unsigned long kpc = 0; @@ -608,35 +499,33 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) keypad_readl(KPC); /* enable matrix keys with automatic scan */ - if (pdata->matrix_key_rows && pdata->matrix_key_cols) { + if (keypad->matrix_key_rows && keypad->matrix_key_cols) { kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL; - kpc |= KPC_MKRN(pdata->matrix_key_rows) | - KPC_MKCN(pdata->matrix_key_cols); + kpc |= KPC_MKRN(keypad->matrix_key_rows) | + KPC_MKCN(keypad->matrix_key_cols); } /* enable rotary key, debounce interval same as direct keys */ - if (pdata->enable_rotary0) { + if (keypad->rotary[0].enabled) { mask |= 0x03; direct_key_num = 2; kpc |= KPC_REE0; } - if (pdata->enable_rotary1) { + if (keypad->rotary[1].enabled) { mask |= 0x0c; direct_key_num = 4; kpc |= KPC_REE1; } - if (pdata->direct_key_num > direct_key_num) - direct_key_num = pdata->direct_key_num; + if (keypad->direct_key_num > direct_key_num) + direct_key_num = keypad->direct_key_num; /* * Direct keys usage may not start from KP_DKIN0, check the platfrom * mask data to config the specific. */ - if (pdata->direct_key_mask) - keypad->direct_key_mask = pdata->direct_key_mask; - else + if (!keypad->direct_key_mask) keypad->direct_key_mask = GENMASK(direct_key_num - 1, 0) & ~mask; /* enable direct key */ @@ -645,7 +534,7 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) keypad_writel(KPC, kpc | KPC_RE_ZERO_DEB); keypad_writel(KPREC, DEFAULT_KPREC); - keypad_writel(KPKDI, pdata->debounce_interval); + keypad_writel(KPKDI, keypad->debounce_interval); } static int pxa27x_keypad_open(struct input_dev *dev) @@ -719,19 +608,12 @@ static int pxa27x_keypad_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(pxa27x_keypad_pm_ops, pxa27x_keypad_suspend, pxa27x_keypad_resume); - static int pxa27x_keypad_probe(struct platform_device *pdev) { - const struct pxa27x_keypad_platform_data *pdata = - dev_get_platdata(&pdev->dev); - struct device_node *np = pdev->dev.of_node; struct pxa27x_keypad *keypad; struct input_dev *input_dev; - int irq, error; - - /* Driver need build keycode from device tree or pdata */ - if (!np && !pdata) - return -EINVAL; + int irq; + int error; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -746,7 +628,6 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) if (!input_dev) return -ENOMEM; - keypad->pdata = pdata; keypad->input_dev = input_dev; keypad->irq = irq; @@ -775,29 +656,12 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); input_set_capability(input_dev, EV_MSC, MSC_SCAN); - if (pdata) { - error = pxa27x_keypad_build_keycode(keypad); - } else { - error = pxa27x_keypad_build_keycode_from_dt(keypad); - /* - * Data that we get from DT resides in dynamically - * allocated memory so we need to update our pdata - * pointer. - */ - pdata = keypad->pdata; - } + error = pxa27x_keypad_parse_properties(keypad); if (error) { - dev_err(&pdev->dev, "failed to build keycode\n"); + dev_err(&pdev->dev, "failed to parse keypad properties\n"); return error; } - keypad->row_shift = get_count_order(pdata->matrix_key_cols); - - if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) || - (pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) { - input_dev->evbit[0] |= BIT_MASK(EV_REL); - } - error = devm_request_irq(&pdev->dev, irq, pxa27x_keypad_irq_handler, 0, pdev->name, keypad); if (error) { diff --git a/include/linux/platform_data/keypad-pxa27x.h b/include/linux/platform_data/keypad-pxa27x.h deleted file mode 100644 index a376442b9935..000000000000 --- a/include/linux/platform_data/keypad-pxa27x.h +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_ARCH_PXA27x_KEYPAD_H -#define __ASM_ARCH_PXA27x_KEYPAD_H - -#include -#include - -#define MAX_MATRIX_KEY_ROWS (8) -#define MAX_MATRIX_KEY_COLS (8) -#define MATRIX_ROW_SHIFT (3) -#define MAX_DIRECT_KEY_NUM (8) - -/* pxa3xx keypad platform specific parameters - * - * NOTE: - * 1. direct_key_num indicates the number of keys in the direct keypad - * _plus_ the number of rotary-encoder sensor inputs, this can be - * left as 0 if only rotary encoders are enabled, the driver will - * automatically calculate this - * - * 2. direct_key_map is the key code map for the direct keys, if rotary - * encoder(s) are enabled, direct key 0/1(2/3) will be ignored - * - * 3. rotary can be either interpreted as a relative input event (e.g. - * REL_WHEEL/REL_HWHEEL) or specific keys (e.g. UP/DOWN/LEFT/RIGHT) - * - * 4. matrix key and direct key will use the same debounce_interval by - * default, which should be sufficient in most cases - * - * pxa168 keypad platform specific parameter - * - * NOTE: - * clear_wakeup_event callback is a workaround required to clear the - * keypad interrupt. The keypad wake must be cleared in addition to - * reading the MI/DI bits in the KPC register. - */ -struct pxa27x_keypad_platform_data { - - /* code map for the matrix keys */ - const struct matrix_keymap_data *matrix_keymap_data; - unsigned int matrix_key_rows; - unsigned int matrix_key_cols; - - /* direct keys */ - int direct_key_num; - unsigned int direct_key_map[MAX_DIRECT_KEY_NUM]; - /* the key output may be low active */ - int direct_key_low_active; - /* give board a chance to choose the start direct key */ - unsigned int direct_key_mask; - - /* rotary encoders 0 */ - int enable_rotary0; - int rotary0_rel_code; - int rotary0_up_key; - int rotary0_down_key; - - /* rotary encoders 1 */ - int enable_rotary1; - int rotary1_rel_code; - int rotary1_up_key; - int rotary1_down_key; - - /* key debounce interval */ - unsigned int debounce_interval; - - /* clear wakeup event requirement for pxa168 */ - void (*clear_wakeup_event)(void); -}; - -extern void pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info); - -#endif /* __ASM_ARCH_PXA27x_KEYPAD_H */ From 890ba82a60cb7a6584968a4ac15546f434afa40b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 17 Aug 2025 14:39:06 -0700 Subject: [PATCH 1018/2711] Input: spear-keyboard - drop support for platform data There are no in-kernel users of spear kbd_platform_data in the kernel, and the driver supports configuration via device tree, so drop support of static platform data and move properties parsing from OF-specific methods to generic ones. Link: https://lore.kernel.org/r/vppjxui76im26uamznx7evm5lmbe3d6v3oxsa7mqyytykh4zm6@nhlf33v3hp6g Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/spear-keyboard.c | 71 ++------ include/linux/platform_data/keyboard-spear.h | 164 ------------------- 2 files changed, 15 insertions(+), 220 deletions(-) delete mode 100644 include/linux/platform_data/keyboard-spear.h diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index 2fae337562a2..53f3ac64c980 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -22,7 +23,6 @@ #include #include #include -#include /* Keyboard Registers */ #define MODE_CTL_REG 0x00 @@ -56,13 +56,12 @@ struct spear_kbd { void __iomem *io_base; struct clk *clk; unsigned int irq; - unsigned int mode; - unsigned int suspended_rate; + u32 mode; + u32 suspended_rate; + u32 mode_ctl_reg; unsigned short last_key; unsigned short keycodes[NUM_ROWS * NUM_COLS]; - bool rep; bool irq_wake_enabled; - u32 mode_ctl_reg; }; static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) @@ -143,46 +142,8 @@ static void spear_kbd_close(struct input_dev *dev) kbd->last_key = KEY_RESERVED; } -#ifdef CONFIG_OF -static int spear_kbd_parse_dt(struct platform_device *pdev, - struct spear_kbd *kbd) -{ - struct device_node *np = pdev->dev.of_node; - int error; - u32 val, suspended_rate; - - if (!np) { - dev_err(&pdev->dev, "Missing DT data\n"); - return -EINVAL; - } - - if (of_property_read_bool(np, "autorepeat")) - kbd->rep = true; - - if (of_property_read_u32(np, "suspended_rate", &suspended_rate)) - kbd->suspended_rate = suspended_rate; - - error = of_property_read_u32(np, "st,mode", &val); - if (error) { - dev_err(&pdev->dev, "DT: Invalid or missing mode\n"); - return error; - } - - kbd->mode = val; - return 0; -} -#else -static inline int spear_kbd_parse_dt(struct platform_device *pdev, - struct spear_kbd *kbd) -{ - return -ENOSYS; -} -#endif - static int spear_kbd_probe(struct platform_device *pdev) { - struct kbd_platform_data *pdata = dev_get_platdata(&pdev->dev); - const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL; struct spear_kbd *kbd; struct input_dev *input_dev; int irq; @@ -198,6 +159,14 @@ static int spear_kbd_probe(struct platform_device *pdev) return -ENOMEM; } + error = device_property_read_u32(&pdev->dev, "st,mode", &kbd->mode); + if (error) { + dev_err(&pdev->dev, "Invalid or missing mode\n"); + return error; + } + + device_property_read_u32(&pdev->dev, "suspended_rate", &kbd->suspended_rate); + input_dev = devm_input_allocate_device(&pdev->dev); if (!input_dev) { dev_err(&pdev->dev, "unable to allocate input device\n"); @@ -207,16 +176,6 @@ static int spear_kbd_probe(struct platform_device *pdev) kbd->input = input_dev; kbd->irq = irq; - if (!pdata) { - error = spear_kbd_parse_dt(pdev, kbd); - if (error) - return error; - } else { - kbd->mode = pdata->mode; - kbd->rep = pdata->rep; - kbd->suspended_rate = pdata->suspended_rate; - } - kbd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(kbd->io_base)) return PTR_ERR(kbd->io_base); @@ -234,21 +193,21 @@ static int spear_kbd_probe(struct platform_device *pdev) input_dev->open = spear_kbd_open; input_dev->close = spear_kbd_close; - error = matrix_keypad_build_keymap(keymap, NULL, NUM_ROWS, NUM_COLS, + error = matrix_keypad_build_keymap(NULL, NULL, NUM_ROWS, NUM_COLS, kbd->keycodes, input_dev); if (error) { dev_err(&pdev->dev, "Failed to build keymap\n"); return error; } - if (kbd->rep) + if (device_property_read_bool(&pdev->dev, "autorepeat")) __set_bit(EV_REP, input_dev->evbit); input_set_capability(input_dev, EV_MSC, MSC_SCAN); input_set_drvdata(input_dev, kbd); error = devm_request_irq(&pdev->dev, irq, spear_kbd_interrupt, 0, - "keyboard", kbd); + "keyboard", kbd); if (error) { dev_err(&pdev->dev, "request_irq failed\n"); return error; diff --git a/include/linux/platform_data/keyboard-spear.h b/include/linux/platform_data/keyboard-spear.h deleted file mode 100644 index 5e3ff653900c..000000000000 --- a/include/linux/platform_data/keyboard-spear.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2010 ST Microelectronics - * Rajeev Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __PLAT_KEYBOARD_H -#define __PLAT_KEYBOARD_H - -#include -#include -#include -#include - -#define DECLARE_9x9_KEYMAP(_name) \ -int _name[] = { \ - KEY(0, 0, KEY_ESC), \ - KEY(0, 1, KEY_1), \ - KEY(0, 2, KEY_2), \ - KEY(0, 3, KEY_3), \ - KEY(0, 4, KEY_4), \ - KEY(0, 5, KEY_5), \ - KEY(0, 6, KEY_6), \ - KEY(0, 7, KEY_7), \ - KEY(0, 8, KEY_8), \ - KEY(1, 0, KEY_9), \ - KEY(1, 1, KEY_MINUS), \ - KEY(1, 2, KEY_EQUAL), \ - KEY(1, 3, KEY_BACKSPACE), \ - KEY(1, 4, KEY_TAB), \ - KEY(1, 5, KEY_Q), \ - KEY(1, 6, KEY_W), \ - KEY(1, 7, KEY_E), \ - KEY(1, 8, KEY_R), \ - KEY(2, 0, KEY_T), \ - KEY(2, 1, KEY_Y), \ - KEY(2, 2, KEY_U), \ - KEY(2, 3, KEY_I), \ - KEY(2, 4, KEY_O), \ - KEY(2, 5, KEY_P), \ - KEY(2, 6, KEY_LEFTBRACE), \ - KEY(2, 7, KEY_RIGHTBRACE), \ - KEY(2, 8, KEY_ENTER), \ - KEY(3, 0, KEY_LEFTCTRL), \ - KEY(3, 1, KEY_A), \ - KEY(3, 2, KEY_S), \ - KEY(3, 3, KEY_D), \ - KEY(3, 4, KEY_F), \ - KEY(3, 5, KEY_G), \ - KEY(3, 6, KEY_H), \ - KEY(3, 7, KEY_J), \ - KEY(3, 8, KEY_K), \ - KEY(4, 0, KEY_L), \ - KEY(4, 1, KEY_SEMICOLON), \ - KEY(4, 2, KEY_APOSTROPHE), \ - KEY(4, 3, KEY_GRAVE), \ - KEY(4, 4, KEY_LEFTSHIFT), \ - KEY(4, 5, KEY_BACKSLASH), \ - KEY(4, 6, KEY_Z), \ - KEY(4, 7, KEY_X), \ - KEY(4, 8, KEY_C), \ - KEY(5, 0, KEY_V), \ - KEY(5, 1, KEY_B), \ - KEY(5, 2, KEY_N), \ - KEY(5, 3, KEY_M), \ - KEY(5, 4, KEY_COMMA), \ - KEY(5, 5, KEY_DOT), \ - KEY(5, 6, KEY_SLASH), \ - KEY(5, 7, KEY_RIGHTSHIFT), \ - KEY(5, 8, KEY_KPASTERISK), \ - KEY(6, 0, KEY_LEFTALT), \ - KEY(6, 1, KEY_SPACE), \ - KEY(6, 2, KEY_CAPSLOCK), \ - KEY(6, 3, KEY_F1), \ - KEY(6, 4, KEY_F2), \ - KEY(6, 5, KEY_F3), \ - KEY(6, 6, KEY_F4), \ - KEY(6, 7, KEY_F5), \ - KEY(6, 8, KEY_F6), \ - KEY(7, 0, KEY_F7), \ - KEY(7, 1, KEY_F8), \ - KEY(7, 2, KEY_F9), \ - KEY(7, 3, KEY_F10), \ - KEY(7, 4, KEY_NUMLOCK), \ - KEY(7, 5, KEY_SCROLLLOCK), \ - KEY(7, 6, KEY_KP7), \ - KEY(7, 7, KEY_KP8), \ - KEY(7, 8, KEY_KP9), \ - KEY(8, 0, KEY_KPMINUS), \ - KEY(8, 1, KEY_KP4), \ - KEY(8, 2, KEY_KP5), \ - KEY(8, 3, KEY_KP6), \ - KEY(8, 4, KEY_KPPLUS), \ - KEY(8, 5, KEY_KP1), \ - KEY(8, 6, KEY_KP2), \ - KEY(8, 7, KEY_KP3), \ - KEY(8, 8, KEY_KP0), \ -} - -#define DECLARE_6x6_KEYMAP(_name) \ -int _name[] = { \ - KEY(0, 0, KEY_RESERVED), \ - KEY(0, 1, KEY_1), \ - KEY(0, 2, KEY_2), \ - KEY(0, 3, KEY_3), \ - KEY(0, 4, KEY_4), \ - KEY(0, 5, KEY_5), \ - KEY(1, 0, KEY_Q), \ - KEY(1, 1, KEY_W), \ - KEY(1, 2, KEY_E), \ - KEY(1, 3, KEY_R), \ - KEY(1, 4, KEY_T), \ - KEY(1, 5, KEY_Y), \ - KEY(2, 0, KEY_D), \ - KEY(2, 1, KEY_F), \ - KEY(2, 2, KEY_G), \ - KEY(2, 3, KEY_H), \ - KEY(2, 4, KEY_J), \ - KEY(2, 5, KEY_K), \ - KEY(3, 0, KEY_B), \ - KEY(3, 1, KEY_N), \ - KEY(3, 2, KEY_M), \ - KEY(3, 3, KEY_COMMA), \ - KEY(3, 4, KEY_DOT), \ - KEY(3, 5, KEY_SLASH), \ - KEY(4, 0, KEY_F6), \ - KEY(4, 1, KEY_F7), \ - KEY(4, 2, KEY_F8), \ - KEY(4, 3, KEY_F9), \ - KEY(4, 4, KEY_F10), \ - KEY(4, 5, KEY_NUMLOCK), \ - KEY(5, 0, KEY_KP2), \ - KEY(5, 1, KEY_KP3), \ - KEY(5, 2, KEY_KP0), \ - KEY(5, 3, KEY_KPDOT), \ - KEY(5, 4, KEY_RO), \ - KEY(5, 5, KEY_ZENKAKUHANKAKU), \ -} - -#define KEYPAD_9x9 0 -#define KEYPAD_6x6 1 -#define KEYPAD_2x2 2 - -/** - * struct kbd_platform_data - spear keyboard platform data - * keymap: pointer to keymap data (table and size) - * rep: enables key autorepeat - * mode: choose keyboard support(9x9, 6x6, 2x2) - * suspended_rate: rate at which keyboard would operate in suspended mode - * - * This structure is supposed to be used by platform code to supply - * keymaps to drivers that implement keyboards. - */ -struct kbd_platform_data { - const struct matrix_keymap_data *keymap; - bool rep; - unsigned int mode; - unsigned int suspended_rate; -}; - -#endif /* __PLAT_KEYBOARD_H */ From c6c973dbfa5e34b1572bcd1852adcad1b5d08fab Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Sun, 7 Sep 2025 20:33:38 +0200 Subject: [PATCH 1019/2711] x86/asm: Remove code depending on __GCC_ASM_FLAG_OUTPUTS__ The minimum supported GCC version is 8.1, which supports flag output operands and always defines __GCC_ASM_FLAG_OUTPUTS__ macro. Remove code depending on __GCC_ASM_FLAG_OUTPUTS__ and use the "=@ccCOND" flag output operand directly. Use the equivalent "=@ccz" instead of "=@cce" flag output operand for CMPXCHG8B and CMPXCHG16B instructions. These instructions set a single flag bit - the Zero flag - and "=@ccz" is used to distinguish the CC user from comparison instructions, where set ZERO flag indeed means that the values are equal. Signed-off-by: Uros Bizjak Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20250905121723.GCaLrU04lP2A50PT-B@fat_crate.local --- arch/x86/boot/bitops.h | 2 +- arch/x86/boot/boot.h | 8 ++++---- arch/x86/boot/string.c | 4 ++-- arch/x86/include/asm/archrandom.h | 6 ++---- arch/x86/include/asm/asm.h | 12 ------------ arch/x86/include/asm/bitops.h | 18 ++++++------------ arch/x86/include/asm/cmpxchg.h | 12 ++++-------- arch/x86/include/asm/cmpxchg_32.h | 6 ++---- arch/x86/include/asm/cmpxchg_64.h | 3 +-- arch/x86/include/asm/percpu.h | 12 ++++-------- arch/x86/include/asm/rmwcc.h | 26 ++------------------------ arch/x86/include/asm/sev.h | 3 +-- arch/x86/include/asm/signal.h | 3 +-- arch/x86/include/asm/special_insns.h | 3 +-- arch/x86/include/asm/uaccess.h | 7 +++---- tools/arch/x86/include/asm/asm.h | 12 ------------ tools/perf/bench/find-bit-bench.c | 2 +- 17 files changed, 35 insertions(+), 104 deletions(-) diff --git a/arch/x86/boot/bitops.h b/arch/x86/boot/bitops.h index 8518ae214c9b..79e15971529d 100644 --- a/arch/x86/boot/bitops.h +++ b/arch/x86/boot/bitops.h @@ -27,7 +27,7 @@ static inline bool variable_test_bit(int nr, const void *addr) bool v; const u32 *p = addr; - asm("btl %2,%1" CC_SET(c) : CC_OUT(c) (v) : "m" (*p), "Ir" (nr)); + asm("btl %2,%1" : "=@ccc" (v) : "m" (*p), "Ir" (nr)); return v; } diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 60580836daf7..a3c58ebe3662 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -155,15 +155,15 @@ static inline void wrgs32(u32 v, addr_t addr) static inline bool memcmp_fs(const void *s1, addr_t s2, size_t len) { bool diff; - asm volatile("fs repe cmpsb" CC_SET(nz) - : CC_OUT(nz) (diff), "+D" (s1), "+S" (s2), "+c" (len)); + asm volatile("fs repe cmpsb" + : "=@ccnz" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; } static inline bool memcmp_gs(const void *s1, addr_t s2, size_t len) { bool diff; - asm volatile("gs repe cmpsb" CC_SET(nz) - : CC_OUT(nz) (diff), "+D" (s1), "+S" (s2), "+c" (len)); + asm volatile("gs repe cmpsb" + : "=@ccnz" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; } diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c index f35369bb14c5..b25c6a9303b7 100644 --- a/arch/x86/boot/string.c +++ b/arch/x86/boot/string.c @@ -32,8 +32,8 @@ int memcmp(const void *s1, const void *s2, size_t len) { bool diff; - asm("repe cmpsb" CC_SET(nz) - : CC_OUT(nz) (diff), "+D" (s1), "+S" (s2), "+c" (len)); + asm("repe cmpsb" + : "=@ccnz" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; } diff --git a/arch/x86/include/asm/archrandom.h b/arch/x86/include/asm/archrandom.h index 02bae8e0758b..4c305305871b 100644 --- a/arch/x86/include/asm/archrandom.h +++ b/arch/x86/include/asm/archrandom.h @@ -23,8 +23,7 @@ static inline bool __must_check rdrand_long(unsigned long *v) unsigned int retry = RDRAND_RETRY_LOOPS; do { asm volatile("rdrand %[out]" - CC_SET(c) - : CC_OUT(c) (ok), [out] "=r" (*v)); + : "=@ccc" (ok), [out] "=r" (*v)); if (ok) return true; } while (--retry); @@ -35,8 +34,7 @@ static inline bool __must_check rdseed_long(unsigned long *v) { bool ok; asm volatile("rdseed %[out]" - CC_SET(c) - : CC_OUT(c) (ok), [out] "=r" (*v)); + : "=@ccc" (ok), [out] "=r" (*v)); return ok; } diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index f963848024a5..d5c8d3afe196 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -122,18 +122,6 @@ static __always_inline __pure void *rip_rel_ptr(void *p) } #endif -/* - * Macros to generate condition code outputs from inline assembly, - * The output operand must be type "bool". - */ -#ifdef __GCC_ASM_FLAG_OUTPUTS__ -# define CC_SET(c) "\n\t/* output condition code " #c "*/\n" -# define CC_OUT(c) "=@cc" #c -#else -# define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n" -# define CC_OUT(c) [_cc_ ## c] "=qm" -#endif - #ifdef __KERNEL__ # include diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index eebbc8889e70..33153dcd119c 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -99,8 +99,7 @@ static __always_inline bool arch_xor_unlock_is_negative_byte(unsigned long mask, { bool negative; asm_inline volatile(LOCK_PREFIX "xorb %2,%1" - CC_SET(s) - : CC_OUT(s) (negative), WBYTE_ADDR(addr) + : "=@ccs" (negative), WBYTE_ADDR(addr) : "iq" ((char)mask) : "memory"); return negative; } @@ -149,8 +148,7 @@ arch___test_and_set_bit(unsigned long nr, volatile unsigned long *addr) bool oldbit; asm(__ASM_SIZE(bts) " %2,%1" - CC_SET(c) - : CC_OUT(c) (oldbit) + : "=@ccc" (oldbit) : ADDR, "Ir" (nr) : "memory"); return oldbit; } @@ -175,8 +173,7 @@ arch___test_and_clear_bit(unsigned long nr, volatile unsigned long *addr) bool oldbit; asm volatile(__ASM_SIZE(btr) " %2,%1" - CC_SET(c) - : CC_OUT(c) (oldbit) + : "=@ccc" (oldbit) : ADDR, "Ir" (nr) : "memory"); return oldbit; } @@ -187,8 +184,7 @@ arch___test_and_change_bit(unsigned long nr, volatile unsigned long *addr) bool oldbit; asm volatile(__ASM_SIZE(btc) " %2,%1" - CC_SET(c) - : CC_OUT(c) (oldbit) + : "=@ccc" (oldbit) : ADDR, "Ir" (nr) : "memory"); return oldbit; @@ -211,8 +207,7 @@ static __always_inline bool constant_test_bit_acquire(long nr, const volatile un bool oldbit; asm volatile("testb %2,%1" - CC_SET(nz) - : CC_OUT(nz) (oldbit) + : "=@ccnz" (oldbit) : "m" (((unsigned char *)addr)[nr >> 3]), "i" (1 << (nr & 7)) :"memory"); @@ -225,8 +220,7 @@ static __always_inline bool variable_test_bit(long nr, volatile const unsigned l bool oldbit; asm volatile(__ASM_SIZE(bt) " %2,%1" - CC_SET(c) - : CC_OUT(c) (oldbit) + : "=@ccc" (oldbit) : "m" (*(unsigned long *)addr), "Ir" (nr) : "memory"); return oldbit; diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h index b61f32c3459f..a88b06f1c35e 100644 --- a/arch/x86/include/asm/cmpxchg.h +++ b/arch/x86/include/asm/cmpxchg.h @@ -166,8 +166,7 @@ extern void __add_wrong_size(void) { \ volatile u8 *__ptr = (volatile u8 *)(_ptr); \ asm_inline volatile(lock "cmpxchgb %[new], %[ptr]" \ - CC_SET(z) \ - : CC_OUT(z) (success), \ + : "=@ccz" (success), \ [ptr] "+m" (*__ptr), \ [old] "+a" (__old) \ : [new] "q" (__new) \ @@ -178,8 +177,7 @@ extern void __add_wrong_size(void) { \ volatile u16 *__ptr = (volatile u16 *)(_ptr); \ asm_inline volatile(lock "cmpxchgw %[new], %[ptr]" \ - CC_SET(z) \ - : CC_OUT(z) (success), \ + : "=@ccz" (success), \ [ptr] "+m" (*__ptr), \ [old] "+a" (__old) \ : [new] "r" (__new) \ @@ -190,8 +188,7 @@ extern void __add_wrong_size(void) { \ volatile u32 *__ptr = (volatile u32 *)(_ptr); \ asm_inline volatile(lock "cmpxchgl %[new], %[ptr]" \ - CC_SET(z) \ - : CC_OUT(z) (success), \ + : "=@ccz" (success), \ [ptr] "+m" (*__ptr), \ [old] "+a" (__old) \ : [new] "r" (__new) \ @@ -202,8 +199,7 @@ extern void __add_wrong_size(void) { \ volatile u64 *__ptr = (volatile u64 *)(_ptr); \ asm_inline volatile(lock "cmpxchgq %[new], %[ptr]" \ - CC_SET(z) \ - : CC_OUT(z) (success), \ + : "=@ccz" (success), \ [ptr] "+m" (*__ptr), \ [old] "+a" (__old) \ : [new] "r" (__new) \ diff --git a/arch/x86/include/asm/cmpxchg_32.h b/arch/x86/include/asm/cmpxchg_32.h index 371f7906019e..1f80a62be969 100644 --- a/arch/x86/include/asm/cmpxchg_32.h +++ b/arch/x86/include/asm/cmpxchg_32.h @@ -46,8 +46,7 @@ static __always_inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new bool ret; \ \ asm_inline volatile(_lock "cmpxchg8b %[ptr]" \ - CC_SET(e) \ - : CC_OUT(e) (ret), \ + : "=@ccz" (ret), \ [ptr] "+m" (*(_ptr)), \ "+a" (o.low), "+d" (o.high) \ : "b" (n.low), "c" (n.high) \ @@ -125,8 +124,7 @@ static __always_inline u64 arch_cmpxchg64_local(volatile u64 *ptr, u64 old, u64 ALTERNATIVE(_lock_loc \ "call cmpxchg8b_emu", \ _lock "cmpxchg8b %a[ptr]", X86_FEATURE_CX8) \ - CC_SET(e) \ - : ALT_OUTPUT_SP(CC_OUT(e) (ret), \ + : ALT_OUTPUT_SP("=@ccz" (ret), \ "+a" (o.low), "+d" (o.high)) \ : "b" (n.low), "c" (n.high), \ [ptr] "S" (_ptr) \ diff --git a/arch/x86/include/asm/cmpxchg_64.h b/arch/x86/include/asm/cmpxchg_64.h index 71d1e72ed879..5afea056fb20 100644 --- a/arch/x86/include/asm/cmpxchg_64.h +++ b/arch/x86/include/asm/cmpxchg_64.h @@ -66,8 +66,7 @@ static __always_inline u128 arch_cmpxchg128_local(volatile u128 *ptr, u128 old, bool ret; \ \ asm_inline volatile(_lock "cmpxchg16b %[ptr]" \ - CC_SET(e) \ - : CC_OUT(e) (ret), \ + : "=@ccz" (ret), \ [ptr] "+m" (*(_ptr)), \ "+a" (o.low), "+d" (o.high) \ : "b" (n.low), "c" (n.high) \ diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index b0d03b6c279b..332428caaed2 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -309,8 +309,7 @@ do { \ \ asm qual (__pcpu_op_##size("cmpxchg") "%[nval], " \ __percpu_arg([var]) \ - CC_SET(z) \ - : CC_OUT(z) (success), \ + : "=@ccz" (success), \ [oval] "+a" (pco_old__), \ [var] "+m" (__my_cpu_var(_var)) \ : [nval] __pcpu_reg_##size(, pco_new__) \ @@ -367,8 +366,7 @@ do { \ asm_inline qual ( \ ALTERNATIVE("call this_cpu_cmpxchg8b_emu", \ "cmpxchg8b " __percpu_arg([var]), X86_FEATURE_CX8) \ - CC_SET(z) \ - : ALT_OUTPUT_SP(CC_OUT(z) (success), \ + : ALT_OUTPUT_SP("=@ccz" (success), \ [var] "+m" (__my_cpu_var(_var)), \ "+a" (old__.low), "+d" (old__.high)) \ : "b" (new__.low), "c" (new__.high), \ @@ -436,8 +434,7 @@ do { \ asm_inline qual ( \ ALTERNATIVE("call this_cpu_cmpxchg16b_emu", \ "cmpxchg16b " __percpu_arg([var]), X86_FEATURE_CX16) \ - CC_SET(z) \ - : ALT_OUTPUT_SP(CC_OUT(z) (success), \ + : ALT_OUTPUT_SP("=@ccz" (success), \ [var] "+m" (__my_cpu_var(_var)), \ "+a" (old__.low), "+d" (old__.high)) \ : "b" (new__.low), "c" (new__.high), \ @@ -585,8 +582,7 @@ do { \ bool oldbit; \ \ asm volatile("btl %[nr], " __percpu_arg([var]) \ - CC_SET(c) \ - : CC_OUT(c) (oldbit) \ + : "=@ccc" (oldbit) \ : [var] "m" (__my_cpu_var(_var)), \ [nr] "rI" (_nr)); \ oldbit; \ diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h index 3821ee3fae35..54c8fc430684 100644 --- a/arch/x86/include/asm/rmwcc.h +++ b/arch/x86/include/asm/rmwcc.h @@ -6,37 +6,15 @@ #define __CLOBBERS_MEM(clb...) "memory", ## clb -#ifndef __GCC_ASM_FLAG_OUTPUTS__ - -/* Use asm goto */ - -#define __GEN_RMWcc(fullop, _var, cc, clobbers, ...) \ -({ \ - bool c = false; \ - asm goto (fullop "; j" #cc " %l[cc_label]" \ - : : [var] "m" (_var), ## __VA_ARGS__ \ - : clobbers : cc_label); \ - if (0) { \ -cc_label: c = true; \ - } \ - c; \ -}) - -#else /* defined(__GCC_ASM_FLAG_OUTPUTS__) */ - -/* Use flags output or a set instruction */ - #define __GEN_RMWcc(fullop, _var, cc, clobbers, ...) \ ({ \ bool c; \ - asm_inline volatile (fullop CC_SET(cc) \ - : [var] "+m" (_var), CC_OUT(cc) (c) \ + asm_inline volatile (fullop \ + : [var] "+m" (_var), "=@cc" #cc (c) \ : __VA_ARGS__ : clobbers); \ c; \ }) -#endif /* defined(__GCC_ASM_FLAG_OUTPUTS__) */ - #define GEN_UNARY_RMWcc_4(op, var, cc, arg0) \ __GEN_RMWcc(op " " arg0, var, cc, __CLOBBERS_MEM()) diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h index 02236962fdb1..7cb8e09e749b 100644 --- a/arch/x86/include/asm/sev.h +++ b/arch/x86/include/asm/sev.h @@ -491,8 +491,7 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) /* "pvalidate" mnemonic support in binutils 2.36 and newer */ asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t" - CC_SET(c) - : CC_OUT(c) (no_rmpupdate), "=a"(rc) + : "=@ccc"(no_rmpupdate), "=a"(rc) : "a"(vaddr), "c"(rmp_psize), "d"(validate) : "memory", "cc"); diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h index c72d46175374..5c03aaa89014 100644 --- a/arch/x86/include/asm/signal.h +++ b/arch/x86/include/asm/signal.h @@ -83,8 +83,7 @@ static inline int __const_sigismember(sigset_t *set, int _sig) static inline int __gen_sigismember(sigset_t *set, int _sig) { bool ret; - asm("btl %2,%1" CC_SET(c) - : CC_OUT(c) (ret) : "m"(*set), "Ir"(_sig-1)); + asm("btl %2,%1" : "=@ccc"(ret) : "m"(*set), "Ir"(_sig-1)); return ret; } diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h index c99914569352..46aa2c9c1bda 100644 --- a/arch/x86/include/asm/special_insns.h +++ b/arch/x86/include/asm/special_insns.h @@ -284,8 +284,7 @@ static inline int enqcmds(void __iomem *dst, const void *src) * See movdir64b()'s comment on operand specification. */ asm volatile(".byte 0xf3, 0x0f, 0x38, 0xf8, 0x02, 0x66, 0x90" - CC_SET(z) - : CC_OUT(z) (zf), "+m" (*__dst) + : "=@ccz" (zf), "+m" (*__dst) : "m" (*__src), "a" (__dst), "d" (__src)); /* Submission failure is indicated via EFLAGS.ZF=1 */ diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 3a7755c1a441..91a3fb8ae7ff 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -378,7 +378,7 @@ do { \ asm_goto_output("\n" \ "1: " LOCK_PREFIX "cmpxchg"itype" %[new], %[ptr]\n"\ _ASM_EXTABLE_UA(1b, %l[label]) \ - : CC_OUT(z) (success), \ + : "=@ccz" (success), \ [ptr] "+m" (*_ptr), \ [old] "+a" (__old) \ : [new] ltype (__new) \ @@ -397,7 +397,7 @@ do { \ asm_goto_output("\n" \ "1: " LOCK_PREFIX "cmpxchg8b %[ptr]\n" \ _ASM_EXTABLE_UA(1b, %l[label]) \ - : CC_OUT(z) (success), \ + : "=@ccz" (success), \ "+A" (__old), \ [ptr] "+m" (*_ptr) \ : "b" ((u32)__new), \ @@ -417,11 +417,10 @@ do { \ __typeof__(*(_ptr)) __new = (_new); \ asm volatile("\n" \ "1: " LOCK_PREFIX "cmpxchg"itype" %[new], %[ptr]\n"\ - CC_SET(z) \ "2:\n" \ _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, \ %[errout]) \ - : CC_OUT(z) (success), \ + : "=@ccz" (success), \ [errout] "+r" (__err), \ [ptr] "+m" (*_ptr), \ [old] "+a" (__old) \ diff --git a/tools/arch/x86/include/asm/asm.h b/tools/arch/x86/include/asm/asm.h index dbe39b44256b..6e1b357c374b 100644 --- a/tools/arch/x86/include/asm/asm.h +++ b/tools/arch/x86/include/asm/asm.h @@ -108,18 +108,6 @@ #endif -/* - * Macros to generate condition code outputs from inline assembly, - * The output operand must be type "bool". - */ -#ifdef __GCC_ASM_FLAG_OUTPUTS__ -# define CC_SET(c) "\n\t/* output condition code " #c "*/\n" -# define CC_OUT(c) "=@cc" #c -#else -# define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n" -# define CC_OUT(c) [_cc_ ## c] "=qm" -#endif - #ifdef __KERNEL__ /* Exception table entry */ diff --git a/tools/perf/bench/find-bit-bench.c b/tools/perf/bench/find-bit-bench.c index 7e25b0e413f6..e697c20951bc 100644 --- a/tools/perf/bench/find-bit-bench.c +++ b/tools/perf/bench/find-bit-bench.c @@ -37,7 +37,7 @@ static noinline void workload(int val) accumulator++; } -#if (defined(__i386__) || defined(__x86_64__)) && defined(__GCC_ASM_FLAG_OUTPUTS__) +#if defined(__i386__) || defined(__x86_64__) static bool asm_test_bit(long nr, const unsigned long *addr) { bool oldbit; From 8742bebb846009af7a22e489fe99aced5e195b51 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 6 Sep 2025 09:17:58 -0700 Subject: [PATCH 1020/2711] Input: synaptics-rmi4 - add includes for types used in rmi_2d_sensor.h Headers should include definitions for types that they use. Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_2d_sensor.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h index 7d335d809710..61a99c8a7a26 100644 --- a/drivers/input/rmi4/rmi_2d_sensor.h +++ b/drivers/input/rmi4/rmi_2d_sensor.h @@ -7,6 +7,9 @@ #ifndef _RMI_2D_SENSOR_H #define _RMI_2D_SENSOR_H +#include +#include + enum rmi_2d_sensor_object_type { RMI_2D_OBJECT_NONE, RMI_2D_OBJECT_FINGER, From 0879768df24027dad5810cb81a4c73d8ed070a25 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 28 Aug 2025 20:38:20 -0400 Subject: [PATCH 1021/2711] clk: nxp: lpc32xx: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Note that the changes involving LPC32XX_DEFINE_PLL_OPS were done by hand. Signed-off-by: Brian Masney --- drivers/clk/nxp/clk-lpc32xx.c | 59 ++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index e00f270bc6aa..09ac025e06d4 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -579,17 +579,17 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, return regmap_update_bits(clk_regmap, clk->reg, 0x1FFFF, val); } -static long clk_hclk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_hclk_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw); - u64 m_i, o = rate, i = *parent_rate, d = (u64)rate << 6; + u64 m_i, o = req->rate, i = req->best_parent_rate, d = (u64)req->rate << 6; u64 m = 0, n = 0, p = 0; int p_i, n_i; - pr_debug("%s: %lu/%lu\n", clk_hw_get_name(hw), *parent_rate, rate); + pr_debug("%s: %lu/%lu\n", clk_hw_get_name(hw), req->best_parent_rate, req->rate); - if (rate > 266500000) + if (req->rate > 266500000) return -EINVAL; /* Have to check all 20 possibilities to find the minimal M */ @@ -614,9 +614,9 @@ static long clk_hclk_pll_round_rate(struct clk_hw *hw, unsigned long rate, } } - if (d == (u64)rate << 6) { + if (d == (u64)req->rate << 6) { pr_err("%s: %lu: no valid PLL parameters are found\n", - clk_hw_get_name(hw), rate); + clk_hw_get_name(hw), req->rate); return -EINVAL; } @@ -634,22 +634,25 @@ static long clk_hclk_pll_round_rate(struct clk_hw *hw, unsigned long rate, if (!d) pr_debug("%s: %lu: found exact match: %llu/%llu/%llu\n", - clk_hw_get_name(hw), rate, m, n, p); + clk_hw_get_name(hw), req->rate, m, n, p); else pr_debug("%s: %lu: found closest: %llu/%llu/%llu - %llu\n", - clk_hw_get_name(hw), rate, m, n, p, o); + clk_hw_get_name(hw), req->rate, m, n, p, o); - return o; + req->rate = o; + + return 0; } -static long clk_usb_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_usb_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw); struct clk_hw *usb_div_hw, *osc_hw; u64 d_i, n_i, m, o; - pr_debug("%s: %lu/%lu\n", clk_hw_get_name(hw), *parent_rate, rate); + pr_debug("%s: %lu/%lu\n", clk_hw_get_name(hw), req->best_parent_rate, + req->rate); /* * The only supported USB clock is 48MHz, with PLL internal constraints @@ -657,7 +660,7 @@ static long clk_usb_pll_round_rate(struct clk_hw *hw, unsigned long rate, * and post-divider must be 4, this slightly simplifies calculation of * USB divider, USB PLL N and M parameters. */ - if (rate != 48000000) + if (req->rate != 48000000) return -EINVAL; /* USB divider clock */ @@ -685,30 +688,30 @@ static long clk_usb_pll_round_rate(struct clk_hw *hw, unsigned long rate, clk->m_div = m; clk->p_div = 2; clk->mode = PLL_NON_INTEGER; - *parent_rate = div64_u64(o, d_i); + req->best_parent_rate = div64_u64(o, d_i); - return rate; + return 0; } } return -EINVAL; } -#define LPC32XX_DEFINE_PLL_OPS(_name, _rc, _sr, _rr) \ +#define LPC32XX_DEFINE_PLL_OPS(_name, _rc, _sr, _dr) \ static const struct clk_ops clk_ ##_name ## _ops = { \ .enable = clk_pll_enable, \ .disable = clk_pll_disable, \ .is_enabled = clk_pll_is_enabled, \ .recalc_rate = _rc, \ .set_rate = _sr, \ - .round_rate = _rr, \ + .determine_rate = _dr, \ } LPC32XX_DEFINE_PLL_OPS(pll_397x, clk_pll_397x_recalc_rate, NULL, NULL); LPC32XX_DEFINE_PLL_OPS(hclk_pll, clk_pll_recalc_rate, - clk_pll_set_rate, clk_hclk_pll_round_rate); + clk_pll_set_rate, clk_hclk_pll_determine_rate); LPC32XX_DEFINE_PLL_OPS(usb_pll, clk_pll_recalc_rate, - clk_pll_set_rate, clk_usb_pll_round_rate); + clk_pll_set_rate, clk_usb_pll_determine_rate); static int clk_ddram_is_enabled(struct clk_hw *hw) { @@ -955,8 +958,8 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, divider->flags, divider->width); } -static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct lpc32xx_clk_div *divider = to_lpc32xx_div(hw); unsigned int bestdiv; @@ -968,11 +971,15 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, bestdiv &= div_mask(divider->width); bestdiv = _get_div(divider->table, bestdiv, divider->flags, divider->width); - return DIV_ROUND_UP(*prate, bestdiv); + req->rate = DIV_ROUND_UP(req->best_parent_rate, bestdiv); + + return 0; } - return divider_round_rate(hw, rate, prate, divider->table, - divider->width, divider->flags); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + divider->table, divider->width, divider->flags); + + return 0; } static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, @@ -991,7 +998,7 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops lpc32xx_clk_divider_ops = { .recalc_rate = clk_divider_recalc_rate, - .round_rate = clk_divider_round_rate, + .determine_rate = clk_divider_determine_rate, .set_rate = clk_divider_set_rate, }; From e20c5abec9e3f37f52d97fd962007e0346850f65 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 28 Aug 2025 20:38:22 -0400 Subject: [PATCH 1022/2711] clk: rockchip: half-divider: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/rockchip/clk-half-divider.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/rockchip/clk-half-divider.c b/drivers/clk/rockchip/clk-half-divider.c index 64f7faad2148..fbc018e8afa4 100644 --- a/drivers/clk/rockchip/clk-half-divider.c +++ b/drivers/clk/rockchip/clk-half-divider.c @@ -92,17 +92,19 @@ static int clk_half_divider_bestdiv(struct clk_hw *hw, unsigned long rate, return bestdiv; } -static long clk_half_divider_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_half_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_divider *divider = to_clk_divider(hw); int div; - div = clk_half_divider_bestdiv(hw, rate, prate, + div = clk_half_divider_bestdiv(hw, req->rate, &req->best_parent_rate, divider->width, divider->flags); - return DIV_ROUND_UP_ULL(((u64)*prate * 2), div * 2 + 3); + req->rate = DIV_ROUND_UP_ULL(((u64)req->best_parent_rate * 2), div * 2 + 3); + + return 0; } static int clk_half_divider_set_rate(struct clk_hw *hw, unsigned long rate, @@ -141,7 +143,7 @@ static int clk_half_divider_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops clk_half_divider_ops = { .recalc_rate = clk_half_divider_recalc_rate, - .round_rate = clk_half_divider_round_rate, + .determine_rate = clk_half_divider_determine_rate, .set_rate = clk_half_divider_set_rate, }; From 9a3b6993613d3fac3b29e44688b865972ff732fd Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 28 Aug 2025 20:38:24 -0400 Subject: [PATCH 1023/2711] clk: sophgo: sg2042-clkgen: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Chen Wang Tested-by: Chen Wang # Pioneerbox Signed-off-by: Brian Masney --- drivers/clk/sophgo/clk-sg2042-clkgen.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/clk/sophgo/clk-sg2042-clkgen.c b/drivers/clk/sophgo/clk-sg2042-clkgen.c index 9e61288d34f3..683661b71787 100644 --- a/drivers/clk/sophgo/clk-sg2042-clkgen.c +++ b/drivers/clk/sophgo/clk-sg2042-clkgen.c @@ -176,9 +176,8 @@ static unsigned long sg2042_clk_divider_recalc_rate(struct clk_hw *hw, return ret_rate; } -static long sg2042_clk_divider_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *prate) +static int sg2042_clk_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw); unsigned long ret_rate; @@ -192,15 +191,17 @@ static long sg2042_clk_divider_round_rate(struct clk_hw *hw, bestdiv = readl(divider->reg) >> divider->shift; bestdiv &= clk_div_mask(divider->width); } - ret_rate = DIV_ROUND_UP_ULL((u64)*prate, bestdiv); + ret_rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, bestdiv); } else { - ret_rate = divider_round_rate(hw, rate, prate, NULL, + ret_rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, NULL, divider->width, divider->div_flags); } pr_debug("--> %s: divider_round_rate: val = %ld\n", clk_hw_get_name(hw), ret_rate); - return ret_rate; + req->rate = ret_rate; + + return 0; } static int sg2042_clk_divider_set_rate(struct clk_hw *hw, @@ -258,13 +259,13 @@ static int sg2042_clk_divider_set_rate(struct clk_hw *hw, static const struct clk_ops sg2042_clk_divider_ops = { .recalc_rate = sg2042_clk_divider_recalc_rate, - .round_rate = sg2042_clk_divider_round_rate, + .determine_rate = sg2042_clk_divider_determine_rate, .set_rate = sg2042_clk_divider_set_rate, }; static const struct clk_ops sg2042_clk_divider_ro_ops = { .recalc_rate = sg2042_clk_divider_recalc_rate, - .round_rate = sg2042_clk_divider_round_rate, + .determine_rate = sg2042_clk_divider_determine_rate, }; /* From d4c515a21b238844cfc3108405bbb0f210cf6d3b Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 28 Aug 2025 20:38:25 -0400 Subject: [PATCH 1024/2711] clk: sophgo: sg2042-pll: remove round_rate() in favor of determine_rate() This driver implements both the determine_rate() and round_rate() clk ops, and the round_rate() clk ops is deprecated. When both are defined, clk_core_determine_round_nolock() from the clk core will only use the determine_rate() clk ops, so let's remove the round_rate() clk ops since it's unused. The implementation of sg2042_clk_pll_determine_rate() calls sg2042_clk_pll_round_rate(), so this folds the two into a single function. Reviewed-by: Chen Wang Tested-by: Chen Wang # Pioneerbox Signed-off-by: Brian Masney --- drivers/clk/sophgo/clk-sg2042-pll.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/clk/sophgo/clk-sg2042-pll.c b/drivers/clk/sophgo/clk-sg2042-pll.c index e5fb0bb7ac4f..110b6ee06fe4 100644 --- a/drivers/clk/sophgo/clk-sg2042-pll.c +++ b/drivers/clk/sophgo/clk-sg2042-pll.c @@ -346,37 +346,30 @@ static unsigned long sg2042_clk_pll_recalc_rate(struct clk_hw *hw, return rate; } -static long sg2042_clk_pll_round_rate(struct clk_hw *hw, - unsigned long req_rate, - unsigned long *prate) +static int sg2042_clk_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct sg2042_pll_ctrl pctrl_table; unsigned int value; long proper_rate; int ret; - ret = sg2042_get_pll_ctl_setting(&pctrl_table, req_rate, *prate); + ret = sg2042_get_pll_ctl_setting(&pctrl_table, + min(req->rate, req->max_rate), + req->best_parent_rate); if (ret) { proper_rate = 0; goto out; } value = sg2042_pll_ctrl_encode(&pctrl_table); - proper_rate = (long)sg2042_pll_recalc_rate(value, *prate); + proper_rate = (long)sg2042_pll_recalc_rate(value, req->best_parent_rate); out: - pr_debug("--> %s: pll_round_rate: val = %ld\n", - clk_hw_get_name(hw), proper_rate); - return proper_rate; -} - -static int sg2042_clk_pll_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - req->rate = sg2042_clk_pll_round_rate(hw, min(req->rate, req->max_rate), - &req->best_parent_rate); pr_debug("--> %s: pll_determine_rate: val = %ld\n", - clk_hw_get_name(hw), req->rate); + clk_hw_get_name(hw), proper_rate); + req->rate = proper_rate; + return 0; } @@ -417,14 +410,13 @@ out: static const struct clk_ops sg2042_clk_pll_ops = { .recalc_rate = sg2042_clk_pll_recalc_rate, - .round_rate = sg2042_clk_pll_round_rate, .determine_rate = sg2042_clk_pll_determine_rate, .set_rate = sg2042_clk_pll_set_rate, }; static const struct clk_ops sg2042_clk_pll_ro_ops = { .recalc_rate = sg2042_clk_pll_recalc_rate, - .round_rate = sg2042_clk_pll_round_rate, + .determine_rate = sg2042_clk_pll_determine_rate, }; /* From f7a6bed91a19304465f318fd05b2e04670584580 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 28 Aug 2025 20:38:26 -0400 Subject: [PATCH 1025/2711] clk: x86: cgu: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/x86/clk-cgu.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/clk/x86/clk-cgu.c b/drivers/clk/x86/clk-cgu.c index 89b53f280aee..d099667355f8 100644 --- a/drivers/clk/x86/clk-cgu.c +++ b/drivers/clk/x86/clk-cgu.c @@ -132,14 +132,15 @@ lgm_clk_divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) divider->flags, divider->width); } -static long -lgm_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int lgm_clk_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct lgm_clk_divider *divider = to_lgm_clk_divider(hw); - return divider_round_rate(hw, rate, prate, divider->table, - divider->width, divider->flags); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, divider->table, + divider->width, divider->flags); + + return 0; } static int @@ -182,7 +183,7 @@ static void lgm_clk_divider_disable(struct clk_hw *hw) static const struct clk_ops lgm_clk_divider_ops = { .recalc_rate = lgm_clk_divider_recalc_rate, - .round_rate = lgm_clk_divider_round_rate, + .determine_rate = lgm_clk_divider_determine_rate, .set_rate = lgm_clk_divider_set_rate, .enable = lgm_clk_divider_enable, .disable = lgm_clk_divider_disable, @@ -487,15 +488,14 @@ lgm_clk_ddiv_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static long -lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int lgm_clk_ddiv_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw); u32 div, ddiv1, ddiv2; u64 rate64; - div = DIV_ROUND_CLOSEST_ULL((u64)*prate, rate); + div = DIV_ROUND_CLOSEST_ULL((u64)req->best_parent_rate, req->rate); /* if predivide bit is enabled, modify div by factor of 2.5 */ if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) { @@ -503,14 +503,17 @@ lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate, div = DIV_ROUND_CLOSEST_ULL((u64)div, 5); } - if (div <= 0) - return *prate; + if (div <= 0) { + req->rate = req->best_parent_rate; + + return 0; + } if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2) != 0) if (lgm_clk_get_ddiv_val(div + 1, &ddiv1, &ddiv2) != 0) return -EINVAL; - rate64 = *prate; + rate64 = req->best_parent_rate; do_div(rate64, ddiv1); do_div(rate64, ddiv2); @@ -520,7 +523,9 @@ lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate, rate64 = DIV_ROUND_CLOSEST_ULL(rate64, 5); } - return rate64; + req->rate = rate64; + + return 0; } static const struct clk_ops lgm_clk_ddiv_ops = { @@ -528,7 +533,7 @@ static const struct clk_ops lgm_clk_ddiv_ops = { .enable = lgm_clk_ddiv_enable, .disable = lgm_clk_ddiv_disable, .set_rate = lgm_clk_ddiv_set_rate, - .round_rate = lgm_clk_ddiv_round_rate, + .determine_rate = lgm_clk_ddiv_determine_rate, }; int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx, From 0f9cf96a01fd8cb690292a5c24fbfda5c6dd47b2 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 28 Aug 2025 20:38:27 -0400 Subject: [PATCH 1026/2711] clk: zynqmp: divider: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/zynqmp/divider.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c index 5a00487ae408..c824eeacd8eb 100644 --- a/drivers/clk/zynqmp/divider.c +++ b/drivers/clk/zynqmp/divider.c @@ -118,9 +118,8 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, * * Return: 0 on success else error+reason */ -static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *prate) +static int zynqmp_clk_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw); const char *clk_name = clk_hw_get_name(hw); @@ -145,17 +144,21 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) bestdiv = 1 << bestdiv; - return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); + req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, bestdiv); + + return 0; } width = fls(divider->max_div); - rate = divider_round_rate(hw, rate, prate, NULL, width, divider->flags); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + NULL, width, divider->flags); - if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && (rate % *prate)) - *prate = rate; + if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && + (req->rate % req->best_parent_rate)) + req->best_parent_rate = req->rate; - return rate; + return 0; } /** @@ -199,13 +202,13 @@ static int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops zynqmp_clk_divider_ops = { .recalc_rate = zynqmp_clk_divider_recalc_rate, - .round_rate = zynqmp_clk_divider_round_rate, + .determine_rate = zynqmp_clk_divider_determine_rate, .set_rate = zynqmp_clk_divider_set_rate, }; static const struct clk_ops zynqmp_clk_divider_ro_ops = { .recalc_rate = zynqmp_clk_divider_recalc_rate, - .round_rate = zynqmp_clk_divider_round_rate, + .determine_rate = zynqmp_clk_divider_determine_rate, }; /** From 47b13635dabc14f1c2fdcaa5468b47ddadbdd1b5 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:17:53 -0400 Subject: [PATCH 1027/2711] clk: at91: peripheral: fix return value determine_rate() is expected to return an error code, or 0 on success. clk_sam9x5_peripheral_determine_rate() has a branch that returns the parent rate on a certain case. This is the behavior of round_rate(), so let's go ahead and fix this by setting req->rate. Fixes: b4c115c76184f ("clk: at91: clk-peripheral: add support for changeable parent rate") Reviewed-by: Alexander Sverdlin Acked-by: Nicolas Ferre Signed-off-by: Brian Masney --- drivers/clk/at91/clk-peripheral.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c index c173a44c800a..629f050a855a 100644 --- a/drivers/clk/at91/clk-peripheral.c +++ b/drivers/clk/at91/clk-peripheral.c @@ -279,8 +279,11 @@ static int clk_sam9x5_peripheral_determine_rate(struct clk_hw *hw, long best_diff = LONG_MIN; u32 shift; - if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) - return parent_rate; + if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) { + req->rate = parent_rate; + + return 0; + } /* Fist step: check the available dividers. */ for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) { From 9236145ffba286e819a37ce84c3b084127dfa208 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:17:54 -0400 Subject: [PATCH 1028/2711] clk: at91: peripheral: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. This driver already has a clk_sam9x5_peripheral_determine_rate() implementation, however it can change the parent rate. The existing round rate does not have this functionality. I could add a check for CLK_SET_RATE_PARENT, and combine the two functions, however there are some other minor differences in the two implementations. I don't have access to this particular hardware. I believe that they could be combined, however it would need to be tested on real hardware. So, let's play it safe and convert the existing round rate implementation to ensure that the driver keeps the same functionality as before. Reviewed-by: Alexander Sverdlin Signed-off-by: Brian Masney --- drivers/clk/at91/clk-peripheral.c | 41 ++++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c index 629f050a855a..e700f40fd87f 100644 --- a/drivers/clk/at91/clk-peripheral.c +++ b/drivers/clk/at91/clk-peripheral.c @@ -335,50 +335,57 @@ end: return 0; } -static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *parent_rate) +static int clk_sam9x5_peripheral_no_parent_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int shift = 0; unsigned long best_rate; unsigned long best_diff; - unsigned long cur_rate = *parent_rate; + unsigned long cur_rate = req->best_parent_rate; unsigned long cur_diff; struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); - if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) - return *parent_rate; + if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) { + req->rate = req->best_parent_rate; + + return 0; + } if (periph->range.max) { for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) { - cur_rate = *parent_rate >> shift; + cur_rate = req->best_parent_rate >> shift; if (cur_rate <= periph->range.max) break; } } - if (rate >= cur_rate) - return cur_rate; + if (req->rate >= cur_rate) { + req->rate = cur_rate; - best_diff = cur_rate - rate; + return 0; + } + + best_diff = cur_rate - req->rate; best_rate = cur_rate; for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) { - cur_rate = *parent_rate >> shift; - if (cur_rate < rate) - cur_diff = rate - cur_rate; + cur_rate = req->best_parent_rate >> shift; + if (cur_rate < req->rate) + cur_diff = req->rate - cur_rate; else - cur_diff = cur_rate - rate; + cur_diff = cur_rate - req->rate; if (cur_diff < best_diff) { best_diff = cur_diff; best_rate = cur_rate; } - if (!best_diff || cur_rate < rate) + if (!best_diff || cur_rate < req->rate) break; } - return best_rate; + req->rate = best_rate; + + return 0; } static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw, @@ -430,7 +437,7 @@ static const struct clk_ops sam9x5_peripheral_ops = { .disable = clk_sam9x5_peripheral_disable, .is_enabled = clk_sam9x5_peripheral_is_enabled, .recalc_rate = clk_sam9x5_peripheral_recalc_rate, - .round_rate = clk_sam9x5_peripheral_round_rate, + .determine_rate = clk_sam9x5_peripheral_no_parent_determine_rate, .set_rate = clk_sam9x5_peripheral_set_rate, .save_context = clk_sam9x5_peripheral_save_context, .restore_context = clk_sam9x5_peripheral_restore_context, From 582de809b052892e1338508374f562e823b29566 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:17:55 -0400 Subject: [PATCH 1029/2711] clk: fixed-factor: add determine_rate() ops The round_rate() clk ops is deprecated, and determine_rate() should be used instead. We can't just simply convert this driver over initially since other drivers depend on this. So let's go ahead and add a determine_rate() clk ops. Once all of the drivers have been converted, then the round_rate() clk ops can be dropped. Signed-off-by: Brian Masney --- drivers/clk/clk-fixed-factor.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index e62ae8794d44..79b9a8c57d4b 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -30,6 +30,23 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, return (unsigned long)rate; } +static int clk_factor_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); + + if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { + unsigned long best_parent; + + best_parent = (req->rate / fix->mult) * fix->div; + req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); + } + + req->rate = (req->best_parent_rate / fix->div) * fix->mult; + + return 0; +} + static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { @@ -50,7 +67,7 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate, { /* * We must report success but we can do so unconditionally because - * clk_factor_round_rate returns values that ensure this call is a + * clk_factor_determine_rate returns values that ensure this call is a * nop. */ @@ -69,6 +86,7 @@ static unsigned long clk_factor_recalc_accuracy(struct clk_hw *hw, } const struct clk_ops clk_fixed_factor_ops = { + .determine_rate = clk_factor_determine_rate, .round_rate = clk_factor_round_rate, .set_rate = clk_factor_set_rate, .recalc_rate = clk_factor_recalc_rate, From ae139c6addbe71ce2459a377c7695494311ef62d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:17:56 -0400 Subject: [PATCH 1030/2711] clk: at91: audio-pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/at91/clk-audio-pll.c | 42 +++++++++++++++++--------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/clk/at91/clk-audio-pll.c b/drivers/clk/at91/clk-audio-pll.c index a92da64c12e1..bf9b635ac9d6 100644 --- a/drivers/clk/at91/clk-audio-pll.c +++ b/drivers/clk/at91/clk-audio-pll.c @@ -270,8 +270,8 @@ static int clk_audio_pll_frac_determine_rate(struct clk_hw *hw, return 0; } -static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_audio_pll_pad_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_hw *pclk = clk_hw_get_parent(hw); long best_rate = -EINVAL; @@ -283,7 +283,7 @@ static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate, int best_diff = -1; pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__, - rate, *parent_rate); + req->rate, req->best_parent_rate); /* * Rate divisor is actually made of two different divisors, multiplied @@ -304,12 +304,12 @@ static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate, continue; best_parent_rate = clk_hw_round_rate(pclk, - rate * tmp_qd * div); + req->rate * tmp_qd * div); tmp_rate = best_parent_rate / (div * tmp_qd); - tmp_diff = abs(rate - tmp_rate); + tmp_diff = abs(req->rate - tmp_rate); if (best_diff < 0 || best_diff > tmp_diff) { - *parent_rate = best_parent_rate; + req->best_parent_rate = best_parent_rate; best_rate = tmp_rate; best_diff = tmp_diff; } @@ -318,11 +318,13 @@ static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate, pr_debug("A PLL/PAD: %s, best_rate = %ld, best_parent_rate = %lu\n", __func__, best_rate, best_parent_rate); - return best_rate; + req->rate = best_rate; + + return 0; } -static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_audio_pll_pmc_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_hw *pclk = clk_hw_get_parent(hw); long best_rate = -EINVAL; @@ -333,20 +335,20 @@ static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate, int best_diff = -1; pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__, - rate, *parent_rate); + req->rate, req->best_parent_rate); - if (!rate) + if (!req->rate) return 0; best_parent_rate = clk_round_rate(pclk->clk, 1); - div = max(best_parent_rate / rate, 1UL); + div = max(best_parent_rate / req->rate, 1UL); for (; div <= AUDIO_PLL_QDPMC_MAX; div++) { - best_parent_rate = clk_round_rate(pclk->clk, rate * div); + best_parent_rate = clk_round_rate(pclk->clk, req->rate * div); tmp_rate = best_parent_rate / div; - tmp_diff = abs(rate - tmp_rate); + tmp_diff = abs(req->rate - tmp_rate); if (best_diff < 0 || best_diff > tmp_diff) { - *parent_rate = best_parent_rate; + req->best_parent_rate = best_parent_rate; best_rate = tmp_rate; best_diff = tmp_diff; tmp_qd = div; @@ -356,9 +358,11 @@ static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate, } pr_debug("A PLL/PMC: %s, best_rate = %ld, best_parent_rate = %lu (qd = %d)\n", - __func__, best_rate, *parent_rate, tmp_qd - 1); + __func__, best_rate, req->best_parent_rate, tmp_qd - 1); - return best_rate; + req->rate = best_rate; + + return 0; } static int clk_audio_pll_frac_set_rate(struct clk_hw *hw, unsigned long rate, @@ -436,7 +440,7 @@ static const struct clk_ops audio_pll_pad_ops = { .enable = clk_audio_pll_pad_enable, .disable = clk_audio_pll_pad_disable, .recalc_rate = clk_audio_pll_pad_recalc_rate, - .round_rate = clk_audio_pll_pad_round_rate, + .determine_rate = clk_audio_pll_pad_determine_rate, .set_rate = clk_audio_pll_pad_set_rate, }; @@ -444,7 +448,7 @@ static const struct clk_ops audio_pll_pmc_ops = { .enable = clk_audio_pll_pmc_enable, .disable = clk_audio_pll_pmc_disable, .recalc_rate = clk_audio_pll_pmc_recalc_rate, - .round_rate = clk_audio_pll_pmc_round_rate, + .determine_rate = clk_audio_pll_pmc_determine_rate, .set_rate = clk_audio_pll_pmc_set_rate, }; From 1ddde15e99a2033c8e21a9ab34a72f166c4bd385 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:17:57 -0400 Subject: [PATCH 1031/2711] clk: at91: h32mx: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/at91/clk-h32mx.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c index 1e6c12eeda10..a9aa93b5a870 100644 --- a/drivers/clk/at91/clk-h32mx.c +++ b/drivers/clk/at91/clk-h32mx.c @@ -40,21 +40,32 @@ static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw, return parent_rate; } -static long clk_sama5d4_h32mx_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_sama5d4_h32mx_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned long div; - if (rate > *parent_rate) - return *parent_rate; - div = *parent_rate / 2; - if (rate < div) - return div; + if (req->rate > req->best_parent_rate) { + req->rate = req->best_parent_rate; - if (rate - div < *parent_rate - rate) - return div; + return 0; + } + div = req->best_parent_rate / 2; + if (req->rate < div) { + req->rate = div; - return *parent_rate; + return 0; + } + + if (req->rate - div < req->best_parent_rate - req->rate) { + req->rate = div; + + return 0; + } + + req->rate = req->best_parent_rate; + + return 0; } static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate, @@ -77,7 +88,7 @@ static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops h32mx_ops = { .recalc_rate = clk_sama5d4_h32mx_recalc_rate, - .round_rate = clk_sama5d4_h32mx_round_rate, + .determine_rate = clk_sama5d4_h32mx_determine_rate, .set_rate = clk_sama5d4_h32mx_set_rate, }; From a635d6b4c7a89b49085016239a483f3cb26de330 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:17:58 -0400 Subject: [PATCH 1032/2711] clk: at91: pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/at91/clk-pll.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c index 249d6a53cedf..5c5f7398effe 100644 --- a/drivers/clk/at91/clk-pll.c +++ b/drivers/clk/at91/clk-pll.c @@ -231,13 +231,15 @@ static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, return bestrate; } -static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_pll *pll = to_clk_pll(hw); - return clk_pll_get_best_div_mul(pll, rate, *parent_rate, - NULL, NULL, NULL); + req->rate = clk_pll_get_best_div_mul(pll, req->rate, req->best_parent_rate, + NULL, NULL, NULL); + + return 0; } static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -302,7 +304,7 @@ static const struct clk_ops pll_ops = { .unprepare = clk_pll_unprepare, .is_prepared = clk_pll_is_prepared, .recalc_rate = clk_pll_recalc_rate, - .round_rate = clk_pll_round_rate, + .determine_rate = clk_pll_determine_rate, .set_rate = clk_pll_set_rate, .save_context = clk_pll_save_context, .restore_context = clk_pll_restore_context, From 3c117b696a8a9733fe9b8affc5a13536c60ff730 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:17:59 -0400 Subject: [PATCH 1033/2711] clk: at91: plldiv: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/at91/clk-plldiv.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c index ba3a1839a96d..3ac09fecc54e 100644 --- a/drivers/clk/at91/clk-plldiv.c +++ b/drivers/clk/at91/clk-plldiv.c @@ -33,21 +33,33 @@ static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw, return parent_rate; } -static long clk_plldiv_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_plldiv_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned long div; - if (rate > *parent_rate) - return *parent_rate; - div = *parent_rate / 2; - if (rate < div) - return div; + if (req->rate > req->best_parent_rate) { + req->rate = req->best_parent_rate; - if (rate - div < *parent_rate - rate) - return div; + return 0; + } - return *parent_rate; + div = req->best_parent_rate / 2; + if (req->rate < div) { + req->rate = div; + + return 0; + } + + if (req->rate - div < req->best_parent_rate - req->rate) { + req->rate = div; + + return 0; + } + + req->rate = req->best_parent_rate; + + return 0; } static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate, @@ -66,7 +78,7 @@ static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops plldiv_ops = { .recalc_rate = clk_plldiv_recalc_rate, - .round_rate = clk_plldiv_round_rate, + .determine_rate = clk_plldiv_determine_rate, .set_rate = clk_plldiv_set_rate, }; From fcf97201711822d90cea8132ca631e267f5d8c1f Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:00 -0400 Subject: [PATCH 1034/2711] clk: at91: sam9x60-pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/at91/clk-sam9x60-pll.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c index cefd9948e103..bc1498c5704a 100644 --- a/drivers/clk/at91/clk-sam9x60-pll.c +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -230,12 +230,16 @@ static long sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core *core, return tmprate; } -static long sam9x60_frac_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int sam9x60_frac_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); - return sam9x60_frac_pll_compute_mul_frac(core, rate, *parent_rate, false); + req->rate = sam9x60_frac_pll_compute_mul_frac(core, req->rate, + req->best_parent_rate, + false); + + return 0; } static int sam9x60_frac_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -321,7 +325,7 @@ static const struct clk_ops sam9x60_frac_pll_ops = { .unprepare = sam9x60_frac_pll_unprepare, .is_prepared = sam9x60_frac_pll_is_prepared, .recalc_rate = sam9x60_frac_pll_recalc_rate, - .round_rate = sam9x60_frac_pll_round_rate, + .determine_rate = sam9x60_frac_pll_determine_rate, .set_rate = sam9x60_frac_pll_set_rate, .save_context = sam9x60_frac_pll_save_context, .restore_context = sam9x60_frac_pll_restore_context, @@ -332,7 +336,7 @@ static const struct clk_ops sam9x60_frac_pll_ops_chg = { .unprepare = sam9x60_frac_pll_unprepare, .is_prepared = sam9x60_frac_pll_is_prepared, .recalc_rate = sam9x60_frac_pll_recalc_rate, - .round_rate = sam9x60_frac_pll_round_rate, + .determine_rate = sam9x60_frac_pll_determine_rate, .set_rate = sam9x60_frac_pll_set_rate_chg, .save_context = sam9x60_frac_pll_save_context, .restore_context = sam9x60_frac_pll_restore_context, @@ -487,12 +491,15 @@ static long sam9x60_div_pll_compute_div(struct sam9x60_pll_core *core, return best_rate; } -static long sam9x60_div_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int sam9x60_div_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); - return sam9x60_div_pll_compute_div(core, parent_rate, rate); + req->rate = sam9x60_div_pll_compute_div(core, &req->best_parent_rate, + req->rate); + + return 0; } static int sam9x60_div_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -601,7 +608,7 @@ static const struct clk_ops sam9x60_div_pll_ops = { .unprepare = sam9x60_div_pll_unprepare, .is_prepared = sam9x60_div_pll_is_prepared, .recalc_rate = sam9x60_div_pll_recalc_rate, - .round_rate = sam9x60_div_pll_round_rate, + .determine_rate = sam9x60_div_pll_determine_rate, .set_rate = sam9x60_div_pll_set_rate, .save_context = sam9x60_div_pll_save_context, .restore_context = sam9x60_div_pll_restore_context, @@ -612,7 +619,7 @@ static const struct clk_ops sam9x60_div_pll_ops_chg = { .unprepare = sam9x60_div_pll_unprepare, .is_prepared = sam9x60_div_pll_is_prepared, .recalc_rate = sam9x60_div_pll_recalc_rate, - .round_rate = sam9x60_div_pll_round_rate, + .determine_rate = sam9x60_div_pll_determine_rate, .set_rate = sam9x60_div_pll_set_rate_chg, .save_context = sam9x60_div_pll_save_context, .restore_context = sam9x60_div_pll_restore_context, @@ -623,7 +630,7 @@ static const struct clk_ops sam9x60_fixed_div_pll_ops = { .unprepare = sam9x60_div_pll_unprepare, .is_prepared = sam9x60_div_pll_is_prepared, .recalc_rate = sam9x60_fixed_div_pll_recalc_rate, - .round_rate = sam9x60_div_pll_round_rate, + .determine_rate = sam9x60_div_pll_determine_rate, .save_context = sam9x60_div_pll_save_context, .restore_context = sam9x60_div_pll_restore_context, }; From a31de1a36e6d2ffa957822e7b7d53bcb2608cb39 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:01 -0400 Subject: [PATCH 1035/2711] clk: at91: usb: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/at91/clk-usb.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index b0696a928aa9..e906928cfbf0 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -319,8 +319,8 @@ static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw, return 0; } -static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int at91rm9200_clk_usb_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); struct clk_hw *parent = clk_hw_get_parent(hw); @@ -336,25 +336,27 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, if (!usb->divisors[i]) continue; - tmp_parent_rate = rate * usb->divisors[i]; + tmp_parent_rate = req->rate * usb->divisors[i]; tmp_parent_rate = clk_hw_round_rate(parent, tmp_parent_rate); tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]); - if (tmprate < rate) - tmpdiff = rate - tmprate; + if (tmprate < req->rate) + tmpdiff = req->rate - tmprate; else - tmpdiff = tmprate - rate; + tmpdiff = tmprate - req->rate; if (bestdiff < 0 || bestdiff > tmpdiff) { bestrate = tmprate; bestdiff = tmpdiff; - *parent_rate = tmp_parent_rate; + req->best_parent_rate = tmp_parent_rate; } if (!bestdiff) break; } - return bestrate; + req->rate = bestrate; + + return 0; } static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, @@ -384,7 +386,7 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops at91rm9200_usb_ops = { .recalc_rate = at91rm9200_clk_usb_recalc_rate, - .round_rate = at91rm9200_clk_usb_round_rate, + .determine_rate = at91rm9200_clk_usb_determine_rate, .set_rate = at91rm9200_clk_usb_set_rate, }; From 9c8a3c6ecba07ba37bd12634d1d363be18e8ba60 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:02 -0400 Subject: [PATCH 1036/2711] clk: baikal-t1: ccu-div: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/baikal-t1/ccu-div.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/clk/baikal-t1/ccu-div.c b/drivers/clk/baikal-t1/ccu-div.c index 8d5fc7158f33..849d1f55765f 100644 --- a/drivers/clk/baikal-t1/ccu-div.c +++ b/drivers/clk/baikal-t1/ccu-div.c @@ -228,15 +228,18 @@ static inline unsigned long ccu_div_var_calc_divider(unsigned long rate, CCU_DIV_CLKDIV_MAX(mask)); } -static long ccu_div_var_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int ccu_div_var_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct ccu_div *div = to_ccu_div(hw); unsigned long divider; - divider = ccu_div_var_calc_divider(rate, *parent_rate, div->mask); + divider = ccu_div_var_calc_divider(req->rate, req->best_parent_rate, + div->mask); - return ccu_div_calc_freq(*parent_rate, divider); + req->rate = ccu_div_calc_freq(req->best_parent_rate, divider); + + return 0; } /* @@ -308,12 +311,14 @@ static unsigned long ccu_div_fixed_recalc_rate(struct clk_hw *hw, return ccu_div_calc_freq(parent_rate, div->divider); } -static long ccu_div_fixed_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int ccu_div_fixed_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct ccu_div *div = to_ccu_div(hw); - return ccu_div_calc_freq(*parent_rate, div->divider); + req->rate = ccu_div_calc_freq(req->best_parent_rate, div->divider); + + return 0; } static int ccu_div_fixed_set_rate(struct clk_hw *hw, unsigned long rate, @@ -534,14 +539,14 @@ static const struct clk_ops ccu_div_var_gate_to_set_ops = { .disable = ccu_div_gate_disable, .is_enabled = ccu_div_gate_is_enabled, .recalc_rate = ccu_div_var_recalc_rate, - .round_rate = ccu_div_var_round_rate, + .determine_rate = ccu_div_var_determine_rate, .set_rate = ccu_div_var_set_rate_fast, .debug_init = ccu_div_var_debug_init }; static const struct clk_ops ccu_div_var_nogate_ops = { .recalc_rate = ccu_div_var_recalc_rate, - .round_rate = ccu_div_var_round_rate, + .determine_rate = ccu_div_var_determine_rate, .set_rate = ccu_div_var_set_rate_slow, .debug_init = ccu_div_var_debug_init }; @@ -551,7 +556,7 @@ static const struct clk_ops ccu_div_gate_ops = { .disable = ccu_div_gate_disable, .is_enabled = ccu_div_gate_is_enabled, .recalc_rate = ccu_div_fixed_recalc_rate, - .round_rate = ccu_div_fixed_round_rate, + .determine_rate = ccu_div_fixed_determine_rate, .set_rate = ccu_div_fixed_set_rate, .debug_init = ccu_div_gate_debug_init }; @@ -565,7 +570,7 @@ static const struct clk_ops ccu_div_buf_ops = { static const struct clk_ops ccu_div_fixed_ops = { .recalc_rate = ccu_div_fixed_recalc_rate, - .round_rate = ccu_div_fixed_round_rate, + .determine_rate = ccu_div_fixed_determine_rate, .set_rate = ccu_div_fixed_set_rate, .debug_init = ccu_div_fixed_debug_init }; From eae23ade8f91ae3f6bbbc0e748787ac0b9d222db Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:03 -0400 Subject: [PATCH 1037/2711] clk: baikal-t1: ccu-pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/baikal-t1/ccu-pll.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/clk/baikal-t1/ccu-pll.c b/drivers/clk/baikal-t1/ccu-pll.c index 13ef28001439..357269f41cdc 100644 --- a/drivers/clk/baikal-t1/ccu-pll.c +++ b/drivers/clk/baikal-t1/ccu-pll.c @@ -228,14 +228,16 @@ static void ccu_pll_calc_factors(unsigned long rate, unsigned long parent_rate, } } -static long ccu_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int ccu_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned long nr = 1, nf = 1, od = 1; - ccu_pll_calc_factors(rate, *parent_rate, &nr, &nf, &od); + ccu_pll_calc_factors(req->rate, req->best_parent_rate, &nr, &nf, &od); - return ccu_pll_calc_freq(*parent_rate, nr, nf, od); + req->rate = ccu_pll_calc_freq(req->best_parent_rate, nr, nf, od); + + return 0; } /* @@ -481,7 +483,7 @@ static const struct clk_ops ccu_pll_gate_to_set_ops = { .disable = ccu_pll_disable, .is_enabled = ccu_pll_is_enabled, .recalc_rate = ccu_pll_recalc_rate, - .round_rate = ccu_pll_round_rate, + .determine_rate = ccu_pll_determine_rate, .set_rate = ccu_pll_set_rate_norst, .debug_init = ccu_pll_debug_init }; @@ -491,7 +493,7 @@ static const struct clk_ops ccu_pll_straight_set_ops = { .disable = ccu_pll_disable, .is_enabled = ccu_pll_is_enabled, .recalc_rate = ccu_pll_recalc_rate, - .round_rate = ccu_pll_round_rate, + .determine_rate = ccu_pll_determine_rate, .set_rate = ccu_pll_set_rate_reset, .debug_init = ccu_pll_debug_init }; From b2b354b075c726ddbd5f2778208392249daa0a39 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:04 -0400 Subject: [PATCH 1038/2711] clk: cdce925: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-cdce925.c | 50 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index c51818c1af98..0b2ad21e6e4d 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -128,13 +128,15 @@ static void cdce925_pll_find_rate(unsigned long rate, } } -static long cdce925_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int cdce925_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u16 n, m; - cdce925_pll_find_rate(rate, *parent_rate, &n, &m); - return (long)cdce925_pll_calculate_rate(*parent_rate, n, m); + cdce925_pll_find_rate(req->rate, req->best_parent_rate, &n, &m); + req->rate = (long)cdce925_pll_calculate_rate(req->best_parent_rate, n, m); + + return 0; } static int cdce925_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -266,7 +268,7 @@ static const struct clk_ops cdce925_pll_ops = { .prepare = cdce925_pll_prepare, .unprepare = cdce925_pll_unprepare, .recalc_rate = cdce925_pll_recalc_rate, - .round_rate = cdce925_pll_round_rate, + .determine_rate = cdce925_pll_determine_rate, .set_rate = cdce925_pll_set_rate, }; @@ -420,20 +422,23 @@ static unsigned long cdce925_clk_best_parent_rate( return rate * pdiv_best; } -static long cdce925_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int cdce925_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned long l_parent_rate = *parent_rate; - u16 divider = cdce925_calc_divider(rate, l_parent_rate); + unsigned long l_parent_rate = req->best_parent_rate; + u16 divider = cdce925_calc_divider(req->rate, l_parent_rate); - if (l_parent_rate / divider != rate) { - l_parent_rate = cdce925_clk_best_parent_rate(hw, rate); - divider = cdce925_calc_divider(rate, l_parent_rate); - *parent_rate = l_parent_rate; + if (l_parent_rate / divider != req->rate) { + l_parent_rate = cdce925_clk_best_parent_rate(hw, req->rate); + divider = cdce925_calc_divider(req->rate, l_parent_rate); + req->best_parent_rate = l_parent_rate; } if (divider) - return (long)(l_parent_rate / divider); + req->rate = (long)(l_parent_rate / divider); + else + req->rate = 0; + return 0; } @@ -451,7 +456,7 @@ static const struct clk_ops cdce925_clk_ops = { .prepare = cdce925_clk_prepare, .unprepare = cdce925_clk_unprepare, .recalc_rate = cdce925_clk_recalc_rate, - .round_rate = cdce925_clk_round_rate, + .determine_rate = cdce925_clk_determine_rate, .set_rate = cdce925_clk_set_rate, }; @@ -473,14 +478,17 @@ static u16 cdce925_y1_calc_divider(unsigned long rate, return (u16)divider; } -static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int cdce925_clk_y1_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned long l_parent_rate = *parent_rate; - u16 divider = cdce925_y1_calc_divider(rate, l_parent_rate); + unsigned long l_parent_rate = req->best_parent_rate; + u16 divider = cdce925_y1_calc_divider(req->rate, l_parent_rate); if (divider) - return (long)(l_parent_rate / divider); + req->rate = (long)(l_parent_rate / divider); + else + req->rate = 0; + return 0; } @@ -498,7 +506,7 @@ static const struct clk_ops cdce925_clk_y1_ops = { .prepare = cdce925_clk_prepare, .unprepare = cdce925_clk_unprepare, .recalc_rate = cdce925_clk_recalc_rate, - .round_rate = cdce925_clk_y1_round_rate, + .determine_rate = cdce925_clk_y1_determine_rate, .set_rate = cdce925_clk_y1_set_rate, }; From 2233ab21bc81dadabed0bd4a9392b7b353445965 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:05 -0400 Subject: [PATCH 1039/2711] clk: cs2000-cp: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-cs2000-cp.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index 35cb93ad298a..8800472ba63f 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -305,15 +305,19 @@ static unsigned long cs2000_recalc_rate(struct clk_hw *hw, return cs2000_ratio_to_rate(ratio, parent_rate, priv->lf_ratio); } -static long cs2000_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int cs2000_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct cs2000_priv *priv = hw_to_priv(hw); u32 ratio; - ratio = cs2000_rate_to_ratio(*parent_rate, rate, priv->lf_ratio); + ratio = cs2000_rate_to_ratio(req->best_parent_rate, req->rate, + priv->lf_ratio); - return cs2000_ratio_to_rate(ratio, *parent_rate, priv->lf_ratio); + req->rate = cs2000_ratio_to_rate(ratio, req->best_parent_rate, + priv->lf_ratio); + + return 0; } static int cs2000_select_ratio_mode(struct cs2000_priv *priv, @@ -430,7 +434,7 @@ static u8 cs2000_get_parent(struct clk_hw *hw) static const struct clk_ops cs2000_ops = { .get_parent = cs2000_get_parent, .recalc_rate = cs2000_recalc_rate, - .round_rate = cs2000_round_rate, + .determine_rate = cs2000_determine_rate, .set_rate = cs2000_set_rate, .prepare = cs2000_enable, .unprepare = cs2000_disable, From 986a96226cd3a20836425deb8a281efb8ff37b9d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:06 -0400 Subject: [PATCH 1040/2711] clk: ep93xx: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Alexander Sverdlin Signed-off-by: Brian Masney --- drivers/clk/clk-ep93xx.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-ep93xx.c b/drivers/clk/clk-ep93xx.c index 4bd8d6ecf6a2..b081ef920e25 100644 --- a/drivers/clk/clk-ep93xx.c +++ b/drivers/clk/clk-ep93xx.c @@ -389,23 +389,25 @@ static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw, return DIV_ROUND_CLOSEST(parent_rate, clk->div[index]); } -static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int ep93xx_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct ep93xx_clk *clk = ep93xx_clk_from(hw); unsigned long best = 0, now; unsigned int i; for (i = 0; i < clk->num_div; i++) { - if ((rate * clk->div[i]) == *parent_rate) - return rate; + if (req->rate * clk->div[i] == req->best_parent_rate) + return 0; - now = DIV_ROUND_CLOSEST(*parent_rate, clk->div[i]); - if (!best || is_best(rate, now, best)) + now = DIV_ROUND_CLOSEST(req->best_parent_rate, clk->div[i]); + if (!best || is_best(req->rate, now, best)) best = now; } - return best; + req->rate = best; + + return 0; } static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate, @@ -437,7 +439,7 @@ static const struct clk_ops ep93xx_div_ops = { .disable = ep93xx_clk_disable, .is_enabled = ep93xx_clk_is_enabled, .recalc_rate = ep93xx_div_recalc_rate, - .round_rate = ep93xx_div_round_rate, + .determine_rate = ep93xx_div_determine_rate, .set_rate = ep93xx_div_set_rate, }; From b87d7e655a86a0f7a9b1d98070fd8540781f9b73 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:07 -0400 Subject: [PATCH 1041/2711] clk: fractional-divider: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-fractional-divider.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index da057172cc90..cd36a6e27f25 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -151,25 +151,32 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw, } EXPORT_SYMBOL_GPL(clk_fractional_divider_general_approximation); -static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_fd_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_fractional_divider *fd = to_clk_fd(hw); unsigned long m, n; u64 ret; - if (!rate || (!clk_hw_can_set_rate_parent(hw) && rate >= *parent_rate)) - return *parent_rate; + if (!req->rate || (!clk_hw_can_set_rate_parent(hw) && req->rate >= req->best_parent_rate)) { + req->rate = req->best_parent_rate; + + return 0; + } if (fd->approximation) - fd->approximation(hw, rate, parent_rate, &m, &n); + fd->approximation(hw, req->rate, &req->best_parent_rate, &m, &n); else - clk_fractional_divider_general_approximation(hw, rate, parent_rate, &m, &n); + clk_fractional_divider_general_approximation(hw, req->rate, + &req->best_parent_rate, + &m, &n); - ret = (u64)*parent_rate * m; + ret = (u64)req->best_parent_rate * m; do_div(ret, n); - return ret; + req->rate = ret; + + return 0; } static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, @@ -250,7 +257,7 @@ static void clk_fd_debug_init(struct clk_hw *hw, struct dentry *dentry) const struct clk_ops clk_fractional_divider_ops = { .recalc_rate = clk_fd_recalc_rate, - .round_rate = clk_fd_round_rate, + .determine_rate = clk_fd_determine_rate, .set_rate = clk_fd_set_rate, #ifdef CONFIG_DEBUG_FS .debug_init = clk_fd_debug_init, From 2ffdd7fbf7af47839ae79aeafc3d33138cf1c72f Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:08 -0400 Subject: [PATCH 1042/2711] clk: gemini: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Linus Walleij Signed-off-by: Brian Masney --- drivers/clk/clk-gemini.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/clk/clk-gemini.c b/drivers/clk/clk-gemini.c index 856b008e07c6..e94589c38568 100644 --- a/drivers/clk/clk-gemini.c +++ b/drivers/clk/clk-gemini.c @@ -126,13 +126,16 @@ static unsigned long gemini_pci_recalc_rate(struct clk_hw *hw, return 33000000; } -static long gemini_pci_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int gemini_pci_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { /* We support 33 and 66 MHz */ - if (rate < 48000000) - return 33000000; - return 66000000; + if (req->rate < 48000000) + req->rate = 33000000; + else + req->rate = 66000000; + + return 0; } static int gemini_pci_set_rate(struct clk_hw *hw, unsigned long rate, @@ -179,7 +182,7 @@ static int gemini_pci_is_enabled(struct clk_hw *hw) static const struct clk_ops gemini_pci_clk_ops = { .recalc_rate = gemini_pci_recalc_rate, - .round_rate = gemini_pci_round_rate, + .determine_rate = gemini_pci_determine_rate, .set_rate = gemini_pci_set_rate, .enable = gemini_pci_enable, .disable = gemini_pci_disable, From 29d6d9e5299dc9fb67cb7176b90984da46cc4f9e Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:09 -0400 Subject: [PATCH 1043/2711] clk: highbank: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-highbank.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c index 6e68a41a70a1..cc583934ecf2 100644 --- a/drivers/clk/clk-highbank.c +++ b/drivers/clk/clk-highbank.c @@ -130,15 +130,17 @@ static void clk_pll_calc(unsigned long rate, unsigned long ref_freq, *pdivf = divf; } -static long clk_pll_round_rate(struct clk_hw *hwclk, unsigned long rate, - unsigned long *parent_rate) +static int clk_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u32 divq, divf; - unsigned long ref_freq = *parent_rate; + unsigned long ref_freq = req->best_parent_rate; - clk_pll_calc(rate, ref_freq, &divq, &divf); + clk_pll_calc(req->rate, ref_freq, &divq, &divf); - return (ref_freq * (divf + 1)) / (1 << divq); + req->rate = (ref_freq * (divf + 1)) / (1 << divq); + + return 0; } static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate, @@ -185,7 +187,7 @@ static const struct clk_ops clk_pll_ops = { .enable = clk_pll_enable, .disable = clk_pll_disable, .recalc_rate = clk_pll_recalc_rate, - .round_rate = clk_pll_round_rate, + .determine_rate = clk_pll_determine_rate, .set_rate = clk_pll_set_rate, }; @@ -227,16 +229,18 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk, return parent_rate / div; } -static long clk_periclk_round_rate(struct clk_hw *hwclk, unsigned long rate, - unsigned long *parent_rate) +static int clk_periclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u32 div; - div = *parent_rate / rate; + div = req->best_parent_rate / req->rate; div++; div &= ~0x1; - return *parent_rate / div; + req->rate = req->best_parent_rate / div; + + return 0; } static int clk_periclk_set_rate(struct clk_hw *hwclk, unsigned long rate, @@ -255,7 +259,7 @@ static int clk_periclk_set_rate(struct clk_hw *hwclk, unsigned long rate, static const struct clk_ops periclk_ops = { .recalc_rate = clk_periclk_recalc_rate, - .round_rate = clk_periclk_round_rate, + .determine_rate = clk_periclk_determine_rate, .set_rate = clk_periclk_set_rate, }; From 619a6210f398eb4ff170bb3eb070dc578cf1cd0c Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:10 -0400 Subject: [PATCH 1044/2711] clk: hisilicon: clkdivider-hi6220: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/hisilicon/clkdivider-hi6220.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c index 5348bafe694f..6bae18a84cb6 100644 --- a/drivers/clk/hisilicon/clkdivider-hi6220.c +++ b/drivers/clk/hisilicon/clkdivider-hi6220.c @@ -55,13 +55,15 @@ static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw, CLK_DIVIDER_ROUND_CLOSEST, dclk->width); } -static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int hi6220_clkdiv_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw); - return divider_round_rate(hw, rate, prate, dclk->table, - dclk->width, CLK_DIVIDER_ROUND_CLOSEST); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, dclk->table, + dclk->width, CLK_DIVIDER_ROUND_CLOSEST); + + return 0; } static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, @@ -93,7 +95,7 @@ static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops hi6220_clkdiv_ops = { .recalc_rate = hi6220_clkdiv_recalc_rate, - .round_rate = hi6220_clkdiv_round_rate, + .determine_rate = hi6220_clkdiv_determine_rate, .set_rate = hi6220_clkdiv_set_rate, }; From bd6fede0903245bbe62cc1554ff399250776b34b Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:11 -0400 Subject: [PATCH 1045/2711] clk: hisilicon: hi3660-stub: move comma from declaration of DEFINE_CLK_STUB() When trying to use Coccinelle to make changes inside drivers/clk/, it really does not like the trailing comma at the end of the declaration of DEFINE_CLK_STUB, and fails to process this file. It also looks weird to not have commas to separate the various array members of hi3660_stub_clks. Let's move the trailing comma out of the define so that Coccinelle can be ran against this source file. Signed-off-by: Brian Masney --- drivers/clk/hisilicon/clk-hi3660-stub.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/hisilicon/clk-hi3660-stub.c b/drivers/clk/hisilicon/clk-hi3660-stub.c index 3a653d54bee0..b0a996385301 100644 --- a/drivers/clk/hisilicon/clk-hi3660-stub.c +++ b/drivers/clk/hisilicon/clk-hi3660-stub.c @@ -34,7 +34,7 @@ .num_parents = 0, \ .flags = CLK_GET_RATE_NOCACHE, \ }, \ - }, + } #define to_stub_clk(_hw) container_of(_hw, struct hi3660_stub_clk, hw) @@ -102,10 +102,10 @@ static const struct clk_ops hi3660_stub_clk_ops = { }; static struct hi3660_stub_clk hi3660_stub_clks[HI3660_CLK_STUB_NUM] = { - DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER0, 0x0001030A, "cpu-cluster.0") - DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER1, 0x0002030A, "cpu-cluster.1") - DEFINE_CLK_STUB(HI3660_CLK_STUB_GPU, 0x0003030A, "clk-g3d") - DEFINE_CLK_STUB(HI3660_CLK_STUB_DDR, 0x00040309, "clk-ddrc") + DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER0, 0x0001030A, "cpu-cluster.0"), + DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER1, 0x0002030A, "cpu-cluster.1"), + DEFINE_CLK_STUB(HI3660_CLK_STUB_GPU, 0x0003030A, "clk-g3d"), + DEFINE_CLK_STUB(HI3660_CLK_STUB_DDR, 0x00040309, "clk-ddrc"), }; static struct clk_hw *hi3660_stub_clk_hw_get(struct of_phandle_args *clkspec, From 97827aa9721844c874cbac54af4b95bad9c21fab Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:12 -0400 Subject: [PATCH 1046/2711] clk: hisilicon: hi3660-stub: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/hisilicon/clk-hi3660-stub.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/hisilicon/clk-hi3660-stub.c b/drivers/clk/hisilicon/clk-hi3660-stub.c index b0a996385301..7c8b00ee6019 100644 --- a/drivers/clk/hisilicon/clk-hi3660-stub.c +++ b/drivers/clk/hisilicon/clk-hi3660-stub.c @@ -67,14 +67,14 @@ static unsigned long hi3660_stub_clk_recalc_rate(struct clk_hw *hw, return stub_clk->rate; } -static long hi3660_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int hi3660_stub_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { /* * LPM3 handles rate rounding so just return whatever * rate is requested. */ - return rate; + return 0; } static int hi3660_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -97,7 +97,7 @@ static int hi3660_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops hi3660_stub_clk_ops = { .recalc_rate = hi3660_stub_clk_recalc_rate, - .round_rate = hi3660_stub_clk_round_rate, + .determine_rate = hi3660_stub_clk_determine_rate, .set_rate = hi3660_stub_clk_set_rate, }; From d983ced6cfe906468d0c63b1eae2880f4d2639c9 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:13 -0400 Subject: [PATCH 1047/2711] clk: hisilicon: hi6220-stub: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/hisilicon/clk-hi6220-stub.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/hisilicon/clk-hi6220-stub.c b/drivers/clk/hisilicon/clk-hi6220-stub.c index a8319795ed1c..bf99cfafafa0 100644 --- a/drivers/clk/hisilicon/clk-hi6220-stub.c +++ b/drivers/clk/hisilicon/clk-hi6220-stub.c @@ -161,11 +161,11 @@ static int hi6220_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate, return ret; } -static long hi6220_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int hi6220_stub_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct hi6220_stub_clk *stub_clk = to_stub_clk(hw); - unsigned long new_rate = rate / 1000; /* kHz */ + unsigned long new_rate = req->rate / 1000; /* kHz */ switch (stub_clk->id) { case HI6220_STUB_ACPU0: @@ -181,12 +181,14 @@ static long hi6220_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate, break; } - return new_rate; + req->rate = new_rate; + + return 0; } static const struct clk_ops hi6220_stub_clk_ops = { .recalc_rate = hi6220_stub_clk_recalc_rate, - .round_rate = hi6220_stub_clk_round_rate, + .determine_rate = hi6220_stub_clk_determine_rate, .set_rate = hi6220_stub_clk_set_rate, }; From 93fc8a13df28fb59c3d0aeb8ba65bbd5a72dad0f Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:14 -0400 Subject: [PATCH 1048/2711] clk: ingenic: cgu: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Paul Cercueil Signed-off-by: Brian Masney --- drivers/clk/ingenic/cgu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c index 0c9c8344ad11..91e7ac0cc334 100644 --- a/drivers/clk/ingenic/cgu.c +++ b/drivers/clk/ingenic/cgu.c @@ -174,14 +174,16 @@ ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info, n * od); } -static long -ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate, - unsigned long *prate) +static int ingenic_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk); - return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL); + req->rate = ingenic_pll_calc(clk_info, req->rate, req->best_parent_rate, + NULL, NULL, NULL); + + return 0; } static inline int ingenic_pll_check_stable(struct ingenic_cgu *cgu, @@ -317,7 +319,7 @@ static int ingenic_pll_is_enabled(struct clk_hw *hw) static const struct clk_ops ingenic_pll_ops = { .recalc_rate = ingenic_pll_recalc_rate, - .round_rate = ingenic_pll_round_rate, + .determine_rate = ingenic_pll_determine_rate, .set_rate = ingenic_pll_set_rate, .enable = ingenic_pll_enable, From 2c52ae540c1f26ac7af86b7fa5a0789889436c2e Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:15 -0400 Subject: [PATCH 1049/2711] clk: ingenic: jz4780-cgu: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/ingenic/jz4780-cgu.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c index b1dadc0a5e75..07e2f3c5c454 100644 --- a/drivers/clk/ingenic/jz4780-cgu.c +++ b/drivers/clk/ingenic/jz4780-cgu.c @@ -128,19 +128,19 @@ static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw, return parent_rate; } -static long jz4780_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate, - unsigned long *parent_rate) +static int jz4780_otg_phy_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - if (req_rate < 15600000) - return 12000000; + if (req->rate < 15600000) + req->rate = 12000000; + else if (req->rate < 21600000) + req->rate = 19200000; + else if (req->rate < 36000000) + req->rate = 24000000; + else + req->rate = 48000000; - if (req_rate < 21600000) - return 19200000; - - if (req_rate < 36000000) - return 24000000; - - return 48000000; + return 0; } static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate, @@ -212,7 +212,7 @@ static int jz4780_otg_phy_is_enabled(struct clk_hw *hw) static const struct clk_ops jz4780_otg_phy_ops = { .recalc_rate = jz4780_otg_phy_recalc_rate, - .round_rate = jz4780_otg_phy_round_rate, + .determine_rate = jz4780_otg_phy_determine_rate, .set_rate = jz4780_otg_phy_set_rate, .enable = jz4780_otg_phy_enable, From 888b3f35c01da7964120e79a9cfae6e1445c3e60 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:16 -0400 Subject: [PATCH 1050/2711] clk: ingenic: x1000-cgu: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Paul Cercueil Signed-off-by: Brian Masney --- drivers/clk/ingenic/x1000-cgu.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/clk/ingenic/x1000-cgu.c b/drivers/clk/ingenic/x1000-cgu.c index feb03eed4fe8..d80886caf393 100644 --- a/drivers/clk/ingenic/x1000-cgu.c +++ b/drivers/clk/ingenic/x1000-cgu.c @@ -84,16 +84,17 @@ static unsigned long x1000_otg_phy_recalc_rate(struct clk_hw *hw, return parent_rate; } -static long x1000_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate, - unsigned long *parent_rate) +static int x1000_otg_phy_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - if (req_rate < 18000000) - return 12000000; + if (req->rate < 18000000) + req->rate = 12000000; + else if (req->rate < 36000000) + req->rate = 24000000; + else + req->rate = 48000000; - if (req_rate < 36000000) - return 24000000; - - return 48000000; + return 0; } static int x1000_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate, @@ -161,7 +162,7 @@ static int x1000_usb_phy_is_enabled(struct clk_hw *hw) static const struct clk_ops x1000_otg_phy_ops = { .recalc_rate = x1000_otg_phy_recalc_rate, - .round_rate = x1000_otg_phy_round_rate, + .determine_rate = x1000_otg_phy_determine_rate, .set_rate = x1000_otg_phy_set_rate, .enable = x1000_usb_phy_enable, From 94f872e762725deb751e0fc56a9d8fe187945d2b Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:17 -0400 Subject: [PATCH 1051/2711] clk: lmk04832: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-lmk04832.c | 53 ++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c index 2bcf422f0b04..b2107b31efa2 100644 --- a/drivers/clk/clk-lmk04832.c +++ b/drivers/clk/clk-lmk04832.c @@ -491,28 +491,33 @@ static long lmk04832_calc_pll2_params(unsigned long prate, unsigned long rate, return DIV_ROUND_CLOSEST(prate * 2 * pll2_p * pll2_n, pll2_r); } -static long lmk04832_vco_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int lmk04832_vco_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco); unsigned int n, p, r; long vco_rate; int ret; - ret = lmk04832_check_vco_ranges(lmk, rate); + ret = lmk04832_check_vco_ranges(lmk, req->rate); if (ret < 0) return ret; - vco_rate = lmk04832_calc_pll2_params(*prate, rate, &n, &p, &r); + vco_rate = lmk04832_calc_pll2_params(req->best_parent_rate, req->rate, + &n, &p, &r); if (vco_rate < 0) { dev_err(lmk->dev, "PLL2 parameters out of range\n"); - return vco_rate; + req->rate = vco_rate; + + return 0; } - if (rate != vco_rate) + if (req->rate != vco_rate) return -EINVAL; - return vco_rate; + req->rate = vco_rate; + + return 0; } static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate, @@ -579,7 +584,7 @@ static const struct clk_ops lmk04832_vco_ops = { .prepare = lmk04832_vco_prepare, .unprepare = lmk04832_vco_unprepare, .recalc_rate = lmk04832_vco_recalc_rate, - .round_rate = lmk04832_vco_round_rate, + .determine_rate = lmk04832_vco_determine_rate, .set_rate = lmk04832_vco_set_rate, }; @@ -888,25 +893,27 @@ static unsigned long lmk04832_sclk_recalc_rate(struct clk_hw *hw, return DIV_ROUND_CLOSEST(prate, sysref_div); } -static long lmk04832_sclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int lmk04832_sclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct lmk04832 *lmk = container_of(hw, struct lmk04832, sclk); unsigned long sclk_rate; unsigned int sysref_div; - sysref_div = DIV_ROUND_CLOSEST(*prate, rate); - sclk_rate = DIV_ROUND_CLOSEST(*prate, sysref_div); + sysref_div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate); + sclk_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, sysref_div); if (sysref_div < 0x07 || sysref_div > 0x1fff) { dev_err(lmk->dev, "SYSREF divider out of range\n"); return -EINVAL; } - if (rate != sclk_rate) + if (req->rate != sclk_rate) return -EINVAL; - return sclk_rate; + req->rate = sclk_rate; + + return 0; } static int lmk04832_sclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -945,7 +952,7 @@ static const struct clk_ops lmk04832_sclk_ops = { .prepare = lmk04832_sclk_prepare, .unprepare = lmk04832_sclk_unprepare, .recalc_rate = lmk04832_sclk_recalc_rate, - .round_rate = lmk04832_sclk_round_rate, + .determine_rate = lmk04832_sclk_determine_rate, .set_rate = lmk04832_sclk_set_rate, }; @@ -1069,26 +1076,28 @@ static unsigned long lmk04832_dclk_recalc_rate(struct clk_hw *hw, return rate; } -static long lmk04832_dclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int lmk04832_dclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct lmk_dclk *dclk = container_of(hw, struct lmk_dclk, hw); struct lmk04832 *lmk = dclk->lmk; unsigned long dclk_rate; unsigned int dclk_div; - dclk_div = DIV_ROUND_CLOSEST(*prate, rate); - dclk_rate = DIV_ROUND_CLOSEST(*prate, dclk_div); + dclk_div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate); + dclk_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, dclk_div); if (dclk_div < 1 || dclk_div > 0x3ff) { dev_err(lmk->dev, "%s_div out of range\n", clk_hw_get_name(hw)); return -EINVAL; } - if (rate != dclk_rate) + if (req->rate != dclk_rate) return -EINVAL; - return dclk_rate; + req->rate = dclk_rate; + + return 0; } static int lmk04832_dclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -1158,7 +1167,7 @@ static const struct clk_ops lmk04832_dclk_ops = { .prepare = lmk04832_dclk_prepare, .unprepare = lmk04832_dclk_unprepare, .recalc_rate = lmk04832_dclk_recalc_rate, - .round_rate = lmk04832_dclk_round_rate, + .determine_rate = lmk04832_dclk_determine_rate, .set_rate = lmk04832_dclk_set_rate, }; From bb40a2ef4fc9d7cef4b03e1b1906b512d9693dd9 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:18 -0400 Subject: [PATCH 1052/2711] clk: loongson1: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-loongson1.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-loongson1.c b/drivers/clk/clk-loongson1.c index a3467aa6790f..f9f060d08a5f 100644 --- a/drivers/clk/clk-loongson1.c +++ b/drivers/clk/clk-loongson1.c @@ -93,14 +93,16 @@ static unsigned long ls1x_divider_recalc_rate(struct clk_hw *hw, d->flags, d->width); } -static long ls1x_divider_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int ls1x_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw); const struct ls1x_clk_div_data *d = ls1x_clk->data; - return divider_round_rate(hw, rate, prate, d->table, - d->width, d->flags); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + d->table, d->width, d->flags); + + return 0; } static int ls1x_divider_set_rate(struct clk_hw *hw, unsigned long rate, @@ -146,7 +148,7 @@ static int ls1x_divider_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops ls1x_clk_divider_ops = { .recalc_rate = ls1x_divider_recalc_rate, - .round_rate = ls1x_divider_round_rate, + .determine_rate = ls1x_divider_determine_rate, .set_rate = ls1x_divider_set_rate, }; From 4f8ccd92870d6be4c11ae4440ee7c3ded4d4bd70 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:19 -0400 Subject: [PATCH 1053/2711] clk: max9485: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-max9485.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/clk/clk-max9485.c b/drivers/clk/clk-max9485.c index be9020b6c789..0515e3e41162 100644 --- a/drivers/clk/clk-max9485.c +++ b/drivers/clk/clk-max9485.c @@ -159,29 +159,32 @@ static unsigned long max9485_clkout_recalc_rate(struct clk_hw *hw, return 0; } -static long max9485_clkout_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int max9485_clkout_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { const struct max9485_rate *curr, *prev = NULL; for (curr = max9485_rates; curr->out != 0; curr++) { /* Exact matches */ - if (curr->out == rate) - return rate; + if (curr->out == req->rate) + return 0; /* * Find the first entry that has a frequency higher than the * requested one. */ - if (curr->out > rate) { + if (curr->out > req->rate) { unsigned int mid; /* * If this is the first entry, clamp the value to the * lowest possible frequency. */ - if (!prev) - return curr->out; + if (!prev) { + req->rate = curr->out; + + return 0; + } /* * Otherwise, determine whether the previous entry or @@ -189,14 +192,18 @@ static long max9485_clkout_round_rate(struct clk_hw *hw, unsigned long rate, */ mid = prev->out + ((curr->out - prev->out) / 2); - return (mid > rate) ? prev->out : curr->out; + req->rate = mid > req->rate ? prev->out : curr->out; + + return 0; } prev = curr; } /* If the last entry was still too high, clamp the value */ - return prev->out; + req->rate = prev->out; + + return 0; } struct max9485_clk { @@ -221,7 +228,7 @@ static const struct max9485_clk max9485_clks[MAX9485_NUM_CLKS] = { .parent_index = -1, .ops = { .set_rate = max9485_clkout_set_rate, - .round_rate = max9485_clkout_round_rate, + .determine_rate = max9485_clkout_determine_rate, .recalc_rate = max9485_clkout_recalc_rate, }, }, From 7b45988fcf7895b2f044c216e09ba3b68764a24d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:20 -0400 Subject: [PATCH 1054/2711] clk: milbeaut: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-milbeaut.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-milbeaut.c b/drivers/clk/clk-milbeaut.c index 18c20aff45f7..b4f9b7143eaa 100644 --- a/drivers/clk/clk-milbeaut.c +++ b/drivers/clk/clk-milbeaut.c @@ -386,8 +386,8 @@ static unsigned long m10v_clk_divider_recalc_rate(struct clk_hw *hw, divider->flags, divider->width); } -static long m10v_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int m10v_clk_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct m10v_clk_divider *divider = to_m10v_div(hw); @@ -398,13 +398,19 @@ static long m10v_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, val = readl(divider->reg) >> divider->shift; val &= clk_div_mask(divider->width); - return divider_ro_round_rate(hw, rate, prate, divider->table, - divider->width, divider->flags, - val); + req->rate = divider_ro_round_rate(hw, req->rate, + &req->best_parent_rate, + divider->table, + divider->width, + divider->flags, val); + + return 0; } - return divider_round_rate(hw, rate, prate, divider->table, - divider->width, divider->flags); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + divider->table, divider->width, divider->flags); + + return 0; } static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, @@ -450,7 +456,7 @@ static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops m10v_clk_divider_ops = { .recalc_rate = m10v_clk_divider_recalc_rate, - .round_rate = m10v_clk_divider_round_rate, + .determine_rate = m10v_clk_divider_determine_rate, .set_rate = m10v_clk_divider_set_rate, }; From 2ffc3f1f39647e522a19a917ec105a96301c5d74 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:21 -0400 Subject: [PATCH 1055/2711] clk: mmp: audio: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/mmp/clk-audio.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/clk/mmp/clk-audio.c b/drivers/clk/mmp/clk-audio.c index 88d798d510cd..ed27fc796c94 100644 --- a/drivers/clk/mmp/clk-audio.c +++ b/drivers/clk/mmp/clk-audio.c @@ -164,23 +164,23 @@ static unsigned long audio_pll_recalc_rate(struct clk_hw *hw, return 0; } -static long audio_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int audio_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned int prediv; unsigned int postdiv; long rounded = 0; for (prediv = 0; prediv < ARRAY_SIZE(predivs); prediv++) { - if (predivs[prediv].parent_rate != *parent_rate) + if (predivs[prediv].parent_rate != req->best_parent_rate) continue; for (postdiv = 0; postdiv < ARRAY_SIZE(postdivs); postdiv++) { long freq = predivs[prediv].freq_vco; freq /= postdivs[postdiv].divisor; - if (freq == rate) - return rate; - if (freq < rate) + if (freq == req->rate) + return 0; + if (freq < req->rate) continue; if (rounded && freq > rounded) continue; @@ -188,7 +188,9 @@ static long audio_pll_round_rate(struct clk_hw *hw, unsigned long rate, } } - return rounded; + req->rate = rounded; + + return 0; } static int audio_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -228,7 +230,7 @@ static int audio_pll_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops audio_pll_ops = { .recalc_rate = audio_pll_recalc_rate, - .round_rate = audio_pll_round_rate, + .determine_rate = audio_pll_determine_rate, .set_rate = audio_pll_set_rate, }; From 4a7aeef18bc568e05962ba7c25f0782970fe5d1d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:22 -0400 Subject: [PATCH 1056/2711] clk: mmp: frac: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/mmp/clk-frac.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c index 6556f6ada2e8..0b1bb01346f0 100644 --- a/drivers/clk/mmp/clk-frac.c +++ b/drivers/clk/mmp/clk-frac.c @@ -21,8 +21,8 @@ #define to_clk_factor(hw) container_of(hw, struct mmp_clk_factor, hw) -static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, - unsigned long *prate) +static int clk_factor_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct mmp_clk_factor *factor = to_clk_factor(hw); u64 rate = 0, prev_rate; @@ -33,19 +33,20 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, d = &factor->ftbl[i]; prev_rate = rate; - rate = (u64)(*prate) * d->denominator; + rate = (u64)(req->best_parent_rate) * d->denominator; do_div(rate, d->numerator * factor->masks->factor); - if (rate > drate) + if (rate > req->rate) break; } - if ((i == 0) || (i == factor->ftbl_cnt)) { - return rate; - } else { - if ((drate - prev_rate) > (rate - drate)) - return rate; - else - return prev_rate; - } + + if ((i == 0) || (i == factor->ftbl_cnt)) + req->rate = rate; + else if ((req->rate - prev_rate) > (rate - req->rate)) + req->rate = rate; + else + req->rate = prev_rate; + + return 0; } static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, @@ -160,7 +161,7 @@ static int clk_factor_init(struct clk_hw *hw) static const struct clk_ops clk_factor_ops = { .recalc_rate = clk_factor_recalc_rate, - .round_rate = clk_factor_round_rate, + .determine_rate = clk_factor_determine_rate, .set_rate = clk_factor_set_rate, .init = clk_factor_init, }; From 772e2dc59c9c5ec419b3db8f867c0d65d44a9590 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:23 -0400 Subject: [PATCH 1057/2711] clk: multiplier: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-multiplier.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-multiplier.c b/drivers/clk/clk-multiplier.c index e507aa958da9..6f2955d408b6 100644 --- a/drivers/clk/clk-multiplier.c +++ b/drivers/clk/clk-multiplier.c @@ -112,14 +112,16 @@ static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate, return bestmult; } -static long clk_multiplier_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_multiplier_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_multiplier *mult = to_clk_multiplier(hw); - unsigned long factor = __bestmult(hw, rate, parent_rate, + unsigned long factor = __bestmult(hw, req->rate, &req->best_parent_rate, mult->width, mult->flags); - return *parent_rate * factor; + req->rate = req->best_parent_rate * factor; + + return 0; } static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate, @@ -150,7 +152,7 @@ static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops clk_multiplier_ops = { .recalc_rate = clk_multiplier_recalc_rate, - .round_rate = clk_multiplier_round_rate, + .determine_rate = clk_multiplier_determine_rate, .set_rate = clk_multiplier_set_rate, }; EXPORT_SYMBOL_GPL(clk_multiplier_ops); From da730b17aae9daa221e6de2c48303b3fb684f683 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:24 -0400 Subject: [PATCH 1058/2711] clk: mxs: div: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. The change to call div->ops->determine_rate() instead of div->ops->round_rate() was done by hand. Signed-off-by: Brian Masney --- drivers/clk/mxs/clk-div.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c index 0a78ef380646..8afe1a9c1552 100644 --- a/drivers/clk/mxs/clk-div.c +++ b/drivers/clk/mxs/clk-div.c @@ -40,12 +40,12 @@ static unsigned long clk_div_recalc_rate(struct clk_hw *hw, return div->ops->recalc_rate(&div->divider.hw, parent_rate); } -static long clk_div_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_div *div = to_clk_div(hw); - return div->ops->round_rate(&div->divider.hw, rate, prate); + return div->ops->determine_rate(&div->divider.hw, req); } static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate, @@ -63,7 +63,7 @@ static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops clk_div_ops = { .recalc_rate = clk_div_recalc_rate, - .round_rate = clk_div_round_rate, + .determine_rate = clk_div_determine_rate, .set_rate = clk_div_set_rate, }; From 755e4880f950221b6944b33dcab94093940d02b9 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:25 -0400 Subject: [PATCH 1059/2711] clk: mxs: frac: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/mxs/clk-frac.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/clk/mxs/clk-frac.c b/drivers/clk/mxs/clk-frac.c index bba0d840dd76..73f514fb84ff 100644 --- a/drivers/clk/mxs/clk-frac.c +++ b/drivers/clk/mxs/clk-frac.c @@ -44,18 +44,18 @@ static unsigned long clk_frac_recalc_rate(struct clk_hw *hw, return tmp_rate >> frac->width; } -static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_frac_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_frac *frac = to_clk_frac(hw); - unsigned long parent_rate = *prate; + unsigned long parent_rate = req->best_parent_rate; u32 div; u64 tmp, tmp_rate, result; - if (rate > parent_rate) + if (req->rate > parent_rate) return -EINVAL; - tmp = rate; + tmp = req->rate; tmp <<= frac->width; do_div(tmp, parent_rate); div = tmp; @@ -67,7 +67,9 @@ static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate, result = tmp_rate >> frac->width; if ((result << frac->width) < tmp_rate) result += 1; - return result; + req->rate = result; + + return 0; } static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate, @@ -103,7 +105,7 @@ static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops clk_frac_ops = { .recalc_rate = clk_frac_recalc_rate, - .round_rate = clk_frac_round_rate, + .determine_rate = clk_frac_determine_rate, .set_rate = clk_frac_set_rate, }; From b248bd3c0525feb7d0e2d2ca5930e5e95261eb4c Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:26 -0400 Subject: [PATCH 1060/2711] clk: mxs: ref: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/mxs/clk-ref.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/clk/mxs/clk-ref.c b/drivers/clk/mxs/clk-ref.c index 2297259da89a..a99ee4cd2ece 100644 --- a/drivers/clk/mxs/clk-ref.c +++ b/drivers/clk/mxs/clk-ref.c @@ -57,22 +57,24 @@ static unsigned long clk_ref_recalc_rate(struct clk_hw *hw, return tmp; } -static long clk_ref_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_ref_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned long parent_rate = *prate; + unsigned long parent_rate = req->best_parent_rate; u64 tmp = parent_rate; u8 frac; - tmp = tmp * 18 + rate / 2; - do_div(tmp, rate); + tmp = tmp * 18 + req->rate / 2; + do_div(tmp, req->rate); frac = clamp(tmp, 18, 35); tmp = parent_rate; tmp *= 18; do_div(tmp, frac); - return tmp; + req->rate = tmp; + + return 0; } static int clk_ref_set_rate(struct clk_hw *hw, unsigned long rate, @@ -104,7 +106,7 @@ static const struct clk_ops clk_ref_ops = { .enable = clk_ref_enable, .disable = clk_ref_disable, .recalc_rate = clk_ref_recalc_rate, - .round_rate = clk_ref_round_rate, + .determine_rate = clk_ref_determine_rate, .set_rate = clk_ref_set_rate, }; From 215f8aa095a1e3384ab5d84bae6b86cab0e491be Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:27 -0400 Subject: [PATCH 1061/2711] clk: nuvoton: ma35d1-divider: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/nuvoton/clk-ma35d1-divider.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/clk/nuvoton/clk-ma35d1-divider.c b/drivers/clk/nuvoton/clk-ma35d1-divider.c index bb8c23d2b895..e39f53d5bf45 100644 --- a/drivers/clk/nuvoton/clk-ma35d1-divider.c +++ b/drivers/clk/nuvoton/clk-ma35d1-divider.c @@ -39,12 +39,16 @@ static unsigned long ma35d1_clkdiv_recalc_rate(struct clk_hw *hw, unsigned long CLK_DIVIDER_ROUND_CLOSEST, dclk->width); } -static long ma35d1_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) +static int ma35d1_clkdiv_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct ma35d1_adc_clk_div *dclk = to_ma35d1_adc_clk_div(hw); - return divider_round_rate(hw, rate, prate, dclk->table, - dclk->width, CLK_DIVIDER_ROUND_CLOSEST); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + dclk->table, dclk->width, + CLK_DIVIDER_ROUND_CLOSEST); + + return 0; } static int ma35d1_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) @@ -71,7 +75,7 @@ static int ma35d1_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, unsigne static const struct clk_ops ma35d1_adc_clkdiv_ops = { .recalc_rate = ma35d1_clkdiv_recalc_rate, - .round_rate = ma35d1_clkdiv_round_rate, + .determine_rate = ma35d1_clkdiv_determine_rate, .set_rate = ma35d1_clkdiv_set_rate, }; From cd9e9bbfd93be277e316ee854614e2c4cd502fa8 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:28 -0400 Subject: [PATCH 1062/2711] clk: nuvoton: ma35d1-pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/nuvoton/clk-ma35d1-pll.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/clk/nuvoton/clk-ma35d1-pll.c b/drivers/clk/nuvoton/clk-ma35d1-pll.c index ff3fb8b87c24..4620acfe47e8 100644 --- a/drivers/clk/nuvoton/clk-ma35d1-pll.c +++ b/drivers/clk/nuvoton/clk-ma35d1-pll.c @@ -244,35 +244,43 @@ static unsigned long ma35d1_clk_pll_recalc_rate(struct clk_hw *hw, unsigned long return 0; } -static long ma35d1_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int ma35d1_clk_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw); u32 reg_ctl[3] = { 0 }; unsigned long pll_freq; long ret; - if (*parent_rate < PLL_FREF_MIN_FREQ || *parent_rate > PLL_FREF_MAX_FREQ) + if (req->best_parent_rate < PLL_FREF_MIN_FREQ || req->best_parent_rate > PLL_FREF_MAX_FREQ) return -EINVAL; - ret = ma35d1_pll_find_closest(pll, rate, *parent_rate, reg_ctl, &pll_freq); + ret = ma35d1_pll_find_closest(pll, req->rate, req->best_parent_rate, + reg_ctl, &pll_freq); if (ret < 0) return ret; switch (pll->id) { case CAPLL: reg_ctl[0] = readl_relaxed(pll->ctl0_base); - pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], *parent_rate); - return pll_freq; + pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], req->best_parent_rate); + req->rate = pll_freq; + + return 0; case DDRPLL: case APLL: case EPLL: case VPLL: reg_ctl[0] = readl_relaxed(pll->ctl0_base); reg_ctl[1] = readl_relaxed(pll->ctl1_base); - pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, *parent_rate); - return pll_freq; + pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, req->best_parent_rate); + req->rate = pll_freq; + + return 0; } + + req->rate = 0; + return 0; } @@ -311,12 +319,12 @@ static const struct clk_ops ma35d1_clk_pll_ops = { .unprepare = ma35d1_clk_pll_unprepare, .set_rate = ma35d1_clk_pll_set_rate, .recalc_rate = ma35d1_clk_pll_recalc_rate, - .round_rate = ma35d1_clk_pll_round_rate, + .determine_rate = ma35d1_clk_pll_determine_rate, }; static const struct clk_ops ma35d1_clk_fixed_pll_ops = { .recalc_rate = ma35d1_clk_pll_recalc_rate, - .round_rate = ma35d1_clk_pll_round_rate, + .determine_rate = ma35d1_clk_pll_determine_rate, }; struct clk_hw *ma35d1_reg_clk_pll(struct device *dev, u32 id, u8 u8mode, const char *name, From b46a3d323a5b7942e65025254c13801d0f475f02 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:29 -0400 Subject: [PATCH 1063/2711] clk: nxp: lpc18xx-cgu: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/nxp/clk-lpc18xx-cgu.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c index 81efa885069b..30e0b283ca60 100644 --- a/drivers/clk/nxp/clk-lpc18xx-cgu.c +++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c @@ -370,23 +370,25 @@ static unsigned long lpc18xx_pll0_recalc_rate(struct clk_hw *hw, return 0; } -static long lpc18xx_pll0_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int lpc18xx_pll0_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned long m; - if (*prate < rate) { + if (req->best_parent_rate < req->rate) { pr_warn("%s: pll dividers not supported\n", __func__); return -EINVAL; } - m = DIV_ROUND_UP_ULL(*prate, rate * 2); + m = DIV_ROUND_UP_ULL(req->best_parent_rate, req->rate * 2); if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { - pr_warn("%s: unable to support rate %lu\n", __func__, rate); + pr_warn("%s: unable to support rate %lu\n", __func__, req->rate); return -EINVAL; } - return 2 * *prate * m; + req->rate = 2 * req->best_parent_rate * m; + + return 0; } static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate, @@ -443,7 +445,7 @@ static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops lpc18xx_pll0_ops = { .recalc_rate = lpc18xx_pll0_recalc_rate, - .round_rate = lpc18xx_pll0_round_rate, + .determine_rate = lpc18xx_pll0_determine_rate, .set_rate = lpc18xx_pll0_set_rate, }; From 1c7452aa7577d8b521eae162a5a51d7408902985 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:31 -0400 Subject: [PATCH 1064/2711] clk: pistachio: pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/pistachio/clk-pll.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/clk/pistachio/clk-pll.c b/drivers/clk/pistachio/clk-pll.c index 025b9df76cdb..d05337915e2b 100644 --- a/drivers/clk/pistachio/clk-pll.c +++ b/drivers/clk/pistachio/clk-pll.c @@ -139,19 +139,23 @@ pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref, return NULL; } -static long pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct pistachio_clk_pll *pll = to_pistachio_pll(hw); unsigned int i; for (i = 0; i < pll->nr_rates; i++) { - if (i > 0 && pll->rates[i].fref == *parent_rate && - pll->rates[i].fout <= rate) - return pll->rates[i - 1].fout; + if (i > 0 && pll->rates[i].fref == req->best_parent_rate && + pll->rates[i].fout <= req->rate) { + req->rate = pll->rates[i - 1].fout; + + return 0; + } } - return pll->rates[0].fout; + req->rate = pll->rates[0].fout; + + return 0; } static int pll_gf40lp_frac_enable(struct clk_hw *hw) @@ -300,7 +304,7 @@ static const struct clk_ops pll_gf40lp_frac_ops = { .disable = pll_gf40lp_frac_disable, .is_enabled = pll_gf40lp_frac_is_enabled, .recalc_rate = pll_gf40lp_frac_recalc_rate, - .round_rate = pll_round_rate, + .determine_rate = pll_determine_rate, .set_rate = pll_gf40lp_frac_set_rate, }; @@ -432,7 +436,7 @@ static const struct clk_ops pll_gf40lp_laint_ops = { .disable = pll_gf40lp_laint_disable, .is_enabled = pll_gf40lp_laint_is_enabled, .recalc_rate = pll_gf40lp_laint_recalc_rate, - .round_rate = pll_round_rate, + .determine_rate = pll_determine_rate, .set_rate = pll_gf40lp_laint_set_rate, }; From 6a67550bc4da6f4f852a2593f893db3c9840a9c7 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:32 -0400 Subject: [PATCH 1065/2711] clk: scpi: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-scpi.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index 19d530d52e64..0b592de7bdb2 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -32,8 +32,8 @@ static unsigned long scpi_clk_recalc_rate(struct clk_hw *hw, return clk->scpi_ops->clk_get_val(clk->id); } -static long scpi_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int scpi_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { /* * We can't figure out what rate it will be, so just return the @@ -41,7 +41,7 @@ static long scpi_clk_round_rate(struct clk_hw *hw, unsigned long rate, * after the rate is set and we'll know what rate the clock is * running at then. */ - return rate; + return 0; } static int scpi_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -54,7 +54,7 @@ static int scpi_clk_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops scpi_clk_ops = { .recalc_rate = scpi_clk_recalc_rate, - .round_rate = scpi_clk_round_rate, + .determine_rate = scpi_clk_determine_rate, .set_rate = scpi_clk_set_rate, }; @@ -92,12 +92,14 @@ static unsigned long scpi_dvfs_recalc_rate(struct clk_hw *hw, return opp->freq; } -static long scpi_dvfs_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int scpi_dvfs_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct scpi_clk *clk = to_scpi_clk(hw); - return __scpi_dvfs_round_rate(clk, rate); + req->rate = __scpi_dvfs_round_rate(clk, req->rate); + + return 0; } static int __scpi_find_dvfs_index(struct scpi_clk *clk, unsigned long rate) @@ -124,7 +126,7 @@ static int scpi_dvfs_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops scpi_dvfs_ops = { .recalc_rate = scpi_dvfs_recalc_rate, - .round_rate = scpi_dvfs_round_rate, + .determine_rate = scpi_dvfs_determine_rate, .set_rate = scpi_dvfs_set_rate, }; From cf93c12ba4342f5b93ff7dd3dfedb299aa4f2552 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:33 -0400 Subject: [PATCH 1066/2711] clk: si514: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-si514.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c index 1127c35ce57d..f61590d70575 100644 --- a/drivers/clk/clk-si514.c +++ b/drivers/clk/clk-si514.c @@ -227,20 +227,28 @@ static unsigned long si514_recalc_rate(struct clk_hw *hw, return si514_calc_rate(&settings); } -static long si514_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int si514_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_si514_muldiv settings; int err; - if (!rate) + if (!req->rate) { + req->rate = 0; + return 0; + } - err = si514_calc_muldiv(&settings, rate); - if (err) - return err; + err = si514_calc_muldiv(&settings, req->rate); + if (err) { + req->rate = err; - return si514_calc_rate(&settings); + return 0; + } + + req->rate = si514_calc_rate(&settings); + + return 0; } /* @@ -289,7 +297,7 @@ static const struct clk_ops si514_clk_ops = { .unprepare = si514_unprepare, .is_prepared = si514_is_prepared, .recalc_rate = si514_recalc_rate, - .round_rate = si514_round_rate, + .determine_rate = si514_determine_rate, .set_rate = si514_set_rate, }; From 6a5626809ca6e6d696bf9e5039e6370d2c128888 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:34 -0400 Subject: [PATCH 1067/2711] clk: si521xx: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-si521xx.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c index 4f7b74f889f1..4ed4e1a5f4f2 100644 --- a/drivers/clk/clk-si521xx.c +++ b/drivers/clk/clk-si521xx.c @@ -164,15 +164,17 @@ static unsigned long si521xx_diff_recalc_rate(struct clk_hw *hw, return (unsigned long)rate; } -static long si521xx_diff_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int si521xx_diff_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned long best_parent; - best_parent = (rate / SI521XX_DIFF_MULT) * SI521XX_DIFF_DIV; - *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); + best_parent = (req->rate / SI521XX_DIFF_MULT) * SI521XX_DIFF_DIV; + req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); - return (*prate / SI521XX_DIFF_DIV) * SI521XX_DIFF_MULT; + req->rate = (req->best_parent_rate / SI521XX_DIFF_DIV) * SI521XX_DIFF_MULT; + + return 0; } static int si521xx_diff_set_rate(struct clk_hw *hw, unsigned long rate, @@ -208,7 +210,7 @@ static void si521xx_diff_unprepare(struct clk_hw *hw) } static const struct clk_ops si521xx_diff_clk_ops = { - .round_rate = si521xx_diff_round_rate, + .determine_rate = si521xx_diff_determine_rate, .set_rate = si521xx_diff_set_rate, .recalc_rate = si521xx_diff_recalc_rate, .prepare = si521xx_diff_prepare, From 90d00a531ea1d785f98de9dce668915928b0dd52 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:35 -0400 Subject: [PATCH 1068/2711] clk: si5341: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-si5341.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c index 5004888c7eca..2499b771cd83 100644 --- a/drivers/clk/clk-si5341.c +++ b/drivers/clk/clk-si5341.c @@ -663,8 +663,8 @@ static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw, return f; } -static long si5341_synth_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int si5341_synth_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_si5341_synth *synth = to_clk_si5341_synth(hw); u64 f; @@ -672,15 +672,21 @@ static long si5341_synth_clk_round_rate(struct clk_hw *hw, unsigned long rate, /* The synthesizer accuracy is such that anything in range will work */ f = synth->data->freq_vco; do_div(f, SI5341_SYNTH_N_MAX); - if (rate < f) - return f; + if (req->rate < f) { + req->rate = f; + + return 0; + } f = synth->data->freq_vco; do_div(f, SI5341_SYNTH_N_MIN); - if (rate > f) - return f; + if (req->rate > f) { + req->rate = f; - return rate; + return 0; + } + + return 0; } static int si5341_synth_program(struct clk_si5341_synth *synth, @@ -741,7 +747,7 @@ static const struct clk_ops si5341_synth_clk_ops = { .prepare = si5341_synth_clk_prepare, .unprepare = si5341_synth_clk_unprepare, .recalc_rate = si5341_synth_clk_recalc_rate, - .round_rate = si5341_synth_clk_round_rate, + .determine_rate = si5341_synth_clk_determine_rate, .set_rate = si5341_synth_clk_set_rate, }; From 0d4ccc375673da246050430817f409c392d0ef0b Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:36 -0400 Subject: [PATCH 1069/2711] clk: si544: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-si544.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c index ca3473efa314..09c06ecec1a5 100644 --- a/drivers/clk/clk-si544.c +++ b/drivers/clk/clk-si544.c @@ -307,16 +307,16 @@ static unsigned long si544_recalc_rate(struct clk_hw *hw, return si544_calc_rate(&settings); } -static long si544_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int si544_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_si544 *data = to_clk_si544(hw); - if (!is_valid_frequency(data, rate)) + if (!is_valid_frequency(data, req->rate)) return -EINVAL; /* The accuracy is less than 1 Hz, so any rate is possible */ - return rate; + return 0; } /* Calculates the maximum "small" change, 950 * rate / 1000000 */ @@ -408,7 +408,7 @@ static const struct clk_ops si544_clk_ops = { .unprepare = si544_unprepare, .is_prepared = si544_is_prepared, .recalc_rate = si544_recalc_rate, - .round_rate = si544_round_rate, + .determine_rate = si544_determine_rate, .set_rate = si544_set_rate, }; From 3859ce9eeb326ebda5d5dd1ca4db733da6c9891f Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:37 -0400 Subject: [PATCH 1070/2711] clk: si570: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-si570.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c index e97fe90443a6..b0b1830dd430 100644 --- a/drivers/clk/clk-si570.c +++ b/drivers/clk/clk-si570.c @@ -246,34 +246,40 @@ static unsigned long si570_recalc_rate(struct clk_hw *hw, return rate; } -static long si570_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int si570_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int err; u64 rfreq; unsigned int n1, hs_div; struct clk_si570 *data = to_clk_si570(hw); - if (!rate) - return 0; + if (!req->rate) { + req->rate = 0; - if (div64_u64(abs(rate - data->frequency) * 10000LL, + return 0; + } + + if (div64_u64(abs(req->rate - data->frequency) * 10000LL, data->frequency) < 35) { - rfreq = div64_u64((data->rfreq * rate) + - div64_u64(data->frequency, 2), data->frequency); + rfreq = div64_u64((data->rfreq * req->rate) + + div64_u64(data->frequency, 2), + data->frequency); n1 = data->n1; hs_div = data->hs_div; } else { - err = si570_calc_divs(rate, data, &rfreq, &n1, &hs_div); + err = si570_calc_divs(req->rate, data, &rfreq, &n1, &hs_div); if (err) { dev_err(&data->i2c_client->dev, "unable to round rate\n"); + req->rate = 0; + return 0; } } - return rate; + return 0; } /** @@ -368,7 +374,7 @@ static int si570_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops si570_clk_ops = { .recalc_rate = si570_recalc_rate, - .round_rate = si570_round_rate, + .determine_rate = si570_determine_rate, .set_rate = si570_set_rate, }; From ff04a06db62669d8c4b69ebb02812b2a9f21d4b8 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:38 -0400 Subject: [PATCH 1071/2711] clk: sifive: sifive-prci: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Note that the changes to the three header files were done by hand. Reviewed-by: Samuel Holland Signed-off-by: Brian Masney --- drivers/clk/sifive/fu540-prci.h | 2 +- drivers/clk/sifive/fu740-prci.h | 2 +- drivers/clk/sifive/sifive-prci.c | 11 ++++++----- drivers/clk/sifive/sifive-prci.h | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/clk/sifive/fu540-prci.h b/drivers/clk/sifive/fu540-prci.h index e0173324f3c5..d45193c210b4 100644 --- a/drivers/clk/sifive/fu540-prci.h +++ b/drivers/clk/sifive/fu540-prci.h @@ -49,7 +49,7 @@ static struct __prci_wrpll_data sifive_fu540_prci_gemgxlpll_data = { static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = { .set_rate = sifive_prci_wrpll_set_rate, - .round_rate = sifive_prci_wrpll_round_rate, + .determine_rate = sifive_prci_wrpll_determine_rate, .recalc_rate = sifive_prci_wrpll_recalc_rate, .enable = sifive_prci_clock_enable, .disable = sifive_prci_clock_disable, diff --git a/drivers/clk/sifive/fu740-prci.h b/drivers/clk/sifive/fu740-prci.h index f31cd30fc395..c605a899d97d 100644 --- a/drivers/clk/sifive/fu740-prci.h +++ b/drivers/clk/sifive/fu740-prci.h @@ -55,7 +55,7 @@ static struct __prci_wrpll_data sifive_fu740_prci_cltxpll_data = { static const struct clk_ops sifive_fu740_prci_wrpll_clk_ops = { .set_rate = sifive_prci_wrpll_set_rate, - .round_rate = sifive_prci_wrpll_round_rate, + .determine_rate = sifive_prci_wrpll_determine_rate, .recalc_rate = sifive_prci_wrpll_recalc_rate, .enable = sifive_prci_clock_enable, .disable = sifive_prci_clock_disable, diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c index caba0400f8a2..4d1cc7adb2b3 100644 --- a/drivers/clk/sifive/sifive-prci.c +++ b/drivers/clk/sifive/sifive-prci.c @@ -183,9 +183,8 @@ unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw, return wrpll_calc_output_rate(&pwd->c, parent_rate); } -long sifive_prci_wrpll_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *parent_rate) +int sifive_prci_wrpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct __prci_clock *pc = clk_hw_to_prci_clock(hw); struct __prci_wrpll_data *pwd = pc->pwd; @@ -193,9 +192,11 @@ long sifive_prci_wrpll_round_rate(struct clk_hw *hw, memcpy(&c, &pwd->c, sizeof(c)); - wrpll_configure_for_rate(&c, rate, *parent_rate); + wrpll_configure_for_rate(&c, req->rate, req->best_parent_rate); - return wrpll_calc_output_rate(&c, *parent_rate); + req->rate = wrpll_calc_output_rate(&c, req->best_parent_rate); + + return 0; } int sifive_prci_wrpll_set_rate(struct clk_hw *hw, diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h index 91658a88af4e..d74b2bddd08a 100644 --- a/drivers/clk/sifive/sifive-prci.h +++ b/drivers/clk/sifive/sifive-prci.h @@ -291,8 +291,8 @@ void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd); void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd); /* Linux clock framework integration */ -long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate); +int sifive_prci_wrpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req); int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate); int sifive_clk_is_enabled(struct clk_hw *hw); From 897c23b906cdc271380cef55ea81301f0dd70593 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:39 -0400 Subject: [PATCH 1072/2711] clk: sophgo: cv18xx-ip: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Alexander Sverdlin Signed-off-by: Brian Masney --- drivers/clk/sophgo/clk-cv18xx-ip.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/clk/sophgo/clk-cv18xx-ip.c b/drivers/clk/sophgo/clk-cv18xx-ip.c index b186e64d4813..c2b58faf0938 100644 --- a/drivers/clk/sophgo/clk-cv18xx-ip.c +++ b/drivers/clk/sophgo/clk-cv18xx-ip.c @@ -45,10 +45,12 @@ static unsigned long gate_recalc_rate(struct clk_hw *hw, return parent_rate; } -static long gate_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int gate_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - return *parent_rate; + req->rate = req->best_parent_rate; + + return 0; } static int gate_set_rate(struct clk_hw *hw, unsigned long rate, @@ -63,7 +65,7 @@ const struct clk_ops cv1800_clk_gate_ops = { .is_enabled = gate_is_enabled, .recalc_rate = gate_recalc_rate, - .round_rate = gate_round_rate, + .determine_rate = gate_determine_rate, .set_rate = gate_set_rate, }; From 19271e0d45221ce5767cd9ba50334f8479f09b3a Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:44 -0400 Subject: [PATCH 1073/2711] clk: sparx5: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-sparx5.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk-sparx5.c b/drivers/clk/clk-sparx5.c index 0fad0c1a0186..b2facc9c95d4 100644 --- a/drivers/clk/clk-sparx5.c +++ b/drivers/clk/clk-sparx5.c @@ -213,19 +213,21 @@ static unsigned long s5_pll_recalc_rate(struct clk_hw *hw, return conf.freq; } -static long s5_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int s5_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct s5_pll_conf conf; - return s5_calc_params(rate, *parent_rate, &conf); + req->rate = s5_calc_params(req->rate, req->best_parent_rate, &conf); + + return 0; } static const struct clk_ops s5_pll_ops = { .enable = s5_pll_enable, .disable = s5_pll_disable, .set_rate = s5_pll_set_rate, - .round_rate = s5_pll_round_rate, + .determine_rate = s5_pll_determine_rate, .recalc_rate = s5_pll_recalc_rate, }; From deb4740a5ff89957309b0479210af7448f1846f2 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:45 -0400 Subject: [PATCH 1074/2711] clk: sprd: div: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Chunyan Zhang Signed-off-by: Brian Masney --- drivers/clk/sprd/div.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/clk/sprd/div.c b/drivers/clk/sprd/div.c index 936782c24127..013423881968 100644 --- a/drivers/clk/sprd/div.c +++ b/drivers/clk/sprd/div.c @@ -9,13 +9,16 @@ #include "div.h" -static long sprd_div_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int sprd_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct sprd_div *cd = hw_to_sprd_div(hw); - return divider_round_rate(&cd->common.hw, rate, parent_rate, NULL, - cd->div.width, 0); + req->rate = divider_round_rate(&cd->common.hw, req->rate, + &req->best_parent_rate, + NULL, cd->div.width, 0); + + return 0; } unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, @@ -75,7 +78,7 @@ static int sprd_div_set_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops sprd_div_ops = { .recalc_rate = sprd_div_recalc_rate, - .round_rate = sprd_div_round_rate, + .determine_rate = sprd_div_determine_rate, .set_rate = sprd_div_set_rate, }; EXPORT_SYMBOL_GPL(sprd_div_ops); From c349d81d6b9a0d5edcfd6183078cd18957fb0ea6 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:46 -0400 Subject: [PATCH 1075/2711] clk: sprd: pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Chunyan Zhang Signed-off-by: Brian Masney --- drivers/clk/sprd/pll.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/sprd/pll.c b/drivers/clk/sprd/pll.c index 13a322b2535a..bc6610d5fcb7 100644 --- a/drivers/clk/sprd/pll.c +++ b/drivers/clk/sprd/pll.c @@ -254,16 +254,16 @@ static int sprd_pll_clk_prepare(struct clk_hw *hw) return 0; } -static long sprd_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int sprd_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - return rate; + return 0; } const struct clk_ops sprd_pll_ops = { .prepare = sprd_pll_clk_prepare, .recalc_rate = sprd_pll_recalc_rate, - .round_rate = sprd_pll_round_rate, + .determine_rate = sprd_pll_determine_rate, .set_rate = sprd_pll_set_rate, }; EXPORT_SYMBOL_GPL(sprd_pll_ops); From 78d4c18e636833cfd3670ddd96d42d0d21318769 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:47 -0400 Subject: [PATCH 1076/2711] clk: st: clkgen-fsyn: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/st/clkgen-fsyn.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 40df1db102a7..e06e7e5cc1a5 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -375,22 +375,21 @@ static int clk_fs660c32_vco_get_params(unsigned long input, return 0; } -static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *prate) +static int quadfs_pll_fs660c32_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct stm_fs params; - if (clk_fs660c32_vco_get_params(*prate, rate, ¶ms)) - return rate; + if (clk_fs660c32_vco_get_params(req->best_parent_rate, req->rate, ¶ms)) + return 0; - clk_fs660c32_vco_get_rate(*prate, ¶ms, &rate); + clk_fs660c32_vco_get_rate(req->best_parent_rate, ¶ms, &req->rate); pr_debug("%s: %s new rate %ld [ndiv=%u]\n", __func__, clk_hw_get_name(hw), - rate, (unsigned int)params.ndiv); + req->rate, (unsigned int)params.ndiv); - return rate; + return 0; } static int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate, @@ -436,7 +435,7 @@ static const struct clk_ops st_quadfs_pll_c32_ops = { .disable = quadfs_pll_disable, .is_enabled = quadfs_pll_is_enabled, .recalc_rate = quadfs_pll_fs660c32_recalc_rate, - .round_rate = quadfs_pll_fs660c32_round_rate, + .determine_rate = quadfs_pll_fs660c32_determine_rate, .set_rate = quadfs_pll_fs660c32_set_rate, }; @@ -814,19 +813,21 @@ static unsigned long quadfs_recalc_rate(struct clk_hw *hw, return rate; } -static long quadfs_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int quadfs_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct stm_fs params; - rate = quadfs_find_best_rate(hw, rate, *prate, ¶ms); + req->rate = quadfs_find_best_rate(hw, req->rate, + req->best_parent_rate, ¶ms); pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n", __func__, clk_hw_get_name(hw), - rate, (unsigned int)params.sdiv, (unsigned int)params.mdiv, - (unsigned int)params.pe, (unsigned int)params.nsdiv); + req->rate, (unsigned int)params.sdiv, + (unsigned int)params.mdiv, + (unsigned int)params.pe, (unsigned int)params.nsdiv); - return rate; + return 0; } @@ -873,7 +874,7 @@ static const struct clk_ops st_quadfs_ops = { .enable = quadfs_fsynth_enable, .disable = quadfs_fsynth_disable, .is_enabled = quadfs_fsynth_is_enabled, - .round_rate = quadfs_round_rate, + .determine_rate = quadfs_determine_rate, .set_rate = quadfs_set_rate, .recalc_rate = quadfs_recalc_rate, }; From 639baa3ce27f43224a9e7904d85395935dd4b04f Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:48 -0400 Subject: [PATCH 1077/2711] clk: st: clkgen-pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Note that prior to running the Coccinelle: - round_rate_stm_pll4600c28() was renamed to stm_pll4600c28_round_rate() - round_rate_stm_pll3200c32() was renamed to stm_pll3200c32_round_rate() Signed-off-by: Brian Masney --- drivers/clk/st/clkgen-pll.c | 38 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c index b36e4d803636..c258ff87a171 100644 --- a/drivers/clk/st/clkgen-pll.c +++ b/drivers/clk/st/clkgen-pll.c @@ -395,25 +395,28 @@ static unsigned long recalc_stm_pll3200c32(struct clk_hw *hw, return rate; } -static long round_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int stm_pll3200c32_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct stm_pll params; - if (!clk_pll3200c32_get_params(*prate, rate, ¶ms)) - clk_pll3200c32_get_rate(*prate, ¶ms, &rate); + if (!clk_pll3200c32_get_params(req->best_parent_rate, req->rate, ¶ms)) + clk_pll3200c32_get_rate(req->best_parent_rate, ¶ms, + &req->rate); else { pr_debug("%s: %s rate %ld Invalid\n", __func__, - __clk_get_name(hw->clk), rate); + __clk_get_name(hw->clk), req->rate); + req->rate = 0; + return 0; } pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n", __func__, __clk_get_name(hw->clk), - rate, (unsigned int)params.ndiv, + req->rate, (unsigned int)params.ndiv, (unsigned int)params.idf); - return rate; + return 0; } static int set_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate, @@ -549,25 +552,28 @@ static unsigned long recalc_stm_pll4600c28(struct clk_hw *hw, return rate; } -static long round_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int stm_pll4600c28_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct stm_pll params; - if (!clk_pll4600c28_get_params(*prate, rate, ¶ms)) { - clk_pll4600c28_get_rate(*prate, ¶ms, &rate); + if (!clk_pll4600c28_get_params(req->best_parent_rate, req->rate, ¶ms)) { + clk_pll4600c28_get_rate(req->best_parent_rate, ¶ms, + &req->rate); } else { pr_debug("%s: %s rate %ld Invalid\n", __func__, - __clk_get_name(hw->clk), rate); + __clk_get_name(hw->clk), req->rate); + req->rate = 0; + return 0; } pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n", __func__, __clk_get_name(hw->clk), - rate, (unsigned int)params.ndiv, + req->rate, (unsigned int)params.ndiv, (unsigned int)params.idf); - return rate; + return 0; } static int set_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate, @@ -628,7 +634,7 @@ static const struct clk_ops stm_pll3200c32_a9_ops = { .disable = clkgen_pll_disable, .is_enabled = clkgen_pll_is_enabled, .recalc_rate = recalc_stm_pll3200c32, - .round_rate = round_rate_stm_pll3200c32, + .determine_rate = stm_pll3200c32_determine_rate, .set_rate = set_rate_stm_pll3200c32, }; @@ -637,7 +643,7 @@ static const struct clk_ops stm_pll4600c28_ops = { .disable = clkgen_pll_disable, .is_enabled = clkgen_pll_is_enabled, .recalc_rate = recalc_stm_pll4600c28, - .round_rate = round_rate_stm_pll4600c28, + .determine_rate = stm_pll4600c28_determine_rate, .set_rate = set_rate_stm_pll4600c28, }; From 028b0eb1c9e66470f9a15e758a3757d13911919b Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:49 -0400 Subject: [PATCH 1078/2711] clk: stm32f4: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-stm32f4.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index 719cddc82ae6..b5d4d48432a0 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -443,8 +443,8 @@ static unsigned long clk_apb_mul_recalc_rate(struct clk_hw *hw, return parent_rate; } -static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_apb_mul_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_apb_mul *am = to_clk_apb_mul(hw); unsigned long mult = 1; @@ -453,12 +453,14 @@ static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate, mult = 2; if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { - unsigned long best_parent = rate / mult; + unsigned long best_parent = req->rate / mult; - *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); + req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); } - return *prate * mult; + req->rate = req->best_parent_rate * mult; + + return 0; } static int clk_apb_mul_set_rate(struct clk_hw *hw, unsigned long rate, @@ -474,7 +476,7 @@ static int clk_apb_mul_set_rate(struct clk_hw *hw, unsigned long rate, } static const struct clk_ops clk_apb_mul_factor_ops = { - .round_rate = clk_apb_mul_round_rate, + .determine_rate = clk_apb_mul_determine_rate, .set_rate = clk_apb_mul_set_rate, .recalc_rate = clk_apb_mul_recalc_rate, }; @@ -670,21 +672,23 @@ static unsigned long stm32f4_pll_recalc(struct clk_hw *hw, return parent_rate * n; } -static long stm32f4_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int stm32f4_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_gate *gate = to_clk_gate(hw); struct stm32f4_pll *pll = to_stm32f4_pll(gate); unsigned long n; - n = rate / *prate; + n = req->rate / req->best_parent_rate; if (n < pll->n_start) n = pll->n_start; else if (n > 432) n = 432; - return *prate * n; + req->rate = req->best_parent_rate * n; + + return 0; } static void stm32f4_pll_set_ssc(struct clk_hw *hw, unsigned long parent_rate, @@ -749,7 +753,7 @@ static const struct clk_ops stm32f4_pll_gate_ops = { .disable = stm32f4_pll_disable, .is_enabled = stm32f4_pll_is_enabled, .recalc_rate = stm32f4_pll_recalc, - .round_rate = stm32f4_pll_round_rate, + .determine_rate = stm32f4_pll_determine_rate, .set_rate = stm32f4_pll_set_rate, }; From cd1cb38836c0fc597718f300f7d19fcea1117a3c Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:50 -0400 Subject: [PATCH 1079/2711] clk: stm32: stm32-core: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Gabriel Fernandez Signed-off-by: Brian Masney --- drivers/clk/stm32/clk-stm32-core.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c index 933e3cde0795..72825b9c36a4 100644 --- a/drivers/clk/stm32/clk-stm32-core.c +++ b/drivers/clk/stm32/clk-stm32-core.c @@ -351,14 +351,14 @@ static int clk_stm32_divider_set_rate(struct clk_hw *hw, unsigned long rate, return ret; } -static long clk_stm32_divider_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_stm32_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_stm32_div *div = to_clk_stm32_divider(hw); const struct stm32_div_cfg *divider; if (div->div_id == NO_STM32_DIV) - return rate; + return 0; divider = &div->clock_data->dividers[div->div_id]; @@ -369,14 +369,22 @@ static long clk_stm32_divider_round_rate(struct clk_hw *hw, unsigned long rate, val = readl(div->base + divider->offset) >> divider->shift; val &= clk_div_mask(divider->width); - return divider_ro_round_rate(hw, rate, prate, divider->table, - divider->width, divider->flags, - val); + req->rate = divider_ro_round_rate(hw, req->rate, + &req->best_parent_rate, + divider->table, + divider->width, + divider->flags, val); + + return 0; } - return divider_round_rate_parent(hw, clk_hw_get_parent(hw), - rate, prate, divider->table, - divider->width, divider->flags); + req->rate = divider_round_rate_parent(hw, clk_hw_get_parent(hw), + req->rate, + &req->best_parent_rate, + divider->table, + divider->width, divider->flags); + + return 0; } static unsigned long clk_stm32_divider_recalc_rate(struct clk_hw *hw, @@ -392,7 +400,7 @@ static unsigned long clk_stm32_divider_recalc_rate(struct clk_hw *hw, const struct clk_ops clk_stm32_divider_ops = { .recalc_rate = clk_stm32_divider_recalc_rate, - .round_rate = clk_stm32_divider_round_rate, + .determine_rate = clk_stm32_divider_determine_rate, .set_rate = clk_stm32_divider_set_rate, }; From 81c438b53bfdcf915475c14e9e3ad409c665de06 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:51 -0400 Subject: [PATCH 1080/2711] clk: stm32: stm32mp1: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Gabriel Fernandez Signed-off-by: Brian Masney --- drivers/clk/stm32/clk-stm32mp1.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/clk/stm32/clk-stm32mp1.c b/drivers/clk/stm32/clk-stm32mp1.c index b8b45ed22f98..2d9ccd96ec98 100644 --- a/drivers/clk/stm32/clk-stm32mp1.c +++ b/drivers/clk/stm32/clk-stm32mp1.c @@ -970,12 +970,15 @@ static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate, return mult; } -static long timer_ker_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int timer_ker_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned long factor = __bestmult(hw, rate, *parent_rate); + unsigned long factor = __bestmult(hw, req->rate, + req->best_parent_rate); - return *parent_rate * factor; + req->rate = req->best_parent_rate * factor; + + return 0; } static int timer_ker_set_rate(struct clk_hw *hw, unsigned long rate, @@ -1026,7 +1029,7 @@ static unsigned long timer_ker_recalc_rate(struct clk_hw *hw, static const struct clk_ops timer_ker_ops = { .recalc_rate = timer_ker_recalc_rate, - .round_rate = timer_ker_round_rate, + .determine_rate = timer_ker_determine_rate, .set_rate = timer_ker_set_rate, }; From eb785c6f395b98f4d1b6c8e2575e03676711736d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:52 -0400 Subject: [PATCH 1081/2711] clk: tps68470: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-tps68470.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-tps68470.c b/drivers/clk/clk-tps68470.c index 38f44b5b9b1b..9511248c6bc9 100644 --- a/drivers/clk/clk-tps68470.c +++ b/drivers/clk/clk-tps68470.c @@ -146,12 +146,14 @@ static unsigned int tps68470_clk_cfg_lookup(unsigned long rate) return best_idx; } -static long tps68470_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int tps68470_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned int idx = tps68470_clk_cfg_lookup(rate); + unsigned int idx = tps68470_clk_cfg_lookup(req->rate); - return clk_freqs[idx].freq; + req->rate = clk_freqs[idx].freq; + + return 0; } static int tps68470_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -186,7 +188,7 @@ static const struct clk_ops tps68470_clk_ops = { .prepare = tps68470_clk_prepare, .unprepare = tps68470_clk_unprepare, .recalc_rate = tps68470_clk_recalc_rate, - .round_rate = tps68470_clk_round_rate, + .determine_rate = tps68470_clk_determine_rate, .set_rate = tps68470_clk_set_rate, }; From 9e3372b2ebac86591a41151bdd073a9942ca9a46 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:53 -0400 Subject: [PATCH 1082/2711] clk: versaclock3: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-versaclock3.c | 70 ++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c index 9fe27dace111..1849863dbd67 100644 --- a/drivers/clk/clk-versaclock3.c +++ b/drivers/clk/clk-versaclock3.c @@ -289,22 +289,25 @@ static unsigned long vc3_pfd_recalc_rate(struct clk_hw *hw, return rate; } -static long vc3_pfd_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int vc3_pfd_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); const struct vc3_pfd_data *pfd = vc3->data; unsigned long idiv; /* PLL cannot operate with input clock above 50 MHz. */ - if (rate > 50000000) + if (req->rate > 50000000) return -EINVAL; /* CLKIN within range of PLL input, feed directly to PLL. */ - if (*parent_rate <= 50000000) - return *parent_rate; + if (req->best_parent_rate <= 50000000) { + req->rate = req->best_parent_rate; - idiv = DIV_ROUND_UP(*parent_rate, rate); + return 0; + } + + idiv = DIV_ROUND_UP(req->best_parent_rate, req->rate); if (pfd->num == VC3_PFD1 || pfd->num == VC3_PFD3) { if (idiv > 63) return -EINVAL; @@ -313,7 +316,9 @@ static long vc3_pfd_round_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; } - return *parent_rate / idiv; + req->rate = req->best_parent_rate / idiv; + + return 0; } static int vc3_pfd_set_rate(struct clk_hw *hw, unsigned long rate, @@ -354,7 +359,7 @@ static int vc3_pfd_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops vc3_pfd_ops = { .recalc_rate = vc3_pfd_recalc_rate, - .round_rate = vc3_pfd_round_rate, + .determine_rate = vc3_pfd_determine_rate, .set_rate = vc3_pfd_set_rate, }; @@ -385,36 +390,38 @@ static unsigned long vc3_pll_recalc_rate(struct clk_hw *hw, return rate; } -static long vc3_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int vc3_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); const struct vc3_pll_data *pll = vc3->data; u64 div_frc; - if (rate < pll->vco.min) - rate = pll->vco.min; - if (rate > pll->vco.max) - rate = pll->vco.max; + if (req->rate < pll->vco.min) + req->rate = pll->vco.min; + if (req->rate > pll->vco.max) + req->rate = pll->vco.max; - vc3->div_int = rate / *parent_rate; + vc3->div_int = req->rate / req->best_parent_rate; if (pll->num == VC3_PLL2) { if (vc3->div_int > 0x7ff) - rate = *parent_rate * 0x7ff; + req->rate = req->best_parent_rate * 0x7ff; /* Determine best fractional part, which is 16 bit wide */ - div_frc = rate % *parent_rate; + div_frc = req->rate % req->best_parent_rate; div_frc *= BIT(16) - 1; - vc3->div_frc = min_t(u64, div64_ul(div_frc, *parent_rate), U16_MAX); - rate = (*parent_rate * - (vc3->div_int * VC3_2_POW_16 + vc3->div_frc) / VC3_2_POW_16); + vc3->div_frc = min_t(u64, + div64_ul(div_frc, req->best_parent_rate), + U16_MAX); + req->rate = (req->best_parent_rate * + (vc3->div_int * VC3_2_POW_16 + vc3->div_frc) / VC3_2_POW_16); } else { - rate = *parent_rate * vc3->div_int; + req->rate = req->best_parent_rate * vc3->div_int; } - return rate; + return 0; } static int vc3_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -441,7 +448,7 @@ static int vc3_pll_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops vc3_pll_ops = { .recalc_rate = vc3_pll_recalc_rate, - .round_rate = vc3_pll_round_rate, + .determine_rate = vc3_pll_determine_rate, .set_rate = vc3_pll_set_rate, }; @@ -498,8 +505,8 @@ static unsigned long vc3_div_recalc_rate(struct clk_hw *hw, div_data->flags, div_data->width); } -static long vc3_div_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int vc3_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); const struct vc3_div_data *div_data = vc3->data; @@ -511,11 +518,16 @@ static long vc3_div_round_rate(struct clk_hw *hw, unsigned long rate, bestdiv >>= div_data->shift; bestdiv &= VC3_DIV_MASK(div_data->width); bestdiv = vc3_get_div(div_data->table, bestdiv, div_data->flags); - return DIV_ROUND_UP(*parent_rate, bestdiv); + req->rate = DIV_ROUND_UP(req->best_parent_rate, bestdiv); + + return 0; } - return divider_round_rate(hw, rate, parent_rate, div_data->table, - div_data->width, div_data->flags); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + div_data->table, + div_data->width, div_data->flags); + + return 0; } static int vc3_div_set_rate(struct clk_hw *hw, unsigned long rate, @@ -534,7 +546,7 @@ static int vc3_div_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops vc3_div_ops = { .recalc_rate = vc3_div_recalc_rate, - .round_rate = vc3_div_round_rate, + .determine_rate = vc3_div_determine_rate, .set_rate = vc3_div_set_rate, }; From ff03cca71ebd54eba32ba7628bc7b3ee1cc2e79f Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:54 -0400 Subject: [PATCH 1083/2711] clk: vt8500: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-vt8500.c | 59 ++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c index 2a74a713ad59..eae5b3fbfb82 100644 --- a/drivers/clk/clk-vt8500.c +++ b/drivers/clk/clk-vt8500.c @@ -128,30 +128,31 @@ static unsigned long vt8500_dclk_recalc_rate(struct clk_hw *hw, return parent_rate / div; } -static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int vt8500_dclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_device *cdev = to_clk_device(hw); u32 divisor; - if (rate == 0) + if (req->rate == 0) return 0; - divisor = *prate / rate; + divisor = req->best_parent_rate / req->rate; /* If prate / rate would be decimal, incr the divisor */ - if (rate * divisor < *prate) + if (req->rate * divisor < req->best_parent_rate) divisor++; /* * If this is a request for SDMMC we have to adjust the divisor * when >31 to use the fixed predivisor */ - if ((cdev->div_mask == 0x3F) && (divisor > 31)) { + if ((cdev->div_mask == 0x3F) && (divisor > 31)) divisor = 64 * ((divisor / 64) + 1); - } - return *prate / divisor; + req->rate = req->best_parent_rate / divisor; + + return 0; } static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -202,7 +203,7 @@ static const struct clk_ops vt8500_gated_clk_ops = { }; static const struct clk_ops vt8500_divisor_clk_ops = { - .round_rate = vt8500_dclk_round_rate, + .determine_rate = vt8500_dclk_determine_rate, .set_rate = vt8500_dclk_set_rate, .recalc_rate = vt8500_dclk_recalc_rate, }; @@ -211,7 +212,7 @@ static const struct clk_ops vt8500_gated_divisor_clk_ops = { .enable = vt8500_dclk_enable, .disable = vt8500_dclk_disable, .is_enabled = vt8500_dclk_is_enabled, - .round_rate = vt8500_dclk_round_rate, + .determine_rate = vt8500_dclk_determine_rate, .set_rate = vt8500_dclk_set_rate, .recalc_rate = vt8500_dclk_recalc_rate, }; @@ -594,8 +595,8 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int vtwm_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_pll *pll = to_clk_pll(hw); u32 filter, mul, div1, div2; @@ -604,33 +605,43 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate, switch (pll->type) { case PLL_TYPE_VT8500: - ret = vt8500_find_pll_bits(rate, *prate, &mul, &div1); + ret = vt8500_find_pll_bits(req->rate, req->best_parent_rate, + &mul, &div1); if (!ret) - round_rate = VT8500_BITS_TO_FREQ(*prate, mul, div1); + round_rate = VT8500_BITS_TO_FREQ(req->best_parent_rate, + mul, div1); break; case PLL_TYPE_WM8650: - ret = wm8650_find_pll_bits(rate, *prate, &mul, &div1, &div2); + ret = wm8650_find_pll_bits(req->rate, req->best_parent_rate, + &mul, &div1, &div2); if (!ret) - round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2); + round_rate = WM8650_BITS_TO_FREQ(req->best_parent_rate, + mul, div1, div2); break; case PLL_TYPE_WM8750: - ret = wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2); + ret = wm8750_find_pll_bits(req->rate, req->best_parent_rate, + &filter, &mul, &div1, &div2); if (!ret) - round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2); + round_rate = WM8750_BITS_TO_FREQ(req->best_parent_rate, + mul, div1, div2); break; case PLL_TYPE_WM8850: - ret = wm8850_find_pll_bits(rate, *prate, &mul, &div1, &div2); + ret = wm8850_find_pll_bits(req->rate, req->best_parent_rate, + &mul, &div1, &div2); if (!ret) - round_rate = WM8850_BITS_TO_FREQ(*prate, mul, div1, div2); + round_rate = WM8850_BITS_TO_FREQ(req->best_parent_rate, + mul, div1, div2); break; default: - ret = -EINVAL; + return -EINVAL; } if (ret) - return ret; + req->rate = ret; + else + req->rate = round_rate; - return round_rate; + return 0; } static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw, @@ -665,7 +676,7 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw, } static const struct clk_ops vtwm_pll_ops = { - .round_rate = vtwm_pll_round_rate, + .determine_rate = vtwm_pll_determine_rate, .set_rate = vtwm_pll_set_rate, .recalc_rate = vtwm_pll_recalc_rate, }; From d616db080a0b9e006c2b3f57a2a8f3bfc67dc8e0 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:55 -0400 Subject: [PATCH 1084/2711] clk: wm831x: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Richard Fitzgerald Signed-off-by: Brian Masney --- drivers/clk/clk-wm831x.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index 34e9d4d541e2..263e927138c2 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -133,18 +133,20 @@ static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw, return 0; } -static long wm831x_fll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *unused) +static int wm831x_fll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int best = 0; int i; for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++) - if (abs(wm831x_fll_auto_rates[i] - rate) < - abs(wm831x_fll_auto_rates[best] - rate)) + if (abs(wm831x_fll_auto_rates[i] - req->rate) < + abs(wm831x_fll_auto_rates[best] - req->rate)) best = i; - return wm831x_fll_auto_rates[best]; + req->rate = wm831x_fll_auto_rates[best]; + + return 0; } static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -214,7 +216,7 @@ static const struct clk_ops wm831x_fll_ops = { .is_prepared = wm831x_fll_is_prepared, .prepare = wm831x_fll_prepare, .unprepare = wm831x_fll_unprepare, - .round_rate = wm831x_fll_round_rate, + .determine_rate = wm831x_fll_determine_rate, .recalc_rate = wm831x_fll_recalc_rate, .set_rate = wm831x_fll_set_rate, .get_parent = wm831x_fll_get_parent, From f95ed76fbe61ee473ed682f93de3578cf6c60a1a Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:57 -0400 Subject: [PATCH 1085/2711] clk: xgene: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-xgene.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index 96946a8e2854..92e39f3237c2 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -271,23 +271,28 @@ static unsigned long xgene_clk_pmd_recalc_rate(struct clk_hw *hw, return ret; } -static long xgene_clk_pmd_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int xgene_clk_pmd_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw); u64 ret, scale; - if (!rate || rate >= *parent_rate) - return *parent_rate; + if (!req->rate || req->rate >= req->best_parent_rate) { + req->rate = req->best_parent_rate; + + return 0; + } /* freq = parent_rate * scaler / denom */ - ret = rate * fd->denom; - scale = DIV_ROUND_UP_ULL(ret, *parent_rate); + ret = req->rate * fd->denom; + scale = DIV_ROUND_UP_ULL(ret, req->best_parent_rate); - ret = (u64)*parent_rate * scale; + ret = (u64)req->best_parent_rate * scale; do_div(ret, fd->denom); - return ret; + req->rate = ret; + + return 0; } static int xgene_clk_pmd_set_rate(struct clk_hw *hw, unsigned long rate, @@ -333,7 +338,7 @@ static int xgene_clk_pmd_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops xgene_clk_pmd_ops = { .recalc_rate = xgene_clk_pmd_recalc_rate, - .round_rate = xgene_clk_pmd_round_rate, + .determine_rate = xgene_clk_pmd_determine_rate, .set_rate = xgene_clk_pmd_set_rate, }; @@ -593,23 +598,25 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate, return parent_rate / divider_save; } -static long xgene_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int xgene_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct xgene_clk *pclk = to_xgene_clk(hw); - unsigned long parent_rate = *prate; + unsigned long parent_rate = req->best_parent_rate; u32 divider; if (pclk->param.divider_reg) { /* Let's compute the divider */ - if (rate > parent_rate) - rate = parent_rate; - divider = parent_rate / rate; /* Rounded down */ + if (req->rate > parent_rate) + req->rate = parent_rate; + divider = parent_rate / req->rate; /* Rounded down */ } else { divider = 1; } - return parent_rate / divider; + req->rate = parent_rate / divider; + + return 0; } static const struct clk_ops xgene_clk_ops = { @@ -618,7 +625,7 @@ static const struct clk_ops xgene_clk_ops = { .is_enabled = xgene_clk_is_enabled, .recalc_rate = xgene_clk_recalc_rate, .set_rate = xgene_clk_set_rate, - .round_rate = xgene_clk_round_rate, + .determine_rate = xgene_clk_determine_rate, }; static struct clk *xgene_register_clk(struct device *dev, From 18fdeebb4d1d3d30a0c2994e8150ce1f85e7d8c1 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:58 -0400 Subject: [PATCH 1086/2711] clk: xilinx: xlnx-clock-wizard: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 55 ++++++++++++---------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c index 0295a13a811c..3ee14770212a 100644 --- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c +++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c @@ -322,8 +322,8 @@ err_reconfig: return err; } -static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_wzrd_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u8 div; @@ -331,9 +331,11 @@ static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate, * since we don't change parent rate we just round rate to closest * achievable */ - div = DIV_ROUND_CLOSEST(*prate, rate); + div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate); - return *prate / div; + req->rate = req->best_parent_rate / div; + + return 0; } static int clk_wzrd_get_divisors_ver(struct clk_hw *hw, unsigned long rate, @@ -642,14 +644,14 @@ static unsigned long clk_wzrd_recalc_rate_all_ver(struct clk_hw *hw, divider->flags, divider->width); } -static long clk_wzrd_round_rate_all(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_wzrd_determine_rate_all(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); u32 m, d, o; int err; - err = clk_wzrd_get_divisors(hw, rate, *prate); + err = clk_wzrd_get_divisors(hw, req->rate, req->best_parent_rate); if (err) return err; @@ -657,19 +659,20 @@ static long clk_wzrd_round_rate_all(struct clk_hw *hw, unsigned long rate, d = divider->d; o = divider->o; - rate = div_u64(*prate * (m * 1000 + divider->m_frac), d * (o * 1000 + divider->o_frac)); - return rate; + req->rate = div_u64(req->best_parent_rate * (m * 1000 + divider->m_frac), + d * (o * 1000 + divider->o_frac)); + return 0; } -static long clk_wzrd_ver_round_rate_all(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_wzrd_ver_determine_rate_all(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); unsigned long int_freq; u32 m, d, o, div, f; int err; - err = clk_wzrd_get_divisors_ver(hw, rate, *prate); + err = clk_wzrd_get_divisors_ver(hw, req->rate, req->best_parent_rate); if (err) return err; @@ -678,36 +681,38 @@ static long clk_wzrd_ver_round_rate_all(struct clk_hw *hw, unsigned long rate, o = divider->o; div = d * o; - int_freq = divider_recalc_rate(hw, *prate * m, div, divider->table, + int_freq = divider_recalc_rate(hw, req->best_parent_rate * m, div, + divider->table, divider->flags, divider->width); - if (rate > int_freq) { - f = DIV_ROUND_CLOSEST_ULL(rate * WZRD_FRAC_POINTS, int_freq); - rate = DIV_ROUND_CLOSEST(int_freq * f, WZRD_FRAC_POINTS); + if (req->rate > int_freq) { + f = DIV_ROUND_CLOSEST_ULL(req->rate * WZRD_FRAC_POINTS, + int_freq); + req->rate = DIV_ROUND_CLOSEST(int_freq * f, WZRD_FRAC_POINTS); } - return rate; + return 0; } static const struct clk_ops clk_wzrd_ver_divider_ops = { - .round_rate = clk_wzrd_round_rate, + .determine_rate = clk_wzrd_determine_rate, .set_rate = clk_wzrd_ver_dynamic_reconfig, .recalc_rate = clk_wzrd_recalc_rate_ver, }; static const struct clk_ops clk_wzrd_ver_div_all_ops = { - .round_rate = clk_wzrd_ver_round_rate_all, + .determine_rate = clk_wzrd_ver_determine_rate_all, .set_rate = clk_wzrd_dynamic_all_ver, .recalc_rate = clk_wzrd_recalc_rate_all_ver, }; static const struct clk_ops clk_wzrd_clk_divider_ops = { - .round_rate = clk_wzrd_round_rate, + .determine_rate = clk_wzrd_determine_rate, .set_rate = clk_wzrd_dynamic_reconfig, .recalc_rate = clk_wzrd_recalc_rate, }; static const struct clk_ops clk_wzrd_clk_div_all_ops = { - .round_rate = clk_wzrd_round_rate_all, + .determine_rate = clk_wzrd_determine_rate_all, .set_rate = clk_wzrd_dynamic_all, .recalc_rate = clk_wzrd_recalc_rate_all, }; @@ -769,14 +774,14 @@ static int clk_wzrd_dynamic_reconfig_f(struct clk_hw *hw, unsigned long rate, WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); } -static long clk_wzrd_round_rate_f(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_wzrd_determine_rate_f(struct clk_hw *hw, + struct clk_rate_request *req) { - return rate; + return 0; } static const struct clk_ops clk_wzrd_clk_divider_ops_f = { - .round_rate = clk_wzrd_round_rate_f, + .determine_rate = clk_wzrd_determine_rate_f, .set_rate = clk_wzrd_dynamic_reconfig_f, .recalc_rate = clk_wzrd_recalc_ratef, }; From 5352b65041cbb546d8c4d386762370e6ad0d1f42 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:18:59 -0400 Subject: [PATCH 1087/2711] clk: xilinx: xlnx_vcu: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/xilinx/xlnx_vcu.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/clk/xilinx/xlnx_vcu.c b/drivers/clk/xilinx/xlnx_vcu.c index 1ded67bee06c..02699bc0f82c 100644 --- a/drivers/clk/xilinx/xlnx_vcu.c +++ b/drivers/clk/xilinx/xlnx_vcu.c @@ -311,18 +311,21 @@ static int xvcu_pll_set_div(struct vcu_pll *pll, int div) return 0; } -static long xvcu_pll_round_rate(struct clk_hw *hw, - unsigned long rate, unsigned long *parent_rate) +static int xvcu_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct vcu_pll *pll = to_vcu_pll(hw); unsigned int feedback_div; - rate = clamp_t(unsigned long, rate, pll->fvco_min, pll->fvco_max); + req->rate = clamp_t(unsigned long, req->rate, pll->fvco_min, + pll->fvco_max); - feedback_div = DIV_ROUND_CLOSEST_ULL(rate, *parent_rate); + feedback_div = DIV_ROUND_CLOSEST_ULL(req->rate, req->best_parent_rate); feedback_div = clamp_t(unsigned int, feedback_div, 25, 125); - return *parent_rate * feedback_div; + req->rate = req->best_parent_rate * feedback_div; + + return 0; } static unsigned long xvcu_pll_recalc_rate(struct clk_hw *hw, @@ -394,7 +397,7 @@ static void xvcu_pll_disable(struct clk_hw *hw) static const struct clk_ops vcu_pll_ops = { .enable = xvcu_pll_enable, .disable = xvcu_pll_disable, - .round_rate = xvcu_pll_round_rate, + .determine_rate = xvcu_pll_determine_rate, .recalc_rate = xvcu_pll_recalc_rate, .set_rate = xvcu_pll_set_rate, }; From 193650c7a87339da14e34b5fe81585535ee77708 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:01 -0400 Subject: [PATCH 1088/2711] clk: zynqmp: pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/zynqmp/pll.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/clk/zynqmp/pll.c b/drivers/clk/zynqmp/pll.c index 7411a7fd50ac..630a3936c97c 100644 --- a/drivers/clk/zynqmp/pll.c +++ b/drivers/clk/zynqmp/pll.c @@ -98,29 +98,29 @@ static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on) * * Return: Frequency closest to @rate the hardware can generate */ -static long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int zynqmp_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u32 fbdiv; u32 mult, div; /* Let rate fall inside the range PS_PLL_VCO_MIN ~ PS_PLL_VCO_MAX */ - if (rate > PS_PLL_VCO_MAX) { - div = DIV_ROUND_UP(rate, PS_PLL_VCO_MAX); - rate = rate / div; + if (req->rate > PS_PLL_VCO_MAX) { + div = DIV_ROUND_UP(req->rate, PS_PLL_VCO_MAX); + req->rate = req->rate / div; } - if (rate < PS_PLL_VCO_MIN) { - mult = DIV_ROUND_UP(PS_PLL_VCO_MIN, rate); - rate = rate * mult; + if (req->rate < PS_PLL_VCO_MIN) { + mult = DIV_ROUND_UP(PS_PLL_VCO_MIN, req->rate); + req->rate = req->rate * mult; } - fbdiv = DIV_ROUND_CLOSEST(rate, *prate); + fbdiv = DIV_ROUND_CLOSEST(req->rate, req->best_parent_rate); if (fbdiv < PLL_FBDIV_MIN || fbdiv > PLL_FBDIV_MAX) { fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX); - rate = *prate * fbdiv; + req->rate = req->best_parent_rate * fbdiv; } - return rate; + return 0; } /** @@ -294,7 +294,7 @@ static const struct clk_ops zynqmp_pll_ops = { .enable = zynqmp_pll_enable, .disable = zynqmp_pll_disable, .is_enabled = zynqmp_pll_is_enabled, - .round_rate = zynqmp_pll_round_rate, + .determine_rate = zynqmp_pll_determine_rate, .recalc_rate = zynqmp_pll_recalc_rate, .set_rate = zynqmp_pll_set_rate, }; From 1547747b55d5d6c045cd94f4c4595b8f38d3b21c Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:02 -0400 Subject: [PATCH 1089/2711] clk: zynq: pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/zynq/pll.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/zynq/pll.c b/drivers/clk/zynq/pll.c index e5f8fb704df2..5eca1c14981a 100644 --- a/drivers/clk/zynq/pll.c +++ b/drivers/clk/zynq/pll.c @@ -48,18 +48,20 @@ struct zynq_pll { * @prate: Clock frequency of parent clock * Return: frequency closest to @rate the hardware can generate. */ -static long zynq_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int zynq_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u32 fbdiv; - fbdiv = DIV_ROUND_CLOSEST(rate, *prate); + fbdiv = DIV_ROUND_CLOSEST(req->rate, req->best_parent_rate); if (fbdiv < PLL_FBDIV_MIN) fbdiv = PLL_FBDIV_MIN; else if (fbdiv > PLL_FBDIV_MAX) fbdiv = PLL_FBDIV_MAX; - return *prate * fbdiv; + req->rate = req->best_parent_rate * fbdiv; + + return 0; } /** @@ -167,7 +169,7 @@ static const struct clk_ops zynq_pll_ops = { .enable = zynq_pll_enable, .disable = zynq_pll_disable, .is_enabled = zynq_pll_is_enabled, - .round_rate = zynq_pll_round_rate, + .determine_rate = zynq_pll_determine_rate, .recalc_rate = zynq_pll_recalc_rate }; From 151831541ae0f2a5d207a152a510b9ff5e8105cc Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:03 -0400 Subject: [PATCH 1090/2711] clk: actions: owl-composite: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/actions/owl-composite.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/actions/owl-composite.c b/drivers/clk/actions/owl-composite.c index 48f177f6ce9c..00b74f8bc437 100644 --- a/drivers/clk/actions/owl-composite.c +++ b/drivers/clk/actions/owl-composite.c @@ -122,13 +122,13 @@ static int owl_comp_fact_set_rate(struct clk_hw *hw, unsigned long rate, rate, parent_rate); } -static long owl_comp_fix_fact_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int owl_comp_fix_fact_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct owl_composite *comp = hw_to_owl_comp(hw); struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw; - return comp->fix_fact_ops->round_rate(&fix_fact_hw->hw, rate, parent_rate); + return comp->fix_fact_ops->determine_rate(&fix_fact_hw->hw, req); } static unsigned long owl_comp_fix_fact_recalc_rate(struct clk_hw *hw, @@ -193,7 +193,7 @@ const struct clk_ops owl_comp_fix_fact_ops = { .is_enabled = owl_comp_is_enabled, /* fix_fact_ops */ - .round_rate = owl_comp_fix_fact_round_rate, + .determine_rate = owl_comp_fix_fact_determine_rate, .recalc_rate = owl_comp_fix_fact_recalc_rate, .set_rate = owl_comp_fix_fact_set_rate, }; From 1b04e12a8bcc3315f1546f2b2a6b2ccca8c4696c Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:04 -0400 Subject: [PATCH 1091/2711] clk: actions: owl-divider: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/actions/owl-divider.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/clk/actions/owl-divider.c b/drivers/clk/actions/owl-divider.c index cddac00fe324..118f1393c678 100644 --- a/drivers/clk/actions/owl-divider.c +++ b/drivers/clk/actions/owl-divider.c @@ -23,13 +23,16 @@ long owl_divider_helper_round_rate(struct owl_clk_common *common, div_hw->div_flags); } -static long owl_divider_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int owl_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct owl_divider *div = hw_to_owl_divider(hw); - return owl_divider_helper_round_rate(&div->common, &div->div_hw, - rate, parent_rate); + req->rate = owl_divider_helper_round_rate(&div->common, &div->div_hw, + req->rate, + &req->best_parent_rate); + + return 0; } unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, @@ -89,6 +92,6 @@ static int owl_divider_set_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops owl_divider_ops = { .recalc_rate = owl_divider_recalc_rate, - .round_rate = owl_divider_round_rate, + .determine_rate = owl_divider_determine_rate, .set_rate = owl_divider_set_rate, }; From 670f7b27117c139e6470ce35c31506ff7147ea72 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:05 -0400 Subject: [PATCH 1092/2711] clk: actions: owl-factor: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/actions/owl-factor.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/actions/owl-factor.c b/drivers/clk/actions/owl-factor.c index 64f316cf7cfc..12f41f6bacd6 100644 --- a/drivers/clk/actions/owl-factor.c +++ b/drivers/clk/actions/owl-factor.c @@ -130,14 +130,16 @@ long owl_factor_helper_round_rate(struct owl_clk_common *common, return *parent_rate * mul / div; } -static long owl_factor_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int owl_factor_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct owl_factor *factor = hw_to_owl_factor(hw); struct owl_factor_hw *factor_hw = &factor->factor_hw; - return owl_factor_helper_round_rate(&factor->common, factor_hw, - rate, parent_rate); + req->rate = owl_factor_helper_round_rate(&factor->common, factor_hw, + req->rate, &req->best_parent_rate); + + return 0; } unsigned long owl_factor_helper_recalc_rate(struct owl_clk_common *common, @@ -214,7 +216,7 @@ static int owl_factor_set_rate(struct clk_hw *hw, unsigned long rate, } const struct clk_ops owl_factor_ops = { - .round_rate = owl_factor_round_rate, + .determine_rate = owl_factor_determine_rate, .recalc_rate = owl_factor_recalc_rate, .set_rate = owl_factor_set_rate, }; From 234b3015358e4fd2271d187d216f91a829bd6255 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:06 -0400 Subject: [PATCH 1093/2711] clk: actions: owl-pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/actions/owl-pll.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/clk/actions/owl-pll.c b/drivers/clk/actions/owl-pll.c index 155f313986b4..869690b79cc1 100644 --- a/drivers/clk/actions/owl-pll.c +++ b/drivers/clk/actions/owl-pll.c @@ -56,8 +56,8 @@ static const struct clk_pll_table *_get_pll_table( return table; } -static long owl_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int owl_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct owl_pll *pll = hw_to_owl_pll(hw); struct owl_pll_hw *pll_hw = &pll->pll_hw; @@ -65,17 +65,24 @@ static long owl_pll_round_rate(struct clk_hw *hw, unsigned long rate, u32 mul; if (pll_hw->table) { - clkt = _get_pll_table(pll_hw->table, rate); - return clkt->rate; + clkt = _get_pll_table(pll_hw->table, req->rate); + req->rate = clkt->rate; + + return 0; } /* fixed frequency */ - if (pll_hw->width == 0) - return pll_hw->bfreq; + if (pll_hw->width == 0) { + req->rate = pll_hw->bfreq; - mul = owl_pll_calculate_mul(pll_hw, rate); + return 0; + } - return pll_hw->bfreq * mul; + mul = owl_pll_calculate_mul(pll_hw, req->rate); + + req->rate = pll_hw->bfreq * mul; + + return 0; } static unsigned long owl_pll_recalc_rate(struct clk_hw *hw, @@ -188,7 +195,7 @@ const struct clk_ops owl_pll_ops = { .enable = owl_pll_enable, .disable = owl_pll_disable, .is_enabled = owl_pll_is_enabled, - .round_rate = owl_pll_round_rate, + .determine_rate = owl_pll_determine_rate, .recalc_rate = owl_pll_recalc_rate, .set_rate = owl_pll_set_rate, }; From 3b8f82ca44ddfb1d78f212313145797c5f4f3158 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:07 -0400 Subject: [PATCH 1094/2711] clk: apple-nco: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Janne Grunau Signed-off-by: Brian Masney --- drivers/clk/clk-apple-nco.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/clk/clk-apple-nco.c b/drivers/clk/clk-apple-nco.c index 457a48d48941..d3ced4a0f029 100644 --- a/drivers/clk/clk-apple-nco.c +++ b/drivers/clk/clk-apple-nco.c @@ -212,13 +212,15 @@ static unsigned long applnco_recalc_rate(struct clk_hw *hw, ((u64) div) * incbase + inc1); } -static long applnco_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int applnco_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned long lo = *parent_rate / (COARSE_DIV_OFFSET + LFSR_TBLSIZE) + 1; - unsigned long hi = *parent_rate / COARSE_DIV_OFFSET; + unsigned long lo = req->best_parent_rate / (COARSE_DIV_OFFSET + LFSR_TBLSIZE) + 1; + unsigned long hi = req->best_parent_rate / COARSE_DIV_OFFSET; - return clamp(rate, lo, hi); + req->rate = clamp(req->rate, lo, hi); + + return 0; } static int applnco_enable(struct clk_hw *hw) @@ -246,7 +248,7 @@ static void applnco_disable(struct clk_hw *hw) static const struct clk_ops applnco_ops = { .set_rate = applnco_set_rate, .recalc_rate = applnco_recalc_rate, - .round_rate = applnco_round_rate, + .determine_rate = applnco_determine_rate, .enable = applnco_enable, .disable = applnco_disable, .is_enabled = applnco_is_enabled, From fccbfc5d77983b3449e55942a2248b2718cd4be4 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:08 -0400 Subject: [PATCH 1095/2711] clk: axs10x: i2s_pll_clock: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/axs10x/i2s_pll_clock.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/axs10x/i2s_pll_clock.c b/drivers/clk/axs10x/i2s_pll_clock.c index 9667ce898428..6f3e1151b354 100644 --- a/drivers/clk/axs10x/i2s_pll_clock.c +++ b/drivers/clk/axs10x/i2s_pll_clock.c @@ -108,21 +108,21 @@ static unsigned long i2s_pll_recalc_rate(struct clk_hw *hw, return ((parent_rate / idiv) * fbdiv) / odiv; } -static long i2s_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int i2s_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct i2s_pll_clk *clk = to_i2s_pll_clk(hw); - const struct i2s_pll_cfg *pll_cfg = i2s_pll_get_cfg(*prate); + const struct i2s_pll_cfg *pll_cfg = i2s_pll_get_cfg(req->best_parent_rate); int i; if (!pll_cfg) { - dev_err(clk->dev, "invalid parent rate=%ld\n", *prate); + dev_err(clk->dev, "invalid parent rate=%ld\n", req->best_parent_rate); return -EINVAL; } for (i = 0; pll_cfg[i].rate != 0; i++) - if (pll_cfg[i].rate == rate) - return rate; + if (pll_cfg[i].rate == req->rate) + return 0; return -EINVAL; } @@ -156,7 +156,7 @@ static int i2s_pll_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops i2s_pll_ops = { .recalc_rate = i2s_pll_recalc_rate, - .round_rate = i2s_pll_round_rate, + .determine_rate = i2s_pll_determine_rate, .set_rate = i2s_pll_set_rate, }; From 8987b993571005d152186b0cde130a03792aae2a Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:09 -0400 Subject: [PATCH 1096/2711] clk: axs10x: pll_clock: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/axs10x/pll_clock.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c index 6c7a2b62b406..c7ca473ee76c 100644 --- a/drivers/clk/axs10x/pll_clock.c +++ b/drivers/clk/axs10x/pll_clock.c @@ -149,8 +149,8 @@ static unsigned long axs10x_pll_recalc_rate(struct clk_hw *hw, return rate; } -static long axs10x_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int axs10x_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int i; long best_rate; @@ -163,11 +163,13 @@ static long axs10x_pll_round_rate(struct clk_hw *hw, unsigned long rate, best_rate = pll_cfg[0].rate; for (i = 1; pll_cfg[i].rate != 0; i++) { - if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate)) + if (abs(req->rate - pll_cfg[i].rate) < abs(req->rate - best_rate)) best_rate = pll_cfg[i].rate; } - return best_rate; + req->rate = best_rate; + + return 0; } static int axs10x_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -208,7 +210,7 @@ static int axs10x_pll_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops axs10x_pll_ops = { .recalc_rate = axs10x_pll_recalc_rate, - .round_rate = axs10x_pll_round_rate, + .determine_rate = axs10x_pll_determine_rate, .set_rate = axs10x_pll_set_rate, }; From e84e82e5760ade3b909254d20ac67b51d26b101b Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:10 -0400 Subject: [PATCH 1097/2711] clk: bcm: iproc-asiu: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/bcm/clk-iproc-asiu.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c index dcacf55c55ae..83ec13da9b2e 100644 --- a/drivers/clk/bcm/clk-iproc-asiu.c +++ b/drivers/clk/bcm/clk-iproc-asiu.c @@ -98,22 +98,27 @@ static unsigned long iproc_asiu_clk_recalc_rate(struct clk_hw *hw, return clk->rate; } -static long iproc_asiu_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int iproc_asiu_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned int div; - if (rate == 0 || *parent_rate == 0) + if (req->rate == 0 || req->best_parent_rate == 0) return -EINVAL; - if (rate == *parent_rate) - return *parent_rate; + if (req->rate == req->best_parent_rate) + return 0; - div = DIV_ROUND_CLOSEST(*parent_rate, rate); - if (div < 2) - return *parent_rate; + div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate); + if (div < 2) { + req->rate = req->best_parent_rate; - return *parent_rate / div; + return 0; + } + + req->rate = req->best_parent_rate / div; + + return 0; } static int iproc_asiu_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -168,7 +173,7 @@ static const struct clk_ops iproc_asiu_ops = { .enable = iproc_asiu_clk_enable, .disable = iproc_asiu_clk_disable, .recalc_rate = iproc_asiu_clk_recalc_rate, - .round_rate = iproc_asiu_clk_round_rate, + .determine_rate = iproc_asiu_clk_determine_rate, .set_rate = iproc_asiu_clk_set_rate, }; From 64613d7fb42f99e955ef4c46b5772b820c3b169d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:11 -0400 Subject: [PATCH 1098/2711] clk: bm1880: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-bm1880.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-bm1880.c b/drivers/clk/clk-bm1880.c index 002f7360b1c6..dac190bc6e19 100644 --- a/drivers/clk/clk-bm1880.c +++ b/drivers/clk/clk-bm1880.c @@ -608,8 +608,8 @@ static unsigned long bm1880_clk_div_recalc_rate(struct clk_hw *hw, return rate; } -static long bm1880_clk_div_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int bm1880_clk_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw); struct bm1880_div_clock *div = &div_hw->div; @@ -621,13 +621,18 @@ static long bm1880_clk_div_round_rate(struct clk_hw *hw, unsigned long rate, val = readl(reg_addr) >> div->shift; val &= clk_div_mask(div->width); - return divider_ro_round_rate(hw, rate, prate, div->table, - div->width, div->flags, - val); + req->rate = divider_ro_round_rate(hw, req->rate, + &req->best_parent_rate, + div->table, + div->width, div->flags, val); + + return 0; } - return divider_round_rate(hw, rate, prate, div->table, - div->width, div->flags); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + div->table, div->width, div->flags); + + return 0; } static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, @@ -665,7 +670,7 @@ static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops bm1880_clk_div_ops = { .recalc_rate = bm1880_clk_div_recalc_rate, - .round_rate = bm1880_clk_div_round_rate, + .determine_rate = bm1880_clk_div_determine_rate, .set_rate = bm1880_clk_div_set_rate, }; From ab0fde4ef51c75f7668e58c3ef889fbe802d7316 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:12 -0400 Subject: [PATCH 1099/2711] clk: cdce706: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-cdce706.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c index d0705bb03a2a..a495d313b02f 100644 --- a/drivers/clk/clk-cdce706.c +++ b/drivers/clk/clk-cdce706.c @@ -183,8 +183,8 @@ static unsigned long cdce706_pll_recalc_rate(struct clk_hw *hw, return 0; } -static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int cdce706_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct cdce706_hw_data *hwd = to_hw_data(hw); unsigned long mul, div; @@ -192,9 +192,9 @@ static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate, dev_dbg(&hwd->dev_data->client->dev, "%s, rate: %lu, parent_rate: %lu\n", - __func__, rate, *parent_rate); + __func__, req->rate, req->best_parent_rate); - rational_best_approximation(rate, *parent_rate, + rational_best_approximation(req->rate, req->best_parent_rate, CDCE706_PLL_N_MAX, CDCE706_PLL_M_MAX, &mul, &div); hwd->mul = mul; @@ -204,9 +204,11 @@ static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate, "%s, pll: %d, mul: %lu, div: %lu\n", __func__, hwd->idx, mul, div); - res = (u64)*parent_rate * hwd->mul; + res = (u64)req->best_parent_rate * hwd->mul; do_div(res, hwd->div); - return res; + req->rate = res; + + return 0; } static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -251,7 +253,7 @@ static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops cdce706_pll_ops = { .recalc_rate = cdce706_pll_recalc_rate, - .round_rate = cdce706_pll_round_rate, + .determine_rate = cdce706_pll_determine_rate, .set_rate = cdce706_pll_set_rate, }; From 23603ba6eff5b16b6e361ee5d8f1933934bbe619 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:13 -0400 Subject: [PATCH 1100/2711] clk: hsdk-pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-hsdk-pll.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-hsdk-pll.c b/drivers/clk/clk-hsdk-pll.c index 921523fc26f2..7d56a47c2aa7 100644 --- a/drivers/clk/clk-hsdk-pll.c +++ b/drivers/clk/clk-hsdk-pll.c @@ -197,8 +197,8 @@ static unsigned long hsdk_pll_recalc_rate(struct clk_hw *hw, return rate; } -static long hsdk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int hsdk_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int i; unsigned long best_rate; @@ -211,13 +211,15 @@ static long hsdk_pll_round_rate(struct clk_hw *hw, unsigned long rate, best_rate = pll_cfg[0].rate; for (i = 1; pll_cfg[i].rate != 0; i++) { - if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate)) + if (abs(req->rate - pll_cfg[i].rate) < abs(req->rate - best_rate)) best_rate = pll_cfg[i].rate; } dev_dbg(clk->dev, "chosen best rate: %lu\n", best_rate); - return best_rate; + req->rate = best_rate; + + return 0; } static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk, @@ -296,7 +298,7 @@ static int hsdk_pll_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops hsdk_pll_ops = { .recalc_rate = hsdk_pll_recalc_rate, - .round_rate = hsdk_pll_round_rate, + .determine_rate = hsdk_pll_determine_rate, .set_rate = hsdk_pll_set_rate, }; From 5c2b6d0fdb637ee840f03127fabcff00a69845dc Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:14 -0400 Subject: [PATCH 1101/2711] clk: mediatek: pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/mediatek/clk-pll.c | 13 ++++++++----- drivers/clk/mediatek/clk-pll.h | 3 +-- drivers/clk/mediatek/clk-pllfh.c | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index ce453e1718e5..139d3bfcf45f 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -200,16 +200,19 @@ unsigned long mtk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return __mtk_pll_recalc_rate(pll, parent_rate, pcw, postdiv); } -long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +int mtk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); u32 pcw = 0; int postdiv; - mtk_pll_calc_values(pll, &pcw, &postdiv, rate, *prate); + mtk_pll_calc_values(pll, &pcw, &postdiv, req->rate, + req->best_parent_rate); - return __mtk_pll_recalc_rate(pll, *prate, pcw, postdiv); + req->rate = __mtk_pll_recalc_rate(pll, req->best_parent_rate, pcw, + postdiv); + + return 0; } int mtk_pll_prepare(struct clk_hw *hw) @@ -279,7 +282,7 @@ const struct clk_ops mtk_pll_ops = { .prepare = mtk_pll_prepare, .unprepare = mtk_pll_unprepare, .recalc_rate = mtk_pll_recalc_rate, - .round_rate = mtk_pll_round_rate, + .determine_rate = mtk_pll_determine_rate, .set_rate = mtk_pll_set_rate, }; diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h index 285c8db958b3..670fa2e9b898 100644 --- a/drivers/clk/mediatek/clk-pll.h +++ b/drivers/clk/mediatek/clk-pll.h @@ -96,8 +96,7 @@ void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv, u32 freq, u32 fin); int mtk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate); -long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate); +int mtk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req); struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, const struct mtk_pll_data *data, diff --git a/drivers/clk/mediatek/clk-pllfh.c b/drivers/clk/mediatek/clk-pllfh.c index 094ec8a26d66..83630ee07ee9 100644 --- a/drivers/clk/mediatek/clk-pllfh.c +++ b/drivers/clk/mediatek/clk-pllfh.c @@ -42,7 +42,7 @@ static const struct clk_ops mtk_pllfh_ops = { .prepare = mtk_pll_prepare, .unprepare = mtk_pll_unprepare, .recalc_rate = mtk_pll_recalc_rate, - .round_rate = mtk_pll_round_rate, + .determine_rate = mtk_pll_determine_rate, .set_rate = mtk_fhctl_set_rate, }; From e9f039c08cdc9b38665aee9a88ae21f59c09ba8c Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:15 -0400 Subject: [PATCH 1102/2711] clk: microchip: core: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/microchip/clk-core.c | 44 ++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/drivers/clk/microchip/clk-core.c b/drivers/clk/microchip/clk-core.c index 6fbc6dc50ca3..3e03e10539c7 100644 --- a/drivers/clk/microchip/clk-core.c +++ b/drivers/clk/microchip/clk-core.c @@ -155,11 +155,13 @@ static unsigned long pbclk_recalc_rate(struct clk_hw *hw, return parent_rate / pbclk_read_pbdiv(pb); } -static long pbclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int pbclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - return calc_best_divided_rate(rate, *parent_rate, - PB_DIV_MAX, PB_DIV_MIN); + req->rate = calc_best_divided_rate(req->rate, req->best_parent_rate, + PB_DIV_MAX, PB_DIV_MIN); + + return 0; } static int pbclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -207,7 +209,7 @@ const struct clk_ops pic32_pbclk_ops = { .disable = pbclk_disable, .is_enabled = pbclk_is_enabled, .recalc_rate = pbclk_recalc_rate, - .round_rate = pbclk_round_rate, + .determine_rate = pbclk_determine_rate, .set_rate = pbclk_set_rate, }; @@ -372,16 +374,18 @@ static unsigned long roclk_recalc_rate(struct clk_hw *hw, return roclk_calc_rate(parent_rate, rodiv, rotrim); } -static long roclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int roclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u32 rotrim, rodiv; /* calculate dividers for new rate */ - roclk_calc_div_trim(rate, *parent_rate, &rodiv, &rotrim); + roclk_calc_div_trim(req->rate, req->best_parent_rate, &rodiv, &rotrim); /* caclulate new rate (rounding) based on new rodiv & rotrim */ - return roclk_calc_rate(*parent_rate, rodiv, rotrim); + req->rate = roclk_calc_rate(req->best_parent_rate, rodiv, rotrim); + + return 0; } static int roclk_determine_rate(struct clk_hw *hw, @@ -665,12 +669,15 @@ static unsigned long spll_clk_recalc_rate(struct clk_hw *hw, return rate64; } -static long spll_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int spll_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct pic32_sys_pll *pll = clkhw_to_spll(hw); - return spll_calc_mult_div(pll, rate, *parent_rate, NULL, NULL); + req->rate = spll_calc_mult_div(pll, req->rate, req->best_parent_rate, + NULL, NULL); + + return 0; } static int spll_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -725,7 +732,7 @@ static int spll_clk_set_rate(struct clk_hw *hw, unsigned long rate, /* SPLL clock operation */ const struct clk_ops pic32_spll_ops = { .recalc_rate = spll_clk_recalc_rate, - .round_rate = spll_clk_round_rate, + .determine_rate = spll_clk_determine_rate, .set_rate = spll_clk_set_rate, }; @@ -780,10 +787,13 @@ static unsigned long sclk_get_rate(struct clk_hw *hw, unsigned long parent_rate) return parent_rate / div; } -static long sclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int sclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - return calc_best_divided_rate(rate, *parent_rate, SLEW_SYSDIV, 1); + req->rate = calc_best_divided_rate(req->rate, req->best_parent_rate, + SLEW_SYSDIV, 1); + + return 0; } static int sclk_set_rate(struct clk_hw *hw, @@ -909,7 +919,7 @@ static int sclk_init(struct clk_hw *hw) const struct clk_ops pic32_sclk_ops = { .get_parent = sclk_get_parent, .set_parent = sclk_set_parent, - .round_rate = sclk_round_rate, + .determine_rate = sclk_determine_rate, .set_rate = sclk_set_rate, .recalc_rate = sclk_get_rate, .init = sclk_init, From 5ea721896c36be7aac161a348b9e097758561402 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:16 -0400 Subject: [PATCH 1103/2711] clk: mstar: msc313-cpupll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Daniel Palmer Signed-off-by: Brian Masney --- drivers/clk/mstar/clk-msc313-cpupll.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/clk/mstar/clk-msc313-cpupll.c b/drivers/clk/mstar/clk-msc313-cpupll.c index a93e2dba09d3..3e643be02fe2 100644 --- a/drivers/clk/mstar/clk-msc313-cpupll.c +++ b/drivers/clk/mstar/clk-msc313-cpupll.c @@ -140,20 +140,22 @@ static unsigned long msc313_cpupll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate); } -static long msc313_cpupll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int msc313_cpupll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - u32 reg = msc313_cpupll_regforfrequecy(rate, *parent_rate); - long rounded = msc313_cpupll_frequencyforreg(reg, *parent_rate); + u32 reg = msc313_cpupll_regforfrequecy(req->rate, req->best_parent_rate); + long rounded = msc313_cpupll_frequencyforreg(reg, req->best_parent_rate); /* * This is my poor attempt at making sure the resulting * rate doesn't overshoot the requested rate. */ - for (; rounded >= rate && reg > 0; reg--) - rounded = msc313_cpupll_frequencyforreg(reg, *parent_rate); + for (; rounded >= req->rate && reg > 0; reg--) + rounded = msc313_cpupll_frequencyforreg(reg, req->best_parent_rate); - return rounded; + req->rate = rounded; + + return 0; } static int msc313_cpupll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) @@ -168,7 +170,7 @@ static int msc313_cpupll_set_rate(struct clk_hw *hw, unsigned long rate, unsigne static const struct clk_ops msc313_cpupll_ops = { .recalc_rate = msc313_cpupll_recalc_rate, - .round_rate = msc313_cpupll_round_rate, + .determine_rate = msc313_cpupll_determine_rate, .set_rate = msc313_cpupll_set_rate, }; From a540d5d408f65f381a19134d17b55f5e69c48435 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:17 -0400 Subject: [PATCH 1104/2711] clk: mvebu: ap-cpu-clk: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/mvebu/ap-cpu-clk.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/mvebu/ap-cpu-clk.c b/drivers/clk/mvebu/ap-cpu-clk.c index 677cc3514849..1e44ace7d951 100644 --- a/drivers/clk/mvebu/ap-cpu-clk.c +++ b/drivers/clk/mvebu/ap-cpu-clk.c @@ -210,19 +210,21 @@ static int ap_cpu_clk_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static long ap_cpu_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int ap_cpu_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - int divider = *parent_rate / rate; + int divider = req->best_parent_rate / req->rate; divider = min(divider, APN806_MAX_DIVIDER); - return *parent_rate / divider; + req->rate = req->best_parent_rate / divider; + + return 0; } static const struct clk_ops ap_cpu_clk_ops = { .recalc_rate = ap_cpu_clk_recalc_rate, - .round_rate = ap_cpu_clk_round_rate, + .determine_rate = ap_cpu_clk_determine_rate, .set_rate = ap_cpu_clk_set_rate, }; From 4b76d76f6f7f99fc525663b8d204d8719c37cd88 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:18 -0400 Subject: [PATCH 1105/2711] clk: mvebu: armada-37xx-periph: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/mvebu/armada-37xx-periph.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index 13906e31bef8..bd0bc8e7b1e7 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -454,12 +454,12 @@ static unsigned long clk_pm_cpu_recalc_rate(struct clk_hw *hw, return DIV_ROUND_UP_ULL((u64)parent_rate, div); } -static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_pm_cpu_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); struct regmap *base = pm_cpu->nb_pm_base; - unsigned int div = *parent_rate / rate; + unsigned int div = req->best_parent_rate / req->rate; unsigned int load_level; /* only available when DVFS is enabled */ if (!armada_3700_pm_dvfs_is_enabled(base)) @@ -474,13 +474,16 @@ static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate, val >>= offset; val &= ARMADA_37XX_NB_TBG_DIV_MASK; - if (val == div) + if (val == div) { /* * We found a load level matching the target * divider, switch to this load level and * return. */ - return *parent_rate / div; + req->rate = req->best_parent_rate / div; + + return 0; + } } /* We didn't find any valid divider */ @@ -600,7 +603,7 @@ static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops clk_pm_cpu_ops = { .get_parent = clk_pm_cpu_get_parent, - .round_rate = clk_pm_cpu_round_rate, + .determine_rate = clk_pm_cpu_determine_rate, .set_rate = clk_pm_cpu_set_rate, .recalc_rate = clk_pm_cpu_recalc_rate, }; From 9a649ab1cf64c9709b43cdfdc37e2ba2f200f5d0 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:19 -0400 Subject: [PATCH 1106/2711] clk: mvebu: corediv: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/mvebu/clk-corediv.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c index 818b175391fa..628032341cbb 100644 --- a/drivers/clk/mvebu/clk-corediv.c +++ b/drivers/clk/mvebu/clk-corediv.c @@ -135,19 +135,21 @@ static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk, return parent_rate / div; } -static long clk_corediv_round_rate(struct clk_hw *hwclk, unsigned long rate, - unsigned long *parent_rate) +static int clk_corediv_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { /* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */ u32 div; - div = *parent_rate / rate; + div = req->best_parent_rate / req->rate; if (div < 4) div = 4; else if (div > 6) div = 8; - return *parent_rate / div; + req->rate = req->best_parent_rate / div; + + return 0; } static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate, @@ -199,7 +201,7 @@ static const struct clk_corediv_soc_desc armada370_corediv_soc = { .disable = clk_corediv_disable, .is_enabled = clk_corediv_is_enabled, .recalc_rate = clk_corediv_recalc_rate, - .round_rate = clk_corediv_round_rate, + .determine_rate = clk_corediv_determine_rate, .set_rate = clk_corediv_set_rate, }, .ratio_reload = BIT(8), @@ -215,7 +217,7 @@ static const struct clk_corediv_soc_desc armada380_corediv_soc = { .disable = clk_corediv_disable, .is_enabled = clk_corediv_is_enabled, .recalc_rate = clk_corediv_recalc_rate, - .round_rate = clk_corediv_round_rate, + .determine_rate = clk_corediv_determine_rate, .set_rate = clk_corediv_set_rate, }, .ratio_reload = BIT(8), @@ -228,7 +230,7 @@ static const struct clk_corediv_soc_desc armada375_corediv_soc = { .ndescs = ARRAY_SIZE(mvebu_corediv_desc), .ops = { .recalc_rate = clk_corediv_recalc_rate, - .round_rate = clk_corediv_round_rate, + .determine_rate = clk_corediv_determine_rate, .set_rate = clk_corediv_set_rate, }, .ratio_reload = BIT(8), @@ -240,7 +242,7 @@ static const struct clk_corediv_soc_desc mv98dx3236_corediv_soc = { .ndescs = ARRAY_SIZE(mv98dx3236_corediv_desc), .ops = { .recalc_rate = clk_corediv_recalc_rate, - .round_rate = clk_corediv_round_rate, + .determine_rate = clk_corediv_determine_rate, .set_rate = clk_corediv_set_rate, }, .ratio_reload = BIT(10), From 27dbfefd16959afb606d7ac62abea08036b8caff Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:20 -0400 Subject: [PATCH 1107/2711] clk: mvebu: cpu: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/mvebu/clk-cpu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c index db2b38c21304..0de7660e73d2 100644 --- a/drivers/clk/mvebu/clk-cpu.c +++ b/drivers/clk/mvebu/clk-cpu.c @@ -56,19 +56,21 @@ static unsigned long clk_cpu_recalc_rate(struct clk_hw *hwclk, return parent_rate / div; } -static long clk_cpu_round_rate(struct clk_hw *hwclk, unsigned long rate, - unsigned long *parent_rate) +static int clk_cpu_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { /* Valid ratio are 1:1, 1:2 and 1:3 */ u32 div; - div = *parent_rate / rate; + div = req->best_parent_rate / req->rate; if (div == 0) div = 1; else if (div > 3) div = 3; - return *parent_rate / div; + req->rate = req->best_parent_rate / div; + + return 0; } static int clk_cpu_off_set_rate(struct clk_hw *hwclk, unsigned long rate, @@ -159,7 +161,7 @@ static int clk_cpu_set_rate(struct clk_hw *hwclk, unsigned long rate, static const struct clk_ops cpu_ops = { .recalc_rate = clk_cpu_recalc_rate, - .round_rate = clk_cpu_round_rate, + .determine_rate = clk_cpu_determine_rate, .set_rate = clk_cpu_set_rate, }; From 34848e21cb1b8052a06aa2517e28b6335319a0fa Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:21 -0400 Subject: [PATCH 1108/2711] clk: mvebu: dove-divider: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/mvebu/dove-divider.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/mvebu/dove-divider.c b/drivers/clk/mvebu/dove-divider.c index 0a90452ee808..47cc49e4cd99 100644 --- a/drivers/clk/mvebu/dove-divider.c +++ b/drivers/clk/mvebu/dove-divider.c @@ -108,23 +108,23 @@ static unsigned long dove_recalc_rate(struct clk_hw *hw, unsigned long parent) return rate; } -static long dove_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent) +static int dove_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct dove_clk *dc = to_dove_clk(hw); - unsigned long parent_rate = *parent; + unsigned long parent_rate = req->best_parent_rate; int divider; - divider = dove_calc_divider(dc, rate, parent_rate, false); + divider = dove_calc_divider(dc, req->rate, parent_rate, false); if (divider < 0) return divider; - rate = DIV_ROUND_CLOSEST(parent_rate, divider); + req->rate = DIV_ROUND_CLOSEST(parent_rate, divider); pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n", - __func__, dc->name, divider, parent_rate, rate); + __func__, dc->name, divider, parent_rate, req->rate); - return rate; + return 0; } static int dove_set_clock(struct clk_hw *hw, unsigned long rate, @@ -154,7 +154,7 @@ static int dove_set_clock(struct clk_hw *hw, unsigned long rate, static const struct clk_ops dove_divider_ops = { .set_rate = dove_set_clock, - .round_rate = dove_round_rate, + .determine_rate = dove_determine_rate, .recalc_rate = dove_recalc_rate, }; From b6f90511c165a2c546650f26d810280237440cb1 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:23 -0400 Subject: [PATCH 1109/2711] clk: qcom: regmap-divider: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Note that prior to running the Coccinelle, div_round_ro_rate() was renamed to div_ro_round_rate(). Reviewed-by: Konrad Dybcio Signed-off-by: Brian Masney --- drivers/clk/qcom/clk-regmap-divider.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c index 63c9fca0d65d..4f5395f0ab6d 100644 --- a/drivers/clk/qcom/clk-regmap-divider.c +++ b/drivers/clk/qcom/clk-regmap-divider.c @@ -15,8 +15,8 @@ static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw) return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr); } -static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int div_ro_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_regmap_div *divider = to_clk_regmap_div(hw); struct clk_regmap *clkr = ÷r->clkr; @@ -26,17 +26,24 @@ static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate, val >>= divider->shift; val &= BIT(divider->width) - 1; - return divider_ro_round_rate(hw, rate, prate, NULL, divider->width, - CLK_DIVIDER_ROUND_CLOSEST, val); + req->rate = divider_ro_round_rate(hw, req->rate, + &req->best_parent_rate, NULL, + divider->width, + CLK_DIVIDER_ROUND_CLOSEST, val); + + return 0; } -static long div_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int div_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct clk_regmap_div *divider = to_clk_regmap_div(hw); - return divider_round_rate(hw, rate, prate, NULL, divider->width, - CLK_DIVIDER_ROUND_CLOSEST); + req->rate = divider_round_rate(hw, req->rate, &req->best_parent_rate, + NULL, + divider->width, + CLK_DIVIDER_ROUND_CLOSEST); + + return 0; } static int div_set_rate(struct clk_hw *hw, unsigned long rate, @@ -70,14 +77,14 @@ static unsigned long div_recalc_rate(struct clk_hw *hw, } const struct clk_ops clk_regmap_div_ops = { - .round_rate = div_round_rate, + .determine_rate = div_determine_rate, .set_rate = div_set_rate, .recalc_rate = div_recalc_rate, }; EXPORT_SYMBOL_GPL(clk_regmap_div_ops); const struct clk_ops clk_regmap_div_ro_ops = { - .round_rate = div_round_ro_rate, + .determine_rate = div_ro_determine_rate, .recalc_rate = div_recalc_rate, }; EXPORT_SYMBOL_GPL(clk_regmap_div_ro_ops); From 1952881181e2426fad4c0bdee1b7a9f5090f4928 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:26 -0400 Subject: [PATCH 1110/2711] clk: rockchip: ddr: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/rockchip/clk-ddr.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c index 86718c54e56b..8866a65982a0 100644 --- a/drivers/clk/rockchip/clk-ddr.c +++ b/drivers/clk/rockchip/clk-ddr.c @@ -55,17 +55,18 @@ rockchip_ddrclk_sip_recalc_rate(struct clk_hw *hw, return res.a0; } -static long rockchip_ddrclk_sip_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *prate) +static int rockchip_ddrclk_sip_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct arm_smccc_res res; - arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, rate, 0, + arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, req->rate, 0, ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE, 0, 0, 0, 0, &res); - return res.a0; + req->rate = res.a0; + + return 0; } static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw) @@ -83,7 +84,7 @@ static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw) static const struct clk_ops rockchip_ddrclk_sip_ops = { .recalc_rate = rockchip_ddrclk_sip_recalc_rate, .set_rate = rockchip_ddrclk_sip_set_rate, - .round_rate = rockchip_ddrclk_sip_round_rate, + .determine_rate = rockchip_ddrclk_sip_determine_rate, .get_parent = rockchip_ddrclk_get_parent, }; From 25370bf23673af60bd4cbb4ed3b4a22477b51464 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:28 -0400 Subject: [PATCH 1111/2711] clk: rockchip: pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/rockchip/clk-pll.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index c9d599c31923..86dba3826a77 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -61,8 +61,8 @@ static const struct rockchip_pll_rate_table *rockchip_get_pll_settings( return NULL; } -static long rockchip_pll_round_rate(struct clk_hw *hw, - unsigned long drate, unsigned long *prate) +static int rockchip_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); const struct rockchip_pll_rate_table *rate_table = pll->rate_table; @@ -70,12 +70,17 @@ static long rockchip_pll_round_rate(struct clk_hw *hw, /* Assuming rate_table is in descending order */ for (i = 0; i < pll->rate_count; i++) { - if (drate >= rate_table[i].rate) - return rate_table[i].rate; + if (req->rate >= rate_table[i].rate) { + req->rate = rate_table[i].rate; + + return 0; + } } /* return minimum supported value */ - return rate_table[i - 1].rate; + req->rate = rate_table[i - 1].rate; + + return 0; } /* @@ -352,7 +357,7 @@ static const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = { static const struct clk_ops rockchip_rk3036_pll_clk_ops = { .recalc_rate = rockchip_rk3036_pll_recalc_rate, - .round_rate = rockchip_pll_round_rate, + .determine_rate = rockchip_pll_determine_rate, .set_rate = rockchip_rk3036_pll_set_rate, .enable = rockchip_rk3036_pll_enable, .disable = rockchip_rk3036_pll_disable, @@ -571,7 +576,7 @@ static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = { static const struct clk_ops rockchip_rk3066_pll_clk_ops = { .recalc_rate = rockchip_rk3066_pll_recalc_rate, - .round_rate = rockchip_pll_round_rate, + .determine_rate = rockchip_pll_determine_rate, .set_rate = rockchip_rk3066_pll_set_rate, .enable = rockchip_rk3066_pll_enable, .disable = rockchip_rk3066_pll_disable, @@ -836,7 +841,7 @@ static const struct clk_ops rockchip_rk3399_pll_clk_norate_ops = { static const struct clk_ops rockchip_rk3399_pll_clk_ops = { .recalc_rate = rockchip_rk3399_pll_recalc_rate, - .round_rate = rockchip_pll_round_rate, + .determine_rate = rockchip_pll_determine_rate, .set_rate = rockchip_rk3399_pll_set_rate, .enable = rockchip_rk3399_pll_enable, .disable = rockchip_rk3399_pll_disable, @@ -1036,7 +1041,7 @@ static const struct clk_ops rockchip_rk3588_pll_clk_norate_ops = { static const struct clk_ops rockchip_rk3588_pll_clk_ops = { .recalc_rate = rockchip_rk3588_pll_recalc_rate, - .round_rate = rockchip_pll_round_rate, + .determine_rate = rockchip_pll_determine_rate, .set_rate = rockchip_rk3588_pll_set_rate, .enable = rockchip_rk3588_pll_enable, .disable = rockchip_rk3588_pll_disable, From d61a1ba87b64ac994895e4e7134e43dfd810f824 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:32 -0400 Subject: [PATCH 1112/2711] clk: sp7021: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-sp7021.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c index 95d66191df4b..445e3da50e29 100644 --- a/drivers/clk/clk-sp7021.c +++ b/drivers/clk/clk-sp7021.c @@ -412,25 +412,27 @@ static long sp_pll_calc_div(struct sp_pll *clk, unsigned long rate) return fbdiv; } -static long sp_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int sp_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct sp_pll *clk = to_sp_pll(hw); long ret; - if (rate == *prate) { - ret = *prate; /* bypass */ + if (req->rate == req->best_parent_rate) { + ret = req->best_parent_rate; /* bypass */ } else if (clk->div_width == DIV_A) { - ret = plla_round_rate(clk, rate); + ret = plla_round_rate(clk, req->rate); } else if (clk->div_width == DIV_TV) { - ret = plltv_div(clk, rate); + ret = plltv_div(clk, req->rate); if (ret < 0) - ret = *prate; + ret = req->best_parent_rate; } else { - ret = sp_pll_calc_div(clk, rate) * clk->brate; + ret = sp_pll_calc_div(clk, req->rate) * clk->brate; } - return ret; + req->rate = ret; + + return 0; } static unsigned long sp_pll_recalc_rate(struct clk_hw *hw, @@ -535,7 +537,7 @@ static const struct clk_ops sp_pll_ops = { .enable = sp_pll_enable, .disable = sp_pll_disable, .is_enabled = sp_pll_is_enabled, - .round_rate = sp_pll_round_rate, + .determine_rate = sp_pll_determine_rate, .recalc_rate = sp_pll_recalc_rate, .set_rate = sp_pll_set_rate }; From f705ed70873e166a25b1332d4b4d7bdc4d14bd64 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:33 -0400 Subject: [PATCH 1113/2711] clk: spear: aux-synth: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/spear/clk-aux-synth.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c index 637938e804f8..d0d063147af8 100644 --- a/drivers/clk/spear/clk-aux-synth.c +++ b/drivers/clk/spear/clk-aux-synth.c @@ -49,14 +49,16 @@ static unsigned long aux_calc_rate(struct clk_hw *hw, unsigned long prate, (rtbl[index].yscale * eq)) * 10000; } -static long clk_aux_round_rate(struct clk_hw *hw, unsigned long drate, - unsigned long *prate) +static int clk_aux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_aux *aux = to_clk_aux(hw); int unused; - return clk_round_rate_index(hw, drate, *prate, aux_calc_rate, - aux->rtbl_cnt, &unused); + req->rate = clk_round_rate_index(hw, req->rate, req->best_parent_rate, + aux_calc_rate, aux->rtbl_cnt, &unused); + + return 0; } static unsigned long clk_aux_recalc_rate(struct clk_hw *hw, @@ -127,7 +129,7 @@ static int clk_aux_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops clk_aux_ops = { .recalc_rate = clk_aux_recalc_rate, - .round_rate = clk_aux_round_rate, + .determine_rate = clk_aux_determine_rate, .set_rate = clk_aux_set_rate, }; From 9ea41da306cd5c535c46b0606cc200774d5da952 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:34 -0400 Subject: [PATCH 1114/2711] clk: spear: frac-synth: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/spear/clk-frac-synth.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/spear/clk-frac-synth.c b/drivers/clk/spear/clk-frac-synth.c index 2380df293a2c..150f051d28e0 100644 --- a/drivers/clk/spear/clk-frac-synth.c +++ b/drivers/clk/spear/clk-frac-synth.c @@ -52,14 +52,16 @@ static unsigned long frac_calc_rate(struct clk_hw *hw, unsigned long prate, return prate; } -static long clk_frac_round_rate(struct clk_hw *hw, unsigned long drate, - unsigned long *prate) +static int clk_frac_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_frac *frac = to_clk_frac(hw); int unused; - return clk_round_rate_index(hw, drate, *prate, frac_calc_rate, - frac->rtbl_cnt, &unused); + req->rate = clk_round_rate_index(hw, req->rate, req->best_parent_rate, + frac_calc_rate, frac->rtbl_cnt, &unused); + + return 0; } static unsigned long clk_frac_recalc_rate(struct clk_hw *hw, @@ -115,7 +117,7 @@ static int clk_frac_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops clk_frac_ops = { .recalc_rate = clk_frac_recalc_rate, - .round_rate = clk_frac_round_rate, + .determine_rate = clk_frac_determine_rate, .set_rate = clk_frac_set_rate, }; From 2767256c6faab122d3d26e0027be0febdd78f56a Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:35 -0400 Subject: [PATCH 1115/2711] clk: spear: gpt-synth: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/spear/clk-gpt-synth.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/spear/clk-gpt-synth.c b/drivers/clk/spear/clk-gpt-synth.c index 4ef747c2abbb..cf9659dc9073 100644 --- a/drivers/clk/spear/clk-gpt-synth.c +++ b/drivers/clk/spear/clk-gpt-synth.c @@ -39,14 +39,16 @@ static unsigned long gpt_calc_rate(struct clk_hw *hw, unsigned long prate, return prate; } -static long clk_gpt_round_rate(struct clk_hw *hw, unsigned long drate, - unsigned long *prate) +static int clk_gpt_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_gpt *gpt = to_clk_gpt(hw); int unused; - return clk_round_rate_index(hw, drate, *prate, gpt_calc_rate, - gpt->rtbl_cnt, &unused); + req->rate = clk_round_rate_index(hw, req->rate, req->best_parent_rate, + gpt_calc_rate, gpt->rtbl_cnt, &unused); + + return 0; } static unsigned long clk_gpt_recalc_rate(struct clk_hw *hw, @@ -104,7 +106,7 @@ static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops clk_gpt_ops = { .recalc_rate = clk_gpt_recalc_rate, - .round_rate = clk_gpt_round_rate, + .determine_rate = clk_gpt_determine_rate, .set_rate = clk_gpt_set_rate, }; From f32c0f8b9097e8c077b804ca4d2741a4cd90217d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:36 -0400 Subject: [PATCH 1116/2711] clk: spear: vco-pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/spear/clk-vco-pll.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c index 348eeab0a906..723a6eb67754 100644 --- a/drivers/clk/spear/clk-vco-pll.c +++ b/drivers/clk/spear/clk-vco-pll.c @@ -110,12 +110,15 @@ static long clk_pll_round_rate_index(struct clk_hw *hw, unsigned long drate, return rate; } -static long clk_pll_round_rate(struct clk_hw *hw, unsigned long drate, - unsigned long *prate) +static int clk_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int unused; - return clk_pll_round_rate_index(hw, drate, prate, &unused); + req->rate = clk_pll_round_rate_index(hw, req->rate, + &req->best_parent_rate, &unused); + + return 0; } static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, unsigned long @@ -164,7 +167,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops clk_pll_ops = { .recalc_rate = clk_pll_recalc_rate, - .round_rate = clk_pll_round_rate, + .determine_rate = clk_pll_determine_rate, .set_rate = clk_pll_set_rate, }; @@ -176,14 +179,16 @@ static inline unsigned long vco_calc_rate(struct clk_hw *hw, return pll_calc_rate(vco->rtbl, prate, index, NULL); } -static long clk_vco_round_rate(struct clk_hw *hw, unsigned long drate, - unsigned long *prate) +static int clk_vco_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_vco *vco = to_clk_vco(hw); int unused; - return clk_round_rate_index(hw, drate, *prate, vco_calc_rate, - vco->rtbl_cnt, &unused); + req->rate = clk_round_rate_index(hw, req->rate, req->best_parent_rate, + vco_calc_rate, vco->rtbl_cnt, &unused); + + return 0; } static unsigned long clk_vco_recalc_rate(struct clk_hw *hw, @@ -265,7 +270,7 @@ static int clk_vco_set_rate(struct clk_hw *hw, unsigned long drate, static const struct clk_ops clk_vco_ops = { .recalc_rate = clk_vco_recalc_rate, - .round_rate = clk_vco_round_rate, + .determine_rate = clk_vco_determine_rate, .set_rate = clk_vco_set_rate, }; From 7a19c341d54c97fdd09c232ce14b4a2fcdd71d9b Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:37 -0400 Subject: [PATCH 1117/2711] clk: ux500: prcmu: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Linus Walleij Signed-off-by: Brian Masney --- drivers/clk/ux500/clk-prcmu.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c index 5cbf24c94606..f775e18acd46 100644 --- a/drivers/clk/ux500/clk-prcmu.c +++ b/drivers/clk/ux500/clk-prcmu.c @@ -53,11 +53,13 @@ static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw, return prcmu_clock_rate(clk->cg_sel); } -static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_prcmu_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_prcmu *clk = to_clk_prcmu(hw); - return prcmu_round_clock_rate(clk->cg_sel, rate); + req->rate = prcmu_round_clock_rate(clk->cg_sel, req->rate); + + return 0; } static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate, @@ -157,7 +159,7 @@ static const struct clk_ops clk_prcmu_scalable_ops = { .prepare = clk_prcmu_prepare, .unprepare = clk_prcmu_unprepare, .recalc_rate = clk_prcmu_recalc_rate, - .round_rate = clk_prcmu_round_rate, + .determine_rate = clk_prcmu_determine_rate, .set_rate = clk_prcmu_set_rate, }; @@ -169,7 +171,7 @@ static const struct clk_ops clk_prcmu_gate_ops = { static const struct clk_ops clk_prcmu_scalable_rate_ops = { .recalc_rate = clk_prcmu_recalc_rate, - .round_rate = clk_prcmu_round_rate, + .determine_rate = clk_prcmu_determine_rate, .set_rate = clk_prcmu_set_rate, }; @@ -187,7 +189,7 @@ static const struct clk_ops clk_prcmu_opp_volt_scalable_ops = { .prepare = clk_prcmu_opp_volt_prepare, .unprepare = clk_prcmu_opp_volt_unprepare, .recalc_rate = clk_prcmu_recalc_rate, - .round_rate = clk_prcmu_round_rate, + .determine_rate = clk_prcmu_determine_rate, .set_rate = clk_prcmu_set_rate, }; From 7bf7153230f7bb14d9410d998ac083d73405d926 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:38 -0400 Subject: [PATCH 1118/2711] clk: versaclock5: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Luca Ceresoli Signed-off-by: Brian Masney --- drivers/clk/clk-versaclock5.c | 71 ++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c index 4200022d2084..57228e88e81d 100644 --- a/drivers/clk/clk-versaclock5.c +++ b/drivers/clk/clk-versaclock5.c @@ -304,11 +304,11 @@ static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw, return parent_rate; } -static long vc5_dbl_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int vc5_dbl_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - if ((*parent_rate == rate) || ((*parent_rate * 2) == rate)) - return rate; + if ((req->best_parent_rate == req->rate) || ((req->best_parent_rate * 2) == req->rate)) + return 0; else return -EINVAL; } @@ -332,7 +332,7 @@ static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops vc5_dbl_ops = { .recalc_rate = vc5_dbl_recalc_rate, - .round_rate = vc5_dbl_round_rate, + .determine_rate = vc5_dbl_determine_rate, .set_rate = vc5_dbl_set_rate, }; @@ -363,24 +363,29 @@ static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw, return parent_rate / VC5_REF_DIVIDER_REF_DIV(div); } -static long vc5_pfd_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int vc5_pfd_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned long idiv; /* PLL cannot operate with input clock above 50 MHz. */ - if (rate > 50000000) + if (req->rate > 50000000) return -EINVAL; /* CLKIN within range of PLL input, feed directly to PLL. */ - if (*parent_rate <= 50000000) - return *parent_rate; + if (req->best_parent_rate <= 50000000) { + req->rate = req->best_parent_rate; - idiv = DIV_ROUND_UP(*parent_rate, rate); + return 0; + } + + idiv = DIV_ROUND_UP(req->best_parent_rate, req->rate); if (idiv > 127) return -EINVAL; - return *parent_rate / idiv; + req->rate = req->best_parent_rate / idiv; + + return 0; } static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate, @@ -420,7 +425,7 @@ static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops vc5_pfd_ops = { .recalc_rate = vc5_pfd_recalc_rate, - .round_rate = vc5_pfd_round_rate, + .determine_rate = vc5_pfd_determine_rate, .set_rate = vc5_pfd_set_rate, }; @@ -444,30 +449,32 @@ static unsigned long vc5_pll_recalc_rate(struct clk_hw *hw, return (parent_rate * div_int) + ((parent_rate * div_frc) >> 24); } -static long vc5_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int vc5_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_driver_data *vc5 = hwdata->vc5; u32 div_int; u64 div_frc; - rate = clamp(rate, VC5_PLL_VCO_MIN, vc5->chip_info->vco_max); + req->rate = clamp(req->rate, VC5_PLL_VCO_MIN, vc5->chip_info->vco_max); /* Determine integer part, which is 12 bit wide */ - div_int = rate / *parent_rate; + div_int = req->rate / req->best_parent_rate; if (div_int > 0xfff) - rate = *parent_rate * 0xfff; + req->rate = req->best_parent_rate * 0xfff; /* Determine best fractional part, which is 24 bit wide */ - div_frc = rate % *parent_rate; + div_frc = req->rate % req->best_parent_rate; div_frc *= BIT(24) - 1; - do_div(div_frc, *parent_rate); + do_div(div_frc, req->best_parent_rate); hwdata->div_int = div_int; hwdata->div_frc = (u32)div_frc; - return (*parent_rate * div_int) + ((*parent_rate * div_frc) >> 24); + req->rate = (req->best_parent_rate * div_int) + ((req->best_parent_rate * div_frc) >> 24); + + return 0; } static int vc5_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -488,7 +495,7 @@ static int vc5_pll_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops vc5_pll_ops = { .recalc_rate = vc5_pll_recalc_rate, - .round_rate = vc5_pll_round_rate, + .determine_rate = vc5_pll_determine_rate, .set_rate = vc5_pll_set_rate, }; @@ -520,17 +527,17 @@ static unsigned long vc5_fod_recalc_rate(struct clk_hw *hw, return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc); } -static long vc5_fod_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int vc5_fod_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); /* VCO frequency is divided by two before entering FOD */ - u32 f_in = *parent_rate / 2; + u32 f_in = req->best_parent_rate / 2; u32 div_int; u64 div_frc; /* Determine integer part, which is 12 bit wide */ - div_int = f_in / rate; + div_int = f_in / req->rate; /* * WARNING: The clock chip does not output signal if the integer part * of the divider is 0xfff and fractional part is non-zero. @@ -538,18 +545,20 @@ static long vc5_fod_round_rate(struct clk_hw *hw, unsigned long rate, */ if (div_int > 0xffe) { div_int = 0xffe; - rate = f_in / div_int; + req->rate = f_in / div_int; } /* Determine best fractional part, which is 30 bit wide */ - div_frc = f_in % rate; + div_frc = f_in % req->rate; div_frc <<= 24; - do_div(div_frc, rate); + do_div(div_frc, req->rate); hwdata->div_int = div_int; hwdata->div_frc = (u32)div_frc; - return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc); + req->rate = div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc); + + return 0; } static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate, @@ -589,7 +598,7 @@ static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops vc5_fod_ops = { .recalc_rate = vc5_fod_recalc_rate, - .round_rate = vc5_fod_round_rate, + .determine_rate = vc5_fod_determine_rate, .set_rate = vc5_fod_set_rate, }; From b4d5ebcf69fa99c11ca9489b1a6e290d206bf3f7 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:39 -0400 Subject: [PATCH 1119/2711] clk: versaclock7: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/clk-versaclock7.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/clk/clk-versaclock7.c b/drivers/clk/clk-versaclock7.c index 483285b30c13..adcc603e3259 100644 --- a/drivers/clk/clk-versaclock7.c +++ b/drivers/clk/clk-versaclock7.c @@ -900,17 +900,18 @@ static unsigned long vc7_fod_recalc_rate(struct clk_hw *hw, unsigned long parent return fod_rate; } -static long vc7_fod_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) +static int vc7_fod_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct vc7_fod_data *fod = container_of(hw, struct vc7_fod_data, hw); unsigned long fod_rate; pr_debug("%s - %s: requested rate: %lu, parent_rate: %lu\n", - __func__, clk_hw_get_name(hw), rate, *parent_rate); + __func__, clk_hw_get_name(hw), req->rate, req->best_parent_rate); - vc7_calc_fod_divider(rate, *parent_rate, + vc7_calc_fod_divider(req->rate, req->best_parent_rate, &fod->fod_1st_int, &fod->fod_2nd_int, &fod->fod_frac); - fod_rate = vc7_calc_fod_2nd_stage_rate(*parent_rate, fod->fod_1st_int, + fod_rate = vc7_calc_fod_2nd_stage_rate(req->best_parent_rate, fod->fod_1st_int, fod->fod_2nd_int, fod->fod_frac); pr_debug("%s - %s: fod_1st_int: %u, fod_2nd_int: %u, fod_frac: %llu\n", @@ -918,7 +919,9 @@ static long vc7_fod_round_rate(struct clk_hw *hw, unsigned long rate, unsigned l fod->fod_1st_int, fod->fod_2nd_int, fod->fod_frac); pr_debug("%s - %s rate: %lu\n", __func__, clk_hw_get_name(hw), fod_rate); - return fod_rate; + req->rate = fod_rate; + + return 0; } static int vc7_fod_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) @@ -952,7 +955,7 @@ static int vc7_fod_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long static const struct clk_ops vc7_fod_ops = { .recalc_rate = vc7_fod_recalc_rate, - .round_rate = vc7_fod_round_rate, + .determine_rate = vc7_fod_determine_rate, .set_rate = vc7_fod_set_rate, }; @@ -978,21 +981,24 @@ static unsigned long vc7_iod_recalc_rate(struct clk_hw *hw, unsigned long parent return iod_rate; } -static long vc7_iod_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) +static int vc7_iod_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct vc7_iod_data *iod = container_of(hw, struct vc7_iod_data, hw); unsigned long iod_rate; pr_debug("%s - %s: requested rate: %lu, parent_rate: %lu\n", - __func__, clk_hw_get_name(hw), rate, *parent_rate); + __func__, clk_hw_get_name(hw), req->rate, req->best_parent_rate); - vc7_calc_iod_divider(rate, *parent_rate, &iod->iod_int); - iod_rate = div64_u64(*parent_rate, iod->iod_int); + vc7_calc_iod_divider(req->rate, req->best_parent_rate, &iod->iod_int); + iod_rate = div64_u64(req->best_parent_rate, iod->iod_int); pr_debug("%s - %s: iod_int: %u\n", __func__, clk_hw_get_name(hw), iod->iod_int); pr_debug("%s - %s rate: %ld\n", __func__, clk_hw_get_name(hw), iod_rate); - return iod_rate; + req->rate = iod_rate; + + return 0; } static int vc7_iod_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) @@ -1023,7 +1029,7 @@ static int vc7_iod_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long static const struct clk_ops vc7_iod_ops = { .recalc_rate = vc7_iod_recalc_rate, - .round_rate = vc7_iod_round_rate, + .determine_rate = vc7_iod_determine_rate, .set_rate = vc7_iod_set_rate, }; From ef6fd5ce7d1d7aacab351219f295757d24a5e414 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:40 -0400 Subject: [PATCH 1120/2711] clk: versatile: icst: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Linus Walleij Signed-off-by: Brian Masney --- drivers/clk/versatile/clk-icst.c | 72 ++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index b69c3fbdfbce..86ca04ad9fab 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -234,39 +234,51 @@ static unsigned long icst_recalc_rate(struct clk_hw *hw, return icst->rate; } -static long icst_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int icst_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_icst *icst = to_icst(hw); struct icst_vco vco; if (icst->ctype == ICST_INTEGRATOR_AP_CM || icst->ctype == ICST_INTEGRATOR_CP_CM_CORE) { - if (rate <= 12000000) - return 12000000; - if (rate >= 160000000) - return 160000000; - /* Slam to closest megahertz */ - return DIV_ROUND_CLOSEST(rate, 1000000) * 1000000; + if (req->rate <= 12000000) + req->rate = 12000000; + else if (req->rate >= 160000000) + req->rate = 160000000; + else { + /* Slam to closest megahertz */ + req->rate = DIV_ROUND_CLOSEST(req->rate, 1000000) * 1000000; + } + + return 0; } if (icst->ctype == ICST_INTEGRATOR_CP_CM_MEM) { - if (rate <= 6000000) - return 6000000; - if (rate >= 66000000) - return 66000000; - /* Slam to closest 0.5 megahertz */ - return DIV_ROUND_CLOSEST(rate, 500000) * 500000; + if (req->rate <= 6000000) + req->rate = 6000000; + else if (req->rate >= 66000000) + req->rate = 66000000; + else { + /* Slam to closest 0.5 megahertz */ + req->rate = DIV_ROUND_CLOSEST(req->rate, 500000) * 500000; + } + + return 0; } if (icst->ctype == ICST_INTEGRATOR_AP_SYS) { /* Divides between 3 and 50 MHz in steps of 0.25 MHz */ - if (rate <= 3000000) - return 3000000; - if (rate >= 50000000) - return 5000000; - /* Slam to closest 0.25 MHz */ - return DIV_ROUND_CLOSEST(rate, 250000) * 250000; + if (req->rate <= 3000000) + req->rate = 3000000; + else if (req->rate >= 50000000) + req->rate = 5000000; + else { + /* Slam to closest 0.25 MHz */ + req->rate = DIV_ROUND_CLOSEST(req->rate, 250000) * 250000; + } + + return 0; } if (icst->ctype == ICST_INTEGRATOR_AP_PCI) { @@ -274,14 +286,20 @@ static long icst_round_rate(struct clk_hw *hw, unsigned long rate, * If we're below or less than halfway from 25 to 33 MHz * select 25 MHz */ - if (rate <= 25000000 || rate < 29000000) - return 25000000; - /* Else just return the default frequency */ - return 33000000; + if (req->rate <= 25000000 || req->rate < 29000000) + req->rate = 25000000; + else { + /* Else just return the default frequency */ + req->rate = 33000000; + } + + return 0; } - vco = icst_hz_to_vco(icst->params, rate); - return icst_hz(icst->params, vco); + vco = icst_hz_to_vco(icst->params, req->rate); + req->rate = icst_hz(icst->params, vco); + + return 0; } static int icst_set_rate(struct clk_hw *hw, unsigned long rate, @@ -329,7 +347,7 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops icst_ops = { .recalc_rate = icst_recalc_rate, - .round_rate = icst_round_rate, + .determine_rate = icst_determine_rate, .set_rate = icst_set_rate, }; From 775e96539dcf980f7f7887feb0732cd7c3e55bc6 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:41 -0400 Subject: [PATCH 1121/2711] clk: versatile: vexpress-osc: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Linus Walleij Signed-off-by: Brian Masney --- drivers/clk/versatile/clk-vexpress-osc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c index c385ca2f4a74..9adbf5c33bd1 100644 --- a/drivers/clk/versatile/clk-vexpress-osc.c +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -33,18 +33,18 @@ static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw, return rate; } -static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int vexpress_osc_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct vexpress_osc *osc = to_vexpress_osc(hw); - if (osc->rate_min && rate < osc->rate_min) - rate = osc->rate_min; + if (osc->rate_min && req->rate < osc->rate_min) + req->rate = osc->rate_min; - if (osc->rate_max && rate > osc->rate_max) - rate = osc->rate_max; + if (osc->rate_max && req->rate > osc->rate_max) + req->rate = osc->rate_max; - return rate; + return 0; } static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate, @@ -57,7 +57,7 @@ static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops vexpress_osc_ops = { .recalc_rate = vexpress_osc_recalc_rate, - .round_rate = vexpress_osc_round_rate, + .determine_rate = vexpress_osc_determine_rate, .set_rate = vexpress_osc_set_rate, }; From e7666eae4858ceb72a0499e4e2a78e0296ca1d35 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:42 -0400 Subject: [PATCH 1122/2711] clk: visconti: pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Reviewed-by: Nobuhiro Iwamatsu Signed-off-by: Brian Masney --- drivers/clk/visconti/pll.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c index 8ca1bad61864..681721d85032 100644 --- a/drivers/clk/visconti/pll.c +++ b/drivers/clk/visconti/pll.c @@ -100,8 +100,8 @@ static unsigned long visconti_get_pll_rate_from_data(struct visconti_pll *pll, return rate_table[0].rate; } -static long visconti_pll_round_rate(struct clk_hw *hw, - unsigned long rate, unsigned long *prate) +static int visconti_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct visconti_pll *pll = to_visconti_pll(hw); const struct visconti_pll_rate_table *rate_table = pll->rate_table; @@ -109,11 +109,16 @@ static long visconti_pll_round_rate(struct clk_hw *hw, /* Assuming rate_table is in descending order */ for (i = 0; i < pll->rate_count; i++) - if (rate >= rate_table[i].rate) - return rate_table[i].rate; + if (req->rate >= rate_table[i].rate) { + req->rate = rate_table[i].rate; + + return 0; + } /* return minimum supported value */ - return rate_table[i - 1].rate; + req->rate = rate_table[i - 1].rate; + + return 0; } static unsigned long visconti_pll_recalc_rate(struct clk_hw *hw, @@ -232,7 +237,7 @@ static const struct clk_ops visconti_pll_ops = { .enable = visconti_pll_enable, .disable = visconti_pll_disable, .is_enabled = visconti_pll_is_enabled, - .round_rate = visconti_pll_round_rate, + .determine_rate = visconti_pll_determine_rate, .recalc_rate = visconti_pll_recalc_rate, .set_rate = visconti_pll_set_rate, }; From d228ece36345d56bb862cc0e5c3575e3097d8dac Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:43 -0400 Subject: [PATCH 1123/2711] clk: divider: remove round_rate() in favor of determine_rate() This driver implements both the determine_rate() and round_rate() clk ops, and the round_rate() clk ops is deprecated. When both are defined, clk_core_determine_round_nolock() from the clk core will only use the determine_rate() clk ops. Also all clk drivers that directly calls divider's round_rate() have been migrated over to determine_rate(). So let's remove the round_rate() clk ops. Reviewed-by: Alexander Sverdlin Reviewed-by: Geert Uytterhoeven Signed-off-by: Brian Masney --- drivers/clk/clk-divider.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index c1f426b8a504..2601b6155afb 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -431,27 +431,6 @@ long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, } EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent); -static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_divider *divider = to_clk_divider(hw); - - /* if read only, just return current value */ - if (divider->flags & CLK_DIVIDER_READ_ONLY) { - u32 val; - - val = clk_div_readl(divider) >> divider->shift; - val &= clk_div_mask(divider->width); - - return divider_ro_round_rate(hw, rate, prate, divider->table, - divider->width, divider->flags, - val); - } - - return divider_round_rate(hw, rate, prate, divider->table, - divider->width, divider->flags); -} - static int clk_divider_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { @@ -527,7 +506,6 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops clk_divider_ops = { .recalc_rate = clk_divider_recalc_rate, - .round_rate = clk_divider_round_rate, .determine_rate = clk_divider_determine_rate, .set_rate = clk_divider_set_rate, }; @@ -535,7 +513,6 @@ EXPORT_SYMBOL_GPL(clk_divider_ops); const struct clk_ops clk_divider_ro_ops = { .recalc_rate = clk_divider_recalc_rate, - .round_rate = clk_divider_round_rate, .determine_rate = clk_divider_determine_rate, }; EXPORT_SYMBOL_GPL(clk_divider_ro_ops); From e0c26569d3ad5a5ad0283b72ec91581bec581845 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 11:19:46 -0400 Subject: [PATCH 1124/2711] clk: fixed-factor: drop round_rate() clk ops This driver implements both the determine_rate() and round_rate() clk ops, and the round_rate() clk ops is deprecated. When both are defined, clk_core_determine_round_nolock() from the clk core will only use the determine_rate() clk ops. Also all clk drivers that directly calls fixed-factor's round_rate() have been migrated over to determine_rate(). So let's remove the round_rate() clk ops. Reviewed-by: Alexander Sverdlin Signed-off-by: Brian Masney --- drivers/clk/clk-fixed-factor.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 79b9a8c57d4b..de658c9e4c53 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -47,21 +47,6 @@ static int clk_factor_determine_rate(struct clk_hw *hw, return 0; } -static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); - - if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { - unsigned long best_parent; - - best_parent = (rate / fix->mult) * fix->div; - *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); - } - - return (*prate / fix->div) * fix->mult; -} - static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -87,7 +72,6 @@ static unsigned long clk_factor_recalc_accuracy(struct clk_hw *hw, const struct clk_ops clk_fixed_factor_ops = { .determine_rate = clk_factor_determine_rate, - .round_rate = clk_factor_round_rate, .set_rate = clk_factor_set_rate, .recalc_rate = clk_factor_recalc_rate, .recalc_accuracy = clk_factor_recalc_accuracy, From 68a74490629eb606ad77a88dd84515f35525e267 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 11 Aug 2025 22:00:12 +0900 Subject: [PATCH 1125/2711] fs: hpfs: Avoid multiple -Wflex-array-member-not-at-end warnings -Wflex-array-member-not-at-end was introduced in GCC-14, and we are getting ready to enable it, globally. So, in order to avoid ending up with a flexible-array member in the middle of other structs, we use the `struct_group_tagged()` helper to create a new tagged `struct bplus_header_fixed`. This structure groups together all the members of the flexible `struct bplus_header` except the flexible array. As a result, the array is effectively separated from the rest of the members without modifying the memory layout of the flexible structure. We then change the type of the middle struct member currently causing trouble from `struct bplus_header` to `struct bplus_header_fixed`. We also want to ensure that when new members need to be added to the flexible structure, they are always included within the newly created tagged struct. For this, we use `static_assert()`. This ensures that the memory layout for both the flexible structure and the new tagged struct is the same after any changes. This approach avoids having to implement `struct bplus_header_fixed` as a completely separate structure, thus preventing having to maintain two independent but basically identical structures, closing the door to potential bugs in the future. We also use `container_of()` (via a wrapper) whenever we need to retrieve a pointer to the flexible structure, through which we can access the flexible-array member, if necessary. So, with these changes, fix 26 of the following type of warnings: fs/hpfs/hpfs.h:456:23: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] fs/hpfs/hpfs.h:498:23: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mikulas Patocka --- fs/hpfs/anode.c | 43 ++++++++++++++++++++++--------------------- fs/hpfs/ea.c | 2 +- fs/hpfs/file.c | 4 +++- fs/hpfs/hpfs.h | 44 +++++++++++++++++++++++++++++++------------- fs/hpfs/map.c | 8 ++++---- 5 files changed, 61 insertions(+), 40 deletions(-) diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c index c14c9a035ee0..a4f5321eafae 100644 --- a/fs/hpfs/anode.c +++ b/fs/hpfs/anode.c @@ -27,7 +27,7 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode, a = le32_to_cpu(btree->u.internal[i].down); brelse(bh); if (!(anode = hpfs_map_anode(s, a, &bh))) return -1; - btree = &anode->btree; + btree = GET_BTREE_PTR(&anode->btree); goto go_down; } hpfs_error(s, "sector %08x not found in internal anode %08x", sec, a); @@ -69,12 +69,13 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi int n; unsigned fs; int c1, c2 = 0; + if (fnod) { if (!(fnode = hpfs_map_fnode(s, node, &bh))) return -1; - btree = &fnode->btree; + btree = GET_BTREE_PTR(&fnode->btree); } else { if (!(anode = hpfs_map_anode(s, node, &bh))) return -1; - btree = &anode->btree; + btree = GET_BTREE_PTR(&anode->btree); } a = node; go_down: @@ -91,7 +92,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_add_sector_to_btree #1")) return -1; if (!(anode = hpfs_map_anode(s, a, &bh))) return -1; - btree = &anode->btree; + btree = GET_BTREE_PTR(&anode->btree); goto go_down; } if (n >= 0) { @@ -151,7 +152,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi } brelse(bh); bh = bh1; - btree = &anode->btree; + btree = GET_BTREE_PTR(&anode->btree); } btree->n_free_nodes--; n = btree->n_used_nodes++; le16_add_cpu(&btree->first_free, 12); @@ -168,10 +169,10 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi if (hpfs_stop_cycles(s, up, &c1, &c2, "hpfs_add_sector_to_btree #2")) return -1; if (up != node || !fnod) { if (!(anode = hpfs_map_anode(s, up, &bh))) return -1; - btree = &anode->btree; + btree = GET_BTREE_PTR(&anode->btree); } else { if (!(fnode = hpfs_map_fnode(s, up, &bh))) return -1; - btree = &fnode->btree; + btree = GET_BTREE_PTR(&fnode->btree); } if (btree->n_free_nodes) { btree->n_free_nodes--; n = btree->n_used_nodes++; @@ -206,8 +207,8 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi anode->btree.n_used_nodes = 1; anode->btree.n_free_nodes = 59; anode->btree.first_free = cpu_to_le16(16); - anode->btree.u.internal[0].down = cpu_to_le32(a); - anode->btree.u.internal[0].file_secno = cpu_to_le32(-1); + GET_BTREE_PTR(&anode->btree)->u.internal[0].down = cpu_to_le32(a); + GET_BTREE_PTR(&anode->btree)->u.internal[0].file_secno = cpu_to_le32(-1); mark_buffer_dirty(bh); brelse(bh); if ((anode = hpfs_map_anode(s, a, &bh))) { @@ -229,20 +230,20 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi brelse(bh2); return -1; } - btree = &anode->btree; + btree = GET_BTREE_PTR(&anode->btree); } else { if (!(fnode = hpfs_map_fnode(s, node, &bh))) { brelse(bh2); return -1; } - btree = &fnode->btree; + btree = GET_BTREE_PTR(&fnode->btree); } ranode->up = cpu_to_le32(node); memcpy(&ranode->btree, btree, le16_to_cpu(btree->first_free)); if (fnod) ranode->btree.flags |= BP_fnode_parent; - ranode->btree.n_free_nodes = (bp_internal(&ranode->btree) ? 60 : 40) - ranode->btree.n_used_nodes; - if (bp_internal(&ranode->btree)) for (n = 0; n < ranode->btree.n_used_nodes; n++) { + GET_BTREE_PTR(&ranode->btree)->n_free_nodes = (bp_internal(GET_BTREE_PTR(&ranode->btree)) ? 60 : 40) - GET_BTREE_PTR(&ranode->btree)->n_used_nodes; + if (bp_internal(GET_BTREE_PTR(&ranode->btree))) for (n = 0; n < GET_BTREE_PTR(&ranode->btree)->n_used_nodes; n++) { struct anode *unode; if ((unode = hpfs_map_anode(s, le32_to_cpu(ranode->u.internal[n].down), &bh1))) { unode->up = cpu_to_le32(ra); @@ -291,7 +292,7 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree) if (hpfs_stop_cycles(s, ano, &d1, &d2, "hpfs_remove_btree #1")) return; if (!(anode = hpfs_map_anode(s, ano, &bh))) return; - btree1 = &anode->btree; + btree1 = GET_BTREE_PTR(&anode->btree); level++; pos = 0; } @@ -307,7 +308,7 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree) ano = le32_to_cpu(anode->up); if (--level) { if (!(anode = hpfs_map_anode(s, ano, &bh))) return; - btree1 = &anode->btree; + btree1 = GET_BTREE_PTR(&anode->btree); } else btree1 = btree; for (i = 0; i < btree1->n_used_nodes; i++) { if (le32_to_cpu(btree1->u.internal[i].down) == oano) { @@ -332,7 +333,7 @@ static secno anode_lookup(struct super_block *s, anode_secno a, unsigned sec) struct anode *anode; struct buffer_head *bh; if (!(anode = hpfs_map_anode(s, a, &bh))) return -1; - return hpfs_bplus_lookup(s, NULL, &anode->btree, sec, bh); + return hpfs_bplus_lookup(s, NULL, GET_BTREE_PTR(&anode->btree), sec, bh); } int hpfs_ea_read(struct super_block *s, secno a, int ano, unsigned pos, @@ -388,7 +389,7 @@ void hpfs_ea_remove(struct super_block *s, secno a, int ano, unsigned len) struct buffer_head *bh; if (ano) { if (!(anode = hpfs_map_anode(s, a, &bh))) return; - hpfs_remove_btree(s, &anode->btree); + hpfs_remove_btree(s, GET_BTREE_PTR(&anode->btree)); brelse(bh); hpfs_free_sectors(s, a, 1); } else hpfs_free_sectors(s, a, (len + 511) >> 9); @@ -407,10 +408,10 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs) int c1, c2 = 0; if (fno) { if (!(fnode = hpfs_map_fnode(s, f, &bh))) return; - btree = &fnode->btree; + btree = GET_BTREE_PTR(&fnode->btree); } else { if (!(anode = hpfs_map_anode(s, f, &bh))) return; - btree = &anode->btree; + btree = GET_BTREE_PTR(&anode->btree); } if (!secs) { hpfs_remove_btree(s, btree); @@ -448,7 +449,7 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs) if (hpfs_stop_cycles(s, node, &c1, &c2, "hpfs_truncate_btree")) return; if (!(anode = hpfs_map_anode(s, node, &bh))) return; - btree = &anode->btree; + btree = GET_BTREE_PTR(&anode->btree); } nodes = btree->n_used_nodes + btree->n_free_nodes; for (i = 0; i < btree->n_used_nodes; i++) @@ -485,7 +486,7 @@ void hpfs_remove_fnode(struct super_block *s, fnode_secno fno) struct extended_attribute *ea; struct extended_attribute *ea_end; if (!(fnode = hpfs_map_fnode(s, fno, &bh))) return; - if (!fnode_is_dir(fnode)) hpfs_remove_btree(s, &fnode->btree); + if (!fnode_is_dir(fnode)) hpfs_remove_btree(s, GET_BTREE_PTR(&fnode->btree)); else hpfs_remove_dtree(s, le32_to_cpu(fnode->u.external[0].disk_secno)); ea_end = fnode_end_ea(fnode); for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) diff --git a/fs/hpfs/ea.c b/fs/hpfs/ea.c index 102ba18e561f..2149d3ca530b 100644 --- a/fs/hpfs/ea.c +++ b/fs/hpfs/ea.c @@ -41,7 +41,7 @@ void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len) struct buffer_head *bh; struct anode *anode; if ((anode = hpfs_map_anode(s, a, &bh))) { - hpfs_remove_btree(s, &anode->btree); + hpfs_remove_btree(s, GET_BTREE_PTR(&anode->btree)); brelse(bh); hpfs_free_sectors(s, a, 1); } diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 263b5bbe1849..29e876705369 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -51,7 +51,9 @@ static secno hpfs_bmap(struct inode *inode, unsigned file_secno, unsigned *n_sec return hpfs_inode->i_disk_sec + n; } if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0; - disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, &fnode->btree, file_secno, bh); + disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, + GET_BTREE_PTR(&fnode->btree), + file_secno, bh); if (disk_secno == -1) return 0; if (hpfs_chk_sectors(inode->i_sb, disk_secno, 1, "bmap")) return 0; n = file_secno - hpfs_inode->i_file_sec; diff --git a/fs/hpfs/hpfs.h b/fs/hpfs/hpfs.h index 281dec8f636b..353f73c914d9 100644 --- a/fs/hpfs/hpfs.h +++ b/fs/hpfs/hpfs.h @@ -394,27 +394,45 @@ enum { BP_binary_search = 0x40, BP_internal = 0x80 }; + +/** + * GET_BTREE_PTR() - Get a pointer to struct bplus_header + * + * Wrapper around container_of() to retrieve a pointer to struct + * bplus_header from a pointer to struct bplus_header_fixed. + * + * @ptr: Pointer to struct bplus_header_fixed. + * + */ +#define GET_BTREE_PTR(ptr) \ + container_of(ptr, struct bplus_header, __hdr) + struct bplus_header { - u8 flags; /* bit 0 - high bit of first free entry offset + /* New members MUST be added within the struct_group() macro below. */ + struct_group_tagged(bplus_header_fixed, __hdr, + u8 flags; /* bit 0 - high bit of first free entry offset bit 5 - we're pointed to by an fnode, the data btree or some ea or the main ea bootage pointer ea_secno bit 6 - suggest binary search (unused) bit 7 - 1 -> (internal) tree of anodes 0 -> (leaf) list of extents */ - u8 fill[3]; - u8 n_free_nodes; /* free nodes in following array */ - u8 n_used_nodes; /* used nodes in following array */ - __le16 first_free; /* offset from start of header to + u8 fill[3]; + u8 n_free_nodes; /* free nodes in following array */ + u8 n_used_nodes; /* used nodes in following array */ + __le16 first_free; /* offset from start of header to first free node in array */ - union { - /* (internal) 2-word entries giving subtree pointers */ - DECLARE_FLEX_ARRAY(struct bplus_internal_node, internal); - /* (external) 3-word entries giving sector runs */ - DECLARE_FLEX_ARRAY(struct bplus_leaf_node, external); - } u; + ); + union { + /* (internal) 2-word entries giving subtree pointers */ + DECLARE_FLEX_ARRAY(struct bplus_internal_node, internal); + /* (external) 3-word entries giving sector runs */ + DECLARE_FLEX_ARRAY(struct bplus_leaf_node, external); + } u; }; +static_assert(offsetof(struct bplus_header, u.internal) == sizeof(struct bplus_header_fixed), + "struct member likely outside of struct_group_tagged()"); static inline bool bp_internal(struct bplus_header *bp) { @@ -453,7 +471,7 @@ struct fnode __le16 flags; /* bit 1 set -> ea_secno is an anode */ /* bit 8 set -> directory. first & only extent points to dnode. */ - struct bplus_header btree; /* b+ tree, 8 extents or 12 subtrees */ + struct bplus_header_fixed btree; /* b+ tree, 8 extents or 12 subtrees */ union { struct bplus_leaf_node external[8]; struct bplus_internal_node internal[12]; @@ -495,7 +513,7 @@ struct anode __le32 self; /* pointer to this anode */ __le32 up; /* parent anode or fnode */ - struct bplus_header btree; /* b+tree, 40 extents or 60 subtrees */ + struct bplus_header_fixed btree; /* b+tree, 40 extents or 60 subtrees */ union { struct bplus_leaf_node external[40]; struct bplus_internal_node internal[60]; diff --git a/fs/hpfs/map.c b/fs/hpfs/map.c index ecd9fccd1663..be73233502f8 100644 --- a/fs/hpfs/map.c +++ b/fs/hpfs/map.c @@ -178,14 +178,14 @@ struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_hea } if (!fnode_is_dir(fnode)) { if ((unsigned)fnode->btree.n_used_nodes + (unsigned)fnode->btree.n_free_nodes != - (bp_internal(&fnode->btree) ? 12 : 8)) { + (bp_internal(GET_BTREE_PTR(&fnode->btree)) ? 12 : 8)) { hpfs_error(s, "bad number of nodes in fnode %08lx", (unsigned long)ino); goto bail; } if (le16_to_cpu(fnode->btree.first_free) != - 8 + fnode->btree.n_used_nodes * (bp_internal(&fnode->btree) ? 8 : 12)) { + 8 + fnode->btree.n_used_nodes * (bp_internal(GET_BTREE_PTR(&fnode->btree)) ? 8 : 12)) { hpfs_error(s, "bad first_free pointer in fnode %08lx", (unsigned long)ino); @@ -233,12 +233,12 @@ struct anode *hpfs_map_anode(struct super_block *s, anode_secno ano, struct buff goto bail; } if ((unsigned)anode->btree.n_used_nodes + (unsigned)anode->btree.n_free_nodes != - (bp_internal(&anode->btree) ? 60 : 40)) { + (bp_internal(GET_BTREE_PTR(&anode->btree)) ? 60 : 40)) { hpfs_error(s, "bad number of nodes in anode %08x", ano); goto bail; } if (le16_to_cpu(anode->btree.first_free) != - 8 + anode->btree.n_used_nodes * (bp_internal(&anode->btree) ? 8 : 12)) { + 8 + anode->btree.n_used_nodes * (bp_internal(GET_BTREE_PTR(&anode->btree)) ? 8 : 12)) { hpfs_error(s, "bad first_free pointer in anode %08x", ano); goto bail; } From fd8a620f195e7966d83c367def68818a2cc71177 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Tue, 27 May 2025 17:00:08 +0800 Subject: [PATCH 1126/2711] hpfs: Replace simple_strtoul with kstrtoint in hpfs_parse_param kstrtoint() is better because simple_strtoul() ignores overflow and the type of 'timeshift' is 'int' rather than 'unsigned long'. Using kstrtoint() is more concise too. Signed-off-by: Su Hui Signed-off-by: Mikulas Patocka --- fs/hpfs/super.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 42b779b4d87f..8ab85e7ac91e 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -404,15 +404,11 @@ static int hpfs_parse_param(struct fs_context *fc, struct fs_parameter *param) break; case Opt_timeshift: { - int m = 1; char *rhs = param->string; int timeshift; - if (*rhs == '-') m = -1; - if (*rhs == '+' || *rhs == '-') rhs++; - timeshift = simple_strtoul(rhs, &rhs, 0) * m; - if (*rhs) - return -EINVAL; + if (kstrtoint(rhs, 0, ×hift)) + return -EINVAL; ctx->timeshift = timeshift; break; } From 32058c38d3b79a28963a59ac0353644dc24775cd Mon Sep 17 00:00:00 2001 From: Yikang Yue Date: Sat, 3 May 2025 20:44:34 -0500 Subject: [PATCH 1127/2711] fs/hpfs: Fix error code for new_inode() failure in mkdir/create/mknod/symlink The function call new_inode() is a primitive for allocating an inode in memory, rather than planning disk space for it. Therefore, -ENOMEM should be returned as the error code rather than -ENOSPC. To be specific, new_inode()'s call path looks like this: new_inode new_inode_pseudo alloc_inode ops->alloc_inode (hpfs_alloc_inode) alloc_inode_sb kmem_cache_alloc_lru Therefore, the failure of new_inode() indicates a memory presure issue (-ENOMEM), not a lack of disk space. However, the current implementation of hpfs_mkdir/create/mknod/symlink incorrectly returns -ENOSPC when new_inode() fails. This patch fix this by set err to -ENOMEM before the goto statement. BTW, we also noticed that other nested calls within these four functions, like hpfs_alloc_f/dnode and hpfs_add_dirent, might also fail due to memory presure. But similarly, only -ENOSPC is returned. Addressing these will involve code modifications in other functions, and we plan to submit dedicated patches for these issues in the future. For this patch, we focus on new_inode(). Signed-off-by: Yikang Yue Signed-off-by: Mikulas Patocka --- fs/hpfs/namei.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index e3cdc421dfba..353e13a615f5 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -52,8 +52,10 @@ static struct dentry *hpfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, dee.fnode = cpu_to_le32(fno); dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(local_get_seconds(dir->i_sb)); result = new_inode(dir->i_sb); - if (!result) + if (!result) { + err = -ENOMEM; goto bail2; + } hpfs_init_inode(result); result->i_ino = fno; hpfs_i(result)->i_parent_dir = dir->i_ino; @@ -153,9 +155,10 @@ static int hpfs_create(struct mnt_idmap *idmap, struct inode *dir, dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(local_get_seconds(dir->i_sb)); result = new_inode(dir->i_sb); - if (!result) + if (!result) { + err = -ENOMEM; goto bail1; - + } hpfs_init_inode(result); result->i_ino = fno; result->i_mode |= S_IFREG; @@ -239,9 +242,10 @@ static int hpfs_mknod(struct mnt_idmap *idmap, struct inode *dir, dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(local_get_seconds(dir->i_sb)); result = new_inode(dir->i_sb); - if (!result) + if (!result) { + err = -ENOMEM; goto bail1; - + } hpfs_init_inode(result); result->i_ino = fno; hpfs_i(result)->i_parent_dir = dir->i_ino; @@ -314,8 +318,10 @@ static int hpfs_symlink(struct mnt_idmap *idmap, struct inode *dir, dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(local_get_seconds(dir->i_sb)); result = new_inode(dir->i_sb); - if (!result) + if (!result) { + err = -ENOMEM; goto bail1; + } result->i_ino = fno; hpfs_init_inode(result); hpfs_i(result)->i_parent_dir = dir->i_ino; From 706000971c7cf18b63f0376a9966c387b096ad54 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 3 Sep 2025 11:15:02 -0400 Subject: [PATCH 1128/2711] clk: tegra: audio-sync: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/tegra/clk-audio-sync.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/tegra/clk-audio-sync.c b/drivers/clk/tegra/clk-audio-sync.c index 2c4bb96eae16..468a4403f147 100644 --- a/drivers/clk/tegra/clk-audio-sync.c +++ b/drivers/clk/tegra/clk-audio-sync.c @@ -17,15 +17,15 @@ static unsigned long clk_sync_source_recalc_rate(struct clk_hw *hw, return sync->rate; } -static long clk_sync_source_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_sync_source_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); - if (rate > sync->max_rate) + if (req->rate > sync->max_rate) return -EINVAL; else - return rate; + return 0; } static int clk_sync_source_set_rate(struct clk_hw *hw, unsigned long rate, @@ -38,7 +38,7 @@ static int clk_sync_source_set_rate(struct clk_hw *hw, unsigned long rate, } const struct clk_ops tegra_clk_sync_source_ops = { - .round_rate = clk_sync_source_round_rate, + .determine_rate = clk_sync_source_determine_rate, .set_rate = clk_sync_source_set_rate, .recalc_rate = clk_sync_source_recalc_rate, }; From 3891c3c70012d634963b0203152aef5eeb079d47 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 3 Sep 2025 11:15:03 -0400 Subject: [PATCH 1129/2711] clk: tegra: divider: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/tegra/clk-divider.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c index 38daf483ddf1..37439fcb3ac0 100644 --- a/drivers/clk/tegra/clk-divider.c +++ b/drivers/clk/tegra/clk-divider.c @@ -58,23 +58,31 @@ static unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw, return rate; } -static long clk_frac_div_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_frac_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); int div, mul; - unsigned long output_rate = *prate; + unsigned long output_rate = req->best_parent_rate; - if (!rate) - return output_rate; + if (!req->rate) { + req->rate = output_rate; - div = get_div(divider, rate, output_rate); - if (div < 0) - return *prate; + return 0; + } + + div = get_div(divider, req->rate, output_rate); + if (div < 0) { + req->rate = req->best_parent_rate; + + return 0; + } mul = get_mul(divider); - return DIV_ROUND_UP(output_rate * mul, div + mul); + req->rate = DIV_ROUND_UP(output_rate * mul, div + mul); + + return 0; } static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate, @@ -127,7 +135,7 @@ static void clk_divider_restore_context(struct clk_hw *hw) const struct clk_ops tegra_clk_frac_div_ops = { .recalc_rate = clk_frac_div_recalc_rate, .set_rate = clk_frac_div_set_rate, - .round_rate = clk_frac_div_round_rate, + .determine_rate = clk_frac_div_determine_rate, .restore_context = clk_divider_restore_context, }; From e3d1744baa7f81de9e5fd30f26964f27b3a61510 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 3 Sep 2025 11:15:04 -0400 Subject: [PATCH 1130/2711] clk: tegra: periph: divider: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate(). Note that this change also requires the same migration to drivers/clk/tegra/clk-divider.c. Signed-off-by: Brian Masney --- drivers/clk/tegra/clk-periph.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index fa0cd7bb8ee6..6ebeaa7cb656 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -51,16 +51,10 @@ static int clk_periph_determine_rate(struct clk_hw *hw, struct tegra_clk_periph *periph = to_clk_periph(hw); const struct clk_ops *div_ops = periph->div_ops; struct clk_hw *div_hw = &periph->divider.hw; - long rate; __clk_hw_set_clk(div_hw, hw); - rate = div_ops->round_rate(div_hw, req->rate, &req->best_parent_rate); - if (rate < 0) - return rate; - - req->rate = (unsigned long)rate; - return 0; + return div_ops->determine_rate(div_hw, req); } static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate, From 65227c79e09c1399c6a2c01b5b0f4652fd7e5aed Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 3 Sep 2025 11:15:05 -0400 Subject: [PATCH 1131/2711] clk: tegra: pll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/tegra/clk-pll.c | 52 ++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 100b5d9b7e26..591b9f0c155a 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -840,8 +840,8 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, return ret; } -static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct tegra_clk_pll *pll = to_clk_pll(hw); struct tegra_clk_pll_freq_table cfg; @@ -849,15 +849,20 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, if (pll->params->flags & TEGRA_PLL_FIXED) { /* PLLM/MB are used for memory; we do not change rate */ if (pll->params->flags & (TEGRA_PLLM | TEGRA_PLLMB)) - return clk_hw_get_rate(hw); - return pll->params->fixed_rate; + req->rate = clk_hw_get_rate(hw); + else + req->rate = pll->params->fixed_rate; + + return 0; } - if (_get_table_rate(hw, &cfg, rate, *prate) && - pll->params->calc_rate(hw, &cfg, rate, *prate)) + if (_get_table_rate(hw, &cfg, req->rate, req->best_parent_rate) && + pll->params->calc_rate(hw, &cfg, req->rate, req->best_parent_rate)) return -EINVAL; - return cfg.output_rate; + req->rate = cfg.output_rate; + + return 0; } static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, @@ -1057,7 +1062,7 @@ const struct clk_ops tegra_clk_pll_ops = { .enable = clk_pll_enable, .disable = clk_pll_disable, .recalc_rate = clk_pll_recalc_rate, - .round_rate = clk_pll_round_rate, + .determine_rate = clk_pll_determine_rate, .set_rate = clk_pll_set_rate, .restore_context = tegra_clk_pll_restore_context, }; @@ -1195,7 +1200,7 @@ static const struct clk_ops tegra_clk_pllu_ops = { .enable = clk_pllu_enable, .disable = clk_pll_disable, .recalc_rate = clk_pll_recalc_rate, - .round_rate = clk_pll_round_rate, + .determine_rate = clk_pll_determine_rate, .set_rate = clk_pll_set_rate, }; @@ -1353,15 +1358,15 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate, return ret; } -static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_pll_ramp_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct tegra_clk_pll *pll = to_clk_pll(hw); struct tegra_clk_pll_freq_table cfg; int ret, p_div; - u64 output_rate = *prate; + u64 output_rate = req->best_parent_rate; - ret = _pll_ramp_calc_pll(hw, &cfg, rate, *prate); + ret = _pll_ramp_calc_pll(hw, &cfg, req->rate, req->best_parent_rate); if (ret < 0) return ret; @@ -1375,7 +1380,9 @@ static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate, output_rate *= cfg.n; do_div(output_rate, cfg.m * p_div); - return output_rate; + req->rate = output_rate; + + return 0; } static void _pllcx_strobe(struct tegra_clk_pll *pll) @@ -1598,12 +1605,15 @@ static unsigned long clk_pllre_recalc_rate(struct clk_hw *hw, return rate; } -static long clk_pllre_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_pllre_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct tegra_clk_pll *pll = to_clk_pll(hw); - return _pllre_calc_rate(pll, NULL, rate, *prate); + req->rate = _pllre_calc_rate(pll, NULL, req->rate, + req->best_parent_rate); + + return 0; } static int clk_plle_tegra114_enable(struct clk_hw *hw) @@ -2003,7 +2013,7 @@ static const struct clk_ops tegra_clk_pllxc_ops = { .enable = clk_pll_enable, .disable = clk_pll_disable, .recalc_rate = clk_pll_recalc_rate, - .round_rate = clk_pll_ramp_round_rate, + .determine_rate = clk_pll_ramp_determine_rate, .set_rate = clk_pllxc_set_rate, }; @@ -2012,7 +2022,7 @@ static const struct clk_ops tegra_clk_pllc_ops = { .enable = clk_pllc_enable, .disable = clk_pllc_disable, .recalc_rate = clk_pll_recalc_rate, - .round_rate = clk_pll_ramp_round_rate, + .determine_rate = clk_pll_ramp_determine_rate, .set_rate = clk_pllc_set_rate, }; @@ -2021,7 +2031,7 @@ static const struct clk_ops tegra_clk_pllre_ops = { .enable = clk_pll_enable, .disable = clk_pll_disable, .recalc_rate = clk_pllre_recalc_rate, - .round_rate = clk_pllre_round_rate, + .determine_rate = clk_pllre_determine_rate, .set_rate = clk_pllre_set_rate, }; @@ -2321,7 +2331,7 @@ static const struct clk_ops tegra_clk_pllss_ops = { .enable = clk_pll_enable, .disable = clk_pll_disable, .recalc_rate = clk_pll_recalc_rate, - .round_rate = clk_pll_ramp_round_rate, + .determine_rate = clk_pll_ramp_determine_rate, .set_rate = clk_pllxc_set_rate, .restore_context = tegra_clk_pll_restore_context, }; From 13e19a074be46c1c24648a426c77f148ac88e398 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 3 Sep 2025 11:15:06 -0400 Subject: [PATCH 1132/2711] clk: tegra: super: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate(). Note that this change also requires the same migration to drivers/clk/tegra/clk-divider.c. Signed-off-by: Brian Masney --- drivers/clk/tegra/clk-super.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c index 7ec47942720c..51fb356e770e 100644 --- a/drivers/clk/tegra/clk-super.c +++ b/drivers/clk/tegra/clk-super.c @@ -147,17 +147,10 @@ static int clk_super_determine_rate(struct clk_hw *hw, { struct tegra_clk_super_mux *super = to_clk_super_mux(hw); struct clk_hw *div_hw = &super->frac_div.hw; - unsigned long rate; __clk_hw_set_clk(div_hw, hw); - rate = super->div_ops->round_rate(div_hw, req->rate, - &req->best_parent_rate); - if (rate < 0) - return rate; - - req->rate = rate; - return 0; + return super->div_ops->determine_rate(div_hw, req); } static unsigned long clk_super_recalc_rate(struct clk_hw *hw, From 3b9877b162c9a22d38c081184db48bd8b2e5e8cc Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 3 Sep 2025 11:15:07 -0400 Subject: [PATCH 1133/2711] clk: tegra: tegra210-emc: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Signed-off-by: Brian Masney --- drivers/clk/tegra/clk-tegra210-emc.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra210-emc.c b/drivers/clk/tegra/clk-tegra210-emc.c index 672ca8c184d2..fbf3c894eb56 100644 --- a/drivers/clk/tegra/clk-tegra210-emc.c +++ b/drivers/clk/tegra/clk-tegra210-emc.c @@ -86,22 +86,30 @@ static unsigned long tegra210_clk_emc_recalc_rate(struct clk_hw *hw, return DIV_ROUND_UP(parent_rate * 2, div); } -static long tegra210_clk_emc_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int tegra210_clk_emc_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw); struct tegra210_clk_emc_provider *provider = emc->provider; unsigned int i; - if (!provider || !provider->configs || provider->num_configs == 0) - return clk_hw_get_rate(hw); + if (!provider || !provider->configs || provider->num_configs == 0) { + req->rate = clk_hw_get_rate(hw); - for (i = 0; i < provider->num_configs; i++) { - if (provider->configs[i].rate >= rate) - return provider->configs[i].rate; + return 0; } - return provider->configs[i - 1].rate; + for (i = 0; i < provider->num_configs; i++) { + if (provider->configs[i].rate >= req->rate) { + req->rate = provider->configs[i].rate; + + return 0; + } + } + + req->rate = provider->configs[i - 1].rate; + + return 0; } static struct clk *tegra210_clk_emc_find_parent(struct tegra210_clk_emc *emc, @@ -259,7 +267,7 @@ static int tegra210_clk_emc_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops tegra210_clk_emc_ops = { .get_parent = tegra210_clk_emc_get_parent, .recalc_rate = tegra210_clk_emc_recalc_rate, - .round_rate = tegra210_clk_emc_round_rate, + .determine_rate = tegra210_clk_emc_determine_rate, .set_rate = tegra210_clk_emc_set_rate, }; From ec70154c8a5f69604bb7796fd1fe40d22e9396b5 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 08:48:06 -0400 Subject: [PATCH 1134/2711] clk: ti: dpll: remove round_rate() in favor of determine_rate() This driver implements both the determine_rate() and round_rate() clk ops, and the round_rate() clk ops is deprecated. When both are defined, clk_core_determine_round_nolock() from the clk core will only use the determine_rate() clk ops, so let's remove the round_rate() clk ops since it's unused. Tested-by: Anddreas Kemnade # OMAP3 GTA04, OMAP4 Panda Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Brian Masney --- drivers/clk/ti/dpll.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 3386bd1903df..1f55554e0d73 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -25,7 +25,6 @@ static const struct clk_ops dpll_m4xen_ck_ops = { .enable = &omap3_noncore_dpll_enable, .disable = &omap3_noncore_dpll_disable, .recalc_rate = &omap4_dpll_regm4xen_recalc, - .round_rate = &omap4_dpll_regm4xen_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, .set_parent = &omap3_noncore_dpll_set_parent, .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, @@ -48,7 +47,6 @@ static const struct clk_ops dpll_ck_ops = { .enable = &omap3_noncore_dpll_enable, .disable = &omap3_noncore_dpll_disable, .recalc_rate = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, .set_parent = &omap3_noncore_dpll_set_parent, .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, @@ -61,7 +59,6 @@ static const struct clk_ops dpll_ck_ops = { static const struct clk_ops dpll_no_gate_ck_ops = { .recalc_rate = &omap3_dpll_recalc, .get_parent = &omap2_init_dpll_parent, - .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, .set_parent = &omap3_noncore_dpll_set_parent, .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, @@ -103,7 +100,6 @@ static const struct clk_ops omap3_dpll_ck_ops = { .set_parent = &omap3_noncore_dpll_set_parent, .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, .determine_rate = &omap3_noncore_dpll_determine_rate, - .round_rate = &omap2_dpll_round_rate, }; static const struct clk_ops omap3_dpll5_ck_ops = { @@ -115,7 +111,6 @@ static const struct clk_ops omap3_dpll5_ck_ops = { .set_parent = &omap3_noncore_dpll_set_parent, .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, .determine_rate = &omap3_noncore_dpll_determine_rate, - .round_rate = &omap2_dpll_round_rate, }; static const struct clk_ops omap3_dpll_per_ck_ops = { @@ -127,7 +122,6 @@ static const struct clk_ops omap3_dpll_per_ck_ops = { .set_parent = &omap3_noncore_dpll_set_parent, .set_rate_and_parent = &omap3_dpll4_set_rate_and_parent, .determine_rate = &omap3_noncore_dpll_determine_rate, - .round_rate = &omap2_dpll_round_rate, }; #endif From fa55aea3dcdb309d8c4cc307dedd6c9390d8185e Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 08:48:07 -0400 Subject: [PATCH 1135/2711] clk: ti: dpll: change error return from ~0 to -EINVAL When the requested rate cannot be achieved, omap2_dpll_round_rate() will return ~0. Let's change this to -EINVAL to make the code a little cleaner to read. This is no functional change. Tested-by: Anddreas Kemnade # OMAP3 GTA04, OMAP4 Panda Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Brian Masney --- drivers/clk/ti/clkt_dpll.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c index dfaa4d1f0b64..a8c0fc20f791 100644 --- a/drivers/clk/ti/clkt_dpll.c +++ b/drivers/clk/ti/clkt_dpll.c @@ -277,8 +277,8 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) * possible, programmable rate for this DPLL. Attempts to select the * minimum possible n. Stores the computed (m, n) in the DPLL's * dpll_data structure so set_rate() will not need to call this - * (expensive) function again. Returns ~0 if the target rate cannot - * be rounded, or the rounded rate upon success. + * (expensive) function again. Returns -EINVAL if the target rate + * cannot be rounded, or the rounded rate upon success. */ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, unsigned long *parent_rate) @@ -295,7 +295,7 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, const char *clk_name; if (!clk || !clk->dpll_data) - return ~0; + return -EINVAL; dd = clk->dpll_data; @@ -360,7 +360,7 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, if (prev_min_delta == LONG_MAX) { pr_debug("clock: %s: cannot round to rate %lu\n", clk_name, target_rate); - return ~0; + return -EINVAL; } dd->last_rounded_m = min_delta_m; From e465ad7ef57aa1ec4122fd5b34c182d59629cb91 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 08:48:08 -0400 Subject: [PATCH 1136/2711] clk: ti: dpll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate(). Part of these changes were done using the Coccinelle semantic patch on the cover letter of this series, and the rest of the changes were manually done. omap4_dpll_regm4xen_round_rate() is now only called by omap4_dpll_regm4xen_determine_rate(), so let's merge that functionality into one function. This is needed for another cleanup to completely remove the round_rate() clk ops from the clk core. Tested-by: Anddreas Kemnade # OMAP3 GTA04, OMAP4 Panda Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Brian Masney --- drivers/clk/ti/clkt_dpll.c | 28 ++++++------ drivers/clk/ti/clock.h | 6 +-- drivers/clk/ti/dpll.c | 4 +- drivers/clk/ti/dpll3xxx.c | 7 ++- drivers/clk/ti/dpll44xx.c | 89 +++++++++++++------------------------- include/linux/clk/ti.h | 8 ++-- 6 files changed, 57 insertions(+), 85 deletions(-) diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c index a8c0fc20f791..2ecd66968af4 100644 --- a/drivers/clk/ti/clkt_dpll.c +++ b/drivers/clk/ti/clkt_dpll.c @@ -268,10 +268,9 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) /* DPLL rate rounding code */ /** - * omap2_dpll_round_rate - round a target rate for an OMAP DPLL + * omap2_dpll_determine_rate - round a target rate for an OMAP DPLL * @hw: struct clk_hw containing the struct clk * for a DPLL - * @target_rate: desired DPLL clock rate - * @parent_rate: parent's DPLL clock rate + * @req: rate request * * Given a DPLL and a desired target rate, round the target rate to a * possible, programmable rate for this DPLL. Attempts to select the @@ -280,8 +279,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) * (expensive) function again. Returns -EINVAL if the target rate * cannot be rounded, or the rounded rate upon success. */ -long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, - unsigned long *parent_rate) +int omap2_dpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); int m, n, r, scaled_max_m; @@ -299,15 +297,15 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, dd = clk->dpll_data; - if (dd->max_rate && target_rate > dd->max_rate) - target_rate = dd->max_rate; + if (dd->max_rate && req->rate > dd->max_rate) + req->rate = dd->max_rate; ref_rate = clk_hw_get_rate(dd->clk_ref); clk_name = clk_hw_get_name(hw); pr_debug("clock: %s: starting DPLL round_rate, target rate %lu\n", - clk_name, target_rate); + clk_name, req->rate); - scaled_rt_rp = target_rate / (ref_rate / DPLL_SCALE_FACTOR); + scaled_rt_rp = req->rate / (ref_rate / DPLL_SCALE_FACTOR); scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; dd->last_rounded_rate = 0; @@ -332,7 +330,7 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, if (m > scaled_max_m) break; - r = _dpll_test_mult(&m, n, &new_rate, target_rate, + r = _dpll_test_mult(&m, n, &new_rate, req->rate, ref_rate); /* m can't be set low enough for this n - try with a larger n */ @@ -340,7 +338,7 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, continue; /* skip rates above our target rate */ - delta = target_rate - new_rate; + delta = req->rate - new_rate; if (delta < 0) continue; @@ -359,13 +357,15 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, if (prev_min_delta == LONG_MAX) { pr_debug("clock: %s: cannot round to rate %lu\n", - clk_name, target_rate); + clk_name, req->rate); return -EINVAL; } dd->last_rounded_m = min_delta_m; dd->last_rounded_n = min_delta_n; - dd->last_rounded_rate = target_rate - prev_min_delta; + dd->last_rounded_rate = req->rate - prev_min_delta; - return dd->last_rounded_rate; + req->rate = dd->last_rounded_rate; + + return 0; } diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 2de7acea1ea0..d5e24fe4ae3a 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -273,8 +273,7 @@ int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, u8 index); int omap3_noncore_dpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req); -long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, - unsigned long *parent_rate); +int omap2_dpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req); unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, unsigned long parent_rate); @@ -296,9 +295,6 @@ void omap3_clk_lock_dpll5(void); unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, unsigned long parent_rate); -long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, - unsigned long target_rate, - unsigned long *parent_rate); int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, struct clk_rate_request *req); int omap2_clk_for_each(int (*fn)(struct clk_hw_omap *hw)); diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 1f55554e0d73..971adafd9a8b 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -77,7 +77,7 @@ const struct clk_hw_omap_ops clkhwops_omap3_dpll = {}; static const struct clk_ops omap2_dpll_core_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap2_dpllcore_recalc, - .round_rate = &omap2_dpll_round_rate, + .determine_rate = &omap2_dpll_determine_rate, .set_rate = &omap2_reprogram_dpllcore, }; #else @@ -88,7 +88,7 @@ static const struct clk_ops omap2_dpll_core_ck_ops = {}; static const struct clk_ops omap3_dpll_core_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, + .determine_rate = &omap2_dpll_determine_rate, }; static const struct clk_ops omap3_dpll_ck_ops = { diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c index 00680486b1bd..8c51b988a04f 100644 --- a/drivers/clk/ti/dpll3xxx.c +++ b/drivers/clk/ti/dpll3xxx.c @@ -587,6 +587,7 @@ int omap3_noncore_dpll_determine_rate(struct clk_hw *hw, { struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct dpll_data *dd; + int ret; if (!req->rate) return -EINVAL; @@ -599,8 +600,10 @@ int omap3_noncore_dpll_determine_rate(struct clk_hw *hw, (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { req->best_parent_hw = dd->clk_bypass; } else { - req->rate = omap2_dpll_round_rate(hw, req->rate, - &req->best_parent_rate); + ret = omap2_dpll_determine_rate(hw, req); + if (ret != 0) + return ret; + req->best_parent_hw = dd->clk_ref; } diff --git a/drivers/clk/ti/dpll44xx.c b/drivers/clk/ti/dpll44xx.c index 3fc2cab69a3f..08ed57f181b4 100644 --- a/drivers/clk/ti/dpll44xx.c +++ b/drivers/clk/ti/dpll44xx.c @@ -133,61 +133,6 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, return rate; } -/** - * omap4_dpll_regm4xen_round_rate - round DPLL rate, considering REGM4XEN bit - * @hw: struct hw_clk containing the struct clk * of the DPLL to round a rate for - * @target_rate: the desired rate of the DPLL - * @parent_rate: clock rate of the DPLL parent - * - * Compute the rate that would be programmed into the DPLL hardware - * for @clk if set_rate() were to be provided with the rate - * @target_rate. Takes the REGM4XEN bit into consideration, which is - * needed for the OMAP4 ABE DPLL. Returns the rounded rate (before - * M-dividers) upon success, -EINVAL if @clk is null or not a DPLL, or - * ~0 if an error occurred in omap2_dpll_round_rate(). - */ -long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, - unsigned long target_rate, - unsigned long *parent_rate) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - struct dpll_data *dd; - long r; - - if (!clk || !clk->dpll_data) - return -EINVAL; - - dd = clk->dpll_data; - - dd->last_rounded_m4xen = 0; - - /* - * First try to compute the DPLL configuration for - * target rate without using the 4X multiplier. - */ - r = omap2_dpll_round_rate(hw, target_rate, NULL); - if (r != ~0) - goto out; - - /* - * If we did not find a valid DPLL configuration, try again, but - * this time see if using the 4X multiplier can help. Enabling the - * 4X multiplier is equivalent to dividing the target rate by 4. - */ - r = omap2_dpll_round_rate(hw, target_rate / OMAP4430_REGM4XEN_MULT, - NULL); - if (r == ~0) - return r; - - dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT; - dd->last_rounded_m4xen = 1; - -out: - omap4_dpll_lpmode_recalc(dd); - - return dd->last_rounded_rate; -} - /** * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL * @hw: pointer to the clock to determine rate for @@ -195,7 +140,7 @@ out: * * Determines which DPLL mode to use for reaching a desired rate. * Checks whether the DPLL shall be in bypass or locked mode, and if - * locked, calculates the M,N values for the DPLL via round-rate. + * locked, calculates the M,N values for the DPLL. * Returns 0 on success and a negative error value otherwise. */ int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, @@ -215,8 +160,36 @@ int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { req->best_parent_hw = dd->clk_bypass; } else { - req->rate = omap4_dpll_regm4xen_round_rate(hw, req->rate, - &req->best_parent_rate); + struct clk_rate_request tmp_req; + long r; + + clk_hw_init_rate_request(hw, &tmp_req, req->rate); + dd->last_rounded_m4xen = 0; + + /* + * First try to compute the DPLL configuration for + * target rate without using the 4X multiplier. + */ + + r = omap2_dpll_determine_rate(hw, &tmp_req); + if (r < 0) { + /* + * If we did not find a valid DPLL configuration, try again, but + * this time see if using the 4X multiplier can help. Enabling the + * 4X multiplier is equivalent to dividing the target rate by 4. + */ + tmp_req.rate /= OMAP4430_REGM4XEN_MULT; + r = omap2_dpll_determine_rate(hw, &tmp_req); + if (r < 0) + return r; + + dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT; + dd->last_rounded_m4xen = 1; + } + + omap4_dpll_lpmode_recalc(dd); + + req->rate = dd->last_rounded_rate; req->best_parent_hw = dd->clk_ref; } diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index e656f63efdce..54a3fa370004 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -34,14 +34,14 @@ struct clk_omap_reg { * @clk_ref: struct clk_hw pointer to the clock's reference clock input * @control_reg: register containing the DPLL mode bitfield * @enable_mask: mask of the DPLL mode bitfield in @control_reg - * @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate() - * @last_rounded_m: cache of the last M result of omap2_dpll_round_rate() + * @last_rounded_rate: cache of the last rate result of omap2_dpll_determine_rate() + * @last_rounded_m: cache of the last M result of omap2_dpll_determine_rate() * @last_rounded_m4xen: cache of the last M4X result of - * omap4_dpll_regm4xen_round_rate() + * omap4_dpll_regm4xen_determine_rate() * @last_rounded_lpmode: cache of the last lpmode result of * omap4_dpll_lpmode_recalc() * @max_multiplier: maximum valid non-bypass multiplier value (actual) - * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate() + * @last_rounded_n: cache of the last N result of omap2_dpll_determine_rate() * @min_divider: minimum valid non-bypass divider value (actual) * @max_divider: maximum valid non-bypass divider value (actual) * @max_rate: maximum clock rate for the DPLL From 849804453d5aae560dcec94578ae28d671dba937 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 08:48:09 -0400 Subject: [PATCH 1137/2711] clk: ti: composite: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Tested-by: Anddreas Kemnade # OMAP3 GTA04, OMAP4 Panda Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Brian Masney --- drivers/clk/ti/composite.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c index b85382c370f7..8cba259188d4 100644 --- a/drivers/clk/ti/composite.c +++ b/drivers/clk/ti/composite.c @@ -26,8 +26,8 @@ static unsigned long ti_composite_recalc_rate(struct clk_hw *hw, return ti_clk_divider_ops.recalc_rate(hw, parent_rate); } -static long ti_composite_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int ti_composite_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { return -EINVAL; } @@ -40,7 +40,7 @@ static int ti_composite_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops ti_composite_divider_ops = { .recalc_rate = &ti_composite_recalc_rate, - .round_rate = &ti_composite_round_rate, + .determine_rate = &ti_composite_determine_rate, .set_rate = &ti_composite_set_rate, }; From 7760b3e1729837a814647be524b2b24053324baf Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 08:48:10 -0400 Subject: [PATCH 1138/2711] clk: ti: divider: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Tested-by: Anddreas Kemnade # OMAP3 GTA04, OMAP4 Panda Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Brian Masney --- drivers/clk/ti/divider.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index ade99ab6cfa9..6f58a0f2e74a 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -223,13 +223,15 @@ static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, return bestdiv; } -static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int ti_clk_divider_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int div; - div = ti_clk_divider_bestdiv(hw, rate, prate); + div = ti_clk_divider_bestdiv(hw, req->rate, &req->best_parent_rate); - return DIV_ROUND_UP(*prate, div); + req->rate = DIV_ROUND_UP(req->best_parent_rate, div); + + return 0; } static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, @@ -299,7 +301,7 @@ static void clk_divider_restore_context(struct clk_hw *hw) const struct clk_ops ti_clk_divider_ops = { .recalc_rate = ti_clk_divider_recalc_rate, - .round_rate = ti_clk_divider_round_rate, + .determine_rate = ti_clk_divider_determine_rate, .set_rate = ti_clk_divider_set_rate, .save_context = clk_divider_save_context, .restore_context = clk_divider_restore_context, From 48f8fb402a4f897de78e12956c52c90ab35e4d79 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 08:48:11 -0400 Subject: [PATCH 1139/2711] clk: ti: dra7-atl: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Tested-by: Anddreas Kemnade # OMAP3 GTA04, OMAP4 Panda Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Brian Masney --- drivers/clk/ti/clk-dra7-atl.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index 0eab7f3e2eab..b02f84d49b96 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -120,16 +120,18 @@ static unsigned long atl_clk_recalc_rate(struct clk_hw *hw, return parent_rate / cdesc->divider; } -static long atl_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int atl_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned divider; - divider = (*parent_rate + rate / 2) / rate; + divider = (req->best_parent_rate + req->rate / 2) / req->rate; if (divider > DRA7_ATL_DIVIDER_MASK + 1) divider = DRA7_ATL_DIVIDER_MASK + 1; - return *parent_rate / divider; + req->rate = req->best_parent_rate / divider; + + return 0; } static int atl_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -156,7 +158,7 @@ static const struct clk_ops atl_clk_ops = { .disable = atl_clk_disable, .is_enabled = atl_clk_is_enabled, .recalc_rate = atl_clk_recalc_rate, - .round_rate = atl_clk_round_rate, + .determine_rate = atl_clk_determine_rate, .set_rate = atl_clk_set_rate, }; From d8a97749bab7f4e1561ba52e41b576175897b13f Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 11 Aug 2025 08:48:12 -0400 Subject: [PATCH 1140/2711] clk: ti: fapll: convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series. Tested-by: Anddreas Kemnade # OMAP3 GTA04, OMAP4 Panda Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Brian Masney --- drivers/clk/ti/fapll.c | 48 ++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c index 2db3fc4a443e..4f28138d2d8a 100644 --- a/drivers/clk/ti/fapll.c +++ b/drivers/clk/ti/fapll.c @@ -214,24 +214,27 @@ static int ti_fapll_set_div_mult(unsigned long rate, return 0; } -static long ti_fapll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int ti_fapll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u32 pre_div_p, mult_n; int error; - if (!rate) + if (!req->rate) return -EINVAL; - error = ti_fapll_set_div_mult(rate, *parent_rate, + error = ti_fapll_set_div_mult(req->rate, req->best_parent_rate, &pre_div_p, &mult_n); - if (error) - return error; + if (error) { + req->rate = error; - rate = *parent_rate / pre_div_p; - rate *= mult_n; + return 0; + } - return rate; + req->rate = req->best_parent_rate / pre_div_p; + req->rate *= mult_n; + + return 0; } static int ti_fapll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -268,7 +271,7 @@ static const struct clk_ops ti_fapll_ops = { .is_enabled = ti_fapll_is_enabled, .recalc_rate = ti_fapll_recalc_rate, .get_parent = ti_fapll_get_parent, - .round_rate = ti_fapll_round_rate, + .determine_rate = ti_fapll_determine_rate, .set_rate = ti_fapll_set_rate, }; @@ -399,14 +402,14 @@ static u32 ti_fapll_synth_set_frac_rate(struct fapll_synth *synth, return post_div_m; } -static long ti_fapll_synth_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int ti_fapll_synth_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct fapll_synth *synth = to_synth(hw); struct fapll_data *fd = synth->fd; unsigned long r; - if (ti_fapll_clock_is_bypass(fd) || !synth->div || !rate) + if (ti_fapll_clock_is_bypass(fd) || !synth->div || !req->rate) return -EINVAL; /* Only post divider m available with no fractional divider? */ @@ -414,23 +417,26 @@ static long ti_fapll_synth_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long frac_rate; u32 synth_post_div_m; - frac_rate = ti_fapll_synth_get_frac_rate(hw, *parent_rate); - synth_post_div_m = DIV_ROUND_UP(frac_rate, rate); + frac_rate = ti_fapll_synth_get_frac_rate(hw, + req->best_parent_rate); + synth_post_div_m = DIV_ROUND_UP(frac_rate, req->rate); r = DIV_ROUND_UP(frac_rate, synth_post_div_m); goto out; } - r = *parent_rate * SYNTH_PHASE_K; - if (rate > r) + r = req->best_parent_rate * SYNTH_PHASE_K; + if (req->rate > r) goto out; r = DIV_ROUND_UP_ULL(r, SYNTH_MAX_INT_DIV * SYNTH_MAX_DIV_M); - if (rate < r) + if (req->rate < r) goto out; - r = rate; + r = req->rate; out: - return r; + req->rate = r; + + return 0; } static int ti_fapll_synth_set_rate(struct clk_hw *hw, unsigned long rate, @@ -477,7 +483,7 @@ static const struct clk_ops ti_fapll_synt_ops = { .disable = ti_fapll_synth_disable, .is_enabled = ti_fapll_synth_is_enabled, .recalc_rate = ti_fapll_synth_recalc_rate, - .round_rate = ti_fapll_synth_round_rate, + .determine_rate = ti_fapll_synth_determine_rate, .set_rate = ti_fapll_synth_set_rate, }; From 80cb2b6edd8368f7e1e8bf2f66aabf57aa7de4b7 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 27 Aug 2025 13:12:07 -0400 Subject: [PATCH 1141/2711] clk: scmi: migrate round_rate() to determine_rate() This driver implements both the determine_rate() and round_rate() clk ops, and the round_rate() clk ops is deprecated. When both are defined, clk_core_determine_round_nolock() from the clk core will only use the determine_rate() clk ops. The existing scmi_clk_determine_rate() is a noop implementation that lets the firmware round the rate as appropriate. Drop the existing determine_rate implementation and convert the existing round_rate() implementation over to determine_rate(). scmi_clk_determine_rate() was added recently when the clock parent support was added, so it's not expected that this change will regress anything. Reviewed-by: Sudeep Holla Reviewed-by: Peng Fan Tested-by: Peng Fan #i.MX95-19x19-EVK Signed-off-by: Brian Masney --- drivers/clk/clk-scmi.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c index d2408403283f..78dd2d9c7cab 100644 --- a/drivers/clk/clk-scmi.c +++ b/drivers/clk/clk-scmi.c @@ -54,8 +54,8 @@ static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw, return rate; } -static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int scmi_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u64 fmin, fmax, ftmp; struct scmi_clk *clk = to_scmi_clk(hw); @@ -67,20 +67,27 @@ static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate, * running at then. */ if (clk->info->rate_discrete) - return rate; + return 0; fmin = clk->info->range.min_rate; fmax = clk->info->range.max_rate; - if (rate <= fmin) - return fmin; - else if (rate >= fmax) - return fmax; + if (req->rate <= fmin) { + req->rate = fmin; - ftmp = rate - fmin; + return 0; + } else if (req->rate >= fmax) { + req->rate = fmax; + + return 0; + } + + ftmp = req->rate - fmin; ftmp += clk->info->range.step_size - 1; /* to round up */ do_div(ftmp, clk->info->range.step_size); - return ftmp * clk->info->range.step_size + fmin; + req->rate = ftmp * clk->info->range.step_size + fmin; + + return 0; } static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -119,15 +126,6 @@ static u8 scmi_clk_get_parent(struct clk_hw *hw) return p_idx; } -static int scmi_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) -{ - /* - * Suppose all the requested rates are supported, and let firmware - * to handle the left work. - */ - return 0; -} - static int scmi_clk_enable(struct clk_hw *hw) { struct scmi_clk *clk = to_scmi_clk(hw); @@ -300,7 +298,6 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key) /* Rate ops */ ops->recalc_rate = scmi_clk_recalc_rate; - ops->round_rate = scmi_clk_round_rate; ops->determine_rate = scmi_clk_determine_rate; if (feats_key & BIT(SCMI_CLK_RATE_CTRL_SUPPORTED)) ops->set_rate = scmi_clk_set_rate; From f414269392443f666bd8bef0cb3f0b53d5147be3 Mon Sep 17 00:00:00 2001 From: Per Larsen Date: Wed, 20 Aug 2025 01:10:05 +0000 Subject: [PATCH 1142/2711] KVM: arm64: Correct return value on host version downgrade attempt Once the hypervisor negotiates the FF-A version with the host, it should remain locked-in. However, it is possible to load FF-A as a module first supporting version 1.1 and then 1.0. Without this patch, the FF-A 1.0 driver will use 1.0 data structures to make calls which the hypervisor will incorrectly interpret as 1.1 data structures. With this patch, negotiation will fail. This patch does not change existing functionality in the case where a FF-A 1.2 driver is loaded after a 1.1 driver; the 1.2 driver will need to use 1.1 in order to proceed. Acked-by: Will Deacon Signed-off-by: Per Larsen Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/nvhe/ffa.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c index 3369dd0c4009..2c199d40811e 100644 --- a/arch/arm64/kvm/hyp/nvhe/ffa.c +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c @@ -712,7 +712,10 @@ static void do_ffa_version(struct arm_smccc_res *res, hyp_spin_lock(&version_lock); if (has_version_negotiated) { - res->a0 = hyp_ffa_version; + if (FFA_MINOR_VERSION(ffa_req_version) < FFA_MINOR_VERSION(hyp_ffa_version)) + res->a0 = FFA_RET_NOT_SUPPORTED; + else + res->a0 = hyp_ffa_version; goto unlock; } From 6f4c348b1d5c08f1105e645700962cc4353a8ac9 Mon Sep 17 00:00:00 2001 From: Per Larsen Date: Wed, 20 Aug 2025 01:10:06 +0000 Subject: [PATCH 1143/2711] KVM: arm64: Use SMCCC 1.2 for FF-A initialization and in host handler SMCCC 1.1 and prior allows four registers to be sent back as a result of an FF-A interface. SMCCC 1.2 increases the number of results that can be sent back to 8 and 16 for 32-bit and 64-bit SMC/HVCs respectively. FF-A 1.0 references SMCCC 1.2 (reference [4] on page xi) and FF-A 1.2 explicitly requires SMCCC 1.2 so it should be safe to use this version unconditionally. Moreover, it is simpler to implement FF-A features without having to worry about compatibility with SMCCC 1.1 and older. SMCCC 1.2 requires that SMC32/HVC32 from aarch64 mode preserves x8-x30 but given that there is no reliable way to distinguish 32-bit/64-bit calls, we assume SMC64 unconditionally. This has the benefit of being consistent with the handling of calls that are passed through, i.e., not proxied. (A cleaner solution will become available in FF-A 1.3.) Update the FF-A initialization and host handler code to use SMCCC 1.2. Signed-off-by: Per Larsen Acked-by: Will Deacon Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/nvhe/Makefile | 1 + arch/arm64/kvm/hyp/nvhe/ffa.c | 193 ++++++++++++++++++++----------- 2 files changed, 125 insertions(+), 69 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile index 0b0a68b663d4..a244ec25f8c5 100644 --- a/arch/arm64/kvm/hyp/nvhe/Makefile +++ b/arch/arm64/kvm/hyp/nvhe/Makefile @@ -27,6 +27,7 @@ hyp-obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o stacktrace.o ffa.o hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \ ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o +hyp-obj-y += ../../../kernel/smccc-call.o hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o hyp-obj-y += $(lib-objs) diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c index 2c199d40811e..8290396384a2 100644 --- a/arch/arm64/kvm/hyp/nvhe/ffa.c +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c @@ -71,36 +71,68 @@ static u32 hyp_ffa_version; static bool has_version_negotiated; static hyp_spinlock_t version_lock; -static void ffa_to_smccc_error(struct arm_smccc_res *res, u64 ffa_errno) +static void ffa_to_smccc_error(struct arm_smccc_1_2_regs *res, u64 ffa_errno) { - *res = (struct arm_smccc_res) { + *res = (struct arm_smccc_1_2_regs) { .a0 = FFA_ERROR, .a2 = ffa_errno, }; } -static void ffa_to_smccc_res_prop(struct arm_smccc_res *res, int ret, u64 prop) +static void ffa_to_smccc_res_prop(struct arm_smccc_1_2_regs *res, int ret, u64 prop) { if (ret == FFA_RET_SUCCESS) { - *res = (struct arm_smccc_res) { .a0 = FFA_SUCCESS, - .a2 = prop }; + *res = (struct arm_smccc_1_2_regs) { .a0 = FFA_SUCCESS, + .a2 = prop }; } else { ffa_to_smccc_error(res, ret); } } -static void ffa_to_smccc_res(struct arm_smccc_res *res, int ret) +static void ffa_to_smccc_res(struct arm_smccc_1_2_regs *res, int ret) { ffa_to_smccc_res_prop(res, ret, 0); } static void ffa_set_retval(struct kvm_cpu_context *ctxt, - struct arm_smccc_res *res) + struct arm_smccc_1_2_regs *res) { cpu_reg(ctxt, 0) = res->a0; cpu_reg(ctxt, 1) = res->a1; cpu_reg(ctxt, 2) = res->a2; cpu_reg(ctxt, 3) = res->a3; + cpu_reg(ctxt, 4) = res->a4; + cpu_reg(ctxt, 5) = res->a5; + cpu_reg(ctxt, 6) = res->a6; + cpu_reg(ctxt, 7) = res->a7; + + /* + * DEN0028C 2.6: SMC32/HVC32 call from aarch64 must preserve x8-x30. + * + * In FF-A 1.2, we cannot rely on the function ID sent by the caller to + * detect 32-bit calls because the CPU cycle management interfaces (e.g. + * FFA_MSG_WAIT, FFA_RUN) are 32-bit only but can have 64-bit responses. + * + * FFA-1.3 introduces 64-bit variants of the CPU cycle management + * interfaces. Moreover, FF-A 1.3 clarifies that SMC32 direct requests + * complete with SMC32 direct reponses which *should* allow us use the + * function ID sent by the caller to determine whether to return x8-x17. + * + * Note that we also cannot rely on function IDs in the response. + * + * Given the above, assume SMC64 and send back x0-x17 unconditionally + * as the passthrough code (__kvm_hyp_host_forward_smc) does the same. + */ + cpu_reg(ctxt, 8) = res->a8; + cpu_reg(ctxt, 9) = res->a9; + cpu_reg(ctxt, 10) = res->a10; + cpu_reg(ctxt, 11) = res->a11; + cpu_reg(ctxt, 12) = res->a12; + cpu_reg(ctxt, 13) = res->a13; + cpu_reg(ctxt, 14) = res->a14; + cpu_reg(ctxt, 15) = res->a15; + cpu_reg(ctxt, 16) = res->a16; + cpu_reg(ctxt, 17) = res->a17; } static bool is_ffa_call(u64 func_id) @@ -113,82 +145,92 @@ static bool is_ffa_call(u64 func_id) static int ffa_map_hyp_buffers(u64 ffa_page_count) { - struct arm_smccc_res res; + struct arm_smccc_1_2_regs res; - arm_smccc_1_1_smc(FFA_FN64_RXTX_MAP, - hyp_virt_to_phys(hyp_buffers.tx), - hyp_virt_to_phys(hyp_buffers.rx), - ffa_page_count, - 0, 0, 0, 0, - &res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = FFA_FN64_RXTX_MAP, + .a1 = hyp_virt_to_phys(hyp_buffers.tx), + .a2 = hyp_virt_to_phys(hyp_buffers.rx), + .a3 = ffa_page_count, + }, &res); return res.a0 == FFA_SUCCESS ? FFA_RET_SUCCESS : res.a2; } static int ffa_unmap_hyp_buffers(void) { - struct arm_smccc_res res; + struct arm_smccc_1_2_regs res; - arm_smccc_1_1_smc(FFA_RXTX_UNMAP, - HOST_FFA_ID, - 0, 0, 0, 0, 0, 0, - &res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = FFA_RXTX_UNMAP, + .a1 = HOST_FFA_ID, + }, &res); return res.a0 == FFA_SUCCESS ? FFA_RET_SUCCESS : res.a2; } -static void ffa_mem_frag_tx(struct arm_smccc_res *res, u32 handle_lo, +static void ffa_mem_frag_tx(struct arm_smccc_1_2_regs *res, u32 handle_lo, u32 handle_hi, u32 fraglen, u32 endpoint_id) { - arm_smccc_1_1_smc(FFA_MEM_FRAG_TX, - handle_lo, handle_hi, fraglen, endpoint_id, - 0, 0, 0, - res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = FFA_MEM_FRAG_TX, + .a1 = handle_lo, + .a2 = handle_hi, + .a3 = fraglen, + .a4 = endpoint_id, + }, res); } -static void ffa_mem_frag_rx(struct arm_smccc_res *res, u32 handle_lo, +static void ffa_mem_frag_rx(struct arm_smccc_1_2_regs *res, u32 handle_lo, u32 handle_hi, u32 fragoff) { - arm_smccc_1_1_smc(FFA_MEM_FRAG_RX, - handle_lo, handle_hi, fragoff, HOST_FFA_ID, - 0, 0, 0, - res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = FFA_MEM_FRAG_RX, + .a1 = handle_lo, + .a2 = handle_hi, + .a3 = fragoff, + .a4 = HOST_FFA_ID, + }, res); } -static void ffa_mem_xfer(struct arm_smccc_res *res, u64 func_id, u32 len, +static void ffa_mem_xfer(struct arm_smccc_1_2_regs *res, u64 func_id, u32 len, u32 fraglen) { - arm_smccc_1_1_smc(func_id, len, fraglen, - 0, 0, 0, 0, 0, - res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = func_id, + .a1 = len, + .a2 = fraglen, + }, res); } -static void ffa_mem_reclaim(struct arm_smccc_res *res, u32 handle_lo, +static void ffa_mem_reclaim(struct arm_smccc_1_2_regs *res, u32 handle_lo, u32 handle_hi, u32 flags) { - arm_smccc_1_1_smc(FFA_MEM_RECLAIM, - handle_lo, handle_hi, flags, - 0, 0, 0, 0, - res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = FFA_MEM_RECLAIM, + .a1 = handle_lo, + .a2 = handle_hi, + .a3 = flags, + }, res); } -static void ffa_retrieve_req(struct arm_smccc_res *res, u32 len) +static void ffa_retrieve_req(struct arm_smccc_1_2_regs *res, u32 len) { - arm_smccc_1_1_smc(FFA_FN64_MEM_RETRIEVE_REQ, - len, len, - 0, 0, 0, 0, 0, - res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = FFA_FN64_MEM_RETRIEVE_REQ, + .a1 = len, + .a2 = len, + }, res); } -static void ffa_rx_release(struct arm_smccc_res *res) +static void ffa_rx_release(struct arm_smccc_1_2_regs *res) { - arm_smccc_1_1_smc(FFA_RX_RELEASE, - 0, 0, - 0, 0, 0, 0, 0, - res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = FFA_RX_RELEASE, + }, res); } -static void do_ffa_rxtx_map(struct arm_smccc_res *res, +static void do_ffa_rxtx_map(struct arm_smccc_1_2_regs *res, struct kvm_cpu_context *ctxt) { DECLARE_REG(phys_addr_t, tx, ctxt, 1); @@ -267,7 +309,7 @@ err_unmap: goto out_unlock; } -static void do_ffa_rxtx_unmap(struct arm_smccc_res *res, +static void do_ffa_rxtx_unmap(struct arm_smccc_1_2_regs *res, struct kvm_cpu_context *ctxt) { DECLARE_REG(u32, id, ctxt, 1); @@ -368,7 +410,7 @@ static int ffa_host_unshare_ranges(struct ffa_mem_region_addr_range *ranges, return ret; } -static void do_ffa_mem_frag_tx(struct arm_smccc_res *res, +static void do_ffa_mem_frag_tx(struct arm_smccc_1_2_regs *res, struct kvm_cpu_context *ctxt) { DECLARE_REG(u32, handle_lo, ctxt, 1); @@ -427,7 +469,7 @@ out: } static void __do_ffa_mem_xfer(const u64 func_id, - struct arm_smccc_res *res, + struct arm_smccc_1_2_regs *res, struct kvm_cpu_context *ctxt) { DECLARE_REG(u32, len, ctxt, 1); @@ -521,7 +563,7 @@ err_unshare: __do_ffa_mem_xfer((fid), (res), (ctxt)); \ } while (0); -static void do_ffa_mem_reclaim(struct arm_smccc_res *res, +static void do_ffa_mem_reclaim(struct arm_smccc_1_2_regs *res, struct kvm_cpu_context *ctxt) { DECLARE_REG(u32, handle_lo, ctxt, 1); @@ -634,7 +676,7 @@ static bool ffa_call_supported(u64 func_id) return true; } -static bool do_ffa_features(struct arm_smccc_res *res, +static bool do_ffa_features(struct arm_smccc_1_2_regs *res, struct kvm_cpu_context *ctxt) { DECLARE_REG(u32, id, ctxt, 1); @@ -666,17 +708,21 @@ out_handled: static int hyp_ffa_post_init(void) { size_t min_rxtx_sz; - struct arm_smccc_res res; + struct arm_smccc_1_2_regs res; - arm_smccc_1_1_smc(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0, &res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){ + .a0 = FFA_ID_GET, + }, &res); if (res.a0 != FFA_SUCCESS) return -EOPNOTSUPP; if (res.a2 != HOST_FFA_ID) return -EINVAL; - arm_smccc_1_1_smc(FFA_FEATURES, FFA_FN64_RXTX_MAP, - 0, 0, 0, 0, 0, 0, &res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){ + .a0 = FFA_FEATURES, + .a1 = FFA_FN64_RXTX_MAP, + }, &res); if (res.a0 != FFA_SUCCESS) return -EOPNOTSUPP; @@ -700,7 +746,7 @@ static int hyp_ffa_post_init(void) return 0; } -static void do_ffa_version(struct arm_smccc_res *res, +static void do_ffa_version(struct arm_smccc_1_2_regs *res, struct kvm_cpu_context *ctxt) { DECLARE_REG(u32, ffa_req_version, ctxt, 1); @@ -724,9 +770,10 @@ static void do_ffa_version(struct arm_smccc_res *res, * first if TEE supports it. */ if (FFA_MINOR_VERSION(ffa_req_version) < FFA_MINOR_VERSION(hyp_ffa_version)) { - arm_smccc_1_1_smc(FFA_VERSION, ffa_req_version, 0, - 0, 0, 0, 0, 0, - res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = FFA_VERSION, + .a1 = ffa_req_version, + }, res); if (res->a0 == FFA_RET_NOT_SUPPORTED) goto unlock; @@ -743,7 +790,7 @@ unlock: hyp_spin_unlock(&version_lock); } -static void do_ffa_part_get(struct arm_smccc_res *res, +static void do_ffa_part_get(struct arm_smccc_1_2_regs *res, struct kvm_cpu_context *ctxt) { DECLARE_REG(u32, uuid0, ctxt, 1); @@ -759,9 +806,14 @@ static void do_ffa_part_get(struct arm_smccc_res *res, goto out_unlock; } - arm_smccc_1_1_smc(FFA_PARTITION_INFO_GET, uuid0, uuid1, - uuid2, uuid3, flags, 0, 0, - res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = FFA_PARTITION_INFO_GET, + .a1 = uuid0, + .a2 = uuid1, + .a3 = uuid2, + .a4 = uuid3, + .a5 = flags, + }, res); if (res->a0 != FFA_SUCCESS) goto out_unlock; @@ -794,7 +846,7 @@ out_unlock: bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id) { - struct arm_smccc_res res; + struct arm_smccc_1_2_regs res; /* * There's no way we can tell what a non-standard SMC call might @@ -863,13 +915,16 @@ out_handled: int hyp_ffa_init(void *pages) { - struct arm_smccc_res res; + struct arm_smccc_1_2_regs res; void *tx, *rx; if (kvm_host_psci_config.smccc_version < ARM_SMCCC_VERSION_1_2) return 0; - arm_smccc_1_1_smc(FFA_VERSION, FFA_VERSION_1_1, 0, 0, 0, 0, 0, 0, &res); + arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { + .a0 = FFA_VERSION, + .a1 = FFA_VERSION_1_1, + }, &res); if (res.a0 == FFA_RET_NOT_SUPPORTED) return 0; From 79195f342417ff773048515964707aba3bfe0e41 Mon Sep 17 00:00:00 2001 From: Per Larsen Date: Wed, 20 Aug 2025 01:10:07 +0000 Subject: [PATCH 1144/2711] KVM: arm64: Mark FFA_NOTIFICATION_* calls as unsupported Prevent FFA_NOTIFICATION_* interfaces from being passed through to TZ. Acked-by: Will Deacon Signed-off-by: Per Larsen Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/nvhe/ffa.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c index 8290396384a2..40a785b6ed06 100644 --- a/arch/arm64/kvm/hyp/nvhe/ffa.c +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c @@ -670,6 +670,14 @@ static bool ffa_call_supported(u64 func_id) case FFA_RXTX_MAP: case FFA_MEM_DONATE: case FFA_MEM_RETRIEVE_REQ: + /* Optional notification interfaces added in FF-A 1.1 */ + case FFA_NOTIFICATION_BITMAP_CREATE: + case FFA_NOTIFICATION_BITMAP_DESTROY: + case FFA_NOTIFICATION_BIND: + case FFA_NOTIFICATION_UNBIND: + case FFA_NOTIFICATION_SET: + case FFA_NOTIFICATION_GET: + case FFA_NOTIFICATION_INFO_GET: return false; } From 8d24683e3e0f93b4bfdb558df50923514042817b Mon Sep 17 00:00:00 2001 From: Per Larsen Date: Wed, 20 Aug 2025 01:10:08 +0000 Subject: [PATCH 1145/2711] KVM: arm64: Mark optional FF-A 1.2 interfaces as unsupported Mark FF-A 1.2 interfaces as unsupported lest they get proxied. Acked-by: Will Deacon Signed-off-by: Per Larsen Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/nvhe/ffa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c index 40a785b6ed06..96109aa99c48 100644 --- a/arch/arm64/kvm/hyp/nvhe/ffa.c +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c @@ -678,6 +678,11 @@ static bool ffa_call_supported(u64 func_id) case FFA_NOTIFICATION_SET: case FFA_NOTIFICATION_GET: case FFA_NOTIFICATION_INFO_GET: + /* Optional interfaces added in FF-A 1.2 */ + case FFA_MSG_SEND_DIRECT_REQ2: /* Optional per 7.5.1 */ + case FFA_MSG_SEND_DIRECT_RESP2: /* Optional per 7.5.1 */ + case FFA_CONSOLE_LOG: /* Optional per 13.1: not in Table 13.1 */ + case FFA_PARTITION_INFO_GET_REGS: /* Optional for virtual instances per 13.1 */ return false; } From 3f5952917498e7bb9d227812d4349668f62c413b Mon Sep 17 00:00:00 2001 From: Per Larsen Date: Wed, 20 Aug 2025 01:10:09 +0000 Subject: [PATCH 1146/2711] KVM: arm64: Mask response to FFA_FEATURE call The minimum size and alignment boundary for FFA_RXTX_MAP is returned in bit[1:0]. Mask off any other bits in w2 when reading the minimum buffer size in hyp_ffa_post_init. Acked-by: Will Deacon Signed-off-by: Per Larsen Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/nvhe/ffa.c | 2 +- include/linux/arm_ffa.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c index 96109aa99c48..a8ec1a94f3f8 100644 --- a/arch/arm64/kvm/hyp/nvhe/ffa.c +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c @@ -739,7 +739,7 @@ static int hyp_ffa_post_init(void) if (res.a0 != FFA_SUCCESS) return -EOPNOTSUPP; - switch (res.a2) { + switch (res.a2 & FFA_FEAT_RXTX_MIN_SZ_MASK) { case FFA_FEAT_RXTX_MIN_SZ_4K: min_rxtx_sz = SZ_4K; break; diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index e1634897e159..cd7ee4df9045 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -128,6 +128,7 @@ #define FFA_FEAT_RXTX_MIN_SZ_4K 0 #define FFA_FEAT_RXTX_MIN_SZ_64K 1 #define FFA_FEAT_RXTX_MIN_SZ_16K 2 +#define FFA_FEAT_RXTX_MIN_SZ_MASK GENMASK(1, 0) /* FFA Bus/Device/Driver related */ struct ffa_device { From 162190f2ccdc5964efa2a26e9fc3e56cf80fc29b Mon Sep 17 00:00:00 2001 From: Per Larsen Date: Wed, 20 Aug 2025 01:10:10 +0000 Subject: [PATCH 1147/2711] KVM: arm64: Bump the supported version of FF-A to 1.2 FF-A version 1.2 introduces the DIRECT_REQ2 ABI. Bump the FF-A version preferred by the hypervisor to enable implementation of the 1.2-only FFA_MSG_SEND_DIRECT_REQ2 and FFA_MSG_SEND_RESP2 messaging interfaces. Co-developed-by: Ayrton Munoz Signed-off-by: Ayrton Munoz Acked-by: Will Deacon Signed-off-by: Per Larsen Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/nvhe/ffa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c index a8ec1a94f3f8..4e16f9b96f63 100644 --- a/arch/arm64/kvm/hyp/nvhe/ffa.c +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c @@ -936,7 +936,7 @@ int hyp_ffa_init(void *pages) arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { .a0 = FFA_VERSION, - .a1 = FFA_VERSION_1_1, + .a1 = FFA_VERSION_1_2, }, &res); if (res.a0 == FFA_RET_NOT_SUPPORTED) return 0; @@ -957,10 +957,10 @@ int hyp_ffa_init(void *pages) if (FFA_MAJOR_VERSION(res.a0) != 1) return -EOPNOTSUPP; - if (FFA_MINOR_VERSION(res.a0) < FFA_MINOR_VERSION(FFA_VERSION_1_1)) + if (FFA_MINOR_VERSION(res.a0) < FFA_MINOR_VERSION(FFA_VERSION_1_2)) hyp_ffa_version = res.a0; else - hyp_ffa_version = FFA_VERSION_1_1; + hyp_ffa_version = FFA_VERSION_1_2; tx = pages; pages += KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE; From 8673e5b22e1e114213d3ca74f415034aed45e528 Mon Sep 17 00:00:00 2001 From: Wei-Lin Chang Date: Sat, 9 Aug 2025 21:53:56 +0800 Subject: [PATCH 1148/2711] KVM: arm64: ptdump: Don't test PTE_VALID alongside other attributes The attribute masks and test values in the ptdump code are meant for individual attributes, however for stage-2 ptdump we included PTE_VALID while testing for R, W, X, and AF. This led to some confusion and the flipped output for the executable attribute. Remove PTE_VALID from all attribute masks and values so that each test matches only the relevant bits. Additionally, the executable attribute printing is updated to align with stage-1 ptdump, printing "NX" for non-executable regions and "x " for executable ones. Suggested-by: Anshuman Khandual Suggested-by: Mark Rutland Suggested-by: Sebastian Ene Signed-off-by: Wei-Lin Chang Acked-by: Will Deacon Reviewed-by: Anshuman Khandual Signed-off-by: Marc Zyngier --- arch/arm64/kvm/ptdump.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm64/kvm/ptdump.c b/arch/arm64/kvm/ptdump.c index 098416d7e5c2..dc5acfb00af9 100644 --- a/arch/arm64/kvm/ptdump.c +++ b/arch/arm64/kvm/ptdump.c @@ -32,23 +32,23 @@ static const struct ptdump_prot_bits stage2_pte_bits[] = { .set = " ", .clear = "F", }, { - .mask = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | PTE_VALID, - .val = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | PTE_VALID, + .mask = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R, + .val = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R, .set = "R", .clear = " ", }, { - .mask = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | PTE_VALID, - .val = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | PTE_VALID, + .mask = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W, + .val = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W, .set = "W", .clear = " ", }, { - .mask = KVM_PTE_LEAF_ATTR_HI_S2_XN | PTE_VALID, - .val = PTE_VALID, - .set = " ", - .clear = "X", + .mask = KVM_PTE_LEAF_ATTR_HI_S2_XN, + .val = KVM_PTE_LEAF_ATTR_HI_S2_XN, + .set = "NX", + .clear = "x ", }, { - .mask = KVM_PTE_LEAF_ATTR_LO_S2_AF | PTE_VALID, - .val = KVM_PTE_LEAF_ATTR_LO_S2_AF | PTE_VALID, + .mask = KVM_PTE_LEAF_ATTR_LO_S2_AF, + .val = KVM_PTE_LEAF_ATTR_LO_S2_AF, .set = "AF", .clear = " ", }, { From d5f6bd3ee3f5048f272182dc91675c082773999e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 5 Sep 2025 20:42:10 +0200 Subject: [PATCH 1149/2711] PCI: endpoint: pci-epf-test: Limit PCIe BAR size for fixed BARs Currently, the test allocates BAR sizes according to fixed table bar_size. This does not work with controllers which have fixed size BARs that are smaller than the requested BAR size. One such controller is Renesas R-Car V4H PCIe controller, which has BAR4 size limited to 256 bytes, which is much less than one of the BAR size, 131072 currently requested by this test. A lot of controllers drivers in-tree have fixed size BARs, and they do work perfectly fine, but it is only because their fixed size is larger than the size requested by pci-epf-test.c Adjust the test such that in case a fixed size BAR is detected, the fixed BAR size is used, as that is the only possible option. This helps with test failures reported as follows: pci_epf_test pci_epf_test.0: requested BAR size is larger than fixed size pci_epf_test pci_epf_test.0: Failed to allocate space for BAR4 Signed-off-by: Marek Vasut [mani: reworded description] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Niklas Cassel Link: https://patch.msgid.link/20250905184240.144431-1-marek.vasut+renesas@mailbox.org --- drivers/pci/endpoint/functions/pci-epf-test.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index e091193bd8a8..2418add64104 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -1050,7 +1050,12 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf) if (bar == test_reg_bar) continue; - base = pci_epf_alloc_space(epf, bar_size[bar], bar, + if (epc_features->bar[bar].type == BAR_FIXED) + test_reg_size = epc_features->bar[bar].fixed_size; + else + test_reg_size = bar_size[bar]; + + base = pci_epf_alloc_space(epf, test_reg_size, bar, epc_features, PRIMARY_INTERFACE); if (!base) dev_err(dev, "Failed to allocate space for BAR%d\n", From 665071186ce4af9f83a5d78bcb7a2a3a6b3ecfe7 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Sun, 24 Aug 2025 11:16:40 -0700 Subject: [PATCH 1150/2711] KVM: selftests: Fix typo in hyperv cpuid test message Fix a typo in hyperv_cpuid.c test assertion log: replace "our of supported range" -> "out of supported range". Signed-off-by: Alok Tiwari Link: https://lore.kernel.org/r/20250824181642.629297-1-alok.a.tiwari@oracle.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86/hyperv_cpuid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86/hyperv_cpuid.c index c863a689aa98..3c21af811d8f 100644 --- a/tools/testing/selftests/kvm/x86/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86/hyperv_cpuid.c @@ -45,7 +45,7 @@ static void test_hv_cpuid(struct kvm_vcpu *vcpu, bool evmcs_expected) TEST_ASSERT((entry->function >= 0x40000000) && (entry->function <= 0x40000082), - "function %x is our of supported range", + "function %x is out of supported range", entry->function); TEST_ASSERT(entry->index == 0, From 2f5f8fb9de095e9b255a89269827f1761c714690 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 21 Aug 2025 14:38:41 -0700 Subject: [PATCH 1151/2711] KVM: SEV: Save the SEV policy if and only if LAUNCH_START succeeds Wait until LAUNCH_START fully succeeds to set a VM's SEV/SNP policy so that KVM doesn't keep a potentially stale policy. In practice, the issue is benign as the policy is only used to detect if the VMSA can be decrypted, and the VMSA only needs to be decrypted if LAUNCH_UPDATE and thus LAUNCH_START succeeded. Fixes: 962e2b6152ef ("KVM: SVM: Decrypt SEV VMSA in dump_vmcb() if debugging is enabled") Cc: Tom Lendacky Cc: Kim Phillips Reviewed-by: Tom Lendacky Link: https://lore.kernel.org/r/20250821213841.3462339-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 86fd270a1d6e..a95b862afa23 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -583,8 +583,6 @@ static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) if (copy_from_user(¶ms, u64_to_user_ptr(argp->data), sizeof(params))) return -EFAULT; - sev->policy = params.policy; - memset(&start, 0, sizeof(start)); dh_blob = NULL; @@ -632,6 +630,7 @@ static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) goto e_free_session; } + sev->policy = params.policy; sev->handle = start.handle; sev->fd = argp->sev_fd; @@ -2205,8 +2204,6 @@ static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) start.desired_tsc_khz = kvm->arch.default_tsc_khz; } - sev->policy = params.policy; - sev->snp_context = snp_context_create(kvm, argp); if (!sev->snp_context) return -ENOTTY; @@ -2222,6 +2219,7 @@ static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) goto e_free_context; } + sev->policy = params.policy; sev->fd = argp->sev_fd; rc = snp_bind_asid(kvm, &argp->error); if (rc) { From 4cd661c248b6671914ad59e16760bb6d908dfc61 Mon Sep 17 00:00:00 2001 From: Nuno Das Neves Date: Wed, 13 Aug 2025 11:20:57 -0700 Subject: [PATCH 1152/2711] hyperv: Add missing field to hv_output_map_device_interrupt This field is unused, but the correct structure size is needed when computing the amount of space for the output argument to reside, so that it does not cross a page boundary. Signed-off-by: Nuno Das Neves Reviewed-by: Michael Kelley Signed-off-by: Wei Liu --- include/hyperv/hvhdk_mini.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/hyperv/hvhdk_mini.h b/include/hyperv/hvhdk_mini.h index 42e7876455b5..858f6a3925b3 100644 --- a/include/hyperv/hvhdk_mini.h +++ b/include/hyperv/hvhdk_mini.h @@ -301,6 +301,7 @@ struct hv_input_map_device_interrupt { /* HV_OUTPUT_MAP_DEVICE_INTERRUPT */ struct hv_output_map_device_interrupt { struct hv_interrupt_entry interrupt_entry; + u64 ext_status_deprecated[5]; } __packed; /* HV_INPUT_UNMAP_DEVICE_INTERRUPT */ From 47691ced158ab3a7ce2189b857b19c0c99a9aa80 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Tue, 12 Aug 2025 19:48:45 +0000 Subject: [PATCH 1153/2711] clocksource: hyper-v: Skip unnecessary checks for the root partition The HV_ACCESS_TSC_INVARIANT bit is always zero when Linux runs as the root partition. The root partition will see directly what the hardware provides. The old logic in ms_hyperv_init_platform caused the native TSC clock source to be incorrectly marked as unstable on x86. Fix it. Skip the unnecessary checks in code for the root partition. Add one extra comment in code to clarify the behavior. Reviewed-by: Nuno Das Neves Signed-off-by: Wei Liu --- arch/x86/kernel/cpu/mshyperv.c | 11 ++++++++++- drivers/clocksource/hyperv_timer.c | 10 +++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index c78f860419d6..25773af116bc 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -565,6 +565,11 @@ static void __init ms_hyperv_init_platform(void) machine_ops.crash_shutdown = hv_machine_crash_shutdown; #endif #endif + /* + * HV_ACCESS_TSC_INVARIANT is always zero for the root partition. Root + * partition doesn't need to write to synthetic MSR to enable invariant + * TSC feature. It sees what the hardware provides. + */ if (ms_hyperv.features & HV_ACCESS_TSC_INVARIANT) { /* * Writing to synthetic MSR 0x40000118 updates/changes the @@ -636,8 +641,12 @@ static void __init ms_hyperv_init_platform(void) * TSC should be marked as unstable only after Hyper-V * clocksource has been initialized. This ensures that the * stability of the sched_clock is not altered. + * + * HV_ACCESS_TSC_INVARIANT is always zero for the root partition. No + * need to check for it. */ - if (!(ms_hyperv.features & HV_ACCESS_TSC_INVARIANT)) + if (!hv_root_partition() && + !(ms_hyperv.features & HV_ACCESS_TSC_INVARIANT)) mark_tsc_unstable("running on Hyper-V"); hardlockup_detector_disable(); diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index 2edc13ca184e..10356d4ec55c 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -549,14 +549,22 @@ static void __init hv_init_tsc_clocksource(void) union hv_reference_tsc_msr tsc_msr; /* + * When running as a guest partition: + * * If Hyper-V offers TSC_INVARIANT, then the virtualized TSC correctly * handles frequency and offset changes due to live migration, * pause/resume, and other VM management operations. So lower the * Hyper-V Reference TSC rating, causing the generic TSC to be used. * TSC_INVARIANT is not offered on ARM64, so the Hyper-V Reference * TSC will be preferred over the virtualized ARM64 arch counter. + * + * When running as the root partition: + * + * There is no HV_ACCESS_TSC_INVARIANT feature. Always lower the rating + * of the Hyper-V Reference TSC. */ - if (ms_hyperv.features & HV_ACCESS_TSC_INVARIANT) { + if ((ms_hyperv.features & HV_ACCESS_TSC_INVARIANT) || + hv_root_partition()) { hyperv_cs_tsc.rating = 250; hyperv_cs_msr.rating = 245; } From f26c9306dff818bbf4ef545c5a5ee0eca7149922 Mon Sep 17 00:00:00 2001 From: Nuno Das Neves Date: Tue, 2 Sep 2025 16:48:33 -0700 Subject: [PATCH 1154/2711] mshv: Add support for a new parent partition configuration Detect booting as an "L1VH" partition. This is a new scenario very similar to root partition where the mshv_root driver can be used to create and manage guest partitions. It mostly works the same as root partition, but there are some differences in how various features are handled. hv_l1vh_partition() is introduced to handle these cases. Add hv_parent_partition() which returns true for either case, replacing some hv_root_partition() checks. Signed-off-by: Nuno Das Neves Acked-by: Wei Liu Reviewed-by: Michael Kelley Signed-off-by: Wei Liu --- drivers/hv/hv_common.c | 22 +++++++++++++--------- drivers/hv/mshv_root_main.c | 26 +++++++++++++------------- include/asm-generic/mshyperv.h | 11 +++++++++++ 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index 49898d10faff..e109a620c83f 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -257,7 +257,7 @@ static void hv_kmsg_dump_register(void) static inline bool hv_output_page_exists(void) { - return hv_root_partition() || IS_ENABLED(CONFIG_HYPERV_VTL_MODE); + return hv_parent_partition() || IS_ENABLED(CONFIG_HYPERV_VTL_MODE); } void __init hv_get_partition_id(void) @@ -377,7 +377,7 @@ int __init hv_common_init(void) BUG_ON(!hyperv_pcpu_output_arg); } - if (hv_root_partition()) { + if (hv_parent_partition()) { hv_synic_eventring_tail = alloc_percpu(u8 *); BUG_ON(!hv_synic_eventring_tail); } @@ -531,7 +531,7 @@ int hv_common_cpu_init(unsigned int cpu) if (msr_vp_index > hv_max_vp_index) hv_max_vp_index = msr_vp_index; - if (hv_root_partition()) { + if (hv_parent_partition()) { synic_eventring_tail = (u8 **)this_cpu_ptr(hv_synic_eventring_tail); *synic_eventring_tail = kcalloc(HV_SYNIC_SINT_COUNT, sizeof(u8), flags); @@ -558,7 +558,7 @@ int hv_common_cpu_die(unsigned int cpu) * originally allocated memory is reused in hv_common_cpu_init(). */ - if (hv_root_partition()) { + if (hv_parent_partition()) { synic_eventring_tail = this_cpu_ptr(hv_synic_eventring_tail); kfree(*synic_eventring_tail); *synic_eventring_tail = NULL; @@ -729,13 +729,17 @@ void hv_identify_partition_type(void) * the root partition setting if also a Confidential VM. */ if ((ms_hyperv.priv_high & HV_CREATE_PARTITIONS) && - (ms_hyperv.priv_high & HV_CPU_MANAGEMENT) && !(ms_hyperv.priv_high & HV_ISOLATION)) { - pr_info("Hyper-V: running as root partition\n"); - if (IS_ENABLED(CONFIG_MSHV_ROOT)) - hv_curr_partition_type = HV_PARTITION_TYPE_ROOT; - else + + if (!IS_ENABLED(CONFIG_MSHV_ROOT)) { pr_crit("Hyper-V: CONFIG_MSHV_ROOT not enabled!\n"); + } else if (ms_hyperv.priv_high & HV_CPU_MANAGEMENT) { + pr_info("Hyper-V: running as root partition\n"); + hv_curr_partition_type = HV_PARTITION_TYPE_ROOT; + } else { + pr_info("Hyper-V: running as L1VH partition\n"); + hv_curr_partition_type = HV_PARTITION_TYPE_L1VH; + } } } diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index 72df774e410a..aa20a5c96afa 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -37,12 +37,6 @@ MODULE_AUTHOR("Microsoft"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Microsoft Hyper-V root partition VMM interface /dev/mshv"); -/* TODO move this to mshyperv.h when needed outside driver */ -static inline bool hv_parent_partition(void) -{ - return hv_root_partition(); -} - /* TODO move this to another file when debugfs code is added */ enum hv_stats_vp_counters { /* HV_THREAD_COUNTER */ #if defined(CONFIG_X86) @@ -2074,9 +2068,13 @@ static int __init hv_retrieve_scheduler_type(enum hv_scheduler_type *out) /* Retrieve and stash the supported scheduler type */ static int __init mshv_retrieve_scheduler_type(struct device *dev) { - int ret; + int ret = 0; + + if (hv_l1vh_partition()) + hv_scheduler_type = HV_SCHEDULER_TYPE_CORE_SMT; + else + ret = hv_retrieve_scheduler_type(&hv_scheduler_type); - ret = hv_retrieve_scheduler_type(&hv_scheduler_type); if (ret) return ret; @@ -2203,9 +2201,6 @@ static int __init mshv_root_partition_init(struct device *dev) { int err; - if (mshv_retrieve_scheduler_type(dev)) - return -ENODEV; - err = root_scheduler_init(dev); if (err) return err; @@ -2227,7 +2222,7 @@ static int __init mshv_parent_partition_init(void) struct device *dev; union hv_hypervisor_version_info version_info; - if (!hv_root_partition() || is_kdump_kernel()) + if (!hv_parent_partition() || is_kdump_kernel()) return -ENODEV; if (hv_get_hypervisor_version(&version_info)) @@ -2264,7 +2259,12 @@ static int __init mshv_parent_partition_init(void) mshv_cpuhp_online = ret; - ret = mshv_root_partition_init(dev); + ret = mshv_retrieve_scheduler_type(dev); + if (ret) + goto remove_cpu_state; + + if (hv_root_partition()) + ret = mshv_root_partition_init(dev); if (ret) goto remove_cpu_state; diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index a729b77983fa..dbd4c2f3aee3 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -31,6 +31,7 @@ enum hv_partition_type { HV_PARTITION_TYPE_GUEST, HV_PARTITION_TYPE_ROOT, + HV_PARTITION_TYPE_L1VH, }; struct ms_hyperv_info { @@ -354,12 +355,22 @@ static inline bool hv_root_partition(void) { return hv_curr_partition_type == HV_PARTITION_TYPE_ROOT; } +static inline bool hv_l1vh_partition(void) +{ + return hv_curr_partition_type == HV_PARTITION_TYPE_L1VH; +} +static inline bool hv_parent_partition(void) +{ + return hv_root_partition() || hv_l1vh_partition(); +} int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages); int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id); int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags); #else /* CONFIG_MSHV_ROOT */ static inline bool hv_root_partition(void) { return false; } +static inline bool hv_l1vh_partition(void) { return false; } +static inline bool hv_parent_partition(void) { return false; } static inline int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages) { return -EOPNOTSUPP; From ac7b0a5cd331862c3d4d49eae71ed93f8f5082f3 Mon Sep 17 00:00:00 2001 From: Abhishek Tiwari Date: Mon, 1 Sep 2025 05:00:00 -0700 Subject: [PATCH 1155/2711] Drivers: hv: util: Cosmetic changes for hv_utils_transport.c Fix issues reported by checkpatch.pl script for hv_utils_transport.c file - Update pr_warn() calls to use __func__ for consistent logging context. - else should follow close brace '}' No functional changes intended. Signed-off-by: Abhishek Tiwari Reviewed-by: Naman Jain Signed-off-by: Wei Liu --- drivers/hv/hv_utils_transport.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index 832885198643..b3de35ff6334 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -129,8 +129,7 @@ static int hvt_op_open(struct inode *inode, struct file *file) * device gets released. */ hvt->mode = HVUTIL_TRANSPORT_CHARDEV; - } - else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) { + } else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) { /* * We're switching from netlink communication to using char * device. Issue the reset first. @@ -195,7 +194,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) } spin_unlock(&hvt_list_lock); if (!hvt_found) { - pr_warn("hvt_cn_callback: spurious message received!\n"); + pr_warn("%s: spurious message received!\n", __func__); return; } @@ -210,7 +209,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) hvt_found->on_msg(msg->data, msg->len); else - pr_warn("hvt_cn_callback: unexpected netlink message!\n"); + pr_warn("%s: unexpected netlink message!\n", __func__); mutex_unlock(&hvt->lock); } @@ -260,8 +259,9 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len, hvt->outmsg_len = len; hvt->on_read = on_read_cb; wake_up_interruptible(&hvt->outmsg_q); - } else + } else { ret = -ENOMEM; + } out_unlock: mutex_unlock(&hvt->lock); return ret; From 2d0ddbb65cef99aab241378b0f4ff2d6ea8c3a5a Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Sun, 31 Aug 2025 09:04:06 -0700 Subject: [PATCH 1156/2711] Drivers: hv: Simplify data structures for VMBus channel close message struct vmbus_close_msg is used for sending the VMBus channel close message. It contains a struct vmbus_channel_msginfo, which has a flex array member at the end. The latter's presence in the middle of struct vmbus_close_msg causes warnings when built with -Wflex-array-member-not-at-end. But the struct vmbus_channel_msginfo is unused because the Hyper-V host does not send a response to the channel close message. So remove the struct vmbus_channel_msginfo. Then, since the only remaining field is struct vmbus_channel_close_channel, also remove the containing struct vmbus_close_msg and directly use struct vmbus_channel_close_channel. Besides eliminating unnecessary complexity, these changes resolve the -Wflex-array-member-not-at-end warnings. Signed-off-by: Michael Kelley Reviewed-by: Tianyu Lan Signed-off-by: Wei Liu --- drivers/hv/channel.c | 2 +- include/linux/hyperv.h | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 7c7c66e0dc3f..162d6aeece7b 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -925,7 +925,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel) /* Send a closing message */ - msg = &channel->close_msg.msg; + msg = &channel->close_msg; msg->header.msgtype = CHANNELMSG_CLOSECHANNEL; msg->child_relid = channel->offermsg.child_relid; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index a59c5c3e95fb..59826c89171c 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -707,11 +707,6 @@ struct vmbus_channel_msginfo { unsigned char msg[]; }; -struct vmbus_close_msg { - struct vmbus_channel_msginfo info; - struct vmbus_channel_close_channel msg; -}; - enum vmbus_device_type { HV_IDE = 0, HV_SCSI, @@ -800,7 +795,7 @@ struct vmbus_channel { struct hv_ring_buffer_info outbound; /* send to parent */ struct hv_ring_buffer_info inbound; /* receive from parent */ - struct vmbus_close_msg close_msg; + struct vmbus_channel_close_channel close_msg; /* Statistics */ u64 interrupts; /* Host to Guest interrupts */ From 945f50036169714dd30b8cb37370059f2dc924e1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 8 Sep 2025 17:36:28 -0300 Subject: [PATCH 1157/2711] perf symbols: Handle 'N' symbols in /proc/kallsyms I started seeing this in recent Fedora 42 kernels: # uname -a Linux number 6.16.3-200.fc42.x86_64 #1 SMP PREEMPT_DYNAMIC Sat Aug 23 17:02:17 UTC 2025 x86_64 GNU/Linux # # perf test vmlinux 1: vmlinux symtab matches kallsyms : FAILED! # Rust is enabled and these were the symbols causing the above failure, i.e. found in vmlinux but not in /proc/kallsyms: $ grep -w N /proc/kallsyms 0000000000000000 N __pfx__RNCINvNtNtNtCsbDUBuN8AbD4_4core4iter8adapters3map12map_try_foldjNtCs6vVzKs5jPr6_12drm_panic_qr7VersionuINtNtNtBa_3ops12control_flow11ControlFlowB10_ENcB10_0NCINvNvNtNtNtB8_6traits8iterator8Iterator4find5checkB10_NCNvMB12_B10_13from_segments0E0E0B12_ 0000000000000000 N _RNCINvNtNtNtCsbDUBuN8AbD4_4core4iter8adapters3map12map_try_foldjNtCs6vVzKs5jPr6_12drm_panic_qr7VersionuINtNtNtBa_3ops12control_flow11ControlFlowB10_ENcB10_0NCINvNvNtNtNtB8_6traits8iterator8Iterator4find5checkB10_NCNvMB12_B10_13from_segments0E0E0B12_ $ So accept those 'N' symbols as well. About them, from 'man nm': "N" The symbol is a debugging symbol. "n" The symbol is in a non-data, non-code, non-debug read-only section. Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Miguel Ojeda Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 3fed54de5401..3d04382687d1 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -107,9 +107,14 @@ static enum dso_binary_type binary_type_symtab[] = { static bool symbol_type__filter(char __symbol_type) { // Since 'U' == undefined and 'u' == unique global symbol, we can't use toupper there + // 'N' is for debugging symbols, 'n' is a non-data, non-code, non-debug read-only section. + // According to 'man nm'. + // 'N' first seen in: + // ffffffff9b35d130 N __pfx__RNCINvNtNtNtCsbDUBuN8AbD4_4core4iter8adapters3map12map_try_foldjNtCs6vVzKs5jPr6_12drm_panic_qr7VersionuINtNtNtBa_3ops12control_flow11ControlFlowB10_ENcB10_0NCINvNvNtNtNtB8_6traits8iterator8Iterator4find5checkB10_NCNvMB12_B10_13from_segments0E0E0B12_ + // a seemingly Rust mangled name char symbol_type = toupper(__symbol_type); return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B' || - __symbol_type == 'u' || __symbol_type == 'l'; + __symbol_type == 'u' || __symbol_type == 'l' || __symbol_type == 'N'; } static int prefix_underscores_count(const char *str) From d5ad57fc428c1e44335d25c822eb89645f425f32 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 9 Sep 2025 16:03:32 +0200 Subject: [PATCH 1158/2711] dt-bindings: input: qcom,pm8941-pwrkey: Fix formatting of descriptions Property descriptions should indent with two spaces and they do not need to preserve formatting. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250909140331.69756-2-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- .../bindings/input/qcom,pm8941-pwrkey.yaml | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml index 62314a5fdce5..72006a14fd41 100644 --- a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml +++ b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml @@ -25,23 +25,22 @@ properties: maxItems: 1 debounce: - description: | - Time in microseconds that key must be pressed or - released for state change interrupt to trigger. + description: + Time in microseconds that key must be pressed or released for state + change interrupt to trigger. $ref: /schemas/types.yaml#/definitions/uint32 bias-pull-up: - description: | - Presence of this property indicates that the KPDPWR_N - pin should be configured for pull up. + description: + Presence of this property indicates that the KPDPWR_N pin should be + configured for pull up. $ref: /schemas/types.yaml#/definitions/flag linux,code: - description: | - The input key-code associated with the power key. - Use the linux event codes defined in - include/dt-bindings/input/linux-event-codes.h - When property is omitted KEY_POWER is assumed. + description: + The input key-code associated with the power key. Use the linux event + codes defined in include/dt-bindings/input/linux-event-codes.h. + When property is omitted KEY_POWER is assumed. required: - compatible From 9ff39b0468c3e04fee05d4e005d2fc03d28b1538 Mon Sep 17 00:00:00 2001 From: Imran Shaik Date: Tue, 9 Sep 2025 15:17:59 +0530 Subject: [PATCH 1159/2711] clk: qcom: dispcc-glymur: Constify 'struct qcom_cc_desc' 'struct qcom_cc_desc' is passed to qcom_cc_map() and qcom_cc_really_probe() only as pointer to const, so make the memory const for safety. Suggested-by: Krzysztof Kozlowski Signed-off-by: Imran Shaik Reviewed-by: Krzysztof Kozlowski Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250909-constify-dispcc-glymur-desc-fix-v1-1-6cb59730863f@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/dispcc-glymur.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/dispcc-glymur.c b/drivers/clk/qcom/dispcc-glymur.c index d755b41cf458..5203fa6383f6 100644 --- a/drivers/clk/qcom/dispcc-glymur.c +++ b/drivers/clk/qcom/dispcc-glymur.c @@ -1945,7 +1945,7 @@ static struct qcom_cc_driver_data disp_cc_glymur_driver_data = { .num_clk_cbcrs = ARRAY_SIZE(disp_cc_glymur_critical_cbcrs), }; -static struct qcom_cc_desc disp_cc_glymur_desc = { +static const struct qcom_cc_desc disp_cc_glymur_desc = { .config = &disp_cc_glymur_regmap_config, .clks = disp_cc_glymur_clocks, .num_clks = ARRAY_SIZE(disp_cc_glymur_clocks), From 80a2d7ea487d9b31d9b78d551aba3bd57642ce97 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 8 Sep 2025 13:10:18 +0100 Subject: [PATCH 1160/2711] perf arm-spe: Show instruction sample types by default Instruction sample types are enabled in the default itrace options in perf, but this never applied to SPE because the default nanoseconds period isn't supported. This meant that instructions ended up being opt-in by the user only when they requested an instruction based period. Change the default period type to instructions so that instruction samples are generated by default. This can overridden by specifying any --itrace option. This solves a common complaint from users that the unfiltered SPE samples appear to be missing, and only the samples that have memory flags set appear in the various memory groups. Signed-off-by: James Clark Tested-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ben Gainey Cc: George Wort Cc: Graham Woodward Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Leo Yan Cc: Mark Rutland Cc: Michael Williams Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 8942fa598a84..b33a0a170ef8 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -1871,10 +1871,14 @@ int arm_spe_process_auxtrace_info(union perf_event *event, if (dump_trace) return 0; - if (session->itrace_synth_opts && session->itrace_synth_opts->set) + if (session->itrace_synth_opts && session->itrace_synth_opts->set) { spe->synth_opts = *session->itrace_synth_opts; - else + } else { itrace_synth_opts__set_default(&spe->synth_opts, false); + /* Default nanoseconds period not supported */ + spe->synth_opts.period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS; + spe->synth_opts.period = 1; + } err = arm_spe_synth_events(spe, session); if (err) From bf1af4f6e62878e053d20cd71267aed8dfb3e715 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 8 Sep 2025 13:10:19 +0100 Subject: [PATCH 1161/2711] perf arm-spe: Downsample all sample types equally The various sample types that are generated are based on the same SPE sample, just placed into different sample type bins. The same sample can be in multiple bins if it has flags set that cause it to be. Currently we're only applying the --itrace interval downsampling to the instruction bin, which means that the sample would appear in one bin but not another if it was skipped due to downsampling. I don't thing anyone would want or expect this, so make this behave consistently by applying the downsampling before generating any sample. You might argue that the "instructions" interval type doesn't make sense to apply to "memory" sample types because it would be skipping every n memory samples, rather than every n instructions. ut the downsampling was already not an instruction interval even for the instruction samples. SPE has a hardware based sampling interval, and the instruction interval was just a convenient way to specify further downsampling. This is hinted at in the warning message shown for intervals greater than 1. This makes SPE diverge from trace technologies like Intel PT and Arm Coresight. In those cases instruction samples can be reduced but all branches are still emitted. This makes sense there, because branches form a complete execution history, and asking to skip branches every n instructions doesn't really make sense. But for SPE, as mentioned above, downsampling the instruction samples already wasn't consistent with trace technologies so we ended up with some middle ground that had no benefit. Now it's possible to reduce the volume of samples in all groups and samples won't be missing from one group but present in another. Reviewed-by: Leo Yan Signed-off-by: James Clark Tested-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ben Gainey Cc: George Wort Cc: Graham Woodward Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Leo Yan Cc: Mark Rutland Cc: Michael Williams Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index b33a0a170ef8..4c81518a033a 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -62,7 +62,6 @@ struct arm_spe { u8 sample_remote_access; u8 sample_memory; u8 sample_instructions; - u64 instructions_sample_period; u64 l1d_miss_id; u64 l1d_access_id; @@ -101,7 +100,7 @@ struct arm_spe_queue { u64 time; u64 timestamp; struct thread *thread; - u64 period_instructions; + u64 sample_count; u32 flags; struct branch_stack *last_branch; }; @@ -228,7 +227,6 @@ static struct arm_spe_queue *arm_spe__alloc_queue(struct arm_spe *spe, speq->pid = -1; speq->tid = -1; speq->cpu = -1; - speq->period_instructions = 0; /* params set */ params.get_trace = arm_spe_get_trace; @@ -352,7 +350,7 @@ static void arm_spe_prep_sample(struct arm_spe *spe, sample->cpumode = arm_spe_cpumode(spe, sample->ip); sample->pid = speq->pid; sample->tid = speq->tid; - sample->period = 1; + sample->period = spe->synth_opts.period; sample->cpu = speq->cpu; sample->simd_flags = arm_spe__synth_simd_flags(record); @@ -527,14 +525,6 @@ static int arm_spe__synth_instruction_sample(struct arm_spe_queue *speq, struct perf_sample sample; int ret; - /* - * Handles perf instruction sampling period. - */ - speq->period_instructions++; - if (speq->period_instructions < spe->instructions_sample_period) - return 0; - speq->period_instructions = 0; - perf_sample__init(&sample, /*all=*/true); arm_spe_prep_sample(spe, speq, event, &sample); @@ -543,7 +533,6 @@ static int arm_spe__synth_instruction_sample(struct arm_spe_queue *speq, sample.addr = record->to_ip; sample.phys_addr = record->phys_addr; sample.data_src = data_src; - sample.period = spe->instructions_sample_period; sample.weight = record->latency; sample.flags = speq->flags; sample.branch_stack = speq->last_branch; @@ -929,6 +918,14 @@ static int arm_spe_sample(struct arm_spe_queue *speq) u64 data_src; int err; + /* + * Discard all samples until period is reached + */ + speq->sample_count++; + if (speq->sample_count < spe->synth_opts.period) + return 0; + speq->sample_count = 0; + arm_spe__sample_flags(speq); data_src = arm_spe__synth_data_source(speq, record); @@ -1628,6 +1625,7 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session) attr.exclude_guest = evsel->core.attr.exclude_guest; attr.sample_id_all = evsel->core.attr.sample_id_all; attr.read_format = evsel->core.attr.read_format; + attr.sample_period = spe->synth_opts.period; /* create new id val to be a fixed offset from evsel id */ id = evsel->core.id[0] + 1000000000; @@ -1754,8 +1752,7 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session) spe->sample_instructions = true; attr.config = PERF_COUNT_HW_INSTRUCTIONS; - attr.sample_period = spe->synth_opts.period; - spe->instructions_sample_period = attr.sample_period; + err = perf_session__deliver_synth_attr_event(session, &attr, id); if (err) return err; From 9574a447478b5e6f5a31ef8b5f5cf5bbfbbc7157 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 8 Sep 2025 13:10:20 +0100 Subject: [PATCH 1162/2711] perf arm-spe: Display --itrace period warnings for all sample types Currently we only display the warning when the instructions group is requested. Instructions are on by default, and the period applies to all sample types anyway so always check the options and show the warning. Reword the messages to be more explicit about which flags the warnings apply to. Signed-off-by: James Clark Tested-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ben Gainey Cc: George Wort Cc: Graham Woodward Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Leo Yan Cc: Mark Rutland Cc: Michael Williams Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 4c81518a033a..228ed52e653d 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -1742,14 +1742,6 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session) } if (spe->synth_opts.instructions) { - if (spe->synth_opts.period_type != PERF_ITRACE_PERIOD_INSTRUCTIONS) { - pr_warning("Only instruction-based sampling period is currently supported by Arm SPE.\n"); - goto synth_instructions_out; - } - if (spe->synth_opts.period > 1) - pr_warning("Arm SPE has a hardware-based sample period.\n" - "Additional instruction events will be discarded by --itrace\n"); - spe->sample_instructions = true; attr.config = PERF_COUNT_HW_INSTRUCTIONS; @@ -1759,7 +1751,6 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session) spe->instructions_id = id; arm_spe_set_event_name(evlist, id, "instructions"); } -synth_instructions_out: return 0; } @@ -1877,6 +1868,15 @@ int arm_spe_process_auxtrace_info(union perf_event *event, spe->synth_opts.period = 1; } + if (spe->synth_opts.period_type != PERF_ITRACE_PERIOD_INSTRUCTIONS) { + ui__error("You must only use i (instructions) --itrace period with Arm SPE. e.g --itrace=i1i\n"); + err = -EINVAL; + goto err_free_queues; + } + if (spe->synth_opts.period > 1) + ui__warning("Arm SPE has a hardware-based sampling period.\n\n" + "--itrace periods > 1i downsample by an interval of n SPE samples rather than n instructions.\n"); + err = arm_spe_synth_events(spe, session); if (err) goto err_free_queues; From edf93f2a24de5791bfaa15d82794e38e97c9498c Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 8 Sep 2025 13:10:21 +0100 Subject: [PATCH 1163/2711] perf docs: Update SPE doc to include default instructions group The instructions group is now generated by default so update the doc to reflect this. Also explain the period/downsampling mechanism in more detail. Signed-off-by: James Clark Tested-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ben Gainey Cc: George Wort Cc: Graham Woodward Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Leo Yan Cc: Mark Rutland Cc: Michael Williams Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-arm-spe.txt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/perf/Documentation/perf-arm-spe.txt b/tools/perf/Documentation/perf-arm-spe.txt index 37afade4f1b2..cda8dd47fc4d 100644 --- a/tools/perf/Documentation/perf-arm-spe.txt +++ b/tools/perf/Documentation/perf-arm-spe.txt @@ -191,14 +191,20 @@ groups: 36 branch 0 remote-access 900 memory + 1800 instructions The arm_spe// and dummy:u events are implementation details and are expected to be empty. -To get a full list of unique samples that are not sorted into groups, set the itrace option to -generate 'instruction' samples. The period option is also taken into account, so set it to 1 -instruction unless you want to further downsample the already sampled SPE data: +The instructions group contains the full list of unique samples that are not +sorted into other groups. To generate only this group use --itrace=i1i. - perf report --itrace=i1i +1i (1 instruction interval) signifies no further downsampling. Rather than an +instruction interval, this generates a sample every n SPE samples. For example +to generate the default set of events for every 100 SPE samples: + + perf report --itrace==bxofmtMai100i + +Other period types, for example nanoseconds (ns) are not currently supported. Memory access details are also stored on the samples and this can be viewed with: From 48330efae9ccf44884af2b2f66fe695447240570 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 7 Sep 2025 23:10:48 -0700 Subject: [PATCH 1164/2711] perf annotate: Fix signature of annotate_browser__show() According to convention, the first argument should be 'struct annotate_browser' instead of 'struct ui_brwoser'. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250908061050.27517-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index b770a8d4623e..6fd4c3483c50 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -766,20 +766,21 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, return __annotate_browser__search_reverse(browser); } -static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) +static int annotate_browser__show(struct annotate_browser *browser, char *title, const char *help) { - struct map_symbol *ms = browser->priv; + struct ui_browser *b = &browser->b; + struct map_symbol *ms = b->priv; struct symbol *sym = ms->sym; char symbol_dso[SYM_TITLE_MAX_SIZE]; - if (ui_browser__show(browser, title, help) < 0) + if (ui_browser__show(b, title, help) < 0) return -1; sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), annotate_opts.percent_type); - ui_browser__gotorc_title(browser, 0, 0); - ui_browser__set_color(browser, HE_COLORSET_ROOT); - ui_browser__write_nstring(browser, symbol_dso, browser->width + 1); + ui_browser__gotorc_title(b, 0, 0); + ui_browser__set_color(b, HE_COLORSET_ROOT); + ui_browser__write_nstring(b, symbol_dso, b->width + 1); return 0; } @@ -858,7 +859,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int key; annotate__scnprintf_title(hists, title, sizeof(title)); - if (annotate_browser__show(&browser->b, title, help) < 0) + if (annotate_browser__show(browser, title, help) < 0) return -1; annotate_browser__calc_percent(browser, evsel); @@ -896,7 +897,7 @@ static int annotate_browser__run(struct annotate_browser *browser, if (delay_secs != 0) { symbol__annotate_decay_histogram(sym, evsel); annotate__scnprintf_title(hists, title, sizeof(title)); - annotate_browser__show(&browser->b, title, help); + annotate_browser__show(browser, title, help); } continue; case K_TAB: @@ -947,7 +948,7 @@ static int annotate_browser__run(struct annotate_browser *browser, continue; case 'r': script_browse(NULL, NULL); - annotate_browser__show(&browser->b, title, help); + annotate_browser__show(browser, title, help); continue; case 'k': annotate_opts.show_linenr = !annotate_opts.show_linenr; @@ -962,7 +963,7 @@ static int annotate_browser__run(struct annotate_browser *browser, if (annotate_browser__toggle_source(browser, evsel)) ui_helpline__puts(help); annotate__scnprintf_title(hists, title, sizeof(title)); - annotate_browser__show(&browser->b, title, help); + annotate_browser__show(browser, title, help); continue; case 'o': annotate_opts.use_offset = !annotate_opts.use_offset; @@ -1050,7 +1051,7 @@ show_sup_ins: case 'b': switch_percent_type(&annotate_opts, key == 'b'); annotate__scnprintf_title(hists, title, sizeof(title)); - annotate_browser__show(&browser->b, title, help); + annotate_browser__show(browser, title, help); continue; case 'B': if (br_cntr_text) @@ -1071,7 +1072,7 @@ show_sup_ins: browser->type_hash = hashmap__new(type_hash, type_equal, /*ctx=*/NULL); } - annotate_browser__show(&browser->b, title, help); + annotate_browser__show(browser, title, help); annotate_browser__debuginfo_warning(browser); continue; case K_LEFT: From 7eabedef445a15d39feef1ff094b659327591140 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 7 Sep 2025 23:10:49 -0700 Subject: [PATCH 1165/2711] perf annotate: Factor out annotate_browser__show_function_title() It'll be used in other places. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 6fd4c3483c50..39f042837d43 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -555,6 +555,20 @@ static int sym_title(struct symbol *sym, struct map *map, char *title, annotate_opts.code_with_type ? "[Type]" : ""); } +static void annotate_browser__show_function_title(struct annotate_browser *browser) +{ + struct ui_browser *b = &browser->b; + struct map_symbol *ms = b->priv; + struct symbol *sym = ms->sym; + char title[SYM_TITLE_MAX_SIZE]; + + sym_title(sym, ms->map, title, sizeof(title), annotate_opts.percent_type); + + ui_browser__gotorc_title(b, 0, 0); + ui_browser__set_color(b, HE_COLORSET_ROOT); + ui_browser__write_nstring(b, title, b->width + 1); +} + /* * This can be called from external jumps, i.e. jumps from one function * to another, like from the kernel's entry_SYSCALL_64 function to the @@ -768,19 +782,10 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, static int annotate_browser__show(struct annotate_browser *browser, char *title, const char *help) { - struct ui_browser *b = &browser->b; - struct map_symbol *ms = b->priv; - struct symbol *sym = ms->sym; - char symbol_dso[SYM_TITLE_MAX_SIZE]; - - if (ui_browser__show(b, title, help) < 0) + if (ui_browser__show(&browser->b, title, help) < 0) return -1; - sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), annotate_opts.percent_type); - - ui_browser__gotorc_title(b, 0, 0); - ui_browser__set_color(b, HE_COLORSET_ROOT); - ui_browser__write_nstring(b, symbol_dso, b->width + 1); + annotate_browser__show_function_title(browser); return 0; } From 1e5881b168b94871fecd4603633a5fe6a519cbbf Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 7 Sep 2025 23:10:50 -0700 Subject: [PATCH 1166/2711] perf annotate: Fix title line after return from call The second title line which shows symbol and DSO name is broken after moving to another function at 'callq' instruction. The ui_browser__show_title() is used for the first line which shows global sample count and event name so it doesn't change across the functions. What it needs after processing 'call' instruction is to update the second line onlly. Add a comment and call appropriate function. You can verify the change by pressing ENTER on a 'call' instruction and then ESC. Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 39f042837d43..8fe699f98542 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -585,7 +585,6 @@ static bool annotate_browser__callq(struct annotate_browser *browser, struct map_symbol *ms = browser->b.priv, target_ms; struct disasm_line *dl = disasm_line(browser->selection); struct annotation *notes; - char title[SYM_TITLE_MAX_SIZE]; if (!dl->ops.target.sym) { ui_helpline__puts("The called function was not found."); @@ -607,8 +606,13 @@ static bool annotate_browser__callq(struct annotate_browser *browser, target_ms.sym = dl->ops.target.sym; annotation__unlock(notes); __hist_entry__tui_annotate(browser->he, &target_ms, evsel, hbt); - sym_title(ms->sym, ms->map, title, sizeof(title), annotate_opts.percent_type); - ui_browser__show_title(&browser->b, title); + + /* + * The annotate_browser above changed the title with the target function + * and now it's back to the original function. Refresh the header line + * for the original function again. + */ + annotate_browser__show_function_title(browser); return true; } From dfea8f7183c711f2bf6af7aaef2a07e30b36a367 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 9 Sep 2025 10:06:35 +0800 Subject: [PATCH 1167/2711] mtd: nand: ecc: fix "writen"->"written" Trivial fix to spelling mistake in comment text. Signed-off-by: Xichao Zhao Signed-off-by: Miquel Raynal --- drivers/mtd/nand/ecc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c index 8f996e8d61b8..6ccdff3fc913 100644 --- a/drivers/mtd/nand/ecc.c +++ b/drivers/mtd/nand/ecc.c @@ -552,7 +552,7 @@ void nand_ecc_tweak_req(struct nand_ecc_req_tweak_ctx *ctx, memset(tweak->oobbuf.in, 0xFF, ctx->oob_buffer_size); } - /* Copy the data that must be writen in the bounce buffers, if needed */ + /* Copy the data that must be written in the bounce buffers, if needed */ if (orig->type == NAND_PAGE_WRITE) { if (ctx->bounce_data) memcpy((void *)tweak->databuf.out + orig->dataoffs, From b2d2c2b8af4321476d58f313c7893b49c30141a4 Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Thu, 4 Sep 2025 11:14:41 +0200 Subject: [PATCH 1168/2711] mtd: rawnand: atmel: Fix pulse read timing for certain flash chips Prevent PMECC errors when reading from AMD/Spansion S34ML02G1 flash on SAM9X60 SoC, after switching to ONFI timing mode 3. From reading the S34ML02G1 and the SAM9X60 datasheets again, it seems like we have to wait tREA after rising RE# before sampling the data. Thus pulse must be at least tREA. The previous approach to set this timing worked on sam9g20 and sama5d2 with the same flash (S34ML02G1), probably because those have a slower mck clock rate and thus the resolution of the timings setup is not as tight as with sam9x60. The approach to fix the issue was carried over from u-boot, which itself got it from at91bootstrap. It has been successfully tested in at91bootstrap, U-Boot and Linux on sam9x60 and sama5d2, for several months here. Link: https://github.com/linux4sam/at91bootstrap/issues/174 Link: https://github.com/linux4sam/at91bootstrap/commit/e2dfd8141d00613a37acee66ef5724f70f34a538 Link: https://lore.kernel.org/u-boot/20240415075755.780653-1-ada@thorsis.com/ Link: https://source.denx.de/u-boot/u-boot/-/commit/344e2f2cd4a407f847b301804f37d036e8a0a10c Cc: Li Bin Signed-off-by: Alexander Dahl Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/atmel/nand-controller.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 84ab4a83cbd6..87481b60f315 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1240,7 +1240,7 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, const struct nand_interface_config *conf, struct atmel_smc_cs_conf *smcconf) { - u32 ncycles, totalcycles, timeps, mckperiodps; + u32 ncycles, totalcycles, timeps, mckperiodps, pulse; struct atmel_nand_controller *nc; int ret; @@ -1366,11 +1366,16 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, ATMEL_SMC_MODE_TDFMODE_OPTIMIZED; /* - * Read pulse timing directly matches tRP: + * Read pulse timing would directly match tRP, + * but some NAND flash chips (S34ML01G2 and W29N02KVxxAF) + * do not work properly in timing mode 3. + * The workaround is to extend the SMC NRD pulse to meet tREA + * timing. * - * NRD_PULSE = tRP + * NRD_PULSE = max(tRP, tREA) */ - ncycles = DIV_ROUND_UP(conf->timings.sdr.tRP_min, mckperiodps); + pulse = max(conf->timings.sdr.tRP_min, conf->timings.sdr.tREA_max); + ncycles = DIV_ROUND_UP(pulse, mckperiodps); totalcycles += ncycles; ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NRD_SHIFT, ncycles); From 7a1e3a452a574ef337c4c2cd9202332a1ae9cd94 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Thu, 4 Sep 2025 21:06:33 +0800 Subject: [PATCH 1169/2711] mtd: rawnand: loongson1: Rename the prefix from ls1x to loongson I am going to introduce the NAND controllers of the Loongson-2K series CPUs, which are similar to Loongson-1. As preparation, rename all prefixes from Loongson1-specific to Loongson-generic. No functional change intended. Signed-off-by: Binbin Zhou Signed-off-by: Miquel Raynal --- MAINTAINERS | 2 +- drivers/mtd/nand/raw/Kconfig | 6 +- drivers/mtd/nand/raw/Makefile | 2 +- ...ontroller.c => loongson-nand-controller.c} | 325 +++++++++--------- 4 files changed, 171 insertions(+), 164 deletions(-) rename drivers/mtd/nand/raw/{loongson1-nand-controller.c => loongson-nand-controller.c} (61%) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..470713cf4f8a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16992,7 +16992,7 @@ F: Documentation/devicetree/bindings/*/loongson,ls1*.yaml F: arch/mips/include/asm/mach-loongson32/ F: arch/mips/loongson32/ F: drivers/*/*loongson1* -F: drivers/mtd/nand/raw/loongson1-nand-controller.c +F: drivers/mtd/nand/raw/loongson-nand-controller.c F: drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c F: sound/soc/loongson/loongson1_ac97.c diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index f053806333c3..489f5c05cda9 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -436,12 +436,12 @@ config MTD_NAND_NUVOTON_MA35 Enables support for the NAND controller found on the Nuvoton MA35 series SoCs. -config MTD_NAND_LOONGSON1 - tristate "Loongson1 NAND controller" +config MTD_NAND_LOONGSON + tristate "Loongson NAND controller" depends on LOONGSON1_APB_DMA || COMPILE_TEST select REGMAP_MMIO help - Enables support for NAND controller on Loongson1 SoCs. + Enables support for NAND controller on Loongson family chips. comment "Misc" diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 363cd18eaf16..619760138d32 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o obj-$(CONFIG_MTD_NAND_PL35X) += pl35x-nand-controller.o obj-$(CONFIG_MTD_NAND_RENESAS) += renesas-nand-controller.o obj-$(CONFIG_MTD_NAND_NUVOTON_MA35) += nuvoton-ma35d1-nand-controller.o -obj-$(CONFIG_MTD_NAND_LOONGSON1) += loongson1-nand-controller.o +obj-$(CONFIG_MTD_NAND_LOONGSON) += loongson-nand-controller.o nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o nand-objs += nand_onfi.o diff --git a/drivers/mtd/nand/raw/loongson1-nand-controller.c b/drivers/mtd/nand/raw/loongson-nand-controller.c similarity index 61% rename from drivers/mtd/nand/raw/loongson1-nand-controller.c rename to drivers/mtd/nand/raw/loongson-nand-controller.c index ef8e4f9ce287..b5a7be0fcacc 100644 --- a/drivers/mtd/nand/raw/loongson1-nand-controller.c +++ b/drivers/mtd/nand/raw/loongson-nand-controller.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * NAND Controller Driver for Loongson-1 SoC + * NAND Controller Driver for Loongson family chips * * Copyright (C) 2015-2025 Keguang Zhang */ @@ -17,42 +17,45 @@ #include #include -/* Loongson-1 NAND Controller Registers */ -#define LS1X_NAND_CMD 0x0 -#define LS1X_NAND_ADDR1 0x4 -#define LS1X_NAND_ADDR2 0x8 -#define LS1X_NAND_TIMING 0xc -#define LS1X_NAND_IDL 0x10 -#define LS1X_NAND_IDH_STATUS 0x14 -#define LS1X_NAND_PARAM 0x18 -#define LS1X_NAND_OP_NUM 0x1c +/* Loongson NAND Controller Registers */ +#define LOONGSON_NAND_CMD 0x0 +#define LOONGSON_NAND_ADDR1 0x4 +#define LOONGSON_NAND_ADDR2 0x8 +#define LOONGSON_NAND_TIMING 0xc +#define LOONGSON_NAND_IDL 0x10 +#define LOONGSON_NAND_IDH_STATUS 0x14 +#define LOONGSON_NAND_PARAM 0x18 +#define LOONGSON_NAND_OP_NUM 0x1c -/* NAND Command Register Bits */ -#define LS1X_NAND_CMD_OP_DONE BIT(10) -#define LS1X_NAND_CMD_OP_SPARE BIT(9) -#define LS1X_NAND_CMD_OP_MAIN BIT(8) -#define LS1X_NAND_CMD_STATUS BIT(7) -#define LS1X_NAND_CMD_RESET BIT(6) -#define LS1X_NAND_CMD_READID BIT(5) -#define LS1X_NAND_CMD_BLOCKS_ERASE BIT(4) -#define LS1X_NAND_CMD_ERASE BIT(3) -#define LS1X_NAND_CMD_WRITE BIT(2) -#define LS1X_NAND_CMD_READ BIT(1) -#define LS1X_NAND_CMD_VALID BIT(0) +/* Bitfields of nand command register */ +#define LOONGSON_NAND_CMD_OP_DONE BIT(10) +#define LOONGSON_NAND_CMD_OP_SPARE BIT(9) +#define LOONGSON_NAND_CMD_OP_MAIN BIT(8) +#define LOONGSON_NAND_CMD_STATUS BIT(7) +#define LOONGSON_NAND_CMD_RESET BIT(6) +#define LOONGSON_NAND_CMD_READID BIT(5) +#define LOONGSON_NAND_CMD_BLOCKS_ERASE BIT(4) +#define LOONGSON_NAND_CMD_ERASE BIT(3) +#define LOONGSON_NAND_CMD_WRITE BIT(2) +#define LOONGSON_NAND_CMD_READ BIT(1) +#define LOONGSON_NAND_CMD_VALID BIT(0) -#define LS1X_NAND_WAIT_CYCLE_MASK GENMASK(7, 0) -#define LS1X_NAND_HOLD_CYCLE_MASK GENMASK(15, 8) -#define LS1X_NAND_CELL_SIZE_MASK GENMASK(11, 8) +/* Bitfields of nand timing register */ +#define LOONGSON_NAND_WAIT_CYCLE_MASK GENMASK(7, 0) +#define LOONGSON_NAND_HOLD_CYCLE_MASK GENMASK(15, 8) -#define LS1X_NAND_COL_ADDR_CYC 2U -#define LS1X_NAND_MAX_ADDR_CYC 5U +/* Bitfields of nand parameter register */ +#define LOONGSON_NAND_CELL_SIZE_MASK GENMASK(11, 8) -#define BITS_PER_WORD (4 * BITS_PER_BYTE) +#define LOONGSON_NAND_COL_ADDR_CYC 2U +#define LOONGSON_NAND_MAX_ADDR_CYC 5U -struct ls1x_nand_host; +#define BITS_PER_WORD (4 * BITS_PER_BYTE) -struct ls1x_nand_op { - char addrs[LS1X_NAND_MAX_ADDR_CYC]; +struct loongson_nand_host; + +struct loongson_nand_op { + char addrs[LOONGSON_NAND_MAX_ADDR_CYC]; unsigned int naddrs; unsigned int addrs_offset; unsigned int aligned_offset; @@ -69,19 +72,19 @@ struct ls1x_nand_op { char *buf; }; -struct ls1x_nand_data { +struct loongson_nand_data { unsigned int status_field; unsigned int op_scope_field; unsigned int hold_cycle; unsigned int wait_cycle; - void (*set_addr)(struct ls1x_nand_host *host, struct ls1x_nand_op *op); + void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op); }; -struct ls1x_nand_host { +struct loongson_nand_host { struct device *dev; struct nand_chip chip; struct nand_controller controller; - const struct ls1x_nand_data *data; + const struct loongson_nand_data *data; void __iomem *reg_base; struct regmap *regmap; /* DMA Engine stuff */ @@ -91,40 +94,41 @@ struct ls1x_nand_host { struct completion dma_complete; }; -static const struct regmap_config ls1x_nand_regmap_config = { +static const struct regmap_config loongson_nand_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, }; -static int ls1x_nand_op_cmd_mapping(struct nand_chip *chip, struct ls1x_nand_op *op, u8 opcode) +static int loongson_nand_op_cmd_mapping(struct nand_chip *chip, struct loongson_nand_op *op, + u8 opcode) { - struct ls1x_nand_host *host = nand_get_controller_data(chip); + struct loongson_nand_host *host = nand_get_controller_data(chip); op->row_start = chip->page_shift + 1; /* The controller abstracts the following NAND operations. */ switch (opcode) { case NAND_CMD_STATUS: - op->cmd_reg = LS1X_NAND_CMD_STATUS; + op->cmd_reg = LOONGSON_NAND_CMD_STATUS; break; case NAND_CMD_RESET: - op->cmd_reg = LS1X_NAND_CMD_RESET; + op->cmd_reg = LOONGSON_NAND_CMD_RESET; break; case NAND_CMD_READID: op->is_readid = true; - op->cmd_reg = LS1X_NAND_CMD_READID; + op->cmd_reg = LOONGSON_NAND_CMD_READID; break; case NAND_CMD_ERASE1: op->is_erase = true; - op->addrs_offset = LS1X_NAND_COL_ADDR_CYC; + op->addrs_offset = LOONGSON_NAND_COL_ADDR_CYC; break; case NAND_CMD_ERASE2: if (!op->is_erase) return -EOPNOTSUPP; /* During erasing, row_start differs from the default value. */ op->row_start = chip->page_shift; - op->cmd_reg = LS1X_NAND_CMD_ERASE; + op->cmd_reg = LOONGSON_NAND_CMD_ERASE; break; case NAND_CMD_SEQIN: op->is_write = true; @@ -132,7 +136,7 @@ static int ls1x_nand_op_cmd_mapping(struct nand_chip *chip, struct ls1x_nand_op case NAND_CMD_PAGEPROG: if (!op->is_write) return -EOPNOTSUPP; - op->cmd_reg = LS1X_NAND_CMD_WRITE; + op->cmd_reg = LOONGSON_NAND_CMD_WRITE; break; case NAND_CMD_READ0: op->is_read = true; @@ -140,7 +144,7 @@ static int ls1x_nand_op_cmd_mapping(struct nand_chip *chip, struct ls1x_nand_op case NAND_CMD_READSTART: if (!op->is_read) return -EOPNOTSUPP; - op->cmd_reg = LS1X_NAND_CMD_READ; + op->cmd_reg = LOONGSON_NAND_CMD_READ; break; case NAND_CMD_RNDOUT: op->is_change_column = true; @@ -148,7 +152,7 @@ static int ls1x_nand_op_cmd_mapping(struct nand_chip *chip, struct ls1x_nand_op case NAND_CMD_RNDOUTSTART: if (!op->is_change_column) return -EOPNOTSUPP; - op->cmd_reg = LS1X_NAND_CMD_READ; + op->cmd_reg = LOONGSON_NAND_CMD_READ; break; default: dev_dbg(host->dev, "unsupported opcode: %u\n", opcode); @@ -158,8 +162,8 @@ static int ls1x_nand_op_cmd_mapping(struct nand_chip *chip, struct ls1x_nand_op return 0; } -static int ls1x_nand_parse_instructions(struct nand_chip *chip, - const struct nand_subop *subop, struct ls1x_nand_op *op) +static int loongson_nand_parse_instructions(struct nand_chip *chip, const struct nand_subop *subop, + struct loongson_nand_op *op) { unsigned int op_id; int ret; @@ -171,14 +175,14 @@ static int ls1x_nand_parse_instructions(struct nand_chip *chip, switch (instr->type) { case NAND_OP_CMD_INSTR: - ret = ls1x_nand_op_cmd_mapping(chip, op, instr->ctx.cmd.opcode); + ret = loongson_nand_op_cmd_mapping(chip, op, instr->ctx.cmd.opcode); if (ret < 0) return ret; break; case NAND_OP_ADDR_INSTR: naddrs = nand_subop_get_num_addr_cyc(subop, op_id); - if (naddrs > LS1X_NAND_MAX_ADDR_CYC) + if (naddrs > LOONGSON_NAND_MAX_ADDR_CYC) return -EOPNOTSUPP; op->naddrs = naddrs; offset = nand_subop_get_addr_start_off(subop, op_id); @@ -206,57 +210,57 @@ static int ls1x_nand_parse_instructions(struct nand_chip *chip, return 0; } -static void ls1b_nand_set_addr(struct ls1x_nand_host *host, struct ls1x_nand_op *op) +static void ls1b_nand_set_addr(struct loongson_nand_host *host, struct loongson_nand_op *op) { struct nand_chip *chip = &host->chip; int i; - for (i = 0; i < LS1X_NAND_MAX_ADDR_CYC; i++) { + for (i = 0; i < LOONGSON_NAND_MAX_ADDR_CYC; i++) { int shift, mask, val; - if (i < LS1X_NAND_COL_ADDR_CYC) { + if (i < LOONGSON_NAND_COL_ADDR_CYC) { shift = i * BITS_PER_BYTE; mask = (u32)0xff << shift; mask &= GENMASK(chip->page_shift, 0); val = (u32)op->addrs[i] << shift; - regmap_update_bits(host->regmap, LS1X_NAND_ADDR1, mask, val); + regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR1, mask, val); } else if (!op->is_change_column) { - shift = op->row_start + (i - LS1X_NAND_COL_ADDR_CYC) * BITS_PER_BYTE; + shift = op->row_start + (i - LOONGSON_NAND_COL_ADDR_CYC) * BITS_PER_BYTE; mask = (u32)0xff << shift; val = (u32)op->addrs[i] << shift; - regmap_update_bits(host->regmap, LS1X_NAND_ADDR1, mask, val); + regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR1, mask, val); if (i == 4) { mask = (u32)0xff >> (BITS_PER_WORD - shift); val = (u32)op->addrs[i] >> (BITS_PER_WORD - shift); - regmap_update_bits(host->regmap, LS1X_NAND_ADDR2, mask, val); + regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR2, mask, val); } } } } -static void ls1c_nand_set_addr(struct ls1x_nand_host *host, struct ls1x_nand_op *op) +static void ls1c_nand_set_addr(struct loongson_nand_host *host, struct loongson_nand_op *op) { int i; - for (i = 0; i < LS1X_NAND_MAX_ADDR_CYC; i++) { + for (i = 0; i < LOONGSON_NAND_MAX_ADDR_CYC; i++) { int shift, mask, val; - if (i < LS1X_NAND_COL_ADDR_CYC) { + if (i < LOONGSON_NAND_COL_ADDR_CYC) { shift = i * BITS_PER_BYTE; mask = (u32)0xff << shift; val = (u32)op->addrs[i] << shift; - regmap_update_bits(host->regmap, LS1X_NAND_ADDR1, mask, val); + regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR1, mask, val); } else if (!op->is_change_column) { - shift = (i - LS1X_NAND_COL_ADDR_CYC) * BITS_PER_BYTE; + shift = (i - LOONGSON_NAND_COL_ADDR_CYC) * BITS_PER_BYTE; mask = (u32)0xff << shift; val = (u32)op->addrs[i] << shift; - regmap_update_bits(host->regmap, LS1X_NAND_ADDR2, mask, val); + regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR2, mask, val); } } } -static void ls1x_nand_trigger_op(struct ls1x_nand_host *host, struct ls1x_nand_op *op) +static void loongson_nand_trigger_op(struct loongson_nand_host *host, struct loongson_nand_op *op) { struct nand_chip *chip = &host->chip; struct mtd_info *mtd = nand_to_mtd(chip); @@ -280,7 +284,7 @@ static void ls1x_nand_trigger_op(struct ls1x_nand_host *host, struct ls1x_nand_o else op->len = op->orig_len; - writel(op->len, host->reg_base + LS1X_NAND_OP_NUM); + writel(op->len, host->reg_base + LOONGSON_NAND_OP_NUM); /* set operation area and scope */ col = op->addrs[1] << BITS_PER_BYTE | op->addrs[0]; @@ -288,33 +292,35 @@ static void ls1x_nand_trigger_op(struct ls1x_nand_host *host, struct ls1x_nand_o unsigned int op_scope = 0; if (col < mtd->writesize) { - op->cmd_reg |= LS1X_NAND_CMD_OP_MAIN; + op->cmd_reg |= LOONGSON_NAND_CMD_OP_MAIN; op_scope = mtd->writesize; } - op->cmd_reg |= LS1X_NAND_CMD_OP_SPARE; + op->cmd_reg |= LOONGSON_NAND_CMD_OP_SPARE; op_scope += mtd->oobsize; op_scope <<= __ffs(host->data->op_scope_field); - regmap_update_bits(host->regmap, LS1X_NAND_PARAM, + regmap_update_bits(host->regmap, LOONGSON_NAND_PARAM, host->data->op_scope_field, op_scope); } /* set command */ - writel(op->cmd_reg, host->reg_base + LS1X_NAND_CMD); + writel(op->cmd_reg, host->reg_base + LOONGSON_NAND_CMD); /* trigger operation */ - regmap_write_bits(host->regmap, LS1X_NAND_CMD, LS1X_NAND_CMD_VALID, LS1X_NAND_CMD_VALID); + regmap_write_bits(host->regmap, LOONGSON_NAND_CMD, LOONGSON_NAND_CMD_VALID, + LOONGSON_NAND_CMD_VALID); } -static int ls1x_nand_wait_for_op_done(struct ls1x_nand_host *host, struct ls1x_nand_op *op) +static int loongson_nand_wait_for_op_done(struct loongson_nand_host *host, + struct loongson_nand_op *op) { unsigned int val; int ret = 0; if (op->rdy_timeout_ms) { - ret = regmap_read_poll_timeout(host->regmap, LS1X_NAND_CMD, - val, val & LS1X_NAND_CMD_OP_DONE, + ret = regmap_read_poll_timeout(host->regmap, LOONGSON_NAND_CMD, + val, val & LOONGSON_NAND_CMD_OP_DONE, 0, op->rdy_timeout_ms * MSEC_PER_SEC); if (ret) dev_err(host->dev, "operation failed\n"); @@ -323,9 +329,9 @@ static int ls1x_nand_wait_for_op_done(struct ls1x_nand_host *host, struct ls1x_n return ret; } -static void ls1x_nand_dma_callback(void *data) +static void loongson_nand_dma_callback(void *data) { - struct ls1x_nand_host *host = (struct ls1x_nand_host *)data; + struct loongson_nand_host *host = (struct loongson_nand_host *)data; struct dma_chan *chan = host->dma_chan; struct device *dev = chan->device->dev; enum dma_status status; @@ -339,7 +345,7 @@ static void ls1x_nand_dma_callback(void *data) } } -static int ls1x_nand_dma_transfer(struct ls1x_nand_host *host, struct ls1x_nand_op *op) +static int loongson_nand_dma_transfer(struct loongson_nand_host *host, struct loongson_nand_op *op) { struct nand_chip *chip = &host->chip; struct dma_chan *chan = host->dma_chan; @@ -374,7 +380,7 @@ static int ls1x_nand_dma_transfer(struct ls1x_nand_host *host, struct ls1x_nand_ ret = -ENOMEM; goto err; } - desc->callback = ls1x_nand_dma_callback; + desc->callback = loongson_nand_dma_callback; desc->callback_param = host; host->dma_cookie = dmaengine_submit(desc); @@ -405,51 +411,51 @@ err: return ret; } -static int ls1x_nand_data_type_exec(struct nand_chip *chip, const struct nand_subop *subop) +static int loongson_nand_data_type_exec(struct nand_chip *chip, const struct nand_subop *subop) { - struct ls1x_nand_host *host = nand_get_controller_data(chip); - struct ls1x_nand_op op = {}; + struct loongson_nand_host *host = nand_get_controller_data(chip); + struct loongson_nand_op op = {}; int ret; - ret = ls1x_nand_parse_instructions(chip, subop, &op); + ret = loongson_nand_parse_instructions(chip, subop, &op); if (ret) return ret; - ls1x_nand_trigger_op(host, &op); + loongson_nand_trigger_op(host, &op); - ret = ls1x_nand_dma_transfer(host, &op); + ret = loongson_nand_dma_transfer(host, &op); if (ret) return ret; - return ls1x_nand_wait_for_op_done(host, &op); + return loongson_nand_wait_for_op_done(host, &op); } -static int ls1x_nand_misc_type_exec(struct nand_chip *chip, - const struct nand_subop *subop, struct ls1x_nand_op *op) +static int loongson_nand_misc_type_exec(struct nand_chip *chip, const struct nand_subop *subop, + struct loongson_nand_op *op) { - struct ls1x_nand_host *host = nand_get_controller_data(chip); + struct loongson_nand_host *host = nand_get_controller_data(chip); int ret; - ret = ls1x_nand_parse_instructions(chip, subop, op); + ret = loongson_nand_parse_instructions(chip, subop, op); if (ret) return ret; - ls1x_nand_trigger_op(host, op); + loongson_nand_trigger_op(host, op); - return ls1x_nand_wait_for_op_done(host, op); + return loongson_nand_wait_for_op_done(host, op); } -static int ls1x_nand_zerolen_type_exec(struct nand_chip *chip, const struct nand_subop *subop) +static int loongson_nand_zerolen_type_exec(struct nand_chip *chip, const struct nand_subop *subop) { - struct ls1x_nand_op op = {}; + struct loongson_nand_op op = {}; - return ls1x_nand_misc_type_exec(chip, subop, &op); + return loongson_nand_misc_type_exec(chip, subop, &op); } -static int ls1x_nand_read_id_type_exec(struct nand_chip *chip, const struct nand_subop *subop) +static int loongson_nand_read_id_type_exec(struct nand_chip *chip, const struct nand_subop *subop) { - struct ls1x_nand_host *host = nand_get_controller_data(chip); - struct ls1x_nand_op op = {}; + struct loongson_nand_host *host = nand_get_controller_data(chip); + struct loongson_nand_op op = {}; int i, ret; union { char ids[5]; @@ -459,12 +465,12 @@ static int ls1x_nand_read_id_type_exec(struct nand_chip *chip, const struct nand }; } nand_id; - ret = ls1x_nand_misc_type_exec(chip, subop, &op); + ret = loongson_nand_misc_type_exec(chip, subop, &op); if (ret) return ret; - nand_id.idl = readl(host->reg_base + LS1X_NAND_IDL); - nand_id.idh = readb(host->reg_base + LS1X_NAND_IDH_STATUS); + nand_id.idl = readl(host->reg_base + LOONGSON_NAND_IDL); + nand_id.idh = readb(host->reg_base + LOONGSON_NAND_IDH_STATUS); for (i = 0; i < min(sizeof(nand_id.ids), op.orig_len); i++) op.buf[i] = nand_id.ids[sizeof(nand_id.ids) - 1 - i]; @@ -472,60 +478,61 @@ static int ls1x_nand_read_id_type_exec(struct nand_chip *chip, const struct nand return ret; } -static int ls1x_nand_read_status_type_exec(struct nand_chip *chip, const struct nand_subop *subop) +static int loongson_nand_read_status_type_exec(struct nand_chip *chip, + const struct nand_subop *subop) { - struct ls1x_nand_host *host = nand_get_controller_data(chip); - struct ls1x_nand_op op = {}; + struct loongson_nand_host *host = nand_get_controller_data(chip); + struct loongson_nand_op op = {}; int val, ret; - ret = ls1x_nand_misc_type_exec(chip, subop, &op); + ret = loongson_nand_misc_type_exec(chip, subop, &op); if (ret) return ret; - val = readl(host->reg_base + LS1X_NAND_IDH_STATUS); + val = readl(host->reg_base + LOONGSON_NAND_IDH_STATUS); val &= ~host->data->status_field; op.buf[0] = val << ffs(host->data->status_field); return ret; } -static const struct nand_op_parser ls1x_nand_op_parser = NAND_OP_PARSER( +static const struct nand_op_parser loongson_nand_op_parser = NAND_OP_PARSER( NAND_OP_PARSER_PATTERN( - ls1x_nand_read_id_type_exec, + loongson_nand_read_id_type_exec, NAND_OP_PARSER_PAT_CMD_ELEM(false), - NAND_OP_PARSER_PAT_ADDR_ELEM(false, LS1X_NAND_MAX_ADDR_CYC), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, LOONGSON_NAND_MAX_ADDR_CYC), NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 8)), NAND_OP_PARSER_PATTERN( - ls1x_nand_read_status_type_exec, + loongson_nand_read_status_type_exec, NAND_OP_PARSER_PAT_CMD_ELEM(false), NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 1)), NAND_OP_PARSER_PATTERN( - ls1x_nand_zerolen_type_exec, + loongson_nand_zerolen_type_exec, NAND_OP_PARSER_PAT_CMD_ELEM(false), NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)), NAND_OP_PARSER_PATTERN( - ls1x_nand_zerolen_type_exec, + loongson_nand_zerolen_type_exec, NAND_OP_PARSER_PAT_CMD_ELEM(false), - NAND_OP_PARSER_PAT_ADDR_ELEM(false, LS1X_NAND_MAX_ADDR_CYC), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, LOONGSON_NAND_MAX_ADDR_CYC), NAND_OP_PARSER_PAT_CMD_ELEM(false), NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)), NAND_OP_PARSER_PATTERN( - ls1x_nand_data_type_exec, + loongson_nand_data_type_exec, NAND_OP_PARSER_PAT_CMD_ELEM(false), - NAND_OP_PARSER_PAT_ADDR_ELEM(false, LS1X_NAND_MAX_ADDR_CYC), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, LOONGSON_NAND_MAX_ADDR_CYC), NAND_OP_PARSER_PAT_CMD_ELEM(false), NAND_OP_PARSER_PAT_WAITRDY_ELEM(true), NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 0)), NAND_OP_PARSER_PATTERN( - ls1x_nand_data_type_exec, + loongson_nand_data_type_exec, NAND_OP_PARSER_PAT_CMD_ELEM(false), - NAND_OP_PARSER_PAT_ADDR_ELEM(false, LS1X_NAND_MAX_ADDR_CYC), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, LOONGSON_NAND_MAX_ADDR_CYC), NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 0), NAND_OP_PARSER_PAT_CMD_ELEM(false), NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)), ); -static int ls1x_nand_is_valid_cmd(u8 opcode) +static int loongson_nand_is_valid_cmd(u8 opcode) { if (opcode == NAND_CMD_STATUS || opcode == NAND_CMD_RESET || opcode == NAND_CMD_READID) return 0; @@ -533,7 +540,7 @@ static int ls1x_nand_is_valid_cmd(u8 opcode) return -EOPNOTSUPP; } -static int ls1x_nand_is_valid_cmd_seq(u8 opcode1, u8 opcode2) +static int loongson_nand_is_valid_cmd_seq(u8 opcode1, u8 opcode2) { if (opcode1 == NAND_CMD_RNDOUT && opcode2 == NAND_CMD_RNDOUTSTART) return 0; @@ -550,7 +557,7 @@ static int ls1x_nand_is_valid_cmd_seq(u8 opcode1, u8 opcode2) return -EOPNOTSUPP; } -static int ls1x_nand_check_op(struct nand_chip *chip, const struct nand_operation *op) +static int loongson_nand_check_op(struct nand_chip *chip, const struct nand_operation *op) { const struct nand_op_instr *instr1 = NULL, *instr2 = NULL; int op_id; @@ -572,23 +579,23 @@ static int ls1x_nand_check_op(struct nand_chip *chip, const struct nand_operatio return -EOPNOTSUPP; if (!instr2) - return ls1x_nand_is_valid_cmd(instr1->ctx.cmd.opcode); + return loongson_nand_is_valid_cmd(instr1->ctx.cmd.opcode); - return ls1x_nand_is_valid_cmd_seq(instr1->ctx.cmd.opcode, instr2->ctx.cmd.opcode); + return loongson_nand_is_valid_cmd_seq(instr1->ctx.cmd.opcode, instr2->ctx.cmd.opcode); } -static int ls1x_nand_exec_op(struct nand_chip *chip, - const struct nand_operation *op, bool check_only) +static int loongson_nand_exec_op(struct nand_chip *chip, const struct nand_operation *op, + bool check_only) { if (check_only) - return ls1x_nand_check_op(chip, op); + return loongson_nand_check_op(chip, op); - return nand_op_parser_exec_op(chip, &ls1x_nand_op_parser, op, check_only); + return nand_op_parser_exec_op(chip, &loongson_nand_op_parser, op, check_only); } -static int ls1x_nand_attach_chip(struct nand_chip *chip) +static int loongson_nand_attach_chip(struct nand_chip *chip) { - struct ls1x_nand_host *host = nand_get_controller_data(chip); + struct loongson_nand_host *host = nand_get_controller_data(chip); u64 chipsize = nanddev_target_size(&chip->base); int cell_size = 0; @@ -632,14 +639,14 @@ static int ls1x_nand_attach_chip(struct nand_chip *chip) } /* set cell size */ - regmap_update_bits(host->regmap, LS1X_NAND_PARAM, LS1X_NAND_CELL_SIZE_MASK, - FIELD_PREP(LS1X_NAND_CELL_SIZE_MASK, cell_size)); + regmap_update_bits(host->regmap, LOONGSON_NAND_PARAM, LOONGSON_NAND_CELL_SIZE_MASK, + FIELD_PREP(LOONGSON_NAND_CELL_SIZE_MASK, cell_size)); - regmap_update_bits(host->regmap, LS1X_NAND_TIMING, LS1X_NAND_HOLD_CYCLE_MASK, - FIELD_PREP(LS1X_NAND_HOLD_CYCLE_MASK, host->data->hold_cycle)); + regmap_update_bits(host->regmap, LOONGSON_NAND_TIMING, LOONGSON_NAND_HOLD_CYCLE_MASK, + FIELD_PREP(LOONGSON_NAND_HOLD_CYCLE_MASK, host->data->hold_cycle)); - regmap_update_bits(host->regmap, LS1X_NAND_TIMING, LS1X_NAND_WAIT_CYCLE_MASK, - FIELD_PREP(LS1X_NAND_WAIT_CYCLE_MASK, host->data->wait_cycle)); + regmap_update_bits(host->regmap, LOONGSON_NAND_TIMING, LOONGSON_NAND_WAIT_CYCLE_MASK, + FIELD_PREP(LOONGSON_NAND_WAIT_CYCLE_MASK, host->data->wait_cycle)); chip->ecc.read_page_raw = nand_monolithic_read_page_raw; chip->ecc.write_page_raw = nand_monolithic_write_page_raw; @@ -647,25 +654,25 @@ static int ls1x_nand_attach_chip(struct nand_chip *chip) return 0; } -static const struct nand_controller_ops ls1x_nand_controller_ops = { - .exec_op = ls1x_nand_exec_op, - .attach_chip = ls1x_nand_attach_chip, +static const struct nand_controller_ops loongson_nand_controller_ops = { + .exec_op = loongson_nand_exec_op, + .attach_chip = loongson_nand_attach_chip, }; -static void ls1x_nand_controller_cleanup(struct ls1x_nand_host *host) +static void loongson_nand_controller_cleanup(struct loongson_nand_host *host) { if (host->dma_chan) dma_release_channel(host->dma_chan); } -static int ls1x_nand_controller_init(struct ls1x_nand_host *host) +static int loongson_nand_controller_init(struct loongson_nand_host *host) { struct device *dev = host->dev; struct dma_chan *chan; struct dma_slave_config cfg = {}; int ret; - host->regmap = devm_regmap_init_mmio(dev, host->reg_base, &ls1x_nand_regmap_config); + host->regmap = devm_regmap_init_mmio(dev, host->reg_base, &loongson_nand_regmap_config); if (IS_ERR(host->regmap)) return dev_err_probe(dev, PTR_ERR(host->regmap), "failed to init regmap\n"); @@ -687,7 +694,7 @@ static int ls1x_nand_controller_init(struct ls1x_nand_host *host) return 0; } -static int ls1x_nand_chip_init(struct ls1x_nand_host *host) +static int loongson_nand_chip_init(struct loongson_nand_host *host) { struct device *dev = host->dev; int nchips = of_get_child_count(dev->of_node); @@ -728,11 +735,11 @@ static int ls1x_nand_chip_init(struct ls1x_nand_host *host) return 0; } -static int ls1x_nand_probe(struct platform_device *pdev) +static int loongson_nand_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct ls1x_nand_data *data; - struct ls1x_nand_host *host; + const struct loongson_nand_data *data; + struct loongson_nand_host *host; struct resource *res; int ret; @@ -759,15 +766,15 @@ static int ls1x_nand_probe(struct platform_device *pdev) host->dev = dev; host->data = data; - host->controller.ops = &ls1x_nand_controller_ops; + host->controller.ops = &loongson_nand_controller_ops; nand_controller_init(&host->controller); - ret = ls1x_nand_controller_init(host); + ret = loongson_nand_controller_init(host); if (ret) goto err; - ret = ls1x_nand_chip_init(host); + ret = loongson_nand_chip_init(host); if (ret) goto err; @@ -775,31 +782,31 @@ static int ls1x_nand_probe(struct platform_device *pdev) return 0; err: - ls1x_nand_controller_cleanup(host); + loongson_nand_controller_cleanup(host); return ret; } -static void ls1x_nand_remove(struct platform_device *pdev) +static void loongson_nand_remove(struct platform_device *pdev) { - struct ls1x_nand_host *host = platform_get_drvdata(pdev); + struct loongson_nand_host *host = platform_get_drvdata(pdev); struct nand_chip *chip = &host->chip; int ret; ret = mtd_device_unregister(nand_to_mtd(chip)); WARN_ON(ret); nand_cleanup(chip); - ls1x_nand_controller_cleanup(host); + loongson_nand_controller_cleanup(host); } -static const struct ls1x_nand_data ls1b_nand_data = { +static const struct loongson_nand_data ls1b_nand_data = { .status_field = GENMASK(15, 8), .hold_cycle = 0x2, .wait_cycle = 0xc, .set_addr = ls1b_nand_set_addr, }; -static const struct ls1x_nand_data ls1c_nand_data = { +static const struct loongson_nand_data ls1c_nand_data = { .status_field = GENMASK(23, 16), .op_scope_field = GENMASK(29, 16), .hold_cycle = 0x2, @@ -807,7 +814,7 @@ static const struct ls1x_nand_data ls1c_nand_data = { .set_addr = ls1c_nand_set_addr, }; -static const struct of_device_id ls1x_nand_match[] = { +static const struct of_device_id loongson_nand_match[] = { { .compatible = "loongson,ls1b-nand-controller", .data = &ls1b_nand_data, @@ -818,19 +825,19 @@ static const struct of_device_id ls1x_nand_match[] = { }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, ls1x_nand_match); +MODULE_DEVICE_TABLE(of, loongson_nand_match); -static struct platform_driver ls1x_nand_driver = { - .probe = ls1x_nand_probe, - .remove = ls1x_nand_remove, +static struct platform_driver loongson_nand_driver = { + .probe = loongson_nand_probe, + .remove = loongson_nand_remove, .driver = { .name = KBUILD_MODNAME, - .of_match_table = ls1x_nand_match, + .of_match_table = loongson_nand_match, }, }; -module_platform_driver(ls1x_nand_driver); +module_platform_driver(loongson_nand_driver); MODULE_AUTHOR("Keguang Zhang "); -MODULE_DESCRIPTION("Loongson-1 NAND Controller Driver"); +MODULE_DESCRIPTION("Loongson NAND Controller Driver"); MODULE_LICENSE("GPL"); From fb1dd6b6722b5187a4fa7385d0be60b28c0f9936 Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Thu, 4 Sep 2025 21:06:34 +0800 Subject: [PATCH 1170/2711] mtd: rawnand: loongson: Add 6-byte NAND ID reading support Loongson-1C and Loongson-2K SoCs support NAND flash chips with 6-byte ID. However, the current implementation only handles 5-byte ID which can lead to incorrect chip detection. Extend loongson_nand_read_id_type_exec() to support 6-byte NAND ID. Signed-off-by: Keguang Zhang Signed-off-by: Binbin Zhou Signed-off-by: Miquel Raynal --- .../mtd/nand/raw/loongson-nand-controller.c | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/raw/loongson-nand-controller.c b/drivers/mtd/nand/raw/loongson-nand-controller.c index b5a7be0fcacc..97cd566420a8 100644 --- a/drivers/mtd/nand/raw/loongson-nand-controller.c +++ b/drivers/mtd/nand/raw/loongson-nand-controller.c @@ -50,6 +50,9 @@ #define LOONGSON_NAND_COL_ADDR_CYC 2U #define LOONGSON_NAND_MAX_ADDR_CYC 5U +#define LOONGSON_NAND_READ_ID_SLEEP_US 1000 +#define LOONGSON_NAND_READ_ID_TIMEOUT_US 5000 + #define BITS_PER_WORD (4 * BITS_PER_BYTE) struct loongson_nand_host; @@ -73,6 +76,8 @@ struct loongson_nand_op { }; struct loongson_nand_data { + unsigned int max_id_cycle; + unsigned int id_cycle_field; unsigned int status_field; unsigned int op_scope_field; unsigned int hold_cycle; @@ -458,10 +463,10 @@ static int loongson_nand_read_id_type_exec(struct nand_chip *chip, const struct struct loongson_nand_op op = {}; int i, ret; union { - char ids[5]; + char ids[6]; struct { int idl; - char idh; + u16 idh; }; } nand_id; @@ -469,11 +474,16 @@ static int loongson_nand_read_id_type_exec(struct nand_chip *chip, const struct if (ret) return ret; - nand_id.idl = readl(host->reg_base + LOONGSON_NAND_IDL); - nand_id.idh = readb(host->reg_base + LOONGSON_NAND_IDH_STATUS); + ret = regmap_read_poll_timeout(host->regmap, LOONGSON_NAND_IDL, nand_id.idl, nand_id.idl, + LOONGSON_NAND_READ_ID_SLEEP_US, + LOONGSON_NAND_READ_ID_TIMEOUT_US); + if (ret) + return ret; - for (i = 0; i < min(sizeof(nand_id.ids), op.orig_len); i++) - op.buf[i] = nand_id.ids[sizeof(nand_id.ids) - 1 - i]; + nand_id.idh = readw(host->reg_base + LOONGSON_NAND_IDH_STATUS); + + for (i = 0; i < min(host->data->max_id_cycle, op.orig_len); i++) + op.buf[i] = nand_id.ids[host->data->max_id_cycle - 1 - i]; return ret; } @@ -676,6 +686,10 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host) if (IS_ERR(host->regmap)) return dev_err_probe(dev, PTR_ERR(host->regmap), "failed to init regmap\n"); + if (host->data->id_cycle_field) + regmap_update_bits(host->regmap, LOONGSON_NAND_PARAM, host->data->id_cycle_field, + host->data->max_id_cycle << __ffs(host->data->id_cycle_field)); + chan = dma_request_chan(dev, "rxtx"); if (IS_ERR(chan)) return dev_err_probe(dev, PTR_ERR(chan), "failed to request DMA channel\n"); @@ -800,6 +814,7 @@ static void loongson_nand_remove(struct platform_device *pdev) } static const struct loongson_nand_data ls1b_nand_data = { + .max_id_cycle = 5, .status_field = GENMASK(15, 8), .hold_cycle = 0x2, .wait_cycle = 0xc, @@ -807,6 +822,8 @@ static const struct loongson_nand_data ls1b_nand_data = { }; static const struct loongson_nand_data ls1c_nand_data = { + .max_id_cycle = 6, + .id_cycle_field = GENMASK(14, 12), .status_field = GENMASK(23, 16), .op_scope_field = GENMASK(29, 16), .hold_cycle = 0x2, From 7ad5bdf88d7295c295a363a5daf481b283acedc2 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Thu, 4 Sep 2025 21:06:35 +0800 Subject: [PATCH 1171/2711] mtd: rawnand: loongson: Add nand chip select support The page address register describes the page address of the starting address for NAND read/write/erase operations. According to the manual, it consists of two parts: {chip select, page number} The `chip select` is fixed at 2 bits, and the `page number` is determined based on the actual capacity of the single-chip memory. Therefore we need to determine the `chip select` bits base on the `page number`. For example, for a 1GB capacity chip (2K page size), it has 1M pages. Thus, [19:0] is used to represent the page number, and [21:20] represents the chip select. Signed-off-by: Binbin Zhou Signed-off-by: Miquel Raynal --- .../mtd/nand/raw/loongson-nand-controller.c | 116 ++++++++++++++---- 1 file changed, 90 insertions(+), 26 deletions(-) diff --git a/drivers/mtd/nand/raw/loongson-nand-controller.c b/drivers/mtd/nand/raw/loongson-nand-controller.c index 97cd566420a8..1427dd6943a7 100644 --- a/drivers/mtd/nand/raw/loongson-nand-controller.c +++ b/drivers/mtd/nand/raw/loongson-nand-controller.c @@ -82,6 +82,7 @@ struct loongson_nand_data { unsigned int op_scope_field; unsigned int hold_cycle; unsigned int wait_cycle; + unsigned int nand_cs; void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op); }; @@ -90,6 +91,7 @@ struct loongson_nand_host { struct nand_chip chip; struct nand_controller controller; const struct loongson_nand_data *data; + unsigned int addr_cs_field; void __iomem *reg_base; struct regmap *regmap; /* DMA Engine stuff */ @@ -215,6 +217,26 @@ static int loongson_nand_parse_instructions(struct nand_chip *chip, const struct return 0; } +static void loongson_nand_set_addr_cs(struct loongson_nand_host *host) +{ + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + + if (!host->data->nand_cs) + return; + + /* + * The Manufacturer/Chip ID read operation precedes attach_chip, at which point + * information such as NAND chip selection and capacity is unknown. As a + * workaround, we use 128MB cellsize (2KB pagesize) as a fallback. + */ + if (!mtd->writesize) + host->addr_cs_field = GENMASK(17, 16); + + regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR2, host->addr_cs_field, + host->data->nand_cs << __ffs(host->addr_cs_field)); +} + static void ls1b_nand_set_addr(struct loongson_nand_host *host, struct loongson_nand_op *op) { struct nand_chip *chip = &host->chip; @@ -263,6 +285,8 @@ static void ls1c_nand_set_addr(struct loongson_nand_host *host, struct loongson_ regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR2, mask, val); } } + + loongson_nand_set_addr_cs(host); } static void loongson_nand_trigger_op(struct loongson_nand_host *host, struct loongson_nand_op *op) @@ -603,42 +627,82 @@ static int loongson_nand_exec_op(struct nand_chip *chip, const struct nand_opera return nand_op_parser_exec_op(chip, &loongson_nand_op_parser, op, check_only); } -static int loongson_nand_attach_chip(struct nand_chip *chip) +static int loongson_nand_get_chip_capacity(struct nand_chip *chip) { struct loongson_nand_host *host = nand_get_controller_data(chip); u64 chipsize = nanddev_target_size(&chip->base); - int cell_size = 0; + struct mtd_info *mtd = nand_to_mtd(chip); - switch (chipsize) { - case SZ_128M: - cell_size = 0x0; + switch (mtd->writesize) { + case SZ_512: + switch (chipsize) { + case SZ_8M: + host->addr_cs_field = GENMASK(15, 14); + return 0x9; + case SZ_16M: + host->addr_cs_field = GENMASK(16, 15); + return 0xa; + case SZ_32M: + host->addr_cs_field = GENMASK(17, 16); + return 0xb; + case SZ_64M: + host->addr_cs_field = GENMASK(18, 17); + return 0xc; + case SZ_128M: + host->addr_cs_field = GENMASK(19, 18); + return 0xd; + } break; - case SZ_256M: - cell_size = 0x1; + case SZ_2K: + switch (chipsize) { + case SZ_128M: + host->addr_cs_field = GENMASK(17, 16); + return 0x0; + case SZ_256M: + host->addr_cs_field = GENMASK(18, 17); + return 0x1; + case SZ_512M: + host->addr_cs_field = GENMASK(19, 18); + return 0x2; + case SZ_1G: + host->addr_cs_field = GENMASK(20, 19); + return 0x3; + } break; - case SZ_512M: - cell_size = 0x2; + case SZ_4K: + if (chipsize == SZ_2G) { + host->addr_cs_field = GENMASK(20, 19); + return 0x4; + } break; - case SZ_1G: - cell_size = 0x3; + case SZ_8K: + switch (chipsize) { + case SZ_4G: + host->addr_cs_field = GENMASK(20, 19); + return 0x5; + case SZ_8G: + host->addr_cs_field = GENMASK(21, 20); + return 0x6; + case SZ_16G: + host->addr_cs_field = GENMASK(22, 21); + return 0x7; + } break; - case SZ_2G: - cell_size = 0x4; - break; - case SZ_4G: - cell_size = 0x5; - break; - case SZ_8G: - cell_size = 0x6; - break; - case SZ_16G: - cell_size = 0x7; - break; - default: - dev_err(host->dev, "unsupported chip size: %llu MB\n", chipsize); - return -EINVAL; } + dev_err(host->dev, "Unsupported chip size: %llu MB with page size %u B\n", + chipsize, mtd->writesize); + return -EINVAL; +} + +static int loongson_nand_attach_chip(struct nand_chip *chip) +{ + struct loongson_nand_host *host = nand_get_controller_data(chip); + int cell_size = loongson_nand_get_chip_capacity(chip); + + if (cell_size < 0) + return cell_size; + switch (chip->ecc.engine_type) { case NAND_ECC_ENGINE_TYPE_NONE: break; From 4a2bab7ccceb14b48e86794b87104248c75aa587 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Thu, 4 Sep 2025 21:07:08 +0800 Subject: [PATCH 1172/2711] dt-bindings: mtd: loongson,ls1b-nand-controller: Document the Loongson-2K0500 NAND controller Add new compatible for the Loongson-2K NAND controller used for Loongson-2K0500 SoC. Acked-by: Rob Herring (Arm) Signed-off-by: Binbin Zhou Signed-off-by: Miquel Raynal --- .../bindings/mtd/loongson,ls1b-nand-controller.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml b/Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml index a09e92e416c4..4ec2b5d1e89d 100644 --- a/Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml @@ -4,13 +4,14 @@ $id: http://devicetree.org/schemas/mtd/loongson,ls1b-nand-controller.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Loongson-1 NAND Controller +title: Loongson NAND Controller maintainers: - Keguang Zhang + - Binbin Zhou description: - The Loongson-1 NAND controller abstracts all supported operations, + The Loongson NAND controller abstracts all supported operations, meaning it does not support low-level access to raw NAND flash chips. Moreover, the controller is paired with the DMA engine to perform READ and PROGRAM functions. @@ -24,6 +25,7 @@ properties: - enum: - loongson,ls1b-nand-controller - loongson,ls1c-nand-controller + - loongson,ls2k0500-nand-controller - items: - enum: - loongson,ls1a-nand-controller From e55bbdd4a4b654dfe8ee8649b3be1db82319d6c0 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Thu, 4 Sep 2025 21:07:09 +0800 Subject: [PATCH 1173/2711] mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support The Loongson-2K0500 NAND controller is similar to the Loongson-1C. It supports a maximum capacity of 16GB FLASH per chip with a maximum page size of 8KB, and it supports up to 4 chip selects and 4 RDY signals. Its DMA controller is defaulted to APBDMA0. Signed-off-by: Binbin Zhou Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/Kconfig | 2 +- .../mtd/nand/raw/loongson-nand-controller.c | 53 ++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 489f5c05cda9..7408f34f0c68 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -438,7 +438,7 @@ config MTD_NAND_NUVOTON_MA35 config MTD_NAND_LOONGSON tristate "Loongson NAND controller" - depends on LOONGSON1_APB_DMA || COMPILE_TEST + depends on LOONGSON1_APB_DMA || LOONGSON2_APB_DMA || COMPILE_TEST select REGMAP_MMIO help Enables support for NAND controller on Loongson family chips. diff --git a/drivers/mtd/nand/raw/loongson-nand-controller.c b/drivers/mtd/nand/raw/loongson-nand-controller.c index 1427dd6943a7..427a0daf8c55 100644 --- a/drivers/mtd/nand/raw/loongson-nand-controller.c +++ b/drivers/mtd/nand/raw/loongson-nand-controller.c @@ -3,6 +3,7 @@ * NAND Controller Driver for Loongson family chips * * Copyright (C) 2015-2025 Keguang Zhang + * Copyright (C) 2025 Binbin Zhou */ #include @@ -26,6 +27,7 @@ #define LOONGSON_NAND_IDH_STATUS 0x14 #define LOONGSON_NAND_PARAM 0x18 #define LOONGSON_NAND_OP_NUM 0x1c +#define LOONGSON_NAND_CS_RDY_MAP 0x20 /* Bitfields of nand command register */ #define LOONGSON_NAND_CMD_OP_DONE BIT(10) @@ -40,6 +42,23 @@ #define LOONGSON_NAND_CMD_READ BIT(1) #define LOONGSON_NAND_CMD_VALID BIT(0) +/* Bitfields of nand cs/rdy map register */ +#define LOONGSON_NAND_MAP_CS1_SEL GENMASK(11, 8) +#define LOONGSON_NAND_MAP_RDY1_SEL GENMASK(15, 12) +#define LOONGSON_NAND_MAP_CS2_SEL GENMASK(19, 16) +#define LOONGSON_NAND_MAP_RDY2_SEL GENMASK(23, 20) +#define LOONGSON_NAND_MAP_CS3_SEL GENMASK(27, 24) +#define LOONGSON_NAND_MAP_RDY3_SEL GENMASK(31, 28) + +#define LOONGSON_NAND_CS_SEL0 BIT(0) +#define LOONGSON_NAND_CS_SEL1 BIT(1) +#define LOONGSON_NAND_CS_SEL2 BIT(2) +#define LOONGSON_NAND_CS_SEL3 BIT(3) +#define LOONGSON_NAND_CS_RDY0 BIT(0) +#define LOONGSON_NAND_CS_RDY1 BIT(1) +#define LOONGSON_NAND_CS_RDY2 BIT(2) +#define LOONGSON_NAND_CS_RDY3 BIT(3) + /* Bitfields of nand timing register */ #define LOONGSON_NAND_WAIT_CYCLE_MASK GENMASK(7, 0) #define LOONGSON_NAND_HOLD_CYCLE_MASK GENMASK(15, 8) @@ -83,6 +102,7 @@ struct loongson_nand_data { unsigned int hold_cycle; unsigned int wait_cycle; unsigned int nand_cs; + unsigned int dma_bits; void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op); }; @@ -744,7 +764,7 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host) struct device *dev = host->dev; struct dma_chan *chan; struct dma_slave_config cfg = {}; - int ret; + int ret, val; host->regmap = devm_regmap_init_mmio(dev, host->reg_base, &loongson_nand_regmap_config); if (IS_ERR(host->regmap)) @@ -754,6 +774,19 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host) regmap_update_bits(host->regmap, LOONGSON_NAND_PARAM, host->data->id_cycle_field, host->data->max_id_cycle << __ffs(host->data->id_cycle_field)); + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(host->data->dma_bits)); + if (ret) + return dev_err_probe(dev, ret, "failed to set DMA mask\n"); + + val = FIELD_PREP(LOONGSON_NAND_MAP_CS1_SEL, LOONGSON_NAND_CS_SEL1) | + FIELD_PREP(LOONGSON_NAND_MAP_RDY1_SEL, LOONGSON_NAND_CS_RDY1) | + FIELD_PREP(LOONGSON_NAND_MAP_CS2_SEL, LOONGSON_NAND_CS_SEL2) | + FIELD_PREP(LOONGSON_NAND_MAP_RDY2_SEL, LOONGSON_NAND_CS_RDY2) | + FIELD_PREP(LOONGSON_NAND_MAP_CS3_SEL, LOONGSON_NAND_CS_SEL3) | + FIELD_PREP(LOONGSON_NAND_MAP_RDY3_SEL, LOONGSON_NAND_CS_RDY3); + + regmap_write(host->regmap, LOONGSON_NAND_CS_RDY_MAP, val); + chan = dma_request_chan(dev, "rxtx"); if (IS_ERR(chan)) return dev_err_probe(dev, PTR_ERR(chan), "failed to request DMA channel\n"); @@ -882,6 +915,7 @@ static const struct loongson_nand_data ls1b_nand_data = { .status_field = GENMASK(15, 8), .hold_cycle = 0x2, .wait_cycle = 0xc, + .dma_bits = 32, .set_addr = ls1b_nand_set_addr, }; @@ -892,6 +926,18 @@ static const struct loongson_nand_data ls1c_nand_data = { .op_scope_field = GENMASK(29, 16), .hold_cycle = 0x2, .wait_cycle = 0xc, + .dma_bits = 32, + .set_addr = ls1c_nand_set_addr, +}; + +static const struct loongson_nand_data ls2k0500_nand_data = { + .max_id_cycle = 6, + .id_cycle_field = GENMASK(14, 12), + .status_field = GENMASK(23, 16), + .op_scope_field = GENMASK(29, 16), + .hold_cycle = 0x4, + .wait_cycle = 0x12, + .dma_bits = 64, .set_addr = ls1c_nand_set_addr, }; @@ -904,6 +950,10 @@ static const struct of_device_id loongson_nand_match[] = { .compatible = "loongson,ls1c-nand-controller", .data = &ls1c_nand_data, }, + { + .compatible = "loongson,ls2k0500-nand-controller", + .data = &ls2k0500_nand_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, loongson_nand_match); @@ -920,5 +970,6 @@ static struct platform_driver loongson_nand_driver = { module_platform_driver(loongson_nand_driver); MODULE_AUTHOR("Keguang Zhang "); +MODULE_AUTHOR("Binbin Zhou "); MODULE_DESCRIPTION("Loongson NAND Controller Driver"); MODULE_LICENSE("GPL"); From 0b1ae6480c3be58ad31afe757cbf1069ae072bb1 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Thu, 4 Sep 2025 21:07:10 +0800 Subject: [PATCH 1174/2711] dt-bindings: mtd: loongson,ls1b-nand-controller: Document the Loongson-2K1000 NAND controller Add new compatible for the Loongson-2K NAND controller used for Loongson-2K1000 SoC. Reviewed-by: Rob Herring (Arm) Signed-off-by: Binbin Zhou Signed-off-by: Miquel Raynal --- .../mtd/loongson,ls1b-nand-controller.yaml | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml b/Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml index 4ec2b5d1e89d..cf85d0cede00 100644 --- a/Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml @@ -26,18 +26,22 @@ properties: - loongson,ls1b-nand-controller - loongson,ls1c-nand-controller - loongson,ls2k0500-nand-controller + - loongson,ls2k1000-nand-controller - items: - enum: - loongson,ls1a-nand-controller - const: loongson,ls1b-nand-controller reg: - maxItems: 2 + minItems: 2 + maxItems: 3 reg-names: + minItems: 2 items: - const: nand - const: nand-dma + - const: dma-config dmas: maxItems: 1 @@ -54,6 +58,27 @@ required: unevaluatedProperties: false +if: + properties: + compatible: + contains: + enum: + - loongson,ls2k1000-nand-controller + +then: + properties: + reg: + minItems: 3 + reg-names: + minItems: 3 + +else: + properties: + reg: + maxItems: 2 + reg-names: + maxItems: 2 + examples: - | nand-controller@1fe78000 { @@ -72,3 +97,26 @@ examples: nand-ecc-algo = "hamming"; }; }; + + - | + nand-controller@1fe26000 { + compatible = "loongson,ls2k1000-nand-controller"; + reg = <0x1fe26000 0x24>, + <0x1fe26040 0x4>, + <0x1fe00438 0x8>; + reg-names = "nand", "nand-dma", "dma-config"; + dmas = <&apbdma0 0>; + dma-names = "rxtx"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + label = "ls2k1000-nand"; + nand-use-soft-ecc-engine; + nand-ecc-algo = "bch"; + nand-ecc-strength = <8>; + nand-ecc-step-size = <512>; + }; + }; From 5808ae66f22e665c7131816e146548f2d7903ae1 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Thu, 4 Sep 2025 21:07:11 +0800 Subject: [PATCH 1175/2711] mtd: rawnand: loongson: Add Loongson-2K1000 NAND controller support The Loongson-2K1000 NAND controller is also similar to the Loongson-1C. It supports a maximum capacity of 16GB FLASH per chip with a maximum page size of 8KB, and it supports up to 4 chip selects and 4 RDY signals. The key difference from the Loongson-2K0500 is that it requires explicit configuration of the DMA control route. Typically, it is configured as APBDMA0. Signed-off-by: Binbin Zhou Signed-off-by: Miquel Raynal --- .../mtd/nand/raw/loongson-nand-controller.c | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/mtd/nand/raw/loongson-nand-controller.c b/drivers/mtd/nand/raw/loongson-nand-controller.c index 427a0daf8c55..8490412d5be1 100644 --- a/drivers/mtd/nand/raw/loongson-nand-controller.c +++ b/drivers/mtd/nand/raw/loongson-nand-controller.c @@ -74,6 +74,14 @@ #define BITS_PER_WORD (4 * BITS_PER_BYTE) +/* Loongson-2K1000 NAND DMA routing register */ +#define LS2K1000_NAND_DMA_MASK GENMASK(2, 0) +#define LS2K1000_DMA0_CONF 0x0 +#define LS2K1000_DMA1_CONF 0x1 +#define LS2K1000_DMA2_CONF 0x2 +#define LS2K1000_DMA3_CONF 0x3 +#define LS2K1000_DMA4_CONF 0x4 + struct loongson_nand_host; struct loongson_nand_op { @@ -103,6 +111,7 @@ struct loongson_nand_data { unsigned int wait_cycle; unsigned int nand_cs; unsigned int dma_bits; + int (*dma_config)(struct device *dev); void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op); }; @@ -759,6 +768,23 @@ static void loongson_nand_controller_cleanup(struct loongson_nand_host *host) dma_release_channel(host->dma_chan); } +static int ls2k1000_nand_apbdma_config(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + void __iomem *regs; + int val; + + regs = devm_platform_ioremap_resource_byname(pdev, "dma-config"); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + val = readl(regs); + val |= FIELD_PREP(LS2K1000_NAND_DMA_MASK, LS2K1000_DMA0_CONF); + writel(val, regs); + + return 0; +} + static int loongson_nand_controller_init(struct loongson_nand_host *host) { struct device *dev = host->dev; @@ -787,6 +813,12 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host) regmap_write(host->regmap, LOONGSON_NAND_CS_RDY_MAP, val); + if (host->data->dma_config) { + ret = host->data->dma_config(dev); + if (ret) + return dev_err_probe(dev, ret, "failed to config DMA routing\n"); + } + chan = dma_request_chan(dev, "rxtx"); if (IS_ERR(chan)) return dev_err_probe(dev, PTR_ERR(chan), "failed to request DMA channel\n"); @@ -941,6 +973,19 @@ static const struct loongson_nand_data ls2k0500_nand_data = { .set_addr = ls1c_nand_set_addr, }; +static const struct loongson_nand_data ls2k1000_nand_data = { + .max_id_cycle = 6, + .id_cycle_field = GENMASK(14, 12), + .status_field = GENMASK(23, 16), + .op_scope_field = GENMASK(29, 16), + .hold_cycle = 0x4, + .wait_cycle = 0x12, + .nand_cs = 0x2, + .dma_bits = 64, + .dma_config = ls2k1000_nand_apbdma_config, + .set_addr = ls1c_nand_set_addr, +}; + static const struct of_device_id loongson_nand_match[] = { { .compatible = "loongson,ls1b-nand-controller", @@ -954,6 +999,10 @@ static const struct of_device_id loongson_nand_match[] = { .compatible = "loongson,ls2k0500-nand-controller", .data = &ls2k0500_nand_data, }, + { + .compatible = "loongson,ls2k1000-nand-controller", + .data = &ls2k1000_nand_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, loongson_nand_match); From 35fae10aaf080c2de06a80463e1129e588600db8 Mon Sep 17 00:00:00 2001 From: Sinan Nalkaya Date: Wed, 27 Aug 2025 15:04:18 -0700 Subject: [PATCH 1176/2711] um: Support SPARSE_IRQ Motivation: IRQ KUnit tests are going to require CONFIG_SPARSE_IRQ [1] in order to: (a) reliably allocate additional (fake) IRQs and (b) ensure we can test managed affinity, which is only supported with SPARSE_IRQ. It seems that the only thing necessary for ARCH=um is to tell the genirq core to skip over our preallocated NR_IRQS. Tested with: $ ./tools/testing/kunit/kunit.py run [...] [13:55:58] Testing complete. Ran 676 tests: passed: 646, skipped: 30 [...] This compares with pre-patch results: Ran 672 tests: passed: 644, skipped: 28 i.e., we no longer skip tests that 'depend on SPARSE_IRQ', and existing tests all pass. [1] [PATCH v2 4/6] genirq/test: Depend on SPARSE_IRQ https://lore.kernel.org/all/CABVgOSngoD0fh1WEkUCEwSdk0Joypo3dA_Y_SjW+K=nVDnZs3Q@mail.gmail.com/ Signed-off-by: Sinan Nalkaya [Brian: Adapted Sinan's patch; rewrote commit message] Signed-off-by: Brian Norris Tested-by: David Gow Signed-off-by: Johannes Berg --- arch/um/Kconfig | 1 + arch/um/kernel/irq.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 9083bfdb7735..8161cc5ae6f7 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -38,6 +38,7 @@ config UML select HAVE_ARCH_TRACEHOOK select HAVE_SYSCALL_TRACEPOINTS select THREAD_INFO_IN_TASK + select SPARSE_IRQ config MMU bool diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 0dfaf96bb7da..d69d137a0334 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -691,6 +691,11 @@ void __init init_IRQ(void) os_setup_epoll(); } +int __init arch_probe_nr_irqs(void) +{ + return NR_IRQS; +} + void sigchld_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs, void *mc) { From a0830785e89da3019a815b51b2073d00bf06e8c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 27 Aug 2025 21:35:35 +0200 Subject: [PATCH 1177/2711] um: virtio-pci: implement .shutdown() We don't want queues stopped since the shutdown can still be doing things with PCI devices, so implement .shutdown() to avoid the generic virtio shutdown. Signed-off-by: Johannes Berg --- arch/um/drivers/virtio_pcidev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/um/drivers/virtio_pcidev.c b/arch/um/drivers/virtio_pcidev.c index e9e23cc3f357..f9b4b6f7582c 100644 --- a/arch/um/drivers/virtio_pcidev.c +++ b/arch/um/drivers/virtio_pcidev.c @@ -598,6 +598,11 @@ static void virtio_pcidev_virtio_remove(struct virtio_device *vdev) kfree(dev); } +static void virtio_pcidev_virtio_shutdown(struct virtio_device *vdev) +{ + /* nothing to do, we just don't want queue shutdown */ +} + static struct virtio_device_id id_table[] = { { CONFIG_UML_PCI_OVER_VIRTIO_DEVICE_ID, VIRTIO_DEV_ANY_ID }, { 0 }, @@ -609,6 +614,7 @@ static struct virtio_driver virtio_pcidev_virtio_driver = { .id_table = id_table, .probe = virtio_pcidev_virtio_probe, .remove = virtio_pcidev_virtio_remove, + .shutdown = virtio_pcidev_virtio_shutdown, }; static int __init virtio_pcidev_init(void) From 26577cfbe1d6b4b98af916f342f44fd25d13af23 Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 27 Aug 2025 08:56:57 +0800 Subject: [PATCH 1178/2711] um: Add missing trailing newline to help messages Some help messages are missing a trailing newline. They should end with two newlines, but only one is present. Add the missing newline to make the --help output more readable. Signed-off-by: Tiwei Bie Signed-off-by: Johannes Berg --- arch/um/drivers/ubd_kern.c | 2 +- arch/um/kernel/dtb.c | 2 +- arch/um/kernel/time.c | 5 +++-- arch/um/os-Linux/skas/process.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 4de6613e7468..01bbd39722c0 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -370,7 +370,7 @@ __uml_help(ubd_setup, " useful when a unique number should be given to the device. Note when\n" " specifying a label, the filename2 must be also presented. It can be\n" " an empty string, in which case the backing file is not used:\n" -" ubd0=File,,Serial\n" +" ubd0=File,,Serial\n\n" ); static int udb_setup(char *str) diff --git a/arch/um/kernel/dtb.c b/arch/um/kernel/dtb.c index 15c342426489..47cd3d869fb2 100644 --- a/arch/um/kernel/dtb.c +++ b/arch/um/kernel/dtb.c @@ -38,5 +38,5 @@ static int __init uml_dtb_setup(char *line, int *add) __uml_setup("dtb=", uml_dtb_setup, "dtb=\n" -" Boot the kernel with the devicetree blob from the specified file.\n" +" Boot the kernel with the devicetree blob from the specified file.\n\n" ); diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index ae0fa2173778..cce5e3371e9f 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -1005,7 +1005,7 @@ __uml_help(setup_time_travel, "have more than one system simultaneously be on simulated time. The virtio\n" "driver code in UML knows about this so you can also simulate networks and\n" "devices using it, assuming the device has the right capabilities.\n" -"The optional ID is a 64-bit integer that's sent to the central scheduler.\n"); +"The optional ID is a 64-bit integer that's sent to the central scheduler.\n\n"); static int setup_time_travel_start(char *str) { @@ -1023,7 +1023,8 @@ __setup("time-travel-start=", setup_time_travel_start); __uml_help(setup_time_travel_start, "time-travel-start=\n" "Configure the UML instance's wall clock to start at this value rather than\n" -"the host's wall clock at the time of UML boot.\n"); +"the host's wall clock at the time of UML boot.\n\n"); + static struct kobject *bc_time_kobject; static ssize_t bc_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 78f48fa9db8b..0bc10cd4cbed 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -895,7 +895,7 @@ __uml_setup("noreboot", noreboot_cmd_param, "noreboot\n" " Rather than rebooting, exit always, akin to QEMU's -no-reboot option.\n" " This is useful if you're using CONFIG_PANIC_TIMEOUT in order to catch\n" -" crashes in CI\n"); +" crashes in CI\n\n"); void reboot_skas(void) { From 2cc62ed234f1038abb9601ccfcaeafa31891e3fe Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 27 Aug 2025 08:56:58 +0800 Subject: [PATCH 1179/2711] um: vector: Fix indentation for help message For consistency with other help messages, use four spaces for indentation instead of a tab plus a space. Signed-off-by: Tiwei Bie Signed-off-by: Johannes Berg --- arch/um/drivers/vector_kern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c index 9bbbddfe866b..25d9258fa592 100644 --- a/arch/um/drivers/vector_kern.c +++ b/arch/um/drivers/vector_kern.c @@ -1721,7 +1721,7 @@ static int __init vector_setup(char *str) __setup("vec", vector_setup); __uml_help(vector_setup, "vec[0-9]+: The above traces are from a Google-VMM based VM, but the same behavior happens with a QEMU based VM that is modified to add a SystemMemory range for the TPM TIS address space. The only reason this doesn't cause problems for HPET, which appears to require a SystemMemory region, is because HPET gets special treatment via x86_init.timers.timer_init(), and so gets a chance to create its UC- mapping before acpi_init() clobbers things. Disabling the early call to hpet_time_init() yields the same behavior for HPET: [ 0.318264] ioremap error for 0xfed00000-0xfed01000, requested 0x2, got 0x0 Hack around the ACPI gap by forcing the legacy PCI hole to UC when overriding the (virtual) MTRRs for CoCo guest, so that ioremap handling of MTRRs naturally kicks in and forces the ACPI mappings to be UC. Note, the requested/mapped memtype doesn't actually matter in terms of accessing the device. In practically every setup, legacy PCI devices are emulated by the hypervisor, and accesses are intercepted and handled as emulated MMIO, i.e. never access physical memory and thus don't have an effective memtype. Even in a theoretical setup where such devices are passed through by the host, i.e. point at real MMIO memory, it is KVM's (as the hypervisor) responsibility to force the memory to be WC/UC, e.g. via EPT memtype under TDX or real hardware MTRRs under SNP. Not doing so cannot work, and the hypervisor is highly motivated to do the right thing as letting the guest access hardware MMIO with WB would likely result in a variety of fatal #MCs. In other words, forcing the range to be UC is all about coercing the kernel's tracking into thinking that it has established UC mappings, so that the ioremap code doesn't reject mappings from e.g. the TPM driver and thus prevent the driver from loading and the device from functioning. Note #2, relying on guest firmware to handle this scenario, e.g. by setting virtual MTRRs and then consuming them in Linux, is not a viable option, as the virtual MTRR state is managed by the untrusted hypervisor, and because OVMF at least has stopped programming virtual MTRRs when running as a TDX guest. Link: https://lore.kernel.org/all/8137d98e-8825-415b-9282-1d2a115bb51a@linux.intel.com Fixes: 8e690b817e38 ("x86/kvm: Override default caching mode for SEV-SNP and TDX") Cc: stable@vger.kernel.org Cc: Peter Gonda Cc: Vitaly Kuznetsov Cc: Tom Lendacky Cc: Jürgen Groß Cc: Korakit Seemakhupt Cc: Jianxiong Gao Cc: Nikolay Borisov Suggested-by: Binbin Wu Reviewed-by: Binbin Wu Tested-by: Korakit Seemakhupt Link: https://lore.kernel.org/r/20250828005249.39339-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kernel/kvm.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 8ae750cde0c6..57379698015e 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -933,6 +933,19 @@ static void kvm_sev_hc_page_enc_status(unsigned long pfn, int npages, bool enc) static void __init kvm_init_platform(void) { + u64 tolud = PFN_PHYS(e820__end_of_low_ram_pfn()); + /* + * Note, hardware requires variable MTRR ranges to be power-of-2 sized + * and naturally aligned. But when forcing guest MTRR state, Linux + * doesn't program the forced ranges into hardware. Don't bother doing + * the math to generate a technically-legal range. + */ + struct mtrr_var_range pci_hole = { + .base_lo = tolud | X86_MEMTYPE_UC, + .mask_lo = (u32)(~(SZ_4G - tolud - 1)) | MTRR_PHYSMASK_V, + .mask_hi = (BIT_ULL(boot_cpu_data.x86_phys_bits) - 1) >> 32, + }; + if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) && kvm_para_has_feature(KVM_FEATURE_MIGRATION_CONTROL)) { unsigned long nr_pages; @@ -982,8 +995,12 @@ static void __init kvm_init_platform(void) kvmclock_init(); x86_platform.apic_post_init = kvm_apic_init; - /* Set WB as the default cache mode for SEV-SNP and TDX */ - guest_force_mtrr_state(NULL, 0, MTRR_TYPE_WRBACK); + /* + * Set WB as the default cache mode for SEV-SNP and TDX, with a single + * UC range for the legacy PCI hole, e.g. so that devices that expect + * to get UC/WC mappings don't get surprised with WB. + */ + guest_force_mtrr_state(&pci_hole, 1, MTRR_TYPE_WRBACK); } #if defined(CONFIG_AMD_MEM_ENCRYPT) From 657bf7048d77c1db6baf0841dd1a65c60d7fc4c7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 29 Jul 2025 08:39:01 -0700 Subject: [PATCH 1261/2711] x86/kvm: Make kvm_async_pf_task_wake() a local static helper Make kvm_async_pf_task_wake() static and drop its export, as the symbol is only referenced from within kvm.c. No functional change intended. Link: https://lore.kernel.org/r/20250729153901.564123-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_para.h | 2 -- arch/x86/kernel/kvm.c | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h index 57bc74e112f2..4a47c16e2df8 100644 --- a/arch/x86/include/asm/kvm_para.h +++ b/arch/x86/include/asm/kvm_para.h @@ -124,7 +124,6 @@ bool kvm_para_available(void); unsigned int kvm_arch_para_features(void); unsigned int kvm_arch_para_hints(void); void kvm_async_pf_task_wait_schedule(u32 token); -void kvm_async_pf_task_wake(u32 token); u32 kvm_read_and_reset_apf_flags(void); bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token); @@ -148,7 +147,6 @@ static inline void kvm_spinlock_init(void) #else /* CONFIG_KVM_GUEST */ #define kvm_async_pf_task_wait_schedule(T) do {} while(0) -#define kvm_async_pf_task_wake(T) do {} while(0) static inline bool kvm_para_available(void) { diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 57379698015e..56608d4d735f 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -190,7 +190,7 @@ static void apf_task_wake_all(void) } } -void kvm_async_pf_task_wake(u32 token) +static void kvm_async_pf_task_wake(u32 token) { u32 key = hash_32(token, KVM_TASK_SLEEP_HASHBITS); struct kvm_task_sleep_head *b = &async_pf_sleepers[key]; @@ -241,7 +241,6 @@ again: /* A dummy token might be allocated and ultimately not used. */ kfree(dummy); } -EXPORT_SYMBOL_GPL(kvm_async_pf_task_wake); noinstr u32 kvm_read_and_reset_apf_flags(void) { From 960550503965094b0babd7e8c83ec66c8a763b0b Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Tue, 22 Jul 2025 19:00:05 +0800 Subject: [PATCH 1262/2711] x86/kvm: Prefer native qspinlock for dedicated vCPUs irrespective of PV_UNHALT The commit b2798ba0b876 ("KVM: X86: Choose qspinlock when dedicated physical CPUs are available") states that when PV_DEDICATED=1 (vCPU has dedicated pCPU), qspinlock should be preferred regardless of PV_UNHALT. However, the current implementation doesn't reflect this: when PV_UNHALT=0, we still use virt_spin_lock() even with dedicated pCPUs. This is suboptimal because: 1. Native qspinlocks should outperform virt_spin_lock() for dedicated vCPUs irrespective of HALT exiting 2. virt_spin_lock() should only be preferred when vCPUs may be preempted (non-dedicated case) So reorder the PV spinlock checks to: 1. First handle dedicated pCPU case (disable virt_spin_lock_key) 2. Second check single CPU, and nopvspin configuration 3. Only then check PV_UNHALT support This ensures we always use native qspinlock for dedicated vCPUs, delivering pretty performance gains at high contention levels. Signed-off-by: Li RongQing Reviewed-by: Sean Christopherson Tested-by: Wangyang Guo Link: https://lore.kernel.org/r/20250722110005.4988-1-lirongqing@baidu.com Signed-off-by: Sean Christopherson --- arch/x86/kernel/kvm.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 56608d4d735f..b67d7c59dca0 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -1088,16 +1088,6 @@ static void kvm_wait(u8 *ptr, u8 val) */ void __init kvm_spinlock_init(void) { - /* - * In case host doesn't support KVM_FEATURE_PV_UNHALT there is still an - * advantage of keeping virt_spin_lock_key enabled: virt_spin_lock() is - * preferred over native qspinlock when vCPU is preempted. - */ - if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT)) { - pr_info("PV spinlocks disabled, no host support\n"); - return; - } - /* * Disable PV spinlocks and use native qspinlock when dedicated pCPUs * are available. @@ -1117,6 +1107,16 @@ void __init kvm_spinlock_init(void) goto out; } + /* + * In case host doesn't support KVM_FEATURE_PV_UNHALT there is still an + * advantage of keeping virt_spin_lock_key enabled: virt_spin_lock() is + * preferred over native qspinlock when vCPU is preempted. + */ + if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT)) { + pr_info("PV spinlocks disabled, no host support\n"); + return; + } + pr_info("PV spinlocks enabled\n"); __pv_init_lock_hash(); From fc55b4cda00aff08ea6dfe86411efa13bdb728c5 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 3 Sep 2025 02:29:50 +0200 Subject: [PATCH 1263/2711] KVM: nSVM: Replace kzalloc() + copy_from_user() with memdup_user() Replace kzalloc() followed by copy_from_user() with memdup_user() to improve and simplify svm_set_nested_state(). Return early if an error occurs instead of trying to allocate memory for 'save' when memory allocation for 'ctl' already failed. Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250903002951.118912-1-thorsten.blum@linux.dev Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/nested.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index b7fd2e869998..826473f2d7c7 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -1798,17 +1798,15 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu, if (kvm_state->size < sizeof(*kvm_state) + KVM_STATE_NESTED_SVM_VMCB_SIZE) return -EINVAL; - ret = -ENOMEM; - ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); - save = kzalloc(sizeof(*save), GFP_KERNEL); - if (!ctl || !save) - goto out_free; + ctl = memdup_user(&user_vmcb->control, sizeof(*ctl)); + if (IS_ERR(ctl)) + return PTR_ERR(ctl); - ret = -EFAULT; - if (copy_from_user(ctl, &user_vmcb->control, sizeof(*ctl))) - goto out_free; - if (copy_from_user(save, &user_vmcb->save, sizeof(*save))) - goto out_free; + save = memdup_user(&user_vmcb->save, sizeof(*save)); + if (IS_ERR(save)) { + kfree(ctl); + return PTR_ERR(save); + } ret = -EINVAL; __nested_copy_vmcb_control_to_cache(vcpu, &ctl_cached, ctl); From 8e7bd526e83673c2b4931163311cca49796657f8 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Fri, 29 Aug 2025 15:22:32 +0300 Subject: [PATCH 1264/2711] clk: tegra: Add DFLL DVCO reset control for Tegra114 The DVCO present in the DFLL IP block has a separate reset line, exposed via the CAR IP block. This reset line is asserted upon SoC reset. Unless something (such as the DFLL driver) deasserts this line, the DVCO will not oscillate, although reads and writes to the DFLL IP block will complete. Based on a3c83ff2 ("clk: tegra: Add DFLL DVCO reset control for Tegra124") Signed-off-by: Svyatoslav Ryhel Reviewed-by: Mikko Perttunen Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra114.c | 30 ++++++++++++++++++++++++++---- drivers/clk/tegra/clk.h | 2 -- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 73303458e886..6c8e053311c3 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "clk.h" #include "clk-id.h" @@ -1272,7 +1273,7 @@ EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_init); * * Assert the reset line of the DFLL's DVCO. No return value. */ -void tegra114_clock_assert_dfll_dvco_reset(void) +static void tegra114_clock_assert_dfll_dvco_reset(void) { u32 v; @@ -1281,7 +1282,6 @@ void tegra114_clock_assert_dfll_dvco_reset(void) writel_relaxed(v, clk_base + RST_DFLL_DVCO); tegra114_car_barrier(); } -EXPORT_SYMBOL(tegra114_clock_assert_dfll_dvco_reset); /** * tegra114_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset @@ -1289,7 +1289,7 @@ EXPORT_SYMBOL(tegra114_clock_assert_dfll_dvco_reset); * Deassert the reset line of the DFLL's DVCO, allowing the DVCO to * operate. No return value. */ -void tegra114_clock_deassert_dfll_dvco_reset(void) +static void tegra114_clock_deassert_dfll_dvco_reset(void) { u32 v; @@ -1298,7 +1298,26 @@ void tegra114_clock_deassert_dfll_dvco_reset(void) writel_relaxed(v, clk_base + RST_DFLL_DVCO); tegra114_car_barrier(); } -EXPORT_SYMBOL(tegra114_clock_deassert_dfll_dvco_reset); + +static int tegra114_reset_assert(unsigned long id) +{ + if (id == TEGRA114_RST_DFLL_DVCO) + tegra114_clock_assert_dfll_dvco_reset(); + else + return -EINVAL; + + return 0; +} + +static int tegra114_reset_deassert(unsigned long id) +{ + if (id == TEGRA114_RST_DFLL_DVCO) + tegra114_clock_deassert_dfll_dvco_reset(); + else + return -EINVAL; + + return 0; +} static void __init tegra114_clock_init(struct device_node *np) { @@ -1344,6 +1363,9 @@ static void __init tegra114_clock_init(struct device_node *np) tegra_super_clk_gen4_init(clk_base, pmc_base, tegra114_clks, &pll_x_params); + tegra_init_special_resets(1, tegra114_reset_assert, + tegra114_reset_deassert); + tegra_add_of_provider(np, of_clk_src_onecell_get); tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 9ea839af14bc..73efd2ff37c9 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -897,8 +897,6 @@ static inline bool tegra124_clk_emc_driver_available(struct clk_hw *emc_hw) void tegra114_clock_tune_cpu_trimmers_high(void); void tegra114_clock_tune_cpu_trimmers_low(void); void tegra114_clock_tune_cpu_trimmers_init(void); -void tegra114_clock_assert_dfll_dvco_reset(void); -void tegra114_clock_deassert_dfll_dvco_reset(void); typedef void (*tegra_clk_apply_init_table_func)(void); extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table; From a24cd110e664396061b0a72930734bf419bf88c4 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 9 Sep 2025 19:07:46 +0100 Subject: [PATCH 1265/2711] dt-bindings: clock: renesas,r9a09g047-cpg: Add USB3.0 core clocks Add definitions for USB3.0 core clocks in the R9A09G047 CPG DT bindings header file. Reviewed-by: Geert Uytterhoeven Acked-by: Conor Dooley Signed-off-by: Biju Das Link: https://patch.msgid.link/20250909180803.140939-2-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- include/dt-bindings/clock/renesas,r9a09g047-cpg.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dt-bindings/clock/renesas,r9a09g047-cpg.h b/include/dt-bindings/clock/renesas,r9a09g047-cpg.h index a27132f9a6c8..f165df8a6f5a 100644 --- a/include/dt-bindings/clock/renesas,r9a09g047-cpg.h +++ b/include/dt-bindings/clock/renesas,r9a09g047-cpg.h @@ -20,5 +20,7 @@ #define R9A09G047_SPI_CLK_SPI 9 #define R9A09G047_GBETH_0_CLK_PTP_REF_I 10 #define R9A09G047_GBETH_1_CLK_PTP_REF_I 11 +#define R9A09G047_USB3_0_REF_ALT_CLK_P 12 +#define R9A09G047_USB3_0_CLKCORE 13 #endif /* __DT_BINDINGS_CLOCK_RENESAS_R9A09G047_CPG_H__ */ From 23c59916bafa396265c12112bc94f373ad560b16 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 4 Sep 2025 16:55:06 +0100 Subject: [PATCH 1266/2711] clk: renesas: r9a09g057: Add clock and reset entries for I3C Add module clock entries for the I3C controller on the RZ/V2H(P) (R9A09G057) SoC. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250904155507.245744-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a09g057-cpg.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c index f7de69a93de1..c2b5d04ed92e 100644 --- a/drivers/clk/renesas/r9a09g057-cpg.c +++ b/drivers/clk/renesas/r9a09g057-cpg.c @@ -260,6 +260,12 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { BUS_MSTOP(11, BIT(2))), DEF_MOD("scif_0_clk_pck", CLK_PLLCM33_DIV16, 8, 15, 4, 15, BUS_MSTOP(3, BIT(14))), + DEF_MOD("i3c_0_pclkrw", CLK_PLLCLN_DIV16, 9, 0, 4, 16, + BUS_MSTOP(10, BIT(15))), + DEF_MOD("i3c_0_pclk", CLK_PLLCLN_DIV16, 9, 1, 4, 17, + BUS_MSTOP(10, BIT(15))), + DEF_MOD("i3c_0_tclk", CLK_PLLCLN_DIV8, 9, 2, 4, 18, + BUS_MSTOP(10, BIT(15))), DEF_MOD("riic_8_ckm", CLK_PLLCM33_DIV16, 9, 3, 4, 19, BUS_MSTOP(3, BIT(13))), DEF_MOD("riic_0_ckm", CLK_PLLCLN_DIV16, 9, 4, 4, 20, @@ -403,6 +409,8 @@ static const struct rzv2h_reset r9a09g057_resets[] __initconst = { DEF_RST(7, 15, 3, 16), /* RSPI_2_PRESETN */ DEF_RST(8, 0, 3, 17), /* RSPI_2_TRESETN */ DEF_RST(9, 5, 4, 6), /* SCIF_0_RST_SYSTEM_N */ + DEF_RST(9, 6, 4, 7), /* I3C_0_PRESETN */ + DEF_RST(9, 7, 4, 8), /* I3C_0_TRESETN */ DEF_RST(9, 8, 4, 9), /* RIIC_0_MRST */ DEF_RST(9, 9, 4, 10), /* RIIC_1_MRST */ DEF_RST(9, 10, 4, 11), /* RIIC_2_MRST */ From 2cfff084f03005079f900fe6d0a031f7c508e881 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 4 Sep 2025 16:55:07 +0100 Subject: [PATCH 1267/2711] clk: renesas: r9a09g056: Add clock and reset entries for I3C Add module clock entries for the I3C controller on the RZ/V2N (R9A09G056) SoC. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250904155507.245744-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a09g056-cpg.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/renesas/r9a09g056-cpg.c b/drivers/clk/renesas/r9a09g056-cpg.c index 437af86f49dd..f0a8c5073fa6 100644 --- a/drivers/clk/renesas/r9a09g056-cpg.c +++ b/drivers/clk/renesas/r9a09g056-cpg.c @@ -205,6 +205,12 @@ static const struct rzv2h_mod_clk r9a09g056_mod_clks[] __initconst = { BUS_MSTOP(5, BIT(13))), DEF_MOD("scif_0_clk_pck", CLK_PLLCM33_DIV16, 8, 15, 4, 15, BUS_MSTOP(3, BIT(14))), + DEF_MOD("i3c_0_pclkrw", CLK_PLLCLN_DIV16, 9, 0, 4, 16, + BUS_MSTOP(10, BIT(15))), + DEF_MOD("i3c_0_pclk", CLK_PLLCLN_DIV16, 9, 1, 4, 17, + BUS_MSTOP(10, BIT(15))), + DEF_MOD("i3c_0_tclk", CLK_PLLCLN_DIV8, 9, 2, 4, 18, + BUS_MSTOP(10, BIT(15))), DEF_MOD("riic_8_ckm", CLK_PLLCM33_DIV16, 9, 3, 4, 19, BUS_MSTOP(3, BIT(13))), DEF_MOD("riic_0_ckm", CLK_PLLCLN_DIV16, 9, 4, 4, 20, @@ -308,6 +314,8 @@ static const struct rzv2h_reset r9a09g056_resets[] __initconst = { DEF_RST(7, 7, 3, 8), /* WDT_2_RESET */ DEF_RST(7, 8, 3, 9), /* WDT_3_RESET */ DEF_RST(9, 5, 4, 6), /* SCIF_0_RST_SYSTEM_N */ + DEF_RST(9, 6, 4, 7), /* I3C_0_PRESETN */ + DEF_RST(9, 7, 4, 8), /* I3C_0_TRESETN */ DEF_RST(9, 8, 4, 9), /* RIIC_0_MRST */ DEF_RST(9, 9, 4, 10), /* RIIC_1_MRST */ DEF_RST(9, 10, 4, 11), /* RIIC_2_MRST */ From 7aa8781f379c32c31bd78f1408a31765b2297c43 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 10 Sep 2025 01:09:47 +0800 Subject: [PATCH 1268/2711] clk: sunxi-ng: sun6i-rtc: Add A523 specifics The A523's RTC block is backward compatible with the R329's, but it also has a calibration function for its internal oscillator, which would allow it to provide a clock rate closer to the desired 32.768 KHz. This is useful on the Radxa Cubie A5E, which does not have an external 32.768 KHz crystal. Add new compatible-specific data for it. Acked-by: Jernej Skrabec Link: https://patch.msgid.link/20250909170947.2221611-1-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/ccu-sun6i-rtc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c index 0536e880b80f..f6bfeba009e8 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c @@ -325,6 +325,13 @@ static const struct sun6i_rtc_match_data sun50i_r329_rtc_ccu_data = { .osc32k_fanout_nparents = ARRAY_SIZE(sun50i_r329_osc32k_fanout_parents), }; +static const struct sun6i_rtc_match_data sun55i_a523_rtc_ccu_data = { + .have_ext_osc32k = true, + .have_iosc_calibration = true, + .osc32k_fanout_parents = sun50i_r329_osc32k_fanout_parents, + .osc32k_fanout_nparents = ARRAY_SIZE(sun50i_r329_osc32k_fanout_parents), +}; + static const struct of_device_id sun6i_rtc_ccu_match[] = { { .compatible = "allwinner,sun50i-h616-rtc", @@ -334,6 +341,10 @@ static const struct of_device_id sun6i_rtc_ccu_match[] = { .compatible = "allwinner,sun50i-r329-rtc", .data = &sun50i_r329_rtc_ccu_data, }, + { + .compatible = "allwinner,sun55i-a523-rtc", + .data = &sun55i_a523_rtc_ccu_data, + }, {}, }; MODULE_DEVICE_TABLE(of, sun6i_rtc_ccu_match); From e414b1005891d74bb0c3d27684c58dfbfbd1754b Mon Sep 17 00:00:00 2001 From: Kai Huang Date: Tue, 9 Sep 2025 19:55:53 +1200 Subject: [PATCH 1269/2711] x86/virt/tdx: Use precalculated TDVPR page physical address All of the x86 KVM guest types (VMX, SEV and TDX) do some special context tracking when entering guests. This means that the actual guest entry sequence must be noinstr. Part of entering a TDX guest is passing a physical address to the TDX module. Right now, that physical address is stored as a 'struct page' and converted to a physical address at guest entry. That page=>phys conversion can be complicated, can vary greatly based on kernel config, and it is definitely _not_ a noinstr path today. There have been a number of tinkering approaches to try and fix this up, but they all fall down due to some part of the page=>phys conversion infrastructure not being noinstr friendly. Precalculate the page=>phys conversion and store it in the existing 'tdx_vp' structure. Use the new field at every site that needs a tdvpr physical address. Remove the now redundant tdx_tdvpr_pa(). Remove the __flatten remnant from the tinkering. Note that only one user of the new field is actually noinstr. All others can use page_to_phys(). But, they might as well save the effort since there is a pre-calculated value sitting there for them. [ dhansen: rewrite all the text ] Signed-off-by: Kai Huang Signed-off-by: Dave Hansen Reviewed-by: Kiryl Shutsemau Tested-by: Farrah Chen --- arch/x86/include/asm/tdx.h | 2 ++ arch/x86/kvm/vmx/tdx.c | 9 +++++++++ arch/x86/virt/vmx/tdx/tdx.c | 21 ++++++++------------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 6120461bd5ff..6b338d7f01b7 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -171,6 +171,8 @@ struct tdx_td { struct tdx_vp { /* TDVP root page */ struct page *tdvpr_page; + /* precalculated page_to_phys(tdvpr_page) for use in noinstr code */ + phys_addr_t tdvpr_pa; /* TD vCPU control structure: */ struct page **tdcx_pages; diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 04b6d332c1af..75326a7449cc 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -852,6 +852,7 @@ void tdx_vcpu_free(struct kvm_vcpu *vcpu) if (tdx->vp.tdvpr_page) { tdx_reclaim_control_page(tdx->vp.tdvpr_page); tdx->vp.tdvpr_page = 0; + tdx->vp.tdvpr_pa = 0; } tdx->state = VCPU_TD_STATE_UNINITIALIZED; @@ -2931,6 +2932,13 @@ static int tdx_td_vcpu_init(struct kvm_vcpu *vcpu, u64 vcpu_rcx) return -ENOMEM; tdx->vp.tdvpr_page = page; + /* + * page_to_phys() does not work in 'noinstr' code, like guest + * entry via tdh_vp_enter(). Precalculate and store it instead + * of doing it at runtime later. + */ + tdx->vp.tdvpr_pa = page_to_phys(tdx->vp.tdvpr_page); + tdx->vp.tdcx_pages = kcalloc(kvm_tdx->td.tdcx_nr_pages, sizeof(*tdx->vp.tdcx_pages), GFP_KERNEL); if (!tdx->vp.tdcx_pages) { @@ -2993,6 +3001,7 @@ free_tdvpr: if (tdx->vp.tdvpr_page) __free_page(tdx->vp.tdvpr_page); tdx->vp.tdvpr_page = 0; + tdx->vp.tdvpr_pa = 0; return ret; } diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 330b560313af..eac403248462 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -1504,11 +1504,6 @@ static inline u64 tdx_tdr_pa(struct tdx_td *td) return page_to_phys(td->tdr_page); } -static inline u64 tdx_tdvpr_pa(struct tdx_vp *td) -{ - return page_to_phys(td->tdvpr_page); -} - /* * The TDX module exposes a CLFLUSH_BEFORE_ALLOC bit to specify whether * a CLFLUSH of pages is required before handing them to the TDX module. @@ -1520,9 +1515,9 @@ static void tdx_clflush_page(struct page *page) clflush_cache_range(page_to_virt(page), PAGE_SIZE); } -noinstr __flatten u64 tdh_vp_enter(struct tdx_vp *td, struct tdx_module_args *args) +noinstr u64 tdh_vp_enter(struct tdx_vp *td, struct tdx_module_args *args) { - args->rcx = tdx_tdvpr_pa(td); + args->rcx = td->tdvpr_pa; return __seamcall_dirty_cache(__seamcall_saved_ret, TDH_VP_ENTER, args); } @@ -1583,7 +1578,7 @@ u64 tdh_vp_addcx(struct tdx_vp *vp, struct page *tdcx_page) { struct tdx_module_args args = { .rcx = page_to_phys(tdcx_page), - .rdx = tdx_tdvpr_pa(vp), + .rdx = vp->tdvpr_pa, }; tdx_clflush_page(tdcx_page); @@ -1652,7 +1647,7 @@ EXPORT_SYMBOL_GPL(tdh_mng_create); u64 tdh_vp_create(struct tdx_td *td, struct tdx_vp *vp) { struct tdx_module_args args = { - .rcx = tdx_tdvpr_pa(vp), + .rcx = vp->tdvpr_pa, .rdx = tdx_tdr_pa(td), }; @@ -1708,7 +1703,7 @@ EXPORT_SYMBOL_GPL(tdh_mr_finalize); u64 tdh_vp_flush(struct tdx_vp *vp) { struct tdx_module_args args = { - .rcx = tdx_tdvpr_pa(vp), + .rcx = vp->tdvpr_pa, }; return seamcall(TDH_VP_FLUSH, &args); @@ -1754,7 +1749,7 @@ EXPORT_SYMBOL_GPL(tdh_mng_init); u64 tdh_vp_rd(struct tdx_vp *vp, u64 field, u64 *data) { struct tdx_module_args args = { - .rcx = tdx_tdvpr_pa(vp), + .rcx = vp->tdvpr_pa, .rdx = field, }; u64 ret; @@ -1771,7 +1766,7 @@ EXPORT_SYMBOL_GPL(tdh_vp_rd); u64 tdh_vp_wr(struct tdx_vp *vp, u64 field, u64 data, u64 mask) { struct tdx_module_args args = { - .rcx = tdx_tdvpr_pa(vp), + .rcx = vp->tdvpr_pa, .rdx = field, .r8 = data, .r9 = mask, @@ -1784,7 +1779,7 @@ EXPORT_SYMBOL_GPL(tdh_vp_wr); u64 tdh_vp_init(struct tdx_vp *vp, u64 initial_rcx, u32 x2apicid) { struct tdx_module_args args = { - .rcx = tdx_tdvpr_pa(vp), + .rcx = vp->tdvpr_pa, .rdx = initial_rcx, .r8 = x2apicid, }; From a85ac2dae6bf8050deaf9839e4c0328756b48720 Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 10 Sep 2025 14:30:11 +0100 Subject: [PATCH 1270/2711] tools headers: Remove unused kvm_perf.h copies These have been unused since commit 162607ea20fa ("perf kvm/{x86,s390}: Remove dependency on uapi/kvm_perf.h") in favour of dynamic discovery. Remove the unused headers to reduce consistency checking overhead and noise. Signed-off-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Suzuki Poulouse Link: https://lore.kernel.org/r/20250910-james-tools-header-cleanup-v1-1-7ae4bedc99e0@linaro.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/s390/include/uapi/asm/kvm_perf.h | 22 --------------------- tools/arch/x86/include/uapi/asm/kvm_perf.h | 17 ---------------- tools/perf/check-headers.sh | 2 -- 3 files changed, 41 deletions(-) delete mode 100644 tools/arch/s390/include/uapi/asm/kvm_perf.h delete mode 100644 tools/arch/x86/include/uapi/asm/kvm_perf.h diff --git a/tools/arch/s390/include/uapi/asm/kvm_perf.h b/tools/arch/s390/include/uapi/asm/kvm_perf.h deleted file mode 100644 index 84606b8cc49e..000000000000 --- a/tools/arch/s390/include/uapi/asm/kvm_perf.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Definitions for perf-kvm on s390 - * - * Copyright 2014 IBM Corp. - * Author(s): Alexander Yarygin - */ - -#ifndef __LINUX_KVM_PERF_S390_H -#define __LINUX_KVM_PERF_S390_H - -#include - -#define DECODE_STR_LEN 40 - -#define VCPU_ID "id" - -#define KVM_ENTRY_TRACE "kvm:kvm_s390_sie_enter" -#define KVM_EXIT_TRACE "kvm:kvm_s390_sie_exit" -#define KVM_EXIT_REASON "icptcode" - -#endif diff --git a/tools/arch/x86/include/uapi/asm/kvm_perf.h b/tools/arch/x86/include/uapi/asm/kvm_perf.h deleted file mode 100644 index 125cf5cdf6c5..000000000000 --- a/tools/arch/x86/include/uapi/asm/kvm_perf.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _ASM_X86_KVM_PERF_H -#define _ASM_X86_KVM_PERF_H - -#include -#include -#include - -#define DECODE_STR_LEN 20 - -#define VCPU_ID "vcpu_id" - -#define KVM_ENTRY_TRACE "kvm:kvm_entry" -#define KVM_EXIT_TRACE "kvm:kvm_exit" -#define KVM_EXIT_REASON "exit_reason" - -#endif /* _ASM_X86_KVM_PERF_H */ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index be519c433ce4..6eacc02fbb1b 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -40,13 +40,11 @@ declare -a FILES=( "arch/s390/include/uapi/asm/perf_regs.h" "arch/x86/include/uapi/asm/perf_regs.h" "arch/x86/include/uapi/asm/kvm.h" - "arch/x86/include/uapi/asm/kvm_perf.h" "arch/x86/include/uapi/asm/svm.h" "arch/x86/include/uapi/asm/unistd.h" "arch/x86/include/uapi/asm/vmx.h" "arch/powerpc/include/uapi/asm/kvm.h" "arch/s390/include/uapi/asm/kvm.h" - "arch/s390/include/uapi/asm/kvm_perf.h" "arch/s390/include/uapi/asm/sie.h" "arch/arm/include/uapi/asm/kvm.h" "arch/arm64/include/uapi/asm/kvm.h" From 4589be8cd0338e6bf0f5b9aaa044442876e78894 Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 10 Sep 2025 14:30:12 +0100 Subject: [PATCH 1271/2711] tools headers: Remove unused arm32 asm/kvm.h copy arm32 KVM was removed in commit 541ad0150ca4 ("arm: Remove 32bit KVM host support"). None of the kvm selftests are compiled for arm32 and it's not indirectly included from anywhere either, so delete it. Reviewed-by: Leo Yan Signed-off-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Suzuki Poulouse Link: https://lore.kernel.org/r/20250910-james-tools-header-cleanup-v1-2-7ae4bedc99e0@linaro.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/arm/include/uapi/asm/kvm.h | 315 -------------------------- tools/perf/check-headers.sh | 1 - 2 files changed, 316 deletions(-) delete mode 100644 tools/arch/arm/include/uapi/asm/kvm.h diff --git a/tools/arch/arm/include/uapi/asm/kvm.h b/tools/arch/arm/include/uapi/asm/kvm.h deleted file mode 100644 index d5dd96902817..000000000000 --- a/tools/arch/arm/include/uapi/asm/kvm.h +++ /dev/null @@ -1,315 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright (C) 2012 - Virtual Open Systems and Columbia University - * Author: Christoffer Dall - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __ARM_KVM_H__ -#define __ARM_KVM_H__ - -#include -#include -#include - -#define __KVM_HAVE_GUEST_DEBUG -#define __KVM_HAVE_IRQ_LINE -#define __KVM_HAVE_READONLY_MEM -#define __KVM_HAVE_VCPU_EVENTS - -#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 - -#define KVM_REG_SIZE(id) \ - (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) - -/* Valid for svc_regs, abt_regs, und_regs, irq_regs in struct kvm_regs */ -#define KVM_ARM_SVC_sp svc_regs[0] -#define KVM_ARM_SVC_lr svc_regs[1] -#define KVM_ARM_SVC_spsr svc_regs[2] -#define KVM_ARM_ABT_sp abt_regs[0] -#define KVM_ARM_ABT_lr abt_regs[1] -#define KVM_ARM_ABT_spsr abt_regs[2] -#define KVM_ARM_UND_sp und_regs[0] -#define KVM_ARM_UND_lr und_regs[1] -#define KVM_ARM_UND_spsr und_regs[2] -#define KVM_ARM_IRQ_sp irq_regs[0] -#define KVM_ARM_IRQ_lr irq_regs[1] -#define KVM_ARM_IRQ_spsr irq_regs[2] - -/* Valid only for fiq_regs in struct kvm_regs */ -#define KVM_ARM_FIQ_r8 fiq_regs[0] -#define KVM_ARM_FIQ_r9 fiq_regs[1] -#define KVM_ARM_FIQ_r10 fiq_regs[2] -#define KVM_ARM_FIQ_fp fiq_regs[3] -#define KVM_ARM_FIQ_ip fiq_regs[4] -#define KVM_ARM_FIQ_sp fiq_regs[5] -#define KVM_ARM_FIQ_lr fiq_regs[6] -#define KVM_ARM_FIQ_spsr fiq_regs[7] - -struct kvm_regs { - struct pt_regs usr_regs; /* R0_usr - R14_usr, PC, CPSR */ - unsigned long svc_regs[3]; /* SP_svc, LR_svc, SPSR_svc */ - unsigned long abt_regs[3]; /* SP_abt, LR_abt, SPSR_abt */ - unsigned long und_regs[3]; /* SP_und, LR_und, SPSR_und */ - unsigned long irq_regs[3]; /* SP_irq, LR_irq, SPSR_irq */ - unsigned long fiq_regs[8]; /* R8_fiq - R14_fiq, SPSR_fiq */ -}; - -/* Supported Processor Types */ -#define KVM_ARM_TARGET_CORTEX_A15 0 -#define KVM_ARM_TARGET_CORTEX_A7 1 -#define KVM_ARM_NUM_TARGETS 2 - -/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ -#define KVM_ARM_DEVICE_TYPE_SHIFT 0 -#define KVM_ARM_DEVICE_TYPE_MASK (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT) -#define KVM_ARM_DEVICE_ID_SHIFT 16 -#define KVM_ARM_DEVICE_ID_MASK (0xffff << KVM_ARM_DEVICE_ID_SHIFT) - -/* Supported device IDs */ -#define KVM_ARM_DEVICE_VGIC_V2 0 - -/* Supported VGIC address types */ -#define KVM_VGIC_V2_ADDR_TYPE_DIST 0 -#define KVM_VGIC_V2_ADDR_TYPE_CPU 1 - -#define KVM_VGIC_V2_DIST_SIZE 0x1000 -#define KVM_VGIC_V2_CPU_SIZE 0x2000 - -/* Supported VGICv3 address types */ -#define KVM_VGIC_V3_ADDR_TYPE_DIST 2 -#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 -#define KVM_VGIC_ITS_ADDR_TYPE 4 -#define KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION 5 - -#define KVM_VGIC_V3_DIST_SIZE SZ_64K -#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K) -#define KVM_VGIC_V3_ITS_SIZE (2 * SZ_64K) - -#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ -#define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */ - -struct kvm_vcpu_init { - __u32 target; - __u32 features[7]; -}; - -struct kvm_sregs { -}; - -struct kvm_fpu { -}; - -struct kvm_guest_debug_arch { -}; - -struct kvm_debug_exit_arch { -}; - -struct kvm_sync_regs { - /* Used with KVM_CAP_ARM_USER_IRQ */ - __u64 device_irq_level; -}; - -struct kvm_arch_memory_slot { -}; - -/* for KVM_GET/SET_VCPU_EVENTS */ -struct kvm_vcpu_events { - struct { - __u8 serror_pending; - __u8 serror_has_esr; - __u8 ext_dabt_pending; - /* Align it to 8 bytes */ - __u8 pad[5]; - __u64 serror_esr; - } exception; - __u32 reserved[12]; -}; - -/* If you need to interpret the index values, here is the key: */ -#define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000 -#define KVM_REG_ARM_COPROC_SHIFT 16 -#define KVM_REG_ARM_32_OPC2_MASK 0x0000000000000007 -#define KVM_REG_ARM_32_OPC2_SHIFT 0 -#define KVM_REG_ARM_OPC1_MASK 0x0000000000000078 -#define KVM_REG_ARM_OPC1_SHIFT 3 -#define KVM_REG_ARM_CRM_MASK 0x0000000000000780 -#define KVM_REG_ARM_CRM_SHIFT 7 -#define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800 -#define KVM_REG_ARM_32_CRN_SHIFT 11 -/* - * For KVM currently all guest registers are nonsecure, but we reserve a bit - * in the encoding to distinguish secure from nonsecure for AArch32 system - * registers that are banked by security. This is 1 for the secure banked - * register, and 0 for the nonsecure banked register or if the register is - * not banked by security. - */ -#define KVM_REG_ARM_SECURE_MASK 0x0000000010000000 -#define KVM_REG_ARM_SECURE_SHIFT 28 - -#define ARM_CP15_REG_SHIFT_MASK(x,n) \ - (((x) << KVM_REG_ARM_ ## n ## _SHIFT) & KVM_REG_ARM_ ## n ## _MASK) - -#define __ARM_CP15_REG(op1,crn,crm,op2) \ - (KVM_REG_ARM | (15 << KVM_REG_ARM_COPROC_SHIFT) | \ - ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \ - ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \ - ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \ - ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2)) - -#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32) - -#define __ARM_CP15_REG64(op1,crm) \ - (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64) -#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__) - -/* PL1 Physical Timer Registers */ -#define KVM_REG_ARM_PTIMER_CTL ARM_CP15_REG32(0, 14, 2, 1) -#define KVM_REG_ARM_PTIMER_CNT ARM_CP15_REG64(0, 14) -#define KVM_REG_ARM_PTIMER_CVAL ARM_CP15_REG64(2, 14) - -/* Virtual Timer Registers */ -#define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1) -#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) -#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) - -/* Normal registers are mapped as coprocessor 16. */ -#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) -#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) - -/* Some registers need more space to represent values. */ -#define KVM_REG_ARM_DEMUX (0x0011 << KVM_REG_ARM_COPROC_SHIFT) -#define KVM_REG_ARM_DEMUX_ID_MASK 0x000000000000FF00 -#define KVM_REG_ARM_DEMUX_ID_SHIFT 8 -#define KVM_REG_ARM_DEMUX_ID_CCSIDR (0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT) -#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF -#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0 - -/* VFP registers: we could overload CP10 like ARM does, but that's ugly. */ -#define KVM_REG_ARM_VFP (0x0012 << KVM_REG_ARM_COPROC_SHIFT) -#define KVM_REG_ARM_VFP_MASK 0x000000000000FFFF -#define KVM_REG_ARM_VFP_BASE_REG 0x0 -#define KVM_REG_ARM_VFP_FPSID 0x1000 -#define KVM_REG_ARM_VFP_FPSCR 0x1001 -#define KVM_REG_ARM_VFP_MVFR1 0x1006 -#define KVM_REG_ARM_VFP_MVFR0 0x1007 -#define KVM_REG_ARM_VFP_FPEXC 0x1008 -#define KVM_REG_ARM_VFP_FPINST 0x1009 -#define KVM_REG_ARM_VFP_FPINST2 0x100A - -/* KVM-as-firmware specific pseudo-registers */ -#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) -#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \ - KVM_REG_ARM_FW | ((r) & 0xffff)) -#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) -#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 KVM_REG_ARM_FW_REG(1) - /* Higher values mean better protection. */ -#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL 0 -#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL 1 -#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED 2 -#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 KVM_REG_ARM_FW_REG(2) - /* Higher values mean better protection. */ -#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL 0 -#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN 1 -#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL 2 -#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED 3 -#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED (1U << 4) - -/* Device Control API: ARM VGIC */ -#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 -#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 -#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 -#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 -#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) -#define KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32 -#define KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \ - (0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT) -#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 -#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) -#define KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff) -#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3 -#define KVM_DEV_ARM_VGIC_GRP_CTRL 4 -#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5 -#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 -#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 -#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8 -#define KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ 9 -#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 -#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ - (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) -#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff -#define VGIC_LEVEL_INFO_LINE_LEVEL 0 - -/* Device Control API on vcpu fd */ -#define KVM_ARM_VCPU_PMU_V3_CTRL 0 -#define KVM_ARM_VCPU_PMU_V3_IRQ 0 -#define KVM_ARM_VCPU_PMU_V3_INIT 1 -#define KVM_ARM_VCPU_TIMER_CTRL 1 -#define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0 -#define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 - -#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 -#define KVM_DEV_ARM_ITS_SAVE_TABLES 1 -#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 -#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 -#define KVM_DEV_ARM_ITS_CTRL_RESET 4 - -/* KVM_IRQ_LINE irq field index values */ -#define KVM_ARM_IRQ_VCPU2_SHIFT 28 -#define KVM_ARM_IRQ_VCPU2_MASK 0xf -#define KVM_ARM_IRQ_TYPE_SHIFT 24 -#define KVM_ARM_IRQ_TYPE_MASK 0xf -#define KVM_ARM_IRQ_VCPU_SHIFT 16 -#define KVM_ARM_IRQ_VCPU_MASK 0xff -#define KVM_ARM_IRQ_NUM_SHIFT 0 -#define KVM_ARM_IRQ_NUM_MASK 0xffff - -/* irq_type field */ -#define KVM_ARM_IRQ_TYPE_CPU 0 -#define KVM_ARM_IRQ_TYPE_SPI 1 -#define KVM_ARM_IRQ_TYPE_PPI 2 - -/* out-of-kernel GIC cpu interrupt injection irq_number field */ -#define KVM_ARM_IRQ_CPU_IRQ 0 -#define KVM_ARM_IRQ_CPU_FIQ 1 - -/* - * This used to hold the highest supported SPI, but it is now obsolete - * and only here to provide source code level compatibility with older - * userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS. - */ -#ifndef __KERNEL__ -#define KVM_ARM_IRQ_GIC_MAX 127 -#endif - -/* One single KVM irqchip, ie. the VGIC */ -#define KVM_NR_IRQCHIPS 1 - -/* PSCI interface */ -#define KVM_PSCI_FN_BASE 0x95c1ba5e -#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n)) - -#define KVM_PSCI_FN_CPU_SUSPEND KVM_PSCI_FN(0) -#define KVM_PSCI_FN_CPU_OFF KVM_PSCI_FN(1) -#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) -#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) - -#define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS -#define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED -#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS -#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED - -#endif /* __ARM_KVM_H__ */ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 6eacc02fbb1b..0987062896bb 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -46,7 +46,6 @@ declare -a FILES=( "arch/powerpc/include/uapi/asm/kvm.h" "arch/s390/include/uapi/asm/kvm.h" "arch/s390/include/uapi/asm/sie.h" - "arch/arm/include/uapi/asm/kvm.h" "arch/arm64/include/uapi/asm/kvm.h" "arch/arm64/include/uapi/asm/unistd.h" "arch/alpha/include/uapi/asm/errno.h" From 57c8e9da3dfe606b918d8f193837ebf2213a9545 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 30 Jul 2025 19:11:12 +0300 Subject: [PATCH 1272/2711] clk: qcom: tcsrcc-x1e80100: Set the bi_tcxo as parent to eDP refclk All the other ref clocks provided by this driver have the bi_tcxo as parent. The eDP refclk is the only one without a parent, leading to reporting its rate as 0. So set its parent to bi_tcxo, just like the rest of the refclks. Cc: stable@vger.kernel.org # v6.9 Fixes: 06aff116199c ("clk: qcom: Add TCSR clock driver for x1e80100") Signed-off-by: Abel Vesa Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250730-clk-qcom-tcsrcc-x1e80100-parent-edp-refclk-v1-1-7a36ef06e045@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/tcsrcc-x1e80100.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/qcom/tcsrcc-x1e80100.c b/drivers/clk/qcom/tcsrcc-x1e80100.c index ff61769a0807..a367e1f55622 100644 --- a/drivers/clk/qcom/tcsrcc-x1e80100.c +++ b/drivers/clk/qcom/tcsrcc-x1e80100.c @@ -29,6 +29,10 @@ static struct clk_branch tcsr_edp_clkref_en = { .enable_mask = BIT(0), .hw.init = &(const struct clk_init_data) { .name = "tcsr_edp_clkref_en", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO_PAD, + }, + .num_parents = 1, .ops = &clk_branch2_ops, }, }, From 0a27bdb14b028fed30a10cec2f945c38cb5ca4fa Mon Sep 17 00:00:00 2001 From: Vernon Yang Date: Fri, 5 Sep 2025 02:25:27 +0800 Subject: [PATCH 1273/2711] PCI/AER: Fix NULL pointer access by aer_info The kzalloc(GFP_KERNEL) may return NULL, so all accesses to aer_info->xxx will result in kernel panic. Fix it. Signed-off-by: Vernon Yang Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250904182527.67371-1-vernon2gm@gmail.com --- drivers/pci/pcie/aer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 62c74b5f99ae..cd0f0b17f097 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -393,6 +393,10 @@ void pci_aer_init(struct pci_dev *dev) return; dev->aer_info = kzalloc(sizeof(*dev->aer_info), GFP_KERNEL); + if (!dev->aer_info) { + dev->aer_cap = 0; + return; + } ratelimit_state_init(&dev->aer_info->correctable_ratelimit, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); From 4ca6a89f38718d6cd84304e6a26e7ddc90e03356 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 10 Sep 2025 15:47:37 +0200 Subject: [PATCH 1274/2711] clk: qcom: gcc-sc8280xp: drop obsolete PCIe GDSC comment Drop an obsolete comment about keeping the PCIe GDSCs always-on, something which is no longer the case since commit db382dd55bcb ("clk: qcom: gcc-sc8280xp: Allow PCIe GDSCs to enter retention state"). Signed-off-by: Johan Hovold Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20250910134737.19381-1-johan+linaro@kernel.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-sc8280xp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/clk/qcom/gcc-sc8280xp.c b/drivers/clk/qcom/gcc-sc8280xp.c index f27d0003f427..b683795475e3 100644 --- a/drivers/clk/qcom/gcc-sc8280xp.c +++ b/drivers/clk/qcom/gcc-sc8280xp.c @@ -6775,10 +6775,6 @@ static struct gdsc pcie_1_tunnel_gdsc = { .flags = VOTABLE | RETAIN_FF_ENABLE, }; -/* - * The Qualcomm PCIe driver does not yet implement suspend so to keep the - * PCIe power domains always-on for now. - */ static struct gdsc pcie_2a_gdsc = { .gdscr = 0x9d004, .collapse_ctrl = 0x52128, From 00f2bf97544cdc7e5b166d19f896f5eaa2bb02ae Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 29 Aug 2025 11:15:45 +0300 Subject: [PATCH 1275/2711] MAINTAINERS: Update Michael Jamet's maintainer entries Michael Jamet is about to continue his professional journey outside of Intel and is stepping down as maintainer of Thunderbolt/USB4 subsystem, and the networking driver. Move him from MAINTAINERS to CREDITS. Thank you, Michael! Cc: Michael Jamet Signed-off-by: Mika Westerberg --- CREDITS | 5 +++++ MAINTAINERS | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CREDITS b/CREDITS index a357f9cbb05d..31ef5c80f0ce 100644 --- a/CREDITS +++ b/CREDITS @@ -1890,6 +1890,11 @@ S: Reading S: RG6 2NU S: United Kingdom +N: Michael Jamet +E: michael.jamet@intel.com +D: Thunderbolt/USB4 driver maintainer +D: Thunderbolt/USB4 networking driver maintainer + N: Dave Jeffery E: dhjeffery@gmail.com D: SCSI hacks and IBM ServeRAID RAID driver maintenance diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..bf0ef08ac6b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25091,7 +25091,6 @@ F: drivers/thunderbolt/dma_test.c THUNDERBOLT DRIVER M: Andreas Noever -M: Michael Jamet M: Mika Westerberg M: Yehezkel Bernat L: linux-usb@vger.kernel.org @@ -25102,7 +25101,6 @@ F: drivers/thunderbolt/ F: include/linux/thunderbolt.h THUNDERBOLT NETWORK DRIVER -M: Michael Jamet M: Mika Westerberg M: Yehezkel Bernat L: netdev@vger.kernel.org From cc55fc58fc1b7f405003fd2ecf79e74653461f0b Mon Sep 17 00:00:00 2001 From: Yuan CHen Date: Mon, 8 Sep 2025 02:28:10 +0100 Subject: [PATCH 1276/2711] clk: renesas: cpg-mssr: Fix memory leak in cpg_mssr_reserved_init() In case of krealloc_array() failure, the current error handling just returns from the function without freeing the original array. Fix this memory leak by freeing the original array. Fixes: 6aa1754764901668 ("clk: renesas: cpg-mssr: Ignore all clocks assigned to non-Linux system") Signed-off-by: Yuan CHen Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250908012810.4767-1-chenyuan_fl@163.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/renesas-cpg-mssr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 5ff6ee1f7d4b..de1cf7ba45b7 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -1082,6 +1082,7 @@ static int __init cpg_mssr_reserved_init(struct cpg_mssr_priv *priv, of_for_each_phandle(&it, rc, node, "clocks", "#clock-cells", -1) { int idx; + unsigned int *new_ids; if (it.node != priv->np) continue; @@ -1092,11 +1093,13 @@ static int __init cpg_mssr_reserved_init(struct cpg_mssr_priv *priv, if (args[0] != CPG_MOD) continue; - ids = krealloc_array(ids, (num + 1), sizeof(*ids), GFP_KERNEL); - if (!ids) { + new_ids = krealloc_array(ids, (num + 1), sizeof(*ids), GFP_KERNEL); + if (!new_ids) { of_node_put(it.node); + kfree(ids); return -ENOMEM; } + ids = new_ids; if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) idx = MOD_CLK_PACK_10(args[1]); /* for DEF_MOD_STB() */ From 82e0aa95ec8cec76bec23146ad8effb5a09e6e92 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 9 Sep 2025 19:07:47 +0100 Subject: [PATCH 1277/2711] clk: renesas: r9a09g047: Add USB3.0 clocks/resets Add USB3.0 clock and reset entries. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250909180803.140939-3-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a09g047-cpg.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r9a09g047-cpg.c b/drivers/clk/renesas/r9a09g047-cpg.c index afd09b95fb74..ef115f9ec0e6 100644 --- a/drivers/clk/renesas/r9a09g047-cpg.c +++ b/drivers/clk/renesas/r9a09g047-cpg.c @@ -16,7 +16,7 @@ enum clk_ids { /* Core Clock Outputs exported to DT */ - LAST_DT_CORE_CLK = R9A09G047_GBETH_1_CLK_PTP_REF_I, + LAST_DT_CORE_CLK = R9A09G047_USB3_0_CLKCORE, /* External Input Clocks */ CLK_AUDIO_EXTAL, @@ -181,6 +181,8 @@ static const struct cpg_core_clk r9a09g047_core_clks[] __initconst = { CLK_PLLETH_DIV_125_FIX, 1, 1), DEF_FIXED("gbeth_1_clk_ptp_ref_i", R9A09G047_GBETH_1_CLK_PTP_REF_I, CLK_PLLETH_DIV_125_FIX, 1, 1), + DEF_FIXED("usb3_0_ref_alt_clk_p", R9A09G047_USB3_0_REF_ALT_CLK_P, CLK_QEXTAL, 1, 1), + DEF_FIXED("usb3_0_core_clk", R9A09G047_USB3_0_CLKCORE, CLK_QEXTAL, 1, 1), }; static const struct rzv2h_mod_clk r9a09g047_mod_clks[] __initconst = { @@ -276,6 +278,10 @@ static const struct rzv2h_mod_clk r9a09g047_mod_clks[] __initconst = { BUS_MSTOP(8, BIT(4))), DEF_MOD("sdhi_2_aclk", CLK_PLLDTY_ACPU_DIV4, 10, 14, 5, 14, BUS_MSTOP(8, BIT(4))), + DEF_MOD("usb3_0_aclk", CLK_PLLDTY_DIV8, 10, 15, 5, 15, + BUS_MSTOP(7, BIT(12))), + DEF_MOD("usb3_0_pclk_usbtst", CLK_PLLDTY_ACPU_DIV4, 11, 0, 5, 16, + BUS_MSTOP(7, BIT(14))), DEF_MOD_MUX_EXTERNAL("gbeth_0_clk_tx_i", CLK_SMUX2_GBE0_TXCLK, 11, 8, 5, 24, BUS_MSTOP(8, BIT(5)), 1), DEF_MOD_MUX_EXTERNAL("gbeth_0_clk_rx_i", CLK_SMUX2_GBE0_RXCLK, 11, 9, 5, 25, @@ -352,6 +358,7 @@ static const struct rzv2h_reset r9a09g047_resets[] __initconst = { DEF_RST(10, 7, 4, 24), /* SDHI_0_IXRST */ DEF_RST(10, 8, 4, 25), /* SDHI_1_IXRST */ DEF_RST(10, 9, 4, 26), /* SDHI_2_IXRST */ + DEF_RST(10, 10, 4, 27), /* USB3_0_ARESETN */ DEF_RST(11, 0, 5, 1), /* GBETH_0_ARESETN_I */ DEF_RST(11, 1, 5, 2), /* GBETH_1_ARESETN_I */ DEF_RST(12, 5, 5, 22), /* CRU_0_PRESETN */ From b5788b96cba97da01e1f0e1316133427c1102ff6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 11 Sep 2025 17:57:58 +0200 Subject: [PATCH 1278/2711] clk: renesas: r9a09g05[67]: Reduce differences The clock drivers for RZ/V2H and RZ/V2N are very similar. Reduce the differences between them by: - Moving and reformatting the PLLCM33_GEAR clock definitions, - Replacing spaces by TABs. Signed-off-by: Geert Uytterhoeven Link: https://patch.msgid.link/2246d2263e8a24d1aaf653db2004cbf2263c9048.1757606097.git.geert+renesas@glider.be --- drivers/clk/renesas/r9a09g056-cpg.c | 8 ++++---- drivers/clk/renesas/r9a09g057-cpg.c | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/clk/renesas/r9a09g056-cpg.c b/drivers/clk/renesas/r9a09g056-cpg.c index f0a8c5073fa6..55f056359dd7 100644 --- a/drivers/clk/renesas/r9a09g056-cpg.c +++ b/drivers/clk/renesas/r9a09g056-cpg.c @@ -36,10 +36,10 @@ enum clk_ids { CLK_PLLCM33_DIV4, CLK_PLLCM33_DIV5, CLK_PLLCM33_DIV16, + CLK_PLLCM33_GEAR, CLK_SMUX2_XSPI_CLK0, CLK_SMUX2_XSPI_CLK1, CLK_PLLCM33_XSPI, - CLK_PLLCM33_GEAR, CLK_PLLCLN_DIV2, CLK_PLLCLN_DIV8, CLK_PLLCLN_DIV16, @@ -120,11 +120,11 @@ static const struct cpg_core_clk r9a09g056_core_clks[] __initconst = { DEF_FIXED(".pllcm33_div4", CLK_PLLCM33_DIV4, CLK_PLLCM33, 1, 4), DEF_FIXED(".pllcm33_div5", CLK_PLLCM33_DIV5, CLK_PLLCM33, 1, 5), DEF_FIXED(".pllcm33_div16", CLK_PLLCM33_DIV16, CLK_PLLCM33, 1, 16), + DEF_DDIV(".pllcm33_gear", CLK_PLLCM33_GEAR, CLK_PLLCM33_DIV4, CDDIV0_DIVCTL1, dtable_2_64), DEF_SMUX(".smux2_xspi_clk0", CLK_SMUX2_XSPI_CLK0, SSEL1_SELCTL2, smux2_xspi_clk0), DEF_SMUX(".smux2_xspi_clk1", CLK_SMUX2_XSPI_CLK1, SSEL1_SELCTL3, smux2_xspi_clk1), DEF_CSDIV(".pllcm33_xspi", CLK_PLLCM33_XSPI, CLK_SMUX2_XSPI_CLK1, CSDIV0_DIVCTL3, dtable_2_16), - DEF_DDIV(".pllcm33_gear", CLK_PLLCM33_GEAR, CLK_PLLCM33_DIV4, CDDIV0_DIVCTL1, dtable_2_64), DEF_FIXED(".pllcln_div2", CLK_PLLCLN_DIV2, CLK_PLLCLN, 1, 2), DEF_FIXED(".pllcln_div8", CLK_PLLCLN_DIV8, CLK_PLLCLN, 1, 8), @@ -325,8 +325,8 @@ static const struct rzv2h_reset r9a09g056_resets[] __initconst = { DEF_RST(9, 14, 4, 15), /* RIIC_6_MRST */ DEF_RST(9, 15, 4, 16), /* RIIC_7_MRST */ DEF_RST(10, 0, 4, 17), /* RIIC_8_MRST */ - DEF_RST(10, 3, 4, 20), /* SPI_HRESETN */ - DEF_RST(10, 4, 4, 21), /* SPI_ARESETN */ + DEF_RST(10, 3, 4, 20), /* SPI_HRESETN */ + DEF_RST(10, 4, 4, 21), /* SPI_ARESETN */ DEF_RST(10, 7, 4, 24), /* SDHI_0_IXRST */ DEF_RST(10, 8, 4, 25), /* SDHI_1_IXRST */ DEF_RST(10, 9, 4, 26), /* SDHI_2_IXRST */ diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c index c2b5d04ed92e..6389c4b6a523 100644 --- a/drivers/clk/renesas/r9a09g057-cpg.c +++ b/drivers/clk/renesas/r9a09g057-cpg.c @@ -134,9 +134,8 @@ static const struct cpg_core_clk r9a09g057_core_clks[] __initconst = { DEF_FIXED(".pllcm33_div3", CLK_PLLCM33_DIV3, CLK_PLLCM33, 1, 3), DEF_FIXED(".pllcm33_div4", CLK_PLLCM33_DIV4, CLK_PLLCM33, 1, 4), DEF_FIXED(".pllcm33_div5", CLK_PLLCM33_DIV5, CLK_PLLCM33, 1, 5), - DEF_DDIV(".pllcm33_gear", CLK_PLLCM33_GEAR, - CLK_PLLCM33_DIV4, CDDIV0_DIVCTL1, dtable_2_64), DEF_FIXED(".pllcm33_div16", CLK_PLLCM33_DIV16, CLK_PLLCM33, 1, 16), + DEF_DDIV(".pllcm33_gear", CLK_PLLCM33_GEAR, CLK_PLLCM33_DIV4, CDDIV0_DIVCTL1, dtable_2_64), DEF_SMUX(".smux2_xspi_clk0", CLK_SMUX2_XSPI_CLK0, SSEL1_SELCTL2, smux2_xspi_clk0), DEF_SMUX(".smux2_xspi_clk1", CLK_SMUX2_XSPI_CLK1, SSEL1_SELCTL3, smux2_xspi_clk1), DEF_CSDIV(".pllcm33_xspi", CLK_PLLCM33_XSPI, CLK_SMUX2_XSPI_CLK1, CSDIV0_DIVCTL3, From c662a6fef10aff3b13befc499335a334205316d5 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader Date: Thu, 4 Sep 2025 21:25:25 +0200 Subject: [PATCH 1279/2711] mips: math-emu: replace deprecated strcpy() in me-debugfs use strscpy() instead of deprecated strcpy(). Signed-off-by: Osama Abdelkader Signed-off-by: Thomas Bogendoerfer --- arch/mips/math-emu/me-debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c index d5ad76b2bb67..aeddf7aecfc5 100644 --- a/arch/mips/math-emu/me-debugfs.c +++ b/arch/mips/math-emu/me-debugfs.c @@ -37,11 +37,11 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n"); * used in debugfs item names to be clearly associated to corresponding * MIPS FPU instructions. */ -static void adjust_instruction_counter_name(char *out_name, char *in_name) +static void adjust_instruction_counter_name(char *out_name, char *in_name, size_t len) { int i = 0; - strcpy(out_name, in_name); + strscpy(out_name, in_name, len); while (in_name[i] != '\0') { if (out_name[i] == '_') out_name[i] = '.'; @@ -226,7 +226,7 @@ do { \ #define FPU_STAT_CREATE_EX(m) \ do { \ - adjust_instruction_counter_name(name, #m); \ + adjust_instruction_counter_name(name, #m, sizeof(name)); \ \ debugfs_create_file(name, 0444, fpuemu_debugfs_inst_dir, \ (void *)FPU_EMU_STAT_OFFSET(m), \ From d5411ed6cabd376468f76584b1fe75235325966c Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Fri, 12 Sep 2025 10:29:16 +0530 Subject: [PATCH 1280/2711] bus: mhi: host: Notify EE change via uevent Notify the MHI device's Execution Environment (EE) state via uevent, enabling applications to receive real-time updates and take appropriate actions based on the current state of MHI. Signed-off-by: Vivek Pernamitta [mani: Reworded subject, removed error print, fixed indentation] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250912-b4-uevent_vdev_next-20250911-v2-1-89440407bf7e@quicinc.com --- drivers/bus/mhi/host/internal.h | 1 + drivers/bus/mhi/host/main.c | 1 + drivers/bus/mhi/host/pm.c | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h index 034be33565b7..d455f0bf0013 100644 --- a/drivers/bus/mhi/host/internal.h +++ b/drivers/bus/mhi/host/internal.h @@ -403,6 +403,7 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, struct mhi_event *mhi_event, u32 event_quota); int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, struct mhi_event *mhi_event, u32 event_quota); +void mhi_uevent_notify(struct mhi_controller *mhi_cntrl, enum mhi_ee_type ee); /* ISR handlers */ irqreturn_t mhi_irq_handler(int irq_number, void *dev); diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c index 52bef663e182..861551274319 100644 --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c @@ -512,6 +512,7 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) if (mhi_cntrl->rddm_image && mhi_is_active(mhi_cntrl)) { mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_RDDM); mhi_cntrl->ee = ee; + mhi_uevent_notify(mhi_cntrl, mhi_cntrl->ee); wake_up_all(&mhi_cntrl->state_event); } break; diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c index 33d92bf2fc3e..9a5ca903d758 100644 --- a/drivers/bus/mhi/host/pm.c +++ b/drivers/bus/mhi/host/pm.c @@ -418,6 +418,7 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) device_for_each_child(&mhi_cntrl->mhi_dev->dev, ¤t_ee, mhi_destroy_device); mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_MISSION_MODE); + mhi_uevent_notify(mhi_cntrl, mhi_cntrl->ee); /* Force MHI to be in M0 state before continuing */ ret = __mhi_device_get_sync(mhi_cntrl); @@ -631,6 +632,8 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) /* Wake up threads waiting for state transition */ wake_up_all(&mhi_cntrl->state_event); + mhi_uevent_notify(mhi_cntrl, mhi_cntrl->ee); + if (MHI_REG_ACCESS_VALID(prev_state)) { /* * If the device is in PBL or SBL, it will only respond to @@ -829,6 +832,8 @@ void mhi_pm_st_worker(struct work_struct *work) mhi_create_devices(mhi_cntrl); if (mhi_cntrl->fbc_download) mhi_download_amss_image(mhi_cntrl); + + mhi_uevent_notify(mhi_cntrl, mhi_cntrl->ee); break; case DEV_ST_TRANSITION_MISSION_MODE: mhi_pm_mission_mode_transition(mhi_cntrl); @@ -838,6 +843,7 @@ void mhi_pm_st_worker(struct work_struct *work) mhi_cntrl->ee = MHI_EE_FP; write_unlock_irq(&mhi_cntrl->pm_lock); mhi_create_devices(mhi_cntrl); + mhi_uevent_notify(mhi_cntrl, mhi_cntrl->ee); break; case DEV_ST_TRANSITION_READY: mhi_ready_state_transition(mhi_cntrl); @@ -1240,6 +1246,8 @@ static void __mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful, write_unlock_irq(&mhi_cntrl->pm_lock); mutex_unlock(&mhi_cntrl->pm_mutex); + mhi_uevent_notify(mhi_cntrl, mhi_cntrl->ee); + if (destroy_device) mhi_queue_state_transition(mhi_cntrl, DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE); @@ -1338,3 +1346,22 @@ void mhi_device_put(struct mhi_device *mhi_dev) read_unlock_bh(&mhi_cntrl->pm_lock); } EXPORT_SYMBOL_GPL(mhi_device_put); + +void mhi_uevent_notify(struct mhi_controller *mhi_cntrl, enum mhi_ee_type ee) +{ + struct device *dev = &mhi_cntrl->mhi_dev->dev; + char *buf[2]; + int ret; + + buf[0] = kasprintf(GFP_KERNEL, "EXEC_ENV=%s", TO_MHI_EXEC_STR(ee)); + buf[1] = NULL; + + if (!buf[0]) + return; + + ret = kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, buf); + if (ret) + dev_err(dev, "Failed to send %s uevent\n", TO_MHI_EXEC_STR(ee)); + + kfree(buf[0]); +} From f5225a34bd8f9f64eec37f6ae1461289aaa3eb86 Mon Sep 17 00:00:00 2001 From: Sumit Kumar Date: Wed, 10 Sep 2025 18:11:09 +0530 Subject: [PATCH 1281/2711] bus: mhi: ep: Fix chained transfer handling in read path The mhi_ep_read_channel function incorrectly assumes the End of Transfer (EOT) bit is present for each packet in a chained transactions, causing it to advance mhi_chan->rd_offset beyond wr_offset during host-to-device transfers when EOT has not yet arrived. This leads to access of unmapped host memory, causing IOMMU faults and processing of stale TREs. Modify the loop condition to ensure mhi_queue is not empty, allowing the function to process only valid TREs up to the current write pointer to prevent premature reads and ensure safe traversal of chained TREs. Due to this change, buf_left needs to be removed from the while loop condition to avoid exiting prematurely before reading the ring completely, and also remove write_offset since it will always be zero because the new cache buffer is allocated every time. Fixes: 5301258899773 ("bus: mhi: ep: Add support for reading from the host") Co-developed-by: Akhil Vinod Signed-off-by: Akhil Vinod Signed-off-by: Sumit Kumar [mani: reworded description slightly] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Krishna Chaitanya Chundru Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250910-final_chained-v3-1-ec77c9d88ace@oss.qualcomm.com --- drivers/bus/mhi/ep/main.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c index b3eafcf2a2c5..cdea24e92919 100644 --- a/drivers/bus/mhi/ep/main.c +++ b/drivers/bus/mhi/ep/main.c @@ -403,17 +403,13 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl, { struct mhi_ep_chan *mhi_chan = &mhi_cntrl->mhi_chan[ring->ch_id]; struct device *dev = &mhi_cntrl->mhi_dev->dev; - size_t tr_len, read_offset, write_offset; + size_t tr_len, read_offset; struct mhi_ep_buf_info buf_info = {}; u32 len = MHI_EP_DEFAULT_MTU; struct mhi_ring_element *el; - bool tr_done = false; void *buf_addr; - u32 buf_left; int ret; - buf_left = len; - do { /* Don't process the transfer ring if the channel is not in RUNNING state */ if (mhi_chan->state != MHI_CH_STATE_RUNNING) { @@ -426,24 +422,23 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl, /* Check if there is data pending to be read from previous read operation */ if (mhi_chan->tre_bytes_left) { dev_dbg(dev, "TRE bytes remaining: %u\n", mhi_chan->tre_bytes_left); - tr_len = min(buf_left, mhi_chan->tre_bytes_left); + tr_len = min(len, mhi_chan->tre_bytes_left); } else { mhi_chan->tre_loc = MHI_TRE_DATA_GET_PTR(el); mhi_chan->tre_size = MHI_TRE_DATA_GET_LEN(el); mhi_chan->tre_bytes_left = mhi_chan->tre_size; - tr_len = min(buf_left, mhi_chan->tre_size); + tr_len = min(len, mhi_chan->tre_size); } read_offset = mhi_chan->tre_size - mhi_chan->tre_bytes_left; - write_offset = len - buf_left; buf_addr = kmem_cache_zalloc(mhi_cntrl->tre_buf_cache, GFP_KERNEL); if (!buf_addr) return -ENOMEM; buf_info.host_addr = mhi_chan->tre_loc + read_offset; - buf_info.dev_addr = buf_addr + write_offset; + buf_info.dev_addr = buf_addr; buf_info.size = tr_len; buf_info.cb = mhi_ep_read_completion; buf_info.cb_buf = buf_addr; @@ -459,16 +454,12 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl, goto err_free_buf_addr; } - buf_left -= tr_len; mhi_chan->tre_bytes_left -= tr_len; - if (!mhi_chan->tre_bytes_left) { - if (MHI_TRE_DATA_GET_IEOT(el)) - tr_done = true; - + if (!mhi_chan->tre_bytes_left) mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size; - } - } while (buf_left && !tr_done); + /* Read until the some buffer is left or the ring becomes not empty */ + } while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE)); return 0; @@ -502,15 +493,11 @@ static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring) mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); } else { /* UL channel */ - do { - ret = mhi_ep_read_channel(mhi_cntrl, ring); - if (ret < 0) { - dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n"); - return ret; - } - - /* Read until the ring becomes empty */ - } while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE)); + ret = mhi_ep_read_channel(mhi_cntrl, ring); + if (ret < 0) { + dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n"); + return ret; + } } return 0; From 2d1a7eb029f7d7a6e55f0ac6c7264f4bbd2f5510 Mon Sep 17 00:00:00 2001 From: Zhang Enpei Date: Thu, 7 Aug 2025 14:18:33 +0800 Subject: [PATCH 1282/2711] interconnect: core: Use device_match_of_node() Make use of device_match_of_node() instead of open coding its functionality. Signed-off-by: Zhang Enpei Link: https://lore.kernel.org/r/20250807141833927wb2idY1sZi1OpUKkrXk44@zte.com.cn Signed-off-by: Georgi Djakov --- drivers/interconnect/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c index 3ebf37ddfc18..6cc979b26151 100644 --- a/drivers/interconnect/core.c +++ b/drivers/interconnect/core.c @@ -385,7 +385,7 @@ struct icc_node_data *of_icc_get_from_provider(const struct of_phandle_args *spe mutex_lock(&icc_lock); list_for_each_entry(provider, &icc_providers, provider_list) { - if (provider->dev->of_node == spec->np) { + if (device_match_of_node(provider->dev, spec->np)) { if (provider->xlate_extended) { data = provider->xlate_extended(spec, provider->data); if (!IS_ERR(data)) { From 273532a0da09638d0e981df3d012199e2af38447 Mon Sep 17 00:00:00 2001 From: Raviteja Laggyshetty Date: Tue, 19 Aug 2025 11:24:46 +0000 Subject: [PATCH 1283/2711] dt-bindings: interconnect: Add OSM L3 compatible for QCS615 SoC Add Operation State Manager (OSM) L3 interconnect provider binding for QCS615 SoC. As the OSM hardware in QCS615 and SM8150 are same, added a family-level compatible for SM8150 SoC. Signed-off-by: Raviteja Laggyshetty Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250819-talos-l3-icc-v3-1-04529e85dac7@oss.qualcomm.com Signed-off-by: Georgi Djakov --- .../devicetree/bindings/interconnect/qcom,osm-l3.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml b/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml index ab5a921c3495..4b9b98fbe8f2 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml @@ -41,6 +41,11 @@ properties: - qcom,qcs8300-epss-l3 - const: qcom,sa8775p-epss-l3 - const: qcom,epss-l3 + - items: + - enum: + - qcom,qcs615-osm-l3 + - const: qcom,sm8150-osm-l3 + - const: qcom,osm-l3 reg: maxItems: 1 From a5d2edb2c9fa48382aec1673c709c2919899527c Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Wed, 10 Sep 2025 18:50:42 +0800 Subject: [PATCH 1284/2711] usb: typec: tcpci: add wakeup support Add wakeup support for tcpci. If the user enables the wakeup file, call enable_irq_wake() during system suspend and disable_irq_wake() during system resume. Since this driver supports shared interrupts, mask the chip interrupt by default when wakeup is disabled to avoid affecting other IRQ users. Reviewed-by: Frank Li Reviewed-by: Badhri Jagan Sridharan Signed-off-by: Xu Yang Link: https://lore.kernel.org/r/20250910105042.695146-1-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpci.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index a56e31b20c21..2a951c585e92 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -949,6 +949,8 @@ static int tcpci_probe(struct i2c_client *client) if (err < 0) goto unregister_port; + device_set_wakeup_capable(chip->tcpci->dev, true); + return 0; unregister_port: @@ -969,6 +971,36 @@ static void tcpci_remove(struct i2c_client *client) tcpci_unregister_port(chip->tcpci); } +static int tcpci_suspend(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + struct tcpci_chip *chip = i2c_get_clientdata(i2c); + int ret; + + if (device_may_wakeup(dev)) + ret = enable_irq_wake(i2c->irq); + else + ret = tcpci_write16(chip->tcpci, TCPC_ALERT_MASK, 0); + + return ret; +} + +static int tcpci_resume(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + struct tcpci_chip *chip = i2c_get_clientdata(i2c); + int ret; + + if (device_may_wakeup(dev)) + ret = disable_irq_wake(i2c->irq); + else + ret = tcpci_write16(chip->tcpci, TCPC_ALERT_MASK, chip->tcpci->alert_mask); + + return ret; +} + +DEFINE_SIMPLE_DEV_PM_OPS(tcpci_pm_ops, tcpci_suspend, tcpci_resume); + static const struct i2c_device_id tcpci_id[] = { { "tcpci" }, { } @@ -987,6 +1019,7 @@ MODULE_DEVICE_TABLE(of, tcpci_of_match); static struct i2c_driver tcpci_i2c_driver = { .driver = { .name = "tcpci", + .pm = pm_sleep_ptr(&tcpci_pm_ops), .of_match_table = of_match_ptr(tcpci_of_match), }, .probe = tcpci_probe, From e77ee1d2a8fa0f3179d4ac7b7d35b555da6a8cea Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Wed, 10 Sep 2025 18:07:30 +0200 Subject: [PATCH 1285/2711] usb: dwc2: Add support for 'maximum-speed' property The DWC2 IP can be properly integrated in a SoC to work at high-speed USB speed but some board issues, EMC constraints or any other reasons can lead to the need to limit this USB speed at board level. The device-tree 'maximum-speed' property already exists for this purpose but is not handled by the DWC2 driver. Fill this lack adding support for 'maximum-speed' property and so allow to limit the USB speed in device-tree (board description). Signed-off-by: Herve Codina Link: https://lore.kernel.org/r/20250910160730.585303-1-herve.codina@bootlin.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/params.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index ea6bd537e337..091bfcfef753 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -1029,11 +1029,33 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) return 0; } +static int dwc2_limit_speed(struct dwc2_hsotg *hsotg) +{ + enum usb_device_speed usb_speed; + + usb_speed = usb_get_maximum_speed(hsotg->dev); + switch (usb_speed) { + case USB_SPEED_LOW: + dev_err(hsotg->dev, "Maximum speed cannot be forced to low-speed\n"); + return -EINVAL; + case USB_SPEED_FULL: + if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW) + break; + hsotg->params.speed = DWC2_SPEED_PARAM_FULL; + break; + default: + break; + } + + return 0; +} + typedef void (*set_params_cb)(struct dwc2_hsotg *data); int dwc2_init_params(struct dwc2_hsotg *hsotg) { set_params_cb set_params; + int ret; dwc2_set_default_params(hsotg); dwc2_get_device_properties(hsotg); @@ -1051,6 +1073,10 @@ int dwc2_init_params(struct dwc2_hsotg *hsotg) } } + ret = dwc2_limit_speed(hsotg); + if (ret) + return ret; + dwc2_check_params(hsotg); return 0; From 7bf1158514e410310aec975e630cec99d4e4092f Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Mon, 18 Aug 2025 16:27:19 +0800 Subject: [PATCH 1286/2711] usb: udc: Add trace event for usb_gadget_set_state While the userspace program can be notified of gadget state changes, timing issue can lead to missed transitions when reading the state value. Introduce a trace event for usb_gadget_set_state to reliably track state transitions. Signed-off-by: Kuen-Han Tsai Link: https://lore.kernel.org/r/20250818082722.2952867-1-khtsai@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/core.c | 1 + drivers/usb/gadget/udc/trace.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index d709e24c1fd4..e28fea614496 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1125,6 +1125,7 @@ void usb_gadget_set_state(struct usb_gadget *gadget, { gadget->state = state; schedule_work(&gadget->work); + trace_usb_gadget_set_state(gadget, 0); } EXPORT_SYMBOL_GPL(usb_gadget_set_state); diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h index 4e334298b0e8..fa3e6ddf0a12 100644 --- a/drivers/usb/gadget/udc/trace.h +++ b/drivers/usb/gadget/udc/trace.h @@ -81,6 +81,11 @@ DECLARE_EVENT_CLASS(udc_log_gadget, __entry->ret) ); +DEFINE_EVENT(udc_log_gadget, usb_gadget_set_state, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + DEFINE_EVENT(udc_log_gadget, usb_gadget_frame_number, TP_PROTO(struct usb_gadget *g, int ret), TP_ARGS(g, ret) From 5df186e2ef11dca3fb6f0f332dc09c4ac0bed870 Mon Sep 17 00:00:00 2001 From: Haotien Hsu Date: Mon, 11 Aug 2025 15:45:58 +0800 Subject: [PATCH 1287/2711] usb: xhci: tegra: Support USB wakeup function for Tegra234 When the system is suspended, USB hot-plugging/unplugging can trigger wake events of the Tegra USB host controller. Enable support for USB wake-up events by parsing device-tree to see if the interrupts for the wake-up events are present and if so configure those interrupts. Note that if wake-up events are not present, still allow the USB host controller to probe as normal. Signed-off-by: Haotien Hsu Link: https://lore.kernel.org/r/20250811074558.1062048-5-haotienh@nvidia.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 82 ++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 460effa0e11e..5255b1002893 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -155,6 +155,8 @@ #define FW_IOCTL_TYPE_SHIFT 24 #define FW_IOCTL_CFGTBL_READ 17 +#define WAKE_IRQ_START_INDEX 2 + struct tegra_xusb_fw_header { __le32 boot_loadaddr_in_imem; __le32 boot_codedfi_offset; @@ -228,6 +230,7 @@ struct tegra_xusb_soc { unsigned int num_supplies; const struct tegra_xusb_phy_type *phy_types; unsigned int num_types; + unsigned int max_num_wakes; const struct tegra_xusb_context_soc *context; struct { @@ -263,6 +266,7 @@ struct tegra_xusb { int xhci_irq; int mbox_irq; int padctl_irq; + int *wake_irqs; void __iomem *ipfs_base; void __iomem *fpci_base; @@ -313,6 +317,7 @@ struct tegra_xusb { bool suspended; struct tegra_xusb_context context; u8 lp0_utmi_pad_mask; + int num_wakes; }; static struct hc_driver __read_mostly tegra_xhci_hc_driver; @@ -1537,6 +1542,58 @@ static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra) otg_set_host(tegra->usbphy[i]->otg, NULL); } +static int tegra_xusb_setup_wakeup(struct platform_device *pdev, struct tegra_xusb *tegra) +{ + unsigned int i; + + if (tegra->soc->max_num_wakes == 0) + return 0; + + tegra->wake_irqs = devm_kcalloc(tegra->dev, + tegra->soc->max_num_wakes, + sizeof(*tegra->wake_irqs), GFP_KERNEL); + if (!tegra->wake_irqs) + return -ENOMEM; + + /* + * USB wake events are independent of each other, so it is not necessary for a platform + * to utilize all wake-up events supported for a given device. The USB host can operate + * even if wake-up events are not defined or fail to be configured. Therefore, we only + * return critical errors, such as -ENOMEM. + */ + for (i = 0; i < tegra->soc->max_num_wakes; i++) { + struct irq_data *data; + + tegra->wake_irqs[i] = platform_get_irq(pdev, i + WAKE_IRQ_START_INDEX); + if (tegra->wake_irqs[i] < 0) + break; + + data = irq_get_irq_data(tegra->wake_irqs[i]); + if (!data) { + dev_warn(tegra->dev, "get wake event %d irq data fail\n", i); + irq_dispose_mapping(tegra->wake_irqs[i]); + break; + } + + irq_set_irq_type(tegra->wake_irqs[i], irqd_get_trigger_type(data)); + } + + tegra->num_wakes = i; + dev_dbg(tegra->dev, "setup %d wake events\n", tegra->num_wakes); + + return 0; +} + +static void tegra_xusb_dispose_wake(struct tegra_xusb *tegra) +{ + unsigned int i; + + for (i = 0; i < tegra->num_wakes; i++) + irq_dispose_mapping(tegra->wake_irqs[i]); + + tegra->num_wakes = 0; +} + static int tegra_xusb_probe(struct platform_device *pdev) { struct tegra_xusb *tegra; @@ -1587,9 +1644,15 @@ static int tegra_xusb_probe(struct platform_device *pdev) if (tegra->mbox_irq < 0) return tegra->mbox_irq; + err = tegra_xusb_setup_wakeup(pdev, tegra); + if (err) + return err; + tegra->padctl = tegra_xusb_padctl_get(&pdev->dev); - if (IS_ERR(tegra->padctl)) - return PTR_ERR(tegra->padctl); + if (IS_ERR(tegra->padctl)) { + err = PTR_ERR(tegra->padctl); + goto dispose_wake; + } np = of_parse_phandle(pdev->dev.of_node, "nvidia,xusb-padctl", 0); if (!np) { @@ -1913,6 +1976,8 @@ put_powerdomains: put_padctl: of_node_put(np); tegra_xusb_padctl_put(tegra->padctl); +dispose_wake: + tegra_xusb_dispose_wake(tegra); return err; } @@ -1945,6 +2010,8 @@ static void tegra_xusb_remove(struct platform_device *pdev) if (tegra->padctl_irq) pm_runtime_disable(&pdev->dev); + tegra_xusb_dispose_wake(tegra); + pm_runtime_put(&pdev->dev); tegra_xusb_disable(tegra); @@ -2355,8 +2422,13 @@ out: pm_runtime_disable(dev); if (device_may_wakeup(dev)) { + unsigned int i; + if (enable_irq_wake(tegra->padctl_irq)) dev_err(dev, "failed to enable padctl wakes\n"); + + for (i = 0; i < tegra->num_wakes; i++) + enable_irq_wake(tegra->wake_irqs[i]); } } @@ -2384,8 +2456,13 @@ static __maybe_unused int tegra_xusb_resume(struct device *dev) } if (device_may_wakeup(dev)) { + unsigned int i; + if (disable_irq_wake(tegra->padctl_irq)) dev_err(dev, "failed to disable padctl wakes\n"); + + for (i = 0; i < tegra->num_wakes; i++) + disable_irq_wake(tegra->wake_irqs[i]); } tegra->suspended = false; mutex_unlock(&tegra->lock); @@ -2636,6 +2713,7 @@ static const struct tegra_xusb_soc tegra234_soc = { .num_supplies = ARRAY_SIZE(tegra194_supply_names), .phy_types = tegra194_phy_types, .num_types = ARRAY_SIZE(tegra194_phy_types), + .max_num_wakes = 7, .context = &tegra186_xusb_context, .ports = { .usb3 = { .offset = 0, .count = 4, }, From 643df901f7ead35a71552a61927ad665a15aa87f Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sun, 7 Sep 2025 23:44:11 +0530 Subject: [PATCH 1288/2711] usb: dwc3: core: Introduce glue callbacks for flattened implementations In certain situations like role switching, the glue layers need to be informed of these events, so that they can take any necessary action. But in non-flattened implementations, the glue drivers have no data on when the core driver probe was successful post invoking of_platform_ populate. Now that the core driver supports flattened implementations as well, introduce vendor callbacks that can be passed on from glue to core before invoking dwc3_core_probe. Introduce callbacks to notify glue layer of role_switch and run_stop changes. These can be used by flattened implementation of Qualcomm glue layer to generate connect/disconnect events in controller during cable connect and run stop modifications by udc in device mode. Acked-by: Thinh Nguyen Signed-off-by: Krishna Kurapati Link: https://lore.kernel.org/r/20250907181412.2174616-2-krishna.kurapati@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 1 + drivers/usb/dwc3/core.h | 26 ++++++++++++++++++++++++++ drivers/usb/dwc3/drd.c | 1 + drivers/usb/dwc3/gadget.c | 1 + 4 files changed, 29 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 370fc524a468..ae140c356295 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -2352,6 +2352,7 @@ static int dwc3_probe(struct platform_device *pdev) return -ENOMEM; dwc->dev = &pdev->dev; + dwc->glue_ops = NULL; probe_data.dwc = dwc; probe_data.res = res; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index d5b985fa12f4..a5fc92c4ffa3 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -992,6 +992,17 @@ struct dwc3_scratchpad_array { __le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS]; }; +/** + * struct dwc3_glue_ops - The ops indicate the notifications that + * need to be passed on to glue layer + * @pre_set_role: Notify glue of role switch notifications + * @pre_run_stop: Notify run stop enable/disable information to glue + */ +struct dwc3_glue_ops { + void (*pre_set_role)(struct dwc3 *dwc, enum usb_role role); + void (*pre_run_stop)(struct dwc3 *dwc, bool is_on); +}; + /** * struct dwc3 - representation of our controller * @drd_work: workqueue used for role swapping @@ -1012,6 +1023,7 @@ struct dwc3_scratchpad_array { * @eps: endpoint array * @gadget: device side representation of the peripheral controller * @gadget_driver: pointer to the gadget driver + * @glue_ops: Vendor callbacks for flattened device implementations. * @bus_clk: clock for accessing the registers * @ref_clk: reference clock * @susp_clk: clock used when the SS phy is in low power (S3) state @@ -1197,6 +1209,8 @@ struct dwc3 { struct usb_gadget *gadget; struct usb_gadget_driver *gadget_driver; + const struct dwc3_glue_ops *glue_ops; + struct clk *bus_clk; struct clk *ref_clk; struct clk *susp_clk; @@ -1614,6 +1628,18 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc); int dwc3_core_soft_reset(struct dwc3 *dwc); void dwc3_enable_susphy(struct dwc3 *dwc, bool enable); +static inline void dwc3_pre_set_role(struct dwc3 *dwc, enum usb_role role) +{ + if (dwc->glue_ops && dwc->glue_ops->pre_set_role) + dwc->glue_ops->pre_set_role(dwc, role); +} + +static inline void dwc3_pre_run_stop(struct dwc3 *dwc, bool is_on) +{ + if (dwc->glue_ops && dwc->glue_ops->pre_run_stop) + dwc->glue_ops->pre_run_stop(dwc, is_on); +} + #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) int dwc3_host_init(struct dwc3 *dwc); void dwc3_host_exit(struct dwc3 *dwc); diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 7977860932b1..4c91240eb429 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -464,6 +464,7 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, break; } + dwc3_pre_set_role(dwc, role); dwc3_set_mode(dwc, mode); return 0; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 554f997eb8c4..6f18b4840a25 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2662,6 +2662,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) dwc->pullups_connected = false; } + dwc3_pre_run_stop(dwc, is_on); dwc3_gadget_dctl_write_safe(dwc, reg); do { From 21188e8d6d75900f35c2acc8baa5a6ed4aec5af7 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sun, 7 Sep 2025 23:44:12 +0530 Subject: [PATCH 1289/2711] usb: dwc3: qcom: Implement glue callbacks to facilitate runtime suspend On Qualcomm DWC3 dual-role controllers, the conndone/disconnect events in device mode are generated by controller when software writes to QSCRATCH registers in Qualcomm Glue layer rather than the vbus line being routed to dwc3 core IP for it to recognize and generate these events. UTMI_OTG_VBUS_VALID bit of QSCRATCH_HS_PHY_CTRL register needs to be set to generate a connection done event and to be cleared for the controller to generate a disconnect event during cable removal. When the disconnect is not generated upon cable removal, the "connected" flag of dwc3 is left marked as "true" and it blocks suspend routines and for that to happen upon cable removal, the cable disconnect notification coming in via set_role call need to be provided to the Qualcomm glue layer as well. Currently, the way DWC3 core and Qualcomm legacy glue driver are designed, there is no mechanism through which the DWC3 core can notify the Qualcomm glue layer of any role changes which it receives via role switch. To register these glue callbacks at probe time, for enabling core to notify glue layer, the legacy Qualcomm driver has no way to find out when the child driver probe was successful since it does not check for the same during of_platform_populate. Hence implement the following glue callbacks for flattened Qualcomm glue driver: 1. set_role: To pass role switching information from drd layer to glue. This information is needed to identify NONE/DEVICE mode switch and modify QSCRATCH to generate connect-done event on device mode entry and disconnect event on cable removal in device mode. 2. run_stop: When booting up in device mode, if autouspend is enabled and userspace doesn't write UDC on boot, controller enters autosuspend. After this, if the userspace writes to UDC in the future, run_stop notifier is required to enable UTMI_OTG_VBUS_VALID of QSCRATCH so that connect done event is generated after run_stop(1) is done to finish enumeration. Acked-by: Thinh Nguyen Signed-off-by: Krishna Kurapati Link: https://lore.kernel.org/r/20250907181412.2174616-3-krishna.kurapati@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 78 +++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 8a9018ca650c..ded2ca86670c 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -83,6 +83,8 @@ struct dwc3_qcom { bool pm_suspended; struct icc_path *icc_path_ddr; struct icc_path *icc_path_apps; + + enum usb_role current_role; }; #define to_dwc3_qcom(d) container_of((d), struct dwc3_qcom, dwc) @@ -111,10 +113,6 @@ static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val) readl(base + offset); } -/* - * TODO: Make the in-core role switching code invoke dwc3_qcom_vbus_override_enable(), - * validate that the in-core extcon support is functional - */ static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable) { if (enable) { @@ -560,6 +558,55 @@ static int dwc3_qcom_setup_irq(struct dwc3_qcom *qcom, struct platform_device *p return 0; } +static void dwc3_qcom_set_role_notifier(struct dwc3 *dwc, enum usb_role next_role) +{ + struct dwc3_qcom *qcom = to_dwc3_qcom(dwc); + + if (qcom->current_role == next_role) + return; + + if (pm_runtime_resume_and_get(qcom->dev)) { + dev_dbg(qcom->dev, "Failed to resume device\n"); + return; + } + + if (qcom->current_role == USB_ROLE_DEVICE) + dwc3_qcom_vbus_override_enable(qcom, false); + else if (qcom->current_role != USB_ROLE_DEVICE) + dwc3_qcom_vbus_override_enable(qcom, true); + + pm_runtime_mark_last_busy(qcom->dev); + pm_runtime_put_sync(qcom->dev); + + /* + * Current role changes via usb_role_switch_set_role callback protected + * internally by mutex lock. + */ + qcom->current_role = next_role; +} + +static void dwc3_qcom_run_stop_notifier(struct dwc3 *dwc, bool is_on) +{ + struct dwc3_qcom *qcom = to_dwc3_qcom(dwc); + + /* + * When autosuspend is enabled and controller goes to suspend + * after removing UDC from userspace, the next UDC write needs + * setting of QSCRATCH VBUS_VALID to "1" to generate a connect + * done event. + */ + if (!is_on) + return; + + dwc3_qcom_vbus_override_enable(qcom, true); + pm_runtime_mark_last_busy(qcom->dev); +} + +struct dwc3_glue_ops dwc3_qcom_glue_ops = { + .pre_set_role = dwc3_qcom_set_role_notifier, + .pre_run_stop = dwc3_qcom_run_stop_notifier, +}; + static int dwc3_qcom_probe(struct platform_device *pdev) { struct dwc3_probe_data probe_data = {}; @@ -636,6 +683,23 @@ static int dwc3_qcom_probe(struct platform_device *pdev) if (ignore_pipe_clk) dwc3_qcom_select_utmi_clk(qcom); + qcom->mode = usb_get_dr_mode(dev); + + if (qcom->mode == USB_DR_MODE_HOST) { + qcom->current_role = USB_ROLE_HOST; + } else if (qcom->mode == USB_DR_MODE_PERIPHERAL) { + qcom->current_role = USB_ROLE_DEVICE; + dwc3_qcom_vbus_override_enable(qcom, true); + } else { + if ((device_property_read_bool(dev, "usb-role-switch")) && + (usb_get_role_switch_default_mode(dev) == USB_DR_MODE_HOST)) + qcom->current_role = USB_ROLE_HOST; + else + qcom->current_role = USB_ROLE_DEVICE; + } + + qcom->dwc.glue_ops = &dwc3_qcom_glue_ops; + qcom->dwc.dev = dev; probe_data.dwc = &qcom->dwc; probe_data.res = &res; @@ -650,12 +714,6 @@ static int dwc3_qcom_probe(struct platform_device *pdev) if (ret) goto remove_core; - qcom->mode = usb_get_dr_mode(dev); - - /* enable vbus override for device mode */ - if (qcom->mode != USB_DR_MODE_HOST) - dwc3_qcom_vbus_override_enable(qcom, true); - wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source"); device_init_wakeup(&pdev->dev, wakeup_source); From 121a0f839dbb397af5fabb701cea3e9983223e50 Mon Sep 17 00:00:00 2001 From: Israel Cepeda Date: Thu, 11 Sep 2025 20:13:41 +0200 Subject: [PATCH 1290/2711] usb: misc: Add Intel USBIO bridge driver Add a driver for the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops. This is an USB bridge driver which adds auxbus child devices for the GPIO, I2C and SPI functions of the USBIO chip and which exports IO-functions for the drivers for the auxbus child devices to communicate with the USBIO device's firmware. Co-developed-by: Hans de Goede Signed-off-by: Hans de Goede Signed-off-by: Israel Cepeda Link: https://lore.kernel.org/r/20250911181343.77398-2-hansg@kernel.org Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 8 + drivers/usb/misc/Kconfig | 14 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/usbio.c | 749 ++++++++++++++++++++++++++++++++++++++ include/linux/usb/usbio.h | 177 +++++++++ 5 files changed, 949 insertions(+) create mode 100644 drivers/usb/misc/usbio.c create mode 100644 include/linux/usb/usbio.h diff --git a/MAINTAINERS b/MAINTAINERS index fed6cd812d79..434ac1593332 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12688,6 +12688,14 @@ S: Maintained F: Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst F: drivers/platform/x86/intel/uncore-frequency/ +INTEL USBIO USB I/O EXPANDER DRIVERS +M: Israel Cepeda +M: Hans de Goede +R: Sakari Ailus +S: Maintained +F: drivers/usb/misc/usbio.c +F: include/linux/usb/usbio.h + INTEL VENDOR SPECIFIC EXTENDED CAPABILITIES DRIVER M: David E. Box S: Supported diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 26eaae32f738..09ac6f1c985f 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -179,6 +179,20 @@ config USB_LJCA This driver can also be built as a module. If so, the module will be called usb-ljca. +config USB_USBIO + tristate "Intel USBIO Bridge support" + depends on USB && ACPI + select AUXILIARY_BUS + help + This adds support for Intel USBIO drivers. + This enables the USBIO bridge driver module in charge to talk + to the USB device. Additional drivers such as GPIO_USBIO and + I2C_USBIO must be enabled in order to use the device's full + functionality. + + This driver can also be built as a module. If so, the module + will be called usbio. + source "drivers/usb/misc/sisusbvga/Kconfig" config USB_LD diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 0cd5bc8f52fe..494ab0377f35 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_EZUSB_FX2) += ezusb.o obj-$(CONFIG_APPLE_MFI_FASTCHARGE) += apple-mfi-fastcharge.o obj-$(CONFIG_USB_LJCA) += usb-ljca.o +obj-$(CONFIG_USB_USBIO) += usbio.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o diff --git a/drivers/usb/misc/usbio.c b/drivers/usb/misc/usbio.c new file mode 100644 index 000000000000..37644dddf157 --- /dev/null +++ b/drivers/usb/misc/usbio.c @@ -0,0 +1,749 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel USBIO Bridge driver + * + * Copyright (c) 2025 Intel Corporation. + * Copyright (c) 2025 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************* + * USBIO Bridge Protocol Definitions * + *************************************/ + +/* USBIO Control Commands */ +#define USBIO_CTRLCMD_PROTVER 0 +#define USBIO_CTRLCMD_FWVER 1 +#define USBIO_CTRLCMD_HS 2 +#define USBIO_CTRLCMD_ENUMGPIO 16 +#define USBIO_CTRLCMD_ENUMI2C 17 + +/* USBIO Packet Flags */ +#define USBIO_PKTFLAG_ACK BIT(0) +#define USBIO_PKTFLAG_RSP BIT(1) +#define USBIO_PKTFLAG_CMP BIT(2) +#define USBIO_PKTFLAG_ERR BIT(3) + +#define USBIO_PKTFLAGS_REQRESP (USBIO_PKTFLAG_CMP | USBIO_PKTFLAG_ACK) + +#define USBIO_CTRLXFER_TIMEOUT 0 +#define USBIO_BULKXFER_TIMEOUT 100 + +struct usbio_protver { + u8 ver; +} __packed; + +struct usbio_fwver { + u8 major; + u8 minor; + __le16 patch; + __le16 build; +} __packed; + +/*********************************** + * USBIO Bridge Device Definitions * + ***********************************/ + +/** + * struct usbio_device - the usb device exposing IOs + * + * @dev: the device in the usb interface + * @udev: the detected usb device + * @intf: the usb interface + * @quirks: quirks + * @ctrl_mutex: protects ctrl_buf + * @ctrl_pipe: the control transfer pipe + * @ctrlbuf_len: the size of the control transfer pipe + * @ctrlbuf: the buffer used for control transfers + * @bulk_mutex: protects tx_buf, rx_buf and split bulk-transfers getting interrupted + * @tx_pipe: the bulk out pipe + * @txbuf_len: the size of the bulk out pipe + * @txbuf: the buffer used for bulk out transfers + * @rx_pipe: the bulk in pipe + * @rxbuf_len: the size of the bulk in pipe + * @rxdat_len: the data length at rx buffer + * @rxbuf: the buffer used for bulk in transfers + * @urb: the urb to read bulk pipe + * @done: completion object as request is done + * @cli_list: device's client list + * @nr_gpio_banks: Number of GPIO banks + * @gpios: GPIO bank descriptors + * @nr_gpio_banks: Number of I2C busses + * @gpios: I2C bank descriptors + */ +struct usbio_device { + struct device *dev; + struct usb_device *udev; + struct usb_interface *intf; + unsigned long quirks; + + struct mutex ctrl_mutex; + unsigned int ctrl_pipe; + u16 ctrlbuf_len; + void *ctrlbuf; + + struct mutex bulk_mutex; + unsigned int tx_pipe; + u16 txbuf_len; + void *txbuf; + + unsigned int rx_pipe; + u16 rxbuf_len; + u16 rxdat_len; + void *rxbuf; + struct urb *urb; + + struct completion done; + + struct list_head cli_list; + + unsigned int nr_gpio_banks; + struct usbio_gpio_bank_desc gpios[USBIO_MAX_GPIOBANKS]; + + unsigned int nr_i2c_buses; + struct usbio_i2c_bus_desc i2cs[USBIO_MAX_I2CBUSES]; +}; + +/** + * struct usbio_client - represents a usbio client + * + * @auxdev: auxiliary device object + * @mutex: protects @bridge + * @bridge: usbio bridge who service the client + * @link: usbio bridge clients list member + */ +struct usbio_client { + struct auxiliary_device auxdev; + struct mutex mutex; + struct usbio_device *bridge; + struct list_head link; +}; + +#define adev_to_client(adev) container_of_const(adev, struct usbio_client, auxdev) + +static int usbio_ctrl_msg(struct usbio_device *usbio, u8 type, u8 cmd, + const void *obuf, u16 obuf_len, void *ibuf, u16 ibuf_len) +{ + u8 request = USB_TYPE_VENDOR | USB_RECIP_DEVICE; + struct usbio_ctrl_packet *cpkt; + unsigned int pipe; + u16 cpkt_len; + int ret; + + lockdep_assert_held(&usbio->ctrl_mutex); + + if ((obuf_len > (usbio->ctrlbuf_len - sizeof(*cpkt))) || + (ibuf_len > (usbio->ctrlbuf_len - sizeof(*cpkt)))) + return -EMSGSIZE; + + /* Prepare Control Packet Header */ + cpkt = usbio->ctrlbuf; + cpkt->header.type = type; + cpkt->header.cmd = cmd; + if (type == USBIO_PKTTYPE_CTRL || ibuf_len) + cpkt->header.flags = USBIO_PKTFLAGS_REQRESP; + else + cpkt->header.flags = USBIO_PKTFLAG_CMP; + cpkt->len = obuf_len; + + /* Copy the data */ + memcpy(cpkt->data, obuf, obuf_len); + + pipe = usb_sndctrlpipe(usbio->udev, usbio->ctrl_pipe); + cpkt_len = sizeof(*cpkt) + obuf_len; + ret = usb_control_msg(usbio->udev, pipe, 0, request | USB_DIR_OUT, 0, 0, + cpkt, cpkt_len, USBIO_CTRLXFER_TIMEOUT); + dev_dbg(usbio->dev, "control out %d hdr %*phN data %*phN\n", ret, + (int)sizeof(*cpkt), cpkt, (int)cpkt->len, cpkt->data); + + if (ret != cpkt_len) { + dev_err(usbio->dev, "USB control out failed: %d\n", ret); + return (ret < 0) ? ret : -EPROTO; + } + + if (!(cpkt->header.flags & USBIO_PKTFLAG_ACK)) + return 0; + + pipe = usb_rcvctrlpipe(usbio->udev, usbio->ctrl_pipe); + cpkt_len = sizeof(*cpkt) + ibuf_len; + ret = usb_control_msg(usbio->udev, pipe, 0, request | USB_DIR_IN, 0, 0, + cpkt, cpkt_len, USBIO_CTRLXFER_TIMEOUT); + dev_dbg(usbio->dev, "control in %d hdr %*phN data %*phN\n", ret, + (int)sizeof(*cpkt), cpkt, (int)cpkt->len, cpkt->data); + + if (ret < sizeof(*cpkt)) { + dev_err(usbio->dev, "USB control in failed: %d\n", ret); + return (ret < 0) ? ret : -EPROTO; + } + + if (cpkt->header.type != type || cpkt->header.cmd != cmd || + !(cpkt->header.flags & USBIO_PKTFLAG_RSP)) { + dev_err(usbio->dev, "Unexpected reply type: %u, cmd: %u, flags: %u\n", + cpkt->header.type, cpkt->header.cmd, cpkt->header.flags); + return -EPROTO; + } + + if (cpkt->header.flags & USBIO_PKTFLAG_ERR) + return -EREMOTEIO; + + if (ibuf_len < cpkt->len) + return -ENOSPC; + + memcpy(ibuf, cpkt->data, cpkt->len); + + return cpkt->len; +} + +int usbio_control_msg(struct auxiliary_device *adev, u8 type, u8 cmd, + const void *obuf, u16 obuf_len, void *ibuf, u16 ibuf_len) +{ + struct usbio_client *client = adev_to_client(adev); + struct usbio_device *usbio; + int ret; + + guard(mutex)(&client->mutex); + + usbio = client->bridge; + if (!usbio) + return -ENODEV; /* Disconnected */ + + ret = usb_autopm_get_interface(usbio->intf); + if (ret) + return ret; + + mutex_lock(&usbio->ctrl_mutex); + + ret = usbio_ctrl_msg(client->bridge, type, cmd, obuf, obuf_len, ibuf, ibuf_len); + + mutex_unlock(&usbio->ctrl_mutex); + usb_autopm_put_interface(usbio->intf); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(usbio_control_msg, "USBIO"); + +static void usbio_bulk_recv(struct urb *urb) +{ + struct usbio_bulk_packet *bpkt = urb->transfer_buffer; + struct usbio_device *usbio = urb->context; + + if (!urb->status) { + if (bpkt->header.flags & USBIO_PKTFLAG_RSP) { + usbio->rxdat_len = urb->actual_length; + complete(&usbio->done); + } + } else if (urb->status != -ENOENT) { + dev_err(usbio->dev, "Bulk in error %d\n", urb->status); + } + + usb_submit_urb(usbio->urb, GFP_ATOMIC); +} + +int usbio_bulk_msg(struct auxiliary_device *adev, u8 type, u8 cmd, bool last, + const void *obuf, u16 obuf_len, void *ibuf, u16 ibuf_len) +{ + struct usbio_client *client = adev_to_client(adev); + struct usbio_device *usbio = client->bridge; + struct usbio_bulk_packet *bpkt; + int ret, act = 0; + u16 bpkt_len; + + lockdep_assert_held(&client->mutex); + lockdep_assert_held(&usbio->bulk_mutex); + + if ((obuf_len > (usbio->txbuf_len - sizeof(*bpkt))) || + (ibuf_len > (usbio->txbuf_len - sizeof(*bpkt)))) + return -EMSGSIZE; + + if (ibuf_len) + reinit_completion(&usbio->done); + + /* If no data to send, skip to read */ + if (!obuf_len) + goto read; + + /* Prepare Bulk Packet Header */ + bpkt = usbio->txbuf; + bpkt->header.type = type; + bpkt->header.cmd = cmd; + if (!last) + bpkt->header.flags = 0; + else if (ibuf_len) + bpkt->header.flags = USBIO_PKTFLAGS_REQRESP; + else + bpkt->header.flags = USBIO_PKTFLAG_CMP; + bpkt->len = cpu_to_le16(obuf_len); + + /* Copy the data */ + memcpy(bpkt->data, obuf, obuf_len); + + bpkt_len = sizeof(*bpkt) + obuf_len; + ret = usb_bulk_msg(usbio->udev, usbio->tx_pipe, bpkt, bpkt_len, &act, + USBIO_BULKXFER_TIMEOUT); + dev_dbg(usbio->dev, "bulk out %d hdr %*phN data %*phN\n", act, + (int)sizeof(*bpkt), bpkt, obuf_len, bpkt->data); + + if (ret || act != bpkt_len) { + dev_err(usbio->dev, "Bulk out failed: %d\n", ret); + return ret ?: -EPROTO; + } + + if (!(bpkt->header.flags & USBIO_PKTFLAG_ACK)) + return obuf_len; + +read: + ret = wait_for_completion_timeout(&usbio->done, USBIO_BULKXFER_TIMEOUT); + if (ret <= 0) { + dev_err(usbio->dev, "Bulk in wait failed: %d\n", ret); + return ret ?: -ETIMEDOUT; + } + + act = usbio->rxdat_len; + bpkt = usbio->rxbuf; + bpkt_len = le16_to_cpu(bpkt->len); + dev_dbg(usbio->dev, "bulk in %d hdr %*phN data %*phN\n", act, + (int)sizeof(*bpkt), bpkt, bpkt_len, bpkt->data); + + /* + * Unsupported bulk commands get only an usbio_packet_header with + * the error flag set as reply. Return -EPIPE for this case. + */ + if (act == sizeof(struct usbio_packet_header) && + (bpkt->header.flags & USBIO_PKTFLAG_ERR)) + return -EPIPE; + + if (act < sizeof(*bpkt)) { + dev_err(usbio->dev, "Bulk in short read: %d\n", act); + return -EPROTO; + } + + if (bpkt->header.type != type || bpkt->header.cmd != cmd || + !(bpkt->header.flags & USBIO_PKTFLAG_RSP)) { + dev_err(usbio->dev, + "Unexpected bulk in type 0x%02x cmd 0x%02x flags 0x%02x\n", + bpkt->header.type, bpkt->header.cmd, bpkt->header.flags); + return -EPROTO; + } + + if (bpkt->header.flags & USBIO_PKTFLAG_ERR) + return -EREMOTEIO; + + if (ibuf_len < bpkt_len) + return -ENOSPC; + + memcpy(ibuf, bpkt->data, bpkt_len); + + return bpkt_len; +} +EXPORT_SYMBOL_NS_GPL(usbio_bulk_msg, "USBIO"); + +int usbio_acquire(struct auxiliary_device *adev) +{ + struct usbio_client *client = adev_to_client(adev); + struct usbio_device *usbio; + int ret; + + mutex_lock(&client->mutex); + + usbio = client->bridge; + if (!usbio) { + ret = -ENODEV; /* Disconnected */ + goto err_unlock; + } + + ret = usb_autopm_get_interface(usbio->intf); + if (ret) + goto err_unlock; + + mutex_lock(&usbio->bulk_mutex); + + /* Leave client locked until release to avoid abba deadlock issues */ + return 0; + +err_unlock: + mutex_unlock(&client->mutex); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(usbio_acquire, "USBIO"); + +void usbio_release(struct auxiliary_device *adev) +{ + struct usbio_client *client = adev_to_client(adev); + struct usbio_device *usbio = client->bridge; + + lockdep_assert_held(&client->mutex); + + mutex_unlock(&usbio->bulk_mutex); + usb_autopm_put_interface(usbio->intf); + mutex_unlock(&client->mutex); +} +EXPORT_SYMBOL_NS_GPL(usbio_release, "USBIO"); + +void usbio_get_txrxbuf_len(struct auxiliary_device *adev, u16 *txbuf_len, u16 *rxbuf_len) +{ + struct usbio_client *client = adev_to_client(adev); + struct usbio_device *usbio; + + guard(mutex)(&client->mutex); + + usbio = client->bridge; + if (!usbio) + return; /* Disconnected */ + + *txbuf_len = usbio->txbuf_len; + *rxbuf_len = usbio->rxbuf_len; +} +EXPORT_SYMBOL_NS_GPL(usbio_get_txrxbuf_len, "USBIO"); + +unsigned long usbio_get_quirks(struct auxiliary_device *adev) +{ + struct usbio_client *client = adev_to_client(adev); + struct usbio_device *usbio; + + guard(mutex)(&client->mutex); + + usbio = client->bridge; + if (!usbio) + return 0; /* Disconnected */ + + return usbio->quirks; +} +EXPORT_SYMBOL_NS_GPL(usbio_get_quirks, "USBIO"); + +static void usbio_auxdev_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + struct usbio_client *client = adev_to_client(adev); + + mutex_destroy(&client->mutex); + kfree(client); +} + +static int usbio_add_client(struct usbio_device *usbio, char *name, u8 id, void *data) +{ + struct usbio_client *client; + struct auxiliary_device *adev; + int ret; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + mutex_init(&client->mutex); + client->bridge = usbio; + adev = &client->auxdev; + adev->name = name; + adev->id = id; + + adev->dev.parent = usbio->dev; + adev->dev.platform_data = data; + adev->dev.release = usbio_auxdev_release; + + ret = auxiliary_device_init(adev); + if (ret) { + usbio_auxdev_release(&adev->dev); + return ret; + } + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + list_add_tail(&client->link, &usbio->cli_list); + + return 0; +} + +static int usbio_enum_gpios(struct usbio_device *usbio) +{ + struct usbio_gpio_bank_desc *gpio = usbio->gpios; + + dev_dbg(usbio->dev, "GPIO Banks: %d\n", usbio->nr_gpio_banks); + + for (unsigned int i = 0; i < usbio->nr_gpio_banks; i++) + dev_dbg(usbio->dev, "\tBank%d[%d] map: %#08x\n", + gpio[i].id, gpio[i].pins, gpio[i].bmap); + + usbio_add_client(usbio, USBIO_GPIO_CLIENT, 0, gpio); + + return 0; +} + +static int usbio_enum_i2cs(struct usbio_device *usbio) +{ + struct usbio_i2c_bus_desc *i2c = usbio->i2cs; + + dev_dbg(usbio->dev, "I2C Busses: %d\n", usbio->nr_i2c_buses); + + for (unsigned int i = 0; i < usbio->nr_i2c_buses; i++) { + dev_dbg(usbio->dev, "\tBus%d caps: %#02x\n", i2c[i].id, i2c[i].caps); + usbio_add_client(usbio, USBIO_I2C_CLIENT, i, &i2c[i]); + } + + return 0; +} + +static int usbio_suspend(struct usb_interface *intf, pm_message_t msg) +{ + struct usbio_device *usbio = usb_get_intfdata(intf); + + usb_kill_urb(usbio->urb); + + return 0; +} + +static int usbio_resume(struct usb_interface *intf) +{ + struct usbio_device *usbio = usb_get_intfdata(intf); + + return usb_submit_urb(usbio->urb, GFP_KERNEL); +} + +static void usbio_disconnect(struct usb_interface *intf) +{ + struct usbio_device *usbio = usb_get_intfdata(intf); + struct usbio_client *client; + + /* Wakeup any clients waiting for a reply */ + usbio->rxdat_len = 0; + complete(&usbio->done); + + /* Let clients know the bridge is gone */ + list_for_each_entry(client, &usbio->cli_list, link) { + mutex_lock(&client->mutex); + client->bridge = NULL; + mutex_unlock(&client->mutex); + } + + /* From here on clients will no longer touch struct usbio_device */ + usb_kill_urb(usbio->urb); + usb_free_urb(usbio->urb); + + list_for_each_entry_reverse(client, &usbio->cli_list, link) { + auxiliary_device_delete(&client->auxdev); + auxiliary_device_uninit(&client->auxdev); + } +} + +static int usbio_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_endpoint_descriptor *ep_in, *ep_out; + struct device *dev = &intf->dev; + struct usbio_protver protver; + struct usbio_device *usbio; + struct usbio_fwver fwver; + int ret; + + usbio = devm_kzalloc(dev, sizeof(*usbio), GFP_KERNEL); + if (!usbio) + return -ENOMEM; + + ret = devm_mutex_init(dev, &usbio->ctrl_mutex); + if (ret) + return ret; + + ret = devm_mutex_init(dev, &usbio->bulk_mutex); + if (ret) + return ret; + + usbio->dev = dev; + usbio->udev = udev; + usbio->intf = intf; + usbio->quirks = id ? id->driver_info : 0; + init_completion(&usbio->done); + INIT_LIST_HEAD(&usbio->cli_list); + usb_set_intfdata(intf, usbio); + + usbio->ctrl_pipe = usb_endpoint_num(&udev->ep0.desc); + usbio->ctrlbuf_len = usb_maxpacket(udev, usbio->ctrl_pipe); + usbio->ctrlbuf = devm_kzalloc(dev, usbio->ctrlbuf_len, GFP_KERNEL); + if (!usbio->ctrlbuf) + return -ENOMEM; + + /* Find the first bulk-in and bulk-out endpoints */ + ret = usb_find_common_endpoints(intf->cur_altsetting, &ep_in, &ep_out, + NULL, NULL); + if (ret) { + dev_err(dev, "Cannot find bulk endpoints: %d\n", ret); + return ret; + } + + usbio->tx_pipe = usb_sndbulkpipe(udev, usb_endpoint_num(ep_out)); + + if (usbio->quirks & USBIO_QUIRK_BULK_MAXP_63) + usbio->txbuf_len = 63; + else + usbio->txbuf_len = usb_endpoint_maxp(ep_out); + + usbio->txbuf = devm_kzalloc(dev, usbio->txbuf_len, GFP_KERNEL); + if (!usbio->txbuf) + return -ENOMEM; + + usbio->rx_pipe = usb_rcvbulkpipe(udev, usb_endpoint_num(ep_in)); + + if (usbio->quirks & USBIO_QUIRK_BULK_MAXP_63) + usbio->rxbuf_len = 63; + else + usbio->rxbuf_len = usb_endpoint_maxp(ep_in); + + usbio->rxbuf = devm_kzalloc(dev, usbio->rxbuf_len, GFP_KERNEL); + if (!usbio->rxbuf) + return -ENOMEM; + + usbio->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!usbio->urb) + return -ENOMEM; + + usb_fill_bulk_urb(usbio->urb, udev, usbio->rx_pipe, usbio->rxbuf, + usbio->rxbuf_len, usbio_bulk_recv, usbio); + ret = usb_submit_urb(usbio->urb, GFP_KERNEL); + if (ret) + return dev_err_probe(dev, ret, "Submitting usb urb\n"); + + mutex_lock(&usbio->ctrl_mutex); + + ret = usbio_ctrl_msg(usbio, USBIO_PKTTYPE_CTRL, USBIO_CTRLCMD_HS, NULL, 0, NULL, 0); + if (ret < 0) + goto err_unlock; + + ret = usbio_ctrl_msg(usbio, USBIO_PKTTYPE_CTRL, USBIO_CTRLCMD_PROTVER, NULL, 0, + &protver, sizeof(protver)); + if (ret < 0) + goto err_unlock; + + ret = usbio_ctrl_msg(usbio, USBIO_PKTTYPE_CTRL, USBIO_CTRLCMD_FWVER, NULL, 0, + &fwver, sizeof(fwver)); + if (ret < 0) + goto err_unlock; + + ret = usbio_ctrl_msg(usbio, USBIO_PKTTYPE_CTRL, USBIO_CTRLCMD_ENUMGPIO, NULL, 0, + usbio->gpios, sizeof(usbio->gpios)); + if (ret < 0 || ret % sizeof(struct usbio_gpio_bank_desc)) { + ret = (ret < 0) ? ret : -EPROTO; + goto err_unlock; + } + usbio->nr_gpio_banks = ret / sizeof(struct usbio_gpio_bank_desc); + + ret = usbio_ctrl_msg(usbio, USBIO_PKTTYPE_CTRL, USBIO_CTRLCMD_ENUMI2C, NULL, 0, + usbio->i2cs, sizeof(usbio->i2cs)); + if (ret < 0 || ret % sizeof(struct usbio_i2c_bus_desc)) { + ret = (ret < 0) ? ret : -EPROTO; + goto err_unlock; + } + usbio->nr_i2c_buses = ret / sizeof(struct usbio_i2c_bus_desc); + + mutex_unlock(&usbio->ctrl_mutex); + + dev_dbg(dev, "ProtVer(BCD): %02x FwVer: %d.%d.%d.%d\n", + protver.ver, fwver.major, fwver.minor, + le16_to_cpu(fwver.patch), le16_to_cpu(fwver.build)); + + usbio_enum_gpios(usbio); + usbio_enum_i2cs(usbio); + + return 0; + +err_unlock: + mutex_unlock(&usbio->ctrl_mutex); + usb_kill_urb(usbio->urb); + usb_free_urb(usbio->urb); + + return ret; +} + +static const struct usb_device_id usbio_table[] = { + { USB_DEVICE(0x2ac1, 0x20c1), /* Lattice NX40 */ + .driver_info = USBIO_QUIRK_I2C_MAX_RW_LEN_52 }, + { USB_DEVICE(0x2ac1, 0x20c9), /* Lattice NX33 */ + .driver_info = USBIO_QUIRK_I2C_NO_INIT_ACK | USBIO_QUIRK_I2C_MAX_RW_LEN_52 | + USBIO_QUIRK_I2C_ALLOW_400KHZ }, + { USB_DEVICE(0x2ac1, 0x20cb) }, /* Lattice NX33U */ + { USB_DEVICE(0x06cb, 0x0701), /* Synaptics Sabre */ + .driver_info = USBIO_QUIRK_BULK_MAXP_63 | USBIO_QUIRK_I2C_USE_CHUNK_LEN }, + { } +}; +MODULE_DEVICE_TABLE(usb, usbio_table); + +static struct usb_driver usbio_driver = { + .name = "usbio-bridge", + .probe = usbio_probe, + .disconnect = usbio_disconnect, + .suspend = usbio_suspend, + .resume = usbio_resume, + .id_table = usbio_table, + .supports_autosuspend = 1, +}; +module_usb_driver(usbio_driver); + +struct usbio_match_ids_walk_data { + struct acpi_device *adev; + const struct acpi_device_id *hids; + unsigned int id; +}; + +static int usbio_match_device_ids(struct acpi_device *adev, void *data) +{ + struct usbio_match_ids_walk_data *wd = data; + unsigned int id = 0; + char *uid; + + if (acpi_match_device_ids(adev, wd->hids)) + return 0; + + uid = acpi_device_uid(adev); + if (uid) { + for (int i = 0; i < strlen(uid); i++) { + if (!kstrtouint(&uid[i], 10, &id)) + break; + } + } + + if (!uid || wd->id == id) { + wd->adev = adev; + return 1; + } + + return 0; +} + +void usbio_acpi_bind(struct auxiliary_device *adev, const struct acpi_device_id *hids) +{ + struct device *dev = &adev->dev; + struct acpi_device *parent; + struct usbio_match_ids_walk_data wd = { + .adev = NULL, + .hids = hids, + .id = adev->id, + }; + + parent = ACPI_COMPANION(dev->parent); + if (!parent) + return; + + acpi_dev_for_each_child(parent, usbio_match_device_ids, &wd); + if (wd.adev) + ACPI_COMPANION_SET(dev, wd.adev); +} +EXPORT_SYMBOL_NS_GPL(usbio_acpi_bind, "USBIO"); + +MODULE_DESCRIPTION("Intel USBIO Bridge driver"); +MODULE_AUTHOR("Israel Cepeda "); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/usb/usbio.h b/include/linux/usb/usbio.h new file mode 100644 index 000000000000..6c4e7c246d58 --- /dev/null +++ b/include/linux/usb/usbio.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2025 Intel Corporation. + * + */ + +#ifndef _LINUX_USBIO_H_ +#define _LINUX_USBIO_H_ + +#include +#include +#include +#include + +/*********************** + * USBIO Clients Names * + ***********************/ +#define USBIO_GPIO_CLIENT "usbio-gpio" +#define USBIO_I2C_CLIENT "usbio-i2c" + +/**************** + * USBIO quirks * + ****************/ +#define USBIO_QUIRK_BULK_MAXP_63 BIT(0) /* Force bulk endpoint maxp to 63 */ +#define USBIO_QUIRK_I2C_NO_INIT_ACK BIT(8) /* Do not ask for ack on I2C init */ +#define USBIO_QUIRK_I2C_MAX_RW_LEN_52 BIT(9) /* Set i2c-adapter max r/w len to 52 */ +#define USBIO_QUIRK_I2C_USE_CHUNK_LEN BIT(10) /* Send chunk-len for split xfers */ +#define USBIO_QUIRK_I2C_ALLOW_400KHZ BIT(11) /* Override desc, allowing 400 KHz */ + +/************************** + * USBIO Type Definitions * + **************************/ + +/* USBIO Packet Type */ +#define USBIO_PKTTYPE_CTRL 1 +#define USBIO_PKTTYPE_DBG 2 +#define USBIO_PKTTYPE_GPIO 3 +#define USBIO_PKTTYPE_I2C 4 + +/* USBIO Packet Header */ +struct usbio_packet_header { + u8 type; + u8 cmd; + u8 flags; +} __packed; + +/* USBIO Control Transfer Packet */ +struct usbio_ctrl_packet { + struct usbio_packet_header header; + u8 len; + u8 data[] __counted_by(len); +} __packed; + +/* USBIO Bulk Transfer Packet */ +struct usbio_bulk_packet { + struct usbio_packet_header header; + __le16 len; + u8 data[] __counted_by(len); +} __packed; + +/* USBIO GPIO commands */ +enum usbio_gpio_cmd { + USBIO_GPIOCMD_DEINIT, + USBIO_GPIOCMD_INIT, + USBIO_GPIOCMD_READ, + USBIO_GPIOCMD_WRITE, + USBIO_GPIOCMD_END +}; + +/* USBIO GPIO config */ +enum usbio_gpio_pincfg { + USBIO_GPIO_PINCFG_DEFAULT, + USBIO_GPIO_PINCFG_PULLUP, + USBIO_GPIO_PINCFG_PULLDOWN, + USBIO_GPIO_PINCFG_PUSHPULL +}; + +#define USBIO_GPIO_PINCFG_SHIFT 2 +#define USBIO_GPIO_PINCFG_MASK (0x3 << USBIO_GPIO_PINCFG_SHIFT) +#define USBIO_GPIO_SET_PINCFG(pincfg) \ + (((pincfg) << USBIO_GPIO_PINCFG_SHIFT) & USBIO_GPIO_PINCFG_MASK) + +enum usbio_gpio_pinmode { + USBIO_GPIO_PINMOD_INVAL, + USBIO_GPIO_PINMOD_INPUT, + USBIO_GPIO_PINMOD_OUTPUT, + USBIO_GPIO_PINMOD_MAXVAL +}; + +#define USBIO_GPIO_PINMOD_MASK 0x3 +#define USBIO_GPIO_SET_PINMOD(pin) (pin & USBIO_GPIO_PINMOD_MASK) + +/************************* + * USBIO GPIO Controller * + *************************/ + +#define USBIO_MAX_GPIOBANKS 5 +#define USBIO_GPIOSPERBANK 32 + +struct usbio_gpio_bank_desc { + u8 id; + u8 pins; + __le32 bmap; +} __packed; + +struct usbio_gpio_init { + u8 bankid; + u8 config; + u8 pincount; + u8 pin; +} __packed; + +struct usbio_gpio_rw { + u8 bankid; + u8 pincount; + u8 pin; + __le32 value; +} __packed; + +/* USBIO I2C commands */ +enum usbio_i2c_cmd { + USBIO_I2CCMD_UNINIT, + USBIO_I2CCMD_INIT, + USBIO_I2CCMD_READ, + USBIO_I2CCMD_WRITE, + USBIO_I2CCMD_END +}; + +/************************ + * USBIO I2C Controller * + ************************/ + +#define USBIO_MAX_I2CBUSES 5 + +#define USBIO_I2C_BUS_ADDR_CAP_10B BIT(3) /* 10bit address support */ +#define USBIO_I2C_BUS_MODE_CAP_MASK 0x3 +#define USBIO_I2C_BUS_MODE_CAP_SM 0 /* Standard Mode */ +#define USBIO_I2C_BUS_MODE_CAP_FM 1 /* Fast Mode */ +#define USBIO_I2C_BUS_MODE_CAP_FMP 2 /* Fast Mode+ */ +#define USBIO_I2C_BUS_MODE_CAP_HSM 3 /* High-Speed Mode */ + +struct usbio_i2c_bus_desc { + u8 id; + u8 caps; +} __packed; + +struct usbio_i2c_uninit { + u8 busid; + __le16 config; +} __packed; + +struct usbio_i2c_init { + u8 busid; + __le16 config; + __le32 speed; +} __packed; + +struct usbio_i2c_rw { + u8 busid; + __le16 config; + __le16 size; + u8 data[] __counted_by(size); +} __packed; + +int usbio_control_msg(struct auxiliary_device *adev, u8 type, u8 cmd, + const void *obuf, u16 obuf_len, void *ibuf, u16 ibuf_len); + +int usbio_bulk_msg(struct auxiliary_device *adev, u8 type, u8 cmd, bool last, + const void *obuf, u16 obuf_len, void *ibuf, u16 ibuf_len); + +int usbio_acquire(struct auxiliary_device *adev); +void usbio_release(struct auxiliary_device *adev); +void usbio_get_txrxbuf_len(struct auxiliary_device *adev, u16 *txbuf_len, u16 *rxbuf_len); +unsigned long usbio_get_quirks(struct auxiliary_device *adev); +void usbio_acpi_bind(struct auxiliary_device *adev, const struct acpi_device_id *hids); + +#endif From c122451ce04e6991316ed37bac41d45646942027 Mon Sep 17 00:00:00 2001 From: Israel Cepeda Date: Thu, 11 Sep 2025 20:13:42 +0200 Subject: [PATCH 1291/2711] gpio: Add Intel USBIO GPIO driver Add a a driver for the GPIO auxbus child device of the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops. Reviewed-by: Linus Walleij Acked-by: Bartosz Golaszewski Co-developed-by: Hans de Goede Signed-off-by: Hans de Goede Signed-off-by: Israel Cepeda Link: https://lore.kernel.org/r/20250911181343.77398-3-hansg@kernel.org Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + drivers/gpio/Kconfig | 11 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-usbio.c | 247 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 260 insertions(+) create mode 100644 drivers/gpio/gpio-usbio.c diff --git a/MAINTAINERS b/MAINTAINERS index 434ac1593332..7fef488118a4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12693,6 +12693,7 @@ M: Israel Cepeda M: Hans de Goede R: Sakari Ailus S: Maintained +F: drivers/gpio/gpio-usbio.c F: drivers/usb/misc/usbio.c F: include/linux/usb/usbio.h diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e43abb322fa6..9390ef4e5079 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1923,6 +1923,17 @@ config GPIO_MPSSE GPIO driver for FTDI's MPSSE interface. These can do input and output. Each MPSSE provides 16 IO pins. +config GPIO_USBIO + tristate "Intel USBIO GPIO support" + depends on USB_USBIO + default USB_USBIO + help + Select this option to enable GPIO driver for the INTEL + USBIO driver stack. + + This driver can also be built as a module. If so, the module + will be called gpio_usbio. + endmenu menu "Virtual GPIO drivers" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 379f55e9ed1e..b1593ce92ebe 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -192,6 +192,7 @@ obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o +obj-$(CONFIG_GPIO_USBIO) += gpio-usbio.o obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VIRTUSER) += gpio-virtuser.o diff --git a/drivers/gpio/gpio-usbio.c b/drivers/gpio/gpio-usbio.c new file mode 100644 index 000000000000..e13c120824e3 --- /dev/null +++ b/drivers/gpio/gpio-usbio.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025 Intel Corporation. + * Copyright (c) 2025 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct usbio_gpio_bank { + u8 config[USBIO_GPIOSPERBANK]; + u32 bitmap; +}; + +struct usbio_gpio { + struct mutex config_mutex; /* Protects banks[x].config */ + struct usbio_gpio_bank banks[USBIO_MAX_GPIOBANKS]; + struct gpio_chip gc; + struct auxiliary_device *adev; +}; + +static const struct acpi_device_id usbio_gpio_acpi_hids[] = { + { "INTC1007" }, /* MTL */ + { "INTC10B2" }, /* ARL */ + { "INTC10B5" }, /* LNL */ + { "INTC10E2" }, /* PTL */ + { } +}; + +static void usbio_gpio_get_bank_and_pin(struct gpio_chip *gc, unsigned int offset, + struct usbio_gpio_bank **bank_ret, + unsigned int *pin_ret) +{ + struct usbio_gpio *gpio = gpiochip_get_data(gc); + struct device *dev = &gpio->adev->dev; + struct usbio_gpio_bank *bank; + unsigned int pin; + + bank = &gpio->banks[offset / USBIO_GPIOSPERBANK]; + pin = offset % USBIO_GPIOSPERBANK; + if (~bank->bitmap & BIT(pin)) { + /* The FW bitmap sometimes is invalid, warn and continue */ + dev_warn_once(dev, FW_BUG "GPIO %u is not in FW pins bitmap\n", offset); + } + + *bank_ret = bank; + *pin_ret = pin; +} + +static int usbio_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct usbio_gpio_bank *bank; + unsigned int pin; + u8 cfg; + + usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin); + + cfg = bank->config[pin] & USBIO_GPIO_PINMOD_MASK; + + return (cfg == USBIO_GPIO_PINMOD_OUTPUT) ? + GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; +} + +static int usbio_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct usbio_gpio *gpio = gpiochip_get_data(gc); + struct usbio_gpio_bank *bank; + struct usbio_gpio_rw gbuf; + unsigned int pin; + int ret; + + usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin); + + gbuf.bankid = offset / USBIO_GPIOSPERBANK; + gbuf.pincount = 1; + gbuf.pin = pin; + + ret = usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_READ, + &gbuf, sizeof(gbuf) - sizeof(gbuf.value), + &gbuf, sizeof(gbuf)); + if (ret != sizeof(gbuf)) + return (ret < 0) ? ret : -EPROTO; + + return (le32_to_cpu(gbuf.value) >> pin) & 1; +} + +static int usbio_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct usbio_gpio *gpio = gpiochip_get_data(gc); + struct usbio_gpio_bank *bank; + struct usbio_gpio_rw gbuf; + unsigned int pin; + + usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin); + + gbuf.bankid = offset / USBIO_GPIOSPERBANK; + gbuf.pincount = 1; + gbuf.pin = pin; + gbuf.value = cpu_to_le32(value << pin); + + return usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_WRITE, + &gbuf, sizeof(gbuf), NULL, 0); +} + +static int usbio_gpio_update_config(struct gpio_chip *gc, unsigned int offset, + u8 mask, u8 value) +{ + struct usbio_gpio *gpio = gpiochip_get_data(gc); + struct usbio_gpio_bank *bank; + struct usbio_gpio_init gbuf; + unsigned int pin; + + usbio_gpio_get_bank_and_pin(gc, offset, &bank, &pin); + + guard(mutex)(&gpio->config_mutex); + + bank->config[pin] &= ~mask; + bank->config[pin] |= value; + + gbuf.bankid = offset / USBIO_GPIOSPERBANK; + gbuf.config = bank->config[pin]; + gbuf.pincount = 1; + gbuf.pin = pin; + + return usbio_control_msg(gpio->adev, USBIO_PKTTYPE_GPIO, USBIO_GPIOCMD_INIT, + &gbuf, sizeof(gbuf), NULL, 0); +} + +static int usbio_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) +{ + return usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINMOD_MASK, + USBIO_GPIO_SET_PINMOD(USBIO_GPIO_PINMOD_INPUT)); +} + +static int usbio_gpio_direction_output(struct gpio_chip *gc, + unsigned int offset, int value) +{ + int ret; + + ret = usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINMOD_MASK, + USBIO_GPIO_SET_PINMOD(USBIO_GPIO_PINMOD_OUTPUT)); + if (ret) + return ret; + + return usbio_gpio_set(gc, offset, value); +} + +static int usbio_gpio_set_config(struct gpio_chip *gc, unsigned int offset, + unsigned long config) +{ + u8 value; + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_DEFAULT); + break; + case PIN_CONFIG_BIAS_PULL_UP: + value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PULLUP); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PULLDOWN); + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + value = USBIO_GPIO_SET_PINCFG(USBIO_GPIO_PINCFG_PUSHPULL); + break; + default: + return -ENOTSUPP; + } + + return usbio_gpio_update_config(gc, offset, USBIO_GPIO_PINCFG_MASK, value); +} + +static int usbio_gpio_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *adev_id) +{ + struct usbio_gpio_bank_desc *bank_desc; + struct device *dev = &adev->dev; + struct usbio_gpio *gpio; + int bank, ret; + + bank_desc = dev_get_platdata(dev); + if (!bank_desc) + return -EINVAL; + + gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + ret = devm_mutex_init(dev, &gpio->config_mutex); + if (ret) + return ret; + + gpio->adev = adev; + + usbio_acpi_bind(gpio->adev, usbio_gpio_acpi_hids); + + for (bank = 0; bank < USBIO_MAX_GPIOBANKS && bank_desc[bank].bmap; bank++) + gpio->banks[bank].bitmap = le32_to_cpu(bank_desc[bank].bmap); + + gpio->gc.label = ACPI_COMPANION(dev) ? + acpi_dev_name(ACPI_COMPANION(dev)) : dev_name(dev); + gpio->gc.parent = dev; + gpio->gc.owner = THIS_MODULE; + gpio->gc.get_direction = usbio_gpio_get_direction; + gpio->gc.direction_input = usbio_gpio_direction_input; + gpio->gc.direction_output = usbio_gpio_direction_output; + gpio->gc.get = usbio_gpio_get; + gpio->gc.set = usbio_gpio_set; + gpio->gc.set_config = usbio_gpio_set_config; + gpio->gc.base = -1; + gpio->gc.ngpio = bank * USBIO_GPIOSPERBANK; + gpio->gc.can_sleep = true; + + ret = devm_gpiochip_add_data(dev, &gpio->gc, gpio); + if (ret) + return ret; + + if (has_acpi_companion(dev)) + acpi_dev_clear_dependencies(ACPI_COMPANION(dev)); + + return 0; +} + +static const struct auxiliary_device_id usbio_gpio_id_table[] = { + { "usbio.usbio-gpio" }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, usbio_gpio_id_table); + +static struct auxiliary_driver usbio_gpio_driver = { + .name = USBIO_GPIO_CLIENT, + .probe = usbio_gpio_probe, + .id_table = usbio_gpio_id_table +}; +module_auxiliary_driver(usbio_gpio_driver); + +MODULE_DESCRIPTION("Intel USBIO GPIO driver"); +MODULE_AUTHOR("Israel Cepeda "); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("USBIO"); From daf161343a3904f6699febbfb1e18d532371ba00 Mon Sep 17 00:00:00 2001 From: Israel Cepeda Date: Thu, 11 Sep 2025 20:13:43 +0200 Subject: [PATCH 1292/2711] i2c: Add Intel USBIO I2C driver Add a a driver for the I2C auxbus child device of the Intel USBIO USB IO-expander used by the MIPI cameras on various new (Meteor Lake and later) Intel laptops. Co-developed-by: Hans de Goede Signed-off-by: Hans de Goede Signed-off-by: Israel Cepeda Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/20250911181343.77398-4-hansg@kernel.org Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + drivers/i2c/busses/Kconfig | 11 ++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-usbio.c | 320 +++++++++++++++++++++++++++++++++ 4 files changed, 333 insertions(+) create mode 100644 drivers/i2c/busses/i2c-usbio.c diff --git a/MAINTAINERS b/MAINTAINERS index 7fef488118a4..c65f2f71db0c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12694,6 +12694,7 @@ M: Hans de Goede R: Sakari Ailus S: Maintained F: drivers/gpio/gpio-usbio.c +F: drivers/i2c/busses/i2c-usbio.c F: drivers/usb/misc/usbio.c F: include/linux/usb/usbio.h diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 070d014fdc5d..06b1b702fd7a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1357,6 +1357,17 @@ config I2C_LJCA This driver can also be built as a module. If so, the module will be called i2c-ljca. +config I2C_USBIO + tristate "Intel USBIO I2C Adapter support" + depends on USB_USBIO + default USB_USBIO + help + Select this option to enable I2C driver for the INTEL + USBIO driver stack. + + This driver can also be built as a module. If so, the module + will be called i2c_usbio. + config I2C_CP2615 tristate "Silicon Labs CP2615 USB sound card and I2C adapter" depends on USB diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 04db855fdfd6..401a79c9767e 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -135,6 +135,7 @@ obj-$(CONFIG_I2C_GXP) += i2c-gxp.o obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o obj-$(CONFIG_I2C_LJCA) += i2c-ljca.o +obj-$(CONFIG_I2C_USBIO) += i2c-usbio.o obj-$(CONFIG_I2C_CP2615) += i2c-cp2615.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PCI1XXXX) += i2c-mchp-pci1xxxx.o diff --git a/drivers/i2c/busses/i2c-usbio.c b/drivers/i2c/busses/i2c-usbio.c new file mode 100644 index 000000000000..d42f9ab6e9a5 --- /dev/null +++ b/drivers/i2c/busses/i2c-usbio.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025 Intel Corporation. + * Copyright (c) 2025 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#define I2C_RW_OVERHEAD (sizeof(struct usbio_bulk_packet) + sizeof(struct usbio_i2c_rw)) + +struct usbio_i2c { + struct i2c_adapter adap; + struct auxiliary_device *adev; + struct usbio_i2c_rw *rwbuf; + unsigned long quirks; + u32 speed; + u16 txbuf_len; + u16 rxbuf_len; +}; + +static const struct acpi_device_id usbio_i2c_acpi_hids[] = { + { "INTC1008" }, /* MTL */ + { "INTC10B3" }, /* ARL */ + { "INTC10B6" }, /* LNL */ + { "INTC10E3" }, /* PTL */ + { } +}; + +static const u32 usbio_i2c_speeds[] = { + I2C_MAX_STANDARD_MODE_FREQ, + I2C_MAX_FAST_MODE_FREQ, + I2C_MAX_FAST_MODE_PLUS_FREQ, + I2C_MAX_HIGH_SPEED_MODE_FREQ +}; + +static void usbio_i2c_uninit(struct i2c_adapter *adap, struct i2c_msg *msg) +{ + struct usbio_i2c *i2c = i2c_get_adapdata(adap); + struct usbio_i2c_uninit ubuf; + + ubuf.busid = i2c->adev->id; + ubuf.config = cpu_to_le16(msg->addr); + + usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_UNINIT, true, + &ubuf, sizeof(ubuf), NULL, 0); +} + +static int usbio_i2c_init(struct i2c_adapter *adap, struct i2c_msg *msg) +{ + struct usbio_i2c *i2c = i2c_get_adapdata(adap); + struct usbio_i2c_init ibuf; + void *reply_buf; + u16 reply_len; + int ret; + + ibuf.busid = i2c->adev->id; + ibuf.config = cpu_to_le16(msg->addr); + ibuf.speed = cpu_to_le32(i2c->speed); + + if (i2c->quirks & USBIO_QUIRK_I2C_NO_INIT_ACK) { + reply_buf = NULL; + reply_len = 0; + } else { + reply_buf = &ibuf; + reply_len = sizeof(ibuf); + } + + ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_INIT, true, + &ibuf, sizeof(ibuf), reply_buf, reply_len); + if (ret != sizeof(ibuf)) + return (ret < 0) ? ret : -EIO; + + return 0; +} + +static int usbio_i2c_read(struct i2c_adapter *adap, struct i2c_msg *msg) +{ + struct usbio_i2c *i2c = i2c_get_adapdata(adap); + u16 rxchunk = i2c->rxbuf_len - I2C_RW_OVERHEAD; + struct usbio_i2c_rw *rbuf = i2c->rwbuf; + int ret; + + rbuf->busid = i2c->adev->id; + rbuf->config = cpu_to_le16(msg->addr); + rbuf->size = cpu_to_le16(msg->len); + + if (msg->len > rxchunk) { + /* Need to split the input buffer */ + u16 len = 0; + + do { + if (msg->len - len < rxchunk) + rxchunk = msg->len - len; + + ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, + USBIO_I2CCMD_READ, true, + rbuf, len == 0 ? sizeof(*rbuf) : 0, + rbuf, sizeof(*rbuf) + rxchunk); + if (ret < 0) + return ret; + + memcpy(&msg->buf[len], rbuf->data, rxchunk); + len += rxchunk; + } while (msg->len > len); + + return 0; + } + + ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_READ, true, + rbuf, sizeof(*rbuf), rbuf, sizeof(*rbuf) + msg->len); + if (ret != sizeof(*rbuf) + msg->len) + return (ret < 0) ? ret : -EIO; + + memcpy(msg->buf, rbuf->data, msg->len); + + return 0; +} + +static int usbio_i2c_write(struct i2c_adapter *adap, struct i2c_msg *msg) +{ + struct usbio_i2c *i2c = i2c_get_adapdata(adap); + u16 txchunk = i2c->txbuf_len - I2C_RW_OVERHEAD; + struct usbio_i2c_rw *wbuf = i2c->rwbuf; + int ret; + + if (msg->len > txchunk) { + /* Need to split the output buffer */ + u16 len = 0; + + do { + wbuf->busid = i2c->adev->id; + wbuf->config = cpu_to_le16(msg->addr); + + if (i2c->quirks & USBIO_QUIRK_I2C_USE_CHUNK_LEN) + wbuf->size = cpu_to_le16(txchunk); + else + wbuf->size = cpu_to_le16(msg->len); + + memcpy(wbuf->data, &msg->buf[len], txchunk); + len += txchunk; + + ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, + USBIO_I2CCMD_WRITE, msg->len == len, + wbuf, sizeof(*wbuf) + txchunk, + wbuf, sizeof(*wbuf)); + if (ret < 0) + return ret; + + if (msg->len - len < txchunk) + txchunk = msg->len - len; + } while (msg->len > len); + + return 0; + } + + wbuf->busid = i2c->adev->id; + wbuf->config = cpu_to_le16(msg->addr); + wbuf->size = cpu_to_le16(msg->len); + memcpy(wbuf->data, msg->buf, msg->len); + + ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_WRITE, true, + wbuf, sizeof(*wbuf) + msg->len, wbuf, sizeof(*wbuf)); + if (ret != sizeof(*wbuf) || le16_to_cpu(wbuf->size) != msg->len) + return (ret < 0) ? ret : -EIO; + + return 0; +} + +static int usbio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct usbio_i2c *i2c = i2c_get_adapdata(adap); + int ret; + + usbio_acquire(i2c->adev); + + ret = usbio_i2c_init(adap, msgs); + if (ret) + goto out_release; + + for (int i = 0; i < num; ret = ++i) { + if (msgs[i].flags & I2C_M_RD) + ret = usbio_i2c_read(adap, &msgs[i]); + else + ret = usbio_i2c_write(adap, &msgs[i]); + + if (ret) + break; + } + + usbio_i2c_uninit(adap, msgs); + +out_release: + usbio_release(i2c->adev); + + return ret; +} + +static u32 usbio_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_adapter_quirks usbio_i2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_NO_REP_START, + .max_read_len = SZ_4K, + .max_write_len = SZ_4K, +}; + +static const struct i2c_adapter_quirks usbio_i2c_quirks_max_rw_len52 = { + .flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_NO_REP_START, + .max_read_len = 52, + .max_write_len = 52, +}; + +static const struct i2c_algorithm usbio_i2c_algo = { + .master_xfer = usbio_i2c_xfer, + .functionality = usbio_i2c_func, +}; + +static int usbio_i2c_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *adev_id) +{ + struct usbio_i2c_bus_desc *i2c_desc; + struct device *dev = &adev->dev; + struct usbio_i2c *i2c; + u32 max_speed; + int ret; + + i2c_desc = dev_get_platdata(dev); + if (!i2c_desc) + return -EINVAL; + + i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->adev = adev; + + usbio_acpi_bind(i2c->adev, usbio_i2c_acpi_hids); + usbio_get_txrxbuf_len(i2c->adev, &i2c->txbuf_len, &i2c->rxbuf_len); + + i2c->rwbuf = devm_kzalloc(dev, max(i2c->txbuf_len, i2c->rxbuf_len), GFP_KERNEL); + if (!i2c->rwbuf) + return -ENOMEM; + + i2c->quirks = usbio_get_quirks(i2c->adev); + + max_speed = usbio_i2c_speeds[i2c_desc->caps & USBIO_I2C_BUS_MODE_CAP_MASK]; + if (max_speed < I2C_MAX_FAST_MODE_FREQ && + (i2c->quirks & USBIO_QUIRK_I2C_ALLOW_400KHZ)) + max_speed = I2C_MAX_FAST_MODE_FREQ; + + i2c->speed = i2c_acpi_find_bus_speed(dev); + if (!i2c->speed) + i2c->speed = I2C_MAX_STANDARD_MODE_FREQ; + else if (i2c->speed > max_speed) { + dev_warn(dev, "Invalid speed %u adjusting to bus max %u\n", + i2c->speed, max_speed); + i2c->speed = max_speed; + } + + i2c->adap.owner = THIS_MODULE; + i2c->adap.class = I2C_CLASS_HWMON; + i2c->adap.dev.parent = dev; + i2c->adap.algo = &usbio_i2c_algo; + + if (i2c->quirks & USBIO_QUIRK_I2C_MAX_RW_LEN_52) + i2c->adap.quirks = &usbio_i2c_quirks_max_rw_len52; + else + i2c->adap.quirks = &usbio_i2c_quirks; + + snprintf(i2c->adap.name, sizeof(i2c->adap.name), "%s.%d", + USBIO_I2C_CLIENT, i2c->adev->id); + + device_set_node(&i2c->adap.dev, dev_fwnode(&adev->dev)); + + auxiliary_set_drvdata(adev, i2c); + i2c_set_adapdata(&i2c->adap, i2c); + + ret = i2c_add_adapter(&i2c->adap); + if (ret) + return ret; + + if (has_acpi_companion(&i2c->adap.dev)) + acpi_dev_clear_dependencies(ACPI_COMPANION(&i2c->adap.dev)); + + return 0; +} + +static void usbio_i2c_remove(struct auxiliary_device *adev) +{ + struct usbio_i2c *i2c = auxiliary_get_drvdata(adev); + + i2c_del_adapter(&i2c->adap); +} + +static const struct auxiliary_device_id usbio_i2c_id_table[] = { + { "usbio.usbio-i2c" }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, usbio_i2c_id_table); + +static struct auxiliary_driver usbio_i2c_driver = { + .name = USBIO_I2C_CLIENT, + .probe = usbio_i2c_probe, + .remove = usbio_i2c_remove, + .id_table = usbio_i2c_id_table +}; +module_auxiliary_driver(usbio_i2c_driver); + +MODULE_DESCRIPTION("Intel USBIO I2C driver"); +MODULE_AUTHOR("Israel Cepeda "); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("USBIO"); From ddb473a51b4bf33d040d827ae9a8724ee5ef1a36 Mon Sep 17 00:00:00 2001 From: Guan-Yu Lin Date: Thu, 11 Sep 2025 14:20:13 +0000 Subject: [PATCH 1293/2711] usb: xhci-plat: separate dev_pm_ops for each pm_event Separate dev_pm_ops for different power events such as suspend, thaw, and hibernation. This is crucial when xhci-plat driver needs to adapt its behavior based on different power state changes. Signed-off-by: Guan-Yu Lin Link: https://lore.kernel.org/r/20250911142051.90822-2-guanyulin@google.com Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250911142051.90822-2-guanyulin@google.com --- drivers/usb/host/xhci-plat.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 5eb51797de32..df2e942ad5f7 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -454,7 +454,7 @@ void xhci_plat_remove(struct platform_device *dev) } EXPORT_SYMBOL_GPL(xhci_plat_remove); -static int xhci_plat_suspend(struct device *dev) +static int xhci_plat_suspend_common(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -482,6 +482,16 @@ static int xhci_plat_suspend(struct device *dev) return 0; } +static int xhci_plat_suspend(struct device *dev) +{ + return xhci_plat_suspend_common(dev); +} + +static int xhci_plat_freeze(struct device *dev) +{ + return xhci_plat_suspend_common(dev); +} + static int xhci_plat_resume_common(struct device *dev, bool power_lost) { struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -529,6 +539,11 @@ static int xhci_plat_resume(struct device *dev) return xhci_plat_resume_common(dev, false); } +static int xhci_plat_thaw(struct device *dev) +{ + return xhci_plat_resume_common(dev, false); +} + static int xhci_plat_restore(struct device *dev) { return xhci_plat_resume_common(dev, true); @@ -558,9 +573,9 @@ static int __maybe_unused xhci_plat_runtime_resume(struct device *dev) const struct dev_pm_ops xhci_plat_pm_ops = { .suspend = pm_sleep_ptr(xhci_plat_suspend), .resume = pm_sleep_ptr(xhci_plat_resume), - .freeze = pm_sleep_ptr(xhci_plat_suspend), - .thaw = pm_sleep_ptr(xhci_plat_resume), - .poweroff = pm_sleep_ptr(xhci_plat_suspend), + .freeze = pm_sleep_ptr(xhci_plat_freeze), + .thaw = pm_sleep_ptr(xhci_plat_thaw), + .poweroff = pm_sleep_ptr(xhci_plat_freeze), .restore = pm_sleep_ptr(xhci_plat_restore), SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend, From 7f70b89b2be66c03ddc76d3ad8aebeeec4a9c505 Mon Sep 17 00:00:00 2001 From: Guan-Yu Lin Date: Thu, 11 Sep 2025 14:20:14 +0000 Subject: [PATCH 1294/2711] usb: offload: add apis for offload usage tracking Introduce offload_usage and corresponding apis to track offload usage on each USB device. Offload denotes that there is another co-processor accessing the USB device via the same USB host controller. To optimize power usage, it's essential to monitor whether the USB device is actively used by other co-processor. This information is vital when determining if a USB device can be safely suspended during system power state transitions. Signed-off-by: Guan-Yu Lin Link: https://lore.kernel.org/r/20250911142051.90822-3-guanyulin@google.com Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250911142051.90822-3-guanyulin@google.com --- drivers/usb/core/Makefile | 1 + drivers/usb/core/offload.c | 136 +++++++++++++++++++++++++++++++++++++ drivers/usb/core/usb.c | 1 + include/linux/usb.h | 18 +++++ 4 files changed, 156 insertions(+) create mode 100644 drivers/usb/core/offload.c diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index ac006abd13b3..766000b4939e 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -9,6 +9,7 @@ usbcore-y += devio.o notify.o generic.o quirks.o devices.o usbcore-y += phy.o port.o usbcore-$(CONFIG_OF) += of.o +usbcore-$(CONFIG_USB_XHCI_SIDEBAND) += offload.o usbcore-$(CONFIG_USB_PCI) += hcd-pci.o usbcore-$(CONFIG_ACPI) += usb-acpi.o diff --git a/drivers/usb/core/offload.c b/drivers/usb/core/offload.c new file mode 100644 index 000000000000..7c699f1b8d2b --- /dev/null +++ b/drivers/usb/core/offload.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * offload.c - USB offload related functions + * + * Copyright (c) 2025, Google LLC. + * + * Author: Guan-Yu Lin + */ + +#include + +#include "usb.h" + +/** + * usb_offload_get - increment the offload_usage of a USB device + * @udev: the USB device to increment its offload_usage + * + * Incrementing the offload_usage of a usb_device indicates that offload is + * enabled on this usb_device; that is, another entity is actively handling USB + * transfers. This information allows the USB driver to adjust its power + * management policy based on offload activity. + * + * Return: 0 on success. A negative error code otherwise. + */ +int usb_offload_get(struct usb_device *udev) +{ + int ret; + + usb_lock_device(udev); + if (udev->state == USB_STATE_NOTATTACHED) { + usb_unlock_device(udev); + return -ENODEV; + } + + if (udev->state == USB_STATE_SUSPENDED || + udev->offload_at_suspend) { + usb_unlock_device(udev); + return -EBUSY; + } + + /* + * offload_usage could only be modified when the device is active, since + * it will alter the suspend flow of the device. + */ + ret = usb_autoresume_device(udev); + if (ret < 0) { + usb_unlock_device(udev); + return ret; + } + + udev->offload_usage++; + usb_autosuspend_device(udev); + usb_unlock_device(udev); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_offload_get); + +/** + * usb_offload_put - drop the offload_usage of a USB device + * @udev: the USB device to drop its offload_usage + * + * The inverse operation of usb_offload_get, which drops the offload_usage of + * a USB device. This information allows the USB driver to adjust its power + * management policy based on offload activity. + * + * Return: 0 on success. A negative error code otherwise. + */ +int usb_offload_put(struct usb_device *udev) +{ + int ret; + + usb_lock_device(udev); + if (udev->state == USB_STATE_NOTATTACHED) { + usb_unlock_device(udev); + return -ENODEV; + } + + if (udev->state == USB_STATE_SUSPENDED || + udev->offload_at_suspend) { + usb_unlock_device(udev); + return -EBUSY; + } + + /* + * offload_usage could only be modified when the device is active, since + * it will alter the suspend flow of the device. + */ + ret = usb_autoresume_device(udev); + if (ret < 0) { + usb_unlock_device(udev); + return ret; + } + + /* Drop the count when it wasn't 0, ignore the operation otherwise. */ + if (udev->offload_usage) + udev->offload_usage--; + usb_autosuspend_device(udev); + usb_unlock_device(udev); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_offload_put); + +/** + * usb_offload_check - check offload activities on a USB device + * @udev: the USB device to check its offload activity. + * + * Check if there are any offload activity on the USB device right now. This + * information could be used for power management or other forms of resource + * management. + * + * The caller must hold @udev's device lock. In addition, the caller should + * ensure downstream usb devices are all either suspended or marked as + * "offload_at_suspend" to ensure the correctness of the return value. + * + * Returns true on any offload activity, false otherwise. + */ +bool usb_offload_check(struct usb_device *udev) __must_hold(&udev->dev->mutex) +{ + struct usb_device *child; + bool active; + int port1; + + usb_hub_for_each_child(udev, port1, child) { + usb_lock_device(child); + active = usb_offload_check(child); + usb_unlock_device(child); + if (active) + return true; + } + + return !!udev->offload_usage; +} +EXPORT_SYMBOL_GPL(usb_offload_check); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index b88b6271cb30..b6b0b8489523 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -670,6 +670,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, set_dev_node(&dev->dev, dev_to_node(bus->sysdev)); dev->state = USB_STATE_ATTACHED; dev->lpm_disable_count = 1; + dev->offload_usage = 0; atomic_set(&dev->urbnum, 0); INIT_LIST_HEAD(&dev->ep0.urb_list); diff --git a/include/linux/usb.h b/include/linux/usb.h index 70ef00c42d22..e85105939af8 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -636,6 +636,8 @@ struct usb3_lpm_parameters { * @do_remote_wakeup: remote wakeup should be enabled * @reset_resume: needs reset instead of resume * @port_is_suspended: the upstream port is suspended (L2 or U3) + * @offload_at_suspend: offload activities during suspend is enabled. + * @offload_usage: number of offload activities happening on this usb device. * @slot_id: Slot ID assigned by xHCI * @l1_params: best effor service latency for USB2 L1 LPM state, and L1 timeout. * @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout. @@ -724,6 +726,8 @@ struct usb_device { unsigned do_remote_wakeup:1; unsigned reset_resume:1; unsigned port_is_suspended:1; + unsigned offload_at_suspend:1; + int offload_usage; enum usb_link_tunnel_mode tunnel_mode; struct device_link *usb4_link; @@ -841,6 +845,20 @@ static inline void usb_mark_last_busy(struct usb_device *udev) { } #endif +#if IS_ENABLED(CONFIG_USB_XHCI_SIDEBAND) +int usb_offload_get(struct usb_device *udev); +int usb_offload_put(struct usb_device *udev); +bool usb_offload_check(struct usb_device *udev); +#else + +static inline int usb_offload_get(struct usb_device *udev) +{ return 0; } +static inline int usb_offload_put(struct usb_device *udev) +{ return 0; } +static inline bool usb_offload_check(struct usb_device *udev) +{ return false; } +#endif + extern int usb_disable_lpm(struct usb_device *udev); extern void usb_enable_lpm(struct usb_device *udev); /* Same as above, but these functions lock/unlock the bandwidth_mutex. */ From ef82a4803aabaf623bfcae07981406f1386eabf9 Mon Sep 17 00:00:00 2001 From: Guan-Yu Lin Date: Thu, 11 Sep 2025 14:20:15 +0000 Subject: [PATCH 1295/2711] xhci: sideband: add api to trace sideband usage The existing sideband driver only registers sidebands without tracking their active usage. To address this, sideband will now record its active usage when it creates/removes interrupters. In addition, a new api is introduced to provide a means for other dirvers to fetch sideband activity information on a USB host controller. Signed-off-by: Guan-Yu Lin Link: https://lore.kernel.org/r/20250911142051.90822-4-guanyulin@google.com Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250911142051.90822-4-guanyulin@google.com --- drivers/usb/host/xhci-sideband.c | 36 +++++++++++++++++++++++++++++++ include/linux/usb/xhci-sideband.h | 9 ++++++++ 2 files changed, 45 insertions(+) diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c index d49f9886dd84..e771a476fef2 100644 --- a/drivers/usb/host/xhci-sideband.c +++ b/drivers/usb/host/xhci-sideband.c @@ -266,6 +266,31 @@ xhci_sideband_get_event_buffer(struct xhci_sideband *sb) } EXPORT_SYMBOL_GPL(xhci_sideband_get_event_buffer); +/** + * xhci_sideband_check - check the existence of active sidebands + * @hcd: the host controller driver associated with the target host controller + * + * Allow other drivers, such as usb controller driver, to check if there are + * any sideband activity on the host controller. This information could be used + * for power management or other forms of resource management. The caller should + * ensure downstream usb devices are all either suspended or marked as + * "offload_at_suspend" to ensure the correctness of the return value. + * + * Returns true on any active sideband existence, false otherwise. + */ +bool xhci_sideband_check(struct usb_hcd *hcd) +{ + struct usb_device *udev = hcd->self.root_hub; + bool active; + + usb_lock_device(udev); + active = usb_offload_check(udev); + usb_unlock_device(udev); + + return active; +} +EXPORT_SYMBOL_GPL(xhci_sideband_check); + /** * xhci_sideband_create_interrupter - creates a new interrupter for this sideband * @sb: sideband instance for this usb device @@ -286,6 +311,7 @@ xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg, bool ip_autoclear, u32 imod_interval, int intr_num) { int ret = 0; + struct usb_device *udev; if (!sb || !sb->xhci) return -ENODEV; @@ -304,6 +330,9 @@ xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg, goto out; } + udev = sb->vdev->udev; + ret = usb_offload_get(udev); + sb->ir->ip_autoclear = ip_autoclear; out: @@ -323,6 +352,8 @@ EXPORT_SYMBOL_GPL(xhci_sideband_create_interrupter); void xhci_sideband_remove_interrupter(struct xhci_sideband *sb) { + struct usb_device *udev; + if (!sb || !sb->ir) return; @@ -330,6 +361,11 @@ xhci_sideband_remove_interrupter(struct xhci_sideband *sb) xhci_remove_secondary_interrupter(xhci_to_hcd(sb->xhci), sb->ir); sb->ir = NULL; + udev = sb->vdev->udev; + + if (udev->state != USB_STATE_NOTATTACHED) + usb_offload_put(udev); + mutex_unlock(&sb->mutex); } EXPORT_SYMBOL_GPL(xhci_sideband_remove_interrupter); diff --git a/include/linux/usb/xhci-sideband.h b/include/linux/usb/xhci-sideband.h index 45288c392f6e..005257085dcb 100644 --- a/include/linux/usb/xhci-sideband.h +++ b/include/linux/usb/xhci-sideband.h @@ -11,6 +11,7 @@ #include #include +#include #define EP_CTX_PER_DEV 31 /* FIXME defined twice, from xhci.h */ @@ -83,6 +84,14 @@ xhci_sideband_get_endpoint_buffer(struct xhci_sideband *sb, struct usb_host_endpoint *host_ep); struct sg_table * xhci_sideband_get_event_buffer(struct xhci_sideband *sb); + +#if IS_ENABLED(CONFIG_USB_XHCI_SIDEBAND) +bool xhci_sideband_check(struct usb_hcd *hcd); +#else +static inline bool xhci_sideband_check(struct usb_hcd *hcd) +{ return false; } +#endif /* IS_ENABLED(CONFIG_USB_XHCI_SIDEBAND) */ + int xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg, bool ip_autoclear, u32 imod_interval, int intr_num); From 38d627bc8522a6a2fd6f9454c8b3b5d3848f5f03 Mon Sep 17 00:00:00 2001 From: Guan-Yu Lin Date: Thu, 11 Sep 2025 14:20:16 +0000 Subject: [PATCH 1296/2711] usb: host: enable USB offload during system sleep Sharing a USB controller with another entity via xhci-sideband driver creates power management complexities. To prevent the USB controller from being inadvertently deactivated while in use by the other entity, a usage-count based mechanism is implemented. This allows the system to manage power effectively, ensuring the controller remains available whenever needed. In order to maintain full functionality of an offloaded USB devices, several changes are made within the suspend flow of such devices: - skip usb_suspend_device() so that the port/hub are still active for USB transfers via offloaded path. - not suspending the endpoints which are used by USB interfaces marked with needs_remote_wakeup. Namely, skip usb_suspend_interface() and usb_hcd_flush_endpoint() on associated USB interfaces. This reserves a pending interrupt urb during system suspend for handling the interrupt transfer, which is necessary since remote wakeup doesn't apply in the offloaded USB devices when controller is still active. - not flushing the endpoints of actively offloaded USB devices. Given that the USB devices is used by another entity, unilaterally flush the endpoint might lead to unexpected behavior on another entity. - not suspending the xhci controller. This is done by skipping the suspend/resume callbacks in the xhci platform driver. Signed-off-by: Guan-Yu Lin Link: https://lore.kernel.org/r/20250911142051.90822-5-guanyulin@google.com Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250911142051.90822-5-guanyulin@google.com --- drivers/usb/core/driver.c | 50 +++++++++++++++++++++++++++++++----- drivers/usb/host/xhci-plat.c | 19 ++++++++++++++ drivers/usb/host/xhci-plat.h | 1 + 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 25358cf3e324..6418cfb0fb37 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1420,11 +1420,28 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) udev->state == USB_STATE_SUSPENDED) goto done; + if (msg.event == PM_EVENT_SUSPEND && usb_offload_check(udev)) { + dev_dbg(&udev->dev, "device offloaded, skip suspend.\n"); + udev->offload_at_suspend = 1; + } + /* Suspend all the interfaces and then udev itself */ if (udev->actconfig) { n = udev->actconfig->desc.bNumInterfaces; for (i = n - 1; i >= 0; --i) { intf = udev->actconfig->interface[i]; + /* + * Don't suspend interfaces with remote wakeup while + * the controller is active. This preserves pending + * interrupt urbs, allowing interrupt events to be + * handled during system suspend. + */ + if (udev->offload_at_suspend && + intf->needs_remote_wakeup) { + dev_dbg(&intf->dev, + "device offloaded, skip suspend.\n"); + continue; + } status = usb_suspend_interface(udev, intf, msg); /* Ignore errors during system sleep transitions */ @@ -1435,7 +1452,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) } } if (status == 0) { - status = usb_suspend_device(udev, msg); + if (!udev->offload_at_suspend) + status = usb_suspend_device(udev, msg); /* * Ignore errors from non-root-hub devices during @@ -1480,9 +1498,11 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) */ } else { udev->can_submit = 0; - for (i = 0; i < 16; ++i) { - usb_hcd_flush_endpoint(udev, udev->ep_out[i]); - usb_hcd_flush_endpoint(udev, udev->ep_in[i]); + if (!udev->offload_at_suspend) { + for (i = 0; i < 16; ++i) { + usb_hcd_flush_endpoint(udev, udev->ep_out[i]); + usb_hcd_flush_endpoint(udev, udev->ep_in[i]); + } } } @@ -1524,17 +1544,35 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) udev->can_submit = 1; /* Resume the device */ - if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume) - status = usb_resume_device(udev, msg); + if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume) { + if (!udev->offload_at_suspend) + status = usb_resume_device(udev, msg); + else + dev_dbg(&udev->dev, + "device offloaded, skip resume.\n"); + } /* Resume the interfaces */ if (status == 0 && udev->actconfig) { for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; + /* + * Interfaces with remote wakeup aren't suspended + * while the controller is active. This preserves + * pending interrupt urbs, allowing interrupt events + * to be handled during system suspend. + */ + if (udev->offload_at_suspend && + intf->needs_remote_wakeup) { + dev_dbg(&intf->dev, + "device offloaded, skip resume.\n"); + continue; + } usb_resume_interface(udev, intf, msg, udev->reset_resume); } } + udev->offload_at_suspend = 0; usb_mark_last_busy(udev); done: diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index df2e942ad5f7..3a56d8f94519 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "xhci.h" #include "xhci-plat.h" @@ -484,6 +485,15 @@ static int xhci_plat_suspend_common(struct device *dev) static int xhci_plat_suspend(struct device *dev) { + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (xhci_sideband_check(hcd)) { + priv->sideband_at_suspend = 1; + dev_dbg(dev, "sideband instance active, skip suspend.\n"); + return 0; + } + return xhci_plat_suspend_common(dev); } @@ -536,6 +546,15 @@ disable_clks: static int xhci_plat_resume(struct device *dev) { + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (priv->sideband_at_suspend) { + priv->sideband_at_suspend = 0; + dev_dbg(dev, "sideband instance active, skip resume.\n"); + return 0; + } + return xhci_plat_resume_common(dev, false); } diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h index fe4f95e690fa..2b32a93d2b76 100644 --- a/drivers/usb/host/xhci-plat.h +++ b/drivers/usb/host/xhci-plat.h @@ -16,6 +16,7 @@ struct xhci_plat_priv { const char *firmware_name; unsigned long long quirks; bool power_lost; + unsigned sideband_at_suspend:1; void (*plat_start)(struct usb_hcd *); int (*init_quirk)(struct usb_hcd *); int (*suspend_quirk)(struct usb_hcd *); From 7cbba32a2d62c3c18128c04f88b1901d702bb2bf Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 12 Sep 2025 14:12:00 +0100 Subject: [PATCH 1297/2711] slimbus: qcom: remove unused qcom controller driver Qcom Slimbus controller driver is totally unused and dead code, there is no point in keeping this driver in the kernel without users. This patch removes the driver along with device tree bindings. Signed-off-by: Srinivas Kandagatla Acked-by: Rob Herring (Arm) Acked-by: Dmitry Baryshkov Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131202.303026-2-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- .../bindings/slimbus/qcom,slim.yaml | 86 -- .../devicetree/bindings/slimbus/slimbus.yaml | 13 +- drivers/slimbus/Kconfig | 7 - drivers/slimbus/Makefile | 3 - drivers/slimbus/qcom-ctrl.c | 735 ------------------ 5 files changed, 4 insertions(+), 840 deletions(-) delete mode 100644 Documentation/devicetree/bindings/slimbus/qcom,slim.yaml delete mode 100644 drivers/slimbus/qcom-ctrl.c diff --git a/Documentation/devicetree/bindings/slimbus/qcom,slim.yaml b/Documentation/devicetree/bindings/slimbus/qcom,slim.yaml deleted file mode 100644 index 883bda58ca97..000000000000 --- a/Documentation/devicetree/bindings/slimbus/qcom,slim.yaml +++ /dev/null @@ -1,86 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/slimbus/qcom,slim.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm SoC SLIMbus controller - -maintainers: - - Krzysztof Kozlowski - - Srinivas Kandagatla - -description: - SLIMbus controller used when applications processor controls SLIMbus master - component. - -allOf: - - $ref: slimbus.yaml# - -properties: - compatible: - items: - - enum: - - qcom,apq8064-slim - - const: qcom,slim - - reg: - items: - - description: Physical address of controller register blocks - - description: SLEW RATE register - - reg-names: - items: - - const: ctrl - - const: slew - - clocks: - items: - - description: Interface clock for this controller - - description: Interrupt for controller core's BAM - - clock-names: - items: - - const: iface - - const: core - - interrupts: - maxItems: 1 - -required: - - compatible - - reg - - reg-names - - clocks - - clock-names - - interrupts - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - - soc { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - slim@28080000 { - compatible = "qcom,apq8064-slim", "qcom,slim"; - reg = <0x28080000 0x2000>, <0x80207c 4>; - reg-names = "ctrl", "slew"; - interrupts = ; - clocks = <&lcc SLIMBUS_SRC>, <&lcc AUDIO_SLIMBUS_CLK>; - clock-names = "iface", "core"; - #address-cells = <2>; - #size-cells = <0>; - - audio-codec@1,0 { - compatible = "slim217,60"; - reg = <1 0>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/slimbus/slimbus.yaml b/Documentation/devicetree/bindings/slimbus/slimbus.yaml index 3b8cae9d1016..89017d9cda10 100644 --- a/Documentation/devicetree/bindings/slimbus/slimbus.yaml +++ b/Documentation/devicetree/bindings/slimbus/slimbus.yaml @@ -68,8 +68,6 @@ additionalProperties: true examples: - | - #include - #include #include soc { @@ -78,17 +76,14 @@ examples: ranges; slim@28080000 { - compatible = "qcom,apq8064-slim", "qcom,slim"; - reg = <0x28080000 0x2000>, <0x80207c 4>; - reg-names = "ctrl", "slew"; - interrupts = ; - clocks = <&lcc SLIMBUS_SRC>, <&lcc AUDIO_SLIMBUS_CLK>; - clock-names = "iface", "core"; + compatible = "qcom,slim-ngd-v1.5.0"; + reg = <0x091c0000 0x2c000>; + interrupts = ; #address-cells = <2>; #size-cells = <0>; audio-codec@1,0 { - compatible = "slim217,60"; + compatible = "slim217,1a0"; reg = <1 0>; }; }; diff --git a/drivers/slimbus/Kconfig b/drivers/slimbus/Kconfig index a0fdf9d792cb..60b0dcbc0ebb 100644 --- a/drivers/slimbus/Kconfig +++ b/drivers/slimbus/Kconfig @@ -13,13 +13,6 @@ menuconfig SLIMBUS if SLIMBUS # SLIMbus controllers -config SLIM_QCOM_CTRL - tristate "Qualcomm SLIMbus Manager Component" - depends on HAS_IOMEM - help - Select driver if Qualcomm's SLIMbus Manager Component is - programmed using Linux kernel. - config SLIM_QCOM_NGD_CTRL tristate "Qualcomm SLIMbus Satellite Non-Generic Device Component" depends on HAS_IOMEM && DMA_ENGINE && NET diff --git a/drivers/slimbus/Makefile b/drivers/slimbus/Makefile index d9aa011b6804..3cfb41c3b592 100644 --- a/drivers/slimbus/Makefile +++ b/drivers/slimbus/Makefile @@ -6,8 +6,5 @@ obj-$(CONFIG_SLIMBUS) += slimbus.o slimbus-y := core.o messaging.o sched.o stream.o #Controllers -obj-$(CONFIG_SLIM_QCOM_CTRL) += slim-qcom-ctrl.o -slim-qcom-ctrl-y := qcom-ctrl.o - obj-$(CONFIG_SLIM_QCOM_NGD_CTRL) += slim-qcom-ngd-ctrl.o slim-qcom-ngd-ctrl-y := qcom-ngd-ctrl.o diff --git a/drivers/slimbus/qcom-ctrl.c b/drivers/slimbus/qcom-ctrl.c deleted file mode 100644 index ab344f7472f2..000000000000 --- a/drivers/slimbus/qcom-ctrl.c +++ /dev/null @@ -1,735 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2011-2017, The Linux Foundation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "slimbus.h" - -/* Manager registers */ -#define MGR_CFG 0x200 -#define MGR_STATUS 0x204 -#define MGR_INT_EN 0x210 -#define MGR_INT_STAT 0x214 -#define MGR_INT_CLR 0x218 -#define MGR_TX_MSG 0x230 -#define MGR_RX_MSG 0x270 -#define MGR_IE_STAT 0x2F0 -#define MGR_VE_STAT 0x300 -#define MGR_CFG_ENABLE 1 - -/* Framer registers */ -#define FRM_CFG 0x400 -#define FRM_STAT 0x404 -#define FRM_INT_EN 0x410 -#define FRM_INT_STAT 0x414 -#define FRM_INT_CLR 0x418 -#define FRM_WAKEUP 0x41C -#define FRM_CLKCTL_DONE 0x420 -#define FRM_IE_STAT 0x430 -#define FRM_VE_STAT 0x440 - -/* Interface registers */ -#define INTF_CFG 0x600 -#define INTF_STAT 0x604 -#define INTF_INT_EN 0x610 -#define INTF_INT_STAT 0x614 -#define INTF_INT_CLR 0x618 -#define INTF_IE_STAT 0x630 -#define INTF_VE_STAT 0x640 - -/* Interrupt status bits */ -#define MGR_INT_TX_NACKED_2 BIT(25) -#define MGR_INT_MSG_BUF_CONTE BIT(26) -#define MGR_INT_RX_MSG_RCVD BIT(30) -#define MGR_INT_TX_MSG_SENT BIT(31) - -/* Framer config register settings */ -#define FRM_ACTIVE 1 -#define CLK_GEAR 7 -#define ROOT_FREQ 11 -#define REF_CLK_GEAR 15 -#define INTR_WAKE 19 - -#define SLIM_MSG_ASM_FIRST_WORD(l, mt, mc, dt, ad) \ - ((l) | ((mt) << 5) | ((mc) << 8) | ((dt) << 15) | ((ad) << 16)) - -#define SLIM_ROOT_FREQ 24576000 -#define QCOM_SLIM_AUTOSUSPEND 1000 - -/* MAX message size over control channel */ -#define SLIM_MSGQ_BUF_LEN 40 -#define QCOM_TX_MSGS 2 -#define QCOM_RX_MSGS 8 -#define QCOM_BUF_ALLOC_RETRIES 10 - -#define CFG_PORT(r, v) ((v) ? CFG_PORT_V2(r) : CFG_PORT_V1(r)) - -/* V2 Component registers */ -#define CFG_PORT_V2(r) ((r ## _V2)) -#define COMP_CFG_V2 4 -#define COMP_TRUST_CFG_V2 0x3000 - -/* V1 Component registers */ -#define CFG_PORT_V1(r) ((r ## _V1)) -#define COMP_CFG_V1 0 -#define COMP_TRUST_CFG_V1 0x14 - -/* Resource group info for manager, and non-ported generic device-components */ -#define EE_MGR_RSC_GRP (1 << 10) -#define EE_NGD_2 (2 << 6) -#define EE_NGD_1 0 - -struct slim_ctrl_buf { - void *base; - spinlock_t lock; - int head; - int tail; - int sl_sz; - int n; -}; - -struct qcom_slim_ctrl { - struct slim_controller ctrl; - struct slim_framer framer; - struct device *dev; - void __iomem *base; - void __iomem *slew_reg; - - struct slim_ctrl_buf rx; - struct slim_ctrl_buf tx; - - struct completion **wr_comp; - int irq; - struct workqueue_struct *rxwq; - struct work_struct wd; - struct clk *rclk; - struct clk *hclk; -}; - -static void qcom_slim_queue_tx(struct qcom_slim_ctrl *ctrl, void *buf, - u8 len, u32 tx_reg) -{ - int count = (len + 3) >> 2; - - __iowrite32_copy(ctrl->base + tx_reg, buf, count); - - /* Ensure Oder of subsequent writes */ - mb(); -} - -static void *slim_alloc_rxbuf(struct qcom_slim_ctrl *ctrl) -{ - unsigned long flags; - int idx; - - spin_lock_irqsave(&ctrl->rx.lock, flags); - if ((ctrl->rx.tail + 1) % ctrl->rx.n == ctrl->rx.head) { - spin_unlock_irqrestore(&ctrl->rx.lock, flags); - dev_err(ctrl->dev, "RX QUEUE full!"); - return NULL; - } - idx = ctrl->rx.tail; - ctrl->rx.tail = (ctrl->rx.tail + 1) % ctrl->rx.n; - spin_unlock_irqrestore(&ctrl->rx.lock, flags); - - return ctrl->rx.base + (idx * ctrl->rx.sl_sz); -} - -static void slim_ack_txn(struct qcom_slim_ctrl *ctrl, int err) -{ - struct completion *comp; - unsigned long flags; - int idx; - - spin_lock_irqsave(&ctrl->tx.lock, flags); - idx = ctrl->tx.head; - ctrl->tx.head = (ctrl->tx.head + 1) % ctrl->tx.n; - spin_unlock_irqrestore(&ctrl->tx.lock, flags); - - comp = ctrl->wr_comp[idx]; - ctrl->wr_comp[idx] = NULL; - - complete(comp); -} - -static irqreturn_t qcom_slim_handle_tx_irq(struct qcom_slim_ctrl *ctrl, - u32 stat) -{ - int err = 0; - - if (stat & MGR_INT_TX_MSG_SENT) - writel_relaxed(MGR_INT_TX_MSG_SENT, - ctrl->base + MGR_INT_CLR); - - if (stat & MGR_INT_TX_NACKED_2) { - u32 mgr_stat = readl_relaxed(ctrl->base + MGR_STATUS); - u32 mgr_ie_stat = readl_relaxed(ctrl->base + MGR_IE_STAT); - u32 frm_stat = readl_relaxed(ctrl->base + FRM_STAT); - u32 frm_cfg = readl_relaxed(ctrl->base + FRM_CFG); - u32 frm_intr_stat = readl_relaxed(ctrl->base + FRM_INT_STAT); - u32 frm_ie_stat = readl_relaxed(ctrl->base + FRM_IE_STAT); - u32 intf_stat = readl_relaxed(ctrl->base + INTF_STAT); - u32 intf_intr_stat = readl_relaxed(ctrl->base + INTF_INT_STAT); - u32 intf_ie_stat = readl_relaxed(ctrl->base + INTF_IE_STAT); - - writel_relaxed(MGR_INT_TX_NACKED_2, ctrl->base + MGR_INT_CLR); - - dev_err(ctrl->dev, "TX Nack MGR:int:0x%x, stat:0x%x\n", - stat, mgr_stat); - dev_err(ctrl->dev, "TX Nack MGR:ie:0x%x\n", mgr_ie_stat); - dev_err(ctrl->dev, "TX Nack FRM:int:0x%x, stat:0x%x\n", - frm_intr_stat, frm_stat); - dev_err(ctrl->dev, "TX Nack FRM:cfg:0x%x, ie:0x%x\n", - frm_cfg, frm_ie_stat); - dev_err(ctrl->dev, "TX Nack INTF:intr:0x%x, stat:0x%x\n", - intf_intr_stat, intf_stat); - dev_err(ctrl->dev, "TX Nack INTF:ie:0x%x\n", - intf_ie_stat); - err = -ENOTCONN; - } - - slim_ack_txn(ctrl, err); - - return IRQ_HANDLED; -} - -static irqreturn_t qcom_slim_handle_rx_irq(struct qcom_slim_ctrl *ctrl, - u32 stat) -{ - u32 *rx_buf, pkt[10]; - bool q_rx = false; - u8 mc, mt, len; - - pkt[0] = readl_relaxed(ctrl->base + MGR_RX_MSG); - mt = SLIM_HEADER_GET_MT(pkt[0]); - len = SLIM_HEADER_GET_RL(pkt[0]); - mc = SLIM_HEADER_GET_MC(pkt[0]>>8); - - /* - * this message cannot be handled by ISR, so - * let work-queue handle it - */ - if (mt == SLIM_MSG_MT_CORE && mc == SLIM_MSG_MC_REPORT_PRESENT) { - rx_buf = (u32 *)slim_alloc_rxbuf(ctrl); - if (!rx_buf) { - dev_err(ctrl->dev, "dropping RX:0x%x due to RX full\n", - pkt[0]); - goto rx_ret_irq; - } - rx_buf[0] = pkt[0]; - - } else { - rx_buf = pkt; - } - - __ioread32_copy(rx_buf + 1, ctrl->base + MGR_RX_MSG + 4, - DIV_ROUND_UP(len, 4)); - - switch (mc) { - - case SLIM_MSG_MC_REPORT_PRESENT: - q_rx = true; - break; - case SLIM_MSG_MC_REPLY_INFORMATION: - case SLIM_MSG_MC_REPLY_VALUE: - slim_msg_response(&ctrl->ctrl, (u8 *)(rx_buf + 1), - (u8)(*rx_buf >> 24), (len - 4)); - break; - default: - dev_err(ctrl->dev, "unsupported MC,%x MT:%x\n", - mc, mt); - break; - } -rx_ret_irq: - writel(MGR_INT_RX_MSG_RCVD, ctrl->base + - MGR_INT_CLR); - if (q_rx) - queue_work(ctrl->rxwq, &ctrl->wd); - - return IRQ_HANDLED; -} - -static irqreturn_t qcom_slim_interrupt(int irq, void *d) -{ - struct qcom_slim_ctrl *ctrl = d; - u32 stat = readl_relaxed(ctrl->base + MGR_INT_STAT); - int ret = IRQ_NONE; - - if (stat & MGR_INT_TX_MSG_SENT || stat & MGR_INT_TX_NACKED_2) - ret = qcom_slim_handle_tx_irq(ctrl, stat); - - if (stat & MGR_INT_RX_MSG_RCVD) - ret = qcom_slim_handle_rx_irq(ctrl, stat); - - return ret; -} - -static int qcom_clk_pause_wakeup(struct slim_controller *sctrl) -{ - struct qcom_slim_ctrl *ctrl = dev_get_drvdata(sctrl->dev); - - clk_prepare_enable(ctrl->hclk); - clk_prepare_enable(ctrl->rclk); - enable_irq(ctrl->irq); - - writel_relaxed(1, ctrl->base + FRM_WAKEUP); - /* Make sure framer wakeup write goes through before ISR fires */ - mb(); - /* - * HW Workaround: Currently, slave is reporting lost-sync messages - * after SLIMbus comes out of clock pause. - * Transaction with slave fail before slave reports that message - * Give some time for that report to come - * SLIMbus wakes up in clock gear 10 at 24.576MHz. With each superframe - * being 250 usecs, we wait for 5-10 superframes here to ensure - * we get the message - */ - usleep_range(1250, 2500); - return 0; -} - -static void *slim_alloc_txbuf(struct qcom_slim_ctrl *ctrl, - struct slim_msg_txn *txn, - struct completion *done) -{ - unsigned long flags; - int idx; - - spin_lock_irqsave(&ctrl->tx.lock, flags); - if (((ctrl->tx.head + 1) % ctrl->tx.n) == ctrl->tx.tail) { - spin_unlock_irqrestore(&ctrl->tx.lock, flags); - dev_err(ctrl->dev, "controller TX buf unavailable"); - return NULL; - } - idx = ctrl->tx.tail; - ctrl->wr_comp[idx] = done; - ctrl->tx.tail = (ctrl->tx.tail + 1) % ctrl->tx.n; - - spin_unlock_irqrestore(&ctrl->tx.lock, flags); - - return ctrl->tx.base + (idx * ctrl->tx.sl_sz); -} - - -static int qcom_xfer_msg(struct slim_controller *sctrl, - struct slim_msg_txn *txn) -{ - struct qcom_slim_ctrl *ctrl = dev_get_drvdata(sctrl->dev); - DECLARE_COMPLETION_ONSTACK(done); - void *pbuf = slim_alloc_txbuf(ctrl, txn, &done); - unsigned long ms = txn->rl + HZ; - u8 *puc; - int ret = 0, retries = QCOM_BUF_ALLOC_RETRIES; - unsigned long time_left; - u8 la = txn->la; - u32 *head; - /* HW expects length field to be excluded */ - txn->rl--; - - /* spin till buffer is made available */ - if (!pbuf) { - while (retries--) { - usleep_range(10000, 15000); - pbuf = slim_alloc_txbuf(ctrl, txn, &done); - if (pbuf) - break; - } - } - - if (retries < 0 && !pbuf) - return -ENOMEM; - - puc = (u8 *)pbuf; - head = (u32 *)pbuf; - - if (txn->dt == SLIM_MSG_DEST_LOGICALADDR) { - *head = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, - txn->mc, 0, la); - puc += 3; - } else { - *head = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, - txn->mc, 1, la); - puc += 2; - } - - if (slim_tid_txn(txn->mt, txn->mc)) - *(puc++) = txn->tid; - - if (slim_ec_txn(txn->mt, txn->mc)) { - *(puc++) = (txn->ec & 0xFF); - *(puc++) = (txn->ec >> 8) & 0xFF; - } - - if (txn->msg && txn->msg->wbuf) - memcpy(puc, txn->msg->wbuf, txn->msg->num_bytes); - - qcom_slim_queue_tx(ctrl, head, txn->rl, MGR_TX_MSG); - time_left = wait_for_completion_timeout(&done, msecs_to_jiffies(ms)); - - if (!time_left) { - dev_err(ctrl->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc, - txn->mt); - ret = -ETIMEDOUT; - } - - return ret; - -} - -static int qcom_set_laddr(struct slim_controller *sctrl, - struct slim_eaddr *ead, u8 laddr) -{ - struct qcom_slim_ctrl *ctrl = dev_get_drvdata(sctrl->dev); - struct { - __be16 manf_id; - __be16 prod_code; - u8 dev_index; - u8 instance; - u8 laddr; - } __packed p; - struct slim_val_inf msg = {0}; - DEFINE_SLIM_EDEST_TXN(txn, SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS, - 10, laddr, &msg); - int ret; - - p.manf_id = cpu_to_be16(ead->manf_id); - p.prod_code = cpu_to_be16(ead->prod_code); - p.dev_index = ead->dev_index; - p.instance = ead->instance; - p.laddr = laddr; - - msg.wbuf = (void *)&p; - msg.num_bytes = 7; - ret = slim_do_transfer(&ctrl->ctrl, &txn); - - if (ret) - dev_err(ctrl->dev, "set LA:0x%x failed:ret:%d\n", - laddr, ret); - return ret; -} - -static int slim_get_current_rxbuf(struct qcom_slim_ctrl *ctrl, void *buf) -{ - unsigned long flags; - - spin_lock_irqsave(&ctrl->rx.lock, flags); - if (ctrl->rx.tail == ctrl->rx.head) { - spin_unlock_irqrestore(&ctrl->rx.lock, flags); - return -ENODATA; - } - memcpy(buf, ctrl->rx.base + (ctrl->rx.head * ctrl->rx.sl_sz), - ctrl->rx.sl_sz); - - ctrl->rx.head = (ctrl->rx.head + 1) % ctrl->rx.n; - spin_unlock_irqrestore(&ctrl->rx.lock, flags); - - return 0; -} - -static void qcom_slim_rxwq(struct work_struct *work) -{ - u8 buf[SLIM_MSGQ_BUF_LEN]; - u8 mc, mt; - int ret; - struct qcom_slim_ctrl *ctrl = container_of(work, struct qcom_slim_ctrl, - wd); - - while ((slim_get_current_rxbuf(ctrl, buf)) != -ENODATA) { - mt = SLIM_HEADER_GET_MT(buf[0]); - mc = SLIM_HEADER_GET_MC(buf[1]); - if (mt == SLIM_MSG_MT_CORE && - mc == SLIM_MSG_MC_REPORT_PRESENT) { - struct slim_eaddr ea; - u8 laddr; - - ea.manf_id = be16_to_cpup((__be16 *)&buf[2]); - ea.prod_code = be16_to_cpup((__be16 *)&buf[4]); - ea.dev_index = buf[6]; - ea.instance = buf[7]; - - ret = slim_device_report_present(&ctrl->ctrl, &ea, - &laddr); - if (ret < 0) - dev_err(ctrl->dev, "assign laddr failed:%d\n", - ret); - } else { - dev_err(ctrl->dev, "unexpected message:mc:%x, mt:%x\n", - mc, mt); - } - } -} - -static void qcom_slim_prg_slew(struct platform_device *pdev, - struct qcom_slim_ctrl *ctrl) -{ - if (!ctrl->slew_reg) { - /* SLEW RATE register for this SLIMbus */ - ctrl->slew_reg = devm_platform_ioremap_resource_byname(pdev, "slew"); - if (IS_ERR(ctrl->slew_reg)) - return; - } - - writel_relaxed(1, ctrl->slew_reg); - /* Make sure SLIMbus-slew rate enabling goes through */ - wmb(); -} - -static int qcom_slim_probe(struct platform_device *pdev) -{ - struct qcom_slim_ctrl *ctrl; - struct slim_controller *sctrl; - int ret, ver; - - ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); - if (!ctrl) - return -ENOMEM; - - ctrl->hclk = devm_clk_get(&pdev->dev, "iface"); - if (IS_ERR(ctrl->hclk)) - return PTR_ERR(ctrl->hclk); - - ctrl->rclk = devm_clk_get(&pdev->dev, "core"); - if (IS_ERR(ctrl->rclk)) - return PTR_ERR(ctrl->rclk); - - ret = clk_set_rate(ctrl->rclk, SLIM_ROOT_FREQ); - if (ret) { - dev_err(&pdev->dev, "ref-clock set-rate failed:%d\n", ret); - return ret; - } - - ctrl->irq = platform_get_irq(pdev, 0); - if (ctrl->irq < 0) - return ctrl->irq; - - sctrl = &ctrl->ctrl; - sctrl->dev = &pdev->dev; - ctrl->dev = &pdev->dev; - platform_set_drvdata(pdev, ctrl); - dev_set_drvdata(ctrl->dev, ctrl); - - ctrl->base = devm_platform_ioremap_resource_byname(pdev, "ctrl"); - if (IS_ERR(ctrl->base)) - return PTR_ERR(ctrl->base); - - sctrl->set_laddr = qcom_set_laddr; - sctrl->xfer_msg = qcom_xfer_msg; - sctrl->wakeup = qcom_clk_pause_wakeup; - ctrl->tx.n = QCOM_TX_MSGS; - ctrl->tx.sl_sz = SLIM_MSGQ_BUF_LEN; - ctrl->rx.n = QCOM_RX_MSGS; - ctrl->rx.sl_sz = SLIM_MSGQ_BUF_LEN; - ctrl->wr_comp = kcalloc(QCOM_TX_MSGS, sizeof(struct completion *), - GFP_KERNEL); - if (!ctrl->wr_comp) - return -ENOMEM; - - spin_lock_init(&ctrl->rx.lock); - spin_lock_init(&ctrl->tx.lock); - INIT_WORK(&ctrl->wd, qcom_slim_rxwq); - ctrl->rxwq = create_singlethread_workqueue("qcom_slim_rx"); - if (!ctrl->rxwq) { - dev_err(ctrl->dev, "Failed to start Rx WQ\n"); - return -ENOMEM; - } - - ctrl->framer.rootfreq = SLIM_ROOT_FREQ / 8; - ctrl->framer.superfreq = - ctrl->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8; - sctrl->a_framer = &ctrl->framer; - sctrl->clkgear = SLIM_MAX_CLK_GEAR; - - qcom_slim_prg_slew(pdev, ctrl); - - ret = devm_request_irq(&pdev->dev, ctrl->irq, qcom_slim_interrupt, - IRQF_TRIGGER_HIGH, "qcom_slim_irq", ctrl); - if (ret) { - dev_err(&pdev->dev, "request IRQ failed\n"); - goto err_request_irq_failed; - } - - ret = clk_prepare_enable(ctrl->hclk); - if (ret) - goto err_hclk_enable_failed; - - ret = clk_prepare_enable(ctrl->rclk); - if (ret) - goto err_rclk_enable_failed; - - ctrl->tx.base = devm_kcalloc(&pdev->dev, ctrl->tx.n, ctrl->tx.sl_sz, - GFP_KERNEL); - if (!ctrl->tx.base) { - ret = -ENOMEM; - goto err; - } - - ctrl->rx.base = devm_kcalloc(&pdev->dev,ctrl->rx.n, ctrl->rx.sl_sz, - GFP_KERNEL); - if (!ctrl->rx.base) { - ret = -ENOMEM; - goto err; - } - - /* Register with framework before enabling frame, clock */ - ret = slim_register_controller(&ctrl->ctrl); - if (ret) { - dev_err(ctrl->dev, "error adding controller\n"); - goto err; - } - - ver = readl_relaxed(ctrl->base); - /* Version info in 16 MSbits */ - ver >>= 16; - /* Component register initialization */ - writel(1, ctrl->base + CFG_PORT(COMP_CFG, ver)); - writel((EE_MGR_RSC_GRP | EE_NGD_2 | EE_NGD_1), - ctrl->base + CFG_PORT(COMP_TRUST_CFG, ver)); - - writel((MGR_INT_TX_NACKED_2 | - MGR_INT_MSG_BUF_CONTE | MGR_INT_RX_MSG_RCVD | - MGR_INT_TX_MSG_SENT), ctrl->base + MGR_INT_EN); - writel(1, ctrl->base + MGR_CFG); - /* Framer register initialization */ - writel((1 << INTR_WAKE) | (0xA << REF_CLK_GEAR) | - (0xA << CLK_GEAR) | (1 << ROOT_FREQ) | (1 << FRM_ACTIVE) | 1, - ctrl->base + FRM_CFG); - writel(MGR_CFG_ENABLE, ctrl->base + MGR_CFG); - writel(1, ctrl->base + INTF_CFG); - writel(1, ctrl->base + CFG_PORT(COMP_CFG, ver)); - - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, QCOM_SLIM_AUTOSUSPEND); - pm_runtime_set_active(&pdev->dev); - pm_runtime_mark_last_busy(&pdev->dev); - pm_runtime_enable(&pdev->dev); - - dev_dbg(ctrl->dev, "QCOM SB controller is up:ver:0x%x!\n", ver); - return 0; - -err: - clk_disable_unprepare(ctrl->rclk); -err_rclk_enable_failed: - clk_disable_unprepare(ctrl->hclk); -err_hclk_enable_failed: -err_request_irq_failed: - destroy_workqueue(ctrl->rxwq); - return ret; -} - -static void qcom_slim_remove(struct platform_device *pdev) -{ - struct qcom_slim_ctrl *ctrl = platform_get_drvdata(pdev); - - pm_runtime_disable(&pdev->dev); - slim_unregister_controller(&ctrl->ctrl); - clk_disable_unprepare(ctrl->rclk); - clk_disable_unprepare(ctrl->hclk); - destroy_workqueue(ctrl->rxwq); -} - -/* - * If PM_RUNTIME is not defined, these 2 functions become helper - * functions to be called from system suspend/resume. - */ -#ifdef CONFIG_PM -static int qcom_slim_runtime_suspend(struct device *device) -{ - struct qcom_slim_ctrl *ctrl = dev_get_drvdata(device); - int ret; - - dev_dbg(device, "pm_runtime: suspending...\n"); - ret = slim_ctrl_clk_pause(&ctrl->ctrl, false, SLIM_CLK_UNSPECIFIED); - if (ret) { - dev_err(device, "clk pause not entered:%d", ret); - } else { - disable_irq(ctrl->irq); - clk_disable_unprepare(ctrl->hclk); - clk_disable_unprepare(ctrl->rclk); - } - return ret; -} - -static int qcom_slim_runtime_resume(struct device *device) -{ - struct qcom_slim_ctrl *ctrl = dev_get_drvdata(device); - int ret = 0; - - dev_dbg(device, "pm_runtime: resuming...\n"); - ret = slim_ctrl_clk_pause(&ctrl->ctrl, true, 0); - if (ret) - dev_err(device, "clk pause not exited:%d", ret); - return ret; -} -#endif - -#ifdef CONFIG_PM_SLEEP -static int qcom_slim_suspend(struct device *dev) -{ - int ret = 0; - - if (!pm_runtime_enabled(dev) || - (!pm_runtime_suspended(dev))) { - dev_dbg(dev, "system suspend"); - ret = qcom_slim_runtime_suspend(dev); - } - - return ret; -} - -static int qcom_slim_resume(struct device *dev) -{ - if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) { - int ret; - - dev_dbg(dev, "system resume"); - ret = qcom_slim_runtime_resume(dev); - if (!ret) { - pm_runtime_mark_last_busy(dev); - pm_request_autosuspend(dev); - } - return ret; - - } - return 0; -} -#endif /* CONFIG_PM_SLEEP */ - -static const struct dev_pm_ops qcom_slim_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(qcom_slim_suspend, qcom_slim_resume) - SET_RUNTIME_PM_OPS( - qcom_slim_runtime_suspend, - qcom_slim_runtime_resume, - NULL - ) -}; - -static const struct of_device_id qcom_slim_dt_match[] = { - { .compatible = "qcom,slim", }, - {} -}; -MODULE_DEVICE_TABLE(of, qcom_slim_dt_match); - -static struct platform_driver qcom_slim_driver = { - .probe = qcom_slim_probe, - .remove = qcom_slim_remove, - .driver = { - .name = "qcom_slim_ctrl", - .of_match_table = qcom_slim_dt_match, - .pm = &qcom_slim_dev_pm_ops, - }, -}; -module_platform_driver(qcom_slim_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Qualcomm SLIMbus Controller"); From 5c6794f16b22a0e66b5feffda39a81762ed27887 Mon Sep 17 00:00:00 2001 From: Qiang Liu Date: Fri, 12 Sep 2025 14:12:01 +0100 Subject: [PATCH 1298/2711] slimbus: messaging: Remove redundant code Assigning txn->comp to itself has no effect. Signed-off-by: Qiang Liu Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131202.303026-3-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/messaging.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/slimbus/messaging.c b/drivers/slimbus/messaging.c index 6f01d944f9c6..27ca16f00e77 100644 --- a/drivers/slimbus/messaging.c +++ b/drivers/slimbus/messaging.c @@ -143,8 +143,6 @@ int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn) if (!txn->msg->comp) txn->comp = &done; - else - txn->comp = txn->comp; } ret = ctrl->xfer_msg(ctrl, txn); From ae0de6333368fd8c4535f5dbdfe1b2660438e089 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Fri, 12 Sep 2025 14:12:02 +0100 Subject: [PATCH 1299/2711] slimbus: messaging: fix "transfered"->"transferred" Trivial fix to spelling mistake in comment text. Signed-off-by: Xichao Zhao Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131202.303026-4-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/messaging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/slimbus/messaging.c b/drivers/slimbus/messaging.c index 27ca16f00e77..e2dbe4a66b70 100644 --- a/drivers/slimbus/messaging.c +++ b/drivers/slimbus/messaging.c @@ -222,7 +222,7 @@ static u16 slim_slicesize(int code) /** * slim_xfer_msg() - Transfer a value info message on slim device * - * @sbdev: slim device to which this msg has to be transfered + * @sbdev: slim device to which this msg has to be transferred * @msg: value info message pointer * @mc: message code of the message * From 8de0848447b9d94db3c09e6aea62181ac1329706 Mon Sep 17 00:00:00 2001 From: Ling Xu Date: Fri, 12 Sep 2025 14:12:59 +0100 Subject: [PATCH 1300/2711] dt-bindings: misc: qcom,fastrpc: Add GDSP label There are some products which support GDSP remoteprocs. GDSP is General Purpose DSP where tasks can be offloaded. There are 2 GDSPs named gdsp0 and gdsp1. Add "gdsp0" and "gdsp1" as the new supported labels for GDSP fastrpc domains. Acked-by: Krzysztof Kozlowski Reviewed-by: Ekansh Gupta Signed-off-by: Ling Xu Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131302.303199-2-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml b/Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml index 0840a3d92513..3f6199fc9ae6 100644 --- a/Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml +++ b/Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml @@ -27,6 +27,8 @@ properties: - sdsp - cdsp - cdsp1 + - gdsp0 + - gdsp1 memory-region: maxItems: 1 From d81c041ed5e444233daaa2d4b0f9ae4008c57f59 Mon Sep 17 00:00:00 2001 From: Ling Xu Date: Fri, 12 Sep 2025 14:13:00 +0100 Subject: [PATCH 1301/2711] misc: fastrpc: Remove kernel-side domain checks from capability ioctl Domain ID in the uAPI is misleading. Remove checks and log messages related to 'domain' field in capability structure. Update UAPI to mark the field as unused. Reviewed-by: Dmitry Baryshkov Reviewed-by: Ekansh Gupta Signed-off-by: Ling Xu Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131302.303199-3-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 14 +------------- include/uapi/misc/fastrpc.h | 2 +- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 53e88a1bc430..2dfcf8a66806 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -1723,7 +1723,6 @@ static int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap, uint32_t attribute_id = cap->attribute_id; uint32_t *dsp_attributes; unsigned long flags; - uint32_t domain = cap->domain; int err; spin_lock_irqsave(&cctx->lock, flags); @@ -1741,7 +1740,7 @@ static int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap, err = fastrpc_get_info_from_dsp(fl, dsp_attributes, FASTRPC_MAX_DSP_ATTRIBUTES); if (err == DSP_UNSUPPORTED_API) { dev_info(&cctx->rpdev->dev, - "Warning: DSP capabilities not supported on domain: %d\n", domain); + "Warning: DSP capabilities not supported\n"); kfree(dsp_attributes); return -EOPNOTSUPP; } else if (err) { @@ -1769,17 +1768,6 @@ static int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp) return -EFAULT; cap.capability = 0; - if (cap.domain >= FASTRPC_DEV_MAX) { - dev_err(&fl->cctx->rpdev->dev, "Error: Invalid domain id:%d, err:%d\n", - cap.domain, err); - return -ECHRNG; - } - - /* Fastrpc Capablities does not support modem domain */ - if (cap.domain == MDSP_DOMAIN_ID) { - dev_err(&fl->cctx->rpdev->dev, "Error: modem not supported %d\n", err); - return -ECHRNG; - } if (cap.attribute_id >= FASTRPC_MAX_DSP_ATTRIBUTES) { dev_err(&fl->cctx->rpdev->dev, "Error: invalid attribute: %d, err: %d\n", diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h index f33d914d8f46..c6e2925f47e6 100644 --- a/include/uapi/misc/fastrpc.h +++ b/include/uapi/misc/fastrpc.h @@ -134,7 +134,7 @@ struct fastrpc_mem_unmap { }; struct fastrpc_ioctl_capability { - __u32 domain; + __u32 unused; /* deprecated, ignored by the kernel */ __u32 attribute_id; __u32 capability; /* dsp capability */ __u32 reserved[4]; From fb4679f628956e09467e66835025f9a9bcead238 Mon Sep 17 00:00:00 2001 From: Ling Xu Date: Fri, 12 Sep 2025 14:13:01 +0100 Subject: [PATCH 1302/2711] misc: fastrpc: Cleanup the domain names Currently the domain ids are added for each instance of domains, this is totally not scalable approach. Clean this mess and create domain ids for only domains not its instances. Co-developed-by: Srinivas Kandagatla Signed-off-by: Srinivas Kandagatla Reviewed-by: Dmitry Baryshkov Reviewed-by: Ekansh Gupta Signed-off-by: Ling Xu Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131302.303199-4-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 2dfcf8a66806..5fc7dec65ed8 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -27,8 +27,6 @@ #define MDSP_DOMAIN_ID (1) #define SDSP_DOMAIN_ID (2) #define CDSP_DOMAIN_ID (3) -#define CDSP1_DOMAIN_ID (4) -#define FASTRPC_DEV_MAX 5 /* adsp, mdsp, slpi, cdsp, cdsp1 */ #define FASTRPC_MAX_SESSIONS 14 #define FASTRPC_MAX_VMIDS 16 #define FASTRPC_ALIGN 128 @@ -106,8 +104,6 @@ #define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev) -static const char *domains[FASTRPC_DEV_MAX] = { "adsp", "mdsp", - "sdsp", "cdsp", "cdsp1" }; struct fastrpc_phy_page { u64 addr; /* physical address */ u64 size; /* size of contiguous region */ @@ -2243,6 +2239,20 @@ static int fastrpc_device_register(struct device *dev, struct fastrpc_channel_ct return err; } +static int fastrpc_get_domain_id(const char *domain) +{ + if (!strncmp(domain, "adsp", 4)) + return ADSP_DOMAIN_ID; + else if (!strncmp(domain, "cdsp", 4)) + return CDSP_DOMAIN_ID; + else if (!strncmp(domain, "mdsp", 4)) + return MDSP_DOMAIN_ID; + else if (!strncmp(domain, "sdsp", 4)) + return SDSP_DOMAIN_ID; + + return -EINVAL; +} + static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) { struct device *rdev = &rpdev->dev; @@ -2258,15 +2268,10 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) return err; } - for (i = 0; i < FASTRPC_DEV_MAX; i++) { - if (!strcmp(domains[i], domain)) { - domain_id = i; - break; - } - } + domain_id = fastrpc_get_domain_id(domain); if (domain_id < 0) { - dev_info(rdev, "FastRPC Invalid Domain ID %d\n", domain_id); + dev_info(rdev, "FastRPC Domain %s not supported\n", domain); return -EINVAL; } @@ -2313,21 +2318,20 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) case ADSP_DOMAIN_ID: case MDSP_DOMAIN_ID: case SDSP_DOMAIN_ID: - /* Unsigned PD offloading is only supported on CDSP and CDSP1 */ + /* Unsigned PD offloading is only supported on CDSP */ data->unsigned_support = false; - err = fastrpc_device_register(rdev, data, secure_dsp, domains[domain_id]); + err = fastrpc_device_register(rdev, data, secure_dsp, domain); if (err) goto err_free_data; break; case CDSP_DOMAIN_ID: - case CDSP1_DOMAIN_ID: data->unsigned_support = true; /* Create both device nodes so that we can allow both Signed and Unsigned PD */ - err = fastrpc_device_register(rdev, data, true, domains[domain_id]); + err = fastrpc_device_register(rdev, data, true, domain); if (err) goto err_free_data; - err = fastrpc_device_register(rdev, data, false, domains[domain_id]); + err = fastrpc_device_register(rdev, data, false, domain); if (err) goto err_deregister_fdev; break; From 698de37f78c7c0100f5506df36871c64588636e9 Mon Sep 17 00:00:00 2001 From: Ling Xu Date: Fri, 12 Sep 2025 14:13:02 +0100 Subject: [PATCH 1303/2711] misc: fastrpc: add support for gdsp remoteproc Some platforms (like lemans) feature one or more GPDSPs (General Purpose DSPs). Similar to other kinds of Hexagon DSPs, they provide a FastRPC implementation, allowing code execution in both signed and unsigned protection domains. Extend the checks to allow domain names starting with "gdsp" (possibly followed by an index). Reviewed-by: Dmitry Baryshkov Reviewed-by: Ekansh Gupta Signed-off-by: Ling Xu Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131302.303199-5-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 5fc7dec65ed8..8e1d97873423 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -27,6 +27,7 @@ #define MDSP_DOMAIN_ID (1) #define SDSP_DOMAIN_ID (2) #define CDSP_DOMAIN_ID (3) +#define GDSP_DOMAIN_ID (4) #define FASTRPC_MAX_SESSIONS 14 #define FASTRPC_MAX_VMIDS 16 #define FASTRPC_ALIGN 128 @@ -2249,6 +2250,8 @@ static int fastrpc_get_domain_id(const char *domain) return MDSP_DOMAIN_ID; else if (!strncmp(domain, "sdsp", 4)) return SDSP_DOMAIN_ID; + else if (!strncmp(domain, "gdsp", 4)) + return GDSP_DOMAIN_ID; return -EINVAL; } @@ -2318,13 +2321,14 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) case ADSP_DOMAIN_ID: case MDSP_DOMAIN_ID: case SDSP_DOMAIN_ID: - /* Unsigned PD offloading is only supported on CDSP */ + /* Unsigned PD offloading is only supported on CDSP and GDSP */ data->unsigned_support = false; err = fastrpc_device_register(rdev, data, secure_dsp, domain); if (err) goto err_free_data; break; case CDSP_DOMAIN_ID: + case GDSP_DOMAIN_ID: data->unsigned_support = true; /* Create both device nodes so that we can allow both Signed and Unsigned PD */ err = fastrpc_device_register(rdev, data, true, domain); From 9b58f88a1f48b75e98ebb03490340c48b54cb804 Mon Sep 17 00:00:00 2001 From: Ciprian Costea Date: Fri, 12 Sep 2025 14:14:11 +0100 Subject: [PATCH 1304/2711] dt-bindings: nvmem: Add the nxp,s32g-ocotp yaml file Add bindings to expose the On Chip One-Time Programmable Controller (OCOTP) for the NXP s32g chipset. There are three versions of this chip but they're compatible so we can fall back to the nxp,s32g2-ocotp compatible. Signed-off-by: Ciprian Costea Signed-off-by: Dan Carpenter Reviewed-by: Rob Herring (Arm) Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131415.303407-2-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- .../bindings/nvmem/nxp,s32g-ocotp-nvmem.yaml | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/nvmem/nxp,s32g-ocotp-nvmem.yaml diff --git a/Documentation/devicetree/bindings/nvmem/nxp,s32g-ocotp-nvmem.yaml b/Documentation/devicetree/bindings/nvmem/nxp,s32g-ocotp-nvmem.yaml new file mode 100644 index 000000000000..8d46e7d28da6 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/nxp,s32g-ocotp-nvmem.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/nxp,s32g-ocotp-nvmem.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP S32G OCOTP NVMEM driver + +maintainers: + - Ciprian Costea + +description: + The drivers provides an interface to access One Time + Programmable memory pages, such as TMU fuse values. + +properties: + compatible: + oneOf: + - enum: + - nxp,s32g2-ocotp + - items: + - enum: + - nxp,s32g3-ocotp + - nxp,s32r45-ocotp + - const: nxp,s32g2-ocotp + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +allOf: + - $ref: nvmem.yaml# + +examples: + - | + nvmem@400a4000 { + compatible = "nxp,s32g2-ocotp"; + reg = <0x400a4000 0x400>; + #address-cells = <1>; + #size-cells = <1>; + }; From 5a356145e9683ec0b4cba6e455b6370d4fcbcd68 Mon Sep 17 00:00:00 2001 From: Ciprian Costea Date: Fri, 12 Sep 2025 14:14:12 +0100 Subject: [PATCH 1305/2711] nvmem: s32g-ocotp: Add driver for S32G OCOTP Provide access to the On Chip One-Time Programmable Controller (OCOTP) pages on the NXP S32G platform. Signed-off-by: Ciprian Costea Co-developed-by: Ghennadi Procopciuc Signed-off-by: Ghennadi Procopciuc Co-developed-by: Larisa Grigore Signed-off-by: Larisa Grigore Signed-off-by: Dan Carpenter Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131415.303407-3-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/Kconfig | 10 ++++ drivers/nvmem/Makefile | 2 + drivers/nvmem/s32g-ocotp-nvmem.c | 100 +++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 drivers/nvmem/s32g-ocotp-nvmem.c diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index edd811444ce5..f3b8ffa77528 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -240,6 +240,16 @@ config NVMEM_NINTENDO_OTP This driver can also be built as a module. If so, the module will be called nvmem-nintendo-otp. +config NVMEM_S32G_OCOTP + tristate "S32G SoC OCOTP support" + depends on ARCH_S32 + help + This is a driver for the 'OCOTP' peripheral available on S32G + platforms. + + If you say Y here, you will get support for the One Time + Programmable memory pages. + config NVMEM_QCOM_QFPROM tristate "QCOM QFPROM Support" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 2021d59688db..5634945f8196 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -79,6 +79,8 @@ obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o nvmem_sunplus_ocotp-y := sunplus-ocotp.o obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o nvmem_sunxi_sid-y := sunxi_sid.o +obj-$(CONFIG_NVMEM_S32G_OCOTP) += nvmem-s32g-ocotp-nvmem.o +nvmem-s32g-ocotp-nvmem-y := s32g-ocotp-nvmem.o obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o nvmem_u-boot-env-y := u-boot-env.o obj-$(CONFIG_NVMEM_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o diff --git a/drivers/nvmem/s32g-ocotp-nvmem.c b/drivers/nvmem/s32g-ocotp-nvmem.c new file mode 100644 index 000000000000..119871ab3a94 --- /dev/null +++ b/drivers/nvmem/s32g-ocotp-nvmem.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2023-2025 NXP + */ + +#include +#include +#include +#include +#include +#include +#include + +struct s32g_ocotp_priv { + struct device *dev; + void __iomem *base; +}; + +static int s32g_ocotp_read(void *context, unsigned int offset, + void *val, size_t bytes) +{ + struct s32g_ocotp_priv *s32g_data = context; + u32 *dst = val; + + while (bytes >= sizeof(u32)) { + *dst++ = ioread32(s32g_data->base + offset); + + bytes -= sizeof(u32); + offset += sizeof(u32); + } + + return 0; +} + +static struct nvmem_keepout s32g_keepouts[] = { + { .start = 0, .end = 520 }, + { .start = 540, .end = 564 }, + { .start = 596, .end = 664 }, + { .start = 668, .end = 676 }, + { .start = 684, .end = 732 }, + { .start = 744, .end = 864 }, + { .start = 908, .end = 924 }, + { .start = 928, .end = 936 }, + { .start = 948, .end = 964 }, + { .start = 968, .end = 976 }, + { .start = 984, .end = 1012 }, +}; + +static struct nvmem_config s32g_ocotp_nvmem_config = { + .name = "s32g-ocotp", + .add_legacy_fixed_of_cells = true, + .read_only = true, + .word_size = 4, + .reg_read = s32g_ocotp_read, + .keepout = s32g_keepouts, + .nkeepout = ARRAY_SIZE(s32g_keepouts), +}; + +static const struct of_device_id ocotp_of_match[] = { + { .compatible = "nxp,s32g2-ocotp" }, + { /* sentinel */ } +}; + +static int s32g_ocotp_probe(struct platform_device *pdev) +{ + struct s32g_ocotp_priv *s32g_data; + struct device *dev = &pdev->dev; + struct nvmem_device *nvmem; + struct resource *res; + + s32g_data = devm_kzalloc(dev, sizeof(*s32g_data), GFP_KERNEL); + if (!s32g_data) + return -ENOMEM; + + s32g_data->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(s32g_data->base)) + return dev_err_probe(dev, PTR_ERR(s32g_data->base), + "Cannot map OCOTP device.\n"); + + s32g_data->dev = dev; + s32g_ocotp_nvmem_config.dev = dev; + s32g_ocotp_nvmem_config.priv = s32g_data; + s32g_ocotp_nvmem_config.size = resource_size(res); + + nvmem = devm_nvmem_register(dev, &s32g_ocotp_nvmem_config); + + return PTR_ERR_OR_ZERO(nvmem); +} + +static struct platform_driver s32g_ocotp_driver = { + .probe = s32g_ocotp_probe, + .driver = { + .name = "s32g-ocotp", + .of_match_table = ocotp_of_match, + }, +}; +module_platform_driver(s32g_ocotp_driver); +MODULE_AUTHOR("NXP"); +MODULE_DESCRIPTION("S32G OCOTP driver"); +MODULE_LICENSE("GPL"); From 4a9b344e90c7ca654d7a469d0a467f90ef2add64 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 12 Sep 2025 14:14:13 +0100 Subject: [PATCH 1306/2711] dt-bindings: nvmem: sl28cpld: add sa67mcu compatible The Kontron SMARC-sAM67 has the same nvmem layout as the SMARC-sAL28. To To be prepared for any board specific quirks, add a specific compatible. Signed-off-by: Michael Walle Acked-by: Krzysztof Kozlowski Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131415.303407-4-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- .../bindings/nvmem/layouts/kontron,sl28-vpd.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml b/Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml index c713e23819f1..afd1919c6b1c 100644 --- a/Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml +++ b/Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml @@ -19,7 +19,12 @@ select: false properties: compatible: - const: kontron,sl28-vpd + oneOf: + - items: + - enum: + - kontron,sa67-vpd + - const: kontron,sl28-vpd + - const: kontron,sl28-vpd serial-number: type: object From ddb095e81d60902d76be250fa5f7f1d1e32f65ec Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 12 Sep 2025 14:14:14 +0100 Subject: [PATCH 1307/2711] dt-bindings: nvmem: Document support for Airoha AN8855 Switch EFUSE Document support for Airoha AN8855 Switch EFUSE used to calibrate internal PHYs and store additional configuration info. Signed-off-by: Christian Marangi Reviewed-by: Rob Herring (Arm) Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131415.303407-5-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- .../bindings/nvmem/airoha,an8855-efuse.yaml | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 Documentation/devicetree/bindings/nvmem/airoha,an8855-efuse.yaml diff --git a/Documentation/devicetree/bindings/nvmem/airoha,an8855-efuse.yaml b/Documentation/devicetree/bindings/nvmem/airoha,an8855-efuse.yaml new file mode 100644 index 000000000000..9802d9ea2176 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/airoha,an8855-efuse.yaml @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/airoha,an8855-efuse.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Airoha AN8855 Switch EFUSE + +maintainers: + - Christian Marangi + +description: + Airoha AN8855 EFUSE used to calibrate internal PHYs and store additional + configuration info. + +$ref: nvmem.yaml# + +properties: + compatible: + const: airoha,an8855-efuse + + '#nvmem-cell-cells': + const: 0 + +required: + - compatible + - '#nvmem-cell-cells' + +unevaluatedProperties: false + +examples: + - | + efuse { + compatible = "airoha,an8855-efuse"; + + #nvmem-cell-cells = <0>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + shift_sel_port0_tx_a: shift-sel-port0-tx-a@c { + reg = <0xc 0x4>; + }; + + shift_sel_port0_tx_b: shift-sel-port0-tx-b@10 { + reg = <0x10 0x4>; + }; + + shift_sel_port0_tx_c: shift-sel-port0-tx-c@14 { + reg = <0x14 0x4>; + }; + + shift_sel_port0_tx_d: shift-sel-port0-tx-d@18 { + reg = <0x18 0x4>; + }; + + shift_sel_port1_tx_a: shift-sel-port1-tx-a@1c { + reg = <0x1c 0x4>; + }; + + shift_sel_port1_tx_b: shift-sel-port1-tx-b@20 { + reg = <0x20 0x4>; + }; + + shift_sel_port1_tx_c: shift-sel-port1-tx-c@24 { + reg = <0x24 0x4>; + }; + + shift_sel_port1_tx_d: shift-sel-port1-tx-d@28 { + reg = <0x28 0x4>; + }; + + shift_sel_port2_tx_a: shift-sel-port2-tx-a@2c { + reg = <0x2c 0x4>; + }; + + shift_sel_port2_tx_b: shift-sel-port2-tx-b@30 { + reg = <0x30 0x4>; + }; + + shift_sel_port2_tx_c: shift-sel-port2-tx-c@34 { + reg = <0x34 0x4>; + }; + + shift_sel_port2_tx_d: shift-sel-port2-tx-d@38 { + reg = <0x38 0x4>; + }; + + shift_sel_port3_tx_a: shift-sel-port3-tx-a@4c { + reg = <0x4c 0x4>; + }; + + shift_sel_port3_tx_b: shift-sel-port3-tx-b@50 { + reg = <0x50 0x4>; + }; + + shift_sel_port3_tx_c: shift-sel-port3-tx-c@54 { + reg = <0x54 0x4>; + }; + + shift_sel_port3_tx_d: shift-sel-port3-tx-d@58 { + reg = <0x58 0x4>; + }; + + shift_sel_port4_tx_a: shift-sel-port4-tx-a@5c { + reg = <0x5c 0x4>; + }; + + shift_sel_port4_tx_b: shift-sel-port4-tx-b@60 { + reg = <0x60 0x4>; + }; + + shift_sel_port4_tx_c: shift-sel-port4-tx-c@64 { + reg = <0x64 0x4>; + }; + + shift_sel_port4_tx_d: shift-sel-port4-tx-d@68 { + reg = <0x68 0x4>; + }; + }; + }; From e2258cfd9b9809002ad52f1f763ff192e612a1fe Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 12 Sep 2025 14:14:15 +0100 Subject: [PATCH 1308/2711] nvmem: an8855: Add support for Airoha AN8855 Switch EFUSE Add support for Airoha AN8855 Switch EFUSE. These EFUSE might be used for calibration data for the internal switch PHYs. Signed-off-by: Christian Marangi Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131415.303407-6-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/Kconfig | 11 ++++++ drivers/nvmem/Makefile | 2 ++ drivers/nvmem/an8855-efuse.c | 68 ++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 drivers/nvmem/an8855-efuse.c diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index f3b8ffa77528..e0d88d3199c1 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -28,6 +28,17 @@ source "drivers/nvmem/layouts/Kconfig" # Devices +config NVMEM_AN8855_EFUSE + tristate "Airoha AN8855 eFuse support" + depends on MFD_AIROHA_AN8855 || COMPILE_TEST + help + Say y here to enable support for reading eFuses on Airoha AN8855 + Switch. These are e.g. used to store factory programmed + calibration data required for the PHY. + + This driver can also be built as a module. If so, the module will + be called nvmem-an8855-efuse. + config NVMEM_APPLE_EFUSES tristate "Apple eFuse support" depends on ARCH_APPLE || COMPILE_TEST diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 5634945f8196..70a4464dcb1e 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -10,6 +10,8 @@ nvmem_layouts-y := layouts.o obj-y += layouts/ # Devices +obj-$(CONFIG_NVMEM_AN8855_EFUSE) += nvmem-an8855-efuse.o +nvmem-an8855-efuse-y := an8855-efuse.o obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o nvmem-apple-efuses-y := apple-efuses.o obj-$(CONFIG_NVMEM_APPLE_SPMI) += apple_nvmem_spmi.o diff --git a/drivers/nvmem/an8855-efuse.c b/drivers/nvmem/an8855-efuse.c new file mode 100644 index 000000000000..d1afde6f623f --- /dev/null +++ b/drivers/nvmem/an8855-efuse.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Airoha AN8855 Switch EFUSE Driver + */ + +#include +#include +#include +#include +#include + +#define AN8855_EFUSE_CELL 50 + +#define AN8855_EFUSE_DATA0 0x1000a500 +#define AN8855_EFUSE_R50O GENMASK(30, 24) + +static int an8855_efuse_read(void *context, unsigned int offset, + void *val, size_t bytes) +{ + struct regmap *regmap = context; + + return regmap_bulk_read(regmap, AN8855_EFUSE_DATA0 + offset, + val, bytes / sizeof(u32)); +} + +static int an8855_efuse_probe(struct platform_device *pdev) +{ + struct nvmem_config an8855_nvmem_config = { + .name = "an8855-efuse", + .size = AN8855_EFUSE_CELL * sizeof(u32), + .stride = sizeof(u32), + .word_size = sizeof(u32), + .reg_read = an8855_efuse_read, + }; + struct device *dev = &pdev->dev; + struct nvmem_device *nvmem; + struct regmap *regmap; + + /* Assign NVMEM priv to MFD regmap */ + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) + return -ENOENT; + + an8855_nvmem_config.priv = regmap; + an8855_nvmem_config.dev = dev; + nvmem = devm_nvmem_register(dev, &an8855_nvmem_config); + + return PTR_ERR_OR_ZERO(nvmem); +} + +static const struct of_device_id an8855_efuse_of_match[] = { + { .compatible = "airoha,an8855-efuse", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, an8855_efuse_of_match); + +static struct platform_driver an8855_efuse_driver = { + .probe = an8855_efuse_probe, + .driver = { + .name = "an8855-efuse", + .of_match_table = an8855_efuse_of_match, + }, +}; +module_platform_driver(an8855_efuse_driver); + +MODULE_AUTHOR("Christian Marangi "); +MODULE_DESCRIPTION("Driver for AN8855 Switch EFUSE"); +MODULE_LICENSE("GPL"); From 013c09b7ac8c471fb721f0966b4e8f749cd5fdfa Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Mon, 8 Sep 2025 08:12:43 +0200 Subject: [PATCH 1309/2711] staging: rtl8723bs: remove unused tables Remove some unused tabels to get rid of dead code and thereby reduce the object file size by more than 1400 bytes. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20250908061243.62692-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/hal/odm.c | 152 ---------------------------- drivers/staging/rtl8723bs/hal/odm.h | 6 -- 2 files changed, 158 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/odm.c b/drivers/staging/rtl8723bs/hal/odm.c index ba85efb30db2..4b36af47f680 100644 --- a/drivers/staging/rtl8723bs/hal/odm.c +++ b/drivers/staging/rtl8723bs/hal/odm.c @@ -9,118 +9,6 @@ /* Global var */ -u32 OFDMSwingTable[OFDM_TABLE_SIZE] = { - 0x7f8001fe, /* 0, +6.0dB */ - 0x788001e2, /* 1, +5.5dB */ - 0x71c001c7, /* 2, +5.0dB */ - 0x6b8001ae, /* 3, +4.5dB */ - 0x65400195, /* 4, +4.0dB */ - 0x5fc0017f, /* 5, +3.5dB */ - 0x5a400169, /* 6, +3.0dB */ - 0x55400155, /* 7, +2.5dB */ - 0x50800142, /* 8, +2.0dB */ - 0x4c000130, /* 9, +1.5dB */ - 0x47c0011f, /* 10, +1.0dB */ - 0x43c0010f, /* 11, +0.5dB */ - 0x40000100, /* 12, +0dB */ - 0x3c8000f2, /* 13, -0.5dB */ - 0x390000e4, /* 14, -1.0dB */ - 0x35c000d7, /* 15, -1.5dB */ - 0x32c000cb, /* 16, -2.0dB */ - 0x300000c0, /* 17, -2.5dB */ - 0x2d4000b5, /* 18, -3.0dB */ - 0x2ac000ab, /* 19, -3.5dB */ - 0x288000a2, /* 20, -4.0dB */ - 0x26000098, /* 21, -4.5dB */ - 0x24000090, /* 22, -5.0dB */ - 0x22000088, /* 23, -5.5dB */ - 0x20000080, /* 24, -6.0dB */ - 0x1e400079, /* 25, -6.5dB */ - 0x1c800072, /* 26, -7.0dB */ - 0x1b00006c, /* 27. -7.5dB */ - 0x19800066, /* 28, -8.0dB */ - 0x18000060, /* 29, -8.5dB */ - 0x16c0005b, /* 30, -9.0dB */ - 0x15800056, /* 31, -9.5dB */ - 0x14400051, /* 32, -10.0dB */ - 0x1300004c, /* 33, -10.5dB */ - 0x12000048, /* 34, -11.0dB */ - 0x11000044, /* 35, -11.5dB */ - 0x10000040, /* 36, -12.0dB */ -}; - -u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8] = { - {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */ - {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */ - {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */ - {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */ - {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */ - {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */ - {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */ - {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */ - {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */ - {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */ - {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */ - {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */ - {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB <== default */ - {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */ - {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */ - {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */ - {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ - {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */ - {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */ - {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */ - {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB */ - {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB */ - {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB */ - {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB */ - {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB */ - {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB */ - {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB */ - {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB */ - {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB */ - {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB */ - {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB */ - {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB */ - {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} /* 32, -16.0dB */ -}; - -u8 CCKSwingTable_Ch14[CCK_TABLE_SIZE][8] = { - {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */ - {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */ - {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */ - {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */ - {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */ - {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */ - {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */ - {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */ - {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */ - {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */ - {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */ - {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */ - {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB <== default */ - {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */ - {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */ - {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */ - {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ - {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */ - {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */ - {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */ - {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB */ - {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB */ - {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB */ - {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB */ - {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB */ - {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB */ - {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB */ - {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB */ - {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB */ - {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB */ - {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB */ - {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB */ - {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */ -}; - u32 OFDMSwingTable_New[OFDM_TABLE_SIZE] = { 0x0b40002d, /* 0, -15.0dB */ 0x0c000030, /* 1, -14.5dB */ @@ -239,46 +127,6 @@ u8 CCKSwingTable_Ch14_New[CCK_TABLE_SIZE][8] = { {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00} /* 32, +0dB */ }; -u32 TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE] = { - 0x081, /* 0, -12.0dB */ - 0x088, /* 1, -11.5dB */ - 0x090, /* 2, -11.0dB */ - 0x099, /* 3, -10.5dB */ - 0x0A2, /* 4, -10.0dB */ - 0x0AC, /* 5, -9.5dB */ - 0x0B6, /* 6, -9.0dB */ - 0x0C0, /* 7, -8.5dB */ - 0x0CC, /* 8, -8.0dB */ - 0x0D8, /* 9, -7.5dB */ - 0x0E5, /* 10, -7.0dB */ - 0x0F2, /* 11, -6.5dB */ - 0x101, /* 12, -6.0dB */ - 0x110, /* 13, -5.5dB */ - 0x120, /* 14, -5.0dB */ - 0x131, /* 15, -4.5dB */ - 0x143, /* 16, -4.0dB */ - 0x156, /* 17, -3.5dB */ - 0x16A, /* 18, -3.0dB */ - 0x180, /* 19, -2.5dB */ - 0x197, /* 20, -2.0dB */ - 0x1AF, /* 21, -1.5dB */ - 0x1C8, /* 22, -1.0dB */ - 0x1E3, /* 23, -0.5dB */ - 0x200, /* 24, +0 dB */ - 0x21E, /* 25, +0.5dB */ - 0x23E, /* 26, +1.0dB */ - 0x261, /* 27, +1.5dB */ - 0x285, /* 28, +2.0dB */ - 0x2AB, /* 29, +2.5dB */ - 0x2D3, /* 30, +3.0dB */ - 0x2FE, /* 31, +3.5dB */ - 0x32B, /* 32, +4.0dB */ - 0x35C, /* 33, +4.5dB */ - 0x38E, /* 34, +5.0dB */ - 0x3C4, /* 35, +5.5dB */ - 0x3FE /* 36, +6.0dB */ -}; - /* Remove Edca by Yu Chen */ static void odm_CommonInfoSelfInit(struct dm_odm_t *pDM_Odm) diff --git a/drivers/staging/rtl8723bs/hal/odm.h b/drivers/staging/rtl8723bs/hal/odm.h index 010274ba8079..1c929d88e596 100644 --- a/drivers/staging/rtl8723bs/hal/odm.h +++ b/drivers/staging/rtl8723bs/hal/odm.h @@ -1080,16 +1080,10 @@ enum { /* tag_RF_Type_Definition */ /* */ /* Extern Global Variables. */ /* */ -extern u32 OFDMSwingTable[OFDM_TABLE_SIZE]; -extern u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8]; -extern u8 CCKSwingTable_Ch14[CCK_TABLE_SIZE][8]; - extern u32 OFDMSwingTable_New[OFDM_TABLE_SIZE]; extern u8 CCKSwingTable_Ch1_Ch13_New[CCK_TABLE_SIZE][8]; extern u8 CCKSwingTable_Ch14_New[CCK_TABLE_SIZE][8]; -extern u32 TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE]; - /* */ /* check Sta pointer valid or not */ /* */ From 6f8fb022ef2c6694e47f6e2f5676eb63be66c208 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Mon, 18 Aug 2025 11:57:15 +0200 Subject: [PATCH 1310/2711] perf: Completely remove possibility to override MAX_NR_CPUS Commit 21b8732eb447 ("perf tools: Allow overriding MAX_NR_CPUS at compile time") added the capability to override MAX_NR_CPUS. At that time it was necessary to reduce the huge amount of RAM used by static stats variables. But this has been unnecessary since commit 6a1e2c5c2673 ("perf stat: Remove a set of shadow stats static variables"), and commit e8399d34d568 ("libperf cpumap: Hide/reduce scope of MAX_NR_CPUS") broke the build in that case because it failed to add the guard around the new definition of MAX_NR_CPUS. So cleanup things and remove guards completely to officialise it is not necessary anymore to override MAX_NR_CPUS. Fixes: e8399d34d568d61c ("libperf cpumap: Hide/reduce scope of MAX_NR_CPUS") Signed-off-by: Christophe Leroy Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/all/8c8553387ebf904a9e5a93eaf643cb01164d9fb3.1736188471.git.christophe.leroy@csgroup.eu/ Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/perf.h | 2 -- tools/perf/util/bpf_skel/kwork_top.bpf.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 3cb40965549f..e004178472d9 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -2,9 +2,7 @@ #ifndef _PERF_PERF_H #define _PERF_PERF_H -#ifndef MAX_NR_CPUS #define MAX_NR_CPUS 4096 -#endif enum perf_affinity { PERF_AFFINITY_SYS = 0, diff --git a/tools/perf/util/bpf_skel/kwork_top.bpf.c b/tools/perf/util/bpf_skel/kwork_top.bpf.c index 73e32e063030..6673386302e2 100644 --- a/tools/perf/util/bpf_skel/kwork_top.bpf.c +++ b/tools/perf/util/bpf_skel/kwork_top.bpf.c @@ -18,9 +18,7 @@ enum kwork_class_type { }; #define MAX_ENTRIES 102400 -#ifndef MAX_NR_CPUS #define MAX_NR_CPUS 4096 -#endif #define PF_KTHREAD 0x00200000 #define MAX_COMMAND_LEN 16 From 6f19c1ef7f95fb432ba2b36d4634870d55e658ce Mon Sep 17 00:00:00 2001 From: Akiyoshi Kurita Date: Tue, 9 Sep 2025 14:33:26 +0900 Subject: [PATCH 1311/2711] staging: rtl8723bs: rtw_efuse.h: simplify copyright banner Replace the banner-style copyright comment with a single-line comment. No functional changes. Signed-off-by: Akiyoshi Kurita Link: https://lore.kernel.org/r/20250909053327.140763-1-weibu@redadmin.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/include/rtw_efuse.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/staging/rtl8723bs/include/rtw_efuse.h b/drivers/staging/rtl8723bs/include/rtw_efuse.h index 904369705ed7..936b204b8830 100644 --- a/drivers/staging/rtl8723bs/include/rtw_efuse.h +++ b/drivers/staging/rtl8723bs/include/rtw_efuse.h @@ -1,9 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ +/* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. */ + #ifndef __RTW_EFUSE_H__ #define __RTW_EFUSE_H__ From 02accdf0ca0242e040f14bbe96d9e9f29f8c95f5 Mon Sep 17 00:00:00 2001 From: Yiming Qian Date: Tue, 9 Sep 2025 14:01:29 +0800 Subject: [PATCH 1312/2711] staging: sm750fb: remove unnecessary volatile qualifiers The use of 'volatile' for memory-mapped I/O pointers is discouraged in the Linux kernel as per Documentation/process/volatile-considered-harmful.rst. This patch removes the unnecessary 'volatile' qualifiers from the lynx_accel struct members, improving code quality and maintainability. Signed-off-by: Yiming Qian Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20250909060130.12919-2-qianym1996@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index d7f40efe3a2c..41f1fb390174 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -50,9 +50,9 @@ struct init_status { struct lynx_accel { /* base virtual address of DPR registers */ - volatile unsigned char __iomem *dprBase; + unsigned char __iomem *dprBase; /* base virtual address of de data port */ - volatile unsigned char __iomem *dpPortBase; + unsigned char __iomem *dpPortBase; /* function pointers */ void (*de_init)(struct lynx_accel *accel); @@ -128,7 +128,7 @@ struct lynx_cursor { char __iomem *vstart; int offset; /* mmio addr of hw cursor */ - volatile char __iomem *mmio; + char __iomem *mmio; }; struct lynxfb_crtc { From 5865a858dbc9cbb0f458d5954ff97971d3fd209f Mon Sep 17 00:00:00 2001 From: Yiming Qian Date: Tue, 9 Sep 2025 14:01:30 +0800 Subject: [PATCH 1313/2711] staging: sm750fb: rename snake case variables Replaces CamelCase variable names with snake_case: - dprBase -> dpr_base - dpPortBase -> dp_port_base Signed-off-by: Yiming Qian Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20250909060130.12919-3-qianym1996@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.h | 4 ++-- drivers/staging/sm750fb/sm750_accel.c | 6 +++--- drivers/staging/sm750fb/sm750_hw.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index 41f1fb390174..fcb7d586ebf0 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -50,9 +50,9 @@ struct init_status { struct lynx_accel { /* base virtual address of DPR registers */ - unsigned char __iomem *dprBase; + unsigned char __iomem *dpr_base; /* base virtual address of de data port */ - unsigned char __iomem *dpPortBase; + unsigned char __iomem *dp_port_base; /* function pointers */ void (*de_init)(struct lynx_accel *accel); diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 44b9e3fe3a41..7ac2e7b6ea0f 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -19,17 +19,17 @@ #include "sm750_accel.h" static inline void write_dpr(struct lynx_accel *accel, int offset, u32 regValue) { - writel(regValue, accel->dprBase + offset); + writel(regValue, accel->dpr_base + offset); } static inline u32 read_dpr(struct lynx_accel *accel, int offset) { - return readl(accel->dprBase + offset); + return readl(accel->dpr_base + offset); } static inline void write_dpPort(struct lynx_accel *accel, u32 data) { - writel(data, accel->dpPortBase); + writel(data, accel->dp_port_base); } void sm750_hw_de_init(struct lynx_accel *accel) diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 7119b67efe11..ce46f240cbaf 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -58,8 +58,8 @@ int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev) } pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg); - sm750_dev->accel.dprBase = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1; - sm750_dev->accel.dpPortBase = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1; + sm750_dev->accel.dpr_base = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1; + sm750_dev->accel.dp_port_base = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1; mmio750 = sm750_dev->pvReg; sm750_set_chip_type(sm750_dev->devid, sm750_dev->revid); From 0daed4c3b6a6f863a40e6b6effa462c5a46f2949 Mon Sep 17 00:00:00 2001 From: Akiyoshi Kurita Date: Fri, 12 Sep 2025 15:44:06 +0900 Subject: [PATCH 1314/2711] staging: rtl8723bs: fix typo in comment Fix a misspelling in a header comment: "configurtions" -> "configurations". Signed-off-by: Akiyoshi Kurita Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20250912064406.707039-1-weibu@redadmin.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/hal/hal_pwr_seq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8723bs/hal/hal_pwr_seq.c b/drivers/staging/rtl8723bs/hal/hal_pwr_seq.c index fba67a7c069c..2438931ca51b 100644 --- a/drivers/staging/rtl8723bs/hal/hal_pwr_seq.c +++ b/drivers/staging/rtl8723bs/hal/hal_pwr_seq.c @@ -8,7 +8,7 @@ /* * This file includes all kinds of Power Action event for RTL8723B -and corresponding hardware configurtions which are released from HW SD. +and corresponding hardware configurations which are released from HW SD. Major Change History: When Who What From fc702e7df456e219f029d0192fbc7cb357a16f4c Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Tue, 9 Sep 2025 08:51:22 +0800 Subject: [PATCH 1315/2711] vt: move vc_saved_screen to within tty allocated judgment Everything starts with the assumption that a tty has been allocated. Therefore, Move it to within the tty allocation check. Fixes: 23743ba64709 ("vt: add support for smput/rmput escape codes") Reported-by: syzbot+f6cb41c144427dc0796a@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=f6cb41c144427dc0796a Tested-by: syzbot+f6cb41c144427dc0796a@syzkaller.appspotmail.com Signed-off-by: Edward Adam Davis Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/tencent_CAD45DB31906CF890DBB25AB0DED12205D07@qq.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 1d9abcfac4c9..6e0089b85c27 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1341,10 +1341,10 @@ struct vc_data *vc_deallocate(unsigned int currcons) vc_uniscr_set(vc, NULL); kfree(vc->vc_screenbuf); vc_cons[currcons].d = NULL; - } - if (vc->vc_saved_screen != NULL) { - kfree(vc->vc_saved_screen); - vc->vc_saved_screen = NULL; + if (vc->vc_saved_screen != NULL) { + kfree(vc->vc_saved_screen); + vc->vc_saved_screen = NULL; + } } return vc; } From 8d17dc05c94ce95a9c9fc7ca5f1b92f6561a9284 Mon Sep 17 00:00:00 2001 From: Tapio Reijonen Date: Mon, 8 Sep 2025 06:53:43 +0000 Subject: [PATCH 1316/2711] serial: max310x: improve interrupt handling When there is a heavy load of receiving characters to all four UART's, the warning 'Hardware RX FIFO overrun' is sometimes detected. The current implementation always service first the highest UART until no more interrupt and then service another UART (ex: UART3 will be serviced for as long as there are interrupts for it, then UART2, etc). This commit handle all individual interrupt sources before reading the global IRQ register again. This commit has also a nice side-effect of improving the efficiency of the driver by reducing the number of reads of the global IRQ register. Signed-off-by: Tapio Reijonen Reviewed-by: Jiri Slaby Reviewed-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20250908-master-max310x-improve-interrupt-handling-v3-1-91985e82ba39@vaisala.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index e8749b862970..ac7d3f197c3a 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -823,17 +823,28 @@ static irqreturn_t max310x_ist(int irq, void *dev_id) bool handled = false; if (s->devtype->nr > 1) { + bool done; + do { unsigned int val = ~0; + unsigned long irq; + unsigned int port; + + done = true; WARN_ON_ONCE(regmap_read(s->regmap, MAX310X_GLOBALIRQ_REG, &val)); - val = ((1 << s->devtype->nr) - 1) & ~val; - if (!val) - break; - if (max310x_port_irq(s, fls(val) - 1) == IRQ_HANDLED) - handled = true; - } while (1); + + irq = val; + + for_each_clear_bit(port, &irq, s->devtype->nr) { + done = false; + + if (max310x_port_irq(s, port) == IRQ_HANDLED) + handled = true; + } + + } while (!done); } else { if (max310x_port_irq(s, 0) == IRQ_HANDLED) handled = true; From 49fce0730fd3c028982574c85eb2eb824d6e63f7 Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 10 Sep 2025 16:23:31 -0500 Subject: [PATCH 1317/2711] dt-bindings: serial: 8250_omap: Add wakeup pinctrl state Pins associated with the 8250 omap unit can be the source of a wakeup in deep sleep states. To be able to wakeup, these pins have to be configured in a special way. To support this configuration add the default and wakeup pinctrl states. Signed-off-by: Markus Schneider-Pargmann Signed-off-by: Kendall Willis Link: https://lore.kernel.org/r/20250910-uart-daisy-chain-8250-omap-v2-1-e90d44c1a9ac@ti.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/8250_omap.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/8250_omap.yaml b/Documentation/devicetree/bindings/serial/8250_omap.yaml index 1859f71297ff..aabacca2b2fa 100644 --- a/Documentation/devicetree/bindings/serial/8250_omap.yaml +++ b/Documentation/devicetree/bindings/serial/8250_omap.yaml @@ -71,6 +71,22 @@ properties: overrun-throttle-ms: true wakeup-source: true + pinctrl-0: + description: Default pinctrl state + + pinctrl-1: + description: Wakeup pinctrl state + + pinctrl-names: + description: + When present should contain at least "default" describing the default pin + states. The second state called "wakeup" describes the pins in their + wakeup configuration required to exit sleep states. + minItems: 1 + items: + - const: default + - const: wakeup + required: - compatible - reg From ed68411e879e9bd512e266d3c46d4b35c5f5fbbc Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Wed, 10 Sep 2025 16:23:32 -0500 Subject: [PATCH 1318/2711] serial: 8250: omap: Support wakeup pinctrl state on suspend UART can be used as a wakeup source for am62 from suspend to ram states. To enable wakeup from UART am62 requires a wakeup flag being set in the pinctrl. If the device is marked as wakeup enabled, select the 'wakeup' pinctrl state on suspend and restore the default pinctrl state on resume. Signed-off-by: Markus Schneider-Pargmann Signed-off-by: Kendall Willis Link: https://lore.kernel.org/r/20250910-uart-daisy-chain-8250-omap-v2-2-e90d44c1a9ac@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index bb23afdd63f2..9e49ef48b851 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "8250.h" @@ -145,6 +147,9 @@ struct omap8250_priv { spinlock_t rx_dma_lock; bool rx_dma_broken; bool throttled; + + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_wakeup; }; struct omap8250_dma_params { @@ -1349,6 +1354,18 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static int omap8250_select_wakeup_pinctrl(struct device *dev, + struct omap8250_priv *priv) +{ + if (IS_ERR_OR_NULL(priv->pinctrl_wakeup)) + return 0; + + if (!device_may_wakeup(dev)) + return 0; + + return pinctrl_select_state(priv->pinctrl, priv->pinctrl_wakeup); +} + static struct omap8250_dma_params am654_dma = { .rx_size = SZ_2K, .rx_trigger = 1, @@ -1573,6 +1590,11 @@ static int omap8250_probe(struct platform_device *pdev) priv->line = ret; pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); + + priv->pinctrl = devm_pinctrl_get(&pdev->dev); + if (!IS_ERR_OR_NULL(priv->pinctrl)) + priv->pinctrl_wakeup = pinctrl_lookup_state(priv->pinctrl, "wakeup"); + return 0; err: pm_runtime_dont_use_autosuspend(&pdev->dev); @@ -1630,6 +1652,13 @@ static int omap8250_suspend(struct device *dev) struct uart_8250_port *up = serial8250_get_port(priv->line); int err = 0; + err = omap8250_select_wakeup_pinctrl(dev, priv); + if (err) { + dev_err(dev, "Failed to select wakeup pinctrl, aborting suspend %pe\n", + ERR_PTR(err)); + return err; + } + serial8250_suspend_port(priv->line); err = pm_runtime_resume_and_get(dev); @@ -1651,6 +1680,13 @@ static int omap8250_resume(struct device *dev) struct uart_8250_port *up = serial8250_get_port(priv->line); int err; + err = pinctrl_select_default_state(dev); + if (err) { + dev_err(dev, "Failed to select default pinctrl state on resume: %pe\n", + ERR_PTR(err)); + return err; + } + if (uart_console(&up->port) && console_suspend_enabled) { err = pm_runtime_force_resume(dev); if (err) From 6d07bee10e4bdd043ec7152cbbb9deb27033c9e2 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Fri, 12 Sep 2025 13:13:21 +0300 Subject: [PATCH 1319/2711] staging: axis-fifo: fix TX handling on copy_from_user() failure If copy_from_user() fails, write() currently returns -EFAULT, but any partially written data leaves the TX FIFO in an inconsistent state. Subsequent write() calls then fail with "transmit length mismatch" errors. Once partial data is written to the hardware FIFO, it cannot be removed without a TX reset. Commit c6e8d85fafa7 ("staging: axis-fifo: Remove hardware resets for user errors") removed a full FIFO reset for this case, which fixed a potential RX data loss, but introduced this TX issue. Fix this by introducing a bounce buffer: copy the full packet from userspace first, and write to the hardware FIFO only if the copy was successful. Fixes: c6e8d85fafa7 ("staging: axis-fifo: Remove hardware resets for user errors") Cc: stable@vger.kernel.org Signed-off-by: Ovidiu Panait Link: https://lore.kernel.org/r/20250912101322.1282507-1-ovidiu.panait.oss@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/axis-fifo/axis-fifo.c | 36 ++++++++------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index 8d5bbe81b499..c03b961896b9 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -43,7 +43,6 @@ #define DRIVER_NAME "axis_fifo" #define READ_BUF_SIZE 128U /* read buffer length in words */ -#define WRITE_BUF_SIZE 128U /* write buffer length in words */ #define AXIS_FIFO_DEBUG_REG_NAME_MAX_LEN 4 @@ -302,11 +301,8 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf, { struct axis_fifo *fifo = (struct axis_fifo *)f->private_data; unsigned int words_to_write; - unsigned int copied; - unsigned int copy; - unsigned int i; + u32 *txbuf; int ret; - u32 tmp_buf[WRITE_BUF_SIZE]; if (len % sizeof(u32)) { dev_err(fifo->dt_device, @@ -371,32 +367,20 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf, } } - /* write data from an intermediate buffer into the fifo IP, refilling - * the buffer with userspace data as needed - */ - copied = 0; - while (words_to_write > 0) { - copy = min(words_to_write, WRITE_BUF_SIZE); - - if (copy_from_user(tmp_buf, buf + copied * sizeof(u32), - copy * sizeof(u32))) { - ret = -EFAULT; - goto end_unlock; - } - - for (i = 0; i < copy; i++) - iowrite32(tmp_buf[i], fifo->base_addr + - XLLF_TDFD_OFFSET); - - copied += copy; - words_to_write -= copy; + txbuf = vmemdup_user(buf, len); + if (IS_ERR(txbuf)) { + ret = PTR_ERR(txbuf); + goto end_unlock; } - ret = copied * sizeof(u32); + for (int i = 0; i < words_to_write; ++i) + iowrite32(txbuf[i], fifo->base_addr + XLLF_TDFD_OFFSET); /* write packet size to fifo */ - iowrite32(ret, fifo->base_addr + XLLF_TLR_OFFSET); + iowrite32(len, fifo->base_addr + XLLF_TLR_OFFSET); + ret = len; + kvfree(txbuf); end_unlock: mutex_unlock(&fifo->write_lock); From 82a051e2553b9e297cba82a975d9c538b882c79e Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Fri, 12 Sep 2025 13:13:22 +0300 Subject: [PATCH 1320/2711] staging: axis-fifo: flush RX FIFO on read errors Flush stale data from the RX FIFO in case of errors, to avoid reading old data when new packets arrive. Commit c6e8d85fafa7 ("staging: axis-fifo: Remove hardware resets for user errors") removed full FIFO resets from the read error paths, which fixed potential TX data losses, but introduced this RX issue. Fixes: c6e8d85fafa7 ("staging: axis-fifo: Remove hardware resets for user errors") Cc: stable@vger.kernel.org Signed-off-by: Ovidiu Panait Link: https://lore.kernel.org/r/20250912101322.1282507-2-ovidiu.panait.oss@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/axis-fifo/axis-fifo.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index c03b961896b9..b6261b96e465 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -227,6 +227,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, } bytes_available = ioread32(fifo->base_addr + XLLF_RLR_OFFSET); + words_available = bytes_available / sizeof(u32); if (!bytes_available) { dev_err(fifo->dt_device, "received a packet of length 0\n"); ret = -EIO; @@ -237,7 +238,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, dev_err(fifo->dt_device, "user read buffer too small (available bytes=%zu user buffer bytes=%zu)\n", bytes_available, len); ret = -EINVAL; - goto end_unlock; + goto err_flush_rx; } if (bytes_available % sizeof(u32)) { @@ -246,11 +247,9 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, */ dev_err(fifo->dt_device, "received a packet that isn't word-aligned\n"); ret = -EIO; - goto end_unlock; + goto err_flush_rx; } - words_available = bytes_available / sizeof(u32); - /* read data into an intermediate buffer, copying the contents * to userspace when the buffer is full */ @@ -262,18 +261,23 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, tmp_buf[i] = ioread32(fifo->base_addr + XLLF_RDFD_OFFSET); } + words_available -= copy; if (copy_to_user(buf + copied * sizeof(u32), tmp_buf, copy * sizeof(u32))) { ret = -EFAULT; - goto end_unlock; + goto err_flush_rx; } copied += copy; - words_available -= copy; } + mutex_unlock(&fifo->read_lock); - ret = bytes_available; + return bytes_available; + +err_flush_rx: + while (words_available--) + ioread32(fifo->base_addr + XLLF_RDFD_OFFSET); end_unlock: mutex_unlock(&fifo->read_lock); From 2910913ef87dd9b9ce39e844c7295e1896b3b039 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 12 Sep 2025 16:27:35 +0200 Subject: [PATCH 1321/2711] HID: steelseries: Fix STEELSERIES_SRWS1 handling in steelseries_remove() srws1_remove label can be only reached only if LEDS subsystem is enabled. To avoid putting horryfing ifdef second time around the label, just perform the cleanup and exit immediately directly. Fixes: a84eeacbf9325 ("HID: steelseries: refactor probe() and remove()") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202509090334.76D4qGtW-lkp@intel.com/ Signed-off-by: Jiri Kosina --- drivers/hid/hid-steelseries.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c index 8af98d67959e..f98435631aa1 100644 --- a/drivers/hid/hid-steelseries.c +++ b/drivers/hid/hid-steelseries.c @@ -582,7 +582,7 @@ static void steelseries_remove(struct hid_device *hdev) if (hdev->product == USB_DEVICE_ID_STEELSERIES_SRWS1) { #if IS_BUILTIN(CONFIG_LEDS_CLASS) || \ (IS_MODULE(CONFIG_LEDS_CLASS) && IS_MODULE(CONFIG_HID_STEELSERIES)) - goto srws1_remove; + hid_hw_stop(hdev); #endif return; } @@ -596,7 +596,6 @@ static void steelseries_remove(struct hid_device *hdev) cancel_delayed_work_sync(&sd->battery_work); hid_hw_close(hdev); -srws1_remove: hid_hw_stop(hdev); } From aa1735d72bc085c4d107fb2017c597f83bb9490c Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Mon, 4 Aug 2025 16:14:49 +0300 Subject: [PATCH 1322/2711] clk: imx95-blk-ctl: Save platform data in imx95_blk_ctl structure Add a platform data (pdata) member to struct imx95_blk_ctl to store the result of of_device_get_match_data() during probe to avoid redundant calls in suspend and resume functions. Signed-off-by: Laurentiu Palcu Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20250804131450.3918846-2-laurentiu.palcu@oss.nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx95-blk-ctl.c | 36 +++++++++++------------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/drivers/clk/imx/clk-imx95-blk-ctl.c b/drivers/clk/imx/clk-imx95-blk-ctl.c index 7e88877a6245..c72debaf3a60 100644 --- a/drivers/clk/imx/clk-imx95-blk-ctl.c +++ b/drivers/clk/imx/clk-imx95-blk-ctl.c @@ -36,6 +36,7 @@ struct imx95_blk_ctl { void __iomem *base; /* clock gate register */ u32 clk_reg_restore; + const struct imx95_blk_ctl_dev_data *pdata; }; struct imx95_blk_ctl_clk_dev_data { @@ -349,7 +350,6 @@ static const struct imx95_blk_ctl_dev_data imx94_dispmix_csr_dev_data = { static int imx95_bc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct imx95_blk_ctl_dev_data *bc_data; struct imx95_blk_ctl *bc; struct clk_hw_onecell_data *clk_hw_data; struct clk_hw **hws; @@ -379,25 +379,25 @@ static int imx95_bc_probe(struct platform_device *pdev) return ret; } - bc_data = of_device_get_match_data(dev); - if (!bc_data) + bc->pdata = of_device_get_match_data(dev); + if (!bc->pdata) return devm_of_platform_populate(dev); - clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, bc_data->num_clks), + clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, bc->pdata->num_clks), GFP_KERNEL); if (!clk_hw_data) return -ENOMEM; - if (bc_data->rpm_enabled) { + if (bc->pdata->rpm_enabled) { devm_pm_runtime_enable(&pdev->dev); pm_runtime_resume_and_get(&pdev->dev); } - clk_hw_data->num = bc_data->num_clks; + clk_hw_data->num = bc->pdata->num_clks; hws = clk_hw_data->hws; - for (i = 0; i < bc_data->num_clks; i++) { - const struct imx95_blk_ctl_clk_dev_data *data = &bc_data->clk_dev_data[i]; + for (i = 0; i < bc->pdata->num_clks; i++) { + const struct imx95_blk_ctl_clk_dev_data *data = &bc->pdata->clk_dev_data[i]; void __iomem *reg = base + data->reg; if (data->type == CLK_MUX) { @@ -439,7 +439,7 @@ static int imx95_bc_probe(struct platform_device *pdev) return 0; cleanup: - for (i = 0; i < bc_data->num_clks; i++) { + for (i = 0; i < bc->pdata->num_clks; i++) { if (IS_ERR_OR_NULL(hws[i])) continue; clk_hw_unregister(hws[i]); @@ -469,14 +469,9 @@ static int imx95_bc_runtime_resume(struct device *dev) static int imx95_bc_suspend(struct device *dev) { struct imx95_blk_ctl *bc = dev_get_drvdata(dev); - const struct imx95_blk_ctl_dev_data *bc_data; int ret; - bc_data = of_device_get_match_data(dev); - if (!bc_data) - return 0; - - if (bc_data->rpm_enabled) { + if (bc->pdata->rpm_enabled) { ret = pm_runtime_get_sync(bc->dev); if (ret < 0) { pm_runtime_put_noidle(bc->dev); @@ -484,7 +479,7 @@ static int imx95_bc_suspend(struct device *dev) } } - bc->clk_reg_restore = readl(bc->base + bc_data->clk_reg_offset); + bc->clk_reg_restore = readl(bc->base + bc->pdata->clk_reg_offset); return 0; } @@ -492,15 +487,10 @@ static int imx95_bc_suspend(struct device *dev) static int imx95_bc_resume(struct device *dev) { struct imx95_blk_ctl *bc = dev_get_drvdata(dev); - const struct imx95_blk_ctl_dev_data *bc_data; - bc_data = of_device_get_match_data(dev); - if (!bc_data) - return 0; + writel(bc->clk_reg_restore, bc->base + bc->pdata->clk_reg_offset); - writel(bc->clk_reg_restore, bc->base + bc_data->clk_reg_offset); - - if (bc_data->rpm_enabled) + if (bc->pdata->rpm_enabled) pm_runtime_put(bc->dev); return 0; From 14be8b7b6cbc0a072c749e46e28d66e0ea6d0857 Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Mon, 4 Aug 2025 16:14:50 +0300 Subject: [PATCH 1323/2711] clk: imx95-blk-ctl: Save/restore registers when RPM routines are called When runtime PM is used for clock providers that are part of a power domain, the power domain supply is cut off during runtime suspend. This causes all BLK CTL registers belonging to that power domain to reset. To prevent this, save the state of the registers before entering suspend and restore them on resume. Additionally, disable the APB clock during suspend to minimize power consumption. Signed-off-by: Laurentiu Palcu Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250804131450.3918846-3-laurentiu.palcu@oss.nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx95-blk-ctl.c | 33 ++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/clk/imx/clk-imx95-blk-ctl.c b/drivers/clk/imx/clk-imx95-blk-ctl.c index c72debaf3a60..56bed4471995 100644 --- a/drivers/clk/imx/clk-imx95-blk-ctl.c +++ b/drivers/clk/imx/clk-imx95-blk-ctl.c @@ -453,15 +453,24 @@ static int imx95_bc_runtime_suspend(struct device *dev) { struct imx95_blk_ctl *bc = dev_get_drvdata(dev); + bc->clk_reg_restore = readl(bc->base + bc->pdata->clk_reg_offset); clk_disable_unprepare(bc->clk_apb); + return 0; } static int imx95_bc_runtime_resume(struct device *dev) { struct imx95_blk_ctl *bc = dev_get_drvdata(dev); + int ret; - return clk_prepare_enable(bc->clk_apb); + ret = clk_prepare_enable(bc->clk_apb); + if (ret) + return ret; + + writel(bc->clk_reg_restore, bc->base + bc->pdata->clk_reg_offset); + + return 0; } #endif @@ -469,17 +478,12 @@ static int imx95_bc_runtime_resume(struct device *dev) static int imx95_bc_suspend(struct device *dev) { struct imx95_blk_ctl *bc = dev_get_drvdata(dev); - int ret; - if (bc->pdata->rpm_enabled) { - ret = pm_runtime_get_sync(bc->dev); - if (ret < 0) { - pm_runtime_put_noidle(bc->dev); - return ret; - } - } + if (pm_runtime_suspended(dev)) + return 0; bc->clk_reg_restore = readl(bc->base + bc->pdata->clk_reg_offset); + clk_disable_unprepare(bc->clk_apb); return 0; } @@ -487,12 +491,17 @@ static int imx95_bc_suspend(struct device *dev) static int imx95_bc_resume(struct device *dev) { struct imx95_blk_ctl *bc = dev_get_drvdata(dev); + int ret; + + if (pm_runtime_suspended(dev)) + return 0; + + ret = clk_prepare_enable(bc->clk_apb); + if (ret) + return ret; writel(bc->clk_reg_restore, bc->base + bc->pdata->clk_reg_offset); - if (bc->pdata->rpm_enabled) - pm_runtime_put(bc->dev); - return 0; } #endif From 810b790033ccc795d55cbef3927668fd01efdfdf Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 12 Sep 2025 14:13:47 +0100 Subject: [PATCH 1324/2711] nvmem: layouts: fix automatic module loading To support loading of a layout module automatically the MODALIAS variable in the uevent is needed. Add it. Fixes: fc29fd821d9a ("nvmem: core: Rework layouts to become regular devices") Cc: stable@vger.kernel.org Signed-off-by: Michael Walle Reviewed-by: Miquel Raynal Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131347.303345-2-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/layouts.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c index 65d39e19f6ec..f381ce1e84bd 100644 --- a/drivers/nvmem/layouts.c +++ b/drivers/nvmem/layouts.c @@ -45,11 +45,24 @@ static void nvmem_layout_bus_remove(struct device *dev) return drv->remove(layout); } +static int nvmem_layout_bus_uevent(const struct device *dev, + struct kobj_uevent_env *env) +{ + int ret; + + ret = of_device_uevent_modalias(dev, env); + if (ret != ENODEV) + return ret; + + return 0; +} + static const struct bus_type nvmem_layout_bus_type = { .name = "nvmem-layout", .match = nvmem_layout_bus_match, .probe = nvmem_layout_bus_probe, .remove = nvmem_layout_bus_remove, + .uevent = nvmem_layout_bus_uevent, }; int __nvmem_layout_driver_register(struct nvmem_layout_driver *drv, From 8b5b456222fd604079b5cf2af1f25ad690f54a25 Mon Sep 17 00:00:00 2001 From: Ling Xu Date: Fri, 12 Sep 2025 14:12:33 +0100 Subject: [PATCH 1325/2711] misc: fastrpc: Save actual DMA size in fastrpc_map structure For user passed fd buffer, map is created using DMA calls. The map related information is stored in fastrpc_map structure. The actual DMA size is not stored in the structure. Store the actual size of buffer and check it against the user passed size. Fixes: c68cfb718c8f ("misc: fastrpc: Add support for context Invoke method") Cc: stable@kernel.org Reviewed-by: Dmitry Baryshkov Co-developed-by: Ekansh Gupta Signed-off-by: Ekansh Gupta Signed-off-by: Ling Xu Reviewed-by: Dmitry Baryshkov Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131236.303102-2-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 53e88a1bc430..52571916acd4 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -323,11 +323,11 @@ static void fastrpc_free_map(struct kref *ref) perm.vmid = QCOM_SCM_VMID_HLOS; perm.perm = QCOM_SCM_PERM_RWX; - err = qcom_scm_assign_mem(map->phys, map->size, + err = qcom_scm_assign_mem(map->phys, map->len, &src_perms, &perm, 1); if (err) { dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d\n", - map->phys, map->size, err); + map->phys, map->len, err); return; } } @@ -758,7 +758,8 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, struct fastrpc_session_ctx *sess = fl->sctx; struct fastrpc_map *map = NULL; struct sg_table *table; - int err = 0; + struct scatterlist *sgl = NULL; + int err = 0, sgl_index = 0; if (!fastrpc_map_lookup(fl, fd, ppmap, true)) return 0; @@ -798,7 +799,15 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, map->phys = sg_dma_address(map->table->sgl); map->phys += ((u64)fl->sctx->sid << 32); } - map->size = len; + for_each_sg(map->table->sgl, sgl, map->table->nents, + sgl_index) + map->size += sg_dma_len(sgl); + if (len > map->size) { + dev_dbg(sess->dev, "Bad size passed len 0x%llx map size 0x%llx\n", + len, map->size); + err = -EINVAL; + goto map_err; + } map->va = sg_virt(map->table->sgl); map->len = len; @@ -815,10 +824,10 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, dst_perms[1].vmid = fl->cctx->vmperms[0].vmid; dst_perms[1].perm = QCOM_SCM_PERM_RWX; map->attr = attr; - err = qcom_scm_assign_mem(map->phys, (u64)map->size, &src_perms, dst_perms, 2); + err = qcom_scm_assign_mem(map->phys, (u64)map->len, &src_perms, dst_perms, 2); if (err) { dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d\n", - map->phys, map->size, err); + map->phys, map->len, err); goto map_err; } } @@ -2046,7 +2055,7 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp) args[0].length = sizeof(req_msg); pages.addr = map->phys; - pages.size = map->size; + pages.size = map->len; args[1].ptr = (u64) (uintptr_t) &pages; args[1].length = sizeof(pages); @@ -2061,7 +2070,7 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp) err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc, &args[0]); if (err) { dev_err(dev, "mem mmap error, fd %d, vaddr %llx, size %lld\n", - req.fd, req.vaddrin, map->size); + req.fd, req.vaddrin, map->len); goto err_invoke; } @@ -2074,7 +2083,7 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp) if (copy_to_user((void __user *)argp, &req, sizeof(req))) { /* unmap the memory and release the buffer */ req_unmap.vaddr = (uintptr_t) rsp_msg.vaddr; - req_unmap.length = map->size; + req_unmap.length = map->len; fastrpc_req_mem_unmap_impl(fl, &req_unmap); return -EFAULT; } From 9031626ade38b092b72638dfe0c6ffce8d8acd43 Mon Sep 17 00:00:00 2001 From: Ling Xu Date: Fri, 12 Sep 2025 14:12:34 +0100 Subject: [PATCH 1326/2711] misc: fastrpc: Fix fastrpc_map_lookup operation Fastrpc driver creates maps for user allocated fd buffers. Before creating a new map, the map list is checked for any already existing maps using map fd. Checking with just map fd is not sufficient as the user can pass offsetted buffer with less size when the map is created and then a larger size the next time which could result in memory issues. Check for dma_buf object also when looking up for the map. Fixes: c68cfb718c8f ("misc: fastrpc: Add support for context Invoke method") Cc: stable@kernel.org Co-developed-by: Ekansh Gupta Signed-off-by: Ekansh Gupta Signed-off-by: Ling Xu Reviewed-by: Dmitry Baryshkov Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131236.303102-3-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 52571916acd4..1815b1e0c607 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -367,11 +367,16 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd, { struct fastrpc_session_ctx *sess = fl->sctx; struct fastrpc_map *map = NULL; + struct dma_buf *buf; int ret = -ENOENT; + buf = dma_buf_get(fd); + if (IS_ERR(buf)) + return PTR_ERR(buf); + spin_lock(&fl->lock); list_for_each_entry(map, &fl->maps, node) { - if (map->fd != fd) + if (map->fd != fd || map->buf != buf) continue; if (take_ref) { From da1ba64176e0138f2bfa96f9e43e8c3640d01e1e Mon Sep 17 00:00:00 2001 From: Ling Xu Date: Fri, 12 Sep 2025 14:12:35 +0100 Subject: [PATCH 1327/2711] misc: fastrpc: fix possible map leak in fastrpc_put_args copy_to_user() failure would cause an early return without cleaning up the fdlist, which has been updated by the DSP. This could lead to map leak. Fix this by redirecting to a cleanup path on failure, ensuring that all mapped buffers are properly released before returning. Fixes: c68cfb718c8f ("misc: fastrpc: Add support for context Invoke method") Cc: stable@kernel.org Co-developed-by: Ekansh Gupta Signed-off-by: Ekansh Gupta Signed-off-by: Ling Xu Reviewed-by: Dmitry Baryshkov Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131236.303102-4-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 1815b1e0c607..d950a179bff8 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -1085,6 +1085,7 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, struct fastrpc_phy_page *pages; u64 *fdlist; int i, inbufs, outbufs, handles; + int ret = 0; inbufs = REMOTE_SCALARS_INBUFS(ctx->sc); outbufs = REMOTE_SCALARS_OUTBUFS(ctx->sc); @@ -1100,14 +1101,17 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, u64 len = rpra[i].buf.len; if (!kernel) { - if (copy_to_user((void __user *)dst, src, len)) - return -EFAULT; + if (copy_to_user((void __user *)dst, src, len)) { + ret = -EFAULT; + goto cleanup_fdlist; + } } else { memcpy(dst, src, len); } } } +cleanup_fdlist: /* Clean up fdlist which is updated by DSP */ for (i = 0; i < FASTRPC_MAX_FDLIST; i++) { if (!fdlist[i]) @@ -1116,7 +1120,7 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, fastrpc_map_put(mmap); } - return 0; + return ret; } static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx, From 10df039834f84a297c72ec962c0f9b7c8c5ca31a Mon Sep 17 00:00:00 2001 From: Ling Xu Date: Fri, 12 Sep 2025 14:12:36 +0100 Subject: [PATCH 1328/2711] misc: fastrpc: Skip reference for DMA handles If multiple dma handles are passed with same fd over a remote call the kernel driver takes a reference and expects that put for the map will be called as many times to free the map. But DSP only updates the fd one time in the fd list when the DSP refcount goes to zero and hence kernel make put call only once for the fd. This can cause SMMU fault issue as the same fd can be used in future for some other call. Fixes: 35a82b87135d ("misc: fastrpc: Add dma handle implementation") Cc: stable@kernel.org Co-developed-by: Ekansh Gupta Signed-off-by: Ekansh Gupta Signed-off-by: Ling Xu Reviewed-by: Dmitry Baryshkov Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20250912131236.303102-5-srini@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 45 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index d950a179bff8..7eec907ed454 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -363,9 +363,8 @@ static int fastrpc_map_get(struct fastrpc_map *map) static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd, - struct fastrpc_map **ppmap, bool take_ref) + struct fastrpc_map **ppmap) { - struct fastrpc_session_ctx *sess = fl->sctx; struct fastrpc_map *map = NULL; struct dma_buf *buf; int ret = -ENOENT; @@ -379,15 +378,6 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd, if (map->fd != fd || map->buf != buf) continue; - if (take_ref) { - ret = fastrpc_map_get(map); - if (ret) { - dev_dbg(sess->dev, "%s: Failed to get map fd=%d ret=%d\n", - __func__, fd, ret); - break; - } - } - *ppmap = map; ret = 0; break; @@ -757,7 +747,7 @@ static const struct dma_buf_ops fastrpc_dma_buf_ops = { .release = fastrpc_release, }; -static int fastrpc_map_create(struct fastrpc_user *fl, int fd, +static int fastrpc_map_attach(struct fastrpc_user *fl, int fd, u64 len, u32 attr, struct fastrpc_map **ppmap) { struct fastrpc_session_ctx *sess = fl->sctx; @@ -766,9 +756,6 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, struct scatterlist *sgl = NULL; int err = 0, sgl_index = 0; - if (!fastrpc_map_lookup(fl, fd, ppmap, true)) - return 0; - map = kzalloc(sizeof(*map), GFP_KERNEL); if (!map) return -ENOMEM; @@ -853,6 +840,24 @@ get_err: return err; } +static int fastrpc_map_create(struct fastrpc_user *fl, int fd, + u64 len, u32 attr, struct fastrpc_map **ppmap) +{ + struct fastrpc_session_ctx *sess = fl->sctx; + int err = 0; + + if (!fastrpc_map_lookup(fl, fd, ppmap)) { + if (!fastrpc_map_get(*ppmap)) + return 0; + dev_dbg(sess->dev, "%s: Failed to get map fd=%d\n", + __func__, fd); + } + + err = fastrpc_map_attach(fl, fd, len, attr, ppmap); + + return err; +} + /* * Fastrpc payload buffer with metadata looks like: * @@ -925,8 +930,12 @@ static int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx) ctx->args[i].length == 0) continue; - err = fastrpc_map_create(ctx->fl, ctx->args[i].fd, - ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]); + if (i < ctx->nbufs) + err = fastrpc_map_create(ctx->fl, ctx->args[i].fd, + ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]); + else + err = fastrpc_map_attach(ctx->fl, ctx->args[i].fd, + ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]); if (err) { dev_err(dev, "Error Creating map %d\n", err); return -EINVAL; @@ -1116,7 +1125,7 @@ cleanup_fdlist: for (i = 0; i < FASTRPC_MAX_FDLIST; i++) { if (!fdlist[i]) break; - if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false)) + if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap)) fastrpc_map_put(mmap); } From 4e411a3f7bba10579bbeec3af77ae2a05c9e4259 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 21 Aug 2025 16:38:13 +0200 Subject: [PATCH 1329/2711] HID: core: factor out hid_set_group() When we load a bpf, we can change the report descriptor. However, the current implementation doesn't change the group meaning that we can not rebind a device from hid-generic to hid-multitouch. This is a preparatory patch to force a rescan of the device after the bpf has been loaded. Signed-off-by: Benjamin Tissoires Reviewed-by: Peter Hutterer Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5419a6c10907..cf68fdffe058 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2708,6 +2708,20 @@ static bool hid_check_device_match(struct hid_device *hdev, return !hid_ignore_special_drivers && !(hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER); } +static void hid_set_group(struct hid_device *hdev) +{ + int ret; + + if (hid_ignore_special_drivers) { + hdev->group = HID_GROUP_GENERIC; + } else if (!hdev->group && + !(hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER)) { + ret = hid_scan_report(hdev); + if (ret) + hid_warn(hdev, "bad device descriptor (%d)\n", ret); + } +} + static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv) { const struct hid_device_id *id; @@ -2903,14 +2917,7 @@ int hid_add_device(struct hid_device *hdev) /* * Scan generic devices for group information */ - if (hid_ignore_special_drivers) { - hdev->group = HID_GROUP_GENERIC; - } else if (!hdev->group && - !(hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER)) { - ret = hid_scan_report(hdev); - if (ret) - hid_warn(hdev, "bad device descriptor (%d)\n", ret); - } + hid_set_group(hdev); hdev->id = atomic_inc_return(&id); From 4c2c5ff9f3d72fb41f884f7c493ae9df83379340 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 21 Aug 2025 16:38:14 +0200 Subject: [PATCH 1330/2711] HID: bpf: rescan the device for the group after a load/unload When a BPF gets loaded, it was previously not possible to bind a hid-generic device to hid-multitouch because the group was never updated. This change forces a rescan of the report descriptor after a bpf is loaded/unloaded so we set up the proper group. This was detected while Peter was trying to fix a Viewsonic device: the HID device sending multiotuch data through a proprietary collection was handled by hid-generic, and we don't have any way of attaching it to hid-multitouch because the pre-scanning wasn't able to see the Contact ID HID usage. Suggested-by: Peter Hutterer Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index cf68fdffe058..a5b3a8ca2fcb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -943,6 +943,15 @@ static int hid_scan_report(struct hid_device *hid) parser->device = hid; hid->group = HID_GROUP_GENERIC; + /* + * In case we are re-scanning after a BPF has been loaded, + * we need to use the bpf report descriptor, not the original one. + */ + if (hid->bpf_rdesc && hid->bpf_rsize) { + start = hid->bpf_rdesc; + end = start + hid->bpf_rsize; + } + /* * The parsing is simpler than the one in hid_open_report() as we should * be robust against hid errors. Those errors will be raised by @@ -2728,6 +2737,12 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv) int ret; if (!hdev->bpf_rsize) { + /* we keep a reference to the currently scanned report descriptor */ + const __u8 *original_rdesc = hdev->bpf_rdesc; + + if (!original_rdesc) + original_rdesc = hdev->dev_rdesc; + /* in case a bpf program gets detached, we need to free the old one */ hid_free_bpf_rdesc(hdev); @@ -2737,6 +2752,12 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv) /* call_hid_bpf_rdesc_fixup will always return a valid pointer */ hdev->bpf_rdesc = call_hid_bpf_rdesc_fixup(hdev, hdev->dev_rdesc, &hdev->bpf_rsize); + + /* the report descriptor changed, we need to re-scan it */ + if (original_rdesc != hdev->bpf_rdesc) { + hdev->group = 0; + hid_set_group(hdev); + } } if (!hid_check_device_match(hdev, hdrv, &id)) From 8931f7b27993444adfc8cd1d3c6592cc167fb280 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Thu, 21 Aug 2025 10:06:09 +0800 Subject: [PATCH 1331/2711] HID: intel-ish-ipc: Remove redundant ready check after timeout function timed_wait_for_timeout() internally checks for ish_is_input_ready() and ishtp_fw_is_ready() based on the provided parameters. If timed_wait_for_timeout() returns 0, it indicates the status is ready. In rare cases, another thread may send a message immediately after timed_wait_for_timeout() returns, causing a subsequent ish_is_input_ready() check to fail. Since the return value of timed_wait_for_timeout() is sufficient to determine readiness, the additional ready check is unnecessary and may introduce issues. This patch removes the redundant check and relies solely on the return value of timed_wait_for_timeout(). Fixes: ae02e5d40d5f ("HID: intel-ish-hid: ipc layer") Signed-off-by: Zhang Lixu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/ipc.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c index 4c861119e97a..3ddaa2cd39d5 100644 --- a/drivers/hid/intel-ish-hid/ipc/ipc.c +++ b/drivers/hid/intel-ish-hid/ipc/ipc.c @@ -498,6 +498,7 @@ static int ish_fw_reset_handler(struct ishtp_device *dev) { uint32_t reset_id; unsigned long flags; + int ret; /* Read reset ID */ reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF; @@ -510,12 +511,11 @@ static int ish_fw_reset_handler(struct ishtp_device *dev) /* ISHTP notification in IPC_RESET */ ishtp_reset_handler(dev); - if (!ish_is_input_ready(dev)) - timed_wait_for_timeout(dev, WAIT_FOR_INPUT_RDY, - TIME_SLICE_FOR_INPUT_RDY_MS, TIMEOUT_FOR_INPUT_RDY_MS); - + ret = timed_wait_for_timeout(dev, WAIT_FOR_INPUT_RDY, + TIME_SLICE_FOR_INPUT_RDY_MS, + TIMEOUT_FOR_INPUT_RDY_MS); /* ISH FW is dead */ - if (!ish_is_input_ready(dev)) + if (ret) return -EPIPE; /* Send clock sync at once after reset */ @@ -531,9 +531,10 @@ static int ish_fw_reset_handler(struct ishtp_device *dev) sizeof(uint32_t)); /* Wait for ISH FW'es ILUP and ISHTP_READY */ - timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY, - TIME_SLICE_FOR_FW_RDY_MS, TIMEOUT_FOR_FW_RDY_MS); - if (!ishtp_fw_is_ready(dev)) { + ret = timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY, + TIME_SLICE_FOR_FW_RDY_MS, + TIMEOUT_FOR_FW_RDY_MS); + if (ret) { /* ISH FW is dead */ uint32_t ish_status; From d927909d4d7a57fc27684e0761fa7ca1991ba115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Sat, 23 Aug 2025 21:45:16 +0200 Subject: [PATCH 1332/2711] HID: pidff: Fix possible null pointer dereference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As reported by Dan Carpenter, if the axes_enable field wasn't found, trying to find the axes themselves will result in a null pointer dereference. This could only occur with a broken PID descriptor, but it's worth protecting from. Exit early if the axes_enable wasn't found AND add a gate to the pidff_find_special_keys to exit early if the passed HID field is null. This will protect again null dereferencing in the future and properly return 0 found special keys. Fixes: 1d72e7bd340b ("HID: pidff: Add support for AXES_ENABLE field") Reported-by: Dan Carpenter Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 0342c0a3f476..edd61ef50e16 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -1194,6 +1194,9 @@ static int pidff_find_special_keys(int *keys, struct hid_field *fld, { int found = 0; + if (!fld) + return 0; + for (int i = 0; i < count; i++) { keys[i] = pidff_find_usage(fld, usage_page | usagetable[i]) + 1; if (keys[i]) @@ -1299,11 +1302,13 @@ static int pidff_find_special_fields(struct pidff_device *pidff) return -1; } - if (!pidff->axes_enable) + if (!pidff->axes_enable) { hid_info(pidff->hid, "axes enable field not found!\n"); - else - hid_dbg(pidff->hid, "axes enable report count: %u\n", - pidff->axes_enable->report_count); + return 0; + } + + hid_dbg(pidff->hid, "axes enable report count: %u\n", + pidff->axes_enable->report_count); uint found = PIDFF_FIND_GENERAL_DESKTOP(direction_axis_id, axes_enable, direction_axis); @@ -1311,7 +1316,7 @@ static int pidff_find_special_fields(struct pidff_device *pidff) pidff->axis_count = found; hid_dbg(pidff->hid, "found direction axes: %u", found); - for (int i = 0; i < sizeof(pidff_direction_axis); i++) { + for (int i = 0; i < ARRAY_SIZE(pidff_direction_axis); i++) { if (!pidff->direction_axis_id[i]) continue; From b595974b4afe0e171dd707da570964ff642742e3 Mon Sep 17 00:00:00 2001 From: Antheas Kapenekakis Date: Thu, 14 Aug 2025 15:01:51 +0200 Subject: [PATCH 1333/2711] HID: asus: add Z13 folio to generic group for multitouch to work The Asus Z13 folio has a multitouch touchpad that needs to bind to the hid-multitouch driver in order to work properly. So bind it to the HID_GROUP_GENERIC group to release the touchpad and move it to the bottom so that the comment applies to it. While at it, change the generic KEYBOARD3 name to Z13_FOLIO. Reviewed-by: Luke D. Jones Signed-off-by: Antheas Kapenekakis Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 6 +++--- drivers/hid/hid-ids.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index d27dcfb2b9e4..722770f3e6c9 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -1384,9 +1384,6 @@ static const struct hid_device_id asus_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3), - QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR), QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, @@ -1416,6 +1413,9 @@ static const struct hid_device_id asus_devices[] = { * Note bind to the HID_GROUP_GENERIC group, so that we only bind to the keyboard * part, while letting hid-multitouch.c handle the touchpad. */ + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_Z13_FOLIO), + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD) }, { } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 149798754570..5531e15eda6d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -223,7 +223,7 @@ #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6 -#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3 0x1a30 +#define USB_DEVICE_ID_ASUSTEK_ROG_Z13_FOLIO 0x1a30 #define USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR 0x18c6 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY 0x1abe #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X 0x1b4c From bdbb4a2d2aeae3d115bbdc402adac72aec071492 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 17 Aug 2025 07:48:17 -0700 Subject: [PATCH 1334/2711] watchdog: intel_oc_wdt: Do not try to write into const memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code tries to update the intel_oc_wdt_info data structure if the watchdog is locked. That data structure is marked as const and can not be written into. Copy it into struct intel_oc_wdt and modify it there to fix the problem. Reported-by: Petar Kulić Cc: Diogo Ivo Fixes: 535d1784d8a9 ("watchdog: Add driver for Intel OC WDT") Signed-off-by: Guenter Roeck Reviewed-by: Diogo Ivo Tested-by: Diogo Ivo Link: https://lore.kernel.org/linux-watchdog/20250818031838.3359-1-diogo.ivo@tecnico.ulisboa.pt/T/#t Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/intel_oc_wdt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/intel_oc_wdt.c b/drivers/watchdog/intel_oc_wdt.c index 7c0551106981..a39892c10770 100644 --- a/drivers/watchdog/intel_oc_wdt.c +++ b/drivers/watchdog/intel_oc_wdt.c @@ -41,6 +41,7 @@ struct intel_oc_wdt { struct watchdog_device wdd; struct resource *ctrl_res; + struct watchdog_info info; bool locked; }; @@ -115,7 +116,6 @@ static const struct watchdog_ops intel_oc_wdt_ops = { static int intel_oc_wdt_setup(struct intel_oc_wdt *oc_wdt) { - struct watchdog_info *info; unsigned long val; val = inl(INTEL_OC_WDT_CTRL_REG(oc_wdt)); @@ -134,7 +134,6 @@ static int intel_oc_wdt_setup(struct intel_oc_wdt *oc_wdt) set_bit(WDOG_HW_RUNNING, &oc_wdt->wdd.status); if (oc_wdt->locked) { - info = (struct watchdog_info *)&intel_oc_wdt_info; /* * Set nowayout unconditionally as we cannot stop * the watchdog. @@ -145,7 +144,7 @@ static int intel_oc_wdt_setup(struct intel_oc_wdt *oc_wdt) * and inform the core we can't change it. */ oc_wdt->wdd.timeout = (val & INTEL_OC_WDT_TOV) + 1; - info->options &= ~WDIOF_SETTIMEOUT; + oc_wdt->info.options &= ~WDIOF_SETTIMEOUT; dev_info(oc_wdt->wdd.parent, "Register access locked, heartbeat fixed at: %u s\n", @@ -193,7 +192,8 @@ static int intel_oc_wdt_probe(struct platform_device *pdev) wdd->min_timeout = INTEL_OC_WDT_MIN_TOV; wdd->max_timeout = INTEL_OC_WDT_MAX_TOV; wdd->timeout = INTEL_OC_WDT_DEF_TOV; - wdd->info = &intel_oc_wdt_info; + oc_wdt->info = intel_oc_wdt_info; + wdd->info = &oc_wdt->info; wdd->ops = &intel_oc_wdt_ops; wdd->parent = dev; From 5cacd26436a66e24b1f0335a5d2b71eed4ab0d74 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 20 Aug 2025 21:23:17 +0100 Subject: [PATCH 1335/2711] dt-bindings: watchdog: renesas,wdt: Add support for RZ/T2H and RZ/N2H Extend the Renesas WDT device tree bindings to support the watchdog timer found on the RZ/T2H (R9A09G077) and RZ/N2H (R9A09G087) SoCs. The RZ/T2H WDT is mostly compatible with the one found on the RZ/V2H(P), but includes an additional register and differs in the clock division ratio settings for the WDTCR[CKS] field. To reflect these differences, introduce a new compatible string, "renesas,r9a09g077-wdt". The binding schema is updated accordingly. On RZ/T2H, the WDT does not require the "resets" property. It also requires two register regions and the presence of a "power-domains" property. The "clock-names" property is limited to a single entry, "pclk", for this SoC. The RZ/N2H SoC uses the same WDT IP as the RZ/T2H. It is supported by using "renesas,r9a09g087-wdt" as the primary compatible string, with "renesas,r9a09g077-wdt" listed as a fallback to describe the shared hardware features. Example: wdt0: watchdog@80082000 { compatible = "renesas,r9a09g077-wdt"; reg = <0 0x80082000 0 0x400>, <0 0x81295100 0 0x04>; clocks = <&cpg CPG_CORE R9A09G077_CLK_PCLKL>; clock-names = "pclk"; power-domains = <&cpg>; status = "disabled"; }; Signed-off-by: Lad Prabhakar Reviewed-by: Rob Herring (Arm) Reviewed-by: Geert Uytterhoeven Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../bindings/watchdog/renesas,wdt.yaml | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml b/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml index 78874b90c88c..b6e60162c263 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml @@ -81,10 +81,17 @@ properties: - renesas,r9a09g056-wdt # RZ/V2N - const: renesas,r9a09g057-wdt # RZ/V2H(P) - - const: renesas,r9a09g057-wdt # RZ/V2H(P) + - enum: + - renesas,r9a09g057-wdt # RZ/V2H(P) + - renesas,r9a09g077-wdt # RZ/T2H + + - items: + - const: renesas,r9a09g087-wdt # RZ/N2H + - const: renesas,r9a09g077-wdt # RZ/T2H reg: - maxItems: 1 + minItems: 1 + maxItems: 2 interrupts: minItems: 1 @@ -132,6 +139,7 @@ allOf: compatible: contains: enum: + - renesas,r9a09g077-wdt - renesas,rza-wdt - renesas,rzn1-wdt then: @@ -183,7 +191,9 @@ allOf: properties: compatible: contains: - const: renesas,r9a09g057-wdt + enum: + - renesas,r9a09g057-wdt + - renesas,r9a09g077-wdt then: properties: interrupts: false @@ -192,6 +202,26 @@ allOf: required: - interrupts + - if: + properties: + compatible: + contains: + const: renesas,r9a09g077-wdt + then: + properties: + resets: false + clock-names: + maxItems: 1 + reg: + minItems: 2 + required: + - clock-names + - power-domains + else: + properties: + reg: + maxItems: 1 + additionalProperties: false examples: From 19f7eaec4d9d1dcd8b49e14dbad56a65810c2910 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 20 Aug 2025 21:23:18 +0100 Subject: [PATCH 1336/2711] watchdog: rzv2h: Obtain clock-divider and timeout values from OF match data Update the rzv2h_wdt driver to fetch clock configuration and timeout parameters from device tree match data rather than relying on hardcoded constants. Introduce a new structure rzv2h_of_data that encapsulates minimum and maximum clock select values (cks_min and cks_max), clock divider (cks_div), timeout cycle count (timeout_cycles), and the timeout period select bits (tops). These values are provided through the OF match table and retrieved via of_device_get_match_data() during probe. This change allows dynamic configuration of the watchdog timer for different SoCs, such as the RZ/T2H, which require different settings. Signed-off-by: Lad Prabhakar Reviewed-by: Wolfram Sang Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/rzv2h_wdt.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/watchdog/rzv2h_wdt.c b/drivers/watchdog/rzv2h_wdt.c index 8defd0241213..755067800ebb 100644 --- a/drivers/watchdog/rzv2h_wdt.c +++ b/drivers/watchdog/rzv2h_wdt.c @@ -35,9 +35,6 @@ #define WDTRCR_RSTIRQS BIT(7) -#define MAX_TIMEOUT_CYCLES 16384 -#define CLOCK_DIV_BY_256 256 - #define WDT_DEFAULT_TIMEOUT 60U static bool nowayout = WATCHDOG_NOWAYOUT; @@ -45,12 +42,21 @@ module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +struct rzv2h_of_data { + u8 cks_min; + u8 cks_max; + u16 cks_div; + u8 tops; + u16 timeout_cycles; +}; + struct rzv2h_wdt_priv { void __iomem *base; struct clk *pclk; struct clk *oscclk; struct reset_control *rstc; struct watchdog_device wdev; + const struct rzv2h_of_data *of_data; }; static int rzv2h_wdt_ping(struct watchdog_device *wdev) @@ -84,6 +90,7 @@ static void rzv2h_wdt_setup(struct watchdog_device *wdev, u16 wdtcr) static int rzv2h_wdt_start(struct watchdog_device *wdev) { struct rzv2h_wdt_priv *priv = watchdog_get_drvdata(wdev); + const struct rzv2h_of_data *of_data = priv->of_data; int ret; ret = pm_runtime_resume_and_get(wdev->parent); @@ -106,8 +113,8 @@ static int rzv2h_wdt_start(struct watchdog_device *wdev) * - RPES[9:8] - Window End Position Select - 11b: 0% * - TOPS[1:0] - Timeout Period Select - 11b: 16384 cycles (3FFFh) */ - rzv2h_wdt_setup(wdev, WDTCR_CKS_CLK_256 | WDTCR_RPSS_100 | - WDTCR_RPES_0 | WDTCR_TOPS_16384); + rzv2h_wdt_setup(wdev, of_data->cks_max | WDTCR_RPSS_100 | + WDTCR_RPES_0 | of_data->tops); /* * Down counting starts after writing the sequence 00h -> FFh to the @@ -184,7 +191,7 @@ static int rzv2h_wdt_restart(struct watchdog_device *wdev, * - RPES[9:8] - Window End Position Select - 00b: 75% * - TOPS[1:0] - Timeout Period Select - 00b: 1024 cycles (03FFh) */ - rzv2h_wdt_setup(wdev, WDTCR_CKS_CLK_1 | WDTCR_RPSS_25 | + rzv2h_wdt_setup(wdev, priv->of_data->cks_min | WDTCR_RPSS_25 | WDTCR_RPES_75 | WDTCR_TOPS_1024); rzv2h_wdt_ping(wdev); @@ -213,6 +220,8 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + priv->of_data = of_device_get_match_data(dev); + priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); @@ -230,8 +239,8 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(priv->rstc), "failed to get cpg reset"); - priv->wdev.max_hw_heartbeat_ms = (MILLI * MAX_TIMEOUT_CYCLES * CLOCK_DIV_BY_256) / - clk_get_rate(priv->oscclk); + priv->wdev.max_hw_heartbeat_ms = (MILLI * priv->of_data->timeout_cycles * + priv->of_data->cks_div) / clk_get_rate(priv->oscclk); dev_dbg(dev, "max hw timeout of %dms\n", priv->wdev.max_hw_heartbeat_ms); ret = devm_pm_runtime_enable(dev); @@ -254,8 +263,16 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) return devm_watchdog_register_device(dev, &priv->wdev); } +static const struct rzv2h_of_data rzv2h_wdt_of_data = { + .cks_min = WDTCR_CKS_CLK_1, + .cks_max = WDTCR_CKS_CLK_256, + .cks_div = 256, + .tops = WDTCR_TOPS_16384, + .timeout_cycles = 16384, +}; + static const struct of_device_id rzv2h_wdt_ids[] = { - { .compatible = "renesas,r9a09g057-wdt", }, + { .compatible = "renesas,r9a09g057-wdt", .data = &rzv2h_wdt_of_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, rzv2h_wdt_ids); From 6229b35298af8c3cb983d866e9da1c1ad4803cc6 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 20 Aug 2025 21:23:19 +0100 Subject: [PATCH 1337/2711] watchdog: rzv2h: Make "oscclk" and reset controller optional Update the rzv2h_wdt driver to make the "oscclk" clock and reset controller optional. Use devm_clk_get_optional_prepared() to obtain the "oscclk" clock, allowing the driver to work on platforms that do not provide this clock, such as the RZ/T2H SoC. Similarly, use devm_reset_control_get_optional_exclusive() to allow the driver to function on platforms that lack a reset controller. These changes are preparatory steps for supporting the RZ/T2H SoC, which does not provide an "oscclk" clock or a reset controller. Signed-off-by: Lad Prabhakar Reviewed-by: Wolfram Sang Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/rzv2h_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/rzv2h_wdt.c b/drivers/watchdog/rzv2h_wdt.c index 755067800ebb..3c02960b65cf 100644 --- a/drivers/watchdog/rzv2h_wdt.c +++ b/drivers/watchdog/rzv2h_wdt.c @@ -230,11 +230,11 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) if (IS_ERR(priv->pclk)) return dev_err_probe(dev, PTR_ERR(priv->pclk), "no pclk"); - priv->oscclk = devm_clk_get_prepared(dev, "oscclk"); + priv->oscclk = devm_clk_get_optional_prepared(dev, "oscclk"); if (IS_ERR(priv->oscclk)) return dev_err_probe(dev, PTR_ERR(priv->oscclk), "no oscclk"); - priv->rstc = devm_reset_control_get_exclusive(dev, NULL); + priv->rstc = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(priv->rstc)) return dev_err_probe(dev, PTR_ERR(priv->rstc), "failed to get cpg reset"); From ef6080fec60af92fc00b96743e85779927baf87b Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 20 Aug 2025 21:23:20 +0100 Subject: [PATCH 1338/2711] watchdog: rzv2h: Add support for configurable count clock source Add support for selecting the count clock source used by the watchdog timer. The RZ/V2H(P) SoC uses the LOCO as the count source, whereas on RZ/T2H and RZ/N2H SoCs, the count source is the peripheral clock (PCLKL). Introduce a `count_source` field in the SoC-specific data structure and refactor the clock rate selection logic accordingly. This prepares the driver for supporting the RZ/T2H and RZ/N2H SoCs, which differ in their watchdog clocking architecture from RZ/V2H(P). Signed-off-by: Lad Prabhakar Reviewed-by: Wolfram Sang Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/rzv2h_wdt.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/rzv2h_wdt.c b/drivers/watchdog/rzv2h_wdt.c index 3c02960b65cf..e71d1e108f69 100644 --- a/drivers/watchdog/rzv2h_wdt.c +++ b/drivers/watchdog/rzv2h_wdt.c @@ -42,12 +42,18 @@ module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +enum rzv2h_wdt_count_source { + COUNT_SOURCE_LOCO, + COUNT_SOURCE_PCLK, +}; + struct rzv2h_of_data { u8 cks_min; u8 cks_max; u16 cks_div; u8 tops; u16 timeout_cycles; + enum rzv2h_wdt_count_source count_source; }; struct rzv2h_wdt_priv { @@ -214,6 +220,7 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rzv2h_wdt_priv *priv; + struct clk *count_clk; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -239,8 +246,19 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(priv->rstc), "failed to get cpg reset"); + switch (priv->of_data->count_source) { + case COUNT_SOURCE_LOCO: + count_clk = priv->oscclk; + break; + case COUNT_SOURCE_PCLK: + count_clk = priv->pclk; + break; + default: + return dev_err_probe(dev, -EINVAL, "Invalid count source\n"); + } + priv->wdev.max_hw_heartbeat_ms = (MILLI * priv->of_data->timeout_cycles * - priv->of_data->cks_div) / clk_get_rate(priv->oscclk); + priv->of_data->cks_div) / clk_get_rate(count_clk); dev_dbg(dev, "max hw timeout of %dms\n", priv->wdev.max_hw_heartbeat_ms); ret = devm_pm_runtime_enable(dev); @@ -269,6 +287,7 @@ static const struct rzv2h_of_data rzv2h_wdt_of_data = { .cks_div = 256, .tops = WDTCR_TOPS_16384, .timeout_cycles = 16384, + .count_source = COUNT_SOURCE_LOCO, }; static const struct of_device_id rzv2h_wdt_ids[] = { From 2b20697635276b0281a2a4abf70099c4377c51dc Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 20 Aug 2025 21:23:21 +0100 Subject: [PATCH 1339/2711] watchdog: rzv2h: Add support for RZ/T2H Add support for the RZ/T2H watchdog timer. The RZ/T2H requires control of the watchdog counter using the WDT Debug Control Register (WDTDCR), which allows explicitly stopping and starting the counter. This behavior differs from RZ/V2H, which doesn't have WDTDCR, so the driver is extended to handle this requirement. To support this, a new `wdtdcr` flag is introduced in the `rzv2h_of_data` structure. When set, the driver maps the WDTDCR register and uses it to control the watchdog counter in the start, stop, and restart callbacks. Additionally, the clock divisor and count source for RZ/T2H are defined to match its hardware configuration. Signed-off-by: Lad Prabhakar Reviewed-by: Wolfram Sang Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/rzv2h_wdt.c | 84 ++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/rzv2h_wdt.c b/drivers/watchdog/rzv2h_wdt.c index e71d1e108f69..ee3ed5a6d98e 100644 --- a/drivers/watchdog/rzv2h_wdt.c +++ b/drivers/watchdog/rzv2h_wdt.c @@ -21,11 +21,17 @@ #define WDTSR 0x04 /* WDT Status Register RW, 16 */ #define WDTRCR 0x06 /* WDT Reset Control Register RW, 8 */ +/* This register is only available on RZ/T2H and RZ/N2H SoCs */ +#define WDTDCR 0x00 /* WDT Debug Control Register RW, 32 */ + #define WDTCR_TOPS_1024 0x00 +#define WDTCR_TOPS_4096 0x01 #define WDTCR_TOPS_16384 0x03 #define WDTCR_CKS_CLK_1 0x00 +#define WDTCR_CKS_CLK_4 0x10 #define WDTCR_CKS_CLK_256 0x50 +#define WDTCR_CKS_CLK_8192 0x80 #define WDTCR_RPES_0 0x300 #define WDTCR_RPES_75 0x000 @@ -35,6 +41,8 @@ #define WDTRCR_RSTIRQS BIT(7) +#define WDTDCR_WDTSTOPCTRL BIT(0) + #define WDT_DEFAULT_TIMEOUT 60U static bool nowayout = WATCHDOG_NOWAYOUT; @@ -54,10 +62,12 @@ struct rzv2h_of_data { u8 tops; u16 timeout_cycles; enum rzv2h_wdt_count_source count_source; + bool wdtdcr; }; struct rzv2h_wdt_priv { void __iomem *base; + void __iomem *wdtdcr; struct clk *pclk; struct clk *oscclk; struct reset_control *rstc; @@ -79,6 +89,20 @@ static int rzv2h_wdt_ping(struct watchdog_device *wdev) return 0; } +static void rzt2h_wdt_wdtdcr_count_stop(struct rzv2h_wdt_priv *priv) +{ + u32 reg = readl(priv->wdtdcr + WDTDCR); + + writel(reg | WDTDCR_WDTSTOPCTRL, priv->wdtdcr + WDTDCR); +} + +static void rzt2h_wdt_wdtdcr_count_start(struct rzv2h_wdt_priv *priv) +{ + u32 reg = readl(priv->wdtdcr + WDTDCR); + + writel(reg & ~WDTDCR_WDTSTOPCTRL, priv->wdtdcr + WDTDCR); +} + static void rzv2h_wdt_setup(struct watchdog_device *wdev, u16 wdtcr) { struct rzv2h_wdt_priv *priv = watchdog_get_drvdata(wdev); @@ -114,14 +138,21 @@ static int rzv2h_wdt_start(struct watchdog_device *wdev) /* * WDTCR - * - CKS[7:4] - Clock Division Ratio Select - 0101b: oscclk/256 + * - CKS[7:4] - Clock Division Ratio Select + * - 0101b: oscclk/256 for RZ/V2H(P) + * - 1000b: pclkl/8192 for RZ/T2H * - RPSS[13:12] - Window Start Position Select - 11b: 100% * - RPES[9:8] - Window End Position Select - 11b: 0% - * - TOPS[1:0] - Timeout Period Select - 11b: 16384 cycles (3FFFh) + * - TOPS[1:0] - Timeout Period Select + * - 11b: 16384 cycles (3FFFh) for RZ/V2H(P) + * - 01b: 4096 cycles (0FFFh) for RZ/T2H */ rzv2h_wdt_setup(wdev, of_data->cks_max | WDTCR_RPSS_100 | WDTCR_RPES_0 | of_data->tops); + if (priv->of_data->wdtdcr) + rzt2h_wdt_wdtdcr_count_start(priv); + /* * Down counting starts after writing the sequence 00h -> FFh to the * WDTRR register. Hence, call the ping operation after loading the counter. @@ -140,6 +171,9 @@ static int rzv2h_wdt_stop(struct watchdog_device *wdev) if (ret) return ret; + if (priv->of_data->wdtdcr) + rzt2h_wdt_wdtdcr_count_stop(priv); + ret = pm_runtime_put(wdev->parent); if (ret < 0) return ret; @@ -192,7 +226,9 @@ static int rzv2h_wdt_restart(struct watchdog_device *wdev, /* * WDTCR - * - CKS[7:4] - Clock Division Ratio Select - 0000b: oscclk/1 + * - CKS[7:4] - Clock Division Ratio Select + * - 0000b: oscclk/1 for RZ/V2H(P) + * - 0100b: pclkl/4 for RZ/T2H * - RPSS[13:12] - Window Start Position Select - 00b: 25% * - RPES[9:8] - Window End Position Select - 00b: 75% * - TOPS[1:0] - Timeout Period Select - 00b: 1024 cycles (03FFh) @@ -200,6 +236,9 @@ static int rzv2h_wdt_restart(struct watchdog_device *wdev, rzv2h_wdt_setup(wdev, priv->of_data->cks_min | WDTCR_RPSS_25 | WDTCR_RPES_75 | WDTCR_TOPS_1024); + if (priv->of_data->wdtdcr) + rzt2h_wdt_wdtdcr_count_start(priv); + rzv2h_wdt_ping(wdev); /* wait for underflow to trigger... */ @@ -216,6 +255,28 @@ static const struct watchdog_ops rzv2h_wdt_ops = { .restart = rzv2h_wdt_restart, }; +static int rzt2h_wdt_wdtdcr_init(struct platform_device *pdev, + struct rzv2h_wdt_priv *priv) +{ + int ret; + + priv->wdtdcr = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(priv->wdtdcr)) + return PTR_ERR(priv->wdtdcr); + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + rzt2h_wdt_wdtdcr_count_stop(priv); + + ret = pm_runtime_put(&pdev->dev); + if (ret < 0) + return ret; + + return 0; +} + static int rzv2h_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -265,6 +326,12 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) if (ret) return ret; + if (priv->of_data->wdtdcr) { + ret = rzt2h_wdt_wdtdcr_init(pdev, priv); + if (ret) + return dev_err_probe(dev, ret, "WDTDCR init failed\n"); + } + priv->wdev.min_timeout = 1; priv->wdev.timeout = WDT_DEFAULT_TIMEOUT; priv->wdev.info = &rzv2h_wdt_ident; @@ -281,6 +348,16 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) return devm_watchdog_register_device(dev, &priv->wdev); } +static const struct rzv2h_of_data rzt2h_wdt_of_data = { + .cks_min = WDTCR_CKS_CLK_4, + .cks_max = WDTCR_CKS_CLK_8192, + .cks_div = 8192, + .tops = WDTCR_TOPS_4096, + .timeout_cycles = 4096, + .count_source = COUNT_SOURCE_PCLK, + .wdtdcr = true, +}; + static const struct rzv2h_of_data rzv2h_wdt_of_data = { .cks_min = WDTCR_CKS_CLK_1, .cks_max = WDTCR_CKS_CLK_256, @@ -292,6 +369,7 @@ static const struct rzv2h_of_data rzv2h_wdt_of_data = { static const struct of_device_id rzv2h_wdt_ids[] = { { .compatible = "renesas,r9a09g057-wdt", .data = &rzv2h_wdt_of_data }, + { .compatible = "renesas,r9a09g077-wdt", .data = &rzt2h_wdt_of_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, rzv2h_wdt_ids); From 73ea1e92be46671d9a139578fdf5f6b93b7e85e4 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 20 Aug 2025 21:23:22 +0100 Subject: [PATCH 1340/2711] watchdog: rzv2h: Improve error strings and add newlines Update rzv2h_wdt_probe() to provide clearer error strings when retrieving the pclk, oscclk, and reset controller, and append missing newline characters to dev_err_probe() and dev_warn() calls for proper log formatting. Signed-off-by: Lad Prabhakar Reviewed-by: Wolfram Sang Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/rzv2h_wdt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/rzv2h_wdt.c b/drivers/watchdog/rzv2h_wdt.c index ee3ed5a6d98e..2027795f212e 100644 --- a/drivers/watchdog/rzv2h_wdt.c +++ b/drivers/watchdog/rzv2h_wdt.c @@ -296,16 +296,16 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) priv->pclk = devm_clk_get_prepared(dev, "pclk"); if (IS_ERR(priv->pclk)) - return dev_err_probe(dev, PTR_ERR(priv->pclk), "no pclk"); + return dev_err_probe(dev, PTR_ERR(priv->pclk), "Failed to get pclk\n"); priv->oscclk = devm_clk_get_optional_prepared(dev, "oscclk"); if (IS_ERR(priv->oscclk)) - return dev_err_probe(dev, PTR_ERR(priv->oscclk), "no oscclk"); + return dev_err_probe(dev, PTR_ERR(priv->oscclk), "Failed to get oscclk\n"); priv->rstc = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(priv->rstc)) return dev_err_probe(dev, PTR_ERR(priv->rstc), - "failed to get cpg reset"); + "Failed to get cpg reset\n"); switch (priv->of_data->count_source) { case COUNT_SOURCE_LOCO: @@ -343,7 +343,7 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) ret = watchdog_init_timeout(&priv->wdev, 0, dev); if (ret) - dev_warn(dev, "Specified timeout invalid, using default"); + dev_warn(dev, "Specified timeout invalid, using default\n"); return devm_watchdog_register_device(dev, &priv->wdev); } From e76bb4ee92dc6b4f21eb13d79b5c190b2e5a97e5 Mon Sep 17 00:00:00 2001 From: Sangwook Shin Date: Mon, 18 Aug 2025 11:18:22 +0900 Subject: [PATCH 1341/2711] watchdog: s3c2410_wdt: Replace hardcoded values with macro definitions Modify the code to utilize macro-defined values instead of hardcoded values. The value 0x100 in the s3c2410wdt_set_heartbeat function represents S3C2410_WTCON_PRESCALE_MAX + 1, but it is hardcoded, making its meaning difficult to understand and reducing code readability. Reviewed-by: Sam Protsenko Reviewed-by: Alim Akhtar Signed-off-by: Sangwook Shin Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/s3c2410_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 40901bdac426..95f7207e390a 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -587,7 +587,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, if (count >= 0x10000) { divisor = DIV_ROUND_UP(count, 0xffff); - if (divisor > 0x100) { + if (divisor > S3C2410_WTCON_PRESCALE_MAX + 1) { dev_err(wdt->dev, "timeout %d too big\n", timeout); return -EINVAL; } From df3c6e0b6d83450563d6266e1dacc7eaf25511f4 Mon Sep 17 00:00:00 2001 From: Sangwook Shin Date: Mon, 18 Aug 2025 11:18:23 +0900 Subject: [PATCH 1342/2711] watchdog: s3c2410_wdt: Fix max_timeout being calculated larger Fix the issue of max_timeout being calculated larger than actual value. The calculation result of freq / (S3C2410_WTCON_PRESCALE_MAX + 1) / S3C2410_WTCON_MAXDIV is smaller than the actual value because the remainder is discarded during the calculation process. This leads to a larger calculated value for max_timeout compared to the actual settable value. To resolve this issue, the order of calculations in the computation process has been adjusted. Reviewed-by: Sam Protsenko Signed-off-by: Sangwook Shin Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/s3c2410_wdt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 95f7207e390a..1e8cf0299713 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -27,6 +27,7 @@ #include #include #include +#include #define S3C2410_WTCON 0x00 #define S3C2410_WTDAT 0x04 @@ -410,9 +411,14 @@ static inline unsigned long s3c2410wdt_get_freq(struct s3c2410_wdt *wdt) static inline unsigned int s3c2410wdt_max_timeout(struct s3c2410_wdt *wdt) { const unsigned long freq = s3c2410wdt_get_freq(wdt); + const u64 n_max = (u64)(S3C2410_WTCON_PRESCALE_MAX + 1) * + S3C2410_WTCON_MAXDIV * S3C2410_WTCNT_MAXCNT; + u64 t_max = div64_ul(n_max, freq); - return S3C2410_WTCNT_MAXCNT / (freq / (S3C2410_WTCON_PRESCALE_MAX + 1) - / S3C2410_WTCON_MAXDIV); + if (t_max > UINT_MAX) + t_max = UINT_MAX; + + return t_max; } static int s3c2410wdt_disable_wdt_reset(struct s3c2410_wdt *wdt, bool mask) From a36c90ab4d28bebd12b679f85ff1c51ea96d8665 Mon Sep 17 00:00:00 2001 From: Sangwook Shin Date: Mon, 18 Aug 2025 11:18:24 +0900 Subject: [PATCH 1343/2711] watchdog: s3c2410_wdt: Increase max timeout value of watchdog Increase max_timeout value from 55s to 3665038s (1018h 3min 58s) with 38400000 frequency system if the system has 32-bit WTCNT register. cat /sys/class/watchdog/watchdog0/max_timeout 3665038 [ 0.330082] s3c2410-wdt 10060000.watchdog_cl0: Heartbeat: count=1099511400000, timeout=3665038, freq=300000 [ 0.330087] s3c2410-wdt 10060000.watchdog_cl0: Heartbeat: timeout=3665038, divisor=256, count=1099511400000 (fffffc87) [ 0.330127] s3c2410-wdt 10060000.watchdog_cl0: starting watchdog timer [ 0.330134] s3c2410-wdt 10060000.watchdog_cl0: Starting watchdog: count=0xfffffc87, wtcon=0001ff39 [ 0.330319] s3c2410-wdt 10060000.watchdog_cl0: watchdog active, reset enabled, irq disabled If the system has a 32-bit WTCNT, add QUIRK_HAS_32BIT_CNT to its quirk flags, and it will operate with a 32-bit counter. If not, it will operate with a 16-bit counter like in the previous version. Reviewed-by: Sam Protsenko Signed-off-by: Sangwook Shin Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/s3c2410_wdt.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 1e8cf0299713..d983cbcb975c 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -34,7 +34,8 @@ #define S3C2410_WTCNT 0x08 #define S3C2410_WTCLRINT 0x0c -#define S3C2410_WTCNT_MAXCNT 0xffff +#define S3C2410_WTCNT_MAXCNT_16 0xffff +#define S3C2410_WTCNT_MAXCNT_32 0xffffffff #define S3C2410_WTCON_RSTEN BIT(0) #define S3C2410_WTCON_INTEN BIT(2) @@ -124,6 +125,10 @@ * %QUIRK_HAS_DBGACK_BIT: WTCON register has DBGACK_MASK bit. Setting the * DBGACK_MASK bit disables the watchdog outputs when the SoC is in debug mode. * Debug mode is determined by the DBGACK CPU signal. + * + * %QUIRK_HAS_32BIT_CNT: WTDAT and WTCNT are 32-bit registers. With these + * 32-bit registers, larger values will be set, which means that larger timeouts + * value can be set. */ #define QUIRK_HAS_WTCLRINT_REG BIT(0) #define QUIRK_HAS_PMU_MASK_RESET BIT(1) @@ -131,6 +136,7 @@ #define QUIRK_HAS_PMU_AUTO_DISABLE BIT(3) #define QUIRK_HAS_PMU_CNT_EN BIT(4) #define QUIRK_HAS_DBGACK_BIT BIT(5) +#define QUIRK_HAS_32BIT_CNT BIT(6) /* These quirks require that we have a PMU register map */ #define QUIRKS_HAVE_PMUREG \ @@ -199,6 +205,7 @@ struct s3c2410_wdt { struct notifier_block freq_transition; const struct s3c2410_wdt_variant *drv_data; struct regmap *pmureg; + u32 max_cnt; }; static const struct s3c2410_wdt_variant drv_data_s3c2410 = { @@ -412,7 +419,7 @@ static inline unsigned int s3c2410wdt_max_timeout(struct s3c2410_wdt *wdt) { const unsigned long freq = s3c2410wdt_get_freq(wdt); const u64 n_max = (u64)(S3C2410_WTCON_PRESCALE_MAX + 1) * - S3C2410_WTCON_MAXDIV * S3C2410_WTCNT_MAXCNT; + S3C2410_WTCON_MAXDIV * wdt->max_cnt; u64 t_max = div64_ul(n_max, freq); if (t_max > UINT_MAX) @@ -572,7 +579,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, { struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); unsigned long freq = s3c2410wdt_get_freq(wdt); - unsigned int count; + unsigned long count; unsigned int divisor = 1; unsigned long wtcon; @@ -582,7 +589,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, freq = DIV_ROUND_UP(freq, 128); count = timeout * freq; - dev_dbg(wdt->dev, "Heartbeat: count=%d, timeout=%d, freq=%lu\n", + dev_dbg(wdt->dev, "Heartbeat: count=%lu, timeout=%d, freq=%lu\n", count, timeout, freq); /* if the count is bigger than the watchdog register, @@ -590,8 +597,8 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, actually make this value */ - if (count >= 0x10000) { - divisor = DIV_ROUND_UP(count, 0xffff); + if (count > wdt->max_cnt) { + divisor = DIV_ROUND_UP(count, wdt->max_cnt); if (divisor > S3C2410_WTCON_PRESCALE_MAX + 1) { dev_err(wdt->dev, "timeout %d too big\n", timeout); @@ -599,7 +606,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, } } - dev_dbg(wdt->dev, "Heartbeat: timeout=%d, divisor=%d, count=%d (%08x)\n", + dev_dbg(wdt->dev, "Heartbeat: timeout=%d, divisor=%d, count=%lu (%08lx)\n", timeout, divisor, count, DIV_ROUND_UP(count, divisor)); count = DIV_ROUND_UP(count, divisor); @@ -807,6 +814,11 @@ static int s3c2410wdt_probe(struct platform_device *pdev) if (IS_ERR(wdt->src_clk)) return dev_err_probe(dev, PTR_ERR(wdt->src_clk), "failed to get source clock\n"); + if (wdt->drv_data->quirks & QUIRK_HAS_32BIT_CNT) + wdt->max_cnt = S3C2410_WTCNT_MAXCNT_32; + else + wdt->max_cnt = S3C2410_WTCNT_MAXCNT_16; + wdt->wdt_device.min_timeout = 1; wdt->wdt_device.max_timeout = s3c2410wdt_max_timeout(wdt); From c76c029ce568a1129fc6e59199558dcbe2a17de7 Mon Sep 17 00:00:00 2001 From: Sangwook Shin Date: Mon, 18 Aug 2025 11:18:25 +0900 Subject: [PATCH 1344/2711] watchdog: s3c2410_wdt: exynosautov920: Enable QUIRK_HAS_32BIT_CNT Enable QUIRK_HAS_32BIT_CNT to ExynosAutov920 SoC which has 32-bit WTCNT. Reviewed-by: Sam Protsenko Signed-off-by: Sangwook Shin Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/s3c2410_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index d983cbcb975c..915d3c88565a 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -357,7 +357,7 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl0 = { .cnt_en_bit = 8, .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN | - QUIRK_HAS_DBGACK_BIT, + QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT, }; static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl1 = { @@ -370,7 +370,7 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl1 = { .cnt_en_bit = 8, .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN | - QUIRK_HAS_DBGACK_BIT, + QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT, }; static const struct of_device_id s3c2410_wdt_match[] = { From 9f2517f59d3638adf954ade6c461ad270b40adba Mon Sep 17 00:00:00 2001 From: Sangwook Shin Date: Mon, 18 Aug 2025 11:18:26 +0900 Subject: [PATCH 1345/2711] watchdog: s3c2410_wdt: exynosautov9: Enable supported features Enable supported features for ExynosAutov9 SoC. - QUIRK_HAS_DBGACK_BIT - QUIRK_HAS_32BIT_CNT Reviewed-by: Sam Protsenko Signed-off-by: Sangwook Shin Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/s3c2410_wdt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 915d3c88565a..b774477190b6 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -306,7 +306,8 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov9_cl0 = { .cnt_en_reg = EXYNOS850_CLUSTER0_NONCPU_OUT, .cnt_en_bit = 7, .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | - QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN, + QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN | + QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT, }; static const struct s3c2410_wdt_variant drv_data_exynosautov9_cl1 = { @@ -318,7 +319,8 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov9_cl1 = { .cnt_en_reg = EXYNOSAUTOV9_CLUSTER1_NONCPU_OUT, .cnt_en_bit = 7, .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | - QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN, + QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN | + QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT, }; static const struct s3c2410_wdt_variant drv_data_gs101_cl0 = { From 66036fa63a9b070a76100179d829d8d34e450e68 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 21:05:09 +0200 Subject: [PATCH 1346/2711] watchdog: rzg2l_wdt: don't print superfluous errors The watchdog core will handle error messages already. Signed-off-by: Wolfram Sang Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/rzg2l_wdt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/watchdog/rzg2l_wdt.c b/drivers/watchdog/rzg2l_wdt.c index 11bbe48160ec..1c9aa366d0a0 100644 --- a/drivers/watchdog/rzg2l_wdt.c +++ b/drivers/watchdog/rzg2l_wdt.c @@ -310,9 +310,7 @@ static int rzg2l_wdt_probe(struct platform_device *pdev) watchdog_set_nowayout(&priv->wdev, nowayout); watchdog_stop_on_unregister(&priv->wdev); - ret = watchdog_init_timeout(&priv->wdev, 0, dev); - if (ret) - dev_warn(dev, "Specified timeout invalid, using default"); + watchdog_init_timeout(&priv->wdev, 0, dev); return devm_watchdog_register_device(&pdev->dev, &priv->wdev); } From 28cee77baf63aa4e98b510753e5c7212ec5b6567 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 21:05:10 +0200 Subject: [PATCH 1347/2711] watchdog: rzv2h_wdt: don't print superfluous errors The watchdog core will handle error messages already. Signed-off-by: Wolfram Sang Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/rzv2h_wdt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/watchdog/rzv2h_wdt.c b/drivers/watchdog/rzv2h_wdt.c index 2027795f212e..a694786837e1 100644 --- a/drivers/watchdog/rzv2h_wdt.c +++ b/drivers/watchdog/rzv2h_wdt.c @@ -341,9 +341,7 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) watchdog_set_nowayout(&priv->wdev, nowayout); watchdog_stop_on_unregister(&priv->wdev); - ret = watchdog_init_timeout(&priv->wdev, 0, dev); - if (ret) - dev_warn(dev, "Specified timeout invalid, using default\n"); + watchdog_init_timeout(&priv->wdev, 0, dev); return devm_watchdog_register_device(dev, &priv->wdev); } From 7c628fb8db079917ceee70bffb0e784d30cb553e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 21:05:11 +0200 Subject: [PATCH 1348/2711] watchdog: visconti: don't print superfluous errors The watchdog core will handle error messages already. Signed-off-by: Wolfram Sang Reviewed-by: Guenter Roeck Reviewed-by: Nobuhiro Iwamatsu Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/visconti_wdt.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/watchdog/visconti_wdt.c b/drivers/watchdog/visconti_wdt.c index cef0794708e7..7795e7fbf67e 100644 --- a/drivers/watchdog/visconti_wdt.c +++ b/drivers/watchdog/visconti_wdt.c @@ -118,7 +118,6 @@ static int visconti_wdt_probe(struct platform_device *pdev) struct visconti_wdt_priv *priv; struct device *dev = &pdev->dev; struct clk *clk; - int ret; unsigned long clk_freq; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -153,9 +152,7 @@ static int visconti_wdt_probe(struct platform_device *pdev) watchdog_stop_on_unregister(wdev); /* This overrides the default timeout only if DT configuration was found */ - ret = watchdog_init_timeout(wdev, 0, dev); - if (ret) - dev_warn(dev, "Specified timeout value invalid, using default\n"); + watchdog_init_timeout(wdev, 0, dev); return devm_watchdog_register_device(dev, wdev); } From 7dfd80f70ef00d871df5af7c391133f7ba61ad9b Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 12 Aug 2025 14:51:26 +0200 Subject: [PATCH 1349/2711] watchdog: mpc8xxx_wdt: Reload the watchdog timer when enabling the watchdog When the watchdog gets enabled with this driver, it leaves enough time for the core watchdog subsystem to start pinging it. But when the watchdog is already started by hardware or by the boot loader, little time remains before it fires and it happens that the core watchdog subsystem doesn't have time to start pinging it. Until commit 19ce9490aa84 ("watchdog: mpc8xxx: use the core worker function") pinging was managed by the driver itself and the watchdog was immediately pinged by setting the timer expiry to 0. So restore similar behaviour by pinging it when enabling it so that if it was already enabled the watchdog timer counter is reloaded. Fixes: 19ce9490aa84 ("watchdog: mpc8xxx: use the core worker function") Signed-off-by: Christophe Leroy Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mpc8xxx_wdt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 867f9f311379..a4b497ecfa20 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -100,6 +100,8 @@ static int mpc8xxx_wdt_start(struct watchdog_device *w) ddata->swtc = tmp >> 16; set_bit(WDOG_HW_RUNNING, &ddata->wdd.status); + mpc8xxx_wdt_keepalive(ddata); + return 0; } From baa03483fdf3545f2b223a4ca775e1938d956284 Mon Sep 17 00:00:00 2001 From: GuoHan Zhao Date: Mon, 8 Sep 2025 14:52:03 +0800 Subject: [PATCH 1350/2711] perf drm_pmu: Fix fd_dir leaks in for_each_drm_fdinfo_in_dir() Fix file descriptor leak when callback function returns error. The function was directly returning without closing fdinfo_dir_fd and fd_dir when cb() returned non-zero value. Fixes: 28917cb17f9df9c2 ("perf drm_pmu: Add a tool like PMU to expose DRM information") Reviewed-by: Ian Rogers Reviewed-by: Markus Elfring Reviewed-by: Namhyung Kim Signed-off-by: GuoHan Zhao Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20250908065203.22187-1-zhaoguohan@kylinos.cn Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/drm_pmu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/drm_pmu.c b/tools/perf/util/drm_pmu.c index 988890f37ba7..98d4d2b556d4 100644 --- a/tools/perf/util/drm_pmu.c +++ b/tools/perf/util/drm_pmu.c @@ -458,8 +458,10 @@ static int for_each_drm_fdinfo_in_dir(int (*cb)(void *args, int fdinfo_dir_fd, c } ret = cb(args, fdinfo_dir_fd, fd_entry->d_name); if (ret) - return ret; + goto close_fdinfo; } + +close_fdinfo: if (fdinfo_dir_fd != -1) close(fdinfo_dir_fd); closedir(fd_dir); From 94d4dfbbe8e011667934d2f681db5c8a2747fe8d Mon Sep 17 00:00:00 2001 From: Yunseong Kim Date: Fri, 22 Aug 2025 23:58:56 +0900 Subject: [PATCH 1351/2711] perf arm64: Sync ESR_ELx_EC_* macros in arm64_exception_types.h with esr.h Update perf util arm64_exception_types.h to match the exception class macros defined in tools/arch/arm64/include/asm/esr.h. This ensures consistency between perf tooling and the kernel header definitions for ESR_ELx_EC_* values. In v2, ESR_ELx_EC_OTHER and ESR_ELx_EC_GCS, which were missing in v1, were included. Reviewed-by: Leo Yan Signed-off-by: Yunseong Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kan Liang Cc: Leo Yan Cc: Levi Yun Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Link: https://lore.kernel.org/r/20250822145855.53071-2-ysk@kzalloc.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/arch/arm64/util/arm64_exception_types.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/perf/arch/arm64/util/arm64_exception_types.h b/tools/perf/arch/arm64/util/arm64_exception_types.h index 27c981ebe401..bf827f19ace0 100644 --- a/tools/perf/arch/arm64/util/arm64_exception_types.h +++ b/tools/perf/arch/arm64/util/arm64_exception_types.h @@ -31,9 +31,10 @@ #define ESR_ELx_EC_FP_ASIMD (0x07) #define ESR_ELx_EC_CP10_ID (0x08) /* EL2 only */ #define ESR_ELx_EC_PAC (0x09) /* EL2 and above */ -/* Unallocated EC: 0x0A - 0x0B */ +#define ESR_ELx_EC_OTHER (0x0A) +/* Unallocated EC: 0x0B */ #define ESR_ELx_EC_CP14_64 (0x0C) -/* Unallocated EC: 0x0d */ +#define ESR_ELx_EC_BTI (0x0D) #define ESR_ELx_EC_ILL (0x0E) /* Unallocated EC: 0x0F - 0x10 */ #define ESR_ELx_EC_SVC32 (0x11) @@ -46,7 +47,10 @@ #define ESR_ELx_EC_SYS64 (0x18) #define ESR_ELx_EC_SVE (0x19) #define ESR_ELx_EC_ERET (0x1a) /* EL2 only */ -/* Unallocated EC: 0x1b - 0x1E */ +/* Unallocated EC: 0x1B */ +#define ESR_ELx_EC_FPAC (0x1C) /* EL1 and above */ +#define ESR_ELx_EC_SME (0x1D) +/* Unallocated EC: 0x1E */ #define ESR_ELx_EC_IMP_DEF (0x1f) /* EL3 only */ #define ESR_ELx_EC_IABT_LOW (0x20) #define ESR_ELx_EC_IABT_CUR (0x21) @@ -55,11 +59,12 @@ #define ESR_ELx_EC_DABT_LOW (0x24) #define ESR_ELx_EC_DABT_CUR (0x25) #define ESR_ELx_EC_SP_ALIGN (0x26) -/* Unallocated EC: 0x27 */ +#define ESR_ELx_EC_MOPS (0x27) #define ESR_ELx_EC_FP_EXC32 (0x28) /* Unallocated EC: 0x29 - 0x2B */ #define ESR_ELx_EC_FP_EXC64 (0x2C) -/* Unallocated EC: 0x2D - 0x2E */ +#define ESR_ELx_EC_GCS (0x2D) +/* Unallocated EC: 0x2E */ #define ESR_ELx_EC_SERROR (0x2F) #define ESR_ELx_EC_BREAKPT_LOW (0x30) #define ESR_ELx_EC_BREAKPT_CUR (0x31) From 43fa1141e2c1af79c91aaa4df03e436c415a6fc3 Mon Sep 17 00:00:00 2001 From: Yunseong Kim Date: Fri, 22 Aug 2025 16:25:08 +0000 Subject: [PATCH 1352/2711] perf util: Fix compression checks returning -1 as bool The lzma_is_compressed and gzip_is_compressed functions are declared to return a "bool" type, but in case of an error (e.g., file open failure), they incorrectly returned -1. A bool type is a boolean value that is either true or false. Returning -1 for a bool return type can lead to unexpected behavior and may violate strict type-checking in some compilers. Fix the return value to be false in error cases, ensuring the function adheres to its declared return type improves for preventing potential bugs related to type mismatch. Fixes: 4b57fd44b61beb51 ("perf tools: Add lzma_is_compressed function") Reviewed-by: Ian Rogers Signed-off-by: Yunseong Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephen Brennan Link: https://lore.kernel.org/r/20250822162506.316844-3-ysk@kzalloc.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/lzma.c | 2 +- tools/perf/util/zlib.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/lzma.c b/tools/perf/util/lzma.c index bbcd2ffcf4bd..c355757ed391 100644 --- a/tools/perf/util/lzma.c +++ b/tools/perf/util/lzma.c @@ -120,7 +120,7 @@ bool lzma_is_compressed(const char *input) ssize_t rc; if (fd < 0) - return -1; + return false; rc = read(fd, buf, sizeof(buf)); close(fd); diff --git a/tools/perf/util/zlib.c b/tools/perf/util/zlib.c index 78d2297c1b67..1f7c06523059 100644 --- a/tools/perf/util/zlib.c +++ b/tools/perf/util/zlib.c @@ -88,7 +88,7 @@ bool gzip_is_compressed(const char *input) ssize_t rc; if (fd < 0) - return -1; + return false; rc = read(fd, buf, sizeof(buf)); close(fd); From 7970e206e18f0d9c2c5e36d2dbdfb0d52902aa9d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 25 Aug 2025 14:12:02 -0700 Subject: [PATCH 1353/2711] perf evsel: Give warning for broken Intel topdown event grouping Extend arch_evsel__open_strerror() from just AMD IBS events to Intel core PMU events, to give a message when a slots event isn't a group leader or when a perf metric event is duplicated within an event group. As generating the warning happens after non-arch specific warnings are generated, disable the missing system wide (-a) flag warning for the core PMU. This assumes core PMU events should support per-thread/process and system-wide. Reviewed-by: Dapeng Mi Signed-off-by: Ian Rogers Tested-by: Dapeng Mi Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Greg Kroah-Hartman Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Yoshihiro Furudera Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/evsel.c | 64 +++++++++++++++++++++++++++++--- tools/perf/util/evsel.c | 7 +++- tools/perf/util/evsel.h | 2 +- 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/tools/perf/arch/x86/util/evsel.c b/tools/perf/arch/x86/util/evsel.c index 9bc80fff3aa0..e67701d26f24 100644 --- a/tools/perf/arch/x86/util/evsel.c +++ b/tools/perf/arch/x86/util/evsel.c @@ -1,10 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include #include +#include "util/evlist.h" #include "util/evsel.h" #include "util/env.h" #include "util/pmu.h" #include "util/pmus.h" +#include "util/stat.h" +#include "util/strbuf.h" #include "linux/string.h" #include "topdown.h" #include "evsel.h" @@ -102,13 +106,15 @@ void arch__post_evsel_config(struct evsel *evsel, struct perf_event_attr *attr) } } -int arch_evsel__open_strerror(struct evsel *evsel, char *msg, size_t size) +static int amd_evsel__open_strerror(struct evsel *evsel, char *msg, size_t size) { - if (!x86__is_amd_cpu()) + struct perf_pmu *pmu; + + if (evsel->core.attr.precise_ip == 0) return 0; - if (!evsel->core.attr.precise_ip && - !(evsel->pmu && !strncmp(evsel->pmu->name, "ibs", 3))) + pmu = evsel__find_pmu(evsel); + if (!pmu || strncmp(pmu->name, "ibs", 3)) return 0; /* More verbose IBS errors. */ @@ -118,6 +124,54 @@ int arch_evsel__open_strerror(struct evsel *evsel, char *msg, size_t size) return scnprintf(msg, size, "AMD IBS doesn't support privilege filtering. Try " "again without the privilege modifiers (like 'k') at the end."); } - return 0; } + +static int intel_evsel__open_strerror(struct evsel *evsel, int err, char *msg, size_t size) +{ + struct strbuf sb = STRBUF_INIT; + int ret; + + if (err != EINVAL) + return 0; + + if (!topdown_sys_has_perf_metrics()) + return 0; + + if (arch_is_topdown_slots(evsel)) { + if (!evsel__is_group_leader(evsel)) { + evlist__uniquify_evsel_names(evsel->evlist, &stat_config); + evlist__format_evsels(evsel->evlist, &sb, 2048); + ret = scnprintf(msg, size, "Topdown slots event can only be group leader " + "in '%s'.", sb.buf); + strbuf_release(&sb); + return ret; + } + } else if (arch_is_topdown_metrics(evsel)) { + struct evsel *pos; + + evlist__for_each_entry(evsel->evlist, pos) { + if (pos == evsel || !arch_is_topdown_metrics(pos)) + continue; + + if (pos->core.attr.config != evsel->core.attr.config) + continue; + + evlist__uniquify_evsel_names(evsel->evlist, &stat_config); + evlist__format_evsels(evsel->evlist, &sb, 2048); + ret = scnprintf(msg, size, "Perf metric event '%s' is duplicated " + "in the same group (only one event is allowed) in '%s'.", + evsel__name(evsel), sb.buf); + strbuf_release(&sb); + return ret; + } + } + return 0; +} + +int arch_evsel__open_strerror(struct evsel *evsel, int err, char *msg, size_t size) +{ + return x86__is_amd_cpu() + ? amd_evsel__open_strerror(evsel, msg, size) + : intel_evsel__open_strerror(evsel, err, msg, size); +} diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 496f42434327..6a31f9699b49 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -3716,6 +3716,7 @@ static int dump_perf_event_processes(char *msg, size_t size) } int __weak arch_evsel__open_strerror(struct evsel *evsel __maybe_unused, + int err __maybe_unused, char *msg __maybe_unused, size_t size __maybe_unused) { @@ -3725,6 +3726,7 @@ int __weak arch_evsel__open_strerror(struct evsel *evsel __maybe_unused, int evsel__open_strerror(struct evsel *evsel, struct target *target, int err, char *msg, size_t size) { + struct perf_pmu *pmu; char sbuf[STRERR_BUFSIZE]; int printed = 0, enforced = 0; int ret; @@ -3840,7 +3842,8 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target, return scnprintf(msg, size, "The 'aux_action' feature is not supported, update the kernel."); if (perf_missing_features.aux_output) return scnprintf(msg, size, "The 'aux_output' feature is not supported, update the kernel."); - if (!target__has_cpu(target)) + pmu = evsel__find_pmu(evsel); + if (!pmu->is_core && !target__has_cpu(target)) return scnprintf(msg, size, "Invalid event (%s) in per-thread mode, enable system wide with '-a'.", evsel__name(evsel)); @@ -3853,7 +3856,7 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target, break; } - ret = arch_evsel__open_strerror(evsel, msg, size); + ret = arch_evsel__open_strerror(evsel, err, msg, size); if (ret) return ret; diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 5797a02e5d6a..e927a3a4fe0e 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -341,7 +341,7 @@ void evsel__set_sample_id(struct evsel *evsel, bool use_sample_identifier); void arch_evsel__set_sample_weight(struct evsel *evsel); void arch__post_evsel_config(struct evsel *evsel, struct perf_event_attr *attr); -int arch_evsel__open_strerror(struct evsel *evsel, char *msg, size_t size); +int arch_evsel__open_strerror(struct evsel *evsel, int err, char *msg, size_t size); int evsel__set_filter(struct evsel *evsel, const char *filter); int evsel__append_tp_filter(struct evsel *evsel, const char *filter); From 9eac5612da1c91027fb842d42cdf228d8c93e350 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 25 Aug 2025 14:12:03 -0700 Subject: [PATCH 1354/2711] perf stat: Don't skip failing group events Pass errno to stat_handle_error() rather than reading errno after it has potentially been clobbered. Move "skippable" handling first as a skippable event (from the perf stat default list) should always just be skipped. Remove logic to skip rather than fail events in a group when they aren't the group leader. The original logic was added in commit cb5ef60067c1 ("perf stat: Error out unsupported group leader immediately") due to error handling and opening being together and an assertion being raised. Not failing this case causes broken groups to not report values, particularly for topdown events. Closes: https://lore.kernel.org/lkml/20250822082233.1850417-1-dapeng1.mi@linux.intel.com/ Reported-by: Dapeng Mi Reviewed-by: Dapeng Mi Signed-off-by: Ian Rogers Tested-by: Dapeng Mi Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Greg Kroah-Hartman Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Yoshihiro Furudera Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 48 +++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 2c38dd98f6ca..ab567919b89a 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -613,33 +613,40 @@ enum counter_recovery { COUNTER_FATAL, }; -static enum counter_recovery stat_handle_error(struct evsel *counter) +static enum counter_recovery stat_handle_error(struct evsel *counter, int err) { char msg[BUFSIZ]; + + if (counter->skippable) { + if (verbose > 0) { + ui__warning("skipping event %s that kernel failed to open .\n", + evsel__name(counter)); + } + counter->supported = false; + counter->errored = true; + return COUNTER_SKIP; + } + /* * PPC returns ENXIO for HW counters until 2.6.37 * (behavior changed with commit b0a873e). */ - if (errno == EINVAL || errno == ENOSYS || - errno == ENOENT || errno == ENXIO) { - if (verbose > 0) + if (err == EINVAL || err == ENOSYS || err == ENOENT || err == ENXIO) { + if (verbose > 0) { ui__warning("%s event is not supported by the kernel.\n", evsel__name(counter)); + } counter->supported = false; /* * errored is a sticky flag that means one of the counter's * cpu event had a problem and needs to be reexamined. */ counter->errored = true; - - if ((evsel__leader(counter) != counter) || - !(counter->core.leader->nr_members > 1)) - return COUNTER_SKIP; - } else if (evsel__fallback(counter, &target, errno, msg, sizeof(msg))) { + } else if (evsel__fallback(counter, &target, err, msg, sizeof(msg))) { if (verbose > 0) ui__warning("%s\n", msg); return COUNTER_RETRY; - } else if (target__has_per_thread(&target) && errno != EOPNOTSUPP && + } else if (target__has_per_thread(&target) && err != EOPNOTSUPP && evsel_list->core.threads && evsel_list->core.threads->err_thread != -1) { /* @@ -651,29 +658,16 @@ static enum counter_recovery stat_handle_error(struct evsel *counter) evsel_list->core.threads->err_thread = -1; return COUNTER_RETRY; } - } else if (counter->skippable) { - if (verbose > 0) - ui__warning("skipping event %s that kernel failed to open .\n", - evsel__name(counter)); - counter->supported = false; - counter->errored = true; - return COUNTER_SKIP; - } - - if (errno == EOPNOTSUPP) { + } else if (err == EOPNOTSUPP) { if (verbose > 0) { ui__warning("%s event is not supported by the kernel.\n", evsel__name(counter)); } counter->supported = false; counter->errored = true; - - if ((evsel__leader(counter) != counter) || - !(counter->core.leader->nr_members > 1)) - return COUNTER_SKIP; } - evsel__open_strerror(counter, &target, errno, msg, sizeof(msg)); + evsel__open_strerror(counter, &target, err, msg, sizeof(msg)); ui__error("%s\n", msg); if (child_pid != -1) @@ -761,7 +755,7 @@ try_again: continue; } - switch (stat_handle_error(counter)) { + switch (stat_handle_error(counter, errno)) { case COUNTER_FATAL: err = -1; goto err_out; @@ -803,7 +797,7 @@ try_again_reset: if (create_perf_stat_counter(counter, &stat_config, &target, evlist_cpu_itr.cpu_map_idx) < 0) { - switch (stat_handle_error(counter)) { + switch (stat_handle_error(counter, errno)) { case COUNTER_FATAL: err = -1; goto err_out; From 035c17893082b403c98330f1fdb58fd925951038 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 25 Aug 2025 14:12:04 -0700 Subject: [PATCH 1355/2711] perf parse-events: Add 'X' modifier to exclude an event from being regrouped The function parse_events__sort_events_and_fix_groups is needed to fix uncore events like: ``` $ perf stat -e '{data_read,data_write}' ... ``` so that the multiple uncore PMUs have a group each of data_read and data_write events. The same function will perform architecture sorting and group fixing, in particular for Intel topdown/perf-metric events. Grouping multiple perf metric events together causes perf_event_open to fail as the group can only support one. This means command lines like: ``` $ perf stat -e 'slots,slots' ... ``` fail as the slots events are forced into a group together to try to satisfy the perf-metric event constraints. As the user may know better than parse_events__sort_events_and_fix_groups add a 'X' modifier to skip its regrouping behavior. This allows the following to succeed rather than fail on the second slots event being opened: ``` $ perf stat -e 'slots,slots:X' -a sleep 1 Performance counter stats for 'system wide': 6,834,154,071 cpu_core/slots/ (50.13%) 5,548,629,453 cpu_core/slots/X (49.87%) 1.002634606 seconds time elapsed ``` Closes: https://lore.kernel.org/lkml/20250822082233.1850417-1-dapeng1.mi@linux.intel.com/ Reported-by: Dapeng Mi Reported-by: Xudong Hao Reviewed-by: Dapeng Mi Signed-off-by: Ian Rogers Tested-by: Dapeng Mi Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Greg Kroah-Hartman Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Falcon Cc: Yoshihiro Furudera Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-list.txt | 1 + tools/perf/util/evsel.h | 1 + tools/perf/util/parse-events.c | 5 +++-- tools/perf/util/parse-events.h | 1 + tools/perf/util/parse-events.l | 5 +++-- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 28215306a78a..a5039d1614f9 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -73,6 +73,7 @@ counted. The following modifiers exist: e - group or event are exclusive and do not share the PMU b - use BPF aggregration (see perf stat --bpf-counters) R - retire latency value of the event + X - don't regroup the event to match PMUs The 'p' modifier can be used for specifying how precise the instruction address should be. The 'p' modifier can be specified multiple times: diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index e927a3a4fe0e..03f9f22e3a0c 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -89,6 +89,7 @@ struct evsel { bool use_config_name; bool skippable; bool retire_lat; + bool dont_regroup; int bpf_fd; struct bpf_object *bpf_obj; struct list_head config_terms; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 0026cff4d69e..452f12191f6e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1896,6 +1896,8 @@ static int parse_events__modifier_list(struct parse_events_state *parse_state, evsel->bpf_counter = true; if (mod.retire_lat) evsel->retire_lat = true; + if (mod.dont_regroup) + evsel->dont_regroup = true; } return 0; } @@ -2192,13 +2194,12 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list) * Set the group leader respecting the given groupings and that * groups can't span PMUs. */ - if (!cur_leader) { + if (!cur_leader || pos->dont_regroup) { cur_leader = pos; cur_leaders_grp = &pos->core; if (pos_force_grouped) force_grouped_leader = pos; } - cur_leader_pmu_name = cur_leader->group_pmu_name; if (strcmp(cur_leader_pmu_name, pos_pmu_name)) { /* PMU changed so the group/leader must change. */ diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 62dc7202e3ba..a5c5fc39fd6f 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -216,6 +216,7 @@ struct parse_events_modifier { bool guest : 1; /* 'G' */ bool host : 1; /* 'H' */ bool retire_lat : 1; /* 'R' */ + bool dont_regroup : 1; /* 'X' */ }; int parse_events__modifier_event(struct parse_events_state *parse_state, void *loc, diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 2034590eb789..294e943bcdb4 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -206,6 +206,7 @@ static int modifiers(struct parse_events_state *parse_state, yyscan_t scanner) CASE('e', exclusive); CASE('b', bpf); CASE('R', retire_lat); + CASE('X', dont_regroup); default: return PE_ERROR; } @@ -251,10 +252,10 @@ term_name {name_start}[a-zA-Z0-9_*?.\[\]!\-:]* quoted_name [\']{name_start}[a-zA-Z0-9_*?.\[\]!\-:,\.=]*[\'] drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)? /* - * If you add a modifier you need to update check_modifier(). + * If you add a modifier you need to update modifiers(). * Also, the letters in modifier_event must not be in modifier_bp. */ -modifier_event [ukhpPGHSDIWebR]{1,16} +modifier_event [ukhpPGHSDIWebRX]{1,17} modifier_bp [rwx]{1,3} lc_type (L1-dcache|l1-d|l1d|L1-data|L1-icache|l1-i|l1i|L1-instruction|LLC|L2|dTLB|d-tlb|Data-TLB|iTLB|i-tlb|Instruction-TLB|branch|branches|bpu|btb|bpc|node) lc_op_result (load|loads|read|store|stores|write|prefetch|prefetches|speculative-read|speculative-load|refs|Reference|ops|access|misses|miss) From fad8e97854504bcd2dc108703fc7d25749945097 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 18 Aug 2025 11:35:04 +0200 Subject: [PATCH 1356/2711] PCI: of: Update parent unit address generation in of_pci_prop_intr_map() Some interrupt controllers require an #address-cells property in their bindings without requiring a "reg" property to be present. The current logic used to craft an interrupt-map property in of_pci_prop_intr_map() is based on reading the #address-cells property in the interrupt-parent and, if != 0, read the interrupt parent "reg" property to determine the parent unit address to be used to create the parent unit interrupt specifier. First of all, it is not correct to read the "reg" property of the interrupt-parent with an #address-cells value taken from the interrupt-parent node, because the #address-cells value define the number of address cells required by child nodes. More importantly, for all modern interrupt controllers, the parent unit address is irrelevant in hardware in relation to the device <-> interrupt-controller connection and the kernel actually ignores the parent unit address value when hierarchically parsing the interrupt-map property (i.e., of_irq_parse_raw()). For the reasons above, remove the code parsing the interrupt parent "reg" property in of_pci_prop_intr_map() -- it is not needed and prevents interrupt-map property generation on systems with an interrupt-controller that has no "reg" property in its interrupt-controller node -- and leave the parent unit address always initialized to 0 since it is simply ignored by the kernel. Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Lizhi Hou Reviewed-by: Rob Herring Link: https://lore.kernel.org/lkml/aJms+YT8TnpzpCY8@lpieralisi/ Link: https://patch.msgid.link/20250818093504.80651-1-lpieralisi@kernel.org --- drivers/pci/of_property.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c index 506fcd507113..7aae46f333d9 100644 --- a/drivers/pci/of_property.c +++ b/drivers/pci/of_property.c @@ -279,13 +279,21 @@ static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs, mapp++; *mapp = out_irq[i].np->phandle; mapp++; - if (addr_sz[i]) { - ret = of_property_read_u32_array(out_irq[i].np, - "reg", mapp, - addr_sz[i]); - if (ret) - goto failed; - } + + /* + * A device address does not affect the device <-> + * interrupt-controller HW connection for all + * modern interrupt controllers; moreover, the + * kernel (i.e., of_irq_parse_raw()) ignores the + * values in the parent unit address cells while + * parsing the interrupt-map property because they + * are irrelevant for interrupt mapping in modern + * systems. + * + * Leave the parent unit address initialized to 0 -- + * just take into account the #address-cells size + * to build the property properly. + */ mapp += addr_sz[i]; memcpy(mapp, out_irq[i].args, out_irq[i].args_count * sizeof(u32)); From f272210b28d050df56ec7dfaecb9fa3bebca6419 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 8 Sep 2025 18:19:42 +0200 Subject: [PATCH 1357/2711] PCI: endpoint: pci-epf-test: Fix doorbell test support The doorbell feature temporarily overrides the inbound translation to point to the address stored in epf_test->db_bar.phys_addr, i.e., it calls set_bar() twice without ever calling clear_bar(), as calling clear_bar() would clear the BAR's PCI address assigned by the host. Thus, when disabling the doorbell, restore the inbound translation to point to the memory allocated for the BAR. Without this, running the PCI endpoint kselftest doorbell test case more than once would fail. Fixes: eff0c286aa91 ("PCI: endpoint: pci-epf-test: Add doorbell test support") Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Frank Li Link: https://patch.msgid.link/20250908161942.534799-2-cassel@kernel.org --- drivers/pci/endpoint/functions/pci-epf-test.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index 2418add64104..09e1b8b46b55 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -772,12 +772,24 @@ static void pci_epf_test_disable_doorbell(struct pci_epf_test *epf_test, u32 status = le32_to_cpu(reg->status); struct pci_epf *epf = epf_test->epf; struct pci_epc *epc = epf->epc; + int ret; if (bar < BAR_0) goto set_status_err; pci_epf_test_doorbell_cleanup(epf_test); - pci_epc_clear_bar(epc, epf->func_no, epf->vfunc_no, &epf_test->db_bar); + + /* + * The doorbell feature temporarily overrides the inbound translation + * to point to the address stored in epf_test->db_bar.phys_addr, i.e., + * it calls set_bar() twice without ever calling clear_bar(), as + * calling clear_bar() would clear the BAR's PCI address assigned by + * the host. Thus, when disabling the doorbell, restore the inbound + * translation to point to the memory allocated for the BAR. + */ + ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf->bar[bar]); + if (ret) + goto set_status_err; status |= STATUS_DOORBELL_DISABLE_SUCCESS; reg->status = cpu_to_le32(status); From 09fefb24ed5e15f3b112f6c04b21a90ea23eaf8b Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 8 Sep 2025 18:59:15 +0200 Subject: [PATCH 1358/2711] PCI: dwc: Verify the single eDMA IRQ in dw_pcie_edma_irq_verify() dw_pcie_edma_irq_verify() is supposed to verify the eDMA IRQs in devicetree by fetching them using either 'dma' or 'dmaX' IRQ names. Former is used when the platform uses a single IRQ for all eDMA channels and latter is used when the platform uses separate IRQ per channel. But currently, dw_pcie_edma_irq_verify() bails out early if edma::nr_irqs is 1, i.e., when a single IRQ is used. This gives an impression that the driver could work with any single IRQ in devicetree, not necessarily with name 'dma'. But dw_pcie_edma_irq_vector(), which actually requests the IRQ, does require the single IRQ to be named as 'dma'. So this creates inconsistency between dw_pcie_edma_irq_verify() and dw_pcie_edma_irq_vector(). Thus, to fix this inconsistency, make sure dw_pcie_edma_irq_verify() also verifies the single IRQ name by removing the bail out code. Signed-off-by: Niklas Cassel [mani: reworded subject and description] Signed-off-by: Manivannan Sadhasivam [bhelgaas: fix typos] Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250908165914.547002-3-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-designware.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 89aad5a08928..c7a2cf5e886f 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -1045,9 +1045,7 @@ static int dw_pcie_edma_irq_verify(struct dw_pcie *pci) char name[15]; int ret; - if (pci->edma.nr_irqs == 1) - return 0; - else if (pci->edma.nr_irqs > 1) + if (pci->edma.nr_irqs > 1) return pci->edma.nr_irqs != ch_cnt ? -EINVAL : 0; ret = platform_get_irq_byname_optional(pdev, "dma"); From eea30c76012245efa87f427ca6d110d1674e433a Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 8 Sep 2025 18:59:16 +0200 Subject: [PATCH 1359/2711] PCI: qcom-ep: Remove redundant edma.nr_irqs initialization dw_pcie_edma_irq_verify() already parses device tree for either "dma" (if there is a single IRQ for all DMA channels) or "dmaX" (if there is one IRQ per DMA channel), and initializes dma.nr_irqs accordingly. Additionally, the probing of the eDMA driver will fail if neither "dma" nor "dmaX" is defined in the device tree. Therefore there is no need for a glue driver to specify edma.nr_irqs, so remove the redundant edma.nr_irqs initialization. Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam [bhelgaas: fix typos] Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250908165914.547002-4-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index bf7c6ac0f3e3..ad98598bb522 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -874,7 +874,6 @@ static int qcom_pcie_ep_probe(struct platform_device *pdev) pcie_ep->pci.dev = dev; pcie_ep->pci.ops = &pci_ops; pcie_ep->pci.ep.ops = &pci_ep_ops; - pcie_ep->pci.edma.nr_irqs = 1; pcie_ep->cfg = of_device_get_match_data(dev); if (pcie_ep->cfg && pcie_ep->cfg->hdma_support) { From 9a23ea1f7558bdd3f8d2b35b1c2e16a2f9bf671e Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 2 Sep 2025 16:21:26 +0300 Subject: [PATCH 1360/2711] crypto: sun8i-ce - remove channel timeout field Using the number of bytes in the request as DMA timeout is really inconsistent, as large requests could possibly set a timeout of hundreds of seconds. Remove the per-channel timeout field and use a single, static DMA timeout of 3 seconds for all requests. Signed-off-by: Ovidiu Panait Tested-by: Corentin LABBE Reviewed-by: Corentin LABBE Signed-off-by: Herbert Xu --- drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c | 1 - drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c | 5 ++--- drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c | 2 -- drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c | 1 - drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c | 1 - drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h | 2 +- 6 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c index 5663df49dd81..113a1100f2ae 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c @@ -276,7 +276,6 @@ static int sun8i_ce_cipher_prepare(struct crypto_engine *engine, void *async_req goto theend_sgs; } - chan->timeout = areq->cryptlen; rctx->nr_sgs = ns; rctx->nr_sgd = nd; return 0; diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c index 658f520cee0c..79ec172e5c99 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c @@ -210,11 +210,10 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name) mutex_unlock(&ce->mlock); wait_for_completion_interruptible_timeout(&ce->chanlist[flow].complete, - msecs_to_jiffies(ce->chanlist[flow].timeout)); + msecs_to_jiffies(CE_DMA_TIMEOUT_MS)); if (ce->chanlist[flow].status == 0) { - dev_err(ce->dev, "DMA timeout for %s (tm=%d) on flow %d\n", name, - ce->chanlist[flow].timeout, flow); + dev_err(ce->dev, "DMA timeout for %s on flow %d\n", name, flow); err = -EFAULT; } /* No need to lock for this read, the channel is locked so diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c index 13bdfb8a2c62..b26f5427c1e0 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c @@ -446,8 +446,6 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) else cet->t_dlen = cpu_to_le32(areq->nbytes / 4 + j); - chan->timeout = areq->nbytes; - err = sun8i_ce_run_task(ce, flow, crypto_ahash_alg_name(tfm)); dma_unmap_single(ce->dev, addr_pad, j * 4, DMA_TO_DEVICE); diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c index 762459867b6c..d0a1ac66738b 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c @@ -137,7 +137,6 @@ int sun8i_ce_prng_generate(struct crypto_rng *tfm, const u8 *src, cet->t_dst[0].addr = desc_addr_val_le32(ce, dma_dst); cet->t_dst[0].len = cpu_to_le32(todo / 4); - ce->chanlist[flow].timeout = 2000; err = sun8i_ce_run_task(ce, 3, "PRNG"); mutex_unlock(&ce->rnglock); diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c index e1e8bc15202e..244529bf0616 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c @@ -79,7 +79,6 @@ static int sun8i_ce_trng_read(struct hwrng *rng, void *data, size_t max, bool wa cet->t_dst[0].addr = desc_addr_val_le32(ce, dma_dst); cet->t_dst[0].len = cpu_to_le32(todo / 4); - ce->chanlist[flow].timeout = todo; err = sun8i_ce_run_task(ce, 3, "TRNG"); mutex_unlock(&ce->rnglock); diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h index 0f9a89067016..f12c32d1843f 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h @@ -106,6 +106,7 @@ #define MAX_SG 8 #define CE_MAX_CLOCKS 4 +#define CE_DMA_TIMEOUT_MS 3000 #define MAXFLOW 4 @@ -196,7 +197,6 @@ struct sun8i_ce_flow { struct completion complete; int status; dma_addr_t t_phy; - int timeout; struct ce_task *tl; void *backup_iv; void *bounce_iv; From 01d7d3c3db778c89b4943cd70c2dc25c8ed96c4f Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 2 Sep 2025 16:21:27 +0300 Subject: [PATCH 1361/2711] crypto: sun8i-ce - remove boilerplate in sun8i_ce_hash_digest() Retrieve the dev pointer from tfm context to eliminate some boilerplate code in sun8i_ce_hash_digest(). Signed-off-by: Ovidiu Panait Tested-by: Corentin LABBE Reviewed-by: Corentin LABBE Signed-off-by: Herbert Xu --- drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c index b26f5427c1e0..61e8d968fdcc 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c @@ -238,19 +238,15 @@ static bool sun8i_ce_hash_need_fallback(struct ahash_request *areq) int sun8i_ce_hash_digest(struct ahash_request *areq) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); - struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg); + struct sun8i_ce_hash_tfm_ctx *ctx = crypto_ahash_ctx(tfm); struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); - struct sun8i_ce_alg_template *algt; - struct sun8i_ce_dev *ce; + struct sun8i_ce_dev *ce = ctx->ce; struct crypto_engine *engine; int e; if (sun8i_ce_hash_need_fallback(areq)) return sun8i_ce_hash_digest_fb(areq); - algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base); - ce = algt->ce; - e = sun8i_ce_get_engine_number(ce); rctx->flow = e; engine = ce->chanlist[e].engine; From 6713d9842bd50463ce5f8e2ed056c4d843b9fee0 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 2 Sep 2025 16:21:28 +0300 Subject: [PATCH 1362/2711] crypto: sun8i-ce - remove unnecessary __maybe_unused annotations There are 3 instances of '__maybe_unused' annotations that are not needed, as the variables are always used, so remove them. Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c | 2 +- drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c | 2 +- drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c index 113a1100f2ae..c57c64a1a388 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c @@ -111,7 +111,7 @@ static int sun8i_ce_cipher_fallback(struct skcipher_request *areq) if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) { struct skcipher_alg *alg = crypto_skcipher_alg(tfm); - struct sun8i_ce_alg_template *algt __maybe_unused; + struct sun8i_ce_alg_template *algt; algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher.base); diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c index 79ec172e5c99..ba30859e749c 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c @@ -1062,7 +1062,7 @@ static int sun8i_ce_probe(struct platform_device *pdev) pm_runtime_put_sync(ce->dev); if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) { - struct dentry *dbgfs_dir __maybe_unused; + struct dentry *dbgfs_dir; struct dentry *dbgfs_stats __maybe_unused; /* Ignore error of debugfs */ diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c index 61e8d968fdcc..df2acef9c679 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c @@ -26,7 +26,7 @@ static void sun8i_ce_hash_stat_fb_inc(struct crypto_ahash *tfm) { if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) { - struct sun8i_ce_alg_template *algt __maybe_unused; + struct sun8i_ce_alg_template *algt; struct ahash_alg *alg = crypto_ahash_alg(tfm); algt = container_of(alg, struct sun8i_ce_alg_template, From cedb1e9e9a6465ce0568588d6b8ff10b9826603e Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 2 Sep 2025 16:21:29 +0300 Subject: [PATCH 1363/2711] crypto: sun8i-ce - add a new function for dumping task descriptors In order to remove code duplication, factor out task descriptor dumping to a new function sun8i_ce_dump_task_descriptors(). Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- .../crypto/allwinner/sun8i-ce/sun8i-ce-core.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c index ba30859e749c..b7093fbb8e9d 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c @@ -169,6 +169,12 @@ static const struct ce_variant ce_r40_variant = { .trng = CE_ID_NOTSUPP, }; +static void sun8i_ce_dump_task_descriptors(struct sun8i_ce_flow *chan) +{ + print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4, + chan->tl, sizeof(struct ce_task), false); +} + /* * sun8i_ce_get_engine_number() get the next channel slot * This is a simple round-robin way of getting the next channel @@ -183,7 +189,6 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name) { u32 v; int err = 0; - struct ce_task *cet = ce->chanlist[flow].tl; #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG ce->chanlist[flow].stat_req++; @@ -225,9 +230,8 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name) /* Sadly, the error bit is not per flow */ if (v) { dev_err(ce->dev, "CE ERROR: %x for flow %x\n", v, flow); + sun8i_ce_dump_task_descriptors(&ce->chanlist[flow]); err = -EFAULT; - print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4, - cet, sizeof(struct ce_task), false); } if (v & CE_ERR_ALGO_NOTSUP) dev_err(ce->dev, "CE ERROR: algorithm not supported\n"); @@ -244,9 +248,8 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name) v &= 0xF; if (v) { dev_err(ce->dev, "CE ERROR: %x for flow %x\n", v, flow); + sun8i_ce_dump_task_descriptors(&ce->chanlist[flow]); err = -EFAULT; - print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4, - cet, sizeof(struct ce_task), false); } if (v & CE_ERR_ALGO_NOTSUP) dev_err(ce->dev, "CE ERROR: algorithm not supported\n"); @@ -260,9 +263,8 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name) v &= 0xFF; if (v) { dev_err(ce->dev, "CE ERROR: %x for flow %x\n", v, flow); + sun8i_ce_dump_task_descriptors(&ce->chanlist[flow]); err = -EFAULT; - print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4, - cet, sizeof(struct ce_task), false); } if (v & CE_ERR_ALGO_NOTSUP) dev_err(ce->dev, "CE ERROR: algorithm not supported\n"); From 27eaada08c8c94f0d89225c8fd982320c68b9a80 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 2 Sep 2025 16:21:30 +0300 Subject: [PATCH 1364/2711] crypto: sun8i-ce - move bounce_iv and backup_iv to request context Currently, the iv buffers are allocated per flow during driver probe, which means that the buffers are shared by all requests. This works because the driver is not yet truly asynchronous, since it waits inside do_one_request() for the completion irq. However, the iv data is request-specific, so it should be part of the request context. Move iv buffers to request context. The bounce_iv buffer is aligned to sizeof(u32) to match the 'word address' requirement for the task descriptor's iv field. Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- .../allwinner/sun8i-ce/sun8i-ce-cipher.c | 18 +++++++++--------- .../crypto/allwinner/sun8i-ce/sun8i-ce-core.c | 12 ------------ drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h | 8 ++++---- 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c index c57c64a1a388..69ba8236cf2d 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c @@ -209,11 +209,11 @@ static int sun8i_ce_cipher_prepare(struct crypto_engine *engine, void *async_req if (areq->iv && ivsize > 0) { if (rctx->op_dir & CE_DECRYPTION) { offset = areq->cryptlen - ivsize; - scatterwalk_map_and_copy(chan->backup_iv, areq->src, + scatterwalk_map_and_copy(rctx->backup_iv, areq->src, offset, ivsize, 0); } - memcpy(chan->bounce_iv, areq->iv, ivsize); - rctx->addr_iv = dma_map_single(ce->dev, chan->bounce_iv, ivsize, + memcpy(rctx->bounce_iv, areq->iv, ivsize); + rctx->addr_iv = dma_map_single(ce->dev, rctx->bounce_iv, ivsize, DMA_TO_DEVICE); if (dma_mapping_error(ce->dev, rctx->addr_iv)) { dev_err(ce->dev, "Cannot DMA MAP IV\n"); @@ -299,13 +299,13 @@ theend_iv: offset = areq->cryptlen - ivsize; if (rctx->op_dir & CE_DECRYPTION) { - memcpy(areq->iv, chan->backup_iv, ivsize); - memzero_explicit(chan->backup_iv, ivsize); + memcpy(areq->iv, rctx->backup_iv, ivsize); + memzero_explicit(rctx->backup_iv, ivsize); } else { scatterwalk_map_and_copy(areq->iv, areq->dst, offset, ivsize, 0); } - memzero_explicit(chan->bounce_iv, ivsize); + memzero_explicit(rctx->bounce_iv, ivsize); } dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE); @@ -348,13 +348,13 @@ static void sun8i_ce_cipher_unprepare(struct crypto_engine *engine, DMA_TO_DEVICE); offset = areq->cryptlen - ivsize; if (rctx->op_dir & CE_DECRYPTION) { - memcpy(areq->iv, chan->backup_iv, ivsize); - memzero_explicit(chan->backup_iv, ivsize); + memcpy(areq->iv, rctx->backup_iv, ivsize); + memzero_explicit(rctx->backup_iv, ivsize); } else { scatterwalk_map_and_copy(areq->iv, areq->dst, offset, ivsize, 0); } - memzero_explicit(chan->bounce_iv, ivsize); + memzero_explicit(rctx->bounce_iv, ivsize); } dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE); diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c index b7093fbb8e9d..c16bb6ce6ee3 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c @@ -759,18 +759,6 @@ static int sun8i_ce_allocate_chanlist(struct sun8i_ce_dev *ce) err = -ENOMEM; goto error_engine; } - ce->chanlist[i].bounce_iv = devm_kmalloc(ce->dev, AES_BLOCK_SIZE, - GFP_KERNEL | GFP_DMA); - if (!ce->chanlist[i].bounce_iv) { - err = -ENOMEM; - goto error_engine; - } - ce->chanlist[i].backup_iv = devm_kmalloc(ce->dev, AES_BLOCK_SIZE, - GFP_KERNEL); - if (!ce->chanlist[i].backup_iv) { - err = -ENOMEM; - goto error_engine; - } } return 0; error_engine: diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h index f12c32d1843f..de3a096c476c 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h @@ -188,8 +188,6 @@ struct ce_task { * @status: set to 1 by interrupt if task is done * @t_phy: Physical address of task * @tl: pointer to the current ce_task for this flow - * @backup_iv: buffer which contain the next IV to store - * @bounce_iv: buffer which contain the IV * @stat_req: number of request done by this flow */ struct sun8i_ce_flow { @@ -198,8 +196,6 @@ struct sun8i_ce_flow { int status; dma_addr_t t_phy; struct ce_task *tl; - void *backup_iv; - void *bounce_iv; #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG unsigned long stat_req; #endif @@ -264,6 +260,8 @@ static inline __le32 desc_addr_val_le32(struct sun8i_ce_dev *dev, * @nr_sgd: The number of destination SG (as given by dma_map_sg()) * @addr_iv: The IV addr returned by dma_map_single, need to unmap later * @addr_key: The key addr returned by dma_map_single, need to unmap later + * @bounce_iv: Current IV buffer + * @backup_iv: Next IV buffer * @fallback_req: request struct for invoking the fallback skcipher TFM */ struct sun8i_cipher_req_ctx { @@ -273,6 +271,8 @@ struct sun8i_cipher_req_ctx { int nr_sgd; dma_addr_t addr_iv; dma_addr_t addr_key; + u8 bounce_iv[AES_BLOCK_SIZE] __aligned(sizeof(u32)); + u8 backup_iv[AES_BLOCK_SIZE]; struct skcipher_request fallback_req; // keep at the end }; From 2dc57f02f24957626f5c07e69486915eecc9ebd8 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 2 Sep 2025 16:21:31 +0300 Subject: [PATCH 1365/2711] crypto: sun8i-ce - fold sun8i_ce_cipher_run() into sun8i_ce_cipher_do_one() Fold sun8i_ce_cipher_run() into it's only caller, sun8i_ce_cipher_do_one(), to eliminate a bit of boilerplate. Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- .../allwinner/sun8i-ce/sun8i-ce-cipher.c | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c index 69ba8236cf2d..f63d21cd1e52 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c @@ -360,31 +360,28 @@ static void sun8i_ce_cipher_unprepare(struct crypto_engine *engine, dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE); } -static void sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq) -{ - struct skcipher_request *breq = container_of(areq, struct skcipher_request, base); - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(breq); - struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); - struct sun8i_ce_dev *ce = op->ce; - struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(breq); - int flow, err; - - flow = rctx->flow; - err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm)); - sun8i_ce_cipher_unprepare(engine, areq); - local_bh_disable(); - crypto_finalize_skcipher_request(engine, breq, err); - local_bh_enable(); -} - int sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq) { - int err = sun8i_ce_cipher_prepare(engine, areq); + struct skcipher_request *req = skcipher_request_cast(areq); + struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(req); + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct sun8i_cipher_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); + struct sun8i_ce_dev *ce = ctx->ce; + int err; + err = sun8i_ce_cipher_prepare(engine, areq); if (err) return err; - sun8i_ce_cipher_run(engine, areq); + err = sun8i_ce_run_task(ce, rctx->flow, + crypto_tfm_alg_name(req->base.tfm)); + + sun8i_ce_cipher_unprepare(engine, areq); + + local_bh_disable(); + crypto_finalize_skcipher_request(engine, req, err); + local_bh_enable(); + return 0; } From 49034c03b5814ba4257927be2916bdadfe281be7 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 2 Sep 2025 16:21:32 +0300 Subject: [PATCH 1366/2711] crypto: sun8i-ce - pass task descriptor to cipher prepare/unprepare To remove some duplicated code, directly pass 'struct skcipher_request' and 'struct ce_task' pointers to sun8i_ce_cipher_{prepare,unprepare}. Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- .../allwinner/sun8i-ce/sun8i-ce-cipher.c | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c index f63d21cd1e52..021614b65e39 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c @@ -131,21 +131,19 @@ static int sun8i_ce_cipher_fallback(struct skcipher_request *areq) return err; } -static int sun8i_ce_cipher_prepare(struct crypto_engine *engine, void *async_req) +static int sun8i_ce_cipher_prepare(struct skcipher_request *areq, + struct ce_task *cet) { - struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base); struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); struct sun8i_ce_dev *ce = op->ce; struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); struct skcipher_alg *alg = crypto_skcipher_alg(tfm); struct sun8i_ce_alg_template *algt; - struct sun8i_ce_flow *chan; - struct ce_task *cet; struct scatterlist *sg; unsigned int todo, len, offset, ivsize; u32 common, sym; - int flow, i; + int i; int nr_sgs = 0; int nr_sgd = 0; int err = 0; @@ -163,14 +161,9 @@ static int sun8i_ce_cipher_prepare(struct crypto_engine *engine, void *async_req if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) algt->stat_req++; - flow = rctx->flow; - - chan = &ce->chanlist[flow]; - - cet = chan->tl; memset(cet, 0, sizeof(struct ce_task)); - cet->t_id = cpu_to_le32(flow); + cet->t_id = cpu_to_le32(rctx->flow); common = ce->variant->alg_cipher[algt->ce_algo_id]; common |= rctx->op_dir | CE_COMM_INT; cet->t_common_ctl = cpu_to_le32(common); @@ -314,24 +307,17 @@ theend: return err; } -static void sun8i_ce_cipher_unprepare(struct crypto_engine *engine, - void *async_req) +static void sun8i_ce_cipher_unprepare(struct skcipher_request *areq, + struct ce_task *cet) { - struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base); struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); struct sun8i_ce_dev *ce = op->ce; struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); - struct sun8i_ce_flow *chan; - struct ce_task *cet; unsigned int ivsize, offset; int nr_sgs = rctx->nr_sgs; int nr_sgd = rctx->nr_sgd; - int flow; - flow = rctx->flow; - chan = &ce->chanlist[flow]; - cet = chan->tl; ivsize = crypto_skcipher_ivsize(tfm); if (areq->src == areq->dst) { @@ -367,16 +353,19 @@ int sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq) struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct sun8i_cipher_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); struct sun8i_ce_dev *ce = ctx->ce; + struct sun8i_ce_flow *chan; int err; - err = sun8i_ce_cipher_prepare(engine, areq); + chan = &ce->chanlist[rctx->flow]; + + err = sun8i_ce_cipher_prepare(req, chan->tl); if (err) return err; err = sun8i_ce_run_task(ce, rctx->flow, crypto_tfm_alg_name(req->base.tfm)); - sun8i_ce_cipher_unprepare(engine, areq); + sun8i_ce_cipher_unprepare(req, chan->tl); local_bh_disable(); crypto_finalize_skcipher_request(engine, req, err); From c3a61eea658a9f6808a3d466a0978320b3855b49 Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 2 Sep 2025 16:21:33 +0300 Subject: [PATCH 1367/2711] crypto: sun8i-ce - save hash buffers and dma info to request context Similar to sun8i-ce skcipher code, move all request-specific data to request context. This simplifies sun8i_ce_hash_run() and it eliminates the remaining kmalloc() calls from the digest path. Since the 'result' buffer in the request ctx struct is used for from-device DMA, it needs to be properly aligned to CRYPTO_DMA_ALIGN. Therefore: - increase reqsize by CRYPTO_DMA_PADDING - add __aligned(CRYPTO_DMA_ALIGN) attribute for the 'result' buffer - convert all ahash_request_ctx_dma() calls to ahash_request_ctx_dma() Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- .../crypto/allwinner/sun8i-ce/sun8i-ce-hash.c | 77 ++++++++----------- drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h | 17 ++++ 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c index df2acef9c679..6573c566bd0d 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c @@ -58,7 +58,8 @@ int sun8i_ce_hash_init_tfm(struct crypto_ahash *tfm) crypto_ahash_set_reqsize(tfm, sizeof(struct sun8i_ce_hash_reqctx) + - crypto_ahash_reqsize(op->fallback_tfm)); + crypto_ahash_reqsize(op->fallback_tfm) + + CRYPTO_DMA_PADDING); if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) memcpy(algt->fbname, @@ -84,7 +85,7 @@ void sun8i_ce_hash_exit_tfm(struct crypto_ahash *tfm) int sun8i_ce_hash_init(struct ahash_request *areq) { - struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); @@ -100,7 +101,7 @@ int sun8i_ce_hash_init(struct ahash_request *areq) int sun8i_ce_hash_export(struct ahash_request *areq, void *out) { - struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); @@ -114,7 +115,7 @@ int sun8i_ce_hash_export(struct ahash_request *areq, void *out) int sun8i_ce_hash_import(struct ahash_request *areq, const void *in) { - struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); @@ -128,7 +129,7 @@ int sun8i_ce_hash_import(struct ahash_request *areq, const void *in) int sun8i_ce_hash_final(struct ahash_request *areq) { - struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); @@ -145,7 +146,7 @@ int sun8i_ce_hash_final(struct ahash_request *areq) int sun8i_ce_hash_update(struct ahash_request *areq) { - struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); @@ -160,7 +161,7 @@ int sun8i_ce_hash_update(struct ahash_request *areq) int sun8i_ce_hash_finup(struct ahash_request *areq) { - struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); @@ -178,7 +179,7 @@ int sun8i_ce_hash_finup(struct ahash_request *areq) static int sun8i_ce_hash_digest_fb(struct ahash_request *areq) { - struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); @@ -239,7 +240,7 @@ int sun8i_ce_hash_digest(struct ahash_request *areq) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct sun8i_ce_hash_tfm_ctx *ctx = crypto_ahash_ctx(tfm); - struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); struct sun8i_ce_dev *ce = ctx->ce; struct crypto_engine *engine; int e; @@ -317,7 +318,7 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) struct ahash_request *areq = container_of(breq, struct ahash_request, base); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg); - struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq); + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); struct sun8i_ce_alg_template *algt; struct sun8i_ce_dev *ce; struct sun8i_ce_flow *chan; @@ -328,12 +329,9 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) u32 common; u64 byte_count; __le32 *bf; - void *buf, *result; int j, i, todo; u64 bs; int digestsize; - dma_addr_t addr_res, addr_pad; - int ns = sg_nents_for_len(areq->src, areq->nbytes); algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base); ce = algt->ce; @@ -345,19 +343,7 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) if (digestsize == SHA384_DIGEST_SIZE) digestsize = SHA512_DIGEST_SIZE; - /* the padding could be up to two block. */ - buf = kcalloc(2, bs, GFP_KERNEL | GFP_DMA); - if (!buf) { - err = -ENOMEM; - goto err_out; - } - bf = (__le32 *)buf; - - result = kzalloc(digestsize, GFP_KERNEL | GFP_DMA); - if (!result) { - err = -ENOMEM; - goto err_free_buf; - } + bf = (__le32 *)rctx->pad; flow = rctx->flow; chan = &ce->chanlist[flow]; @@ -378,11 +364,12 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) cet->t_sym_ctl = 0; cet->t_asym_ctl = 0; - nr_sgs = dma_map_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE); + rctx->nr_sgs = sg_nents_for_len(areq->src, areq->nbytes); + nr_sgs = dma_map_sg(ce->dev, areq->src, rctx->nr_sgs, DMA_TO_DEVICE); if (nr_sgs <= 0 || nr_sgs > MAX_SG) { dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs); err = -EINVAL; - goto err_free_result; + goto err_out; } len = areq->nbytes; @@ -397,10 +384,13 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) err = -EINVAL; goto err_unmap_src; } - addr_res = dma_map_single(ce->dev, result, digestsize, DMA_FROM_DEVICE); - cet->t_dst[0].addr = desc_addr_val_le32(ce, addr_res); - cet->t_dst[0].len = cpu_to_le32(digestsize / 4); - if (dma_mapping_error(ce->dev, addr_res)) { + + rctx->result_len = digestsize; + rctx->addr_res = dma_map_single(ce->dev, rctx->result, rctx->result_len, + DMA_FROM_DEVICE); + cet->t_dst[0].addr = desc_addr_val_le32(ce, rctx->addr_res); + cet->t_dst[0].len = cpu_to_le32(rctx->result_len / 4); + if (dma_mapping_error(ce->dev, rctx->addr_res)) { dev_err(ce->dev, "DMA map dest\n"); err = -EINVAL; goto err_unmap_src; @@ -428,10 +418,12 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) goto err_unmap_result; } - addr_pad = dma_map_single(ce->dev, buf, j * 4, DMA_TO_DEVICE); - cet->t_src[i].addr = desc_addr_val_le32(ce, addr_pad); + rctx->pad_len = j * 4; + rctx->addr_pad = dma_map_single(ce->dev, rctx->pad, rctx->pad_len, + DMA_TO_DEVICE); + cet->t_src[i].addr = desc_addr_val_le32(ce, rctx->addr_pad); cet->t_src[i].len = cpu_to_le32(j); - if (dma_mapping_error(ce->dev, addr_pad)) { + if (dma_mapping_error(ce->dev, rctx->addr_pad)) { dev_err(ce->dev, "DMA error on padding SG\n"); err = -EINVAL; goto err_unmap_result; @@ -444,21 +436,16 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) err = sun8i_ce_run_task(ce, flow, crypto_ahash_alg_name(tfm)); - dma_unmap_single(ce->dev, addr_pad, j * 4, DMA_TO_DEVICE); + dma_unmap_single(ce->dev, rctx->addr_pad, rctx->pad_len, DMA_TO_DEVICE); err_unmap_result: - dma_unmap_single(ce->dev, addr_res, digestsize, DMA_FROM_DEVICE); + dma_unmap_single(ce->dev, rctx->addr_res, rctx->result_len, + DMA_FROM_DEVICE); if (!err) - memcpy(areq->result, result, crypto_ahash_digestsize(tfm)); + memcpy(areq->result, rctx->result, crypto_ahash_digestsize(tfm)); err_unmap_src: - dma_unmap_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE); - -err_free_result: - kfree(result); - -err_free_buf: - kfree(buf); + dma_unmap_sg(ce->dev, areq->src, rctx->nr_sgs, DMA_TO_DEVICE); err_out: local_bh_disable(); diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h index de3a096c476c..71f5a0cd3d45 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h @@ -110,6 +110,9 @@ #define MAXFLOW 4 +#define CE_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE +#define CE_MAX_HASH_BLOCK_SIZE SHA512_BLOCK_SIZE + /* * struct ce_clock - Describe clocks used by sun8i-ce * @name: Name of clock needed by this variant @@ -304,9 +307,23 @@ struct sun8i_ce_hash_tfm_ctx { * struct sun8i_ce_hash_reqctx - context for an ahash request * @fallback_req: pre-allocated fallback request * @flow: the flow to use for this request + * @nr_sgs: number of entries in the source scatterlist + * @result_len: result length in bytes + * @pad_len: padding length in bytes + * @addr_res: DMA address of the result buffer, returned by dma_map_single() + * @addr_pad: DMA address of the padding buffer, returned by dma_map_single() + * @result: per-request result buffer + * @pad: per-request padding buffer (up to 2 blocks) */ struct sun8i_ce_hash_reqctx { int flow; + int nr_sgs; + size_t result_len; + size_t pad_len; + dma_addr_t addr_res; + dma_addr_t addr_pad; + u8 result[CE_MAX_HASH_DIGEST_SIZE] __aligned(CRYPTO_DMA_ALIGN); + u8 pad[2 * CE_MAX_HASH_BLOCK_SIZE]; struct ahash_request fallback_req; // keep at the end }; From 27d5a2d1ad94561994fe6b5ed3a2258039e9ac2b Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Tue, 2 Sep 2025 16:21:34 +0300 Subject: [PATCH 1368/2711] crytpo: sun8i-ce - factor out prepare/unprepare from sun8i_ce_hash_run() In order to make the ahash code more clear and modular, split the monolithic sun8i_ce_hash_run() callback into two parts, prepare and unprepare (therefore aligning it with the sun8i-ce skcipher code). Signed-off-by: Ovidiu Panait Signed-off-by: Herbert Xu --- .../crypto/allwinner/sun8i-ce/sun8i-ce-hash.c | 62 ++++++++++++++----- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c index 6573c566bd0d..d01594353d9a 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c @@ -313,18 +313,15 @@ static u64 hash_pad(__le32 *buf, unsigned int bufsize, u64 padi, u64 byte_count, return j; } -int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) +static int sun8i_ce_hash_prepare(struct ahash_request *areq, struct ce_task *cet) { - struct ahash_request *areq = container_of(breq, struct ahash_request, base); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg); struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); struct sun8i_ce_alg_template *algt; struct sun8i_ce_dev *ce; - struct sun8i_ce_flow *chan; - struct ce_task *cet; struct scatterlist *sg; - int nr_sgs, flow, err; + int nr_sgs, err; unsigned int len; u32 common; u64 byte_count; @@ -345,18 +342,14 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) bf = (__le32 *)rctx->pad; - flow = rctx->flow; - chan = &ce->chanlist[flow]; - if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) algt->stat_req++; dev_dbg(ce->dev, "%s %s len=%d\n", __func__, crypto_tfm_alg_name(areq->base.tfm), areq->nbytes); - cet = chan->tl; memset(cet, 0, sizeof(struct ce_task)); - cet->t_id = cpu_to_le32(flow); + cet->t_id = cpu_to_le32(rctx->flow); common = ce->variant->alg_hash[algt->ce_algo_id]; common |= CE_COMM_INT; cet->t_common_ctl = cpu_to_le32(common); @@ -434,22 +427,59 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) else cet->t_dlen = cpu_to_le32(areq->nbytes / 4 + j); - err = sun8i_ce_run_task(ce, flow, crypto_ahash_alg_name(tfm)); - - dma_unmap_single(ce->dev, rctx->addr_pad, rctx->pad_len, DMA_TO_DEVICE); + return 0; err_unmap_result: dma_unmap_single(ce->dev, rctx->addr_res, rctx->result_len, DMA_FROM_DEVICE); - if (!err) - memcpy(areq->result, rctx->result, crypto_ahash_digestsize(tfm)); err_unmap_src: dma_unmap_sg(ce->dev, areq->src, rctx->nr_sgs, DMA_TO_DEVICE); err_out: + return err; +} + +static void sun8i_ce_hash_unprepare(struct ahash_request *areq, + struct ce_task *cet) +{ + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); + struct sun8i_ce_hash_tfm_ctx *ctx = crypto_ahash_ctx(tfm); + struct sun8i_ce_dev *ce = ctx->ce; + + dma_unmap_single(ce->dev, rctx->addr_pad, rctx->pad_len, DMA_TO_DEVICE); + dma_unmap_single(ce->dev, rctx->addr_res, rctx->result_len, + DMA_FROM_DEVICE); + dma_unmap_sg(ce->dev, areq->src, rctx->nr_sgs, DMA_TO_DEVICE); +} + +int sun8i_ce_hash_run(struct crypto_engine *engine, void *async_req) +{ + struct ahash_request *areq = ahash_request_cast(async_req); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); + struct sun8i_ce_hash_tfm_ctx *ctx = crypto_ahash_ctx(tfm); + struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx_dma(areq); + struct sun8i_ce_dev *ce = ctx->ce; + struct sun8i_ce_flow *chan; + int err; + + chan = &ce->chanlist[rctx->flow]; + + err = sun8i_ce_hash_prepare(areq, chan->tl); + if (err) + return err; + + err = sun8i_ce_run_task(ce, rctx->flow, crypto_ahash_alg_name(tfm)); + + sun8i_ce_hash_unprepare(areq, chan->tl); + + if (!err) + memcpy(areq->result, rctx->result, + crypto_ahash_digestsize(tfm)); + local_bh_disable(); - crypto_finalize_hash_request(engine, breq, err); + crypto_finalize_hash_request(engine, async_req, err); local_bh_enable(); return 0; From 21140e5caf019e4a24e1ceabcaaa16bd693b393f Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 3 Sep 2025 10:06:46 +0200 Subject: [PATCH 1369/2711] crypto: rockchip - Fix dma_unmap_sg() nents value The dma_unmap_sg() functions should be called with the same nents as the dma_map_sg(), not the value the map function returned. Fixes: 57d67c6e8219 ("crypto: rockchip - rework by using crypto_engine") Cc: Signed-off-by: Thomas Fourier Signed-off-by: Herbert Xu --- drivers/crypto/rockchip/rk3288_crypto_ahash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/rockchip/rk3288_crypto_ahash.c b/drivers/crypto/rockchip/rk3288_crypto_ahash.c index d6928ebe9526..b9f5a8b42e66 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_ahash.c +++ b/drivers/crypto/rockchip/rk3288_crypto_ahash.c @@ -254,7 +254,7 @@ static void rk_hash_unprepare(struct crypto_engine *engine, void *breq) struct rk_ahash_rctx *rctx = ahash_request_ctx(areq); struct rk_crypto_info *rkc = rctx->dev; - dma_unmap_sg(rkc->dev, areq->src, rctx->nrsg, DMA_TO_DEVICE); + dma_unmap_sg(rkc->dev, areq->src, sg_nents(areq->src), DMA_TO_DEVICE); } static int rk_hash_run(struct crypto_engine *engine, void *breq) From f5d643156ef62216955c119216d2f3815bd51cb1 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 3 Sep 2025 10:34:46 +0200 Subject: [PATCH 1370/2711] crypto: atmel - Fix dma_unmap_sg() direction It seems like everywhere in this file, dd->in_sg is mapped with DMA_TO_DEVICE and dd->out_sg is mapped with DMA_FROM_DEVICE. Fixes: 13802005d8f2 ("crypto: atmel - add Atmel DES/TDES driver") Cc: Signed-off-by: Thomas Fourier Signed-off-by: Herbert Xu --- drivers/crypto/atmel-tdes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index 098f5532f389..3b2a92029b16 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -512,7 +512,7 @@ static int atmel_tdes_crypt_start(struct atmel_tdes_dev *dd) if (err && (dd->flags & TDES_FLAGS_FAST)) { dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); - dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE); + dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); } return err; From 2b0dc40ac6ca16ee0c489927f4856cf9cd3874c7 Mon Sep 17 00:00:00 2001 From: Yunseong Kim Date: Wed, 3 Sep 2025 22:16:43 +0900 Subject: [PATCH 1371/2711] crypto: ccp - Fix incorrect payload size calculation in psp_poulate_hsti() payload_size field of the request header is incorrectly calculated using sizeof(req). Since 'req' is a pointer (struct hsti_request *), sizeof(req) returns the size of the pointer itself (e.g., 8 bytes on a 64-bit system), rather than the size of the structure it points to. This leads to an incorrect payload size being sent to the Platform Security Processor (PSP), potentially causing the HSTI query command to fail. Fix this by using sizeof(*req) to correctly calculate the size of the struct hsti_request. Signed-off-by: Yunseong Kim Reviewed-by: Mario Limonciello (AMD) > --- Signed-off-by: Herbert Xu --- drivers/crypto/ccp/hsti.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/hsti.c b/drivers/crypto/ccp/hsti.c index 36f6534fbe08..c29c6a9c0f3f 100644 --- a/drivers/crypto/ccp/hsti.c +++ b/drivers/crypto/ccp/hsti.c @@ -88,7 +88,7 @@ static int psp_populate_hsti(struct psp_device *psp) if (!req) return -ENOMEM; - req->header.payload_size = sizeof(req); + req->header.payload_size = sizeof(*req); ret = psp_send_platform_access_msg(PSP_CMD_HSTI_QUERY, (struct psp_request *)req); if (ret) From e002780c14392373b26f73890ed88365e97c1cd4 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Wed, 3 Sep 2025 21:25:35 +0800 Subject: [PATCH 1372/2711] crypto: ccp - Use int type to store negative error codes Change the 'ret' variable in __sev_do_cmd_locked() from unsigned int to int, as it needs to store negative error codes. No effect on runtime. Signed-off-by: Qianfeng Rong Acked-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sev-dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 4f000dc2e639..6c116f6f9b79 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -848,9 +848,10 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret) struct sev_device *sev; unsigned int cmdbuff_hi, cmdbuff_lo; unsigned int phys_lsb, phys_msb; - unsigned int reg, ret = 0; + unsigned int reg; void *cmd_buf; int buf_len; + int ret = 0; if (!psp || !psp->sev_data) return -ENODEV; From a9a84a853c81b8ecc4ec601f9b04577cf1f86742 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Wed, 3 Sep 2025 21:25:36 +0800 Subject: [PATCH 1373/2711] crypto: hisilicon/sec - Use int type to store negative error codes Change the 'ret' variable in sec_hw_init() from u32 to int, as it needs to store either negative error codes or zero returned by sec_ipv4_hashmask(). No effect on runtime. Signed-off-by: Qianfeng Rong Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/sec/sec_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/hisilicon/sec/sec_drv.c b/drivers/crypto/hisilicon/sec/sec_drv.c index ef0cb733c92c..129cb6faa0b7 100644 --- a/drivers/crypto/hisilicon/sec/sec_drv.c +++ b/drivers/crypto/hisilicon/sec/sec_drv.c @@ -922,7 +922,8 @@ static int sec_hw_init(struct sec_dev_info *info) struct iommu_domain *domain; u32 sec_ipv4_mask = 0; u32 sec_ipv6_mask[10] = {}; - u32 i, ret; + int ret; + u32 i; domain = iommu_get_domain_for_dev(info->dev); From a710a71cd8ad294937e03b352cd71deb7ad08700 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Wed, 3 Sep 2025 21:25:37 +0800 Subject: [PATCH 1374/2711] crypto: tegra - Use int type to store negative error codes Change the 'ret' variable in tegra_sha_do_update() from unsigned int to int, as it needs to store either negative error codes or zero returned by tegra_se_host1x_submit(). No effect on runtime. Signed-off-by: Qianfeng Rong Signed-off-by: Herbert Xu --- drivers/crypto/tegra/tegra-se-hash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/tegra/tegra-se-hash.c b/drivers/crypto/tegra/tegra-se-hash.c index d09b4aaeecef..4a298ace6e9f 100644 --- a/drivers/crypto/tegra/tegra-se-hash.c +++ b/drivers/crypto/tegra/tegra-se-hash.c @@ -400,8 +400,9 @@ static int tegra_sha_do_update(struct ahash_request *req) struct tegra_sha_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); struct tegra_sha_reqctx *rctx = ahash_request_ctx(req); struct tegra_se *se = ctx->se; - unsigned int nblks, nresidue, size, ret; + unsigned int nblks, nresidue, size; u32 *cpuvaddr = se->cmdbuf->addr; + int ret; nresidue = (req->nbytes + rctx->residue.size) % rctx->blk_size; nblks = (req->nbytes + rctx->residue.size) / rctx->blk_size; From 408cf4850f640f08470450569c209dc3fdfaf12d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 4 Sep 2025 20:01:53 -0700 Subject: [PATCH 1375/2711] crypto: qat - Use library to prepare HMAC keys To prepare HMAC keys, just use the library functions instead of crypto_shash. This is much simpler, avoids depending on the fragile export_core and import_core methods, and is faster too. Acked-by: Giovanni Cabiddu Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/Kconfig | 7 +- .../crypto/intel/qat/qat_common/qat_algs.c | 195 ++++++------------ 2 files changed, 63 insertions(+), 139 deletions(-) diff --git a/drivers/crypto/intel/qat/Kconfig b/drivers/crypto/intel/qat/Kconfig index 359c61f0c8a1..4b4861460dd4 100644 --- a/drivers/crypto/intel/qat/Kconfig +++ b/drivers/crypto/intel/qat/Kconfig @@ -6,12 +6,11 @@ config CRYPTO_DEV_QAT select CRYPTO_SKCIPHER select CRYPTO_AKCIPHER select CRYPTO_DH - select CRYPTO_HMAC select CRYPTO_RSA - select CRYPTO_SHA1 - select CRYPTO_SHA256 - select CRYPTO_SHA512 select CRYPTO_LIB_AES + select CRYPTO_LIB_SHA1 + select CRYPTO_LIB_SHA256 + select CRYPTO_LIB_SHA512 select FW_LOADER select CRC8 diff --git a/drivers/crypto/intel/qat/qat_common/qat_algs.c b/drivers/crypto/intel/qat/qat_common/qat_algs.c index 43e6dd9b77b7..7f638a62e3ad 100644 --- a/drivers/crypto/intel/qat/qat_common/qat_algs.c +++ b/drivers/crypto/intel/qat/qat_common/qat_algs.c @@ -5,12 +5,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -68,16 +66,10 @@ struct qat_alg_aead_ctx { dma_addr_t dec_cd_paddr; struct icp_qat_fw_la_bulk_req enc_fw_req; struct icp_qat_fw_la_bulk_req dec_fw_req; - struct crypto_shash *hash_tfm; enum icp_qat_hw_auth_algo qat_hash_alg; + unsigned int hash_digestsize; + unsigned int hash_blocksize; struct qat_crypto_instance *inst; - union { - struct sha1_state sha1; - struct sha256_state sha256; - struct sha512_state sha512; - }; - char ipad[SHA512_BLOCK_SIZE]; /* sufficient for SHA-1/SHA-256 as well */ - char opad[SHA512_BLOCK_SIZE]; }; struct qat_alg_skcipher_ctx { @@ -94,125 +86,57 @@ struct qat_alg_skcipher_ctx { int mode; }; -static int qat_get_inter_state_size(enum icp_qat_hw_auth_algo qat_hash_alg) -{ - switch (qat_hash_alg) { - case ICP_QAT_HW_AUTH_ALGO_SHA1: - return ICP_QAT_HW_SHA1_STATE1_SZ; - case ICP_QAT_HW_AUTH_ALGO_SHA256: - return ICP_QAT_HW_SHA256_STATE1_SZ; - case ICP_QAT_HW_AUTH_ALGO_SHA512: - return ICP_QAT_HW_SHA512_STATE1_SZ; - default: - return -EFAULT; - } -} - static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash, struct qat_alg_aead_ctx *ctx, const u8 *auth_key, unsigned int auth_keylen) { - SHASH_DESC_ON_STACK(shash, ctx->hash_tfm); - int block_size = crypto_shash_blocksize(ctx->hash_tfm); - int digest_size = crypto_shash_digestsize(ctx->hash_tfm); - __be32 *hash_state_out; - __be64 *hash512_state_out; - int i, offset; - - memset(ctx->ipad, 0, block_size); - memset(ctx->opad, 0, block_size); - shash->tfm = ctx->hash_tfm; - - if (auth_keylen > block_size) { - int ret = crypto_shash_digest(shash, auth_key, - auth_keylen, ctx->ipad); - if (ret) - return ret; - - memcpy(ctx->opad, ctx->ipad, digest_size); - } else { - memcpy(ctx->ipad, auth_key, auth_keylen); - memcpy(ctx->opad, auth_key, auth_keylen); - } - - for (i = 0; i < block_size; i++) { - char *ipad_ptr = ctx->ipad + i; - char *opad_ptr = ctx->opad + i; - *ipad_ptr ^= HMAC_IPAD_VALUE; - *opad_ptr ^= HMAC_OPAD_VALUE; - } - - if (crypto_shash_init(shash)) - return -EFAULT; - - if (crypto_shash_update(shash, ctx->ipad, block_size)) - return -EFAULT; - - hash_state_out = (__be32 *)hash->sha.state1; - hash512_state_out = (__be64 *)hash_state_out; - switch (ctx->qat_hash_alg) { - case ICP_QAT_HW_AUTH_ALGO_SHA1: - if (crypto_shash_export_core(shash, &ctx->sha1)) - return -EFAULT; - for (i = 0; i < digest_size >> 2; i++, hash_state_out++) - *hash_state_out = cpu_to_be32(ctx->sha1.state[i]); - break; - case ICP_QAT_HW_AUTH_ALGO_SHA256: - if (crypto_shash_export_core(shash, &ctx->sha256)) - return -EFAULT; - for (i = 0; i < digest_size >> 2; i++, hash_state_out++) - *hash_state_out = cpu_to_be32(ctx->sha256.state[i]); - break; - case ICP_QAT_HW_AUTH_ALGO_SHA512: - if (crypto_shash_export_core(shash, &ctx->sha512)) - return -EFAULT; - for (i = 0; i < digest_size >> 3; i++, hash512_state_out++) - *hash512_state_out = cpu_to_be64(ctx->sha512.state[i]); - break; + case ICP_QAT_HW_AUTH_ALGO_SHA1: { + struct hmac_sha1_key key; + __be32 *istate = (__be32 *)hash->sha.state1; + __be32 *ostate = (__be32 *)(hash->sha.state1 + + round_up(sizeof(key.istate.h), 8)); + + hmac_sha1_preparekey(&key, auth_key, auth_keylen); + for (int i = 0; i < ARRAY_SIZE(key.istate.h); i++) { + istate[i] = cpu_to_be32(key.istate.h[i]); + ostate[i] = cpu_to_be32(key.ostate.h[i]); + } + memzero_explicit(&key, sizeof(key)); + return 0; + } + case ICP_QAT_HW_AUTH_ALGO_SHA256: { + struct hmac_sha256_key key; + __be32 *istate = (__be32 *)hash->sha.state1; + __be32 *ostate = (__be32 *)(hash->sha.state1 + + sizeof(key.key.istate.h)); + + hmac_sha256_preparekey(&key, auth_key, auth_keylen); + for (int i = 0; i < ARRAY_SIZE(key.key.istate.h); i++) { + istate[i] = cpu_to_be32(key.key.istate.h[i]); + ostate[i] = cpu_to_be32(key.key.ostate.h[i]); + } + memzero_explicit(&key, sizeof(key)); + return 0; + } + case ICP_QAT_HW_AUTH_ALGO_SHA512: { + struct hmac_sha512_key key; + __be64 *istate = (__be64 *)hash->sha.state1; + __be64 *ostate = (__be64 *)(hash->sha.state1 + + sizeof(key.key.istate.h)); + + hmac_sha512_preparekey(&key, auth_key, auth_keylen); + for (int i = 0; i < ARRAY_SIZE(key.key.istate.h); i++) { + istate[i] = cpu_to_be64(key.key.istate.h[i]); + ostate[i] = cpu_to_be64(key.key.ostate.h[i]); + } + memzero_explicit(&key, sizeof(key)); + return 0; + } default: return -EFAULT; } - - if (crypto_shash_init(shash)) - return -EFAULT; - - if (crypto_shash_update(shash, ctx->opad, block_size)) - return -EFAULT; - - offset = round_up(qat_get_inter_state_size(ctx->qat_hash_alg), 8); - if (offset < 0) - return -EFAULT; - - hash_state_out = (__be32 *)(hash->sha.state1 + offset); - hash512_state_out = (__be64 *)hash_state_out; - - switch (ctx->qat_hash_alg) { - case ICP_QAT_HW_AUTH_ALGO_SHA1: - if (crypto_shash_export_core(shash, &ctx->sha1)) - return -EFAULT; - for (i = 0; i < digest_size >> 2; i++, hash_state_out++) - *hash_state_out = cpu_to_be32(ctx->sha1.state[i]); - break; - case ICP_QAT_HW_AUTH_ALGO_SHA256: - if (crypto_shash_export_core(shash, &ctx->sha256)) - return -EFAULT; - for (i = 0; i < digest_size >> 2; i++, hash_state_out++) - *hash_state_out = cpu_to_be32(ctx->sha256.state[i]); - break; - case ICP_QAT_HW_AUTH_ALGO_SHA512: - if (crypto_shash_export_core(shash, &ctx->sha512)) - return -EFAULT; - for (i = 0; i < digest_size >> 3; i++, hash512_state_out++) - *hash512_state_out = cpu_to_be64(ctx->sha512.state[i]); - break; - default: - return -EFAULT; - } - memzero_explicit(ctx->ipad, block_size); - memzero_explicit(ctx->opad, block_size); - return 0; } static void qat_alg_init_common_hdr(struct icp_qat_fw_comn_req_hdr *header) @@ -259,7 +183,7 @@ static int qat_alg_aead_init_enc_session(struct crypto_aead *aead_tfm, ICP_QAT_HW_AUTH_CONFIG_BUILD(ICP_QAT_HW_AUTH_MODE1, ctx->qat_hash_alg, digestsize); hash->sha.inner_setup.auth_counter.counter = - cpu_to_be32(crypto_shash_blocksize(ctx->hash_tfm)); + cpu_to_be32(ctx->hash_blocksize); if (qat_alg_do_precomputes(hash, ctx, keys->authkey, keys->authkeylen)) return -EFAULT; @@ -326,7 +250,7 @@ static int qat_alg_aead_init_dec_session(struct crypto_aead *aead_tfm, struct icp_qat_hw_cipher_algo_blk *cipher = (struct icp_qat_hw_cipher_algo_blk *)((char *)dec_ctx + sizeof(struct icp_qat_hw_auth_setup) + - roundup(crypto_shash_digestsize(ctx->hash_tfm), 8) * 2); + roundup(ctx->hash_digestsize, 8) * 2); struct icp_qat_fw_la_bulk_req *req_tmpl = &ctx->dec_fw_req; struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req_tmpl->cd_pars; struct icp_qat_fw_comn_req_hdr *header = &req_tmpl->comn_hdr; @@ -346,7 +270,7 @@ static int qat_alg_aead_init_dec_session(struct crypto_aead *aead_tfm, ctx->qat_hash_alg, digestsize); hash->sha.inner_setup.auth_counter.counter = - cpu_to_be32(crypto_shash_blocksize(ctx->hash_tfm)); + cpu_to_be32(ctx->hash_blocksize); if (qat_alg_do_precomputes(hash, ctx, keys->authkey, keys->authkeylen)) return -EFAULT; @@ -368,7 +292,7 @@ static int qat_alg_aead_init_dec_session(struct crypto_aead *aead_tfm, cipher_cd_ctrl->cipher_state_sz = AES_BLOCK_SIZE >> 3; cipher_cd_ctrl->cipher_cfg_offset = (sizeof(struct icp_qat_hw_auth_setup) + - roundup(crypto_shash_digestsize(ctx->hash_tfm), 8) * 2) >> 3; + roundup(ctx->hash_digestsize, 8) * 2) >> 3; ICP_QAT_FW_COMN_CURR_ID_SET(cipher_cd_ctrl, ICP_QAT_FW_SLICE_CIPHER); ICP_QAT_FW_COMN_NEXT_ID_SET(cipher_cd_ctrl, ICP_QAT_FW_SLICE_DRAM_WR); @@ -1150,32 +1074,35 @@ static int qat_alg_skcipher_xts_decrypt(struct skcipher_request *req) } static int qat_alg_aead_init(struct crypto_aead *tfm, - enum icp_qat_hw_auth_algo hash, - const char *hash_name) + enum icp_qat_hw_auth_algo hash_alg, + unsigned int hash_digestsize, + unsigned int hash_blocksize) { struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm); - ctx->hash_tfm = crypto_alloc_shash(hash_name, 0, 0); - if (IS_ERR(ctx->hash_tfm)) - return PTR_ERR(ctx->hash_tfm); - ctx->qat_hash_alg = hash; + ctx->qat_hash_alg = hash_alg; + ctx->hash_digestsize = hash_digestsize; + ctx->hash_blocksize = hash_blocksize; crypto_aead_set_reqsize(tfm, sizeof(struct qat_crypto_request)); return 0; } static int qat_alg_aead_sha1_init(struct crypto_aead *tfm) { - return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA1, "sha1"); + return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA1, + SHA1_DIGEST_SIZE, SHA1_BLOCK_SIZE); } static int qat_alg_aead_sha256_init(struct crypto_aead *tfm) { - return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA256, "sha256"); + return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA256, + SHA256_DIGEST_SIZE, SHA256_BLOCK_SIZE); } static int qat_alg_aead_sha512_init(struct crypto_aead *tfm) { - return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA512, "sha512"); + return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA512, + SHA512_DIGEST_SIZE, SHA512_BLOCK_SIZE); } static void qat_alg_aead_exit(struct crypto_aead *tfm) @@ -1184,8 +1111,6 @@ static void qat_alg_aead_exit(struct crypto_aead *tfm) struct qat_crypto_instance *inst = ctx->inst; struct device *dev; - crypto_free_shash(ctx->hash_tfm); - if (!inst) return; From 9c6ed103a75756aadee0e4e6a1aa3b8187b55c22 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 4 Sep 2025 20:04:28 -0700 Subject: [PATCH 1376/2711] crypto: chelsio - Use library to prepare HMAC keys To prepare HMAC keys, just use the library functions instead of crypto_shash. This is much simpler, avoids depending on the fragile export_core and import_core methods, and is faster too. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/Kconfig | 6 +- drivers/crypto/chelsio/chcr_algo.c | 255 ++++++--------------------- drivers/crypto/chelsio/chcr_crypto.h | 1 - 3 files changed, 61 insertions(+), 201 deletions(-) diff --git a/drivers/crypto/chelsio/Kconfig b/drivers/crypto/chelsio/Kconfig index 5dd3f6a4781a..37294bb74003 100644 --- a/drivers/crypto/chelsio/Kconfig +++ b/drivers/crypto/chelsio/Kconfig @@ -4,9 +4,9 @@ config CRYPTO_DEV_CHELSIO depends on CHELSIO_T4 select CRYPTO_LIB_AES select CRYPTO_LIB_GF128MUL - select CRYPTO_SHA1 - select CRYPTO_SHA256 - select CRYPTO_SHA512 + select CRYPTO_LIB_SHA1 + select CRYPTO_LIB_SHA256 + select CRYPTO_LIB_SHA512 select CRYPTO_AUTHENC help The Chelsio Crypto Co-processor driver for T6 adapters. diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index be21e4e2016c..22cbc343198a 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -51,7 +51,6 @@ #include #include -#include #include #include #include @@ -277,88 +276,60 @@ static void get_aes_decrypt_key(unsigned char *dec_key, } } -static struct crypto_shash *chcr_alloc_shash(unsigned int ds) +static int chcr_prepare_hmac_key(const u8 *raw_key, unsigned int raw_key_len, + int digestsize, void *istate, void *ostate) { - struct crypto_shash *base_hash = ERR_PTR(-EINVAL); + __be32 *istate32 = istate, *ostate32 = ostate; + __be64 *istate64 = istate, *ostate64 = ostate; + union { + struct hmac_sha1_key sha1; + struct hmac_sha224_key sha224; + struct hmac_sha256_key sha256; + struct hmac_sha384_key sha384; + struct hmac_sha512_key sha512; + } k; - switch (ds) { + switch (digestsize) { case SHA1_DIGEST_SIZE: - base_hash = crypto_alloc_shash("sha1", 0, 0); + hmac_sha1_preparekey(&k.sha1, raw_key, raw_key_len); + for (int i = 0; i < ARRAY_SIZE(k.sha1.istate.h); i++) { + istate32[i] = cpu_to_be32(k.sha1.istate.h[i]); + ostate32[i] = cpu_to_be32(k.sha1.ostate.h[i]); + } break; case SHA224_DIGEST_SIZE: - base_hash = crypto_alloc_shash("sha224", 0, 0); + hmac_sha224_preparekey(&k.sha224, raw_key, raw_key_len); + for (int i = 0; i < ARRAY_SIZE(k.sha224.key.istate.h); i++) { + istate32[i] = cpu_to_be32(k.sha224.key.istate.h[i]); + ostate32[i] = cpu_to_be32(k.sha224.key.ostate.h[i]); + } break; case SHA256_DIGEST_SIZE: - base_hash = crypto_alloc_shash("sha256", 0, 0); + hmac_sha256_preparekey(&k.sha256, raw_key, raw_key_len); + for (int i = 0; i < ARRAY_SIZE(k.sha256.key.istate.h); i++) { + istate32[i] = cpu_to_be32(k.sha256.key.istate.h[i]); + ostate32[i] = cpu_to_be32(k.sha256.key.ostate.h[i]); + } break; case SHA384_DIGEST_SIZE: - base_hash = crypto_alloc_shash("sha384", 0, 0); + hmac_sha384_preparekey(&k.sha384, raw_key, raw_key_len); + for (int i = 0; i < ARRAY_SIZE(k.sha384.key.istate.h); i++) { + istate64[i] = cpu_to_be64(k.sha384.key.istate.h[i]); + ostate64[i] = cpu_to_be64(k.sha384.key.ostate.h[i]); + } break; case SHA512_DIGEST_SIZE: - base_hash = crypto_alloc_shash("sha512", 0, 0); + hmac_sha512_preparekey(&k.sha512, raw_key, raw_key_len); + for (int i = 0; i < ARRAY_SIZE(k.sha512.key.istate.h); i++) { + istate64[i] = cpu_to_be64(k.sha512.key.istate.h[i]); + ostate64[i] = cpu_to_be64(k.sha512.key.ostate.h[i]); + } break; + default: + return -EINVAL; } - - return base_hash; -} - -static int chcr_compute_partial_hash(struct shash_desc *desc, - char *iopad, char *result_hash, - int digest_size) -{ - struct sha1_state sha1_st; - struct sha256_state sha256_st; - struct sha512_state sha512_st; - int error; - - if (digest_size == SHA1_DIGEST_SIZE) { - error = crypto_shash_init(desc) ?: - crypto_shash_update(desc, iopad, SHA1_BLOCK_SIZE) ?: - crypto_shash_export_core(desc, &sha1_st); - memcpy(result_hash, sha1_st.state, SHA1_DIGEST_SIZE); - } else if (digest_size == SHA224_DIGEST_SIZE) { - error = crypto_shash_init(desc) ?: - crypto_shash_update(desc, iopad, SHA256_BLOCK_SIZE) ?: - crypto_shash_export_core(desc, &sha256_st); - memcpy(result_hash, sha256_st.state, SHA256_DIGEST_SIZE); - - } else if (digest_size == SHA256_DIGEST_SIZE) { - error = crypto_shash_init(desc) ?: - crypto_shash_update(desc, iopad, SHA256_BLOCK_SIZE) ?: - crypto_shash_export_core(desc, &sha256_st); - memcpy(result_hash, sha256_st.state, SHA256_DIGEST_SIZE); - - } else if (digest_size == SHA384_DIGEST_SIZE) { - error = crypto_shash_init(desc) ?: - crypto_shash_update(desc, iopad, SHA512_BLOCK_SIZE) ?: - crypto_shash_export_core(desc, &sha512_st); - memcpy(result_hash, sha512_st.state, SHA512_DIGEST_SIZE); - - } else if (digest_size == SHA512_DIGEST_SIZE) { - error = crypto_shash_init(desc) ?: - crypto_shash_update(desc, iopad, SHA512_BLOCK_SIZE) ?: - crypto_shash_export_core(desc, &sha512_st); - memcpy(result_hash, sha512_st.state, SHA512_DIGEST_SIZE); - } else { - error = -EINVAL; - pr_err("Unknown digest size %d\n", digest_size); - } - return error; -} - -static void chcr_change_order(char *buf, int ds) -{ - int i; - - if (ds == SHA512_DIGEST_SIZE) { - for (i = 0; i < (ds / sizeof(u64)); i++) - *((__be64 *)buf + i) = - cpu_to_be64(*((u64 *)buf + i)); - } else { - for (i = 0; i < (ds / sizeof(u32)); i++) - *((__be32 *)buf + i) = - cpu_to_be32(*((u32 *)buf + i)); - } + memzero_explicit(&k, sizeof(k)); + return 0; } static inline int is_hmac(struct crypto_tfm *tfm) @@ -1547,11 +1518,6 @@ static int get_alg_config(struct algo_param *params, return 0; } -static inline void chcr_free_shash(struct crypto_shash *base_hash) -{ - crypto_free_shash(base_hash); -} - /** * create_hash_wr - Create hash work request * @req: Cipher req base @@ -2202,53 +2168,13 @@ static int chcr_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) { struct hmac_ctx *hmacctx = HMAC_CTX(h_ctx(tfm)); - unsigned int digestsize = crypto_ahash_digestsize(tfm); - unsigned int bs = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); - unsigned int i, err = 0, updated_digestsize; - - SHASH_DESC_ON_STACK(shash, hmacctx->base_hash); /* use the key to calculate the ipad and opad. ipad will sent with the * first request's data. opad will be sent with the final hash result * ipad in hmacctx->ipad and opad in hmacctx->opad location */ - shash->tfm = hmacctx->base_hash; - if (keylen > bs) { - err = crypto_shash_digest(shash, key, keylen, - hmacctx->ipad); - if (err) - goto out; - keylen = digestsize; - } else { - memcpy(hmacctx->ipad, key, keylen); - } - memset(hmacctx->ipad + keylen, 0, bs - keylen); - unsafe_memcpy(hmacctx->opad, hmacctx->ipad, bs, - "fortified memcpy causes -Wrestrict warning"); - - for (i = 0; i < bs / sizeof(int); i++) { - *((unsigned int *)(&hmacctx->ipad) + i) ^= IPAD_DATA; - *((unsigned int *)(&hmacctx->opad) + i) ^= OPAD_DATA; - } - - updated_digestsize = digestsize; - if (digestsize == SHA224_DIGEST_SIZE) - updated_digestsize = SHA256_DIGEST_SIZE; - else if (digestsize == SHA384_DIGEST_SIZE) - updated_digestsize = SHA512_DIGEST_SIZE; - err = chcr_compute_partial_hash(shash, hmacctx->ipad, - hmacctx->ipad, digestsize); - if (err) - goto out; - chcr_change_order(hmacctx->ipad, updated_digestsize); - - err = chcr_compute_partial_hash(shash, hmacctx->opad, - hmacctx->opad, digestsize); - if (err) - goto out; - chcr_change_order(hmacctx->opad, updated_digestsize); -out: - return err; + return chcr_prepare_hmac_key(key, keylen, crypto_ahash_digestsize(tfm), + hmacctx->ipad, hmacctx->opad); } static int chcr_aes_xts_setkey(struct crypto_skcipher *cipher, const u8 *key, @@ -2344,30 +2270,11 @@ static int chcr_hmac_init(struct ahash_request *areq) static int chcr_hmac_cra_init(struct crypto_tfm *tfm) { - struct chcr_context *ctx = crypto_tfm_ctx(tfm); - struct hmac_ctx *hmacctx = HMAC_CTX(ctx); - unsigned int digestsize = - crypto_ahash_digestsize(__crypto_ahash_cast(tfm)); - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), sizeof(struct chcr_ahash_req_ctx)); - hmacctx->base_hash = chcr_alloc_shash(digestsize); - if (IS_ERR(hmacctx->base_hash)) - return PTR_ERR(hmacctx->base_hash); return chcr_device_init(crypto_tfm_ctx(tfm)); } -static void chcr_hmac_cra_exit(struct crypto_tfm *tfm) -{ - struct chcr_context *ctx = crypto_tfm_ctx(tfm); - struct hmac_ctx *hmacctx = HMAC_CTX(ctx); - - if (hmacctx->base_hash) { - chcr_free_shash(hmacctx->base_hash); - hmacctx->base_hash = NULL; - } -} - inline void chcr_aead_common_exit(struct aead_request *req) { struct chcr_aead_reqctx *reqctx = aead_request_ctx_dma(req); @@ -3557,15 +3464,12 @@ static int chcr_authenc_setkey(struct crypto_aead *authenc, const u8 *key, struct chcr_authenc_ctx *actx = AUTHENC_CTX(aeadctx); /* it contains auth and cipher key both*/ struct crypto_authenc_keys keys; - unsigned int bs, subtype; + unsigned int subtype; unsigned int max_authsize = crypto_aead_alg(authenc)->maxauthsize; - int err = 0, i, key_ctx_len = 0; + int err = 0, key_ctx_len = 0; unsigned char ck_size = 0; - unsigned char pad[CHCR_HASH_MAX_BLOCK_SIZE_128] = { 0 }; - struct crypto_shash *base_hash = ERR_PTR(-EINVAL); struct algo_param param; int align; - u8 *o_ptr = NULL; crypto_aead_clear_flags(aeadctx->sw_cipher, CRYPTO_TFM_REQ_MASK); crypto_aead_set_flags(aeadctx->sw_cipher, crypto_aead_get_flags(authenc) @@ -3613,68 +3517,26 @@ static int chcr_authenc_setkey(struct crypto_aead *authenc, const u8 *key, get_aes_decrypt_key(actx->dec_rrkey, aeadctx->key, aeadctx->enckey_len << 3); } - base_hash = chcr_alloc_shash(max_authsize); - if (IS_ERR(base_hash)) { - pr_err("Base driver cannot be loaded\n"); + + align = KEYCTX_ALIGN_PAD(max_authsize); + err = chcr_prepare_hmac_key(keys.authkey, keys.authkeylen, max_authsize, + actx->h_iopad, + actx->h_iopad + param.result_size + align); + if (err) goto out; - } - { - SHASH_DESC_ON_STACK(shash, base_hash); - shash->tfm = base_hash; - bs = crypto_shash_blocksize(base_hash); - align = KEYCTX_ALIGN_PAD(max_authsize); - o_ptr = actx->h_iopad + param.result_size + align; + key_ctx_len = sizeof(struct _key_ctx) + roundup(keys.enckeylen, 16) + + (param.result_size + align) * 2; + aeadctx->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size, param.mk_size, 0, 1, + key_ctx_len >> 4); + actx->auth_mode = param.auth_mode; - if (keys.authkeylen > bs) { - err = crypto_shash_digest(shash, keys.authkey, - keys.authkeylen, - o_ptr); - if (err) { - pr_err("Base driver cannot be loaded\n"); - goto out; - } - keys.authkeylen = max_authsize; - } else - memcpy(o_ptr, keys.authkey, keys.authkeylen); + memzero_explicit(&keys, sizeof(keys)); + return 0; - /* Compute the ipad-digest*/ - memset(pad + keys.authkeylen, 0, bs - keys.authkeylen); - memcpy(pad, o_ptr, keys.authkeylen); - for (i = 0; i < bs >> 2; i++) - *((unsigned int *)pad + i) ^= IPAD_DATA; - - if (chcr_compute_partial_hash(shash, pad, actx->h_iopad, - max_authsize)) - goto out; - /* Compute the opad-digest */ - memset(pad + keys.authkeylen, 0, bs - keys.authkeylen); - memcpy(pad, o_ptr, keys.authkeylen); - for (i = 0; i < bs >> 2; i++) - *((unsigned int *)pad + i) ^= OPAD_DATA; - - if (chcr_compute_partial_hash(shash, pad, o_ptr, max_authsize)) - goto out; - - /* convert the ipad and opad digest to network order */ - chcr_change_order(actx->h_iopad, param.result_size); - chcr_change_order(o_ptr, param.result_size); - key_ctx_len = sizeof(struct _key_ctx) + - roundup(keys.enckeylen, 16) + - (param.result_size + align) * 2; - aeadctx->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size, param.mk_size, - 0, 1, key_ctx_len >> 4); - actx->auth_mode = param.auth_mode; - chcr_free_shash(base_hash); - - memzero_explicit(&keys, sizeof(keys)); - return 0; - } out: aeadctx->enckey_len = 0; memzero_explicit(&keys, sizeof(keys)); - if (!IS_ERR(base_hash)) - chcr_free_shash(base_hash); return -EINVAL; } @@ -4490,7 +4352,6 @@ static int chcr_register_alg(void) if (driver_algs[i].type == CRYPTO_ALG_TYPE_HMAC) { a_hash->halg.base.cra_init = chcr_hmac_cra_init; - a_hash->halg.base.cra_exit = chcr_hmac_cra_exit; a_hash->init = chcr_hmac_init; a_hash->setkey = chcr_ahash_setkey; a_hash->halg.base.cra_ctxsize = SZ_AHASH_H_CTX; diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index 1d693b8436e6..e1e79e5f01e7 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -241,7 +241,6 @@ struct chcr_aead_ctx { }; struct hmac_ctx { - struct crypto_shash *base_hash; u8 ipad[CHCR_HASH_MAX_BLOCK_SIZE_128]; u8 opad[CHCR_HASH_MAX_BLOCK_SIZE_128]; }; From a5d71f011ee1f211e437333555fd981e040c146c Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 5 Sep 2025 10:57:01 +0200 Subject: [PATCH 1377/2711] crypto: cryptd - WQ_PERCPU added to alloc_workqueue users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. alloc_workqueue() treats all queues as per-CPU by default, while unbound workqueues must opt-in via WQ_UNBOUND. This default is suboptimal: most workloads benefit from unbound queues, allowing the scheduler to place worker threads where they’re needed and reducing noise when CPUs are isolated. This default is suboptimal: most workloads benefit from unbound queues, allowing the scheduler to place worker threads where they’re needed and reducing noise when CPUs are isolated. This patch adds a new WQ_PERCPU flag to explicitly request the use of the per-CPU behavior. Both flags coexist for one release cycle to allow callers to transition their calls. Once migration is complete, WQ_UNBOUND can be removed and unbound will become the implicit default. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. All existing users have been updated accordingly. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Signed-off-by: Herbert Xu --- crypto/cryptd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/cryptd.c b/crypto/cryptd.c index efff54e707cb..cd38f4676176 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -1115,7 +1115,8 @@ static int __init cryptd_init(void) { int err; - cryptd_wq = alloc_workqueue("cryptd", WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, + cryptd_wq = alloc_workqueue("cryptd", + WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE | WQ_PERCPU, 1); if (!cryptd_wq) return -ENOMEM; From b6d02e0e41aa87aaa46b9b995e71a585284c5d27 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 5 Sep 2025 11:05:32 +0200 Subject: [PATCH 1378/2711] padata: replace use of system_unbound_wq with system_dfl_wq Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. system_unbound_wq should be the default workqueue so as not to enforce locality constraints for random work whenever it's not required. Adding system_dfl_wq to encourage its use when unbound work should be used. queue_work() / queue_delayed_work() / mod_delayed_work() will now use the new unbound wq: whether the user still use the old wq a warn will be printed along with a wq redirect to the new one. The old system_unbound_wq will be kept for a few release cycles. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Signed-off-by: Herbert Xu --- kernel/padata.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/padata.c b/kernel/padata.c index 833740d75483..d7cc95367209 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -490,9 +490,9 @@ void __init padata_do_multithreaded(struct padata_mt_job *job) do { nid = next_node_in(old_node, node_states[N_CPU]); } while (!atomic_try_cmpxchg(&last_used_nid, &old_node, nid)); - queue_work_node(nid, system_unbound_wq, &pw->pw_work); + queue_work_node(nid, system_dfl_wq, &pw->pw_work); } else { - queue_work(system_unbound_wq, &pw->pw_work); + queue_work(system_dfl_wq, &pw->pw_work); } /* Use the current thread, which saves starting a workqueue worker. */ From 4fcd322914068f2c6aec7bb5cfd12ce0207b3a21 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 5 Sep 2025 11:05:33 +0200 Subject: [PATCH 1379/2711] padata: WQ_PERCPU added to alloc_workqueue users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. alloc_workqueue() treats all queues as per-CPU by default, while unbound workqueues must opt-in via WQ_UNBOUND. This default is suboptimal: most workloads benefit from unbound queues, allowing the scheduler to place worker threads where they’re needed and reducing noise when CPUs are isolated. This default is suboptimal: most workloads benefit from unbound queues, allowing the scheduler to place worker threads where they’re needed and reducing noise when CPUs are isolated. This patch adds a new WQ_PERCPU flag to explicitly request the use of the per-CPU behavior. Both flags coexist for one release cycle to allow callers to transition their calls. Once migration is complete, WQ_UNBOUND can be removed and unbound will become the implicit default. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. All existing users have been updated accordingly. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Signed-off-by: Herbert Xu --- kernel/padata.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/padata.c b/kernel/padata.c index d7cc95367209..f4def028c48c 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -967,8 +967,9 @@ struct padata_instance *padata_alloc(const char *name) cpus_read_lock(); - pinst->serial_wq = alloc_workqueue("%s_serial", WQ_MEM_RECLAIM | - WQ_CPU_INTENSIVE, 1, name); + pinst->serial_wq = alloc_workqueue("%s_serial", + WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE | WQ_PERCPU, + 1, name); if (!pinst->serial_wq) goto err_put_cpus; From 9048beca9c5614d486e2b492c0a7867164bf56a8 Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Fri, 5 Sep 2025 15:41:48 +0530 Subject: [PATCH 1380/2711] crypto: caam - double the entropy delay interval for retry during entropy evaluation, if the generated samples fail any statistical test, then, all of the bits will be discarded, and a second set of samples will be generated and tested. the entropy delay interval should be doubled before performing the retry. also, ctrlpriv->rng4_sh_init and inst_handles both reads RNG DRNG status register, but only inst_handles is updated before every retry. so only check inst_handles and removing ctrlpriv->rng4_sh_init Signed-off-by: Gaurav Jain Signed-off-by: Herbert Xu --- drivers/crypto/caam/ctrl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index ca4f6eb53b9f..320be5d77737 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -703,12 +703,12 @@ static int caam_ctrl_rng_init(struct device *dev) */ if (needs_entropy_delay_adjustment()) ent_delay = 12000; - if (!(ctrlpriv->rng4_sh_init || inst_handles)) { + if (!inst_handles) { dev_info(dev, "Entropy delay = %u\n", ent_delay); kick_trng(dev, ent_delay); - ent_delay += 400; + ent_delay = ent_delay * 2; } /* * if instantiate_rng(...) fails, the loop will rerun From 1e26339703e2afd397037defa798682b2b93dcc0 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 5 Sep 2025 18:39:11 +0200 Subject: [PATCH 1381/2711] crypto: qat - Replace kzalloc() + copy_from_user() with memdup_user() Replace kzalloc() followed by copy_from_user() with memdup_user() to improve and simplify adf_ctl_alloc_resources(). memdup_user() returns either -ENOMEM or -EFAULT (instead of -EIO) if an error occurs. Remove the unnecessary device id initialization, since memdup_user() (like copy_from_user()) immediately overwrites it. No functional changes intended other than returning the more idiomatic error code -EFAULT. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c index 48c62a14a6a7..84bc89e16742 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c @@ -94,17 +94,10 @@ static int adf_ctl_alloc_resources(struct adf_user_cfg_ctl_data **ctl_data, { struct adf_user_cfg_ctl_data *cfg_data; - cfg_data = kzalloc(sizeof(*cfg_data), GFP_KERNEL); - if (!cfg_data) - return -ENOMEM; - - /* Initialize device id to NO DEVICE as 0 is a valid device id */ - cfg_data->device_id = ADF_CFG_NO_DEVICE; - - if (copy_from_user(cfg_data, (void __user *)arg, sizeof(*cfg_data))) { + cfg_data = memdup_user((void __user *)arg, sizeof(*cfg_data)); + if (IS_ERR(cfg_data)) { pr_err("QAT: failed to copy from user cfg_data.\n"); - kfree(cfg_data); - return -EIO; + return PTR_ERR(cfg_data); } *ctl_data = cfg_data; From 381e8ee368234a51b3a4f231f6f24ff0b09d9f9e Mon Sep 17 00:00:00 2001 From: Ryo Takakura Date: Sat, 6 Sep 2025 11:41:35 +0000 Subject: [PATCH 1382/2711] crypto: omap - convert from tasklet to BH workqueue tasklet has been marked deprecated and it's planned to be removed. Make omap crypto drivers to use BH workqueue which is the new interface for executing in BH context in place of tasklet. Signed-off-by: Ryo Takakura Acked-by: Tejun Heo Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 15 ++++++++------- drivers/crypto/omap-aes.h | 2 +- drivers/crypto/omap-des.c | 17 +++++++++-------- drivers/crypto/omap-sham.c | 15 ++++++++------- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 244e24e52987..3cc802622dd5 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "omap-crypto.h" #include "omap-aes.h" @@ -221,7 +222,7 @@ static void omap_aes_dma_out_callback(void *data) struct omap_aes_dev *dd = data; /* dma_lch_out - completed */ - tasklet_schedule(&dd->done_task); + queue_work(system_bh_wq, &dd->done_task); } static int omap_aes_dma_init(struct omap_aes_dev *dd) @@ -494,9 +495,9 @@ static void omap_aes_copy_ivout(struct omap_aes_dev *dd, u8 *ivbuf) ((u32 *)ivbuf)[i] = omap_aes_read(dd, AES_REG_IV(dd, i)); } -static void omap_aes_done_task(unsigned long data) +static void omap_aes_done_task(struct work_struct *t) { - struct omap_aes_dev *dd = (struct omap_aes_dev *)data; + struct omap_aes_dev *dd = from_work(dd, t, done_task); pr_debug("enter done_task\n"); @@ -925,7 +926,7 @@ static irqreturn_t omap_aes_irq(int irq, void *dev_id) if (!dd->total) /* All bytes read! */ - tasklet_schedule(&dd->done_task); + queue_work(system_bh_wq, &dd->done_task); else /* Enable DATA_IN interrupt for next block */ omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x2); @@ -1140,7 +1141,7 @@ static int omap_aes_probe(struct platform_device *pdev) (reg & dd->pdata->major_mask) >> dd->pdata->major_shift, (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift); - tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd); + INIT_WORK(&dd->done_task, omap_aes_done_task); err = omap_aes_dma_init(dd); if (err == -EPROBE_DEFER) { @@ -1229,7 +1230,7 @@ err_engine: omap_aes_dma_cleanup(dd); err_irq: - tasklet_kill(&dd->done_task); + cancel_work_sync(&dd->done_task); err_pm_disable: pm_runtime_disable(dev); err_res: @@ -1264,7 +1265,7 @@ static void omap_aes_remove(struct platform_device *pdev) crypto_engine_exit(dd->engine); - tasklet_kill(&dd->done_task); + cancel_work_sync(&dd->done_task); omap_aes_dma_cleanup(dd); pm_runtime_disable(dd->dev); } diff --git a/drivers/crypto/omap-aes.h b/drivers/crypto/omap-aes.h index 41d67780fd45..99c36a777e97 100644 --- a/drivers/crypto/omap-aes.h +++ b/drivers/crypto/omap-aes.h @@ -159,7 +159,7 @@ struct omap_aes_dev { unsigned long flags; int err; - struct tasklet_struct done_task; + struct work_struct done_task; struct aead_queue aead_queue; spinlock_t lock; diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index 9c5538ae17db..149ebd77710b 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "omap-crypto.h" @@ -130,7 +131,7 @@ struct omap_des_dev { unsigned long flags; int err; - struct tasklet_struct done_task; + struct work_struct done_task; struct skcipher_request *req; struct crypto_engine *engine; @@ -325,7 +326,7 @@ static void omap_des_dma_out_callback(void *data) struct omap_des_dev *dd = data; /* dma_lch_out - completed */ - tasklet_schedule(&dd->done_task); + queue_work(system_bh_wq, &dd->done_task); } static int omap_des_dma_init(struct omap_des_dev *dd) @@ -580,9 +581,9 @@ static int omap_des_crypt_req(struct crypto_engine *engine, omap_des_crypt_dma_start(dd); } -static void omap_des_done_task(unsigned long data) +static void omap_des_done_task(struct work_struct *t) { - struct omap_des_dev *dd = (struct omap_des_dev *)data; + struct omap_des_dev *dd = from_work(dd, t, done_task); int i; pr_debug("enter done_task\n"); @@ -890,7 +891,7 @@ static irqreturn_t omap_des_irq(int irq, void *dev_id) if (!dd->total) /* All bytes read! */ - tasklet_schedule(&dd->done_task); + queue_work(system_bh_wq, &dd->done_task); else /* Enable DATA_IN interrupt for next block */ omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2); @@ -986,7 +987,7 @@ static int omap_des_probe(struct platform_device *pdev) (reg & dd->pdata->major_mask) >> dd->pdata->major_shift, (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift); - tasklet_init(&dd->done_task, omap_des_done_task, (unsigned long)dd); + INIT_WORK(&dd->done_task, omap_des_done_task); err = omap_des_dma_init(dd); if (err == -EPROBE_DEFER) { @@ -1053,7 +1054,7 @@ err_engine: omap_des_dma_cleanup(dd); err_irq: - tasklet_kill(&dd->done_task); + cancel_work_sync(&dd->done_task); err_get: pm_runtime_disable(dev); err_res: @@ -1077,7 +1078,7 @@ static void omap_des_remove(struct platform_device *pdev) crypto_engine_unregister_skcipher( &dd->pdata->algs_info[i].algs_list[j]); - tasklet_kill(&dd->done_task); + cancel_work_sync(&dd->done_task); omap_des_dma_cleanup(dd); pm_runtime_disable(dd->dev); } diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 6328e8026b91..ff8aac02994a 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -37,6 +37,7 @@ #include #include #include +#include #define MD5_DIGEST_SIZE 16 @@ -217,7 +218,7 @@ struct omap_sham_dev { int irq; int err; struct dma_chan *dma_lch; - struct tasklet_struct done_task; + struct work_struct done_task; u8 polling_mode; u8 xmit_buf[BUFLEN] OMAP_ALIGNED; @@ -561,7 +562,7 @@ static void omap_sham_dma_callback(void *param) struct omap_sham_dev *dd = param; set_bit(FLAGS_DMA_READY, &dd->flags); - tasklet_schedule(&dd->done_task); + queue_work(system_bh_wq, &dd->done_task); } static int omap_sham_xmit_dma(struct omap_sham_dev *dd, size_t length, @@ -1703,9 +1704,9 @@ static struct ahash_engine_alg algs_sha384_sha512[] = { }, }; -static void omap_sham_done_task(unsigned long data) +static void omap_sham_done_task(struct work_struct *t) { - struct omap_sham_dev *dd = (struct omap_sham_dev *)data; + struct omap_sham_dev *dd = from_work(dd, t, done_task); int err = 0; dev_dbg(dd->dev, "%s: flags=%lx\n", __func__, dd->flags); @@ -1739,7 +1740,7 @@ finish: static irqreturn_t omap_sham_irq_common(struct omap_sham_dev *dd) { set_bit(FLAGS_OUTPUT_READY, &dd->flags); - tasklet_schedule(&dd->done_task); + queue_work(system_bh_wq, &dd->done_task); return IRQ_HANDLED; } @@ -2059,7 +2060,7 @@ static int omap_sham_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dd); INIT_LIST_HEAD(&dd->list); - tasklet_init(&dd->done_task, omap_sham_done_task, (unsigned long)dd); + INIT_WORK(&dd->done_task, omap_sham_done_task); crypto_init_queue(&dd->queue, OMAP_SHAM_QUEUE_LENGTH); err = (dev->of_node) ? omap_sham_get_res_of(dd, dev, &res) : @@ -2194,7 +2195,7 @@ static void omap_sham_remove(struct platform_device *pdev) &dd->pdata->algs_info[i].algs_list[j]); dd->pdata->algs_info[i].registered--; } - tasklet_kill(&dd->done_task); + cancel_work_sync(&dd->done_task); pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); From 828dea389683d8e1df687fbd4521d391df369437 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 12 Sep 2025 01:47:06 +0800 Subject: [PATCH 1383/2711] clk: sunxi-ng: sun55i-a523-ccu: Add missing NPU module clock The main clock controller on the A523/T527 has the NPU's module clock. It was missing from the original submission, likely because that was based on the A523 user manual; the A523 is marketed without the NPU. Also, merge the private header back into the driver code itself. The header only contains a macro containing the total number of clocks. This has to be updated every time a missing clock gets added. Having it in a separate file doesn't help the process. Instead just drop the macro, and thus the header no longer has any reason to exist. Also move the .num value to after the list of clks to make it obvious that it should be updated when new clks are added. Reviewed-by: Andre Przywara Reviewed-by: Jernej Skrabec Link: https://patch.msgid.link/20250911174710.3149589-4-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/ccu-sun55i-a523.c | 21 ++++++++++++++++++--- drivers/clk/sunxi-ng/ccu-sun55i-a523.h | 14 -------------- 2 files changed, 18 insertions(+), 17 deletions(-) delete mode 100644 drivers/clk/sunxi-ng/ccu-sun55i-a523.h diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523.c index 1a9a1cb869e2..acb532f8361b 100644 --- a/drivers/clk/sunxi-ng/ccu-sun55i-a523.c +++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523.c @@ -11,6 +11,9 @@ #include #include +#include +#include + #include "../clk.h" #include "ccu_common.h" @@ -25,8 +28,6 @@ #include "ccu_nkmp.h" #include "ccu_nm.h" -#include "ccu-sun55i-a523.h" - /* * The 24 MHz oscillator, the root of most of the clock tree. * .fw_name is the string used in the DT "clock-names" property, used to @@ -486,6 +487,18 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, static SUNXI_CCU_GATE_HWS(bus_ve_clk, "bus-ve", ahb_hws, 0x69c, BIT(0), 0); +static const struct clk_hw *npu_parents[] = { + &pll_periph0_480M_clk.common.hw, + &pll_periph0_600M_clk.hw, + &pll_periph0_800M_clk.common.hw, + &pll_npu_2x_clk.hw, +}; +static SUNXI_CCU_M_HW_WITH_MUX_GATE(npu_clk, "npu", npu_parents, 0x6e0, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + static SUNXI_CCU_GATE_HWS(bus_dma_clk, "bus-dma", ahb_hws, 0x70c, BIT(0), 0); static SUNXI_CCU_GATE_HWS(bus_msgbox_clk, "bus-msgbox", ahb_hws, 0x71c, @@ -1217,6 +1230,7 @@ static struct ccu_common *sun55i_a523_ccu_clks[] = { &bus_ce_sys_clk.common, &ve_clk.common, &bus_ve_clk.common, + &npu_clk.common, &bus_dma_clk.common, &bus_msgbox_clk.common, &bus_spinlock_clk.common, @@ -1343,7 +1357,6 @@ static struct ccu_common *sun55i_a523_ccu_clks[] = { }; static struct clk_hw_onecell_data sun55i_a523_hw_clks = { - .num = CLK_NUMBER, .hws = { [CLK_PLL_DDR0] = &pll_ddr_clk.common.hw, [CLK_PLL_PERIPH0_4X] = &pll_periph0_4x_clk.common.hw, @@ -1524,7 +1537,9 @@ static struct clk_hw_onecell_data sun55i_a523_hw_clks = { [CLK_FANOUT0] = &fanout0_clk.common.hw, [CLK_FANOUT1] = &fanout1_clk.common.hw, [CLK_FANOUT2] = &fanout2_clk.common.hw, + [CLK_NPU] = &npu_clk.common.hw, }, + .num = CLK_NPU + 1, }; static struct ccu_reset_map sun55i_a523_ccu_resets[] = { diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523.h b/drivers/clk/sunxi-ng/ccu-sun55i-a523.h deleted file mode 100644 index fc8dd42f1b47..000000000000 --- a/drivers/clk/sunxi-ng/ccu-sun55i-a523.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright 2024 Arm Ltd. - */ - -#ifndef _CCU_SUN55I_A523_H -#define _CCU_SUN55I_A523_H - -#include -#include - -#define CLK_NUMBER (CLK_FANOUT2 + 1) - -#endif /* _CCU_SUN55I_A523_H */ From 44293edd013e5ed48060e6a8848c215fd3bf8ce3 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 12 Sep 2025 01:47:07 +0800 Subject: [PATCH 1384/2711] clk: sunxi-ng: div: support power-of-two dividers Some clocks (for timers) on the A523 are mux-divider-gate types with the divider being values of power-of-two. Add a macro for these types of clocks so that we can use the divider types instead of the M-P types without an M divider. Reviewed-by: Jernej Skrabec Link: https://patch.msgid.link/20250911174710.3149589-5-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/ccu_div.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h index 90d49ee8e0cc..be00b3277e97 100644 --- a/drivers/clk/sunxi-ng/ccu_div.h +++ b/drivers/clk/sunxi-ng/ccu_div.h @@ -274,6 +274,24 @@ struct ccu_div { SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg, \ _mshift, _mwidth, 0, _flags) +#define SUNXI_CCU_P_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_div _struct = { \ + .enable = _gate, \ + .div = _SUNXI_CCU_DIV_FLAGS(_mshift, _mwidth, \ + CLK_DIVIDER_POWER_OF_TWO), \ + .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ + _parents, \ + &ccu_div_ops, \ + _flags), \ + }, \ + } + static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw) { struct ccu_common *common = hw_to_ccu_common(hw); From 598e4b6713b54267acc257b3c66a269079ee4d8f Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 12 Sep 2025 01:47:08 +0800 Subject: [PATCH 1385/2711] clk: sunxi-ng: add support for the A523/T527 MCU CCU The A523/T527 SoCs have a new MCU PRCM, which has more clocks and reset controls for the RISC-V MCU and other peripherals. There is a second audio PLL, but no bus clock dividers. The BSP driver uses the 24MHz main oscillator as the parent for all the bus clocks. But the diagram suggests busses from the other PRCM are used in this block as well. Add a driver to support this part. Unlike the BSP driver, the SoC's main MBUS clock is chosen as the parent for the MCU MBUS clock, and the latter then serves as the parent of the MCU DMA controller's MBUS clock. The bus gate clocks also use their respective bus clocks as parents according to the system bus tree diagram. In cases where a block does not appear in that diagram, an educated guess is made. Reviewed-by: Jernej Skrabec Link: https://patch.msgid.link/20250911174710.3149589-6-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/Kconfig | 5 + drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun55i-a523-mcu.c | 469 +++++++++++++++++++++ 3 files changed, 476 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun55i-a523-mcu.c diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index 8896fd052ef1..6af2d020e03e 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -57,6 +57,11 @@ config SUN55I_A523_CCU default ARCH_SUNXI depends on ARM64 || COMPILE_TEST +config SUN55I_A523_MCU_CCU + tristate "Support for the Allwinner A523/T527 MCU CCU" + default ARCH_SUNXI + depends on ARM64 || COMPILE_TEST + config SUN55I_A523_R_CCU tristate "Support for the Allwinner A523/T527 PRCM CCU" default ARCH_SUNXI diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 82e471036de6..a1c4087d7241 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SUN50I_H6_CCU) += sun50i-h6-ccu.o obj-$(CONFIG_SUN50I_H6_R_CCU) += sun50i-h6-r-ccu.o obj-$(CONFIG_SUN50I_H616_CCU) += sun50i-h616-ccu.o obj-$(CONFIG_SUN55I_A523_CCU) += sun55i-a523-ccu.o +obj-$(CONFIG_SUN55I_A523_MCU_CCU) += sun55i-a523-mcu-ccu.o obj-$(CONFIG_SUN55I_A523_R_CCU) += sun55i-a523-r-ccu.o obj-$(CONFIG_SUN4I_A10_CCU) += sun4i-a10-ccu.o obj-$(CONFIG_SUN5I_CCU) += sun5i-ccu.o @@ -61,6 +62,7 @@ sun50i-h6-ccu-y += ccu-sun50i-h6.o sun50i-h6-r-ccu-y += ccu-sun50i-h6-r.o sun50i-h616-ccu-y += ccu-sun50i-h616.o sun55i-a523-ccu-y += ccu-sun55i-a523.o +sun55i-a523-mcu-ccu-y += ccu-sun55i-a523-mcu.o sun55i-a523-r-ccu-y += ccu-sun55i-a523-r.o sun4i-a10-ccu-y += ccu-sun4i-a10.o sun5i-ccu-y += ccu-sun5i.o diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523-mcu.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523-mcu.c new file mode 100644 index 000000000000..197844f0fe4e --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523-mcu.c @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Chen-Yu Tsai + * + * Based on the A523 CCU driver: + * Copyright (C) 2023-2024 Arm Ltd. + */ + +#include +#include +#include +#include + +#include +#include + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_mult.h" +#include "ccu_nm.h" + +static const struct clk_parent_data osc24M[] = { + { .fw_name = "hosc" } +}; + +static const struct clk_parent_data ahb[] = { + { .fw_name = "r-ahb" } +}; + +static const struct clk_parent_data apb[] = { + { .fw_name = "r-apb0" } +}; + +#define SUN55I_A523_PLL_AUDIO1_REG 0x00c +static struct ccu_sdm_setting pll_audio1_sdm_table[] = { + { .rate = 2167603200, .pattern = 0xa000a234, .m = 1, .n = 90 }, /* div2->22.5792 */ + { .rate = 2359296000, .pattern = 0xa0009ba6, .m = 1, .n = 98 }, /* div2->24.576 */ + { .rate = 1806336000, .pattern = 0xa000872b, .m = 1, .n = 75 }, /* div5->22.576 */ +}; + +static struct ccu_nm pll_audio1_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 11), + .m = _SUNXI_CCU_DIV(1, 1), + .sdm = _SUNXI_CCU_SDM(pll_audio1_sdm_table, BIT(24), + 0x010, BIT(31)), + .min_rate = 180000000U, + .max_rate = 3500000000U, + .common = { + .reg = 0x00c, + .features = CCU_FEATURE_SIGMA_DELTA_MOD, + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-audio1", + osc24M, &ccu_nm_ops, + CLK_SET_RATE_GATE), + }, +}; + +/* + * /2 and /5 dividers are actually programmable, but we just use the + * values from the BSP, since the audio PLL only needs to provide a + * couple clock rates. This also matches the names given in the manual. + */ +static const struct clk_hw *pll_audio1_div_parents[] = { &pll_audio1_clk.common.hw }; +static CLK_FIXED_FACTOR_HWS(pll_audio1_div2_clk, "pll-audio1-div2", + pll_audio1_div_parents, 2, 1, + CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HWS(pll_audio1_div5_clk, "pll-audio1-div5", + pll_audio1_div_parents, 5, 1, + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_M_WITH_GATE(audio_out_clk, "audio-out", + "pll-audio1-div2", 0x01c, + 0, 5, BIT(31), CLK_SET_RATE_PARENT); + +static const struct clk_parent_data dsp_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, + /* + * The order of the following two parent is from the BSP code. It is + * the opposite in the manual. Testing with the DSP is required to + * figure out the real order. + */ + { .hw = &pll_audio1_div5_clk.hw }, + { .hw = &pll_audio1_div2_clk.hw }, + { .fw_name = "dsp" }, +}; +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(dsp_clk, "mcu-dsp", dsp_parents, 0x0020, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static const struct clk_parent_data i2s_parents[] = { + { .fw_name = "pll-audio0-4x" }, + { .hw = &pll_audio1_div2_clk.hw }, + { .hw = &pll_audio1_div5_clk.hw }, +}; + +static SUNXI_CCU_DUALDIV_MUX_GATE(i2s0_clk, "i2s0", i2s_parents, 0x02c, + 0, 5, /* M */ + 5, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); +static SUNXI_CCU_DUALDIV_MUX_GATE(i2s1_clk, "i2s1", i2s_parents, 0x030, + 0, 5, /* M */ + 5, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); +static SUNXI_CCU_DUALDIV_MUX_GATE(i2s2_clk, "i2s2", i2s_parents, 0x034, + 0, 5, /* M */ + 5, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); +static SUNXI_CCU_DUALDIV_MUX_GATE(i2s3_clk, "i2s3", i2s_parents, 0x038, + 0, 5, /* M */ + 5, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static const struct clk_parent_data i2s3_asrc_parents[] = { + { .fw_name = "pll-periph0-300m" }, + { .hw = &pll_audio1_div2_clk.hw }, + { .hw = &pll_audio1_div5_clk.hw }, +}; +static SUNXI_CCU_DUALDIV_MUX_GATE(i2s3_asrc_clk, "i2s3-asrc", + i2s3_asrc_parents, 0x03c, + 0, 5, /* M */ + 5, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE_DATA(bus_i2s0_clk, "bus-i2s0", apb, 0x040, BIT(0), 0); +static SUNXI_CCU_GATE_DATA(bus_i2s1_clk, "bus-i2s1", apb, 0x040, BIT(1), 0); +static SUNXI_CCU_GATE_DATA(bus_i2s2_clk, "bus-i2s2", apb, 0x040, BIT(2), 0); +static SUNXI_CCU_GATE_DATA(bus_i2s3_clk, "bus-i2s3", apb, 0x040, BIT(3), 0); + +static const struct clk_parent_data audio_parents[] = { + { .fw_name = "pll-audio0-4x" }, + { .hw = &pll_audio1_div2_clk.hw }, + { .hw = &pll_audio1_div5_clk.hw }, +}; +static SUNXI_CCU_DUALDIV_MUX_GATE(spdif_tx_clk, "spdif-tx", + audio_parents, 0x044, + 0, 5, /* M */ + 5, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); +static SUNXI_CCU_DUALDIV_MUX_GATE(spdif_rx_clk, "spdif-rx", + i2s3_asrc_parents, 0x048, + 0, 5, /* M */ + 5, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE_DATA(bus_spdif_clk, "bus-spdif", apb, 0x04c, BIT(0), 0); + +static SUNXI_CCU_DUALDIV_MUX_GATE(dmic_clk, "dmic", audio_parents, 0x050, + 0, 5, /* M */ + 5, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE_DATA(bus_dmic_clk, "bus-dmic", apb, 0x054, BIT(0), 0); + +static SUNXI_CCU_DUALDIV_MUX_GATE(audio_dac_clk, "audio-dac", + audio_parents, 0x058, + 0, 5, /* M */ + 5, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); +static SUNXI_CCU_DUALDIV_MUX_GATE(audio_adc_clk, "audio-adc", + audio_parents, 0x05c, + 0, 5, /* M */ + 5, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE_DATA(bus_audio_codec_clk, "bus-audio-codec", + apb, 0x060, BIT(0), 0); + +static SUNXI_CCU_GATE_DATA(bus_dsp_msgbox_clk, "bus-dsp-msgbox", + ahb, 0x068, BIT(0), 0); +static SUNXI_CCU_GATE_DATA(bus_dsp_cfg_clk, "bus-dsp-cfg", + apb, 0x06c, BIT(0), 0); + +static SUNXI_CCU_GATE_DATA(bus_npu_hclk, "bus-npu-hclk", ahb, 0x070, BIT(1), 0); +static SUNXI_CCU_GATE_DATA(bus_npu_aclk, "bus-npu-aclk", ahb, 0x070, BIT(2), 0); + +static const struct clk_parent_data timer_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, + { .fw_name = "r-ahb" } +}; +static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer0_clk, "mcu-timer0", timer_parents, + 0x074, + 1, 3, /* P */ + 4, 2, /* mux */ + BIT(0), /* gate */ + 0); +static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer1_clk, "mcu-timer1", timer_parents, + 0x078, + 1, 3, /* P */ + 4, 2, /* mux */ + BIT(0), /* gate */ + 0); +static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer2_clk, "mcu-timer2", timer_parents, + 0x07c, + 1, 3, /* P */ + 4, 2, /* mux */ + BIT(0), /* gate */ + 0); +static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer3_clk, "mcu-timer3", timer_parents, + 0x080, + 1, 3, /* P */ + 4, 2, /* mux */ + BIT(0), /* gate */ + 0); +static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer4_clk, "mcu-timer4", timer_parents, + 0x084, + 1, 3, /* P */ + 4, 2, /* mux */ + BIT(0), /* gate */ + 0); +static SUNXI_CCU_P_DATA_WITH_MUX_GATE(mcu_timer5_clk, "mcu-timer5", timer_parents, + 0x088, + 1, 3, /* P */ + 4, 2, /* mux */ + BIT(0), /* gate */ + 0); +static SUNXI_CCU_GATE_DATA(bus_mcu_timer_clk, "bus-mcu-timer", ahb, 0x08c, BIT(0), 0); +static SUNXI_CCU_GATE_DATA(bus_mcu_dma_clk, "bus-mcu-dma", ahb, 0x104, BIT(0), 0); +/* tzma* only found in BSP code. */ +static SUNXI_CCU_GATE_DATA(tzma0_clk, "tzma0", ahb, 0x108, BIT(0), 0); +static SUNXI_CCU_GATE_DATA(tzma1_clk, "tzma1", ahb, 0x10c, BIT(0), 0); +/* parent is a guess as this block is not shown in the system bus tree diagram */ +static SUNXI_CCU_GATE_DATA(bus_pubsram_clk, "bus-pubsram", ahb, 0x114, BIT(0), 0); + +/* + * user manual has "mbus" clock as parent of both clocks below, + * but this makes more sense, since BSP MCU DMA controller has + * reference to both of them, likely needing both enabled. + */ +static SUNXI_CCU_GATE_FW(mbus_mcu_clk, "mbus-mcu", "mbus", 0x11c, BIT(1), 0); +static SUNXI_CCU_GATE_HW(mbus_mcu_dma_clk, "mbus-mcu-dma", + &mbus_mcu_clk.common.hw, 0x11c, BIT(0), 0); + +static const struct clk_parent_data riscv_pwm_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, +}; + +static SUNXI_CCU_MUX_DATA_WITH_GATE(riscv_clk, "riscv", + riscv_pwm_parents, 0x120, + 27, 3, BIT(31), 0); +/* Parents are guesses as these two blocks are not shown in the system bus tree diagram */ +static SUNXI_CCU_GATE_DATA(bus_riscv_cfg_clk, "bus-riscv-cfg", ahb, + 0x124, BIT(0), 0); +static SUNXI_CCU_GATE_DATA(bus_riscv_msgbox_clk, "bus-riscv-msgbox", ahb, + 0x128, BIT(0), 0); + +static SUNXI_CCU_MUX_DATA_WITH_GATE(mcu_pwm0_clk, "mcu-pwm0", + riscv_pwm_parents, 0x130, + 24, 3, BIT(31), 0); +static SUNXI_CCU_GATE_DATA(bus_mcu_pwm0_clk, "bus-mcu-pwm0", apb, + 0x134, BIT(0), 0); + +/* + * Contains all clocks that are controlled by a hardware register. They + * have a (sunxi) .common member, which needs to be initialised by the common + * sunxi CCU code, to be filled with the MMIO base address and the shared lock. + */ +static struct ccu_common *sun55i_a523_mcu_ccu_clks[] = { + &pll_audio1_clk.common, + &audio_out_clk.common, + &dsp_clk.common, + &i2s0_clk.common, + &i2s1_clk.common, + &i2s2_clk.common, + &i2s3_clk.common, + &i2s3_asrc_clk.common, + &bus_i2s0_clk.common, + &bus_i2s1_clk.common, + &bus_i2s2_clk.common, + &bus_i2s3_clk.common, + &spdif_tx_clk.common, + &spdif_rx_clk.common, + &bus_spdif_clk.common, + &dmic_clk.common, + &bus_dmic_clk.common, + &audio_dac_clk.common, + &audio_adc_clk.common, + &bus_audio_codec_clk.common, + &bus_dsp_msgbox_clk.common, + &bus_dsp_cfg_clk.common, + &bus_npu_aclk.common, + &bus_npu_hclk.common, + &mcu_timer0_clk.common, + &mcu_timer1_clk.common, + &mcu_timer2_clk.common, + &mcu_timer3_clk.common, + &mcu_timer4_clk.common, + &mcu_timer5_clk.common, + &bus_mcu_timer_clk.common, + &bus_mcu_dma_clk.common, + &tzma0_clk.common, + &tzma1_clk.common, + &bus_pubsram_clk.common, + &mbus_mcu_dma_clk.common, + &mbus_mcu_clk.common, + &riscv_clk.common, + &bus_riscv_cfg_clk.common, + &bus_riscv_msgbox_clk.common, + &mcu_pwm0_clk.common, + &bus_mcu_pwm0_clk.common, +}; + +static struct clk_hw_onecell_data sun55i_a523_mcu_hw_clks = { + .hws = { + [CLK_MCU_PLL_AUDIO1] = &pll_audio1_clk.common.hw, + [CLK_MCU_PLL_AUDIO1_DIV2] = &pll_audio1_div2_clk.hw, + [CLK_MCU_PLL_AUDIO1_DIV5] = &pll_audio1_div5_clk.hw, + [CLK_MCU_AUDIO_OUT] = &audio_out_clk.common.hw, + [CLK_MCU_DSP] = &dsp_clk.common.hw, + [CLK_MCU_I2S0] = &i2s0_clk.common.hw, + [CLK_MCU_I2S1] = &i2s1_clk.common.hw, + [CLK_MCU_I2S2] = &i2s2_clk.common.hw, + [CLK_MCU_I2S3] = &i2s3_clk.common.hw, + [CLK_MCU_I2S3_ASRC] = &i2s3_asrc_clk.common.hw, + [CLK_BUS_MCU_I2S0] = &bus_i2s0_clk.common.hw, + [CLK_BUS_MCU_I2S1] = &bus_i2s1_clk.common.hw, + [CLK_BUS_MCU_I2S2] = &bus_i2s2_clk.common.hw, + [CLK_BUS_MCU_I2S3] = &bus_i2s3_clk.common.hw, + [CLK_MCU_SPDIF_TX] = &spdif_tx_clk.common.hw, + [CLK_MCU_SPDIF_RX] = &spdif_rx_clk.common.hw, + [CLK_BUS_MCU_SPDIF] = &bus_spdif_clk.common.hw, + [CLK_MCU_DMIC] = &dmic_clk.common.hw, + [CLK_BUS_MCU_DMIC] = &bus_dmic_clk.common.hw, + [CLK_MCU_AUDIO_CODEC_DAC] = &audio_dac_clk.common.hw, + [CLK_MCU_AUDIO_CODEC_ADC] = &audio_adc_clk.common.hw, + [CLK_BUS_MCU_AUDIO_CODEC] = &bus_audio_codec_clk.common.hw, + [CLK_BUS_MCU_DSP_MSGBOX] = &bus_dsp_msgbox_clk.common.hw, + [CLK_BUS_MCU_DSP_CFG] = &bus_dsp_cfg_clk.common.hw, + [CLK_BUS_MCU_NPU_HCLK] = &bus_npu_hclk.common.hw, + [CLK_BUS_MCU_NPU_ACLK] = &bus_npu_aclk.common.hw, + [CLK_MCU_TIMER0] = &mcu_timer0_clk.common.hw, + [CLK_MCU_TIMER1] = &mcu_timer1_clk.common.hw, + [CLK_MCU_TIMER2] = &mcu_timer2_clk.common.hw, + [CLK_MCU_TIMER3] = &mcu_timer3_clk.common.hw, + [CLK_MCU_TIMER4] = &mcu_timer4_clk.common.hw, + [CLK_MCU_TIMER5] = &mcu_timer5_clk.common.hw, + [CLK_BUS_MCU_TIMER] = &bus_mcu_timer_clk.common.hw, + [CLK_BUS_MCU_DMA] = &bus_mcu_dma_clk.common.hw, + [CLK_MCU_TZMA0] = &tzma0_clk.common.hw, + [CLK_MCU_TZMA1] = &tzma1_clk.common.hw, + [CLK_BUS_MCU_PUBSRAM] = &bus_pubsram_clk.common.hw, + [CLK_MCU_MBUS_DMA] = &mbus_mcu_dma_clk.common.hw, + [CLK_MCU_MBUS] = &mbus_mcu_clk.common.hw, + [CLK_MCU_RISCV] = &riscv_clk.common.hw, + [CLK_BUS_MCU_RISCV_CFG] = &bus_riscv_cfg_clk.common.hw, + [CLK_BUS_MCU_RISCV_MSGBOX] = &bus_riscv_msgbox_clk.common.hw, + [CLK_MCU_PWM0] = &mcu_pwm0_clk.common.hw, + [CLK_BUS_MCU_PWM0] = &bus_mcu_pwm0_clk.common.hw, + }, + .num = CLK_BUS_MCU_PWM0 + 1, +}; + +static struct ccu_reset_map sun55i_a523_mcu_ccu_resets[] = { + [RST_BUS_MCU_I2S0] = { 0x0040, BIT(16) }, + [RST_BUS_MCU_I2S1] = { 0x0040, BIT(17) }, + [RST_BUS_MCU_I2S2] = { 0x0040, BIT(18) }, + [RST_BUS_MCU_I2S3] = { 0x0040, BIT(19) }, + [RST_BUS_MCU_SPDIF] = { 0x004c, BIT(16) }, + [RST_BUS_MCU_DMIC] = { 0x0054, BIT(16) }, + [RST_BUS_MCU_AUDIO_CODEC] = { 0x0060, BIT(16) }, + [RST_BUS_MCU_DSP_MSGBOX] = { 0x0068, BIT(16) }, + [RST_BUS_MCU_DSP_CFG] = { 0x006c, BIT(16) }, + [RST_BUS_MCU_NPU] = { 0x0070, BIT(16) }, + [RST_BUS_MCU_TIMER] = { 0x008c, BIT(16) }, + /* dsp and dsp_debug resets only found in BSP code. */ + [RST_BUS_MCU_DSP_DEBUG] = { 0x0100, BIT(16) }, + [RST_BUS_MCU_DSP] = { 0x0100, BIT(17) }, + [RST_BUS_MCU_DMA] = { 0x0104, BIT(16) }, + [RST_BUS_MCU_PUBSRAM] = { 0x0114, BIT(16) }, + [RST_BUS_MCU_RISCV_CFG] = { 0x0124, BIT(16) }, + [RST_BUS_MCU_RISCV_DEBUG] = { 0x0124, BIT(17) }, + [RST_BUS_MCU_RISCV_CORE] = { 0x0124, BIT(18) }, + [RST_BUS_MCU_RISCV_MSGBOX] = { 0x0128, BIT(16) }, + [RST_BUS_MCU_PWM0] = { 0x0134, BIT(16) }, +}; + +static const struct sunxi_ccu_desc sun55i_a523_mcu_ccu_desc = { + .ccu_clks = sun55i_a523_mcu_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun55i_a523_mcu_ccu_clks), + + .hw_clks = &sun55i_a523_mcu_hw_clks, + + .resets = sun55i_a523_mcu_ccu_resets, + .num_resets = ARRAY_SIZE(sun55i_a523_mcu_ccu_resets), +}; + +static int sun55i_a523_mcu_ccu_probe(struct platform_device *pdev) +{ + void __iomem *reg; + u32 val; + int ret; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + val = readl(reg + SUN55I_A523_PLL_AUDIO1_REG); + + /* + * The PLL clock code does not model all bits, for instance it does + * not support a separate enable and gate bit. We present the + * gate bit(27) as the enable bit, but then have to set the + * PLL Enable, LDO Enable, and Lock Enable bits on all PLLs here. + */ + val |= BIT(31) | BIT(30) | BIT(29); + + /* Enforce p1 = 5, p0 = 2 (the default) for PLL_AUDIO1 */ + val &= ~(GENMASK(22, 20) | GENMASK(18, 16)); + val |= (4 << 20) | (1 << 16); + + writel(val, reg + SUN55I_A523_PLL_AUDIO1_REG); + + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun55i_a523_mcu_ccu_desc); + if (ret) + return ret; + + return 0; +} + +static const struct of_device_id sun55i_a523_mcu_ccu_ids[] = { + { .compatible = "allwinner,sun55i-a523-mcu-ccu" }, + { } +}; + +static struct platform_driver sun55i_a523_mcu_ccu_driver = { + .probe = sun55i_a523_mcu_ccu_probe, + .driver = { + .name = "sun55i-a523-mcu-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun55i_a523_mcu_ccu_ids, + }, +}; +module_platform_driver(sun55i_a523_mcu_ccu_driver); + +MODULE_IMPORT_NS("SUNXI_CCU"); +MODULE_DESCRIPTION("Support for the Allwinner A523 MCU CCU"); +MODULE_LICENSE("GPL"); From abe629ebdabea4827f7c8f1c8fe79caf1fc4deb9 Mon Sep 17 00:00:00 2001 From: Akshay Jindal Date: Wed, 10 Sep 2025 01:16:46 +0530 Subject: [PATCH 1386/2711] iio: light: ltr390: Implement runtime PM support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement runtime power management for the LTR390 sensor. The device autosuspends after 1s of idle time, reducing current consumption from 100 µA in active mode to 1 µA in standby mode as per the datasheet. Ensure that interrupts continue to be delivered with runtime PM. Since the LTR390 cannot be used as a wakeup source during runtime suspend, therefore increment the runtime PM refcount when enabling events and decrement it when disabling events or powering down. This prevents event loss while still allowing power savings when IRQs are unused. Signed-off-by: Akshay Jindal Signed-off-by: Jonathan Cameron --- drivers/iio/light/ltr390.c | 136 ++++++++++++++++++++++++++++++++----- 1 file changed, 119 insertions(+), 17 deletions(-) diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c index 2e1cf62e8201..a2b804e9089a 100644 --- a/drivers/iio/light/ltr390.c +++ b/drivers/iio/light/ltr390.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -105,6 +106,7 @@ struct ltr390_data { enum ltr390_mode mode; int gain; int int_time_us; + bool irq_enabled; }; static const struct regmap_range ltr390_readable_reg_ranges[] = { @@ -215,9 +217,10 @@ static int ltr390_get_samp_freq_or_period(struct ltr390_data *data, return ltr390_samp_freq_table[value][option]; } -static int ltr390_read_raw(struct iio_dev *iio_device, - struct iio_chan_spec const *chan, int *val, - int *val2, long mask) + +static int ltr390_do_read_raw(struct iio_dev *iio_device, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) { int ret; struct ltr390_data *data = iio_priv(iio_device); @@ -280,6 +283,27 @@ static int ltr390_read_raw(struct iio_dev *iio_device, } } +static int ltr390_read_raw(struct iio_dev *iio_device, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + struct ltr390_data *data = iio_priv(iio_device); + struct device *dev = &data->client->dev; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) { + dev_err(dev, "runtime PM failed to resume: %d\n", ret); + return ret; + } + + ret = ltr390_do_read_raw(iio_device, chan, val, val2, mask); + + pm_runtime_put_autosuspend(dev); + + return ret; +} + /* integration time in us */ static const int ltr390_int_time_map_us[] = { 400000, 200000, 100000, 50000, 25000, 12500 }; static const int ltr390_gain_map[] = { 1, 3, 6, 9, 18 }; @@ -586,11 +610,11 @@ static int ltr390_read_event_config(struct iio_dev *indio_dev, return FIELD_GET(LTR390_LS_INT_EN, status); } -static int ltr390_write_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - bool state) +static int ltr390_do_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) { struct ltr390_data *data = iio_priv(indio_dev); int ret; @@ -598,7 +622,6 @@ static int ltr390_write_event_config(struct iio_dev *indio_dev, if (!state) return regmap_clear_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN); - guard(mutex)(&data->lock); ret = regmap_set_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN); if (ret < 0) return ret; @@ -623,6 +646,37 @@ static int ltr390_write_event_config(struct iio_dev *indio_dev, } } +static int ltr390_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + int ret; + struct ltr390_data *data = iio_priv(indio_dev); + struct device *dev = &data->client->dev; + + guard(mutex)(&data->lock); + + if (state && !data->irq_enabled) { + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) { + dev_err(dev, "runtime PM failed to resume: %d\n", ret); + return ret; + } + data->irq_enabled = true; + } + + ret = ltr390_do_event_config(indio_dev, chan, type, dir, state); + + if (!state && data->irq_enabled) { + data->irq_enabled = false; + pm_runtime_put_autosuspend(dev); + } + + return ret; +} + static int ltr390_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) @@ -683,17 +737,38 @@ static irqreturn_t ltr390_interrupt_handler(int irq, void *private) static void ltr390_powerdown(void *priv) { struct ltr390_data *data = priv; + struct device *dev = &data->client->dev; + int ret; guard(mutex)(&data->lock); /* Ensure that power off and interrupts are disabled */ - if (regmap_clear_bits(data->regmap, LTR390_INT_CFG, - LTR390_LS_INT_EN) < 0) - dev_err(&data->client->dev, "failed to disable interrupts\n"); + if (data->irq_enabled) { + ret = regmap_clear_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN); + if (ret < 0) + dev_err(dev, "failed to disable interrupts\n"); - if (regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, - LTR390_SENSOR_ENABLE) < 0) - dev_err(&data->client->dev, "failed to disable sensor\n"); + data->irq_enabled = false; + pm_runtime_put_autosuspend(dev); + } + + ret = regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE); + if (ret < 0) + dev_err(dev, "failed to disable sensor\n"); +} + +static int ltr390_pm_init(struct ltr390_data *data) +{ + int ret; + struct device *dev = &data->client->dev; + + ret = devm_pm_runtime_set_active_enabled(dev); + if (ret) + return dev_err_probe(dev, ret, "failed to enable runtime PM\n"); + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + return 0; } static int ltr390_probe(struct i2c_client *client) @@ -708,6 +783,8 @@ static int ltr390_probe(struct i2c_client *client) if (!indio_dev) return -ENOMEM; + i2c_set_clientdata(client, indio_dev); + data = iio_priv(indio_dev); data->regmap = devm_regmap_init_i2c(client, <r390_regmap_config); if (IS_ERR(data->regmap)) @@ -721,6 +798,8 @@ static int ltr390_probe(struct i2c_client *client) data->gain = 3; /* default mode for ltr390 is ALS mode */ data->mode = LTR390_SET_ALS_MODE; + /* default value of irq_enabled is false */ + data->irq_enabled = false; mutex_init(&data->lock); @@ -763,6 +842,10 @@ static int ltr390_probe(struct i2c_client *client) "request irq (%d) failed\n", client->irq); } + ret = ltr390_pm_init(data); + if (ret) + return dev_err_probe(dev, ret, "failed to initialize runtime PM\n"); + return devm_iio_device_register(dev, indio_dev); } @@ -784,7 +867,26 @@ static int ltr390_resume(struct device *dev) LTR390_SENSOR_ENABLE); } -static DEFINE_SIMPLE_DEV_PM_OPS(ltr390_pm_ops, ltr390_suspend, ltr390_resume); +static int ltr390_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ltr390_data *data = iio_priv(indio_dev); + + return regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE); +} + +static int ltr390_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ltr390_data *data = iio_priv(indio_dev); + + return regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE); +} + +static const struct dev_pm_ops ltr390_pm_ops = { + SYSTEM_SLEEP_PM_OPS(ltr390_suspend, ltr390_resume) + RUNTIME_PM_OPS(ltr390_runtime_suspend, ltr390_runtime_resume, NULL) +}; static const struct i2c_device_id ltr390_id[] = { { "ltr390" }, @@ -802,7 +904,7 @@ static struct i2c_driver ltr390_driver = { .driver = { .name = "ltr390", .of_match_table = ltr390_of_table, - .pm = pm_sleep_ptr(<r390_pm_ops), + .pm = pm_ptr(<r390_pm_ops), }, .probe = ltr390_probe, .id_table = ltr390_id, From f15bc37d8c336e79491209b268e73868c44733c4 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 8 Sep 2025 07:35:21 +0000 Subject: [PATCH 1387/2711] iio: add IIO_ALTCURRENT channel type Add support for IIO_ALTCURRENT channel type to distinguish AC current measurements from DC current measurements. This follows the same pattern as IIO_VOLTAGE and IIO_ALTVOLTAGE. Reviewed-by: David Lechner Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 1 + include/uapi/linux/iio/types.h | 1 + tools/iio/iio_event_monitor.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 38848d753a33..4ff2c44f9324 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -97,6 +97,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_COLORTEMP] = "colortemp", [IIO_CHROMATICITY] = "chromaticity", [IIO_ATTENTION] = "attention", + [IIO_ALTCURRENT] = "altcurrent", }; static const char * const iio_modifier_names[] = { diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 3eb0821af7a4..3c3cc1497a1e 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -52,6 +52,7 @@ enum iio_chan_type { IIO_COLORTEMP, IIO_CHROMATICITY, IIO_ATTENTION, + IIO_ALTCURRENT, }; enum iio_modifier { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index eab7b082f19d..d26aff649f3f 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -64,6 +64,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_COLORTEMP] = "colortemp", [IIO_CHROMATICITY] = "chromaticity", [IIO_ATTENTION] = "attention", + [IIO_ALTCURRENT] = "altcurrent", }; static const char * const iio_ev_type_text[] = { @@ -187,6 +188,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_COLORTEMP: case IIO_CHROMATICITY: case IIO_ATTENTION: + case IIO_ALTCURRENT: break; default: return false; From 70da02061499ca89ab92f7c4310f815d5fe674ec Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 8 Sep 2025 07:35:22 +0000 Subject: [PATCH 1388/2711] iio: add power and energy measurement modifiers Add new IIO modifiers to support power and energy measurement devices: Power modifiers: - IIO_MOD_ACTIVE: Real power consumed by the load - IIO_MOD_REACTIVE: Power that oscillates between source and load - IIO_MOD_APPARENT: Magnitude of complex power Signal quality modifiers: - IIO_MOD_RMS: Root Mean Square value Additionally adds: - IIO_CHAN_INFO_POWERFACTOR: Power factor channel info type for representing the ratio of active power to apparent power These modifiers enable proper representation of power measurement devices like energy meters and power analyzers. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 29 +++++++++++++++++++++++++ drivers/iio/industrialio-core.c | 5 +++++ include/linux/iio/types.h | 1 + include/uapi/linux/iio/types.h | 4 ++++ tools/iio/iio_event_monitor.c | 8 +++++++ 5 files changed, 47 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 2fb2cea4b192..78da68826307 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -167,7 +167,18 @@ Description: is required is a consistent labeling. Units after application of scale and offset are millivolts. +What: /sys/bus/iio/devices/iio:deviceX/in_altvoltageY_rms_raw +KernelVersion: 6.18 +Contact: linux-iio@vger.kernel.org +Description: + Raw (unscaled) Root Mean Square (RMS) voltage measurement from + channel Y. Units after application of scale and offset are + millivolts. + What: /sys/bus/iio/devices/iio:deviceX/in_powerY_raw +What: /sys/bus/iio/devices/iio:deviceX/in_powerY_active_raw +What: /sys/bus/iio/devices/iio:deviceX/in_powerY_reactive_raw +What: /sys/bus/iio/devices/iio:deviceX/in_powerY_apparent_raw KernelVersion: 4.5 Contact: linux-iio@vger.kernel.org Description: @@ -176,6 +187,13 @@ Description: unique to allow association with event codes. Units after application of scale and offset are milliwatts. +What: /sys/bus/iio/devices/iio:deviceX/in_powerY_powerfactor +KernelVersion: 6.18 +Contact: linux-iio@vger.kernel.org +Description: + Power factor measurement from channel Y. Power factor is the + ratio of active power to apparent power. The value is unitless. + What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw KernelVersion: 3.2 Contact: linux-iio@vger.kernel.org @@ -1569,6 +1587,9 @@ Description: What: /sys/.../iio:deviceX/in_energy_input What: /sys/.../iio:deviceX/in_energy_raw +What: /sys/.../iio:deviceX/in_energyY_active_raw +What: /sys/.../iio:deviceX/in_energyY_reactive_raw +What: /sys/.../iio:deviceX/in_energyY_apparent_raw KernelVersion: 4.0 Contact: linux-iio@vger.kernel.org Description: @@ -1707,6 +1728,14 @@ Description: component of the signal while the 'q' channel contains the quadrature component. +What: /sys/bus/iio/devices/iio:deviceX/in_altcurrentY_rms_raw +KernelVersion: 6.18 +Contact: linux-iio@vger.kernel.org +Description: + Raw (unscaled no bias removal etc.) Root Mean Square (RMS) current + measurement from channel Y. Units after application of scale and + offset are milliamps. + What: /sys/.../iio:deviceX/in_energy_en What: /sys/.../iio:deviceX/in_distance_en What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_en diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 4ff2c44f9324..88c3d585a1bd 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -153,6 +153,10 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_PITCH] = "pitch", [IIO_MOD_YAW] = "yaw", [IIO_MOD_ROLL] = "roll", + [IIO_MOD_RMS] = "rms", + [IIO_MOD_ACTIVE] = "active", + [IIO_MOD_REACTIVE] = "reactive", + [IIO_MOD_APPARENT] = "apparent", }; /* relies on pairs of these shared then separate */ @@ -190,6 +194,7 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_ZEROPOINT] = "zeropoint", [IIO_CHAN_INFO_TROUGH] = "trough_raw", [IIO_CHAN_INFO_CONVDELAY] = "convdelay", + [IIO_CHAN_INFO_POWERFACTOR] = "powerfactor", }; /** * iio_device_id() - query the unique ID for the device diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index ad2761efcc83..34eebad12d2c 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -70,6 +70,7 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_ZEROPOINT, IIO_CHAN_INFO_TROUGH, IIO_CHAN_INFO_CONVDELAY, + IIO_CHAN_INFO_POWERFACTOR, }; #endif /* _IIO_TYPES_H_ */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 3c3cc1497a1e..6d269b844271 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -109,6 +109,10 @@ enum iio_modifier { IIO_MOD_ROLL, IIO_MOD_LIGHT_UVA, IIO_MOD_LIGHT_UVB, + IIO_MOD_RMS, + IIO_MOD_ACTIVE, + IIO_MOD_REACTIVE, + IIO_MOD_APPARENT, }; enum iio_event_type { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index d26aff649f3f..03ca33869ce8 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -141,6 +141,10 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_PITCH] = "pitch", [IIO_MOD_YAW] = "yaw", [IIO_MOD_ROLL] = "roll", + [IIO_MOD_RMS] = "rms", + [IIO_MOD_ACTIVE] = "active", + [IIO_MOD_REACTIVE] = "reactive", + [IIO_MOD_APPARENT] = "apparent", }; static bool event_is_known(struct iio_event_data *event) @@ -240,6 +244,10 @@ static bool event_is_known(struct iio_event_data *event) case IIO_MOD_PM4: case IIO_MOD_PM10: case IIO_MOD_O2: + case IIO_MOD_RMS: + case IIO_MOD_ACTIVE: + case IIO_MOD_REACTIVE: + case IIO_MOD_APPARENT: break; default: return false; From a29d1137efd9c20b6801caf14f3b7a1053e75839 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 8 Sep 2025 07:35:23 +0000 Subject: [PATCH 1389/2711] dt-bindings: iio: adc: add ade9000 Add devicetree bindings support for ade9000. Signed-off-by: Antoniu Miclaus Reviewed-by: Conor Dooley Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ade9000.yaml | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml new file mode 100644 index 000000000000..bd429552d568 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2025 Analog Devices Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ade9000.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADE9000 High Performance, Polyphase Energy Metering + +maintainers: + - Antoniu Miclaus + +description: | + The ADE9000 is a highly accurate, fully integrated, multiphase energy and power + quality monitoring device. Superior analog performance and a digital signal + processing (DSP) core enable accurate energy monitoring over a wide dynamic + range. An integrated high end reference ensures low drift over temperature + with a combined drift of less than ±25 ppm/°C maximum for the entire channel + including a programmable gain amplifier (PGA) and an analog-to-digital + converter (ADC). + + https://www.analog.com/media/en/technical-documentation/data-sheets/ADE9000.pdf + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - adi,ade9000 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 20000000 + + interrupts: + maxItems: 3 + + interrupt-names: + items: + enum: [irq0, irq1, dready] + minItems: 1 + maxItems: 3 + + reset-gpios: + description: + Must be the device tree identifier of the RESET pin. As the line is + active low, it should be marked GPIO_ACTIVE_LOW. + maxItems: 1 + + vdd-supply: true + + vref-supply: true + + clocks: + description: External clock source when not using crystal + maxItems: 1 + + + "#clock-cells": + description: + ADE9000 can provide clock output via CLKOUT pin with external buffer. + const: 0 + +required: + - compatible + - reg + - vdd-supply + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ade9000"; + reg = <0>; + spi-max-frequency = <7000000>; + + #clock-cells = <0>; + reset-gpios = <&gpio 4 GPIO_ACTIVE_LOW>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>, <3 IRQ_TYPE_EDGE_FALLING>, <4 IRQ_TYPE_EDGE_FALLING>; + interrupt-names = "irq0", "irq1", "dready"; + interrupt-parent = <&gpio>; + clocks = <&ext_clock_24576khz>; + vdd-supply = <&vdd_reg>; + }; + }; From 81de7b4619fc3682a3bedaa7e8d6b2d67ab4e10a Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 8 Sep 2025 07:35:24 +0000 Subject: [PATCH 1390/2711] iio: adc: add ade9000 support Add driver support for the ade9000. highly accurate, fully integrated, multiphase energy and power quality monitoring device. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 19 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ade9000.c | 1799 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1819 insertions(+) create mode 100644 drivers/iio/adc/ade9000.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 99f8d6478199..09ab25c8cfdb 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -508,6 +508,25 @@ config AD9467 To compile this driver as a module, choose M here: the module will be called ad9467. +config ADE9000 + tristate "Analog Devices ADE9000 Multiphase Energy, and Power Quality Monitoring IC Driver" + depends on SPI + select REGMAP_SPI + select IIO_BUFFER + select IIO_KFIFO_BUF + help + Say yes here to build support for the Analog Devices ADE9000, + a highly accurate, multiphase energy and power quality monitoring + integrated circuit. + + The device features high-precision analog-to-digital converters + and digital signal processing to compute RMS values, power factor, + frequency, and harmonic analysis. It supports SPI communication + and provides buffered data output through the IIO framework. + + To compile this driver as a module, choose M here: the module will + be called ade9000. + config ADI_AXI_ADC tristate "Analog Devices Generic AXI ADC IP core driver" depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 89d72bf9ce70..4d071f290911 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_AD7944) += ad7944.o obj-$(CONFIG_AD7949) += ad7949.o obj-$(CONFIG_AD799X) += ad799x.o obj-$(CONFIG_AD9467) += ad9467.o +obj-$(CONFIG_ADE9000) += ade9000.o obj-$(CONFIG_ADI_AXI_ADC) += adi-axi-adc.o obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o obj-$(CONFIG_AT91_ADC) += at91_adc.o diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c new file mode 100644 index 000000000000..94e05e11abd9 --- /dev/null +++ b/drivers/iio/adc/ade9000.c @@ -0,0 +1,1799 @@ +// SPDX-License-Identifier: GPL-2.0-only +/** + * ADE9000 driver + * + * Copyright 2025 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Address of ADE9000 registers */ +#define ADE9000_REG_AIGAIN 0x000 +#define ADE9000_REG_AVGAIN 0x00B +#define ADE9000_REG_AIRMSOS 0x00C +#define ADE9000_REG_AVRMSOS 0x00D +#define ADE9000_REG_APGAIN 0x00E +#define ADE9000_REG_AWATTOS 0x00F +#define ADE9000_REG_AVAROS 0x010 +#define ADE9000_REG_AFVAROS 0x012 +#define ADE9000_REG_CONFIG0 0x060 +#define ADE9000_REG_DICOEFF 0x072 +#define ADE9000_REG_AI_PCF 0x20A +#define ADE9000_REG_AV_PCF 0x20B +#define ADE9000_REG_AIRMS 0x20C +#define ADE9000_REG_AVRMS 0x20D +#define ADE9000_REG_AWATT 0x210 +#define ADE9000_REG_AVAR 0x211 +#define ADE9000_REG_AVA 0x212 +#define ADE9000_REG_AFVAR 0x214 +#define ADE9000_REG_APF 0x216 +#define ADE9000_REG_BI_PCF 0x22A +#define ADE9000_REG_BV_PCF 0x22B +#define ADE9000_REG_BIRMS 0x22C +#define ADE9000_REG_BVRMS 0x22D +#define ADE9000_REG_CI_PCF 0x24A +#define ADE9000_REG_CV_PCF 0x24B +#define ADE9000_REG_CIRMS 0x24C +#define ADE9000_REG_CVRMS 0x24D +#define ADE9000_REG_AWATT_ACC 0x2E5 +#define ADE9000_REG_AWATTHR_LO 0x2E6 +#define ADE9000_REG_AVAHR_LO 0x2FA +#define ADE9000_REG_AFVARHR_LO 0x30E +#define ADE9000_REG_BWATTHR_LO 0x322 +#define ADE9000_REG_BVAHR_LO 0x336 +#define ADE9000_REG_BFVARHR_LO 0x34A +#define ADE9000_REG_CWATTHR_LO 0x35E +#define ADE9000_REG_CVAHR_LO 0x372 +#define ADE9000_REG_CFVARHR_LO 0x386 +#define ADE9000_REG_STATUS0 0x402 +#define ADE9000_REG_STATUS1 0x403 +#define ADE9000_REG_MASK0 0x405 +#define ADE9000_REG_MASK1 0x406 +#define ADE9000_REG_EVENT_MASK 0x407 +#define ADE9000_REG_VLEVEL 0x40F +#define ADE9000_REG_DIP_LVL 0x410 +#define ADE9000_REG_DIPA 0x411 +#define ADE9000_REG_DIPB 0x412 +#define ADE9000_REG_DIPC 0x413 +#define ADE9000_REG_SWELL_LVL 0x414 +#define ADE9000_REG_SWELLA 0x415 +#define ADE9000_REG_SWELLB 0x416 +#define ADE9000_REG_SWELLC 0x417 +#define ADE9000_REG_APERIOD 0x418 +#define ADE9000_REG_BPERIOD 0x419 +#define ADE9000_REG_CPERIOD 0x41A +#define ADE9000_REG_RUN 0x480 +#define ADE9000_REG_CONFIG1 0x481 +#define ADE9000_REG_ACCMODE 0x492 +#define ADE9000_REG_CONFIG3 0x493 +#define ADE9000_REG_ZXTOUT 0x498 +#define ADE9000_REG_ZX_LP_SEL 0x49A +#define ADE9000_REG_WFB_CFG 0x4A0 +#define ADE9000_REG_WFB_PG_IRQEN 0x4A1 +#define ADE9000_REG_WFB_TRG_CFG 0x4A2 +#define ADE9000_REG_WFB_TRG_STAT 0x4A3 +#define ADE9000_REG_CONFIG2 0x4AF +#define ADE9000_REG_EP_CFG 0x4B0 +#define ADE9000_REG_EGY_TIME 0x4B2 +#define ADE9000_REG_PGA_GAIN 0x4B9 +#define ADE9000_REG_VERSION 0x4FE +#define ADE9000_REG_WF_BUFF 0x800 +#define ADE9000_REG_WF_HALF_BUFF 0xC00 + +#define ADE9000_REG_ADDR_MASK GENMASK(15, 4) +#define ADE9000_REG_READ_BIT_MASK BIT(3) + +#define ADE9000_WF_CAP_EN_MASK BIT(4) +#define ADE9000_WF_CAP_SEL_MASK BIT(5) +#define ADE9000_WF_MODE_MASK GENMASK(7, 6) +#define ADE9000_WF_SRC_MASK GENMASK(9, 8) +#define ADE9000_WF_IN_EN_MASK BIT(12) + +/* External reference selection bit in CONFIG1 */ +#define ADE9000_EXT_REF_MASK BIT(15) + +/* + * Configuration registers + */ +#define ADE9000_PGA_GAIN 0x0000 + +/* Default configuration */ + +#define ADE9000_CONFIG0 0x00000000 + +/* CF3/ZX pin outputs Zero crossing, CF4 = DREADY */ +#define ADE9000_CONFIG1 0x000E + +/* Default High pass corner frequency of 1.25Hz */ +#define ADE9000_CONFIG2 0x0A00 + +/* Peak and overcurrent detection disabled */ +#define ADE9000_CONFIG3 0x0000 + +/* + * 50Hz operation, 3P4W Wye configuration, signed accumulation + * 3P4W Wye = 3-Phase 4-Wire star configuration (3 phases + neutral wire) + * Clear bit 8 i.e. ACCMODE=0x00xx for 50Hz operation + * ACCMODE=0x0x9x for 3Wire delta when phase B is used as reference + * 3Wire delta = 3-Phase 3-Wire triangle configuration (3 phases, no neutral) + */ +#define ADE9000_ACCMODE 0x0000 +#define ADE9000_ACCMODE_60HZ 0x0100 + +/*Line period and zero crossing obtained from VA */ +#define ADE9000_ZX_LP_SEL 0x0000 + +/* Interrupt mask values for initialization */ +#define ADE9000_MASK0_ALL_INT_DIS 0 +#define ADE9000_MASK1_ALL_INT_DIS 0x00000000 + +/* Events disabled */ +#define ADE9000_EVENT_DISABLE 0x00000000 + +/* + * Assuming Vnom=1/2 of full scale. + * Refer to Technical reference manual for detailed calculations. + */ +#define ADE9000_VLEVEL 0x0022EA28 + +/* Set DICOEFF= 0xFFFFE000 when integrator is enabled */ +#define ADE9000_DICOEFF 0x00000000 + +/* DSP ON */ +#define ADE9000_RUN_ON 0xFFFFFFFF + +/* + * Energy Accumulation Settings + * Enable energy accumulation, accumulate samples at 8ksps + * latch energy accumulation after EGYRDY + * If accumulation is changed to half line cycle mode, change EGY_TIME + */ +#define ADE9000_EP_CFG 0x0011 + +/* Accumulate 4000 samples */ +#define ADE9000_EGY_TIME 7999 + +/* + * Constant Definitions + * ADE9000 FDSP: 8000sps, ADE9000 FDSP: 4000sps + */ +#define ADE9000_FDSP 4000 +#define ADE9000_DEFAULT_CLK_FREQ_HZ 24576000 +#define ADE9000_WFB_CFG 0x03E9 +#define ADE9000_WFB_PAGE_SIZE 128 +#define ADE9000_WFB_NR_OF_PAGES 16 +#define ADE9000_WFB_MAX_CHANNELS 8 +#define ADE9000_WFB_BYTES_IN_SAMPLE 4 +#define ADE9000_WFB_SAMPLES_IN_PAGE \ + (ADE9000_WFB_PAGE_SIZE / ADE9000_WFB_MAX_CHANNELS) +#define ADE9000_WFB_MAX_SAMPLES_CHAN \ + (ADE9000_WFB_SAMPLES_IN_PAGE * ADE9000_WFB_NR_OF_PAGES) +#define ADE9000_WFB_FULL_BUFF_NR_SAMPLES \ + (ADE9000_WFB_PAGE_SIZE * ADE9000_WFB_NR_OF_PAGES) +#define ADE9000_WFB_FULL_BUFF_SIZE \ + (ADE9000_WFB_FULL_BUFF_NR_SAMPLES * ADE9000_WFB_BYTES_IN_SAMPLE) + +#define ADE9000_SWRST_BIT BIT(0) + +/* Status and Mask register bits*/ +#define ADE9000_ST0_WFB_TRIG_BIT BIT(16) +#define ADE9000_ST0_PAGE_FULL_BIT BIT(17) +#define ADE9000_ST0_EGYRDY BIT(0) + +#define ADE9000_ST1_ZXTOVA_BIT BIT(6) +#define ADE9000_ST1_ZXTOVB_BIT BIT(7) +#define ADE9000_ST1_ZXTOVC_BIT BIT(8) +#define ADE9000_ST1_ZXVA_BIT BIT(9) +#define ADE9000_ST1_ZXVB_BIT BIT(10) +#define ADE9000_ST1_ZXVC_BIT BIT(11) +#define ADE9000_ST1_ZXIA_BIT BIT(13) +#define ADE9000_ST1_ZXIB_BIT BIT(14) +#define ADE9000_ST1_ZXIC_BIT BIT(15) +#define ADE9000_ST1_RSTDONE_BIT BIT(16) +#define ADE9000_ST1_SEQERR_BIT BIT(18) +#define ADE9000_ST1_SWELLA_BIT BIT(20) +#define ADE9000_ST1_SWELLB_BIT BIT(21) +#define ADE9000_ST1_SWELLC_BIT BIT(22) +#define ADE9000_ST1_DIPA_BIT BIT(23) +#define ADE9000_ST1_DIPB_BIT BIT(24) +#define ADE9000_ST1_DIPC_BIT BIT(25) +#define ADE9000_ST1_ERROR0_BIT BIT(28) +#define ADE9000_ST1_ERROR1_BIT BIT(29) +#define ADE9000_ST1_ERROR2_BIT BIT(30) +#define ADE9000_ST1_ERROR3_BIT BIT(31) +#define ADE9000_ST_ERROR \ + (ADE9000_ST1_ERROR0 | ADE9000_ST1_ERROR1 | \ + ADE9000_ST1_ERROR2 | ADE9000_ST1_ERROR3) +#define ADE9000_ST1_CROSSING_FIRST 6 +#define ADE9000_ST1_CROSSING_DEPTH 25 + +#define ADE9000_WFB_TRG_DIP_BIT BIT(0) +#define ADE9000_WFB_TRG_SWELL_BIT BIT(1) +#define ADE9000_WFB_TRG_ZXIA_BIT BIT(3) +#define ADE9000_WFB_TRG_ZXIB_BIT BIT(4) +#define ADE9000_WFB_TRG_ZXIC_BIT BIT(5) +#define ADE9000_WFB_TRG_ZXVA_BIT BIT(6) +#define ADE9000_WFB_TRG_ZXVB_BIT BIT(7) +#define ADE9000_WFB_TRG_ZXVC_BIT BIT(8) + +/* Stop when waveform buffer is full */ +#define ADE9000_WFB_FULL_MODE 0x0 +/* Continuous fill—stop only on enabled trigger events */ +#define ADE9000_WFB_EN_TRIG_MODE 0x1 +/* Continuous filling—center capture around enabled trigger events */ +#define ADE9000_WFB_C_EN_TRIG_MODE 0x2 +/* Continuous fill—used as streaming mode for continuous data output */ +#define ADE9000_WFB_STREAMING_MODE 0x3 + +#define ADE9000_LAST_PAGE_BIT BIT(15) +#define ADE9000_MIDDLE_PAGE_BIT BIT(7) + +/* + * Full scale Codes referred from Datasheet. Respective digital codes are + * produced when ADC inputs are at full scale. + */ +#define ADE9000_RMS_FULL_SCALE_CODES 52866837 +#define ADE9000_WATT_FULL_SCALE_CODES 20694066 +#define ADE9000_PCF_FULL_SCALE_CODES 74770000 + +/* Phase and channel definitions */ +#define ADE9000_PHASE_A_NR 0 +#define ADE9000_PHASE_B_NR 1 +#define ADE9000_PHASE_C_NR 2 + +#define ADE9000_SCAN_POS_IA BIT(0) +#define ADE9000_SCAN_POS_VA BIT(1) +#define ADE9000_SCAN_POS_IB BIT(2) +#define ADE9000_SCAN_POS_VB BIT(3) +#define ADE9000_SCAN_POS_IC BIT(4) +#define ADE9000_SCAN_POS_VC BIT(5) + +/* Waveform buffer configuration values */ +enum ade9000_wfb_cfg { + ADE9000_WFB_CFG_ALL_CHAN = 0x0, + ADE9000_WFB_CFG_IA_VA = 0x1, + ADE9000_WFB_CFG_IB_VB = 0x2, + ADE9000_WFB_CFG_IC_VC = 0x3, + ADE9000_WFB_CFG_IA = 0x8, + ADE9000_WFB_CFG_VA = 0x9, + ADE9000_WFB_CFG_IB = 0xA, + ADE9000_WFB_CFG_VB = 0xB, + ADE9000_WFB_CFG_IC = 0xC, + ADE9000_WFB_CFG_VC = 0xD, +}; + +#define ADE9000_PHASE_B_POS_BIT BIT(5) +#define ADE9000_PHASE_C_POS_BIT BIT(6) + +#define ADE9000_MAX_PHASE_NR 3 +#define AD9000_CHANNELS_PER_PHASE 10 + +/* + * Calculate register address for multi-phase device. + * Phase A (chan 0): base address + 0x00 + * Phase B (chan 1): base address + 0x20 + * Phase C (chan 2): base address + 0x40 + */ +#define ADE9000_ADDR_ADJUST(addr, chan) \ + (((chan) == 0 ? 0 : (chan) == 1 ? 2 : 4) << 4 | (addr)) + +struct ade9000_state { + struct completion reset_completion; + struct mutex lock; /* Protects SPI transactions */ + u8 wf_src; + u32 wfb_trg; + u8 wfb_nr_activ_chan; + u32 wfb_nr_samples; + struct spi_device *spi; + struct clk *clkin; + struct spi_transfer xfer[2]; + struct spi_message spi_msg; + struct regmap *regmap; + union{ + u8 byte[ADE9000_WFB_FULL_BUFF_SIZE]; + __be32 word[ADE9000_WFB_FULL_BUFF_NR_SAMPLES]; + } rx_buff __aligned(IIO_DMA_MINALIGN); + u8 tx_buff[2] __aligned(IIO_DMA_MINALIGN); + unsigned int bulk_read_buf[2]; +}; + +struct ade9000_irq1_event { + u32 bit_mask; + enum iio_chan_type chan_type; + u32 channel; + enum iio_event_type event_type; + enum iio_event_direction event_dir; +}; + +static const struct ade9000_irq1_event ade9000_irq1_events[] = { + { ADE9000_ST1_ZXVA_BIT, IIO_VOLTAGE, ADE9000_PHASE_A_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_ZXIA_BIT, IIO_CURRENT, ADE9000_PHASE_A_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_ZXVB_BIT, IIO_VOLTAGE, ADE9000_PHASE_B_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_ZXIB_BIT, IIO_CURRENT, ADE9000_PHASE_B_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_ZXVC_BIT, IIO_VOLTAGE, ADE9000_PHASE_C_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_ZXIC_BIT, IIO_CURRENT, ADE9000_PHASE_C_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER }, + { ADE9000_ST1_SWELLA_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_A_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING }, + { ADE9000_ST1_SWELLB_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_B_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING }, + { ADE9000_ST1_SWELLC_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_C_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING }, + { ADE9000_ST1_DIPA_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_A_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING }, + { ADE9000_ST1_DIPB_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_B_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING }, + { ADE9000_ST1_DIPC_BIT, IIO_ALTVOLTAGE, ADE9000_PHASE_C_NR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING }, +}; + +/* Voltage events (zero crossing on instantaneous voltage) */ +static const struct iio_event_spec ade9000_voltage_events[] = { + { + /* Zero crossing detection - datasheet: ZXV interrupts */ + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + }, +}; + +/* Current events (zero crossing on instantaneous current) */ +static const struct iio_event_spec ade9000_current_events[] = { + { + /* Zero crossing detection - datasheet: ZXI interrupts */ + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + }, +}; + +/* RMS voltage events (swell/sag detection on RMS values) */ +static const struct iio_event_spec ade9000_rms_voltage_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, /* RMS swell detection */ + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, /* RMS sag/dip detection */ + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE), + }, +}; + +static const char * const ade9000_filter_type_items[] = { + "sinc4", "sinc4+lp", +}; + +static const int ade9000_filter_type_values[] = { + 0, 2, +}; + +static int ade9000_filter_type_get(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ade9000_state *st = iio_priv(indio_dev); + u32 val; + int ret; + unsigned int i; + + ret = regmap_read(st->regmap, ADE9000_REG_WFB_CFG, &val); + if (ret) + return ret; + + val = FIELD_GET(ADE9000_WF_SRC_MASK, val); + + for (i = 0; i < ARRAY_SIZE(ade9000_filter_type_values); i++) { + if (ade9000_filter_type_values[i] == val) + return i; + } + + return -EINVAL; +} + +static int ade9000_filter_type_set(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int index) +{ + struct ade9000_state *st = iio_priv(indio_dev); + int ret, val; + + if (index >= ARRAY_SIZE(ade9000_filter_type_values)) + return -EINVAL; + + val = ade9000_filter_type_values[index]; + + /* Update the WFB_CFG register with the new filter type */ + ret = regmap_update_bits(st->regmap, ADE9000_REG_WFB_CFG, + ADE9000_WF_SRC_MASK, + FIELD_PREP(ADE9000_WF_SRC_MASK, val)); + if (ret) + return ret; + + /* Update cached value */ + st->wf_src = val; + + return 0; +} + +static const struct iio_enum ade9000_filter_type_enum = { + .items = ade9000_filter_type_items, + .num_items = ARRAY_SIZE(ade9000_filter_type_items), + .get = ade9000_filter_type_get, + .set = ade9000_filter_type_set, +}; + +static const struct iio_chan_spec_ext_info ade9000_ext_info[] = { + IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ade9000_filter_type_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL, &ade9000_filter_type_enum), + { } +}; + +#define ADE9000_CURRENT_CHANNEL(num) { \ + .type = IIO_CURRENT, \ + .channel = num, \ + .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AI_PCF, num), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBSCALE), \ + .event_spec = ade9000_current_events, \ + .num_event_specs = ARRAY_SIZE(ade9000_current_events), \ + .scan_index = num, \ + .indexed = 1, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 32, \ + .storagebits = 32, \ + .endianness = IIO_BE, \ + }, \ +} + +#define ADE9000_VOLTAGE_CHANNEL(num) { \ + .type = IIO_VOLTAGE, \ + .channel = num, \ + .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AV_PCF, num), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_FREQUENCY), \ + .event_spec = ade9000_voltage_events, \ + .num_event_specs = ARRAY_SIZE(ade9000_voltage_events), \ + .scan_index = num + 1, /* interleave with current channels */ \ + .indexed = 1, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 32, \ + .storagebits = 32, \ + .endianness = IIO_BE, \ + }, \ + .ext_info = ade9000_ext_info, \ +} + +#define ADE9000_ALTCURRENT_RMS_CHANNEL(num) { \ + .type = IIO_ALTCURRENT, \ + .channel = num, \ + .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AIRMS, num), \ + .channel2 = IIO_MOD_RMS, \ + .modified = 1, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .scan_index = -1 \ +} + +#define ADE9000_ALTVOLTAGE_RMS_CHANNEL(num) { \ + .type = IIO_ALTVOLTAGE, \ + .channel = num, \ + .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AVRMS, num), \ + .channel2 = IIO_MOD_RMS, \ + .modified = 1, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .event_spec = ade9000_rms_voltage_events, \ + .num_event_specs = ARRAY_SIZE(ade9000_rms_voltage_events), \ + .scan_index = -1 \ +} + +#define ADE9000_POWER_ACTIVE_CHANNEL(num) { \ + .type = IIO_POWER, \ + .channel = num, \ + .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AWATT, num), \ + .channel2 = IIO_MOD_ACTIVE, \ + .modified = 1, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS) | \ + BIT(IIO_CHAN_INFO_CALIBSCALE), \ + .scan_index = -1 \ +} + +#define ADE9000_POWER_REACTIVE_CHANNEL(num) { \ + .type = IIO_POWER, \ + .channel = num, \ + .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AVAR, num), \ + .channel2 = IIO_MOD_REACTIVE, \ + .modified = 1, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .scan_index = -1 \ +} + +#define ADE9000_POWER_APPARENT_CHANNEL(num) { \ + .type = IIO_POWER, \ + .channel = num, \ + .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AVA, num), \ + .channel2 = IIO_MOD_APPARENT, \ + .modified = 1, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = -1 \ +} + + #define ADE9000_ENERGY_ACTIVE_CHANNEL(num, addr) { \ + .type = IIO_ENERGY, \ + .channel = num, \ + .address = addr, \ + .channel2 = IIO_MOD_ACTIVE, \ + .modified = 1, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_index = -1 \ +} + +#define ADE9000_ENERGY_APPARENT_CHANNEL(num, addr) { \ + .type = IIO_ENERGY, \ + .channel = num, \ + .address = addr, \ + .channel2 = IIO_MOD_APPARENT, \ + .modified = 1, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_index = -1 \ +} + +#define ADE9000_ENERGY_REACTIVE_CHANNEL(num, addr) { \ + .type = IIO_ENERGY, \ + .channel = num, \ + .address = addr, \ + .channel2 = IIO_MOD_REACTIVE, \ + .modified = 1, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_index = -1 \ +} + +#define ADE9000_POWER_FACTOR_CHANNEL(num) { \ + .type = IIO_POWER, \ + .channel = num, \ + .address = ADE9000_ADDR_ADJUST(ADE9000_REG_APF, num), \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_POWERFACTOR), \ + .scan_index = -1 \ +} + +static const struct iio_chan_spec ade9000_channels[] = { + /* Phase A channels */ + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_A_NR), + ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AWATTHR_LO), + ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AVAHR_LO), + ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AFVARHR_LO), + ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_A_NR), + /* Phase B channels */ + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_B_NR), + ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BWATTHR_LO), + ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BVAHR_LO), + ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BFVARHR_LO), + ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_B_NR), + /* Phase C channels */ + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_C_NR), + ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CWATTHR_LO), + ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CVAHR_LO), + ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CFVARHR_LO), + ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_C_NR), +}; + +static const struct reg_sequence ade9000_initialization_sequence[] = { + { ADE9000_REG_PGA_GAIN, ADE9000_PGA_GAIN }, + { ADE9000_REG_CONFIG0, ADE9000_CONFIG0 }, + { ADE9000_REG_CONFIG1, ADE9000_CONFIG1 }, + { ADE9000_REG_CONFIG2, ADE9000_CONFIG2 }, + { ADE9000_REG_CONFIG3, ADE9000_CONFIG3 }, + { ADE9000_REG_ACCMODE, ADE9000_ACCMODE }, + { ADE9000_REG_ZX_LP_SEL, ADE9000_ZX_LP_SEL }, + { ADE9000_REG_MASK0, ADE9000_MASK0_ALL_INT_DIS }, + { ADE9000_REG_MASK1, ADE9000_MASK1_ALL_INT_DIS }, + { ADE9000_REG_EVENT_MASK, ADE9000_EVENT_DISABLE }, + { ADE9000_REG_WFB_CFG, ADE9000_WFB_CFG }, + { ADE9000_REG_VLEVEL, ADE9000_VLEVEL }, + { ADE9000_REG_DICOEFF, ADE9000_DICOEFF }, + { ADE9000_REG_EGY_TIME, ADE9000_EGY_TIME }, + { ADE9000_REG_EP_CFG, ADE9000_EP_CFG }, + /* Clear all pending status bits by writing 1s */ + { ADE9000_REG_STATUS0, GENMASK(31, 0) }, + { ADE9000_REG_STATUS1, GENMASK(31, 0) }, + { ADE9000_REG_RUN, ADE9000_RUN_ON } +}; + +static int ade9000_spi_write_reg(void *context, unsigned int reg, + unsigned int val) +{ + struct ade9000_state *st = context; + u8 tx_buf[6]; + u16 addr; + int ret, len; + + guard(mutex)(&st->lock); + + addr = FIELD_PREP(ADE9000_REG_ADDR_MASK, reg); + put_unaligned_be16(addr, tx_buf); + + if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION) { + put_unaligned_be16(val, &tx_buf[2]); + len = 4; + } else { + put_unaligned_be32(val, &tx_buf[2]); + len = 6; + } + + ret = spi_write_then_read(st->spi, tx_buf, len, NULL, 0); + if (ret) + dev_err(&st->spi->dev, "problem when writing register 0x%x\n", reg); + + return ret; +} + +static int ade9000_spi_read_reg(void *context, unsigned int reg, + unsigned int *val) +{ + struct ade9000_state *st = context; + u8 tx_buf[2]; + u8 rx_buf[4]; + u16 addr; + int ret, rx_len; + + guard(mutex)(&st->lock); + + addr = FIELD_PREP(ADE9000_REG_ADDR_MASK, reg) | + ADE9000_REG_READ_BIT_MASK; + + put_unaligned_be16(addr, tx_buf); + + /* Skip CRC bytes - only read actual data */ + if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION) + rx_len = 2; + else + rx_len = 4; + + ret = spi_write_then_read(st->spi, tx_buf, 2, rx_buf, rx_len); + if (ret) { + dev_err(&st->spi->dev, "error reading register 0x%x\n", reg); + return ret; + } + + if (reg > ADE9000_REG_RUN && reg < ADE9000_REG_VERSION) + *val = get_unaligned_be16(rx_buf); + else + *val = get_unaligned_be32(rx_buf); + + return 0; +} + +static bool ade9000_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + /* Interrupt/error status registers - volatile */ + case ADE9000_REG_STATUS0: + case ADE9000_REG_STATUS1: + return true; + default: + /* All other registers are non-volatile */ + return false; + } +} + +static void ade9000_configure_scan(struct iio_dev *indio_dev, u32 wfb_addr) +{ + struct ade9000_state *st = iio_priv(indio_dev); + u16 addr; + + addr = FIELD_PREP(ADE9000_REG_ADDR_MASK, wfb_addr) | + ADE9000_REG_READ_BIT_MASK; + + put_unaligned_be16(addr, st->tx_buff); + + st->xfer[0].tx_buf = &st->tx_buff[0]; + st->xfer[0].len = 2; + + st->xfer[1].rx_buf = st->rx_buff.byte; + + /* Always use streaming mode */ + st->xfer[1].len = (st->wfb_nr_samples / 2) * 4; + + spi_message_init_with_transfers(&st->spi_msg, st->xfer, ARRAY_SIZE(st->xfer)); +} + +static int ade9000_iio_push_streaming(struct iio_dev *indio_dev) +{ + struct ade9000_state *st = iio_priv(indio_dev); + struct device *dev = &st->spi->dev; + u32 current_page, i; + int ret; + + guard(mutex)(&st->lock); + + ret = spi_sync(st->spi, &st->spi_msg); + if (ret) { + dev_err_ratelimited(dev, "SPI fail in trigger handler\n"); + return ret; + } + + /* In streaming mode, only half the buffer is filled per interrupt */ + for (i = 0; i < st->wfb_nr_samples / 2; i += st->wfb_nr_activ_chan) + iio_push_to_buffers(indio_dev, &st->rx_buff.word[i]); + + ret = regmap_read(st->regmap, ADE9000_REG_WFB_PG_IRQEN, ¤t_page); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 WFB read fail\n"); + return ret; + } + + if (current_page & ADE9000_MIDDLE_PAGE_BIT) { + ret = regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_LAST_PAGE_BIT); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 WFB write fail\n"); + return ret; + } + + ade9000_configure_scan(indio_dev, + ADE9000_REG_WF_HALF_BUFF); + } else { + ret = regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_MIDDLE_PAGE_BIT); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 WFB write fail"); + return IRQ_HANDLED; + } + + ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF); + } + + return 0; +} + +static int ade9000_iio_push_buffer(struct iio_dev *indio_dev) +{ + struct ade9000_state *st = iio_priv(indio_dev); + int ret; + u32 i; + + guard(mutex)(&st->lock); + + ret = spi_sync(st->spi, &st->spi_msg); + if (ret) { + dev_err_ratelimited(&st->spi->dev, + "SPI fail in trigger handler\n"); + return ret; + } + + for (i = 0; i < st->wfb_nr_samples; i += st->wfb_nr_activ_chan) + iio_push_to_buffers(indio_dev, &st->rx_buff.word[i]); + + return 0; +} + +static irqreturn_t ade9000_irq0_thread(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct ade9000_state *st = iio_priv(indio_dev); + struct device *dev = &st->spi->dev; + u32 handled_irq = 0; + u32 interrupts, status; + int ret; + + ret = regmap_read(st->regmap, ADE9000_REG_STATUS0, &status); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 read status fail\n"); + return IRQ_HANDLED; + } + + ret = regmap_read(st->regmap, ADE9000_REG_MASK0, &interrupts); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 read mask fail\n"); + return IRQ_HANDLED; + } + + if ((status & ADE9000_ST0_PAGE_FULL_BIT) && + (interrupts & ADE9000_ST0_PAGE_FULL_BIT)) { + /* Always use streaming mode */ + ret = ade9000_iio_push_streaming(indio_dev); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 IIO push fail\n"); + return IRQ_HANDLED; + } + + handled_irq |= ADE9000_ST0_PAGE_FULL_BIT; + } + + if ((status & ADE9000_ST0_WFB_TRIG_BIT) && + (interrupts & ADE9000_ST0_WFB_TRIG_BIT)) { + ret = regmap_update_bits(st->regmap, ADE9000_REG_WFB_CFG, + ADE9000_WF_CAP_EN_MASK, 0); + if (ret) { + dev_err_ratelimited(dev, "IRQ0 WFB fail\n"); + return IRQ_HANDLED; + } + + if (iio_buffer_enabled(indio_dev)) { + ret = ade9000_iio_push_buffer(indio_dev); + if (ret) { + dev_err_ratelimited(dev, + "IRQ0 IIO push fail @ WFB TRIG\n"); + return IRQ_HANDLED; + } + } + + handled_irq |= ADE9000_ST0_WFB_TRIG_BIT; + } + + ret = regmap_write(st->regmap, ADE9000_REG_STATUS0, handled_irq); + if (ret) + dev_err_ratelimited(dev, "IRQ0 write status fail\n"); + + return IRQ_HANDLED; +} + +static irqreturn_t ade9000_irq1_thread(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct ade9000_state *st = iio_priv(indio_dev); + unsigned int bit = ADE9000_ST1_CROSSING_FIRST; + s64 timestamp = iio_get_time_ns(indio_dev); + u32 handled_irq = 0; + u32 interrupts, result, status, tmp; + DECLARE_BITMAP(interrupt_bits, ADE9000_ST1_CROSSING_DEPTH); + const struct ade9000_irq1_event *event; + int ret, i; + + if (!completion_done(&st->reset_completion)) { + ret = regmap_read(st->regmap, ADE9000_REG_STATUS1, &result); + if (ret) { + dev_err_ratelimited(&st->spi->dev, "IRQ1 read status fail\n"); + return IRQ_HANDLED; + } + + if (result & ADE9000_ST1_RSTDONE_BIT) { + complete(&st->reset_completion); + /* Clear the reset done status bit */ + ret = regmap_write(st->regmap, ADE9000_REG_STATUS1, ADE9000_ST1_RSTDONE_BIT); + if (ret) + dev_err_ratelimited(&st->spi->dev, + "IRQ1 clear reset status fail\n"); + } else { + dev_err_ratelimited(&st->spi->dev, + "Error testing reset done\n"); + } + + return IRQ_HANDLED; + } + + ret = regmap_read(st->regmap, ADE9000_REG_STATUS1, &status); + if (ret) { + dev_err_ratelimited(&st->spi->dev, "IRQ1 read status fail\n"); + return IRQ_HANDLED; + } + + ret = regmap_read(st->regmap, ADE9000_REG_MASK1, &interrupts); + if (ret) { + dev_err_ratelimited(&st->spi->dev, "IRQ1 read mask fail\n"); + return IRQ_HANDLED; + } + + bitmap_from_arr32(interrupt_bits, &interrupts, ADE9000_ST1_CROSSING_DEPTH); + for_each_set_bit_from(bit, interrupt_bits, + ADE9000_ST1_CROSSING_DEPTH) { + tmp = status & BIT(bit); + if (!tmp) + continue; + + event = NULL; + + /* Find corresponding event in lookup table */ + for (i = 0; i < ARRAY_SIZE(ade9000_irq1_events); i++) { + if (ade9000_irq1_events[i].bit_mask == tmp) { + event = &ade9000_irq1_events[i]; + break; + } + } + + if (event) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(event->chan_type, + event->channel, + event->event_type, + event->event_dir), + timestamp); + } + handled_irq |= tmp; + } + + ret = regmap_write(st->regmap, ADE9000_REG_STATUS1, handled_irq); + if (ret) + dev_err_ratelimited(&st->spi->dev, "IRQ1 write status fail\n"); + + return IRQ_HANDLED; +} + +static irqreturn_t ade9000_dready_thread(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + + /* Handle data ready interrupt from C4/EVENT/DREADY pin */ + if (!iio_device_claim_buffer_mode(indio_dev)) { + ade9000_iio_push_buffer(indio_dev); + iio_device_release_buffer_mode(indio_dev); + } + + return IRQ_HANDLED; +} + +static int ade9000_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct ade9000_state *st = iio_priv(indio_dev); + unsigned int measured; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + if (chan->type == IIO_VOLTAGE) { + int period_reg; + int period; + + switch (chan->channel) { + case ADE9000_PHASE_A_NR: + period_reg = ADE9000_REG_APERIOD; + break; + case ADE9000_PHASE_B_NR: + period_reg = ADE9000_REG_BPERIOD; + break; + case ADE9000_PHASE_C_NR: + period_reg = ADE9000_REG_CPERIOD; + break; + default: + return -EINVAL; + } + ret = regmap_read(st->regmap, period_reg, &period); + if (ret) + return ret; + /* + * Frequency = (4MHz * 65536) / (PERIOD + 1) + * 4MHz = ADC sample rate, 65536 = 2^16 period register scaling + * See ADE9000 datasheet section on period measurement + */ + *val = 4000 * 65536; + *val2 = period + 1; + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; + case IIO_CHAN_INFO_RAW: + if (chan->type == IIO_ENERGY) { + u16 lo_reg = chan->address; + + ret = regmap_bulk_read(st->regmap, lo_reg, + st->bulk_read_buf, 2); + if (ret) + return ret; + + *val = st->bulk_read_buf[0]; /* Lower 32 bits */ + *val2 = st->bulk_read_buf[1]; /* Upper 32 bits */ + return IIO_VAL_INT_64; + } + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_read(st->regmap, chan->address, &measured); + iio_device_release_direct(indio_dev); + if (ret) + return ret; + + *val = measured; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_POWERFACTOR: + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_read(st->regmap, chan->address, &measured); + iio_device_release_direct(indio_dev); + if (ret) + return ret; + + *val = measured; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_CURRENT: + case IIO_VOLTAGE: + case IIO_ALTVOLTAGE: + case IIO_ALTCURRENT: + switch (chan->address) { + case ADE9000_REG_AI_PCF: + case ADE9000_REG_AV_PCF: + case ADE9000_REG_BI_PCF: + case ADE9000_REG_BV_PCF: + case ADE9000_REG_CI_PCF: + case ADE9000_REG_CV_PCF: + *val = 1; + *val2 = ADE9000_PCF_FULL_SCALE_CODES; + return IIO_VAL_FRACTIONAL; + case ADE9000_REG_AIRMS: + case ADE9000_REG_AVRMS: + case ADE9000_REG_BIRMS: + case ADE9000_REG_BVRMS: + case ADE9000_REG_CIRMS: + case ADE9000_REG_CVRMS: + *val = 1; + *val2 = ADE9000_RMS_FULL_SCALE_CODES; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_POWER: + *val = 1; + *val2 = ADE9000_WATT_FULL_SCALE_CODES; + return IIO_VAL_FRACTIONAL; + default: + break; + } + + return -EINVAL; + default: + return -EINVAL; + } +} + +static int ade9000_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct ade9000_state *st = iio_priv(indio_dev); + u32 tmp; + + switch (mask) { + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + case IIO_CURRENT: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AIRMSOS, + chan->channel), val); + case IIO_VOLTAGE: + case IIO_ALTVOLTAGE: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AVRMSOS, + chan->channel), val); + case IIO_POWER: + tmp = chan->address; + tmp &= ~ADE9000_PHASE_B_POS_BIT; + tmp &= ~ADE9000_PHASE_C_POS_BIT; + + switch (tmp) { + case ADE9000_REG_AWATTOS: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AWATTOS, + chan->channel), val); + case ADE9000_REG_AVAR: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AVAROS, + chan->channel), val); + case ADE9000_REG_AFVAR: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AFVAROS, + chan->channel), val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } + case IIO_CHAN_INFO_CALIBSCALE: + /* + * Calibration gain registers for fine-tuning measurements. + * These are separate from PGA gain and applied in the digital domain. + */ + switch (chan->type) { + case IIO_CURRENT: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AIGAIN, + chan->channel), val); + case IIO_VOLTAGE: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_AVGAIN, + chan->channel), val); + case IIO_POWER: + return regmap_write(st->regmap, + ADE9000_ADDR_ADJUST(ADE9000_REG_APGAIN, + chan->channel), val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + /* Per-channel scales are read-only */ + return -EINVAL; + default: + return -EINVAL; + } +} + +static int ade9000_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int tx_val, + unsigned int *rx_val) +{ + struct ade9000_state *st = iio_priv(indio_dev); + + if (rx_val) + return regmap_read(st->regmap, reg, rx_val); + + return regmap_write(st->regmap, reg, tx_val); +} + +static int ade9000_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct ade9000_state *st = iio_priv(indio_dev); + u32 interrupts1; + int ret; + + /* All events use MASK1 register */ + ret = regmap_read(st->regmap, ADE9000_REG_MASK1, &interrupts1); + if (ret) + return ret; + + switch (chan->channel) { + case ADE9000_PHASE_A_NR: + if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXVA_BIT); + else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXIA_BIT); + else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING) + return !!(interrupts1 & ADE9000_ST1_SWELLA_BIT); + else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING) + return !!(interrupts1 & ADE9000_ST1_DIPA_BIT); + dev_err_ratelimited(&indio_dev->dev, + "Invalid channel type %d or direction %d for phase A\n", chan->type, dir); + return -EINVAL; + case ADE9000_PHASE_B_NR: + if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXVB_BIT); + else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXIB_BIT); + else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING) + return !!(interrupts1 & ADE9000_ST1_SWELLB_BIT); + else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING) + return !!(interrupts1 & ADE9000_ST1_DIPB_BIT); + dev_err_ratelimited(&indio_dev->dev, + "Invalid channel type %d or direction %d for phase B\n", chan->type, dir); + return -EINVAL; + case ADE9000_PHASE_C_NR: + if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXVC_BIT); + else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER) + return !!(interrupts1 & ADE9000_ST1_ZXIC_BIT); + else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING) + return !!(interrupts1 & ADE9000_ST1_SWELLC_BIT); + else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING) + return !!(interrupts1 & ADE9000_ST1_DIPC_BIT); + dev_err_ratelimited(&indio_dev->dev, + "Invalid channel type %d or direction %d for phase C\n", chan->type, dir); + return -EINVAL; + default: + return -EINVAL; + } +} + +static int ade9000_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct ade9000_state *st = iio_priv(indio_dev); + u32 bit_mask; + int ret; + + /* Clear all pending events in STATUS1 register (write 1 to clear) */ + ret = regmap_write(st->regmap, ADE9000_REG_STATUS1, GENMASK(31, 0)); + if (ret) + return ret; + + /* Determine which interrupt bit to enable/disable */ + switch (chan->channel) { + case ADE9000_PHASE_A_NR: + if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER) { + bit_mask = ADE9000_ST1_ZXVA_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_ZXVA_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_ZXVA_BIT; + } else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER) { + bit_mask = ADE9000_ST1_ZXIA_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_ZXIA_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_ZXIA_BIT; + } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING) { + bit_mask = ADE9000_ST1_SWELLA_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_SWELL_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_SWELL_BIT; + } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING) { + bit_mask = ADE9000_ST1_DIPA_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_DIP_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_DIP_BIT; + } else { + dev_err_ratelimited(&indio_dev->dev, "Invalid channel type %d or direction %d for phase A\n", + chan->type, dir); + return -EINVAL; + } + break; + case ADE9000_PHASE_B_NR: + if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER) { + bit_mask = ADE9000_ST1_ZXVB_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_ZXVB_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_ZXVB_BIT; + } else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER) { + bit_mask = ADE9000_ST1_ZXIB_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_ZXIB_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_ZXIB_BIT; + } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING) { + bit_mask = ADE9000_ST1_SWELLB_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_SWELL_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_SWELL_BIT; + } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING) { + bit_mask = ADE9000_ST1_DIPB_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_DIP_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_DIP_BIT; + } else { + dev_err_ratelimited(&indio_dev->dev, + "Invalid channel type %d or direction %d for phase B\n", + chan->type, dir); + return -EINVAL; + } + break; + case ADE9000_PHASE_C_NR: + if (chan->type == IIO_VOLTAGE && dir == IIO_EV_DIR_EITHER) { + bit_mask = ADE9000_ST1_ZXVC_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_ZXVC_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_ZXVC_BIT; + } else if (chan->type == IIO_CURRENT && dir == IIO_EV_DIR_EITHER) { + bit_mask = ADE9000_ST1_ZXIC_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_ZXIC_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_ZXIC_BIT; + } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_RISING) { + bit_mask = ADE9000_ST1_SWELLC_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_SWELL_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_SWELL_BIT; + } else if (chan->type == IIO_ALTVOLTAGE && dir == IIO_EV_DIR_FALLING) { + bit_mask = ADE9000_ST1_DIPC_BIT; + if (state) + st->wfb_trg |= ADE9000_WFB_TRG_DIP_BIT; + else + st->wfb_trg &= ~ADE9000_WFB_TRG_DIP_BIT; + } else { + dev_err_ratelimited(&indio_dev->dev, + "Invalid channel type %d or direction %d for phase C\n", + chan->type, dir); + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + /* Set bits if enabling event, clear bits if disabling */ + return regmap_assign_bits(st->regmap, ADE9000_REG_MASK1, bit_mask, state ? bit_mask : 0); +} + +static int ade9000_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct ade9000_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_FALLING: + return regmap_write(st->regmap, ADE9000_REG_DIP_LVL, val); + case IIO_EV_DIR_RISING: + return regmap_write(st->regmap, ADE9000_REG_SWELL_LVL, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ade9000_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct ade9000_state *st = iio_priv(indio_dev); + unsigned int data; + int ret; + + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_FALLING: + ret = regmap_read(st->regmap, ADE9000_REG_DIP_LVL, &data); + if (ret) + return ret; + *val = data; + return IIO_VAL_INT; + case IIO_EV_DIR_RISING: + ret = regmap_read(st->regmap, ADE9000_REG_SWELL_LVL, &data); + if (ret) + return ret; + *val = data; + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ade9000_waveform_buffer_config(struct iio_dev *indio_dev) +{ + struct ade9000_state *st = iio_priv(indio_dev); + u32 wfb_cfg_val; + u32 active_scans; + + bitmap_to_arr32(&active_scans, indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + + switch (active_scans) { + case ADE9000_SCAN_POS_IA | ADE9000_SCAN_POS_VA: + wfb_cfg_val = ADE9000_WFB_CFG_IA_VA; + st->wfb_nr_activ_chan = 2; + break; + case ADE9000_SCAN_POS_IB | ADE9000_SCAN_POS_VB: + wfb_cfg_val = ADE9000_WFB_CFG_IB_VB; + st->wfb_nr_activ_chan = 2; + break; + case ADE9000_SCAN_POS_IC | ADE9000_SCAN_POS_VC: + wfb_cfg_val = ADE9000_WFB_CFG_IC_VC; + st->wfb_nr_activ_chan = 2; + break; + case ADE9000_SCAN_POS_IA: + wfb_cfg_val = ADE9000_WFB_CFG_IA; + st->wfb_nr_activ_chan = 1; + break; + case ADE9000_SCAN_POS_VA: + wfb_cfg_val = ADE9000_WFB_CFG_VA; + st->wfb_nr_activ_chan = 1; + break; + case ADE9000_SCAN_POS_IB: + wfb_cfg_val = ADE9000_WFB_CFG_IB; + st->wfb_nr_activ_chan = 1; + break; + case ADE9000_SCAN_POS_VB: + wfb_cfg_val = ADE9000_WFB_CFG_VB; + st->wfb_nr_activ_chan = 1; + break; + case ADE9000_SCAN_POS_IC: + wfb_cfg_val = ADE9000_WFB_CFG_IC; + st->wfb_nr_activ_chan = 1; + break; + case ADE9000_SCAN_POS_VC: + wfb_cfg_val = ADE9000_WFB_CFG_VC; + st->wfb_nr_activ_chan = 1; + break; + case (ADE9000_SCAN_POS_IA | ADE9000_SCAN_POS_VA | ADE9000_SCAN_POS_IB | + ADE9000_SCAN_POS_VB | ADE9000_SCAN_POS_IC | ADE9000_SCAN_POS_VC): + wfb_cfg_val = ADE9000_WFB_CFG_ALL_CHAN; + st->wfb_nr_activ_chan = 6; + break; + default: + dev_err(&st->spi->dev, "Unsupported combination of scans\n"); + return -EINVAL; + } + + wfb_cfg_val |= FIELD_PREP(ADE9000_WF_SRC_MASK, st->wf_src); + + return regmap_write(st->regmap, ADE9000_REG_WFB_CFG, wfb_cfg_val); +} + +static int ade9000_waveform_buffer_interrupt_setup(struct ade9000_state *st) +{ + int ret; + + ret = regmap_write(st->regmap, ADE9000_REG_WFB_TRG_CFG, 0x0); + if (ret) + return ret; + + /* Always use streaming mode setup */ + ret = regmap_write(st->regmap, ADE9000_REG_WFB_PG_IRQEN, + ADE9000_MIDDLE_PAGE_BIT); + if (ret) + return ret; + + ret = regmap_write(st->regmap, ADE9000_REG_STATUS0, GENMASK(31, 0)); + if (ret) + return ret; + + return regmap_set_bits(st->regmap, ADE9000_REG_MASK0, + ADE9000_ST0_PAGE_FULL_BIT); +} + +static int ade9000_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ade9000_state *st = iio_priv(indio_dev); + int ret; + + ret = ade9000_waveform_buffer_config(indio_dev); + if (ret) + return ret; + + st->wfb_nr_samples = ADE9000_WFB_MAX_SAMPLES_CHAN * st->wfb_nr_activ_chan; + + ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF); + + ret = ade9000_waveform_buffer_interrupt_setup(st); + if (ret) + return ret; + + ret = regmap_set_bits(st->regmap, ADE9000_REG_WFB_CFG, + ADE9000_WF_CAP_EN_MASK); + if (ret) { + dev_err(&st->spi->dev, "Post-enable waveform buffer enable fail\n"); + return ret; + } + + return 0; +} + +static int ade9000_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ade9000_state *st = iio_priv(indio_dev); + struct device *dev = &st->spi->dev; + u32 interrupts; + int ret; + + ret = regmap_clear_bits(st->regmap, ADE9000_REG_WFB_CFG, + ADE9000_WF_CAP_EN_MASK); + if (ret) { + dev_err(dev, "Post-disable waveform buffer disable fail\n"); + return ret; + } + + ret = regmap_write(st->regmap, ADE9000_REG_WFB_TRG_CFG, 0x0); + if (ret) + return ret; + + interrupts = ADE9000_ST0_WFB_TRIG_BIT | ADE9000_ST0_PAGE_FULL_BIT; + + ret = regmap_clear_bits(st->regmap, ADE9000_REG_MASK0, interrupts); + if (ret) { + dev_err(dev, "Post-disable update maks0 fail\n"); + return ret; + } + + return regmap_write(st->regmap, ADE9000_REG_STATUS0, GENMASK(31, 0)); +} + +static const struct iio_buffer_setup_ops ade9000_buffer_ops = { + .preenable = &ade9000_buffer_preenable, + .postdisable = &ade9000_buffer_postdisable, +}; + +static int ade9000_reset(struct ade9000_state *st) +{ + struct device *dev = &st->spi->dev; + struct gpio_desc *gpio_reset; + int ret; + + gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpio_reset)) + return PTR_ERR(gpio_reset); + + /* Software reset via register if no GPIO available */ + if (!gpio_reset) { + ret = regmap_set_bits(st->regmap, ADE9000_REG_CONFIG1, + ADE9000_SWRST_BIT); + if (ret) + return ret; + fsleep(90); + return 0; + } + + /* Hardware reset via GPIO */ + fsleep(10); + gpiod_set_value_cansleep(gpio_reset, 0); + fsleep(50000); + + /* Only wait for completion if IRQ1 is available to signal reset done */ + if (fwnode_irq_get_byname(dev_fwnode(dev), "irq1") >= 0) { + if (!wait_for_completion_timeout(&st->reset_completion, + msecs_to_jiffies(1000))) { + dev_err(dev, "Reset timeout after 1s\n"); + return -ETIMEDOUT; + } + } + /* If no IRQ available, reset is already complete after the 50ms delay above */ + + return 0; +} + +static int ade9000_setup(struct ade9000_state *st) +{ + struct device *dev = &st->spi->dev; + int ret; + + ret = regmap_multi_reg_write(st->regmap, ade9000_initialization_sequence, + ARRAY_SIZE(ade9000_initialization_sequence)); + if (ret) + return dev_err_probe(dev, ret, "Failed to write register sequence"); + + fsleep(2000); + + return 0; +} + +static const struct iio_info ade9000_info = { + .read_raw = ade9000_read_raw, + .write_raw = ade9000_write_raw, + .debugfs_reg_access = ade9000_reg_access, + .write_event_config = ade9000_write_event_config, + .read_event_config = ade9000_read_event_config, + .write_event_value = ade9000_write_event_value, + .read_event_value = ade9000_read_event_value, +}; + +static const struct regmap_config ade9000_regmap_config = { + .reg_bits = 16, + .val_bits = 32, + .max_register = 0x6bc, + .zero_flag_mask = true, + .cache_type = REGCACHE_RBTREE, + .reg_read = ade9000_spi_read_reg, + .reg_write = ade9000_spi_write_reg, + .volatile_reg = ade9000_is_volatile_reg, +}; + +static int ade9000_setup_clkout(struct device *dev, struct ade9000_state *st) +{ + struct clk_hw *clkout_hw; + int ret; + + if (!IS_ENABLED(CONFIG_COMMON_CLK)) + return 0; + + /* + * Only provide clock output when using external CMOS clock. + * When using crystal, CLKOUT is connected to crystal and shouldn't + * be used as clock provider for other devices. + */ + if (!device_property_present(dev, "#clock-cells") || !st->clkin) + return 0; + + /* CLKOUT passes through CLKIN with divider of 1 */ + clkout_hw = devm_clk_hw_register_divider(dev, "clkout", __clk_get_name(st->clkin), + CLK_SET_RATE_PARENT, NULL, 0, 1, 0, NULL); + if (IS_ERR(clkout_hw)) + return dev_err_probe(dev, PTR_ERR(clkout_hw), "Failed to register clkout"); + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, clkout_hw); + if (ret) + return dev_err_probe(dev, ret, "Failed to add clock provider"); + + return 0; +} + +static int ade9000_request_irq(struct device *dev, const char *name, + irq_handler_t handler, void *dev_id) +{ + int irq, ret; + + irq = fwnode_irq_get_byname(dev_fwnode(dev), name); + if (irq == -EINVAL) + return 0; /* interrupts are optional */ + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get %s irq", name); + + ret = devm_request_threaded_irq(dev, irq, NULL, handler, + IRQF_ONESHOT, KBUILD_MODNAME, dev_id); + if (ret) + return dev_err_probe(dev, ret, "Failed to request %s irq", name); + + return 0; +} + +static int ade9000_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct ade9000_state *st; + struct regmap *regmap; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + regmap = devm_regmap_init(dev, NULL, st, &ade9000_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Unable to allocate ADE9000 regmap"); + + st->regmap = regmap; + st->spi = spi; + + init_completion(&st->reset_completion); + + ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev); + if (ret) + return ret; + + ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev); + if (ret) + return ret; + + ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev); + if (ret) + return ret; + + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + /* External CMOS clock input (optional - crystal can be used instead) */ + st->clkin = devm_clk_get_optional_enabled(dev, NULL); + if (IS_ERR(st->clkin)) + return dev_err_probe(dev, PTR_ERR(st->clkin), "Failed to get and enable clkin"); + + ret = ade9000_setup_clkout(dev, st); + if (ret) + return ret; + + indio_dev->name = "ade9000"; + indio_dev->info = &ade9000_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->setup_ops = &ade9000_buffer_ops; + + ret = devm_regulator_get_enable(&spi->dev, "vdd"); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to get and enable vdd regulator\n"); + + indio_dev->channels = ade9000_channels; + indio_dev->num_channels = ARRAY_SIZE(ade9000_channels); + + ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, + &ade9000_buffer_ops); + if (ret) + return dev_err_probe(dev, ret, "Failed to setup IIO buffer"); + + ret = ade9000_reset(st); + if (ret) + return ret; + + /* Configure reference selection if vref regulator is available */ + ret = devm_regulator_get_enable_optional(dev, "vref"); + if (ret != -ENODEV && ret >= 0) { + ret = regmap_set_bits(st->regmap, ADE9000_REG_CONFIG1, + ADE9000_EXT_REF_MASK); + if (ret) + return ret; + } else if (ret < 0 && ret != -ENODEV) { + return dev_err_probe(dev, ret, + "Failed to get and enable vref regulator\n"); + } + + ret = ade9000_setup(st); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +}; + +static const struct spi_device_id ade9000_id[] = { + { "ade9000", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ade9000_id); + +static const struct of_device_id ade9000_of_match[] = { + { .compatible = "adi,ade9000" }, + { } +}; +MODULE_DEVICE_TABLE(of, ade9000_of_match); + +static struct spi_driver ade9000_driver = { + .driver = { + .name = "ade9000", + .of_match_table = ade9000_of_match, + }, + .probe = ade9000_probe, + .id_table = ade9000_id, +}; +module_spi_driver(ade9000_driver); + +MODULE_AUTHOR("Antoniu Miclaus "); +MODULE_DESCRIPTION("Analog Devices ADE9000"); +MODULE_LICENSE("GPL"); From 942ab02bc96f4a03c5221a8855d5fb0d27515e6a Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 8 Sep 2025 07:35:25 +0000 Subject: [PATCH 1391/2711] docs: iio: add documentation for ade9000 driver Add documentation for ade9000 driver which describes the driver device files and shows how the user may use the ABI for various scenarios (configuration, measurement, etc.). Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- Documentation/iio/ade9000.rst | 268 ++++++++++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + 2 files changed, 269 insertions(+) create mode 100644 Documentation/iio/ade9000.rst diff --git a/Documentation/iio/ade9000.rst b/Documentation/iio/ade9000.rst new file mode 100644 index 000000000000..43d4b8dc1cb7 --- /dev/null +++ b/Documentation/iio/ade9000.rst @@ -0,0 +1,268 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============== +ADE9000 driver +=============== + +This driver supports Analog Device's ADE9000 energy measurement IC on SPI bus. + +1. Supported devices +==================== + +* `ADE9000 `_ + +The ADE9000 is a highly accurate, fully integrated, multiphase energy and power +quality monitoring device. Superior analog performance and a digital signal +processing (DSP) core enable accurate energy monitoring over a wide dynamic +range. An integrated high end reference ensures low drift over temperature +with a combined drift of less than ±25 ppm/°C maximum for the entire channel +including a programmable gain amplifier (PGA) and an analog-to-digital +converter (ADC). + +2. Device attributes +==================== + +Power and energy measurements are provided for voltage, current, active power, +reactive power, apparent power, and power factor across three phases. + +Each IIO device has a device folder under ``/sys/bus/iio/devices/iio:deviceX``, +where X is the IIO index of the device. Under these folders reside a set of +device files, depending on the characteristics and features of the hardware +device in question. These files are consistently generalized and documented in +the IIO ABI documentation. + +The following tables show the ADE9000 related device files, found in the +specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. + ++---------------------------------------------------+----------------------------------------------------------+ +| Current measurement related device files | Description | ++---------------------------------------------------+----------------------------------------------------------+ +| in_current[0-2]_raw | Raw current measurement for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_current[0-2]_scale | Scale for current channels. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_current[0-2]_calibscale | Calibration gain for current channels (AIGAIN reg). | ++---------------------------------------------------+----------------------------------------------------------+ +| in_altcurrent[0-2]_rms_raw | RMS current measurement for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_altcurrent[0-2]_rms_scale | Scale for RMS current channels. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_altcurrent[0-2]_rms_calibbias | RMS offset correction for current channels (IRMSOS reg). | ++---------------------------------------------------+----------------------------------------------------------+ + ++---------------------------------------------------+----------------------------------------------------------+ +| Voltage measurement related device files | Description | ++---------------------------------------------------+----------------------------------------------------------+ +| in_voltage[0-2]_raw | Raw voltage measurement for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_voltage[0-2]_scale | Scale for voltage channels. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_voltage[0-2]_calibscale | Calibration gain for voltage channels (AVGAIN reg). | ++---------------------------------------------------+----------------------------------------------------------+ +| in_voltage[0-2]_frequency | Measured line frequency from instantaneous voltage. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_altvoltage[0-2]_rms_raw | RMS voltage measurement for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_altvoltage[0-2]_rms_scale | Scale for RMS voltage channels. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_altvoltage[0-2]_rms_calibbias | RMS offset correction for voltage channels (VRMSOS reg). | ++---------------------------------------------------+----------------------------------------------------------+ + ++---------------------------------------------------+----------------------------------------------------------+ +| Power measurement related device files | Description | ++---------------------------------------------------+----------------------------------------------------------+ +| in_power[0-2]_active_raw | Active power measurement for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_power[0-2]_active_scale | Scale for active power channels. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_power[0-2]_active_calibbias | Calibration offset for active power (xWATTOS regs). | ++---------------------------------------------------+----------------------------------------------------------+ +| in_power[0-2]_active_calibscale | Calibration gain for active power (APGAIN reg). | ++---------------------------------------------------+----------------------------------------------------------+ +| in_power[0-2]_reactive_raw | Reactive power measurement for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_power[0-2]_reactive_scale | Scale for reactive power channels. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_power[0-2]_reactive_calibbias | Calibration offset for reactive power (xVAROS regs). | ++---------------------------------------------------+----------------------------------------------------------+ +| in_power[0-2]_apparent_raw | Apparent power measurement for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_power[0-2]_apparent_scale | Scale for apparent power channels. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_power[0-2]_powerfactor | Power factor for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ + ++---------------------------------------------------+----------------------------------------------------------+ +| Energy measurement related device files | Description | ++---------------------------------------------------+----------------------------------------------------------+ +| in_energy[0-2]_active_raw | Active energy measurement for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_energy[0-2]_reactive_raw | Reactive energy measurement for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ +| in_energy[0-2]_apparent_raw | Apparent energy measurement for phases A, B, C. | ++---------------------------------------------------+----------------------------------------------------------+ + ++------------------------------+------------------------------------------------------------------+ +| Shared device attributes | Description | ++------------------------------+------------------------------------------------------------------+ +| name | Name of the IIO device. | ++------------------------------+------------------------------------------------------------------+ +| filter_type | Waveform buffer filter type (sinc4, sinc4+lp). | ++------------------------------+------------------------------------------------------------------+ +| filter_type_available | Available filter types for waveform buffer. | ++------------------------------+------------------------------------------------------------------+ + +3. Calibration and scaling +=========================== + +The ADE9000 provides multiple levels of gain and offset correction: + +**Calibration Gain (per-channel)** + Fine-tuning calibration gains applied in the digital domain for each channel type. + Controlled via ``calibscale`` attributes (AIGAIN, AVGAIN, APGAIN registers). + +**Calibration Bias (per-channel)** + Hardware calibration offsets applied by the device internally: + + - Power measurements: Controlled via ``calibbias`` attributes for power channels (xWATTOS, xVAROS registers). + - RMS measurements: Controlled via ``calibbias`` attributes for RMS channels (IRMSOS, VRMSOS registers). + + These are internal chip calibrations, not userspace-applied offsets. + +4. Event attributes +=================== + +The ADE9000 provides various interrupts that are mapped to IIO events. +Event functionality is only available if the corresponding interrupts are +connected in the device tree. + ++---------------------------------------------------+----------------------------------------------------------+ +| IIO Event Attribute | ADE9000 Datasheet Equivalent | ++---------------------------------------------------+----------------------------------------------------------+ +| in_voltage[0-2]_thresh_either_en | Zero crossing detection interrupt (ZXVx) | ++---------------------------------------------------+----------------------------------------------------------+ +| in_altvoltage[0-2]_rms_thresh_rising_en | RMS swell detection interrupt (SWELLx) | ++---------------------------------------------------+----------------------------------------------------------+ +| in_altvoltage[0-2]_rms_thresh_rising_value | RMS swell threshold (SWELL_LVL register) | ++---------------------------------------------------+----------------------------------------------------------+ +| in_altvoltage[0-2]_rms_thresh_falling_en | RMS sag/dip detection interrupt (DIPx) | ++---------------------------------------------------+----------------------------------------------------------+ +| in_altvoltage[0-2]_rms_thresh_falling_value | RMS sag/dip threshold (DIP_LVL register) | ++---------------------------------------------------+----------------------------------------------------------+ +| in_current[0-2]_thresh_either_en | Current zero crossing detection interrupt (ZXIx) | ++---------------------------------------------------+----------------------------------------------------------+ + +Event directions: + +- ``rising``: Upper threshold crossing (swell detection) +- ``falling``: Lower threshold crossing (sag/dip detection) +- ``either``: Any threshold crossing (zero crossing detection) +- ``none``: Timeout or non-directional events + +**Note**: Event attributes are only available if the corresponding interrupts +(irq0, irq1, dready) are specified in the device tree. The driver works without +interrupts but with reduced functionality. + +5. Device buffers +================= + +This driver supports IIO buffers for waveform capture. Buffer functionality +requires the dready interrupt to be connected. + +The device supports capturing voltage and current waveforms for power quality +analysis. The waveform buffer can be configured to capture data from different +channel combinations. + +Supported channel combinations for buffered capture: + +- Phase A: voltage and current (IA + VA) +- Phase B: voltage and current (IB + VB) +- Phase C: voltage and current (IC + VC) +- All phases: all voltage and current channels +- Individual channels: IA, VA, IB, VB, IC, VC + +Usage examples +-------------- + +Enable waveform capture for Phase A: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_current0_en + root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_voltage0_en + +Set buffer length and enable: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> echo 100 > buffer/length + root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable + +6. Clock output +=============== + +The ADE9000 can provide a clock output via the CLKOUT pin when using an external +crystal/clock source. This feature is enabled by specifying ``#clock-cells = <0>`` +in the device tree. The output clock will be registered as "clkout" and can be +referenced by other devices. + +7. Usage examples +================= + +Show device name: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat name + ade9000 + +Read voltage measurements: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_voltage0_raw + 12345 + root:/sys/bus/iio/devices/iio:device0> cat in_voltage0_scale + 0.000030517 + +- Phase A voltage = in_voltage0_raw * in_voltage0_scale = 0.3769 V + +Read power measurements: + +.. code-block:: bash + + root:/sys/bus/iio/devices/iio:device0> cat in_power0_active_raw + 5678 + root:/sys/bus/iio/devices/iio:device0> cat in_power0_scale + 0.000244140 + +- Phase A active power = in_power0_active_raw * in_power0_scale = 1.386 W + +Configure calibration gains: + +.. code-block:: bash + + # Set current channel 0 calibration gain + root:/sys/bus/iio/devices/iio:device0> echo 0x800000 > in_current0_calibscale + # Set voltage channel 0 calibration gain + root:/sys/bus/iio/devices/iio:device0> echo 0x7FFFFF > in_voltage0_calibscale + +Configure RMS voltage event thresholds (requires interrupts): + +.. code-block:: bash + + # Set RMS sag detection threshold + root:/sys/bus/iio/devices/iio:device0> echo 180000 > events/in_altvoltage0_rms_thresh_falling_value + # Enable RMS sag detection + root:/sys/bus/iio/devices/iio:device0> echo 1 > events/in_altvoltage0_rms_thresh_falling_en + + # Set RMS swell detection threshold + root:/sys/bus/iio/devices/iio:device0> echo 260000 > events/in_altvoltage0_rms_thresh_rising_value + # Enable RMS swell detection + root:/sys/bus/iio/devices/iio:device0> echo 1 > events/in_altvoltage0_rms_thresh_rising_en + +8. IIO Interfacing Tools +======================== + +See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO +interfacing tools. diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index 9d34d9c89c43..315ae37d6fd4 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -28,6 +28,7 @@ Industrial I/O Kernel Drivers ad7606 ad7625 ad7944 + ade9000 adis16475 adis16480 adis16550 From ee905c92feb469daac1b48ae0db026f528f8b5f7 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 8 Sep 2025 07:35:26 +0000 Subject: [PATCH 1392/2711] Documentation: ABI: iio: add sinc4+lp Add new filter type to the sysfs-bus-iio ABI documentation: - "sinc4+lp" for Sinc4 + Low Pass Filter Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 78da68826307..cb300135b4c4 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -2319,6 +2319,7 @@ Description: time. * "sinc4" - Sinc 4. Excellent noise performance. Long 1st conversion time. + * "sinc4+lp" - Sinc4 + Low Pass Filter. * "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion time. * "sinc5" - The digital sinc5 filter. Excellent noise From 08a9e5f8bb1e2233d19fb0c12f454e2d625532f5 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 10 Sep 2025 12:33:29 -0500 Subject: [PATCH 1393/2711] iio: adc: ad7124: fix sample rate for multi-channel use Change how the FS[10:0] field of the FILTER register is calculated to get consistent sample rates when only one channel is enabled vs when multiple channels are enabled in a buffered read. By default, the AD7124 allows larger sampling frequencies when only one channel is enabled. It assumes that you will discard the first sample or so to allow for settling time and then no additional settling time is needed between samples because there is no multiplexing due to only one channel being enabled. The conversion formula to convert between the sampling frequency and the FS[10:0] field is: fADC = fCLK / (FS[10:0] x 32) which is what the driver has been using. On the other hand, when multiple channels are enabled, there is additional settling time needed when switching between channels so the calculation to convert between becomes: fADC = fCLK / (FS[10:0] x 32 x N) where N depends on if SINGLE_CYCLE is set, the selected filter type and, in some cases, the power mode. The FILTER register has a SINGLE_CYCLE bit that can be set to force the single channel case to use the same timing as the multi-channel case. Before this change, the first formula was always used, so if all of the in_voltageY_sampling_frequency attributes were set to 10 Hz, then doing a buffered read with 1 channel enabled would result in the requested sampling frequency of 10 Hz. But when more than one channel was enabled, the actual sampling frequency would be 2.5 Hz per channel, which is 1/4 of the requested frequency. After this change, the SINGLE_CYCLE flag is now always enabled and the multi-channel formula is now always used. This causes the sampling frequency to be consistent regardless of the number of channels enabled. For now, we are hard-coding N = 4 since the driver doesn't yet support other filter types other than the default sinc4 filter. The AD7124_FILTER_FS define is moved while we are touching this to keep the bit fields in descending order to be consistent with the rest of the file. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index d5bb0faf9111..6f4629c4a2f0 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -93,10 +93,11 @@ #define AD7124_CONFIG_PGA GENMASK(2, 0) /* AD7124_FILTER_X */ -#define AD7124_FILTER_FS GENMASK(10, 0) #define AD7124_FILTER_FILTER GENMASK(23, 21) #define AD7124_FILTER_FILTER_SINC4 0 #define AD7124_FILTER_FILTER_SINC3 2 +#define AD7124_FILTER_SINGLE_CYCLE BIT(16) +#define AD7124_FILTER_FS GENMASK(10, 0) #define AD7124_MAX_CONFIGS 8 #define AD7124_MAX_CHANNELS 16 @@ -285,18 +286,20 @@ static u32 ad7124_get_fclk_hz(struct ad7124_state *st) static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, unsigned int odr) { - unsigned int fclk, odr_sel_bits; + unsigned int fclk, factor, odr_sel_bits; fclk = ad7124_get_fclk_hz(st); /* - * FS[10:0] = fCLK / (fADC x 32) where: + * FS[10:0] = fCLK / (fADC x 32 * N) where: * fADC is the output data rate * fCLK is the master clock frequency + * N is number of conversions per sample (depends on filter type) * FS[10:0] are the bits in the filter register * FS[10:0] can have a value from 1 to 2047 */ - odr_sel_bits = DIV_ROUND_CLOSEST(fclk, odr * 32); + factor = 32 * 4; /* N = 4 for default sinc4 filter. */ + odr_sel_bits = DIV_ROUND_CLOSEST(fclk, odr * factor); if (odr_sel_bits < 1) odr_sel_bits = 1; else if (odr_sel_bits > 2047) @@ -306,7 +309,8 @@ static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel st->channels[channel].cfg.live = false; /* fADC = fCLK / (FS[10:0] x 32) */ - st->channels[channel].cfg.odr = DIV_ROUND_CLOSEST(fclk, odr_sel_bits * 32); + st->channels[channel].cfg.odr = DIV_ROUND_CLOSEST(fclk, odr_sel_bits * + factor); st->channels[channel].cfg.odr_sel_bits = odr_sel_bits; } @@ -439,10 +443,20 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co if (ret < 0) return ret; + /* + * NB: AD7124_FILTER_SINGLE_CYCLE is always set so that we get the same + * sampling frequency even when only one channel is enabled in a + * buffered read. If it was not set, the N in ad7124_set_channel_odr() + * would be 1 and we would get a faster sampling frequency than what + * was requested. + */ tmp = FIELD_PREP(AD7124_FILTER_FILTER, cfg->filter_type) | + AD7124_FILTER_SINGLE_CYCLE | FIELD_PREP(AD7124_FILTER_FS, cfg->odr_sel_bits); return ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot), - AD7124_FILTER_FILTER | AD7124_FILTER_FS, + AD7124_FILTER_FILTER | + AD7124_FILTER_SINGLE_CYCLE | + AD7124_FILTER_FS, tmp, 3); } From faf7f9e72a57481448f5047bb3c7a951e9683952 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 11 Sep 2025 16:42:00 -0500 Subject: [PATCH 1394/2711] iio: adc: ad7124: use clamp() Use clamp() instead of open-coding clamping. Signed-off-by: David Lechner Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 6f4629c4a2f0..8213f625bb3e 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -299,11 +300,7 @@ static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel * FS[10:0] can have a value from 1 to 2047 */ factor = 32 * 4; /* N = 4 for default sinc4 filter. */ - odr_sel_bits = DIV_ROUND_CLOSEST(fclk, odr * factor); - if (odr_sel_bits < 1) - odr_sel_bits = 1; - else if (odr_sel_bits > 2047) - odr_sel_bits = 2047; + odr_sel_bits = clamp(DIV_ROUND_CLOSEST(fclk, odr * factor), 1, 2047); if (odr_sel_bits != st->channels[channel].cfg.odr_sel_bits) st->channels[channel].cfg.live = false; From 1b4956cac19bb8bc9cf97ee8d3a7d5ee27871c7b Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 11 Sep 2025 16:42:01 -0500 Subject: [PATCH 1395/2711] iio: adc: ad7124: use read_avail() for scale_available Replace custom attribute with the standard IIO read_avail() callback to provide in_voltage_scale_available attribute. Signed-off-by: David Lechner Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 42 +++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 8213f625bb3e..58f072c6bc67 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -621,6 +621,33 @@ static const struct ad_sigma_delta_info ad7124_sigma_delta_info = { .num_resetclks = 64, }; +static const int ad7124_voltage_scales[][2] = { + { 0, 1164 }, + { 0, 2328 }, + { 0, 4656 }, + { 0, 9313 }, + { 0, 18626 }, + { 0, 37252 }, + { 0, 74505 }, + { 0, 149011 }, + { 0, 298023 }, +}; + +static int ad7124_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, long info) +{ + switch (info) { + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)ad7124_voltage_scales; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(ad7124_voltage_scales) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + static int ad7124_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) @@ -775,18 +802,6 @@ static int ad7124_reg_access(struct iio_dev *indio_dev, return ret; } -static IIO_CONST_ATTR(in_voltage_scale_available, - "0.000001164 0.000002328 0.000004656 0.000009313 0.000018626 0.000037252 0.000074505 0.000149011 0.000298023"); - -static struct attribute *ad7124_attributes[] = { - &iio_const_attr_in_voltage_scale_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad7124_attrs_group = { - .attrs = ad7124_attributes, -}; - static int ad7124_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { @@ -816,12 +831,12 @@ static int ad7124_update_scan_mode(struct iio_dev *indio_dev, } static const struct iio_info ad7124_info = { + .read_avail = ad7124_read_avail, .read_raw = ad7124_read_raw, .write_raw = ad7124_write_raw, .debugfs_reg_access = &ad7124_reg_access, .validate_trigger = ad_sd_validate_trigger, .update_scan_mode = ad7124_update_scan_mode, - .attrs = &ad7124_attrs_group, }; /* Only called during probe, so dev_err_probe() can be used */ @@ -1011,6 +1026,7 @@ static const struct iio_chan_spec ad7124_channel_template = { BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), .scan_type = { .sign = 'u', .realbits = 24, From d904b8e6d4efadbcb4a4a0e077850cabbee513ed Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 11 Sep 2025 16:42:02 -0500 Subject: [PATCH 1396/2711] iio: adc: ad7124: use guard(mutex) to simplify return paths Use guard(mutex) in a couple of functions to allow direct returns. This simplifies the code a bit and will make later changes easier. cleanup.h was already included for prior use of __free() Signed-off-by: David Lechner Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 58f072c6bc67..789cfacd2eb0 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -739,24 +739,20 @@ static int ad7124_write_raw(struct iio_dev *indio_dev, { struct ad7124_state *st = iio_priv(indio_dev); unsigned int res, gain, full_scale, vref; - int ret = 0; - mutex_lock(&st->cfgs_lock); + guard(mutex)(&st->cfgs_lock); switch (info) { case IIO_CHAN_INFO_SAMP_FREQ: - if (val2 != 0 || val == 0) { - ret = -EINVAL; - break; - } + if (val2 != 0 || val == 0) + return -EINVAL; ad7124_set_channel_odr(st, chan->address, val); - break; + + return 0; case IIO_CHAN_INFO_SCALE: - if (val != 0) { - ret = -EINVAL; - break; - } + if (val != 0) + return -EINVAL; if (st->channels[chan->address].cfg.bipolar) full_scale = 1 << (chan->scan_type.realbits - 1); @@ -772,13 +768,10 @@ static int ad7124_write_raw(struct iio_dev *indio_dev, st->channels[chan->address].cfg.live = false; st->channels[chan->address].cfg.pga_bits = res; - break; + return 0; default: - ret = -EINVAL; + return -EINVAL; } - - mutex_unlock(&st->cfgs_lock); - return ret; } static int ad7124_reg_access(struct iio_dev *indio_dev, @@ -810,7 +803,8 @@ static int ad7124_update_scan_mode(struct iio_dev *indio_dev, int ret; int i; - mutex_lock(&st->cfgs_lock); + guard(mutex)(&st->cfgs_lock); + for (i = 0; i < st->num_channels; i++) { bit_set = test_bit(i, scan_mask); if (bit_set) @@ -818,15 +812,10 @@ static int ad7124_update_scan_mode(struct iio_dev *indio_dev, else ret = ad7124_spi_write_mask(st, AD7124_CHANNEL(i), AD7124_CHANNEL_ENABLE, 0, 2); - if (ret < 0) { - mutex_unlock(&st->cfgs_lock); - + if (ret < 0) return ret; - } } - mutex_unlock(&st->cfgs_lock); - return 0; } From b2dbba2b9388636d0a6066c52f9507c7a7cdf40c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 11 Sep 2025 16:42:03 -0500 Subject: [PATCH 1397/2711] iio: adc: ad7124: support fractional sampling_frequency Modify the attribute read/write functions for sampling_frequency and filter_low_pass_3db_frequency to return fractional values. These ADCs support output data rates in the single digits, so being able to specify fractional values is necessary to use all possible sampling frequencies. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 65 ++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 789cfacd2eb0..cc865ffaed14 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -166,7 +166,6 @@ struct ad7124_channel_config { bool buf_negative; unsigned int vref_mv; unsigned int pga_bits; - unsigned int odr; unsigned int odr_sel_bits; unsigned int filter_type; unsigned int calibration_offset; @@ -285,7 +284,17 @@ static u32 ad7124_get_fclk_hz(struct ad7124_state *st) return fclk_hz; } -static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, unsigned int odr) +static u32 ad7124_get_fadc_divisor(struct ad7124_state *st, unsigned int channel) +{ + /* + * The output data rate (f_ADC) is f_CLK / divisor. We are returning + * the divisor. + */ + return st->channels[channel].cfg.odr_sel_bits * 32 * 4; +} + +static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, + unsigned int odr, unsigned int odr_micro) { unsigned int fclk, factor, odr_sel_bits; @@ -300,29 +309,28 @@ static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel * FS[10:0] can have a value from 1 to 2047 */ factor = 32 * 4; /* N = 4 for default sinc4 filter. */ - odr_sel_bits = clamp(DIV_ROUND_CLOSEST(fclk, odr * factor), 1, 2047); + odr_sel_bits = DIV_ROUND_CLOSEST(fclk, odr * factor + + odr_micro * factor / MICRO); + odr_sel_bits = clamp(odr_sel_bits, 1, 2047); if (odr_sel_bits != st->channels[channel].cfg.odr_sel_bits) st->channels[channel].cfg.live = false; - /* fADC = fCLK / (FS[10:0] x 32) */ - st->channels[channel].cfg.odr = DIV_ROUND_CLOSEST(fclk, odr_sel_bits * - factor); st->channels[channel].cfg.odr_sel_bits = odr_sel_bits; } -static int ad7124_get_3db_filter_freq(struct ad7124_state *st, - unsigned int channel) +static int ad7124_get_3db_filter_factor(struct ad7124_state *st, + unsigned int channel) { - unsigned int fadc; - - fadc = st->channels[channel].cfg.odr; - + /* + * 3dB point is the f_CLK rate times some factor. This functions returns + * the factor times 1000. + */ switch (st->channels[channel].cfg.filter_type) { case AD7124_FILTER_FILTER_SINC3: - return DIV_ROUND_CLOSEST(fadc * 272, 1000); + return 272; case AD7124_FILTER_FILTER_SINC4: - return DIV_ROUND_CLOSEST(fadc * 230, 1000); + return 230; default: return -EINVAL; } @@ -346,7 +354,6 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_ bool buf_negative; unsigned int vref_mv; unsigned int pga_bits; - unsigned int odr; unsigned int odr_sel_bits; unsigned int filter_type; unsigned int calibration_offset; @@ -363,7 +370,6 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_ cfg->buf_negative == cfg_aux->buf_negative && cfg->vref_mv == cfg_aux->vref_mv && cfg->pga_bits == cfg_aux->pga_bits && - cfg->odr == cfg_aux->odr && cfg->odr_sel_bits == cfg_aux->odr_sel_bits && cfg->filter_type == cfg_aux->filter_type && cfg->calibration_offset == cfg_aux->calibration_offset && @@ -718,16 +724,23 @@ static int ad7124_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SAMP_FREQ: mutex_lock(&st->cfgs_lock); - *val = st->channels[chan->address].cfg.odr; + *val = ad7124_get_fclk_hz(st); + *val2 = ad7124_get_fadc_divisor(st, chan->address); mutex_unlock(&st->cfgs_lock); - return IIO_VAL_INT; - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - mutex_lock(&st->cfgs_lock); - *val = ad7124_get_3db_filter_freq(st, chan->scan_index); - mutex_unlock(&st->cfgs_lock); + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: { + guard(mutex)(&st->cfgs_lock); - return IIO_VAL_INT; + ret = ad7124_get_3db_filter_factor(st, chan->address); + if (ret < 0) + return ret; + + /* 3dB point is the f_CLK rate times a fractional value */ + *val = ret * ad7124_get_fclk_hz(st); + *val2 = MILLI * ad7124_get_fadc_divisor(st, chan->address); + return IIO_VAL_FRACTIONAL; + } default: return -EINVAL; } @@ -744,10 +757,10 @@ static int ad7124_write_raw(struct iio_dev *indio_dev, switch (info) { case IIO_CHAN_INFO_SAMP_FREQ: - if (val2 != 0 || val == 0) + if (val2 < 0 || val < 0 || (val2 == 0 && val == 0)) return -EINVAL; - ad7124_set_channel_odr(st, chan->address, val); + ad7124_set_channel_odr(st, chan->address, val, val2); return 0; case IIO_CHAN_INFO_SCALE: @@ -1296,7 +1309,7 @@ static int ad7124_setup(struct ad7124_state *st) * regardless of the selected power mode. Round it up to 10 and * set all channels to this default value. */ - ad7124_set_channel_odr(st, i, 10); + ad7124_set_channel_odr(st, i, 10, 0); } ad7124_disable_all(&st->sd); From f1496949c75d8c77c6829fa5b2c7dcca2d1a0764 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 11 Sep 2025 16:42:04 -0500 Subject: [PATCH 1398/2711] iio: adc: ad7124: add filter support Add support to the ad7124 driver for selecting the filter type. The filter type has an influence on the effective sampling frequency of each channel. For sinc3+pf{1,2,3,4}, the sampling frequency is fixed. For sinc{3,4} (without post filter), there is a factor of 3 or 4 depending on the filter type. For the extra +sinc1, there is an extra averaging factor that depends on the power mode. In order to select the closest sampling frequency for each filter type, we keep a copy of the requested sampling frequency. This way, if the user sets the sampling frequency first and then selects the filter type, the sampling frequency will still be as close as possible to the requested value. Since we always either have the SINGLE_CYCLE bit set or have more than one channel enabled, the sampling frequency is always using the "zero-latency" calculation from the data sheet. This is only documented for the basic sinc{3,4} filters, so the other filter types had to be inferred and confirmed through testing. Since the flat filter type list consists of multiple register fields, the struct ad7124_channel_config::filter_type field is changed to the enum ad7124_filter_type type to avoid nested switch statements in a lot of places. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 262 ++++++++++++++++++++++++++++++++++----- 1 file changed, 230 insertions(+), 32 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index cc865ffaed14..9ea419003cc6 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -3,6 +3,7 @@ * AD7124 SPI ADC driver * * Copyright 2018 Analog Devices Inc. + * Copyright 2025 BayLibre, SAS */ #include #include @@ -97,6 +98,15 @@ #define AD7124_FILTER_FILTER GENMASK(23, 21) #define AD7124_FILTER_FILTER_SINC4 0 #define AD7124_FILTER_FILTER_SINC3 2 +#define AD7124_FILTER_FILTER_SINC4_SINC1 4 +#define AD7124_FILTER_FILTER_SINC3_SINC1 5 +#define AD7124_FILTER_FILTER_SINC3_PF 7 +#define AD7124_FILTER_REJ60 BIT(20) +#define AD7124_FILTER_POST_FILTER GENMASK(19, 17) +#define AD7124_FILTER_POST_FILTER_47dB 2 +#define AD7124_FILTER_POST_FILTER_62dB 3 +#define AD7124_FILTER_POST_FILTER_86dB 5 +#define AD7124_FILTER_POST_FILTER_92dB 6 #define AD7124_FILTER_SINGLE_CYCLE BIT(16) #define AD7124_FILTER_FS GENMASK(10, 0) @@ -151,9 +161,24 @@ struct ad7124_chip_info { unsigned int num_inputs; }; +enum ad7124_filter_type { + AD7124_FILTER_TYPE_SINC3, + AD7124_FILTER_TYPE_SINC3_PF1, + AD7124_FILTER_TYPE_SINC3_PF2, + AD7124_FILTER_TYPE_SINC3_PF3, + AD7124_FILTER_TYPE_SINC3_PF4, + AD7124_FILTER_TYPE_SINC3_REJ60, + AD7124_FILTER_TYPE_SINC3_SINC1, + AD7124_FILTER_TYPE_SINC4, + AD7124_FILTER_TYPE_SINC4_REJ60, + AD7124_FILTER_TYPE_SINC4_SINC1, +}; + struct ad7124_channel_config { bool live; unsigned int cfg_slot; + unsigned int requested_odr; + unsigned int requested_odr_micro; /* * Following fields are used to compare for equality. If you * make adaptations in it, you most likely also have to adapt @@ -167,7 +192,7 @@ struct ad7124_channel_config { unsigned int vref_mv; unsigned int pga_bits; unsigned int odr_sel_bits; - unsigned int filter_type; + enum ad7124_filter_type filter_type; unsigned int calibration_offset; unsigned int calibration_gain; ); @@ -284,21 +309,50 @@ static u32 ad7124_get_fclk_hz(struct ad7124_state *st) return fclk_hz; } +static u32 ad7124_get_fs_factor(struct ad7124_state *st, unsigned int channel) +{ + enum ad7124_power_mode power_mode = + FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE, st->adc_control); + u32 avg = power_mode == AD7124_LOW_POWER ? 8 : 16; + + /* + * These are the "zero-latency" factors from the data sheet. For the + * sinc1 filters, these aren't documented, but derived by taking the + * single-channel formula from the sinc1 section of the data sheet and + * multiplying that by the sinc3/4 factor from the corresponding zero- + * latency sections. + */ + switch (st->channels[channel].cfg.filter_type) { + case AD7124_FILTER_TYPE_SINC4: + case AD7124_FILTER_TYPE_SINC4_REJ60: + return 4 * 32; + case AD7124_FILTER_TYPE_SINC4_SINC1: + return 4 * avg * 32; + case AD7124_FILTER_TYPE_SINC3_SINC1: + return 3 * avg * 32; + default: + return 3 * 32; + } +} + static u32 ad7124_get_fadc_divisor(struct ad7124_state *st, unsigned int channel) { + u32 factor = ad7124_get_fs_factor(st, channel); + /* * The output data rate (f_ADC) is f_CLK / divisor. We are returning * the divisor. */ - return st->channels[channel].cfg.odr_sel_bits * 32 * 4; + return st->channels[channel].cfg.odr_sel_bits * factor; } -static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, - unsigned int odr, unsigned int odr_micro) +static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel) { - unsigned int fclk, factor, odr_sel_bits; + struct ad7124_channel_config *cfg = &st->channels[channel].cfg; + unsigned int fclk, factor, divisor, odr_sel_bits; fclk = ad7124_get_fclk_hz(st); + factor = ad7124_get_fs_factor(st, channel); /* * FS[10:0] = fCLK / (fADC x 32 * N) where: @@ -308,10 +362,9 @@ static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel * FS[10:0] are the bits in the filter register * FS[10:0] can have a value from 1 to 2047 */ - factor = 32 * 4; /* N = 4 for default sinc4 filter. */ - odr_sel_bits = DIV_ROUND_CLOSEST(fclk, odr * factor + - odr_micro * factor / MICRO); - odr_sel_bits = clamp(odr_sel_bits, 1, 2047); + divisor = cfg->requested_odr * factor + + cfg->requested_odr_micro * factor / MICRO; + odr_sel_bits = clamp(DIV_ROUND_CLOSEST(fclk, divisor), 1, 2047); if (odr_sel_bits != st->channels[channel].cfg.odr_sel_bits) st->channels[channel].cfg.live = false; @@ -322,15 +375,29 @@ static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel static int ad7124_get_3db_filter_factor(struct ad7124_state *st, unsigned int channel) { + struct ad7124_channel_config *cfg = &st->channels[channel].cfg; + /* * 3dB point is the f_CLK rate times some factor. This functions returns * the factor times 1000. */ - switch (st->channels[channel].cfg.filter_type) { - case AD7124_FILTER_FILTER_SINC3: + switch (cfg->filter_type) { + case AD7124_FILTER_TYPE_SINC3: + case AD7124_FILTER_TYPE_SINC3_REJ60: + case AD7124_FILTER_TYPE_SINC3_SINC1: return 272; - case AD7124_FILTER_FILTER_SINC4: + case AD7124_FILTER_TYPE_SINC4: + case AD7124_FILTER_TYPE_SINC4_REJ60: + case AD7124_FILTER_TYPE_SINC4_SINC1: return 230; + case AD7124_FILTER_TYPE_SINC3_PF1: + return 633; + case AD7124_FILTER_TYPE_SINC3_PF2: + return 605; + case AD7124_FILTER_TYPE_SINC3_PF3: + return 669; + case AD7124_FILTER_TYPE_SINC3_PF4: + return 759; default: return -EINVAL; } @@ -355,7 +422,7 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_ unsigned int vref_mv; unsigned int pga_bits; unsigned int odr_sel_bits; - unsigned int filter_type; + enum ad7124_filter_type filter_type; unsigned int calibration_offset; unsigned int calibration_gain; })); @@ -422,8 +489,9 @@ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channe static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_config *cfg, unsigned int cfg_slot) { - unsigned int tmp; - unsigned int val; + unsigned int val, filter; + unsigned int rej60 = 0; + unsigned int post = 0; int ret; cfg->cfg_slot = cfg_slot; @@ -446,6 +514,47 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co if (ret < 0) return ret; + switch (cfg->filter_type) { + case AD7124_FILTER_TYPE_SINC3: + filter = AD7124_FILTER_FILTER_SINC3; + break; + case AD7124_FILTER_TYPE_SINC3_PF1: + filter = AD7124_FILTER_FILTER_SINC3_PF; + post = AD7124_FILTER_POST_FILTER_47dB; + break; + case AD7124_FILTER_TYPE_SINC3_PF2: + filter = AD7124_FILTER_FILTER_SINC3_PF; + post = AD7124_FILTER_POST_FILTER_62dB; + break; + case AD7124_FILTER_TYPE_SINC3_PF3: + filter = AD7124_FILTER_FILTER_SINC3_PF; + post = AD7124_FILTER_POST_FILTER_86dB; + break; + case AD7124_FILTER_TYPE_SINC3_PF4: + filter = AD7124_FILTER_FILTER_SINC3_PF; + post = AD7124_FILTER_POST_FILTER_92dB; + break; + case AD7124_FILTER_TYPE_SINC3_REJ60: + filter = AD7124_FILTER_FILTER_SINC3; + rej60 = 1; + break; + case AD7124_FILTER_TYPE_SINC3_SINC1: + filter = AD7124_FILTER_FILTER_SINC3_SINC1; + break; + case AD7124_FILTER_TYPE_SINC4: + filter = AD7124_FILTER_FILTER_SINC4; + break; + case AD7124_FILTER_TYPE_SINC4_REJ60: + filter = AD7124_FILTER_FILTER_SINC4; + rej60 = 1; + break; + case AD7124_FILTER_TYPE_SINC4_SINC1: + filter = AD7124_FILTER_FILTER_SINC4_SINC1; + break; + default: + return -EINVAL; + } + /* * NB: AD7124_FILTER_SINGLE_CYCLE is always set so that we get the same * sampling frequency even when only one channel is enabled in a @@ -453,14 +562,12 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co * would be 1 and we would get a faster sampling frequency than what * was requested. */ - tmp = FIELD_PREP(AD7124_FILTER_FILTER, cfg->filter_type) | - AD7124_FILTER_SINGLE_CYCLE | - FIELD_PREP(AD7124_FILTER_FS, cfg->odr_sel_bits); - return ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot), - AD7124_FILTER_FILTER | - AD7124_FILTER_SINGLE_CYCLE | - AD7124_FILTER_FS, - tmp, 3); + return ad_sd_write_reg(&st->sd, AD7124_FILTER(cfg->cfg_slot), 3, + FIELD_PREP(AD7124_FILTER_FILTER, filter) | + FIELD_PREP(AD7124_FILTER_REJ60, rej60) | + FIELD_PREP(AD7124_FILTER_POST_FILTER, post) | + AD7124_FILTER_SINGLE_CYCLE | + FIELD_PREP(AD7124_FILTER_FS, cfg->odr_sel_bits)); } static struct ad7124_channel_config *ad7124_pop_config(struct ad7124_state *st) @@ -722,13 +829,47 @@ static int ad7124_read_raw(struct iio_dev *indio_dev, return -EINVAL; } - case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&st->cfgs_lock); - *val = ad7124_get_fclk_hz(st); - *val2 = ad7124_get_fadc_divisor(st, chan->address); - mutex_unlock(&st->cfgs_lock); + case IIO_CHAN_INFO_SAMP_FREQ: { + struct ad7124_channel_config *cfg = &st->channels[chan->address].cfg; - return IIO_VAL_FRACTIONAL; + guard(mutex)(&st->cfgs_lock); + + switch (cfg->filter_type) { + case AD7124_FILTER_TYPE_SINC3: + case AD7124_FILTER_TYPE_SINC3_REJ60: + case AD7124_FILTER_TYPE_SINC3_SINC1: + case AD7124_FILTER_TYPE_SINC4: + case AD7124_FILTER_TYPE_SINC4_REJ60: + case AD7124_FILTER_TYPE_SINC4_SINC1: + *val = ad7124_get_fclk_hz(st); + *val2 = ad7124_get_fadc_divisor(st, chan->address); + return IIO_VAL_FRACTIONAL; + /* + * Post filters force the chip to a fixed rate. These are the + * single-channel rates from the data sheet divided by 3 for + * the multi-channel case (data sheet doesn't explicitly state + * this but confirmed through testing). + */ + case AD7124_FILTER_TYPE_SINC3_PF1: + *val = 300; + *val2 = 33; + return IIO_VAL_FRACTIONAL; + case AD7124_FILTER_TYPE_SINC3_PF2: + *val = 25; + *val2 = 3; + return IIO_VAL_FRACTIONAL; + case AD7124_FILTER_TYPE_SINC3_PF3: + *val = 20; + *val2 = 3; + return IIO_VAL_FRACTIONAL; + case AD7124_FILTER_TYPE_SINC3_PF4: + *val = 50; + *val2 = 9; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + } case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: { guard(mutex)(&st->cfgs_lock); @@ -751,6 +892,7 @@ static int ad7124_write_raw(struct iio_dev *indio_dev, int val, int val2, long info) { struct ad7124_state *st = iio_priv(indio_dev); + struct ad7124_channel_config *cfg = &st->channels[chan->address].cfg; unsigned int res, gain, full_scale, vref; guard(mutex)(&st->cfgs_lock); @@ -760,7 +902,9 @@ static int ad7124_write_raw(struct iio_dev *indio_dev, if (val2 < 0 || val < 0 || (val2 == 0 && val == 0)) return -EINVAL; - ad7124_set_channel_odr(st, chan->address, val, val2); + cfg->requested_odr = val; + cfg->requested_odr_micro = val2; + ad7124_set_channel_odr(st, chan->address); return 0; case IIO_CHAN_INFO_SCALE: @@ -1006,6 +1150,52 @@ static const struct iio_enum ad7124_syscalib_mode_enum = { .get = ad7124_get_syscalib_mode }; +static const char * const ad7124_filter_types[] = { + [AD7124_FILTER_TYPE_SINC3] = "sinc3", + [AD7124_FILTER_TYPE_SINC3_PF1] = "sinc3+pf1", + [AD7124_FILTER_TYPE_SINC3_PF2] = "sinc3+pf2", + [AD7124_FILTER_TYPE_SINC3_PF3] = "sinc3+pf3", + [AD7124_FILTER_TYPE_SINC3_PF4] = "sinc3+pf4", + [AD7124_FILTER_TYPE_SINC3_REJ60] = "sinc3+rej60", + [AD7124_FILTER_TYPE_SINC3_SINC1] = "sinc3+sinc1", + [AD7124_FILTER_TYPE_SINC4] = "sinc4", + [AD7124_FILTER_TYPE_SINC4_REJ60] = "sinc4+rej60", + [AD7124_FILTER_TYPE_SINC4_SINC1] = "sinc4+sinc1", +}; + +static int ad7124_set_filter_type_attr(struct iio_dev *dev, + const struct iio_chan_spec *chan, + unsigned int value) +{ + struct ad7124_state *st = iio_priv(dev); + struct ad7124_channel_config *cfg = &st->channels[chan->address].cfg; + + guard(mutex)(&st->cfgs_lock); + + cfg->live = false; + cfg->filter_type = value; + ad7124_set_channel_odr(st, chan->address); + + return 0; +} + +static int ad7124_get_filter_type_attr(struct iio_dev *dev, + const struct iio_chan_spec *chan) +{ + struct ad7124_state *st = iio_priv(dev); + + guard(mutex)(&st->cfgs_lock); + + return st->channels[chan->address].cfg.filter_type; +} + +static const struct iio_enum ad7124_filter_type_enum = { + .items = ad7124_filter_types, + .num_items = ARRAY_SIZE(ad7124_filter_types), + .set = ad7124_set_filter_type_attr, + .get = ad7124_get_filter_type_attr, +}; + static const struct iio_chan_spec_ext_info ad7124_calibsys_ext_info[] = { { .name = "sys_calibration", @@ -1016,6 +1206,9 @@ static const struct iio_chan_spec_ext_info ad7124_calibsys_ext_info[] = { &ad7124_syscalib_mode_enum), IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE, &ad7124_syscalib_mode_enum), + IIO_ENUM("filter_type", IIO_SEPARATE, &ad7124_filter_type_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_TYPE, + &ad7124_filter_type_enum), { } }; @@ -1299,17 +1492,22 @@ static int ad7124_setup(struct ad7124_state *st) mutex_init(&st->cfgs_lock); INIT_KFIFO(st->live_cfgs_fifo); for (i = 0; i < st->num_channels; i++) { + struct ad7124_channel_config *cfg = &st->channels[i].cfg; - ret = ad7124_init_config_vref(st, &st->channels[i].cfg); + ret = ad7124_init_config_vref(st, cfg); if (ret < 0) return ret; + /* Default filter type on the ADC after reset. */ + cfg->filter_type = AD7124_FILTER_TYPE_SINC4; + /* * 9.38 SPS is the minimum output data rate supported * regardless of the selected power mode. Round it up to 10 and * set all channels to this default value. */ - ad7124_set_channel_odr(st, i, 10, 0); + cfg->requested_odr = 10; + ad7124_set_channel_odr(st, i); } ad7124_disable_all(&st->sd); From 29cc0ac502a4804e624ffe152d720ba7dd28703c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 11 Sep 2025 16:42:05 -0500 Subject: [PATCH 1399/2711] iio: ABI: document "sinc4+rej60" filter_type Add a bullet point for "sinc4+rej60" filter_type that is used in the ad7124 driver. Signed-off-by: David Lechner Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index cb300135b4c4..43ca01251c4e 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -2322,6 +2322,7 @@ Description: * "sinc4+lp" - Sinc4 + Low Pass Filter. * "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion time. + * "sinc4+rej60" - Sinc4 + 60Hz rejection. * "sinc5" - The digital sinc5 filter. Excellent noise performance * "sinc5+avg" - Sinc5 + averaging by 4. From 0f06e28747b3d896b9c71c2a7e9f48061755162b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duje=20Mihanovi=C4=87?= Date: Thu, 11 Sep 2025 14:43:44 +0200 Subject: [PATCH 1400/2711] dt-bindings: mfd: 88pm886: Add #io-channel-cells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an #io-channel-cells property to the Marvell 88PM886 PMIC binding to allow referencing the IO channels exposed by its GPADC. Acked-by: Karel Balej # for the PMIC Acked-by: Krzysztof Kozlowski Signed-off-by: Duje Mihanović Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/mfd/marvell,88pm886-a1.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/marvell,88pm886-a1.yaml b/Documentation/devicetree/bindings/mfd/marvell,88pm886-a1.yaml index d6a71c912b76..92a72a99fd79 100644 --- a/Documentation/devicetree/bindings/mfd/marvell,88pm886-a1.yaml +++ b/Documentation/devicetree/bindings/mfd/marvell,88pm886-a1.yaml @@ -35,6 +35,9 @@ properties: description: LDO or buck regulator. unevaluatedProperties: false + '#io-channel-cells': + const: 1 + required: - compatible - reg @@ -53,6 +56,7 @@ examples: reg = <0x30>; interrupts = <0 4 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&gic>; + #io-channel-cells = <1>; wakeup-source; regulators { From 3422b4bc606eee2ba7758ea9347c83332eeec3e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duje=20Mihanovi=C4=87?= Date: Thu, 11 Sep 2025 14:43:45 +0200 Subject: [PATCH 1401/2711] iio: adc: Add driver for Marvell 88PM886 PMIC ADC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marvell's 88PM886 PMIC has a so-called General Purpose ADC used for monitoring various system voltages and temperatures. Add the relevant register definitions to the MFD header and a driver for the ADC. Acked-by: Karel Balej # for the PMIC Signed-off-by: Duje Mihanović Signed-off-by: Jonathan Cameron --- MAINTAINERS | 5 + drivers/iio/adc/88pm886-gpadc.c | 393 ++++++++++++++++++++++++++++++++ drivers/iio/adc/Kconfig | 13 ++ drivers/iio/adc/Makefile | 1 + include/linux/mfd/88pm886.h | 58 +++++ 5 files changed, 470 insertions(+) create mode 100644 drivers/iio/adc/88pm886-gpadc.c diff --git a/MAINTAINERS b/MAINTAINERS index 75615d82593e..5c572204933d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14714,6 +14714,11 @@ F: drivers/regulator/88pm886-regulator.c F: drivers/rtc/rtc-88pm886.c F: include/linux/mfd/88pm886.h +MARVELL 88PM886 PMIC GPADC DRIVER +M: Duje Mihanović +S: Maintained +F: drivers/iio/adc/88pm886-gpadc.c + MARVELL ARMADA 3700 PHY DRIVERS M: Miquel Raynal S: Maintained diff --git a/drivers/iio/adc/88pm886-gpadc.c b/drivers/iio/adc/88pm886-gpadc.c new file mode 100644 index 000000000000..cffe35136685 --- /dev/null +++ b/drivers/iio/adc/88pm886-gpadc.c @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2025, Duje Mihanović + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +struct pm886_gpadc { + struct regmap *map; +}; + +enum pm886_gpadc_channel { + VSC_CHAN, + VCHG_PWR_CHAN, + VCF_OUT_CHAN, + VBAT_CHAN, + VBAT_SLP_CHAN, + VBUS_CHAN, + + GPADC0_CHAN, + GPADC1_CHAN, + GPADC2_CHAN, + GPADC3_CHAN, + + GND_DET1_CHAN, + GND_DET2_CHAN, + MIC_DET_CHAN, + + TINT_CHAN, +}; + +static const int pm886_gpadc_regs[] = { + [VSC_CHAN] = PM886_REG_GPADC_VSC, + [VCHG_PWR_CHAN] = PM886_REG_GPADC_VCHG_PWR, + [VCF_OUT_CHAN] = PM886_REG_GPADC_VCF_OUT, + [VBAT_CHAN] = PM886_REG_GPADC_VBAT, + [VBAT_SLP_CHAN] = PM886_REG_GPADC_VBAT_SLP, + [VBUS_CHAN] = PM886_REG_GPADC_VBUS, + + [GPADC0_CHAN] = PM886_REG_GPADC_GPADC0, + [GPADC1_CHAN] = PM886_REG_GPADC_GPADC1, + [GPADC2_CHAN] = PM886_REG_GPADC_GPADC2, + [GPADC3_CHAN] = PM886_REG_GPADC_GPADC3, + + [GND_DET1_CHAN] = PM886_REG_GPADC_GND_DET1, + [GND_DET2_CHAN] = PM886_REG_GPADC_GND_DET2, + [MIC_DET_CHAN] = PM886_REG_GPADC_MIC_DET, + + [TINT_CHAN] = PM886_REG_GPADC_TINT, +}; + +#define ADC_CHANNEL_VOLTAGE(index, lsb, name) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = index, \ + .address = lsb, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .datasheet_name = name, \ +} + +#define ADC_CHANNEL_RESISTANCE(index, lsb, name) \ +{ \ + .type = IIO_RESISTANCE, \ + .indexed = 1, \ + .channel = index, \ + .address = lsb, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ + .datasheet_name = name, \ +} + +#define ADC_CHANNEL_TEMPERATURE(index, lsb, name) \ +{ \ + .type = IIO_TEMP, \ + .indexed = 1, \ + .channel = index, \ + .address = lsb, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .datasheet_name = name, \ +} + +static const struct iio_chan_spec pm886_gpadc_channels[] = { + ADC_CHANNEL_VOLTAGE(VSC_CHAN, 1367, "vsc"), + ADC_CHANNEL_VOLTAGE(VCHG_PWR_CHAN, 1709, "vchg_pwr"), + ADC_CHANNEL_VOLTAGE(VCF_OUT_CHAN, 1367, "vcf_out"), + ADC_CHANNEL_VOLTAGE(VBAT_CHAN, 1367, "vbat"), + ADC_CHANNEL_VOLTAGE(VBAT_SLP_CHAN, 1367, "vbat_slp"), + ADC_CHANNEL_VOLTAGE(VBUS_CHAN, 1709, "vbus"), + + ADC_CHANNEL_RESISTANCE(GPADC0_CHAN, 342, "gpadc0"), + ADC_CHANNEL_RESISTANCE(GPADC1_CHAN, 342, "gpadc1"), + ADC_CHANNEL_RESISTANCE(GPADC2_CHAN, 342, "gpadc2"), + ADC_CHANNEL_RESISTANCE(GPADC3_CHAN, 342, "gpadc3"), + + ADC_CHANNEL_VOLTAGE(GND_DET1_CHAN, 342, "gnddet1"), + ADC_CHANNEL_VOLTAGE(GND_DET2_CHAN, 342, "gnddet2"), + ADC_CHANNEL_VOLTAGE(MIC_DET_CHAN, 1367, "mic_det"), + + ADC_CHANNEL_TEMPERATURE(TINT_CHAN, 104, "tint"), +}; + +static const struct regmap_config pm886_gpadc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = PM886_GPADC_MAX_REGISTER, +}; + +static int gpadc_get_raw(struct iio_dev *iio, enum pm886_gpadc_channel chan) +{ + struct pm886_gpadc *gpadc = iio_priv(iio); + __be16 buf; + int ret; + + ret = regmap_bulk_read(gpadc->map, pm886_gpadc_regs[chan], &buf, sizeof(buf)); + if (ret) + return ret; + + return be16_to_cpu(buf) >> 4; +} + +static int +gpadc_set_bias(struct pm886_gpadc *gpadc, enum pm886_gpadc_channel chan, bool on) +{ + unsigned int gpadc_num = chan - GPADC0_CHAN; + unsigned int bits = BIT(gpadc_num + 4) | BIT(gpadc_num); + + return regmap_assign_bits(gpadc->map, PM886_REG_GPADC_CONFIG(0x14), bits, on); +} + +static int +gpadc_find_bias_current(struct iio_dev *iio, struct iio_chan_spec const *chan, + unsigned int *raw_uV, unsigned int *raw_uA) +{ + struct pm886_gpadc *gpadc = iio_priv(iio); + unsigned int gpadc_num = chan->channel - GPADC0_CHAN; + unsigned int reg = PM886_REG_GPADC_CONFIG(0xb + gpadc_num); + unsigned long lsb = chan->address; + int ret; + + for (unsigned int i = 0; i < PM886_GPADC_BIAS_LEVELS; i++) { + ret = regmap_update_bits(gpadc->map, reg, GENMASK(3, 0), i); + if (ret) + return ret; + + /* Wait for the new bias level to apply. */ + fsleep(5 * USEC_PER_MSEC); + + *raw_uA = PM886_GPADC_INDEX_TO_BIAS_uA(i); + *raw_uV = gpadc_get_raw(iio, chan->channel) * lsb; + + /* + * Vendor kernel errors out above 1.25 V, but testing shows + * that the resistance of the battery detection channel (GPADC2 + * on coreprimevelte) reaches about 1.4 MΩ when the battery is + * removed, which can't be measured with such a low upper + * limit. Therefore, to be able to detect the battery without + * ugly externs as used in the vendor fuel gauge driver, + * increase this limit a bit. + */ + if (WARN_ON(*raw_uV > 1500 * (MICRO / MILLI))) + return -EIO; + + /* + * Vendor kernel errors out under 300 mV, but for the same + * reason as above (except the channel hovers around 3.5 kΩ + * with battery present) reduce this limit. + */ + if (*raw_uV < 200 * (MICRO / MILLI)) { + dev_dbg(&iio->dev, "bad bias for chan %d: %d uA @ %d uV\n", + chan->channel, *raw_uA, *raw_uV); + continue; + } + + dev_dbg(&iio->dev, "good bias for chan %d: %d uA @ %d uV\n", + chan->channel, *raw_uA, *raw_uV); + return 0; + } + + dev_err(&iio->dev, "failed to find good bias for chan %d\n", chan->channel); + return -EINVAL; +} + +static int +gpadc_get_resistance_ohm(struct iio_dev *iio, struct iio_chan_spec const *chan) +{ + struct pm886_gpadc *gpadc = iio_priv(iio); + unsigned int raw_uV, raw_uA; + int ret; + + ret = gpadc_set_bias(gpadc, chan->channel, true); + if (ret) + goto out; + + ret = gpadc_find_bias_current(iio, chan, &raw_uV, &raw_uA); + if (ret) + goto out; + + ret = DIV_ROUND_CLOSEST(raw_uV, raw_uA); +out: + gpadc_set_bias(gpadc, chan->channel, false); + return ret; +} + +static int +__pm886_gpadc_read_raw(struct iio_dev *iio, struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + unsigned long lsb = chan->address; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + *val = gpadc_get_raw(iio, chan->channel); + if (*val < 0) + return *val; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = lsb; + + if (chan->type == IIO_VOLTAGE) { + *val2 = MILLI; + return IIO_VAL_FRACTIONAL; + } else { + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_OFFSET: + /* Raw value is 104 millikelvin/LSB, convert it to 104 millicelsius/LSB */ + *val = ABSOLUTE_ZERO_MILLICELSIUS; + *val2 = lsb; + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_PROCESSED: + *val = gpadc_get_resistance_ohm(iio, chan); + if (*val < 0) + return *val; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int pm886_gpadc_read_raw(struct iio_dev *iio, struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct device *dev = iio->dev.parent; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = __pm886_gpadc_read_raw(iio, chan, val, val2, mask); + + pm_runtime_put_autosuspend(dev); + return ret; +} + +static int pm886_gpadc_hw_enable(struct regmap *map) +{ + const u8 config[] = { + PM886_GPADC_CONFIG1_EN_ALL, + PM886_GPADC_CONFIG2_EN_ALL, + PM886_GPADC_GND_DET2_EN, + }; + int ret; + + /* Enable the ADC block. */ + ret = regmap_set_bits(map, PM886_REG_GPADC_CONFIG(0x6), BIT(0)); + if (ret) + return ret; + + /* Enable all channels. */ + return regmap_bulk_write(map, PM886_REG_GPADC_CONFIG(0x1), config, ARRAY_SIZE(config)); +} + +static int pm886_gpadc_hw_disable(struct regmap *map) +{ + return regmap_clear_bits(map, PM886_REG_GPADC_CONFIG(0x6), BIT(0)); +} + +static const struct iio_info pm886_gpadc_iio_info = { + .read_raw = pm886_gpadc_read_raw, +}; + +static int pm886_gpadc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pm886_chip *chip = dev_get_drvdata(dev->parent); + struct i2c_client *client = chip->client; + struct pm886_gpadc *gpadc; + struct i2c_client *page; + struct iio_dev *iio; + int ret; + + iio = devm_iio_device_alloc(dev, sizeof(*gpadc)); + if (!iio) + return -ENOMEM; + + gpadc = iio_priv(iio); + dev_set_drvdata(dev, iio); + + page = devm_i2c_new_dummy_device(dev, client->adapter, + client->addr + PM886_PAGE_OFFSET_GPADC); + if (IS_ERR(page)) + return dev_err_probe(dev, PTR_ERR(page), "Failed to initialize GPADC page\n"); + + gpadc->map = devm_regmap_init_i2c(page, &pm886_gpadc_regmap_config); + if (IS_ERR(gpadc->map)) + return dev_err_probe(dev, PTR_ERR(gpadc->map), + "Failed to initialize GPADC regmap\n"); + + iio->name = "88pm886-gpadc"; + iio->modes = INDIO_DIRECT_MODE; + iio->info = &pm886_gpadc_iio_info; + iio->channels = pm886_gpadc_channels; + iio->num_channels = ARRAY_SIZE(pm886_gpadc_channels); + device_set_node(&iio->dev, dev_fwnode(dev->parent)); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); + + pm_runtime_set_autosuspend_delay(dev, 50); + pm_runtime_use_autosuspend(dev); + ret = devm_iio_device_register(dev, iio); + if (ret) + return dev_err_probe(dev, ret, "Failed to register ADC\n"); + + return 0; +} + +static int pm886_gpadc_runtime_resume(struct device *dev) +{ + struct iio_dev *iio = dev_get_drvdata(dev); + struct pm886_gpadc *gpadc = iio_priv(iio); + + return pm886_gpadc_hw_enable(gpadc->map); +} + +static int pm886_gpadc_runtime_suspend(struct device *dev) +{ + struct iio_dev *iio = dev_get_drvdata(dev); + struct pm886_gpadc *gpadc = iio_priv(iio); + + return pm886_gpadc_hw_disable(gpadc->map); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(pm886_gpadc_pm_ops, + pm886_gpadc_runtime_suspend, + pm886_gpadc_runtime_resume, NULL); + +static const struct platform_device_id pm886_gpadc_id[] = { + { "88pm886-gpadc" }, + { } +}; +MODULE_DEVICE_TABLE(platform, pm886_gpadc_id); + +static struct platform_driver pm886_gpadc_driver = { + .driver = { + .name = "88pm886-gpadc", + .pm = pm_ptr(&pm886_gpadc_pm_ops), + }, + .probe = pm886_gpadc_probe, + .id_table = pm886_gpadc_id, +}; +module_platform_driver(pm886_gpadc_driver); + +MODULE_AUTHOR("Duje Mihanović "); +MODULE_DESCRIPTION("Marvell 88PM886 GPADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 09ab25c8cfdb..8c84b2c1d223 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -9,6 +9,19 @@ menu "Analog to digital converters" config IIO_ADC_HELPER tristate +config 88PM886_GPADC + tristate "Marvell 88PM886 GPADC driver" + depends on MFD_88PM886_PMIC + default MFD_88PM886_PMIC + help + Say Y here to enable support for the GPADC (General Purpose ADC) + found on the Marvell 88PM886 PMIC. The GPADC measures various + internal voltages and temperatures, including (but not limited to) + system, battery and USB Vbus. + + To compile this driver as a module, choose M here: the module will be + called 88pm886-gpadc. + config AB8500_GPADC bool "ST-Ericsson AB8500 GPADC driver" depends on AB8500_CORE && REGULATOR_AB8500 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 4d071f290911..611c16430621 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_IIO_ADC_HELPER) += industrialio-adc.o # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_88PM886_GPADC) += 88pm886-gpadc.o obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD4000) += ad4000.o diff --git a/include/linux/mfd/88pm886.h b/include/linux/mfd/88pm886.h index 85eca44f39ab..38892ba7b8a4 100644 --- a/include/linux/mfd/88pm886.h +++ b/include/linux/mfd/88pm886.h @@ -10,6 +10,7 @@ #define PM886_IRQ_ONKEY 0 #define PM886_PAGE_OFFSET_REGULATORS 1 +#define PM886_PAGE_OFFSET_GPADC 2 #define PM886_REG_ID 0x00 @@ -70,6 +71,63 @@ #define PM886_LDO_VSEL_MASK 0x0f #define PM886_BUCK_VSEL_MASK 0x7f +/* GPADC enable/disable registers */ +#define PM886_REG_GPADC_CONFIG(n) (n) + +#define PM886_GPADC_VSC_EN BIT(0) +#define PM886_GPADC_VBAT_EN BIT(1) +#define PM886_GPADC_GNDDET1_EN BIT(3) +#define PM886_GPADC_VBUS_EN BIT(4) +#define PM886_GPADC_VCHG_PWR_EN BIT(5) +#define PM886_GPADC_VCF_OUT_EN BIT(6) +#define PM886_GPADC_CONFIG1_EN_ALL \ + (PM886_GPADC_VSC_EN | \ + PM886_GPADC_VBAT_EN | \ + PM886_GPADC_GNDDET1_EN | \ + PM886_GPADC_VBUS_EN | \ + PM886_GPADC_VCHG_PWR_EN | \ + PM886_GPADC_VCF_OUT_EN) + +#define PM886_GPADC_TINT_EN BIT(0) +#define PM886_GPADC_PMODE_EN BIT(1) +#define PM886_GPADC_GPADC0_EN BIT(2) +#define PM886_GPADC_GPADC1_EN BIT(3) +#define PM886_GPADC_GPADC2_EN BIT(4) +#define PM886_GPADC_GPADC3_EN BIT(5) +#define PM886_GPADC_MIC_DET_EN BIT(6) +#define PM886_GPADC_CONFIG2_EN_ALL \ + (PM886_GPADC_TINT_EN | \ + PM886_GPADC_GPADC0_EN | \ + PM886_GPADC_GPADC1_EN | \ + PM886_GPADC_GPADC2_EN | \ + PM886_GPADC_GPADC3_EN | \ + PM886_GPADC_MIC_DET_EN) + +/* No CONFIG3_EN_ALL because this is the only bit there. */ +#define PM886_GPADC_GND_DET2_EN BIT(0) + +/* GPADC channel registers */ +#define PM886_REG_GPADC_VSC 0x40 +#define PM886_REG_GPADC_VCHG_PWR 0x4c +#define PM886_REG_GPADC_VCF_OUT 0x4e +#define PM886_REG_GPADC_TINT 0x50 +#define PM886_REG_GPADC_GPADC0 0x54 +#define PM886_REG_GPADC_GPADC1 0x56 +#define PM886_REG_GPADC_GPADC2 0x58 +#define PM886_REG_GPADC_VBAT 0xa0 +#define PM886_REG_GPADC_GND_DET1 0xa4 +#define PM886_REG_GPADC_GND_DET2 0xa6 +#define PM886_REG_GPADC_VBUS 0xa8 +#define PM886_REG_GPADC_GPADC3 0xaa +#define PM886_REG_GPADC_MIC_DET 0xac +#define PM886_REG_GPADC_VBAT_SLP 0xb0 + +/* VBAT_SLP is the last register and is 2 bytes wide like other channels. */ +#define PM886_GPADC_MAX_REGISTER (PM886_REG_GPADC_VBAT_SLP + 1) + +#define PM886_GPADC_BIAS_LEVELS 16 +#define PM886_GPADC_INDEX_TO_BIAS_uA(i) (1 + (i) * 5) + struct pm886_chip { struct i2c_client *client; unsigned int chip_id; From 63cc48ea772e0aa9633ce91e70f6a7756d4060c9 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 12 Sep 2025 14:09:30 -0500 Subject: [PATCH 1402/2711] iio: adc: ad7173: rename ad7173_chan_spec_ext_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename ad7173_calibsys_ext_info[] to ad7173_chan_spec_ext_info[]. This array is not limited to calibration attributes, so the name should be more generic. Reviewed-by: Nuno Sá Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 2dd09b177734..4eb936c7868a 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -369,7 +369,7 @@ static const struct iio_enum ad7173_syscalib_mode_enum = { .get = ad7173_get_syscalib_mode }; -static const struct iio_chan_spec_ext_info ad7173_calibsys_ext_info[] = { +static const struct iio_chan_spec_ext_info ad7173_chan_spec_ext_info[] = { { .name = "sys_calibration", .write = ad7173_write_syscalib, @@ -1399,7 +1399,7 @@ static const struct iio_chan_spec ad7173_channel_template = { .storagebits = 32, .endianness = IIO_BE, }, - .ext_info = ad7173_calibsys_ext_info, + .ext_info = ad7173_chan_spec_ext_info, }; static const struct iio_chan_spec ad7173_temp_iio_channel_template = { From 27901cbc5bbcd4dbe0514999e08304074988a5d7 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 12 Sep 2025 14:09:31 -0500 Subject: [PATCH 1403/2711] iio: adc: ad7173: rename odr field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename odr to sinc5_odr_index in the channel setup structure. In a following commit, we will be adding a separate odr field for when the sinc3 filter is used instead so having sinc5 in the name will help avoid confusion. And _index makes it more clear that this is an index of the sinc5_data_rates array and not the output data rate itself. Reviewed-by: Nuno Sá Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 4eb936c7868a..dece394cc023 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -205,7 +205,7 @@ struct ad7173_channel_config { struct_group(config_props, bool bipolar; bool input_buf; - u8 odr; + u8 sinc5_odr_index; u8 ref_sel; ); }; @@ -582,13 +582,13 @@ static bool ad7173_is_setup_equal(const struct ad7173_channel_config *cfg1, sizeof(struct { bool bipolar; bool input_buf; - u8 odr; + u8 sinc5_odr_index; u8 ref_sel; })); return cfg1->bipolar == cfg2->bipolar && cfg1->input_buf == cfg2->input_buf && - cfg1->odr == cfg2->odr && + cfg1->sinc5_odr_index == cfg2->sinc5_odr_index && cfg1->ref_sel == cfg2->ref_sel; } @@ -650,7 +650,7 @@ static int ad7173_load_config(struct ad7173_state *st, return ret; return ad_sd_write_reg(&st->sd, AD7173_REG_FILTER(free_cfg_slot), 2, - AD7173_FILTER_ODR0_MASK & cfg->odr); + AD7173_FILTER_ODR0_MASK & cfg->sinc5_odr_index); } static int ad7173_config_channel(struct ad7173_state *st, int addr) @@ -1183,7 +1183,7 @@ static int ad7173_read_raw(struct iio_dev *indio_dev, return -EINVAL; } case IIO_CHAN_INFO_SAMP_FREQ: - reg = st->channels[chan->address].cfg.odr; + reg = st->channels[chan->address].cfg.sinc5_odr_index; *val = st->info->sinc5_data_rates[reg] / MILLI; *val2 = (st->info->sinc5_data_rates[reg] % MILLI) * (MICRO / MILLI); @@ -1229,7 +1229,7 @@ static int ad7173_write_raw(struct iio_dev *indio_dev, break; cfg = &st->channels[chan->address].cfg; - cfg->odr = i; + cfg->sinc5_odr_index = i; cfg->live = false; break; @@ -1655,7 +1655,7 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) chan_st_priv->cfg.bipolar = false; chan_st_priv->cfg.input_buf = st->info->has_input_buf; chan_st_priv->cfg.ref_sel = AD7173_SETUP_REF_SEL_INT_REF; - chan_st_priv->cfg.odr = st->info->odr_start_value; + chan_st_priv->cfg.sinc5_odr_index = st->info->odr_start_value; chan_st_priv->cfg.openwire_comp_chan = -1; st->adc_mode |= AD7173_ADC_MODE_REF_EN; if (st->info->data_reg_only_16bit) @@ -1727,7 +1727,7 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) chan->scan_index = chan_index; chan->channel = ain[0]; chan_st_priv->cfg.input_buf = st->info->has_input_buf; - chan_st_priv->cfg.odr = st->info->odr_start_value; + chan_st_priv->cfg.sinc5_odr_index = st->info->odr_start_value; chan_st_priv->cfg.openwire_comp_chan = -1; chan_st_priv->cfg.bipolar = fwnode_property_read_bool(child, "bipolar"); From ff06b39be1a1f5c97a6095e03a519967966819fe Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 12 Sep 2025 14:09:32 -0500 Subject: [PATCH 1404/2711] iio: adc: ad7173: support changing filter type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for changing the filter type to the ad7173 driver. This family of chips by default uses a sinc5+sinc1 filter. There are also optional post-filters that can be added in this configuration for various 50/60Hz rejection purposes. The sinc3 filter doesn't have any post-filters and handles the output data rate (ODR) a bit differently. Here, we've opted to use SINC3_MAPx to get the maximum possible sampling frequencies with the SINC3 filter. Adding support consists of adding the filter_type and filter_type_available attributes, making the sampling_frequency attribute aware of the filter type, and programming the filter parameters when we configure the channel of the ADC for reading a sample. Reviewed-by: Nuno Sá Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 186 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 181 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index dece394cc023..d36612352b44 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -8,6 +8,7 @@ * AD7175-8/AD7176-2/AD7177-2 * * Copyright (C) 2015, 2024 Analog Devices, Inc. + * Copyright (C) 2025 BayLibre, SAS */ #include @@ -149,7 +150,12 @@ (pin2) < st->info->num_voltage_in && \ (pin2) >= st->info->num_voltage_in_div) -#define AD7173_FILTER_ODR0_MASK GENMASK(5, 0) +#define AD7173_FILTER_SINC3_MAP BIT(15) +#define AD7173_FILTER_SINC3_MAP_DIV GENMASK(14, 0) +#define AD7173_FILTER_ENHFILTEN BIT(11) +#define AD7173_FILTER_ENHFILT_MASK GENMASK(10, 8) +#define AD7173_FILTER_ORDER BIT(6) +#define AD7173_FILTER_ODR_MASK GENMASK(5, 0) #define AD7173_MAX_CONFIGS 8 #define AD4111_OW_DET_THRSH_MV 300 @@ -190,6 +196,15 @@ struct ad7173_device_info { u8 num_gpios; }; +enum ad7173_filter_type { + AD7173_FILTER_SINC3, + AD7173_FILTER_SINC5_SINC1, + AD7173_FILTER_SINC5_SINC1_PF1, + AD7173_FILTER_SINC5_SINC1_PF2, + AD7173_FILTER_SINC5_SINC1_PF3, + AD7173_FILTER_SINC5_SINC1_PF4, +}; + struct ad7173_channel_config { /* Openwire detection threshold */ unsigned int openwire_thrsh_raw; @@ -205,8 +220,10 @@ struct ad7173_channel_config { struct_group(config_props, bool bipolar; bool input_buf; + u16 sinc3_odr_div; u8 sinc5_odr_index; u8 ref_sel; + enum ad7173_filter_type filter_type; ); }; @@ -266,6 +283,24 @@ static const unsigned int ad7175_sinc5_data_rates[] = { 5000, /* 20 */ }; +/** + * ad7173_sinc3_odr_div_from_odr() - Convert ODR to divider value + * @odr_millihz: ODR (sampling_frequency) in milliHz + * Returns: Divider value for SINC3 filter to pass. + */ +static u16 ad7173_sinc3_odr_div_from_odr(u32 odr_millihz) +{ + /* + * Divider is f_MOD (1 MHz) / 32 / ODR. ODR freq is in milliHz, so + * we need to convert f_MOD to the same units. When SING_CYC=1 or + * multiple channels are enabled (currently always the case), there + * is an additional factor of 3. + */ + u32 div = DIV_ROUND_CLOSEST(MEGA * MILLI, odr_millihz * 32 * 3); + /* Avoid divide by 0 and limit to register field size. */ + return clamp(div, 1U, AD7173_FILTER_SINC3_MAP_DIV); +} + static unsigned int ad4111_current_channel_config[] = { /* Ain sel: pos neg */ 0x1E8, /* 15:IIN0+ 8:IIN0− */ @@ -369,6 +404,47 @@ static const struct iio_enum ad7173_syscalib_mode_enum = { .get = ad7173_get_syscalib_mode }; +static const char * const ad7173_filter_types_str[] = { + [AD7173_FILTER_SINC3] = "sinc3", + [AD7173_FILTER_SINC5_SINC1] = "sinc5+sinc1", + [AD7173_FILTER_SINC5_SINC1_PF1] = "sinc5+sinc1+pf1", + [AD7173_FILTER_SINC5_SINC1_PF2] = "sinc5+sinc1+pf2", + [AD7173_FILTER_SINC5_SINC1_PF3] = "sinc5+sinc1+pf3", + [AD7173_FILTER_SINC5_SINC1_PF4] = "sinc5+sinc1+pf4", +}; + +static int ad7173_set_filter_type(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int val) +{ + struct ad7173_state *st = iio_priv(indio_dev); + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + st->channels[chan->address].cfg.filter_type = val; + st->channels[chan->address].cfg.live = false; + + iio_device_release_direct(indio_dev); + + return 0; +} + +static int ad7173_get_filter_type(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad7173_state *st = iio_priv(indio_dev); + + return st->channels[chan->address].cfg.filter_type; +} + +static const struct iio_enum ad7173_filter_type_enum = { + .items = ad7173_filter_types_str, + .num_items = ARRAY_SIZE(ad7173_filter_types_str), + .set = ad7173_set_filter_type, + .get = ad7173_get_filter_type, +}; + static const struct iio_chan_spec_ext_info ad7173_chan_spec_ext_info[] = { { .name = "sys_calibration", @@ -379,6 +455,16 @@ static const struct iio_chan_spec_ext_info ad7173_chan_spec_ext_info[] = { &ad7173_syscalib_mode_enum), IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE, &ad7173_syscalib_mode_enum), + IIO_ENUM("filter_type", IIO_SEPARATE, &ad7173_filter_type_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_TYPE, + &ad7173_filter_type_enum), + { } +}; + +static const struct iio_chan_spec_ext_info ad7173_temp_chan_spec_ext_info[] = { + IIO_ENUM("filter_type", IIO_SEPARATE, &ad7173_filter_type_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_TYPE, + &ad7173_filter_type_enum), { } }; @@ -582,14 +668,18 @@ static bool ad7173_is_setup_equal(const struct ad7173_channel_config *cfg1, sizeof(struct { bool bipolar; bool input_buf; + u16 sinc3_odr_div; u8 sinc5_odr_index; u8 ref_sel; + enum ad7173_filter_type filter_type; })); return cfg1->bipolar == cfg2->bipolar && cfg1->input_buf == cfg2->input_buf && + cfg1->sinc3_odr_div == cfg2->sinc3_odr_div && cfg1->sinc5_odr_index == cfg2->sinc5_odr_index && - cfg1->ref_sel == cfg2->ref_sel; + cfg1->ref_sel == cfg2->ref_sel && + cfg1->filter_type == cfg2->filter_type; } static struct ad7173_channel_config * @@ -630,6 +720,7 @@ static int ad7173_load_config(struct ad7173_state *st, { unsigned int config; int free_cfg_slot, ret; + u8 post_filter_enable, post_filter_select; free_cfg_slot = ida_alloc_range(&st->cfg_slots_status, 0, st->info->num_configs - 1, GFP_KERNEL); @@ -649,8 +740,49 @@ static int ad7173_load_config(struct ad7173_state *st, if (ret) return ret; + /* + * When SINC3_MAP flag is enabled, the rest of the register has a + * different meaning. We are using this option to allow the most + * possible sampling frequencies with SINC3 filter. + */ + if (cfg->filter_type == AD7173_FILTER_SINC3) + return ad_sd_write_reg(&st->sd, AD7173_REG_FILTER(free_cfg_slot), 2, + FIELD_PREP(AD7173_FILTER_SINC3_MAP, 1) | + FIELD_PREP(AD7173_FILTER_SINC3_MAP_DIV, + cfg->sinc3_odr_div)); + + switch (cfg->filter_type) { + case AD7173_FILTER_SINC5_SINC1_PF1: + post_filter_enable = 1; + post_filter_select = 2; + break; + case AD7173_FILTER_SINC5_SINC1_PF2: + post_filter_enable = 1; + post_filter_select = 3; + break; + case AD7173_FILTER_SINC5_SINC1_PF3: + post_filter_enable = 1; + post_filter_select = 5; + break; + case AD7173_FILTER_SINC5_SINC1_PF4: + post_filter_enable = 1; + post_filter_select = 6; + break; + default: + post_filter_enable = 0; + post_filter_select = 0; + break; + } + return ad_sd_write_reg(&st->sd, AD7173_REG_FILTER(free_cfg_slot), 2, - AD7173_FILTER_ODR0_MASK & cfg->sinc5_odr_index); + FIELD_PREP(AD7173_FILTER_SINC3_MAP, 0) | + FIELD_PREP(AD7173_FILTER_ENHFILT_MASK, + post_filter_enable) | + FIELD_PREP(AD7173_FILTER_ENHFILTEN, + post_filter_select) | + FIELD_PREP(AD7173_FILTER_ORDER, 0) | + FIELD_PREP(AD7173_FILTER_ODR_MASK, + cfg->sinc5_odr_index)); } static int ad7173_config_channel(struct ad7173_state *st, int addr) @@ -1183,6 +1315,13 @@ static int ad7173_read_raw(struct iio_dev *indio_dev, return -EINVAL; } case IIO_CHAN_INFO_SAMP_FREQ: + if (st->channels[chan->address].cfg.filter_type == AD7173_FILTER_SINC3) { + /* Inverse operation of ad7173_sinc3_odr_div_from_odr() */ + *val = MEGA; + *val2 = 3 * 32 * st->channels[chan->address].cfg.sinc3_odr_div; + return IIO_VAL_FRACTIONAL; + } + reg = st->channels[chan->address].cfg.sinc5_odr_index; *val = st->info->sinc5_data_rates[reg] / MILLI; @@ -1221,6 +1360,10 @@ static int ad7173_write_raw(struct iio_dev *indio_dev, * * This will cause the reading of CH1 to be actually done once every * 200.16ms, an effective rate of 4.99sps. + * + * Both the sinc5 and sinc3 rates are set here so that if the filter + * type is changed, the requested rate will still be set (aside from + * rounding differences). */ case IIO_CHAN_INFO_SAMP_FREQ: freq = val * MILLI + val2 / MILLI; @@ -1230,6 +1373,7 @@ static int ad7173_write_raw(struct iio_dev *indio_dev, cfg = &st->channels[chan->address].cfg; cfg->sinc5_odr_index = i; + cfg->sinc3_odr_div = ad7173_sinc3_odr_div_from_odr(freq); cfg->live = false; break; @@ -1246,17 +1390,40 @@ static int ad7173_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct ad7173_state *st = iio_priv(indio_dev); + u16 sinc3_count = 0; + u16 sinc3_div = 0; int i, j, k, ret; for (i = 0; i < indio_dev->num_channels; i++) { - if (test_bit(i, scan_mask)) + const struct ad7173_channel_config *cfg = &st->channels[i].cfg; + + if (test_bit(i, scan_mask)) { + if (cfg->filter_type == AD7173_FILTER_SINC3) { + sinc3_count++; + + if (sinc3_div == 0) { + sinc3_div = cfg->sinc3_odr_div; + } else if (sinc3_div != cfg->sinc3_odr_div) { + dev_err(&st->sd.spi->dev, + "All enabled channels must have the same sampling_frequency for sinc3 filter_type\n"); + return -EINVAL; + } + } + ret = ad7173_set_channel(&st->sd, i); - else + } else { ret = ad_sd_write_reg(&st->sd, AD7173_REG_CH(i), 2, 0); + } if (ret < 0) return ret; } + if (sinc3_count && sinc3_count < bitmap_weight(scan_mask, indio_dev->num_channels)) { + dev_err(&st->sd.spi->dev, + "All enabled channels must have sinc3 filter_type\n"); + return -EINVAL; + } + /* * On some chips, there are more channels that setups, so if there were * more unique setups requested than the number of available slots, @@ -1415,6 +1582,7 @@ static const struct iio_chan_spec ad7173_temp_iio_channel_template = { .storagebits = 32, .endianness = IIO_BE, }, + .ext_info = ad7173_temp_chan_spec_ext_info, }; static void ad7173_disable_regulators(void *data) @@ -1655,7 +1823,11 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) chan_st_priv->cfg.bipolar = false; chan_st_priv->cfg.input_buf = st->info->has_input_buf; chan_st_priv->cfg.ref_sel = AD7173_SETUP_REF_SEL_INT_REF; + chan_st_priv->cfg.sinc3_odr_div = ad7173_sinc3_odr_div_from_odr( + st->info->sinc5_data_rates[st->info->odr_start_value] + ); chan_st_priv->cfg.sinc5_odr_index = st->info->odr_start_value; + chan_st_priv->cfg.filter_type = AD7173_FILTER_SINC5_SINC1; chan_st_priv->cfg.openwire_comp_chan = -1; st->adc_mode |= AD7173_ADC_MODE_REF_EN; if (st->info->data_reg_only_16bit) @@ -1727,7 +1899,11 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) chan->scan_index = chan_index; chan->channel = ain[0]; chan_st_priv->cfg.input_buf = st->info->has_input_buf; + chan_st_priv->cfg.sinc3_odr_div = ad7173_sinc3_odr_div_from_odr( + st->info->sinc5_data_rates[st->info->odr_start_value] + ); chan_st_priv->cfg.sinc5_odr_index = st->info->odr_start_value; + chan_st_priv->cfg.filter_type = AD7173_FILTER_SINC5_SINC1; chan_st_priv->cfg.openwire_comp_chan = -1; chan_st_priv->cfg.bipolar = fwnode_property_read_bool(child, "bipolar"); From bf99115eb2b8e7022e497290c1d4c585b56a6926 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 12 Sep 2025 14:09:33 -0500 Subject: [PATCH 1405/2711] iio: ABI: add filter types for ad7173 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new filter types used in the ad7173 driver to the IIO ABI documentation. These chips have a few filter types that haven't been seen before in other drivers. Reviewed-by: Nuno Sá Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 43ca01251c4e..89b4740dcfa1 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -2327,6 +2327,11 @@ Description: performance * "sinc5+avg" - Sinc5 + averaging by 4. * "sinc5+pf1" - Sinc5 + device specific Post Filter 1. + * "sinc5+sinc1" - Sinc5 + Sinc1. + * "sinc5+sinc1+pf1" - Sinc5 + Sinc1 + device specific Post Filter 1. + * "sinc5+sinc1+pf2" - Sinc5 + Sinc1 + device specific Post Filter 2. + * "sinc5+sinc1+pf3" - Sinc5 + Sinc1 + device specific Post Filter 3. + * "sinc5+sinc1+pf4" - Sinc5 + Sinc1 + device specific Post Filter 4. * "wideband" - filter with wideband low ripple passband and sharp transition band. From 6233067494ae034484882e37ece378fa08bca6a4 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Mon, 18 Aug 2025 10:27:31 +0100 Subject: [PATCH 1406/2711] iio: pressure: bmp280: Remove noisy dev_info() Remove `dev_info()` call as it was considered noisy and is not necessary for normal driver operation. Signed-off-by: Salah Triki Reviewed-by: David Lechner Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 48e76d907180..cf3f34f7bd7e 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -3212,7 +3212,6 @@ int bmp280_common_probe(struct device *dev, return dev_err_probe(dev, PTR_ERR(gpiod), "failed to get reset GPIO\n"); /* Deassert the signal */ - dev_info(dev, "release reset\n"); gpiod_set_value(gpiod, 0); data->regmap = regmap; From 671b9b6d7f4fe17a174c410397e72253877ca64e Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sun, 24 Aug 2025 13:06:09 +0100 Subject: [PATCH 1407/2711] iio: pressure: bmp280: Use gpiod_set_value_cansleep() Replace `gpiod_set_value()` with `gpiod_set_value_cansleep()`, which is required when the GPIO controller is connected via a slow bus such as I2C. This is also safe to use in sleepable contexts like the driver probe function. Signed-off-by: Salah Triki Reviewed-by: David Lechner Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index cf3f34f7bd7e..c04e8bb4c993 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -3212,7 +3212,7 @@ int bmp280_common_probe(struct device *dev, return dev_err_probe(dev, PTR_ERR(gpiod), "failed to get reset GPIO\n"); /* Deassert the signal */ - gpiod_set_value(gpiod, 0); + gpiod_set_value_cansleep(gpiod, 0); data->regmap = regmap; From 3acb913c9d5bd8dcf61677ccba96d349e7681cf8 Mon Sep 17 00:00:00 2001 From: "Mike Rapoport (Microsoft)" Date: Mon, 18 Aug 2025 09:46:12 +0300 Subject: [PATCH 1408/2711] mm/mm_init: use deferred_init_memmap_chunk() in deferred_grow_zone() deferred_grow_zone() initializes one or more sections in the memory map if buddy runs out of initialized struct pages when CONFIG_DEFERRED_STRUCT_PAGE_INIT is enabled. It loops through memblock regions and initializes and frees pages in MAX_ORDER_NR_PAGES chunks. Essentially the same loop is implemented in deferred_init_memmap_chunk(), the only actual difference is that deferred_init_memmap_chunk() does not count initialized pages. Make deferred_init_memmap_chunk() count the initialized pages and return their number, wrap it with deferred_init_memmap_job() for multithreaded initialization with padata_do_multithreaded() and replace open-coded initialization of struct pages in deferred_grow_zone() with a call to deferred_init_memmap_chunk(). Reviewed-by: David Hildenbrand Reviewed-by: Wei Yang Signed-off-by: Mike Rapoport (Microsoft) --- mm/mm_init.c | 70 +++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/mm/mm_init.c b/mm/mm_init.c index 5c21b3af216b..e73f313dc375 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -2134,12 +2134,12 @@ deferred_init_maxorder(u64 *i, struct zone *zone, unsigned long *start_pfn, return nr_pages; } -static void __init +static unsigned long __init deferred_init_memmap_chunk(unsigned long start_pfn, unsigned long end_pfn, - void *arg) + struct zone *zone) { + unsigned long nr_pages = 0; unsigned long spfn, epfn; - struct zone *zone = arg; u64 i = 0; deferred_init_mem_pfn_range_in_zone(&i, zone, &spfn, &epfn, start_pfn); @@ -2149,9 +2149,23 @@ deferred_init_memmap_chunk(unsigned long start_pfn, unsigned long end_pfn, * we can avoid introducing any issues with the buddy allocator. */ while (spfn < end_pfn) { - deferred_init_maxorder(&i, zone, &spfn, &epfn); - cond_resched(); + nr_pages += deferred_init_maxorder(&i, zone, &spfn, &epfn); + if (irqs_disabled()) + touch_nmi_watchdog(); + else + cond_resched(); } + + return nr_pages; +} + +static void __init +deferred_init_memmap_job(unsigned long start_pfn, unsigned long end_pfn, + void *arg) +{ + struct zone *zone = arg; + + deferred_init_memmap_chunk(start_pfn, end_pfn, zone); } static unsigned int __init @@ -2204,7 +2218,7 @@ static int __init deferred_init_memmap(void *data) while (deferred_init_mem_pfn_range_in_zone(&i, zone, &spfn, &epfn, first_init_pfn)) { first_init_pfn = ALIGN(epfn, PAGES_PER_SECTION); struct padata_mt_job job = { - .thread_fn = deferred_init_memmap_chunk, + .thread_fn = deferred_init_memmap_job, .fn_arg = zone, .start = spfn, .size = first_init_pfn - spfn, @@ -2240,12 +2254,11 @@ static int __init deferred_init_memmap(void *data) */ bool __init deferred_grow_zone(struct zone *zone, unsigned int order) { - unsigned long nr_pages_needed = ALIGN(1 << order, PAGES_PER_SECTION); + unsigned long nr_pages_needed = SECTION_ALIGN_UP(1 << order); pg_data_t *pgdat = zone->zone_pgdat; unsigned long first_deferred_pfn = pgdat->first_deferred_pfn; unsigned long spfn, epfn, flags; unsigned long nr_pages = 0; - u64 i = 0; /* Only the last zone may have deferred pages */ if (zone_end_pfn(zone) != pgdat_end_pfn(pgdat)) @@ -2262,37 +2275,26 @@ bool __init deferred_grow_zone(struct zone *zone, unsigned int order) return true; } - /* If the zone is empty somebody else may have cleared out the zone */ - if (!deferred_init_mem_pfn_range_in_zone(&i, zone, &spfn, &epfn, - first_deferred_pfn)) { - pgdat->first_deferred_pfn = ULONG_MAX; - pgdat_resize_unlock(pgdat, &flags); - /* Retry only once. */ - return first_deferred_pfn != ULONG_MAX; + /* + * Initialize at least nr_pages_needed in section chunks. + * If a section has less free memory than nr_pages_needed, the next + * section will be also initialized. + * Note, that it still does not guarantee that allocation of order can + * be satisfied if the sections are fragmented because of memblock + * allocations. + */ + for (spfn = first_deferred_pfn, epfn = SECTION_ALIGN_UP(spfn + 1); + nr_pages < nr_pages_needed && spfn < zone_end_pfn(zone); + spfn = epfn, epfn += PAGES_PER_SECTION) { + nr_pages += deferred_init_memmap_chunk(spfn, epfn, zone); } /* - * Initialize and free pages in MAX_PAGE_ORDER sized increments so - * that we can avoid introducing any issues with the buddy - * allocator. + * There were no pages to initialize and free which means the zone's + * memory map is completely initialized. */ - while (spfn < epfn) { - /* update our first deferred PFN for this section */ - first_deferred_pfn = spfn; + pgdat->first_deferred_pfn = nr_pages ? spfn : ULONG_MAX; - nr_pages += deferred_init_maxorder(&i, zone, &spfn, &epfn); - touch_nmi_watchdog(); - - /* We should only stop along section boundaries */ - if ((first_deferred_pfn ^ spfn) < PAGES_PER_SECTION) - continue; - - /* If our quota has been met we can stop here */ - if (nr_pages >= nr_pages_needed) - break; - } - - pgdat->first_deferred_pfn = spfn; pgdat_resize_unlock(pgdat, &flags); return nr_pages > 0; From f1f86187fd72332ef214716a3c5b71616c0d340e Mon Sep 17 00:00:00 2001 From: "Mike Rapoport (Microsoft)" Date: Mon, 18 Aug 2025 09:46:13 +0300 Subject: [PATCH 1409/2711] mm/mm_init: deferred_init_memmap: use a job per zone deferred_init_memmap() loops over free memory ranges and creates a padata_mt_job for every free range that intersects with the zone being initialized. padata_do_multithreaded() then splits every such range to several chunks and runs a thread that initializes struct pages in that chunk using deferred_init_memmap_chunk(). The number of threads is limited by amount of the CPUs on the node (or 1 for memoryless nodes). Looping through free memory ranges is then repeated in deferred_init_memmap_chunk() first to find the first range that should be initialized and then to traverse the ranges until the end of the chunk is reached. Remove the loop over free memory regions in deferred_init_memmap() and pass the entire zone to padata_do_multithreaded() so that it will be divided to several chunks by the parallelization code. Reviewed-by: David Hildenbrand Reviewed-by: Wei Yang Signed-off-by: Mike Rapoport (Microsoft) --- mm/mm_init.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/mm/mm_init.c b/mm/mm_init.c index e73f313dc375..57b256ea9e6c 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -2179,12 +2179,10 @@ static int __init deferred_init_memmap(void *data) { pg_data_t *pgdat = data; const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id); - unsigned long spfn = 0, epfn = 0; - unsigned long first_init_pfn, flags; + int max_threads = deferred_page_init_max_threads(cpumask); + unsigned long first_init_pfn, last_pfn, flags; unsigned long start = jiffies; struct zone *zone; - int max_threads; - u64 i = 0; /* Bind memory initialisation thread to a local node if possible */ if (!cpumask_empty(cpumask)) @@ -2212,24 +2210,20 @@ static int __init deferred_init_memmap(void *data) /* Only the highest zone is deferred */ zone = pgdat->node_zones + pgdat->nr_zones - 1; + last_pfn = SECTION_ALIGN_UP(zone_end_pfn(zone)); - max_threads = deferred_page_init_max_threads(cpumask); + struct padata_mt_job job = { + .thread_fn = deferred_init_memmap_job, + .fn_arg = zone, + .start = first_init_pfn, + .size = last_pfn - first_init_pfn, + .align = PAGES_PER_SECTION, + .min_chunk = PAGES_PER_SECTION, + .max_threads = max_threads, + .numa_aware = false, + }; - while (deferred_init_mem_pfn_range_in_zone(&i, zone, &spfn, &epfn, first_init_pfn)) { - first_init_pfn = ALIGN(epfn, PAGES_PER_SECTION); - struct padata_mt_job job = { - .thread_fn = deferred_init_memmap_job, - .fn_arg = zone, - .start = spfn, - .size = first_init_pfn - spfn, - .align = PAGES_PER_SECTION, - .min_chunk = PAGES_PER_SECTION, - .max_threads = max_threads, - .numa_aware = false, - }; - - padata_do_multithreaded(&job); - } + padata_do_multithreaded(&job); /* Sanity check that the next zone really is unpopulated */ WARN_ON(pgdat->nr_zones < MAX_NR_ZONES && populated_zone(++zone)); From 219f624d0690459440c5c4d4ebfc54f0d440d615 Mon Sep 17 00:00:00 2001 From: "Mike Rapoport (Microsoft)" Date: Mon, 18 Aug 2025 09:46:14 +0300 Subject: [PATCH 1410/2711] mm/mm_init: drop deferred_init_maxorder() deferred_init_memmap_chunk() calls deferred_init_maxorder() to initialize struct pages in MAX_ORDER_NR_PAGES because according to commit 0e56acae4b4d ("mm: initialize MAX_ORDER_NR_PAGES at a time instead of doing larger sections") this provides better cache locality than initializing the memory map in larger sections. The looping through free memory ranges is quite cumbersome in the current implementation as it is divided between deferred_init_memmap_chunk() and deferred_init_maxorder(). Besides, the latter has two loops, one that initializes struct pages and another one that frees them. There is no need in two loops because it is safe to free pages in groups smaller than MAX_ORDER_NR_PAGES. Even if lookup for a buddy page will access a struct page ahead of the pages being initialized, that page is guaranteed to be initialized either by memmap_init_reserved_pages() or by init_unavailable_range(). Simplify the code by moving initialization and freeing of the pages into deferred_init_memmap_chunk() and dropping deferred_init_maxorder(). Reviewed-by: David Hildenbrand Reviewed-by: Wei Yang Signed-off-by: Mike Rapoport (Microsoft) --- mm/mm_init.c | 133 ++++++++++++++------------------------------------- 1 file changed, 35 insertions(+), 98 deletions(-) diff --git a/mm/mm_init.c b/mm/mm_init.c index 57b256ea9e6c..7e5e6984bb5d 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -2046,114 +2046,51 @@ static unsigned long __init deferred_init_pages(struct zone *zone, } /* - * This function is meant to pre-load the iterator for the zone init from - * a given point. - * Specifically it walks through the ranges starting with initial index - * passed to it until we are caught up to the first_init_pfn value and - * exits there. If we never encounter the value we return false indicating - * there are no valid ranges left. - */ -static bool __init -deferred_init_mem_pfn_range_in_zone(u64 *i, struct zone *zone, - unsigned long *spfn, unsigned long *epfn, - unsigned long first_init_pfn) -{ - u64 j = *i; - - if (j == 0) - __next_mem_pfn_range_in_zone(&j, zone, spfn, epfn); - - /* - * Start out by walking through the ranges in this zone that have - * already been initialized. We don't need to do anything with them - * so we just need to flush them out of the system. - */ - for_each_free_mem_pfn_range_in_zone_from(j, zone, spfn, epfn) { - if (*epfn <= first_init_pfn) - continue; - if (*spfn < first_init_pfn) - *spfn = first_init_pfn; - *i = j; - return true; - } - - return false; -} - -/* - * Initialize and free pages. We do it in two loops: first we initialize - * struct page, then free to buddy allocator, because while we are - * freeing pages we can access pages that are ahead (computing buddy - * page in __free_one_page()). + * Initialize and free pages. * - * In order to try and keep some memory in the cache we have the loop - * broken along max page order boundaries. This way we will not cause - * any issues with the buddy page computation. + * At this point reserved pages and struct pages that correspond to holes in + * memblock.memory are already intialized so every free range has a valid + * memory map around it. + * This ensures that access of pages that are ahead of the range being + * initialized (computing buddy page in __free_one_page()) always reads a valid + * struct page. + * + * In order to try and improve CPU cache locality we have the loop broken along + * max page order boundaries. */ -static unsigned long __init -deferred_init_maxorder(u64 *i, struct zone *zone, unsigned long *start_pfn, - unsigned long *end_pfn) -{ - unsigned long mo_pfn = ALIGN(*start_pfn + 1, MAX_ORDER_NR_PAGES); - unsigned long spfn = *start_pfn, epfn = *end_pfn; - unsigned long nr_pages = 0; - u64 j = *i; - - /* First we loop through and initialize the page values */ - for_each_free_mem_pfn_range_in_zone_from(j, zone, start_pfn, end_pfn) { - unsigned long t; - - if (mo_pfn <= *start_pfn) - break; - - t = min(mo_pfn, *end_pfn); - nr_pages += deferred_init_pages(zone, *start_pfn, t); - - if (mo_pfn < *end_pfn) { - *start_pfn = mo_pfn; - break; - } - } - - /* Reset values and now loop through freeing pages as needed */ - swap(j, *i); - - for_each_free_mem_pfn_range_in_zone_from(j, zone, &spfn, &epfn) { - unsigned long t; - - if (mo_pfn <= spfn) - break; - - t = min(mo_pfn, epfn); - deferred_free_pages(spfn, t - spfn); - - if (mo_pfn <= epfn) - break; - } - - return nr_pages; -} - static unsigned long __init deferred_init_memmap_chunk(unsigned long start_pfn, unsigned long end_pfn, struct zone *zone) { + int nid = zone_to_nid(zone); unsigned long nr_pages = 0; - unsigned long spfn, epfn; + phys_addr_t start, end; u64 i = 0; - deferred_init_mem_pfn_range_in_zone(&i, zone, &spfn, &epfn, start_pfn); + for_each_free_mem_range(i, nid, 0, &start, &end, NULL) { + unsigned long spfn = PFN_UP(start); + unsigned long epfn = PFN_DOWN(end); - /* - * Initialize and free pages in MAX_PAGE_ORDER sized increments so that - * we can avoid introducing any issues with the buddy allocator. - */ - while (spfn < end_pfn) { - nr_pages += deferred_init_maxorder(&i, zone, &spfn, &epfn); - if (irqs_disabled()) - touch_nmi_watchdog(); - else - cond_resched(); + if (spfn >= end_pfn) + break; + + spfn = max(spfn, start_pfn); + epfn = min(epfn, end_pfn); + + while (spfn < epfn) { + unsigned long mo_pfn = ALIGN(spfn + 1, MAX_ORDER_NR_PAGES); + unsigned long chunk_end = min(mo_pfn, epfn); + + nr_pages += deferred_init_pages(zone, spfn, chunk_end); + deferred_free_pages(spfn, chunk_end - spfn); + + spfn = chunk_end; + + if (irqs_disabled()) + touch_nmi_watchdog(); + else + cond_resched(); + } } return nr_pages; From e68f150bc11d0a05cbe984a4e5c0f72a95cae07d Mon Sep 17 00:00:00 2001 From: "Mike Rapoport (Microsoft)" Date: Mon, 18 Aug 2025 09:46:15 +0300 Subject: [PATCH 1411/2711] memblock: drop for_each_free_mem_pfn_range_in_zone_from() for_each_free_mem_pfn_range_in_zone_from() and its "backend" implementation __next_mem_pfn_range_in_zone() were only used by deferred initialization of the memory map. Remove them as they are not used anymore. Reviewed-by: Wei Yang Reviewed-by: David Hildenbrand Signed-off-by: Mike Rapoport (Microsoft) --- .clang-format | 1 - include/linux/memblock.h | 22 -------------- mm/memblock.c | 64 ---------------------------------------- 3 files changed, 87 deletions(-) diff --git a/.clang-format b/.clang-format index 48405c54ef27..f371a13b4d19 100644 --- a/.clang-format +++ b/.clang-format @@ -294,7 +294,6 @@ ForEachMacros: - 'for_each_fib6_node_rt_rcu' - 'for_each_fib6_walker_rt' - 'for_each_file_lock' - - 'for_each_free_mem_pfn_range_in_zone_from' - 'for_each_free_mem_range' - 'for_each_free_mem_range_reverse' - 'for_each_func_rsrc' diff --git a/include/linux/memblock.h b/include/linux/memblock.h index fcda8481de9a..221118b5a16e 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -324,28 +324,6 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn, for (i = -1, __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid); \ i >= 0; __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid)) -#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT -void __next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone, - unsigned long *out_spfn, - unsigned long *out_epfn); - -/** - * for_each_free_mem_pfn_range_in_zone_from - iterate through zone specific - * free memblock areas from a given point - * @i: u64 used as loop variable - * @zone: zone in which all of the memory blocks reside - * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL - * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL - * - * Walks over free (memory && !reserved) areas of memblock in a specific - * zone, continuing from current position. Available as soon as memblock is - * initialized. - */ -#define for_each_free_mem_pfn_range_in_zone_from(i, zone, p_start, p_end) \ - for (; i != U64_MAX; \ - __next_mem_pfn_range_in_zone(&i, zone, p_start, p_end)) - -#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ /** * for_each_free_mem_range - iterate through free memblock areas diff --git a/mm/memblock.c b/mm/memblock.c index 117d963e677c..120a501a887a 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1445,70 +1445,6 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size, return 0; } -#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT -/** - * __next_mem_pfn_range_in_zone - iterator for for_each_*_range_in_zone() - * - * @idx: pointer to u64 loop variable - * @zone: zone in which all of the memory blocks reside - * @out_spfn: ptr to ulong for start pfn of the range, can be %NULL - * @out_epfn: ptr to ulong for end pfn of the range, can be %NULL - * - * This function is meant to be a zone/pfn specific wrapper for the - * for_each_mem_range type iterators. Specifically they are used in the - * deferred memory init routines and as such we were duplicating much of - * this logic throughout the code. So instead of having it in multiple - * locations it seemed like it would make more sense to centralize this to - * one new iterator that does everything they need. - */ -void __init_memblock -__next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone, - unsigned long *out_spfn, unsigned long *out_epfn) -{ - int zone_nid = zone_to_nid(zone); - phys_addr_t spa, epa; - - __next_mem_range(idx, zone_nid, MEMBLOCK_NONE, - &memblock.memory, &memblock.reserved, - &spa, &epa, NULL); - - while (*idx != U64_MAX) { - unsigned long epfn = PFN_DOWN(epa); - unsigned long spfn = PFN_UP(spa); - - /* - * Verify the end is at least past the start of the zone and - * that we have at least one PFN to initialize. - */ - if (zone->zone_start_pfn < epfn && spfn < epfn) { - /* if we went too far just stop searching */ - if (zone_end_pfn(zone) <= spfn) { - *idx = U64_MAX; - break; - } - - if (out_spfn) - *out_spfn = max(zone->zone_start_pfn, spfn); - if (out_epfn) - *out_epfn = min(zone_end_pfn(zone), epfn); - - return; - } - - __next_mem_range(idx, zone_nid, MEMBLOCK_NONE, - &memblock.memory, &memblock.reserved, - &spa, &epa, NULL); - } - - /* signal end of iteration */ - if (out_spfn) - *out_spfn = ULONG_MAX; - if (out_epfn) - *out_epfn = 0; -} - -#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ - /** * memblock_alloc_range_nid - allocate boot memory block * @size: size of memory block to be allocated in bytes From 5aba939e80f439c1a67adb6d9cae23cc72db7ef9 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Fri, 29 Aug 2025 15:22:33 +0300 Subject: [PATCH 1412/2711] clk: tegra: dfll: Add CVB tables for Tegra114 Extend the Tegra124 DFLL driver to include configuration settings required for Tegra114 compatibility. Signed-off-by: Svyatoslav Ryhel Reviewed-by: Mikko Perttunen [treding@nvidia.com: Use TEGRA210 instead of T210] Signed-off-by: Thierry Reding --- drivers/clk/tegra/Kconfig | 2 +- drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 158 +++++++++++++++++---- 2 files changed, 132 insertions(+), 28 deletions(-) diff --git a/drivers/clk/tegra/Kconfig b/drivers/clk/tegra/Kconfig index 90df619dc087..62147a069606 100644 --- a/drivers/clk/tegra/Kconfig +++ b/drivers/clk/tegra/Kconfig @@ -4,7 +4,7 @@ config CLK_TEGRA_BPMP depends on TEGRA_BPMP config TEGRA_CLK_DFLL - depends on ARCH_TEGRA_124_SOC || ARCH_TEGRA_210_SOC + depends on ARCH_TEGRA_114_SOC || ARCH_TEGRA_124_SOC || ARCH_TEGRA_210_SOC select PM_OPP def_bool y diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index 0251618b82c8..457a77c5bb62 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -28,6 +28,99 @@ struct dfll_fcpu_data { unsigned int cpu_cvb_tables_size; }; +/* Maximum CPU frequency, indexed by CPU speedo id */ +static const unsigned long tegra114_cpu_max_freq_table[] = { + [0] = 2040000000UL, + [1] = 1810500000UL, + [2] = 1912500000UL, + [3] = 1810500000UL, +}; + +#define T114_CPU_CVB_TABLE \ + .min_millivolts = 1000, \ + .max_millivolts = 1320, \ + .speedo_scale = 100, \ + .voltage_scale = 1000, \ + .entries = { \ + { 306000000UL, { 2190643, -141851, 3576 } }, \ + { 408000000UL, { 2250968, -144331, 3576 } }, \ + { 510000000UL, { 2313333, -146811, 3576 } }, \ + { 612000000UL, { 2377738, -149291, 3576 } }, \ + { 714000000UL, { 2444183, -151771, 3576 } }, \ + { 816000000UL, { 2512669, -154251, 3576 } }, \ + { 918000000UL, { 2583194, -156731, 3576 } }, \ + { 1020000000UL, { 2655759, -159211, 3576 } }, \ + { 1122000000UL, { 2730365, -161691, 3576 } }, \ + { 1224000000UL, { 2807010, -164171, 3576 } }, \ + { 1326000000UL, { 2885696, -166651, 3576 } }, \ + { 1428000000UL, { 2966422, -169131, 3576 } }, \ + { 1530000000UL, { 3049183, -171601, 3576 } }, \ + { 1606500000UL, { 3112179, -173451, 3576 } }, \ + { 1708500000UL, { 3198504, -175931, 3576 } }, \ + { 1810500000UL, { 3304747, -179126, 3576 } }, \ + { 1912500000UL, { 3395401, -181606, 3576 } }, \ + { 0UL, { 0, 0, 0 } }, \ + }, \ + .cpu_dfll_data = { \ + .tune0_low = 0x00b0039d, \ + .tune0_high = 0x00b0009d, \ + .tune1 = 0x0000001f, \ + .tune_high_min_millivolts = 1050, \ + } + +static const struct cvb_table tegra114_cpu_cvb_tables[] = { + { + .speedo_id = 0, + .process_id = -1, + .min_millivolts = 1000, + .max_millivolts = 1250, + .speedo_scale = 100, + .voltage_scale = 100, + .entries = { + { 306000000UL, { 107330, -1569, 0 } }, + { 408000000UL, { 111250, -1666, 0 } }, + { 510000000UL, { 110000, -1460, 0 } }, + { 612000000UL, { 117290, -1745, 0 } }, + { 714000000UL, { 122700, -1910, 0 } }, + { 816000000UL, { 125620, -1945, 0 } }, + { 918000000UL, { 130560, -2076, 0 } }, + { 1020000000UL, { 137280, -2303, 0 } }, + { 1122000000UL, { 146440, -2660, 0 } }, + { 1224000000UL, { 152190, -2825, 0 } }, + { 1326000000UL, { 157520, -2953, 0 } }, + { 1428000000UL, { 166100, -3261, 0 } }, + { 1530000000UL, { 176410, -3647, 0 } }, + { 1632000000UL, { 189620, -4186, 0 } }, + { 1734000000UL, { 203190, -4725, 0 } }, + { 1836000000UL, { 222670, -5573, 0 } }, + { 1938000000UL, { 256210, -7165, 0 } }, + { 2040000000UL, { 250050, -6544, 0 } }, + { 0UL, { 0, 0, 0 } }, + }, + .cpu_dfll_data = { + .tune0_low = 0x00b0019d, + .tune0_high = 0x00b0019d, + .tune1 = 0x0000001f, + .tune_high_min_millivolts = 1000, + } + }, + { + .speedo_id = 1, + .process_id = -1, + T114_CPU_CVB_TABLE + }, + { + .speedo_id = 2, + .process_id = -1, + T114_CPU_CVB_TABLE + }, + { + .speedo_id = 3, + .process_id = -1, + T114_CPU_CVB_TABLE + }, +}; + /* Maximum CPU frequency, indexed by CPU speedo id */ static const unsigned long tegra124_cpu_max_freq_table[] = { [0] = 2014500000UL, @@ -93,7 +186,7 @@ static const unsigned long tegra210_cpu_max_freq_table[] = { [10] = 1504500000UL, }; -#define CPU_CVB_TABLE \ +#define TEGRA210_CPU_CVB_TABLE \ .speedo_scale = 100, \ .voltage_scale = 1000, \ .entries = { \ @@ -120,7 +213,7 @@ static const unsigned long tegra210_cpu_max_freq_table[] = { { 0UL, { 0, 0, 0 } }, \ } -#define CPU_CVB_TABLE_XA \ +#define TEGRA210_CPU_CVB_TABLE_XA \ .speedo_scale = 100, \ .voltage_scale = 1000, \ .entries = { \ @@ -143,7 +236,7 @@ static const unsigned long tegra210_cpu_max_freq_table[] = { { 0UL, { 0, 0, 0 } }, \ } -#define CPU_CVB_TABLE_EUCM1 \ +#define TEGRA210_CPU_CVB_TABLE_EUCM1 \ .speedo_scale = 100, \ .voltage_scale = 1000, \ .entries = { \ @@ -166,7 +259,7 @@ static const unsigned long tegra210_cpu_max_freq_table[] = { { 0UL, { 0, 0, 0 } }, \ } -#define CPU_CVB_TABLE_EUCM2 \ +#define TEGRA210_CPU_CVB_TABLE_EUCM2 \ .speedo_scale = 100, \ .voltage_scale = 1000, \ .entries = { \ @@ -188,7 +281,7 @@ static const unsigned long tegra210_cpu_max_freq_table[] = { { 0UL, { 0, 0, 0 } }, \ } -#define CPU_CVB_TABLE_EUCM2_JOINT_RAIL \ +#define TEGRA210_CPU_CVB_TABLE_EUCM2_JOINT_RAIL \ .speedo_scale = 100, \ .voltage_scale = 1000, \ .entries = { \ @@ -209,7 +302,7 @@ static const unsigned long tegra210_cpu_max_freq_table[] = { { 0UL, { 0, 0, 0 } }, \ } -#define CPU_CVB_TABLE_ODN \ +#define TEGRA210_CPU_CVB_TABLE_ODN \ .speedo_scale = 100, \ .voltage_scale = 1000, \ .entries = { \ @@ -238,7 +331,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 0, .min_millivolts = 840, .max_millivolts = 1120, - CPU_CVB_TABLE_EUCM2_JOINT_RAIL, + TEGRA210_CPU_CVB_TABLE_EUCM2_JOINT_RAIL, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -251,7 +344,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 1, .min_millivolts = 840, .max_millivolts = 1120, - CPU_CVB_TABLE_EUCM2_JOINT_RAIL, + TEGRA210_CPU_CVB_TABLE_EUCM2_JOINT_RAIL, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -264,7 +357,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 0, .min_millivolts = 900, .max_millivolts = 1162, - CPU_CVB_TABLE_EUCM2, + TEGRA210_CPU_CVB_TABLE_EUCM2, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -276,7 +369,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 1, .min_millivolts = 900, .max_millivolts = 1162, - CPU_CVB_TABLE_EUCM2, + TEGRA210_CPU_CVB_TABLE_EUCM2, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -288,7 +381,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 0, .min_millivolts = 900, .max_millivolts = 1195, - CPU_CVB_TABLE_EUCM2, + TEGRA210_CPU_CVB_TABLE_EUCM2, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -300,7 +393,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 1, .min_millivolts = 900, .max_millivolts = 1195, - CPU_CVB_TABLE_EUCM2, + TEGRA210_CPU_CVB_TABLE_EUCM2, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -312,7 +405,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 0, .min_millivolts = 841, .max_millivolts = 1227, - CPU_CVB_TABLE_EUCM1, + TEGRA210_CPU_CVB_TABLE_EUCM1, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -325,7 +418,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 1, .min_millivolts = 841, .max_millivolts = 1227, - CPU_CVB_TABLE_EUCM1, + TEGRA210_CPU_CVB_TABLE_EUCM1, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -338,7 +431,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 0, .min_millivolts = 870, .max_millivolts = 1150, - CPU_CVB_TABLE, + TEGRA210_CPU_CVB_TABLE, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune1 = 0x20091d9, @@ -349,7 +442,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 1, .min_millivolts = 870, .max_millivolts = 1150, - CPU_CVB_TABLE, + TEGRA210_CPU_CVB_TABLE, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune1 = 0x25501d0, @@ -360,7 +453,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 0, .min_millivolts = 818, .max_millivolts = 1227, - CPU_CVB_TABLE, + TEGRA210_CPU_CVB_TABLE, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -373,7 +466,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 1, .min_millivolts = 818, .max_millivolts = 1227, - CPU_CVB_TABLE, + TEGRA210_CPU_CVB_TABLE, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -386,7 +479,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = -1, .min_millivolts = 918, .max_millivolts = 1113, - CPU_CVB_TABLE_XA, + TEGRA210_CPU_CVB_TABLE_XA, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune1 = 0x17711BD, @@ -397,7 +490,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 0, .min_millivolts = 825, .max_millivolts = 1227, - CPU_CVB_TABLE_ODN, + TEGRA210_CPU_CVB_TABLE_ODN, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -410,7 +503,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 1, .min_millivolts = 825, .max_millivolts = 1227, - CPU_CVB_TABLE_ODN, + TEGRA210_CPU_CVB_TABLE_ODN, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -423,7 +516,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 0, .min_millivolts = 870, .max_millivolts = 1227, - CPU_CVB_TABLE, + TEGRA210_CPU_CVB_TABLE, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune1 = 0x20091d9, @@ -434,7 +527,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 1, .min_millivolts = 870, .max_millivolts = 1227, - CPU_CVB_TABLE, + TEGRA210_CPU_CVB_TABLE, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune1 = 0x25501d0, @@ -445,7 +538,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 0, .min_millivolts = 837, .max_millivolts = 1227, - CPU_CVB_TABLE, + TEGRA210_CPU_CVB_TABLE, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -458,7 +551,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 1, .min_millivolts = 837, .max_millivolts = 1227, - CPU_CVB_TABLE, + TEGRA210_CPU_CVB_TABLE, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -471,7 +564,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 0, .min_millivolts = 850, .max_millivolts = 1170, - CPU_CVB_TABLE, + TEGRA210_CPU_CVB_TABLE, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -484,7 +577,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { .process_id = 1, .min_millivolts = 850, .max_millivolts = 1170, - CPU_CVB_TABLE, + TEGRA210_CPU_CVB_TABLE, .cpu_dfll_data = { .tune0_low = 0xffead0ff, .tune0_high = 0xffead0ff, @@ -494,6 +587,13 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = { }, }; +static const struct dfll_fcpu_data tegra114_dfll_fcpu_data = { + .cpu_max_freq_table = tegra114_cpu_max_freq_table, + .cpu_max_freq_table_size = ARRAY_SIZE(tegra114_cpu_max_freq_table), + .cpu_cvb_tables = tegra114_cpu_cvb_tables, + .cpu_cvb_tables_size = ARRAY_SIZE(tegra114_cpu_cvb_tables) +}; + static const struct dfll_fcpu_data tegra124_dfll_fcpu_data = { .cpu_max_freq_table = tegra124_cpu_max_freq_table, .cpu_max_freq_table_size = ARRAY_SIZE(tegra124_cpu_max_freq_table), @@ -509,6 +609,10 @@ static const struct dfll_fcpu_data tegra210_dfll_fcpu_data = { }; static const struct of_device_id tegra124_dfll_fcpu_of_match[] = { + { + .compatible = "nvidia,tegra114-dfll", + .data = &tegra114_dfll_fcpu_data, + }, { .compatible = "nvidia,tegra124-dfll", .data = &tegra124_dfll_fcpu_data, From be5ae730ffa6fd774a00a4705c1e11e078b08ca1 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sun, 14 Sep 2025 12:56:06 +0000 Subject: [PATCH 1413/2711] usb: typec: tipd: Clear interrupts first Right now the interrupt handler first reads all updated status registers and only then clears the interrupts. It's possible that a duplicate interrupt for a changed register or plug state comes in after the interrupts have been processed but before they have been cleared: * plug is inserted, TPS_REG_INT_PLUG_EVENT is set * TPS_REG_INT_EVENT1 is read * tps6598x_handle_plug_event() has run and registered the plug * plug is removed again, TPS_REG_INT_PLUG_EVENT is set (again) * TPS_REG_INT_CLEAR1 is written, TPS_REG_INT_PLUG_EVENT is cleared We then have no plug connected and no pending interrupt but the tipd core still thinks there is a plug. It's possible to trigger this with e.g. a slightly broken Type-C to USB A converter. Fix this by first clearing the interrupts and only then reading the updated registers. Fixes: 45188f27b3d0 ("usb: typec: tipd: Add support for Apple CD321X") Fixes: 0a4c005bd171 ("usb: typec: driver for TI TPS6598x USB Power Delivery controllers") Cc: stable@kernel.org Reviewed-by: Heikki Krogerus Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-1-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index dcf141ada078..1c80296c3b27 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -545,24 +545,23 @@ static irqreturn_t cd321x_interrupt(int irq, void *data) if (!event) goto err_unlock; + tps6598x_write64(tps, TPS_REG_INT_CLEAR1, event); + if (!tps6598x_read_status(tps, &status)) - goto err_clear_ints; + goto err_unlock; if (event & APPLE_CD_REG_INT_POWER_STATUS_UPDATE) if (!tps6598x_read_power_status(tps)) - goto err_clear_ints; + goto err_unlock; if (event & APPLE_CD_REG_INT_DATA_STATUS_UPDATE) if (!tps6598x_read_data_status(tps)) - goto err_clear_ints; + goto err_unlock; /* Handle plug insert or removal */ if (event & APPLE_CD_REG_INT_PLUG_EVENT) tps6598x_handle_plug_event(tps, status); -err_clear_ints: - tps6598x_write64(tps, TPS_REG_INT_CLEAR1, event); - err_unlock: mutex_unlock(&tps->lock); @@ -668,25 +667,24 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data) if (!(event1[0] | event1[1] | event2[0] | event2[1])) goto err_unlock; + tps6598x_block_write(tps, TPS_REG_INT_CLEAR1, event1, intev_len); + tps6598x_block_write(tps, TPS_REG_INT_CLEAR2, event2, intev_len); + if (!tps6598x_read_status(tps, &status)) - goto err_clear_ints; + goto err_unlock; if ((event1[0] | event2[0]) & TPS_REG_INT_POWER_STATUS_UPDATE) if (!tps6598x_read_power_status(tps)) - goto err_clear_ints; + goto err_unlock; if ((event1[0] | event2[0]) & TPS_REG_INT_DATA_STATUS_UPDATE) if (!tps6598x_read_data_status(tps)) - goto err_clear_ints; + goto err_unlock; /* Handle plug insert or removal */ if ((event1[0] | event2[0]) & TPS_REG_INT_PLUG_EVENT) tps6598x_handle_plug_event(tps, status); -err_clear_ints: - tps6598x_block_write(tps, TPS_REG_INT_CLEAR1, event1, intev_len); - tps6598x_block_write(tps, TPS_REG_INT_CLEAR2, event2, intev_len); - err_unlock: mutex_unlock(&tps->lock); From b3dddff502c5e049e43e3d0c43586de342b9e1d7 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sun, 14 Sep 2025 12:56:07 +0000 Subject: [PATCH 1414/2711] usb: typec: tipd: Move initial irq mask to tipd_data Since the irq mask was originally added more tipd variants have been introduced and there's now struct tipd_data. Move the initial mask in there. Reviewed-by: Heikki Krogerus Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-2-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 1c80296c3b27..6d8bcbc9cad8 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -112,6 +112,7 @@ struct tps6598x; struct tipd_data { irq_handler_t irq_handler; + u64 irq_mask1; int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node); void (*trace_power_status)(u16 status); void (*trace_status)(u32 status); @@ -1298,7 +1299,6 @@ static int tps6598x_probe(struct i2c_client *client) u32 status; u32 vid; int ret; - u64 mask1; tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) @@ -1337,16 +1337,6 @@ static int tps6598x_probe(struct i2c_client *client) if (ret) return ret; - /* CD321X chips have all interrupts masked initially */ - mask1 = APPLE_CD_REG_INT_POWER_STATUS_UPDATE | - APPLE_CD_REG_INT_DATA_STATUS_UPDATE | - APPLE_CD_REG_INT_PLUG_EVENT; - - } else { - /* Enable power status, data status and plug event interrupts */ - mask1 = TPS_REG_INT_POWER_STATUS_UPDATE | - TPS_REG_INT_DATA_STATUS_UPDATE | - TPS_REG_INT_PLUG_EVENT; } tps->data = i2c_get_match_data(client); @@ -1364,7 +1354,7 @@ static int tps6598x_probe(struct i2c_client *client) return ret; } - ret = tps6598x_write64(tps, TPS_REG_INT_MASK1, mask1); + ret = tps6598x_write64(tps, TPS_REG_INT_MASK1, tps->data->irq_mask1); if (ret) goto err_reset_controller; @@ -1527,6 +1517,9 @@ static const struct dev_pm_ops tps6598x_pm_ops = { static const struct tipd_data cd321x_data = { .irq_handler = cd321x_interrupt, + .irq_mask1 = APPLE_CD_REG_INT_POWER_STATUS_UPDATE | + APPLE_CD_REG_INT_DATA_STATUS_UPDATE | + APPLE_CD_REG_INT_PLUG_EVENT, .register_port = tps6598x_register_port, .trace_power_status = trace_tps6598x_power_status, .trace_status = trace_tps6598x_status, @@ -1536,6 +1529,9 @@ static const struct tipd_data cd321x_data = { static const struct tipd_data tps6598x_data = { .irq_handler = tps6598x_interrupt, + .irq_mask1 = TPS_REG_INT_POWER_STATUS_UPDATE | + TPS_REG_INT_DATA_STATUS_UPDATE | + TPS_REG_INT_PLUG_EVENT, .register_port = tps6598x_register_port, .trace_power_status = trace_tps6598x_power_status, .trace_status = trace_tps6598x_status, @@ -1546,6 +1542,9 @@ static const struct tipd_data tps6598x_data = { static const struct tipd_data tps25750_data = { .irq_handler = tps25750_interrupt, + .irq_mask1 = TPS_REG_INT_POWER_STATUS_UPDATE | + TPS_REG_INT_DATA_STATUS_UPDATE | + TPS_REG_INT_PLUG_EVENT, .register_port = tps25750_register_port, .trace_power_status = trace_tps25750_power_status, .trace_status = trace_tps25750_status, From ff175d85888e6bb4c41101493b8e74717842fb39 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sun, 14 Sep 2025 12:56:08 +0000 Subject: [PATCH 1415/2711] usb: typec: tipd: Move switch_power_state to tipd_data When support for CD321x was originally added no other hardware variant was supported and there was no need for struct tipd_data. Now that it exists move the special case in there so that we can drop the of_device_is_compatible_check entirely. Reviewed-by: Heikki Krogerus Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-3-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 6d8bcbc9cad8..4815c5c46283 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -118,6 +118,7 @@ struct tipd_data { void (*trace_status)(u32 status); int (*apply_patch)(struct tps6598x *tps); int (*init)(struct tps6598x *tps); + int (*switch_power_state)(struct tps6598x *tps, u8 target_state); int (*reset)(struct tps6598x *tps); }; @@ -1293,7 +1294,6 @@ tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) static int tps6598x_probe(struct i2c_client *client) { - struct device_node *np = client->dev.of_node; struct tps6598x *tps; struct fwnode_handle *fwnode; u32 status; @@ -1331,18 +1331,16 @@ static int tps6598x_probe(struct i2c_client *client) if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) tps->i2c_protocol = true; - if (np && of_device_is_compatible(np, "apple,cd321x")) { - /* Switch CD321X chips to the correct system power state */ - ret = cd321x_switch_power_state(tps, TPS_SYSTEM_POWER_STATE_S0); - if (ret) - return ret; - - } - tps->data = i2c_get_match_data(client); if (!tps->data) return -EINVAL; + if (tps->data->switch_power_state) { + ret = tps->data->switch_power_state(tps, TPS_SYSTEM_POWER_STATE_S0); + if (ret) + return ret; + } + /* Make sure the controller has application firmware running */ ret = tps6598x_check_mode(tps); if (ret < 0) @@ -1525,6 +1523,7 @@ static const struct tipd_data cd321x_data = { .trace_status = trace_tps6598x_status, .init = cd321x_init, .reset = cd321x_reset, + .switch_power_state = cd321x_switch_power_state, }; static const struct tipd_data tps6598x_data = { From 60e1ff66179ca59bf98ec64a849d0325c0db0f57 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sun, 14 Sep 2025 12:56:09 +0000 Subject: [PATCH 1416/2711] usb: typec: tipd: Trace data status for CD321x correctly Some bits inside the CD321x TPS_DATA_STATUS register have a different function compared to the original tipd chip. Add these and introduce a separate trace function to show them correctly. Reviewed-by: Heikki Krogerus Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-4-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 8 ++++++- drivers/usb/typec/tipd/tps6598x.h | 5 ++++ drivers/usb/typec/tipd/trace.h | 39 +++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 4815c5c46283..19d713937870 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -114,6 +114,7 @@ struct tipd_data { irq_handler_t irq_handler; u64 irq_mask1; int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node); + void (*trace_data_status)(u32 status); void (*trace_power_status)(u16 status); void (*trace_status)(u32 status); int (*apply_patch)(struct tps6598x *tps); @@ -492,7 +493,9 @@ static bool tps6598x_read_data_status(struct tps6598x *tps) dev_err(tps->dev, "failed to read data status: %d\n", ret); return false; } - trace_tps6598x_data_status(data_status); + + if (tps->data->trace_data_status) + tps->data->trace_data_status(data_status); return true; } @@ -1519,6 +1522,7 @@ static const struct tipd_data cd321x_data = { APPLE_CD_REG_INT_DATA_STATUS_UPDATE | APPLE_CD_REG_INT_PLUG_EVENT, .register_port = tps6598x_register_port, + .trace_data_status = trace_cd321x_data_status, .trace_power_status = trace_tps6598x_power_status, .trace_status = trace_tps6598x_status, .init = cd321x_init, @@ -1532,6 +1536,7 @@ static const struct tipd_data tps6598x_data = { TPS_REG_INT_DATA_STATUS_UPDATE | TPS_REG_INT_PLUG_EVENT, .register_port = tps6598x_register_port, + .trace_data_status = trace_tps6598x_data_status, .trace_power_status = trace_tps6598x_power_status, .trace_status = trace_tps6598x_status, .apply_patch = tps6598x_apply_patch, @@ -1545,6 +1550,7 @@ static const struct tipd_data tps25750_data = { TPS_REG_INT_DATA_STATUS_UPDATE | TPS_REG_INT_PLUG_EVENT, .register_port = tps25750_register_port, + .trace_data_status = trace_tps6598x_data_status, .trace_power_status = trace_tps25750_power_status, .trace_status = trace_tps25750_status, .apply_patch = tps25750_apply_patch, diff --git a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps6598x.h index cecb8d11d239..03edbb77bbd6 100644 --- a/drivers/usb/typec/tipd/tps6598x.h +++ b/drivers/usb/typec/tipd/tps6598x.h @@ -197,6 +197,11 @@ #define TPS_DATA_STATUS_FORCE_LSX BIT(23) #define TPS_DATA_STATUS_POWER_MISMATCH BIT(24) +/* modified TPS_REG_DATA_STATUS bits for CD321x (and likely also TPS65987DDK) */ +#define CD321X_DATA_STATUS_HPD_IRQ BIT(14) +#define CD321X_DATA_STATUS_HPD_LEVEL BIT(15) +#define CD321X_DATA_STATUS_USB4_CONNECTION BIT(23) + #define TPS_DATA_STATUS_DP_PIN_ASSIGNMENT_MASK GENMASK(11, 10) #define TPS_DATA_STATUS_DP_PIN_ASSIGNMENT(x) \ TPS_FIELD_GET(TPS_DATA_STATUS_DP_PIN_ASSIGNMENT_MASK, (x)) diff --git a/drivers/usb/typec/tipd/trace.h b/drivers/usb/typec/tipd/trace.h index bea383f2db9d..e9e40425138a 100644 --- a/drivers/usb/typec/tipd/trace.h +++ b/drivers/usb/typec/tipd/trace.h @@ -217,6 +217,26 @@ { TPS_DATA_STATUS_FORCE_LSX, "FORCE_LSX" }, \ { TPS_DATA_STATUS_POWER_MISMATCH, "POWER_MISMATCH" }) +#define show_cd321x_data_status_flags(data_status) \ + __print_flags(data_status & TPS_DATA_STATUS_FLAGS_MASK, "|", \ + { TPS_DATA_STATUS_DATA_CONNECTION, "DATA_CONNECTION" }, \ + { TPS_DATA_STATUS_UPSIDE_DOWN, "DATA_UPSIDE_DOWN" }, \ + { TPS_DATA_STATUS_ACTIVE_CABLE, "ACTIVE_CABLE" }, \ + { TPS_DATA_STATUS_USB2_CONNECTION, "USB2_CONNECTION" }, \ + { TPS_DATA_STATUS_USB3_CONNECTION, "USB3_CONNECTION" }, \ + { TPS_DATA_STATUS_USB3_GEN2, "USB3_GEN2" }, \ + { TPS_DATA_STATUS_USB_DATA_ROLE, "USB_DATA_ROLE" }, \ + { TPS_DATA_STATUS_DP_CONNECTION, "DP_CONNECTION" }, \ + { TPS_DATA_STATUS_DP_SINK, "DP_SINK" }, \ + { CD321X_DATA_STATUS_HPD_IRQ, "HPD_IRQ" }, \ + { CD321X_DATA_STATUS_HPD_LEVEL, "HPD_LEVEL" }, \ + { TPS_DATA_STATUS_TBT_CONNECTION, "TBT_CONNECTION" }, \ + { TPS_DATA_STATUS_TBT_TYPE, "TBT_TYPE" }, \ + { TPS_DATA_STATUS_OPTICAL_CABLE, "OPTICAL_CABLE" }, \ + { TPS_DATA_STATUS_ACTIVE_LINK_TRAIN, "ACTIVE_LINK_TRAIN" }, \ + { CD321X_DATA_STATUS_USB4_CONNECTION, "USB4" }, \ + { TPS_DATA_STATUS_POWER_MISMATCH, "POWER_MISMATCH" }) + #define show_data_status_dp_pin_assignment(data_status) \ __print_symbolic(TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT(data_status), \ { TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_E, "E" }, \ @@ -388,6 +408,25 @@ TRACE_EVENT(tps6598x_data_status, ) ); +TRACE_EVENT(cd321x_data_status, + TP_PROTO(u32 data_status), + TP_ARGS(data_status), + + TP_STRUCT__entry( + __field(u32, data_status) + ), + + TP_fast_assign( + __entry->data_status = data_status; + ), + + TP_printk("%s%s%s", + show_cd321x_data_status_flags(__entry->data_status), + __entry->data_status & TPS_DATA_STATUS_DP_CONNECTION ? ", DP pinout " : "", + maybe_show_data_status_dp_pin_assignment(__entry->data_status) + ) +); + #endif /* _TPS6598X_TRACE_H_ */ /* This part must be outside protection */ From 9f36fdfcf36445db4c886afdeff2d1d126f16c45 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sun, 14 Sep 2025 12:56:10 +0000 Subject: [PATCH 1417/2711] usb: typec: tipd: Add cd321x struct with separate size We're about to add more fields to struct tps6598x which are only relevant for Apple's CD321x and to ensure that we don't waste memory everywhere for those add a separate struct for cd321x and prepare to allocate more space inside probe. Reviewed-by: Heikki Krogerus Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-5-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 19d713937870..51b0f3be8b66 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -113,6 +113,7 @@ struct tps6598x; struct tipd_data { irq_handler_t irq_handler; u64 irq_mask1; + size_t tps_struct_size; int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node); void (*trace_data_status)(u32 status); void (*trace_power_status)(u16 status); @@ -148,6 +149,10 @@ struct tps6598x { const struct tipd_data *data; }; +struct cd321x { + struct tps6598x tps; +}; + static enum power_supply_property tps6598x_psy_props[] = { POWER_SUPPLY_PROP_USB_TYPE, POWER_SUPPLY_PROP_ONLINE, @@ -1297,18 +1302,24 @@ tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) static int tps6598x_probe(struct i2c_client *client) { + const struct tipd_data *data; struct tps6598x *tps; struct fwnode_handle *fwnode; u32 status; u32 vid; int ret; - tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); + data = i2c_get_match_data(client); + if (!data) + return -EINVAL; + + tps = devm_kzalloc(&client->dev, data->tps_struct_size, GFP_KERNEL); if (!tps) return -ENOMEM; mutex_init(&tps->lock); tps->dev = &client->dev; + tps->data = data; tps->reset = devm_gpiod_get_optional(tps->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(tps->reset)) @@ -1334,10 +1345,6 @@ static int tps6598x_probe(struct i2c_client *client) if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) tps->i2c_protocol = true; - tps->data = i2c_get_match_data(client); - if (!tps->data) - return -EINVAL; - if (tps->data->switch_power_state) { ret = tps->data->switch_power_state(tps, TPS_SYSTEM_POWER_STATE_S0); if (ret) @@ -1521,6 +1528,7 @@ static const struct tipd_data cd321x_data = { .irq_mask1 = APPLE_CD_REG_INT_POWER_STATUS_UPDATE | APPLE_CD_REG_INT_DATA_STATUS_UPDATE | APPLE_CD_REG_INT_PLUG_EVENT, + .tps_struct_size = sizeof(struct cd321x), .register_port = tps6598x_register_port, .trace_data_status = trace_cd321x_data_status, .trace_power_status = trace_tps6598x_power_status, @@ -1535,6 +1543,7 @@ static const struct tipd_data tps6598x_data = { .irq_mask1 = TPS_REG_INT_POWER_STATUS_UPDATE | TPS_REG_INT_DATA_STATUS_UPDATE | TPS_REG_INT_PLUG_EVENT, + .tps_struct_size = sizeof(struct tps6598x), .register_port = tps6598x_register_port, .trace_data_status = trace_tps6598x_data_status, .trace_power_status = trace_tps6598x_power_status, @@ -1549,6 +1558,7 @@ static const struct tipd_data tps25750_data = { .irq_mask1 = TPS_REG_INT_POWER_STATUS_UPDATE | TPS_REG_INT_DATA_STATUS_UPDATE | TPS_REG_INT_PLUG_EVENT, + .tps_struct_size = sizeof(struct tps6598x), .register_port = tps25750_register_port, .trace_data_status = trace_tps6598x_data_status, .trace_power_status = trace_tps25750_power_status, From 0b31c978935fb15863c0299a4c35ec6e89b492d2 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sun, 14 Sep 2025 12:56:11 +0000 Subject: [PATCH 1418/2711] usb: typec: tipd: Read USB4, Thunderbolt and DisplayPort status for cd321x CD321x supports various alternate modes and stores information once these are entered into separate status registers. Read those when they are active when reading TPS_DATA_STATUS to prepare supporting these. Reviewed-by: Heikki Krogerus Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-6-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 80 +++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 51b0f3be8b66..afd11b3e1ae5 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -35,14 +35,18 @@ #define TPS_REG_INT_MASK2 0x17 #define TPS_REG_INT_CLEAR1 0x18 #define TPS_REG_INT_CLEAR2 0x19 -#define TPS_REG_SYSTEM_POWER_STATE 0x20 #define TPS_REG_STATUS 0x1a +#define TPS_REG_SYSTEM_POWER_STATE 0x20 +#define TPS_REG_USB4_STATUS 0x24 #define TPS_REG_SYSTEM_CONF 0x28 #define TPS_REG_CTRL_CONF 0x29 #define TPS_REG_BOOT_STATUS 0x2D #define TPS_REG_POWER_STATUS 0x3f #define TPS_REG_PD_STATUS 0x40 #define TPS_REG_RX_IDENTITY_SOP 0x48 +#define TPS_REG_CF_VID_STATUS 0x5e +#define TPS_REG_DP_SID_STATUS 0x58 +#define TPS_REG_INTEL_VID_STATUS 0x59 #define TPS_REG_DATA_STATUS 0x5f #define TPS_REG_SLEEP_CONF 0x70 @@ -85,6 +89,31 @@ struct tps6598x_rx_identity_reg { struct usb_pd_identity identity; } __packed; +/* TPS_REG_USB4_STATUS */ +struct tps6598x_usb4_status_reg { + u8 mode_status; + __le32 eudo; + __le32 unknown; +} __packed; + +/* TPS_REG_DP_SID_STATUS */ +struct tps6598x_dp_sid_status_reg { + u8 mode_status; + __le32 status_tx; + __le32 status_rx; + __le32 configure; + __le32 mode_data; +} __packed; + +/* TPS_REG_INTEL_VID_STATUS */ +struct tps6598x_intel_vid_status_reg { + u8 mode_status; + __le32 attention_vdo; + __le16 enter_vdo; + __le16 device_mode; + __le16 cable_mode; +} __packed; + /* Standard Task return codes */ #define TPS_TASK_TIMEOUT 1 #define TPS_TASK_REJECTED 3 @@ -121,6 +150,7 @@ struct tipd_data { int (*apply_patch)(struct tps6598x *tps); int (*init)(struct tps6598x *tps); int (*switch_power_state)(struct tps6598x *tps, u8 target_state); + bool (*read_data_status)(struct tps6598x *tps); int (*reset)(struct tps6598x *tps); }; @@ -151,6 +181,10 @@ struct tps6598x { struct cd321x { struct tps6598x tps; + + struct tps6598x_dp_sid_status_reg dp_sid_status; + struct tps6598x_intel_vid_status_reg intel_vid_status; + struct tps6598x_usb4_status_reg usb4_status; }; static enum power_supply_property tps6598x_psy_props[] = { @@ -505,6 +539,41 @@ static bool tps6598x_read_data_status(struct tps6598x *tps) return true; } +static bool cd321x_read_data_status(struct tps6598x *tps) +{ + struct cd321x *cd321x = container_of(tps, struct cd321x, tps); + int ret; + + ret = tps6598x_read_data_status(tps); + if (ret < 0) + return false; + + if (tps->data_status & TPS_DATA_STATUS_DP_CONNECTION) { + ret = tps6598x_block_read(tps, TPS_REG_DP_SID_STATUS, + &cd321x->dp_sid_status, sizeof(cd321x->dp_sid_status)); + if (ret) + dev_err(tps->dev, "Failed to read DP SID Status: %d\n", + ret); + } + + if (tps->data_status & TPS_DATA_STATUS_TBT_CONNECTION) { + ret = tps6598x_block_read(tps, TPS_REG_INTEL_VID_STATUS, + &cd321x->intel_vid_status, sizeof(cd321x->intel_vid_status)); + if (ret) + dev_err(tps->dev, "Failed to read Intel VID Status: %d\n", ret); + } + + if (tps->data_status & CD321X_DATA_STATUS_USB4_CONNECTION) { + ret = tps6598x_block_read(tps, TPS_REG_USB4_STATUS, + &cd321x->usb4_status, sizeof(cd321x->usb4_status)); + if (ret) + dev_err(tps->dev, + "Failed to read USB4 Status: %d\n", ret); + } + + return true; +} + static bool tps6598x_read_power_status(struct tps6598x *tps) { u16 pwr_status; @@ -565,7 +634,7 @@ static irqreturn_t cd321x_interrupt(int irq, void *data) goto err_unlock; if (event & APPLE_CD_REG_INT_DATA_STATUS_UPDATE) - if (!tps6598x_read_data_status(tps)) + if (!tps->data->read_data_status(tps)) goto err_unlock; /* Handle plug insert or removal */ @@ -614,7 +683,7 @@ static irqreturn_t tps25750_interrupt(int irq, void *data) goto err_clear_ints; if (event[0] & TPS_REG_INT_DATA_STATUS_UPDATE) - if (!tps6598x_read_data_status(tps)) + if (!tps->data->read_data_status(tps)) goto err_clear_ints; /* @@ -688,7 +757,7 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data) goto err_unlock; if ((event1[0] | event2[0]) & TPS_REG_INT_DATA_STATUS_UPDATE) - if (!tps6598x_read_data_status(tps)) + if (!tps->data->read_data_status(tps)) goto err_unlock; /* Handle plug insert or removal */ @@ -1534,6 +1603,7 @@ static const struct tipd_data cd321x_data = { .trace_power_status = trace_tps6598x_power_status, .trace_status = trace_tps6598x_status, .init = cd321x_init, + .read_data_status = cd321x_read_data_status, .reset = cd321x_reset, .switch_power_state = cd321x_switch_power_state, }; @@ -1550,6 +1620,7 @@ static const struct tipd_data tps6598x_data = { .trace_status = trace_tps6598x_status, .apply_patch = tps6598x_apply_patch, .init = tps6598x_init, + .read_data_status = tps6598x_read_data_status, .reset = tps6598x_reset, }; @@ -1565,6 +1636,7 @@ static const struct tipd_data tps25750_data = { .trace_status = trace_tps25750_status, .apply_patch = tps25750_apply_patch, .init = tps25750_init, + .read_data_status = tps6598x_read_data_status, .reset = tps25750_reset, }; From 7b1d318506839ea8b71b258a3e48b1f87f69d1bb Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sun, 14 Sep 2025 12:56:12 +0000 Subject: [PATCH 1419/2711] usb: typec: tipd: Register DisplayPort and Thunderbolt altmodes for cd321x Ports equipped with a CD321x are only found on Apple Silicon machines and always support DisplayPort, Thunderbolt and USB4. Register these port modes unconditionally. Reviewed-by: Heikki Krogerus Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-7-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 85 +++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 3 deletions(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index afd11b3e1ae5..c7cf936e5a61 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -144,6 +146,7 @@ struct tipd_data { u64 irq_mask1; size_t tps_struct_size; int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node); + void (*unregister_port)(struct tps6598x *tps); void (*trace_data_status)(u32 status); void (*trace_power_status)(u16 status); void (*trace_status)(u32 status); @@ -185,6 +188,9 @@ struct cd321x { struct tps6598x_dp_sid_status_reg dp_sid_status; struct tps6598x_intel_vid_status_reg intel_vid_status; struct tps6598x_usb4_status_reg usb4_status; + + struct typec_altmode *port_altmode_dp; + struct typec_altmode *port_altmode_tbt; }; static enum power_supply_property tps6598x_psy_props[] = { @@ -964,6 +970,76 @@ tps6598x_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) return 0; } +static int cd321x_register_port_altmodes(struct cd321x *cd321x) +{ + struct typec_altmode_desc desc; + struct typec_altmode *amode; + + memset(&desc, 0, sizeof(desc)); + desc.svid = USB_TYPEC_DP_SID; + desc.mode = USB_TYPEC_DP_MODE; + desc.vdo = DP_CONF_SET_PIN_ASSIGN(BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D)); + desc.vdo |= DP_CAP_DFP_D; + amode = typec_port_register_altmode(cd321x->tps.port, &desc); + if (IS_ERR(amode)) + return PTR_ERR(amode); + cd321x->port_altmode_dp = amode; + + memset(&desc, 0, sizeof(desc)); + desc.svid = USB_TYPEC_TBT_SID; + desc.mode = TYPEC_ANY_MODE; + amode = typec_port_register_altmode(cd321x->tps.port, &desc); + if (IS_ERR(amode)) { + typec_unregister_altmode(cd321x->port_altmode_dp); + cd321x->port_altmode_dp = NULL; + return PTR_ERR(amode); + } + cd321x->port_altmode_tbt = amode; + + return 0; +} + +static int +cd321x_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) +{ + struct cd321x *cd321x = container_of(tps, struct cd321x, tps); + int ret; + + ret = tps6598x_register_port(tps, fwnode); + if (ret) + return ret; + + ret = cd321x_register_port_altmodes(cd321x); + if (ret) + goto err_unregister_port; + + typec_set_mode(tps->port, TYPEC_STATE_SAFE); + + return 0; + +err_unregister_port: + typec_unregister_port(tps->port); + return ret; +} + +static void +tps6598x_unregister_port(struct tps6598x *tps) +{ + typec_unregister_port(tps->port); +} + +static void +cd321x_unregister_port(struct tps6598x *tps) +{ + struct cd321x *cd321x = container_of(tps, struct cd321x, tps); + + typec_unregister_altmode(cd321x->port_altmode_dp); + cd321x->port_altmode_dp = NULL; + typec_unregister_altmode(cd321x->port_altmode_tbt); + cd321x->port_altmode_tbt = NULL; + typec_unregister_port(tps->port); +} + static int tps_request_firmware(struct tps6598x *tps, const struct firmware **fw, const char **firmware_name) { @@ -1505,7 +1581,7 @@ static int tps6598x_probe(struct i2c_client *client) err_disconnect: tps6598x_disconnect(tps, 0); err_unregister_port: - typec_unregister_port(tps->port); + tps->data->unregister_port(tps); err_role_put: usb_role_switch_put(tps->role_sw); err_fwnode_put: @@ -1529,7 +1605,7 @@ static void tps6598x_remove(struct i2c_client *client) devm_free_irq(tps->dev, client->irq, tps); tps6598x_disconnect(tps, 0); - typec_unregister_port(tps->port); + tps->data->unregister_port(tps); usb_role_switch_put(tps->role_sw); /* Reset PD controller to remove any applied patch */ @@ -1598,7 +1674,8 @@ static const struct tipd_data cd321x_data = { APPLE_CD_REG_INT_DATA_STATUS_UPDATE | APPLE_CD_REG_INT_PLUG_EVENT, .tps_struct_size = sizeof(struct cd321x), - .register_port = tps6598x_register_port, + .register_port = cd321x_register_port, + .unregister_port = cd321x_unregister_port, .trace_data_status = trace_cd321x_data_status, .trace_power_status = trace_tps6598x_power_status, .trace_status = trace_tps6598x_status, @@ -1615,6 +1692,7 @@ static const struct tipd_data tps6598x_data = { TPS_REG_INT_PLUG_EVENT, .tps_struct_size = sizeof(struct tps6598x), .register_port = tps6598x_register_port, + .unregister_port = tps6598x_unregister_port, .trace_data_status = trace_tps6598x_data_status, .trace_power_status = trace_tps6598x_power_status, .trace_status = trace_tps6598x_status, @@ -1631,6 +1709,7 @@ static const struct tipd_data tps25750_data = { TPS_REG_INT_PLUG_EVENT, .tps_struct_size = sizeof(struct tps6598x), .register_port = tps25750_register_port, + .unregister_port = tps6598x_unregister_port, .trace_data_status = trace_tps6598x_data_status, .trace_power_status = trace_tps25750_power_status, .trace_status = trace_tps25750_status, From 36c791c1996db13d5042960aa5895f777239845b Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 14 Sep 2025 12:56:13 +0000 Subject: [PATCH 1420/2711] usb: typec: tipd: Update partner identity when power status was updated Whenever the power status is changed make sure to also update the partner identity to be able to detect changes once de-bouncing and mode changes are added for CD321x. Signed-off-by: Hector Martin Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-8-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index c7cf936e5a61..e16c6c07c72a 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -635,9 +635,16 @@ static irqreturn_t cd321x_interrupt(int irq, void *data) if (!tps6598x_read_status(tps, &status)) goto err_unlock; - if (event & APPLE_CD_REG_INT_POWER_STATUS_UPDATE) + if (event & APPLE_CD_REG_INT_POWER_STATUS_UPDATE) { if (!tps6598x_read_power_status(tps)) goto err_unlock; + if (TPS_POWER_STATUS_PWROPMODE(tps->pwr_status) == TYPEC_PWR_MODE_PD) { + if (tps6598x_read_partner_identity(tps)) { + dev_err(tps->dev, "failed to read partner identity\n"); + tps->partner_identity = (struct usb_pd_identity) {0}; + } + } + } if (event & APPLE_CD_REG_INT_DATA_STATUS_UPDATE) if (!tps->data->read_data_status(tps)) From 77ed2f4538da7356a1813e9d4e4c13de6e3d5a2a Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 14 Sep 2025 12:56:14 +0000 Subject: [PATCH 1421/2711] usb: typec: tipd: Use read_power_status function in probe We need the initial power status to be able to reliably detect connector changes once we introduce de-bouncing for CD321x next. read_power_status takes care of this and also forwards the status to the trace subsystem so let's use that instead of open-coding it inside probe. Signed-off-by: Hector Martin Reviewed-by: Heikki Krogerus Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-9-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index e16c6c07c72a..f546f4ae563a 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -1549,11 +1549,8 @@ static int tps6598x_probe(struct i2c_client *client) goto err_role_put; if (status & TPS_STATUS_PLUG_PRESENT) { - ret = tps6598x_read16(tps, TPS_REG_POWER_STATUS, &tps->pwr_status); - if (ret < 0) { - dev_err(tps->dev, "failed to read power status: %d\n", ret); + if (!tps6598x_read_power_status(tps)) goto err_unregister_port; - } ret = tps6598x_connect(tps, status); if (ret) dev_err(&client->dev, "failed to register partner\n"); From 04041fd7d6ec0bc5c4277711e17b43ffb45e30ba Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 14 Sep 2025 12:56:15 +0000 Subject: [PATCH 1422/2711] usb: typec: tipd: Read data status in probe and cache its value Just like for power status we also need to keep track of data status to be able to detect mode changes once we introduce de-bouncing for CD321x. Read it during probe and keep a cached copy of its value. Signed-off-by: Hector Martin Reviewed-by: Heikki Krogerus Reviewed-by: Neal Gompa Signed-off-by: Sven Peter Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-10-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index f546f4ae563a..f347e5bc6254 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -176,6 +176,7 @@ struct tps6598x { int wakeup; u32 status; /* status reg */ + u32 data_status; u16 pwr_status; struct delayed_work wq_poll; @@ -538,6 +539,7 @@ static bool tps6598x_read_data_status(struct tps6598x *tps) dev_err(tps->dev, "failed to read data status: %d\n", ret); return false; } + tps->data_status = data_status; if (tps->data->trace_data_status) tps->data->trace_data_status(data_status); @@ -1551,6 +1553,8 @@ static int tps6598x_probe(struct i2c_client *client) if (status & TPS_STATUS_PLUG_PRESENT) { if (!tps6598x_read_power_status(tps)) goto err_unregister_port; + if (!tps->data->read_data_status(tps)) + goto err_unregister_port; ret = tps6598x_connect(tps, status); if (ret) dev_err(&client->dev, "failed to register partner\n"); From 82432bbfb9e83b7e81d04660fe129b99a29b2ac2 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 14 Sep 2025 12:56:16 +0000 Subject: [PATCH 1423/2711] usb: typec: tipd: Handle mode transitions for CD321x On Apple Silicon machines there is no control over which alt mode is chosen. The CD321x' firmware negotiates the target mode on its own and only lets the main CPU know after the mode has already been chosen. Especially after plugging a new cable in this can result to quick mode changes from e.g. power only -> USB3 only -> USB3+DisplayPort in a short time. It is not possile to influence this in any way and we also do not get direct access to the PDOs or VDOs exchanged via USB PD. Additionally, mode changes must be tightly synchronized between DWC3 and the Type C PHY and most mode changes require a full reset of DWC3 to make the port work correctly. This is all done synchronously from the role switch handler inside the DWC3 glue driver on these machines to avoid tripping any failsafes or watchdogs inside the Type-C PHY that may, in the worst case, reset the entire SoC. To be able to control all this we trigger the entire process in the correct order directly from the TIPD driver and de-bounce any mode changes to avoid tearing down and re-setting DWC3 back up multiple times any time a new connection is made. Signed-off-by: Hector Martin Reviewed-by: Heikki Krogerus Reviewed-by: Neal Gompa Co-developed-by: Sven Peter Signed-off-by: Sven Peter Reviewed-by: Janne Grunau Link: https://lore.kernel.org/r/20250914-apple-usb3-tipd-v1-11-4e99c8649024@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tipd/core.c | 290 +++++++++++++++++++++++++++++++++- 1 file changed, 286 insertions(+), 4 deletions(-) diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index f347e5bc6254..2b1049c9a6f3 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,9 @@ struct tps6598x_intel_vid_status_reg { #define TPS_TASK_TIMEOUT 1 #define TPS_TASK_REJECTED 3 +/* Debounce delay for mode changes, in milliseconds */ +#define CD321X_DEBOUNCE_DELAY_MS 500 + enum { TPS_MODE_APP, TPS_MODE_BOOT, @@ -145,6 +149,7 @@ struct tipd_data { irq_handler_t irq_handler; u64 irq_mask1; size_t tps_struct_size; + void (*remove)(struct tps6598x *tps); int (*register_port)(struct tps6598x *tps, struct fwnode_handle *node); void (*unregister_port)(struct tps6598x *tps); void (*trace_data_status)(u32 status); @@ -155,6 +160,7 @@ struct tipd_data { int (*switch_power_state)(struct tps6598x *tps, u8 target_state); bool (*read_data_status)(struct tps6598x *tps); int (*reset)(struct tps6598x *tps); + int (*connect)(struct tps6598x *tps, u32 status); }; struct tps6598x { @@ -183,6 +189,17 @@ struct tps6598x { const struct tipd_data *data; }; +struct cd321x_status { + u32 status; + u32 pwr_status; + u32 data_status; + u32 status_changed; + struct usb_pd_identity partner_identity; + struct tps6598x_dp_sid_status_reg dp_sid_status; + struct tps6598x_intel_vid_status_reg intel_vid_status; + struct tps6598x_usb4_status_reg usb4_status; +}; + struct cd321x { struct tps6598x tps; @@ -192,6 +209,13 @@ struct cd321x { struct typec_altmode *port_altmode_dp; struct typec_altmode *port_altmode_tbt; + + struct typec_mux *mux; + struct typec_mux_state state; + + struct cd321x_status update_status; + struct delayed_work update_work; + struct usb_pd_identity cur_partner_identity; }; static enum power_supply_property tps6598x_psy_props[] = { @@ -613,6 +637,233 @@ static void tps6598x_handle_plug_event(struct tps6598x *tps, u32 status) } } +static void cd321x_typec_update_mode(struct tps6598x *tps, struct cd321x_status *st) +{ + struct cd321x *cd321x = container_of(tps, struct cd321x, tps); + + if (!(st->data_status & TPS_DATA_STATUS_DATA_CONNECTION)) { + if (cd321x->state.mode == TYPEC_STATE_SAFE) + return; + cd321x->state.alt = NULL; + cd321x->state.mode = TYPEC_STATE_SAFE; + cd321x->state.data = NULL; + typec_mux_set(cd321x->mux, &cd321x->state); + } else if (st->data_status & TPS_DATA_STATUS_DP_CONNECTION) { + struct typec_displayport_data dp_data; + unsigned long mode; + + switch (TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT(st->data_status)) { + case TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_A: + mode = TYPEC_DP_STATE_A; + break; + case TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_B: + mode = TYPEC_DP_STATE_B; + break; + case TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_C: + mode = TYPEC_DP_STATE_C; + break; + case TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_D: + mode = TYPEC_DP_STATE_D; + break; + case TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_E: + mode = TYPEC_DP_STATE_E; + break; + case TPS_DATA_STATUS_DP_SPEC_PIN_ASSIGNMENT_F: + mode = TYPEC_DP_STATE_F; + break; + default: + dev_err(tps->dev, "Invalid DP pin assignment\n"); + return; + } + + if (cd321x->state.alt == cd321x->port_altmode_dp && + cd321x->state.mode == mode) { + return; + } + + dp_data.status = le32_to_cpu(st->dp_sid_status.status_rx); + dp_data.conf = le32_to_cpu(st->dp_sid_status.configure); + cd321x->state.alt = cd321x->port_altmode_dp; + cd321x->state.data = &dp_data; + cd321x->state.mode = mode; + typec_mux_set(cd321x->mux, &cd321x->state); + } else if (st->data_status & TPS_DATA_STATUS_TBT_CONNECTION) { + struct typec_thunderbolt_data tbt_data; + + if (cd321x->state.alt == cd321x->port_altmode_tbt && + cd321x->state.mode == TYPEC_TBT_MODE) + return; + + tbt_data.cable_mode = le16_to_cpu(st->intel_vid_status.cable_mode); + tbt_data.device_mode = le16_to_cpu(st->intel_vid_status.device_mode); + tbt_data.enter_vdo = le16_to_cpu(st->intel_vid_status.enter_vdo); + cd321x->state.alt = cd321x->port_altmode_tbt; + cd321x->state.mode = TYPEC_TBT_MODE; + cd321x->state.data = &tbt_data; + typec_mux_set(cd321x->mux, &cd321x->state); + } else if (st->data_status & CD321X_DATA_STATUS_USB4_CONNECTION) { + struct enter_usb_data eusb_data; + + if (cd321x->state.alt == NULL && cd321x->state.mode == TYPEC_MODE_USB4) + return; + + eusb_data.eudo = le32_to_cpu(st->usb4_status.eudo); + eusb_data.active_link_training = + !!(st->data_status & TPS_DATA_STATUS_ACTIVE_LINK_TRAIN); + + cd321x->state.alt = NULL; + cd321x->state.data = &eusb_data; + cd321x->state.mode = TYPEC_MODE_USB4; + typec_mux_set(cd321x->mux, &cd321x->state); + } else { + if (cd321x->state.alt == NULL && cd321x->state.mode == TYPEC_STATE_USB) + return; + cd321x->state.alt = NULL; + cd321x->state.mode = TYPEC_STATE_USB; + cd321x->state.data = NULL; + typec_mux_set(cd321x->mux, &cd321x->state); + } + + /* Clear data since it's no longer used after typec_mux_set and points to the stack */ + cd321x->state.data = NULL; +} + +static void cd321x_update_work(struct work_struct *work) +{ + struct cd321x *cd321x = container_of(to_delayed_work(work), + struct cd321x, update_work); + struct tps6598x *tps = &cd321x->tps; + struct cd321x_status st; + + guard(mutex)(&tps->lock); + + st = cd321x->update_status; + cd321x->update_status.status_changed = 0; + + bool old_connected = !!tps->partner; + bool new_connected = st.status & TPS_STATUS_PLUG_PRESENT; + bool was_disconnected = st.status_changed & TPS_STATUS_PLUG_PRESENT; + + bool usb_connection = st.data_status & + (TPS_DATA_STATUS_USB2_CONNECTION | TPS_DATA_STATUS_USB3_CONNECTION); + + enum usb_role old_role = usb_role_switch_get_role(tps->role_sw); + enum usb_role new_role = USB_ROLE_NONE; + enum typec_pwr_opmode pwr_opmode = TYPEC_PWR_MODE_USB; + enum typec_orientation orientation = TYPEC_ORIENTATION_NONE; + + if (usb_connection) { + if (tps->data_status & TPS_DATA_STATUS_USB_DATA_ROLE) + new_role = USB_ROLE_DEVICE; + else + new_role = USB_ROLE_HOST; + } + + if (new_connected) { + pwr_opmode = TPS_POWER_STATUS_PWROPMODE(st.pwr_status); + orientation = TPS_STATUS_TO_UPSIDE_DOWN(st.status) ? + TYPEC_ORIENTATION_REVERSE : TYPEC_ORIENTATION_NORMAL; + } + + bool is_pd = pwr_opmode == TYPEC_PWR_MODE_PD; + bool partner_changed = old_connected && new_connected && + (was_disconnected || + (is_pd && memcmp(&st.partner_identity, + &cd321x->cur_partner_identity, sizeof(struct usb_pd_identity)))); + + /* If we are switching from an active role, transition to USB_ROLE_NONE first */ + if (old_role != USB_ROLE_NONE && (new_role != old_role || was_disconnected)) + usb_role_switch_set_role(tps->role_sw, USB_ROLE_NONE); + + /* Process partner disconnection or change */ + if (!new_connected || partner_changed) { + if (!IS_ERR(tps->partner)) + typec_unregister_partner(tps->partner); + tps->partner = NULL; + } + + /* If there was a disconnection, set PHY to off */ + if (!new_connected || was_disconnected) { + cd321x->state.alt = NULL; + cd321x->state.mode = TYPEC_STATE_SAFE; + cd321x->state.data = NULL; + typec_set_mode(tps->port, TYPEC_STATE_SAFE); + } + + /* Update Type-C properties */ + typec_set_pwr_opmode(tps->port, pwr_opmode); + typec_set_pwr_role(tps->port, TPS_STATUS_TO_TYPEC_PORTROLE(st.status)); + typec_set_vconn_role(tps->port, TPS_STATUS_TO_TYPEC_VCONN(st.status)); + typec_set_orientation(tps->port, orientation); + typec_set_data_role(tps->port, TPS_STATUS_TO_TYPEC_DATAROLE(st.status)); + power_supply_changed(tps->psy); + + /* If the plug is disconnected, we are done */ + if (!new_connected) + return; + + /* Set up partner if we were previously disconnected (or changed). */ + if (!tps->partner) { + struct typec_partner_desc desc; + + desc.usb_pd = is_pd; + desc.accessory = TYPEC_ACCESSORY_NONE; /* XXX: handle accessories */ + desc.identity = NULL; + + if (desc.usb_pd) + desc.identity = &st.partner_identity; + + tps->partner = typec_register_partner(tps->port, &desc); + if (IS_ERR(tps->partner)) + dev_warn(tps->dev, "%s: failed to register partnet\n", __func__); + + if (desc.identity) { + typec_partner_set_identity(tps->partner); + cd321x->cur_partner_identity = st.partner_identity; + } + } + + /* Update the TypeC MUX/PHY state */ + cd321x_typec_update_mode(tps, &st); + + /* Launch the USB role switch */ + usb_role_switch_set_role(tps->role_sw, new_role); + + power_supply_changed(tps->psy); +} + +static void cd321x_queue_status(struct cd321x *cd321x) +{ + cd321x->update_status.status_changed |= cd321x->update_status.status ^ cd321x->tps.status; + + cd321x->update_status.status = cd321x->tps.status; + cd321x->update_status.pwr_status = cd321x->tps.pwr_status; + cd321x->update_status.data_status = cd321x->tps.data_status; + + cd321x->update_status.partner_identity = cd321x->tps.partner_identity; + cd321x->update_status.dp_sid_status = cd321x->dp_sid_status; + cd321x->update_status.intel_vid_status = cd321x->intel_vid_status; + cd321x->update_status.usb4_status = cd321x->usb4_status; +} + +static int cd321x_connect(struct tps6598x *tps, u32 status) +{ + struct cd321x *cd321x = container_of(tps, struct cd321x, tps); + + tps->status = status; + cd321x_queue_status(cd321x); + + /* + * Cancel pending work if not already running, then requeue after CD321X_DEBOUNCE_DELAY_MS + * regardless since the work function will check for any plug or altmodes changes since + * its last run anyway. + */ + cancel_delayed_work(&cd321x->update_work); + schedule_delayed_work(&cd321x->update_work, msecs_to_jiffies(CD321X_DEBOUNCE_DELAY_MS)); + + return 0; +} + static irqreturn_t cd321x_interrupt(int irq, void *data) { struct tps6598x *tps = data; @@ -652,9 +903,8 @@ static irqreturn_t cd321x_interrupt(int irq, void *data) if (!tps->data->read_data_status(tps)) goto err_unlock; - /* Handle plug insert or removal */ - if (event & APPLE_CD_REG_INT_PLUG_EVENT) - tps6598x_handle_plug_event(tps, status); + /* Can be called uncondtionally since it will check for any changes itself */ + cd321x_connect(tps, status); err_unlock: mutex_unlock(&tps->lock); @@ -1014,6 +1264,8 @@ cd321x_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) struct cd321x *cd321x = container_of(tps, struct cd321x, tps); int ret; + INIT_DELAYED_WORK(&cd321x->update_work, cd321x_update_work); + ret = tps6598x_register_port(tps, fwnode); if (ret) return ret; @@ -1022,10 +1274,24 @@ cd321x_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) if (ret) goto err_unregister_port; + cd321x->mux = fwnode_typec_mux_get(fwnode); + if (IS_ERR(cd321x->mux)) { + ret = PTR_ERR(cd321x->mux); + goto err_unregister_altmodes; + } + + cd321x->state.alt = NULL; + cd321x->state.mode = TYPEC_STATE_SAFE; + cd321x->state.data = NULL; typec_set_mode(tps->port, TYPEC_STATE_SAFE); return 0; +err_unregister_altmodes: + typec_unregister_altmode(cd321x->port_altmode_dp); + typec_unregister_altmode(cd321x->port_altmode_tbt); + cd321x->port_altmode_dp = NULL; + cd321x->port_altmode_tbt = NULL; err_unregister_port: typec_unregister_port(tps->port); return ret; @@ -1042,6 +1308,8 @@ cd321x_unregister_port(struct tps6598x *tps) { struct cd321x *cd321x = container_of(tps, struct cd321x, tps); + typec_mux_put(cd321x->mux); + cd321x->mux = NULL; typec_unregister_altmode(cd321x->port_altmode_dp); cd321x->port_altmode_dp = NULL; typec_unregister_altmode(cd321x->port_altmode_tbt); @@ -1454,6 +1722,13 @@ tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode) return 0; } +static void cd321x_remove(struct tps6598x *tps) +{ + struct cd321x *cd321x = container_of(tps, struct cd321x, tps); + + cancel_delayed_work_sync(&cd321x->update_work); +} + static int tps6598x_probe(struct i2c_client *client) { const struct tipd_data *data; @@ -1555,7 +1830,7 @@ static int tps6598x_probe(struct i2c_client *client) goto err_unregister_port; if (!tps->data->read_data_status(tps)) goto err_unregister_port; - ret = tps6598x_connect(tps, status); + ret = tps->data->connect(tps, status); if (ret) dev_err(&client->dev, "failed to register partner\n"); } @@ -1612,6 +1887,9 @@ static void tps6598x_remove(struct i2c_client *client) else devm_free_irq(tps->dev, client->irq, tps); + if (tps->data->remove) + tps->data->remove(tps); + tps6598x_disconnect(tps, 0); tps->data->unregister_port(tps); usb_role_switch_put(tps->role_sw); @@ -1682,6 +1960,7 @@ static const struct tipd_data cd321x_data = { APPLE_CD_REG_INT_DATA_STATUS_UPDATE | APPLE_CD_REG_INT_PLUG_EVENT, .tps_struct_size = sizeof(struct cd321x), + .remove = cd321x_remove, .register_port = cd321x_register_port, .unregister_port = cd321x_unregister_port, .trace_data_status = trace_cd321x_data_status, @@ -1691,6 +1970,7 @@ static const struct tipd_data cd321x_data = { .read_data_status = cd321x_read_data_status, .reset = cd321x_reset, .switch_power_state = cd321x_switch_power_state, + .connect = cd321x_connect, }; static const struct tipd_data tps6598x_data = { @@ -1708,6 +1988,7 @@ static const struct tipd_data tps6598x_data = { .init = tps6598x_init, .read_data_status = tps6598x_read_data_status, .reset = tps6598x_reset, + .connect = tps6598x_connect, }; static const struct tipd_data tps25750_data = { @@ -1725,6 +2006,7 @@ static const struct tipd_data tps25750_data = { .init = tps25750_init, .read_data_status = tps6598x_read_data_status, .reset = tps25750_reset, + .connect = tps6598x_connect, }; static const struct of_device_id tps6598x_of_match[] = { From 357704a3cf366146f1f829062970bc52162f0c76 Mon Sep 17 00:00:00 2001 From: Akiyoshi Kurita Date: Sat, 13 Sep 2025 01:26:13 +0900 Subject: [PATCH 1424/2711] staging: rtl8723bs: hal: put return type and function name on one line Make the function definition of phy_StoreTxPowerByRateBase() follow the kernel coding style by placing the return type and function name on a single line. No functional change. Signed-off-by: Akiyoshi Kurita Link: https://lore.kernel.org/r/20250912162613.776769-1-weibu@redadmin.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/hal/hal_com_phycfg.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c index d5649e7d8f99..cd76e26e868f 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c +++ b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c @@ -59,10 +59,7 @@ phy_SetTxPowerByRateBase(struct adapter *Adapter, u8 RfPath, } } -static void -phy_StoreTxPowerByRateBase( -struct adapter *padapter - ) +static void phy_StoreTxPowerByRateBase(struct adapter *padapter) { u8 path, base; From e4cb5665211013e5fe4488493b5bd6a13797901e Mon Sep 17 00:00:00 2001 From: Ahmet Sezgin Duran Date: Fri, 12 Sep 2025 16:26:27 +0000 Subject: [PATCH 1425/2711] staging: sm750fb: rename camel case variable Rename regValue to reg_value to follow kernel coding style. Signed-off-by: Ahmet Sezgin Duran Link: https://lore.kernel.org/r/20250912162627.95010-1-ahmet@sezginduran.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_accel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 7ac2e7b6ea0f..b07c1aa68621 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -17,9 +17,9 @@ #include "sm750.h" #include "sm750_accel.h" -static inline void write_dpr(struct lynx_accel *accel, int offset, u32 regValue) +static inline void write_dpr(struct lynx_accel *accel, int offset, u32 reg_value) { - writel(regValue, accel->dpr_base + offset); + writel(reg_value, accel->dpr_base + offset); } static inline u32 read_dpr(struct lynx_accel *accel, int offset) From 2ba972bf71cb71d2127ec6c3db1ceb6dd0c73173 Mon Sep 17 00:00:00 2001 From: Ben Horgan Date: Fri, 15 Aug 2025 17:26:55 +0100 Subject: [PATCH 1426/2711] KVM: arm64: Fix debug checking for np-guests using huge mappings When running with transparent huge pages and CONFIG_NVHE_EL2_DEBUG then the debug checking in assert_host_shared_guest() fails on the launch of an np-guest. This WARN_ON() causes a panic and generates the stack below. In __pkvm_host_relax_perms_guest() the debug checking assumes the mapping is a single page but it may be a block map. Update the checking so that the size is not checked and just assumes the correct size. While we're here make the same fix in __pkvm_host_mkyoung_guest(). Info: # lkvm run -k /share/arch/arm64/boot/Image -m 704 -c 8 --name guest-128 Info: Removed ghost socket file "/.lkvm//guest-128.sock". [ 1406.521757] kvm [141]: nVHE hyp BUG at: arch/arm64/kvm/hyp/nvhe/mem_protect.c:1088! [ 1406.521804] kvm [141]: nVHE call trace: [ 1406.521828] kvm [141]: [] __kvm_nvhe_hyp_panic+0xb4/0xe8 [ 1406.521946] kvm [141]: [] __kvm_nvhe_assert_host_shared_guest+0xb0/0x10c [ 1406.522049] kvm [141]: [] __kvm_nvhe___pkvm_host_relax_perms_guest+0x48/0x104 [ 1406.522157] kvm [141]: [] __kvm_nvhe_handle___pkvm_host_relax_perms_guest+0x64/0x7c [ 1406.522250] kvm [141]: [] __kvm_nvhe_handle_trap+0x8c/0x1a8 [ 1406.522333] kvm [141]: [] __kvm_nvhe___skip_pauth_save+0x4/0x4 [ 1406.522454] kvm [141]: ---[ end nVHE call trace ]--- [ 1406.522477] kvm [141]: Hyp Offset: 0xfffece8013600000 [ 1406.522554] Kernel panic - not syncing: HYP panic: [ 1406.522554] PS:834003c9 PC:0000b1806db6d170 ESR:00000000f2000800 [ 1406.522554] FAR:ffff8000804be420 HPFAR:0000000000804be0 PAR:0000000000000000 [ 1406.522554] VCPU:0000000000000000 [ 1406.523337] CPU: 3 UID: 0 PID: 141 Comm: kvm-vcpu-0 Not tainted 6.16.0-rc7 #97 PREEMPT [ 1406.523485] Hardware name: FVP Base RevC (DT) [ 1406.523566] Call trace: [ 1406.523629] show_stack+0x18/0x24 (C) [ 1406.523753] dump_stack_lvl+0xd4/0x108 [ 1406.523899] dump_stack+0x18/0x24 [ 1406.524040] panic+0x3d8/0x448 [ 1406.524184] nvhe_hyp_panic_handler+0x10c/0x23c [ 1406.524325] kvm_handle_guest_abort+0x68c/0x109c [ 1406.524500] handle_exit+0x60/0x17c [ 1406.524630] kvm_arch_vcpu_ioctl_run+0x2e0/0x8c0 [ 1406.524794] kvm_vcpu_ioctl+0x1a8/0x9cc [ 1406.524919] __arm64_sys_ioctl+0xac/0x104 [ 1406.525067] invoke_syscall+0x48/0x10c [ 1406.525189] el0_svc_common.constprop.0+0x40/0xe0 [ 1406.525322] do_el0_svc+0x1c/0x28 [ 1406.525441] el0_svc+0x38/0x120 [ 1406.525588] el0t_64_sync_handler+0x10c/0x138 [ 1406.525750] el0t_64_sync+0x1ac/0x1b0 [ 1406.525876] SMP: stopping secondary CPUs [ 1406.525965] Kernel Offset: disabled [ 1406.526032] CPU features: 0x0000,00000080,8e134ca1,9446773f [ 1406.526130] Memory Limit: none [ 1406.959099] ---[ end Kernel panic - not syncing: HYP panic: [ 1406.959099] PS:834003c9 PC:0000b1806db6d170 ESR:00000000f2000800 [ 1406.959099] FAR:ffff8000804be420 HPFAR:0000000000804be0 PAR:0000000000000000 [ 1406.959099] VCPU:0000000000000000 ] Signed-off-by: Ben Horgan Fixes: f28f1d02f4eaa ("KVM: arm64: Add a range to __pkvm_host_unshare_guest()") Cc: Vincent Donnefort Cc: Quentin Perret Cc: Ryan Roberts Cc: stable@vger.kernel.org Reviewed-by: Vincent Donnefort Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/nvhe/mem_protect.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 8957734d6183..ddc8beb55eee 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -1010,9 +1010,12 @@ static int __check_host_shared_guest(struct pkvm_hyp_vm *vm, u64 *__phys, u64 ip return ret; if (!kvm_pte_valid(pte)) return -ENOENT; - if (kvm_granule_size(level) != size) + if (size && kvm_granule_size(level) != size) return -E2BIG; + if (!size) + size = kvm_granule_size(level); + state = guest_get_page_state(pte, ipa); if (state != PKVM_PAGE_SHARED_BORROWED) return -EPERM; @@ -1100,7 +1103,7 @@ int __pkvm_host_relax_perms_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu, enum kvm_ if (prot & ~KVM_PGTABLE_PROT_RWX) return -EINVAL; - assert_host_shared_guest(vm, ipa, PAGE_SIZE); + assert_host_shared_guest(vm, ipa, 0); guest_lock_component(vm); ret = kvm_pgtable_stage2_relax_perms(&vm->pgt, ipa, prot, 0); guest_unlock_component(vm); @@ -1156,7 +1159,7 @@ int __pkvm_host_mkyoung_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu) if (pkvm_hyp_vm_is_protected(vm)) return -EPERM; - assert_host_shared_guest(vm, ipa, PAGE_SIZE); + assert_host_shared_guest(vm, ipa, 0); guest_lock_component(vm); kvm_pgtable_stage2_mkyoung(&vm->pgt, ipa, 0); guest_unlock_component(vm); From f9ac33e45d57bc4aa365363ffb650c830e5bb325 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 9 Sep 2025 08:24:28 +0100 Subject: [PATCH 1427/2711] KVM: arm64: Add build-time check for duplicate DECLARE_REG use The DECLARE_REG() macro provides a convenient way to create a local variable initialized from a cpu context in the hyp trap handlers. However, a common error is to use the macro multiple times in the same scope with the same register index, but for different logical purposes. This results in valid C code that compiles without error, but introduces subtle bugs where a developer expects two different variables to hold values from two different registers, when in fact they are both sourced from the same one. To prevent this entire class of bugs, modify the DECLARE_REG() macro to declare a dummy variable whose name is derived from the register index. If the macro is used again with the same index in the same scope, the compiler will fail with a "redeclaration of variable" error, turning a subtle runtime bug into an obvious build-time failure. Signed-off-by: Fuad Tabba Tested-by: Mark Brown Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/include/nvhe/trap_handler.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/include/nvhe/trap_handler.h b/arch/arm64/kvm/hyp/include/nvhe/trap_handler.h index 1e6d995968a1..ba5382c12787 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/trap_handler.h +++ b/arch/arm64/kvm/hyp/include/nvhe/trap_handler.h @@ -12,7 +12,8 @@ #include #define cpu_reg(ctxt, r) (ctxt)->regs.regs[r] -#define DECLARE_REG(type, name, ctxt, reg) \ +#define DECLARE_REG(type, name, ctxt, reg) \ + __always_unused int ___check_reg_ ## reg; \ type name = (type)cpu_reg(ctxt, (reg)) #endif /* __ARM64_KVM_NVHE_TRAP_HANDLER_H__ */ From 58dfb66b1e4cfb998db9e71437a2c0d9b83a93c0 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 9 Sep 2025 08:24:29 +0100 Subject: [PATCH 1428/2711] KVM: arm64: Rename pkvm.enabled to pkvm.is_protected The 'pkvm.enabled' field in struct kvm_protected_vm is confusingly named. Its purpose is to indicate whether a VM is a _protected_ VM under pKVM, and not whether the VM itself is enabled or running. For a non-protected VM, the VM can be fully active and running, yet this field would be false. This ambiguity can lead to incorrect assumptions about the VM's operational state and makes the code harder to reason about. Rename the field to 'is_protected' to make it unambiguous that the flag tracks the protected status of the VM. No functional change intended. Reviewed-by: Kunwu Chan Signed-off-by: Fuad Tabba Reviewed-by: Kunwu Chan Tested-by: Mark Brown Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 4 ++-- arch/arm64/kvm/hyp/nvhe/pkvm.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 2f2394cce24e..a4289c2f13f5 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -252,7 +252,7 @@ struct kvm_protected_vm { pkvm_handle_t handle; struct kvm_hyp_memcache teardown_mc; struct kvm_hyp_memcache stage2_teardown_mc; - bool enabled; + bool is_protected; }; struct kvm_mpidr_data { @@ -1548,7 +1548,7 @@ struct kvm *kvm_arch_alloc_vm(void); #define __KVM_HAVE_ARCH_FLUSH_REMOTE_TLBS_RANGE -#define kvm_vm_is_protected(kvm) (is_protected_kvm_enabled() && (kvm)->arch.pkvm.enabled) +#define kvm_vm_is_protected(kvm) (is_protected_kvm_enabled() && (kvm)->arch.pkvm.is_protected) #define vcpu_is_protected(vcpu) kvm_vm_is_protected((vcpu)->kvm) diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 338505cb0171..6198c1d27b5b 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -406,7 +406,7 @@ static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm, hyp_vm->host_kvm = host_kvm; hyp_vm->kvm.created_vcpus = nr_vcpus; hyp_vm->kvm.arch.mmu.vtcr = host_mmu.arch.mmu.vtcr; - hyp_vm->kvm.arch.pkvm.enabled = READ_ONCE(host_kvm->arch.pkvm.enabled); + hyp_vm->kvm.arch.pkvm.is_protected = READ_ONCE(host_kvm->arch.pkvm.is_protected); hyp_vm->kvm.arch.flags = 0; pkvm_init_features_from_host(hyp_vm, host_kvm); } From 604a5032b454bde03200d755f6ecc3f724511c6a Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 9 Sep 2025 08:24:30 +0100 Subject: [PATCH 1429/2711] KVM: arm64: Rename 'host_kvm' to 'kvm' in pKVM host code In hypervisor (EL2) code, it is important to distinguish between the host's 'struct kvm' and a protected VM's 'struct kvm'. Using 'host_kvm' as variable name in that context makes this distinction clear. However, in the host kernel code (EL1), there is no such ambiguity. The code is only ever concerned with the host's own 'struct kvm' instance. The 'host_' prefix is therefore redundant and adds unnecessary verbosity. Simplify the code by renaming the 'host_kvm' parameter to 'kvm' in all functions within host-side kernel code (EL1). This improves readability and makes the naming consistent with other host-side kernel code. No functional change intended. Signed-off-by: Fuad Tabba Tested-by: Mark Brown Signed-off-by: Marc Zyngier --- arch/arm64/kvm/pkvm.c | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index fcd70bfe44fb..7aaeb66e3f39 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -85,16 +85,16 @@ void __init kvm_hyp_reserve(void) hyp_mem_base); } -static void __pkvm_destroy_hyp_vm(struct kvm *host_kvm) +static void __pkvm_destroy_hyp_vm(struct kvm *kvm) { - if (host_kvm->arch.pkvm.handle) { + if (kvm->arch.pkvm.handle) { WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm, - host_kvm->arch.pkvm.handle)); + kvm->arch.pkvm.handle)); } - host_kvm->arch.pkvm.handle = 0; - free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc); - free_hyp_memcache(&host_kvm->arch.pkvm.stage2_teardown_mc); + kvm->arch.pkvm.handle = 0; + free_hyp_memcache(&kvm->arch.pkvm.teardown_mc); + free_hyp_memcache(&kvm->arch.pkvm.stage2_teardown_mc); } static int __pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu) @@ -129,16 +129,16 @@ static int __pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu) * * Return 0 on success, negative error code on failure. */ -static int __pkvm_create_hyp_vm(struct kvm *host_kvm) +static int __pkvm_create_hyp_vm(struct kvm *kvm) { size_t pgd_sz, hyp_vm_sz; void *pgd, *hyp_vm; int ret; - if (host_kvm->created_vcpus < 1) + if (kvm->created_vcpus < 1) return -EINVAL; - pgd_sz = kvm_pgtable_stage2_pgd_size(host_kvm->arch.mmu.vtcr); + pgd_sz = kvm_pgtable_stage2_pgd_size(kvm->arch.mmu.vtcr); /* * The PGD pages will be reclaimed using a hyp_memcache which implies @@ -152,7 +152,7 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm) /* Allocate memory to donate to hyp for vm and vcpu pointers. */ hyp_vm_sz = PAGE_ALIGN(size_add(PKVM_HYP_VM_SIZE, size_mul(sizeof(void *), - host_kvm->created_vcpus))); + kvm->created_vcpus))); hyp_vm = alloc_pages_exact(hyp_vm_sz, GFP_KERNEL_ACCOUNT); if (!hyp_vm) { ret = -ENOMEM; @@ -160,12 +160,12 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm) } /* Donate the VM memory to hyp and let hyp initialize it. */ - ret = kvm_call_hyp_nvhe(__pkvm_init_vm, host_kvm, hyp_vm, pgd); + ret = kvm_call_hyp_nvhe(__pkvm_init_vm, kvm, hyp_vm, pgd); if (ret < 0) goto free_vm; - host_kvm->arch.pkvm.handle = ret; - host_kvm->arch.pkvm.stage2_teardown_mc.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2; + kvm->arch.pkvm.handle = ret; + kvm->arch.pkvm.stage2_teardown_mc.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2; kvm_account_pgtable_pages(pgd, pgd_sz / PAGE_SIZE); return 0; @@ -176,14 +176,14 @@ free_pgd: return ret; } -int pkvm_create_hyp_vm(struct kvm *host_kvm) +int pkvm_create_hyp_vm(struct kvm *kvm) { int ret = 0; - mutex_lock(&host_kvm->arch.config_lock); - if (!host_kvm->arch.pkvm.handle) - ret = __pkvm_create_hyp_vm(host_kvm); - mutex_unlock(&host_kvm->arch.config_lock); + mutex_lock(&kvm->arch.config_lock); + if (!kvm->arch.pkvm.handle) + ret = __pkvm_create_hyp_vm(kvm); + mutex_unlock(&kvm->arch.config_lock); return ret; } @@ -200,14 +200,14 @@ int pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu) return ret; } -void pkvm_destroy_hyp_vm(struct kvm *host_kvm) +void pkvm_destroy_hyp_vm(struct kvm *kvm) { - mutex_lock(&host_kvm->arch.config_lock); - __pkvm_destroy_hyp_vm(host_kvm); - mutex_unlock(&host_kvm->arch.config_lock); + mutex_lock(&kvm->arch.config_lock); + __pkvm_destroy_hyp_vm(kvm); + mutex_unlock(&kvm->arch.config_lock); } -int pkvm_init_host_vm(struct kvm *host_kvm) +int pkvm_init_host_vm(struct kvm *kvm) { return 0; } From 070362648f5f546018747a9a1857c1597594934e Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 9 Sep 2025 08:24:31 +0100 Subject: [PATCH 1430/2711] KVM: arm64: Clarify comments to distinguish pKVM mode from protected VMs The hypervisor code for protected KVM contains comments that are imprecise and at times flat-out wrong. They often refer to a "protected VM" in contexts where the code or data structure applies to _any_ VM managed by the hypervisor when pKVM is enabled. For instance, the 'vm_table' holds handles for all VMs known to the hypervisor, not exclusively for those that are configured as protected. This inaccurate terminology can make the code scope harder to understand for future (and current) developers. Clarify the comments throughout the pKVM hypervisor code to make a clear distinction between the pKVM feature itself (i.e., "protected mode") and the VMs that are specifically configured to be protected. This involves replacing ambiguous uses of "protected VM" with more accurate phrasing. No functional change intended. Signed-off-by: Fuad Tabba Tested-by: Mark Brown Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/include/nvhe/pkvm.h | 2 +- arch/arm64/kvm/hyp/nvhe/pkvm.c | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h index ce31d3b73603..4540324b5657 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h +++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h @@ -29,7 +29,7 @@ struct pkvm_hyp_vcpu { }; /* - * Holds the relevant data for running a protected vm. + * Holds the relevant data for running a vm in protected mode. */ struct pkvm_hyp_vm { struct kvm kvm; diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 6198c1d27b5b..abe173406c88 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -23,8 +23,8 @@ unsigned int kvm_arm_vmid_bits; unsigned int kvm_host_sve_max_vl; /* - * The currently loaded hyp vCPU for each physical CPU. Used only when - * protected KVM is enabled, but for both protected and non-protected VMs. + * The currently loaded hyp vCPU for each physical CPU. Used in protected mode + * for both protected and non-protected VMs. */ static DEFINE_PER_CPU(struct pkvm_hyp_vcpu *, loaded_hyp_vcpu); @@ -135,7 +135,7 @@ static int pkvm_check_pvm_cpu_features(struct kvm_vcpu *vcpu) { struct kvm *kvm = vcpu->kvm; - /* Protected KVM does not support AArch32 guests. */ + /* No AArch32 support for protected guests. */ if (kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL0, AARCH32) || kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL1, AARCH32)) return -EINVAL; @@ -210,8 +210,8 @@ static pkvm_handle_t idx_to_vm_handle(unsigned int idx) DEFINE_HYP_SPINLOCK(vm_table_lock); /* - * The table of VM entries for protected VMs in hyp. - * Allocated at hyp initialization and setup. + * A table that tracks all VMs in protected mode. + * Allocated during hyp initialization and setup. */ static struct pkvm_hyp_vm **vm_table; @@ -495,7 +495,7 @@ static int find_free_vm_table_entry(struct kvm *host_kvm) /* * Allocate a VM table entry and insert a pointer to the new vm. * - * Return a unique handle to the protected VM on success, + * Return a unique handle to the VM on success, * negative error code on failure. */ static pkvm_handle_t insert_vm_table_entry(struct kvm *host_kvm, @@ -594,10 +594,8 @@ static void unmap_donated_memory_noclear(void *va, size_t size) } /* - * Initialize the hypervisor copy of the protected VM state using the - * memory donated by the host. - * - * Unmaps the donated memory from the host at stage 2. + * Initialize the hypervisor copy of the VM state using host-donated memory. + * Unmap the donated memory from the host at stage 2. * * host_kvm: A pointer to the host's struct kvm. * vm_hva: The host va of the area being donated for the VM state. @@ -606,7 +604,7 @@ static void unmap_donated_memory_noclear(void *va, size_t size) * the VM. Must be page aligned. Its size is implied by the VM's * VTCR. * - * Return a unique handle to the protected VM on success, + * Return a unique handle to the VM on success, * negative error code on failure. */ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva, @@ -668,10 +666,9 @@ err_unpin_kvm: } /* - * Initialize the hypervisor copy of the protected vCPU state using the - * memory donated by the host. + * Initialize the hypervisor copy of the vCPU state using host-donated memory. * - * handle: The handle for the protected vm. + * handle: The hypervisor handle for the vm. * host_vcpu: A pointer to the corresponding host vcpu. * vcpu_hva: The host va of the area being donated for the vcpu state. * Must be page aligned. The size of the area must be equal to From 3c45b67625357ac680ee2508493b697cdcd78128 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 9 Sep 2025 08:24:32 +0100 Subject: [PATCH 1431/2711] KVM: arm64: Decouple hyp VM creation state from its handle Currently, the presence of a pKVM handle (pkvm.handle != 0) is used to determine if the corresponding hypervisor (EL2) VM has been created and initialized. This couples the handle's lifecycle with the VM's creation state. This coupling will become problematic with upcoming changes that will allocate the pKVM handle earlier in the VM's life, before the VM is instantiated at the hypervisor. To prepare for this and make the state tracking explicit, decouple the two concepts. Introduce a new boolean flag, 'pkvm.is_created', to track whether the hypervisor-side VM has been created and initialized. A new helper, pkvm_hyp_vm_is_created(), is added to check this flag. All call sites that previously checked for the handle's existence are converted to use the new, explicit check. The 'is_created' flag is set to true upon successful creation in the hypervisor (EL2) and cleared upon destruction. Signed-off-by: Fuad Tabba Tested-by: Mark Brown Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/include/asm/kvm_pkvm.h | 1 + arch/arm64/kvm/hyp/nvhe/pkvm.c | 1 + arch/arm64/kvm/pkvm.c | 11 +++++++++-- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index a4289c2f13f5..bc57749e3fb9 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -253,6 +253,7 @@ struct kvm_protected_vm { struct kvm_hyp_memcache teardown_mc; struct kvm_hyp_memcache stage2_teardown_mc; bool is_protected; + bool is_created; }; struct kvm_mpidr_data { diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h index ea58282f59bb..08be89c95466 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -18,6 +18,7 @@ int pkvm_init_host_vm(struct kvm *kvm); int pkvm_create_hyp_vm(struct kvm *kvm); +bool pkvm_hyp_vm_is_created(struct kvm *kvm); void pkvm_destroy_hyp_vm(struct kvm *kvm); int pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index abe173406c88..969f6b293234 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -407,6 +407,7 @@ static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm, hyp_vm->kvm.created_vcpus = nr_vcpus; hyp_vm->kvm.arch.mmu.vtcr = host_mmu.arch.mmu.vtcr; hyp_vm->kvm.arch.pkvm.is_protected = READ_ONCE(host_kvm->arch.pkvm.is_protected); + hyp_vm->kvm.arch.pkvm.is_created = true; hyp_vm->kvm.arch.flags = 0; pkvm_init_features_from_host(hyp_vm, host_kvm); } diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index 7aaeb66e3f39..45d699bba96a 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -87,12 +87,13 @@ void __init kvm_hyp_reserve(void) static void __pkvm_destroy_hyp_vm(struct kvm *kvm) { - if (kvm->arch.pkvm.handle) { + if (pkvm_hyp_vm_is_created(kvm)) { WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm, kvm->arch.pkvm.handle)); } kvm->arch.pkvm.handle = 0; + kvm->arch.pkvm.is_created = false; free_hyp_memcache(&kvm->arch.pkvm.teardown_mc); free_hyp_memcache(&kvm->arch.pkvm.stage2_teardown_mc); } @@ -165,6 +166,7 @@ static int __pkvm_create_hyp_vm(struct kvm *kvm) goto free_vm; kvm->arch.pkvm.handle = ret; + kvm->arch.pkvm.is_created = true; kvm->arch.pkvm.stage2_teardown_mc.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2; kvm_account_pgtable_pages(pgd, pgd_sz / PAGE_SIZE); @@ -176,12 +178,17 @@ free_pgd: return ret; } +bool pkvm_hyp_vm_is_created(struct kvm *kvm) +{ + return READ_ONCE(kvm->arch.pkvm.is_created); +} + int pkvm_create_hyp_vm(struct kvm *kvm) { int ret = 0; mutex_lock(&kvm->arch.config_lock); - if (!kvm->arch.pkvm.handle) + if (!pkvm_hyp_vm_is_created(kvm)) ret = __pkvm_create_hyp_vm(kvm); mutex_unlock(&kvm->arch.config_lock); From 1abc1ad52989fcc45a0de68bc49656d9fd0c2d74 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 9 Sep 2025 08:24:33 +0100 Subject: [PATCH 1432/2711] KVM: arm64: Separate allocation and insertion of pKVM VM table entries The current insert_vm_table_entry() function performs two actions at once: it finds a free slot in the pKVM VM table and populates it with the pkvm_hyp_vm pointer. Refactor this function as a preparatory step for future work that will require reserving a VM slot and its corresponding handle earlier in the VM lifecycle, before the pkvm_hyp_vm structure is initialized and ready to be inserted. Split the function into a two-phase process: - A new allocate_vm_table_entry() function finds an empty slot, marks it as reserved with a RESERVED_ENTRY placeholder, and returns a handle derived from the slot's index. - The insert_vm_table_entry() function is repurposed to take the handle, validate that the corresponding slot is in the reserved state, and then populate it with the pkvm_hyp_vm pointer. Signed-off-by: Fuad Tabba Tested-by: Mark Brown Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/nvhe/pkvm.c | 52 ++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 969f6b293234..64b760d30d05 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -192,6 +192,11 @@ static int pkvm_vcpu_init_traps(struct pkvm_hyp_vcpu *hyp_vcpu) */ #define HANDLE_OFFSET 0x1000 +/* + * Marks a reserved but not yet used entry in the VM table. + */ +#define RESERVED_ENTRY ((void *)0xa110ca7ed) + static unsigned int vm_handle_to_idx(pkvm_handle_t handle) { return handle - HANDLE_OFFSET; @@ -231,6 +236,10 @@ static struct pkvm_hyp_vm *get_vm_by_handle(pkvm_handle_t handle) if (unlikely(idx >= KVM_MAX_PVMS)) return NULL; + /* A reserved entry doesn't represent an initialized VM. */ + if (unlikely(vm_table[idx] == RESERVED_ENTRY)) + return NULL; + return vm_table[idx]; } @@ -481,7 +490,7 @@ done: return ret; } -static int find_free_vm_table_entry(struct kvm *host_kvm) +static int find_free_vm_table_entry(void) { int i; @@ -494,15 +503,13 @@ static int find_free_vm_table_entry(struct kvm *host_kvm) } /* - * Allocate a VM table entry and insert a pointer to the new vm. + * Reserve a VM table entry. * * Return a unique handle to the VM on success, * negative error code on failure. */ -static pkvm_handle_t insert_vm_table_entry(struct kvm *host_kvm, - struct pkvm_hyp_vm *hyp_vm) +static int allocate_vm_table_entry(void) { - struct kvm_s2_mmu *mmu = &hyp_vm->kvm.arch.mmu; int idx; hyp_assert_lock_held(&vm_table_lock); @@ -515,10 +522,30 @@ static pkvm_handle_t insert_vm_table_entry(struct kvm *host_kvm, if (unlikely(!vm_table)) return -EINVAL; - idx = find_free_vm_table_entry(host_kvm); - if (idx < 0) + idx = find_free_vm_table_entry(); + if (unlikely(idx < 0)) return idx; + vm_table[idx] = RESERVED_ENTRY; + + return idx; +} + +/* + * Insert a pointer to the new VM into the VM table. + * + * Return 0 on success, or negative error code on failure. + */ +static int insert_vm_table_entry(struct kvm *host_kvm, + struct pkvm_hyp_vm *hyp_vm, + pkvm_handle_t handle) +{ + struct kvm_s2_mmu *mmu = &hyp_vm->kvm.arch.mmu; + unsigned int idx; + + hyp_assert_lock_held(&vm_table_lock); + + idx = vm_handle_to_idx(handle); hyp_vm->kvm.arch.pkvm.handle = idx_to_vm_handle(idx); /* VMID 0 is reserved for the host */ @@ -528,7 +555,7 @@ static pkvm_handle_t insert_vm_table_entry(struct kvm *host_kvm, mmu->pgt = &hyp_vm->pgt; vm_table[idx] = hyp_vm; - return hyp_vm->kvm.arch.pkvm.handle; + return 0; } /* @@ -614,6 +641,7 @@ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva, struct pkvm_hyp_vm *hyp_vm = NULL; size_t vm_size, pgd_size; unsigned int nr_vcpus; + pkvm_handle_t handle; void *pgd = NULL; int ret; @@ -643,10 +671,16 @@ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva, init_pkvm_hyp_vm(host_kvm, hyp_vm, nr_vcpus); hyp_spin_lock(&vm_table_lock); - ret = insert_vm_table_entry(host_kvm, hyp_vm); + ret = allocate_vm_table_entry(); if (ret < 0) goto err_unlock; + handle = idx_to_vm_handle(ret); + + ret = insert_vm_table_entry(host_kvm, hyp_vm, handle); + if (ret) + goto err_unlock; + ret = kvm_guest_prepare_stage2(hyp_vm, pgd); if (ret) goto err_remove_vm_table_entry; From 814fd6beacf3c105ab8c8796be07d740952899fe Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 9 Sep 2025 08:24:34 +0100 Subject: [PATCH 1433/2711] KVM: arm64: Consolidate pKVM hypervisor VM initialization logic The insert_vm_table_entry() function was performing tasks beyond its primary responsibility. In addition to inserting a VM pointer into the vm_table, it was also initializing several fields within 'struct pkvm_hyp_vm', such as the VMID and stage-2 MMU pointers. This mixing of concerns made the code harder to follow. As another preparatory step towards allowing a VM table entry to be reserved before the VM is fully created, this logic must be cleaned up. By separating table insertion from state initialization, we can control the timing of the initialization step more precisely in subsequent patches. Refactor the code to consolidate all initialization logic into init_pkvm_hyp_vm(): - Move the initialization of the handle, VMID, and MMU fields from insert_vm_table_entry() to init_pkvm_hyp_vm(). - Simplify insert_vm_table_entry() to perform only one action: placing the provided pkvm_hyp_vm pointer into the vm_table. - Update the calling sequence in __pkvm_init_vm() to first allocate an entry in the VM table, initialize the VM, and then insert the VM into the VM table. This is all protected by the vm_table_lock for now. Subsequent patches will adjust the sequence and not hold the vm_table_lock while initializing the VM at the hypervisor (init_pkvm_hyp_vm()). Signed-off-by: Fuad Tabba Tested-by: Mark Brown Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/nvhe/pkvm.c | 47 +++++++++++++++++----------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 64b760d30d05..a9abbeb530f0 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -410,15 +410,26 @@ static void unpin_host_vcpus(struct pkvm_hyp_vcpu *hyp_vcpus[], } static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm, - unsigned int nr_vcpus) + unsigned int nr_vcpus, pkvm_handle_t handle) { + struct kvm_s2_mmu *mmu = &hyp_vm->kvm.arch.mmu; + int idx = vm_handle_to_idx(handle); + + hyp_vm->kvm.arch.pkvm.handle = handle; + hyp_vm->host_kvm = host_kvm; hyp_vm->kvm.created_vcpus = nr_vcpus; - hyp_vm->kvm.arch.mmu.vtcr = host_mmu.arch.mmu.vtcr; hyp_vm->kvm.arch.pkvm.is_protected = READ_ONCE(host_kvm->arch.pkvm.is_protected); hyp_vm->kvm.arch.pkvm.is_created = true; hyp_vm->kvm.arch.flags = 0; pkvm_init_features_from_host(hyp_vm, host_kvm); + + /* VMID 0 is reserved for the host */ + atomic64_set(&mmu->vmid.id, idx + 1); + + mmu->vtcr = host_mmu.arch.mmu.vtcr; + mmu->arch = &hyp_vm->kvm.arch; + mmu->pgt = &hyp_vm->pgt; } static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *host_vcpu) @@ -532,29 +543,19 @@ static int allocate_vm_table_entry(void) } /* - * Insert a pointer to the new VM into the VM table. + * Insert a pointer to the initialized VM into the VM table. * * Return 0 on success, or negative error code on failure. */ -static int insert_vm_table_entry(struct kvm *host_kvm, - struct pkvm_hyp_vm *hyp_vm, - pkvm_handle_t handle) +static int insert_vm_table_entry(pkvm_handle_t handle, + struct pkvm_hyp_vm *hyp_vm) { - struct kvm_s2_mmu *mmu = &hyp_vm->kvm.arch.mmu; unsigned int idx; hyp_assert_lock_held(&vm_table_lock); - idx = vm_handle_to_idx(handle); - hyp_vm->kvm.arch.pkvm.handle = idx_to_vm_handle(idx); - - /* VMID 0 is reserved for the host */ - atomic64_set(&mmu->vmid.id, idx + 1); - - mmu->arch = &hyp_vm->kvm.arch; - mmu->pgt = &hyp_vm->pgt; - vm_table[idx] = hyp_vm; + return 0; } @@ -668,8 +669,6 @@ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva, if (!pgd) goto err_remove_mappings; - init_pkvm_hyp_vm(host_kvm, hyp_vm, nr_vcpus); - hyp_spin_lock(&vm_table_lock); ret = allocate_vm_table_entry(); if (ret < 0) @@ -677,19 +676,21 @@ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva, handle = idx_to_vm_handle(ret); - ret = insert_vm_table_entry(host_kvm, hyp_vm, handle); - if (ret) - goto err_unlock; + init_pkvm_hyp_vm(host_kvm, hyp_vm, nr_vcpus, handle); ret = kvm_guest_prepare_stage2(hyp_vm, pgd); + if (ret) + goto err_remove_vm_table_entry; + + ret = insert_vm_table_entry(handle, hyp_vm); if (ret) goto err_remove_vm_table_entry; hyp_spin_unlock(&vm_table_lock); - return hyp_vm->kvm.arch.pkvm.handle; + return handle; err_remove_vm_table_entry: - remove_vm_table_entry(hyp_vm->kvm.arch.pkvm.handle); + remove_vm_table_entry(handle); err_unlock: hyp_spin_unlock(&vm_table_lock); err_remove_mappings: From 256b4668cd890b741c54f83dbbef76ba847c23be Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 9 Sep 2025 08:24:35 +0100 Subject: [PATCH 1434/2711] KVM: arm64: Introduce separate hypercalls for pKVM VM reservation and initialization The existing __pkvm_init_vm hypercall performs both the reservation of a VM table entry and the initialization of the hypervisor VM state in a single operation. This design prevents the host from obtaining a VM handle from the hypervisor until all preparation for the creation and the initialization of the VM is done, which is on the first vCPU run operation. To support more flexible VM lifecycle management, the host needs the ability to reserve a handle early, before the first vCPU run. Refactor the hypercall interface to enable this, splitting the single hypercall into a two-stage process: - __pkvm_reserve_vm: A new hypercall that allocates a slot in the hypervisor's vm_table, marks it as reserved, and returns a unique handle to the host. - __pkvm_unreserve_vm: A corresponding cleanup hypercall to safely release the reservation if the host fails to proceed with full initialization. - __pkvm_init_vm: The existing hypercall is modified to no longer allocate a slot. It now expects a pre-reserved handle and commits the donated VM memory to that slot. For now, the host-side code in __pkvm_create_hyp_vm calls the new reserve and init hypercalls back-to-back to maintain existing behavior. This paves the way for subsequent patches to separate the reservation and initialization steps in the VM's lifecycle. Signed-off-by: Fuad Tabba Tested-by: Mark Brown Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_asm.h | 2 + arch/arm64/kvm/hyp/include/nvhe/pkvm.h | 2 + arch/arm64/kvm/hyp/nvhe/hyp-main.c | 14 ++++ arch/arm64/kvm/hyp/nvhe/pkvm.c | 102 +++++++++++++++++++------ arch/arm64/kvm/pkvm.c | 12 ++- 5 files changed, 108 insertions(+), 24 deletions(-) diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index bec227f9500a..9da54d4ee49e 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -81,6 +81,8 @@ enum __kvm_host_smccc_func { __KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff, __KVM_HOST_SMCCC_FUNC___vgic_v3_save_vmcr_aprs, __KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs, + __KVM_HOST_SMCCC_FUNC___pkvm_reserve_vm, + __KVM_HOST_SMCCC_FUNC___pkvm_unreserve_vm, __KVM_HOST_SMCCC_FUNC___pkvm_init_vm, __KVM_HOST_SMCCC_FUNC___pkvm_init_vcpu, __KVM_HOST_SMCCC_FUNC___pkvm_teardown_vm, diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h index 4540324b5657..184ad7a39950 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h +++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h @@ -67,6 +67,8 @@ static inline bool pkvm_hyp_vm_is_protected(struct pkvm_hyp_vm *hyp_vm) void pkvm_hyp_vm_table_init(void *tbl); +int __pkvm_reserve_vm(void); +void __pkvm_unreserve_vm(pkvm_handle_t handle); int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva, unsigned long pgd_hva); int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu, diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index 3206b2c07f82..29430c031095 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -546,6 +546,18 @@ static void handle___pkvm_prot_finalize(struct kvm_cpu_context *host_ctxt) cpu_reg(host_ctxt, 1) = __pkvm_prot_finalize(); } +static void handle___pkvm_reserve_vm(struct kvm_cpu_context *host_ctxt) +{ + cpu_reg(host_ctxt, 1) = __pkvm_reserve_vm(); +} + +static void handle___pkvm_unreserve_vm(struct kvm_cpu_context *host_ctxt) +{ + DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1); + + __pkvm_unreserve_vm(handle); +} + static void handle___pkvm_init_vm(struct kvm_cpu_context *host_ctxt) { DECLARE_REG(struct kvm *, host_kvm, host_ctxt, 1); @@ -606,6 +618,8 @@ static const hcall_t host_hcall[] = { HANDLE_FUNC(__kvm_timer_set_cntvoff), HANDLE_FUNC(__vgic_v3_save_vmcr_aprs), HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs), + HANDLE_FUNC(__pkvm_reserve_vm), + HANDLE_FUNC(__pkvm_unreserve_vm), HANDLE_FUNC(__pkvm_init_vm), HANDLE_FUNC(__pkvm_init_vcpu), HANDLE_FUNC(__pkvm_teardown_vm), diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index a9abbeb530f0..05774aed09cb 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -542,6 +542,33 @@ static int allocate_vm_table_entry(void) return idx; } +static int __insert_vm_table_entry(pkvm_handle_t handle, + struct pkvm_hyp_vm *hyp_vm) +{ + unsigned int idx; + + hyp_assert_lock_held(&vm_table_lock); + + /* + * Initializing protected state might have failed, yet a malicious + * host could trigger this function. Thus, ensure that 'vm_table' + * exists. + */ + if (unlikely(!vm_table)) + return -EINVAL; + + idx = vm_handle_to_idx(handle); + if (unlikely(idx >= KVM_MAX_PVMS)) + return -EINVAL; + + if (unlikely(vm_table[idx] != RESERVED_ENTRY)) + return -EINVAL; + + vm_table[idx] = hyp_vm; + + return 0; +} + /* * Insert a pointer to the initialized VM into the VM table. * @@ -550,13 +577,13 @@ static int allocate_vm_table_entry(void) static int insert_vm_table_entry(pkvm_handle_t handle, struct pkvm_hyp_vm *hyp_vm) { - unsigned int idx; + int ret; - hyp_assert_lock_held(&vm_table_lock); - idx = vm_handle_to_idx(handle); - vm_table[idx] = hyp_vm; + hyp_spin_lock(&vm_table_lock); + ret = __insert_vm_table_entry(handle, hyp_vm); + hyp_spin_unlock(&vm_table_lock); - return 0; + return ret; } /* @@ -622,8 +649,45 @@ static void unmap_donated_memory_noclear(void *va, size_t size) __unmap_donated_memory(va, size); } +/* + * Reserves an entry in the hypervisor for a new VM in protected mode. + * + * Return a unique handle to the VM on success, negative error code on failure. + */ +int __pkvm_reserve_vm(void) +{ + int ret; + + hyp_spin_lock(&vm_table_lock); + ret = allocate_vm_table_entry(); + hyp_spin_unlock(&vm_table_lock); + + if (ret < 0) + return ret; + + return idx_to_vm_handle(ret); +} + +/* + * Removes a reserved entry, but only if is hasn't been used yet. + * Otherwise, the VM needs to be destroyed. + */ +void __pkvm_unreserve_vm(pkvm_handle_t handle) +{ + unsigned int idx = vm_handle_to_idx(handle); + + if (unlikely(!vm_table)) + return; + + hyp_spin_lock(&vm_table_lock); + if (likely(idx < KVM_MAX_PVMS && vm_table[idx] == RESERVED_ENTRY)) + remove_vm_table_entry(handle); + hyp_spin_unlock(&vm_table_lock); +} + /* * Initialize the hypervisor copy of the VM state using host-donated memory. + * * Unmap the donated memory from the host at stage 2. * * host_kvm: A pointer to the host's struct kvm. @@ -633,8 +697,7 @@ static void unmap_donated_memory_noclear(void *va, size_t size) * the VM. Must be page aligned. Its size is implied by the VM's * VTCR. * - * Return a unique handle to the VM on success, - * negative error code on failure. + * Return 0 success, negative error code on failure. */ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva, unsigned long pgd_hva) @@ -656,6 +719,12 @@ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva, goto err_unpin_kvm; } + handle = READ_ONCE(host_kvm->arch.pkvm.handle); + if (unlikely(handle < HANDLE_OFFSET)) { + ret = -EINVAL; + goto err_unpin_kvm; + } + vm_size = pkvm_get_hyp_vm_size(nr_vcpus); pgd_size = kvm_pgtable_stage2_pgd_size(host_mmu.arch.mmu.vtcr); @@ -669,30 +738,19 @@ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva, if (!pgd) goto err_remove_mappings; - hyp_spin_lock(&vm_table_lock); - ret = allocate_vm_table_entry(); - if (ret < 0) - goto err_unlock; - - handle = idx_to_vm_handle(ret); - init_pkvm_hyp_vm(host_kvm, hyp_vm, nr_vcpus, handle); ret = kvm_guest_prepare_stage2(hyp_vm, pgd); if (ret) - goto err_remove_vm_table_entry; + goto err_remove_mappings; + /* Must be called last since this publishes the VM. */ ret = insert_vm_table_entry(handle, hyp_vm); if (ret) - goto err_remove_vm_table_entry; - hyp_spin_unlock(&vm_table_lock); + goto err_remove_mappings; - return handle; + return 0; -err_remove_vm_table_entry: - remove_vm_table_entry(handle); -err_unlock: - hyp_spin_unlock(&vm_table_lock); err_remove_mappings: unmap_donated_memory(hyp_vm, vm_size); unmap_donated_memory(pgd, pgd_size); diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index 45d699bba96a..082bc15f436c 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -160,17 +160,25 @@ static int __pkvm_create_hyp_vm(struct kvm *kvm) goto free_pgd; } - /* Donate the VM memory to hyp and let hyp initialize it. */ - ret = kvm_call_hyp_nvhe(__pkvm_init_vm, kvm, hyp_vm, pgd); + /* Reserve the VM in hyp and obtain a hyp handle for the VM. */ + ret = kvm_call_hyp_nvhe(__pkvm_reserve_vm); if (ret < 0) goto free_vm; kvm->arch.pkvm.handle = ret; + + /* Donate the VM memory to hyp and let hyp initialize it. */ + ret = kvm_call_hyp_nvhe(__pkvm_init_vm, kvm, hyp_vm, pgd); + if (ret) + goto unreserve_vm; + kvm->arch.pkvm.is_created = true; kvm->arch.pkvm.stage2_teardown_mc.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2; kvm_account_pgtable_pages(pgd, pgd_sz / PAGE_SIZE); return 0; +unreserve_vm: + kvm_call_hyp_nvhe(__pkvm_unreserve_vm, kvm->arch.pkvm.handle); free_vm: free_pages_exact(hyp_vm, hyp_vm_sz); free_pgd: From 07aeb70707b1d52968f4959a5dba321ea4219c8a Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 9 Sep 2025 08:24:36 +0100 Subject: [PATCH 1435/2711] KVM: arm64: Reserve pKVM handle during pkvm_init_host_vm() When a pKVM guest is active, TLB invalidations triggered by host MMU notifiers require a valid hypervisor handle. Currently, this handle is only allocated when the first vCPU is run. However, the guest's memory is associated with the host MMU much earlier, during kvm_arch_init_vm(). This creates a window where an MMU invalidation could occur after the kvm_pgtable pointer checked by the notifiers is set but before the pKVM handle has been created. Fix this by reserving the pKVM handle when the host VM is first set up. Move the call to the __pkvm_reserve_vm hypercall from the first-vCPU-run path into pkvm_init_host_vm(), which is called during initial VM setup. This ensures the handle is available before any subsystem can trigger an MMU notification for the VM. The VM destruction path is updated to call __pkvm_unreserve_vm for cases where a VM was reserved but never fully created at the hypervisor, ensuring the handle is properly released. This fix leverages the two-stage reservation/initialization hypercall interface introduced in preceding patches. Signed-off-by: Fuad Tabba Tested-by: Mark Brown Signed-off-by: Marc Zyngier --- arch/arm64/kvm/arm.c | 14 ++++++++++---- arch/arm64/kvm/pkvm.c | 33 +++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 888f7c7abf54..1849bdede4f2 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -170,10 +170,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) if (ret) return ret; - ret = pkvm_init_host_vm(kvm); - if (ret) - goto err_unshare_kvm; - if (!zalloc_cpumask_var(&kvm->arch.supported_cpus, GFP_KERNEL_ACCOUNT)) { ret = -ENOMEM; goto err_unshare_kvm; @@ -184,6 +180,16 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) if (ret) goto err_free_cpumask; + if (is_protected_kvm_enabled()) { + /* + * If any failures occur after this is successful, make sure to + * call __pkvm_unreserve_vm to unreserve the VM in hyp. + */ + ret = pkvm_init_host_vm(kvm); + if (ret) + goto err_free_cpumask; + } + kvm_vgic_early_init(kvm); kvm_timer_init_vm(kvm); diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index 082bc15f436c..24f0f8a8c943 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -90,6 +90,12 @@ static void __pkvm_destroy_hyp_vm(struct kvm *kvm) if (pkvm_hyp_vm_is_created(kvm)) { WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm, kvm->arch.pkvm.handle)); + } else if (kvm->arch.pkvm.handle) { + /* + * The VM could have been reserved but hyp initialization has + * failed. Make sure to unreserve it. + */ + kvm_call_hyp_nvhe(__pkvm_unreserve_vm, kvm->arch.pkvm.handle); } kvm->arch.pkvm.handle = 0; @@ -160,25 +166,16 @@ static int __pkvm_create_hyp_vm(struct kvm *kvm) goto free_pgd; } - /* Reserve the VM in hyp and obtain a hyp handle for the VM. */ - ret = kvm_call_hyp_nvhe(__pkvm_reserve_vm); - if (ret < 0) - goto free_vm; - - kvm->arch.pkvm.handle = ret; - /* Donate the VM memory to hyp and let hyp initialize it. */ ret = kvm_call_hyp_nvhe(__pkvm_init_vm, kvm, hyp_vm, pgd); if (ret) - goto unreserve_vm; + goto free_vm; kvm->arch.pkvm.is_created = true; kvm->arch.pkvm.stage2_teardown_mc.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2; kvm_account_pgtable_pages(pgd, pgd_sz / PAGE_SIZE); return 0; -unreserve_vm: - kvm_call_hyp_nvhe(__pkvm_unreserve_vm, kvm->arch.pkvm.handle); free_vm: free_pages_exact(hyp_vm, hyp_vm_sz); free_pgd: @@ -224,6 +221,22 @@ void pkvm_destroy_hyp_vm(struct kvm *kvm) int pkvm_init_host_vm(struct kvm *kvm) { + int ret; + + if (pkvm_hyp_vm_is_created(kvm)) + return -EINVAL; + + /* VM is already reserved, no need to proceed. */ + if (kvm->arch.pkvm.handle) + return 0; + + /* Reserve the VM in hyp and obtain a hyp handle for the VM. */ + ret = kvm_call_hyp_nvhe(__pkvm_reserve_vm); + if (ret < 0) + return ret; + + kvm->arch.pkvm.handle = ret; + return 0; } From 8810c6e7cca8fbfce7652b53e05acc465e671d28 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 9 Sep 2025 10:00:04 +0000 Subject: [PATCH 1436/2711] KVM: arm64: vgic-init: Remove vgic_ready() macro It is now used only within kvm_vgic_map_resources(). vgic_dist::ready is already written directly by this function, so it is clearer to bypass the macro for reads as well. Signed-off-by: Keir Fraser Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic/vgic-init.c | 5 ++--- include/kvm/arm_vgic.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index 1e680ad6e863..3f207b5f80a5 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -554,7 +554,6 @@ int vgic_lazy_init(struct kvm *kvm) * Also map the virtual CPU interface into the VM. * v2 calls vgic_init() if not already done. * v3 and derivatives return an error if the VGIC is not initialized. - * vgic_ready() returns true if this function has succeeded. */ int kvm_vgic_map_resources(struct kvm *kvm) { @@ -563,12 +562,12 @@ int kvm_vgic_map_resources(struct kvm *kvm) gpa_t dist_base; int ret = 0; - if (likely(vgic_ready(kvm))) + if (likely(dist->ready)) return 0; mutex_lock(&kvm->slots_lock); mutex_lock(&kvm->arch.config_lock); - if (vgic_ready(kvm)) + if (dist->ready) goto out; if (!irqchip_in_kernel(kvm)) diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 404883c7af6e..e7ffaf4bf2e7 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -406,7 +406,6 @@ u64 vgic_v3_get_misr(struct kvm_vcpu *vcpu); #define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel)) #define vgic_initialized(k) ((k)->arch.vgic.initialized) -#define vgic_ready(k) ((k)->arch.vgic.ready) #define vgic_valid_spi(k, i) (((i) >= VGIC_NR_PRIVATE_IRQS) && \ ((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS)) From 11490b5ec6bc4fe3a36f90817bbc8021ba8b05cd Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 9 Sep 2025 10:00:05 +0000 Subject: [PATCH 1437/2711] KVM: arm64: vgic: Explicitly implement vgic_dist::ready ordering In preparation to remove synchronize_srcu() from MMIO registration, remove the distributor's dependency on this implicit barrier by direct acquire-release synchronization on the flag write and its lock-free check. Signed-off-by: Keir Fraser Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic/vgic-init.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index 3f207b5f80a5..ccccb5c04ac1 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -562,7 +562,7 @@ int kvm_vgic_map_resources(struct kvm *kvm) gpa_t dist_base; int ret = 0; - if (likely(dist->ready)) + if (likely(smp_load_acquire(&dist->ready))) return 0; mutex_lock(&kvm->slots_lock); @@ -593,14 +593,7 @@ int kvm_vgic_map_resources(struct kvm *kvm) goto out_slots; } - /* - * kvm_io_bus_register_dev() guarantees all readers see the new MMIO - * registration before returning through synchronize_srcu(), which also - * implies a full memory barrier. As such, marking the distributor as - * 'ready' here is guaranteed to be ordered after all vCPUs having seen - * a completely configured distributor. - */ - dist->ready = true; + smp_store_release(&dist->ready, true); goto out_slots; out: mutex_unlock(&kvm->arch.config_lock); From 7788255aba6545a27b8d143c5256536f8dfb2c0a Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 9 Sep 2025 10:00:06 +0000 Subject: [PATCH 1438/2711] KVM: Implement barriers before accessing kvm->buses[] on SRCU read paths This ensures that, if a VCPU has "observed" that an IO registration has occurred, the instruction currently being trapped or emulated will also observe the IO registration. At the same time, enforce that kvm_get_bus() is used only on the update side, ensuring that a long-term reference cannot be obtained by an SRCU reader. Signed-off-by: Keir Fraser Signed-off-by: Marc Zyngier --- arch/x86/kvm/vmx/vmx.c | 7 +++++++ include/linux/kvm_host.h | 10 +++++++--- virt/kvm/kvm_main.c | 32 ++++++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index aa157fe5b7b3..0bdf9405969a 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -5785,6 +5785,13 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) if (kvm_test_request(KVM_REQ_EVENT, vcpu)) return 1; + /* + * Ensure that any updates to kvm->buses[] observed by the + * previous instruction (emulated or otherwise) are also + * visible to the instruction KVM is about to emulate. + */ + smp_rmb(); + if (!kvm_emulate_instruction(vcpu, 0)) return 0; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 15656b7fba6c..e7d6111cf254 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -966,11 +966,15 @@ static inline bool kvm_dirty_log_manual_protect_and_init_set(struct kvm *kvm) return !!(kvm->manual_dirty_log_protect & KVM_DIRTY_LOG_INITIALLY_SET); } +/* + * Get a bus reference under the update-side lock. No long-term SRCU reader + * references are permitted, to avoid stale reads vs concurrent IO + * registrations. + */ static inline struct kvm_io_bus *kvm_get_bus(struct kvm *kvm, enum kvm_bus idx) { - return srcu_dereference_check(kvm->buses[idx], &kvm->srcu, - lockdep_is_held(&kvm->slots_lock) || - !refcount_read(&kvm->users_count)); + return rcu_dereference_protected(kvm->buses[idx], + lockdep_is_held(&kvm->slots_lock)); } static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 6c07dd423458..870ad8ea93a7 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1103,6 +1103,14 @@ void __weak kvm_arch_create_vm_debugfs(struct kvm *kvm) { } +/* Called only on cleanup and destruction paths when there are no users. */ +static inline struct kvm_io_bus *kvm_get_bus_for_destruction(struct kvm *kvm, + enum kvm_bus idx) +{ + return rcu_dereference_protected(kvm->buses[idx], + !refcount_read(&kvm->users_count)); +} + static struct kvm *kvm_create_vm(unsigned long type, const char *fdname) { struct kvm *kvm = kvm_arch_alloc_vm(); @@ -1228,7 +1236,7 @@ out_err_no_disable: out_err_no_arch_destroy_vm: WARN_ON_ONCE(!refcount_dec_and_test(&kvm->users_count)); for (i = 0; i < KVM_NR_BUSES; i++) - kfree(kvm_get_bus(kvm, i)); + kfree(kvm_get_bus_for_destruction(kvm, i)); kvm_free_irq_routing(kvm); out_err_no_irq_routing: cleanup_srcu_struct(&kvm->irq_srcu); @@ -1276,7 +1284,7 @@ static void kvm_destroy_vm(struct kvm *kvm) kvm_free_irq_routing(kvm); for (i = 0; i < KVM_NR_BUSES; i++) { - struct kvm_io_bus *bus = kvm_get_bus(kvm, i); + struct kvm_io_bus *bus = kvm_get_bus_for_destruction(kvm, i); if (bus) kvm_io_bus_destroy(bus); @@ -5843,6 +5851,18 @@ static int __kvm_io_bus_write(struct kvm_vcpu *vcpu, struct kvm_io_bus *bus, return -EOPNOTSUPP; } +static struct kvm_io_bus *kvm_get_bus_srcu(struct kvm *kvm, enum kvm_bus idx) +{ + /* + * Ensure that any updates to kvm_buses[] observed by the previous vCPU + * machine instruction are also visible to the vCPU machine instruction + * that triggered this call. + */ + smp_mb__after_srcu_read_lock(); + + return srcu_dereference(kvm->buses[idx], &kvm->srcu); +} + int kvm_io_bus_write(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr, int len, const void *val) { @@ -5855,7 +5875,7 @@ int kvm_io_bus_write(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr, .len = len, }; - bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu); + bus = kvm_get_bus_srcu(vcpu->kvm, bus_idx); if (!bus) return -ENOMEM; r = __kvm_io_bus_write(vcpu, bus, &range, val); @@ -5874,7 +5894,7 @@ int kvm_io_bus_write_cookie(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, .len = len, }; - bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu); + bus = kvm_get_bus_srcu(vcpu->kvm, bus_idx); if (!bus) return -ENOMEM; @@ -5924,7 +5944,7 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr, .len = len, }; - bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu); + bus = kvm_get_bus_srcu(vcpu->kvm, bus_idx); if (!bus) return -ENOMEM; r = __kvm_io_bus_read(vcpu, bus, &range, val); @@ -6033,7 +6053,7 @@ struct kvm_io_device *kvm_io_bus_get_dev(struct kvm *kvm, enum kvm_bus bus_idx, srcu_idx = srcu_read_lock(&kvm->srcu); - bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); + bus = kvm_get_bus_srcu(kvm, bus_idx); if (!bus) goto out_unlock; From 7d9a0273c45962e9a6bc06f3b87eef7c431c1853 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 9 Sep 2025 10:00:07 +0000 Subject: [PATCH 1439/2711] KVM: Avoid synchronize_srcu() in kvm_io_bus_register_dev() Device MMIO registration may happen quite frequently during VM boot, and the SRCU synchronization each time has a measurable effect on VM startup time. In our experiments it can account for around 25% of a VM's startup time. Replace the synchronization with a deferred free of the old kvm_io_bus structure. Tested-by: Li RongQing Signed-off-by: Keir Fraser Signed-off-by: Marc Zyngier --- include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index e7d6111cf254..103be35caf0d 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -206,6 +206,7 @@ struct kvm_io_range { struct kvm_io_bus { int dev_count; int ioeventfd_count; + struct rcu_head rcu; struct kvm_io_range range[]; }; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 870ad8ea93a7..bcef324ccbf2 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1320,6 +1320,7 @@ static void kvm_destroy_vm(struct kvm *kvm) kvm_free_memslots(kvm, &kvm->__memslots[i][1]); } cleanup_srcu_struct(&kvm->irq_srcu); + srcu_barrier(&kvm->srcu); cleanup_srcu_struct(&kvm->srcu); #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES xa_destroy(&kvm->mem_attr_array); @@ -5952,6 +5953,13 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr, } EXPORT_SYMBOL_GPL(kvm_io_bus_read); +static void __free_bus(struct rcu_head *rcu) +{ + struct kvm_io_bus *bus = container_of(rcu, struct kvm_io_bus, rcu); + + kfree(bus); +} + int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, int len, struct kvm_io_device *dev) { @@ -5990,8 +5998,7 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, memcpy(new_bus->range + i + 1, bus->range + i, (bus->dev_count - i) * sizeof(struct kvm_io_range)); rcu_assign_pointer(kvm->buses[bus_idx], new_bus); - synchronize_srcu_expedited(&kvm->srcu); - kfree(bus); + call_srcu(&kvm->srcu, &bus->rcu, __free_bus); return 0; } From 27d2b47eef033f1fc6c0452dc1017e43dad5fe14 Mon Sep 17 00:00:00 2001 From: Yingchao Deng Date: Tue, 2 Sep 2025 11:48:25 +0800 Subject: [PATCH 1440/2711] KVM: arm64: Return early from trace helpers when KVM isn't available When Linux is booted at EL1, host_data_ptr() resolves to the nVHE hypervisor's copy of host data. When hyp mode isn't available for KVM the nVHE percpu bases remain uninitialized. Consequently, any usage of host_data_ptr() will result in a NULL dereference which has been observed in KVM's trace filtering helpers. Add an early return to the trace filtering helpers if KVM isn't initialized, avoiding the NULL dereference. Take this opportunity to move the TRBE-skipping checks to a common helper. Fixes: 054b88391bbe2 ("KVM: arm64: Support trace filtering for guests") Signed-off-by: Yingchao Deng Reviewed-by: James Clark [maz: repainted the helpers to be readable, and the commit message with Oliver's suggestion] Signed-off-by: Marc Zyngier --- arch/arm64/kvm/debug.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 381382c19fe4..1aaeb40a9a38 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -230,29 +230,29 @@ void kvm_debug_handle_oslar(struct kvm_vcpu *vcpu, u64 val) preempt_enable(); } +static bool skip_trbe_access(bool skip_condition) +{ + return (WARN_ON_ONCE(preemptible()) || skip_condition || + is_protected_kvm_enabled() || !is_kvm_arm_initialised()); +} + void kvm_enable_trbe(void) { - if (has_vhe() || is_protected_kvm_enabled() || - WARN_ON_ONCE(preemptible())) - return; - - host_data_set_flag(TRBE_ENABLED); + if (!skip_trbe_access(has_vhe())) + host_data_set_flag(TRBE_ENABLED); } EXPORT_SYMBOL_GPL(kvm_enable_trbe); void kvm_disable_trbe(void) { - if (has_vhe() || is_protected_kvm_enabled() || - WARN_ON_ONCE(preemptible())) - return; - - host_data_clear_flag(TRBE_ENABLED); + if (!skip_trbe_access(has_vhe())) + host_data_clear_flag(TRBE_ENABLED); } EXPORT_SYMBOL_GPL(kvm_disable_trbe); void kvm_tracing_set_el1_configuration(u64 trfcr_while_in_guest) { - if (is_protected_kvm_enabled() || WARN_ON_ONCE(preemptible())) + if (skip_trbe_access(false)) return; if (has_vhe()) { From 92b7624fe052ffb0b7b70d96cd514e02e91664a8 Mon Sep 17 00:00:00 2001 From: Mostafa Saleh Date: Tue, 9 Sep 2025 13:36:30 +0000 Subject: [PATCH 1441/2711] KVM: arm64: Dump instruction on hyp panic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to the kernel panic, where the instruction code is printed, we can do the same for hypervisor panics. This patch does that only in case of “CONFIG_NVHE_EL2_DEBUG” or nvhe. The next patch adds support for pKVM. Also, remove the hardcoded argument dump_kernel_instr(). Signed-off-by: Mostafa Saleh Tested-by: Kunwu Chan Reviewed-by: Kunwu Chan Acked-by: Will Deacon Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/traps.h | 1 + arch/arm64/kernel/traps.c | 15 +++++++++------ arch/arm64/kvm/handle_exit.c | 5 +++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index e3e8944a71c3..e92e4a0e48fc 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -36,6 +36,7 @@ int kasan_brk_handler(struct pt_regs *regs, unsigned long esr); int ubsan_brk_handler(struct pt_regs *regs, unsigned long esr); int early_brk64(unsigned long addr, unsigned long esr, struct pt_regs *regs); +void dump_kernel_instr(unsigned long kaddr); /* * Move regs->pc to next instruction and do necessary setup before it diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index f528b6041f6a..83e6d1409e1f 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -149,19 +149,18 @@ pstate_check_t * const aarch32_opcode_cond_checks[16] = { int show_unhandled_signals = 0; -static void dump_kernel_instr(const char *lvl, struct pt_regs *regs) +void dump_kernel_instr(unsigned long kaddr) { - unsigned long addr = instruction_pointer(regs); char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str; int i; - if (user_mode(regs)) + if (!is_ttbr1_addr(kaddr)) return; for (i = -4; i < 1; i++) { unsigned int val, bad; - bad = aarch64_insn_read(&((u32 *)addr)[i], &val); + bad = aarch64_insn_read(&((u32 *)kaddr)[i], &val); if (!bad) p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val); @@ -169,7 +168,7 @@ static void dump_kernel_instr(const char *lvl, struct pt_regs *regs) p += sprintf(p, i == 0 ? "(????????) " : "???????? "); } - printk("%sCode: %s\n", lvl, str); + printk(KERN_EMERG "Code: %s\n", str); } #define S_SMP " SMP" @@ -178,6 +177,7 @@ static int __die(const char *str, long err, struct pt_regs *regs) { static int die_counter; int ret; + unsigned long addr = instruction_pointer(regs); pr_emerg("Internal error: %s: %016lx [#%d] " S_SMP "\n", str, err, ++die_counter); @@ -190,7 +190,10 @@ static int __die(const char *str, long err, struct pt_regs *regs) print_modules(); show_regs(regs); - dump_kernel_instr(KERN_EMERG, regs); + if (user_mode(regs)) + return ret; + + dump_kernel_instr(addr); return ret; } diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index a598072f36d2..99a8205fc104 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -559,6 +559,11 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, /* Dump the nVHE hypervisor backtrace */ kvm_nvhe_dump_backtrace(hyp_offset); + /* Dump the faulting instruction */ + if (!is_protected_kvm_enabled() || + IS_ENABLED(CONFIG_NVHE_EL2_DEBUG)) + dump_kernel_instr(panic_addr + kaslr_offset()); + /* * Hyp has panicked and we're going to handle that by panicking the * kernel. The kernel offset will be revealed in the panic so we're From 6f1ece1e868839cf81a28c77e19420ff57df7ecf Mon Sep 17 00:00:00 2001 From: Mostafa Saleh Date: Tue, 9 Sep 2025 13:36:31 +0000 Subject: [PATCH 1442/2711] KVM: arm64: Map hyp text as RO and dump instr on panic Map the hyp text section as RO, there are no secrets there and that allows the kernel extract info for debugging. As in case of panic we can now dump the faulting instructions similar to the kernel. Signed-off-by: Mostafa Saleh Acked-by: Will Deacon Signed-off-by: Marc Zyngier --- arch/arm64/kvm/handle_exit.c | 4 +--- arch/arm64/kvm/hyp/nvhe/setup.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 99a8205fc104..d449e15680e4 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -560,9 +560,7 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, kvm_nvhe_dump_backtrace(hyp_offset); /* Dump the faulting instruction */ - if (!is_protected_kvm_enabled() || - IS_ENABLED(CONFIG_NVHE_EL2_DEBUG)) - dump_kernel_instr(panic_addr + kaslr_offset()); + dump_kernel_instr(panic_addr + kaslr_offset()); /* * Hyp has panicked and we're going to handle that by panicking the diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c index a48d3f5a5afb..90bd014e952f 100644 --- a/arch/arm64/kvm/hyp/nvhe/setup.c +++ b/arch/arm64/kvm/hyp/nvhe/setup.c @@ -192,6 +192,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx, enum pkvm_page_state state; struct hyp_page *page; phys_addr_t phys; + enum kvm_pgtable_prot prot; if (!kvm_pte_valid(ctx->old)) return 0; @@ -210,11 +211,18 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx, * configured in the hypervisor stage-1, and make sure to propagate them * to the hyp_vmemmap state. */ - state = pkvm_getstate(kvm_pgtable_hyp_pte_prot(ctx->old)); + prot = kvm_pgtable_hyp_pte_prot(ctx->old); + state = pkvm_getstate(prot); switch (state) { case PKVM_PAGE_OWNED: set_hyp_state(page, PKVM_PAGE_OWNED); - return host_stage2_set_owner_locked(phys, PAGE_SIZE, PKVM_ID_HYP); + /* hyp text is RO in the host stage-2 to be inspected on panic. */ + if (prot == PAGE_HYP_EXEC) { + set_host_state(page, PKVM_NOPAGE); + return host_stage2_idmap_locked(phys, PAGE_SIZE, KVM_PGTABLE_PROT_R); + } else { + return host_stage2_set_owner_locked(phys, PAGE_SIZE, PKVM_ID_HYP); + } case PKVM_PAGE_SHARED_OWNED: set_hyp_state(page, PKVM_PAGE_SHARED_OWNED); set_host_state(page, PKVM_PAGE_SHARED_BORROWED); From be975448a45cd024e2b98598eefc0e164ad93f09 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 22 Jul 2025 14:25:35 -0700 Subject: [PATCH 1443/2711] srcu: Document __srcu_read_{,un}lock_fast() implicit RCU readers This commit documents the implicit RCU readers that are implied by the this_cpu_inc() and atomic_long_inc() operations in __srcu_read_lock_fast() and __srcu_read_unlock_fast(). While in the area, fix the documentation of the memory pairing of atomic_long_inc() in __srcu_read_lock_fast(). [ paulmck: Apply Joel Fernandes feedback. ] Signed-off-by: Paul E. McKenney Cc: Mathieu Desnoyers Cc: Steven Rostedt Cc: Sebastian Andrzej Siewior Cc: --- include/linux/srcutree.h | 42 ++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/include/linux/srcutree.h b/include/linux/srcutree.h index 4d2fee4d3828..42098e0fa0b7 100644 --- a/include/linux/srcutree.h +++ b/include/linux/srcutree.h @@ -232,9 +232,27 @@ static inline struct srcu_ctr __percpu *__srcu_ctr_to_ptr(struct srcu_struct *ss * srcu_read_unlock_fast(). * * Note that both this_cpu_inc() and atomic_long_inc() are RCU read-side - * critical sections either because they disables interrupts, because they - * are a single instruction, or because they are a read-modify-write atomic - * operation, depending on the whims of the architecture. + * critical sections either because they disables interrupts, because + * they are a single instruction, or because they are read-modify-write + * atomic operations, depending on the whims of the architecture. + * This matters because the SRCU-fast grace-period mechanism uses either + * synchronize_rcu() or synchronize_rcu_expedited(), that is, RCU, + * *not* SRCU, in order to eliminate the need for the read-side smp_mb() + * invocations that are used by srcu_read_lock() and srcu_read_unlock(). + * The __srcu_read_unlock_fast() function also relies on this same RCU + * (again, *not* SRCU) trick to eliminate the need for smp_mb(). + * + * The key point behind this RCU trick is that if any part of a given + * RCU reader precedes the beginning of a given RCU grace period, then + * the entirety of that RCU reader and everything preceding it happens + * before the end of that same RCU grace period. Similarly, if any part + * of a given RCU reader follows the end of a given RCU grace period, + * then the entirety of that RCU reader and everything following it + * happens after the beginning of that same RCU grace period. Therefore, + * the operations labeled Y in __srcu_read_lock_fast() and those labeled Z + * in __srcu_read_unlock_fast() are ordered against the corresponding SRCU + * read-side critical section from the viewpoint of the SRCU grace period. + * This is all the ordering that is required, hence no calls to smp_mb(). * * This means that __srcu_read_lock_fast() is not all that fast * on architectures that support NMIs but do not supply NMI-safe @@ -245,9 +263,9 @@ static inline struct srcu_ctr __percpu notrace *__srcu_read_lock_fast(struct src struct srcu_ctr __percpu *scp = READ_ONCE(ssp->srcu_ctrp); if (!IS_ENABLED(CONFIG_NEED_SRCU_NMI_SAFE)) - this_cpu_inc(scp->srcu_locks.counter); /* Y */ + this_cpu_inc(scp->srcu_locks.counter); // Y, and implicit RCU reader. else - atomic_long_inc(raw_cpu_ptr(&scp->srcu_locks)); /* Z */ + atomic_long_inc(raw_cpu_ptr(&scp->srcu_locks)); // Y, and implicit RCU reader. barrier(); /* Avoid leaking the critical section. */ return scp; } @@ -258,23 +276,17 @@ static inline struct srcu_ctr __percpu notrace *__srcu_read_lock_fast(struct src * different CPU than that which was incremented by the corresponding * srcu_read_lock_fast(), but it must be within the same task. * - * Note that both this_cpu_inc() and atomic_long_inc() are RCU read-side - * critical sections either because they disables interrupts, because they - * are a single instruction, or because they are a read-modify-write atomic - * operation, depending on the whims of the architecture. - * - * This means that __srcu_read_unlock_fast() is not all that fast - * on architectures that support NMIs but do not supply NMI-safe - * implementations of this_cpu_inc(). + * Please see the __srcu_read_lock_fast() function's header comment for + * information on implicit RCU readers and NMI safety. */ static inline void notrace __srcu_read_unlock_fast(struct srcu_struct *ssp, struct srcu_ctr __percpu *scp) { barrier(); /* Avoid leaking the critical section. */ if (!IS_ENABLED(CONFIG_NEED_SRCU_NMI_SAFE)) - this_cpu_inc(scp->srcu_unlocks.counter); /* Z */ + this_cpu_inc(scp->srcu_unlocks.counter); // Z, and implicit RCU reader. else - atomic_long_inc(raw_cpu_ptr(&scp->srcu_unlocks)); /* Z */ + atomic_long_inc(raw_cpu_ptr(&scp->srcu_unlocks)); // Z, and implicit RCU reader. } void __srcu_check_read_flavor(struct srcu_struct *ssp, int read_flavor); From 1c77e862b81e8fe84d3a908271c72da9711ea801 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 22 Jul 2025 14:57:33 -0700 Subject: [PATCH 1444/2711] srcu: Document srcu_flip() memory-barrier D relation to SRCU-fast The smp_mb() memory barrier at the end of srcu_flip() has a comment, but that comment does not make it clear that this memory barrier is an optimization, as opposed to being needed for correctness. This commit therefore adds this information and points out that it is omitted for SRCU-fast, where a much heavier weight synchronize_srcu() would be required. Signed-off-by: Paul E. McKenney Cc: Mathieu Desnoyers Cc: Steven Rostedt Cc: Sebastian Andrzej Siewior Cc: --- kernel/rcu/srcutree.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c index c5e8ebc493d5..1ff94b76d91f 100644 --- a/kernel/rcu/srcutree.c +++ b/kernel/rcu/srcutree.c @@ -1168,6 +1168,16 @@ static void srcu_flip(struct srcu_struct *ssp) * counter update. Note that both this memory barrier and the * one in srcu_readers_active_idx_check() provide the guarantee * for __srcu_read_lock(). + * + * Note that this is a performance optimization, in which we spend + * an otherwise unnecessary smp_mb() in order to reduce the number + * of full per-CPU-variable scans in srcu_readers_lock_idx() and + * srcu_readers_unlock_idx(). But this performance optimization + * is not so optimal for SRCU-fast, where we would be spending + * not smp_mb(), but rather synchronize_rcu(). At the same time, + * the overhead of the smp_mb() is in the noise, so there is no + * point in omitting it in the SRCU-fast case. So the same code + * is executed either way. */ smp_mb(); /* D */ /* Pairs with C. */ } From e6a43aeb71852a39432332dcc3a6d11bb464b075 Mon Sep 17 00:00:00 2001 From: Zqiang Date: Thu, 11 Sep 2025 20:51:55 +0800 Subject: [PATCH 1445/2711] srcu/tiny: Remove preempt_disable/enable() in srcu_gp_start_if_needed() Currently, the srcu_gp_start_if_needed() is always be invoked in preempt disable's critical section, this commit therefore remove redundant preempt_disable/enable() in srcu_gp_start_if_needed() and adds a call to lockdep_assert_preemption_disabled() in order to enable lockdep to diagnose mistaken invocations of this function from preempts-enabled code. Fixes: 65b4a59557f6 ("srcu: Make Tiny SRCU explicitly disable preemption") Signed-off-by: Zqiang Signed-off-by: Paul E. McKenney --- kernel/rcu/srcutiny.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/rcu/srcutiny.c b/kernel/rcu/srcutiny.c index 6e9fe2ce1075..e3b64a5e0ec7 100644 --- a/kernel/rcu/srcutiny.c +++ b/kernel/rcu/srcutiny.c @@ -176,10 +176,9 @@ static void srcu_gp_start_if_needed(struct srcu_struct *ssp) { unsigned long cookie; - preempt_disable(); // Needed for PREEMPT_LAZY + lockdep_assert_preemption_disabled(); // Needed for PREEMPT_LAZY cookie = get_state_synchronize_srcu(ssp); if (ULONG_CMP_GE(READ_ONCE(ssp->srcu_idx_max), cookie)) { - preempt_enable(); return; } WRITE_ONCE(ssp->srcu_idx_max, cookie); @@ -189,7 +188,6 @@ static void srcu_gp_start_if_needed(struct srcu_struct *ssp) else if (list_empty(&ssp->srcu_work.entry)) list_add(&ssp->srcu_work.entry, &srcu_boot_list); } - preempt_enable(); } /* From fb7855a6b58b045f60a7456096da29842e9ca079 Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Wed, 10 Sep 2025 20:44:19 +0530 Subject: [PATCH 1446/2711] refperf: Remove redundant kfree() after torture_stop_kthread() Remove unnecessary kfree(main_task) call in ref_scale_cleanup() as torture_stop_kthread() already handles the memory cleanup for the task structure internally. The additional kfree(main_task) call after torture_stop_kthread() is redundant and confusing since torture_stop_kthread() sets the pointer to NULL, making this a no-op. This pattern is consistent with other torture test modules where torture_stop_kthread() is called without explicit kfree() of the task pointer, as the torture framework manages the task lifecycle internally. Signed-off-by: Kaushlendra Kumar Signed-off-by: Paul E. McKenney --- kernel/rcu/refscale.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/rcu/refscale.c b/kernel/rcu/refscale.c index 5840fac06feb..7f3d23762ef7 100644 --- a/kernel/rcu/refscale.c +++ b/kernel/rcu/refscale.c @@ -1135,7 +1135,6 @@ ref_scale_cleanup(void) kfree(reader_tasks); torture_stop_kthread("main_task", main_task); - kfree(main_task); // Do scale-type-specific cleanup operations. if (cur_ops->cleanup != NULL) From 1441edd129e36cf5d1a9c2abff39619d5d90e1a8 Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Thu, 11 Sep 2025 08:48:11 +0530 Subject: [PATCH 1447/2711] refperf: Set reader_tasks to NULL after kfree() Set reader_tasks to NULL after kfree() in ref_scale_cleanup() to improve debugging experience with kernel debugging tools. This follows the common pattern of NULLing pointers after freeing to avoid dangling pointer issues during debugging sessions. Setting pointers to NULL after freeing helps debugging tools like kdgb,drgn, and other kernel debuggers by providing clear indication that the memory has been freed and the pointer is no longer valid. Suggested-by: Paul E. McKenney Signed-off-by: Kaushlendra Kumar Signed-off-by: Paul E. McKenney --- kernel/rcu/refscale.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/rcu/refscale.c b/kernel/rcu/refscale.c index 7f3d23762ef7..19841704d8f5 100644 --- a/kernel/rcu/refscale.c +++ b/kernel/rcu/refscale.c @@ -1133,6 +1133,7 @@ ref_scale_cleanup(void) reader_tasks[i].task); } kfree(reader_tasks); + reader_tasks = NULL; torture_stop_kthread("main_task", main_task); From 5e0ae59159e3a07391a35865bb79ff335473fa79 Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:42 +0000 Subject: [PATCH 1448/2711] HID: add haptics page defines Introduce haptic usages as defined in HID Usage Tables specification. Add HID units for newton and gram. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Signed-off-by: Benjamin Tissoires --- include/linux/hid.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/linux/hid.h b/include/linux/hid.h index 2cc4f1e4ea96..10f113c758fe 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -156,6 +156,7 @@ struct hid_item { #define HID_UP_TELEPHONY 0x000b0000 #define HID_UP_CONSUMER 0x000c0000 #define HID_UP_DIGITIZER 0x000d0000 +#define HID_UP_HAPTIC 0x000e0000 #define HID_UP_PID 0x000f0000 #define HID_UP_BATTERY 0x00850000 #define HID_UP_CAMERA 0x00900000 @@ -316,6 +317,28 @@ struct hid_item { #define HID_DG_TOOLSERIALNUMBER 0x000d005b #define HID_DG_LATENCYMODE 0x000d0060 +#define HID_HP_SIMPLECONTROLLER 0x000e0001 +#define HID_HP_WAVEFORMLIST 0x000e0010 +#define HID_HP_DURATIONLIST 0x000e0011 +#define HID_HP_AUTOTRIGGER 0x000e0020 +#define HID_HP_MANUALTRIGGER 0x000e0021 +#define HID_HP_AUTOTRIGGERASSOCIATEDCONTROL 0x000e0022 +#define HID_HP_INTENSITY 0x000e0023 +#define HID_HP_REPEATCOUNT 0x000e0024 +#define HID_HP_RETRIGGERPERIOD 0x000e0025 +#define HID_HP_WAVEFORMVENDORPAGE 0x000e0026 +#define HID_HP_WAVEFORMVENDORID 0x000e0027 +#define HID_HP_WAVEFORMCUTOFFTIME 0x000e0028 +#define HID_HP_WAVEFORMNONE 0x000e1001 +#define HID_HP_WAVEFORMSTOP 0x000e1002 +#define HID_HP_WAVEFORMCLICK 0x000e1003 +#define HID_HP_WAVEFORMBUZZCONTINUOUS 0x000e1004 +#define HID_HP_WAVEFORMRUMBLECONTINUOUS 0x000e1005 +#define HID_HP_WAVEFORMPRESS 0x000e1006 +#define HID_HP_WAVEFORMRELEASE 0x000e1007 +#define HID_HP_VENDORWAVEFORMMIN 0x000e2001 +#define HID_HP_VENDORWAVEFORMMAX 0x000e2fff + #define HID_BAT_ABSOLUTESTATEOFCHARGE 0x00850065 #define HID_BAT_CHARGING 0x00850044 @@ -423,6 +446,12 @@ struct hid_item { #define HID_REPORT_PROTOCOL 1 #define HID_BOOT_PROTOCOL 0 +/* + * HID units + */ +#define HID_UNIT_GRAM 0x0101 +#define HID_UNIT_NEWTON 0xe111 + /* * This is the global environment of the parser. This information is * persistent for main-items. The global environment can be saved and From 08a72a220e960e7f153a810fb633638afd0b7563 Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:43 +0000 Subject: [PATCH 1449/2711] Input: add FF_HAPTIC effect type FF_HAPTIC effect type can be used to trigger haptic feedback with HID simple haptic usages. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Acked-by: Dmitry Torokhov Signed-off-by: Benjamin Tissoires --- include/uapi/linux/input.h | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index 127119c287cf..6aa703fcfcfb 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -429,6 +429,24 @@ struct ff_rumble_effect { __u16 weak_magnitude; }; +/** + * struct ff_haptic_effect + * @hid_usage: hid_usage according to Haptics page (WAVEFORM_CLICK, etc.) + * @vendor_id: the waveform vendor ID if hid_usage is in the vendor-defined range + * @vendor_waveform_page: the vendor waveform page if hid_usage is in the vendor-defined range + * @intensity: strength of the effect as percentage + * @repeat_count: number of times to retrigger effect + * @retrigger_period: time before effect is retriggered (in ms) + */ +struct ff_haptic_effect { + __u16 hid_usage; + __u16 vendor_id; + __u8 vendor_waveform_page; + __u16 intensity; + __u16 repeat_count; + __u16 retrigger_period; +}; + /** * struct ff_effect - defines force feedback effect * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING, @@ -465,6 +483,7 @@ struct ff_effect { struct ff_periodic_effect periodic; struct ff_condition_effect condition[2]; /* One for each axis */ struct ff_rumble_effect rumble; + struct ff_haptic_effect haptic; } u; }; @@ -472,6 +491,7 @@ struct ff_effect { * Force feedback effect types */ +#define FF_HAPTIC 0x4f #define FF_RUMBLE 0x50 #define FF_PERIODIC 0x51 #define FF_CONSTANT 0x52 @@ -481,7 +501,7 @@ struct ff_effect { #define FF_INERTIA 0x56 #define FF_RAMP 0x57 -#define FF_EFFECT_MIN FF_RUMBLE +#define FF_EFFECT_MIN FF_HAPTIC #define FF_EFFECT_MAX FF_RAMP /* From 7075ae4ac9db93a3e762f3c2793ad57dbbf8a120 Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:44 +0000 Subject: [PATCH 1450/2711] Input: add INPUT_PROP_HAPTIC_TOUCHPAD INPUT_PROP_HAPTIC_TOUCHPAD property is to be set for a device with simple haptic capabilities. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Acked-by: Dmitry Torokhov Reviewed-by: Randy Dunlap Signed-off-by: Benjamin Tissoires --- Documentation/input/event-codes.rst | 14 ++++++++++++++ include/uapi/linux/input-event-codes.h | 1 + 2 files changed, 15 insertions(+) diff --git a/Documentation/input/event-codes.rst b/Documentation/input/event-codes.rst index b4557462edd7..1ead9bb8d9c6 100644 --- a/Documentation/input/event-codes.rst +++ b/Documentation/input/event-codes.rst @@ -400,6 +400,20 @@ can report through the rotational axes (absolute and/or relative rx, ry, rz). All other axes retain their meaning. A device must not mix regular directional axes and accelerometer axes on the same event node. +INPUT_PROP_HAPTIC_TOUCHPAD +-------------------------- + +The INPUT_PROP_HAPTIC_TOUCHPAD property indicates that device: +- supports simple haptic auto and manual triggering +- can differentiate between at least 5 fingers +- uses correct resolution for the X/Y (units and value) +- reports correct force per touch, and correct units for them (newtons or grams) +- follows the MT protocol type B + +Summing up, such devices follow the MS spec for input devices in +Win8 and Win8.1, and in addition support the Simple haptic controller HID table, +and report correct units for the pressure. + Guidelines ========== diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index ca5851e97fac..4a9fbf42aa9f 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -27,6 +27,7 @@ #define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */ #define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */ #define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */ +#define INPUT_PROP_HAPTIC_TOUCHPAD 0x07 /* is a haptic touchpad */ #define INPUT_PROP_MAX 0x1f #define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) From b44779d44f7152c1b62091ab31514a62b4629d4c Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:45 +0000 Subject: [PATCH 1451/2711] HID: haptic: introduce hid_haptic_device Define a new structure that contains simple haptic device configuration as well as current state. Add functions that recognize auto trigger and manual trigger reports as well as save their addresses. Verify that the pressure unit is either grams or newtons. Mark the input device as a haptic touchpad if the unit is correct and the reports are found. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Signed-off-by: Benjamin Tissoires --- drivers/hid/Kconfig | 11 +++++ drivers/hid/Makefile | 1 + drivers/hid/hid-haptic.c | 72 ++++++++++++++++++++++++++++ drivers/hid/hid-haptic.h | 101 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 drivers/hid/hid-haptic.c create mode 100644 drivers/hid/hid-haptic.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 79997553d8f9..8b7a2b9e800c 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -92,6 +92,17 @@ config HID_GENERIC If unsure, say Y. +config HID_HAPTIC + tristate "Haptic touchpad support" + default n + help + Support for touchpads with force sensors and haptic actuators instead of a + traditional button. + Adds extra parsing and FF device for the hid multitouch driver. + It can be used for Elan 2703 haptic touchpad. + + If unsure, say N. + menu "Special HID drivers" config HID_A4TECH diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 10ae5dedbd84..361a7daedeb8 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -4,6 +4,7 @@ # hid-y := hid-core.o hid-input.o hid-quirks.o hid-$(CONFIG_DEBUG_FS) += hid-debug.o +hid-$(CONFIG_HID_HAPTIC) += hid-haptic.o obj-$(CONFIG_HID_BPF) += bpf/ diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c new file mode 100644 index 000000000000..d659a430c1a6 --- /dev/null +++ b/drivers/hid/hid-haptic.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HID Haptic support for Linux + * + * Copyright (c) 2021 Angela Czubak + */ + +#include "hid-haptic.h" + +void hid_haptic_feature_mapping(struct hid_device *hdev, + struct hid_haptic_device *haptic, + struct hid_field *field, struct hid_usage *usage) +{ + if (usage->hid == HID_HP_AUTOTRIGGER) { + if (usage->usage_index >= field->report_count) { + dev_err(&hdev->dev, + "HID_HP_AUTOTRIGGER out of range\n"); + return; + } + + hid_device_io_start(hdev); + hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT); + hid_hw_wait(hdev); + hid_device_io_stop(hdev); + haptic->default_auto_trigger = + field->value[usage->usage_index]; + haptic->auto_trigger_report = field->report; + } +} +EXPORT_SYMBOL_GPL(hid_haptic_feature_mapping); + +bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic, + struct hid_input *hi, struct hid_field *field) +{ + if (field->unit == HID_UNIT_GRAM || field->unit == HID_UNIT_NEWTON) + return true; + return false; +} +EXPORT_SYMBOL_GPL(hid_haptic_check_pressure_unit); + +int hid_haptic_input_mapping(struct hid_device *hdev, + struct hid_haptic_device *haptic, + struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->hid == HID_HP_MANUALTRIGGER) { + haptic->manual_trigger_report = field->report; + /* we don't really want to map these fields */ + return -1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(hid_haptic_input_mapping); + +int hid_haptic_input_configured(struct hid_device *hdev, + struct hid_haptic_device *haptic, + struct hid_input *hi) +{ + + if (hi->application == HID_DG_TOUCHPAD) { + if (haptic->auto_trigger_report && + haptic->manual_trigger_report) { + __set_bit(INPUT_PROP_HAPTIC_TOUCHPAD, hi->input->propbit); + return 1; + } + return 0; + } + return -1; +} +EXPORT_SYMBOL_GPL(hid_haptic_input_configured); diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h new file mode 100644 index 000000000000..2e89addf5ec2 --- /dev/null +++ b/drivers/hid/hid-haptic.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * HID Haptic support for Linux + * + * Copyright (c) 2021 Angela Czubak + */ + +#include + +#define HID_HAPTIC_ORDINAL_WAVEFORMNONE 1 +#define HID_HAPTIC_ORDINAL_WAVEFORMSTOP 2 + +#define HID_HAPTIC_MODE_DEVICE 0 +#define HID_HAPTIC_MODE_HOST 1 + +struct hid_haptic_effect { + u8 *report_buf; + struct input_dev *input_dev; + struct work_struct work; + struct list_head control; + struct mutex control_mutex; +}; + +struct hid_haptic_effect_node { + struct list_head node; + struct file *file; +}; + +struct hid_haptic_device { + struct input_dev *input_dev; + struct hid_device *hdev; + struct hid_report *auto_trigger_report; + struct mutex auto_trigger_mutex; + struct workqueue_struct *wq; + struct hid_report *manual_trigger_report; + struct mutex manual_trigger_mutex; + size_t manual_trigger_report_len; + int pressed_state; + s32 pressure_sum; + s32 force_logical_minimum; + s32 force_physical_minimum; + s32 force_resolution; + u32 mode; + u32 default_auto_trigger; + u32 vendor_page; + u32 vendor_id; + u32 max_waveform_id; + u32 max_duration_id; + u16 *hid_usage_map; + u32 *duration_map; + u16 press_ordinal; + u16 release_ordinal; + struct hid_haptic_effect *effect; + struct hid_haptic_effect stop_effect; +}; + +#if IS_ENABLED(CONFIG_HID_HAPTIC) +void hid_haptic_feature_mapping(struct hid_device *hdev, + struct hid_haptic_device *haptic, + struct hid_field *field, struct hid_usage + *usage); +bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic, + struct hid_input *hi, struct hid_field *field); +int hid_haptic_input_mapping(struct hid_device *hdev, + struct hid_haptic_device *haptic, + struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max); +int hid_haptic_input_configured(struct hid_device *hdev, + struct hid_haptic_device *haptic, + struct hid_input *hi); +#else +static inline +void hid_haptic_feature_mapping(struct hid_device *hdev, + struct hid_haptic_device *haptic, + struct hid_field *field, struct hid_usage + *usage) +{} +static inline +bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic, + struct hid_input *hi, struct hid_field *field) +{ + return false; +} +static inline +int hid_haptic_input_mapping(struct hid_device *hdev, + struct hid_haptic_device *haptic, + struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + return 0; +} +static inline +int hid_haptic_input_configured(struct hid_device *hdev, + struct hid_haptic_device *haptic, + struct hid_input *hi) +{ + return 0; +} +#endif From 7a56e7b211e5b6e78cd87786ea4c5a62231d1da2 Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:46 +0000 Subject: [PATCH 1452/2711] HID: input: allow mapping of haptic output This change makes it possible to parse output reports by input mapping functions by HID drivers. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Reviewed-by: Dmitry Torokhov Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-input.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index f45f856a127f..f6a920fe3102 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -683,9 +683,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel if (field->report_count < 1) goto ignore; - /* only LED usages are supported in output fields */ + /* only LED and HAPTIC usages are supported in output fields */ if (field->report_type == HID_OUTPUT_REPORT && - (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { + (usage->hid & HID_USAGE_PAGE) != HID_UP_LED && + (usage->hid & HID_USAGE_PAGE) != HID_UP_HAPTIC) { goto ignore; } From 344ff358495706abc7aac1e0c59a5bb16b350307 Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:47 +0000 Subject: [PATCH 1453/2711] HID: haptic: initialize haptic device Add hid_haptic_init(). Parse autotrigger report to retrieve ordinals for press and release waveforms. Implement force feedback functions. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-haptic.c | 438 +++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-haptic.h | 5 + 2 files changed, 443 insertions(+) diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c index d659a430c1a6..ef09b4039f33 100644 --- a/drivers/hid/hid-haptic.c +++ b/drivers/hid/hid-haptic.c @@ -5,12 +5,16 @@ * Copyright (c) 2021 Angela Czubak */ +#include + #include "hid-haptic.h" void hid_haptic_feature_mapping(struct hid_device *hdev, struct hid_haptic_device *haptic, struct hid_field *field, struct hid_usage *usage) { + u16 usage_hid; + if (usage->hid == HID_HP_AUTOTRIGGER) { if (usage->usage_index >= field->report_count) { dev_err(&hdev->dev, @@ -25,6 +29,20 @@ void hid_haptic_feature_mapping(struct hid_device *hdev, haptic->default_auto_trigger = field->value[usage->usage_index]; haptic->auto_trigger_report = field->report; + } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ORDINAL) { + usage_hid = usage->hid & HID_USAGE; + switch (field->logical) { + case HID_HP_WAVEFORMLIST: + if (usage_hid > haptic->max_waveform_id) + haptic->max_waveform_id = usage_hid; + break; + case HID_HP_DURATIONLIST: + if (usage_hid > haptic->max_duration_id) + haptic->max_duration_id = usage_hid; + break; + default: + break; + } } } EXPORT_SYMBOL_GPL(hid_haptic_feature_mapping); @@ -70,3 +88,423 @@ int hid_haptic_input_configured(struct hid_device *hdev, return -1; } EXPORT_SYMBOL_GPL(hid_haptic_input_configured); + +static void parse_auto_trigger_field(struct hid_haptic_device *haptic, + struct hid_field *field) +{ + int count = field->report_count; + int n; + u16 usage_hid; + + for (n = 0; n < count; n++) { + switch (field->usage[n].hid & HID_USAGE_PAGE) { + case HID_UP_ORDINAL: + usage_hid = field->usage[n].hid & HID_USAGE; + switch (field->logical) { + case HID_HP_WAVEFORMLIST: + haptic->hid_usage_map[usage_hid] = field->value[n]; + if (field->value[n] == + (HID_HP_WAVEFORMPRESS & HID_USAGE)) { + haptic->press_ordinal = usage_hid; + } else if (field->value[n] == + (HID_HP_WAVEFORMRELEASE & HID_USAGE)) { + haptic->release_ordinal = usage_hid; + } + break; + case HID_HP_DURATIONLIST: + haptic->duration_map[usage_hid] = + field->value[n]; + break; + default: + break; + } + break; + case HID_UP_HAPTIC: + switch (field->usage[n].hid) { + case HID_HP_WAVEFORMVENDORID: + haptic->vendor_id = field->value[n]; + break; + case HID_HP_WAVEFORMVENDORPAGE: + haptic->vendor_page = field->value[n]; + break; + default: + break; + } + break; + default: + /* Should not really happen */ + break; + } + } +} + +static void fill_effect_buf(struct hid_haptic_device *haptic, + struct ff_haptic_effect *effect, + struct hid_haptic_effect *haptic_effect, + int waveform_ordinal) +{ + struct hid_report *rep = haptic->manual_trigger_report; + struct hid_usage *usage; + struct hid_field *field; + s32 value; + int i, j; + u8 *buf = haptic_effect->report_buf; + + mutex_lock(&haptic->manual_trigger_mutex); + for (i = 0; i < rep->maxfield; i++) { + field = rep->field[i]; + /* Ignore if report count is out of bounds. */ + if (field->report_count < 1) + continue; + + for (j = 0; j < field->maxusage; j++) { + usage = &field->usage[j]; + + switch (usage->hid) { + case HID_HP_INTENSITY: + if (effect->intensity > 100) { + value = field->logical_maximum; + } else { + value = field->logical_minimum + + effect->intensity * + (field->logical_maximum - + field->logical_minimum) / 100; + } + break; + case HID_HP_REPEATCOUNT: + value = effect->repeat_count; + break; + case HID_HP_RETRIGGERPERIOD: + value = effect->retrigger_period; + break; + case HID_HP_MANUALTRIGGER: + value = waveform_ordinal; + break; + default: + break; + } + + field->value[j] = value; + } + } + + hid_output_report(rep, buf); + mutex_unlock(&haptic->manual_trigger_mutex); +} + +static int hid_haptic_upload_effect(struct input_dev *dev, struct ff_effect *effect, + struct ff_effect *old) +{ + struct ff_device *ff = dev->ff; + struct hid_haptic_device *haptic = ff->private; + int i, ordinal = 0; + + /* If vendor range, check vendor id and page */ + if (effect->u.haptic.hid_usage >= (HID_HP_VENDORWAVEFORMMIN & HID_USAGE) && + effect->u.haptic.hid_usage <= (HID_HP_VENDORWAVEFORMMAX & HID_USAGE) && + (effect->u.haptic.vendor_id != haptic->vendor_id || + effect->u.haptic.vendor_waveform_page != haptic->vendor_page)) + return -EINVAL; + + /* Check hid_usage */ + for (i = 1; i <= haptic->max_waveform_id; i++) { + if (haptic->hid_usage_map[i] == effect->u.haptic.hid_usage) { + ordinal = i; + break; + } + } + if (ordinal < 1) + return -EINVAL; + + /* Fill the buffer for the effect id */ + fill_effect_buf(haptic, &effect->u.haptic, &haptic->effect[effect->id], + ordinal); + + return 0; +} + +static int play_effect(struct hid_device *hdev, struct hid_haptic_device *haptic, + struct hid_haptic_effect *effect) +{ + int ret; + + ret = hid_hw_output_report(hdev, effect->report_buf, + haptic->manual_trigger_report_len); + if (ret < 0) { + ret = hid_hw_raw_request(hdev, + haptic->manual_trigger_report->id, + effect->report_buf, + haptic->manual_trigger_report_len, + HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); + } + + return ret; +} + +static void haptic_work_handler(struct work_struct *work) +{ + + struct hid_haptic_effect *effect = container_of(work, + struct hid_haptic_effect, + work); + struct input_dev *dev = effect->input_dev; + struct hid_device *hdev = input_get_drvdata(dev); + struct hid_haptic_device *haptic = dev->ff->private; + + mutex_lock(&haptic->manual_trigger_mutex); + if (effect != &haptic->stop_effect) + play_effect(hdev, haptic, &haptic->stop_effect); + + play_effect(hdev, haptic, effect); + mutex_unlock(&haptic->manual_trigger_mutex); + +} + +static int hid_haptic_playback(struct input_dev *dev, int effect_id, int value) +{ + struct hid_haptic_device *haptic = dev->ff->private; + + if (value) + queue_work(haptic->wq, &haptic->effect[effect_id].work); + else + queue_work(haptic->wq, &haptic->stop_effect.work); + + return 0; +} + +static void effect_set_default(struct ff_effect *effect) +{ + effect->type = FF_HAPTIC; + effect->id = -1; + effect->u.haptic.hid_usage = HID_HP_WAVEFORMNONE & HID_USAGE; + effect->u.haptic.intensity = 100; + effect->u.haptic.retrigger_period = 0; + effect->u.haptic.repeat_count = 0; +} + +static int hid_haptic_erase(struct input_dev *dev, int effect_id) +{ + struct hid_haptic_device *haptic = dev->ff->private; + struct ff_effect effect; + int ordinal; + + effect_set_default(&effect); + + if (effect.u.haptic.hid_usage == (HID_HP_WAVEFORMRELEASE & HID_USAGE)) { + ordinal = haptic->release_ordinal; + if (!ordinal) + ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE; + else + effect.u.haptic.hid_usage = HID_HP_WAVEFORMRELEASE & + HID_USAGE; + fill_effect_buf(haptic, &effect.u.haptic, &haptic->effect[effect_id], + ordinal); + } else if (effect.u.haptic.hid_usage == (HID_HP_WAVEFORMPRESS & HID_USAGE)) { + ordinal = haptic->press_ordinal; + if (!ordinal) + ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE; + else + effect.u.haptic.hid_usage = HID_HP_WAVEFORMPRESS & + HID_USAGE; + fill_effect_buf(haptic, &effect.u.haptic, &haptic->effect[effect_id], + ordinal); + } + + return 0; +} + +static void hid_haptic_destroy(struct ff_device *ff) +{ + struct hid_haptic_device *haptic = ff->private; + struct hid_device *hdev = haptic->hdev; + int r; + + if (hdev) + put_device(&hdev->dev); + + kfree(haptic->stop_effect.report_buf); + haptic->stop_effect.report_buf = NULL; + + if (haptic->effect) { + for (r = 0; r < ff->max_effects; r++) + kfree(haptic->effect[r].report_buf); + kfree(haptic->effect); + } + haptic->effect = NULL; + + destroy_workqueue(haptic->wq); + haptic->wq = NULL; + + kfree(haptic->duration_map); + haptic->duration_map = NULL; + + kfree(haptic->hid_usage_map); + haptic->hid_usage_map = NULL; + + module_put(THIS_MODULE); +} + +int hid_haptic_init(struct hid_device *hdev, + struct hid_haptic_device **haptic_ptr) +{ + struct hid_haptic_device *haptic = *haptic_ptr; + struct input_dev *dev = NULL; + struct hid_input *hidinput; + struct ff_device *ff; + int ret = 0, r; + struct ff_haptic_effect stop_effect = { + .hid_usage = HID_HP_WAVEFORMSTOP & HID_USAGE, + }; + const char *prefix = "hid-haptic"; + char *name; + int (*flush)(struct input_dev *dev, struct file *file); + int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); + + haptic->hdev = hdev; + haptic->max_waveform_id = max(2u, haptic->max_waveform_id); + haptic->max_duration_id = max(2u, haptic->max_duration_id); + + haptic->hid_usage_map = kcalloc(haptic->max_waveform_id + 1, + sizeof(u16), GFP_KERNEL); + if (!haptic->hid_usage_map) { + ret = -ENOMEM; + goto exit; + } + haptic->duration_map = kcalloc(haptic->max_duration_id + 1, + sizeof(u32), GFP_KERNEL); + if (!haptic->duration_map) { + ret = -ENOMEM; + goto usage_map; + } + + if (haptic->max_waveform_id != haptic->max_duration_id) + dev_warn(&hdev->dev, + "Haptic duration and waveform lists have different max id (%u and %u).\n", + haptic->max_duration_id, haptic->max_waveform_id); + + haptic->hid_usage_map[HID_HAPTIC_ORDINAL_WAVEFORMNONE] = + HID_HP_WAVEFORMNONE & HID_USAGE; + haptic->hid_usage_map[HID_HAPTIC_ORDINAL_WAVEFORMSTOP] = + HID_HP_WAVEFORMSTOP & HID_USAGE; + + for (r = 0; r < haptic->auto_trigger_report->maxfield; r++) + parse_auto_trigger_field(haptic, haptic->auto_trigger_report->field[r]); + + list_for_each_entry(hidinput, &hdev->inputs, list) { + if (hidinput->application == HID_DG_TOUCHPAD) { + dev = hidinput->input; + break; + } + } + + if (!dev) { + dev_err(&hdev->dev, "Failed to find the input device\n"); + ret = -ENODEV; + goto duration_map; + } + + haptic->input_dev = dev; + haptic->manual_trigger_report_len = + hid_report_len(haptic->manual_trigger_report); + mutex_init(&haptic->manual_trigger_mutex); + name = kmalloc(strlen(prefix) + strlen(hdev->name) + 2, GFP_KERNEL); + if (name) { + sprintf(name, "%s %s", prefix, hdev->name); + haptic->wq = create_singlethread_workqueue(name); + kfree(name); + } + if (!haptic->wq) { + ret = -ENOMEM; + goto duration_map; + } + haptic->effect = kcalloc(FF_MAX_EFFECTS, + sizeof(struct hid_haptic_effect), GFP_KERNEL); + if (!haptic->effect) { + ret = -ENOMEM; + goto output_queue; + } + for (r = 0; r < FF_MAX_EFFECTS; r++) { + haptic->effect[r].report_buf = + hid_alloc_report_buf(haptic->manual_trigger_report, + GFP_KERNEL); + if (!haptic->effect[r].report_buf) { + dev_err(&hdev->dev, + "Failed to allocate a buffer for an effect.\n"); + ret = -ENOMEM; + goto buffer_free; + } + haptic->effect[r].input_dev = dev; + INIT_WORK(&haptic->effect[r].work, haptic_work_handler); + } + haptic->stop_effect.report_buf = + hid_alloc_report_buf(haptic->manual_trigger_report, + GFP_KERNEL); + if (!haptic->stop_effect.report_buf) { + dev_err(&hdev->dev, + "Failed to allocate a buffer for stop effect.\n"); + ret = -ENOMEM; + goto buffer_free; + } + haptic->stop_effect.input_dev = dev; + INIT_WORK(&haptic->stop_effect.work, haptic_work_handler); + fill_effect_buf(haptic, &stop_effect, &haptic->stop_effect, + HID_HAPTIC_ORDINAL_WAVEFORMSTOP); + + input_set_capability(dev, EV_FF, FF_HAPTIC); + + flush = dev->flush; + event = dev->event; + ret = input_ff_create(dev, FF_MAX_EFFECTS); + if (ret) { + dev_err(&hdev->dev, "Failed to create ff device.\n"); + goto stop_buffer_free; + } + + ff = dev->ff; + ff->private = haptic; + ff->upload = hid_haptic_upload_effect; + ff->playback = hid_haptic_playback; + ff->erase = hid_haptic_erase; + ff->destroy = hid_haptic_destroy; + if (!try_module_get(THIS_MODULE)) { + dev_err(&hdev->dev, "Failed to increase module count.\n"); + goto input_free; + } + if (!get_device(&hdev->dev)) { + dev_err(&hdev->dev, "Failed to get hdev device.\n"); + module_put(THIS_MODULE); + goto input_free; + } + return 0; + +input_free: + input_ff_destroy(dev); + /* Do not let double free happen, input_ff_destroy will call + * hid_haptic_destroy. + */ + *haptic_ptr = NULL; + /* Restore dev flush and event */ + dev->flush = flush; + dev->event = event; + return ret; +stop_buffer_free: + kfree(haptic->stop_effect.report_buf); + haptic->stop_effect.report_buf = NULL; +buffer_free: + while (--r >= 0) + kfree(haptic->effect[r].report_buf); + kfree(haptic->effect); + haptic->effect = NULL; +output_queue: + destroy_workqueue(haptic->wq); + haptic->wq = NULL; +duration_map: + kfree(haptic->duration_map); + haptic->duration_map = NULL; +usage_map: + kfree(haptic->hid_usage_map); + haptic->hid_usage_map = NULL; +exit: + return ret; +} +EXPORT_SYMBOL_GPL(hid_haptic_init); diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h index 2e89addf5ec2..25e0e2cef939 100644 --- a/drivers/hid/hid-haptic.h +++ b/drivers/hid/hid-haptic.h @@ -69,6 +69,7 @@ int hid_haptic_input_mapping(struct hid_device *hdev, int hid_haptic_input_configured(struct hid_device *hdev, struct hid_haptic_device *haptic, struct hid_input *hi); +int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr); #else static inline void hid_haptic_feature_mapping(struct hid_device *hdev, @@ -98,4 +99,8 @@ int hid_haptic_input_configured(struct hid_device *hdev, { return 0; } +int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr) +{ + return 0; +} #endif From 7657bf0b7cfb63ded95a6fe4e1cf106cf386b6cc Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:48 +0000 Subject: [PATCH 1454/2711] HID: input: calculate resolution for pressure Assume that if the pressure is given in newtons it should be normalized to grams. If the pressure has no unit do not calculate resolution. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-input.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index f6a920fe3102..5d7532d79d21 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -303,6 +303,19 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) } break; + case ABS_PRESSURE: + case ABS_MT_PRESSURE: + if (field->unit == HID_UNIT_NEWTON) { + /* Convert to grams, 1 newton is 101.97 grams */ + prev = physical_extents; + physical_extents *= 10197; + if (physical_extents < prev) + return 0; + unit_exponent -= 2; + } else if (field->unit != HID_UNIT_GRAM) { + return 0; + } + break; default: return 0; } From a77efca3aa85e382b52b587ca9976c0f8e11d49c Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:49 +0000 Subject: [PATCH 1455/2711] HID: haptic: add functions handling events Implement hid_haptic_handle_press_release() which generates haptic feedback as well as saves the pressed state of the haptic device. Add functions to increase and reset the state of the pressure detected by the device. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-haptic.c | 20 +++++++++++++++++++- drivers/hid/hid-haptic.h | 15 +++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c index ef09b4039f33..c02af820051c 100644 --- a/drivers/hid/hid-haptic.c +++ b/drivers/hid/hid-haptic.c @@ -50,8 +50,13 @@ EXPORT_SYMBOL_GPL(hid_haptic_feature_mapping); bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic, struct hid_input *hi, struct hid_field *field) { - if (field->unit == HID_UNIT_GRAM || field->unit == HID_UNIT_NEWTON) + if (field->unit == HID_UNIT_GRAM || field->unit == HID_UNIT_NEWTON) { + haptic->force_logical_minimum = field->logical_minimum; + haptic->force_physical_minimum = field->physical_minimum; + haptic->force_resolution = input_abs_get_res(hi->input, + ABS_MT_PRESSURE); return true; + } return false; } EXPORT_SYMBOL_GPL(hid_haptic_check_pressure_unit); @@ -508,3 +513,16 @@ exit: return ret; } EXPORT_SYMBOL_GPL(hid_haptic_init); + +void hid_haptic_pressure_reset(struct hid_haptic_device *haptic) +{ + haptic->pressure_sum = 0; +} +EXPORT_SYMBOL_GPL(hid_haptic_pressure_reset); + +void hid_haptic_pressure_increase(struct hid_haptic_device *haptic, + __s32 pressure) +{ + haptic->pressure_sum += pressure; +} +EXPORT_SYMBOL_GPL(hid_haptic_pressure_increase); diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h index 25e0e2cef939..abdd7d710c0b 100644 --- a/drivers/hid/hid-haptic.h +++ b/drivers/hid/hid-haptic.h @@ -70,6 +70,10 @@ int hid_haptic_input_configured(struct hid_device *hdev, struct hid_haptic_device *haptic, struct hid_input *hi); int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr); +void hid_haptic_handle_press_release(struct hid_haptic_device *haptic); +void hid_haptic_pressure_reset(struct hid_haptic_device *haptic); +void hid_haptic_pressure_increase(struct hid_haptic_device *haptic, + __s32 pressure); #else static inline void hid_haptic_feature_mapping(struct hid_device *hdev, @@ -103,4 +107,15 @@ int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_p { return 0; } +static inline +void hid_haptic_handle_press_release(struct hid_haptic_device *haptic) +{} +static inline +void hid_haptic_pressure_reset(struct hid_haptic_device *haptic) +{} +static inline +void hid_haptic_pressure_increase(struct hid_haptic_device *haptic, + __s32 pressure) +{} #endif + From 4e584ac737884ef0fd80f6836b917972fad86b17 Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:50 +0000 Subject: [PATCH 1456/2711] Input: MT - add INPUT_MT_TOTAL_FORCE flags Add a flag to generate ABS_PRESSURE as sum of ABS_MT_PRESSURE across all slots. This flag should be set if one knows a device reports true force and would like to report total force to the userspace. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Acked-by: Dmitry Torokhov Signed-off-by: Benjamin Tissoires --- drivers/input/input-mt.c | 14 ++++++++++---- include/linux/input/mt.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index 337006dd9dcf..09f518897d4a 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -198,6 +198,7 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) struct input_mt *mt = dev->mt; struct input_mt_slot *oldest; int oldid, count, i; + int p, reported_p = 0; if (!mt) return; @@ -216,6 +217,13 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) oldest = ps; oldid = id; } + if (test_bit(ABS_MT_PRESSURE, dev->absbit)) { + p = input_mt_get_value(ps, ABS_MT_PRESSURE); + if (mt->flags & INPUT_MT_TOTAL_FORCE) + reported_p += p; + else if (oldid == id) + reported_p = p; + } count++; } @@ -245,10 +253,8 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) input_event(dev, EV_ABS, ABS_X, x); input_event(dev, EV_ABS, ABS_Y, y); - if (test_bit(ABS_MT_PRESSURE, dev->absbit)) { - int p = input_mt_get_value(oldest, ABS_MT_PRESSURE); - input_event(dev, EV_ABS, ABS_PRESSURE, p); - } + if (test_bit(ABS_MT_PRESSURE, dev->absbit)) + input_event(dev, EV_ABS, ABS_PRESSURE, reported_p); } else { if (test_bit(ABS_MT_PRESSURE, dev->absbit)) input_event(dev, EV_ABS, ABS_PRESSURE, 0); diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h index 2cf89a538b18..d30286298a00 100644 --- a/include/linux/input/mt.h +++ b/include/linux/input/mt.h @@ -17,6 +17,7 @@ #define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame */ #define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */ #define INPUT_MT_SEMI_MT 0x0010 /* semi-mt device, finger count handled manually */ +#define INPUT_MT_TOTAL_FORCE 0x0020 /* calculate total force from slots pressure */ /** * struct input_mt_slot - represents the state of an input MT slot From ff66b8eebbab37146ef1399d93332f82b752990b Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:51 +0000 Subject: [PATCH 1457/2711] HID: haptic: add hid_haptic_switch_mode Function hid_haptic_switch_mode() can be used to switch between device-controlled mode and host-controlled mode. Uploading a WAVEFORMPRESS or WAVEFORMRELEASE effect triggers host-controlled mode if the device is in device-controlled mode. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-haptic.c | 66 +++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c index c02af820051c..aa090684c1f2 100644 --- a/drivers/hid/hid-haptic.c +++ b/drivers/hid/hid-haptic.c @@ -5,6 +5,7 @@ * Copyright (c) 2021 Angela Czubak */ +#include #include #include "hid-haptic.h" @@ -197,12 +198,46 @@ static void fill_effect_buf(struct hid_haptic_device *haptic, mutex_unlock(&haptic->manual_trigger_mutex); } +static void switch_mode(struct hid_device *hdev, struct hid_haptic_device *haptic, + int mode) +{ + struct hid_report *rep = haptic->auto_trigger_report; + struct hid_field *field; + s32 value; + int i, j; + + if (mode == HID_HAPTIC_MODE_HOST) + value = HID_HAPTIC_ORDINAL_WAVEFORMSTOP; + else + value = haptic->default_auto_trigger; + + mutex_lock(&haptic->auto_trigger_mutex); + for (i = 0; i < rep->maxfield; i++) { + field = rep->field[i]; + /* Ignore if report count is out of bounds. */ + if (field->report_count < 1) + continue; + + for (j = 0; j < field->maxusage; j++) { + if (field->usage[j].hid == HID_HP_AUTOTRIGGER) + field->value[j] = value; + } + } + + /* send the report */ + hid_hw_request(hdev, rep, HID_REQ_SET_REPORT); + mutex_unlock(&haptic->auto_trigger_mutex); + haptic->mode = mode; +} + static int hid_haptic_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) { + struct hid_device *hdev = input_get_drvdata(dev); struct ff_device *ff = dev->ff; struct hid_haptic_device *haptic = ff->private; int i, ordinal = 0; + bool switch_modes = false; /* If vendor range, check vendor id and page */ if (effect->u.haptic.hid_usage >= (HID_HP_VENDORWAVEFORMMIN & HID_USAGE) && @@ -225,6 +260,16 @@ static int hid_haptic_upload_effect(struct input_dev *dev, struct ff_effect *eff fill_effect_buf(haptic, &effect->u.haptic, &haptic->effect[effect->id], ordinal); + if (effect->u.haptic.hid_usage == (HID_HP_WAVEFORMPRESS & HID_USAGE) || + effect->u.haptic.hid_usage == (HID_HP_WAVEFORMRELEASE & HID_USAGE)) + switch_modes = true; + + /* If device is in autonomous mode, and the uploaded effect signals userspace + * wants control of the device, change modes + */ + if (switch_modes && haptic->mode == HID_HAPTIC_MODE_DEVICE) + switch_mode(hdev, haptic, HID_HAPTIC_MODE_HOST); + return 0; } @@ -290,6 +335,7 @@ static void effect_set_default(struct ff_effect *effect) static int hid_haptic_erase(struct input_dev *dev, int effect_id) { struct hid_haptic_device *haptic = dev->ff->private; + struct hid_device *hdev = input_get_drvdata(dev); struct ff_effect effect; int ordinal; @@ -297,20 +343,25 @@ static int hid_haptic_erase(struct input_dev *dev, int effect_id) if (effect.u.haptic.hid_usage == (HID_HP_WAVEFORMRELEASE & HID_USAGE)) { ordinal = haptic->release_ordinal; - if (!ordinal) + if (!ordinal) { ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE; - else - effect.u.haptic.hid_usage = HID_HP_WAVEFORMRELEASE & - HID_USAGE; + if (haptic->mode == HID_HAPTIC_MODE_HOST) + switch_mode(hdev, haptic, HID_HAPTIC_MODE_DEVICE); + } else + effect.u.haptic.hid_usage = HID_HP_WAVEFORMRELEASE & HID_USAGE; + fill_effect_buf(haptic, &effect.u.haptic, &haptic->effect[effect_id], ordinal); } else if (effect.u.haptic.hid_usage == (HID_HP_WAVEFORMPRESS & HID_USAGE)) { ordinal = haptic->press_ordinal; - if (!ordinal) + if (!ordinal) { ordinal = HID_HAPTIC_ORDINAL_WAVEFORMNONE; + if (haptic->mode == HID_HAPTIC_MODE_HOST) + switch_mode(hdev, haptic, HID_HAPTIC_MODE_DEVICE); + } else - effect.u.haptic.hid_usage = HID_HP_WAVEFORMPRESS & - HID_USAGE; + effect.u.haptic.hid_usage = HID_HP_WAVEFORMPRESS & HID_USAGE; + fill_effect_buf(haptic, &effect.u.haptic, &haptic->effect[effect_id], ordinal); } @@ -392,6 +443,7 @@ int hid_haptic_init(struct hid_device *hdev, haptic->hid_usage_map[HID_HAPTIC_ORDINAL_WAVEFORMSTOP] = HID_HP_WAVEFORMSTOP & HID_USAGE; + mutex_init(&haptic->auto_trigger_mutex); for (r = 0; r < haptic->auto_trigger_report->maxfield; r++) parse_auto_trigger_field(haptic, haptic->auto_trigger_report->field[r]); From 8d0bf7908b5a6532a18ee658337d498158672862 Mon Sep 17 00:00:00 2001 From: Angela Czubak Date: Mon, 18 Aug 2025 23:08:52 +0000 Subject: [PATCH 1458/2711] HID: multitouch: add haptic multitouch support If CONFIG_HID_HAPTIC is enabled, and the device is recognized to have simple haptic capabilities, try initializing the haptic device, check input frames for pressure and handle it using hid_haptic_* API. Signed-off-by: Angela Czubak Co-developed-by: Jonathan Denose Signed-off-by: Jonathan Denose Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-haptic.h | 16 ++++++++---- drivers/hid/hid-multitouch.c | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h index abdd7d710c0b..c6539ac04c1d 100644 --- a/drivers/hid/hid-haptic.h +++ b/drivers/hid/hid-haptic.h @@ -103,19 +103,25 @@ int hid_haptic_input_configured(struct hid_device *hdev, { return 0; } +static inline +void hid_haptic_reset(struct hid_device *hdev, struct hid_haptic_device *haptic) +{} +static inline int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr) { return 0; } static inline -void hid_haptic_handle_press_release(struct hid_haptic_device *haptic) -{} +void hid_haptic_handle_press_release(struct hid_haptic_device *haptic) {} static inline -void hid_haptic_pressure_reset(struct hid_haptic_device *haptic) -{} +bool hid_haptic_handle_input(struct hid_haptic_device *haptic) +{ + return false; +} +static inline +void hid_haptic_pressure_reset(struct hid_haptic_device *haptic) {} static inline void hid_haptic_pressure_increase(struct hid_haptic_device *haptic, __s32 pressure) {} #endif - diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 22c6314a8843..2879e65cf303 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -49,6 +49,8 @@ MODULE_LICENSE("GPL"); #include "hid-ids.h" +#include "hid-haptic.h" + /* quirks to control the device */ #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) #define MT_QUIRK_SLOT_IS_CONTACTID BIT(1) @@ -168,11 +170,13 @@ struct mt_report_data { struct mt_device { struct mt_class mtclass; /* our mt device class */ struct timer_list release_timer; /* to release sticky fingers */ + struct hid_haptic_device *haptic; /* haptic related configuration */ struct hid_device *hdev; /* hid_device we're attached to */ unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ __u8 inputmode_value; /* InputMode HID feature value */ __u8 maxcontacts; bool is_buttonpad; /* is this device a button pad? */ + bool is_haptic_touchpad; /* is this device a haptic touchpad? */ bool serial_maybe; /* need to check for serial protocol */ struct list_head applications; @@ -533,6 +537,8 @@ static void mt_feature_mapping(struct hid_device *hdev, mt_get_feature(hdev, field->report); break; } + + hid_haptic_feature_mapping(hdev, td->haptic, field, usage); } static void set_abs(struct input_dev *input, unsigned int code, @@ -888,6 +894,9 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_TIPPRESSURE: set_abs(hi->input, ABS_MT_PRESSURE, field, cls->sn_pressure); + td->is_haptic_touchpad = + hid_haptic_check_pressure_unit(td->haptic, + hi, field); MT_STORE_FIELD(p); return 1; case HID_DG_SCANTIME: @@ -1008,6 +1017,8 @@ static void mt_sync_frame(struct mt_device *td, struct mt_application *app, app->num_received = 0; app->left_button_state = 0; + if (td->is_haptic_touchpad) + hid_haptic_pressure_reset(td->haptic); if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags)) set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); @@ -1165,6 +1176,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, minor = minor >> 1; } + if (td->is_haptic_touchpad) + hid_haptic_pressure_increase(td->haptic, *slot->p); + x = hdev->quirks & HID_QUIRK_X_INVERT ? input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x : *slot->x; @@ -1366,6 +1380,9 @@ static int mt_touch_input_configured(struct hid_device *hdev, if (cls->is_indirect) app->mt_flags |= INPUT_MT_POINTER; + if (td->is_haptic_touchpad) + app->mt_flags |= INPUT_MT_TOTAL_FORCE; + if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) app->mt_flags |= INPUT_MT_DROP_UNUSED; @@ -1401,6 +1418,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct mt_device *td = hid_get_drvdata(hdev); struct mt_application *application; struct mt_report_data *rdata; + int ret; rdata = mt_find_report_data(td, field->report); if (!rdata) { @@ -1463,6 +1481,11 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, if (field->physical == HID_DG_STYLUS) hi->application = HID_DG_STYLUS; + ret = hid_haptic_input_mapping(hdev, td->haptic, hi, field, usage, bit, + max); + if (ret != 0) + return ret; + /* let hid-core decide for the others */ return 0; } @@ -1685,6 +1708,14 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) struct hid_report *report; int ret; + if (td->is_haptic_touchpad && (td->mtclass.name == MT_CLS_WIN_8 || + td->mtclass.name == MT_CLS_WIN_8_FORCE_MULTI_INPUT)) { + if (hid_haptic_input_configured(hdev, td->haptic, hi) == 0) + td->is_haptic_touchpad = false; + } else { + td->is_haptic_touchpad = false; + } + list_for_each_entry(report, &hi->reports, hidinput_list) { rdata = mt_find_report_data(td, report); if (!rdata) { @@ -1827,6 +1858,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) dev_err(&hdev->dev, "cannot allocate multitouch data\n"); return -ENOMEM; } + td->haptic = devm_kzalloc(&hdev->dev, sizeof(*(td->haptic)), GFP_KERNEL); + if (!td->haptic) + return -ENOMEM; + + td->haptic->hdev = hdev; td->hdev = hdev; td->mtclass = *mtclass; td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; @@ -1895,6 +1931,17 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); + if (td->is_haptic_touchpad) { + if (hid_haptic_init(hdev, &td->haptic)) { + dev_warn(&hdev->dev, "Cannot allocate haptic for %s\n", + hdev->name); + td->is_haptic_touchpad = false; + devm_kfree(&hdev->dev, td->haptic); + } + } else { + devm_kfree(&hdev->dev, td->haptic); + } + return 0; } From 4c8bad3ed035ab85ad9b0d247154be43a53ef84d Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 15 Sep 2025 14:05:39 +0200 Subject: [PATCH 1459/2711] xtensa: use HZ_PER_MHZ in platform_calibrate_ccount Replace the hardcoded 1000000UL with the HZ_PER_MHZ unit macro, and add a space in "10 MHz" to improve the readability of the error message. Signed-off-by: Thorsten Blum Message-Id: <20250915120540.2150841-3-thorsten.blum@linux.dev> Signed-off-by: Max Filippov --- arch/xtensa/kernel/platform.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/xtensa/kernel/platform.c b/arch/xtensa/kernel/platform.c index 926b8bf0f14c..f14713060fd4 100644 --- a/arch/xtensa/kernel/platform.c +++ b/arch/xtensa/kernel/platform.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -38,7 +39,7 @@ void __weak platform_idle(void) #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT void __weak platform_calibrate_ccount(void) { - pr_err("ERROR: Cannot calibrate cpu frequency! Assuming 10MHz.\n"); - ccount_freq = 10 * 1000000UL; + pr_err("ERROR: Cannot calibrate cpu frequency! Assuming 10 MHz.\n"); + ccount_freq = 10 * HZ_PER_MHZ; } #endif From ff24e5b26dc6853364b0c006130b653f65a15acd Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:45 +0800 Subject: [PATCH 1460/2711] remoteproc: imx_rproc: Introduce start/stop/detect_mode ops for imx_rproc_dcfg Simplify the logic in imx_rproc_start(), imx_rproc_stop() and imx_rproc_detect_mode(), introduce start, stop and detect_mode ops for the imx_rproc_dcfg structure. Allow each platform to provide its own implementation of start/stop/detect_mode operations, and prepare to eliminate the need for multiple switch-case statements. Improve code readability and maintainability by encapsulating platform-specific behavior. No functional changes. Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-1-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 15 +++++++++++++++ drivers/remoteproc/imx_rproc.h | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index a6eef0080ca9..5cdc5045e575 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -376,6 +376,11 @@ static int imx_rproc_start(struct rproc *rproc) if (ret) return ret; + if (dcfg->ops && dcfg->ops->start) { + ret = dcfg->ops->start(rproc); + goto start_ret; + } + switch (dcfg->method) { case IMX_RPROC_MMIO: if (priv->gpr) { @@ -398,6 +403,7 @@ static int imx_rproc_start(struct rproc *rproc) return -EOPNOTSUPP; } +start_ret: if (ret) dev_err(dev, "Failed to enable remote core!\n"); @@ -412,6 +418,11 @@ static int imx_rproc_stop(struct rproc *rproc) struct arm_smccc_res res; int ret; + if (dcfg->ops && dcfg->ops->stop) { + ret = dcfg->ops->stop(rproc); + goto stop_ret; + } + switch (dcfg->method) { case IMX_RPROC_MMIO: if (priv->gpr) { @@ -440,6 +451,7 @@ static int imx_rproc_stop(struct rproc *rproc) return -EOPNOTSUPP; } +stop_ret: if (ret) dev_err(dev, "Failed to stop remote core\n"); else @@ -933,6 +945,9 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) u32 val; u8 pt; + if (dcfg->ops && dcfg->ops->detect_mode) + return dcfg->ops->detect_mode(priv->rproc); + switch (dcfg->method) { case IMX_RPROC_NONE: priv->rproc->state = RPROC_DETACHED; diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h index cfd38d37e146..3a9adaaf048b 100644 --- a/drivers/remoteproc/imx_rproc.h +++ b/drivers/remoteproc/imx_rproc.h @@ -31,6 +31,12 @@ enum imx_rproc_method { /* dcfg flags */ #define IMX_RPROC_NEED_SYSTEM_OFF BIT(0) +struct imx_rproc_plat_ops { + int (*start)(struct rproc *rproc); + int (*stop)(struct rproc *rproc); + int (*detect_mode)(struct rproc *rproc); +}; + struct imx_rproc_dcfg { u32 src_reg; u32 src_mask; @@ -42,6 +48,7 @@ struct imx_rproc_dcfg { size_t att_size; enum imx_rproc_method method; u32 flags; + const struct imx_rproc_plat_ops *ops; }; #endif /* _IMX_RPROC_H */ From 11a8d3cb4c624a2b29e2fa1d8b5046f69b71b40f Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:46 +0800 Subject: [PATCH 1461/2711] remoteproc: imx_rproc: Move imx_rproc_dcfg closer to imx_rproc_of_match Move the imx_rproc_dcfg structure definitions closer to imx_rproc_of_match to prepare for adding start/stop/detect_mode ops for each i.MX variant. This relocation avoids the need to declare function prototypes such as 'static int imx_rproc_xtr_mbox_init(struct rproc *rproc, bool tx_block)' at the beginning of the file, improving code organization and readability. No functional changes. Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-2-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 158 ++++++++++++++++----------------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 5cdc5045e575..af7b69d750de 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -285,85 +285,6 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { - .src_reg = IMX7D_SRC_SCR, - .src_mask = IMX7D_M4_RST_MASK, - .src_start = IMX7D_M4_START, - .src_stop = IMX8M_M7_STOP, - .gpr_reg = IMX8M_GPR22, - .gpr_wait = IMX8M_GPR22_CM7_CPUWAIT, - .att = imx_rproc_att_imx8mn, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), - .method = IMX_RPROC_MMIO, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { - .att = imx_rproc_att_imx8mn, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), - .method = IMX_RPROC_SMC, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { - .src_reg = IMX7D_SRC_SCR, - .src_mask = IMX7D_M4_RST_MASK, - .src_start = IMX7D_M4_START, - .src_stop = IMX7D_M4_STOP, - .att = imx_rproc_att_imx8mq, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), - .method = IMX_RPROC_MMIO, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { - .att = imx_rproc_att_imx8qm, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8qm), - .method = IMX_RPROC_SCU_API, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qxp = { - .att = imx_rproc_att_imx8qxp, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8qxp), - .method = IMX_RPROC_SCU_API, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = { - .att = imx_rproc_att_imx8ulp, - .att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp), - .method = IMX_RPROC_NONE, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = { - .att = imx_rproc_att_imx7ulp, - .att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp), - .method = IMX_RPROC_NONE, - .flags = IMX_RPROC_NEED_SYSTEM_OFF, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { - .src_reg = IMX7D_SRC_SCR, - .src_mask = IMX7D_M4_RST_MASK, - .src_start = IMX7D_M4_START, - .src_stop = IMX7D_M4_STOP, - .att = imx_rproc_att_imx7d, - .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), - .method = IMX_RPROC_MMIO, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { - .src_reg = IMX6SX_SRC_SCR, - .src_mask = IMX6SX_M4_RST_MASK, - .src_start = IMX6SX_M4_START, - .src_stop = IMX6SX_M4_STOP, - .att = imx_rproc_att_imx6sx, - .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), - .method = IMX_RPROC_MMIO, -}; - -static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { - .att = imx_rproc_att_imx93, - .att_size = ARRAY_SIZE(imx_rproc_att_imx93), - .method = IMX_RPROC_SMC, -}; - static int imx_rproc_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -1222,6 +1143,85 @@ static void imx_rproc_remove(struct platform_device *pdev) destroy_workqueue(priv->workqueue); } +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX8M_M7_STOP, + .gpr_reg = IMX8M_GPR22, + .gpr_wait = IMX8M_GPR22_CM7_CPUWAIT, + .att = imx_rproc_att_imx8mn, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), + .method = IMX_RPROC_MMIO, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { + .att = imx_rproc_att_imx8mn, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), + .method = IMX_RPROC_SMC, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX7D_M4_STOP, + .att = imx_rproc_att_imx8mq, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), + .method = IMX_RPROC_MMIO, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { + .att = imx_rproc_att_imx8qm, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8qm), + .method = IMX_RPROC_SCU_API, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qxp = { + .att = imx_rproc_att_imx8qxp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8qxp), + .method = IMX_RPROC_SCU_API, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = { + .att = imx_rproc_att_imx8ulp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp), + .method = IMX_RPROC_NONE, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = { + .att = imx_rproc_att_imx7ulp, + .att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp), + .method = IMX_RPROC_NONE, + .flags = IMX_RPROC_NEED_SYSTEM_OFF, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX7D_M4_STOP, + .att = imx_rproc_att_imx7d, + .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), + .method = IMX_RPROC_MMIO, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { + .src_reg = IMX6SX_SRC_SCR, + .src_mask = IMX6SX_M4_RST_MASK, + .src_start = IMX6SX_M4_START, + .src_stop = IMX6SX_M4_STOP, + .att = imx_rproc_att_imx6sx, + .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), + .method = IMX_RPROC_MMIO, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { + .att = imx_rproc_att_imx93, + .att_size = ARRAY_SIZE(imx_rproc_att_imx93), + .method = IMX_RPROC_SMC, +}; + static const struct of_device_id imx_rproc_of_match[] = { { .compatible = "fsl,imx7ulp-cm4", .data = &imx_rproc_cfg_imx7ulp }, { .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d }, From e14168bf3493aa86dcca1eb2666318a61b450b18 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:47 +0800 Subject: [PATCH 1462/2711] remoteproc: imx_rproc: Simplify IMX_RPROC_MMIO switch case Introduce imx_rproc_mmio_{start, stop, detect_mode}() helper functions for all i.MX variants using IMX_RPROC_MMIO to manage remote processors. This allows the removal of the IMX_RPROC_MMIO switch-case blocks from imx_rproc_start(), imx_rproc_stop(), and imx_rproc_detect_mode(), resulting in cleaner and more maintainable code. No functional changes. Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-3-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 148 +++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 62 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index af7b69d750de..c37dd6759596 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -285,6 +285,17 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; +static int imx_rproc_mmio_start(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + + if (priv->gpr) + return regmap_clear_bits(priv->gpr, dcfg->gpr_reg, dcfg->gpr_wait); + + return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_start); +} + static int imx_rproc_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -303,16 +314,6 @@ static int imx_rproc_start(struct rproc *rproc) } switch (dcfg->method) { - case IMX_RPROC_MMIO: - if (priv->gpr) { - ret = regmap_clear_bits(priv->gpr, dcfg->gpr_reg, - dcfg->gpr_wait); - } else { - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, - dcfg->src_mask, - dcfg->src_start); - } - break; case IMX_RPROC_SMC: arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); ret = res.a0; @@ -331,6 +332,23 @@ start_ret: return ret; } +static int imx_rproc_mmio_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + int ret; + + if (priv->gpr) { + ret = regmap_set_bits(priv->gpr, dcfg->gpr_reg, dcfg->gpr_wait); + if (ret) { + dev_err(priv->dev, "Failed to quiescence M4 platform!\n"); + return ret; + } + } + + return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_stop); +} + static int imx_rproc_stop(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -345,20 +363,6 @@ static int imx_rproc_stop(struct rproc *rproc) } switch (dcfg->method) { - case IMX_RPROC_MMIO: - if (priv->gpr) { - ret = regmap_set_bits(priv->gpr, dcfg->gpr_reg, - dcfg->gpr_wait); - if (ret) { - dev_err(priv->dev, - "Failed to quiescence M4 platform!\n"); - return ret; - } - } - - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, - dcfg->src_stop); - break; case IMX_RPROC_SMC: arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); ret = res.a0; @@ -855,15 +859,60 @@ static int imx_rproc_attach_pd(struct imx_rproc *priv) return 0; } -static int imx_rproc_detect_mode(struct imx_rproc *priv) +static int imx_rproc_mmio_detect_mode(struct rproc *rproc) { - struct regmap_config config = { .name = "imx-rproc" }; + const struct regmap_config config = { .name = "imx-rproc" }; + struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; struct regmap *regmap; + u32 val; + int ret; + + priv->gpr = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,iomuxc-gpr"); + if (IS_ERR(priv->gpr)) + priv->gpr = NULL; + + regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to find syscon\n"); + return PTR_ERR(regmap); + } + + priv->regmap = regmap; + regmap_attach_dev(dev, regmap, &config); + + if (priv->gpr) { + ret = regmap_read(priv->gpr, dcfg->gpr_reg, &val); + if (val & dcfg->gpr_wait) { + /* + * After cold boot, the CM indicates its in wait + * state, but not fully powered off. Power it off + * fully so firmware can be loaded into it. + */ + imx_rproc_stop(priv->rproc); + return 0; + } + } + + ret = regmap_read(regmap, dcfg->src_reg, &val); + if (ret) { + dev_err(dev, "Failed to read src\n"); + return ret; + } + + if ((val & dcfg->src_mask) != dcfg->src_stop) + priv->rproc->state = RPROC_DETACHED; + + return 0; +} + +static int imx_rproc_detect_mode(struct imx_rproc *priv) +{ + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + struct device *dev = priv->dev; struct arm_smccc_res res; int ret; - u32 val; u8 pt; if (dcfg->ops && dcfg->ops->detect_mode) @@ -937,41 +986,6 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) break; } - priv->gpr = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,iomuxc-gpr"); - if (IS_ERR(priv->gpr)) - priv->gpr = NULL; - - regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); - if (IS_ERR(regmap)) { - dev_err(dev, "failed to find syscon\n"); - return PTR_ERR(regmap); - } - - priv->regmap = regmap; - regmap_attach_dev(dev, regmap, &config); - - if (priv->gpr) { - ret = regmap_read(priv->gpr, dcfg->gpr_reg, &val); - if (val & dcfg->gpr_wait) { - /* - * After cold boot, the CM indicates its in wait - * state, but not fully powered off. Power it off - * fully so firmware can be loaded into it. - */ - imx_rproc_stop(priv->rproc); - return 0; - } - } - - ret = regmap_read(regmap, dcfg->src_reg, &val); - if (ret) { - dev_err(dev, "Failed to read src\n"); - return ret; - } - - if ((val & dcfg->src_mask) != dcfg->src_stop) - priv->rproc->state = RPROC_DETACHED; - return 0; } @@ -1143,6 +1157,12 @@ static void imx_rproc_remove(struct platform_device *pdev) destroy_workqueue(priv->workqueue); } +static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = { + .start = imx_rproc_mmio_start, + .stop = imx_rproc_mmio_stop, + .detect_mode = imx_rproc_mmio_detect_mode, +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { .src_reg = IMX7D_SRC_SCR, .src_mask = IMX7D_M4_RST_MASK, @@ -1153,6 +1173,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { .att = imx_rproc_att_imx8mn, .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { @@ -1169,6 +1190,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { .att = imx_rproc_att_imx8mq, .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { @@ -1204,6 +1226,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { .att = imx_rproc_att_imx7d, .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { @@ -1214,6 +1237,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { .att = imx_rproc_att_imx6sx, .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { From b7ea858a82194160952875a2e8643ceda1943db5 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:48 +0800 Subject: [PATCH 1463/2711] remoteproc: imx_rproc: Simplify IMX_RPROC_SCU_API switch case Introduce imx_rproc_scu_api_{start, stop, detect_mode}() helper functions for all i.MX variants using IMX_RPROC_SCU_API to manage remote processors. This allows the removal of the IMX_RPROC_SCU_API switch-case blocks from imx_rproc_start(), imx_rproc_stop(), and imx_rproc_detect_mode(), resulting in cleaner and more maintainable code. No functional changes. Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-4-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 149 +++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 64 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index c37dd6759596..ea34080970c6 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -296,6 +296,13 @@ static int imx_rproc_mmio_start(struct rproc *rproc) return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_start); } +static int imx_rproc_scu_api_start(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + + return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); +} + static int imx_rproc_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -318,9 +325,6 @@ static int imx_rproc_start(struct rproc *rproc) arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); ret = res.a0; break; - case IMX_RPROC_SCU_API: - ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); - break; default: return -EOPNOTSUPP; } @@ -349,6 +353,13 @@ static int imx_rproc_mmio_stop(struct rproc *rproc) return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_stop); } +static int imx_rproc_scu_api_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + + return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry); +} + static int imx_rproc_stop(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -369,9 +380,6 @@ static int imx_rproc_stop(struct rproc *rproc) if (res.a1) dev_info(dev, "Not in wfi, force stopped\n"); break; - case IMX_RPROC_SCU_API: - ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry); - break; default: return -EOPNOTSUPP; } @@ -907,13 +915,73 @@ static int imx_rproc_mmio_detect_mode(struct rproc *rproc) return 0; } +static int imx_rproc_scu_api_detect_mode(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + struct device *dev = priv->dev; + int ret; + u8 pt; + + ret = imx_scu_get_handle(&priv->ipc_handle); + if (ret) + return ret; + ret = of_property_read_u32(dev->of_node, "fsl,resource-id", &priv->rsrc_id); + if (ret) { + dev_err(dev, "No fsl,resource-id property\n"); + return ret; + } + + if (priv->rsrc_id == IMX_SC_R_M4_1_PID0) + priv->core_index = 1; + else + priv->core_index = 0; + + /* + * If Mcore resource is not owned by Acore partition, It is kicked by ROM, + * and Linux could only do IPC with Mcore and nothing else. + */ + if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) { + if (of_property_read_u32(dev->of_node, "fsl,entry-address", &priv->entry)) + return -EINVAL; + + return imx_rproc_attach_pd(priv); + } + + priv->rproc->state = RPROC_DETACHED; + priv->rproc->recovery_disabled = false; + rproc_set_feature(priv->rproc, RPROC_FEAT_ATTACH_ON_RECOVERY); + + /* Get partition id and enable irq in SCFW */ + ret = imx_sc_rm_get_resource_owner(priv->ipc_handle, priv->rsrc_id, &pt); + if (ret) { + dev_err(dev, "not able to get resource owner\n"); + return ret; + } + + priv->rproc_pt = pt; + priv->rproc_nb.notifier_call = imx_rproc_partition_notify; + + ret = imx_scu_irq_register_notifier(&priv->rproc_nb); + if (ret) { + dev_err(dev, "register scu notifier failed, %d\n", ret); + return ret; + } + + ret = imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED, BIT(priv->rproc_pt), + true); + if (ret) { + imx_scu_irq_unregister_notifier(&priv->rproc_nb); + dev_err(dev, "Enable irq failed, %d\n", ret); + return ret; + } + + return 0; +} + static int imx_rproc_detect_mode(struct imx_rproc *priv) { const struct imx_rproc_dcfg *dcfg = priv->dcfg; - struct device *dev = priv->dev; struct arm_smccc_res res; - int ret; - u8 pt; if (dcfg->ops && dcfg->ops->detect_mode) return dcfg->ops->detect_mode(priv->rproc); @@ -927,61 +995,6 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) if (res.a0) priv->rproc->state = RPROC_DETACHED; return 0; - case IMX_RPROC_SCU_API: - ret = imx_scu_get_handle(&priv->ipc_handle); - if (ret) - return ret; - ret = of_property_read_u32(dev->of_node, "fsl,resource-id", &priv->rsrc_id); - if (ret) { - dev_err(dev, "No fsl,resource-id property\n"); - return ret; - } - - if (priv->rsrc_id == IMX_SC_R_M4_1_PID0) - priv->core_index = 1; - else - priv->core_index = 0; - - /* - * If Mcore resource is not owned by Acore partition, It is kicked by ROM, - * and Linux could only do IPC with Mcore and nothing else. - */ - if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) { - if (of_property_read_u32(dev->of_node, "fsl,entry-address", &priv->entry)) - return -EINVAL; - - return imx_rproc_attach_pd(priv); - } - - priv->rproc->state = RPROC_DETACHED; - priv->rproc->recovery_disabled = false; - rproc_set_feature(priv->rproc, RPROC_FEAT_ATTACH_ON_RECOVERY); - - /* Get partition id and enable irq in SCFW */ - ret = imx_sc_rm_get_resource_owner(priv->ipc_handle, priv->rsrc_id, &pt); - if (ret) { - dev_err(dev, "not able to get resource owner\n"); - return ret; - } - - priv->rproc_pt = pt; - priv->rproc_nb.notifier_call = imx_rproc_partition_notify; - - ret = imx_scu_irq_register_notifier(&priv->rproc_nb); - if (ret) { - dev_err(dev, "register scu notifier failed, %d\n", ret); - return ret; - } - - ret = imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED, BIT(priv->rproc_pt), - true); - if (ret) { - imx_scu_irq_unregister_notifier(&priv->rproc_nb); - dev_err(dev, "Enable irq failed, %d\n", ret); - return ret; - } - - return 0; default: break; } @@ -1163,6 +1176,12 @@ static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = { .detect_mode = imx_rproc_mmio_detect_mode, }; +static const struct imx_rproc_plat_ops imx_rproc_ops_scu_api = { + .start = imx_rproc_scu_api_start, + .stop = imx_rproc_scu_api_stop, + .detect_mode = imx_rproc_scu_api_detect_mode, +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { .src_reg = IMX7D_SRC_SCR, .src_mask = IMX7D_M4_RST_MASK, @@ -1197,12 +1216,14 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qm = { .att = imx_rproc_att_imx8qm, .att_size = ARRAY_SIZE(imx_rproc_att_imx8qm), .method = IMX_RPROC_SCU_API, + .ops = &imx_rproc_ops_scu_api, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx8qxp = { .att = imx_rproc_att_imx8qxp, .att_size = ARRAY_SIZE(imx_rproc_att_imx8qxp), .method = IMX_RPROC_SCU_API, + .ops = &imx_rproc_ops_scu_api, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = { From ecadd767fb83556fe4db599fd5305b08b8328cef Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:49 +0800 Subject: [PATCH 1464/2711] remoteproc: imx_rproc: Simplify IMX_RPROC_SMC switch case Introduce imx_rproc_arm_smc_{start, stop, detect_mode}() helper functions for all i.MX variants using IMX_RPROC_SMC to manage remote processors. This allows the removal of the IMX_RPROC_SMC switch-case blocks from imx_rproc_start(), imx_rproc_stop(), and imx_rproc_detect_mode(), resulting in cleaner and more maintainable code. Since this is the last switch in imx_rproc_{start,stop}{}, remove the switch-case. No functional changes. Reviewed-by: Frank Li Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-5-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 69 +++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index ea34080970c6..5fa729f4286f 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -285,6 +285,15 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; +static int imx_rproc_arm_smc_start(struct rproc *rproc) +{ + struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); + + return res.a0; +} + static int imx_rproc_mmio_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -308,7 +317,6 @@ static int imx_rproc_start(struct rproc *rproc) struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; - struct arm_smccc_res res; int ret; ret = imx_rproc_xtr_mbox_init(rproc, true); @@ -320,14 +328,7 @@ static int imx_rproc_start(struct rproc *rproc) goto start_ret; } - switch (dcfg->method) { - case IMX_RPROC_SMC: - arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); - ret = res.a0; - break; - default: - return -EOPNOTSUPP; - } + return -EOPNOTSUPP; start_ret: if (ret) @@ -336,6 +337,18 @@ start_ret: return ret; } +static int imx_rproc_arm_smc_stop(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); + if (res.a1) + dev_info(priv->dev, "Not in wfi, force stopped\n"); + + return res.a0; +} + static int imx_rproc_mmio_stop(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; @@ -365,7 +378,6 @@ static int imx_rproc_stop(struct rproc *rproc) struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; - struct arm_smccc_res res; int ret; if (dcfg->ops && dcfg->ops->stop) { @@ -373,16 +385,7 @@ static int imx_rproc_stop(struct rproc *rproc) goto stop_ret; } - switch (dcfg->method) { - case IMX_RPROC_SMC: - arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); - ret = res.a0; - if (res.a1) - dev_info(dev, "Not in wfi, force stopped\n"); - break; - default: - return -EOPNOTSUPP; - } + return -EOPNOTSUPP; stop_ret: if (ret) @@ -867,6 +870,18 @@ static int imx_rproc_attach_pd(struct imx_rproc *priv) return 0; } +static int imx_rproc_arm_smc_detect_mode(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + priv->rproc->state = RPROC_DETACHED; + + return 0; +} + static int imx_rproc_mmio_detect_mode(struct rproc *rproc) { const struct regmap_config config = { .name = "imx-rproc" }; @@ -981,7 +996,6 @@ static int imx_rproc_scu_api_detect_mode(struct rproc *rproc) static int imx_rproc_detect_mode(struct imx_rproc *priv) { const struct imx_rproc_dcfg *dcfg = priv->dcfg; - struct arm_smccc_res res; if (dcfg->ops && dcfg->ops->detect_mode) return dcfg->ops->detect_mode(priv->rproc); @@ -990,11 +1004,6 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) case IMX_RPROC_NONE: priv->rproc->state = RPROC_DETACHED; return 0; - case IMX_RPROC_SMC: - arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res); - if (res.a0) - priv->rproc->state = RPROC_DETACHED; - return 0; default: break; } @@ -1170,6 +1179,12 @@ static void imx_rproc_remove(struct platform_device *pdev) destroy_workqueue(priv->workqueue); } +static const struct imx_rproc_plat_ops imx_rproc_ops_arm_smc = { + .start = imx_rproc_arm_smc_start, + .stop = imx_rproc_arm_smc_stop, + .detect_mode = imx_rproc_arm_smc_detect_mode, +}; + static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = { .start = imx_rproc_mmio_start, .stop = imx_rproc_mmio_stop, @@ -1199,6 +1214,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { .att = imx_rproc_att_imx8mn, .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), .method = IMX_RPROC_SMC, + .ops = &imx_rproc_ops_arm_smc, }; static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { @@ -1265,6 +1281,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { .att = imx_rproc_att_imx93, .att_size = ARRAY_SIZE(imx_rproc_att_imx93), .method = IMX_RPROC_SMC, + .ops = &imx_rproc_ops_arm_smc, }; static const struct of_device_id imx_rproc_of_match[] = { From e65a9ed4c3ec11fb40474f3340b9c1e1551c6b7a Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Sep 2025 15:11:50 +0800 Subject: [PATCH 1465/2711] remoteproc: imx_rproc: Clean up after ops introduction With the switch-case in imx_rproc_{start,stop}{} removed, simplify the code logic by removing 'goto'. The last switch-case in imx_rproc_detect_mode() are no longer needed and can be removed. This cleanup improves code readability and aligns with the new ops-based design. No functional changes. Reviewed-by: Daniel Baluta Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20250910-imx-rproc-cleanup-v2-6-10386685b8a9@nxp.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 5fa729f4286f..bb25221a4a89 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -323,14 +323,10 @@ static int imx_rproc_start(struct rproc *rproc) if (ret) return ret; - if (dcfg->ops && dcfg->ops->start) { - ret = dcfg->ops->start(rproc); - goto start_ret; - } + if (!dcfg->ops || !dcfg->ops->start) + return -EOPNOTSUPP; - return -EOPNOTSUPP; - -start_ret: + ret = dcfg->ops->start(rproc); if (ret) dev_err(dev, "Failed to enable remote core!\n"); @@ -380,14 +376,10 @@ static int imx_rproc_stop(struct rproc *rproc) struct device *dev = priv->dev; int ret; - if (dcfg->ops && dcfg->ops->stop) { - ret = dcfg->ops->stop(rproc); - goto stop_ret; - } + if (!dcfg->ops || !dcfg->ops->stop) + return -EOPNOTSUPP; - return -EOPNOTSUPP; - -stop_ret: + ret = dcfg->ops->stop(rproc); if (ret) dev_err(dev, "Failed to stop remote core\n"); else @@ -997,18 +989,16 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) { const struct imx_rproc_dcfg *dcfg = priv->dcfg; - if (dcfg->ops && dcfg->ops->detect_mode) - return dcfg->ops->detect_mode(priv->rproc); - - switch (dcfg->method) { - case IMX_RPROC_NONE: + /* + * To i.MX{7,8} ULP, Linux is under control of RTOS, no need + * dcfg->ops or dcfg->ops->detect_mode, it is state RPROC_DETACHED. + */ + if (!dcfg->ops || !dcfg->ops->detect_mode) { priv->rproc->state = RPROC_DETACHED; return 0; - default: - break; } - return 0; + return dcfg->ops->detect_mode(priv->rproc); } static int imx_rproc_clk_enable(struct imx_rproc *priv) From 597f41e1743882db32f99dde062adbec29104586 Mon Sep 17 00:00:00 2001 From: Alexandru Elisei Date: Mon, 15 Sep 2025 16:52:34 +0100 Subject: [PATCH 1466/2711] KVM: arm64: Update stale comment for sanitise_mte_tags() Commit c911f0d46879 ("KVM: arm64: permit all VM_MTE_ALLOWED mappings with MTE enabled") allowed VM_SHARED VMAs in a VM with MTE enabled, so remove the comment to the contrary. Commit d77e59a8fccd ("arm64: mte: Lock a page for MTE tag initialisation") removed the race that can lead to tags being zeroed more than once when multiple threads attempt initialisation at the same time, so remove the comment about mmap_lock too. Note that sanitise_mte_tags() was never called with the mmap_lock held from user_mem_abort() and the race was prevented by kvm->mmu_lock. However, the function still requires to have the kvm->mmu_lock held to ensure that the memory remains mapped in the userspace process while the tags are zeroed. Document this in a comment. CC: Peter Collingbourne CC: Catalin Marinas CC: Steven Price Signed-off-by: Alexandru Elisei Reviewed-by: Steven Price Signed-off-by: Marc Zyngier --- arch/arm64/kvm/mmu.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 1c78864767c5..006fdb017c54 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1426,11 +1426,8 @@ static int get_vma_page_shift(struct vm_area_struct *vma, unsigned long hva) * able to see the page's tags and therefore they must be initialised first. If * PG_mte_tagged is set, tags have already been initialised. * - * The race in the test/set of the PG_mte_tagged flag is handled by: - * - preventing VM_SHARED mappings in a memslot with MTE preventing two VMs - * racing to santise the same page - * - mmap_lock protects between a VM faulting a page in and the VMM performing - * an mprotect() to add VM_MTE + * Must be called with kvm->mmu_lock held to ensure the memory remains mapped + * while the tags are zeroed. */ static void sanitise_mte_tags(struct kvm *kvm, kvm_pfn_t pfn, unsigned long size) From d7fc7d9833f6b60805f67e3f913b7a646ce2a47e Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Wed, 20 Aug 2025 20:50:01 +0000 Subject: [PATCH 1467/2711] KVM: SEV: Introduce new min,max sev_es and sev_snp asid variables Introduce new min, max sev_es_asid and sev_snp_asid variables. The new {min,max}_{sev_es,snp}_asid variables along with existing {min,max}_sev_asid variable simplifies partitioning of the SEV and SEV-ES+ ASID space. Suggested-by: Sean Christopherson Reviewed-by: Tom Lendacky Signed-off-by: Ashish Kalra Link: https://lore.kernel.org/r/1db48277e8e96a633d734786ea69bf830f014857.1755721927.git.ashish.kalra@amd.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 2fbdebf79fbb..b5f4e69ff579 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -85,6 +85,10 @@ static DECLARE_RWSEM(sev_deactivate_lock); static DEFINE_MUTEX(sev_bitmap_lock); unsigned int max_sev_asid; static unsigned int min_sev_asid; +static unsigned int max_sev_es_asid; +static unsigned int min_sev_es_asid; +static unsigned int max_snp_asid; +static unsigned int min_snp_asid; static unsigned long sev_me_mask; static unsigned int nr_asids; static unsigned long *sev_asid_bitmap; @@ -173,20 +177,31 @@ static void sev_misc_cg_uncharge(struct kvm_sev_info *sev) misc_cg_uncharge(type, sev->misc_cg, 1); } -static int sev_asid_new(struct kvm_sev_info *sev) +static int sev_asid_new(struct kvm_sev_info *sev, unsigned long vm_type) { /* * SEV-enabled guests must use asid from min_sev_asid to max_sev_asid. * SEV-ES-enabled guest can use from 1 to min_sev_asid - 1. - * Note: min ASID can end up larger than the max if basic SEV support is - * effectively disabled by disallowing use of ASIDs for SEV guests. */ - unsigned int min_asid = sev->es_active ? 1 : min_sev_asid; - unsigned int max_asid = sev->es_active ? min_sev_asid - 1 : max_sev_asid; - unsigned int asid; + unsigned int min_asid, max_asid, asid; bool retry = true; int ret; + if (vm_type == KVM_X86_SNP_VM) { + min_asid = min_snp_asid; + max_asid = max_snp_asid; + } else if (sev->es_active) { + min_asid = min_sev_es_asid; + max_asid = max_sev_es_asid; + } else { + min_asid = min_sev_asid; + max_asid = max_sev_asid; + } + + /* + * The min ASID can end up larger than the max if basic SEV support is + * effectively disabled by disallowing use of ASIDs for SEV guests. + */ if (min_asid > max_asid) return -ENOTTY; @@ -440,7 +455,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, if (vm_type == KVM_X86_SNP_VM) sev->vmsa_features |= SVM_SEV_FEAT_SNP_ACTIVE; - ret = sev_asid_new(sev); + ret = sev_asid_new(sev, vm_type); if (ret) goto e_no_asid; @@ -3042,6 +3057,9 @@ void __init sev_hardware_setup(void) if (min_sev_asid == 1) goto out; + min_sev_es_asid = min_snp_asid = 1; + max_sev_es_asid = max_snp_asid = min_sev_asid - 1; + sev_es_asid_count = min_sev_asid - 1; WARN_ON_ONCE(misc_cg_set_capacity(MISC_CG_RES_SEV_ES, sev_es_asid_count)); sev_es_supported = true; @@ -3065,11 +3083,11 @@ out: if (boot_cpu_has(X86_FEATURE_SEV_ES)) pr_info("SEV-ES %s (ASIDs %u - %u)\n", str_enabled_disabled(sev_es_supported), - min_sev_asid > 1 ? 1 : 0, min_sev_asid - 1); + min_sev_es_asid, max_sev_es_asid); if (boot_cpu_has(X86_FEATURE_SEV_SNP)) pr_info("SEV-SNP %s (ASIDs %u - %u)\n", str_enabled_disabled(sev_snp_supported), - min_sev_asid > 1 ? 1 : 0, min_sev_asid - 1); + min_snp_asid, max_snp_asid); sev_enabled = sev_supported; sev_es_enabled = sev_es_supported; From 6c7c620585c6537dd5dcc75f972b875caf00f773 Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Wed, 20 Aug 2025 20:50:25 +0000 Subject: [PATCH 1468/2711] KVM: SEV: Add SEV-SNP CipherTextHiding support Ciphertext hiding prevents host accesses from reading the ciphertext of SNP guest private memory. Instead of reading ciphertext, the host reads will see constant default values (0xff). The SEV ASID space is split into SEV and SEV-ES/SEV-SNP ASID ranges. Enabling ciphertext hiding further splits the SEV-ES/SEV-SNP ASID space into separate ASID ranges for SEV-ES and SEV-SNP guests. Add a new off-by-default kvm-amd module parameter to enable ciphertext hiding and allow the admin to configure the SEV-ES and SEV-SNP ASID ranges. Simply cap the maximum SEV-SNP ASID as appropriate, i.e. don't reject loading KVM or disable ciphertest hiding for a too-big value, as KVM's general approach for module params is to sanitize inputs based on hardware/kernel support, not burn the world down. This also allows the admin to use -1u to assign all SEV-ES/SNP ASIDs to SNP without needing dedicated handling in KVM. Suggested-by: Sean Christopherson Signed-off-by: Ashish Kalra Co-developed-by: Sean Christopherson Link: https://lore.kernel.org/r/95abc49edfde36d4fb791570ea2a4be6ad95fd0d.1755721927.git.ashish.kalra@amd.com Signed-off-by: Sean Christopherson --- .../admin-guide/kernel-parameters.txt | 21 ++++++++++++ arch/x86/kvm/svm/sev.c | 32 ++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 747a55abf494..69d640efb661 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2957,6 +2957,27 @@ (enabled). Disable by KVM if hardware lacks support for NPT. + kvm-amd.ciphertext_hiding_asids= + [KVM,AMD] Ciphertext hiding prevents disallowed accesses + to SNP private memory from reading ciphertext. Instead, + reads will see constant default values (0xff). + + If ciphertext hiding is enabled, the joint SEV-ES and + SEV-SNP ASID space is partitioned into separate SEV-ES + and SEV-SNP ASID ranges, with the SEV-SNP range being + [1..max_snp_asid] and the SEV-ES range being + (max_snp_asid..min_sev_asid), where min_sev_asid is + enumerated by CPUID.0x.8000_001F[EDX]. + + A non-zero value enables SEV-SNP ciphertext hiding and + adjusts the ASID ranges for SEV-ES and SEV-SNP guests. + KVM caps the number of SEV-SNP ASIDs at the maximum + possible value, e.g. specifying -1u will assign all + joint SEV-ES and SEV-SNP ASIDs to SEV-SNP. Note, + assigning all joint ASIDs to SEV-SNP, i.e. configuring + max_snp_asid == min_sev_asid-1, will effectively make + SEV-ES unusable. + kvm-arm.mode= [KVM,ARM,EARLY] Select one of KVM/arm64's modes of operation. diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index b5f4e69ff579..01345b73f879 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -59,6 +59,9 @@ static bool sev_es_debug_swap_enabled = true; module_param_named(debug_swap, sev_es_debug_swap_enabled, bool, 0444); static u64 sev_supported_vmsa_features; +static unsigned int nr_ciphertext_hiding_asids; +module_param_named(ciphertext_hiding_asids, nr_ciphertext_hiding_asids, uint, 0444); + #define AP_RESET_HOLD_NONE 0 #define AP_RESET_HOLD_NAE_EVENT 1 #define AP_RESET_HOLD_MSR_PROTO 2 @@ -201,6 +204,9 @@ static int sev_asid_new(struct kvm_sev_info *sev, unsigned long vm_type) /* * The min ASID can end up larger than the max if basic SEV support is * effectively disabled by disallowing use of ASIDs for SEV guests. + * Similarly for SEV-ES guests the min ASID can end up larger than the + * max when ciphertext hiding is enabled, effectively disabling SEV-ES + * support. */ if (min_asid > max_asid) return -ENOTTY; @@ -3068,10 +3074,32 @@ void __init sev_hardware_setup(void) out: if (sev_enabled) { init_args.probe = true; + + if (sev_is_snp_ciphertext_hiding_supported()) + init_args.max_snp_asid = min(nr_ciphertext_hiding_asids, + min_sev_asid - 1); + if (sev_platform_init(&init_args)) sev_supported = sev_es_supported = sev_snp_supported = false; else if (sev_snp_supported) sev_snp_supported = is_sev_snp_initialized(); + + if (sev_snp_supported) + nr_ciphertext_hiding_asids = init_args.max_snp_asid; + + /* + * If ciphertext hiding is enabled, the joint SEV-ES/SEV-SNP + * ASID range is partitioned into separate SEV-ES and SEV-SNP + * ASID ranges, with the SEV-SNP range being [1..max_snp_asid] + * and the SEV-ES range being (max_snp_asid..max_sev_es_asid]. + * Note, SEV-ES may effectively be disabled if all ASIDs from + * the joint range are assigned to SEV-SNP. + */ + if (nr_ciphertext_hiding_asids) { + max_snp_asid = nr_ciphertext_hiding_asids; + min_sev_es_asid = max_snp_asid + 1; + pr_info("SEV-SNP ciphertext hiding enabled\n"); + } } if (boot_cpu_has(X86_FEATURE_SEV)) @@ -3082,7 +3110,9 @@ out: min_sev_asid, max_sev_asid); if (boot_cpu_has(X86_FEATURE_SEV_ES)) pr_info("SEV-ES %s (ASIDs %u - %u)\n", - str_enabled_disabled(sev_es_supported), + sev_es_supported ? min_sev_es_asid <= max_sev_es_asid ? "enabled" : + "unusable" : + "disabled", min_sev_es_asid, max_sev_es_asid); if (boot_cpu_has(X86_FEATURE_SEV_SNP)) pr_info("SEV-SNP %s (ASIDs %u - %u)\n", From d021fb3ae844dad0a1d2f037a9657fde330955bb Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 15 Sep 2025 10:12:26 +0300 Subject: [PATCH 1469/2711] dt-bindings: iio: adc: ROHM BD79112 ADC/GPIO The ROHM BD79112 is an ADC/GPIO with 32 channels. The channel inputs can be used as ADC or GPIO. Using the GPIOs as IRQ sources isn't supported. The ADC is 12-bit, supporting input voltages up to 5.7V, and separate I/O voltage supply. Maximum SPI clock rate is 20 MHz (10 MHz with daisy-chain configuration) and maximum sampling rate is 1MSPS. Add a device tree binding document for the ROHM BD79112. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Reviewed-by: Linus Walleij Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/rohm,bd79112.yaml | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/rohm,bd79112.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/rohm,bd79112.yaml b/Documentation/devicetree/bindings/iio/adc/rohm,bd79112.yaml new file mode 100644 index 000000000000..aa8b07c3fac1 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/rohm,bd79112.yaml @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/rohm,bd79112.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD79112 ADC/GPO + +maintainers: + - Matti Vaittinen + +description: | + The ROHM BD79112 is a 12-bit, 32-channel, SAR ADC. ADC input pins can be + also configured as general purpose inputs/outputs. SPI should use MODE 3. + +properties: + compatible: + const: rohm,bd79112 + + reg: + maxItems: 1 + + spi-cpha: true + spi-cpol: true + + gpio-controller: true + "#gpio-cells": + const: 2 + + vdd-supply: true + + iovdd-supply: true + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^channel@([0-9]|[12][0-9]|3[01])$": + type: object + $ref: /schemas/iio/adc/adc.yaml# + description: Represents ADC channel. Omitted channels' inputs are GPIOs. + + properties: + reg: + description: AIN pin number + minimum: 0 + maximum: 31 + + required: + - reg + + additionalProperties: false + +required: + - compatible + - reg + - iovdd-supply + - vdd-supply + - spi-cpha + - spi-cpol + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + adc: adc@0 { + compatible = "rohm,bd79112"; + reg = <0x0>; + + spi-cpha; + spi-cpol; + + vdd-supply = <&dummyreg>; + iovdd-supply = <&dummyreg>; + + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + channel@0 { + reg = <0>; + }; + channel@1 { + reg = <1>; + }; + channel@2 { + reg = <2>; + }; + channel@16 { + reg = <16>; + }; + channel@20 { + reg = <20>; + }; + }; + }; From edf2fc7b5bc4213abd19e9532b80a16e7690a512 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 15 Sep 2025 10:12:43 +0300 Subject: [PATCH 1470/2711] iio: adc: Support ROHM BD79112 ADC/GPIO The ROHM BD79112 is an ADC/GPIO with 32 channels. The channel inputs can be used as ADC or GPIO. Using the GPIOs as IRQ sources isn't supported. The ADC is 12-bit, supporting input voltages up to 5.7V, and separate I/O voltage supply. Maximum SPI clock rate is 20 MHz (10 MHz with daisy-chain configuration) and maximum sampling rate is 1MSPS. The IC does also support CRC but it is not implemented in the driver. Signed-off-by: Matti Vaittinen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 10 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/rohm-bd79112.c | 556 +++++++++++++++++++++++++++++++++ 3 files changed, 567 insertions(+) create mode 100644 drivers/iio/adc/rohm-bd79112.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 237fa2061329..58a14e6833f6 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1342,6 +1342,16 @@ config RN5T618_ADC This driver can also be built as a module. If so, the module will be called rn5t618-adc. +config ROHM_BD79112 + tristate "Rohm BD79112 ADC driver" + depends on SPI && GPIOLIB + select REGMAP_SPI + select IIO_ADC_HELPER + help + Say yes here to build support for the ROHM BD79112 ADC. The + ROHM BD79112 is a 12-bit, 32-channel, SAR ADC. Analog inputs + can also be used for GPIO. + config ROHM_BD79124 tristate "Rohm BD79124 ADC driver" depends on I2C && GPIOLIB diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 611c16430621..d008f78dc010 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -119,6 +119,7 @@ obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o +obj-$(CONFIG_ROHM_BD79112) += rohm-bd79112.o obj-$(CONFIG_ROHM_BD79124) += rohm-bd79124.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o diff --git a/drivers/iio/adc/rohm-bd79112.c b/drivers/iio/adc/rohm-bd79112.c new file mode 100644 index 000000000000..d15e06c8b94d --- /dev/null +++ b/drivers/iio/adc/rohm-bd79112.c @@ -0,0 +1,556 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ROHM ADC driver for BD79112 signal monitoring hub. + * Copyright (C) 2025, ROHM Semiconductor. + * + * SPI communication derived from ad7923.c and ti-ads7950.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define BD79112_MAX_NUM_CHANNELS 32 + +struct bd79112_data { + struct spi_device *spi; + struct regmap *map; + struct device *dev; + struct gpio_chip gc; + unsigned long gpio_valid_mask; + unsigned int vref_mv; + struct spi_transfer read_xfer[2]; + struct spi_transfer write_xfer; + struct spi_message read_msg; + struct spi_message write_msg; + /* 16-bit TX, valid data in high byte */ + u8 read_tx[2] __aligned(IIO_DMA_MINALIGN); + /* 8-bit address followed by 8-bit data */ + u8 reg_write_tx[2]; + /* 12-bit of ADC data or 8 bit of reg data */ + __be16 read_rx; +}; + +/* + * The ADC data is read issuing SPI-command matching the channel number. + * We treat this as a register address. + */ +#define BD79112_REG_AGIO0A 0x00 +#define BD79112_REG_AGIO15B 0x1f + +/* + * ADC STATUS_FLAG appended to ADC data will be set, if the ADC result is being + * read for a channel, which input pin is muxed to be a GPIO. + */ +#define BD79112_ADC_STATUS_FLAG BIT(14) + +/* + * The BD79112 requires "R/W bit" to be set for SPI register (not ADC data) + * reads and an "IOSET bit" to be set for read/write operations (which aren't + * reading the ADC data). + */ +#define BD79112_BIT_RW BIT(4) +#define BD79112_BIT_IO BIT(5) + +#define BD79112_REG_GPI_VALUE_B8_15 (BD79112_BIT_IO | 0x0) +#define BD79112_REG_GPI_VALUE_B0_B7 (BD79112_BIT_IO | 0x1) +#define BD79112_REG_GPI_VALUE_A8_15 (BD79112_BIT_IO | 0x2) +#define BD79112_REG_GPI_VALUE_A0_A7 (BD79112_BIT_IO | 0x3) + +#define BD79112_REG_GPI_EN_B7_B15 (BD79112_BIT_IO | 0x4) +#define BD79112_REG_GPI_EN_B0_B7 (BD79112_BIT_IO | 0x5) +#define BD79112_REG_GPI_EN_A8_A15 (BD79112_BIT_IO | 0x6) +#define BD79112_REG_GPI_EN_A0_A7 (BD79112_BIT_IO | 0x7) + +#define BD79112_REG_GPO_EN_B7_B15 (BD79112_BIT_IO | 0x8) +#define BD79112_REG_GPO_EN_B0_B7 (BD79112_BIT_IO | 0x9) +#define BD79112_REG_GPO_EN_A8_A15 (BD79112_BIT_IO | 0xa) +#define BD79112_REG_GPO_EN_A0_A7 (BD79112_BIT_IO | 0xb) + +#define BD79112_NUM_GPIO_EN_REGS 8 +#define BD79112_FIRST_GPIO_EN_REG BD79112_REG_GPI_EN_B7_B15 + +#define BD79112_REG_GPO_VALUE_B8_15 (BD79112_BIT_IO | 0xc) +#define BD79112_REG_GPO_VALUE_B0_B7 (BD79112_BIT_IO | 0xd) +#define BD79112_REG_GPO_VALUE_A8_15 (BD79112_BIT_IO | 0xe) +#define BD79112_REG_GPO_VALUE_A0_A7 (BD79112_BIT_IO | 0xf) + +#define BD79112_REG_MAX BD79112_REG_GPO_VALUE_A0_A7 + +/* + * Read transaction consists of two 16-bit sequences separated by CSB. + * For register read, 'IOSET' bit must be set. For ADC read, IOSET is cleared + * and ADDR equals the channel number (0 ... 31). + * + * First 16-bit sequence, MOSI as below, MISO data ignored: + * - SCK: | 1 | 2 | 3 | 4 | 5 .. 8 | 9 .. 16 | + * - MOSI:| 0 | 0 | IOSET | RW (1) | ADDR | 8'b0 | + * + * CSB released and re-acquired between these sequences + * + * Second 16-bit sequence, MISO as below, MOSI data ignored: + * For Register read data is 8 bits: + * - SCK: | 1 .. 8 | 9 .. 16 | + * - MISO:| 8'b0 | 8-bit data | + * + * For ADC read data is 12 bits: + * - SCK: | 1 | 2 | 3 4 | 4 .. 16 | + * - MISO:| 0 | STATUS_FLAG | 2'b0 | 12-bit data | + * The 'STATUS_FLAG' is set if the read input pin was configured as a GPIO. + */ +static int bd79112_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct bd79112_data *data = context; + int ret; + + if (reg & BD79112_BIT_IO) + reg |= BD79112_BIT_RW; + + data->read_tx[0] = reg; + + ret = spi_sync(data->spi, &data->read_msg); + if (!ret) + *val = be16_to_cpu(data->read_rx); + + return ret; +} + +/* + * Write, single 16-bit sequence (broken down below): + * + * First 8-bit, MOSI as below, MISO data ignored: + * - SCK: | 1 | 2 | 3 | 4 | 5 .. 8 | + * - MOSI:| 0 | 0 |IOSET| RW(0) | ADDR | + * + * Last 8 SCK cycles (b8 ... b15), MISO contains register data, MOSI ignored. + * - SCK: | 9 .. 16 | + * - MISO:| data | + */ +static int bd79112_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct bd79112_data *data = context; + + data->reg_write_tx[0] = reg; + data->reg_write_tx[1] = val; + + return spi_sync(data->spi, &data->write_msg); +} + +static int _get_gpio_reg(unsigned int offset, unsigned int base) +{ + int regoffset = offset / 8; + + if (offset > 31) + return -EINVAL; + + return base - regoffset; +} + +#define GET_GPIO_BIT(offset) BIT((offset) % 8) +#define GET_GPO_EN_REG(offset) _get_gpio_reg((offset), BD79112_REG_GPO_EN_A0_A7) +#define GET_GPI_EN_REG(offset) _get_gpio_reg((offset), BD79112_REG_GPI_EN_A0_A7) +#define GET_GPO_VAL_REG(offset) _get_gpio_reg((offset), BD79112_REG_GPO_VALUE_A0_A7) +#define GET_GPI_VAL_REG(offset) _get_gpio_reg((offset), BD79112_REG_GPI_VALUE_A0_A7) + +static const struct regmap_range bd71815_volatile_ro_ranges[] = { + { + /* Read ADC data */ + .range_min = BD79112_REG_AGIO0A, + .range_max = BD79112_REG_AGIO15B, + }, { + /* GPI state */ + .range_min = BD79112_REG_GPI_VALUE_B8_15, + .range_max = BD79112_REG_GPI_VALUE_A0_A7, + }, +}; + +static const struct regmap_access_table bd79112_volatile_regs = { + .yes_ranges = &bd71815_volatile_ro_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bd71815_volatile_ro_ranges), +}; + +static const struct regmap_access_table bd79112_ro_regs = { + .no_ranges = &bd71815_volatile_ro_ranges[0], + .n_no_ranges = ARRAY_SIZE(bd71815_volatile_ro_ranges), +}; + +static const struct regmap_config bd79112_regmap = { + .reg_read = bd79112_reg_read, + .reg_write = bd79112_reg_write, + .volatile_table = &bd79112_volatile_regs, + .wr_table = &bd79112_ro_regs, + .cache_type = REGCACHE_MAPLE, + .max_register = BD79112_REG_MAX, +}; + +static int bd79112_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long m) +{ + struct bd79112_data *data = iio_priv(indio_dev); + int ret; + + switch (m) { + case IIO_CHAN_INFO_RAW: + ret = regmap_read(data->map, chan->channel, val); + if (ret < 0) + return ret; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = data->vref_mv; + *val2 = 12; + + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static const struct iio_info bd79112_info = { + .read_raw = bd79112_read_raw, +}; + +static const struct iio_chan_spec bd79112_chan_template = { + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, +}; + +static int bd79112_gpio_init_valid_mask(struct gpio_chip *gc, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct bd79112_data *data = gpiochip_get_data(gc); + + *valid_mask = data->gpio_valid_mask; + + return 0; +} + +static int bd79112_gpio_dir_get(struct gpio_chip *gc, unsigned int offset) +{ + struct bd79112_data *data = gpiochip_get_data(gc); + unsigned int reg, bit, val; + int ret; + + bit = GET_GPIO_BIT(offset); + reg = GET_GPO_EN_REG(offset); + + ret = regmap_read(data->map, reg, &val); + if (ret) + return ret; + + if (bit & val) + return GPIO_LINE_DIRECTION_OUT; + + reg = GET_GPI_EN_REG(offset); + ret = regmap_read(data->map, reg, &val); + if (ret) + return ret; + + if (bit & val) + return GPIO_LINE_DIRECTION_IN; + + /* + * Ouch. Seems the pin is ADC input - shouldn't happen as changing mux + * at runtime is not supported and non GPIO pins should be invalidated + * by the valid_mask at probe. Maybe someone wrote a register bypassing + * the driver? + */ + dev_err(data->dev, "Pin not a GPIO\n"); + + return -EINVAL; +} + +static int bd79112_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct bd79112_data *data = gpiochip_get_data(gc); + unsigned int reg, bit, val; + int ret; + + bit = GET_GPIO_BIT(offset); + reg = GET_GPI_VAL_REG(offset); + + ret = regmap_read(data->map, reg, &val); + if (ret) + return ret; + + return !!(val & bit); +} + +static int bd79112_gpio_set(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct bd79112_data *data = gpiochip_get_data(gc); + unsigned int reg, bit; + + bit = GET_GPIO_BIT(offset); + reg = GET_GPO_VAL_REG(offset); + + return regmap_assign_bits(data->map, reg, bit, value); +} + +static int bd79112_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct bd79112_data *data = gpiochip_get_data(gc); + unsigned long i, bank_mask; + + for_each_set_clump8(i, bank_mask, mask, gc->ngpio) { + unsigned long bank_bits; + unsigned int reg; + int ret; + + bank_bits = bitmap_get_value8(bits, i); + reg = BD79112_REG_GPO_VALUE_A0_A7 - i / 8; + ret = regmap_update_bits(data->map, reg, bank_mask, bank_bits); + if (ret) + return ret; + } + + return 0; +} + +static int bd79112_gpio_dir_set(struct bd79112_data *data, unsigned int offset, + int dir) +{ + unsigned int gpi_reg, gpo_reg, bit; + int ret; + + bit = GET_GPIO_BIT(offset); + gpi_reg = GET_GPI_EN_REG(offset); + gpo_reg = GET_GPO_EN_REG(offset); + + if (dir == GPIO_LINE_DIRECTION_OUT) { + ret = regmap_clear_bits(data->map, gpi_reg, bit); + if (ret) + return ret; + + return regmap_set_bits(data->map, gpo_reg, bit); + } + + ret = regmap_set_bits(data->map, gpi_reg, bit); + if (ret) + return ret; + + return regmap_clear_bits(data->map, gpo_reg, bit); +} + +static int bd79112_gpio_input(struct gpio_chip *gc, unsigned int offset) +{ + struct bd79112_data *data = gpiochip_get_data(gc); + + return bd79112_gpio_dir_set(data, offset, GPIO_LINE_DIRECTION_IN); +} + +static int bd79112_gpio_output(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct bd79112_data *data = gpiochip_get_data(gc); + int ret; + + ret = bd79112_gpio_set(gc, offset, value); + if (ret) + return ret; + + return bd79112_gpio_dir_set(data, offset, GPIO_LINE_DIRECTION_OUT); +} + +static const struct gpio_chip bd79112_gpio_chip = { + .label = "bd79112-gpio", + .get_direction = bd79112_gpio_dir_get, + .direction_input = bd79112_gpio_input, + .direction_output = bd79112_gpio_output, + .get = bd79112_gpio_get, + .set = bd79112_gpio_set, + .set_multiple = bd79112_gpio_set_multiple, + .init_valid_mask = bd79112_gpio_init_valid_mask, + .can_sleep = true, + .ngpio = 32, + .base = -1, +}; + +static unsigned int bd79112_get_gpio_pins(const struct iio_chan_spec *cs, int num_channels) +{ + unsigned int i, gpio_channels; + + /* + * Let's initialize the mux config to say that all 32 channels are + * GPIOs. Then we can just loop through the iio_chan_spec and clear the + * bits for found ADC channels. + */ + gpio_channels = GENMASK(31, 0); + for (i = 0; i < num_channels; i++) + gpio_channels &= ~BIT(cs[i].channel); + + return gpio_channels; +} + +/* ADC channels as named in the data-sheet */ +static const char * const bd79112_chan_names[] = { + "AGIO0A", "AGIO1A", "AGIO2A", "AGIO3A", /* 0 - 3 */ + "AGIO4A", "AGIO5A", "AGIO6A", "AGIO7A", /* 4 - 7 */ + "AGIO8A", "AGIO9A", "AGIO10A", "AGIO11A", /* 8 - 11 */ + "AGIO12A", "AGIO13A", "AGIO14A", "AGIO15A", /* 12 - 15 */ + "AGIO0B", "AGIO1B", "AGIO2B", "AGIO3B", /* 16 - 19 */ + "AGIO4B", "AGIO5B", "AGIO6B", "AGIO7B", /* 20 - 23 */ + "AGIO8B", "AGIO9B", "AGIO10B", "AGIO11B", /* 24 - 27 */ + "AGIO12B", "AGIO13B", "AGIO14B", "AGIO15B", /* 28 - 31 */ +}; + +static int bd79112_probe(struct spi_device *spi) +{ + struct bd79112_data *data; + struct iio_dev *iio_dev; + struct iio_chan_spec *cs; + struct device *dev = &spi->dev; + unsigned long gpio_pins, pin; + unsigned int i; + int ret; + + iio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!iio_dev) + return -ENOMEM; + + data = iio_priv(iio_dev); + data->spi = spi; + data->dev = dev; + data->map = devm_regmap_init(dev, NULL, data, &bd79112_regmap); + if (IS_ERR(data->map)) + return dev_err_probe(dev, PTR_ERR(data->map), + "Failed to initialize Regmap\n"); + + ret = devm_regulator_get_enable_read_voltage(dev, "vdd"); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get the Vdd\n"); + + data->vref_mv = ret / 1000; + + ret = devm_regulator_get_enable(dev, "iovdd"); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable I/O voltage\n"); + + data->read_xfer[0].tx_buf = &data->read_tx[0]; + data->read_xfer[0].len = sizeof(data->read_tx); + data->read_xfer[0].cs_change = 1; + data->read_xfer[1].rx_buf = &data->read_rx; + data->read_xfer[1].len = sizeof(data->read_rx); + spi_message_init_with_transfers(&data->read_msg, data->read_xfer, 2); + ret = devm_spi_optimize_message(dev, spi, &data->read_msg); + if (ret < 0) + return dev_err_probe(dev, ret, + "Failed to optimize SPI read message\n"); + + data->write_xfer.tx_buf = &data->reg_write_tx[0]; + data->write_xfer.len = sizeof(data->reg_write_tx); + spi_message_init_with_transfers(&data->write_msg, &data->write_xfer, 1); + ret = devm_spi_optimize_message(dev, spi, &data->write_msg); + if (ret < 0) + return dev_err_probe(dev, ret, + "Failed to optimize SPI write message\n"); + + ret = devm_iio_adc_device_alloc_chaninfo_se(dev, &bd79112_chan_template, + BD79112_MAX_NUM_CHANNELS - 1, + &cs); + + /* Register all pins as GPIOs if there are no ADC channels */ + if (ret == -ENOENT) + goto register_gpios; + + if (ret < 0) + return ret; + + iio_dev->num_channels = ret; + iio_dev->channels = cs; + + for (i = 0; i < iio_dev->num_channels; i++) + cs[i].datasheet_name = bd79112_chan_names[cs[i].channel]; + + iio_dev->info = &bd79112_info; + iio_dev->name = "bd79112"; + iio_dev->modes = INDIO_DIRECT_MODE; + + /* + * Ensure all channels are ADCs. This allows us to register the IIO + * device early (before checking which pins are to be used for GPIO) + * without having to worry about some pins being initially used for + * GPIO. + */ + for (i = 0; i < BD79112_NUM_GPIO_EN_REGS; i++) { + ret = regmap_write(data->map, BD79112_FIRST_GPIO_EN_REG + i, 0); + if (ret) + return dev_err_probe(dev, ret, + "Failed to initialize channels\n"); + } + + ret = devm_iio_device_register(data->dev, iio_dev); + if (ret) + return dev_err_probe(data->dev, ret, "Failed to register ADC\n"); + +register_gpios: + gpio_pins = bd79112_get_gpio_pins(iio_dev->channels, + iio_dev->num_channels); + + /* If all channels are reserved for ADC, then we're done. */ + if (!gpio_pins) + return 0; + + /* Default all the GPIO pins to GPI */ + for_each_set_bit(pin, &gpio_pins, BD79112_MAX_NUM_CHANNELS) { + ret = bd79112_gpio_dir_set(data, pin, GPIO_LINE_DIRECTION_IN); + if (ret) + return dev_err_probe(dev, ret, + "Failed to mark pin as GPI\n"); + } + + data->gpio_valid_mask = gpio_pins; + data->gc = bd79112_gpio_chip; + data->gc.parent = dev; + + return devm_gpiochip_add_data(dev, &data->gc, data); +} + +static const struct of_device_id bd79112_of_match[] = { + { .compatible = "rohm,bd79112" }, + { } +}; +MODULE_DEVICE_TABLE(of, bd79112_of_match); + +static const struct spi_device_id bd79112_id[] = { + { "bd79112" }, + { } +}; +MODULE_DEVICE_TABLE(spi, bd79112_id); + +static struct spi_driver bd79112_driver = { + .driver = { + .name = "bd79112", + .of_match_table = bd79112_of_match, + }, + .probe = bd79112_probe, + .id_table = bd79112_id, +}; +module_spi_driver(bd79112_driver); + +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("Driver for ROHM BD79112 ADC/GPIO"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DRIVER"); From 561285d048053fec8a3d6d1e3ddc60df11c393a0 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 15 Sep 2025 10:12:57 +0300 Subject: [PATCH 1471/2711] MAINTAINERS: Support ROHM BD79112 ADC Add the ROHM BD79112 ADC in the list of the BD791xx ADC drivers which are maintained by undersigned. Signed-off-by: Matti Vaittinen Signed-off-by: Jonathan Cameron --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index d53a536288ca..f090c2f6e63a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21905,9 +21905,10 @@ S: Supported F: drivers/power/supply/bd99954-charger.c F: drivers/power/supply/bd99954-charger.h -ROHM BD79124 ADC / GPO IC +ROHM BD791xx ADC / GPO IC M: Matti Vaittinen S: Supported +F: drivers/iio/adc/rohm-bd79112.c F: drivers/iio/adc/rohm-bd79124.c ROHM BH1745 COLOUR SENSOR From 6f576fc0aeb9072ac17630a58e693de0488f9ce3 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Fri, 10 Jan 2025 16:46:59 -0800 Subject: [PATCH 1472/2711] RISC-V: KVM: Add support for SBI_FWFT_POINTER_MASKING_PMLEN Pointer masking is controlled through a WARL field in henvcfg. Expose the feature only if at least one PMLEN value is supported for VS-mode. Allow the VMM to block access to the feature by disabling the Smnpm ISA extension in the guest. Signed-off-by: Samuel Holland Reviewed-by: Anup Patel Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250111004702.2813013-3-samuel.holland@sifive.com Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h | 4 + arch/riscv/kvm/vcpu_onereg.c | 1 - arch/riscv/kvm/vcpu_sbi_fwft.c | 90 ++++++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h b/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h index 9ba841355758..afb6305e46bb 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h @@ -22,6 +22,10 @@ struct kvm_sbi_fwft_config { /* FWFT data structure per vcpu */ struct kvm_sbi_fwft { struct kvm_sbi_fwft_config *configs; +#ifndef CONFIG_32BIT + bool have_vs_pmlen_7; + bool have_vs_pmlen_16; +#endif }; #define vcpu_to_fwft(vcpu) (&(vcpu)->arch.fwft_context) diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index cce6a38ea54f..b77748a56a59 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -173,7 +173,6 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_C: case KVM_RISCV_ISA_EXT_I: case KVM_RISCV_ISA_EXT_M: - case KVM_RISCV_ISA_EXT_SMNPM: /* There is not architectural config bit to disable sscofpmf completely */ case KVM_RISCV_ISA_EXT_SSCOFPMF: case KVM_RISCV_ISA_EXT_SSNPM: diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c index 6770c043bbcb..93bcc8fb45d6 100644 --- a/arch/riscv/kvm/vcpu_sbi_fwft.c +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c @@ -103,6 +103,88 @@ static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu, return SBI_SUCCESS; } +#ifndef CONFIG_32BIT + +static bool try_to_set_pmm(unsigned long value) +{ + csr_set(CSR_HENVCFG, value); + return (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value; +} + +static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu) +{ + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + + if (!riscv_isa_extension_available(vcpu->arch.isa, SMNPM)) + return false; + + fwft->have_vs_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7); + fwft->have_vs_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16); + + return fwft->have_vs_pmlen_7 || fwft->have_vs_pmlen_16; +} + +static long kvm_sbi_fwft_set_pointer_masking_pmlen(struct kvm_vcpu *vcpu, + struct kvm_sbi_fwft_config *conf, + unsigned long value) +{ + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + unsigned long pmm; + + switch (value) { + case 0: + pmm = ENVCFG_PMM_PMLEN_0; + break; + case 7: + if (!fwft->have_vs_pmlen_7) + return SBI_ERR_INVALID_PARAM; + pmm = ENVCFG_PMM_PMLEN_7; + break; + case 16: + if (!fwft->have_vs_pmlen_16) + return SBI_ERR_INVALID_PARAM; + pmm = ENVCFG_PMM_PMLEN_16; + break; + default: + return SBI_ERR_INVALID_PARAM; + } + + vcpu->arch.cfg.henvcfg &= ~ENVCFG_PMM; + vcpu->arch.cfg.henvcfg |= pmm; + + /* + * Instead of waiting for vcpu_load/put() to update HENVCFG CSR, + * update here so that VCPU see's pointer masking mode change + * immediately. + */ + csr_write(CSR_HENVCFG, vcpu->arch.cfg.henvcfg); + + return SBI_SUCCESS; +} + +static long kvm_sbi_fwft_get_pointer_masking_pmlen(struct kvm_vcpu *vcpu, + struct kvm_sbi_fwft_config *conf, + unsigned long *value) +{ + switch (vcpu->arch.cfg.henvcfg & ENVCFG_PMM) { + case ENVCFG_PMM_PMLEN_0: + *value = 0; + break; + case ENVCFG_PMM_PMLEN_7: + *value = 7; + break; + case ENVCFG_PMM_PMLEN_16: + *value = 16; + break; + default: + return SBI_ERR_FAILURE; + } + + return SBI_SUCCESS; +} + +#endif + static const struct kvm_sbi_fwft_feature features[] = { { .id = SBI_FWFT_MISALIGNED_EXC_DELEG, @@ -110,6 +192,14 @@ static const struct kvm_sbi_fwft_feature features[] = { .set = kvm_sbi_fwft_set_misaligned_delegation, .get = kvm_sbi_fwft_get_misaligned_delegation, }, +#ifndef CONFIG_32BIT + { + .id = SBI_FWFT_POINTER_MASKING_PMLEN, + .supported = kvm_sbi_fwft_pointer_masking_pmlen_supported, + .set = kvm_sbi_fwft_set_pointer_masking_pmlen, + .get = kvm_sbi_fwft_get_pointer_masking_pmlen, + }, +#endif }; static struct kvm_sbi_fwft_config * From eca26eadd27e59d6d673308d2a28416dd741513e Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Fri, 8 Aug 2025 18:18:21 +0800 Subject: [PATCH 1473/2711] RISC-V: KVM: Change zicbom/zicboz block size to depend on the host isa The zicbom/zicboz block size registers should depend on the host's isa, the reason is that we otherwise create an ioctl order dependency on the VMM. Signed-off-by: Quan Zhou Reviewed-by: Andrew Jones Reviwed-by: Troy Mitchell Reviewed-by: Nutty Liu Link: https://lore.kernel.org/r/fef5907425455ecd41b224e0093f1b6bc4067138.1754646071.git.zhouquan@iscas.ac.cn Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_onereg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index b77748a56a59..87a2ee369ac2 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -276,12 +276,12 @@ static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu, reg_val = vcpu->arch.isa[0] & KVM_RISCV_BASE_ISA_MASK; break; case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): - if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOM)) + if (!riscv_isa_extension_available(NULL, ZICBOM)) return -ENOENT; reg_val = riscv_cbom_block_size; break; case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): - if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOZ)) + if (!riscv_isa_extension_available(NULL, ZICBOZ)) return -ENOENT; reg_val = riscv_cboz_block_size; break; @@ -365,13 +365,13 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, } break; case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): - if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOM)) + if (!riscv_isa_extension_available(NULL, ZICBOM)) return -ENOENT; if (reg_val != riscv_cbom_block_size) return -EINVAL; break; case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): - if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOZ)) + if (!riscv_isa_extension_available(NULL, ZICBOZ)) return -ENOENT; if (reg_val != riscv_cboz_block_size) return -EINVAL; @@ -816,10 +816,10 @@ static int copy_config_reg_indices(const struct kvm_vcpu *vcpu, * was not available. */ if (i == KVM_REG_RISCV_CONFIG_REG(zicbom_block_size) && - !riscv_isa_extension_available(vcpu->arch.isa, ZICBOM)) + !riscv_isa_extension_available(NULL, ZICBOM)) continue; else if (i == KVM_REG_RISCV_CONFIG_REG(zicboz_block_size) && - !riscv_isa_extension_available(vcpu->arch.isa, ZICBOZ)) + !riscv_isa_extension_available(NULL, ZICBOZ)) continue; size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; From 48e2febcda745150b4e05a8f6e6d8fd2e14e25ec Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Fri, 8 Aug 2025 18:18:34 +0800 Subject: [PATCH 1474/2711] RISC-V: KVM: Provide UAPI for Zicbop block size We're about to allow guests to use the Zicbop extension. KVM userspace needs to know the cache block size in order to properly advertise it to the guest. Provide a virtual config register for userspace to get it with the GET_ONE_REG API, but setting it cannot be supported, so disallow SET_ONE_REG. Signed-off-by: Quan Zhou Reviewed-by: Nutty Liu Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/befd8403cd76d7adb97231ac993eaeb86bf2582c.1754646071.git.zhouquan@iscas.ac.cn Signed-off-by: Anup Patel --- arch/riscv/include/uapi/asm/kvm.h | 1 + arch/riscv/kvm/vcpu_onereg.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index a5ca0f4ce2d3..4644e10bf4af 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -56,6 +56,7 @@ struct kvm_riscv_config { unsigned long mimpid; unsigned long zicboz_block_size; unsigned long satp_mode; + unsigned long zicbop_block_size; }; /* CORE registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 87a2ee369ac2..dcbcefbf64b0 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -285,6 +285,11 @@ static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu, return -ENOENT; reg_val = riscv_cboz_block_size; break; + case KVM_REG_RISCV_CONFIG_REG(zicbop_block_size): + if (!riscv_isa_extension_available(NULL, ZICBOP)) + return -ENOENT; + reg_val = riscv_cbop_block_size; + break; case KVM_REG_RISCV_CONFIG_REG(mvendorid): reg_val = vcpu->arch.mvendorid; break; @@ -376,6 +381,12 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, if (reg_val != riscv_cboz_block_size) return -EINVAL; break; + case KVM_REG_RISCV_CONFIG_REG(zicbop_block_size): + if (!riscv_isa_extension_available(NULL, ZICBOP)) + return -ENOENT; + if (reg_val != riscv_cbop_block_size) + return -EINVAL; + break; case KVM_REG_RISCV_CONFIG_REG(mvendorid): if (reg_val == vcpu->arch.mvendorid) break; @@ -821,6 +832,9 @@ static int copy_config_reg_indices(const struct kvm_vcpu *vcpu, else if (i == KVM_REG_RISCV_CONFIG_REG(zicboz_block_size) && !riscv_isa_extension_available(NULL, ZICBOZ)) continue; + else if (i == KVM_REG_RISCV_CONFIG_REG(zicbop_block_size) && + !riscv_isa_extension_available(NULL, ZICBOP)) + continue; size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CONFIG | i; From 0efd9a29c52d357088e190d0bf6c33dc8ed53d2d Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Fri, 8 Aug 2025 18:18:44 +0800 Subject: [PATCH 1475/2711] RISC-V: KVM: Allow Zicbop extension for Guest/VM Extend the KVM ISA extension ONE_REG interface to allow KVM user space to detect and enable Zicbop extension for Guest/VM. Signed-off-by: Quan Zhou Reviewed-by: Andrew Jones Reviewed-by: Nutty Liu Reviewed-by: Nutty Liu Link: https://lore.kernel.org/r/db4a9b679cc653bb6f5f5574e4196de7a980e458.1754646071.git.zhouquan@iscas.ac.cn Signed-off-by: Anup Patel --- arch/riscv/include/uapi/asm/kvm.h | 1 + arch/riscv/kvm/vcpu_onereg.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 4644e10bf4af..821b00865496 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -186,6 +186,7 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_ZICCRSE, KVM_RISCV_ISA_EXT_ZAAMO, KVM_RISCV_ISA_EXT_ZALRSC, + KVM_RISCV_ISA_EXT_ZICBOP, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index dcbcefbf64b0..eefacf780970 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -68,6 +68,7 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(ZFH), KVM_ISA_EXT_ARR(ZFHMIN), KVM_ISA_EXT_ARR(ZICBOM), + KVM_ISA_EXT_ARR(ZICBOP), KVM_ISA_EXT_ARR(ZICBOZ), KVM_ISA_EXT_ARR(ZICCRSE), KVM_ISA_EXT_ARR(ZICNTR), @@ -200,6 +201,7 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_ZFA: case KVM_RISCV_ISA_EXT_ZFH: case KVM_RISCV_ISA_EXT_ZFHMIN: + case KVM_RISCV_ISA_EXT_ZICBOP: case KVM_RISCV_ISA_EXT_ZICCRSE: case KVM_RISCV_ISA_EXT_ZICNTR: case KVM_RISCV_ISA_EXT_ZICOND: From 44c3d084e4c8737cbef6fed262af21965d6adfb1 Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Fri, 8 Aug 2025 18:18:51 +0800 Subject: [PATCH 1476/2711] RISC-V: KVM: Allow bfloat16 extension for Guest/VM Extend the KVM ISA extension ONE_REG interface to allow KVM user space to detect and enable Zfbfmin/Zvfbfmin/Zvfbfwma extension for Guest/VM. Signed-off-by: Quan Zhou Reviewed-by: Andrew Jones Reviewed-by: Nutty Liu Reviewed-by: Nutty Liu Link: https://lore.kernel.org/r/f846cecd330ab9fc88211c55bc73126f903f8713.1754646071.git.zhouquan@iscas.ac.cn Signed-off-by: Anup Patel --- arch/riscv/include/uapi/asm/kvm.h | 3 +++ arch/riscv/kvm/vcpu_onereg.c | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 821b00865496..d2ebc4d0be4b 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -187,6 +187,9 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_ZAAMO, KVM_RISCV_ISA_EXT_ZALRSC, KVM_RISCV_ISA_EXT_ZICBOP, + KVM_RISCV_ISA_EXT_ZFBFMIN, + KVM_RISCV_ISA_EXT_ZVFBFMIN, + KVM_RISCV_ISA_EXT_ZVFBFWMA, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index eefacf780970..9f8b196e7697 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -65,6 +65,7 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(ZCF), KVM_ISA_EXT_ARR(ZCMOP), KVM_ISA_EXT_ARR(ZFA), + KVM_ISA_EXT_ARR(ZFBFMIN), KVM_ISA_EXT_ARR(ZFH), KVM_ISA_EXT_ARR(ZFHMIN), KVM_ISA_EXT_ARR(ZICBOM), @@ -89,6 +90,8 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(ZTSO), KVM_ISA_EXT_ARR(ZVBB), KVM_ISA_EXT_ARR(ZVBC), + KVM_ISA_EXT_ARR(ZVFBFMIN), + KVM_ISA_EXT_ARR(ZVFBFWMA), KVM_ISA_EXT_ARR(ZVFH), KVM_ISA_EXT_ARR(ZVFHMIN), KVM_ISA_EXT_ARR(ZVKB), @@ -199,6 +202,7 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_ZCF: case KVM_RISCV_ISA_EXT_ZCMOP: case KVM_RISCV_ISA_EXT_ZFA: + case KVM_RISCV_ISA_EXT_ZFBFMIN: case KVM_RISCV_ISA_EXT_ZFH: case KVM_RISCV_ISA_EXT_ZFHMIN: case KVM_RISCV_ISA_EXT_ZICBOP: @@ -221,6 +225,8 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_ZTSO: case KVM_RISCV_ISA_EXT_ZVBB: case KVM_RISCV_ISA_EXT_ZVBC: + case KVM_RISCV_ISA_EXT_ZVFBFMIN: + case KVM_RISCV_ISA_EXT_ZVFBFWMA: case KVM_RISCV_ISA_EXT_ZVFH: case KVM_RISCV_ISA_EXT_ZVFHMIN: case KVM_RISCV_ISA_EXT_ZVKB: From e677fab86502e7c716dc893299965cffec57b9f5 Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Fri, 8 Aug 2025 18:19:00 +0800 Subject: [PATCH 1477/2711] KVM: riscv: selftests: Add Zicbop extension to get-reg-list test The KVM RISC-V allows Zicbop extension for Guest/VM so add them to get-reg-list test. Signed-off-by: Quan Zhou Reviewed-by: Andrew Jones Reviewed-by: Nutty Liu Link: https://lore.kernel.org/r/076908690c15070f907f43d2ff81ba7e95582ec7.1754646071.git.zhouquan@iscas.ac.cn Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/riscv/get-reg-list.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index a0b7dabb5040..221c39ef4f87 100644 --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -83,6 +83,7 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZFH: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZFHMIN: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOM: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOP: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOZ: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICCRSE: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICNTR: @@ -255,6 +256,8 @@ static const char *config_id_to_str(const char *prefix, __u64 id) return "KVM_REG_RISCV_CONFIG_REG(zicbom_block_size)"; case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): return "KVM_REG_RISCV_CONFIG_REG(zicboz_block_size)"; + case KVM_REG_RISCV_CONFIG_REG(zicbop_block_size): + return "KVM_REG_RISCV_CONFIG_REG(zicbop_block_size)"; case KVM_REG_RISCV_CONFIG_REG(mvendorid): return "KVM_REG_RISCV_CONFIG_REG(mvendorid)"; case KVM_REG_RISCV_CONFIG_REG(marchid): @@ -535,6 +538,7 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off) KVM_ISA_EXT_ARR(ZFH), KVM_ISA_EXT_ARR(ZFHMIN), KVM_ISA_EXT_ARR(ZICBOM), + KVM_ISA_EXT_ARR(ZICBOP), KVM_ISA_EXT_ARR(ZICBOZ), KVM_ISA_EXT_ARR(ZICCRSE), KVM_ISA_EXT_ARR(ZICNTR), @@ -780,10 +784,13 @@ void print_reg(const char *prefix, __u64 id) */ static __u64 base_regs[] = { KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(isa), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicbom_block_size), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(mvendorid), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(marchid), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(mimpid), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicboz_block_size), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(satp_mode), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicbop_block_size), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.pc), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.ra), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.sp), @@ -864,6 +871,11 @@ static __u64 zicbom_regs[] = { KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOM, }; +static __u64 zicbop_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicbop_block_size), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOP, +}; + static __u64 zicboz_regs[] = { KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicboz_block_size), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOZ, @@ -1012,6 +1024,8 @@ static __u64 vector_regs[] = { .regs = sbi_sta_regs, .regs_n = ARRAY_SIZE(sbi_sta_regs),} #define SUBLIST_ZICBOM \ {"zicbom", .feature = KVM_RISCV_ISA_EXT_ZICBOM, .regs = zicbom_regs, .regs_n = ARRAY_SIZE(zicbom_regs),} +#define SUBLIST_ZICBOP \ + {"zicbop", .feature = KVM_RISCV_ISA_EXT_ZICBOP, .regs = zicbop_regs, .regs_n = ARRAY_SIZE(zicbop_regs),} #define SUBLIST_ZICBOZ \ {"zicboz", .feature = KVM_RISCV_ISA_EXT_ZICBOZ, .regs = zicboz_regs, .regs_n = ARRAY_SIZE(zicboz_regs),} #define SUBLIST_AIA \ @@ -1130,6 +1144,7 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zfa, ZFA); KVM_ISA_EXT_SIMPLE_CONFIG(zfh, ZFH); KVM_ISA_EXT_SIMPLE_CONFIG(zfhmin, ZFHMIN); KVM_ISA_EXT_SUBLIST_CONFIG(zicbom, ZICBOM); +KVM_ISA_EXT_SUBLIST_CONFIG(zicbop, ZICBOP); KVM_ISA_EXT_SUBLIST_CONFIG(zicboz, ZICBOZ); KVM_ISA_EXT_SIMPLE_CONFIG(ziccrse, ZICCRSE); KVM_ISA_EXT_SIMPLE_CONFIG(zicntr, ZICNTR); @@ -1204,6 +1219,7 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_zfh, &config_zfhmin, &config_zicbom, + &config_zicbop, &config_zicboz, &config_ziccrse, &config_zicntr, From b4ab605e2ff5ffdcbf26ccdd9dec938dc38c6970 Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Fri, 8 Aug 2025 18:19:18 +0800 Subject: [PATCH 1478/2711] KVM: riscv: selftests: Add bfloat16 extension to get-reg-list test The KVM RISC-V allows Zfbfmin/Zvfbfmin/Zvfbfwma extensions for Guest/VM so add them to get-reg-list test. Signed-off-by: Quan Zhou Reviewed-by: Andrew Jones Reviewed-by: Nutty Liu Reviewed-by: Nutty Liu Link: https://lore.kernel.org/r/40e52ff7053401a2fcb206e75f45ebc8557fc28b.1754646071.git.zhouquan@iscas.ac.cn Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/riscv/get-reg-list.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index 221c39ef4f87..34456e8cba02 100644 --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -80,6 +80,7 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZCF: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZCMOP: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZFA: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZFBFMIN: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZFH: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZFHMIN: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOM: @@ -104,6 +105,8 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZTSO: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZVBB: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZVBC: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZVFBFMIN: + case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZVFBFWMA: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZVFH: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZVFHMIN: case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZVKB: @@ -535,6 +538,7 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off) KVM_ISA_EXT_ARR(ZCF), KVM_ISA_EXT_ARR(ZCMOP), KVM_ISA_EXT_ARR(ZFA), + KVM_ISA_EXT_ARR(ZFBFMIN), KVM_ISA_EXT_ARR(ZFH), KVM_ISA_EXT_ARR(ZFHMIN), KVM_ISA_EXT_ARR(ZICBOM), @@ -559,6 +563,8 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off) KVM_ISA_EXT_ARR(ZTSO), KVM_ISA_EXT_ARR(ZVBB), KVM_ISA_EXT_ARR(ZVBC), + KVM_ISA_EXT_ARR(ZVFBFMIN), + KVM_ISA_EXT_ARR(ZVFBFWMA), KVM_ISA_EXT_ARR(ZVFH), KVM_ISA_EXT_ARR(ZVFHMIN), KVM_ISA_EXT_ARR(ZVKB), @@ -1141,6 +1147,7 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zcd, ZCD); KVM_ISA_EXT_SIMPLE_CONFIG(zcf, ZCF); KVM_ISA_EXT_SIMPLE_CONFIG(zcmop, ZCMOP); KVM_ISA_EXT_SIMPLE_CONFIG(zfa, ZFA); +KVM_ISA_EXT_SIMPLE_CONFIG(zfbfmin, ZFBFMIN); KVM_ISA_EXT_SIMPLE_CONFIG(zfh, ZFH); KVM_ISA_EXT_SIMPLE_CONFIG(zfhmin, ZFHMIN); KVM_ISA_EXT_SUBLIST_CONFIG(zicbom, ZICBOM); @@ -1165,6 +1172,8 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zkt, ZKT); KVM_ISA_EXT_SIMPLE_CONFIG(ztso, ZTSO); KVM_ISA_EXT_SIMPLE_CONFIG(zvbb, ZVBB); KVM_ISA_EXT_SIMPLE_CONFIG(zvbc, ZVBC); +KVM_ISA_EXT_SIMPLE_CONFIG(zvfbfmin, ZVFBFMIN); +KVM_ISA_EXT_SIMPLE_CONFIG(zvfbfwma, ZVFBFWMA); KVM_ISA_EXT_SIMPLE_CONFIG(zvfh, ZVFH); KVM_ISA_EXT_SIMPLE_CONFIG(zvfhmin, ZVFHMIN); KVM_ISA_EXT_SIMPLE_CONFIG(zvkb, ZVKB); @@ -1216,6 +1225,7 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_zcf, &config_zcmop, &config_zfa, + &config_zfbfmin, &config_zfh, &config_zfhmin, &config_zicbom, @@ -1240,6 +1250,8 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_ztso, &config_zvbb, &config_zvbc, + &config_zvfbfmin, + &config_zvfbfwma, &config_zvfh, &config_zvfhmin, &config_zvkb, From c92786e179e0def2cf9a8003e7be0fcba73afb15 Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Mon, 1 Sep 2025 15:35:49 +0800 Subject: [PATCH 1479/2711] KVM: riscv: selftests: Use the existing RISCV_FENCE macro in `rseq-riscv.h` To avoid redefinition issues with RISCV_FENCE, directly reference the existing macro in `rseq-riscv.h`. Signed-off-by: Quan Zhou Signed-off-by: Dong Yang Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/85e5e51757c9289ca463fbc4ba6d22f9c9db791b.1756710918.git.dayss1224@gmail.com Signed-off-by: Anup Patel --- tools/testing/selftests/rseq/rseq-riscv.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/testing/selftests/rseq/rseq-riscv.h b/tools/testing/selftests/rseq/rseq-riscv.h index 67d544aaa9a3..06c840e81c8b 100644 --- a/tools/testing/selftests/rseq/rseq-riscv.h +++ b/tools/testing/selftests/rseq/rseq-riscv.h @@ -8,6 +8,7 @@ * exception when executed in all modes. */ #include +#include #if defined(__BYTE_ORDER) ? (__BYTE_ORDER == __LITTLE_ENDIAN) : defined(__LITTLE_ENDIAN) #define RSEQ_SIG 0xf1401073 /* csrr mhartid, x0 */ @@ -24,8 +25,6 @@ #define REG_L __REG_SEL("ld ", "lw ") #define REG_S __REG_SEL("sd ", "sw ") -#define RISCV_FENCE(p, s) \ - __asm__ __volatile__ ("fence " #p "," #s : : : "memory") #define rseq_smp_mb() RISCV_FENCE(rw, rw) #define rseq_smp_rmb() RISCV_FENCE(r, r) #define rseq_smp_wmb() RISCV_FENCE(w, w) From f4103c1171a4e661a61783e16073160be31b956f Mon Sep 17 00:00:00 2001 From: Dong Yang Date: Mon, 1 Sep 2025 15:35:50 +0800 Subject: [PATCH 1480/2711] KVM: riscv: selftests: Add missing headers for new testcases Add missing headers to fix the build for new RISC-V KVM selftests. Signed-off-by: Quan Zhou Signed-off-by: Dong Yang Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/bfb66541918de68cd89b83bc3430af94bdc75a85.1756710918.git.dayss1224@gmail.com Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/access_tracking_perf_test.c | 1 + tools/testing/selftests/kvm/include/riscv/processor.h | 1 + tools/testing/selftests/kvm/memslot_modification_stress_test.c | 1 + tools/testing/selftests/kvm/memslot_perf_test.c | 1 + 4 files changed, 4 insertions(+) diff --git a/tools/testing/selftests/kvm/access_tracking_perf_test.c b/tools/testing/selftests/kvm/access_tracking_perf_test.c index c9de66537ec3..b058f27b2141 100644 --- a/tools/testing/selftests/kvm/access_tracking_perf_test.c +++ b/tools/testing/selftests/kvm/access_tracking_perf_test.c @@ -50,6 +50,7 @@ #include "memstress.h" #include "guest_modes.h" #include "processor.h" +#include "ucall_common.h" #include "cgroup_util.h" #include "lru_gen_util.h" diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h index 162f303d9daa..e58282488beb 100644 --- a/tools/testing/selftests/kvm/include/riscv/processor.h +++ b/tools/testing/selftests/kvm/include/riscv/processor.h @@ -9,6 +9,7 @@ #include #include +#include #include "kvm_util.h" #define INSN_OPCODE_MASK 0x007c diff --git a/tools/testing/selftests/kvm/memslot_modification_stress_test.c b/tools/testing/selftests/kvm/memslot_modification_stress_test.c index c81a84990eab..3cdfa3b19b85 100644 --- a/tools/testing/selftests/kvm/memslot_modification_stress_test.c +++ b/tools/testing/selftests/kvm/memslot_modification_stress_test.c @@ -22,6 +22,7 @@ #include "processor.h" #include "test_util.h" #include "guest_modes.h" +#include "ucall_common.h" #define DUMMY_MEMSLOT_INDEX 7 diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c index e3711beff7f3..5087d082c4b0 100644 --- a/tools/testing/selftests/kvm/memslot_perf_test.c +++ b/tools/testing/selftests/kvm/memslot_perf_test.c @@ -25,6 +25,7 @@ #include #include #include +#include #define MEM_EXTRA_SIZE SZ_64K From dbe3d1d1609e171bd26de077abba6ae142de86af Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Mon, 1 Sep 2025 15:35:51 +0800 Subject: [PATCH 1481/2711] KVM: riscv: selftests: Add common supported test cases Some common KVM test cases are supported on riscv now as following: access_tracking_perf_test dirty_log_perf_test memslot_modification_stress_test memslot_perf_test mmu_stress_test rseq_test Signed-off-by: Quan Zhou Signed-off-by: Dong Yang Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/c447f18115b27562cd65863645e41a5ef89bd37b.1756710918.git.dayss1224@gmail.com Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/Makefile.kvm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 41b40c676d7f..3502348800f4 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -196,9 +196,15 @@ TEST_GEN_PROGS_s390 += rseq_test TEST_GEN_PROGS_riscv = $(TEST_GEN_PROGS_COMMON) TEST_GEN_PROGS_riscv += riscv/sbi_pmu_test TEST_GEN_PROGS_riscv += riscv/ebreak_test +TEST_GEN_PROGS_riscv += access_tracking_perf_test TEST_GEN_PROGS_riscv += arch_timer TEST_GEN_PROGS_riscv += coalesced_io_test +TEST_GEN_PROGS_riscv += dirty_log_perf_test TEST_GEN_PROGS_riscv += get-reg-list +TEST_GEN_PROGS_riscv += memslot_modification_stress_test +TEST_GEN_PROGS_riscv += memslot_perf_test +TEST_GEN_PROGS_riscv += mmu_stress_test +TEST_GEN_PROGS_riscv += rseq_test TEST_GEN_PROGS_riscv += steal_time TEST_GEN_PROGS_loongarch += coalesced_io_test From 2b351e3d04be9e1533f26c3464f1e44a5beace30 Mon Sep 17 00:00:00 2001 From: Fangyu Yu Date: Thu, 21 Aug 2025 10:25:40 -0400 Subject: [PATCH 1482/2711] RISC-V: KVM: Write hgatp register with valid mode bits According to the RISC-V Privileged Architecture Spec, when MODE=Bare is selected,software must write zero to the remaining fields of hgatp. We have detected the valid mode supported by the HW before, So using a valid mode to detect how many vmid bits are supported. Fixes: fd7bb4a251df ("RISC-V: KVM: Implement VMID allocator") Reviewed-by: Nutty Liu Reviewed-by: Troy Mitchell Reviewed-by: Guo Ren (Alibaba DAMO Academy) Signed-off-by: Fangyu Yu Signed-off-by: Guo Ren (Alibaba DAMO Academy) Link: https://lore.kernel.org/r/20250821142542.2472079-2-guoren@kernel.org Signed-off-by: Anup Patel --- arch/riscv/kvm/vmid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kvm/vmid.c b/arch/riscv/kvm/vmid.c index 3b426c800480..5f33625f4070 100644 --- a/arch/riscv/kvm/vmid.c +++ b/arch/riscv/kvm/vmid.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -28,7 +29,7 @@ void __init kvm_riscv_gstage_vmid_detect(void) /* Figure-out number of VMID bits in HW */ old = csr_read(CSR_HGATP); - csr_write(CSR_HGATP, old | HGATP_VMID); + csr_write(CSR_HGATP, (kvm_riscv_gstage_mode << HGATP_MODE_SHIFT) | HGATP_VMID); vmid_bits = csr_read(CSR_HGATP); vmid_bits = (vmid_bits & HGATP_VMID) >> HGATP_VMID_SHIFT; vmid_bits = fls_long(vmid_bits); From 9eac3744db944e887c0a73ce0fb4e5680614dd70 Mon Sep 17 00:00:00 2001 From: "Guo Ren (Alibaba DAMO Academy)" Date: Thu, 21 Aug 2025 10:25:41 -0400 Subject: [PATCH 1483/2711] RISC-V: KVM: Remove unnecessary HGATP csr_read The HGATP has been set to zero in gstage_mode_detect(), so there is no need to save the old context. Unify the code convention with gstage_mode_detect(). Reviewed-by: Fangyu Yu Signed-off-by: Fangyu Yu Signed-off-by: Guo Ren (Alibaba DAMO Academy) Reviewed-by: Nutty Liu Link: https://lore.kernel.org/r/20250821142542.2472079-3-guoren@kernel.org Signed-off-by: Anup Patel --- arch/riscv/kvm/vmid.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/riscv/kvm/vmid.c b/arch/riscv/kvm/vmid.c index 5f33625f4070..abb1c2bf2542 100644 --- a/arch/riscv/kvm/vmid.c +++ b/arch/riscv/kvm/vmid.c @@ -25,15 +25,12 @@ static DEFINE_SPINLOCK(vmid_lock); void __init kvm_riscv_gstage_vmid_detect(void) { - unsigned long old; - /* Figure-out number of VMID bits in HW */ - old = csr_read(CSR_HGATP); csr_write(CSR_HGATP, (kvm_riscv_gstage_mode << HGATP_MODE_SHIFT) | HGATP_VMID); vmid_bits = csr_read(CSR_HGATP); vmid_bits = (vmid_bits & HGATP_VMID) >> HGATP_VMID_SHIFT; vmid_bits = fls_long(vmid_bits); - csr_write(CSR_HGATP, old); + csr_write(CSR_HGATP, 0); /* We polluted local TLB so flush all guest TLB */ kvm_riscv_local_hfence_gvma_all(); From b8d13949a6125c0e2e59f0c1f102a38d3c4809d1 Mon Sep 17 00:00:00 2001 From: "Guo Ren (Alibaba DAMO Academy)" Date: Thu, 21 Aug 2025 10:25:42 -0400 Subject: [PATCH 1484/2711] RISC-V: KVM: Prevent HGATP_MODE_BARE passed Current kvm_riscv_gstage_mode_detect() assumes H-extension must have HGATP_MODE_SV39X4/SV32X4 at least, but the spec allows H-extension with HGATP_MODE_BARE alone. The KVM depends on !HGATP_MODE_BARE at least, so enhance the gstage-mode-detect to block HGATP_MODE_BARE. Move gstage-mode-check closer to gstage-mode-detect to prevent unnecessary init. Reviewed-by: Troy Mitchell Reviewed-by: Nutty Liu Signed-off-by: Guo Ren (Alibaba DAMO Academy) Reviewed-by: Fangyu Yu Link: https://lore.kernel.org/r/20250821142542.2472079-4-guoren@kernel.org Signed-off-by: Anup Patel --- arch/riscv/kvm/gstage.c | 27 ++++++++++++++++++++++++--- arch/riscv/kvm/main.c | 33 +++++++++++++++++---------------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c index 24c270d6d0e2..b67d60d722c2 100644 --- a/arch/riscv/kvm/gstage.c +++ b/arch/riscv/kvm/gstage.c @@ -321,7 +321,7 @@ void __init kvm_riscv_gstage_mode_detect(void) if ((csr_read(CSR_HGATP) >> HGATP_MODE_SHIFT) == HGATP_MODE_SV57X4) { kvm_riscv_gstage_mode = HGATP_MODE_SV57X4; kvm_riscv_gstage_pgd_levels = 5; - goto skip_sv48x4_test; + goto done; } /* Try Sv48x4 G-stage mode */ @@ -329,10 +329,31 @@ void __init kvm_riscv_gstage_mode_detect(void) if ((csr_read(CSR_HGATP) >> HGATP_MODE_SHIFT) == HGATP_MODE_SV48X4) { kvm_riscv_gstage_mode = HGATP_MODE_SV48X4; kvm_riscv_gstage_pgd_levels = 4; + goto done; } -skip_sv48x4_test: + /* Try Sv39x4 G-stage mode */ + csr_write(CSR_HGATP, HGATP_MODE_SV39X4 << HGATP_MODE_SHIFT); + if ((csr_read(CSR_HGATP) >> HGATP_MODE_SHIFT) == HGATP_MODE_SV39X4) { + kvm_riscv_gstage_mode = HGATP_MODE_SV39X4; + kvm_riscv_gstage_pgd_levels = 3; + goto done; + } +#else /* CONFIG_32BIT */ + /* Try Sv32x4 G-stage mode */ + csr_write(CSR_HGATP, HGATP_MODE_SV32X4 << HGATP_MODE_SHIFT); + if ((csr_read(CSR_HGATP) >> HGATP_MODE_SHIFT) == HGATP_MODE_SV32X4) { + kvm_riscv_gstage_mode = HGATP_MODE_SV32X4; + kvm_riscv_gstage_pgd_levels = 2; + goto done; + } +#endif + + /* KVM depends on !HGATP_MODE_OFF */ + kvm_riscv_gstage_mode = HGATP_MODE_OFF; + kvm_riscv_gstage_pgd_levels = 0; + +done: csr_write(CSR_HGATP, 0); kvm_riscv_local_hfence_gvma_all(); -#endif } diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c index 67c876de74ef..77dc1655b442 100644 --- a/arch/riscv/kvm/main.c +++ b/arch/riscv/kvm/main.c @@ -93,6 +93,23 @@ static int __init riscv_kvm_init(void) return rc; kvm_riscv_gstage_mode_detect(); + switch (kvm_riscv_gstage_mode) { + case HGATP_MODE_SV32X4: + str = "Sv32x4"; + break; + case HGATP_MODE_SV39X4: + str = "Sv39x4"; + break; + case HGATP_MODE_SV48X4: + str = "Sv48x4"; + break; + case HGATP_MODE_SV57X4: + str = "Sv57x4"; + break; + default: + kvm_riscv_nacl_exit(); + return -ENODEV; + } kvm_riscv_gstage_vmid_detect(); @@ -135,22 +152,6 @@ static int __init riscv_kvm_init(void) (rc) ? slist : "no features"); } - switch (kvm_riscv_gstage_mode) { - case HGATP_MODE_SV32X4: - str = "Sv32x4"; - break; - case HGATP_MODE_SV39X4: - str = "Sv39x4"; - break; - case HGATP_MODE_SV48X4: - str = "Sv48x4"; - break; - case HGATP_MODE_SV57X4: - str = "Sv57x4"; - break; - default: - return -ENODEV; - } kvm_info("using %s G-stage page table format\n", str); kvm_info("VMID %ld bits available\n", kvm_riscv_gstage_vmid_bits()); From 83df1d64d663f4bf450a924cf337ff0cb7d63261 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Sat, 23 Aug 2025 21:29:42 +0530 Subject: [PATCH 1485/2711] RISC-V: KVM: Set initial value of hedeleg in kvm_arch_vcpu_create() The hedeleg may be updated by ONE_REG interface before the VCPU is run at least once hence set the initial value of hedeleg in kvm_arch_vcpu_create() instead of kvm_riscv_vcpu_setup_config(). Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Reviewed-by: Nutty Liu Link: https://lore.kernel.org/r/20250823155947.1354229-2-apatel@ventanamicro.com Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 3ebcfffaa978..47bcf190ccc5 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -133,6 +133,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) /* Mark this VCPU never ran */ vcpu->arch.ran_atleast_once = false; + + vcpu->arch.cfg.hedeleg = KVM_HEDELEG_DEFAULT; vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO; bitmap_zero(vcpu->arch.isa, RISCV_ISA_EXT_MAX); @@ -570,7 +572,6 @@ static void kvm_riscv_vcpu_setup_config(struct kvm_vcpu *vcpu) cfg->hstateen0 |= SMSTATEEN0_SSTATEEN0; } - cfg->hedeleg = KVM_HEDELEG_DEFAULT; if (vcpu->guest_debug) cfg->hedeleg &= ~BIT(EXC_BREAKPOINT); } From a6250b18b5df7880b3c26e5d16ca24c31c1be259 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Sat, 23 Aug 2025 21:29:43 +0530 Subject: [PATCH 1486/2711] RISC-V: KVM: Introduce feature specific reset for SBI FWFT The SBI FWFT feature values must be reset upon VCPU reset so introduce feature specific reset callback for this purpose. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Reviewed-by: Nutty Liu Link: https://lore.kernel.org/r/20250823155947.1354229-3-apatel@ventanamicro.com Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_sbi_fwft.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c index 93bcc8fb45d6..252899f07482 100644 --- a/arch/riscv/kvm/vcpu_sbi_fwft.c +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c @@ -30,6 +30,13 @@ struct kvm_sbi_fwft_feature { */ bool (*supported)(struct kvm_vcpu *vcpu); + /** + * @reset: Reset the feature value irrespective whether feature is supported or not + * + * This callback is mandatory + */ + void (*reset)(struct kvm_vcpu *vcpu); + /** * @set: Set the feature value * @@ -75,6 +82,13 @@ static bool kvm_sbi_fwft_misaligned_delegation_supported(struct kvm_vcpu *vcpu) return misaligned_traps_can_delegate(); } +static void kvm_sbi_fwft_reset_misaligned_delegation(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; + + cfg->hedeleg &= ~MIS_DELEG; +} + static long kvm_sbi_fwft_set_misaligned_delegation(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long value) @@ -124,6 +138,11 @@ static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu) return fwft->have_vs_pmlen_7 || fwft->have_vs_pmlen_16; } +static void kvm_sbi_fwft_reset_pointer_masking_pmlen(struct kvm_vcpu *vcpu) +{ + vcpu->arch.cfg.henvcfg &= ~ENVCFG_PMM; +} + static long kvm_sbi_fwft_set_pointer_masking_pmlen(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long value) @@ -189,6 +208,7 @@ static const struct kvm_sbi_fwft_feature features[] = { { .id = SBI_FWFT_MISALIGNED_EXC_DELEG, .supported = kvm_sbi_fwft_misaligned_delegation_supported, + .reset = kvm_sbi_fwft_reset_misaligned_delegation, .set = kvm_sbi_fwft_set_misaligned_delegation, .get = kvm_sbi_fwft_get_misaligned_delegation, }, @@ -196,6 +216,7 @@ static const struct kvm_sbi_fwft_feature features[] = { { .id = SBI_FWFT_POINTER_MASKING_PMLEN, .supported = kvm_sbi_fwft_pointer_masking_pmlen_supported, + .reset = kvm_sbi_fwft_reset_pointer_masking_pmlen, .set = kvm_sbi_fwft_set_pointer_masking_pmlen, .get = kvm_sbi_fwft_get_pointer_masking_pmlen, }, @@ -330,11 +351,16 @@ static void kvm_sbi_ext_fwft_deinit(struct kvm_vcpu *vcpu) static void kvm_sbi_ext_fwft_reset(struct kvm_vcpu *vcpu) { - int i; struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + const struct kvm_sbi_fwft_feature *feature; + int i; - for (i = 0; i < ARRAY_SIZE(features); i++) + for (i = 0; i < ARRAY_SIZE(features); i++) { fwft->configs[i].flags = 0; + feature = &features[i]; + if (feature->reset) + feature->reset(vcpu); + } } const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft = { From 699a53aedb18da50b4040b870784f9943dead5d8 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Sat, 23 Aug 2025 21:29:44 +0530 Subject: [PATCH 1487/2711] RISC-V: KVM: Introduce optional ONE_REG callbacks for SBI extensions SBI extensions can have per-VCPU state which needs to be saved/restored through ONE_REG interface for Guest/VM migration. Introduce optional ONE_REG callbacks for SBI extensions so that ONE_REG implementation for an SBI extenion is part of the extension sources. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250823155947.1354229-4-apatel@ventanamicro.com Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_vcpu_sbi.h | 20 +-- arch/riscv/kvm/vcpu_onereg.c | 31 +---- arch/riscv/kvm/vcpu_sbi.c | 167 ++++++++++++++++++++------ arch/riscv/kvm/vcpu_sbi_sta.c | 65 ++++++---- 4 files changed, 188 insertions(+), 95 deletions(-) diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h index 766031e80960..8970cc7530c4 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h @@ -59,6 +59,14 @@ struct kvm_vcpu_sbi_extension { void (*deinit)(struct kvm_vcpu *vcpu); void (*reset)(struct kvm_vcpu *vcpu); + + unsigned long state_reg_subtype; + unsigned long (*get_state_reg_count)(struct kvm_vcpu *vcpu); + int (*get_state_reg_id)(struct kvm_vcpu *vcpu, int index, u64 *reg_id); + int (*get_state_reg)(struct kvm_vcpu *vcpu, unsigned long reg_num, + unsigned long reg_size, void *reg_val); + int (*set_state_reg)(struct kvm_vcpu *vcpu, unsigned long reg_num, + unsigned long reg_size, const void *reg_val); }; void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run); @@ -73,10 +81,9 @@ int kvm_riscv_vcpu_set_reg_sbi_ext(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); -int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg); -int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg); +int kvm_riscv_vcpu_reg_indices_sbi(struct kvm_vcpu *vcpu, u64 __user *uindices); +int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); +int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext( struct kvm_vcpu *vcpu, unsigned long extid); bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx); @@ -85,11 +92,6 @@ void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_sbi_deinit(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_sbi_reset(struct kvm_vcpu *vcpu); -int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num, - unsigned long *reg_val); -int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num, - unsigned long reg_val); - #ifdef CONFIG_RISCV_SBI_V01 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01; #endif diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 9f8b196e7697..0f4e444e5e10 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -1112,36 +1112,9 @@ static unsigned long num_sbi_ext_regs(struct kvm_vcpu *vcpu) return copy_sbi_ext_reg_indices(vcpu, NULL); } -static int copy_sbi_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) -{ - struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; - int total = 0; - - if (scontext->ext_status[KVM_RISCV_SBI_EXT_STA] == KVM_RISCV_SBI_EXT_STATUS_ENABLED) { - u64 size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; - int n = sizeof(struct kvm_riscv_sbi_sta) / sizeof(unsigned long); - - for (int i = 0; i < n; i++) { - u64 reg = KVM_REG_RISCV | size | - KVM_REG_RISCV_SBI_STATE | - KVM_REG_RISCV_SBI_STA | i; - - if (uindices) { - if (put_user(reg, uindices)) - return -EFAULT; - uindices++; - } - } - - total += n; - } - - return total; -} - static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu) { - return copy_sbi_reg_indices(vcpu, NULL); + return kvm_riscv_vcpu_reg_indices_sbi(vcpu, NULL); } static inline unsigned long num_vector_regs(const struct kvm_vcpu *vcpu) @@ -1269,7 +1242,7 @@ int kvm_riscv_vcpu_copy_reg_indices(struct kvm_vcpu *vcpu, return ret; uindices += ret; - ret = copy_sbi_reg_indices(vcpu, uindices); + ret = kvm_riscv_vcpu_reg_indices_sbi(vcpu, uindices); if (ret < 0) return ret; uindices += ret; diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index 01a93f4fdb16..04903e5012d6 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -364,64 +364,163 @@ int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu, return 0; } -int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) +int kvm_riscv_vcpu_reg_indices_sbi(struct kvm_vcpu *vcpu, u64 __user *uindices) { - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_SBI_STATE); - unsigned long reg_subtype, reg_val; + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; + const struct kvm_riscv_sbi_extension_entry *entry; + const struct kvm_vcpu_sbi_extension *ext; + unsigned long state_reg_count; + int i, j, rc, count = 0; + u64 reg; - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; + for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { + entry = &sbi_ext[i]; + ext = entry->ext_ptr; - if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) - return -EFAULT; + if (!ext->get_state_reg_count || + scontext->ext_status[entry->ext_idx] != KVM_RISCV_SBI_EXT_STATUS_ENABLED) + continue; - reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; - reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + state_reg_count = ext->get_state_reg_count(vcpu); + if (!uindices) + goto skip_put_user; - switch (reg_subtype) { - case KVM_REG_RISCV_SBI_STA: - return kvm_riscv_vcpu_set_reg_sbi_sta(vcpu, reg_num, reg_val); - default: - return -EINVAL; + for (j = 0; j < state_reg_count; j++) { + if (ext->get_state_reg_id) { + rc = ext->get_state_reg_id(vcpu, j, ®); + if (rc) + return rc; + } else { + reg = KVM_REG_RISCV | + (IS_ENABLED(CONFIG_32BIT) ? + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64) | + KVM_REG_RISCV_SBI_STATE | + ext->state_reg_subtype | j; + } + + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + +skip_put_user: + count += state_reg_count; } - return 0; + return count; } -int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) +static const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext_withstate(struct kvm_vcpu *vcpu, + unsigned long subtype) +{ + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; + const struct kvm_riscv_sbi_extension_entry *entry; + const struct kvm_vcpu_sbi_extension *ext; + int i; + + for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { + entry = &sbi_ext[i]; + ext = entry->ext_ptr; + + if (ext->get_state_reg_count && + ext->state_reg_subtype == subtype && + scontext->ext_status[entry->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_ENABLED) + return ext; + } + + return NULL; +} + +int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { unsigned long __user *uaddr = (unsigned long __user *)(unsigned long)reg->addr; unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_RISCV_SBI_STATE); - unsigned long reg_subtype, reg_val; - int ret; + const struct kvm_vcpu_sbi_extension *ext; + unsigned long reg_subtype; + void *reg_val; + u64 data64; + u32 data32; + u16 data16; + u8 data8; - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - - reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; - reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; - - switch (reg_subtype) { - case KVM_REG_RISCV_SBI_STA: - ret = kvm_riscv_vcpu_get_reg_sbi_sta(vcpu, reg_num, ®_val); + switch (KVM_REG_SIZE(reg->id)) { + case 1: + reg_val = &data8; + break; + case 2: + reg_val = &data16; + break; + case 4: + reg_val = &data32; + break; + case 8: + reg_val = &data64; break; default: return -EINVAL; } + if (copy_from_user(reg_val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + + ext = kvm_vcpu_sbi_find_ext_withstate(vcpu, reg_subtype); + if (!ext || !ext->set_state_reg) + return -EINVAL; + + return ext->set_state_reg(vcpu, reg_num, KVM_REG_SIZE(reg->id), reg_val); +} + +int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) +{ + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_SBI_STATE); + const struct kvm_vcpu_sbi_extension *ext; + unsigned long reg_subtype; + void *reg_val; + u64 data64; + u32 data32; + u16 data16; + u8 data8; + int ret; + + switch (KVM_REG_SIZE(reg->id)) { + case 1: + reg_val = &data8; + break; + case 2: + reg_val = &data16; + break; + case 4: + reg_val = &data32; + break; + case 8: + reg_val = &data64; + break; + default: + return -EINVAL; + } + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + + ext = kvm_vcpu_sbi_find_ext_withstate(vcpu, reg_subtype); + if (!ext || !ext->get_state_reg) + return -EINVAL; + + ret = ext->get_state_reg(vcpu, reg_num, KVM_REG_SIZE(reg->id), reg_val); if (ret) return ret; - if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) + if (copy_to_user(uaddr, reg_val, KVM_REG_SIZE(reg->id))) return -EFAULT; return 0; diff --git a/arch/riscv/kvm/vcpu_sbi_sta.c b/arch/riscv/kvm/vcpu_sbi_sta.c index cc6cb7c8f0e4..68486f90a61e 100644 --- a/arch/riscv/kvm/vcpu_sbi_sta.c +++ b/arch/riscv/kvm/vcpu_sbi_sta.c @@ -151,63 +151,82 @@ static unsigned long kvm_sbi_ext_sta_probe(struct kvm_vcpu *vcpu) return !!sched_info_on(); } -const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta = { - .extid_start = SBI_EXT_STA, - .extid_end = SBI_EXT_STA, - .handler = kvm_sbi_ext_sta_handler, - .probe = kvm_sbi_ext_sta_probe, - .reset = kvm_riscv_vcpu_sbi_sta_reset, -}; - -int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, - unsigned long reg_num, - unsigned long *reg_val) +static unsigned long kvm_sbi_ext_sta_get_state_reg_count(struct kvm_vcpu *vcpu) { + return sizeof(struct kvm_riscv_sbi_sta) / sizeof(unsigned long); +} + +static int kvm_sbi_ext_sta_get_reg(struct kvm_vcpu *vcpu, unsigned long reg_num, + unsigned long reg_size, void *reg_val) +{ + unsigned long *value; + + if (reg_size != sizeof(unsigned long)) + return -EINVAL; + value = reg_val; + switch (reg_num) { case KVM_REG_RISCV_SBI_STA_REG(shmem_lo): - *reg_val = (unsigned long)vcpu->arch.sta.shmem; + *value = (unsigned long)vcpu->arch.sta.shmem; break; case KVM_REG_RISCV_SBI_STA_REG(shmem_hi): if (IS_ENABLED(CONFIG_32BIT)) - *reg_val = upper_32_bits(vcpu->arch.sta.shmem); + *value = upper_32_bits(vcpu->arch.sta.shmem); else - *reg_val = 0; + *value = 0; break; default: - return -EINVAL; + return -ENOENT; } return 0; } -int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu, - unsigned long reg_num, - unsigned long reg_val) +static int kvm_sbi_ext_sta_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num, + unsigned long reg_size, const void *reg_val) { + unsigned long value; + + if (reg_size != sizeof(unsigned long)) + return -EINVAL; + value = *(const unsigned long *)reg_val; + switch (reg_num) { case KVM_REG_RISCV_SBI_STA_REG(shmem_lo): if (IS_ENABLED(CONFIG_32BIT)) { gpa_t hi = upper_32_bits(vcpu->arch.sta.shmem); - vcpu->arch.sta.shmem = reg_val; + vcpu->arch.sta.shmem = value; vcpu->arch.sta.shmem |= hi << 32; } else { - vcpu->arch.sta.shmem = reg_val; + vcpu->arch.sta.shmem = value; } break; case KVM_REG_RISCV_SBI_STA_REG(shmem_hi): if (IS_ENABLED(CONFIG_32BIT)) { gpa_t lo = lower_32_bits(vcpu->arch.sta.shmem); - vcpu->arch.sta.shmem = ((gpa_t)reg_val << 32); + vcpu->arch.sta.shmem = ((gpa_t)value << 32); vcpu->arch.sta.shmem |= lo; - } else if (reg_val != 0) { + } else if (value != 0) { return -EINVAL; } break; default: - return -EINVAL; + return -ENOENT; } return 0; } + +const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta = { + .extid_start = SBI_EXT_STA, + .extid_end = SBI_EXT_STA, + .handler = kvm_sbi_ext_sta_handler, + .probe = kvm_sbi_ext_sta_probe, + .reset = kvm_riscv_vcpu_sbi_sta_reset, + .state_reg_subtype = KVM_REG_RISCV_SBI_STA, + .get_state_reg_count = kvm_sbi_ext_sta_get_state_reg_count, + .get_state_reg = kvm_sbi_ext_sta_get_reg, + .set_state_reg = kvm_sbi_ext_sta_set_reg, +}; From 85e7850e0dcd754112cf54c9e4baf0ae9ffda345 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Sat, 23 Aug 2025 21:29:45 +0530 Subject: [PATCH 1488/2711] RISC-V: KVM: Move copy_sbi_ext_reg_indices() to SBI implementation The ONE_REG handling of SBI extension enable/disable registers and SBI extension state registers is already under SBI implementation. On similar lines, let's move copy_sbi_ext_reg_indices() under SBI implementation. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250823155947.1354229-5-apatel@ventanamicro.com Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_vcpu_sbi.h | 2 +- arch/riscv/kvm/vcpu_onereg.c | 29 ++------------------------- arch/riscv/kvm/vcpu_sbi.c | 27 ++++++++++++++++++++++++- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h index 8970cc7530c4..d75ca45c0152 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h @@ -77,6 +77,7 @@ void kvm_riscv_vcpu_sbi_request_reset(struct kvm_vcpu *vcpu, unsigned long pc, unsigned long a1); void kvm_riscv_vcpu_sbi_load_reset_state(struct kvm_vcpu *vcpu); int kvm_riscv_vcpu_sbi_return(struct kvm_vcpu *vcpu, struct kvm_run *run); +int kvm_riscv_vcpu_reg_indices_sbi_ext(struct kvm_vcpu *vcpu, u64 __user *uindices); int kvm_riscv_vcpu_set_reg_sbi_ext(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu, @@ -86,7 +87,6 @@ int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg * int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext( struct kvm_vcpu *vcpu, unsigned long extid); -bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx); int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run); void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_sbi_deinit(struct kvm_vcpu *vcpu); diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 0f4e444e5e10..865dae903aa0 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -1082,34 +1082,9 @@ static inline unsigned long num_isa_ext_regs(const struct kvm_vcpu *vcpu) return copy_isa_ext_reg_indices(vcpu, NULL); } -static int copy_sbi_ext_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) -{ - unsigned int n = 0; - - for (int i = 0; i < KVM_RISCV_SBI_EXT_MAX; i++) { - u64 size = IS_ENABLED(CONFIG_32BIT) ? - KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; - u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT | - KVM_REG_RISCV_SBI_SINGLE | i; - - if (!riscv_vcpu_supports_sbi_ext(vcpu, i)) - continue; - - if (uindices) { - if (put_user(reg, uindices)) - return -EFAULT; - uindices++; - } - - n++; - } - - return n; -} - static unsigned long num_sbi_ext_regs(struct kvm_vcpu *vcpu) { - return copy_sbi_ext_reg_indices(vcpu, NULL); + return kvm_riscv_vcpu_reg_indices_sbi_ext(vcpu, NULL); } static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu) @@ -1237,7 +1212,7 @@ int kvm_riscv_vcpu_copy_reg_indices(struct kvm_vcpu *vcpu, return ret; uindices += ret; - ret = copy_sbi_ext_reg_indices(vcpu, uindices); + ret = kvm_riscv_vcpu_reg_indices_sbi_ext(vcpu, uindices); if (ret < 0) return ret; uindices += ret; diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index 04903e5012d6..1b13623380e1 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -110,7 +110,7 @@ riscv_vcpu_get_sbi_ext(struct kvm_vcpu *vcpu, unsigned long idx) return sext; } -bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx) +static bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx) { struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; const struct kvm_riscv_sbi_extension_entry *sext; @@ -288,6 +288,31 @@ static int riscv_vcpu_get_sbi_ext_multi(struct kvm_vcpu *vcpu, return 0; } +int kvm_riscv_vcpu_reg_indices_sbi_ext(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + unsigned int n = 0; + + for (int i = 0; i < KVM_RISCV_SBI_EXT_MAX; i++) { + u64 size = IS_ENABLED(CONFIG_32BIT) ? + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; + u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT | + KVM_REG_RISCV_SBI_SINGLE | i; + + if (!riscv_vcpu_supports_sbi_ext(vcpu, i)) + continue; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + + n++; + } + + return n; +} + int kvm_riscv_vcpu_set_reg_sbi_ext(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { From 48d67106f4a72a32dcd762774e639e7ed9dbed5e Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Sat, 23 Aug 2025 21:29:46 +0530 Subject: [PATCH 1489/2711] RISC-V: KVM: Implement ONE_REG interface for SBI FWFT state The KVM user-space needs a way to save/restore the state of SBI FWFT features so implement SBI extension ONE_REG callbacks. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250823155947.1354229-6-apatel@ventanamicro.com Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h | 1 + arch/riscv/include/uapi/asm/kvm.h | 15 ++ arch/riscv/kvm/vcpu_sbi_fwft.c | 197 +++++++++++++++++++-- 3 files changed, 200 insertions(+), 13 deletions(-) diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h b/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h index afb6305e46bb..5604cec79902 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h @@ -16,6 +16,7 @@ struct kvm_sbi_fwft_feature; struct kvm_sbi_fwft_config { const struct kvm_sbi_fwft_feature *feature; bool supported; + bool enabled; unsigned long flags; }; diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index d2ebc4d0be4b..11fe4a89600c 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -220,6 +220,18 @@ struct kvm_riscv_sbi_sta { unsigned long shmem_hi; }; +struct kvm_riscv_sbi_fwft_feature { + unsigned long enable; + unsigned long flags; + unsigned long value; +}; + +/* SBI FWFT extension registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ +struct kvm_riscv_sbi_fwft { + struct kvm_riscv_sbi_fwft_feature misaligned_deleg; + struct kvm_riscv_sbi_fwft_feature pointer_masking; +}; + /* Possible states for kvm_riscv_timer */ #define KVM_RISCV_TIMER_STATE_OFF 0 #define KVM_RISCV_TIMER_STATE_ON 1 @@ -303,6 +315,9 @@ struct kvm_riscv_sbi_sta { #define KVM_REG_RISCV_SBI_STA (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT) #define KVM_REG_RISCV_SBI_STA_REG(name) \ (offsetof(struct kvm_riscv_sbi_sta, name) / sizeof(unsigned long)) +#define KVM_REG_RISCV_SBI_FWFT (0x1 << KVM_REG_RISCV_SUBTYPE_SHIFT) +#define KVM_REG_RISCV_SBI_FWFT_REG(name) \ + (offsetof(struct kvm_riscv_sbi_fwft, name) / sizeof(unsigned long)) /* Device Control API: RISC-V AIA */ #define KVM_DEV_RISCV_APLIC_ALIGN 0x1000 diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c index 252899f07482..62cc9c3d5759 100644 --- a/arch/riscv/kvm/vcpu_sbi_fwft.c +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c @@ -22,6 +22,11 @@ struct kvm_sbi_fwft_feature { */ enum sbi_fwft_feature_t id; + /** + * @first_reg_num: ONE_REG index of the first ONE_REG register + */ + unsigned long first_reg_num; + /** * @supported: Check if the feature is supported on the vcpu * @@ -44,7 +49,8 @@ struct kvm_sbi_fwft_feature { * * This callback is mandatory */ - long (*set)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long value); + long (*set)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, + bool one_reg_access, unsigned long value); /** * @get: Get the feature current value @@ -53,7 +59,8 @@ struct kvm_sbi_fwft_feature { * * This callback is mandatory */ - long (*get)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long *value); + long (*get)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, + bool one_reg_access, unsigned long *value); }; static const enum sbi_fwft_feature_t kvm_fwft_defined_features[] = { @@ -91,16 +98,18 @@ static void kvm_sbi_fwft_reset_misaligned_delegation(struct kvm_vcpu *vcpu) static long kvm_sbi_fwft_set_misaligned_delegation(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, - unsigned long value) + bool one_reg_access, unsigned long value) { struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; if (value == 1) { cfg->hedeleg |= MIS_DELEG; - csr_set(CSR_HEDELEG, MIS_DELEG); + if (!one_reg_access) + csr_set(CSR_HEDELEG, MIS_DELEG); } else if (value == 0) { cfg->hedeleg &= ~MIS_DELEG; - csr_clear(CSR_HEDELEG, MIS_DELEG); + if (!one_reg_access) + csr_clear(CSR_HEDELEG, MIS_DELEG); } else { return SBI_ERR_INVALID_PARAM; } @@ -110,10 +119,11 @@ static long kvm_sbi_fwft_set_misaligned_delegation(struct kvm_vcpu *vcpu, static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, - unsigned long *value) + bool one_reg_access, unsigned long *value) { - *value = (csr_read(CSR_HEDELEG) & MIS_DELEG) == MIS_DELEG; + struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; + *value = (cfg->hedeleg & MIS_DELEG) == MIS_DELEG; return SBI_SUCCESS; } @@ -145,7 +155,7 @@ static void kvm_sbi_fwft_reset_pointer_masking_pmlen(struct kvm_vcpu *vcpu) static long kvm_sbi_fwft_set_pointer_masking_pmlen(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, - unsigned long value) + bool one_reg_access, unsigned long value) { struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); unsigned long pmm; @@ -176,14 +186,15 @@ static long kvm_sbi_fwft_set_pointer_masking_pmlen(struct kvm_vcpu *vcpu, * update here so that VCPU see's pointer masking mode change * immediately. */ - csr_write(CSR_HENVCFG, vcpu->arch.cfg.henvcfg); + if (!one_reg_access) + csr_write(CSR_HENVCFG, vcpu->arch.cfg.henvcfg); return SBI_SUCCESS; } static long kvm_sbi_fwft_get_pointer_masking_pmlen(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, - unsigned long *value) + bool one_reg_access, unsigned long *value) { switch (vcpu->arch.cfg.henvcfg & ENVCFG_PMM) { case ENVCFG_PMM_PMLEN_0: @@ -207,6 +218,8 @@ static long kvm_sbi_fwft_get_pointer_masking_pmlen(struct kvm_vcpu *vcpu, static const struct kvm_sbi_fwft_feature features[] = { { .id = SBI_FWFT_MISALIGNED_EXC_DELEG, + .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, misaligned_deleg.enable) / + sizeof(unsigned long), .supported = kvm_sbi_fwft_misaligned_delegation_supported, .reset = kvm_sbi_fwft_reset_misaligned_delegation, .set = kvm_sbi_fwft_set_misaligned_delegation, @@ -215,6 +228,8 @@ static const struct kvm_sbi_fwft_feature features[] = { #ifndef CONFIG_32BIT { .id = SBI_FWFT_POINTER_MASKING_PMLEN, + .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pointer_masking.enable) / + sizeof(unsigned long), .supported = kvm_sbi_fwft_pointer_masking_pmlen_supported, .reset = kvm_sbi_fwft_reset_pointer_masking_pmlen, .set = kvm_sbi_fwft_set_pointer_masking_pmlen, @@ -223,6 +238,20 @@ static const struct kvm_sbi_fwft_feature features[] = { #endif }; +static const struct kvm_sbi_fwft_feature *kvm_sbi_fwft_regnum_to_feature(unsigned long reg_num) +{ + const struct kvm_sbi_fwft_feature *feature; + int i; + + for (i = 0; i < ARRAY_SIZE(features); i++) { + feature = &features[i]; + if (feature->first_reg_num <= reg_num && reg_num < (feature->first_reg_num + 3)) + return feature; + } + + return NULL; +} + static struct kvm_sbi_fwft_config * kvm_sbi_fwft_get_config(struct kvm_vcpu *vcpu, enum sbi_fwft_feature_t feature) { @@ -250,7 +279,7 @@ static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature, return SBI_ERR_DENIED; } - if (!tconf->supported) + if (!tconf->supported || !tconf->enabled) return SBI_ERR_NOT_SUPPORTED; *conf = tconf; @@ -276,7 +305,7 @@ static int kvm_sbi_fwft_set(struct kvm_vcpu *vcpu, u32 feature, conf->flags = flags; - return conf->feature->set(vcpu, conf, value); + return conf->feature->set(vcpu, conf, false, value); } static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, unsigned long feature, @@ -289,7 +318,7 @@ static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, unsigned long feature, if (ret) return ret; - return conf->feature->get(vcpu, conf, value); + return conf->feature->get(vcpu, conf, false, value); } static int kvm_sbi_ext_fwft_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, @@ -336,6 +365,7 @@ static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu) else conf->supported = true; + conf->enabled = conf->supported; conf->feature = feature; } @@ -363,6 +393,142 @@ static void kvm_sbi_ext_fwft_reset(struct kvm_vcpu *vcpu) } } +static unsigned long kvm_sbi_ext_fwft_get_reg_count(struct kvm_vcpu *vcpu) +{ + unsigned long max_reg_count = sizeof(struct kvm_riscv_sbi_fwft) / sizeof(unsigned long); + const struct kvm_sbi_fwft_feature *feature; + struct kvm_sbi_fwft_config *conf; + unsigned long reg, ret = 0; + + for (reg = 0; reg < max_reg_count; reg++) { + feature = kvm_sbi_fwft_regnum_to_feature(reg); + if (!feature) + continue; + + conf = kvm_sbi_fwft_get_config(vcpu, feature->id); + if (!conf || !conf->supported) + continue; + + ret++; + } + + return ret; +} + +static int kvm_sbi_ext_fwft_get_reg_id(struct kvm_vcpu *vcpu, int index, u64 *reg_id) +{ + int reg, max_reg_count = sizeof(struct kvm_riscv_sbi_fwft) / sizeof(unsigned long); + const struct kvm_sbi_fwft_feature *feature; + struct kvm_sbi_fwft_config *conf; + int idx = 0; + + for (reg = 0; reg < max_reg_count; reg++) { + feature = kvm_sbi_fwft_regnum_to_feature(reg); + if (!feature) + continue; + + conf = kvm_sbi_fwft_get_config(vcpu, feature->id); + if (!conf || !conf->supported) + continue; + + if (index == idx) { + *reg_id = KVM_REG_RISCV | + (IS_ENABLED(CONFIG_32BIT) ? + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64) | + KVM_REG_RISCV_SBI_STATE | + KVM_REG_RISCV_SBI_FWFT | reg; + return 0; + } + + idx++; + } + + return -ENOENT; +} + +static int kvm_sbi_ext_fwft_get_reg(struct kvm_vcpu *vcpu, unsigned long reg_num, + unsigned long reg_size, void *reg_val) +{ + const struct kvm_sbi_fwft_feature *feature; + struct kvm_sbi_fwft_config *conf; + unsigned long *value; + int ret = 0; + + if (reg_size != sizeof(unsigned long)) + return -EINVAL; + value = reg_val; + + feature = kvm_sbi_fwft_regnum_to_feature(reg_num); + if (!feature) + return -ENOENT; + + conf = kvm_sbi_fwft_get_config(vcpu, feature->id); + if (!conf || !conf->supported) + return -ENOENT; + + switch (reg_num - feature->first_reg_num) { + case 0: + *value = conf->enabled; + break; + case 1: + *value = conf->flags; + break; + case 2: + ret = conf->feature->get(vcpu, conf, true, value); + break; + default: + return -ENOENT; + } + + return sbi_err_map_linux_errno(ret); +} + +static int kvm_sbi_ext_fwft_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num, + unsigned long reg_size, const void *reg_val) +{ + const struct kvm_sbi_fwft_feature *feature; + struct kvm_sbi_fwft_config *conf; + unsigned long value; + int ret = 0; + + if (reg_size != sizeof(unsigned long)) + return -EINVAL; + value = *(const unsigned long *)reg_val; + + feature = kvm_sbi_fwft_regnum_to_feature(reg_num); + if (!feature) + return -ENOENT; + + conf = kvm_sbi_fwft_get_config(vcpu, feature->id); + if (!conf || !conf->supported) + return -ENOENT; + + switch (reg_num - feature->first_reg_num) { + case 0: + switch (value) { + case 0: + conf->enabled = false; + break; + case 1: + conf->enabled = true; + break; + default: + return -EINVAL; + } + break; + case 1: + conf->flags = value & SBI_FWFT_SET_FLAG_LOCK; + break; + case 2: + ret = conf->feature->set(vcpu, conf, true, value); + break; + default: + return -ENOENT; + } + + return sbi_err_map_linux_errno(ret); +} + const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft = { .extid_start = SBI_EXT_FWFT, .extid_end = SBI_EXT_FWFT, @@ -370,4 +536,9 @@ const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft = { .init = kvm_sbi_ext_fwft_init, .deinit = kvm_sbi_ext_fwft_deinit, .reset = kvm_sbi_ext_fwft_reset, + .state_reg_subtype = KVM_REG_RISCV_SBI_FWFT, + .get_state_reg_count = kvm_sbi_ext_fwft_get_reg_count, + .get_state_reg_id = kvm_sbi_ext_fwft_get_reg_id, + .get_state_reg = kvm_sbi_ext_fwft_get_reg, + .set_state_reg = kvm_sbi_ext_fwft_set_reg, }; From 5c6d333a9e10d6230d4ab74125c7dcb4fdd69825 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Sat, 23 Aug 2025 21:29:47 +0530 Subject: [PATCH 1490/2711] KVM: riscv: selftests: Add SBI FWFT to get-reg-list test KVM RISC-V now supports SBI FWFT, so add it to the get-reg-list test. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250823155947.1354229-7-apatel@ventanamicro.com Signed-off-by: Anup Patel --- .../selftests/kvm/riscv/get-reg-list.c | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index 34456e8cba02..705ab3d7778b 100644 --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -132,6 +132,7 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_DBCN: case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_SUSP: case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_STA: + case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT: case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_EXPERIMENTAL: case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_VENDOR: return true; @@ -637,6 +638,7 @@ static const char *sbi_ext_single_id_to_str(__u64 reg_off) KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_DBCN), KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_SUSP), KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_STA), + KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_FWFT), KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_EXPERIMENTAL), KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_VENDOR), }; @@ -693,6 +695,19 @@ static const char *sbi_sta_id_to_str(__u64 reg_off) return strdup_printf("KVM_REG_RISCV_SBI_STA | %lld /* UNKNOWN */", reg_off); } +static const char *sbi_fwft_id_to_str(__u64 reg_off) +{ + switch (reg_off) { + case 0: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable)"; + case 1: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags)"; + case 2: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value)"; + case 3: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable)"; + case 4: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags)"; + case 5: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value)"; + } + return strdup_printf("KVM_REG_RISCV_SBI_FWFT | %lld /* UNKNOWN */", reg_off); +} + static const char *sbi_id_to_str(const char *prefix, __u64 id) { __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_SBI_STATE); @@ -705,6 +720,8 @@ static const char *sbi_id_to_str(const char *prefix, __u64 id) switch (reg_subtype) { case KVM_REG_RISCV_SBI_STA: return sbi_sta_id_to_str(reg_off); + case KVM_REG_RISCV_SBI_FWFT: + return sbi_fwft_id_to_str(reg_off); } return strdup_printf("%lld | %lld /* UNKNOWN */", reg_subtype, reg_off); @@ -872,6 +889,16 @@ static __u64 sbi_sta_regs[] = { KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_STA | KVM_REG_RISCV_SBI_STA_REG(shmem_hi), }; +static __u64 sbi_fwft_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value), +}; + static __u64 zicbom_regs[] = { KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicbom_block_size), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOM, @@ -1028,6 +1055,9 @@ static __u64 vector_regs[] = { #define SUBLIST_SBI_STA \ {"sbi-sta", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_STA, \ .regs = sbi_sta_regs, .regs_n = ARRAY_SIZE(sbi_sta_regs),} +#define SUBLIST_SBI_FWFT \ + {"sbi-fwft", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_FWFT, \ + .regs = sbi_fwft_regs, .regs_n = ARRAY_SIZE(sbi_fwft_regs),} #define SUBLIST_ZICBOM \ {"zicbom", .feature = KVM_RISCV_ISA_EXT_ZICBOM, .regs = zicbom_regs, .regs_n = ARRAY_SIZE(zicbom_regs),} #define SUBLIST_ZICBOP \ @@ -1112,6 +1142,7 @@ KVM_SBI_EXT_SUBLIST_CONFIG(sta, STA); KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU); KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN); KVM_SBI_EXT_SIMPLE_CONFIG(susp, SUSP); +KVM_SBI_EXT_SUBLIST_CONFIG(fwft, FWFT); KVM_ISA_EXT_SUBLIST_CONFIG(aia, AIA); KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, FP_F); @@ -1191,6 +1222,7 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_sbi_pmu, &config_sbi_dbcn, &config_sbi_susp, + &config_sbi_fwft, &config_aia, &config_fp_f, &config_fp_d, From 8c8d0f002b769dbef26c93d68e49d1d0ba54d094 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Tue, 9 Sep 2025 00:03:20 -0700 Subject: [PATCH 1491/2711] drivers/perf: riscv: Add SBI v3.0 flag There are new PMU related features introduced in SBI v3.0. 1. Raw Event v2 which allows mhpmeventX value to be 56 bit wide. 2. Get Event info function to do a bulk query at one shot. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Acked-by: Paul Walmsley Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-1-d8f80cacb884@rivosinc.com Signed-off-by: Anup Patel --- drivers/perf/riscv_pmu_sbi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 698de8ddf895..cfd6946fca42 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -63,6 +63,7 @@ PMU_FORMAT_ATTR(event, "config:0-47"); PMU_FORMAT_ATTR(firmware, "config:62-63"); static bool sbi_v2_available; +static bool sbi_v3_available; static DEFINE_STATIC_KEY_FALSE(sbi_pmu_snapshot_available); #define sbi_pmu_snapshot_available() \ static_branch_unlikely(&sbi_pmu_snapshot_available) @@ -1452,6 +1453,9 @@ static int __init pmu_sbi_devinit(void) if (sbi_spec_version >= sbi_mk_version(2, 0)) sbi_v2_available = true; + if (sbi_spec_version >= sbi_mk_version(3, 0)) + sbi_v3_available = true; + ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_RISCV_STARTING, "perf/riscv/pmu:starting", pmu_sbi_starting_cpu, pmu_sbi_dying_cpu); From 656ef2ea30a90f910e1d2691674c98e5dcd164b5 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Tue, 9 Sep 2025 00:03:21 -0700 Subject: [PATCH 1492/2711] drivers/perf: riscv: Add raw event v2 support SBI v3.0 introduced a new raw event type that allows wider mhpmeventX width to be programmed via CFG_MATCH. Use the raw event v2 if SBI v3.0 is available. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Acked-by: Paul Walmsley Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-2-d8f80cacb884@rivosinc.com Signed-off-by: Anup Patel --- arch/riscv/include/asm/sbi.h | 4 ++++ drivers/perf/riscv_pmu_sbi.c | 16 +++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 341e74238aa0..b0c41ef56968 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -161,7 +161,10 @@ struct riscv_pmu_snapshot_data { #define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(47, 0) #define RISCV_PMU_PLAT_FW_EVENT_MASK GENMASK_ULL(61, 0) +/* SBI v3.0 allows extended hpmeventX width value */ +#define RISCV_PMU_RAW_EVENT_V2_MASK GENMASK_ULL(55, 0) #define RISCV_PMU_RAW_EVENT_IDX 0x20000 +#define RISCV_PMU_RAW_EVENT_V2_IDX 0x30000 #define RISCV_PLAT_FW_EVENT 0xFFFF /** General pmu event codes specified in SBI PMU extension */ @@ -219,6 +222,7 @@ enum sbi_pmu_event_type { SBI_PMU_EVENT_TYPE_HW = 0x0, SBI_PMU_EVENT_TYPE_CACHE = 0x1, SBI_PMU_EVENT_TYPE_RAW = 0x2, + SBI_PMU_EVENT_TYPE_RAW_V2 = 0x3, SBI_PMU_EVENT_TYPE_FW = 0xf, }; diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index cfd6946fca42..3644bed4c8ab 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -59,7 +59,7 @@ asm volatile(ALTERNATIVE( \ #define PERF_EVENT_FLAG_USER_ACCESS BIT(SYSCTL_USER_ACCESS) #define PERF_EVENT_FLAG_LEGACY BIT(SYSCTL_LEGACY) -PMU_FORMAT_ATTR(event, "config:0-47"); +PMU_FORMAT_ATTR(event, "config:0-55"); PMU_FORMAT_ATTR(firmware, "config:62-63"); static bool sbi_v2_available; @@ -527,8 +527,10 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig) break; case PERF_TYPE_RAW: /* - * As per SBI specification, the upper 16 bits must be unused - * for a hardware raw event. + * As per SBI v0.3 specification, + * -- the upper 16 bits must be unused for a hardware raw event. + * As per SBI v2.0 specification, + * -- the upper 8 bits must be unused for a hardware raw event. * Bits 63:62 are used to distinguish between raw events * 00 - Hardware raw event * 10 - SBI firmware events @@ -537,8 +539,12 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig) switch (config >> 62) { case 0: - /* Return error any bits [48-63] is set as it is not allowed by the spec */ - if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) { + if (sbi_v3_available) { + if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) { + *econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK; + ret = RISCV_PMU_RAW_EVENT_V2_IDX; + } + } else if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) { *econfig = config & RISCV_PMU_RAW_EVENT_MASK; ret = RISCV_PMU_RAW_EVENT_IDX; } From 190b74154299d210de7937d7325571fc3fa37383 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Tue, 9 Sep 2025 00:03:22 -0700 Subject: [PATCH 1493/2711] RISC-V: KVM: Add support for Raw event v2 SBI v3.0 introduced a new raw event type v2 for wider mhpmeventX programming. Add the support in kvm for that. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Acked-by: Paul Walmsley Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-3-d8f80cacb884@rivosinc.com Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_pmu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c index 78ac3216a54d..15d71a7b75ba 100644 --- a/arch/riscv/kvm/vcpu_pmu.c +++ b/arch/riscv/kvm/vcpu_pmu.c @@ -60,6 +60,7 @@ static u32 kvm_pmu_get_perf_event_type(unsigned long eidx) type = PERF_TYPE_HW_CACHE; break; case SBI_PMU_EVENT_TYPE_RAW: + case SBI_PMU_EVENT_TYPE_RAW_V2: case SBI_PMU_EVENT_TYPE_FW: type = PERF_TYPE_RAW; break; @@ -128,6 +129,9 @@ static u64 kvm_pmu_get_perf_event_config(unsigned long eidx, uint64_t evt_data) case SBI_PMU_EVENT_TYPE_RAW: config = evt_data & RISCV_PMU_RAW_EVENT_MASK; break; + case SBI_PMU_EVENT_TYPE_RAW_V2: + config = evt_data & RISCV_PMU_RAW_EVENT_V2_MASK; + break; case SBI_PMU_EVENT_TYPE_FW: if (ecode < SBI_PMU_FW_MAX) config = (1ULL << 63) | ecode; From adffbd06d0036a1f2d8424ecc22d37ca38709012 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Tue, 9 Sep 2025 00:03:23 -0700 Subject: [PATCH 1494/2711] drivers/perf: riscv: Implement PMU event info function With the new SBI PMU event info function, we can query the availability of the all standard SBI PMU events at boot time with a single ecall. This improves the bootime by avoiding making an SBI call for each standard PMU event. Since this function is defined only in SBI v3.0, invoke this only if the underlying SBI implementation is v3.0 or higher. Signed-off-by: Atish Patra Reviewed-by: Anup Patel Acked-by: Paul Walmsley Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-4-d8f80cacb884@rivosinc.com Signed-off-by: Anup Patel --- arch/riscv/include/asm/sbi.h | 9 +++++ drivers/perf/riscv_pmu_sbi.c | 69 ++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index b0c41ef56968..5ca7cebc13cc 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -136,6 +136,7 @@ enum sbi_ext_pmu_fid { SBI_EXT_PMU_COUNTER_FW_READ, SBI_EXT_PMU_COUNTER_FW_READ_HI, SBI_EXT_PMU_SNAPSHOT_SET_SHMEM, + SBI_EXT_PMU_EVENT_GET_INFO, }; union sbi_pmu_ctr_info { @@ -159,6 +160,14 @@ struct riscv_pmu_snapshot_data { u64 reserved[447]; }; +struct riscv_pmu_event_info { + u32 event_idx; + u32 output; + u64 event_data; +}; + +#define RISCV_PMU_EVENT_INFO_OUTPUT_MASK 0x01 + #define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(47, 0) #define RISCV_PMU_PLAT_FW_EVENT_MASK GENMASK_ULL(61, 0) /* SBI v3.0 allows extended hpmeventX width value */ diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 3644bed4c8ab..a6c479f853e1 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -299,6 +299,66 @@ static struct sbi_pmu_event_data pmu_cache_event_map[PERF_COUNT_HW_CACHE_MAX] }, }; +static int pmu_sbi_check_event_info(void) +{ + int num_events = ARRAY_SIZE(pmu_hw_event_map) + PERF_COUNT_HW_CACHE_MAX * + PERF_COUNT_HW_CACHE_OP_MAX * PERF_COUNT_HW_CACHE_RESULT_MAX; + struct riscv_pmu_event_info *event_info_shmem; + phys_addr_t base_addr; + int i, j, k, result = 0, count = 0; + struct sbiret ret; + + event_info_shmem = kcalloc(num_events, sizeof(*event_info_shmem), GFP_KERNEL); + if (!event_info_shmem) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) + event_info_shmem[count++].event_idx = pmu_hw_event_map[i].event_idx; + + for (i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++) { + for (j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++) { + for (k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++) + event_info_shmem[count++].event_idx = + pmu_cache_event_map[i][j][k].event_idx; + } + } + + base_addr = __pa(event_info_shmem); + if (IS_ENABLED(CONFIG_32BIT)) + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_EVENT_GET_INFO, lower_32_bits(base_addr), + upper_32_bits(base_addr), count, 0, 0, 0); + else + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_EVENT_GET_INFO, base_addr, 0, + count, 0, 0, 0); + if (ret.error) { + result = -EOPNOTSUPP; + goto free_mem; + } + + for (i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) { + if (!(event_info_shmem[i].output & RISCV_PMU_EVENT_INFO_OUTPUT_MASK)) + pmu_hw_event_map[i].event_idx = -ENOENT; + } + + count = ARRAY_SIZE(pmu_hw_event_map); + + for (i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++) { + for (j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++) { + for (k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++) { + if (!(event_info_shmem[count].output & + RISCV_PMU_EVENT_INFO_OUTPUT_MASK)) + pmu_cache_event_map[i][j][k].event_idx = -ENOENT; + count++; + } + } + } + +free_mem: + kfree(event_info_shmem); + + return result; +} + static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata) { struct sbiret ret; @@ -316,6 +376,15 @@ static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata) static void pmu_sbi_check_std_events(struct work_struct *work) { + int ret; + + if (sbi_v3_available) { + ret = pmu_sbi_check_event_info(); + if (ret) + pr_err("pmu_sbi_check_event_info failed with error %d\n", ret); + return; + } + for (int i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) pmu_sbi_check_event(&pmu_hw_event_map[i]); From 880fcc329e2473ba02ffbc446fcd403972ab1fca Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Tue, 9 Sep 2025 00:03:24 -0700 Subject: [PATCH 1495/2711] drivers/perf: riscv: Export PMU event info function The event mapping function can be used in event info function to find out the corresponding SBI PMU event encoding during the get_event_info function as well. Refactor and export it so that it can be invoked from kvm and internal driver. Signed-off-by: Atish Patra Reviewed-by: Anup Patel Acked-by: Paul Walmsley Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-5-d8f80cacb884@rivosinc.com Signed-off-by: Anup Patel --- drivers/perf/riscv_pmu_sbi.c | 122 ++++++++++++++++++--------------- include/linux/perf/riscv_pmu.h | 1 + 2 files changed, 68 insertions(+), 55 deletions(-) diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index a6c479f853e1..0392900d828e 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -100,6 +100,7 @@ static unsigned int riscv_pmu_irq; /* Cache the available counters in a bitmask */ static unsigned long cmask; +static int pmu_event_find_cache(u64 config); struct sbi_pmu_event_data { union { union { @@ -412,6 +413,71 @@ static bool pmu_sbi_ctr_is_fw(int cidx) return (info->type == SBI_PMU_CTR_TYPE_FW) ? true : false; } +int riscv_pmu_get_event_info(u32 type, u64 config, u64 *econfig) +{ + int ret = -ENOENT; + + switch (type) { + case PERF_TYPE_HARDWARE: + if (config >= PERF_COUNT_HW_MAX) + return -EINVAL; + ret = pmu_hw_event_map[config].event_idx; + break; + case PERF_TYPE_HW_CACHE: + ret = pmu_event_find_cache(config); + break; + case PERF_TYPE_RAW: + /* + * As per SBI v0.3 specification, + * -- the upper 16 bits must be unused for a hardware raw event. + * As per SBI v2.0 specification, + * -- the upper 8 bits must be unused for a hardware raw event. + * Bits 63:62 are used to distinguish between raw events + * 00 - Hardware raw event + * 10 - SBI firmware events + * 11 - Risc-V platform specific firmware event + */ + switch (config >> 62) { + case 0: + if (sbi_v3_available) { + /* Return error any bits [56-63] is set as it is not allowed by the spec */ + if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) { + if (econfig) + *econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK; + ret = RISCV_PMU_RAW_EVENT_V2_IDX; + } + /* Return error any bits [48-63] is set as it is not allowed by the spec */ + } else if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) { + if (econfig) + *econfig = config & RISCV_PMU_RAW_EVENT_MASK; + ret = RISCV_PMU_RAW_EVENT_IDX; + } + break; + case 2: + ret = (config & 0xFFFF) | (SBI_PMU_EVENT_TYPE_FW << 16); + break; + case 3: + /* + * For Risc-V platform specific firmware events + * Event code - 0xFFFF + * Event data - raw event encoding + */ + ret = SBI_PMU_EVENT_TYPE_FW << 16 | RISCV_PLAT_FW_EVENT; + if (econfig) + *econfig = config & RISCV_PMU_PLAT_FW_EVENT_MASK; + break; + default: + break; + } + break; + default: + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(riscv_pmu_get_event_info); + /* * Returns the counter width of a programmable counter and number of hardware * counters. As we don't support heterogeneous CPUs yet, it is okay to just @@ -577,7 +643,6 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig) { u32 type = event->attr.type; u64 config = event->attr.config; - int ret = -ENOENT; /* * Ensure we are finished checking standard hardware events for @@ -585,60 +650,7 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig) */ flush_work(&check_std_events_work); - switch (type) { - case PERF_TYPE_HARDWARE: - if (config >= PERF_COUNT_HW_MAX) - return -EINVAL; - ret = pmu_hw_event_map[event->attr.config].event_idx; - break; - case PERF_TYPE_HW_CACHE: - ret = pmu_event_find_cache(config); - break; - case PERF_TYPE_RAW: - /* - * As per SBI v0.3 specification, - * -- the upper 16 bits must be unused for a hardware raw event. - * As per SBI v2.0 specification, - * -- the upper 8 bits must be unused for a hardware raw event. - * Bits 63:62 are used to distinguish between raw events - * 00 - Hardware raw event - * 10 - SBI firmware events - * 11 - Risc-V platform specific firmware event - */ - - switch (config >> 62) { - case 0: - if (sbi_v3_available) { - if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) { - *econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK; - ret = RISCV_PMU_RAW_EVENT_V2_IDX; - } - } else if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) { - *econfig = config & RISCV_PMU_RAW_EVENT_MASK; - ret = RISCV_PMU_RAW_EVENT_IDX; - } - break; - case 2: - ret = (config & 0xFFFF) | (SBI_PMU_EVENT_TYPE_FW << 16); - break; - case 3: - /* - * For Risc-V platform specific firmware events - * Event code - 0xFFFF - * Event data - raw event encoding - */ - ret = SBI_PMU_EVENT_TYPE_FW << 16 | RISCV_PLAT_FW_EVENT; - *econfig = config & RISCV_PMU_PLAT_FW_EVENT_MASK; - break; - default: - break; - } - break; - default: - break; - } - - return ret; + return riscv_pmu_get_event_info(type, config, econfig); } static void pmu_sbi_snapshot_free(struct riscv_pmu *pmu) diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index 701974639ff2..f82a28040594 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -89,6 +89,7 @@ static inline void riscv_pmu_legacy_skip_init(void) {}; struct riscv_pmu *riscv_pmu_alloc(void); #ifdef CONFIG_RISCV_PMU_SBI int riscv_pmu_get_hpm_info(u32 *hw_ctr_width, u32 *num_hw_ctr); +int riscv_pmu_get_event_info(u32 type, u64 config, u64 *econfig); #endif #endif /* CONFIG_RISCV_PMU */ From 41f4d0cc331a1e9dc247ce22ae45f983f0ed9054 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Tue, 9 Sep 2025 00:03:25 -0700 Subject: [PATCH 1496/2711] RISC-V: KVM: No need of explicit writable slot check There is not much value in checking if a memslot is writable explicitly before a write as it may change underneath after the check. Rather, return invalid address error when write_guest fails as it checks if the slot is writable anyways. Suggested-by: Sean Christopherson Signed-off-by: Atish Patra Reviewed-by: Anup Patel Acked-by: Paul Walmsley Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-6-d8f80cacb884@rivosinc.com Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_pmu.c | 11 ++--------- arch/riscv/kvm/vcpu_sbi_sta.c | 9 ++------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c index 15d71a7b75ba..f8514086bd6b 100644 --- a/arch/riscv/kvm/vcpu_pmu.c +++ b/arch/riscv/kvm/vcpu_pmu.c @@ -409,8 +409,6 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s int snapshot_area_size = sizeof(struct riscv_pmu_snapshot_data); int sbiret = 0; gpa_t saddr; - unsigned long hva; - bool writable; if (!kvpmu || flags) { sbiret = SBI_ERR_INVALID_PARAM; @@ -432,19 +430,14 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s goto out; } - hva = kvm_vcpu_gfn_to_hva_prot(vcpu, saddr >> PAGE_SHIFT, &writable); - if (kvm_is_error_hva(hva) || !writable) { - sbiret = SBI_ERR_INVALID_ADDRESS; - goto out; - } - kvpmu->sdata = kzalloc(snapshot_area_size, GFP_ATOMIC); if (!kvpmu->sdata) return -ENOMEM; + /* No need to check writable slot explicitly as kvm_vcpu_write_guest does it internally */ if (kvm_vcpu_write_guest(vcpu, saddr, kvpmu->sdata, snapshot_area_size)) { kfree(kvpmu->sdata); - sbiret = SBI_ERR_FAILURE; + sbiret = SBI_ERR_INVALID_ADDRESS; goto out; } diff --git a/arch/riscv/kvm/vcpu_sbi_sta.c b/arch/riscv/kvm/vcpu_sbi_sta.c index 68486f90a61e..afa0545c3bcf 100644 --- a/arch/riscv/kvm/vcpu_sbi_sta.c +++ b/arch/riscv/kvm/vcpu_sbi_sta.c @@ -85,8 +85,6 @@ static int kvm_sbi_sta_steal_time_set_shmem(struct kvm_vcpu *vcpu) unsigned long shmem_phys_hi = cp->a1; u32 flags = cp->a2; struct sbi_sta_struct zero_sta = {0}; - unsigned long hva; - bool writable; gpa_t shmem; int ret; @@ -111,13 +109,10 @@ static int kvm_sbi_sta_steal_time_set_shmem(struct kvm_vcpu *vcpu) return SBI_ERR_INVALID_ADDRESS; } - hva = kvm_vcpu_gfn_to_hva_prot(vcpu, shmem >> PAGE_SHIFT, &writable); - if (kvm_is_error_hva(hva) || !writable) - return SBI_ERR_INVALID_ADDRESS; - + /* No need to check writable slot explicitly as kvm_vcpu_write_guest does it internally */ ret = kvm_vcpu_write_guest(vcpu, shmem, &zero_sta, sizeof(zero_sta)); if (ret) - return SBI_ERR_FAILURE; + return SBI_ERR_INVALID_ADDRESS; vcpu->arch.sta.shmem = shmem; vcpu->arch.sta.last_steal = current->sched_info.run_delay; From e309fd113b9f6c34672a487be08fecb7e12e7e29 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Tue, 9 Sep 2025 00:03:26 -0700 Subject: [PATCH 1497/2711] RISC-V: KVM: Implement get event info function The new get_event_info funciton allows the guest to query the presence of multiple events with single SBI call. Currently, the perf driver in linux guest invokes it for all the standard SBI PMU events. Support the SBI function implementation in KVM as well. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Acked-by: Paul Walmsley Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-7-d8f80cacb884@rivosinc.com Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_vcpu_pmu.h | 3 ++ arch/riscv/kvm/vcpu_pmu.c | 59 +++++++++++++++++++++++++++ arch/riscv/kvm/vcpu_sbi_pmu.c | 3 ++ 3 files changed, 65 insertions(+) diff --git a/arch/riscv/include/asm/kvm_vcpu_pmu.h b/arch/riscv/include/asm/kvm_vcpu_pmu.h index 1d85b6617508..9a930afc8f57 100644 --- a/arch/riscv/include/asm/kvm_vcpu_pmu.h +++ b/arch/riscv/include/asm/kvm_vcpu_pmu.h @@ -98,6 +98,9 @@ void kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu); int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long saddr_low, unsigned long saddr_high, unsigned long flags, struct kvm_vcpu_sbi_return *retdata); +int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low, + unsigned long saddr_high, unsigned long num_events, + unsigned long flags, struct kvm_vcpu_sbi_return *retdata); void kvm_riscv_vcpu_pmu_deinit(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu); diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c index f8514086bd6b..a2fae70ee174 100644 --- a/arch/riscv/kvm/vcpu_pmu.c +++ b/arch/riscv/kvm/vcpu_pmu.c @@ -449,6 +449,65 @@ out: return 0; } +int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low, + unsigned long saddr_high, unsigned long num_events, + unsigned long flags, struct kvm_vcpu_sbi_return *retdata) +{ + struct riscv_pmu_event_info *einfo = NULL; + int shmem_size = num_events * sizeof(*einfo); + gpa_t shmem; + u32 eidx, etype; + u64 econfig; + int ret; + + if (flags != 0 || (saddr_low & (SZ_16 - 1) || num_events == 0)) { + ret = SBI_ERR_INVALID_PARAM; + goto out; + } + + shmem = saddr_low; + if (saddr_high != 0) { + if (IS_ENABLED(CONFIG_32BIT)) { + shmem |= ((gpa_t)saddr_high << 32); + } else { + ret = SBI_ERR_INVALID_ADDRESS; + goto out; + } + } + + einfo = kzalloc(shmem_size, GFP_KERNEL); + if (!einfo) + return -ENOMEM; + + ret = kvm_vcpu_read_guest(vcpu, shmem, einfo, shmem_size); + if (ret) { + ret = SBI_ERR_FAILURE; + goto free_mem; + } + + for (int i = 0; i < num_events; i++) { + eidx = einfo[i].event_idx; + etype = kvm_pmu_get_perf_event_type(eidx); + econfig = kvm_pmu_get_perf_event_config(eidx, einfo[i].event_data); + ret = riscv_pmu_get_event_info(etype, econfig, NULL); + einfo[i].output = (ret > 0) ? 1 : 0; + } + + ret = kvm_vcpu_write_guest(vcpu, shmem, einfo, shmem_size); + if (ret) { + ret = SBI_ERR_INVALID_ADDRESS; + goto free_mem; + } + + ret = 0; +free_mem: + kfree(einfo); +out: + retdata->err_val = ret; + + return 0; +} + int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_return *retdata) { diff --git a/arch/riscv/kvm/vcpu_sbi_pmu.c b/arch/riscv/kvm/vcpu_sbi_pmu.c index e4be34e03e83..a020d979d179 100644 --- a/arch/riscv/kvm/vcpu_sbi_pmu.c +++ b/arch/riscv/kvm/vcpu_sbi_pmu.c @@ -73,6 +73,9 @@ static int kvm_sbi_ext_pmu_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, case SBI_EXT_PMU_SNAPSHOT_SET_SHMEM: ret = kvm_riscv_vcpu_pmu_snapshot_set_shmem(vcpu, cp->a0, cp->a1, cp->a2, retdata); break; + case SBI_EXT_PMU_EVENT_GET_INFO: + ret = kvm_riscv_vcpu_pmu_event_info(vcpu, cp->a0, cp->a1, cp->a2, cp->a3, retdata); + break; default: retdata->err_val = SBI_ERR_NOT_SUPPORTED; } From dbdadd943a278fb8a24ae4199a668131108034b4 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Tue, 9 Sep 2025 00:03:27 -0700 Subject: [PATCH 1498/2711] RISC-V: KVM: Upgrade the supported SBI version to 3.0 Upgrade the SBI version to v3.0 so that corresponding features can be enabled in the guest. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Acked-by: Paul Walmsley Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-8-d8f80cacb884@rivosinc.com Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_vcpu_sbi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h index d75ca45c0152..3497489e04db 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h @@ -11,7 +11,7 @@ #define KVM_SBI_IMPID 3 -#define KVM_SBI_VERSION_MAJOR 2 +#define KVM_SBI_VERSION_MAJOR 3 #define KVM_SBI_VERSION_MINOR 0 enum kvm_riscv_sbi_ext_status { From 85afa9ea122dd9d4a2ead104a951d318975dcd25 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Kawasaki Date: Tue, 16 Sep 2025 11:57:56 +0900 Subject: [PATCH 1499/2711] PCI: endpoint: pci-epf-test: Add NULL check for DMA channels before release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fields dma_chan_tx and dma_chan_rx of the struct pci_epf_test can be NULL even after EPF initialization. Then it is prudent to check that they have non-NULL values before releasing the channels. Add the checks in pci_epf_test_clean_dma_chan(). Without the checks, NULL pointer dereferences happen and they can lead to a kernel panic in some cases: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000050 Call trace: dma_release_channel+0x2c/0x120 (P) pci_epf_test_epc_deinit+0x94/0xc0 [pci_epf_test] pci_epc_deinit_notify+0x74/0xc0 tegra_pcie_ep_pex_rst_irq+0x250/0x5d8 irq_thread_fn+0x34/0xb8 irq_thread+0x18c/0x2e8 kthread+0x14c/0x210 ret_from_fork+0x10/0x20 Fixes: 8353813c88ef ("PCI: endpoint: Enable DMA tests for endpoints with DMA capabilities") Fixes: 5ebf3fc59bd2 ("PCI: endpoint: functions/pci-epf-test: Add DMA support to transfer data") Signed-off-by: Shin'ichiro Kawasaki [mani: trimmed the stack trace] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Damien Le Moal Reviewed-by: Krzysztof Wilczyński Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250916025756.34807-1-shinichiro.kawasaki@wdc.com --- drivers/pci/endpoint/functions/pci-epf-test.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index 09e1b8b46b55..31617772ad51 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -301,15 +301,20 @@ static void pci_epf_test_clean_dma_chan(struct pci_epf_test *epf_test) if (!epf_test->dma_supported) return; - dma_release_channel(epf_test->dma_chan_tx); - if (epf_test->dma_chan_tx == epf_test->dma_chan_rx) { + if (epf_test->dma_chan_tx) { + dma_release_channel(epf_test->dma_chan_tx); + if (epf_test->dma_chan_tx == epf_test->dma_chan_rx) { + epf_test->dma_chan_tx = NULL; + epf_test->dma_chan_rx = NULL; + return; + } epf_test->dma_chan_tx = NULL; - epf_test->dma_chan_rx = NULL; - return; } - dma_release_channel(epf_test->dma_chan_rx); - epf_test->dma_chan_rx = NULL; + if (epf_test->dma_chan_rx) { + dma_release_channel(epf_test->dma_chan_rx); + epf_test->dma_chan_rx = NULL; + } } static void pci_epf_test_print_rate(struct pci_epf_test *epf_test, From 7d62beb102d6fa9a4e5e874be7fbf47a62fcc4f6 Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Tue, 9 Sep 2025 06:00:06 -0500 Subject: [PATCH 1500/2711] HID: i2c-hid: Resolve touchpad issues on Dell systems during S4 Dell systems utilize an EC-based touchpad emulation when the ACPI touchpad _DSM is not invoked. This emulation acts as a secondary master on the I2C bus, designed for scenarios where the I2C touchpad driver is absent, such as in BIOS menus. Typically, loading the i2c-hid module triggers the _DSM at initialization, disabling the EC-based emulation. However, if the i2c-hid module is missing from the boot kernel used for hibernation snapshot restoration, the _DSM remains uncalled, resulting in dual masters on the I2C bus and subsequent arbitration errors. This issue arises when i2c-hid resides in the rootfs instead of the kernel or initramfs. To address this, switch from using the SYSTEM_SLEEP_PM_OPS() macro to dedicated callbacks, introducing a specific callback for restoring the S4 image. This callback ensures the _DSM is invoked. Signed-off-by: Mario Limonciello (AMD) Signed-off-by: Benjamin Tissoires --- drivers/hid/i2c-hid/i2c-hid-acpi.c | 8 ++++++++ drivers/hid/i2c-hid/i2c-hid-core.c | 28 +++++++++++++++++++++++++++- drivers/hid/i2c-hid/i2c-hid.h | 2 ++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi.c b/drivers/hid/i2c-hid/i2c-hid-acpi.c index 1b49243adb16..abd700a101f4 100644 --- a/drivers/hid/i2c-hid/i2c-hid-acpi.c +++ b/drivers/hid/i2c-hid/i2c-hid-acpi.c @@ -76,6 +76,13 @@ static int i2c_hid_acpi_get_descriptor(struct i2c_hid_acpi *ihid_acpi) return hid_descriptor_address; } +static void i2c_hid_acpi_restore_sequence(struct i2chid_ops *ops) +{ + struct i2c_hid_acpi *ihid_acpi = container_of(ops, struct i2c_hid_acpi, ops); + + i2c_hid_acpi_get_descriptor(ihid_acpi); +} + static void i2c_hid_acpi_shutdown_tail(struct i2chid_ops *ops) { struct i2c_hid_acpi *ihid_acpi = container_of(ops, struct i2c_hid_acpi, ops); @@ -96,6 +103,7 @@ static int i2c_hid_acpi_probe(struct i2c_client *client) ihid_acpi->adev = ACPI_COMPANION(dev); ihid_acpi->ops.shutdown_tail = i2c_hid_acpi_shutdown_tail; + ihid_acpi->ops.restore_sequence = i2c_hid_acpi_restore_sequence; ret = i2c_hid_acpi_get_descriptor(ihid_acpi); if (ret < 0) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index d3912e3f2f13..3257aa87be89 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -961,6 +961,14 @@ static void i2c_hid_core_shutdown_tail(struct i2c_hid *ihid) ihid->ops->shutdown_tail(ihid->ops); } +static void i2c_hid_core_restore_sequence(struct i2c_hid *ihid) +{ + if (!ihid->ops->restore_sequence) + return; + + ihid->ops->restore_sequence(ihid->ops); +} + static int i2c_hid_core_suspend(struct i2c_hid *ihid, bool force_poweroff) { struct i2c_client *client = ihid->client; @@ -1360,8 +1368,26 @@ static int i2c_hid_core_pm_resume(struct device *dev) return i2c_hid_core_resume(ihid); } +static int i2c_hid_core_pm_restore(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct i2c_hid *ihid = i2c_get_clientdata(client); + + if (ihid->is_panel_follower) + return 0; + + i2c_hid_core_restore_sequence(ihid); + + return i2c_hid_core_resume(ihid); +} + const struct dev_pm_ops i2c_hid_core_pm = { - SYSTEM_SLEEP_PM_OPS(i2c_hid_core_pm_suspend, i2c_hid_core_pm_resume) + .suspend = pm_sleep_ptr(i2c_hid_core_pm_suspend), + .resume = pm_sleep_ptr(i2c_hid_core_pm_resume), + .freeze = pm_sleep_ptr(i2c_hid_core_pm_suspend), + .thaw = pm_sleep_ptr(i2c_hid_core_pm_resume), + .poweroff = pm_sleep_ptr(i2c_hid_core_pm_suspend), + .restore = pm_sleep_ptr(i2c_hid_core_pm_restore), }; EXPORT_SYMBOL_GPL(i2c_hid_core_pm); diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h index 2c7b66d5caa0..1724a435c783 100644 --- a/drivers/hid/i2c-hid/i2c-hid.h +++ b/drivers/hid/i2c-hid/i2c-hid.h @@ -27,11 +27,13 @@ static inline u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product) * @power_up: do sequencing to power up the device. * @power_down: do sequencing to power down the device. * @shutdown_tail: called at the end of shutdown. + * @restore_sequence: hibernation restore sequence. */ struct i2chid_ops { int (*power_up)(struct i2chid_ops *ops); void (*power_down)(struct i2chid_ops *ops); void (*shutdown_tail)(struct i2chid_ops *ops); + void (*restore_sequence)(struct i2chid_ops *ops); }; int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops, From 8236b4667aca63afcd29620a48a084f6a0eed162 Mon Sep 17 00:00:00 2001 From: Yen-Chi Huang Date: Wed, 10 Sep 2025 11:58:13 +0800 Subject: [PATCH 1501/2711] platform/x86: portwell-ec: Add hwmon support for voltage and temperature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integrates voltage and temperature monitoring into the driver via the hwmon subsystem, enabling standardized reporting via tools like lm-sensors. Signed-off-by: Yen-Chi Huang Link: https://patch.msgid.link/0d73c577-1941-44b4-917e-3aed6f1f664a@portwell.com.tw [ij: align struct member comments] Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/portwell-ec.c | 170 +++++++++++++++++++++++++++-- 1 file changed, 162 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/portwell-ec.c b/drivers/platform/x86/portwell-ec.c index 13db9aa485d3..ac506ea40eff 100644 --- a/drivers/platform/x86/portwell-ec.c +++ b/drivers/platform/x86/portwell-ec.c @@ -5,15 +5,13 @@ * Tested on: * - Portwell NANO-6064 * - * This driver provides support for GPIO and Watchdog Timer - * functionalities of the Portwell boards with ITE embedded controller (EC). + * This driver supports Portwell boards with an ITE embedded controller (EC). * The EC is accessed through I/O ports and provides: + * - Temperature and voltage readings (hwmon) * - 8 GPIO pins for control and monitoring * - Hardware watchdog with 1-15300 second timeout range * - * It integrates with the Linux GPIO and Watchdog subsystems, allowing - * userspace interaction with EC GPIO pins and watchdog control, - * ensuring system stability and configurability. + * It integrates with the Linux hwmon, GPIO and Watchdog subsystems. * * (C) Copyright 2025 Portwell, Inc. * Author: Yen-Chi Huang (jesse.huang@portwell.com.tw) @@ -22,9 +20,11 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include +#include #include #include #include @@ -33,6 +33,7 @@ #include #include #include +#include #include #define PORTWELL_EC_IOSPACE 0xe300 @@ -42,6 +43,9 @@ #define PORTWELL_GPIO_DIR_REG 0x2b #define PORTWELL_GPIO_VAL_REG 0x2c +#define PORTWELL_HWMON_TEMP_NUM 3 +#define PORTWELL_HWMON_VOLT_NUM 5 + #define PORTWELL_WDT_EC_CONFIG_ADDR 0x06 #define PORTWELL_WDT_CONFIG_ENABLE 0x1 #define PORTWELL_WDT_CONFIG_DISABLE 0x0 @@ -53,16 +57,60 @@ #define PORTWELL_EC_FW_VENDOR_LENGTH 3 #define PORTWELL_EC_FW_VENDOR_NAME "PWG" +#define PORTWELL_EC_ADC_MAX 1023 + static bool force; module_param(force, bool, 0444); MODULE_PARM_DESC(force, "Force loading EC driver without checking DMI boardname"); +/* A sensor's metadata (label, scale, and register) */ +struct pwec_sensor_prop { + const char *label; + u8 reg; + u32 scale; +}; + +/* Master configuration with properties for all possible sensors */ +static const struct { + const struct pwec_sensor_prop temp_props[PORTWELL_HWMON_TEMP_NUM]; + const struct pwec_sensor_prop in_props[PORTWELL_HWMON_VOLT_NUM]; +} pwec_master_data = { + .temp_props = { + { "CPU Temperature", 0x00, 0 }, + { "System Temperature", 0x02, 0 }, + { "Aux Temperature", 0x04, 0 }, + }, + .in_props = { + { "Vcore", 0x20, 3000 }, + { "3.3V", 0x22, 6000 }, + { "5V", 0x24, 9600 }, + { "12V", 0x30, 19800 }, + { "VDIMM", 0x32, 3000 }, + }, +}; + +struct pwec_board_info { + u32 temp_mask; /* bit N = temperature channel N */ + u32 in_mask; /* bit N = voltage channel N */ +}; + +static const struct pwec_board_info pwec_board_info_default = { + .temp_mask = GENMASK(PORTWELL_HWMON_TEMP_NUM - 1, 0), + .in_mask = GENMASK(PORTWELL_HWMON_VOLT_NUM - 1, 0), +}; + +static const struct pwec_board_info pwec_board_info_nano = { + .temp_mask = BIT(0) | BIT(1), + .in_mask = GENMASK(4, 0), +}; + static const struct dmi_system_id pwec_dmi_table[] = { { .ident = "NANO-6064 series", .matches = { DMI_MATCH(DMI_BOARD_NAME, "NANO-6064"), }, + .driver_data = (void *)&pwec_board_info_nano, }, { } }; @@ -80,6 +128,20 @@ static u8 pwec_read(u8 address) return inb(PORTWELL_EC_IOSPACE + address); } +/* Ensure consistent 16-bit read across potential MSB rollover. */ +static u16 pwec_read16_stable(u8 lsb_reg) +{ + u8 lsb, msb, old_msb; + + do { + old_msb = pwec_read(lsb_reg + 1); + lsb = pwec_read(lsb_reg); + msb = pwec_read(lsb_reg + 1); + } while (msb != old_msb); + + return (msb << 8) | lsb; +} + /* GPIO functions */ static int pwec_gpio_get(struct gpio_chip *chip, unsigned int offset) @@ -205,6 +267,81 @@ static struct watchdog_device ec_wdt_dev = { .max_timeout = PORTWELL_WDT_EC_MAX_COUNT_SECOND, }; +/* HWMON functions */ + +static umode_t pwec_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct pwec_board_info *info = drvdata; + + switch (type) { + case hwmon_temp: + return (info->temp_mask & BIT(channel)) ? 0444 : 0; + case hwmon_in: + return (info->in_mask & BIT(channel)) ? 0444 : 0; + default: + return 0; + } +} + +static int pwec_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + u16 tmp16; + + switch (type) { + case hwmon_temp: + *val = pwec_read(pwec_master_data.temp_props[channel].reg) * MILLIDEGREE_PER_DEGREE; + return 0; + case hwmon_in: + tmp16 = pwec_read16_stable(pwec_master_data.in_props[channel].reg); + *val = (tmp16 * pwec_master_data.in_props[channel].scale) / PORTWELL_EC_ADC_MAX; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int pwec_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + switch (type) { + case hwmon_temp: + *str = pwec_master_data.temp_props[channel].label; + return 0; + case hwmon_in: + *str = pwec_master_data.in_props[channel].label; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_channel_info *pwec_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL), + NULL +}; + +static const struct hwmon_ops pwec_hwmon_ops = { + .is_visible = pwec_hwmon_is_visible, + .read = pwec_hwmon_read, + .read_string = pwec_hwmon_read_string, +}; + +static const struct hwmon_chip_info pwec_chip_info = { + .ops = &pwec_hwmon_ops, + .info = pwec_hwmon_info, +}; + static int pwec_firmware_vendor_check(void) { u8 buf[PORTWELL_EC_FW_VENDOR_LENGTH + 1]; @@ -219,6 +356,8 @@ static int pwec_firmware_vendor_check(void) static int pwec_probe(struct platform_device *pdev) { + struct device *hwmon_dev; + void *drvdata = dev_get_platdata(&pdev->dev); int ret; if (!devm_request_region(&pdev->dev, PORTWELL_EC_IOSPACE, @@ -237,6 +376,14 @@ static int pwec_probe(struct platform_device *pdev) return ret; } + if (IS_REACHABLE(CONFIG_HWMON)) { + hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, + "portwell_ec", drvdata, &pwec_chip_info, NULL); + ret = PTR_ERR_OR_ZERO(hwmon_dev); + if (ret) + return ret; + } + ec_wdt_dev.parent = &pdev->dev; return devm_watchdog_register_device(&pdev->dev, &ec_wdt_dev); } @@ -271,19 +418,26 @@ static struct platform_device *pwec_dev; static int __init pwec_init(void) { + const struct dmi_system_id *match; + const struct pwec_board_info *hwmon_data; int ret; - if (!dmi_check_system(pwec_dmi_table)) { + match = dmi_first_match(pwec_dmi_table); + if (!match) { if (!force) return -ENODEV; - pr_warn("force load portwell-ec without DMI check\n"); + hwmon_data = &pwec_board_info_default; + pr_warn("force load portwell-ec without DMI check, using full display config\n"); + } else { + hwmon_data = match->driver_data; } ret = platform_driver_register(&pwec_driver); if (ret) return ret; - pwec_dev = platform_device_register_simple("portwell-ec", -1, NULL, 0); + pwec_dev = platform_device_register_data(NULL, "portwell-ec", PLATFORM_DEVID_NONE, + hwmon_data, sizeof(*hwmon_data)); if (IS_ERR(pwec_dev)) { platform_driver_unregister(&pwec_driver); return PTR_ERR(pwec_dev); From 06ce29264f1d46f00fdb46b0c2d9fb060ce72368 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 3 Sep 2025 15:11:27 -0400 Subject: [PATCH 1502/2711] dt-bindings: rtc: pcf85063: remove quartz-load-femtofarads restriction for nxp,pcf85063 Original TXT binding doc have not limitition about quartz-load-femtofarads, which only allow 7000 for nxp,pcf85063. So remove it to fix below CHECK_DTBS warnings: arch/arm/boot/dts/nxp/imx/imx6dl-skov-revc-lt2.dtb: rtc@51 (nxp,pcf85063): quartz-load-femtofarads:0: 7000 was expected from schema $id: http://devicetree.org/schemas/rtc/nxp,pcf85063.yaml# Signed-off-by: Frank Li Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250903191128.439164-1-Frank.Li@nxp.com Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/nxp,pcf85063.yaml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml index 1e6277e524c2..f7013cd8fc20 100644 --- a/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml +++ b/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml @@ -62,16 +62,6 @@ allOf: then: properties: quartz-load-femtofarads: false - - if: - properties: - compatible: - contains: - enum: - - nxp,pcf85063 - then: - properties: - quartz-load-femtofarads: - const: 7000 - if: properties: compatible: From 0dbb84b5c447ddf2681ed0248a6fb7c9fc3fdb6c Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 27 Aug 2025 15:33:55 -0400 Subject: [PATCH 1503/2711] dt-bindings: rtc: trivial-rtc: add dallas,m41t00 Add compatible string dallas,m41t00 for dallas m41t00 RTC. Signed-off-by: Frank Li Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250827193356.78368-1-Frank.Li@nxp.com Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/trivial-rtc.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index 5e0c7cd25cc6..587b7cd5806c 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -38,6 +38,8 @@ properties: - dallas,ds1672 # Extremely Accurate I²C RTC with Integrated Crystal and SRAM - dallas,ds3232 + # Dallas m41t00 Real-time Clock + - dallas,m41t00 # SD2405AL Real-Time Clock - dfrobot,sd2405al # EM Microelectronic EM3027 RTC From d06b24f805b5c86c83f4182f32ed1cdd7c690171 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 30 Aug 2025 15:00:25 +0200 Subject: [PATCH 1504/2711] rtc: s3c: Drop unused defines Drop defines for S3C2416 and S3C2443 SoCs which are not used anywhere. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250830130024.142815-4-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/rtc/rtc-s3c.h b/drivers/rtc/rtc-s3c.h index 3552914aa611..44e9d6c9428f 100644 --- a/drivers/rtc/rtc-s3c.h +++ b/drivers/rtc/rtc-s3c.h @@ -24,22 +24,6 @@ #define S3C2410_TICNT S3C2410_RTCREG(0x44) #define S3C2410_TICNT_ENABLE (1 << 7) -/* S3C2443: tick count is 15 bit wide - * TICNT[6:0] contains upper 7 bits - * TICNT1[7:0] contains lower 8 bits - */ -#define S3C2443_TICNT_PART(x) ((x & 0x7f00) >> 8) -#define S3C2443_TICNT1 S3C2410_RTCREG(0x4C) -#define S3C2443_TICNT1_PART(x) (x & 0xff) - -/* S3C2416: tick count is 32 bit wide - * TICNT[6:0] contains bits [14:8] - * TICNT1[7:0] contains lower 8 bits - * TICNT2[16:0] contains upper 17 bits - */ -#define S3C2416_TICNT2 S3C2410_RTCREG(0x48) -#define S3C2416_TICNT2_PART(x) ((x & 0xffff8000) >> 15) - #define S3C2410_RTCALM S3C2410_RTCREG(0x50) #define S3C2410_RTCALM_ALMEN (1 << 6) #define S3C2410_RTCALM_YEAREN (1 << 5) From 9693342805748bcf0c02b16ac0a0aa852688dea9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 30 Aug 2025 15:00:26 +0200 Subject: [PATCH 1505/2711] rtc: s3c: Drop support for S3C2410 Samsung S3C24xx family of SoCs was removed the Linux kernel in the commit 61b7f8920b17 ("ARM: s3c: remove all s3c24xx support"), in January 2023. There are no in-kernel users of remaining S3C24xx compatibles. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250830130024.142815-5-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.c | 49 ++----------------------------------------- drivers/rtc/rtc-s3c.h | 3 --- 2 files changed, 2 insertions(+), 50 deletions(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 79b2a16f15ad..291c0ccb0acd 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -331,7 +331,7 @@ static const struct rtc_class_ops s3c_rtcops = { .alarm_irq_enable = s3c_rtc_setaie, }; -static void s3c24xx_rtc_enable(struct s3c_rtc *info) +static void s3c6410_rtc_enable(struct s3c_rtc *info) { unsigned int con, tmp; @@ -361,19 +361,6 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info) } } -static void s3c24xx_rtc_disable(struct s3c_rtc *info) -{ - unsigned int con; - - con = readw(info->base + S3C2410_RTCCON); - con &= ~S3C2410_RTCCON_RTCEN; - writew(con, info->base + S3C2410_RTCCON); - - con = readb(info->base + S3C2410_TICNT); - con &= ~S3C2410_TICNT_ENABLE; - writeb(con, info->base + S3C2410_TICNT); -} - static void s3c6410_rtc_disable(struct s3c_rtc *info) { unsigned int con; @@ -538,53 +525,21 @@ static int s3c_rtc_resume(struct device *dev) #endif static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume); -static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask) -{ - rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); -} - static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask) { rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); writeb(mask, info->base + S3C2410_INTP); } -static const struct s3c_rtc_data s3c2410_rtc_data = { - .irq_handler = s3c24xx_rtc_irq, - .enable = s3c24xx_rtc_enable, - .disable = s3c24xx_rtc_disable, -}; - -static const struct s3c_rtc_data s3c2416_rtc_data = { - .irq_handler = s3c24xx_rtc_irq, - .enable = s3c24xx_rtc_enable, - .disable = s3c24xx_rtc_disable, -}; - -static const struct s3c_rtc_data s3c2443_rtc_data = { - .irq_handler = s3c24xx_rtc_irq, - .enable = s3c24xx_rtc_enable, - .disable = s3c24xx_rtc_disable, -}; - static const struct s3c_rtc_data s3c6410_rtc_data = { .needs_src_clk = true, .irq_handler = s3c6410_rtc_irq, - .enable = s3c24xx_rtc_enable, + .enable = s3c6410_rtc_enable, .disable = s3c6410_rtc_disable, }; static const __maybe_unused struct of_device_id s3c_rtc_dt_match[] = { { - .compatible = "samsung,s3c2410-rtc", - .data = &s3c2410_rtc_data, - }, { - .compatible = "samsung,s3c2416-rtc", - .data = &s3c2416_rtc_data, - }, { - .compatible = "samsung,s3c2443-rtc", - .data = &s3c2443_rtc_data, - }, { .compatible = "samsung,s3c6410-rtc", .data = &s3c6410_rtc_data, }, { diff --git a/drivers/rtc/rtc-s3c.h b/drivers/rtc/rtc-s3c.h index 44e9d6c9428f..11d7a1255ce4 100644 --- a/drivers/rtc/rtc-s3c.h +++ b/drivers/rtc/rtc-s3c.h @@ -21,9 +21,6 @@ #define S3C2443_RTCCON_TICSEL (1 << 4) #define S3C64XX_RTCCON_TICEN (1 << 8) -#define S3C2410_TICNT S3C2410_RTCREG(0x44) -#define S3C2410_TICNT_ENABLE (1 << 7) - #define S3C2410_RTCALM S3C2410_RTCREG(0x50) #define S3C2410_RTCALM_ALMEN (1 << 6) #define S3C2410_RTCALM_YEAREN (1 << 5) From bf7ab18cd741ae82ee8d8e356f73ce3003f6b2fc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 30 Aug 2025 15:00:27 +0200 Subject: [PATCH 1506/2711] dt-bindings: rtc: s3c: Drop S3C2410 Samsung S3C24xx family of SoCs was removed the Linux kernel in the commit 61b7f8920b17 ("ARM: s3c: remove all s3c24xx support"), in January 2023. There are no in-kernel users of remaining S3C24xx compatibles. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250830130024.142815-6-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/s3c-rtc.yaml | 40 ++----------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml b/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml index bf4e11d6dffb..338874e7ed7f 100644 --- a/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml @@ -13,9 +13,6 @@ properties: compatible: oneOf: - enum: - - samsung,s3c2410-rtc - - samsung,s3c2416-rtc - - samsung,s3c2443-rtc - samsung,s3c6410-rtc - items: - enum: @@ -29,19 +26,12 @@ properties: maxItems: 1 clocks: - description: - Must contain a list of phandle and clock specifier for the rtc - clock and in the case of a s3c6410 compatible controller, also - a source clock. - minItems: 1 maxItems: 2 clock-names: - description: - Must contain "rtc" and for a s3c6410 compatible controller - also "rtc_src". - minItems: 1 - maxItems: 2 + items: + - const: rtc + - const: rtc_src interrupts: description: @@ -54,30 +44,6 @@ properties: allOf: - $ref: rtc.yaml# - - if: - properties: - compatible: - contains: - enum: - - samsung,s3c6410-rtc - - samsung,exynos3250-rtc - then: - properties: - clocks: - minItems: 2 - maxItems: 2 - clock-names: - items: - - const: rtc - - const: rtc_src - else: - properties: - clocks: - minItems: 1 - maxItems: 1 - clock-names: - items: - - const: rtc unevaluatedProperties: false From a6f1a4f05970664004a9370459c6799c1b2f2dcf Mon Sep 17 00:00:00 2001 From: Josua Mayer Date: Mon, 25 Aug 2025 19:54:09 +0200 Subject: [PATCH 1507/2711] rtc: pcf2127: clear minute/second interrupt PCF2127 can generate interrupt every full second or minute configured from control and status register 1, bits MI (1) and SI (0). On interrupt control register 2 bit MSF (7) is set and must be cleared to continue normal operation. While the driver never enables this interrupt on its own, users or firmware may do so - e.g. as an easy way to test the interrupt. Add preprocessor definition for MSF bit and include it in the irq bitmask to ensure minute and second interrupts are cleared when fired. This fixes an issue where the rtc enters a test mode and becomes unresponsive after a second interrupt has fired and is not cleared in time. In this state register writes to control registers have no effect and the interrupt line is kept asserted [1]: [1] userspace commands to put rtc into unresponsive state: $ i2cget -f -y 2 0x51 0x00 0x04 $ i2cset -f -y 2 0x51 0x00 0x05 # set bit 0 SI $ i2cget -f -y 2 0x51 0x00 0x84 # bit 8 EXT_TEST set $ i2cset -f -y 2 0x51 0x00 0x05 # try overwrite control register $ i2cget -f -y 2 0x51 0x00 0x84 # no change Signed-off-by: Josua Mayer Reviewed-by: Bruno Thomsen Link: https://lore.kernel.org/r/20250825-rtc-irq-v1-1-0133319406a7@solid-run.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 2e1ac0c42e93..3ba1de30e89c 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -42,6 +42,7 @@ #define PCF2127_BIT_CTRL2_AF BIT(4) #define PCF2127_BIT_CTRL2_TSF2 BIT(5) #define PCF2127_BIT_CTRL2_WDTF BIT(6) +#define PCF2127_BIT_CTRL2_MSF BIT(7) /* Control register 3 */ #define PCF2127_REG_CTRL3 0x02 #define PCF2127_BIT_CTRL3_BLIE BIT(0) @@ -96,7 +97,8 @@ #define PCF2127_CTRL2_IRQ_MASK ( \ PCF2127_BIT_CTRL2_AF | \ PCF2127_BIT_CTRL2_WDTF | \ - PCF2127_BIT_CTRL2_TSF2) + PCF2127_BIT_CTRL2_TSF2 | \ + PCF2127_BIT_CTRL2_MSF) #define PCF2127_MAX_TS_SUPPORTED 4 From 18a3510bc87d48deec0abb72bc9e0b2f8393ff0b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 14 Jul 2025 08:08:45 +0200 Subject: [PATCH 1508/2711] rtc: efi: Remove wakeup functionality The EFI rtc driver is used by non-x86 architectures only, and exposes the get/set wakeup time functionality provided by the underlying platform. This is usually broken on most platforms, and not widely used to begin with [if at all], so let's just remove it. Signed-off-by: Ard Biesheuvel Tested-by: Feng Tang Link: https://lore.kernel.org/r/20250714060843.4029171-6-ardb+git@google.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-efi.c | 76 ++----------------------------------------- 1 file changed, 2 insertions(+), 74 deletions(-) diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index fa8bf82df948..b4f44999ef0f 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -112,48 +112,6 @@ convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime) return true; } -static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) -{ - efi_time_t eft; - efi_status_t status; - - /* - * As of EFI v1.10, this call always returns an unsupported status - */ - status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled, - (efi_bool_t *)&wkalrm->pending, &eft); - - if (status != EFI_SUCCESS) - return -EINVAL; - - if (!convert_from_efi_time(&eft, &wkalrm->time)) - return -EIO; - - return rtc_valid_tm(&wkalrm->time); -} - -static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) -{ - efi_time_t eft; - efi_status_t status; - - convert_to_efi_time(&wkalrm->time, &eft); - - /* - * XXX Fixme: - * As of EFI 0.92 with the firmware I have on my - * machine this call does not seem to work quite - * right - * - * As of v1.10, this call always returns an unsupported status - */ - status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft); - - dev_warn(dev, "write status is %d\n", (int)status); - - return status == EFI_SUCCESS ? 0 : -EINVAL; -} - static int efi_read_time(struct device *dev, struct rtc_time *tm) { efi_status_t status; @@ -188,17 +146,13 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm) static int efi_procfs(struct device *dev, struct seq_file *seq) { - efi_time_t eft, alm; + efi_time_t eft; efi_time_cap_t cap; - efi_bool_t enabled, pending; - struct rtc_device *rtc = dev_get_drvdata(dev); memset(&eft, 0, sizeof(eft)); - memset(&alm, 0, sizeof(alm)); memset(&cap, 0, sizeof(cap)); efi.get_time(&eft, &cap); - efi.get_wakeup_time(&enabled, &pending, &alm); seq_printf(seq, "Time\t\t: %u:%u:%u.%09u\n" @@ -214,26 +168,6 @@ static int efi_procfs(struct device *dev, struct seq_file *seq) /* XXX fixme: convert to string? */ seq_printf(seq, "Timezone\t: %u\n", eft.timezone); - if (test_bit(RTC_FEATURE_ALARM, rtc->features)) { - seq_printf(seq, - "Alarm Time\t: %u:%u:%u.%09u\n" - "Alarm Date\t: %u-%u-%u\n" - "Alarm Daylight\t: %u\n" - "Enabled\t\t: %s\n" - "Pending\t\t: %s\n", - alm.hour, alm.minute, alm.second, alm.nanosecond, - alm.year, alm.month, alm.day, - alm.daylight, - enabled == 1 ? "yes" : "no", - pending == 1 ? "yes" : "no"); - - if (alm.timezone == EFI_UNSPECIFIED_TIMEZONE) - seq_puts(seq, "Timezone\t: unspecified\n"); - else - /* XXX fixme: convert to string? */ - seq_printf(seq, "Timezone\t: %u\n", alm.timezone); - } - /* * now prints the capabilities */ @@ -249,8 +183,6 @@ static int efi_procfs(struct device *dev, struct seq_file *seq) static const struct rtc_class_ops efi_rtc_ops = { .read_time = efi_read_time, .set_time = efi_set_time, - .read_alarm = efi_read_alarm, - .set_alarm = efi_set_alarm, .proc = efi_procfs, }; @@ -271,11 +203,7 @@ static int __init efi_rtc_probe(struct platform_device *dev) platform_set_drvdata(dev, rtc); rtc->ops = &efi_rtc_ops; - clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); - if (efi_rt_services_supported(EFI_RT_SUPPORTED_WAKEUP_SERVICES)) - set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features); - else - clear_bit(RTC_FEATURE_ALARM, rtc->features); + clear_bit(RTC_FEATURE_ALARM, rtc->features); device_init_wakeup(&dev->dev, true); From 84454c4e504b1fe86f77a898190d63b4193ca25d Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 7 Aug 2025 16:44:13 -0500 Subject: [PATCH 1509/2711] dt-bindings: rtc: Drop isil,isl12057.txt The "isil,isl12057" compatible is already supported by rtc-ds1307.yaml, so remove the old text binding. Signed-off-by: Rob Herring (Arm) Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250807214414.4172910-1-robh@kernel.org Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/isil,isl12057.txt | 74 ------------------- 1 file changed, 74 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/isil,isl12057.txt diff --git a/Documentation/devicetree/bindings/rtc/isil,isl12057.txt b/Documentation/devicetree/bindings/rtc/isil,isl12057.txt deleted file mode 100644 index ff7c43555199..000000000000 --- a/Documentation/devicetree/bindings/rtc/isil,isl12057.txt +++ /dev/null @@ -1,74 +0,0 @@ -Intersil ISL12057 I2C RTC/Alarm chip - -ISL12057 is a trivial I2C device (it has simple device tree bindings, -consisting of a compatible field, an address and possibly an interrupt -line). - -Nonetheless, it also supports an option boolean property -("wakeup-source") to handle the specific use-case found -on at least three in-tree users of the chip (NETGEAR ReadyNAS 102, 104 -and 2120 ARM-based NAS); On those devices, the IRQ#2 pin of the chip -(associated with the alarm supported by the driver) is not connected -to the SoC but to a PMIC. It allows the device to be powered up when -RTC alarm rings. In order to mark the device has a wakeup source and -get access to the 'wakealarm' sysfs entry, this specific property can -be set when the IRQ#2 pin of the chip is not connected to the SoC but -can wake up the device. - -Required properties supported by the device: - - - "compatible": must be "isil,isl12057" - - "reg": I2C bus address of the device - -Optional properties: - - - "wakeup-source": mark the chip as a wakeup source, independently of - the availability of an IRQ line connected to the SoC. - - -Example isl12057 node without IRQ#2 pin connected (no alarm support): - - isl12057: isl12057@68 { - compatible = "isil,isl12057"; - reg = <0x68>; - }; - - -Example isl12057 node with IRQ#2 pin connected to main SoC via MPP6 (note -that the pinctrl-related properties below are given for completeness and -may not be required or may be different depending on your system or -SoC, and the main function of the MPP used as IRQ line, i.e. -"interrupt-parent" and "interrupts" are usually sufficient): - - pinctrl { - ... - - rtc_alarm_pin: rtc_alarm_pin { - marvell,pins = "mpp6"; - marvell,function = "gpio"; - }; - - ... - - }; - - ... - - isl12057: isl12057@68 { - compatible = "isil,isl12057"; - reg = <0x68>; - pinctrl-0 = <&rtc_alarm_pin>; - pinctrl-names = "default"; - interrupt-parent = <&gpio0>; - interrupts = <6 IRQ_TYPE_EDGE_FALLING>; - }; - - -Example isl12057 node without IRQ#2 pin connected to the SoC but to a -PMIC, allowing the device to be started based on configured alarm: - - isl12057: isl12057@68 { - compatible = "isil,isl12057"; - reg = <0x68>; - wakeup-source; - }; From f0ea5f6e75f6b8bbe5d393720bfaf804d04e383f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 13 Aug 2025 18:15:03 +0200 Subject: [PATCH 1510/2711] rtc: remove unneeded 'fast_io' parameter in regmap_config When using MMIO with regmap, fast_io is implied. No need to set it again. Signed-off-by: Wolfram Sang Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250813161517.4746-18-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-meson.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-meson.c b/drivers/rtc/rtc-meson.c index 47e9ebf58ffc..21eceb9e2e13 100644 --- a/drivers/rtc/rtc-meson.c +++ b/drivers/rtc/rtc-meson.c @@ -72,7 +72,6 @@ static const struct regmap_config meson_rtc_peripheral_regmap_config = { .val_bits = 32, .reg_stride = 4, .max_register = RTC_REG4, - .fast_io = true, }; /* RTC front-end serialiser controls */ From f2e44e5fb2de9a464b4fc94d8de071da7ebfda15 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 21 Aug 2025 16:57:01 -0500 Subject: [PATCH 1511/2711] dt-bindings: rtc: Fix Xicor X1205 vendor prefix The vendor for the Xircom X1205 RTC is not Xircom, but Xicor which was acquired by Intersil. Signed-off-by: Rob Herring (Arm) Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20250821215703.869628-1-robh@kernel.org Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/trivial-rtc.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index 587b7cd5806c..b47822370d6f 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -85,8 +85,8 @@ properties: - via,vt8500-rtc # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC - whwave,sd3078 - # Xircom X1205 I2C RTC - - xircom,x1205 + # Xicor/Intersil X1205 I2C RTC + - xicor,x1205 reg: maxItems: 1 From 606d19ee37de3a72f1b6e95a4ea544f6f20dbb46 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 21 Aug 2025 16:57:02 -0500 Subject: [PATCH 1512/2711] rtc: x1205: Fix Xicor X1205 vendor prefix The vendor for the X1205 RTC is not Xircom, but Xicor which was acquired by Intersil. Since the I2C subsystem drops the vendor prefix for driver matching, the vendor prefix hasn't mattered. Fixes: 6875404fdb44 ("rtc: x1205: Add DT probing support") Signed-off-by: Rob Herring (Arm) Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20250821215703.869628-2-robh@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-x1205.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 4bcd7ca32f27..b8a0fccef14e 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -669,7 +669,7 @@ static const struct i2c_device_id x1205_id[] = { MODULE_DEVICE_TABLE(i2c, x1205_id); static const struct of_device_id x1205_dt_ids[] = { - { .compatible = "xircom,x1205", }, + { .compatible = "xicor,x1205", }, {}, }; MODULE_DEVICE_TABLE(of, x1205_dt_ids); From a531350d2fe58f7fc4516e555f22391dee94efd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Goffic?= Date: Tue, 15 Jul 2025 16:07:13 +0200 Subject: [PATCH 1513/2711] rtc: optee: fix memory leak on driver removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a memory leak in case of driver removal. Free the shared memory used for arguments exchanges between kernel and OP-TEE RTC PTA. Fixes: 81c2f059ab90 ("rtc: optee: add RTC driver for OP-TEE RTC PTA") Signed-off-by: Clément Le Goffic Link: https://lore.kernel.org/r/20250715-upstream-optee-rtc-v1-1-e0fdf8aae545@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-optee.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-optee.c b/drivers/rtc/rtc-optee.c index 9f8b5d4a8f6b..6b77c122fdc1 100644 --- a/drivers/rtc/rtc-optee.c +++ b/drivers/rtc/rtc-optee.c @@ -320,6 +320,7 @@ static int optee_rtc_remove(struct device *dev) { struct optee_rtc *priv = dev_get_drvdata(dev); + tee_shm_free(priv->shm); tee_client_close_session(priv->ctx, priv->session_id); tee_client_close_context(priv->ctx); From 44fee00f2139894b2ae4433f0661d70134b511c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Goffic?= Date: Tue, 15 Jul 2025 16:07:14 +0200 Subject: [PATCH 1514/2711] rtc: optee: remove unnecessary memory operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove memcpy by using directly the shared memory. Remove memset be initialize variable to 0 on stack. Signed-off-by: Clément Le Goffic Link: https://lore.kernel.org/r/20250715-upstream-optee-rtc-v1-2-e0fdf8aae545@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-optee.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/rtc/rtc-optee.c b/drivers/rtc/rtc-optee.c index 6b77c122fdc1..b65953eb7ca1 100644 --- a/drivers/rtc/rtc-optee.c +++ b/drivers/rtc/rtc-optee.c @@ -97,18 +97,9 @@ static int optee_rtc_settime(struct device *dev, struct rtc_time *tm) struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[4] = {0}; - struct optee_rtc_time optee_tm; - void *rtc_data; + struct optee_rtc_time *optee_tm; int ret; - optee_tm.tm_sec = tm->tm_sec; - optee_tm.tm_min = tm->tm_min; - optee_tm.tm_hour = tm->tm_hour; - optee_tm.tm_mday = tm->tm_mday; - optee_tm.tm_mon = tm->tm_mon; - optee_tm.tm_year = tm->tm_year + 1900; - optee_tm.tm_wday = tm->tm_wday; - inv_arg.func = TA_CMD_RTC_SET_TIME; inv_arg.session = priv->session_id; inv_arg.num_params = 4; @@ -117,11 +108,17 @@ static int optee_rtc_settime(struct device *dev, struct rtc_time *tm) param[0].u.memref.shm = priv->shm; param[0].u.memref.size = sizeof(struct optee_rtc_time); - rtc_data = tee_shm_get_va(priv->shm, 0); - if (IS_ERR(rtc_data)) - return PTR_ERR(rtc_data); + optee_tm = tee_shm_get_va(priv->shm, 0); + if (IS_ERR(optee_tm)) + return PTR_ERR(optee_tm); - memcpy(rtc_data, &optee_tm, sizeof(struct optee_rtc_time)); + optee_tm->tm_min = tm->tm_min; + optee_tm->tm_sec = tm->tm_sec; + optee_tm->tm_hour = tm->tm_hour; + optee_tm->tm_mday = tm->tm_mday; + optee_tm->tm_mon = tm->tm_mon; + optee_tm->tm_year = tm->tm_year + 1900; + optee_tm->tm_wday = tm->tm_wday; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) @@ -241,14 +238,12 @@ static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) static int optee_rtc_probe(struct device *dev) { struct tee_client_device *rtc_device = to_tee_client_device(dev); - struct tee_ioctl_open_session_arg sess_arg; + struct tee_ioctl_open_session_arg sess_arg = {0}; struct optee_rtc *priv; struct rtc_device *rtc; struct tee_shm *shm; int ret, err; - memset(&sess_arg, 0, sizeof(sess_arg)); - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; From 6266aea864fa5484f6e8313f913a69e794765fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Goffic?= Date: Tue, 15 Jul 2025 16:07:15 +0200 Subject: [PATCH 1515/2711] rtc: optee: add alarm related rtc ops to optee rtc driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add read_alarm and set_alarm ops from the rtc framework. The support of an alarm is handled by a kernel thread waiting in OP-TEE for an asynchronous notification that comes in the interrupt handler of the alarm interruption on OP-TEE secure world. Once the notification arrives, the kernel thread previously suspended is rescheduled (this is handled by the OP-TEE kernel driver) and comes back with the alarm information to the kernel. A second session is therefore needed to enable/disable/cancel a waiting alarm event as the kernel thread stopped in OP-TEE takes a form of mutex on the session and so no one can use this session in parallel. Signed-off-by: Clément Le Goffic Link: https://lore.kernel.org/r/20250715-upstream-optee-rtc-v1-3-e0fdf8aae545@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-optee.c | 434 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 413 insertions(+), 21 deletions(-) diff --git a/drivers/rtc/rtc-optee.c b/drivers/rtc/rtc-optee.c index b65953eb7ca1..27db403e3047 100644 --- a/drivers/rtc/rtc-optee.c +++ b/drivers/rtc/rtc-optee.c @@ -5,19 +5,104 @@ #include #include +#include #include #include #include -#define RTC_INFO_VERSION 0x1 +#define RTC_INFO_VERSION 0x1 -#define TA_CMD_RTC_GET_INFO 0x0 -#define TA_CMD_RTC_GET_TIME 0x1 -#define TA_CMD_RTC_SET_TIME 0x2 -#define TA_CMD_RTC_GET_OFFSET 0x3 -#define TA_CMD_RTC_SET_OFFSET 0x4 +#define TA_RTC_FEATURE_CORRECTION BIT(0) +#define TA_RTC_FEATURE_ALARM BIT(1) +#define TA_RTC_FEATURE_WAKEUP_ALARM BIT(2) -#define TA_RTC_FEATURE_CORRECTION BIT(0) +enum rtc_optee_pta_cmd { + /* PTA_CMD_RTC_GET_INFO - Get RTC information + * + * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_info + */ + PTA_CMD_RTC_GET_INF = 0x0, + + /* + * PTA_CMD_RTC_GET_TIME - Get time from RTC + * + * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_time + */ + PTA_CMD_RTC_GET_TIME = 0x1, + + /* + * PTA_CMD_RTC_SET_TIME - Set time from RTC + * + * [in] memref[0] RTC buffer memory reference containing a struct pta_rtc_time to be + * used as RTC time + */ + PTA_CMD_RTC_SET_TIME = 0x2, + + /* + * PTA_CMD_RTC_GET_OFFSET - Get RTC offset + * + * [out] value[0].a RTC offset (signed 32bit value) + */ + PTA_CMD_RTC_GET_OFFSET = 0x3, + + /* + * PTA_CMD_RTC_SET_OFFSET - Set RTC offset + * + * [in] value[0].a RTC offset to be set (signed 32bit value) + */ + PTA_CMD_RTC_SET_OFFSET = 0x4, + + /* + * PTA_CMD_RTC_READ_ALARM - Read RTC alarm + * + * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_alarm + */ + PTA_CMD_RTC_READ_ALARM = 0x5, + + /* + * PTA_CMD_RTC_SET_ALARM - Set RTC alarm + * + * [in] memref[0] RTC buffer memory reference containing a struct pta_rtc_alarm to be + * used as RTC alarm + */ + PTA_CMD_RTC_SET_ALARM = 0x6, + + /* + * PTA_CMD_RTC_ENABLE_ALARM - Enable Alarm + * + * [in] value[0].a RTC IRQ flag (uint32_t), 0 to disable the alarm, 1 to enable + */ + PTA_CMD_RTC_ENABLE_ALARM = 0x7, + + /* + * PTA_CMD_RTC_WAIT_ALARM - Get alarm event + * + * [out] value[0].a RTC wait alarm return status (uint32_t): + * - 0: No alarm event + * - 1: Alarm event occurred + * - 2: Alarm event canceled + */ + PTA_CMD_RTC_WAIT_ALARM = 0x8, + + /* + * PTA_CMD_RTC_CANCEL_WAIT - Cancel wait for alarm event + */ + PTA_CMD_RTC_CANCEL_WAIT = 0x9, + + /* + * PTA_CMD_RTC_SET_WAKE_ALARM_STATUS - Set RTC wake alarm status flag + * + * [in] value[0].a RTC IRQ wake alarm flag (uint32_t), 0 to disable the wake up + * capability, 1 to enable. + */ + PTA_CMD_RTC_SET_WAKE_ALARM_STATUS = 0xA, +}; + +enum rtc_wait_alarm_status { + WAIT_ALARM_RESET = 0x0, + WAIT_ALARM_ALARM_OCCURRED = 0x1, + WAIT_ALARM_CANCELED = 0x2, +}; struct optee_rtc_time { u32 tm_sec; @@ -29,6 +114,12 @@ struct optee_rtc_time { u32 tm_wday; }; +struct optee_rtc_alarm { + u8 enabled; + u8 pending; + struct optee_rtc_time time; +}; + struct optee_rtc_info { u64 version; u64 features; @@ -41,15 +132,21 @@ struct optee_rtc_info { * @dev: OP-TEE based RTC device. * @ctx: OP-TEE context handler. * @session_id: RTC TA session identifier. + * @session2_id: RTC wait alarm session identifier. * @shm: Memory pool shared with RTC device. * @features: Bitfield of RTC features + * @alarm_task: RTC wait alamr task. + * @rtc: RTC device. */ struct optee_rtc { struct device *dev; struct tee_context *ctx; u32 session_id; + u32 session2_id; struct tee_shm *shm; u64 features; + struct task_struct *alarm_task; + struct rtc_device *rtc; }; static int optee_rtc_readtime(struct device *dev, struct rtc_time *tm) @@ -60,7 +157,7 @@ static int optee_rtc_readtime(struct device *dev, struct rtc_time *tm) struct tee_param param[4] = {0}; int ret; - inv_arg.func = TA_CMD_RTC_GET_TIME; + inv_arg.func = PTA_CMD_RTC_GET_TIME; inv_arg.session = priv->session_id; inv_arg.num_params = 4; @@ -100,7 +197,7 @@ static int optee_rtc_settime(struct device *dev, struct rtc_time *tm) struct optee_rtc_time *optee_tm; int ret; - inv_arg.func = TA_CMD_RTC_SET_TIME; + inv_arg.func = PTA_CMD_RTC_SET_TIME; inv_arg.session = priv->session_id; inv_arg.num_params = 4; @@ -137,7 +234,7 @@ static int optee_rtc_readoffset(struct device *dev, long *offset) if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) return -EOPNOTSUPP; - inv_arg.func = TA_CMD_RTC_GET_OFFSET; + inv_arg.func = PTA_CMD_RTC_GET_OFFSET; inv_arg.session = priv->session_id; inv_arg.num_params = 4; @@ -162,7 +259,7 @@ static int optee_rtc_setoffset(struct device *dev, long offset) if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) return -EOPNOTSUPP; - inv_arg.func = TA_CMD_RTC_SET_OFFSET; + inv_arg.func = PTA_CMD_RTC_SET_OFFSET; inv_arg.session = priv->session_id; inv_arg.num_params = 4; @@ -176,13 +273,228 @@ static int optee_rtc_setoffset(struct device *dev, long offset) return 0; } +static int optee_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct optee_rtc_alarm *optee_alarm; + struct tee_param param[1] = {0}; + int ret; + + if (!(priv->features & TA_RTC_FEATURE_ALARM)) + return -EOPNOTSUPP; + + inv_arg.func = PTA_CMD_RTC_READ_ALARM; + inv_arg.session = priv->session_id; + inv_arg.num_params = 1; + + /* Fill invoke cmd params */ + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; + param[0].u.memref.shm = priv->shm; + param[0].u.memref.size = sizeof(struct optee_rtc_alarm); + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + optee_alarm = tee_shm_get_va(priv->shm, 0); + if (IS_ERR(optee_alarm)) + return PTR_ERR(alarm); + + if (param[0].u.memref.size != sizeof(*optee_alarm)) + return -EPROTO; + + alarm->enabled = optee_alarm->enabled; + alarm->pending = optee_alarm->pending; + alarm->time.tm_sec = optee_alarm->time.tm_sec; + alarm->time.tm_min = optee_alarm->time.tm_min; + alarm->time.tm_hour = optee_alarm->time.tm_hour; + alarm->time.tm_mday = optee_alarm->time.tm_mday; + alarm->time.tm_mon = optee_alarm->time.tm_mon; + alarm->time.tm_year = optee_alarm->time.tm_year - 1900; + alarm->time.tm_wday = optee_alarm->time.tm_wday; + alarm->time.tm_yday = rtc_year_days(alarm->time.tm_mday, + alarm->time.tm_mon, + alarm->time.tm_year); + + return 0; +} + +static int optee_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct optee_rtc_alarm *optee_alarm; + struct tee_param param[1] = {0}; + int ret; + + if (!(priv->features & TA_RTC_FEATURE_ALARM)) + return -EOPNOTSUPP; + + inv_arg.func = PTA_CMD_RTC_SET_ALARM; + inv_arg.session = priv->session_id; + inv_arg.num_params = 1; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; + param[0].u.memref.shm = priv->shm; + param[0].u.memref.size = sizeof(struct optee_rtc_alarm); + + optee_alarm = tee_shm_get_va(priv->shm, 0); + if (IS_ERR(optee_alarm)) + return PTR_ERR(optee_alarm); + + optee_alarm->enabled = alarm->enabled; + optee_alarm->pending = alarm->pending; + optee_alarm->time.tm_sec = alarm->time.tm_sec; + optee_alarm->time.tm_min = alarm->time.tm_min; + optee_alarm->time.tm_hour = alarm->time.tm_hour; + optee_alarm->time.tm_mday = alarm->time.tm_mday; + optee_alarm->time.tm_mon = alarm->time.tm_mon; + optee_alarm->time.tm_year = alarm->time.tm_year + 1900; + optee_alarm->time.tm_wday = alarm->time.tm_wday; + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + return 0; +} + +static int optee_rtc_enable_alarm(struct device *dev, unsigned int enabled) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct tee_param param[1] = {0}; + int ret; + + if (!(priv->features & TA_RTC_FEATURE_ALARM)) + return -EOPNOTSUPP; + + inv_arg.func = PTA_CMD_RTC_ENABLE_ALARM; + inv_arg.session = priv->session_id; + inv_arg.num_params = 1; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; + param[0].u.value.a = (bool)enabled; + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + return 0; +} + static const struct rtc_class_ops optee_rtc_ops = { - .read_time = optee_rtc_readtime, - .set_time = optee_rtc_settime, - .set_offset = optee_rtc_setoffset, - .read_offset = optee_rtc_readoffset, + .read_time = optee_rtc_readtime, + .set_time = optee_rtc_settime, + .set_offset = optee_rtc_setoffset, + .read_offset = optee_rtc_readoffset, + .read_alarm = optee_rtc_read_alarm, + .set_alarm = optee_rtc_set_alarm, + .alarm_irq_enable = optee_rtc_enable_alarm, }; +static int optee_rtc_wait_alarm(struct device *dev, int *return_status) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct tee_param param[1] = {0}; + int ret; + + if (!(priv->features & TA_RTC_FEATURE_ALARM)) + return -EOPNOTSUPP; + + inv_arg.func = PTA_CMD_RTC_WAIT_ALARM; + inv_arg.session = priv->session2_id; + inv_arg.num_params = 1; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + *return_status = param[0].u.value.a; + + return 0; +} + +static int optee_rtc_cancel_wait_alarm(struct device *dev) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct tee_param param[1] = {0}; + int ret; + + if (!(priv->features & TA_RTC_FEATURE_ALARM)) + return -EOPNOTSUPP; + + inv_arg.func = PTA_CMD_RTC_CANCEL_WAIT; + inv_arg.session = priv->session_id; + inv_arg.num_params = 0; + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + return 0; +} + +static int optee_rtc_set_alarm_wake_status(struct device *dev, bool status) +{ + struct optee_rtc *priv = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = {0}; + struct tee_param param[1] = {0}; + int ret; + + if (!(priv->features & TA_RTC_FEATURE_ALARM)) + return -EOPNOTSUPP; + + inv_arg.func = PTA_CMD_RTC_SET_WAKE_ALARM_STATUS; + inv_arg.session = priv->session_id; + inv_arg.num_params = 1; + + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; + param[0].u.value.a = status; + + ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); + + if (ret < 0 || inv_arg.ret != 0) + return ret ? ret : -EPROTO; + + return 0; +} + +static int optee_rtc_handle_alarm_event(void *data) +{ + struct optee_rtc *priv = (struct optee_rtc *)data; + int wait_alarm_return_status = 0; + int ret; + + while (!kthread_should_stop()) { + ret = optee_rtc_wait_alarm(priv->dev, &wait_alarm_return_status); + if (ret) { + dev_err(priv->dev, "Failed to wait for alarm: %d\n", ret); + return ret; + } + switch (wait_alarm_return_status) { + case WAIT_ALARM_ALARM_OCCURRED: + dev_dbg(priv->dev, "Alarm occurred\n"); + rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF); + break; + case WAIT_ALARM_CANCELED: + dev_dbg(priv->dev, "Alarm canceled\n"); + break; + default: + dev_warn(priv->dev, "Unknown return status: %d\n", + wait_alarm_return_status); + break; + } + } + + return 0; +} + static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc, u64 *features) { @@ -193,7 +505,7 @@ static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc, struct optee_rtc_time *tm; int ret; - inv_arg.func = TA_CMD_RTC_GET_INFO; + inv_arg.func = PTA_CMD_RTC_GET_INF; inv_arg.session = priv->session_id; inv_arg.num_params = 4; @@ -238,6 +550,7 @@ static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) static int optee_rtc_probe(struct device *dev) { struct tee_client_device *rtc_device = to_tee_client_device(dev); + struct tee_ioctl_open_session_arg sess2_arg = {0}; struct tee_ioctl_open_session_arg sess_arg = {0}; struct optee_rtc *priv; struct rtc_device *rtc; @@ -252,12 +565,14 @@ static int optee_rtc_probe(struct device *dev) if (IS_ERR(rtc)) return PTR_ERR(rtc); + priv->rtc = rtc; + /* Open context with TEE driver */ priv->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(priv->ctx)) return -ENODEV; - /* Open session with rtc Trusted App */ + /* Open first session with rtc Pseudo Trusted App */ export_uuid(sess_arg.uuid, &rtc_device->id.uuid); sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL; @@ -269,6 +584,11 @@ static int optee_rtc_probe(struct device *dev) } priv->session_id = sess_arg.session; + /* + * Shared memory is used for passing an instance of either struct optee_rtc_info, + * struct optee_rtc_time or struct optee_rtc_alarm to OP-TEE service. + * The former is by definition large enough to cover both parameter cases. + */ shm = tee_shm_alloc_kernel_buf(priv->ctx, sizeof(struct optee_rtc_info)); if (IS_ERR(shm)) { dev_err(priv->dev, "tee_shm_alloc_kernel_buf failed\n"); @@ -288,19 +608,69 @@ static int optee_rtc_probe(struct device *dev) goto out_shm; } + /* Handle feature's related setup before registering to rtc framework */ + if (priv->features & TA_RTC_FEATURE_ALARM) { + priv->alarm_task = kthread_create(optee_rtc_handle_alarm_event, + priv, "rtc_alarm_evt"); + if (IS_ERR(priv->alarm_task)) { + dev_err(dev, "Failed to create alarm thread\n"); + goto out_shm; + } + + /* + * In case of supported alarm feature on optee side, we create a kthread + * that will, in a new optee session, call a PTA interface "rtc_wait_alarm". + * This call return in case of alarm and in case of canceled alarm. + * The new optee session is therefore only needed in this case as we cannot + * use the same session for parallel calls to optee PTA. + * Hence one session is reserved to wait for alarms and the other to make + * standard calls to RTC PTA. + */ + + /* Open second session with rtc Trusted App */ + export_uuid(sess2_arg.uuid, &rtc_device->id.uuid); + sess2_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL; + + ret = tee_client_open_session(priv->ctx, &sess2_arg, NULL); + if (ret < 0 || sess2_arg.ret != 0) { + dev_err(dev, "tee_client_open_session failed, err: %x\n", sess2_arg.ret); + err = -EINVAL; + goto out_thrd; + } + priv->session2_id = sess2_arg.session; + + if (priv->features & TA_RTC_FEATURE_WAKEUP_ALARM) + device_init_wakeup(dev, true); + } + err = devm_rtc_register_device(rtc); if (err) - goto out_shm; + goto out_wk; /* - * We must clear this bit after registering because rtc_register_device - * will set it if it sees that .set_offset is provided. + * We must clear those bits after registering because registering a rtc_device + * will set them if it sees that .set_offset and .set_alarm are provided. */ if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) clear_bit(RTC_FEATURE_CORRECTION, rtc->features); + if (!(priv->features & TA_RTC_FEATURE_ALARM)) + clear_bit(RTC_FEATURE_ALARM, rtc->features); + + /* Start the thread after the rtc is setup */ + if (priv->alarm_task) { + wake_up_process(priv->alarm_task); + dev_dbg(dev, "Wait alarm thread successfully started\n"); + } return 0; - +out_wk: + if (priv->features & TA_RTC_FEATURE_ALARM) { + device_init_wakeup(dev, false); + tee_client_close_session(priv->ctx, priv->session2_id); + } +out_thrd: + if (priv->features & TA_RTC_FEATURE_ALARM) + kthread_stop(priv->alarm_task); out_shm: tee_shm_free(priv->shm); out_sess: @@ -315,6 +685,13 @@ static int optee_rtc_remove(struct device *dev) { struct optee_rtc *priv = dev_get_drvdata(dev); + if (priv->features & TA_RTC_FEATURE_ALARM) { + optee_rtc_cancel_wait_alarm(dev); + kthread_stop(priv->alarm_task); + device_init_wakeup(dev, false); + tee_client_close_session(priv->ctx, priv->session2_id); + } + tee_shm_free(priv->shm); tee_client_close_session(priv->ctx, priv->session_id); tee_client_close_context(priv->ctx); @@ -322,6 +699,20 @@ static int optee_rtc_remove(struct device *dev) return 0; } +static int optee_rtc_suspend(struct device *dev) +{ + int res = optee_rtc_set_alarm_wake_status(dev, device_may_wakeup(dev)); + + if (res) { + dev_err(dev, "Unable to transmit wakeup information to optee rtc\n"); + return res; + } + + return 0; +} + +DEFINE_SIMPLE_DEV_PM_OPS(optee_rtc_pm_ops, optee_rtc_suspend, NULL); + static const struct tee_client_device_id optee_rtc_id_table[] = { {UUID_INIT(0xf389f8c8, 0x845f, 0x496c, 0x8b, 0xbe, 0xd6, 0x4b, 0xd2, 0x4c, 0x92, 0xfd)}, @@ -337,6 +728,7 @@ static struct tee_client_driver optee_rtc_driver = { .bus = &tee_bus_type, .probe = optee_rtc_probe, .remove = optee_rtc_remove, + .pm = pm_sleep_ptr(&optee_rtc_pm_ops), }, }; From a6de182daa2b1a627d88a594526a0db4ac1e396e Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Aug 2025 12:20:53 -0500 Subject: [PATCH 1516/2711] rtc: spacemit: support the SpacemiT P1 RTC Add support for the RTC found in the SpacemiT P1 PMIC. Initially only setting and reading the time are supported. The PMIC is implemented as a multi-function device. This RTC is probed based on this driver being named in a MFD cell in the simple MFD I2C driver. Signed-off-by: Alex Elder Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20250825172057.163883-5-elder@riscstar.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-spacemit-p1.c | 167 ++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 drivers/rtc/rtc-spacemit-p1.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 64f6e9756aff..31d355b103d4 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -406,6 +406,16 @@ config RTC_DRV_MAX77686 This driver can also be built as a module. If so, the module will be called rtc-max77686. +config RTC_DRV_SPACEMIT_P1 + tristate "SpacemiT P1 RTC" + depends on ARCH_SPACEMIT || COMPILE_TEST + select MFD_SPACEMIT_P1 + default ARCH_SPACEMIT + help + Enable support for the RTC function in the SpacemiT P1 PMIC. + This driver can also be built as a module, which will be called + "spacemit-p1-rtc". + config RTC_DRV_NCT3018Y tristate "Nuvoton NCT3018Y" depends on OF diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 789bddfea99d..f41fdb4fabae 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -171,6 +171,7 @@ obj-$(CONFIG_RTC_DRV_SD2405AL) += rtc-sd2405al.o obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o +obj-$(CONFIG_RTC_DRV_SPACEMIT_P1) += rtc-spacemit-p1.o obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o diff --git a/drivers/rtc/rtc-spacemit-p1.c b/drivers/rtc/rtc-spacemit-p1.c new file mode 100644 index 000000000000..43ab62494bb4 --- /dev/null +++ b/drivers/rtc/rtc-spacemit-p1.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the RTC found in the SpacemiT P1 PMIC + * + * Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#define MOD_NAME "spacemit-p1-rtc" + +/* + * Six consecutive 1-byte registers hold the seconds, minutes, hours, + * day-of-month, month, and year (respectively). + * + * The range of values in these registers is: + * seconds 0-59 + * minutes 0-59 + * hours 0-59 + * day 0-30 (struct tm is 1-31) + * month 0-11 + * year years since 2000 (struct tm is since 1900) + * + * Note that the day and month must be converted after reading and + * before writing. + */ +#define RTC_TIME 0x0d /* Offset of the seconds register */ + +#define RTC_CTRL 0x1d +#define RTC_EN BIT(2) + +/* Number of attempts to read a consistent time stamp before giving up */ +#define RTC_READ_TRIES 20 /* At least 1 */ + +struct p1_rtc { + struct regmap *regmap; + struct rtc_device *rtc; +}; + +/* + * The P1 hardware documentation states that the register values are + * latched to ensure a consistent time snapshot within the registers, + * but these are in fact unstable due to a bug in the hardware design. + * So we loop until we get two identical readings. + */ +static int p1_rtc_read_time(struct device *dev, struct rtc_time *t) +{ + struct p1_rtc *p1 = dev_get_drvdata(dev); + struct regmap *regmap = p1->regmap; + u32 count = RTC_READ_TRIES; + u8 seconds; + u8 time[6]; + int ret; + + if (!regmap_test_bits(regmap, RTC_CTRL, RTC_EN)) + return -EINVAL; /* RTC is disabled */ + + ret = regmap_bulk_read(regmap, RTC_TIME, time, sizeof(time)); + if (ret) + return ret; + + do { + seconds = time[0]; + ret = regmap_bulk_read(regmap, RTC_TIME, time, sizeof(time)); + if (ret) + return ret; + } while (time[0] != seconds && --count); + + if (!count) + return -EIO; /* Unable to get a consistent result */ + + t->tm_sec = time[0] & GENMASK(5, 0); + t->tm_min = time[1] & GENMASK(5, 0); + t->tm_hour = time[2] & GENMASK(4, 0); + t->tm_mday = (time[3] & GENMASK(4, 0)) + 1; + t->tm_mon = time[4] & GENMASK(3, 0); + t->tm_year = (time[5] & GENMASK(5, 0)) + 100; + + return 0; +} + +/* + * The P1 hardware documentation states that values in the registers are + * latched so when written they represent a consistent time snapshot. + * Nevertheless, this is not guaranteed by the implementation, so we must + * disable the RTC while updating it. + */ +static int p1_rtc_set_time(struct device *dev, struct rtc_time *t) +{ + struct p1_rtc *p1 = dev_get_drvdata(dev); + struct regmap *regmap = p1->regmap; + u8 time[6]; + int ret; + + time[0] = t->tm_sec; + time[1] = t->tm_min; + time[2] = t->tm_hour; + time[3] = t->tm_mday - 1; + time[4] = t->tm_mon; + time[5] = t->tm_year - 100; + + /* Disable the RTC to update; re-enable again when done */ + ret = regmap_clear_bits(regmap, RTC_CTRL, RTC_EN); + if (ret) + return ret; + + /* If something goes wrong, leave the RTC disabled */ + ret = regmap_bulk_write(regmap, RTC_TIME, time, sizeof(time)); + if (ret) + return ret; + + return regmap_set_bits(regmap, RTC_CTRL, RTC_EN); +} + +static const struct rtc_class_ops p1_rtc_class_ops = { + .read_time = p1_rtc_read_time, + .set_time = p1_rtc_set_time, +}; + +static int p1_rtc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtc_device *rtc; + struct p1_rtc *p1; + + p1 = devm_kzalloc(dev, sizeof(*p1), GFP_KERNEL); + if (!p1) + return -ENOMEM; + dev_set_drvdata(dev, p1); + + p1->regmap = dev_get_regmap(dev->parent, NULL); + if (!p1->regmap) + return dev_err_probe(dev, -ENODEV, "failed to get regmap\n"); + + rtc = devm_rtc_allocate_device(dev); + if (IS_ERR(rtc)) + return dev_err_probe(dev, PTR_ERR(rtc), + "error allocating device\n"); + p1->rtc = rtc; + + rtc->ops = &p1_rtc_class_ops; + rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->range_max = RTC_TIMESTAMP_END_2063; + + clear_bit(RTC_FEATURE_ALARM, rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); + + return devm_rtc_register_device(rtc); +} + +static struct platform_driver p1_rtc_driver = { + .probe = p1_rtc_probe, + .driver = { + .name = MOD_NAME, + }, +}; + +module_platform_driver(p1_rtc_driver); + +MODULE_DESCRIPTION("SpacemiT P1 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" MOD_NAME); From 01cc0dc9de9c5647a2e42309f86db0f2d3cc0f68 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Mon, 15 Sep 2025 15:50:01 +0200 Subject: [PATCH 1517/2711] Documentation: PCI: Sync AER doc with code The PCIe Advanced Error Reporting driver has evolved over the years but its documentation hasn't. Catch up with past code changes: * The documentation claims that Correctable Errors are logged with KERN_INFO severity, but the code uses KERN_WARN. It had used KERN_WARN from the beginning with commit 6c2b374d7485 ("PCI-Express AER implemetation: AER core and aerdriver"). In 2013, commit 2cced2d95961 ("aerdrv: Cleanup log output for AER") switched to KERN_ERR, until 2020 when it was reverted back to KERN_WARN by commit e83e2ca3c395 ("PCI/AER: Log correctable errors as warning, not error"). * An example log message in the documentation uses the term "Uncorrected", but the code uses "Uncorrectable" since commit 02a06f5f1a6a ("PCI/AER: Use 'Correctable' and 'Uncorrectable' spec terms for errors"). * The example contains the Requester ID "id=0500", which is omitted since commit 010caed4ccb6 ("PCI/AER: Decode Error Source Requester ID"). * The example contains the error name "Unsupported Request", which is instead reported as "UnsupReq" since commit bd237801fef2 ("PCI/AER: Adopt lspci names for AER error decoding"). * The example doesn't prepend "0x" to hex values from the TLP Header Log, as introduced by commit f68ea779d98a ("PCI: Add pcie_print_tlp_log() to print TLP Header and Prefix Log"). * The documentation refers to a reset_link callback which was removed by commit b6cf1a42f916 ("PCI/ERR: Remove service dependency in pcie_do_recovery()"). * Commit 579086225502 ("PCI/ERR: Recover from RCiEP AER errors") added support to recover Root Complex Integrated Endpoints by applying a Function Level Reset, alternatively to the Secondary Bus Reset which is applied otherwise. * On non-fatal errors, a reset was previously never performed. But the AER driver has just been amended to allow drivers to opt in to a reset. * The documentation claims that a warning message is logged if a driver lacks pci_error_handlers. But the message has been informational (logged with KERN_INFO severity) since its introduction with commit 01daacfb9035 ("PCI/AER: Log which device prevents error recovery"). The documentation claims that the message is only logged for fatal errors, which is incorrect. Moreover it refers to "section 3", even though the documentation no longer contains section numbers since commit 4e37f055a92e ("Documentation: PCI: convert pcieaer-howto.txt to reST"). Section 3 is titled "Developer Guide". That's the same section where the reference is located, so it is self-referential and can be dropped. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Brian Norris Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/7501bfc5b9920193a25998a3cbcf72c47674ec63.1757942121.git.lukas@wunner.de --- Documentation/PCI/pcieaer-howto.rst | 81 ++++++++++++++--------------- 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/Documentation/PCI/pcieaer-howto.rst b/Documentation/PCI/pcieaer-howto.rst index 4b71e2f43ca7..d448efe572c8 100644 --- a/Documentation/PCI/pcieaer-howto.rst +++ b/Documentation/PCI/pcieaer-howto.rst @@ -70,16 +70,16 @@ AER error output ---------------- When a PCIe AER error is captured, an error message will be output to -console. If it's a correctable error, it is output as an info message. +console. If it's a correctable error, it is output as a warning message. Otherwise, it is printed as an error. So users could choose different log level to filter out correctable error messages. Below shows an example:: - 0000:50:00.0: PCIe Bus Error: severity=Uncorrected (Fatal), type=Transaction Layer, id=0500(Requester ID) + 0000:50:00.0: PCIe Bus Error: severity=Uncorrectable (Fatal), type=Transaction Layer, (Requester ID) 0000:50:00.0: device [8086:0329] error status/mask=00100000/00000000 - 0000:50:00.0: [20] Unsupported Request (First) - 0000:50:00.0: TLP Header: 04000001 00200a03 05010000 00050100 + 0000:50:00.0: [20] UnsupReq (First) + 0000:50:00.0: TLP Header: 0x04000001 0x00200a03 0x05010000 0x00050100 In the example, 'Requester ID' means the ID of the device that sent the error message to the Root Port. Please refer to PCIe specs for other @@ -152,18 +152,6 @@ the device driver. Provide callbacks ----------------- -callback reset_link to reset PCIe link -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This callback is used to reset the PCIe physical link when a -fatal error happens. The Root Port AER service driver provides a -default reset_link function, but different Upstream Ports might -have different specifications to reset the PCIe link, so -Upstream Port drivers may provide their own reset_link functions. - -Section 3.2.2.2 provides more detailed info on when to call -reset_link. - PCI error-recovery callbacks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -174,8 +162,8 @@ when performing error recovery actions. Data struct pci_driver has a pointer, err_handler, to point to pci_error_handlers who consists of a couple of callback function pointers. The AER driver follows the rules defined in -pci-error-recovery.rst except PCIe-specific parts (e.g. -reset_link). Please refer to pci-error-recovery.rst for detailed +pci-error-recovery.rst except PCIe-specific parts (see +below). Please refer to pci-error-recovery.rst for detailed definitions of the callbacks. The sections below specify when to call the error callback functions. @@ -189,10 +177,21 @@ software intervention or any loss of data. These errors do not require any recovery actions. The AER driver clears the device's correctable error status register accordingly and logs these errors. -Non-correctable (non-fatal and fatal) errors -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Uncorrectable (non-fatal and fatal) errors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If an error message indicates a non-fatal error, performing link reset +The AER driver performs a Secondary Bus Reset to recover from +uncorrectable errors. The reset is applied at the port above +the originating device: If the originating device is an Endpoint, +only the Endpoint is reset. If on the other hand the originating +device has subordinate devices, those are all affected by the +reset as well. + +If the originating device is a Root Complex Integrated Endpoint, +there's no port above where a Secondary Bus Reset could be applied. +In this case, the AER driver instead applies a Function Level Reset. + +If an error message indicates a non-fatal error, performing a reset at upstream is not required. The AER driver calls error_detected(dev, pci_channel_io_normal) to all drivers associated within a hierarchy in question. For example:: @@ -204,38 +203,34 @@ Downstream Port B and Endpoint. A driver may return PCI_ERS_RESULT_CAN_RECOVER, PCI_ERS_RESULT_DISCONNECT, or PCI_ERS_RESULT_NEED_RESET, depending on -whether it can recover or the AER driver calls mmio_enabled as next. +whether it can recover without a reset, considers the device unrecoverable +or needs a reset for recovery. If all affected drivers agree that they can +recover without a reset, it is skipped. Should one driver request a reset, +it overrides all other drivers. If an error message indicates a fatal error, kernel will broadcast error_detected(dev, pci_channel_io_frozen) to all drivers within -a hierarchy in question. Then, performing link reset at upstream is -necessary. As different kinds of devices might use different approaches -to reset link, AER port service driver is required to provide the -function to reset link via callback parameter of pcie_do_recovery() -function. If reset_link is not NULL, recovery function will use it -to reset the link. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER -and reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes -to mmio_enabled. +a hierarchy in question. Then, performing a reset at upstream is +necessary. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER +to indicate that recovery without a reset is possible, the error +handling goes to mmio_enabled, but afterwards a reset is still +performed. -Frequent Asked Questions ------------------------- +In other words, for non-fatal errors, drivers may opt in to a reset. +But for fatal errors, they cannot opt out of a reset, based on the +assumption that the link is unreliable. + +Frequently Asked Questions +-------------------------- Q: What happens if a PCIe device driver does not provide an error recovery handler (pci_driver->err_handler is equal to NULL)? A: - The devices attached with the driver won't be recovered. If the - error is fatal, kernel will print out warning messages. Please refer - to section 3 for more information. - -Q: - What happens if an upstream port service driver does not provide - callback reset_link? - -A: - Fatal error recovery will fail if the errors are reported by the - upstream ports who are attached by the service driver. + The devices attached with the driver won't be recovered. + The kernel will print out informational messages to identify + unrecoverable devices. Software error injection From 8e4a13fc61d364ff61b4410810f7b947b6208039 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Mon, 15 Sep 2025 15:50:02 +0200 Subject: [PATCH 1518/2711] Documentation: PCI: Sync error recovery doc with code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amend the documentation on PCI error recovery to fix minor inaccuracies vis-à-vis the actual code: * The documentation claims that a missing ->resume() or ->mmio_enabled() callback always leads to recovery through reset. But none of the implementations do this (pcie_do_recovery(), eeh_handle_normal_event(), zpci_event_do_error_state_clear()). Drop the claim to align the documentation with the code. * The documentation does not list PCI_ERS_RESULT_RECOVERED as a valid return value from ->error_detected(). But none of the implementations forbid this and some drivers are returning it, e.g.: drivers/bus/mhi/host/pci_generic.c drivers/infiniband/hw/hfi1/pcie.c Further down in the documentation it is implied that the return value is in fact allowed: "The platform will call the resume() callback on all affected device drivers if all drivers on the segment have returned PCI_ERS_RESULT_RECOVERED from one of the 3 previous callbacks." The "3 previous callbacks" being ->error_detected(), ->mmio_enabled() and ->slot_reset(). Add it to the valid return values for consistency. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Brian Norris Reviewed-by: Niklas Schnelle Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/ed3c3385499775fcc25f1ee66f395e212919f94a.1757942121.git.lukas@wunner.de --- Documentation/PCI/pci-error-recovery.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst index 42e1e78353f3..d5c661baa87f 100644 --- a/Documentation/PCI/pci-error-recovery.rst +++ b/Documentation/PCI/pci-error-recovery.rst @@ -108,8 +108,8 @@ A driver does not have to implement all of these callbacks; however, if it implements any, it must implement error_detected(). If a callback is not implemented, the corresponding feature is considered unsupported. For example, if mmio_enabled() and resume() aren't there, then it -is assumed that the driver is not doing any direct recovery and requires -a slot reset. Typically a driver will want to know about +is assumed that the driver does not need these callbacks +for recovery. Typically a driver will want to know about a slot_reset(). The actual steps taken by a platform to recover from a PCI error @@ -141,6 +141,9 @@ shouldn't do any new IOs. Called in task context. This is sort of a All drivers participating in this system must implement this call. The driver must return one of the following result codes: + - PCI_ERS_RESULT_RECOVERED + Driver returns this if it thinks the device is usable despite + the error and does not need further intervention. - PCI_ERS_RESULT_CAN_RECOVER Driver returns this if it thinks it might be able to recover the HW by just banging IOs or if it wants to be given From 15dea68d41d58979dcf9011b5dd787aed5fe7dba Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Mon, 15 Sep 2025 15:50:03 +0200 Subject: [PATCH 1519/2711] Documentation: PCI: Amend error recovery doc with DPC/AER specifics Amend the documentation on PCI error recovery with specifics about Downstream Port Containment and Advanced Error Reporting: * Explain that with DPC, devices are inaccessible upon an error (similar to EEH on powerpc) and do not become accessible until the link is re-enabled. * Explain that with AER, although devices may already be accessible in the ->error_detected() callback, accesses should be deferred to the ->mmio_enabled() callback for compatibility with EEH on powerpc and with s390. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Brian Norris Reviewed-by: Niklas Schnelle Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/61d8eeadb20ee71c3a852f44c863bfe0209c454d.1757942121.git.lukas@wunner.de --- Documentation/PCI/pci-error-recovery.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst index d5c661baa87f..9e1e2f2a13fa 100644 --- a/Documentation/PCI/pci-error-recovery.rst +++ b/Documentation/PCI/pci-error-recovery.rst @@ -122,6 +122,10 @@ A PCI bus error is detected by the PCI hardware. On powerpc, the slot is isolated, in that all I/O is blocked: all reads return 0xffffffff, all writes are ignored. +Similarly, on platforms supporting Downstream Port Containment +(PCIe r7.0 sec 6.2.11), the link to the sub-hierarchy with the +faulting device is disabled. Any device in the sub-hierarchy +becomes inaccessible. STEP 1: Notification -------------------- @@ -204,6 +208,24 @@ link reset was performed by the HW. If the platform can't just re-enable IOs without a slot reset or a link reset, it will not call this callback, and instead will have gone directly to STEP 3 (Link Reset) or STEP 4 (Slot Reset) +.. note:: + + On platforms supporting Advanced Error Reporting (PCIe r7.0 sec 6.2), + the faulting device may already be accessible in STEP 1 (Notification). + Drivers should nevertheless defer accesses to STEP 2 (MMIO Enabled) + to be compatible with EEH on powerpc and with s390 (where devices are + inaccessible until STEP 2). + + On platforms supporting Downstream Port Containment, the link to the + sub-hierarchy with the faulting device is re-enabled in STEP 3 (Link + Reset). Hence devices in the sub-hierarchy are inaccessible until + STEP 4 (Slot Reset). + + For errors such as Surprise Down (PCIe r7.0 sec 6.2.7), the device + may not even be accessible in STEP 4 (Slot Reset). Drivers can detect + accessibility by checking whether reads from the device return all 1's + (PCI_POSSIBLE_ERROR()). + .. note:: The following is proposed; no platform implements this yet: From 40103d2a42fe68f3aad77609b42451ee5c713f6e Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Mon, 15 Sep 2025 15:50:04 +0200 Subject: [PATCH 1520/2711] Documentation: PCI: Tidy error recovery doc's PCIe nomenclature Commit 11502feab423 ("Documentation: PCI: Tidy AER documentation") replaced the terms "PCI-E", "PCI-Express" and "PCI Express" with "PCIe" in the AER documentation. Do the same in the documentation on PCI error recovery. While at it, add a missing period and a missing blank. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Brian Norris Reviewed-by: Niklas Schnelle Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/db56b7ef12043f709a04ce67c1d1e102ab5f4e19.1757942121.git.lukas@wunner.de --- Documentation/PCI/pci-error-recovery.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst index 9e1e2f2a13fa..5df481ac6193 100644 --- a/Documentation/PCI/pci-error-recovery.rst +++ b/Documentation/PCI/pci-error-recovery.rst @@ -13,7 +13,7 @@ PCI Error Recovery Many PCI bus controllers are able to detect a variety of hardware PCI errors on the bus, such as parity errors on the data and address buses, as well as SERR and PERR errors. Some of the more advanced -chipsets are able to deal with these errors; these include PCI-E chipsets, +chipsets are able to deal with these errors; these include PCIe chipsets, and the PCI-host bridges found on IBM Power4, Power5 and Power6-based pSeries boxes. A typical action taken is to disconnect the affected device, halting all I/O to it. The goal of a disconnection is to avoid system @@ -206,7 +206,7 @@ reset or some such, but not restart operations. This callback is made if all drivers on a segment agree that they can try to recover and if no automatic link reset was performed by the HW. If the platform can't just re-enable IOs without a slot reset or a link reset, it will not call this callback, and -instead will have gone directly to STEP 3 (Link Reset) or STEP 4 (Slot Reset) +instead will have gone directly to STEP 3 (Link Reset) or STEP 4 (Slot Reset). .. note:: @@ -259,14 +259,14 @@ The driver should return one of the following result codes: The next step taken depends on the results returned by the drivers. If all drivers returned PCI_ERS_RESULT_RECOVERED, then the platform -proceeds to either STEP3 (Link Reset) or to STEP 5 (Resume Operations). +proceeds to either STEP 3 (Link Reset) or to STEP 5 (Resume Operations). If any driver returned PCI_ERS_RESULT_NEED_RESET, then the platform proceeds to STEP 4 (Slot Reset) STEP 3: Link Reset ------------------ -The platform resets the link. This is a PCI-Express specific step +The platform resets the link. This is a PCIe specific step and is done whenever a fatal error has been detected that can be "solved" by resetting the link. @@ -288,13 +288,13 @@ that is equivalent to what it would be after a fresh system power-on followed by power-on BIOS/system firmware initialization. Soft reset is also known as hot-reset. -Powerpc fundamental reset is supported by PCI Express cards only +Powerpc fundamental reset is supported by PCIe cards only and results in device's state machines, hardware logic, port states and configuration registers to initialize to their default conditions. For most PCI devices, a soft reset will be sufficient for recovery. Optional fundamental reset is provided to support a limited number -of PCI Express devices for which a soft reset is not sufficient +of PCIe devices for which a soft reset is not sufficient for recovery. If the platform supports PCI hotplug, then the reset might be @@ -338,7 +338,7 @@ Result codes: - PCI_ERS_RESULT_DISCONNECT Same as above. -Drivers for PCI Express cards that require a fundamental reset must +Drivers for PCIe cards that require a fundamental reset must set the needs_freset bit in the pci_dev structure in their probe function. For example, the QLogic qla2xxx driver sets the needs_freset bit for certain PCI card types:: From 11bdf36be82721b8c4eda95a21c78ad856e047f9 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Wed, 27 Aug 2025 10:13:25 +0800 Subject: [PATCH 1521/2711] nvdimm: Use str_plural() to simplify the code Use the string choice helper function str_plural() to simplify the code. Signed-off-by: Xichao Zhao Reviewed-by: Dave Jiang Signed-off-by: Ira Weiny --- drivers/nvdimm/namespace_devs.c | 2 +- drivers/nvdimm/region.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 55cfbf1e0a95..53bce1fa376e 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1983,7 +1983,7 @@ static struct device **scan_labels(struct nd_region *nd_region) } dev_dbg(&nd_region->dev, "discovered %d namespace%s\n", count, - count == 1 ? "" : "s"); + str_plural(count)); if (count == 0) { struct nd_namespace_pmem *nspm; diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c index 88dc062af5f8..68a26002f8b9 100644 --- a/drivers/nvdimm/region.c +++ b/drivers/nvdimm/region.c @@ -70,7 +70,7 @@ static int nd_region_probe(struct device *dev) * "/" namespace count. */ dev_err(dev, "failed to register %d namespace%s, continuing...\n", - err, err == 1 ? "" : "s"); + err, str_plural(err)); return 0; } From d1a599a8136b16522b5afebd122395524496d549 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 2 Sep 2025 12:45:18 +0100 Subject: [PATCH 1522/2711] ACPI: NFIT: Fix incorrect ndr_desc being reportedin dev_err message There appears to be a cut-n-paste error with the incorrect field ndr_desc->numa_node being reported for the target node. Fix this by using ndr_desc->target_node instead. Fixes: f060db99374e ("ACPI: NFIT: Use fallback node id when numa info in NFIT table is incorrect") Signed-off-by: Colin Ian King Reviewed-by: Ira Weiny Signed-off-by: Ira Weiny --- drivers/acpi/nfit/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index ae035b93da08..3eb56b77cb6d 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2637,7 +2637,7 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc, if (ndr_desc->target_node == NUMA_NO_NODE) { ndr_desc->target_node = phys_to_target_node(spa->address); dev_info(acpi_desc->dev, "changing target node from %d to %d for nfit region [%pa-%pa]", - NUMA_NO_NODE, ndr_desc->numa_node, &res.start, &res.end); + NUMA_NO_NODE, ndr_desc->target_node, &res.start, &res.end); } /* From 6e460c3d611009a1d1c2c1f61c96578284a14fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 30 Jun 2025 17:26:39 +0300 Subject: [PATCH 1523/2711] PCI: Ensure relaxed tail alignment does not increase min_align MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using relaxed tail alignment for the bridge window, pbus_size_mem() also tries to minimize min_align, which can under certain scenarios end up increasing min_align from that found by calculate_mem_align(). Ensure min_align is not increased by the relaxed tail alignment. Eventually, it would be better to add calculate_relaxed_head_align() similar to calculate_mem_align() which finds out what alignment can be used for the head without introducing any gaps into the bridge window to give flexibility on head address too. But that looks relatively complex so it requires much more testing than fixing the immediate problem causing a regression. Fixes: 67f9085596ee ("PCI: Allow relaxed bridge window tail sizing for optional resources") Reported-by: Rio Liu Closes: https://lore.kernel.org/all/o2bL8MtD_40-lf8GlslTw-AZpUPzm8nmfCnJKvS8RQ3NOzOW1uq1dVCEfRpUjJ2i7G2WjfQhk2IWZ7oGp-7G-jXN4qOdtnyOcjRR0PZWK5I=@r26.me/ Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Tested-by: Rio Liu Cc: stable@vger.kernel.org # v6.15+ Link: https://patch.msgid.link/20250822123359.16305-2-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 7853ac6999e2..527f0479e983 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1169,6 +1169,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, resource_size_t children_add_size = 0; resource_size_t children_add_align = 0; resource_size_t add_align = 0; + resource_size_t relaxed_align; if (!b_res) return -ENOSPC; @@ -1246,8 +1247,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, if (bus->self && size0 && !pbus_upstream_space_available(bus, mask | IORESOURCE_PREFETCH, type, size0, min_align)) { - min_align = 1ULL << (max_order + __ffs(SZ_1M)); - min_align = max(min_align, win_align); + relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); + relaxed_align = max(relaxed_align, win_align); + min_align = min(min_align, relaxed_align); size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), win_align); pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n", b_res, &bus->busn_res); @@ -1261,8 +1263,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, if (bus->self && size1 && !pbus_upstream_space_available(bus, mask | IORESOURCE_PREFETCH, type, size1, add_align)) { - min_align = 1ULL << (max_order + __ffs(SZ_1M)); - min_align = max(min_align, win_align); + relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); + relaxed_align = max(relaxed_align, win_align); + min_align = min(min_align, relaxed_align); size1 = calculate_memsize(size, min_size, add_size, children_add_size, resource_size(b_res), win_align); pci_info(bus->self, From ff77c5219747d6b78e8b0ffc4c43d3dd8173d1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 30 Jun 2025 17:26:40 +0300 Subject: [PATCH 1524/2711] PCI: Fix pdev_resources_assignable() disparity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pdev_sort_resources() uses pdev_resources_assignable() helper to decide if device's resources cannot be assigned, so it ignores class 0 (PCI_CLASS_NOT_DEFINED) devices. pbus_size_mem(), on the other hand, does not do the same check. This could lead into a situation where a resource ends up on realloc_head list but is not on the head list, which in turn prevents emptying the resource from the realloc_head list in __assign_resources_sorted(). A non-empty realloc_head is unacceptable because it triggers an internal sanity check as shown in this log with a device that has class 0 (PCI_CLASS_NOT_DEFINED): pci 0001:01:00.0: [144d:a5a5] type 00 class 0x000000 PCIe Endpoint pci 0001:01:00.0: BAR 0 [mem 0x00000000-0x000fffff 64bit] pci 0001:01:00.0: ROM [mem 0x00000000-0x0000ffff pref] pcieport 0001:00:00.0: bridge window [mem 0x00100000-0x001fffff] to [bus 01-ff] add_size 100000 add_align 100000 pcieport 0001:00:00.0: bridge window [mem 0x40000000-0x401fffff]: assigned ------------[ cut here ]------------ kernel BUG at drivers/pci/setup-bus.c:2532! Internal error: Oops - BUG: 00000000f2000800 [#1] SMP ... Call trace: pci_assign_unassigned_bus_resources+0x110/0x114 (P) pci_rescan_bus+0x28/0x48 Use pdev_resources_assignable() also within pbus_size_mem() to skip processing of non-assignable resources which removes the disparity in between what resources pdev_sort_resources() and pbus_size_mem() consider. As non-assignable resources are no longer processed, they are not added to the realloc_head list, thus the sanity check no longer triggers. This disparity problem is very old but only now became apparent after 2499f5348431 ("PCI: Rework optional resource handling") that made the ROM resources optional when calculating bridge window sizes which required adding the resource to the realloc_head list. Previously, bridge windows were just sized larger than necessary. Fixes: 2499f5348431 ("PCI: Rework optional resource handling") Reported-by: Tudor Ambarus Closes: https://lore.kernel.org/all/5f103643-5e1c-43c6-b8fe-9617d3b5447c@linaro.org/ Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org # v6.15+ Link: https://patch.msgid.link/20250822123359.16305-3-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 527f0479e983..df5aec46c29d 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1191,6 +1191,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, resource_size_t r_size; if (r->parent || (r->flags & IORESOURCE_PCI_FIXED) || + !pdev_resources_assignable(dev) || ((r->flags & mask) != type && (r->flags & mask) != type2 && (r->flags & mask) != type3)) From 31af09b3eaf3603870ce9fd5a7b6c8693129c4cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 30 Jun 2025 17:26:41 +0300 Subject: [PATCH 1525/2711] PCI: Fix failure detection during resource resize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 96336ec70264 ("PCI: Perform reset_resource() and build fail list in sync") the failed list is always built and returned to let the caller decide what to do with the failures. The caller may want to retry resource fitting and assignment and before that can happen, the resources should be restored to their original state (a reset effectively clears the struct resource), which requires returning them to the failed list so the original state remains stored in the associated struct pci_dev_resource. Resource resizing is different from the ordinary resource fitting and assignment in that it only considers part of the resources. This means failures for other resource types are not relevant at all and should be ignored. As resize doesn't unassign such unrelated resources, those resources ending up in the failed list implies assignment of that resource must have failed before resize too. The check in pci_reassign_bridge_resources() to decide if the whole assignment is successful, however, is based on list emptiness which will cause false negatives when the failed list has resources with an unrelated type. If the failed list is not empty, call pci_required_resource_failed() and extend it to be able to filter on specific resource types too (if provided). Calling pci_required_resource_failed() at this point is slightly problematic because the resource itself is reset when the failed list is constructed in __assign_resources_sorted(). As a result, pci_resource_is_optional() does not have access to the original resource flags. This could be worked around by restoring and re-resetting the resource around the call to pci_resource_is_optional(), however, it shouldn't cause issue as resource resizing is meant for 64-bit prefetchable resources according to Christian König (see the Link which unfortunately doesn't point directly to Christian's reply because lore didn't store that email at all). Fixes: 96336ec70264 ("PCI: Perform reset_resource() and build fail list in sync") Link: https://lore.kernel.org/all/c5d1b5d8-8669-5572-75a7-0b480f581ac1@linux.intel.com/ Reported-by: D Scott Phillips Closes: https://lore.kernel.org/all/86plf0lgit.fsf@scott-ph-mail.amperecomputing.com/ Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Tested-by: D Scott Phillips Reviewed-by: D Scott Phillips Cc: Christian König Cc: stable@vger.kernel.org # v6.15+ Link: https://patch.msgid.link/20250822123359.16305-4-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index df5aec46c29d..def29506700e 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -28,6 +28,10 @@ #include #include "pci.h" +#define PCI_RES_TYPE_MASK \ + (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH |\ + IORESOURCE_MEM_64) + unsigned int pci_flags; EXPORT_SYMBOL_GPL(pci_flags); @@ -384,13 +388,19 @@ static bool pci_need_to_release(unsigned long mask, struct resource *res) } /* Return: @true if assignment of a required resource failed. */ -static bool pci_required_resource_failed(struct list_head *fail_head) +static bool pci_required_resource_failed(struct list_head *fail_head, + unsigned long type) { struct pci_dev_resource *fail_res; + type &= PCI_RES_TYPE_MASK; + list_for_each_entry(fail_res, fail_head, list) { int idx = pci_resource_num(fail_res->dev, fail_res->res); + if (type && (fail_res->flags & PCI_RES_TYPE_MASK) != type) + continue; + if (!pci_resource_is_optional(fail_res->dev, idx)) return true; } @@ -504,7 +514,7 @@ assign: } /* Without realloc_head and only optional fails, nothing more to do. */ - if (!pci_required_resource_failed(&local_fail_head) && + if (!pci_required_resource_failed(&local_fail_head, 0) && list_empty(realloc_head)) { list_for_each_entry(save_res, &save_head, list) { struct resource *res = save_res->res; @@ -1708,10 +1718,6 @@ static void __pci_bridge_assign_resources(const struct pci_dev *bridge, } } -#define PCI_RES_TYPE_MASK \ - (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH |\ - IORESOURCE_MEM_64) - static void pci_bridge_release_resources(struct pci_bus *bus, unsigned long type) { @@ -2450,8 +2456,12 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) free_list(&added); if (!list_empty(&failed)) { - ret = -ENOSPC; - goto cleanup; + if (pci_required_resource_failed(&failed, type)) { + ret = -ENOSPC; + goto cleanup; + } + /* Only resources with unrelated types failed (again) */ + free_list(&failed); } list_for_each_entry(dev_res, &saved, list) { From 2657a0c982239fecc41d0df5a69091ca4297647c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:10:50 +0300 Subject: [PATCH 1526/2711] m68k/PCI: Use pci_enable_resources() in pcibios_enable_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit m68k has a resource enable (check) loop in its pcibios_enable_device() which for some reason differs from pci_enable_resources(). This could lead to inconsistencies in behavior, especially now as pci_enable_resources() and the bridge window resource flags behavior are going to be altered by upcoming changes. The check for !r->start && r->end is already covered by the more generic checks done in pci_enable_resources(). The entire pcibios_enable_device() suspiciously looks copy-paste from some other arch as also indicated by the preceding comment. However, it also enables PCI_COMMAND_IO | PCI_COMMAND_MEMORY always for bridges. It is not clear why that is being done as the commit e93a6bbeb5a5 ("m68k: common PCI support definitions and code") introducing this code states "Nothing specific to any PCI implementation in any m68k class CPU hardware yet". Replace the resource enable loop with a call to pci_enable_resources() and adjust the Command Register afterwards as it's unclear if that is necessary or not so keep it for now. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-2-ilpo.jarvinen@linux.intel.com --- arch/m68k/kernel/pcibios.c | 39 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/arch/m68k/kernel/pcibios.c b/arch/m68k/kernel/pcibios.c index 9504eb19d73a..e6ab3f9ff5d8 100644 --- a/arch/m68k/kernel/pcibios.c +++ b/arch/m68k/kernel/pcibios.c @@ -44,41 +44,24 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, */ int pcibios_enable_device(struct pci_dev *dev, int mask) { - struct resource *r; u16 cmd, newcmd; - int idx; + int ret; - pci_read_config_word(dev, PCI_COMMAND, &cmd); - newcmd = cmd; - - for (idx = 0; idx < 6; idx++) { - /* Only set up the requested stuff */ - if (!(mask & (1 << idx))) - continue; - - r = dev->resource + idx; - if (!r->start && r->end) { - pr_err("PCI: Device %s not available because of resource collisions\n", - pci_name(dev)); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - newcmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - newcmd |= PCI_COMMAND_MEMORY; - } + ret = pci_enable_resources(dev, mask); + if (ret < 0) + return ret; /* * Bridges (eg, cardbus bridges) need to be fully enabled */ - if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) + if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); newcmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - - - if (newcmd != cmd) { - pr_info("PCI: enabling device %s (0x%04x -> 0x%04x)\n", - pci_name(dev), cmd, newcmd); - pci_write_config_word(dev, PCI_COMMAND, newcmd); + if (newcmd != cmd) { + pr_info("PCI: enabling bridge %s (0x%04x -> 0x%04x)\n", + pci_name(dev), cmd, newcmd); + pci_write_config_word(dev, PCI_COMMAND, newcmd); + } } return 0; } From 754babaaf33349d9ef27bb1ac6f5d9d5a503a2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:10:51 +0300 Subject: [PATCH 1527/2711] sparc/PCI: Remove pcibios_enable_device() as they do nothing extra MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under arch/sparc/ there are multiple copies of pcibios_enable_device() but none of those seem to do anything extra beyond what pci_enable_resources() is supposed to do. These functions could lead to inconsistencies in behavior, especially now as pci_enable_resources() and the bridge window resource flags behavior are going to be altered by upcoming changes. Remove all pcibios_enable_device() from arch/sparc/ so that PCI core can simply call into pci_enable_resources() instead using its __weak version of pcibios_enable_device(). Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-3-ilpo.jarvinen@linux.intel.com --- arch/sparc/kernel/leon_pci.c | 27 --------------------------- arch/sparc/kernel/pci.c | 27 --------------------------- arch/sparc/kernel/pcic.c | 27 --------------------------- 3 files changed, 81 deletions(-) diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c index 8de6646e9ce8..10934dfa987a 100644 --- a/arch/sparc/kernel/leon_pci.c +++ b/arch/sparc/kernel/leon_pci.c @@ -60,30 +60,3 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info) pci_assign_unassigned_resources(); pci_bus_add_devices(root_bus); } - -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - struct resource *res; - u16 cmd, oldcmd; - int i; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - oldcmd = cmd; - - pci_dev_for_each_resource(dev, res, i) { - /* Only set up the requested stuff */ - if (!(mask & (1<flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (res->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - - if (cmd != oldcmd) { - pci_info(dev, "enabling device (%04x -> %04x)\n", oldcmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - return 0; -} diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index ddac216a2aff..a9448088e762 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -722,33 +722,6 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm, return bus; } -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - struct resource *res; - u16 cmd, oldcmd; - int i; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - oldcmd = cmd; - - pci_dev_for_each_resource(dev, res, i) { - /* Only set up the requested stuff */ - if (!(mask & (1<flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (res->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - - if (cmd != oldcmd) { - pci_info(dev, "enabling device (%04x -> %04x)\n", oldcmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - return 0; -} - /* Platform support for /proc/bus/pci/X/Y mmap()s. */ int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma) { diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 25fe0a061732..3d54ad5656a4 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -641,33 +641,6 @@ void pcibios_fixup_bus(struct pci_bus *bus) } } -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - struct resource *res; - u16 cmd, oldcmd; - int i; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - oldcmd = cmd; - - pci_dev_for_each_resource(dev, res, i) { - /* Only set up the requested stuff */ - if (!(mask & (1<flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (res->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - - if (cmd != oldcmd) { - pci_info(dev, "enabling device (%04x -> %04x)\n", oldcmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - return 0; -} - /* Makes compiler happy */ static volatile int pcic_timer_dummy; From ae81aad5c2e17fd1fafd930e75b81aedc837f705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:10:52 +0300 Subject: [PATCH 1528/2711] MIPS: PCI: Use pci_enable_resources() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci-legacy.c under MIPS has a copy of pci_enable_resources() named as pcibios_enable_resources(). Having own copy of same functionality could lead to inconsistencies in behavior, especially now as pci_enable_resources() and the bridge window resource flags behavior are going to be altered by upcoming changes. The check for !r->start && r->end is already covered by the more generic checks done in pci_enable_resources(). Call pci_enable_resources() from MIPS's pcibios_enable_device() and remove pcibios_enable_resources(). Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Acked-by: Thomas Bogendoerfer Link: https://patch.msgid.link/20250829131113.36754-4-ilpo.jarvinen@linux.intel.com --- arch/mips/pci/pci-legacy.c | 38 ++------------------------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/arch/mips/pci/pci-legacy.c b/arch/mips/pci/pci-legacy.c index 66898fd182dc..d04b7c1294b6 100644 --- a/arch/mips/pci/pci-legacy.c +++ b/arch/mips/pci/pci-legacy.c @@ -249,45 +249,11 @@ static int __init pcibios_init(void) subsys_initcall(pcibios_init); -static int pcibios_enable_resources(struct pci_dev *dev, int mask) -{ - u16 cmd, old_cmd; - int idx; - struct resource *r; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - pci_dev_for_each_resource(dev, r, idx) { - /* Only set up the requested stuff */ - if (!(mask & (1<flags & (IORESOURCE_IO | IORESOURCE_MEM))) - continue; - if ((idx == PCI_ROM_RESOURCE) && - (!(r->flags & IORESOURCE_ROM_ENABLE))) - continue; - if (!r->start && r->end) { - pci_err(dev, - "can't enable device: resource collisions\n"); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - if (cmd != old_cmd) { - pci_info(dev, "enabling device (%04x -> %04x)\n", old_cmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - return 0; -} - int pcibios_enable_device(struct pci_dev *dev, int mask) { - int err = pcibios_enable_resources(dev, mask); + int err; + err = pci_enable_resources(dev, mask); if (err < 0) return err; From e240edffd04fe179536f7b5c22daae1e3b509b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:10:53 +0300 Subject: [PATCH 1529/2711] PCI: Move find_bus_resource_of_type() earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move find_bus_resource_of_type() earlier in setup-bus.c to be able to call it in upcoming changes. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-5-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 56 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index def29506700e..4097d8703b8f 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -140,6 +140,34 @@ static void restore_dev_resource(struct pci_dev_resource *dev_res) res->flags = dev_res->flags; } +/* + * Helper function for sizing routines. Assigned resources have non-NULL + * parent resource. + * + * Return first unassigned resource of the correct type. If there is none, + * return first assigned resource of the correct type. If none of the + * above, return NULL. + * + * Returning an assigned resource of the correct type allows the caller to + * distinguish between already assigned and no resource of the correct type. + */ +static struct resource *find_bus_resource_of_type(struct pci_bus *bus, + unsigned long type_mask, + unsigned long type) +{ + struct resource *r, *r_assigned = NULL; + + pci_bus_for_each_resource(bus, r) { + if (r == &ioport_resource || r == &iomem_resource) + continue; + if (r && (r->flags & type_mask) == type && !r->parent) + return r; + if (r && (r->flags & type_mask) == type && !r_assigned) + r_assigned = r; + } + return r_assigned; +} + static bool pdev_resources_assignable(struct pci_dev *dev) { u16 class = dev->class >> 8, command; @@ -876,34 +904,6 @@ static void pci_bridge_check_ranges(struct pci_bus *bus) } } -/* - * Helper function for sizing routines. Assigned resources have non-NULL - * parent resource. - * - * Return first unassigned resource of the correct type. If there is none, - * return first assigned resource of the correct type. If none of the - * above, return NULL. - * - * Returning an assigned resource of the correct type allows the caller to - * distinguish between already assigned and no resource of the correct type. - */ -static struct resource *find_bus_resource_of_type(struct pci_bus *bus, - unsigned long type_mask, - unsigned long type) -{ - struct resource *r, *r_assigned = NULL; - - pci_bus_for_each_resource(bus, r) { - if (r == &ioport_resource || r == &iomem_resource) - continue; - if (r && (r->flags & type_mask) == type && !r->parent) - return r; - if (r && (r->flags & type_mask) == type && !r_assigned) - r_assigned = r; - } - return r_assigned; -} - static resource_size_t calculate_iosize(resource_size_t size, resource_size_t min_size, resource_size_t size1, From 1ce76bc0497b9289d6f6195258d8bdc1c42eb91a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:10:54 +0300 Subject: [PATCH 1530/2711] PCI: Refactor find_bus_resource_of_type() logic checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorder the logic checks in find_bus_resource_of_type() to simplify them. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-6-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 4097d8703b8f..c5fc4e2825be 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -158,11 +158,15 @@ static struct resource *find_bus_resource_of_type(struct pci_bus *bus, struct resource *r, *r_assigned = NULL; pci_bus_for_each_resource(bus, r) { - if (r == &ioport_resource || r == &iomem_resource) + if (!r || r == &ioport_resource || r == &iomem_resource) continue; - if (r && (r->flags & type_mask) == type && !r->parent) + + if ((r->flags & type_mask) != type) + continue; + + if (!r->parent) return r; - if (r && (r->flags & type_mask) == type && !r_assigned) + if (!r_assigned) r_assigned = r; } return r_assigned; From 2ee33aa14d3f2e92ba8ae80443f2cd9b575f08cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:10:55 +0300 Subject: [PATCH 1531/2711] PCI: Always claim bridge window before its setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the claim of a resource fails for the full range in pci_claim_bridge_resource(), clipping the resource to a smaller size is attempted. If clipping is successful, the new bridge window is programmed and only as the last step the code attempts to claim the resource again. The order of the last two steps is slightly illogical and inconsistent with the assignment call chains. If claiming the bridge window after clipping fails, the bridge window that was set up is left in place. Rework the logic such that the bridge window is claimed before calling the relevant bridge setup function. This make the behavior consistent with resource fitting call chains that always assign the bridge window before programming it. If claiming the bridge window fails, the clipped bridge window is no longer set up but pci_claim_bridge_resource() returns without writing the bridge window at all. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-7-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index c5fc4e2825be..b477f68b236c 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -857,9 +857,16 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i) if ((bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI) return 0; + if (i > PCI_BRIDGE_PREF_MEM_WINDOW) + return -EINVAL; + + /* Try to clip the resource and claim the smaller window */ if (!pci_bus_clip_resource(bridge, i)) return -EINVAL; /* Clipping didn't change anything */ + if (!pci_claim_resource(bridge, i)) + return -EINVAL; + switch (i) { case PCI_BRIDGE_IO_WINDOW: pci_setup_bridge_io(bridge); @@ -874,10 +881,7 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i) return -EINVAL; } - if (pci_claim_resource(bridge, i) == 0) - return 0; /* Claimed a smaller window */ - - return -EINVAL; + return 0; } /* From b15f45ab65e2ce04339fbd54387a9209529d315b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:10:56 +0300 Subject: [PATCH 1532/2711] PCI: Disable non-claimed bridge window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If clipping or claiming the bridge window fails, the bridge window is left in a state that does not match the kernel's view on what the bridge window is. Disable the bridge window by writing the magic disable value into the Base and Limit Registers if clipping or claiming failed. To detect if claiming the resource was successful, add res->parent checks into the bridge setup functions. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-8-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index b477f68b236c..6bdc1af887da 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -660,7 +660,7 @@ void pci_setup_cardbus(struct pci_bus *bus) res = bus->resource[0]; pcibios_resource_to_bus(bridge->bus, ®ion, res); - if (res->flags & IORESOURCE_IO) { + if (res->parent && res->flags & IORESOURCE_IO) { /* * The IO resource is allocated a range twice as large as it * would normally need. This allows us to set both IO regs. @@ -674,7 +674,7 @@ void pci_setup_cardbus(struct pci_bus *bus) res = bus->resource[1]; pcibios_resource_to_bus(bridge->bus, ®ion, res); - if (res->flags & IORESOURCE_IO) { + if (res->parent && res->flags & IORESOURCE_IO) { pci_info(bridge, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, region.start); @@ -684,7 +684,7 @@ void pci_setup_cardbus(struct pci_bus *bus) res = bus->resource[2]; pcibios_resource_to_bus(bridge->bus, ®ion, res); - if (res->flags & IORESOURCE_MEM) { + if (res->parent && res->flags & IORESOURCE_MEM) { pci_info(bridge, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, region.start); @@ -694,7 +694,7 @@ void pci_setup_cardbus(struct pci_bus *bus) res = bus->resource[3]; pcibios_resource_to_bus(bridge->bus, ®ion, res); - if (res->flags & IORESOURCE_MEM) { + if (res->parent && res->flags & IORESOURCE_MEM) { pci_info(bridge, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, region.start); @@ -735,7 +735,7 @@ static void pci_setup_bridge_io(struct pci_dev *bridge) res = &bridge->resource[PCI_BRIDGE_IO_WINDOW]; res_name = pci_resource_name(bridge, PCI_BRIDGE_IO_WINDOW); pcibios_resource_to_bus(bridge->bus, ®ion, res); - if (res->flags & IORESOURCE_IO) { + if (res->parent && res->flags & IORESOURCE_IO) { pci_read_config_word(bridge, PCI_IO_BASE, &l); io_base_lo = (region.start >> 8) & io_mask; io_limit_lo = (region.end >> 8) & io_mask; @@ -767,7 +767,7 @@ static void pci_setup_bridge_mmio(struct pci_dev *bridge) res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW]; res_name = pci_resource_name(bridge, PCI_BRIDGE_MEM_WINDOW); pcibios_resource_to_bus(bridge->bus, ®ion, res); - if (res->flags & IORESOURCE_MEM) { + if (res->parent && res->flags & IORESOURCE_MEM) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; pci_info(bridge, " %s %pR\n", res_name, res); @@ -796,7 +796,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge) res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; res_name = pci_resource_name(bridge, PCI_BRIDGE_PREF_MEM_WINDOW); pcibios_resource_to_bus(bridge->bus, ®ion, res); - if (res->flags & IORESOURCE_PREFETCH) { + if (res->parent && res->flags & IORESOURCE_PREFETCH) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; if (res->flags & IORESOURCE_MEM_64) { @@ -848,6 +848,8 @@ static void pci_setup_bridge(struct pci_bus *bus) int pci_claim_bridge_resource(struct pci_dev *bridge, int i) { + int ret = -EINVAL; + if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END) return 0; @@ -861,11 +863,8 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i) return -EINVAL; /* Try to clip the resource and claim the smaller window */ - if (!pci_bus_clip_resource(bridge, i)) - return -EINVAL; /* Clipping didn't change anything */ - - if (!pci_claim_resource(bridge, i)) - return -EINVAL; + if (pci_bus_clip_resource(bridge, i)) + ret = pci_claim_resource(bridge, i); switch (i) { case PCI_BRIDGE_IO_WINDOW: @@ -881,7 +880,7 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i) return -EINVAL; } - return 0; + return ret; } /* From 3baeae36039afc233d4a42d6ff4aa7019892619f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:10:57 +0300 Subject: [PATCH 1533/2711] PCI: Use pci_release_resource() instead of release_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few places in setup-bus.c call release_resource() directly and end up duplicating functionality from pci_release_resource() such as parent check, logging, and clearing the resource. Worse yet, the way the resource is cleared is inconsistent between different sites. Convert release_resource() calls into pci_release_resource() to remove code duplication. This will also make the resource start, end, and flags behavior consistent, i.e., start address is cleared, and only IORESOURCE_UNSET is asserted for the resource. While at it, eliminate the unnecessary initialization of idx variable in pci_bridge_release_resources(). Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-9-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 46 +++++++++++++---------------------------- drivers/pci/setup-res.c | 11 +++++++--- include/linux/pci.h | 2 +- 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 6bdc1af887da..b62465665abc 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -473,8 +473,6 @@ static void __assign_resources_sorted(struct list_head *head, struct pci_dev_resource *dev_res, *tmp_res, *dev_res2; struct resource *res; struct pci_dev *dev; - const char *res_name; - int idx; unsigned long fail_type; resource_size_t add_align, align; @@ -582,14 +580,7 @@ assign: res = dev_res->res; dev = dev_res->dev; - if (!res->parent) - continue; - - idx = pci_resource_num(dev, res); - res_name = pci_resource_name(dev, idx); - pci_dbg(dev, "%s %pR: releasing\n", res_name, res); - - release_resource(res); + pci_release_resource(dev, pci_resource_num(dev, res)); restore_dev_resource(dev_res); } /* Restore start/end/flags from saved list */ @@ -1732,7 +1723,7 @@ static void pci_bridge_release_resources(struct pci_bus *bus, struct resource *r; unsigned int old_flags; struct resource *b_res; - int idx = 1; + int idx, ret; b_res = &dev->resource[PCI_BRIDGE_RESOURCES]; @@ -1766,21 +1757,18 @@ static void pci_bridge_release_resources(struct pci_bus *bus, /* If there are children, release them all */ release_child_resources(r); - if (!release_resource(r)) { - type = old_flags = r->flags & PCI_RES_TYPE_MASK; - pci_info(dev, "resource %d %pR released\n", - PCI_BRIDGE_RESOURCES + idx, r); - /* Keep the old size */ - resource_set_range(r, 0, resource_size(r)); - r->flags = 0; - /* Avoiding touch the one without PREF */ - if (type & IORESOURCE_PREFETCH) - type = IORESOURCE_PREFETCH; - __pci_setup_bridge(bus, type); - /* For next child res under same bridge */ - r->flags = old_flags; - } + type = old_flags = r->flags & PCI_RES_TYPE_MASK; + ret = pci_release_resource(dev, PCI_BRIDGE_RESOURCES + idx); + if (ret) + return; + + /* Avoiding touch the one without PREF */ + if (type & IORESOURCE_PREFETCH) + type = IORESOURCE_PREFETCH; + __pci_setup_bridge(bus, type); + /* For next child res under same bridge */ + r->flags = old_flags; } enum release_type { @@ -2425,7 +2413,6 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) for (i = PCI_BRIDGE_RESOURCES; i < PCI_BRIDGE_RESOURCE_END; i++) { struct resource *res = &bridge->resource[i]; - const char *res_name = pci_resource_name(bridge, i); if ((res->flags ^ type) & PCI_RES_TYPE_MASK) continue; @@ -2438,12 +2425,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) if (ret) goto cleanup; - pci_info(bridge, "%s %pR: releasing\n", res_name, res); - - if (res->parent) - release_resource(res); - res->start = 0; - res->end = 0; + pci_release_resource(bridge, i); break; } if (i == PCI_BRIDGE_RESOURCE_END) diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index d2b3ed51e880..0468c058b598 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -406,20 +406,25 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, return 0; } -void pci_release_resource(struct pci_dev *dev, int resno) +int pci_release_resource(struct pci_dev *dev, int resno) { struct resource *res = pci_resource_n(dev, resno); const char *res_name = pci_resource_name(dev, resno); + int ret; if (!res->parent) - return; + return 0; pci_info(dev, "%s %pR: releasing\n", res_name, res); - release_resource(res); + ret = release_resource(res); + if (ret) + return ret; res->end = resource_size(res) - 1; res->start = 0; res->flags |= IORESOURCE_UNSET; + + return 0; } EXPORT_SYMBOL(pci_release_resource); diff --git a/include/linux/pci.h b/include/linux/pci.h index 59876de13860..275df4058767 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1417,7 +1417,7 @@ void pci_reset_secondary_bus(struct pci_dev *dev); void pcibios_reset_secondary_bus(struct pci_dev *dev); void pci_update_resource(struct pci_dev *dev, int resno); int __must_check pci_assign_resource(struct pci_dev *dev, int i); -void pci_release_resource(struct pci_dev *dev, int resno); +int pci_release_resource(struct pci_dev *dev, int resno); static inline int pci_rebar_bytes_to_size(u64 bytes) { bytes = roundup_pow_of_two(bytes); From 1cdffa51ecc4ee02c46160bafa2e5d25d09e97ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:10:58 +0300 Subject: [PATCH 1534/2711] PCI: Enable bridge even if bridge window fails to assign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A normal PCI bridge has multiple bridge windows and not all of them are always required by devices underneath the bridge. If a Root Port or bridge does not have a device underneath, no bridge windows get assigned. Yet, pci_enable_resources() is set to fail indiscriminantly on any resource assignment failure if the resource is not known to be optional. In practice, the code in pci_enable_resources() is currently largely dormant. The kernel sets resource flags to zero for any unused bridge window and resets flags to zero in case of an resource assignment failure, which short-circuits pci_enable_resources() because of this check: if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) continue; However, an upcoming change to resource flags will alter how bridge window resource flags behave activating these long dormants checks in pci_enable_resources(). While complex logic could be built to selectively enable a bridge only under some conditions, a few versions of such logic were tried during development of this change and none of them worked satisfactorily. Thus, I just gave up and decided to enable any bridge regardless of the bridge windows as there seems to be no clear benefit from not enabling it, but a major downside as pcieport will not be probed for the bridge if it's not enabled. Therefore, change pci_enable_resources() to not check if bridge window resources remain unassigned. Resource assignment failures are pretty noisy already so there is no need to log that for bridge windows in pci_enable_resources(). Ignoring bridge window failures hopefully prevents an obvious source of regressions when the upcoming change that no longer clears resource flags for bridge windows is enacted. I've hit this problem even during my own testing on multiple occasions so I expect it to be a quite common problem. This can always be revisited later if somebody thinks the enable check for bridges is not strict enough, but expect a mind-boggling number of regressions from such a change. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-10-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-res.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 0468c058b598..4e0e60256f04 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -527,22 +527,26 @@ int pci_enable_resources(struct pci_dev *dev, int mask) if (pci_resource_is_optional(dev, i)) continue; - if (r->flags & IORESOURCE_UNSET) { - pci_err(dev, "%s %pR: not assigned; can't enable device\n", - r_name, r); - return -EINVAL; + if (i < PCI_BRIDGE_RESOURCES) { + if (r->flags & IORESOURCE_UNSET) { + pci_err(dev, "%s %pR: not assigned; can't enable device\n", + r_name, r); + return -EINVAL; + } + + if (!r->parent) { + pci_err(dev, "%s %pR: not claimed; can't enable device\n", + r_name, r); + return -EINVAL; + } } - if (!r->parent) { - pci_err(dev, "%s %pR: not claimed; can't enable device\n", - r_name, r); - return -EINVAL; + if (r->parent) { + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; } - - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; } if (cmd != old_cmd) { From 8278c6914306f35f32d73bdf2a918950919a0051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:10:59 +0300 Subject: [PATCH 1535/2711] PCI: Preserve bridge window resource type flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a bridge window is found unused or fails to assign, the flags of the associated resource are cleared. Clearing flags is problematic as it also removes the type information of the resource which is needed later. Thus, always preserve the bridge window type flags and use IORESOURCE_UNSET and IORESOURCE_DISABLED to indicate the status of the bridge window. Also, when initializing resources, make sure all valid bridge windows do get their type flags set. Change various places that relied on resource flags being cleared to check for IORESOURCE_UNSET and IORESOURCE_DISABLED to allow bridge window resource to retain their type flags. Add pdev_resource_assignable() and pdev_resource_should_fit() helpers to filter out disabled bridge windows during resource fitting; the latter combines more common checks into the helper. When reading the bridge windows from the registers, instead of leaving the resource flags cleared for bridge windows that are not enabled, always set up the flags and set IORESOURCE_UNSET | IORESOURCE_DISABLED as needed. When resource fitting or assignment fails for a bridge window resource, or the bridge window is not needed, mark the resource with IORESOURCE_UNSET or IORESOURCE_DISABLED, respectively. Use dummy zero resource in resource_show() for backwards compatibility as lspci will otherwise misrepresent disabled bridge windows. This change fixes an issue which highlights the importance of keeping the resource type flags intact: At the end of __assign_resources_sorted(), reset_resource() is called, previously clearing the flags. Later, pci_prepare_next_assign_round() attempted to release bridge resources using pci_bus_release_bridge_resources() that calls into pci_bridge_release_resources() that assumes type flags are still present. As type flags were cleared, IORESOURCE_MEM_64 was not set leading to resources under an incorrect bridge window to be released (idx = 1 instead of idx = 2). While the assignments performed later covered this problem so that the wrongly released resources got assigned in the end, it was still causing extra release+assign pairs. There are other reasons why the resource flags should be retained in upcoming changes too. Removing the flag reset for non-bridge window resource is left as future work, in part because it has a much higher regression potential due to pci_enable_resources() that will start to work also for those resources then and due to what endpoint drivers might assume about resources. Despite the Fixes tag, backporting this (at least any time soon) is highly discouraged. The issue fixed is borderline cosmetic as the later assignments normally cover the problem entirely. Also there might be non-obvious dependencies. Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-11-ilpo.jarvinen@linux.intel.com --- drivers/pci/bus.c | 3 ++ drivers/pci/pci-sysfs.c | 7 ++++ drivers/pci/probe.c | 25 +++++++++--- drivers/pci/setup-bus.c | 89 +++++++++++++++++++++++++++-------------- drivers/pci/setup-res.c | 3 ++ 5 files changed, 90 insertions(+), 37 deletions(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index b77fd30bbfd9..58b5388423ee 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -204,6 +204,9 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, if (!r) continue; + if (r->flags & (IORESOURCE_UNSET|IORESOURCE_DISABLED)) + continue; + /* type_mask must match */ if ((res->flags ^ r->flags) & type_mask) continue; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5eea14c1f7f5..162a5241c7f7 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -177,6 +177,13 @@ static ssize_t resource_show(struct device *dev, struct device_attribute *attr, for (i = 0; i < max; i++) { struct resource *res = &pci_dev->resource[i]; + struct resource zerores = {}; + + /* For backwards compatibility */ + if (i >= PCI_BRIDGE_RESOURCES && i <= PCI_BRIDGE_RESOURCE_END && + res->flags & (IORESOURCE_UNSET | IORESOURCE_DISABLED)) + res = &zerores; + pci_resource_to_user(pci_dev, i, res, &start, &end); len += sysfs_emit_at(buf, len, "0x%016llx 0x%016llx 0x%016llx\n", (unsigned long long)start, diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f41128f91ca7..f31d27c7708a 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -419,13 +419,17 @@ static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res, limit |= ((unsigned long) io_limit_hi << 16); } + res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; + if (base <= limit) { - res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; region.start = base; region.end = limit + io_granularity - 1; pcibios_bus_to_resource(dev->bus, res, ®ion); if (log) pci_info(dev, " bridge window %pR\n", res); + } else { + resource_set_range(res, 0, 0); + res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; } } @@ -440,13 +444,18 @@ static void pci_read_bridge_mmio(struct pci_dev *dev, struct resource *res, pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); base = ((unsigned long) mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; limit = ((unsigned long) mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; + + res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; + if (base <= limit) { - res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; region.start = base; region.end = limit + 0xfffff; pcibios_bus_to_resource(dev->bus, res, ®ion); if (log) pci_info(dev, " bridge window %pR\n", res); + } else { + resource_set_range(res, 0, 0); + res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; } } @@ -489,16 +498,20 @@ static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res, return; } + res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) | IORESOURCE_MEM | + IORESOURCE_PREFETCH; + if (res->flags & PCI_PREF_RANGE_TYPE_64) + res->flags |= IORESOURCE_MEM_64; + if (base <= limit) { - res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) | - IORESOURCE_MEM | IORESOURCE_PREFETCH; - if (res->flags & PCI_PREF_RANGE_TYPE_64) - res->flags |= IORESOURCE_MEM_64; region.start = base; region.end = limit + 0xfffff; pcibios_bus_to_resource(dev->bus, res, ®ion); if (log) pci_info(dev, " bridge window %pR\n", res); + } else { + resource_set_range(res, 0, 0); + res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; } } diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index b62465665abc..70b210ed200d 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -190,6 +190,31 @@ static bool pdev_resources_assignable(struct pci_dev *dev) return true; } +static bool pdev_resource_assignable(struct pci_dev *dev, struct resource *res) +{ + int idx = pci_resource_num(dev, res); + + if (!res->flags) + return false; + + if (idx >= PCI_BRIDGE_RESOURCES && idx <= PCI_BRIDGE_RESOURCE_END && + res->flags & IORESOURCE_DISABLED) + return false; + + return true; +} + +static bool pdev_resource_should_fit(struct pci_dev *dev, struct resource *res) +{ + if (res->parent) + return false; + + if (res->flags & IORESOURCE_PCI_FIXED) + return false; + + return pdev_resource_assignable(dev, res); +} + /* Sort resources by alignment */ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) { @@ -205,10 +230,7 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) resource_size_t r_align; struct list_head *n; - if (r->flags & IORESOURCE_PCI_FIXED) - continue; - - if (!(r->flags) || r->parent) + if (!pdev_resource_should_fit(dev, r)) continue; r_align = pci_resource_alignment(dev, r); @@ -257,8 +279,15 @@ bool pci_resource_is_optional(const struct pci_dev *dev, int resno) return false; } -static inline void reset_resource(struct resource *res) +static inline void reset_resource(struct pci_dev *dev, struct resource *res) { + int idx = pci_resource_num(dev, res); + + if (idx >= PCI_BRIDGE_RESOURCES && idx <= PCI_BRIDGE_RESOURCE_END) { + res->flags |= IORESOURCE_UNSET; + return; + } + res->start = 0; res->end = 0; res->flags = 0; @@ -610,7 +639,7 @@ out: 0 /* don't care */); } - reset_resource(res); + reset_resource(dev, res); } free_list(head); @@ -1014,8 +1043,11 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, if (r->parent || !(r->flags & IORESOURCE_IO)) continue; - r_size = resource_size(r); + if (!pdev_resource_assignable(dev, r)) + continue; + + r_size = resource_size(r); if (r_size < SZ_1K) /* Might be re-aligned for ISA */ size += r_size; @@ -1034,6 +1066,9 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, size0 = calculate_iosize(size, min_size, size1, 0, 0, resource_size(b_res), min_align); + if (size0) + b_res->flags &= ~IORESOURCE_DISABLED; + size1 = size0; if (realloc_head && (add_size > 0 || children_add_size > 0)) { size1 = calculate_iosize(size, min_size, size1, add_size, @@ -1045,13 +1080,14 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, if (bus->self && (b_res->start || b_res->end)) pci_info(bus->self, "disabling bridge window %pR to %pR (unused)\n", b_res, &bus->busn_res); - b_res->flags = 0; + b_res->flags |= IORESOURCE_DISABLED; return; } resource_set_range(b_res, min_align, size0); b_res->flags |= IORESOURCE_STARTALIGN; if (bus->self && size1 > size0 && realloc_head) { + b_res->flags &= ~IORESOURCE_DISABLED; add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); pci_info(bus->self, "bridge window %pR to %pR add_size %llx\n", @@ -1198,11 +1234,13 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, const char *r_name = pci_resource_name(dev, i); resource_size_t r_size; - if (r->parent || (r->flags & IORESOURCE_PCI_FIXED) || - !pdev_resources_assignable(dev) || - ((r->flags & mask) != type && - (r->flags & mask) != type2 && - (r->flags & mask) != type3)) + if (!pdev_resources_assignable(dev) || + !pdev_resource_should_fit(dev, r)) + continue; + + if ((r->flags & mask) != type && + (r->flags & mask) != type2 && + (r->flags & mask) != type3) continue; r_size = resource_size(r); @@ -1253,6 +1291,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, min_align = max(min_align, win_align); size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), min_align); + if (size0) + b_res->flags &= ~IORESOURCE_DISABLED; + if (bus->self && size0 && !pbus_upstream_space_available(bus, mask | IORESOURCE_PREFETCH, type, size0, min_align)) { @@ -1287,13 +1328,14 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, if (bus->self && (b_res->start || b_res->end)) pci_info(bus->self, "disabling bridge window %pR to %pR (unused)\n", b_res, &bus->busn_res); - b_res->flags = 0; + b_res->flags |= IORESOURCE_DISABLED; return 0; } resource_set_range(b_res, min_align, size0); b_res->flags |= IORESOURCE_STARTALIGN; if (bus->self && size1 > size0 && realloc_head) { + b_res->flags &= ~IORESOURCE_DISABLED; add_to_list(realloc_head, bus->self, b_res, size1-size0, add_align); pci_info(bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n", b_res, &bus->busn_res, @@ -1721,7 +1763,6 @@ static void pci_bridge_release_resources(struct pci_bus *bus, { struct pci_dev *dev = bus->self; struct resource *r; - unsigned int old_flags; struct resource *b_res; int idx, ret; @@ -1758,17 +1799,15 @@ static void pci_bridge_release_resources(struct pci_bus *bus, /* If there are children, release them all */ release_child_resources(r); - type = old_flags = r->flags & PCI_RES_TYPE_MASK; ret = pci_release_resource(dev, PCI_BRIDGE_RESOURCES + idx); if (ret) return; + type = r->flags & PCI_RES_TYPE_MASK; /* Avoiding touch the one without PREF */ if (type & IORESOURCE_PREFETCH) type = IORESOURCE_PREFETCH; __pci_setup_bridge(bus, type); - /* For next child res under same bridge */ - r->flags = old_flags; } enum release_type { @@ -2246,21 +2285,9 @@ static void pci_prepare_next_assign_round(struct list_head *fail_head, } /* Restore size and flags */ - list_for_each_entry(fail_res, fail_head, list) { - struct resource *res = fail_res->res; - struct pci_dev *dev = fail_res->dev; - int idx = pci_resource_num(dev, res); - + list_for_each_entry(fail_res, fail_head, list) restore_dev_resource(fail_res); - if (!pci_is_bridge(dev)) - continue; - - if (idx >= PCI_BRIDGE_RESOURCES && - idx <= PCI_BRIDGE_RESOURCE_END) - res->flags = 0; - } - free_list(fail_head); } diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 4e0e60256f04..21f77e5c647c 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -359,6 +359,9 @@ int pci_assign_resource(struct pci_dev *dev, int resno) res->flags &= ~IORESOURCE_UNSET; res->flags &= ~IORESOURCE_STARTALIGN; + if (resno >= PCI_BRIDGE_RESOURCES && resno <= PCI_BRIDGE_RESOURCE_END) + res->flags &= ~IORESOURCE_DISABLED; + pci_info(dev, "%s %pR: assigned\n", res_name, res); if (resno < PCI_BRIDGE_RESOURCES) pci_update_resource(dev, resno); From e4934832c588f72bcc139d3ca0acc490c63a821c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:00 +0300 Subject: [PATCH 1536/2711] PCI: Add defines for bridge window indexing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit include/linux/pci.h provides PCI_BRIDGE_{IO,MEM,PREF_MEM}_WINDOW defines, however, they're based on the resource array indexing in the pci_dev struct. The struct pci_bus also has pointers to those same resources but they start from zeroth index. Add PCI_BUS_BRIDGE_{IO,MEM,PREF_MEM}_WINDOW defines to get rid of literal indexing. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-12-ilpo.jarvinen@linux.intel.com --- drivers/pci/pci.h | 4 ++++ drivers/pci/probe.c | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 34f65d69662e..1dc8a8066761 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -81,6 +81,10 @@ struct pcie_tlp_log; #define PCIE_MSG_CODE_DEASSERT_INTC 0x26 #define PCIE_MSG_CODE_DEASSERT_INTD 0x27 +#define PCI_BUS_BRIDGE_IO_WINDOW 0 +#define PCI_BUS_BRIDGE_MEM_WINDOW 1 +#define PCI_BUS_BRIDGE_PREF_MEM_WINDOW 2 + extern const unsigned char pcie_link_speed[]; extern bool pci_early_dump; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f31d27c7708a..eaeb66bec433 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -598,9 +598,13 @@ void pci_read_bridge_bases(struct pci_bus *child) for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; - pci_read_bridge_io(child->self, child->resource[0], false); - pci_read_bridge_mmio(child->self, child->resource[1], false); - pci_read_bridge_mmio_pref(child->self, child->resource[2], false); + pci_read_bridge_io(child->self, + child->resource[PCI_BUS_BRIDGE_IO_WINDOW], false); + pci_read_bridge_mmio(child->self, + child->resource[PCI_BUS_BRIDGE_MEM_WINDOW], false); + pci_read_bridge_mmio_pref(child->self, + child->resource[PCI_BUS_BRIDGE_PREF_MEM_WINDOW], + false); if (!dev->transparent) return; From 74afce3dfcba117064c0eb7eb4d075836aa1370f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:01 +0300 Subject: [PATCH 1537/2711] PCI: Add bridge window selection functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various places in the PCI core code independently decide into which bridge window a child resource should be placed. It is hard to see whether these decisions always end up in agreement, especially in the corner cases, and in some places it requires complex logic to pass multiple resource types and/or bridge windows around. Add pbus_select_window() and pbus_select_window_for_type() for cases where the former cannot be used so that eventually the same helper can be used to select the bridge window everywhere. Using the same function ensures the selected bridge window remains always the same and it can be easily recalculated in-situ allowing simplifying the interfaces between internal functions in upcoming changes. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-13-ilpo.jarvinen@linux.intel.com --- drivers/pci/pci.h | 2 + drivers/pci/setup-bus.c | 101 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 1dc8a8066761..cbd40f05c39c 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -385,6 +385,8 @@ static inline int pci_resource_num(const struct pci_dev *dev, return resno; } +struct resource *pbus_select_window(struct pci_bus *bus, + const struct resource *res); void pci_reassigndev_resource_alignment(struct pci_dev *dev); void pci_disable_bridge_window(struct pci_dev *dev); struct pci_bus *pci_bus_get(struct pci_bus *bus); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 70b210ed200d..913fd41e1d0d 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -172,6 +172,107 @@ static struct resource *find_bus_resource_of_type(struct pci_bus *bus, return r_assigned; } +/** + * pbus_select_window_for_type - Select bridge window for a resource type + * @bus: PCI bus + * @type: Resource type (resource flags can be passed as is) + * + * Select the bridge window based on a resource @type. + * + * For memory resources, the selection is done as follows: + * + * Any non-prefetchable resource is put into the non-prefetchable window. + * + * If there is no prefetchable MMIO window, put all memory resources into the + * non-prefetchable window. + * + * If there's a 64-bit prefetchable MMIO window, put all 64-bit prefetchable + * resources into it and place 32-bit prefetchable memory into the + * non-prefetchable window. + * + * Otherwise, put all prefetchable resources into the prefetchable window. + * + * Return: the bridge window resource or NULL if no bridge window is found. + */ +static struct resource *pbus_select_window_for_type(struct pci_bus *bus, + unsigned long type) +{ + int iores_type = type & IORESOURCE_TYPE_BITS; /* w/o 64bit & pref */ + struct resource *mmio, *mmio_pref, *win; + + type &= PCI_RES_TYPE_MASK; /* with 64bit & pref */ + + if ((iores_type != IORESOURCE_IO) && (iores_type != IORESOURCE_MEM)) + return NULL; + + if (pci_is_root_bus(bus)) { + win = find_bus_resource_of_type(bus, type, type); + if (win) + return win; + + type &= ~IORESOURCE_MEM_64; + win = find_bus_resource_of_type(bus, type, type); + if (win) + return win; + + type &= ~IORESOURCE_PREFETCH; + return find_bus_resource_of_type(bus, type, type); + } + + switch (iores_type) { + case IORESOURCE_IO: + return pci_bus_resource_n(bus, PCI_BUS_BRIDGE_IO_WINDOW); + + case IORESOURCE_MEM: + mmio = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_MEM_WINDOW); + mmio_pref = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_PREF_MEM_WINDOW); + + if (!(type & IORESOURCE_PREFETCH) || + !(mmio_pref->flags & IORESOURCE_MEM)) + return mmio; + + if ((type & IORESOURCE_MEM_64) || + !(mmio_pref->flags & IORESOURCE_MEM_64)) + return mmio_pref; + + return mmio; + default: + return NULL; + } +} + +/** + * pbus_select_window - Select bridge window for a resource + * @bus: PCI bus + * @res: Resource + * + * Select the bridge window for @res. If the resource is already assigned, + * return the current bridge window. + * + * For memory resources, the selection is done as follows: + * + * Any non-prefetchable resource is put into the non-prefetchable window. + * + * If there is no prefetchable MMIO window, put all memory resources into the + * non-prefetchable window. + * + * If there's a 64-bit prefetchable MMIO window, put all 64-bit prefetchable + * resources into it and place 32-bit prefetchable memory into the + * non-prefetchable window. + * + * Otherwise, put all prefetchable resources into the prefetchable window. + * + * Return: the bridge window resource or NULL if no bridge window is found. + */ +struct resource *pbus_select_window(struct pci_bus *bus, + const struct resource *res) +{ + if (res->parent) + return res->parent; + + return pbus_select_window_for_type(bus, res->flags); +} + static bool pdev_resources_assignable(struct pci_dev *dev) { u16 class = dev->class >> 8, command; From 3ab10f83e277ba9640742cbba67b8df369591450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:02 +0300 Subject: [PATCH 1538/2711] PCI: Fix finding bridge window in pci_reassign_bridge_resources() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_reassign_bridge_resources() walks upwards in the PCI bus hierarchy, locates the relevant bridge window on each level using flags check, and attempts to release the bridge window. The flags-based check is fragile due to various fallbacks in the bridge window selection logic. As such, the algorithm might not locate the correct bridge window. Refactor pci_reassign_bridge_resources() to determine the correct bridge window using pbus_select_window(), which contains logic to handle all fallback cases correctly. Change function prefix to pbus as it now inputs struct bus and resource for which to locate the bridge window. The main purpose is to make bridge window selection logic consistent across the entire PCI core (one step at a time). While this technically also fixes the commit 8bb705e3e79d ("PCI: Add pci_resize_resource() for resizing BARs") making the bridge window walk algorithm more robust, the normal setup having a 64-bit resizable BAR underneath bridge(s) with 64-bit prefetchable windows does not need to use any fallbacks. As such, the practical impact is low (requiring BAR resize use case and a non-typical bridge device). The way to detect if unrelated resource failed again is left to use the type based approximation which should not behave worse than before. Fixes: 8bb705e3e79d ("PCI: Add pci_resize_resource() for resizing BARs") Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-14-ilpo.jarvinen@linux.intel.com --- drivers/pci/pci.h | 2 +- drivers/pci/setup-bus.c | 38 ++++++++++++++++++-------------------- drivers/pci/setup-res.c | 2 +- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index cbd40f05c39c..0d96a9141227 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -334,7 +334,7 @@ struct device *pci_get_host_bridge_device(struct pci_dev *dev); void pci_put_host_bridge_device(struct device *dev); unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge); -int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type); +int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *res); int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align); int pci_configure_extended_tags(struct pci_dev *dev, void *ign); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 913fd41e1d0d..4b08b9cecab3 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -2522,10 +2522,16 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) } EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); -int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) +/* + * Walk to the root bus, find the bridge window relevant for @res and + * release it when possible. If the bridge window contains assigned + * resources, it cannot be released. + */ +int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *res) { + unsigned long type = res->flags; struct pci_dev_resource *dev_res; - struct pci_dev *next; + struct pci_dev *bridge; LIST_HEAD(saved); LIST_HEAD(added); LIST_HEAD(failed); @@ -2534,33 +2540,25 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) down_read(&pci_bus_sem); - /* Walk to the root hub, releasing bridge BARs when possible */ - next = bridge; - do { - bridge = next; - for (i = PCI_BRIDGE_RESOURCES; i < PCI_BRIDGE_RESOURCE_END; - i++) { - struct resource *res = &bridge->resource[i]; + while (!pci_is_root_bus(bus)) { + bridge = bus->self; + res = pbus_select_window(bus, res); + if (!res) + break; - if ((res->flags ^ type) & PCI_RES_TYPE_MASK) - continue; - - /* Ignore BARs which are still in use */ - if (res->child) - continue; + i = pci_resource_num(bridge, res); + /* Ignore BARs which are still in use */ + if (!res->child) { ret = add_to_list(&saved, bridge, res, 0, 0); if (ret) goto cleanup; pci_release_resource(bridge, i); - break; } - if (i == PCI_BRIDGE_RESOURCE_END) - break; - next = bridge->bus ? bridge->bus->self : NULL; - } while (next); + bus = bus->parent; + } if (list_empty(&saved)) { up_read(&pci_bus_sem); diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 21f77e5c647c..c3ba4ccecd43 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -496,7 +496,7 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size) /* Check if the new config works by trying to assign everything. */ if (dev->bus->self) { - ret = pci_reassign_bridge_resources(dev->bus->self, res->flags); + ret = pbus_reassign_bridge_resources(dev->bus, res); if (ret) goto error_resize; } From 85796d20a6907e8ede81380a8fa73745d486f0af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:03 +0300 Subject: [PATCH 1539/2711] PCI: Warn if bridge window cannot be released when resizing BAR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BAR resizing calls to pci_reassign_bridge_resources(), which attempts to release any upstream bridge window to allow them to accommodate the new BAR size. The release can only be performed if there are no other child resources for the bridge window. Previously the code continued silently when other child resources were detected. Add pci_warn() to inform user that a bridge window could not be released because of child resources. As a small bridge window is often the reason why BAR resize fails, this warning will help to pinpoint to the cause. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-15-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 4b08b9cecab3..47f1a4747607 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -2555,6 +2555,12 @@ int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *res) goto cleanup; pci_release_resource(bridge, i); + } else { + const char *res_name = pci_resource_name(bridge, i); + + pci_warn(bridge, + "%s %pR: was not released (still contains assigned resources)\n", + res_name, res); } bus = bus->parent; From 7dc58aa7f1b32a215fb0b7c6ca30ddf4663dedf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:04 +0300 Subject: [PATCH 1540/2711] PCI: Use pbus_select_window() during BAR resize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to a BAR resize, __resource_resize_store() loops through the normal resources of the PCI device and releases those that match to the flags of the BAR to be resized. This is necessary to allow resizing also the upstream bridge window as only childless bridge windows can be resized. While the flags check (mostly) works (if corner cases are ignored), the more straightforward way is to check if the resources share the bridge window. Change __resource_resize_store() to do the check using pbus_select_window(). Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-16-ilpo.jarvinen@linux.intel.com --- drivers/pci/pci-sysfs.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 162a5241c7f7..ce3923c4aa80 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1562,13 +1562,19 @@ static ssize_t __resource_resize_store(struct device *dev, int n, const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); - unsigned long size, flags; + struct pci_bus *bus = pdev->bus; + struct resource *b_win, *res; + unsigned long size; int ret, i; u16 cmd; if (kstrtoul(buf, 0, &size) < 0) return -EINVAL; + b_win = pbus_select_window(bus, pci_resource_n(pdev, n)); + if (!b_win) + return -EINVAL; + device_lock(dev); if (dev->driver || pci_num_vf(pdev)) { ret = -EBUSY; @@ -1588,19 +1594,19 @@ static ssize_t __resource_resize_store(struct device *dev, int n, pci_write_config_word(pdev, PCI_COMMAND, cmd & ~PCI_COMMAND_MEMORY); - flags = pci_resource_flags(pdev, n); - pci_remove_resource_files(pdev); - for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) { - if (pci_resource_len(pdev, i) && - pci_resource_flags(pdev, i) == flags) + pci_dev_for_each_resource(pdev, res, i) { + if (i >= PCI_BRIDGE_RESOURCES) + break; + + if (b_win == pbus_select_window(bus, res)) pci_release_resource(pdev, i); } ret = pci_resize_resource(pdev, n, size); - pci_assign_unassigned_bus_resources(pdev->bus); + pci_assign_unassigned_bus_resources(bus); if (pci_create_resource_files(pdev)) pci_warn(pdev, "Failed to recreate resource files after BAR resizing\n"); From ebe091ad81e1d3e5cbb1592ebc18175b5ca3d2bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:05 +0300 Subject: [PATCH 1541/2711] PCI: Use pbus_select_window_for_type() during IO window sizing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert pbus_size_io() to use pbus_select_window_for_type(). Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-17-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 47f1a4747607..a21d6367e525 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1122,8 +1122,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, struct list_head *realloc_head) { struct pci_dev *dev; - struct resource *b_res = find_bus_resource_of_type(bus, IORESOURCE_IO, - IORESOURCE_IO); + struct resource *b_res = pbus_select_window_for_type(bus, IORESOURCE_IO); resource_size_t size = 0, size0 = 0, size1 = 0; resource_size_t children_add_size = 0; resource_size_t min_align, align; From da07881005e57b3c19dccce2ad2f488ba96e8a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:06 +0300 Subject: [PATCH 1542/2711] PCI: Rename resource variable from r to res MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resource is going to be passed in as argument aften an upcoming change. Rename the struct resource variable from "r" to "res" to avoid using one letter variable name in a function argument. This rename is made separately to reduce churn in the upcoming change. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-18-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index a21d6367e525..5ec446c2b779 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1241,24 +1241,24 @@ static bool pbus_upstream_space_available(struct pci_bus *bus, unsigned long mas .align = align, }; struct pci_bus *downstream = bus; - struct resource *r; + struct resource *res; while ((bus = bus->parent)) { if (pci_is_root_bus(bus)) break; - pci_bus_for_each_resource(bus, r) { - if (!r || !r->parent || (r->flags & mask) != type) + pci_bus_for_each_resource(bus, res) { + if (!res || !res->parent || (res->flags & mask) != type) continue; - if (resource_size(r) >= size) { + if (resource_size(res) >= size) { struct resource gap = {}; - if (find_resource_space(r, &gap, size, &constraint) == 0) { + if (find_resource_space(res, &gap, size, &constraint) == 0) { gap.flags = type; pci_dbg(bus->self, "Assigned bridge window %pR to %pR free space at %pR\n", - r, &bus->busn_res, &gap); + res, &bus->busn_res, &gap); return true; } } @@ -1266,7 +1266,7 @@ static bool pbus_upstream_space_available(struct pci_bus *bus, unsigned long mas if (bus->self) { pci_info(bus->self, "Assigned bridge window %pR to %pR cannot fit 0x%llx required for %s bridging to %pR\n", - r, &bus->busn_res, + res, &bus->busn_res, (unsigned long long)size, pci_name(downstream->self), &downstream->busn_res); From 13016e15d595125ec2da83e1715083efe7499f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:07 +0300 Subject: [PATCH 1543/2711] PCI: Use pbus_select_window() in space available checker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pbus_upstream_space_available() figures out the upstream bridge window resources on its own. Migrate it to use pbus_select_window(). Note: pbus_select_window() -> pbus_select_window_for_type() calls find_bus_resource_of_type() for root bus, which does not do parent check similar to what pbus_upstream_space_available() did earlier, but the difference does not matter because pbus_upstream_space_available() itself stops when it encounters the root bus. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-19-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 71 ++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 5ec446c2b779..865bacae9cac 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1221,19 +1221,20 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns, /** * pbus_upstream_space_available - Check no upstream resource limits allocation * @bus: The bus - * @mask: Mask the resource flag, then compare it with type - * @type: The type of resource from bridge + * @res: The resource to help select the correct bridge window * @size: The size required from the bridge window * @align: Required alignment for the resource * - * Checks that @size can fit inside the upstream bridge resources that are - * already assigned. + * Check that @size can fit inside the upstream bridge resources that are + * already assigned. Select the upstream bridge window based on the type of + * @res. * * Return: %true if enough space is available on all assigned upstream * resources. */ -static bool pbus_upstream_space_available(struct pci_bus *bus, unsigned long mask, - unsigned long type, resource_size_t size, +static bool pbus_upstream_space_available(struct pci_bus *bus, + struct resource *res, + resource_size_t size, resource_size_t align) { struct resource_constraint constraint = { @@ -1241,39 +1242,39 @@ static bool pbus_upstream_space_available(struct pci_bus *bus, unsigned long mas .align = align, }; struct pci_bus *downstream = bus; - struct resource *res; while ((bus = bus->parent)) { if (pci_is_root_bus(bus)) break; - pci_bus_for_each_resource(bus, res) { - if (!res || !res->parent || (res->flags & mask) != type) - continue; - - if (resource_size(res) >= size) { - struct resource gap = {}; - - if (find_resource_space(res, &gap, size, &constraint) == 0) { - gap.flags = type; - pci_dbg(bus->self, - "Assigned bridge window %pR to %pR free space at %pR\n", - res, &bus->busn_res, &gap); - return true; - } - } - - if (bus->self) { - pci_info(bus->self, - "Assigned bridge window %pR to %pR cannot fit 0x%llx required for %s bridging to %pR\n", - res, &bus->busn_res, - (unsigned long long)size, - pci_name(downstream->self), - &downstream->busn_res); - } - + res = pbus_select_window(bus, res); + if (!res) return false; + if (!res->parent) + continue; + + if (resource_size(res) >= size) { + struct resource gap = {}; + + if (find_resource_space(res, &gap, size, &constraint) == 0) { + gap.flags = res->flags; + pci_dbg(bus->self, + "Assigned bridge window %pR to %pR free space at %pR\n", + res, &bus->busn_res, &gap); + return true; + } } + + if (bus->self) { + pci_info(bus->self, + "Assigned bridge window %pR to %pR cannot fit 0x%llx required for %s bridging to %pR\n", + res, &bus->busn_res, + (unsigned long long)size, + pci_name(downstream->self), + &downstream->busn_res); + } + + return false; } return true; @@ -1395,8 +1396,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, b_res->flags &= ~IORESOURCE_DISABLED; if (bus->self && size0 && - !pbus_upstream_space_available(bus, mask | IORESOURCE_PREFETCH, type, - size0, min_align)) { + !pbus_upstream_space_available(bus, b_res, size0, min_align)) { relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); relaxed_align = max(relaxed_align, win_align); min_align = min(min_align, relaxed_align); @@ -1411,8 +1411,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, resource_size(b_res), add_align); if (bus->self && size1 && - !pbus_upstream_space_available(bus, mask | IORESOURCE_PREFETCH, type, - size1, add_align)) { + !pbus_upstream_space_available(bus, b_res, size1, add_align)) { relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); relaxed_align = max(relaxed_align, win_align); min_align = min(min_align, relaxed_align); From ae88d0b9c57f70086dca4f8ccb14c64b2f144c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:08 +0300 Subject: [PATCH 1544/2711] PCI: Use pbus_select_window_for_type() during mem window sizing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __pci_bus_size_bridges() goes to great lengths of helping pbus_size_mem() in which types it should put into a particular bridge window, requiring passing up to three resource type into pbus_size_mem(). Instead of having complex logic in __pci_bus_size_bridges() and a non-straightforward interface between those functions, use pbus_select_window_for_type() and pbus_select_window() to find the correct bridge window and compare if the resources belong to that window. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-20-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 111 +++++++++------------------------------- 1 file changed, 24 insertions(+), 87 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 865bacae9cac..720159bca54d 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1284,24 +1284,22 @@ static bool pbus_upstream_space_available(struct pci_bus *bus, * pbus_size_mem() - Size the memory window of a given bus * * @bus: The bus - * @mask: Mask the resource flag, then compare it with type - * @type: The type of free resource from bridge - * @type2: Second match type - * @type3: Third match type + * @type: The type of bridge resource * @min_size: The minimum memory window that must be allocated * @add_size: Additional optional memory window * @realloc_head: Track the additional memory window on this list * - * Calculate the size of the bus and minimal alignment which guarantees - * that all child resources fit in this size. + * Calculate the size of the bus resource for @type and minimal alignment + * which guarantees that all child resources fit in this size. * - * Return -ENOSPC if there's no available bus resource of the desired - * type. Otherwise, set the bus resource start/end to indicate the - * required size, add things to realloc_head (if supplied), and return 0. + * Set the bus resource start/end to indicate the required size if there an + * available unassigned bus resource of the desired @type. + * + * Add optional resource requests to the @realloc_head list if it is + * supplied. */ -static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, - unsigned long type, unsigned long type2, - unsigned long type3, resource_size_t min_size, +static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + resource_size_t min_size, resource_size_t add_size, struct list_head *realloc_head) { @@ -1309,19 +1307,18 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, resource_size_t min_align, win_align, align, size, size0, size1 = 0; resource_size_t aligns[28]; /* Alignments from 1MB to 128TB */ int order, max_order; - struct resource *b_res = find_bus_resource_of_type(bus, - mask | IORESOURCE_PREFETCH, type); + struct resource *b_res = pbus_select_window_for_type(bus, type); resource_size_t children_add_size = 0; resource_size_t children_add_align = 0; resource_size_t add_align = 0; resource_size_t relaxed_align; if (!b_res) - return -ENOSPC; + return; /* If resource is already assigned, nothing more to do */ if (b_res->parent) - return 0; + return; memset(aligns, 0, sizeof(aligns)); max_order = 0; @@ -1338,11 +1335,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, if (!pdev_resources_assignable(dev) || !pdev_resource_should_fit(dev, r)) continue; - - if ((r->flags & mask) != type && - (r->flags & mask) != type2 && - (r->flags & mask) != type3) + if (b_res != pbus_select_window(bus, r)) continue; + r_size = resource_size(r); /* Put SRIOV requested res to the optional list */ @@ -1428,7 +1423,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, pci_info(bus->self, "disabling bridge window %pR to %pR (unused)\n", b_res, &bus->busn_res); b_res->flags |= IORESOURCE_DISABLED; - return 0; + return; } resource_set_range(b_res, min_align, size0); @@ -1441,7 +1436,6 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, (unsigned long long) (size1 - size0), (unsigned long long) add_align); } - return 0; } unsigned long pci_cardbus_resource_alignment(struct resource *res) @@ -1546,12 +1540,11 @@ handle_done: void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) { struct pci_dev *dev; - unsigned long mask, prefmask, type2 = 0, type3 = 0; resource_size_t additional_io_size = 0, additional_mmio_size = 0, additional_mmio_pref_size = 0; struct resource *pref; struct pci_host_bridge *host; - int hdr_type, ret; + int hdr_type; list_for_each_entry(dev, &bus->devices, bus_list) { struct pci_bus *b = dev->subordinate; @@ -1601,71 +1594,15 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) pbus_size_io(bus, realloc_head ? 0 : additional_io_size, additional_io_size, realloc_head); - /* - * If there's a 64-bit prefetchable MMIO window, compute - * the size required to put all 64-bit prefetchable - * resources in it. - */ - mask = IORESOURCE_MEM; - prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; - if (pref && (pref->flags & IORESOURCE_MEM_64)) { - prefmask |= IORESOURCE_MEM_64; - ret = pbus_size_mem(bus, prefmask, prefmask, - prefmask, prefmask, - realloc_head ? 0 : additional_mmio_pref_size, - additional_mmio_pref_size, realloc_head); - - /* - * If successful, all non-prefetchable resources - * and any 32-bit prefetchable resources will go in - * the non-prefetchable window. - */ - if (ret == 0) { - mask = prefmask; - type2 = prefmask & ~IORESOURCE_MEM_64; - type3 = prefmask & ~IORESOURCE_PREFETCH; - } + if (pref) { + pbus_size_mem(bus, + IORESOURCE_MEM | IORESOURCE_PREFETCH | + (pref->flags & IORESOURCE_MEM_64), + realloc_head ? 0 : additional_mmio_pref_size, + additional_mmio_pref_size, realloc_head); } - /* - * If there is no 64-bit prefetchable window, compute the - * size required to put all prefetchable resources in the - * 32-bit prefetchable window (if there is one). - */ - if (!type2) { - prefmask &= ~IORESOURCE_MEM_64; - ret = pbus_size_mem(bus, prefmask, prefmask, - prefmask, prefmask, - realloc_head ? 0 : additional_mmio_pref_size, - additional_mmio_pref_size, realloc_head); - - /* - * If successful, only non-prefetchable resources - * will go in the non-prefetchable window. - */ - if (ret == 0) - mask = prefmask; - else - additional_mmio_size += additional_mmio_pref_size; - - type2 = type3 = IORESOURCE_MEM; - } - - /* - * Compute the size required to put everything else in the - * non-prefetchable window. This includes: - * - * - all non-prefetchable resources - * - 32-bit prefetchable resources if there's a 64-bit - * prefetchable window or no prefetchable window at all - * - 64-bit prefetchable resources if there's no prefetchable - * window at all - * - * Note that the strategy in __pci_assign_resource() must match - * that used here. Specifically, we cannot put a 32-bit - * prefetchable resource in a 64-bit prefetchable window. - */ - pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3, + pbus_size_mem(bus, IORESOURCE_MEM, realloc_head ? 0 : additional_mmio_size, additional_mmio_size, realloc_head); break; From 4292a1e45fd464551efac7b2b52fd3606e956c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:09 +0300 Subject: [PATCH 1545/2711] PCI: Refactor distributing available memory to use loops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_bus_distribute_available_resources() and pci_bridge_distribute_available_resources() retain bridge window resources and related data needed for distributing the available window in independent variables for io, memory, and prefetchable memory windows. The code is essentially the same for all of them and therefore repeated three times with different variable names. Refactor pci_bus_distribute_available_resources() to take an array. This is complicated slightly by the function taking advantage of passing the struct as value, which cannot be done for arrays in C. Therefore, copy the data into a local array in the stack in the first loop. Variable names are (hopefully) improved slightly as well. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-21-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 162 ++++++++++++++++++---------------------- include/linux/pci.h | 3 +- 2 files changed, 74 insertions(+), 91 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 720159bca54d..3bc329b1b923 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -2059,15 +2059,16 @@ static void remove_dev_resource(struct resource *avail, struct pci_dev *dev, avail->start = min(avail->start + tmp, avail->end + 1); } -static void remove_dev_resources(struct pci_dev *dev, struct resource *io, - struct resource *mmio, - struct resource *mmio_pref) +static void remove_dev_resources(struct pci_dev *dev, + struct resource available[PCI_P2P_BRIDGE_RESOURCE_NUM]) { + struct resource *mmio_pref = &available[PCI_BUS_BRIDGE_PREF_MEM_WINDOW]; struct resource *res; pci_dev_for_each_resource(dev, res) { if (resource_type(res) == IORESOURCE_IO) { - remove_dev_resource(io, dev, res); + remove_dev_resource(&available[PCI_BUS_BRIDGE_IO_WINDOW], + dev, res); } else if (resource_type(res) == IORESOURCE_MEM) { /* @@ -2081,10 +2082,13 @@ static void remove_dev_resources(struct pci_dev *dev, struct resource *io, */ if ((res->flags & IORESOURCE_PREFETCH) && ((res->flags & IORESOURCE_MEM_64) == - (mmio_pref->flags & IORESOURCE_MEM_64))) - remove_dev_resource(mmio_pref, dev, res); - else - remove_dev_resource(mmio, dev, res); + (mmio_pref->flags & IORESOURCE_MEM_64))) { + remove_dev_resource(&available[PCI_BUS_BRIDGE_PREF_MEM_WINDOW], + dev, res); + } else { + remove_dev_resource(&available[PCI_BUS_BRIDGE_MEM_WINDOW], + dev, res); + } } } } @@ -2099,45 +2103,39 @@ static void remove_dev_resources(struct pci_dev *dev, struct resource *io, * shared with the bridges. */ static void pci_bus_distribute_available_resources(struct pci_bus *bus, - struct list_head *add_list, - struct resource io, - struct resource mmio, - struct resource mmio_pref) + struct list_head *add_list, + struct resource available_in[PCI_P2P_BRIDGE_RESOURCE_NUM]) { + struct resource available[PCI_P2P_BRIDGE_RESOURCE_NUM]; unsigned int normal_bridges = 0, hotplug_bridges = 0; - struct resource *io_res, *mmio_res, *mmio_pref_res; struct pci_dev *dev, *bridge = bus->self; - resource_size_t io_per_b, mmio_per_b, mmio_pref_per_b, align; + resource_size_t per_bridge[PCI_P2P_BRIDGE_RESOURCE_NUM]; + resource_size_t align; + int i; - io_res = &bridge->resource[PCI_BRIDGE_IO_WINDOW]; - mmio_res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW]; - mmio_pref_res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; + for (i = 0; i < PCI_P2P_BRIDGE_RESOURCE_NUM; i++) { + struct resource *res = pci_bus_resource_n(bus, i); - /* - * The alignment of this bridge is yet to be considered, hence it must - * be done now before extending its bridge window. - */ - align = pci_resource_alignment(bridge, io_res); - if (!io_res->parent && align) - io.start = min(ALIGN(io.start, align), io.end + 1); + available[i] = available_in[i]; - align = pci_resource_alignment(bridge, mmio_res); - if (!mmio_res->parent && align) - mmio.start = min(ALIGN(mmio.start, align), mmio.end + 1); + /* + * The alignment of this bridge is yet to be considered, + * hence it must be done now before extending its bridge + * window. + */ + align = pci_resource_alignment(bridge, res); + if (!res->parent && align) + available[i].start = min(ALIGN(available[i].start, align), + available[i].end + 1); - align = pci_resource_alignment(bridge, mmio_pref_res); - if (!mmio_pref_res->parent && align) - mmio_pref.start = min(ALIGN(mmio_pref.start, align), - mmio_pref.end + 1); - - /* - * Now that we have adjusted for alignment, update the bridge window - * resources to fill as much remaining resource space as possible. - */ - adjust_bridge_window(bridge, io_res, add_list, resource_size(&io)); - adjust_bridge_window(bridge, mmio_res, add_list, resource_size(&mmio)); - adjust_bridge_window(bridge, mmio_pref_res, add_list, - resource_size(&mmio_pref)); + /* + * Now that we have adjusted for alignment, update the + * bridge window resources to fill as much remaining + * resource space as possible. + */ + adjust_bridge_window(bridge, res, add_list, + resource_size(&available[i])); + } /* * Calculate how many hotplug bridges and normal bridges there @@ -2161,7 +2159,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, */ list_for_each_entry(dev, &bus->devices, bus_list) { if (!dev->is_virtfn) - remove_dev_resources(dev, &io, &mmio, &mmio_pref); + remove_dev_resources(dev, available); } /* @@ -2173,16 +2171,9 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, * split between non-hotplug bridges. This is to allow possible * hotplug bridges below them to get the extra space as well. */ - if (hotplug_bridges) { - io_per_b = div64_ul(resource_size(&io), hotplug_bridges); - mmio_per_b = div64_ul(resource_size(&mmio), hotplug_bridges); - mmio_pref_per_b = div64_ul(resource_size(&mmio_pref), - hotplug_bridges); - } else { - io_per_b = div64_ul(resource_size(&io), normal_bridges); - mmio_per_b = div64_ul(resource_size(&mmio), normal_bridges); - mmio_pref_per_b = div64_ul(resource_size(&mmio_pref), - normal_bridges); + for (i = 0; i < PCI_P2P_BRIDGE_RESOURCE_NUM; i++) { + per_bridge[i] = div64_ul(resource_size(&available[i]), + hotplug_bridges ?: normal_bridges); } for_each_pci_bridge(dev, bus) { @@ -2195,49 +2186,41 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, if (hotplug_bridges && !dev->is_hotplug_bridge) continue; - res = &dev->resource[PCI_BRIDGE_IO_WINDOW]; + for (i = 0; i < PCI_P2P_BRIDGE_RESOURCE_NUM; i++) { + res = pci_bus_resource_n(bus, i); - /* - * Make sure the split resource space is properly aligned - * for bridge windows (align it down to avoid going above - * what is available). - */ - align = pci_resource_alignment(dev, res); - resource_set_size(&io, ALIGN_DOWN_IF_NONZERO(io_per_b, align)); + /* + * Make sure the split resource space is properly + * aligned for bridge windows (align it down to + * avoid going above what is available). + */ + align = pci_resource_alignment(dev, res); + resource_set_size(&available[i], + ALIGN_DOWN_IF_NONZERO(per_bridge[i], + align)); - /* - * The x_per_b holds the extra resource space that can be - * added for each bridge but there is the minimal already - * reserved as well so adjust x.start down accordingly to - * cover the whole space. - */ - io.start -= resource_size(res); + /* + * The per_bridge holds the extra resource space + * that can be added for each bridge but there is + * the minimal already reserved as well so adjust + * x.start down accordingly to cover the whole + * space. + */ + available[i].start -= resource_size(res); + } - res = &dev->resource[PCI_BRIDGE_MEM_WINDOW]; - align = pci_resource_alignment(dev, res); - resource_set_size(&mmio, - ALIGN_DOWN_IF_NONZERO(mmio_per_b,align)); - mmio.start -= resource_size(res); + pci_bus_distribute_available_resources(b, add_list, available); - res = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; - align = pci_resource_alignment(dev, res); - resource_set_size(&mmio_pref, - ALIGN_DOWN_IF_NONZERO(mmio_pref_per_b, align)); - mmio_pref.start -= resource_size(res); - - pci_bus_distribute_available_resources(b, add_list, io, mmio, - mmio_pref); - - io.start += io.end + 1; - mmio.start += mmio.end + 1; - mmio_pref.start += mmio_pref.end + 1; + for (i = 0; i < PCI_P2P_BRIDGE_RESOURCE_NUM; i++) + available[i].start += available[i].end + 1; } } static void pci_bridge_distribute_available_resources(struct pci_dev *bridge, struct list_head *add_list) { - struct resource available_io, available_mmio, available_mmio_pref; + struct resource *res, available[PCI_P2P_BRIDGE_RESOURCE_NUM]; + unsigned int i; if (!bridge->is_hotplug_bridge) return; @@ -2245,14 +2228,13 @@ static void pci_bridge_distribute_available_resources(struct pci_dev *bridge, pci_dbg(bridge, "distributing available resources\n"); /* Take the initial extra resources from the hotplug port */ - available_io = bridge->resource[PCI_BRIDGE_IO_WINDOW]; - available_mmio = bridge->resource[PCI_BRIDGE_MEM_WINDOW]; - available_mmio_pref = bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; + for (i = 0; i < PCI_P2P_BRIDGE_RESOURCE_NUM; i++) { + res = pci_resource_n(bridge, PCI_BRIDGE_RESOURCES + i); + available[i] = *res; + } pci_bus_distribute_available_resources(bridge->subordinate, - add_list, available_io, - available_mmio, - available_mmio_pref); + add_list, available); } static bool pci_bridge_resources_not_assigned(struct pci_dev *dev) diff --git a/include/linux/pci.h b/include/linux/pci.h index 275df4058767..723e9cede69d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -119,7 +119,8 @@ enum { #define PCI_CB_BRIDGE_MEM_1_WINDOW (PCI_BRIDGE_RESOURCES + 3) /* Total number of bridge resources for P2P and CardBus */ -#define PCI_BRIDGE_RESOURCE_NUM 4 +#define PCI_P2P_BRIDGE_RESOURCE_NUM 3 +#define PCI_BRIDGE_RESOURCE_NUM 4 /* Resources assigned to buses behind the bridge */ PCI_BRIDGE_RESOURCES, From aaae2863e7319b0201029868433e8356b923063c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:10 +0300 Subject: [PATCH 1546/2711] PCI: Refactor remove_dev_resources() to use pbus_select_window() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert remove_dev_resources() to use pbus_select_window(). As 'available' is not the real resources, the index has to be adjusted as only bridge resource counterparts are present in the 'available' array. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-22-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 3bc329b1b923..cb91c6cb4d32 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -2062,34 +2062,18 @@ static void remove_dev_resource(struct resource *avail, struct pci_dev *dev, static void remove_dev_resources(struct pci_dev *dev, struct resource available[PCI_P2P_BRIDGE_RESOURCE_NUM]) { - struct resource *mmio_pref = &available[PCI_BUS_BRIDGE_PREF_MEM_WINDOW]; - struct resource *res; + struct resource *res, *b_win; + int idx; pci_dev_for_each_resource(dev, res) { - if (resource_type(res) == IORESOURCE_IO) { - remove_dev_resource(&available[PCI_BUS_BRIDGE_IO_WINDOW], - dev, res); - } else if (resource_type(res) == IORESOURCE_MEM) { + b_win = pbus_select_window(dev->bus, res); + if (!b_win) + continue; - /* - * Make sure prefetchable memory is reduced from - * the correct resource. Specifically we put 32-bit - * prefetchable memory in non-prefetchable window - * if there is a 64-bit prefetchable window. - * - * See comments in __pci_bus_size_bridges() for - * more information. - */ - if ((res->flags & IORESOURCE_PREFETCH) && - ((res->flags & IORESOURCE_MEM_64) == - (mmio_pref->flags & IORESOURCE_MEM_64))) { - remove_dev_resource(&available[PCI_BUS_BRIDGE_PREF_MEM_WINDOW], - dev, res); - } else { - remove_dev_resource(&available[PCI_BUS_BRIDGE_MEM_WINDOW], - dev, res); - } - } + idx = pci_resource_num(dev->bus->self, b_win); + idx -= PCI_BRIDGE_RESOURCES; + + remove_dev_resource(&available[idx], dev, res); } } From ebbebd8873c4bab4f3553b22f43388de6349f1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:11 +0300 Subject: [PATCH 1547/2711] PCI: Add pci_setup_one_bridge_window() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_bridge_release_resources() contains a resource type hack to work around the unsuitable __pci_setup_bridge() interface. Extract the switch statement that picks the correct bridge window setup function from pci_claim_bridge_resource() into pci_setup_one_bridge_window() and use it also in pci_bridge_release_resources(). Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-23-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index cb91c6cb4d32..031ad682aca1 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -953,6 +953,23 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); } +static void pci_setup_one_bridge_window(struct pci_dev *bridge, int resno) +{ + switch (resno) { + case PCI_BRIDGE_IO_WINDOW: + pci_setup_bridge_io(bridge); + break; + case PCI_BRIDGE_MEM_WINDOW: + pci_setup_bridge_mmio(bridge); + break; + case PCI_BRIDGE_PREF_MEM_WINDOW: + pci_setup_bridge_mmio_pref(bridge); + break; + default: + return; + } +} + void __weak pcibios_setup_bridge(struct pci_bus *bus, unsigned long type) { } @@ -987,19 +1004,7 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i) if (pci_bus_clip_resource(bridge, i)) ret = pci_claim_resource(bridge, i); - switch (i) { - case PCI_BRIDGE_IO_WINDOW: - pci_setup_bridge_io(bridge); - break; - case PCI_BRIDGE_MEM_WINDOW: - pci_setup_bridge_mmio(bridge); - break; - case PCI_BRIDGE_PREF_MEM_WINDOW: - pci_setup_bridge_mmio_pref(bridge); - break; - default: - return -EINVAL; - } + pci_setup_one_bridge_window(bridge, i); return ret; } @@ -1839,11 +1844,7 @@ static void pci_bridge_release_resources(struct pci_bus *bus, if (ret) return; - type = r->flags & PCI_RES_TYPE_MASK; - /* Avoiding touch the one without PREF */ - if (type & IORESOURCE_PREFETCH) - type = IORESOURCE_PREFETCH; - __pci_setup_bridge(bus, type); + pci_setup_one_bridge_window(dev, PCI_BRIDGE_RESOURCES + idx); } enum release_type { From 159fbfd0412b0351a512d716757b6eac4639da84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:12 +0300 Subject: [PATCH 1548/2711] PCI: Pass bridge window to pci_bus_release_bridge_resources() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_bus_release_bridge_resources() takes type, which is converted into a bridge window resource in pci_bridge_release_resources(). Find out the correct bridge window for resource whose assignment failed. Pass that bridge window to pci_bus_release_bridge_resources() instead of passing the type. When recursing to subordinate, check which bridge windows have to be released and recurse for each. For now, use pbus_select_window_for_type() instead of pbus_select_window() because non-bridge window resources still have their flags reset which destroys the type information from the struct resource. The struct pci_dev_resource holds a copy of the flags which are used instead. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-24-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 71 ++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 031ad682aca1..4ce747b5dea3 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1800,51 +1800,24 @@ static void __pci_bridge_assign_resources(const struct pci_dev *bridge, } static void pci_bridge_release_resources(struct pci_bus *bus, - unsigned long type) + struct resource *b_win) { struct pci_dev *dev = bus->self; - struct resource *r; - struct resource *b_res; int idx, ret; - b_res = &dev->resource[PCI_BRIDGE_RESOURCES]; - - /* - * 1. If IO port assignment fails, release bridge IO port. - * 2. If non pref MMIO assignment fails, release bridge nonpref MMIO. - * 3. If 64bit pref MMIO assignment fails, and bridge pref is 64bit, - * release bridge pref MMIO. - * 4. If pref MMIO assignment fails, and bridge pref is 32bit, - * release bridge pref MMIO. - * 5. If pref MMIO assignment fails, and bridge pref is not - * assigned, release bridge nonpref MMIO. - */ - if (type & IORESOURCE_IO) - idx = 0; - else if (!(type & IORESOURCE_PREFETCH)) - idx = 1; - else if ((type & IORESOURCE_MEM_64) && - (b_res[2].flags & IORESOURCE_MEM_64)) - idx = 2; - else if (!(b_res[2].flags & IORESOURCE_MEM_64) && - (b_res[2].flags & IORESOURCE_PREFETCH)) - idx = 2; - else - idx = 1; - - r = &b_res[idx]; - - if (!r->parent) + if (!b_win->parent) return; - /* If there are children, release them all */ - release_child_resources(r); + idx = pci_resource_num(dev, b_win); - ret = pci_release_resource(dev, PCI_BRIDGE_RESOURCES + idx); + /* If there are children, release them all */ + release_child_resources(b_win); + + ret = pci_release_resource(dev, idx); if (ret) return; - pci_setup_one_bridge_window(dev, PCI_BRIDGE_RESOURCES + idx); + pci_setup_one_bridge_window(dev, idx); } enum release_type { @@ -1857,7 +1830,7 @@ enum release_type { * a larger window later. */ static void pci_bus_release_bridge_resources(struct pci_bus *bus, - unsigned long type, + struct resource *b_win, enum release_type rel_type) { struct pci_dev *dev; @@ -1865,6 +1838,8 @@ static void pci_bus_release_bridge_resources(struct pci_bus *bus, list_for_each_entry(dev, &bus->devices, bus_list) { struct pci_bus *b = dev->subordinate; + struct resource *res; + if (!b) continue; @@ -1873,9 +1848,15 @@ static void pci_bus_release_bridge_resources(struct pci_bus *bus, if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) continue; - if (rel_type == whole_subtree) - pci_bus_release_bridge_resources(b, type, - whole_subtree); + if (rel_type != whole_subtree) + continue; + + pci_bus_for_each_resource(b, res) { + if (res->parent != b_win) + continue; + + pci_bus_release_bridge_resources(b, res, whole_subtree); + } } if (pci_is_root_bus(bus)) @@ -1885,7 +1866,7 @@ static void pci_bus_release_bridge_resources(struct pci_bus *bus, return; if ((rel_type == whole_subtree) || is_leaf_bridge) - pci_bridge_release_resources(bus, type); + pci_bridge_release_resources(bus, b_win); } static void pci_bus_dump_res(struct pci_bus *bus) @@ -2282,9 +2263,13 @@ static void pci_prepare_next_assign_round(struct list_head *fail_head, * enough to contain child device resources. */ list_for_each_entry(fail_res, fail_head, list) { - pci_bus_release_bridge_resources(fail_res->dev->bus, - fail_res->flags & PCI_RES_TYPE_MASK, - rel_type); + struct pci_bus *bus = fail_res->dev->bus; + struct resource *b_win; + + b_win = pbus_select_window_for_type(bus, fail_res->flags); + if (!b_win) + continue; + pci_bus_release_bridge_resources(bus, b_win, rel_type); } /* Restore size and flags */ From 43b4f7cd064b2ae11742f33e2af195adae00c617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Aug 2025 16:11:13 +0300 Subject: [PATCH 1549/2711] PCI: Alter misleading recursion to pci_bus_release_bridge_resources() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recursing into pci_bus_release_bridge_resources() should not alter rel_type because it makes no sense to change the release type within the recursion call chain. A literal "whole_subtree" is passed into the recursion instead of "rel_type" parameter which is misleading as the release type should remain the same throughout the entire operation. This is not a correctness issue because of the preceding if () that only allows the recursion to happen if rel_type is "whole_subtree". Still, replace the non-intuitive parameter with direct passing of "rel_type". Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250829131113.36754-25-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 4ce747b5dea3..d264f16772b9 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1855,7 +1855,7 @@ static void pci_bus_release_bridge_resources(struct pci_bus *bus, if (res->parent != b_win) continue; - pci_bus_release_bridge_resources(b, res, whole_subtree); + pci_bus_release_bridge_resources(b, res, rel_type); } } From c5dca38633daa1e240144bac453cf9065604a413 Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Mon, 15 Sep 2025 16:57:20 +0200 Subject: [PATCH 1550/2711] cxl: Documentation/driver-api/cxl: Describe the x86 Low Memory Hole solution Add documentation on how to resolve conflicts between CXL Fixed Memory Windows, Platform Low Memory Holes, intermediate Switch and Endpoint Decoders. [dj]: Fixed inconsistent spacing after '.' [dj]: Fixed subject line from Alison. [dj]: Removed '::' before table from Bagas. Reviewed-by: Gregory Price Signed-off-by: Fabio M. De Francesco Reviewed-by: Bagas Sanjaya Reviewed-by: Alison Schofield Reviewed-by: Dave Jiang Signed-off-by: Dave Jiang --- Documentation/driver-api/cxl/conventions.rst | 135 +++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/Documentation/driver-api/cxl/conventions.rst b/Documentation/driver-api/cxl/conventions.rst index da347a81a237..e37336d7b116 100644 --- a/Documentation/driver-api/cxl/conventions.rst +++ b/Documentation/driver-api/cxl/conventions.rst @@ -45,3 +45,138 @@ Detailed Description of the Change ---------------------------------- + + +Resolve conflict between CFMWS, Platform Memory Holes, and Endpoint Decoders +============================================================================ + +Document +-------- + +CXL Revision 3.2, Version 1.0 + +License +------- + +SPDX-License Identifier: CC-BY-4.0 + +Creator/Contributors +-------------------- + +- Fabio M. De Francesco, Intel +- Dan J. Williams, Intel +- Mahesh Natu, Intel + +Summary of the Change +--------------------- + +According to the current Compute Express Link (CXL) Specifications (Revision +3.2, Version 1.0), the CXL Fixed Memory Window Structure (CFMWS) describes zero +or more Host Physical Address (HPA) windows associated with each CXL Host +Bridge. Each window represents a contiguous HPA range that may be interleaved +across one or more targets, including CXL Host Bridges. Each window has a set +of restrictions that govern its usage. It is the Operating System-directed +configuration and Power Management (OSPM) responsibility to utilize each window +for the specified use. + +Table 9-22 of the current CXL Specifications states that the Window Size field +contains the total number of consecutive bytes of HPA this window describes. +This value must be a multiple of the Number of Interleave Ways (NIW) * 256 MB. + +Platform Firmware (BIOS) might reserve physical addresses below 4 GB where a +memory gap such as the Low Memory Hole for PCIe MMIO may exist. In such cases, +the CFMWS Range Size may not adhere to the NIW * 256 MB rule. + +The HPA represents the actual physical memory address space that the CXL devices +can decode and respond to, while the System Physical Address (SPA), a related +but distinct concept, represents the system-visible address space that users can +direct transaction to and so it excludes reserved regions. + +BIOS publishes CFMWS to communicate the active SPA ranges that, on platforms +with LMH's, map to a strict subset of the HPA. The SPA range trims out the hole, +resulting in lost capacity in the Endpoints with no SPA to map to that part of +the HPA range that intersects the hole. + +E.g, an x86 platform with two CFMWS and an LMH starting at 2 GB: + + +--------+------------+-------------------+------------------+-------------------+------+ + | Window | CFMWS Base | CFMWS Size | HDM Decoder Base | HDM Decoder Size | Ways | + +========+============+===================+==================+===================+======+ + |  0 | 0 GB | 2 GB | 0 GB | 3 GB | 12 | + +--------+------------+-------------------+------------------+-------------------+------+ + |  1 | 4 GB | NIW*256MB Aligned | 4 GB | NIW*256MB Aligned | 12 | + +--------+------------+-------------------+------------------+-------------------+------+ + +HDM decoder base and HDM decoder size represent all the 12 Endpoint Decoders of +a 12 ways region and all the intermediate Switch Decoders. They are configured +by the BIOS according to the NIW * 256MB rule, resulting in a HPA range size of +3GB. Instead, the CFMWS Base and CFMWS Size are used to configure the Root +Decoder HPA range that results smaller (2GB) than that of the Switch and +Endpoint Decoders in the hierarchy (3GB). + +This creates 2 issues which lead to a failure to construct a region: + +1) A mismatch in region size between root and any HDM decoder. The root decoders + will always be smaller due to the trim. + +2) The trim causes the root decoder to violate the (NIW * 256MB) rule. + +This change allows a region with a base address of 0GB to bypass these checks to +allow for region creation with the trimmed root decoder address range. + +This change does not allow for any other arbitrary region to violate these +checks - it is intended exclusively to enable x86 platforms which map CXL memory +under 4GB. + +Despite the HDM decoders covering the PCIE hole HPA region, it is expected that +the platform will never route address accesses to the CXL complex because the +root decoder only covers the trimmed region (which excludes this). This is +outside the ability of Linux to enforce. + +On the example platform, only the first 2GB will be potentially usable, but +Linux, aiming to adhere to the current specifications, fails to construct +Regions and attach Endpoint and intermediate Switch Decoders to them. + +There are several points of failure that due to the expectation that the Root +Decoder HPA size, that is equal to the CFMWS from which it is configured, has +to be greater or equal to the matching Switch and Endpoint HDM Decoders. + +In order to succeed with construction and attachment, Linux must construct a +Region with Root Decoder HPA range size, and then attach to that all the +intermediate Switch Decoders and Endpoint Decoders that belong to the hierarchy +regardless of their range sizes. + +Benefits of the Change +---------------------- + +Without the change, the OSPM wouldn't match intermediate Switch and Endpoint +Decoders with Root Decoders configured with CFMWS HPA sizes that don't align +with the NIW * 256MB constraint, and so it leads to lost memdev capacity. + +This change allows the OSPM to construct Regions and attach intermediate Switch +and Endpoint Decoders to them, so that the addressable part of the memory +devices total capacity is made available to the users. + +References +---------- + +Compute Express Link Specification Revision 3.2, Version 1.0 + + +Detailed Description of the Change +---------------------------------- + +The description of the Window Size field in table 9-22 needs to account for +platforms with Low Memory Holes, where SPA ranges might be subsets of the +endpoints HPA. Therefore, it has to be changed to the following: + +"The total number of consecutive bytes of HPA this window represents. This value +shall be a multiple of NIW * 256 MB. + +On platforms that reserve physical addresses below 4 GB, such as the Low Memory +Hole for PCIe MMIO on x86, an instance of CFMWS whose Base HPA range is 0 might +have a size that doesn't align with the NIW * 256 MB constraint. + +Note that the matching intermediate Switch Decoders and the Endpoint Decoders +HPA range sizes must still align to the above-mentioned rule, but the memory +capacity that exceeds the CFMWS window size won't be accessible.". From b3a37bff8daf50cdd6fa9ebe4a503d4261d99796 Mon Sep 17 00:00:00 2001 From: Sagi Shahar Date: Tue, 26 Aug 2025 18:17:26 -0700 Subject: [PATCH 1551/2711] KVM: TDX: Reject fully in-kernel irqchip if EOIs are protected, i.e. for TDX VMs Reject KVM_CREATE_IRQCHIP if the VM type has protected EOIs, i.e. if KVM can't intercept EOI and thus can't faithfully emulate level-triggered interrupts that are routed through the I/O APIC. For TDX VMs, the TDX-Module owns the VMX EOI-bitmap and configures all IRQ vectors to have the CPU accelerate EOIs, i.e. doesn't allow KVM to intercept any EOIs. KVM already requires a split irqchip[1], but does so during vCPU creation, which is both too late to allow userspace to fallback to a split irqchip and a less-than-stellar experience for userspace since an -EINVAL on KVM_VCPU_CREATE is far harder to debug/triage than failure exactly on KVM_CREATE_IRQCHIP. And of course, allowing an action that ultimately fails is arguably a bug regardless of the impact on userspace. Link: https://lore.kernel.org/lkml/20250222014757.897978-11-binbin.wu@linux.intel.com [1] Link: https://lore.kernel.org/lkml/aK3vZ5HuKKeFuuM4@google.com Suggested-by: Sean Christopherson Signed-off-by: Sagi Shahar Reviewed-by: Xiaoyao Li Reviewed-by: Binbin Wu Acked-by: Kai Huang Link: https://lore.kernel.org/r/20250827011726.2451115-1-sagis@google.com [sean: massage shortlog+changelog, relocate setting has_protected_eoi] Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx/tdx.c | 5 +++++ arch/x86/kvm/x86.c | 9 +++++++++ 3 files changed, 15 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index b1f87b5750f8..990fbbb96ebf 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1362,6 +1362,7 @@ struct kvm_arch { u8 vm_type; bool has_private_mem; bool has_protected_state; + bool has_protected_eoi; bool pre_fault_allowed; struct hlist_head *mmu_page_hash; struct list_head active_mmu_pages; diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 66744f5768c8..17559f3ffbd5 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -629,6 +629,11 @@ int tdx_vm_init(struct kvm *kvm) struct kvm_tdx *kvm_tdx = to_kvm_tdx(kvm); kvm->arch.has_protected_state = true; + /* + * TDX Module doesn't allow the hypervisor to modify the EOI-bitmap, + * i.e. all EOIs are accelerated and never trigger exits. + */ + kvm->arch.has_protected_eoi = true; kvm->arch.has_private_mem = true; kvm->arch.disabled_quirks |= KVM_X86_QUIRK_IGNORE_GUEST_PAT; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bf386f2ebba3..99f2a150ca78 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6989,6 +6989,15 @@ set_identity_unlock: if (irqchip_in_kernel(kvm)) goto create_irqchip_unlock; + /* + * Disallow an in-kernel I/O APIC if the VM has protected EOIs, + * i.e. if KVM can't intercept EOIs and thus can't properly + * emulate level-triggered interrupts. + */ + r = -ENOTTY; + if (kvm->arch.has_protected_eoi) + goto create_irqchip_unlock; + r = -EINVAL; if (kvm->created_vcpus) goto create_irqchip_unlock; From 06dc910f5e07a3b85ea1a6891596689f492ecc72 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Fri, 18 Jul 2025 08:19:01 +0800 Subject: [PATCH 1552/2711] KVM: x86/pmu: Correct typo "_COUTNERS" to "_COUNTERS" Fix typos. "_COUTNERS" -> "_COUNTERS". Signed-off-by: Dapeng Mi Tested-by: Yi Lai Link: https://lore.kernel.org/r/20250718001905.196989-2-dapeng1.mi@linux.intel.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 8 ++++---- arch/x86/kvm/vmx/pmu_intel.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 990fbbb96ebf..464a636b2dc6 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -545,10 +545,10 @@ struct kvm_pmc { #define KVM_MAX_NR_GP_COUNTERS KVM_MAX(KVM_MAX_NR_INTEL_GP_COUNTERS, \ KVM_MAX_NR_AMD_GP_COUNTERS) -#define KVM_MAX_NR_INTEL_FIXED_COUTNERS 3 -#define KVM_MAX_NR_AMD_FIXED_COUTNERS 0 -#define KVM_MAX_NR_FIXED_COUNTERS KVM_MAX(KVM_MAX_NR_INTEL_FIXED_COUTNERS, \ - KVM_MAX_NR_AMD_FIXED_COUTNERS) +#define KVM_MAX_NR_INTEL_FIXED_COUNTERS 3 +#define KVM_MAX_NR_AMD_FIXED_COUNTERS 0 +#define KVM_MAX_NR_FIXED_COUNTERS KVM_MAX(KVM_MAX_NR_INTEL_FIXED_COUNTERS, \ + KVM_MAX_NR_AMD_FIXED_COUNTERS) struct kvm_pmu { u8 version; diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 07baff96300f..b2a2c4ebf448 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -478,8 +478,8 @@ static __always_inline u64 intel_get_fixed_pmc_eventsel(unsigned int index) }; u64 eventsel; - BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_perf_ids) != KVM_MAX_NR_INTEL_FIXED_COUTNERS); - BUILD_BUG_ON(index >= KVM_MAX_NR_INTEL_FIXED_COUTNERS); + BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_perf_ids) != KVM_MAX_NR_INTEL_FIXED_COUNTERS); + BUILD_BUG_ON(index >= KVM_MAX_NR_INTEL_FIXED_COUNTERS); /* * Yell if perf reports support for a fixed counter but perf doesn't @@ -625,7 +625,7 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu) pmu->gp_counters[i].current_config = 0; } - for (i = 0; i < KVM_MAX_NR_INTEL_FIXED_COUTNERS; i++) { + for (i = 0; i < KVM_MAX_NR_INTEL_FIXED_COUNTERS; i++) { pmu->fixed_counters[i].type = KVM_PMC_FIXED; pmu->fixed_counters[i].vcpu = vcpu; pmu->fixed_counters[i].idx = i + KVM_FIXED_PMC_BASE_IDX; From 4319fa120f0f42be167d56d84ece94340e11d61e Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Mon, 1 Sep 2025 21:18:21 +0800 Subject: [PATCH 1553/2711] KVM: x86: Use guard() instead of mutex_lock() to simplify code Use guard(mutex) instead of mutex_lock/mutex_unlock pair to simplify the error handling when allocating the APIC access page. No functional change intended. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250901131822.647802-1-liaoyuanhong@vivo.com [sean: add blank link to isolate guard(), tweak changelog] Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index ab48e057dbdc..c7486f213432 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2747,24 +2747,21 @@ void kvm_apic_update_apicv(struct kvm_vcpu *vcpu) int kvm_alloc_apic_access_page(struct kvm *kvm) { void __user *hva; - int ret = 0; - mutex_lock(&kvm->slots_lock); + guard(mutex)(&kvm->slots_lock); + if (kvm->arch.apic_access_memslot_enabled || kvm->arch.apic_access_memslot_inhibited) - goto out; + return 0; hva = __x86_set_memory_region(kvm, APIC_ACCESS_PAGE_PRIVATE_MEMSLOT, APIC_DEFAULT_PHYS_BASE, PAGE_SIZE); - if (IS_ERR(hva)) { - ret = PTR_ERR(hva); - goto out; - } + if (IS_ERR(hva)) + return PTR_ERR(hva); kvm->arch.apic_access_memslot_enabled = true; -out: - mutex_unlock(&kvm->slots_lock); - return ret; + + return 0; } EXPORT_SYMBOL_GPL(kvm_alloc_apic_access_page); From cbd860293d139fae44b76d821d8112aab89d8e17 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Mon, 1 Sep 2025 21:16:04 +0800 Subject: [PATCH 1554/2711] KVM: x86: hyper-v: Use guard() instead of mutex_lock() to simplify code Use guard(mutex) instead of mutex_lock/mutex_unlock pair to simplify the error handling when setting up the TSC page for a Hyper-V guest. No functional change intended. Signed-off-by: Liao Yuanhong Link: https://lore.kernel.org/r/20250901131604.646415-1-liaoyuanhong@vivo.com [sean: tweak changelog] Signed-off-by: Sean Christopherson --- arch/x86/kvm/hyperv.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 72b19a88a776..a471900c7325 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1168,15 +1168,15 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm, BUILD_BUG_ON(sizeof(tsc_seq) != sizeof(hv->tsc_ref.tsc_sequence)); BUILD_BUG_ON(offsetof(struct ms_hyperv_tsc_page, tsc_sequence) != 0); - mutex_lock(&hv->hv_lock); + guard(mutex)(&hv->hv_lock); if (hv->hv_tsc_page_status == HV_TSC_PAGE_BROKEN || hv->hv_tsc_page_status == HV_TSC_PAGE_SET || hv->hv_tsc_page_status == HV_TSC_PAGE_UNSET) - goto out_unlock; + return; if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE)) - goto out_unlock; + return; gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT; /* @@ -1192,7 +1192,7 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm, goto out_err; hv->hv_tsc_page_status = HV_TSC_PAGE_SET; - goto out_unlock; + return; } /* @@ -1228,12 +1228,10 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm, goto out_err; hv->hv_tsc_page_status = HV_TSC_PAGE_SET; - goto out_unlock; + return; out_err: hv->hv_tsc_page_status = HV_TSC_PAGE_BROKEN; -out_unlock: - mutex_unlock(&hv->hv_lock); } void kvm_hv_request_tsc_page_update(struct kvm *kvm) From 5b5133e6a55bf6ca18de1b33c2ffe17d1162ec8e Mon Sep 17 00:00:00 2001 From: Jiaming Zhang Date: Sat, 6 Sep 2025 01:47:36 +0800 Subject: [PATCH 1555/2711] Documentation: KVM: Call out that KVM strictly follows the 8254 PIT spec Explicitly document that the behavior of KVM_SET_PIT2 strictly conforms to the Intel 8254 PIT hardware specification, specifically that a write of '0' adheres to the spec's definition that a programmed count of '0' is converted to the maximum possible value (2^16). E.g. an unaware userspace might attempt to validate that KVM_GET_PIT2 returns the exact state set via KVM_SET_PIT2, and be surprised when the returned count is 65536, not 0. Add a references to the Intel 8254 PIT datasheet that will hopefully stay fresh for some time (the internet isn't exactly brimming with copies of the 8254 datasheet). Link: https://lore.kernel.org/all/CANypQFbEySjKOFLqtFFf2vrEe=NBr7XJfbkjQhqXuZGg7Rpoxw@mail.gmail.com Signed-off-by: Jiaming Zhang Link: https://lore.kernel.org/r/20250905174736.260694-1-r772577952@gmail.com [sean: add context Link, drop local APIC change, massage changelog accordingly] Signed-off-by: Sean Christopherson --- Documentation/virt/kvm/api.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 6aa40ee05a4a..b3f2395a62d1 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -3075,6 +3075,12 @@ This IOCTL replaces the obsolete KVM_GET_PIT. Sets the state of the in-kernel PIT model. Only valid after KVM_CREATE_PIT2. See KVM_GET_PIT2 for details on struct kvm_pit_state2. +.. Tip:: + ``KVM_SET_PIT2`` strictly adheres to the spec of Intel 8254 PIT. For example, + a ``count`` value of 0 in ``struct kvm_pit_channel_state`` is interpreted as + 65536, which is the maximum count value. Refer to `Intel 8254 programmable + interval timer `_. + This IOCTL replaces the obsolete KVM_SET_PIT. From 7c85e4da8ce734eaca66a921aabeb6107842169f Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Sat, 6 Sep 2025 15:16:56 -0500 Subject: [PATCH 1556/2711] dt-bindings: clock: silabs,si5341: Add missing properties Add "clock-output-names" which is a standard property for clock providers. Add the "always-on" boolean property which was undocumented, but already in use for some time. The flag prevents a clock output from being disabled. Signed-off-by: Rob Herring (Arm) Tested-by: Michal Simek Reviewed-by: Michal Simek Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/silabs,si5341.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.yaml b/Documentation/devicetree/bindings/clock/silabs,si5341.yaml index b4f7efdf0b7b..d6416bded3d5 100644 --- a/Documentation/devicetree/bindings/clock/silabs,si5341.yaml +++ b/Documentation/devicetree/bindings/clock/silabs,si5341.yaml @@ -73,6 +73,8 @@ properties: - const: in1 - const: in2 + clock-output-names: true + interrupts: maxItems: 1 description: Interrupt for INTRb pin @@ -130,6 +132,10 @@ patternProperties: description: Number of clock output maximum: 9 + always-on: + description: Set to keep the clock output always running + type: boolean + silabs,format: description: Output format $ref: /schemas/types.yaml#/definitions/uint32 From 1fac4d003fd6895599053f8f046139108fba68b8 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:21 +0200 Subject: [PATCH 1557/2711] thunderbolt: Update acpi.c function documentation Make acpi.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/acpi.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/thunderbolt/acpi.c b/drivers/thunderbolt/acpi.c index d2a0054217da..45d1415871b4 100644 --- a/drivers/thunderbolt/acpi.c +++ b/drivers/thunderbolt/acpi.c @@ -86,7 +86,7 @@ out_put: * @nhi ACPI node. For each reference a device link is added. The link * is automatically removed by the driver core. * - * Returns %true if at least one link was created. + * Returns %true if at least one link was created, %false otherwise. */ bool tb_acpi_add_links(struct tb_nhi *nhi) { @@ -113,8 +113,10 @@ bool tb_acpi_add_links(struct tb_nhi *nhi) /** * tb_acpi_is_native() - Did the platform grant native TBT/USB4 control * - * Returns %true if the platform granted OS native control over - * TBT/USB4. In this case software based connection manager can be used, + * Return: %true if the platform granted OS native control over + * TBT/USB4, %false otherwise. + * + * When returned %true, software based connection manager can be used, * otherwise there is firmware based connection manager running. */ bool tb_acpi_is_native(void) @@ -126,8 +128,8 @@ bool tb_acpi_is_native(void) /** * tb_acpi_may_tunnel_usb3() - Is USB3 tunneling allowed by the platform * - * When software based connection manager is used, this function - * returns %true if platform allows native USB3 tunneling. + * Return: %true if software based connection manager is used and + * platform allows native USB 3.x tunneling, %false otherwise. */ bool tb_acpi_may_tunnel_usb3(void) { @@ -139,8 +141,8 @@ bool tb_acpi_may_tunnel_usb3(void) /** * tb_acpi_may_tunnel_dp() - Is DisplayPort tunneling allowed by the platform * - * When software based connection manager is used, this function - * returns %true if platform allows native DP tunneling. + * Return: %true if software based connection manager is used and + * platform allows native DP tunneling, %false otherwise. */ bool tb_acpi_may_tunnel_dp(void) { @@ -152,8 +154,8 @@ bool tb_acpi_may_tunnel_dp(void) /** * tb_acpi_may_tunnel_pcie() - Is PCIe tunneling allowed by the platform * - * When software based connection manager is used, this function - * returns %true if platform allows native PCIe tunneling. + * Return: %true if software based connection manager is used and + * platform allows native PCIe tunneling, %false otherwise. */ bool tb_acpi_may_tunnel_pcie(void) { @@ -165,8 +167,8 @@ bool tb_acpi_may_tunnel_pcie(void) /** * tb_acpi_is_xdomain_allowed() - Are XDomain connections allowed * - * When software based connection manager is used, this function - * returns %true if platform allows XDomain connections. + * Return: %true if software based connection manager is used and + * platform allows XDomain tunneling, %false otherwise. */ bool tb_acpi_is_xdomain_allowed(void) { @@ -256,7 +258,7 @@ static int tb_acpi_retimer_set_power(struct tb_port *port, bool power) * * This should only be called if the USB4/TBT link is not up. * - * Returns %0 on success. + * Return: %0 on success, negative errno otherwise. */ int tb_acpi_power_on_retimers(struct tb_port *port) { @@ -270,7 +272,7 @@ int tb_acpi_power_on_retimers(struct tb_port *port) * This is the opposite of tb_acpi_power_on_retimers(). After returning * successfully the normal operations with the @port can continue. * - * Returns %0 on success. + * Return: %0 on success, negative errno otherwise. */ int tb_acpi_power_off_retimers(struct tb_port *port) { From c0a078d7bc008d27f06cfc6bb05d311158d4b3b9 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:22 +0200 Subject: [PATCH 1558/2711] thunderbolt: Update cap.c function documentation Make cap.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/cap.c | 49 +++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/drivers/thunderbolt/cap.c b/drivers/thunderbolt/cap.c index 8ecd610c62d5..4ab22d5291ac 100644 --- a/drivers/thunderbolt/cap.c +++ b/drivers/thunderbolt/cap.c @@ -64,10 +64,14 @@ static void tb_port_dummy_read(struct tb_port *port) * @port: Port to find the capability for * @offset: Previous capability offset (%0 for start) * - * Returns dword offset of the next capability in port config space - * capability list and returns it. Passing %0 returns the first entry in - * the capability list. If no next capability is found returns %0. In case - * of failure returns negative errno. + * Finds dword offset of the next capability in port config space + * capability list. When passed %0 in @offset parameter, first entry + * will be returned, if it exists. + * + * Return: + * * Double word offset of the first or next capability - On success. + * * %0 - If no next capability is found. + * * Negative errno - Another error occurred. */ int tb_port_next_cap(struct tb_port *port, unsigned int offset) { @@ -112,9 +116,10 @@ static int __tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap) * @port: Port to find the capability for * @cap: Capability to look * - * Returns offset to start of capability or %-ENOENT if no such - * capability was found. Negative errno is returned if there was an - * error. + * Return: + * * Offset to the start of capability - On success. + * * %-ENOENT - If no such capability was found. + * * Negative errno - Another error occurred. */ int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap) { @@ -137,10 +142,14 @@ int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap) * @sw: Switch to find the capability for * @offset: Previous capability offset (%0 for start) * - * Finds dword offset of the next capability in router config space - * capability list and returns it. Passing %0 returns the first entry in - * the capability list. If no next capability is found returns %0. In case - * of failure returns negative errno. + * Finds dword offset of the next capability in port config space + * capability list. When passed %0 in @offset parameter, first entry + * will be returned, if it exists. + * + * Return: + * * Double word offset of the first or next capability - On success. + * * %0 - If no next capability is found. + * * Negative errno - Another error occurred. */ int tb_switch_next_cap(struct tb_switch *sw, unsigned int offset) { @@ -181,9 +190,10 @@ int tb_switch_next_cap(struct tb_switch *sw, unsigned int offset) * @sw: Switch to find the capability for * @cap: Capability to look * - * Returns offset to start of capability or %-ENOENT if no such - * capability was found. Negative errno is returned if there was an - * error. + * Return: + * * Offset to the start of capability - On success. + * * %-ENOENT - If no such capability was found. + * * Negative errno - Another error occurred. */ int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap) { @@ -213,10 +223,13 @@ int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap) * @sw: Switch to find the capability for * @vsec: Vendor specific capability to look * - * Functions enumerates vendor specific capabilities (VSEC) of a switch - * and returns offset when capability matching @vsec is found. If no - * such capability is found returns %-ENOENT. In case of error returns - * negative errno. + * This function enumerates vendor specific capabilities (VSEC) of a + * switch and returns offset when capability matching @vsec is found. + * + * Return: + * * Offset of capability - On success. + * * %-ENOENT - If capability was not found. + * * Negative errno - Another error occurred. */ int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec) { From 66cf14cc9fdf2a9747bdaf2a629e3a510d31a3de Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:23 +0200 Subject: [PATCH 1559/2711] thunderbolt: Update clx.c function documentation Make clx.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/clx.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/thunderbolt/clx.c b/drivers/thunderbolt/clx.c index 787dfd1550e5..1637e79d988a 100644 --- a/drivers/thunderbolt/clx.c +++ b/drivers/thunderbolt/clx.c @@ -167,7 +167,8 @@ static int tb_port_clx(struct tb_port *port) * @port: USB4 port to check * @clx: Mask of CL states to check * - * Returns true if any of the given CL states is enabled for @port. + * Return: %true if any of the given CL states is enabled for @port, + * %false otherwise. */ bool tb_port_clx_is_enabled(struct tb_port *port, unsigned int clx) { @@ -177,6 +178,8 @@ bool tb_port_clx_is_enabled(struct tb_port *port, unsigned int clx) /** * tb_switch_clx_is_supported() - Is CLx supported on this type of router * @sw: The router to check CLx support for + * + * Return: %true if CLx is supported, %false otherwise. */ static bool tb_switch_clx_is_supported(const struct tb_switch *sw) { @@ -203,7 +206,7 @@ static bool tb_switch_clx_is_supported(const struct tb_switch *sw) * Can be called for any router. Initializes the current CL state by * reading it from the hardware. * - * Returns %0 in case of success and negative errno in case of failure. + * Return: %0 on success, negative errno otherwise. */ int tb_switch_clx_init(struct tb_switch *sw) { @@ -313,7 +316,7 @@ static bool validate_mask(unsigned int clx) * is not inter-domain link. The complete set of conditions is described in CM * Guide 1.0 section 8.1. * - * Returns %0 on success or an error code on failure. + * Return: %0 on success, negative errno otherwise. */ int tb_switch_clx_enable(struct tb_switch *sw, unsigned int clx) { @@ -390,8 +393,7 @@ int tb_switch_clx_enable(struct tb_switch *sw, unsigned int clx) * Disables all CL states of the given router. Can be called on any * router and if the states were not enabled already does nothing. * - * Returns the CL states that were disabled or negative errno in case of - * failure. + * Return: CL states that were disabled or negative errno otherwise. */ int tb_switch_clx_disable(struct tb_switch *sw) { From 38f33b8e2cc2d3d3bae88dd5b4546e4f38cda3be Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:24 +0200 Subject: [PATCH 1560/2711] thunderbolt: Update ctl.c function documentation Make ctl.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/ctl.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index 1db2e951b53f..f92175ee3841 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -82,6 +82,8 @@ static DEFINE_MUTEX(tb_cfg_request_lock); * * This is refcounted object so when you are done with this, call * tb_cfg_request_put() to it. + * + * Return: &struct tb_cfg_request on success, %NULL otherwise. */ struct tb_cfg_request *tb_cfg_request_alloc(void) { @@ -359,7 +361,7 @@ static void tb_ctl_tx_callback(struct tb_ring *ring, struct ring_frame *frame, * * len must be a multiple of four. * - * Return: Returns 0 on success or an error code on failure. + * Return: %0 on success, negative errno otherwise. */ static int tb_ctl_tx(struct tb_ctl *ctl, const void *data, size_t len, enum tb_cfg_pkg_type type) @@ -539,6 +541,8 @@ static void tb_cfg_request_work(struct work_struct *work) * * This queues @req on the given control channel without waiting for it * to complete. When the request completes @callback is called. + * + * Return: %0 on success, negative errno otherwise. */ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req, void (*callback)(void *), void *callback_data) @@ -605,6 +609,9 @@ static void tb_cfg_request_complete(void *data) * triggers the request is canceled before function returns. Note the * caller needs to make sure only one message for given switch is active * at a time. + * + * Return: &struct tb_cfg_result with non-zero @err field if error + * has occurred. */ struct tb_cfg_result tb_cfg_request_sync(struct tb_ctl *ctl, struct tb_cfg_request *req, @@ -641,7 +648,7 @@ struct tb_cfg_result tb_cfg_request_sync(struct tb_ctl *ctl, * * cb will be invoked once for every hot plug event. * - * Return: Returns a pointer on success or NULL on failure. + * Return: Pointer to &struct tb_ctl, %NULL on failure. */ struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int index, int timeout_msec, event_cb cb, void *cb_data) @@ -764,8 +771,9 @@ void tb_ctl_stop(struct tb_ctl *ctl) * @route: Router that originated the event * @error: Pointer to the notification package * - * Call this as response for non-plug notification to ack it. Returns - * %0 on success or an error code on failure. + * Call this as a response for non-plug notification to ack it. + * + * Return: %0 on success, negative errno otherwise. */ int tb_cfg_ack_notification(struct tb_ctl *ctl, u64 route, const struct cfg_error_pkg *error) @@ -827,8 +835,9 @@ int tb_cfg_ack_notification(struct tb_ctl *ctl, u64 route, * @port: Port where the hot plug/unplug happened * @unplug: Ack hot plug or unplug * - * Call this as response for hot plug/unplug event to ack it. - * Returns %0 on success or an error code on failure. + * Call this as a response for hot plug/unplug event to ack it. + * + * Return: %0 on success, negative errno otherwise. */ int tb_cfg_ack_plug(struct tb_ctl *ctl, u64 route, u32 port, bool unplug) { @@ -895,6 +904,9 @@ static bool tb_cfg_copy(struct tb_cfg_request *req, const struct ctl_pkg *pkg) * If the switch at route is incorrectly configured then we will not receive a * reply (even though the switch will reset). The caller should check for * -ETIMEDOUT and attempt to reconfigure the switch. + * + * Return: &struct tb_cfg_result with non-zero @err field if error + * has occurred. */ struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route) { @@ -937,6 +949,9 @@ struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route) * @timeout_msec: Timeout in ms how long to wait for the response * * Reads from router config space without translating the possible error. + * + * Return: &struct tb_cfg_result with non-zero @err field if error + * has occurred. */ struct tb_cfg_result tb_cfg_read_raw(struct tb_ctl *ctl, void *buffer, u64 route, u32 port, enum tb_cfg_space space, @@ -1008,6 +1023,9 @@ struct tb_cfg_result tb_cfg_read_raw(struct tb_ctl *ctl, void *buffer, * @timeout_msec: Timeout in ms how long to wait for the response * * Writes to router config space without translating the possible error. + * + * Return: &struct tb_cfg_result with non-zero @err field if error + * has occurred. */ struct tb_cfg_result tb_cfg_write_raw(struct tb_ctl *ctl, const void *buffer, u64 route, u32 port, enum tb_cfg_space space, @@ -1150,8 +1168,7 @@ int tb_cfg_write(struct tb_ctl *ctl, const void *buffer, u64 route, u32 port, * Reads the first dword from the switches TB_CFG_SWITCH config area and * returns the port number from which the reply originated. * - * Return: Returns the upstream port number on success or an error code on - * failure. + * Return: Upstream port number on success or negative error code on failure. */ int tb_cfg_get_upstream_port(struct tb_ctl *ctl, u64 route) { From 12cb68e48691ffb6700ef0d8dceae7b4739b8dea Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:25 +0200 Subject: [PATCH 1561/2711] thunderbolt: Add missing documentation in ctl.h tb_cfg_request struct Add missing @request field description in tb_cfg_request struct kernel-doc. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/ctl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thunderbolt/ctl.h b/drivers/thunderbolt/ctl.h index 7e08ca8f0895..db1646eb4fd0 100644 --- a/drivers/thunderbolt/ctl.h +++ b/drivers/thunderbolt/ctl.h @@ -54,6 +54,7 @@ struct ctl_pkg { * @kref: Reference count * @ctl: Pointer to the control channel structure. Only set when the * request is queued. + * @request: Request is stored here * @request_size: Size of the request packet (in bytes) * @request_type: Type of the request packet * @response: Response is stored here From a84be45d332ae69b1ed1ef82143d98936b14201d Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:26 +0200 Subject: [PATCH 1562/2711] thunderbolt: Update dma_port.c function documentation Make dma_port.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/dma_port.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/thunderbolt/dma_port.c b/drivers/thunderbolt/dma_port.c index 9f20c7bbf0ce..dc8ea188a114 100644 --- a/drivers/thunderbolt/dma_port.c +++ b/drivers/thunderbolt/dma_port.c @@ -197,6 +197,8 @@ static int dma_find_port(struct tb_switch *sw) * * The DMA control port is functional also when the switch is in safe * mode. + * + * Return: &struct tb_dma_port on success, %NULL otherwise. */ struct tb_dma_port *dma_port_alloc(struct tb_switch *sw) { @@ -354,6 +356,8 @@ static int dma_port_flash_write_block(void *data, unsigned int dwaddress, * @address: Address relative to the start of active region * @buf: Buffer where the data is read * @size: Size of the buffer + * + * Return: %0 on success, negative errno otherwise. */ int dma_port_flash_read(struct tb_dma_port *dma, unsigned int address, void *buf, size_t size) @@ -372,6 +376,8 @@ int dma_port_flash_read(struct tb_dma_port *dma, unsigned int address, * Writes block of data to the non-active flash region of the switch. If * the address is given as %DMA_PORT_CSS_ADDRESS the block is written * using CSS command. + * + * Return: %0 on success, negative errno otherwise. */ int dma_port_flash_write(struct tb_dma_port *dma, unsigned int address, const void *buf, size_t size) @@ -393,6 +399,8 @@ int dma_port_flash_write(struct tb_dma_port *dma, unsigned int address, * dma_port_flash_update_auth_status() to get status of this command. * This is because if the switch in question is root switch the * thunderbolt host controller gets reset as well. + * + * Return: %0 on success, negative errno otherwise. */ int dma_port_flash_update_auth(struct tb_dma_port *dma) { @@ -410,12 +418,13 @@ int dma_port_flash_update_auth(struct tb_dma_port *dma) * @status: Status code of the operation * * The function checks if there is status available from the last update - * auth command. Returns %0 if there is no status and no further - * action is required. If there is status, %1 is returned instead and - * @status holds the failure code. + * auth command. * - * Negative return means there was an error reading status from the - * switch. + * Return: + * * %0 - If there is no status and no further action is required. + * * %1 - If there is some status. @status holds the failure code. + * * Negative errno - An error occurred when reading status from the + * switch. */ int dma_port_flash_update_auth_status(struct tb_dma_port *dma, u32 *status) { @@ -446,6 +455,8 @@ int dma_port_flash_update_auth_status(struct tb_dma_port *dma, u32 *status) * @dma: DMA control port * * Triggers power cycle to the switch. + * + * Return: %0 on success, negative errno otherwise. */ int dma_port_power_cycle(struct tb_dma_port *dma) { From 250afc7f396d456a3458cc9160cf44990474c644 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:27 +0200 Subject: [PATCH 1563/2711] thunderbolt: Update domain.c function documentation Make domain.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/domain.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c index 5272c255e046..83defc915d33 100644 --- a/drivers/thunderbolt/domain.c +++ b/drivers/thunderbolt/domain.c @@ -369,7 +369,7 @@ static bool tb_domain_event_cb(void *data, enum tb_cfg_pkg_type type, * Call tb_domain_put() to release the domain before it has been added * to the system. * - * Return: allocated domain structure on %NULL in case of error + * Return: Pointer to &struct tb or %NULL in case of error. */ struct tb *tb_domain_alloc(struct tb_nhi *nhi, int timeout_msec, size_t privsize) { @@ -431,7 +431,7 @@ err_free: * and release the domain after this function has been called, call * tb_domain_remove(). * - * Return: %0 in case of success and negative errno in case of error + * Return: %0 on success, negative errno otherwise. */ int tb_domain_add(struct tb *tb, bool reset) { @@ -519,6 +519,8 @@ void tb_domain_remove(struct tb *tb) * @tb: Domain to suspend * * Suspends all devices in the domain and stops the control channel. + * + * Return: %0 on success, negative errno otherwise. */ int tb_domain_suspend_noirq(struct tb *tb) { @@ -545,6 +547,8 @@ int tb_domain_suspend_noirq(struct tb *tb) * * Re-starts the control channel, and resumes all devices connected to * the domain. + * + * Return: %0 on success, negative errno otherwise. */ int tb_domain_resume_noirq(struct tb *tb) { @@ -644,6 +648,8 @@ int tb_domain_disapprove_switch(struct tb *tb, struct tb_switch *sw) * This will approve switch by connection manager specific means. In * case of success the connection manager will create PCIe tunnel from * parent to @sw. + * + * Return: %0 on success, negative errno otherwise. */ int tb_domain_approve_switch(struct tb *tb, struct tb_switch *sw) { @@ -742,7 +748,7 @@ int tb_domain_challenge_switch_key(struct tb *tb, struct tb_switch *sw) * This needs to be called in preparation for NVM upgrade of the host * controller. Makes sure all PCIe paths are disconnected. * - * Return %0 on success and negative errno in case of error. + * Return: %0 on success and negative errno in case of error. */ int tb_domain_disconnect_pcie_paths(struct tb *tb) { @@ -764,9 +770,11 @@ int tb_domain_disconnect_pcie_paths(struct tb *tb) * Calls connection manager specific method to enable DMA paths to the * XDomain in question. * - * Return: 0% in case of success and negative errno otherwise. In - * particular returns %-ENOTSUPP if the connection manager - * implementation does not support XDomains. + * Return: + * * %0 - On success. + * * %-ENOTSUPP - If the connection manager implementation does not support + * XDomains. + * * Negative errno - An error occurred. */ int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, int transmit_path, int transmit_ring, @@ -791,9 +799,11 @@ int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, * Calls connection manager specific method to disconnect DMA paths to * the XDomain in question. * - * Return: 0% in case of success and negative errno otherwise. In - * particular returns %-ENOTSUPP if the connection manager - * implementation does not support XDomains. + * Return: + * * %0 - On success. + * * %-ENOTSUPP - If the connection manager implementation does not support + * XDomains. + * * Negative errno - An error occurred. */ int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, int transmit_path, int transmit_ring, From 728ab0e4a0ca78f550ca59d9267e0b2835f523fa Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:28 +0200 Subject: [PATCH 1564/2711] thunderbolt: Update eeprom.c function documentation Make eeprom.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/eeprom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index e66183a72cf9..1af65fece495 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -298,6 +298,8 @@ struct tb_drom_entry_desc { * * Does not use the cached copy in sw->drom. Used during resume to check switch * identity. + * + * Return: %0 on success, negative errno otherwise. */ int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid) { @@ -709,7 +711,7 @@ static int tb_drom_device_read(struct tb_switch *sw) * populates the fields in @sw accordingly. Can be called for any router * generation. * - * Returns %0 in case of success and negative errno otherwise. + * Return: %0 on success, negative errno otherwise. */ int tb_drom_read(struct tb_switch *sw) { From 4815b7548cf669b402919d592583a1ad00de9305 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:29 +0200 Subject: [PATCH 1565/2711] thunderbolt: Update lc.c function documentation Make lc.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/lc.c | 58 +++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c index 63cb4b6afb71..0891d51ac2e9 100644 --- a/drivers/thunderbolt/lc.c +++ b/drivers/thunderbolt/lc.c @@ -14,6 +14,8 @@ * tb_lc_read_uuid() - Read switch UUID from link controller common register * @sw: Switch whose UUID is read * @uuid: UUID is placed here + * + * Return: %0 on success, negative errno otherwise. */ int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid) { @@ -52,9 +54,10 @@ static int find_port_lc_cap(struct tb_port *port) * @port: Port that is reset * * Triggers downstream port reset through link controller registers. - * Returns %0 in case of success negative errno otherwise. Only supports - * non-USB4 routers with link controller (that's Thunderbolt 2 and - * Thunderbolt 3). + * Only supports non-USB4 routers with link controller (that's + * Thunderbolt 2 and Thunderbolt 3). + * + * Return: %0 on success, negative errno otherwise. */ int tb_lc_reset_port(struct tb_port *port) { @@ -132,6 +135,8 @@ static int tb_lc_set_port_configured(struct tb_port *port, bool configured) * @port: Port that is set as configured * * Sets the port configured for power management purposes. + * + * Return: %0 on success, negative errno otherwise. */ int tb_lc_configure_port(struct tb_port *port) { @@ -143,6 +148,8 @@ int tb_lc_configure_port(struct tb_port *port) * @port: Port that is set as configured * * Sets the port unconfigured for power management purposes. + * + * Return: %0 on success, negative errno otherwise. */ void tb_lc_unconfigure_port(struct tb_port *port) { @@ -184,8 +191,10 @@ static int tb_lc_set_xdomain_configured(struct tb_port *port, bool configure) * tb_lc_configure_xdomain() - Inform LC that the link is XDomain * @port: Switch downstream port connected to another host * - * Sets the lane configured for XDomain accordingly so that the LC knows - * about this. Returns %0 in success and negative errno in failure. + * Sets the lane configured for XDomain accordingly so that LC knows + * about this. + * + * Return: %0 on success, negative errno otherwise. */ int tb_lc_configure_xdomain(struct tb_port *port) { @@ -211,7 +220,7 @@ void tb_lc_unconfigure_xdomain(struct tb_port *port) * sleep. Should be called for those downstream lane adapters that were * not connected (tb_lc_configure_port() was not called) before sleep. * - * Returns %0 in success and negative errno in case of failure. + * Return: %0 on success, negative errno otherwise. */ int tb_lc_start_lane_initialization(struct tb_port *port) { @@ -244,6 +253,8 @@ int tb_lc_start_lane_initialization(struct tb_port *port) * * TB_LC_LINK_ATTR_CPS bit reflects if the link supports CLx including * active cables (if connected on the link). + * + * Return: %true if CLx is supported, %false otherwise. */ bool tb_lc_is_clx_supported(struct tb_port *port) { @@ -266,7 +277,8 @@ bool tb_lc_is_clx_supported(struct tb_port *port) * tb_lc_is_usb_plugged() - Is there USB device connected to port * @port: Device router lane 0 adapter * - * Returns true if the @port has USB type-C device connected. + * Return: %true if the @port has USB Type-C device connected, %false + * otherwise. */ bool tb_lc_is_usb_plugged(struct tb_port *port) { @@ -292,7 +304,8 @@ bool tb_lc_is_usb_plugged(struct tb_port *port) * tb_lc_is_xhci_connected() - Is the internal xHCI connected * @port: Device router lane 0 adapter * - * Returns true if the internal xHCI has been connected to @port. + * Return: %true if the internal xHCI has been connected to + * @port, %false otherwise. */ bool tb_lc_is_xhci_connected(struct tb_port *port) { @@ -343,9 +356,10 @@ static int __tb_lc_xhci_connect(struct tb_port *port, bool connect) * tb_lc_xhci_connect() - Connect internal xHCI * @port: Device router lane 0 adapter * - * Tells LC to connect the internal xHCI to @port. Returns %0 on success - * and negative errno in case of failure. Can be called for Thunderbolt 3 - * routers only. + * Tells LC to connect the internal xHCI to @port. Can be called for + * Thunderbolt 3 routers only. + * + * Return: %0 on success, negative errno otherwise. */ int tb_lc_xhci_connect(struct tb_port *port) { @@ -408,6 +422,8 @@ static int tb_lc_set_wake_one(struct tb_switch *sw, unsigned int offset, * @flags: Wakeup flags (%0 to disable) * * For each LC sets wake bits accordingly. + * + * Return: %0 on success, negative errno otherwise. */ int tb_lc_set_wake(struct tb_switch *sw, unsigned int flags) { @@ -447,6 +463,8 @@ int tb_lc_set_wake(struct tb_switch *sw, unsigned int flags) * * Let the switch link controllers know that the switch is going to * sleep. + * + * Return: %0 on success, negative errno otherwise. */ int tb_lc_set_sleep(struct tb_switch *sw) { @@ -491,6 +509,8 @@ int tb_lc_set_sleep(struct tb_switch *sw) * * Checks whether conditions for lane bonding from parent to @sw are * possible. + * + * Return: %true if lane bonding is possible, %false otherwise. */ bool tb_lc_lane_bonding_possible(struct tb_switch *sw) { @@ -562,6 +582,8 @@ static int tb_lc_dp_sink_available(struct tb_switch *sw, int sink) * * Queries through LC SNK_ALLOCATION registers whether DP sink is available * for the given DP IN port or not. + * + * Return: %true if DP sink is available, %false otherwise. */ bool tb_lc_dp_sink_query(struct tb_switch *sw, struct tb_port *in) { @@ -586,10 +608,12 @@ bool tb_lc_dp_sink_query(struct tb_switch *sw, struct tb_port *in) * @sw: Switch whose DP sink is allocated * @in: DP IN port the DP sink is allocated for * - * Allocate DP sink for @in via LC SNK_ALLOCATION registers. If the - * resource is available and allocation is successful returns %0. In all - * other cases returs negative errno. In particular %-EBUSY is returned if - * the resource was not available. + * Allocate DP sink for @in via LC SNK_ALLOCATION registers. + * + * Return: + * * %0 - If the resource is available and allocation is successful. + * * %-EBUSY - If resource is not available. + * * Negative errno - Another error occurred. */ int tb_lc_dp_sink_alloc(struct tb_switch *sw, struct tb_port *in) { @@ -637,6 +661,8 @@ int tb_lc_dp_sink_alloc(struct tb_switch *sw, struct tb_port *in) * @in: DP IN port whose DP sink is de-allocated * * De-allocate DP sink from @in using LC SNK_ALLOCATION registers. + * + * Return: %0 on success, negative errno otherwise. */ int tb_lc_dp_sink_dealloc(struct tb_switch *sw, struct tb_port *in) { @@ -680,6 +706,8 @@ int tb_lc_dp_sink_dealloc(struct tb_switch *sw, struct tb_port *in) * * This is useful to let authentication cycle pass even without * a Thunderbolt link present. + * + * Return: %0 on success, negative errno otherwise. */ int tb_lc_force_power(struct tb_switch *sw) { From a38523805007a7498a4cbc56239ffb7709826179 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:30 +0200 Subject: [PATCH 1566/2711] thunderbolt: Update nhi.c function documentation Make nhi.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/nhi.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index 8a38b05d25c5..5f63f9b9cf40 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -344,8 +344,10 @@ EXPORT_SYMBOL_GPL(__tb_ring_enqueue); * * This function can be called when @start_poll callback of the @ring * has been called. It will read one completed frame from the ring and - * return it to the caller. Returns %NULL if there is no more completed - * frames. + * return it to the caller. + * + * Return: Pointer to &struct ring_frame, %NULL if there is no more + * completed frames. */ struct ring_frame *tb_ring_poll(struct tb_ring *ring) { @@ -640,6 +642,8 @@ err_free_ring: * @hop: HopID (ring) to allocate * @size: Number of entries in the ring * @flags: Flags for the ring + * + * Return: Pointer to &struct tb_ring, %NULL otherwise. */ struct tb_ring *tb_ring_alloc_tx(struct tb_nhi *nhi, int hop, int size, unsigned int flags) @@ -661,6 +665,8 @@ EXPORT_SYMBOL_GPL(tb_ring_alloc_tx); * interrupt is triggered and masked, instead of callback * in each Rx frame. * @poll_data: Optional data passed to @start_poll + * + * Return: Pointer to &struct tb_ring, %NULL otherwise. */ struct tb_ring *tb_ring_alloc_rx(struct tb_nhi *nhi, int hop, int size, unsigned int flags, int e2e_tx_hop, @@ -854,8 +860,9 @@ EXPORT_SYMBOL_GPL(tb_ring_free); * @cmd: Command to send * @data: Data to be send with the command * - * Sends mailbox command to the firmware running on NHI. Returns %0 in - * case of success and negative errno in case of failure. + * Sends mailbox command to the firmware running on NHI. + * + * Return: %0 on success, negative errno otherwise. */ int nhi_mailbox_cmd(struct tb_nhi *nhi, enum nhi_mailbox_cmd cmd, u32 data) { @@ -891,6 +898,8 @@ int nhi_mailbox_cmd(struct tb_nhi *nhi, enum nhi_mailbox_cmd cmd, u32 data) * * The function reads current firmware operation mode using NHI mailbox * registers and returns it to the caller. + * + * Return: &enum nhi_fw_mode. */ enum nhi_fw_mode nhi_mailbox_mode(struct tb_nhi *nhi) { From bbbca9bfd1720d5eaeede878d63a171e34ea4b9b Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:31 +0200 Subject: [PATCH 1567/2711] thunderbolt: Add missing documentation in nhi_regs.h ring_desc structure Add missing description of fields in ring_desc struct found in "nhi_regs.h". No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/nhi_regs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/thunderbolt/nhi_regs.h b/drivers/thunderbolt/nhi_regs.h index 297a3e440648..cf5222bee971 100644 --- a/drivers/thunderbolt/nhi_regs.h +++ b/drivers/thunderbolt/nhi_regs.h @@ -21,6 +21,12 @@ enum ring_flags { /** * struct ring_desc - TX/RX ring entry + * @phys: DMA mapped address of the frame + * @length: Size of the ring + * @eof: End of frame protocol defined field + * @sof: Start of frame protocol defined field + * @flags: Ring descriptor flags + * @time: Fill with zero * * For TX set length/eof/sof. * For RX length/eof/sof are set by the NHI. From fe83a27383ca0a95022f5b5807e8516d4d7554fe Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:32 +0200 Subject: [PATCH 1568/2711] thunderbolt: Update nvm.c function documentation Make nvm.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/nvm.c | 42 ++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/thunderbolt/nvm.c b/drivers/thunderbolt/nvm.c index da11c8112e29..6901058b7ac0 100644 --- a/drivers/thunderbolt/nvm.c +++ b/drivers/thunderbolt/nvm.c @@ -278,9 +278,13 @@ static const struct tb_nvm_vendor retimer_nvm_vendors[] = { * tb_nvm_alloc() - Allocate new NVM structure * @dev: Device owning the NVM * - * Allocates new NVM structure with unique @id and returns it. In case - * of error returns ERR_PTR(). Specifically returns %-EOPNOTSUPP if the - * NVM format of the @dev is not known by the kernel. + * Allocates new NVM structure with unique @id and returns it. + * + * Return: + * * Pointer to &struct tb_nvm - On success. + * * %-EOPNOTSUPP - If the NVM format of the @dev is not known by the + * kernel. + * * %ERR_PTR - In case of failure. */ struct tb_nvm *tb_nvm_alloc(struct device *dev) { @@ -347,9 +351,10 @@ struct tb_nvm *tb_nvm_alloc(struct device *dev) * tb_nvm_read_version() - Read and populate NVM version * @nvm: NVM structure * - * Uses vendor specific means to read out and fill in the existing - * active NVM version. Returns %0 in case of success and negative errno - * otherwise. + * Uses vendor specific means to read and fill out the existing + * active NVM version. + * + * Return: %0 on success, negative errno otherwise. */ int tb_nvm_read_version(struct tb_nvm *nvm) { @@ -365,12 +370,11 @@ int tb_nvm_read_version(struct tb_nvm *nvm) * tb_nvm_validate() - Validate new NVM image * @nvm: NVM structure * - * Runs vendor specific validation over the new NVM image and if all - * checks pass returns %0. As side effect updates @nvm->buf_data_start - * and @nvm->buf_data_size fields to match the actual data to be written - * to the NVM. + * Runs vendor specific validation over the new NVM image. As a + * side effect, updates @nvm->buf_data_start and @nvm->buf_data_size + * fields to match the actual data to be written to the NVM. * - * If the validation does not pass then returns negative errno. + * Return: %0 on successful validation, negative errno otherwise. */ int tb_nvm_validate(struct tb_nvm *nvm) { @@ -405,7 +409,7 @@ int tb_nvm_validate(struct tb_nvm *nvm) * the image, this function does that. Can be called even if the device * does not need this. * - * Returns %0 in case of success and negative errno otherwise. + * Return: %0 on success, negative errno otherwise. */ int tb_nvm_write_headers(struct tb_nvm *nvm) { @@ -423,7 +427,8 @@ int tb_nvm_write_headers(struct tb_nvm *nvm) * Registers new active NVmem device for @nvm. The @reg_read is called * directly from NVMem so it must handle possible concurrent access if * needed. The first parameter passed to @reg_read is @nvm structure. - * Returns %0 in success and negative errno otherwise. + * + * Return: %0 on success, negative errno otherwise. */ int tb_nvm_add_active(struct tb_nvm *nvm, nvmem_reg_read_t reg_read) { @@ -461,6 +466,11 @@ int tb_nvm_add_active(struct tb_nvm *nvm, nvmem_reg_read_t reg_read) * Helper function to cache the new NVM image before it is actually * written to the flash. Copies @bytes from @val to @nvm->buf starting * from @offset. + * + * Return: + * * %0 - On success. + * * %-ENOMEM - If buffer allocation failed. + * * Negative errno - Another error occurred. */ int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val, size_t bytes) @@ -488,7 +498,7 @@ int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val, * needed. The first parameter passed to @reg_write is @nvm structure. * The size of the NVMem device is set to %NVM_MAX_SIZE. * - * Returns %0 in success and negative errno otherwise. + * Return: %0 on success, negative errno otherwise. */ int tb_nvm_add_non_active(struct tb_nvm *nvm, nvmem_reg_write_t reg_write) { @@ -545,7 +555,7 @@ void tb_nvm_free(struct tb_nvm *nvm) * This is a generic function that reads data from NVM or NVM like * device. * - * Returns %0 on success and negative errno otherwise. + * Return: %0 on success, negative errno otherwise. */ int tb_nvm_read_data(unsigned int address, void *buf, size_t size, unsigned int retries, read_block_fn read_block, @@ -592,7 +602,7 @@ int tb_nvm_read_data(unsigned int address, void *buf, size_t size, * * This is generic function that writes data to NVM or NVM like device. * - * Returns %0 on success and negative errno otherwise. + * Return: %0 on success, negative errno otherwise. */ int tb_nvm_write_data(unsigned int address, const void *buf, size_t size, unsigned int retries, write_block_fn write_block, From a6e3f939ada8c4502bb9264adce106f5f2c9d51d Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:33 +0200 Subject: [PATCH 1569/2711] thunderbolt: Update path.c function documentation Make path.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/path.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c index e1a5f6e3d0b6..f9b11dadfbdd 100644 --- a/drivers/thunderbolt/path.c +++ b/drivers/thunderbolt/path.c @@ -96,7 +96,7 @@ static int tb_path_find_src_hopid(struct tb_port *src, * that the @dst port is the expected one. If it is not, the path can be * cleaned up by calling tb_path_deactivate() before tb_path_free(). * - * Return: Discovered path on success, %NULL in case of failure + * Return: Pointer to &struct tb_path, %NULL in case of failure. */ struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid, struct tb_port *dst, int dst_hopid, @@ -233,7 +233,7 @@ err: * links on the path, prioritizes using @link_nr but takes into account * that the lanes may be bonded. * - * Return: Returns a tb_path on success or NULL on failure. + * Return: Pointer to &struct tb_path, %NULL in case of failure. */ struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid, struct tb_port *dst, int dst_hopid, int link_nr, @@ -452,7 +452,9 @@ static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index, * @hop_index: HopID of the path to be cleared * * This deactivates or clears a single path config space entry at - * @hop_index. Returns %0 in success and negative errno otherwise. + * @hop_index. + * + * Return: %0 on success, negative errno otherwise. */ int tb_path_deactivate_hop(struct tb_port *port, int hop_index) { @@ -498,7 +500,7 @@ void tb_path_deactivate(struct tb_path *path) * Activate a path starting with the last hop and iterating backwards. The * caller must fill path->hops before calling tb_path_activate(). * - * Return: Returns 0 on success or an error code on failure. + * Return: %0 on success, negative errno otherwise. */ int tb_path_activate(struct tb_path *path) { @@ -592,7 +594,7 @@ err: * tb_path_is_invalid() - check whether any ports on the path are invalid * @path: Path to check * - * Return: Returns true if the path is invalid, false otherwise. + * Return: %true if the path is invalid, %false otherwise. */ bool tb_path_is_invalid(struct tb_path *path) { @@ -613,6 +615,8 @@ bool tb_path_is_invalid(struct tb_path *path) * * Goes over all hops on path and checks if @port is any of them. * Direction does not matter. + * + * Return: %true if port is on the path, %false otherwise. */ bool tb_path_port_on_path(const struct tb_path *path, const struct tb_port *port) { From d015642ad36d78e6eba12d8ab96cea6fd4602b49 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:34 +0200 Subject: [PATCH 1570/2711] thunderbolt: Update property.c function documentation Make property.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/property.c | 38 +++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/thunderbolt/property.c b/drivers/thunderbolt/property.c index dc555cda98e6..31aa0516932a 100644 --- a/drivers/thunderbolt/property.c +++ b/drivers/thunderbolt/property.c @@ -211,11 +211,13 @@ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block, * * This function parses the XDomain properties data block into format that * can be traversed using the helper functions provided by this module. - * Upon success returns the parsed directory. In case of error returns - * %NULL. The resulting &struct tb_property_dir needs to be released by + * + * The resulting &struct tb_property_dir needs to be released by * calling tb_property_free_dir() when not needed anymore. * * The @block is expected to be root directory. + * + * Return: Pointer to &struct tb_property_dir, %NULL in case of failure. */ struct tb_property_dir *tb_property_parse_dir(const u32 *block, size_t block_len) @@ -238,6 +240,8 @@ struct tb_property_dir *tb_property_parse_dir(const u32 *block, * * Creates new, empty property directory. If @uuid is %NULL then the * directory is assumed to be root directory. + * + * Return: Pointer to &struct tb_property_dir, %NULL in case of failure. */ struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid) { @@ -481,9 +485,11 @@ static ssize_t __tb_property_format_dir(const struct tb_property_dir *dir, * @block_len: Length of the property block * * This function formats the directory to the packed format that can be - * then send over the thunderbolt fabric to receiving host. Returns %0 in - * case of success and negative errno on faulure. Passing %NULL in @block - * returns number of entries the block takes. + * then sent over the thunderbolt fabric to receiving host. + * + * Passing %NULL in @block returns number of entries the block takes. + * + * Return: %0 on success, negative errno otherwise. */ ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block, size_t block_len) @@ -505,9 +511,9 @@ ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block, * tb_property_copy_dir() - Take a deep copy of directory * @dir: Directory to copy * - * This function takes a deep copy of @dir and returns back the copy. In - * case of error returns %NULL. The resulting directory needs to be - * released by calling tb_property_free_dir(). + * The resulting directory needs to be released by calling tb_property_free_dir(). + * + * Return: Pointer to &struct tb_property_dir, %NULL in case of failure. */ struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir) { @@ -577,6 +583,8 @@ err_free: * @parent: Directory to add the property * @key: Key for the property * @value: Immediate value to store with the property + * + * Return: %0 on success, negative errno otherwise. */ int tb_property_add_immediate(struct tb_property_dir *parent, const char *key, u32 value) @@ -606,6 +614,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_immediate); * @buflen: Number of bytes in the data buffer * * Function takes a copy of @buf and adds it to the directory. + * + * Return: %0 on success, negative errno otherwise. */ int tb_property_add_data(struct tb_property_dir *parent, const char *key, const void *buf, size_t buflen) @@ -642,6 +652,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_data); * @text: String to add * * Function takes a copy of @text and adds it to the directory. + * + * Return: %0 on success, negative errno otherwise. */ int tb_property_add_text(struct tb_property_dir *parent, const char *key, const char *text) @@ -676,6 +688,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_text); * @parent: Directory to add the property * @key: Key for the property * @dir: Directory to add + * + * Return: %0 on success, negative errno otherwise. */ int tb_property_add_dir(struct tb_property_dir *parent, const char *key, struct tb_property_dir *dir) @@ -716,8 +730,10 @@ EXPORT_SYMBOL_GPL(tb_property_remove); * @key: Key to look for * @type: Type of the property * - * Finds and returns property from the given directory. Does not recurse - * into sub-directories. Returns %NULL if the property was not found. + * Finds and returns property from the given directory. Does not + * recurse into sub-directories. + * + * Return: Pointer to &struct tb_property, %NULL if the property was not found. */ struct tb_property *tb_property_find(struct tb_property_dir *dir, const char *key, enum tb_property_type type) @@ -737,6 +753,8 @@ EXPORT_SYMBOL_GPL(tb_property_find); * tb_property_get_next() - Get next property from directory * @dir: Directory holding properties * @prev: Previous property in the directory (%NULL returns the first) + * + * Return: Pointer to &struct tb_property, %NULL if property was not found. */ struct tb_property *tb_property_get_next(struct tb_property_dir *dir, struct tb_property *prev) From f72f4d5cdb1ddbc323df6c3f638dd2499c038bef Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:35 +0200 Subject: [PATCH 1571/2711] thunderbolt: Update retimer.c function documentation Make retimer.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/retimer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c index 361fece3d818..3a0f486a24d5 100644 --- a/drivers/thunderbolt/retimer.c +++ b/drivers/thunderbolt/retimer.c @@ -27,8 +27,9 @@ * @buf: Data read from NVM is stored here * @size: Number of bytes to read * - * Reads retimer NVM and copies the contents to @buf. Returns %0 if the - * read was successful and negative errno in case of failure. + * Reads retimer NVM and copies the contents to @buf. + * + * Return: %0 if the read was successful, negative errno in case of failure. */ int tb_retimer_nvm_read(struct tb_retimer *rt, unsigned int address, void *buf, size_t size) @@ -503,6 +504,8 @@ static struct tb_retimer *tb_port_find_retimer(struct tb_port *port, u8 index) * Then Tries to enumerate on-board retimers connected to @port. Found * retimers are registered as children of @port if @add is set. Does * not scan for cable retimers for now. + * + * Return: %0 on success, negative errno otherwise. */ int tb_retimer_scan(struct tb_port *port, bool add) { From 207b8a260578b3240f1501feb75376e4b00706b1 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:36 +0200 Subject: [PATCH 1572/2711] thunderbolt: Update switch.c function documentation Make switch.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/switch.c | 140 +++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 38 deletions(-) diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index e9f4186f20f4..0e07904aa73b 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -290,8 +290,9 @@ static int nvm_authenticate(struct tb_switch *sw, bool auth_only) * @size: Size of the buffer in bytes * * Reads from router NVM and returns the requested data in @buf. Locking - * is up to the caller. Returns %0 in success and negative errno in case - * of failure. + * is up to the caller. + * + * Return: %0 on success, negative errno otherwise. */ int tb_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf, size_t size) @@ -464,7 +465,7 @@ static void tb_dump_port(struct tb *tb, const struct tb_port *port) * * The port must have a TB_CAP_PHY (i.e. it should be a real port). * - * Return: Returns an enum tb_port_state on success or an error code on failure. + * Return: &enum tb_port_state or negative error code on failure. */ int tb_port_state(struct tb_port *port) { @@ -491,9 +492,11 @@ int tb_port_state(struct tb_port *port) * switch resume). Otherwise we only wait if a device is registered but the link * has not yet been established. * - * Return: Returns an error code on failure. Returns 0 if the port is not - * connected or failed to reach state TB_PORT_UP within one second. Returns 1 - * if the port is connected and in state TB_PORT_UP. + * Return: + * * %0 - If the port is not connected or failed to reach + * state %TB_PORT_UP within one second. + * * %1 - If the port is connected and in state %TB_PORT_UP. + * * Negative errno - An error occurred. */ int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged) { @@ -562,7 +565,7 @@ int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged) * Change the number of NFC credits allocated to @port by @credits. To remove * NFC credits pass a negative amount of credits. * - * Return: Returns 0 on success or an error code on failure. + * Return: %0 on success, negative errno otherwise. */ int tb_port_add_nfc_credits(struct tb_port *port, int credits) { @@ -599,7 +602,7 @@ int tb_port_add_nfc_credits(struct tb_port *port, int credits) * @port: Port whose counters to clear * @counter: Counter index to clear * - * Return: Returns 0 on success or an error code on failure. + * Return: %0 on success, negative errno otherwise. */ int tb_port_clear_counter(struct tb_port *port, int counter) { @@ -614,6 +617,8 @@ int tb_port_clear_counter(struct tb_port *port, int counter) * * Needed for USB4 but can be called for any CIO/USB4 ports. Makes the * downstream router accessible for CM. + * + * Return: %0 on success, negative errno otherwise. */ int tb_port_unlock(struct tb_port *port) { @@ -659,6 +664,8 @@ static int __tb_port_enable(struct tb_port *port, bool enable) * @port: Port to enable (can be %NULL) * * This is used for lane 0 and 1 adapters to enable it. + * + * Return: %0 on success, negative errno otherwise. */ int tb_port_enable(struct tb_port *port) { @@ -670,6 +677,8 @@ int tb_port_enable(struct tb_port *port) * @port: Port to disable (can be %NULL) * * This is used for lane 0 and 1 adapters to disable it. + * + * Return: %0 on success, negative errno otherwise. */ int tb_port_disable(struct tb_port *port) { @@ -689,7 +698,7 @@ static int tb_port_reset(struct tb_port *port) * This is a helper method for tb_switch_alloc. Does not check or initialize * any downstream switches. * - * Return: Returns 0 on success or an error code on failure. + * Return: %0 on success, negative errno otherwise. */ static int tb_init_port(struct tb_port *port) { @@ -847,9 +856,9 @@ static inline bool tb_switch_is_reachable(const struct tb_switch *parent, * link port, the function follows that link and returns another end on * that same link. * - * If the @end port has been reached, return %NULL. - * * Domain tb->lock must be held when this function is called. + * + * Return: Pointer to &struct tb_port, %NULL if the @end port has been reached. */ struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end, struct tb_port *prev) @@ -894,7 +903,7 @@ struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end, * tb_port_get_link_speed() - Get current link speed * @port: Port to check (USB4 or CIO) * - * Returns link speed in Gb/s or negative errno in case of failure. + * Return: Link speed in Gb/s or negative errno in case of failure. */ int tb_port_get_link_speed(struct tb_port *port) { @@ -926,9 +935,11 @@ int tb_port_get_link_speed(struct tb_port *port) * tb_port_get_link_generation() - Returns link generation * @port: Lane adapter * - * Returns link generation as number or negative errno in case of - * failure. Does not distinguish between Thunderbolt 1 and Thunderbolt 2 - * links so for those always returns 2. + * Return: Link generation as a number or negative errno in case of + * failure. + * + * Does not distinguish between Thunderbolt 1 and Thunderbolt 2 + * links so for those always returns %2. */ int tb_port_get_link_generation(struct tb_port *port) { @@ -952,8 +963,8 @@ int tb_port_get_link_generation(struct tb_port *port) * tb_port_get_link_width() - Get current link width * @port: Port to check (USB4 or CIO) * - * Returns link width. Return the link width as encoded in &enum - * tb_link_width or negative errno in case of failure. + * Return: Link width encoded in &enum tb_link_width or + * negative errno in case of failure. */ int tb_port_get_link_width(struct tb_port *port) { @@ -979,7 +990,9 @@ int tb_port_get_link_width(struct tb_port *port) * @width: Widths to check (bitmask) * * Can be called to any lane adapter. Checks if given @width is - * supported by the hardware and returns %true if it is. + * supported by the hardware. + * + * Return: %true if link width is supported, %false otherwise. */ bool tb_port_width_supported(struct tb_port *port, unsigned int width) { @@ -1016,7 +1029,7 @@ bool tb_port_width_supported(struct tb_port *port, unsigned int width) * Sets the target link width of the lane adapter to @width. Does not * enable/disable lane bonding. For that call tb_port_set_lane_bonding(). * - * Return: %0 in case of success and negative errno in case of error + * Return: %0 on success, negative errno otherwise. */ int tb_port_set_link_width(struct tb_port *port, enum tb_link_width width) { @@ -1070,7 +1083,7 @@ int tb_port_set_link_width(struct tb_port *port, enum tb_link_width width) * cases one should use tb_port_lane_bonding_enable() instead to enable * lane bonding. * - * Return: %0 in case of success and negative errno in case of error + * Return: %0 on success, negative errno otherwise. */ static int tb_port_set_lane_bonding(struct tb_port *port, bool bonding) { @@ -1104,7 +1117,7 @@ static int tb_port_set_lane_bonding(struct tb_port *port, bool bonding) * tb_port_wait_for_link_width() before enabling any paths through the * link to make sure the link is in expected state. * - * Return: %0 in case of success and negative errno in case of error + * Return: %0 on success, negative errno otherwise. */ int tb_port_lane_bonding_enable(struct tb_port *port) { @@ -1181,9 +1194,14 @@ void tb_port_lane_bonding_disable(struct tb_port *port) * * Should be used after both ends of the link have been bonded (or * bonding has been disabled) to wait until the link actually reaches - * the expected state. Returns %-ETIMEDOUT if the width was not reached - * within the given timeout, %0 if it did. Can be passed a mask of - * expected widths and succeeds if any of the widths is reached. + * the expected state. + * + * Can be passed a mask of expected widths. + * + * Return: + * * %0 - If link reaches any of the specified widths. + * * %-ETIMEDOUT - If link does not reach specified width. + * * Negative errno - Another error occurred. */ int tb_port_wait_for_link_width(struct tb_port *port, unsigned int width, int timeout_msec) @@ -1248,6 +1266,8 @@ static int tb_port_do_update_credits(struct tb_port *port) * After the link is bonded (or bonding was disabled) the port total * credits may change, so this function needs to be called to re-read * the credits. Updates also the second lane adapter. + * + * Return: %0 on success, negative errno otherwise. */ int tb_port_update_credits(struct tb_port *port) { @@ -1303,6 +1323,8 @@ static bool tb_port_resume(struct tb_port *port) /** * tb_port_is_enabled() - Is the adapter port enabled * @port: Port to check + * + * Return: %true if port is enabled, %false otherwise. */ bool tb_port_is_enabled(struct tb_port *port) { @@ -1327,6 +1349,8 @@ bool tb_port_is_enabled(struct tb_port *port) /** * tb_usb3_port_is_enabled() - Is the USB3 adapter port enabled * @port: USB3 adapter port to check + * + * Return: %true if port is enabled, %false otherwise. */ bool tb_usb3_port_is_enabled(struct tb_port *port) { @@ -1343,6 +1367,8 @@ bool tb_usb3_port_is_enabled(struct tb_port *port) * tb_usb3_port_enable() - Enable USB3 adapter port * @port: USB3 adapter port to enable * @enable: Enable/disable the USB3 adapter + * + * Return: %0 on success, negative errno otherwise. */ int tb_usb3_port_enable(struct tb_port *port, bool enable) { @@ -1358,6 +1384,8 @@ int tb_usb3_port_enable(struct tb_port *port, bool enable) /** * tb_pci_port_is_enabled() - Is the PCIe adapter port enabled * @port: PCIe port to check + * + * Return: %true if port is enabled, %false otherwise. */ bool tb_pci_port_is_enabled(struct tb_port *port) { @@ -1374,6 +1402,8 @@ bool tb_pci_port_is_enabled(struct tb_port *port) * tb_pci_port_enable() - Enable PCIe adapter port * @port: PCIe port to enable * @enable: Enable/disable the PCIe adapter + * + * Return: %0 on success, negative errno otherwise. */ int tb_pci_port_enable(struct tb_port *port, bool enable) { @@ -1389,6 +1419,8 @@ int tb_pci_port_enable(struct tb_port *port, bool enable) * @port: DP out port to check * * Checks if the DP OUT adapter port has HPD bit already set. + * + * Return: %1 if HPD is active, %0 otherwise. */ int tb_dp_port_hpd_is_active(struct tb_port *port) { @@ -1408,6 +1440,8 @@ int tb_dp_port_hpd_is_active(struct tb_port *port) * @port: Port to clear HPD * * If the DP IN port has HPD set, this function can be used to clear it. + * + * Return: %0 on success, negative errno otherwise. */ int tb_dp_port_hpd_clear(struct tb_port *port) { @@ -1434,6 +1468,8 @@ int tb_dp_port_hpd_clear(struct tb_port *port) * Programs specified Hop IDs for DP IN/OUT port. Can be called for USB4 * router DP adapters too but does not program the values as the fields * are read-only. + * + * Return: %0 on success, negative errno otherwise. */ int tb_dp_port_set_hops(struct tb_port *port, unsigned int video, unsigned int aux_tx, unsigned int aux_rx) @@ -1466,6 +1502,8 @@ int tb_dp_port_set_hops(struct tb_port *port, unsigned int video, /** * tb_dp_port_is_enabled() - Is DP adapter port enabled * @port: DP adapter port to check + * + * Return: %true if DP port is enabled, %false otherwise. */ bool tb_dp_port_is_enabled(struct tb_port *port) { @@ -1485,6 +1523,8 @@ bool tb_dp_port_is_enabled(struct tb_port *port) * * Once Hop IDs are programmed DP paths can be enabled or disabled by * calling this function. + * + * Return: %0 on success, negative errno otherwise. */ int tb_dp_port_enable(struct tb_port *port, bool enable) { @@ -1634,7 +1674,7 @@ static bool tb_switch_enumerated(struct tb_switch *sw) * * If the router is not enumerated does nothing. * - * Returns %0 on success or negative errno in case of failure. + * Return: %0 on success, negative errno otherwise. */ int tb_switch_reset(struct tb_switch *sw) { @@ -1670,8 +1710,12 @@ int tb_switch_reset(struct tb_switch *sw) * @timeout_msec: Timeout in ms how long to wait * * Wait till the specified bits in specified offset reach specified value. - * Returns %0 in case of success, %-ETIMEDOUT if the @value was not reached - * within the given timeout or a negative errno in case of failure. + * + * Return: + * * %0 - On success. + * * %-ETIMEDOUT - If the @value was not reached within + * the given timeout. + * * Negative errno - In case of failure. */ int tb_switch_wait_for_bit(struct tb_switch *sw, u32 offset, u32 bit, u32 value, int timeout_msec) @@ -1700,7 +1744,7 @@ int tb_switch_wait_for_bit(struct tb_switch *sw, u32 offset, u32 bit, * * Also configures a sane plug_events_delay of 255ms. * - * Return: Returns 0 on success or an error code on failure. + * Return: %0 on success, negative errno otherwise. */ static int tb_plug_events_active(struct tb_switch *sw, bool active) { @@ -2406,8 +2450,7 @@ static bool tb_switch_exceeds_max_depth(const struct tb_switch *sw, int depth) * separately. The returned switch should be released by calling * tb_switch_put(). * - * Return: Pointer to the allocated switch or ERR_PTR() in case of - * failure. + * Return: Pointer to &struct tb_switch or ERR_PTR() in case of failure. */ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent, u64 route) @@ -2526,7 +2569,7 @@ err_free_sw_ports: * * The returned switch must be released by calling tb_switch_put(). * - * Return: Pointer to the allocated switch or ERR_PTR() in case of failure + * Return: Pointer to &struct tb_switch or ERR_PTR() in case of failure. */ struct tb_switch * tb_switch_alloc_safe_mode(struct tb *tb, struct device *parent, u64 route) @@ -2562,7 +2605,7 @@ tb_switch_alloc_safe_mode(struct tb *tb, struct device *parent, u64 route) * connection manager to use. Can be called to the switch again after * resume from low power states to re-initialize it. * - * Return: %0 in case of success and negative errno in case of failure + * Return: %0 on success, negative errno otherwise. */ int tb_switch_configure(struct tb_switch *sw) { @@ -2625,7 +2668,7 @@ int tb_switch_configure(struct tb_switch *sw) * Needs to be called before any tunnels can be setup through the * router. Can be called to any router. * - * Returns %0 in success and negative errno otherwise. + * Return: %0 on success, negative errno otherwise. */ int tb_switch_configuration_valid(struct tb_switch *sw) { @@ -2900,6 +2943,8 @@ static void tb_switch_link_init(struct tb_switch *sw) * Connection manager can call this function to enable lane bonding of a * switch. If conditions are correct and both switches support the feature, * lanes are bonded. It is safe to call this to any switch. + * + * Return: %0 on success, negative errno otherwise. */ static int tb_switch_lane_bonding_enable(struct tb_switch *sw) { @@ -2950,6 +2995,8 @@ static int tb_switch_lane_bonding_enable(struct tb_switch *sw) * * Disables lane bonding between @sw and parent. This can be called even * if lanes were not bonded originally. + * + * Return: %0 on success, negative errno otherwise. */ static int tb_switch_lane_bonding_disable(struct tb_switch *sw) { @@ -3074,7 +3121,7 @@ static int tb_switch_asym_disable(struct tb_switch *sw) * * Does nothing for host router. * - * Returns %0 in case of success, negative errno otherwise. + * Return: %0 on success, negative errno otherwise. */ int tb_switch_set_link_width(struct tb_switch *sw, enum tb_link_width width) { @@ -3145,7 +3192,7 @@ int tb_switch_set_link_width(struct tb_switch *sw, enum tb_link_width width) * * It is recommended that this is called after lane bonding is enabled. * - * Returns %0 on success and negative errno in case of error. + * Return: %0 on success and negative errno otherwise. */ int tb_switch_configure_link(struct tb_switch *sw) { @@ -3245,7 +3292,7 @@ static int tb_switch_port_hotplug_enable(struct tb_switch *sw) * exposed to the userspace when this function successfully returns. To * remove and release the switch, call tb_switch_remove(). * - * Return: %0 in case of success and negative errno in case of failure + * Return: %0 on success, negative errno otherwise. */ int tb_switch_add(struct tb_switch *sw) { @@ -3467,6 +3514,8 @@ static void tb_switch_check_wakes(struct tb_switch *sw) * suspend. If this is resume from system sleep, notifies PM core about the * wakes occurred during suspend. Disables all wakes, except USB4 wake of * upstream port for USB4 routers that shall be always enabled. + * + * Return: %0 on success, negative errno otherwise. */ int tb_switch_resume(struct tb_switch *sw, bool runtime) { @@ -3617,7 +3666,9 @@ void tb_switch_suspend(struct tb_switch *sw, bool runtime) * @in: DP IN port * * Queries availability of DP resource for DP tunneling using switch - * specific means. Returns %true if resource is available. + * specific means. + * + * Return: %true if resource is available, %false otherwise. */ bool tb_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in) { @@ -3633,7 +3684,8 @@ bool tb_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in) * * Allocates DP resource for DP tunneling. The resource must be * available for this to succeed (see tb_switch_query_dp_resource()). - * Returns %0 in success and negative errno otherwise. + * + * Return: %0 on success, negative errno otherwise. */ int tb_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in) { @@ -3718,6 +3770,8 @@ static int tb_switch_match(struct device *dev, const void *data) * * Returned switch has reference count increased so the caller needs to * call tb_switch_put() when done with the switch. + * + * Return: Pointer to &struct tb_switch, %NULL if not found. */ struct tb_switch *tb_switch_find_by_link_depth(struct tb *tb, u8 link, u8 depth) { @@ -3743,6 +3797,8 @@ struct tb_switch *tb_switch_find_by_link_depth(struct tb *tb, u8 link, u8 depth) * * Returned switch has reference count increased so the caller needs to * call tb_switch_put() when done with the switch. + * + * Return: Pointer to &struct tb_switch, %NULL if not found. */ struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_t *uuid) { @@ -3767,6 +3823,8 @@ struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_t *uuid) * * Returned switch has reference count increased so the caller needs to * call tb_switch_put() when done with the switch. + * + * Return: Pointer to &struct tb_switch, %NULL if not found. */ struct tb_switch *tb_switch_find_by_route(struct tb *tb, u64 route) { @@ -3791,6 +3849,8 @@ struct tb_switch *tb_switch_find_by_route(struct tb *tb, u64 route) * tb_switch_find_port() - return the first port of @type on @sw or NULL * @sw: Switch to find the port from * @type: Port type to look for + * + * Return: Pointer to &struct tb_port, %NULL if not found. */ struct tb_port *tb_switch_find_port(struct tb_switch *sw, enum tb_port_type type) @@ -3859,6 +3919,8 @@ static int tb_switch_pcie_bridge_write(struct tb_switch *sw, unsigned int bridge * entry to PCIe L1 state. Shall be called after the upstream PCIe tunnel * was configured. Due to Intel platforms limitation, shall be called only * for first hop switch. + * + * Return: %0 on success, negative errno otherwise. */ int tb_switch_pcie_l1_enable(struct tb_switch *sw) { @@ -3893,6 +3955,8 @@ int tb_switch_pcie_l1_enable(struct tb_switch *sw) * connected to the type-C port. Call only after PCIe tunnel has been * established. The function only does the connect if not done already * so can be called several times for the same router. + * + * Return: %0 on success, negative errno otherwise. */ int tb_switch_xhci_connect(struct tb_switch *sw) { From d05cc39d1d2b9df8cd86ca24c21f36408a5c72a7 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:37 +0200 Subject: [PATCH 1573/2711] thunderbolt: Update tb.c function documentation Make tb.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tb.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 83a33fc1486a..4a94cb406bdf 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -225,14 +225,12 @@ static int tb_enable_clx(struct tb_switch *sw) return ret == -EOPNOTSUPP ? 0 : ret; } -/** - * tb_disable_clx() - Disable CL states up to host router - * @sw: Router to start +/* + * Disables CL states from @sw up to the host router. * - * Disables CL states from @sw up to the host router. Returns true if - * any CL state were disabled. This can be used to figure out whether - * the link was setup by us or the boot firmware so we don't - * accidentally enable them if they were not enabled during discovery. + * This can be used to figure out whether the link was setup by us or the + * boot firmware so we don't accidentally enable them if they were not + * enabled during discovery. */ static bool tb_disable_clx(struct tb_switch *sw) { @@ -456,10 +454,8 @@ static void tb_scan_xdomain(struct tb_port *port) } } -/** - * tb_find_unused_port() - return the first inactive port on @sw - * @sw: Switch to find the port on - * @type: Port type to look for +/* + * Returns the first inactive port on @sw. */ static struct tb_port *tb_find_unused_port(struct tb_switch *sw, enum tb_port_type type) @@ -549,6 +545,8 @@ static struct tb_tunnel *tb_find_first_usb3_tunnel(struct tb *tb, * from @src_port to @dst_port. Does not take USB3 tunnel starting from * @src_port and ending on @src_port into account because that bandwidth is * already included in as part of the "first hop" USB3 tunnel. + * + * Return: %0 on success, negative errno otherwise. */ static int tb_consumed_usb3_pcie_bandwidth(struct tb *tb, struct tb_port *src_port, @@ -601,6 +599,8 @@ static int tb_consumed_usb3_pcie_bandwidth(struct tb *tb, * If there is bandwidth reserved for any of the groups between * @src_port and @dst_port (but not yet used) that is also taken into * account in the returned consumed bandwidth. + * + * Return: %0 on success, negative errno otherwise. */ static int tb_consumed_dp_bandwidth(struct tb *tb, struct tb_port *src_port, @@ -701,6 +701,8 @@ static bool tb_asym_supported(struct tb_port *src_port, struct tb_port *dst_port * single link at @port. If @include_asym is set then includes the * additional banwdith if the links are transitioned into asymmetric to * direction from @src_port to @dst_port. + * + * Return: %0 on success, negative errno otherwise. */ static int tb_maximum_bandwidth(struct tb *tb, struct tb_port *src_port, struct tb_port *dst_port, struct tb_port *port, @@ -807,6 +809,8 @@ static int tb_maximum_bandwidth(struct tb *tb, struct tb_port *src_port, * If @include_asym is true then includes also bandwidth that can be * added when the links are transitioned into asymmetric (but does not * transition the links). + * + * Return: %0 on success, negative errno otherwise. */ static int tb_available_bandwidth(struct tb *tb, struct tb_port *src_port, struct tb_port *dst_port, int *available_up, @@ -1029,6 +1033,8 @@ static int tb_create_usb3_tunnels(struct tb_switch *sw) * (requested + currently consumed) on that link exceed @asym_threshold. * * Must be called with available >= requested over all links. + * + * Return: %0 on success, negative errno otherwise. */ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port, struct tb_port *dst_port, int requested_up, @@ -1135,6 +1141,8 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port, * Goes over each link from @src_port to @dst_port and tries to * transition the link to symmetric if the currently consumed bandwidth * allows and link asymmetric preference is ignored (if @keep_asym is %false). + * + * Return: %0 on success, negative errno otherwise. */ static int tb_configure_sym(struct tb *tb, struct tb_port *src_port, struct tb_port *dst_port, bool keep_asym) From 978a3d608f9f162ba2f0fa3c392ce8adaa171c95 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:38 +0200 Subject: [PATCH 1574/2711] thunderbolt: Update tb.h function documentation Make tb.h function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tb.h | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index f503bad86413..c1ffaf0bb39e 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -558,7 +558,7 @@ static inline void *tb_priv(struct tb *tb) * During switch alloc/init tb_upstream_port()->remote may be NULL, even for * non root switches (on the NHI port remote is always NULL). * - * Return: Returns the upstream port of the switch. + * Return: Pointer to &struct tb_port. */ static inline struct tb_port *tb_upstream_port(struct tb_switch *sw) { @@ -569,8 +569,8 @@ static inline struct tb_port *tb_upstream_port(struct tb_switch *sw) * tb_is_upstream_port() - Is the port upstream facing * @port: Port to check * - * Returns true if @port is upstream facing port. In case of dual link - * ports both return true. + * Return: %true if @port is upstream facing port. In case of dual link + * ports, both return %true. */ static inline bool tb_is_upstream_port(const struct tb_port *port) { @@ -613,7 +613,7 @@ static inline const char *tb_width_name(enum tb_link_width width) * tb_port_has_remote() - Does the port have switch connected downstream * @port: Port to check * - * Returns true only when the port is primary port and has remote set. + * Return: %true only when the port is primary port and has remote set. */ static inline bool tb_port_has_remote(const struct tb_port *port) { @@ -905,8 +905,9 @@ static inline struct tb_switch *tb_switch_parent(struct tb_switch *sw) * tb_switch_downstream_port() - Return downstream facing port of parent router * @sw: Device router pointer * - * Only call for device routers. Returns the downstream facing port of - * the parent router. + * Call only for device routers. + * + * Return: Pointer to &struct tb_port or %NULL in case of failure. */ static inline struct tb_port *tb_switch_downstream_port(struct tb_switch *sw) { @@ -918,6 +919,8 @@ static inline struct tb_port *tb_switch_downstream_port(struct tb_switch *sw) /** * tb_switch_depth() - Returns depth of the connected router * @sw: Router + * + * Return: Router depth level as a number. */ static inline int tb_switch_depth(const struct tb_switch *sw) { @@ -1010,6 +1013,9 @@ static inline bool tb_switch_is_tiger_lake(const struct tb_switch *sw) * is handling @sw this function can be called. It is valid to call this * after tb_switch_alloc() and tb_switch_configure() has been called * (latter only for SW CM case). + * + * Return: %true if switch is handled by ICM, %false if handled by + * software CM. */ static inline bool tb_switch_is_icm(const struct tb_switch *sw) { @@ -1037,6 +1043,8 @@ int tb_switch_tmu_configure(struct tb_switch *sw, enum tb_switch_tmu_mode mode); * * Checks if given router TMU mode is configured to @mode. Note the * router TMU might not be enabled to this mode. + * + * Return: %true if TMU mode is equal to @mode, %false otherwise. */ static inline bool tb_switch_tmu_is_configured(const struct tb_switch *sw, enum tb_switch_tmu_mode mode) @@ -1048,8 +1056,8 @@ static inline bool tb_switch_tmu_is_configured(const struct tb_switch *sw, * tb_switch_tmu_is_enabled() - Checks if the specified TMU mode is enabled * @sw: Router whose TMU mode to check * - * Return true if hardware TMU configuration matches the requested - * configuration (and is not %TB_SWITCH_TMU_MODE_OFF). + * Return: %true if hardware TMU configuration matches the requested + * configuration (and is not %TB_SWITCH_TMU_MODE_OFF), %false otherwise. */ static inline bool tb_switch_tmu_is_enabled(const struct tb_switch *sw) { @@ -1069,9 +1077,10 @@ int tb_switch_clx_disable(struct tb_switch *sw); * @clx: The CLx states to check for * * Checks if the specified CLx is enabled on the router upstream link. - * Returns true if any of the given states is enabled. * * Not applicable for a host router. + * + * Return: %true if any of the given states is enabled, %false otherwise. */ static inline bool tb_switch_clx_is_enabled(const struct tb_switch *sw, unsigned int clx) @@ -1103,7 +1112,7 @@ struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end, * @src: Source adapter * @dst: Destination adapter * - * Returns %true only if the specified path from source adapter (@src) + * Return: %true only if the specified path from source adapter (@src) * to destination adapter (@dst) is directed downstream. */ static inline bool @@ -1235,7 +1244,7 @@ static inline int tb_route_length(u64 route) * * Port must not be the upstream port (otherwise a loop is created). * - * Return: Returns a route to the switch behind @port. + * Return: Route to the switch behind @port. */ static inline u64 tb_downstream_route(struct tb_port *port) { @@ -1263,7 +1272,7 @@ static inline struct tb_switch *tb_xdomain_parent(struct tb_xdomain *xd) * tb_xdomain_downstream_port() - Return downstream facing port of parent router * @xd: Xdomain pointer * - * Returns the downstream port the XDomain is connected to. + * Return: Pointer to &struct tb_port or %NULL in case of failure. */ static inline struct tb_port *tb_xdomain_downstream_port(struct tb_xdomain *xd) { @@ -1291,7 +1300,7 @@ static inline struct tb_retimer *tb_to_retimer(struct device *dev) * usb4_switch_version() - Returns USB4 version of the router * @sw: Router to check * - * Returns major version of USB4 router (%1 for v1, %2 for v2 and so + * Return: Major version of USB4 router (%1 for v1, %2 for v2 and so * on). Can be called to pre-USB4 router too and in that case returns %0. */ static inline unsigned int usb4_switch_version(const struct tb_switch *sw) @@ -1303,7 +1312,7 @@ static inline unsigned int usb4_switch_version(const struct tb_switch *sw) * tb_switch_is_usb4() - Is the switch USB4 compliant * @sw: Switch to check * - * Returns true if the @sw is USB4 compliant router, false otherwise. + * Return: %true if the @sw is USB4 compliant router, %false otherwise. */ static inline bool tb_switch_is_usb4(const struct tb_switch *sw) { From b30234f27396c915547fa5905dcf79e5e9be3ff6 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:39 +0200 Subject: [PATCH 1575/2711] thunderbolt: Add missing documentation in tb.h Add missing parameters and struct/enum description in tb.h kernel-doc comments. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tb.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index c1ffaf0bb39e..8e2762ff8d51 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -324,7 +324,7 @@ struct usb4_port { }; /** - * tb_retimer: Thunderbolt retimer + * struct tb_retimer - Thunderbolt retimer * @dev: Device for the retimer * @tb: Pointer to the domain the retimer belongs to * @index: Retimer index facing the router USB4 port @@ -552,6 +552,7 @@ static inline void *tb_priv(struct tb *tb) /** * tb_upstream_port() - return the upstream port of a switch + * @sw: Router * * Every switch has an upstream port (for the root switch it is the NHI). * @@ -1241,6 +1242,7 @@ static inline int tb_route_length(u64 route) /** * tb_downstream_route() - get route to downstream switch + * @port: Port to check * * Port must not be the upstream port (otherwise a loop is created). * @@ -1364,7 +1366,7 @@ int usb4_port_asym_set_link_width(struct tb_port *port, enum tb_link_width width int usb4_port_asym_start(struct tb_port *port); /** - * enum tb_sb_target - Sideband transaction target + * enum usb4_sb_target - Sideband transaction target * @USB4_SB_TARGET_ROUTER: Target is the router itself * @USB4_SB_TARGET_PARTNER: Target is partner * @USB4_SB_TARGET_RETIMER: Target is retimer @@ -1409,6 +1411,8 @@ enum usb4_margining_lane { * @voltage_time_offset: Offset for voltage / time for software margining * @optional_voltage_offset_range: Enable optional extended voltage range * @right_high: %false if left/low margin test is performed, %true if right/high + * @upper_eye: %true if margin test is done on upper eye, %false if done on + * lower eye * @time: %true if time margining is used instead of voltage */ struct usb4_port_margining_params { From 371c2374449db296675a865c46cde54336ff2ef7 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:40 +0200 Subject: [PATCH 1576/2711] thunderbolt: Update tmu.c function documentation Make tmu.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tmu.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/thunderbolt/tmu.c b/drivers/thunderbolt/tmu.c index 9a259c72e5a7..b22831b41ec0 100644 --- a/drivers/thunderbolt/tmu.c +++ b/drivers/thunderbolt/tmu.c @@ -405,6 +405,8 @@ static int tmu_mode_init(struct tb_switch *sw) * This function must be called before other TMU related functions to * makes the internal structures are filled in correctly. Does not * change any hardware configuration. + * + * Return: %0 on success, negative errno otherwise. */ int tb_switch_tmu_init(struct tb_switch *sw) { @@ -439,6 +441,8 @@ int tb_switch_tmu_init(struct tb_switch *sw) * @sw: Switch whose time to update * * Updates switch local time using time posting procedure. + * + * Return: %0 on success, negative errno otherwise. */ int tb_switch_tmu_post_time(struct tb_switch *sw) { @@ -555,6 +559,8 @@ static int disable_enhanced(struct tb_port *up, struct tb_port *down) * @sw: Switch whose TMU to disable * * Turns off TMU of @sw if it is enabled. If not enabled does nothing. + * + * Return: %0 on success, negative errno otherwise. */ int tb_switch_tmu_disable(struct tb_switch *sw) { @@ -938,6 +944,8 @@ out: * Enables TMU of a router to be in uni-directional Normal/HiFi or * bi-directional HiFi mode. Calling tb_switch_tmu_configure() is * required before calling this function. + * + * Return: %0 on success, negative errno otherwise. */ int tb_switch_tmu_enable(struct tb_switch *sw) { @@ -1017,9 +1025,11 @@ int tb_switch_tmu_enable(struct tb_switch *sw) * Selects the TMU mode that is enabled when tb_switch_tmu_enable() is * next called. * - * Returns %0 in success and negative errno otherwise. Specifically - * returns %-EOPNOTSUPP if the requested mode is not possible (not - * supported by the router and/or topology). + * Return: + * * %0 - On success. + * * %-EOPNOTSUPP - If the requested mode is not possible (not supported by + * the router and/or topology). + * * Negative errno - Another error occurred. */ int tb_switch_tmu_configure(struct tb_switch *sw, enum tb_switch_tmu_mode mode) { From 6f3ed985b7d1e4950f1f63139f32a7d889e4aaee Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:41 +0200 Subject: [PATCH 1577/2711] thunderbolt: Update tunnel.c function documentation Make tunnel.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tunnel.c | 85 ++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index d52efe3f658c..850d9b107abd 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -121,6 +121,8 @@ static inline unsigned int tb_usable_credits(const struct tb_port *port) * @port: Lane adapter to check * @max_dp_streams: If non-%NULL stores maximum number of simultaneous DP * streams possible through this lane adapter + * + * Return: Number of available credits. */ static unsigned int tb_available_credits(const struct tb_port *port, size_t *max_dp_streams) @@ -415,8 +417,9 @@ static int tb_pci_init_path(struct tb_path *path) * @alloc_hopid: Allocate HopIDs from visited ports * * If @down adapter is active, follows the tunnel to the PCIe upstream - * adapter and back. Returns the discovered tunnel or %NULL if there was - * no tunnel. + * adapter and back. + * + * Return: Pointer to &struct tb_tunnel or %NULL if there was no tunnel. */ struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down, bool alloc_hopid) @@ -496,7 +499,7 @@ err_free: * Allocate a PCI tunnel. The ports must be of type TB_TYPE_PCIE_UP and * TB_TYPE_PCIE_DOWN. * - * Return: Returns a tb_tunnel on success or NULL on failure. + * Return: Pointer to @struct tb_tunnel or %NULL on failure. */ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up, struct tb_port *down) @@ -543,9 +546,12 @@ err_free: * * Can be called to any connected lane 0 adapter to find out how much * bandwidth needs to be left in reserve for possible PCIe bulk traffic. - * Returns true if there is something to be reserved and writes the - * amount to @reserved_down/@reserved_up. Otherwise returns false and - * does not touch the parameters. + * + * Return: + * * %true - If there is something to be reserved. Writes the amount to + * @reserved_down/@reserved_up. + * * %false - Nothing to be reserved. Leaves @reserved_down/@reserved_up + * unmodified. */ bool tb_tunnel_reserved_pci(struct tb_port *port, int *reserved_up, int *reserved_down) @@ -1151,7 +1157,8 @@ static int tb_dp_activate(struct tb_tunnel *tunnel, bool active) * @tunnel: DP tunnel to check * @max_bw_rounded: Maximum bandwidth in Mb/s rounded up to the next granularity * - * Returns maximum possible bandwidth for this tunnel in Mb/s. + * Return: Maximum possible bandwidth for this tunnel in Mb/s, negative errno + * in case of failure. */ static int tb_dp_bandwidth_mode_maximum_bandwidth(struct tb_tunnel *tunnel, int *max_bw_rounded) @@ -1547,7 +1554,7 @@ static void tb_dp_dump(struct tb_tunnel *tunnel) * and back. Returns the discovered tunnel or %NULL if there was no * tunnel. * - * Return: DP tunnel or %NULL if no tunnel found. + * Return: Pointer to &struct tb_tunnel or %NULL if no tunnel found. */ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, bool alloc_hopid) @@ -1648,7 +1655,7 @@ err_free: * successful (or if it returns %false there was some sort of issue). * The @callback is called without @tb->lock held. * - * Return: Returns a tb_tunnel on success or &NULL on failure. + * Return: Pointer to @struct tb_tunnel or %NULL in case of failure. */ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in, struct tb_port *out, int link_nr, @@ -1861,7 +1868,7 @@ static void tb_dma_destroy(struct tb_tunnel *tunnel) * @receive_ring: NHI ring number used to receive packets from the * other domain. Set to %-1 if RX path is not needed. * - * Return: Returns a tb_tunnel on success or NULL on failure. + * Return: Pointer to @struct tb_tunnel or %NULL in case of failure. */ struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi, struct tb_port *dst, int transmit_path, @@ -1938,7 +1945,8 @@ err_free: * * This function can be used to match specific DMA tunnel, if there are * multiple DMA tunnels going through the same XDomain connection. - * Returns true if there is match and false otherwise. + * + * Return: %true if there is a match, %false otherwise. */ bool tb_tunnel_match_dma(const struct tb_tunnel *tunnel, int transmit_path, int transmit_ring, int receive_path, int receive_ring) @@ -2160,8 +2168,9 @@ static void tb_usb3_init_path(struct tb_path *path) * @alloc_hopid: Allocate HopIDs from visited ports * * If @down adapter is active, follows the tunnel to the USB3 upstream - * adapter and back. Returns the discovered tunnel or %NULL if there was - * no tunnel. + * adapter and back. + * + * Return: Pointer to &struct tb_tunnel or %NULL if there was no tunnel. */ struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down, bool alloc_hopid) @@ -2266,7 +2275,7 @@ err_free: * Allocate an USB3 tunnel. The ports must be of type @TB_TYPE_USB3_UP and * @TB_TYPE_USB3_DOWN. * - * Return: Returns a tb_tunnel on success or %NULL on failure. + * Return: Pointer to @struct tb_tunnel or %NULL in case of failure. */ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up, struct tb_port *down, int max_up, @@ -2337,6 +2346,8 @@ err_free: /** * tb_tunnel_is_invalid - check whether an activated path is still valid * @tunnel: Tunnel to check + * + * Return: %true if path is valid, %false otherwise. */ bool tb_tunnel_is_invalid(struct tb_tunnel *tunnel) { @@ -2355,10 +2366,11 @@ bool tb_tunnel_is_invalid(struct tb_tunnel *tunnel) * tb_tunnel_activate() - activate a tunnel * @tunnel: Tunnel to activate * - * Return: 0 on success and negative errno in case if failure. - * Specifically returns %-EINPROGRESS if the tunnel activation is still - * in progress (that's for DP tunnels to complete DPRX capabilities - * read). + * Return: + * * %0 - On success. + * * %-EINPROGRESS - If the tunnel activation is still in progress (that's + * for DP tunnels to complete DPRX capabilities read). + * * Negative errno - Another error occurred. */ int tb_tunnel_activate(struct tb_tunnel *tunnel) { @@ -2438,8 +2450,8 @@ void tb_tunnel_deactivate(struct tb_tunnel *tunnel) * @tunnel: Tunnel to check * @port: Port to check * - * Returns true if @tunnel goes through @port (direction does not matter), - * false otherwise. + * Return: %true if @tunnel goes through @port (direction does not matter), + * %false otherwise. */ bool tb_tunnel_port_on_path(const struct tb_tunnel *tunnel, const struct tb_port *port) @@ -2469,9 +2481,11 @@ static bool tb_tunnel_is_activated(const struct tb_tunnel *tunnel) * @max_up: Maximum upstream bandwidth in Mb/s * @max_down: Maximum downstream bandwidth in Mb/s * - * Returns maximum possible bandwidth this tunnel can go if not limited - * by other bandwidth clients. If the tunnel does not support this - * returns %-EOPNOTSUPP. + * Return: + * * Maximum possible bandwidth this tunnel can support if not + * limited by other bandwidth clients. + * * %-EOPNOTSUPP - If the tunnel does not support this function. + * * %-ENOTCONN - If the tunnel is not active. */ int tb_tunnel_maximum_bandwidth(struct tb_tunnel *tunnel, int *max_up, int *max_down) @@ -2491,8 +2505,12 @@ int tb_tunnel_maximum_bandwidth(struct tb_tunnel *tunnel, int *max_up, * @allocated_down: Currently allocated downstream bandwidth in Mb/s is * stored here * - * Returns the bandwidth allocated for the tunnel. This may be higher - * than what the tunnel actually consumes. + * Return: + * * Bandwidth allocated for the tunnel. This may be higher than what the + * tunnel actually consumes. + * * %-EOPNOTSUPP - If the tunnel does not support this function. + * * %-ENOTCONN - If the tunnel is not active. + * * Negative errno - Another error occurred. */ int tb_tunnel_allocated_bandwidth(struct tb_tunnel *tunnel, int *allocated_up, int *allocated_down) @@ -2512,10 +2530,12 @@ int tb_tunnel_allocated_bandwidth(struct tb_tunnel *tunnel, int *allocated_up, * @alloc_up: New upstream bandwidth in Mb/s * @alloc_down: New downstream bandwidth in Mb/s * - * Tries to change tunnel bandwidth allocation. If succeeds returns %0 - * and updates @alloc_up and @alloc_down to that was actually allocated - * (it may not be the same as passed originally). Returns negative errno - * in case of failure. + * Tries to change tunnel bandwidth allocation. + * + * Return: + * * %0 - On success. Updates @alloc_up and @alloc_down to values that were + * actually allocated (it may not be the same as passed originally). + * * Negative errno - In case of failure. */ int tb_tunnel_alloc_bandwidth(struct tb_tunnel *tunnel, int *alloc_up, int *alloc_down) @@ -2546,8 +2566,9 @@ int tb_tunnel_alloc_bandwidth(struct tb_tunnel *tunnel, int *alloc_up, * Can be %NULL. * * Stores the amount of isochronous bandwidth @tunnel consumes in - * @consumed_up and @consumed_down. In case of success returns %0, - * negative errno otherwise. + * @consumed_up and @consumed_down. + * + * Return: %0 on success, negative errno otherwise. */ int tb_tunnel_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up, int *consumed_down) @@ -2585,7 +2606,7 @@ int tb_tunnel_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up, * If tunnel supports dynamic bandwidth management (USB3 tunnels at the * moment) this function makes it to release all the unused bandwidth. * - * Returns %0 in case of success and negative errno otherwise. + * Return: %0 on success, negative errno otherwise. */ int tb_tunnel_release_unused_bandwidth(struct tb_tunnel *tunnel) { From e262b91b223a237fa87c83ce1b4e4e2dafd053ad Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:42 +0200 Subject: [PATCH 1578/2711] thunderbolt: Update tunnel.h function documentation Make tunnel.h function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tunnel.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h index 5e9fb73d5220..2c44fc8a10bc 100644 --- a/drivers/thunderbolt/tunnel.h +++ b/drivers/thunderbolt/tunnel.h @@ -142,10 +142,11 @@ void tb_tunnel_deactivate(struct tb_tunnel *tunnel); * tb_tunnel_is_active() - Is tunnel fully activated * @tunnel: Tunnel to check * - * Returns %true if @tunnel is fully activated. For other than DP - * tunnels this is pretty much once tb_tunnel_activate() returns - * successfully. However, for DP tunnels this returns %true only once the - * DPRX capabilities read has been issued successfully. + * Return: %true if @tunnel is fully activated. + * + * Note for DP tunnels this returns %true only once the DPRX capabilities + * read has been issued successfully. For other tunnels, this function + * returns %true pretty much once tb_tunnel_activate() returns successfully. */ static inline bool tb_tunnel_is_active(const struct tb_tunnel *tunnel) { From 9a5abaf8be02aeedd8f374b253da472f9eedfbf1 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:43 +0200 Subject: [PATCH 1579/2711] thunderbolt: Update usb4.c function documentation Make usb4.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/usb4.c | 333 +++++++++++++++++++++++++------------ 1 file changed, 229 insertions(+), 104 deletions(-) diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index e160afadd501..76f01713a875 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -237,6 +237,8 @@ static bool link_is_usb4(struct tb_port *port) * * This does not set the configuration valid bit of the router. To do * that call usb4_switch_configuration_valid(). + * + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_setup(struct tb_switch *sw) { @@ -304,7 +306,7 @@ int usb4_switch_setup(struct tb_switch *sw) * usb4_switch_setup() has been called. Can be called to host and device * routers (does nothing for the latter). * - * Returns %0 in success and negative errno otherwise. + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_configuration_valid(struct tb_switch *sw) { @@ -334,6 +336,8 @@ int usb4_switch_configuration_valid(struct tb_switch *sw) * @uid: UID is stored here * * Reads 64-bit UID from USB4 router config space. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_read_uid(struct tb_switch *sw, u64 *uid) { @@ -371,6 +375,8 @@ static int usb4_switch_drom_read_block(void *data, * Uses USB4 router operations to read router DROM. For devices this * should always work but for hosts it may return %-EOPNOTSUPP in which * case the host router does not have DROM. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_drom_read(struct tb_switch *sw, unsigned int address, void *buf, size_t size) @@ -385,6 +391,8 @@ int usb4_switch_drom_read(struct tb_switch *sw, unsigned int address, void *buf, * * Checks whether conditions are met so that lane bonding can be * established with the upstream router. Call only for device routers. + * + * Return: %true if lane bonding is possible, %false otherwise. */ bool usb4_switch_lane_bonding_possible(struct tb_switch *sw) { @@ -407,6 +415,8 @@ bool usb4_switch_lane_bonding_possible(struct tb_switch *sw) * @runtime: Wake is being programmed during system runtime * * Enables/disables router to wake up from sleep. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags, bool runtime) { @@ -484,8 +494,10 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags, bool runtime) * usb4_switch_set_sleep() - Prepare the router to enter sleep * @sw: USB4 router * - * Sets sleep bit for the router. Returns when the router sleep ready + * Sets sleep bit for the router and waits until router sleep ready * bit has been asserted. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_set_sleep(struct tb_switch *sw) { @@ -511,9 +523,10 @@ int usb4_switch_set_sleep(struct tb_switch *sw) * usb4_switch_nvm_sector_size() - Return router NVM sector size * @sw: USB4 router * - * If the router supports NVM operations this function returns the NVM - * sector size in bytes. If NVM operations are not supported returns - * %-EOPNOTSUPP. + * Return: + * * NVM sector size in bytes if router supports NVM operations. + * * %-EOPNOTSUPP - If router does not support NVM operations. + * * Negative errno - Another error occurred. */ int usb4_switch_nvm_sector_size(struct tb_switch *sw) { @@ -560,8 +573,12 @@ static int usb4_switch_nvm_read_block(void *data, * @buf: Read data is placed here * @size: How many bytes to read * - * Reads NVM contents of the router. If NVM is not supported returns - * %-EOPNOTSUPP. + * Reads NVM contents of the router. + * + * Return: + * * %0 - Read completed successfully. + * * %-EOPNOTSUPP - NVM not supported. + * * Negative errno - Another error occurred. */ int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf, size_t size) @@ -578,7 +595,7 @@ int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf, * Explicitly sets NVM write offset. Normally when writing to NVM this * is done automatically by usb4_switch_nvm_write(). * - * Returns %0 in success and negative errno if there was a failure. + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_nvm_set_offset(struct tb_switch *sw, unsigned int address) { @@ -620,8 +637,12 @@ static int usb4_switch_nvm_write_next_block(void *data, unsigned int dwaddress, * @buf: Pointer to the data to write * @size: Size of @buf in bytes * - * Writes @buf to the router NVM using USB4 router operations. If NVM - * write is not supported returns %-EOPNOTSUPP. + * Writes @buf to the router NVM using USB4 router operations. + * + * Return: + * * %0 - Write completed successfully. + * * %-EOPNOTSUPP - NVM write not supported. + * * Negative errno - Another error occurred. */ int usb4_switch_nvm_write(struct tb_switch *sw, unsigned int address, const void *buf, size_t size) @@ -643,11 +664,13 @@ int usb4_switch_nvm_write(struct tb_switch *sw, unsigned int address, * After the new NVM has been written via usb4_switch_nvm_write(), this * function triggers NVM authentication process. The router gets power * cycled and if the authentication is successful the new NVM starts - * running. In case of failure returns negative errno. + * running. * * The caller should call usb4_switch_nvm_authenticate_status() to read * the status of the authentication after power cycle. It should be the * first router operation to avoid the status being lost. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_nvm_authenticate(struct tb_switch *sw) { @@ -675,11 +698,13 @@ int usb4_switch_nvm_authenticate(struct tb_switch *sw) * @status: Status code of the operation * * The function checks if there is status available from the last NVM - * authenticate router operation. If there is status then %0 is returned - * and the status code is placed in @status. Returns negative errno in case - * of failure. + * authenticate router operation. * * Must be called before any other router operation. + * + * Return: + * * %0 - If there is status. Status code is placed in @status. + * * Negative errno - Failure occurred. */ int usb4_switch_nvm_authenticate_status(struct tb_switch *sw, u32 *status) { @@ -723,7 +748,7 @@ int usb4_switch_nvm_authenticate_status(struct tb_switch *sw, u32 *status) * allocation fields accordingly. Specifically @sw->credits_allocation * is set to %true if these parameters can be used in tunneling. * - * Returns %0 on success and negative errno otherwise. + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_credits_init(struct tb_switch *sw) { @@ -862,8 +887,10 @@ err_invalid: * @in: DP IN adapter * * For DP tunneling this function can be used to query availability of - * DP IN resource. Returns true if the resource is available for DP - * tunneling, false otherwise. + * DP IN resource. + * + * Return: %true if the resource is available for DP tunneling, %false + * otherwise. */ bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in) { @@ -891,9 +918,12 @@ bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in) * @in: DP IN adapter * * Allocates DP IN resource for DP tunneling using USB4 router - * operations. If the resource was allocated returns %0. Otherwise - * returns negative errno, in particular %-EBUSY if the resource is - * already allocated. + * operations. + * + * Return: + * * %0 - Resource allocated successfully. + * * %-EBUSY - Resource is already allocated. + * * Negative errno - Other failure occurred. */ int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in) { @@ -917,6 +947,8 @@ int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in) * @in: DP IN adapter * * Releases the previously allocated DP IN resource. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in) { @@ -972,6 +1004,8 @@ int usb4_port_index(const struct tb_switch *sw, const struct tb_port *port) * downstream adapters where the PCIe topology is extended. This * function returns the corresponding downstream PCIe adapter or %NULL * if no such mapping was possible. + * + * Return: Pointer to &struct tb_port or %NULL if not found. */ struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw, const struct tb_port *port) @@ -1003,6 +1037,8 @@ struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw, * downstream adapters where the USB 3.x topology is extended. This * function returns the corresponding downstream USB 3.x adapter or * %NULL if no such mapping was possible. + * + * Return: Pointer to &struct tb_port or %NULL if not found. */ struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw, const struct tb_port *port) @@ -1032,7 +1068,7 @@ struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw, * For USB4 router finds all USB4 ports and registers devices for each. * Can be called to any router. * - * Return %0 in case of success and negative errno in case of failure. + * Return: %0 on success, negative errno otherwise. */ int usb4_switch_add_ports(struct tb_switch *sw) { @@ -1085,6 +1121,8 @@ void usb4_switch_remove_ports(struct tb_switch *sw) * * Unlocks USB4 downstream port so that the connection manager can * access the router below this port. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_unlock(struct tb_port *port) { @@ -1105,6 +1143,8 @@ int usb4_port_unlock(struct tb_port *port) * * Enables hot plug events on a given port. This is only intended * to be used on lane, DP-IN, and DP-OUT adapters. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_hotplug_enable(struct tb_port *port) { @@ -1124,6 +1164,8 @@ int usb4_port_hotplug_enable(struct tb_port *port) * @port: USB4 port to reset * * Issues downstream port reset to @port. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_reset(struct tb_port *port) { @@ -1185,6 +1227,8 @@ static int usb4_port_set_configured(struct tb_port *port, bool configured) * @port: USB4 router * * Sets the USB4 link to be configured for power management purposes. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_configure(struct tb_port *port) { @@ -1196,6 +1240,8 @@ int usb4_port_configure(struct tb_port *port) * @port: USB4 router * * Sets the USB4 link to be unconfigured for power management purposes. + * + * Return: %0 on success, negative errno otherwise. */ void usb4_port_unconfigure(struct tb_port *port) { @@ -1230,7 +1276,9 @@ static int usb4_set_xdomain_configured(struct tb_port *port, bool configured) * @xd: XDomain that is connected to the port * * Marks the USB4 port as being connected to another host and updates - * the link type. Returns %0 in success and negative errno in failure. + * the link type. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_configure_xdomain(struct tb_port *port, struct tb_xdomain *xd) { @@ -1300,7 +1348,8 @@ static int usb4_port_write_data(struct tb_port *port, const void *data, * @size: Size of @buf * * Reads data from sideband register @reg and copies it into @buf. - * Returns %0 in case of success and negative errno in case of failure. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, u8 index, u8 reg, void *buf, u8 size) @@ -1351,8 +1400,9 @@ int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, u8 index * @buf: Data to write * @size: Size of @buf * - * Writes @buf to sideband register @reg. Returns %0 in case of success - * and negative errno in case of failure. + * Writes @buf to sideband register @reg. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target, u8 index, u8 reg, const void *buf, u8 size) @@ -1469,8 +1519,7 @@ static int usb4_port_set_router_offline(struct tb_port *port, bool offline) * port does not react on hotplug events anymore. This needs to be * called before retimer access is done when the USB4 links is not up. * - * Returns %0 in case of success and negative errno if there was an - * error. + * Return: %0 on success, negative errno otherwise. */ int usb4_port_router_offline(struct tb_port *port) { @@ -1482,6 +1531,8 @@ int usb4_port_router_offline(struct tb_port *port) * @port: USB4 port * * Makes the USB4 port functional again. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_router_online(struct tb_port *port) { @@ -1493,8 +1544,9 @@ int usb4_port_router_online(struct tb_port *port) * @port: USB4 port * * This forces the USB4 port to send broadcast RT transaction which - * makes the retimers on the link to assign index to themselves. Returns - * %0 in case of success and negative errno if there was an error. + * makes the retimers on the link assign index to themselves. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_enumerate_retimers(struct tb_port *port) { @@ -1511,6 +1563,8 @@ int usb4_port_enumerate_retimers(struct tb_port *port) * * PORT_CS_18_CPS bit reflects if the link supports CLx including * active cables (if connected on the link). + * + * Return: %true if Clx is supported, %false otherwise. */ bool usb4_port_clx_supported(struct tb_port *port) { @@ -1529,8 +1583,9 @@ bool usb4_port_clx_supported(struct tb_port *port) * usb4_port_asym_supported() - If the port supports asymmetric link * @port: USB4 port * - * Checks if the port and the cable supports asymmetric link and returns - * %true in that case. + * Checks if the port and the cable support asymmetric link. + * + * Return: %true if asymmetric link is supported, %false otherwise. */ bool usb4_port_asym_supported(struct tb_port *port) { @@ -1552,6 +1607,8 @@ bool usb4_port_asym_supported(struct tb_port *port) * * Sets USB4 port link width to @width. Can be called for widths where * usb4_port_asym_width_supported() returned @true. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_asym_set_link_width(struct tb_port *port, enum tb_link_width width) { @@ -1596,8 +1653,10 @@ int usb4_port_asym_set_link_width(struct tb_port *port, enum tb_link_width width * (according to what was previously set in tb_port_set_link_width(). * Wait for completion of the change. * - * Returns %0 in case of success, %-ETIMEDOUT if case of timeout or - * a negative errno in case of a failure. + * Return: + * * %0 - Symmetry change was successful. + * * %-ETIMEDOUT - Timeout occurred. + * * Negative errno - Other failure occurred. */ int usb4_port_asym_start(struct tb_port *port) { @@ -1641,6 +1700,8 @@ int usb4_port_asym_start(struct tb_port *port) * @ncaps: Number of elements in the caps array * * Reads the USB4 port lane margining capabilities into @caps. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target, u8 index, u32 *caps, size_t ncaps) @@ -1667,6 +1728,8 @@ int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target, * * Runs hardware lane margining on USB4 port and returns the result in * @results. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target, u8 index, const struct usb4_port_margining_params *params, @@ -1711,8 +1774,9 @@ int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target, * @results: Data word for the operation completion data * * Runs software lane margining on USB4 port. Read back the error - * counters by calling usb4_port_sw_margin_errors(). Returns %0 in - * success and negative errno otherwise. + * counters by calling usb4_port_sw_margin_errors(). + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target, u8 index, const struct usb4_port_margining_params *params, @@ -1759,7 +1823,8 @@ int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target, * @errors: Error metadata is copied here. * * This reads back the software margining error counters from the port. - * Returns %0 in success and negative errno otherwise. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_sw_margin_errors(struct tb_port *port, enum usb4_sb_target target, u8 index, u32 *errors) @@ -1790,6 +1855,8 @@ static inline int usb4_port_retimer_op(struct tb_port *port, u8 index, * * Enables sideband channel transations on SBTX. Can be used when USB4 * link does not go up, for example if there is no device connected. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index) { @@ -1817,6 +1884,8 @@ int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index) * * Disables sideband channel transations on SBTX. The reverse of * usb4_port_retimer_set_inbound_sbtx(). + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index) { @@ -1829,10 +1898,12 @@ int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index) * @port: USB4 port * @index: Retimer index * - * If the retimer at @index is last one (connected directly to the - * Type-C port) this function returns %1. If it is not returns %0. If - * the retimer is not present returns %-ENODEV. Otherwise returns - * negative errno. + * Return: + * * %1 - Retimer at @index is the last one (connected directly to the + * Type-C port). + * * %0 - Retimer at @index is not the last one. + * * %-ENODEV - Retimer is not present. + * * Negative errno - Other failure occurred. */ int usb4_port_retimer_is_last(struct tb_port *port, u8 index) { @@ -1854,9 +1925,11 @@ int usb4_port_retimer_is_last(struct tb_port *port, u8 index) * @port: USB4 port * @index: Retimer index * - * If the retimer at @index is last cable retimer this function returns - * %1 and %0 if it is on-board retimer. In case a retimer is not present - * at @index returns %-ENODEV. Otherwise returns negative errno. + * Return: + * * %1 - Retimer at @index is the last cable retimer. + * * %0 - Retimer at @index is on-board retimer. + * * %-ENODEV - Retimer is not present. + * * Negative errno - Other failure occurred. */ int usb4_port_retimer_is_cable(struct tb_port *port, u8 index) { @@ -1880,9 +1953,12 @@ int usb4_port_retimer_is_cable(struct tb_port *port, u8 index) * * Reads NVM sector size (in bytes) of a retimer at @index. This * operation can be used to determine whether the retimer supports NVM - * upgrade for example. Returns sector size in bytes or negative errno - * in case of error. Specifically returns %-ENODEV if there is no - * retimer at @index. + * upgrade for example. + * + * Return: + * * Sector size in bytes. + * * %-ENODEV - If there is no retimer at @index. + * * Negative errno - In case of an error. */ int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index) { @@ -1908,7 +1984,7 @@ int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index) * Exlicitly sets NVM write offset. Normally when writing to NVM this is * done automatically by usb4_port_retimer_nvm_write(). * - * Returns %0 in success and negative errno if there was a failure. + * Return: %0 on success, negative errno otherwise. */ int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index, unsigned int address) @@ -1961,9 +2037,12 @@ static int usb4_port_retimer_nvm_write_next_block(void *data, * @size: Size in bytes how much to write * * Writes @size bytes from @buf to the retimer NVM. Used for NVM - * upgrade. Returns %0 if the data was written successfully and negative - * errno in case of failure. Specifically returns %-ENODEV if there is - * no retimer at @index. + * upgrade. + * + * Return: + * * %0 - If the data was written successfully. + * * %-ENODEV - If there is no retimer at @index. + * * Negative errno - In case of an error. */ int usb4_port_retimer_nvm_write(struct tb_port *port, u8 index, unsigned int address, const void *buf, size_t size) @@ -1989,6 +2068,8 @@ int usb4_port_retimer_nvm_write(struct tb_port *port, u8 index, unsigned int add * successful the retimer restarts with the new NVM and may not have the * index set so one needs to call usb4_port_enumerate_retimers() to * force index to be assigned. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_retimer_nvm_authenticate(struct tb_port *port, u8 index) { @@ -2013,9 +2094,9 @@ int usb4_port_retimer_nvm_authenticate(struct tb_port *port, u8 index) * This can be called after usb4_port_retimer_nvm_authenticate() and * usb4_port_enumerate_retimers() to fetch status of the NVM upgrade. * - * Returns %0 if the authentication status was successfully read. The + * Return: %0 if the authentication status was successfully read. The * completion metadata (the result) is then stored into @status. If - * reading the status fails, returns negative errno. + * status read fails, returns negative errno. */ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index, u32 *status) @@ -2083,9 +2164,12 @@ static int usb4_port_retimer_nvm_read_block(void *data, unsigned int dwaddress, * @buf: Data read from NVM is stored here * @size: Number of bytes to read * - * Reads retimer NVM and copies the contents to @buf. Returns %0 if the - * read was successful and negative errno in case of failure. - * Specifically returns %-ENODEV if there is no retimer at @index. + * Reads retimer NVM and copies the contents to @buf. + * + * Return: + * * %0 - If the read was successful. + * * %-ENODEV - If there is no retimer at @index. + * * Negative errno - In case of an error. */ int usb4_port_retimer_nvm_read(struct tb_port *port, u8 index, unsigned int address, void *buf, size_t size) @@ -2109,8 +2193,8 @@ usb4_usb3_port_max_bandwidth(const struct tb_port *port, unsigned int bw) * usb4_usb3_port_max_link_rate() - Maximum support USB3 link rate * @port: USB3 adapter port * - * Return maximum supported link rate of a USB3 adapter in Mb/s. - * Negative errno in case of error. + * Return: Maximum supported link rate of a USB3 adapter in Mb/s. + * Negative errno in case of an error. */ int usb4_usb3_port_max_link_rate(struct tb_port *port) { @@ -2228,8 +2312,9 @@ static int usb4_usb3_port_read_allocated_bandwidth(struct tb_port *port, * @downstream_bw: Allocated downstream bandwidth is stored here * * Stores currently allocated USB3 bandwidth into @upstream_bw and - * @downstream_bw in Mb/s. Returns %0 in case of success and negative - * errno in failure. + * @downstream_bw in Mb/s. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_usb3_port_allocated_bandwidth(struct tb_port *port, int *upstream_bw, int *downstream_bw) @@ -2331,8 +2416,7 @@ static int usb4_usb3_port_write_allocated_bandwidth(struct tb_port *port, * cannot be taken away by CM). The actual new values are returned in * @upstream_bw and @downstream_bw. * - * Returns %0 in case of success and negative errno if there was a - * failure. + * Return: %0 on success, negative errno otherwise. */ int usb4_usb3_port_allocate_bandwidth(struct tb_port *port, int *upstream_bw, int *downstream_bw) @@ -2374,7 +2458,7 @@ err_request: * Releases USB3 allocated bandwidth down to what is actually consumed. * The new bandwidth is returned in @upstream_bw and @downstream_bw. * - * Returns 0% in success and negative errno in case of failure. + * Return: %0 on success, negative errno otherwise. */ int usb4_usb3_port_release_bandwidth(struct tb_port *port, int *upstream_bw, int *downstream_bw) @@ -2426,9 +2510,12 @@ static bool is_usb4_dpin(const struct tb_port *port) * @port: DP IN adapter * @cm_id: CM ID to assign * - * Sets CM ID for the @port. Returns %0 on success and negative errno - * otherwise. Speficially returns %-EOPNOTSUPP if the @port does not - * support this. + * Sets CM ID for the @port. + * + * Return: + * * %0 - On success. + * * %-EOPNOTSUPP - If the @port does not support this. + * * Negative errno - Another error occurred. */ int usb4_dp_port_set_cm_id(struct tb_port *port, int cm_id) { @@ -2455,8 +2542,10 @@ int usb4_dp_port_set_cm_id(struct tb_port *port, int cm_id) * supported * @port: DP IN adapter to check * - * Can be called to any DP IN adapter. Returns true if the adapter - * supports USB4 bandwidth allocation mode, false otherwise. + * Can be called to any DP IN adapter. + * + * Return: %true if the adapter supports USB4 bandwidth allocation mode, + * %false otherwise. */ bool usb4_dp_port_bandwidth_mode_supported(struct tb_port *port) { @@ -2479,8 +2568,10 @@ bool usb4_dp_port_bandwidth_mode_supported(struct tb_port *port) * enabled * @port: DP IN adapter to check * - * Can be called to any DP IN adapter. Returns true if the bandwidth - * allocation mode has been enabled, false otherwise. + * Can be called to any DP IN adapter. + * + * Return: %true if the bandwidth allocation mode has been enabled, + * %false otherwise. */ bool usb4_dp_port_bandwidth_mode_enabled(struct tb_port *port) { @@ -2505,9 +2596,12 @@ bool usb4_dp_port_bandwidth_mode_enabled(struct tb_port *port) * @supported: Does the CM support bandwidth allocation mode * * Can be called to any DP IN adapter. Sets or clears the CM support bit - * of the DP IN adapter. Returns %0 in success and negative errno - * otherwise. Specifically returns %-OPNOTSUPP if the passed in adapter - * does not support this. + * of the DP IN adapter. + * + * * Return: + * * %0 - On success. + * * %-EOPNOTSUPP - If the passed IN adapter does not support this. + * * Negative errno - Another error occurred. */ int usb4_dp_port_set_cm_bandwidth_mode_supported(struct tb_port *port, bool supported) @@ -2537,8 +2631,12 @@ int usb4_dp_port_set_cm_bandwidth_mode_supported(struct tb_port *port, * @port: DP IN adapter * * Reads bandwidth allocation Group ID from the DP IN adapter and - * returns it. If the adapter does not support setting Group_ID - * %-EOPNOTSUPP is returned. + * returns it. + * + * Return: + * * Group ID assigned to adapter @port. + * * %-EOPNOTSUPP - If adapter does not support setting GROUP_ID. + * * Negative errno - Another error occurred. */ int usb4_dp_port_group_id(struct tb_port *port) { @@ -2562,9 +2660,11 @@ int usb4_dp_port_group_id(struct tb_port *port) * @group_id: Group ID for the adapter * * Sets bandwidth allocation mode Group ID for the DP IN adapter. - * Returns %0 in case of success and negative errno otherwise. - * Specifically returns %-EOPNOTSUPP if the adapter does not support - * this. + * + * Return: + * * %0 - On success. + * * %-EOPNOTSUPP - If the adapter does not support this. + * * Negative errno - Another error occurred. */ int usb4_dp_port_set_group_id(struct tb_port *port, int group_id) { @@ -2592,9 +2692,12 @@ int usb4_dp_port_set_group_id(struct tb_port *port, int group_id) * @rate: Non-reduced rate in Mb/s is placed here * @lanes: Non-reduced lanes are placed here * - * Reads the non-reduced rate and lanes from the DP IN adapter. Returns - * %0 in success and negative errno otherwise. Specifically returns - * %-EOPNOTSUPP if the adapter does not support this. + * Reads the non-reduced rate and lanes from the DP IN adapter. + * + * Return: + * * %0 - On success. + * * %-EOPNOTSUPP - If the adapter does not support this. + * * Negative errno - Another error occurred. */ int usb4_dp_port_nrd(struct tb_port *port, int *rate, int *lanes) { @@ -2647,10 +2750,13 @@ int usb4_dp_port_nrd(struct tb_port *port, int *rate, int *lanes) * @rate: Non-reduced rate in Mb/s * @lanes: Non-reduced lanes * - * Before the capabilities reduction this function can be used to set - * the non-reduced values for the DP IN adapter. Returns %0 in success - * and negative errno otherwise. If the adapter does not support this - * %-EOPNOTSUPP is returned. + * Before the capabilities reduction, this function can be used to set + * the non-reduced values for the DP IN adapter. + * + * Return: + * * %0 - On success. + * * %-EOPNOTSUPP - If the adapter does not support this. + * * Negative errno - Another error occurred. */ int usb4_dp_port_set_nrd(struct tb_port *port, int rate, int lanes) { @@ -2709,9 +2815,13 @@ int usb4_dp_port_set_nrd(struct tb_port *port, int rate, int lanes) * usb4_dp_port_granularity() - Return granularity for the bandwidth values * @port: DP IN adapter * - * Reads the programmed granularity from @port. If the DP IN adapter does - * not support bandwidth allocation mode returns %-EOPNOTSUPP and negative - * errno in other error cases. + * Reads the programmed granularity from @port. + * + * Return: + * * Granularity value of a @port. + * * %-EOPNOTSUPP - If the DP IN adapter does not support bandwidth + * allocation mode. + * * Negative errno - Another error occurred. */ int usb4_dp_port_granularity(struct tb_port *port) { @@ -2747,8 +2857,12 @@ int usb4_dp_port_granularity(struct tb_port *port) * @granularity: Granularity in Mb/s. Supported values: 1000, 500 and 250. * * Sets the granularity used with the estimated, allocated and requested - * bandwidth. Returns %0 in success and negative errno otherwise. If the - * adapter does not support this %-EOPNOTSUPP is returned. + * bandwidth. + * + * Return: + * * %0 - On success. + * * %-EOPNOTSUPP - If the adapter does not support this. + * * Negative errno - Another error occurred. */ int usb4_dp_port_set_granularity(struct tb_port *port, int granularity) { @@ -2789,10 +2903,13 @@ int usb4_dp_port_set_granularity(struct tb_port *port, int granularity) * @bw: Estimated bandwidth in Mb/s. * * Sets the estimated bandwidth to @bw. Set the granularity by calling - * usb4_dp_port_set_granularity() before calling this. The @bw is round - * down to the closest granularity multiplier. Returns %0 in success - * and negative errno otherwise. Specifically returns %-EOPNOTSUPP if - * the adapter does not support this. + * usb4_dp_port_set_granularity() before calling this. The @bw is rounded + * down to the closest granularity multiplier. + * + * Return: + * * %0 - On success. + * * %-EOPNOTSUPP - If the adapter does not support this. + * * Negative errno - Another error occurred. */ int usb4_dp_port_set_estimated_bandwidth(struct tb_port *port, int bw) { @@ -2823,9 +2940,10 @@ int usb4_dp_port_set_estimated_bandwidth(struct tb_port *port, int bw) * usb4_dp_port_allocated_bandwidth() - Return allocated bandwidth * @port: DP IN adapter * - * Reads and returns allocated bandwidth for @port in Mb/s (taking into - * account the programmed granularity). Returns negative errno in case - * of error. + * Reads the allocated bandwidth for @port in Mb/s (taking into account + * the programmed granularity). + * + * Return: Allocated bandwidth in Mb/s or negative errno in case of an error. */ int usb4_dp_port_allocated_bandwidth(struct tb_port *port) { @@ -2920,8 +3038,9 @@ static int usb4_dp_port_wait_and_clear_cm_ack(struct tb_port *port, * @bw: New allocated bandwidth in Mb/s * * Communicates the new allocated bandwidth with the DPCD (graphics - * driver). Takes into account the programmed granularity. Returns %0 in - * success and negative errno in case of error. + * driver). Takes into account the programmed granularity. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_dp_port_allocate_bandwidth(struct tb_port *port, int bw) { @@ -2961,10 +3080,15 @@ int usb4_dp_port_allocate_bandwidth(struct tb_port *port, int bw) * @port: DP IN adapter * * Reads the DPCD (graphics driver) requested bandwidth and returns it - * in Mb/s. Takes the programmed granularity into account. In case of - * error returns negative errno. Specifically returns %-EOPNOTSUPP if - * the adapter does not support bandwidth allocation mode, and %ENODATA - * if there is no active bandwidth request from the graphics driver. + * in Mb/s. Takes the programmed granularity into account. + * + * Return: + * * Requested bandwidth in Mb/s - On success. + * * %-EOPNOTSUPP - If the adapter does not support bandwidth allocation + * mode. + * * %ENODATA - If there is no active bandwidth request from the graphics + * driver. + * * Negative errno - On failure. */ int usb4_dp_port_requested_bandwidth(struct tb_port *port) { @@ -2996,8 +3120,9 @@ int usb4_dp_port_requested_bandwidth(struct tb_port *port) * @enable: Enable/disable extended encapsulation * * Enables or disables extended encapsulation used in PCIe tunneling. Caller - * needs to make sure both adapters support this before enabling. Returns %0 on - * success and negative errno otherwise. + * needs to make sure both adapters support this before enabling. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_pci_port_set_ext_encapsulation(struct tb_port *port, bool enable) { From a2ba553cd45a5fb33f0edc6dd8c6b5280cad4ab0 Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:44 +0200 Subject: [PATCH 1580/2711] thunderbolt: Update usb4_port.c function documentation Make usb4_port.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/usb4_port.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/thunderbolt/usb4_port.c b/drivers/thunderbolt/usb4_port.c index 852a45fcd19d..b5e06237261b 100644 --- a/drivers/thunderbolt/usb4_port.c +++ b/drivers/thunderbolt/usb4_port.c @@ -296,8 +296,9 @@ const struct device_type usb4_port_device_type = { * usb4_port_device_add() - Add USB4 port device * @port: Lane 0 adapter port to add the USB4 port * - * Creates and registers a USB4 port device for @port. Returns the new - * USB4 port device pointer or ERR_PTR() in case of error. + * Creates and registers a USB4 port device for @port. + * + * Return: Pointer to &struct usb4_port or ERR_PTR() in case of an error. */ struct usb4_port *usb4_port_device_add(struct tb_port *port) { @@ -356,6 +357,8 @@ void usb4_port_device_remove(struct usb4_port *usb4) * @usb4: USB4 port device * * Used to resume USB4 port device after sleep state. + * + * Return: %0 on success, negative errno otherwise. */ int usb4_port_device_resume(struct usb4_port *usb4) { From 81a1962cb281636a95c49f02ef57d37deb6ceb8f Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:45 +0200 Subject: [PATCH 1581/2711] thunderbolt: Update xdomain.c function documentation Make xdomain.c function documentation compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- drivers/thunderbolt/xdomain.c | 46 +++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index fffa28cc491d..9d220ba544ec 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -160,7 +160,7 @@ static int __tb_xdomain_response(struct tb_ctl *ctl, const void *response, * This can be used to send a XDomain response message to the other * domain. No response for the message is expected. * - * Return: %0 in case of success and negative errno in case of failure + * Return: %0 on success, negative errno otherwise. */ int tb_xdomain_response(struct tb_xdomain *xd, const void *response, size_t size, enum tb_cfg_pkg_type type) @@ -212,7 +212,7 @@ static int __tb_xdomain_request(struct tb_ctl *ctl, const void *request, * the other domain. The function waits until the response is received * or when timeout triggers. Whichever comes first. * - * Return: %0 in case of success and negative errno in case of failure + * Return: %0 on success, negative errno otherwise. */ int tb_xdomain_request(struct tb_xdomain *xd, const void *request, size_t request_size, enum tb_cfg_pkg_type request_type, @@ -613,6 +613,8 @@ static int tb_xdp_link_state_change_response(struct tb_ctl *ctl, u64 route, * messages. After this function is called the service driver needs to * be able to handle calls to callback whenever a package with the * registered protocol is received. + * + * Return: %0 on success, negative errno otherwise. */ int tb_register_protocol_handler(struct tb_protocol_handler *handler) { @@ -877,6 +879,8 @@ tb_xdp_schedule_request(struct tb *tb, const struct tb_xdp_header *hdr, * @drv: Driver to register * * Registers new service driver from @drv to the bus. + * + * Return: %0 on success, negative errno otherwise. */ int tb_register_service_driver(struct tb_service_driver *drv) { @@ -1955,6 +1959,8 @@ static void tb_xdomain_link_exit(struct tb_xdomain *xd) * * Allocates new XDomain structure and returns pointer to that. The * object must be released by calling tb_xdomain_put(). + * + * Return: Pointer to &struct tb_xdomain, %NULL in case of failure. */ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent, u64 route, const uuid_t *local_uuid, @@ -2091,7 +2097,7 @@ void tb_xdomain_remove(struct tb_xdomain *xd) * to enable bonding by first enabling the port and waiting for the CL0 * state. * - * Return: %0 in case of success and negative errno in case of error. + * Return: %0 on success, negative errno otherwise. */ int tb_xdomain_lane_bonding_enable(struct tb_xdomain *xd) { @@ -2171,10 +2177,14 @@ EXPORT_SYMBOL_GPL(tb_xdomain_lane_bonding_disable); * @xd: XDomain connection * @hopid: Preferred HopID or %-1 for next available * - * Returns allocated HopID or negative errno. Specifically returns - * %-ENOSPC if there are no more available HopIDs. Returned HopID is - * guaranteed to be within range supported by the input lane adapter. + * Returned HopID is guaranteed to be within range supported by the input + * lane adapter. * Call tb_xdomain_release_in_hopid() to release the allocated HopID. + * + * Return: + * * Allocated HopID - On success. + * * %-ENOSPC - If there are no more available HopIDs. + * * Negative errno - Another error occurred. */ int tb_xdomain_alloc_in_hopid(struct tb_xdomain *xd, int hopid) { @@ -2193,10 +2203,14 @@ EXPORT_SYMBOL_GPL(tb_xdomain_alloc_in_hopid); * @xd: XDomain connection * @hopid: Preferred HopID or %-1 for next available * - * Returns allocated HopID or negative errno. Specifically returns - * %-ENOSPC if there are no more available HopIDs. Returned HopID is - * guaranteed to be within range supported by the output lane adapter. - * Call tb_xdomain_release_in_hopid() to release the allocated HopID. + * Returned HopID is guaranteed to be within range supported by the + * output lane adapter. + * Call tb_xdomain_release_out_hopid() to release the allocated HopID. + * + * Return: + * * Allocated HopID - On success. + * * %-ENOSPC - If there are no more available HopIDs. + * * Negative errno - Another error occurred. */ int tb_xdomain_alloc_out_hopid(struct tb_xdomain *xd, int hopid) { @@ -2245,7 +2259,7 @@ EXPORT_SYMBOL_GPL(tb_xdomain_release_out_hopid); * path. If a transmit or receive path is not needed, pass %-1 for those * parameters. * - * Return: %0 in case of success and negative errno in case of error + * Return: %0 on success, negative errno otherwise. */ int tb_xdomain_enable_paths(struct tb_xdomain *xd, int transmit_path, int transmit_ring, int receive_path, @@ -2270,7 +2284,7 @@ EXPORT_SYMBOL_GPL(tb_xdomain_enable_paths); * as path/ring parameter means don't care. Normally the callers should * pass the same values here as they do when paths are enabled. * - * Return: %0 in case of success and negative errno in case of error + * Return: %0 on success, negative errno otherwise. */ int tb_xdomain_disable_paths(struct tb_xdomain *xd, int transmit_path, int transmit_ring, int receive_path, @@ -2335,6 +2349,8 @@ static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw, * to the bus (handshake is still in progress). * * The caller needs to hold @tb->lock. + * + * Return: Pointer to &struct tb_xdomain or %NULL if not found. */ struct tb_xdomain *tb_xdomain_find_by_uuid(struct tb *tb, const uuid_t *uuid) { @@ -2364,6 +2380,8 @@ EXPORT_SYMBOL_GPL(tb_xdomain_find_by_uuid); * to the bus (handshake is still in progress). * * The caller needs to hold @tb->lock. + * + * Return: Pointer to &struct tb_xdomain or %NULL if not found. */ struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, u8 depth) @@ -2393,6 +2411,8 @@ struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, * to the bus (handshake is still in progress). * * The caller needs to hold @tb->lock. + * + * Return: Pointer to &struct tb_xdomain or %NULL if not found. */ struct tb_xdomain *tb_xdomain_find_by_route(struct tb *tb, u64 route) { @@ -2491,7 +2511,7 @@ static bool remove_directory(const char *key, const struct tb_property_dir *dir) * notified so they can re-read properties of this host if they are * interested. * - * Return: %0 on success and negative errno on failure + * Return: %0 on success, negative errno otherwise. */ int tb_register_property_dir(const char *key, struct tb_property_dir *dir) { From ea6bb47fd6a4c5a332f9349c39bf7462e3e7a35b Mon Sep 17 00:00:00 2001 From: Alan Borzeszkowski Date: Wed, 27 Aug 2025 13:56:46 +0200 Subject: [PATCH 1582/2711] thunderbolt: Update thunderbolt.h header file Make Thunderbolt header file compliant with current kernel-doc standards. No functional changes. Signed-off-by: Alan Borzeszkowski Signed-off-by: Mika Westerberg --- include/linux/thunderbolt.h | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h index 75247486616b..0ba112175bb3 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -213,7 +213,7 @@ enum tb_link_width { * queried first * @service_ids: Used to generate IDs for the services * @in_hopids: Input HopIDs for DMA tunneling - * @out_hopids; Output HopIDs for DMA tunneling + * @out_hopids: Output HopIDs for DMA tunneling * @local_property_block: Local block of properties * @local_property_block_gen: Generation of @local_property_block * @local_property_block_len: Length of the @local_property_block in dwords @@ -356,7 +356,7 @@ int tb_xdomain_request(struct tb_xdomain *xd, const void *request, unsigned int timeout_msec); /** - * tb_protocol_handler - Protocol specific handler + * struct tb_protocol_handler - Protocol specific handler * @uuid: XDomain messages with this UUID are dispatched to this handler * @callback: Callback called with the XDomain message. Returning %1 * here tells the XDomain core that the message was handled @@ -437,7 +437,7 @@ static inline struct tb_service *tb_to_service(struct device *dev) } /** - * tb_service_driver - Thunderbolt service driver + * struct tb_service_driver - Thunderbolt service driver * @driver: Driver structure * @probe: Called when the driver is probed * @remove: Called when the driver is removed (optional) @@ -519,6 +519,7 @@ struct tb_nhi { * @head: Head of the ring (write next descriptor here) * @tail: Tail of the ring (complete next descriptor here) * @descriptors: Allocated descriptors for this ring + * @descriptors_dma: DMA address of descriptors for this ring * @queue: Queue holding frames to be transferred over this ring * @in_flight: Queue holding frames that are currently in flight * @work: Interrupt work structure @@ -571,12 +572,12 @@ typedef void (*ring_cb)(struct tb_ring *, struct ring_frame *, bool canceled); /** * enum ring_desc_flags - Flags for DMA ring descriptor - * %RING_DESC_ISOCH: Enable isonchronous DMA (Tx only) - * %RING_DESC_CRC_ERROR: In frame mode CRC check failed for the frame (Rx only) - * %RING_DESC_COMPLETED: Descriptor completed (set by NHI) - * %RING_DESC_POSTED: Always set this - * %RING_DESC_BUFFER_OVERRUN: RX buffer overrun - * %RING_DESC_INTERRUPT: Request an interrupt on completion + * @RING_DESC_ISOCH: Enable isonchronous DMA (Tx only) + * @RING_DESC_CRC_ERROR: In frame mode CRC check failed for the frame (Rx only) + * @RING_DESC_COMPLETED: Descriptor completed (set by NHI) + * @RING_DESC_POSTED: Always set this + * @RING_DESC_BUFFER_OVERRUN: RX buffer overrun + * @RING_DESC_INTERRUPT: Request an interrupt on completion */ enum ring_desc_flags { RING_DESC_ISOCH = 0x1, @@ -636,7 +637,7 @@ int __tb_ring_enqueue(struct tb_ring *ring, struct ring_frame *frame); * If ring_stop() is called after the packet has been enqueued * @frame->callback will be called with canceled set to true. * - * Return: Returns %-ESHUTDOWN if ring_stop has been called. Zero otherwise. + * Return: %-ESHUTDOWN if ring_stop() has been called, %0 otherwise. */ static inline int tb_ring_rx(struct tb_ring *ring, struct ring_frame *frame) { @@ -657,7 +658,7 @@ static inline int tb_ring_rx(struct tb_ring *ring, struct ring_frame *frame) * If ring_stop() is called after the packet has been enqueued @frame->callback * will be called with canceled set to true. * - * Return: Returns %-ESHUTDOWN if ring_stop has been called. Zero otherwise. + * Return: %-ESHUTDOWN if ring_stop has been called, %0 otherwise. */ static inline int tb_ring_tx(struct tb_ring *ring, struct ring_frame *frame) { @@ -675,6 +676,8 @@ void tb_ring_poll_complete(struct tb_ring *ring); * * Use this function when you are mapping DMA for buffers that are * passed to the ring for sending/receiving. + * + * Return: Pointer to device used for DMA mapping. */ static inline struct device *tb_ring_dma_device(struct tb_ring *ring) { From 0d52aafb8bcee01b11ec8f3b46050540585431eb Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:45 +0300 Subject: [PATCH 1583/2711] HID: playstation: Make use of bitfield macros Improve code readability and make it more robust by replacing open coded bit operations with the equivalent bitfield macros. While at it, also fix the vertical alignment for some of the bitfield constants. Signed-off-by: Cristian Ciocaltea Reviewed-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 77 ++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 1468fb11e39d..79190147fa00 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -5,6 +5,7 @@ * Copyright (c) 2020-2022 Sony Interactive Entertainment */ +#include #include #include #include @@ -111,34 +112,45 @@ struct ps_led_info { #define DS_BUTTONS2_MIC_MUTE BIT(2) /* Status field of DualSense input report. */ -#define DS_STATUS_BATTERY_CAPACITY GENMASK(3, 0) -#define DS_STATUS_CHARGING GENMASK(7, 4) -#define DS_STATUS_CHARGING_SHIFT 4 +#define DS_STATUS_BATTERY_CAPACITY GENMASK(3, 0) +#define DS_STATUS_CHARGING GENMASK(7, 4) /* Feature version from DualSense Firmware Info report. */ -#define DS_FEATURE_VERSION(major, minor) ((major & 0xff) << 8 | (minor & 0xff)) - +#define DS_FEATURE_VERSION_MINOR GENMASK(7, 0) +#define DS_FEATURE_VERSION_MAJOR GENMASK(15, 8) +#define DS_FEATURE_VERSION(major, minor) (FIELD_PREP(DS_FEATURE_VERSION_MAJOR, major) | \ + FIELD_PREP(DS_FEATURE_VERSION_MINOR, minor)) /* * Status of a DualSense touch point contact. * Contact IDs, with highest bit set are 'inactive' * and any associated data is then invalid. */ -#define DS_TOUCH_POINT_INACTIVE BIT(7) +#define DS_TOUCH_POINT_INACTIVE BIT(7) +#define DS_TOUCH_POINT_X_LO GENMASK(7, 0) +#define DS_TOUCH_POINT_X_HI GENMASK(11, 8) +#define DS_TOUCH_POINT_X(hi, lo) (FIELD_PREP(DS_TOUCH_POINT_X_HI, hi) | \ + FIELD_PREP(DS_TOUCH_POINT_X_LO, lo)) +#define DS_TOUCH_POINT_Y_LO GENMASK(3, 0) +#define DS_TOUCH_POINT_Y_HI GENMASK(11, 4) +#define DS_TOUCH_POINT_Y(hi, lo) (FIELD_PREP(DS_TOUCH_POINT_Y_HI, hi) | \ + FIELD_PREP(DS_TOUCH_POINT_Y_LO, lo)) /* Magic value required in tag field of Bluetooth output report. */ -#define DS_OUTPUT_TAG 0x10 +#define DS_OUTPUT_TAG 0x10 +#define DS_OUTPUT_SEQ_TAG GENMASK(3, 0) +#define DS_OUTPUT_SEQ_NO GENMASK(7, 4) /* Flags for DualSense output report. */ -#define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0) -#define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1) -#define DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE BIT(0) -#define DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE BIT(1) -#define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2) -#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3) -#define DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE BIT(4) -#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1) -#define DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2 BIT(2) -#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4) -#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1) +#define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0) +#define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1) +#define DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE BIT(0) +#define DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE BIT(1) +#define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2) +#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3) +#define DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE BIT(4) +#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1) +#define DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2 BIT(2) +#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4) +#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1) /* DualSense hardware limits */ #define DS_ACC_RES_PER_G 8192 @@ -315,7 +327,9 @@ struct dualsense_output_report { * Contact IDs, with highest bit set are 'inactive' * and any associated data is then invalid. */ -#define DS4_TOUCH_POINT_INACTIVE BIT(7) +#define DS4_TOUCH_POINT_INACTIVE BIT(7) +#define DS4_TOUCH_POINT_X(hi, lo) DS_TOUCH_POINT_X(hi, lo) +#define DS4_TOUCH_POINT_Y(hi, lo) DS_TOUCH_POINT_Y(hi, lo) /* Status field of DualShock4 input report. */ #define DS4_STATUS0_BATTERY_CAPACITY GENMASK(3, 0) @@ -1194,7 +1208,8 @@ static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_ * Highest 4-bit is a sequence number, which needs to be increased * every report. Lowest 4-bit is tag and can be zero for now. */ - bt->seq_tag = (ds->output_seq << 4) | 0x0; + bt->seq_tag = FIELD_PREP(DS_OUTPUT_SEQ_NO, ds->output_seq) | + FIELD_PREP(DS_OUTPUT_SEQ_TAG, 0x0); if (++ds->output_seq == 16) ds->output_seq = 0; @@ -1439,19 +1454,18 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r input_mt_report_slot_state(ds->touchpad, MT_TOOL_FINGER, active); if (active) { - int x = (point->x_hi << 8) | point->x_lo; - int y = (point->y_hi << 4) | point->y_lo; - - input_report_abs(ds->touchpad, ABS_MT_POSITION_X, x); - input_report_abs(ds->touchpad, ABS_MT_POSITION_Y, y); + input_report_abs(ds->touchpad, ABS_MT_POSITION_X, + DS_TOUCH_POINT_X(point->x_hi, point->x_lo)); + input_report_abs(ds->touchpad, ABS_MT_POSITION_Y, + DS_TOUCH_POINT_Y(point->y_hi, point->y_lo)); } } input_mt_sync_frame(ds->touchpad); input_report_key(ds->touchpad, BTN_LEFT, ds_report->buttons[2] & DS_BUTTONS2_TOUCHPAD); input_sync(ds->touchpad); - battery_data = ds_report->status & DS_STATUS_BATTERY_CAPACITY; - charging_status = (ds_report->status & DS_STATUS_CHARGING) >> DS_STATUS_CHARGING_SHIFT; + battery_data = FIELD_GET(DS_STATUS_BATTERY_CAPACITY, ds_report->status); + charging_status = FIELD_GET(DS_STATUS_CHARGING, ds_report->status); switch (charging_status) { case 0x0: @@ -2351,11 +2365,10 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * input_mt_report_slot_state(ds4->touchpad, MT_TOOL_FINGER, active); if (active) { - int x = (point->x_hi << 8) | point->x_lo; - int y = (point->y_hi << 4) | point->y_lo; - - input_report_abs(ds4->touchpad, ABS_MT_POSITION_X, x); - input_report_abs(ds4->touchpad, ABS_MT_POSITION_Y, y); + input_report_abs(ds4->touchpad, ABS_MT_POSITION_X, + DS4_TOUCH_POINT_X(point->x_hi, point->x_lo)); + input_report_abs(ds4->touchpad, ABS_MT_POSITION_Y, + DS4_TOUCH_POINT_Y(point->y_hi, point->y_lo)); } } input_mt_sync_frame(ds4->touchpad); From 6c6af4c4dfd3ca734b3507361476ec1774dca477 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:46 +0300 Subject: [PATCH 1584/2711] HID: playstation: Add spaces around arithmetic operators Get rid of several checkpatch.pl complaints: CHECK: spaces preferred around that '*' (ctx:VxV) CHECK: spaces preferred around that '/' (ctx:VxV) Signed-off-by: Cristian Ciocaltea Reviewed-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 42 ++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 79190147fa00..799b47cdfe03 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -154,9 +154,9 @@ struct ps_led_info { /* DualSense hardware limits */ #define DS_ACC_RES_PER_G 8192 -#define DS_ACC_RANGE (4*DS_ACC_RES_PER_G) +#define DS_ACC_RANGE (4 * DS_ACC_RES_PER_G) #define DS_GYRO_RES_PER_DEG_S 1024 -#define DS_GYRO_RANGE (2048*DS_GYRO_RES_PER_DEG_S) +#define DS_GYRO_RANGE (2048 * DS_GYRO_RES_PER_DEG_S) #define DS_TOUCHPAD_WIDTH 1920 #define DS_TOUCHPAD_HEIGHT 1080 @@ -363,9 +363,9 @@ struct dualsense_output_report { /* DualShock4 hardware limits */ #define DS4_ACC_RES_PER_G 8192 -#define DS4_ACC_RANGE (4*DS_ACC_RES_PER_G) +#define DS4_ACC_RANGE (4 * DS_ACC_RES_PER_G) #define DS4_GYRO_RES_PER_DEG_S 1024 -#define DS4_GYRO_RANGE (2048*DS_GYRO_RES_PER_DEG_S) +#define DS4_GYRO_RANGE (2048 * DS_GYRO_RES_PER_DEG_S) #define DS4_LIGHTBAR_MAX_BLINK 255 /* 255 centiseconds */ #define DS4_TOUCHPAD_WIDTH 1920 #define DS4_TOUCHPAD_HEIGHT 942 @@ -1015,19 +1015,19 @@ static int dualsense_get_calibration_data(struct dualsense *ds) speed_2x = (gyro_speed_plus + gyro_speed_minus); ds->gyro_calib_data[0].abs_code = ABS_RX; ds->gyro_calib_data[0].bias = 0; - ds->gyro_calib_data[0].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; + ds->gyro_calib_data[0].sens_numer = speed_2x * DS_GYRO_RES_PER_DEG_S; ds->gyro_calib_data[0].sens_denom = abs(gyro_pitch_plus - gyro_pitch_bias) + abs(gyro_pitch_minus - gyro_pitch_bias); ds->gyro_calib_data[1].abs_code = ABS_RY; ds->gyro_calib_data[1].bias = 0; - ds->gyro_calib_data[1].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; + ds->gyro_calib_data[1].sens_numer = speed_2x * DS_GYRO_RES_PER_DEG_S; ds->gyro_calib_data[1].sens_denom = abs(gyro_yaw_plus - gyro_yaw_bias) + abs(gyro_yaw_minus - gyro_yaw_bias); ds->gyro_calib_data[2].abs_code = ABS_RZ; ds->gyro_calib_data[2].bias = 0; - ds->gyro_calib_data[2].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; + ds->gyro_calib_data[2].sens_numer = speed_2x * DS_GYRO_RES_PER_DEG_S; ds->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) + abs(gyro_roll_minus - gyro_roll_bias); @@ -1053,19 +1053,19 @@ static int dualsense_get_calibration_data(struct dualsense *ds) range_2g = acc_x_plus - acc_x_minus; ds->accel_calib_data[0].abs_code = ABS_X; ds->accel_calib_data[0].bias = acc_x_plus - range_2g / 2; - ds->accel_calib_data[0].sens_numer = 2*DS_ACC_RES_PER_G; + ds->accel_calib_data[0].sens_numer = 2 * DS_ACC_RES_PER_G; ds->accel_calib_data[0].sens_denom = range_2g; range_2g = acc_y_plus - acc_y_minus; ds->accel_calib_data[1].abs_code = ABS_Y; ds->accel_calib_data[1].bias = acc_y_plus - range_2g / 2; - ds->accel_calib_data[1].sens_numer = 2*DS_ACC_RES_PER_G; + ds->accel_calib_data[1].sens_numer = 2 * DS_ACC_RES_PER_G; ds->accel_calib_data[1].sens_denom = range_2g; range_2g = acc_z_plus - acc_z_minus; ds->accel_calib_data[2].abs_code = ABS_Z; ds->accel_calib_data[2].bias = acc_z_plus - range_2g / 2; - ds->accel_calib_data[2].sens_numer = 2*DS_ACC_RES_PER_G; + ds->accel_calib_data[2].sens_numer = 2 * DS_ACC_RES_PER_G; ds->accel_calib_data[2].sens_denom = range_2g; /* @@ -1881,19 +1881,19 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) speed_2x = (gyro_speed_plus + gyro_speed_minus); ds4->gyro_calib_data[0].abs_code = ABS_RX; ds4->gyro_calib_data[0].bias = 0; - ds4->gyro_calib_data[0].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + ds4->gyro_calib_data[0].sens_numer = speed_2x * DS4_GYRO_RES_PER_DEG_S; ds4->gyro_calib_data[0].sens_denom = abs(gyro_pitch_plus - gyro_pitch_bias) + abs(gyro_pitch_minus - gyro_pitch_bias); ds4->gyro_calib_data[1].abs_code = ABS_RY; ds4->gyro_calib_data[1].bias = 0; - ds4->gyro_calib_data[1].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + ds4->gyro_calib_data[1].sens_numer = speed_2x * DS4_GYRO_RES_PER_DEG_S; ds4->gyro_calib_data[1].sens_denom = abs(gyro_yaw_plus - gyro_yaw_bias) + abs(gyro_yaw_minus - gyro_yaw_bias); ds4->gyro_calib_data[2].abs_code = ABS_RZ; ds4->gyro_calib_data[2].bias = 0; - ds4->gyro_calib_data[2].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + ds4->gyro_calib_data[2].sens_numer = speed_2x * DS4_GYRO_RES_PER_DEG_S; ds4->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) + abs(gyro_roll_minus - gyro_roll_bias); @@ -1904,19 +1904,19 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) range_2g = acc_x_plus - acc_x_minus; ds4->accel_calib_data[0].abs_code = ABS_X; ds4->accel_calib_data[0].bias = acc_x_plus - range_2g / 2; - ds4->accel_calib_data[0].sens_numer = 2*DS4_ACC_RES_PER_G; + ds4->accel_calib_data[0].sens_numer = 2 * DS4_ACC_RES_PER_G; ds4->accel_calib_data[0].sens_denom = range_2g; range_2g = acc_y_plus - acc_y_minus; ds4->accel_calib_data[1].abs_code = ABS_Y; ds4->accel_calib_data[1].bias = acc_y_plus - range_2g / 2; - ds4->accel_calib_data[1].sens_numer = 2*DS4_ACC_RES_PER_G; + ds4->accel_calib_data[1].sens_numer = 2 * DS4_ACC_RES_PER_G; ds4->accel_calib_data[1].sens_denom = range_2g; range_2g = acc_z_plus - acc_z_minus; ds4->accel_calib_data[2].abs_code = ABS_Z; ds4->accel_calib_data[2].bias = acc_z_plus - range_2g / 2; - ds4->accel_calib_data[2].sens_numer = 2*DS4_ACC_RES_PER_G; + ds4->accel_calib_data[2].sens_numer = 2 * DS4_ACC_RES_PER_G; ds4->accel_calib_data[2].sens_denom = range_2g; transfer_failed: @@ -2058,8 +2058,10 @@ static int dualshock4_led_set_blink(struct led_classdev *led, unsigned long *del ds4->lightbar_blink_off = 50; } else { /* Blink delays in centiseconds. */ - ds4->lightbar_blink_on = min_t(unsigned long, *delay_on/10, DS4_LIGHTBAR_MAX_BLINK); - ds4->lightbar_blink_off = min_t(unsigned long, *delay_off/10, DS4_LIGHTBAR_MAX_BLINK); + ds4->lightbar_blink_on = min_t(unsigned long, *delay_on / 10, + DS4_LIGHTBAR_MAX_BLINK); + ds4->lightbar_blink_off = min_t(unsigned long, *delay_off / 10, + DS4_LIGHTBAR_MAX_BLINK); } ds4->update_lightbar_blink = true; @@ -2339,7 +2341,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * /* Convert timestamp (in 5.33us unit) to timestamp_us */ sensor_timestamp = le16_to_cpu(ds4_report->sensor_timestamp); if (!ds4->sensor_timestamp_initialized) { - ds4->sensor_timestamp_us = DIV_ROUND_CLOSEST(sensor_timestamp*16, 3); + ds4->sensor_timestamp_us = DIV_ROUND_CLOSEST(sensor_timestamp * 16, 3); ds4->sensor_timestamp_initialized = true; } else { uint16_t delta; @@ -2348,7 +2350,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * delta = (U16_MAX - ds4->prev_sensor_timestamp + sensor_timestamp + 1); else delta = sensor_timestamp - ds4->prev_sensor_timestamp; - ds4->sensor_timestamp_us += DIV_ROUND_CLOSEST(delta*16, 3); + ds4->sensor_timestamp_us += DIV_ROUND_CLOSEST(delta * 16, 3); } ds4->prev_sensor_timestamp = sensor_timestamp; input_event(ds4->sensors, EV_MSC, MSC_TIMESTAMP, ds4->sensor_timestamp_us); From a38d070ffe338710037f6a45767542ce249c61a0 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:47 +0300 Subject: [PATCH 1585/2711] HID: playstation: Simplify locking with guard() and scoped_guard() Use guard() and scoped_guard() infrastructure instead of explicitly acquiring and releasing spinlocks and mutexes to simplify the code and ensure that all locks are released properly. Signed-off-by: Cristian Ciocaltea Reviewed-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 214 +++++++++++++++------------------- 1 file changed, 92 insertions(+), 122 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 799b47cdfe03..ab3a0c505c4d 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -566,26 +567,25 @@ static int ps_devices_list_add(struct ps_device *dev) { struct ps_device *entry; - mutex_lock(&ps_devices_lock); + guard(mutex)(&ps_devices_lock); + list_for_each_entry(entry, &ps_devices_list, list) { if (!memcmp(entry->mac_address, dev->mac_address, sizeof(dev->mac_address))) { hid_err(dev->hdev, "Duplicate device found for MAC address %pMR.\n", dev->mac_address); - mutex_unlock(&ps_devices_lock); return -EEXIST; } } list_add_tail(&dev->list, &ps_devices_list); - mutex_unlock(&ps_devices_lock); return 0; } static int ps_devices_list_remove(struct ps_device *dev) { - mutex_lock(&ps_devices_lock); + guard(mutex)(&ps_devices_lock); + list_del(&dev->list); - mutex_unlock(&ps_devices_lock); return 0; } @@ -649,13 +649,12 @@ static int ps_battery_get_property(struct power_supply *psy, struct ps_device *dev = power_supply_get_drvdata(psy); uint8_t battery_capacity; int battery_status; - unsigned long flags; int ret = 0; - spin_lock_irqsave(&dev->lock, flags); - battery_capacity = dev->battery_capacity; - battery_status = dev->battery_status; - spin_unlock_irqrestore(&dev->lock, flags); + scoped_guard(spinlock_irqsave, &dev->lock) { + battery_capacity = dev->battery_capacity; + battery_status = dev->battery_status; + } switch (psp) { case POWER_SUPPLY_PROP_STATUS: @@ -1173,19 +1172,17 @@ static int dualsense_player_led_set_brightness(struct led_classdev *led, enum le { struct hid_device *hdev = to_hid_device(led->dev->parent); struct dualsense *ds = hid_get_drvdata(hdev); - unsigned long flags; unsigned int led_index; - spin_lock_irqsave(&ds->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds->base.lock) { + led_index = led - ds->player_leds; + if (value == LED_OFF) + ds->player_leds_state &= ~BIT(led_index); + else + ds->player_leds_state |= BIT(led_index); - led_index = led - ds->player_leds; - if (value == LED_OFF) - ds->player_leds_state &= ~BIT(led_index); - else - ds->player_leds_state |= BIT(led_index); - - ds->update_player_leds = true; - spin_unlock_irqrestore(&ds->base.lock, flags); + ds->update_player_leds = true; + } dualsense_schedule_work(ds); @@ -1234,12 +1231,9 @@ static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_ static inline void dualsense_schedule_work(struct dualsense *ds) { - unsigned long flags; - - spin_lock_irqsave(&ds->base.lock, flags); + guard(spinlock_irqsave)(&ds->base.lock); if (ds->output_worker_initialized) schedule_work(&ds->output_worker); - spin_unlock_irqrestore(&ds->base.lock, flags); } /* @@ -1337,7 +1331,6 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r int battery_status; uint32_t sensor_timestamp; bool btn_mic_state; - unsigned long flags; int i; /* @@ -1399,10 +1392,10 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r */ btn_mic_state = !!(ds_report->buttons[2] & DS_BUTTONS2_MIC_MUTE); if (btn_mic_state && !ds->last_btn_mic_state) { - spin_lock_irqsave(&ps_dev->lock, flags); - ds->update_mic_mute = true; - ds->mic_muted = !ds->mic_muted; /* toggle */ - spin_unlock_irqrestore(&ps_dev->lock, flags); + scoped_guard(spinlock_irqsave, &ps_dev->lock) { + ds->update_mic_mute = true; + ds->mic_muted = !ds->mic_muted; /* toggle */ + } /* Schedule updating of microphone state at hardware level. */ dualsense_schedule_work(ds); @@ -1495,10 +1488,10 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r battery_status = POWER_SUPPLY_STATUS_UNKNOWN; } - spin_lock_irqsave(&ps_dev->lock, flags); - ps_dev->battery_capacity = battery_capacity; - ps_dev->battery_status = battery_status; - spin_unlock_irqrestore(&ps_dev->lock, flags); + scoped_guard(spinlock_irqsave, &ps_dev->lock) { + ps_dev->battery_capacity = battery_capacity; + ps_dev->battery_status = battery_status; + } return 0; } @@ -1507,16 +1500,15 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef { struct hid_device *hdev = input_get_drvdata(dev); struct dualsense *ds = hid_get_drvdata(hdev); - unsigned long flags; if (effect->type != FF_RUMBLE) return 0; - spin_lock_irqsave(&ds->base.lock, flags); - ds->update_rumble = true; - ds->motor_left = effect->u.rumble.strong_magnitude / 256; - ds->motor_right = effect->u.rumble.weak_magnitude / 256; - spin_unlock_irqrestore(&ds->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds->base.lock) { + ds->update_rumble = true; + ds->motor_left = effect->u.rumble.strong_magnitude / 256; + ds->motor_right = effect->u.rumble.weak_magnitude / 256; + } dualsense_schedule_work(ds); return 0; @@ -1525,11 +1517,9 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef static void dualsense_remove(struct ps_device *ps_dev) { struct dualsense *ds = container_of(ps_dev, struct dualsense, base); - unsigned long flags; - spin_lock_irqsave(&ds->base.lock, flags); - ds->output_worker_initialized = false; - spin_unlock_irqrestore(&ds->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds->base.lock) + ds->output_worker_initialized = false; cancel_work_sync(&ds->output_worker); } @@ -1561,14 +1551,12 @@ static int dualsense_reset_leds(struct dualsense *ds) static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue) { - unsigned long flags; - - spin_lock_irqsave(&ds->base.lock, flags); - ds->update_lightbar = true; - ds->lightbar_red = red; - ds->lightbar_green = green; - ds->lightbar_blue = blue; - spin_unlock_irqrestore(&ds->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds->base.lock) { + ds->update_lightbar = true; + ds->lightbar_red = red; + ds->lightbar_green = green; + ds->lightbar_blue = blue; + } dualsense_schedule_work(ds); } @@ -1755,7 +1743,6 @@ err: static void dualshock4_dongle_calibration_work(struct work_struct *work) { struct dualshock4 *ds4 = container_of(work, struct dualshock4, dongle_hotplug_worker); - unsigned long flags; enum dualshock4_dongle_state dongle_state; int ret; @@ -1774,9 +1761,8 @@ static void dualshock4_dongle_calibration_work(struct work_struct *work) dongle_state = DONGLE_CONNECTED; } - spin_lock_irqsave(&ds4->base.lock, flags); - ds4->dongle_state = dongle_state; - spin_unlock_irqrestore(&ds4->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds4->base.lock) + ds4->dongle_state = dongle_state; } static int dualshock4_get_calibration_data(struct dualshock4 *ds4) @@ -2048,26 +2034,23 @@ static int dualshock4_led_set_blink(struct led_classdev *led, unsigned long *del { struct hid_device *hdev = to_hid_device(led->dev->parent); struct dualshock4 *ds4 = hid_get_drvdata(hdev); - unsigned long flags; - spin_lock_irqsave(&ds4->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds4->base.lock) { + if (!*delay_on && !*delay_off) { + /* Default to 1 Hz (50 centiseconds on, 50 centiseconds off). */ + ds4->lightbar_blink_on = 50; + ds4->lightbar_blink_off = 50; + } else { + /* Blink delays in centiseconds. */ + ds4->lightbar_blink_on = min_t(unsigned long, *delay_on / 10, + DS4_LIGHTBAR_MAX_BLINK); + ds4->lightbar_blink_off = min_t(unsigned long, *delay_off / 10, + DS4_LIGHTBAR_MAX_BLINK); + } - if (!*delay_on && !*delay_off) { - /* Default to 1 Hz (50 centiseconds on, 50 centiseconds off). */ - ds4->lightbar_blink_on = 50; - ds4->lightbar_blink_off = 50; - } else { - /* Blink delays in centiseconds. */ - ds4->lightbar_blink_on = min_t(unsigned long, *delay_on / 10, - DS4_LIGHTBAR_MAX_BLINK); - ds4->lightbar_blink_off = min_t(unsigned long, *delay_off / 10, - DS4_LIGHTBAR_MAX_BLINK); + ds4->update_lightbar_blink = true; } - ds4->update_lightbar_blink = true; - - spin_unlock_irqrestore(&ds4->base.lock, flags); - dualshock4_schedule_work(ds4); /* Report scaled values back to LED subsystem */ @@ -2081,37 +2064,34 @@ static int dualshock4_led_set_brightness(struct led_classdev *led, enum led_brig { struct hid_device *hdev = to_hid_device(led->dev->parent); struct dualshock4 *ds4 = hid_get_drvdata(hdev); - unsigned long flags; unsigned int led_index; - spin_lock_irqsave(&ds4->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds4->base.lock) { + led_index = led - ds4->lightbar_leds; + switch (led_index) { + case 0: + ds4->lightbar_red = value; + break; + case 1: + ds4->lightbar_green = value; + break; + case 2: + ds4->lightbar_blue = value; + break; + case 3: + ds4->lightbar_enabled = !!value; - led_index = led - ds4->lightbar_leds; - switch (led_index) { - case 0: - ds4->lightbar_red = value; - break; - case 1: - ds4->lightbar_green = value; - break; - case 2: - ds4->lightbar_blue = value; - break; - case 3: - ds4->lightbar_enabled = !!value; - - /* brightness = 0 also cancels blinking in Linux. */ - if (!ds4->lightbar_enabled) { - ds4->lightbar_blink_off = 0; - ds4->lightbar_blink_on = 0; - ds4->update_lightbar_blink = true; + /* brightness = 0 also cancels blinking in Linux. */ + if (!ds4->lightbar_enabled) { + ds4->lightbar_blink_off = 0; + ds4->lightbar_blink_on = 0; + ds4->update_lightbar_blink = true; + } } + + ds4->update_lightbar = true; } - ds4->update_lightbar = true; - - spin_unlock_irqrestore(&ds4->base.lock, flags); - dualshock4_schedule_work(ds4); return 0; @@ -2242,7 +2222,6 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * uint8_t battery_capacity, num_touch_reports, value; int battery_status, i, j; uint16_t sensor_timestamp; - unsigned long flags; bool is_minimal = false; /* @@ -2420,10 +2399,10 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * battery_status = POWER_SUPPLY_STATUS_DISCHARGING; } - spin_lock_irqsave(&ps_dev->lock, flags); - ps_dev->battery_capacity = battery_capacity; - ps_dev->battery_status = battery_status; - spin_unlock_irqrestore(&ps_dev->lock, flags); + scoped_guard(spinlock_irqsave, &ps_dev->lock) { + ps_dev->battery_capacity = battery_capacity; + ps_dev->battery_status = battery_status; + } return 0; } @@ -2441,7 +2420,6 @@ static int dualshock4_dongle_parse_report(struct ps_device *ps_dev, struct hid_r */ if (data[0] == DS4_INPUT_REPORT_USB && size == DS4_INPUT_REPORT_USB_SIZE) { struct dualshock4_input_report_common *ds4_report = (struct dualshock4_input_report_common *)&data[1]; - unsigned long flags; connected = ds4_report->status[1] & DS4_STATUS1_DONGLE_STATE ? false : true; @@ -2450,9 +2428,8 @@ static int dualshock4_dongle_parse_report(struct ps_device *ps_dev, struct hid_r dualshock4_set_default_lightbar_colors(ds4); - spin_lock_irqsave(&ps_dev->lock, flags); - ds4->dongle_state = DONGLE_CALIBRATING; - spin_unlock_irqrestore(&ps_dev->lock, flags); + scoped_guard(spinlock_irqsave, &ps_dev->lock) + ds4->dongle_state = DONGLE_CALIBRATING; schedule_work(&ds4->dongle_hotplug_worker); @@ -2464,9 +2441,8 @@ static int dualshock4_dongle_parse_report(struct ps_device *ps_dev, struct hid_r ds4->dongle_state == DONGLE_DISABLED) && !connected) { hid_info(ps_dev->hdev, "DualShock 4 USB dongle: controller disconnected\n"); - spin_lock_irqsave(&ps_dev->lock, flags); - ds4->dongle_state = DONGLE_DISCONNECTED; - spin_unlock_irqrestore(&ps_dev->lock, flags); + scoped_guard(spinlock_irqsave, &ps_dev->lock) + ds4->dongle_state = DONGLE_DISCONNECTED; /* Return 0, so hidraw can get the report. */ return 0; @@ -2488,16 +2464,15 @@ static int dualshock4_play_effect(struct input_dev *dev, void *data, struct ff_e { struct hid_device *hdev = input_get_drvdata(dev); struct dualshock4 *ds4 = hid_get_drvdata(hdev); - unsigned long flags; if (effect->type != FF_RUMBLE) return 0; - spin_lock_irqsave(&ds4->base.lock, flags); - ds4->update_rumble = true; - ds4->motor_left = effect->u.rumble.strong_magnitude / 256; - ds4->motor_right = effect->u.rumble.weak_magnitude / 256; - spin_unlock_irqrestore(&ds4->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds4->base.lock) { + ds4->update_rumble = true; + ds4->motor_left = effect->u.rumble.strong_magnitude / 256; + ds4->motor_right = effect->u.rumble.weak_magnitude / 256; + } dualshock4_schedule_work(ds4); return 0; @@ -2506,11 +2481,9 @@ static int dualshock4_play_effect(struct input_dev *dev, void *data, struct ff_e static void dualshock4_remove(struct ps_device *ps_dev) { struct dualshock4 *ds4 = container_of(ps_dev, struct dualshock4, base); - unsigned long flags; - spin_lock_irqsave(&ds4->base.lock, flags); - ds4->output_worker_initialized = false; - spin_unlock_irqrestore(&ds4->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds4->base.lock) + ds4->output_worker_initialized = false; cancel_work_sync(&ds4->output_worker); @@ -2520,12 +2493,9 @@ static void dualshock4_remove(struct ps_device *ps_dev) static inline void dualshock4_schedule_work(struct dualshock4 *ds4) { - unsigned long flags; - - spin_lock_irqsave(&ds4->base.lock, flags); + guard(spinlock_irqsave)(&ds4->base.lock); if (ds4->output_worker_initialized) schedule_work(&ds4->output_worker); - spin_unlock_irqrestore(&ds4->base.lock, flags); } static void dualshock4_set_bt_poll_interval(struct dualshock4 *ds4, uint8_t interval) From 134a40c9d6d9bf27a6743e65eebdb81985880712 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:48 +0300 Subject: [PATCH 1586/2711] HID: playstation: Replace uint{32,16,8}_t with u{32,16,8} And get rid of the following checkpatch.pl complaints: CHECK: Prefer kernel type 'u32' over 'uint32_t' CHECK: Prefer kernel type 'u16' over 'uint16_t' CHECK: Prefer kernel type 'u8' over 'uint8_t' Signed-off-by: Cristian Ciocaltea Reviewed-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 272 +++++++++++++++++----------------- 1 file changed, 136 insertions(+), 136 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index ab3a0c505c4d..78d28a0eb697 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -40,17 +40,17 @@ struct ps_device { struct hid_device *hdev; spinlock_t lock; - uint32_t player_id; + u32 player_id; struct power_supply_desc battery_desc; struct power_supply *battery; - uint8_t battery_capacity; + u8 battery_capacity; int battery_status; const char *input_dev_name; /* Name of primary input device. */ - uint8_t mac_address[6]; /* Note: stored in little endian order. */ - uint32_t hw_version; - uint32_t fw_version; + u8 mac_address[6]; /* Note: stored in little endian order. */ + u32 hw_version; + u32 fw_version; int (*parse_report)(struct ps_device *dev, struct hid_report *report, u8 *data, int size); void (*remove)(struct ps_device *dev); @@ -168,7 +168,7 @@ struct dualsense { struct input_dev *touchpad; /* Update version is used as a feature/capability version. */ - uint16_t update_version; + u16 update_version; /* Calibration data for accelerometer and gyroscope. */ struct ps_calibration_data accel_calib_data[3]; @@ -176,21 +176,21 @@ struct dualsense { /* Timestamp for sensor data */ bool sensor_timestamp_initialized; - uint32_t prev_sensor_timestamp; - uint32_t sensor_timestamp_us; + u32 prev_sensor_timestamp; + u32 sensor_timestamp_us; /* Compatible rumble state */ bool use_vibration_v2; bool update_rumble; - uint8_t motor_left; - uint8_t motor_right; + u8 motor_left; + u8 motor_right; /* RGB lightbar */ struct led_classdev_mc lightbar; bool update_lightbar; - uint8_t lightbar_red; - uint8_t lightbar_green; - uint8_t lightbar_blue; + u8 lightbar_red; + u8 lightbar_green; + u8 lightbar_blue; /* Microphone */ bool update_mic_mute; @@ -199,90 +199,90 @@ struct dualsense { /* Player leds */ bool update_player_leds; - uint8_t player_leds_state; + u8 player_leds_state; struct led_classdev player_leds[5]; struct work_struct output_worker; bool output_worker_initialized; void *output_report_dmabuf; - uint8_t output_seq; /* Sequence number for output report. */ + u8 output_seq; /* Sequence number for output report. */ }; struct dualsense_touch_point { - uint8_t contact; - uint8_t x_lo; - uint8_t x_hi:4, y_lo:4; - uint8_t y_hi; + u8 contact; + u8 x_lo; + u8 x_hi:4, y_lo:4; + u8 y_hi; } __packed; static_assert(sizeof(struct dualsense_touch_point) == 4); /* Main DualSense input report excluding any BT/USB specific headers. */ struct dualsense_input_report { - uint8_t x, y; - uint8_t rx, ry; - uint8_t z, rz; - uint8_t seq_number; - uint8_t buttons[4]; - uint8_t reserved[4]; + u8 x, y; + u8 rx, ry; + u8 z, rz; + u8 seq_number; + u8 buttons[4]; + u8 reserved[4]; /* Motion sensors */ __le16 gyro[3]; /* x, y, z */ __le16 accel[3]; /* x, y, z */ __le32 sensor_timestamp; - uint8_t reserved2; + u8 reserved2; /* Touchpad */ struct dualsense_touch_point points[2]; - uint8_t reserved3[12]; - uint8_t status; - uint8_t reserved4[10]; + u8 reserved3[12]; + u8 status; + u8 reserved4[10]; } __packed; /* Common input report size shared equals the size of the USB report minus 1 byte for ReportID. */ static_assert(sizeof(struct dualsense_input_report) == DS_INPUT_REPORT_USB_SIZE - 1); /* Common data between DualSense BT/USB main output report. */ struct dualsense_output_report_common { - uint8_t valid_flag0; - uint8_t valid_flag1; + u8 valid_flag0; + u8 valid_flag1; /* For DualShock 4 compatibility mode. */ - uint8_t motor_right; - uint8_t motor_left; + u8 motor_right; + u8 motor_left; /* Audio controls */ - uint8_t reserved[4]; - uint8_t mute_button_led; + u8 reserved[4]; + u8 mute_button_led; - uint8_t power_save_control; - uint8_t reserved2[28]; + u8 power_save_control; + u8 reserved2[28]; /* LEDs and lightbar */ - uint8_t valid_flag2; - uint8_t reserved3[2]; - uint8_t lightbar_setup; - uint8_t led_brightness; - uint8_t player_leds; - uint8_t lightbar_red; - uint8_t lightbar_green; - uint8_t lightbar_blue; + u8 valid_flag2; + u8 reserved3[2]; + u8 lightbar_setup; + u8 led_brightness; + u8 player_leds; + u8 lightbar_red; + u8 lightbar_green; + u8 lightbar_blue; } __packed; static_assert(sizeof(struct dualsense_output_report_common) == 47); struct dualsense_output_report_bt { - uint8_t report_id; /* 0x31 */ - uint8_t seq_tag; - uint8_t tag; + u8 report_id; /* 0x31 */ + u8 seq_tag; + u8 tag; struct dualsense_output_report_common common; - uint8_t reserved[24]; + u8 reserved[24]; __le32 crc32; } __packed; static_assert(sizeof(struct dualsense_output_report_bt) == DS_OUTPUT_REPORT_BT_SIZE); struct dualsense_output_report_usb { - uint8_t report_id; /* 0x02 */ + u8 report_id; /* 0x02 */ struct dualsense_output_report_common common; - uint8_t reserved[15]; + u8 reserved[15]; } __packed; static_assert(sizeof(struct dualsense_output_report_usb) == DS_OUTPUT_REPORT_USB_SIZE); @@ -292,8 +292,8 @@ static_assert(sizeof(struct dualsense_output_report_usb) == DS_OUTPUT_REPORT_USB * This structure hide the differences between the two to simplify sending output reports. */ struct dualsense_output_report { - uint8_t *data; /* Start of data */ - uint8_t len; /* Size of output report */ + u8 *data; /* Start of data */ + u8 len; /* Size of output report */ /* Points to Bluetooth data payload in case for a Bluetooth report else NULL. */ struct dualsense_output_report_bt *bt; @@ -395,26 +395,26 @@ struct dualshock4 { /* Timestamp for sensor data */ bool sensor_timestamp_initialized; - uint32_t prev_sensor_timestamp; - uint32_t sensor_timestamp_us; + u32 prev_sensor_timestamp; + u32 sensor_timestamp_us; /* Bluetooth poll interval */ bool update_bt_poll_interval; - uint8_t bt_poll_interval; + u8 bt_poll_interval; bool update_rumble; - uint8_t motor_left; - uint8_t motor_right; + u8 motor_left; + u8 motor_right; /* Lightbar leds */ bool update_lightbar; bool update_lightbar_blink; bool lightbar_enabled; /* For use by global LED control. */ - uint8_t lightbar_red; - uint8_t lightbar_green; - uint8_t lightbar_blue; - uint8_t lightbar_blink_on; /* In increments of 10ms. */ - uint8_t lightbar_blink_off; /* In increments of 10ms. */ + u8 lightbar_red; + u8 lightbar_green; + u8 lightbar_blue; + u8 lightbar_blink_on; /* In increments of 10ms. */ + u8 lightbar_blink_off; /* In increments of 10ms. */ struct led_classdev lightbar_leds[4]; struct work_struct output_worker; @@ -423,88 +423,88 @@ struct dualshock4 { }; struct dualshock4_touch_point { - uint8_t contact; - uint8_t x_lo; - uint8_t x_hi:4, y_lo:4; - uint8_t y_hi; + u8 contact; + u8 x_lo; + u8 x_hi:4, y_lo:4; + u8 y_hi; } __packed; static_assert(sizeof(struct dualshock4_touch_point) == 4); struct dualshock4_touch_report { - uint8_t timestamp; + u8 timestamp; struct dualshock4_touch_point points[2]; } __packed; static_assert(sizeof(struct dualshock4_touch_report) == 9); /* Main DualShock4 input report excluding any BT/USB specific headers. */ struct dualshock4_input_report_common { - uint8_t x, y; - uint8_t rx, ry; - uint8_t buttons[3]; - uint8_t z, rz; + u8 x, y; + u8 rx, ry; + u8 buttons[3]; + u8 z, rz; /* Motion sensors */ __le16 sensor_timestamp; - uint8_t sensor_temperature; + u8 sensor_temperature; __le16 gyro[3]; /* x, y, z */ __le16 accel[3]; /* x, y, z */ - uint8_t reserved2[5]; + u8 reserved2[5]; - uint8_t status[2]; - uint8_t reserved3; + u8 status[2]; + u8 reserved3; } __packed; static_assert(sizeof(struct dualshock4_input_report_common) == 32); struct dualshock4_input_report_usb { - uint8_t report_id; /* 0x01 */ + u8 report_id; /* 0x01 */ struct dualshock4_input_report_common common; - uint8_t num_touch_reports; + u8 num_touch_reports; struct dualshock4_touch_report touch_reports[3]; - uint8_t reserved[3]; + u8 reserved[3]; } __packed; static_assert(sizeof(struct dualshock4_input_report_usb) == DS4_INPUT_REPORT_USB_SIZE); struct dualshock4_input_report_bt { - uint8_t report_id; /* 0x11 */ - uint8_t reserved[2]; + u8 report_id; /* 0x11 */ + u8 reserved[2]; struct dualshock4_input_report_common common; - uint8_t num_touch_reports; + u8 num_touch_reports; struct dualshock4_touch_report touch_reports[4]; /* BT has 4 compared to 3 for USB */ - uint8_t reserved2[2]; + u8 reserved2[2]; __le32 crc32; } __packed; static_assert(sizeof(struct dualshock4_input_report_bt) == DS4_INPUT_REPORT_BT_SIZE); /* Common data between Bluetooth and USB DualShock4 output reports. */ struct dualshock4_output_report_common { - uint8_t valid_flag0; - uint8_t valid_flag1; + u8 valid_flag0; + u8 valid_flag1; - uint8_t reserved; + u8 reserved; - uint8_t motor_right; - uint8_t motor_left; + u8 motor_right; + u8 motor_left; - uint8_t lightbar_red; - uint8_t lightbar_green; - uint8_t lightbar_blue; - uint8_t lightbar_blink_on; - uint8_t lightbar_blink_off; + u8 lightbar_red; + u8 lightbar_green; + u8 lightbar_blue; + u8 lightbar_blink_on; + u8 lightbar_blink_off; } __packed; struct dualshock4_output_report_usb { - uint8_t report_id; /* 0x5 */ + u8 report_id; /* 0x5 */ struct dualshock4_output_report_common common; - uint8_t reserved[21]; + u8 reserved[21]; } __packed; static_assert(sizeof(struct dualshock4_output_report_usb) == DS4_OUTPUT_REPORT_USB_SIZE); struct dualshock4_output_report_bt { - uint8_t report_id; /* 0x11 */ - uint8_t hw_control; - uint8_t audio_control; + u8 report_id; /* 0x11 */ + u8 hw_control; + u8 audio_control; struct dualshock4_output_report_common common; - uint8_t reserved[61]; + u8 reserved[61]; __le32 crc32; } __packed; static_assert(sizeof(struct dualshock4_output_report_bt) == DS4_OUTPUT_REPORT_BT_SIZE); @@ -515,8 +515,8 @@ static_assert(sizeof(struct dualshock4_output_report_bt) == DS4_OUTPUT_REPORT_BT * This structure hide the differences between the two to simplify sending output reports. */ struct dualshock4_output_report { - uint8_t *data; /* Start of data */ - uint8_t len; /* Size of output report */ + u8 *data; /* Start of data */ + u8 len; /* Size of output report */ /* Points to Bluetooth data payload in case for a Bluetooth report else NULL. */ struct dualshock4_output_report_bt *bt; @@ -555,7 +555,7 @@ static const struct {int x; int y; } ps_gamepad_hat_mapping[] = { static int dualshock4_get_calibration_data(struct dualshock4 *ds4); static inline void dualsense_schedule_work(struct dualsense *ds); static inline void dualshock4_schedule_work(struct dualshock4 *ds4); -static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue); +static void dualsense_set_lightbar(struct dualsense *ds, u8 red, u8 green, u8 blue); static void dualshock4_set_default_lightbar_colors(struct dualshock4 *ds4); /* @@ -647,7 +647,7 @@ static int ps_battery_get_property(struct power_supply *psy, union power_supply_propval *val) { struct ps_device *dev = power_supply_get_drvdata(psy); - uint8_t battery_capacity; + u8 battery_capacity; int battery_status; int ret = 0; @@ -710,9 +710,9 @@ static int ps_device_register_battery(struct ps_device *dev) } /* Compute crc32 of HID data and compare against expected CRC. */ -static bool ps_check_crc32(uint8_t seed, uint8_t *data, size_t len, uint32_t report_crc) +static bool ps_check_crc32(u8 seed, u8 *data, size_t len, u32 report_crc) { - uint32_t crc; + u32 crc; crc = crc32_le(0xFFFFFFFF, &seed, 1); crc = ~crc32_le(crc, data, len); @@ -758,7 +758,7 @@ static struct input_dev *ps_gamepad_create(struct hid_device *hdev, return gamepad; } -static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *buf, size_t size, +static int ps_get_report(struct hid_device *hdev, u8 report_id, u8 *buf, size_t size, bool check_crc) { int ret; @@ -782,8 +782,8 @@ static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *bu if (hdev->bus == BUS_BLUETOOTH && check_crc) { /* Last 4 bytes contains crc32. */ - uint8_t crc_offset = size - 4; - uint32_t report_crc = get_unaligned_le32(&buf[crc_offset]); + u8 crc_offset = size - 4; + u32 report_crc = get_unaligned_le32(&buf[crc_offset]); if (!ps_check_crc32(PS_FEATURE_CRC32_SEED, buf, crc_offset, report_crc)) { hid_err(hdev, "CRC check failed for reportID=%d\n", report_id); @@ -976,7 +976,7 @@ static int dualsense_get_calibration_data(struct dualsense *ds) int range_2g; int ret = 0; int i; - uint8_t *buf; + u8 *buf; buf = kzalloc(DS_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL); if (!buf) @@ -1090,7 +1090,7 @@ err_free: static int dualsense_get_firmware_info(struct dualsense *ds) { - uint8_t *buf; + u8 *buf; int ret; buf = kzalloc(DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE, GFP_KERNEL); @@ -1123,7 +1123,7 @@ err_free: static int dualsense_get_mac_address(struct dualsense *ds) { - uint8_t *buf; + u8 *buf; int ret = 0; buf = kzalloc(DS_FEATURE_REPORT_PAIRING_INFO_SIZE, GFP_KERNEL); @@ -1149,7 +1149,7 @@ static int dualsense_lightbar_set_brightness(struct led_classdev *cdev, { struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); struct dualsense *ds = container_of(mc_cdev, struct dualsense, lightbar); - uint8_t red, green, blue; + u8 red, green, blue; led_mc_calc_color_components(mc_cdev, brightness); red = mc_cdev->subled_info[0].brightness; @@ -1247,8 +1247,8 @@ static void dualsense_send_output_report(struct dualsense *ds, /* Bluetooth packets need to be signed with a CRC in the last 4 bytes. */ if (report->bt) { - uint32_t crc; - uint8_t seed = PS_OUTPUT_CRC32_SEED; + u32 crc; + u8 seed = PS_OUTPUT_CRC32_SEED; crc = crc32_le(0xFFFFFFFF, &seed, 1); crc = ~crc32_le(crc, report->data, report->len - 4); @@ -1327,9 +1327,9 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r struct hid_device *hdev = ps_dev->hdev; struct dualsense *ds = container_of(ps_dev, struct dualsense, base); struct dualsense_input_report *ds_report; - uint8_t battery_data, battery_capacity, charging_status, value; + u8 battery_data, battery_capacity, charging_status, value; int battery_status; - uint32_t sensor_timestamp; + u32 sensor_timestamp; bool btn_mic_state; int i; @@ -1344,7 +1344,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r } else if (hdev->bus == BUS_BLUETOOTH && report->id == DS_INPUT_REPORT_BT && size == DS_INPUT_REPORT_BT_SIZE) { /* Last 4 bytes of input report contain crc32 */ - uint32_t report_crc = get_unaligned_le32(&data[size - 4]); + u32 report_crc = get_unaligned_le32(&data[size - 4]); if (!ps_check_crc32(PS_INPUT_CRC32_SEED, data, size - 4, report_crc)) { hid_err(hdev, "DualSense input CRC's check failed\n"); @@ -1427,7 +1427,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r ds->sensor_timestamp_us = DIV_ROUND_CLOSEST(sensor_timestamp, 3); ds->sensor_timestamp_initialized = true; } else { - uint32_t delta; + u32 delta; if (ds->prev_sensor_timestamp > sensor_timestamp) delta = (U32_MAX - ds->prev_sensor_timestamp + sensor_timestamp + 1); @@ -1527,7 +1527,7 @@ static void dualsense_remove(struct ps_device *ps_dev) static int dualsense_reset_leds(struct dualsense *ds) { struct dualsense_output_report report; - uint8_t *buf; + u8 *buf; buf = kzalloc(sizeof(struct dualsense_output_report_bt), GFP_KERNEL); if (!buf) @@ -1549,7 +1549,7 @@ static int dualsense_reset_leds(struct dualsense *ds) return 0; } -static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue) +static void dualsense_set_lightbar(struct dualsense *ds, u8 red, u8 green, u8 blue) { scoped_guard(spinlock_irqsave, &ds->base.lock) { ds->update_lightbar = true; @@ -1577,7 +1577,7 @@ static void dualsense_set_player_leds(struct dualsense *ds) BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0) }; - uint8_t player_id = ds->base.player_id % ARRAY_SIZE(player_ids); + u8 player_id = ds->base.player_id % ARRAY_SIZE(player_ids); ds->update_player_leds = true; ds->player_leds_state = player_ids[player_id]; @@ -1588,7 +1588,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) { struct dualsense *ds; struct ps_device *ps_dev; - uint8_t max_output_report_size; + u8 max_output_report_size; int i, ret; static const struct ps_led_info player_leds_info[] = { @@ -1779,7 +1779,7 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) int range_2g; int ret = 0; int i; - uint8_t *buf; + u8 *buf; if (ds4->base.hdev->bus == BUS_USB) { int retries; @@ -1943,7 +1943,7 @@ transfer_failed: static int dualshock4_get_firmware_info(struct dualshock4 *ds4) { - uint8_t *buf; + u8 *buf; int ret; buf = kzalloc(DS4_FEATURE_REPORT_FIRMWARE_INFO_SIZE, GFP_KERNEL); @@ -1971,7 +1971,7 @@ err_free: static int dualshock4_get_mac_address(struct dualshock4 *ds4) { struct hid_device *hdev = ds4->base.hdev; - uint8_t *buf; + u8 *buf; int ret = 0; if (hdev->bus == BUS_USB) { @@ -2190,8 +2190,8 @@ static void dualshock4_output_worker(struct work_struct *work) /* Bluetooth packets need additional flags as well as a CRC in the last 4 bytes. */ if (report.bt) { - uint32_t crc; - uint8_t seed = PS_OUTPUT_CRC32_SEED; + u32 crc; + u8 seed = PS_OUTPUT_CRC32_SEED; /* Hardware control flags need to set to let the device know * there is HID data as well as CRC. @@ -2219,9 +2219,9 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * struct dualshock4 *ds4 = container_of(ps_dev, struct dualshock4, base); struct dualshock4_input_report_common *ds4_report; struct dualshock4_touch_report *touch_reports; - uint8_t battery_capacity, num_touch_reports, value; + u8 battery_capacity, num_touch_reports, value; int battery_status, i, j; - uint16_t sensor_timestamp; + u16 sensor_timestamp; bool is_minimal = false; /* @@ -2239,7 +2239,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * } else if (hdev->bus == BUS_BLUETOOTH && report->id == DS4_INPUT_REPORT_BT && size == DS4_INPUT_REPORT_BT_SIZE) { struct dualshock4_input_report_bt *bt = (struct dualshock4_input_report_bt *)data; - uint32_t report_crc = get_unaligned_le32(&bt->crc32); + u32 report_crc = get_unaligned_le32(&bt->crc32); /* Last 4 bytes of input report contains CRC. */ if (!ps_check_crc32(PS_INPUT_CRC32_SEED, data, size - 4, report_crc)) { @@ -2323,7 +2323,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * ds4->sensor_timestamp_us = DIV_ROUND_CLOSEST(sensor_timestamp * 16, 3); ds4->sensor_timestamp_initialized = true; } else { - uint16_t delta; + u16 delta; if (ds4->prev_sensor_timestamp > sensor_timestamp) delta = (U16_MAX - ds4->prev_sensor_timestamp + sensor_timestamp + 1); @@ -2368,7 +2368,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * * - 15: charge error */ if (ds4_report->status[0] & DS4_STATUS0_CABLE_STATE) { - uint8_t battery_data = ds4_report->status[0] & DS4_STATUS0_BATTERY_CAPACITY; + u8 battery_data = ds4_report->status[0] & DS4_STATUS0_BATTERY_CAPACITY; if (battery_data < 10) { /* Take the mid-point for each battery capacity value, @@ -2389,7 +2389,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * battery_status = POWER_SUPPLY_STATUS_UNKNOWN; } } else { - uint8_t battery_data = ds4_report->status[0] & DS4_STATUS0_BATTERY_CAPACITY; + u8 battery_data = ds4_report->status[0] & DS4_STATUS0_BATTERY_CAPACITY; if (battery_data < 10) battery_capacity = battery_data * 10 + 5; @@ -2498,7 +2498,7 @@ static inline void dualshock4_schedule_work(struct dualshock4 *ds4) schedule_work(&ds4->output_worker); } -static void dualshock4_set_bt_poll_interval(struct dualshock4 *ds4, uint8_t interval) +static void dualshock4_set_bt_poll_interval(struct dualshock4 *ds4, u8 interval) { ds4->bt_poll_interval = interval; ds4->update_bt_poll_interval = true; @@ -2518,7 +2518,7 @@ static void dualshock4_set_default_lightbar_colors(struct dualshock4 *ds4) { 0x20, 0x00, 0x20 } /* Pink */ }; - uint8_t player_id = ds4->base.player_id % ARRAY_SIZE(player_colors); + u8 player_id = ds4->base.player_id % ARRAY_SIZE(player_colors); ds4->lightbar_enabled = true; ds4->lightbar_red = player_colors[player_id][0]; @@ -2533,7 +2533,7 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) { struct dualshock4 *ds4; struct ps_device *ps_dev; - uint8_t max_output_report_size; + u8 max_output_report_size; int i, ret; /* The DualShock4 has an RGB lightbar, which the original hid-sony driver From 70db9aa76d29663047a84f337091f438be3c8a4f Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:49 +0300 Subject: [PATCH 1587/2711] HID: playstation: Correct spelling in comment sections Handle a couple of spelling complaints from checkpatch.pl: CHECK: 'connectd' may be misspelled - perhaps 'connected'? CHECK: 'Comptabile' may be misspelled - perhaps 'Compatible'? Signed-off-by: Cristian Ciocaltea Reviewed-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 78d28a0eb697..349d6cac964a 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -338,7 +338,7 @@ struct dualsense_output_report { /* Battery status within batery_status field. */ #define DS4_BATTERY_STATUS_FULL 11 /* Status1 bit2 contains dongle connection state: - * 0 = connectd + * 0 = connected * 1 = disconnected */ #define DS4_STATUS1_DONGLE_STATE BIT(2) @@ -2169,7 +2169,7 @@ static void dualshock4_output_worker(struct work_struct *work) if (ds4->update_lightbar) { common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED; - /* Comptabile behavior with hid-sony, which used a dummy global LED to + /* Compatible behavior with hid-sony, which used a dummy global LED to * allow enabling/disabling the lightbar. The global LED maps to * lightbar_enabled. */ From 56d7f285bfaa38fad082c1b50e20c1b57b2a8e18 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:50 +0300 Subject: [PATCH 1588/2711] HID: playstation: Fix all alignment and line length issues Format code to address the following checkpatch.pl reports: CHECK: Alignment should match open parenthesis CHECK: line length of exceeds 100 columns CHECK: Please don't use multiple blank lines Signed-off-by: Cristian Ciocaltea Reviewed-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 163 +++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 74 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 349d6cac964a..811b0b90c0e2 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -572,7 +572,7 @@ static int ps_devices_list_add(struct ps_device *dev) list_for_each_entry(entry, &ps_devices_list, list) { if (!memcmp(entry->mac_address, dev->mac_address, sizeof(dev->mac_address))) { hid_err(dev->hdev, "Duplicate device found for MAC address %pMR.\n", - dev->mac_address); + dev->mac_address); return -EEXIST; } } @@ -607,7 +607,8 @@ static void ps_device_release_player_id(struct ps_device *dev) dev->player_id = U32_MAX; } -static struct input_dev *ps_allocate_input_dev(struct hid_device *hdev, const char *name_suffix) +static struct input_dev *ps_allocate_input_dev(struct hid_device *hdev, + const char *name_suffix) { struct input_dev *input_dev; @@ -622,8 +623,8 @@ static struct input_dev *ps_allocate_input_dev(struct hid_device *hdev, const ch input_dev->uniq = hdev->uniq; if (name_suffix) { - input_dev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s %s", hdev->name, - name_suffix); + input_dev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s %s", + hdev->name, name_suffix); if (!input_dev->name) return ERR_PTR(-ENOMEM); } else { @@ -643,8 +644,8 @@ static enum power_supply_property ps_power_supply_props[] = { }; static int ps_battery_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) + enum power_supply_property psp, + union power_supply_propval *val) { struct ps_device *dev = power_supply_get_drvdata(psy); u8 battery_capacity; @@ -688,7 +689,7 @@ static int ps_device_register_battery(struct ps_device *dev) dev->battery_desc.num_properties = ARRAY_SIZE(ps_power_supply_props); dev->battery_desc.get_property = ps_battery_get_property; dev->battery_desc.name = devm_kasprintf(&dev->hdev->dev, GFP_KERNEL, - "ps-controller-battery-%pMR", dev->mac_address); + "ps-controller-battery-%pMR", dev->mac_address); if (!dev->battery_desc.name) return -ENOMEM; @@ -720,8 +721,9 @@ static bool ps_check_crc32(u8 seed, u8 *data, size_t len, u32 report_crc) return crc == report_crc; } -static struct input_dev *ps_gamepad_create(struct hid_device *hdev, - int (*play_effect)(struct input_dev *, void *, struct ff_effect *)) +static struct input_dev * +ps_gamepad_create(struct hid_device *hdev, + int (*play_effect)(struct input_dev *, void *, struct ff_effect *)) { struct input_dev *gamepad; unsigned int i; @@ -758,8 +760,8 @@ static struct input_dev *ps_gamepad_create(struct hid_device *hdev, return gamepad; } -static int ps_get_report(struct hid_device *hdev, u8 report_id, u8 *buf, size_t size, - bool check_crc) +static int ps_get_report(struct hid_device *hdev, u8 report_id, u8 *buf, + size_t size, bool check_crc) { int ret; @@ -795,17 +797,20 @@ static int ps_get_report(struct hid_device *hdev, u8 report_id, u8 *buf, size_t } static int ps_led_register(struct ps_device *ps_dev, struct led_classdev *led, - const struct ps_led_info *led_info) + const struct ps_led_info *led_info) { int ret; if (led_info->name) { - led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL, - "%s:%s:%s", ps_dev->input_dev_name, led_info->color, led_info->name); + led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL, "%s:%s:%s", + ps_dev->input_dev_name, led_info->color, + led_info->name); } else { - /* Backwards compatible mode for hid-sony, but not compliant with LED class spec. */ - led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL, - "%s:%s", ps_dev->input_dev_name, led_info->color); + /* Backwards compatible mode for hid-sony, but not compliant + * with LED class spec. + */ + led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL, "%s:%s", + ps_dev->input_dev_name, led_info->color); } if (!led->name) @@ -829,7 +834,7 @@ static int ps_led_register(struct ps_device *ps_dev, struct led_classdev *led, /* Register a DualSense/DualShock4 RGB lightbar represented by a multicolor LED. */ static int ps_lightbar_register(struct ps_device *ps_dev, struct led_classdev_mc *lightbar_mc_dev, - int (*brightness_set)(struct led_classdev *, enum led_brightness)) + int (*brightness_set)(struct led_classdev *, enum led_brightness)) { struct hid_device *hdev = ps_dev->hdev; struct mc_subled *mc_led_info; @@ -850,7 +855,7 @@ static int ps_lightbar_register(struct ps_device *ps_dev, struct led_classdev_mc led_cdev = &lightbar_mc_dev->led_cdev; led_cdev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s:rgb:indicator", - ps_dev->input_dev_name); + ps_dev->input_dev_name); if (!led_cdev->name) return -ENOMEM; led_cdev->brightness = 255; @@ -866,8 +871,8 @@ static int ps_lightbar_register(struct ps_device *ps_dev, struct led_classdev_mc return 0; } -static struct input_dev *ps_sensors_create(struct hid_device *hdev, int accel_range, int accel_res, - int gyro_range, int gyro_res) +static struct input_dev *ps_sensors_create(struct hid_device *hdev, int accel_range, + int accel_res, int gyro_range, int gyro_res) { struct input_dev *sensors; int ret; @@ -903,8 +908,8 @@ static struct input_dev *ps_sensors_create(struct hid_device *hdev, int accel_ra return sensors; } -static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width, int height, - unsigned int num_contacts) +static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width, + int height, unsigned int num_contacts) { struct input_dev *touchpad; int ret; @@ -932,8 +937,7 @@ static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width, } static ssize_t firmware_version_show(struct device *dev, - struct device_attribute - *attr, char *buf) + struct device_attribute *attr, char *buf) { struct hid_device *hdev = to_hid_device(dev); struct ps_device *ps_dev = hid_get_drvdata(hdev); @@ -944,8 +948,7 @@ static ssize_t firmware_version_show(struct device *dev, static DEVICE_ATTR_RO(firmware_version); static ssize_t hardware_version_show(struct device *dev, - struct device_attribute - *attr, char *buf) + struct device_attribute *attr, char *buf) { struct hid_device *hdev = to_hid_device(dev); struct ps_device *ps_dev = hid_get_drvdata(hdev); @@ -983,7 +986,7 @@ static int dualsense_get_calibration_data(struct dualsense *ds) return -ENOMEM; ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_CALIBRATION, buf, - DS_FEATURE_REPORT_CALIBRATION_SIZE, true); + DS_FEATURE_REPORT_CALIBRATION_SIZE, true); if (ret) { hid_err(ds->base.hdev, "Failed to retrieve DualSense calibration info: %d\n", ret); goto err_free; @@ -1037,8 +1040,9 @@ static int dualsense_get_calibration_data(struct dualsense *ds) */ for (i = 0; i < ARRAY_SIZE(ds->gyro_calib_data); i++) { if (ds->gyro_calib_data[i].sens_denom == 0) { - hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.", - ds->gyro_calib_data[i].abs_code); + hid_warn(hdev, + "Invalid gyro calibration data for axis (%d), disabling calibration.", + ds->gyro_calib_data[i].abs_code); ds->gyro_calib_data[i].bias = 0; ds->gyro_calib_data[i].sens_numer = DS_GYRO_RANGE; ds->gyro_calib_data[i].sens_denom = S16_MAX; @@ -1074,8 +1078,9 @@ static int dualsense_get_calibration_data(struct dualsense *ds) */ for (i = 0; i < ARRAY_SIZE(ds->accel_calib_data); i++) { if (ds->accel_calib_data[i].sens_denom == 0) { - hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.", - ds->accel_calib_data[i].abs_code); + hid_warn(hdev, + "Invalid accelerometer calibration data for axis (%d), disabling calibration.", + ds->accel_calib_data[i].abs_code); ds->accel_calib_data[i].bias = 0; ds->accel_calib_data[i].sens_numer = DS_ACC_RANGE; ds->accel_calib_data[i].sens_denom = S16_MAX; @@ -1087,7 +1092,6 @@ err_free: return ret; } - static int dualsense_get_firmware_info(struct dualsense *ds) { u8 *buf; @@ -1098,7 +1102,7 @@ static int dualsense_get_firmware_info(struct dualsense *ds) return -ENOMEM; ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_FIRMWARE_INFO, buf, - DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE, true); + DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE, true); if (ret) { hid_err(ds->base.hdev, "Failed to retrieve DualSense firmware info: %d\n", ret); goto err_free; @@ -1131,7 +1135,7 @@ static int dualsense_get_mac_address(struct dualsense *ds) return -ENOMEM; ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_PAIRING_INFO, buf, - DS_FEATURE_REPORT_PAIRING_INFO_SIZE, true); + DS_FEATURE_REPORT_PAIRING_INFO_SIZE, true); if (ret) { hid_err(ds->base.hdev, "Failed to retrieve DualSense pairing info: %d\n", ret); goto err_free; @@ -1145,7 +1149,7 @@ err_free: } static int dualsense_lightbar_set_brightness(struct led_classdev *cdev, - enum led_brightness brightness) + enum led_brightness brightness) { struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); struct dualsense *ds = container_of(mc_cdev, struct dualsense, lightbar); @@ -1189,8 +1193,8 @@ static int dualsense_player_led_set_brightness(struct led_classdev *led, enum le return 0; } -static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_output_report *rp, - void *buf) +static void dualsense_init_output_report(struct dualsense *ds, + struct dualsense_output_report *rp, void *buf) { struct hid_device *hdev = ds->base.hdev; @@ -1241,7 +1245,7 @@ static inline void dualsense_schedule_work(struct dualsense *ds) * for Bluetooth reports. */ static void dualsense_send_output_report(struct dualsense *ds, - struct dualsense_output_report *report) + struct dualsense_output_report *report) { struct hid_device *hdev = ds->base.hdev; @@ -1322,7 +1326,7 @@ static void dualsense_output_worker(struct work_struct *work) } static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *report, - u8 *data, int size) + u8 *data, int size) { struct hid_device *hdev = ps_dev->hdev; struct dualsense *ds = container_of(ps_dev, struct dualsense, base); @@ -1339,10 +1343,10 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r * the full report using reportID 49. */ if (hdev->bus == BUS_USB && report->id == DS_INPUT_REPORT_USB && - size == DS_INPUT_REPORT_USB_SIZE) { + size == DS_INPUT_REPORT_USB_SIZE) { ds_report = (struct dualsense_input_report *)&data[1]; } else if (hdev->bus == BUS_BLUETOOTH && report->id == DS_INPUT_REPORT_BT && - size == DS_INPUT_REPORT_BT_SIZE) { + size == DS_INPUT_REPORT_BT_SIZE) { /* Last 4 bytes of input report contain crc32 */ u32 report_crc = get_unaligned_le32(&data[size - 4]); @@ -1677,7 +1681,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) ps_dev->input_dev_name = dev_name(&ds->gamepad->dev); ds->sensors = ps_sensors_create(hdev, DS_ACC_RANGE, DS_ACC_RES_PER_G, - DS_GYRO_RANGE, DS_GYRO_RES_PER_DEG_S); + DS_GYRO_RANGE, DS_GYRO_RES_PER_DEG_S); if (IS_ERR(ds->sensors)) { ret = PTR_ERR(ds->sensors); goto err; @@ -1731,7 +1735,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) * can change behavior. */ hid_info(hdev, "Registered DualSense controller hw_version=0x%08x fw_version=0x%08x\n", - ds->base.hw_version, ds->base.fw_version); + ds->base.hw_version, ds->base.fw_version); return &ds->base; @@ -1754,7 +1758,8 @@ static void dualshock4_dongle_calibration_work(struct work_struct *work) * DS4 hotplug is detect from sony_raw_event as any issues * are likely resolved then (the dongle is quite stupid). */ - hid_err(ds4->base.hdev, "DualShock 4 USB dongle: calibration failed, disabling device\n"); + hid_err(ds4->base.hdev, + "DualShock 4 USB dongle: calibration failed, disabling device\n"); dongle_state = DONGLE_DISABLED; } else { hid_info(ds4->base.hdev, "DualShock 4 USB dongle: calibration completed\n"); @@ -1798,14 +1803,17 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) */ for (retries = 0; retries < 3; retries++) { ret = ps_get_report(hdev, DS4_FEATURE_REPORT_CALIBRATION, buf, - DS4_FEATURE_REPORT_CALIBRATION_SIZE, true); + DS4_FEATURE_REPORT_CALIBRATION_SIZE, true); if (ret) { if (retries < 2) { - hid_warn(hdev, "Retrying DualShock 4 get calibration report (0x02) request\n"); + hid_warn(hdev, + "Retrying DualShock 4 get calibration report (0x02) request\n"); continue; } - hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); + hid_warn(hdev, + "Failed to retrieve DualShock4 calibration info: %d\n", + ret); ret = -EILSEQ; goto transfer_failed; } else { @@ -1820,7 +1828,7 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) } ret = ps_get_report(hdev, DS4_FEATURE_REPORT_CALIBRATION_BT, buf, - DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, true); + DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, true); if (ret) { hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); @@ -1914,8 +1922,9 @@ transfer_failed: for (i = 0; i < ARRAY_SIZE(ds4->gyro_calib_data); i++) { if (ds4->gyro_calib_data[i].sens_denom == 0) { ds4->gyro_calib_data[i].abs_code = ABS_RX + i; - hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.", - ds4->gyro_calib_data[i].abs_code); + hid_warn(hdev, + "Invalid gyro calibration data for axis (%d), disabling calibration.", + ds4->gyro_calib_data[i].abs_code); ds4->gyro_calib_data[i].bias = 0; ds4->gyro_calib_data[i].sens_numer = DS4_GYRO_RANGE; ds4->gyro_calib_data[i].sens_denom = S16_MAX; @@ -1930,8 +1939,9 @@ transfer_failed: for (i = 0; i < ARRAY_SIZE(ds4->accel_calib_data); i++) { if (ds4->accel_calib_data[i].sens_denom == 0) { ds4->accel_calib_data[i].abs_code = ABS_X + i; - hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.", - ds4->accel_calib_data[i].abs_code); + hid_warn(hdev, + "Invalid accelerometer calibration data for axis (%d), disabling calibration.", + ds4->accel_calib_data[i].abs_code); ds4->accel_calib_data[i].bias = 0; ds4->accel_calib_data[i].sens_numer = DS4_ACC_RANGE; ds4->accel_calib_data[i].sens_denom = S16_MAX; @@ -1954,7 +1964,7 @@ static int dualshock4_get_firmware_info(struct dualshock4 *ds4) * lacks CRC support, so must be disabled in ps_get_report. */ ret = ps_get_report(ds4->base.hdev, DS4_FEATURE_REPORT_FIRMWARE_INFO, buf, - DS4_FEATURE_REPORT_FIRMWARE_INFO_SIZE, false); + DS4_FEATURE_REPORT_FIRMWARE_INFO_SIZE, false); if (ret) { hid_err(ds4->base.hdev, "Failed to retrieve DualShock4 firmware info: %d\n", ret); goto err_free; @@ -1980,7 +1990,7 @@ static int dualshock4_get_mac_address(struct dualshock4 *ds4) return -ENOMEM; ret = ps_get_report(hdev, DS4_FEATURE_REPORT_PAIRING_INFO, buf, - DS4_FEATURE_REPORT_PAIRING_INFO_SIZE, false); + DS4_FEATURE_REPORT_PAIRING_INFO_SIZE, false); if (ret) { hid_err(hdev, "Failed to retrieve DualShock4 pairing info: %d\n", ret); goto err_free; @@ -1993,9 +2003,9 @@ static int dualshock4_get_mac_address(struct dualshock4 *ds4) return -EINVAL; ret = sscanf(hdev->uniq, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - &ds4->base.mac_address[5], &ds4->base.mac_address[4], - &ds4->base.mac_address[3], &ds4->base.mac_address[2], - &ds4->base.mac_address[1], &ds4->base.mac_address[0]); + &ds4->base.mac_address[5], &ds4->base.mac_address[4], + &ds4->base.mac_address[3], &ds4->base.mac_address[2], + &ds4->base.mac_address[1], &ds4->base.mac_address[0]); if (ret != sizeof(ds4->base.mac_address)) return -EINVAL; @@ -2030,7 +2040,7 @@ static enum led_brightness dualshock4_led_get_brightness(struct led_classdev *le } static int dualshock4_led_set_blink(struct led_classdev *led, unsigned long *delay_on, - unsigned long *delay_off) + unsigned long *delay_off) { struct hid_device *hdev = to_hid_device(led->dev->parent); struct dualshock4 *ds4 = hid_get_drvdata(hdev); @@ -2098,7 +2108,7 @@ static int dualshock4_led_set_brightness(struct led_classdev *led, enum led_brig } static void dualshock4_init_output_report(struct dualshock4 *ds4, - struct dualshock4_output_report *rp, void *buf) + struct dualshock4_output_report *rp, void *buf) { struct hid_device *hdev = ds4->base.hdev; @@ -2213,7 +2223,7 @@ static void dualshock4_output_worker(struct work_struct *work) } static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *report, - u8 *data, int size) + u8 *data, int size) { struct hid_device *hdev = ps_dev->hdev; struct dualshock4 *ds4 = container_of(ps_dev, struct dualshock4, base); @@ -2230,14 +2240,15 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * * the full report using reportID 17. */ if (hdev->bus == BUS_USB && report->id == DS4_INPUT_REPORT_USB && - size == DS4_INPUT_REPORT_USB_SIZE) { - struct dualshock4_input_report_usb *usb = (struct dualshock4_input_report_usb *)data; + size == DS4_INPUT_REPORT_USB_SIZE) { + struct dualshock4_input_report_usb *usb = + (struct dualshock4_input_report_usb *)data; ds4_report = &usb->common; num_touch_reports = usb->num_touch_reports; touch_reports = usb->touch_reports; } else if (hdev->bus == BUS_BLUETOOTH && report->id == DS4_INPUT_REPORT_BT && - size == DS4_INPUT_REPORT_BT_SIZE) { + size == DS4_INPUT_REPORT_BT_SIZE) { struct dualshock4_input_report_bt *bt = (struct dualshock4_input_report_bt *)data; u32 report_crc = get_unaligned_le32(&bt->crc32); @@ -2408,7 +2419,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * } static int dualshock4_dongle_parse_report(struct ps_device *ps_dev, struct hid_report *report, - u8 *data, int size) + u8 *data, int size) { struct dualshock4 *ds4 = container_of(ps_dev, struct dualshock4, base); bool connected = false; @@ -2419,7 +2430,8 @@ static int dualshock4_dongle_parse_report(struct ps_device *ps_dev, struct hid_r * parsing code. */ if (data[0] == DS4_INPUT_REPORT_USB && size == DS4_INPUT_REPORT_USB_SIZE) { - struct dualshock4_input_report_common *ds4_report = (struct dualshock4_input_report_common *)&data[1]; + struct dualshock4_input_report_common *ds4_report = + (struct dualshock4_input_report_common *)&data[1]; connected = ds4_report->status[1] & DS4_STATUS1_DONGLE_STATE ? false : true; @@ -2546,11 +2558,14 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) * existing applications (e.g. Android). Nothing matches against MAC address. */ static const struct ps_led_info lightbar_leds_info[] = { - { NULL, "red", 255, dualshock4_led_get_brightness, dualshock4_led_set_brightness }, - { NULL, "green", 255, dualshock4_led_get_brightness, dualshock4_led_set_brightness }, - { NULL, "blue", 255, dualshock4_led_get_brightness, dualshock4_led_set_brightness }, - { NULL, "global", 1, dualshock4_led_get_brightness, dualshock4_led_set_brightness, - dualshock4_led_set_blink }, + { NULL, "red", 255, dualshock4_led_get_brightness, + dualshock4_led_set_brightness }, + { NULL, "green", 255, dualshock4_led_get_brightness, + dualshock4_led_set_brightness }, + { NULL, "blue", 255, dualshock4_led_get_brightness, + dualshock4_led_set_brightness }, + { NULL, "global", 1, dualshock4_led_get_brightness, + dualshock4_led_set_brightness, dualshock4_led_set_blink }, }; ds4 = devm_kzalloc(&hdev->dev, sizeof(*ds4), GFP_KERNEL); @@ -2620,7 +2635,7 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) ps_dev->input_dev_name = dev_name(&ds4->gamepad->dev); ds4->sensors = ps_sensors_create(hdev, DS4_ACC_RANGE, DS4_ACC_RES_PER_G, - DS4_GYRO_RANGE, DS4_GYRO_RES_PER_DEG_S); + DS4_GYRO_RANGE, DS4_GYRO_RES_PER_DEG_S); if (IS_ERR(ds4->sensors)) { ret = PTR_ERR(ds4->sensors); goto err; @@ -2659,7 +2674,7 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) * can change behavior. */ hid_info(hdev, "Registered DualShock4 controller hw_version=0x%08x fw_version=0x%08x\n", - ds4->base.hw_version, ds4->base.fw_version); + ds4->base.hw_version, ds4->base.fw_version); return &ds4->base; err: @@ -2668,7 +2683,7 @@ err: } static int ps_raw_event(struct hid_device *hdev, struct hid_report *report, - u8 *data, int size) + u8 *data, int size) { struct ps_device *dev = hid_get_drvdata(hdev); From d9812f06be437c64e00fd557ed374100c97077cc Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:51 +0300 Subject: [PATCH 1589/2711] HID: playstation: Document spinlock_t usage Document the usage of 'lock' member in struct ps_device and silent checkpatch.pl complaint: CHECK: spinlock_t definition without comment Signed-off-by: Cristian Ciocaltea Reviewed-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 811b0b90c0e2..37fc1a74517c 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -38,7 +38,7 @@ enum PS_TYPE { struct ps_device { struct list_head list; struct hid_device *hdev; - spinlock_t lock; + spinlock_t lock; /* Sync between event handler and workqueue */ u32 player_id; From 400c6bbc7b48a011c18c765cd1fbb396113e2f63 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:52 +0300 Subject: [PATCH 1590/2711] HID: playstation: Prefer kzalloc(sizeof(*buf)...) Use the shorter variant as suggested by checkpatch.pl: CHECK: Prefer kzalloc(sizeof(*buf)...) over kzalloc(sizeof(struct dualsense_output_report_bt)...) This also improves further maintainability. Signed-off-by: Cristian Ciocaltea Reviewed-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 37fc1a74517c..6e3132418f2e 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -1531,9 +1531,9 @@ static void dualsense_remove(struct ps_device *ps_dev) static int dualsense_reset_leds(struct dualsense *ds) { struct dualsense_output_report report; - u8 *buf; + struct dualsense_output_report_bt *buf; - buf = kzalloc(sizeof(struct dualsense_output_report_bt), GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return -ENOMEM; From d7b744fa977b4c402c25ba723b4981a8420ad15a Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:53 +0300 Subject: [PATCH 1591/2711] HID: playstation: Redefine DualSense input report status field The 'status' member of struct dualsense_input_report is currently used to store just the battery data, despite the fact that hardware is capable to report two extra bytes of status information. In preparation to make use of some of the additional data, redefine the field type as a 3-byte array. Moreover, to preserve consistency with the related DS_STATUS[0..2]_* registers in datasheet, rename DS_STATUS_* bitfield macros accordingly. Signed-off-by: Cristian Ciocaltea Reviewed-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 6e3132418f2e..f523ca989a2f 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -112,9 +112,9 @@ struct ps_led_info { #define DS_BUTTONS2_TOUCHPAD BIT(1) #define DS_BUTTONS2_MIC_MUTE BIT(2) -/* Status field of DualSense input report. */ -#define DS_STATUS_BATTERY_CAPACITY GENMASK(3, 0) -#define DS_STATUS_CHARGING GENMASK(7, 4) +/* Battery status field of DualSense input report. */ +#define DS_STATUS0_BATTERY_CAPACITY GENMASK(3, 0) +#define DS_STATUS0_CHARGING GENMASK(7, 4) /* Feature version from DualSense Firmware Info report. */ #define DS_FEATURE_VERSION_MINOR GENMASK(7, 0) @@ -235,8 +235,8 @@ struct dualsense_input_report { struct dualsense_touch_point points[2]; u8 reserved3[12]; - u8 status; - u8 reserved4[10]; + u8 status[3]; + u8 reserved4[8]; } __packed; /* Common input report size shared equals the size of the USB report minus 1 byte for ReportID. */ static_assert(sizeof(struct dualsense_input_report) == DS_INPUT_REPORT_USB_SIZE - 1); @@ -1461,8 +1461,8 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r input_report_key(ds->touchpad, BTN_LEFT, ds_report->buttons[2] & DS_BUTTONS2_TOUCHPAD); input_sync(ds->touchpad); - battery_data = FIELD_GET(DS_STATUS_BATTERY_CAPACITY, ds_report->status); - charging_status = FIELD_GET(DS_STATUS_CHARGING, ds_report->status); + battery_data = FIELD_GET(DS_STATUS0_BATTERY_CAPACITY, ds_report->status[0]); + charging_status = FIELD_GET(DS_STATUS0_CHARGING, ds_report->status[0]); switch (charging_status) { case 0x0: From b1b4806c0c528e51c648dbaf8cd9f7027c1c11b7 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:54 +0300 Subject: [PATCH 1592/2711] HID: playstation: Support DualSense audio jack hotplug detection The default audio output path on DualSense controller hardware is set to headphones, regardless of whether they are actually inserted or not. Detect when the plugged state of the 3.5mm audio jack changes and toggle audio output between headphones and internal speaker, as required. The latter is achieved by essentially routing the right channel of the audio source to the mono speaker. Additionally, adjust the speaker volume since its default level is too low and, therefore, cannot generate any audible sound. It's worth noting the audio functionality is currently not supported for Bluetooth, hence it's limited to USB connectivity. Signed-off-by: Cristian Ciocaltea Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 91 +++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index f523ca989a2f..4285260c7e22 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -112,9 +112,13 @@ struct ps_led_info { #define DS_BUTTONS2_TOUCHPAD BIT(1) #define DS_BUTTONS2_MIC_MUTE BIT(2) -/* Battery status field of DualSense input report. */ +/* Status fields of DualSense input report. */ #define DS_STATUS0_BATTERY_CAPACITY GENMASK(3, 0) #define DS_STATUS0_CHARGING GENMASK(7, 4) +#define DS_STATUS1_HP_DETECT BIT(0) +#define DS_STATUS1_MIC_DETECT BIT(1) +#define DS_STATUS1_JACK_DETECT (DS_STATUS1_HP_DETECT | DS_STATUS1_MIC_DETECT) +#define DS_STATUS1_MIC_MUTE BIT(2) /* Feature version from DualSense Firmware Info report. */ #define DS_FEATURE_VERSION_MINOR GENMASK(7, 0) @@ -143,13 +147,19 @@ struct ps_led_info { /* Flags for DualSense output report. */ #define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0) #define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1) +#define DS_OUTPUT_VALID_FLAG0_SPEAKER_VOLUME_ENABLE BIT(5) +#define DS_OUTPUT_VALID_FLAG0_MIC_VOLUME_ENABLE BIT(6) +#define DS_OUTPUT_VALID_FLAG0_AUDIO_CONTROL_ENABLE BIT(7) #define DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE BIT(0) #define DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE BIT(1) #define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2) #define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3) #define DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE BIT(4) +#define DS_OUTPUT_VALID_FLAG1_AUDIO_CONTROL2_ENABLE BIT(7) #define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1) #define DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2 BIT(2) +#define DS_OUTPUT_AUDIO_FLAGS_OUTPUT_PATH_SEL GENMASK(5, 4) +#define DS_OUTPUT_AUDIO_FLAGS2_SP_PREAMP_GAIN GENMASK(2, 0) #define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4) #define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1) @@ -192,6 +202,11 @@ struct dualsense { u8 lightbar_green; u8 lightbar_blue; + /* Audio Jack plugged state */ + u8 plugged_state; + u8 prev_plugged_state; + bool prev_plugged_state_valid; + /* Microphone */ bool update_mic_mute; bool mic_muted; @@ -251,11 +266,15 @@ struct dualsense_output_report_common { u8 motor_left; /* Audio controls */ - u8 reserved[4]; + u8 headphone_volume; /* 0x0 - 0x7f */ + u8 speaker_volume; /* 0x0 - 0xff */ + u8 mic_volume; /* 0x0 - 0x40 */ + u8 audio_control; u8 mute_button_led; u8 power_save_control; - u8 reserved2[28]; + u8 reserved2[27]; + u8 audio_control2; /* LEDs and lightbar */ u8 valid_flag2; @@ -1303,6 +1322,46 @@ static void dualsense_output_worker(struct work_struct *work) ds->update_player_leds = false; } + if (ds->plugged_state != ds->prev_plugged_state) { + u8 val = ds->plugged_state & DS_STATUS1_HP_DETECT; + + if (val != (ds->prev_plugged_state & DS_STATUS1_HP_DETECT)) { + common->valid_flag0 = DS_OUTPUT_VALID_FLAG0_AUDIO_CONTROL_ENABLE; + /* + * _--------> Output path setup in audio_flag0 + * / _------> Headphone (HP) Left channel sink + * | / _----> Headphone (HP) Right channel sink + * | | / _--> Internal Speaker (SP) sink + * | | | / + * | | | | L/R - Left/Right channel source + * 0 L-R X X - Unrouted (muted) channel source + * 1 L-L X + * 2 L-L R + * 3 X-X R + */ + if (val) { + /* Mute SP and route L+R channels to HP */ + common->audio_control = 0; + } else { + /* Mute HP and route R channel to SP */ + common->audio_control = + FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS_OUTPUT_PATH_SEL, 0x3); + /* + * Set SP hardware volume to 100%. + * Note the accepted range seems to be [0x3d..0x64] + */ + common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_SPEAKER_VOLUME_ENABLE; + common->speaker_volume = 0x64; + /* Set SP preamp gain to ~30% */ + common->valid_flag1 = DS_OUTPUT_VALID_FLAG1_AUDIO_CONTROL2_ENABLE; + common->audio_control2 = + FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS2_SP_PREAMP_GAIN, 0x2); + } + } + + ds->prev_plugged_state = ds->plugged_state; + } + if (ds->update_mic_mute) { common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE; common->mute_button_led = ds->mic_muted; @@ -1406,6 +1465,32 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r } ds->last_btn_mic_state = btn_mic_state; + /* + * Parse HP/MIC plugged state data for USB use case, since Bluetooth + * audio is currently not supported. + */ + if (hdev->bus == BUS_USB) { + value = ds_report->status[1] & DS_STATUS1_JACK_DETECT; + + if (!ds->prev_plugged_state_valid) { + /* Initial handling of the plugged state report */ + scoped_guard(spinlock_irqsave, &ps_dev->lock) { + ds->plugged_state = (~value) & DS_STATUS1_JACK_DETECT; + ds->prev_plugged_state_valid = true; + } + } + + if (value != ds->plugged_state) { + scoped_guard(spinlock_irqsave, &ps_dev->lock) { + ds->prev_plugged_state = ds->plugged_state; + ds->plugged_state = value; + } + + /* Schedule audio routing towards active endpoint. */ + dualsense_schedule_work(ds); + } + } + /* Parse and calibrate gyroscope data. */ for (i = 0; i < ARRAY_SIZE(ds_report->gyro); i++) { int raw_data = (short)le16_to_cpu(ds_report->gyro[i]); From e1c24d545b8d0f4f04e01258f1ac5d2934c6a08d Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Wed, 25 Jun 2025 00:56:55 +0300 Subject: [PATCH 1593/2711] HID: playstation: Support DualSense audio jack event reporting The DualSense controller complies with v1.0 of the USB Audio Class spec (UAC1), hence it cannot advertise any jack detection capability. However, this feature can be implemented in the generic USB audio driver via quirks, i.e. by configuring an input handler to receive hotplug events from the HID driver. When operating in USB mode, register a dedicated input device for the audio jack and use it to report all headphone and headset mic insert events. Signed-off-by: Cristian Ciocaltea Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 4285260c7e22..d2bee1a314b1 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -176,6 +176,7 @@ struct dualsense { struct input_dev *gamepad; struct input_dev *sensors; struct input_dev *touchpad; + struct input_dev *jack; /* Update version is used as a feature/capability version. */ u16 update_version; @@ -955,6 +956,25 @@ static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width, return touchpad; } +static struct input_dev *ps_headset_jack_create(struct hid_device *hdev) +{ + struct input_dev *jack; + int ret; + + jack = ps_allocate_input_dev(hdev, "Headset Jack"); + if (IS_ERR(jack)) + return ERR_CAST(jack); + + input_set_capability(jack, EV_SW, SW_HEADPHONE_INSERT); + input_set_capability(jack, EV_SW, SW_MICROPHONE_INSERT); + + ret = input_register_device(jack); + if (ret) + return ERR_PTR(ret); + + return jack; +} + static ssize_t firmware_version_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1357,8 +1377,15 @@ static void dualsense_output_worker(struct work_struct *work) common->audio_control2 = FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS2_SP_PREAMP_GAIN, 0x2); } + + input_report_switch(ds->jack, SW_HEADPHONE_INSERT, val); } + val = ds->plugged_state & DS_STATUS1_MIC_DETECT; + if (val != (ds->prev_plugged_state & DS_STATUS1_MIC_DETECT)) + input_report_switch(ds->jack, SW_MICROPHONE_INSERT, val); + + input_sync(ds->jack); ds->prev_plugged_state = ds->plugged_state; } @@ -1778,6 +1805,15 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) goto err; } + /* Bluetooth audio is currently not supported. */ + if (hdev->bus == BUS_USB) { + ds->jack = ps_headset_jack_create(hdev); + if (IS_ERR(ds->jack)) { + ret = PTR_ERR(ds->jack); + goto err; + } + } + ret = ps_device_register_battery(ps_dev); if (ret) goto err; From be66a27b4f391ecd9cfb9394feb4369c4d39f94f Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 21 Aug 2025 16:29:55 +0200 Subject: [PATCH 1594/2711] selftests/hid: update vmtest.sh for virtme-ng This commit is a rewrite almost from scratch of vmtest.sh. By relying on virtme-ng, we get rid of boot2container, reducing the total bootup time (and network requirements). That means that we are relying on the programs being installed on the host, but that shouldn't be an issue. The generation of the kconfig is also now handled by virtme-ng, so that's one less thing to worry. I used tools/testing/selftests/vsock/vmtest.sh as a base and modified it to look mostly like my previous script: - removed the custom ssh handling - make use of vng for compiling, which allows to bring remote compilation (and potentially remote compilation on a remote container) - change the verbosity logic by having 2 levels: - first one shows the tests outputs - second level also shows the VM logs - instead of only running the compiled kernel when it is built, if we are in the kernel tree, use the kernel artifacts there (and complain if they are not built) - adapted the tests list to match the HID subsystem tests Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- tools/testing/selftests/hid/vmtest.sh | 714 ++++++++++++++++---------- 1 file changed, 446 insertions(+), 268 deletions(-) diff --git a/tools/testing/selftests/hid/vmtest.sh b/tools/testing/selftests/hid/vmtest.sh index db534e9099a8..ecbd57f775a0 100755 --- a/tools/testing/selftests/hid/vmtest.sh +++ b/tools/testing/selftests/hid/vmtest.sh @@ -1,296 +1,474 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2025 Red Hat +# Copyright (c) 2025 Meta Platforms, Inc. and affiliates +# +# Dependencies: +# * virtme-ng +# * busybox-static (used by virtme-ng) +# * qemu (used by virtme-ng) -set -u -set -e +readonly SCRIPT_DIR="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" +readonly KERNEL_CHECKOUT=$(realpath "${SCRIPT_DIR}"/../../../../) -# This script currently only works for x86_64 -ARCH="$(uname -m)" -case "${ARCH}" in -x86_64) - QEMU_BINARY=qemu-system-x86_64 - BZIMAGE="arch/x86/boot/bzImage" - ;; -*) - echo "Unsupported architecture" - exit 1 - ;; -esac -SCRIPT_DIR="$(dirname $(realpath $0))" -OUTPUT_DIR="$SCRIPT_DIR/results" -KCONFIG_REL_PATHS=("${SCRIPT_DIR}/config" "${SCRIPT_DIR}/config.common" "${SCRIPT_DIR}/config.${ARCH}") -B2C_URL="https://gitlab.freedesktop.org/gfx-ci/boot2container/-/raw/main/vm2c.py" -NUM_COMPILE_JOBS="$(nproc)" -LOG_FILE_BASE="$(date +"hid_selftests.%Y-%m-%d_%H-%M-%S")" -LOG_FILE="${LOG_FILE_BASE}.log" -EXIT_STATUS_FILE="${LOG_FILE_BASE}.exit_status" -CONTAINER_IMAGE="registry.freedesktop.org/bentiss/hid/fedora/39:2023-11-22.1" +source "${SCRIPT_DIR}"/../kselftest/ktap_helpers.sh -TARGETS="${TARGETS:=$(basename ${SCRIPT_DIR})}" -DEFAULT_COMMAND="pip3 install hid-tools; make -C tools/testing/selftests TARGETS=${TARGETS} run_tests" +readonly HID_BPF_TEST="${SCRIPT_DIR}"/hid_bpf +readonly HIDRAW_TEST="${SCRIPT_DIR}"/hidraw +readonly HID_BPF_PROGS="${KERNEL_CHECKOUT}/drivers/hid/bpf/progs" +readonly SSH_GUEST_PORT=22 +readonly WAIT_PERIOD=3 +readonly WAIT_PERIOD_MAX=60 +readonly WAIT_TOTAL=$(( WAIT_PERIOD * WAIT_PERIOD_MAX )) +readonly QEMU_PIDFILE=$(mktemp /tmp/qemu_hid_vmtest_XXXX.pid) -usage() -{ - cat <] -- [] +readonly QEMU_OPTS="\ + --pidfile ${QEMU_PIDFILE} \ +" +readonly KERNEL_CMDLINE="" +readonly LOG=$(mktemp /tmp/hid_vmtest_XXXX.log) +readonly TEST_NAMES=(vm_hid_bpf vm_hidraw vm_pytest) +readonly TEST_DESCS=( + "Run hid_bpf tests in the VM." + "Run hidraw tests in the VM." + "Run the hid-tools test-suite in the VM." +) - is the command you would normally run when you are in -the source kernel direcory. e.g: +VERBOSE=0 +SHELL_MODE=0 +BUILD_HOST="" +BUILD_HOST_PODMAN_CONTAINER_NAME="" - $0 -- ./tools/testing/selftests/hid/hid_bpf +usage() { + local name + local desc + local i -If no command is specified and a debug shell (-s) is not requested, -"${DEFAULT_COMMAND}" will be run by default. + echo + echo "$0 [OPTIONS] [TEST]... [-- tests-args]" + echo "If no TEST argument is given, all tests will be run." + echo + echo "Options" + echo " -b: build the kernel from the current source tree and use it for guest VMs" + echo " -H: hostname for remote build host (used with -b)" + echo " -p: podman container name for remote build host (used with -b)" + echo " Example: -H beefyserver -p vng" + echo " -q: set the path to or name of qemu binary" + echo " -s: start a shell in the VM instead of running tests" + echo " -v: more verbose output (can be repeated multiple times)" + echo + echo "Available tests" -If you build your kernel using KBUILD_OUTPUT= or O= options, these -can be passed as environment variables to the script: - - O= $0 -- ./tools/testing/selftests/hid/hid_bpf - -or - - KBUILD_OUTPUT= $0 -- ./tools/testing/selftests/hid/hid_bpf - -Options: - - -u) Update the boot2container script to a newer version. - -d) Update the output directory (default: ${OUTPUT_DIR}) - -b) Run only the build steps for the kernel and the selftests - -j) Number of jobs for compilation, similar to -j in make - (default: ${NUM_COMPILE_JOBS}) - -s) Instead of powering off the VM, start an interactive - shell. If is specified, the shell runs after - the command finishes executing -EOF -} - -download() -{ - local file="$1" - - echo "Downloading $file..." >&2 - curl -Lsf "$file" -o "${@:2}" -} - -recompile_kernel() -{ - local kernel_checkout="$1" - local make_command="$2" - - cd "${kernel_checkout}" - - ${make_command} olddefconfig - ${make_command} headers - ${make_command} -} - -update_selftests() -{ - local kernel_checkout="$1" - local selftests_dir="${kernel_checkout}/tools/testing/selftests/hid" - - cd "${selftests_dir}" - ${make_command} -} - -run_vm() -{ - local run_dir="$1" - local b2c="$2" - local kernel_bzimage="$3" - local command="$4" - local post_command="" - - cd "${run_dir}" - - if ! which "${QEMU_BINARY}" &> /dev/null; then - cat < ${OUTPUT_DIR}/${EXIT_STATUS_FILE} - - set -e - - ${post_command} -} - -is_rel_path() -{ - local path="$1" - - [[ ${path:0:1} != "/" ]] -} - -do_update_kconfig() -{ - local kernel_checkout="$1" - local kconfig_file="$2" - - rm -f "$kconfig_file" 2> /dev/null - - for config in "${KCONFIG_REL_PATHS[@]}"; do - local kconfig_src="${config}" - cat "$kconfig_src" >> "$kconfig_file" + for ((i = 0; i < ${#TEST_NAMES[@]}; i++)); do + name=${TEST_NAMES[${i}]} + desc=${TEST_DESCS[${i}]} + printf "\t%-35s%-35s\n" "${name}" "${desc}" done + echo + + exit 1 } -update_kconfig() -{ - local kernel_checkout="$1" - local kconfig_file="$2" +die() { + echo "$*" >&2 + exit "${KSFT_FAIL}" +} - if [[ -f "${kconfig_file}" ]]; then - local local_modified="$(stat -c %Y "${kconfig_file}")" +vm_ssh() { + # vng --ssh-client keeps shouting "Warning: Permanently added 'virtme-ng%22' + # (ED25519) to the list of known hosts.", + # So replace the command with what's actually called and add the "-q" option + stdbuf -oL ssh -q \ + -F ${HOME}/.cache/virtme-ng/.ssh/virtme-ng-ssh.conf \ + -l root virtme-ng%${SSH_GUEST_PORT} \ + "$@" + return $? +} - for config in "${KCONFIG_REL_PATHS[@]}"; do - local kconfig_src="${config}" - local src_modified="$(stat -c %Y "${kconfig_src}")" - # Only update the config if it has been updated after the - # previously cached config was created. This avoids - # unnecessarily compiling the kernel and selftests. - if [[ "${src_modified}" -gt "${local_modified}" ]]; then - do_update_kconfig "$kernel_checkout" "$kconfig_file" - # Once we have found one outdated configuration - # there is no need to check other ones. +cleanup() { + if [[ -s "${QEMU_PIDFILE}" ]]; then + pkill -SIGTERM -F "${QEMU_PIDFILE}" > /dev/null 2>&1 + fi + + # If failure occurred during or before qemu start up, then we need + # to clean this up ourselves. + if [[ -e "${QEMU_PIDFILE}" ]]; then + rm "${QEMU_PIDFILE}" + fi +} + +check_args() { + local found + + for arg in "$@"; do + found=0 + for name in "${TEST_NAMES[@]}"; do + if [[ "${name}" = "${arg}" ]]; then + found=1 break fi done - else - do_update_kconfig "$kernel_checkout" "$kconfig_file" - fi -} -main() -{ - local script_dir="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" - local kernel_checkout=$(realpath "${script_dir}"/../../../../) - # By default the script searches for the kernel in the checkout directory but - # it also obeys environment variables O= and KBUILD_OUTPUT= - local kernel_bzimage="${kernel_checkout}/${BZIMAGE}" - local command="${DEFAULT_COMMAND}" - local update_b2c="no" - local debug_shell="no" - local build_only="no" - - while getopts ':hsud:j:b' opt; do - case ${opt} in - u) - update_b2c="yes" - ;; - d) - OUTPUT_DIR="$OPTARG" - ;; - j) - NUM_COMPILE_JOBS="$OPTARG" - ;; - s) - command="/bin/sh" - debug_shell="yes" - ;; - b) - build_only="yes" - ;; - h) + if [[ "${found}" -eq 0 ]]; then + echo "${arg} is not an available test" >&2 usage - exit 0 - ;; - \? ) - echo "Invalid Option: -$OPTARG" - usage - exit 1 - ;; - : ) - echo "Invalid Option: -$OPTARG requires an argument" - usage - exit 1 - ;; - esac + fi done - shift $((OPTIND -1)) - # trap 'catch "$?"' EXIT - if [[ "${build_only}" == "no" && "${debug_shell}" == "no" ]]; then - if [[ $# -eq 0 ]]; then - echo "No command specified, will run ${DEFAULT_COMMAND} in the vm" - else - command="$@" - - if [[ "${command}" == "/bin/bash" || "${command}" == "bash" ]] - then - debug_shell="yes" - fi + for arg in "$@"; do + if ! command -v > /dev/null "test_${arg}"; then + echo "Test ${arg} not found" >&2 + usage fi + done +} + +check_deps() { + for dep in vng ${QEMU} busybox pkill ssh pytest; do + if [[ ! -x $(command -v "${dep}") ]]; then + echo -e "skip: dependency ${dep} not found!\n" + exit "${KSFT_SKIP}" + fi + done + + if [[ ! -x $(command -v "${HID_BPF_TEST}") ]]; then + printf "skip: %s not found!" "${HID_BPF_TEST}" + printf " Please build the kselftest hid_bpf target.\n" + exit "${KSFT_SKIP}" fi - local kconfig_file="${OUTPUT_DIR}/latest.config" - local make_command="make -j ${NUM_COMPILE_JOBS} KCONFIG_CONFIG=${kconfig_file}" - - # Figure out where the kernel is being built. - # O takes precedence over KBUILD_OUTPUT. - if [[ "${O:=""}" != "" ]]; then - if is_rel_path "${O}"; then - O="$(realpath "${PWD}/${O}")" - fi - kernel_bzimage="${O}/${BZIMAGE}" - make_command="${make_command} O=${O}" - elif [[ "${KBUILD_OUTPUT:=""}" != "" ]]; then - if is_rel_path "${KBUILD_OUTPUT}"; then - KBUILD_OUTPUT="$(realpath "${PWD}/${KBUILD_OUTPUT}")" - fi - kernel_bzimage="${KBUILD_OUTPUT}/${BZIMAGE}" - make_command="${make_command} KBUILD_OUTPUT=${KBUILD_OUTPUT}" - fi - - local b2c="${OUTPUT_DIR}/vm2c.py" - - echo "Output directory: ${OUTPUT_DIR}" - - mkdir -p "${OUTPUT_DIR}" - update_kconfig "${kernel_checkout}" "${kconfig_file}" - - recompile_kernel "${kernel_checkout}" "${make_command}" - update_selftests "${kernel_checkout}" "${make_command}" - - if [[ "${build_only}" == "no" ]]; then - if [[ "${update_b2c}" == "no" && ! -f "${b2c}" ]]; then - echo "vm2c script not found in ${b2c}" - update_b2c="yes" - fi - - if [[ "${update_b2c}" == "yes" ]]; then - download $B2C_URL $b2c - chmod +x $b2c - fi - - run_vm "${kernel_checkout}" $b2c "${kernel_bzimage}" "${command}" - if [[ "${debug_shell}" != "yes" ]]; then - echo "Logs saved in ${OUTPUT_DIR}/${LOG_FILE}" - fi - - exit $(cat ${OUTPUT_DIR}/${EXIT_STATUS_FILE}) + if [[ ! -x $(command -v "${HIDRAW_TEST}") ]]; then + printf "skip: %s not found!" "${HIDRAW_TEST}" + printf " Please build the kselftest hidraw target.\n" + exit "${KSFT_SKIP}" fi } -main "$@" +check_vng() { + local tested_versions + local version + local ok + + tested_versions=("1.36" "1.37") + version="$(vng --version)" + + ok=0 + for tv in "${tested_versions[@]}"; do + if [[ "${version}" == *"${tv}"* ]]; then + ok=1 + break + fi + done + + if [[ ! "${ok}" -eq 1 ]]; then + printf "warning: vng version '%s' has not been tested and may " "${version}" >&2 + printf "not function properly.\n\tThe following versions have been tested: " >&2 + echo "${tested_versions[@]}" >&2 + fi +} + +handle_build() { + if [[ ! "${BUILD}" -eq 1 ]]; then + return + fi + + if [[ ! -d "${KERNEL_CHECKOUT}" ]]; then + echo "-b requires vmtest.sh called from the kernel source tree" >&2 + exit 1 + fi + + pushd "${KERNEL_CHECKOUT}" &>/dev/null + + if ! vng --kconfig --config "${SCRIPT_DIR}"/config; then + die "failed to generate .config for kernel source tree (${KERNEL_CHECKOUT})" + fi + + local vng_args=("-v" "--config" "${SCRIPT_DIR}/config" "--build") + + if [[ -n "${BUILD_HOST}" ]]; then + vng_args+=("--build-host" "${BUILD_HOST}") + fi + + if [[ -n "${BUILD_HOST_PODMAN_CONTAINER_NAME}" ]]; then + vng_args+=("--build-host-exec-prefix" \ + "podman exec -ti ${BUILD_HOST_PODMAN_CONTAINER_NAME}") + fi + + if ! vng "${vng_args[@]}"; then + die "failed to build kernel from source tree (${KERNEL_CHECKOUT})" + fi + + if ! make -j$(nproc) -C "${HID_BPF_PROGS}"; then + die "failed to build HID bpf objects from source tree (${HID_BPF_PROGS})" + fi + + if ! make -j$(nproc) -C "${SCRIPT_DIR}"; then + die "failed to build HID selftests from source tree (${SCRIPT_DIR})" + fi + + popd &>/dev/null +} + +vm_start() { + local logfile=/dev/null + local verbose_opt="" + local kernel_opt="" + local qemu + + qemu=$(command -v "${QEMU}") + + if [[ "${VERBOSE}" -eq 2 ]]; then + verbose_opt="--verbose" + logfile=/dev/stdout + fi + + # If we are running from within the kernel source tree, use the kernel source tree + # as the kernel to boot, otherwise use the currently running kernel. + if [[ "$(realpath "$(pwd)")" == "${KERNEL_CHECKOUT}"* ]]; then + kernel_opt="${KERNEL_CHECKOUT}" + fi + + vng \ + --run \ + ${kernel_opt} \ + ${verbose_opt} \ + --qemu-opts="${QEMU_OPTS}" \ + --qemu="${qemu}" \ + --user root \ + --append "${KERNEL_CMDLINE}" \ + --ssh "${SSH_GUEST_PORT}" \ + --rw &> ${logfile} & + + local vng_pid=$! + local elapsed=0 + + while [[ ! -s "${QEMU_PIDFILE}" ]]; do + if ! kill -0 "${vng_pid}" 2>/dev/null; then + echo "vng process (PID ${vng_pid}) exited early, check logs for details" >&2 + die "failed to boot VM" + fi + + if [[ ${elapsed} -ge ${WAIT_TOTAL} ]]; then + echo "Timed out after ${WAIT_TOTAL} seconds waiting for VM to boot" >&2 + die "failed to boot VM" + fi + + sleep 1 + elapsed=$((elapsed + 1)) + done +} + +vm_wait_for_ssh() { + local i + + i=0 + while true; do + if [[ ${i} -gt ${WAIT_PERIOD_MAX} ]]; then + die "Timed out waiting for guest ssh" + fi + if vm_ssh -- true; then + break + fi + i=$(( i + 1 )) + sleep ${WAIT_PERIOD} + done +} + +vm_mount_bpffs() { + vm_ssh -- mount bpffs -t bpf /sys/fs/bpf +} + +__log_stdin() { + stdbuf -oL awk '{ printf "%s:\t%s\n","'"${prefix}"'", $0; fflush() }' +} + +__log_args() { + echo "$*" | awk '{ printf "%s:\t%s\n","'"${prefix}"'", $0 }' +} + +log() { + local verbose="$1" + shift + + local prefix="$1" + + shift + local redirect= + if [[ ${verbose} -le 0 ]]; then + redirect=/dev/null + else + redirect=/dev/stdout + fi + + if [[ "$#" -eq 0 ]]; then + __log_stdin | tee -a "${LOG}" > ${redirect} + else + __log_args "$@" | tee -a "${LOG}" > ${redirect} + fi +} + +log_setup() { + log $((VERBOSE-1)) "setup" "$@" +} + +log_host() { + local testname=$1 + + shift + log $((VERBOSE-1)) "test:${testname}:host" "$@" +} + +log_guest() { + local testname=$1 + + shift + log ${VERBOSE} "# test:${testname}" "$@" +} + +test_vm_hid_bpf() { + local testname="${FUNCNAME[0]#test_}" + + vm_ssh -- "${HID_BPF_TEST}" \ + 2>&1 | log_guest "${testname}" + + return ${PIPESTATUS[0]} +} + +test_vm_hidraw() { + local testname="${FUNCNAME[0]#test_}" + + vm_ssh -- "${HIDRAW_TEST}" \ + 2>&1 | log_guest "${testname}" + + return ${PIPESTATUS[0]} +} + +test_vm_pytest() { + local testname="${FUNCNAME[0]#test_}" + + shift + + vm_ssh -- pytest ${SCRIPT_DIR}/tests --color=yes "$@" \ + 2>&1 | log_guest "${testname}" + + return ${PIPESTATUS[0]} +} + +run_test() { + local vm_oops_cnt_before + local vm_warn_cnt_before + local vm_oops_cnt_after + local vm_warn_cnt_after + local name + local rc + + vm_oops_cnt_before=$(vm_ssh -- dmesg | grep -c -i 'Oops') + vm_error_cnt_before=$(vm_ssh -- dmesg --level=err | wc -l) + + name=$(echo "${1}" | awk '{ print $1 }') + eval test_"${name}" "$@" + rc=$? + + vm_oops_cnt_after=$(vm_ssh -- dmesg | grep -i 'Oops' | wc -l) + if [[ ${vm_oops_cnt_after} -gt ${vm_oops_cnt_before} ]]; then + echo "FAIL: kernel oops detected on vm" | log_host "${name}" + rc=$KSFT_FAIL + fi + + vm_error_cnt_after=$(vm_ssh -- dmesg --level=err | wc -l) + if [[ ${vm_error_cnt_after} -gt ${vm_error_cnt_before} ]]; then + echo "FAIL: kernel error detected on vm" | log_host "${name}" + vm_ssh -- dmesg --level=err | log_host "${name}" + rc=$KSFT_FAIL + fi + + return "${rc}" +} + +QEMU="qemu-system-$(uname -m)" + +while getopts :hvsbq:H:p: o +do + case $o in + v) VERBOSE=$((VERBOSE+1));; + s) SHELL_MODE=1;; + b) BUILD=1;; + q) QEMU=$OPTARG;; + H) BUILD_HOST=$OPTARG;; + p) BUILD_HOST_PODMAN_CONTAINER_NAME=$OPTARG;; + h|*) usage;; + esac +done +shift $((OPTIND-1)) + +trap cleanup EXIT + +PARAMS="" + +if [[ ${#} -eq 0 ]]; then + ARGS=("${TEST_NAMES[@]}") +else + ARGS=() + COUNT=0 + for arg in $@; do + COUNT=$((COUNT+1)) + if [[ x"$arg" == x"--" ]]; then + break + fi + ARGS+=($arg) + done + shift $COUNT + PARAMS="$@" +fi + +if [[ "${SHELL_MODE}" -eq 0 ]]; then + check_args "${ARGS[@]}" + echo "1..${#ARGS[@]}" +fi +check_deps +check_vng +handle_build + +log_setup "Booting up VM" +vm_start +vm_wait_for_ssh +vm_mount_bpffs +log_setup "VM booted up" + +if [[ "${SHELL_MODE}" -eq 1 ]]; then + log_setup "Starting interactive shell in VM" + echo "Starting shell in VM. Use 'exit' to quit and shutdown the VM." + CURRENT_DIR="$(pwd)" + vm_ssh -t -- "cd '${CURRENT_DIR}' && exec bash -l" + exit "$KSFT_PASS" +fi + +cnt_pass=0 +cnt_fail=0 +cnt_skip=0 +cnt_total=0 +for arg in "${ARGS[@]}"; do + run_test "${arg}" "${PARAMS}" + rc=$? + if [[ ${rc} -eq $KSFT_PASS ]]; then + cnt_pass=$(( cnt_pass + 1 )) + echo "ok ${cnt_total} ${arg}" + elif [[ ${rc} -eq $KSFT_SKIP ]]; then + cnt_skip=$(( cnt_skip + 1 )) + echo "ok ${cnt_total} ${arg} # SKIP" + elif [[ ${rc} -eq $KSFT_FAIL ]]; then + cnt_fail=$(( cnt_fail + 1 )) + echo "not ok ${cnt_total} ${arg} # exit=$rc" + fi + cnt_total=$(( cnt_total + 1 )) +done + +echo "SUMMARY: PASS=${cnt_pass} SKIP=${cnt_skip} FAIL=${cnt_fail}" +echo "Log: ${LOG}" + +if [ $((cnt_pass + cnt_skip)) -eq ${cnt_total} ]; then + exit "$KSFT_PASS" +else + exit "$KSFT_FAIL" +fi From bb6c861a290f2d6b3df2b176d2c2491f1a242265 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 12 Sep 2025 18:58:49 +0200 Subject: [PATCH 1595/2711] selftests/hid: hidraw: add more coverage for hidraw ioctls Try to ensure all ioctls are having at least one test. Most of the scaffholding has been generated by claude-4-sonnet and then carefully reviewed. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- tools/testing/selftests/hid/hid_common.h | 6 + tools/testing/selftests/hid/hidraw.c | 346 +++++++++++++++++++++++ 2 files changed, 352 insertions(+) diff --git a/tools/testing/selftests/hid/hid_common.h b/tools/testing/selftests/hid/hid_common.h index f77f69c6657d..8085519c47cb 100644 --- a/tools/testing/selftests/hid/hid_common.h +++ b/tools/testing/selftests/hid/hid_common.h @@ -230,6 +230,12 @@ static int uhid_event(struct __test_metadata *_metadata, int fd) break; case UHID_SET_REPORT: UHID_LOG("UHID_SET_REPORT from uhid-dev"); + + answer.type = UHID_SET_REPORT_REPLY; + answer.u.set_report_reply.id = ev.u.set_report.id; + answer.u.set_report_reply.err = 0; /* success */ + + uhid_write(_metadata, fd, &answer); break; default: TH_LOG("Invalid event from uhid-dev: %u", ev.type); diff --git a/tools/testing/selftests/hid/hidraw.c b/tools/testing/selftests/hid/hidraw.c index 821db37ba4bb..6d61d03e2ef0 100644 --- a/tools/testing/selftests/hid/hidraw.c +++ b/tools/testing/selftests/hid/hidraw.c @@ -2,6 +2,9 @@ /* Copyright (c) 2022-2024 Red Hat */ #include "hid_common.h" +#include +#include +#include /* for older kernels */ #ifndef HIDIOCREVOKE @@ -215,6 +218,349 @@ TEST_F(hidraw, write_event_revoked) pthread_mutex_unlock(&uhid_output_mtx); } +/* + * Test HIDIOCGRDESCSIZE ioctl to get report descriptor size + */ +TEST_F(hidraw, ioctl_rdescsize) +{ + int desc_size = 0; + int err; + + /* call HIDIOCGRDESCSIZE ioctl */ + err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size); + ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRDESCSIZE ioctl failed"); + + /* verify the size matches our test report descriptor */ + ASSERT_EQ(desc_size, sizeof(rdesc)) + TH_LOG("expected size %zu, got %d", sizeof(rdesc), desc_size); +} + +/* + * Test HIDIOCGRDESC ioctl to get report descriptor data + */ +TEST_F(hidraw, ioctl_rdesc) +{ + struct hidraw_report_descriptor desc; + int err; + + /* get the full report descriptor */ + desc.size = sizeof(rdesc); + err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &desc); + ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRDESC ioctl failed"); + + /* verify the descriptor data matches our test descriptor */ + ASSERT_EQ(memcmp(desc.value, rdesc, sizeof(rdesc)), 0) + TH_LOG("report descriptor data mismatch"); +} + +/* + * Test HIDIOCGRDESC ioctl with smaller buffer size + */ +TEST_F(hidraw, ioctl_rdesc_small_buffer) +{ + struct hidraw_report_descriptor desc; + int err; + size_t small_size = sizeof(rdesc) / 2; /* request half the descriptor size */ + + /* get partial report descriptor */ + desc.size = small_size; + err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &desc); + ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRDESC ioctl failed with small buffer"); + + /* verify we got the first part of the descriptor */ + ASSERT_EQ(memcmp(desc.value, rdesc, small_size), 0) + TH_LOG("partial report descriptor data mismatch"); +} + +/* + * Test HIDIOCGRAWINFO ioctl to get device information + */ +TEST_F(hidraw, ioctl_rawinfo) +{ + struct hidraw_devinfo devinfo; + int err; + + /* get device info */ + err = ioctl(self->hidraw_fd, HIDIOCGRAWINFO, &devinfo); + ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRAWINFO ioctl failed"); + + /* verify device info matches our test setup */ + ASSERT_EQ(devinfo.bustype, BUS_USB) + TH_LOG("expected bustype 0x03, got 0x%x", devinfo.bustype); + ASSERT_EQ(devinfo.vendor, 0x0001) + TH_LOG("expected vendor 0x0001, got 0x%x", devinfo.vendor); + ASSERT_EQ(devinfo.product, 0x0a37) + TH_LOG("expected product 0x0a37, got 0x%x", devinfo.product); +} + +/* + * Test HIDIOCGFEATURE ioctl to get feature report + */ +TEST_F(hidraw, ioctl_gfeature) +{ + __u8 buf[10] = {0}; + int err; + + /* set report ID 1 in first byte */ + buf[0] = 1; + + /* get feature report */ + err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); + ASSERT_EQ(err, sizeof(feature_data)) TH_LOG("HIDIOCGFEATURE ioctl failed, got %d", err); + + /* verify we got the expected feature data */ + ASSERT_EQ(buf[0], feature_data[0]) + TH_LOG("expected feature_data[0] = %d, got %d", feature_data[0], buf[0]); + ASSERT_EQ(buf[1], feature_data[1]) + TH_LOG("expected feature_data[1] = %d, got %d", feature_data[1], buf[1]); +} + +/* + * Test HIDIOCGFEATURE ioctl with invalid report ID + */ +TEST_F(hidraw, ioctl_gfeature_invalid) +{ + __u8 buf[10] = {0}; + int err; + + /* set invalid report ID (not 1) */ + buf[0] = 2; + + /* try to get feature report */ + err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE should have failed with invalid report ID"); + ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno); +} + +/* + * Test HIDIOCSFEATURE ioctl to set feature report + */ +TEST_F(hidraw, ioctl_sfeature) +{ + __u8 buf[10] = {0}; + int err; + + /* prepare feature report data */ + buf[0] = 1; /* report ID */ + buf[1] = 0x42; + buf[2] = 0x24; + + /* set feature report */ + err = ioctl(self->hidraw_fd, HIDIOCSFEATURE(3), buf); + ASSERT_EQ(err, 3) TH_LOG("HIDIOCSFEATURE ioctl failed, got %d", err); + + /* + * Note: The uhid mock doesn't validate the set report data, + * so we just verify the ioctl succeeds + */ +} + +/* + * Test HIDIOCGINPUT ioctl to get input report + */ +TEST_F(hidraw, ioctl_ginput) +{ + __u8 buf[10] = {0}; + int err; + + /* set report ID 1 in first byte */ + buf[0] = 1; + + /* get input report */ + err = ioctl(self->hidraw_fd, HIDIOCGINPUT(sizeof(buf)), buf); + ASSERT_EQ(err, sizeof(feature_data)) TH_LOG("HIDIOCGINPUT ioctl failed, got %d", err); + + /* verify we got the expected input data */ + ASSERT_EQ(buf[0], feature_data[0]) + TH_LOG("expected feature_data[0] = %d, got %d", feature_data[0], buf[0]); + ASSERT_EQ(buf[1], feature_data[1]) + TH_LOG("expected feature_data[1] = %d, got %d", feature_data[1], buf[1]); +} + +/* + * Test HIDIOCGINPUT ioctl with invalid report ID + */ +TEST_F(hidraw, ioctl_ginput_invalid) +{ + __u8 buf[10] = {0}; + int err; + + /* set invalid report ID (not 1) */ + buf[0] = 2; + + /* try to get input report */ + err = ioctl(self->hidraw_fd, HIDIOCGINPUT(sizeof(buf)), buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGINPUT should have failed with invalid report ID"); + ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno); +} + +/* + * Test HIDIOCSINPUT ioctl to set input report + */ +TEST_F(hidraw, ioctl_sinput) +{ + __u8 buf[10] = {0}; + int err; + + /* prepare input report data */ + buf[0] = 1; /* report ID */ + buf[1] = 0x55; + buf[2] = 0xAA; + + /* set input report */ + err = ioctl(self->hidraw_fd, HIDIOCSINPUT(3), buf); + ASSERT_EQ(err, 3) TH_LOG("HIDIOCSINPUT ioctl failed, got %d", err); + + /* + * Note: The uhid mock doesn't validate the set report data, + * so we just verify the ioctl succeeds + */ +} + +/* + * Test HIDIOCGOUTPUT ioctl to get output report + */ +TEST_F(hidraw, ioctl_goutput) +{ + __u8 buf[10] = {0}; + int err; + + /* set report ID 1 in first byte */ + buf[0] = 1; + + /* get output report */ + err = ioctl(self->hidraw_fd, HIDIOCGOUTPUT(sizeof(buf)), buf); + ASSERT_EQ(err, sizeof(feature_data)) TH_LOG("HIDIOCGOUTPUT ioctl failed, got %d", err); + + /* verify we got the expected output data */ + ASSERT_EQ(buf[0], feature_data[0]) + TH_LOG("expected feature_data[0] = %d, got %d", feature_data[0], buf[0]); + ASSERT_EQ(buf[1], feature_data[1]) + TH_LOG("expected feature_data[1] = %d, got %d", feature_data[1], buf[1]); +} + +/* + * Test HIDIOCGOUTPUT ioctl with invalid report ID + */ +TEST_F(hidraw, ioctl_goutput_invalid) +{ + __u8 buf[10] = {0}; + int err; + + /* set invalid report ID (not 1) */ + buf[0] = 2; + + /* try to get output report */ + err = ioctl(self->hidraw_fd, HIDIOCGOUTPUT(sizeof(buf)), buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGOUTPUT should have failed with invalid report ID"); + ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno); +} + +/* + * Test HIDIOCSOUTPUT ioctl to set output report + */ +TEST_F(hidraw, ioctl_soutput) +{ + __u8 buf[10] = {0}; + int err; + + /* prepare output report data */ + buf[0] = 1; /* report ID */ + buf[1] = 0x33; + buf[2] = 0xCC; + + /* set output report */ + err = ioctl(self->hidraw_fd, HIDIOCSOUTPUT(3), buf); + ASSERT_EQ(err, 3) TH_LOG("HIDIOCSOUTPUT ioctl failed, got %d", err); + + /* + * Note: The uhid mock doesn't validate the set report data, + * so we just verify the ioctl succeeds + */ +} + +/* + * Test HIDIOCGRAWNAME ioctl to get device name string + */ +TEST_F(hidraw, ioctl_rawname) +{ + char name[256] = {0}; + char expected_name[64]; + int err; + + /* get device name */ + err = ioctl(self->hidraw_fd, HIDIOCGRAWNAME(sizeof(name)), name); + ASSERT_GT(err, 0) TH_LOG("HIDIOCGRAWNAME ioctl failed, got %d", err); + + /* construct expected name based on device id */ + snprintf(expected_name, sizeof(expected_name), "test-uhid-device-%d", self->hid.dev_id); + + /* verify the name matches expected pattern */ + ASSERT_EQ(strcmp(name, expected_name), 0) + TH_LOG("expected name '%s', got '%s'", expected_name, name); +} + +/* + * Test HIDIOCGRAWPHYS ioctl to get device physical address string + */ +TEST_F(hidraw, ioctl_rawphys) +{ + char phys[256] = {0}; + char expected_phys[64]; + int err; + + /* get device physical address */ + err = ioctl(self->hidraw_fd, HIDIOCGRAWPHYS(sizeof(phys)), phys); + ASSERT_GT(err, 0) TH_LOG("HIDIOCGRAWPHYS ioctl failed, got %d", err); + + /* construct expected phys based on device id */ + snprintf(expected_phys, sizeof(expected_phys), "%d", self->hid.dev_id); + + /* verify the phys matches expected value */ + ASSERT_EQ(strcmp(phys, expected_phys), 0) + TH_LOG("expected phys '%s', got '%s'", expected_phys, phys); +} + +/* + * Test HIDIOCGRAWUNIQ ioctl to get device unique identifier string + */ +TEST_F(hidraw, ioctl_rawuniq) +{ + char uniq[256] = {0}; + int err; + + /* get device unique identifier */ + err = ioctl(self->hidraw_fd, HIDIOCGRAWUNIQ(sizeof(uniq)), uniq); + ASSERT_GE(err, 0) TH_LOG("HIDIOCGRAWUNIQ ioctl failed, got %d", err); + + /* uniq is typically empty in our test setup */ + ASSERT_EQ(strlen(uniq), 0) TH_LOG("expected empty uniq, got '%s'", uniq); +} + +/* + * Test device string ioctls with small buffer sizes + */ +TEST_F(hidraw, ioctl_strings_small_buffer) +{ + char small_buf[8] = {0}; + char expected_name[64]; + int err; + + /* test HIDIOCGRAWNAME with small buffer */ + err = ioctl(self->hidraw_fd, HIDIOCGRAWNAME(sizeof(small_buf)), small_buf); + ASSERT_EQ(err, sizeof(small_buf)) + TH_LOG("HIDIOCGRAWNAME with small buffer failed, got %d", err); + + /* construct expected truncated name */ + snprintf(expected_name, sizeof(expected_name), "test-uhid-device-%d", self->hid.dev_id); + + /* verify we got truncated name (first 8 chars, no null terminator guaranteed) */ + ASSERT_EQ(strncmp(small_buf, expected_name, sizeof(small_buf)), 0) + TH_LOG("expected truncated name to match first %zu chars", sizeof(small_buf)); + + /* Note: hidraw driver doesn't guarantee null termination when buffer is too small */ +} + int main(int argc, char **argv) { return test_harness_run(argc, argv); From 8c62074fa824db0878a039e40f8424c3c3284f42 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 12 Sep 2025 18:58:50 +0200 Subject: [PATCH 1596/2711] selftests/hid: hidraw: forge wrong ioctls and tests them We also need coverage for when the malicious user is not using the proper ioctls definitions and tries to work around the driver. Most of the scaffholding has been generated by claude-4-sonnet and then carefully reviewed. Suggested-by: Arnd Bergmann Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- tools/testing/selftests/hid/hidraw.c | 127 +++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/tools/testing/selftests/hid/hidraw.c b/tools/testing/selftests/hid/hidraw.c index 6d61d03e2ef0..d625772f8b7c 100644 --- a/tools/testing/selftests/hid/hidraw.c +++ b/tools/testing/selftests/hid/hidraw.c @@ -332,6 +332,133 @@ TEST_F(hidraw, ioctl_gfeature_invalid) ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno); } +/* + * Test ioctl with incorrect nr bits + */ +TEST_F(hidraw, ioctl_invalid_nr) +{ + char buf[256] = {0}; + int err; + unsigned int bad_cmd; + + /* + * craft an ioctl command with wrong _IOC_NR bits + */ + bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x00, sizeof(buf)); /* 0 is not valid */ + + /* test the ioctl */ + err = ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("ioctl read-write with wrong _IOC_NR (0) should have failed"); + ASSERT_EQ(errno, ENOTTY) + TH_LOG("expected ENOTTY for wrong read-write _IOC_NR (0), got errno %d", errno); + + /* + * craft an ioctl command with wrong _IOC_NR bits + */ + bad_cmd = _IOC(_IOC_READ, 'H', 0x00, sizeof(buf)); /* 0 is not valid */ + + /* test the ioctl */ + err = ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("ioctl read-only with wrong _IOC_NR (0) should have failed"); + ASSERT_EQ(errno, ENOTTY) + TH_LOG("expected ENOTTY for wrong read-only _IOC_NR (0), got errno %d", errno); + + /* also test with bigger number */ + bad_cmd = _IOC(_IOC_READ, 'H', 0x42, sizeof(buf)); /* 0x42 is not valid as well */ + + err = ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("ioctl read-only with wrong _IOC_NR (0x42) should have failed"); + ASSERT_EQ(errno, ENOTTY) + TH_LOG("expected ENOTTY for wrong read-only _IOC_NR (0x42), got errno %d", errno); + + /* also test with bigger number: 0x42 is not valid as well */ + bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x42, sizeof(buf)); + + err = ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("ioctl read-write with wrong _IOC_NR (0x42) should have failed"); + ASSERT_EQ(errno, ENOTTY) + TH_LOG("expected ENOTTY for wrong read-write _IOC_NR (0x42), got errno %d", errno); +} + +/* + * Test ioctl with incorrect type bits + */ +TEST_F(hidraw, ioctl_invalid_type) +{ + char buf[256] = {0}; + int err; + unsigned int bad_cmd; + + /* + * craft an ioctl command with wrong _IOC_TYPE bits + */ + bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'I', 0x01, sizeof(buf)); /* 'I' should be 'H' */ + + /* test the ioctl */ + err = ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("ioctl with wrong _IOC_TYPE (I) should have failed"); + ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_NR, got errno %d", errno); +} + +/* + * Test HIDIOCGFEATURE ioctl with incorrect _IOC_DIR bits + */ +TEST_F(hidraw, ioctl_gfeature_invalid_dir) +{ + __u8 buf[10] = {0}; + int err; + unsigned int bad_cmd; + + /* set report ID 1 in first byte */ + buf[0] = 1; + + /* + * craft an ioctl command with wrong _IOC_DIR bits + * HIDIOCGFEATURE should have _IOC_WRITE|_IOC_READ, let's use only _IOC_WRITE + */ + bad_cmd = _IOC(_IOC_WRITE, 'H', 0x07, sizeof(buf)); /* should be _IOC_WRITE|_IOC_READ */ + + /* try to get feature report with wrong direction bits */ + err = ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE with wrong _IOC_DIR should have failed"); + ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno); + + /* also test with only _IOC_READ */ + bad_cmd = _IOC(_IOC_READ, 'H', 0x07, sizeof(buf)); /* should be _IOC_WRITE|_IOC_READ */ + + err = ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE with wrong _IOC_DIR should have failed"); + ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno); +} + +/* + * Test read-only ioctl with incorrect _IOC_DIR bits + */ +TEST_F(hidraw, ioctl_readonly_invalid_dir) +{ + char buf[256] = {0}; + int err; + unsigned int bad_cmd; + + /* + * craft an ioctl command with wrong _IOC_DIR bits + * HIDIOCGRAWNAME should have _IOC_READ, let's use _IOC_WRITE + */ + bad_cmd = _IOC(_IOC_WRITE, 'H', 0x04, sizeof(buf)); /* should be _IOC_READ */ + + /* try to get device name with wrong direction bits */ + err = ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGRAWNAME with wrong _IOC_DIR should have failed"); + ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno); + + /* also test with _IOC_WRITE|_IOC_READ */ + bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x04, sizeof(buf)); /* should be only _IOC_READ */ + + err = ioctl(self->hidraw_fd, bad_cmd, buf); + ASSERT_LT(err, 0) TH_LOG("HIDIOCGRAWNAME with wrong _IOC_DIR should have failed"); + ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno); +} + /* * Test HIDIOCSFEATURE ioctl to set feature report */ From 75d5546f60b36900051d75ee623fceccbeb6750c Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 12 Sep 2025 18:58:51 +0200 Subject: [PATCH 1597/2711] HID: hidraw: tighten ioctl command parsing The handling for variable-length ioctl commands in hidraw_ioctl() is rather complex and the check for the data direction is incomplete. Simplify this code by factoring out the various ioctls grouped by dir and size, and using a switch() statement with the size masked out, to ensure the rest of the command is correctly matched. Fixes: 9188e79ec3fd ("HID: add phys and name ioctls to hidraw") Reported-by: Arnd Bergmann Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 262 +++++++++++++++++++----------------- include/uapi/linux/hidraw.h | 2 + 2 files changed, 143 insertions(+), 121 deletions(-) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index c887f48756f4..bbd6f23bce78 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -394,15 +394,127 @@ static int hidraw_revoke(struct hidraw_list *list) return 0; } -static long hidraw_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) +static long hidraw_fixed_size_ioctl(struct file *file, struct hidraw *dev, unsigned int cmd, + void __user *arg) +{ + struct hid_device *hid = dev->hid; + + switch (cmd) { + case HIDIOCGRDESCSIZE: + if (put_user(hid->rsize, (int __user *)arg)) + return -EFAULT; + break; + + case HIDIOCGRDESC: + { + __u32 len; + + if (get_user(len, (int __user *)arg)) + return -EFAULT; + + if (len > HID_MAX_DESCRIPTOR_SIZE - 1) + return -EINVAL; + + if (copy_to_user(arg + offsetof( + struct hidraw_report_descriptor, + value[0]), + hid->rdesc, + min(hid->rsize, len))) + return -EFAULT; + + break; + } + case HIDIOCGRAWINFO: + { + struct hidraw_devinfo dinfo; + + dinfo.bustype = hid->bus; + dinfo.vendor = hid->vendor; + dinfo.product = hid->product; + if (copy_to_user(arg, &dinfo, sizeof(dinfo))) + return -EFAULT; + break; + } + case HIDIOCREVOKE: + { + struct hidraw_list *list = file->private_data; + + if (arg) + return -EINVAL; + + return hidraw_revoke(list); + } + default: + /* + * None of the above ioctls can return -EAGAIN, so + * use it as a marker that we need to check variable + * length ioctls. + */ + return -EAGAIN; + } + + return 0; +} + +static long hidraw_rw_variable_size_ioctl(struct file *file, struct hidraw *dev, unsigned int cmd, + void __user *user_arg) +{ + int len = _IOC_SIZE(cmd); + + switch (cmd & ~IOCSIZE_MASK) { + case HIDIOCSFEATURE(0): + return hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT); + case HIDIOCGFEATURE(0): + return hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT); + case HIDIOCSINPUT(0): + return hidraw_send_report(file, user_arg, len, HID_INPUT_REPORT); + case HIDIOCGINPUT(0): + return hidraw_get_report(file, user_arg, len, HID_INPUT_REPORT); + case HIDIOCSOUTPUT(0): + return hidraw_send_report(file, user_arg, len, HID_OUTPUT_REPORT); + case HIDIOCGOUTPUT(0): + return hidraw_get_report(file, user_arg, len, HID_OUTPUT_REPORT); + } + + return -EINVAL; +} + +static long hidraw_ro_variable_size_ioctl(struct file *file, struct hidraw *dev, unsigned int cmd, + void __user *user_arg) +{ + struct hid_device *hid = dev->hid; + int len = _IOC_SIZE(cmd); + int field_len; + + switch (cmd & ~IOCSIZE_MASK) { + case HIDIOCGRAWNAME(0): + field_len = strlen(hid->name) + 1; + if (len > field_len) + len = field_len; + return copy_to_user(user_arg, hid->name, len) ? -EFAULT : len; + case HIDIOCGRAWPHYS(0): + field_len = strlen(hid->phys) + 1; + if (len > field_len) + len = field_len; + return copy_to_user(user_arg, hid->phys, len) ? -EFAULT : len; + case HIDIOCGRAWUNIQ(0): + field_len = strlen(hid->uniq) + 1; + if (len > field_len) + len = field_len; + return copy_to_user(user_arg, hid->uniq, len) ? -EFAULT : len; + } + + return -EINVAL; +} + +static long hidraw_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(file); unsigned int minor = iminor(inode); - long ret = 0; struct hidraw *dev; struct hidraw_list *list = file->private_data; - void __user *user_arg = (void __user*) arg; + void __user *user_arg = (void __user *)arg; + int ret; down_read(&minors_rwsem); dev = hidraw_table[minor]; @@ -411,124 +523,32 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, goto out; } - switch (cmd) { - case HIDIOCGRDESCSIZE: - if (put_user(dev->hid->rsize, (int __user *)arg)) - ret = -EFAULT; - break; - - case HIDIOCGRDESC: - { - __u32 len; - - if (get_user(len, (int __user *)arg)) - ret = -EFAULT; - else if (len > HID_MAX_DESCRIPTOR_SIZE - 1) - ret = -EINVAL; - else if (copy_to_user(user_arg + offsetof( - struct hidraw_report_descriptor, - value[0]), - dev->hid->rdesc, - min(dev->hid->rsize, len))) - ret = -EFAULT; - break; - } - case HIDIOCGRAWINFO: - { - struct hidraw_devinfo dinfo; - - dinfo.bustype = dev->hid->bus; - dinfo.vendor = dev->hid->vendor; - dinfo.product = dev->hid->product; - if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) - ret = -EFAULT; - break; - } - case HIDIOCREVOKE: - { - if (user_arg) - ret = -EINVAL; - else - ret = hidraw_revoke(list); - break; - } - default: - { - struct hid_device *hid = dev->hid; - if (_IOC_TYPE(cmd) != 'H') { - ret = -EINVAL; - break; - } - - if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) { - int len = _IOC_SIZE(cmd); - ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT); - break; - } - if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) { - int len = _IOC_SIZE(cmd); - ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT); - break; - } - - if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSINPUT(0))) { - int len = _IOC_SIZE(cmd); - ret = hidraw_send_report(file, user_arg, len, HID_INPUT_REPORT); - break; - } - if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGINPUT(0))) { - int len = _IOC_SIZE(cmd); - ret = hidraw_get_report(file, user_arg, len, HID_INPUT_REPORT); - break; - } - - if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSOUTPUT(0))) { - int len = _IOC_SIZE(cmd); - ret = hidraw_send_report(file, user_arg, len, HID_OUTPUT_REPORT); - break; - } - if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGOUTPUT(0))) { - int len = _IOC_SIZE(cmd); - ret = hidraw_get_report(file, user_arg, len, HID_OUTPUT_REPORT); - break; - } - - /* Begin Read-only ioctls. */ - if (_IOC_DIR(cmd) != _IOC_READ) { - ret = -EINVAL; - break; - } - - if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) { - int len = strlen(hid->name) + 1; - if (len > _IOC_SIZE(cmd)) - len = _IOC_SIZE(cmd); - ret = copy_to_user(user_arg, hid->name, len) ? - -EFAULT : len; - break; - } - - if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) { - int len = strlen(hid->phys) + 1; - if (len > _IOC_SIZE(cmd)) - len = _IOC_SIZE(cmd); - ret = copy_to_user(user_arg, hid->phys, len) ? - -EFAULT : len; - break; - } - - if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWUNIQ(0))) { - int len = strlen(hid->uniq) + 1; - if (len > _IOC_SIZE(cmd)) - len = _IOC_SIZE(cmd); - ret = copy_to_user(user_arg, hid->uniq, len) ? - -EFAULT : len; - break; - } - } - - ret = -ENOTTY; + if (_IOC_TYPE(cmd) != 'H') { + ret = -EINVAL; + goto out; } + + if (_IOC_NR(cmd) > HIDIOCTL_LAST || _IOC_NR(cmd) == 0) { + ret = -ENOTTY; + goto out; + } + + ret = hidraw_fixed_size_ioctl(file, dev, cmd, user_arg); + if (ret != -EAGAIN) + goto out; + + switch (_IOC_DIR(cmd)) { + case (_IOC_READ | _IOC_WRITE): + ret = hidraw_rw_variable_size_ioctl(file, dev, cmd, user_arg); + break; + case _IOC_READ: + ret = hidraw_ro_variable_size_ioctl(file, dev, cmd, user_arg); + break; + default: + /* Any other IOC_DIR is wrong */ + ret = -EINVAL; + } + out: up_read(&minors_rwsem); return ret; diff --git a/include/uapi/linux/hidraw.h b/include/uapi/linux/hidraw.h index d5ee269864e0..ebd701b3c18d 100644 --- a/include/uapi/linux/hidraw.h +++ b/include/uapi/linux/hidraw.h @@ -48,6 +48,8 @@ struct hidraw_devinfo { #define HIDIOCGOUTPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0C, len) #define HIDIOCREVOKE _IOW('H', 0x0D, int) /* Revoke device access */ +#define HIDIOCTL_LAST _IOC_NR(HIDIOCREVOKE) + #define HIDRAW_FIRST_MINOR 0 #define HIDRAW_MAX_DEVICES 64 /* number of reports to buffer */ From d1dd75c6500c74b91c5286fd3277710371d3e3ca Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Sat, 13 Sep 2025 16:12:54 +0000 Subject: [PATCH 1598/2711] HID: core: Change hid_driver to use a const char* for name name is never mutated by the core HID stack. Making name a const char* simplifies passing the string from Rust to C. Otherwise, it becomes difficult to pass a 'static lifetime CStr from Rust to a char*, rather than a const char*, due to lack of guarantee that the underlying data of the CStr will not be mutated by the C code. Signed-off-by: Rahul Rameshbabu Signed-off-by: Benjamin Tissoires --- include/linux/hid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/hid.h b/include/linux/hid.h index 2cc4f1e4ea96..426b22ed42b4 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -816,7 +816,7 @@ struct hid_usage_id { * zero from them. */ struct hid_driver { - char *name; + const char *name; const struct hid_device_id *id_table; struct list_head dyn_list; From af8df709bf365f5583d31091280354e1ef0b201f Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 12 Sep 2025 14:05:02 +0530 Subject: [PATCH 1599/2711] PCI: qcom: Move host bridge 'phy' and 'reset' pointers to struct qcom_pcie_port DT binding allows specifying 'phy' and 'reset' properties in both host bridge and Root Port nodes, though specifying in the host bridge node is marked as deprecated. Still, the pcie-qcom driver should support both combinations for maintaining the DT backwards compatibility. For this purpose, the driver is holding the relevant pointers of these properties in two structs: struct qcom_pcie_port and struct qcom_pcie. However, this causes confusion and increases the driver complexity. Hence, move the pointers from struct qcom_pcie to struct qcom_pcie_port. As a result, even if these properties are specified in the host bridge node, the pointers will be stored in struct qcom_pcie_port as if the properties are specified in a single Root Port node. This logic simplifies the driver a lot. Suggested-by: Bjorn Helgaas Signed-off-by: Manivannan Sadhasivam Reviewed-by: Bjorn Helgaas Link: https://patch.msgid.link/20250912-pci-pwrctrl-perst-v3-2-3c0ac62b032c@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-qcom.c | 87 +++++++++++--------------- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index a93740ae602f..15d71109a2f7 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -279,8 +279,6 @@ struct qcom_pcie { void __iomem *elbi; /* DT elbi */ void __iomem *mhi; union qcom_pcie_resources res; - struct phy *phy; - struct gpio_desc *reset; struct icc_path *icc_mem; struct icc_path *icc_cpu; const struct qcom_pcie_cfg *cfg; @@ -297,11 +295,8 @@ static void qcom_perst_assert(struct qcom_pcie *pcie, bool assert) struct qcom_pcie_port *port; int val = assert ? 1 : 0; - if (list_empty(&pcie->ports)) - gpiod_set_value_cansleep(pcie->reset, val); - else - list_for_each_entry(port, &pcie->ports, list) - gpiod_set_value_cansleep(port->reset, val); + list_for_each_entry(port, &pcie->ports, list) + gpiod_set_value_cansleep(port->reset, val); usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); } @@ -1253,57 +1248,32 @@ static bool qcom_pcie_link_up(struct dw_pcie *pci) return val & PCI_EXP_LNKSTA_DLLLA; } -static void qcom_pcie_phy_exit(struct qcom_pcie *pcie) -{ - struct qcom_pcie_port *port; - - if (list_empty(&pcie->ports)) - phy_exit(pcie->phy); - else - list_for_each_entry(port, &pcie->ports, list) - phy_exit(port->phy); -} - static void qcom_pcie_phy_power_off(struct qcom_pcie *pcie) { struct qcom_pcie_port *port; - if (list_empty(&pcie->ports)) { - phy_power_off(pcie->phy); - } else { - list_for_each_entry(port, &pcie->ports, list) - phy_power_off(port->phy); - } + list_for_each_entry(port, &pcie->ports, list) + phy_power_off(port->phy); } static int qcom_pcie_phy_power_on(struct qcom_pcie *pcie) { struct qcom_pcie_port *port; - int ret = 0; + int ret; - if (list_empty(&pcie->ports)) { - ret = phy_set_mode_ext(pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC); + list_for_each_entry(port, &pcie->ports, list) { + ret = phy_set_mode_ext(port->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC); if (ret) return ret; - ret = phy_power_on(pcie->phy); - if (ret) + ret = phy_power_on(port->phy); + if (ret) { + qcom_pcie_phy_power_off(pcie); return ret; - } else { - list_for_each_entry(port, &pcie->ports, list) { - ret = phy_set_mode_ext(port->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC); - if (ret) - return ret; - - ret = phy_power_on(port->phy); - if (ret) { - qcom_pcie_phy_power_off(pcie); - return ret; - } } } - return ret; + return 0; } static int qcom_pcie_host_init(struct dw_pcie_rp *pp) @@ -1750,8 +1720,10 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pcie) return ret; err_port_del: - list_for_each_entry_safe(port, tmp, &pcie->ports, list) + list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + phy_exit(port->phy); list_del(&port->list); + } return ret; } @@ -1759,20 +1731,32 @@ err_port_del: static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie) { struct device *dev = pcie->pci->dev; + struct qcom_pcie_port *port; + struct gpio_desc *reset; + struct phy *phy; int ret; - pcie->phy = devm_phy_optional_get(dev, "pciephy"); - if (IS_ERR(pcie->phy)) - return PTR_ERR(pcie->phy); + phy = devm_phy_optional_get(dev, "pciephy"); + if (IS_ERR(phy)) + return PTR_ERR(phy); - pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH); - if (IS_ERR(pcie->reset)) - return PTR_ERR(pcie->reset); + reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH); + if (IS_ERR(reset)) + return PTR_ERR(reset); - ret = phy_init(pcie->phy); + ret = phy_init(phy); if (ret) return ret; + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->reset = reset; + port->phy = phy; + INIT_LIST_HEAD(&port->list); + list_add_tail(&port->list, &pcie->ports); + return 0; } @@ -1986,9 +1970,10 @@ static int qcom_pcie_probe(struct platform_device *pdev) err_host_deinit: dw_pcie_host_deinit(pp); err_phy_exit: - qcom_pcie_phy_exit(pcie); - list_for_each_entry_safe(port, tmp, &pcie->ports, list) + list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + phy_exit(port->phy); list_del(&port->list); + } err_pm_runtime_put: pm_runtime_put(dev); pm_runtime_disable(dev); From b76029bdd71054b17f62740fe9617d6b2ea601c3 Mon Sep 17 00:00:00 2001 From: Akiyoshi Kurita Date: Wed, 17 Sep 2025 15:37:29 +0900 Subject: [PATCH 1600/2711] staging: rtl8723bs: xmit: rephrase comment and drop extra space Rephrase the comment to avoid the "number of" construction and remove an extra leading space. Signed-off-by: Akiyoshi Kurita Link: https://lore.kernel.org/r/20250917063729.1450525-1-weibu@redadmin.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c index 842e19b53421..abb6fdfe7e1f 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c @@ -76,7 +76,7 @@ query_free_page: /* check if hardware tx fifo page is enough */ if (!rtw_hal_sdio_query_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num)) { if (!bUpdatePageNum) { - /* Total number of page is NOT available, so update current FIFO status */ + /* Total page count is not available, so update current FIFO status */ HalQueryTxBufferStatus8723BSdio(padapter); bUpdatePageNum = true; goto query_free_page; From 7d547c1c249872b7732767e483758cb4fcb2d99b Mon Sep 17 00:00:00 2001 From: Ze Huang Date: Sat, 13 Sep 2025 00:53:47 +0800 Subject: [PATCH 1601/2711] dt-bindings: usb: dwc3: add support for SpacemiT K1 Add support for the USB 3.0 Dual-Role Device (DRD) controller embedded in the SpacemiT K1 SoC. The controller is based on the Synopsys DesignWare Core USB 3 (DWC3) IP, supporting USB3.0 host mode and USB 2.0 DRD mode. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Ze Huang Link: https://lore.kernel.org/r/20250913-dwc3_generic-v8-1-b50f81f05f95@linux.dev Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250913-dwc3_generic-v8-1-b50f81f05f95@linux.dev --- .../bindings/usb/spacemit,k1-dwc3.yaml | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/spacemit,k1-dwc3.yaml diff --git a/Documentation/devicetree/bindings/usb/spacemit,k1-dwc3.yaml b/Documentation/devicetree/bindings/usb/spacemit,k1-dwc3.yaml new file mode 100644 index 000000000000..0f0b5e061ca1 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/spacemit,k1-dwc3.yaml @@ -0,0 +1,121 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/spacemit,k1-dwc3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SpacemiT K1 SuperSpeed DWC3 USB SoC Controller + +maintainers: + - Ze Huang + +description: | + The SpacemiT K1 embeds a DWC3 USB IP Core which supports Host functions + for USB 3.0 and DRD for USB 2.0. + + Key features: + - USB3.0 SuperSpeed and USB2.0 High/Full/Low-Speed support + - Supports low-power modes (USB2.0 suspend, USB3.0 U1/U2/U3) + - Internal DMA controller and flexible endpoint FIFO sizing + + Communication Interface: + - Use of PIPE3 (125MHz) interface for USB3.0 PHY + - Use of UTMI+ (30/60MHz) interface for USB2.0 PHY + +allOf: + - $ref: snps,dwc3-common.yaml# + +properties: + compatible: + const: spacemit,k1-dwc3 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: usbdrd30 + + interrupts: + maxItems: 1 + + phys: + items: + - description: phandle to USB2/HS PHY + - description: phandle to USB3/SS PHY + + phy-names: + items: + - const: usb2-phy + - const: usb3-phy + + resets: + items: + - description: USB3.0 AHB reset + - description: USB3.0 VCC reset + - description: USB3.0 PHY reset + + reset-names: + items: + - const: ahb + - const: vcc + - const: phy + + reset-delay: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 2 + description: delay after reset sequence [us] + + vbus-supply: + description: A phandle to the regulator supplying the VBUS voltage. + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - phys + - phy-names + - resets + - reset-names + +unevaluatedProperties: false + +examples: + - | + usb@c0a00000 { + compatible = "spacemit,k1-dwc3"; + reg = <0xc0a00000 0x10000>; + clocks = <&syscon_apmu 16>; + clock-names = "usbdrd30"; + interrupts = <125>; + phys = <&usb2phy>, <&usb3phy>; + phy-names = "usb2-phy", "usb3-phy"; + resets = <&syscon_apmu 8>, + <&syscon_apmu 9>, + <&syscon_apmu 10>; + reset-names = "ahb", "vcc", "phy"; + reset-delay = <2>; + vbus-supply = <&usb3_vbus>; + #address-cells = <1>; + #size-cells = <0>; + + hub_2_0: hub@1 { + compatible = "usb2109,2817"; + reg = <1>; + vdd-supply = <&usb3_vhub>; + peer-hub = <&hub_3_0>; + reset-gpios = <&gpio 3 28 1>; + }; + + hub_3_0: hub@2 { + compatible = "usb2109,817"; + reg = <2>; + vdd-supply = <&usb3_vhub>; + peer-hub = <&hub_2_0>; + reset-gpios = <&gpio 3 28 1>; + }; + }; From e0b6dc00c701e600e655417aab1e100b73de821a Mon Sep 17 00:00:00 2001 From: Ze Huang Date: Sat, 13 Sep 2025 00:53:48 +0800 Subject: [PATCH 1602/2711] usb: dwc3: add generic driver to support flattened To support flattened dwc3 dt model and drop the glue layer, introduce the `dwc3-generic` driver. This enables direct binding of the DWC3 core driver and offers an alternative to the existing glue driver `dwc3-of-simple`. Acked-by: Thinh Nguyen Signed-off-by: Ze Huang Link: https://lore.kernel.org/r/20250913-dwc3_generic-v8-2-b50f81f05f95@linux.dev Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250913-dwc3_generic-v8-2-b50f81f05f95@linux.dev --- drivers/usb/dwc3/Kconfig | 11 ++ drivers/usb/dwc3/Makefile | 1 + drivers/usb/dwc3/dwc3-generic-plat.c | 166 +++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 drivers/usb/dwc3/dwc3-generic-plat.c diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 310d182e10b5..4925d15084f8 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -189,4 +189,15 @@ config USB_DWC3_RTK or dual-role mode. Say 'Y' or 'M' if you have such device. +config USB_DWC3_GENERIC_PLAT + tristate "DWC3 Generic Platform Driver" + depends on OF && COMMON_CLK + default USB_DWC3 + help + Support USB3 functionality in simple SoC integrations. + Currently supports SpacemiT DWC USB3. Platforms using + dwc3-of-simple can easily switch to dwc3-generic by flattening + the dwc3 child node in the device tree. + Say 'Y' or 'M' here if your platform integrates DWC3 in a similar way. + endif diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 830e6c9e5fe0..96469e48ff9d 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -57,3 +57,4 @@ obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o obj-$(CONFIG_USB_DWC3_OCTEON) += dwc3-octeon.o obj-$(CONFIG_USB_DWC3_RTK) += dwc3-rtk.o +obj-$(CONFIG_USB_DWC3_GENERIC_PLAT) += dwc3-generic-plat.o diff --git a/drivers/usb/dwc3/dwc3-generic-plat.c b/drivers/usb/dwc3/dwc3-generic-plat.c new file mode 100644 index 000000000000..d96b20570002 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-generic-plat.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * dwc3-generic-plat.c - DesignWare USB3 generic platform driver + * + * Copyright (C) 2025 Ze Huang + * + * Inspired by dwc3-qcom.c and dwc3-of-simple.c + */ + +#include +#include +#include +#include "glue.h" + +struct dwc3_generic { + struct device *dev; + struct dwc3 dwc; + struct clk_bulk_data *clks; + int num_clocks; + struct reset_control *resets; +}; + +#define to_dwc3_generic(d) container_of((d), struct dwc3_generic, dwc) + +static void dwc3_generic_reset_control_assert(void *data) +{ + reset_control_assert(data); +} + +static int dwc3_generic_probe(struct platform_device *pdev) +{ + struct dwc3_probe_data probe_data = {}; + struct device *dev = &pdev->dev; + struct dwc3_generic *dwc3g; + struct resource *res; + int ret; + + dwc3g = devm_kzalloc(dev, sizeof(*dwc3g), GFP_KERNEL); + if (!dwc3g) + return -ENOMEM; + + dwc3g->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing memory resource\n"); + return -ENODEV; + } + + dwc3g->resets = devm_reset_control_array_get_optional_exclusive(dev); + if (IS_ERR(dwc3g->resets)) + return dev_err_probe(dev, PTR_ERR(dwc3g->resets), "failed to get resets\n"); + + ret = reset_control_assert(dwc3g->resets); + if (ret) + return dev_err_probe(dev, ret, "failed to assert resets\n"); + + /* Not strict timing, just for safety */ + udelay(2); + + ret = reset_control_deassert(dwc3g->resets); + if (ret) + return dev_err_probe(dev, ret, "failed to deassert resets\n"); + + ret = devm_add_action_or_reset(dev, dwc3_generic_reset_control_assert, dwc3g->resets); + if (ret) + return ret; + + ret = devm_clk_bulk_get_all_enabled(dwc3g->dev, &dwc3g->clks); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get clocks\n"); + + dwc3g->num_clocks = ret; + dwc3g->dwc.dev = dev; + probe_data.dwc = &dwc3g->dwc; + probe_data.res = res; + probe_data.ignore_clocks_and_resets = true; + ret = dwc3_core_probe(&probe_data); + if (ret) + return dev_err_probe(dev, ret, "failed to register DWC3 Core\n"); + + return 0; +} + +static void dwc3_generic_remove(struct platform_device *pdev) +{ + struct dwc3 *dwc = platform_get_drvdata(pdev); + struct dwc3_generic *dwc3g = to_dwc3_generic(dwc); + + dwc3_core_remove(dwc); + + clk_bulk_disable_unprepare(dwc3g->num_clocks, dwc3g->clks); +} + +static int dwc3_generic_suspend(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + struct dwc3_generic *dwc3g = to_dwc3_generic(dwc); + int ret; + + ret = dwc3_pm_suspend(dwc); + if (ret) + return ret; + + clk_bulk_disable_unprepare(dwc3g->num_clocks, dwc3g->clks); + + return 0; +} + +static int dwc3_generic_resume(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + struct dwc3_generic *dwc3g = to_dwc3_generic(dwc); + int ret; + + ret = clk_bulk_prepare_enable(dwc3g->num_clocks, dwc3g->clks); + if (ret) + return ret; + + ret = dwc3_pm_resume(dwc); + if (ret) + return ret; + + return 0; +} + +static int dwc3_generic_runtime_suspend(struct device *dev) +{ + return dwc3_runtime_suspend(dev_get_drvdata(dev)); +} + +static int dwc3_generic_runtime_resume(struct device *dev) +{ + return dwc3_runtime_resume(dev_get_drvdata(dev)); +} + +static int dwc3_generic_runtime_idle(struct device *dev) +{ + return dwc3_runtime_idle(dev_get_drvdata(dev)); +} + +static const struct dev_pm_ops dwc3_generic_dev_pm_ops = { + SYSTEM_SLEEP_PM_OPS(dwc3_generic_suspend, dwc3_generic_resume) + RUNTIME_PM_OPS(dwc3_generic_runtime_suspend, dwc3_generic_runtime_resume, + dwc3_generic_runtime_idle) +}; + +static const struct of_device_id dwc3_generic_of_match[] = { + { .compatible = "spacemit,k1-dwc3", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dwc3_generic_of_match); + +static struct platform_driver dwc3_generic_driver = { + .probe = dwc3_generic_probe, + .remove = dwc3_generic_remove, + .driver = { + .name = "dwc3-generic-plat", + .of_match_table = dwc3_generic_of_match, + .pm = pm_ptr(&dwc3_generic_dev_pm_ops), + }, +}; +module_platform_driver(dwc3_generic_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DesignWare USB3 generic platform driver"); From 41cf11946b9076383a2222bbf1ef57d64d033f66 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Tue, 16 Sep 2025 17:34:36 +0530 Subject: [PATCH 1603/2711] usb: xhci: plat: Facilitate using autosuspend for xhci plat devices Allow autosuspend to be used by xhci plat device. For Qualcomm SoCs, when in host mode, it is intended that the controller goes to suspend state to save power and wait for interrupts from connected peripheral to wake it up. This is particularly used in cases where a HID or Audio device is connected. In such scenarios, the usb controller can enter auto suspend and resume action after getting interrupts from the connected device. Signed-off-by: Krishna Kurapati Link: https://lore.kernel.org/r/20250916120436.3617598-1-krishna.kurapati@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 3a56d8f94519..b3f895505cbe 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -172,6 +172,7 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s return ret; pm_runtime_set_active(&pdev->dev); + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); From 368ed48a5ef52e384f54d5809f0a0b79ac567479 Mon Sep 17 00:00:00 2001 From: Forest Crossman Date: Mon, 15 Sep 2025 15:55:10 -0400 Subject: [PATCH 1604/2711] usb: mon: Increase BUFF_MAX to 64 MiB to support multi-MB URBs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The usbmon binary interface currently truncates captures of large transfers from higher-speed USB devices. Because a single event capture is limited to one-fifth of the total buffer size, the current maximum size of a captured URB is around 240 KiB. This is insufficient when capturing traffic from modern devices that use transfers of several hundred kilobytes or more, as truncated URBs can make it impossible for user-space USB analysis tools like Wireshark to properly defragment and reassemble higher-level protocol packets in the captured data. The root cause of this issue is the 1200 KiB BUFF_MAX limit, which has not been changed since the binary interface was introduced in 2006. To resolve this issue, this patch increases BUFF_MAX to 64 MiB. The original comment for BUFF_MAX based the limit's calculation on a saturated 480 Mbit/s bus. Applying the same logic to a modern USB 3.2 Gen 2×2 20 Gbit/s bus (~2500 MB/s over a 20ms window) indicates the buffer should be at least 50 MB. The new limit of 64 MiB covers that, plus a little extra for any overhead. With this change, both users and developers should now be able to debug and reverse engineer modern USB devices even when running unmodified distro kernels. Please note that this change does not affect the default buffer size. A larger buffer is only allocated when a user explicitly requests it via the MON_IOCT_RING_SIZE ioctl, so the change to the maximum buffer size should not unduly increase memory usage for users that don't deliberately request a larger buffer. Link: https://lore.kernel.org/CAO3ALPzdUkmMr0YMrODLeDSLZqNCkWcAP8NumuPHLjNJ8wC1kQ@mail.gmail.com Signed-off-by: Forest Crossman Acked-by: Alan Stern Link: https://lore.kernel.org/r/CAO3ALPxU5RzcoueC454L=WZ1qGMfAcnxm+T+p+9D8O9mcrUbCQ@mail.gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index c93b43f5bc46..e713fc5964b1 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -68,18 +68,20 @@ * The magic limit was calculated so that it allows the monitoring * application to pick data once in two ticks. This way, another application, * which presumably drives the bus, gets to hog CPU, yet we collect our data. - * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an - * enormous overhead built into the bus protocol, so we need about 1000 KB. + * + * Originally, for a 480 Mbit/s bus this required a buffer of about 1 MB. For + * modern 20 Gbps buses, this value increases to over 50 MB. The maximum + * buffer size is set to 64 MiB to accommodate this. * * This is still too much for most cases, where we just snoop a few * descriptor fetches for enumeration. So, the default is a "reasonable" - * amount for systems with HZ=250 and incomplete bus saturation. + * amount for typical, low-throughput use cases. * * XXX What about multi-megabyte URBs which take minutes to transfer? */ -#define BUFF_MAX CHUNK_ALIGN(1200*1024) -#define BUFF_DFL CHUNK_ALIGN(300*1024) -#define BUFF_MIN CHUNK_ALIGN(8*1024) +#define BUFF_MAX CHUNK_ALIGN(64*1024*1024) +#define BUFF_DFL CHUNK_ALIGN(300*1024) +#define BUFF_MIN CHUNK_ALIGN(8*1024) /* * The per-event API header (2 per URB). From 45fe729be9a6be326a1ca25af82d34de32ba2ce8 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Sep 2025 10:16:20 +0800 Subject: [PATCH 1605/2711] usb: typec: Stub out typec_switch APIs when CONFIG_TYPEC=n Ease driver development by adding stubs for the typec_switch APIs when CONFIG_TYPEC=n. Copy the same method used for the typec_mux APIs to be consistent. Acked-by: Greg Kroah-Hartman Reviewed-by: Heikki Krogerus Signed-off-by: Stephen Boyd Signed-off-by: Xu Yang Link: https://lore.kernel.org/r/20250916021620.1303995-1-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/typec_mux.h | 46 +++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/include/linux/usb/typec_mux.h b/include/linux/usb/typec_mux.h index 2489a7857d8e..aa9ebb7e2fe0 100644 --- a/include/linux/usb/typec_mux.h +++ b/include/linux/usb/typec_mux.h @@ -3,6 +3,7 @@ #ifndef __USB_TYPEC_MUX #define __USB_TYPEC_MUX +#include #include #include @@ -24,16 +25,13 @@ struct typec_switch_desc { void *drvdata; }; +#if IS_ENABLED(CONFIG_TYPEC) + struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode); void typec_switch_put(struct typec_switch *sw); int typec_switch_set(struct typec_switch *sw, enum typec_orientation orientation); -static inline struct typec_switch *typec_switch_get(struct device *dev) -{ - return fwnode_typec_switch_get(dev_fwnode(dev)); -} - struct typec_switch_dev * typec_switch_register(struct device *parent, const struct typec_switch_desc *desc); @@ -42,6 +40,44 @@ void typec_switch_unregister(struct typec_switch_dev *sw); void typec_switch_set_drvdata(struct typec_switch_dev *sw, void *data); void *typec_switch_get_drvdata(struct typec_switch_dev *sw); +#else + +static inline struct typec_switch * +fwnode_typec_switch_get(struct fwnode_handle *fwnode) +{ + return NULL; +} + +static inline void typec_switch_put(struct typec_switch *sw) {} + +static inline int typec_switch_set(struct typec_switch *sw, + enum typec_orientation orientation) +{ + return 0; +} + +static inline struct typec_switch_dev * +typec_switch_register(struct device *parent, + const struct typec_switch_desc *desc) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline void typec_switch_unregister(struct typec_switch_dev *sw) {} + +static inline void typec_switch_set_drvdata(struct typec_switch_dev *sw, void *data) {} +static inline void *typec_switch_get_drvdata(struct typec_switch_dev *sw) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +#endif /* CONFIG_TYPEC */ + +static inline struct typec_switch *typec_switch_get(struct device *dev) +{ + return fwnode_typec_switch_get(dev_fwnode(dev)); +} + struct typec_mux_state { struct typec_altmode *alt; unsigned long mode; From cfd6f1a7b42f62523c96d9703ef32b0dbc495ba4 Mon Sep 17 00:00:00 2001 From: Owen Gu Date: Mon, 15 Sep 2025 17:29:07 +0800 Subject: [PATCH 1606/2711] usb: gadget: f_fs: Fix epfile null pointer access after ep enable. A race condition occurs when ffs_func_eps_enable() runs concurrently with ffs_data_reset(). The ffs_data_clear() called in ffs_data_reset() sets ffs->epfiles to NULL before resetting ffs->eps_count to 0, leading to a NULL pointer dereference when accessing epfile->ep in ffs_func_eps_enable() after successful usb_ep_enable(). The ffs->epfiles pointer is set to NULL in both ffs_data_clear() and ffs_data_close() functions, and its modification is protected by the spinlock ffs->eps_lock. And the whole ffs_func_eps_enable() function is also protected by ffs->eps_lock. Thus, add NULL pointer handling for ffs->epfiles in the ffs_func_eps_enable() function to fix issues Signed-off-by: Owen Gu Link: https://lore.kernel.org/r/20250915092907.17802-1-guhuinan@xiaomi.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 08a251df20c4..04058261cdd0 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2407,7 +2407,12 @@ static int ffs_func_eps_enable(struct ffs_function *func) ep = func->eps; epfile = ffs->epfiles; count = ffs->eps_count; - while(count--) { + if (!epfile) { + ret = -ENOMEM; + goto done; + } + + while (count--) { ep->ep->driver_data = ep; ret = config_ep_by_speed(func->gadget, &func->function, ep->ep); @@ -2431,6 +2436,7 @@ static int ffs_func_eps_enable(struct ffs_function *func) } wake_up_interruptible(&ffs->wait); +done: spin_unlock_irqrestore(&func->ffs->eps_lock, flags); return ret; From dd0d2618e3f815a030622599e540d3be1964a888 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 16 Sep 2025 16:02:39 +0100 Subject: [PATCH 1607/2711] dt-bindings: usb: Document Renesas RZ/G3E USB3HOST Document the Renesas RZ/G3E USB3.2 Gen2 Host Controller (a.k.a USB3HOST). The USB3HOST is compliant with the Universal Serial Bus 3.2 Specification Revision 1.0. - Supports 1 downstream USB receptacles - Number of SSP Gen2 or SS ports: 1 - Number of HS or FS or LS ports: 1 - Supports Super Speed Plus Gen2x1 (10 Gbps), Super Speed (5 Gbps), High Speed (480 Mbps), Full Speed (12Mbps), and Low Speed (1.5 Mbps). - Supports all transfer-types: Control, Bulk, Interrupt, Isochronous, and these split-transactions. - Supports Power Control and Over Current Detection. Reviewed-by: Rob Herring (Arm) Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250916150255.4231-4-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/renesas,rzg3e-xhci.yaml | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/renesas,rzg3e-xhci.yaml diff --git a/Documentation/devicetree/bindings/usb/renesas,rzg3e-xhci.yaml b/Documentation/devicetree/bindings/usb/renesas,rzg3e-xhci.yaml new file mode 100644 index 000000000000..98260f9fb442 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/renesas,rzg3e-xhci.yaml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/renesas,rzg3e-xhci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas RZ/G3E USB 3.2 Gen2 Host controller + +maintainers: + - Biju Das + +properties: + compatible: + const: renesas,r9a09g047-xhci + + reg: + maxItems: 1 + + interrupts: + items: + - description: Logical OR of all interrupt signals. + - description: System management interrupt + - description: Host system error interrupt + - description: Power management event interrupt + - description: xHC interrupt + + interrupt-names: + items: + - const: all + - const: smi + - const: hse + - const: pme + - const: xhc + + clocks: + maxItems: 1 + + phys: + maxItems: 2 + + phy-names: + items: + - const: usb2-phy + - const: usb3-phy + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - power-domains + - resets + - phys + - phy-names + +allOf: + - $ref: usb-xhci.yaml + +additionalProperties: false + +examples: + - | + #include + #include + + usb@15850000 { + compatible = "renesas,r9a09g047-xhci"; + reg = <0x15850000 0x10000>; + interrupts = , + , + , + , + ; + interrupt-names = "all", "smi", "hse", "pme", "xhc"; + clocks = <&cpg CPG_MOD 0xaf>; + power-domains = <&cpg>; + resets = <&cpg 0xaa>; + phys = <&usb3_phy>, <&usb3_phy>; + phy-names = "usb2-phy", "usb3-phy"; + }; From f7acd12eba05fb9e7dba3222e2aeca5f49d38b3a Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 16 Sep 2025 16:02:40 +0100 Subject: [PATCH 1608/2711] usb: host: xhci-rcar: Move R-Car reg definitions Move xhci-rcar reg definitions to a header file for the preparation of adding support for RZ/G3E XHCI that has different register definitions. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250916150255.4231-5-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-rcar-regs.h | 49 +++++++++++++++++++++++++++++++ drivers/usb/host/xhci-rcar.c | 45 +--------------------------- 2 files changed, 50 insertions(+), 44 deletions(-) create mode 100644 drivers/usb/host/xhci-rcar-regs.h diff --git a/drivers/usb/host/xhci-rcar-regs.h b/drivers/usb/host/xhci-rcar-regs.h new file mode 100644 index 000000000000..5ecbda858be0 --- /dev/null +++ b/drivers/usb/host/xhci-rcar-regs.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __XHCI_RCAR_H +#define __XHCI_RCAR_H + +/*** Register Offset ***/ +#define RCAR_USB3_AXH_STA 0x104 /* AXI Host Control Status */ +#define RCAR_USB3_INT_ENA 0x224 /* Interrupt Enable */ +#define RCAR_USB3_DL_CTRL 0x250 /* FW Download Control & Status */ +#define RCAR_USB3_FW_DATA0 0x258 /* FW Data0 */ + +#define RCAR_USB3_LCLK 0xa44 /* LCLK Select */ +#define RCAR_USB3_CONF1 0xa48 /* USB3.0 Configuration1 */ +#define RCAR_USB3_CONF2 0xa5c /* USB3.0 Configuration2 */ +#define RCAR_USB3_CONF3 0xaa8 /* USB3.0 Configuration3 */ +#define RCAR_USB3_RX_POL 0xab0 /* USB3.0 RX Polarity */ +#define RCAR_USB3_TX_POL 0xab8 /* USB3.0 TX Polarity */ + +/*** Register Settings ***/ +/* AXI Host Control Status */ +#define RCAR_USB3_AXH_STA_B3_PLL_ACTIVE 0x00010000 +#define RCAR_USB3_AXH_STA_B2_PLL_ACTIVE 0x00000001 +#define RCAR_USB3_AXH_STA_PLL_ACTIVE_MASK (RCAR_USB3_AXH_STA_B3_PLL_ACTIVE | \ + RCAR_USB3_AXH_STA_B2_PLL_ACTIVE) + +/* Interrupt Enable */ +#define RCAR_USB3_INT_XHC_ENA 0x00000001 +#define RCAR_USB3_INT_PME_ENA 0x00000002 +#define RCAR_USB3_INT_HSE_ENA 0x00000004 +#define RCAR_USB3_INT_ENA_VAL (RCAR_USB3_INT_XHC_ENA | \ + RCAR_USB3_INT_PME_ENA | RCAR_USB3_INT_HSE_ENA) + +/* FW Download Control & Status */ +#define RCAR_USB3_DL_CTRL_ENABLE 0x00000001 +#define RCAR_USB3_DL_CTRL_FW_SUCCESS 0x00000010 +#define RCAR_USB3_DL_CTRL_FW_SET_DATA0 0x00000100 + +/* LCLK Select */ +#define RCAR_USB3_LCLK_ENA_VAL 0x01030001 + +/* USB3.0 Configuration */ +#define RCAR_USB3_CONF1_VAL 0x00030204 +#define RCAR_USB3_CONF2_VAL 0x00030300 +#define RCAR_USB3_CONF3_VAL 0x13802007 + +/* USB3.0 Polarity */ +#define RCAR_USB3_RX_POL_VAL BIT(21) +#define RCAR_USB3_TX_POL_VAL BIT(4) + +#endif /* __XHCI_RCAR_H */ diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 1cc082a3b793..6d4662def87f 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -14,6 +14,7 @@ #include "xhci.h" #include "xhci-plat.h" +#include "xhci-rcar-regs.h" #include "xhci-rzv2m.h" #define XHCI_RCAR_FIRMWARE_NAME_V1 "r8a779x_usb3_v1.dlmem" @@ -29,50 +30,6 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V1); MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); -/*** Register Offset ***/ -#define RCAR_USB3_AXH_STA 0x104 /* AXI Host Control Status */ -#define RCAR_USB3_INT_ENA 0x224 /* Interrupt Enable */ -#define RCAR_USB3_DL_CTRL 0x250 /* FW Download Control & Status */ -#define RCAR_USB3_FW_DATA0 0x258 /* FW Data0 */ - -#define RCAR_USB3_LCLK 0xa44 /* LCLK Select */ -#define RCAR_USB3_CONF1 0xa48 /* USB3.0 Configuration1 */ -#define RCAR_USB3_CONF2 0xa5c /* USB3.0 Configuration2 */ -#define RCAR_USB3_CONF3 0xaa8 /* USB3.0 Configuration3 */ -#define RCAR_USB3_RX_POL 0xab0 /* USB3.0 RX Polarity */ -#define RCAR_USB3_TX_POL 0xab8 /* USB3.0 TX Polarity */ - -/*** Register Settings ***/ -/* AXI Host Control Status */ -#define RCAR_USB3_AXH_STA_B3_PLL_ACTIVE 0x00010000 -#define RCAR_USB3_AXH_STA_B2_PLL_ACTIVE 0x00000001 -#define RCAR_USB3_AXH_STA_PLL_ACTIVE_MASK (RCAR_USB3_AXH_STA_B3_PLL_ACTIVE | \ - RCAR_USB3_AXH_STA_B2_PLL_ACTIVE) - -/* Interrupt Enable */ -#define RCAR_USB3_INT_XHC_ENA 0x00000001 -#define RCAR_USB3_INT_PME_ENA 0x00000002 -#define RCAR_USB3_INT_HSE_ENA 0x00000004 -#define RCAR_USB3_INT_ENA_VAL (RCAR_USB3_INT_XHC_ENA | \ - RCAR_USB3_INT_PME_ENA | RCAR_USB3_INT_HSE_ENA) - -/* FW Download Control & Status */ -#define RCAR_USB3_DL_CTRL_ENABLE 0x00000001 -#define RCAR_USB3_DL_CTRL_FW_SUCCESS 0x00000010 -#define RCAR_USB3_DL_CTRL_FW_SET_DATA0 0x00000100 - -/* LCLK Select */ -#define RCAR_USB3_LCLK_ENA_VAL 0x01030001 - -/* USB3.0 Configuration */ -#define RCAR_USB3_CONF1_VAL 0x00030204 -#define RCAR_USB3_CONF2_VAL 0x00030300 -#define RCAR_USB3_CONF3_VAL 0x13802007 - -/* USB3.0 Polarity */ -#define RCAR_USB3_RX_POL_VAL BIT(21) -#define RCAR_USB3_TX_POL_VAL BIT(4) - static void xhci_rcar_start_gen2(struct usb_hcd *hcd) { /* LCLK Select */ From 2ef16e4eb41fe711479d92805e4b9e430c7bbefd Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 16 Sep 2025 16:02:41 +0100 Subject: [PATCH 1609/2711] usb: host: xhci-plat: Add .post_resume_quirk for struct xhci_plat_priv Some SoCs (eg Renesas RZ/G3E SoC) have special sequence after xhci_resume, add .post_resume_quick for it. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250916150255.4231-6-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 14 ++++++++++++++ drivers/usb/host/xhci-plat.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index b3f895505cbe..074d9c731639 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -75,6 +75,16 @@ static int xhci_priv_resume_quirk(struct usb_hcd *hcd) return priv->resume_quirk(hcd); } +static int xhci_priv_post_resume_quirk(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (!priv->post_resume_quirk) + return 0; + + return priv->post_resume_quirk(hcd); +} + static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) { struct xhci_plat_priv *priv = xhci_to_priv(xhci); @@ -530,6 +540,10 @@ static int xhci_plat_resume_common(struct device *dev, bool power_lost) if (ret) goto disable_clks; + ret = xhci_priv_post_resume_quirk(hcd); + if (ret) + goto disable_clks; + pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h index 2b32a93d2b76..00751d851831 100644 --- a/drivers/usb/host/xhci-plat.h +++ b/drivers/usb/host/xhci-plat.h @@ -21,6 +21,7 @@ struct xhci_plat_priv { int (*init_quirk)(struct usb_hcd *); int (*suspend_quirk)(struct usb_hcd *); int (*resume_quirk)(struct usb_hcd *); + int (*post_resume_quirk)(struct usb_hcd *); }; #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv) From 5db5025d32e5b0b4c13198b5570f33d92ae941d3 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 16 Sep 2025 16:02:42 +0100 Subject: [PATCH 1610/2711] usb: host: xhci-rcar: Add Renesas RZ/G3E USB3 Host driver support The USB3.2 Gen2 Host controller (a.k.a USB3HOST), IP found on the RZ/G3E SoC is similar to R-Car XHCI, but it doesn't require any firmware. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20250916150255.4231-7-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 2 +- drivers/usb/host/xhci-rcar.c | 55 ++++++++++++++++++++++++++++++ drivers/usb/host/xhci-rzg3e-regs.h | 12 +++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/host/xhci-rzg3e-regs.h diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 109100cc77a3..c4f17ce5c77b 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -93,7 +93,7 @@ config USB_XHCI_RCAR default ARCH_RENESAS help Say 'Y' to enable the support for the xHCI host controller - found in Renesas R-Car ARM SoCs. + found in Renesas R-Car and RZ/G3E alike ARM SoCs. config USB_XHCI_RZV2M bool "xHCI support for Renesas RZ/V2M SoC" diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 6d4662def87f..8a993ee21c87 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -11,10 +11,12 @@ #include #include #include +#include #include "xhci.h" #include "xhci-plat.h" #include "xhci-rcar-regs.h" +#include "xhci-rzg3e-regs.h" #include "xhci-rzv2m.h" #define XHCI_RCAR_FIRMWARE_NAME_V1 "r8a779x_usb3_v1.dlmem" @@ -67,6 +69,48 @@ static void xhci_rcar_start(struct usb_hcd *hcd) } } +static void xhci_rzg3e_start(struct usb_hcd *hcd) +{ + u32 int_en; + + if (hcd->regs) { + /* Update the controller initial setting */ + writel(0x03130200, hcd->regs + RZG3E_USB3_HOST_U3P0PIPESC(0)); + writel(0x00160200, hcd->regs + RZG3E_USB3_HOST_U3P0PIPESC(1)); + writel(0x03150000, hcd->regs + RZG3E_USB3_HOST_U3P0PIPESC(2)); + writel(0x03130200, hcd->regs + RZG3E_USB3_HOST_U3P0PIPESC(3)); + writel(0x00180000, hcd->regs + RZG3E_USB3_HOST_U3P0PIPESC(4)); + + /* Interrupt Enable */ + int_en = readl(hcd->regs + RZG3E_USB3_HOST_INTEN); + int_en |= RZG3E_USB3_HOST_INTEN_ENA; + writel(int_en, hcd->regs + RZG3E_USB3_HOST_INTEN); + } +} + +static int xhci_rzg3e_resume(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + return reset_control_deassert(xhci->reset); +} + +static int xhci_rzg3e_post_resume(struct usb_hcd *hcd) +{ + xhci_rzg3e_start(hcd); + + return 0; +} + +static int xhci_rzg3e_suspend(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + reset_control_assert(xhci->reset); + + return 0; +} + static int xhci_rcar_download_firmware(struct usb_hcd *hcd) { struct device *dev = hcd->self.controller; @@ -190,6 +234,14 @@ static const struct xhci_plat_priv xhci_plat_renesas_rzv2m = { .plat_start = xhci_rzv2m_start, }; +static const struct xhci_plat_priv xhci_plat_renesas_rzg3e = { + .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_RESET_ON_RESUME | XHCI_SUSPEND_RESUME_CLKS, + .plat_start = xhci_rzg3e_start, + .suspend_quirk = xhci_rzg3e_suspend, + .resume_quirk = xhci_rzg3e_resume, + .post_resume_quirk = xhci_rzg3e_post_resume, +}; + static const struct of_device_id usb_xhci_of_match[] = { { .compatible = "renesas,xhci-r8a7790", @@ -206,6 +258,9 @@ static const struct of_device_id usb_xhci_of_match[] = { }, { .compatible = "renesas,xhci-r8a7796", .data = &xhci_plat_renesas_rcar_gen3, + }, { + .compatible = "renesas,r9a09g047-xhci", + .data = &xhci_plat_renesas_rzg3e, }, { .compatible = "renesas,rcar-gen2-xhci", .data = &xhci_plat_renesas_rcar_gen2, diff --git a/drivers/usb/host/xhci-rzg3e-regs.h b/drivers/usb/host/xhci-rzg3e-regs.h new file mode 100644 index 000000000000..7a244a47b882 --- /dev/null +++ b/drivers/usb/host/xhci-rzg3e-regs.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __XHCI_RZG3E_H +#define __XHCI_RZG3E_H + +#define RZG3E_USB3_HOST_INTEN 0x1044 /* Interrupt Enable */ +#define RZG3E_USB3_HOST_U3P0PIPESC(x) (0x10c0 + (x) * 4) /* PIPE Status and Control Register */ + +#define RZG3E_USB3_HOST_INTEN_XHC BIT(0) +#define RZG3E_USB3_HOST_INTEN_HSE BIT(2) +#define RZG3E_USB3_HOST_INTEN_ENA (RZG3E_USB3_HOST_INTEN_XHC | RZG3E_USB3_HOST_INTEN_HSE) + +#endif /* __XHCI_RZG3E_H */ From bfb1d99d969fe3b892db30848aeebfa19d21f57f Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Tue, 16 Sep 2025 16:21:32 +0800 Subject: [PATCH 1611/2711] usb: gadget: Store endpoint pointer in usb_request Gadget function drivers often have goto-based error handling in their bind paths, which can be bug-prone. Refactoring these paths to use __free() scope-based cleanup is desirable, but currently blocked. The blocker is that usb_ep_free_request(ep, req) requires two parameters, while the __free() mechanism can only pass a pointer to the request itself. Store an endpoint pointer in the struct usb_request. The pointer is populated centrally in usb_ep_alloc_request() on every successful allocation, making the request object self-contained. Signed-off-by: Kuen-Han Tsai Link: https://lore.kernel.org/r/20250916-ready-v1-1-4997bf277548@google.com Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250916-ready-v1-1-4997bf277548@google.com --- drivers/usb/gadget/udc/core.c | 3 +++ include/linux/usb/gadget.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index d709e24c1fd4..e3d63b8fa0f4 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -194,6 +194,9 @@ struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, req = ep->ops->alloc_request(ep, gfp_flags); + if (req) + req->ep = ep; + trace_usb_ep_alloc_request(ep, req, req ? 0 : -ENOMEM); return req; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 0f28c5512fcb..0f2079476088 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -32,6 +32,7 @@ struct usb_ep; /** * struct usb_request - describes one i/o request + * @ep: The associated endpoint set by usb_ep_alloc_request(). * @buf: Buffer used for data. Always provide this; some controllers * only use PIO, or don't use DMA for some endpoints. * @dma: DMA address corresponding to 'buf'. If you don't set this @@ -98,6 +99,7 @@ struct usb_ep; */ struct usb_request { + struct usb_ep *ep; void *buf; unsigned length; dma_addr_t dma; From 201c53c687f2b55a7cc6d9f4000af4797860174b Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Tue, 16 Sep 2025 16:21:33 +0800 Subject: [PATCH 1612/2711] usb: gadget: Introduce free_usb_request helper Introduce the free_usb_request() function that frees both the request's buffer and the request itself. This function serves as the cleanup callback for DEFINE_FREE() to enable automatic, scope-based cleanup for usb_request pointers. Signed-off-by: Kuen-Han Tsai Link: https://lore.kernel.org/r/20250916-ready-v1-2-4997bf277548@google.com Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250916-ready-v1-2-4997bf277548@google.com --- include/linux/usb/gadget.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 0f2079476088..3aaf19e77558 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -15,6 +15,7 @@ #ifndef __LINUX_USB_GADGET_H #define __LINUX_USB_GADGET_H +#include #include #include #include @@ -293,6 +294,28 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep) /*-------------------------------------------------------------------------*/ +/** + * free_usb_request - frees a usb_request object and its buffer + * @req: the request being freed + * + * This helper function frees both the request's buffer and the request object + * itself by calling usb_ep_free_request(). Its signature is designed to be used + * with DEFINE_FREE() to enable automatic, scope-based cleanup for usb_request + * pointers. + */ +static inline void free_usb_request(struct usb_request *req) +{ + if (!req) + return; + + kfree(req->buf); + usb_ep_free_request(req->ep, req); +} + +DEFINE_FREE(free_usb_request, struct usb_request *, free_usb_request(_T)) + +/*-------------------------------------------------------------------------*/ + struct usb_dcd_config_params { __u8 bU1devExitLat; /* U1 Device exit Latency */ #define USB_DEFAULT_U1_DEV_EXIT_LAT 0x01 /* Less then 1 microsec */ From 75a5b8d4ddd4eb6b16cb0b475d14ff4ae64295ef Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Tue, 16 Sep 2025 16:21:34 +0800 Subject: [PATCH 1613/2711] usb: gadget: f_ncm: Refactor bind path to use __free() After an bind/unbind cycle, the ncm->notify_req is left stale. If a subsequent bind fails, the unified error label attempts to free this stale request, leading to a NULL pointer dereference when accessing ep->ops->free_request. Refactor the error handling in the bind path to use the __free() automatic cleanup mechanism. Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020 Call trace: usb_ep_free_request+0x2c/0xec ncm_bind+0x39c/0x3dc usb_add_function+0xcc/0x1f0 configfs_composite_bind+0x468/0x588 gadget_bind_driver+0x104/0x270 really_probe+0x190/0x374 __driver_probe_device+0xa0/0x12c driver_probe_device+0x3c/0x218 __device_attach_driver+0x14c/0x188 bus_for_each_drv+0x10c/0x168 __device_attach+0xfc/0x198 device_initial_probe+0x14/0x24 bus_probe_device+0x94/0x11c device_add+0x268/0x48c usb_add_gadget+0x198/0x28c dwc3_gadget_init+0x700/0x858 __dwc3_set_mode+0x3cc/0x664 process_scheduled_works+0x1d8/0x488 worker_thread+0x244/0x334 kthread+0x114/0x1bc ret_from_fork+0x10/0x20 Fixes: 9f6ce4240a2b ("usb: gadget: f_ncm.c added") Cc: stable@kernel.org Signed-off-by: Kuen-Han Tsai Link: https://lore.kernel.org/r/20250916-ready-v1-3-4997bf277548@google.com Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250916-ready-v1-3-4997bf277548@google.com --- drivers/usb/gadget/function/f_ncm.c | 78 ++++++++++++----------------- 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 58b0dd575af3..0148d60926dc 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -11,6 +11,7 @@ * Copyright (C) 2008 Nokia Corporation */ +#include #include #include #include @@ -20,6 +21,7 @@ #include #include +#include #include "u_ether.h" #include "u_ether_configfs.h" @@ -1436,18 +1438,18 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; struct f_ncm_opts *ncm_opts; + struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; + struct usb_request *request __free(free_usb_request) = NULL; + if (!can_support_ecm(cdev->gadget)) return -EINVAL; ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); if (cdev->use_os_string) { - f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), - GFP_KERNEL); - if (!f->os_desc_table) + os_desc_table = kzalloc(sizeof(*os_desc_table), GFP_KERNEL); + if (!os_desc_table) return -ENOMEM; - f->os_desc_n = 1; - f->os_desc_table[0].os_desc = &ncm_opts->ncm_os_desc; } mutex_lock(&ncm_opts->lock); @@ -1459,16 +1461,15 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) mutex_unlock(&ncm_opts->lock); if (status) - goto fail; + return status; ncm_opts->bound = true; us = usb_gstrings_attach(cdev, ncm_strings, ARRAY_SIZE(ncm_string_defs)); - if (IS_ERR(us)) { - status = PTR_ERR(us); - goto fail; - } + if (IS_ERR(us)) + return PTR_ERR(us); + ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id; ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id; ncm_data_intf.iInterface = us[STRING_DATA_IDX].id; @@ -1478,20 +1479,16 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) - goto fail; + return status; ncm->ctrl_id = status; ncm_iad_desc.bFirstInterface = status; ncm_control_intf.bInterfaceNumber = status; ncm_union_desc.bMasterInterface0 = status; - if (cdev->use_os_string) - f->os_desc_table[0].if_id = - ncm_iad_desc.bFirstInterface; - status = usb_interface_id(c, f); if (status < 0) - goto fail; + return status; ncm->data_id = status; ncm_data_nop_intf.bInterfaceNumber = status; @@ -1500,35 +1497,31 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) ecm_desc.wMaxSegmentSize = cpu_to_le16(ncm_opts->max_segment_size); - status = -ENODEV; - /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_in_desc); if (!ep) - goto fail; + return -ENODEV; ncm->port.in_ep = ep; ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_out_desc); if (!ep) - goto fail; + return -ENODEV; ncm->port.out_ep = ep; ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_notify_desc); if (!ep) - goto fail; + return -ENODEV; ncm->notify = ep; - status = -ENOMEM; - /* allocate notification request and buffer */ - ncm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!ncm->notify_req) - goto fail; - ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT, GFP_KERNEL); - if (!ncm->notify_req->buf) - goto fail; - ncm->notify_req->context = ncm; - ncm->notify_req->complete = ncm_notify_complete; + request = usb_ep_alloc_request(ep, GFP_KERNEL); + if (!request) + return -ENOMEM; + request->buf = kmalloc(NCM_STATUS_BYTECOUNT, GFP_KERNEL); + if (!request->buf) + return -ENOMEM; + request->context = ncm; + request->complete = ncm_notify_complete; /* * support all relevant hardware speeds... we expect that when @@ -1548,7 +1541,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function, ncm_ss_function, ncm_ss_function); if (status) - goto fail; + return status; /* * NOTE: all that is done without knowing or caring about @@ -1561,23 +1554,18 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) hrtimer_setup(&ncm->task_timer, ncm_tx_timeout, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); + if (cdev->use_os_string) { + os_desc_table[0].os_desc = &ncm_opts->ncm_os_desc; + os_desc_table[0].if_id = ncm_iad_desc.bFirstInterface; + f->os_desc_table = no_free_ptr(os_desc_table); + f->os_desc_n = 1; + } + ncm->notify_req = no_free_ptr(request); + DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n", ncm->port.in_ep->name, ncm->port.out_ep->name, ncm->notify->name); return 0; - -fail: - kfree(f->os_desc_table); - f->os_desc_n = 0; - - if (ncm->notify_req) { - kfree(ncm->notify_req->buf); - usb_ep_free_request(ncm->notify, ncm->notify_req); - } - - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; } static inline struct f_ncm_opts *to_f_ncm_opts(struct config_item *item) From 47b2116e54b4a854600341487e8b55249e926324 Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Tue, 16 Sep 2025 16:21:35 +0800 Subject: [PATCH 1614/2711] usb: gadget: f_acm: Refactor bind path to use __free() After an bind/unbind cycle, the acm->notify_req is left stale. If a subsequent bind fails, the unified error label attempts to free this stale request, leading to a NULL pointer dereference when accessing ep->ops->free_request. Refactor the error handling in the bind path to use the __free() automatic cleanup mechanism. Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020 Call trace: usb_ep_free_request+0x2c/0xec gs_free_req+0x30/0x44 acm_bind+0x1b8/0x1f4 usb_add_function+0xcc/0x1f0 configfs_composite_bind+0x468/0x588 gadget_bind_driver+0x104/0x270 really_probe+0x190/0x374 __driver_probe_device+0xa0/0x12c driver_probe_device+0x3c/0x218 __device_attach_driver+0x14c/0x188 bus_for_each_drv+0x10c/0x168 __device_attach+0xfc/0x198 device_initial_probe+0x14/0x24 bus_probe_device+0x94/0x11c device_add+0x268/0x48c usb_add_gadget+0x198/0x28c dwc3_gadget_init+0x700/0x858 __dwc3_set_mode+0x3cc/0x664 process_scheduled_works+0x1d8/0x488 worker_thread+0x244/0x334 kthread+0x114/0x1bc ret_from_fork+0x10/0x20 Fixes: 1f1ba11b6494 ("usb gadget: issue notifications from ACM function") Cc: stable@kernel.org Signed-off-by: Kuen-Han Tsai Link: https://lore.kernel.org/r/20250916-ready-v1-4-4997bf277548@google.com Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250916-ready-v1-4-4997bf277548@google.com --- drivers/usb/gadget/function/f_acm.c | 42 +++++++++++++---------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c index 7061720b9732..106046e17c4e 100644 --- a/drivers/usb/gadget/function/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -11,12 +11,15 @@ /* #define VERBOSE_DEBUG */ +#include #include #include #include #include #include +#include + #include "u_serial.h" @@ -613,6 +616,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) struct usb_string *us; int status; struct usb_ep *ep; + struct usb_request *request __free(free_usb_request) = NULL; /* REVISIT might want instance-specific strings to help * distinguish instances ... @@ -630,7 +634,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) /* allocate instance-specific interface IDs, and patch descriptors */ status = usb_interface_id(c, f); if (status < 0) - goto fail; + return status; acm->ctrl_id = status; acm_iad_descriptor.bFirstInterface = status; @@ -639,43 +643,41 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) status = usb_interface_id(c, f); if (status < 0) - goto fail; + return status; acm->data_id = status; acm_data_interface_desc.bInterfaceNumber = status; acm_union_desc.bSlaveInterface0 = status; acm_call_mgmt_descriptor.bDataInterface = status; - status = -ENODEV; - /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc); if (!ep) - goto fail; + return -ENODEV; acm->port.in = ep; ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc); if (!ep) - goto fail; + return -ENODEV; acm->port.out = ep; ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc); if (!ep) - goto fail; + return -ENODEV; acm->notify = ep; acm_iad_descriptor.bFunctionProtocol = acm->bInterfaceProtocol; acm_control_interface_desc.bInterfaceProtocol = acm->bInterfaceProtocol; /* allocate notification */ - acm->notify_req = gs_alloc_req(ep, - sizeof(struct usb_cdc_notification) + 2, - GFP_KERNEL); - if (!acm->notify_req) - goto fail; + request = gs_alloc_req(ep, + sizeof(struct usb_cdc_notification) + 2, + GFP_KERNEL); + if (!request) + return -ENODEV; - acm->notify_req->complete = acm_cdc_notify_complete; - acm->notify_req->context = acm; + request->complete = acm_cdc_notify_complete; + request->context = acm; /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at @@ -692,7 +694,9 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function, acm_ss_function, acm_ss_function); if (status) - goto fail; + return status; + + acm->notify_req = no_free_ptr(request); dev_dbg(&cdev->gadget->dev, "acm ttyGS%d: IN/%s OUT/%s NOTIFY/%s\n", @@ -700,14 +704,6 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) acm->port.in->name, acm->port.out->name, acm->notify->name); return 0; - -fail: - if (acm->notify_req) - gs_free_req(acm->notify, acm->notify_req); - - ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status); - - return status; } static void acm_unbind(struct usb_configuration *c, struct usb_function *f) From 42988380ac67c76bb9dff8f77d7ef3eefd50b7b5 Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Tue, 16 Sep 2025 16:21:36 +0800 Subject: [PATCH 1615/2711] usb: gadget: f_ecm: Refactor bind path to use __free() After an bind/unbind cycle, the ecm->notify_req is left stale. If a subsequent bind fails, the unified error label attempts to free this stale request, leading to a NULL pointer dereference when accessing ep->ops->free_request. Refactor the error handling in the bind path to use the __free() automatic cleanup mechanism. Fixes: da741b8c56d6 ("usb ethernet gadget: split CDC Ethernet function") Cc: stable@kernel.org Signed-off-by: Kuen-Han Tsai Link: https://lore.kernel.org/r/20250916-ready-v1-5-4997bf277548@google.com Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250916-ready-v1-5-4997bf277548@google.com --- drivers/usb/gadget/function/f_ecm.c | 48 ++++++++++++----------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index 027226325039..675d2bc538a4 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -8,6 +8,7 @@ /* #define VERBOSE_DEBUG */ +#include #include #include #include @@ -15,6 +16,8 @@ #include #include +#include + #include "u_ether.h" #include "u_ether_configfs.h" #include "u_ecm.h" @@ -678,6 +681,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; struct f_ecm_opts *ecm_opts; + struct usb_request *request __free(free_usb_request) = NULL; if (!can_support_ecm(cdev->gadget)) return -EINVAL; @@ -711,7 +715,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) - goto fail; + return status; ecm->ctrl_id = status; ecm_iad_descriptor.bFirstInterface = status; @@ -720,24 +724,22 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) status = usb_interface_id(c, f); if (status < 0) - goto fail; + return status; ecm->data_id = status; ecm_data_nop_intf.bInterfaceNumber = status; ecm_data_intf.bInterfaceNumber = status; ecm_union_desc.bSlaveInterface0 = status; - status = -ENODEV; - /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_in_desc); if (!ep) - goto fail; + return -ENODEV; ecm->port.in_ep = ep; ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_out_desc); if (!ep) - goto fail; + return -ENODEV; ecm->port.out_ep = ep; /* NOTE: a status/notification endpoint is *OPTIONAL* but we @@ -746,20 +748,18 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) */ ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_notify_desc); if (!ep) - goto fail; + return -ENODEV; ecm->notify = ep; - status = -ENOMEM; - /* allocate notification request and buffer */ - ecm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!ecm->notify_req) - goto fail; - ecm->notify_req->buf = kmalloc(ECM_STATUS_BYTECOUNT, GFP_KERNEL); - if (!ecm->notify_req->buf) - goto fail; - ecm->notify_req->context = ecm; - ecm->notify_req->complete = ecm_notify_complete; + request = usb_ep_alloc_request(ep, GFP_KERNEL); + if (!request) + return -ENOMEM; + request->buf = kmalloc(ECM_STATUS_BYTECOUNT, GFP_KERNEL); + if (!request->buf) + return -ENOMEM; + request->context = ecm; + request->complete = ecm_notify_complete; /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at @@ -778,7 +778,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function, ecm_ss_function, ecm_ss_function); if (status) - goto fail; + return status; /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -788,20 +788,12 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ecm->port.open = ecm_open; ecm->port.close = ecm_close; + ecm->notify_req = no_free_ptr(request); + DBG(cdev, "CDC Ethernet: IN/%s OUT/%s NOTIFY/%s\n", ecm->port.in_ep->name, ecm->port.out_ep->name, ecm->notify->name); return 0; - -fail: - if (ecm->notify_req) { - kfree(ecm->notify_req->buf); - usb_ep_free_request(ecm->notify, ecm->notify_req); - } - - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; } static inline struct f_ecm_opts *to_f_ecm_opts(struct config_item *item) From 08228941436047bdcd35a612c1aec0912a29d8cd Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Tue, 16 Sep 2025 16:21:37 +0800 Subject: [PATCH 1616/2711] usb: gadget: f_rndis: Refactor bind path to use __free() After an bind/unbind cycle, the rndis->notify_req is left stale. If a subsequent bind fails, the unified error label attempts to free this stale request, leading to a NULL pointer dereference when accessing ep->ops->free_request. Refactor the error handling in the bind path to use the __free() automatic cleanup mechanism. Fixes: 45fe3b8e5342 ("usb ethernet gadget: split RNDIS function") Cc: stable@kernel.org Signed-off-by: Kuen-Han Tsai Link: https://lore.kernel.org/r/20250916-ready-v1-6-4997bf277548@google.com Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250916-ready-v1-6-4997bf277548@google.com --- drivers/usb/gadget/function/f_rndis.c | 85 +++++++++++---------------- 1 file changed, 35 insertions(+), 50 deletions(-) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 7cec19d65fb5..7451e7cb7a85 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -19,6 +19,8 @@ #include +#include + #include "u_ether.h" #include "u_ether_configfs.h" #include "u_rndis.h" @@ -662,6 +664,8 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; struct f_rndis_opts *rndis_opts; + struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; + struct usb_request *request __free(free_usb_request) = NULL; if (!can_support_rndis(c)) return -EINVAL; @@ -669,12 +673,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst); if (cdev->use_os_string) { - f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), - GFP_KERNEL); - if (!f->os_desc_table) + os_desc_table = kzalloc(sizeof(*os_desc_table), GFP_KERNEL); + if (!os_desc_table) return -ENOMEM; - f->os_desc_n = 1; - f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc; } rndis_iad_descriptor.bFunctionClass = rndis_opts->class; @@ -692,16 +693,14 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) gether_set_gadget(rndis_opts->net, cdev->gadget); status = gether_register_netdev(rndis_opts->net); if (status) - goto fail; + return status; rndis_opts->bound = true; } us = usb_gstrings_attach(cdev, rndis_strings, ARRAY_SIZE(rndis_string_defs)); - if (IS_ERR(us)) { - status = PTR_ERR(us); - goto fail; - } + if (IS_ERR(us)) + return PTR_ERR(us); rndis_control_intf.iInterface = us[0].id; rndis_data_intf.iInterface = us[1].id; rndis_iad_descriptor.iFunction = us[2].id; @@ -709,36 +708,30 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) - goto fail; + return status; rndis->ctrl_id = status; rndis_iad_descriptor.bFirstInterface = status; rndis_control_intf.bInterfaceNumber = status; rndis_union_desc.bMasterInterface0 = status; - if (cdev->use_os_string) - f->os_desc_table[0].if_id = - rndis_iad_descriptor.bFirstInterface; - status = usb_interface_id(c, f); if (status < 0) - goto fail; + return status; rndis->data_id = status; rndis_data_intf.bInterfaceNumber = status; rndis_union_desc.bSlaveInterface0 = status; - status = -ENODEV; - /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc); if (!ep) - goto fail; + return -ENODEV; rndis->port.in_ep = ep; ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc); if (!ep) - goto fail; + return -ENODEV; rndis->port.out_ep = ep; /* NOTE: a status/notification endpoint is, strictly speaking, @@ -747,21 +740,19 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) */ ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc); if (!ep) - goto fail; + return -ENODEV; rndis->notify = ep; - status = -ENOMEM; - /* allocate notification request and buffer */ - rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!rndis->notify_req) - goto fail; - rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL); - if (!rndis->notify_req->buf) - goto fail; - rndis->notify_req->length = STATUS_BYTECOUNT; - rndis->notify_req->context = rndis; - rndis->notify_req->complete = rndis_response_complete; + request = usb_ep_alloc_request(ep, GFP_KERNEL); + if (!request) + return -ENOMEM; + request->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL); + if (!request->buf) + return -ENOMEM; + request->length = STATUS_BYTECOUNT; + request->context = rndis; + request->complete = rndis_response_complete; /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at @@ -778,7 +769,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function, eth_ss_function, eth_ss_function); if (status) - goto fail; + return status; rndis->port.open = rndis_open; rndis->port.close = rndis_close; @@ -789,10 +780,19 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) if (rndis->manufacturer && rndis->vendorID && rndis_set_param_vendor(rndis->params, rndis->vendorID, rndis->manufacturer)) { - status = -EINVAL; - goto fail_free_descs; + usb_free_all_descriptors(f); + return -EINVAL; } + if (cdev->use_os_string) { + os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc; + os_desc_table[0].if_id = rndis_iad_descriptor.bFirstInterface; + f->os_desc_table = no_free_ptr(os_desc_table); + f->os_desc_n = 1; + + } + rndis->notify_req = no_free_ptr(request); + /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code * until we're activated via set_alt(). @@ -802,21 +802,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis->port.in_ep->name, rndis->port.out_ep->name, rndis->notify->name); return 0; - -fail_free_descs: - usb_free_all_descriptors(f); -fail: - kfree(f->os_desc_table); - f->os_desc_n = 0; - - if (rndis->notify_req) { - kfree(rndis->notify_req->buf); - usb_ep_free_request(rndis->notify, rndis->notify_req); - } - - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; } void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net) From f4abab350840d58d69814c6993736f03ac27df83 Mon Sep 17 00:00:00 2001 From: Arturs Artamonovs Date: Tue, 16 Sep 2025 16:57:17 +0100 Subject: [PATCH 1617/2711] tty: serial: fix help message for SERIAL_CPM Running checkpatch reported error extra whitespace at the end of help message for SERIAL_CPM menu entry Signed-off-by: Arturs Artamonovs Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 1e27a822c1cb..8523ccfb364d 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -782,7 +782,7 @@ config SERIAL_CPM depends on CPM2 || CPM1 select SERIAL_CORE help - This driver supports the SCC and SMC serial ports on Motorola + This driver supports the SCC and SMC serial ports on Motorola embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx) config SERIAL_CPM_CONSOLE From a699213d4e6ef4286348c6439837990f121e0c03 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 17 Sep 2025 10:04:38 +0900 Subject: [PATCH 1618/2711] serial: qcom-geni: Fix blocked task Revert commit 1afa70632c39 ("serial: qcom-geni: Enable PM runtime for serial driver") and its dependent commit 86fa39dd6fb7 ("serial: qcom-geni: Enable Serial on SA8255p Qualcomm platforms") because the first one causes regression - hang task on Qualcomm RB1 board (QRB2210) and unable to use serial at all during normal boot: INFO: task kworker/u16:0:12 blocked for more than 42 seconds. Not tainted 6.17.0-rc1-00004-g53e760d89498 #9 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. task:kworker/u16:0 state:D stack:0 pid:12 tgid:12 ppid:2 task_flags:0x4208060 flags:0x00000010 Workqueue: async async_run_entry_fn Call trace: __switch_to+0xe8/0x1a0 (T) __schedule+0x290/0x7c0 schedule+0x34/0x118 rpm_resume+0x14c/0x66c rpm_resume+0x2a4/0x66c rpm_resume+0x2a4/0x66c rpm_resume+0x2a4/0x66c __pm_runtime_resume+0x50/0x9c __driver_probe_device+0x58/0x120 driver_probe_device+0x3c/0x154 __driver_attach_async_helper+0x4c/0xc0 async_run_entry_fn+0x34/0xe0 process_one_work+0x148/0x290 worker_thread+0x2c4/0x3e0 kthread+0x118/0x1c0 ret_from_fork+0x10/0x20 The issue was reported on 12th of August and was ignored by author of commits introducing issue for two weeks. Only after complaining author produced a fix which did not work, so if original commits cannot be reliably fixed for 5 weeks, they obviously are buggy and need to be dropped. Fixes: 1afa70632c39 ("serial: qcom-geni: Enable PM runtime for serial driver") Reported-by: Alexey Klimov Closes: https://lore.kernel.org/all/DC0D53ZTNOBU.E8LSD5E5Z8TX@linaro.org/ Signed-off-by: Krzysztof Kozlowski Tested-by: Alexey Klimov Reviewed-by: Alexey Klimov Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20250917010437.129912-2-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 176 +++----------------------- 1 file changed, 16 insertions(+), 160 deletions(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 32ec632fd080..81f385d900d0 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -100,16 +99,10 @@ #define DMA_RX_BUF_SIZE 2048 static DEFINE_IDA(port_ida); -#define DOMAIN_IDX_POWER 0 -#define DOMAIN_IDX_PERF 1 struct qcom_geni_device_data { bool console; enum geni_se_xfer_mode mode; - struct dev_pm_domain_attach_data pd_data; - int (*resources_init)(struct uart_port *uport); - int (*set_rate)(struct uart_port *uport, unsigned int baud); - int (*power_state)(struct uart_port *uport, bool state); }; struct qcom_geni_private_data { @@ -147,7 +140,6 @@ struct qcom_geni_serial_port { struct qcom_geni_private_data private_data; const struct qcom_geni_device_data *dev_data; - struct dev_pm_domain_list *pd_list; }; static const struct uart_ops qcom_geni_console_pops; @@ -1370,42 +1362,6 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud) return 0; } -static int geni_serial_set_level(struct uart_port *uport, unsigned int baud) -{ - struct qcom_geni_serial_port *port = to_dev_port(uport); - struct device *perf_dev = port->pd_list->pd_devs[DOMAIN_IDX_PERF]; - - /* - * The performance protocol sets UART communication - * speeds by selecting different performance levels - * through the OPP framework. - * - * Supported perf levels for baudrates in firmware are below - * +---------------------+--------------------+ - * | Perf level value | Baudrate values | - * +---------------------+--------------------+ - * | 300 | 300 | - * | 1200 | 1200 | - * | 2400 | 2400 | - * | 4800 | 4800 | - * | 9600 | 9600 | - * | 19200 | 19200 | - * | 38400 | 38400 | - * | 57600 | 57600 | - * | 115200 | 115200 | - * | 230400 | 230400 | - * | 460800 | 460800 | - * | 921600 | 921600 | - * | 2000000 | 2000000 | - * | 3000000 | 3000000 | - * | 3200000 | 3200000 | - * | 4000000 | 4000000 | - * +---------------------+--------------------+ - */ - - return dev_pm_opp_set_level(perf_dev, baud); -} - static void qcom_geni_serial_set_termios(struct uart_port *uport, struct ktermios *termios, const struct ktermios *old) @@ -1424,7 +1380,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, /* baud rate */ baud = uart_get_baud_rate(uport, termios, old, 300, 8000000); - ret = port->dev_data->set_rate(uport, baud); + ret = geni_serial_set_rate(uport, baud); if (ret) return; @@ -1711,27 +1667,8 @@ static int geni_serial_resources_off(struct uart_port *uport) return 0; } -static int geni_serial_resource_state(struct uart_port *uport, bool power_on) +static int geni_serial_resource_init(struct qcom_geni_serial_port *port) { - return power_on ? geni_serial_resources_on(uport) : geni_serial_resources_off(uport); -} - -static int geni_serial_pwr_init(struct uart_port *uport) -{ - struct qcom_geni_serial_port *port = to_dev_port(uport); - int ret; - - ret = dev_pm_domain_attach_list(port->se.dev, - &port->dev_data->pd_data, &port->pd_list); - if (ret <= 0) - return -EINVAL; - - return 0; -} - -static int geni_serial_resource_init(struct uart_port *uport) -{ - struct qcom_geni_serial_port *port = to_dev_port(uport); int ret; port->se.clk = devm_clk_get(port->se.dev, "se"); @@ -1776,10 +1713,10 @@ static void qcom_geni_serial_pm(struct uart_port *uport, old_state = UART_PM_STATE_OFF; if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) - pm_runtime_resume_and_get(uport->dev); + geni_serial_resources_on(uport); else if (new_state == UART_PM_STATE_OFF && old_state == UART_PM_STATE_ON) - pm_runtime_put_sync(uport->dev); + geni_serial_resources_off(uport); } @@ -1882,16 +1819,13 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) port->se.dev = &pdev->dev; port->se.wrapper = dev_get_drvdata(pdev->dev.parent); - ret = port->dev_data->resources_init(uport); + ret = geni_serial_resource_init(port); if (ret) return ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -EINVAL; - goto error; - } - + if (!res) + return -EINVAL; uport->mapbase = res->start; uport->rs485_config = qcom_geni_rs485_config; @@ -1903,26 +1837,19 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) if (!data->console) { port->rx_buf = devm_kzalloc(uport->dev, DMA_RX_BUF_SIZE, GFP_KERNEL); - if (!port->rx_buf) { - ret = -ENOMEM; - goto error; - } + if (!port->rx_buf) + return -ENOMEM; } port->name = devm_kasprintf(uport->dev, GFP_KERNEL, "qcom_geni_serial_%s%d", uart_console(uport) ? "console" : "uart", uport->line); - if (!port->name) { - ret = -ENOMEM; - goto error; - } + if (!port->name) + return -ENOMEM; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto error; - } - + if (irq < 0) + return irq; uport->irq = irq; uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE); @@ -1944,18 +1871,16 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) IRQF_TRIGGER_HIGH, port->name, uport); if (ret) { dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret); - goto error; + return ret; } ret = uart_get_rs485_mode(uport); if (ret) return ret; - devm_pm_runtime_enable(port->se.dev); - ret = uart_add_one_port(drv, uport); if (ret) - goto error; + return ret; if (port->wakeup_irq > 0) { device_init_wakeup(&pdev->dev, true); @@ -1965,15 +1890,11 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, false); ida_free(&port_ida, uport->line); uart_remove_one_port(drv, uport); - goto error; + return ret; } } return 0; - -error: - dev_pm_domain_detach_list(port->pd_list); - return ret; } static void qcom_geni_serial_remove(struct platform_device *pdev) @@ -1986,31 +1907,6 @@ static void qcom_geni_serial_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, false); ida_free(&port_ida, uport->line); uart_remove_one_port(drv, &port->uport); - dev_pm_domain_detach_list(port->pd_list); -} - -static int __maybe_unused qcom_geni_serial_runtime_suspend(struct device *dev) -{ - struct qcom_geni_serial_port *port = dev_get_drvdata(dev); - struct uart_port *uport = &port->uport; - int ret = 0; - - if (port->dev_data->power_state) - ret = port->dev_data->power_state(uport, false); - - return ret; -} - -static int __maybe_unused qcom_geni_serial_runtime_resume(struct device *dev) -{ - struct qcom_geni_serial_port *port = dev_get_drvdata(dev); - struct uart_port *uport = &port->uport; - int ret = 0; - - if (port->dev_data->power_state) - ret = port->dev_data->power_state(uport, true); - - return ret; } static int qcom_geni_serial_suspend(struct device *dev) @@ -2048,46 +1944,14 @@ static int qcom_geni_serial_resume(struct device *dev) static const struct qcom_geni_device_data qcom_geni_console_data = { .console = true, .mode = GENI_SE_FIFO, - .resources_init = geni_serial_resource_init, - .set_rate = geni_serial_set_rate, - .power_state = geni_serial_resource_state, }; static const struct qcom_geni_device_data qcom_geni_uart_data = { .console = false, .mode = GENI_SE_DMA, - .resources_init = geni_serial_resource_init, - .set_rate = geni_serial_set_rate, - .power_state = geni_serial_resource_state, -}; - -static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = { - .console = true, - .mode = GENI_SE_FIFO, - .pd_data = { - .pd_flags = PD_FLAG_DEV_LINK_ON, - .pd_names = (const char*[]) { "power", "perf" }, - .num_pd_names = 2, - }, - .resources_init = geni_serial_pwr_init, - .set_rate = geni_serial_set_level, -}; - -static const struct qcom_geni_device_data sa8255p_qcom_geni_uart_data = { - .console = false, - .mode = GENI_SE_DMA, - .pd_data = { - .pd_flags = PD_FLAG_DEV_LINK_ON, - .pd_names = (const char*[]) { "power", "perf" }, - .num_pd_names = 2, - }, - .resources_init = geni_serial_pwr_init, - .set_rate = geni_serial_set_level, }; static const struct dev_pm_ops qcom_geni_serial_pm_ops = { - SET_RUNTIME_PM_OPS(qcom_geni_serial_runtime_suspend, - qcom_geni_serial_runtime_resume, NULL) SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume) }; @@ -2096,18 +1960,10 @@ static const struct of_device_id qcom_geni_serial_match_table[] = { .compatible = "qcom,geni-debug-uart", .data = &qcom_geni_console_data, }, - { - .compatible = "qcom,sa8255p-geni-debug-uart", - .data = &sa8255p_qcom_geni_console_data, - }, { .compatible = "qcom,geni-uart", .data = &qcom_geni_uart_data, }, - { - .compatible = "qcom,sa8255p-geni-uart", - .data = &sa8255p_qcom_geni_uart_data, - }, {} }; MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table); From 4fde89539a18d39169a511fda00db65eeba1a8e0 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 11:09:19 -0700 Subject: [PATCH 1619/2711] cxl: Add helper to detect top of CXL device topology Add a helper to replace the open code detection of CXL device hierarchy root, or the host bridge. The helper will be used for delayed downstream port (dport) creation. Reviewed-by: Jonathan Cameron Reviewed-by: Li Ming Reviewed-by: Dan Williams Reviewed-by: Alison Schofield Reviewed-by: Robert Richter Tested-by: Robert Richter Signed-off-by: Dave Jiang --- drivers/cxl/core/port.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 29197376b18e..855623cebd7d 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -33,6 +33,15 @@ static DEFINE_IDA(cxl_port_ida); static DEFINE_XARRAY(cxl_root_buses); +/* + * The terminal device in PCI is NULL and @platform_bus + * for platform devices (for cxl_test) + */ +static bool is_cxl_host_bridge(struct device *dev) +{ + return (!dev || dev == &platform_bus); +} + int cxl_num_decoders_committed(struct cxl_port *port) { lockdep_assert_held(&cxl_rwsem.region); @@ -1541,7 +1550,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd, resource_size_t component_reg_phys; int rc; - if (!dparent) { + if (is_cxl_host_bridge(dparent)) { /* * The iteration reached the topology root without finding the * CXL-root 'cxl_port' on a previous iteration, fail for now to @@ -1629,11 +1638,7 @@ retry: struct device *uport_dev; struct cxl_dport *dport; - /* - * The terminal "grandparent" in PCI is NULL and @platform_bus - * for platform devices - */ - if (!dport_dev || dport_dev == &platform_bus) + if (is_cxl_host_bridge(dport_dev)) return 0; uport_dev = dport_dev->parent; From 8330671c57c7056ef5e1e8dccfcdda7d5fe6d0b0 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 11:09:20 -0700 Subject: [PATCH 1620/2711] cxl: Add helper to delete dport Refactor the code in reap_dports() out to provide a helper function that reaps a single dport. This will be used later in the cleanup path for allocating a dport. Renaming to del_port() and del_dports() to mirror devm_cxl_add_dport(). [dj] Fixed up subject per Robert Reviewed-by: Jonathan Cameron Reviewed-by: Li Ming Reviewed-by: Alison Schofield Reviewed-by: Dan Williams Tested-by: Robert Richter Signed-off-by: Dave Jiang --- drivers/cxl/core/port.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 855623cebd7d..88f19abf3327 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1432,7 +1432,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, "CXL"); * through ->remove(). This "bottom-up" removal selectively removes individual * child ports manually. This depends on devm_cxl_add_port() to not change is * devm action registration order, and for dports to have already been - * destroyed by reap_dports(). + * destroyed by del_dports(). */ static void delete_switch_port(struct cxl_port *port) { @@ -1441,18 +1441,24 @@ static void delete_switch_port(struct cxl_port *port) devm_release_action(port->dev.parent, unregister_port, port); } -static void reap_dports(struct cxl_port *port) +static void del_dport(struct cxl_dport *dport) +{ + struct cxl_port *port = dport->port; + + devm_release_action(&port->dev, cxl_dport_unlink, dport); + devm_release_action(&port->dev, cxl_dport_remove, dport); + devm_kfree(&port->dev, dport); +} + +static void del_dports(struct cxl_port *port) { struct cxl_dport *dport; unsigned long index; device_lock_assert(&port->dev); - xa_for_each(&port->dports, index, dport) { - devm_release_action(&port->dev, cxl_dport_unlink, dport); - devm_release_action(&port->dev, cxl_dport_remove, dport); - devm_kfree(&port->dev, dport); - } + xa_for_each(&port->dports, index, dport) + del_dport(dport); } struct detach_ctx { @@ -1510,7 +1516,7 @@ static void cxl_detach_ep(void *data) */ died = true; port->dead = true; - reap_dports(port); + del_dports(port); } device_unlock(&port->dev); From 02edab6ceefaaf8cb917e864d8c26dbac0ea9686 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 11:09:21 -0700 Subject: [PATCH 1621/2711] cxl: Add a cached copy of target_map to cxl_decoder Add a cached copy of the hardware port-id list that is available at init before all @dport objects have been instantiated. Change is in preparation of delayed dport instantiation. Reviewed-by: Robert Richter Reviewed-by: Jonathan Cameron Tested-by: Robert Richter Reviewed-by: Alison Schofield Signed-off-by: Dave Jiang --- drivers/cxl/acpi.c | 7 +++---- drivers/cxl/core/hdm.c | 20 ++++++++------------ drivers/cxl/core/port.c | 22 +++++++--------------- drivers/cxl/core/region.c | 4 +++- drivers/cxl/cxl.h | 8 ++++++-- tools/testing/cxl/test/cxl.c | 8 ++++---- 6 files changed, 31 insertions(+), 38 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 712624cba2b6..bb0871d92620 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -398,7 +398,6 @@ DEFINE_FREE(del_cxl_resource, struct resource *, if (_T) del_cxl_resource(_T)) static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws, struct cxl_cfmws_context *ctx) { - int target_map[CXL_DECODER_MAX_INTERLEAVE]; struct cxl_port *root_port = ctx->root_port; struct cxl_cxims_context cxims_ctx; struct device *dev = ctx->dev; @@ -416,8 +415,6 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws, rc = eig_to_granularity(cfmws->granularity, &ig); if (rc) return rc; - for (i = 0; i < ways; i++) - target_map[i] = cfmws->interleave_targets[i]; struct resource *res __free(del_cxl_resource) = alloc_cxl_resource( cfmws->base_hpa, cfmws->window_size, ctx->id++); @@ -443,6 +440,8 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws, .end = cfmws->base_hpa + cfmws->window_size - 1, }; cxld->interleave_ways = ways; + for (i = 0; i < ways; i++) + cxld->target_map[i] = cfmws->interleave_targets[i]; /* * Minimize the x1 granularity to advertise support for any * valid region granularity @@ -475,7 +474,7 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws, if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_XOR) cxlrd->hpa_to_spa = cxl_xor_hpa_to_spa; - rc = cxl_decoder_add(cxld, target_map); + rc = cxl_decoder_add(cxld); if (rc) return rc; diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index e9e1d555cec6..cee68bbc7ff6 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -21,12 +21,11 @@ struct cxl_rwsem cxl_rwsem = { .dpa = __RWSEM_INITIALIZER(cxl_rwsem.dpa), }; -static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, - int *target_map) +static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld) { int rc; - rc = cxl_decoder_add_locked(cxld, target_map); + rc = cxl_decoder_add_locked(cxld); if (rc) { put_device(&cxld->dev); dev_err(&port->dev, "Failed to add decoder\n"); @@ -54,7 +53,6 @@ int devm_cxl_add_passthrough_decoder(struct cxl_port *port) { struct cxl_switch_decoder *cxlsd; struct cxl_dport *dport = NULL; - int single_port_map[1]; unsigned long index; struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); @@ -73,9 +71,9 @@ int devm_cxl_add_passthrough_decoder(struct cxl_port *port) xa_for_each(&port->dports, index, dport) break; - single_port_map[0] = dport->port_id; + cxlsd->cxld.target_map[0] = dport->port_id; - return add_hdm_decoder(port, &cxlsd->cxld, single_port_map); + return add_hdm_decoder(port, &cxlsd->cxld); } EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, "CXL"); @@ -984,7 +982,7 @@ static int cxl_setup_hdm_decoder_from_dvsec( } static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, - int *target_map, void __iomem *hdm, int which, + void __iomem *hdm, int which, u64 *dpa_base, struct cxl_endpoint_dvsec_info *info) { struct cxl_endpoint_decoder *cxled = NULL; @@ -1103,7 +1101,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, hi = readl(hdm + CXL_HDM_DECODER0_TL_HIGH(which)); target_list.value = (hi << 32) + lo; for (i = 0; i < cxld->interleave_ways; i++) - target_map[i] = target_list.target_id[i]; + cxld->target_map[i] = target_list.target_id[i]; return 0; } @@ -1179,7 +1177,6 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, cxl_settle_decoders(cxlhdm); for (i = 0; i < cxlhdm->decoder_count; i++) { - int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 }; int rc, target_count = cxlhdm->target_count; struct cxl_decoder *cxld; @@ -1207,8 +1204,7 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, cxld = &cxlsd->cxld; } - rc = init_hdm_decoder(port, cxld, target_map, hdm, i, - &dpa_base, info); + rc = init_hdm_decoder(port, cxld, hdm, i, &dpa_base, info); if (rc) { dev_warn(&port->dev, "Failed to initialize decoder%d.%d\n", @@ -1216,7 +1212,7 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, put_device(&cxld->dev); return rc; } - rc = add_hdm_decoder(port, cxld, target_map); + rc = add_hdm_decoder(port, cxld); if (rc) { dev_warn(&port->dev, "Failed to add decoder%d.%d\n", port->id, i); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 88f19abf3327..7344048f678e 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1715,13 +1715,11 @@ struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd, EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, "CXL"); static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd, - struct cxl_port *port, int *target_map) + struct cxl_port *port) { + struct cxl_decoder *cxld = &cxlsd->cxld; int i; - if (!target_map) - return 0; - device_lock_assert(&port->dev); if (xa_empty(&port->dports)) @@ -1729,7 +1727,7 @@ static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd, guard(rwsem_write)(&cxl_rwsem.region); for (i = 0; i < cxlsd->cxld.interleave_ways; i++) { - struct cxl_dport *dport = find_dport(port, target_map[i]); + struct cxl_dport *dport = find_dport(port, cxld->target_map[i]); if (!dport) return -ENXIO; @@ -1921,9 +1919,6 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_alloc, "CXL"); /** * cxl_decoder_add_locked - Add a decoder with targets * @cxld: The cxl decoder allocated by cxl__decoder_alloc() - * @target_map: A list of downstream ports that this decoder can direct memory - * traffic to. These numbers should correspond with the port number - * in the PCIe Link Capabilities structure. * * Certain types of decoders may not have any targets. The main example of this * is an endpoint device. A more awkward example is a hostbridge whose root @@ -1937,7 +1932,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_alloc, "CXL"); * Return: Negative error code if the decoder wasn't properly configured; else * returns 0. */ -int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map) +int cxl_decoder_add_locked(struct cxl_decoder *cxld) { struct cxl_port *port; struct device *dev; @@ -1958,7 +1953,7 @@ int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map) if (!is_endpoint_decoder(dev)) { struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev); - rc = decoder_populate_targets(cxlsd, port, target_map); + rc = decoder_populate_targets(cxlsd, port); if (rc && (cxld->flags & CXL_DECODER_F_ENABLE)) { dev_err(&port->dev, "Failed to populate active decoder targets\n"); @@ -1977,9 +1972,6 @@ EXPORT_SYMBOL_NS_GPL(cxl_decoder_add_locked, "CXL"); /** * cxl_decoder_add - Add a decoder with targets * @cxld: The cxl decoder allocated by cxl__decoder_alloc() - * @target_map: A list of downstream ports that this decoder can direct memory - * traffic to. These numbers should correspond with the port number - * in the PCIe Link Capabilities structure. * * This is the unlocked variant of cxl_decoder_add_locked(). * See cxl_decoder_add_locked(). @@ -1987,7 +1979,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_decoder_add_locked, "CXL"); * Context: Process context. Takes and releases the device lock of the port that * owns the @cxld. */ -int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map) +int cxl_decoder_add(struct cxl_decoder *cxld) { struct cxl_port *port; @@ -2000,7 +1992,7 @@ int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map) port = to_cxl_port(cxld->dev.parent); guard(device)(&port->dev); - return cxl_decoder_add_locked(cxld, target_map); + return cxl_decoder_add_locked(cxld); } EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, "CXL"); diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 71cc42d05248..bba62867df90 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1510,8 +1510,10 @@ add_target: cxl_rr->nr_targets_set); return -ENXIO; } - } else + } else { cxlsd->target[cxl_rr->nr_targets_set] = ep->dport; + cxlsd->cxld.target_map[cxl_rr->nr_targets_set] = ep->dport->port_id; + } inc = 1; out_target_set: cxl_rr->nr_targets_set += inc; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 847e37be42c4..4b858f3d44c6 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -357,6 +357,9 @@ enum cxl_decoder_type { * @target_type: accelerator vs expander (type2 vs type3) selector * @region: currently assigned region for this decoder * @flags: memory type capabilities and locking + * @target_map: cached copy of hardware port-id list, available at init + * before all @dport objects have been instantiated. While + * dport id is 8bit, CFMWS interleave targets are 32bits. * @commit: device/decoder-type specific callback to commit settings to hw * @reset: device/decoder-type specific callback to reset hw settings */ @@ -369,6 +372,7 @@ struct cxl_decoder { enum cxl_decoder_type target_type; struct cxl_region *region; unsigned long flags; + u32 target_map[CXL_DECODER_MAX_INTERLEAVE]; int (*commit)(struct cxl_decoder *cxld); void (*reset)(struct cxl_decoder *cxld); }; @@ -781,9 +785,9 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port, unsigned int nr_targets); struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port, unsigned int nr_targets); -int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map); +int cxl_decoder_add(struct cxl_decoder *cxld); struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port); -int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map); +int cxl_decoder_add_locked(struct cxl_decoder *cxld); int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld); static inline int cxl_root_decoder_autoremove(struct device *host, struct cxl_root_decoder *cxlrd) diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c index 6a25cca5636f..8faf4143d04e 100644 --- a/tools/testing/cxl/test/cxl.c +++ b/tools/testing/cxl/test/cxl.c @@ -651,7 +651,7 @@ static int mock_cxl_add_passthrough_decoder(struct cxl_port *port) struct target_map_ctx { - int *target_map; + u32 *target_map; int index; int target_count; }; @@ -863,9 +863,7 @@ static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, target_count = NR_CXL_SWITCH_PORTS; for (i = 0; i < NR_CXL_PORT_DECODERS; i++) { - int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 }; struct target_map_ctx ctx = { - .target_map = target_map, .target_count = target_count, }; struct cxl_decoder *cxld; @@ -894,6 +892,8 @@ static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, cxld = &cxled->cxld; } + ctx.target_map = cxld->target_map; + mock_init_hdm_decoder(cxld); if (target_count) { @@ -905,7 +905,7 @@ static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, } } - rc = cxl_decoder_add_locked(cxld, target_map); + rc = cxl_decoder_add_locked(cxld); if (rc) { put_device(&cxld->dev); dev_err(&port->dev, "Failed to add decoder\n"); From cf6ee09b0913308729f9c38cfbcb8320c10fe5d5 Mon Sep 17 00:00:00 2001 From: Matthew Wood Date: Wed, 17 Sep 2025 05:58:14 -0700 Subject: [PATCH 1622/2711] PCI/sysfs: Expose PCI device serial number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a single sysfs read-only interface for reading PCI device serial numbers from userspace in a programmatic way. This device attribute uses the same hexadecimal 1-byte dashed formatting as lspci serial number capability output. If a device doesn't support the serial number capability, the serial_number sysfs attribute will not be visible. Signed-off-by: Matthew Wood Signed-off-by: Bjorn Helgaas Reviewed-by: Mario Limonciello Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Weißschuh Reviewed-by: Keith Busch Reviewed-by: Krzysztof Wilczyński Link: https://patch.msgid.link/20250917125815.722952-2-thepacketgeek@gmail.com --- Documentation/ABI/testing/sysfs-bus-pci | 9 +++++++++ drivers/pci/pci-sysfs.c | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 69f952fffec7..92debe879ffb 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -612,3 +612,12 @@ Description: # ls doe_features 0001:01 0001:02 doe_discovery + +What: /sys/bus/pci/devices/.../serial_number +Date: December 2025 +Contact: Matthew Wood +Description: + This is visible only for PCI devices that support the serial + number extended capability. The file is read only and due to + the possible sensitivity of accessible serial numbers, admin + only. diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5eea14c1f7f5..95d9c0145359 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "pci.h" #ifndef ARCH_PCI_DEV_GROUPS @@ -694,6 +695,22 @@ static ssize_t boot_vga_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(boot_vga); +static ssize_t serial_number_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + u64 dsn; + u8 bytes[8]; + + dsn = pci_get_dsn(pci_dev); + if (!dsn) + return -EIO; + + put_unaligned_be64(dsn, bytes); + return sysfs_emit(buf, "%8phD\n", bytes); +} +static DEVICE_ATTR_ADMIN_RO(serial_number); + static ssize_t pci_read_config(struct file *filp, struct kobject *kobj, const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) @@ -1698,6 +1715,7 @@ late_initcall(pci_sysfs_init); static struct attribute *pci_dev_dev_attrs[] = { &dev_attr_boot_vga.attr, + &dev_attr_serial_number.attr, NULL, }; @@ -1710,6 +1728,9 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj, if (a == &dev_attr_boot_vga.attr && pci_is_vga(pdev)) return a->mode; + if (a == &dev_attr_serial_number.attr && pci_get_dsn(pdev)) + return a->mode; + return 0; } From 6515c612e79949b17ef4b8c4180c07bbeaf01e4d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 16 Sep 2025 17:11:03 +0100 Subject: [PATCH 1623/2711] KVM: arm64: Fix kvm_vcpu_{set,is}_be() to deal with EL2 state Nobody really cares about BE, but KVM currently only deals with SCTLR_EL1 when evaluating or setting the endianness in PSCI, meaning that we evaluate whatever the L2 state has been at some point. Teach these primitives about SCTLR_EL2, and forget about BE... Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_emulate.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index fa8a08a1ccd5..85f998dffea5 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -511,21 +511,29 @@ static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu) if (vcpu_mode_is_32bit(vcpu)) { *vcpu_cpsr(vcpu) |= PSR_AA32_E_BIT; } else { - u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1); + enum vcpu_sysreg r; + u64 sctlr; + + r = vcpu_has_nv(vcpu) ? SCTLR_EL2 : SCTLR_EL1; + + sctlr = vcpu_read_sys_reg(vcpu, r); sctlr |= SCTLR_ELx_EE; - vcpu_write_sys_reg(vcpu, sctlr, SCTLR_EL1); + vcpu_write_sys_reg(vcpu, sctlr, r); } } static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu) { + enum vcpu_sysreg r; + u64 bit; + if (vcpu_mode_is_32bit(vcpu)) return !!(*vcpu_cpsr(vcpu) & PSR_AA32_E_BIT); - if (vcpu_mode_priv(vcpu)) - return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & SCTLR_ELx_EE); - else - return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & SCTLR_EL1_E0E); + r = is_hyp_ctxt(vcpu) ? SCTLR_EL2 : SCTLR_EL1; + bit = vcpu_mode_priv(vcpu) ? SCTLR_ELx_EE : SCTLR_EL1_E0E; + + return vcpu_read_sys_reg(vcpu, r) & bit; } static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu, From 5f9466b50c1b4253d91abf81780b90a722133162 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Wed, 17 Sep 2025 14:07:37 +0100 Subject: [PATCH 1624/2711] KVM: arm64: Fix page leak in user_mem_abort() The user_mem_abort() function acquires a page reference via __kvm_faultin_pfn() early in its execution. However, the subsequent checks for mismatched attributes between stage 1 and stage 2 mappings would return an error code directly, bypassing the corresponding page release. Fix this by storing the error and releasing the unused page before returning the error. Fixes: 6d674e28f642 ("KVM: arm/arm64: Properly handle faulting of device mappings") Fixes: 2a8dfab26677 ("KVM: arm64: Block cacheable PFNMAP mapping") Signed-off-by: Fuad Tabba Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier Cc: stable@vger.kernel.org --- arch/arm64/kvm/mmu.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 006fdb017c54..61ef7d748e7a 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1670,7 +1670,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, * cache maintenance. */ if (!kvm_supports_cacheable_pfnmap()) - return -EFAULT; + ret = -EFAULT; } else { /* * If the page was identified as device early by looking at @@ -1693,7 +1693,12 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, } if (exec_fault && s2_force_noncacheable) - return -ENOEXEC; + ret = -ENOEXEC; + + if (ret) { + kvm_release_page_unused(page); + return ret; + } /* * Potentially reduce shadow S2 permissions to match the guest's own From 9664d5810e9bc919a9a661594e01eabc80befe8a Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 17 Sep 2025 10:11:28 +0100 Subject: [PATCH 1625/2711] KVM: arm64: Don't access ICC_SRE_EL2 if GICv3 doesn't support v2 compatibility We currently access ICC_SRE_EL2 at each load/put on VHE, and on each entry/exit on nVHE. Both are quite onerous on NV, as this register always traps. We do this to make sure the EL1 guest doesn't flip between v2 and v3 behind our back. But all modern implementations have dropped v2, and this is just overhead. At the same time, the GICv5 spec has been fixed to allow access to ICC_SRE_EL2 in legacy mode. Use this opportunity to replace the GICv5 checks for v2 compat checks, with an ad-hoc static key. Co-developed-by: Sascha Bischoff Signed-off-by: Sascha Bischoff Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kernel/image-vars.h | 3 +++ arch/arm64/kvm/hyp/vgic-v3-sr.c | 25 +++++++++---------------- arch/arm64/kvm/vgic/vgic-v3.c | 8 ++++++++ include/kvm/arm_vgic.h | 1 + 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index 714b0b5ec5ac..5369763606e7 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h @@ -105,6 +105,9 @@ KVM_NVHE_ALIAS(__hyp_stub_vectors); KVM_NVHE_ALIAS(vgic_v2_cpuif_trap); KVM_NVHE_ALIAS(vgic_v3_cpuif_trap); +/* Static key indicating whether GICv3 has GICv2 compatibility */ +KVM_NVHE_ALIAS(vgic_v3_has_v2_compat); + /* Static key which is set if CNTVOFF_EL2 is unusable */ KVM_NVHE_ALIAS(broken_cntvoff_key); diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c index d81275790e69..acd909b7f225 100644 --- a/arch/arm64/kvm/hyp/vgic-v3-sr.c +++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c @@ -295,12 +295,8 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if) } } - /* - * GICv5 BET0 FEAT_GCIE_LEGACY doesn't include ICC_SRE_EL2. This is due - * to be relaxed in a future spec release, at which point this in - * condition can be dropped. - */ - if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF)) { + /* Only disable SRE if the host implements the GICv2 interface */ + if (static_branch_unlikely(&vgic_v3_has_v2_compat)) { /* * Prevent the guest from touching the ICC_SRE_EL1 system * register. Note that this may not have any effect, as @@ -329,19 +325,16 @@ void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if) cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2); } - /* - * Can be dropped in the future when GICv5 spec is relaxed. See comment - * above. - */ - if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF)) { + /* Only restore SRE if the host implements the GICv2 interface */ + if (static_branch_unlikely(&vgic_v3_has_v2_compat)) { val = read_gicreg(ICC_SRE_EL2); write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2); - } - if (!cpu_if->vgic_sre) { - /* Make sure ENABLE is set at EL2 before setting SRE at EL1 */ - isb(); - write_gicreg(1, ICC_SRE_EL1); + if (!cpu_if->vgic_sre) { + /* Make sure ENABLE is set at EL2 before setting SRE at EL1 */ + isb(); + write_gicreg(1, ICC_SRE_EL1); + } } /* diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c index b9ad7c42c5b0..f1c153106c56 100644 --- a/arch/arm64/kvm/vgic/vgic-v3.c +++ b/arch/arm64/kvm/vgic/vgic-v3.c @@ -588,6 +588,7 @@ int vgic_v3_map_resources(struct kvm *kvm) } DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap); +DEFINE_STATIC_KEY_FALSE(vgic_v3_has_v2_compat); static int __init early_group0_trap_cfg(char *buf) { @@ -697,6 +698,13 @@ int vgic_v3_probe(const struct gic_kvm_info *info) if (kvm_vgic_global_state.vcpu_base == 0) kvm_info("disabling GICv2 emulation\n"); + /* + * Flip the static branch if the HW supports v2, even if we're + * not using it (such as in protected mode). + */ + if (has_v2) + static_branch_enable(&vgic_v3_has_v2_compat); + if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_30115)) { group0_trap = true; group1_trap = true; diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 404883c7af6e..9a6340d9c91e 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -375,6 +375,7 @@ struct vgic_cpu { extern struct static_key_false vgic_v2_cpuif_trap; extern struct static_key_false vgic_v3_cpuif_trap; +extern struct static_key_false vgic_v3_has_v2_compat; int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev_addr); void kvm_vgic_early_init(struct kvm *kvm); From d5a012af348d4d84287267547eb8637b937545af Mon Sep 17 00:00:00 2001 From: Sascha Bischoff Date: Thu, 28 Aug 2025 10:59:42 +0000 Subject: [PATCH 1626/2711] KVM: arm64: Enable nested for GICv5 host with FEAT_GCIE_LEGACY Extend the NV check to pass for a GICv5 host that has FEAT_GCIE_LEGACY. The has_gcie_v3_compat flag is only set on GICv5 hosts (that explicitly support FEAT_GCIE_LEGACY), and hence the explicit check for a VGIC_V5 is omitted. As of this change, vGICv3-based VMs can run with nested on a compatible GICv5 host. Signed-off-by: Sascha Bischoff Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/arm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 5bf101c869c9..49485d08ece2 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -2315,8 +2315,9 @@ static int __init init_subsystems(void) } if (kvm_mode == KVM_MODE_NV && - !(vgic_present && kvm_vgic_global_state.type == VGIC_V3)) { - kvm_err("NV support requires GICv3, giving up\n"); + !(vgic_present && (kvm_vgic_global_state.type == VGIC_V3 || + kvm_vgic_global_state.has_gcie_v3_compat))) { + kvm_err("NV support requires GICv3 or GICv5 with legacy support, giving up\n"); err = -EINVAL; goto out; } From 7847f51189343b29a24ca7edafb60a9032d5acf8 Mon Sep 17 00:00:00 2001 From: Sascha Bischoff Date: Thu, 28 Aug 2025 10:59:42 +0000 Subject: [PATCH 1627/2711] arm64: cpucaps: Add GICv5 Legacy vCPU interface (GCIE_LEGACY) capability Implement the GCIE_LEGACY capability as a system feature to be able to check for support from KVM. The type is explicitly ARM64_CPUCAP_EARLY_LOCAL_CPU_FEATURE, which means that the capability is enabled early if all boot CPUs support it. Additionally, if this capability is enabled during boot, it prevents late onlining of CPUs that lack it, thereby avoiding potential mismatched configurations which would break KVM. Signed-off-by: Sascha Bischoff Reviewed-by: Suzuki K Poulose Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kernel/cpufeature.c | 15 +++++++++++++++ arch/arm64/tools/cpucaps | 1 + 2 files changed, 16 insertions(+) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index ef269a5a37e1..770a41fa7214 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -2539,6 +2539,15 @@ test_has_mpam_hcr(const struct arm64_cpu_capabilities *entry, int scope) return idr & MPAMIDR_EL1_HAS_HCR; } +static bool +test_has_gicv5_legacy(const struct arm64_cpu_capabilities *entry, int scope) +{ + if (!this_cpu_has_cap(ARM64_HAS_GICV5_CPUIF)) + return false; + + return !!(read_sysreg_s(SYS_ICC_IDR0_EL1) & ICC_IDR0_EL1_GCIE_LEGACY); +} + static const struct arm64_cpu_capabilities arm64_features[] = { { .capability = ARM64_ALWAYS_BOOT, @@ -3156,6 +3165,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, ARM64_CPUID_FIELDS(ID_AA64PFR2_EL1, GCIE, IMP) }, + { + .desc = "GICv5 Legacy vCPU interface", + .type = ARM64_CPUCAP_EARLY_LOCAL_CPU_FEATURE, + .capability = ARM64_HAS_GICV5_LEGACY, + .matches = test_has_gicv5_legacy, + }, {}, }; diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index 9ff5cdbd2759..1b32c1232d28 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -37,6 +37,7 @@ HAS_GENERIC_AUTH_ARCH_QARMA5 HAS_GENERIC_AUTH_IMP_DEF HAS_GICV3_CPUIF HAS_GICV5_CPUIF +HAS_GICV5_LEGACY HAS_GIC_PRIO_MASKING HAS_GIC_PRIO_RELAXED_SYNC HAS_HCR_NV1 From 754e43b09561f59dd04e0b8aafe4f5c9a71a4d1f Mon Sep 17 00:00:00 2001 From: Sascha Bischoff Date: Thu, 28 Aug 2025 10:59:42 +0000 Subject: [PATCH 1628/2711] KVM: arm64: Use ARM64_HAS_GICV5_LEGACY for GICv5 probing The previous implementation of the probing function had the flaw that it wouldn't catch mismatched CPU features. Specifically, GICv5 legacy support (support for GICv3 VMs on a GICv5 host) was being enabled as long as the initial boot CPU had support for the feature. This allowed the support to become enabled on mismatched configurations. Move to using cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY) instead, which only returns true when all booted CPUs support FEAT_GCIE_LEGACY. A byproduct of this is that it ensures that late onlining of CPUs is blocked on feature mismatch. Signed-off-by: Sascha Bischoff Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic/vgic-v5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c index 6bdbb221bcde..2d3811f4e117 100644 --- a/arch/arm64/kvm/vgic/vgic-v5.c +++ b/arch/arm64/kvm/vgic/vgic-v5.c @@ -15,7 +15,7 @@ int vgic_v5_probe(const struct gic_kvm_info *info) u64 ich_vtr_el2; int ret; - if (!info->has_gcie_v3_compat) + if (!cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY)) return -ENODEV; kvm_vgic_global_state.type = VGIC_V5; From 5c5db9efe323dd0b0d7917dbe5b9c0999c95e79e Mon Sep 17 00:00:00 2001 From: Sascha Bischoff Date: Thu, 28 Aug 2025 10:59:43 +0000 Subject: [PATCH 1629/2711] irqchip/gic-v5: Drop has_gcie_v3_compat from gic_kvm_info The presence of FEAT_GCIE_LEGACY is now handled as a CPU feature. Therefore, drop the check and flag from the GIC driver and gic_kvm_info as it is no longer required or used by KVM. Signed-off-by: Sascha Bischoff Acked-by: Thomas Gleixner Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v5.c | 7 ------- include/linux/irqchip/arm-vgic-info.h | 2 -- 2 files changed, 9 deletions(-) diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c index 4bd224f359a7..41ef286c4d78 100644 --- a/drivers/irqchip/irq-gic-v5.c +++ b/drivers/irqchip/irq-gic-v5.c @@ -1062,16 +1062,9 @@ static void gicv5_set_cpuif_idbits(void) #ifdef CONFIG_KVM static struct gic_kvm_info gic_v5_kvm_info __initdata; -static bool __init gicv5_cpuif_has_gcie_legacy(void) -{ - u64 idr0 = read_sysreg_s(SYS_ICC_IDR0_EL1); - return !!FIELD_GET(ICC_IDR0_EL1_GCIE_LEGACY, idr0); -} - static void __init gic_of_setup_kvm_info(struct device_node *node) { gic_v5_kvm_info.type = GIC_V5; - gic_v5_kvm_info.has_gcie_v3_compat = gicv5_cpuif_has_gcie_legacy(); /* GIC Virtual CPU interface maintenance interrupt */ gic_v5_kvm_info.no_maint_irq_mask = false; diff --git a/include/linux/irqchip/arm-vgic-info.h b/include/linux/irqchip/arm-vgic-info.h index ca1713fac6e3..a470a73a805a 100644 --- a/include/linux/irqchip/arm-vgic-info.h +++ b/include/linux/irqchip/arm-vgic-info.h @@ -36,8 +36,6 @@ struct gic_kvm_info { bool has_v4_1; /* Deactivation impared, subpar stuff */ bool no_hw_deactivation; - /* v3 compat support (GICv5 hosts, only) */ - bool has_gcie_v3_compat; }; #ifdef CONFIG_KVM From 0c01fe49651d387776abed6a28541e80c8a93319 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 27 Aug 2025 16:54:27 +0200 Subject: [PATCH 1630/2711] ARM: at91: pm: save and restore ACR during PLL disable/enable Add a new word in assembly to store ACR value during the calls to at91_plla_disable/at91_plla_enable macros and use it. Signed-off-by: Nicolas Ferre [cristian.birsan@microchip.com: remove ACR_DEFAULT_PLLA loading] Signed-off-by: Cristian Birsan Link: https://lore.kernel.org/r/20250827145427.46819-4-nicolas.ferre@microchip.com Reviewed-by: Alexandre Belloni Signed-off-by: Claudiu Beznea --- arch/arm/mach-at91/pm_suspend.S | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index e23b86834096..861be0205458 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -689,6 +689,10 @@ sr_dis_exit: bic tmp2, tmp2, #AT91_PMC_PLL_UPDT_ID str tmp2, [pmc, #AT91_PMC_PLL_UPDT] + /* save acr */ + ldr tmp2, [pmc, #AT91_PMC_PLL_ACR] + str tmp2, .saved_acr + /* save div. */ mov tmp1, #0 ldr tmp2, [pmc, #AT91_PMC_PLL_CTRL0] @@ -758,7 +762,7 @@ sr_dis_exit: str tmp1, [pmc, #AT91_PMC_PLL_UPDT] /* step 2. */ - ldr tmp1, =AT91_PMC_PLL_ACR_DEFAULT_PLLA + ldr tmp1, .saved_acr str tmp1, [pmc, #AT91_PMC_PLL_ACR] /* step 3. */ @@ -1207,6 +1211,8 @@ ENDPROC(at91_pm_suspend_in_sram) #endif .saved_mckr: .word 0 +.saved_acr: + .word 0 .saved_pllar: .word 0 .saved_sam9_lpr: From af98caeaa7b6ad11eb7b7c8bfaddc769df2889f3 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 27 Aug 2025 17:08:10 +0200 Subject: [PATCH 1631/2711] clk: at91: clk-sam9x60-pll: force write to PLL_UPDT register This register is important for sequencing the commands to PLLs, so actually write the update bits with regmap_write_bits() instead of relying on a read/modify/write regmap command that could skip the actual hardware write if the value is identical to the one read. It's changed when modification is needed to the PLL, when read-only operation is done, we could keep the call to regmap_update_bits(). Add a comment to the sam9x60_div_pll_set_div() function that uses this PLL_UPDT register so that it's used consistently, according to the product's datasheet. Signed-off-by: Nicolas Ferre Tested-by: Ryan Wanner # on sama7d65 and sam9x75 Link: https://lore.kernel.org/r/20250827150811.82496-1-nicolas.ferre@microchip.com [claudiu.beznea: fix "Alignment should match open parenthesis" checkpatch.pl check] Signed-off-by: Claudiu Beznea --- drivers/clk/at91/clk-sam9x60-pll.c | 75 ++++++++++++++++-------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c index cefd9948e103..a035dc15454b 100644 --- a/drivers/clk/at91/clk-sam9x60-pll.c +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -93,8 +93,8 @@ static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core) spin_lock_irqsave(core->lock, flags); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_ID_MSK, core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_ID_MSK, core->id); regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val); cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift; cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift; @@ -128,17 +128,17 @@ static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core) udelay(10); } - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, - AT91_PMC_PLL_UPDT_UPDATE | core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | core->id); regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL, AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, - AT91_PMC_PLL_UPDT_UPDATE | core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | core->id); while (!sam9x60_pll_ready(regmap, core->id)) cpu_relax(); @@ -164,8 +164,8 @@ static void sam9x60_frac_pll_unprepare(struct clk_hw *hw) spin_lock_irqsave(core->lock, flags); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_ID_MSK, core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_ID_MSK, core->id); regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, AT91_PMC_PLL_CTRL0_ENPLL, 0); @@ -173,9 +173,9 @@ static void sam9x60_frac_pll_unprepare(struct clk_hw *hw) regmap_update_bits(regmap, AT91_PMC_PLL_ACR, AT91_PMC_PLL_ACR_UTMIBG | AT91_PMC_PLL_ACR_UTMIVR, 0); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, - AT91_PMC_PLL_UPDT_UPDATE | core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | core->id); spin_unlock_irqrestore(core->lock, flags); } @@ -262,8 +262,8 @@ static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate, spin_lock_irqsave(core->lock, irqflags); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, - core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + core->id); regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val); cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift; cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift; @@ -275,18 +275,18 @@ static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate, (frac->mul << core->layout->mul_shift) | (frac->frac << core->layout->frac_shift)); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, - AT91_PMC_PLL_UPDT_UPDATE | core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | core->id); regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL, AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, - AT91_PMC_PLL_UPDT_UPDATE | core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | core->id); while (!sam9x60_pll_ready(regmap, core->id)) cpu_relax(); @@ -338,7 +338,10 @@ static const struct clk_ops sam9x60_frac_pll_ops_chg = { .restore_context = sam9x60_frac_pll_restore_context, }; -/* This function should be called with spinlock acquired. */ +/* This function should be called with spinlock acquired. + * Warning: this function must be called only if the same PLL ID was set in + * PLL_UPDT register previously. + */ static void sam9x60_div_pll_set_div(struct sam9x60_pll_core *core, u32 div, bool enable) { @@ -350,9 +353,9 @@ static void sam9x60_div_pll_set_div(struct sam9x60_pll_core *core, u32 div, core->layout->div_mask | ena_msk, (div << core->layout->div_shift) | ena_val); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, - AT91_PMC_PLL_UPDT_UPDATE | core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | core->id); while (!sam9x60_pll_ready(regmap, core->id)) cpu_relax(); @@ -366,8 +369,8 @@ static int sam9x60_div_pll_set(struct sam9x60_pll_core *core) unsigned int val, cdiv; spin_lock_irqsave(core->lock, flags); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_ID_MSK, core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_ID_MSK, core->id); regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val); cdiv = (val & core->layout->div_mask) >> core->layout->div_shift; @@ -398,15 +401,15 @@ static void sam9x60_div_pll_unprepare(struct clk_hw *hw) spin_lock_irqsave(core->lock, flags); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_ID_MSK, core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_ID_MSK, core->id); regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, core->layout->endiv_mask, 0); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, - AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, - AT91_PMC_PLL_UPDT_UPDATE | core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, + AT91_PMC_PLL_UPDT_UPDATE | core->id); spin_unlock_irqrestore(core->lock, flags); } @@ -518,8 +521,8 @@ static int sam9x60_div_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate, div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1; spin_lock_irqsave(core->lock, irqflags); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, - core->id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + core->id); regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val); cdiv = (val & core->layout->div_mask) >> core->layout->div_shift; @@ -574,8 +577,8 @@ static int sam9x60_div_pll_notifier_fn(struct notifier_block *notifier, div->div = div->safe_div; spin_lock_irqsave(core.lock, irqflags); - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, - core.id); + regmap_write_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK, + core.id); regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val); cdiv = (val & core.layout->div_mask) >> core.layout->div_shift; From e0237f5635727d64635ec6665e1de9f4cacce35c Mon Sep 17 00:00:00 2001 From: Ryan Wanner Date: Mon, 8 Sep 2025 13:07:17 -0700 Subject: [PATCH 1632/2711] clk: at91: clk-master: Add check for divide by 3 A potential divider for the master clock is div/3. The register configuration for div/3 is MASTER_PRES_MAX. The current bit shifting method does not work for this case. Checking for MASTER_PRES_MAX will ensure the correct decimal value is stored in the system. Signed-off-by: Ryan Wanner Signed-off-by: Nicolas Ferre --- drivers/clk/at91/clk-master.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index 7a544e429d34..d5ea2069ec83 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -580,6 +580,9 @@ clk_sama7g5_master_recalc_rate(struct clk_hw *hw, { struct clk_master *master = to_clk_master(hw); + if (master->div == MASTER_PRES_MAX) + return DIV_ROUND_CLOSEST_ULL(parent_rate, 3); + return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div)); } From 94a1274100e397a27361ae53ace37be6da42a079 Mon Sep 17 00:00:00 2001 From: Balamanikandan Gunasundar Date: Tue, 9 Sep 2025 16:08:17 +0530 Subject: [PATCH 1633/2711] clk: at91: sam9x7: Add peripheral clock id for pmecc Add pmecc instance id in peripheral clock description. Signed-off-by: Balamanikandan Gunasundar Link: https://lore.kernel.org/r/20250909103817.49334-1-balamanikandan.gunasundar@microchip.com [claudiu.beznea@tuxon.dev: use tabs instead of spaces] Signed-off-by: Claudiu Beznea Signed-off-by: Nicolas Ferre --- drivers/clk/at91/sam9x7.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/at91/sam9x7.c b/drivers/clk/at91/sam9x7.c index ffab32b047a0..740f52906f6b 100644 --- a/drivers/clk/at91/sam9x7.c +++ b/drivers/clk/at91/sam9x7.c @@ -403,6 +403,7 @@ static const struct { { .n = "pioD_clk", .id = 44, }, { .n = "tcb1_clk", .id = 45, }, { .n = "dbgu_clk", .id = 47, }, + { .n = "pmecc_clk", .id = 48, }, /* * mpddr_clk feeds DDR controller and is enabled by bootloader thus we * need to keep it enabled in case there is no Linux consumer for it. From bfa2bddf6ffe0ac034d02cda20c74ef05571210e Mon Sep 17 00:00:00 2001 From: Cristian Birsan Date: Thu, 21 Nov 2024 17:47:17 +0200 Subject: [PATCH 1634/2711] clk: at91: add ACR in all PLL settings Add the ACR register to all PLL settings and provide the correct ACR value for each PLL used in different SoCs. Suggested-by: Mihai Sain Signed-off-by: Cristian Birsan [nicolas.ferre@microchip.com: add sama7d65 and review commit message] Signed-off-by: Nicolas Ferre --- drivers/clk/at91/pmc.h | 1 + drivers/clk/at91/sam9x60.c | 2 ++ drivers/clk/at91/sam9x7.c | 5 +++++ drivers/clk/at91/sama7d65.c | 4 ++++ drivers/clk/at91/sama7g5.c | 2 ++ 5 files changed, 14 insertions(+) diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 4fb29ca111f7..5daa32c4cf25 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -80,6 +80,7 @@ struct clk_pll_characteristics { u16 *icpll; u8 *out; u8 upll : 1; + u32 acr; }; struct clk_programmable_layout { diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index db6db9e2073e..18baf4a256f4 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -36,6 +36,7 @@ static const struct clk_pll_characteristics plla_characteristics = { .num_output = ARRAY_SIZE(plla_outputs), .output = plla_outputs, .core_output = core_outputs, + .acr = UL(0x00020010), }; static const struct clk_range upll_outputs[] = { @@ -48,6 +49,7 @@ static const struct clk_pll_characteristics upll_characteristics = { .output = upll_outputs, .core_output = core_outputs, .upll = true, + .acr = UL(0x12023010), /* fIN = [18 MHz, 32 MHz]*/ }; static const struct clk_pll_layout pll_frac_layout = { diff --git a/drivers/clk/at91/sam9x7.c b/drivers/clk/at91/sam9x7.c index 740f52906f6b..89868a0aeaba 100644 --- a/drivers/clk/at91/sam9x7.c +++ b/drivers/clk/at91/sam9x7.c @@ -107,6 +107,7 @@ static const struct clk_pll_characteristics plla_characteristics = { .num_output = ARRAY_SIZE(plla_outputs), .output = plla_outputs, .core_output = plla_core_outputs, + .acr = UL(0x00020010), /* Old ACR_DEFAULT_PLLA value */ }; static const struct clk_pll_characteristics upll_characteristics = { @@ -115,6 +116,7 @@ static const struct clk_pll_characteristics upll_characteristics = { .output = upll_outputs, .core_output = upll_core_outputs, .upll = true, + .acr = UL(0x12023010), /* fIN=[20 MHz, 32 MHz] */ }; static const struct clk_pll_characteristics lvdspll_characteristics = { @@ -122,6 +124,7 @@ static const struct clk_pll_characteristics lvdspll_characteristics = { .num_output = ARRAY_SIZE(lvdspll_outputs), .output = lvdspll_outputs, .core_output = lvdspll_core_outputs, + .acr = UL(0x12023010), /* fIN=[20 MHz, 32 MHz] */ }; static const struct clk_pll_characteristics audiopll_characteristics = { @@ -129,6 +132,7 @@ static const struct clk_pll_characteristics audiopll_characteristics = { .num_output = ARRAY_SIZE(audiopll_outputs), .output = audiopll_outputs, .core_output = audiopll_core_outputs, + .acr = UL(0x12023010), /* fIN=[20 MHz, 32 MHz] */ }; static const struct clk_pll_characteristics plladiv2_characteristics = { @@ -136,6 +140,7 @@ static const struct clk_pll_characteristics plladiv2_characteristics = { .num_output = ARRAY_SIZE(plladiv2_outputs), .output = plladiv2_outputs, .core_output = plladiv2_core_outputs, + .acr = UL(0x00020010), /* Old ACR_DEFAULT_PLLA value */ }; /* Layout for fractional PLL ID PLLA. */ diff --git a/drivers/clk/at91/sama7d65.c b/drivers/clk/at91/sama7d65.c index a5d40df8b2f2..7dee2b160ffb 100644 --- a/drivers/clk/at91/sama7d65.c +++ b/drivers/clk/at91/sama7d65.c @@ -138,6 +138,7 @@ static const struct clk_pll_characteristics cpu_pll_characteristics = { .num_output = ARRAY_SIZE(cpu_pll_outputs), .output = cpu_pll_outputs, .core_output = core_outputs, + .acr = UL(0x00070010), }; /* PLL characteristics. */ @@ -146,6 +147,7 @@ static const struct clk_pll_characteristics pll_characteristics = { .num_output = ARRAY_SIZE(pll_outputs), .output = pll_outputs, .core_output = core_outputs, + .acr = UL(0x00070010), }; static const struct clk_pll_characteristics lvdspll_characteristics = { @@ -153,6 +155,7 @@ static const struct clk_pll_characteristics lvdspll_characteristics = { .num_output = ARRAY_SIZE(lvdspll_outputs), .output = lvdspll_outputs, .core_output = lvdspll_core_outputs, + .acr = UL(0x00070010), }; static const struct clk_pll_characteristics upll_characteristics = { @@ -160,6 +163,7 @@ static const struct clk_pll_characteristics upll_characteristics = { .num_output = ARRAY_SIZE(upll_outputs), .output = upll_outputs, .core_output = upll_core_outputs, + .acr = UL(0x12020010), .upll = true, }; diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index 8385badc1c70..1340c2b00619 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -113,6 +113,7 @@ static const struct clk_pll_characteristics cpu_pll_characteristics = { .num_output = ARRAY_SIZE(cpu_pll_outputs), .output = cpu_pll_outputs, .core_output = core_outputs, + .acr = UL(0x00070010), }; /* PLL characteristics. */ @@ -121,6 +122,7 @@ static const struct clk_pll_characteristics pll_characteristics = { .num_output = ARRAY_SIZE(pll_outputs), .output = pll_outputs, .core_output = core_outputs, + .acr = UL(0x00070010), }; /* From 652b08afba69d5d26fe91098eb832b1bcc0f91c2 Mon Sep 17 00:00:00 2001 From: Cristian Birsan Date: Thu, 21 Nov 2024 20:16:38 +0200 Subject: [PATCH 1635/2711] ARM: at91: remove default values for PMC_PLL_ACR Remove default values for PMC PLL Analog Control Register(ACR) as the values are specific for each SoC and PLL and load them from PLL characteristics structure Co-developed-by: Andrei Simion Signed-off-by: Andrei Simion Signed-off-by: Cristian Birsan [nicolas.ferre@microchip.com: fix pll acr write sequence, preserve val] Signed-off-by: Nicolas Ferre --- drivers/clk/at91/clk-sam9x60-pll.c | 7 ++----- include/linux/clk/at91_pmc.h | 2 -- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c index a035dc15454b..3dc75a394ce1 100644 --- a/drivers/clk/at91/clk-sam9x60-pll.c +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -103,11 +103,8 @@ static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core) (cmul == frac->mul && cfrac == frac->frac)) goto unlock; - /* Recommended value for PMC_PLL_ACR */ - if (core->characteristics->upll) - val = AT91_PMC_PLL_ACR_DEFAULT_UPLL; - else - val = AT91_PMC_PLL_ACR_DEFAULT_PLLA; + /* Load recommended value for PMC_PLL_ACR */ + val = core->characteristics->acr; regmap_write(regmap, AT91_PMC_PLL_ACR, val); regmap_write(regmap, AT91_PMC_PLL_CTRL1, diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 7af499bdbecb..d60ce9708ea2 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -47,8 +47,6 @@ #define AT91_PMC_PCSR 0x18 /* Peripheral Clock Status Register */ #define AT91_PMC_PLL_ACR 0x18 /* PLL Analog Control Register [for SAM9X60] */ -#define AT91_PMC_PLL_ACR_DEFAULT_UPLL UL(0x12020010) /* Default PLL ACR value for UPLL */ -#define AT91_PMC_PLL_ACR_DEFAULT_PLLA UL(0x00020010) /* Default PLL ACR value for PLLA */ #define AT91_PMC_PLL_ACR_UTMIVR (1 << 12) /* UPLL Voltage regulator Control */ #define AT91_PMC_PLL_ACR_UTMIBG (1 << 13) /* UPLL Bandgap Control */ From f9d803784f8dfea60f394d7fc94084c5f1eb4027 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 17 Sep 2025 14:11:18 -0700 Subject: [PATCH 1636/2711] dt-bindings: input: touchscreen: document Himax HX852x(ES) Himax HX852x(ES) is a touch panel controller with optional support for capacitive touch keys. Unfortunately, the model naming is quite unclear and confusing. There seems to be a distinction between models (e.g. HX8526) and the "series" suffix (e.g. -A, -B, -C, -D, -E, -ES). But this doesn't seem to be applied very consistently because e.g. HX8527-E(44) actually seems to belong to the -ES series. The compatible consists of the actual part number followed by the "series" as fallback compatible. Typically only the latter will be interesting for drivers as there is no relevant difference on the driver side. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20250915-hx852x-v5-1-b938182f1056@linaro.org Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/himax,hx852es.yaml | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/himax,hx852es.yaml diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax,hx852es.yaml b/Documentation/devicetree/bindings/input/touchscreen/himax,hx852es.yaml new file mode 100644 index 000000000000..40a60880111d --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/himax,hx852es.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/himax,hx852es.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Himax HX852x(ES) touch panel controller + +maintainers: + - Stephan Gerhold + +allOf: + - $ref: touchscreen.yaml# + +properties: + compatible: + items: + - enum: + - himax,hx8525e + - himax,hx8526e + - himax,hx8527e + - const: himax,hx852es + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + description: Touch Screen Interrupt (TSIX), active low + + reset-gpios: + maxItems: 1 + description: External Reset (XRES), active low + + vcca-supply: + description: Analog power supply (VCCA) + + vccd-supply: + description: Digital power supply (VCCD) + + touchscreen-inverted-x: true + touchscreen-inverted-y: true + touchscreen-size-x: true + touchscreen-size-y: true + touchscreen-swapped-x-y: true + + linux,keycodes: + minItems: 1 + maxItems: 4 + +required: + - compatible + - reg + - interrupts + - reset-gpios + +additionalProperties: false + +examples: + - | + #include + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@48 { + compatible = "himax,hx8527e", "himax,hx852es"; + reg = <0x48>; + interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>; + vcca-supply = <®_ts_vcca>; + vccd-supply = <&pm8916_l6>; + linux,keycodes = ; + }; + }; + +... From 09fd8626cf8285503b4803b30b06c296599a24e7 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 17 Sep 2025 14:11:32 -0700 Subject: [PATCH 1637/2711] Input: add Himax HX852x(ES) touchscreen driver Add a simple driver for the Himax HX852x(ES) touch panel controller, with support for multi-touch and capacitive touch keys. The driver is somewhat based on sample code from Himax. However, that code was rather confusing, so that we spent a significant amount of time just trying to understand the packet format and register commands. In this driver they are described with clean structs and defines rather than magic numbers and offset calculations. Co-developed-by: Jonathan Albrieux Signed-off-by: Jonathan Albrieux Reviewed-by: Jeff LaBundy Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20250915-hx852x-v5-2-b938182f1056@linaro.org Signed-off-by: Dmitry Torokhov --- MAINTAINERS | 7 + drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/himax_hx852x.c | 503 +++++++++++++++++++++++ 4 files changed, 521 insertions(+) create mode 100644 drivers/input/touchscreen/himax_hx852x.c diff --git a/MAINTAINERS b/MAINTAINERS index 6ac78b0ccc1c..55df846b3934 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10965,6 +10965,13 @@ S: Maintained F: Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml F: drivers/input/touchscreen/himax_hx83112b.c +HIMAX HX852X TOUCHSCREEN DRIVER +M: Stephan Gerhold +L: linux-input@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/input/touchscreen/himax,hx852es.yaml +F: drivers/input/touchscreen/himax_hx852x.c + HIPPI M: Jes Sorensen S: Maintained diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 196905162945..762d71f79abd 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -441,6 +441,16 @@ config TOUCHSCREEN_HIDEEP To compile this driver as a module, choose M here : the module will be called hideep_ts. +config TOUCHSCREEN_HIMAX_HX852X + tristate "Himax HX852x(ES) touchscreen" + depends on I2C + help + Say Y here if you have a Himax HX852x(ES) touchscreen. + If unsure, say N. + + To compile this driver as a module, choose M here: the module + will be called himax_hx852x. + config TOUCHSCREEN_HYCON_HY46XX tristate "Hycon hy46xx touchscreen support" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 97a025c6a377..1e7c2f324e12 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI) += goodix_berlin_spi.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX852X) += himax_hx852x.o obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o diff --git a/drivers/input/touchscreen/himax_hx852x.c b/drivers/input/touchscreen/himax_hx852x.c new file mode 100644 index 000000000000..83c60e137a55 --- /dev/null +++ b/drivers/input/touchscreen/himax_hx852x.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Himax HX852x(ES) Touchscreen Driver + * Copyright (c) 2020-2024 Stephan Gerhold + * Copyright (c) 2020 Jonathan Albrieux + * + * Based on the Himax Android Driver Sample Code Ver 0.3 for HMX852xES chipset: + * Copyright (c) 2014 Himax Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HX852X_COORD_SIZE(fingers) ((fingers) * sizeof(struct hx852x_coord)) +#define HX852X_WIDTH_SIZE(fingers) ALIGN(fingers, 4) +#define HX852X_BUF_SIZE(fingers) (HX852X_COORD_SIZE(fingers) + \ + HX852X_WIDTH_SIZE(fingers) + \ + sizeof(struct hx852x_touch_info)) + +#define HX852X_MAX_FINGERS 12 +#define HX852X_MAX_KEY_COUNT 4 +#define HX852X_MAX_BUF_SIZE HX852X_BUF_SIZE(HX852X_MAX_FINGERS) + +#define HX852X_TS_SLEEP_IN 0x80 +#define HX852X_TS_SLEEP_OUT 0x81 +#define HX852X_TS_SENSE_OFF 0x82 +#define HX852X_TS_SENSE_ON 0x83 +#define HX852X_READ_ONE_EVENT 0x85 +#define HX852X_READ_ALL_EVENTS 0x86 +#define HX852X_READ_LATEST_EVENT 0x87 +#define HX852X_CLEAR_EVENT_STACK 0x88 + +#define HX852X_REG_SRAM_SWITCH 0x8c +#define HX852X_REG_SRAM_ADDR 0x8b +#define HX852X_REG_FLASH_RPLACE 0x5a + +#define HX852X_SRAM_SWITCH_TEST_MODE 0x14 +#define HX852X_SRAM_ADDR_CONFIG 0x7000 + +struct hx852x { + struct i2c_client *client; + struct input_dev *input_dev; + struct touchscreen_properties props; + struct gpio_desc *reset_gpiod; + struct regulator_bulk_data supplies[2]; + unsigned int max_fingers; + unsigned int keycount; + unsigned int keycodes[HX852X_MAX_KEY_COUNT]; +}; + +struct hx852x_config { + u8 rx_num; + u8 tx_num; + u8 max_pt; + u8 padding1[3]; + __be16 x_res; + __be16 y_res; + u8 padding2[2]; +} __packed __aligned(4); + +struct hx852x_coord { + __be16 x; + __be16 y; +} __packed __aligned(4); + +struct hx852x_touch_info { + u8 finger_num; + __le16 finger_pressed; + u8 padding; +} __packed __aligned(4); + +static int hx852x_i2c_read(struct hx852x *hx, u8 cmd, void *data, u16 len) +{ + struct i2c_client *client = hx->client; + int error; + int ret; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &cmd, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + error = ret < 0 ? ret : -EIO; + dev_err(&client->dev, "failed to read %#x: %d\n", cmd, error); + return error; + } + + return 0; +} + +static int hx852x_power_on(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + int error; + + error = regulator_bulk_enable(ARRAY_SIZE(hx->supplies), hx->supplies); + if (error) { + dev_err(dev, "failed to enable regulators: %d\n", error); + return error; + } + + gpiod_set_value_cansleep(hx->reset_gpiod, 1); + msleep(20); + gpiod_set_value_cansleep(hx->reset_gpiod, 0); + msleep(50); + + return 0; +} + +static int hx852x_start(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + int error; + + error = i2c_smbus_write_byte(hx->client, HX852X_TS_SLEEP_OUT); + if (error) { + dev_err(dev, "failed to send TS_SLEEP_OUT: %d\n", error); + return error; + } + msleep(30); + + error = i2c_smbus_write_byte(hx->client, HX852X_TS_SENSE_ON); + if (error) { + dev_err(dev, "failed to send TS_SENSE_ON: %d\n", error); + return error; + } + msleep(20); + + return 0; +} + +static int hx852x_stop(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + int error; + + error = i2c_smbus_write_byte(hx->client, HX852X_TS_SENSE_OFF); + if (error) { + dev_err(dev, "failed to send TS_SENSE_OFF: %d\n", error); + return error; + } + msleep(20); + + error = i2c_smbus_write_byte(hx->client, HX852X_TS_SLEEP_IN); + if (error) { + dev_err(dev, "failed to send TS_SLEEP_IN: %d\n", error); + return error; + } + msleep(30); + + return 0; +} + +static int hx852x_power_off(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + int error; + + error = regulator_bulk_disable(ARRAY_SIZE(hx->supplies), hx->supplies); + if (error) { + dev_err(dev, "failed to disable regulators: %d\n", error); + return error; + } + + return 0; +} + +static int hx852x_read_config(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + struct hx852x_config conf; + int x_res, y_res; + int error, error2; + + error = hx852x_power_on(hx); + if (error) + return error; + + /* Sensing must be turned on briefly to load the config */ + error = hx852x_start(hx); + if (error) + goto err_power_off; + + error = hx852x_stop(hx); + if (error) + goto err_power_off; + + error = i2c_smbus_write_byte_data(hx->client, HX852X_REG_SRAM_SWITCH, + HX852X_SRAM_SWITCH_TEST_MODE); + if (error) + goto err_power_off; + + error = i2c_smbus_write_word_data(hx->client, HX852X_REG_SRAM_ADDR, + HX852X_SRAM_ADDR_CONFIG); + if (error) + goto err_test_mode; + + error = hx852x_i2c_read(hx, HX852X_REG_FLASH_RPLACE, &conf, sizeof(conf)); + if (error) + goto err_test_mode; + + x_res = be16_to_cpu(conf.x_res); + y_res = be16_to_cpu(conf.y_res); + hx->max_fingers = (conf.max_pt & 0xf0) >> 4; + dev_dbg(dev, "x res: %u, y res: %u, max fingers: %u\n", + x_res, y_res, hx->max_fingers); + + if (hx->max_fingers > HX852X_MAX_FINGERS) { + dev_err(dev, "max supported fingers: %u, found: %u\n", + HX852X_MAX_FINGERS, hx->max_fingers); + error = -EINVAL; + goto err_test_mode; + } + + if (x_res && y_res) { + input_set_abs_params(hx->input_dev, ABS_MT_POSITION_X, 0, x_res - 1, 0, 0); + input_set_abs_params(hx->input_dev, ABS_MT_POSITION_Y, 0, y_res - 1, 0, 0); + } + +err_test_mode: + error2 = i2c_smbus_write_byte_data(hx->client, HX852X_REG_SRAM_SWITCH, 0); + error = error ?: error2; +err_power_off: + error2 = hx852x_power_off(hx); + return error ?: error2; +} + +static int hx852x_handle_events(struct hx852x *hx) +{ + /* + * The event packets have variable size, depending on the amount of + * supported fingers (hx->max_fingers). They are laid out as follows: + * - struct hx852x_coord[hx->max_fingers]: Coordinates for each finger + * - u8[ALIGN(hx->max_fingers, 4)]: Touch width for each finger + * with padding for 32-bit alignment + * - struct hx852x_touch_info + * + * Load everything into a 32-bit aligned buffer so the coordinates + * can be assigned directly, without using get_unaligned_*(). + */ + u8 buf[HX852X_MAX_BUF_SIZE] __aligned(4); + struct hx852x_coord *coord = (struct hx852x_coord *)buf; + u8 *width = &buf[HX852X_COORD_SIZE(hx->max_fingers)]; + struct hx852x_touch_info *info = (struct hx852x_touch_info *) + &width[HX852X_WIDTH_SIZE(hx->max_fingers)]; + unsigned long finger_pressed, key_pressed; + unsigned int i, x, y, w; + int error; + + error = hx852x_i2c_read(hx, HX852X_READ_ALL_EVENTS, buf, + HX852X_BUF_SIZE(hx->max_fingers)); + if (error) + return error; + + finger_pressed = get_unaligned_le16(&info->finger_pressed); + key_pressed = finger_pressed >> HX852X_MAX_FINGERS; + + /* All bits are set when no touch is detected */ + if (info->finger_num == 0xff || !(info->finger_num & 0x0f)) + finger_pressed = 0; + if (key_pressed == 0xf) + key_pressed = 0; + + for_each_set_bit(i, &finger_pressed, hx->max_fingers) { + x = be16_to_cpu(coord[i].x); + y = be16_to_cpu(coord[i].y); + w = width[i]; + + input_mt_slot(hx->input_dev, i); + input_mt_report_slot_state(hx->input_dev, MT_TOOL_FINGER, 1); + touchscreen_report_pos(hx->input_dev, &hx->props, x, y, true); + input_report_abs(hx->input_dev, ABS_MT_TOUCH_MAJOR, w); + } + input_mt_sync_frame(hx->input_dev); + + for (i = 0; i < hx->keycount; i++) + input_report_key(hx->input_dev, hx->keycodes[i], key_pressed & BIT(i)); + + input_sync(hx->input_dev); + return 0; +} + +static irqreturn_t hx852x_interrupt(int irq, void *ptr) +{ + struct hx852x *hx = ptr; + int error; + + error = hx852x_handle_events(hx); + if (error) { + dev_err_ratelimited(&hx->client->dev, + "failed to handle events: %d\n", error); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static int hx852x_input_open(struct input_dev *dev) +{ + struct hx852x *hx = input_get_drvdata(dev); + int error; + + error = hx852x_power_on(hx); + if (error) + return error; + + error = hx852x_start(hx); + if (error) { + hx852x_power_off(hx); + return error; + } + + enable_irq(hx->client->irq); + return 0; +} + +static void hx852x_input_close(struct input_dev *dev) +{ + struct hx852x *hx = input_get_drvdata(dev); + + hx852x_stop(hx); + disable_irq(hx->client->irq); + hx852x_power_off(hx); +} + +static int hx852x_parse_properties(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + int error, count; + + count = device_property_count_u32(dev, "linux,keycodes"); + if (count == -EINVAL) { + /* Property does not exist, keycodes are optional */ + return 0; + } else if (count < 0) { + dev_err(dev, "Failed to read linux,keycodes: %d\n", count); + return count; + } else if (count > HX852X_MAX_KEY_COUNT) { + dev_err(dev, "max supported keys: %u, found: %u\n", + HX852X_MAX_KEY_COUNT, hx->keycount); + return -EINVAL; + } + hx->keycount = count; + + error = device_property_read_u32_array(dev, "linux,keycodes", + hx->keycodes, hx->keycount); + if (error) { + dev_err(dev, "failed to read linux,keycodes: %d\n", error); + return error; + } + + return 0; +} + +static int hx852x_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct hx852x *hx; + int error, i; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | + I2C_FUNC_SMBUS_WRITE_BYTE | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA | + I2C_FUNC_SMBUS_WRITE_WORD_DATA)) { + dev_err(dev, "not all required i2c functionality supported\n"); + return -ENXIO; + } + + hx = devm_kzalloc(dev, sizeof(*hx), GFP_KERNEL); + if (!hx) + return -ENOMEM; + + hx->client = client; + hx->input_dev = devm_input_allocate_device(dev); + if (!hx->input_dev) + return -ENOMEM; + + hx->input_dev->name = "Himax HX852x"; + hx->input_dev->id.bustype = BUS_I2C; + hx->input_dev->open = hx852x_input_open; + hx->input_dev->close = hx852x_input_close; + + i2c_set_clientdata(client, hx); + input_set_drvdata(hx->input_dev, hx); + + hx->supplies[0].supply = "vcca"; + hx->supplies[1].supply = "vccd"; + error = devm_regulator_bulk_get(dev, ARRAY_SIZE(hx->supplies), hx->supplies); + if (error) + return dev_err_probe(dev, error, "failed to get regulators\n"); + + hx->reset_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(hx->reset_gpiod)) + return dev_err_probe(dev, PTR_ERR(hx->reset_gpiod), + "failed to get reset gpio\n"); + + error = devm_request_threaded_irq(dev, client->irq, NULL, hx852x_interrupt, + IRQF_ONESHOT | IRQF_NO_AUTOEN, NULL, hx); + if (error) + return dev_err_probe(dev, error, "failed to request irq %d", client->irq); + + error = hx852x_read_config(hx); + if (error) + return error; + + input_set_capability(hx->input_dev, EV_ABS, ABS_MT_POSITION_X); + input_set_capability(hx->input_dev, EV_ABS, ABS_MT_POSITION_Y); + input_set_abs_params(hx->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + + touchscreen_parse_properties(hx->input_dev, true, &hx->props); + error = hx852x_parse_properties(hx); + if (error) + return error; + + hx->input_dev->keycode = hx->keycodes; + hx->input_dev->keycodemax = hx->keycount; + hx->input_dev->keycodesize = sizeof(hx->keycodes[0]); + for (i = 0; i < hx->keycount; i++) + input_set_capability(hx->input_dev, EV_KEY, hx->keycodes[i]); + + error = input_mt_init_slots(hx->input_dev, hx->max_fingers, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) + return dev_err_probe(dev, error, "failed to init MT slots\n"); + + error = input_register_device(hx->input_dev); + if (error) + return dev_err_probe(dev, error, "failed to register input device\n"); + + return 0; +} + +static int hx852x_suspend(struct device *dev) +{ + struct hx852x *hx = dev_get_drvdata(dev); + + guard(mutex)(&hx->input_dev->mutex); + + if (input_device_enabled(hx->input_dev)) + return hx852x_stop(hx); + + return 0; +} + +static int hx852x_resume(struct device *dev) +{ + struct hx852x *hx = dev_get_drvdata(dev); + + guard(mutex)(&hx->input_dev->mutex); + + if (input_device_enabled(hx->input_dev)) + return hx852x_start(hx); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(hx852x_pm_ops, hx852x_suspend, hx852x_resume); + +#ifdef CONFIG_OF +static const struct of_device_id hx852x_of_match[] = { + { .compatible = "himax,hx852es" }, + { } +}; +MODULE_DEVICE_TABLE(of, hx852x_of_match); +#endif + +static struct i2c_driver hx852x_driver = { + .probe = hx852x_probe, + .driver = { + .name = "himax_hx852x", + .pm = pm_sleep_ptr(&hx852x_pm_ops), + .of_match_table = of_match_ptr(hx852x_of_match), + }, +}; +module_i2c_driver(hx852x_driver); + +MODULE_DESCRIPTION("Himax HX852x(ES) Touchscreen Driver"); +MODULE_AUTHOR("Jonathan Albrieux "); +MODULE_AUTHOR("Stephan Gerhold "); +MODULE_LICENSE("GPL"); From 11fafeb2657e2c2df3d011ca759962a4e81b19b1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 14 Aug 2025 11:47:06 -0700 Subject: [PATCH 1638/2711] Input: twl4030_keypad - drop support for platform data Support for platform data from dropped from twl in 4a346a03a63c ("mfd: twl: Remove platform data support") and board files were dropped even earlier. There are no in-kernel users of twl4030_keypad_data in the kernel, and the driver supports configuration via generic device properties. Drop support of static platform data from the keypad driver. Reviewed-by: Andreas Kemnade Link: https://lore.kernel.org/r/tica7ol7xwv5tqb7hlkzu6wkiv4quxwrpqv6croe4wfnwvj6wv@4ob6ktqqi3cr Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/twl4030_keypad.c | 35 +++++-------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 77e0743a3cf8..5e3d17c5dc9b 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -28,10 +28,6 @@ * an internal state machine that decodes pressed keys, including * multi-key combinations. * - * This driver lets boards define what keycodes they wish to report for - * which scancodes, as part of the "struct twl4030_keypad_data" used in - * the probe() routine. - * * See the TPS65950 documentation; that's the general availability * version of the TWL5030 second generation part. */ @@ -47,7 +43,6 @@ struct twl4030_keypad { unsigned short keymap[TWL4030_KEYMAP_SIZE]; u16 kp_state[TWL4030_MAX_ROWS]; - bool autorepeat; unsigned int n_rows; unsigned int n_cols; int irq; @@ -322,8 +317,6 @@ static int twl4030_kp_program(struct twl4030_keypad *kp) */ static int twl4030_kp_probe(struct platform_device *pdev) { - struct twl4030_keypad_data *pdata = dev_get_platdata(&pdev->dev); - const struct matrix_keymap_data *keymap_data = NULL; struct twl4030_keypad *kp; struct input_dev *input; u8 reg; @@ -350,24 +343,10 @@ static int twl4030_kp_probe(struct platform_device *pdev) input->id.product = 0x0001; input->id.version = 0x0003; - if (pdata) { - if (!pdata->rows || !pdata->cols || !pdata->keymap_data) { - dev_err(&pdev->dev, "Missing platform_data\n"); - return -EINVAL; - } - - kp->n_rows = pdata->rows; - kp->n_cols = pdata->cols; - kp->autorepeat = pdata->rep; - keymap_data = pdata->keymap_data; - } else { - error = matrix_keypad_parse_properties(&pdev->dev, &kp->n_rows, - &kp->n_cols); - if (error) - return error; - - kp->autorepeat = true; - } + error = matrix_keypad_parse_properties(&pdev->dev, + &kp->n_rows, &kp->n_cols); + if (error) + return error; if (kp->n_rows > TWL4030_MAX_ROWS || kp->n_cols > TWL4030_MAX_COLS) { dev_err(&pdev->dev, @@ -379,7 +358,7 @@ static int twl4030_kp_probe(struct platform_device *pdev) if (kp->irq < 0) return kp->irq; - error = matrix_keypad_build_keymap(keymap_data, NULL, + error = matrix_keypad_build_keymap(NULL, NULL, TWL4030_MAX_ROWS, 1 << TWL4030_ROW_SHIFT, kp->keymap, input); @@ -389,9 +368,7 @@ static int twl4030_kp_probe(struct platform_device *pdev) } input_set_capability(input, EV_MSC, MSC_SCAN); - /* Enable auto repeat feature of Linux input subsystem */ - if (kp->autorepeat) - __set_bit(EV_REP, input->evbit); + __set_bit(EV_REP, input->evbit); error = input_register_device(input); if (error) { From 1b7d2e1742427527aac2b2d5cb92fb8f2f047cad Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 16 Sep 2025 13:13:26 -0400 Subject: [PATCH 1639/2711] dt-bindings: input: convert tca8418_keypad.txt to yaml format Convert tca8418_keypad.txt to yaml format. Signed-off-by: Frank Li Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250916171327.3773620-1-Frank.Li@nxp.com Signed-off-by: Dmitry Torokhov --- .../bindings/input/tca8418_keypad.txt | 10 --- .../devicetree/bindings/input/ti,tca8418.yaml | 61 +++++++++++++++++++ 2 files changed, 61 insertions(+), 10 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/tca8418_keypad.txt create mode 100644 Documentation/devicetree/bindings/input/ti,tca8418.yaml diff --git a/Documentation/devicetree/bindings/input/tca8418_keypad.txt b/Documentation/devicetree/bindings/input/tca8418_keypad.txt deleted file mode 100644 index 255185009167..000000000000 --- a/Documentation/devicetree/bindings/input/tca8418_keypad.txt +++ /dev/null @@ -1,10 +0,0 @@ -This binding is based on the matrix-keymap binding with the following -changes: - -keypad,num-rows and keypad,num-columns are required. - -Required properties: -- compatible: "ti,tca8418" -- reg: the I2C address -- interrupts: IRQ line number, should trigger on falling edge -- linux,keymap: Keys definitions, see keypad-matrix. diff --git a/Documentation/devicetree/bindings/input/ti,tca8418.yaml b/Documentation/devicetree/bindings/input/ti,tca8418.yaml new file mode 100644 index 000000000000..624a1830d0b0 --- /dev/null +++ b/Documentation/devicetree/bindings/input/ti,tca8418.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/ti,tca8418.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI TCA8418 I2C/SMBus keypad scanner + +maintainers: + - Frank Li + +properties: + compatible: + enum: + - ti,tca8418 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +allOf: + - $ref: matrix-keymap.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + keypad@34 { + compatible = "ti,tca8418"; + reg = <0x34>; + interrupt-parent = <&gpio5>; + interrupts = <11 IRQ_TYPE_EDGE_FALLING>; + keypad,num-rows = <4>; + keypad,num-columns = <4>; + linux,keymap = < MATRIX_KEY(0x00, 0x01, BTN_0) + MATRIX_KEY(0x00, 0x00, BTN_1) + MATRIX_KEY(0x01, 0x01, BTN_2) + MATRIX_KEY(0x01, 0x00, BTN_3) + MATRIX_KEY(0x02, 0x00, BTN_4) + MATRIX_KEY(0x00, 0x03, BTN_5) + MATRIX_KEY(0x00, 0x02, BTN_6) + MATRIX_KEY(0x01, 0x03, BTN_7) + MATRIX_KEY(0x01, 0x02, BTN_8) + MATRIX_KEY(0x02, 0x02, BTN_9) + >; + }; + }; From 6c521885da34e61908d84a4f3eda85545f060848 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Wed, 17 Sep 2025 10:05:06 +0200 Subject: [PATCH 1640/2711] Input: imx6ul_tsc - fix typo in register name Replace 'SETING' with 'SETTING'. Signed-off-by: Michael Trimarchi Signed-off-by: Dario Binacchi Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250917080534.1772202-2-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imx6ul_tsc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index 6ac8fa84ed9f..c2c6e50efc54 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -55,7 +55,7 @@ #define ADC_TIMEOUT msecs_to_jiffies(100) /* TSC registers */ -#define REG_TSC_BASIC_SETING 0x00 +#define REG_TSC_BASIC_SETTING 0x00 #define REG_TSC_PRE_CHARGE_TIME 0x10 #define REG_TSC_FLOW_CONTROL 0x20 #define REG_TSC_MEASURE_VALUE 0x30 @@ -192,7 +192,7 @@ static void imx6ul_tsc_set(struct imx6ul_tsc *tsc) basic_setting |= tsc->measure_delay_time << 8; basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE; - writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETING); + writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETTING); writel(DE_GLITCH_2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2); From 05fcd78bcb14f68d46e4de8812ce6646d3d7f941 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Wed, 17 Sep 2025 10:05:07 +0200 Subject: [PATCH 1641/2711] Input: imx6ul_tsc - use BIT, FIELD_{GET,PREP} and GENMASK macros Replace opencoded masking and shifting, with BIT(), GENMASK(), FIELD_GET() and FIELD_PREP() macros. Signed-off-by: Dario Binacchi Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250917080534.1772202-3-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imx6ul_tsc.c | 96 +++++++++++++++----------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index c2c6e50efc54..e2c59cc7c82c 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -20,25 +21,23 @@ #include /* ADC configuration registers field define */ -#define ADC_AIEN (0x1 << 7) +#define ADC_AIEN BIT(7) +#define ADC_ADCH_MASK GENMASK(4, 0) #define ADC_CONV_DISABLE 0x1F -#define ADC_AVGE (0x1 << 5) -#define ADC_CAL (0x1 << 7) -#define ADC_CALF 0x2 -#define ADC_12BIT_MODE (0x2 << 2) -#define ADC_CONV_MODE_MASK (0x3 << 2) +#define ADC_AVGE BIT(5) +#define ADC_CAL BIT(7) +#define ADC_CALF BIT(1) +#define ADC_CONV_MODE_MASK GENMASK(3, 2) +#define ADC_12BIT_MODE 0x2 #define ADC_IPG_CLK 0x00 -#define ADC_INPUT_CLK_MASK 0x3 -#define ADC_CLK_DIV_8 (0x03 << 5) -#define ADC_CLK_DIV_MASK (0x3 << 5) -#define ADC_SHORT_SAMPLE_MODE (0x0 << 4) -#define ADC_SAMPLE_MODE_MASK (0x1 << 4) -#define ADC_HARDWARE_TRIGGER (0x1 << 13) -#define ADC_AVGS_SHIFT 14 -#define ADC_AVGS_MASK (0x3 << 14) +#define ADC_INPUT_CLK_MASK GENMASK(1, 0) +#define ADC_CLK_DIV_8 0x03 +#define ADC_CLK_DIV_MASK GENMASK(6, 5) +#define ADC_SAMPLE_MODE BIT(4) +#define ADC_HARDWARE_TRIGGER BIT(13) +#define ADC_AVGS_MASK GENMASK(15, 14) #define SELECT_CHANNEL_4 0x04 #define SELECT_CHANNEL_1 0x01 -#define DISABLE_CONVERSION_INT (0x0 << 7) /* ADC registers */ #define REG_ADC_HC0 0x00 @@ -65,19 +64,26 @@ #define REG_TSC_DEBUG_MODE 0x70 #define REG_TSC_DEBUG_MODE2 0x80 +/* TSC_MEASURE_VALUE register field define */ +#define X_VALUE_MASK GENMASK(27, 16) +#define Y_VALUE_MASK GENMASK(11, 0) + /* TSC configuration registers field define */ -#define DETECT_4_WIRE_MODE (0x0 << 4) -#define AUTO_MEASURE 0x1 -#define MEASURE_SIGNAL 0x1 -#define DETECT_SIGNAL (0x1 << 4) -#define VALID_SIGNAL (0x1 << 8) -#define MEASURE_INT_EN 0x1 -#define MEASURE_SIG_EN 0x1 -#define VALID_SIG_EN (0x1 << 8) -#define DE_GLITCH_2 (0x2 << 29) -#define START_SENSE (0x1 << 12) -#define TSC_DISABLE (0x1 << 16) +#define MEASURE_DELAY_TIME_MASK GENMASK(31, 8) +#define DETECT_5_WIRE_MODE BIT(4) +#define AUTO_MEASURE BIT(0) +#define MEASURE_SIGNAL BIT(0) +#define DETECT_SIGNAL BIT(4) +#define VALID_SIGNAL BIT(8) +#define MEASURE_INT_EN BIT(0) +#define MEASURE_SIG_EN BIT(0) +#define VALID_SIG_EN BIT(8) +#define DE_GLITCH_MASK GENMASK(30, 29) +#define DE_GLITCH_2 0x02 +#define START_SENSE BIT(12) +#define TSC_DISABLE BIT(16) #define DETECT_MODE 0x2 +#define STATE_MACHINE_MASK GENMASK(22, 20) struct imx6ul_tsc { struct device *dev; @@ -112,19 +118,20 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG); adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK); - adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK; - adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK); - adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE; + adc_cfg |= FIELD_PREP(ADC_CONV_MODE_MASK, ADC_12BIT_MODE) | + FIELD_PREP(ADC_INPUT_CLK_MASK, ADC_IPG_CLK); + adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE); + adc_cfg |= FIELD_PREP(ADC_CLK_DIV_MASK, ADC_CLK_DIV_8); if (tsc->average_enable) { adc_cfg &= ~ADC_AVGS_MASK; - adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT; + adc_cfg |= FIELD_PREP(ADC_AVGS_MASK, tsc->average_select); } adc_cfg &= ~ADC_HARDWARE_TRIGGER; writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG); /* enable calibration interrupt */ adc_hc |= ADC_AIEN; - adc_hc |= ADC_CONV_DISABLE; + adc_hc |= FIELD_PREP(ADC_ADCH_MASK, ADC_CONV_DISABLE); writel(adc_hc, tsc->adc_regs + REG_ADC_HC0); /* start ADC calibration */ @@ -164,19 +171,21 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc) { u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4; - adc_hc0 = DISABLE_CONVERSION_INT; + adc_hc0 = FIELD_PREP(ADC_AIEN, 0); writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0); - adc_hc1 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_4; + adc_hc1 = FIELD_PREP(ADC_AIEN, 0) | + FIELD_PREP(ADC_ADCH_MASK, SELECT_CHANNEL_4); writel(adc_hc1, tsc->adc_regs + REG_ADC_HC1); - adc_hc2 = DISABLE_CONVERSION_INT; + adc_hc2 = FIELD_PREP(ADC_AIEN, 0); writel(adc_hc2, tsc->adc_regs + REG_ADC_HC2); - adc_hc3 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_1; + adc_hc3 = FIELD_PREP(ADC_AIEN, 0) | + FIELD_PREP(ADC_ADCH_MASK, SELECT_CHANNEL_1); writel(adc_hc3, tsc->adc_regs + REG_ADC_HC3); - adc_hc4 = DISABLE_CONVERSION_INT; + adc_hc4 = FIELD_PREP(ADC_AIEN, 0); writel(adc_hc4, tsc->adc_regs + REG_ADC_HC4); } @@ -188,13 +197,16 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc) static void imx6ul_tsc_set(struct imx6ul_tsc *tsc) { u32 basic_setting = 0; + u32 debug_mode2; u32 start; - basic_setting |= tsc->measure_delay_time << 8; - basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE; + basic_setting |= FIELD_PREP(MEASURE_DELAY_TIME_MASK, + tsc->measure_delay_time); + basic_setting |= AUTO_MEASURE; writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETTING); - writel(DE_GLITCH_2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2); + debug_mode2 = FIELD_PREP(DE_GLITCH_MASK, DE_GLITCH_2); + writel(debug_mode2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2); writel(tsc->pre_charge_time, tsc->tsc_regs + REG_TSC_PRE_CHARGE_TIME); writel(MEASURE_INT_EN, tsc->tsc_regs + REG_TSC_INT_EN); @@ -250,7 +262,7 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc) usleep_range(200, 400); debug_mode2 = readl(tsc->tsc_regs + REG_TSC_DEBUG_MODE2); - state_machine = (debug_mode2 >> 20) & 0x7; + state_machine = FIELD_GET(STATE_MACHINE_MASK, debug_mode2); } while (state_machine != DETECT_MODE); usleep_range(200, 400); @@ -278,8 +290,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id) if (status & MEASURE_SIGNAL) { value = readl(tsc->tsc_regs + REG_TSC_MEASURE_VALUE); - x = (value >> 16) & 0x0fff; - y = value & 0x0fff; + x = FIELD_GET(X_VALUE_MASK, value); + y = FIELD_GET(Y_VALUE_MASK, value); /* * In detect mode, we can get the xnur gpio value, From 6e4a5154934f8c7283452651c4d398d34a46e952 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 10 Sep 2025 18:44:01 -0400 Subject: [PATCH 1642/2711] dt-bindings: touchscreen: resistive-adc-touch: change to unevaluatedProperties Change additionalProperties to unevaluatedProperties because it refs to touchscreen.yaml. Fix below CHECK_DTBS warnings: arch/arm/boot/dts/nxp/imx/imx6dl-skov-revc-lt6.dtb: touchscreen (resistive-adc-touch): 'touchscreen-y-plate-ohms' does not match any of the regexes: '^pinctrl-[0-9]+$' from schema $id: http://devicetree.org/schemas/input/touchscreen/resistive-adc-touch.yaml# Signed-off-by: Frank Li Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250910224402.994046-1-Frank.Li@nxp.com Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/resistive-adc-touch.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.yaml b/Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.yaml index 7fc22a403d48..059d419f6c1c 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.yaml @@ -55,7 +55,7 @@ properties: touchscreen-min-pressure: true touchscreen-x-plate-ohms: true -additionalProperties: false +unevaluatedProperties: false required: - compatible From 08fa726e66039dfa80226dfa112931f60ad4c898 Mon Sep 17 00:00:00 2001 From: Michal Pecio Date: Thu, 18 Sep 2025 00:07:20 +0300 Subject: [PATCH 1643/2711] Revert "usb: xhci: Avoid Stop Endpoint retry loop if the endpoint seems Running" This reverts commit 28a76fcc4c85dd39633fb96edb643c91820133e3. No actual HW bugs are known where Endpoint Context shows Running state but Stop Endpoint fails repeatedly with Context State Error and leaves the endpoint state unchanged. Stop Endpoint retries on Running EPs have been performed since early 2021 with no such issues reported so far. Trying to handle this hypothetical case brings a more realistic danger: if Stop Endpoint fails on an endpoint which hasn't yet started after a doorbell ring and enough latency occurs before this completion event is handled, the driver may time out and begin removing cancelled TDs from a running endpoint, even though one more retry would stop it reliably. Such high latency is rare but not impossible, and removing TDs from a running endpoint can cause more damage than not giving back a cancelled URB (which wasn't happening anyway). So err on the side of caution and revert to the old policy of always retrying if the EP appears running. [Remove stable tag as we are dealing with theoretical cases -Mathias] Fixes: 28a76fcc4c85d ("usb: xhci: Avoid Stop Endpoint retry loop if the endpoint seems Running") Signed-off-by: Michal Pecio Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20250917210726.97100-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 3c08682020f0..d7bef1dd519f 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1262,19 +1262,16 @@ reset_done: * Stopped state, but it will soon change to Running. * * Assume this bug on unexpected Stop Endpoint failures. - * Keep retrying until the EP starts and stops again. + * Keep retrying until the EP starts and stops again, on + * chips where this is known to help. Wait for 100ms. */ + if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100))) + break; fallthrough; case EP_STATE_RUNNING: /* Race, HW handled stop ep cmd before ep was running */ xhci_dbg(xhci, "Stop ep completion ctx error, ctx_state %d\n", GET_EP_CTX_STATE(ep_ctx)); - /* - * Don't retry forever if we guessed wrong or a defective HC never starts - * the EP or says 'Running' but fails the command. We must give back TDs. - */ - if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100))) - break; command = xhci_alloc_command(xhci, false, GFP_ATOMIC); if (!command) { From 0ed023a88396088d4221c345a3911f553dd42598 Mon Sep 17 00:00:00 2001 From: Michal Pecio Date: Thu, 18 Sep 2025 00:07:21 +0300 Subject: [PATCH 1644/2711] usb: xhci: Update a comment about Stop Endpoint retries Retries are no longer gated by a quirk, so remove that part. Add a brief explanation of the timeout. Signed-off-by: Michal Pecio Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20250917210726.97100-3-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index d7bef1dd519f..543cbec560c5 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1262,8 +1262,9 @@ reset_done: * Stopped state, but it will soon change to Running. * * Assume this bug on unexpected Stop Endpoint failures. - * Keep retrying until the EP starts and stops again, on - * chips where this is known to help. Wait for 100ms. + * Keep retrying until the EP starts and stops again or + * up to a timeout (a defective HC may never start, or a + * driver bug may cause stopping an already stopped EP). */ if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100))) break; From 719de070f764e079cdcb4ddeeb5b19b3ddddf9c1 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Thu, 18 Sep 2025 00:07:22 +0300 Subject: [PATCH 1645/2711] usb: xhci-pci: add support for hosts with zero USB3 ports Add xhci support for PCI hosts that have zero USB3 ports. Avoid creating a shared Host Controller Driver (HCD) when there is only one root hub. Additionally, all references to 'xhci->shared_hcd' are now checked before use. Only xhci-pci.c requires modification to accommodate this change, as the xhci core already supports configurations with zero USB3 ports. This capability was introduced when xHCI Platform and MediaTek added support for zero USB3 ports. Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220181 Tested-by: Nick Nielsen Tested-by: grm1 Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20250917210726.97100-4-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 44 +++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 00fac8b233d2..5c8ab519f497 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -610,7 +610,7 @@ int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval; struct xhci_hcd *xhci; - struct usb_hcd *hcd; + struct usb_hcd *hcd, *usb3_hcd; struct reset_control *reset; reset = devm_reset_control_get_optional_exclusive(&dev->dev, NULL); @@ -636,26 +636,32 @@ int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id) hcd = dev_get_drvdata(&dev->dev); xhci = hcd_to_xhci(hcd); xhci->reset = reset; - xhci->shared_hcd = usb_create_shared_hcd(&xhci_pci_hc_driver, &dev->dev, - pci_name(dev), hcd); - if (!xhci->shared_hcd) { - retval = -ENOMEM; - goto dealloc_usb2_hcd; + + xhci->allow_single_roothub = 1; + if (!xhci_has_one_roothub(xhci)) { + xhci->shared_hcd = usb_create_shared_hcd(&xhci_pci_hc_driver, &dev->dev, + pci_name(dev), hcd); + if (!xhci->shared_hcd) { + retval = -ENOMEM; + goto dealloc_usb2_hcd; + } + + retval = xhci_ext_cap_init(xhci); + if (retval) + goto put_usb3_hcd; + + retval = usb_add_hcd(xhci->shared_hcd, dev->irq, IRQF_SHARED); + if (retval) + goto put_usb3_hcd; + } else { + retval = xhci_ext_cap_init(xhci); + if (retval) + goto dealloc_usb2_hcd; } - retval = xhci_ext_cap_init(xhci); - if (retval) - goto put_usb3_hcd; - - retval = usb_add_hcd(xhci->shared_hcd, dev->irq, - IRQF_SHARED); - if (retval) - goto put_usb3_hcd; - /* Roothub already marked as USB 3.0 speed */ - - if (!(xhci->quirks & XHCI_BROKEN_STREAMS) && - HCC_MAX_PSA(xhci->hcc_params) >= 4) - xhci->shared_hcd->can_do_streams = 1; + usb3_hcd = xhci_get_usb3_hcd(xhci); + if (usb3_hcd && !(xhci->quirks & XHCI_BROKEN_STREAMS) && HCC_MAX_PSA(xhci->hcc_params) >= 4) + usb3_hcd->can_do_streams = 1; /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */ pm_runtime_put_noidle(&dev->dev); From 931e468764b22a587febf562e57249e95e84350d Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Thu, 18 Sep 2025 00:07:23 +0300 Subject: [PATCH 1646/2711] usb: xhci: improve TR Dequeue Pointer mask Address the naming and usage of the TR Dequeue Pointer mask in the xhci driver. The Endpoint Context Field at offset 0x08 is defined as follows: Bit 0 Dequeue Cycle State (DCS) Bits 3:1 RsvdZ (Reserved and Zero) Bits 63:4 TR Dequeue Pointer When extracting the TR Dequeue Pointer for an Endpoint without Streams, in xhci_handle_cmd_set_deq(), the inverted Dequeue Cycle State mask (~EP_CTX_CYCLE_MASK) is used, inadvertently including the Reserved bits. Although bits 3:1 are typically zero, using the incorrect mask could cause issues. The existing mask, named "SCTX_DEQ_MASK," is misleading because "SCTX" implies exclusivity to Stream Contexts, whereas the TR Dequeue Pointer is applicable to both Stream and non-Stream Contexts. Rename the mask to "TR_DEQ_PTR_MASK", utilize GENMASK_ULL() macro and use the mask when handling the TR Dequeue Pointer field. Function xhci_get_hw_deq() returns the Endpoint Context Field 0x08, either directly from the Endpoint context or a Stream. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20250917210726.97100-5-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 12 ++++++------ drivers/usb/host/xhci.h | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 543cbec560c5..8e209aa33ea7 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -711,7 +711,7 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, return -ENODEV; } - hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id); + hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id) & TR_DEQ_PTR_MASK; new_seg = ep_ring->deq_seg; new_deq = ep_ring->dequeue; new_cycle = le32_to_cpu(td->end_trb->generic.field[3]) & TRB_CYCLE; @@ -723,7 +723,7 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, */ do { if (!hw_dequeue_found && xhci_trb_virt_to_dma(new_seg, new_deq) - == (dma_addr_t)(hw_dequeue & ~0xf)) { + == (dma_addr_t)hw_dequeue) { hw_dequeue_found = true; if (td_last_trb_found) break; @@ -1066,7 +1066,7 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) */ hw_deq = xhci_get_hw_deq(xhci, ep->vdev, ep->ep_index, td->urb->stream_id); - hw_deq &= ~0xf; + hw_deq &= TR_DEQ_PTR_MASK; if (td->cancel_status == TD_HALTED || trb_in_td(td, hw_deq)) { switch (td->cancel_status) { @@ -1156,7 +1156,7 @@ static struct xhci_td *find_halted_td(struct xhci_virt_ep *ep) if (!list_empty(&ep->ring->td_list)) { /* Not streams compatible */ hw_deq = xhci_get_hw_deq(ep->xhci, ep->vdev, ep->ep_index, 0); - hw_deq &= ~0xf; + hw_deq &= TR_DEQ_PTR_MASK; td = list_first_entry(&ep->ring->td_list, struct xhci_td, td_list); if (trb_in_td(td, hw_deq)) return td; @@ -1479,7 +1479,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, u64 deq; /* 4.6.10 deq ptr is written to the stream ctx for streams */ if (ep->ep_state & EP_HAS_STREAMS) { - deq = le64_to_cpu(stream_ctx->stream_ring) & SCTX_DEQ_MASK; + deq = le64_to_cpu(stream_ctx->stream_ring) & TR_DEQ_PTR_MASK; /* * Cadence xHCI controllers store some endpoint state @@ -1495,7 +1495,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, stream_ctx->reserved[1] = 0; } } else { - deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK; + deq = le64_to_cpu(ep_ctx->deq) & TR_DEQ_PTR_MASK; } xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Successful Set TR Deq Ptr cmd, deq = @%08llx", deq); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index e09bd9a5a996..58a51f09cceb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -500,7 +500,8 @@ struct xhci_ep_ctx { /* deq bitmasks */ #define EP_CTX_CYCLE_MASK (1 << 0) -#define SCTX_DEQ_MASK (~0xfL) +/* bits 63:4 - TR Dequeue Pointer */ +#define TR_DEQ_PTR_MASK GENMASK_ULL(63, 4) /** From e16fdeaa96846aefd05760ca45be32da8c1dfc83 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Thu, 18 Sep 2025 00:07:24 +0300 Subject: [PATCH 1647/2711] usb: xhci: correct indentation for PORTSC tracing function Correct the indentation in USB Port Register Set (PORTSC) tracing. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20250917210726.97100-6-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-trace.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index bfb5c5c17012..f303ce600ff5 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -541,23 +541,23 @@ DEFINE_EVENT(xhci_log_ring, xhci_inc_deq, ); DECLARE_EVENT_CLASS(xhci_log_portsc, - TP_PROTO(struct xhci_port *port, u32 portsc), - TP_ARGS(port, portsc), - TP_STRUCT__entry( - __field(u32, busnum) - __field(u32, portnum) - __field(u32, portsc) - ), - TP_fast_assign( - __entry->busnum = port->rhub->hcd->self.busnum; - __entry->portnum = port->hcd_portnum; - __entry->portsc = portsc; - ), - TP_printk("port %d-%d: %s", - __entry->busnum, - __entry->portnum, - xhci_decode_portsc(__get_buf(XHCI_MSG_MAX), __entry->portsc) - ) + TP_PROTO(struct xhci_port *port, u32 portsc), + TP_ARGS(port, portsc), + TP_STRUCT__entry( + __field(u32, busnum) + __field(u32, portnum) + __field(u32, portsc) + ), + TP_fast_assign( + __entry->busnum = port->rhub->hcd->self.busnum; + __entry->portnum = port->hcd_portnum; + __entry->portsc = portsc; + ), + TP_printk("port %d-%d: %s", + __entry->busnum, + __entry->portnum, + xhci_decode_portsc(__get_buf(XHCI_MSG_MAX), __entry->portsc) + ) ); DEFINE_EVENT(xhci_log_portsc, xhci_handle_port_status, From a4e143636d5def935dd461539b67b61287a8dfef Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Thu, 18 Sep 2025 00:07:25 +0300 Subject: [PATCH 1648/2711] usb: xhci: align PORTSC trace with one-based port numbering In the xHCI driver, port numbers are typically described using a one-based index. However, tracing currently uses a zero-based index. To ensure consistency between tracing and dynamic debugging, update the trace port number to use a one-based index. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20250917210726.97100-7-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index f303ce600ff5..9abc904f1749 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -550,7 +550,7 @@ DECLARE_EVENT_CLASS(xhci_log_portsc, ), TP_fast_assign( __entry->busnum = port->rhub->hcd->self.busnum; - __entry->portnum = port->hcd_portnum; + __entry->portnum = port->hcd_portnum + 1; __entry->portsc = portsc; ), TP_printk("port %d-%d: %s", From 01adc8207cf3c42c5cf389be7578fd726ef26fe1 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 10 Sep 2025 14:36:45 +0200 Subject: [PATCH 1649/2711] mtd: nand: ecc-mxic: Lower log level during init A working init shall be silent rather than exposing the configuration with kernel messages at the error level. Thwart myself from the past and use the debug level for these. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/ecc-mxic.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/ecc-mxic.c b/drivers/mtd/nand/ecc-mxic.c index 1bf9a5a64b87..60cdcb4175ef 100644 --- a/drivers/mtd/nand/ecc-mxic.c +++ b/drivers/mtd/nand/ecc-mxic.c @@ -322,14 +322,14 @@ static int mxic_ecc_init_ctx(struct nand_device *nand, struct device *dev) sg_init_table(ctx->sg, 2); /* Configuration dump and sanity checks */ - dev_err(dev, "DPE version number: %d\n", + dev_dbg(dev, "DPE version number: %d\n", readl(mxic->regs + DP_VER) >> DP_VER_OFFSET); - dev_err(dev, "Chunk size: %d\n", readl(mxic->regs + CHUNK_SIZE)); - dev_err(dev, "Main size: %d\n", readl(mxic->regs + MAIN_SIZE)); - dev_err(dev, "Spare size: %d\n", SPARE_SZ(spare_reg)); - dev_err(dev, "Rsv size: %ld\n", RSV_SZ(spare_reg)); - dev_err(dev, "Parity size: %d\n", ctx->parity_sz); - dev_err(dev, "Meta size: %d\n", ctx->meta_sz); + dev_dbg(dev, "Chunk size: %d\n", readl(mxic->regs + CHUNK_SIZE)); + dev_dbg(dev, "Main size: %d\n", readl(mxic->regs + MAIN_SIZE)); + dev_dbg(dev, "Spare size: %d\n", SPARE_SZ(spare_reg)); + dev_dbg(dev, "Rsv size: %ld\n", RSV_SZ(spare_reg)); + dev_dbg(dev, "Parity size: %d\n", ctx->parity_sz); + dev_dbg(dev, "Meta size: %d\n", ctx->meta_sz); if ((ctx->meta_sz + ctx->parity_sz + RSV_SZ(spare_reg)) != SPARE_SZ(spare_reg)) { From 6b88293aae7fb78872e5cc1ec36e2f750ae12e38 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Wed, 10 Sep 2025 14:32:58 -0400 Subject: [PATCH 1650/2711] mtd: nand: move nand_check_erased_ecc_chunk() to nand/core The check function for bitflips in erased blocks will be needed by the Realtek ECC engine driver (which is currently under development). Right now it is located in raw/nand_base.c. While this is sufficient for the current usecases, there is no real dependency for an ECC engine on the raw nand library. Move the function over to a more generic place in core library. Suggested-by: Miquel Raynal Signed-off-by: Markus Stockhausen Signed-off-by: Miquel Raynal --- drivers/mtd/nand/core.c | 131 +++++++++++++++++++++++++++++++ drivers/mtd/nand/raw/nand_base.c | 131 ------------------------------- include/linux/mtd/nand.h | 5 ++ include/linux/mtd/rawnand.h | 5 -- 4 files changed, 136 insertions(+), 136 deletions(-) diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c index 7737b1a4a177..3e76d127715f 100644 --- a/drivers/mtd/nand/core.c +++ b/drivers/mtd/nand/core.c @@ -12,6 +12,137 @@ #include #include +/** + * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data + * @buf: buffer to test + * @len: buffer length + * @bitflips_threshold: maximum number of bitflips + * + * Check if a buffer contains only 0xff, which means the underlying region + * has been erased and is ready to be programmed. + * The bitflips_threshold specify the maximum number of bitflips before + * considering the region is not erased. + * Note: The logic of this function has been extracted from the memweight + * implementation, except that nand_check_erased_buf function exit before + * testing the whole buffer if the number of bitflips exceed the + * bitflips_threshold value. + * + * Returns a positive number of bitflips less than or equal to + * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the + * threshold. + */ +static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold) +{ + const unsigned char *bitmap = buf; + int bitflips = 0; + int weight; + + for (; len && ((uintptr_t)bitmap) % sizeof(long); + len--, bitmap++) { + weight = hweight8(*bitmap); + bitflips += BITS_PER_BYTE - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + for (; len >= sizeof(long); + len -= sizeof(long), bitmap += sizeof(long)) { + unsigned long d = *((unsigned long *)bitmap); + if (d == ~0UL) + continue; + weight = hweight_long(d); + bitflips += BITS_PER_LONG - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + for (; len > 0; len--, bitmap++) { + weight = hweight8(*bitmap); + bitflips += BITS_PER_BYTE - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + return bitflips; +} + +/** + * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only + * 0xff data + * @data: data buffer to test + * @datalen: data length + * @ecc: ECC buffer + * @ecclen: ECC length + * @extraoob: extra OOB buffer + * @extraooblen: extra OOB length + * @bitflips_threshold: maximum number of bitflips + * + * Check if a data buffer and its associated ECC and OOB data contains only + * 0xff pattern, which means the underlying region has been erased and is + * ready to be programmed. + * The bitflips_threshold specify the maximum number of bitflips before + * considering the region as not erased. + * + * Note: + * 1/ ECC algorithms are working on pre-defined block sizes which are usually + * different from the NAND page size. When fixing bitflips, ECC engines will + * report the number of errors per chunk, and the NAND core infrastructure + * expect you to return the maximum number of bitflips for the whole page. + * This is why you should always use this function on a single chunk and + * not on the whole page. After checking each chunk you should update your + * max_bitflips value accordingly. + * 2/ When checking for bitflips in erased pages you should not only check + * the payload data but also their associated ECC data, because a user might + * have programmed almost all bits to 1 but a few. In this case, we + * shouldn't consider the chunk as erased, and checking ECC bytes prevent + * this case. + * 3/ The extraoob argument is optional, and should be used if some of your OOB + * data are protected by the ECC engine. + * It could also be used if you support subpages and want to attach some + * extra OOB data to an ECC chunk. + * + * Returns a positive number of bitflips less than or equal to + * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the + * threshold. In case of success, the passed buffers are filled with 0xff. + */ +int nand_check_erased_ecc_chunk(void *data, int datalen, + void *ecc, int ecclen, + void *extraoob, int extraooblen, + int bitflips_threshold) +{ + int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0; + + data_bitflips = nand_check_erased_buf(data, datalen, + bitflips_threshold); + if (data_bitflips < 0) + return data_bitflips; + + bitflips_threshold -= data_bitflips; + + ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold); + if (ecc_bitflips < 0) + return ecc_bitflips; + + bitflips_threshold -= ecc_bitflips; + + extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen, + bitflips_threshold); + if (extraoob_bitflips < 0) + return extraoob_bitflips; + + if (data_bitflips) + memset(data, 0xff, datalen); + + if (ecc_bitflips) + memset(ecc, 0xff, ecclen); + + if (extraoob_bitflips) + memset(extraoob, 0xff, extraooblen); + + return data_bitflips + ecc_bitflips + extraoob_bitflips; +} +EXPORT_SYMBOL(nand_check_erased_ecc_chunk); + /** * nanddev_isbad() - Check if a block is bad * @nand: NAND device diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 13e4060bd1b6..c7d9501f646b 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -2783,137 +2783,6 @@ int nand_set_features(struct nand_chip *chip, int addr, return nand_set_features_op(chip, addr, subfeature_param); } -/** - * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data - * @buf: buffer to test - * @len: buffer length - * @bitflips_threshold: maximum number of bitflips - * - * Check if a buffer contains only 0xff, which means the underlying region - * has been erased and is ready to be programmed. - * The bitflips_threshold specify the maximum number of bitflips before - * considering the region is not erased. - * Note: The logic of this function has been extracted from the memweight - * implementation, except that nand_check_erased_buf function exit before - * testing the whole buffer if the number of bitflips exceed the - * bitflips_threshold value. - * - * Returns a positive number of bitflips less than or equal to - * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the - * threshold. - */ -static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold) -{ - const unsigned char *bitmap = buf; - int bitflips = 0; - int weight; - - for (; len && ((uintptr_t)bitmap) % sizeof(long); - len--, bitmap++) { - weight = hweight8(*bitmap); - bitflips += BITS_PER_BYTE - weight; - if (unlikely(bitflips > bitflips_threshold)) - return -EBADMSG; - } - - for (; len >= sizeof(long); - len -= sizeof(long), bitmap += sizeof(long)) { - unsigned long d = *((unsigned long *)bitmap); - if (d == ~0UL) - continue; - weight = hweight_long(d); - bitflips += BITS_PER_LONG - weight; - if (unlikely(bitflips > bitflips_threshold)) - return -EBADMSG; - } - - for (; len > 0; len--, bitmap++) { - weight = hweight8(*bitmap); - bitflips += BITS_PER_BYTE - weight; - if (unlikely(bitflips > bitflips_threshold)) - return -EBADMSG; - } - - return bitflips; -} - -/** - * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only - * 0xff data - * @data: data buffer to test - * @datalen: data length - * @ecc: ECC buffer - * @ecclen: ECC length - * @extraoob: extra OOB buffer - * @extraooblen: extra OOB length - * @bitflips_threshold: maximum number of bitflips - * - * Check if a data buffer and its associated ECC and OOB data contains only - * 0xff pattern, which means the underlying region has been erased and is - * ready to be programmed. - * The bitflips_threshold specify the maximum number of bitflips before - * considering the region as not erased. - * - * Note: - * 1/ ECC algorithms are working on pre-defined block sizes which are usually - * different from the NAND page size. When fixing bitflips, ECC engines will - * report the number of errors per chunk, and the NAND core infrastructure - * expect you to return the maximum number of bitflips for the whole page. - * This is why you should always use this function on a single chunk and - * not on the whole page. After checking each chunk you should update your - * max_bitflips value accordingly. - * 2/ When checking for bitflips in erased pages you should not only check - * the payload data but also their associated ECC data, because a user might - * have programmed almost all bits to 1 but a few. In this case, we - * shouldn't consider the chunk as erased, and checking ECC bytes prevent - * this case. - * 3/ The extraoob argument is optional, and should be used if some of your OOB - * data are protected by the ECC engine. - * It could also be used if you support subpages and want to attach some - * extra OOB data to an ECC chunk. - * - * Returns a positive number of bitflips less than or equal to - * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the - * threshold. In case of success, the passed buffers are filled with 0xff. - */ -int nand_check_erased_ecc_chunk(void *data, int datalen, - void *ecc, int ecclen, - void *extraoob, int extraooblen, - int bitflips_threshold) -{ - int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0; - - data_bitflips = nand_check_erased_buf(data, datalen, - bitflips_threshold); - if (data_bitflips < 0) - return data_bitflips; - - bitflips_threshold -= data_bitflips; - - ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold); - if (ecc_bitflips < 0) - return ecc_bitflips; - - bitflips_threshold -= ecc_bitflips; - - extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen, - bitflips_threshold); - if (extraoob_bitflips < 0) - return extraoob_bitflips; - - if (data_bitflips) - memset(data, 0xff, datalen); - - if (ecc_bitflips) - memset(ecc, 0xff, ecclen); - - if (extraoob_bitflips) - memset(extraoob, 0xff, extraooblen); - - return data_bitflips + ecc_bitflips + extraoob_bitflips; -} -EXPORT_SYMBOL(nand_check_erased_ecc_chunk); - /** * nand_read_page_raw_notsupp - dummy read raw page function * @chip: nand chip info structure diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 07486168d104..09c8c93e4dba 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -1136,4 +1136,9 @@ static inline bool nanddev_bbt_is_initialized(struct nand_device *nand) int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo); int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len); +int nand_check_erased_ecc_chunk(void *data, int datalen, + void *ecc, int ecclen, + void *extraoob, int extraooblen, + int threshold); + #endif /* __LINUX_MTD_NAND_H */ diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index e84522e31301..d30bdc3fcfd7 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1519,11 +1519,6 @@ int rawnand_sw_bch_correct(struct nand_chip *chip, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc); void rawnand_sw_bch_cleanup(struct nand_chip *chip); -int nand_check_erased_ecc_chunk(void *data, int datalen, - void *ecc, int ecclen, - void *extraoob, int extraooblen, - int threshold); - int nand_ecc_choose_conf(struct nand_chip *chip, const struct nand_ecc_caps *caps, int oobavail); From b8df622cf7f6808c85764e681847150ed6d85f3d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Sep 2025 18:07:37 +0200 Subject: [PATCH 1651/2711] mtd: rawnand: fsmc: Default to autodetect buswidth If you don't specify buswidth 2 (16 bits) in the device tree, FSMC doesn't even probe anymore: fsmc-nand 10100000.flash: FSMC device partno 090, manufacturer 80, revision 00, config 00 nand: device found, Manufacturer ID: 0x20, Chip ID: 0xb1 nand: ST Micro 10100000.flash nand: bus width 8 instead of 16 bits nand: No NAND device found fsmc-nand 10100000.flash: probe with driver fsmc-nand failed with error -22 With this patch to use autodetection unless buswidth is specified, the device is properly detected again: fsmc-nand 10100000.flash: FSMC device partno 090, manufacturer 80, revision 00, config 00 nand: device found, Manufacturer ID: 0x20, Chip ID: 0xb1 nand: ST Micro NAND 128MiB 1,8V 16-bit nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64 fsmc-nand 10100000.flash: Using 1-bit HW ECC scheme Scanning device for bad blocks I don't know where or how this happened, I think some change in the nand core. Cc: stable@vger.kernel.org Signed-off-by: Linus Walleij Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/fsmc_nand.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index df61db8ce466..b13b2b0c3f30 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -876,10 +876,14 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, if (!of_property_read_u32(np, "bank-width", &val)) { if (val == 2) { nand->options |= NAND_BUSWIDTH_16; - } else if (val != 1) { + } else if (val == 1) { + nand->options |= NAND_BUSWIDTH_AUTO; + } else { dev_err(&pdev->dev, "invalid bank-width %u\n", val); return -EINVAL; } + } else { + nand->options |= NAND_BUSWIDTH_AUTO; } if (of_property_read_bool(np, "nand-skip-bbtscan")) From 3ebcd3460cad351f198c39c6edb4af519a0ed934 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Mon, 15 Sep 2025 22:12:47 +0000 Subject: [PATCH 1652/2711] binder: fix double-free in dbitmap A process might fail to allocate a new bitmap when trying to expand its proc->dmap. In that case, dbitmap_grow() fails and frees the old bitmap via dbitmap_free(). However, the driver calls dbitmap_free() again when the same process terminates, leading to a double-free error: ================================================================== BUG: KASAN: double-free in binder_proc_dec_tmpref+0x2e0/0x55c Free of addr ffff00000b7c1420 by task kworker/9:1/209 CPU: 9 UID: 0 PID: 209 Comm: kworker/9:1 Not tainted 6.17.0-rc6-dirty #5 PREEMPT Hardware name: linux,dummy-virt (DT) Workqueue: events binder_deferred_func Call trace: kfree+0x164/0x31c binder_proc_dec_tmpref+0x2e0/0x55c binder_deferred_func+0xc24/0x1120 process_one_work+0x520/0xba4 [...] Allocated by task 448: __kmalloc_noprof+0x178/0x3c0 bitmap_zalloc+0x24/0x30 binder_open+0x14c/0xc10 [...] Freed by task 449: kfree+0x184/0x31c binder_inc_ref_for_node+0xb44/0xe44 binder_transaction+0x29b4/0x7fbc binder_thread_write+0x1708/0x442c binder_ioctl+0x1b50/0x2900 [...] ================================================================== Fix this issue by marking proc->map NULL in dbitmap_free(). Cc: stable@vger.kernel.org Fixes: 15d9da3f818c ("binder: use bitmap for faster descriptor lookup") Signed-off-by: Carlos Llamas Reviewed-by: Alice Ryhl Reviewed-by: Tiffany Yang Link: https://lore.kernel.org/r/20250915221248.3470154-1-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/dbitmap.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/android/dbitmap.h b/drivers/android/dbitmap.h index 956f1bd087d1..c7299ce8b374 100644 --- a/drivers/android/dbitmap.h +++ b/drivers/android/dbitmap.h @@ -37,6 +37,7 @@ static inline void dbitmap_free(struct dbitmap *dmap) { dmap->nbits = 0; kfree(dmap->map); + dmap->map = NULL; } /* Returns the nbits that a dbitmap can shrink to, 0 if not possible. */ From 4a684088421d5a1ffb3b13243c58a9078c99e4b9 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 13:31:24 -0700 Subject: [PATCH 1653/2711] KVM: arm64: nv: Trap debug registers when in hyp context In case you haven't realized it yet, the architecture is _slightly_ broken in the context of nested virt. Here we have another example of FEAT_NV2 redirecting a sysreg (MDSCR_EL1) to memory that actually affects execution at vEL2. Fortunately, MDCR_EL2.TDA provides the necessary traps to hide this mess at the expense of unnecessarily trapping the breakpoint/watchpoint registers. Yes, FEAT_FGT gives us a precise trap but let's just opt for obvious correctness to start. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_nested.h | 2 ++ arch/arm64/kvm/debug.c | 3 +++ arch/arm64/kvm/nested.c | 11 +++++++++++ 3 files changed, 16 insertions(+) diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index 7fd76f41c296..cd3ab06abdca 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -83,6 +83,8 @@ extern void check_nested_vcpu_requests(struct kvm_vcpu *vcpu); extern void kvm_nested_flush_hwstate(struct kvm_vcpu *vcpu); extern void kvm_nested_sync_hwstate(struct kvm_vcpu *vcpu); +extern void kvm_nested_setup_mdcr_el2(struct kvm_vcpu *vcpu); + struct kvm_s2_trans { phys_addr_t output; unsigned long block_size; diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 381382c19fe4..fc275335c0ee 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -56,6 +56,9 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu) if (!kvm_guest_owns_debug_regs(vcpu)) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; + if (vcpu_has_nv(vcpu)) + kvm_nested_setup_mdcr_el2(vcpu); + /* Write MDCR_EL2 directly if we're already at EL2 */ if (has_vhe()) write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2); diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 77db81bae86f..9559c64e7e0c 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1796,3 +1796,14 @@ void kvm_nested_sync_hwstate(struct kvm_vcpu *vcpu) if (unlikely(vcpu_test_and_clear_flag(vcpu, NESTED_SERROR_PENDING))) kvm_inject_serror_esr(vcpu, vcpu_get_vsesr(vcpu)); } + +void kvm_nested_setup_mdcr_el2(struct kvm_vcpu *vcpu) +{ + /* + * In yet another example where FEAT_NV2 is fscking broken, accesses + * to MDSCR_EL1 are redirected to the VNCR despite having an effect + * at EL2. Use a big hammer to apply sanity. + */ + if (is_hyp_ctxt(vcpu)) + vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; +} From 3af1105c4fa362d17d577b55d2b8a7c4609f16fc Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 13:31:25 -0700 Subject: [PATCH 1654/2711] KVM: arm64: nv: Apply guest's MDCR traps in nested context KVM needs to ensure the guest hypervisor's traps take effect when the vCPU is in a nested context. While supporting infrastructure is in place for most of the EL2 trap registers, MDCR_EL2 is not. Fold the guest's trap configuration into the effective MDCR_EL2. Apply it directly to the in-memory representation as it gets recomputed on every vcpu_load() anyway. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 9559c64e7e0c..61542d6fd8f5 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1797,8 +1797,25 @@ void kvm_nested_sync_hwstate(struct kvm_vcpu *vcpu) kvm_inject_serror_esr(vcpu, vcpu_get_vsesr(vcpu)); } +/* + * KVM unconditionally sets most of these traps anyway but use an allowlist + * to document the guest hypervisor traps that may take precedence and guard + * against future changes to the non-nested trap configuration. + */ +#define NV_MDCR_GUEST_INCLUDE (MDCR_EL2_TDE | \ + MDCR_EL2_TDA | \ + MDCR_EL2_TDRA | \ + MDCR_EL2_TTRF | \ + MDCR_EL2_TPMS | \ + MDCR_EL2_TPM | \ + MDCR_EL2_TPMCR | \ + MDCR_EL2_TDCC | \ + MDCR_EL2_TDOSA) + void kvm_nested_setup_mdcr_el2(struct kvm_vcpu *vcpu) { + u64 guest_mdcr = __vcpu_sys_reg(vcpu, MDCR_EL2); + /* * In yet another example where FEAT_NV2 is fscking broken, accesses * to MDSCR_EL1 are redirected to the VNCR despite having an effect @@ -1806,4 +1823,6 @@ void kvm_nested_setup_mdcr_el2(struct kvm_vcpu *vcpu) */ if (is_hyp_ctxt(vcpu)) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; + else + vcpu->arch.mdcr_el2 |= (guest_mdcr & NV_MDCR_GUEST_INCLUDE); } From 68be6c432cfa84abe908668b0d5c26060f2fe589 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Mon, 15 Sep 2025 15:45:54 +0300 Subject: [PATCH 1655/2711] mei: gsc: fix remove operations order The mei disconnect should be the last operation in remove flow. Otherwise the device is used after destruction. Fix minor free flow that happens after device destruction too. The fault leads to the following oops in Intel Gfx CI: <4>[ 267.871331] Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6bcb: 0000 [#1] SMP NOPTI ... <4>[ 267.871410] RIP: 0010:mei_gsc_remove+0x44/0x90 [mei_gsc] ... <4>[ 267.871555] Call Trace: <4>[ 267.871562] <4>[ 267.871570] auxiliary_bus_remove+0x1b/0x30 <4>[ 267.871589] device_remove+0x43/0x80 <4>[ 267.871604] device_release_driver_internal+0x215/0x280 <4>[ 267.871619] device_release_driver+0x12/0x20 <4>[ 267.871630] bus_remove_device+0xdc/0x150 <4>[ 267.871645] device_del+0x15f/0x3b0 <4>[ 267.871656] ? bus_unregister_notifier+0x37/0x50 <4>[ 267.871672] gsc_destroy_one.isra.0+0x44/0x210 [i915] <4>[ 267.872295] intel_gsc_fini+0x28/0x50 [i915] <4>[ 267.872860] intel_gt_driver_unregister+0x2c/0x80 [i915] <4>[ 267.873300] i915_driver_remove+0x6e/0x150 [i915] <4>[ 267.873694] i915_pci_remove+0x1e/0x40 [i915] <4>[ 267.874095] pci_device_remove+0x3e/0xb0 <4>[ 267.874111] device_remove+0x43/0x80 <4>[ 267.874126] device_release_driver_internal+0x215/0x280 <4>[ 267.874137] ? bus_find_device+0xa5/0xe0 <4>[ 267.874153] device_driver_detach+0x14/0x20 <4>[ 267.874164] unbind_store+0xac/0xc0 <4>[ 267.874178] drv_attr_store+0x21/0x50 <4>[ 267.874190] sysfs_kf_write+0x4a/0x80 <4>[ 267.874204] kernfs_fop_write_iter+0x188/0x240 <4>[ 267.874222] vfs_write+0x283/0x540 <4>[ 267.874241] ksys_write+0x6f/0xf0 <4>[ 267.874253] __x64_sys_write+0x19/0x30 <4>[ 267.874264] x64_sys_call+0x79/0x26a0 <4>[ 267.874277] do_syscall_64+0x93/0xd50 <4>[ 267.874291] ? do_syscall_64+0x1a2/0xd50 <4>[ 267.874301] ? do_syscall_64+0x1a2/0xd50 <4>[ 267.874313] ? do_syscall_64+0x1a2/0xd50 <4>[ 267.874324] ? clear_bhb_loop+0x30/0x80 <4>[ 267.874336] ? clear_bhb_loop+0x30/0x80 <4>[ 267.874349] entry_SYSCALL_64_after_hwframe+0x76/0x7e Fixes: 7704e6be4ed2 ("mei: hook mei_device on class device") Signed-off-by: Alexander Usyskin Link: https://lore.kernel.org/r/20250915124554.2263330-1-alexander.usyskin@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/gsc-me.c | 4 ++-- drivers/misc/mei/main.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/misc/mei/gsc-me.c b/drivers/misc/mei/gsc-me.c index f147258e7c28..93cba090ea08 100644 --- a/drivers/misc/mei/gsc-me.c +++ b/drivers/misc/mei/gsc-me.c @@ -150,13 +150,13 @@ static void mei_gsc_remove(struct auxiliary_device *aux_dev) if (mei_me_hw_use_polling(hw)) kthread_stop(hw->polling_thread); - mei_deregister(dev); - pm_runtime_disable(&aux_dev->dev); mei_disable_interrupts(dev); if (!mei_me_hw_use_polling(hw)) devm_free_irq(&aux_dev->dev, hw->irq, dev); + + mei_deregister(dev); } static int __maybe_unused mei_gsc_pm_suspend(struct device *device) diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index f37f9b8b1f51..93c518bb5e14 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -1208,12 +1208,12 @@ static int mei_minor_get(struct mei_device *dev) /** * mei_minor_free - mark device minor number as free * - * @dev: device pointer + * @minor: minor number to free */ -static void mei_minor_free(struct mei_device *dev) +static void mei_minor_free(int minor) { mutex_lock(&mei_minor_lock); - idr_remove(&mei_idr, dev->minor); + idr_remove(&mei_idr, minor); mutex_unlock(&mei_minor_lock); } @@ -1225,11 +1225,14 @@ static void mei_device_release(struct device *dev) int mei_register(struct mei_device *dev, struct device *parent) { int ret, devno; + int minor; ret = mei_minor_get(dev); if (ret < 0) return ret; + minor = dev->minor; + /* Fill in the data structures */ devno = MKDEV(MAJOR(mei_devt), dev->minor); @@ -1279,7 +1282,7 @@ int mei_register(struct mei_device *dev, struct device *parent) err_del_cdev: cdev_del(dev->cdev); err: - mei_minor_free(dev); + mei_minor_free(minor); return ret; } EXPORT_SYMBOL_GPL(mei_register); @@ -1287,6 +1290,7 @@ EXPORT_SYMBOL_GPL(mei_register); void mei_deregister(struct mei_device *dev) { int devno; + int minor = dev->minor; devno = dev->cdev->dev; cdev_del(dev->cdev); @@ -1295,7 +1299,7 @@ void mei_deregister(struct mei_device *dev) device_destroy(&mei_class, devno); - mei_minor_free(dev); + mei_minor_free(minor); } EXPORT_SYMBOL_GPL(mei_deregister); From 2cedb296988c384e1555d74fb55e3b7b9fb268ae Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Thu, 18 Sep 2025 16:04:31 +0300 Subject: [PATCH 1656/2711] mei: me: trigger link reset if hw ready is unexpected Driver can receive HW not ready interrupt unexpectedly. E.g. for cards that go donwn to D3cold. Trigger link reset in this case to synchronize driver and firmware state. No need to do that sync if driver is going down or interrupt is received before driver started initial link reset sequence. Introduce UNINITIALIZED device state to allow interrupt handler to ignore interrupts before first init. Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250918130435.3327400-2-alexander.usyskin@intel.com --- drivers/misc/mei/hw-me.c | 17 ++++++++++++++--- drivers/misc/mei/init.c | 2 +- drivers/misc/mei/mei_dev.h | 3 ++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 346633ebc6e6..3172dc095b53 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1373,9 +1373,20 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) /* check if we need to start the dev */ if (!mei_host_is_ready(dev)) { if (mei_hw_is_ready(dev)) { - dev_dbg(&dev->dev, "we need to start the dev.\n"); - dev->recvd_hw_ready = true; - wake_up(&dev->wait_hw_ready); + /* synchronized by dev mutex */ + if (waitqueue_active(&dev->wait_hw_ready)) { + dev_dbg(&dev->dev, "we need to start the dev.\n"); + dev->recvd_hw_ready = true; + wake_up(&dev->wait_hw_ready); + } else if (dev->dev_state != MEI_DEV_UNINITIALIZED && + dev->dev_state != MEI_DEV_POWERING_DOWN && + dev->dev_state != MEI_DEV_POWER_DOWN) { + dev_dbg(&dev->dev, "Force link reset.\n"); + schedule_work(&dev->reset_work); + } else { + dev_dbg(&dev->dev, "Ignore this interrupt in state = %d\n", + dev->dev_state); + } } else { dev_dbg(&dev->dev, "Spurious Interrupt\n"); } diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 4d1d5423b612..b9fb54328a7b 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -399,7 +399,7 @@ void mei_device_init(struct mei_device *dev, init_waitqueue_head(&dev->wait_hw_ready); init_waitqueue_head(&dev->wait_pg); init_waitqueue_head(&dev->wait_hbm_start); - dev->dev_state = MEI_DEV_INITIALIZING; + dev->dev_state = MEI_DEV_UNINITIALIZED; dev->reset_count = 0; INIT_LIST_HEAD(&dev->write_list); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 4ab2b9100fd4..9f2044ae6cc4 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -57,7 +57,8 @@ enum file_state { /* MEI device states */ enum mei_dev_state { - MEI_DEV_INITIALIZING = 0, + MEI_DEV_UNINITIALIZED = 0, + MEI_DEV_INITIALIZING, MEI_DEV_INIT_CLIENTS, MEI_DEV_ENABLED, MEI_DEV_RESETTING, From bb29fc32ae56393269d8fe775159fd59e45682d1 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Thu, 18 Sep 2025 16:04:32 +0300 Subject: [PATCH 1657/2711] mei: make a local copy of client uuid in connect Connect ioctl has the same memory for in and out parameters. Copy in parameter (client uuid) to the local stack to avoid it be overwritten by out parameters fill. Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250918130435.3327400-3-alexander.usyskin@intel.com --- drivers/misc/mei/main.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index f37f9b8b1f51..2d41a05b8694 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -646,7 +646,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) struct mei_cl *cl = file->private_data; struct mei_connect_client_data conn; struct mei_connect_client_data_vtag conn_vtag; - const uuid_le *cl_uuid; + uuid_le cl_uuid; struct mei_client *props; u8 vtag; u32 notify_get, notify_req; @@ -674,18 +674,18 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) rets = -EFAULT; goto out; } - cl_uuid = &conn.in_client_uuid; + cl_uuid = conn.in_client_uuid; props = &conn.out_client_properties; vtag = 0; - rets = mei_vt_support_check(dev, cl_uuid); + rets = mei_vt_support_check(dev, &cl_uuid); if (rets == -ENOTTY) goto out; if (!rets) - rets = mei_ioctl_connect_vtag(file, cl_uuid, props, + rets = mei_ioctl_connect_vtag(file, &cl_uuid, props, vtag); else - rets = mei_ioctl_connect_client(file, cl_uuid, props); + rets = mei_ioctl_connect_client(file, &cl_uuid, props); if (rets) goto out; @@ -707,14 +707,14 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) goto out; } - cl_uuid = &conn_vtag.connect.in_client_uuid; + cl_uuid = conn_vtag.connect.in_client_uuid; props = &conn_vtag.out_client_properties; vtag = conn_vtag.connect.vtag; - rets = mei_vt_support_check(dev, cl_uuid); + rets = mei_vt_support_check(dev, &cl_uuid); if (rets == -EOPNOTSUPP) cl_dbg(dev, cl, "FW Client %pUl does not support vtags\n", - cl_uuid); + &cl_uuid); if (rets) goto out; @@ -724,7 +724,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) goto out; } - rets = mei_ioctl_connect_vtag(file, cl_uuid, props, vtag); + rets = mei_ioctl_connect_vtag(file, &cl_uuid, props, vtag); if (rets) goto out; From 2b5c4cb2c008f01182f87f529cb104bc5bc80418 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Thu, 18 Sep 2025 16:04:33 +0300 Subject: [PATCH 1658/2711] mei: retry connect if interrupted by link reset When device is in D3cold the connect message will wake device and cause link reset. Link reset flow cleans all queues and wakes all waiters. Retry the connect flow if connect is failed and link reset is detected. Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250918130435.3327400-4-alexander.usyskin@intel.com --- drivers/misc/mei/hw.h | 2 ++ drivers/misc/mei/init.c | 2 ++ drivers/misc/mei/main.c | 25 +++++++++++++++++++++++++ drivers/misc/mei/mei_dev.h | 3 +++ 4 files changed, 32 insertions(+) diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 2e9cf6f4efb6..3771aa09c592 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -27,6 +27,8 @@ #define MKHI_RCV_TIMEOUT 500 /* receive timeout in msec */ #define MKHI_RCV_TIMEOUT_SLOW 10000 /* receive timeout in msec, slow FW */ +#define MEI_LINK_RESET_WAIT_TIMEOUT_MSEC 500 /* Max wait timeout for link reset, in msec */ + /* * FW page size for DMA allocations */ diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index b9fb54328a7b..32ce6a879207 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -400,6 +400,7 @@ void mei_device_init(struct mei_device *dev, init_waitqueue_head(&dev->wait_pg); init_waitqueue_head(&dev->wait_hbm_start); dev->dev_state = MEI_DEV_UNINITIALIZED; + init_waitqueue_head(&dev->wait_dev_state); dev->reset_count = 0; INIT_LIST_HEAD(&dev->write_list); @@ -442,5 +443,6 @@ void mei_device_init(struct mei_device *dev, dev->timeouts.hbm = mei_secs_to_jiffies(MEI_HBM_TIMEOUT); dev->timeouts.mkhi_recv = msecs_to_jiffies(MKHI_RCV_TIMEOUT); } + dev->timeouts.link_reset_wait = msecs_to_jiffies(MEI_LINK_RESET_WAIT_TIMEOUT_MSEC); } EXPORT_SYMBOL_GPL(mei_device_init); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 2d41a05b8694..e69140fc5aa4 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -423,6 +423,7 @@ static int mei_ioctl_connect_client(struct file *file, cl->state != MEI_FILE_DISCONNECTED) return -EBUSY; +retry: /* find ME client we're trying to connect to */ me_cl = mei_me_cl_by_uuid(dev, in_client_uuid); if (!me_cl) { @@ -454,6 +455,28 @@ static int mei_ioctl_connect_client(struct file *file, rets = mei_cl_connect(cl, me_cl, file); + if (rets && cl->status == -EFAULT && + (dev->dev_state == MEI_DEV_RESETTING || + dev->dev_state == MEI_DEV_INIT_CLIENTS)) { + /* in link reset, wait for it completion */ + mutex_unlock(&dev->device_lock); + rets = wait_event_interruptible_timeout(dev->wait_dev_state, + dev->dev_state == MEI_DEV_ENABLED, + dev->timeouts.link_reset_wait); + mutex_lock(&dev->device_lock); + if (rets < 0) { + if (signal_pending(current)) + rets = -EINTR; + goto end; + } + if (dev->dev_state != MEI_DEV_ENABLED) { + rets = -ETIME; + goto end; + } + mei_me_cl_put(me_cl); + goto retry; + } + end: mei_me_cl_put(me_cl); return rets; @@ -1120,6 +1143,8 @@ void mei_set_devstate(struct mei_device *dev, enum mei_dev_state state) dev->dev_state = state; + wake_up_interruptible_all(&dev->wait_dev_state); + if (!dev->cdev) return; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 9f2044ae6cc4..23afa381a0a0 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -466,6 +466,7 @@ struct mei_dev_timeouts { unsigned int d0i3; /* D0i3 set/unset max response time, in jiffies */ unsigned long hbm; /* HBM operation timeout, in jiffies */ unsigned long mkhi_recv; /* receive timeout, in jiffies */ + unsigned long link_reset_wait; /* link reset wait timeout, in jiffies */ }; /** @@ -496,6 +497,7 @@ struct mei_dev_timeouts { * * @reset_count : number of consecutive resets * @dev_state : device state + * @wait_dev_state: wait queue for device state change * @hbm_state : state of host bus message protocol * @pxp_mode : PXP device mode * @init_clients_timer : HBM init handshake timeout @@ -588,6 +590,7 @@ struct mei_device { */ unsigned long reset_count; enum mei_dev_state dev_state; + wait_queue_head_t wait_dev_state; enum mei_hbm_state hbm_state; enum mei_dev_pxp_mode pxp_mode; u16 init_clients_timer; From ecdddd20b0c5987a824bb4f3948d5a597d8fb8d8 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Thu, 18 Sep 2025 16:04:34 +0300 Subject: [PATCH 1659/2711] mei: bus: demote error on connect There are flows, like exit from D3cold where connect via bus can fail. Demote error print to debug level to unclutter dmesg. Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250918130435.3327400-5-alexander.usyskin@intel.com --- drivers/misc/mei/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 6c8ec5c0d359..38735a41f750 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -814,7 +814,7 @@ int mei_cldev_enable(struct mei_cl_device *cldev) ret = mei_cl_connect(cl, cldev->me_cl, NULL); if (ret < 0) { - dev_err(&cldev->dev, "cannot connect\n"); + dev_dbg(&cldev->dev, "cannot connect\n"); mei_cl_bus_vtag_free(cldev); } From f9deb462d52e71e12f339a43b10f4443287e1f08 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Thu, 18 Sep 2025 16:04:35 +0300 Subject: [PATCH 1660/2711] mei: gsc: demote unexpected reset print Discrete graphic card can go to D3cold. On the exit from D3cold the link reset is performed. Driver did not expect such link reset and print warning. Print debug message for unexpected reset in discrete graphic case and remove infrastructure to print warning is some cases. Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250918130435.3327400-6-alexander.usyskin@intel.com --- drivers/misc/mei/hw-me.c | 42 +++----------------------------------- drivers/misc/mei/init.c | 17 --------------- drivers/misc/mei/mei_dev.h | 6 ------ 3 files changed, 3 insertions(+), 62 deletions(-) diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 3172dc095b53..d4612c659784 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -493,43 +493,6 @@ static int mei_me_hw_ready_wait(struct mei_device *dev) return 0; } -/** - * mei_me_check_fw_reset - check for the firmware reset error and exception conditions - * - * @dev: mei device - */ -static void mei_me_check_fw_reset(struct mei_device *dev) -{ - struct mei_fw_status fw_status; - char fw_sts_str[MEI_FW_STATUS_STR_SZ] = {0}; - int ret; - u32 fw_pm_event = 0; - - if (!dev->saved_fw_status_flag) - goto end; - - if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) { - ret = mei_fw_status(dev, &fw_status); - if (!ret) { - fw_pm_event = fw_status.status[1] & PCI_CFG_HFS_2_PM_EVENT_MASK; - if (fw_pm_event != PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR && - fw_pm_event != PCI_CFG_HFS_2_PM_CM_RESET_ERROR) - goto end; - } else { - dev_err(&dev->dev, "failed to read firmware status: %d\n", ret); - } - } - - mei_fw_status2str(&dev->saved_fw_status, fw_sts_str, sizeof(fw_sts_str)); - dev_warn(&dev->dev, "unexpected reset: fw_pm_event = 0x%x, dev_state = %u fw status = %s\n", - fw_pm_event, dev->saved_dev_state, fw_sts_str); - -end: - if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) - dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DONE; - dev->saved_fw_status_flag = false; -} - /** * mei_me_hw_start - hw start routine * @@ -540,8 +503,9 @@ static int mei_me_hw_start(struct mei_device *dev) { int ret = mei_me_hw_ready_wait(dev); - if (kind_is_gsc(dev) || kind_is_gscfi(dev)) - mei_me_check_fw_reset(dev); + if ((kind_is_gsc(dev) || kind_is_gscfi(dev)) && + dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DONE; if (ret) return ret; dev_dbg(&dev->dev, "hw is ready\n"); diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 32ce6a879207..b789c4d9c709 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -89,22 +89,6 @@ void mei_cancel_work(struct mei_device *dev) } EXPORT_SYMBOL_GPL(mei_cancel_work); -static void mei_save_fw_status(struct mei_device *dev) -{ - struct mei_fw_status fw_status; - int ret; - - ret = mei_fw_status(dev, &fw_status); - if (ret) { - dev_err(&dev->dev, "failed to read firmware status: %d\n", ret); - return; - } - - dev->saved_dev_state = dev->dev_state; - dev->saved_fw_status_flag = true; - memcpy(&dev->saved_fw_status, &fw_status, sizeof(fw_status)); -} - /** * mei_reset - resets host and fw. * @@ -128,7 +112,6 @@ int mei_reset(struct mei_device *dev) if (kind_is_gsc(dev) || kind_is_gscfi(dev)) { dev_dbg(&dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", mei_dev_state_str(state), fw_sts_str); - mei_save_fw_status(dev); } else { dev_warn(&dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", mei_dev_state_str(state), fw_sts_str); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 23afa381a0a0..0bf8d552c3ea 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -551,9 +551,6 @@ struct mei_dev_timeouts { * * @dbgfs_dir : debugfs mei root directory * - * @saved_fw_status : saved firmware status - * @saved_dev_state : saved device state - * @saved_fw_status_flag : flag indicating that firmware status was saved * @gsc_reset_to_pxp : state of reset to the PXP mode * * @ops: : hw specific operations @@ -654,9 +651,6 @@ struct mei_device { struct dentry *dbgfs_dir; #endif /* CONFIG_DEBUG_FS */ - struct mei_fw_status saved_fw_status; - enum mei_dev_state saved_dev_state; - bool saved_fw_status_flag; enum mei_dev_reset_to_pxp gsc_reset_to_pxp; const struct mei_hw_ops *ops; From 68d5d9734c12fce20ad493fe24738ab2019108c0 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 11:09:23 -0700 Subject: [PATCH 1661/2711] cxl/test: Refactor decoder setup to reduce cxl_test burden Group the decoder setup code in switch and endpoint port probe into a single function for each to reduce the number of functions to be mocked in cxl_test. Introduce devm_cxl_switch_port_decoders_setup() and devm_cxl_endpoint_decoders_setup(). These two functions will be mocked instead with some functions optimized out since the mock version does not do anything. Remove devm_cxl_setup_hdm(), devm_cxl_add_passthrough_decoder(), and devm_cxl_enumerate_decoders() in cxl_test mock code. In turn, mock_cxl_add_passthrough_decoder() can be removed since cxl_test does not setup passthrough decoders. __wrap_cxl_hdm_decode_init() and __wrap_cxl_dvsec_rr_decode() can be removed as well since they only return 0 when called. [dj: drop 'struct cxl_port' forward declaration (Robert)] Suggested-by: Robert Richter Reviewed-by: Alison Schofield Reviewed-by: Jonathan Cameron Reviewed-by: Robert Richter Signed-off-by: Dave Jiang --- drivers/cxl/core/core.h | 5 +++ drivers/cxl/core/hdm.c | 81 +++++++++++++++++++++++++++++++---- drivers/cxl/core/pci.c | 42 ++++++++++++++++++ drivers/cxl/cxl.h | 9 ++-- drivers/cxl/cxlpci.h | 2 - drivers/cxl/port.c | 38 +--------------- tools/testing/cxl/Kbuild | 7 +-- tools/testing/cxl/test/cxl.c | 42 +++++++++++++----- tools/testing/cxl/test/mock.c | 69 ++++------------------------- tools/testing/cxl/test/mock.h | 7 +-- 10 files changed, 169 insertions(+), 133 deletions(-) diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 2669f251d677..b07490aa93c7 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -147,6 +147,11 @@ int cxl_ras_init(void); void cxl_ras_exit(void); int cxl_gpf_port_setup(struct cxl_dport *dport); +struct cxl_hdm; +int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, + struct cxl_endpoint_dvsec_info *info); +int cxl_port_get_possible_dports(struct cxl_port *port); + #ifdef CONFIG_CXL_FEATURES struct cxl_feat_entry * cxl_feature_info(struct cxl_features_state *cxlfs, const uuid_t *uuid); diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index cee68bbc7ff6..78bfe4f55b96 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -49,7 +49,7 @@ static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld) * are claimed and passed to the single dport. Disable the range until the first * CXL region is enumerated / activated. */ -int devm_cxl_add_passthrough_decoder(struct cxl_port *port) +static int devm_cxl_add_passthrough_decoder(struct cxl_port *port) { struct cxl_switch_decoder *cxlsd; struct cxl_dport *dport = NULL; @@ -75,7 +75,6 @@ int devm_cxl_add_passthrough_decoder(struct cxl_port *port) return add_hdm_decoder(port, &cxlsd->cxld); } -EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, "CXL"); static void parse_hdm_decoder_caps(struct cxl_hdm *cxlhdm) { @@ -145,8 +144,8 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info) * @port: cxl_port to map * @info: cached DVSEC range register info */ -struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, - struct cxl_endpoint_dvsec_info *info) +static struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, + struct cxl_endpoint_dvsec_info *info) { struct cxl_register_map *reg_map = &port->reg_map; struct device *dev = &port->dev; @@ -201,7 +200,6 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, return cxlhdm; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, "CXL"); static void __cxl_dpa_debug(struct seq_file *file, struct resource *r, int depth) { @@ -1166,8 +1164,8 @@ static void cxl_settle_decoders(struct cxl_hdm *cxlhdm) * @cxlhdm: Structure to populate with HDM capabilities * @info: cached DVSEC range register info */ -int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, - struct cxl_endpoint_dvsec_info *info) +static int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, + struct cxl_endpoint_dvsec_info *info) { void __iomem *hdm = cxlhdm->regs.hdm_decoder; struct cxl_port *port = cxlhdm->port; @@ -1222,4 +1220,71 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, return 0; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_decoders, "CXL"); + +/** + * devm_cxl_switch_port_decoders_setup - allocate and setup switch decoders + * @port: CXL port context + * + * Return 0 or -errno on error + */ +int devm_cxl_switch_port_decoders_setup(struct cxl_port *port) +{ + struct cxl_hdm *cxlhdm; + + if (is_cxl_root(port) || is_cxl_endpoint(port)) + return -EOPNOTSUPP; + + cxlhdm = devm_cxl_setup_hdm(port, NULL); + if (!IS_ERR(cxlhdm)) + return devm_cxl_enumerate_decoders(cxlhdm, NULL); + + if (PTR_ERR(cxlhdm) != -ENODEV) { + dev_err(&port->dev, "Failed to map HDM decoder capability\n"); + return PTR_ERR(cxlhdm); + } + + if (cxl_port_get_possible_dports(port) == 1) { + dev_dbg(&port->dev, "Fallback to passthrough decoder\n"); + return devm_cxl_add_passthrough_decoder(port); + } + + dev_err(&port->dev, "HDM decoder capability not found\n"); + return -ENXIO; +} +EXPORT_SYMBOL_NS_GPL(devm_cxl_switch_port_decoders_setup, "CXL"); + +/** + * devm_cxl_endpoint_decoders_setup - allocate and setup endpoint decoders + * @port: CXL port context + * + * Return 0 or -errno on error + */ +int devm_cxl_endpoint_decoders_setup(struct cxl_port *port) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev); + struct cxl_endpoint_dvsec_info info = { .port = port }; + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_hdm *cxlhdm; + int rc; + + if (!is_cxl_endpoint(port)) + return -EOPNOTSUPP; + + rc = cxl_dvsec_rr_decode(cxlds, &info); + if (rc < 0) + return rc; + + cxlhdm = devm_cxl_setup_hdm(port, &info); + if (IS_ERR(cxlhdm)) { + if (PTR_ERR(cxlhdm) == -ENODEV) + dev_err(&port->dev, "HDM decoder registers not found\n"); + return PTR_ERR(cxlhdm); + } + + rc = cxl_hdm_decode_init(cxlds, cxlhdm, &info); + if (rc) + return rc; + + return devm_cxl_enumerate_decoders(cxlhdm, &info); +} +EXPORT_SYMBOL_NS_GPL(devm_cxl_endpoint_decoders_setup, "CXL"); diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index b50551601c2e..fa02366d35f2 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -1169,3 +1169,45 @@ int cxl_gpf_port_setup(struct cxl_dport *dport) return 0; } + +static int count_dports(struct pci_dev *pdev, void *data) +{ + struct cxl_walk_context *ctx = data; + int type = pci_pcie_type(pdev); + + if (pdev->bus != ctx->bus) + return 0; + if (!pci_is_pcie(pdev)) + return 0; + if (type != ctx->type) + return 0; + + ctx->count++; + return 0; +} + +int cxl_port_get_possible_dports(struct cxl_port *port) +{ + struct pci_bus *bus = cxl_port_to_pci_bus(port); + struct cxl_walk_context ctx; + int type; + + if (!bus) { + dev_err(&port->dev, "No PCI bus found for port %s\n", + dev_name(&port->dev)); + return -ENXIO; + } + + if (pci_is_root_bus(bus)) + type = PCI_EXP_TYPE_ROOT_PORT; + else + type = PCI_EXP_TYPE_DOWNSTREAM; + + ctx = (struct cxl_walk_context) { + .bus = bus, + .type = type, + }; + pci_walk_bus(bus, count_dports, &ctx); + + return ctx.count; +} diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 4b858f3d44c6..672f43b7a87f 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -810,12 +810,9 @@ struct cxl_endpoint_dvsec_info { struct range dvsec_range[2]; }; -struct cxl_hdm; -struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, - struct cxl_endpoint_dvsec_info *info); -int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, - struct cxl_endpoint_dvsec_info *info); -int devm_cxl_add_passthrough_decoder(struct cxl_port *port); +int devm_cxl_switch_port_decoders_setup(struct cxl_port *port); +int devm_cxl_endpoint_decoders_setup(struct cxl_port *port); + struct cxl_dev_state; int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds, struct cxl_endpoint_dvsec_info *info); diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h index 54e219b0049e..7ae621e618e7 100644 --- a/drivers/cxl/cxlpci.h +++ b/drivers/cxl/cxlpci.h @@ -129,8 +129,6 @@ static inline bool cxl_pci_flit_256(struct pci_dev *pdev) int devm_cxl_port_enumerate_dports(struct cxl_port *port); struct cxl_dev_state; -int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, - struct cxl_endpoint_dvsec_info *info); void read_cdat_data(struct cxl_port *port); void cxl_cor_error_detected(struct pci_dev *pdev); pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index cf32dc50b7a6..d8cae2b5bac6 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -59,7 +59,6 @@ static int discover_region(struct device *dev, void *unused) static int cxl_switch_port_probe(struct cxl_port *port) { - struct cxl_hdm *cxlhdm; int rc; /* Cache the data early to ensure is_visible() works */ @@ -71,43 +70,14 @@ static int cxl_switch_port_probe(struct cxl_port *port) cxl_switch_parse_cdat(port); - cxlhdm = devm_cxl_setup_hdm(port, NULL); - if (!IS_ERR(cxlhdm)) - return devm_cxl_enumerate_decoders(cxlhdm, NULL); - - if (PTR_ERR(cxlhdm) != -ENODEV) { - dev_err(&port->dev, "Failed to map HDM decoder capability\n"); - return PTR_ERR(cxlhdm); - } - - if (rc == 1) { - dev_dbg(&port->dev, "Fallback to passthrough decoder\n"); - return devm_cxl_add_passthrough_decoder(port); - } - - dev_err(&port->dev, "HDM decoder capability not found\n"); - return -ENXIO; + return devm_cxl_switch_port_decoders_setup(port); } static int cxl_endpoint_port_probe(struct cxl_port *port) { - struct cxl_endpoint_dvsec_info info = { .port = port }; struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev); - struct cxl_dev_state *cxlds = cxlmd->cxlds; - struct cxl_hdm *cxlhdm; int rc; - rc = cxl_dvsec_rr_decode(cxlds, &info); - if (rc < 0) - return rc; - - cxlhdm = devm_cxl_setup_hdm(port, &info); - if (IS_ERR(cxlhdm)) { - if (PTR_ERR(cxlhdm) == -ENODEV) - dev_err(&port->dev, "HDM decoder registers not found\n"); - return PTR_ERR(cxlhdm); - } - /* Cache the data early to ensure is_visible() works */ read_cdat_data(port); cxl_endpoint_parse_cdat(port); @@ -117,11 +87,7 @@ static int cxl_endpoint_port_probe(struct cxl_port *port) if (rc) return rc; - rc = cxl_hdm_decode_init(cxlds, cxlhdm, &info); - if (rc) - return rc; - - rc = devm_cxl_enumerate_decoders(cxlhdm, &info); + rc = devm_cxl_endpoint_decoders_setup(port); if (rc) return rc; diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild index d07f14cb7aa4..51b8ab289eae 100644 --- a/tools/testing/cxl/Kbuild +++ b/tools/testing/cxl/Kbuild @@ -5,16 +5,13 @@ ldflags-y += --wrap=acpi_evaluate_integer ldflags-y += --wrap=acpi_pci_find_root ldflags-y += --wrap=nvdimm_bus_register ldflags-y += --wrap=devm_cxl_port_enumerate_dports -ldflags-y += --wrap=devm_cxl_setup_hdm -ldflags-y += --wrap=devm_cxl_add_passthrough_decoder -ldflags-y += --wrap=devm_cxl_enumerate_decoders ldflags-y += --wrap=cxl_await_media_ready -ldflags-y += --wrap=cxl_hdm_decode_init -ldflags-y += --wrap=cxl_dvsec_rr_decode ldflags-y += --wrap=devm_cxl_add_rch_dport ldflags-y += --wrap=cxl_rcd_component_reg_phys ldflags-y += --wrap=cxl_endpoint_parse_cdat ldflags-y += --wrap=cxl_dport_init_ras_reporting +ldflags-y += --wrap=devm_cxl_switch_port_decoders_setup +ldflags-y += --wrap=devm_cxl_endpoint_decoders_setup DRIVERS := ../../../drivers CXL_SRC := $(DRIVERS)/cxl diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c index 8faf4143d04e..8b5c559a4a8c 100644 --- a/tools/testing/cxl/test/cxl.c +++ b/tools/testing/cxl/test/cxl.c @@ -643,13 +643,6 @@ static struct cxl_hdm *mock_cxl_setup_hdm(struct cxl_port *port, return cxlhdm; } -static int mock_cxl_add_passthrough_decoder(struct cxl_port *port) -{ - dev_err(&port->dev, "unexpected passthrough decoder for cxl_test\n"); - return -EOPNOTSUPP; -} - - struct target_map_ctx { u32 *target_map; int index; @@ -921,6 +914,36 @@ static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, return 0; } +static int __mock_cxl_decoders_setup(struct cxl_port *port) +{ + struct cxl_hdm *cxlhdm; + + cxlhdm = mock_cxl_setup_hdm(port, NULL); + if (IS_ERR(cxlhdm)) { + if (PTR_ERR(cxlhdm) != -ENODEV) + dev_err(&port->dev, "Failed to map HDM decoder capability\n"); + return PTR_ERR(cxlhdm); + } + + return mock_cxl_enumerate_decoders(cxlhdm, NULL); +} + +static int mock_cxl_switch_port_decoders_setup(struct cxl_port *port) +{ + if (is_cxl_root(port) || is_cxl_endpoint(port)) + return -EOPNOTSUPP; + + return __mock_cxl_decoders_setup(port); +} + +static int mock_cxl_endpoint_decoders_setup(struct cxl_port *port) +{ + if (!is_cxl_endpoint(port)) + return -EOPNOTSUPP; + + return __mock_cxl_decoders_setup(port); +} + static int mock_cxl_port_enumerate_dports(struct cxl_port *port) { struct platform_device **array; @@ -1035,10 +1058,9 @@ static struct cxl_mock_ops cxl_mock_ops = { .acpi_table_parse_cedt = mock_acpi_table_parse_cedt, .acpi_evaluate_integer = mock_acpi_evaluate_integer, .acpi_pci_find_root = mock_acpi_pci_find_root, + .devm_cxl_switch_port_decoders_setup = mock_cxl_switch_port_decoders_setup, + .devm_cxl_endpoint_decoders_setup = mock_cxl_endpoint_decoders_setup, .devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports, - .devm_cxl_setup_hdm = mock_cxl_setup_hdm, - .devm_cxl_add_passthrough_decoder = mock_cxl_add_passthrough_decoder, - .devm_cxl_enumerate_decoders = mock_cxl_enumerate_decoders, .cxl_endpoint_parse_cdat = mock_cxl_endpoint_parse_cdat, .list = LIST_HEAD_INIT(cxl_mock_ops.list), }; diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c index 1989ae020df3..f335889b7756 100644 --- a/tools/testing/cxl/test/mock.c +++ b/tools/testing/cxl/test/mock.c @@ -131,55 +131,35 @@ __wrap_nvdimm_bus_register(struct device *dev, } EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register); -struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port, - struct cxl_endpoint_dvsec_info *info) - -{ - int index; - struct cxl_hdm *cxlhdm; - struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); - - if (ops && ops->is_mock_port(port->uport_dev)) - cxlhdm = ops->devm_cxl_setup_hdm(port, info); - else - cxlhdm = devm_cxl_setup_hdm(port, info); - put_cxl_mock_ops(index); - - return cxlhdm; -} -EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_setup_hdm, "CXL"); - -int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port) +int __wrap_devm_cxl_switch_port_decoders_setup(struct cxl_port *port) { int rc, index; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); if (ops && ops->is_mock_port(port->uport_dev)) - rc = ops->devm_cxl_add_passthrough_decoder(port); + rc = ops->devm_cxl_switch_port_decoders_setup(port); else - rc = devm_cxl_add_passthrough_decoder(port); + rc = devm_cxl_switch_port_decoders_setup(port); put_cxl_mock_ops(index); return rc; } -EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_passthrough_decoder, "CXL"); +EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_switch_port_decoders_setup, "CXL"); -int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, - struct cxl_endpoint_dvsec_info *info) +int __wrap_devm_cxl_endpoint_decoders_setup(struct cxl_port *port) { int rc, index; - struct cxl_port *port = cxlhdm->port; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); if (ops && ops->is_mock_port(port->uport_dev)) - rc = ops->devm_cxl_enumerate_decoders(cxlhdm, info); + rc = ops->devm_cxl_endpoint_decoders_setup(port); else - rc = devm_cxl_enumerate_decoders(cxlhdm, info); + rc = devm_cxl_endpoint_decoders_setup(port); put_cxl_mock_ops(index); return rc; } -EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_enumerate_decoders, "CXL"); +EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_endpoint_decoders_setup, "CXL"); int __wrap_devm_cxl_port_enumerate_dports(struct cxl_port *port) { @@ -211,39 +191,6 @@ int __wrap_cxl_await_media_ready(struct cxl_dev_state *cxlds) } EXPORT_SYMBOL_NS_GPL(__wrap_cxl_await_media_ready, "CXL"); -int __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds, - struct cxl_hdm *cxlhdm, - struct cxl_endpoint_dvsec_info *info) -{ - int rc = 0, index; - struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); - - if (ops && ops->is_mock_dev(cxlds->dev)) - rc = 0; - else - rc = cxl_hdm_decode_init(cxlds, cxlhdm, info); - put_cxl_mock_ops(index); - - return rc; -} -EXPORT_SYMBOL_NS_GPL(__wrap_cxl_hdm_decode_init, "CXL"); - -int __wrap_cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds, - struct cxl_endpoint_dvsec_info *info) -{ - int rc = 0, index; - struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); - - if (ops && ops->is_mock_dev(cxlds->dev)) - rc = 0; - else - rc = cxl_dvsec_rr_decode(cxlds, info); - put_cxl_mock_ops(index); - - return rc; -} -EXPORT_SYMBOL_NS_GPL(__wrap_cxl_dvsec_rr_decode, "CXL"); - struct cxl_dport *__wrap_devm_cxl_add_rch_dport(struct cxl_port *port, struct device *dport_dev, int port_id, diff --git a/tools/testing/cxl/test/mock.h b/tools/testing/cxl/test/mock.h index d1b0271d2822..9d5ad3fd55ec 100644 --- a/tools/testing/cxl/test/mock.h +++ b/tools/testing/cxl/test/mock.h @@ -20,11 +20,8 @@ struct cxl_mock_ops { bool (*is_mock_port)(struct device *dev); bool (*is_mock_dev)(struct device *dev); int (*devm_cxl_port_enumerate_dports)(struct cxl_port *port); - struct cxl_hdm *(*devm_cxl_setup_hdm)( - struct cxl_port *port, struct cxl_endpoint_dvsec_info *info); - int (*devm_cxl_add_passthrough_decoder)(struct cxl_port *port); - int (*devm_cxl_enumerate_decoders)( - struct cxl_hdm *hdm, struct cxl_endpoint_dvsec_info *info); + int (*devm_cxl_switch_port_decoders_setup)(struct cxl_port *port); + int (*devm_cxl_endpoint_decoders_setup)(struct cxl_port *port); void (*cxl_endpoint_parse_cdat)(struct cxl_port *port); }; From 4f06d81e7c6a02f850bfe9812295b1e859ab2db0 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 11:09:24 -0700 Subject: [PATCH 1662/2711] cxl: Defer dport allocation for switch ports The current implementation enumerates the dports during the cxl_port driver probe. Without an endpoint connected, the dport may not be active during port probe. This scheme may prevent a valid hardware dport id to be retrieved and MMIO registers to be read when an endpoint is hot-plugged. Move the dport allocation and setup to behind memdev probe so the endpoint is guaranteed to be connected. In the original enumeration behavior, there are 3 phases (or 2 if no CXL switches) for port creation. cxl_acpi() creates a Root Port (RP) from the ACPI0017.N device. Through that it enumerates downstream ports composed of ACPI0016.N devices through add_host_bridge_dport(). Once done, it uses add_host_bridge_uport() to create the ports that enumerate the PCI RPs as the dports of these ports. Every time a port is created, the port driver is attached, cxl_switch_porbe_probe() is called and devm_cxl_port_enumerate_dports() is invoked to enumerate and probe the dports. The second phase is if there are any CXL switches. When the pci endpoint device driver (cxl_pci) calls probe, it will add a mem device and triggers the cxl_mem_probe(). cxl_mem_probe() calls devm_cxl_enumerate_ports() and attempts to discovery and create all the ports represent CXL switches. During this phase, a port is created per switch and the attached dports are also enumerated and probed. The last phase is creating endpoint port which happens for all endpoint devices. The new sequence is instead of creating all possible dports at initial port creation, defer port instantiation until a memdev beneath that dport arrives. Introduce devm_cxl_create_or_extend_port() to centralize the creation and extension of ports with new dports as memory devices arrive. As part of this rework, switch decoder target list is amended at runtime as dports show up. While the decoders are allocated during the port driver probe, The decoders must also be updated since previously they were setup when all the dports are setup. Now every time a dport is setup per endpoint, the switch target listing need to be updated with new dport. A guard(rwsem_write) is used to update decoder targets. This is similar to when decoder_populate_target() is called and the decoder programming must be protected. Also the port registers are probed the first time when the first dport shows up. This ensures that the CXL link is established when the port registers are probed. [dj] Use ERR_CAST() (Jonathan) Link: https://lore.kernel.org/linux-cxl/20250305100123.3077031-1-rrichter@amd.com/ Reviewed-by: Alison Schofield Reviewed-by: Jonathan Cameron Signed-off-by: Dave Jiang --- drivers/cxl/core/cdat.c | 2 +- drivers/cxl/core/core.h | 2 + drivers/cxl/core/hdm.c | 6 - drivers/cxl/core/pci.c | 46 ++++++++ drivers/cxl/core/port.c | 240 ++++++++++++++++++++++++++++++++-------- drivers/cxl/port.c | 11 +- 6 files changed, 247 insertions(+), 60 deletions(-) diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index c0af645425f4..b156b81a9b20 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -338,7 +338,7 @@ static int match_cxlrd_hb(struct device *dev, void *data) guard(rwsem_read)(&cxl_rwsem.region); for (int i = 0; i < cxlsd->nr_targets; i++) { - if (host_bridge == cxlsd->target[i]->dport_dev) + if (cxlsd->target[i] && host_bridge == cxlsd->target[i]->dport_dev) return 1; } diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index b07490aa93c7..e18425f119bd 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -146,6 +146,8 @@ int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port, int cxl_ras_init(void); void cxl_ras_exit(void); int cxl_gpf_port_setup(struct cxl_dport *dport); +struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, + struct device *dport_dev); struct cxl_hdm; int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 78bfe4f55b96..72594f84d2a1 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -52,8 +52,6 @@ static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld) static int devm_cxl_add_passthrough_decoder(struct cxl_port *port) { struct cxl_switch_decoder *cxlsd; - struct cxl_dport *dport = NULL; - unsigned long index; struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); /* @@ -69,10 +67,6 @@ static int devm_cxl_add_passthrough_decoder(struct cxl_port *port) device_lock_assert(&port->dev); - xa_for_each(&port->dports, index, dport) - break; - cxlsd->cxld.target_map[0] = dport->port_id; - return add_hdm_decoder(port, &cxlsd->cxld); } diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index fa02366d35f2..9ec288ed39ae 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -24,6 +24,52 @@ static unsigned short media_ready_timeout = 60; module_param(media_ready_timeout, ushort, 0644); MODULE_PARM_DESC(media_ready_timeout, "seconds to wait for media ready"); +static int pci_get_port_num(struct pci_dev *pdev) +{ + u32 lnkcap; + int type; + + type = pci_pcie_type(pdev); + if (type != PCI_EXP_TYPE_DOWNSTREAM && type != PCI_EXP_TYPE_ROOT_PORT) + return -EINVAL; + + if (pci_read_config_dword(pdev, pci_pcie_cap(pdev) + PCI_EXP_LNKCAP, + &lnkcap)) + return -ENXIO; + + return FIELD_GET(PCI_EXP_LNKCAP_PN, lnkcap); +} + +/** + * devm_cxl_add_dport_by_dev - allocate a dport by the dport device + * @port: cxl_port that hosts the dport + * @dport_dev: 'struct device' of the dport + * + * Returns the allocated dport on success or ERR_PTR() of -errno on error + */ +struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, + struct device *dport_dev) +{ + struct cxl_register_map map; + struct pci_dev *pdev; + int port_num, rc; + + if (!dev_is_pci(dport_dev)) + return ERR_PTR(-EINVAL); + + pdev = to_pci_dev(dport_dev); + port_num = pci_get_port_num(pdev); + if (port_num < 0) + return ERR_PTR(port_num); + + rc = cxl_find_regblock(pdev, CXL_REGLOC_RBI_COMPONENT, &map); + if (rc) + return ERR_PTR(rc); + + device_lock_assert(&port->dev); + return devm_cxl_add_dport(port, dport_dev, port_num, map.resource); +} + struct cxl_walk_context { struct pci_bus *bus; struct cxl_port *port; diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 7344048f678e..bcdb6fdaa18c 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1357,21 +1357,6 @@ static struct cxl_port *find_cxl_port(struct device *dport_dev, return port; } -static struct cxl_port *find_cxl_port_at(struct cxl_port *parent_port, - struct device *dport_dev, - struct cxl_dport **dport) -{ - struct cxl_find_port_ctx ctx = { - .dport_dev = dport_dev, - .parent_port = parent_port, - .dport = dport, - }; - struct cxl_port *port; - - port = __find_cxl_port(&ctx); - return port; -} - /* * All users of grandparent() are using it to walk PCIe-like switch port * hierarchy. A PCIe switch is comprised of a bridge device representing the @@ -1547,13 +1532,154 @@ static resource_size_t find_component_registers(struct device *dev) return map.resource; } +static int match_port_by_uport(struct device *dev, const void *data) +{ + const struct device *uport_dev = data; + struct cxl_port *port; + + if (!is_cxl_port(dev)) + return 0; + + port = to_cxl_port(dev); + return uport_dev == port->uport_dev; +} + +/* + * Function takes a device reference on the port device. Caller should do a + * put_device() when done. + */ +static struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev) +{ + struct device *dev; + + dev = bus_find_device(&cxl_bus_type, NULL, uport_dev, match_port_by_uport); + if (dev) + return to_cxl_port(dev); + return NULL; +} + +static int update_decoder_targets(struct device *dev, void *data) +{ + struct cxl_dport *dport = data; + struct cxl_switch_decoder *cxlsd; + struct cxl_decoder *cxld; + int i; + + if (!is_switch_decoder(dev)) + return 0; + + cxlsd = to_cxl_switch_decoder(dev); + cxld = &cxlsd->cxld; + guard(rwsem_write)(&cxl_rwsem.region); + + for (i = 0; i < cxld->interleave_ways; i++) { + if (cxld->target_map[i] == dport->port_id) { + cxlsd->target[i] = dport; + dev_dbg(dev, "dport%d found in target list, index %d\n", + dport->port_id, i); + return 1; + } + } + + return 0; +} + +DEFINE_FREE(del_cxl_dport, struct cxl_dport *, if (!IS_ERR_OR_NULL(_T)) del_dport(_T)) +static struct cxl_dport *cxl_port_add_dport(struct cxl_port *port, + struct device *dport_dev) +{ + struct cxl_dport *dport; + int rc; + + device_lock_assert(&port->dev); + if (!port->dev.driver) + return ERR_PTR(-ENXIO); + + dport = cxl_find_dport_by_dev(port, dport_dev); + if (dport) { + dev_dbg(&port->dev, "dport%d:%s already exists\n", + dport->port_id, dev_name(dport_dev)); + return ERR_PTR(-EBUSY); + } + + struct cxl_dport *new_dport __free(del_cxl_dport) = + devm_cxl_add_dport_by_dev(port, dport_dev); + if (IS_ERR(new_dport)) + return new_dport; + + cxl_switch_parse_cdat(port); + + if (ida_is_empty(&port->decoder_ida)) { + rc = devm_cxl_switch_port_decoders_setup(port); + if (rc) + return ERR_PTR(rc); + dev_dbg(&port->dev, "first dport%d:%s added with decoders\n", + new_dport->port_id, dev_name(dport_dev)); + return no_free_ptr(new_dport); + } + + /* New dport added, update the decoder targets */ + device_for_each_child(&port->dev, new_dport, update_decoder_targets); + + dev_dbg(&port->dev, "dport%d:%s added\n", new_dport->port_id, + dev_name(dport_dev)); + + return no_free_ptr(new_dport); +} + +static struct cxl_dport *devm_cxl_create_port(struct device *ep_dev, + struct cxl_port *parent_port, + struct cxl_dport *parent_dport, + struct device *uport_dev, + struct device *dport_dev) +{ + resource_size_t component_reg_phys; + + device_lock_assert(&parent_port->dev); + if (!parent_port->dev.driver) { + dev_warn(ep_dev, + "port %s:%s:%s disabled, failed to enumerate CXL.mem\n", + dev_name(&parent_port->dev), dev_name(uport_dev), + dev_name(dport_dev)); + } + + struct cxl_port *port __free(put_cxl_port) = + find_cxl_port_by_uport(uport_dev); + if (!port) { + component_reg_phys = find_component_registers(uport_dev); + port = devm_cxl_add_port(&parent_port->dev, uport_dev, + component_reg_phys, parent_dport); + if (IS_ERR(port)) + return ERR_CAST(port); + + /* + * retry to make sure a port is found. a port device + * reference is taken. + */ + port = find_cxl_port_by_uport(uport_dev); + if (!port) + return ERR_PTR(-ENODEV); + + dev_dbg(ep_dev, "created port %s:%s\n", + dev_name(&port->dev), dev_name(port->uport_dev)); + } else { + /* + * Port was created before right before this function is + * called. Signal the caller to deal with it. + */ + return ERR_PTR(-EAGAIN); + } + + guard(device)(&port->dev); + return cxl_port_add_dport(port, dport_dev); +} + static int add_port_attach_ep(struct cxl_memdev *cxlmd, struct device *uport_dev, struct device *dport_dev) { struct device *dparent = grandparent(dport_dev); struct cxl_dport *dport, *parent_dport; - resource_size_t component_reg_phys; int rc; if (is_cxl_host_bridge(dparent)) { @@ -1568,42 +1694,31 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd, } struct cxl_port *parent_port __free(put_cxl_port) = - find_cxl_port(dparent, &parent_dport); + find_cxl_port_by_uport(dparent->parent); if (!parent_port) { /* iterate to create this parent_port */ return -EAGAIN; } - /* - * Definition with __free() here to keep the sequence of - * dereferencing the device of the port before the parent_port releasing. - */ - struct cxl_port *port __free(put_cxl_port) = NULL; scoped_guard(device, &parent_port->dev) { - if (!parent_port->dev.driver) { - dev_warn(&cxlmd->dev, - "port %s:%s disabled, failed to enumerate CXL.mem\n", - dev_name(&parent_port->dev), dev_name(uport_dev)); - return -ENXIO; + parent_dport = cxl_find_dport_by_dev(parent_port, dparent); + if (!parent_dport) { + parent_dport = cxl_port_add_dport(parent_port, dparent); + if (IS_ERR(parent_dport)) + return PTR_ERR(parent_dport); } - port = find_cxl_port_at(parent_port, dport_dev, &dport); - if (!port) { - component_reg_phys = find_component_registers(uport_dev); - port = devm_cxl_add_port(&parent_port->dev, uport_dev, - component_reg_phys, parent_dport); - if (IS_ERR(port)) - return PTR_ERR(port); - - /* retry find to pick up the new dport information */ - port = find_cxl_port_at(parent_port, dport_dev, &dport); - if (!port) - return -ENXIO; + dport = devm_cxl_create_port(&cxlmd->dev, parent_port, + parent_dport, uport_dev, + dport_dev); + if (IS_ERR(dport)) { + /* Port already exists, restart iteration */ + if (PTR_ERR(dport) == -EAGAIN) + return 0; + return PTR_ERR(dport); } } - dev_dbg(&cxlmd->dev, "add to new port %s:%s\n", - dev_name(&port->dev), dev_name(port->uport_dev)); rc = cxl_add_ep(dport, &cxlmd->dev); if (rc == -EBUSY) { /* @@ -1616,6 +1731,25 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd, return rc; } +static struct cxl_dport *find_or_add_dport(struct cxl_port *port, + struct device *dport_dev) +{ + struct cxl_dport *dport; + + device_lock_assert(&port->dev); + dport = cxl_find_dport_by_dev(port, dport_dev); + if (!dport) { + dport = cxl_port_add_dport(port, dport_dev); + if (IS_ERR(dport)) + return dport; + + /* New dport added, restart iteration */ + return ERR_PTR(-EAGAIN); + } + + return dport; +} + int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd) { struct device *dev = &cxlmd->dev; @@ -1658,12 +1792,26 @@ retry: dev_name(iter), dev_name(dport_dev), dev_name(uport_dev)); struct cxl_port *port __free(put_cxl_port) = - find_cxl_port(dport_dev, &dport); + find_cxl_port_by_uport(uport_dev); if (port) { dev_dbg(&cxlmd->dev, "found already registered port %s:%s\n", dev_name(&port->dev), dev_name(port->uport_dev)); + + /* + * RP port enumerated by cxl_acpi without dport will + * have the dport added here. + */ + scoped_guard(device, &port->dev) { + dport = find_or_add_dport(port, dport_dev); + if (IS_ERR(dport)) { + if (PTR_ERR(dport) == -EAGAIN) + goto retry; + return PTR_ERR(dport); + } + } + rc = cxl_add_ep(dport, &cxlmd->dev); /* @@ -1723,14 +1871,16 @@ static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd, device_lock_assert(&port->dev); if (xa_empty(&port->dports)) - return -EINVAL; + return 0; guard(rwsem_write)(&cxl_rwsem.region); for (i = 0; i < cxlsd->cxld.interleave_ways; i++) { struct cxl_dport *dport = find_dport(port, cxld->target_map[i]); - if (!dport) - return -ENXIO; + if (!dport) { + /* dport may be activated later */ + continue; + } cxlsd->target[i] = dport; } diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index d8cae2b5bac6..51c8f2f84717 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -59,18 +59,13 @@ static int discover_region(struct device *dev, void *unused) static int cxl_switch_port_probe(struct cxl_port *port) { - int rc; + /* Reset nr_dports for rebind of driver */ + port->nr_dports = 0; /* Cache the data early to ensure is_visible() works */ read_cdat_data(port); - rc = devm_cxl_port_enumerate_dports(port); - if (rc < 0) - return rc; - - cxl_switch_parse_cdat(port); - - return devm_cxl_switch_port_decoders_setup(port); + return 0; } static int cxl_endpoint_port_probe(struct cxl_port *port) From d96eb90d9ca6e4652c8a23d48c94364aa061fdc4 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 11:09:25 -0700 Subject: [PATCH 1663/2711] cxl/test: Add mock version of devm_cxl_add_dport_by_dev() devm_cxl_add_dport_by_dev() outside of cxl_test is done through PCI hierarchy. However with cxl_test, it needs to be done through the platform device hierarchy. Add the mock function for devm_cxl_add_dport_by_dev(). When cxl_core calls a cxl_core exported function and that function is mocked by cxl_test, the call chain causes a circular dependency issue. Dan provided a workaround to avoid this issue. Apply the method to changes from the late dport allocation changes in order to enable cxl-test. In cxl_core they are defined with "__" added in front of the function. A macro is used to define the original function names for when non-test version of the kernel is built. A bit of macros and typedefs are used to allow mocking of those functions in cxl_test. Co-developed-by: Dan Williams Signed-off-by: Dan Williams Reviewed-by: Jonathan Cameron Reviewed-by: Li Ming Tested-by: Alison Schofield Tested-by: Robert Richter Signed-off-by: Dave Jiang --- drivers/cxl/core/core.h | 2 -- drivers/cxl/core/pci.c | 7 ++-- drivers/cxl/cxl.h | 20 +++++++++++ tools/testing/cxl/Kbuild | 1 + tools/testing/cxl/cxl_core_exports.c | 12 +++++++ tools/testing/cxl/exports.h | 10 ++++++ tools/testing/cxl/test/cxl.c | 53 ++++++++++++++++++++++++++-- tools/testing/cxl/test/mock.c | 23 ++++++++++++ tools/testing/cxl/test/mock.h | 2 ++ 9 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 tools/testing/cxl/exports.h diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index e18425f119bd..b07490aa93c7 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -146,8 +146,6 @@ int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port, int cxl_ras_init(void); void cxl_ras_exit(void); int cxl_gpf_port_setup(struct cxl_dport *dport); -struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, - struct device *dport_dev); struct cxl_hdm; int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 9ec288ed39ae..18825e1505d6 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -41,14 +41,14 @@ static int pci_get_port_num(struct pci_dev *pdev) } /** - * devm_cxl_add_dport_by_dev - allocate a dport by the dport device + * __devm_cxl_add_dport_by_dev - allocate a dport by dport device * @port: cxl_port that hosts the dport * @dport_dev: 'struct device' of the dport * * Returns the allocated dport on success or ERR_PTR() of -errno on error */ -struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, - struct device *dport_dev) +struct cxl_dport *__devm_cxl_add_dport_by_dev(struct cxl_port *port, + struct device *dport_dev) { struct cxl_register_map map; struct pci_dev *pdev; @@ -69,6 +69,7 @@ struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, device_lock_assert(&port->dev); return devm_cxl_add_dport(port, dport_dev, port_num, map.resource); } +EXPORT_SYMBOL_NS_GPL(__devm_cxl_add_dport_by_dev, "CXL"); struct cxl_walk_context { struct pci_bus *bus; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 672f43b7a87f..99d358455032 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -906,6 +906,10 @@ void cxl_coordinates_combine(struct access_coordinate *out, struct access_coordinate *c2); bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port); +struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, + struct device *dport_dev); +struct cxl_dport *__devm_cxl_add_dport_by_dev(struct cxl_port *port, + struct device *dport_dev); /* * Unit test builds overrides this to __weak, find the 'strong' version @@ -916,4 +920,20 @@ bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port); #endif u16 cxl_gpf_get_dvsec(struct device *dev); + +/* + * Declaration for functions that are mocked by cxl_test that are called by + * cxl_core. The respective functions are defined as __foo() and called by + * cxl_core as foo(). The macros below ensures that those functions would + * exist as foo(). See tools/testing/cxl/cxl_core_exports.c and + * tools/testing/cxl/exports.h for setting up the mock functions. The dance + * is done to avoid a circular dependency where cxl_core calls a function that + * ends up being a mock function and goes to * cxl_test where it calls a + * cxl_core function. + */ +#ifndef CXL_TEST_ENABLE +#define DECLARE_TESTABLE(x) __##x +#define devm_cxl_add_dport_by_dev DECLARE_TESTABLE(devm_cxl_add_dport_by_dev) +#endif + #endif /* __CXL_H__ */ diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild index 51b8ab289eae..81e3795673c5 100644 --- a/tools/testing/cxl/Kbuild +++ b/tools/testing/cxl/Kbuild @@ -18,6 +18,7 @@ CXL_SRC := $(DRIVERS)/cxl CXL_CORE_SRC := $(DRIVERS)/cxl/core ccflags-y := -I$(srctree)/drivers/cxl/ ccflags-y += -D__mock=__weak +ccflags-y += -DCXL_TEST_ENABLE=1 ccflags-y += -DTRACE_INCLUDE_PATH=$(CXL_CORE_SRC) -I$(srctree)/drivers/cxl/core/ obj-m += cxl_acpi.o diff --git a/tools/testing/cxl/cxl_core_exports.c b/tools/testing/cxl/cxl_core_exports.c index f088792a8925..0d18abc1f5a3 100644 --- a/tools/testing/cxl/cxl_core_exports.c +++ b/tools/testing/cxl/cxl_core_exports.c @@ -2,6 +2,18 @@ /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ #include "cxl.h" +#include "exports.h" /* Exporting of cxl_core symbols that are only used by cxl_test */ EXPORT_SYMBOL_NS_GPL(cxl_num_decoders_committed, "CXL"); + +cxl_add_dport_by_dev_fn _devm_cxl_add_dport_by_dev = + __devm_cxl_add_dport_by_dev; +EXPORT_SYMBOL_NS_GPL(_devm_cxl_add_dport_by_dev, "CXL"); + +struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, + struct device *dport_dev) +{ + return _devm_cxl_add_dport_by_dev(port, dport_dev); +} +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport_by_dev, "CXL"); diff --git a/tools/testing/cxl/exports.h b/tools/testing/cxl/exports.h new file mode 100644 index 000000000000..9261ce6f1197 --- /dev/null +++ b/tools/testing/cxl/exports.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2025 Intel Corporation */ +#ifndef __MOCK_CXL_EXPORTS_H_ +#define __MOCK_CXL_EXPORTS_H_ + +typedef struct cxl_dport *(*cxl_add_dport_by_dev_fn)(struct cxl_port *port, + struct device *dport_dev); +extern cxl_add_dport_by_dev_fn _devm_cxl_add_dport_by_dev; + +#endif diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c index 8b5c559a4a8c..e3b4dc265a3b 100644 --- a/tools/testing/cxl/test/cxl.c +++ b/tools/testing/cxl/test/cxl.c @@ -944,10 +944,12 @@ static int mock_cxl_endpoint_decoders_setup(struct cxl_port *port) return __mock_cxl_decoders_setup(port); } -static int mock_cxl_port_enumerate_dports(struct cxl_port *port) +static int get_port_array(struct cxl_port *port, + struct platform_device ***port_array, + int *port_array_size) { struct platform_device **array; - int i, array_size; + int array_size; if (port->depth == 1) { if (is_multi_bridge(port->uport_dev)) { @@ -981,6 +983,22 @@ static int mock_cxl_port_enumerate_dports(struct cxl_port *port) return -ENXIO; } + *port_array = array; + *port_array_size = array_size; + + return 0; +} + +static int mock_cxl_port_enumerate_dports(struct cxl_port *port) +{ + struct platform_device **array; + int i, array_size; + int rc; + + rc = get_port_array(port, &array, &array_size); + if (rc) + return rc; + for (i = 0; i < array_size; i++) { struct platform_device *pdev = array[i]; struct cxl_dport *dport; @@ -1002,6 +1020,36 @@ static int mock_cxl_port_enumerate_dports(struct cxl_port *port) return 0; } +static struct cxl_dport *mock_cxl_add_dport_by_dev(struct cxl_port *port, + struct device *dport_dev) +{ + struct platform_device **array; + int rc, i, array_size; + + rc = get_port_array(port, &array, &array_size); + if (rc) + return ERR_PTR(rc); + + for (i = 0; i < array_size; i++) { + struct platform_device *pdev = array[i]; + + if (pdev->dev.parent != port->uport_dev) { + dev_dbg(&port->dev, "%s: mismatch parent %s\n", + dev_name(port->uport_dev), + dev_name(pdev->dev.parent)); + continue; + } + + if (&pdev->dev != dport_dev) + continue; + + return devm_cxl_add_dport(port, &pdev->dev, pdev->id, + CXL_RESOURCE_NONE); + } + + return ERR_PTR(-ENODEV); +} + /* * Faking the cxl_dpa_perf for the memdev when appropriate. */ @@ -1062,6 +1110,7 @@ static struct cxl_mock_ops cxl_mock_ops = { .devm_cxl_endpoint_decoders_setup = mock_cxl_endpoint_decoders_setup, .devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports, .cxl_endpoint_parse_cdat = mock_cxl_endpoint_parse_cdat, + .devm_cxl_add_dport_by_dev = mock_cxl_add_dport_by_dev, .list = LIST_HEAD_INIT(cxl_mock_ops.list), }; diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c index f335889b7756..e98101f083cd 100644 --- a/tools/testing/cxl/test/mock.c +++ b/tools/testing/cxl/test/mock.c @@ -10,12 +10,18 @@ #include #include #include "mock.h" +#include "../exports.h" static LIST_HEAD(mock); +static struct cxl_dport * +redirect_devm_cxl_add_dport_by_dev(struct cxl_port *port, + struct device *dport_dev); + void register_cxl_mock_ops(struct cxl_mock_ops *ops) { list_add_rcu(&ops->list, &mock); + _devm_cxl_add_dport_by_dev = redirect_devm_cxl_add_dport_by_dev; } EXPORT_SYMBOL_GPL(register_cxl_mock_ops); @@ -23,6 +29,7 @@ DEFINE_STATIC_SRCU(cxl_mock_srcu); void unregister_cxl_mock_ops(struct cxl_mock_ops *ops) { + _devm_cxl_add_dport_by_dev = __devm_cxl_add_dport_by_dev; list_del_rcu(&ops->list); synchronize_srcu(&cxl_mock_srcu); } @@ -258,6 +265,22 @@ void __wrap_cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device } EXPORT_SYMBOL_NS_GPL(__wrap_cxl_dport_init_ras_reporting, "CXL"); +struct cxl_dport *redirect_devm_cxl_add_dport_by_dev(struct cxl_port *port, + struct device *dport_dev) +{ + int index; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + struct cxl_dport *dport; + + if (ops && ops->is_mock_port(port->uport_dev)) + dport = ops->devm_cxl_add_dport_by_dev(port, dport_dev); + else + dport = __devm_cxl_add_dport_by_dev(port, dport_dev); + put_cxl_mock_ops(index); + + return dport; +} + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("cxl_test: emulation module"); MODULE_IMPORT_NS("ACPI"); diff --git a/tools/testing/cxl/test/mock.h b/tools/testing/cxl/test/mock.h index 9d5ad3fd55ec..4ed932e76aae 100644 --- a/tools/testing/cxl/test/mock.h +++ b/tools/testing/cxl/test/mock.h @@ -23,6 +23,8 @@ struct cxl_mock_ops { int (*devm_cxl_switch_port_decoders_setup)(struct cxl_port *port); int (*devm_cxl_endpoint_decoders_setup)(struct cxl_port *port); void (*cxl_endpoint_parse_cdat)(struct cxl_port *port); + struct cxl_dport *(*devm_cxl_add_dport_by_dev)(struct cxl_port *port, + struct device *dport_dev); }; void register_cxl_mock_ops(struct cxl_mock_ops *ops); From 644685abc16b58b3afcc2feb0ac14e86476ca2ed Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 11:09:26 -0700 Subject: [PATCH 1664/2711] cxl/test: Adjust the mock version of devm_cxl_switch_port_decoders_setup() With devm_cxl_switch_port_decoders_setup() being called within cxl_core instead of by the port driver probe, adjustments are needed to deal with circular symbol dependency when this function is being mock'd. Add the appropriate changes to get around the circular dependency. Reviewed-by: Alison Schofield Reviewed-by: Jonathan Cameron Signed-off-by: Dave Jiang --- drivers/cxl/core/hdm.c | 6 +++--- drivers/cxl/cxl.h | 2 ++ tools/testing/cxl/Kbuild | 1 - tools/testing/cxl/cxl_core_exports.c | 10 ++++++++++ tools/testing/cxl/exports.h | 3 +++ tools/testing/cxl/test/mock.c | 10 +++++++--- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 72594f84d2a1..5fa7635c9b75 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -1216,12 +1216,12 @@ static int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, } /** - * devm_cxl_switch_port_decoders_setup - allocate and setup switch decoders + * __devm_cxl_switch_port_decoders_setup - allocate and setup switch decoders * @port: CXL port context * * Return 0 or -errno on error */ -int devm_cxl_switch_port_decoders_setup(struct cxl_port *port) +int __devm_cxl_switch_port_decoders_setup(struct cxl_port *port) { struct cxl_hdm *cxlhdm; @@ -1245,7 +1245,7 @@ int devm_cxl_switch_port_decoders_setup(struct cxl_port *port) dev_err(&port->dev, "HDM decoder capability not found\n"); return -ENXIO; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_switch_port_decoders_setup, "CXL"); +EXPORT_SYMBOL_NS_GPL(__devm_cxl_switch_port_decoders_setup, "CXL"); /** * devm_cxl_endpoint_decoders_setup - allocate and setup endpoint decoders diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 99d358455032..c995ae334b1b 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -811,6 +811,7 @@ struct cxl_endpoint_dvsec_info { }; int devm_cxl_switch_port_decoders_setup(struct cxl_port *port); +int __devm_cxl_switch_port_decoders_setup(struct cxl_port *port); int devm_cxl_endpoint_decoders_setup(struct cxl_port *port); struct cxl_dev_state; @@ -934,6 +935,7 @@ u16 cxl_gpf_get_dvsec(struct device *dev); #ifndef CXL_TEST_ENABLE #define DECLARE_TESTABLE(x) __##x #define devm_cxl_add_dport_by_dev DECLARE_TESTABLE(devm_cxl_add_dport_by_dev) +#define devm_cxl_switch_port_decoders_setup DECLARE_TESTABLE(devm_cxl_switch_port_decoders_setup) #endif #endif /* __CXL_H__ */ diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild index 81e3795673c5..0d5ce4b74b9f 100644 --- a/tools/testing/cxl/Kbuild +++ b/tools/testing/cxl/Kbuild @@ -10,7 +10,6 @@ ldflags-y += --wrap=devm_cxl_add_rch_dport ldflags-y += --wrap=cxl_rcd_component_reg_phys ldflags-y += --wrap=cxl_endpoint_parse_cdat ldflags-y += --wrap=cxl_dport_init_ras_reporting -ldflags-y += --wrap=devm_cxl_switch_port_decoders_setup ldflags-y += --wrap=devm_cxl_endpoint_decoders_setup DRIVERS := ../../../drivers diff --git a/tools/testing/cxl/cxl_core_exports.c b/tools/testing/cxl/cxl_core_exports.c index 0d18abc1f5a3..6754de35598d 100644 --- a/tools/testing/cxl/cxl_core_exports.c +++ b/tools/testing/cxl/cxl_core_exports.c @@ -17,3 +17,13 @@ struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, return _devm_cxl_add_dport_by_dev(port, dport_dev); } EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport_by_dev, "CXL"); + +cxl_switch_decoders_setup_fn _devm_cxl_switch_port_decoders_setup = + __devm_cxl_switch_port_decoders_setup; +EXPORT_SYMBOL_NS_GPL(_devm_cxl_switch_port_decoders_setup, "CXL"); + +int devm_cxl_switch_port_decoders_setup(struct cxl_port *port) +{ + return _devm_cxl_switch_port_decoders_setup(port); +} +EXPORT_SYMBOL_NS_GPL(devm_cxl_switch_port_decoders_setup, "CXL"); diff --git a/tools/testing/cxl/exports.h b/tools/testing/cxl/exports.h index 9261ce6f1197..7ebee7c0bd67 100644 --- a/tools/testing/cxl/exports.h +++ b/tools/testing/cxl/exports.h @@ -7,4 +7,7 @@ typedef struct cxl_dport *(*cxl_add_dport_by_dev_fn)(struct cxl_port *port, struct device *dport_dev); extern cxl_add_dport_by_dev_fn _devm_cxl_add_dport_by_dev; +typedef int(*cxl_switch_decoders_setup_fn)(struct cxl_port *port); +extern cxl_switch_decoders_setup_fn _devm_cxl_switch_port_decoders_setup; + #endif diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c index e98101f083cd..995269a75cbd 100644 --- a/tools/testing/cxl/test/mock.c +++ b/tools/testing/cxl/test/mock.c @@ -17,11 +17,14 @@ static LIST_HEAD(mock); static struct cxl_dport * redirect_devm_cxl_add_dport_by_dev(struct cxl_port *port, struct device *dport_dev); +static int redirect_devm_cxl_switch_port_decoders_setup(struct cxl_port *port); void register_cxl_mock_ops(struct cxl_mock_ops *ops) { list_add_rcu(&ops->list, &mock); _devm_cxl_add_dport_by_dev = redirect_devm_cxl_add_dport_by_dev; + _devm_cxl_switch_port_decoders_setup = + redirect_devm_cxl_switch_port_decoders_setup; } EXPORT_SYMBOL_GPL(register_cxl_mock_ops); @@ -29,6 +32,8 @@ DEFINE_STATIC_SRCU(cxl_mock_srcu); void unregister_cxl_mock_ops(struct cxl_mock_ops *ops) { + _devm_cxl_switch_port_decoders_setup = + __devm_cxl_switch_port_decoders_setup; _devm_cxl_add_dport_by_dev = __devm_cxl_add_dport_by_dev; list_del_rcu(&ops->list); synchronize_srcu(&cxl_mock_srcu); @@ -138,7 +143,7 @@ __wrap_nvdimm_bus_register(struct device *dev, } EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register); -int __wrap_devm_cxl_switch_port_decoders_setup(struct cxl_port *port) +int redirect_devm_cxl_switch_port_decoders_setup(struct cxl_port *port) { int rc, index; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); @@ -146,12 +151,11 @@ int __wrap_devm_cxl_switch_port_decoders_setup(struct cxl_port *port) if (ops && ops->is_mock_port(port->uport_dev)) rc = ops->devm_cxl_switch_port_decoders_setup(port); else - rc = devm_cxl_switch_port_decoders_setup(port); + rc = __devm_cxl_switch_port_decoders_setup(port); put_cxl_mock_ops(index); return rc; } -EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_switch_port_decoders_setup, "CXL"); int __wrap_devm_cxl_endpoint_decoders_setup(struct cxl_port *port) { From 87439b598ad962ffc5744e2e0a8b461e78d8d32f Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 11:09:27 -0700 Subject: [PATCH 1665/2711] cxl/test: Setup target_map for cxl_test decoder initialization cxl_test uses mock functions for decoder enumaration. Add initialization of the cxld->target_map[] for cxl_test based decoders in the mock functions. Reviewed-by: Jonathan Cameron Tested-by: Robert Richter Reviewed-by: Alison Schofield Signed-off-by: Dave Jiang --- tools/testing/cxl/test/cxl.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c index e3b4dc265a3b..5d0040b7d7db 100644 --- a/tools/testing/cxl/test/cxl.c +++ b/tools/testing/cxl/test/cxl.c @@ -811,15 +811,21 @@ static void mock_init_hdm_decoder(struct cxl_decoder *cxld) */ if (WARN_ON(!dev)) continue; + cxlsd = to_cxl_switch_decoder(dev); if (i == 0) { /* put cxl_mem.4 second in the decode order */ - if (pdev->id == 4) + if (pdev->id == 4) { cxlsd->target[1] = dport; - else + cxld->target_map[1] = dport->port_id; + } else { cxlsd->target[0] = dport; - } else + cxld->target_map[0] = dport->port_id; + } + } else { cxlsd->target[0] = dport; + cxld->target_map[0] = dport->port_id; + } cxld = &cxlsd->cxld; cxld->target_type = CXL_DECODER_HOSTONLYMEM; cxld->flags = CXL_DECODER_F_ENABLE; From d64035a5a37741b25712fb9c2f6aca535c2967ea Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Aug 2025 11:09:28 -0700 Subject: [PATCH 1666/2711] cxl: Change sslbis handler to only handle single dport While cxl_switch_parse_cdat() is harmless to be run multiple times, it is not efficient in the current scheme where one dport is being updated at a time by the memdev probe path. Change the input parameter to the specific dport being updated to pick up the SSLBIS information for just that dport. Reviewed-by: Gregory Price Reviewed-by: Jonathan Cameron Reviewed-by: Li Ming Reviewed-by: Alison Schofield Reviewed-by: Dan Williams Tested-by: Robert Richter Signed-off-by: Dave Jiang --- drivers/cxl/core/cdat.c | 23 ++++++++++------------- drivers/cxl/core/port.c | 2 +- drivers/cxl/cxl.h | 2 +- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index b156b81a9b20..84c50e7e8d0a 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -440,8 +440,8 @@ static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, } *tbl = (struct acpi_cdat_sslbis_table *)header; int size = sizeof(header->cdat) + sizeof(tbl->sslbis_header); struct acpi_cdat_sslbis *sslbis; - struct cxl_port *port = arg; - struct device *dev = &port->dev; + struct cxl_dport *dport = arg; + struct device *dev = &dport->port->dev; int remain, entries, i; u16 len; @@ -467,8 +467,6 @@ static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, u16 y = le16_to_cpu((__force __le16)tbl->entries[i].porty_id); __le64 le_base; __le16 le_val; - struct cxl_dport *dport; - unsigned long index; u16 dsp_id; u64 val; @@ -499,28 +497,27 @@ static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, val = cdat_normalize(le16_to_cpu(le_val), le64_to_cpu(le_base), sslbis->data_type); - xa_for_each(&port->dports, index, dport) { - if (dsp_id == ACPI_CDAT_SSLBIS_ANY_PORT || - dsp_id == dport->port_id) { - cxl_access_coordinate_set(dport->coord, - sslbis->data_type, - val); - } + if (dsp_id == ACPI_CDAT_SSLBIS_ANY_PORT || + dsp_id == dport->port_id) { + cxl_access_coordinate_set(dport->coord, + sslbis->data_type, val); + return 0; } } return 0; } -void cxl_switch_parse_cdat(struct cxl_port *port) +void cxl_switch_parse_cdat(struct cxl_dport *dport) { + struct cxl_port *port = dport->port; int rc; if (!port->cdat.table) return; rc = cdat_table_parse(ACPI_CDAT_TYPE_SSLBIS, cdat_sslbis_handler, - port, port->cdat.table, port->cdat.length); + dport, port->cdat.table, port->cdat.length); rc = cdat_table_parse_output(rc); if (rc) dev_dbg(&port->dev, "Failed to parse SSLBIS: %d\n", rc); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index bcdb6fdaa18c..18547a217f88 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1607,7 +1607,7 @@ static struct cxl_dport *cxl_port_add_dport(struct cxl_port *port, if (IS_ERR(new_dport)) return new_dport; - cxl_switch_parse_cdat(port); + cxl_switch_parse_cdat(new_dport); if (ida_is_empty(&port->decoder_ida)) { rc = devm_cxl_switch_port_decoders_setup(port); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index c995ae334b1b..e7f4c929785b 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -892,7 +892,7 @@ static inline u64 cxl_port_get_spa_cache_alias(struct cxl_port *endpoint, #endif void cxl_endpoint_parse_cdat(struct cxl_port *port); -void cxl_switch_parse_cdat(struct cxl_port *port); +void cxl_switch_parse_cdat(struct cxl_dport *dport); int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, struct access_coordinate *coord); From 4687a2c4e6a61b247ad14ffb2ef5ca56e44fa4f2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 6 Aug 2025 12:56:36 -0700 Subject: [PATCH 1667/2711] KVM: VMX: Setup canonical VMCS config prior to kvm_x86_vendor_init() Setup the golden VMCS config during vmx_init(), before the call to kvm_x86_vendor_init(), instead of waiting until the callback to do hardware setup. setup_vmcs_config() only touches VMX state, i.e. doesn't poke anything in kvm.ko, and has no runtime dependencies beyond hv_init_evmcs(). Setting the VMCS config early on will allow referencing VMCS and VMX capabilities at any point during setup, e.g. to check for PERF_GLOBAL_CTRL save/load support during mediated PMU initialization. Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-15-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index a3f0d458be9d..99be305555a7 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8359,8 +8359,6 @@ __init int vmx_hardware_setup(void) vmx_setup_user_return_msrs(); - if (setup_vmcs_config(&vmcs_config, &vmx_capability) < 0) - return -EIO; if (boot_cpu_has(X86_FEATURE_NX)) kvm_enable_efer_bits(EFER_NX); @@ -8584,11 +8582,18 @@ int __init vmx_init(void) return -EOPNOTSUPP; /* - * Note, hv_init_evmcs() touches only VMX knobs, i.e. there's nothing - * to unwind if a later step fails. + * Note, VMCS and eVMCS configuration only touch VMX knobs/variables, + * i.e. there's nothing to unwind if a later step fails. */ hv_init_evmcs(); + /* + * Parse the VMCS config and VMX capabilities before anything else, so + * that the information is available to all setup flows. + */ + if (setup_vmcs_config(&vmcs_config, &vmx_capability) < 0) + return -EIO; + r = kvm_x86_vendor_init(&vt_init_ops); if (r) return r; From e3d1f2826da68c763cba1f29dba5cc81d3fdaaee Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 6 Aug 2025 12:56:37 -0700 Subject: [PATCH 1668/2711] KVM: SVM: Check pmu->version, not enable_pmu, when getting PMC MSRs Gate access to PMC MSRs based on pmu->version, not on kvm->arch.enable_pmu, to more accurately reflect KVM's behavior. This is a glorified nop, as pmu->version and pmu->nr_arch_gp_counters can only be non-zero if amd_pmu_refresh() is reached, kvm_pmu_refresh() invokes amd_pmu_refresh() if and only if kvm->arch.enable_pmu is true, and amd_pmu_refresh() forces pmu->version to be 1 or 2. I.e. the following holds true: !pmu->nr_arch_gp_counters || kvm->arch.enable_pmu == (pmu->version > 0) and so the only way for amd_pmu_get_pmc() to return a non-NULL value is if both kvm->arch.enable_pmu and pmu->version evaluate to true. No real functional change intended. Reviewed-by: Sandipan Das Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-16-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index aa4379e46e96..f3163237286f 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -41,7 +41,7 @@ static inline struct kvm_pmc *get_gp_pmc_amd(struct kvm_pmu *pmu, u32 msr, struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu); unsigned int idx; - if (!vcpu->kvm->arch.enable_pmu) + if (!pmu->version) return NULL; switch (msr) { From 51f34b1e650fc5843530266cea4341750bd1ae37 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 6 Aug 2025 12:56:39 -0700 Subject: [PATCH 1669/2711] KVM: x86/pmu: Snapshot host (i.e. perf's) reported PMU capabilities Take a snapshot of the unadulterated PMU capabilities provided by perf so that KVM can compare guest vPMU capabilities against hardware capabilities when determining whether or not to intercept PMU MSRs (and RDPMC). Reviewed-by: Sandipan Das Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-18-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 40b076a7a5f6..5205f0d9ced9 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -26,6 +26,10 @@ /* This is enough to filter the vast majority of currently defined events. */ #define KVM_PMU_EVENT_FILTER_MAX_EVENTS 300 +/* Unadultered PMU capabilities of the host, i.e. of hardware. */ +static struct x86_pmu_capability __read_mostly kvm_host_pmu; + +/* KVM's PMU capabilities, i.e. the intersection of KVM and hardware support. */ struct x86_pmu_capability __read_mostly kvm_pmu_cap; EXPORT_SYMBOL_GPL(kvm_pmu_cap); @@ -104,6 +108,8 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops) bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL; int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS; + perf_get_x86_pmu_capability(&kvm_host_pmu); + /* * Hybrid PMUs don't play nice with virtualization without careful * configuration by userspace, and KVM's APIs for reporting supported @@ -114,18 +120,16 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops) enable_pmu = false; if (enable_pmu) { - perf_get_x86_pmu_capability(&kvm_pmu_cap); - /* * WARN if perf did NOT disable hardware PMU if the number of * architecturally required GP counters aren't present, i.e. if * there are a non-zero number of counters, but fewer than what * is architecturally required. */ - if (!kvm_pmu_cap.num_counters_gp || - WARN_ON_ONCE(kvm_pmu_cap.num_counters_gp < min_nr_gp_ctrs)) + if (!kvm_host_pmu.num_counters_gp || + WARN_ON_ONCE(kvm_host_pmu.num_counters_gp < min_nr_gp_ctrs)) enable_pmu = false; - else if (is_intel && !kvm_pmu_cap.version) + else if (is_intel && !kvm_host_pmu.version) enable_pmu = false; } @@ -134,6 +138,7 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops) return; } + memcpy(&kvm_pmu_cap, &kvm_host_pmu, sizeof(kvm_host_pmu)); kvm_pmu_cap.version = min(kvm_pmu_cap.version, 2); kvm_pmu_cap.num_counters_gp = min(kvm_pmu_cap.num_counters_gp, pmu_ops->MAX_NR_GP_COUNTERS); From 1e24bece26812547608dd02eb1fc138359d0f813 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Wed, 6 Aug 2025 12:56:44 -0700 Subject: [PATCH 1670/2711] KVM: x86: Rename vmx_vmentry/vmexit_ctrl() helpers Rename the two helpers vmx_vmentry/vmexit_ctrl() to vmx_get_initial_vmentry/vmexit_ctrl() to represent their real meaning. No functional change intended. Suggested-by: Sean Christopherson Signed-off-by: Dapeng Mi Signed-off-by: Mingwei Zhang Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-23-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 99be305555a7..75cd5768e8ad 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4304,7 +4304,7 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx) return pin_based_exec_ctrl; } -static u32 vmx_vmentry_ctrl(void) +static u32 vmx_get_initial_vmentry_ctrl(void) { u32 vmentry_ctrl = vmcs_config.vmentry_ctrl; @@ -4321,7 +4321,7 @@ static u32 vmx_vmentry_ctrl(void) return vmentry_ctrl; } -static u32 vmx_vmexit_ctrl(void) +static u32 vmx_get_initial_vmexit_ctrl(void) { u32 vmexit_ctrl = vmcs_config.vmexit_ctrl; @@ -4686,10 +4686,10 @@ static void init_vmcs(struct vcpu_vmx *vmx) if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) vmcs_write64(GUEST_IA32_PAT, vmx->vcpu.arch.pat); - vm_exit_controls_set(vmx, vmx_vmexit_ctrl()); + vm_exit_controls_set(vmx, vmx_get_initial_vmexit_ctrl()); /* 22.2.1, 20.8.1 */ - vm_entry_controls_set(vmx, vmx_vmentry_ctrl()); + vm_entry_controls_set(vmx, vmx_get_initial_vmentry_ctrl()); vmx->vcpu.arch.cr0_guest_owned_bits = vmx_l1_guest_owned_cr0_bits(); vmcs_writel(CR0_GUEST_HOST_MASK, ~vmx->vcpu.arch.cr0_guest_owned_bits); From cdfed9370b96aabaa2d20f65ca4e9c9b009fe8fa Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Wed, 6 Aug 2025 12:56:45 -0700 Subject: [PATCH 1671/2711] KVM: x86/pmu: Move PMU_CAP_{FW_WRITES,LBR_FMT} into msr-index.h header Move PMU_CAP_{FW_WRITES,LBR_FMT} into msr-index.h and rename them with PERF_CAP prefix to keep consistent with other perf capabilities macros. No functional change intended. Signed-off-by: Dapeng Mi Signed-off-by: Mingwei Zhang Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-24-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/msr-index.h | 15 +++++++++------ arch/x86/kvm/vmx/capabilities.h | 3 --- arch/x86/kvm/vmx/pmu_intel.c | 4 ++-- arch/x86/kvm/vmx/vmx.c | 12 ++++++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 20fa4a79df13..717baeba6db3 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -315,12 +315,15 @@ #define PERF_CAP_PT_IDX 16 #define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6 -#define PERF_CAP_PEBS_TRAP BIT_ULL(6) -#define PERF_CAP_ARCH_REG BIT_ULL(7) -#define PERF_CAP_PEBS_FORMAT 0xf00 -#define PERF_CAP_PEBS_BASELINE BIT_ULL(14) -#define PERF_CAP_PEBS_MASK (PERF_CAP_PEBS_TRAP | PERF_CAP_ARCH_REG | \ - PERF_CAP_PEBS_FORMAT | PERF_CAP_PEBS_BASELINE) + +#define PERF_CAP_LBR_FMT 0x3f +#define PERF_CAP_PEBS_TRAP BIT_ULL(6) +#define PERF_CAP_ARCH_REG BIT_ULL(7) +#define PERF_CAP_PEBS_FORMAT 0xf00 +#define PERF_CAP_FW_WRITES BIT_ULL(13) +#define PERF_CAP_PEBS_BASELINE BIT_ULL(14) +#define PERF_CAP_PEBS_MASK (PERF_CAP_PEBS_TRAP | PERF_CAP_ARCH_REG | \ + PERF_CAP_PEBS_FORMAT | PERF_CAP_PEBS_BASELINE) #define MSR_IA32_RTIT_CTL 0x00000570 #define RTIT_CTL_TRACEEN BIT(0) diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h index 5316c27f6099..f614428dbeda 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -20,9 +20,6 @@ extern int __read_mostly pt_mode; #define PT_MODE_SYSTEM 0 #define PT_MODE_HOST_GUEST 1 -#define PMU_CAP_FW_WRITES (1ULL << 13) -#define PMU_CAP_LBR_FMT 0x3f - struct nested_vmx_msrs { /* * We only store the "true" versions of the VMX capability MSRs. We diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index b2a2c4ebf448..343de013eacd 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -138,7 +138,7 @@ static inline u64 vcpu_get_perf_capabilities(struct kvm_vcpu *vcpu) static inline bool fw_writes_is_enabled(struct kvm_vcpu *vcpu) { - return (vcpu_get_perf_capabilities(vcpu) & PMU_CAP_FW_WRITES) != 0; + return (vcpu_get_perf_capabilities(vcpu) & PERF_CAP_FW_WRITES) != 0; } static inline struct kvm_pmc *get_fw_gp_pmc(struct kvm_pmu *pmu, u32 msr) @@ -588,7 +588,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) perf_capabilities = vcpu_get_perf_capabilities(vcpu); if (intel_pmu_lbr_is_compatible(vcpu) && - (perf_capabilities & PMU_CAP_LBR_FMT)) + (perf_capabilities & PERF_CAP_LBR_FMT)) memcpy(&lbr_desc->records, &vmx_lbr_caps, sizeof(vmx_lbr_caps)); else lbr_desc->records.nr = 0; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 75cd5768e8ad..5d3a50547c3e 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2127,7 +2127,7 @@ u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiated) (host_initiated || guest_cpu_cap_has(vcpu, X86_FEATURE_BUS_LOCK_DETECT))) debugctl |= DEBUGCTLMSR_BUS_LOCK_DETECT; - if ((kvm_caps.supported_perf_cap & PMU_CAP_LBR_FMT) && + if ((kvm_caps.supported_perf_cap & PERF_CAP_LBR_FMT) && (host_initiated || intel_pmu_lbr_is_enabled(vcpu))) debugctl |= DEBUGCTLMSR_LBR | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI; @@ -2412,9 +2412,9 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vmx->pt_desc.guest.addr_a[index / 2] = data; break; case MSR_IA32_PERF_CAPABILITIES: - if (data & PMU_CAP_LBR_FMT) { - if ((data & PMU_CAP_LBR_FMT) != - (kvm_caps.supported_perf_cap & PMU_CAP_LBR_FMT)) + if (data & PERF_CAP_LBR_FMT) { + if ((data & PERF_CAP_LBR_FMT) != + (kvm_caps.supported_perf_cap & PERF_CAP_LBR_FMT)) return 1; if (!cpuid_model_is_consistent(vcpu)) return 1; @@ -7810,7 +7810,7 @@ void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) static __init u64 vmx_get_perf_capabilities(void) { - u64 perf_cap = PMU_CAP_FW_WRITES; + u64 perf_cap = PERF_CAP_FW_WRITES; u64 host_perf_cap = 0; if (!enable_pmu) @@ -7830,7 +7830,7 @@ static __init u64 vmx_get_perf_capabilities(void) if (!vmx_lbr_caps.has_callstack) memset(&vmx_lbr_caps, 0, sizeof(vmx_lbr_caps)); else if (vmx_lbr_caps.nr) - perf_cap |= host_perf_cap & PMU_CAP_LBR_FMT; + perf_cap |= host_perf_cap & PERF_CAP_LBR_FMT; } if (vmx_pebs_supported()) { From 6057497336bbfabd3a2f632bba2cd2bfbcb7b304 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 6 Aug 2025 12:56:46 -0700 Subject: [PATCH 1672/2711] KVM: x86: Rework KVM_REQ_MSR_FILTER_CHANGED into a generic RECALC_INTERCEPTS Rework the MSR_FILTER_CHANGED request into a more generic RECALC_INTERCEPTS request, and expand the responsibilities of vendor code to recalculate all intercepts that vary based on userspace input, e.g. instruction intercepts that are tied to guest CPUID. Providing a generic recalc request will allow the upcoming mediated PMU support to trigger a recalc when PMU features, e.g. PERF_CAPABILITIES, are set by userspace, without having to make multiple calls to/from PMU code. As a bonus, using a request will effectively coalesce recalcs, e.g. will reduce the number of recalcs for normal usage from 3+ to 1 (vCPU create, set CPUID, set PERF_CAPABILITIES (Intel only), set filter). The downside is that MSR filter changes that are done in isolation will do a small amount of unnecessary work, but that's already a relatively slow path, and the cost of recalculating instruction intercepts is negligible. Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-25-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm-x86-ops.h | 2 +- arch/x86/include/asm/kvm_host.h | 4 ++-- arch/x86/kvm/svm/svm.c | 8 ++++---- arch/x86/kvm/vmx/main.c | 14 +++++++------- arch/x86/kvm/vmx/vmx.c | 9 +++++++-- arch/x86/kvm/vmx/x86_ops.h | 2 +- arch/x86/kvm/x86.c | 15 +++++++-------- 7 files changed, 29 insertions(+), 25 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 18a5c3119e1a..7c240e23bd52 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -138,7 +138,7 @@ KVM_X86_OP(check_emulate_instruction) KVM_X86_OP(apic_init_signal_blocked) KVM_X86_OP_OPTIONAL(enable_l2_tlb_flush) KVM_X86_OP_OPTIONAL(migrate_timers) -KVM_X86_OP(recalc_msr_intercepts) +KVM_X86_OP(recalc_intercepts) KVM_X86_OP(complete_emulated_msr) KVM_X86_OP(vcpu_deliver_sipi_vector) KVM_X86_OP_OPTIONAL_RET0(vcpu_get_apicv_inhibit_reasons); diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 464a636b2dc6..7e1e41f04752 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -120,7 +120,7 @@ #define KVM_REQ_TLB_FLUSH_GUEST \ KVM_ARCH_REQ_FLAGS(27, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) #define KVM_REQ_APF_READY KVM_ARCH_REQ(28) -#define KVM_REQ_MSR_FILTER_CHANGED KVM_ARCH_REQ(29) +#define KVM_REQ_RECALC_INTERCEPTS KVM_ARCH_REQ(29) #define KVM_REQ_UPDATE_CPU_DIRTY_LOGGING \ KVM_ARCH_REQ_FLAGS(30, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) #define KVM_REQ_MMU_FREE_OBSOLETE_ROOTS \ @@ -1914,7 +1914,7 @@ struct kvm_x86_ops { int (*enable_l2_tlb_flush)(struct kvm_vcpu *vcpu); void (*migrate_timers)(struct kvm_vcpu *vcpu); - void (*recalc_msr_intercepts)(struct kvm_vcpu *vcpu); + void (*recalc_intercepts)(struct kvm_vcpu *vcpu); int (*complete_emulated_msr)(struct kvm_vcpu *vcpu, int err); void (*vcpu_deliver_sipi_vector)(struct kvm_vcpu *vcpu, u8 vector); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 7e7821ee8ee1..711f160113d1 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1077,7 +1077,7 @@ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu) } } -static void svm_recalc_intercepts_after_set_cpuid(struct kvm_vcpu *vcpu) +static void svm_recalc_intercepts(struct kvm_vcpu *vcpu) { svm_recalc_instruction_intercepts(vcpu); svm_recalc_msr_intercepts(vcpu); @@ -1225,7 +1225,7 @@ static void init_vmcb(struct kvm_vcpu *vcpu) svm_hv_init_vmcb(vmcb); - svm_recalc_intercepts_after_set_cpuid(vcpu); + svm_recalc_intercepts(vcpu); vmcb_mark_all_dirty(vmcb); @@ -4479,7 +4479,7 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) if (sev_guest(vcpu->kvm)) sev_vcpu_after_set_cpuid(svm); - svm_recalc_intercepts_after_set_cpuid(vcpu); + svm_recalc_intercepts(vcpu); } static bool svm_has_wbinvd_exit(void) @@ -5181,7 +5181,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { .apic_init_signal_blocked = svm_apic_init_signal_blocked, - .recalc_msr_intercepts = svm_recalc_msr_intercepts, + .recalc_intercepts = svm_recalc_intercepts, .complete_emulated_msr = svm_complete_emulated_msr, .vcpu_deliver_sipi_vector = svm_vcpu_deliver_sipi_vector, diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c index dbab1c15b0cd..68dcafd177a8 100644 --- a/arch/x86/kvm/vmx/main.c +++ b/arch/x86/kvm/vmx/main.c @@ -188,18 +188,18 @@ static int vt_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return vmx_get_msr(vcpu, msr_info); } -static void vt_recalc_msr_intercepts(struct kvm_vcpu *vcpu) +static void vt_recalc_intercepts(struct kvm_vcpu *vcpu) { /* - * TDX doesn't allow VMM to configure interception of MSR accesses. - * TDX guest requests MSR accesses by calling TDVMCALL. The MSR - * filters will be applied when handling the TDVMCALL for RDMSR/WRMSR - * if the userspace has set any. + * TDX doesn't allow VMM to configure interception of instructions or + * MSR accesses. TDX guest requests MSR accesses by calling TDVMCALL. + * The MSR filters will be applied when handling the TDVMCALL for + * RDMSR/WRMSR if the userspace has set any. */ if (is_td_vcpu(vcpu)) return; - vmx_recalc_msr_intercepts(vcpu); + vmx_recalc_intercepts(vcpu); } static int vt_complete_emulated_msr(struct kvm_vcpu *vcpu, int err) @@ -995,7 +995,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = { .apic_init_signal_blocked = vt_op(apic_init_signal_blocked), .migrate_timers = vmx_migrate_timers, - .recalc_msr_intercepts = vt_op(recalc_msr_intercepts), + .recalc_intercepts = vt_op(recalc_intercepts), .complete_emulated_msr = vt_op(complete_emulated_msr), .vcpu_deliver_sipi_vector = kvm_vcpu_deliver_sipi_vector, diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 5d3a50547c3e..68bec421f3fc 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4068,7 +4068,7 @@ void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu) } } -void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu) +static void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu) { if (!cpu_has_vmx_msr_bitmap()) return; @@ -4121,6 +4121,11 @@ void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu) */ } +void vmx_recalc_intercepts(struct kvm_vcpu *vcpu) +{ + vmx_recalc_msr_intercepts(vcpu); +} + static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu, int vector) { @@ -7802,7 +7807,7 @@ void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) ~FEAT_CTL_SGX_LC_ENABLED; /* Recalc MSR interception to account for feature changes. */ - vmx_recalc_msr_intercepts(vcpu); + vmx_recalc_intercepts(vcpu); /* Refresh #PF interception to account for MAXPHYADDR changes. */ vmx_update_exception_bitmap(vcpu); diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h index 2b3424f638db..2c590ff44ced 100644 --- a/arch/x86/kvm/vmx/x86_ops.h +++ b/arch/x86/kvm/vmx/x86_ops.h @@ -52,7 +52,7 @@ void vmx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode, int trig_mode, int vector); void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu); bool vmx_has_emulated_msr(struct kvm *kvm, u32 index); -void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu); +void vmx_recalc_intercepts(struct kvm_vcpu *vcpu); void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu); void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu); int vmx_get_feature_msr(u32 msr, u64 *data); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 99f2a150ca78..64e08148909b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6794,7 +6794,11 @@ static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, kvm_free_msr_filter(old_filter); - kvm_make_all_cpus_request(kvm, KVM_REQ_MSR_FILTER_CHANGED); + /* + * Recalc MSR intercepts as userspace may want to intercept accesses to + * MSRs that KVM would otherwise pass through to the guest. + */ + kvm_make_all_cpus_request(kvm, KVM_REQ_RECALC_INTERCEPTS); return 0; } @@ -10827,13 +10831,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) if (kvm_check_request(KVM_REQ_APF_READY, vcpu)) kvm_check_async_pf_completion(vcpu); - /* - * Recalc MSR intercepts as userspace may want to intercept - * accesses to MSRs that KVM would otherwise pass through to - * the guest. - */ - if (kvm_check_request(KVM_REQ_MSR_FILTER_CHANGED, vcpu)) - kvm_x86_call(recalc_msr_intercepts)(vcpu); + if (kvm_check_request(KVM_REQ_RECALC_INTERCEPTS, vcpu)) + kvm_x86_call(recalc_intercepts)(vcpu); if (kvm_check_request(KVM_REQ_UPDATE_CPU_DIRTY_LOGGING, vcpu)) kvm_x86_call(update_cpu_dirty_logging)(vcpu); From 5a1a726e68ff256f564cf51ad21a96bceb4dd954 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 6 Aug 2025 12:56:47 -0700 Subject: [PATCH 1673/2711] KVM: x86: Use KVM_REQ_RECALC_INTERCEPTS to react to CPUID updates Defer recalculating MSR and instruction intercepts after a CPUID update via RECALC_INTERCEPTS to converge on RECALC_INTERCEPTS as the "official" mechanism for triggering recalcs. As a bonus, because KVM does a "recalc" during vCPU creation, and every functional VMM sets CPUID at least once, for all intents and purposes this saves at least one recalc. Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-26-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/cpuid.c | 2 ++ arch/x86/kvm/svm/svm.c | 4 +--- arch/x86/kvm/vmx/vmx.c | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index ad6cadf09930..efee08fad72e 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -448,6 +448,8 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) * adjustments to the reserved GPA bits. */ kvm_mmu_after_set_cpuid(vcpu); + + kvm_make_request(KVM_REQ_RECALC_INTERCEPTS, vcpu); } int cpuid_query_maxphyaddr(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 711f160113d1..22c5e4ffa132 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1225,7 +1225,7 @@ static void init_vmcb(struct kvm_vcpu *vcpu) svm_hv_init_vmcb(vmcb); - svm_recalc_intercepts(vcpu); + kvm_make_request(KVM_REQ_RECALC_INTERCEPTS, vcpu); vmcb_mark_all_dirty(vmcb); @@ -4478,8 +4478,6 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) if (sev_guest(vcpu->kvm)) sev_vcpu_after_set_cpuid(svm); - - svm_recalc_intercepts(vcpu); } static bool svm_has_wbinvd_exit(void) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 68bec421f3fc..6b9523ca082c 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7806,9 +7806,6 @@ void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) vmx->msr_ia32_feature_control_valid_bits &= ~FEAT_CTL_SGX_LC_ENABLED; - /* Recalc MSR interception to account for feature changes. */ - vmx_recalc_intercepts(vcpu); - /* Refresh #PF interception to account for MAXPHYADDR changes. */ vmx_update_exception_bitmap(vcpu); } From 2bff2edf69ed80b21d35470a3580f25979be2c4b Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Wed, 6 Aug 2025 12:56:48 -0700 Subject: [PATCH 1674/2711] KVM: VMX: Add helpers to toggle/change a bit in VMCS execution controls Expand the VMCS controls builder macros to generate helpers to change a bit to the desired value, and use the new helpers when toggling APICv related controls. No functional change intended. Suggested-by: Sean Christopherson Signed-off-by: Dapeng Mi Signed-off-by: Mingwei Zhang [sean: rewrite changelog] Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-27-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 20 +++++++------------- arch/x86/kvm/vmx/vmx.h | 8 ++++++++ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 6b9523ca082c..d2fa64bddb57 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4356,19 +4356,13 @@ void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) pin_controls_set(vmx, vmx_pin_based_exec_ctrl(vmx)); - if (kvm_vcpu_apicv_active(vcpu)) { - secondary_exec_controls_setbit(vmx, - SECONDARY_EXEC_APIC_REGISTER_VIRT | - SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); - if (enable_ipiv) - tertiary_exec_controls_setbit(vmx, TERTIARY_EXEC_IPI_VIRT); - } else { - secondary_exec_controls_clearbit(vmx, - SECONDARY_EXEC_APIC_REGISTER_VIRT | - SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); - if (enable_ipiv) - tertiary_exec_controls_clearbit(vmx, TERTIARY_EXEC_IPI_VIRT); - } + secondary_exec_controls_changebit(vmx, + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY, + kvm_vcpu_apicv_active(vcpu)); + if (enable_ipiv) + tertiary_exec_controls_changebit(vmx, TERTIARY_EXEC_IPI_VIRT, + kvm_vcpu_apicv_active(vcpu)); vmx_update_msr_bitmap_x2apic(vcpu); } diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 24d65dac5e89..23d6e89b96f2 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -608,6 +608,14 @@ static __always_inline void lname##_controls_clearbit(struct vcpu_vmx *vmx, u##b { \ BUILD_BUG_ON(!(val & (KVM_REQUIRED_VMX_##uname | KVM_OPTIONAL_VMX_##uname))); \ lname##_controls_set(vmx, lname##_controls_get(vmx) & ~val); \ +} \ +static __always_inline void lname##_controls_changebit(struct vcpu_vmx *vmx, u##bits val, \ + bool set) \ +{ \ + if (set) \ + lname##_controls_setbit(vmx, val); \ + else \ + lname##_controls_clearbit(vmx, val); \ } BUILD_CONTROLS_SHADOW(vm_entry, VM_ENTRY_CONTROLS, 32) BUILD_CONTROLS_SHADOW(vm_exit, VM_EXIT_CONTROLS, 32) From 30c0267f15812114d7ab96a7dd45874742d736fe Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Wed, 6 Aug 2025 12:56:51 -0700 Subject: [PATCH 1675/2711] KVM: x86/pmu: Use BIT_ULL() instead of open coded equivalents Replace a variety of "1ull << N" and "(u64)1 << N" snippets with BIT_ULL() in the PMU code. No functional change intended. Signed-off-by: Dapeng Mi [sean: split to separate patch, write changelog] Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-30-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/pmu.c | 4 ++-- arch/x86/kvm/vmx/pmu_intel.c | 15 ++++++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index f3163237286f..25ccd6a99838 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -200,11 +200,11 @@ static void amd_pmu_refresh(struct kvm_vcpu *vcpu) kvm_pmu_cap.num_counters_gp); if (pmu->version > 1) { - pmu->global_ctrl_rsvd = ~((1ull << pmu->nr_arch_gp_counters) - 1); + pmu->global_ctrl_rsvd = ~(BIT_ULL(pmu->nr_arch_gp_counters) - 1); pmu->global_status_rsvd = pmu->global_ctrl_rsvd; } - pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << 48) - 1; + pmu->counter_bitmask[KVM_PMC_GP] = BIT_ULL(48) - 1; pmu->reserved_bits = 0xfffffff000280000ull; pmu->raw_event_mask = AMD64_RAW_EVENT_MASK; /* not applicable to AMD; but clean them to prevent any fall out */ diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 343de013eacd..096f091980f0 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -536,11 +536,10 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) kvm_pmu_cap.num_counters_gp); eax.split.bit_width = min_t(int, eax.split.bit_width, kvm_pmu_cap.bit_width_gp); - pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << eax.split.bit_width) - 1; + pmu->counter_bitmask[KVM_PMC_GP] = BIT_ULL(eax.split.bit_width) - 1; eax.split.mask_length = min_t(int, eax.split.mask_length, kvm_pmu_cap.events_mask_len); - pmu->available_event_types = ~entry->ebx & - ((1ull << eax.split.mask_length) - 1); + pmu->available_event_types = ~entry->ebx & (BIT_ULL(eax.split.mask_length) - 1); if (pmu->version == 1) { pmu->nr_arch_fixed_counters = 0; @@ -549,16 +548,15 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) kvm_pmu_cap.num_counters_fixed); edx.split.bit_width_fixed = min_t(int, edx.split.bit_width_fixed, kvm_pmu_cap.bit_width_fixed); - pmu->counter_bitmask[KVM_PMC_FIXED] = - ((u64)1 << edx.split.bit_width_fixed) - 1; + pmu->counter_bitmask[KVM_PMC_FIXED] = BIT_ULL(edx.split.bit_width_fixed) - 1; } intel_pmu_enable_fixed_counter_bits(pmu, INTEL_FIXED_0_KERNEL | INTEL_FIXED_0_USER | INTEL_FIXED_0_ENABLE_PMI); - counter_rsvd = ~(((1ull << pmu->nr_arch_gp_counters) - 1) | - (((1ull << pmu->nr_arch_fixed_counters) - 1) << KVM_FIXED_PMC_BASE_IDX)); + counter_rsvd = ~((BIT_ULL(pmu->nr_arch_gp_counters) - 1) | + ((BIT_ULL(pmu->nr_arch_fixed_counters) - 1) << KVM_FIXED_PMC_BASE_IDX)); pmu->global_ctrl_rsvd = counter_rsvd; /* @@ -603,8 +601,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->pebs_data_cfg_rsvd = ~0xff00000full; intel_pmu_enable_fixed_counter_bits(pmu, ICL_FIXED_0_ADAPTIVE); } else { - pmu->pebs_enable_rsvd = - ~((1ull << pmu->nr_arch_gp_counters) - 1); + pmu->pebs_enable_rsvd = ~(BIT_ULL(pmu->nr_arch_gp_counters) - 1); } } } From 9bae7a086394128bd829c0c04f9f75600fdc1bc1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 6 Aug 2025 12:56:52 -0700 Subject: [PATCH 1676/2711] KVM: x86/pmu: Move initialization of valid PMCs bitmask to common x86 Move all initialization of all_valid_pmc_idx to common code, as the logic is 100% common to Intel and AMD, and KVM heavily relies on Intel and AMD having the same semantics. E.g. the fact that AMD doesn't support fixed counters doesn't allow KVM to use all_valid_pmc_idx[63:32] for other purposes. Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-31-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 4 ++++ arch/x86/kvm/svm/pmu.c | 1 - arch/x86/kvm/vmx/pmu_intel.c | 5 ----- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 5205f0d9ced9..b7dc5bd981ba 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -888,6 +888,10 @@ void kvm_pmu_refresh(struct kvm_vcpu *vcpu) */ if (kvm_pmu_has_perf_global_ctrl(pmu) && pmu->nr_arch_gp_counters) pmu->global_ctrl = GENMASK_ULL(pmu->nr_arch_gp_counters - 1, 0); + + bitmap_set(pmu->all_valid_pmc_idx, 0, pmu->nr_arch_gp_counters); + bitmap_set(pmu->all_valid_pmc_idx, KVM_FIXED_PMC_BASE_IDX, + pmu->nr_arch_fixed_counters); } void kvm_pmu_init(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 25ccd6a99838..bc062285fbf5 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -210,7 +210,6 @@ static void amd_pmu_refresh(struct kvm_vcpu *vcpu) /* not applicable to AMD; but clean them to prevent any fall out */ pmu->counter_bitmask[KVM_PMC_FIXED] = 0; pmu->nr_arch_fixed_counters = 0; - bitmap_set(pmu->all_valid_pmc_idx, 0, pmu->nr_arch_gp_counters); } static void amd_pmu_init(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 096f091980f0..edf0db8e53ad 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -579,11 +579,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->raw_event_mask |= (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED); } - bitmap_set(pmu->all_valid_pmc_idx, - 0, pmu->nr_arch_gp_counters); - bitmap_set(pmu->all_valid_pmc_idx, - INTEL_PMC_MAX_GENERIC, pmu->nr_arch_fixed_counters); - perf_capabilities = vcpu_get_perf_capabilities(vcpu); if (intel_pmu_lbr_is_compatible(vcpu) && (perf_capabilities & PERF_CAP_LBR_FMT)) From c49aa98376864ddf82175a7ea48977c637398653 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 6 Aug 2025 12:56:53 -0700 Subject: [PATCH 1677/2711] KVM: x86/pmu: Restrict GLOBAL_{CTRL,STATUS}, fixed PMCs, and PEBS to PMU v2+ Restrict support for GLOBAL_CTRL, GLOBAL_STATUS, fixed PMCs, and PEBS to v2 or later vPMUs. The SDM explicitly states that GLOBAL_{CTRL,STATUS} and fixed counters were introduced with PMU v2, and PEBS has hard dependencies on fixed counters and the bitmap MSR layouts established by PMU v2. Reported-by: Dapeng Mi Tested-by: Xudong Hao Link: https://lore.kernel.org/r/20250806195706.1650976-32-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 51 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index edf0db8e53ad..de1d9785c01f 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -541,16 +541,33 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) kvm_pmu_cap.events_mask_len); pmu->available_event_types = ~entry->ebx & (BIT_ULL(eax.split.mask_length) - 1); - if (pmu->version == 1) { - pmu->nr_arch_fixed_counters = 0; - } else { - pmu->nr_arch_fixed_counters = min_t(int, edx.split.num_counters_fixed, - kvm_pmu_cap.num_counters_fixed); - edx.split.bit_width_fixed = min_t(int, edx.split.bit_width_fixed, - kvm_pmu_cap.bit_width_fixed); - pmu->counter_bitmask[KVM_PMC_FIXED] = BIT_ULL(edx.split.bit_width_fixed) - 1; + entry = kvm_find_cpuid_entry_index(vcpu, 7, 0); + if (entry && + (boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) && + (entry->ebx & (X86_FEATURE_HLE|X86_FEATURE_RTM))) { + pmu->reserved_bits ^= HSW_IN_TX; + pmu->raw_event_mask |= (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED); } + perf_capabilities = vcpu_get_perf_capabilities(vcpu); + if (intel_pmu_lbr_is_compatible(vcpu) && + (perf_capabilities & PERF_CAP_LBR_FMT)) + memcpy(&lbr_desc->records, &vmx_lbr_caps, sizeof(vmx_lbr_caps)); + else + lbr_desc->records.nr = 0; + + if (lbr_desc->records.nr) + bitmap_set(pmu->all_valid_pmc_idx, INTEL_PMC_IDX_FIXED_VLBR, 1); + + if (pmu->version == 1) + return; + + pmu->nr_arch_fixed_counters = min_t(int, edx.split.num_counters_fixed, + kvm_pmu_cap.num_counters_fixed); + edx.split.bit_width_fixed = min_t(int, edx.split.bit_width_fixed, + kvm_pmu_cap.bit_width_fixed); + pmu->counter_bitmask[KVM_PMC_FIXED] = BIT_ULL(edx.split.bit_width_fixed) - 1; + intel_pmu_enable_fixed_counter_bits(pmu, INTEL_FIXED_0_KERNEL | INTEL_FIXED_0_USER | INTEL_FIXED_0_ENABLE_PMI); @@ -571,24 +588,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->global_status_rsvd &= ~MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI; - entry = kvm_find_cpuid_entry_index(vcpu, 7, 0); - if (entry && - (boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) && - (entry->ebx & (X86_FEATURE_HLE|X86_FEATURE_RTM))) { - pmu->reserved_bits ^= HSW_IN_TX; - pmu->raw_event_mask |= (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED); - } - - perf_capabilities = vcpu_get_perf_capabilities(vcpu); - if (intel_pmu_lbr_is_compatible(vcpu) && - (perf_capabilities & PERF_CAP_LBR_FMT)) - memcpy(&lbr_desc->records, &vmx_lbr_caps, sizeof(vmx_lbr_caps)); - else - lbr_desc->records.nr = 0; - - if (lbr_desc->records.nr) - bitmap_set(pmu->all_valid_pmc_idx, INTEL_PMC_IDX_FIXED_VLBR, 1); - if (perf_capabilities & PERF_CAP_PEBS_FORMAT) { if (perf_capabilities & PERF_CAP_PEBS_BASELINE) { pmu->pebs_enable_rsvd = counter_rsvd; From 7e52794b88f8bce684ffd7081279ac4236131ae1 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Thu, 18 Sep 2025 17:36:06 +0200 Subject: [PATCH 1678/2711] dt-bindings: touchscreen: convert bu21013 bindings to json schema Convert Rohm BU21013 I2C touchscreen controller device tree binding to json-schema. Additional changes: - Replace -supply with avdd-supply to match example and existing DTS. - Add reset-gpios in the example because it is required. Signed-off-by: Dario Binacchi Reviewed-by: Krzysztof Kozlowski Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250918153630.2535208-1-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/bu21013.txt | 43 --------- .../input/touchscreen/rohm,bu21013.yaml | 95 +++++++++++++++++++ 2 files changed, 95 insertions(+), 43 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/bu21013.txt create mode 100644 Documentation/devicetree/bindings/input/touchscreen/rohm,bu21013.yaml diff --git a/Documentation/devicetree/bindings/input/touchscreen/bu21013.txt b/Documentation/devicetree/bindings/input/touchscreen/bu21013.txt deleted file mode 100644 index da4c9d8b99b1..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/bu21013.txt +++ /dev/null @@ -1,43 +0,0 @@ -* Rohm BU21013 Touch Screen - -Required properties: - - compatible : "rohm,bu21013_tp" - - reg : I2C device address - - reset-gpios : GPIO pin enabling (selecting) chip (CS) - - interrupt-parent : the phandle for the gpio controller - - interrupts : (gpio) interrupt to which the chip is connected - -Optional properties: - - touch-gpios : GPIO pin registering a touch event - - -supply : Phandle to a regulator supply - - touchscreen-size-x : General touchscreen binding, see [1]. - - touchscreen-size-y : General touchscreen binding, see [1]. - - touchscreen-inverted-x : General touchscreen binding, see [1]. - - touchscreen-inverted-y : General touchscreen binding, see [1]. - - touchscreen-swapped-x-y : General touchscreen binding, see [1]. - -[1] All general touchscreen properties are described in - Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt. - -Deprecated properties: - - rohm,touch-max-x : Maximum outward permitted limit in the X axis - - rohm,touch-max-y : Maximum outward permitted limit in the Y axis - - rohm,flip-x : Flip touch coordinates on the X axis - - rohm,flip-y : Flip touch coordinates on the Y axis - -Example: - - i2c@80110000 { - bu21013_tp@5c { - compatible = "rohm,bu21013_tp"; - reg = <0x5c>; - interrupt-parent = <&gpio2>; - interrupts <&20 IRQ_TYPE_LEVEL_LOW>; - touch-gpio = <&gpio2 20 GPIO_ACTIVE_LOW>; - avdd-supply = <&ab8500_ldo_aux1_reg>; - - touchscreen-size-x = <384>; - touchscreen-size-y = <704>; - touchscreen-inverted-y; - }; - }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/rohm,bu21013.yaml b/Documentation/devicetree/bindings/input/touchscreen/rohm,bu21013.yaml new file mode 100644 index 000000000000..adea2c4edf1f --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/rohm,bu21013.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/rohm,bu21013.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rohm BU21013 touchscreen + +description: + Rohm BU21013 I2C driven touchscreen controller. + +maintainers: + - Dario Binacchi + +allOf: + - $ref: touchscreen.yaml# + +properties: + compatible: + enum: + - rohm,bu21013_tp + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + touch-gpios: + maxItems: 1 + description: GPIO registering a touch event. + + avdd-supply: + description: Analogic power supply + + rohm,touch-max-x: + deprecated: true + description: Maximum value on the X axis. + $ref: /schemas/types.yaml#/definitions/uint32 + + rohm,touch-max-y: + deprecated: true + description: Maximum value on the Y axis. + $ref: /schemas/types.yaml#/definitions/uint32 + + rohm,flip-x: + deprecated: true + description: Flip touch coordinates on the X axis + type: boolean + + rohm,flip-y: + deprecated: true + description: Flip touch coordinates on the Y axis + type: boolean + + touchscreen-inverted-x: true + touchscreen-inverted-y: true + touchscreen-size-x: true + touchscreen-size-y: true + touchscreen-swapped-x-y: true + +additionalProperties: false + +required: + - compatible + - reg + - reset-gpios + - interrupts + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@5c { + compatible = "rohm,bu21013_tp"; + reg = <0x5c>; + + interrupt-parent = <&gpio2>; + interrupts = <0x20 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio2 19 GPIO_ACTIVE_LOW>; + touch-gpios = <&gpio2 20 GPIO_ACTIVE_LOW>; + avdd-supply = <&ab8500_ldo_aux1_reg>; + + touchscreen-size-x = <384>; + touchscreen-size-y = <704>; + touchscreen-inverted-y; + }; + }; From 7ee0f793d00d586bf01017a0a24308659873975c Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Thu, 18 Sep 2025 17:36:09 +0200 Subject: [PATCH 1679/2711] dt-bindings: touchscreen: convert zet6223 bindings to json schema Convert Zeitec ZET6223 touchscreen controller device tree binding to json-schema. Signed-off-by: Dario Binacchi Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250918153630.2535208-4-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/zeitec,zet6223.yaml | 62 +++++++++++++++++++ .../bindings/input/touchscreen/zet6223.txt | 30 --------- 2 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/zeitec,zet6223.yaml delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/zet6223.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/zeitec,zet6223.yaml b/Documentation/devicetree/bindings/input/touchscreen/zeitec,zet6223.yaml new file mode 100644 index 000000000000..d5e132ec0273 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/zeitec,zet6223.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/zeitec,zet6223.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zeitec ZET6223 touchscreen controller + +description: + Zeitec ZET6223 I2C driven touchscreen controller. + +maintainers: + - Dario Binacchi + +allOf: + - $ref: touchscreen.yaml# + +properties: + compatible: + enum: + - zeitec,zet6223 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vio-supply: + description: 1.8V or 3.3V VIO supply. + + vcc-supply: + description: 3.3V VCC supply. + + touchscreen-inverted-x: true + touchscreen-inverted-y: true + touchscreen-size-x: true + touchscreen-size-y: true + touchscreen-swapped-x-y: true + +additionalProperties: false + +required: + - compatible + - reg + - interrupts + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@76 { + compatible = "zeitec,zet6223"; + reg = <0x76>; + interrupt-parent = <&pio>; + interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/zet6223.txt b/Documentation/devicetree/bindings/input/touchscreen/zet6223.txt deleted file mode 100644 index 27d55a506f18..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/zet6223.txt +++ /dev/null @@ -1,30 +0,0 @@ -Zeitec ZET6223 I2C touchscreen controller - -Required properties: -- compatible : "zeitec,zet6223" -- reg : I2C slave address of the chip (0x76) -- interrupts : interrupt specification for the zet6223 interrupt - -Optional properties: - -- vio-supply : Specification for VIO supply (1.8V or 3.3V, - depending on system interface needs). -- vcc-supply : Specification for 3.3V VCC supply. -- touchscreen-size-x : See touchscreen.txt -- touchscreen-size-y : See touchscreen.txt -- touchscreen-inverted-x : See touchscreen.txt -- touchscreen-inverted-y : See touchscreen.txt -- touchscreen-swapped-x-y : See touchscreen.txt - -Example: - -i2c@00000000 { - - zet6223: touchscreen@76 { - compatible = "zeitec,zet6223"; - reg = <0x76>; - interrupt-parent = <&pio>; - interrupts = <6 11 IRQ_TYPE_EDGE_FALLING> - }; - -}; From f6ee24913de24dbda8d49213e1a27f5e1a5204cc Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 14 Aug 2025 15:21:44 -0700 Subject: [PATCH 1680/2711] cxl: Move port register setup to when first dport appear This patch moves the port register setup to when the first dport appears via the memdev probe path. At this point, the CXL link should be established and the register access is expected to succeed. This change addresses an error message observed when PCIe hotplug is enabled on an Intel platform. The error messages "cxl portN: Couldn't locate the CXL.cache and CXL.mem capability array header" is observed for the host bridge (CHBCR) during cxl_acpi driver probe. If the cxl_acpi module probe is running before the CXL link between the endpoint device and the RP is established, then the platform may not have exposed DVSEC ID 3 and/or DVSEC ID 7 blocks which will trigger the error message. This behavior is defined by the CXL spec r3.2 9.12.3 for RPs and DSPs, however the Intel platform also added this behavior to the host bridge. This change also needs the dport enumeration to be moved to the memdev probe path in order to address the issue. This change is not a wholly contained solution by itself. [dj: Add missing var init during port alloc] Suggested-by: Dan Williams Reviewed-by: Jonathan Cameron Tested-by: Robert Richter Reviewed-by: Alison Schofield Reviewed-by: Ira Weiny Signed-off-by: Dave Jiang --- drivers/cxl/core/port.c | 17 ++++++++++++++--- drivers/cxl/cxl.h | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 18547a217f88..e0a505f78ebc 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -749,6 +749,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev, xa_init(&port->dports); xa_init(&port->endpoints); xa_init(&port->regions); + port->component_reg_phys = CXL_RESOURCE_NONE; device_initialize(dev); lockdep_set_class_and_subclass(&dev->mutex, &cxl_port_key, port->depth); @@ -867,9 +868,7 @@ static int cxl_port_add(struct cxl_port *port, if (rc) return rc; - rc = cxl_port_setup_regs(port, component_reg_phys); - if (rc) - return rc; + port->component_reg_phys = component_reg_phys; } else { rc = dev_set_name(dev, "root%d", port->id); if (rc) @@ -1200,6 +1199,18 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, cxl_debugfs_create_dport_dir(dport); + /* + * Setup port register if this is the first dport showed up. Having + * a dport also means that there is at least 1 active link. + */ + if (port->nr_dports == 1 && + port->component_reg_phys != CXL_RESOURCE_NONE) { + rc = cxl_port_setup_regs(port, port->component_reg_phys); + if (rc) + return ERR_PTR(rc); + port->component_reg_phys = CXL_RESOURCE_NONE; + } + return dport; } diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index e7f4c929785b..4784f0670f3e 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -599,6 +599,7 @@ struct cxl_dax_region { * @cdat: Cached CDAT data * @cdat_available: Should a CDAT attribute be available in sysfs * @pci_latency: Upstream latency in picoseconds + * @component_reg_phys: Physical address of component register */ struct cxl_port { struct device dev; @@ -622,6 +623,7 @@ struct cxl_port { } cdat; bool cdat_available; long pci_latency; + resource_size_t component_reg_phys; }; /** From 8a760c454da263f4b5f0f557e26141b2a3186b40 Mon Sep 17 00:00:00 2001 From: Emilio Perez Date: Mon, 18 Aug 2025 03:31:21 +0100 Subject: [PATCH 1681/2711] Documentation: PCI: Fix typos The PCIe spec uses "Requester ID", not "requestor ID". Follow the spec to avoid confusion. Signed-off-by: Emilio Perez [bhelgaas: capitalize as a hint that the spec defines this] Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250818023121.33427-1-emiliopeju@gmail.com --- Documentation/PCI/pcieaer-howto.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/PCI/pcieaer-howto.rst b/Documentation/PCI/pcieaer-howto.rst index d448efe572c8..3210c4792978 100644 --- a/Documentation/PCI/pcieaer-howto.rst +++ b/Documentation/PCI/pcieaer-howto.rst @@ -138,7 +138,7 @@ error message to the Root Port above it when it captures an error. The Root Port, upon receiving an error reporting message, internally processes and logs the error message in its AER Capability structure. Error information being logged includes storing -the error reporting agent's requestor ID into the Error Source +the error reporting agent's Requester ID into the Error Source Identification Registers and setting the error bits of the Root Error Status Register accordingly. If AER error reporting is enabled in the Root Error Command Register, the Root Port generates an interrupt when an From a9e3d5a69cf8d1a73733c52f593a3f803f576391 Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Fri, 12 Sep 2025 18:18:05 +0530 Subject: [PATCH 1682/2711] bus: mhi: host: Add support for separate controller configurations for VF and PF Implement support for separate controller configurations for both Virtual Functions (VF) and Physical Functions (PF). This enhancement allows for more flexible and efficient management of resources. The PF takes on a supervisory role and will have bootup information such as SAHARA, DIAG, and NDB (for file system sync data, etc.). VFs can handle resources associated with the main data movement of the Function are available to the SI (system image) as per PCIe SRIOV spec (rev 0.9 1.Architectural overview) Signed-off-by: Vivek Pernamitta Reviewed-by: Krishna Chaitanya Chundru Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250912-uevent_vdev_next-20250911-v4-1-fa2f6ccd301b@quicinc.com --- drivers/bus/mhi/host/pci_generic.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 4564e2528775..8a605cb3b8e1 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -34,6 +34,7 @@ /** * struct mhi_pci_dev_info - MHI PCI device specific information * @config: MHI controller configuration + * @vf_config: MHI controller configuration for Virtual function (optional) * @name: name of the PCI module * @fw: firmware path (if any) * @edl: emergency download mode firmware path (if any) @@ -47,6 +48,7 @@ */ struct mhi_pci_dev_info { const struct mhi_controller_config *config; + const struct mhi_controller_config *vf_config; const char *name; const char *fw; const char *edl; @@ -1299,9 +1301,14 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM; INIT_WORK(&mhi_pdev->recovery_work, mhi_pci_recovery_work); + + if (pdev->is_virtfn && info->vf_config) + mhi_cntrl_config = info->vf_config; + else + mhi_cntrl_config = info->config; + timer_setup(&mhi_pdev->health_check_timer, health_check, 0); - mhi_cntrl_config = info->config; mhi_cntrl = &mhi_pdev->mhi_cntrl; mhi_cntrl->cntrl_dev = &pdev->dev; From b4d01c5b9a9d2dc39f52be22809e845cc4c46f03 Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Fri, 12 Sep 2025 18:18:06 +0530 Subject: [PATCH 1683/2711] bus: mhi: host: pci_generic: Read SUBSYSTEM_VENDOR_ID for VF's to check status In SR-IOV enabled devices, reading the VF DEVICE/VENDOR ID register returns `FFFFh`, as specified in section 3.4.1.1 of the PCIe SR-IOV spec. To accurately determine device activity, read the PCIe VENDOR_ID of the Physical Function (PF) instead. Health check monitoring for Virtual Functions (VFs) has been disabled, since VFs are not physical functions and lack direct hardware control. This change prevents unnecessary CPU cycles from being consumed by VF health checks, which are both unintended and non-functional. Signed-off-by: Vivek Pernamitta Signed-off-by: Manivannan Sadhasivam Reviewed-by: Krishna Chaitanya Chundru Link: https://patch.msgid.link/20250912-uevent_vdev_next-20250911-v4-2-fa2f6ccd301b@quicinc.com --- drivers/bus/mhi/host/pci_generic.c | 34 +++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 8a605cb3b8e1..6fa16975e320 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -1082,7 +1082,7 @@ static bool mhi_pci_is_alive(struct mhi_controller *mhi_cntrl) struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev); u16 vendor = 0; - if (pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor)) + if (pci_read_config_word(pci_physfn(pdev), PCI_VENDOR_ID, &vendor)) return false; if (vendor == (u16) ~0 || vendor == 0) @@ -1193,7 +1193,9 @@ static void mhi_pci_recovery_work(struct work_struct *work) dev_warn(&pdev->dev, "device recovery started\n"); - timer_delete(&mhi_pdev->health_check_timer); + if (pdev->is_physfn) + timer_delete(&mhi_pdev->health_check_timer); + pm_runtime_forbid(&pdev->dev); /* Clean up MHI state */ @@ -1220,7 +1222,10 @@ static void mhi_pci_recovery_work(struct work_struct *work) dev_dbg(&pdev->dev, "Recovery completed\n"); set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status); - mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + + if (pdev->is_physfn) + mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + return; err_unprepare: @@ -1307,7 +1312,9 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) else mhi_cntrl_config = info->config; - timer_setup(&mhi_pdev->health_check_timer, health_check, 0); + /* Initialize health check monitor only for Physical functions */ + if (pdev->is_physfn) + timer_setup(&mhi_pdev->health_check_timer, health_check, 0); mhi_cntrl = &mhi_pdev->mhi_cntrl; @@ -1371,7 +1378,8 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status); /* start health check */ - mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + if (pdev->is_physfn) + mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); /* Allow runtime suspend only if both PME from D3Hot and M3 are supported */ if (pci_pme_capable(pdev, PCI_D3hot) && !(info->no_m3)) { @@ -1396,7 +1404,8 @@ static void mhi_pci_remove(struct pci_dev *pdev) struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev); struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; - timer_delete_sync(&mhi_pdev->health_check_timer); + if (pdev->is_physfn) + timer_delete_sync(&mhi_pdev->health_check_timer); cancel_work_sync(&mhi_pdev->recovery_work); if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) { @@ -1424,7 +1433,8 @@ static void mhi_pci_reset_prepare(struct pci_dev *pdev) dev_info(&pdev->dev, "reset\n"); - timer_delete(&mhi_pdev->health_check_timer); + if (pdev->is_physfn) + timer_delete(&mhi_pdev->health_check_timer); /* Clean up MHI state */ if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) { @@ -1469,7 +1479,8 @@ static void mhi_pci_reset_done(struct pci_dev *pdev) } set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status); - mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + if (pdev->is_physfn) + mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); } static pci_ers_result_t mhi_pci_error_detected(struct pci_dev *pdev, @@ -1534,7 +1545,9 @@ static int __maybe_unused mhi_pci_runtime_suspend(struct device *dev) if (test_and_set_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status)) return 0; - timer_delete(&mhi_pdev->health_check_timer); + if (pdev->is_physfn) + timer_delete(&mhi_pdev->health_check_timer); + cancel_work_sync(&mhi_pdev->recovery_work); if (!test_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status) || @@ -1585,7 +1598,8 @@ static int __maybe_unused mhi_pci_runtime_resume(struct device *dev) } /* Resume health check */ - mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + if (pdev->is_physfn) + mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); /* It can be a remote wakeup (no mhi runtime_get), update access time */ pm_runtime_mark_last_busy(dev); From fd6e0509d0e86059f9a1c25b0b91ef5d0021701f Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Fri, 12 Sep 2025 18:18:07 +0530 Subject: [PATCH 1684/2711] bus: mhi: host: pci_generic: Add SRIOV support pci_sriov_configure_simple() will enable or disable SR-IOV for devices that don't require any specific PF setup before enabling SR-IOV. Signed-off-by: Vivek Pernamitta Signed-off-by: Manivannan Sadhasivam Reviewed-by: Krishna Chaitanya Chundru Link: https://patch.msgid.link/20250912-uevent_vdev_next-20250911-v4-3-fa2f6ccd301b@quicinc.com --- drivers/bus/mhi/host/pci_generic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 6fa16975e320..6d0bade28826 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -1685,7 +1685,8 @@ static struct pci_driver mhi_pci_driver = { .remove = mhi_pci_remove, .shutdown = mhi_pci_shutdown, .err_handler = &mhi_pci_err_handler, - .driver.pm = &mhi_pci_pm_ops + .driver.pm = &mhi_pci_pm_ops, + .sriov_configure = pci_sriov_configure_simple, }; module_pci_driver(mhi_pci_driver); From 12543f4405887da9f3e401e708ca0ff796a7b866 Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Fri, 12 Sep 2025 18:18:08 +0530 Subject: [PATCH 1685/2711] bus: mhi: host: pci_generic: Reset QDU100 while the MHI driver is removed So, When the MHI driver is removed from the host side, it is essential to ensure a clean and stable recovery of the device. This commit introduces the following steps to achieve that: 1. Disable SR-IOV for any SR-IOV-enabled devices on the Physical Function. 2. Perform a SOC_RESET on the PF to fully reset the device. Disabling SR-IOV ensures all Virtual Functions (VFs) are properly shutdown, preventing issues during the reset process. The SOC_RESET guarantees that the PF is restored to a known good state. If soc_reset is not performed device at driver remove, device will be stuck in mission mode state and subsequent driver insert/power_up will not proceed further. Signed-off-by: Vivek Pernamitta [mani: reworded subject] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250912-uevent_vdev_next-20250911-v4-4-fa2f6ccd301b@quicinc.com --- drivers/bus/mhi/host/pci_generic.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 6d0bade28826..4de7e56d4b88 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -45,6 +45,7 @@ * @sideband_wake: Devices using dedicated sideband GPIO for wakeup instead * of inband wake support (such as sdx24) * @no_m3: M3 not supported + * @reset_on_remove: Set true for devices that require SoC during driver removal */ struct mhi_pci_dev_info { const struct mhi_controller_config *config; @@ -58,6 +59,7 @@ struct mhi_pci_dev_info { unsigned int mru_default; bool sideband_wake; bool no_m3; + bool reset_on_remove; }; #define MHI_CHANNEL_CONFIG_UL(ch_num, ch_name, el_count, ev_ring) \ @@ -300,6 +302,7 @@ static const struct mhi_pci_dev_info mhi_qcom_qdu100_info = { .dma_data_width = 32, .sideband_wake = false, .no_m3 = true, + .reset_on_remove = true, }; static const struct mhi_channel_config mhi_qcom_sa8775p_channels[] = { @@ -1027,6 +1030,7 @@ struct mhi_pci_device { struct work_struct recovery_work; struct timer_list health_check_timer; unsigned long status; + bool reset_on_remove; }; static int mhi_pci_read_reg(struct mhi_controller *mhi_cntrl, @@ -1332,6 +1336,9 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mhi_cntrl->mru = info->mru_default; mhi_cntrl->name = info->name; + if (pdev->is_physfn) + mhi_pdev->reset_on_remove = info->reset_on_remove; + if (info->edl_trigger) mhi_cntrl->edl_trigger = mhi_pci_generic_edl_trigger; @@ -1404,6 +1411,8 @@ static void mhi_pci_remove(struct pci_dev *pdev) struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev); struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; + pci_disable_sriov(pdev); + if (pdev->is_physfn) timer_delete_sync(&mhi_pdev->health_check_timer); cancel_work_sync(&mhi_pdev->recovery_work); @@ -1417,6 +1426,9 @@ static void mhi_pci_remove(struct pci_dev *pdev) if (pci_pme_capable(pdev, PCI_D3hot)) pm_runtime_get_noresume(&pdev->dev); + if (mhi_pdev->reset_on_remove) + mhi_soc_reset(mhi_cntrl); + mhi_unregister_controller(mhi_cntrl); } From aa1a0e93ed21a06acb7ca9d4a4a9fce75ea53d0c Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Fri, 12 Sep 2025 18:18:09 +0530 Subject: [PATCH 1686/2711] bus: mhi: core: Improve mhi_sync_power_up handling for SYS_ERR state Allow mhi_sync_power_up to handle SYS_ERR during power-up, reboot, or recovery. This is to avoid premature exit when MHI_PM_IN_ERROR_STATE is observed during above mentioned system states. To achieve this, treat SYS_ERR as a valid state and let its handler process the error and queue the next transition to Mission Mode instead of aborting early. Signed-off-by: Vivek Pernamitta [mani: reworded description] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250912-uevent_vdev_next-20250911-v4-5-fa2f6ccd301b@quicinc.com --- drivers/bus/mhi/host/internal.h | 2 ++ drivers/bus/mhi/host/pm.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h index d455f0bf0013..7937bb1f742c 100644 --- a/drivers/bus/mhi/host/internal.h +++ b/drivers/bus/mhi/host/internal.h @@ -170,6 +170,8 @@ enum mhi_pm_state { MHI_PM_IN_ERROR_STATE(pm_state)) #define MHI_PM_IN_SUSPEND_STATE(pm_state) (pm_state & \ (MHI_PM_M3_ENTER | MHI_PM_M3)) +#define MHI_PM_FATAL_ERROR(pm_state) ((pm_state == MHI_PM_FW_DL_ERR) || \ + (pm_state >= MHI_PM_SYS_ERR_FAIL)) #define NR_OF_CMD_RINGS 1 #define CMD_EL_PER_RING 128 diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c index 9a5ca903d758..b4ef115189b5 100644 --- a/drivers/bus/mhi/host/pm.c +++ b/drivers/bus/mhi/host/pm.c @@ -1287,7 +1287,7 @@ int mhi_sync_power_up(struct mhi_controller *mhi_cntrl) mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms; wait_event_timeout(mhi_cntrl->state_event, MHI_IN_MISSION_MODE(mhi_cntrl->ee) || - MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), + MHI_PM_FATAL_ERROR(mhi_cntrl->pm_state), msecs_to_jiffies(timeout_ms)); ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT; From e8fe3f07a357c39d429e02ca34f740692d88967a Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 19 Aug 2025 18:10:13 +0200 Subject: [PATCH 1687/2711] 9p/trans_fd: p9_fd_request: kick rx thread if EPOLLIN p9_read_work() doesn't set Rworksched and doesn't do schedule_work(m->rq) if list_empty(&m->req_list). However, if the pipe is full, we need to read more data and this used to work prior to commit aaec5a95d59615 ("pipe_read: don't wake up the writer if the pipe is still full"). p9_read_work() does p9_fd_read() -> ... -> anon_pipe_read() which (before the commit above) triggered the unnecessary wakeup. This wakeup calls p9_pollwake() which kicks p9_poll_workfn() -> p9_poll_mux(), p9_poll_mux() will notice EPOLLIN and schedule_work(&m->rq). This no longer happens after the optimization above, change p9_fd_request() to use p9_poll_mux() instead of only checking for EPOLLOUT. Reported-by: syzbot+d1b5dace43896bc386c3@syzkaller.appspotmail.com Tested-by: syzbot+d1b5dace43896bc386c3@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/68a2de8f.050a0220.e29e5.0097.GAE@google.com/ Link: https://lore.kernel.org/all/67dedd2f.050a0220.31a16b.003f.GAE@google.com/ Co-developed-by: K Prateek Nayak Signed-off-by: K Prateek Nayak Signed-off-by: Oleg Nesterov Tested-by: K Prateek Nayak Message-ID: <20250819161013.GB11345@redhat.com> Signed-off-by: Dominique Martinet --- net/9p/trans_fd.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 8992d8bebbdd..a516745f732f 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -666,7 +666,6 @@ static void p9_poll_mux(struct p9_conn *m) static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) { - __poll_t n; int err; struct p9_trans_fd *ts = client->trans; struct p9_conn *m = &ts->conn; @@ -686,13 +685,7 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) list_add_tail(&req->req_list, &m->unsent_req_list); spin_unlock(&m->req_lock); - if (test_and_clear_bit(Wpending, &m->wsched)) - n = EPOLLOUT; - else - n = p9_fd_poll(m->client, NULL, NULL); - - if (n & EPOLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) - schedule_work(&m->wq); + p9_poll_mux(m); return 0; } From eafedbc7c050c44744fbdf80bdf3315e860b7513 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 19 Sep 2025 06:42:07 +0000 Subject: [PATCH 1688/2711] rust_binder: add Rust Binder driver We're generally not proponents of rewrites (nasty uncomfortable things that make you late for dinner!). So why rewrite Binder? Binder has been evolving over the past 15+ years to meet the evolving needs of Android. Its responsibilities, expectations, and complexity have grown considerably during that time. While we expect Binder to continue to evolve along with Android, there are a number of factors that currently constrain our ability to develop/maintain it. Briefly those are: 1. Complexity: Binder is at the intersection of everything in Android and fulfills many responsibilities beyond IPC. It has become many things to many people, and due to its many features and their interactions with each other, its complexity is quite high. In just 6kLOC it must deliver transactions to the right threads. It must correctly parse and translate the contents of transactions, which can contain several objects of different types (e.g., pointers, fds) that can interact with each other. It controls the size of thread pools in userspace, and ensures that transactions are assigned to threads in ways that avoid deadlocks where the threadpool has run out of threads. It must track refcounts of objects that are shared by several processes by forwarding refcount changes between the processes correctly. It must handle numerous error scenarios and it combines/nests 13 different locks, 7 reference counters, and atomic variables. Finally, It must do all of this as fast and efficiently as possible. Minor performance regressions can cause a noticeably degraded user experience. 2. Things to improve: Thousand-line functions [1], error-prone error handling [2], and confusing structure can occur as a code base grows organically. After more than a decade of development, this codebase could use an overhaul. [1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/android/binder.c?h=v6.5#n2896 [2]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/android/binder.c?h=v6.5#n3658 3. Security critical: Binder is a critical part of Android's sandboxing strategy. Even Android's most de-privileged sandboxes (e.g. the Chrome renderer, or SW Codec) have direct access to Binder. More than just about any other component, it's important that Binder provide robust security, and itself be robust against security vulnerabilities. It's #1 (high complexity) that has made continuing to evolve Binder and resolving #2 (tech debt) exceptionally difficult without causing #3 (security issues). For Binder to continue to meet Android's needs, we need better ways to manage (and reduce!) complexity without increasing the risk. The biggest change is obviously the choice of programming language. We decided to use Rust because it directly addresses a number of the challenges within Binder that we have faced during the last years. It prevents mistakes with ref counting, locking, bounds checking, and also does a lot to reduce the complexity of error handling. Additionally, we've been able to use the more expressive type system to encode the ownership semantics of the various structs and pointers, which takes the complexity of managing object lifetimes out of the hands of the programmer, reducing the risk of use-after-frees and similar problems. Rust has many different pointer types that it uses to encode ownership semantics into the type system, and this is probably one of the most important aspects of how it helps in Binder. The Binder driver has a lot of different objects that have complex ownership semantics; some pointers own a refcount, some pointers have exclusive ownership, and some pointers just reference the object and it is kept alive in some other manner. With Rust, we can use a different pointer type for each kind of pointer, which enables the compiler to enforce that the ownership semantics are implemented correctly. Another useful feature is Rust's error handling. Rust allows for more simplified error handling with features such as destructors, and you get compilation failures if errors are not properly handled. This means that even though Rust requires you to spend more lines of code than C on things such as writing down invariants that are left implicit in C, the Rust driver is still slightly smaller than C binder: Rust is 5.5kLOC and C is 5.8kLOC. (These numbers are excluding blank lines, comments, binderfs, and any debugging facilities in C that are not yet implemented in the Rust driver. The numbers include abstractions in rust/kernel/ that are unlikely to be used by other drivers than Binder.) Although this rewrite completely rethinks how the code is structured and how assumptions are enforced, we do not fundamentally change *how* the driver does the things it does. A lot of careful thought has gone into the existing design. The rewrite is aimed rather at improving code health, structure, readability, robustness, security, maintainability and extensibility. We also include more inline documentation, and improve how assumptions in the code are enforced. Furthermore, all unsafe code is annotated with a SAFETY comment that explains why it is correct. We have left the binderfs filesystem component in C. Rewriting it in Rust would be a large amount of work and requires a lot of bindings to the file system interfaces. Binderfs has not historically had the same challenges with security and complexity, so rewriting binderfs seems to have lower value than the rest of Binder. Correctness and feature parity ------------------------------ Rust binder passes all tests that validate the correctness of Binder in the Android Open Source Project. We can boot a device, and run a variety of apps and functionality without issues. We have performed this both on the Cuttlefish Android emulator device, and on a Pixel 6 Pro. As for feature parity, Rust binder currently implements all features that C binder supports, with the exception of some debugging facilities. The missing debugging facilities will be added before we submit the Rust implementation upstream. Tracepoints ----------- I did not include all of the tracepoints as I felt that the mechansim for making C access fields of Rust structs should be discussed on list separately. I also did not include the support for building Rust Binder as a module since that requires exporting a bunch of additional symbols on the C side. Original RFC Link with old benchmark numbers: https://lore.kernel.org/r/20231101-rust-binder-v1-0-08ba9197f637@google.com Co-developed-by: Wedson Almeida Filho Signed-off-by: Wedson Almeida Filho Co-developed-by: Matt Gilbride Signed-off-by: Matt Gilbride Acked-by: Carlos Llamas Acked-by: Paul Moore Signed-off-by: Alice Ryhl Link: https://lore.kernel.org/r/20250919-rust-binder-v2-1-a384b09f28dd@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/Kconfig | 15 +- drivers/android/Makefile | 1 + drivers/android/binder/Makefile | 9 + drivers/android/binder/allocation.rs | 602 ++++++ drivers/android/binder/context.rs | 180 ++ drivers/android/binder/deferred_close.rs | 204 ++ drivers/android/binder/defs.rs | 182 ++ drivers/android/binder/error.rs | 99 + drivers/android/binder/freeze.rs | 388 ++++ drivers/android/binder/node.rs | 1131 +++++++++++ drivers/android/binder/node/wrapper.rs | 78 + drivers/android/binder/page_range.rs | 734 +++++++ drivers/android/binder/page_range_helper.c | 24 + drivers/android/binder/page_range_helper.h | 15 + drivers/android/binder/process.rs | 1696 +++++++++++++++++ drivers/android/binder/range_alloc/array.rs | 251 +++ drivers/android/binder/range_alloc/mod.rs | 329 ++++ drivers/android/binder/range_alloc/tree.rs | 488 +++++ drivers/android/binder/rust_binder.h | 23 + drivers/android/binder/rust_binder_events.c | 59 + drivers/android/binder/rust_binder_events.h | 36 + drivers/android/binder/rust_binder_internal.h | 87 + drivers/android/binder/rust_binder_main.rs | 627 ++++++ drivers/android/binder/rust_binderfs.c | 850 +++++++++ drivers/android/binder/stats.rs | 89 + drivers/android/binder/thread.rs | 1596 ++++++++++++++++ drivers/android/binder/trace.rs | 16 + drivers/android/binder/transaction.rs | 456 +++++ include/uapi/linux/android/binder.h | 2 +- rust/bindings/bindings_helper.h | 8 + rust/helpers/binder.c | 26 + rust/helpers/helpers.c | 1 + rust/helpers/page.c | 8 + rust/helpers/security.c | 24 + rust/kernel/cred.rs | 6 + rust/kernel/page.rs | 6 + rust/kernel/security.rs | 37 + rust/uapi/uapi_helper.h | 1 + 38 files changed, 10382 insertions(+), 2 deletions(-) create mode 100644 drivers/android/binder/Makefile create mode 100644 drivers/android/binder/allocation.rs create mode 100644 drivers/android/binder/context.rs create mode 100644 drivers/android/binder/deferred_close.rs create mode 100644 drivers/android/binder/defs.rs create mode 100644 drivers/android/binder/error.rs create mode 100644 drivers/android/binder/freeze.rs create mode 100644 drivers/android/binder/node.rs create mode 100644 drivers/android/binder/node/wrapper.rs create mode 100644 drivers/android/binder/page_range.rs create mode 100644 drivers/android/binder/page_range_helper.c create mode 100644 drivers/android/binder/page_range_helper.h create mode 100644 drivers/android/binder/process.rs create mode 100644 drivers/android/binder/range_alloc/array.rs create mode 100644 drivers/android/binder/range_alloc/mod.rs create mode 100644 drivers/android/binder/range_alloc/tree.rs create mode 100644 drivers/android/binder/rust_binder.h create mode 100644 drivers/android/binder/rust_binder_events.c create mode 100644 drivers/android/binder/rust_binder_events.h create mode 100644 drivers/android/binder/rust_binder_internal.h create mode 100644 drivers/android/binder/rust_binder_main.rs create mode 100644 drivers/android/binder/rust_binderfs.c create mode 100644 drivers/android/binder/stats.rs create mode 100644 drivers/android/binder/thread.rs create mode 100644 drivers/android/binder/trace.rs create mode 100644 drivers/android/binder/transaction.rs create mode 100644 rust/helpers/binder.c diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 75af3cf472c8..e2e402c9d175 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -14,6 +14,19 @@ config ANDROID_BINDER_IPC Android process, using Binder to identify, invoke and pass arguments between said processes. +config ANDROID_BINDER_IPC_RUST + bool "Rust version of Android Binder IPC Driver" + depends on RUST && MMU && !ANDROID_BINDER_IPC + help + This enables the Rust implementation of the Binder driver. + + Binder is used in Android for both communication between processes, + and remote method invocation. + + This means one Android process can call a method/routine in another + Android process, using Binder to identify, invoke and pass arguments + between said processes. + config ANDROID_BINDERFS bool "Android Binderfs filesystem" depends on ANDROID_BINDER_IPC @@ -28,7 +41,7 @@ config ANDROID_BINDERFS config ANDROID_BINDER_DEVICES string "Android Binder devices" - depends on ANDROID_BINDER_IPC + depends on ANDROID_BINDER_IPC || ANDROID_BINDER_IPC_RUST default "binder,hwbinder,vndbinder" help Default value for the binder.devices parameter. diff --git a/drivers/android/Makefile b/drivers/android/Makefile index f422f91e026b..e0c650d3898e 100644 --- a/drivers/android/Makefile +++ b/drivers/android/Makefile @@ -4,3 +4,4 @@ ccflags-y += -I$(src) # needed for trace events obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o binder_netlink.o obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += tests/ +obj-$(CONFIG_ANDROID_BINDER_IPC_RUST) += binder/ diff --git a/drivers/android/binder/Makefile b/drivers/android/binder/Makefile new file mode 100644 index 000000000000..09eabb527fa0 --- /dev/null +++ b/drivers/android/binder/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +ccflags-y += -I$(src) # needed for trace events + +obj-$(CONFIG_ANDROID_BINDER_IPC_RUST) += rust_binder.o +rust_binder-y := \ + rust_binder_main.o \ + rust_binderfs.o \ + rust_binder_events.o \ + page_range_helper.o diff --git a/drivers/android/binder/allocation.rs b/drivers/android/binder/allocation.rs new file mode 100644 index 000000000000..7f65a9c3a0e5 --- /dev/null +++ b/drivers/android/binder/allocation.rs @@ -0,0 +1,602 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use core::mem::{size_of, size_of_val, MaybeUninit}; +use core::ops::Range; + +use kernel::{ + bindings, + fs::file::{File, FileDescriptorReservation}, + prelude::*, + sync::{aref::ARef, Arc}, + transmute::{AsBytes, FromBytes}, + uaccess::UserSliceReader, + uapi, +}; + +use crate::{ + deferred_close::DeferredFdCloser, + defs::*, + node::{Node, NodeRef}, + process::Process, + DArc, +}; + +#[derive(Default)] +pub(crate) struct AllocationInfo { + /// Range within the allocation where we can find the offsets to the object descriptors. + pub(crate) offsets: Option>, + /// The target node of the transaction this allocation is associated to. + /// Not set for replies. + pub(crate) target_node: Option, + /// When this allocation is dropped, call `pending_oneway_finished` on the node. + /// + /// This is used to serialize oneway transaction on the same node. Binder guarantees that + /// oneway transactions to the same node are delivered sequentially in the order they are sent. + pub(crate) oneway_node: Option>, + /// Zero the data in the buffer on free. + pub(crate) clear_on_free: bool, + /// List of files embedded in this transaction. + file_list: FileList, +} + +/// Represents an allocation that the kernel is currently using. +/// +/// When allocations are idle, the range allocator holds the data related to them. +/// +/// # Invariants +/// +/// This allocation corresponds to an allocation in the range allocator, so the relevant pages are +/// marked in use in the page range. +pub(crate) struct Allocation { + pub(crate) offset: usize, + size: usize, + pub(crate) ptr: usize, + pub(crate) process: Arc, + allocation_info: Option, + free_on_drop: bool, + pub(crate) oneway_spam_detected: bool, + #[allow(dead_code)] + pub(crate) debug_id: usize, +} + +impl Allocation { + pub(crate) fn new( + process: Arc, + debug_id: usize, + offset: usize, + size: usize, + ptr: usize, + oneway_spam_detected: bool, + ) -> Self { + Self { + process, + offset, + size, + ptr, + debug_id, + oneway_spam_detected, + allocation_info: None, + free_on_drop: true, + } + } + + fn size_check(&self, offset: usize, size: usize) -> Result { + let overflow_fail = offset.checked_add(size).is_none(); + let cmp_size_fail = offset.wrapping_add(size) > self.size; + if overflow_fail || cmp_size_fail { + return Err(EFAULT); + } + Ok(()) + } + + pub(crate) fn copy_into( + &self, + reader: &mut UserSliceReader, + offset: usize, + size: usize, + ) -> Result { + self.size_check(offset, size)?; + + // SAFETY: While this object exists, the range allocator will keep the range allocated, and + // in turn, the pages will be marked as in use. + unsafe { + self.process + .pages + .copy_from_user_slice(reader, self.offset + offset, size) + } + } + + pub(crate) fn read(&self, offset: usize) -> Result { + self.size_check(offset, size_of::())?; + + // SAFETY: While this object exists, the range allocator will keep the range allocated, and + // in turn, the pages will be marked as in use. + unsafe { self.process.pages.read(self.offset + offset) } + } + + pub(crate) fn write(&self, offset: usize, obj: &T) -> Result { + self.size_check(offset, size_of_val::(obj))?; + + // SAFETY: While this object exists, the range allocator will keep the range allocated, and + // in turn, the pages will be marked as in use. + unsafe { self.process.pages.write(self.offset + offset, obj) } + } + + pub(crate) fn fill_zero(&self) -> Result { + // SAFETY: While this object exists, the range allocator will keep the range allocated, and + // in turn, the pages will be marked as in use. + unsafe { self.process.pages.fill_zero(self.offset, self.size) } + } + + pub(crate) fn keep_alive(mut self) { + self.process + .buffer_make_freeable(self.offset, self.allocation_info.take()); + self.free_on_drop = false; + } + + pub(crate) fn set_info(&mut self, info: AllocationInfo) { + self.allocation_info = Some(info); + } + + pub(crate) fn get_or_init_info(&mut self) -> &mut AllocationInfo { + self.allocation_info.get_or_insert_with(Default::default) + } + + pub(crate) fn set_info_offsets(&mut self, offsets: Range) { + self.get_or_init_info().offsets = Some(offsets); + } + + pub(crate) fn set_info_oneway_node(&mut self, oneway_node: DArc) { + self.get_or_init_info().oneway_node = Some(oneway_node); + } + + pub(crate) fn set_info_clear_on_drop(&mut self) { + self.get_or_init_info().clear_on_free = true; + } + + pub(crate) fn set_info_target_node(&mut self, target_node: NodeRef) { + self.get_or_init_info().target_node = Some(target_node); + } + + /// Reserve enough space to push at least `num_fds` fds. + pub(crate) fn info_add_fd_reserve(&mut self, num_fds: usize) -> Result { + self.get_or_init_info() + .file_list + .files_to_translate + .reserve(num_fds, GFP_KERNEL)?; + + Ok(()) + } + + pub(crate) fn info_add_fd( + &mut self, + file: ARef, + buffer_offset: usize, + close_on_free: bool, + ) -> Result { + self.get_or_init_info().file_list.files_to_translate.push( + FileEntry { + file, + buffer_offset, + close_on_free, + }, + GFP_KERNEL, + )?; + + Ok(()) + } + + pub(crate) fn set_info_close_on_free(&mut self, cof: FdsCloseOnFree) { + self.get_or_init_info().file_list.close_on_free = cof.0; + } + + pub(crate) fn translate_fds(&mut self) -> Result { + let file_list = match self.allocation_info.as_mut() { + Some(info) => &mut info.file_list, + None => return Ok(TranslatedFds::new()), + }; + + let files = core::mem::take(&mut file_list.files_to_translate); + + let num_close_on_free = files.iter().filter(|entry| entry.close_on_free).count(); + let mut close_on_free = KVec::with_capacity(num_close_on_free, GFP_KERNEL)?; + + let mut reservations = KVec::with_capacity(files.len(), GFP_KERNEL)?; + for file_info in files { + let res = FileDescriptorReservation::get_unused_fd_flags(bindings::O_CLOEXEC)?; + let fd = res.reserved_fd(); + self.write::(file_info.buffer_offset, &fd)?; + + reservations.push( + Reservation { + res, + file: file_info.file, + }, + GFP_KERNEL, + )?; + if file_info.close_on_free { + close_on_free.push(fd, GFP_KERNEL)?; + } + } + + Ok(TranslatedFds { + reservations, + close_on_free: FdsCloseOnFree(close_on_free), + }) + } + + /// Should the looper return to userspace when freeing this allocation? + pub(crate) fn looper_need_return_on_free(&self) -> bool { + // Closing fds involves pushing task_work for execution when we return to userspace. Hence, + // we should return to userspace asap if we are closing fds. + match self.allocation_info { + Some(ref info) => !info.file_list.close_on_free.is_empty(), + None => false, + } + } +} + +impl Drop for Allocation { + fn drop(&mut self) { + if !self.free_on_drop { + return; + } + + if let Some(mut info) = self.allocation_info.take() { + if let Some(oneway_node) = info.oneway_node.as_ref() { + oneway_node.pending_oneway_finished(); + } + + info.target_node = None; + + if let Some(offsets) = info.offsets.clone() { + let view = AllocationView::new(self, offsets.start); + for i in offsets.step_by(size_of::()) { + if view.cleanup_object(i).is_err() { + pr_warn!("Error cleaning up object at offset {}\n", i) + } + } + } + + for &fd in &info.file_list.close_on_free { + let closer = match DeferredFdCloser::new(GFP_KERNEL) { + Ok(closer) => closer, + Err(kernel::alloc::AllocError) => { + // Ignore allocation failures. + break; + } + }; + + // Here, we ignore errors. The operation can fail if the fd is not valid, or if the + // method is called from a kthread. However, this is always called from a syscall, + // so the latter case cannot happen, and we don't care about the first case. + let _ = closer.close_fd(fd); + } + + if info.clear_on_free { + if let Err(e) = self.fill_zero() { + pr_warn!("Failed to clear data on free: {:?}", e); + } + } + } + + self.process.buffer_raw_free(self.ptr); + } +} + +/// A wrapper around `Allocation` that is being created. +/// +/// If the allocation is destroyed while wrapped in this wrapper, then the allocation will be +/// considered to be part of a failed transaction. Successful transactions avoid that by calling +/// `success`, which skips the destructor. +#[repr(transparent)] +pub(crate) struct NewAllocation(pub(crate) Allocation); + +impl NewAllocation { + pub(crate) fn success(self) -> Allocation { + // This skips the destructor. + // + // SAFETY: This type is `#[repr(transparent)]`, so the layout matches. + unsafe { core::mem::transmute(self) } + } +} + +impl core::ops::Deref for NewAllocation { + type Target = Allocation; + fn deref(&self) -> &Allocation { + &self.0 + } +} + +impl core::ops::DerefMut for NewAllocation { + fn deref_mut(&mut self) -> &mut Allocation { + &mut self.0 + } +} + +/// A view into the beginning of an allocation. +/// +/// All attempts to read or write outside of the view will fail. To intentionally access outside of +/// this view, use the `alloc` field of this struct directly. +pub(crate) struct AllocationView<'a> { + pub(crate) alloc: &'a mut Allocation, + limit: usize, +} + +impl<'a> AllocationView<'a> { + pub(crate) fn new(alloc: &'a mut Allocation, limit: usize) -> Self { + AllocationView { alloc, limit } + } + + pub(crate) fn read(&self, offset: usize) -> Result { + if offset.checked_add(size_of::()).ok_or(EINVAL)? > self.limit { + return Err(EINVAL); + } + self.alloc.read(offset) + } + + pub(crate) fn write(&self, offset: usize, obj: &T) -> Result { + if offset.checked_add(size_of::()).ok_or(EINVAL)? > self.limit { + return Err(EINVAL); + } + self.alloc.write(offset, obj) + } + + pub(crate) fn copy_into( + &self, + reader: &mut UserSliceReader, + offset: usize, + size: usize, + ) -> Result { + if offset.checked_add(size).ok_or(EINVAL)? > self.limit { + return Err(EINVAL); + } + self.alloc.copy_into(reader, offset, size) + } + + pub(crate) fn transfer_binder_object( + &self, + offset: usize, + obj: &uapi::flat_binder_object, + strong: bool, + node_ref: NodeRef, + ) -> Result { + let mut newobj = FlatBinderObject::default(); + let node = node_ref.node.clone(); + if Arc::ptr_eq(&node_ref.node.owner, &self.alloc.process) { + // The receiving process is the owner of the node, so send it a binder object (instead + // of a handle). + let (ptr, cookie) = node.get_id(); + newobj.hdr.type_ = if strong { + BINDER_TYPE_BINDER + } else { + BINDER_TYPE_WEAK_BINDER + }; + newobj.flags = obj.flags; + newobj.__bindgen_anon_1.binder = ptr as _; + newobj.cookie = cookie as _; + self.write(offset, &newobj)?; + // Increment the user ref count on the node. It will be decremented as part of the + // destruction of the buffer, when we see a binder or weak-binder object. + node.update_refcount(true, 1, strong); + } else { + // The receiving process is different from the owner, so we need to insert a handle to + // the binder object. + let handle = self + .alloc + .process + .as_arc_borrow() + .insert_or_update_handle(node_ref, false)?; + newobj.hdr.type_ = if strong { + BINDER_TYPE_HANDLE + } else { + BINDER_TYPE_WEAK_HANDLE + }; + newobj.flags = obj.flags; + newobj.__bindgen_anon_1.handle = handle; + if self.write(offset, &newobj).is_err() { + // Decrement ref count on the handle we just created. + let _ = self + .alloc + .process + .as_arc_borrow() + .update_ref(handle, false, strong); + return Err(EINVAL); + } + } + + Ok(()) + } + + fn cleanup_object(&self, index_offset: usize) -> Result { + let offset = self.alloc.read(index_offset)?; + let header = self.read::(offset)?; + match header.type_ { + BINDER_TYPE_WEAK_BINDER | BINDER_TYPE_BINDER => { + let obj = self.read::(offset)?; + let strong = header.type_ == BINDER_TYPE_BINDER; + // SAFETY: The type is `BINDER_TYPE_{WEAK_}BINDER`, so the `binder` field is + // populated. + let ptr = unsafe { obj.__bindgen_anon_1.binder }; + let cookie = obj.cookie; + self.alloc.process.update_node(ptr, cookie, strong); + Ok(()) + } + BINDER_TYPE_WEAK_HANDLE | BINDER_TYPE_HANDLE => { + let obj = self.read::(offset)?; + let strong = header.type_ == BINDER_TYPE_HANDLE; + // SAFETY: The type is `BINDER_TYPE_{WEAK_}HANDLE`, so the `handle` field is + // populated. + let handle = unsafe { obj.__bindgen_anon_1.handle }; + self.alloc + .process + .as_arc_borrow() + .update_ref(handle, false, strong) + } + _ => Ok(()), + } + } +} + +/// A binder object as it is serialized. +/// +/// # Invariants +/// +/// All bytes must be initialized, and the value of `self.hdr.type_` must be one of the allowed +/// types. +#[repr(C)] +pub(crate) union BinderObject { + hdr: uapi::binder_object_header, + fbo: uapi::flat_binder_object, + fdo: uapi::binder_fd_object, + bbo: uapi::binder_buffer_object, + fdao: uapi::binder_fd_array_object, +} + +/// A view into a `BinderObject` that can be used in a match statement. +pub(crate) enum BinderObjectRef<'a> { + Binder(&'a mut uapi::flat_binder_object), + Handle(&'a mut uapi::flat_binder_object), + Fd(&'a mut uapi::binder_fd_object), + Ptr(&'a mut uapi::binder_buffer_object), + Fda(&'a mut uapi::binder_fd_array_object), +} + +impl BinderObject { + pub(crate) fn read_from(reader: &mut UserSliceReader) -> Result { + let object = Self::read_from_inner(|slice| { + let read_len = usize::min(slice.len(), reader.len()); + reader.clone_reader().read_slice(&mut slice[..read_len])?; + Ok(()) + })?; + + // If we used a object type smaller than the largest object size, then we've read more + // bytes than we needed to. However, we used `.clone_reader()` to avoid advancing the + // original reader. Now, we call `skip` so that the caller's reader is advanced by the + // right amount. + // + // The `skip` call fails if the reader doesn't have `size` bytes available. This could + // happen if the type header corresponds to an object type that is larger than the rest of + // the reader. + // + // Any extra bytes beyond the size of the object are inaccessible after this call, so + // reading them again from the `reader` later does not result in TOCTOU bugs. + reader.skip(object.size())?; + + Ok(object) + } + + /// Use the provided reader closure to construct a `BinderObject`. + /// + /// The closure should write the bytes for the object into the provided slice. + pub(crate) fn read_from_inner(reader: R) -> Result + where + R: FnOnce(&mut [u8; size_of::()]) -> Result<()>, + { + let mut obj = MaybeUninit::::zeroed(); + + // SAFETY: The lengths of `BinderObject` and `[u8; size_of::()]` are equal, + // and the byte array has an alignment requirement of one, so the pointer cast is okay. + // Additionally, `obj` was initialized to zeros, so the byte array will not be + // uninitialized. + (reader)(unsafe { &mut *obj.as_mut_ptr().cast() })?; + + // SAFETY: The entire object is initialized, so accessing this field is safe. + let type_ = unsafe { obj.assume_init_ref().hdr.type_ }; + if Self::type_to_size(type_).is_none() { + // The value of `obj.hdr_type_` was invalid. + return Err(EINVAL); + } + + // SAFETY: All bytes are initialized (since we zeroed them at the start) and we checked + // that `self.hdr.type_` is one of the allowed types, so the type invariants are satisfied. + unsafe { Ok(obj.assume_init()) } + } + + pub(crate) fn as_ref(&mut self) -> BinderObjectRef<'_> { + use BinderObjectRef::*; + // SAFETY: The constructor ensures that all bytes of `self` are initialized, and all + // variants of this union accept all initialized bit patterns. + unsafe { + match self.hdr.type_ { + BINDER_TYPE_WEAK_BINDER | BINDER_TYPE_BINDER => Binder(&mut self.fbo), + BINDER_TYPE_WEAK_HANDLE | BINDER_TYPE_HANDLE => Handle(&mut self.fbo), + BINDER_TYPE_FD => Fd(&mut self.fdo), + BINDER_TYPE_PTR => Ptr(&mut self.bbo), + BINDER_TYPE_FDA => Fda(&mut self.fdao), + // SAFETY: By the type invariant, the value of `self.hdr.type_` cannot have any + // other value than the ones checked above. + _ => core::hint::unreachable_unchecked(), + } + } + } + + pub(crate) fn size(&self) -> usize { + // SAFETY: The entire object is initialized, so accessing this field is safe. + let type_ = unsafe { self.hdr.type_ }; + + // SAFETY: The type invariants guarantee that the type field is correct. + unsafe { Self::type_to_size(type_).unwrap_unchecked() } + } + + fn type_to_size(type_: u32) -> Option { + match type_ { + BINDER_TYPE_WEAK_BINDER => Some(size_of::()), + BINDER_TYPE_BINDER => Some(size_of::()), + BINDER_TYPE_WEAK_HANDLE => Some(size_of::()), + BINDER_TYPE_HANDLE => Some(size_of::()), + BINDER_TYPE_FD => Some(size_of::()), + BINDER_TYPE_PTR => Some(size_of::()), + BINDER_TYPE_FDA => Some(size_of::()), + _ => None, + } + } +} + +#[derive(Default)] +struct FileList { + files_to_translate: KVec, + close_on_free: KVec, +} + +struct FileEntry { + /// The file for which a descriptor will be created in the recipient process. + file: ARef, + /// The offset in the buffer where the file descriptor is stored. + buffer_offset: usize, + /// Whether this fd should be closed when the allocation is freed. + close_on_free: bool, +} + +pub(crate) struct TranslatedFds { + reservations: KVec, + /// If commit is called, then these fds should be closed. (If commit is not called, then they + /// shouldn't be closed.) + close_on_free: FdsCloseOnFree, +} + +struct Reservation { + res: FileDescriptorReservation, + file: ARef, +} + +impl TranslatedFds { + pub(crate) fn new() -> Self { + Self { + reservations: KVec::new(), + close_on_free: FdsCloseOnFree(KVec::new()), + } + } + + pub(crate) fn commit(self) -> FdsCloseOnFree { + for entry in self.reservations { + entry.res.fd_install(entry.file); + } + + self.close_on_free + } +} + +pub(crate) struct FdsCloseOnFree(KVec); diff --git a/drivers/android/binder/context.rs b/drivers/android/binder/context.rs new file mode 100644 index 000000000000..3d135ec03ca7 --- /dev/null +++ b/drivers/android/binder/context.rs @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use kernel::{ + error::Error, + list::{List, ListArc, ListLinks}, + prelude::*, + security, + str::{CStr, CString}, + sync::{Arc, Mutex}, + task::Kuid, +}; + +use crate::{error::BinderError, node::NodeRef, process::Process}; + +kernel::sync::global_lock! { + // SAFETY: We call `init` in the module initializer, so it's initialized before first use. + pub(crate) unsafe(uninit) static CONTEXTS: Mutex = ContextList { + list: List::new(), + }; +} + +pub(crate) struct ContextList { + list: List, +} + +pub(crate) fn get_all_contexts() -> Result>> { + let lock = CONTEXTS.lock(); + + let count = lock.list.iter().count(); + + let mut ctxs = KVec::with_capacity(count, GFP_KERNEL)?; + for ctx in &lock.list { + ctxs.push(Arc::from(ctx), GFP_KERNEL)?; + } + Ok(ctxs) +} + +/// This struct keeps track of the processes using this context, and which process is the context +/// manager. +struct Manager { + node: Option, + uid: Option, + all_procs: List, +} + +/// There is one context per binder file (/dev/binder, /dev/hwbinder, etc) +#[pin_data] +pub(crate) struct Context { + #[pin] + manager: Mutex, + pub(crate) name: CString, + #[pin] + links: ListLinks, +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<0> for Context { untracked; } +} +kernel::list::impl_list_item! { + impl ListItem<0> for Context { + using ListLinks { self.links }; + } +} + +impl Context { + pub(crate) fn new(name: &CStr) -> Result> { + let name = CString::try_from(name)?; + let list_ctx = ListArc::pin_init::( + try_pin_init!(Context { + name, + links <- ListLinks::new(), + manager <- kernel::new_mutex!(Manager { + all_procs: List::new(), + node: None, + uid: None, + }, "Context::manager"), + }), + GFP_KERNEL, + )?; + + let ctx = list_ctx.clone_arc(); + CONTEXTS.lock().list.push_back(list_ctx); + + Ok(ctx) + } + + /// Called when the file for this context is unlinked. + /// + /// No-op if called twice. + pub(crate) fn deregister(&self) { + // SAFETY: We never add the context to any other linked list than this one, so it is either + // in this list, or not in any list. + unsafe { CONTEXTS.lock().list.remove(self) }; + } + + pub(crate) fn register_process(self: &Arc, proc: ListArc) { + if !Arc::ptr_eq(self, &proc.ctx) { + pr_err!("Context::register_process called on the wrong context."); + return; + } + self.manager.lock().all_procs.push_back(proc); + } + + pub(crate) fn deregister_process(self: &Arc, proc: &Process) { + if !Arc::ptr_eq(self, &proc.ctx) { + pr_err!("Context::deregister_process called on the wrong context."); + return; + } + // SAFETY: We just checked that this is the right list. + unsafe { self.manager.lock().all_procs.remove(proc) }; + } + + pub(crate) fn set_manager_node(&self, node_ref: NodeRef) -> Result { + let mut manager = self.manager.lock(); + if manager.node.is_some() { + pr_warn!("BINDER_SET_CONTEXT_MGR already set"); + return Err(EBUSY); + } + security::binder_set_context_mgr(&node_ref.node.owner.cred)?; + + // If the context manager has been set before, ensure that we use the same euid. + let caller_uid = Kuid::current_euid(); + if let Some(ref uid) = manager.uid { + if *uid != caller_uid { + return Err(EPERM); + } + } + + manager.node = Some(node_ref); + manager.uid = Some(caller_uid); + Ok(()) + } + + pub(crate) fn unset_manager_node(&self) { + let node_ref = self.manager.lock().node.take(); + drop(node_ref); + } + + pub(crate) fn get_manager_node(&self, strong: bool) -> Result { + self.manager + .lock() + .node + .as_ref() + .ok_or_else(BinderError::new_dead)? + .clone(strong) + .map_err(BinderError::from) + } + + pub(crate) fn for_each_proc(&self, mut func: F) + where + F: FnMut(&Process), + { + let lock = self.manager.lock(); + for proc in &lock.all_procs { + func(&proc); + } + } + + pub(crate) fn get_all_procs(&self) -> Result>> { + let lock = self.manager.lock(); + let count = lock.all_procs.iter().count(); + + let mut procs = KVec::with_capacity(count, GFP_KERNEL)?; + for proc in &lock.all_procs { + procs.push(Arc::from(proc), GFP_KERNEL)?; + } + Ok(procs) + } + + pub(crate) fn get_procs_with_pid(&self, pid: i32) -> Result>> { + let orig = self.get_all_procs()?; + let mut backing = KVec::with_capacity(orig.len(), GFP_KERNEL)?; + for proc in orig.into_iter().filter(|proc| proc.task.pid() == pid) { + backing.push(proc, GFP_KERNEL)?; + } + Ok(backing) + } +} diff --git a/drivers/android/binder/deferred_close.rs b/drivers/android/binder/deferred_close.rs new file mode 100644 index 000000000000..ac895c04d0cb --- /dev/null +++ b/drivers/android/binder/deferred_close.rs @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! Logic for closing files in a deferred manner. +//! +//! This file could make sense to have in `kernel::fs`, but it was rejected for being too +//! Binder-specific. + +use core::mem::MaybeUninit; +use kernel::{ + alloc::{AllocError, Flags}, + bindings, + prelude::*, +}; + +/// Helper used for closing file descriptors in a way that is safe even if the file is currently +/// held using `fdget`. +/// +/// Additional motivation can be found in commit 80cd795630d6 ("binder: fix use-after-free due to +/// ksys_close() during fdget()") and in the comments on `binder_do_fd_close`. +pub(crate) struct DeferredFdCloser { + inner: KBox, +} + +/// SAFETY: This just holds an allocation with no real content, so there's no safety issue with +/// moving it across threads. +unsafe impl Send for DeferredFdCloser {} +/// SAFETY: This just holds an allocation with no real content, so there's no safety issue with +/// moving it across threads. +unsafe impl Sync for DeferredFdCloser {} + +/// # Invariants +/// +/// If the `file` pointer is non-null, then it points at a `struct file` and owns a refcount to +/// that file. +#[repr(C)] +struct DeferredFdCloserInner { + twork: MaybeUninit, + file: *mut bindings::file, +} + +impl DeferredFdCloser { + /// Create a new [`DeferredFdCloser`]. + pub(crate) fn new(flags: Flags) -> Result { + Ok(Self { + // INVARIANT: The `file` pointer is null, so the type invariant does not apply. + inner: KBox::new( + DeferredFdCloserInner { + twork: MaybeUninit::uninit(), + file: core::ptr::null_mut(), + }, + flags, + )?, + }) + } + + /// Schedule a task work that closes the file descriptor when this task returns to userspace. + /// + /// Fails if this is called from a context where we cannot run work when returning to + /// userspace. (E.g., from a kthread.) + pub(crate) fn close_fd(self, fd: u32) -> Result<(), DeferredFdCloseError> { + use bindings::task_work_notify_mode_TWA_RESUME as TWA_RESUME; + + // In this method, we schedule the task work before closing the file. This is because + // scheduling a task work is fallible, and we need to know whether it will fail before we + // attempt to close the file. + + // Task works are not available on kthreads. + let current = kernel::current!(); + + // Check if this is a kthread. + // SAFETY: Reading `flags` from a task is always okay. + if unsafe { ((*current.as_ptr()).flags & bindings::PF_KTHREAD) != 0 } { + return Err(DeferredFdCloseError::TaskWorkUnavailable); + } + + // Transfer ownership of the box's allocation to a raw pointer. This disables the + // destructor, so we must manually convert it back to a KBox to drop it. + // + // Until we convert it back to a `KBox`, there are no aliasing requirements on this + // pointer. + let inner = KBox::into_raw(self.inner); + + // The `callback_head` field is first in the struct, so this cast correctly gives us a + // pointer to the field. + let callback_head = inner.cast::(); + // SAFETY: This pointer offset operation does not go out-of-bounds. + let file_field = unsafe { core::ptr::addr_of_mut!((*inner).file) }; + + let current = current.as_ptr(); + + // SAFETY: This function currently has exclusive access to the `DeferredFdCloserInner`, so + // it is okay for us to perform unsynchronized writes to its `callback_head` field. + unsafe { bindings::init_task_work(callback_head, Some(Self::do_close_fd)) }; + + // SAFETY: This inserts the `DeferredFdCloserInner` into the task workqueue for the current + // task. If this operation is successful, then this transfers exclusive ownership of the + // `callback_head` field to the C side until it calls `do_close_fd`, and we don't touch or + // invalidate the field during that time. + // + // When the C side calls `do_close_fd`, the safety requirements of that method are + // satisfied because when a task work is executed, the callback is given ownership of the + // pointer. + // + // The file pointer is currently null. If it is changed to be non-null before `do_close_fd` + // is called, then that change happens due to the write at the end of this function, and + // that write has a safety comment that explains why the refcount can be dropped when + // `do_close_fd` runs. + let res = unsafe { bindings::task_work_add(current, callback_head, TWA_RESUME) }; + + if res != 0 { + // SAFETY: Scheduling the task work failed, so we still have ownership of the box, so + // we may destroy it. + unsafe { drop(KBox::from_raw(inner)) }; + + return Err(DeferredFdCloseError::TaskWorkUnavailable); + } + + // This removes the fd from the fd table in `current`. The file is not fully closed until + // `filp_close` is called. We are given ownership of one refcount to the file. + // + // SAFETY: This is safe no matter what `fd` is. If the `fd` is valid (that is, if the + // pointer is non-null), then we call `filp_close` on the returned pointer as required by + // `file_close_fd`. + let file = unsafe { bindings::file_close_fd(fd) }; + if file.is_null() { + // We don't clean up the task work since that might be expensive if the task work queue + // is long. Just let it execute and let it clean up for itself. + return Err(DeferredFdCloseError::BadFd); + } + + // Acquire a second refcount to the file. + // + // SAFETY: The `file` pointer points at a file with a non-zero refcount. + unsafe { bindings::get_file(file) }; + + // This method closes the fd, consuming one of our two refcounts. There could be active + // light refcounts created from that fd, so we must ensure that the file has a positive + // refcount for the duration of those active light refcounts. We do that by holding on to + // the second refcount until the current task returns to userspace. + // + // SAFETY: The `file` pointer is valid. Passing `current->files` as the file table to close + // it in is correct, since we just got the `fd` from `file_close_fd` which also uses + // `current->files`. + // + // Note: fl_owner_t is currently a void pointer. + unsafe { bindings::filp_close(file, (*current).files as bindings::fl_owner_t) }; + + // We update the file pointer that the task work is supposed to fput. This transfers + // ownership of our last refcount. + // + // INVARIANT: This changes the `file` field of a `DeferredFdCloserInner` from null to + // non-null. This doesn't break the type invariant for `DeferredFdCloserInner` because we + // still own a refcount to the file, so we can pass ownership of that refcount to the + // `DeferredFdCloserInner`. + // + // When `do_close_fd` runs, it must be safe for it to `fput` the refcount. However, this is + // the case because all light refcounts that are associated with the fd we closed + // previously must be dropped when `do_close_fd`, since light refcounts must be dropped + // before returning to userspace. + // + // SAFETY: Task works are executed on the current thread right before we return to + // userspace, so this write is guaranteed to happen before `do_close_fd` is called, which + // means that a race is not possible here. + unsafe { *file_field = file }; + + Ok(()) + } + + /// # Safety + /// + /// The provided pointer must point at the `twork` field of a `DeferredFdCloserInner` stored in + /// a `KBox`, and the caller must pass exclusive ownership of that `KBox`. Furthermore, if the + /// file pointer is non-null, then it must be okay to release the refcount by calling `fput`. + unsafe extern "C" fn do_close_fd(inner: *mut bindings::callback_head) { + // SAFETY: The caller just passed us ownership of this box. + let inner = unsafe { KBox::from_raw(inner.cast::()) }; + if !inner.file.is_null() { + // SAFETY: By the type invariants, we own a refcount to this file, and the caller + // guarantees that dropping the refcount now is okay. + unsafe { bindings::fput(inner.file) }; + } + // The allocation is freed when `inner` goes out of scope. + } +} + +/// Represents a failure to close an fd in a deferred manner. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(crate) enum DeferredFdCloseError { + /// Closing the fd failed because we were unable to schedule a task work. + TaskWorkUnavailable, + /// Closing the fd failed because the fd does not exist. + BadFd, +} + +impl From for Error { + fn from(err: DeferredFdCloseError) -> Error { + match err { + DeferredFdCloseError::TaskWorkUnavailable => ESRCH, + DeferredFdCloseError::BadFd => EBADF, + } + } +} diff --git a/drivers/android/binder/defs.rs b/drivers/android/binder/defs.rs new file mode 100644 index 000000000000..33f51b4139c7 --- /dev/null +++ b/drivers/android/binder/defs.rs @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use core::mem::MaybeUninit; +use core::ops::{Deref, DerefMut}; +use kernel::{ + transmute::{AsBytes, FromBytes}, + uapi::{self, *}, +}; + +macro_rules! pub_no_prefix { + ($prefix:ident, $($newname:ident),+ $(,)?) => { + $(pub(crate) const $newname: u32 = kernel::macros::concat_idents!($prefix, $newname);)+ + }; +} + +pub_no_prefix!( + binder_driver_return_protocol_, + BR_TRANSACTION, + BR_TRANSACTION_SEC_CTX, + BR_REPLY, + BR_DEAD_REPLY, + BR_FAILED_REPLY, + BR_FROZEN_REPLY, + BR_NOOP, + BR_SPAWN_LOOPER, + BR_TRANSACTION_COMPLETE, + BR_TRANSACTION_PENDING_FROZEN, + BR_ONEWAY_SPAM_SUSPECT, + BR_OK, + BR_ERROR, + BR_INCREFS, + BR_ACQUIRE, + BR_RELEASE, + BR_DECREFS, + BR_DEAD_BINDER, + BR_CLEAR_DEATH_NOTIFICATION_DONE, + BR_FROZEN_BINDER, + BR_CLEAR_FREEZE_NOTIFICATION_DONE, +); + +pub_no_prefix!( + binder_driver_command_protocol_, + BC_TRANSACTION, + BC_TRANSACTION_SG, + BC_REPLY, + BC_REPLY_SG, + BC_FREE_BUFFER, + BC_ENTER_LOOPER, + BC_EXIT_LOOPER, + BC_REGISTER_LOOPER, + BC_INCREFS, + BC_ACQUIRE, + BC_RELEASE, + BC_DECREFS, + BC_INCREFS_DONE, + BC_ACQUIRE_DONE, + BC_REQUEST_DEATH_NOTIFICATION, + BC_CLEAR_DEATH_NOTIFICATION, + BC_DEAD_BINDER_DONE, + BC_REQUEST_FREEZE_NOTIFICATION, + BC_CLEAR_FREEZE_NOTIFICATION, + BC_FREEZE_NOTIFICATION_DONE, +); + +pub_no_prefix!( + flat_binder_object_flags_, + FLAT_BINDER_FLAG_ACCEPTS_FDS, + FLAT_BINDER_FLAG_TXN_SECURITY_CTX +); + +pub_no_prefix!( + transaction_flags_, + TF_ONE_WAY, + TF_ACCEPT_FDS, + TF_CLEAR_BUF, + TF_UPDATE_TXN +); + +pub(crate) use uapi::{ + BINDER_TYPE_BINDER, BINDER_TYPE_FD, BINDER_TYPE_FDA, BINDER_TYPE_HANDLE, BINDER_TYPE_PTR, + BINDER_TYPE_WEAK_BINDER, BINDER_TYPE_WEAK_HANDLE, +}; + +macro_rules! decl_wrapper { + ($newname:ident, $wrapped:ty) => { + // Define a wrapper around the C type. Use `MaybeUninit` to enforce that the value of + // padding bytes must be preserved. + #[derive(Copy, Clone)] + #[repr(transparent)] + pub(crate) struct $newname(MaybeUninit<$wrapped>); + + // SAFETY: This macro is only used with types where this is ok. + unsafe impl FromBytes for $newname {} + // SAFETY: This macro is only used with types where this is ok. + unsafe impl AsBytes for $newname {} + + impl Deref for $newname { + type Target = $wrapped; + fn deref(&self) -> &Self::Target { + // SAFETY: We use `MaybeUninit` only to preserve padding. The value must still + // always be valid. + unsafe { self.0.assume_init_ref() } + } + } + + impl DerefMut for $newname { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: We use `MaybeUninit` only to preserve padding. The value must still + // always be valid. + unsafe { self.0.assume_init_mut() } + } + } + + impl Default for $newname { + fn default() -> Self { + // Create a new value of this type where all bytes (including padding) are zeroed. + Self(MaybeUninit::zeroed()) + } + } + }; +} + +decl_wrapper!(BinderNodeDebugInfo, uapi::binder_node_debug_info); +decl_wrapper!(BinderNodeInfoForRef, uapi::binder_node_info_for_ref); +decl_wrapper!(FlatBinderObject, uapi::flat_binder_object); +decl_wrapper!(BinderFdObject, uapi::binder_fd_object); +decl_wrapper!(BinderFdArrayObject, uapi::binder_fd_array_object); +decl_wrapper!(BinderObjectHeader, uapi::binder_object_header); +decl_wrapper!(BinderBufferObject, uapi::binder_buffer_object); +decl_wrapper!(BinderTransactionData, uapi::binder_transaction_data); +decl_wrapper!( + BinderTransactionDataSecctx, + uapi::binder_transaction_data_secctx +); +decl_wrapper!(BinderTransactionDataSg, uapi::binder_transaction_data_sg); +decl_wrapper!(BinderWriteRead, uapi::binder_write_read); +decl_wrapper!(BinderVersion, uapi::binder_version); +decl_wrapper!(BinderFrozenStatusInfo, uapi::binder_frozen_status_info); +decl_wrapper!(BinderFreezeInfo, uapi::binder_freeze_info); +decl_wrapper!(BinderFrozenStateInfo, uapi::binder_frozen_state_info); +decl_wrapper!(BinderHandleCookie, uapi::binder_handle_cookie); +decl_wrapper!(ExtendedError, uapi::binder_extended_error); + +impl BinderVersion { + pub(crate) fn current() -> Self { + Self(MaybeUninit::new(uapi::binder_version { + protocol_version: BINDER_CURRENT_PROTOCOL_VERSION as _, + })) + } +} + +impl BinderTransactionData { + pub(crate) fn with_buffers_size(self, buffers_size: u64) -> BinderTransactionDataSg { + BinderTransactionDataSg(MaybeUninit::new(uapi::binder_transaction_data_sg { + transaction_data: *self, + buffers_size, + })) + } +} + +impl BinderTransactionDataSecctx { + /// View the inner data as wrapped in `BinderTransactionData`. + pub(crate) fn tr_data(&mut self) -> &mut BinderTransactionData { + // SAFETY: Transparent wrapper is safe to transmute. + unsafe { + &mut *(&mut self.transaction_data as *mut uapi::binder_transaction_data + as *mut BinderTransactionData) + } + } +} + +impl ExtendedError { + pub(crate) fn new(id: u32, command: u32, param: i32) -> Self { + Self(MaybeUninit::new(uapi::binder_extended_error { + id, + command, + param, + })) + } +} diff --git a/drivers/android/binder/error.rs b/drivers/android/binder/error.rs new file mode 100644 index 000000000000..9921827267d0 --- /dev/null +++ b/drivers/android/binder/error.rs @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use kernel::prelude::*; + +use crate::defs::*; + +pub(crate) type BinderResult = core::result::Result; + +/// An error that will be returned to userspace via the `BINDER_WRITE_READ` ioctl rather than via +/// errno. +pub(crate) struct BinderError { + pub(crate) reply: u32, + source: Option, +} + +impl BinderError { + pub(crate) fn new_dead() -> Self { + Self { + reply: BR_DEAD_REPLY, + source: None, + } + } + + pub(crate) fn new_frozen() -> Self { + Self { + reply: BR_FROZEN_REPLY, + source: None, + } + } + + pub(crate) fn new_frozen_oneway() -> Self { + Self { + reply: BR_TRANSACTION_PENDING_FROZEN, + source: None, + } + } + + pub(crate) fn is_dead(&self) -> bool { + self.reply == BR_DEAD_REPLY + } + + pub(crate) fn as_errno(&self) -> kernel::ffi::c_int { + self.source.unwrap_or(EINVAL).to_errno() + } + + pub(crate) fn should_pr_warn(&self) -> bool { + self.source.is_some() + } +} + +/// Convert an errno into a `BinderError` and store the errno used to construct it. The errno +/// should be stored as the thread's extended error when given to userspace. +impl From for BinderError { + fn from(source: Error) -> Self { + Self { + reply: BR_FAILED_REPLY, + source: Some(source), + } + } +} + +impl From for BinderError { + fn from(source: kernel::fs::file::BadFdError) -> Self { + BinderError::from(Error::from(source)) + } +} + +impl From for BinderError { + fn from(_: kernel::alloc::AllocError) -> Self { + Self { + reply: BR_FAILED_REPLY, + source: Some(ENOMEM), + } + } +} + +impl core::fmt::Debug for BinderError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self.reply { + BR_FAILED_REPLY => match self.source.as_ref() { + Some(source) => f + .debug_struct("BR_FAILED_REPLY") + .field("source", source) + .finish(), + None => f.pad("BR_FAILED_REPLY"), + }, + BR_DEAD_REPLY => f.pad("BR_DEAD_REPLY"), + BR_FROZEN_REPLY => f.pad("BR_FROZEN_REPLY"), + BR_TRANSACTION_PENDING_FROZEN => f.pad("BR_TRANSACTION_PENDING_FROZEN"), + BR_TRANSACTION_COMPLETE => f.pad("BR_TRANSACTION_COMPLETE"), + _ => f + .debug_struct("BinderError") + .field("reply", &self.reply) + .finish(), + } + } +} diff --git a/drivers/android/binder/freeze.rs b/drivers/android/binder/freeze.rs new file mode 100644 index 000000000000..e68c3c8bc55a --- /dev/null +++ b/drivers/android/binder/freeze.rs @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use kernel::{ + alloc::AllocError, + list::ListArc, + prelude::*, + rbtree::{self, RBTreeNodeReservation}, + seq_file::SeqFile, + seq_print, + sync::{Arc, UniqueArc}, + uaccess::UserSliceReader, +}; + +use crate::{ + defs::*, node::Node, process::Process, thread::Thread, BinderReturnWriter, DArc, DLArc, + DTRWrap, DeliverToRead, +}; + +#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] +pub(crate) struct FreezeCookie(u64); + +/// Represents a listener for changes to the frozen state of a process. +pub(crate) struct FreezeListener { + /// The node we are listening for. + pub(crate) node: DArc, + /// The cookie of this freeze listener. + cookie: FreezeCookie, + /// What value of `is_frozen` did we most recently tell userspace about? + last_is_frozen: Option, + /// We sent a `BR_FROZEN_BINDER` and we are waiting for `BC_FREEZE_NOTIFICATION_DONE` before + /// sending any other commands. + is_pending: bool, + /// Userspace sent `BC_CLEAR_FREEZE_NOTIFICATION` and we need to reply with + /// `BR_CLEAR_FREEZE_NOTIFICATION_DONE` as soon as possible. If `is_pending` is set, then we + /// must wait for it to be unset before we can reply. + is_clearing: bool, + /// Number of cleared duplicates that can't be deleted until userspace sends + /// `BC_FREEZE_NOTIFICATION_DONE`. + num_pending_duplicates: u64, + /// Number of cleared duplicates that can be deleted. + num_cleared_duplicates: u64, +} + +impl FreezeListener { + /// Is it okay to create a new listener with the same cookie as this one for the provided node? + /// + /// Under some scenarios, userspace may delete a freeze listener and immediately recreate it + /// with the same cookie. This results in duplicate listeners. To avoid issues with ambiguity, + /// we allow this only if the new listener is for the same node, and we also require that the + /// old listener has already been cleared. + fn allow_duplicate(&self, node: &DArc) -> bool { + Arc::ptr_eq(&self.node, node) && self.is_clearing + } +} + +type UninitFM = UniqueArc>>; + +/// Represents a notification that the freeze state has changed. +pub(crate) struct FreezeMessage { + cookie: FreezeCookie, +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<0> for FreezeMessage { + untracked; + } +} + +impl FreezeMessage { + fn new(flags: kernel::alloc::Flags) -> Result { + UniqueArc::new_uninit(flags) + } + + fn init(ua: UninitFM, cookie: FreezeCookie) -> DLArc { + match ua.pin_init_with(DTRWrap::new(FreezeMessage { cookie })) { + Ok(msg) => ListArc::from(msg), + Err(err) => match err {}, + } + } +} + +impl DeliverToRead for FreezeMessage { + fn do_work( + self: DArc, + thread: &Thread, + writer: &mut BinderReturnWriter<'_>, + ) -> Result { + let _removed_listener; + let mut node_refs = thread.process.node_refs.lock(); + let Some(mut freeze_entry) = node_refs.freeze_listeners.find_mut(&self.cookie) else { + return Ok(true); + }; + let freeze = freeze_entry.get_mut(); + + if freeze.num_cleared_duplicates > 0 { + freeze.num_cleared_duplicates -= 1; + drop(node_refs); + writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?; + writer.write_payload(&self.cookie.0)?; + return Ok(true); + } + + if freeze.is_pending { + return Ok(true); + } + if freeze.is_clearing { + _removed_listener = freeze_entry.remove_node(); + drop(node_refs); + writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?; + writer.write_payload(&self.cookie.0)?; + Ok(true) + } else { + let is_frozen = freeze.node.owner.inner.lock().is_frozen; + if freeze.last_is_frozen == Some(is_frozen) { + return Ok(true); + } + + let mut state_info = BinderFrozenStateInfo::default(); + state_info.is_frozen = is_frozen as u32; + state_info.cookie = freeze.cookie.0; + freeze.is_pending = true; + freeze.last_is_frozen = Some(is_frozen); + drop(node_refs); + + writer.write_code(BR_FROZEN_BINDER)?; + writer.write_payload(&state_info)?; + // BR_FROZEN_BINDER notifications can cause transactions + Ok(false) + } + } + + fn cancel(self: DArc) {} + + fn should_sync_wakeup(&self) -> bool { + false + } + + #[inline(never)] + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + seq_print!(m, "{}has frozen binder\n", prefix); + Ok(()) + } +} + +impl FreezeListener { + pub(crate) fn on_process_exit(&self, proc: &Arc) { + if !self.is_clearing { + self.node.remove_freeze_listener(proc); + } + } +} + +impl Process { + pub(crate) fn request_freeze_notif( + self: &Arc, + reader: &mut UserSliceReader, + ) -> Result<()> { + let hc = reader.read::()?; + let handle = hc.handle; + let cookie = FreezeCookie(hc.cookie); + + let msg = FreezeMessage::new(GFP_KERNEL)?; + let alloc = RBTreeNodeReservation::new(GFP_KERNEL)?; + + let mut node_refs_guard = self.node_refs.lock(); + let node_refs = &mut *node_refs_guard; + let Some(info) = node_refs.by_handle.get_mut(&handle) else { + pr_warn!("BC_REQUEST_FREEZE_NOTIFICATION invalid ref {}\n", handle); + return Err(EINVAL); + }; + if info.freeze().is_some() { + pr_warn!("BC_REQUEST_FREEZE_NOTIFICATION already set\n"); + return Err(EINVAL); + } + let node_ref = info.node_ref(); + let freeze_entry = node_refs.freeze_listeners.entry(cookie); + + if let rbtree::Entry::Occupied(ref dupe) = freeze_entry { + if !dupe.get().allow_duplicate(&node_ref.node) { + pr_warn!("BC_REQUEST_FREEZE_NOTIFICATION duplicate cookie\n"); + return Err(EINVAL); + } + } + + // All failure paths must come before this call, and all modifications must come after this + // call. + node_ref.node.add_freeze_listener(self, GFP_KERNEL)?; + + match freeze_entry { + rbtree::Entry::Vacant(entry) => { + entry.insert( + FreezeListener { + cookie, + node: node_ref.node.clone(), + last_is_frozen: None, + is_pending: false, + is_clearing: false, + num_pending_duplicates: 0, + num_cleared_duplicates: 0, + }, + alloc, + ); + } + rbtree::Entry::Occupied(mut dupe) => { + let dupe = dupe.get_mut(); + if dupe.is_pending { + dupe.num_pending_duplicates += 1; + } else { + dupe.num_cleared_duplicates += 1; + } + dupe.last_is_frozen = None; + dupe.is_pending = false; + dupe.is_clearing = false; + } + } + + *info.freeze() = Some(cookie); + let msg = FreezeMessage::init(msg, cookie); + drop(node_refs_guard); + let _ = self.push_work(msg); + Ok(()) + } + + pub(crate) fn freeze_notif_done(self: &Arc, reader: &mut UserSliceReader) -> Result<()> { + let cookie = FreezeCookie(reader.read()?); + let alloc = FreezeMessage::new(GFP_KERNEL)?; + let mut node_refs_guard = self.node_refs.lock(); + let node_refs = &mut *node_refs_guard; + let Some(freeze) = node_refs.freeze_listeners.get_mut(&cookie) else { + pr_warn!("BC_FREEZE_NOTIFICATION_DONE {:016x} not found\n", cookie.0); + return Err(EINVAL); + }; + let mut clear_msg = None; + if freeze.num_pending_duplicates > 0 { + clear_msg = Some(FreezeMessage::init(alloc, cookie)); + freeze.num_pending_duplicates -= 1; + freeze.num_cleared_duplicates += 1; + } else { + if !freeze.is_pending { + pr_warn!( + "BC_FREEZE_NOTIFICATION_DONE {:016x} not pending\n", + cookie.0 + ); + return Err(EINVAL); + } + if freeze.is_clearing { + // Immediately send another FreezeMessage for BR_CLEAR_FREEZE_NOTIFICATION_DONE. + clear_msg = Some(FreezeMessage::init(alloc, cookie)); + } + freeze.is_pending = false; + } + drop(node_refs_guard); + if let Some(clear_msg) = clear_msg { + let _ = self.push_work(clear_msg); + } + Ok(()) + } + + pub(crate) fn clear_freeze_notif(self: &Arc, reader: &mut UserSliceReader) -> Result<()> { + let hc = reader.read::()?; + let handle = hc.handle; + let cookie = FreezeCookie(hc.cookie); + + let alloc = FreezeMessage::new(GFP_KERNEL)?; + let mut node_refs_guard = self.node_refs.lock(); + let node_refs = &mut *node_refs_guard; + let Some(info) = node_refs.by_handle.get_mut(&handle) else { + pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION invalid ref {}\n", handle); + return Err(EINVAL); + }; + let Some(info_cookie) = info.freeze() else { + pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION freeze notification not active\n"); + return Err(EINVAL); + }; + if *info_cookie != cookie { + pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION freeze notification cookie mismatch\n"); + return Err(EINVAL); + } + let Some(listener) = node_refs.freeze_listeners.get_mut(&cookie) else { + pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION invalid cookie {}\n", handle); + return Err(EINVAL); + }; + listener.is_clearing = true; + listener.node.remove_freeze_listener(self); + *info.freeze() = None; + let mut msg = None; + if !listener.is_pending { + msg = Some(FreezeMessage::init(alloc, cookie)); + } + drop(node_refs_guard); + + if let Some(msg) = msg { + let _ = self.push_work(msg); + } + Ok(()) + } + + fn get_freeze_cookie(&self, node: &DArc) -> Option { + let node_refs = &mut *self.node_refs.lock(); + let handle = node_refs.by_node.get(&node.global_id())?; + let node_ref = node_refs.by_handle.get_mut(handle)?; + *node_ref.freeze() + } + + /// Creates a vector of every freeze listener on this process. + /// + /// Returns pairs of the remote process listening for notifications and the local node it is + /// listening on. + #[expect(clippy::type_complexity)] + fn find_freeze_recipients(&self) -> Result, Arc)>, AllocError> { + // Defined before `inner` to drop after releasing spinlock if `push_within_capacity` fails. + let mut node_proc_pair; + + // We pre-allocate space for up to 8 recipients before we take the spinlock. However, if + // the allocation fails, use a vector with a capacity of zero instead of failing. After + // all, there might not be any freeze listeners, in which case this operation could still + // succeed. + let mut recipients = + KVVec::with_capacity(8, GFP_KERNEL).unwrap_or_else(|_err| KVVec::new()); + + let mut inner = self.lock_with_nodes(); + let mut curr = inner.nodes.cursor_front(); + while let Some(cursor) = curr { + let (key, node) = cursor.current(); + let key = *key; + let list = node.freeze_list(&inner.inner); + let len = list.len(); + + if recipients.spare_capacity_mut().len() < len { + drop(inner); + recipients.reserve(len, GFP_KERNEL)?; + inner = self.lock_with_nodes(); + // Find the node we were looking at and try again. If the set of nodes was changed, + // then just proceed to the next node. This is ok because we don't guarantee the + // inclusion of nodes that are added or removed in parallel with this operation. + curr = inner.nodes.cursor_lower_bound(&key); + continue; + } + + for proc in list { + node_proc_pair = (node.clone(), proc.clone()); + recipients + .push_within_capacity(node_proc_pair) + .map_err(|_| { + pr_err!( + "push_within_capacity failed even though we checked the capacity\n" + ); + AllocError + })?; + } + + curr = cursor.move_next(); + } + Ok(recipients) + } + + /// Prepare allocations for sending freeze messages. + pub(crate) fn prepare_freeze_messages(&self) -> Result { + let recipients = self.find_freeze_recipients()?; + let mut batch = KVVec::with_capacity(recipients.len(), GFP_KERNEL)?; + for (node, proc) in recipients { + let Some(cookie) = proc.get_freeze_cookie(&node) else { + // If the freeze listener was removed in the meantime, just discard the + // notification. + continue; + }; + let msg_alloc = FreezeMessage::new(GFP_KERNEL)?; + let msg = FreezeMessage::init(msg_alloc, cookie); + batch.push((proc, msg), GFP_KERNEL)?; + } + + Ok(FreezeMessages { batch }) + } +} + +pub(crate) struct FreezeMessages { + batch: KVVec<(Arc, DLArc)>, +} + +impl FreezeMessages { + pub(crate) fn send_messages(self) { + for (proc, msg) in self.batch { + let _ = proc.push_work(msg); + } + } +} diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs new file mode 100644 index 000000000000..ade895ef791e --- /dev/null +++ b/drivers/android/binder/node.rs @@ -0,0 +1,1131 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use kernel::{ + list::{AtomicTracker, List, ListArc, ListLinks, TryNewListArc}, + prelude::*, + seq_file::SeqFile, + seq_print, + sync::lock::{spinlock::SpinLockBackend, Guard}, + sync::{Arc, LockedBy, SpinLock}, +}; + +use crate::{ + defs::*, + error::BinderError, + process::{NodeRefInfo, Process, ProcessInner}, + thread::Thread, + transaction::Transaction, + BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverToRead, +}; + +use core::mem; + +mod wrapper; +pub(crate) use self::wrapper::CritIncrWrapper; + +#[derive(Debug)] +pub(crate) struct CouldNotDeliverCriticalIncrement; + +/// Keeps track of how this node is scheduled. +/// +/// There are two ways to schedule a node to a work list. Just schedule the node itself, or +/// allocate a wrapper that references the node and schedule the wrapper. These wrappers exists to +/// make it possible to "move" a node from one list to another - when `do_work` is called directly +/// on the `Node`, then it's a no-op if there's also a pending wrapper. +/// +/// Wrappers are generally only needed for zero-to-one refcount increments, and there are two cases +/// of this: weak increments and strong increments. We call such increments "critical" because it +/// is critical that they are delivered to the thread doing the increment. Some examples: +/// +/// * One thread makes a zero-to-one strong increment, and another thread makes a zero-to-one weak +/// increment. Delivering the node to the thread doing the weak increment is wrong, since the +/// thread doing the strong increment may have ended a long time ago when the command is actually +/// processed by userspace. +/// +/// * We have a weak reference and are about to drop it on one thread. But then another thread does +/// a zero-to-one strong increment. If the strong increment gets sent to the thread that was +/// about to drop the weak reference, then the strong increment could be processed after the +/// other thread has already exited, which would be too late. +/// +/// Note that trying to create a `ListArc` to the node can succeed even if `has_normal_push` is +/// set. This is because another thread might just have popped the node from a todo list, but not +/// yet called `do_work`. However, if `has_normal_push` is false, then creating a `ListArc` should +/// always succeed. +/// +/// Like the other fields in `NodeInner`, the delivery state is protected by the process lock. +struct DeliveryState { + /// Is the `Node` currently scheduled? + has_pushed_node: bool, + + /// Is a wrapper currently scheduled? + /// + /// The wrapper is used only for strong zero2one increments. + has_pushed_wrapper: bool, + + /// Is the currently scheduled `Node` scheduled due to a weak zero2one increment? + /// + /// Weak zero2one operations are always scheduled using the `Node`. + has_weak_zero2one: bool, + + /// Is the currently scheduled wrapper/`Node` scheduled due to a strong zero2one increment? + /// + /// If `has_pushed_wrapper` is set, then the strong zero2one increment was scheduled using the + /// wrapper. Otherwise, `has_pushed_node` must be set and it was scheduled using the `Node`. + has_strong_zero2one: bool, +} + +impl DeliveryState { + fn should_normal_push(&self) -> bool { + !self.has_pushed_node && !self.has_pushed_wrapper + } + + fn did_normal_push(&mut self) { + assert!(self.should_normal_push()); + self.has_pushed_node = true; + } + + fn should_push_weak_zero2one(&self) -> bool { + !self.has_weak_zero2one && !self.has_strong_zero2one + } + + fn can_push_weak_zero2one_normally(&self) -> bool { + !self.has_pushed_node + } + + fn did_push_weak_zero2one(&mut self) { + assert!(self.should_push_weak_zero2one()); + assert!(self.can_push_weak_zero2one_normally()); + self.has_pushed_node = true; + self.has_weak_zero2one = true; + } + + fn should_push_strong_zero2one(&self) -> bool { + !self.has_strong_zero2one + } + + fn can_push_strong_zero2one_normally(&self) -> bool { + !self.has_pushed_node + } + + fn did_push_strong_zero2one(&mut self) { + assert!(self.should_push_strong_zero2one()); + assert!(self.can_push_strong_zero2one_normally()); + self.has_pushed_node = true; + self.has_strong_zero2one = true; + } + + fn did_push_strong_zero2one_wrapper(&mut self) { + assert!(self.should_push_strong_zero2one()); + assert!(!self.can_push_strong_zero2one_normally()); + self.has_pushed_wrapper = true; + self.has_strong_zero2one = true; + } +} + +struct CountState { + /// The reference count. + count: usize, + /// Whether the process that owns this node thinks that we hold a refcount on it. (Note that + /// even if count is greater than one, we only increment it once in the owning process.) + has_count: bool, +} + +impl CountState { + fn new() -> Self { + Self { + count: 0, + has_count: false, + } + } +} + +struct NodeInner { + /// Strong refcounts held on this node by `NodeRef` objects. + strong: CountState, + /// Weak refcounts held on this node by `NodeRef` objects. + weak: CountState, + delivery_state: DeliveryState, + /// The binder driver guarantees that oneway transactions sent to the same node are serialized, + /// that is, userspace will not be given the next one until it has finished processing the + /// previous oneway transaction. This is done to avoid the case where two oneway transactions + /// arrive in opposite order from the order in which they were sent. (E.g., they could be + /// delivered to two different threads, which could appear as-if they were sent in opposite + /// order.) + /// + /// To fix that, we store pending oneway transactions in a separate list in the node, and don't + /// deliver the next oneway transaction until userspace signals that it has finished processing + /// the previous oneway transaction by calling the `BC_FREE_BUFFER` ioctl. + oneway_todo: List>, + /// Keeps track of whether this node has a pending oneway transaction. + /// + /// When this is true, incoming oneway transactions are stored in `oneway_todo`, instead of + /// being delivered directly to the process. + has_oneway_transaction: bool, + /// List of processes to deliver a notification to when this node is destroyed (usually due to + /// the process dying). + death_list: List, 1>, + /// List of processes to deliver freeze notifications to. + freeze_list: KVVec>, + /// The number of active BR_INCREFS or BR_ACQUIRE operations. (should be maximum two) + /// + /// If this is non-zero, then we postpone any BR_RELEASE or BR_DECREFS notifications until the + /// active operations have ended. This avoids the situation an increment and decrement get + /// reordered from userspace's perspective. + active_inc_refs: u8, + /// List of `NodeRefInfo` objects that reference this node. + refs: List, +} + +#[pin_data] +pub(crate) struct Node { + pub(crate) debug_id: usize, + ptr: u64, + pub(crate) cookie: u64, + pub(crate) flags: u32, + pub(crate) owner: Arc, + inner: LockedBy, + #[pin] + links_track: AtomicTracker, +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<0> for Node { + tracked_by links_track: AtomicTracker; + } +} + +// Make `oneway_todo` work. +kernel::list::impl_list_item! { + impl ListItem<0> for DTRWrap { + using ListLinks { self.links.inner }; + } +} + +impl Node { + pub(crate) fn new( + ptr: u64, + cookie: u64, + flags: u32, + owner: Arc, + ) -> impl PinInit { + pin_init!(Self { + inner: LockedBy::new( + &owner.inner, + NodeInner { + strong: CountState::new(), + weak: CountState::new(), + delivery_state: DeliveryState { + has_pushed_node: false, + has_pushed_wrapper: false, + has_weak_zero2one: false, + has_strong_zero2one: false, + }, + death_list: List::new(), + oneway_todo: List::new(), + freeze_list: KVVec::new(), + has_oneway_transaction: false, + active_inc_refs: 0, + refs: List::new(), + }, + ), + debug_id: super::next_debug_id(), + ptr, + cookie, + flags, + owner, + links_track <- AtomicTracker::new(), + }) + } + + pub(crate) fn has_oneway_transaction(&self, owner_inner: &mut ProcessInner) -> bool { + let inner = self.inner.access_mut(owner_inner); + inner.has_oneway_transaction + } + + #[inline(never)] + pub(crate) fn full_debug_print( + &self, + m: &SeqFile, + owner_inner: &mut ProcessInner, + ) -> Result<()> { + let inner = self.inner.access_mut(owner_inner); + seq_print!( + m, + " node {}: u{:016x} c{:016x} hs {} hw {} cs {} cw {}", + self.debug_id, + self.ptr, + self.cookie, + inner.strong.has_count, + inner.weak.has_count, + inner.strong.count, + inner.weak.count, + ); + if !inner.refs.is_empty() { + seq_print!(m, " proc"); + for node_ref in &inner.refs { + seq_print!(m, " {}", node_ref.process.task.pid()); + } + } + seq_print!(m, "\n"); + for t in &inner.oneway_todo { + t.debug_print_inner(m, " pending async transaction "); + } + Ok(()) + } + + /// Insert the `NodeRef` into this `refs` list. + /// + /// # Safety + /// + /// It must be the case that `info.node_ref.node` is this node. + pub(crate) unsafe fn insert_node_info( + &self, + info: ListArc, + ) { + self.inner + .access_mut(&mut self.owner.inner.lock()) + .refs + .push_front(info); + } + + /// Insert the `NodeRef` into this `refs` list. + /// + /// # Safety + /// + /// It must be the case that `info.node_ref.node` is this node. + pub(crate) unsafe fn remove_node_info( + &self, + info: &NodeRefInfo, + ) -> Option> { + // SAFETY: We always insert `NodeRefInfo` objects into the `refs` list of the node that it + // references in `info.node_ref.node`. That is this node, so `info` cannot possibly be in + // the `refs` list of another node. + unsafe { + self.inner + .access_mut(&mut self.owner.inner.lock()) + .refs + .remove(info) + } + } + + /// An id that is unique across all binder nodes on the system. Used as the key in the + /// `by_node` map. + pub(crate) fn global_id(&self) -> usize { + self as *const Node as usize + } + + pub(crate) fn get_id(&self) -> (u64, u64) { + (self.ptr, self.cookie) + } + + pub(crate) fn add_death( + &self, + death: ListArc, 1>, + guard: &mut Guard<'_, ProcessInner, SpinLockBackend>, + ) { + self.inner.access_mut(guard).death_list.push_back(death); + } + + pub(crate) fn inc_ref_done_locked( + self: &DArc, + _strong: bool, + owner_inner: &mut ProcessInner, + ) -> Option> { + let inner = self.inner.access_mut(owner_inner); + if inner.active_inc_refs == 0 { + pr_err!("inc_ref_done called when no active inc_refs"); + return None; + } + + inner.active_inc_refs -= 1; + if inner.active_inc_refs == 0 { + // Having active inc_refs can inhibit dropping of ref-counts. Calculate whether we + // would send a refcount decrement, and if so, tell the caller to schedule us. + let strong = inner.strong.count > 0; + let has_strong = inner.strong.has_count; + let weak = strong || inner.weak.count > 0; + let has_weak = inner.weak.has_count; + + let should_drop_weak = !weak && has_weak; + let should_drop_strong = !strong && has_strong; + + // If we want to drop the ref-count again, tell the caller to schedule a work node for + // that. + let need_push = should_drop_weak || should_drop_strong; + + if need_push && inner.delivery_state.should_normal_push() { + let list_arc = ListArc::try_from_arc(self.clone()).ok().unwrap(); + inner.delivery_state.did_normal_push(); + Some(list_arc) + } else { + None + } + } else { + None + } + } + + pub(crate) fn update_refcount_locked( + self: &DArc, + inc: bool, + strong: bool, + count: usize, + owner_inner: &mut ProcessInner, + ) -> Option> { + let is_dead = owner_inner.is_dead; + let inner = self.inner.access_mut(owner_inner); + + // Get a reference to the state we'll update. + let state = if strong { + &mut inner.strong + } else { + &mut inner.weak + }; + + // Update the count and determine whether we need to push work. + let need_push = if inc { + state.count += count; + // TODO: This method shouldn't be used for zero-to-one increments. + !is_dead && !state.has_count + } else { + if state.count < count { + pr_err!("Failure: refcount underflow!"); + return None; + } + state.count -= count; + !is_dead && state.count == 0 && state.has_count + }; + + if need_push && inner.delivery_state.should_normal_push() { + let list_arc = ListArc::try_from_arc(self.clone()).ok().unwrap(); + inner.delivery_state.did_normal_push(); + Some(list_arc) + } else { + None + } + } + + pub(crate) fn incr_refcount_allow_zero2one( + self: &DArc, + strong: bool, + owner_inner: &mut ProcessInner, + ) -> Result>, CouldNotDeliverCriticalIncrement> { + let is_dead = owner_inner.is_dead; + let inner = self.inner.access_mut(owner_inner); + + // Get a reference to the state we'll update. + let state = if strong { + &mut inner.strong + } else { + &mut inner.weak + }; + + // Update the count and determine whether we need to push work. + state.count += 1; + if is_dead || state.has_count { + return Ok(None); + } + + // Userspace needs to be notified of this. + if !strong && inner.delivery_state.should_push_weak_zero2one() { + assert!(inner.delivery_state.can_push_weak_zero2one_normally()); + let list_arc = ListArc::try_from_arc(self.clone()).ok().unwrap(); + inner.delivery_state.did_push_weak_zero2one(); + Ok(Some(list_arc)) + } else if strong && inner.delivery_state.should_push_strong_zero2one() { + if inner.delivery_state.can_push_strong_zero2one_normally() { + let list_arc = ListArc::try_from_arc(self.clone()).ok().unwrap(); + inner.delivery_state.did_push_strong_zero2one(); + Ok(Some(list_arc)) + } else { + state.count -= 1; + Err(CouldNotDeliverCriticalIncrement) + } + } else { + // Work is already pushed, and we don't need to push again. + Ok(None) + } + } + + pub(crate) fn incr_refcount_allow_zero2one_with_wrapper( + self: &DArc, + strong: bool, + wrapper: CritIncrWrapper, + owner_inner: &mut ProcessInner, + ) -> Option> { + match self.incr_refcount_allow_zero2one(strong, owner_inner) { + Ok(Some(node)) => Some(node as _), + Ok(None) => None, + Err(CouldNotDeliverCriticalIncrement) => { + assert!(strong); + let inner = self.inner.access_mut(owner_inner); + inner.strong.count += 1; + inner.delivery_state.did_push_strong_zero2one_wrapper(); + Some(wrapper.init(self.clone())) + } + } + } + + pub(crate) fn update_refcount(self: &DArc, inc: bool, count: usize, strong: bool) { + self.owner + .inner + .lock() + .update_node_refcount(self, inc, strong, count, None); + } + + pub(crate) fn populate_counts( + &self, + out: &mut BinderNodeInfoForRef, + guard: &Guard<'_, ProcessInner, SpinLockBackend>, + ) { + let inner = self.inner.access(guard); + out.strong_count = inner.strong.count as _; + out.weak_count = inner.weak.count as _; + } + + pub(crate) fn populate_debug_info( + &self, + out: &mut BinderNodeDebugInfo, + guard: &Guard<'_, ProcessInner, SpinLockBackend>, + ) { + out.ptr = self.ptr as _; + out.cookie = self.cookie as _; + let inner = self.inner.access(guard); + if inner.strong.has_count { + out.has_strong_ref = 1; + } + if inner.weak.has_count { + out.has_weak_ref = 1; + } + } + + pub(crate) fn force_has_count(&self, guard: &mut Guard<'_, ProcessInner, SpinLockBackend>) { + let inner = self.inner.access_mut(guard); + inner.strong.has_count = true; + inner.weak.has_count = true; + } + + fn write(&self, writer: &mut BinderReturnWriter<'_>, code: u32) -> Result { + writer.write_code(code)?; + writer.write_payload(&self.ptr)?; + writer.write_payload(&self.cookie)?; + Ok(()) + } + + pub(crate) fn submit_oneway( + &self, + transaction: DLArc, + guard: &mut Guard<'_, ProcessInner, SpinLockBackend>, + ) -> Result<(), (BinderError, DLArc)> { + if guard.is_dead { + return Err((BinderError::new_dead(), transaction)); + } + + let inner = self.inner.access_mut(guard); + if inner.has_oneway_transaction { + inner.oneway_todo.push_back(transaction); + } else { + inner.has_oneway_transaction = true; + guard.push_work(transaction)?; + } + Ok(()) + } + + pub(crate) fn release(&self) { + let mut guard = self.owner.inner.lock(); + while let Some(work) = self.inner.access_mut(&mut guard).oneway_todo.pop_front() { + drop(guard); + work.into_arc().cancel(); + guard = self.owner.inner.lock(); + } + + let death_list = core::mem::take(&mut self.inner.access_mut(&mut guard).death_list); + drop(guard); + for death in death_list { + death.into_arc().set_dead(); + } + } + + pub(crate) fn pending_oneway_finished(&self) { + let mut guard = self.owner.inner.lock(); + if guard.is_dead { + // Cleanup will happen in `Process::deferred_release`. + return; + } + + let inner = self.inner.access_mut(&mut guard); + + let transaction = inner.oneway_todo.pop_front(); + inner.has_oneway_transaction = transaction.is_some(); + if let Some(transaction) = transaction { + match guard.push_work(transaction) { + Ok(()) => {} + Err((_err, work)) => { + // Process is dead. + // This shouldn't happen due to the `is_dead` check, but if it does, just drop + // the transaction and return. + drop(guard); + drop(work); + } + } + } + } + + /// Finds an outdated transaction that the given transaction can replace. + /// + /// If one is found, it is removed from the list and returned. + pub(crate) fn take_outdated_transaction( + &self, + new: &Transaction, + guard: &mut Guard<'_, ProcessInner, SpinLockBackend>, + ) -> Option> { + let inner = self.inner.access_mut(guard); + let mut cursor = inner.oneway_todo.cursor_front(); + while let Some(next) = cursor.peek_next() { + if new.can_replace(&next) { + return Some(next.remove()); + } + cursor.move_next(); + } + None + } + + /// This is split into a separate function since it's called by both `Node::do_work` and + /// `NodeWrapper::do_work`. + fn do_work_locked( + &self, + writer: &mut BinderReturnWriter<'_>, + mut guard: Guard<'_, ProcessInner, SpinLockBackend>, + ) -> Result { + let inner = self.inner.access_mut(&mut guard); + let strong = inner.strong.count > 0; + let has_strong = inner.strong.has_count; + let weak = strong || inner.weak.count > 0; + let has_weak = inner.weak.has_count; + + if weak && !has_weak { + inner.weak.has_count = true; + inner.active_inc_refs += 1; + } + + if strong && !has_strong { + inner.strong.has_count = true; + inner.active_inc_refs += 1; + } + + let no_active_inc_refs = inner.active_inc_refs == 0; + let should_drop_weak = no_active_inc_refs && (!weak && has_weak); + let should_drop_strong = no_active_inc_refs && (!strong && has_strong); + if should_drop_weak { + inner.weak.has_count = false; + } + if should_drop_strong { + inner.strong.has_count = false; + } + if no_active_inc_refs && !weak { + // Remove the node if there are no references to it. + guard.remove_node(self.ptr); + } + drop(guard); + + if weak && !has_weak { + self.write(writer, BR_INCREFS)?; + } + if strong && !has_strong { + self.write(writer, BR_ACQUIRE)?; + } + if should_drop_strong { + self.write(writer, BR_RELEASE)?; + } + if should_drop_weak { + self.write(writer, BR_DECREFS)?; + } + + Ok(true) + } + + pub(crate) fn add_freeze_listener( + &self, + process: &Arc, + flags: kernel::alloc::Flags, + ) -> Result { + let mut vec_alloc = KVVec::>::new(); + loop { + let mut guard = self.owner.inner.lock(); + // Do not check for `guard.dead`. The `dead` flag that matters here is the owner of the + // listener, no the target. + let inner = self.inner.access_mut(&mut guard); + let len = inner.freeze_list.len(); + if len >= inner.freeze_list.capacity() { + if len >= vec_alloc.capacity() { + drop(guard); + vec_alloc = KVVec::with_capacity((1 + len).next_power_of_two(), flags)?; + continue; + } + mem::swap(&mut inner.freeze_list, &mut vec_alloc); + for elem in vec_alloc.drain_all() { + inner.freeze_list.push_within_capacity(elem)?; + } + } + inner.freeze_list.push_within_capacity(process.clone())?; + return Ok(()); + } + } + + pub(crate) fn remove_freeze_listener(&self, p: &Arc) { + let _unused_capacity; + let mut guard = self.owner.inner.lock(); + let inner = self.inner.access_mut(&mut guard); + let len = inner.freeze_list.len(); + inner.freeze_list.retain(|proc| !Arc::ptr_eq(proc, p)); + if len == inner.freeze_list.len() { + pr_warn!( + "Could not remove freeze listener for {}\n", + p.pid_in_current_ns() + ); + } + if inner.freeze_list.is_empty() { + _unused_capacity = mem::replace(&mut inner.freeze_list, KVVec::new()); + } + } + + pub(crate) fn freeze_list<'a>(&'a self, guard: &'a ProcessInner) -> &'a [Arc] { + &self.inner.access(guard).freeze_list + } +} + +impl DeliverToRead for Node { + fn do_work( + self: DArc, + _thread: &Thread, + writer: &mut BinderReturnWriter<'_>, + ) -> Result { + let mut owner_inner = self.owner.inner.lock(); + let inner = self.inner.access_mut(&mut owner_inner); + + assert!(inner.delivery_state.has_pushed_node); + if inner.delivery_state.has_pushed_wrapper { + // If the wrapper is scheduled, then we are either a normal push or weak zero2one + // increment, and the wrapper is a strong zero2one increment, so the wrapper always + // takes precedence over us. + assert!(inner.delivery_state.has_strong_zero2one); + inner.delivery_state.has_pushed_node = false; + inner.delivery_state.has_weak_zero2one = false; + return Ok(true); + } + + inner.delivery_state.has_pushed_node = false; + inner.delivery_state.has_weak_zero2one = false; + inner.delivery_state.has_strong_zero2one = false; + + self.do_work_locked(writer, owner_inner) + } + + fn cancel(self: DArc) {} + + fn should_sync_wakeup(&self) -> bool { + false + } + + #[inline(never)] + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + seq_print!( + m, + "{}node work {}: u{:016x} c{:016x}\n", + prefix, + self.debug_id, + self.ptr, + self.cookie, + ); + Ok(()) + } +} + +/// Represents something that holds one or more ref-counts to a `Node`. +/// +/// Whenever process A holds a refcount to a node owned by a different process B, then process A +/// will store a `NodeRef` that refers to the `Node` in process B. When process A releases the +/// refcount, we destroy the NodeRef, which decrements the ref-count in process A. +/// +/// This type is also used for some other cases. For example, a transaction allocation holds a +/// refcount on the target node, and this is implemented by storing a `NodeRef` in the allocation +/// so that the destructor of the allocation will drop a refcount of the `Node`. +pub(crate) struct NodeRef { + pub(crate) node: DArc, + /// How many times does this NodeRef hold a refcount on the Node? + strong_node_count: usize, + weak_node_count: usize, + /// How many times does userspace hold a refcount on this NodeRef? + strong_count: usize, + weak_count: usize, +} + +impl NodeRef { + pub(crate) fn new(node: DArc, strong_count: usize, weak_count: usize) -> Self { + Self { + node, + strong_node_count: strong_count, + weak_node_count: weak_count, + strong_count, + weak_count, + } + } + + pub(crate) fn absorb(&mut self, mut other: Self) { + assert!( + Arc::ptr_eq(&self.node, &other.node), + "absorb called with differing nodes" + ); + self.strong_node_count += other.strong_node_count; + self.weak_node_count += other.weak_node_count; + self.strong_count += other.strong_count; + self.weak_count += other.weak_count; + other.strong_count = 0; + other.weak_count = 0; + other.strong_node_count = 0; + other.weak_node_count = 0; + + if self.strong_node_count >= 2 || self.weak_node_count >= 2 { + let mut guard = self.node.owner.inner.lock(); + let inner = self.node.inner.access_mut(&mut guard); + + if self.strong_node_count >= 2 { + inner.strong.count -= self.strong_node_count - 1; + self.strong_node_count = 1; + assert_ne!(inner.strong.count, 0); + } + if self.weak_node_count >= 2 { + inner.weak.count -= self.weak_node_count - 1; + self.weak_node_count = 1; + assert_ne!(inner.weak.count, 0); + } + } + } + + pub(crate) fn get_count(&self) -> (usize, usize) { + (self.strong_count, self.weak_count) + } + + pub(crate) fn clone(&self, strong: bool) -> Result { + if strong && self.strong_count == 0 { + return Err(EINVAL); + } + Ok(self + .node + .owner + .inner + .lock() + .new_node_ref(self.node.clone(), strong, None)) + } + + /// Updates (increments or decrements) the number of references held against the node. If the + /// count being updated transitions from 0 to 1 or from 1 to 0, the node is notified by having + /// its `update_refcount` function called. + /// + /// Returns whether `self` should be removed (when both counts are zero). + pub(crate) fn update(&mut self, inc: bool, strong: bool) -> bool { + if strong && self.strong_count == 0 { + return false; + } + let (count, node_count, other_count) = if strong { + ( + &mut self.strong_count, + &mut self.strong_node_count, + self.weak_count, + ) + } else { + ( + &mut self.weak_count, + &mut self.weak_node_count, + self.strong_count, + ) + }; + if inc { + if *count == 0 { + *node_count = 1; + self.node.update_refcount(true, 1, strong); + } + *count += 1; + } else { + if *count == 0 { + pr_warn!( + "pid {} performed invalid decrement on ref\n", + kernel::current!().pid() + ); + return false; + } + *count -= 1; + if *count == 0 { + self.node.update_refcount(false, *node_count, strong); + *node_count = 0; + return other_count == 0; + } + } + false + } +} + +impl Drop for NodeRef { + // This destructor is called conditionally from `Allocation::drop`. That branch is often + // mispredicted. Inlining this method call reduces the cost of those branch mispredictions. + #[inline(always)] + fn drop(&mut self) { + if self.strong_node_count > 0 { + self.node + .update_refcount(false, self.strong_node_count, true); + } + if self.weak_node_count > 0 { + self.node + .update_refcount(false, self.weak_node_count, false); + } + } +} + +struct NodeDeathInner { + dead: bool, + cleared: bool, + notification_done: bool, + /// Indicates whether the normal flow was interrupted by removing the handle. In this case, we + /// need behave as if the death notification didn't exist (i.e., we don't deliver anything to + /// the user. + aborted: bool, +} + +/// Used to deliver notifications when a process dies. +/// +/// A process can request to be notified when a process dies using `BC_REQUEST_DEATH_NOTIFICATION`. +/// This will make the driver send a `BR_DEAD_BINDER` to userspace when the process dies (or +/// immediately if it is already dead). Userspace is supposed to respond with `BC_DEAD_BINDER_DONE` +/// once it has processed the notification. +/// +/// Userspace can unregister from death notifications using the `BC_CLEAR_DEATH_NOTIFICATION` +/// command. In this case, the kernel will respond with `BR_CLEAR_DEATH_NOTIFICATION_DONE` once the +/// notification has been removed. Note that if the remote process dies before the kernel has +/// responded with `BR_CLEAR_DEATH_NOTIFICATION_DONE`, then the kernel will still send a +/// `BR_DEAD_BINDER`, which userspace must be able to process. In this case, the kernel will wait +/// for the `BC_DEAD_BINDER_DONE` command before it sends `BR_CLEAR_DEATH_NOTIFICATION_DONE`. +/// +/// Note that even if the kernel sends a `BR_DEAD_BINDER`, this does not remove the death +/// notification. Userspace must still remove it manually using `BC_CLEAR_DEATH_NOTIFICATION`. +/// +/// If a process uses `BC_RELEASE` to destroy its last refcount on a node that has an active death +/// registration, then the death registration is immediately deleted (we implement this using the +/// `aborted` field). However, userspace is not supposed to delete a `NodeRef` without first +/// deregistering death notifications, so this codepath is not executed under normal circumstances. +#[pin_data] +pub(crate) struct NodeDeath { + node: DArc, + process: Arc, + pub(crate) cookie: u64, + #[pin] + links_track: AtomicTracker<0>, + /// Used by the owner `Node` to store a list of registered death notifications. + /// + /// # Invariants + /// + /// Only ever used with the `death_list` list of `self.node`. + #[pin] + death_links: ListLinks<1>, + /// Used by the process to keep track of the death notifications for which we have sent a + /// `BR_DEAD_BINDER` but not yet received a `BC_DEAD_BINDER_DONE`. + /// + /// # Invariants + /// + /// Only ever used with the `delivered_deaths` list of `self.process`. + #[pin] + delivered_links: ListLinks<2>, + #[pin] + delivered_links_track: AtomicTracker<2>, + #[pin] + inner: SpinLock, +} + +impl NodeDeath { + /// Constructs a new node death notification object. + pub(crate) fn new( + node: DArc, + process: Arc, + cookie: u64, + ) -> impl PinInit> { + DTRWrap::new(pin_init!( + Self { + node, + process, + cookie, + links_track <- AtomicTracker::new(), + death_links <- ListLinks::new(), + delivered_links <- ListLinks::new(), + delivered_links_track <- AtomicTracker::new(), + inner <- kernel::new_spinlock!(NodeDeathInner { + dead: false, + cleared: false, + notification_done: false, + aborted: false, + }, "NodeDeath::inner"), + } + )) + } + + /// Sets the cleared flag to `true`. + /// + /// It removes `self` from the node's death notification list if needed. + /// + /// Returns whether it needs to be queued. + pub(crate) fn set_cleared(self: &DArc, abort: bool) -> bool { + let (needs_removal, needs_queueing) = { + // Update state and determine if we need to queue a work item. We only need to do it + // when the node is not dead or if the user already completed the death notification. + let mut inner = self.inner.lock(); + if abort { + inner.aborted = true; + } + if inner.cleared { + // Already cleared. + return false; + } + inner.cleared = true; + (!inner.dead, !inner.dead || inner.notification_done) + }; + + // Remove death notification from node. + if needs_removal { + let mut owner_inner = self.node.owner.inner.lock(); + let node_inner = self.node.inner.access_mut(&mut owner_inner); + // SAFETY: A `NodeDeath` is never inserted into the death list of any node other than + // its owner, so it is either in this death list or in no death list. + unsafe { node_inner.death_list.remove(self) }; + } + needs_queueing + } + + /// Sets the 'notification done' flag to `true`. + pub(crate) fn set_notification_done(self: DArc, thread: &Thread) { + let needs_queueing = { + let mut inner = self.inner.lock(); + inner.notification_done = true; + inner.cleared + }; + if needs_queueing { + if let Some(death) = ListArc::try_from_arc_or_drop(self) { + let _ = thread.push_work_if_looper(death); + } + } + } + + /// Sets the 'dead' flag to `true` and queues work item if needed. + pub(crate) fn set_dead(self: DArc) { + let needs_queueing = { + let mut inner = self.inner.lock(); + if inner.cleared { + false + } else { + inner.dead = true; + true + } + }; + if needs_queueing { + // Push the death notification to the target process. There is nothing else to do if + // it's already dead. + if let Some(death) = ListArc::try_from_arc_or_drop(self) { + let process = death.process.clone(); + let _ = process.push_work(death); + } + } + } +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<0> for NodeDeath { + tracked_by links_track: AtomicTracker; + } +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<1> for DTRWrap { untracked; } +} +kernel::list::impl_list_item! { + impl ListItem<1> for DTRWrap { + using ListLinks { self.wrapped.death_links }; + } +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<2> for DTRWrap { + tracked_by wrapped: NodeDeath; + } +} +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<2> for NodeDeath { + tracked_by delivered_links_track: AtomicTracker<2>; + } +} +kernel::list::impl_list_item! { + impl ListItem<2> for DTRWrap { + using ListLinks { self.wrapped.delivered_links }; + } +} + +impl DeliverToRead for NodeDeath { + fn do_work( + self: DArc, + _thread: &Thread, + writer: &mut BinderReturnWriter<'_>, + ) -> Result { + let done = { + let inner = self.inner.lock(); + if inner.aborted { + return Ok(true); + } + inner.cleared && (!inner.dead || inner.notification_done) + }; + + let cookie = self.cookie; + let cmd = if done { + BR_CLEAR_DEATH_NOTIFICATION_DONE + } else { + let process = self.process.clone(); + let mut process_inner = process.inner.lock(); + let inner = self.inner.lock(); + if inner.aborted { + return Ok(true); + } + // We're still holding the inner lock, so it cannot be aborted while we insert it into + // the delivered list. + process_inner.death_delivered(self.clone()); + BR_DEAD_BINDER + }; + + writer.write_code(cmd)?; + writer.write_payload(&cookie)?; + // DEAD_BINDER notifications can cause transactions, so stop processing work items when we + // get to a death notification. + Ok(cmd != BR_DEAD_BINDER) + } + + fn cancel(self: DArc) {} + + fn should_sync_wakeup(&self) -> bool { + false + } + + #[inline(never)] + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + let inner = self.inner.lock(); + + let dead_binder = inner.dead && !inner.notification_done; + + if dead_binder { + if inner.cleared { + seq_print!(m, "{}has cleared dead binder\n", prefix); + } else { + seq_print!(m, "{}has dead binder\n", prefix); + } + } else { + seq_print!(m, "{}has cleared death notification\n", prefix); + } + + Ok(()) + } +} diff --git a/drivers/android/binder/node/wrapper.rs b/drivers/android/binder/node/wrapper.rs new file mode 100644 index 000000000000..43294c050502 --- /dev/null +++ b/drivers/android/binder/node/wrapper.rs @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use kernel::{list::ListArc, prelude::*, seq_file::SeqFile, seq_print, sync::UniqueArc}; + +use crate::{node::Node, thread::Thread, BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverToRead}; + +use core::mem::MaybeUninit; + +pub(crate) struct CritIncrWrapper { + inner: UniqueArc>>, +} + +impl CritIncrWrapper { + pub(crate) fn new() -> Result { + Ok(CritIncrWrapper { + inner: UniqueArc::new_uninit(GFP_KERNEL)?, + }) + } + + pub(super) fn init(self, node: DArc) -> DLArc { + match self.inner.pin_init_with(DTRWrap::new(NodeWrapper { node })) { + Ok(initialized) => ListArc::from(initialized) as _, + Err(err) => match err {}, + } + } +} + +struct NodeWrapper { + node: DArc, +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<0> for NodeWrapper { + untracked; + } +} + +impl DeliverToRead for NodeWrapper { + fn do_work( + self: DArc, + _thread: &Thread, + writer: &mut BinderReturnWriter<'_>, + ) -> Result { + let node = &self.node; + let mut owner_inner = node.owner.inner.lock(); + let inner = node.inner.access_mut(&mut owner_inner); + + let ds = &mut inner.delivery_state; + + assert!(ds.has_pushed_wrapper); + assert!(ds.has_strong_zero2one); + ds.has_pushed_wrapper = false; + ds.has_strong_zero2one = false; + + node.do_work_locked(writer, owner_inner) + } + + fn cancel(self: DArc) {} + + fn should_sync_wakeup(&self) -> bool { + false + } + + #[inline(never)] + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + seq_print!( + m, + "{}node work {}: u{:016x} c{:016x}\n", + prefix, + self.node.debug_id, + self.node.ptr, + self.node.cookie, + ); + Ok(()) + } +} diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/page_range.rs new file mode 100644 index 000000000000..9379038f61f5 --- /dev/null +++ b/drivers/android/binder/page_range.rs @@ -0,0 +1,734 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! This module has utilities for managing a page range where unused pages may be reclaimed by a +//! vma shrinker. + +// To avoid deadlocks, locks are taken in the order: +// +// 1. mmap lock +// 2. spinlock +// 3. lru spinlock +// +// The shrinker will use trylock methods because it locks them in a different order. + +use core::{ + marker::PhantomPinned, + mem::{size_of, size_of_val, MaybeUninit}, + ptr, +}; + +use kernel::{ + bindings, + error::Result, + ffi::{c_ulong, c_void}, + mm::{virt, Mm, MmWithUser}, + new_mutex, new_spinlock, + page::{Page, PAGE_SHIFT, PAGE_SIZE}, + prelude::*, + str::CStr, + sync::{aref::ARef, Mutex, SpinLock}, + task::Pid, + transmute::FromBytes, + types::Opaque, + uaccess::UserSliceReader, +}; + +/// Represents a shrinker that can be registered with the kernel. +/// +/// Each shrinker can be used by many `ShrinkablePageRange` objects. +#[repr(C)] +pub(crate) struct Shrinker { + inner: Opaque<*mut bindings::shrinker>, + list_lru: Opaque, +} + +// SAFETY: The shrinker and list_lru are thread safe. +unsafe impl Send for Shrinker {} +// SAFETY: The shrinker and list_lru are thread safe. +unsafe impl Sync for Shrinker {} + +impl Shrinker { + /// Create a new shrinker. + /// + /// # Safety + /// + /// Before using this shrinker with a `ShrinkablePageRange`, the `register` method must have + /// been called exactly once, and it must not have returned an error. + pub(crate) const unsafe fn new() -> Self { + Self { + inner: Opaque::uninit(), + list_lru: Opaque::uninit(), + } + } + + /// Register this shrinker with the kernel. + pub(crate) fn register(&'static self, name: &CStr) -> Result<()> { + // SAFETY: These fields are not yet used, so it's okay to zero them. + unsafe { + self.inner.get().write(ptr::null_mut()); + self.list_lru.get().write_bytes(0, 1); + } + + // SAFETY: The field is not yet used, so we can initialize it. + let ret = unsafe { bindings::__list_lru_init(self.list_lru.get(), false, ptr::null_mut()) }; + if ret != 0 { + return Err(Error::from_errno(ret)); + } + + // SAFETY: The `name` points at a valid c string. + let shrinker = unsafe { bindings::shrinker_alloc(0, name.as_char_ptr()) }; + if shrinker.is_null() { + // SAFETY: We initialized it, so its okay to destroy it. + unsafe { bindings::list_lru_destroy(self.list_lru.get()) }; + return Err(Error::from_errno(ret)); + } + + // SAFETY: We're about to register the shrinker, and these are the fields we need to + // initialize. (All other fields are already zeroed.) + unsafe { + (&raw mut (*shrinker).count_objects).write(Some(rust_shrink_count)); + (&raw mut (*shrinker).scan_objects).write(Some(rust_shrink_scan)); + (&raw mut (*shrinker).private_data).write(self.list_lru.get().cast()); + } + + // SAFETY: The new shrinker has been fully initialized, so we can register it. + unsafe { bindings::shrinker_register(shrinker) }; + + // SAFETY: This initializes the pointer to the shrinker so that we can use it. + unsafe { self.inner.get().write(shrinker) }; + + Ok(()) + } +} + +/// A container that manages a page range in a vma. +/// +/// The pages can be thought of as an array of booleans of whether the pages are usable. The +/// methods `use_range` and `stop_using_range` set all booleans in a range to true or false +/// respectively. Initially, no pages are allocated. When a page is not used, it is not freed +/// immediately. Instead, it is made available to the memory shrinker to free it if the device is +/// under memory pressure. +/// +/// It's okay for `use_range` and `stop_using_range` to race with each other, although there's no +/// way to know whether an index ends up with true or false if a call to `use_range` races with +/// another call to `stop_using_range` on a given index. +/// +/// It's also okay for the two methods to race with themselves, e.g. if two threads call +/// `use_range` on the same index, then that's fine and neither call will return until the page is +/// allocated and mapped. +/// +/// The methods that read or write to a range require that the page is marked as in use. So it is +/// _not_ okay to call `stop_using_range` on a page that is in use by the methods that read or +/// write to the page. +#[pin_data(PinnedDrop)] +pub(crate) struct ShrinkablePageRange { + /// Shrinker object registered with the kernel. + shrinker: &'static Shrinker, + /// Pid using this page range. Only used as debugging information. + pid: Pid, + /// The mm for the relevant process. + mm: ARef, + /// Used to synchronize calls to `vm_insert_page` and `zap_page_range_single`. + #[pin] + mm_lock: Mutex<()>, + /// Spinlock protecting changes to pages. + #[pin] + lock: SpinLock, + + /// Must not move, since page info has pointers back. + #[pin] + _pin: PhantomPinned, +} + +struct Inner { + /// Array of pages. + /// + /// Since this is also accessed by the shrinker, we can't use a `Box`, which asserts exclusive + /// ownership. To deal with that, we manage it using raw pointers. + pages: *mut PageInfo, + /// Length of the `pages` array. + size: usize, + /// The address of the vma to insert the pages into. + vma_addr: usize, +} + +// SAFETY: proper locking is in place for `Inner` +unsafe impl Send for Inner {} + +type StableMmGuard = + kernel::sync::lock::Guard<'static, (), kernel::sync::lock::mutex::MutexBackend>; + +/// An array element that describes the current state of a page. +/// +/// There are three states: +/// +/// * Free. The page is None. The `lru` element is not queued. +/// * Available. The page is Some. The `lru` element is queued to the shrinker's lru. +/// * Used. The page is Some. The `lru` element is not queued. +/// +/// When an element is available, the shrinker is able to free the page. +#[repr(C)] +struct PageInfo { + lru: bindings::list_head, + page: Option, + range: *const ShrinkablePageRange, +} + +impl PageInfo { + /// # Safety + /// + /// The caller ensures that writing to `me.page` is ok, and that the page is not currently set. + unsafe fn set_page(me: *mut PageInfo, page: Page) { + // SAFETY: This pointer offset is in bounds. + let ptr = unsafe { &raw mut (*me).page }; + + // SAFETY: The pointer is valid for writing, so also valid for reading. + if unsafe { (*ptr).is_some() } { + pr_err!("set_page called when there is already a page"); + // SAFETY: We will initialize the page again below. + unsafe { ptr::drop_in_place(ptr) }; + } + + // SAFETY: The pointer is valid for writing. + unsafe { ptr::write(ptr, Some(page)) }; + } + + /// # Safety + /// + /// The caller ensures that reading from `me.page` is ok for the duration of 'a. + unsafe fn get_page<'a>(me: *const PageInfo) -> Option<&'a Page> { + // SAFETY: This pointer offset is in bounds. + let ptr = unsafe { &raw const (*me).page }; + + // SAFETY: The pointer is valid for reading. + unsafe { (*ptr).as_ref() } + } + + /// # Safety + /// + /// The caller ensures that writing to `me.page` is ok for the duration of 'a. + unsafe fn take_page(me: *mut PageInfo) -> Option { + // SAFETY: This pointer offset is in bounds. + let ptr = unsafe { &raw mut (*me).page }; + + // SAFETY: The pointer is valid for reading. + unsafe { (*ptr).take() } + } + + /// Add this page to the lru list, if not already in the list. + /// + /// # Safety + /// + /// The pointer must be valid, and it must be the right shrinker and nid. + unsafe fn list_lru_add(me: *mut PageInfo, nid: i32, shrinker: &'static Shrinker) { + // SAFETY: This pointer offset is in bounds. + let lru_ptr = unsafe { &raw mut (*me).lru }; + // SAFETY: The lru pointer is valid, and we're not using it with any other lru list. + unsafe { bindings::list_lru_add(shrinker.list_lru.get(), lru_ptr, nid, ptr::null_mut()) }; + } + + /// Remove this page from the lru list, if it is in the list. + /// + /// # Safety + /// + /// The pointer must be valid, and it must be the right shrinker and nid. + unsafe fn list_lru_del(me: *mut PageInfo, nid: i32, shrinker: &'static Shrinker) { + // SAFETY: This pointer offset is in bounds. + let lru_ptr = unsafe { &raw mut (*me).lru }; + // SAFETY: The lru pointer is valid, and we're not using it with any other lru list. + unsafe { bindings::list_lru_del(shrinker.list_lru.get(), lru_ptr, nid, ptr::null_mut()) }; + } +} + +impl ShrinkablePageRange { + /// Create a new `ShrinkablePageRange` using the given shrinker. + pub(crate) fn new(shrinker: &'static Shrinker) -> impl PinInit { + try_pin_init!(Self { + shrinker, + pid: kernel::current!().pid(), + mm: ARef::from(&**kernel::current!().mm().ok_or(ESRCH)?), + mm_lock <- new_mutex!((), "ShrinkablePageRange::mm"), + lock <- new_spinlock!(Inner { + pages: ptr::null_mut(), + size: 0, + vma_addr: 0, + }, "ShrinkablePageRange"), + _pin: PhantomPinned, + }) + } + + pub(crate) fn stable_trylock_mm(&self) -> Option { + // SAFETY: This extends the duration of the reference. Since this call happens before + // `mm_lock` is taken in the destructor of `ShrinkablePageRange`, the destructor will block + // until the returned guard is dropped. This ensures that the guard is valid until dropped. + let mm_lock = unsafe { &*ptr::from_ref(&self.mm_lock) }; + + mm_lock.try_lock() + } + + /// Register a vma with this page range. Returns the size of the region. + pub(crate) fn register_with_vma(&self, vma: &virt::VmaNew) -> Result { + let num_bytes = usize::min(vma.end() - vma.start(), bindings::SZ_4M as usize); + let num_pages = num_bytes >> PAGE_SHIFT; + + if !ptr::eq::(&*self.mm, &**vma.mm()) { + pr_debug!("Failed to register with vma: invalid vma->vm_mm"); + return Err(EINVAL); + } + if num_pages == 0 { + pr_debug!("Failed to register with vma: size zero"); + return Err(EINVAL); + } + + let mut pages = KVVec::::with_capacity(num_pages, GFP_KERNEL)?; + + // SAFETY: This just initializes the pages array. + unsafe { + let self_ptr = self as *const ShrinkablePageRange; + for i in 0..num_pages { + let info = pages.as_mut_ptr().add(i); + (&raw mut (*info).range).write(self_ptr); + (&raw mut (*info).page).write(None); + let lru = &raw mut (*info).lru; + (&raw mut (*lru).next).write(lru); + (&raw mut (*lru).prev).write(lru); + } + } + + let mut inner = self.lock.lock(); + if inner.size > 0 { + pr_debug!("Failed to register with vma: already registered"); + drop(inner); + return Err(EBUSY); + } + + inner.pages = pages.into_raw_parts().0; + inner.size = num_pages; + inner.vma_addr = vma.start(); + + Ok(num_pages) + } + + /// Make sure that the given pages are allocated and mapped. + /// + /// Must not be called from an atomic context. + pub(crate) fn use_range(&self, start: usize, end: usize) -> Result<()> { + if start >= end { + return Ok(()); + } + let mut inner = self.lock.lock(); + assert!(end <= inner.size); + + for i in start..end { + // SAFETY: This pointer offset is in bounds. + let page_info = unsafe { inner.pages.add(i) }; + + // SAFETY: The pointer is valid, and we hold the lock so reading from the page is okay. + if let Some(page) = unsafe { PageInfo::get_page(page_info) } { + // Since we're going to use the page, we should remove it from the lru list so that + // the shrinker will not free it. + // + // SAFETY: The pointer is valid, and this is the right shrinker. + // + // The shrinker can't free the page between the check and this call to + // `list_lru_del` because we hold the lock. + unsafe { PageInfo::list_lru_del(page_info, page.nid(), self.shrinker) }; + } else { + // We have to allocate a new page. Use the slow path. + drop(inner); + // SAFETY: `i < end <= inner.size` so `i` is in bounds. + match unsafe { self.use_page_slow(i) } { + Ok(()) => {} + Err(err) => { + pr_warn!("Error in use_page_slow: {:?}", err); + return Err(err); + } + } + inner = self.lock.lock(); + } + } + Ok(()) + } + + /// Mark the given page as in use, slow path. + /// + /// Must not be called from an atomic context. + /// + /// # Safety + /// + /// Assumes that `i` is in bounds. + #[cold] + unsafe fn use_page_slow(&self, i: usize) -> Result<()> { + let new_page = Page::alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO)?; + + let mm_mutex = self.mm_lock.lock(); + let inner = self.lock.lock(); + + // SAFETY: This pointer offset is in bounds. + let page_info = unsafe { inner.pages.add(i) }; + + // SAFETY: The pointer is valid, and we hold the lock so reading from the page is okay. + if let Some(page) = unsafe { PageInfo::get_page(page_info) } { + // The page was already there, or someone else added the page while we didn't hold the + // spinlock. + // + // SAFETY: The pointer is valid, and this is the right shrinker. + // + // The shrinker can't free the page between the check and this call to + // `list_lru_del` because we hold the lock. + unsafe { PageInfo::list_lru_del(page_info, page.nid(), self.shrinker) }; + return Ok(()); + } + + let vma_addr = inner.vma_addr; + // Release the spinlock while we insert the page into the vma. + drop(inner); + + // No overflow since we stay in bounds of the vma. + let user_page_addr = vma_addr + (i << PAGE_SHIFT); + + // We use `mmput_async` when dropping the `mm` because `use_page_slow` is usually used from + // a remote process. If the call to `mmput` races with the process shutting down, then the + // caller of `use_page_slow` becomes responsible for cleaning up the `mm`, which doesn't + // happen until it returns to userspace. However, the caller might instead go to sleep and + // wait for the owner of the `mm` to wake it up, which doesn't happen because it's in the + // middle of a shutdown process that won't complete until the `mm` is dropped. This can + // amount to a deadlock. + // + // Using `mmput_async` avoids this, because then the `mm` cleanup is instead queued to a + // workqueue. + MmWithUser::into_mmput_async(self.mm.mmget_not_zero().ok_or(ESRCH)?) + .mmap_read_lock() + .vma_lookup(vma_addr) + .ok_or(ESRCH)? + .as_mixedmap_vma() + .ok_or(ESRCH)? + .vm_insert_page(user_page_addr, &new_page) + .inspect_err(|err| { + pr_warn!( + "Failed to vm_insert_page({}): vma_addr:{} i:{} err:{:?}", + user_page_addr, + vma_addr, + i, + err + ) + })?; + + let inner = self.lock.lock(); + + // SAFETY: The `page_info` pointer is valid and currently does not have a page. The page + // can be written to since we hold the lock. + // + // We released and reacquired the spinlock since we checked that the page is null, but we + // always hold the mm_lock mutex when setting the page to a non-null value, so it's not + // possible for someone else to have changed it since our check. + unsafe { PageInfo::set_page(page_info, new_page) }; + + drop(inner); + drop(mm_mutex); + + Ok(()) + } + + /// If the given page is in use, then mark it as available so that the shrinker can free it. + /// + /// May be called from an atomic context. + pub(crate) fn stop_using_range(&self, start: usize, end: usize) { + if start >= end { + return; + } + let inner = self.lock.lock(); + assert!(end <= inner.size); + + for i in (start..end).rev() { + // SAFETY: The pointer is in bounds. + let page_info = unsafe { inner.pages.add(i) }; + + // SAFETY: Okay for reading since we have the lock. + if let Some(page) = unsafe { PageInfo::get_page(page_info) } { + // SAFETY: The pointer is valid, and it's the right shrinker. + unsafe { PageInfo::list_lru_add(page_info, page.nid(), self.shrinker) }; + } + } + } + + /// Helper for reading or writing to a range of bytes that may overlap with several pages. + /// + /// # Safety + /// + /// All pages touched by this operation must be in use for the duration of this call. + unsafe fn iterate(&self, mut offset: usize, mut size: usize, mut cb: T) -> Result + where + T: FnMut(&Page, usize, usize) -> Result, + { + if size == 0 { + return Ok(()); + } + + let (pages, num_pages) = { + let inner = self.lock.lock(); + (inner.pages, inner.size) + }; + let num_bytes = num_pages << PAGE_SHIFT; + + // Check that the request is within the buffer. + if offset.checked_add(size).ok_or(EFAULT)? > num_bytes { + return Err(EFAULT); + } + + let mut page_index = offset >> PAGE_SHIFT; + offset &= PAGE_SIZE - 1; + while size > 0 { + let available = usize::min(size, PAGE_SIZE - offset); + // SAFETY: The pointer is in bounds. + let page_info = unsafe { pages.add(page_index) }; + // SAFETY: The caller guarantees that this page is in the "in use" state for the + // duration of this call to `iterate`, so nobody will change the page. + let page = unsafe { PageInfo::get_page(page_info) }; + if page.is_none() { + pr_warn!("Page is null!"); + } + let page = page.ok_or(EFAULT)?; + cb(page, offset, available)?; + size -= available; + page_index += 1; + offset = 0; + } + Ok(()) + } + + /// Copy from userspace into this page range. + /// + /// # Safety + /// + /// All pages touched by this operation must be in use for the duration of this call. + pub(crate) unsafe fn copy_from_user_slice( + &self, + reader: &mut UserSliceReader, + offset: usize, + size: usize, + ) -> Result { + // SAFETY: `self.iterate` has the same safety requirements as `copy_from_user_slice`. + unsafe { + self.iterate(offset, size, |page, offset, to_copy| { + page.copy_from_user_slice_raw(reader, offset, to_copy) + }) + } + } + + /// Copy from this page range into kernel space. + /// + /// # Safety + /// + /// All pages touched by this operation must be in use for the duration of this call. + pub(crate) unsafe fn read(&self, offset: usize) -> Result { + let mut out = MaybeUninit::::uninit(); + let mut out_offset = 0; + // SAFETY: `self.iterate` has the same safety requirements as `read`. + unsafe { + self.iterate(offset, size_of::(), |page, offset, to_copy| { + // SAFETY: The sum of `offset` and `to_copy` is bounded by the size of T. + let obj_ptr = (out.as_mut_ptr() as *mut u8).add(out_offset); + // SAFETY: The pointer points is in-bounds of the `out` variable, so it is valid. + page.read_raw(obj_ptr, offset, to_copy)?; + out_offset += to_copy; + Ok(()) + })?; + } + // SAFETY: We just initialised the data. + Ok(unsafe { out.assume_init() }) + } + + /// Copy from kernel space into this page range. + /// + /// # Safety + /// + /// All pages touched by this operation must be in use for the duration of this call. + pub(crate) unsafe fn write(&self, offset: usize, obj: &T) -> Result { + let mut obj_offset = 0; + // SAFETY: `self.iterate` has the same safety requirements as `write`. + unsafe { + self.iterate(offset, size_of_val(obj), |page, offset, to_copy| { + // SAFETY: The sum of `offset` and `to_copy` is bounded by the size of T. + let obj_ptr = (obj as *const T as *const u8).add(obj_offset); + // SAFETY: We have a reference to the object, so the pointer is valid. + page.write_raw(obj_ptr, offset, to_copy)?; + obj_offset += to_copy; + Ok(()) + }) + } + } + + /// Write zeroes to the given range. + /// + /// # Safety + /// + /// All pages touched by this operation must be in use for the duration of this call. + pub(crate) unsafe fn fill_zero(&self, offset: usize, size: usize) -> Result { + // SAFETY: `self.iterate` has the same safety requirements as `copy_into`. + unsafe { + self.iterate(offset, size, |page, offset, len| { + page.fill_zero_raw(offset, len) + }) + } + } +} + +#[pinned_drop] +impl PinnedDrop for ShrinkablePageRange { + fn drop(self: Pin<&mut Self>) { + let (pages, size) = { + let lock = self.lock.lock(); + (lock.pages, lock.size) + }; + + if size == 0 { + return; + } + + // Note: This call is also necessary for the safety of `stable_trylock_mm`. + let mm_lock = self.mm_lock.lock(); + + // This is the destructor, so unlike the other methods, we only need to worry about races + // with the shrinker here. Since we hold the `mm_lock`, we also can't race with the + // shrinker, and after this loop, the shrinker will not access any of our pages since we + // removed them from the lru list. + for i in 0..size { + // SAFETY: Loop is in-bounds of the size. + let p_ptr = unsafe { pages.add(i) }; + // SAFETY: No other readers, so we can read. + if let Some(p) = unsafe { PageInfo::get_page(p_ptr) } { + // SAFETY: The pointer is valid and it's the right shrinker. + unsafe { PageInfo::list_lru_del(p_ptr, p.nid(), self.shrinker) }; + } + } + + drop(mm_lock); + + // SAFETY: `pages` was allocated as an `KVVec` with capacity `size`. Furthermore, + // all `size` elements are initialized. Also, the array is no longer shared with the + // shrinker due to the above loop. + drop(unsafe { KVVec::from_raw_parts(pages, size, size) }); + } +} + +/// # Safety +/// Called by the shrinker. +#[no_mangle] +unsafe extern "C" fn rust_shrink_count( + shrink: *mut bindings::shrinker, + _sc: *mut bindings::shrink_control, +) -> c_ulong { + // SAFETY: We can access our own private data. + let list_lru = unsafe { (*shrink).private_data.cast::() }; + // SAFETY: Accessing the lru list is okay. Just an FFI call. + unsafe { bindings::list_lru_count(list_lru) } +} + +/// # Safety +/// Called by the shrinker. +#[no_mangle] +unsafe extern "C" fn rust_shrink_scan( + shrink: *mut bindings::shrinker, + sc: *mut bindings::shrink_control, +) -> c_ulong { + // SAFETY: We can access our own private data. + let list_lru = unsafe { (*shrink).private_data.cast::() }; + // SAFETY: Caller guarantees that it is safe to read this field. + let nr_to_scan = unsafe { (*sc).nr_to_scan }; + // SAFETY: Accessing the lru list is okay. Just an FFI call. + unsafe { + bindings::list_lru_walk( + list_lru, + Some(bindings::rust_shrink_free_page_wrap), + ptr::null_mut(), + nr_to_scan, + ) + } +} + +const LRU_SKIP: bindings::lru_status = bindings::lru_status_LRU_SKIP; +const LRU_REMOVED_ENTRY: bindings::lru_status = bindings::lru_status_LRU_REMOVED_RETRY; + +/// # Safety +/// Called by the shrinker. +#[no_mangle] +unsafe extern "C" fn rust_shrink_free_page( + item: *mut bindings::list_head, + lru: *mut bindings::list_lru_one, + _cb_arg: *mut c_void, +) -> bindings::lru_status { + // Fields that should survive after unlocking the lru lock. + let page; + let page_index; + let mm; + let mmap_read; + let mm_mutex; + let vma_addr; + + { + // CAST: The `list_head` field is first in `PageInfo`. + let info = item as *mut PageInfo; + // SAFETY: The `range` field of `PageInfo` is immutable. + let range = unsafe { &*((*info).range) }; + + mm = match range.mm.mmget_not_zero() { + Some(mm) => MmWithUser::into_mmput_async(mm), + None => return LRU_SKIP, + }; + + mm_mutex = match range.stable_trylock_mm() { + Some(guard) => guard, + None => return LRU_SKIP, + }; + + mmap_read = match mm.mmap_read_trylock() { + Some(guard) => guard, + None => return LRU_SKIP, + }; + + // We can't lock it normally here, since we hold the lru lock. + let inner = match range.lock.try_lock() { + Some(inner) => inner, + None => return LRU_SKIP, + }; + + // SAFETY: The item is in this lru list, so it's okay to remove it. + unsafe { bindings::list_lru_isolate(lru, item) }; + + // SAFETY: Both pointers are in bounds of the same allocation. + page_index = unsafe { info.offset_from(inner.pages) } as usize; + + // SAFETY: We hold the spinlock, so we can take the page. + // + // This sets the page pointer to zero before we unmap it from the vma. However, we call + // `zap_page_range` before we release the mmap lock, so `use_page_slow` will not be able to + // insert a new page until after our call to `zap_page_range`. + page = unsafe { PageInfo::take_page(info) }; + vma_addr = inner.vma_addr; + + // From this point on, we don't access this PageInfo or ShrinkablePageRange again, because + // they can be freed at any point after we unlock `lru_lock`. This is with the exception of + // `mm_mutex` which is kept alive by holding the lock. + } + + // SAFETY: The lru lock is locked when this method is called. + unsafe { bindings::spin_unlock(&raw mut (*lru).lock) }; + + if let Some(vma) = mmap_read.vma_lookup(vma_addr) { + let user_page_addr = vma_addr + (page_index << PAGE_SHIFT); + vma.zap_page_range_single(user_page_addr, PAGE_SIZE); + } + + drop(mmap_read); + drop(mm_mutex); + drop(mm); + drop(page); + + // SAFETY: We just unlocked the lru lock, but it should be locked when we return. + unsafe { bindings::spin_lock(&raw mut (*lru).lock) }; + + LRU_REMOVED_ENTRY +} diff --git a/drivers/android/binder/page_range_helper.c b/drivers/android/binder/page_range_helper.c new file mode 100644 index 000000000000..496887723ee0 --- /dev/null +++ b/drivers/android/binder/page_range_helper.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* C helper for page_range.rs to work around a CFI violation. + * + * Bindgen currently pretends that `enum lru_status` is the same as an integer. + * This assumption is fine ABI-wise, but once you add CFI to the mix, it + * triggers a CFI violation because `enum lru_status` gets a different CFI tag. + * + * This file contains a workaround until bindgen can be fixed. + * + * Copyright (C) 2025 Google LLC. + */ +#include "page_range_helper.h" + +unsigned int rust_shrink_free_page(struct list_head *item, + struct list_lru_one *list, + void *cb_arg); + +enum lru_status +rust_shrink_free_page_wrap(struct list_head *item, struct list_lru_one *list, + void *cb_arg) +{ + return rust_shrink_free_page(item, list, cb_arg); +} diff --git a/drivers/android/binder/page_range_helper.h b/drivers/android/binder/page_range_helper.h new file mode 100644 index 000000000000..18dd2dd117b2 --- /dev/null +++ b/drivers/android/binder/page_range_helper.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Google, Inc. + */ + +#ifndef _LINUX_PAGE_RANGE_HELPER_H +#define _LINUX_PAGE_RANGE_HELPER_H + +#include + +enum lru_status +rust_shrink_free_page_wrap(struct list_head *item, struct list_lru_one *list, + void *cb_arg); + +#endif /* _LINUX_PAGE_RANGE_HELPER_H */ diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs new file mode 100644 index 000000000000..f13a747e784c --- /dev/null +++ b/drivers/android/binder/process.rs @@ -0,0 +1,1696 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! This module defines the `Process` type, which represents a process using a particular binder +//! context. +//! +//! The `Process` object keeps track of all of the resources that this process owns in the binder +//! context. +//! +//! There is one `Process` object for each binder fd that a process has opened, so processes using +//! several binder contexts have several `Process` objects. This ensures that the contexts are +//! fully separated. + +use core::mem::take; + +use kernel::{ + bindings, + cred::Credential, + error::Error, + fs::file::{self, File}, + list::{List, ListArc, ListArcField, ListLinks}, + mm, + prelude::*, + rbtree::{self, RBTree, RBTreeNode, RBTreeNodeReservation}, + seq_file::SeqFile, + seq_print, + sync::poll::PollTable, + sync::{ + lock::{spinlock::SpinLockBackend, Guard}, + Arc, ArcBorrow, CondVar, CondVarTimeoutResult, Mutex, SpinLock, UniqueArc, + }, + task::Task, + types::ARef, + uaccess::{UserSlice, UserSliceReader}, + uapi, + workqueue::{self, Work}, +}; + +use crate::{ + allocation::{Allocation, AllocationInfo, NewAllocation}, + context::Context, + defs::*, + error::{BinderError, BinderResult}, + node::{CouldNotDeliverCriticalIncrement, CritIncrWrapper, Node, NodeDeath, NodeRef}, + page_range::ShrinkablePageRange, + range_alloc::{RangeAllocator, ReserveNew, ReserveNewArgs}, + stats::BinderStats, + thread::{PushWorkRes, Thread}, + BinderfsProcFile, DArc, DLArc, DTRWrap, DeliverToRead, +}; + +#[path = "freeze.rs"] +mod freeze; +use self::freeze::{FreezeCookie, FreezeListener}; + +struct Mapping { + address: usize, + alloc: RangeAllocator, +} + +impl Mapping { + fn new(address: usize, size: usize) -> Self { + Self { + address, + alloc: RangeAllocator::new(size), + } + } +} + +// bitflags for defer_work. +const PROC_DEFER_FLUSH: u8 = 1; +const PROC_DEFER_RELEASE: u8 = 2; + +/// The fields of `Process` protected by the spinlock. +pub(crate) struct ProcessInner { + is_manager: bool, + pub(crate) is_dead: bool, + threads: RBTree>, + /// INVARIANT: Threads pushed to this list must be owned by this process. + ready_threads: List, + nodes: RBTree>, + mapping: Option, + work: List>, + delivered_deaths: List, 2>, + + /// The number of requested threads that haven't registered yet. + requested_thread_count: u32, + /// The maximum number of threads used by the process thread pool. + max_threads: u32, + /// The number of threads the started and registered with the thread pool. + started_thread_count: u32, + + /// Bitmap of deferred work to do. + defer_work: u8, + + /// Number of transactions to be transmitted before processes in freeze_wait + /// are woken up. + outstanding_txns: u32, + /// Process is frozen and unable to service binder transactions. + pub(crate) is_frozen: bool, + /// Process received sync transactions since last frozen. + pub(crate) sync_recv: bool, + /// Process received async transactions since last frozen. + pub(crate) async_recv: bool, + pub(crate) binderfs_file: Option, + /// Check for oneway spam + oneway_spam_detection_enabled: bool, +} + +impl ProcessInner { + fn new() -> Self { + Self { + is_manager: false, + is_dead: false, + threads: RBTree::new(), + ready_threads: List::new(), + mapping: None, + nodes: RBTree::new(), + work: List::new(), + delivered_deaths: List::new(), + requested_thread_count: 0, + max_threads: 0, + started_thread_count: 0, + defer_work: 0, + outstanding_txns: 0, + is_frozen: false, + sync_recv: false, + async_recv: false, + binderfs_file: None, + oneway_spam_detection_enabled: false, + } + } + + /// Schedule the work item for execution on this process. + /// + /// If any threads are ready for work, then the work item is given directly to that thread and + /// it is woken up. Otherwise, it is pushed to the process work list. + /// + /// This call can fail only if the process is dead. In this case, the work item is returned to + /// the caller so that the caller can drop it after releasing the inner process lock. This is + /// necessary since the destructor of `Transaction` will take locks that can't necessarily be + /// taken while holding the inner process lock. + pub(crate) fn push_work( + &mut self, + work: DLArc, + ) -> Result<(), (BinderError, DLArc)> { + // Try to find a ready thread to which to push the work. + if let Some(thread) = self.ready_threads.pop_front() { + // Push to thread while holding state lock. This prevents the thread from giving up + // (for example, because of a signal) when we're about to deliver work. + match thread.push_work(work) { + PushWorkRes::Ok => Ok(()), + PushWorkRes::FailedDead(work) => Err((BinderError::new_dead(), work)), + } + } else if self.is_dead { + Err((BinderError::new_dead(), work)) + } else { + let sync = work.should_sync_wakeup(); + + // Didn't find a thread waiting for proc work; this can happen + // in two scenarios: + // 1. All threads are busy handling transactions + // In that case, one of those threads should call back into + // the kernel driver soon and pick up this work. + // 2. Threads are using the (e)poll interface, in which case + // they may be blocked on the waitqueue without having been + // added to waiting_threads. For this case, we just iterate + // over all threads not handling transaction work, and + // wake them all up. We wake all because we don't know whether + // a thread that called into (e)poll is handling non-binder + // work currently. + self.work.push_back(work); + + // Wake up polling threads, if any. + for thread in self.threads.values() { + thread.notify_if_poll_ready(sync); + } + + Ok(()) + } + } + + pub(crate) fn remove_node(&mut self, ptr: u64) { + self.nodes.remove(&ptr); + } + + /// Updates the reference count on the given node. + pub(crate) fn update_node_refcount( + &mut self, + node: &DArc, + inc: bool, + strong: bool, + count: usize, + othread: Option<&Thread>, + ) { + let push = node.update_refcount_locked(inc, strong, count, self); + + // If we decided that we need to push work, push either to the process or to a thread if + // one is specified. + if let Some(node) = push { + if let Some(thread) = othread { + thread.push_work_deferred(node); + } else { + let _ = self.push_work(node); + // Nothing to do: `push_work` may fail if the process is dead, but that's ok as in + // that case, it doesn't care about the notification. + } + } + } + + pub(crate) fn new_node_ref( + &mut self, + node: DArc, + strong: bool, + thread: Option<&Thread>, + ) -> NodeRef { + self.update_node_refcount(&node, true, strong, 1, thread); + let strong_count = if strong { 1 } else { 0 }; + NodeRef::new(node, strong_count, 1 - strong_count) + } + + pub(crate) fn new_node_ref_with_thread( + &mut self, + node: DArc, + strong: bool, + thread: &Thread, + wrapper: Option, + ) -> Result { + let push = match wrapper { + None => node + .incr_refcount_allow_zero2one(strong, self)? + .map(|node| node as _), + Some(wrapper) => node.incr_refcount_allow_zero2one_with_wrapper(strong, wrapper, self), + }; + if let Some(node) = push { + thread.push_work_deferred(node); + } + let strong_count = if strong { 1 } else { 0 }; + Ok(NodeRef::new(node, strong_count, 1 - strong_count)) + } + + /// Returns an existing node with the given pointer and cookie, if one exists. + /// + /// Returns an error if a node with the given pointer but a different cookie exists. + fn get_existing_node(&self, ptr: u64, cookie: u64) -> Result>> { + match self.nodes.get(&ptr) { + None => Ok(None), + Some(node) => { + let (_, node_cookie) = node.get_id(); + if node_cookie == cookie { + Ok(Some(node.clone())) + } else { + Err(EINVAL) + } + } + } + } + + fn register_thread(&mut self) -> bool { + if self.requested_thread_count == 0 { + return false; + } + + self.requested_thread_count -= 1; + self.started_thread_count += 1; + true + } + + /// Finds a delivered death notification with the given cookie, removes it from the thread's + /// delivered list, and returns it. + fn pull_delivered_death(&mut self, cookie: u64) -> Option> { + let mut cursor = self.delivered_deaths.cursor_front(); + while let Some(next) = cursor.peek_next() { + if next.cookie == cookie { + return Some(next.remove().into_arc()); + } + cursor.move_next(); + } + None + } + + pub(crate) fn death_delivered(&mut self, death: DArc) { + if let Some(death) = ListArc::try_from_arc_or_drop(death) { + self.delivered_deaths.push_back(death); + } else { + pr_warn!("Notification added to `delivered_deaths` twice."); + } + } + + pub(crate) fn add_outstanding_txn(&mut self) { + self.outstanding_txns += 1; + } + + fn txns_pending_locked(&self) -> bool { + if self.outstanding_txns > 0 { + return true; + } + for thread in self.threads.values() { + if thread.has_current_transaction() { + return true; + } + } + false + } +} + +/// Used to keep track of a node that this process has a handle to. +#[pin_data] +pub(crate) struct NodeRefInfo { + debug_id: usize, + /// The refcount that this process owns to the node. + node_ref: ListArcField, + death: ListArcField>, { Self::LIST_PROC }>, + /// Cookie of the active freeze listener for this node. + freeze: ListArcField, { Self::LIST_PROC }>, + /// Used to store this `NodeRefInfo` in the node's `refs` list. + #[pin] + links: ListLinks<{ Self::LIST_NODE }>, + /// The handle for this `NodeRefInfo`. + handle: u32, + /// The process that has a handle to the node. + pub(crate) process: Arc, +} + +impl NodeRefInfo { + /// The id used for the `Node::refs` list. + pub(crate) const LIST_NODE: u64 = 0x2da16350fb724a10; + /// The id used for the `ListArc` in `ProcessNodeRefs`. + const LIST_PROC: u64 = 0xd703a5263dcc8650; + + fn new(node_ref: NodeRef, handle: u32, process: Arc) -> impl PinInit { + pin_init!(Self { + debug_id: super::next_debug_id(), + node_ref: ListArcField::new(node_ref), + death: ListArcField::new(None), + freeze: ListArcField::new(None), + links <- ListLinks::new(), + handle, + process, + }) + } + + kernel::list::define_list_arc_field_getter! { + pub(crate) fn death(&mut self<{Self::LIST_PROC}>) -> &mut Option> { death } + pub(crate) fn freeze(&mut self<{Self::LIST_PROC}>) -> &mut Option { freeze } + pub(crate) fn node_ref(&mut self<{Self::LIST_PROC}>) -> &mut NodeRef { node_ref } + pub(crate) fn node_ref2(&self<{Self::LIST_PROC}>) -> &NodeRef { node_ref } + } +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<{Self::LIST_NODE}> for NodeRefInfo { untracked; } + impl ListArcSafe<{Self::LIST_PROC}> for NodeRefInfo { untracked; } +} +kernel::list::impl_list_item! { + impl ListItem<{Self::LIST_NODE}> for NodeRefInfo { + using ListLinks { self.links }; + } +} + +/// Keeps track of references this process has to nodes owned by other processes. +/// +/// TODO: Currently, the rbtree requires two allocations per node reference, and two tree +/// traversals to look up a node by `Node::global_id`. Once the rbtree is more powerful, these +/// extra costs should be eliminated. +struct ProcessNodeRefs { + /// Used to look up nodes using the 32-bit id that this process knows it by. + by_handle: RBTree>, + /// Used to look up nodes without knowing their local 32-bit id. The usize is the address of + /// the underlying `Node` struct as returned by `Node::global_id`. + by_node: RBTree, + /// Used to look up a `FreezeListener` by cookie. + /// + /// There might be multiple freeze listeners for the same node, but at most one of them is + /// active. + freeze_listeners: RBTree, +} + +impl ProcessNodeRefs { + fn new() -> Self { + Self { + by_handle: RBTree::new(), + by_node: RBTree::new(), + freeze_listeners: RBTree::new(), + } + } +} + +/// A process using binder. +/// +/// Strictly speaking, there can be multiple of these per process. There is one for each binder fd +/// that a process has opened, so processes using several binder contexts have several `Process` +/// objects. This ensures that the contexts are fully separated. +#[pin_data] +pub(crate) struct Process { + pub(crate) ctx: Arc, + + // The task leader (process). + pub(crate) task: ARef, + + // Credential associated with file when `Process` is created. + pub(crate) cred: ARef, + + #[pin] + pub(crate) inner: SpinLock, + + #[pin] + pub(crate) pages: ShrinkablePageRange, + + // Waitqueue of processes waiting for all outstanding transactions to be + // processed. + #[pin] + freeze_wait: CondVar, + + // Node references are in a different lock to avoid recursive acquisition when + // incrementing/decrementing a node in another process. + #[pin] + node_refs: Mutex, + + // Work node for deferred work item. + #[pin] + defer_work: Work, + + // Links for process list in Context. + #[pin] + links: ListLinks, + + pub(crate) stats: BinderStats, +} + +kernel::impl_has_work! { + impl HasWork for Process { self.defer_work } +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<0> for Process { untracked; } +} +kernel::list::impl_list_item! { + impl ListItem<0> for Process { + using ListLinks { self.links }; + } +} + +impl workqueue::WorkItem for Process { + type Pointer = Arc; + + fn run(me: Arc) { + let defer; + { + let mut inner = me.inner.lock(); + defer = inner.defer_work; + inner.defer_work = 0; + } + + if defer & PROC_DEFER_FLUSH != 0 { + me.deferred_flush(); + } + if defer & PROC_DEFER_RELEASE != 0 { + me.deferred_release(); + } + } +} + +impl Process { + fn new(ctx: Arc, cred: ARef) -> Result> { + let current = kernel::current!(); + let list_process = ListArc::pin_init::( + try_pin_init!(Process { + ctx, + cred, + inner <- kernel::new_spinlock!(ProcessInner::new(), "Process::inner"), + pages <- ShrinkablePageRange::new(&super::BINDER_SHRINKER), + node_refs <- kernel::new_mutex!(ProcessNodeRefs::new(), "Process::node_refs"), + freeze_wait <- kernel::new_condvar!("Process::freeze_wait"), + task: current.group_leader().into(), + defer_work <- kernel::new_work!("Process::defer_work"), + links <- ListLinks::new(), + stats: BinderStats::new(), + }), + GFP_KERNEL, + )?; + + let process = list_process.clone_arc(); + process.ctx.register_process(list_process); + + Ok(process) + } + + pub(crate) fn pid_in_current_ns(&self) -> kernel::task::Pid { + self.task.tgid_nr_ns(None) + } + + #[inline(never)] + pub(crate) fn debug_print_stats(&self, m: &SeqFile, ctx: &Context) -> Result<()> { + seq_print!(m, "proc {}\n", self.pid_in_current_ns()); + seq_print!(m, "context {}\n", &*ctx.name); + + let inner = self.inner.lock(); + seq_print!(m, " threads: {}\n", inner.threads.iter().count()); + seq_print!( + m, + " requested threads: {}+{}/{}\n", + inner.requested_thread_count, + inner.started_thread_count, + inner.max_threads, + ); + if let Some(mapping) = &inner.mapping { + seq_print!( + m, + " free oneway space: {}\n", + mapping.alloc.free_oneway_space() + ); + seq_print!(m, " buffers: {}\n", mapping.alloc.count_buffers()); + } + seq_print!( + m, + " outstanding transactions: {}\n", + inner.outstanding_txns + ); + seq_print!(m, " nodes: {}\n", inner.nodes.iter().count()); + drop(inner); + + { + let mut refs = self.node_refs.lock(); + let (mut count, mut weak, mut strong) = (0, 0, 0); + for r in refs.by_handle.values_mut() { + let node_ref = r.node_ref(); + let (nstrong, nweak) = node_ref.get_count(); + count += 1; + weak += nweak; + strong += nstrong; + } + seq_print!(m, " refs: {count} s {strong} w {weak}\n"); + } + + self.stats.debug_print(" ", m); + + Ok(()) + } + + #[inline(never)] + pub(crate) fn debug_print(&self, m: &SeqFile, ctx: &Context, print_all: bool) -> Result<()> { + seq_print!(m, "proc {}\n", self.pid_in_current_ns()); + seq_print!(m, "context {}\n", &*ctx.name); + + let mut all_threads = KVec::new(); + let mut all_nodes = KVec::new(); + loop { + let inner = self.inner.lock(); + let num_threads = inner.threads.iter().count(); + let num_nodes = inner.nodes.iter().count(); + + if all_threads.capacity() < num_threads || all_nodes.capacity() < num_nodes { + drop(inner); + all_threads.reserve(num_threads, GFP_KERNEL)?; + all_nodes.reserve(num_nodes, GFP_KERNEL)?; + continue; + } + + for thread in inner.threads.values() { + assert!(all_threads.len() < all_threads.capacity()); + let _ = all_threads.push(thread.clone(), GFP_ATOMIC); + } + + for node in inner.nodes.values() { + assert!(all_nodes.len() < all_nodes.capacity()); + let _ = all_nodes.push(node.clone(), GFP_ATOMIC); + } + + break; + } + + for thread in all_threads { + thread.debug_print(m, print_all)?; + } + + let mut inner = self.inner.lock(); + for node in all_nodes { + if print_all || node.has_oneway_transaction(&mut inner) { + node.full_debug_print(m, &mut inner)?; + } + } + drop(inner); + + if print_all { + let mut refs = self.node_refs.lock(); + for r in refs.by_handle.values_mut() { + let node_ref = r.node_ref(); + let dead = node_ref.node.owner.inner.lock().is_dead; + let (strong, weak) = node_ref.get_count(); + let debug_id = node_ref.node.debug_id; + + seq_print!( + m, + " ref {}: desc {} {}node {debug_id} s {strong} w {weak}", + r.debug_id, + r.handle, + if dead { "dead " } else { "" }, + ); + } + } + + let inner = self.inner.lock(); + for work in &inner.work { + work.debug_print(m, " ", " pending transaction ")?; + } + for _death in &inner.delivered_deaths { + seq_print!(m, " has delivered dead binder\n"); + } + if let Some(mapping) = &inner.mapping { + mapping.alloc.debug_print(m)?; + } + drop(inner); + + Ok(()) + } + + /// Attempts to fetch a work item from the process queue. + pub(crate) fn get_work(&self) -> Option> { + self.inner.lock().work.pop_front() + } + + /// Attempts to fetch a work item from the process queue. If none is available, it registers the + /// given thread as ready to receive work directly. + /// + /// This must only be called when the thread is not participating in a transaction chain; when + /// it is, work will always be delivered directly to the thread (and not through the process + /// queue). + pub(crate) fn get_work_or_register<'a>( + &'a self, + thread: &'a Arc, + ) -> GetWorkOrRegister<'a> { + let mut inner = self.inner.lock(); + // Try to get work from the process queue. + if let Some(work) = inner.work.pop_front() { + return GetWorkOrRegister::Work(work); + } + + // Register the thread as ready. + GetWorkOrRegister::Register(Registration::new(thread, &mut inner)) + } + + fn get_current_thread(self: ArcBorrow<'_, Self>) -> Result> { + let id = { + let current = kernel::current!(); + if !core::ptr::eq(current.group_leader(), &*self.task) { + pr_err!("get_current_thread was called from the wrong process."); + return Err(EINVAL); + } + current.pid() + }; + + { + let inner = self.inner.lock(); + if let Some(thread) = inner.threads.get(&id) { + return Ok(thread.clone()); + } + } + + // Allocate a new `Thread` without holding any locks. + let reservation = RBTreeNodeReservation::new(GFP_KERNEL)?; + let ta: Arc = Thread::new(id, self.into())?; + + let mut inner = self.inner.lock(); + match inner.threads.entry(id) { + rbtree::Entry::Vacant(entry) => { + entry.insert(ta.clone(), reservation); + Ok(ta) + } + rbtree::Entry::Occupied(_entry) => { + pr_err!("Cannot create two threads with the same id."); + Err(EINVAL) + } + } + } + + pub(crate) fn push_work(&self, work: DLArc) -> BinderResult { + // If push_work fails, drop the work item outside the lock. + let res = self.inner.lock().push_work(work); + match res { + Ok(()) => Ok(()), + Err((err, work)) => { + drop(work); + Err(err) + } + } + } + + fn set_as_manager( + self: ArcBorrow<'_, Self>, + info: Option, + thread: &Thread, + ) -> Result { + let (ptr, cookie, flags) = if let Some(obj) = info { + ( + // SAFETY: The object type for this ioctl is implicitly `BINDER_TYPE_BINDER`, so it + // is safe to access the `binder` field. + unsafe { obj.__bindgen_anon_1.binder }, + obj.cookie, + obj.flags, + ) + } else { + (0, 0, 0) + }; + let node_ref = self.get_node(ptr, cookie, flags as _, true, thread)?; + let node = node_ref.node.clone(); + self.ctx.set_manager_node(node_ref)?; + self.inner.lock().is_manager = true; + + // Force the state of the node to prevent the delivery of acquire/increfs. + let mut owner_inner = node.owner.inner.lock(); + node.force_has_count(&mut owner_inner); + Ok(()) + } + + fn get_node_inner( + self: ArcBorrow<'_, Self>, + ptr: u64, + cookie: u64, + flags: u32, + strong: bool, + thread: &Thread, + wrapper: Option, + ) -> Result> { + // Try to find an existing node. + { + let mut inner = self.inner.lock(); + if let Some(node) = inner.get_existing_node(ptr, cookie)? { + return Ok(inner.new_node_ref_with_thread(node, strong, thread, wrapper)); + } + } + + // Allocate the node before reacquiring the lock. + let node = DTRWrap::arc_pin_init(Node::new(ptr, cookie, flags, self.into()))?.into_arc(); + let rbnode = RBTreeNode::new(ptr, node.clone(), GFP_KERNEL)?; + let mut inner = self.inner.lock(); + if let Some(node) = inner.get_existing_node(ptr, cookie)? { + return Ok(inner.new_node_ref_with_thread(node, strong, thread, wrapper)); + } + + inner.nodes.insert(rbnode); + // This can only fail if someone has already pushed the node to a list, but we just created + // it and still hold the lock, so it can't fail right now. + let node_ref = inner + .new_node_ref_with_thread(node, strong, thread, wrapper) + .unwrap(); + + Ok(Ok(node_ref)) + } + + pub(crate) fn get_node( + self: ArcBorrow<'_, Self>, + ptr: u64, + cookie: u64, + flags: u32, + strong: bool, + thread: &Thread, + ) -> Result { + let mut wrapper = None; + for _ in 0..2 { + match self.get_node_inner(ptr, cookie, flags, strong, thread, wrapper) { + Err(err) => return Err(err), + Ok(Ok(node_ref)) => return Ok(node_ref), + Ok(Err(CouldNotDeliverCriticalIncrement)) => { + wrapper = Some(CritIncrWrapper::new()?); + } + } + } + // We only get a `CouldNotDeliverCriticalIncrement` error if `wrapper` is `None`, so the + // loop should run at most twice. + unreachable!() + } + + pub(crate) fn insert_or_update_handle( + self: ArcBorrow<'_, Process>, + node_ref: NodeRef, + is_mananger: bool, + ) -> Result { + { + let mut refs = self.node_refs.lock(); + + // Do a lookup before inserting. + if let Some(handle_ref) = refs.by_node.get(&node_ref.node.global_id()) { + let handle = *handle_ref; + let info = refs.by_handle.get_mut(&handle).unwrap(); + info.node_ref().absorb(node_ref); + return Ok(handle); + } + } + + // Reserve memory for tree nodes. + let reserve1 = RBTreeNodeReservation::new(GFP_KERNEL)?; + let reserve2 = RBTreeNodeReservation::new(GFP_KERNEL)?; + let info = UniqueArc::new_uninit(GFP_KERNEL)?; + + let mut refs = self.node_refs.lock(); + + // Do a lookup again as node may have been inserted before the lock was reacquired. + if let Some(handle_ref) = refs.by_node.get(&node_ref.node.global_id()) { + let handle = *handle_ref; + let info = refs.by_handle.get_mut(&handle).unwrap(); + info.node_ref().absorb(node_ref); + return Ok(handle); + } + + // Find id. + let mut target: u32 = if is_mananger { 0 } else { 1 }; + for handle in refs.by_handle.keys() { + if *handle > target { + break; + } + if *handle == target { + target = target.checked_add(1).ok_or(ENOMEM)?; + } + } + + let gid = node_ref.node.global_id(); + let (info_proc, info_node) = { + let info_init = NodeRefInfo::new(node_ref, target, self.into()); + match info.pin_init_with(info_init) { + Ok(info) => ListArc::pair_from_pin_unique(info), + // error is infallible + Err(err) => match err {}, + } + }; + + // Ensure the process is still alive while we insert a new reference. + // + // This releases the lock before inserting the nodes, but since `is_dead` is set as the + // first thing in `deferred_release`, process cleanup will not miss the items inserted into + // `refs` below. + if self.inner.lock().is_dead { + return Err(ESRCH); + } + + // SAFETY: `info_proc` and `info_node` reference the same node, so we are inserting + // `info_node` into the right node's `refs` list. + unsafe { info_proc.node_ref2().node.insert_node_info(info_node) }; + + refs.by_node.insert(reserve1.into_node(gid, target)); + refs.by_handle.insert(reserve2.into_node(target, info_proc)); + Ok(target) + } + + pub(crate) fn get_transaction_node(&self, handle: u32) -> BinderResult { + // When handle is zero, try to get the context manager. + if handle == 0 { + Ok(self.ctx.get_manager_node(true)?) + } else { + Ok(self.get_node_from_handle(handle, true)?) + } + } + + pub(crate) fn get_node_from_handle(&self, handle: u32, strong: bool) -> Result { + self.node_refs + .lock() + .by_handle + .get_mut(&handle) + .ok_or(ENOENT)? + .node_ref() + .clone(strong) + } + + pub(crate) fn remove_from_delivered_deaths(&self, death: &DArc) { + let mut inner = self.inner.lock(); + // SAFETY: By the invariant on the `delivered_links` field, this is the right linked list. + let removed = unsafe { inner.delivered_deaths.remove(death) }; + drop(inner); + drop(removed); + } + + pub(crate) fn update_ref( + self: ArcBorrow<'_, Process>, + handle: u32, + inc: bool, + strong: bool, + ) -> Result { + if inc && handle == 0 { + if let Ok(node_ref) = self.ctx.get_manager_node(strong) { + if core::ptr::eq(&*self, &*node_ref.node.owner) { + return Err(EINVAL); + } + let _ = self.insert_or_update_handle(node_ref, true); + return Ok(()); + } + } + + // To preserve original binder behaviour, we only fail requests where the manager tries to + // increment references on itself. + let mut refs = self.node_refs.lock(); + if let Some(info) = refs.by_handle.get_mut(&handle) { + if info.node_ref().update(inc, strong) { + // Clean up death if there is one attached to this node reference. + if let Some(death) = info.death().take() { + death.set_cleared(true); + self.remove_from_delivered_deaths(&death); + } + + // Remove reference from process tables, and from the node's `refs` list. + + // SAFETY: We are removing the `NodeRefInfo` from the right node. + unsafe { info.node_ref2().node.remove_node_info(info) }; + + let id = info.node_ref().node.global_id(); + refs.by_handle.remove(&handle); + refs.by_node.remove(&id); + } + } else { + // All refs are cleared in process exit, so this warning is expected in that case. + if !self.inner.lock().is_dead { + pr_warn!("{}: no such ref {handle}\n", self.pid_in_current_ns()); + } + } + Ok(()) + } + + /// Decrements the refcount of the given node, if one exists. + pub(crate) fn update_node(&self, ptr: u64, cookie: u64, strong: bool) { + let mut inner = self.inner.lock(); + if let Ok(Some(node)) = inner.get_existing_node(ptr, cookie) { + inner.update_node_refcount(&node, false, strong, 1, None); + } + } + + pub(crate) fn inc_ref_done(&self, reader: &mut UserSliceReader, strong: bool) -> Result { + let ptr = reader.read::()?; + let cookie = reader.read::()?; + let mut inner = self.inner.lock(); + if let Ok(Some(node)) = inner.get_existing_node(ptr, cookie) { + if let Some(node) = node.inc_ref_done_locked(strong, &mut inner) { + // This only fails if the process is dead. + let _ = inner.push_work(node); + } + } + Ok(()) + } + + pub(crate) fn buffer_alloc( + self: &Arc, + debug_id: usize, + size: usize, + is_oneway: bool, + from_pid: i32, + ) -> BinderResult { + use kernel::page::PAGE_SIZE; + + let mut reserve_new_args = ReserveNewArgs { + debug_id, + size, + is_oneway, + pid: from_pid, + ..ReserveNewArgs::default() + }; + + let (new_alloc, addr) = loop { + let mut inner = self.inner.lock(); + let mapping = inner.mapping.as_mut().ok_or_else(BinderError::new_dead)?; + let alloc_request = match mapping.alloc.reserve_new(reserve_new_args)? { + ReserveNew::Success(new_alloc) => break (new_alloc, mapping.address), + ReserveNew::NeedAlloc(request) => request, + }; + drop(inner); + // We need to allocate memory and then call `reserve_new` again. + reserve_new_args = alloc_request.make_alloc()?; + }; + + let res = Allocation::new( + self.clone(), + debug_id, + new_alloc.offset, + size, + addr + new_alloc.offset, + new_alloc.oneway_spam_detected, + ); + + // This allocation will be marked as in use until the `Allocation` is used to free it. + // + // This method can't be called while holding a lock, so we release the lock first. It's + // okay for several threads to use the method on the same index at the same time. In that + // case, one of the calls will allocate the given page (if missing), and the other call + // will wait for the other call to finish allocating the page. + // + // We will not call `stop_using_range` in parallel with this on the same page, because the + // allocation can only be removed via the destructor of the `Allocation` object that we + // currently own. + match self.pages.use_range( + new_alloc.offset / PAGE_SIZE, + (new_alloc.offset + size).div_ceil(PAGE_SIZE), + ) { + Ok(()) => {} + Err(err) => { + pr_warn!("use_range failure {:?}", err); + return Err(err.into()); + } + } + + Ok(NewAllocation(res)) + } + + pub(crate) fn buffer_get(self: &Arc, ptr: usize) -> Option { + let mut inner = self.inner.lock(); + let mapping = inner.mapping.as_mut()?; + let offset = ptr.checked_sub(mapping.address)?; + let (size, debug_id, odata) = mapping.alloc.reserve_existing(offset).ok()?; + let mut alloc = Allocation::new(self.clone(), debug_id, offset, size, ptr, false); + if let Some(data) = odata { + alloc.set_info(data); + } + Some(alloc) + } + + pub(crate) fn buffer_raw_free(&self, ptr: usize) { + let mut inner = self.inner.lock(); + if let Some(ref mut mapping) = &mut inner.mapping { + let offset = match ptr.checked_sub(mapping.address) { + Some(offset) => offset, + None => return, + }; + + let freed_range = match mapping.alloc.reservation_abort(offset) { + Ok(freed_range) => freed_range, + Err(_) => { + pr_warn!( + "Pointer {:x} failed to free, base = {:x}\n", + ptr, + mapping.address + ); + return; + } + }; + + // No more allocations in this range. Mark them as not in use. + // + // Must be done before we release the lock so that `use_range` is not used on these + // indices until `stop_using_range` returns. + self.pages + .stop_using_range(freed_range.start_page_idx, freed_range.end_page_idx); + } + } + + pub(crate) fn buffer_make_freeable(&self, offset: usize, mut data: Option) { + let mut inner = self.inner.lock(); + if let Some(ref mut mapping) = &mut inner.mapping { + if mapping.alloc.reservation_commit(offset, &mut data).is_err() { + pr_warn!("Offset {} failed to be marked freeable\n", offset); + } + } + } + + fn create_mapping(&self, vma: &mm::virt::VmaNew) -> Result { + use kernel::page::PAGE_SIZE; + let size = usize::min(vma.end() - vma.start(), bindings::SZ_4M as usize); + let mapping = Mapping::new(vma.start(), size); + let page_count = self.pages.register_with_vma(vma)?; + if page_count * PAGE_SIZE != size { + return Err(EINVAL); + } + + // Save range allocator for later. + self.inner.lock().mapping = Some(mapping); + + Ok(()) + } + + fn version(&self, data: UserSlice) -> Result { + data.writer().write(&BinderVersion::current()) + } + + pub(crate) fn register_thread(&self) -> bool { + self.inner.lock().register_thread() + } + + fn remove_thread(&self, thread: Arc) { + self.inner.lock().threads.remove(&thread.id); + thread.release(); + } + + fn set_max_threads(&self, max: u32) { + self.inner.lock().max_threads = max; + } + + fn set_oneway_spam_detection_enabled(&self, enabled: u32) { + self.inner.lock().oneway_spam_detection_enabled = enabled != 0; + } + + pub(crate) fn is_oneway_spam_detection_enabled(&self) -> bool { + self.inner.lock().oneway_spam_detection_enabled + } + + fn get_node_debug_info(&self, data: UserSlice) -> Result { + let (mut reader, mut writer) = data.reader_writer(); + + // Read the starting point. + let ptr = reader.read::()?.ptr; + let mut out = BinderNodeDebugInfo::default(); + + { + let inner = self.inner.lock(); + for (node_ptr, node) in &inner.nodes { + if *node_ptr > ptr { + node.populate_debug_info(&mut out, &inner); + break; + } + } + } + + writer.write(&out) + } + + fn get_node_info_from_ref(&self, data: UserSlice) -> Result { + let (mut reader, mut writer) = data.reader_writer(); + let mut out = reader.read::()?; + + if out.strong_count != 0 + || out.weak_count != 0 + || out.reserved1 != 0 + || out.reserved2 != 0 + || out.reserved3 != 0 + { + return Err(EINVAL); + } + + // Only the context manager is allowed to use this ioctl. + if !self.inner.lock().is_manager { + return Err(EPERM); + } + + { + let mut node_refs = self.node_refs.lock(); + let node_info = node_refs.by_handle.get_mut(&out.handle).ok_or(ENOENT)?; + let node_ref = node_info.node_ref(); + let owner_inner = node_ref.node.owner.inner.lock(); + node_ref.node.populate_counts(&mut out, &owner_inner); + } + + // Write the result back. + writer.write(&out) + } + + pub(crate) fn needs_thread(&self) -> bool { + let mut inner = self.inner.lock(); + let ret = inner.requested_thread_count == 0 + && inner.ready_threads.is_empty() + && inner.started_thread_count < inner.max_threads; + if ret { + inner.requested_thread_count += 1 + } + ret + } + + pub(crate) fn request_death( + self: &Arc, + reader: &mut UserSliceReader, + thread: &Thread, + ) -> Result { + let handle: u32 = reader.read()?; + let cookie: u64 = reader.read()?; + + // Queue BR_ERROR if we can't allocate memory for the death notification. + let death = UniqueArc::new_uninit(GFP_KERNEL).inspect_err(|_| { + thread.push_return_work(BR_ERROR); + })?; + let mut refs = self.node_refs.lock(); + let Some(info) = refs.by_handle.get_mut(&handle) else { + pr_warn!("BC_REQUEST_DEATH_NOTIFICATION invalid ref {handle}\n"); + return Ok(()); + }; + + // Nothing to do if there is already a death notification request for this handle. + if info.death().is_some() { + pr_warn!("BC_REQUEST_DEATH_NOTIFICATION death notification already set\n"); + return Ok(()); + } + + let death = { + let death_init = NodeDeath::new(info.node_ref().node.clone(), self.clone(), cookie); + match death.pin_init_with(death_init) { + Ok(death) => death, + // error is infallible + Err(err) => match err {}, + } + }; + + // Register the death notification. + { + let owner = info.node_ref2().node.owner.clone(); + let mut owner_inner = owner.inner.lock(); + if owner_inner.is_dead { + let death = Arc::from(death); + *info.death() = Some(death.clone()); + drop(owner_inner); + death.set_dead(); + } else { + let death = ListArc::from(death); + *info.death() = Some(death.clone_arc()); + info.node_ref().node.add_death(death, &mut owner_inner); + } + } + Ok(()) + } + + pub(crate) fn clear_death(&self, reader: &mut UserSliceReader, thread: &Thread) -> Result { + let handle: u32 = reader.read()?; + let cookie: u64 = reader.read()?; + + let mut refs = self.node_refs.lock(); + let Some(info) = refs.by_handle.get_mut(&handle) else { + pr_warn!("BC_CLEAR_DEATH_NOTIFICATION invalid ref {handle}\n"); + return Ok(()); + }; + + let Some(death) = info.death().take() else { + pr_warn!("BC_CLEAR_DEATH_NOTIFICATION death notification not active\n"); + return Ok(()); + }; + if death.cookie != cookie { + *info.death() = Some(death); + pr_warn!("BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch\n"); + return Ok(()); + } + + // Update state and determine if we need to queue a work item. We only need to do it when + // the node is not dead or if the user already completed the death notification. + if death.set_cleared(false) { + if let Some(death) = ListArc::try_from_arc_or_drop(death) { + let _ = thread.push_work_if_looper(death); + } + } + + Ok(()) + } + + pub(crate) fn dead_binder_done(&self, cookie: u64, thread: &Thread) { + if let Some(death) = self.inner.lock().pull_delivered_death(cookie) { + death.set_notification_done(thread); + } + } + + /// Locks the spinlock and move the `nodes` rbtree out. + /// + /// This allows you to iterate through `nodes` while also allowing you to give other parts of + /// the codebase exclusive access to `ProcessInner`. + pub(crate) fn lock_with_nodes(&self) -> WithNodes<'_> { + let mut inner = self.inner.lock(); + WithNodes { + nodes: take(&mut inner.nodes), + inner, + } + } + + fn deferred_flush(&self) { + let inner = self.inner.lock(); + for thread in inner.threads.values() { + thread.exit_looper(); + } + } + + fn deferred_release(self: Arc) { + let is_manager = { + let mut inner = self.inner.lock(); + inner.is_dead = true; + inner.is_frozen = false; + inner.sync_recv = false; + inner.async_recv = false; + inner.is_manager + }; + + if is_manager { + self.ctx.unset_manager_node(); + } + + self.ctx.deregister_process(&self); + + let binderfs_file = self.inner.lock().binderfs_file.take(); + drop(binderfs_file); + + // Release threads. + let threads = { + let mut inner = self.inner.lock(); + let threads = take(&mut inner.threads); + let ready = take(&mut inner.ready_threads); + drop(inner); + drop(ready); + + for thread in threads.values() { + thread.release(); + } + threads + }; + + // Release nodes. + { + while let Some(node) = { + let mut lock = self.inner.lock(); + lock.nodes.cursor_front().map(|c| c.remove_current().1) + } { + node.to_key_value().1.release(); + } + } + + // Clean up death listeners and remove nodes from external node info lists. + for info in self.node_refs.lock().by_handle.values_mut() { + // SAFETY: We are removing the `NodeRefInfo` from the right node. + unsafe { info.node_ref2().node.remove_node_info(info) }; + + // Remove all death notifications from the nodes (that belong to a different process). + let death = if let Some(existing) = info.death().take() { + existing + } else { + continue; + }; + death.set_cleared(false); + } + + // Clean up freeze listeners. + let freeze_listeners = take(&mut self.node_refs.lock().freeze_listeners); + for listener in freeze_listeners.values() { + listener.on_process_exit(&self); + } + drop(freeze_listeners); + + // Release refs on foreign nodes. + { + let mut refs = self.node_refs.lock(); + let by_handle = take(&mut refs.by_handle); + let by_node = take(&mut refs.by_node); + drop(refs); + drop(by_node); + drop(by_handle); + } + + // Cancel all pending work items. + while let Some(work) = self.get_work() { + work.into_arc().cancel(); + } + + let delivered_deaths = take(&mut self.inner.lock().delivered_deaths); + drop(delivered_deaths); + + // Free any resources kept alive by allocated buffers. + let omapping = self.inner.lock().mapping.take(); + if let Some(mut mapping) = omapping { + let address = mapping.address; + mapping + .alloc + .take_for_each(|offset, size, debug_id, odata| { + let ptr = offset + address; + pr_warn!( + "{}: removing orphan mapping {offset}:{size}\n", + self.pid_in_current_ns() + ); + let mut alloc = + Allocation::new(self.clone(), debug_id, offset, size, ptr, false); + if let Some(data) = odata { + alloc.set_info(data); + } + drop(alloc) + }); + } + + // calls to synchronize_rcu() in thread drop will happen here + drop(threads); + } + + pub(crate) fn drop_outstanding_txn(&self) { + let wake = { + let mut inner = self.inner.lock(); + if inner.outstanding_txns == 0 { + pr_err!("outstanding_txns underflow"); + return; + } + inner.outstanding_txns -= 1; + inner.is_frozen && inner.outstanding_txns == 0 + }; + + if wake { + self.freeze_wait.notify_all(); + } + } + + pub(crate) fn ioctl_freeze(&self, info: &BinderFreezeInfo) -> Result { + if info.enable == 0 { + let msgs = self.prepare_freeze_messages()?; + let mut inner = self.inner.lock(); + inner.sync_recv = false; + inner.async_recv = false; + inner.is_frozen = false; + drop(inner); + msgs.send_messages(); + return Ok(()); + } + + let mut inner = self.inner.lock(); + inner.sync_recv = false; + inner.async_recv = false; + inner.is_frozen = true; + + if info.timeout_ms > 0 { + let mut jiffies = kernel::time::msecs_to_jiffies(info.timeout_ms); + while jiffies > 0 { + if inner.outstanding_txns == 0 { + break; + } + + match self + .freeze_wait + .wait_interruptible_timeout(&mut inner, jiffies) + { + CondVarTimeoutResult::Signal { .. } => { + inner.is_frozen = false; + return Err(ERESTARTSYS); + } + CondVarTimeoutResult::Woken { jiffies: remaining } => { + jiffies = remaining; + } + CondVarTimeoutResult::Timeout => { + jiffies = 0; + } + } + } + } + + if inner.txns_pending_locked() { + inner.is_frozen = false; + Err(EAGAIN) + } else { + drop(inner); + match self.prepare_freeze_messages() { + Ok(batch) => { + batch.send_messages(); + Ok(()) + } + Err(kernel::alloc::AllocError) => { + self.inner.lock().is_frozen = false; + Err(ENOMEM) + } + } + } + } +} + +fn get_frozen_status(data: UserSlice) -> Result { + let (mut reader, mut writer) = data.reader_writer(); + + let mut info = reader.read::()?; + info.sync_recv = 0; + info.async_recv = 0; + let mut found = false; + + for ctx in crate::context::get_all_contexts()? { + ctx.for_each_proc(|proc| { + if proc.task.pid() == info.pid as _ { + found = true; + let inner = proc.inner.lock(); + let txns_pending = inner.txns_pending_locked(); + info.async_recv |= inner.async_recv as u32; + info.sync_recv |= inner.sync_recv as u32; + info.sync_recv |= (txns_pending as u32) << 1; + } + }); + } + + if found { + writer.write(&info)?; + Ok(()) + } else { + Err(EINVAL) + } +} + +fn ioctl_freeze(reader: &mut UserSliceReader) -> Result { + let info = reader.read::()?; + + // Very unlikely for there to be more than 3, since a process normally uses at most binder and + // hwbinder. + let mut procs = KVec::with_capacity(3, GFP_KERNEL)?; + + let ctxs = crate::context::get_all_contexts()?; + for ctx in ctxs { + for proc in ctx.get_procs_with_pid(info.pid as i32)? { + procs.push(proc, GFP_KERNEL)?; + } + } + + for proc in procs { + proc.ioctl_freeze(&info)?; + } + Ok(()) +} + +/// The ioctl handler. +impl Process { + /// Ioctls that are write-only from the perspective of userspace. + /// + /// The kernel will only read from the pointer that userspace provided to us. + fn ioctl_write_only( + this: ArcBorrow<'_, Process>, + _file: &File, + cmd: u32, + reader: &mut UserSliceReader, + ) -> Result { + let thread = this.get_current_thread()?; + match cmd { + uapi::BINDER_SET_MAX_THREADS => this.set_max_threads(reader.read()?), + uapi::BINDER_THREAD_EXIT => this.remove_thread(thread), + uapi::BINDER_SET_CONTEXT_MGR => this.set_as_manager(None, &thread)?, + uapi::BINDER_SET_CONTEXT_MGR_EXT => { + this.set_as_manager(Some(reader.read()?), &thread)? + } + uapi::BINDER_ENABLE_ONEWAY_SPAM_DETECTION => { + this.set_oneway_spam_detection_enabled(reader.read()?) + } + uapi::BINDER_FREEZE => ioctl_freeze(reader)?, + _ => return Err(EINVAL), + } + Ok(()) + } + + /// Ioctls that are read/write from the perspective of userspace. + /// + /// The kernel will both read from and write to the pointer that userspace provided to us. + fn ioctl_write_read( + this: ArcBorrow<'_, Process>, + file: &File, + cmd: u32, + data: UserSlice, + ) -> Result { + let thread = this.get_current_thread()?; + let blocking = (file.flags() & file::flags::O_NONBLOCK) == 0; + match cmd { + uapi::BINDER_WRITE_READ => thread.write_read(data, blocking)?, + uapi::BINDER_GET_NODE_DEBUG_INFO => this.get_node_debug_info(data)?, + uapi::BINDER_GET_NODE_INFO_FOR_REF => this.get_node_info_from_ref(data)?, + uapi::BINDER_VERSION => this.version(data)?, + uapi::BINDER_GET_FROZEN_INFO => get_frozen_status(data)?, + uapi::BINDER_GET_EXTENDED_ERROR => thread.get_extended_error(data)?, + _ => return Err(EINVAL), + } + Ok(()) + } +} + +/// The file operations supported by `Process`. +impl Process { + pub(crate) fn open(ctx: ArcBorrow<'_, Context>, file: &File) -> Result> { + Self::new(ctx.into(), ARef::from(file.cred())) + } + + pub(crate) fn release(this: Arc, _file: &File) { + let binderfs_file; + let should_schedule; + { + let mut inner = this.inner.lock(); + should_schedule = inner.defer_work == 0; + inner.defer_work |= PROC_DEFER_RELEASE; + binderfs_file = inner.binderfs_file.take(); + } + + if should_schedule { + // Ignore failures to schedule to the workqueue. Those just mean that we're already + // scheduled for execution. + let _ = workqueue::system().enqueue(this); + } + + drop(binderfs_file); + } + + pub(crate) fn flush(this: ArcBorrow<'_, Process>) -> Result { + let should_schedule; + { + let mut inner = this.inner.lock(); + should_schedule = inner.defer_work == 0; + inner.defer_work |= PROC_DEFER_FLUSH; + } + + if should_schedule { + // Ignore failures to schedule to the workqueue. Those just mean that we're already + // scheduled for execution. + let _ = workqueue::system().enqueue(Arc::from(this)); + } + Ok(()) + } + + pub(crate) fn ioctl(this: ArcBorrow<'_, Process>, file: &File, cmd: u32, arg: usize) -> Result { + use kernel::ioctl::{_IOC_DIR, _IOC_SIZE}; + use kernel::uapi::{_IOC_READ, _IOC_WRITE}; + + crate::trace::trace_ioctl(cmd, arg); + + let user_slice = UserSlice::new(UserPtr::from_addr(arg), _IOC_SIZE(cmd)); + + const _IOC_READ_WRITE: u32 = _IOC_READ | _IOC_WRITE; + + match _IOC_DIR(cmd) { + _IOC_WRITE => Self::ioctl_write_only(this, file, cmd, &mut user_slice.reader()), + _IOC_READ_WRITE => Self::ioctl_write_read(this, file, cmd, user_slice), + _ => Err(EINVAL), + } + } + + pub(crate) fn compat_ioctl( + this: ArcBorrow<'_, Process>, + file: &File, + cmd: u32, + arg: usize, + ) -> Result { + Self::ioctl(this, file, cmd, arg) + } + + pub(crate) fn mmap( + this: ArcBorrow<'_, Process>, + _file: &File, + vma: &mm::virt::VmaNew, + ) -> Result { + // We don't allow mmap to be used in a different process. + if !core::ptr::eq(kernel::current!().group_leader(), &*this.task) { + return Err(EINVAL); + } + if vma.start() == 0 { + return Err(EINVAL); + } + + vma.try_clear_maywrite().map_err(|_| EPERM)?; + vma.set_dontcopy(); + vma.set_mixedmap(); + + // TODO: Set ops. We need to learn when the user unmaps so that we can stop using it. + this.create_mapping(vma) + } + + pub(crate) fn poll( + this: ArcBorrow<'_, Process>, + file: &File, + table: PollTable<'_>, + ) -> Result { + let thread = this.get_current_thread()?; + let (from_proc, mut mask) = thread.poll(file, table); + if mask == 0 && from_proc && !this.inner.lock().work.is_empty() { + mask |= bindings::POLLIN; + } + Ok(mask) + } +} + +/// Represents that a thread has registered with the `ready_threads` list of its process. +/// +/// The destructor of this type will unregister the thread from the list of ready threads. +pub(crate) struct Registration<'a> { + thread: &'a Arc, +} + +impl<'a> Registration<'a> { + fn new(thread: &'a Arc, guard: &mut Guard<'_, ProcessInner, SpinLockBackend>) -> Self { + assert!(core::ptr::eq(&thread.process.inner, guard.lock_ref())); + // INVARIANT: We are pushing this thread to the right `ready_threads` list. + if let Ok(list_arc) = ListArc::try_from_arc(thread.clone()) { + guard.ready_threads.push_front(list_arc); + } else { + // It is an error to hit this branch, and it should not be reachable. We try to do + // something reasonable when the failure path happens. Most likely, the thread in + // question will sleep forever. + pr_err!("Same thread registered with `ready_threads` twice."); + } + Self { thread } + } +} + +impl Drop for Registration<'_> { + fn drop(&mut self) { + let mut inner = self.thread.process.inner.lock(); + // SAFETY: The thread has the invariant that we never push it to any other linked list than + // the `ready_threads` list of its parent process. Therefore, the thread is either in that + // list, or in no list. + unsafe { inner.ready_threads.remove(self.thread) }; + } +} + +pub(crate) struct WithNodes<'a> { + pub(crate) inner: Guard<'a, ProcessInner, SpinLockBackend>, + pub(crate) nodes: RBTree>, +} + +impl Drop for WithNodes<'_> { + fn drop(&mut self) { + core::mem::swap(&mut self.nodes, &mut self.inner.nodes); + if self.nodes.iter().next().is_some() { + pr_err!("nodes array was modified while using lock_with_nodes\n"); + } + } +} + +pub(crate) enum GetWorkOrRegister<'a> { + Work(DLArc), + Register(Registration<'a>), +} diff --git a/drivers/android/binder/range_alloc/array.rs b/drivers/android/binder/range_alloc/array.rs new file mode 100644 index 000000000000..07e1dec2ce63 --- /dev/null +++ b/drivers/android/binder/range_alloc/array.rs @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use kernel::{ + page::{PAGE_MASK, PAGE_SIZE}, + prelude::*, + seq_file::SeqFile, + seq_print, + task::Pid, +}; + +use crate::range_alloc::{DescriptorState, FreedRange, Range}; + +/// Keeps track of allocations in a process' mmap. +/// +/// Each process has an mmap where the data for incoming transactions will be placed. This struct +/// keeps track of allocations made in the mmap. For each allocation, we store a descriptor that +/// has metadata related to the allocation. We also keep track of available free space. +pub(super) struct ArrayRangeAllocator { + /// This stores all ranges that are allocated. Unlike the tree based allocator, we do *not* + /// store the free ranges. + /// + /// Sorted by offset. + pub(super) ranges: KVec>, + size: usize, + free_oneway_space: usize, +} + +struct FindEmptyRes { + /// Which index in `ranges` should we insert the new range at? + /// + /// Inserting the new range at this index keeps `ranges` sorted. + insert_at_idx: usize, + /// Which offset should we insert the new range at? + insert_at_offset: usize, +} + +impl ArrayRangeAllocator { + pub(crate) fn new(size: usize, alloc: EmptyArrayAlloc) -> Self { + Self { + ranges: alloc.ranges, + size, + free_oneway_space: size / 2, + } + } + + pub(crate) fn free_oneway_space(&self) -> usize { + self.free_oneway_space + } + + pub(crate) fn count_buffers(&self) -> usize { + self.ranges.len() + } + + pub(crate) fn total_size(&self) -> usize { + self.size + } + + pub(crate) fn is_full(&self) -> bool { + self.ranges.len() == self.ranges.capacity() + } + + pub(crate) fn debug_print(&self, m: &SeqFile) -> Result<()> { + for range in &self.ranges { + seq_print!( + m, + " buffer {}: {} size {} pid {} oneway {}", + 0, + range.offset, + range.size, + range.state.pid(), + range.state.is_oneway(), + ); + if let DescriptorState::Reserved(_) = range.state { + seq_print!(m, " reserved\n"); + } else { + seq_print!(m, " allocated\n"); + } + } + Ok(()) + } + + /// Find somewhere to put a new range. + /// + /// Unlike the tree implementation, we do not bother to find the smallest gap. The idea is that + /// fragmentation isn't a big issue when we don't have many ranges. + /// + /// Returns the index that the new range should have in `self.ranges` after insertion. + fn find_empty_range(&self, size: usize) -> Option { + let after_last_range = self.ranges.last().map(Range::endpoint).unwrap_or(0); + + if size <= self.total_size() - after_last_range { + // We can put the range at the end, so just do that. + Some(FindEmptyRes { + insert_at_idx: self.ranges.len(), + insert_at_offset: after_last_range, + }) + } else { + let mut end_of_prev = 0; + for (i, range) in self.ranges.iter().enumerate() { + // Does it fit before the i'th range? + if size <= range.offset - end_of_prev { + return Some(FindEmptyRes { + insert_at_idx: i, + insert_at_offset: end_of_prev, + }); + } + end_of_prev = range.endpoint(); + } + None + } + } + + pub(crate) fn reserve_new( + &mut self, + debug_id: usize, + size: usize, + is_oneway: bool, + pid: Pid, + ) -> Result { + // Compute new value of free_oneway_space, which is set only on success. + let new_oneway_space = if is_oneway { + match self.free_oneway_space.checked_sub(size) { + Some(new_oneway_space) => new_oneway_space, + None => return Err(ENOSPC), + } + } else { + self.free_oneway_space + }; + + let FindEmptyRes { + insert_at_idx, + insert_at_offset, + } = self.find_empty_range(size).ok_or(ENOSPC)?; + self.free_oneway_space = new_oneway_space; + + let new_range = Range { + offset: insert_at_offset, + size, + state: DescriptorState::new(is_oneway, debug_id, pid), + }; + // Insert the value at the given index to keep the array sorted. + self.ranges + .insert_within_capacity(insert_at_idx, new_range) + .ok() + .unwrap(); + + Ok(insert_at_offset) + } + + pub(crate) fn reservation_abort(&mut self, offset: usize) -> Result { + // This could use a binary search, but linear scans are usually faster for small arrays. + let i = self + .ranges + .iter() + .position(|range| range.offset == offset) + .ok_or(EINVAL)?; + let range = &self.ranges[i]; + + if let DescriptorState::Allocated(_) = range.state { + return Err(EPERM); + } + + let size = range.size; + let offset = range.offset; + + if range.state.is_oneway() { + self.free_oneway_space += size; + } + + // This computes the range of pages that are no longer used by *any* allocated range. The + // caller will mark them as unused, which means that they can be freed if the system comes + // under memory pressure. + let mut freed_range = FreedRange::interior_pages(offset, size); + #[expect(clippy::collapsible_if)] // reads better like this + if offset % PAGE_SIZE != 0 { + if i == 0 || self.ranges[i - 1].endpoint() <= (offset & PAGE_MASK) { + freed_range.start_page_idx -= 1; + } + } + if range.endpoint() % PAGE_SIZE != 0 { + let page_after = (range.endpoint() & PAGE_MASK) + PAGE_SIZE; + if i + 1 == self.ranges.len() || page_after <= self.ranges[i + 1].offset { + freed_range.end_page_idx += 1; + } + } + + self.ranges.remove(i)?; + Ok(freed_range) + } + + pub(crate) fn reservation_commit(&mut self, offset: usize, data: &mut Option) -> Result { + // This could use a binary search, but linear scans are usually faster for small arrays. + let range = self + .ranges + .iter_mut() + .find(|range| range.offset == offset) + .ok_or(ENOENT)?; + + let DescriptorState::Reserved(reservation) = &range.state else { + return Err(ENOENT); + }; + + range.state = DescriptorState::Allocated(reservation.clone().allocate(data.take())); + Ok(()) + } + + pub(crate) fn reserve_existing(&mut self, offset: usize) -> Result<(usize, usize, Option)> { + // This could use a binary search, but linear scans are usually faster for small arrays. + let range = self + .ranges + .iter_mut() + .find(|range| range.offset == offset) + .ok_or(ENOENT)?; + + let DescriptorState::Allocated(allocation) = &mut range.state else { + return Err(ENOENT); + }; + + let data = allocation.take(); + let debug_id = allocation.reservation.debug_id; + range.state = DescriptorState::Reserved(allocation.reservation.clone()); + Ok((range.size, debug_id, data)) + } + + pub(crate) fn take_for_each)>(&mut self, callback: F) { + for range in self.ranges.iter_mut() { + if let DescriptorState::Allocated(allocation) = &mut range.state { + callback( + range.offset, + range.size, + allocation.reservation.debug_id, + allocation.data.take(), + ); + } + } + } +} + +pub(crate) struct EmptyArrayAlloc { + ranges: KVec>, +} + +impl EmptyArrayAlloc { + pub(crate) fn try_new(capacity: usize) -> Result { + Ok(Self { + ranges: KVec::with_capacity(capacity, GFP_KERNEL)?, + }) + } +} diff --git a/drivers/android/binder/range_alloc/mod.rs b/drivers/android/binder/range_alloc/mod.rs new file mode 100644 index 000000000000..2301e2bc1a1f --- /dev/null +++ b/drivers/android/binder/range_alloc/mod.rs @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use kernel::{page::PAGE_SIZE, prelude::*, seq_file::SeqFile, task::Pid}; + +mod tree; +use self::tree::{FromArrayAllocs, ReserveNewTreeAlloc, TreeRangeAllocator}; + +mod array; +use self::array::{ArrayRangeAllocator, EmptyArrayAlloc}; + +enum DescriptorState { + Reserved(Reservation), + Allocated(Allocation), +} + +impl DescriptorState { + fn new(is_oneway: bool, debug_id: usize, pid: Pid) -> Self { + DescriptorState::Reserved(Reservation { + debug_id, + is_oneway, + pid, + }) + } + + fn pid(&self) -> Pid { + match self { + DescriptorState::Reserved(inner) => inner.pid, + DescriptorState::Allocated(inner) => inner.reservation.pid, + } + } + + fn is_oneway(&self) -> bool { + match self { + DescriptorState::Reserved(inner) => inner.is_oneway, + DescriptorState::Allocated(inner) => inner.reservation.is_oneway, + } + } +} + +#[derive(Clone)] +struct Reservation { + debug_id: usize, + is_oneway: bool, + pid: Pid, +} + +impl Reservation { + fn allocate(self, data: Option) -> Allocation { + Allocation { + data, + reservation: self, + } + } +} + +struct Allocation { + reservation: Reservation, + data: Option, +} + +impl Allocation { + fn deallocate(self) -> (Reservation, Option) { + (self.reservation, self.data) + } + + fn debug_id(&self) -> usize { + self.reservation.debug_id + } + + fn take(&mut self) -> Option { + self.data.take() + } +} + +/// The array implementation must switch to the tree if it wants to go beyond this number of +/// ranges. +const TREE_THRESHOLD: usize = 8; + +/// Represents a range of pages that have just become completely free. +#[derive(Copy, Clone)] +pub(crate) struct FreedRange { + pub(crate) start_page_idx: usize, + pub(crate) end_page_idx: usize, +} + +impl FreedRange { + fn interior_pages(offset: usize, size: usize) -> FreedRange { + FreedRange { + // Divide round up + start_page_idx: offset.div_ceil(PAGE_SIZE), + // Divide round down + end_page_idx: (offset + size) / PAGE_SIZE, + } + } +} + +struct Range { + offset: usize, + size: usize, + state: DescriptorState, +} + +impl Range { + fn endpoint(&self) -> usize { + self.offset + self.size + } +} + +pub(crate) struct RangeAllocator { + inner: Impl, +} + +enum Impl { + Empty(usize), + Array(ArrayRangeAllocator), + Tree(TreeRangeAllocator), +} + +impl RangeAllocator { + pub(crate) fn new(size: usize) -> Self { + Self { + inner: Impl::Empty(size), + } + } + + pub(crate) fn free_oneway_space(&self) -> usize { + match &self.inner { + Impl::Empty(size) => size / 2, + Impl::Array(array) => array.free_oneway_space(), + Impl::Tree(tree) => tree.free_oneway_space(), + } + } + + pub(crate) fn count_buffers(&self) -> usize { + match &self.inner { + Impl::Empty(_size) => 0, + Impl::Array(array) => array.count_buffers(), + Impl::Tree(tree) => tree.count_buffers(), + } + } + + pub(crate) fn debug_print(&self, m: &SeqFile) -> Result<()> { + match &self.inner { + Impl::Empty(_size) => Ok(()), + Impl::Array(array) => array.debug_print(m), + Impl::Tree(tree) => tree.debug_print(m), + } + } + + /// Try to reserve a new buffer, using the provided allocation if necessary. + pub(crate) fn reserve_new(&mut self, mut args: ReserveNewArgs) -> Result> { + match &mut self.inner { + Impl::Empty(size) => { + let empty_array = match args.empty_array_alloc.take() { + Some(empty_array) => ArrayRangeAllocator::new(*size, empty_array), + None => { + return Ok(ReserveNew::NeedAlloc(ReserveNewNeedAlloc { + args, + need_empty_array_alloc: true, + need_new_tree_alloc: false, + need_tree_alloc: false, + })) + } + }; + + self.inner = Impl::Array(empty_array); + self.reserve_new(args) + } + Impl::Array(array) if array.is_full() => { + let allocs = match args.new_tree_alloc { + Some(ref mut allocs) => allocs, + None => { + return Ok(ReserveNew::NeedAlloc(ReserveNewNeedAlloc { + args, + need_empty_array_alloc: false, + need_new_tree_alloc: true, + need_tree_alloc: true, + })) + } + }; + + let new_tree = + TreeRangeAllocator::from_array(array.total_size(), &mut array.ranges, allocs); + + self.inner = Impl::Tree(new_tree); + self.reserve_new(args) + } + Impl::Array(array) => { + let offset = + array.reserve_new(args.debug_id, args.size, args.is_oneway, args.pid)?; + Ok(ReserveNew::Success(ReserveNewSuccess { + offset, + oneway_spam_detected: false, + _empty_array_alloc: args.empty_array_alloc, + _new_tree_alloc: args.new_tree_alloc, + _tree_alloc: args.tree_alloc, + })) + } + Impl::Tree(tree) => { + let alloc = match args.tree_alloc { + Some(alloc) => alloc, + None => { + return Ok(ReserveNew::NeedAlloc(ReserveNewNeedAlloc { + args, + need_empty_array_alloc: false, + need_new_tree_alloc: false, + need_tree_alloc: true, + })); + } + }; + let (offset, oneway_spam_detected) = + tree.reserve_new(args.debug_id, args.size, args.is_oneway, args.pid, alloc)?; + Ok(ReserveNew::Success(ReserveNewSuccess { + offset, + oneway_spam_detected, + _empty_array_alloc: args.empty_array_alloc, + _new_tree_alloc: args.new_tree_alloc, + _tree_alloc: None, + })) + } + } + } + + /// Deletes the allocations at `offset`. + pub(crate) fn reservation_abort(&mut self, offset: usize) -> Result { + match &mut self.inner { + Impl::Empty(_size) => Err(EINVAL), + Impl::Array(array) => array.reservation_abort(offset), + Impl::Tree(tree) => { + let freed_range = tree.reservation_abort(offset)?; + if tree.is_empty() { + self.inner = Impl::Empty(tree.total_size()); + } + Ok(freed_range) + } + } + } + + /// Called when an allocation is no longer in use by the kernel. + /// + /// The value in `data` will be stored, if any. A mutable reference is used to avoid dropping + /// the `T` when an error is returned. + pub(crate) fn reservation_commit(&mut self, offset: usize, data: &mut Option) -> Result { + match &mut self.inner { + Impl::Empty(_size) => Err(EINVAL), + Impl::Array(array) => array.reservation_commit(offset, data), + Impl::Tree(tree) => tree.reservation_commit(offset, data), + } + } + + /// Called when the kernel starts using an allocation. + /// + /// Returns the size of the existing entry and the data associated with it. + pub(crate) fn reserve_existing(&mut self, offset: usize) -> Result<(usize, usize, Option)> { + match &mut self.inner { + Impl::Empty(_size) => Err(EINVAL), + Impl::Array(array) => array.reserve_existing(offset), + Impl::Tree(tree) => tree.reserve_existing(offset), + } + } + + /// Call the provided callback at every allocated region. + /// + /// This destroys the range allocator. Used only during shutdown. + pub(crate) fn take_for_each)>(&mut self, callback: F) { + match &mut self.inner { + Impl::Empty(_size) => {} + Impl::Array(array) => array.take_for_each(callback), + Impl::Tree(tree) => tree.take_for_each(callback), + } + } +} + +/// The arguments for `reserve_new`. +#[derive(Default)] +pub(crate) struct ReserveNewArgs { + pub(crate) size: usize, + pub(crate) is_oneway: bool, + pub(crate) debug_id: usize, + pub(crate) pid: Pid, + pub(crate) empty_array_alloc: Option>, + pub(crate) new_tree_alloc: Option>, + pub(crate) tree_alloc: Option>, +} + +/// The return type of `ReserveNew`. +pub(crate) enum ReserveNew { + Success(ReserveNewSuccess), + NeedAlloc(ReserveNewNeedAlloc), +} + +/// Returned by `reserve_new` when the reservation was successul. +pub(crate) struct ReserveNewSuccess { + pub(crate) offset: usize, + pub(crate) oneway_spam_detected: bool, + + // If the user supplied an allocation that we did not end up using, then we return it here. + // The caller will kfree it outside of the lock. + _empty_array_alloc: Option>, + _new_tree_alloc: Option>, + _tree_alloc: Option>, +} + +/// Returned by `reserve_new` to request the caller to make an allocation before calling the method +/// again. +pub(crate) struct ReserveNewNeedAlloc { + args: ReserveNewArgs, + need_empty_array_alloc: bool, + need_new_tree_alloc: bool, + need_tree_alloc: bool, +} + +impl ReserveNewNeedAlloc { + /// Make the necessary allocations for another call to `reserve_new`. + pub(crate) fn make_alloc(mut self) -> Result> { + if self.need_empty_array_alloc && self.args.empty_array_alloc.is_none() { + self.args.empty_array_alloc = Some(EmptyArrayAlloc::try_new(TREE_THRESHOLD)?); + } + if self.need_new_tree_alloc && self.args.new_tree_alloc.is_none() { + self.args.new_tree_alloc = Some(FromArrayAllocs::try_new(TREE_THRESHOLD)?); + } + if self.need_tree_alloc && self.args.tree_alloc.is_none() { + self.args.tree_alloc = Some(ReserveNewTreeAlloc::try_new()?); + } + Ok(self.args) + } +} diff --git a/drivers/android/binder/range_alloc/tree.rs b/drivers/android/binder/range_alloc/tree.rs new file mode 100644 index 000000000000..7b1a248fcb02 --- /dev/null +++ b/drivers/android/binder/range_alloc/tree.rs @@ -0,0 +1,488 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use kernel::{ + page::PAGE_SIZE, + prelude::*, + rbtree::{RBTree, RBTreeNode, RBTreeNodeReservation}, + seq_file::SeqFile, + seq_print, + task::Pid, +}; + +use crate::range_alloc::{DescriptorState, FreedRange, Range}; + +/// Keeps track of allocations in a process' mmap. +/// +/// Each process has an mmap where the data for incoming transactions will be placed. This struct +/// keeps track of allocations made in the mmap. For each allocation, we store a descriptor that +/// has metadata related to the allocation. We also keep track of available free space. +pub(super) struct TreeRangeAllocator { + /// This collection contains descriptors for *both* ranges containing an allocation, *and* free + /// ranges between allocations. The free ranges get merged, so there are never two free ranges + /// next to each other. + tree: RBTree>, + /// Contains an entry for every free range in `self.tree`. This tree sorts the ranges by size, + /// letting us look up the smallest range whose size is at least some lower bound. + free_tree: RBTree, + size: usize, + free_oneway_space: usize, +} + +impl TreeRangeAllocator { + pub(crate) fn from_array( + size: usize, + ranges: &mut KVec>, + alloc: &mut FromArrayAllocs, + ) -> Self { + let mut tree = TreeRangeAllocator { + tree: RBTree::new(), + free_tree: RBTree::new(), + size, + free_oneway_space: size / 2, + }; + + let mut free_offset = 0; + for range in ranges.drain_all() { + let free_size = range.offset - free_offset; + if free_size > 0 { + let free_node = alloc.free_tree.pop().unwrap(); + tree.free_tree + .insert(free_node.into_node((free_size, free_offset), ())); + let tree_node = alloc.tree.pop().unwrap(); + tree.tree.insert( + tree_node.into_node(free_offset, Descriptor::new(free_offset, free_size)), + ); + } + free_offset = range.endpoint(); + + if range.state.is_oneway() { + tree.free_oneway_space = tree.free_oneway_space.saturating_sub(range.size); + } + + let free_res = alloc.free_tree.pop().unwrap(); + let tree_node = alloc.tree.pop().unwrap(); + let mut desc = Descriptor::new(range.offset, range.size); + desc.state = Some((range.state, free_res)); + tree.tree.insert(tree_node.into_node(range.offset, desc)); + } + + // After the last range, we may need a free range. + if free_offset < size { + let free_size = size - free_offset; + let free_node = alloc.free_tree.pop().unwrap(); + tree.free_tree + .insert(free_node.into_node((free_size, free_offset), ())); + let tree_node = alloc.tree.pop().unwrap(); + tree.tree + .insert(tree_node.into_node(free_offset, Descriptor::new(free_offset, free_size))); + } + + tree + } + + pub(crate) fn is_empty(&self) -> bool { + let mut tree_iter = self.tree.values(); + // There's always at least one range, because index zero is either the start of a free or + // allocated range. + let first_value = tree_iter.next().unwrap(); + if tree_iter.next().is_some() { + // There are never two free ranges next to each other, so if there is more than one + // descriptor, then at least one of them must hold an allocated range. + return false; + } + // There is only one descriptor. Return true if it is for a free range. + first_value.state.is_none() + } + + pub(crate) fn total_size(&self) -> usize { + self.size + } + + pub(crate) fn free_oneway_space(&self) -> usize { + self.free_oneway_space + } + + pub(crate) fn count_buffers(&self) -> usize { + self.tree + .values() + .filter(|desc| desc.state.is_some()) + .count() + } + + pub(crate) fn debug_print(&self, m: &SeqFile) -> Result<()> { + for desc in self.tree.values() { + let state = match &desc.state { + Some(state) => &state.0, + None => continue, + }; + seq_print!( + m, + " buffer: {} size {} pid {}", + desc.offset, + desc.size, + state.pid(), + ); + if state.is_oneway() { + seq_print!(m, " oneway"); + } + match state { + DescriptorState::Reserved(_res) => { + seq_print!(m, " reserved\n"); + } + DescriptorState::Allocated(_alloc) => { + seq_print!(m, " allocated\n"); + } + } + } + Ok(()) + } + + fn find_best_match(&mut self, size: usize) -> Option<&mut Descriptor> { + let free_cursor = self.free_tree.cursor_lower_bound(&(size, 0))?; + let ((_, offset), ()) = free_cursor.current(); + self.tree.get_mut(offset) + } + + /// Try to reserve a new buffer, using the provided allocation if necessary. + pub(crate) fn reserve_new( + &mut self, + debug_id: usize, + size: usize, + is_oneway: bool, + pid: Pid, + alloc: ReserveNewTreeAlloc, + ) -> Result<(usize, bool)> { + // Compute new value of free_oneway_space, which is set only on success. + let new_oneway_space = if is_oneway { + match self.free_oneway_space.checked_sub(size) { + Some(new_oneway_space) => new_oneway_space, + None => return Err(ENOSPC), + } + } else { + self.free_oneway_space + }; + + // Start detecting spammers once we have less than 20% + // of async space left (which is less than 10% of total + // buffer size). + // + // (This will short-circut, so `low_oneway_space` is + // only called when necessary.) + let oneway_spam_detected = + is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid); + + let (found_size, found_off, tree_node, free_tree_node) = match self.find_best_match(size) { + None => { + pr_warn!("ENOSPC from range_alloc.reserve_new - size: {}", size); + return Err(ENOSPC); + } + Some(desc) => { + let found_size = desc.size; + let found_offset = desc.offset; + + // In case we need to break up the descriptor + let new_desc = Descriptor::new(found_offset + size, found_size - size); + let (tree_node, free_tree_node, desc_node_res) = alloc.initialize(new_desc); + + desc.state = Some(( + DescriptorState::new(is_oneway, debug_id, pid), + desc_node_res, + )); + desc.size = size; + + (found_size, found_offset, tree_node, free_tree_node) + } + }; + self.free_oneway_space = new_oneway_space; + self.free_tree.remove(&(found_size, found_off)); + + if found_size != size { + self.tree.insert(tree_node); + self.free_tree.insert(free_tree_node); + } + + Ok((found_off, oneway_spam_detected)) + } + + pub(crate) fn reservation_abort(&mut self, offset: usize) -> Result { + let mut cursor = self.tree.cursor_lower_bound(&offset).ok_or_else(|| { + pr_warn!( + "EINVAL from range_alloc.reservation_abort - offset: {}", + offset + ); + EINVAL + })?; + + let (_, desc) = cursor.current_mut(); + + if desc.offset != offset { + pr_warn!( + "EINVAL from range_alloc.reservation_abort - offset: {}", + offset + ); + return Err(EINVAL); + } + + let (reservation, free_node_res) = desc.try_change_state(|state| match state { + Some((DescriptorState::Reserved(reservation), free_node_res)) => { + (None, Ok((reservation, free_node_res))) + } + None => { + pr_warn!( + "EINVAL from range_alloc.reservation_abort - offset: {}", + offset + ); + (None, Err(EINVAL)) + } + allocated => { + pr_warn!( + "EPERM from range_alloc.reservation_abort - offset: {}", + offset + ); + (allocated, Err(EPERM)) + } + })?; + + let mut size = desc.size; + let mut offset = desc.offset; + let free_oneway_space_add = if reservation.is_oneway { size } else { 0 }; + + self.free_oneway_space += free_oneway_space_add; + + let mut freed_range = FreedRange::interior_pages(offset, size); + // Compute how large the next free region needs to be to include one more page in + // the newly freed range. + let add_next_page_needed = match (offset + size) % PAGE_SIZE { + 0 => usize::MAX, + unalign => PAGE_SIZE - unalign, + }; + // Compute how large the previous free region needs to be to include one more page + // in the newly freed range. + let add_prev_page_needed = match offset % PAGE_SIZE { + 0 => usize::MAX, + unalign => unalign, + }; + + // Merge next into current if next is free + let remove_next = match cursor.peek_next() { + Some((_, next)) if next.state.is_none() => { + if next.size >= add_next_page_needed { + freed_range.end_page_idx += 1; + } + self.free_tree.remove(&(next.size, next.offset)); + size += next.size; + true + } + _ => false, + }; + + if remove_next { + let (_, desc) = cursor.current_mut(); + desc.size = size; + cursor.remove_next(); + } + + // Merge current into prev if prev is free + match cursor.peek_prev_mut() { + Some((_, prev)) if prev.state.is_none() => { + if prev.size >= add_prev_page_needed { + freed_range.start_page_idx -= 1; + } + // merge previous with current, remove current + self.free_tree.remove(&(prev.size, prev.offset)); + offset = prev.offset; + size += prev.size; + prev.size = size; + cursor.remove_current(); + } + _ => {} + }; + + self.free_tree + .insert(free_node_res.into_node((size, offset), ())); + + Ok(freed_range) + } + + pub(crate) fn reservation_commit(&mut self, offset: usize, data: &mut Option) -> Result { + let desc = self.tree.get_mut(&offset).ok_or(ENOENT)?; + + desc.try_change_state(|state| match state { + Some((DescriptorState::Reserved(reservation), free_node_res)) => ( + Some(( + DescriptorState::Allocated(reservation.allocate(data.take())), + free_node_res, + )), + Ok(()), + ), + other => (other, Err(ENOENT)), + }) + } + + /// Takes an entry at the given offset from [`DescriptorState::Allocated`] to + /// [`DescriptorState::Reserved`]. + /// + /// Returns the size of the existing entry and the data associated with it. + pub(crate) fn reserve_existing(&mut self, offset: usize) -> Result<(usize, usize, Option)> { + let desc = self.tree.get_mut(&offset).ok_or_else(|| { + pr_warn!( + "ENOENT from range_alloc.reserve_existing - offset: {}", + offset + ); + ENOENT + })?; + + let (debug_id, data) = desc.try_change_state(|state| match state { + Some((DescriptorState::Allocated(allocation), free_node_res)) => { + let (reservation, data) = allocation.deallocate(); + let debug_id = reservation.debug_id; + ( + Some((DescriptorState::Reserved(reservation), free_node_res)), + Ok((debug_id, data)), + ) + } + other => { + pr_warn!( + "ENOENT from range_alloc.reserve_existing - offset: {}", + offset + ); + (other, Err(ENOENT)) + } + })?; + + Ok((desc.size, debug_id, data)) + } + + /// Call the provided callback at every allocated region. + /// + /// This destroys the range allocator. Used only during shutdown. + pub(crate) fn take_for_each)>(&mut self, callback: F) { + for (_, desc) in self.tree.iter_mut() { + if let Some((DescriptorState::Allocated(allocation), _)) = &mut desc.state { + callback( + desc.offset, + desc.size, + allocation.debug_id(), + allocation.take(), + ); + } + } + } + + /// Find the amount and size of buffers allocated by the current caller. + /// + /// The idea is that once we cross the threshold, whoever is responsible + /// for the low async space is likely to try to send another async transaction, + /// and at some point we'll catch them in the act. This is more efficient + /// than keeping a map per pid. + fn low_oneway_space(&self, calling_pid: Pid) -> bool { + let mut total_alloc_size = 0; + let mut num_buffers = 0; + for (_, desc) in self.tree.iter() { + if let Some((state, _)) = &desc.state { + if state.is_oneway() && state.pid() == calling_pid { + total_alloc_size += desc.size; + num_buffers += 1; + } + } + } + + // Warn if this pid has more than 50 transactions, or more than 50% of + // async space (which is 25% of total buffer size). Oneway spam is only + // detected when the threshold is exceeded. + num_buffers > 50 || total_alloc_size > self.size / 4 + } +} + +type TreeDescriptorState = (DescriptorState, FreeNodeRes); +struct Descriptor { + size: usize, + offset: usize, + state: Option>, +} + +impl Descriptor { + fn new(offset: usize, size: usize) -> Self { + Self { + size, + offset, + state: None, + } + } + + fn try_change_state(&mut self, f: F) -> Result + where + F: FnOnce(Option>) -> (Option>, Result), + { + let (new_state, result) = f(self.state.take()); + self.state = new_state; + result + } +} + +// (Descriptor.size, Descriptor.offset) +type FreeKey = (usize, usize); +type FreeNodeRes = RBTreeNodeReservation; + +/// An allocation for use by `reserve_new`. +pub(crate) struct ReserveNewTreeAlloc { + tree_node_res: RBTreeNodeReservation>, + free_tree_node_res: FreeNodeRes, + desc_node_res: FreeNodeRes, +} + +impl ReserveNewTreeAlloc { + pub(crate) fn try_new() -> Result { + let tree_node_res = RBTreeNodeReservation::new(GFP_KERNEL)?; + let free_tree_node_res = RBTreeNodeReservation::new(GFP_KERNEL)?; + let desc_node_res = RBTreeNodeReservation::new(GFP_KERNEL)?; + Ok(Self { + tree_node_res, + free_tree_node_res, + desc_node_res, + }) + } + + fn initialize( + self, + desc: Descriptor, + ) -> ( + RBTreeNode>, + RBTreeNode, + FreeNodeRes, + ) { + let size = desc.size; + let offset = desc.offset; + ( + self.tree_node_res.into_node(offset, desc), + self.free_tree_node_res.into_node((size, offset), ()), + self.desc_node_res, + ) + } +} + +/// An allocation for creating a tree from an `ArrayRangeAllocator`. +pub(crate) struct FromArrayAllocs { + tree: KVec>>, + free_tree: KVec>, +} + +impl FromArrayAllocs { + pub(crate) fn try_new(len: usize) -> Result { + let num_descriptors = 2 * len + 1; + + let mut tree = KVec::with_capacity(num_descriptors, GFP_KERNEL)?; + for _ in 0..num_descriptors { + tree.push(RBTreeNodeReservation::new(GFP_KERNEL)?, GFP_KERNEL)?; + } + + let mut free_tree = KVec::with_capacity(num_descriptors, GFP_KERNEL)?; + for _ in 0..num_descriptors { + free_tree.push(RBTreeNodeReservation::new(GFP_KERNEL)?, GFP_KERNEL)?; + } + + Ok(Self { tree, free_tree }) + } +} diff --git a/drivers/android/binder/rust_binder.h b/drivers/android/binder/rust_binder.h new file mode 100644 index 000000000000..31806890ed1a --- /dev/null +++ b/drivers/android/binder/rust_binder.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Google, Inc. + */ + +#ifndef _LINUX_RUST_BINDER_H +#define _LINUX_RUST_BINDER_H + +#include +#include + +/* + * These symbols are exposed by `rust_binderfs.c` and exist here so that Rust + * Binder can call them. + */ +int init_rust_binderfs(void); + +struct dentry; +struct inode; +struct dentry *rust_binderfs_create_proc_file(struct inode *nodp, int pid); +void rust_binderfs_remove_file(struct dentry *dentry); + +#endif diff --git a/drivers/android/binder/rust_binder_events.c b/drivers/android/binder/rust_binder_events.c new file mode 100644 index 000000000000..488b1470060c --- /dev/null +++ b/drivers/android/binder/rust_binder_events.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* rust_binder_events.c + * + * Rust Binder tracepoints. + * + * Copyright 2025 Google LLC + */ + +#include "rust_binder.h" + +const char * const binder_command_strings[] = { + "BC_TRANSACTION", + "BC_REPLY", + "BC_ACQUIRE_RESULT", + "BC_FREE_BUFFER", + "BC_INCREFS", + "BC_ACQUIRE", + "BC_RELEASE", + "BC_DECREFS", + "BC_INCREFS_DONE", + "BC_ACQUIRE_DONE", + "BC_ATTEMPT_ACQUIRE", + "BC_REGISTER_LOOPER", + "BC_ENTER_LOOPER", + "BC_EXIT_LOOPER", + "BC_REQUEST_DEATH_NOTIFICATION", + "BC_CLEAR_DEATH_NOTIFICATION", + "BC_DEAD_BINDER_DONE", + "BC_TRANSACTION_SG", + "BC_REPLY_SG", +}; + +const char * const binder_return_strings[] = { + "BR_ERROR", + "BR_OK", + "BR_TRANSACTION", + "BR_REPLY", + "BR_ACQUIRE_RESULT", + "BR_DEAD_REPLY", + "BR_TRANSACTION_COMPLETE", + "BR_INCREFS", + "BR_ACQUIRE", + "BR_RELEASE", + "BR_DECREFS", + "BR_ATTEMPT_ACQUIRE", + "BR_NOOP", + "BR_SPAWN_LOOPER", + "BR_FINISHED", + "BR_DEAD_BINDER", + "BR_CLEAR_DEATH_NOTIFICATION_DONE", + "BR_FAILED_REPLY", + "BR_FROZEN_REPLY", + "BR_ONEWAY_SPAM_SUSPECT", + "BR_TRANSACTION_PENDING_FROZEN" +}; + +#define CREATE_TRACE_POINTS +#define CREATE_RUST_TRACE_POINTS +#include "rust_binder_events.h" diff --git a/drivers/android/binder/rust_binder_events.h b/drivers/android/binder/rust_binder_events.h new file mode 100644 index 000000000000..2f3efbf9dba6 --- /dev/null +++ b/drivers/android/binder/rust_binder_events.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2025 Google, Inc. + */ + +#undef TRACE_SYSTEM +#undef TRACE_INCLUDE_FILE +#undef TRACE_INCLUDE_PATH +#define TRACE_SYSTEM rust_binder +#define TRACE_INCLUDE_FILE rust_binder_events +#define TRACE_INCLUDE_PATH ../drivers/android/binder + +#if !defined(_RUST_BINDER_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _RUST_BINDER_TRACE_H + +#include + +TRACE_EVENT(rust_binder_ioctl, + TP_PROTO(unsigned int cmd, unsigned long arg), + TP_ARGS(cmd, arg), + + TP_STRUCT__entry( + __field(unsigned int, cmd) + __field(unsigned long, arg) + ), + TP_fast_assign( + __entry->cmd = cmd; + __entry->arg = arg; + ), + TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg) +); + +#endif /* _RUST_BINDER_TRACE_H */ + +/* This part must be outside protection */ +#include diff --git a/drivers/android/binder/rust_binder_internal.h b/drivers/android/binder/rust_binder_internal.h new file mode 100644 index 000000000000..78288fe7964d --- /dev/null +++ b/drivers/android/binder/rust_binder_internal.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* rust_binder_internal.h + * + * This file contains internal data structures used by Rust Binder. Mostly, + * these are type definitions used only by binderfs or things that Rust Binder + * define and export to binderfs. + * + * It does not include things exported by binderfs to Rust Binder since this + * file is not included as input to bindgen. + * + * Copyright (C) 2025 Google LLC. + */ + +#ifndef _LINUX_RUST_BINDER_INTERNAL_H +#define _LINUX_RUST_BINDER_INTERNAL_H + +#define RUST_BINDERFS_SUPER_MAGIC 0x6c6f6f71 + +#include +#include +#include + +/* + * The internal data types in the Rust Binder driver are opaque to C, so we use + * void pointer typedefs for these types. + */ +typedef void *rust_binder_context; + +/** + * struct binder_device - information about a binder device node + * @minor: the minor number used by this device + * @ctx: the Rust Context used by this device, or null for binder-control + * + * This is used as the private data for files directly in binderfs, but not + * files in the binder_logs subdirectory. This struct owns a refcount on `ctx` + * and the entry for `minor` in `binderfs_minors`. For binder-control `ctx` is + * null. + */ +struct binder_device { + int minor; + rust_binder_context ctx; +}; + +int rust_binder_stats_show(struct seq_file *m, void *unused); +int rust_binder_state_show(struct seq_file *m, void *unused); +int rust_binder_transactions_show(struct seq_file *m, void *unused); +int rust_binder_proc_show(struct seq_file *m, void *pid); + +extern const struct file_operations rust_binder_fops; +rust_binder_context rust_binder_new_context(char *name); +void rust_binder_remove_context(rust_binder_context device); + +/** + * binderfs_mount_opts - mount options for binderfs + * @max: maximum number of allocatable binderfs binder devices + * @stats_mode: enable binder stats in binderfs. + */ +struct binderfs_mount_opts { + int max; + int stats_mode; +}; + +/** + * binderfs_info - information about a binderfs mount + * @ipc_ns: The ipc namespace the binderfs mount belongs to. + * @control_dentry: This records the dentry of this binderfs mount + * binder-control device. + * @root_uid: uid that needs to be used when a new binder device is + * created. + * @root_gid: gid that needs to be used when a new binder device is + * created. + * @mount_opts: The mount options in use. + * @device_count: The current number of allocated binder devices. + * @proc_log_dir: Pointer to the directory dentry containing process-specific + * logs. + */ +struct binderfs_info { + struct ipc_namespace *ipc_ns; + struct dentry *control_dentry; + kuid_t root_uid; + kgid_t root_gid; + struct binderfs_mount_opts mount_opts; + int device_count; + struct dentry *proc_log_dir; +}; + +#endif /* _LINUX_RUST_BINDER_INTERNAL_H */ diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs new file mode 100644 index 000000000000..6773b7c273ec --- /dev/null +++ b/drivers/android/binder/rust_binder_main.rs @@ -0,0 +1,627 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! Binder -- the Android IPC mechanism. +#![recursion_limit = "256"] +#![allow( + clippy::as_underscore, + clippy::ref_as_ptr, + clippy::ptr_as_ptr, + clippy::cast_lossless +)] + +use kernel::{ + bindings::{self, seq_file}, + fs::File, + list::{ListArc, ListArcSafe, ListLinksSelfPtr, TryNewListArc}, + prelude::*, + seq_file::SeqFile, + seq_print, + sync::poll::PollTable, + sync::Arc, + task::Pid, + transmute::AsBytes, + types::ForeignOwnable, + uaccess::UserSliceWriter, +}; + +use crate::{context::Context, page_range::Shrinker, process::Process, thread::Thread}; + +use core::{ + ptr::NonNull, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, +}; + +mod allocation; +mod context; +mod deferred_close; +mod defs; +mod error; +mod node; +mod page_range; +mod process; +mod range_alloc; +mod stats; +mod thread; +mod trace; +mod transaction; + +#[allow(warnings)] // generated bindgen code +mod binderfs { + use kernel::bindings::{dentry, inode}; + + extern "C" { + pub fn init_rust_binderfs() -> kernel::ffi::c_int; + } + extern "C" { + pub fn rust_binderfs_create_proc_file( + nodp: *mut inode, + pid: kernel::ffi::c_int, + ) -> *mut dentry; + } + extern "C" { + pub fn rust_binderfs_remove_file(dentry: *mut dentry); + } + pub type rust_binder_context = *mut kernel::ffi::c_void; + #[repr(C)] + #[derive(Copy, Clone)] + pub struct binder_device { + pub minor: kernel::ffi::c_int, + pub ctx: rust_binder_context, + } + impl Default for binder_device { + fn default() -> Self { + let mut s = ::core::mem::MaybeUninit::::uninit(); + unsafe { + ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } + } +} + +module! { + type: BinderModule, + name: "rust_binder", + authors: ["Wedson Almeida Filho", "Alice Ryhl"], + description: "Android Binder", + license: "GPL", +} + +fn next_debug_id() -> usize { + static NEXT_DEBUG_ID: AtomicUsize = AtomicUsize::new(0); + + NEXT_DEBUG_ID.fetch_add(1, Ordering::Relaxed) +} + +/// Provides a single place to write Binder return values via the +/// supplied `UserSliceWriter`. +pub(crate) struct BinderReturnWriter<'a> { + writer: UserSliceWriter, + thread: &'a Thread, +} + +impl<'a> BinderReturnWriter<'a> { + fn new(writer: UserSliceWriter, thread: &'a Thread) -> Self { + BinderReturnWriter { writer, thread } + } + + /// Write a return code back to user space. + /// Should be a `BR_` constant from [`defs`] e.g. [`defs::BR_TRANSACTION_COMPLETE`]. + fn write_code(&mut self, code: u32) -> Result { + stats::GLOBAL_STATS.inc_br(code); + self.thread.process.stats.inc_br(code); + self.writer.write(&code) + } + + /// Write something *other than* a return code to user space. + fn write_payload(&mut self, payload: &T) -> Result { + self.writer.write(payload) + } + + fn len(&self) -> usize { + self.writer.len() + } +} + +/// Specifies how a type should be delivered to the read part of a BINDER_WRITE_READ ioctl. +/// +/// When a value is pushed to the todo list for a process or thread, it is stored as a trait object +/// with the type `Arc`. Trait objects are a Rust feature that lets you +/// implement dynamic dispatch over many different types. This lets us store many different types +/// in the todo list. +trait DeliverToRead: ListArcSafe + Send + Sync { + /// Performs work. Returns true if remaining work items in the queue should be processed + /// immediately, or false if it should return to caller before processing additional work + /// items. + fn do_work( + self: DArc, + thread: &Thread, + writer: &mut BinderReturnWriter<'_>, + ) -> Result; + + /// Cancels the given work item. This is called instead of [`DeliverToRead::do_work`] when work + /// won't be delivered. + fn cancel(self: DArc); + + /// Should we use `wake_up_interruptible_sync` or `wake_up_interruptible` when scheduling this + /// work item? + /// + /// Generally only set to true for non-oneway transactions. + fn should_sync_wakeup(&self) -> bool; + + fn debug_print(&self, m: &SeqFile, prefix: &str, transaction_prefix: &str) -> Result<()>; +} + +// Wrapper around a `DeliverToRead` with linked list links. +#[pin_data] +struct DTRWrap { + #[pin] + links: ListLinksSelfPtr>, + #[pin] + wrapped: T, +} +kernel::list::impl_list_arc_safe! { + impl{T: ListArcSafe + ?Sized} ListArcSafe<0> for DTRWrap { + tracked_by wrapped: T; + } +} +kernel::list::impl_list_item! { + impl ListItem<0> for DTRWrap { + using ListLinksSelfPtr { self.links }; + } +} + +impl core::ops::Deref for DTRWrap { + type Target = T; + fn deref(&self) -> &T { + &self.wrapped + } +} + +type DArc = kernel::sync::Arc>; +type DLArc = kernel::list::ListArc>; + +impl DTRWrap { + fn new(val: impl PinInit) -> impl PinInit { + pin_init!(Self { + links <- ListLinksSelfPtr::new(), + wrapped <- val, + }) + } + + fn arc_try_new(val: T) -> Result, kernel::alloc::AllocError> { + ListArc::pin_init( + try_pin_init!(Self { + links <- ListLinksSelfPtr::new(), + wrapped: val, + }), + GFP_KERNEL, + ) + .map_err(|_| kernel::alloc::AllocError) + } + + fn arc_pin_init(init: impl PinInit) -> Result, kernel::error::Error> { + ListArc::pin_init( + try_pin_init!(Self { + links <- ListLinksSelfPtr::new(), + wrapped <- init, + }), + GFP_KERNEL, + ) + } +} + +struct DeliverCode { + code: u32, + skip: AtomicBool, +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<0> for DeliverCode { untracked; } +} + +impl DeliverCode { + fn new(code: u32) -> Self { + Self { + code, + skip: AtomicBool::new(false), + } + } + + /// Disable this DeliverCode and make it do nothing. + /// + /// This is used instead of removing it from the work list, since `LinkedList::remove` is + /// unsafe, whereas this method is not. + fn skip(&self) { + self.skip.store(true, Ordering::Relaxed); + } +} + +impl DeliverToRead for DeliverCode { + fn do_work( + self: DArc, + _thread: &Thread, + writer: &mut BinderReturnWriter<'_>, + ) -> Result { + if !self.skip.load(Ordering::Relaxed) { + writer.write_code(self.code)?; + } + Ok(true) + } + + fn cancel(self: DArc) {} + + fn should_sync_wakeup(&self) -> bool { + false + } + + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + seq_print!(m, "{}", prefix); + if self.skip.load(Ordering::Relaxed) { + seq_print!(m, "(skipped) "); + } + if self.code == defs::BR_TRANSACTION_COMPLETE { + seq_print!(m, "transaction complete\n"); + } else { + seq_print!(m, "transaction error: {}\n", self.code); + } + Ok(()) + } +} + +fn ptr_align(value: usize) -> Option { + let size = core::mem::size_of::() - 1; + Some(value.checked_add(size)? & !size) +} + +// SAFETY: We call register in `init`. +static BINDER_SHRINKER: Shrinker = unsafe { Shrinker::new() }; + +struct BinderModule {} + +impl kernel::Module for BinderModule { + fn init(_module: &'static kernel::ThisModule) -> Result { + // SAFETY: The module initializer never runs twice, so we only call this once. + unsafe { crate::context::CONTEXTS.init() }; + + pr_warn!("Loaded Rust Binder."); + + BINDER_SHRINKER.register(kernel::c_str!("android-binder"))?; + + // SAFETY: The module is being loaded, so we can initialize binderfs. + unsafe { kernel::error::to_result(binderfs::init_rust_binderfs())? }; + + Ok(Self {}) + } +} + +/// Makes the inner type Sync. +#[repr(transparent)] +pub struct AssertSync(T); +// SAFETY: Used only to insert `file_operations` into a global, which is safe. +unsafe impl Sync for AssertSync {} + +/// File operations that rust_binderfs.c can use. +#[no_mangle] +#[used] +pub static rust_binder_fops: AssertSync = { + // SAFETY: All zeroes is safe for the `file_operations` type. + let zeroed_ops = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + let ops = kernel::bindings::file_operations { + owner: THIS_MODULE.as_ptr(), + poll: Some(rust_binder_poll), + unlocked_ioctl: Some(rust_binder_unlocked_ioctl), + compat_ioctl: Some(rust_binder_compat_ioctl), + mmap: Some(rust_binder_mmap), + open: Some(rust_binder_open), + release: Some(rust_binder_release), + flush: Some(rust_binder_flush), + ..zeroed_ops + }; + AssertSync(ops) +}; + +/// # Safety +/// Only called by binderfs. +#[no_mangle] +unsafe extern "C" fn rust_binder_new_context( + name: *const kernel::ffi::c_char, +) -> *mut kernel::ffi::c_void { + // SAFETY: The caller will always provide a valid c string here. + let name = unsafe { kernel::str::CStr::from_char_ptr(name) }; + match Context::new(name) { + Ok(ctx) => Arc::into_foreign(ctx), + Err(_err) => core::ptr::null_mut(), + } +} + +/// # Safety +/// Only called by binderfs. +#[no_mangle] +unsafe extern "C" fn rust_binder_remove_context(device: *mut kernel::ffi::c_void) { + if !device.is_null() { + // SAFETY: The caller ensures that the `device` pointer came from a previous call to + // `rust_binder_new_device`. + let ctx = unsafe { Arc::::from_foreign(device) }; + ctx.deregister(); + drop(ctx); + } +} + +/// # Safety +/// Only called by binderfs. +unsafe extern "C" fn rust_binder_open( + inode: *mut bindings::inode, + file_ptr: *mut bindings::file, +) -> kernel::ffi::c_int { + // SAFETY: The `rust_binderfs.c` file ensures that `i_private` is set to a + // `struct binder_device`. + let device = unsafe { (*inode).i_private } as *const binderfs::binder_device; + + assert!(!device.is_null()); + + // SAFETY: The `rust_binderfs.c` file ensures that `device->ctx` holds a binder context when + // using the rust binder fops. + let ctx = unsafe { Arc::::borrow((*device).ctx) }; + + // SAFETY: The caller provides a valid file pointer to a new `struct file`. + let file = unsafe { File::from_raw_file(file_ptr) }; + let process = match Process::open(ctx, file) { + Ok(process) => process, + Err(err) => return err.to_errno(), + }; + + // SAFETY: This is an `inode` for a newly created binder file. + match unsafe { BinderfsProcFile::new(inode, process.task.pid()) } { + Ok(Some(file)) => process.inner.lock().binderfs_file = Some(file), + Ok(None) => { /* pid already exists */ } + Err(err) => return err.to_errno(), + } + + // SAFETY: This file is associated with Rust binder, so we own the `private_data` field. + unsafe { (*file_ptr).private_data = process.into_foreign() }; + 0 +} + +/// # Safety +/// Only called by binderfs. +unsafe extern "C" fn rust_binder_release( + _inode: *mut bindings::inode, + file: *mut bindings::file, +) -> kernel::ffi::c_int { + // SAFETY: We previously set `private_data` in `rust_binder_open`. + let process = unsafe { Arc::::from_foreign((*file).private_data) }; + // SAFETY: The caller ensures that the file is valid. + let file = unsafe { File::from_raw_file(file) }; + Process::release(process, file); + 0 +} + +/// # Safety +/// Only called by binderfs. +unsafe extern "C" fn rust_binder_compat_ioctl( + file: *mut bindings::file, + cmd: kernel::ffi::c_uint, + arg: kernel::ffi::c_ulong, +) -> kernel::ffi::c_long { + // SAFETY: We previously set `private_data` in `rust_binder_open`. + let f = unsafe { Arc::::borrow((*file).private_data) }; + // SAFETY: The caller ensures that the file is valid. + match Process::compat_ioctl(f, unsafe { File::from_raw_file(file) }, cmd as _, arg as _) { + Ok(()) => 0, + Err(err) => err.to_errno() as isize, + } +} + +/// # Safety +/// Only called by binderfs. +unsafe extern "C" fn rust_binder_unlocked_ioctl( + file: *mut bindings::file, + cmd: kernel::ffi::c_uint, + arg: kernel::ffi::c_ulong, +) -> kernel::ffi::c_long { + // SAFETY: We previously set `private_data` in `rust_binder_open`. + let f = unsafe { Arc::::borrow((*file).private_data) }; + // SAFETY: The caller ensures that the file is valid. + match Process::ioctl(f, unsafe { File::from_raw_file(file) }, cmd as _, arg as _) { + Ok(()) => 0, + Err(err) => err.to_errno() as isize, + } +} + +/// # Safety +/// Only called by binderfs. +unsafe extern "C" fn rust_binder_mmap( + file: *mut bindings::file, + vma: *mut bindings::vm_area_struct, +) -> kernel::ffi::c_int { + // SAFETY: We previously set `private_data` in `rust_binder_open`. + let f = unsafe { Arc::::borrow((*file).private_data) }; + // SAFETY: The caller ensures that the vma is valid. + let area = unsafe { kernel::mm::virt::VmaNew::from_raw(vma) }; + // SAFETY: The caller ensures that the file is valid. + match Process::mmap(f, unsafe { File::from_raw_file(file) }, area) { + Ok(()) => 0, + Err(err) => err.to_errno(), + } +} + +/// # Safety +/// Only called by binderfs. +unsafe extern "C" fn rust_binder_poll( + file: *mut bindings::file, + wait: *mut bindings::poll_table_struct, +) -> bindings::__poll_t { + // SAFETY: We previously set `private_data` in `rust_binder_open`. + let f = unsafe { Arc::::borrow((*file).private_data) }; + // SAFETY: The caller ensures that the file is valid. + let fileref = unsafe { File::from_raw_file(file) }; + // SAFETY: The caller ensures that the `PollTable` is valid. + match Process::poll(f, fileref, unsafe { PollTable::from_raw(wait) }) { + Ok(v) => v, + Err(_) => bindings::POLLERR, + } +} + +/// # Safety +/// Only called by binderfs. +unsafe extern "C" fn rust_binder_flush( + file: *mut bindings::file, + _id: bindings::fl_owner_t, +) -> kernel::ffi::c_int { + // SAFETY: We previously set `private_data` in `rust_binder_open`. + let f = unsafe { Arc::::borrow((*file).private_data) }; + match Process::flush(f) { + Ok(()) => 0, + Err(err) => err.to_errno(), + } +} + +/// # Safety +/// Only called by binderfs. +#[no_mangle] +unsafe extern "C" fn rust_binder_stats_show( + ptr: *mut seq_file, + _: *mut kernel::ffi::c_void, +) -> kernel::ffi::c_int { + // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which + // this method is called. + let m = unsafe { SeqFile::from_raw(ptr) }; + if let Err(err) = rust_binder_stats_show_impl(m) { + seq_print!(m, "failed to generate state: {:?}\n", err); + } + 0 +} + +/// # Safety +/// Only called by binderfs. +#[no_mangle] +unsafe extern "C" fn rust_binder_state_show( + ptr: *mut seq_file, + _: *mut kernel::ffi::c_void, +) -> kernel::ffi::c_int { + // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which + // this method is called. + let m = unsafe { SeqFile::from_raw(ptr) }; + if let Err(err) = rust_binder_state_show_impl(m) { + seq_print!(m, "failed to generate state: {:?}\n", err); + } + 0 +} + +/// # Safety +/// Only called by binderfs. +#[no_mangle] +unsafe extern "C" fn rust_binder_proc_show( + ptr: *mut seq_file, + _: *mut kernel::ffi::c_void, +) -> kernel::ffi::c_int { + // SAFETY: Accessing the private field of `seq_file` is okay. + let pid = (unsafe { (*ptr).private }) as usize as Pid; + // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which + // this method is called. + let m = unsafe { SeqFile::from_raw(ptr) }; + if let Err(err) = rust_binder_proc_show_impl(m, pid) { + seq_print!(m, "failed to generate state: {:?}\n", err); + } + 0 +} + +/// # Safety +/// Only called by binderfs. +#[no_mangle] +unsafe extern "C" fn rust_binder_transactions_show( + ptr: *mut seq_file, + _: *mut kernel::ffi::c_void, +) -> kernel::ffi::c_int { + // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which + // this method is called. + let m = unsafe { SeqFile::from_raw(ptr) }; + if let Err(err) = rust_binder_transactions_show_impl(m) { + seq_print!(m, "failed to generate state: {:?}\n", err); + } + 0 +} + +fn rust_binder_transactions_show_impl(m: &SeqFile) -> Result<()> { + seq_print!(m, "binder transactions:\n"); + let contexts = context::get_all_contexts()?; + for ctx in contexts { + let procs = ctx.get_all_procs()?; + for proc in procs { + proc.debug_print(m, &ctx, false)?; + seq_print!(m, "\n"); + } + } + Ok(()) +} + +fn rust_binder_stats_show_impl(m: &SeqFile) -> Result<()> { + seq_print!(m, "binder stats:\n"); + stats::GLOBAL_STATS.debug_print("", m); + let contexts = context::get_all_contexts()?; + for ctx in contexts { + let procs = ctx.get_all_procs()?; + for proc in procs { + proc.debug_print_stats(m, &ctx)?; + seq_print!(m, "\n"); + } + } + Ok(()) +} + +fn rust_binder_state_show_impl(m: &SeqFile) -> Result<()> { + seq_print!(m, "binder state:\n"); + let contexts = context::get_all_contexts()?; + for ctx in contexts { + let procs = ctx.get_all_procs()?; + for proc in procs { + proc.debug_print(m, &ctx, true)?; + seq_print!(m, "\n"); + } + } + Ok(()) +} + +fn rust_binder_proc_show_impl(m: &SeqFile, pid: Pid) -> Result<()> { + seq_print!(m, "binder proc state:\n"); + let contexts = context::get_all_contexts()?; + for ctx in contexts { + let procs = ctx.get_procs_with_pid(pid)?; + for proc in procs { + proc.debug_print(m, &ctx, true)?; + seq_print!(m, "\n"); + } + } + Ok(()) +} + +struct BinderfsProcFile(NonNull); + +// SAFETY: Safe to drop any thread. +unsafe impl Send for BinderfsProcFile {} + +impl BinderfsProcFile { + /// # Safety + /// + /// Takes an inode from a newly created binder file. + unsafe fn new(nodp: *mut bindings::inode, pid: i32) -> Result> { + // SAFETY: The caller passes an `inode` for a newly created binder file. + let dentry = unsafe { binderfs::rust_binderfs_create_proc_file(nodp, pid) }; + match kernel::error::from_err_ptr(dentry) { + Ok(dentry) => Ok(NonNull::new(dentry).map(Self)), + Err(err) if err == EEXIST => Ok(None), + Err(err) => Err(err), + } + } +} + +impl Drop for BinderfsProcFile { + fn drop(&mut self) { + // SAFETY: This is a dentry from `rust_binderfs_remove_file` that has not been deleted yet. + unsafe { binderfs::rust_binderfs_remove_file(self.0.as_ptr()) }; + } +} diff --git a/drivers/android/binder/rust_binderfs.c b/drivers/android/binder/rust_binderfs.c new file mode 100644 index 000000000000..6b497146b698 --- /dev/null +++ b/drivers/android/binder/rust_binderfs.c @@ -0,0 +1,850 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rust_binder.h" +#include "rust_binder_internal.h" + +#define FIRST_INODE 1 +#define SECOND_INODE 2 +#define INODE_OFFSET 3 +#define BINDERFS_MAX_MINOR (1U << MINORBITS) +/* Ensure that the initial ipc namespace always has devices available. */ +#define BINDERFS_MAX_MINOR_CAPPED (BINDERFS_MAX_MINOR - 4) + +DEFINE_SHOW_ATTRIBUTE(rust_binder_stats); +DEFINE_SHOW_ATTRIBUTE(rust_binder_state); +DEFINE_SHOW_ATTRIBUTE(rust_binder_transactions); +DEFINE_SHOW_ATTRIBUTE(rust_binder_proc); + +char *rust_binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; +module_param_named(rust_devices, rust_binder_devices_param, charp, 0444); + +static dev_t binderfs_dev; +static DEFINE_MUTEX(binderfs_minors_mutex); +static DEFINE_IDA(binderfs_minors); + +enum binderfs_param { + Opt_max, + Opt_stats_mode, +}; + +enum binderfs_stats_mode { + binderfs_stats_mode_unset, + binderfs_stats_mode_global, +}; + +struct binder_features { + bool oneway_spam_detection; + bool extended_error; + bool freeze_notification; +}; + +static const struct constant_table binderfs_param_stats[] = { + { "global", binderfs_stats_mode_global }, + {} +}; + +static const struct fs_parameter_spec binderfs_fs_parameters[] = { + fsparam_u32("max", Opt_max), + fsparam_enum("stats", Opt_stats_mode, binderfs_param_stats), + {} +}; + +static struct binder_features binder_features = { + .oneway_spam_detection = true, + .extended_error = true, + .freeze_notification = true, +}; + +static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb) +{ + return sb->s_fs_info; +} + +/** + * binderfs_binder_device_create - allocate inode from super block of a + * binderfs mount + * @ref_inode: inode from wich the super block will be taken + * @userp: buffer to copy information about new device for userspace to + * @req: struct binderfs_device as copied from userspace + * + * This function allocates a new binder_device and reserves a new minor + * number for it. + * Minor numbers are limited and tracked globally in binderfs_minors. The + * function will stash a struct binder_device for the specific binder + * device in i_private of the inode. + * It will go on to allocate a new inode from the super block of the + * filesystem mount, stash a struct binder_device in its i_private field + * and attach a dentry to that inode. + * + * Return: 0 on success, negative errno on failure + */ +static int binderfs_binder_device_create(struct inode *ref_inode, + struct binderfs_device __user *userp, + struct binderfs_device *req) +{ + int minor, ret; + struct dentry *dentry, *root; + struct binder_device *device = NULL; + rust_binder_context ctx = NULL; + struct inode *inode = NULL; + struct super_block *sb = ref_inode->i_sb; + struct binderfs_info *info = sb->s_fs_info; +#if defined(CONFIG_IPC_NS) + bool use_reserve = (info->ipc_ns == &init_ipc_ns); +#else + bool use_reserve = true; +#endif + + /* Reserve new minor number for the new device. */ + mutex_lock(&binderfs_minors_mutex); + if (++info->device_count <= info->mount_opts.max) + minor = ida_alloc_max(&binderfs_minors, + use_reserve ? BINDERFS_MAX_MINOR : + BINDERFS_MAX_MINOR_CAPPED, + GFP_KERNEL); + else + minor = -ENOSPC; + if (minor < 0) { + --info->device_count; + mutex_unlock(&binderfs_minors_mutex); + return minor; + } + mutex_unlock(&binderfs_minors_mutex); + + ret = -ENOMEM; + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) + goto err; + + req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */ + + ctx = rust_binder_new_context(req->name); + if (!ctx) + goto err; + + inode = new_inode(sb); + if (!inode) + goto err; + + inode->i_ino = minor + INODE_OFFSET; + simple_inode_init_ts(inode); + init_special_inode(inode, S_IFCHR | 0600, + MKDEV(MAJOR(binderfs_dev), minor)); + inode->i_fop = &rust_binder_fops; + inode->i_uid = info->root_uid; + inode->i_gid = info->root_gid; + + req->major = MAJOR(binderfs_dev); + req->minor = minor; + device->ctx = ctx; + device->minor = minor; + + if (userp && copy_to_user(userp, req, sizeof(*req))) { + ret = -EFAULT; + goto err; + } + + root = sb->s_root; + inode_lock(d_inode(root)); + + /* look it up */ + dentry = lookup_noperm(&QSTR(req->name), root); + if (IS_ERR(dentry)) { + inode_unlock(d_inode(root)); + ret = PTR_ERR(dentry); + goto err; + } + + if (d_really_is_positive(dentry)) { + /* already exists */ + dput(dentry); + inode_unlock(d_inode(root)); + ret = -EEXIST; + goto err; + } + + inode->i_private = device; + d_instantiate(dentry, inode); + fsnotify_create(root->d_inode, dentry); + inode_unlock(d_inode(root)); + + return 0; + +err: + kfree(device); + rust_binder_remove_context(ctx); + mutex_lock(&binderfs_minors_mutex); + --info->device_count; + ida_free(&binderfs_minors, minor); + mutex_unlock(&binderfs_minors_mutex); + iput(inode); + + return ret; +} + +/** + * binder_ctl_ioctl - handle binder device node allocation requests + * + * The request handler for the binder-control device. All requests operate on + * the binderfs mount the binder-control device resides in: + * - BINDER_CTL_ADD + * Allocate a new binder device. + * + * Return: %0 on success, negative errno on failure. + */ +static long binder_ctl_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = -EINVAL; + struct inode *inode = file_inode(file); + struct binderfs_device __user *device = (struct binderfs_device __user *)arg; + struct binderfs_device device_req; + + switch (cmd) { + case BINDER_CTL_ADD: + ret = copy_from_user(&device_req, device, sizeof(device_req)); + if (ret) { + ret = -EFAULT; + break; + } + + ret = binderfs_binder_device_create(inode, device, &device_req); + break; + default: + break; + } + + return ret; +} + +static void binderfs_evict_inode(struct inode *inode) +{ + struct binder_device *device = inode->i_private; + struct binderfs_info *info = BINDERFS_SB(inode->i_sb); + + clear_inode(inode); + + if (!S_ISCHR(inode->i_mode) || !device) + return; + + mutex_lock(&binderfs_minors_mutex); + --info->device_count; + ida_free(&binderfs_minors, device->minor); + mutex_unlock(&binderfs_minors_mutex); + + /* ctx is null for binder-control, but this function ignores null pointers */ + rust_binder_remove_context(device->ctx); + + kfree(device); +} + +static int binderfs_fs_context_parse_param(struct fs_context *fc, + struct fs_parameter *param) +{ + int opt; + struct binderfs_mount_opts *ctx = fc->fs_private; + struct fs_parse_result result; + + opt = fs_parse(fc, binderfs_fs_parameters, param, &result); + if (opt < 0) + return opt; + + switch (opt) { + case Opt_max: + if (result.uint_32 > BINDERFS_MAX_MINOR) + return invalfc(fc, "Bad value for '%s'", param->key); + + ctx->max = result.uint_32; + break; + case Opt_stats_mode: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ctx->stats_mode = result.uint_32; + break; + default: + return invalfc(fc, "Unsupported parameter '%s'", param->key); + } + + return 0; +} + +static int binderfs_fs_context_reconfigure(struct fs_context *fc) +{ + struct binderfs_mount_opts *ctx = fc->fs_private; + struct binderfs_info *info = BINDERFS_SB(fc->root->d_sb); + + if (info->mount_opts.stats_mode != ctx->stats_mode) + return invalfc(fc, "Binderfs stats mode cannot be changed during a remount"); + + info->mount_opts.stats_mode = ctx->stats_mode; + info->mount_opts.max = ctx->max; + return 0; +} + +static int binderfs_show_options(struct seq_file *seq, struct dentry *root) +{ + struct binderfs_info *info = BINDERFS_SB(root->d_sb); + + if (info->mount_opts.max <= BINDERFS_MAX_MINOR) + seq_printf(seq, ",max=%d", info->mount_opts.max); + + switch (info->mount_opts.stats_mode) { + case binderfs_stats_mode_unset: + break; + case binderfs_stats_mode_global: + seq_puts(seq, ",stats=global"); + break; + } + + return 0; +} + +static const struct super_operations binderfs_super_ops = { + .evict_inode = binderfs_evict_inode, + .show_options = binderfs_show_options, + .statfs = simple_statfs, +}; + +static inline bool is_binderfs_control_device(const struct dentry *dentry) +{ + struct binderfs_info *info = dentry->d_sb->s_fs_info; + + return info->control_dentry == dentry; +} + +static int binderfs_rename(struct mnt_idmap *idmap, + struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +{ + if (is_binderfs_control_device(old_dentry) || + is_binderfs_control_device(new_dentry)) + return -EPERM; + + return simple_rename(idmap, old_dir, old_dentry, new_dir, + new_dentry, flags); +} + +static int binderfs_unlink(struct inode *dir, struct dentry *dentry) +{ + if (is_binderfs_control_device(dentry)) + return -EPERM; + + return simple_unlink(dir, dentry); +} + +static const struct file_operations binder_ctl_fops = { + .owner = THIS_MODULE, + .open = nonseekable_open, + .unlocked_ioctl = binder_ctl_ioctl, + .compat_ioctl = binder_ctl_ioctl, + .llseek = noop_llseek, +}; + +/** + * binderfs_binder_ctl_create - create a new binder-control device + * @sb: super block of the binderfs mount + * + * This function creates a new binder-control device node in the binderfs mount + * referred to by @sb. + * + * Return: 0 on success, negative errno on failure + */ +static int binderfs_binder_ctl_create(struct super_block *sb) +{ + int minor, ret; + struct dentry *dentry; + struct binder_device *device; + struct inode *inode = NULL; + struct dentry *root = sb->s_root; + struct binderfs_info *info = sb->s_fs_info; +#if defined(CONFIG_IPC_NS) + bool use_reserve = (info->ipc_ns == &init_ipc_ns); +#else + bool use_reserve = true; +#endif + + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) + return -ENOMEM; + + /* If we have already created a binder-control node, return. */ + if (info->control_dentry) { + ret = 0; + goto out; + } + + ret = -ENOMEM; + inode = new_inode(sb); + if (!inode) + goto out; + + /* Reserve a new minor number for the new device. */ + mutex_lock(&binderfs_minors_mutex); + minor = ida_alloc_max(&binderfs_minors, + use_reserve ? BINDERFS_MAX_MINOR : + BINDERFS_MAX_MINOR_CAPPED, + GFP_KERNEL); + mutex_unlock(&binderfs_minors_mutex); + if (minor < 0) { + ret = minor; + goto out; + } + + inode->i_ino = SECOND_INODE; + simple_inode_init_ts(inode); + init_special_inode(inode, S_IFCHR | 0600, + MKDEV(MAJOR(binderfs_dev), minor)); + inode->i_fop = &binder_ctl_fops; + inode->i_uid = info->root_uid; + inode->i_gid = info->root_gid; + + device->minor = minor; + device->ctx = NULL; + + dentry = d_alloc_name(root, "binder-control"); + if (!dentry) + goto out; + + inode->i_private = device; + info->control_dentry = dentry; + d_add(dentry, inode); + + return 0; + +out: + kfree(device); + iput(inode); + + return ret; +} + +static const struct inode_operations binderfs_dir_inode_operations = { + .lookup = simple_lookup, + .rename = binderfs_rename, + .unlink = binderfs_unlink, +}; + +static struct inode *binderfs_make_inode(struct super_block *sb, int mode) +{ + struct inode *ret; + + ret = new_inode(sb); + if (ret) { + ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET); + ret->i_mode = mode; + simple_inode_init_ts(ret); + } + return ret; +} + +static struct dentry *binderfs_create_dentry(struct dentry *parent, + const char *name) +{ + struct dentry *dentry; + + dentry = lookup_noperm(&QSTR(name), parent); + if (IS_ERR(dentry)) + return dentry; + + /* Return error if the file/dir already exists. */ + if (d_really_is_positive(dentry)) { + dput(dentry); + return ERR_PTR(-EEXIST); + } + + return dentry; +} + +void rust_binderfs_remove_file(struct dentry *dentry) +{ + struct inode *parent_inode; + + parent_inode = d_inode(dentry->d_parent); + inode_lock(parent_inode); + if (simple_positive(dentry)) { + dget(dentry); + simple_unlink(parent_inode, dentry); + d_delete(dentry); + dput(dentry); + } + inode_unlock(parent_inode); +} + +static struct dentry *rust_binderfs_create_file(struct dentry *parent, const char *name, + const struct file_operations *fops, + void *data) +{ + struct dentry *dentry; + struct inode *new_inode, *parent_inode; + struct super_block *sb; + + parent_inode = d_inode(parent); + inode_lock(parent_inode); + + dentry = binderfs_create_dentry(parent, name); + if (IS_ERR(dentry)) + goto out; + + sb = parent_inode->i_sb; + new_inode = binderfs_make_inode(sb, S_IFREG | 0444); + if (!new_inode) { + dput(dentry); + dentry = ERR_PTR(-ENOMEM); + goto out; + } + + new_inode->i_fop = fops; + new_inode->i_private = data; + d_instantiate(dentry, new_inode); + fsnotify_create(parent_inode, dentry); + +out: + inode_unlock(parent_inode); + return dentry; +} + +struct dentry *rust_binderfs_create_proc_file(struct inode *nodp, int pid) +{ + struct binderfs_info *info = nodp->i_sb->s_fs_info; + struct dentry *dir = info->proc_log_dir; + char strbuf[20 + 1]; + void *data = (void *)(unsigned long) pid; + + if (!dir) + return NULL; + + snprintf(strbuf, sizeof(strbuf), "%u", pid); + return rust_binderfs_create_file(dir, strbuf, &rust_binder_proc_fops, data); +} + +static struct dentry *binderfs_create_dir(struct dentry *parent, + const char *name) +{ + struct dentry *dentry; + struct inode *new_inode, *parent_inode; + struct super_block *sb; + + parent_inode = d_inode(parent); + inode_lock(parent_inode); + + dentry = binderfs_create_dentry(parent, name); + if (IS_ERR(dentry)) + goto out; + + sb = parent_inode->i_sb; + new_inode = binderfs_make_inode(sb, S_IFDIR | 0755); + if (!new_inode) { + dput(dentry); + dentry = ERR_PTR(-ENOMEM); + goto out; + } + + new_inode->i_fop = &simple_dir_operations; + new_inode->i_op = &simple_dir_inode_operations; + + set_nlink(new_inode, 2); + d_instantiate(dentry, new_inode); + inc_nlink(parent_inode); + fsnotify_mkdir(parent_inode, dentry); + +out: + inode_unlock(parent_inode); + return dentry; +} + +static int binder_features_show(struct seq_file *m, void *unused) +{ + bool *feature = m->private; + + seq_printf(m, "%d\n", *feature); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(binder_features); + +static int init_binder_features(struct super_block *sb) +{ + struct dentry *dentry, *dir; + + dir = binderfs_create_dir(sb->s_root, "features"); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + dentry = rust_binderfs_create_file(dir, "oneway_spam_detection", + &binder_features_fops, + &binder_features.oneway_spam_detection); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + dentry = rust_binderfs_create_file(dir, "extended_error", + &binder_features_fops, + &binder_features.extended_error); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + dentry = rust_binderfs_create_file(dir, "freeze_notification", + &binder_features_fops, + &binder_features.freeze_notification); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + return 0; +} + +static int init_binder_logs(struct super_block *sb) +{ + struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir; + struct binderfs_info *info; + int ret = 0; + + binder_logs_root_dir = binderfs_create_dir(sb->s_root, + "binder_logs"); + if (IS_ERR(binder_logs_root_dir)) { + ret = PTR_ERR(binder_logs_root_dir); + goto out; + } + + dentry = rust_binderfs_create_file(binder_logs_root_dir, "stats", + &rust_binder_stats_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = rust_binderfs_create_file(binder_logs_root_dir, "state", + &rust_binder_state_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + dentry = rust_binderfs_create_file(binder_logs_root_dir, "transactions", + &rust_binder_transactions_fops, NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } + + proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc"); + if (IS_ERR(proc_log_dir)) { + ret = PTR_ERR(proc_log_dir); + goto out; + } + info = sb->s_fs_info; + info->proc_log_dir = proc_log_dir; + +out: + return ret; +} + +static int binderfs_fill_super(struct super_block *sb, struct fs_context *fc) +{ + int ret; + struct binderfs_info *info; + struct binderfs_mount_opts *ctx = fc->fs_private; + struct inode *inode = NULL; + struct binderfs_device device_info = {}; + const char *name; + size_t len; + + sb->s_blocksize = PAGE_SIZE; + sb->s_blocksize_bits = PAGE_SHIFT; + + /* + * The binderfs filesystem can be mounted by userns root in a + * non-initial userns. By default such mounts have the SB_I_NODEV flag + * set in s_iflags to prevent security issues where userns root can + * just create random device nodes via mknod() since it owns the + * filesystem mount. But binderfs does not allow to create any files + * including devices nodes. The only way to create binder devices nodes + * is through the binder-control device which userns root is explicitly + * allowed to do. So removing the SB_I_NODEV flag from s_iflags is both + * necessary and safe. + */ + sb->s_iflags &= ~SB_I_NODEV; + sb->s_iflags |= SB_I_NOEXEC; + sb->s_magic = RUST_BINDERFS_SUPER_MAGIC; + sb->s_op = &binderfs_super_ops; + sb->s_time_gran = 1; + + sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL); + if (!sb->s_fs_info) + return -ENOMEM; + info = sb->s_fs_info; + + info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns); + + info->root_gid = make_kgid(sb->s_user_ns, 0); + if (!gid_valid(info->root_gid)) + info->root_gid = GLOBAL_ROOT_GID; + info->root_uid = make_kuid(sb->s_user_ns, 0); + if (!uid_valid(info->root_uid)) + info->root_uid = GLOBAL_ROOT_UID; + info->mount_opts.max = ctx->max; + info->mount_opts.stats_mode = ctx->stats_mode; + + inode = new_inode(sb); + if (!inode) + return -ENOMEM; + + inode->i_ino = FIRST_INODE; + inode->i_fop = &simple_dir_operations; + inode->i_mode = S_IFDIR | 0755; + simple_inode_init_ts(inode); + inode->i_op = &binderfs_dir_inode_operations; + set_nlink(inode, 2); + + sb->s_root = d_make_root(inode); + if (!sb->s_root) + return -ENOMEM; + + ret = binderfs_binder_ctl_create(sb); + if (ret) + return ret; + + name = rust_binder_devices_param; + for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { + strscpy(device_info.name, name, len + 1); + ret = binderfs_binder_device_create(inode, NULL, &device_info); + if (ret) + return ret; + name += len; + if (*name == ',') + name++; + } + + ret = init_binder_features(sb); + if (ret) + return ret; + + if (info->mount_opts.stats_mode == binderfs_stats_mode_global) + return init_binder_logs(sb); + + return 0; +} + +static int binderfs_fs_context_get_tree(struct fs_context *fc) +{ + return get_tree_nodev(fc, binderfs_fill_super); +} + +static void binderfs_fs_context_free(struct fs_context *fc) +{ + struct binderfs_mount_opts *ctx = fc->fs_private; + + kfree(ctx); +} + +static const struct fs_context_operations binderfs_fs_context_ops = { + .free = binderfs_fs_context_free, + .get_tree = binderfs_fs_context_get_tree, + .parse_param = binderfs_fs_context_parse_param, + .reconfigure = binderfs_fs_context_reconfigure, +}; + +static int binderfs_init_fs_context(struct fs_context *fc) +{ + struct binderfs_mount_opts *ctx; + + ctx = kzalloc(sizeof(struct binderfs_mount_opts), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->max = BINDERFS_MAX_MINOR; + ctx->stats_mode = binderfs_stats_mode_unset; + + fc->fs_private = ctx; + fc->ops = &binderfs_fs_context_ops; + + return 0; +} + +static void binderfs_kill_super(struct super_block *sb) +{ + struct binderfs_info *info = sb->s_fs_info; + + /* + * During inode eviction struct binderfs_info is needed. + * So first wipe the super_block then free struct binderfs_info. + */ + kill_litter_super(sb); + + if (info && info->ipc_ns) + put_ipc_ns(info->ipc_ns); + + kfree(info); +} + +static struct file_system_type binder_fs_type = { + .name = "binder", + .init_fs_context = binderfs_init_fs_context, + .parameters = binderfs_fs_parameters, + .kill_sb = binderfs_kill_super, + .fs_flags = FS_USERNS_MOUNT, +}; + +int init_rust_binderfs(void) +{ + int ret; + const char *name; + size_t len; + + /* Verify that the default binderfs device names are valid. */ + name = rust_binder_devices_param; + for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { + if (len > BINDERFS_MAX_NAME) + return -E2BIG; + name += len; + if (*name == ',') + name++; + } + + /* Allocate new major number for binderfs. */ + ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR, + "rust_binder"); + if (ret) + return ret; + + ret = register_filesystem(&binder_fs_type); + if (ret) { + unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR); + return ret; + } + + return ret; +} diff --git a/drivers/android/binder/stats.rs b/drivers/android/binder/stats.rs new file mode 100644 index 000000000000..a83ec111d2cb --- /dev/null +++ b/drivers/android/binder/stats.rs @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! Keep track of statistics for binder_logs. + +use crate::defs::*; +use core::sync::atomic::{AtomicU32, Ordering::Relaxed}; +use kernel::{ioctl::_IOC_NR, seq_file::SeqFile, seq_print}; + +const BC_COUNT: usize = _IOC_NR(BC_REPLY_SG) as usize + 1; +const BR_COUNT: usize = _IOC_NR(BR_TRANSACTION_PENDING_FROZEN) as usize + 1; + +pub(crate) static GLOBAL_STATS: BinderStats = BinderStats::new(); + +pub(crate) struct BinderStats { + bc: [AtomicU32; BC_COUNT], + br: [AtomicU32; BR_COUNT], +} + +impl BinderStats { + pub(crate) const fn new() -> Self { + #[expect(clippy::declare_interior_mutable_const)] + const ZERO: AtomicU32 = AtomicU32::new(0); + + Self { + bc: [ZERO; BC_COUNT], + br: [ZERO; BR_COUNT], + } + } + + pub(crate) fn inc_bc(&self, bc: u32) { + let idx = _IOC_NR(bc) as usize; + if let Some(bc_ref) = self.bc.get(idx) { + bc_ref.fetch_add(1, Relaxed); + } + } + + pub(crate) fn inc_br(&self, br: u32) { + let idx = _IOC_NR(br) as usize; + if let Some(br_ref) = self.br.get(idx) { + br_ref.fetch_add(1, Relaxed); + } + } + + pub(crate) fn debug_print(&self, prefix: &str, m: &SeqFile) { + for (i, cnt) in self.bc.iter().enumerate() { + let cnt = cnt.load(Relaxed); + if cnt > 0 { + seq_print!(m, "{}{}: {}\n", prefix, command_string(i), cnt); + } + } + for (i, cnt) in self.br.iter().enumerate() { + let cnt = cnt.load(Relaxed); + if cnt > 0 { + seq_print!(m, "{}{}: {}\n", prefix, return_string(i), cnt); + } + } + } +} + +mod strings { + use core::str::from_utf8_unchecked; + use kernel::str::CStr; + + extern "C" { + static binder_command_strings: [*const u8; super::BC_COUNT]; + static binder_return_strings: [*const u8; super::BR_COUNT]; + } + + pub(super) fn command_string(i: usize) -> &'static str { + // SAFETY: Accessing `binder_command_strings` is always safe. + let c_str_ptr = unsafe { binder_command_strings[i] }; + // SAFETY: The `binder_command_strings` array only contains nul-terminated strings. + let bytes = unsafe { CStr::from_char_ptr(c_str_ptr) }.as_bytes(); + // SAFETY: The `binder_command_strings` array only contains strings with ascii-chars. + unsafe { from_utf8_unchecked(bytes) } + } + + pub(super) fn return_string(i: usize) -> &'static str { + // SAFETY: Accessing `binder_return_strings` is always safe. + let c_str_ptr = unsafe { binder_return_strings[i] }; + // SAFETY: The `binder_command_strings` array only contains nul-terminated strings. + let bytes = unsafe { CStr::from_char_ptr(c_str_ptr) }.as_bytes(); + // SAFETY: The `binder_command_strings` array only contains strings with ascii-chars. + unsafe { from_utf8_unchecked(bytes) } + } +} +use strings::{command_string, return_string}; diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs new file mode 100644 index 000000000000..7e34ccd394f8 --- /dev/null +++ b/drivers/android/binder/thread.rs @@ -0,0 +1,1596 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! This module defines the `Thread` type, which represents a userspace thread that is using +//! binder. +//! +//! The `Process` object stores all of the threads in an rb tree. + +use kernel::{ + bindings, + fs::{File, LocalFile}, + list::{AtomicTracker, List, ListArc, ListLinks, TryNewListArc}, + prelude::*, + security, + seq_file::SeqFile, + seq_print, + sync::poll::{PollCondVar, PollTable}, + sync::{Arc, SpinLock}, + task::Task, + types::ARef, + uaccess::UserSlice, + uapi, +}; + +use crate::{ + allocation::{Allocation, AllocationView, BinderObject, BinderObjectRef, NewAllocation}, + defs::*, + error::BinderResult, + process::{GetWorkOrRegister, Process}, + ptr_align, + stats::GLOBAL_STATS, + transaction::Transaction, + BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverCode, DeliverToRead, +}; + +use core::{ + mem::size_of, + sync::atomic::{AtomicU32, Ordering}, +}; + +/// Stores the layout of the scatter-gather entries. This is used during the `translate_objects` +/// call and is discarded when it returns. +struct ScatterGatherState { + /// A struct that tracks the amount of unused buffer space. + unused_buffer_space: UnusedBufferSpace, + /// Scatter-gather entries to copy. + sg_entries: KVec, + /// Indexes into `sg_entries` corresponding to the last binder_buffer_object that + /// was processed and all of its ancestors. The array is in sorted order. + ancestors: KVec, +} + +/// This entry specifies an additional buffer that should be copied using the scatter-gather +/// mechanism. +struct ScatterGatherEntry { + /// The index in the offset array of the BINDER_TYPE_PTR that this entry originates from. + obj_index: usize, + /// Offset in target buffer. + offset: usize, + /// User address in source buffer. + sender_uaddr: usize, + /// Number of bytes to copy. + length: usize, + /// The minimum offset of the next fixup in this buffer. + fixup_min_offset: usize, + /// The offsets within this buffer that contain pointers which should be translated. + pointer_fixups: KVec, +} + +/// This entry specifies that a fixup should happen at `target_offset` of the +/// buffer. If `skip` is nonzero, then the fixup is a `binder_fd_array_object` +/// and is applied later. Otherwise if `skip` is zero, then the size of the +/// fixup is `sizeof::()` and `pointer_value` is written to the buffer. +struct PointerFixupEntry { + /// The number of bytes to skip, or zero for a `binder_buffer_object` fixup. + skip: usize, + /// The translated pointer to write when `skip` is zero. + pointer_value: u64, + /// The offset at which the value should be written. The offset is relative + /// to the original buffer. + target_offset: usize, +} + +/// Return type of `apply_and_validate_fixup_in_parent`. +struct ParentFixupInfo { + /// The index of the parent buffer in `sg_entries`. + parent_sg_index: usize, + /// The number of ancestors of the buffer. + /// + /// The buffer is considered an ancestor of itself, so this is always at + /// least one. + num_ancestors: usize, + /// New value of `fixup_min_offset` if this fixup is applied. + new_min_offset: usize, + /// The offset of the fixup in the target buffer. + target_offset: usize, +} + +impl ScatterGatherState { + /// Called when a `binder_buffer_object` or `binder_fd_array_object` tries + /// to access a region in its parent buffer. These accesses have various + /// restrictions, which this method verifies. + /// + /// The `parent_offset` and `length` arguments describe the offset and + /// length of the access in the parent buffer. + /// + /// # Detailed restrictions + /// + /// Obviously the fixup must be in-bounds for the parent buffer. + /// + /// For safety reasons, we only allow fixups inside a buffer to happen + /// at increasing offsets; additionally, we only allow fixup on the last + /// buffer object that was verified, or one of its parents. + /// + /// Example of what is allowed: + /// + /// A + /// B (parent = A, offset = 0) + /// C (parent = A, offset = 16) + /// D (parent = C, offset = 0) + /// E (parent = A, offset = 32) // min_offset is 16 (C.parent_offset) + /// + /// Examples of what is not allowed: + /// + /// Decreasing offsets within the same parent: + /// A + /// C (parent = A, offset = 16) + /// B (parent = A, offset = 0) // decreasing offset within A + /// + /// Arcerring to a parent that wasn't the last object or any of its parents: + /// A + /// B (parent = A, offset = 0) + /// C (parent = A, offset = 0) + /// C (parent = A, offset = 16) + /// D (parent = B, offset = 0) // B is not A or any of A's parents + fn validate_parent_fixup( + &self, + parent: usize, + parent_offset: usize, + length: usize, + ) -> Result { + // Using `position` would also be correct, but `rposition` avoids + // quadratic running times. + let ancestors_i = self + .ancestors + .iter() + .copied() + .rposition(|sg_idx| self.sg_entries[sg_idx].obj_index == parent) + .ok_or(EINVAL)?; + let sg_idx = self.ancestors[ancestors_i]; + let sg_entry = match self.sg_entries.get(sg_idx) { + Some(sg_entry) => sg_entry, + None => { + pr_err!( + "self.ancestors[{}] is {}, but self.sg_entries.len() is {}", + ancestors_i, + sg_idx, + self.sg_entries.len() + ); + return Err(EINVAL); + } + }; + if sg_entry.fixup_min_offset > parent_offset { + pr_warn!( + "validate_parent_fixup: fixup_min_offset={}, parent_offset={}", + sg_entry.fixup_min_offset, + parent_offset + ); + return Err(EINVAL); + } + let new_min_offset = parent_offset.checked_add(length).ok_or(EINVAL)?; + if new_min_offset > sg_entry.length { + pr_warn!( + "validate_parent_fixup: new_min_offset={}, sg_entry.length={}", + new_min_offset, + sg_entry.length + ); + return Err(EINVAL); + } + let target_offset = sg_entry.offset.checked_add(parent_offset).ok_or(EINVAL)?; + // The `ancestors_i + 1` operation can't overflow since the output of the addition is at + // most `self.ancestors.len()`, which also fits in a usize. + Ok(ParentFixupInfo { + parent_sg_index: sg_idx, + num_ancestors: ancestors_i + 1, + new_min_offset, + target_offset, + }) + } +} + +/// Keeps track of how much unused buffer space is left. The initial amount is the number of bytes +/// requested by the user using the `buffers_size` field of `binder_transaction_data_sg`. Each time +/// we translate an object of type `BINDER_TYPE_PTR`, some of the unused buffer space is consumed. +struct UnusedBufferSpace { + /// The start of the remaining space. + offset: usize, + /// The end of the remaining space. + limit: usize, +} +impl UnusedBufferSpace { + /// Claim the next `size` bytes from the unused buffer space. The offset for the claimed chunk + /// into the buffer is returned. + fn claim_next(&mut self, size: usize) -> Result { + // We require every chunk to be aligned. + let size = ptr_align(size).ok_or(EINVAL)?; + let new_offset = self.offset.checked_add(size).ok_or(EINVAL)?; + + if new_offset <= self.limit { + let offset = self.offset; + self.offset = new_offset; + Ok(offset) + } else { + Err(EINVAL) + } + } +} + +pub(crate) enum PushWorkRes { + Ok, + FailedDead(DLArc), +} + +impl PushWorkRes { + fn is_ok(&self) -> bool { + match self { + PushWorkRes::Ok => true, + PushWorkRes::FailedDead(_) => false, + } + } +} + +/// The fields of `Thread` protected by the spinlock. +struct InnerThread { + /// Determines the looper state of the thread. It is a bit-wise combination of the constants + /// prefixed with `LOOPER_`. + looper_flags: u32, + + /// Determines whether the looper should return. + looper_need_return: bool, + + /// Determines if thread is dead. + is_dead: bool, + + /// Work item used to deliver error codes to the thread that started a transaction. Stored here + /// so that it can be reused. + reply_work: DArc, + + /// Work item used to deliver error codes to the current thread. Stored here so that it can be + /// reused. + return_work: DArc, + + /// Determines whether the work list below should be processed. When set to false, `work_list` + /// is treated as if it were empty. + process_work_list: bool, + /// List of work items to deliver to userspace. + work_list: List>, + current_transaction: Option>, + + /// Extended error information for this thread. + extended_error: ExtendedError, +} + +const LOOPER_REGISTERED: u32 = 0x01; +const LOOPER_ENTERED: u32 = 0x02; +const LOOPER_EXITED: u32 = 0x04; +const LOOPER_INVALID: u32 = 0x08; +const LOOPER_WAITING: u32 = 0x10; +const LOOPER_WAITING_PROC: u32 = 0x20; +const LOOPER_POLL: u32 = 0x40; + +impl InnerThread { + fn new() -> Result { + fn next_err_id() -> u32 { + static EE_ID: AtomicU32 = AtomicU32::new(0); + EE_ID.fetch_add(1, Ordering::Relaxed) + } + + Ok(Self { + looper_flags: 0, + looper_need_return: false, + is_dead: false, + process_work_list: false, + reply_work: ThreadError::try_new()?, + return_work: ThreadError::try_new()?, + work_list: List::new(), + current_transaction: None, + extended_error: ExtendedError::new(next_err_id(), BR_OK, 0), + }) + } + + fn pop_work(&mut self) -> Option> { + if !self.process_work_list { + return None; + } + + let ret = self.work_list.pop_front(); + self.process_work_list = !self.work_list.is_empty(); + ret + } + + fn push_work(&mut self, work: DLArc) -> PushWorkRes { + if self.is_dead { + PushWorkRes::FailedDead(work) + } else { + self.work_list.push_back(work); + self.process_work_list = true; + PushWorkRes::Ok + } + } + + fn push_reply_work(&mut self, code: u32) { + if let Ok(work) = ListArc::try_from_arc(self.reply_work.clone()) { + work.set_error_code(code); + self.push_work(work); + } else { + pr_warn!("Thread reply work is already in use."); + } + } + + fn push_return_work(&mut self, reply: u32) { + if let Ok(work) = ListArc::try_from_arc(self.return_work.clone()) { + work.set_error_code(reply); + self.push_work(work); + } else { + pr_warn!("Thread return work is already in use."); + } + } + + /// Used to push work items that do not need to be processed immediately and can wait until the + /// thread gets another work item. + fn push_work_deferred(&mut self, work: DLArc) { + self.work_list.push_back(work); + } + + /// Fetches the transaction this thread can reply to. If the thread has a pending transaction + /// (that it could respond to) but it has also issued a transaction, it must first wait for the + /// previously-issued transaction to complete. + /// + /// The `thread` parameter should be the thread containing this `ThreadInner`. + fn pop_transaction_to_reply(&mut self, thread: &Thread) -> Result> { + let transaction = self.current_transaction.take().ok_or(EINVAL)?; + if core::ptr::eq(thread, transaction.from.as_ref()) { + self.current_transaction = Some(transaction); + return Err(EINVAL); + } + // Find a new current transaction for this thread. + self.current_transaction = transaction.find_from(thread).cloned(); + Ok(transaction) + } + + fn pop_transaction_replied(&mut self, transaction: &DArc) -> bool { + match self.current_transaction.take() { + None => false, + Some(old) => { + if !Arc::ptr_eq(transaction, &old) { + self.current_transaction = Some(old); + return false; + } + self.current_transaction = old.clone_next(); + true + } + } + } + + fn looper_enter(&mut self) { + self.looper_flags |= LOOPER_ENTERED; + if self.looper_flags & LOOPER_REGISTERED != 0 { + self.looper_flags |= LOOPER_INVALID; + } + } + + fn looper_register(&mut self, valid: bool) { + self.looper_flags |= LOOPER_REGISTERED; + if !valid || self.looper_flags & LOOPER_ENTERED != 0 { + self.looper_flags |= LOOPER_INVALID; + } + } + + fn looper_exit(&mut self) { + self.looper_flags |= LOOPER_EXITED; + } + + /// Determines whether the thread is part of a pool, i.e., if it is a looper. + fn is_looper(&self) -> bool { + self.looper_flags & (LOOPER_ENTERED | LOOPER_REGISTERED) != 0 + } + + /// Determines whether the thread should attempt to fetch work items from the process queue. + /// This is generally case when the thread is registered as a looper and not part of a + /// transaction stack. But if there is local work, we want to return to userspace before we + /// deliver any remote work. + fn should_use_process_work_queue(&self) -> bool { + self.current_transaction.is_none() && !self.process_work_list && self.is_looper() + } + + fn poll(&mut self) -> u32 { + self.looper_flags |= LOOPER_POLL; + if self.process_work_list || self.looper_need_return { + bindings::POLLIN + } else { + 0 + } + } +} + +/// This represents a thread that's used with binder. +#[pin_data] +pub(crate) struct Thread { + pub(crate) id: i32, + pub(crate) process: Arc, + pub(crate) task: ARef, + #[pin] + inner: SpinLock, + #[pin] + work_condvar: PollCondVar, + /// Used to insert this thread into the process' `ready_threads` list. + /// + /// INVARIANT: May never be used for any other list than the `self.process.ready_threads`. + #[pin] + links: ListLinks, + #[pin] + links_track: AtomicTracker, +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<0> for Thread { + tracked_by links_track: AtomicTracker; + } +} +kernel::list::impl_list_item! { + impl ListItem<0> for Thread { + using ListLinks { self.links }; + } +} + +impl Thread { + pub(crate) fn new(id: i32, process: Arc) -> Result> { + let inner = InnerThread::new()?; + + Arc::pin_init( + try_pin_init!(Thread { + id, + process, + task: ARef::from(&**kernel::current!()), + inner <- kernel::new_spinlock!(inner, "Thread::inner"), + work_condvar <- kernel::new_poll_condvar!("Thread::work_condvar"), + links <- ListLinks::new(), + links_track <- AtomicTracker::new(), + }), + GFP_KERNEL, + ) + } + + #[inline(never)] + pub(crate) fn debug_print(self: &Arc, m: &SeqFile, print_all: bool) -> Result<()> { + let inner = self.inner.lock(); + + if print_all || inner.current_transaction.is_some() || !inner.work_list.is_empty() { + seq_print!( + m, + " thread {}: l {:02x} need_return {}\n", + self.id, + inner.looper_flags, + inner.looper_need_return, + ); + } + + let mut t_opt = inner.current_transaction.as_ref(); + while let Some(t) = t_opt { + if Arc::ptr_eq(&t.from, self) { + t.debug_print_inner(m, " outgoing transaction "); + t_opt = t.from_parent.as_ref(); + } else if Arc::ptr_eq(&t.to, &self.process) { + t.debug_print_inner(m, " incoming transaction "); + t_opt = t.find_from(self); + } else { + t.debug_print_inner(m, " bad transaction "); + t_opt = None; + } + } + + for work in &inner.work_list { + work.debug_print(m, " ", " pending transaction ")?; + } + Ok(()) + } + + pub(crate) fn get_extended_error(&self, data: UserSlice) -> Result { + let mut writer = data.writer(); + let ee = self.inner.lock().extended_error; + writer.write(&ee)?; + Ok(()) + } + + pub(crate) fn set_current_transaction(&self, transaction: DArc) { + self.inner.lock().current_transaction = Some(transaction); + } + + pub(crate) fn has_current_transaction(&self) -> bool { + self.inner.lock().current_transaction.is_some() + } + + /// Attempts to fetch a work item from the thread-local queue. The behaviour if the queue is + /// empty depends on `wait`: if it is true, the function waits for some work to be queued (or a + /// signal); otherwise it returns indicating that none is available. + fn get_work_local(self: &Arc, wait: bool) -> Result>> { + { + let mut inner = self.inner.lock(); + if inner.looper_need_return { + return Ok(inner.pop_work()); + } + } + + // Try once if the caller does not want to wait. + if !wait { + return self.inner.lock().pop_work().ok_or(EAGAIN).map(Some); + } + + // Loop waiting only on the local queue (i.e., not registering with the process queue). + let mut inner = self.inner.lock(); + loop { + if let Some(work) = inner.pop_work() { + return Ok(Some(work)); + } + + inner.looper_flags |= LOOPER_WAITING; + let signal_pending = self.work_condvar.wait_interruptible_freezable(&mut inner); + inner.looper_flags &= !LOOPER_WAITING; + + if signal_pending { + return Err(EINTR); + } + if inner.looper_need_return { + return Ok(None); + } + } + } + + /// Attempts to fetch a work item from the thread-local queue, falling back to the process-wide + /// queue if none is available locally. + /// + /// This must only be called when the thread is not participating in a transaction chain. If it + /// is, the local version (`get_work_local`) should be used instead. + fn get_work(self: &Arc, wait: bool) -> Result>> { + // Try to get work from the thread's work queue, using only a local lock. + { + let mut inner = self.inner.lock(); + if let Some(work) = inner.pop_work() { + return Ok(Some(work)); + } + if inner.looper_need_return { + drop(inner); + return Ok(self.process.get_work()); + } + } + + // If the caller doesn't want to wait, try to grab work from the process queue. + // + // We know nothing will have been queued directly to the thread queue because it is not in + // a transaction and it is not in the process' ready list. + if !wait { + return self.process.get_work().ok_or(EAGAIN).map(Some); + } + + // Get work from the process queue. If none is available, atomically register as ready. + let reg = match self.process.get_work_or_register(self) { + GetWorkOrRegister::Work(work) => return Ok(Some(work)), + GetWorkOrRegister::Register(reg) => reg, + }; + + let mut inner = self.inner.lock(); + loop { + if let Some(work) = inner.pop_work() { + return Ok(Some(work)); + } + + inner.looper_flags |= LOOPER_WAITING | LOOPER_WAITING_PROC; + let signal_pending = self.work_condvar.wait_interruptible_freezable(&mut inner); + inner.looper_flags &= !(LOOPER_WAITING | LOOPER_WAITING_PROC); + + if signal_pending || inner.looper_need_return { + // We need to return now. We need to pull the thread off the list of ready threads + // (by dropping `reg`), then check the state again after it's off the list to + // ensure that something was not queued in the meantime. If something has been + // queued, we just return it (instead of the error). + drop(inner); + drop(reg); + + let res = match self.inner.lock().pop_work() { + Some(work) => Ok(Some(work)), + None if signal_pending => Err(EINTR), + None => Ok(None), + }; + return res; + } + } + } + + /// Push the provided work item to be delivered to user space via this thread. + /// + /// Returns whether the item was successfully pushed. This can only fail if the thread is dead. + pub(crate) fn push_work(&self, work: DLArc) -> PushWorkRes { + let sync = work.should_sync_wakeup(); + + let res = self.inner.lock().push_work(work); + + if res.is_ok() { + if sync { + self.work_condvar.notify_sync(); + } else { + self.work_condvar.notify_one(); + } + } + + res + } + + /// Attempts to push to given work item to the thread if it's a looper thread (i.e., if it's + /// part of a thread pool) and is alive. Otherwise, push the work item to the process instead. + pub(crate) fn push_work_if_looper(&self, work: DLArc) -> BinderResult { + let mut inner = self.inner.lock(); + if inner.is_looper() && !inner.is_dead { + inner.push_work(work); + Ok(()) + } else { + drop(inner); + self.process.push_work(work) + } + } + + pub(crate) fn push_work_deferred(&self, work: DLArc) { + self.inner.lock().push_work_deferred(work); + } + + pub(crate) fn push_return_work(&self, reply: u32) { + self.inner.lock().push_return_work(reply); + } + + fn translate_object( + &self, + obj_index: usize, + offset: usize, + object: BinderObjectRef<'_>, + view: &mut AllocationView<'_>, + allow_fds: bool, + sg_state: &mut ScatterGatherState, + ) -> BinderResult { + match object { + BinderObjectRef::Binder(obj) => { + let strong = obj.hdr.type_ == BINDER_TYPE_BINDER; + // SAFETY: `binder` is a `binder_uintptr_t`; any bit pattern is a valid + // representation. + let ptr = unsafe { obj.__bindgen_anon_1.binder } as _; + let cookie = obj.cookie as _; + let flags = obj.flags as _; + let node = self + .process + .as_arc_borrow() + .get_node(ptr, cookie, flags, strong, self)?; + security::binder_transfer_binder(&self.process.cred, &view.alloc.process.cred)?; + view.transfer_binder_object(offset, obj, strong, node)?; + } + BinderObjectRef::Handle(obj) => { + let strong = obj.hdr.type_ == BINDER_TYPE_HANDLE; + // SAFETY: `handle` is a `u32`; any bit pattern is a valid representation. + let handle = unsafe { obj.__bindgen_anon_1.handle } as _; + let node = self.process.get_node_from_handle(handle, strong)?; + security::binder_transfer_binder(&self.process.cred, &view.alloc.process.cred)?; + view.transfer_binder_object(offset, obj, strong, node)?; + } + BinderObjectRef::Fd(obj) => { + if !allow_fds { + return Err(EPERM.into()); + } + + // SAFETY: `fd` is a `u32`; any bit pattern is a valid representation. + let fd = unsafe { obj.__bindgen_anon_1.fd }; + let file = LocalFile::fget(fd)?; + // SAFETY: The binder driver never calls `fdget_pos` and this code runs from an + // ioctl, so there are no active calls to `fdget_pos` on this thread. + let file = unsafe { LocalFile::assume_no_fdget_pos(file) }; + security::binder_transfer_file( + &self.process.cred, + &view.alloc.process.cred, + &file, + )?; + + let mut obj_write = BinderFdObject::default(); + obj_write.hdr.type_ = BINDER_TYPE_FD; + // This will be overwritten with the actual fd when the transaction is received. + obj_write.__bindgen_anon_1.fd = u32::MAX; + obj_write.cookie = obj.cookie; + view.write::(offset, &obj_write)?; + + const FD_FIELD_OFFSET: usize = + core::mem::offset_of!(uapi::binder_fd_object, __bindgen_anon_1.fd); + + let field_offset = offset + FD_FIELD_OFFSET; + + view.alloc.info_add_fd(file, field_offset, false)?; + } + BinderObjectRef::Ptr(obj) => { + let obj_length = obj.length.try_into().map_err(|_| EINVAL)?; + let alloc_offset = match sg_state.unused_buffer_space.claim_next(obj_length) { + Ok(alloc_offset) => alloc_offset, + Err(err) => { + pr_warn!( + "Failed to claim space for a BINDER_TYPE_PTR. (offset: {}, limit: {}, size: {})", + sg_state.unused_buffer_space.offset, + sg_state.unused_buffer_space.limit, + obj_length, + ); + return Err(err.into()); + } + }; + + let sg_state_idx = sg_state.sg_entries.len(); + sg_state.sg_entries.push( + ScatterGatherEntry { + obj_index, + offset: alloc_offset, + sender_uaddr: obj.buffer as _, + length: obj_length, + pointer_fixups: KVec::new(), + fixup_min_offset: 0, + }, + GFP_KERNEL, + )?; + + let buffer_ptr_in_user_space = (view.alloc.ptr + alloc_offset) as u64; + + if obj.flags & uapi::BINDER_BUFFER_FLAG_HAS_PARENT == 0 { + sg_state.ancestors.clear(); + sg_state.ancestors.push(sg_state_idx, GFP_KERNEL)?; + } else { + // Another buffer also has a pointer to this buffer, and we need to fixup that + // pointer too. + + let parent_index = usize::try_from(obj.parent).map_err(|_| EINVAL)?; + let parent_offset = usize::try_from(obj.parent_offset).map_err(|_| EINVAL)?; + + let info = sg_state.validate_parent_fixup( + parent_index, + parent_offset, + size_of::(), + )?; + + sg_state.ancestors.truncate(info.num_ancestors); + sg_state.ancestors.push(sg_state_idx, GFP_KERNEL)?; + + let parent_entry = match sg_state.sg_entries.get_mut(info.parent_sg_index) { + Some(parent_entry) => parent_entry, + None => { + pr_err!( + "validate_parent_fixup returned index out of bounds for sg.entries" + ); + return Err(EINVAL.into()); + } + }; + + parent_entry.fixup_min_offset = info.new_min_offset; + parent_entry.pointer_fixups.push( + PointerFixupEntry { + skip: 0, + pointer_value: buffer_ptr_in_user_space, + target_offset: info.target_offset, + }, + GFP_KERNEL, + )?; + } + + let mut obj_write = BinderBufferObject::default(); + obj_write.hdr.type_ = BINDER_TYPE_PTR; + obj_write.flags = obj.flags; + obj_write.buffer = buffer_ptr_in_user_space; + obj_write.length = obj.length; + obj_write.parent = obj.parent; + obj_write.parent_offset = obj.parent_offset; + view.write::(offset, &obj_write)?; + } + BinderObjectRef::Fda(obj) => { + if !allow_fds { + return Err(EPERM.into()); + } + let parent_index = usize::try_from(obj.parent).map_err(|_| EINVAL)?; + let parent_offset = usize::try_from(obj.parent_offset).map_err(|_| EINVAL)?; + let num_fds = usize::try_from(obj.num_fds).map_err(|_| EINVAL)?; + let fds_len = num_fds.checked_mul(size_of::()).ok_or(EINVAL)?; + + let info = sg_state.validate_parent_fixup(parent_index, parent_offset, fds_len)?; + view.alloc.info_add_fd_reserve(num_fds)?; + + sg_state.ancestors.truncate(info.num_ancestors); + let parent_entry = match sg_state.sg_entries.get_mut(info.parent_sg_index) { + Some(parent_entry) => parent_entry, + None => { + pr_err!( + "validate_parent_fixup returned index out of bounds for sg.entries" + ); + return Err(EINVAL.into()); + } + }; + + parent_entry.fixup_min_offset = info.new_min_offset; + parent_entry + .pointer_fixups + .push( + PointerFixupEntry { + skip: fds_len, + pointer_value: 0, + target_offset: info.target_offset, + }, + GFP_KERNEL, + ) + .map_err(|_| ENOMEM)?; + + let fda_uaddr = parent_entry + .sender_uaddr + .checked_add(parent_offset) + .ok_or(EINVAL)?; + let mut fda_bytes = KVec::new(); + UserSlice::new(UserPtr::from_addr(fda_uaddr as _), fds_len) + .read_all(&mut fda_bytes, GFP_KERNEL)?; + + if fds_len != fda_bytes.len() { + pr_err!("UserSlice::read_all returned wrong length in BINDER_TYPE_FDA"); + return Err(EINVAL.into()); + } + + for i in (0..fds_len).step_by(size_of::()) { + let fd = { + let mut fd_bytes = [0u8; size_of::()]; + fd_bytes.copy_from_slice(&fda_bytes[i..i + size_of::()]); + u32::from_ne_bytes(fd_bytes) + }; + + let file = LocalFile::fget(fd)?; + // SAFETY: The binder driver never calls `fdget_pos` and this code runs from an + // ioctl, so there are no active calls to `fdget_pos` on this thread. + let file = unsafe { LocalFile::assume_no_fdget_pos(file) }; + security::binder_transfer_file( + &self.process.cred, + &view.alloc.process.cred, + &file, + )?; + + // The `validate_parent_fixup` call ensuers that this addition will not + // overflow. + view.alloc.info_add_fd(file, info.target_offset + i, true)?; + } + drop(fda_bytes); + + let mut obj_write = BinderFdArrayObject::default(); + obj_write.hdr.type_ = BINDER_TYPE_FDA; + obj_write.num_fds = obj.num_fds; + obj_write.parent = obj.parent; + obj_write.parent_offset = obj.parent_offset; + view.write::(offset, &obj_write)?; + } + } + Ok(()) + } + + fn apply_sg(&self, alloc: &mut Allocation, sg_state: &mut ScatterGatherState) -> BinderResult { + for sg_entry in &mut sg_state.sg_entries { + let mut end_of_previous_fixup = sg_entry.offset; + let offset_end = sg_entry.offset.checked_add(sg_entry.length).ok_or(EINVAL)?; + + let mut reader = + UserSlice::new(UserPtr::from_addr(sg_entry.sender_uaddr), sg_entry.length).reader(); + for fixup in &mut sg_entry.pointer_fixups { + let fixup_len = if fixup.skip == 0 { + size_of::() + } else { + fixup.skip + }; + + let target_offset_end = fixup.target_offset.checked_add(fixup_len).ok_or(EINVAL)?; + if fixup.target_offset < end_of_previous_fixup || offset_end < target_offset_end { + pr_warn!( + "Fixups oob {} {} {} {}", + fixup.target_offset, + end_of_previous_fixup, + offset_end, + target_offset_end + ); + return Err(EINVAL.into()); + } + + let copy_off = end_of_previous_fixup; + let copy_len = fixup.target_offset - end_of_previous_fixup; + if let Err(err) = alloc.copy_into(&mut reader, copy_off, copy_len) { + pr_warn!("Failed copying into alloc: {:?}", err); + return Err(err.into()); + } + if fixup.skip == 0 { + let res = alloc.write::(fixup.target_offset, &fixup.pointer_value); + if let Err(err) = res { + pr_warn!("Failed copying ptr into alloc: {:?}", err); + return Err(err.into()); + } + } + if let Err(err) = reader.skip(fixup_len) { + pr_warn!("Failed skipping {} from reader: {:?}", fixup_len, err); + return Err(err.into()); + } + end_of_previous_fixup = target_offset_end; + } + let copy_off = end_of_previous_fixup; + let copy_len = offset_end - end_of_previous_fixup; + if let Err(err) = alloc.copy_into(&mut reader, copy_off, copy_len) { + pr_warn!("Failed copying remainder into alloc: {:?}", err); + return Err(err.into()); + } + } + Ok(()) + } + + /// This method copies the payload of a transaction into the target process. + /// + /// The resulting payload will have several different components, which will be stored next to + /// each other in the allocation. Furthermore, various objects can be embedded in the payload, + /// and those objects have to be translated so that they make sense to the target transaction. + pub(crate) fn copy_transaction_data( + &self, + to_process: Arc, + tr: &BinderTransactionDataSg, + debug_id: usize, + allow_fds: bool, + txn_security_ctx_offset: Option<&mut usize>, + ) -> BinderResult { + let trd = &tr.transaction_data; + let is_oneway = trd.flags & TF_ONE_WAY != 0; + let mut secctx = if let Some(offset) = txn_security_ctx_offset { + let secid = self.process.cred.get_secid(); + let ctx = match security::SecurityCtx::from_secid(secid) { + Ok(ctx) => ctx, + Err(err) => { + pr_warn!("Failed to get security ctx for id {}: {:?}", secid, err); + return Err(err.into()); + } + }; + Some((offset, ctx)) + } else { + None + }; + + let data_size = trd.data_size.try_into().map_err(|_| EINVAL)?; + let aligned_data_size = ptr_align(data_size).ok_or(EINVAL)?; + let offsets_size = trd.offsets_size.try_into().map_err(|_| EINVAL)?; + let aligned_offsets_size = ptr_align(offsets_size).ok_or(EINVAL)?; + let buffers_size = tr.buffers_size.try_into().map_err(|_| EINVAL)?; + let aligned_buffers_size = ptr_align(buffers_size).ok_or(EINVAL)?; + let aligned_secctx_size = match secctx.as_ref() { + Some((_offset, ctx)) => ptr_align(ctx.len()).ok_or(EINVAL)?, + None => 0, + }; + + // This guarantees that at least `sizeof(usize)` bytes will be allocated. + let len = usize::max( + aligned_data_size + .checked_add(aligned_offsets_size) + .and_then(|sum| sum.checked_add(aligned_buffers_size)) + .and_then(|sum| sum.checked_add(aligned_secctx_size)) + .ok_or(ENOMEM)?, + size_of::(), + ); + let secctx_off = aligned_data_size + aligned_offsets_size + aligned_buffers_size; + let mut alloc = + match to_process.buffer_alloc(debug_id, len, is_oneway, self.process.task.pid()) { + Ok(alloc) => alloc, + Err(err) => { + pr_warn!( + "Failed to allocate buffer. len:{}, is_oneway:{}", + len, + is_oneway + ); + return Err(err); + } + }; + + // SAFETY: This accesses a union field, but it's okay because the field's type is valid for + // all bit-patterns. + let trd_data_ptr = unsafe { &trd.data.ptr }; + let mut buffer_reader = + UserSlice::new(UserPtr::from_addr(trd_data_ptr.buffer as _), data_size).reader(); + let mut end_of_previous_object = 0; + let mut sg_state = None; + + // Copy offsets if there are any. + if offsets_size > 0 { + { + let mut reader = + UserSlice::new(UserPtr::from_addr(trd_data_ptr.offsets as _), offsets_size) + .reader(); + alloc.copy_into(&mut reader, aligned_data_size, offsets_size)?; + } + + let offsets_start = aligned_data_size; + let offsets_end = aligned_data_size + aligned_offsets_size; + + // This state is used for BINDER_TYPE_PTR objects. + let sg_state = sg_state.insert(ScatterGatherState { + unused_buffer_space: UnusedBufferSpace { + offset: offsets_end, + limit: len, + }, + sg_entries: KVec::new(), + ancestors: KVec::new(), + }); + + // Traverse the objects specified. + let mut view = AllocationView::new(&mut alloc, data_size); + for (index, index_offset) in (offsets_start..offsets_end) + .step_by(size_of::()) + .enumerate() + { + let offset = view.alloc.read(index_offset)?; + + if offset < end_of_previous_object { + pr_warn!("Got transaction with invalid offset."); + return Err(EINVAL.into()); + } + + // Copy data between two objects. + if end_of_previous_object < offset { + view.copy_into( + &mut buffer_reader, + end_of_previous_object, + offset - end_of_previous_object, + )?; + } + + let mut object = BinderObject::read_from(&mut buffer_reader)?; + + match self.translate_object( + index, + offset, + object.as_ref(), + &mut view, + allow_fds, + sg_state, + ) { + Ok(()) => end_of_previous_object = offset + object.size(), + Err(err) => { + pr_warn!("Error while translating object."); + return Err(err); + } + } + + // Update the indexes containing objects to clean up. + let offset_after_object = index_offset + size_of::(); + view.alloc + .set_info_offsets(offsets_start..offset_after_object); + } + } + + // Copy remaining raw data. + alloc.copy_into( + &mut buffer_reader, + end_of_previous_object, + data_size - end_of_previous_object, + )?; + + if let Some(sg_state) = sg_state.as_mut() { + if let Err(err) = self.apply_sg(&mut alloc, sg_state) { + pr_warn!("Failure in apply_sg: {:?}", err); + return Err(err); + } + } + + if let Some((off_out, secctx)) = secctx.as_mut() { + if let Err(err) = alloc.write(secctx_off, secctx.as_bytes()) { + pr_warn!("Failed to write security context: {:?}", err); + return Err(err.into()); + } + **off_out = secctx_off; + } + Ok(alloc) + } + + fn unwind_transaction_stack(self: &Arc) { + let mut thread = self.clone(); + while let Ok(transaction) = { + let mut inner = thread.inner.lock(); + inner.pop_transaction_to_reply(thread.as_ref()) + } { + let reply = Err(BR_DEAD_REPLY); + if !transaction.from.deliver_single_reply(reply, &transaction) { + break; + } + + thread = transaction.from.clone(); + } + } + + pub(crate) fn deliver_reply( + &self, + reply: Result, u32>, + transaction: &DArc, + ) { + if self.deliver_single_reply(reply, transaction) { + transaction.from.unwind_transaction_stack(); + } + } + + /// Delivers a reply to the thread that started a transaction. The reply can either be a + /// reply-transaction or an error code to be delivered instead. + /// + /// Returns whether the thread is dead. If it is, the caller is expected to unwind the + /// transaction stack by completing transactions for threads that are dead. + fn deliver_single_reply( + &self, + reply: Result, u32>, + transaction: &DArc, + ) -> bool { + if let Ok(transaction) = &reply { + transaction.set_outstanding(&mut self.process.inner.lock()); + } + + { + let mut inner = self.inner.lock(); + if !inner.pop_transaction_replied(transaction) { + return false; + } + + if inner.is_dead { + return true; + } + + match reply { + Ok(work) => { + inner.push_work(work); + } + Err(code) => inner.push_reply_work(code), + } + } + + // Notify the thread now that we've released the inner lock. + self.work_condvar.notify_sync(); + false + } + + /// Determines if the given transaction is the current transaction for this thread. + fn is_current_transaction(&self, transaction: &DArc) -> bool { + let inner = self.inner.lock(); + match &inner.current_transaction { + None => false, + Some(current) => Arc::ptr_eq(current, transaction), + } + } + + /// Determines the current top of the transaction stack. It fails if the top is in another + /// thread (i.e., this thread belongs to a stack but it has called another thread). The top is + /// [`None`] if the thread is not currently participating in a transaction stack. + fn top_of_transaction_stack(&self) -> Result>> { + let inner = self.inner.lock(); + if let Some(cur) = &inner.current_transaction { + if core::ptr::eq(self, cur.from.as_ref()) { + pr_warn!("got new transaction with bad transaction stack"); + return Err(EINVAL); + } + Ok(Some(cur.clone())) + } else { + Ok(None) + } + } + + fn transaction(self: &Arc, tr: &BinderTransactionDataSg, inner: T) + where + T: FnOnce(&Arc, &BinderTransactionDataSg) -> BinderResult, + { + if let Err(err) = inner(self, tr) { + if err.should_pr_warn() { + let mut ee = self.inner.lock().extended_error; + ee.command = err.reply; + ee.param = err.as_errno(); + pr_warn!( + "Transaction failed: {:?} my_pid:{}", + err, + self.process.pid_in_current_ns() + ); + } + + self.push_return_work(err.reply); + } + } + + fn transaction_inner(self: &Arc, tr: &BinderTransactionDataSg) -> BinderResult { + // SAFETY: Handle's type has no invalid bit patterns. + let handle = unsafe { tr.transaction_data.target.handle }; + let node_ref = self.process.get_transaction_node(handle)?; + security::binder_transaction(&self.process.cred, &node_ref.node.owner.cred)?; + // TODO: We need to ensure that there isn't a pending transaction in the work queue. How + // could this happen? + let top = self.top_of_transaction_stack()?; + let list_completion = DTRWrap::arc_try_new(DeliverCode::new(BR_TRANSACTION_COMPLETE))?; + let completion = list_completion.clone_arc(); + let transaction = Transaction::new(node_ref, top, self, tr)?; + + // Check that the transaction stack hasn't changed while the lock was released, then update + // it with the new transaction. + { + let mut inner = self.inner.lock(); + if !transaction.is_stacked_on(&inner.current_transaction) { + pr_warn!("Transaction stack changed during transaction!"); + return Err(EINVAL.into()); + } + inner.current_transaction = Some(transaction.clone_arc()); + // We push the completion as a deferred work so that we wait for the reply before + // returning to userland. + inner.push_work_deferred(list_completion); + } + + if let Err(e) = transaction.submit() { + completion.skip(); + // Define `transaction` first to drop it after `inner`. + let transaction; + let mut inner = self.inner.lock(); + transaction = inner.current_transaction.take().unwrap(); + inner.current_transaction = transaction.clone_next(); + Err(e) + } else { + Ok(()) + } + } + + fn reply_inner(self: &Arc, tr: &BinderTransactionDataSg) -> BinderResult { + let orig = self.inner.lock().pop_transaction_to_reply(self)?; + if !orig.from.is_current_transaction(&orig) { + return Err(EINVAL.into()); + } + + // We need to complete the transaction even if we cannot complete building the reply. + let out = (|| -> BinderResult<_> { + let completion = DTRWrap::arc_try_new(DeliverCode::new(BR_TRANSACTION_COMPLETE))?; + let process = orig.from.process.clone(); + let allow_fds = orig.flags & TF_ACCEPT_FDS != 0; + let reply = Transaction::new_reply(self, process, tr, allow_fds)?; + self.inner.lock().push_work(completion); + orig.from.deliver_reply(Ok(reply), &orig); + Ok(()) + })() + .map_err(|mut err| { + // At this point we only return `BR_TRANSACTION_COMPLETE` to the caller, and we must let + // the sender know that the transaction has completed (with an error in this case). + pr_warn!( + "Failure {:?} during reply - delivering BR_FAILED_REPLY to sender.", + err + ); + let reply = Err(BR_FAILED_REPLY); + orig.from.deliver_reply(reply, &orig); + err.reply = BR_TRANSACTION_COMPLETE; + err + }); + + out + } + + fn oneway_transaction_inner(self: &Arc, tr: &BinderTransactionDataSg) -> BinderResult { + // SAFETY: The `handle` field is valid for all possible byte values, so reading from the + // union is okay. + let handle = unsafe { tr.transaction_data.target.handle }; + let node_ref = self.process.get_transaction_node(handle)?; + security::binder_transaction(&self.process.cred, &node_ref.node.owner.cred)?; + let transaction = Transaction::new(node_ref, None, self, tr)?; + let code = if self.process.is_oneway_spam_detection_enabled() + && transaction.oneway_spam_detected + { + BR_ONEWAY_SPAM_SUSPECT + } else { + BR_TRANSACTION_COMPLETE + }; + let list_completion = DTRWrap::arc_try_new(DeliverCode::new(code))?; + let completion = list_completion.clone_arc(); + self.inner.lock().push_work(list_completion); + match transaction.submit() { + Ok(()) => Ok(()), + Err(err) => { + completion.skip(); + Err(err) + } + } + } + + fn write(self: &Arc, req: &mut BinderWriteRead) -> Result { + let write_start = req.write_buffer.wrapping_add(req.write_consumed); + let write_len = req.write_size.saturating_sub(req.write_consumed); + let mut reader = + UserSlice::new(UserPtr::from_addr(write_start as _), write_len as _).reader(); + + while reader.len() >= size_of::() && self.inner.lock().return_work.is_unused() { + let before = reader.len(); + let cmd = reader.read::()?; + GLOBAL_STATS.inc_bc(cmd); + self.process.stats.inc_bc(cmd); + match cmd { + BC_TRANSACTION => { + let tr = reader.read::()?.with_buffers_size(0); + if tr.transaction_data.flags & TF_ONE_WAY != 0 { + self.transaction(&tr, Self::oneway_transaction_inner); + } else { + self.transaction(&tr, Self::transaction_inner); + } + } + BC_TRANSACTION_SG => { + let tr = reader.read::()?; + if tr.transaction_data.flags & TF_ONE_WAY != 0 { + self.transaction(&tr, Self::oneway_transaction_inner); + } else { + self.transaction(&tr, Self::transaction_inner); + } + } + BC_REPLY => { + let tr = reader.read::()?.with_buffers_size(0); + self.transaction(&tr, Self::reply_inner) + } + BC_REPLY_SG => { + let tr = reader.read::()?; + self.transaction(&tr, Self::reply_inner) + } + BC_FREE_BUFFER => { + let buffer = self.process.buffer_get(reader.read()?); + if let Some(buffer) = &buffer { + if buffer.looper_need_return_on_free() { + self.inner.lock().looper_need_return = true; + } + } + drop(buffer); + } + BC_INCREFS => { + self.process + .as_arc_borrow() + .update_ref(reader.read()?, true, false)? + } + BC_ACQUIRE => { + self.process + .as_arc_borrow() + .update_ref(reader.read()?, true, true)? + } + BC_RELEASE => { + self.process + .as_arc_borrow() + .update_ref(reader.read()?, false, true)? + } + BC_DECREFS => { + self.process + .as_arc_borrow() + .update_ref(reader.read()?, false, false)? + } + BC_INCREFS_DONE => self.process.inc_ref_done(&mut reader, false)?, + BC_ACQUIRE_DONE => self.process.inc_ref_done(&mut reader, true)?, + BC_REQUEST_DEATH_NOTIFICATION => self.process.request_death(&mut reader, self)?, + BC_CLEAR_DEATH_NOTIFICATION => self.process.clear_death(&mut reader, self)?, + BC_DEAD_BINDER_DONE => self.process.dead_binder_done(reader.read()?, self), + BC_REGISTER_LOOPER => { + let valid = self.process.register_thread(); + self.inner.lock().looper_register(valid); + } + BC_ENTER_LOOPER => self.inner.lock().looper_enter(), + BC_EXIT_LOOPER => self.inner.lock().looper_exit(), + BC_REQUEST_FREEZE_NOTIFICATION => self.process.request_freeze_notif(&mut reader)?, + BC_CLEAR_FREEZE_NOTIFICATION => self.process.clear_freeze_notif(&mut reader)?, + BC_FREEZE_NOTIFICATION_DONE => self.process.freeze_notif_done(&mut reader)?, + + // Fail if given an unknown error code. + // BC_ATTEMPT_ACQUIRE and BC_ACQUIRE_RESULT are no longer supported. + _ => return Err(EINVAL), + } + // Update the number of write bytes consumed. + req.write_consumed += (before - reader.len()) as u64; + } + + Ok(()) + } + + fn read(self: &Arc, req: &mut BinderWriteRead, wait: bool) -> Result { + let read_start = req.read_buffer.wrapping_add(req.read_consumed); + let read_len = req.read_size.saturating_sub(req.read_consumed); + let mut writer = BinderReturnWriter::new( + UserSlice::new(UserPtr::from_addr(read_start as _), read_len as _).writer(), + self, + ); + let (in_pool, use_proc_queue) = { + let inner = self.inner.lock(); + (inner.is_looper(), inner.should_use_process_work_queue()) + }; + + let getter = if use_proc_queue { + Self::get_work + } else { + Self::get_work_local + }; + + // Reserve some room at the beginning of the read buffer so that we can send a + // BR_SPAWN_LOOPER if we need to. + let mut has_noop_placeholder = false; + if req.read_consumed == 0 { + if let Err(err) = writer.write_code(BR_NOOP) { + pr_warn!("Failure when writing BR_NOOP at beginning of buffer."); + return Err(err); + } + has_noop_placeholder = true; + } + + // Loop doing work while there is room in the buffer. + let initial_len = writer.len(); + while writer.len() >= size_of::() + 4 { + match getter(self, wait && initial_len == writer.len()) { + Ok(Some(work)) => match work.into_arc().do_work(self, &mut writer) { + Ok(true) => {} + Ok(false) => break, + Err(err) => { + return Err(err); + } + }, + Ok(None) => { + break; + } + Err(err) => { + // Propagate the error if we haven't written anything else. + if err != EINTR && err != EAGAIN { + pr_warn!("Failure in work getter: {:?}", err); + } + if initial_len == writer.len() { + return Err(err); + } else { + break; + } + } + } + } + + req.read_consumed += read_len - writer.len() as u64; + + // Write BR_SPAWN_LOOPER if the process needs more threads for its pool. + if has_noop_placeholder && in_pool && self.process.needs_thread() { + let mut writer = + UserSlice::new(UserPtr::from_addr(req.read_buffer as _), req.read_size as _) + .writer(); + writer.write(&BR_SPAWN_LOOPER)?; + } + Ok(()) + } + + pub(crate) fn write_read(self: &Arc, data: UserSlice, wait: bool) -> Result { + let (mut reader, mut writer) = data.reader_writer(); + let mut req = reader.read::()?; + + // Go through the write buffer. + let mut ret = Ok(()); + if req.write_size > 0 { + ret = self.write(&mut req); + if let Err(err) = ret { + pr_warn!( + "Write failure {:?} in pid:{}", + err, + self.process.pid_in_current_ns() + ); + req.read_consumed = 0; + writer.write(&req)?; + self.inner.lock().looper_need_return = false; + return ret; + } + } + + // Go through the work queue. + if req.read_size > 0 { + ret = self.read(&mut req, wait); + if ret.is_err() && ret != Err(EINTR) { + pr_warn!( + "Read failure {:?} in pid:{}", + ret, + self.process.pid_in_current_ns() + ); + } + } + + // Write the request back so that the consumed fields are visible to the caller. + writer.write(&req)?; + + self.inner.lock().looper_need_return = false; + + ret + } + + pub(crate) fn poll(&self, file: &File, table: PollTable<'_>) -> (bool, u32) { + table.register_wait(file, &self.work_condvar); + let mut inner = self.inner.lock(); + (inner.should_use_process_work_queue(), inner.poll()) + } + + /// Make the call to `get_work` or `get_work_local` return immediately, if any. + pub(crate) fn exit_looper(&self) { + let mut inner = self.inner.lock(); + let should_notify = inner.looper_flags & LOOPER_WAITING != 0; + if should_notify { + inner.looper_need_return = true; + } + drop(inner); + + if should_notify { + self.work_condvar.notify_one(); + } + } + + pub(crate) fn notify_if_poll_ready(&self, sync: bool) { + // Determine if we need to notify. This requires the lock. + let inner = self.inner.lock(); + let notify = inner.looper_flags & LOOPER_POLL != 0 && inner.should_use_process_work_queue(); + drop(inner); + + // Now that the lock is no longer held, notify the waiters if we have to. + if notify { + if sync { + self.work_condvar.notify_sync(); + } else { + self.work_condvar.notify_one(); + } + } + } + + pub(crate) fn release(self: &Arc) { + self.inner.lock().is_dead = true; + + //self.work_condvar.clear(); + self.unwind_transaction_stack(); + + // Cancel all pending work items. + while let Ok(Some(work)) = self.get_work_local(false) { + work.into_arc().cancel(); + } + } +} + +#[pin_data] +struct ThreadError { + error_code: AtomicU32, + #[pin] + links_track: AtomicTracker, +} + +impl ThreadError { + fn try_new() -> Result> { + DTRWrap::arc_pin_init(pin_init!(Self { + error_code: AtomicU32::new(BR_OK), + links_track <- AtomicTracker::new(), + })) + .map(ListArc::into_arc) + } + + fn set_error_code(&self, code: u32) { + self.error_code.store(code, Ordering::Relaxed); + } + + fn is_unused(&self) -> bool { + self.error_code.load(Ordering::Relaxed) == BR_OK + } +} + +impl DeliverToRead for ThreadError { + fn do_work( + self: DArc, + _thread: &Thread, + writer: &mut BinderReturnWriter<'_>, + ) -> Result { + let code = self.error_code.load(Ordering::Relaxed); + self.error_code.store(BR_OK, Ordering::Relaxed); + writer.write_code(code)?; + Ok(true) + } + + fn cancel(self: DArc) {} + + fn should_sync_wakeup(&self) -> bool { + false + } + + fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> { + seq_print!( + m, + "{}transaction error: {}\n", + prefix, + self.error_code.load(Ordering::Relaxed) + ); + Ok(()) + } +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<0> for ThreadError { + tracked_by links_track: AtomicTracker; + } +} diff --git a/drivers/android/binder/trace.rs b/drivers/android/binder/trace.rs new file mode 100644 index 000000000000..af0e4392805e --- /dev/null +++ b/drivers/android/binder/trace.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use kernel::ffi::{c_uint, c_ulong}; +use kernel::tracepoint::declare_trace; + +declare_trace! { + unsafe fn rust_binder_ioctl(cmd: c_uint, arg: c_ulong); +} + +#[inline] +pub(crate) fn trace_ioctl(cmd: u32, arg: usize) { + // SAFETY: Always safe to call. + unsafe { rust_binder_ioctl(cmd, arg as c_ulong) } +} diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs new file mode 100644 index 000000000000..02512175d622 --- /dev/null +++ b/drivers/android/binder/transaction.rs @@ -0,0 +1,456 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +use core::sync::atomic::{AtomicBool, Ordering}; +use kernel::{ + prelude::*, + seq_file::SeqFile, + seq_print, + sync::{Arc, SpinLock}, + task::Kuid, + time::{Instant, Monotonic}, + types::ScopeGuard, +}; + +use crate::{ + allocation::{Allocation, TranslatedFds}, + defs::*, + error::{BinderError, BinderResult}, + node::{Node, NodeRef}, + process::{Process, ProcessInner}, + ptr_align, + thread::{PushWorkRes, Thread}, + BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverToRead, +}; + +#[pin_data(PinnedDrop)] +pub(crate) struct Transaction { + pub(crate) debug_id: usize, + target_node: Option>, + pub(crate) from_parent: Option>, + pub(crate) from: Arc, + pub(crate) to: Arc, + #[pin] + allocation: SpinLock>, + is_outstanding: AtomicBool, + code: u32, + pub(crate) flags: u32, + data_size: usize, + offsets_size: usize, + data_address: usize, + sender_euid: Kuid, + txn_security_ctx_off: Option, + pub(crate) oneway_spam_detected: bool, + start_time: Instant, +} + +kernel::list::impl_list_arc_safe! { + impl ListArcSafe<0> for Transaction { untracked; } +} + +impl Transaction { + pub(crate) fn new( + node_ref: NodeRef, + from_parent: Option>, + from: &Arc, + tr: &BinderTransactionDataSg, + ) -> BinderResult> { + let debug_id = super::next_debug_id(); + let trd = &tr.transaction_data; + let allow_fds = node_ref.node.flags & FLAT_BINDER_FLAG_ACCEPTS_FDS != 0; + let txn_security_ctx = node_ref.node.flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX != 0; + let mut txn_security_ctx_off = if txn_security_ctx { Some(0) } else { None }; + let to = node_ref.node.owner.clone(); + let mut alloc = match from.copy_transaction_data( + to.clone(), + tr, + debug_id, + allow_fds, + txn_security_ctx_off.as_mut(), + ) { + Ok(alloc) => alloc, + Err(err) => { + if !err.is_dead() { + pr_warn!("Failure in copy_transaction_data: {:?}", err); + } + return Err(err); + } + }; + let oneway_spam_detected = alloc.oneway_spam_detected; + if trd.flags & TF_ONE_WAY != 0 { + if from_parent.is_some() { + pr_warn!("Oneway transaction should not be in a transaction stack."); + return Err(EINVAL.into()); + } + alloc.set_info_oneway_node(node_ref.node.clone()); + } + if trd.flags & TF_CLEAR_BUF != 0 { + alloc.set_info_clear_on_drop(); + } + let target_node = node_ref.node.clone(); + alloc.set_info_target_node(node_ref); + let data_address = alloc.ptr; + + Ok(DTRWrap::arc_pin_init(pin_init!(Transaction { + debug_id, + target_node: Some(target_node), + from_parent, + sender_euid: from.process.task.euid(), + from: from.clone(), + to, + code: trd.code, + flags: trd.flags, + data_size: trd.data_size as _, + offsets_size: trd.offsets_size as _, + data_address, + allocation <- kernel::new_spinlock!(Some(alloc.success()), "Transaction::new"), + is_outstanding: AtomicBool::new(false), + txn_security_ctx_off, + oneway_spam_detected, + start_time: Instant::now(), + }))?) + } + + pub(crate) fn new_reply( + from: &Arc, + to: Arc, + tr: &BinderTransactionDataSg, + allow_fds: bool, + ) -> BinderResult> { + let debug_id = super::next_debug_id(); + let trd = &tr.transaction_data; + let mut alloc = match from.copy_transaction_data(to.clone(), tr, debug_id, allow_fds, None) + { + Ok(alloc) => alloc, + Err(err) => { + pr_warn!("Failure in copy_transaction_data: {:?}", err); + return Err(err); + } + }; + let oneway_spam_detected = alloc.oneway_spam_detected; + if trd.flags & TF_CLEAR_BUF != 0 { + alloc.set_info_clear_on_drop(); + } + Ok(DTRWrap::arc_pin_init(pin_init!(Transaction { + debug_id, + target_node: None, + from_parent: None, + sender_euid: from.process.task.euid(), + from: from.clone(), + to, + code: trd.code, + flags: trd.flags, + data_size: trd.data_size as _, + offsets_size: trd.offsets_size as _, + data_address: alloc.ptr, + allocation <- kernel::new_spinlock!(Some(alloc.success()), "Transaction::new"), + is_outstanding: AtomicBool::new(false), + txn_security_ctx_off: None, + oneway_spam_detected, + start_time: Instant::now(), + }))?) + } + + #[inline(never)] + pub(crate) fn debug_print_inner(&self, m: &SeqFile, prefix: &str) { + seq_print!( + m, + "{}{}: from {}:{} to {} code {:x} flags {:x} elapsed {}ms", + prefix, + self.debug_id, + self.from.process.task.pid(), + self.from.id, + self.to.task.pid(), + self.code, + self.flags, + self.start_time.elapsed().as_millis(), + ); + if let Some(target_node) = &self.target_node { + seq_print!(m, " node {}", target_node.debug_id); + } + seq_print!(m, " size {}:{}\n", self.data_size, self.offsets_size); + } + + /// Determines if the transaction is stacked on top of the given transaction. + pub(crate) fn is_stacked_on(&self, onext: &Option>) -> bool { + match (&self.from_parent, onext) { + (None, None) => true, + (Some(from_parent), Some(next)) => Arc::ptr_eq(from_parent, next), + _ => false, + } + } + + /// Returns a pointer to the next transaction on the transaction stack, if there is one. + pub(crate) fn clone_next(&self) -> Option> { + Some(self.from_parent.as_ref()?.clone()) + } + + /// Searches in the transaction stack for a thread that belongs to the target process. This is + /// useful when finding a target for a new transaction: if the node belongs to a process that + /// is already part of the transaction stack, we reuse the thread. + fn find_target_thread(&self) -> Option> { + let mut it = &self.from_parent; + while let Some(transaction) = it { + if Arc::ptr_eq(&transaction.from.process, &self.to) { + return Some(transaction.from.clone()); + } + it = &transaction.from_parent; + } + None + } + + /// Searches in the transaction stack for a transaction originating at the given thread. + pub(crate) fn find_from(&self, thread: &Thread) -> Option<&DArc> { + let mut it = &self.from_parent; + while let Some(transaction) = it { + if core::ptr::eq(thread, transaction.from.as_ref()) { + return Some(transaction); + } + + it = &transaction.from_parent; + } + None + } + + pub(crate) fn set_outstanding(&self, to_process: &mut ProcessInner) { + // No race because this method is only called once. + if !self.is_outstanding.load(Ordering::Relaxed) { + self.is_outstanding.store(true, Ordering::Relaxed); + to_process.add_outstanding_txn(); + } + } + + /// Decrement `outstanding_txns` in `to` if it hasn't already been decremented. + fn drop_outstanding_txn(&self) { + // No race because this is called at most twice, and one of the calls are in the + // destructor, which is guaranteed to not race with any other operations on the + // transaction. It also cannot race with `set_outstanding`, since submission happens + // before delivery. + if self.is_outstanding.load(Ordering::Relaxed) { + self.is_outstanding.store(false, Ordering::Relaxed); + self.to.drop_outstanding_txn(); + } + } + + /// Submits the transaction to a work queue. Uses a thread if there is one in the transaction + /// stack, otherwise uses the destination process. + /// + /// Not used for replies. + pub(crate) fn submit(self: DLArc) -> BinderResult { + // Defined before `process_inner` so that the destructor runs after releasing the lock. + let mut _t_outdated; + + let oneway = self.flags & TF_ONE_WAY != 0; + let process = self.to.clone(); + let mut process_inner = process.inner.lock(); + + self.set_outstanding(&mut process_inner); + + if oneway { + if let Some(target_node) = self.target_node.clone() { + if process_inner.is_frozen { + process_inner.async_recv = true; + if self.flags & TF_UPDATE_TXN != 0 { + if let Some(t_outdated) = + target_node.take_outdated_transaction(&self, &mut process_inner) + { + // Save the transaction to be dropped after locks are released. + _t_outdated = t_outdated; + } + } + } + match target_node.submit_oneway(self, &mut process_inner) { + Ok(()) => {} + Err((err, work)) => { + drop(process_inner); + // Drop work after releasing process lock. + drop(work); + return Err(err); + } + } + + if process_inner.is_frozen { + return Err(BinderError::new_frozen_oneway()); + } else { + return Ok(()); + } + } else { + pr_err!("Failed to submit oneway transaction to node."); + } + } + + if process_inner.is_frozen { + process_inner.sync_recv = true; + return Err(BinderError::new_frozen()); + } + + let res = if let Some(thread) = self.find_target_thread() { + match thread.push_work(self) { + PushWorkRes::Ok => Ok(()), + PushWorkRes::FailedDead(me) => Err((BinderError::new_dead(), me)), + } + } else { + process_inner.push_work(self) + }; + drop(process_inner); + + match res { + Ok(()) => Ok(()), + Err((err, work)) => { + // Drop work after releasing process lock. + drop(work); + Err(err) + } + } + } + + /// Check whether one oneway transaction can supersede another. + pub(crate) fn can_replace(&self, old: &Transaction) -> bool { + if self.from.process.task.pid() != old.from.process.task.pid() { + return false; + } + + if self.flags & old.flags & (TF_ONE_WAY | TF_UPDATE_TXN) != (TF_ONE_WAY | TF_UPDATE_TXN) { + return false; + } + + let target_node_match = match (self.target_node.as_ref(), old.target_node.as_ref()) { + (None, None) => true, + (Some(tn1), Some(tn2)) => Arc::ptr_eq(tn1, tn2), + _ => false, + }; + + self.code == old.code && self.flags == old.flags && target_node_match + } + + fn prepare_file_list(&self) -> Result { + let mut alloc = self.allocation.lock().take().ok_or(ESRCH)?; + + match alloc.translate_fds() { + Ok(translated) => { + *self.allocation.lock() = Some(alloc); + Ok(translated) + } + Err(err) => { + // Free the allocation eagerly. + drop(alloc); + Err(err) + } + } + } +} + +impl DeliverToRead for Transaction { + fn do_work( + self: DArc, + thread: &Thread, + writer: &mut BinderReturnWriter<'_>, + ) -> Result { + let send_failed_reply = ScopeGuard::new(|| { + if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 { + let reply = Err(BR_FAILED_REPLY); + self.from.deliver_reply(reply, &self); + } + self.drop_outstanding_txn(); + }); + + let files = if let Ok(list) = self.prepare_file_list() { + list + } else { + // On failure to process the list, we send a reply back to the sender and ignore the + // transaction on the recipient. + return Ok(true); + }; + + let mut tr_sec = BinderTransactionDataSecctx::default(); + let tr = tr_sec.tr_data(); + if let Some(target_node) = &self.target_node { + let (ptr, cookie) = target_node.get_id(); + tr.target.ptr = ptr as _; + tr.cookie = cookie as _; + }; + tr.code = self.code; + tr.flags = self.flags; + tr.data_size = self.data_size as _; + tr.data.ptr.buffer = self.data_address as _; + tr.offsets_size = self.offsets_size as _; + if tr.offsets_size > 0 { + tr.data.ptr.offsets = (self.data_address + ptr_align(self.data_size).unwrap()) as _; + } + tr.sender_euid = self.sender_euid.into_uid_in_current_ns(); + tr.sender_pid = 0; + if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 { + // Not a reply and not one-way. + tr.sender_pid = self.from.process.pid_in_current_ns(); + } + let code = if self.target_node.is_none() { + BR_REPLY + } else if self.txn_security_ctx_off.is_some() { + BR_TRANSACTION_SEC_CTX + } else { + BR_TRANSACTION + }; + + // Write the transaction code and data to the user buffer. + writer.write_code(code)?; + if let Some(off) = self.txn_security_ctx_off { + tr_sec.secctx = (self.data_address + off) as u64; + writer.write_payload(&tr_sec)?; + } else { + writer.write_payload(&*tr)?; + } + + let mut alloc = self.allocation.lock().take().ok_or(ESRCH)?; + + // Dismiss the completion of transaction with a failure. No failure paths are allowed from + // here on out. + send_failed_reply.dismiss(); + + // Commit files, and set FDs in FDA to be closed on buffer free. + let close_on_free = files.commit(); + alloc.set_info_close_on_free(close_on_free); + + // It is now the user's responsibility to clear the allocation. + alloc.keep_alive(); + + self.drop_outstanding_txn(); + + // When this is not a reply and not a oneway transaction, update `current_transaction`. If + // it's a reply, `current_transaction` has already been updated appropriately. + if self.target_node.is_some() && tr_sec.transaction_data.flags & TF_ONE_WAY == 0 { + thread.set_current_transaction(self); + } + + Ok(false) + } + + fn cancel(self: DArc) { + let allocation = self.allocation.lock().take(); + drop(allocation); + + // If this is not a reply or oneway transaction, then send a dead reply. + if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 { + let reply = Err(BR_DEAD_REPLY); + self.from.deliver_reply(reply, &self); + } + + self.drop_outstanding_txn(); + } + + fn should_sync_wakeup(&self) -> bool { + self.flags & TF_ONE_WAY == 0 + } + + fn debug_print(&self, m: &SeqFile, _prefix: &str, tprefix: &str) -> Result<()> { + self.debug_print_inner(m, tprefix); + Ok(()) + } +} + +#[pinned_drop] +impl PinnedDrop for Transaction { + fn drop(self: Pin<&mut Self>) { + self.drop_outstanding_txn(); + } +} diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 1fd92021a573..03ee4c7010d7 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -38,7 +38,7 @@ enum { BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE), }; -enum { +enum flat_binder_object_flags { FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 84d60635e8a9..9b3a4ab95818 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -99,3 +101,9 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT; const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC = XA_FLAGS_ALLOC; const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC1 = XA_FLAGS_ALLOC1; + +#if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST) +#include "../../drivers/android/binder/rust_binder.h" +#include "../../drivers/android/binder/rust_binder_events.h" +#include "../../drivers/android/binder/page_range_helper.h" +#endif diff --git a/rust/helpers/binder.c b/rust/helpers/binder.c new file mode 100644 index 000000000000..224d38a92f1d --- /dev/null +++ b/rust/helpers/binder.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2025 Google LLC. + */ + +#include +#include + +unsigned long rust_helper_list_lru_count(struct list_lru *lru) +{ + return list_lru_count(lru); +} + +unsigned long rust_helper_list_lru_walk(struct list_lru *lru, + list_lru_walk_cb isolate, void *cb_arg, + unsigned long nr_to_walk) +{ + return list_lru_walk(lru, isolate, cb_arg, nr_to_walk); +} + +void rust_helper_init_task_work(struct callback_head *twork, + task_work_func_t func) +{ + init_task_work(twork, func); +} diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 7cf7fe95e41d..8e8277bdddca 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -8,6 +8,7 @@ */ #include "auxiliary.c" +#include "binder.c" #include "blk.c" #include "bug.c" #include "build_assert.c" diff --git a/rust/helpers/page.c b/rust/helpers/page.c index b3f2b8fbf87f..7144de5a61db 100644 --- a/rust/helpers/page.c +++ b/rust/helpers/page.c @@ -2,6 +2,7 @@ #include #include +#include struct page *rust_helper_alloc_pages(gfp_t gfp_mask, unsigned int order) { @@ -17,3 +18,10 @@ void rust_helper_kunmap_local(const void *addr) { kunmap_local(addr); } + +#ifndef NODE_NOT_IN_PAGE_FLAGS +int rust_helper_page_to_nid(const struct page *page) +{ + return page_to_nid(page); +} +#endif diff --git a/rust/helpers/security.c b/rust/helpers/security.c index 0c4c2065df28..ca22da09548d 100644 --- a/rust/helpers/security.c +++ b/rust/helpers/security.c @@ -17,4 +17,28 @@ void rust_helper_security_release_secctx(struct lsm_context *cp) { security_release_secctx(cp); } + +int rust_helper_security_binder_set_context_mgr(const struct cred *mgr) +{ + return security_binder_set_context_mgr(mgr); +} + +int rust_helper_security_binder_transaction(const struct cred *from, + const struct cred *to) +{ + return security_binder_transaction(from, to); +} + +int rust_helper_security_binder_transfer_binder(const struct cred *from, + const struct cred *to) +{ + return security_binder_transfer_binder(from, to); +} + +int rust_helper_security_binder_transfer_file(const struct cred *from, + const struct cred *to, + const struct file *file) +{ + return security_binder_transfer_file(from, to, file); +} #endif diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs index 2599f01e8b28..3aa2e4c4a50c 100644 --- a/rust/kernel/cred.rs +++ b/rust/kernel/cred.rs @@ -54,6 +54,12 @@ impl Credential { unsafe { &*ptr.cast() } } + /// Returns a raw pointer to the inner credential. + #[inline] + pub fn as_ptr(&self) -> *const bindings::cred { + self.0.get() + } + /// Get the id for this security context. #[inline] pub fn get_secid(&self) -> u32 { diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs index 7c1b17246ed5..811fe30e8e6f 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -85,6 +85,12 @@ impl Page { self.page.as_ptr() } + /// Get the node id containing this page. + pub fn nid(&self) -> i32 { + // SAFETY: Always safe to call with a valid page. + unsafe { bindings::page_to_nid(self.as_ptr()) } + } + /// Runs a piece of code with this page mapped to an address. /// /// The page is unmapped when this call returns. diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs index 0c63e9e7e564..9d271695265f 100644 --- a/rust/kernel/security.rs +++ b/rust/kernel/security.rs @@ -8,9 +8,46 @@ use crate::{ bindings, + cred::Credential, error::{to_result, Result}, + fs::File, }; +/// Calls the security modules to determine if the given task can become the manager of a binder +/// context. +#[inline] +pub fn binder_set_context_mgr(mgr: &Credential) -> Result { + // SAFETY: `mrg.0` is valid because the shared reference guarantees a nonzero refcount. + to_result(unsafe { bindings::security_binder_set_context_mgr(mgr.as_ptr()) }) +} + +/// Calls the security modules to determine if binder transactions are allowed from task `from` to +/// task `to`. +#[inline] +pub fn binder_transaction(from: &Credential, to: &Credential) -> Result { + // SAFETY: `from` and `to` are valid because the shared references guarantee nonzero refcounts. + to_result(unsafe { bindings::security_binder_transaction(from.as_ptr(), to.as_ptr()) }) +} + +/// Calls the security modules to determine if task `from` is allowed to send binder objects +/// (owned by itself or other processes) to task `to` through a binder transaction. +#[inline] +pub fn binder_transfer_binder(from: &Credential, to: &Credential) -> Result { + // SAFETY: `from` and `to` are valid because the shared references guarantee nonzero refcounts. + to_result(unsafe { bindings::security_binder_transfer_binder(from.as_ptr(), to.as_ptr()) }) +} + +/// Calls the security modules to determine if task `from` is allowed to send the given file to +/// task `to` (which would get its own file descriptor) through a binder transaction. +#[inline] +pub fn binder_transfer_file(from: &Credential, to: &Credential, file: &File) -> Result { + // SAFETY: `from`, `to` and `file` are valid because the shared references guarantee nonzero + // refcounts. + to_result(unsafe { + bindings::security_binder_transfer_file(from.as_ptr(), to.as_ptr(), file.as_ptr()) + }) +} + /// A security context string. /// /// # Invariants diff --git a/rust/uapi/uapi_helper.h b/rust/uapi/uapi_helper.h index 1409441359f5..de3562b08d0c 100644 --- a/rust/uapi/uapi_helper.h +++ b/rust/uapi/uapi_helper.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include From 54c67740fff7360b6607d02b8499d09b944b3fda Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Fri, 12 Sep 2025 18:18:10 +0530 Subject: [PATCH 1689/2711] bus: mhi: host: pci_generic: Set DMA mask for VFs VFs in devices like QDU100 are capable of accessing host memory up to 40 bits, compared to 32 bits used by PFs and other non-SR-IOV capable MHI devices. To support this, configure `dma_mask` independently for PFs and VFs, by introducing a new 'vf_dma_data_width' member in 'mhi_pci_dev_info' struct and set it to 40 for QDU100. Signed-off-by: Vivek Pernamitta [mani: reworded subject and description] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250912-uevent_vdev_next-20250911-v4-6-fa2f6ccd301b@quicinc.com --- drivers/bus/mhi/host/pci_generic.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 4de7e56d4b88..b188bbf7de04 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -41,6 +41,7 @@ * @edl_trigger: capable of triggering EDL mode in the device (if supported) * @bar_num: PCI base address register to use for MHI MMIO register space * @dma_data_width: DMA transfer word size (32 or 64 bits) + * @vf_dma_data_width: DMA transfer word size for VF's (optional) * @mru_default: default MRU size for MBIM network packets * @sideband_wake: Devices using dedicated sideband GPIO for wakeup instead * of inband wake support (such as sdx24) @@ -56,6 +57,7 @@ struct mhi_pci_dev_info { bool edl_trigger; unsigned int bar_num; unsigned int dma_data_width; + unsigned int vf_dma_data_width; unsigned int mru_default; bool sideband_wake; bool no_m3; @@ -300,6 +302,7 @@ static const struct mhi_pci_dev_info mhi_qcom_qdu100_info = { .config = &mhi_qcom_qdu100_config, .bar_num = MHI_PCI_DEFAULT_BAR_NUM, .dma_data_width = 32, + .vf_dma_data_width = 40, .sideband_wake = false, .no_m3 = true, .reset_on_remove = true, @@ -1300,6 +1303,7 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) const struct mhi_controller_config *mhi_cntrl_config; struct mhi_pci_device *mhi_pdev; struct mhi_controller *mhi_cntrl; + unsigned int dma_data_width; int err; dev_info(&pdev->dev, "MHI PCI device found: %s\n", info->name); @@ -1322,9 +1326,12 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mhi_cntrl = &mhi_pdev->mhi_cntrl; + dma_data_width = (pdev->is_virtfn && info->vf_dma_data_width) ? + info->vf_dma_data_width : info->dma_data_width; + mhi_cntrl->cntrl_dev = &pdev->dev; mhi_cntrl->iova_start = 0; - mhi_cntrl->iova_stop = (dma_addr_t)DMA_BIT_MASK(info->dma_data_width); + mhi_cntrl->iova_stop = (dma_addr_t)DMA_BIT_MASK(dma_data_width); mhi_cntrl->fw_image = info->fw; mhi_cntrl->edl_image = info->edl; @@ -1348,7 +1355,7 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mhi_cntrl->wake_toggle = mhi_pci_wake_toggle_nop; } - err = mhi_pci_claim(mhi_cntrl, info->bar_num, DMA_BIT_MASK(info->dma_data_width)); + err = mhi_pci_claim(mhi_cntrl, info->bar_num, DMA_BIT_MASK(dma_data_width)); if (err) return err; From ff37a41db8b47834b747b3bb427825fc75bc86a7 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Thu, 18 Sep 2025 09:46:31 -0700 Subject: [PATCH 1690/2711] KVM: arm64: nv: Treat AMO as 1 when at EL2 and {E2H,TGE} = {1, 0} SErrors are not deliverable at EL2 when the effective value of HCR_EL2.{TGE,AMO} = {0, 0}. This is bothersome to deal with in nested as we need to use auxiliary pending state to track the pending vSError since HCR_EL2.VSE has no mechanism for honoring the guest HCR. On top of that, we have no way of making that auxiliary pending state visible in ISR_EL1. A defect against the architecture now allows an implementation to treat HCR_EL2.AMO as 1 when HCR_EL2.{E2H,TGE} = {1, 0}. Let's do exactly that, meaning SErrors are always deliverable at EL2 for the typical E2H=RES1 VM. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_emulate.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index fa8a08a1ccd5..64ce3fec73ee 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -220,6 +220,20 @@ static inline bool vcpu_el2_tge_is_set(const struct kvm_vcpu *vcpu) static inline bool vcpu_el2_amo_is_set(const struct kvm_vcpu *vcpu) { + /* + * DDI0487L.b Known Issue D22105 + * + * When executing at EL2 and HCR_EL2.{E2H,TGE} = {1, 0} it is + * IMPLEMENTATION DEFINED whether the effective value of HCR_EL2.AMO + * is the value programmed or 1. + * + * Make the implementation choice of treating the effective value as 1 as + * we cannot subsequently catch changes to TGE or AMO that would + * otherwise lead to the SError becoming deliverable. + */ + if (vcpu_is_el2(vcpu) && vcpu_el2_e2h_is_set(vcpu) && !vcpu_el2_tge_is_set(vcpu)) + return true; + return ctxt_sys_reg(&vcpu->arch.ctxt, HCR_EL2) & HCR_AMO; } From 5aea4096380f5b14e3c0345bdafc291e9ae6d8d1 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Thu, 18 Sep 2025 09:55:05 -0700 Subject: [PATCH 1691/2711] KVM: arm64: nv: Allow userspace to de-feature stage-2 TGRANs KVM advertises the stage-2 TGRAN fields as writable to userspace but prevents any modification for NV-enabled VMs. Update the special-cased sanitization to permit de-featuring a particular TGRAN without allowing the legacy value which refers to the stage-1 field for support. Reported-by: Itaru Kitayama Signed-off-by: Oliver Upton Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index b29f72478a50..83ecfdb46704 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2148,16 +2148,29 @@ static int set_id_aa64pfr1_el1(struct kvm_vcpu *vcpu, return set_id_reg(vcpu, rd, user_val); } +/* + * Allow userspace to de-feature a stage-2 translation granule but prevent it + * from claiming the impossible. + */ +#define tgran2_val_allowed(tg, safe, user) \ +({ \ + u8 __s = SYS_FIELD_GET(ID_AA64MMFR0_EL1, tg, safe); \ + u8 __u = SYS_FIELD_GET(ID_AA64MMFR0_EL1, tg, user); \ + \ + __s == __u || __u == ID_AA64MMFR0_EL1_##tg##_NI; \ +}) + static int set_id_aa64mmfr0_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, u64 user_val) { u64 sanitized_val = kvm_read_sanitised_id_reg(vcpu, rd); - u64 tgran2_mask = ID_AA64MMFR0_EL1_TGRAN4_2_MASK | - ID_AA64MMFR0_EL1_TGRAN16_2_MASK | - ID_AA64MMFR0_EL1_TGRAN64_2_MASK; - if (vcpu_has_nv(vcpu) && - ((sanitized_val & tgran2_mask) != (user_val & tgran2_mask))) + if (!vcpu_has_nv(vcpu)) + return set_id_reg(vcpu, rd, user_val); + + if (!tgran2_val_allowed(TGRAN4_2, sanitized_val, user_val) || + !tgran2_val_allowed(TGRAN16_2, sanitized_val, user_val) || + !tgran2_val_allowed(TGRAN64_2, sanitized_val, user_val)) return -EINVAL; return set_id_reg(vcpu, rd, user_val); From c3b3bbd160d2014a638d40bda17909a0afd85d09 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 18 Sep 2025 16:13:53 +0100 Subject: [PATCH 1692/2711] KVM: arm64: Remove duplicate FEAT_{SYSREG128,MTE2} descriptions Turns out I'm rather bad at noticing that the description of features has already been added. Remove superflusous definitions for SYSREG128 and MTE2. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/config.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index da66c4a14775..d85dd05c00b0 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -131,7 +131,6 @@ struct reg_bits_to_feat_map { #define FEAT_SPMU ID_AA64DFR1_EL1, SPMU, IMP #define FEAT_SPE_nVM ID_AA64DFR2_EL1, SPE_nVM, IMP #define FEAT_STEP2 ID_AA64DFR2_EL1, STEP, IMP -#define FEAT_SYSREG128 ID_AA64ISAR2_EL1, SYSREG_128, IMP #define FEAT_CPA2 ID_AA64ISAR3_EL1, CPA, CPA2 #define FEAT_ASID2 ID_AA64MMFR4_EL1, ASID2, IMP #define FEAT_MEC ID_AA64MMFR3_EL1, MEC, IMP @@ -143,7 +142,6 @@ struct reg_bits_to_feat_map { #define FEAT_LSMAOC ID_AA64MMFR2_EL1, LSM, IMP #define FEAT_MixedEnd ID_AA64MMFR0_EL1, BIGEND, IMP #define FEAT_MixedEndEL0 ID_AA64MMFR0_EL1, BIGENDEL0, IMP -#define FEAT_MTE2 ID_AA64PFR1_EL1, MTE, MTE2 #define FEAT_MTE_ASYNC ID_AA64PFR1_EL1, MTE_frac, ASYNC #define FEAT_MTE_STORE_ONLY ID_AA64PFR2_EL1, MTESTOREONLY, IMP #define FEAT_PAN ID_AA64MMFR1_EL1, PAN, IMP From 559442afea8812814135ec6fa33bc62c9d09f5c4 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 18 Sep 2025 16:13:54 +0100 Subject: [PATCH 1693/2711] KVM: arm64: Add reg_feat_map_desc to describe full register dependency struct reg_bits_to_feat_map is great to describe bit-to-feature dependency, but not so much to describe register-to-feature dependency. Yet both need to exist. Add a new reg_feat_map_desc structure to describe this. Extra complexity is added by the need to source the RES0 bits from the runtime-computed FGT masks, for which we need an extra flag and extra complexity. Oh well. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/config.c | 81 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index d85dd05c00b0..c2bfffe660bc 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -7,12 +7,22 @@ #include #include +/* + * Describes the dependencies between a set of bits (or the negation + * of a set of RES0 bits) and a feature. The flags indicate how the + * data is interpreted. + */ struct reg_bits_to_feat_map { - u64 bits; + union { + u64 bits; + u64 *res0p; + }; #define NEVER_FGU BIT(0) /* Can trap, but never UNDEF */ #define CALL_FUNC BIT(1) /* Needs to evaluate tons of crap */ #define FIXED_VALUE BIT(2) /* RAZ/WI or RAO/WI in KVM */ +#define RES0_POINTER BIT(3) /* Pointer to RES0 value instead of bits */ + unsigned long flags; union { @@ -28,9 +38,27 @@ struct reg_bits_to_feat_map { }; }; -#define __NEEDS_FEAT_3(m, f, id, fld, lim) \ +/* + * Describes the dependencies for a given register: + * + * @feat_map describes the dependency for the whole register. If the + * features the register depends on are not present, the whole + * register is effectively RES0. + * + * @bit_feat_map describes the dependencies for a set of bits in that + * register. If the features these bits depend on are not present, the + * bits are effectively RES0. + */ +struct reg_feat_map_desc { + const char *name; + const struct reg_bits_to_feat_map feat_map; + const struct reg_bits_to_feat_map *bit_feat_map; + const unsigned int bit_feat_map_sz; +}; + +#define __NEEDS_FEAT_3(m, f, w, id, fld, lim) \ { \ - .bits = (m), \ + .w = (m), \ .flags = (f), \ .regidx = IDREG_IDX(SYS_ ## id), \ .shift = id ##_## fld ## _SHIFT, \ @@ -39,28 +67,63 @@ struct reg_bits_to_feat_map { .lo_lim = id ##_## fld ##_## lim \ } -#define __NEEDS_FEAT_2(m, f, fun, dummy) \ +#define __NEEDS_FEAT_2(m, f, w, fun, dummy) \ { \ - .bits = (m), \ + .w = (m), \ .flags = (f) | CALL_FUNC, \ .fval = (fun), \ } -#define __NEEDS_FEAT_1(m, f, fun) \ +#define __NEEDS_FEAT_1(m, f, w, fun) \ { \ - .bits = (m), \ + .w = (m), \ .flags = (f) | CALL_FUNC, \ .match = (fun), \ } +#define __NEEDS_FEAT_FLAG(m, f, w, ...) \ + CONCATENATE(__NEEDS_FEAT_, COUNT_ARGS(__VA_ARGS__))(m, f, w, __VA_ARGS__) + #define NEEDS_FEAT_FLAG(m, f, ...) \ - CONCATENATE(__NEEDS_FEAT_, COUNT_ARGS(__VA_ARGS__))(m, f, __VA_ARGS__) + __NEEDS_FEAT_FLAG(m, f, bits, __VA_ARGS__) #define NEEDS_FEAT_FIXED(m, ...) \ - NEEDS_FEAT_FLAG(m, FIXED_VALUE, __VA_ARGS__, 0) + __NEEDS_FEAT_FLAG(m, FIXED_VALUE, bits, __VA_ARGS__, 0) +#define NEEDS_FEAT_RES0(p, ...) \ + __NEEDS_FEAT_FLAG(p, RES0_POINTER, res0p, __VA_ARGS__) + +/* + * Declare the dependency between a set of bits and a set of features, + * generating a struct reg_bit_to_feat_map. + */ #define NEEDS_FEAT(m, ...) NEEDS_FEAT_FLAG(m, 0, __VA_ARGS__) +/* + * Declare the dependency between a non-FGT register, a set of + * feature, and the set of individual bits it contains. This generates + * a struct reg_feat_map_desc. + */ +#define DECLARE_FEAT_MAP(n, r, m, f) \ + struct reg_feat_map_desc n = { \ + .name = #r, \ + .feat_map = NEEDS_FEAT(~r##_RES0, f), \ + .bit_feat_map = m, \ + .bit_feat_map_sz = ARRAY_SIZE(m), \ + } + +/* + * Specialised version of the above for FGT registers that have their + * RES0 masks described as struct fgt_masks. + */ +#define DECLARE_FEAT_MAP_FGT(n, msk, m, f) \ + struct reg_feat_map_desc n = { \ + .name = #msk, \ + .feat_map = NEEDS_FEAT_RES0(&msk.res0, f),\ + .bit_feat_map = m, \ + .bit_feat_map_sz = ARRAY_SIZE(m), \ + } + #define FEAT_SPE ID_AA64DFR0_EL1, PMSVer, IMP #define FEAT_SPE_FnE ID_AA64DFR0_EL1, PMSVer, V1P2 #define FEAT_BRBE ID_AA64DFR0_EL1, BRBE, IMP From 7d3a4d048925d52e5511d82e479cbdcf7354aa7c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 18 Sep 2025 16:13:55 +0100 Subject: [PATCH 1694/2711] KVM: arm64: Enforce absence of FEAT_FGT on FGT registers As we want to enforce FGT registers behaving as RES0 when FEAT_FGT is not exposed to the guest, We move a bumch of things that are so far passed as parameter into a structure that points to the bit description. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/config.c | 126 ++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 49 deletions(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index c2bfffe660bc..887e7338fffe 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -458,6 +458,10 @@ static const struct reg_bits_to_feat_map hfgrtr_feat_map[] = { NEVER_FGU, FEAT_AA64EL1), }; + +static const DECLARE_FEAT_MAP_FGT(hfgrtr_desc, hfgrtr_masks, + hfgrtr_feat_map, FEAT_FGT); + static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = { NEEDS_FEAT(HFGWTR_EL2_nAMAIR2_EL1 | HFGWTR_EL2_nMAIR2_EL1, @@ -522,6 +526,9 @@ static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = { NEVER_FGU, FEAT_AA64EL1), }; +static const DECLARE_FEAT_MAP_FGT(hfgwtr_desc, hfgwtr_masks, + hfgwtr_feat_map, FEAT_FGT); + static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = { NEEDS_FEAT(HDFGRTR_EL2_PMBIDR_EL1 | HDFGRTR_EL2_PMSLATFR_EL1 | @@ -589,6 +596,9 @@ static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = { NEVER_FGU, FEAT_AA64EL1) }; +static const DECLARE_FEAT_MAP_FGT(hdfgrtr_desc, hdfgrtr_masks, + hdfgrtr_feat_map, FEAT_FGT); + static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = { NEEDS_FEAT(HDFGWTR_EL2_PMSLATFR_EL1 | HDFGWTR_EL2_PMSIRR_EL1 | @@ -649,6 +659,8 @@ static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = { NEEDS_FEAT(HDFGWTR_EL2_TRFCR_EL1, FEAT_TRF), }; +static const DECLARE_FEAT_MAP_FGT(hdfgwtr_desc, hdfgwtr_masks, + hdfgwtr_feat_map, FEAT_FGT); static const struct reg_bits_to_feat_map hfgitr_feat_map[] = { NEEDS_FEAT(HFGITR_EL2_PSBCSYNC, FEAT_SPEv1p5), @@ -723,6 +735,9 @@ static const struct reg_bits_to_feat_map hfgitr_feat_map[] = { NEVER_FGU, FEAT_AA64EL1), }; +static const DECLARE_FEAT_MAP_FGT(hfgitr_desc, hfgitr_masks, + hfgitr_feat_map, FEAT_FGT); + static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = { NEEDS_FEAT(HAFGRTR_EL2_AMEVTYPER115_EL0 | HAFGRTR_EL2_AMEVTYPER114_EL0 | @@ -765,6 +780,9 @@ static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = { FEAT_AMUv1), }; +static const DECLARE_FEAT_MAP_FGT(hafgrtr_desc, hafgrtr_masks, + hafgrtr_feat_map, FEAT_FGT); + static const struct reg_bits_to_feat_map hfgitr2_feat_map[] = { NEEDS_FEAT(HFGITR2_EL2_nDCCIVAPS, FEAT_PoPS), NEEDS_FEAT(HFGITR2_EL2_TSBCSYNC, FEAT_TRBEv1p1) @@ -1122,20 +1140,25 @@ static void __init check_feat_map(const struct reg_bits_to_feat_map *map, str, mask ^ ~res0); } +static u64 reg_feat_map_bits(const struct reg_bits_to_feat_map *map) +{ + return map->flags & RES0_POINTER ? ~(*map->res0p) : map->bits; +} + +static void __init check_reg_desc(const struct reg_feat_map_desc *r) +{ + check_feat_map(r->bit_feat_map, r->bit_feat_map_sz, + ~reg_feat_map_bits(&r->feat_map), r->name); +} + void __init check_feature_map(void) { - check_feat_map(hfgrtr_feat_map, ARRAY_SIZE(hfgrtr_feat_map), - hfgrtr_masks.res0, hfgrtr_masks.str); - check_feat_map(hfgwtr_feat_map, ARRAY_SIZE(hfgwtr_feat_map), - hfgwtr_masks.res0, hfgwtr_masks.str); - check_feat_map(hfgitr_feat_map, ARRAY_SIZE(hfgitr_feat_map), - hfgitr_masks.res0, hfgitr_masks.str); - check_feat_map(hdfgrtr_feat_map, ARRAY_SIZE(hdfgrtr_feat_map), - hdfgrtr_masks.res0, hdfgrtr_masks.str); - check_feat_map(hdfgwtr_feat_map, ARRAY_SIZE(hdfgwtr_feat_map), - hdfgwtr_masks.res0, hdfgwtr_masks.str); - check_feat_map(hafgrtr_feat_map, ARRAY_SIZE(hafgrtr_feat_map), - hafgrtr_masks.res0, hafgrtr_masks.str); + check_reg_desc(&hfgrtr_desc); + check_reg_desc(&hfgwtr_desc); + check_reg_desc(&hfgitr_desc); + check_reg_desc(&hdfgrtr_desc); + check_reg_desc(&hdfgwtr_desc); + check_reg_desc(&hafgrtr_desc); check_feat_map(hcrx_feat_map, ARRAY_SIZE(hcrx_feat_map), __HCRX_EL2_RES0, "HCRX_EL2"); check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map), @@ -1190,7 +1213,7 @@ static u64 __compute_fixed_bits(struct kvm *kvm, match = idreg_feat_match(kvm, &map[i]); if (!match || (map[i].flags & FIXED_VALUE)) - val |= map[i].bits; + val |= reg_feat_map_bits(&map[i]); } return val; @@ -1206,6 +1229,29 @@ static u64 compute_res0_bits(struct kvm *kvm, require, exclude | FIXED_VALUE); } +static u64 compute_reg_res0_bits(struct kvm *kvm, + const struct reg_feat_map_desc *r, + unsigned long require, unsigned long exclude) + +{ + u64 res0; + + res0 = compute_res0_bits(kvm, r->bit_feat_map, r->bit_feat_map_sz, + require, exclude); + + /* + * If computing FGUs, don't take RES0 or register existence + * into account -- we're not computing bits for the register + * itself. + */ + if (!(exclude & NEVER_FGU)) { + res0 |= compute_res0_bits(kvm, &r->feat_map, 1, require, exclude); + res0 |= ~reg_feat_map_bits(&r->feat_map); + } + + return res0; +} + static u64 compute_fixed_bits(struct kvm *kvm, const struct reg_bits_to_feat_map *map, int map_size, @@ -1223,30 +1269,24 @@ void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt) switch (fgt) { case HFGRTR_GROUP: - val |= compute_res0_bits(kvm, hfgrtr_feat_map, - ARRAY_SIZE(hfgrtr_feat_map), - 0, NEVER_FGU); - val |= compute_res0_bits(kvm, hfgwtr_feat_map, - ARRAY_SIZE(hfgwtr_feat_map), - 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hfgrtr_desc, + 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hfgwtr_desc, + 0, NEVER_FGU); break; case HFGITR_GROUP: - val |= compute_res0_bits(kvm, hfgitr_feat_map, - ARRAY_SIZE(hfgitr_feat_map), - 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hfgitr_desc, + 0, NEVER_FGU); break; case HDFGRTR_GROUP: - val |= compute_res0_bits(kvm, hdfgrtr_feat_map, - ARRAY_SIZE(hdfgrtr_feat_map), - 0, NEVER_FGU); - val |= compute_res0_bits(kvm, hdfgwtr_feat_map, - ARRAY_SIZE(hdfgwtr_feat_map), - 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hdfgrtr_desc, + 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hdfgwtr_desc, + 0, NEVER_FGU); break; case HAFGRTR_GROUP: - val |= compute_res0_bits(kvm, hafgrtr_feat_map, - ARRAY_SIZE(hafgrtr_feat_map), - 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hafgrtr_desc, + 0, NEVER_FGU); break; case HFGRTR2_GROUP: val |= compute_res0_bits(kvm, hfgrtr2_feat_map, @@ -1282,39 +1322,27 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r switch (reg) { case HFGRTR_EL2: - *res0 = compute_res0_bits(kvm, hfgrtr_feat_map, - ARRAY_SIZE(hfgrtr_feat_map), 0, 0); - *res0 |= hfgrtr_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hfgrtr_desc, 0, 0); *res1 = HFGRTR_EL2_RES1; break; case HFGWTR_EL2: - *res0 = compute_res0_bits(kvm, hfgwtr_feat_map, - ARRAY_SIZE(hfgwtr_feat_map), 0, 0); - *res0 |= hfgwtr_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hfgwtr_desc, 0, 0); *res1 = HFGWTR_EL2_RES1; break; case HFGITR_EL2: - *res0 = compute_res0_bits(kvm, hfgitr_feat_map, - ARRAY_SIZE(hfgitr_feat_map), 0, 0); - *res0 |= hfgitr_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hfgitr_desc, 0, 0); *res1 = HFGITR_EL2_RES1; break; case HDFGRTR_EL2: - *res0 = compute_res0_bits(kvm, hdfgrtr_feat_map, - ARRAY_SIZE(hdfgrtr_feat_map), 0, 0); - *res0 |= hdfgrtr_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hdfgrtr_desc, 0, 0); *res1 = HDFGRTR_EL2_RES1; break; case HDFGWTR_EL2: - *res0 = compute_res0_bits(kvm, hdfgwtr_feat_map, - ARRAY_SIZE(hdfgwtr_feat_map), 0, 0); - *res0 |= hdfgwtr_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hdfgwtr_desc, 0, 0); *res1 = HDFGWTR_EL2_RES1; break; case HAFGRTR_EL2: - *res0 = compute_res0_bits(kvm, hafgrtr_feat_map, - ARRAY_SIZE(hafgrtr_feat_map), 0, 0); - *res0 |= hafgrtr_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hafgrtr_desc, 0, 0); *res1 = HAFGRTR_EL2_RES1; break; case HFGRTR2_EL2: From 338a41e83c3dab81573ac33bc30f0f36bd29cd78 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 18 Sep 2025 16:13:56 +0100 Subject: [PATCH 1695/2711] KVM: arm64: Enforce absence of FEAT_FGT2 on FGT2 registers Similarly to the FEAT_FGT registers, add the dependency between the registers and the controlling feature. WHile we're at it, add the missing checks for the RES0 vs valid bit overlap. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/config.c | 67 +++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index 887e7338fffe..824ad91b4616 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -212,6 +212,7 @@ struct reg_feat_map_desc { #define FEAT_SSBS ID_AA64PFR1_EL1, SSBS, IMP #define FEAT_TIDCP1 ID_AA64MMFR1_EL1, TIDCP1, IMP #define FEAT_FGT ID_AA64MMFR0_EL1, FGT, IMP +#define FEAT_FGT2 ID_AA64MMFR0_EL1, FGT, FGT2 #define FEAT_MTPMU ID_AA64DFR0_EL1, MTPMU, IMP static bool not_feat_aa64el3(struct kvm *kvm) @@ -788,6 +789,9 @@ static const struct reg_bits_to_feat_map hfgitr2_feat_map[] = { NEEDS_FEAT(HFGITR2_EL2_TSBCSYNC, FEAT_TRBEv1p1) }; +static const DECLARE_FEAT_MAP_FGT(hfgitr2_desc, hfgitr2_masks, + hfgitr2_feat_map, FEAT_FGT2); + static const struct reg_bits_to_feat_map hfgrtr2_feat_map[] = { NEEDS_FEAT(HFGRTR2_EL2_nPFAR_EL1, FEAT_PFAR), NEEDS_FEAT(HFGRTR2_EL2_nERXGSR_EL1, FEAT_RASv2), @@ -807,6 +811,9 @@ static const struct reg_bits_to_feat_map hfgrtr2_feat_map[] = { NEEDS_FEAT(HFGRTR2_EL2_nRCWSMASK_EL1, FEAT_THE), }; +static const DECLARE_FEAT_MAP_FGT(hfgrtr2_desc, hfgrtr2_masks, + hfgrtr2_feat_map, FEAT_FGT2); + static const struct reg_bits_to_feat_map hfgwtr2_feat_map[] = { NEEDS_FEAT(HFGWTR2_EL2_nPFAR_EL1, FEAT_PFAR), NEEDS_FEAT(HFGWTR2_EL2_nACTLRALIAS_EL1 | @@ -825,6 +832,9 @@ static const struct reg_bits_to_feat_map hfgwtr2_feat_map[] = { NEEDS_FEAT(HFGWTR2_EL2_nRCWSMASK_EL1, FEAT_THE), }; +static const DECLARE_FEAT_MAP_FGT(hfgwtr2_desc, hfgwtr2_masks, + hfgwtr2_feat_map, FEAT_FGT2); + static const struct reg_bits_to_feat_map hdfgrtr2_feat_map[] = { NEEDS_FEAT(HDFGRTR2_EL2_nMDSELR_EL1, FEAT_Debugv8p9), NEEDS_FEAT(HDFGRTR2_EL2_nPMECR_EL1, feat_ebep_pmuv3_ss), @@ -855,6 +865,9 @@ static const struct reg_bits_to_feat_map hdfgrtr2_feat_map[] = { NEEDS_FEAT(HDFGRTR2_EL2_nTRBMPAM_EL1, feat_trbe_mpam), }; +static const DECLARE_FEAT_MAP_FGT(hdfgrtr2_desc, hdfgrtr2_masks, + hdfgrtr2_feat_map, FEAT_FGT2); + static const struct reg_bits_to_feat_map hdfgwtr2_feat_map[] = { NEEDS_FEAT(HDFGWTR2_EL2_nMDSELR_EL1, FEAT_Debugv8p9), NEEDS_FEAT(HDFGWTR2_EL2_nPMECR_EL1, feat_ebep_pmuv3_ss), @@ -883,6 +896,10 @@ static const struct reg_bits_to_feat_map hdfgwtr2_feat_map[] = { NEEDS_FEAT(HDFGWTR2_EL2_nTRBMPAM_EL1, feat_trbe_mpam), }; +static const DECLARE_FEAT_MAP_FGT(hdfgwtr2_desc, hdfgwtr2_masks, + hdfgwtr2_feat_map, FEAT_FGT2); + + static const struct reg_bits_to_feat_map hcrx_feat_map[] = { NEEDS_FEAT(HCRX_EL2_PACMEn, feat_pauth_lr), NEEDS_FEAT(HCRX_EL2_EnFPM, FEAT_FPMR), @@ -1159,6 +1176,11 @@ void __init check_feature_map(void) check_reg_desc(&hdfgrtr_desc); check_reg_desc(&hdfgwtr_desc); check_reg_desc(&hafgrtr_desc); + check_reg_desc(&hfgrtr2_desc); + check_reg_desc(&hfgwtr2_desc); + check_reg_desc(&hfgitr2_desc); + check_reg_desc(&hdfgrtr2_desc); + check_reg_desc(&hdfgwtr2_desc); check_feat_map(hcrx_feat_map, ARRAY_SIZE(hcrx_feat_map), __HCRX_EL2_RES0, "HCRX_EL2"); check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map), @@ -1289,25 +1311,20 @@ void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt) 0, NEVER_FGU); break; case HFGRTR2_GROUP: - val |= compute_res0_bits(kvm, hfgrtr2_feat_map, - ARRAY_SIZE(hfgrtr2_feat_map), - 0, NEVER_FGU); - val |= compute_res0_bits(kvm, hfgwtr2_feat_map, - ARRAY_SIZE(hfgwtr2_feat_map), - 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hfgrtr2_desc, + 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hfgwtr2_desc, + 0, NEVER_FGU); break; case HFGITR2_GROUP: - val |= compute_res0_bits(kvm, hfgitr2_feat_map, - ARRAY_SIZE(hfgitr2_feat_map), - 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hfgitr2_desc, + 0, NEVER_FGU); break; case HDFGRTR2_GROUP: - val |= compute_res0_bits(kvm, hdfgrtr2_feat_map, - ARRAY_SIZE(hdfgrtr2_feat_map), - 0, NEVER_FGU); - val |= compute_res0_bits(kvm, hdfgwtr2_feat_map, - ARRAY_SIZE(hdfgwtr2_feat_map), - 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hdfgrtr2_desc, + 0, NEVER_FGU); + val |= compute_reg_res0_bits(kvm, &hdfgwtr2_desc, + 0, NEVER_FGU); break; default: BUG(); @@ -1346,33 +1363,23 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r *res1 = HAFGRTR_EL2_RES1; break; case HFGRTR2_EL2: - *res0 = compute_res0_bits(kvm, hfgrtr2_feat_map, - ARRAY_SIZE(hfgrtr2_feat_map), 0, 0); - *res0 |= hfgrtr2_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hfgrtr2_desc, 0, 0); *res1 = HFGRTR2_EL2_RES1; break; case HFGWTR2_EL2: - *res0 = compute_res0_bits(kvm, hfgwtr2_feat_map, - ARRAY_SIZE(hfgwtr2_feat_map), 0, 0); - *res0 |= hfgwtr2_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hfgwtr2_desc, 0, 0); *res1 = HFGWTR2_EL2_RES1; break; case HFGITR2_EL2: - *res0 = compute_res0_bits(kvm, hfgitr2_feat_map, - ARRAY_SIZE(hfgitr2_feat_map), 0, 0); - *res0 |= hfgitr2_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hfgitr2_desc, 0, 0); *res1 = HFGITR2_EL2_RES1; break; case HDFGRTR2_EL2: - *res0 = compute_res0_bits(kvm, hdfgrtr2_feat_map, - ARRAY_SIZE(hdfgrtr2_feat_map), 0, 0); - *res0 |= hdfgrtr2_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hdfgrtr2_desc, 0, 0); *res1 = HDFGRTR2_EL2_RES1; break; case HDFGWTR2_EL2: - *res0 = compute_res0_bits(kvm, hdfgwtr2_feat_map, - ARRAY_SIZE(hdfgwtr2_feat_map), 0, 0); - *res0 |= hdfgwtr2_masks.res0; + *res0 = compute_reg_res0_bits(kvm, &hdfgwtr2_desc, 0, 0); *res1 = HDFGWTR2_EL2_RES1; break; case HCRX_EL2: From c99d62771f63116ffe54636980414fc74ab3471c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 18 Sep 2025 16:13:57 +0100 Subject: [PATCH 1696/2711] KVM: arm64: Enforce absence of FEAT_HCX on HCRX_EL2 Add the dependency between the HCRX_EL2 register and FEAT_HCX. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/config.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index 824ad91b4616..31e6947a4805 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -214,6 +214,7 @@ struct reg_feat_map_desc { #define FEAT_FGT ID_AA64MMFR0_EL1, FGT, IMP #define FEAT_FGT2 ID_AA64MMFR0_EL1, FGT, FGT2 #define FEAT_MTPMU ID_AA64DFR0_EL1, MTPMU, IMP +#define FEAT_HCX ID_AA64MMFR1_EL1, HCX, IMP static bool not_feat_aa64el3(struct kvm *kvm) { @@ -929,6 +930,10 @@ static const struct reg_bits_to_feat_map hcrx_feat_map[] = { NEEDS_FEAT(HCRX_EL2_EnAS0, FEAT_LS64_ACCDATA), }; + +static const DECLARE_FEAT_MAP(hcrx_desc, __HCRX_EL2, + hcrx_feat_map, FEAT_HCX); + static const struct reg_bits_to_feat_map hcr_feat_map[] = { NEEDS_FEAT(HCR_EL2_TID0, FEAT_AA32EL0), NEEDS_FEAT_FIXED(HCR_EL2_RW, compute_hcr_rw), @@ -1181,8 +1186,7 @@ void __init check_feature_map(void) check_reg_desc(&hfgitr2_desc); check_reg_desc(&hdfgrtr2_desc); check_reg_desc(&hdfgwtr2_desc); - check_feat_map(hcrx_feat_map, ARRAY_SIZE(hcrx_feat_map), - __HCRX_EL2_RES0, "HCRX_EL2"); + check_reg_desc(&hcrx_desc); check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map), HCR_EL2_RES0, "HCR_EL2"); check_feat_map(sctlr2_feat_map, ARRAY_SIZE(sctlr2_feat_map), @@ -1383,9 +1387,7 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r *res1 = HDFGWTR2_EL2_RES1; break; case HCRX_EL2: - *res0 = compute_res0_bits(kvm, hcrx_feat_map, - ARRAY_SIZE(hcrx_feat_map), 0, 0); - *res0 |= __HCRX_EL2_RES0; + *res0 = compute_reg_res0_bits(kvm, &hcrx_desc, 0, 0); *res1 = __HCRX_EL2_RES1; break; case HCR_EL2: From efe5406c55fb3203028507555c7da2bb417a397c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 18 Sep 2025 16:13:58 +0100 Subject: [PATCH 1697/2711] KVM: arm64: Convert HCR_EL2 RES0 handling to compute_reg_res0_bits() While HCR_EL2 is unlikely to ever be RES0 (at least when NV is on), but consistency doesn't hurt, and it can be described in the same way as the other registers. Convert it over to the new RES0-computing infrastructure. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/config.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index 31e6947a4805..a6d3701e2870 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -136,6 +136,7 @@ struct reg_feat_map_desc { #define FEAT_AA32EL0 ID_AA64PFR0_EL1, EL0, AARCH32 #define FEAT_AA32EL1 ID_AA64PFR0_EL1, EL1, AARCH32 #define FEAT_AA64EL1 ID_AA64PFR0_EL1, EL1, IMP +#define FEAT_AA64EL2 ID_AA64PFR0_EL1, EL2, IMP #define FEAT_AA64EL3 ID_AA64PFR0_EL1, EL3, IMP #define FEAT_AIE ID_AA64MMFR3_EL1, AIE, IMP #define FEAT_S2POE ID_AA64MMFR3_EL1, S2POE, IMP @@ -1005,6 +1006,9 @@ static const struct reg_bits_to_feat_map hcr_feat_map[] = { NEEDS_FEAT_FIXED(HCR_EL2_E2H, compute_hcr_e2h), }; +static const DECLARE_FEAT_MAP(hcr_desc, HCR_EL2, + hcr_feat_map, FEAT_AA64EL2); + static const struct reg_bits_to_feat_map sctlr2_feat_map[] = { NEEDS_FEAT(SCTLR2_EL1_NMEA | SCTLR2_EL1_EASE, @@ -1187,8 +1191,7 @@ void __init check_feature_map(void) check_reg_desc(&hdfgrtr2_desc); check_reg_desc(&hdfgwtr2_desc); check_reg_desc(&hcrx_desc); - check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map), - HCR_EL2_RES0, "HCR_EL2"); + check_reg_desc(&hcr_desc); check_feat_map(sctlr2_feat_map, ARRAY_SIZE(sctlr2_feat_map), SCTLR2_EL1_RES0, "SCTLR2_EL1"); check_feat_map(tcr2_el2_feat_map, ARRAY_SIZE(tcr2_el2_feat_map), @@ -1278,15 +1281,13 @@ static u64 compute_reg_res0_bits(struct kvm *kvm, return res0; } -static u64 compute_fixed_bits(struct kvm *kvm, - const struct reg_bits_to_feat_map *map, - int map_size, - u64 *fixed_bits, - unsigned long require, - unsigned long exclude) +static u64 compute_reg_fixed_bits(struct kvm *kvm, + const struct reg_feat_map_desc *r, + u64 *fixed_bits, unsigned long require, + unsigned long exclude) { - return __compute_fixed_bits(kvm, map, map_size, fixed_bits, - require | FIXED_VALUE, exclude); + return __compute_fixed_bits(kvm, r->bit_feat_map, r->bit_feat_map_sz, + fixed_bits, require | FIXED_VALUE, exclude); } void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt) @@ -1391,12 +1392,9 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r *res1 = __HCRX_EL2_RES1; break; case HCR_EL2: - mask = compute_fixed_bits(kvm, hcr_feat_map, - ARRAY_SIZE(hcr_feat_map), &fixed, - 0, 0); - *res0 = compute_res0_bits(kvm, hcr_feat_map, - ARRAY_SIZE(hcr_feat_map), 0, 0); - *res0 |= HCR_EL2_RES0 | (mask & ~fixed); + mask = compute_reg_fixed_bits(kvm, &hcr_desc, &fixed, 0, 0); + *res0 = compute_reg_res0_bits(kvm, &hcr_desc, 0, 0); + *res0 |= (mask & ~fixed); *res1 = HCR_EL2_RES1 | (mask & fixed); break; case SCTLR2_EL1: From f89763efe86cc05f8465c7eea85a76183f218c56 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 18 Sep 2025 16:13:59 +0100 Subject: [PATCH 1698/2711] KVM: arm64: Enforce absence of FEAT_SCTLR2 on SCTLR2_EL{1,2} Enforce that SCTLR2_EL{1,2} are RES0 when FEAT_SCTLR2 isn't present. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/config.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index a6d3701e2870..5927ef89778f 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -1026,6 +1026,9 @@ static const struct reg_bits_to_feat_map sctlr2_feat_map[] = { FEAT_CPA2), }; +static const DECLARE_FEAT_MAP(sctlr2_desc, SCTLR2_EL1, + sctlr2_feat_map, FEAT_SCTLR2); + static const struct reg_bits_to_feat_map tcr2_el2_feat_map[] = { NEEDS_FEAT(TCR2_EL2_FNG1 | TCR2_EL2_FNG0 | @@ -1192,8 +1195,7 @@ void __init check_feature_map(void) check_reg_desc(&hdfgwtr2_desc); check_reg_desc(&hcrx_desc); check_reg_desc(&hcr_desc); - check_feat_map(sctlr2_feat_map, ARRAY_SIZE(sctlr2_feat_map), - SCTLR2_EL1_RES0, "SCTLR2_EL1"); + check_reg_desc(&sctlr2_desc); check_feat_map(tcr2_el2_feat_map, ARRAY_SIZE(tcr2_el2_feat_map), TCR2_EL2_RES0, "TCR2_EL2"); check_feat_map(sctlr_el1_feat_map, ARRAY_SIZE(sctlr_el1_feat_map), @@ -1399,9 +1401,7 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r break; case SCTLR2_EL1: case SCTLR2_EL2: - *res0 = compute_res0_bits(kvm, sctlr2_feat_map, - ARRAY_SIZE(sctlr2_feat_map), 0, 0); - *res0 |= SCTLR2_EL1_RES0; + *res0 = compute_reg_res0_bits(kvm, &sctlr2_desc, 0, 0); *res1 = SCTLR2_EL1_RES1; break; case TCR2_EL2: From 4870a8c1d18897681b6f6a50288d0b6dd5e21e24 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 18 Sep 2025 16:14:00 +0100 Subject: [PATCH 1699/2711] KVM: arm64: Enforce absence of FEAT_TCR2 on TCR2_EL2 Enforce that TCR2_EL2 are RES0 when FEAT_TCR2 isn't present. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/config.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index 5927ef89778f..8c6c89d311ac 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -1051,6 +1051,9 @@ static const struct reg_bits_to_feat_map tcr2_el2_feat_map[] = { NEEDS_FEAT(TCR2_EL2_PIE, FEAT_S1PIE), }; +static const DECLARE_FEAT_MAP(tcr2_el2_desc, TCR2_EL2, + tcr2_el2_feat_map, FEAT_TCR2); + static const struct reg_bits_to_feat_map sctlr_el1_feat_map[] = { NEEDS_FEAT(SCTLR_EL1_CP15BEN | SCTLR_EL1_ITD | @@ -1196,8 +1199,7 @@ void __init check_feature_map(void) check_reg_desc(&hcrx_desc); check_reg_desc(&hcr_desc); check_reg_desc(&sctlr2_desc); - check_feat_map(tcr2_el2_feat_map, ARRAY_SIZE(tcr2_el2_feat_map), - TCR2_EL2_RES0, "TCR2_EL2"); + check_reg_desc(&tcr2_el2_desc); check_feat_map(sctlr_el1_feat_map, ARRAY_SIZE(sctlr_el1_feat_map), SCTLR_EL1_RES0, "SCTLR_EL1"); check_feat_map(mdcr_el2_feat_map, ARRAY_SIZE(mdcr_el2_feat_map), @@ -1405,9 +1407,7 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r *res1 = SCTLR2_EL1_RES1; break; case TCR2_EL2: - *res0 = compute_res0_bits(kvm, tcr2_el2_feat_map, - ARRAY_SIZE(tcr2_el2_feat_map), 0, 0); - *res0 |= TCR2_EL2_RES0; + *res0 = compute_reg_res0_bits(kvm, &tcr2_el2_desc, 0, 0); *res1 = TCR2_EL2_RES1; break; case SCTLR_EL1: From d2a1d78ce5962b01500d09b15e2a854768552d44 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 18 Sep 2025 16:14:01 +0100 Subject: [PATCH 1700/2711] KVM: arm64: Convert SCTLR_EL1 RES0 handling to compute_reg_res0_bits() While SCTLR_EL1 cannot be RES0, convert it to the same infrastructure anyway, as it make things cleaner. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/config.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index 8c6c89d311ac..cab28773ef1f 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -1128,6 +1128,9 @@ static const struct reg_bits_to_feat_map sctlr_el1_feat_map[] = { FEAT_AA64EL1), }; +static const DECLARE_FEAT_MAP(sctlr_el1_desc, SCTLR_EL1, + sctlr_el1_feat_map, FEAT_AA64EL1); + static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = { NEEDS_FEAT(MDCR_EL2_EBWE, FEAT_Debugv8p9), NEEDS_FEAT(MDCR_EL2_TDOSA, FEAT_DoubleLock), @@ -1200,8 +1203,7 @@ void __init check_feature_map(void) check_reg_desc(&hcr_desc); check_reg_desc(&sctlr2_desc); check_reg_desc(&tcr2_el2_desc); - check_feat_map(sctlr_el1_feat_map, ARRAY_SIZE(sctlr_el1_feat_map), - SCTLR_EL1_RES0, "SCTLR_EL1"); + check_reg_desc(&sctlr_el1_desc); check_feat_map(mdcr_el2_feat_map, ARRAY_SIZE(mdcr_el2_feat_map), MDCR_EL2_RES0, "MDCR_EL2"); } @@ -1411,9 +1413,7 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r *res1 = TCR2_EL2_RES1; break; case SCTLR_EL1: - *res0 = compute_res0_bits(kvm, sctlr_el1_feat_map, - ARRAY_SIZE(sctlr_el1_feat_map), 0, 0); - *res0 |= SCTLR_EL1_RES0; + *res0 = compute_reg_res0_bits(kvm, &sctlr_el1_desc, 0, 0); *res1 = SCTLR_EL1_RES1; break; case MDCR_EL2: From ac53365990a19e808fde2758074ee31be65d1015 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 18 Sep 2025 16:14:02 +0100 Subject: [PATCH 1701/2711] KVM: arm64: Convert MDCR_EL2 RES0 handling to compute_reg_res0_bits() While MDCR_EL2 cannot be RES0, convert it to the same infrastructure anyway, as it make things cleaner. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/config.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index cab28773ef1f..fbd8944a3dea 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -1162,6 +1162,9 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = { FEAT_AA64EL1), }; +static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2, + mdcr_el2_feat_map, FEAT_AA64EL2); + static void __init check_feat_map(const struct reg_bits_to_feat_map *map, int map_size, u64 res0, const char *str) { @@ -1204,8 +1207,7 @@ void __init check_feature_map(void) check_reg_desc(&sctlr2_desc); check_reg_desc(&tcr2_el2_desc); check_reg_desc(&sctlr_el1_desc); - check_feat_map(mdcr_el2_feat_map, ARRAY_SIZE(mdcr_el2_feat_map), - MDCR_EL2_RES0, "MDCR_EL2"); + check_reg_desc(&mdcr_el2_desc); } static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map) @@ -1417,9 +1419,7 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r *res1 = SCTLR_EL1_RES1; break; case MDCR_EL2: - *res0 = compute_res0_bits(kvm, mdcr_el2_feat_map, - ARRAY_SIZE(mdcr_el2_feat_map), 0, 0); - *res0 |= MDCR_EL2_RES0; + *res0 = compute_reg_res0_bits(kvm, &mdcr_el2_desc, 0, 0); *res1 = MDCR_EL2_RES1; break; default: From 1a0b2bf6ff11d2e0438f3a7d1d299339edab96e8 Mon Sep 17 00:00:00 2001 From: Jinqian Yang Date: Thu, 11 Sep 2025 19:46:20 +0800 Subject: [PATCH 1702/2711] KVM: arm64: Make ID_AA64MMFR1_EL1.{HCX, TWED} writable from userspace Allow userspace to downgrade {HCX, TWED} in ID_AA64MMFR1_EL1. Userspace can only change the value from high to low. Signed-off-by: Jinqian Yang Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index b29f72478a50..e6ec971eb9d1 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3152,8 +3152,6 @@ static const struct sys_reg_desc sys_reg_descs[] = { ~(ID_AA64MMFR0_EL1_RES0 | ID_AA64MMFR0_EL1_ASIDBITS)), ID_WRITABLE(ID_AA64MMFR1_EL1, ~(ID_AA64MMFR1_EL1_RES0 | - ID_AA64MMFR1_EL1_HCX | - ID_AA64MMFR1_EL1_TWED | ID_AA64MMFR1_EL1_XNX | ID_AA64MMFR1_EL1_VH | ID_AA64MMFR1_EL1_VMIDBits)), From be8c9192eaeee21fdaacd72ad4ba992b9e42377b Mon Sep 17 00:00:00 2001 From: Jinqian Yang Date: Thu, 11 Sep 2025 19:46:21 +0800 Subject: [PATCH 1703/2711] KVM: arm64: selftests: Test writes to ID_AA64MMFR1_EL1.{HCX, TWED} Assert that the EL2 features {HCX, TWED} of ID_AA64MMFR1_EL1 are writable from userspace. They are only allowed to be downgraded in userspace. Signed-off-by: Jinqian Yang Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/arm64/set_id_regs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c index 189321e96925..d0aaecf77710 100644 --- a/tools/testing/selftests/kvm/arm64/set_id_regs.c +++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c @@ -165,7 +165,9 @@ static const struct reg_ftr_bits ftr_id_aa64mmfr0_el1[] = { static const struct reg_ftr_bits ftr_id_aa64mmfr1_el1[] = { REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, TIDCP1, 0), REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, AFP, 0), + REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, HCX, 0), REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, ETS, 0), + REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, TWED, 0), REG_FTR_BITS(FTR_HIGHER_SAFE, ID_AA64MMFR1_EL1, SpecSEI, 0), REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, PAN, 0), REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, LO, 0), From d3c35b7c57fc33ce787921e2faf84b7d58989a2a Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:48 -0700 Subject: [PATCH 1704/2711] KVM: arm64: nv: Convert masks to denylists in limit_nv_id_reg() Consistently use denylisting of features such that the limitations of KVM's nested implementation are explicitly documented (rather than implied). Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 47 +++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 77db81bae86f..53c57d105c93 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1462,9 +1462,18 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) case SYS_ID_AA64PFR1_EL1: /* Only support BTI, SSBS, CSV2_frac */ - val &= (ID_AA64PFR1_EL1_BT | - ID_AA64PFR1_EL1_SSBS | - ID_AA64PFR1_EL1_CSV2_frac); + val &= ~(ID_AA64PFR1_EL1_PFAR | + ID_AA64PFR1_EL1_DF2 | + ID_AA64PFR1_EL1_MTEX | + ID_AA64PFR1_EL1_THE | + ID_AA64PFR1_EL1_GCS | + ID_AA64PFR1_EL1_MTE_frac | + ID_AA64PFR1_EL1_NMI | + ID_AA64PFR1_EL1_SME | + ID_AA64PFR1_EL1_RES0 | + ID_AA64PFR1_EL1_MPAM_frac | + ID_AA64PFR1_EL1_RAS_frac | + ID_AA64PFR1_EL1_MTE); break; case SYS_ID_AA64MMFR0_EL1: @@ -1517,12 +1526,16 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) break; case SYS_ID_AA64MMFR1_EL1: - val &= (ID_AA64MMFR1_EL1_HCX | - ID_AA64MMFR1_EL1_PAN | - ID_AA64MMFR1_EL1_LO | - ID_AA64MMFR1_EL1_HPDS | - ID_AA64MMFR1_EL1_VH | - ID_AA64MMFR1_EL1_VMIDBits); + val &= ~(ID_AA64MMFR1_EL1_ECBHB | + ID_AA64MMFR1_EL1_CMOW | + ID_AA64MMFR1_EL1_TIDCP1 | + ID_AA64MMFR1_EL1_nTLBPA | + ID_AA64MMFR1_EL1_AFP | + ID_AA64MMFR1_EL1_ETS | + ID_AA64MMFR1_EL1_TWED | + ID_AA64MMFR1_EL1_XNX | + ID_AA64MMFR1_EL1_SpecSEI | + ID_AA64MMFR1_EL1_HAFDBS); /* FEAT_E2H0 implies no VHE */ if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features)) val &= ~ID_AA64MMFR1_EL1_VH; @@ -1564,11 +1577,17 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) case SYS_ID_AA64DFR0_EL1: /* Only limited support for PMU, Debug, BPs, WPs, and HPMN0 */ - val &= (ID_AA64DFR0_EL1_PMUVer | - ID_AA64DFR0_EL1_WRPs | - ID_AA64DFR0_EL1_BRPs | - ID_AA64DFR0_EL1_DebugVer| - ID_AA64DFR0_EL1_HPMN0); + val &= ~(ID_AA64DFR0_EL1_ExtTrcBuff | + ID_AA64DFR0_EL1_BRBE | + ID_AA64DFR0_EL1_MTPMU | + ID_AA64DFR0_EL1_TraceBuffer | + ID_AA64DFR0_EL1_TraceFilt | + ID_AA64DFR0_EL1_DoubleLock | + ID_AA64DFR0_EL1_PMSVer | + ID_AA64DFR0_EL1_CTX_CMPs | + ID_AA64DFR0_EL1_SEBEP | + ID_AA64DFR0_EL1_PMSS | + ID_AA64DFR0_EL1_TraceVer); /* Cap Debug to ARMv8.1 */ val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, VHE); From 49da9872a6a6fa943c02448eeae6db5e7f479283 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:49 -0700 Subject: [PATCH 1705/2711] KVM: arm64: nv: Don't erroneously claim FEAT_DoubleLock for NV VMs ID_AA64DFR0_EL1.DoubleLock is one of those annoying signed feature fields where a non-negative value implies that a feature is implemented and a negative value implies that it is not. While the intention of masking this field was likely to hide the feature, KVM actually advertises it, even on unsupporting hardware. Remove FEAT_DoubleLock from the mask, making the NI value visible to the VM. Take care to accept the old, incorrect values for this field as we've lied to userspace. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 1 - arch/arm64/kvm/sys_regs.c | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 53c57d105c93..4044dc66fa39 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1582,7 +1582,6 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) ID_AA64DFR0_EL1_MTPMU | ID_AA64DFR0_EL1_TraceBuffer | ID_AA64DFR0_EL1_TraceFilt | - ID_AA64DFR0_EL1_DoubleLock | ID_AA64DFR0_EL1_PMSVer | ID_AA64DFR0_EL1_CTX_CMPs | ID_AA64DFR0_EL1_SEBEP | diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index e6ec971eb9d1..caf80c324b35 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1997,6 +1997,26 @@ static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val) return val; } +/* + * Older versions of KVM erroneously claim support for FEAT_DoubleLock with + * NV-enabled VMs on unsupporting hardware. Silently ignore the incorrect + * value if it is consistent with the bug. + */ +static bool ignore_feat_doublelock(struct kvm_vcpu *vcpu, u64 val) +{ + u8 host, user; + + if (!vcpu_has_nv(vcpu)) + return false; + + host = SYS_FIELD_GET(ID_AA64DFR0_EL1, DoubleLock, + read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1)); + user = SYS_FIELD_GET(ID_AA64DFR0_EL1, DoubleLock, val); + + return host == ID_AA64DFR0_EL1_DoubleLock_NI && + user == ID_AA64DFR0_EL1_DoubleLock_IMP; +} + static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, u64 val) @@ -2028,6 +2048,11 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu, if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP) return -EINVAL; + if (ignore_feat_doublelock(vcpu, val)) { + val &= ~ID_AA64DFR0_EL1_DoubleLock; + val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DoubleLock, NI); + } + return set_id_reg(vcpu, rd, val); } From fac4ee7abe47a078a790ad2a9dd777257a186acc Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:50 -0700 Subject: [PATCH 1706/2711] KVM: arm64: nv: Expose FEAT_DF2 to NV-enabled VMs The supporting infrastructure in KVM's abort injection code was merged a while ago, but the author (me!) forgot to relax the NV limitation when FEAT_DF2 got exposed to non-NV VMs. Fix it. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 4044dc66fa39..5e46e95e2684 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1463,7 +1463,6 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) case SYS_ID_AA64PFR1_EL1: /* Only support BTI, SSBS, CSV2_frac */ val &= ~(ID_AA64PFR1_EL1_PFAR | - ID_AA64PFR1_EL1_DF2 | ID_AA64PFR1_EL1_MTEX | ID_AA64PFR1_EL1_THE | ID_AA64PFR1_EL1_GCS | From 26785cf28bb10bc94b2a52820c8ba1b3cfc534e5 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:51 -0700 Subject: [PATCH 1707/2711] KVM: arm64: nv: Expose FEAT_RASv1p1 via RAS_frac KVM already supports FEAT_RASv1p1 for NV-enabled VMs but only when advertised through the canonical field. Stop masking the silly frac field to expose the feature on systems without FEAT_DF. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 5e46e95e2684..35fa6e00c9be 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1471,7 +1471,6 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) ID_AA64PFR1_EL1_SME | ID_AA64PFR1_EL1_RES0 | ID_AA64PFR1_EL1_MPAM_frac | - ID_AA64PFR1_EL1_RAS_frac | ID_AA64PFR1_EL1_MTE); break; From 7cbdb25bed4046dacf139cce25fad9ef39a04a5f Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:52 -0700 Subject: [PATCH 1708/2711] KVM: arm64: nv: Expose FEAT_ECBHB to NV-enabled VMs The exact wording of the restrictions on branch prediction due to FEAT_ECBHB in DDI0487L.b is as follows: When FEAT_ECBHB is implemented, the branch history information created in a context before an exception to a higher Exception level using AArch64 cannot be used by code before that exception to exploitatively control the execution of any indirect branches in code in a different context after the exception. While vEL2 and EL1 are multiplexed at EL1, they exist in different hardware-described contexts as KVM uses different stage-2 MMUs to represent the corresponding translation regimes. Additionally, exception entries into vEL2 always imply a hardware exception entry into literal EL2 for the emulated regime change. Given all of this, and the fact that FEAT_ECBHB places no limitation on the EL of the protected context after the exception, we can claim FEAT_ECBHB on supporting hardware. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 35fa6e00c9be..20e7b11d5d67 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1524,8 +1524,7 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) break; case SYS_ID_AA64MMFR1_EL1: - val &= ~(ID_AA64MMFR1_EL1_ECBHB | - ID_AA64MMFR1_EL1_CMOW | + val &= ~(ID_AA64MMFR1_EL1_CMOW | ID_AA64MMFR1_EL1_TIDCP1 | ID_AA64MMFR1_EL1_nTLBPA | ID_AA64MMFR1_EL1_AFP | From 09dc6b42c62e47718ce0e94d44db7deffdc193ff Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:53 -0700 Subject: [PATCH 1709/2711] KVM: arm64: nv: Expose FEAT_AFP to NV-enabled VMs FEAT_AFP doesn't intersect with any EL2 trap behavior, expose to NV-enabled VMs. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 20e7b11d5d67..4e70b4908c99 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1527,7 +1527,6 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) val &= ~(ID_AA64MMFR1_EL1_CMOW | ID_AA64MMFR1_EL1_TIDCP1 | ID_AA64MMFR1_EL1_nTLBPA | - ID_AA64MMFR1_EL1_AFP | ID_AA64MMFR1_EL1_ETS | ID_AA64MMFR1_EL1_TWED | ID_AA64MMFR1_EL1_XNX | From 05d9f3408334afb97b91dc869c658e6951c3dcb3 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:54 -0700 Subject: [PATCH 1710/2711] KVM: arm64: nv: Exclude guest's TWED configuration when TWE isn't set Ignore the guest hypervisor's configured TWE delay if it hasn't actually requested WFE traps. Otherwise, OR'ing these fields into the effective HCR when the guest sets TWE is safe as KVM doesn't use FEAT_TWED and leaves the fields initialized to 0. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp/vhe/switch.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c index 0998ad4a2552..9984c492305a 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -95,6 +95,13 @@ static u64 __compute_hcr(struct kvm_vcpu *vcpu) /* Force NV2 in case the guest is forgetful... */ guest_hcr |= HCR_NV2; } + + /* + * Exclude the guest's TWED configuration if it hasn't set TWE + * to avoid potentially delaying traps for the host. + */ + if (!(guest_hcr & HCR_TWE)) + guest_hcr &= ~(HCR_EL2_TWEDEn | HCR_EL2_TWEDEL); } BUG_ON(host_data_test_flag(VCPU_IN_HYP_CONTEXT) && From 952387c9d39998c7ba48a93aa7f8b8eb420d61dd Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:55 -0700 Subject: [PATCH 1711/2711] KVM: arm64: nv: Expose FEAT_TWED to NV-enabled VMs KVM now handles HCR_EL2.{TWEDEn,TWEDEL} correctly when computing the effective HCR for a nested context. Advertise the feature. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 4e70b4908c99..a5e1a3de2742 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1528,7 +1528,6 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) ID_AA64MMFR1_EL1_TIDCP1 | ID_AA64MMFR1_EL1_nTLBPA | ID_AA64MMFR1_EL1_ETS | - ID_AA64MMFR1_EL1_TWED | ID_AA64MMFR1_EL1_XNX | ID_AA64MMFR1_EL1_SpecSEI | ID_AA64MMFR1_EL1_HAFDBS); From fe2c9cd439e0f84a31b3610e2530663e5d1d3fa8 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:56 -0700 Subject: [PATCH 1712/2711] KVM: arm64: nv: Advertise FEAT_SpecSEI to NV-enabled VMs FEAT_SpecSEI is an informational feature describing whether speculative loads may generate SErrors. Since there are already cases where KVM reinjects an SError into the VM it is already possible this may happen due to a speculative load within the VM. Stop hiding the feature from NV-enabled VMs. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index a5e1a3de2742..d3186f656d83 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1529,7 +1529,6 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) ID_AA64MMFR1_EL1_nTLBPA | ID_AA64MMFR1_EL1_ETS | ID_AA64MMFR1_EL1_XNX | - ID_AA64MMFR1_EL1_SpecSEI | ID_AA64MMFR1_EL1_HAFDBS); /* FEAT_E2H0 implies no VHE */ if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features)) From 6f2224ef07437116ae9c46257b323306260074d1 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:57 -0700 Subject: [PATCH 1713/2711] KVM: arm64: nv: Advertise FEAT_TIDCP1 to NV-enabled VMs While KVM does not expose IMPDEF features to VMs, FEAT_TIDCP1 is an architecturally-defined EL1 trap of a particular sysreg encoding range. Furthermore, KVM already advertises this feature to non-NV VMs. As there is no interaction with EL2 traps, expose the feature. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index d3186f656d83..65b5fbb88510 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1525,7 +1525,6 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) case SYS_ID_AA64MMFR1_EL1: val &= ~(ID_AA64MMFR1_EL1_CMOW | - ID_AA64MMFR1_EL1_TIDCP1 | ID_AA64MMFR1_EL1_nTLBPA | ID_AA64MMFR1_EL1_ETS | ID_AA64MMFR1_EL1_XNX | From b8b1d62f17d6fb323dc1f38dd7ad43a88fcd75e3 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Fri, 12 Sep 2025 14:22:58 -0700 Subject: [PATCH 1714/2711] KVM: arm64: nv: Expose up to FEAT_Debugv8p8 to NV-enabled VMs The changes to the debug architecture up to v8.8 are concerned with external debug, which of course has no direct impact on VMs. Raise the feature limit and document what's preventing us from raising it further. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/nested.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 65b5fbb88510..74bd5140c9a4 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -1581,8 +1581,11 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) ID_AA64DFR0_EL1_PMSS | ID_AA64DFR0_EL1_TraceVer); - /* Cap Debug to ARMv8.1 */ - val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, VHE); + /* + * FEAT_Debugv8p9 requires support for extended breakpoints / + * watchpoints. + */ + val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8); break; } From 557c82a4480719f64cf6530b5090001e9d908904 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 1 Sep 2025 13:40:36 +0100 Subject: [PATCH 1715/2711] KVM: arm64: Add trap configs for PMSDSFR_EL1 SPE data source filtering (SPE_FEAT_FDS) adds a new register PMSDSFR_EL1, add the trap configs for it. PMSNEVFR_EL1 was also missing its VNCR offset so add it along with PMSDSFR_EL1. Tested-by: Leo Yan Signed-off-by: James Clark Reviewed-by: Joey Gouly Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/vncr_mapping.h | 2 ++ arch/arm64/kvm/emulate-nested.c | 1 + arch/arm64/kvm/sys_regs.c | 1 + 3 files changed, 4 insertions(+) diff --git a/arch/arm64/include/asm/vncr_mapping.h b/arch/arm64/include/asm/vncr_mapping.h index f6ec500ad3fa..c2485a862e69 100644 --- a/arch/arm64/include/asm/vncr_mapping.h +++ b/arch/arm64/include/asm/vncr_mapping.h @@ -94,6 +94,8 @@ #define VNCR_PMSICR_EL1 0x838 #define VNCR_PMSIRR_EL1 0x840 #define VNCR_PMSLATFR_EL1 0x848 +#define VNCR_PMSNEVFR_EL1 0x850 +#define VNCR_PMSDSFR_EL1 0x858 #define VNCR_TRFCR_EL1 0x880 #define VNCR_MPAM1_EL1 0x900 #define VNCR_MPAMHCR_EL2 0x930 diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 90cb4b7ae0ff..aeaba7813275 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -1185,6 +1185,7 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = { SR_TRAP(SYS_PMSIRR_EL1, CGT_MDCR_TPMS), SR_TRAP(SYS_PMSLATFR_EL1, CGT_MDCR_TPMS), SR_TRAP(SYS_PMSNEVFR_EL1, CGT_MDCR_TPMS), + SR_TRAP(SYS_PMSDSFR_EL1, CGT_MDCR_TPMS), SR_TRAP(SYS_TRFCR_EL1, CGT_MDCR_TTRF), SR_TRAP(SYS_TRBBASER_EL1, CGT_MDCR_E2TB), SR_TRAP(SYS_TRBLIMITR_EL1, CGT_MDCR_E2TB), diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 82ffb3b3b3cf..d1a55cf589b7 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3083,6 +3083,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_PMBLIMITR_EL1), undef_access }, { SYS_DESC(SYS_PMBPTR_EL1), undef_access }, { SYS_DESC(SYS_PMBSR_EL1), undef_access }, + { SYS_DESC(SYS_PMSDSFR_EL1), undef_access }, /* PMBIDR_EL1 is not trapped */ { PMU_SYS_REG(PMINTENSET_EL1), From 5d20605c8e7930254f7bee41336e421be247181c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 18 Sep 2025 20:42:06 +0100 Subject: [PATCH 1716/2711] KVM: arm64: Expose FEAT_LSFE to guests FEAT_LSFE (Large System Float Extension), providing atomic floating point memory operations, is optional from v9.5. This feature adds no new architectural state, expose the relevant ID register field to guests so they can discover it. Signed-off-by: Mark Brown Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index d1a55cf589b7..1099b815cd61 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1642,7 +1642,8 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_WFxT); break; case SYS_ID_AA64ISAR3_EL1: - val &= ID_AA64ISAR3_EL1_FPRCVT | ID_AA64ISAR3_EL1_FAMINMAX; + val &= ID_AA64ISAR3_EL1_FPRCVT | ID_AA64ISAR3_EL1_LSFE | + ID_AA64ISAR3_EL1_FAMINMAX; break; case SYS_ID_AA64MMFR2_EL1: val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK; @@ -2991,6 +2992,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { ID_AA64ISAR2_EL1_APA3 | ID_AA64ISAR2_EL1_GPA3)), ID_WRITABLE(ID_AA64ISAR3_EL1, (ID_AA64ISAR3_EL1_FPRCVT | + ID_AA64ISAR3_EL1_LSFE | ID_AA64ISAR3_EL1_FAMINMAX)), ID_UNALLOCATED(6,4), ID_UNALLOCATED(6,5), From 0b1fca9dce44d0d2a8f4c55df1e4149744934a91 Mon Sep 17 00:00:00 2001 From: Xinpeng Sun Date: Wed, 17 Sep 2025 09:53:44 +0800 Subject: [PATCH 1717/2711] HID: intel-thc-hid: intel-quicki2c: support ACPI config for advanced features There is a new BIOS enhancement that adds the capability to configure the following two features of I2C subsystem introduced in commit 1ed0b48 ("Intel-thc: Introduce max input size control") and commit 3f2a921 ("Intel-thc: Introduce interrupt delay control"): - Max input size control - Interrupt delay control As BIOS is used for the configuration of these two features, change driver data usage to indicate hardware capability, and add corresponding ACPI configuration support in QuickI2C driver. Signed-off-by: Xinpeng Sun Tested-by: Rui Zhang Reviewed-by: Even Xu Signed-off-by: Jiri Kosina --- .../intel-quicki2c/pci-quicki2c.c | 39 +++++++++++++++---- .../intel-quicki2c/quicki2c-dev.h | 24 +++++++++++- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c index 854926b3cfd4..3ce5a692b92b 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c @@ -23,6 +23,7 @@ static struct quicki2c_ddata ptl_ddata = { .max_detect_size = MAX_RX_DETECT_SIZE_PTL, + .max_interrupt_delay = MAX_RX_INTERRUPT_DELAY, }; /* THC QuickI2C ACPI method to get device properties */ @@ -200,6 +201,21 @@ static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev) return -EOPNOTSUPP; } + if (qcdev->ddata) { + qcdev->i2c_max_frame_size_enable = i2c_config.FSEN; + qcdev->i2c_int_delay_enable = i2c_config.INDE; + + if (i2c_config.FSVL <= qcdev->ddata->max_detect_size) + qcdev->i2c_max_frame_size = i2c_config.FSVL; + else + qcdev->i2c_max_frame_size = qcdev->ddata->max_detect_size; + + if (i2c_config.INDV <= qcdev->ddata->max_interrupt_delay) + qcdev->i2c_int_delay = i2c_config.INDV; + else + qcdev->i2c_int_delay = qcdev->ddata->max_interrupt_delay; + } + return 0; } @@ -441,17 +457,24 @@ static void quicki2c_dma_adv_enable(struct quicki2c_device *qcdev) * max input length <= THC detect capability, enable the feature with device * max input length. */ - if (qcdev->ddata->max_detect_size >= - le16_to_cpu(qcdev->dev_desc.max_input_len)) { - thc_i2c_set_rx_max_size(qcdev->thc_hw, - le16_to_cpu(qcdev->dev_desc.max_input_len)); + if (qcdev->i2c_max_frame_size_enable) { + if (qcdev->i2c_max_frame_size >= + le16_to_cpu(qcdev->dev_desc.max_input_len)) { + thc_i2c_set_rx_max_size(qcdev->thc_hw, + le16_to_cpu(qcdev->dev_desc.max_input_len)); + } else { + dev_warn(qcdev->dev, + "Max frame size is smaller than hid max input length!"); + thc_i2c_set_rx_max_size(qcdev->thc_hw, + le16_to_cpu(qcdev->i2c_max_frame_size)); + } thc_i2c_rx_max_size_enable(qcdev->thc_hw, true); } /* If platform supports interrupt delay feature, enable it with given delay */ - if (qcdev->ddata->interrupt_delay) { + if (qcdev->i2c_int_delay_enable) { thc_i2c_set_rx_int_delay(qcdev->thc_hw, - qcdev->ddata->interrupt_delay); + qcdev->i2c_int_delay * 10); thc_i2c_rx_int_delay_enable(qcdev->thc_hw, true); } } @@ -464,10 +487,10 @@ static void quicki2c_dma_adv_enable(struct quicki2c_device *qcdev) */ static void quicki2c_dma_adv_disable(struct quicki2c_device *qcdev) { - if (qcdev->ddata->max_detect_size) + if (qcdev->i2c_max_frame_size_enable) thc_i2c_rx_max_size_enable(qcdev->thc_hw, false); - if (qcdev->ddata->interrupt_delay) + if (qcdev->i2c_int_delay_enable) thc_i2c_rx_int_delay_enable(qcdev->thc_hw, false); } diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h index d412eafcf9ea..0d423d5dd7a7 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h @@ -38,6 +38,8 @@ /* PTL Max packet size detection capability is 255 Bytes */ #define MAX_RX_DETECT_SIZE_PTL 255 +/* Max interrupt delay capability is 2.56ms */ +#define MAX_RX_INTERRUPT_DELAY 256 /* Default interrupt delay is 1ms, suitable for most devices */ #define DEFAULT_INTERRUPT_DELAY_US (1 * USEC_PER_MSEC) @@ -101,6 +103,10 @@ struct quicki2c_subip_acpi_parameter { * @HMTD: High Speed Mode Plus (3.4Mbits/sec) Serial Data Line Transmit HOLD Period * @HMRD: High Speed Mode Plus (3.4Mbits/sec) Serial Data Line Receive HOLD Period * @HMSL: Maximum length (in ic_clk_cycles) of suppressed spikes in High Speed Mode + * @FSEN: Maximum Frame Size Feature Enable Control + * @FSVL: Maximum Frame Size Value (unit in Bytes) + * @INDE: Interrupt Delay Feature Enable Control + * @INDV: Interrupt Delay Value (unit in 10 us) * * Those properties get from QUICKI2C_ACPI_METHOD_NAME_ISUB method, used for * I2C timing configure. @@ -127,17 +133,22 @@ struct quicki2c_subip_acpi_config { u64 HMTD; u64 HMRD; u64 HMSL; + + u64 FSEN; + u64 FSVL; + u64 INDE; + u64 INDV; u8 reserved; }; /** * struct quicki2c_ddata - Driver specific data for quicki2c device * @max_detect_size: Identify max packet size detect for rx - * @interrupt_delay: Identify interrupt detect delay for rx + * @interrupt_delay: Identify max interrupt detect delay for rx */ struct quicki2c_ddata { u32 max_detect_size; - u32 interrupt_delay; + u32 max_interrupt_delay; }; struct device; @@ -170,6 +181,10 @@ struct acpi_device; * @report_len: The length of input/output report packet * @reset_ack_wq: Workqueue for waiting reset response from device * @reset_ack: Indicate reset response received or not + * @i2c_max_frame_size_enable: Indicate max frame size feature enabled or not + * @i2c_max_frame_size: Max RX frame size (unit in Bytes) + * @i2c_int_delay_enable: Indicate interrupt delay feature enabled or not + * @i2c_int_delay: Interrupt detection delay value (unit in 10 us) */ struct quicki2c_device { struct device *dev; @@ -200,6 +215,11 @@ struct quicki2c_device { wait_queue_head_t reset_ack_wq; bool reset_ack; + + u32 i2c_max_frame_size_enable; + u32 i2c_max_frame_size; + u32 i2c_int_delay_enable; + u32 i2c_int_delay; }; #endif /* _QUICKI2C_DEV_H_ */ From 039fd0634a0629132432632d7ac9a14915406b5c Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:08 +0100 Subject: [PATCH 1718/2711] perf arm_spe: Correct setting remote access Set the mem_remote field for a remote access to appropriately represent the event. Fixes: a89dbc9b988f3ba8 ("perf arm-spe: Set sample's data source field") Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 228ed52e653d..63a32255197a 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -828,7 +828,7 @@ static void arm_spe__synth_memory_level(const struct arm_spe_record *record, } if (record->type & ARM_SPE_REMOTE_ACCESS) - data_src->mem_lvl |= PERF_MEM_LVL_REM_CCE1; + data_src->mem_remote = PERF_MEM_REMOTE_REMOTE; } static bool arm_spe__synth_ds(struct arm_spe_queue *speq, From cb300e3515057fb555983ce47e8acc86a5c69c3c Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:09 +0100 Subject: [PATCH 1719/2711] perf arm_spe: Correct memory level for remote access For remote accesses, the data source packet does not contain information about the memory level. To avoid misinformation, set the memory level to NA (Not Available). Fixes: 4e6430cbb1a9f1dc ("perf arm-spe: Use SPE data source for neoverse cores") Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 63a32255197a..6fb012d89488 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -659,8 +659,8 @@ static void arm_spe__synth_data_source_common(const struct arm_spe_record *recor * socket */ case ARM_SPE_COMMON_DS_REMOTE: - data_src->mem_lvl = PERF_MEM_LVL_REM_CCE1; - data_src->mem_lvl_num = PERF_MEM_LVLNUM_ANY_CACHE; + data_src->mem_lvl = PERF_MEM_LVL_NA; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_NA; data_src->mem_remote = PERF_MEM_REMOTE_REMOTE; data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER; break; From 7203a22492e6c1836e641c8f65786c40e456dd42 Mon Sep 17 00:00:00 2001 From: James Clark Date: Fri, 12 Sep 2025 16:42:10 +0100 Subject: [PATCH 1720/2711] perf arm_spe: Use full type for data_src data_src has an actual type rather than just being a u64. To help readers, delay decomposing it to a u64 until it's finally assigned to the sample. Signed-off-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 6fb012d89488..38e6f8331f27 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -469,7 +469,8 @@ arm_spe_deliver_synth_event(struct arm_spe *spe, } static int arm_spe__synth_mem_sample(struct arm_spe_queue *speq, - u64 spe_events_id, u64 data_src) + u64 spe_events_id, + union perf_mem_data_src data_src) { struct arm_spe *spe = speq->spe; struct arm_spe_record *record = &speq->decoder->record; @@ -484,7 +485,7 @@ static int arm_spe__synth_mem_sample(struct arm_spe_queue *speq, sample.stream_id = spe_events_id; sample.addr = record->virt_addr; sample.phys_addr = record->phys_addr; - sample.data_src = data_src; + sample.data_src = data_src.val; sample.weight = record->latency; ret = arm_spe_deliver_synth_event(spe, speq, event, &sample); @@ -517,7 +518,8 @@ static int arm_spe__synth_branch_sample(struct arm_spe_queue *speq, } static int arm_spe__synth_instruction_sample(struct arm_spe_queue *speq, - u64 spe_events_id, u64 data_src) + u64 spe_events_id, + union perf_mem_data_src data_src) { struct arm_spe *spe = speq->spe; struct arm_spe_record *record = &speq->decoder->record; @@ -532,7 +534,7 @@ static int arm_spe__synth_instruction_sample(struct arm_spe_queue *speq, sample.stream_id = spe_events_id; sample.addr = record->to_ip; sample.phys_addr = record->phys_addr; - sample.data_src = data_src; + sample.data_src = data_src.val; sample.weight = record->latency; sample.flags = speq->flags; sample.branch_stack = speq->last_branch; @@ -880,21 +882,22 @@ static bool arm_spe__synth_ds(struct arm_spe_queue *speq, return false; } -static u64 arm_spe__synth_data_source(struct arm_spe_queue *speq, - const struct arm_spe_record *record) +static union perf_mem_data_src +arm_spe__synth_data_source(struct arm_spe_queue *speq, + const struct arm_spe_record *record) { - union perf_mem_data_src data_src = { .mem_op = PERF_MEM_OP_NA }; + union perf_mem_data_src data_src = {}; /* Only synthesize data source for LDST operations */ if (!is_ldst_op(record->op)) - return 0; + return data_src; if (record->op & ARM_SPE_OP_LD) data_src.mem_op = PERF_MEM_OP_LOAD; else if (record->op & ARM_SPE_OP_ST) data_src.mem_op = PERF_MEM_OP_STORE; else - return 0; + return data_src; if (!arm_spe__synth_ds(speq, record, &data_src)) arm_spe__synth_memory_level(record, &data_src); @@ -908,14 +911,14 @@ static u64 arm_spe__synth_data_source(struct arm_spe_queue *speq, data_src.mem_dtlb |= PERF_MEM_TLB_HIT; } - return data_src.val; + return data_src; } static int arm_spe_sample(struct arm_spe_queue *speq) { const struct arm_spe_record *record = &speq->decoder->record; struct arm_spe *spe = speq->spe; - u64 data_src; + union perf_mem_data_src data_src; int err; /* From 45854b6d775b3a0610cdd5e00393253539338d14 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:11 +0100 Subject: [PATCH 1721/2711] perf arm_spe: Directly propagate raw event Two sets of event bits are defined: one for generating samples and another are raw event bits used in the backend decoder. Reduce the redundancy by using the raw event bits directly in the frontend code. To avoid overflow issues, change the type of the event variable from enum to u64. Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- .../util/arm-spe-decoder/arm-spe-decoder.c | 37 +------------------ .../util/arm-spe-decoder/arm-spe-decoder.h | 28 +++++++------- 2 files changed, 14 insertions(+), 51 deletions(-) diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c index 688fe6d75244..96eb7cced6fd 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c @@ -229,42 +229,7 @@ static int arm_spe_read_record(struct arm_spe_decoder *decoder) } break; case ARM_SPE_EVENTS: - if (payload & BIT(EV_L1D_REFILL)) - decoder->record.type |= ARM_SPE_L1D_MISS; - - if (payload & BIT(EV_L1D_ACCESS)) - decoder->record.type |= ARM_SPE_L1D_ACCESS; - - if (payload & BIT(EV_TLB_WALK)) - decoder->record.type |= ARM_SPE_TLB_MISS; - - if (payload & BIT(EV_TLB_ACCESS)) - decoder->record.type |= ARM_SPE_TLB_ACCESS; - - if (payload & BIT(EV_LLC_MISS)) - decoder->record.type |= ARM_SPE_LLC_MISS; - - if (payload & BIT(EV_LLC_ACCESS)) - decoder->record.type |= ARM_SPE_LLC_ACCESS; - - if (payload & BIT(EV_REMOTE_ACCESS)) - decoder->record.type |= ARM_SPE_REMOTE_ACCESS; - - if (payload & BIT(EV_MISPRED)) - decoder->record.type |= ARM_SPE_BRANCH_MISS; - - if (payload & BIT(EV_NOT_TAKEN)) - decoder->record.type |= ARM_SPE_BRANCH_NOT_TAKEN; - - if (payload & BIT(EV_TRANSACTIONAL)) - decoder->record.type |= ARM_SPE_IN_TXN; - - if (payload & BIT(EV_PARTIAL_PREDICATE)) - decoder->record.type |= ARM_SPE_SVE_PARTIAL_PRED; - - if (payload & BIT(EV_EMPTY_PREDICATE)) - decoder->record.type |= ARM_SPE_SVE_EMPTY_PRED; - + decoder->record.type = payload; break; case ARM_SPE_DATA_SOURCE: decoder->record.source = payload; diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h index 881d9f29c138..03da55453da8 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h @@ -13,20 +13,18 @@ #include "arm-spe-pkt-decoder.h" -enum arm_spe_sample_type { - ARM_SPE_L1D_ACCESS = 1 << 0, - ARM_SPE_L1D_MISS = 1 << 1, - ARM_SPE_LLC_ACCESS = 1 << 2, - ARM_SPE_LLC_MISS = 1 << 3, - ARM_SPE_TLB_ACCESS = 1 << 4, - ARM_SPE_TLB_MISS = 1 << 5, - ARM_SPE_BRANCH_MISS = 1 << 6, - ARM_SPE_REMOTE_ACCESS = 1 << 7, - ARM_SPE_SVE_PARTIAL_PRED = 1 << 8, - ARM_SPE_SVE_EMPTY_PRED = 1 << 9, - ARM_SPE_BRANCH_NOT_TAKEN = 1 << 10, - ARM_SPE_IN_TXN = 1 << 11, -}; +#define ARM_SPE_L1D_ACCESS BIT(EV_L1D_ACCESS) +#define ARM_SPE_L1D_MISS BIT(EV_L1D_REFILL) +#define ARM_SPE_LLC_ACCESS BIT(EV_LLC_ACCESS) +#define ARM_SPE_LLC_MISS BIT(EV_LLC_MISS) +#define ARM_SPE_TLB_ACCESS BIT(EV_TLB_ACCESS) +#define ARM_SPE_TLB_MISS BIT(EV_TLB_WALK) +#define ARM_SPE_BRANCH_MISS BIT(EV_MISPRED) +#define ARM_SPE_BRANCH_NOT_TAKEN BIT(EV_NOT_TAKEN) +#define ARM_SPE_REMOTE_ACCESS BIT(EV_REMOTE_ACCESS) +#define ARM_SPE_SVE_PARTIAL_PRED BIT(EV_PARTIAL_PREDICATE) +#define ARM_SPE_SVE_EMPTY_PRED BIT(EV_EMPTY_PREDICATE) +#define ARM_SPE_IN_TXN BIT(EV_TRANSACTIONAL) enum arm_spe_op_type { /* First level operation type */ @@ -100,7 +98,7 @@ enum arm_spe_hisi_hip_data_source { }; struct arm_spe_record { - enum arm_spe_sample_type type; + u64 type; int err; u32 op; u32 latency; From e44e2b2b16dffc56c86cc062d85721644dcf37f4 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:12 +0100 Subject: [PATCH 1722/2711] perf arm_spe: Decode event types for new features Decode new event types introduced by FEAT_SPEv1p4, FEAT_SPE_SME and FEAT_SPE_SME. The printed event names don't strictly follow the naming in the Arm ARM. For example, the "Cache data modified" event is shown as "HITM", and the "Data snooped" event is printed as "SNOOPED". Shorter names are easier to read while preserving core meanings. Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- .../util/arm-spe-decoder/arm-spe-pkt-decoder.c | 14 ++++++++++++++ .../util/arm-spe-decoder/arm-spe-pkt-decoder.h | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c index 13cadb2f1cea..80561630253d 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c @@ -314,6 +314,20 @@ static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet, arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-PARTIAL-PRED"); if (payload & BIT(EV_EMPTY_PREDICATE)) arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-EMPTY-PRED"); + if (payload & BIT(EV_L2D_ACCESS)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " L2D-ACCESS"); + if (payload & BIT(EV_L2D_MISS)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " L2D-MISS"); + if (payload & BIT(EV_CACHE_DATA_MODIFIED)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " HITM"); + if (payload & BIT(EV_RECENTLY_FETCHED)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " LFB"); + if (payload & BIT(EV_DATA_SNOOPED)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " SNOOPED"); + if (payload & BIT(EV_STREAMING_SVE_MODE)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " STREAMING-SVE"); + if (payload & BIT(EV_SMCU)) + arm_spe_pkt_out_string(&err, &buf, &buf_len, " SMCU"); return err; } diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h index 2cdf9f6da268..d00c2481712d 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h @@ -108,6 +108,13 @@ enum arm_spe_events { EV_TRANSACTIONAL = 16, EV_PARTIAL_PREDICATE = 17, EV_EMPTY_PREDICATE = 18, + EV_L2D_ACCESS = 19, + EV_L2D_MISS = 20, + EV_CACHE_DATA_MODIFIED = 21, + EV_RECENTLY_FETCHED = 22, + EV_DATA_SNOOPED = 23, + EV_STREAMING_SVE_MODE = 24, + EV_SMCU = 25, }; /* Operation packet header */ From 99940fd9e145895d03b4ee456491b9583ae88795 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:13 +0100 Subject: [PATCH 1723/2711] perf arm_spe: Add "event_filter" entry in meta data Add a new "event_filter" entry in the meta data and dump it in raw data mode. After: # perf script -D ... 0 0 0x470 [0x1f0]: PERF_RECORD_AUXTRACE_INFO type: 4 Header version :2 Header size :4 PMU type v2 :11 CPU number :8 Magic :0x1010101010101010 CPU # :0 Num of params :4 MIDR :0x410fd0f0 PMU Type :11 Min Interval :256 Event Filter :0x3fe08fe ... Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm64/util/arm-spe.c | 5 +++++ tools/perf/util/arm-spe.c | 1 + tools/perf/util/arm-spe.h | 2 ++ 3 files changed, 8 insertions(+) diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 4f2833b62ff5..cac43cde7dbe 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -121,12 +121,17 @@ static int arm_spe_save_cpu_header(struct auxtrace_record *itr, /* No Arm SPE PMU is found */ data[ARM_SPE_CPU_PMU_TYPE] = ULLONG_MAX; data[ARM_SPE_CAP_MIN_IVAL] = 0; + data[ARM_SPE_CAP_EVENT_FILTER] = 0; } else { data[ARM_SPE_CPU_PMU_TYPE] = pmu->type; if (perf_pmu__scan_file(pmu, "caps/min_interval", "%lu", &val) != 1) val = 0; data[ARM_SPE_CAP_MIN_IVAL] = val; + + if (perf_pmu__scan_file(pmu, "caps/event_filter", "%lx", &val) != 1) + val = 0; + data[ARM_SPE_CAP_EVENT_FILTER] = val; } free(cpuid); diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 38e6f8331f27..24968fc15693 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -1532,6 +1532,7 @@ static const char * const metadata_per_cpu_fmts[] = { [ARM_SPE_CPU_MIDR] = " MIDR :0x%"PRIx64"\n", [ARM_SPE_CPU_PMU_TYPE] = " PMU Type :%"PRId64"\n", [ARM_SPE_CAP_MIN_IVAL] = " Min Interval :%"PRId64"\n", + [ARM_SPE_CAP_EVENT_FILTER] = " Event Filter :0x%"PRIx64"\n", }; static void arm_spe_print_info(struct arm_spe *spe, __u64 *arr) diff --git a/tools/perf/util/arm-spe.h b/tools/perf/util/arm-spe.h index 390679a4af2f..3966df1856d8 100644 --- a/tools/perf/util/arm-spe.h +++ b/tools/perf/util/arm-spe.h @@ -47,6 +47,8 @@ enum { ARM_SPE_CPU_PMU_TYPE, /* Minimal interval */ ARM_SPE_CAP_MIN_IVAL, + /* Event filter */ + ARM_SPE_CAP_EVENT_FILTER, ARM_SPE_CPU_PRIV_MAX, }; From 98f993ae6f4bc50fcdb0168a1673f7943e1189f2 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:14 +0100 Subject: [PATCH 1724/2711] perf arm_spe: Refine memory level filling This commit introduces macros for detecting cache level and cache miss. Populates the 'mem_lvl_num' field which is a later added attribute for representing memory level. Set NA ("not available") to memory levels if memory hierarchy info is absent. Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 24968fc15693..255a36ecd7bc 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -39,6 +39,15 @@ #define is_ldst_op(op) (!!((op) & ARM_SPE_OP_LDST)) +#define ARM_SPE_CACHE_EVENT(lvl) \ + (ARM_SPE_##lvl##_ACCESS | ARM_SPE_##lvl##_MISS) + +#define arm_spe_is_cache_level(type, lvl) \ + ((type) & ARM_SPE_CACHE_EVENT(lvl)) + +#define arm_spe_is_cache_miss(type, lvl) \ + ((type) & ARM_SPE_##lvl##_MISS) + struct arm_spe { struct auxtrace auxtrace; struct auxtrace_queues queues; @@ -813,20 +822,21 @@ static const struct data_source_handle data_source_handles[] = { static void arm_spe__synth_memory_level(const struct arm_spe_record *record, union perf_mem_data_src *data_src) { - if (record->type & (ARM_SPE_LLC_ACCESS | ARM_SPE_LLC_MISS)) { + if (arm_spe_is_cache_level(record->type, LLC)) { data_src->mem_lvl = PERF_MEM_LVL_L3; - - if (record->type & ARM_SPE_LLC_MISS) - data_src->mem_lvl |= PERF_MEM_LVL_MISS; - else - data_src->mem_lvl |= PERF_MEM_LVL_HIT; - } else if (record->type & (ARM_SPE_L1D_ACCESS | ARM_SPE_L1D_MISS)) { + data_src->mem_lvl |= arm_spe_is_cache_miss(record->type, LLC) ? + PERF_MEM_LVL_MISS : PERF_MEM_LVL_HIT; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3; + } else if (arm_spe_is_cache_level(record->type, L1D)) { data_src->mem_lvl = PERF_MEM_LVL_L1; + data_src->mem_lvl |= arm_spe_is_cache_miss(record->type, L1D) ? + PERF_MEM_LVL_MISS : PERF_MEM_LVL_HIT; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1; + } - if (record->type & ARM_SPE_L1D_MISS) - data_src->mem_lvl |= PERF_MEM_LVL_MISS; - else - data_src->mem_lvl |= PERF_MEM_LVL_HIT; + if (!data_src->mem_lvl) { + data_src->mem_lvl = PERF_MEM_LVL_NA; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_NA; } if (record->type & ARM_SPE_REMOTE_ACCESS) From 14d4ecb15e885ebea8eeb0389c6a35e3a166f199 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:15 +0100 Subject: [PATCH 1725/2711] perf arm_spe: Separate setting of memory levels for loads and stores For a load hit, the lowest-level cache reflects the latency of fetching a data. Otherwise, the highest-level cache involved in refilling indicates the overhead caused by a load. Store operations remain unchanged to keep the descending order when iterating through cache levels. Split into two functions: one is for setting memory levels for loads and another for stores. Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe.c | 45 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 255a36ecd7bc..433af83ec3d1 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -45,6 +45,9 @@ #define arm_spe_is_cache_level(type, lvl) \ ((type) & ARM_SPE_CACHE_EVENT(lvl)) +#define arm_spe_is_cache_hit(type, lvl) \ + (((type) & ARM_SPE_CACHE_EVENT(lvl)) == ARM_SPE_##lvl##_ACCESS) + #define arm_spe_is_cache_miss(type, lvl) \ ((type) & ARM_SPE_##lvl##_MISS) @@ -819,9 +822,38 @@ static const struct data_source_handle data_source_handles[] = { DS(hisi_hip_ds_encoding_cpus, data_source_hisi_hip), }; -static void arm_spe__synth_memory_level(const struct arm_spe_record *record, - union perf_mem_data_src *data_src) +static void arm_spe__synth_ld_memory_level(const struct arm_spe_record *record, + union perf_mem_data_src *data_src) { + /* + * To find a cache hit, search in ascending order from the lower level + * caches to the higher level caches. This reflects the best scenario + * for a cache hit. + */ + if (arm_spe_is_cache_hit(record->type, L1D)) { + data_src->mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1; + } else if (arm_spe_is_cache_hit(record->type, LLC)) { + data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3; + /* + * To find a cache miss, search in descending order from the higher + * level cache to the lower level cache. This represents the worst + * scenario for a cache miss. + */ + } else if (arm_spe_is_cache_miss(record->type, LLC)) { + data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_MISS; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3; + } else if (arm_spe_is_cache_miss(record->type, L1D)) { + data_src->mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1; + } +} + +static void arm_spe__synth_st_memory_level(const struct arm_spe_record *record, + union perf_mem_data_src *data_src) +{ + /* Record the greatest level info for a store operation. */ if (arm_spe_is_cache_level(record->type, LLC)) { data_src->mem_lvl = PERF_MEM_LVL_L3; data_src->mem_lvl |= arm_spe_is_cache_miss(record->type, LLC) ? @@ -833,6 +865,15 @@ static void arm_spe__synth_memory_level(const struct arm_spe_record *record, PERF_MEM_LVL_MISS : PERF_MEM_LVL_HIT; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1; } +} + +static void arm_spe__synth_memory_level(const struct arm_spe_record *record, + union perf_mem_data_src *data_src) +{ + if (data_src->mem_op == PERF_MEM_OP_LOAD) + arm_spe__synth_ld_memory_level(record, data_src); + if (data_src->mem_op == PERF_MEM_OP_STORE) + arm_spe__synth_st_memory_level(record, data_src); if (!data_src->mem_lvl) { data_src->mem_lvl = PERF_MEM_LVL_NA; From 786e7e7a504634168c0287ad8de3f4fe34f1b1f6 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:16 +0100 Subject: [PATCH 1726/2711] perf arm_spe: Fill memory levels for FEAT_SPEv1p4 Starting with FEAT_SPEv1p4, Arm SPE provides information on Level 2 data cache and recently fetched events. This patch fills in the memory levels for these new events. The recently fetched events are matched to line-fill buffer (LFB). In general, the latency for accessing LFB is higher than accessing L1 cache but lower than accessing L2 cache. Thus, it locates in the memory hierarchy information between L1 cache and L2 cache. Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe-decoder/arm-spe-decoder.h | 3 +++ tools/perf/util/arm-spe.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h index 03da55453da8..3afa8703b21d 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h @@ -25,6 +25,9 @@ #define ARM_SPE_SVE_PARTIAL_PRED BIT(EV_PARTIAL_PREDICATE) #define ARM_SPE_SVE_EMPTY_PRED BIT(EV_EMPTY_PREDICATE) #define ARM_SPE_IN_TXN BIT(EV_TRANSACTIONAL) +#define ARM_SPE_L2D_ACCESS BIT(EV_L2D_ACCESS) +#define ARM_SPE_L2D_MISS BIT(EV_L2D_MISS) +#define ARM_SPE_RECENTLY_FETCHED BIT(EV_RECENTLY_FETCHED) enum arm_spe_op_type { /* First level operation type */ diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 433af83ec3d1..c5fd62534e03 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -833,6 +833,12 @@ static void arm_spe__synth_ld_memory_level(const struct arm_spe_record *record, if (arm_spe_is_cache_hit(record->type, L1D)) { data_src->mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1; + } else if (record->type & ARM_SPE_RECENTLY_FETCHED) { + data_src->mem_lvl = PERF_MEM_LVL_LFB | PERF_MEM_LVL_HIT; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_LFB; + } else if (arm_spe_is_cache_hit(record->type, L2D)) { + data_src->mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_HIT; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2; } else if (arm_spe_is_cache_hit(record->type, LLC)) { data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3; @@ -844,6 +850,9 @@ static void arm_spe__synth_ld_memory_level(const struct arm_spe_record *record, } else if (arm_spe_is_cache_miss(record->type, LLC)) { data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_MISS; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3; + } else if (arm_spe_is_cache_miss(record->type, L2D)) { + data_src->mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_MISS; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2; } else if (arm_spe_is_cache_miss(record->type, L1D)) { data_src->mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1; @@ -859,6 +868,11 @@ static void arm_spe__synth_st_memory_level(const struct arm_spe_record *record, data_src->mem_lvl |= arm_spe_is_cache_miss(record->type, LLC) ? PERF_MEM_LVL_MISS : PERF_MEM_LVL_HIT; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3; + } else if (arm_spe_is_cache_level(record->type, L2D)) { + data_src->mem_lvl = PERF_MEM_LVL_L2; + data_src->mem_lvl |= arm_spe_is_cache_miss(record->type, L2D) ? + PERF_MEM_LVL_MISS : PERF_MEM_LVL_HIT; + data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2; } else if (arm_spe_is_cache_level(record->type, L1D)) { data_src->mem_lvl = PERF_MEM_LVL_L1; data_src->mem_lvl |= arm_spe_is_cache_miss(record->type, L1D) ? From 04abd5c06516a3c59fe14fbee0e510d3c21fc3b6 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:17 +0100 Subject: [PATCH 1727/2711] perf arm_spe: Refactor arm_spe__get_metadata_by_cpu() Handle "CPU=-1" (per-thread mode) in the arm_spe__get_metadata_by_cpu() function. As a result, the function is more general and will be invoked by a sequential change. Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index c5fd62534e03..58f80b5c0ab9 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -315,15 +315,28 @@ static int arm_spe_set_tid(struct arm_spe_queue *speq, pid_t tid) return 0; } -static u64 *arm_spe__get_metadata_by_cpu(struct arm_spe *spe, u64 cpu) +static u64 *arm_spe__get_metadata_by_cpu(struct arm_spe *spe, int cpu) { u64 i; if (!spe->metadata) return NULL; + /* CPU ID is -1 for per-thread mode */ + if (cpu < 0) { + /* + * On the heterogeneous system, due to CPU ID is -1, + * cannot confirm the data source packet is supported. + */ + if (!spe->is_homogeneous) + return NULL; + + /* In homogeneous system, simply use CPU0's metadata */ + return spe->metadata[0]; + } + for (i = 0; i < spe->metadata_nr_cpu; i++) - if (spe->metadata[i][ARM_SPE_CPU] == cpu) + if (spe->metadata[i][ARM_SPE_CPU] == (u64)cpu) return spe->metadata[i]; return NULL; @@ -915,22 +928,7 @@ static bool arm_spe__synth_ds(struct arm_spe_queue *speq, cpuid = perf_env__cpuid(perf_session__env(spe->session)); midr = strtol(cpuid, NULL, 16); } else { - /* CPU ID is -1 for per-thread mode */ - if (speq->cpu < 0) { - /* - * On the heterogeneous system, due to CPU ID is -1, - * cannot confirm the data source packet is supported. - */ - if (!spe->is_homogeneous) - return false; - - /* In homogeneous system, simply use CPU0's metadata */ - if (spe->metadata) - metadata = spe->metadata[0]; - } else { - metadata = arm_spe__get_metadata_by_cpu(spe, speq->cpu); - } - + metadata = arm_spe__get_metadata_by_cpu(spe, speq->cpu); if (!metadata) return false; From d510568970f38539eff41e6fe4ef76809f1b184c Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:18 +0100 Subject: [PATCH 1728/2711] perf arm_spe: Set HITM flag Since FEAT_SPEv1p4, Arm SPE provides two extra events: "Cache data modified" and "Data snooped". Set the snoop mode as: - If both the "Cache data modified" event and the "Data snooped" event are set, which indicates a load operation that snooped from a outside cache and hit a modified copy, set the HITM flag to inspect false sharing. - If the snooped event bit is not set, and the snooped event has been supported by the hardware, set as NONE mode (no snoop operation). - If the snooped event bit is not set, and the event is not supported or absent the events info in the meta data, set as NA mode (not available). Don't set any mode for only "Cache data modified" event, as it hits a local modified copy. Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- .../util/arm-spe-decoder/arm-spe-decoder.h | 2 ++ tools/perf/util/arm-spe.c | 26 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h index 3afa8703b21d..fbb57f805237 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h @@ -28,6 +28,8 @@ #define ARM_SPE_L2D_ACCESS BIT(EV_L2D_ACCESS) #define ARM_SPE_L2D_MISS BIT(EV_L2D_MISS) #define ARM_SPE_RECENTLY_FETCHED BIT(EV_RECENTLY_FETCHED) +#define ARM_SPE_DATA_SNOOPED BIT(EV_DATA_SNOOPED) +#define ARM_SPE_HITM BIT(EV_CACHE_DATA_MODIFIED) enum arm_spe_op_type { /* First level operation type */ diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 58f80b5c0ab9..08cb493c3265 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -894,9 +894,12 @@ static void arm_spe__synth_st_memory_level(const struct arm_spe_record *record, } } -static void arm_spe__synth_memory_level(const struct arm_spe_record *record, +static void arm_spe__synth_memory_level(struct arm_spe_queue *speq, + const struct arm_spe_record *record, union perf_mem_data_src *data_src) { + struct arm_spe *spe = speq->spe; + if (data_src->mem_op == PERF_MEM_OP_LOAD) arm_spe__synth_ld_memory_level(record, data_src); if (data_src->mem_op == PERF_MEM_OP_STORE) @@ -907,6 +910,25 @@ static void arm_spe__synth_memory_level(const struct arm_spe_record *record, data_src->mem_lvl_num = PERF_MEM_LVLNUM_NA; } + if (record->type & ARM_SPE_DATA_SNOOPED) { + if (record->type & ARM_SPE_HITM) + data_src->mem_snoop = PERF_MEM_SNOOP_HITM; + else + data_src->mem_snoop = PERF_MEM_SNOOP_HIT; + } else { + u64 *metadata = arm_spe__get_metadata_by_cpu(spe, speq->cpu); + + /* + * Set NA ("Not available") mode if no meta data or the + * SNOOPED event is not supported. + */ + if (!metadata || + !(metadata[ARM_SPE_CAP_EVENT_FILTER] & ARM_SPE_DATA_SNOOPED)) + data_src->mem_snoop = PERF_MEM_SNOOP_NA; + else + data_src->mem_snoop = PERF_MEM_SNOOP_NONE; + } + if (record->type & ARM_SPE_REMOTE_ACCESS) data_src->mem_remote = PERF_MEM_REMOTE_REMOTE; } @@ -963,7 +985,7 @@ arm_spe__synth_data_source(struct arm_spe_queue *speq, return data_src; if (!arm_spe__synth_ds(speq, record, &data_src)) - arm_spe__synth_memory_level(record, &data_src); + arm_spe__synth_memory_level(speq, record, &data_src); if (record->type & (ARM_SPE_TLB_ACCESS | ARM_SPE_TLB_MISS)) { data_src.mem_dtlb = PERF_MEM_TLB_WK; From d120cb34c9c75cf49d8ef821215d26d6e22fe8a9 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 12 Sep 2025 16:42:19 +0100 Subject: [PATCH 1729/2711] perf arm_spe: Allow parsing both data source and events Current code skips to parse events after generating data source. The reason is the data source packets have cache and snooping related info, the afterwards event packets might contain duplicate info. This commit changes to continue parsing the events after data source analysis. If data source does not give out memory level and snooping types, then the event info is used to synthesize the related fields. As a result, both the peer snoop option ('-d peer') and hitm options ('-d tot/lcl/rmt') are supported by Arm SPE in 'perf c2c'. Reviewed-by: James Clark Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ali Saidi Cc: German Gomez Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/arm-spe.c | 73 +++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 08cb493c3265..71be979f5077 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -900,40 +900,56 @@ static void arm_spe__synth_memory_level(struct arm_spe_queue *speq, { struct arm_spe *spe = speq->spe; - if (data_src->mem_op == PERF_MEM_OP_LOAD) - arm_spe__synth_ld_memory_level(record, data_src); - if (data_src->mem_op == PERF_MEM_OP_STORE) - arm_spe__synth_st_memory_level(record, data_src); + /* + * The data source packet contains more info for cache levels for + * peer snooping. So respect the memory level if has been set by + * data source parsing. + */ + if (!data_src->mem_lvl) { + if (data_src->mem_op == PERF_MEM_OP_LOAD) + arm_spe__synth_ld_memory_level(record, data_src); + if (data_src->mem_op == PERF_MEM_OP_STORE) + arm_spe__synth_st_memory_level(record, data_src); + } if (!data_src->mem_lvl) { data_src->mem_lvl = PERF_MEM_LVL_NA; data_src->mem_lvl_num = PERF_MEM_LVLNUM_NA; } - if (record->type & ARM_SPE_DATA_SNOOPED) { - if (record->type & ARM_SPE_HITM) - data_src->mem_snoop = PERF_MEM_SNOOP_HITM; - else - data_src->mem_snoop = PERF_MEM_SNOOP_HIT; - } else { - u64 *metadata = arm_spe__get_metadata_by_cpu(spe, speq->cpu); + /* + * If 'mem_snoop' has been set by data source packet, skip to set + * it at here. + */ + if (!data_src->mem_snoop) { + if (record->type & ARM_SPE_DATA_SNOOPED) { + if (record->type & ARM_SPE_HITM) + data_src->mem_snoop = PERF_MEM_SNOOP_HITM; + else + data_src->mem_snoop = PERF_MEM_SNOOP_HIT; + } else { + u64 *metadata = + arm_spe__get_metadata_by_cpu(spe, speq->cpu); - /* - * Set NA ("Not available") mode if no meta data or the - * SNOOPED event is not supported. - */ - if (!metadata || - !(metadata[ARM_SPE_CAP_EVENT_FILTER] & ARM_SPE_DATA_SNOOPED)) - data_src->mem_snoop = PERF_MEM_SNOOP_NA; - else - data_src->mem_snoop = PERF_MEM_SNOOP_NONE; + /* + * Set NA ("Not available") mode if no meta data or the + * SNOOPED event is not supported. + */ + if (!metadata || + !(metadata[ARM_SPE_CAP_EVENT_FILTER] & ARM_SPE_DATA_SNOOPED)) + data_src->mem_snoop = PERF_MEM_SNOOP_NA; + else + data_src->mem_snoop = PERF_MEM_SNOOP_NONE; + } } - if (record->type & ARM_SPE_REMOTE_ACCESS) - data_src->mem_remote = PERF_MEM_REMOTE_REMOTE; + if (!data_src->mem_remote) { + if (record->type & ARM_SPE_REMOTE_ACCESS) + data_src->mem_remote = PERF_MEM_REMOTE_REMOTE; + } } -static bool arm_spe__synth_ds(struct arm_spe_queue *speq, +static void arm_spe__synth_ds(struct arm_spe_queue *speq, const struct arm_spe_record *record, union perf_mem_data_src *data_src) { @@ -952,19 +968,18 @@ static bool arm_spe__synth_ds(struct arm_spe_queue *speq, } else { metadata = arm_spe__get_metadata_by_cpu(spe, speq->cpu); if (!metadata) - return false; + return; midr = metadata[ARM_SPE_CPU_MIDR]; } for (i = 0; i < ARRAY_SIZE(data_source_handles); i++) { if (is_midr_in_range_list(midr, data_source_handles[i].midr_ranges)) { - data_source_handles[i].ds_synth(record, data_src); - return true; + return data_source_handles[i].ds_synth(record, data_src); } } - return false; + return; } static union perf_mem_data_src @@ -984,8 +999,8 @@ arm_spe__synth_data_source(struct arm_spe_queue *speq, else return data_src; - if (!arm_spe__synth_ds(speq, record, &data_src)) - arm_spe__synth_memory_level(speq, record, &data_src); + arm_spe__synth_ds(speq, record, &data_src); + arm_spe__synth_memory_level(speq, record, &data_src); if (record->type & (ARM_SPE_TLB_ACCESS | ARM_SPE_TLB_MISS)) { data_src.mem_dtlb = PERF_MEM_TLB_WK; From ece3c7754fc94aed15b7da567a4d22e30e3ee52b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 20 Aug 2025 17:32:20 -0700 Subject: [PATCH 1730/2711] perf trace: Add --max-summary option The --max-summary option is to limit the number of output lines for syscall summary stats. The max applies to each entries like thread and cgroups. For total summary, it will just print up to the given number. For example, $ sudo perf trace -as --max-summary 3 sleep 0.1 ThreadPoolServi (1011651), 114 events, 14.8% syscall calls errors total min avg max stddev (msec) (msec) (msec) (msec) (%) --------------- -------- ------ -------- --------- --------- --------- ------ epoll_wait 38 0 95.589 0.000 2.515 11.153 28.98% futex 9 0 0.040 0.002 0.004 0.014 28.63% read 10 0 0.037 0.003 0.004 0.005 4.67% sleep (1050529), 250 events, 32.4% syscall calls errors total min avg max stddev (msec) (msec) (msec) (msec) (%) --------------- -------- ------ -------- --------- --------- --------- ------ clock_nanosleep 1 0 100.156 100.156 100.156 100.156 0.00% execve 4 3 1.020 0.005 0.255 0.989 95.93% openat 36 17 0.416 0.003 0.012 0.029 10.58% ... And this is for per-cgroup summary using BPF. $ sudo perf trace -as --max-summary 3 --summary-mode=cgroup --bpf-summary sleep 0.1 cgroup /user.slice/user-657345.slice/user@657345.service/session.slice/org.gnome.Shell@x11.service, 12 events syscall calls errors total min avg max stddev (msec) (msec) (msec) (msec) (%) --------------- -------- ------ -------- --------- --------- --------- ------ recvmsg 8 7 0.016 0.001 0.002 0.006 39.73% ppoll 1 0 0.014 0.014 0.014 0.014 0.00% write 2 0 0.010 0.002 0.005 0.008 61.02% cgroup /user.slice/user-657345.slice/session-4.scope, 73 events syscall calls errors total min avg max stddev (msec) (msec) (msec) (msec) (%) --------------- -------- ------ -------- --------- --------- --------- ------ epoll_wait 8 0 13.461 0.010 1.683 12.235 89.66% ioctl 20 0 0.204 0.001 0.010 0.113 54.01% writev 11 0 0.164 0.004 0.015 0.042 20.34% Reviewed-by: Howard Chu Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-trace.txt | 4 +++ tools/perf/builtin-trace.c | 10 ++++++- tools/perf/util/bpf-trace-summary.c | 40 ++++++++++++++----------- tools/perf/util/trace.h | 4 +-- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 973fede403a0..892c82a9bf40 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt @@ -249,6 +249,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. works well with -s/--summary option where no argument information is required. +--max-summary=N:: + Maximum number of lines in the summary mode. Note that this applies to + each entry (thread or cgroup). + PAGEFAULTS ---------- diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index fe737b3ac6e6..5f54777d8ba0 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -196,6 +196,7 @@ struct trace { unsigned int max_stack; unsigned int min_stack; enum trace_summary_mode summary_mode; + int max_summary; int raw_augmented_syscalls_args_size; bool raw_augmented_syscalls; bool fd_path_disabled; @@ -4599,7 +4600,7 @@ out_disable: if (!err) { if (trace->summary) { if (trace->summary_bpf) - trace_print_bpf_summary(trace->output); + trace_print_bpf_summary(trace->output, trace->max_summary); else if (trace->summary_mode == SUMMARY__BY_TOTAL) trace__fprintf_total_summary(trace, trace->output); else @@ -4822,6 +4823,7 @@ static size_t syscall__dump_stats(struct trace *trace, int e_machine, FILE *fp, struct hashmap *syscall_stats) { size_t printed = 0; + int lines = 0; struct syscall *sc; struct syscall_entry *entries; @@ -4866,7 +4868,11 @@ static size_t syscall__dump_stats(struct trace *trace, int e_machine, FILE *fp, fprintf(fp, "\t\t\t\t%s: %d\n", perf_env__arch_strerrno(trace->host->env, e + 1), stats->errnos[e]); } } + lines++; } + + if (trace->max_summary && trace->max_summary <= lines) + break; } free(entries); @@ -5443,6 +5449,8 @@ int cmd_trace(int argc, const char **argv) OPT_BOOLEAN(0, "force-btf", &trace.force_btf, "Prefer btf_dump general pretty printer" "to customized ones"), OPT_BOOLEAN(0, "bpf-summary", &trace.summary_bpf, "Summary syscall stats in BPF"), + OPT_INTEGER(0, "max-summary", &trace.max_summary, + "Max number of entries in the summary."), OPTS_EVSWITCH(&trace.evswitch), OPT_END() }; diff --git a/tools/perf/util/bpf-trace-summary.c b/tools/perf/util/bpf-trace-summary.c index 69fb165da206..8dfe7e678941 100644 --- a/tools/perf/util/bpf-trace-summary.c +++ b/tools/perf/util/bpf-trace-summary.c @@ -138,11 +138,14 @@ static bool sc_node_equal(long key1, long key2, void *ctx __maybe_unused) return key1 == key2; } -static int print_common_stats(struct syscall_data *data, FILE *fp) +static int print_common_stats(struct syscall_data *data, int max_summary, FILE *fp) { int printed = 0; - for (int i = 0; i < data->nr_nodes; i++) { + if (max_summary == 0 || max_summary > data->nr_nodes) + max_summary = data->nr_nodes; + + for (int i = 0; i < max_summary; i++) { struct syscall_node *node = &data->nodes[i]; struct syscall_stats *stat = &node->stats; double total = (double)(stat->total_time) / NSEC_PER_MSEC; @@ -200,7 +203,7 @@ static int update_thread_stats(struct hashmap *hash, struct syscall_key *map_key return 0; } -static int print_thread_stat(struct syscall_data *data, FILE *fp) +static int print_thread_stat(struct syscall_data *data, int max_summary, FILE *fp) { int printed = 0; @@ -213,18 +216,18 @@ static int print_thread_stat(struct syscall_data *data, FILE *fp) printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); printed += fprintf(fp, " --------------- -------- ------ -------- --------- --------- --------- ------\n"); - printed += print_common_stats(data, fp); + printed += print_common_stats(data, max_summary, fp); printed += fprintf(fp, "\n\n"); return printed; } -static int print_thread_stats(struct syscall_data **data, int nr_data, FILE *fp) +static int print_thread_stats(struct syscall_data **data, int nr_data, int max_summary, FILE *fp) { int printed = 0; for (int i = 0; i < nr_data; i++) - printed += print_thread_stat(data[i], fp); + printed += print_thread_stat(data[i], max_summary, fp); return printed; } @@ -277,7 +280,7 @@ static int update_total_stats(struct hashmap *hash, struct syscall_key *map_key, return 0; } -static int print_total_stats(struct syscall_data **data, int nr_data, FILE *fp) +static int print_total_stats(struct syscall_data **data, int nr_data, int max_summary, FILE *fp) { int printed = 0; int nr_events = 0; @@ -291,8 +294,11 @@ static int print_total_stats(struct syscall_data **data, int nr_data, FILE *fp) printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); printed += fprintf(fp, " --------------- -------- ------ -------- --------- --------- --------- ------\n"); - for (int i = 0; i < nr_data; i++) - printed += print_common_stats(data[i], fp); + if (max_summary == 0 || max_summary > nr_data) + max_summary = nr_data; + + for (int i = 0; i < max_summary; i++) + printed += print_common_stats(data[i], max_summary, fp); printed += fprintf(fp, "\n\n"); return printed; @@ -333,7 +339,7 @@ static int update_cgroup_stats(struct hashmap *hash, struct syscall_key *map_key return 0; } -static int print_cgroup_stat(struct syscall_data *data, FILE *fp) +static int print_cgroup_stat(struct syscall_data *data, int max_summary, FILE *fp) { int printed = 0; struct cgroup *cgrp = __cgroup__find(&cgroups, data->key); @@ -351,23 +357,23 @@ static int print_cgroup_stat(struct syscall_data *data, FILE *fp) printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); printed += fprintf(fp, " --------------- -------- ------ -------- --------- --------- --------- ------\n"); - printed += print_common_stats(data, fp); + printed += print_common_stats(data, max_summary, fp); printed += fprintf(fp, "\n\n"); return printed; } -static int print_cgroup_stats(struct syscall_data **data, int nr_data, FILE *fp) +static int print_cgroup_stats(struct syscall_data **data, int nr_data, int max_summary, FILE *fp) { int printed = 0; for (int i = 0; i < nr_data; i++) - printed += print_cgroup_stat(data[i], fp); + printed += print_cgroup_stat(data[i], max_summary, fp); return printed; } -int trace_print_bpf_summary(FILE *fp) +int trace_print_bpf_summary(FILE *fp, int max_summary) { struct bpf_map *map = skel->maps.syscall_stats_map; struct syscall_key *prev_key, key; @@ -420,13 +426,13 @@ int trace_print_bpf_summary(FILE *fp) switch (skel->rodata->aggr_mode) { case SYSCALL_AGGR_THREAD: - printed += print_thread_stats(data, nr_data, fp); + printed += print_thread_stats(data, nr_data, max_summary, fp); break; case SYSCALL_AGGR_CPU: - printed += print_total_stats(data, nr_data, fp); + printed += print_total_stats(data, nr_data, max_summary, fp); break; case SYSCALL_AGGR_CGROUP: - printed += print_cgroup_stats(data, nr_data, fp); + printed += print_cgroup_stats(data, nr_data, max_summary, fp); break; default: break; diff --git a/tools/perf/util/trace.h b/tools/perf/util/trace.h index fa8d480527a2..fbbcfe6f44fe 100644 --- a/tools/perf/util/trace.h +++ b/tools/perf/util/trace.h @@ -16,7 +16,7 @@ enum trace_summary_mode { int trace_prepare_bpf_summary(enum trace_summary_mode mode); void trace_start_bpf_summary(void); void trace_end_bpf_summary(void); -int trace_print_bpf_summary(FILE *fp); +int trace_print_bpf_summary(FILE *fp, int max_summary); void trace_cleanup_bpf_summary(void); #else /* !HAVE_BPF_SKEL */ @@ -27,7 +27,7 @@ static inline int trace_prepare_bpf_summary(enum trace_summary_mode mode __maybe } static inline void trace_start_bpf_summary(void) {} static inline void trace_end_bpf_summary(void) {} -static inline int trace_print_bpf_summary(FILE *fp __maybe_unused) +static inline int trace_print_bpf_summary(FILE *fp __maybe_unused, int max_summary __maybe_unused) { return 0; } From 97996580da08f06f8b09a86f3384ed9fa7a52e32 Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen Date: Wed, 10 Sep 2025 12:52:12 -0700 Subject: [PATCH 1731/2711] perf vendor events arm64 AmpereOneX: Fix typo - should be l1d_cache_access_prefetches Add missing 'h' to l1d_cache_access_prefetces Also fix a couple of typos and use consistent term in brief descriptions Fixes: 16438b652b464ef7 ("perf vendor events arm64 AmpereOneX: Add core PMU events and metrics") Reviewed-by: James Clark Signed-off-by: Ilkka Koskinen Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ilkka Koskinen Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/arm64/ampere/ampereonex/metrics.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/metrics.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/metrics.json index 5228f94a793f..6817cac149e0 100644 --- a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/metrics.json +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/metrics.json @@ -113,7 +113,7 @@ { "MetricName": "load_store_spec_rate", "MetricExpr": "LDST_SPEC / INST_SPEC", - "BriefDescription": "The rate of load or store instructions speculatively executed to overall instructions speclatively executed", + "BriefDescription": "The rate of load or store instructions speculatively executed to overall instructions speculatively executed", "MetricGroup": "Operation_Mix", "ScaleUnit": "100percent of operations" }, @@ -132,7 +132,7 @@ { "MetricName": "pc_write_spec_rate", "MetricExpr": "PC_WRITE_SPEC / INST_SPEC", - "BriefDescription": "The rate of software change of the PC speculatively executed to overall instructions speclatively executed", + "BriefDescription": "The rate of software change of the PC speculatively executed to overall instructions speculatively executed", "MetricGroup": "Operation_Mix", "ScaleUnit": "100percent of operations" }, @@ -195,14 +195,14 @@ { "MetricName": "stall_frontend_cache_rate", "MetricExpr": "STALL_FRONTEND_CACHE / CPU_CYCLES", - "BriefDescription": "Proportion of cycles stalled and no ops delivered from frontend and cache miss", + "BriefDescription": "Proportion of cycles stalled and no operations delivered from frontend and cache miss", "MetricGroup": "Stall", "ScaleUnit": "100percent of cycles" }, { "MetricName": "stall_frontend_tlb_rate", "MetricExpr": "STALL_FRONTEND_TLB / CPU_CYCLES", - "BriefDescription": "Proportion of cycles stalled and no ops delivered from frontend and TLB miss", + "BriefDescription": "Proportion of cycles stalled and no operations delivered from frontend and TLB miss", "MetricGroup": "Stall", "ScaleUnit": "100percent of cycles" }, @@ -391,7 +391,7 @@ "ScaleUnit": "100percent of cache acceses" }, { - "MetricName": "l1d_cache_access_prefetces", + "MetricName": "l1d_cache_access_prefetches", "MetricExpr": "L1D_CACHE_PRFM / L1D_CACHE", "BriefDescription": "L1D cache access - prefetch", "MetricGroup": "Cache", From acd331d706f6b11e56670875fb228379feb7906c Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen Date: Wed, 10 Sep 2025 12:52:13 -0700 Subject: [PATCH 1732/2711] perf vendor events arm64 AmpereOne: Fix typos in metrics' descriptions While fixing a typo in "l1d_cache_access_prefetches" in AmpereOneX, a few other typos were found in metrics' descriptions too. While AmpereOne doesn't have the metric, it did have the typos in the descriptions. Reviewed-by: James Clark Signed-off-by: Ilkka Koskinen Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Link: https://lore.kernel.org/r/20250910195214.50814-3-ilkka@os.amperecomputing.com Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/arm64/ampere/ampereone/metrics.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereone/metrics.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereone/metrics.json index afcdad58ef89..324104438e78 100644 --- a/tools/perf/pmu-events/arch/arm64/ampere/ampereone/metrics.json +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereone/metrics.json @@ -113,7 +113,7 @@ { "MetricName": "load_store_spec_rate", "MetricExpr": "((LDST_SPEC / INST_SPEC) * 100)", - "BriefDescription": "The rate of load or store instructions speculatively executed to overall instructions speclatively executed", + "BriefDescription": "The rate of load or store instructions speculatively executed to overall instructions speculatively executed", "MetricGroup": "Operation_Mix", "ScaleUnit": "1percent of operations" }, @@ -132,7 +132,7 @@ { "MetricName": "pc_write_spec_rate", "MetricExpr": "((PC_WRITE_SPEC / INST_SPEC) * 100)", - "BriefDescription": "The rate of software change of the PC speculatively executed to overall instructions speclatively executed", + "BriefDescription": "The rate of software change of the PC speculatively executed to overall instructions speculatively executed", "MetricGroup": "Operation_Mix", "ScaleUnit": "1percent of operations" }, @@ -195,14 +195,14 @@ { "MetricName": "stall_frontend_cache_rate", "MetricExpr": "((STALL_FRONTEND_CACHE / CPU_CYCLES) * 100)", - "BriefDescription": "Proportion of cycles stalled and no ops delivered from frontend and cache miss", + "BriefDescription": "Proportion of cycles stalled and no operations delivered from frontend and cache miss", "MetricGroup": "Stall", "ScaleUnit": "1percent of cycles" }, { "MetricName": "stall_frontend_tlb_rate", "MetricExpr": "((STALL_FRONTEND_TLB / CPU_CYCLES) * 100)", - "BriefDescription": "Proportion of cycles stalled and no ops delivered from frontend and TLB miss", + "BriefDescription": "Proportion of cycles stalled and no operations delivered from frontend and TLB miss", "MetricGroup": "Stall", "ScaleUnit": "1percent of cycles" }, From 54a7685fd2d687dc4a7015d7bc32614d65d0d05a Mon Sep 17 00:00:00 2001 From: Gautam Menghani Date: Mon, 4 Aug 2025 16:36:01 +0530 Subject: [PATCH 1733/2711] perf auxtrace: Avoid redundant NULL check in auxtrace_mmap_params__set_idx() Since commit eead8a011477 ("libperf threadmap: Don't segv for index 0 for the NULL 'struct perf_thread_map' pointer"), perf_thread_map__pid() can check for a NULL map and return -1 if idx is 0. Cleanup auxtrace_mmap_params__set_idx() and remove the redundant NULL check. No functional change intended. Reviewed-by: Aditya Bodkhe Reviewed-by: Adrian Hunter Reviewed-by: Amit Machhiwal Signed-off-by: Gautam Menghani Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/auxtrace.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index ebd32f1b8f12..5e437133c753 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -185,10 +185,7 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, if (per_cpu) { mp->cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx); - if (evlist->core.threads) - mp->tid = perf_thread_map__pid(evlist->core.threads, 0); - else - mp->tid = -1; + mp->tid = perf_thread_map__pid(evlist->core.threads, 0); } else { mp->cpu.cpu = -1; mp->tid = perf_thread_map__pid(evlist->core.threads, idx); From 2e3501212293c5005873c6ca6bb4f963a7eec442 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 12 Sep 2025 17:03:50 -0700 Subject: [PATCH 1734/2711] perf test: AMD IBS swfilt skip kernel tests if paranoia is >1 If not root and the perf_event_paranoid is set >1 swfilt will fail to open the event failing the test. Add check to skip the test in that case. Fixes: 0e71bcdcf1f0b10b ("perf test: Add AMD IBS sw filter test") Reviewed-by: Namhyung Kim Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Collin Funk Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Link: https://lore.kernel.org/r/20250913000350.1306948-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/amd-ibs-swfilt.sh | 51 ++++++++++++++++++------ 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/tools/perf/tests/shell/amd-ibs-swfilt.sh b/tools/perf/tests/shell/amd-ibs-swfilt.sh index 7045ec72ba4c..e7f66df05c4b 100755 --- a/tools/perf/tests/shell/amd-ibs-swfilt.sh +++ b/tools/perf/tests/shell/amd-ibs-swfilt.sh @@ -1,6 +1,10 @@ #!/bin/bash # AMD IBS software filtering +ParanoidAndNotRoot() { + [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] +} + echo "check availability of IBS swfilt" # check if IBS PMU is available @@ -16,6 +20,7 @@ if [ ! -f /sys/bus/event_source/devices/ibs_op/format/swfilt ]; then fi echo "run perf record with modifier and swfilt" +err=0 # setting any modifiers should fail perf record -B -e ibs_op//u -o /dev/null true 2> /dev/null @@ -31,11 +36,17 @@ if [ $? -ne 0 ]; then exit 1 fi -# setting it with swfilt=1 should be fine -perf record -B -e ibs_op/swfilt=1/k -o /dev/null true -if [ $? -ne 0 ]; then - echo "[FAIL] IBS op PMU cannot handle swfilt for exclude_user" - exit 1 +if ! ParanoidAndNotRoot 1 +then + # setting it with swfilt=1 should be fine + perf record -B -e ibs_op/swfilt=1/k -o /dev/null true + if [ $? -ne 0 ]; then + echo "[FAIL] IBS op PMU cannot handle swfilt for exclude_user" + exit 1 + fi +else + echo "[SKIP] not root and perf_event_paranoid too high for exclude_user" + err=2 fi # check ibs_fetch PMU as well @@ -46,10 +57,16 @@ if [ $? -ne 0 ]; then fi # check system wide recording -perf record -aB --synth=no -e ibs_op/swfilt/k -o /dev/null true -if [ $? -ne 0 ]; then - echo "[FAIL] IBS op PMU cannot handle swfilt in system-wide mode" - exit 1 +if ! ParanoidAndNotRoot 0 +then + perf record -aB --synth=no -e ibs_op/swfilt/k -o /dev/null true + if [ $? -ne 0 ]; then + echo "[FAIL] IBS op PMU cannot handle swfilt in system-wide mode" + exit 1 + fi +else + echo "[SKIP] not root and perf_event_paranoid too high for system-wide/exclude_user" + err=2 fi echo "check number of samples with swfilt" @@ -60,8 +77,16 @@ if [ ${kernel_sample} -ne 0 ]; then exit 1 fi -user_sample=$(perf record -e ibs_fetch/swfilt/k -o- true | perf script -i- -F misc | grep -c ^U) -if [ ${user_sample} -ne 0 ]; then - echo "[FAIL] unexpected user samples: " ${user_sample} - exit 1 +if ! ParanoidAndNotRoot 1 +then + user_sample=$(perf record -e ibs_fetch/swfilt/k -o- true | perf script -i- -F misc | grep -c ^U) + if [ ${user_sample} -ne 0 ]; then + echo "[FAIL] unexpected user samples: " ${user_sample} + exit 1 + fi +else + echo "[SKIP] not root and perf_event_paranoid too high for exclude_user" + err=2 fi + +exit $err From 8c6d842302f3d070a5f41c296f1668fd69dae468 Mon Sep 17 00:00:00 2001 From: Zecheng Li Date: Mon, 25 Aug 2025 19:54:04 +0000 Subject: [PATCH 1735/2711] perf dwarf-aux: More accurate variable type match for breg Introduces the function is_breg_access_indirect to determine whether a memory access involving a DW_OP_breg* operation refers to the variable's value directly or requires dereferencing the variable's type as a pointer based on the DWARF expression. Previously, all breg based accesses were assumed to directly access the variable's value (is_pointer = false). The is_breg_access_indirect function handles three cases: 1. Base register + offset only: (e.g., DW_OP_breg7 RSP+88) The calculated address is the location of the variable. The access is direct, so no type dereference is needed. Returns false. 2. Base register + offset, followed by other operations ending in DW_OP_stack_value, including DW_OP_deref: (e.g., DW_OP_breg*, DW_OP_deref, DW_OP_stack_value) The DWARF expression computes the variable's value, but that value requires a dereference. The memory access is fetching that value, so no type dereference is needed. Returns false. 3. Base register + offset, followed only by DW_OP_stack_value: (e.g., DW_OP_breg13 R13+256, DW_OP_stack_value) This indicates the value at the base + offset is the variable's value. Since this value is being used as an address in the memory access, the variable's type is treated as a pointer and requires a type dereference. Returns true. The is_pointer argument passed to match_var_offset is now set by is_breg_access_indirect for breg accesses. There are more complex expressions that includes multiple operations and may require additional handling, such as DW_OP_deref without a DW_OP_stack_value, or including multiple base registers. They are less common in the Linux kernel dwarf and are skipped in check_allowed_ops. Reviewed-by: Namhyung Kim Signed-off-by: Zecheng Li Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Xu Liu Link: https://lore.kernel.org/r/CAJUgMyK2wTiEZB__dtgCELmaNGFWhG1j0g9rv_C=cLD6Zq4_5w@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 38 ++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 920054425578..449bc9ad7aff 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1423,6 +1423,34 @@ static bool match_var_offset(Dwarf_Die *die_mem, struct find_var_data *data, return true; } +/** + * is_breg_access_indirect - Check if breg based access implies type + * dereference + * @ops: DWARF operations array + * @nops: Number of operations in @ops + * + * Returns true if the DWARF expression evaluates to the variable's + * value, so the memory access on that register needs type dereference. + * Returns false if the expression evaluates to the variable's address. + * This is called after check_allowed_ops. + */ +static bool is_breg_access_indirect(Dwarf_Op *ops, size_t nops) +{ + /* only the base register */ + if (nops == 1) + return false; + + if (nops == 2 && ops[1].atom == DW_OP_stack_value) + return true; + + if (nops == 3 && (ops[1].atom == DW_OP_deref || + ops[1].atom == DW_OP_deref_size) && + ops[2].atom == DW_OP_stack_value) + return false; + /* unreachable, OP not supported */ + return false; +} + /* Only checks direct child DIEs in the given scope. */ static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg) { @@ -1451,7 +1479,7 @@ static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg) if (data->is_fbreg && ops->atom == DW_OP_fbreg && check_allowed_ops(ops, nops) && match_var_offset(die_mem, data, data->offset, ops->number, - /*is_pointer=*/false)) + is_breg_access_indirect(ops, nops))) return DIE_FIND_CB_END; /* Only match with a simple case */ @@ -1463,11 +1491,11 @@ static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg) /*is_pointer=*/true)) return DIE_FIND_CB_END; - /* Local variables accessed by a register + offset */ + /* variables accessed by a register + offset */ if (ops->atom == (DW_OP_breg0 + data->reg) && check_allowed_ops(ops, nops) && match_var_offset(die_mem, data, data->offset, ops->number, - /*is_pointer=*/false)) + is_breg_access_indirect(ops, nops))) return DIE_FIND_CB_END; } else { /* pointer variables saved in a register 32 or above */ @@ -1477,11 +1505,11 @@ static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg) /*is_pointer=*/true)) return DIE_FIND_CB_END; - /* Local variables accessed by a register + offset */ + /* variables accessed by a register + offset */ if (ops->atom == DW_OP_bregx && data->reg == ops->number && check_allowed_ops(ops, nops) && match_var_offset(die_mem, data, data->offset, ops->number2, - /*is_poitner=*/false)) + is_breg_access_indirect(ops, nops))) return DIE_FIND_CB_END; } } From 4a6ce9ad20257a9b8fc32994366a24170a3dfa3d Mon Sep 17 00:00:00 2001 From: Zecheng Li Date: Mon, 25 Aug 2025 19:54:05 +0000 Subject: [PATCH 1736/2711] perf dwarf-aux: Better variable collection for insn tracking Utilizes the previous is_breg_access_indirect function to determine if the register + offset stores the variable itself or the struct it points to, save the information in die_var_type.is_reg_var_addr. Since we are storing the real types in the stack state, we need to do a type dereference when is_reg_var_addr is set to false for stack/frame registers. For other gp registers, skip the variable when the register is a pointer to the type. If we want to accept these variables, we might also utilize is_reg_var_addr in a different way, we need to mark that register as a pointer to the type. Reviewed-by: Namhyung Kim Signed-off-by: Zecheng Li Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Xu Liu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 9 +++++++++ tools/perf/util/dwarf-aux.c | 11 ++++++++++- tools/perf/util/dwarf-aux.h | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 1ef2edbc71d9..258157cc43c2 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -868,6 +868,11 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo int offset = var->offset; struct type_state_stack *stack; + /* If the reg location holds the pointer value, dereference the type */ + if (!var->is_reg_var_addr && is_pointer_type(&mem_die) && + __die_get_real_type(&mem_die, &mem_die) == NULL) + continue; + if (var->reg != DWARF_REG_FB) offset -= fb_offset; @@ -893,6 +898,10 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo reg = &state->regs[var->reg]; + /* For gp registers, skip the address registers for now */ + if (var->is_reg_var_addr) + continue; + if (reg->ok && reg->kind == TSR_KIND_TYPE && !is_better_type(®->type, &mem_die)) continue; diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 449bc9ad7aff..6fd2db5d9381 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1627,13 +1627,22 @@ static int __die_collect_vars_cb(Dwarf_Die *die_mem, void *arg) if (!check_allowed_ops(ops, nops)) return DIE_FIND_CB_SIBLING; - if (die_get_real_type(die_mem, &type_die) == NULL) + if (__die_get_real_type(die_mem, &type_die) == NULL) return DIE_FIND_CB_SIBLING; vt = malloc(sizeof(*vt)); if (vt == NULL) return DIE_FIND_CB_END; + /* Usually a register holds the value of a variable */ + vt->is_reg_var_addr = false; + + if (((ops->atom >= DW_OP_breg0 && ops->atom <= DW_OP_breg31) || + ops->atom == DW_OP_bregx || ops->atom == DW_OP_fbreg) && + !is_breg_access_indirect(ops, nops)) + /* The register contains an address of the variable. */ + vt->is_reg_var_addr = true; + vt->die_off = dwarf_dieoffset(&type_die); vt->addr = start; vt->reg = reg_from_dwarf_op(ops); diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 892c8c5c23fc..cd481ec9c5a1 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -148,6 +148,8 @@ struct die_var_type { u64 addr; int reg; int offset; + /* Whether the register holds a address to the type */ + bool is_reg_var_addr; }; /* Return type info of a member at offset */ From e7ace97fcf6d2eb458bd7e16bba8e3f24d396e9b Mon Sep 17 00:00:00 2001 From: Zecheng Li Date: Mon, 25 Aug 2025 19:58:17 +0000 Subject: [PATCH 1737/2711] perf dwarf-aux: Fix __die_find_scope_cb() for namespaces Currently __die_find_scope_cb() goes to check siblings when the DIE doesn't include the given PC. However namespaces don't have a PC and could contain children that have that PC. When we encounter a namespace, we should check both its children and siblings. Reviewed-by: Namhyung Kim Signed-off-by: Zecheng Li Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Xu Liu Link: https://lore.kernel.org/r/20250825195817.226560-1-zecheng@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 6fd2db5d9381..9267af204c7d 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1958,6 +1958,7 @@ struct find_scope_data { static int __die_find_scope_cb(Dwarf_Die *die_mem, void *arg) { struct find_scope_data *data = arg; + int tag = dwarf_tag(die_mem); if (dwarf_haspc(die_mem, data->pc)) { Dwarf_Die *tmp; @@ -1971,6 +1972,14 @@ static int __die_find_scope_cb(Dwarf_Die *die_mem, void *arg) data->nr++; return DIE_FIND_CB_CHILD; } + + /* + * If the DIE doesn't have the PC, we still need to check its children + * and siblings if it's a container like a namespace. + */ + if (tag == DW_TAG_namespace) + return DIE_FIND_CB_CONTINUE; + return DIE_FIND_CB_SIBLING; } From c0e885e92534ae83ff2721332c17022a48d769c7 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Thu, 14 Aug 2025 17:19:08 +0530 Subject: [PATCH 1738/2711] perf tests record: Update testcase to fix usage of affinity for machines with #CPUs > 1K The perf record testcase fails on systems with more than 1K CPUs. Testcase: perf test -vv "PERF_RECORD_* events & perf_sample fields" PERF_RECORD_* events & perf_sample fields : --- start --- test child forked, pid 272482 sched_getaffinity: Invalid argument sched__get_first_possible_cpu: Invalid argument test child finished with -1 ---- end ---- PERF_RECORD_* events & perf_sample fields: FAILED! sched__get_first_possible_cpu uses "sched_getaffinity" to get the cpumask and this call is returning EINVAL (Invalid argument). This happens because the default mask size in glibc is 1024. To overcome this 1024 CPUs mask size limitation of cpu_set_t, change the mask size using the CPU_*_S macros ie, use CPU_ALLOC to allocate cpumask, CPU_ALLOC_SIZE for size. Same fix needed for mask which is used to setaffinity so that mask size is large enough to represent number of possible CPU's in the system. Reported-by: Tejas Manhas Signed-off-by: Athira Rajeev Tested-by: Ian Rogers Tested-by: Tejas Manhas Tested-by: Venkat Rao Bagalkote Acked-by: Namhyung Kim Cc: Aditya Bodkhe Cc: Adrian Hunter Cc: Hari Bathini Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/perf-record.c | 38 ++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 0b3c37e66871..d895df037707 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -13,15 +13,19 @@ #include "tests.h" #include "util/mmap.h" #include "util/sample.h" +#include "util/cpumap.h" static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t *maskp) { - int i, cpu = -1, nrcpus = 1024; -realloc: - CPU_ZERO(maskp); + int i, cpu = -1; + int nrcpus = cpu__max_cpu().cpu; + size_t size = CPU_ALLOC_SIZE(nrcpus); - if (sched_getaffinity(pid, sizeof(*maskp), maskp) == -1) { - if (errno == EINVAL && nrcpus < (1024 << 8)) { +realloc: + CPU_ZERO_S(size, maskp); + + if (sched_getaffinity(pid, size, maskp) == -1) { + if (errno == EINVAL && nrcpus < (cpu__max_cpu().cpu << 8)) { nrcpus = nrcpus << 2; goto realloc; } @@ -30,11 +34,11 @@ realloc: } for (i = 0; i < nrcpus; i++) { - if (CPU_ISSET(i, maskp)) { + if (CPU_ISSET_S(i, size, maskp)) { if (cpu == -1) cpu = i; else - CPU_CLR(i, maskp); + CPU_CLR_S(i, size, maskp); } } @@ -50,8 +54,9 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest .no_buffering = true, .mmap_pages = 256, }; - cpu_set_t cpu_mask; - size_t cpu_mask_size = sizeof(cpu_mask); + int nrcpus = cpu__max_cpu().cpu; + cpu_set_t *cpu_mask; + size_t cpu_mask_size; struct evlist *evlist = evlist__new_dummy(); struct evsel *evsel; struct perf_sample sample; @@ -69,12 +74,22 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; char sbuf[STRERR_BUFSIZE]; + cpu_mask = CPU_ALLOC(nrcpus); + if (!cpu_mask) { + pr_debug("failed to create cpumask\n"); + goto out; + } + + cpu_mask_size = CPU_ALLOC_SIZE(nrcpus); + CPU_ZERO_S(cpu_mask_size, cpu_mask); + perf_sample__init(&sample, /*all=*/false); if (evlist == NULL) /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */ evlist = evlist__new_default(); if (evlist == NULL) { pr_debug("Not enough memory to create evlist\n"); + CPU_FREE(cpu_mask); goto out; } @@ -111,7 +126,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest evsel__set_sample_bit(evsel, TIME); evlist__config(evlist, &opts, NULL); - err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); + err = sched__get_first_possible_cpu(evlist->workload.pid, cpu_mask); if (err < 0) { pr_debug("sched__get_first_possible_cpu: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); @@ -123,7 +138,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest /* * So that we can check perf_sample.cpu on all the samples. */ - if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { + if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) { pr_debug("sched_setaffinity: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; @@ -328,6 +343,7 @@ found_exit: ++errs; } out_delete_evlist: + CPU_FREE(cpu_mask); evlist__delete(evlist); out: perf_sample__exit(&sample); From 817af72c05c8adfc5b5c8c772e237a2ac85b25f5 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 5 Aug 2025 11:03:49 +0200 Subject: [PATCH 1739/2711] perf tools: Update header documentation on BPF_PROG_INFO Update the perf.data file format description on header section HEADER_BPF_PROG_INFO. The information is taken from process_bpf_prog_info() and write_bpf_prog_info() from file util/header.c. Reviewed-by: Jan Polensky Signed-off-by: Thomas Richter Acked-by: Namhyung Kim Acked-by: Sumanth Korikkar Cc: Alexander Gordeev Cc: Heiko Carstens Cc: Vasily Gorbik Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf.data-file-format.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt index cd95ba09f727..c9d4dec65344 100644 --- a/tools/perf/Documentation/perf.data-file-format.txt +++ b/tools/perf/Documentation/perf.data-file-format.txt @@ -348,6 +348,16 @@ to special needs. struct perf_bpil, which contains detailed information about a BPF program, including type, id, tag, jited/xlated instructions, etc. +The format of data in HEADER_BPF_PROG_INFO is as follows: + u32 count + + struct perf_bpil { + u32 info_len; /* size of struct bpf_prog_info, when the tool is compiled */ + u32 data_len; /* total bytes allocated for data, round up to 8 bytes */ + u64 arrays; /* which arrays are included in data */ + struct bpf_prog_info info; + u8 data[]; + }[count]; HEADER_BPF_BTF = 26, From 98dbed7aee7f8fd664927a6eea5fce15663be198 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 8 Aug 2025 15:26:50 -0700 Subject: [PATCH 1740/2711] perf tools: Remove a pointless check Static analyser cppcheck says: linux-6.16/tools/perf/util/tool_pmu.c:242:15: warning: Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition] Source code is: for (thread = 0; thread < nthreads; thread++) { if (thread >= nthreads) break; Reported-by: David Binderman Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/tool_pmu.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/perf/util/tool_pmu.c b/tools/perf/util/tool_pmu.c index d99e699e646d..f075098488ba 100644 --- a/tools/perf/util/tool_pmu.c +++ b/tools/perf/util/tool_pmu.c @@ -239,9 +239,6 @@ int evsel__tool_pmu_open(struct evsel *evsel, nthreads = perf_thread_map__nr(threads); for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) { for (thread = 0; thread < nthreads; thread++) { - if (thread >= nthreads) - break; - if (!evsel->cgrp && !evsel->core.system_wide) pid = perf_thread_map__pid(threads, thread); From 48314d20fe467d6653783cbf5536cb2fcc9bdd7c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 21 Aug 2025 15:18:31 -0700 Subject: [PATCH 1741/2711] perf test shell lbr: Avoid failures with perf event paranoia When not running as root and with higher perf event paranoia values the perf record LBR tests could fail rather than skipping the problematic tests. Add the sensitivity to the test and confirm it passes with paranoia values from -1 to 2. Committer testing: Testing with '$ perf test -vv lbr', i.e. as non root, and then comparing the output shows the mentioned errors before this patch: acme@x1:~$ grep -m1 "model name" /proc/cpuinfo model name : 13th Gen Intel(R) Core(TM) i7-1365U acme@x1:~$ Before: 132: perf record LBR tests : Skip After: 132: perf record LBR tests : Ok Fixes: 32559b99e0f59070 ("perf test: Add set of perf record LBR tests") Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Chun-Tse Shao Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/record_lbr.sh | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tools/perf/tests/shell/record_lbr.sh b/tools/perf/tests/shell/record_lbr.sh index 6fcb5e52b9b4..78a02e90ece1 100755 --- a/tools/perf/tests/shell/record_lbr.sh +++ b/tools/perf/tests/shell/record_lbr.sh @@ -4,6 +4,10 @@ set -e +ParanoidAndNotRoot() { + [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] +} + if [ ! -f /sys/bus/event_source/devices/cpu/caps/branches ] && [ ! -f /sys/bus/event_source/devices/cpu_core/caps/branches ] then @@ -23,6 +27,7 @@ cleanup() { } trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" cleanup exit 1 } @@ -123,8 +128,11 @@ lbr_test "-j ind_call" "any indirect call" 2 lbr_test "-j ind_jmp" "any indirect jump" 100 lbr_test "-j call" "direct calls" 2 lbr_test "-j ind_call,u" "any indirect user call" 100 -lbr_test "-a -b" "system wide any branch" 2 -lbr_test "-a -j any_call" "system wide any call" 2 +if ! ParanoidAndNotRoot 1 +then + lbr_test "-a -b" "system wide any branch" 2 + lbr_test "-a -j any_call" "system wide any call" 2 +fi # Parallel parallel_lbr_test "-b" "parallel any branch" 100 & @@ -141,10 +149,16 @@ parallel_lbr_test "-j call" "parallel direct calls" 100 & pid6=$! parallel_lbr_test "-j ind_call,u" "parallel any indirect user call" 100 & pid7=$! -parallel_lbr_test "-a -b" "parallel system wide any branch" 100 & -pid8=$! -parallel_lbr_test "-a -j any_call" "parallel system wide any call" 100 & -pid9=$! +if ParanoidAndNotRoot 1 +then + pid8= + pid9= +else + parallel_lbr_test "-a -b" "parallel system wide any branch" 100 & + pid8=$! + parallel_lbr_test "-a -j any_call" "parallel system wide any call" 100 & + pid9=$! +fi for pid in $pid1 $pid2 $pid3 $pid4 $pid5 $pid6 $pid7 $pid8 $pid9 do From 0e9e7bc14e8f7a3b4193a8e3febb9e1e92051bd3 Mon Sep 17 00:00:00 2001 From: Trevor Allison Date: Tue, 16 Sep 2025 15:30:46 -0400 Subject: [PATCH 1742/2711] perf test attr: Add missing int_mist.uop_dropping event to test-stat files Setup 'struct perf_event_attr' test was failing on EMR cpu because 'perf stat' was providing an event that was not included in the test. Type 4 Config 4269 or 10ad, int_misc.uop_dropping. Add event type=4 config=4269 to test-stat-default and test-stat-detailed-* files with optional=1 so EMR (Emerald Rapids) machines can pass the test. Fixes: d9a6bb9e359e6f81 ("perf vendor events: Update emeraldrapids events/metrics") Reviewed-by: Ian Rogers Signed-off-by: Trevor Allison Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/attr/test-stat-default | 7 +++++++ tools/perf/tests/shell/attr/test-stat-detailed-1 | 7 +++++++ tools/perf/tests/shell/attr/test-stat-detailed-2 | 7 +++++++ tools/perf/tests/shell/attr/test-stat-detailed-3 | 7 +++++++ 4 files changed, 28 insertions(+) diff --git a/tools/perf/tests/shell/attr/test-stat-default b/tools/perf/tests/shell/attr/test-stat-default index e47fb4944679..8dd27c1fb661 100644 --- a/tools/perf/tests/shell/attr/test-stat-default +++ b/tools/perf/tests/shell/attr/test-stat-default @@ -227,3 +227,10 @@ fd=28 type=4 config=270 optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event29:base-stat] +fd=29 +type=4 +config=4269 +optional=1 \ No newline at end of file diff --git a/tools/perf/tests/shell/attr/test-stat-detailed-1 b/tools/perf/tests/shell/attr/test-stat-detailed-1 index 3d500d3e0c5c..12a2ebf4e64a 100644 --- a/tools/perf/tests/shell/attr/test-stat-detailed-1 +++ b/tools/perf/tests/shell/attr/test-stat-detailed-1 @@ -269,3 +269,10 @@ fd=32 type=3 config=65538 optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event33:base-stat] +fd=33 +type=4 +config=4269 +optional=1 \ No newline at end of file diff --git a/tools/perf/tests/shell/attr/test-stat-detailed-2 b/tools/perf/tests/shell/attr/test-stat-detailed-2 index 01777a63752f..66ea25b7d38f 100644 --- a/tools/perf/tests/shell/attr/test-stat-detailed-2 +++ b/tools/perf/tests/shell/attr/test-stat-detailed-2 @@ -329,3 +329,10 @@ fd=38 type=3 config=65540 optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event39:base-stat] +fd=39 +type=4 +config=4269 +optional=1 \ No newline at end of file diff --git a/tools/perf/tests/shell/attr/test-stat-detailed-3 b/tools/perf/tests/shell/attr/test-stat-detailed-3 index 8400abd7e1e4..4a27bbfb9f87 100644 --- a/tools/perf/tests/shell/attr/test-stat-detailed-3 +++ b/tools/perf/tests/shell/attr/test-stat-detailed-3 @@ -349,3 +349,10 @@ fd=40 type=3 config=66048 optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event41:base-stat] +fd=41 +type=4 +config=4269 +optional=1 \ No newline at end of file From b0f4ade163e551d0c470ead7ac57eaf373eec71a Mon Sep 17 00:00:00 2001 From: Fushuai Wang Date: Wed, 17 Sep 2025 17:54:22 +0800 Subject: [PATCH 1743/2711] perf trace: Fix IS_ERR() vs NULL check bug The alloc_syscall_stats() function always returns an error pointer (ERR_PTR) on failure. So replace NULL check with IS_ERR() check after calling alloc_syscall_stats() function. Fixes: fc00897c8a3f7f57 ("perf trace: Add --summary-mode option") Reviewed-by: Ian Rogers Signed-off-by: Fushuai Wang Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 5f54777d8ba0..c607f39b8c8b 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -4441,7 +4441,7 @@ create_maps: if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) { trace->syscall_stats = alloc_syscall_stats(); - if (trace->syscall_stats == NULL) + if (IS_ERR(trace->syscall_stats)) goto out_delete_evlist; } @@ -4749,7 +4749,7 @@ static int trace__replay(struct trace *trace) if (trace->summary_mode == SUMMARY__BY_TOTAL) { trace->syscall_stats = alloc_syscall_stats(); - if (trace->syscall_stats == NULL) + if (IS_ERR(trace->syscall_stats)) goto out; } From 79a0194f2f28abca7a17c37d5384762355d17c26 Mon Sep 17 00:00:00 2001 From: Ankur Arora Date: Wed, 17 Sep 2025 08:24:03 -0700 Subject: [PATCH 1744/2711] perf bench mem: Remove repetition around time measurement We have two copies of each mem benchmark: one using cycles to measure time, the second for gettimeofday(). Unify. Reviewed-by: Namhyung Kim Signed-off-by: Ankur Arora Cc: Andrew Morton Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Dave Hansen Cc: David Hildenbrand Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Konrad Rzeszutek Wilk Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Peter Zijlstra Cc: Raghavendra K T Cc: Thomas Gleixner Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-functions.c | 110 +++++++++++++------------------ 1 file changed, 46 insertions(+), 64 deletions(-) diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 19d45c377ac1..8599ed96ee1f 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -51,6 +51,11 @@ static const struct option options[] = { OPT_END() }; +union bench_clock { + u64 cycles; + struct timeval tv; +}; + typedef void *(*memcpy_t)(void *, const void *, size_t); typedef void *(*memset_t)(void *, int, size_t); @@ -91,6 +96,26 @@ static u64 get_cycles(void) return clk; } +static void clock_get(union bench_clock *t) +{ + if (use_cycles) + t->cycles = get_cycles(); + else + BUG_ON(gettimeofday(&t->tv, NULL)); +} + +static union bench_clock clock_diff(union bench_clock *s, union bench_clock *e) +{ + union bench_clock t; + + if (use_cycles) + t.cycles = e->cycles - s->cycles; + else + timersub(&e->tv, &s->tv, &t.tv); + + return t; +} + static double timeval2double(struct timeval *ts) { return (double)ts->tv_sec + (double)ts->tv_usec / (double)USEC_PER_SEC; @@ -109,8 +134,7 @@ static double timeval2double(struct timeval *ts) struct bench_mem_info { const struct function *functions; - u64 (*do_cycles)(const struct function *r, size_t size, void *src, void *dst); - double (*do_gettimeofday)(const struct function *r, size_t size, void *src, void *dst); + union bench_clock (*do_op)(const struct function *r, size_t size, void *src, void *dst); const char *const *usage; bool alloc_src; }; @@ -119,7 +143,7 @@ static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t { const struct function *r = &info->functions[r_idx]; double result_bps = 0.0; - u64 result_cycles = 0; + union bench_clock rt = { 0 }; void *src = NULL, *dst = zalloc(size); printf("# function '%s' (%s)\n", r->name, r->desc); @@ -136,25 +160,23 @@ static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t if (bench_format == BENCH_FORMAT_DEFAULT) printf("# Copying %s bytes ...\n\n", size_str); - if (use_cycles) { - result_cycles = info->do_cycles(r, size, src, dst); - } else { - result_bps = info->do_gettimeofday(r, size, src, dst); - } + rt = info->do_op(r, size, src, dst); switch (bench_format) { case BENCH_FORMAT_DEFAULT: if (use_cycles) { - printf(" %14lf cycles/byte\n", (double)result_cycles/size_total); + printf(" %14lf cycles/byte\n", (double)rt.cycles/size_total); } else { + result_bps = size_total/timeval2double(&rt.tv); print_bps(result_bps); } break; case BENCH_FORMAT_SIMPLE: if (use_cycles) { - printf("%lf\n", (double)result_cycles/size_total); + printf("%lf\n", (double)rt.cycles/size_total); } else { + result_bps = size_total/timeval2double(&rt.tv); printf("%lf\n", result_bps); } break; @@ -235,38 +257,21 @@ static void memcpy_prefault(memcpy_t fn, size_t size, void *src, void *dst) fn(dst, src, size); } -static u64 do_memcpy_cycles(const struct function *r, size_t size, void *src, void *dst) +static union bench_clock do_memcpy(const struct function *r, size_t size, + void *src, void *dst) { - u64 cycle_start = 0ULL, cycle_end = 0ULL; + union bench_clock start, end; memcpy_t fn = r->fn.memcpy; int i; memcpy_prefault(fn, size, src, dst); - cycle_start = get_cycles(); + clock_get(&start); for (i = 0; i < nr_loops; ++i) fn(dst, src, size); - cycle_end = get_cycles(); + clock_get(&end); - return cycle_end - cycle_start; -} - -static double do_memcpy_gettimeofday(const struct function *r, size_t size, void *src, void *dst) -{ - struct timeval tv_start, tv_end, tv_diff; - memcpy_t fn = r->fn.memcpy; - int i; - - memcpy_prefault(fn, size, src, dst); - - BUG_ON(gettimeofday(&tv_start, NULL)); - for (i = 0; i < nr_loops; ++i) - fn(dst, src, size); - BUG_ON(gettimeofday(&tv_end, NULL)); - - timersub(&tv_end, &tv_start, &tv_diff); - - return (double)(((double)size * nr_loops) / timeval2double(&tv_diff)); + return clock_diff(&start, &end); } struct function memcpy_functions[] = { @@ -292,8 +297,7 @@ int bench_mem_memcpy(int argc, const char **argv) { struct bench_mem_info info = { .functions = memcpy_functions, - .do_cycles = do_memcpy_cycles, - .do_gettimeofday = do_memcpy_gettimeofday, + .do_op = do_memcpy, .usage = bench_mem_memcpy_usage, .alloc_src = true, }; @@ -301,9 +305,10 @@ int bench_mem_memcpy(int argc, const char **argv) return bench_mem_common(argc, argv, &info); } -static u64 do_memset_cycles(const struct function *r, size_t size, void *src __maybe_unused, void *dst) +static union bench_clock do_memset(const struct function *r, size_t size, + void *src __maybe_unused, void *dst) { - u64 cycle_start = 0ULL, cycle_end = 0ULL; + union bench_clock start, end; memset_t fn = r->fn.memset; int i; @@ -313,34 +318,12 @@ static u64 do_memset_cycles(const struct function *r, size_t size, void *src __m */ fn(dst, -1, size); - cycle_start = get_cycles(); + clock_get(&start); for (i = 0; i < nr_loops; ++i) fn(dst, i, size); - cycle_end = get_cycles(); + clock_get(&end); - return cycle_end - cycle_start; -} - -static double do_memset_gettimeofday(const struct function *r, size_t size, void *src __maybe_unused, void *dst) -{ - struct timeval tv_start, tv_end, tv_diff; - memset_t fn = r->fn.memset; - int i; - - /* - * We prefault the freshly allocated memory range here, - * to not measure page fault overhead: - */ - fn(dst, -1, size); - - BUG_ON(gettimeofday(&tv_start, NULL)); - for (i = 0; i < nr_loops; ++i) - fn(dst, i, size); - BUG_ON(gettimeofday(&tv_end, NULL)); - - timersub(&tv_end, &tv_start, &tv_diff); - - return (double)(((double)size * nr_loops) / timeval2double(&tv_diff)); + return clock_diff(&start, &end); } static const char * const bench_mem_memset_usage[] = { @@ -366,8 +349,7 @@ int bench_mem_memset(int argc, const char **argv) { struct bench_mem_info info = { .functions = memset_functions, - .do_cycles = do_memset_cycles, - .do_gettimeofday = do_memset_gettimeofday, + .do_op = do_memset, .usage = bench_mem_memset_usage, }; From 07e257245d5ee0c5393ae2fe8c7fc18071c5a637 Mon Sep 17 00:00:00 2001 From: Ankur Arora Date: Wed, 17 Sep 2025 08:24:04 -0700 Subject: [PATCH 1745/2711] perf bench mem: Defer type munging of size to float Do type conversion to double at the point of use. Reviewed-by: Namhyung Kim Signed-off-by: Ankur Arora Cc: Andrew Morton Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Dave Hansen Cc: David Hildenbrand Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Konrad Rzeszutek Wilk Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Peter Zijlstra Cc: Raghavendra K T Cc: Thomas Gleixner Link: https://lore.kernel.org/r/20250917152418.4077386-3-ankur.a.arora@oracle.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-functions.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 8599ed96ee1f..fddb2acd2d3a 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -139,7 +139,7 @@ struct bench_mem_info { bool alloc_src; }; -static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t size, double size_total) +static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t size, size_t size_total) { const struct function *r = &info->functions[r_idx]; double result_bps = 0.0; @@ -165,18 +165,18 @@ static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t switch (bench_format) { case BENCH_FORMAT_DEFAULT: if (use_cycles) { - printf(" %14lf cycles/byte\n", (double)rt.cycles/size_total); + printf(" %14lf cycles/byte\n", (double)rt.cycles/(double)size_total); } else { - result_bps = size_total/timeval2double(&rt.tv); + result_bps = (double)size_total/timeval2double(&rt.tv); print_bps(result_bps); } break; case BENCH_FORMAT_SIMPLE: if (use_cycles) { - printf("%lf\n", (double)rt.cycles/size_total); + printf("%lf\n", (double)rt.cycles/(double)size_total); } else { - result_bps = size_total/timeval2double(&rt.tv); + result_bps = (double)size_total/timeval2double(&rt.tv); printf("%lf\n", result_bps); } break; @@ -199,7 +199,7 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * { int i; size_t size; - double size_total; + size_t size_total; argc = parse_options(argc, argv, options, info->usage, 0); @@ -212,7 +212,7 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * } size = (size_t)perf_atoll((char *)size_str); - size_total = (double)size * nr_loops; + size_total = size * nr_loops; if ((s64)size <= 0) { fprintf(stderr, "Invalid size:%s\n", size_str); From dbf5dad1540e28bddde701268beb77beadb58321 Mon Sep 17 00:00:00 2001 From: Ankur Arora Date: Wed, 17 Sep 2025 08:24:05 -0700 Subject: [PATCH 1746/2711] perf bench mem: Move mem op parameters into a structure Move benchmark function parameters in struct bench_params. Reviewed-by: Namhyung Kim Signed-off-by: Ankur Arora Cc: Andrew Morton Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Dave Hansen Cc: David Hildenbrand Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Konrad Rzeszutek Wilk Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Peter Zijlstra Cc: Raghavendra K T Cc: Thomas Gleixner Link: https://lore.kernel.org/r/20250917152418.4077386-4-ankur.a.arora@oracle.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-functions.c | 62 +++++++++++++++++--------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index fddb2acd2d3a..4d723774c1b3 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -30,7 +30,7 @@ static const char *size_str = "1MB"; static const char *function_str = "all"; -static int nr_loops = 1; +static unsigned int nr_loops = 1; static bool use_cycles; static int cycles_fd; @@ -42,7 +42,7 @@ static const struct option options[] = { OPT_STRING('f', "function", &function_str, "all", "Specify the function to run, \"all\" runs all available functions, \"help\" lists them"), - OPT_INTEGER('l', "nr_loops", &nr_loops, + OPT_UINTEGER('l', "nr_loops", &nr_loops, "Specify the number of loops to run. (default: 1)"), OPT_BOOLEAN('c', "cycles", &use_cycles, @@ -56,6 +56,12 @@ union bench_clock { struct timeval tv; }; +struct bench_params { + size_t size; + size_t size_total; + unsigned int nr_loops; +}; + typedef void *(*memcpy_t)(void *, const void *, size_t); typedef void *(*memset_t)(void *, int, size_t); @@ -134,17 +140,19 @@ static double timeval2double(struct timeval *ts) struct bench_mem_info { const struct function *functions; - union bench_clock (*do_op)(const struct function *r, size_t size, void *src, void *dst); + union bench_clock (*do_op)(const struct function *r, struct bench_params *p, + void *src, void *dst); const char *const *usage; bool alloc_src; }; -static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t size, size_t size_total) +static void __bench_mem_function(struct bench_mem_info *info, struct bench_params *p, + int r_idx) { const struct function *r = &info->functions[r_idx]; double result_bps = 0.0; union bench_clock rt = { 0 }; - void *src = NULL, *dst = zalloc(size); + void *src = NULL, *dst = zalloc(p->size); printf("# function '%s' (%s)\n", r->name, r->desc); @@ -152,7 +160,7 @@ static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t goto out_alloc_failed; if (info->alloc_src) { - src = zalloc(size); + src = zalloc(p->size); if (src == NULL) goto out_alloc_failed; } @@ -160,23 +168,23 @@ static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t if (bench_format == BENCH_FORMAT_DEFAULT) printf("# Copying %s bytes ...\n\n", size_str); - rt = info->do_op(r, size, src, dst); + rt = info->do_op(r, p, src, dst); switch (bench_format) { case BENCH_FORMAT_DEFAULT: if (use_cycles) { - printf(" %14lf cycles/byte\n", (double)rt.cycles/(double)size_total); + printf(" %14lf cycles/byte\n", (double)rt.cycles/(double)p->size_total); } else { - result_bps = (double)size_total/timeval2double(&rt.tv); + result_bps = (double)p->size_total/timeval2double(&rt.tv); print_bps(result_bps); } break; case BENCH_FORMAT_SIMPLE: if (use_cycles) { - printf("%lf\n", (double)rt.cycles/(double)size_total); + printf("%lf\n", (double)rt.cycles/(double)p->size_total); } else { - result_bps = (double)size_total/timeval2double(&rt.tv); + result_bps = (double)p->size_total/timeval2double(&rt.tv); printf("%lf\n", result_bps); } break; @@ -198,8 +206,7 @@ out_alloc_failed: static int bench_mem_common(int argc, const char **argv, struct bench_mem_info *info) { int i; - size_t size; - size_t size_total; + struct bench_params p = { 0 }; argc = parse_options(argc, argv, options, info->usage, 0); @@ -211,17 +218,18 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * } } - size = (size_t)perf_atoll((char *)size_str); - size_total = size * nr_loops; + p.nr_loops = nr_loops; + p.size = (size_t)perf_atoll((char *)size_str); - if ((s64)size <= 0) { + if ((s64)p.size <= 0) { fprintf(stderr, "Invalid size:%s\n", size_str); return 1; } + p.size_total = p.size * p.nr_loops; if (!strncmp(function_str, "all", 3)) { for (i = 0; info->functions[i].name; i++) - __bench_mem_function(info, i, size, size_total); + __bench_mem_function(info, &p, i); return 0; } @@ -240,7 +248,7 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * return 1; } - __bench_mem_function(info, i, size, size_total); + __bench_mem_function(info, &p, i); return 0; } @@ -257,18 +265,17 @@ static void memcpy_prefault(memcpy_t fn, size_t size, void *src, void *dst) fn(dst, src, size); } -static union bench_clock do_memcpy(const struct function *r, size_t size, +static union bench_clock do_memcpy(const struct function *r, struct bench_params *p, void *src, void *dst) { union bench_clock start, end; memcpy_t fn = r->fn.memcpy; - int i; - memcpy_prefault(fn, size, src, dst); + memcpy_prefault(fn, p->size, src, dst); clock_get(&start); - for (i = 0; i < nr_loops; ++i) - fn(dst, src, size); + for (unsigned int i = 0; i < p->nr_loops; ++i) + fn(dst, src, p->size); clock_get(&end); return clock_diff(&start, &end); @@ -305,22 +312,21 @@ int bench_mem_memcpy(int argc, const char **argv) return bench_mem_common(argc, argv, &info); } -static union bench_clock do_memset(const struct function *r, size_t size, +static union bench_clock do_memset(const struct function *r, struct bench_params *p, void *src __maybe_unused, void *dst) { union bench_clock start, end; memset_t fn = r->fn.memset; - int i; /* * We prefault the freshly allocated memory range here, * to not measure page fault overhead: */ - fn(dst, -1, size); + fn(dst, -1, p->size); clock_get(&start); - for (i = 0; i < nr_loops; ++i) - fn(dst, i, size); + for (unsigned int i = 0; i < p->nr_loops; ++i) + fn(dst, i, p->size); clock_get(&end); return clock_diff(&start, &end); From bdc22a83dc2a2f1ecfc4cdd8e605d6c075b3dd82 Mon Sep 17 00:00:00 2001 From: Ankur Arora Date: Wed, 17 Sep 2025 08:24:06 -0700 Subject: [PATCH 1747/2711] perf bench mem: Pull out init/fini logic No functional change. Reviewed-by: Namhyung Kim Signed-off-by: Ankur Arora Cc: Andrew Morton Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Dave Hansen Cc: David Hildenbrand Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Konrad Rzeszutek Wilk Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Peter Zijlstra Cc: Raghavendra K T Cc: Thomas Gleixner Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-functions.c | 103 +++++++++++++------ tools/perf/bench/mem-memcpy-arch.h | 2 +- tools/perf/bench/mem-memcpy-x86-64-asm-def.h | 4 + tools/perf/bench/mem-memset-arch.h | 2 +- tools/perf/bench/mem-memset-x86-64-asm-def.h | 4 + 5 files changed, 81 insertions(+), 34 deletions(-) diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 4d723774c1b3..60ea20277507 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -62,15 +62,31 @@ struct bench_params { unsigned int nr_loops; }; +struct bench_mem_info { + const struct function *functions; + int (*do_op)(const struct function *r, struct bench_params *p, + void *src, void *dst, union bench_clock *rt); + const char *const *usage; + bool alloc_src; +}; + +typedef bool (*mem_init_t)(struct bench_mem_info *, struct bench_params *, + void **, void **); +typedef void (*mem_fini_t)(struct bench_mem_info *, struct bench_params *, + void **, void **); typedef void *(*memcpy_t)(void *, const void *, size_t); typedef void *(*memset_t)(void *, int, size_t); struct function { const char *name; const char *desc; - union { - memcpy_t memcpy; - memset_t memset; + struct { + mem_init_t init; + mem_fini_t fini; + union { + memcpy_t memcpy; + memset_t memset; + }; } fn; }; @@ -138,37 +154,24 @@ static double timeval2double(struct timeval *ts) printf(" %14lf GB/sec\n", x / K / K / K); \ } while (0) -struct bench_mem_info { - const struct function *functions; - union bench_clock (*do_op)(const struct function *r, struct bench_params *p, - void *src, void *dst); - const char *const *usage; - bool alloc_src; -}; - static void __bench_mem_function(struct bench_mem_info *info, struct bench_params *p, int r_idx) { const struct function *r = &info->functions[r_idx]; double result_bps = 0.0; union bench_clock rt = { 0 }; - void *src = NULL, *dst = zalloc(p->size); + void *src = NULL, *dst = NULL; printf("# function '%s' (%s)\n", r->name, r->desc); - if (dst == NULL) - goto out_alloc_failed; - - if (info->alloc_src) { - src = zalloc(p->size); - if (src == NULL) - goto out_alloc_failed; - } + if (r->fn.init && r->fn.init(info, p, &src, &dst)) + goto out_init_failed; if (bench_format == BENCH_FORMAT_DEFAULT) printf("# Copying %s bytes ...\n\n", size_str); - rt = info->do_op(r, p, src, dst); + if (info->do_op(r, p, src, dst, &rt)) + goto out_test_failed; switch (bench_format) { case BENCH_FORMAT_DEFAULT: @@ -194,11 +197,11 @@ static void __bench_mem_function(struct bench_mem_info *info, struct bench_param break; } +out_test_failed: out_free: - free(src); - free(dst); + if (r->fn.fini) r->fn.fini(info, p, &src, &dst); return; -out_alloc_failed: +out_init_failed: printf("# Memory allocation failed - maybe size (%s) is too large?\n", size_str); goto out_free; } @@ -265,8 +268,8 @@ static void memcpy_prefault(memcpy_t fn, size_t size, void *src, void *dst) fn(dst, src, size); } -static union bench_clock do_memcpy(const struct function *r, struct bench_params *p, - void *src, void *dst) +static int do_memcpy(const struct function *r, struct bench_params *p, + void *src, void *dst, union bench_clock *rt) { union bench_clock start, end; memcpy_t fn = r->fn.memcpy; @@ -278,16 +281,47 @@ static union bench_clock do_memcpy(const struct function *r, struct bench_params fn(dst, src, p->size); clock_get(&end); - return clock_diff(&start, &end); + *rt = clock_diff(&start, &end); + + return 0; +} + +static bool mem_alloc(struct bench_mem_info *info, struct bench_params *p, + void **src, void **dst) +{ + bool failed; + + *dst = zalloc(p->size); + failed = *dst == NULL; + + if (info->alloc_src) { + *src = zalloc(p->size); + failed = failed || *src == NULL; + } + + return failed; +} + +static void mem_free(struct bench_mem_info *info __maybe_unused, + struct bench_params *p __maybe_unused, + void **src, void **dst) +{ + free(*dst); + free(*src); + + *dst = *src = NULL; } struct function memcpy_functions[] = { { .name = "default", .desc = "Default memcpy() provided by glibc", + .fn.init = mem_alloc, + .fn.fini = mem_free, .fn.memcpy = memcpy }, #ifdef HAVE_ARCH_X86_64_SUPPORT -# define MEMCPY_FN(_fn, _name, _desc) {.name = _name, .desc = _desc, .fn.memcpy = _fn}, +# define MEMCPY_FN(_fn, _init, _fini, _name, _desc) \ + {.name = _name, .desc = _desc, .fn.memcpy = _fn, .fn.init = _init, .fn.fini = _fini }, # include "mem-memcpy-x86-64-asm-def.h" # undef MEMCPY_FN #endif @@ -312,8 +346,8 @@ int bench_mem_memcpy(int argc, const char **argv) return bench_mem_common(argc, argv, &info); } -static union bench_clock do_memset(const struct function *r, struct bench_params *p, - void *src __maybe_unused, void *dst) +static int do_memset(const struct function *r, struct bench_params *p, + void *src __maybe_unused, void *dst, union bench_clock *rt) { union bench_clock start, end; memset_t fn = r->fn.memset; @@ -329,7 +363,9 @@ static union bench_clock do_memset(const struct function *r, struct bench_params fn(dst, i, p->size); clock_get(&end); - return clock_diff(&start, &end); + *rt = clock_diff(&start, &end); + + return 0; } static const char * const bench_mem_memset_usage[] = { @@ -340,10 +376,13 @@ static const char * const bench_mem_memset_usage[] = { static const struct function memset_functions[] = { { .name = "default", .desc = "Default memset() provided by glibc", + .fn.init = mem_alloc, + .fn.fini = mem_free, .fn.memset = memset }, #ifdef HAVE_ARCH_X86_64_SUPPORT -# define MEMSET_FN(_fn, _name, _desc) { .name = _name, .desc = _desc, .fn.memset = _fn }, +# define MEMSET_FN(_fn, _init, _fini, _name, _desc) \ + {.name = _name, .desc = _desc, .fn.memset = _fn, .fn.init = _init, .fn.fini = _fini }, # include "mem-memset-x86-64-asm-def.h" # undef MEMSET_FN #endif diff --git a/tools/perf/bench/mem-memcpy-arch.h b/tools/perf/bench/mem-memcpy-arch.h index 5bcaec5601a8..852e48cfd8fe 100644 --- a/tools/perf/bench/mem-memcpy-arch.h +++ b/tools/perf/bench/mem-memcpy-arch.h @@ -2,7 +2,7 @@ #ifdef HAVE_ARCH_X86_64_SUPPORT -#define MEMCPY_FN(fn, name, desc) \ +#define MEMCPY_FN(fn, init, fini, name, desc) \ void *fn(void *, const void *, size_t); #include "mem-memcpy-x86-64-asm-def.h" diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h index 6188e19d3129..f43038f4448b 100644 --- a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h +++ b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h @@ -1,9 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 */ MEMCPY_FN(memcpy_orig, + mem_alloc, + mem_free, "x86-64-unrolled", "unrolled memcpy() in arch/x86/lib/memcpy_64.S") MEMCPY_FN(__memcpy, + mem_alloc, + mem_free, "x86-64-movsq", "movsq-based memcpy() in arch/x86/lib/memcpy_64.S") diff --git a/tools/perf/bench/mem-memset-arch.h b/tools/perf/bench/mem-memset-arch.h index 53f45482663f..278c5da12d63 100644 --- a/tools/perf/bench/mem-memset-arch.h +++ b/tools/perf/bench/mem-memset-arch.h @@ -2,7 +2,7 @@ #ifdef HAVE_ARCH_X86_64_SUPPORT -#define MEMSET_FN(fn, name, desc) \ +#define MEMSET_FN(fn, init, fini, name, desc) \ void *fn(void *, int, size_t); #include "mem-memset-x86-64-asm-def.h" diff --git a/tools/perf/bench/mem-memset-x86-64-asm-def.h b/tools/perf/bench/mem-memset-x86-64-asm-def.h index 247c72fdfb9d..80ad1b7ea770 100644 --- a/tools/perf/bench/mem-memset-x86-64-asm-def.h +++ b/tools/perf/bench/mem-memset-x86-64-asm-def.h @@ -1,9 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 */ MEMSET_FN(memset_orig, + mem_alloc, + mem_free, "x86-64-unrolled", "unrolled memset() in arch/x86/lib/memset_64.S") MEMSET_FN(__memset, + mem_alloc, + mem_free, "x86-64-stosq", "movsq-based memset() in arch/x86/lib/memset_64.S") From fe0f3216dd8736afc1a6ddb0b79fd24f37418357 Mon Sep 17 00:00:00 2001 From: Ankur Arora Date: Wed, 17 Sep 2025 08:24:07 -0700 Subject: [PATCH 1748/2711] perf bench mem: Switch from zalloc() to mmap() Using mmap() ensures that the buffer is always aligned at a fixed boundary. Switch to that to remove one source of variability. Since we always want to read/write from the allocated buffers map with pagetables pre-populated. Reviewed-by: Namhyung Kim Signed-off-by: Ankur Arora Cc: Andrew Morton Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Dave Hansen Cc: David Hildenbrand Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Konrad Rzeszutek Wilk Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Peter Zijlstra Cc: Raghavendra K T Cc: Thomas Gleixner Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-functions.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 60ea20277507..e97962dd8f81 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -22,9 +22,9 @@ #include #include #include +#include #include #include -#include #define K 1024 @@ -286,16 +286,33 @@ static int do_memcpy(const struct function *r, struct bench_params *p, return 0; } +static void *bench_mmap(size_t size, bool populate) +{ + void *p; + int extra = populate ? MAP_POPULATE : 0; + + p = mmap(NULL, size, PROT_READ|PROT_WRITE, + extra | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + + return p == MAP_FAILED ? NULL : p; +} + +static void bench_munmap(void *p, size_t size) +{ + if (p) + munmap(p, size); +} + static bool mem_alloc(struct bench_mem_info *info, struct bench_params *p, void **src, void **dst) { bool failed; - *dst = zalloc(p->size); + *dst = bench_mmap(p->size, true); failed = *dst == NULL; if (info->alloc_src) { - *src = zalloc(p->size); + *src = bench_mmap(p->size, true); failed = failed || *src == NULL; } @@ -306,8 +323,8 @@ static void mem_free(struct bench_mem_info *info __maybe_unused, struct bench_params *p __maybe_unused, void **src, void **dst) { - free(*dst); - free(*src); + bench_munmap(*dst, p->size); + bench_munmap(*src, p->size); *dst = *src = NULL; } From 7b6837e63a091d15ea35974aae5ccf2605ad7047 Mon Sep 17 00:00:00 2001 From: Ankur Arora Date: Wed, 17 Sep 2025 08:24:08 -0700 Subject: [PATCH 1749/2711] perf bench mem: Allow mapping of hugepages Page sizes that can be selected: 4KB, 2MB, 1GB. Both the reservation and node from which hugepages are allocated from are expected to be addressed by the user. An example of page-size selection: $ perf bench mem memset -s 4gb -p 2mb # Running 'mem/memset' benchmark: # function 'default' (Default memset() provided by glibc) # Copying 4gb bytes ... 14.919194 GB/sec # function 'x86-64-unrolled' (unrolled memset() in arch/x86/lib/memset_64.S) # Copying 4gb bytes ... 11.514503 GB/sec # function 'x86-64-stosq' (movsq-based memset() in arch/x86/lib/memset_64.S) # Copying 4gb bytes ... 12.600568 GB/sec Signed-off-by: Ankur Arora Tested-by: Arnaldo Carvalho de Melo Cc: Andrew Morton Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Dave Hansen Cc: David Hildenbrand Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Konrad Rzeszutek Wilk Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raghavendra K T Cc: Thomas Gleixner Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-bench.txt | 14 +++++++++-- tools/perf/bench/mem-functions.c | 33 ++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt index 8331bd28b10e..04cdc31a0b0b 100644 --- a/tools/perf/Documentation/perf-bench.txt +++ b/tools/perf/Documentation/perf-bench.txt @@ -177,11 +177,16 @@ Suite for evaluating performance of simple memory copy in various ways. Options of *memcpy* ^^^^^^^^^^^^^^^^^^^ --l:: +-s:: --size:: Specify size of memory to copy (default: 1MB). Available units are B, KB, MB, GB and TB (case insensitive). +-p:: +--page:: +Specify page-size for mapping memory buffers (default: 4KB). +Available values are 4KB, 2MB, 1GB (case insensitive). + -f:: --function:: Specify function to copy (default: default). @@ -201,11 +206,16 @@ Suite for evaluating performance of simple memory set in various ways. Options of *memset* ^^^^^^^^^^^^^^^^^^^ --l:: +-s:: --size:: Specify size of memory to set (default: 1MB). Available units are B, KB, MB, GB and TB (case insensitive). +-p:: +--page:: +Specify page-size for mapping memory buffers (default: 4KB). +Available values are 4KB, 2MB, 1GB (case insensitive). + -f:: --function:: Specify function to set (default: default). diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index e97962dd8f81..6aa1f02553ba 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -25,11 +25,17 @@ #include #include #include +#include #define K 1024 +#define PAGE_SHIFT_4KB 12 +#define PAGE_SHIFT_2MB 21 +#define PAGE_SHIFT_1GB 30 + static const char *size_str = "1MB"; static const char *function_str = "all"; +static const char *page_size_str = "4KB"; static unsigned int nr_loops = 1; static bool use_cycles; static int cycles_fd; @@ -39,6 +45,10 @@ static const struct option options[] = { "Specify the size of the memory buffers. " "Available units: B, KB, MB, GB and TB (case insensitive)"), + OPT_STRING('p', "page", &page_size_str, "4KB", + "Specify page-size for mapping memory buffers. " + "Available sizes: 4KB, 2MB, 1GB (case insensitive)"), + OPT_STRING('f', "function", &function_str, "all", "Specify the function to run, \"all\" runs all available functions, \"help\" lists them"), @@ -60,6 +70,7 @@ struct bench_params { size_t size; size_t size_total; unsigned int nr_loops; + unsigned int page_shift; }; struct bench_mem_info { @@ -202,7 +213,8 @@ out_free: if (r->fn.fini) r->fn.fini(info, p, &src, &dst); return; out_init_failed: - printf("# Memory allocation failed - maybe size (%s) is too large?\n", size_str); + printf("# Memory allocation failed - maybe size (%s) %s?\n", size_str, + p->page_shift != PAGE_SHIFT_4KB ? "has insufficient hugepages" : "is too large"); goto out_free; } @@ -210,6 +222,7 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * { int i; struct bench_params p = { 0 }; + unsigned int page_size; argc = parse_options(argc, argv, options, info->usage, 0); @@ -230,6 +243,15 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * } p.size_total = p.size * p.nr_loops; + page_size = (unsigned int)perf_atoll((char *)page_size_str); + if (page_size != (1 << PAGE_SHIFT_4KB) && + page_size != (1 << PAGE_SHIFT_2MB) && + page_size != (1 << PAGE_SHIFT_1GB)) { + fprintf(stderr, "Invalid page-size:%s\n", page_size_str); + return 1; + } + p.page_shift = ilog2(page_size); + if (!strncmp(function_str, "all", 3)) { for (i = 0; info->functions[i].name; i++) __bench_mem_function(info, &p, i); @@ -286,11 +308,14 @@ static int do_memcpy(const struct function *r, struct bench_params *p, return 0; } -static void *bench_mmap(size_t size, bool populate) +static void *bench_mmap(size_t size, bool populate, unsigned int page_shift) { void *p; int extra = populate ? MAP_POPULATE : 0; + if (page_shift != PAGE_SHIFT_4KB) + extra |= MAP_HUGETLB | (page_shift << MAP_HUGE_SHIFT); + p = mmap(NULL, size, PROT_READ|PROT_WRITE, extra | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); @@ -308,11 +333,11 @@ static bool mem_alloc(struct bench_mem_info *info, struct bench_params *p, { bool failed; - *dst = bench_mmap(p->size, true); + *dst = bench_mmap(p->size, true, p->page_shift); failed = *dst == NULL; if (info->alloc_src) { - *src = bench_mmap(p->size, true); + *src = bench_mmap(p->size, true, p->page_shift); failed = failed || *src == NULL; } From fd1d882c4c34e1925bf134e31dddf4891578a72f Mon Sep 17 00:00:00 2001 From: Ankur Arora Date: Wed, 17 Sep 2025 08:24:09 -0700 Subject: [PATCH 1750/2711] perf bench mem: Allow chunking on a memory region There can be a significant gap in memset/memcpy performance depending on the size of the region being operated on. With chunk-size=4kb: $ echo madvise > /sys/kernel/mm/transparent_hugepage/enabled $ perf bench mem memset -p 4kb -k 4kb -s 4gb -l 10 -f x86-64-stosq # Running 'mem/memset' benchmark: # function 'x86-64-stosq' (movsq-based memset() in arch/x86/lib/memset_64.S) # Copying 4gb bytes ... 13.011655 GB/sec With chunk-size=1gb: $ echo madvise > /sys/kernel/mm/transparent_hugepage/enabled $ perf bench mem memset -p 4kb -k 1gb -s 4gb -l 10 -f x86-64-stosq # Running 'mem/memset' benchmark: # function 'x86-64-stosq' (movsq-based memset() in arch/x86/lib/memset_64.S) # Copying 4gb bytes ... 21.936355 GB/sec So, allow the user to specify the chunk-size. The default value is identical to the total size of the region, which preserves current behaviour. Reviewed-by: Namhyung Kim Signed-off-by: Ankur Arora Tested-by: Arnaldo Carvalho de Melo Cc: Andrew Morton Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Dave Hansen Cc: David Hildenbrand Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Konrad Rzeszutek Wilk Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Peter Zijlstra Cc: Raghavendra K T Cc: Thomas Gleixner Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-bench.txt | 10 ++++++++++ tools/perf/bench/mem-functions.c | 20 ++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt index 04cdc31a0b0b..3d1455d880c3 100644 --- a/tools/perf/Documentation/perf-bench.txt +++ b/tools/perf/Documentation/perf-bench.txt @@ -187,6 +187,11 @@ Available units are B, KB, MB, GB and TB (case insensitive). Specify page-size for mapping memory buffers (default: 4KB). Available values are 4KB, 2MB, 1GB (case insensitive). +-k:: +--chunk:: +Specify the chunk-size for each invocation. (default: 0, or full-extent) +Available units are B, KB, MB, GB and TB (case insensitive). + -f:: --function:: Specify function to copy (default: default). @@ -216,6 +221,11 @@ Available units are B, KB, MB, GB and TB (case insensitive). Specify page-size for mapping memory buffers (default: 4KB). Available values are 4KB, 2MB, 1GB (case insensitive). +-k:: +--chunk:: +Specify the chunk-size for each invocation. (default: 0, or full-extent) +Available units are B, KB, MB, GB and TB (case insensitive). + -f:: --function:: Specify function to set (default: default). diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 6aa1f02553ba..69968ba63d81 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -36,6 +36,7 @@ static const char *size_str = "1MB"; static const char *function_str = "all"; static const char *page_size_str = "4KB"; +static const char *chunk_size_str = "0"; static unsigned int nr_loops = 1; static bool use_cycles; static int cycles_fd; @@ -49,6 +50,10 @@ static const struct option options[] = { "Specify page-size for mapping memory buffers. " "Available sizes: 4KB, 2MB, 1GB (case insensitive)"), + OPT_STRING('k', "chunk", &chunk_size_str, "0", + "Specify the chunk-size for each invocation. " + "Available units: B, KB, MB, GB and TB (case insensitive)"), + OPT_STRING('f', "function", &function_str, "all", "Specify the function to run, \"all\" runs all available functions, \"help\" lists them"), @@ -69,6 +74,7 @@ union bench_clock { struct bench_params { size_t size; size_t size_total; + size_t chunk_size; unsigned int nr_loops; unsigned int page_shift; }; @@ -243,6 +249,14 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * } p.size_total = p.size * p.nr_loops; + p.chunk_size = (size_t)perf_atoll((char *)chunk_size_str); + if ((s64)p.chunk_size < 0 || (s64)p.chunk_size > (s64)p.size) { + fprintf(stderr, "Invalid chunk_size:%s\n", chunk_size_str); + return 1; + } + if (!p.chunk_size) + p.chunk_size = p.size; + page_size = (unsigned int)perf_atoll((char *)page_size_str); if (page_size != (1 << PAGE_SHIFT_4KB) && page_size != (1 << PAGE_SHIFT_2MB) && @@ -300,7 +314,8 @@ static int do_memcpy(const struct function *r, struct bench_params *p, clock_get(&start); for (unsigned int i = 0; i < p->nr_loops; ++i) - fn(dst, src, p->size); + for (size_t off = 0; off < p->size; off += p->chunk_size) + fn(dst + off, src + off, min(p->chunk_size, p->size - off)); clock_get(&end); *rt = clock_diff(&start, &end); @@ -402,7 +417,8 @@ static int do_memset(const struct function *r, struct bench_params *p, clock_get(&start); for (unsigned int i = 0; i < p->nr_loops; ++i) - fn(dst, i, p->size); + for (size_t off = 0; off < p->size; off += p->chunk_size) + fn(dst + off, i, min(p->chunk_size, p->size - off)); clock_get(&end); *rt = clock_diff(&start, &end); From c3047f9a1ab457b60caa3b2baa2c605b935ca4f1 Mon Sep 17 00:00:00 2001 From: Ankur Arora Date: Wed, 17 Sep 2025 08:24:10 -0700 Subject: [PATCH 1751/2711] perf bench mem: Refactor mem_options Split mem benchmark options into common and memset/memcpy specific. Reviewed-by: Namhyung Kim Signed-off-by: Ankur Arora Cc: Andrew Morton Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Dave Hansen Cc: David Hildenbrand Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Konrad Rzeszutek Wilk Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Peter Zijlstra Cc: Raghavendra K T Cc: Thomas Gleixner Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-functions.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 69968ba63d81..2a23bed8c2d3 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -41,7 +41,7 @@ static unsigned int nr_loops = 1; static bool use_cycles; static int cycles_fd; -static const struct option options[] = { +static const struct option bench_common_options[] = { OPT_STRING('s', "size", &size_str, "1MB", "Specify the size of the memory buffers. " "Available units: B, KB, MB, GB and TB (case insensitive)"), @@ -50,10 +50,6 @@ static const struct option options[] = { "Specify page-size for mapping memory buffers. " "Available sizes: 4KB, 2MB, 1GB (case insensitive)"), - OPT_STRING('k', "chunk", &chunk_size_str, "0", - "Specify the chunk-size for each invocation. " - "Available units: B, KB, MB, GB and TB (case insensitive)"), - OPT_STRING('f', "function", &function_str, "all", "Specify the function to run, \"all\" runs all available functions, \"help\" lists them"), @@ -66,6 +62,14 @@ static const struct option options[] = { OPT_END() }; +static const struct option bench_mem_options[] = { + OPT_STRING('k', "chunk", &chunk_size_str, "0", + "Specify the chunk-size for each invocation. " + "Available units: B, KB, MB, GB and TB (case insensitive)"), + OPT_PARENT(bench_common_options), + OPT_END() +}; + union bench_clock { u64 cycles; struct timeval tv; @@ -84,6 +88,7 @@ struct bench_mem_info { int (*do_op)(const struct function *r, struct bench_params *p, void *src, void *dst, union bench_clock *rt); const char *const *usage; + const struct option *options; bool alloc_src; }; @@ -230,7 +235,7 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * struct bench_params p = { 0 }; unsigned int page_size; - argc = parse_options(argc, argv, options, info->usage, 0); + argc = parse_options(argc, argv, info->options, info->usage, 0); if (use_cycles) { i = init_cycles(); @@ -397,6 +402,7 @@ int bench_mem_memcpy(int argc, const char **argv) .functions = memcpy_functions, .do_op = do_memcpy, .usage = bench_mem_memcpy_usage, + .options = bench_mem_options, .alloc_src = true, }; @@ -454,6 +460,7 @@ int bench_mem_memset(int argc, const char **argv) .functions = memset_functions, .do_op = do_memset, .usage = bench_mem_memset_usage, + .options = bench_mem_options, }; return bench_mem_common(argc, argv, &info); From a8f0992998af9ea1135ee6415c68c1d84cb5ad22 Mon Sep 17 00:00:00 2001 From: Ankur Arora Date: Wed, 17 Sep 2025 08:24:11 -0700 Subject: [PATCH 1752/2711] perf bench mem: Add mmap() workloads Add two mmap() workloads: one that eagerly populates a region and another that demand faults it in. The intent is to probe the memory subsytem performance incurred by mmap(). $ perf bench mem mmap -s 4gb -p 4kb -l 10 -f populate # Running 'mem/mmap' benchmark: # function 'populate' (Eagerly populated map()) # Copying 4gb bytes ... 1.811691 GB/sec $ perf bench mem mmap -s 4gb -p 2mb -l 10 -f populate # Running 'mem/mmap' benchmark: # function 'populate' (Eagerly populated mmap()) # Copying 4gb bytes ... 12.272017 GB/sec $ perf bench mem mmap -s 4gb -p 1gb -l 10 -f populate # Running 'mem/mmap' benchmark: # function 'populate' (Eagerly populated mmap()) # Copying 4gb bytes ... 17.085927 GB/sec Signed-off-by: Ankur Arora Tested-by: Arnaldo Carvalho de Melo Cc: Andrew Morton Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Dave Hansen Cc: David Hildenbrand Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Konrad Rzeszutek Wilk Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raghavendra K T Cc: Thomas Gleixner Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-bench.txt | 34 +++++++++ tools/perf/bench/bench.h | 1 + tools/perf/bench/mem-functions.c | 96 +++++++++++++++++++++++++ tools/perf/builtin-bench.c | 1 + 4 files changed, 132 insertions(+) diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt index 3d1455d880c3..1160224cb718 100644 --- a/tools/perf/Documentation/perf-bench.txt +++ b/tools/perf/Documentation/perf-bench.txt @@ -240,6 +240,40 @@ Repeat memset invocation this number of times. --cycles:: Use perf's cpu-cycles event instead of gettimeofday syscall. +*mmap*:: +Suite for evaluating memory subsystem performance for mmap()'d memory. + +Options of *mmap* +^^^^^^^^^^^^^^^^^ +-s:: +--size:: +Specify size of memory to set (default: 1MB). +Available units are B, KB, MB, GB and TB (case insensitive). + +-p:: +--page:: +Specify page-size for mapping memory buffers (default: 4KB). +Available values are 4KB, 2MB, 1GB (case insensitive). + +-r:: +--randomize:: +Specify seed to randomize page access offset (default: 0, or not randomized). + +-f:: +--function:: +Specify function to set (default: all). +Available functions are 'demand' and 'populate', with the first +demand faulting pages in the region and the second using an eager +mapping. + +-l:: +--nr_loops:: +Repeat mmap() invocation this number of times. + +-c:: +--cycles:: +Use perf's cpu-cycles event instead of gettimeofday syscall. + SUITES FOR 'numa' ~~~~~~~~~~~~~~~~~ *mem*:: diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h index 9f736423af53..8519eb5a42fa 100644 --- a/tools/perf/bench/bench.h +++ b/tools/perf/bench/bench.h @@ -28,6 +28,7 @@ int bench_syscall_fork(int argc, const char **argv); int bench_syscall_execve(int argc, const char **argv); int bench_mem_memcpy(int argc, const char **argv); int bench_mem_memset(int argc, const char **argv); +int bench_mem_mmap(int argc, const char **argv); int bench_mem_find_bit(int argc, const char **argv); int bench_futex_hash(int argc, const char **argv); int bench_futex_wake(int argc, const char **argv); diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 2a23bed8c2d3..2908a3a796c9 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -40,6 +40,7 @@ static const char *chunk_size_str = "0"; static unsigned int nr_loops = 1; static bool use_cycles; static int cycles_fd; +static unsigned int seed; static const struct option bench_common_options[] = { OPT_STRING('s', "size", &size_str, "1MB", @@ -81,6 +82,7 @@ struct bench_params { size_t chunk_size; unsigned int nr_loops; unsigned int page_shift; + unsigned int seed; }; struct bench_mem_info { @@ -98,6 +100,7 @@ typedef void (*mem_fini_t)(struct bench_mem_info *, struct bench_params *, void **, void **); typedef void *(*memcpy_t)(void *, const void *, size_t); typedef void *(*memset_t)(void *, int, size_t); +typedef void (*mmap_op_t)(void *, size_t, unsigned int, bool); struct function { const char *name; @@ -108,6 +111,7 @@ struct function { union { memcpy_t memcpy; memset_t memset; + mmap_op_t mmap_op; }; } fn; }; @@ -160,6 +164,14 @@ static union bench_clock clock_diff(union bench_clock *s, union bench_clock *e) return t; } +static void clock_accum(union bench_clock *a, union bench_clock *b) +{ + if (use_cycles) + a->cycles += b->cycles; + else + timeradd(&a->tv, &b->tv, &a->tv); +} + static double timeval2double(struct timeval *ts) { return (double)ts->tv_sec + (double)ts->tv_usec / (double)USEC_PER_SEC; @@ -271,6 +283,8 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * } p.page_shift = ilog2(page_size); + p.seed = seed; + if (!strncmp(function_str, "all", 3)) { for (i = 0; info->functions[i].name; i++) __bench_mem_function(info, &p, i); @@ -465,3 +479,85 @@ int bench_mem_memset(int argc, const char **argv) return bench_mem_common(argc, argv, &info); } + +static void mmap_page_touch(void *dst, size_t size, unsigned int page_shift, bool random) +{ + unsigned long npages = size / (1 << page_shift); + unsigned long offset = 0, r = 0; + + for (unsigned long i = 0; i < npages; i++) { + if (random) + r = rand() % (1 << page_shift); + + *((char *)dst + offset + r) = *(char *)(dst + offset + r) + i; + offset += 1 << page_shift; + } +} + +static int do_mmap(const struct function *r, struct bench_params *p, + void *src __maybe_unused, void *dst __maybe_unused, + union bench_clock *accum) +{ + union bench_clock start, end, diff; + mmap_op_t fn = r->fn.mmap_op; + bool populate = strcmp(r->name, "populate") == 0; + + if (p->seed) + srand(p->seed); + + for (unsigned int i = 0; i < p->nr_loops; i++) { + clock_get(&start); + dst = bench_mmap(p->size, populate, p->page_shift); + if (!dst) + goto out; + + fn(dst, p->size, p->page_shift, p->seed); + clock_get(&end); + diff = clock_diff(&start, &end); + clock_accum(accum, &diff); + + bench_munmap(dst, p->size); + } + + return 0; +out: + printf("# Memory allocation failed - maybe size (%s) %s?\n", size_str, + p->page_shift != PAGE_SHIFT_4KB ? "has insufficient hugepages" : "is too large"); + return -1; +} + +static const char * const bench_mem_mmap_usage[] = { + "perf bench mem mmap ", + NULL +}; + +static const struct function mmap_functions[] = { + { .name = "demand", + .desc = "Demand loaded mmap()", + .fn.mmap_op = mmap_page_touch }, + + { .name = "populate", + .desc = "Eagerly populated mmap()", + .fn.mmap_op = mmap_page_touch }, + + { .name = NULL, } +}; + +int bench_mem_mmap(int argc, const char **argv) +{ + static const struct option bench_mmap_options[] = { + OPT_UINTEGER('r', "randomize", &seed, + "Seed to randomize page access offset."), + OPT_PARENT(bench_common_options), + OPT_END() + }; + + struct bench_mem_info info = { + .functions = mmap_functions, + .do_op = do_mmap, + .usage = bench_mem_mmap_usage, + .options = bench_mmap_options, + }; + + return bench_mem_common(argc, argv, &info); +} diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index 2c1a9f3d847a..02dea1b88228 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -65,6 +65,7 @@ static struct bench mem_benchmarks[] = { { "memcpy", "Benchmark for memcpy() functions", bench_mem_memcpy }, { "memset", "Benchmark for memset() functions", bench_mem_memset }, { "find_bit", "Benchmark for find_bit() functions", bench_mem_find_bit }, + { "mmap", "Benchmark for mmap() mappings", bench_mem_mmap }, { "all", "Run all memory access benchmarks", NULL }, { NULL, NULL, NULL } }; From c17dda8013495d8132c976cbf349be9949d0fbd1 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Fri, 8 Aug 2025 14:24:40 +0100 Subject: [PATCH 1753/2711] perf session: Fix handling when buffer exceeds 2 GiB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a user specifies an AUX buffer larger than 2 GiB, the returned size may exceed 0x80000000. Since the err variable is defined as a signed 32-bit integer, such a value overflows and becomes negative. As a result, the perf record command reports an error: 0x146e8 [0x30]: failed to process type: 71 [Unknown error 183711232] Change the type of the err variable to a signed 64-bit integer to accommodate large buffer sizes correctly. Fixes: d5652d865ea734a1 ("perf session: Add ability to skip 4GiB or more") Reported-by: Tamas Zsoldos Signed-off-by: Leo Yan Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Link: https://lore.kernel.org/r/20250808-perf_fix_big_buffer_size-v1-1-45f45444a9a4@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 26ae078278cd..09af486c83e4 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1402,7 +1402,7 @@ static s64 perf_session__process_user_event(struct perf_session *session, const struct perf_tool *tool = session->tool; struct perf_sample sample; int fd = perf_data__fd(session->data); - int err; + s64 err; perf_sample__init(&sample, /*all=*/true); if ((event->header.type != PERF_RECORD_COMPRESSED && From 4e4a4f58bed19e1a3a5a7c3a18ce3b927b76fcd3 Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Fri, 12 Sep 2025 10:35:32 +0800 Subject: [PATCH 1754/2711] dt-bindings: pci: Add Sophgo SG2042 PCIe host Add binding for Sophgo SG2042 PCIe host controller. Signed-off-by: Chen Wang Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/2755f145755b6096247c26852b63671a6fea4dbf.1757643388.git.unicorn_wang@outlook.com --- .../bindings/pci/sophgo,sg2042-pcie-host.yaml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/sophgo,sg2042-pcie-host.yaml diff --git a/Documentation/devicetree/bindings/pci/sophgo,sg2042-pcie-host.yaml b/Documentation/devicetree/bindings/pci/sophgo,sg2042-pcie-host.yaml new file mode 100644 index 000000000000..f8b7ca57fff1 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/sophgo,sg2042-pcie-host.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/sophgo,sg2042-pcie-host.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sophgo SG2042 PCIe Host (Cadence PCIe Wrapper) + +description: + Sophgo SG2042 PCIe host controller is based on the Cadence PCIe core. + +maintainers: + - Chen Wang + +properties: + compatible: + const: sophgo,sg2042-pcie-host + + reg: + maxItems: 2 + + reg-names: + items: + - const: reg + - const: cfg + + vendor-id: + const: 0x1f1c + + device-id: + const: 0x2042 + + msi-parent: true + +allOf: + - $ref: cdns-pcie-host.yaml# + +required: + - compatible + - reg + - reg-names + +unevaluatedProperties: false + +examples: + - | + #include + + pcie@62000000 { + compatible = "sophgo,sg2042-pcie-host"; + device_type = "pci"; + reg = <0x62000000 0x00800000>, + <0x48000000 0x00001000>; + reg-names = "reg", "cfg"; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0 0x00000000 0xde000000 0 0x00010000>, + <0x82000000 0 0xd0400000 0xd0400000 0 0x0d000000>; + bus-range = <0x00 0xff>; + vendor-id = <0x1f1c>; + device-id = <0x2042>; + cdns,no-bar-match-nbits = <48>; + msi-parent = <&msi>; + }; From 49a6c160ad4812476f8ae1a8f4ed6d15adfa6c09 Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Fri, 12 Sep 2025 10:36:01 +0800 Subject: [PATCH 1755/2711] PCI: cadence: Check for the existence of cdns_pcie::ops before using it cdns_pcie::ops might not be populated by all the Cadence glue drivers. This is going to be true for the upcoming Sophgo platform which doesn't set the ops. Hence, add a check to prevent NULL pointer dereference. Signed-off-by: Chen Wang [mani: reworded subject and description] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/35182ee1d972dfcd093a964e11205efcebbdc044.1757643388.git.unicorn_wang@outlook.com --- drivers/pci/controller/cadence/pcie-cadence-host.c | 2 +- drivers/pci/controller/cadence/pcie-cadence.c | 4 ++-- drivers/pci/controller/cadence/pcie-cadence.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c index 59a4631de79f..fffd63d6665e 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-host.c +++ b/drivers/pci/controller/cadence/pcie-cadence-host.c @@ -531,7 +531,7 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc) cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1); cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1); - if (pcie->ops->cpu_addr_fixup) + if (pcie->ops && pcie->ops->cpu_addr_fixup) cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr); addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) | diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c index 70a19573440e..61806bbd8aa3 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.c +++ b/drivers/pci/controller/cadence/pcie-cadence.c @@ -92,7 +92,7 @@ void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn, cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1); /* Set the CPU address */ - if (pcie->ops->cpu_addr_fixup) + if (pcie->ops && pcie->ops->cpu_addr_fixup) cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr); addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) | @@ -123,7 +123,7 @@ void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, } /* Set the CPU address */ - if (pcie->ops->cpu_addr_fixup) + if (pcie->ops && pcie->ops->cpu_addr_fixup) cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr); addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(17) | diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h index 1d81c4bf6c6d..2f07ba661bda 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.h +++ b/drivers/pci/controller/cadence/pcie-cadence.h @@ -468,7 +468,7 @@ static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg) static inline int cdns_pcie_start_link(struct cdns_pcie *pcie) { - if (pcie->ops->start_link) + if (pcie->ops && pcie->ops->start_link) return pcie->ops->start_link(pcie); return 0; @@ -476,13 +476,13 @@ static inline int cdns_pcie_start_link(struct cdns_pcie *pcie) static inline void cdns_pcie_stop_link(struct cdns_pcie *pcie) { - if (pcie->ops->stop_link) + if (pcie->ops && pcie->ops->stop_link) pcie->ops->stop_link(pcie); } static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie) { - if (pcie->ops->link_up) + if (pcie->ops && pcie->ops->link_up) return pcie->ops->link_up(pcie); return true; From 1c72774df028429836eec3394212f2921bb830fc Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Fri, 12 Sep 2025 10:36:31 +0800 Subject: [PATCH 1756/2711] PCI: sg2042: Add Sophgo SG2042 PCIe driver Add support for PCIe controller in Sophgo SG2042 SoC. The controller uses the Cadence PCIe core programmed by pcie-cadence* common driver. The PCIe controller in SG2042 works in host mode only, supporting data rate up to 16 GT/s and lanes up to x16 or x8. Signed-off-by: Chen Wang [mani: reworded description and minor code cleanups] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/01b0a57cd9dba8bed7c1f2d52997046c2c6f042b.1757643388.git.unicorn_wang@outlook.com --- drivers/pci/controller/cadence/Kconfig | 10 ++ drivers/pci/controller/cadence/Makefile | 1 + drivers/pci/controller/cadence/pcie-sg2042.c | 134 +++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 drivers/pci/controller/cadence/pcie-sg2042.c diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig index 666e16b6367f..02a639e55fd8 100644 --- a/drivers/pci/controller/cadence/Kconfig +++ b/drivers/pci/controller/cadence/Kconfig @@ -42,6 +42,15 @@ config PCIE_CADENCE_PLAT_EP endpoint mode. This PCIe controller may be embedded into many different vendors SoCs. +config PCIE_SG2042_HOST + tristate "Sophgo SG2042 PCIe controller (host mode)" + depends on OF && (ARCH_SOPHGO || COMPILE_TEST) + select PCIE_CADENCE_HOST + help + Say Y here if you want to support the Sophgo SG2042 PCIe platform + controller in host mode. Sophgo SG2042 PCIe controller uses Cadence + PCIe core. + config PCI_J721E tristate select PCIE_CADENCE_HOST if PCI_J721E_HOST != n @@ -67,4 +76,5 @@ config PCI_J721E_EP Say Y here if you want to support the TI J721E PCIe platform controller in endpoint mode. TI J721E PCIe controller uses Cadence PCIe core. + endmenu diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile index 9bac5fb2f13d..5e23f8539ecc 100644 --- a/drivers/pci/controller/cadence/Makefile +++ b/drivers/pci/controller/cadence/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o obj-$(CONFIG_PCI_J721E) += pci-j721e.o +obj-$(CONFIG_PCIE_SG2042_HOST) += pcie-sg2042.o diff --git a/drivers/pci/controller/cadence/pcie-sg2042.c b/drivers/pci/controller/cadence/pcie-sg2042.c new file mode 100644 index 000000000000..a077b28d4894 --- /dev/null +++ b/drivers/pci/controller/cadence/pcie-sg2042.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * pcie-sg2042 - PCIe controller driver for Sophgo SG2042 SoC + * + * Copyright (C) 2025 Sophgo Technology Inc. + * Copyright (C) 2025 Chen Wang + */ + +#include +#include +#include +#include + +#include "pcie-cadence.h" + +/* + * SG2042 only supports 4-byte aligned access, so for the rootbus (i.e. to + * read/write the Root Port itself, read32/write32 is required. For + * non-rootbus (i.e. to read/write the PCIe peripheral registers, supports + * 1/2/4 byte aligned access, so directly using read/write should be fine. + */ + +static struct pci_ops sg2042_pcie_root_ops = { + .map_bus = cdns_pci_map_bus, + .read = pci_generic_config_read32, + .write = pci_generic_config_write32, +}; + +static struct pci_ops sg2042_pcie_child_ops = { + .map_bus = cdns_pci_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, +}; + +static int sg2042_pcie_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pci_host_bridge *bridge; + struct cdns_pcie *pcie; + struct cdns_pcie_rc *rc; + int ret; + + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); + if (!bridge) + return dev_err_probe(dev, -ENOMEM, "Failed to alloc host bridge!\n"); + + bridge->ops = &sg2042_pcie_root_ops; + bridge->child_ops = &sg2042_pcie_child_ops; + + rc = pci_host_bridge_priv(bridge); + pcie = &rc->pcie; + pcie->dev = dev; + + platform_set_drvdata(pdev, pcie); + + pm_runtime_set_active(dev); + pm_runtime_no_callbacks(dev); + devm_pm_runtime_enable(dev); + + ret = cdns_pcie_init_phy(dev, pcie); + if (ret) + return dev_err_probe(dev, ret, "Failed to init phy!\n"); + + ret = cdns_pcie_host_setup(rc); + if (ret) { + dev_err_probe(dev, ret, "Failed to setup host!\n"); + cdns_pcie_disable_phy(pcie); + return ret; + } + + return 0; +} + +static void sg2042_pcie_remove(struct platform_device *pdev) +{ + struct cdns_pcie *pcie = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + struct cdns_pcie_rc *rc; + + rc = container_of(pcie, struct cdns_pcie_rc, pcie); + cdns_pcie_host_disable(rc); + + cdns_pcie_disable_phy(pcie); + + pm_runtime_disable(dev); +} + +static int sg2042_pcie_suspend_noirq(struct device *dev) +{ + struct cdns_pcie *pcie = dev_get_drvdata(dev); + + cdns_pcie_disable_phy(pcie); + + return 0; +} + +static int sg2042_pcie_resume_noirq(struct device *dev) +{ + struct cdns_pcie *pcie = dev_get_drvdata(dev); + int ret; + + ret = cdns_pcie_enable_phy(pcie); + if (ret) { + dev_err(dev, "failed to enable PHY\n"); + return ret; + } + + return 0; +} + +static DEFINE_NOIRQ_DEV_PM_OPS(sg2042_pcie_pm_ops, + sg2042_pcie_suspend_noirq, + sg2042_pcie_resume_noirq); + +static const struct of_device_id sg2042_pcie_of_match[] = { + { .compatible = "sophgo,sg2042-pcie-host" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sg2042_pcie_of_match); + +static struct platform_driver sg2042_pcie_driver = { + .driver = { + .name = "sg2042-pcie", + .of_match_table = sg2042_pcie_of_match, + .pm = pm_sleep_ptr(&sg2042_pcie_pm_ops), + }, + .probe = sg2042_pcie_probe, + .remove = sg2042_pcie_remove, +}; +module_platform_driver(sg2042_pcie_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PCIe controller driver for SG2042 SoCs"); +MODULE_AUTHOR("Chen Wang "); From b90d027afbdde5a0b640586f4cf91cc5cc97a5bc Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 9 Sep 2025 08:49:02 +0300 Subject: [PATCH 1757/2711] dt-bindings: input: maxtouch: add common touchscreen properties Since atmel,maxtouch describes touchscreens too, it should include common touchscreen properties. Signed-off-by: Svyatoslav Ryhel Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250909054903.11519-2-clamor95@gmail.com Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/atmel,maxtouch.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml b/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml index c40799355ed7..d79b254f1cde 100644 --- a/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml +++ b/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml @@ -16,6 +16,7 @@ description: | allOf: - $ref: input.yaml# + - $ref: touchscreen/touchscreen.yaml# properties: compatible: @@ -95,7 +96,7 @@ required: - reg - interrupts -additionalProperties: false +unevaluatedProperties: false examples: - | From 05457d96175d25c976ab6241c332ae2eb5e07833 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 9 Jun 2025 20:53:11 +0700 Subject: [PATCH 1758/2711] sparc/module: Add R_SPARC_UA64 relocation handling This is needed so that the kernel can handle R_SPARC_UA64 relocations, which is emitted by LLVM's IAS. Signed-off-by: Koakuma Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/include/asm/elf_64.h | 1 + arch/sparc/kernel/module.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/sparc/include/asm/elf_64.h b/arch/sparc/include/asm/elf_64.h index 8fb09eec8c3e..694ed081cf8d 100644 --- a/arch/sparc/include/asm/elf_64.h +++ b/arch/sparc/include/asm/elf_64.h @@ -58,6 +58,7 @@ #define R_SPARC_7 43 #define R_SPARC_5 44 #define R_SPARC_6 45 +#define R_SPARC_UA64 54 /* Bits present in AT_HWCAP, primarily for Sparc32. */ #define HWCAP_SPARC_FLUSH 0x00000001 diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index b8c51cc23d96..6e3d4dde4f9a 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -87,6 +87,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, break; #ifdef CONFIG_SPARC64 case R_SPARC_64: + case R_SPARC_UA64: location[0] = v >> 56; location[1] = v >> 48; location[2] = v >> 40; From dee099fd9d9af800ef28a3f930d32974104cf36a Mon Sep 17 00:00:00 2001 From: Koakuma Date: Mon, 9 Jun 2025 20:53:12 +0700 Subject: [PATCH 1759/2711] sparc/module: Make it clear that relocation numbers are shown in hex This is to ease debugging by removing the ambiguity of the shown number base. Signed-off-by: Koakuma Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/kernel/module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 6e3d4dde4f9a..49740450a685 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -142,7 +142,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, break; default: - printk(KERN_ERR "module %s: Unknown relocation: %x\n", + printk(KERN_ERR "module %s: Unknown relocation: 0x%x\n", me->name, (int) (ELF_R_TYPE(rel[i].r_info) & 0xff)); return -ENOEXEC; From fd321a861fcae862a4800fa49375336ee64e6c9c Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 9 Sep 2025 08:49:03 +0300 Subject: [PATCH 1760/2711] Input: atmel_mxt_ts - add support for generic touchscreen configurations This provides support for generic touchscreen configuration options like swapped-x-y, min-x, min-y, size-x, size-y, etc. Signed-off-by: Svyatoslav Ryhel Link: https://lore.kernel.org/r/20250909054903.11519-3-clamor95@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 322d5a3d40a0..fc624101147e 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -355,6 +356,8 @@ struct mxt_data { enum mxt_suspend_mode suspend_mode; u32 wakeup_method; + + struct touchscreen_properties prop; }; struct mxt_vb2_buffer { @@ -888,8 +891,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message) /* Touch active */ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1); - input_report_abs(input_dev, ABS_MT_POSITION_X, x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + touchscreen_report_pos(input_dev, &data->prop, x, y, true); input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude); input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area); } else { @@ -1010,8 +1012,7 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message) id, type, x, y, major, pressure, orientation); input_mt_report_slot_state(input_dev, tool, 1); - input_report_abs(input_dev, ABS_MT_POSITION_X, x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + touchscreen_report_pos(input_dev, &data->prop, x, y, true); input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major); input_report_abs(input_dev, ABS_MT_PRESSURE, pressure); input_report_abs(input_dev, ABS_MT_DISTANCE, distance); @@ -2212,6 +2213,8 @@ static int mxt_initialize_input_device(struct mxt_data *data) 0, 255, 0, 0); } + touchscreen_parse_properties(input_dev, true, &data->prop); + /* For T15 and T97 Key Array */ if (data->T15_reportid_min || data->T97_reportid_min) { for (i = 0; i < data->t15_num_keys; i++) From 6fd44a481b3c6111e4801cec964627791d0f3ec5 Mon Sep 17 00:00:00 2001 From: Anthony Yznaga Date: Tue, 15 Jul 2025 18:24:46 -0700 Subject: [PATCH 1761/2711] sparc64: fix hugetlb for sun4u An attempt to exercise sparc hugetlb code in a sun4u-based guest running under qemu results in the guest hanging due to being stuck in a trap loop. This is due to invalid hugetlb TTEs being installed that do not have the expected _PAGE_PMD_HUGE and page size bits set. Although the breakage has gone apparently unnoticed for several years, fix it now so there is the option to exercise sparc hugetlb code under qemu. This can be useful because sun4v support in qemu does not support linux guests currently and sun4v-based hardware resources may not be readily available. Fix tested with a 6.15.2 and 6.16-rc6 kernels by running libhugetlbfs tests on a qemu guest running Debian 13. Fixes: c7d9f77d33a7 ("sparc64: Multi-page size support") Cc: stable@vger.kernel.org Signed-off-by: Anthony Yznaga Tested-by: John Paul Adrian Glaubitz Reviewed-by: John Paul Adrian Glaubitz Reviewed-by: Andreas Larsson Link: https://lore.kernel.org/r/20250716012446.10357-1-anthony.yznaga@oracle.com Signed-off-by: Andreas Larsson --- arch/sparc/mm/hugetlbpage.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 4b9431311e05..4652e868663b 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -22,6 +22,26 @@ static pte_t sun4u_hugepage_shift_to_tte(pte_t entry, unsigned int shift) { + unsigned long hugepage_size = _PAGE_SZ4MB_4U; + + pte_val(entry) = pte_val(entry) & ~_PAGE_SZALL_4U; + + switch (shift) { + case HPAGE_256MB_SHIFT: + hugepage_size = _PAGE_SZ256MB_4U; + pte_val(entry) |= _PAGE_PMD_HUGE; + break; + case HPAGE_SHIFT: + pte_val(entry) |= _PAGE_PMD_HUGE; + break; + case HPAGE_64K_SHIFT: + hugepage_size = _PAGE_SZ64K_4U; + break; + default: + WARN_ONCE(1, "unsupported hugepage shift=%u\n", shift); + } + + pte_val(entry) = pte_val(entry) | hugepage_size; return entry; } From 3751aa6e7147791e0c0c446f5f55c61762886a2f Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sat, 9 Aug 2025 22:33:01 +0800 Subject: [PATCH 1762/2711] sparc64: Remove redundant __GFP_NOWARN Commit 16f5dfbc851b ("gfp: include __GFP_NOWARN in GFP_NOWAIT") made GFP_NOWAIT implicitly include __GFP_NOWARN. Therefore, explicit __GFP_NOWARN combined with GFP_NOWAIT (e.g., `GFP_NOWAIT | __GFP_NOWARN`) is now redundant. Let's clean up these redundant flags across subsystems. No functional changes. Signed-off-by: Qianfeng Rong Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/kernel/adi_64.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sparc/kernel/adi_64.c b/arch/sparc/kernel/adi_64.c index e0e4fc527b24..18036a43cf56 100644 --- a/arch/sparc/kernel/adi_64.c +++ b/arch/sparc/kernel/adi_64.c @@ -202,7 +202,7 @@ static tag_storage_desc_t *alloc_tag_store(struct mm_struct *mm, } else { size = sizeof(tag_storage_desc_t)*max_desc; - mm->context.tag_store = kzalloc(size, GFP_NOWAIT|__GFP_NOWARN); + mm->context.tag_store = kzalloc(size, GFP_NOWAIT); if (mm->context.tag_store == NULL) { tag_desc = NULL; goto out; @@ -281,7 +281,7 @@ static tag_storage_desc_t *alloc_tag_store(struct mm_struct *mm, size = (size + (PAGE_SIZE-adi_blksize()))/PAGE_SIZE; size = size * PAGE_SIZE; } - tags = kzalloc(size, GFP_NOWAIT|__GFP_NOWARN); + tags = kzalloc(size, GFP_NOWAIT); if (tags == NULL) { tag_desc->tag_users = 0; tag_desc = NULL; From 7205ef77dfe167df1b83aea28cf00fc02d662990 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 10 Aug 2025 04:42:08 +0100 Subject: [PATCH 1763/2711] sparc64: fix prototypes of reads[bwl]() Conventions for readsl() are the same as for readl() - any __iomem pointer is acceptable, both const and volatile ones being OK. Same for readsb() and readsw(). Signed-off-by: Al Viro Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson # Making sparc64 subject prefix --- arch/sparc/include/asm/io_64.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h index c9528e4719cd..d8ed296624af 100644 --- a/arch/sparc/include/asm/io_64.h +++ b/arch/sparc/include/asm/io_64.h @@ -250,19 +250,19 @@ void insl(unsigned long, void *, unsigned long); #define insw insw #define insl insl -static inline void readsb(void __iomem *port, void *buf, unsigned long count) +static inline void readsb(const volatile void __iomem *port, void *buf, unsigned long count) { insb((unsigned long __force)port, buf, count); } #define readsb readsb -static inline void readsw(void __iomem *port, void *buf, unsigned long count) +static inline void readsw(const volatile void __iomem *port, void *buf, unsigned long count) { insw((unsigned long __force)port, buf, count); } #define readsw readsw -static inline void readsl(void __iomem *port, void *buf, unsigned long count) +static inline void readsl(const volatile void __iomem *port, void *buf, unsigned long count) { insl((unsigned long __force)port, buf, count); } From 4fba1713001195e59cfc001ff1f2837dab877efb Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 5 Sep 2025 00:03:30 +0200 Subject: [PATCH 1764/2711] sparc: fix accurate exception reporting in copy_{from_to}_user for UltraSPARC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The referenced commit introduced exception handlers on user-space memory references in copy_from_user and copy_to_user. These handlers return from the respective function and calculate the remaining bytes left to copy using the current register contents. This commit fixes a couple of bad calculations. This will fix the return value of copy_from_user and copy_to_user in the faulting case. The behaviour of memcpy stays unchanged. Fixes: cb736fdbb208 ("sparc64: Convert U1copy_{from,to}_user to accurate exception reporting.") Tested-by: John Paul Adrian Glaubitz # on QEMU 10.0.3 Tested-by: René Rebe # on Ultra 5 UltraSparc IIi Tested-by: Jonathan 'theJPster' Pallant # on Sun Netra T1 Signed-off-by: Michael Karcher Reviewed-by: Andreas Larsson Link: https://lore.kernel.org/r/20250905-memcpy_series-v4-1-1ca72dda195b@mkarcher.dialup.fu-berlin.de Signed-off-by: Andreas Larsson --- arch/sparc/lib/U1memcpy.S | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/sparc/lib/U1memcpy.S b/arch/sparc/lib/U1memcpy.S index 635398ec7540..154fbd35400c 100644 --- a/arch/sparc/lib/U1memcpy.S +++ b/arch/sparc/lib/U1memcpy.S @@ -164,17 +164,18 @@ ENTRY(U1_gs_40_fp) retl add %o0, %o2, %o0 ENDPROC(U1_gs_40_fp) -ENTRY(U1_g3_0_fp) - VISExitHalf - retl - add %g3, %o2, %o0 -ENDPROC(U1_g3_0_fp) ENTRY(U1_g3_8_fp) VISExitHalf add %g3, 8, %g3 retl add %g3, %o2, %o0 ENDPROC(U1_g3_8_fp) +ENTRY(U1_g3_16_fp) + VISExitHalf + add %g3, 16, %g3 + retl + add %g3, %o2, %o0 +ENDPROC(U1_g3_16_fp) ENTRY(U1_o2_0_fp) VISExitHalf retl @@ -547,18 +548,18 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ 62: FINISH_VISCHUNK(o0, f44, f46) 63: UNEVEN_VISCHUNK_LAST(o0, f46, f0) -93: EX_LD_FP(LOAD(ldd, %o1, %f2), U1_g3_0_fp) +93: EX_LD_FP(LOAD(ldd, %o1, %f2), U1_g3_8_fp) add %o1, 8, %o1 subcc %g3, 8, %g3 faligndata %f0, %f2, %f8 - EX_ST_FP(STORE(std, %f8, %o0), U1_g3_8_fp) + EX_ST_FP(STORE(std, %f8, %o0), U1_g3_16_fp) bl,pn %xcc, 95f add %o0, 8, %o0 - EX_LD_FP(LOAD(ldd, %o1, %f0), U1_g3_0_fp) + EX_LD_FP(LOAD(ldd, %o1, %f0), U1_g3_8_fp) add %o1, 8, %o1 subcc %g3, 8, %g3 faligndata %f2, %f0, %f8 - EX_ST_FP(STORE(std, %f8, %o0), U1_g3_8_fp) + EX_ST_FP(STORE(std, %f8, %o0), U1_g3_16_fp) bge,pt %xcc, 93b add %o0, 8, %o0 From 47b49c06eb62504075f0f2e2227aee2e2c2a58b3 Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 5 Sep 2025 00:03:31 +0200 Subject: [PATCH 1765/2711] sparc: fix accurate exception reporting in copy_{from_to}_user for UltraSPARC III MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Anthony Yznaga tracked down that a BUG_ON in ext4 code with large folios enabled resulted from copy_from_user() returning impossibly large values greater than the size to be copied. This lead to __copy_from_iter() returning impossible values instead of the actual number of bytes it was able to copy. The BUG_ON has been reported in https://lore.kernel.org/r/b14f55642207e63e907965e209f6323a0df6dcee.camel@physik.fu-berlin.de The referenced commit introduced exception handlers on user-space memory references in copy_from_user and copy_to_user. These handlers return from the respective function and calculate the remaining bytes left to copy using the current register contents. The exception handlers expect that %o2 has already been masked during the bulk copy loop, but the masking was performed after that loop. This will fix the return value of copy_from_user and copy_to_user in the faulting case. The behaviour of memcpy stays unchanged. Fixes: ee841d0aff64 ("sparc64: Convert U3copy_{from,to}_user to accurate exception reporting.") Tested-by: John Paul Adrian Glaubitz # on Sun Netra 240 Reviewed-by: Anthony Yznaga Tested-by: René Rebe # on UltraSparc III+ and UltraSparc IIIi Signed-off-by: Michael Karcher Reviewed-by: Andreas Larsson Link: https://lore.kernel.org/r/20250905-memcpy_series-v4-2-1ca72dda195b@mkarcher.dialup.fu-berlin.de Signed-off-by: Andreas Larsson --- arch/sparc/lib/U3memcpy.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/lib/U3memcpy.S b/arch/sparc/lib/U3memcpy.S index 9248d59c734c..bace3a18f836 100644 --- a/arch/sparc/lib/U3memcpy.S +++ b/arch/sparc/lib/U3memcpy.S @@ -267,6 +267,7 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ faligndata %f10, %f12, %f26 EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0), U3_retl_o2) + and %o2, 0x3f, %o2 subcc GLOBAL_SPARE, 0x80, GLOBAL_SPARE add %o1, 0x40, %o1 bgu,pt %XCC, 1f @@ -336,7 +337,6 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ * Also notice how this code is careful not to perform a * load past the end of the src buffer. */ - and %o2, 0x3f, %o2 andcc %o2, 0x38, %g2 be,pn %XCC, 2f subcc %g2, 0x8, %g2 From 0b67c8fc10b13a9090340c5f8a37d308f4e1571c Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 5 Sep 2025 00:03:32 +0200 Subject: [PATCH 1766/2711] sparc: fix accurate exception reporting in copy_{from_to}_user for Niagara The referenced commit introduced exception handlers on user-space memory references in copy_from_user and copy_to_user. These handlers return from the respective function and calculate the remaining bytes left to copy using the current register contents. This commit fixes a couple of bad calculations and a broken epilogue in the exception handlers. This will prevent crashes and ensure correct return values of copy_from_user and copy_to_user in the faulting case. The behaviour of memcpy stays unchanged. Fixes: 7ae3aaf53f16 ("sparc64: Convert NGcopy_{from,to}_user to accurate exception reporting.") Tested-by: John Paul Adrian Glaubitz # on SPARC T4 with modified kernel to use Niagara 1 code Tested-by: Magnus Lindholm # on Sun Fire T2000 Signed-off-by: Michael Karcher Tested-by: Ethan Hawke # on Sun Fire T2000 Tested-by: Ken Link # on Sun Fire T1000 Reviewed-by: Andreas Larsson Link: https://lore.kernel.org/r/20250905-memcpy_series-v4-3-1ca72dda195b@mkarcher.dialup.fu-berlin.de Signed-off-by: Andreas Larsson --- arch/sparc/lib/NGmemcpy.S | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/arch/sparc/lib/NGmemcpy.S b/arch/sparc/lib/NGmemcpy.S index ee51c1230689..bbd3ea0a6482 100644 --- a/arch/sparc/lib/NGmemcpy.S +++ b/arch/sparc/lib/NGmemcpy.S @@ -79,8 +79,8 @@ #ifndef EX_RETVAL #define EX_RETVAL(x) x __restore_asi: - ret wr %g0, ASI_AIUS, %asi + ret restore ENTRY(NG_ret_i2_plus_i4_plus_1) ba,pt %xcc, __restore_asi @@ -125,15 +125,16 @@ ENTRY(NG_ret_i2_plus_g1_minus_56) ba,pt %xcc, __restore_asi add %i2, %g1, %i0 ENDPROC(NG_ret_i2_plus_g1_minus_56) -ENTRY(NG_ret_i2_plus_i4) +ENTRY(NG_ret_i2_plus_i4_plus_16) + add %i4, 16, %i4 ba,pt %xcc, __restore_asi add %i2, %i4, %i0 -ENDPROC(NG_ret_i2_plus_i4) -ENTRY(NG_ret_i2_plus_i4_minus_8) - sub %i4, 8, %i4 +ENDPROC(NG_ret_i2_plus_i4_plus_16) +ENTRY(NG_ret_i2_plus_i4_plus_8) + add %i4, 8, %i4 ba,pt %xcc, __restore_asi add %i2, %i4, %i0 -ENDPROC(NG_ret_i2_plus_i4_minus_8) +ENDPROC(NG_ret_i2_plus_i4_plus_8) ENTRY(NG_ret_i2_plus_8) ba,pt %xcc, __restore_asi add %i2, 8, %i0 @@ -160,6 +161,12 @@ ENTRY(NG_ret_i2_and_7_plus_i4) ba,pt %xcc, __restore_asi add %i2, %i4, %i0 ENDPROC(NG_ret_i2_and_7_plus_i4) +ENTRY(NG_ret_i2_and_7_plus_i4_plus_8) + and %i2, 7, %i2 + add %i4, 8, %i4 + ba,pt %xcc, __restore_asi + add %i2, %i4, %i0 +ENDPROC(NG_ret_i2_and_7_plus_i4) #endif .align 64 @@ -405,13 +412,13 @@ FUNC_NAME: /* %i0=dst, %i1=src, %i2=len */ andn %i2, 0xf, %i4 and %i2, 0xf, %i2 1: subcc %i4, 0x10, %i4 - EX_LD(LOAD(ldx, %i1, %o4), NG_ret_i2_plus_i4) + EX_LD(LOAD(ldx, %i1, %o4), NG_ret_i2_plus_i4_plus_16) add %i1, 0x08, %i1 - EX_LD(LOAD(ldx, %i1, %g1), NG_ret_i2_plus_i4) + EX_LD(LOAD(ldx, %i1, %g1), NG_ret_i2_plus_i4_plus_16) sub %i1, 0x08, %i1 - EX_ST(STORE(stx, %o4, %i1 + %i3), NG_ret_i2_plus_i4) + EX_ST(STORE(stx, %o4, %i1 + %i3), NG_ret_i2_plus_i4_plus_16) add %i1, 0x8, %i1 - EX_ST(STORE(stx, %g1, %i1 + %i3), NG_ret_i2_plus_i4_minus_8) + EX_ST(STORE(stx, %g1, %i1 + %i3), NG_ret_i2_plus_i4_plus_8) bgu,pt %XCC, 1b add %i1, 0x8, %i1 73: andcc %i2, 0x8, %g0 @@ -468,7 +475,7 @@ FUNC_NAME: /* %i0=dst, %i1=src, %i2=len */ subcc %i4, 0x8, %i4 srlx %g3, %i3, %i5 or %i5, %g2, %i5 - EX_ST(STORE(stx, %i5, %o0), NG_ret_i2_and_7_plus_i4) + EX_ST(STORE(stx, %i5, %o0), NG_ret_i2_and_7_plus_i4_plus_8) add %o0, 0x8, %o0 bgu,pt %icc, 1b sllx %g3, %g1, %g2 From 5a746c1a2c7980de6c888b6373299f751ad7790b Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 5 Sep 2025 00:03:33 +0200 Subject: [PATCH 1767/2711] sparc: fix accurate exception reporting in copy_to_user for Niagara 4 The referenced commit introduced exception handlers on user-space memory references in copy_from_user and copy_to_user. These handlers return from the respective function and calculate the remaining bytes left to copy using the current register contents. This commit fixes a bad calculation. This will fix the return value of copy_to_user in a specific faulting case. The behaviour of memcpy stays unchanged. Fixes: 957077048009 ("sparc64: Convert NG4copy_{from,to}_user to accurate exception reporting.") Tested-by: John Paul Adrian Glaubitz # on Oracle SPARC T4-1 Signed-off-by: Michael Karcher Reviewed-by: Andreas Larsson Link: https://lore.kernel.org/r/20250905-memcpy_series-v4-4-1ca72dda195b@mkarcher.dialup.fu-berlin.de Signed-off-by: Andreas Larsson --- arch/sparc/lib/NG4memcpy.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/lib/NG4memcpy.S b/arch/sparc/lib/NG4memcpy.S index 7ad58ebe0d00..df0ec1bd1948 100644 --- a/arch/sparc/lib/NG4memcpy.S +++ b/arch/sparc/lib/NG4memcpy.S @@ -281,7 +281,7 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ subcc %o5, 0x20, %o5 EX_ST(STORE(stx, %g1, %o0 + 0x00), memcpy_retl_o2_plus_o5_plus_32) EX_ST(STORE(stx, %g2, %o0 + 0x08), memcpy_retl_o2_plus_o5_plus_24) - EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x10), memcpy_retl_o2_plus_o5_plus_24) + EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x10), memcpy_retl_o2_plus_o5_plus_16) EX_ST(STORE(stx, %o4, %o0 + 0x18), memcpy_retl_o2_plus_o5_plus_8) bne,pt %icc, 1b add %o0, 0x20, %o0 From 936fb512752af349fc30ccbe0afe14a2ae6d7159 Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 5 Sep 2025 00:03:34 +0200 Subject: [PATCH 1768/2711] sparc: fix accurate exception reporting in copy_{from,to}_user for M7 The referenced commit introduced exception handlers on user-space memory references in copy_from_user and copy_to_user. These handlers return from the respective function and calculate the remaining bytes left to copy using the current register contents. This commit fixes a couple of bad calculations. This will fix the return value of copy_from_user and copy_to_user in the faulting case. The behaviour of memcpy stays unchanged. Fixes: 34060b8fffa7 ("arch/sparc: Add accurate exception reporting in M7memcpy") Tested-by: John Paul Adrian Glaubitz # on Oracle SPARC S7 Tested-by: Tony Rodriguez # S7, see https://lore.kernel.org/r/98564e2e68df2dda0e00c67a75c7f7dfedb33c7e.camel@physik.fu-berlin.de Signed-off-by: Michael Karcher Reviewed-by: Andreas Larsson Link: https://lore.kernel.org/r/20250905-memcpy_series-v4-5-1ca72dda195b@mkarcher.dialup.fu-berlin.de Signed-off-by: Andreas Larsson --- arch/sparc/lib/M7memcpy.S | 20 ++++++++++---------- arch/sparc/lib/Memcpy_utils.S | 9 +++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/arch/sparc/lib/M7memcpy.S b/arch/sparc/lib/M7memcpy.S index cbd42ea7c3f7..99357bfa8e82 100644 --- a/arch/sparc/lib/M7memcpy.S +++ b/arch/sparc/lib/M7memcpy.S @@ -696,16 +696,16 @@ FUNC_NAME: EX_LD_FP(LOAD(ldd, %o4+40, %f26), memcpy_retl_o2_plus_o5_plus_40) faligndata %f24, %f26, %f10 EX_ST_FP(STORE(std, %f6, %o0+24), memcpy_retl_o2_plus_o5_plus_40) - EX_LD_FP(LOAD(ldd, %o4+48, %f28), memcpy_retl_o2_plus_o5_plus_40) + EX_LD_FP(LOAD(ldd, %o4+48, %f28), memcpy_retl_o2_plus_o5_plus_32) faligndata %f26, %f28, %f12 - EX_ST_FP(STORE(std, %f8, %o0+32), memcpy_retl_o2_plus_o5_plus_40) + EX_ST_FP(STORE(std, %f8, %o0+32), memcpy_retl_o2_plus_o5_plus_32) add %o4, 64, %o4 - EX_LD_FP(LOAD(ldd, %o4-8, %f30), memcpy_retl_o2_plus_o5_plus_40) + EX_LD_FP(LOAD(ldd, %o4-8, %f30), memcpy_retl_o2_plus_o5_plus_24) faligndata %f28, %f30, %f14 - EX_ST_FP(STORE(std, %f10, %o0+40), memcpy_retl_o2_plus_o5_plus_40) - EX_ST_FP(STORE(std, %f12, %o0+48), memcpy_retl_o2_plus_o5_plus_40) + EX_ST_FP(STORE(std, %f10, %o0+40), memcpy_retl_o2_plus_o5_plus_24) + EX_ST_FP(STORE(std, %f12, %o0+48), memcpy_retl_o2_plus_o5_plus_16) add %o0, 64, %o0 - EX_ST_FP(STORE(std, %f14, %o0-8), memcpy_retl_o2_plus_o5_plus_40) + EX_ST_FP(STORE(std, %f14, %o0-8), memcpy_retl_o2_plus_o5_plus_8) fsrc2 %f30, %f14 bgu,pt %xcc, .Lunalign_sloop prefetch [%o4 + (8 * BLOCK_SIZE)], 20 @@ -728,7 +728,7 @@ FUNC_NAME: add %o4, 8, %o4 faligndata %f0, %f2, %f16 subcc %o5, 8, %o5 - EX_ST_FP(STORE(std, %f16, %o0), memcpy_retl_o2_plus_o5) + EX_ST_FP(STORE(std, %f16, %o0), memcpy_retl_o2_plus_o5_plus_8) fsrc2 %f2, %f0 bgu,pt %xcc, .Lunalign_by8 add %o0, 8, %o0 @@ -772,7 +772,7 @@ FUNC_NAME: subcc %o5, 0x20, %o5 EX_ST(STORE(stx, %o3, %o0 + 0x00), memcpy_retl_o2_plus_o5_plus_32) EX_ST(STORE(stx, %g2, %o0 + 0x08), memcpy_retl_o2_plus_o5_plus_24) - EX_ST(STORE(stx, %g7, %o0 + 0x10), memcpy_retl_o2_plus_o5_plus_24) + EX_ST(STORE(stx, %g7, %o0 + 0x10), memcpy_retl_o2_plus_o5_plus_16) EX_ST(STORE(stx, %o4, %o0 + 0x18), memcpy_retl_o2_plus_o5_plus_8) bne,pt %xcc, 1b add %o0, 0x20, %o0 @@ -804,12 +804,12 @@ FUNC_NAME: brz,pt %o3, 2f sub %o2, %o3, %o2 -1: EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1) +1: EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_o3) add %o1, 1, %o1 subcc %o3, 1, %o3 add %o0, 1, %o0 bne,pt %xcc, 1b - EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_g1_plus_1) + EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_o3_plus_1) 2: and %o1, 0x7, %o3 brz,pn %o3, .Lmedium_noprefetch_cp diff --git a/arch/sparc/lib/Memcpy_utils.S b/arch/sparc/lib/Memcpy_utils.S index 64fbac28b3db..207343367bb2 100644 --- a/arch/sparc/lib/Memcpy_utils.S +++ b/arch/sparc/lib/Memcpy_utils.S @@ -137,6 +137,15 @@ ENTRY(memcpy_retl_o2_plus_63_8) ba,pt %xcc, __restore_asi add %o2, 8, %o0 ENDPROC(memcpy_retl_o2_plus_63_8) +ENTRY(memcpy_retl_o2_plus_o3) + ba,pt %xcc, __restore_asi + add %o2, %o3, %o0 +ENDPROC(memcpy_retl_o2_plus_o3) +ENTRY(memcpy_retl_o2_plus_o3_plus_1) + add %o3, 1, %o3 + ba,pt %xcc, __restore_asi + add %o2, %o3, %o0 +ENDPROC(memcpy_retl_o2_plus_o3_plus_1) ENTRY(memcpy_retl_o2_plus_o5) ba,pt %xcc, __restore_asi add %o2, %o5, %o0 From 5519b69183c80fbbed8d6eb6dcdf63ba52090d77 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 8 Sep 2025 11:19:18 -0700 Subject: [PATCH 1769/2711] tools build: Make libperl opt-in rather than opt-out, deprecate If libperl is installed then the perf tool build will build against it. There appears to be limited interest in the scripting support for perl so let's make it opt-in and deprecate it. With this patch applied you need to add LIBPERL=1 to get libperl support in perf - there is no warning if libperl is missing, but building will fail if libperl is missing and the build has LIBPERL=1. The perf version output is changed to: ``` $ perf version --build-options perf version 6.17.rc3.g8eca69269947 aio: [ on ] # HAVE_AIO_SUPPORT bpf: [ on ] # HAVE_LIBBPF_SUPPORT bpf_skeletons: [ on ] # HAVE_BPF_SKEL debuginfod: [ on ] # HAVE_DEBUGINFOD_SUPPORT dwarf: [ on ] # HAVE_LIBDW_SUPPORT dwarf_getlocations: [ on ] # HAVE_LIBDW_SUPPORT dwarf-unwind: [ on ] # HAVE_DWARF_UNWIND_SUPPORT auxtrace: [ on ] # HAVE_AUXTRACE_SUPPORT libbfd: [ OFF ] # HAVE_LIBBFD_SUPPORT ( tip: Deprecated, license incompatibility, use BUILD_NONDISTRO=1 and install binutils-dev[el] ) libbpf-strings: [ on ] # HAVE_LIBBPF_STRINGS_SUPPORT libcapstone: [ on ] # HAVE_LIBCAPSTONE_SUPPORT libdw-dwarf-unwind: [ on ] # HAVE_LIBDW_SUPPORT libelf: [ on ] # HAVE_LIBELF_SUPPORT libnuma: [ on ] # HAVE_LIBNUMA_SUPPORT libopencsd: [ OFF ] # HAVE_CSTRACE_SUPPORT libperl: [ OFF ] # HAVE_LIBPERL_SUPPORT ( tip: Deprecated, use LIBPERL=1 and install libperl-dev to build with it ) libpfm4: [ on ] # HAVE_LIBPFM libpython: [ on ] # HAVE_LIBPYTHON_SUPPORT libslang: [ on ] # HAVE_SLANG_SUPPORT libtraceevent: [ on ] # HAVE_LIBTRACEEVENT libunwind: [ OFF ] # HAVE_LIBUNWIND_SUPPORT ( tip: Deprecated, use LIBUNWIND=1 and install libunwind-dev[el] to build with it ) lzma: [ on ] # HAVE_LZMA_SUPPORT numa_num_possible_cpus: [ on ] # HAVE_LIBNUMA_SUPPORT zlib: [ on ] # HAVE_ZLIB_SUPPORT zstd: [ on ] # HAVE_ZSTD_SUPPORT ``` i.e. there is a tip saying about deprecation and how to get support back. Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Charlie Jenkins Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Michael Petlan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Quentin Monnet Cc: Steven Rostedt (VMware) Cc: Tomas Glozar Cc: Yuzhuo Jing Link: https://lore.kernel.org/lkml/aMrk03gigBlGcYLK@x1/ Link: https://lore.kernel.org/lkml/CAP-5=fVX+bLBRJCiziDi_hBySgv2NFtDoghtpheSSxVAvvETGw@mail.gmail.com [ Keep the pre-existing perl-ExtUtils-Embed hint for Fedora/RHEL systems ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Makefile.feature | 3 +-- tools/build/feature/test-all.c | 9 ++------- tools/perf/Makefile.config | 12 +++--------- tools/perf/Makefile.perf | 4 ++-- tools/perf/builtin-check.c | 2 +- tools/perf/tests/make | 8 ++++---- 6 files changed, 13 insertions(+), 25 deletions(-) diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 649c5ab8e8f2..9c1a69d26f51 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -80,7 +80,6 @@ FEATURE_TESTS_BASIC := \ libelf-zstd \ libnuma \ numa_num_possible_cpus \ - libperl \ libpython \ libslang \ libtraceevent \ @@ -121,6 +120,7 @@ FEATURE_TESTS_EXTRA := \ libbfd-liberty \ libbfd-liberty-z \ libopencsd \ + libperl \ cxx \ llvm \ clang \ @@ -144,7 +144,6 @@ FEATURE_DISPLAY ?= \ libelf \ libnuma \ numa_num_possible_cpus \ - libperl \ libpython \ libcapstone \ llvm-perf \ diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c index 4419fb4710bd..e1847db6f8e6 100644 --- a/tools/build/feature/test-all.c +++ b/tools/build/feature/test-all.c @@ -7,17 +7,13 @@ */ /* - * Quirk: Python and Perl headers cannot be in arbitrary places, so keep - * these 3 testcases at the top: + * Quirk: Python headers cannot be in arbitrary places, so keep this testcase at + * the top: */ #define main main_test_libpython # include "test-libpython.c" #undef main -#define main main_test_libperl -# include "test-libperl.c" -#undef main - #define main main_test_hello # include "test-hello.c" #undef main @@ -161,7 +157,6 @@ int main(int argc, char *argv[]) { main_test_libpython(); - main_test_libperl(); main_test_hello(); main_test_libelf(); main_test_get_current_dir_name(); diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 5a5832ee7b53..0f4b297fbacc 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -817,9 +817,7 @@ ifdef GTK2 endif endif -ifdef NO_LIBPERL - CFLAGS += -DNO_LIBPERL -else +ifdef LIBPERL PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null) PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS)) PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) @@ -829,17 +827,13 @@ else PERL_EMBED_LDOPTS := $(filter-out -specs=%,$(PERL_EMBED_LDOPTS)) FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) + $(call feature_check,libperl) ifneq ($(feature-libperl), 1) - CFLAGS += -DNO_LIBPERL - NO_LIBPERL := 1 - $(warning Missing perl devel files. Disabling perl scripting support, please install perl-ExtUtils-Embed/libperl-dev) + $(error Missing perl devel files. Please install perl-ExtUtils-Embed/libperl-dev) else LDFLAGS += $(PERL_EMBED_LDFLAGS) EXTLIBS += $(PERL_EMBED_LIBADD) CFLAGS += -DHAVE_LIBPERL_SUPPORT - ifeq ($(CC_NO_CLANG), 0) - CFLAGS += -Wno-compound-token-split-by-macro - endif $(call detected,CONFIG_LIBPERL) endif endif diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index e2150acc2c13..7d6ac03a7109 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -17,7 +17,7 @@ include ../scripts/utilities.mak # # Define CROSS_COMPILE as prefix name of compiler if you want cross-builds. # -# Define NO_LIBPERL to disable perl script extension. +# Define LIBPERL to enable perl script extension. # # Define NO_LIBPYTHON to disable python script extension. # @@ -1103,7 +1103,7 @@ endif $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' $(call QUIET_INSTALL, perf-iostat) \ $(INSTALL) $(OUTPUT)perf-iostat -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' -ifndef NO_LIBPERL +ifdef LIBPERL $(call QUIET_INSTALL, perl-scripts) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \ $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \ diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c index b1e205871ab1..7fd054760e47 100644 --- a/tools/perf/builtin-check.c +++ b/tools/perf/builtin-check.c @@ -49,7 +49,7 @@ struct feature_status supported_features[] = { FEATURE_STATUS("libelf", HAVE_LIBELF_SUPPORT), FEATURE_STATUS("libnuma", HAVE_LIBNUMA_SUPPORT), FEATURE_STATUS("libopencsd", HAVE_CSTRACE_SUPPORT), - FEATURE_STATUS("libperl", HAVE_LIBPERL_SUPPORT), + FEATURE_STATUS_TIP("libperl", HAVE_LIBPERL_SUPPORT, "Deprecated, use LIBPERL=1 and install perl-ExtUtils-Embed/libperl-dev to build with it"), FEATURE_STATUS("libpfm4", HAVE_LIBPFM), FEATURE_STATUS("libpython", HAVE_LIBPYTHON_SUPPORT), FEATURE_STATUS("libslang", HAVE_SLANG_SUPPORT), diff --git a/tools/perf/tests/make b/tools/perf/tests/make index c574a678c28a..b650ce8864ed 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -73,9 +73,9 @@ make_extra_tests := EXTRA_TESTS=1 make_jevents_all := JEVENTS_ARCH=all make_no_bpf_skel := BUILD_BPF_SKEL=0 make_gen_vmlinux_h := GEN_VMLINUX_H=1 -make_no_libperl := NO_LIBPERL=1 +make_libperl := LIBPERL=1 make_no_libpython := NO_LIBPYTHON=1 -make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1 +make_no_scripts := NO_LIBPYTHON=1 make_no_slang := NO_SLANG=1 make_no_gtk2 := NO_GTK2=1 make_no_ui := NO_SLANG=1 NO_GTK2=1 @@ -118,7 +118,7 @@ make_install_prefix_slash := install prefix=/tmp/krava/ make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 NO_LIBTRACEEVENT=1 NO_LIBELF=1 # all the NO_* variable combined -make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_GTK2=1 +make_minimal := NO_LIBPYTHON=1 NO_GTK2=1 make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_BACKTRACE=1 make_minimal += NO_LIBNUMA=1 NO_LIBBIONIC=1 NO_LIBDW=1 make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 @@ -143,7 +143,7 @@ run += make_extra_tests run += make_jevents_all run += make_no_bpf_skel run += make_gen_vmlinux_h -run += make_no_libperl +run += make_libperl run += make_no_libpython run += make_no_scripts run += make_no_slang From 48918cacefd226af44373e914e63304927c0e7dc Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 18 Sep 2025 15:22:00 -0700 Subject: [PATCH 1770/2711] perf test: Don't leak workload gopipe in PERF_RECORD_* The test starts a workload and then opens events. If the events fail to open, for example because of perf_event_paranoid, the gopipe of the workload is leaked and the file descriptor leak check fails when the test exits. To avoid this cancel the workload when opening the events fails. Before: ``` $ perf test -vv 7 7: PERF_RECORD_* events & perf_sample fields: --- start --- test child forked, pid 1189568 Using CPUID GenuineIntel-6-B7-1 ------------------------------------------------------------ perf_event_attr: type 0 (PERF_TYPE_HARDWARE) config 0xa00000000 (cpu_atom/PERF_COUNT_HW_CPU_CYCLES/) disabled 1 ------------------------------------------------------------ sys_perf_event_open: pid 0 cpu -1 group_fd -1 flags 0x8 sys_perf_event_open failed, error -13 ------------------------------------------------------------ perf_event_attr: type 0 (PERF_TYPE_HARDWARE) config 0xa00000000 (cpu_atom/PERF_COUNT_HW_CPU_CYCLES/) disabled 1 exclude_kernel 1 ------------------------------------------------------------ sys_perf_event_open: pid 0 cpu -1 group_fd -1 flags 0x8 = 3 ------------------------------------------------------------ perf_event_attr: type 0 (PERF_TYPE_HARDWARE) config 0x400000000 (cpu_core/PERF_COUNT_HW_CPU_CYCLES/) disabled 1 ------------------------------------------------------------ sys_perf_event_open: pid 0 cpu -1 group_fd -1 flags 0x8 sys_perf_event_open failed, error -13 ------------------------------------------------------------ perf_event_attr: type 0 (PERF_TYPE_HARDWARE) config 0x400000000 (cpu_core/PERF_COUNT_HW_CPU_CYCLES/) disabled 1 exclude_kernel 1 ------------------------------------------------------------ sys_perf_event_open: pid 0 cpu -1 group_fd -1 flags 0x8 = 3 Attempt to add: software/cpu-clock/ ..after resolving event: software/config=0/ cpu-clock -> software/cpu-clock/ ------------------------------------------------------------ perf_event_attr: type 1 (PERF_TYPE_SOFTWARE) size 136 config 0x9 (PERF_COUNT_SW_DUMMY) sample_type IP|TID|TIME|CPU read_format ID|LOST disabled 1 inherit 1 mmap 1 comm 1 enable_on_exec 1 task 1 sample_id_all 1 mmap2 1 comm_exec 1 ksymbol 1 bpf_event 1 { wakeup_events, wakeup_watermark } 1 ------------------------------------------------------------ sys_perf_event_open: pid 1189569 cpu 0 group_fd -1 flags 0x8 sys_perf_event_open failed, error -13 perf_evlist__open: Permission denied ---- end(-2) ---- Leak of file descriptor 6 that opened: 'pipe:[14200347]' ---- unexpected signal (6) ---- iFailed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon Failed to read build ID for //anon #0 0x565358f6666e in child_test_sig_handler builtin-test.c:311 #1 0x7f29ce849df0 in __restore_rt libc_sigaction.c:0 #2 0x7f29ce89e95c in __pthread_kill_implementation pthread_kill.c:44 #3 0x7f29ce849cc2 in raise raise.c:27 #4 0x7f29ce8324ac in abort abort.c:81 #5 0x565358f662d4 in check_leaks builtin-test.c:226 #6 0x565358f6682e in run_test_child builtin-test.c:344 #7 0x565358ef7121 in start_command run-command.c:128 #8 0x565358f67273 in start_test builtin-test.c:545 #9 0x565358f6771d in __cmd_test builtin-test.c:647 #10 0x565358f682bd in cmd_test builtin-test.c:849 #11 0x565358ee5ded in run_builtin perf.c:349 #12 0x565358ee6085 in handle_internal_command perf.c:401 #13 0x565358ee61de in run_argv perf.c:448 #14 0x565358ee6527 in main perf.c:555 #15 0x7f29ce833ca8 in __libc_start_call_main libc_start_call_main.h:74 #16 0x7f29ce833d65 in __libc_start_main@@GLIBC_2.34 libc-start.c:128 #17 0x565358e391c1 in _start perf[851c1] 7: PERF_RECORD_* events & perf_sample fields : FAILED! ``` After: ``` $ perf test 7 7: PERF_RECORD_* events & perf_sample fields : Skip (permissions) ``` Fixes: 16d00fee703866c6 ("perf tests: Move test__PERF_RECORD into separate object") Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Chun-Tse Shao Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/perf-record.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index d895df037707..efbd9cd60c63 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -130,6 +130,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest if (err < 0) { pr_debug("sched__get_first_possible_cpu: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); + evlist__cancel_workload(evlist); goto out_delete_evlist; } @@ -141,6 +142,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) { pr_debug("sched_setaffinity: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); + evlist__cancel_workload(evlist); goto out_delete_evlist; } @@ -152,6 +154,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest if (err < 0) { pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); + evlist__cancel_workload(evlist); goto out_delete_evlist; } @@ -164,6 +167,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest if (err < 0) { pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); + evlist__cancel_workload(evlist); goto out_delete_evlist; } From 693101792e45eefc888c7ba10b91108047399f5d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 18 Sep 2025 15:22:01 -0700 Subject: [PATCH 1771/2711] perf evsel: Fix uniquification when PMU given without suffix The PMU name is appearing twice in: ``` $ perf stat -e uncore_imc_free_running/data_total/ -A true Performance counter stats for 'system wide': CPU0 1.57 MiB uncore_imc_free_running_0/uncore_imc_free_running,data_total/ CPU0 1.58 MiB uncore_imc_free_running_1/uncore_imc_free_running,data_total/ 0.000892376 seconds time elapsed ``` Use the pmu_name_len_no_suffix to avoid this problem. Committer testing: After this patch: root@x1:~# perf stat -e uncore_imc_free_running/data_total/ -A true Performance counter stats for 'system wide': CPU0 1.69 MiB uncore_imc_free_running_0/data_total/ CPU0 1.68 MiB uncore_imc_free_running_1/data_total/ 0.002141605 seconds time elapsed root@x1:~# Fixes: 7d45f402d3117e0b ("perf evlist: Make uniquifying counter names consistent") Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Chun-Tse Shao Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 6a31f9699b49..6947072598b1 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -4053,9 +4053,9 @@ bool evsel__set_needs_uniquify(struct evsel *counter, const struct perf_stat_con void evsel__uniquify_counter(struct evsel *counter) { - const char *name, *pmu_name; - char *new_name, *config; - int ret; + const char *name, *pmu_name, *config; + char *new_name; + int len, ret; /* No uniquification necessary. */ if (!counter->needs_uniquify) @@ -4069,15 +4069,23 @@ void evsel__uniquify_counter(struct evsel *counter) counter->uniquified_name = true; name = evsel__name(counter); - pmu_name = counter->pmu->name; - /* Already prefixed by the PMU name. */ - if (!strncmp(name, pmu_name, strlen(pmu_name))) - return; - config = strchr(name, '/'); - if (config) { - int len = config - name; + pmu_name = counter->pmu->name; + /* Already prefixed by the PMU name? */ + len = pmu_name_len_no_suffix(pmu_name); + + if (!strncmp(name, pmu_name, len)) { + /* + * If the PMU name is there, then there is no sense in not + * having a slash. Do this for robustness. + */ + if (config == NULL) + config = name - 1; + + ret = asprintf(&new_name, "%s/%s", pmu_name, config + 1); + } else if (config) { + len = config - name; if (config[1] == '/') { /* case: event// */ ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 2); @@ -4089,7 +4097,7 @@ void evsel__uniquify_counter(struct evsel *counter) config = strchr(name, ':'); if (config) { /* case: event:.. */ - int len = config - name; + len = config - name; ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 1); } else { From edaeb4bcf1511fe4e464fff9dd4a3abf6b0096da Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 18 Sep 2025 15:22:02 -0700 Subject: [PATCH 1772/2711] perf test: Avoid uncore_imc/clockticks in uniquification test The detection of uncore_imc may happen for free running PMUs and the clockticks event may be present on uncore_clock. Rewrite the test to detect duplicated/deduplicated events from perf list, not hardcoded to uncore_imc. If perf stat fails then assume it is permissions and skip the test. Committer testing: Before: root@x1:~# perf test -vv uniquifyi 96: perf stat events uniquifying: --- start --- test child forked, pid 220851 stat event uniquifying test grep: Unmatched [, [^, [:, [., or [= Event is not uniquified [Failed] perf stat -e clockticks -A -o /tmp/__perf_test.stat_output.X7ChD -- true # started on Fri Sep 19 16:48:38 2025 Performance counter stats for 'system wide': CPU0 2,310,956 uncore_clock/clockticks/ 0.001746771 seconds time elapsed ---- end(-1) ---- 96: perf stat events uniquifying : FAILED! root@x1:~# After: root@x1:~# perf test -vv uniquifyi 96: perf stat events uniquifying: --- start --- test child forked, pid 222366 Uniquification of PMU sysfs events test Testing event uncore_imc_free_running/data_read/ is uniquified to uncore_imc_free_running_0/data_read/ Testing event uncore_imc_free_running/data_total/ is uniquified to uncore_imc_free_running_0/data_total/ Testing event uncore_imc_free_running/data_write/ is uniquified to uncore_imc_free_running_0/data_write/ Testing event uncore_imc_free_running/data_read/ is uniquified to uncore_imc_free_running_1/data_read/ Testing event uncore_imc_free_running/data_total/ is uniquified to uncore_imc_free_running_1/data_total/ Testing event uncore_imc_free_running/data_write/ is uniquified to uncore_imc_free_running_1/data_write/ ---- end(0) ---- 96: perf stat events uniquifying : Ok root@x1:~# Fixes: 070b315333ee942f ("perf test: Restrict uniquifying test to machines with 'uncore_imc'") Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Chun-Tse Shao Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- .../tests/shell/stat+event_uniquifying.sh | 113 ++++++++---------- 1 file changed, 51 insertions(+), 62 deletions(-) diff --git a/tools/perf/tests/shell/stat+event_uniquifying.sh b/tools/perf/tests/shell/stat+event_uniquifying.sh index bf54bd6c3e2e..b5dec6b6da36 100755 --- a/tools/perf/tests/shell/stat+event_uniquifying.sh +++ b/tools/perf/tests/shell/stat+event_uniquifying.sh @@ -4,74 +4,63 @@ set -e -stat_output=$(mktemp /tmp/__perf_test.stat_output.XXXXX) -perf_tool=perf err=0 +stat_output=$(mktemp /tmp/__perf_test.stat_output.XXXXX) + +cleanup() { + rm -f "${stat_output}" + + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT test_event_uniquifying() { - # We use `clockticks` in `uncore_imc` to verify the uniquify behavior. - pmu="uncore_imc" - event="clockticks" + echo "Uniquification of PMU sysfs events test" - # If the `-A` option is added, the event should be uniquified. - # - # $perf list -v clockticks - # - # List of pre-defined events (to be used in -e or -M): - # - # uncore_imc_0/clockticks/ [Kernel PMU event] - # uncore_imc_1/clockticks/ [Kernel PMU event] - # uncore_imc_2/clockticks/ [Kernel PMU event] - # uncore_imc_3/clockticks/ [Kernel PMU event] - # uncore_imc_4/clockticks/ [Kernel PMU event] - # uncore_imc_5/clockticks/ [Kernel PMU event] - # - # ... - # - # $perf stat -e clockticks -A -- true - # - # Performance counter stats for 'system wide': - # - # CPU0 3,773,018 uncore_imc_0/clockticks/ - # CPU0 3,609,025 uncore_imc_1/clockticks/ - # CPU0 0 uncore_imc_2/clockticks/ - # CPU0 3,230,009 uncore_imc_3/clockticks/ - # CPU0 3,049,897 uncore_imc_4/clockticks/ - # CPU0 0 uncore_imc_5/clockticks/ - # - # 0.002029828 seconds time elapsed - - echo "stat event uniquifying test" - uniquified_event_array=() - - # Skip if the machine does not have `uncore_imc` device. - if ! ${perf_tool} list pmu | grep -q ${pmu}; then - echo "Target does not support PMU ${pmu} [Skipped]" - err=2 - return - fi - - # Check how many uniquified events. - while IFS= read -r line; do - uniquified_event=$(echo "$line" | awk '{print $1}') - uniquified_event_array+=("${uniquified_event}") - done < <(${perf_tool} list -v ${event} | grep ${pmu}) - - perf_command="${perf_tool} stat -e $event -A -o ${stat_output} -- true" - $perf_command - - # Check the output contains all uniquified events. - for uniquified_event in "${uniquified_event_array[@]}"; do - if ! cat "${stat_output}" | grep -q "${uniquified_event}"; then - echo "Event is not uniquified [Failed]" - echo "${perf_command}" - cat "${stat_output}" - err=1 - break - fi + # Read events from perf list with and without -v. With -v the duplicate PMUs + # aren't deduplicated. Note, json events are listed by perf list without a + # PMU. + read -ra pmu_events <<< "$(perf list --raw pmu)" + read -ra pmu_v_events <<< "$(perf list -v --raw pmu)" + # For all non-deduplicated events. + for pmu_v_event in "${pmu_v_events[@]}"; do + # If the event matches an event in the deduplicated events then it musn't + # be an event with duplicate PMUs, continue the outer loop. + for pmu_event in "${pmu_events[@]}"; do + if [[ "$pmu_v_event" == "$pmu_event" ]]; then + continue 2 + fi + done + # Strip the suffix from the non-deduplicated event's PMU. + event=$(echo "$pmu_v_event" | sed -E 's/_[0-9]+//') + for pmu_event in "${pmu_events[@]}"; do + if [[ "$event" == "$pmu_event" ]]; then + echo "Testing event ${event} is uniquified to ${pmu_v_event}" + if ! perf stat -e "$event" -A -o ${stat_output} -- true; then + echo "Error running perf stat for event '$event' [Skip]" + if [ $err = 0 ]; then + err=2 + fi + continue + fi + # Ensure the non-deduplicated event appears in the output. + if ! grep -q "${pmu_v_event}" "${stat_output}"; then + echo "Uniquification of PMU sysfs events test [Failed]" + cat "${stat_output}" + err=1 + fi + break + fi + done done } test_event_uniquifying -rm -f "${stat_output}" +cleanup exit $err From 24937ee839e4bbc097acde73eeed67812bad2d99 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 18 Sep 2025 10:24:15 -0700 Subject: [PATCH 1773/2711] perf evsel: Ensure the fallback message is always written to The fallback message is unconditionally printed in places like record__open(). If no fallback is attempted this can lead to printing uninitialized data, crashes, etc. Fixes: c0a54341c0e89333 ("perf evsel: Introduce event fallback method") Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 6947072598b1..1a29d4f47bbf 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -3562,7 +3562,7 @@ bool evsel__fallback(struct evsel *evsel, struct target *target, int err, /* If event has exclude user then don't exclude kernel. */ if (evsel->core.attr.exclude_user) - return false; + goto no_fallback; /* Is there already the separator in the name. */ if (strchr(name, '/') || @@ -3570,7 +3570,7 @@ bool evsel__fallback(struct evsel *evsel, struct target *target, int err, sep = ""; if (asprintf(&new_name, "%s%su", name, sep) < 0) - return false; + goto no_fallback; free(evsel->name); evsel->name = new_name; @@ -3593,17 +3593,19 @@ bool evsel__fallback(struct evsel *evsel, struct target *target, int err, sep = ""; if (asprintf(&new_name, "%s%sH", name, sep) < 0) - return false; + goto no_fallback; free(evsel->name); evsel->name = new_name; /* Apple M1 requires exclude_guest */ - scnprintf(msg, msgsize, "trying to fall back to excluding guest samples"); + scnprintf(msg, msgsize, "Trying to fall back to excluding guest samples"); evsel->core.attr.exclude_guest = 1; return true; } - +no_fallback: + scnprintf(msg, msgsize, "No fallback found for '%s' for error %d", + evsel__name(evsel), err); return false; } From 0dc96cae063cbf9ebf6631b33b08e9ba02324248 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 18 Sep 2025 10:24:16 -0700 Subject: [PATCH 1774/2711] perf build-id: Ensure snprintf string is empty when size is 0 The string result of build_id__snprintf() is unconditionally used in places like dsos__fprintf_buildid_cb(). If the build id has size 0 then this creates a use of uninitialized memory. Add null termination for the size 0 case. A similar fix was written by Jiri Olsa in commit 6311951d4f8f28c4 ("perf tools: Initialize output buffer in build_id__sprintf") but lost in the transition to snprintf. Fixes: fccaaf6fbbc59910 ("perf build-id: Change sprintf functions to snprintf") Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Howard Chu Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/build-id.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index bf7f3268b9a2..35505a1ffd11 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -86,6 +86,13 @@ int build_id__snprintf(const struct build_id *build_id, char *bf, size_t bf_size { size_t offs = 0; + if (build_id->size == 0) { + /* Ensure bf is always \0 terminated. */ + if (bf_size > 0) + bf[0] = '\0'; + return 0; + } + for (size_t i = 0; i < build_id->size && offs < bf_size; ++i) offs += snprintf(bf + offs, bf_size - offs, "%02x", build_id->data[i]); From 6dbcc6ed4bd340f96fde4335a901d985401dd45b Mon Sep 17 00:00:00 2001 From: Mostafa Saleh Date: Wed, 20 Aug 2025 20:31:02 +0000 Subject: [PATCH 1775/2711] MAINTAINERS: Add myself as VFIO-platform reviewer Based on discussion: https://lore.kernel.org/kvm/20250806170314.3768750-3-alex.williamson@redhat.com/ I will start looking into adding support for modern HW and more features to VFIO-platform. Signed-off-by: Mostafa Saleh Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20250820203102.2034333-1-smostafa@google.com Signed-off-by: Alex Williamson --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 839f910bad6b..3a80b7fc7935 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26493,6 +26493,7 @@ F: drivers/vfio/pci/pds/ VFIO PLATFORM DRIVER M: Eric Auger +R: Mostafa Saleh L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/platform/ From 08fb9897f75719947303acfb23b8c41039118a2d Mon Sep 17 00:00:00 2001 From: Pranjal Shrivastava Date: Mon, 1 Sep 2025 19:16:19 +0000 Subject: [PATCH 1776/2711] MAINTAINERS: Add myself as VFIO-platform reviewer While my work at Google Cloud focuses on various areas of the kernel, my background in IOMMU and the VFIO subsystem motivates me to help with the maintenance effort for vfio-platform (based on the discussion [1]) and ensure its continued health. Link: https://lore.kernel.org/all/aKxpyyKvYcd84Ayi@google.com/ [1] Signed-off-by: Pranjal Shrivastava Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20250901191619.183116-1-praan@google.com Signed-off-by: Alex Williamson --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3a80b7fc7935..3f9890ec18a4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26494,6 +26494,7 @@ F: drivers/vfio/pci/pds/ VFIO PLATFORM DRIVER M: Eric Auger R: Mostafa Saleh +R: Pranjal Shrivastava L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/platform/ From fd0f75308bfde358e39b0ebd25a50750b6139ae5 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 25 Aug 2025 11:58:00 -0600 Subject: [PATCH 1777/2711] vfio/amba: Mark for removal vfio-amba has only been touched to keep up with the rest of the code base for the past 10 years. We have no basis to believe that it's currently tested or used. Mark it for deprecation. Reviewed-by: Pranjal Shrivastava Reviewed-by: Mostafa Saleh Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20250825175807.3264083-2-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/platform/Kconfig | 5 ++++- drivers/vfio/platform/vfio_amba.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/platform/Kconfig b/drivers/vfio/platform/Kconfig index 88fcde51f024..c6be29b2c24b 100644 --- a/drivers/vfio/platform/Kconfig +++ b/drivers/vfio/platform/Kconfig @@ -17,10 +17,13 @@ config VFIO_PLATFORM If you don't know what to do here, say N. config VFIO_AMBA - tristate "VFIO support for AMBA devices" + tristate "VFIO support for AMBA devices (DEPRECATED)" depends on ARM_AMBA || COMPILE_TEST select VFIO_PLATFORM_BASE help + The vfio-amba driver is deprecated and will be removed in a + future kernel release. + Support for ARM AMBA devices with VFIO. This is required to make use of ARM AMBA devices present on the system using the VFIO framework. diff --git a/drivers/vfio/platform/vfio_amba.c b/drivers/vfio/platform/vfio_amba.c index ff8ff8480968..9f5c527baa8a 100644 --- a/drivers/vfio/platform/vfio_amba.c +++ b/drivers/vfio/platform/vfio_amba.c @@ -70,6 +70,8 @@ static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id) struct vfio_platform_device *vdev; int ret; + dev_err_once(&adev->dev, "DEPRECATION: vfio-amba is deprecated and will be removed in a future kernel release\n"); + vdev = vfio_alloc_device(vfio_platform_device, vdev, &adev->dev, &vfio_amba_ops); if (IS_ERR(vdev)) From 801ca4ce0bce45aae1da2c8914d2f86cb68f8b55 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 25 Aug 2025 11:58:01 -0600 Subject: [PATCH 1778/2711] vfio/platform: Mark reset drivers for removal While vfio-platform itself is on a reprieve from being removed[1], these reset drivers don't support any current hardware, are not being tested, and suggest a level of support that doesn't really exist. Mark them for removal to surface any remaining user such that we can potentially drop them and simplify the code if none appear. Link: https://lore.kernel.org/all/20250806170314.3768750-3-alex.williamson@redhat.com [1] Reviewed-by: Pranjal Shrivastava Reviewed-by: Mostafa Saleh Reviewed-by: Eric Auger Link: https://lore.kernel.org/r/20250825175807.3264083-3-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/platform/reset/Kconfig | 6 +++--- drivers/vfio/platform/reset/vfio_platform_amdxgbe.c | 2 ++ drivers/vfio/platform/reset/vfio_platform_bcmflexrm.c | 2 ++ drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c | 2 ++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/vfio/platform/reset/Kconfig b/drivers/vfio/platform/reset/Kconfig index dcc08dc145a5..70af0dbe293b 100644 --- a/drivers/vfio/platform/reset/Kconfig +++ b/drivers/vfio/platform/reset/Kconfig @@ -1,21 +1,21 @@ # SPDX-License-Identifier: GPL-2.0-only if VFIO_PLATFORM config VFIO_PLATFORM_CALXEDAXGMAC_RESET - tristate "VFIO support for calxeda xgmac reset" + tristate "VFIO support for calxeda xgmac reset (DEPRECATED)" help Enables the VFIO platform driver to handle reset for Calxeda xgmac If you don't know what to do here, say N. config VFIO_PLATFORM_AMDXGBE_RESET - tristate "VFIO support for AMD XGBE reset" + tristate "VFIO support for AMD XGBE reset (DEPRECATED)" help Enables the VFIO platform driver to handle reset for AMD XGBE If you don't know what to do here, say N. config VFIO_PLATFORM_BCMFLEXRM_RESET - tristate "VFIO support for Broadcom FlexRM reset" + tristate "VFIO support for Broadcom FlexRM reset (DEPRECATED)" depends on ARCH_BCM_IPROC || COMPILE_TEST default ARCH_BCM_IPROC help diff --git a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c index abdca900802d..45f386a042a9 100644 --- a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c +++ b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c @@ -52,6 +52,8 @@ static int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev) u32 dma_mr_value, pcs_value, value; unsigned int count; + dev_err_once(vdev->device, "DEPRECATION: VFIO AMD XGBE platform reset is deprecated and will be removed in a future kernel release\n"); + if (!xgmac_regs->ioaddr) { xgmac_regs->ioaddr = ioremap(xgmac_regs->addr, xgmac_regs->size); diff --git a/drivers/vfio/platform/reset/vfio_platform_bcmflexrm.c b/drivers/vfio/platform/reset/vfio_platform_bcmflexrm.c index 1131ebe4837d..51c9d156f307 100644 --- a/drivers/vfio/platform/reset/vfio_platform_bcmflexrm.c +++ b/drivers/vfio/platform/reset/vfio_platform_bcmflexrm.c @@ -72,6 +72,8 @@ static int vfio_platform_bcmflexrm_reset(struct vfio_platform_device *vdev) int rc = 0, ret = 0, ring_num = 0; struct vfio_platform_region *reg = &vdev->regions[0]; + dev_err_once(vdev->device, "DEPRECATION: VFIO Broadcom FlexRM platform reset is deprecated and will be removed in a future kernel release\n"); + /* Map FlexRM ring registers if not mapped */ if (!reg->ioaddr) { reg->ioaddr = ioremap(reg->addr, reg->size); diff --git a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c index 63cc7f0b2e4a..a298045a8e19 100644 --- a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c +++ b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c @@ -50,6 +50,8 @@ static int vfio_platform_calxedaxgmac_reset(struct vfio_platform_device *vdev) { struct vfio_platform_region *reg = &vdev->regions[0]; + dev_err_once(vdev->device, "DEPRECATION: VFIO Calxeda xgmac platform reset is deprecated and will be removed in a future kernel release\n"); + if (!reg->ioaddr) { reg->ioaddr = ioremap(reg->addr, reg->size); From eaba58355ecd124b4a8c91df7335970ad9fe2624 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Mon, 1 Sep 2025 16:18:08 +0800 Subject: [PATCH 1779/2711] hisi_acc_vfio_pci: Fix reference leak in hisi_acc_vfio_debug_init The debugfs_lookup() function returns a dentry with an increased reference count that must be released by calling dput(). Fixes: b398f91779b8 ("hisi_acc_vfio_pci: register debugfs for hisilicon migration driver") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Reviewed-by: Longfang Liu Link: https://lore.kernel.org/r/20250901081809.2286649-1-linmq006@gmail.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c index 397f5e445136..fde33f54e99e 100644 --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c @@ -1612,8 +1612,10 @@ static void hisi_acc_vfio_debug_init(struct hisi_acc_vf_core_device *hisi_acc_vd } migf = kzalloc(sizeof(*migf), GFP_KERNEL); - if (!migf) + if (!migf) { + dput(vfio_dev_migration); return; + } hisi_acc_vdev->debug_migf = migf; vfio_hisi_acc = debugfs_create_dir("hisi_acc", vfio_dev_migration); @@ -1623,6 +1625,8 @@ static void hisi_acc_vfio_debug_init(struct hisi_acc_vf_core_device *hisi_acc_vd hisi_acc_vf_migf_read); debugfs_create_devm_seqfile(dev, "cmd_state", vfio_hisi_acc, hisi_acc_vf_debug_cmd); + + dput(vfio_dev_migration); } static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev) From 16df67f2189a71a8310bcebddb87ed569e8352be Mon Sep 17 00:00:00 2001 From: Alex Mastro Date: Mon, 8 Sep 2025 08:58:40 -0700 Subject: [PATCH 1780/2711] vfio: return -ENOTTY for unsupported device feature The two implementers of vfio_device_ops.device_feature, vfio_cdx_ioctl_feature and vfio_pci_core_ioctl_feature, return -ENOTTY in the fallthrough case when the feature is unsupported. For consistency, the base case, vfio_ioctl_device_feature, should do the same when device_feature == NULL, indicating an implementation has no feature extensions. Signed-off-by: Alex Mastro Link: https://lore.kernel.org/r/20250908-vfio-enotty-v1-1-4428e1539e2e@fb.com Signed-off-by: Alex Williamson --- drivers/vfio/vfio_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 91a8eae308ea..38c8e9350a60 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -1252,7 +1252,7 @@ static int vfio_ioctl_device_feature(struct vfio_device *device, feature.argsz - minsz); default: if (unlikely(!device->ops->device_feature)) - return -EINVAL; + return -ENOTTY; return device->ops->device_feature(device, feature.flags, arg->data, feature.argsz - minsz); From acb59a4bb8ed34e738a4c3463127bf3f6b5e11a9 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Sat, 13 Sep 2025 15:31:54 +0000 Subject: [PATCH 1781/2711] vfio/pds: replace bitmap_free with vfree host_seq_bmp is allocated with vzalloc but is currently freed with bitmap_free, which uses kfree internally. This mismach prevents the resource from being released properly and may result in memory leaks or other issues. Fix this by freeing host_seq_bmp with vfree to match the vzalloc allocation. Fixes: f232836a9152 ("vfio/pds: Add support for dirty page tracking") Signed-off-by: Zilin Guan Reviewed-by: Brett Creeley Link: https://lore.kernel.org/r/20250913153154.1028835-1-zilin@seu.edu.cn Signed-off-by: Alex Williamson --- drivers/vfio/pci/pds/dirty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vfio/pci/pds/dirty.c b/drivers/vfio/pci/pds/dirty.c index c51f5e4c3dd6..481992142f79 100644 --- a/drivers/vfio/pci/pds/dirty.c +++ b/drivers/vfio/pci/pds/dirty.c @@ -82,7 +82,7 @@ static int pds_vfio_dirty_alloc_bitmaps(struct pds_vfio_region *region, host_ack_bmp = vzalloc(bytes); if (!host_ack_bmp) { - bitmap_free(host_seq_bmp); + vfree(host_seq_bmp); return -ENOMEM; } From 510c47f165f0c1f0b57329a30a9a797795519831 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 18 Sep 2025 08:32:25 +0300 Subject: [PATCH 1782/2711] KVM: TDX: Fix uninitialized error code for __tdx_bringup() Fix a Smatch static checker warning reported by Dan: arch/x86/kvm/vmx/tdx.c:3464 __tdx_bringup() warn: missing error code 'r' Initialize r to -EINVAL before tdx_get_sysinfo() to simplify the code and to prevent similar issues from sneaking in later on as suggested by Kai. Cc: stable@vger.kernel.org Reported-by: Dan Carpenter Fixes: 61bb28279623 ("KVM: TDX: Get system-wide info about TDX module on initialization") Suggested-by: Kai Huang Reviewed-by: Kai Huang Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20250918053226.802204-1-tony.lindgren@linux.intel.com [sean: tag for stable] Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/tdx.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 6784aaaced87..36c15035ecb4 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -3457,12 +3457,11 @@ static int __init __tdx_bringup(void) if (r) goto tdx_bringup_err; + r = -EINVAL; /* Get TDX global information for later use */ tdx_sysinfo = tdx_get_sysinfo(); - if (WARN_ON_ONCE(!tdx_sysinfo)) { - r = -EINVAL; + if (WARN_ON_ONCE(!tdx_sysinfo)) goto get_sysinfo_err; - } /* Check TDX module and KVM capabilities */ if (!tdx_get_supported_attrs(&tdx_sysinfo->td_conf) || @@ -3505,14 +3504,11 @@ static int __init __tdx_bringup(void) if (td_conf->max_vcpus_per_td < num_present_cpus()) { pr_err("Disable TDX: MAX_VCPU_PER_TD (%u) smaller than number of logical CPUs (%u).\n", td_conf->max_vcpus_per_td, num_present_cpus()); - r = -EINVAL; goto get_sysinfo_err; } - if (misc_cg_set_capacity(MISC_CG_RES_TDX, tdx_get_nr_guest_keyids())) { - r = -EINVAL; + if (misc_cg_set_capacity(MISC_CG_RES_TDX, tdx_get_nr_guest_keyids())) goto get_sysinfo_err; - } /* * Leave hardware virtualization enabled after TDX is enabled From 7e2e4e32cd47a4129bf25c21e7049ff0571b7b90 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 18 Sep 2025 18:06:01 +0200 Subject: [PATCH 1783/2711] clk: amlogic: fix recent code refactoring Commit 4c4e17f27013 ("clk: amlogic: naming consistency alignment") refactored some internals in the g12a meson clock driver. Unfortunately it introduced a bug in the clock init data, which results in the following kernel panic: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 Mem abort info: ... Data abort info: ... [0000000000000000] user address but active_mm is swapper Internal error: Oops: 0000000096000004 [#1] SMP Modules linked in: CPU: 4 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.17.0-rc1+ #11158 PREEMPT Hardware name: Hardkernel ODROID-N2 (DT) pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : __clk_register+0x60/0x92c lr : __clk_register+0x48/0x92c ... Call trace: __clk_register+0x60/0x92c (P) devm_clk_hw_register+0x5c/0xd8 meson_eeclkc_probe+0x74/0x110 g12a_clkc_probe+0x2c/0x58 platform_probe+0x5c/0xac really_probe+0xbc/0x298 __driver_probe_device+0x78/0x12c driver_probe_device+0xdc/0x164 __driver_attach+0x9c/0x1ac bus_for_each_dev+0x74/0xd0 driver_attach+0x24/0x30 bus_add_driver+0xe4/0x208 driver_register+0x60/0x128 __platform_driver_register+0x24/0x30 g12a_clkc_driver_init+0x1c/0x28 do_one_initcall+0x64/0x308 kernel_init_freeable+0x27c/0x4f8 kernel_init+0x20/0x1d8 ret_from_fork+0x10/0x20 Code: 52800038 aa0003fc b9010018 52819801 (f9400260) ---[ end trace 0000000000000000 ]--- Fix this by correcting the clock init data. Fixes: 4c4e17f27013 ("clk: amlogic: naming consistency alignment") Signed-off-by: Marek Szyprowski Tested-by: Neil Armstrong # on BananPi M2S Reviewed-by: Neil Armstrong Reviewed-by: Jerome Brunet Signed-off-by: Stephen Boyd --- drivers/clk/meson/g12a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 348aff4fae68..185b6348251d 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -4931,7 +4931,7 @@ static struct clk_hw *g12b_hw_clks[] = { [CLKID_CPUB_CLK_DYN0_SEL] = &g12b_cpub_clk_dyn0_sel.hw, [CLKID_CPUB_CLK_DYN0_DIV] = &g12b_cpub_clk_dyn0_div.hw, [CLKID_CPUB_CLK_DYN0] = &g12b_cpub_clk_dyn0.hw, - [CLKID_CPUB_CLK_DYN1_SEL] = &g12b_cpub_clk_dyn1.hw, + [CLKID_CPUB_CLK_DYN1_SEL] = &g12b_cpub_clk_dyn1_sel.hw, [CLKID_CPUB_CLK_DYN1_DIV] = &g12b_cpub_clk_dyn1_div.hw, [CLKID_CPUB_CLK_DYN1] = &g12b_cpub_clk_dyn1.hw, [CLKID_CPUB_CLK_DYN] = &g12b_cpub_clk_dyn.hw, From 1e0d75258bd09323cb452655549e03975992b29e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 25 Aug 2025 16:08:11 +0200 Subject: [PATCH 1784/2711] clk: ti: am33xx: keep WKUP_DEBUGSS_CLKCTRL enabled As described in AM335x Errata Advisory 1.0.42, WKUP_DEBUGSS_CLKCTRL can't be disabled - the clock module will just be stuck in transitioning state forever, resulting in the following warning message after the wait loop times out: l3-aon-clkctrl:0000:0: failed to disable Just add the clock to enable_init_clks, so no attempt is made to disable it. Signed-off-by: Matthias Schiffer Signed-off-by: Alexander Stein Acked-by: Kevin Hilman Signed-off-by: Stephen Boyd --- drivers/clk/ti/clk-33xx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c index 85c50ea39e6d..9269e6a0db6a 100644 --- a/drivers/clk/ti/clk-33xx.c +++ b/drivers/clk/ti/clk-33xx.c @@ -258,6 +258,8 @@ static const char *enable_init_clks[] = { "dpll_ddr_m2_ck", "dpll_mpu_m2_ck", "l3_gclk", + /* WKUP_DEBUGSS_CLKCTRL - disable fails, AM335x Errata Advisory 1.0.42 */ + "l3-aon-clkctrl:0000:0", /* AM3_L3_L3_MAIN_CLKCTRL, needed during suspend */ "l3-clkctrl:00bc:0", "l4hs_gclk", From 048546931339b322f13c5863ce1815c9e5e7b0bd Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Tue, 16 Sep 2025 18:15:18 +0530 Subject: [PATCH 1785/2711] clk: keystone: sci-clk: use devm_kmemdup_array() Convert to use devm_kmemdup_array() which is more robust. Signed-off-by: Raag Jadav Reviewed-by: Andy Shevchenko Reviewed-by: Nishanth Menon Signed-off-by: Stephen Boyd --- drivers/clk/keystone/sci-clk.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c index c5894fc9395e..a4b42811de55 100644 --- a/drivers/clk/keystone/sci-clk.c +++ b/drivers/clk/keystone/sci-clk.c @@ -480,13 +480,10 @@ static int ti_sci_scan_clocks_from_fw(struct sci_clk_provider *provider) num_clks++; } - provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk), - GFP_KERNEL); + provider->clocks = devm_kmemdup_array(dev, clks, num_clks, sizeof(sci_clk), GFP_KERNEL); if (!provider->clocks) return -ENOMEM; - memcpy(provider->clocks, clks, num_clks * sizeof(sci_clk)); - provider->num_clocks = num_clks; devm_kfree(dev, clks); From ac28c7598611df3034c0f61d25da7b3377bbce87 Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Tue, 26 Aug 2025 09:39:34 +0200 Subject: [PATCH 1786/2711] dt-bindings: clock: mediatek: Add power-domains property The mt8183-mfgcfg node uses a power domain in its device tree node. To prevent schema validation warnings, add the optional `power-domains` property to the binding schema for mediatek syscon clocks. Fixes: 1781f2c46180 ("arm64: dts: mediatek: mt8183: Add power-domains properity to mfgcfg") Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Julien Massot Acked-by: Rob Herring (Arm) Signed-off-by: Stephen Boyd --- .../bindings/clock/mediatek,syscon.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml b/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml index a86a64893c67..a52f90bfc9f9 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml @@ -76,6 +76,9 @@ properties: - const: mediatek,mt2701-vdecsys - const: syscon + power-domains: + maxItems: 1 + reg: maxItems: 1 @@ -86,6 +89,18 @@ required: - compatible - '#clock-cells' +if: + properties: + compatible: + contains: + const: mediatek,mt8183-mfgcfg +then: + properties: + power-domains: true +else: + properties: + power-domains: false + additionalProperties: false examples: From 18db1ff2dea0f97dedaeadd18b0cb0a0d76154df Mon Sep 17 00:00:00 2001 From: Jacky Bai Date: Mon, 28 Jul 2025 15:04:46 +0800 Subject: [PATCH 1787/2711] clk: scmi: Add duty cycle ops only when duty cycle is supported For some of the SCMI based platforms, the oem extended config may be supported, but not for duty cycle purpose. Skip the duty cycle ops if err return when trying to get duty cycle info. Signed-off-by: Jacky Bai Reviewed-by: Sudeep Holla Signed-off-by: Stephen Boyd --- drivers/clk/clk-scmi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c index d2408403283f..c2f3ef4e58fe 100644 --- a/drivers/clk/clk-scmi.c +++ b/drivers/clk/clk-scmi.c @@ -349,6 +349,8 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable, unsigned int atomic_threshold_us, const struct clk_ops **clk_ops_db, size_t db_size) { + int ret; + u32 val; const struct scmi_clock_info *ci = sclk->info; unsigned int feats_key = 0; const struct clk_ops *ops; @@ -370,8 +372,13 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable, if (!ci->parent_ctrl_forbidden) feats_key |= BIT(SCMI_CLK_PARENT_CTRL_SUPPORTED); - if (ci->extended_config) - feats_key |= BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED); + if (ci->extended_config) { + ret = scmi_proto_clk_ops->config_oem_get(sclk->ph, sclk->id, + SCMI_CLOCK_CFG_DUTY_CYCLE, + &val, NULL, false); + if (!ret) + feats_key |= BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED); + } if (WARN_ON(feats_key >= db_size)) return NULL; From 8be1f299041220512195e40590bb4984f297ae48 Mon Sep 17 00:00:00 2001 From: Troy Mitchell Date: Thu, 11 Sep 2025 11:34:03 +0800 Subject: [PATCH 1788/2711] dt-bindings: clock: spacemit: introduce i2s pre-clock to fix i2s clock Previously, the K1 clock driver did not include the parent clocks of the I2S sysclk. Introduce pre-clock to fix I2S clock. Otherwise, the I2S clock may not work as expected. This patch adds their definitions to allow proper registration in the driver and usage in the device tree. Fixes: 1b72c59db0add ("clk: spacemit: Add clock support for SpacemiT K1 SoC") Acked-by: Krzysztof Kozlowski Signed-off-by: Troy Mitchell Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/spacemit,k1-syscon.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/dt-bindings/clock/spacemit,k1-syscon.h b/include/dt-bindings/clock/spacemit,k1-syscon.h index 505205453d7f..0f8b59d6753c 100644 --- a/include/dt-bindings/clock/spacemit,k1-syscon.h +++ b/include/dt-bindings/clock/spacemit,k1-syscon.h @@ -77,6 +77,10 @@ #define CLK_I2S_BCLK 30 #define CLK_APB 31 #define CLK_WDT_BUS 32 +#define CLK_I2S_153P6 33 +#define CLK_I2S_153P6_BASE 34 +#define CLK_I2S_SYSCLK_SRC 35 +#define CLK_I2S_BCLK_FACTOR 36 /* MPMU resets */ #define RESET_WDT 0 From 74246a820c817f195f6191e370c3df98d2df5d91 Mon Sep 17 00:00:00 2001 From: Troy Mitchell Date: Thu, 11 Sep 2025 11:34:04 +0800 Subject: [PATCH 1789/2711] clk: spacemit: introduce pre-div for ddn clock The original DDN operations applied an implicit divide-by-2, which should not be a default behavior. This patch removes that assumption, letting each clock define its actual behavior explicitly. Reviewed-by: Haylen Chu Signed-off-by: Troy Mitchell Signed-off-by: Stephen Boyd --- drivers/clk/spacemit/ccu-k1.c | 4 ++-- drivers/clk/spacemit/ccu_ddn.c | 12 ++++++------ drivers/clk/spacemit/ccu_ddn.h | 6 ++++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/clk/spacemit/ccu-k1.c b/drivers/clk/spacemit/ccu-k1.c index 62cdba516a29..14a88d0372dd 100644 --- a/drivers/clk/spacemit/ccu-k1.c +++ b/drivers/clk/spacemit/ccu-k1.c @@ -136,8 +136,8 @@ CCU_GATE_DEFINE(pll1_d3_819p2, CCU_PARENT_HW(pll1_d3), MPMU_ACGR, BIT(14), 0); CCU_GATE_DEFINE(pll1_d2_1228p8, CCU_PARENT_HW(pll1_d2), MPMU_ACGR, BIT(16), 0); CCU_GATE_DEFINE(slow_uart, CCU_PARENT_NAME(osc), MPMU_ACGR, BIT(1), CLK_IGNORE_UNUSED); -CCU_DDN_DEFINE(slow_uart1_14p74, pll1_d16_153p6, MPMU_SUCCR, 16, 13, 0, 13, 0); -CCU_DDN_DEFINE(slow_uart2_48, pll1_d4_614p4, MPMU_SUCCR_1, 16, 13, 0, 13, 0); +CCU_DDN_DEFINE(slow_uart1_14p74, pll1_d16_153p6, MPMU_SUCCR, 16, 13, 0, 13, 2, 0); +CCU_DDN_DEFINE(slow_uart2_48, pll1_d4_614p4, MPMU_SUCCR_1, 16, 13, 0, 13, 2, 0); CCU_GATE_DEFINE(wdt_clk, CCU_PARENT_HW(pll1_d96_25p6), MPMU_WDTPCR, BIT(1), 0); diff --git a/drivers/clk/spacemit/ccu_ddn.c b/drivers/clk/spacemit/ccu_ddn.c index 02b68ea84db9..5b16e273bee5 100644 --- a/drivers/clk/spacemit/ccu_ddn.c +++ b/drivers/clk/spacemit/ccu_ddn.c @@ -22,21 +22,21 @@ #include "ccu_ddn.h" -static unsigned long ccu_ddn_calc_rate(unsigned long prate, - unsigned long num, unsigned long den) +static unsigned long ccu_ddn_calc_rate(unsigned long prate, unsigned long num, + unsigned long den, unsigned int pre_div) { - return prate * den / 2 / num; + return prate * den / pre_div / num; } static unsigned long ccu_ddn_calc_best_rate(struct ccu_ddn *ddn, unsigned long rate, unsigned long prate, unsigned long *num, unsigned long *den) { - rational_best_approximation(rate, prate / 2, + rational_best_approximation(rate, prate / ddn->pre_div, ddn->den_mask >> ddn->den_shift, ddn->num_mask >> ddn->num_shift, den, num); - return ccu_ddn_calc_rate(prate, *num, *den); + return ccu_ddn_calc_rate(prate, *num, *den, ddn->pre_div); } static int ccu_ddn_determine_rate(struct clk_hw *hw, @@ -61,7 +61,7 @@ static unsigned long ccu_ddn_recalc_rate(struct clk_hw *hw, unsigned long prate) num = (val & ddn->num_mask) >> ddn->num_shift; den = (val & ddn->den_mask) >> ddn->den_shift; - return ccu_ddn_calc_rate(prate, num, den); + return ccu_ddn_calc_rate(prate, num, den, ddn->pre_div); } static int ccu_ddn_set_rate(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/clk/spacemit/ccu_ddn.h b/drivers/clk/spacemit/ccu_ddn.h index a52fabe77d62..4838414a8e8d 100644 --- a/drivers/clk/spacemit/ccu_ddn.h +++ b/drivers/clk/spacemit/ccu_ddn.h @@ -18,13 +18,14 @@ struct ccu_ddn { unsigned int num_shift; unsigned int den_mask; unsigned int den_shift; + unsigned int pre_div; }; #define CCU_DDN_INIT(_name, _parent, _flags) \ CLK_HW_INIT_HW(#_name, &_parent.common.hw, &spacemit_ccu_ddn_ops, _flags) #define CCU_DDN_DEFINE(_name, _parent, _reg_ctrl, _num_shift, _num_width, \ - _den_shift, _den_width, _flags) \ + _den_shift, _den_width, _pre_div, _flags) \ static struct ccu_ddn _name = { \ .common = { \ .reg_ctrl = _reg_ctrl, \ @@ -33,7 +34,8 @@ static struct ccu_ddn _name = { \ .num_mask = GENMASK(_num_shift + _num_width - 1, _num_shift), \ .num_shift = _num_shift, \ .den_mask = GENMASK(_den_shift + _den_width - 1, _den_shift), \ - .den_shift = _den_shift, \ + .den_shift = _den_shift, \ + .pre_div = _pre_div, \ } static inline struct ccu_ddn *hw_to_ccu_ddn(struct clk_hw *hw) From 519cff1d85694cbdf33b27591740e7e37348e6b4 Mon Sep 17 00:00:00 2001 From: Troy Mitchell Date: Thu, 11 Sep 2025 11:34:05 +0800 Subject: [PATCH 1790/2711] clk: spacemit: fix i2s clock Defining i2s_bclk and i2s_sysclk as fixed-rate clocks is insufficient for real I2S use cases. Moreover, the current I2S clock configuration does not work as expected due to missing parent clocks. This patch adds the missing parent clocks, defines i2s_sysclk as a DDN clock, and i2s_bclk as a DIV clock. A special note for i2s_bclk: From the register definition, the i2s_bclk divider always implies an additional 1/2 factor. The following table shows the correspondence between index and frequency division coefficients: | index | div | |-------|-------| | 0 | 2 | | 1 | 4 | | 2 | 6 | | 3 | 8 | From a software perspective, introducing i2s_bclk_factor as the parent of i2s_bclk is sufficient to address the issue. The I2S-related clock registers can be found here [1]. Link: https://developer.spacemit.com/documentation?token=LCrKwWDasiJuROkVNusc2pWTnEb [1] Fixes: 1b72c59db0add ("clk: spacemit: Add clock support for SpacemiT K1 SoC") Co-developer: Jinmei Wei Suggested-by: Haylen Chu Signed-off-by: Jinmei Wei Signed-off-by: Troy Mitchell Signed-off-by: Stephen Boyd --- drivers/clk/spacemit/ccu-k1.c | 28 ++++++++++++++++++++++++++-- include/soc/spacemit/k1-syscon.h | 1 + 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/clk/spacemit/ccu-k1.c b/drivers/clk/spacemit/ccu-k1.c index 14a88d0372dd..f5a9fe6ba185 100644 --- a/drivers/clk/spacemit/ccu-k1.c +++ b/drivers/clk/spacemit/ccu-k1.c @@ -141,8 +141,28 @@ CCU_DDN_DEFINE(slow_uart2_48, pll1_d4_614p4, MPMU_SUCCR_1, 16, 13, 0, 13, 2, 0); CCU_GATE_DEFINE(wdt_clk, CCU_PARENT_HW(pll1_d96_25p6), MPMU_WDTPCR, BIT(1), 0); -CCU_FACTOR_GATE_DEFINE(i2s_sysclk, CCU_PARENT_HW(pll1_d16_153p6), MPMU_ISCCR, BIT(31), 50, 1); -CCU_FACTOR_GATE_DEFINE(i2s_bclk, CCU_PARENT_HW(i2s_sysclk), MPMU_ISCCR, BIT(29), 1, 1); +CCU_FACTOR_DEFINE(i2s_153p6, CCU_PARENT_HW(pll1_d8_307p2), 2, 1); + +static const struct clk_parent_data i2s_153p6_base_parents[] = { + CCU_PARENT_HW(i2s_153p6), + CCU_PARENT_HW(pll1_d8_307p2), +}; +CCU_MUX_DEFINE(i2s_153p6_base, i2s_153p6_base_parents, MPMU_FCCR, 29, 1, 0); + +static const struct clk_parent_data i2s_sysclk_src_parents[] = { + CCU_PARENT_HW(pll1_d96_25p6), + CCU_PARENT_HW(i2s_153p6_base) +}; +CCU_MUX_GATE_DEFINE(i2s_sysclk_src, i2s_sysclk_src_parents, MPMU_ISCCR, 30, 1, BIT(31), 0); + +CCU_DDN_DEFINE(i2s_sysclk, i2s_sysclk_src, MPMU_ISCCR, 0, 15, 15, 12, 1, 0); + +CCU_FACTOR_DEFINE(i2s_bclk_factor, CCU_PARENT_HW(i2s_sysclk), 2, 1); +/* + * Divider of i2s_bclk always implies a 1/2 factor, which is + * described by i2s_bclk_factor. + */ +CCU_DIV_GATE_DEFINE(i2s_bclk, CCU_PARENT_HW(i2s_bclk_factor), MPMU_ISCCR, 27, 2, BIT(29), 0); static const struct clk_parent_data apb_parents[] = { CCU_PARENT_HW(pll1_d96_25p6), @@ -775,6 +795,10 @@ static struct clk_hw *k1_ccu_mpmu_hws[] = { [CLK_I2S_BCLK] = &i2s_bclk.common.hw, [CLK_APB] = &apb_clk.common.hw, [CLK_WDT_BUS] = &wdt_bus_clk.common.hw, + [CLK_I2S_153P6] = &i2s_153p6.common.hw, + [CLK_I2S_153P6_BASE] = &i2s_153p6_base.common.hw, + [CLK_I2S_SYSCLK_SRC] = &i2s_sysclk_src.common.hw, + [CLK_I2S_BCLK_FACTOR] = &i2s_bclk_factor.common.hw, }; static const struct spacemit_ccu_data k1_ccu_mpmu_data = { diff --git a/include/soc/spacemit/k1-syscon.h b/include/soc/spacemit/k1-syscon.h index c59bd7a38e5b..354751562c55 100644 --- a/include/soc/spacemit/k1-syscon.h +++ b/include/soc/spacemit/k1-syscon.h @@ -30,6 +30,7 @@ to_spacemit_ccu_adev(struct auxiliary_device *adev) /* MPMU register offset */ #define MPMU_POSR 0x0010 +#define MPMU_FCCR 0x0008 #define POSR_PLL1_LOCK BIT(27) #define POSR_PLL2_LOCK BIT(28) #define POSR_PLL3_LOCK BIT(29) From 0090c0a247cd3dc37181be4a9af4750ae3fedbd0 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 26 Jul 2025 11:38:09 +0100 Subject: [PATCH 1791/2711] KVM: arm64: Add helper computing the state of 52bit PA support Track whether the guest is using 52bit PAs, either LPA or LPA2. This further simplifies the handling of LVA for 4k and 16k pages, as LPA2 implies LVA in this case. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_nested.h | 1 + arch/arm64/kvm/at.c | 31 ++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index 7fd76f41c296..038e35430bb2 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -299,6 +299,7 @@ struct s1_walk_info { bool pan; bool be; bool s2; + bool pa52bit; }; struct s1_walk_result { diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index d71ca4ddc9d1..8e275ea68cfa 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -31,6 +31,29 @@ static bool check_output_size(u64 ipa, struct s1_walk_info *wi) return wi->max_oa_bits < 48 && (ipa & GENMASK_ULL(47, wi->max_oa_bits)); } +static bool has_52bit_pa(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, u64 tcr) +{ + switch (BIT(wi->pgshift)) { + case SZ_64K: + default: /* IMPDEF: treat any other value as 64k */ + if (!kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR0_EL1, PARANGE, 52)) + return false; + return ((wi->regime == TR_EL2 ? + FIELD_GET(TCR_EL2_PS_MASK, tcr) : + FIELD_GET(TCR_IPS_MASK, tcr)) == 0b0110); + case SZ_16K: + if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT)) + return false; + break; + case SZ_4K: + if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT)) + return false; + break; + } + + return (tcr & (wi->regime == TR_EL2 ? TCR_EL2_DS : TCR_DS)); +} + /* Return the translation regime that applies to an AT instruction */ static enum trans_regime compute_translation_regime(struct kvm_vcpu *vcpu, u32 op) { @@ -232,15 +255,13 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, goto transfault_l0; } + wi->pa52bit = has_52bit_pa(vcpu, wi, tcr); + /* R_GTJBY, R_SXWGM */ switch (BIT(wi->pgshift)) { case SZ_4K: - lva = kvm_has_feat(vcpu->kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT); - lva &= tcr & (wi->regime == TR_EL2 ? TCR_EL2_DS : TCR_DS); - break; case SZ_16K: - lva = kvm_has_feat(vcpu->kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT); - lva &= tcr & (wi->regime == TR_EL2 ? TCR_EL2_DS : TCR_DS); + lva = wi->pa52bit; break; case SZ_64K: lva = kvm_has_feat(vcpu->kvm, ID_AA64MMFR2_EL1, VARange, 52); From 23cf13def0c87d9ce234f12eb6132f6bf9442f29 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 26 Jul 2025 11:52:34 +0100 Subject: [PATCH 1792/2711] KVM: arm64: Account for 52bit when computing maximum OA Adjust the computation of the max OA to account for 52bit PAs. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_nested.h | 7 +++++-- arch/arm64/kvm/at.c | 2 +- arch/arm64/kvm/nested.c | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index 038e35430bb2..1a03095b03c5 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -265,7 +265,7 @@ static inline u64 decode_range_tlbi(u64 val, u64 *range, u16 *asid) return base; } -static inline unsigned int ps_to_output_size(unsigned int ps) +static inline unsigned int ps_to_output_size(unsigned int ps, bool pa52bit) { switch (ps) { case 0: return 32; @@ -273,7 +273,10 @@ static inline unsigned int ps_to_output_size(unsigned int ps) case 2: return 40; case 3: return 42; case 4: return 44; - case 5: + case 5: return 48; + case 6: if (pa52bit) + return 52; + fallthrough; default: return 48; } diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index 8e275ea68cfa..96452fdc90e2 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -295,7 +295,7 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, ps = (wi->regime == TR_EL2 ? FIELD_GET(TCR_EL2_PS_MASK, tcr) : FIELD_GET(TCR_IPS_MASK, tcr)); - wi->max_oa_bits = min(get_kvm_ipa_limit(), ps_to_output_size(ps)); + wi->max_oa_bits = min(get_kvm_ipa_limit(), ps_to_output_size(ps, wi->pa52bit)); /* Compute minimal alignment */ x = 3 + ia_bits - ((3 - wi->sl) * stride + wi->pgshift); diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 77db81bae86f..cb36974e010a 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -349,7 +349,7 @@ static void vtcr_to_walk_info(u64 vtcr, struct s2_walk_info *wi) wi->sl = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr); /* Global limit for now, should eventually be per-VM */ wi->max_oa_bits = min(get_kvm_ipa_limit(), - ps_to_output_size(FIELD_GET(VTCR_EL2_PS_MASK, vtcr))); + ps_to_output_size(FIELD_GET(VTCR_EL2_PS_MASK, vtcr), false)); } int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa, From e645226a9c238db919d105d0ee7b4e09d80d13b1 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 27 Jul 2025 10:18:56 +0100 Subject: [PATCH 1793/2711] KVM: arm64: Compute 52bit TTBR address and alignment 52bit addresses from TTBR need extra adjustment and alignment checks. Implement the requirements of the architecture. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/at.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index 96452fdc90e2..e02e467fc2cc 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -28,6 +28,8 @@ static int get_ia_size(struct s1_walk_info *wi) /* Return true if the IPA is out of the OA range */ static bool check_output_size(u64 ipa, struct s1_walk_info *wi) { + if (wi->pa52bit) + return wi->max_oa_bits < 52 && (ipa & GENMASK_ULL(51, wi->max_oa_bits)); return wi->max_oa_bits < 48 && (ipa & GENMASK_ULL(47, wi->max_oa_bits)); } @@ -301,6 +303,16 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, x = 3 + ia_bits - ((3 - wi->sl) * stride + wi->pgshift); wi->baddr = ttbr & TTBRx_EL1_BADDR; + if (wi->pa52bit) { + /* + * Force the alignment on 64 bytes for top-level tables + * smaller than 8 entries, since TTBR.BADDR[5:2] are used to + * store bits [51:48] of the first level of lookup. + */ + x = max(x, 6); + + wi->baddr |= FIELD_GET(GENMASK_ULL(5, 2), ttbr) << 48; + } /* R_VPBBF */ if (check_output_size(wi->baddr, wi)) From df1d0197a2b939e28321686cafaead4a183980fa Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 27 Jul 2025 18:46:02 +0100 Subject: [PATCH 1794/2711] KVM: arm64: Decouple output address from the PT descriptor Add a helper converting the descriptor into a nicely formed OA, irrespective of the in-descriptor representation (< 52bit, LPA or LPA2). Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/at.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index e02e467fc2cc..bdb2c3e22f24 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -56,6 +56,29 @@ static bool has_52bit_pa(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, u64 tcr return (tcr & (wi->regime == TR_EL2 ? TCR_EL2_DS : TCR_DS)); } +static u64 desc_to_oa(struct s1_walk_info *wi, u64 desc) +{ + u64 addr; + + if (!wi->pa52bit) + return desc & GENMASK_ULL(47, wi->pgshift); + + switch (BIT(wi->pgshift)) { + case SZ_4K: + case SZ_16K: + addr = desc & GENMASK_ULL(49, wi->pgshift); + addr |= FIELD_GET(KVM_PTE_ADDR_51_50_LPA2, desc) << 50; + break; + case SZ_64K: + default: /* IMPDEF: treat any other value as 64k */ + addr = desc & GENMASK_ULL(47, wi->pgshift); + addr |= FIELD_GET(KVM_PTE_ADDR_51_48, desc) << 48; + break; + } + + return addr; +} + /* Return the translation regime that applies to an AT instruction */ static enum trans_regime compute_translation_regime(struct kvm_vcpu *vcpu, u32 op) { @@ -402,7 +425,7 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, wr->PXNTable |= FIELD_GET(PMD_TABLE_PXN, desc); } - baddr = desc & GENMASK_ULL(47, wi->pgshift); + baddr = desc_to_oa(wi, desc); /* Check for out-of-range OA */ if (check_output_size(baddr, wi)) @@ -431,7 +454,8 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, goto transfault; } - if (check_output_size(desc & GENMASK(47, va_bottom), wi)) + baddr = desc_to_oa(wi, desc); + if (check_output_size(baddr & GENMASK(52, va_bottom), wi)) goto addrsz; if (!(desc & PTE_AF)) { @@ -444,7 +468,7 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, wr->failed = false; wr->level = level; wr->desc = desc; - wr->pa = desc & GENMASK(47, va_bottom); + wr->pa = baddr & GENMASK(52, va_bottom); wr->pa |= va & GENMASK_ULL(va_bottom - 1, 0); wr->nG = (wi->regime != TR_EL2) && (desc & PTE_NG); From e4bd479884a1353efd43aa950c996d333145642d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 25 Aug 2025 14:48:32 +0100 Subject: [PATCH 1795/2711] KVM: arm64: Pass the walk_info structure to compute_par_s1() Instead of just passing the translation regime, pass the full walk_info structure to compute_par_s1(). This will help further chamges that will require it. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/at.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index bdb2c3e22f24..acf6a5d49777 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -807,8 +807,8 @@ static u64 compute_par_s12(struct kvm_vcpu *vcpu, u64 s1_par, return par; } -static u64 compute_par_s1(struct kvm_vcpu *vcpu, struct s1_walk_result *wr, - enum trans_regime regime) +static u64 compute_par_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, + struct s1_walk_result *wr) { u64 par; @@ -823,7 +823,7 @@ static u64 compute_par_s1(struct kvm_vcpu *vcpu, struct s1_walk_result *wr, par = SYS_PAR_EL1_NSE; par |= wr->pa & GENMASK_ULL(47, 12); - if (regime == TR_EL10 && + if (wi->regime == TR_EL10 && (__vcpu_sys_reg(vcpu, HCR_EL2) & HCR_DC)) { par |= FIELD_PREP(SYS_PAR_EL1_ATTR, MEMATTR(WbRaWa, WbRaWa)); @@ -838,14 +838,14 @@ static u64 compute_par_s1(struct kvm_vcpu *vcpu, struct s1_walk_result *wr, par = SYS_PAR_EL1_NSE; - mair = (regime == TR_EL10 ? + mair = (wi->regime == TR_EL10 ? vcpu_read_sys_reg(vcpu, MAIR_EL1) : vcpu_read_sys_reg(vcpu, MAIR_EL2)); mair >>= FIELD_GET(PTE_ATTRINDX_MASK, wr->desc) * 8; mair &= 0xff; - sctlr = (regime == TR_EL10 ? + sctlr = (wi->regime == TR_EL10 ? vcpu_read_sys_reg(vcpu, SCTLR_EL1) : vcpu_read_sys_reg(vcpu, SCTLR_EL2)); @@ -1243,7 +1243,7 @@ static u64 handle_at_slow(struct kvm_vcpu *vcpu, u32 op, u64 vaddr) fail_s1_walk(&wr, ESR_ELx_FSC_PERM_L(wr.level), false); compute_par: - return compute_par_s1(vcpu, &wr, wi.regime); + return compute_par_s1(vcpu, &wi, &wr); } /* From c0cc438046eed8d906ac917bc70a7284b6cc3f03 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 27 Jul 2025 19:37:01 +0100 Subject: [PATCH 1796/2711] KVM: arm64: Compute shareability for LPA2 LPA2 gets the memory access shareability from TCR_ELx instead of getting it form the descriptors. Store it in the walk info struct so that it is passed around and evaluated as required. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_nested.h | 1 + arch/arm64/kvm/at.c | 37 +++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index 1a03095b03c5..f3135ded47b7 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -295,6 +295,7 @@ struct s1_walk_info { unsigned int pgshift; unsigned int txsz; int sl; + u8 sh; bool as_el0; bool hpd; bool e0poe; diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index acf6a5d49777..410d12b5b0ac 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -188,6 +188,12 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, if (!tbi && (u64)sign_extend64(va, 55) != va) goto addrsz; + wi->sh = (wi->regime == TR_EL2 ? + FIELD_GET(TCR_EL2_SH0_MASK, tcr) : + (va55 ? + FIELD_GET(TCR_SH1_MASK, tcr) : + FIELD_GET(TCR_SH0_MASK, tcr))); + va = (u64)sign_extend64(va, 55); /* Let's put the MMU disabled case aside immediately */ @@ -697,21 +703,36 @@ static u8 combine_s1_s2_attr(u8 s1, u8 s2) #define ATTR_OSH 0b10 #define ATTR_ISH 0b11 -static u8 compute_sh(u8 attr, u64 desc) +static u8 compute_final_sh(u8 attr, u8 sh) { - u8 sh; - /* Any form of device, as well as NC has SH[1:0]=0b10 */ if (MEMATTR_IS_DEVICE(attr) || attr == MEMATTR(NC, NC)) return ATTR_OSH; - sh = FIELD_GET(PTE_SHARED, desc); if (sh == ATTR_RSV) /* Reserved, mapped to NSH */ sh = ATTR_NSH; return sh; } +static u8 compute_s1_sh(struct s1_walk_info *wi, struct s1_walk_result *wr, + u8 attr) +{ + u8 sh; + + /* + * non-52bit and LPA have their basic shareability described in the + * descriptor. LPA2 gets it from the corresponding field in TCR, + * conveniently recorded in the walk info. + */ + if (!wi->pa52bit || BIT(wi->pgshift) == SZ_64K) + sh = FIELD_GET(KVM_PTE_LEAF_ATTR_LO_S1_SH, wr->desc); + else + sh = wi->sh; + + return compute_final_sh(attr, sh); +} + static u8 combine_sh(u8 s1_sh, u8 s2_sh) { if (s1_sh == ATTR_OSH || s2_sh == ATTR_OSH) @@ -725,7 +746,7 @@ static u8 combine_sh(u8 s1_sh, u8 s2_sh) static u64 compute_par_s12(struct kvm_vcpu *vcpu, u64 s1_par, struct kvm_s2_trans *tr) { - u8 s1_parattr, s2_memattr, final_attr; + u8 s1_parattr, s2_memattr, final_attr, s2_sh; u64 par; /* If S2 has failed to translate, report the damage */ @@ -798,11 +819,13 @@ static u64 compute_par_s12(struct kvm_vcpu *vcpu, u64 s1_par, !MEMATTR_IS_DEVICE(final_attr)) final_attr = MEMATTR(NC, NC); + s2_sh = FIELD_GET(KVM_PTE_LEAF_ATTR_LO_S2_SH, tr->desc); + par = FIELD_PREP(SYS_PAR_EL1_ATTR, final_attr); par |= tr->output & GENMASK(47, 12); par |= FIELD_PREP(SYS_PAR_EL1_SH, combine_sh(FIELD_GET(SYS_PAR_EL1_SH, s1_par), - compute_sh(final_attr, tr->desc))); + compute_final_sh(final_attr, s2_sh))); return par; } @@ -856,7 +879,7 @@ static u64 compute_par_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, par |= FIELD_PREP(SYS_PAR_EL1_ATTR, mair); par |= wr->pa & GENMASK_ULL(47, 12); - sh = compute_sh(mair, wr->desc); + sh = compute_s1_sh(wi, wr, mair); par |= FIELD_PREP(SYS_PAR_EL1_SH, sh); } From dd82412c2b2b30bf4aa08ef069eb38c7795cd9b8 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 27 Jul 2025 19:47:00 +0100 Subject: [PATCH 1797/2711] KVM: arm64: Populate PAR_EL1 with 52bit addresses Expand the output address populated in PAR_EL1 to 52bit addresses. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/at.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index 410d12b5b0ac..d06cf816f848 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -844,7 +844,7 @@ static u64 compute_par_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, } else if (wr->level == S1_MMU_DISABLED) { /* MMU off or HCR_EL2.DC == 1 */ par = SYS_PAR_EL1_NSE; - par |= wr->pa & GENMASK_ULL(47, 12); + par |= wr->pa & SYS_PAR_EL1_PA; if (wi->regime == TR_EL10 && (__vcpu_sys_reg(vcpu, HCR_EL2) & HCR_DC)) { @@ -877,7 +877,7 @@ static u64 compute_par_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, mair = MEMATTR(NC, NC); par |= FIELD_PREP(SYS_PAR_EL1_ATTR, mair); - par |= wr->pa & GENMASK_ULL(47, 12); + par |= wr->pa & SYS_PAR_EL1_PA; sh = compute_s1_sh(wi, wr, mair); par |= FIELD_PREP(SYS_PAR_EL1_SH, sh); From 5da3a3b27a0108562547086e0ba7d9593f147cfe Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 28 Jul 2025 16:29:56 +0100 Subject: [PATCH 1798/2711] KVM: arm64: Expand valid block mappings to FEAT_LPA/LPA2 support With 52bit PAs, block mappings can exist at different levels (such as level 0 for 4kB pages, or level 1 for 16kB and 64kB pages). Account for this in walk_s1(). Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/at.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index d06cf816f848..e740df0d82f8 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -448,11 +448,11 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, switch (BIT(wi->pgshift)) { case SZ_4K: - valid_block = level == 1 || level == 2; + valid_block = level == 1 || level == 2 || (wi->pa52bit && level == 0); break; case SZ_16K: case SZ_64K: - valid_block = level == 2; + valid_block = level == 2 || (wi->pa52bit && level == 1); break; } From dabf9f73fed86e096255c5be12c7e1d08a939c67 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 28 Jul 2025 17:20:29 +0100 Subject: [PATCH 1799/2711] KVM: arm64: Report faults from S1 walk setup at the expected start level Translation faults from TTBR must be reported on the start level, and not level-0. Enforcing this requires moving quite a lot of code around so that the start level can be computed early enough that it is usable. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/at.c | 103 +++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index e740df0d82f8..7b9711021db0 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -154,9 +154,6 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, va55 = va & BIT(55); - if (wi->regime == TR_EL2 && va55) - goto addrsz; - wi->s2 = wi->regime == TR_EL10 && (hcr & (HCR_VM | HCR_DC)); switch (wi->regime) { @@ -179,6 +176,46 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, BUG(); } + /* Someone was silly enough to encode TG0/TG1 differently */ + if (va55 && wi->regime != TR_EL2) { + wi->txsz = FIELD_GET(TCR_T1SZ_MASK, tcr); + tg = FIELD_GET(TCR_TG1_MASK, tcr); + + switch (tg << TCR_TG1_SHIFT) { + case TCR_TG1_4K: + wi->pgshift = 12; break; + case TCR_TG1_16K: + wi->pgshift = 14; break; + case TCR_TG1_64K: + default: /* IMPDEF: treat any other value as 64k */ + wi->pgshift = 16; break; + } + } else { + wi->txsz = FIELD_GET(TCR_T0SZ_MASK, tcr); + tg = FIELD_GET(TCR_TG0_MASK, tcr); + + switch (tg << TCR_TG0_SHIFT) { + case TCR_TG0_4K: + wi->pgshift = 12; break; + case TCR_TG0_16K: + wi->pgshift = 14; break; + case TCR_TG0_64K: + default: /* IMPDEF: treat any other value as 64k */ + wi->pgshift = 16; break; + } + } + + wi->pa52bit = has_52bit_pa(vcpu, wi, tcr); + + ia_bits = get_ia_size(wi); + + /* AArch64.S1StartLevel() */ + stride = wi->pgshift - 3; + wi->sl = 3 - (((ia_bits - 1) - wi->pgshift) / stride); + + if (wi->regime == TR_EL2 && va55) + goto addrsz; + tbi = (wi->regime == TR_EL2 ? FIELD_GET(TCR_EL2_TBI, tcr) : (va55 ? @@ -248,46 +285,15 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, /* R_BVXDG */ wi->hpd |= (wi->poe || wi->e0poe); - /* Someone was silly enough to encode TG0/TG1 differently */ - if (va55) { - wi->txsz = FIELD_GET(TCR_T1SZ_MASK, tcr); - tg = FIELD_GET(TCR_TG1_MASK, tcr); - - switch (tg << TCR_TG1_SHIFT) { - case TCR_TG1_4K: - wi->pgshift = 12; break; - case TCR_TG1_16K: - wi->pgshift = 14; break; - case TCR_TG1_64K: - default: /* IMPDEF: treat any other value as 64k */ - wi->pgshift = 16; break; - } - } else { - wi->txsz = FIELD_GET(TCR_T0SZ_MASK, tcr); - tg = FIELD_GET(TCR_TG0_MASK, tcr); - - switch (tg << TCR_TG0_SHIFT) { - case TCR_TG0_4K: - wi->pgshift = 12; break; - case TCR_TG0_16K: - wi->pgshift = 14; break; - case TCR_TG0_64K: - default: /* IMPDEF: treat any other value as 64k */ - wi->pgshift = 16; break; - } - } - /* R_PLCGL, R_YXNYW */ if (!kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR2_EL1, ST, 48_47)) { if (wi->txsz > 39) - goto transfault_l0; + goto transfault; } else { if (wi->txsz > 48 || (BIT(wi->pgshift) == SZ_64K && wi->txsz > 47)) - goto transfault_l0; + goto transfault; } - wi->pa52bit = has_52bit_pa(vcpu, wi, tcr); - /* R_GTJBY, R_SXWGM */ switch (BIT(wi->pgshift)) { case SZ_4K: @@ -300,28 +306,22 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, } if ((lva && wi->txsz < 12) || (!lva && wi->txsz < 16)) - goto transfault_l0; - - ia_bits = get_ia_size(wi); + goto transfault; /* R_YYVYV, I_THCZK */ if ((!va55 && va > GENMASK(ia_bits - 1, 0)) || (va55 && va < GENMASK(63, ia_bits))) - goto transfault_l0; + goto transfault; /* I_ZFSYQ */ if (wi->regime != TR_EL2 && (tcr & (va55 ? TCR_EPD1_MASK : TCR_EPD0_MASK))) - goto transfault_l0; + goto transfault; /* R_BNDVG and following statements */ if (kvm_has_feat(vcpu->kvm, ID_AA64MMFR2_EL1, E0PD, IMP) && wi->as_el0 && (tcr & (va55 ? TCR_E0PD1 : TCR_E0PD0))) - goto transfault_l0; - - /* AArch64.S1StartLevel() */ - stride = wi->pgshift - 3; - wi->sl = 3 - (((ia_bits - 1) - wi->pgshift) / stride); + goto transfault; ps = (wi->regime == TR_EL2 ? FIELD_GET(TCR_EL2_PS_MASK, tcr) : FIELD_GET(TCR_IPS_MASK, tcr)); @@ -351,12 +351,17 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, return 0; -addrsz: /* Address Size Fault level 0 */ +addrsz: + /* + * Address Size Fault level 0 to indicate it comes from TTBR. + * yes, this is an oddity. + */ fail_s1_walk(wr, ESR_ELx_FSC_ADDRSZ_L(0), false); return -EFAULT; -transfault_l0: /* Translation Fault level 0 */ - fail_s1_walk(wr, ESR_ELx_FSC_FAULT_L(0), false); +transfault: + /* Translation Fault on start level */ + fail_s1_walk(wr, ESR_ELx_FSC_FAULT_L(wi->sl), false); return -EFAULT; } From 14d4802dc22acf670333c8aad4e1931e7d6ee412 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 29 Jul 2025 12:06:14 +0100 Subject: [PATCH 1800/2711] KVM: arm64: Allow use of S1 PTW for non-NV vcpus As we are about to use the S1 PTW in non-NV contexts, we must make sure that we don't evaluate the EL2 state when dealing with the EL1&0 translation regime. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/at.c | 58 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index 7b9711021db0..9baa929c102f 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -98,21 +98,26 @@ static enum trans_regime compute_translation_regime(struct kvm_vcpu *vcpu, u32 o } } +static u64 effective_tcr2(struct kvm_vcpu *vcpu, enum trans_regime regime) +{ + if (regime == TR_EL10) { + if (vcpu_has_nv(vcpu) && + !(__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En)) + return 0; + + return __vcpu_sys_reg(vcpu, TCR2_EL1); + } + + return vcpu_read_sys_reg(vcpu, TCR2_EL2); +} + static bool s1pie_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime) { if (!kvm_has_s1pie(vcpu->kvm)) return false; - switch (regime) { - case TR_EL2: - case TR_EL20: - return vcpu_read_sys_reg(vcpu, TCR2_EL2) & TCR2_EL2_PIE; - case TR_EL10: - return (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En) && - (__vcpu_sys_reg(vcpu, TCR2_EL1) & TCR2_EL1_PIE); - default: - BUG(); - } + /* Abuse TCR2_EL1_PIE and use it for EL2 as well */ + return effective_tcr2(vcpu, regime) & TCR2_EL1_PIE; } static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi) @@ -124,23 +129,11 @@ static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi) return; } - switch (wi->regime) { - case TR_EL2: - case TR_EL20: - val = vcpu_read_sys_reg(vcpu, TCR2_EL2); - wi->poe = val & TCR2_EL2_POE; - wi->e0poe = (wi->regime == TR_EL20) && (val & TCR2_EL2_E0POE); - break; - case TR_EL10: - if (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En) { - wi->poe = wi->e0poe = false; - return; - } + val = effective_tcr2(vcpu, wi->regime); - val = __vcpu_sys_reg(vcpu, TCR2_EL1); - wi->poe = val & TCR2_EL1_POE; - wi->e0poe = val & TCR2_EL1_E0POE; - } + /* Abuse TCR2_EL1_* for EL2 */ + wi->poe = val & TCR2_EL1_POE; + wi->e0poe = (wi->regime != TR_EL2) && (val & TCR2_EL1_E0POE); } static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, @@ -150,11 +143,16 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, unsigned int stride, x; bool va55, tbi, lva; - hcr = __vcpu_sys_reg(vcpu, HCR_EL2); - va55 = va & BIT(55); - wi->s2 = wi->regime == TR_EL10 && (hcr & (HCR_VM | HCR_DC)); + if (vcpu_has_nv(vcpu)) { + hcr = __vcpu_sys_reg(vcpu, HCR_EL2); + wi->s2 = wi->regime == TR_EL10 && (hcr & (HCR_VM | HCR_DC)); + } else { + WARN_ON_ONCE(wi->regime != TR_EL10); + wi->s2 = false; + hcr = 0; + } switch (wi->regime) { case TR_EL10: @@ -851,7 +849,7 @@ static u64 compute_par_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, par = SYS_PAR_EL1_NSE; par |= wr->pa & SYS_PAR_EL1_PA; - if (wi->regime == TR_EL10 && + if (wi->regime == TR_EL10 && vcpu_has_nv(vcpu) && (__vcpu_sys_reg(vcpu, HCR_EL2) & HCR_DC)) { par |= FIELD_PREP(SYS_PAR_EL1_ATTR, MEMATTR(WbRaWa, WbRaWa)); From cb1762904c5000220a0facf9bcab68ba687ec417 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 25 Aug 2025 15:20:06 +0100 Subject: [PATCH 1801/2711] KVM: arm64: Allow EL1 control registers to be accessed from the CPU state As we are about to plug the SW PTW into the EL1-only code, we can no longer assume that the EL1 state is not resident on the CPU, as we don't necessarily get there from EL2 traps. Turn the __vcpu_sys_reg() access on the EL1 state into calls to the vcpu_read_sys_reg() helper, which is guaranteed to do the right thing. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/at.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index 9baa929c102f..4efa2167116f 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -105,7 +105,7 @@ static u64 effective_tcr2(struct kvm_vcpu *vcpu, enum trans_regime regime) !(__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En)) return 0; - return __vcpu_sys_reg(vcpu, TCR2_EL1); + return vcpu_read_sys_reg(vcpu, TCR2_EL1); } return vcpu_read_sys_reg(vcpu, TCR2_EL2); @@ -956,7 +956,7 @@ static void compute_s1_direct_permissions(struct kvm_vcpu *vcpu, wxn = (vcpu_read_sys_reg(vcpu, SCTLR_EL2) & SCTLR_ELx_WXN); break; case TR_EL10: - wxn = (__vcpu_sys_reg(vcpu, SCTLR_EL1) & SCTLR_ELx_WXN); + wxn = (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & SCTLR_ELx_WXN); break; } From 61b0280a670bdbb3a209ae474625f387788af0a8 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 25 Aug 2025 11:24:11 +0100 Subject: [PATCH 1802/2711] KVM: arm64: Don't switch MMU on translation from non-NV context If calling into the AT code from guest EL1, there is no need to consider any context switch, as we are guaranteed to be in the correct context. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/at.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index 4efa2167116f..c06a8e831f33 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -1285,7 +1285,7 @@ static u64 __kvm_at_s1e01_fast(struct kvm_vcpu *vcpu, u32 op, u64 vaddr) { struct mmu_config config; struct kvm_s2_mmu *mmu; - bool fail; + bool fail, mmu_cs; u64 par; par = SYS_PAR_EL1_F; @@ -1301,8 +1301,13 @@ static u64 __kvm_at_s1e01_fast(struct kvm_vcpu *vcpu, u32 op, u64 vaddr) * If HCR_EL2.{E2H,TGE} == {1,1}, the MMU context is already * the right one (as we trapped from vEL2). If not, save the * full MMU context. + * + * We are also guaranteed to be in the correct context if + * we're not in a nested VM. */ - if (vcpu_el2_e2h_is_set(vcpu) && vcpu_el2_tge_is_set(vcpu)) + mmu_cs = (vcpu_has_nv(vcpu) && + !(vcpu_el2_e2h_is_set(vcpu) && vcpu_el2_tge_is_set(vcpu))); + if (!mmu_cs) goto skip_mmu_switch; /* @@ -1370,7 +1375,7 @@ skip_mmu_switch: write_sysreg_hcr(HCR_HOST_VHE_FLAGS); - if (!(vcpu_el2_e2h_is_set(vcpu) && vcpu_el2_tge_is_set(vcpu))) + if (mmu_cs) __mmu_config_restore(&config); return par; From 0c5471408cb5c518bce76b851aff89719283a428 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 25 Aug 2025 11:28:19 +0100 Subject: [PATCH 1803/2711] KVM: arm64: Add filtering hook to S1 page table walk Add a filtering hook that can get called on each level of the walk, and providing access to the full state. Crucially, this is called *before* the access is made, so that it is possible to track down the level of a faulting access. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_nested.h | 14 ++++++++++++++ arch/arm64/kvm/at.c | 11 +++++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index f3135ded47b7..cce0e4cb5448 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -288,7 +288,21 @@ enum trans_regime { TR_EL2, }; +struct s1_walk_info; + +struct s1_walk_context { + struct s1_walk_info *wi; + u64 table_ipa; + int level; +}; + +struct s1_walk_filter { + int (*fn)(struct s1_walk_context *, void *); + void *priv; +}; + struct s1_walk_info { + struct s1_walk_filter *filter; u64 baddr; enum trans_regime regime; unsigned int max_oa_bits; diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index c06a8e831f33..b70b777a3c20 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -404,6 +404,17 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, ipa = kvm_s2_trans_output(&s2_trans); } + if (wi->filter) { + ret = wi->filter->fn(&(struct s1_walk_context) + { + .wi = wi, + .table_ipa = baddr, + .level = level, + }, wi->filter->priv); + if (ret) + return ret; + } + ret = kvm_read_guest(vcpu->kvm, ipa, &desc, sizeof(desc)); if (ret) { fail_s1_walk(wr, ESR_ELx_FSC_SEA_TTW(level), false); From b8e625167a321138f83b1f6c99cf25d1290cb04e Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 25 Aug 2025 11:31:33 +0100 Subject: [PATCH 1804/2711] KVM: arm64: Add S1 IPA to page table level walker Use the filtering hook infrastructure to implement a new walker that, for a given VA and an IPA, returns the level of the first occurence of this IPA in the walk from that VA. This will be used to improve our SEA syndrome reporting. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_nested.h | 2 + arch/arm64/kvm/at.c | 65 +++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index cce0e4cb5448..2be6c3de74e3 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -353,6 +353,8 @@ struct s1_walk_result { int __kvm_translate_va(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, struct s1_walk_result *wr, u64 va); +int __kvm_find_s1_desc_level(struct kvm_vcpu *vcpu, u64 va, u64 ipa, + int *level); /* VNCR management */ int kvm_vcpu_allocate_vncr_tlb(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index b70b777a3c20..20bb9af125b1 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -1569,3 +1569,68 @@ int __kvm_translate_va(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, return 0; } + +struct desc_match { + u64 ipa; + int level; +}; + +static int match_s1_desc(struct s1_walk_context *ctxt, void *priv) +{ + struct desc_match *dm = priv; + u64 ipa = dm->ipa; + + /* Use S1 granule alignment */ + ipa &= GENMASK(51, ctxt->wi->pgshift); + + /* Not the IPA we're looking for? Continue. */ + if (ipa != ctxt->table_ipa) + return 0; + + /* Note the level and interrupt the walk */ + dm->level = ctxt->level; + return -EINTR; +} + +int __kvm_find_s1_desc_level(struct kvm_vcpu *vcpu, u64 va, u64 ipa, int *level) +{ + struct desc_match dm = { + .ipa = ipa, + }; + struct s1_walk_info wi = { + .filter = &(struct s1_walk_filter){ + .fn = match_s1_desc, + .priv = &dm, + }, + .regime = TR_EL10, + .as_el0 = false, + .pan = false, + }; + struct s1_walk_result wr = {}; + int ret; + + ret = setup_s1_walk(vcpu, &wi, &wr, va); + if (ret) + return ret; + + /* We really expect the S1 MMU to be on here... */ + if (WARN_ON_ONCE(wr.level == S1_MMU_DISABLED)) { + *level = 0; + return 0; + } + + /* Walk the guest's PT, looking for a match along the way */ + ret = walk_s1(vcpu, &wi, &wr, va); + switch (ret) { + case -EINTR: + /* We interrupted the walk on a match, return the level */ + *level = dm.level; + return 0; + case 0: + /* The walk completed, we failed to find the entry */ + return -ENOENT; + default: + /* Any other error... */ + return ret; + } +} From 50f77dc87f133b09db44a5bbfdd64b1ca83a8d8e Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 25 Aug 2025 13:13:56 +0100 Subject: [PATCH 1805/2711] KVM: arm64: Populate level on S1PTW SEA injection Our fault injection mechanism is mildly primitive, and doesn't really implement the architecture when it comes to reporting the level of a failing S1 PTW (we blindly report a SEA outside of a PTW). Now that we can walk the S1 page tables and look for a particular IPA in the descriptors, it is pretty easy to improve the SEA injection code. Note that we only do it for AArch64 guests, and that 32bit guests are left to their own device (oddly enough, I don't fancy writing a 32bit PTW...). Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- arch/arm64/kvm/inject_fault.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index 6745f38b64f9..dfcd66c65517 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -106,7 +106,30 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr { unsigned long cpsr = *vcpu_cpsr(vcpu); bool is_aarch32 = vcpu_mode_is_32bit(vcpu); - u64 esr = 0; + u64 esr = 0, fsc; + int level; + + /* + * If injecting an abort from a failed S1PTW, rewalk the S1 PTs to + * find the failing level. If we can't find it, assume the error was + * transient and restart without changing the state. + */ + if (kvm_vcpu_abt_iss1tw(vcpu)) { + u64 hpfar = kvm_vcpu_get_fault_ipa(vcpu); + int ret; + + if (hpfar == INVALID_GPA) + return; + + ret = __kvm_find_s1_desc_level(vcpu, addr, hpfar, &level); + if (ret) + return; + + WARN_ON_ONCE(level < -1 || level > 3); + fsc = ESR_ELx_FSC_SEA_TTW(level); + } else { + fsc = ESR_ELx_FSC_EXTABT; + } /* This delight is brought to you by FEAT_DoubleFault2. */ if (effective_sctlr2_ease(vcpu)) @@ -133,7 +156,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr if (!is_iabt) esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT; - esr |= ESR_ELx_FSC_EXTABT; + esr |= fsc; vcpu_write_sys_reg(vcpu, addr, exception_far_elx(vcpu)); vcpu_write_sys_reg(vcpu, esr, exception_esr_elx(vcpu)); From 00a37271c8a68070dc64f81a5d64644beb4cef2f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 26 Aug 2025 17:33:24 +0100 Subject: [PATCH 1806/2711] KVM: arm64: selftest: Expand external_aborts test to look for TTW levels Add a basic test corrupting a level-2 table entry to check that the resulting abort is a SEA on a PTW at level-3. Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- .../selftests/kvm/arm64/external_aborts.c | 42 +++++++++++++++++++ .../selftests/kvm/include/arm64/processor.h | 1 + .../selftests/kvm/lib/arm64/processor.c | 13 +++++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/arm64/external_aborts.c b/tools/testing/selftests/kvm/arm64/external_aborts.c index 062bf84cced1..592b26ded779 100644 --- a/tools/testing/selftests/kvm/arm64/external_aborts.c +++ b/tools/testing/selftests/kvm/arm64/external_aborts.c @@ -250,6 +250,47 @@ static void test_serror(void) kvm_vm_free(vm); } +static void expect_sea_s1ptw_handler(struct ex_regs *regs) +{ + u64 esr = read_sysreg(esr_el1); + + GUEST_ASSERT_EQ(regs->pc, expected_abort_pc); + GUEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_CUR); + GUEST_ASSERT_EQ((esr & ESR_ELx_FSC), ESR_ELx_FSC_SEA_TTW(3)); + + GUEST_DONE(); +} + +static noinline void test_s1ptw_abort_guest(void) +{ + extern char test_s1ptw_abort_insn; + + WRITE_ONCE(expected_abort_pc, (u64)&test_s1ptw_abort_insn); + + asm volatile("test_s1ptw_abort_insn:\n\t" + "ldr x0, [%0]\n\t" + : : "r" (MMIO_ADDR) : "x0", "memory"); + + GUEST_FAIL("Load on S1PTW abort should not retire"); +} + +static void test_s1ptw_abort(void) +{ + struct kvm_vcpu *vcpu; + u64 *ptep, bad_pa; + struct kvm_vm *vm = vm_create_with_dabt_handler(&vcpu, test_s1ptw_abort_guest, + expect_sea_s1ptw_handler); + + ptep = virt_get_pte_hva_at_level(vm, MMIO_ADDR, 2); + bad_pa = BIT(vm->pa_bits) - vm->page_size; + + *ptep &= ~GENMASK(47, 12); + *ptep |= bad_pa; + + vcpu_run_expect_done(vcpu); + kvm_vm_free(vm); +} + static void test_serror_emulated_guest(void) { GUEST_ASSERT(!(read_sysreg(isr_el1) & ISR_EL1_A)); @@ -327,4 +368,5 @@ int main(void) test_serror_masked(); test_serror_emulated(); test_mmio_ease(); + test_s1ptw_abort(); } diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h index 255fed769a8a..e3e916b1d9c4 100644 --- a/tools/testing/selftests/kvm/include/arm64/processor.h +++ b/tools/testing/selftests/kvm/include/arm64/processor.h @@ -175,6 +175,7 @@ void vm_install_exception_handler(struct kvm_vm *vm, void vm_install_sync_handler(struct kvm_vm *vm, int vector, int ec, handler_fn handler); +uint64_t *virt_get_pte_hva_at_level(struct kvm_vm *vm, vm_vaddr_t gva, int level); uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva); static inline void cpu_relax(void) diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index eb115123d741..bd7480a93f96 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -185,7 +185,7 @@ void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) _virt_pg_map(vm, vaddr, paddr, attr_idx); } -uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva) +uint64_t *virt_get_pte_hva_at_level(struct kvm_vm *vm, vm_vaddr_t gva, int level) { uint64_t *ptep; @@ -195,17 +195,23 @@ uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva) ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, gva) * 8; if (!ptep) goto unmapped_gva; + if (level == 0) + return ptep; switch (vm->pgtable_levels) { case 4: ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8; if (!ptep) goto unmapped_gva; + if (level == 1) + break; /* fall through */ case 3: ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, gva) * 8; if (!ptep) goto unmapped_gva; + if (level == 2) + break; /* fall through */ case 2: ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, gva) * 8; @@ -223,6 +229,11 @@ unmapped_gva: exit(EXIT_FAILURE); } +uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva) +{ + return virt_get_pte_hva_at_level(vm, gva, 3); +} + vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) { uint64_t *ptep = virt_get_pte_hva(vm, gva); From f75f66683ded09f7135aef2e763c245a07c8271a Mon Sep 17 00:00:00 2001 From: Dan Moulding Date: Mon, 8 Sep 2025 10:12:43 -0600 Subject: [PATCH 1807/2711] crypto: comp - Use same definition of context alloc and free ops In commit 42d9f6c77479 ("crypto: acomp - Move scomp stream allocation code into acomp"), the crypto_acomp_streams struct was made to rely on having the alloc_ctx and free_ctx operations defined in the same order as the scomp_alg struct. But in that same commit, the alloc_ctx and free_ctx members of scomp_alg may be randomized by structure layout randomization, since they are contained in a pure ops structure (containing only function pointers). If the pointers within scomp_alg are randomized, but those in crypto_acomp_streams are not, then the order may no longer match. This fixes the problem by removing the union from scomp_alg so that both crypto_acomp_streams and scomp_alg will share the same definition of alloc_ctx and free_ctx, ensuring they will always have the same layout. Signed-off-by: Dan Moulding Suggested-by: Herbert Xu Fixes: 42d9f6c77479 ("crypto: acomp - Move scomp stream allocation code into acomp") Signed-off-by: Herbert Xu --- crypto/842.c | 6 ++++-- crypto/lz4.c | 6 ++++-- crypto/lz4hc.c | 6 ++++-- crypto/lzo-rle.c | 6 ++++-- crypto/lzo.c | 6 ++++-- drivers/crypto/nx/nx-common-powernv.c | 6 ++++-- drivers/crypto/nx/nx-common-pseries.c | 6 ++++-- include/crypto/internal/scompress.h | 11 +---------- 8 files changed, 29 insertions(+), 24 deletions(-) diff --git a/crypto/842.c b/crypto/842.c index 8c257c40e2b9..4007e87bed80 100644 --- a/crypto/842.c +++ b/crypto/842.c @@ -54,8 +54,10 @@ static int crypto842_sdecompress(struct crypto_scomp *tfm, } static struct scomp_alg scomp = { - .alloc_ctx = crypto842_alloc_ctx, - .free_ctx = crypto842_free_ctx, + .streams = { + .alloc_ctx = crypto842_alloc_ctx, + .free_ctx = crypto842_free_ctx, + }, .compress = crypto842_scompress, .decompress = crypto842_sdecompress, .base = { diff --git a/crypto/lz4.c b/crypto/lz4.c index 7a984ae5ae52..57b713516aef 100644 --- a/crypto/lz4.c +++ b/crypto/lz4.c @@ -68,8 +68,10 @@ static int lz4_sdecompress(struct crypto_scomp *tfm, const u8 *src, } static struct scomp_alg scomp = { - .alloc_ctx = lz4_alloc_ctx, - .free_ctx = lz4_free_ctx, + .streams = { + .alloc_ctx = lz4_alloc_ctx, + .free_ctx = lz4_free_ctx, + }, .compress = lz4_scompress, .decompress = lz4_sdecompress, .base = { diff --git a/crypto/lz4hc.c b/crypto/lz4hc.c index 9c61d05b6214..bb84f8a68cb5 100644 --- a/crypto/lz4hc.c +++ b/crypto/lz4hc.c @@ -66,8 +66,10 @@ static int lz4hc_sdecompress(struct crypto_scomp *tfm, const u8 *src, } static struct scomp_alg scomp = { - .alloc_ctx = lz4hc_alloc_ctx, - .free_ctx = lz4hc_free_ctx, + .streams = { + .alloc_ctx = lz4hc_alloc_ctx, + .free_ctx = lz4hc_free_ctx, + }, .compress = lz4hc_scompress, .decompress = lz4hc_sdecompress, .base = { diff --git a/crypto/lzo-rle.c b/crypto/lzo-rle.c index ba013f2d5090..794e7ec49536 100644 --- a/crypto/lzo-rle.c +++ b/crypto/lzo-rle.c @@ -70,8 +70,10 @@ static int lzorle_sdecompress(struct crypto_scomp *tfm, const u8 *src, } static struct scomp_alg scomp = { - .alloc_ctx = lzorle_alloc_ctx, - .free_ctx = lzorle_free_ctx, + .streams = { + .alloc_ctx = lzorle_alloc_ctx, + .free_ctx = lzorle_free_ctx, + }, .compress = lzorle_scompress, .decompress = lzorle_sdecompress, .base = { diff --git a/crypto/lzo.c b/crypto/lzo.c index 7867e2c67c4e..d43242b24b4e 100644 --- a/crypto/lzo.c +++ b/crypto/lzo.c @@ -70,8 +70,10 @@ static int lzo_sdecompress(struct crypto_scomp *tfm, const u8 *src, } static struct scomp_alg scomp = { - .alloc_ctx = lzo_alloc_ctx, - .free_ctx = lzo_free_ctx, + .streams = { + .alloc_ctx = lzo_alloc_ctx, + .free_ctx = lzo_free_ctx, + }, .compress = lzo_scompress, .decompress = lzo_sdecompress, .base = { diff --git a/drivers/crypto/nx/nx-common-powernv.c b/drivers/crypto/nx/nx-common-powernv.c index fd0a98b2fb1b..0493041ea088 100644 --- a/drivers/crypto/nx/nx-common-powernv.c +++ b/drivers/crypto/nx/nx-common-powernv.c @@ -1043,8 +1043,10 @@ static struct scomp_alg nx842_powernv_alg = { .base.cra_priority = 300, .base.cra_module = THIS_MODULE, - .alloc_ctx = nx842_powernv_crypto_alloc_ctx, - .free_ctx = nx842_crypto_free_ctx, + .streams = { + .alloc_ctx = nx842_powernv_crypto_alloc_ctx, + .free_ctx = nx842_crypto_free_ctx, + }, .compress = nx842_crypto_compress, .decompress = nx842_crypto_decompress, }; diff --git a/drivers/crypto/nx/nx-common-pseries.c b/drivers/crypto/nx/nx-common-pseries.c index f528e072494a..fc0222ebe807 100644 --- a/drivers/crypto/nx/nx-common-pseries.c +++ b/drivers/crypto/nx/nx-common-pseries.c @@ -1020,8 +1020,10 @@ static struct scomp_alg nx842_pseries_alg = { .base.cra_priority = 300, .base.cra_module = THIS_MODULE, - .alloc_ctx = nx842_pseries_crypto_alloc_ctx, - .free_ctx = nx842_crypto_free_ctx, + .streams = { + .alloc_ctx = nx842_pseries_crypto_alloc_ctx, + .free_ctx = nx842_crypto_free_ctx, + }, .compress = nx842_crypto_compress, .decompress = nx842_crypto_decompress, }; diff --git a/include/crypto/internal/scompress.h b/include/crypto/internal/scompress.h index 533d6c16a491..6a2c5f2e90f9 100644 --- a/include/crypto/internal/scompress.h +++ b/include/crypto/internal/scompress.h @@ -18,11 +18,8 @@ struct crypto_scomp { /** * struct scomp_alg - synchronous compression algorithm * - * @alloc_ctx: Function allocates algorithm specific context - * @free_ctx: Function frees context allocated with alloc_ctx * @compress: Function performs a compress operation * @decompress: Function performs a de-compress operation - * @base: Common crypto API algorithm data structure * @streams: Per-cpu memory for algorithm * @calg: Cmonn algorithm data structure shared with acomp */ @@ -34,13 +31,7 @@ struct scomp_alg { unsigned int slen, u8 *dst, unsigned int *dlen, void *ctx); - union { - struct { - void *(*alloc_ctx)(void); - void (*free_ctx)(void *ctx); - }; - struct crypto_acomp_streams streams; - }; + struct crypto_acomp_streams streams; union { struct COMP_ALG_COMMON; From bee8a520eb84950193d0566ea2c2e46406a4b6ce Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 9 Sep 2025 17:50:56 +0800 Subject: [PATCH 1808/2711] rhashtable: Use rcu_dereference_all and rcu_dereference_all_check Add rcu_dereference_all and rcu_dereference_all_check so that library code such as rhashtable can be used with any RCU variant. As it stands rcu_dereference is used within rashtable, which creates false-positive warnings if the user calls it from another RCU context, such as preempt_disable(). Use the rcu_dereference_all and rcu_dereference_all_check calls in rhashtable to suppress these warnings. Also replace the rcu_dereference_raw calls in the list iterators with rcu_dereference_all to uncover buggy calls. Reported-by: Menglong Dong Signed-off-by: Herbert Xu Reviewed-by: Paul E. McKenney Signed-off-by: Herbert Xu --- include/linux/rcupdate.h | 26 ++++++++++++++++++++++++++ include/linux/rhashtable.h | 14 +++++++------- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 120536f4c6eb..448eb1f0cb48 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -713,6 +713,24 @@ do { \ (c) || rcu_read_lock_sched_held(), \ __rcu) +/** + * rcu_dereference_all_check() - rcu_dereference_all with debug checking + * @p: The pointer to read, prior to dereferencing + * @c: The conditions under which the dereference will take place + * + * This is similar to rcu_dereference_check(), but allows protection + * by all forms of vanilla RCU readers, including preemption disabled, + * bh-disabled, and interrupt-disabled regions of code. Note that "vanilla + * RCU" excludes SRCU and the various Tasks RCU flavors. Please note + * that this macro should not be backported to any Linux-kernel version + * preceding v5.0 due to changes in synchronize_rcu() semantics prior + * to that version. + */ +#define rcu_dereference_all_check(p, c) \ + __rcu_dereference_check((p), __UNIQUE_ID(rcu), \ + (c) || rcu_read_lock_any_held(), \ + __rcu) + /* * The tracing infrastructure traces RCU (we want that), but unfortunately * some of the RCU checks causes tracing to lock up the system. @@ -767,6 +785,14 @@ do { \ */ #define rcu_dereference_sched(p) rcu_dereference_sched_check(p, 0) +/** + * rcu_dereference_all() - fetch RCU-all-protected pointer for dereferencing + * @p: The pointer to read, prior to dereferencing + * + * Makes rcu_dereference_check() do the dirty work. + */ +#define rcu_dereference_all(p) rcu_dereference_all_check(p, 0) + /** * rcu_pointer_handoff() - Hand off a pointer from RCU to other mechanism * @p: The pointer to hand off diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h index e740157f3cd7..05a221ce79a6 100644 --- a/include/linux/rhashtable.h +++ b/include/linux/rhashtable.h @@ -272,13 +272,13 @@ struct rhash_lock_head __rcu **rht_bucket_nested_insert( rcu_dereference_protected(p, lockdep_rht_mutex_is_held(ht)) #define rht_dereference_rcu(p, ht) \ - rcu_dereference_check(p, lockdep_rht_mutex_is_held(ht)) + rcu_dereference_all_check(p, lockdep_rht_mutex_is_held(ht)) #define rht_dereference_bucket(p, tbl, hash) \ rcu_dereference_protected(p, lockdep_rht_bucket_is_held(tbl, hash)) #define rht_dereference_bucket_rcu(p, tbl, hash) \ - rcu_dereference_check(p, lockdep_rht_bucket_is_held(tbl, hash)) + rcu_dereference_all_check(p, lockdep_rht_bucket_is_held(tbl, hash)) #define rht_entry(tpos, pos, member) \ ({ tpos = container_of(pos, typeof(*tpos), member); 1; }) @@ -373,7 +373,7 @@ static inline struct rhash_head *__rht_ptr( static inline struct rhash_head *rht_ptr_rcu( struct rhash_lock_head __rcu *const *bkt) { - return __rht_ptr(rcu_dereference(*bkt), bkt); + return __rht_ptr(rcu_dereference_all(*bkt), bkt); } static inline struct rhash_head *rht_ptr( @@ -497,7 +497,7 @@ static inline void rht_assign_unlock(struct bucket_table *tbl, for (({barrier(); }), \ pos = head; \ !rht_is_a_nulls(pos); \ - pos = rcu_dereference_raw(pos->next)) + pos = rcu_dereference_all(pos->next)) /** * rht_for_each_rcu - iterate over rcu hash chain @@ -513,7 +513,7 @@ static inline void rht_assign_unlock(struct bucket_table *tbl, for (({barrier(); }), \ pos = rht_ptr_rcu(rht_bucket(tbl, hash)); \ !rht_is_a_nulls(pos); \ - pos = rcu_dereference_raw(pos->next)) + pos = rcu_dereference_all(pos->next)) /** * rht_for_each_entry_rcu_from - iterated over rcu hash chain from given head @@ -560,7 +560,7 @@ static inline void rht_assign_unlock(struct bucket_table *tbl, * list returned by rhltable_lookup. */ #define rhl_for_each_rcu(pos, list) \ - for (pos = list; pos; pos = rcu_dereference_raw(pos->next)) + for (pos = list; pos; pos = rcu_dereference_all(pos->next)) /** * rhl_for_each_entry_rcu - iterate over rcu hash table list of given type @@ -574,7 +574,7 @@ static inline void rht_assign_unlock(struct bucket_table *tbl, */ #define rhl_for_each_entry_rcu(tpos, pos, list, member) \ for (pos = list; pos && rht_entry(tpos, pos, member); \ - pos = rcu_dereference_raw(pos->next)) + pos = rcu_dereference_all(pos->next)) static inline int rhashtable_compare(struct rhashtable_compare_arg *arg, const void *obj) From 838d2d51513e6d2504a678e906823cfd2ecaaa22 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 10 Sep 2025 10:22:31 +0200 Subject: [PATCH 1809/2711] crypto: aspeed - Fix dma_unmap_sg() direction It seems like everywhere in this file, when the request is not bidirectionala, req->src is mapped with DMA_TO_DEVICE and req->dst is mapped with DMA_FROM_DEVICE. Fixes: 62f58b1637b7 ("crypto: aspeed - add HACE crypto driver") Cc: Signed-off-by: Thomas Fourier Signed-off-by: Herbert Xu --- drivers/crypto/aspeed/aspeed-hace-crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/aspeed-hace-crypto.c index a72dfebc53ff..fa201dae1f81 100644 --- a/drivers/crypto/aspeed/aspeed-hace-crypto.c +++ b/drivers/crypto/aspeed/aspeed-hace-crypto.c @@ -346,7 +346,7 @@ free_req: } else { dma_unmap_sg(hace_dev->dev, req->dst, rctx->dst_nents, - DMA_TO_DEVICE); + DMA_FROM_DEVICE); dma_unmap_sg(hace_dev->dev, req->src, rctx->src_nents, DMA_TO_DEVICE); } From 5ce9891ea928208a915411ce8227f8c3e37e5ad9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 13 Sep 2025 12:24:55 +0800 Subject: [PATCH 1810/2711] crypto: qat - Return pointer directly in adf_ctl_alloc_resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Returning values through arguments is confusing and that has upset the compiler with the recent change to memdup_user: ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c: In function ‘adf_ctl_ioctl’: ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:308:26: warning: ‘ctl_data’ may be used uninitialized [-Wmaybe-uninitialized] 308 | ctl_data->device_id); | ^~ ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:294:39: note: ‘ctl_data’ was declared here 294 | struct adf_user_cfg_ctl_data *ctl_data; | ^~~~~~~~ In function ‘adf_ctl_ioctl_dev_stop’, inlined from ‘adf_ctl_ioctl’ at ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:386:9: ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:273:48: warning: ‘ctl_data’ may be used uninitialized [-Wmaybe-uninitialized] 273 | ret = adf_ctl_is_device_in_use(ctl_data->device_id); | ~~~~~~~~^~~~~~~~~~~ ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c: In function ‘adf_ctl_ioctl’: ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:261:39: note: ‘ctl_data’ was declared here 261 | struct adf_user_cfg_ctl_data *ctl_data; | ^~~~~~~~ In function ‘adf_ctl_ioctl_dev_config’, inlined from ‘adf_ctl_ioctl’ at ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:382:9: ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:192:54: warning: ‘ctl_data’ may be used uninitialized [-Wmaybe-uninitialized] 192 | accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id); | ~~~~~~~~^~~~~~~~~~~ ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c: In function ‘adf_ctl_ioctl’: ../drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c:185:39: note: ‘ctl_data’ was declared here 185 | struct adf_user_cfg_ctl_data *ctl_data; | ^~~~~~~~ Fix this by returning the pointer directly. Signed-off-by: Herbert Xu Reviewed-by: Thorsten Blum Acked-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../crypto/intel/qat/qat_common/adf_ctl_drv.c | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c index 84bc89e16742..c2e6f0cb7480 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c @@ -89,19 +89,14 @@ err_chrdev_unreg: return -EFAULT; } -static int adf_ctl_alloc_resources(struct adf_user_cfg_ctl_data **ctl_data, - unsigned long arg) +static struct adf_user_cfg_ctl_data *adf_ctl_alloc_resources(unsigned long arg) { struct adf_user_cfg_ctl_data *cfg_data; cfg_data = memdup_user((void __user *)arg, sizeof(*cfg_data)); - if (IS_ERR(cfg_data)) { + if (IS_ERR(cfg_data)) pr_err("QAT: failed to copy from user cfg_data.\n"); - return PTR_ERR(cfg_data); - } - - *ctl_data = cfg_data; - return 0; + return cfg_data; } static int adf_add_key_value_data(struct adf_accel_dev *accel_dev, @@ -181,13 +176,13 @@ out_err: static int adf_ctl_ioctl_dev_config(struct file *fp, unsigned int cmd, unsigned long arg) { - int ret; struct adf_user_cfg_ctl_data *ctl_data; struct adf_accel_dev *accel_dev; + int ret = 0; - ret = adf_ctl_alloc_resources(&ctl_data, arg); - if (ret) - return ret; + ctl_data = adf_ctl_alloc_resources(arg); + if (IS_ERR(ctl_data)) + return PTR_ERR(ctl_data); accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id); if (!accel_dev) { @@ -260,9 +255,9 @@ static int adf_ctl_ioctl_dev_stop(struct file *fp, unsigned int cmd, int ret; struct adf_user_cfg_ctl_data *ctl_data; - ret = adf_ctl_alloc_resources(&ctl_data, arg); - if (ret) - return ret; + ctl_data = adf_ctl_alloc_resources(arg); + if (IS_ERR(ctl_data)) + return PTR_ERR(ctl_data); if (adf_devmgr_verify_id(ctl_data->device_id)) { pr_err("QAT: Device %d not found\n", ctl_data->device_id); @@ -294,9 +289,9 @@ static int adf_ctl_ioctl_dev_start(struct file *fp, unsigned int cmd, struct adf_user_cfg_ctl_data *ctl_data; struct adf_accel_dev *accel_dev; - ret = adf_ctl_alloc_resources(&ctl_data, arg); - if (ret) - return ret; + ctl_data = adf_ctl_alloc_resources(arg); + if (IS_ERR(ctl_data)) + return PTR_ERR(ctl_data); ret = -ENODEV; accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id); From 85acd1b26b8f5b838887dc965dc3aa2c0253f4d1 Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Sat, 13 Sep 2025 18:57:50 +0800 Subject: [PATCH 1811/2711] crypto: hisilicon/qm - invalidate queues in use Before the device reset, although the driver has set the queue status to intercept doorbells sent by the task process, the reset thread is isolated from the user-mode task process, so the task process may still send doorbells. Therefore, before the reset, the queue is directly invalidated, and the device directly discards the doorbells sent by the process. Signed-off-by: Weili Qian Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 53 ++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 98099117bb38..c1ffaae78532 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -45,6 +45,8 @@ #define QM_SQ_TYPE_MASK GENMASK(3, 0) #define QM_SQ_TAIL_IDX(sqc) ((le16_to_cpu((sqc).w11) >> 6) & 0x1) +#define QM_SQC_DISABLE_QP (1U << 6) +#define QM_XQC_RANDOM_DATA 0xaaaa /* cqc shift */ #define QM_CQ_HOP_NUM_SHIFT 0 @@ -3194,6 +3196,9 @@ static int qm_eq_aeq_ctx_cfg(struct hisi_qm *qm) qm_init_eq_aeq_status(qm); + /* Before starting the dev, clear the memory and then configure to device using. */ + memset(qm->qdma.va, 0, qm->qdma.size); + ret = qm_eq_ctx_cfg(qm); if (ret) { dev_err(dev, "Set eqc failed!\n"); @@ -3205,9 +3210,13 @@ static int qm_eq_aeq_ctx_cfg(struct hisi_qm *qm) static int __hisi_qm_start(struct hisi_qm *qm) { + struct device *dev = &qm->pdev->dev; int ret; - WARN_ON(!qm->qdma.va); + if (!qm->qdma.va) { + dev_err(dev, "qm qdma is NULL!\n"); + return -EINVAL; + } if (qm->fun_type == QM_HW_PF) { ret = hisi_qm_set_vft(qm, 0, qm->qp_base, qm->qp_num); @@ -3281,7 +3290,7 @@ static int qm_restart(struct hisi_qm *qm) for (i = 0; i < qm->qp_num; i++) { qp = &qm->qp_array[i]; if (atomic_read(&qp->qp_status.flags) == QP_STOP && - qp->is_resetting == true) { + qp->is_resetting == true && qp->is_in_kernel == true) { ret = qm_start_qp_nolock(qp, 0); if (ret < 0) { dev_err(dev, "Failed to start qp%d!\n", i); @@ -3313,24 +3322,44 @@ static void qm_stop_started_qp(struct hisi_qm *qm) } /** - * qm_clear_queues() - Clear all queues memory in a qm. - * @qm: The qm in which the queues will be cleared. + * qm_invalid_queues() - invalid all queues in use. + * @qm: The qm in which the queues will be invalidated. * - * This function clears all queues memory in a qm. Reset of accelerator can - * use this to clear queues. + * This function invalid all queues in use. If the doorbell command is sent + * to device in user space after the device is reset, the device discards + * the doorbell command. */ -static void qm_clear_queues(struct hisi_qm *qm) +static void qm_invalid_queues(struct hisi_qm *qm) { struct hisi_qp *qp; + struct qm_sqc *sqc; + struct qm_cqc *cqc; int i; + /* + * Normal stop queues is no longer used and does not need to be + * invalid queues. + */ + if (qm->status.stop_reason == QM_NORMAL) + return; + + if (qm->status.stop_reason == QM_DOWN) + hisi_qm_cache_wb(qm); + for (i = 0; i < qm->qp_num; i++) { qp = &qm->qp_array[i]; - if (qp->is_in_kernel && qp->is_resetting) + if (!qp->is_resetting) + continue; + + /* Modify random data and set sqc close bit to invalid queue. */ + sqc = qm->sqc + i; + cqc = qm->cqc + i; + sqc->w8 = cpu_to_le16(QM_XQC_RANDOM_DATA); + sqc->w13 = cpu_to_le16(QM_SQC_DISABLE_QP); + cqc->w8 = cpu_to_le16(QM_XQC_RANDOM_DATA); + if (qp->is_in_kernel) memset(qp->qdma.va, 0, qp->qdma.size); } - - memset(qm->qdma.va, 0, qm->qdma.size); } /** @@ -3387,7 +3416,7 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r) } } - qm_clear_queues(qm); + qm_invalid_queues(qm); qm->status.stop_reason = QM_NORMAL; err_unlock: @@ -4785,8 +4814,6 @@ void hisi_qm_dev_shutdown(struct pci_dev *pdev) ret = hisi_qm_stop(qm, QM_DOWN); if (ret) dev_err(&pdev->dev, "Fail to stop qm in shutdown!\n"); - - hisi_qm_cache_wb(qm); } EXPORT_SYMBOL_GPL(hisi_qm_dev_shutdown); From 3d716c51e0e8791f8dd72479a3e6d5e7650ac35e Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Sat, 13 Sep 2025 18:57:51 +0800 Subject: [PATCH 1812/2711] crypto: hisilicon/qm - mask axi error before memory init After the device memory is cleared, if the software sends the doorbell operation, the hardware may trigger a axi error when processing the doorbell. This error is caused by memory clearing and hardware access to address 0. Therefore, the axi error is masked during this period. Signed-off-by: Weili Qian Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 100 +++++++++++++-------- drivers/crypto/hisilicon/qm.c | 66 ++++++++++---- drivers/crypto/hisilicon/sec2/sec_main.c | 90 +++++++++++++------ drivers/crypto/hisilicon/zip/zip_main.c | 102 ++++++++++++++-------- include/linux/hisi_acc_qm.h | 21 +++-- 5 files changed, 257 insertions(+), 122 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index f437f361a2c9..718abe3fa5fe 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -39,6 +39,7 @@ #define HPRE_HAC_RAS_NFE_ENB 0x301414 #define HPRE_HAC_RAS_FE_ENB 0x301418 #define HPRE_HAC_INT_SET 0x301500 +#define HPRE_AXI_ERROR_MASK GENMASK(21, 10) #define HPRE_RNG_TIMEOUT_NUM 0x301A34 #define HPRE_CORE_INT_ENABLE 0 #define HPRE_RDCHN_INI_ST 0x301a00 @@ -798,8 +799,7 @@ static void hpre_master_ooo_ctrl(struct hisi_qm *qm, bool enable) val1 = readl(qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB); if (enable) { val1 |= HPRE_AM_OOO_SHUTDOWN_ENABLE; - val2 = hisi_qm_get_hw_info(qm, hpre_basic_info, - HPRE_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); + val2 = qm->err_info.dev_err.shutdown_mask; } else { val1 &= ~HPRE_AM_OOO_SHUTDOWN_ENABLE; val2 = 0x0; @@ -813,38 +813,33 @@ static void hpre_master_ooo_ctrl(struct hisi_qm *qm, bool enable) static void hpre_hw_error_disable(struct hisi_qm *qm) { - u32 ce, nfe; - - ce = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CE_MASK_CAP, qm->cap_ver); - nfe = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_NFE_MASK_CAP, qm->cap_ver); + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; /* disable hpre hw error interrupts */ - writel(ce | nfe | HPRE_HAC_RAS_FE_ENABLE, qm->io_base + HPRE_INT_MASK); + writel(err_mask, qm->io_base + HPRE_INT_MASK); /* disable HPRE block master OOO when nfe occurs on Kunpeng930 */ hpre_master_ooo_ctrl(qm, false); } static void hpre_hw_error_enable(struct hisi_qm *qm) { - u32 ce, nfe, err_en; - - ce = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CE_MASK_CAP, qm->cap_ver); - nfe = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_NFE_MASK_CAP, qm->cap_ver); + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; /* clear HPRE hw error source if having */ - writel(ce | nfe | HPRE_HAC_RAS_FE_ENABLE, qm->io_base + HPRE_HAC_SOURCE_INT); + writel(err_mask, qm->io_base + HPRE_HAC_SOURCE_INT); /* configure error type */ - writel(ce, qm->io_base + HPRE_RAS_CE_ENB); - writel(nfe, qm->io_base + HPRE_RAS_NFE_ENB); - writel(HPRE_HAC_RAS_FE_ENABLE, qm->io_base + HPRE_RAS_FE_ENB); + writel(dev_err->ce, qm->io_base + HPRE_RAS_CE_ENB); + writel(dev_err->nfe, qm->io_base + HPRE_RAS_NFE_ENB); + writel(dev_err->fe, qm->io_base + HPRE_RAS_FE_ENB); /* enable HPRE block master OOO when nfe occurs on Kunpeng930 */ hpre_master_ooo_ctrl(qm, true); /* enable hpre hw error interrupts */ - err_en = ce | nfe | HPRE_HAC_RAS_FE_ENABLE; - writel(~err_en, qm->io_base + HPRE_INT_MASK); + writel(~err_mask, qm->io_base + HPRE_INT_MASK); } static inline struct hisi_qm *hpre_file_to_qm(struct hpre_debugfs_file *file) @@ -1399,9 +1394,8 @@ static void hpre_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts) static void hpre_disable_error_report(struct hisi_qm *qm, u32 err_type) { - u32 nfe_mask; + u32 nfe_mask = qm->err_info.dev_err.nfe; - nfe_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_NFE_MASK_CAP, qm->cap_ver); writel(nfe_mask & (~err_type), qm->io_base + HPRE_RAS_NFE_ENB); } @@ -1422,11 +1416,11 @@ static enum acc_err_result hpre_get_err_result(struct hisi_qm *qm) err_status = hpre_get_hw_err_status(qm); if (err_status) { - if (err_status & qm->err_info.ecc_2bits_mask) + if (err_status & qm->err_info.dev_err.ecc_2bits_mask) qm->err_status.is_dev_ecc_mbit = true; hpre_log_hw_error(qm, err_status); - if (err_status & qm->err_info.dev_reset_mask) { + if (err_status & qm->err_info.dev_err.reset_mask) { /* Disable the same error reporting until device is recovered. */ hpre_disable_error_report(qm, err_status); return ACC_ERR_NEED_RESET; @@ -1442,28 +1436,64 @@ static bool hpre_dev_is_abnormal(struct hisi_qm *qm) u32 err_status; err_status = hpre_get_hw_err_status(qm); - if (err_status & qm->err_info.dev_shutdown_mask) + if (err_status & qm->err_info.dev_err.shutdown_mask) return true; return false; } +static void hpre_disable_axi_error(struct hisi_qm *qm) +{ + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; + u32 val; + + val = ~(err_mask & (~HPRE_AXI_ERROR_MASK)); + writel(val, qm->io_base + HPRE_INT_MASK); + + if (qm->ver > QM_HW_V2) + writel(dev_err->shutdown_mask & (~HPRE_AXI_ERROR_MASK), + qm->io_base + HPRE_OOO_SHUTDOWN_SEL); +} + +static void hpre_enable_axi_error(struct hisi_qm *qm) +{ + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; + + /* clear axi error source */ + writel(HPRE_AXI_ERROR_MASK, qm->io_base + HPRE_HAC_SOURCE_INT); + + writel(~err_mask, qm->io_base + HPRE_INT_MASK); + + if (qm->ver > QM_HW_V2) + writel(dev_err->shutdown_mask, qm->io_base + HPRE_OOO_SHUTDOWN_SEL); +} + static void hpre_err_info_init(struct hisi_qm *qm) { struct hisi_qm_err_info *err_info = &qm->err_info; + struct hisi_qm_err_mask *qm_err = &err_info->qm_err; + struct hisi_qm_err_mask *dev_err = &err_info->dev_err; + + qm_err->fe = HPRE_HAC_RAS_FE_ENABLE; + qm_err->ce = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_QM_CE_MASK_CAP, qm->cap_ver); + qm_err->nfe = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_QM_NFE_MASK_CAP, qm->cap_ver); + qm_err->shutdown_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, + HPRE_QM_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); + qm_err->reset_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, + HPRE_QM_RESET_MASK_CAP, qm->cap_ver); + qm_err->ecc_2bits_mask = QM_ECC_MBIT; + + dev_err->fe = HPRE_HAC_RAS_FE_ENABLE; + dev_err->ce = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CE_MASK_CAP, qm->cap_ver); + dev_err->nfe = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_NFE_MASK_CAP, qm->cap_ver); + dev_err->shutdown_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, + HPRE_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); + dev_err->reset_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, + HPRE_RESET_MASK_CAP, qm->cap_ver); + dev_err->ecc_2bits_mask = HPRE_CORE_ECC_2BIT_ERR | HPRE_OOO_ECC_2BIT_ERR; - err_info->fe = HPRE_HAC_RAS_FE_ENABLE; - err_info->ce = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_QM_CE_MASK_CAP, qm->cap_ver); - err_info->nfe = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_QM_NFE_MASK_CAP, qm->cap_ver); - err_info->ecc_2bits_mask = HPRE_CORE_ECC_2BIT_ERR | HPRE_OOO_ECC_2BIT_ERR; - err_info->dev_shutdown_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, - HPRE_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); - err_info->qm_shutdown_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, - HPRE_QM_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); - err_info->qm_reset_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, - HPRE_QM_RESET_MASK_CAP, qm->cap_ver); - err_info->dev_reset_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, - HPRE_RESET_MASK_CAP, qm->cap_ver); err_info->msi_wr_port = HPRE_WR_MSI_PORT; err_info->acpi_rst = "HRST"; } @@ -1481,6 +1511,8 @@ static const struct hisi_qm_err_ini hpre_err_ini = { .err_info_init = hpre_err_info_init, .get_err_result = hpre_get_err_result, .dev_is_abnormal = hpre_dev_is_abnormal, + .disable_axi_error = hpre_disable_axi_error, + .enable_axi_error = hpre_enable_axi_error, }; static int hpre_pf_probe_init(struct hpre *hpre) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index c1ffaae78532..d0d1fc45b8fe 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -147,9 +147,9 @@ #define QM_RAS_CE_TIMES_PER_IRQ 1 #define QM_OOO_SHUTDOWN_SEL 0x1040f8 #define QM_AXI_RRESP_ERR BIT(0) -#define QM_ECC_MBIT BIT(2) #define QM_DB_TIMEOUT BIT(10) #define QM_OF_FIFO_OF BIT(11) +#define QM_RAS_AXI_ERROR (BIT(0) | BIT(1) | BIT(12)) #define QM_RESET_WAIT_TIMEOUT 400 #define QM_PEH_VENDOR_ID 0x1000d8 @@ -165,7 +165,6 @@ #define ACC_MASTER_TRANS_RETURN 0x300150 #define ACC_MASTER_GLOBAL_CTRL 0x300000 #define ACC_AM_CFG_PORT_WR_EN 0x30001c -#define QM_RAS_NFE_MBIT_DISABLE ~QM_ECC_MBIT #define ACC_AM_ROB_ECC_INT_STS 0x300104 #define ACC_ROB_ECC_ERR_MULTPL BIT(1) #define QM_MSI_CAP_ENABLE BIT(16) @@ -522,7 +521,7 @@ static bool qm_check_dev_error(struct hisi_qm *qm) return false; err_status = qm_get_hw_error_status(pf_qm); - if (err_status & pf_qm->err_info.qm_shutdown_mask) + if (err_status & pf_qm->err_info.qm_err.shutdown_mask) return true; if (pf_qm->err_ini->dev_is_abnormal) @@ -1397,17 +1396,17 @@ static void qm_hw_error_init_v1(struct hisi_qm *qm) static void qm_hw_error_cfg(struct hisi_qm *qm) { - struct hisi_qm_err_info *err_info = &qm->err_info; + struct hisi_qm_err_mask *qm_err = &qm->err_info.qm_err; - qm->error_mask = err_info->nfe | err_info->ce | err_info->fe; + qm->error_mask = qm_err->nfe | qm_err->ce | qm_err->fe; /* clear QM hw residual error source */ writel(qm->error_mask, qm->io_base + QM_ABNORMAL_INT_SOURCE); /* configure error type */ - writel(err_info->ce, qm->io_base + QM_RAS_CE_ENABLE); + writel(qm_err->ce, qm->io_base + QM_RAS_CE_ENABLE); writel(QM_RAS_CE_TIMES_PER_IRQ, qm->io_base + QM_RAS_CE_THRESHOLD); - writel(err_info->nfe, qm->io_base + QM_RAS_NFE_ENABLE); - writel(err_info->fe, qm->io_base + QM_RAS_FE_ENABLE); + writel(qm_err->nfe, qm->io_base + QM_RAS_NFE_ENABLE); + writel(qm_err->fe, qm->io_base + QM_RAS_FE_ENABLE); } static void qm_hw_error_init_v2(struct hisi_qm *qm) @@ -1436,7 +1435,7 @@ static void qm_hw_error_init_v3(struct hisi_qm *qm) qm_hw_error_cfg(qm); /* enable close master ooo when hardware error happened */ - writel(qm->err_info.qm_shutdown_mask, qm->io_base + QM_OOO_SHUTDOWN_SEL); + writel(qm->err_info.qm_err.shutdown_mask, qm->io_base + QM_OOO_SHUTDOWN_SEL); irq_unmask = ~qm->error_mask; irq_unmask &= readl(qm->io_base + QM_ABNORMAL_INT_MASK); @@ -1498,6 +1497,7 @@ static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status) static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm) { + struct hisi_qm_err_mask *qm_err = &qm->err_info.qm_err; u32 error_status; error_status = qm_get_hw_error_status(qm); @@ -1506,17 +1506,16 @@ static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm) qm->err_status.is_qm_ecc_mbit = true; qm_log_hw_error(qm, error_status); - if (error_status & qm->err_info.qm_reset_mask) { + if (error_status & qm_err->reset_mask) { /* Disable the same error reporting until device is recovered. */ - writel(qm->err_info.nfe & (~error_status), - qm->io_base + QM_RAS_NFE_ENABLE); + writel(qm_err->nfe & (~error_status), qm->io_base + QM_RAS_NFE_ENABLE); return ACC_ERR_NEED_RESET; } /* Clear error source if not need reset. */ writel(error_status, qm->io_base + QM_ABNORMAL_INT_SOURCE); - writel(qm->err_info.nfe, qm->io_base + QM_RAS_NFE_ENABLE); - writel(qm->err_info.ce, qm->io_base + QM_RAS_CE_ENABLE); + writel(qm_err->nfe, qm->io_base + QM_RAS_NFE_ENABLE); + writel(qm_err->ce, qm->io_base + QM_RAS_CE_ENABLE); } return ACC_ERR_RECOVERED; @@ -4227,9 +4226,9 @@ static void qm_dev_ecc_mbit_handle(struct hisi_qm *qm) !qm->err_status.is_qm_ecc_mbit && !qm->err_ini->close_axi_master_ooo) { nfe_enb = readl(qm->io_base + QM_RAS_NFE_ENABLE); - writel(nfe_enb & QM_RAS_NFE_MBIT_DISABLE, + writel(nfe_enb & ~qm->err_info.qm_err.ecc_2bits_mask, qm->io_base + QM_RAS_NFE_ENABLE); - writel(QM_ECC_MBIT, qm->io_base + QM_ABNORMAL_INT_SET); + writel(qm->err_info.qm_err.ecc_2bits_mask, qm->io_base + QM_ABNORMAL_INT_SET); } } @@ -4508,12 +4507,12 @@ static void qm_restart_prepare(struct hisi_qm *qm) qm->io_base + ACC_AM_CFG_PORT_WR_EN); /* clear dev ecc 2bit error source if having */ - value = qm_get_dev_err_status(qm) & qm->err_info.ecc_2bits_mask; + value = qm_get_dev_err_status(qm) & qm->err_info.dev_err.ecc_2bits_mask; if (value && qm->err_ini->clear_dev_hw_err_status) qm->err_ini->clear_dev_hw_err_status(qm, value); /* clear QM ecc mbit error source */ - writel(QM_ECC_MBIT, qm->io_base + QM_ABNORMAL_INT_SOURCE); + writel(qm->err_info.qm_err.ecc_2bits_mask, qm->io_base + QM_ABNORMAL_INT_SOURCE); /* clear AM Reorder Buffer ecc mbit source */ writel(ACC_ROB_ECC_ERR_MULTPL, qm->io_base + ACC_AM_ROB_ECC_INT_STS); @@ -4540,6 +4539,34 @@ clear_flags: qm->err_status.is_dev_ecc_mbit = false; } +static void qm_disable_axi_error(struct hisi_qm *qm) +{ + struct hisi_qm_err_mask *qm_err = &qm->err_info.qm_err; + u32 val; + + val = ~(qm->error_mask & (~QM_RAS_AXI_ERROR)); + writel(val, qm->io_base + QM_ABNORMAL_INT_MASK); + if (qm->ver > QM_HW_V2) + writel(qm_err->shutdown_mask & (~QM_RAS_AXI_ERROR), + qm->io_base + QM_OOO_SHUTDOWN_SEL); + + if (qm->err_ini->disable_axi_error) + qm->err_ini->disable_axi_error(qm); +} + +static void qm_enable_axi_error(struct hisi_qm *qm) +{ + /* clear axi error source */ + writel(QM_RAS_AXI_ERROR, qm->io_base + QM_ABNORMAL_INT_SOURCE); + + writel(~qm->error_mask, qm->io_base + QM_ABNORMAL_INT_MASK); + if (qm->ver > QM_HW_V2) + writel(qm->err_info.qm_err.shutdown_mask, qm->io_base + QM_OOO_SHUTDOWN_SEL); + + if (qm->err_ini->enable_axi_error) + qm->err_ini->enable_axi_error(qm); +} + static int qm_controller_reset_done(struct hisi_qm *qm) { struct pci_dev *pdev = qm->pdev; @@ -4573,6 +4600,7 @@ static int qm_controller_reset_done(struct hisi_qm *qm) qm_restart_prepare(qm); hisi_qm_dev_err_init(qm); + qm_disable_axi_error(qm); if (qm->err_ini->open_axi_master_ooo) qm->err_ini->open_axi_master_ooo(qm); @@ -4595,7 +4623,7 @@ static int qm_controller_reset_done(struct hisi_qm *qm) ret = qm_wait_vf_prepare_finish(qm); if (ret) pci_err(pdev, "failed to start by vfs in soft reset!\n"); - + qm_enable_axi_error(qm); qm_cmd_init(qm); qm_restart_done(qm); diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index bdb2d52ee1b6..19fda486fefb 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -47,6 +47,8 @@ #define SEC_RAS_FE_ENB_MSK 0x0 #define SEC_OOO_SHUTDOWN_SEL 0x301014 #define SEC_RAS_DISABLE 0x0 +#define SEC_AXI_ERROR_MASK (BIT(0) | BIT(1)) + #define SEC_MEM_START_INIT_REG 0x301100 #define SEC_MEM_INIT_DONE_REG 0x301104 @@ -713,8 +715,7 @@ static void sec_master_ooo_ctrl(struct hisi_qm *qm, bool enable) val1 = readl(qm->io_base + SEC_CONTROL_REG); if (enable) { val1 |= SEC_AXI_SHUTDOWN_ENABLE; - val2 = hisi_qm_get_hw_info(qm, sec_basic_info, - SEC_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); + val2 = qm->err_info.dev_err.shutdown_mask; } else { val1 &= SEC_AXI_SHUTDOWN_DISABLE; val2 = 0x0; @@ -728,7 +729,8 @@ static void sec_master_ooo_ctrl(struct hisi_qm *qm, bool enable) static void sec_hw_error_enable(struct hisi_qm *qm) { - u32 ce, nfe; + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; if (qm->ver == QM_HW_V1) { writel(SEC_CORE_INT_DISABLE, qm->io_base + SEC_CORE_INT_MASK); @@ -736,22 +738,19 @@ static void sec_hw_error_enable(struct hisi_qm *qm) return; } - ce = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_CE_MASK_CAP, qm->cap_ver); - nfe = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_NFE_MASK_CAP, qm->cap_ver); - /* clear SEC hw error source if having */ - writel(ce | nfe | SEC_RAS_FE_ENB_MSK, qm->io_base + SEC_CORE_INT_SOURCE); + writel(err_mask, qm->io_base + SEC_CORE_INT_SOURCE); /* enable RAS int */ - writel(ce, qm->io_base + SEC_RAS_CE_REG); - writel(SEC_RAS_FE_ENB_MSK, qm->io_base + SEC_RAS_FE_REG); - writel(nfe, qm->io_base + SEC_RAS_NFE_REG); + writel(dev_err->ce, qm->io_base + SEC_RAS_CE_REG); + writel(dev_err->fe, qm->io_base + SEC_RAS_FE_REG); + writel(dev_err->nfe, qm->io_base + SEC_RAS_NFE_REG); /* enable SEC block master OOO when nfe occurs on Kunpeng930 */ sec_master_ooo_ctrl(qm, true); /* enable SEC hw error interrupts */ - writel(ce | nfe | SEC_RAS_FE_ENB_MSK, qm->io_base + SEC_CORE_INT_MASK); + writel(err_mask, qm->io_base + SEC_CORE_INT_MASK); } static void sec_hw_error_disable(struct hisi_qm *qm) @@ -1108,9 +1107,8 @@ static void sec_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts) static void sec_disable_error_report(struct hisi_qm *qm, u32 err_type) { - u32 nfe_mask; + u32 nfe_mask = qm->err_info.dev_err.nfe; - nfe_mask = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_NFE_MASK_CAP, qm->cap_ver); writel(nfe_mask & (~err_type), qm->io_base + SEC_RAS_NFE_REG); } @@ -1129,11 +1127,11 @@ static enum acc_err_result sec_get_err_result(struct hisi_qm *qm) err_status = sec_get_hw_err_status(qm); if (err_status) { - if (err_status & qm->err_info.ecc_2bits_mask) + if (err_status & qm->err_info.dev_err.ecc_2bits_mask) qm->err_status.is_dev_ecc_mbit = true; sec_log_hw_error(qm, err_status); - if (err_status & qm->err_info.dev_reset_mask) { + if (err_status & qm->err_info.dev_err.reset_mask) { /* Disable the same error reporting until device is recovered. */ sec_disable_error_report(qm, err_status); return ACC_ERR_NEED_RESET; @@ -1149,28 +1147,62 @@ static bool sec_dev_is_abnormal(struct hisi_qm *qm) u32 err_status; err_status = sec_get_hw_err_status(qm); - if (err_status & qm->err_info.dev_shutdown_mask) + if (err_status & qm->err_info.dev_err.shutdown_mask) return true; return false; } +static void sec_disable_axi_error(struct hisi_qm *qm) +{ + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; + + writel(err_mask & ~SEC_AXI_ERROR_MASK, qm->io_base + SEC_CORE_INT_MASK); + + if (qm->ver > QM_HW_V2) + writel(dev_err->shutdown_mask & (~SEC_AXI_ERROR_MASK), + qm->io_base + SEC_OOO_SHUTDOWN_SEL); +} + +static void sec_enable_axi_error(struct hisi_qm *qm) +{ + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; + + /* clear axi error source */ + writel(SEC_AXI_ERROR_MASK, qm->io_base + SEC_CORE_INT_SOURCE); + + writel(err_mask, qm->io_base + SEC_CORE_INT_MASK); + + if (qm->ver > QM_HW_V2) + writel(dev_err->shutdown_mask, qm->io_base + SEC_OOO_SHUTDOWN_SEL); +} + static void sec_err_info_init(struct hisi_qm *qm) { struct hisi_qm_err_info *err_info = &qm->err_info; + struct hisi_qm_err_mask *qm_err = &err_info->qm_err; + struct hisi_qm_err_mask *dev_err = &err_info->dev_err; + + qm_err->fe = SEC_RAS_FE_ENB_MSK; + qm_err->ce = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_QM_CE_MASK_CAP, qm->cap_ver); + qm_err->nfe = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_QM_NFE_MASK_CAP, qm->cap_ver); + qm_err->shutdown_mask = hisi_qm_get_hw_info(qm, sec_basic_info, + SEC_QM_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); + qm_err->reset_mask = hisi_qm_get_hw_info(qm, sec_basic_info, + SEC_QM_RESET_MASK_CAP, qm->cap_ver); + qm_err->ecc_2bits_mask = QM_ECC_MBIT; + + dev_err->fe = SEC_RAS_FE_ENB_MSK; + dev_err->ce = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_CE_MASK_CAP, qm->cap_ver); + dev_err->nfe = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_NFE_MASK_CAP, qm->cap_ver); + dev_err->shutdown_mask = hisi_qm_get_hw_info(qm, sec_basic_info, + SEC_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); + dev_err->reset_mask = hisi_qm_get_hw_info(qm, sec_basic_info, + SEC_RESET_MASK_CAP, qm->cap_ver); + dev_err->ecc_2bits_mask = SEC_CORE_INT_STATUS_M_ECC; - err_info->fe = SEC_RAS_FE_ENB_MSK; - err_info->ce = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_QM_CE_MASK_CAP, qm->cap_ver); - err_info->nfe = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_QM_NFE_MASK_CAP, qm->cap_ver); - err_info->ecc_2bits_mask = SEC_CORE_INT_STATUS_M_ECC; - err_info->qm_shutdown_mask = hisi_qm_get_hw_info(qm, sec_basic_info, - SEC_QM_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); - err_info->dev_shutdown_mask = hisi_qm_get_hw_info(qm, sec_basic_info, - SEC_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); - err_info->qm_reset_mask = hisi_qm_get_hw_info(qm, sec_basic_info, - SEC_QM_RESET_MASK_CAP, qm->cap_ver); - err_info->dev_reset_mask = hisi_qm_get_hw_info(qm, sec_basic_info, - SEC_RESET_MASK_CAP, qm->cap_ver); err_info->msi_wr_port = BIT(0); err_info->acpi_rst = "SRST"; } @@ -1188,6 +1220,8 @@ static const struct hisi_qm_err_ini sec_err_ini = { .err_info_init = sec_err_info_init, .get_err_result = sec_get_err_result, .dev_is_abnormal = sec_dev_is_abnormal, + .disable_axi_error = sec_disable_axi_error, + .enable_axi_error = sec_enable_axi_error, }; static int sec_pf_probe_init(struct sec_dev *sec) diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 62cd090e13af..6b5cad82c856 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -65,6 +65,7 @@ #define HZIP_SRAM_ECC_ERR_NUM_SHIFT 16 #define HZIP_SRAM_ECC_ERR_ADDR_SHIFT 24 #define HZIP_CORE_INT_MASK_ALL GENMASK(12, 0) +#define HZIP_AXI_ERROR_MASK (BIT(2) | BIT(3)) #define HZIP_SQE_SIZE 128 #define HZIP_PF_DEF_Q_NUM 64 #define HZIP_PF_DEF_Q_BASE 0 @@ -662,8 +663,7 @@ static void hisi_zip_master_ooo_ctrl(struct hisi_qm *qm, bool enable) val1 = readl(qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL); if (enable) { val1 |= HZIP_AXI_SHUTDOWN_ENABLE; - val2 = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - ZIP_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); + val2 = qm->err_info.dev_err.shutdown_mask; } else { val1 &= ~HZIP_AXI_SHUTDOWN_ENABLE; val2 = 0x0; @@ -677,7 +677,8 @@ static void hisi_zip_master_ooo_ctrl(struct hisi_qm *qm, bool enable) static void hisi_zip_hw_error_enable(struct hisi_qm *qm) { - u32 nfe, ce; + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; if (qm->ver == QM_HW_V1) { writel(HZIP_CORE_INT_MASK_ALL, @@ -686,33 +687,29 @@ static void hisi_zip_hw_error_enable(struct hisi_qm *qm) return; } - nfe = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_NFE_MASK_CAP, qm->cap_ver); - ce = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CE_MASK_CAP, qm->cap_ver); - /* clear ZIP hw error source if having */ - writel(ce | nfe | HZIP_CORE_INT_RAS_FE_ENB_MASK, qm->io_base + HZIP_CORE_INT_SOURCE); + writel(err_mask, qm->io_base + HZIP_CORE_INT_SOURCE); /* configure error type */ - writel(ce, qm->io_base + HZIP_CORE_INT_RAS_CE_ENB); - writel(HZIP_CORE_INT_RAS_FE_ENB_MASK, qm->io_base + HZIP_CORE_INT_RAS_FE_ENB); - writel(nfe, qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB); + writel(dev_err->ce, qm->io_base + HZIP_CORE_INT_RAS_CE_ENB); + writel(dev_err->fe, qm->io_base + HZIP_CORE_INT_RAS_FE_ENB); + writel(dev_err->nfe, qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB); hisi_zip_master_ooo_ctrl(qm, true); /* enable ZIP hw error interrupts */ - writel(0, qm->io_base + HZIP_CORE_INT_MASK_REG); + writel(~err_mask, qm->io_base + HZIP_CORE_INT_MASK_REG); hisi_dae_hw_error_enable(qm); } static void hisi_zip_hw_error_disable(struct hisi_qm *qm) { - u32 nfe, ce; + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; /* disable ZIP hw error interrupts */ - nfe = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_NFE_MASK_CAP, qm->cap_ver); - ce = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CE_MASK_CAP, qm->cap_ver); - writel(ce | nfe | HZIP_CORE_INT_RAS_FE_ENB_MASK, qm->io_base + HZIP_CORE_INT_MASK_REG); + writel(err_mask, qm->io_base + HZIP_CORE_INT_MASK_REG); hisi_zip_master_ooo_ctrl(qm, false); @@ -1186,9 +1183,8 @@ static void hisi_zip_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts) static void hisi_zip_disable_error_report(struct hisi_qm *qm, u32 err_type) { - u32 nfe_mask; + u32 nfe_mask = qm->err_info.dev_err.nfe; - nfe_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_NFE_MASK_CAP, qm->cap_ver); writel(nfe_mask & (~err_type), qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB); } @@ -1230,14 +1226,14 @@ static enum acc_err_result hisi_zip_get_err_result(struct hisi_qm *qm) /* Get device hardware new error status */ err_status = hisi_zip_get_hw_err_status(qm); if (err_status) { - if (err_status & qm->err_info.ecc_2bits_mask) + if (err_status & qm->err_info.dev_err.ecc_2bits_mask) qm->err_status.is_dev_ecc_mbit = true; hisi_zip_log_hw_error(qm, err_status); - if (err_status & qm->err_info.dev_reset_mask) { + if (err_status & qm->err_info.dev_err.reset_mask) { /* Disable the same error reporting until device is recovered. */ hisi_zip_disable_error_report(qm, err_status); - return ACC_ERR_NEED_RESET; + zip_result = ACC_ERR_NEED_RESET; } else { hisi_zip_clear_hw_err_status(qm, err_status); } @@ -1255,7 +1251,7 @@ static bool hisi_zip_dev_is_abnormal(struct hisi_qm *qm) u32 err_status; err_status = hisi_zip_get_hw_err_status(qm); - if (err_status & qm->err_info.dev_shutdown_mask) + if (err_status & qm->err_info.dev_err.shutdown_mask) return true; return hisi_dae_dev_is_abnormal(qm); @@ -1266,23 +1262,59 @@ static int hisi_zip_set_priv_status(struct hisi_qm *qm) return hisi_dae_close_axi_master_ooo(qm); } +static void hisi_zip_disable_axi_error(struct hisi_qm *qm) +{ + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; + u32 val; + + val = ~(err_mask & (~HZIP_AXI_ERROR_MASK)); + writel(val, qm->io_base + HZIP_CORE_INT_MASK_REG); + + if (qm->ver > QM_HW_V2) + writel(dev_err->shutdown_mask & (~HZIP_AXI_ERROR_MASK), + qm->io_base + HZIP_OOO_SHUTDOWN_SEL); +} + +static void hisi_zip_enable_axi_error(struct hisi_qm *qm) +{ + struct hisi_qm_err_mask *dev_err = &qm->err_info.dev_err; + u32 err_mask = dev_err->ce | dev_err->nfe | dev_err->fe; + + /* clear axi error source */ + writel(HZIP_AXI_ERROR_MASK, qm->io_base + HZIP_CORE_INT_SOURCE); + + writel(~err_mask, qm->io_base + HZIP_CORE_INT_MASK_REG); + + if (qm->ver > QM_HW_V2) + writel(dev_err->shutdown_mask, qm->io_base + HZIP_OOO_SHUTDOWN_SEL); +} + static void hisi_zip_err_info_init(struct hisi_qm *qm) { struct hisi_qm_err_info *err_info = &qm->err_info; + struct hisi_qm_err_mask *qm_err = &err_info->qm_err; + struct hisi_qm_err_mask *dev_err = &err_info->dev_err; + + qm_err->fe = HZIP_CORE_INT_RAS_FE_ENB_MASK; + qm_err->ce = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_QM_CE_MASK_CAP, qm->cap_ver); + qm_err->nfe = hisi_qm_get_hw_info(qm, zip_basic_cap_info, + ZIP_QM_NFE_MASK_CAP, qm->cap_ver); + qm_err->ecc_2bits_mask = QM_ECC_MBIT; + qm_err->reset_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, + ZIP_QM_RESET_MASK_CAP, qm->cap_ver); + qm_err->shutdown_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, + ZIP_QM_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); + + dev_err->fe = HZIP_CORE_INT_RAS_FE_ENB_MASK; + dev_err->ce = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CE_MASK_CAP, qm->cap_ver); + dev_err->nfe = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_NFE_MASK_CAP, qm->cap_ver); + dev_err->ecc_2bits_mask = HZIP_CORE_INT_STATUS_M_ECC; + dev_err->shutdown_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, + ZIP_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); + dev_err->reset_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, + ZIP_RESET_MASK_CAP, qm->cap_ver); - err_info->fe = HZIP_CORE_INT_RAS_FE_ENB_MASK; - err_info->ce = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_QM_CE_MASK_CAP, qm->cap_ver); - err_info->nfe = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - ZIP_QM_NFE_MASK_CAP, qm->cap_ver); - err_info->ecc_2bits_mask = HZIP_CORE_INT_STATUS_M_ECC; - err_info->qm_shutdown_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - ZIP_QM_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); - err_info->dev_shutdown_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - ZIP_OOO_SHUTDOWN_MASK_CAP, qm->cap_ver); - err_info->qm_reset_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - ZIP_QM_RESET_MASK_CAP, qm->cap_ver); - err_info->dev_reset_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - ZIP_RESET_MASK_CAP, qm->cap_ver); err_info->msi_wr_port = HZIP_WR_PORT; err_info->acpi_rst = "ZRST"; } @@ -1302,6 +1334,8 @@ static const struct hisi_qm_err_ini hisi_zip_err_ini = { .get_err_result = hisi_zip_get_err_result, .set_priv_status = hisi_zip_set_priv_status, .dev_is_abnormal = hisi_zip_dev_is_abnormal, + .disable_axi_error = hisi_zip_disable_axi_error, + .enable_axi_error = hisi_zip_enable_axi_error, }; static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index f2254ddc327c..c4690e365ade 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -104,6 +104,8 @@ #define UACCE_MODE_SVA 1 /* use uacce sva mode */ #define UACCE_MODE_DESC "0(default) means only register to crypto, 1 means both register to crypto and uacce" +#define QM_ECC_MBIT BIT(2) + enum qm_stop_reason { QM_NORMAL, QM_SOFT_RESET, @@ -240,19 +242,22 @@ enum acc_err_result { ACC_ERR_RECOVERED, }; -struct hisi_qm_err_info { - char *acpi_rst; - u32 msi_wr_port; +struct hisi_qm_err_mask { u32 ecc_2bits_mask; - u32 qm_shutdown_mask; - u32 dev_shutdown_mask; - u32 qm_reset_mask; - u32 dev_reset_mask; + u32 shutdown_mask; + u32 reset_mask; u32 ce; u32 nfe; u32 fe; }; +struct hisi_qm_err_info { + char *acpi_rst; + u32 msi_wr_port; + struct hisi_qm_err_mask qm_err; + struct hisi_qm_err_mask dev_err; +}; + struct hisi_qm_err_status { u32 is_qm_ecc_mbit; u32 is_dev_ecc_mbit; @@ -273,6 +278,8 @@ struct hisi_qm_err_ini { enum acc_err_result (*get_err_result)(struct hisi_qm *qm); bool (*dev_is_abnormal)(struct hisi_qm *qm); int (*set_priv_status)(struct hisi_qm *qm); + void (*disable_axi_error)(struct hisi_qm *qm); + void (*enable_axi_error)(struct hisi_qm *qm); }; struct hisi_qm_cap_info { From 80736a97cf94eeb02da6de6cfbc5a74514c85a16 Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Sat, 13 Sep 2025 18:57:52 +0800 Subject: [PATCH 1813/2711] crypto: hisilicon - enable error reporting again When an error occurs on the device, an interrupt is reported. When the firmware forwards the interrupt to the driver and masks the error. If the driver does not enable error reporting when an error does not need to be reset, the device does not report the error to the driver when the error occurs again. Therefore, after the driver obtains the information, the error reporting needs to be enabled again. Signed-off-by: Weili Qian Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 11 +++++++++++ drivers/crypto/hisilicon/sec2/sec_main.c | 11 +++++++++++ drivers/crypto/hisilicon/zip/dae_main.c | 8 ++++++++ drivers/crypto/hisilicon/zip/zip_main.c | 11 +++++++++++ 4 files changed, 41 insertions(+) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 718abe3fa5fe..b94fecd765ee 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -1399,6 +1399,15 @@ static void hpre_disable_error_report(struct hisi_qm *qm, u32 err_type) writel(nfe_mask & (~err_type), qm->io_base + HPRE_RAS_NFE_ENB); } +static void hpre_enable_error_report(struct hisi_qm *qm) +{ + u32 nfe_mask = qm->err_info.dev_err.nfe; + u32 ce_mask = qm->err_info.dev_err.ce; + + writel(nfe_mask, qm->io_base + HPRE_RAS_NFE_ENB); + writel(ce_mask, qm->io_base + HPRE_RAS_CE_ENB); +} + static void hpre_open_axi_master_ooo(struct hisi_qm *qm) { u32 value; @@ -1426,6 +1435,8 @@ static enum acc_err_result hpre_get_err_result(struct hisi_qm *qm) return ACC_ERR_NEED_RESET; } hpre_clear_hw_err_status(qm, err_status); + /* Avoid firmware disable error report, re-enable. */ + hpre_enable_error_report(qm); } return ACC_ERR_RECOVERED; diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 19fda486fefb..5eb2d6820742 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -1112,6 +1112,15 @@ static void sec_disable_error_report(struct hisi_qm *qm, u32 err_type) writel(nfe_mask & (~err_type), qm->io_base + SEC_RAS_NFE_REG); } +static void sec_enable_error_report(struct hisi_qm *qm) +{ + u32 nfe_mask = qm->err_info.dev_err.nfe; + u32 ce_mask = qm->err_info.dev_err.ce; + + writel(nfe_mask, qm->io_base + SEC_RAS_NFE_REG); + writel(ce_mask, qm->io_base + SEC_RAS_CE_REG); +} + static void sec_open_axi_master_ooo(struct hisi_qm *qm) { u32 val; @@ -1137,6 +1146,8 @@ static enum acc_err_result sec_get_err_result(struct hisi_qm *qm) return ACC_ERR_NEED_RESET; } sec_clear_hw_err_status(qm, err_status); + /* Avoid firmware disable error report, re-enable. */ + sec_enable_error_report(qm); } return ACC_ERR_RECOVERED; diff --git a/drivers/crypto/hisilicon/zip/dae_main.c b/drivers/crypto/hisilicon/zip/dae_main.c index 4c5481c77436..68aebd02fc84 100644 --- a/drivers/crypto/hisilicon/zip/dae_main.c +++ b/drivers/crypto/hisilicon/zip/dae_main.c @@ -175,6 +175,12 @@ static void hisi_dae_disable_error_report(struct hisi_qm *qm, u32 err_type) writel(DAE_ERR_NFE_MASK & (~err_type), qm->io_base + DAE_ERR_NFE_OFFSET); } +static void hisi_dae_enable_error_report(struct hisi_qm *qm) +{ + writel(DAE_ERR_CE_MASK, qm->io_base + DAE_ERR_CE_OFFSET); + writel(DAE_ERR_NFE_MASK, qm->io_base + DAE_ERR_NFE_OFFSET); +} + static void hisi_dae_log_hw_error(struct hisi_qm *qm, u32 err_type) { const struct hisi_dae_hw_error *err = dae_hw_error; @@ -216,6 +222,8 @@ enum acc_err_result hisi_dae_get_err_result(struct hisi_qm *qm) return ACC_ERR_NEED_RESET; } hisi_dae_clear_hw_err_status(qm, err_status); + /* Avoid firmware disable error report, re-enable. */ + hisi_dae_enable_error_report(qm); return ACC_ERR_RECOVERED; } diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 6b5cad82c856..4fcbe6bada06 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -1188,6 +1188,15 @@ static void hisi_zip_disable_error_report(struct hisi_qm *qm, u32 err_type) writel(nfe_mask & (~err_type), qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB); } +static void hisi_zip_enable_error_report(struct hisi_qm *qm) +{ + u32 nfe_mask = qm->err_info.dev_err.nfe; + u32 ce_mask = qm->err_info.dev_err.ce; + + writel(nfe_mask, qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB); + writel(ce_mask, qm->io_base + HZIP_CORE_INT_RAS_CE_ENB); +} + static void hisi_zip_open_axi_master_ooo(struct hisi_qm *qm) { u32 val; @@ -1236,6 +1245,8 @@ static enum acc_err_result hisi_zip_get_err_result(struct hisi_qm *qm) zip_result = ACC_ERR_NEED_RESET; } else { hisi_zip_clear_hw_err_status(qm, err_status); + /* Avoid firmware disable error report, re-enable. */ + hisi_zip_enable_error_report(qm); } } From 64b9642fc29a14e1fe67842be9c69c7b90a3bcd6 Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Sat, 13 Sep 2025 18:57:53 +0800 Subject: [PATCH 1814/2711] crypto: hisilicon/qm - clear all VF configurations in the hardware When disabling SR-IOV, clear the configuration of each VF in the hardware. Do not exit the configuration clearing process due to the failure of a single VF. Additionally, Clear the VF configurations before decrementing the PM counter. Signed-off-by: Weili Qian Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index d0d1fc45b8fe..a5b96adf2d1e 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -3660,19 +3660,19 @@ static int qm_vf_q_assign(struct hisi_qm *qm, u32 num_vfs) return 0; } -static int qm_clear_vft_config(struct hisi_qm *qm) +static void qm_clear_vft_config(struct hisi_qm *qm) { - int ret; u32 i; - for (i = 1; i <= qm->vfs_num; i++) { - ret = hisi_qm_set_vft(qm, i, 0, 0); - if (ret) - return ret; - } - qm->vfs_num = 0; + /* + * When disabling SR-IOV, clear the configuration of each VF in the hardware + * sequentially. Failure to clear a single VF should not affect the clearing + * operation of other VFs. + */ + for (i = 1; i <= qm->vfs_num; i++) + (void)hisi_qm_set_vft(qm, i, 0, 0); - return 0; + qm->vfs_num = 0; } static int qm_func_shaper_enable(struct hisi_qm *qm, u32 fun_index, u32 qos) @@ -4007,13 +4007,13 @@ int hisi_qm_sriov_enable(struct pci_dev *pdev, int max_vfs) goto err_put_sync; } + qm->vfs_num = num_vfs; ret = pci_enable_sriov(pdev, num_vfs); if (ret) { pci_err(pdev, "Can't enable VF!\n"); qm_clear_vft_config(qm); goto err_put_sync; } - qm->vfs_num = num_vfs; pci_info(pdev, "VF enabled, vfs_num(=%d)!\n", num_vfs); @@ -4048,11 +4048,10 @@ int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen) } pci_disable_sriov(pdev); - - qm->vfs_num = 0; + qm_clear_vft_config(qm); qm_pm_put_sync(qm); - return qm_clear_vft_config(qm); + return 0; } EXPORT_SYMBOL_GPL(hisi_qm_sriov_disable); From f0cafb02de883b3b413d34eb079c9680782a9cc1 Mon Sep 17 00:00:00 2001 From: Chenghai Huang Date: Sat, 13 Sep 2025 18:57:54 +0800 Subject: [PATCH 1815/2711] crypto: hisilicon/qm - set NULL to qm->debug.qm_diff_regs When the initialization of qm->debug.acc_diff_reg fails, the probe process does not exit. However, after qm->debug.qm_diff_regs is freed, it is not set to NULL. This can lead to a double free when the remove process attempts to free it again. Therefore, qm->debug.qm_diff_regs should be set to NULL after it is freed. Fixes: 8be091338971 ("crypto: hisilicon/debugfs - Fix debugfs uninit process issue") Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/debugfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c index 45e130b901eb..17eb236e9ee4 100644 --- a/drivers/crypto/hisilicon/debugfs.c +++ b/drivers/crypto/hisilicon/debugfs.c @@ -888,6 +888,7 @@ static int qm_diff_regs_init(struct hisi_qm *qm, dfx_regs_uninit(qm, qm->debug.qm_diff_regs, ARRAY_SIZE(qm_diff_regs)); ret = PTR_ERR(qm->debug.acc_diff_regs); qm->debug.acc_diff_regs = NULL; + qm->debug.qm_diff_regs = NULL; return ret; } From b73f28d2f847c24ca5d858a79fd37055036b0a67 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 14 Sep 2025 16:25:55 +0200 Subject: [PATCH 1816/2711] crypto: anubis - simplify return statement in anubis_mod_init Return the result of calling crypto_register_alg() directly and remove the local return variable. Signed-off-by: Thorsten Blum Signed-off-by: Herbert Xu --- crypto/anubis.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crypto/anubis.c b/crypto/anubis.c index 4268c3833baa..4b01b6ec961a 100644 --- a/crypto/anubis.c +++ b/crypto/anubis.c @@ -683,10 +683,7 @@ static struct crypto_alg anubis_alg = { static int __init anubis_mod_init(void) { - int ret = 0; - - ret = crypto_register_alg(&anubis_alg); - return ret; + return crypto_register_alg(&anubis_alg); } static void __exit anubis_mod_fini(void) From 05c81eddc44733fee60d4c55508c76017995900e Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 18 Aug 2025 01:13:49 +0200 Subject: [PATCH 1817/2711] kernel: debug: gdbstub: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. Link: https://github.com/KSPP/linux/issues/88 Reviewed-by: Douglas Anderson Signed-off-by: Thorsten Blum Signed-off-by: Daniel Thompson (RISCstar) --- kernel/debug/gdbstub.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c index f625172d4b67..22fe969c5d2e 100644 --- a/kernel/debug/gdbstub.c +++ b/kernel/debug/gdbstub.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -547,7 +548,7 @@ static void gdb_cmd_setregs(struct kgdb_state *ks) error_packet(remcom_out_buffer, -EINVAL); } else { gdb_regs_to_pt_regs(gdb_regs, ks->linux_regs); - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); } } @@ -577,7 +578,7 @@ static void gdb_cmd_memwrite(struct kgdb_state *ks) if (err) error_packet(remcom_out_buffer, err); else - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); } #if DBG_MAX_REG_NUM > 0 @@ -630,7 +631,7 @@ static void gdb_cmd_reg_set(struct kgdb_state *ks) i = i / 2; kgdb_hex2mem(ptr, (char *)gdb_regs, i); dbg_set_reg(regnum, gdb_regs, ks->linux_regs); - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); } #endif /* DBG_MAX_REG_NUM > 0 */ @@ -642,7 +643,7 @@ static void gdb_cmd_binwrite(struct kgdb_state *ks) if (err) error_packet(remcom_out_buffer, err); else - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); } /* Handle the 'D' or 'k', detach or kill packets */ @@ -656,7 +657,7 @@ static void gdb_cmd_detachkill(struct kgdb_state *ks) if (error < 0) { error_packet(remcom_out_buffer, error); } else { - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); kgdb_connected = 0; } put_packet(remcom_out_buffer); @@ -676,7 +677,7 @@ static int gdb_cmd_reboot(struct kgdb_state *ks) /* For now, only honor R0 */ if (strcmp(remcom_in_buffer, "R0") == 0) { printk(KERN_CRIT "Executing emergency reboot\n"); - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); put_packet(remcom_out_buffer); /* @@ -739,7 +740,7 @@ static void gdb_cmd_query(struct kgdb_state *ks) case 'C': /* Current thread id */ - strcpy(remcom_out_buffer, "QC"); + strscpy(remcom_out_buffer, "QC"); ks->threadid = shadow_pid(current->pid); int_to_threadref(thref, ks->threadid); pack_threadid(remcom_out_buffer + 2, thref); @@ -773,7 +774,7 @@ static void gdb_cmd_query(struct kgdb_state *ks) int len = strlen(remcom_in_buffer + 6); if ((len % 2) != 0) { - strcpy(remcom_out_buffer, "E01"); + strscpy(remcom_out_buffer, "E01"); break; } kgdb_hex2mem(remcom_in_buffer + 6, @@ -785,14 +786,14 @@ static void gdb_cmd_query(struct kgdb_state *ks) kdb_parse(remcom_out_buffer); kdb_common_deinit_state(); - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); } break; #endif #ifdef CONFIG_HAVE_ARCH_KGDB_QXFER_PKT case 'S': if (!strncmp(remcom_in_buffer, "qSupported:", 11)) - strcpy(remcom_out_buffer, kgdb_arch_gdb_stub_feature); + strscpy(remcom_out_buffer, kgdb_arch_gdb_stub_feature); break; case 'X': if (!strncmp(remcom_in_buffer, "qXfer:", 6)) @@ -822,7 +823,7 @@ static void gdb_cmd_task(struct kgdb_state *ks) } kgdb_usethread = thread; ks->kgdb_usethreadid = ks->threadid; - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); break; case 'c': ptr = &remcom_in_buffer[2]; @@ -837,7 +838,7 @@ static void gdb_cmd_task(struct kgdb_state *ks) } kgdb_contthread = thread; } - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); break; } } @@ -851,7 +852,7 @@ static void gdb_cmd_thread(struct kgdb_state *ks) kgdb_hex2long(&ptr, &ks->threadid); thread = getthread(ks->linux_regs, ks->threadid); if (thread) - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); else error_packet(remcom_out_buffer, -EINVAL); } @@ -913,7 +914,7 @@ static void gdb_cmd_break(struct kgdb_state *ks) (int) length, *bpt_type - '0'); if (error == 0) - strcpy(remcom_out_buffer, "OK"); + strscpy(remcom_out_buffer, "OK"); else error_packet(remcom_out_buffer, error); } From d4be3238d9e5f4841e5385cba3d81268c00d9e7d Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 19 Aug 2025 11:59:03 +0200 Subject: [PATCH 1818/2711] kdb: Replace deprecated strcpy() with memcpy() in kdb_strdup() strcpy() is deprecated; use memcpy() instead. Link: https://github.com/KSPP/linux/issues/88 Reviewed-by: Douglas Anderson Signed-off-by: Thorsten Blum Signed-off-by: Daniel Thompson (RISCstar) --- kernel/debug/kdb/kdb_support.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c index 05b137e7dcb9..d36281142fa1 100644 --- a/kernel/debug/kdb/kdb_support.c +++ b/kernel/debug/kdb/kdb_support.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "kdb_private.h" @@ -246,11 +247,12 @@ void kdb_symbol_print(unsigned long addr, const kdb_symtab_t *symtab_p, */ char *kdb_strdup(const char *str, gfp_t type) { - int n = strlen(str)+1; + size_t n = strlen(str) + 1; char *s = kmalloc(n, type); if (!s) return NULL; - return strcpy(s, str); + memcpy(s, str, n); + return s; } /* From 8790cc2940bf9f5ec4d7458b0ea7f94a8acb094f Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 19 Aug 2025 11:59:04 +0200 Subject: [PATCH 1819/2711] kdb: Replace deprecated strcpy() with memmove() in vkdb_printf() strcpy() is deprecated and its behavior is undefined when the source and destination buffers overlap. Use memmove() instead to avoid any undefined behavior. Adjust comments for clarity. Link: https://github.com/KSPP/linux/issues/88 Fixes: 5d5314d6795f ("kdb: core for kgdb back end (1 of 2)") Reviewed-by: Douglas Anderson Signed-off-by: Thorsten Blum Signed-off-by: Daniel Thompson (RISCstar) --- kernel/debug/kdb/kdb_io.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index 9b11b10b120c..b12b9db75c1d 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -714,8 +714,8 @@ int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap) * it, depending on the results of the search. */ cp++; /* to byte after the newline */ - replaced_byte = *cp; /* remember what/where it was */ - cphold = cp; + replaced_byte = *cp; /* remember what it was */ + cphold = cp; /* remember where it was */ *cp = '\0'; /* end the string for our search */ /* @@ -732,8 +732,9 @@ int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap) * Shift the buffer left. */ *cphold = replaced_byte; - strcpy(kdb_buffer, cphold); - len = strlen(kdb_buffer); + len = strlen(cphold); + /* Use memmove() because the buffers overlap */ + memmove(kdb_buffer, cphold, len + 1); next_avail = kdb_buffer + len; size_avail = sizeof(kdb_buffer) - len; goto kdb_print_out; @@ -872,8 +873,9 @@ kdb_printit: */ if (kdb_grepping_flag && !suspend_grep) { *cphold = replaced_byte; - strcpy(kdb_buffer, cphold); - len = strlen(kdb_buffer); + len = strlen(cphold); + /* Use memmove() because the buffers overlap */ + memmove(kdb_buffer, cphold, len + 1); next_avail = kdb_buffer + len; size_avail = sizeof(kdb_buffer) - len; } From 5b26f1a3146454a24dbcb8b1cdae5d507f7432e6 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 19 Aug 2025 11:59:05 +0200 Subject: [PATCH 1820/2711] kdb: Replace deprecated strcpy() with memcpy() in parse_grep() strcpy() is deprecated; use memcpy() instead. We can safely use memcpy() because we already know the length of the source string 'cp' and that it is guaranteed to be NUL-terminated within the first KDB_GREP_STRLEN bytes. Link: https://github.com/KSPP/linux/issues/88 Reviewed-by: Douglas Anderson Signed-off-by: Thorsten Blum Signed-off-by: Daniel Thompson (RISCstar) --- kernel/debug/kdb/kdb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 7a4d2d4689a5..cdf91976eb7c 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -860,7 +860,7 @@ static void parse_grep(const char *str) kdb_printf("search string too long\n"); return; } - strcpy(kdb_grep_string, cp); + memcpy(kdb_grep_string, cp, len + 1); kdb_grepping_flag++; return; } From 0c28a23722e03695ae1cbbadde3dd32d75c1cb7f Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 19 Aug 2025 11:59:06 +0200 Subject: [PATCH 1821/2711] kdb: Replace deprecated strcpy() with helper function in kdb_defcmd() strcpy() is deprecated; use the new helper function kdb_strdup_dequote() instead. In addition to string duplication similar to kdb_strdup(), it also trims surrounding quotes from the input string if present. kdb_strdup_dequote() also checks for a trailing quote in the input string which was previously not checked. Link: https://github.com/KSPP/linux/issues/88 Reviewed-by: Douglas Anderson Signed-off-by: Thorsten Blum Signed-off-by: Daniel Thompson (RISCstar) --- kernel/debug/kdb/kdb_main.c | 12 ++---------- kernel/debug/kdb/kdb_private.h | 1 + kernel/debug/kdb/kdb_support.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index cdf91976eb7c..dddf2b5aad57 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -721,20 +721,12 @@ static int kdb_defcmd(int argc, const char **argv) mp->name = kdb_strdup(argv[1], GFP_KDB); if (!mp->name) goto fail_name; - mp->usage = kdb_strdup(argv[2], GFP_KDB); + mp->usage = kdb_strdup_dequote(argv[2], GFP_KDB); if (!mp->usage) goto fail_usage; - mp->help = kdb_strdup(argv[3], GFP_KDB); + mp->help = kdb_strdup_dequote(argv[3], GFP_KDB); if (!mp->help) goto fail_help; - if (mp->usage[0] == '"') { - strcpy(mp->usage, argv[2]+1); - mp->usage[strlen(mp->usage)-1] = '\0'; - } - if (mp->help[0] == '"') { - strcpy(mp->help, argv[3]+1); - mp->help[strlen(mp->help)-1] = '\0'; - } INIT_LIST_HEAD(&kdb_macro->statements); defcmd_in_progress = true; diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h index d2520d72b1f5..a2fc7d2bc9fc 100644 --- a/kernel/debug/kdb/kdb_private.h +++ b/kernel/debug/kdb/kdb_private.h @@ -110,6 +110,7 @@ extern int kdbgetaddrarg(int, const char **, int*, unsigned long *, extern int kdbgetsymval(const char *, kdb_symtab_t *); extern int kdbnearsym(unsigned long, kdb_symtab_t *); extern char *kdb_strdup(const char *str, gfp_t type); +extern char *kdb_strdup_dequote(const char *str, gfp_t type); extern void kdb_symbol_print(unsigned long, const kdb_symtab_t *, unsigned int); /* Routine for debugging the debugger state. */ diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c index d36281142fa1..56f7b906e7cc 100644 --- a/kernel/debug/kdb/kdb_support.c +++ b/kernel/debug/kdb/kdb_support.c @@ -255,6 +255,35 @@ char *kdb_strdup(const char *str, gfp_t type) return s; } +/* + * kdb_strdup_dequote - same as kdb_strdup(), but trims surrounding quotes from + * the input string if present. + * Remarks: + * Quotes are only removed if there is both a leading and a trailing quote. + */ +char *kdb_strdup_dequote(const char *str, gfp_t type) +{ + size_t len = strlen(str); + char *s; + + if (str[0] == '"' && len > 1 && str[len - 1] == '"') { + /* trim both leading and trailing quotes */ + str++; + len -= 2; + } + + len++; /* add space for NUL terminator */ + + s = kmalloc(len, type); + if (!s) + return NULL; + + memcpy(s, str, len - 1); + s[len - 1] = '\0'; + + return s; +} + /* * kdb_getarea_size - Read an area of data. The kdb equivalent of * copy_from_user, with kdb messages for invalid addresses. From fdbdd0ccb30af18d3b29e714ac8d5ab6163279e0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 7 May 2025 11:43:37 +0100 Subject: [PATCH 1822/2711] kdb: remove redundant check for scancode 0xe0 The check for scancode 0xe0 is always false because earlier on the scan code is masked with 0x7f so there are never going to be values greater than 0x7f. Remove the redundant check. Signed-off-by: Colin Ian King Reviewed-by: Douglas Anderson Signed-off-by: Daniel Thompson (RISCstar) --- kernel/debug/kdb/kdb_keyboard.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/kernel/debug/kdb/kdb_keyboard.c b/kernel/debug/kdb/kdb_keyboard.c index 3a74604fdb8a..386d30e530b7 100644 --- a/kernel/debug/kdb/kdb_keyboard.c +++ b/kernel/debug/kdb/kdb_keyboard.c @@ -145,9 +145,6 @@ int kdb_get_kbd_char(void) return CTRL('F'); } - if (scancode == 0xe0) - return -1; - /* * For Japanese 86/106 keyboards * See comment in drivers/char/pc_keyb.c. From c8a8df494f7103f66d2d677347b7b941d8de71a1 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Tue, 29 Apr 2025 12:45:43 +0200 Subject: [PATCH 1823/2711] rpmsg: Use strscpy() instead of strscpy_pad() kzalloc() already zero-initializes the destination buffer, making strscpy() sufficient for safely copying the name. The additional NUL- padding performed by strscpy_pad() is unnecessary. The size parameter is optional, and strscpy() automatically determines the size of the destination buffer using sizeof() when the argument is omitted. RPMSG_NAME_SIZE is equal to sizeof(rpdev->id.name) and can be removed - remove it. No functional changes intended. Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250429104543.66927-2-thorsten.blum@linux.dev Signed-off-by: Bjorn Andersson --- drivers/rpmsg/qcom_glink_native.c | 2 +- drivers/rpmsg/qcom_smd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index a2f9d85c7156..820a6ca5b1d7 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1663,7 +1663,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, } rpdev->ept = &channel->ept; - strscpy_pad(rpdev->id.name, name, RPMSG_NAME_SIZE); + strscpy(rpdev->id.name, name); rpdev->src = RPMSG_ADDR_ANY; rpdev->dst = RPMSG_ADDR_ANY; rpdev->ops = &glink_device_ops; diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index 87c944d4b4f3..f0f12e7ad2a6 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -1089,7 +1089,7 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel) /* Assign public information to the rpmsg_device */ rpdev = &qsdev->rpdev; - strscpy_pad(rpdev->id.name, channel->name, RPMSG_NAME_SIZE); + strscpy(rpdev->id.name, channel->name); rpdev->src = RPMSG_ADDR_ANY; rpdev->dst = RPMSG_ADDR_ANY; From 09390ed9af37ed612dd0967ff2b0d639872b8776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20Cz=C3=A9m=C3=A1n?= Date: Fri, 25 Jul 2025 22:02:58 +0200 Subject: [PATCH 1824/2711] rpmsg: qcom_smd: Fix fallback to qcom,ipc parse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mbox_request_channel() returning value was changed in case of error. It uses returning value of of_parse_phandle_with_args(). It is returning with -ENOENT instead of -ENODEV when no mboxes property exists. Fixes: 24fdd5074b20 ("mailbox: use error ret code of of_parse_phandle_with_args()") Reviewed-by: Dmitry Baryshkov Reviewed-by: Stephan Gerhold Tested-by: Stephan Gerhold # msm8939 Signed-off-by: Barnabás Czémán Link: https://lore.kernel.org/r/20250725-fix-qcom-smd-v2-1-e4e43613f874@mainlining.org Signed-off-by: Bjorn Andersson --- drivers/rpmsg/qcom_smd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index f0f12e7ad2a6..42594f5ee438 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -1368,7 +1368,7 @@ static int qcom_smd_parse_edge(struct device *dev, edge->mbox_client.knows_txdone = true; edge->mbox_chan = mbox_request_channel(&edge->mbox_client, 0); if (IS_ERR(edge->mbox_chan)) { - if (PTR_ERR(edge->mbox_chan) != -ENODEV) { + if (PTR_ERR(edge->mbox_chan) != -ENOENT) { ret = dev_err_probe(dev, PTR_ERR(edge->mbox_chan), "failed to acquire IPC mailbox\n"); goto put_node; From 581e3dea0ece4b59cf714c9dfe195a178d3ae13b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 6 Jul 2025 17:47:08 +0300 Subject: [PATCH 1825/2711] remoteproc: qcom_q6v5_mss: support loading MBN file on msm8974 On MSM8974 / APQ8074, MSM8226 and MSM8926 the MSS requires loading raw MBA image instead of the ELF file. Skip the ELF headers if mba.mbn was specified as the firmware image. Fixes: a5a4e02d083d ("remoteproc: qcom: Add support for parsing fw dt bindings") Signed-off-by: Dmitry Baryshkov Signed-off-by: Dmitry Baryshkov Tested-by: Luca Weiss # msm8974pro-fairphone-fp2 Link: https://lore.kernel.org/r/20250706-msm8974-fix-mss-v4-1-630907dbd898@oss.qualcomm.com [bjorn: Unwrapped the long memcpy line, to taste] Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 0c0199fb0e68..3087d895b87f 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -498,6 +498,8 @@ static void q6v5_debug_policy_load(struct q6v5 *qproc, void *mba_region) release_firmware(dp_fw); } +#define MSM8974_B00_OFFSET 0x1000 + static int q6v5_load(struct rproc *rproc, const struct firmware *fw) { struct q6v5 *qproc = rproc->priv; @@ -516,7 +518,14 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw) return -EBUSY; } - memcpy(mba_region, fw->data, fw->size); + if ((qproc->version == MSS_MSM8974 || + qproc->version == MSS_MSM8226 || + qproc->version == MSS_MSM8926) && + fw->size > MSM8974_B00_OFFSET && + !memcmp(fw->data, ELFMAG, SELFMAG)) + memcpy(mba_region, fw->data + MSM8974_B00_OFFSET, fw->size - MSM8974_B00_OFFSET); + else + memcpy(mba_region, fw->data, fw->size); q6v5_debug_policy_load(qproc, mba_region); memunmap(mba_region); From 24723d7c09ddac90bdd9e9864f92eb43ed70a083 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 15 Sep 2025 13:15:18 +0200 Subject: [PATCH 1826/2711] dt-bindings: remoteproc: qcom,milos-pas: Document remoteprocs Document the bindings for the ADSP, CDSP, MPSS and WPSS PAS on the Milos (e.g. SM7635) SoC. Signed-off-by: Luca Weiss Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250915-sm7635-remoteprocs-v5-1-96526cac59c6@fairphone.com Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/qcom,milos-pas.yaml | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml new file mode 100644 index 000000000000..c47d97004b33 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/qcom,milos-pas.yaml @@ -0,0 +1,198 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/qcom,milos-pas.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Milos SoC Peripheral Authentication Service + +maintainers: + - Luca Weiss + +description: + Qualcomm Milos SoC Peripheral Authentication Service loads and boots firmware + on the Qualcomm DSP Hexagon cores. + +properties: + compatible: + enum: + - qcom,milos-adsp-pas + - qcom,milos-cdsp-pas + - qcom,milos-mpss-pas + - qcom,milos-wpss-pas + + reg: + maxItems: 1 + + clocks: + items: + - description: XO clock + + clock-names: + items: + - const: xo + + interrupts: + minItems: 6 + maxItems: 6 + + interrupt-names: + minItems: 6 + maxItems: 6 + + qcom,qmp: + $ref: /schemas/types.yaml#/definitions/phandle + description: Reference to the AOSS side-channel message RAM. + + smd-edge: false + + firmware-name: + minItems: 1 + items: + - description: Firmware name of the Hexagon core + - description: Firmware name of the Hexagon Devicetree + + memory-region: + minItems: 1 + items: + - description: Memory region for core Firmware authentication + - description: Memory region for Devicetree Firmware authentication + +required: + - compatible + - reg + - memory-region + +allOf: + - $ref: /schemas/remoteproc/qcom,pas-common.yaml# + - if: + properties: + compatible: + enum: + - qcom,milos-adsp-pas + - qcom,milos-cdsp-pas + then: + properties: + memory-region: + minItems: 2 + firmware-name: + minItems: 2 + else: + properties: + memory-region: + maxItems: 1 + firmware-name: + maxItems: 1 + + - if: + properties: + compatible: + contains: + enum: + - qcom,milos-adsp-pas + then: + properties: + power-domains: + items: + - description: LCX power domain + - description: LMX power domain + power-domain-names: + items: + - const: lcx + - const: lmx + + - if: + properties: + compatible: + enum: + - qcom,milos-cdsp-pas + - qcom,milos-wpss-pas + then: + properties: + power-domains: + items: + - description: CX power domain + - description: MX power domain + power-domain-names: + items: + - const: cx + - const: mx + + - if: + properties: + compatible: + enum: + - qcom,milos-mpss-pas + then: + properties: + power-domains: + items: + - description: CX power domain + - description: MSS power domain + power-domain-names: + items: + - const: cx + - const: mss + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + + remoteproc@3000000 { + compatible = "qcom,milos-adsp-pas"; + reg = <0x03000000 0x10000>; + + interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack", + "shutdown-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&rpmhpd RPMHPD_LCX>, + <&rpmhpd RPMHPD_LMX>; + power-domain-names = "lcx", + "lmx"; + + interconnects = <&lpass_ag_noc MASTER_LPASS_PROC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + + memory-region = <&adspslpi_mem>, <&q6_adsp_dtb_mem>; + + firmware-name = "qcom/milos/vendor/device/adsp.mbn", + "qcom/milos/vendor/device/adsp_dtb.mbn"; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&smp2p_adsp_out 0>; + qcom,smem-state-names = "stop"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "lpass"; + qcom,remote-pid = <2>; + + /* ... */ + }; + }; From ef575ff2054ceb2bd6701630db2f3d33f5c1a1cf Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 15 Sep 2025 13:15:19 +0200 Subject: [PATCH 1827/2711] remoteproc: qcom: pas: Add Milos remoteproc support Add the different remoteprocs found on the Milos SoC: ADSP, CDSP, MPSS and WPSS. Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20250915-sm7635-remoteprocs-v5-2-96526cac59c6@fairphone.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 02e29171cbbe..6fe5ae0a9eb1 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -1256,6 +1256,26 @@ static const struct qcom_pas_data sdx55_mpss_resource = { .ssctl_id = 0x22, }; +static const struct qcom_pas_data milos_cdsp_resource = { + .crash_reason_smem = 601, + .firmware_name = "cdsp.mbn", + .dtb_firmware_name = "cdsp_dtb.mbn", + .pas_id = 18, + .dtb_pas_id = 0x25, + .minidump_id = 7, + .auto_boot = true, + .proxy_pd_names = (char*[]){ + "cx", + "mx", + NULL + }, + .load_state = "cdsp", + .ssr_name = "cdsp", + .sysmon_name = "cdsp", + .ssctl_id = 0x17, + .smem_host_id = 5, +}; + static const struct qcom_pas_data sm8450_mpss_resource = { .crash_reason_smem = 421, .firmware_name = "modem.mdt", @@ -1430,6 +1450,10 @@ static const struct qcom_pas_data sm8750_mpss_resource = { }; static const struct of_device_id qcom_pas_of_match[] = { + { .compatible = "qcom,milos-adsp-pas", .data = &sm8550_adsp_resource}, + { .compatible = "qcom,milos-cdsp-pas", .data = &milos_cdsp_resource}, + { .compatible = "qcom,milos-mpss-pas", .data = &sm8450_mpss_resource}, + { .compatible = "qcom,milos-wpss-pas", .data = &sc7280_wpss_resource}, { .compatible = "qcom,msm8226-adsp-pil", .data = &msm8996_adsp_resource}, { .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource}, { .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init}, From 072ce917bf95fc31f3c8c106b71a31e8607553ce Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Thu, 31 Jul 2025 18:06:17 -0300 Subject: [PATCH 1828/2711] clk: bcm: rpi: Add missing logs if firmware fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In contrary to raspberrypi_fw_set_rate(), the ops for is_prepared() and recalc_rate() silently ignore firmware errors by just returning 0. Since these operations should never fail, add at least error logs to inform the user. Signed-off-by: Stefan Wahren Signed-off-by: Maíra Canal Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-raspberrypi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index 8e4fde03ed23..166d0bec3803 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -194,8 +194,11 @@ static int raspberrypi_fw_is_prepared(struct clk_hw *hw) ret = raspberrypi_clock_property(rpi->firmware, data, RPI_FIRMWARE_GET_CLOCK_STATE, &val); - if (ret) + if (ret) { + dev_err_ratelimited(rpi->dev, "Failed to get %s state: %d\n", + clk_hw_get_name(hw), ret); return 0; + } return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT); } @@ -211,8 +214,11 @@ static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw, ret = raspberrypi_clock_property(rpi->firmware, data, RPI_FIRMWARE_GET_CLOCK_RATE, &val); - if (ret) + if (ret) { + dev_err_ratelimited(rpi->dev, "Failed to get %s frequency: %d\n", + clk_hw_get_name(hw), ret); return 0; + } return val; } From 919d6924ae9b4bcc9cb1d5ce4b78d5b92665d630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 31 Jul 2025 18:06:18 -0300 Subject: [PATCH 1829/2711] clk: bcm: rpi: Turn firmware clock on/off when preparing/unpreparing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, when we prepare or unprepare RPi's clocks, we don't actually enable/disable the firmware clock. This means that `clk_disable_unprepare()` doesn't actually change the clock state at all, nor does it lowers the clock rate. From the Mailbox Property Interface documentation [1], we can see that we should use `RPI_FIRMWARE_SET_CLOCK_STATE` to set the clock state off/on. Therefore, use `RPI_FIRMWARE_SET_CLOCK_STATE` to create a prepare and an unprepare hook for RPi's firmware clock. As now the clocks are actually turned off, some of them are now marked CLK_IS_CRITICAL, as those are required to be on during the whole system operation. Link: https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface [1] Signed-off-by: Maíra Canal Reviewed-by: Stefan Wahren Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-raspberrypi.c | 56 ++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index 166d0bec3803..70acfa68827d 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -68,6 +68,7 @@ struct raspberrypi_clk_variant { char *clkdev; unsigned long min_rate; bool minimize; + u32 flags; }; static struct raspberrypi_clk_variant @@ -75,6 +76,7 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { [RPI_FIRMWARE_ARM_CLK_ID] = { .export = true, .clkdev = "cpu0", + .flags = CLK_IS_CRITICAL, }, [RPI_FIRMWARE_CORE_CLK_ID] = { .export = true, @@ -90,6 +92,12 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { * always use the minimum the drivers will let us. */ .minimize = true, + + /* + * It should never be disabled as it drives the bus for + * everything else. + */ + .flags = CLK_IS_CRITICAL, }, [RPI_FIRMWARE_M2MC_CLK_ID] = { .export = true, @@ -115,6 +123,15 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { * drivers will let us. */ .minimize = true, + + /* + * As mentioned above, this clock is disabled during boot, + * the firmware will skip the HSM initialization, resulting + * in a bus lockup. Therefore, make sure it's enabled + * during boot, but after it, it can be enabled/disabled + * by the driver. + */ + .flags = CLK_IGNORE_UNUSED, }, [RPI_FIRMWARE_V3D_CLK_ID] = { .export = true, @@ -123,10 +140,12 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { [RPI_FIRMWARE_PIXEL_CLK_ID] = { .export = true, .minimize = true, + .flags = CLK_IS_CRITICAL, }, [RPI_FIRMWARE_HEVC_CLK_ID] = { .export = true, .minimize = true, + .flags = CLK_IS_CRITICAL, }, [RPI_FIRMWARE_ISP_CLK_ID] = { .export = true, @@ -135,6 +154,7 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = { .export = true, .minimize = true, + .flags = CLK_IS_CRITICAL, }, [RPI_FIRMWARE_VEC_CLK_ID] = { .export = true, @@ -265,7 +285,41 @@ static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw, return 0; } +static int raspberrypi_fw_prepare(struct clk_hw *hw) +{ + const struct raspberrypi_clk_data *data = clk_hw_to_data(hw); + struct raspberrypi_clk *rpi = data->rpi; + u32 state = RPI_FIRMWARE_STATE_ENABLE_BIT; + int ret; + + ret = raspberrypi_clock_property(rpi->firmware, data, + RPI_FIRMWARE_SET_CLOCK_STATE, &state); + if (ret) + dev_err_ratelimited(rpi->dev, + "Failed to set clock %s state to on: %d\n", + clk_hw_get_name(hw), ret); + + return ret; +} + +static void raspberrypi_fw_unprepare(struct clk_hw *hw) +{ + const struct raspberrypi_clk_data *data = clk_hw_to_data(hw); + struct raspberrypi_clk *rpi = data->rpi; + u32 state = 0; + int ret; + + ret = raspberrypi_clock_property(rpi->firmware, data, + RPI_FIRMWARE_SET_CLOCK_STATE, &state); + if (ret) + dev_err_ratelimited(rpi->dev, + "Failed to set clock %s state to off: %d\n", + clk_hw_get_name(hw), ret); +} + static const struct clk_ops raspberrypi_firmware_clk_ops = { + .prepare = raspberrypi_fw_prepare, + .unprepare = raspberrypi_fw_unprepare, .is_prepared = raspberrypi_fw_is_prepared, .recalc_rate = raspberrypi_fw_get_rate, .determine_rate = raspberrypi_fw_dumb_determine_rate, @@ -295,7 +349,7 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, if (!init.name) return ERR_PTR(-ENOMEM); init.ops = &raspberrypi_firmware_clk_ops; - init.flags = CLK_GET_RATE_NOCACHE; + init.flags = variant->flags | CLK_GET_RATE_NOCACHE; data->hw.init = &init; From 6526402b9bac873d7a64c6e81eb53307d8471f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Thu, 31 Jul 2025 18:06:19 -0300 Subject: [PATCH 1830/2711] clk: bcm: rpi: Maximize V3D clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although minimizing the clock rate is the best for most scenarios, as stated in commit 4d85abb0fb8e ("clk: bcm: rpi: Enable minimize for all firmware clocks"), when it comes to the GPU, it's ideal to have the maximum rate allowed. Add an option to maximize a firmware clock's rate when the clock is enabled and set this option for V3D. Signed-off-by: Maíra Canal Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-raspberrypi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index 70acfa68827d..1a9162f0ae31 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -68,6 +68,7 @@ struct raspberrypi_clk_variant { char *clkdev; unsigned long min_rate; bool minimize; + bool maximize; u32 flags; }; @@ -135,7 +136,7 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NUM_CLK_ID] = { }, [RPI_FIRMWARE_V3D_CLK_ID] = { .export = true, - .minimize = true, + .maximize = true, }, [RPI_FIRMWARE_PIXEL_CLK_ID] = { .export = true, @@ -386,6 +387,9 @@ static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, } } + if (variant->maximize) + variant->min_rate = max_rate; + if (variant->min_rate) { unsigned long rate; From 6c4c26b624790098988c1034541087e3e5ed5bed Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 24 Jul 2025 10:38:28 +0200 Subject: [PATCH 1831/2711] clk: mediatek: mt8195-infra_ao: Fix parent for infra_ao_hdmi_26m The infrastructure gate for the HDMI specific crystal needs the top_hdmi_xtal clock to be configured in order to ungate the 26m clock to the HDMI IP, and it wouldn't work without. Reparent the infra_ao_hdmi_26m clock to top_hdmi_xtal to fix that. Fixes: e2edf59dec0b ("clk: mediatek: Add MT8195 infrastructure clock support") Signed-off-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt8195-infra_ao.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/mediatek/clk-mt8195-infra_ao.c b/drivers/clk/mediatek/clk-mt8195-infra_ao.c index bb648a88e43a..ad47fdb23460 100644 --- a/drivers/clk/mediatek/clk-mt8195-infra_ao.c +++ b/drivers/clk/mediatek/clk-mt8195-infra_ao.c @@ -103,7 +103,7 @@ static const struct mtk_gate infra_ao_clks[] = { GATE_INFRA_AO0(CLK_INFRA_AO_CQ_DMA_FPC, "infra_ao_cq_dma_fpc", "fpc", 28), GATE_INFRA_AO0(CLK_INFRA_AO_UART5, "infra_ao_uart5", "top_uart", 29), /* INFRA_AO1 */ - GATE_INFRA_AO1(CLK_INFRA_AO_HDMI_26M, "infra_ao_hdmi_26m", "clk26m", 0), + GATE_INFRA_AO1(CLK_INFRA_AO_HDMI_26M, "infra_ao_hdmi_26m", "top_hdmi_xtal", 0), GATE_INFRA_AO1(CLK_INFRA_AO_SPI0, "infra_ao_spi0", "top_spi", 1), GATE_INFRA_AO1(CLK_INFRA_AO_MSDC0, "infra_ao_msdc0", "top_msdc50_0_hclk", 2), GATE_INFRA_AO1(CLK_INFRA_AO_MSDC1, "infra_ao_msdc1", "top_axi", 4), From 64e7df08ed43e45aa1a8382b459b516d04d47e99 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 24 Jul 2025 10:39:05 +0200 Subject: [PATCH 1832/2711] dt-bindings: clock: mt7622: Add AFE_MRGIF clock Add the missing AFE Merge Interface clock to MT7622 to make use of it in the audio subsystem. While at it, also remove the useless CLK_AUDIO_NR_CLK definition. Signed-off-by: AngeloGioacchino Del Regno Acked-by: Rob Herring (Arm) Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/mt7622-clk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/mt7622-clk.h b/include/dt-bindings/clock/mt7622-clk.h index c12e7eab0788..a173eb132892 100644 --- a/include/dt-bindings/clock/mt7622-clk.h +++ b/include/dt-bindings/clock/mt7622-clk.h @@ -228,7 +228,7 @@ #define CLK_AUDIO_MEM_ASRC4 44 #define CLK_AUDIO_MEM_ASRC5 45 #define CLK_AUDIO_AFE_CONN 46 -#define CLK_AUDIO_NR_CLK 47 +#define CLK_AUDIO_AFE_MRGIF 47 /* SSUSBSYS */ From cc5f9cfb2a2d22f05f5aa1c09bfa816cbfc4e10a Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 24 Jul 2025 10:39:06 +0200 Subject: [PATCH 1833/2711] clk: mediatek: mt7622-aud: Add missing AFE_MRGIF clock Add the AFE Merge Interface clock used for the audio subsystem. Signed-off-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt7622-aud.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/mediatek/clk-mt7622-aud.c b/drivers/clk/mediatek/clk-mt7622-aud.c index 931a0598e598..a4ea5e20efa2 100644 --- a/drivers/clk/mediatek/clk-mt7622-aud.c +++ b/drivers/clk/mediatek/clk-mt7622-aud.c @@ -75,6 +75,7 @@ static const struct mtk_gate audio_clks[] = { GATE_AUDIO1(CLK_AUDIO_A1SYS, "audio_a1sys", "a1sys_hp_sel", 21), GATE_AUDIO1(CLK_AUDIO_A2SYS, "audio_a2sys", "a2sys_hp_sel", 22), GATE_AUDIO1(CLK_AUDIO_AFE_CONN, "audio_afe_conn", "a1sys_hp_sel", 23), + GATE_AUDIO1(CLK_AUDIO_AFE_MRGIF, "audio_afe_mrgif", "aud_mux1_sel", 25), /* AUDIO2 */ GATE_AUDIO2(CLK_AUDIO_UL1, "audio_ul1", "a1sys_hp_sel", 0), GATE_AUDIO2(CLK_AUDIO_UL2, "audio_ul2", "a1sys_hp_sel", 1), From 5e121370a7ad3414c7f3a77002e2b18abe5c6fe1 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 25 Aug 2025 23:09:31 +0800 Subject: [PATCH 1834/2711] clk: mediatek: clk-mux: Do not pass flags to clk_mux_determine_rate_flags() The `flags` in |struct mtk_mux| are core clk flags, not mux clk flags. Passing one to the other is wrong. Since there aren't any actual users adding CLK_MUX_* flags, just drop it for now. Fixes: b05ea3314390 ("clk: mediatek: clk-mux: Add .determine_rate() callback") Signed-off-by: Chen-Yu Tsai Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mux.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c index 60990296450b..9a12e58230be 100644 --- a/drivers/clk/mediatek/clk-mux.c +++ b/drivers/clk/mediatek/clk-mux.c @@ -146,9 +146,7 @@ static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index) static int mtk_clk_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); - - return clk_mux_determine_rate_flags(hw, req, mux->data->flags); + return clk_mux_determine_rate_flags(hw, req, 0); } const struct clk_ops mtk_mux_clr_set_upd_ops = { From aee9ffa010e9b06f4138c6575a9318422ac32fc3 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:21 +0200 Subject: [PATCH 1835/2711] clk: mediatek: clk-pll: Add set/clr regs for shared PLL enable control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On MT8196, there are set/clr registers to control a shared PLL enable register. These are intended to prevent different masters from manipulating the PLLs independently. Add the corresponding en_set_reg and en_clr_reg fields to the mtk_pll_data structure. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-pll.c | 4 ++++ drivers/clk/mediatek/clk-pll.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index ce453e1718e5..49ca25dd5418 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -308,6 +308,10 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, pll->en_addr = base + data->en_reg; else pll->en_addr = pll->base_addr + REG_CON0; + if (data->en_set_reg) + pll->en_set_addr = base + data->en_set_reg; + if (data->en_clr_reg) + pll->en_clr_addr = base + data->en_clr_reg; pll->hw.init = &init; pll->data = data; diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h index 285c8db958b3..c4d06bb11516 100644 --- a/drivers/clk/mediatek/clk-pll.h +++ b/drivers/clk/mediatek/clk-pll.h @@ -47,6 +47,8 @@ struct mtk_pll_data { const struct mtk_pll_div_table *div_table; const char *parent_name; u32 en_reg; + u32 en_set_reg; + u32 en_clr_reg; u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */ u8 pcw_chg_bit; }; @@ -68,6 +70,8 @@ struct mtk_clk_pll { void __iomem *pcw_addr; void __iomem *pcw_chg_addr; void __iomem *en_addr; + void __iomem *en_set_addr; + void __iomem *en_clr_addr; const struct mtk_pll_data *data; }; From 2c327a17718d8d6e7e79c2ab73ea6073aae9f22d Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:22 +0200 Subject: [PATCH 1836/2711] clk: mediatek: clk-pll: Add ops for PLLs using set/clr regs and FENC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MT8196 uses a combination of set/clr registers to control the PLL enable state, along with a FENC bit to check the preparation status. Add new set of PLL clock operations with support for set/clr enable and FENC status logic. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-pll.c | 41 +++++++++++++++++++++++++++++++++- drivers/clk/mediatek/clk-pll.h | 4 ++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 49ca25dd5418..d717a120793b 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -37,6 +37,13 @@ int mtk_pll_is_prepared(struct clk_hw *hw) return (readl(pll->en_addr) & BIT(pll->data->pll_en_bit)) != 0; } +static int mtk_pll_fenc_is_prepared(struct clk_hw *hw) +{ + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); + + return !!(readl(pll->fenc_addr) & BIT(pll->data->fenc_sta_bit)); +} + static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin, u32 pcw, int postdiv) { @@ -274,6 +281,25 @@ void mtk_pll_unprepare(struct clk_hw *hw) writel(r, pll->pwr_addr); } +static int mtk_pll_prepare_setclr(struct clk_hw *hw) +{ + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); + + writel(BIT(pll->data->pll_en_bit), pll->en_set_addr); + + /* Wait 20us after enable for the PLL to stabilize */ + udelay(20); + + return 0; +} + +static void mtk_pll_unprepare_setclr(struct clk_hw *hw) +{ + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); + + writel(BIT(pll->data->pll_en_bit), pll->en_clr_addr); +} + const struct clk_ops mtk_pll_ops = { .is_prepared = mtk_pll_is_prepared, .prepare = mtk_pll_prepare, @@ -283,6 +309,16 @@ const struct clk_ops mtk_pll_ops = { .set_rate = mtk_pll_set_rate, }; +const struct clk_ops mtk_pll_fenc_clr_set_ops = { + .is_prepared = mtk_pll_fenc_is_prepared, + .prepare = mtk_pll_prepare_setclr, + .unprepare = mtk_pll_unprepare_setclr, + .recalc_rate = mtk_pll_recalc_rate, + .round_rate = mtk_pll_round_rate, + .set_rate = mtk_pll_set_rate, +}; +EXPORT_SYMBOL_GPL(mtk_pll_fenc_clr_set_ops); + struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, const struct mtk_pll_data *data, void __iomem *base, @@ -315,6 +351,8 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, pll->hw.init = &init; pll->data = data; + pll->fenc_addr = base + data->fenc_sta_ofs; + init.name = data->name; init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0; init.ops = pll_ops; @@ -337,12 +375,13 @@ struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data, { struct mtk_clk_pll *pll; struct clk_hw *hw; + const struct clk_ops *pll_ops = data->ops ? data->ops : &mtk_pll_ops; pll = kzalloc(sizeof(*pll), GFP_KERNEL); if (!pll) return ERR_PTR(-ENOMEM); - hw = mtk_clk_register_pll_ops(pll, data, base, &mtk_pll_ops); + hw = mtk_clk_register_pll_ops(pll, data, base, pll_ops); if (IS_ERR(hw)) kfree(pll); diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h index c4d06bb11516..c6346c21c784 100644 --- a/drivers/clk/mediatek/clk-pll.h +++ b/drivers/clk/mediatek/clk-pll.h @@ -29,6 +29,7 @@ struct mtk_pll_data { u32 reg; u32 pwr_reg; u32 en_mask; + u32 fenc_sta_ofs; u32 pd_reg; u32 tuner_reg; u32 tuner_en_reg; @@ -51,6 +52,7 @@ struct mtk_pll_data { u32 en_clr_reg; u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */ u8 pcw_chg_bit; + u8 fenc_sta_bit; }; /* @@ -72,6 +74,7 @@ struct mtk_clk_pll { void __iomem *en_addr; void __iomem *en_set_addr; void __iomem *en_clr_addr; + void __iomem *fenc_addr; const struct mtk_pll_data *data; }; @@ -82,6 +85,7 @@ void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls, struct clk_hw_onecell_data *clk_data); extern const struct clk_ops mtk_pll_ops; +extern const struct clk_ops mtk_pll_fenc_clr_set_ops; static inline struct mtk_clk_pll *to_mtk_clk_pll(struct clk_hw *hw) { From d3c4dde9770dbe2eb3a57c3d952c630e81fcd1c0 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:23 +0200 Subject: [PATCH 1837/2711] clk: mediatek: clk-mux: Add ops for mux gates with set/clr/upd and FENC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MT8196 uses set/clr/upd registers for mux gate enable/disable control, along with a FENC bit to check the status. Add new set of mux gate clock operations with support for set/clr/upd and FENC status logic. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mux.c | 49 ++++++++++++++++++++++++++++++++++ drivers/clk/mediatek/clk-mux.h | 45 +++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c index 9a12e58230be..5e12ef40511e 100644 --- a/drivers/clk/mediatek/clk-mux.c +++ b/drivers/clk/mediatek/clk-mux.c @@ -17,6 +17,8 @@ #include "clk-mux.h" +#define MTK_WAIT_FENC_DONE_US 30 + struct mtk_clk_mux { struct clk_hw hw; struct regmap *regmap; @@ -30,6 +32,33 @@ static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw) return container_of(hw, struct mtk_clk_mux, hw); } +static int mtk_clk_mux_fenc_enable_setclr(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + unsigned long flags; + u32 val; + int ret; + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + else + __acquire(mux->lock); + + regmap_write(mux->regmap, mux->data->clr_ofs, + BIT(mux->data->gate_shift)); + + ret = regmap_read_poll_timeout_atomic(mux->regmap, mux->data->fenc_sta_mon_ofs, + val, val & BIT(mux->data->fenc_shift), 1, + MTK_WAIT_FENC_DONE_US); + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + else + __release(mux->lock); + + return ret; +} + static int mtk_clk_mux_enable_setclr(struct clk_hw *hw) { struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); @@ -70,6 +99,16 @@ static void mtk_clk_mux_disable_setclr(struct clk_hw *hw) BIT(mux->data->gate_shift)); } +static int mtk_clk_mux_fenc_is_enabled(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 val; + + regmap_read(mux->regmap, mux->data->fenc_sta_mon_ofs, &val); + + return !!(val & BIT(mux->data->fenc_shift)); +} + static int mtk_clk_mux_is_enabled(struct clk_hw *hw) { struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); @@ -166,6 +205,16 @@ const struct clk_ops mtk_mux_gate_clr_set_upd_ops = { }; EXPORT_SYMBOL_GPL(mtk_mux_gate_clr_set_upd_ops); +const struct clk_ops mtk_mux_gate_fenc_clr_set_upd_ops = { + .enable = mtk_clk_mux_fenc_enable_setclr, + .disable = mtk_clk_mux_disable_setclr, + .is_enabled = mtk_clk_mux_fenc_is_enabled, + .get_parent = mtk_clk_mux_get_parent, + .set_parent = mtk_clk_mux_set_parent_setclr_lock, + .determine_rate = mtk_clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(mtk_mux_gate_fenc_clr_set_upd_ops); + static struct clk_hw *mtk_clk_register_mux(struct device *dev, const struct mtk_mux *mux, struct regmap *regmap, diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h index 943ad1d7ce4b..a4fd17a18532 100644 --- a/drivers/clk/mediatek/clk-mux.h +++ b/drivers/clk/mediatek/clk-mux.h @@ -28,11 +28,13 @@ struct mtk_mux { u32 set_ofs; u32 clr_ofs; u32 upd_ofs; + u32 fenc_sta_mon_ofs; u8 mux_shift; u8 mux_width; u8 gate_shift; s8 upd_shift; + u8 fenc_shift; const struct clk_ops *ops; signed char num_parents; @@ -77,6 +79,7 @@ struct mtk_mux { extern const struct clk_ops mtk_mux_clr_set_upd_ops; extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops; +extern const struct clk_ops mtk_mux_gate_fenc_clr_set_upd_ops; #define MUX_GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ @@ -118,6 +121,48 @@ extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops; 0, _upd_ofs, _upd, CLK_SET_RATE_PARENT, \ mtk_mux_clr_set_upd_ops) +#define MUX_GATE_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, _paridx, \ + _num_parents, _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ + _shift, _width, _gate, _upd_ofs, _upd, \ + _fenc_sta_mon_ofs, _fenc, _flags) { \ + .id = _id, \ + .name = _name, \ + .mux_ofs = _mux_ofs, \ + .set_ofs = _mux_set_ofs, \ + .clr_ofs = _mux_clr_ofs, \ + .upd_ofs = _upd_ofs, \ + .fenc_sta_mon_ofs = _fenc_sta_mon_ofs, \ + .mux_shift = _shift, \ + .mux_width = _width, \ + .gate_shift = _gate, \ + .upd_shift = _upd, \ + .fenc_shift = _fenc, \ + .parent_names = _parents, \ + .parent_index = _paridx, \ + .num_parents = _num_parents, \ + .flags = _flags, \ + .ops = &mtk_mux_gate_fenc_clr_set_upd_ops, \ + } + +#define MUX_GATE_FENC_CLR_SET_UPD(_id, _name, _parents, \ + _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ + _shift, _width, _gate, _upd_ofs, _upd, \ + _fenc_sta_mon_ofs, _fenc) \ + MUX_GATE_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ + NULL, ARRAY_SIZE(_parents), _mux_ofs, \ + _mux_set_ofs, _mux_clr_ofs, _shift, \ + _width, _gate, _upd_ofs, _upd, \ + _fenc_sta_mon_ofs, _fenc, 0) + +#define MUX_GATE_FENC_CLR_SET_UPD_INDEXED(_id, _name, _parents, _paridx, \ + _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ + _shift, _width, _gate, _upd_ofs, _upd, \ + _fenc_sta_mon_ofs, _fenc) \ + MUX_GATE_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, _paridx, \ + ARRAY_SIZE(_paridx), _mux_ofs, _mux_set_ofs, \ + _mux_clr_ofs, _shift, _width, _gate, _upd_ofs, _upd, \ + _fenc_sta_mon_ofs, _fenc, 0) + int mtk_clk_register_muxes(struct device *dev, const struct mtk_mux *muxes, int num, struct device_node *node, From 516edf79a5c6af2ce862e83a34c9d9d74770ac93 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:24 +0200 Subject: [PATCH 1838/2711] clk: mediatek: clk-mtk: Introduce mtk_clk_get_hwv_regmap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On MT8196, some clock controllers use a separate regmap for hardware voting via set/clear/status registers. Add mtk_clk_get_hwv_regmap() to retrieve this optional regmap, avoiding duplicated lookup code in  mtk_clk_register_muxes() and mtk_clk_register_gate(). Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mtk.c | 16 ++++++++++++++++ drivers/clk/mediatek/clk-mtk.h | 1 + 2 files changed, 17 insertions(+) diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index ba1d1c495bc2..19cd27941747 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -685,4 +685,20 @@ void mtk_clk_simple_remove(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(mtk_clk_simple_remove); +struct regmap *mtk_clk_get_hwv_regmap(struct device_node *node) +{ + struct device_node *hwv_node; + struct regmap *regmap_hwv; + + hwv_node = of_parse_phandle(node, "mediatek,hardware-voter", 0); + if (!hwv_node) + return NULL; + + regmap_hwv = device_node_to_regmap(hwv_node); + of_node_put(hwv_node); + + return regmap_hwv; +} +EXPORT_SYMBOL_GPL(mtk_clk_get_hwv_regmap); + MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index c17fe1c2d732..11962fac43ea 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -245,5 +245,6 @@ int mtk_clk_pdev_probe(struct platform_device *pdev); void mtk_clk_pdev_remove(struct platform_device *pdev); int mtk_clk_simple_probe(struct platform_device *pdev); void mtk_clk_simple_remove(struct platform_device *pdev); +struct regmap *mtk_clk_get_hwv_regmap(struct device_node *node); #endif /* __DRV_CLK_MTK_H */ From be89999259376eba724a52cc31560588bd5c95d8 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:25 +0200 Subject: [PATCH 1839/2711] clk: mediatek: clk-mux: Add ops for mux gates with HW voter and FENC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MT8196 use a HW voter for mux gate enable/disable control, along with a FENC status bit to check the status. Voting is performed using set/clr/upd registers, with a status bit used to verify the vote state. Add new set of mux gate clock operations with support for voting via set/clr/upd regs and FENC status logic. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mtk.h | 2 + drivers/clk/mediatek/clk-mux.c | 71 +++++++++++++++++++++++++++++++++- drivers/clk/mediatek/clk-mux.h | 42 ++++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 11962fac43ea..c381d6a6d908 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -20,6 +20,8 @@ #define MHZ (1000 * 1000) +#define MTK_WAIT_HWV_DONE_US 30 + struct platform_device; /* diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c index 5e12ef40511e..c5af6dc078a3 100644 --- a/drivers/clk/mediatek/clk-mux.c +++ b/drivers/clk/mediatek/clk-mux.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,7 @@ #include #include +#include "clk-mtk.h" #include "clk-mux.h" #define MTK_WAIT_FENC_DONE_US 30 @@ -22,6 +24,7 @@ struct mtk_clk_mux { struct clk_hw hw; struct regmap *regmap; + struct regmap *regmap_hwv; const struct mtk_mux *data; spinlock_t *lock; bool reparent; @@ -119,6 +122,41 @@ static int mtk_clk_mux_is_enabled(struct clk_hw *hw) return (val & BIT(mux->data->gate_shift)) == 0; } +static int mtk_clk_mux_hwv_fenc_enable(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 val; + int ret; + + regmap_write(mux->regmap_hwv, mux->data->hwv_set_ofs, + BIT(mux->data->gate_shift)); + + ret = regmap_read_poll_timeout_atomic(mux->regmap_hwv, mux->data->hwv_sta_ofs, + val, val & BIT(mux->data->gate_shift), 0, + MTK_WAIT_HWV_DONE_US); + if (ret) + return ret; + + ret = regmap_read_poll_timeout_atomic(mux->regmap, mux->data->fenc_sta_mon_ofs, + val, val & BIT(mux->data->fenc_shift), 1, + MTK_WAIT_FENC_DONE_US); + + return ret; +} + +static void mtk_clk_mux_hwv_disable(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 val; + + regmap_write(mux->regmap_hwv, mux->data->hwv_clr_ofs, + BIT(mux->data->gate_shift)); + + regmap_read_poll_timeout_atomic(mux->regmap_hwv, mux->data->hwv_sta_ofs, + val, (val & BIT(mux->data->gate_shift)), + 0, MTK_WAIT_HWV_DONE_US); +} + static u8 mtk_clk_mux_get_parent(struct clk_hw *hw) { struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); @@ -188,6 +226,14 @@ static int mtk_clk_mux_determine_rate(struct clk_hw *hw, return clk_mux_determine_rate_flags(hw, req, 0); } +static bool mtk_clk_mux_uses_hwv(const struct clk_ops *ops) +{ + if (ops == &mtk_mux_gate_hwv_fenc_clr_set_upd_ops) + return true; + + return false; +} + const struct clk_ops mtk_mux_clr_set_upd_ops = { .get_parent = mtk_clk_mux_get_parent, .set_parent = mtk_clk_mux_set_parent_setclr_lock, @@ -215,9 +261,20 @@ const struct clk_ops mtk_mux_gate_fenc_clr_set_upd_ops = { }; EXPORT_SYMBOL_GPL(mtk_mux_gate_fenc_clr_set_upd_ops); +const struct clk_ops mtk_mux_gate_hwv_fenc_clr_set_upd_ops = { + .enable = mtk_clk_mux_hwv_fenc_enable, + .disable = mtk_clk_mux_hwv_disable, + .is_enabled = mtk_clk_mux_fenc_is_enabled, + .get_parent = mtk_clk_mux_get_parent, + .set_parent = mtk_clk_mux_set_parent_setclr_lock, + .determine_rate = mtk_clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(mtk_mux_gate_hwv_fenc_clr_set_upd_ops); + static struct clk_hw *mtk_clk_register_mux(struct device *dev, const struct mtk_mux *mux, struct regmap *regmap, + struct regmap *regmap_hwv, spinlock_t *lock) { struct mtk_clk_mux *clk_mux; @@ -233,8 +290,13 @@ static struct clk_hw *mtk_clk_register_mux(struct device *dev, init.parent_names = mux->parent_names; init.num_parents = mux->num_parents; init.ops = mux->ops; + if (mtk_clk_mux_uses_hwv(init.ops) && !regmap_hwv) + return dev_err_ptr_probe( + dev, -ENXIO, + "regmap not found for hardware voter clocks\n"); clk_mux->regmap = regmap; + clk_mux->regmap_hwv = regmap_hwv; clk_mux->data = mux; clk_mux->lock = lock; clk_mux->hw.init = &init; @@ -267,6 +329,7 @@ int mtk_clk_register_muxes(struct device *dev, struct clk_hw_onecell_data *clk_data) { struct regmap *regmap; + struct regmap *regmap_hwv; struct clk_hw *hw; int i; @@ -276,6 +339,12 @@ int mtk_clk_register_muxes(struct device *dev, return PTR_ERR(regmap); } + regmap_hwv = mtk_clk_get_hwv_regmap(node); + if (IS_ERR(regmap_hwv)) + return dev_err_probe( + dev, PTR_ERR(regmap_hwv), + "Cannot find hardware voter regmap for %pOF\n", node); + for (i = 0; i < num; i++) { const struct mtk_mux *mux = &muxes[i]; @@ -285,7 +354,7 @@ int mtk_clk_register_muxes(struct device *dev, continue; } - hw = mtk_clk_register_mux(dev, mux, regmap, lock); + hw = mtk_clk_register_mux(dev, mux, regmap, regmap_hwv, lock); if (IS_ERR(hw)) { pr_err("Failed to register clk %s: %pe\n", mux->name, diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h index a4fd17a18532..151e56dcf884 100644 --- a/drivers/clk/mediatek/clk-mux.h +++ b/drivers/clk/mediatek/clk-mux.h @@ -28,6 +28,10 @@ struct mtk_mux { u32 set_ofs; u32 clr_ofs; u32 upd_ofs; + + u32 hwv_set_ofs; + u32 hwv_clr_ofs; + u32 hwv_sta_ofs; u32 fenc_sta_mon_ofs; u8 mux_shift; @@ -80,6 +84,7 @@ struct mtk_mux { extern const struct clk_ops mtk_mux_clr_set_upd_ops; extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops; extern const struct clk_ops mtk_mux_gate_fenc_clr_set_upd_ops; +extern const struct clk_ops mtk_mux_gate_hwv_fenc_clr_set_upd_ops; #define MUX_GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ @@ -121,6 +126,43 @@ extern const struct clk_ops mtk_mux_gate_fenc_clr_set_upd_ops; 0, _upd_ofs, _upd, CLK_SET_RATE_PARENT, \ mtk_mux_clr_set_upd_ops) +#define MUX_GATE_HWV_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ + _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ + _hwv_sta_ofs, _hwv_set_ofs, _hwv_clr_ofs, \ + _shift, _width, _gate, _upd_ofs, _upd, \ + _fenc_sta_mon_ofs, _fenc, _flags) { \ + .id = _id, \ + .name = _name, \ + .mux_ofs = _mux_ofs, \ + .set_ofs = _mux_set_ofs, \ + .clr_ofs = _mux_clr_ofs, \ + .hwv_sta_ofs = _hwv_sta_ofs, \ + .hwv_set_ofs = _hwv_set_ofs, \ + .hwv_clr_ofs = _hwv_clr_ofs, \ + .upd_ofs = _upd_ofs, \ + .fenc_sta_mon_ofs = _fenc_sta_mon_ofs, \ + .mux_shift = _shift, \ + .mux_width = _width, \ + .gate_shift = _gate, \ + .upd_shift = _upd, \ + .fenc_shift = _fenc, \ + .parent_names = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .flags = _flags, \ + .ops = &mtk_mux_gate_hwv_fenc_clr_set_upd_ops, \ + } + +#define MUX_GATE_HWV_FENC_CLR_SET_UPD(_id, _name, _parents, \ + _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ + _hwv_sta_ofs, _hwv_set_ofs, _hwv_clr_ofs, \ + _shift, _width, _gate, _upd_ofs, _upd, \ + _fenc_sta_mon_ofs, _fenc) \ + MUX_GATE_HWV_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ + _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ + _hwv_sta_ofs, _hwv_set_ofs, _hwv_clr_ofs, \ + _shift, _width, _gate, _upd_ofs, _upd, \ + _fenc_sta_mon_ofs, _fenc, 0) + #define MUX_GATE_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, _paridx, \ _num_parents, _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ _shift, _width, _gate, _upd_ofs, _upd, \ From 8ceff24a754ac065123ae0ec9f31ec03aff55f8a Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:26 +0200 Subject: [PATCH 1840/2711] clk: mediatek: clk-gate: Refactor mtk_clk_register_gate to use mtk_gate struct MT8196 uses a HW voter for gate enable/disable control, with set/clr/sta registers located in a separate regmap. Refactor mtk_clk_register_gate() to take a struct mtk_gate, and add a pointer to it in struct mtk_clk_gate. This allows reuse of the static gate data (including HW voter register offsets) without adding extra function arguments, and removes redundant duplication in the runtime data struct. Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-gate.c | 52 ++++++++++++--------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c index 67d9e741c5e7..816e5f2d4079 100644 --- a/drivers/clk/mediatek/clk-gate.c +++ b/drivers/clk/mediatek/clk-gate.c @@ -17,10 +17,7 @@ struct mtk_clk_gate { struct clk_hw hw; struct regmap *regmap; - int set_ofs; - int clr_ofs; - int sta_ofs; - u8 bit; + const struct mtk_gate *gate; }; static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw) @@ -33,9 +30,9 @@ static u32 mtk_get_clockgating(struct clk_hw *hw) struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); u32 val; - regmap_read(cg->regmap, cg->sta_ofs, &val); + regmap_read(cg->regmap, cg->gate->regs->sta_ofs, &val); - return val & BIT(cg->bit); + return val & BIT(cg->gate->shift); } static int mtk_cg_bit_is_cleared(struct clk_hw *hw) @@ -52,28 +49,30 @@ static void mtk_cg_set_bit(struct clk_hw *hw) { struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); - regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit)); + regmap_write(cg->regmap, cg->gate->regs->set_ofs, BIT(cg->gate->shift)); } static void mtk_cg_clr_bit(struct clk_hw *hw) { struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); - regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit)); + regmap_write(cg->regmap, cg->gate->regs->clr_ofs, BIT(cg->gate->shift)); } static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw) { struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); - regmap_set_bits(cg->regmap, cg->sta_ofs, BIT(cg->bit)); + regmap_set_bits(cg->regmap, cg->gate->regs->sta_ofs, + BIT(cg->gate->shift)); } static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw) { struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); - regmap_clear_bits(cg->regmap, cg->sta_ofs, BIT(cg->bit)); + regmap_clear_bits(cg->regmap, cg->gate->regs->sta_ofs, + BIT(cg->gate->shift)); } static int mtk_cg_enable(struct clk_hw *hw) @@ -152,12 +151,9 @@ const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = { }; EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv); -static struct clk_hw *mtk_clk_register_gate(struct device *dev, const char *name, - const char *parent_name, - struct regmap *regmap, int set_ofs, - int clr_ofs, int sta_ofs, u8 bit, - const struct clk_ops *ops, - unsigned long flags) +static struct clk_hw *mtk_clk_register_gate(struct device *dev, + const struct mtk_gate *gate, + struct regmap *regmap) { struct mtk_clk_gate *cg; int ret; @@ -167,18 +163,14 @@ static struct clk_hw *mtk_clk_register_gate(struct device *dev, const char *name if (!cg) return ERR_PTR(-ENOMEM); - init.name = name; - init.flags = flags | CLK_SET_RATE_PARENT; - init.parent_names = parent_name ? &parent_name : NULL; - init.num_parents = parent_name ? 1 : 0; - init.ops = ops; + init.name = gate->name; + init.flags = gate->flags | CLK_SET_RATE_PARENT; + init.parent_names = gate->parent_name ? &gate->parent_name : NULL; + init.num_parents = gate->parent_name ? 1 : 0; + init.ops = gate->ops; cg->regmap = regmap; - cg->set_ofs = set_ofs; - cg->clr_ofs = clr_ofs; - cg->sta_ofs = sta_ofs; - cg->bit = bit; - + cg->gate = gate; cg->hw.init = &init; ret = clk_hw_register(dev, &cg->hw); @@ -228,13 +220,7 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node, continue; } - hw = mtk_clk_register_gate(dev, gate->name, gate->parent_name, - regmap, - gate->regs->set_ofs, - gate->regs->clr_ofs, - gate->regs->sta_ofs, - gate->shift, gate->ops, - gate->flags); + hw = mtk_clk_register_gate(dev, gate, regmap); if (IS_ERR(hw)) { pr_err("Failed to register clk %s: %pe\n", gate->name, From e504d3bdb3d0bf581056f18ed12f7d2a59815cd1 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:27 +0200 Subject: [PATCH 1841/2711] clk: mediatek: clk-gate: Add ops for gates with HW voter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MT8196 use a HW voter for gate enable/disable control. Voting is performed using set/clr regs, with a status bit used to verify the vote state. Add new set of gate clock operations with support for voting via set/clr regs. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-gate.c | 71 +++++++++++++++++++++++++++++++-- drivers/clk/mediatek/clk-gate.h | 3 ++ 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c index 816e5f2d4079..f6b1429ff757 100644 --- a/drivers/clk/mediatek/clk-gate.c +++ b/drivers/clk/mediatek/clk-gate.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -12,11 +13,13 @@ #include #include +#include "clk-mtk.h" #include "clk-gate.h" struct mtk_clk_gate { struct clk_hw hw; struct regmap *regmap; + struct regmap *regmap_hwv; const struct mtk_gate *gate; }; @@ -99,6 +102,32 @@ static void mtk_cg_disable_inv(struct clk_hw *hw) mtk_cg_clr_bit(hw); } +static int mtk_cg_hwv_set_en(struct clk_hw *hw, bool enable) +{ + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); + u32 val; + + regmap_write(cg->regmap_hwv, + enable ? cg->gate->hwv_regs->set_ofs : + cg->gate->hwv_regs->clr_ofs, + BIT(cg->gate->shift)); + + return regmap_read_poll_timeout_atomic(cg->regmap_hwv, + cg->gate->hwv_regs->sta_ofs, val, + val & BIT(cg->gate->shift), 0, + MTK_WAIT_HWV_DONE_US); +} + +static int mtk_cg_hwv_enable(struct clk_hw *hw) +{ + return mtk_cg_hwv_set_en(hw, true); +} + +static void mtk_cg_hwv_disable(struct clk_hw *hw) +{ + mtk_cg_hwv_set_en(hw, false); +} + static int mtk_cg_enable_no_setclr(struct clk_hw *hw) { mtk_cg_clr_bit_no_setclr(hw); @@ -123,6 +152,15 @@ static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw) mtk_cg_clr_bit_no_setclr(hw); } +static bool mtk_cg_uses_hwv(const struct clk_ops *ops) +{ + if (ops == &mtk_clk_gate_hwv_ops_setclr || + ops == &mtk_clk_gate_hwv_ops_setclr_inv) + return true; + + return false; +} + const struct clk_ops mtk_clk_gate_ops_setclr = { .is_enabled = mtk_cg_bit_is_cleared, .enable = mtk_cg_enable, @@ -137,6 +175,20 @@ const struct clk_ops mtk_clk_gate_ops_setclr_inv = { }; EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr_inv); +const struct clk_ops mtk_clk_gate_hwv_ops_setclr = { + .is_enabled = mtk_cg_bit_is_cleared, + .enable = mtk_cg_hwv_enable, + .disable = mtk_cg_hwv_disable, +}; +EXPORT_SYMBOL_GPL(mtk_clk_gate_hwv_ops_setclr); + +const struct clk_ops mtk_clk_gate_hwv_ops_setclr_inv = { + .is_enabled = mtk_cg_bit_is_set, + .enable = mtk_cg_hwv_enable, + .disable = mtk_cg_hwv_disable, +}; +EXPORT_SYMBOL_GPL(mtk_clk_gate_hwv_ops_setclr_inv); + const struct clk_ops mtk_clk_gate_ops_no_setclr = { .is_enabled = mtk_cg_bit_is_cleared, .enable = mtk_cg_enable_no_setclr, @@ -152,8 +204,9 @@ const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = { EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv); static struct clk_hw *mtk_clk_register_gate(struct device *dev, - const struct mtk_gate *gate, - struct regmap *regmap) + const struct mtk_gate *gate, + struct regmap *regmap, + struct regmap *regmap_hwv) { struct mtk_clk_gate *cg; int ret; @@ -168,8 +221,13 @@ static struct clk_hw *mtk_clk_register_gate(struct device *dev, init.parent_names = gate->parent_name ? &gate->parent_name : NULL; init.num_parents = gate->parent_name ? 1 : 0; init.ops = gate->ops; + if (mtk_cg_uses_hwv(init.ops) && !regmap_hwv) + return dev_err_ptr_probe( + dev, -ENXIO, + "regmap not found for hardware voter clocks\n"); cg->regmap = regmap; + cg->regmap_hwv = regmap_hwv; cg->gate = gate; cg->hw.init = &init; @@ -201,6 +259,7 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node, int i; struct clk_hw *hw; struct regmap *regmap; + struct regmap *regmap_hwv; if (!clk_data) return -ENOMEM; @@ -211,6 +270,12 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node, return PTR_ERR(regmap); } + regmap_hwv = mtk_clk_get_hwv_regmap(node); + if (IS_ERR(regmap_hwv)) + return dev_err_probe( + dev, PTR_ERR(regmap_hwv), + "Cannot find hardware voter regmap for %pOF\n", node); + for (i = 0; i < num; i++) { const struct mtk_gate *gate = &clks[i]; @@ -220,7 +285,7 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node, continue; } - hw = mtk_clk_register_gate(dev, gate, regmap); + hw = mtk_clk_register_gate(dev, gate, regmap, regmap_hwv); if (IS_ERR(hw)) { pr_err("Failed to register clk %s: %pe\n", gate->name, diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h index 1a46b4c56fc5..4f05b9855dae 100644 --- a/drivers/clk/mediatek/clk-gate.h +++ b/drivers/clk/mediatek/clk-gate.h @@ -19,6 +19,8 @@ extern const struct clk_ops mtk_clk_gate_ops_setclr; extern const struct clk_ops mtk_clk_gate_ops_setclr_inv; extern const struct clk_ops mtk_clk_gate_ops_no_setclr; extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv; +extern const struct clk_ops mtk_clk_gate_hwv_ops_setclr; +extern const struct clk_ops mtk_clk_gate_hwv_ops_setclr_inv; struct mtk_gate_regs { u32 sta_ofs; @@ -31,6 +33,7 @@ struct mtk_gate { const char *name; const char *parent_name; const struct mtk_gate_regs *regs; + const struct mtk_gate_regs *hwv_regs; int shift; const struct clk_ops *ops; unsigned long flags; From a94737a6652bd9fe2db4161e2b81dce58505b4cc Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:28 +0200 Subject: [PATCH 1842/2711] clk: mediatek: clk-mtk: Add MUX_DIV_GATE macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On MT8196, some clocks use one register for parent selection and gating, and a separate register for frequency division. Since composite clocks can combine a mux, divider, and gate in a single entity, add a macro to simplify registration of such clocks by combining parent selection, frequency scaling, and enable control into one definition. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mtk.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index c381d6a6d908..5417b9264e6d 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -175,6 +175,25 @@ struct mtk_composite { .flags = 0, \ } +#define MUX_DIV_GATE(_id, _name, _parents, \ + _mux_reg, _mux_shift, _mux_width, \ + _div_reg, _div_shift, _div_width, \ + _gate_reg, _gate_shift) { \ + .id = _id, \ + .name = _name, \ + .parent_names = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .mux_reg = _mux_reg, \ + .mux_shift = _mux_shift, \ + .mux_width = _mux_width, \ + .divider_reg = _div_reg, \ + .divider_shift = _div_shift, \ + .divider_width = _div_width, \ + .gate_reg = _gate_reg, \ + .gate_shift = _gate_shift, \ + .flags = CLK_SET_RATE_PARENT, \ + } + int mtk_clk_register_composites(struct device *dev, const struct mtk_composite *mcs, int num, void __iomem *base, spinlock_t *lock, From dd240e95f1bee671f58148dea25e3be7cb39b50d Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:29 +0200 Subject: [PATCH 1843/2711] dt-bindings: clock: mediatek: Describe MT8196 clock controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce binding documentation for system clocks, functional clocks, and PEXTP0/1 and UFS reset controllers on MediaTek MT8196. This binding also includes a handle to the hardware voter, a fixed-function MCU designed to aggregate votes from the application processor and other remote processors to manage clocks and power domains. The HWV on MT8196/MT6991 is incomplete and requires software to manually enable power supplies, parent clocks, and FENC, as well as write to both the HWV MMIO and the controller registers. Because of these constraints, the HWV cannot be modeled using generic clock, power domain, or interconnect APIs. Instead, a custom phandle is exceptionally used to provide direct, syscon-like register access to drivers. Reviewed-by: Nícolas F. R. A. Prado Co-developed-by: AngeloGioacchino Del Regno Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Krzysztof Kozlowski Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- .../bindings/clock/mediatek,mt8196-clock.yaml | 112 +++ .../clock/mediatek,mt8196-sys-clock.yaml | 107 +++ .../dt-bindings/clock/mediatek,mt8196-clock.h | 803 ++++++++++++++++++ .../reset/mediatek,mt8196-resets.h | 26 + 4 files changed, 1048 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8196-clock.yaml create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8196-sys-clock.yaml create mode 100644 include/dt-bindings/clock/mediatek,mt8196-clock.h create mode 100644 include/dt-bindings/reset/mediatek,mt8196-resets.h diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8196-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8196-clock.yaml new file mode 100644 index 000000000000..bfdbd2e4a167 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8196-clock.yaml @@ -0,0 +1,112 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt8196-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Functional Clock Controller for MT8196 + +maintainers: + - Guangjie Song + - Laura Nao + +description: | + The clock architecture in MediaTek SoCs is structured like below: + PLLs --> + dividers --> + muxes + --> + clock gate + + The device nodes provide clock gate control in different IP blocks. + +properties: + compatible: + items: + - enum: + - mediatek,mt8196-imp-iic-wrap-c + - mediatek,mt8196-imp-iic-wrap-e + - mediatek,mt8196-imp-iic-wrap-n + - mediatek,mt8196-imp-iic-wrap-w + - mediatek,mt8196-mdpsys0 + - mediatek,mt8196-mdpsys1 + - mediatek,mt8196-pericfg-ao + - mediatek,mt8196-pextp0cfg-ao + - mediatek,mt8196-pextp1cfg-ao + - mediatek,mt8196-ufscfg-ao + - mediatek,mt8196-vencsys + - mediatek,mt8196-vencsys-c1 + - mediatek,mt8196-vencsys-c2 + - mediatek,mt8196-vdecsys + - mediatek,mt8196-vdecsys-soc + - mediatek,mt8196-vdisp-ao + - const: syscon + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + description: + Reset lines for PEXTP0/1 and UFS blocks. + + mediatek,hardware-voter: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + Phandle to the "Hardware Voter" (HWV), as named in the vendor + documentation for MT8196/MT6991. + + The HWV is a SoC-internal fixed-function MCU used to collect votes from + both the Application Processor and other remote processors within the SoC. + It is intended to transparently enable or disable hardware resources (such + as power domains or clocks) based on internal vote aggregation handled by + the MCU's internal state machine. + + However, in practice, this design is incomplete. While the HWV performs + some internal vote aggregation,software is still required to + - Manually enable power supplies externally, if present and if required + - Manually enable parent clocks via direct MMIO writes to clock controllers + - Enable the FENC after the clock has been ungated via direct MMIO + writes to clock controllers + + As such, the HWV behaves more like a hardware-managed clock reference + counter than a true voter. Furthermore, it is not a separate + controller. It merely serves as an alternative interface to the same + underlying clock or power controller. Actual control still requires + direct access to the controller's own MMIO register space, in + addition to writing to the HWV's MMIO region. + + For this reason, a custom phandle is used here - drivers need to directly + access the HWV MMIO region in a syscon-like fashion, due to how the + hardware is wired. This differs from true hardware voting systems, which + typically do not require custom phandles and rely instead on generic APIs + (clocks, power domains, interconnects). + + The name "hardware-voter" is retained to match vendor documentation, but + this should not be reused or misunderstood as a proper voting mechanism. + +required: + - compatible + - reg + - '#clock-cells' + +additionalProperties: false + +examples: + - | + pericfg_ao: clock-controller@16640000 { + compatible = "mediatek,mt8196-pericfg-ao", "syscon"; + reg = <0x16640000 0x1000>; + mediatek,hardware-voter = <&scp_hwv>; + #clock-cells = <1>; + }; + - | + pextp0cfg_ao: clock-controller@169b0000 { + compatible = "mediatek,mt8196-pextp0cfg-ao", "syscon"; + reg = <0x169b0000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8196-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8196-sys-clock.yaml new file mode 100644 index 000000000000..660ab64f390d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8196-sys-clock.yaml @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt8196-sys-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek System Clock Controller for MT8196 + +maintainers: + - Guangjie Song + - Laura Nao + +description: | + The clock architecture in MediaTek SoCs is structured like below: + PLLs --> + dividers --> + muxes + --> + clock gate + + The apmixedsys, apmixedsys_gp2, vlpckgen, armpll, ccipll, mfgpll and ptppll + provide most of the PLLs which are generated from the SoC's 26MHZ crystal oscillator. + The topckgen, topckgen_gp2 and vlpckgen provide dividers and muxes which + provide the clock source to other IP blocks. + +properties: + compatible: + items: + - enum: + - mediatek,mt8196-apmixedsys + - mediatek,mt8196-armpll-b-pll-ctrl + - mediatek,mt8196-armpll-bl-pll-ctrl + - mediatek,mt8196-armpll-ll-pll-ctrl + - mediatek,mt8196-apmixedsys-gp2 + - mediatek,mt8196-ccipll-pll-ctrl + - mediatek,mt8196-mfgpll-pll-ctrl + - mediatek,mt8196-mfgpll-sc0-pll-ctrl + - mediatek,mt8196-mfgpll-sc1-pll-ctrl + - mediatek,mt8196-ptppll-pll-ctrl + - mediatek,mt8196-topckgen + - mediatek,mt8196-topckgen-gp2 + - mediatek,mt8196-vlpckgen + - const: syscon + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + mediatek,hardware-voter: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + Phandle to the "Hardware Voter" (HWV), as named in the vendor + documentation for MT8196/MT6991. + + The HWV is a SoC-internal fixed-function MCU used to collect votes from + both the Application Processor and other remote processors within the SoC. + It is intended to transparently enable or disable hardware resources (such + as power domains or clocks) based on internal vote aggregation handled by + the MCU's internal state machine. + + However, in practice, this design is incomplete. While the HWV performs + some internal vote aggregation,software is still required to + - Manually enable power supplies externally, if present and if required + - Manually enable parent clocks via direct MMIO writes to clock controllers + - Enable the FENC after the clock has been ungated via direct MMIO + writes to clock controllers + + As such, the HWV behaves more like a hardware-managed clock reference + counter than a true voter. Furthermore, it is not a separate + controller. It merely serves as an alternative interface to the same + underlying clock or power controller. Actual control still requires + direct access to the controller's own MMIO register space, in + addition to writing to the HWV's MMIO region. + + For this reason, a custom phandle is used here - drivers need to directly + access the HWV MMIO region in a syscon-like fashion, due to how the + hardware is wired. This differs from true hardware voting systems, which + typically do not require custom phandles and rely instead on generic APIs + (clocks, power domains, interconnects). + + The name "hardware-voter" is retained to match vendor documentation, but + this should not be reused or misunderstood as a proper voting mechanism. + +required: + - compatible + - reg + - '#clock-cells' + +additionalProperties: false + +examples: + - | + apmixedsys_clk: syscon@10000800 { + compatible = "mediatek,mt8196-apmixedsys", "syscon"; + reg = <0x10000800 0x1000>; + #clock-cells = <1>; + }; + - | + topckgen: syscon@10000000 { + compatible = "mediatek,mt8196-topckgen", "syscon"; + reg = <0x10000000 0x800>; + mediatek,hardware-voter = <&scp_hwv>; + #clock-cells = <1>; + }; + diff --git a/include/dt-bindings/clock/mediatek,mt8196-clock.h b/include/dt-bindings/clock/mediatek,mt8196-clock.h new file mode 100644 index 000000000000..ae0946ab7621 --- /dev/null +++ b/include/dt-bindings/clock/mediatek,mt8196-clock.h @@ -0,0 +1,803 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ + +#ifndef _DT_BINDINGS_CLK_MT8196_H +#define _DT_BINDINGS_CLK_MT8196_H + +/* CKSYS */ +#define CLK_TOP_AXI 0 +#define CLK_TOP_MEM_SUB 1 +#define CLK_TOP_IO_NOC 2 +#define CLK_TOP_P_AXI 3 +#define CLK_TOP_UFS_PEXTP0_AXI 4 +#define CLK_TOP_PEXTP1_USB_AXI 5 +#define CLK_TOP_P_FMEM_SUB 6 +#define CLK_TOP_PEXPT0_MEM_SUB 7 +#define CLK_TOP_PEXTP1_USB_MEM_SUB 8 +#define CLK_TOP_P_NOC 9 +#define CLK_TOP_EMI_N 10 +#define CLK_TOP_EMI_S 11 +#define CLK_TOP_AP2CONN_HOST 12 +#define CLK_TOP_ATB 13 +#define CLK_TOP_CIRQ 14 +#define CLK_TOP_PBUS_156M 15 +#define CLK_TOP_EFUSE 16 +#define CLK_TOP_MCL3GIC 17 +#define CLK_TOP_MCINFRA 18 +#define CLK_TOP_DSP 19 +#define CLK_TOP_MFG_REF 20 +#define CLK_TOP_MFG_EB 21 +#define CLK_TOP_UART 22 +#define CLK_TOP_SPI0_BCLK 23 +#define CLK_TOP_SPI1_BCLK 24 +#define CLK_TOP_SPI2_BCLK 25 +#define CLK_TOP_SPI3_BCLK 26 +#define CLK_TOP_SPI4_BCLK 27 +#define CLK_TOP_SPI5_BCLK 28 +#define CLK_TOP_SPI6_BCLK 29 +#define CLK_TOP_SPI7_BCLK 30 +#define CLK_TOP_MSDC30_1 31 +#define CLK_TOP_MSDC30_2 32 +#define CLK_TOP_DISP_PWM 33 +#define CLK_TOP_USB_TOP_1P 34 +#define CLK_TOP_USB_XHCI_1P 35 +#define CLK_TOP_USB_FMCNT_P1 36 +#define CLK_TOP_I2C_P 37 +#define CLK_TOP_I2C_EAST 38 +#define CLK_TOP_I2C_WEST 39 +#define CLK_TOP_I2C_NORTH 40 +#define CLK_TOP_AES_UFSFDE 41 +#define CLK_TOP_UFS 42 +#define CLK_TOP_AUD_1 43 +#define CLK_TOP_AUD_2 44 +#define CLK_TOP_ADSP 45 +#define CLK_TOP_ADSP_UARTHUB_B 46 +#define CLK_TOP_DPMAIF_MAIN 47 +#define CLK_TOP_PWM 48 +#define CLK_TOP_MCUPM 49 +#define CLK_TOP_IPSEAST 50 +#define CLK_TOP_TL 51 +#define CLK_TOP_TL_P1 52 +#define CLK_TOP_TL_P2 53 +#define CLK_TOP_EMI_INTERFACE_546 54 +#define CLK_TOP_SDF 55 +#define CLK_TOP_UARTHUB_BCLK 56 +#define CLK_TOP_DPSW_CMP_26M 57 +#define CLK_TOP_SMAP 58 +#define CLK_TOP_SSR_PKA 59 +#define CLK_TOP_SSR_DMA 60 +#define CLK_TOP_SSR_KDF 61 +#define CLK_TOP_SSR_RNG 62 +#define CLK_TOP_SPU0 63 +#define CLK_TOP_SPU1 64 +#define CLK_TOP_DXCC 65 +#define CLK_TOP_APLL_I2SIN0 66 +#define CLK_TOP_APLL_I2SIN1 67 +#define CLK_TOP_APLL_I2SIN2 68 +#define CLK_TOP_APLL_I2SIN3 69 +#define CLK_TOP_APLL_I2SIN4 70 +#define CLK_TOP_APLL_I2SIN6 71 +#define CLK_TOP_APLL_I2SOUT0 72 +#define CLK_TOP_APLL_I2SOUT1 73 +#define CLK_TOP_APLL_I2SOUT2 74 +#define CLK_TOP_APLL_I2SOUT3 75 +#define CLK_TOP_APLL_I2SOUT4 76 +#define CLK_TOP_APLL_I2SOUT6 77 +#define CLK_TOP_APLL_FMI2S 78 +#define CLK_TOP_APLL_TDMOUT 79 +#define CLK_TOP_APLL12_DIV_TDMOUT_M 80 +#define CLK_TOP_APLL12_DIV_TDMOUT_B 81 +#define CLK_TOP_MAINPLL_D3 82 +#define CLK_TOP_MAINPLL_D4 83 +#define CLK_TOP_MAINPLL_D4_D2 84 +#define CLK_TOP_MAINPLL_D4_D4 85 +#define CLK_TOP_MAINPLL_D4_D8 86 +#define CLK_TOP_MAINPLL_D5 87 +#define CLK_TOP_MAINPLL_D5_D2 88 +#define CLK_TOP_MAINPLL_D5_D4 89 +#define CLK_TOP_MAINPLL_D5_D8 90 +#define CLK_TOP_MAINPLL_D6 91 +#define CLK_TOP_MAINPLL_D6_D2 92 +#define CLK_TOP_MAINPLL_D7 93 +#define CLK_TOP_MAINPLL_D7_D2 94 +#define CLK_TOP_MAINPLL_D7_D4 95 +#define CLK_TOP_MAINPLL_D7_D8 96 +#define CLK_TOP_MAINPLL_D9 97 +#define CLK_TOP_UNIVPLL_D4 98 +#define CLK_TOP_UNIVPLL_D4_D2 99 +#define CLK_TOP_UNIVPLL_D4_D4 100 +#define CLK_TOP_UNIVPLL_D4_D8 101 +#define CLK_TOP_UNIVPLL_D5 102 +#define CLK_TOP_UNIVPLL_D5_D2 103 +#define CLK_TOP_UNIVPLL_D5_D4 104 +#define CLK_TOP_UNIVPLL_D6 105 +#define CLK_TOP_UNIVPLL_D6_D2 106 +#define CLK_TOP_UNIVPLL_D6_D4 107 +#define CLK_TOP_UNIVPLL_D6_D8 108 +#define CLK_TOP_UNIVPLL_D6_D16 109 +#define CLK_TOP_UNIVPLL_192M 110 +#define CLK_TOP_UNIVPLL_192M_D4 111 +#define CLK_TOP_UNIVPLL_192M_D8 112 +#define CLK_TOP_UNIVPLL_192M_D16 113 +#define CLK_TOP_UNIVPLL_192M_D32 114 +#define CLK_TOP_UNIVPLL_192M_D10 115 +#define CLK_TOP_TVDPLL1_D2 116 +#define CLK_TOP_MSDCPLL_D2 117 +#define CLK_TOP_OSC_D2 118 +#define CLK_TOP_OSC_D3 119 +#define CLK_TOP_OSC_D4 120 +#define CLK_TOP_OSC_D5 121 +#define CLK_TOP_OSC_D7 122 +#define CLK_TOP_OSC_D8 123 +#define CLK_TOP_OSC_D10 124 +#define CLK_TOP_OSC_D14 125 +#define CLK_TOP_OSC_D20 126 +#define CLK_TOP_OSC_D32 127 +#define CLK_TOP_OSC_D40 128 +#define CLK_TOP_SFLASH 129 + +/* APMIXEDSYS */ +#define CLK_APMIXED_MAINPLL 0 +#define CLK_APMIXED_UNIVPLL 1 +#define CLK_APMIXED_MSDCPLL 2 +#define CLK_APMIXED_ADSPPLL 3 +#define CLK_APMIXED_EMIPLL 4 +#define CLK_APMIXED_EMIPLL2 5 +#define CLK_APMIXED_NET1PLL 6 +#define CLK_APMIXED_SGMIIPLL 7 + +/* CKSYS_GP2 */ +#define CLK_TOP2_SENINF0 0 +#define CLK_TOP2_SENINF1 1 +#define CLK_TOP2_SENINF2 2 +#define CLK_TOP2_SENINF3 3 +#define CLK_TOP2_SENINF4 4 +#define CLK_TOP2_SENINF5 5 +#define CLK_TOP2_IMG1 6 +#define CLK_TOP2_IPE 7 +#define CLK_TOP2_CAM 8 +#define CLK_TOP2_CAMTM 9 +#define CLK_TOP2_DPE 10 +#define CLK_TOP2_VDEC 11 +#define CLK_TOP2_CCUSYS 12 +#define CLK_TOP2_CCUTM 13 +#define CLK_TOP2_VENC 14 +#define CLK_TOP2_DP1 15 +#define CLK_TOP2_DP0 16 +#define CLK_TOP2_DISP 17 +#define CLK_TOP2_MDP 18 +#define CLK_TOP2_MMINFRA 19 +#define CLK_TOP2_MMINFRA_SNOC 20 +#define CLK_TOP2_MMUP 21 +#define CLK_TOP2_MMINFRA_AO 22 +#define CLK_TOP2_MAINPLL2_D2 23 +#define CLK_TOP2_MAINPLL2_D3 24 +#define CLK_TOP2_MAINPLL2_D4 25 +#define CLK_TOP2_MAINPLL2_D4_D2 26 +#define CLK_TOP2_MAINPLL2_D4_D4 27 +#define CLK_TOP2_MAINPLL2_D5 28 +#define CLK_TOP2_MAINPLL2_D5_D2 29 +#define CLK_TOP2_MAINPLL2_D6 30 +#define CLK_TOP2_MAINPLL2_D6_D2 31 +#define CLK_TOP2_MAINPLL2_D7 32 +#define CLK_TOP2_MAINPLL2_D7_D2 33 +#define CLK_TOP2_MAINPLL2_D9 34 +#define CLK_TOP2_UNIVPLL2_D3 35 +#define CLK_TOP2_UNIVPLL2_D4 36 +#define CLK_TOP2_UNIVPLL2_D4_D2 37 +#define CLK_TOP2_UNIVPLL2_D5 38 +#define CLK_TOP2_UNIVPLL2_D5_D2 39 +#define CLK_TOP2_UNIVPLL2_D6 40 +#define CLK_TOP2_UNIVPLL2_D6_D2 41 +#define CLK_TOP2_UNIVPLL2_D6_D4 42 +#define CLK_TOP2_UNIVPLL2_D7 43 +#define CLK_TOP2_IMGPLL_D2 44 +#define CLK_TOP2_IMGPLL_D4 45 +#define CLK_TOP2_IMGPLL_D5 46 +#define CLK_TOP2_IMGPLL_D5_D2 47 +#define CLK_TOP2_MMPLL2_D3 48 +#define CLK_TOP2_MMPLL2_D4 49 +#define CLK_TOP2_MMPLL2_D4_D2 50 +#define CLK_TOP2_MMPLL2_D5 51 +#define CLK_TOP2_MMPLL2_D5_D2 52 +#define CLK_TOP2_MMPLL2_D6 53 +#define CLK_TOP2_MMPLL2_D6_D2 54 +#define CLK_TOP2_MMPLL2_D7 55 +#define CLK_TOP2_MMPLL2_D9 56 +#define CLK_TOP2_TVDPLL1_D4 57 +#define CLK_TOP2_TVDPLL1_D8 58 +#define CLK_TOP2_TVDPLL1_D16 59 +#define CLK_TOP2_TVDPLL2_D2 60 +#define CLK_TOP2_TVDPLL2_D4 61 +#define CLK_TOP2_TVDPLL2_D8 62 +#define CLK_TOP2_TVDPLL2_D16 63 +#define CLK_TOP2_DVO 64 +#define CLK_TOP2_DVO_FAVT 65 +#define CLK_TOP2_TVDPLL3_D2 66 +#define CLK_TOP2_TVDPLL3_D4 67 +#define CLK_TOP2_TVDPLL3_D8 68 +#define CLK_TOP2_TVDPLL3_D16 69 + +/* APMIXEDSYS_GP2 */ +#define CLK_APMIXED2_MAINPLL2 0 +#define CLK_APMIXED2_UNIVPLL2 1 +#define CLK_APMIXED2_MMPLL2 2 +#define CLK_APMIXED2_IMGPLL 3 +#define CLK_APMIXED2_TVDPLL1 4 +#define CLK_APMIXED2_TVDPLL2 5 +#define CLK_APMIXED2_TVDPLL3 6 + +/* IMP_IIC_WRAP_E */ +#define CLK_IMPE_I2C5 0 + +/* IMP_IIC_WRAP_W */ +#define CLK_IMPW_I2C0 0 +#define CLK_IMPW_I2C3 1 +#define CLK_IMPW_I2C6 2 +#define CLK_IMPW_I2C10 3 + +/* IMP_IIC_WRAP_N */ +#define CLK_IMPN_I2C1 0 +#define CLK_IMPN_I2C2 1 +#define CLK_IMPN_I2C4 2 +#define CLK_IMPN_I2C7 3 +#define CLK_IMPN_I2C8 4 +#define CLK_IMPN_I2C9 5 + +/* IMP_IIC_WRAP_C */ +#define CLK_IMPC_I2C11 0 +#define CLK_IMPC_I2C12 1 +#define CLK_IMPC_I2C13 2 +#define CLK_IMPC_I2C14 3 + +/* PERICFG_AO */ +#define CLK_PERI_AO_UART0_BCLK 0 +#define CLK_PERI_AO_UART1_BCLK 1 +#define CLK_PERI_AO_UART2_BCLK 2 +#define CLK_PERI_AO_UART3_BCLK 3 +#define CLK_PERI_AO_UART4_BCLK 4 +#define CLK_PERI_AO_UART5_BCLK 5 +#define CLK_PERI_AO_PWM_X16W_HCLK 6 +#define CLK_PERI_AO_PWM_X16W_BCLK 7 +#define CLK_PERI_AO_PWM_PWM_BCLK0 8 +#define CLK_PERI_AO_PWM_PWM_BCLK1 9 +#define CLK_PERI_AO_PWM_PWM_BCLK2 10 +#define CLK_PERI_AO_PWM_PWM_BCLK3 11 +#define CLK_PERI_AO_SPI0_BCLK 12 +#define CLK_PERI_AO_SPI1_BCLK 13 +#define CLK_PERI_AO_SPI2_BCLK 14 +#define CLK_PERI_AO_SPI3_BCLK 15 +#define CLK_PERI_AO_SPI4_BCLK 16 +#define CLK_PERI_AO_SPI5_BCLK 17 +#define CLK_PERI_AO_SPI6_BCLK 18 +#define CLK_PERI_AO_SPI7_BCLK 19 +#define CLK_PERI_AO_AP_DMA_X32W_BCLK 20 +#define CLK_PERI_AO_MSDC1_MSDC_SRC 21 +#define CLK_PERI_AO_MSDC1_HCLK 22 +#define CLK_PERI_AO_MSDC1_AXI 23 +#define CLK_PERI_AO_MSDC1_HCLK_WRAP 24 +#define CLK_PERI_AO_MSDC2_MSDC_SRC 25 +#define CLK_PERI_AO_MSDC2_HCLK 26 +#define CLK_PERI_AO_MSDC2_AXI 27 +#define CLK_PERI_AO_MSDC2_HCLK_WRAP 28 +#define CLK_PERI_AO_FLASHIF_FLASH 29 +#define CLK_PERI_AO_FLASHIF_27M 30 +#define CLK_PERI_AO_FLASHIF_DRAM 31 +#define CLK_PERI_AO_FLASHIF_AXI 32 +#define CLK_PERI_AO_FLASHIF_BCLK 33 + +/* UFSCFG_AO */ +#define CLK_UFSAO_UNIPRO_TX_SYM 0 +#define CLK_UFSAO_UNIPRO_RX_SYM0 1 +#define CLK_UFSAO_UNIPRO_RX_SYM1 2 +#define CLK_UFSAO_UNIPRO_SYS 3 +#define CLK_UFSAO_UNIPRO_SAP 4 +#define CLK_UFSAO_PHY_SAP 5 +#define CLK_UFSAO_UFSHCI_UFS 6 +#define CLK_UFSAO_UFSHCI_AES 7 + +/* PEXTP0CFG_AO */ +#define CLK_PEXT_PEXTP_MAC_P0_TL 0 +#define CLK_PEXT_PEXTP_MAC_P0_REF 1 +#define CLK_PEXT_PEXTP_PHY_P0_MCU_BUS 2 +#define CLK_PEXT_PEXTP_PHY_P0_PEXTP_REF 3 +#define CLK_PEXT_PEXTP_MAC_P0_AXI_250 4 +#define CLK_PEXT_PEXTP_MAC_P0_AHB_APB 5 +#define CLK_PEXT_PEXTP_MAC_P0_PL_P 6 +#define CLK_PEXT_PEXTP_VLP_AO_P0_LP 7 + +/* PEXTP1CFG_AO */ +#define CLK_PEXT1_PEXTP_MAC_P1_TL 0 +#define CLK_PEXT1_PEXTP_MAC_P1_REF 1 +#define CLK_PEXT1_PEXTP_MAC_P2_TL 2 +#define CLK_PEXT1_PEXTP_MAC_P2_REF 3 +#define CLK_PEXT1_PEXTP_PHY_P1_MCU_BUS 4 +#define CLK_PEXT1_PEXTP_PHY_P1_PEXTP_REF 5 +#define CLK_PEXT1_PEXTP_PHY_P2_MCU_BUS 6 +#define CLK_PEXT1_PEXTP_PHY_P2_PEXTP_REF 7 +#define CLK_PEXT1_PEXTP_MAC_P1_AXI_250 8 +#define CLK_PEXT1_PEXTP_MAC_P1_AHB_APB 9 +#define CLK_PEXT1_PEXTP_MAC_P1_PL_P 10 +#define CLK_PEXT1_PEXTP_MAC_P2_AXI_250 11 +#define CLK_PEXT1_PEXTP_MAC_P2_AHB_APB 12 +#define CLK_PEXT1_PEXTP_MAC_P2_PL_P 13 +#define CLK_PEXT1_PEXTP_VLP_AO_P1_LP 14 +#define CLK_PEXT1_PEXTP_VLP_AO_P2_LP 15 + +/* VLP_CKSYS */ +#define CLK_VLP_APLL1 0 +#define CLK_VLP_APLL2 1 +#define CLK_VLP_SCP 2 +#define CLK_VLP_SCP_SPI 3 +#define CLK_VLP_SCP_IIC 4 +#define CLK_VLP_SCP_IIC_HS 5 +#define CLK_VLP_PWRAP_ULPOSC 6 +#define CLK_VLP_SPMI_M_TIA_32K 7 +#define CLK_VLP_APXGPT_26M_B 8 +#define CLK_VLP_DPSW 9 +#define CLK_VLP_DPSW_CENTRAL 10 +#define CLK_VLP_SPMI_M_MST 11 +#define CLK_VLP_DVFSRC 12 +#define CLK_VLP_PWM_VLP 13 +#define CLK_VLP_AXI_VLP 14 +#define CLK_VLP_SYSTIMER_26M 15 +#define CLK_VLP_SSPM 16 +#define CLK_VLP_SRCK 17 +#define CLK_VLP_CAMTG0 18 +#define CLK_VLP_CAMTG1 19 +#define CLK_VLP_CAMTG2 20 +#define CLK_VLP_CAMTG3 21 +#define CLK_VLP_CAMTG4 22 +#define CLK_VLP_CAMTG5 23 +#define CLK_VLP_CAMTG6 24 +#define CLK_VLP_CAMTG7 25 +#define CLK_VLP_SSPM_26M 26 +#define CLK_VLP_ULPOSC_SSPM 27 +#define CLK_VLP_VLP_PBUS_26M 28 +#define CLK_VLP_DEBUG_ERR_FLAG 29 +#define CLK_VLP_DPMSRDMA 30 +#define CLK_VLP_VLP_PBUS_156M 31 +#define CLK_VLP_SPM 32 +#define CLK_VLP_MMINFRA 33 +#define CLK_VLP_USB_TOP 34 +#define CLK_VLP_USB_XHCI 35 +#define CLK_VLP_NOC_VLP 36 +#define CLK_VLP_AUDIO_H 37 +#define CLK_VLP_AUD_ENGEN1 38 +#define CLK_VLP_AUD_ENGEN2 39 +#define CLK_VLP_AUD_INTBUS 40 +#define CLK_VLP_SPVLP_26M 41 +#define CLK_VLP_SPU0_VLP 42 +#define CLK_VLP_SPU1_VLP 43 +#define CLK_VLP_CLK26M 44 +#define CLK_VLP_APLL1_D4 45 +#define CLK_VLP_APLL1_D8 46 +#define CLK_VLP_APLL2_D4 47 +#define CLK_VLP_APLL2_D8 48 + +/* DISPSYS_CONFIG */ +#define CLK_MM_CONFIG 0 +#define CLK_MM_DISP_MUTEX0 1 +#define CLK_MM_DISP_AAL0 2 +#define CLK_MM_DISP_AAL1 3 +#define CLK_MM_DISP_C3D0 4 +#define CLK_MM_DISP_C3D1 5 +#define CLK_MM_DISP_C3D2 6 +#define CLK_MM_DISP_C3D3 7 +#define CLK_MM_DISP_CCORR0 8 +#define CLK_MM_DISP_CCORR1 9 +#define CLK_MM_DISP_CCORR2 10 +#define CLK_MM_DISP_CCORR3 11 +#define CLK_MM_DISP_CHIST0 12 +#define CLK_MM_DISP_CHIST1 13 +#define CLK_MM_DISP_COLOR0 14 +#define CLK_MM_DISP_COLOR1 15 +#define CLK_MM_DISP_DITHER0 16 +#define CLK_MM_DISP_DITHER1 17 +#define CLK_MM_DISP_DLI_ASYNC0 18 +#define CLK_MM_DISP_DLI_ASYNC1 19 +#define CLK_MM_DISP_DLI_ASYNC2 20 +#define CLK_MM_DISP_DLI_ASYNC3 21 +#define CLK_MM_DISP_DLI_ASYNC4 22 +#define CLK_MM_DISP_DLI_ASYNC5 23 +#define CLK_MM_DISP_DLI_ASYNC6 24 +#define CLK_MM_DISP_DLI_ASYNC7 25 +#define CLK_MM_DISP_DLI_ASYNC8 26 +#define CLK_MM_DISP_DLI_ASYNC9 27 +#define CLK_MM_DISP_DLI_ASYNC10 28 +#define CLK_MM_DISP_DLI_ASYNC11 29 +#define CLK_MM_DISP_DLI_ASYNC12 30 +#define CLK_MM_DISP_DLI_ASYNC13 31 +#define CLK_MM_DISP_DLI_ASYNC14 32 +#define CLK_MM_DISP_DLI_ASYNC15 33 +#define CLK_MM_DISP_DLO_ASYNC0 34 +#define CLK_MM_DISP_DLO_ASYNC1 35 +#define CLK_MM_DISP_DLO_ASYNC2 36 +#define CLK_MM_DISP_DLO_ASYNC3 37 +#define CLK_MM_DISP_DLO_ASYNC4 38 +#define CLK_MM_DISP_DLO_ASYNC5 39 +#define CLK_MM_DISP_DLO_ASYNC6 40 +#define CLK_MM_DISP_DLO_ASYNC7 41 +#define CLK_MM_DISP_DLO_ASYNC8 42 +#define CLK_MM_DISP_GAMMA0 43 +#define CLK_MM_DISP_GAMMA1 44 +#define CLK_MM_MDP_AAL0 45 +#define CLK_MM_MDP_AAL1 46 +#define CLK_MM_MDP_RDMA0 47 +#define CLK_MM_DISP_POSTMASK0 48 +#define CLK_MM_DISP_POSTMASK1 49 +#define CLK_MM_MDP_RSZ0 50 +#define CLK_MM_MDP_RSZ1 51 +#define CLK_MM_DISP_SPR0 52 +#define CLK_MM_DISP_TDSHP0 53 +#define CLK_MM_DISP_TDSHP1 54 +#define CLK_MM_DISP_WDMA0 55 +#define CLK_MM_DISP_Y2R0 56 +#define CLK_MM_SMI_SUB_COMM0 57 +#define CLK_MM_DISP_FAKE_ENG0 58 + +/* DISPSYS1_CONFIG */ +#define CLK_MM1_DISPSYS1_CONFIG 0 +#define CLK_MM1_DISPSYS1_S_CONFIG 1 +#define CLK_MM1_DISP_MUTEX0 2 +#define CLK_MM1_DISP_DLI_ASYNC20 3 +#define CLK_MM1_DISP_DLI_ASYNC21 4 +#define CLK_MM1_DISP_DLI_ASYNC22 5 +#define CLK_MM1_DISP_DLI_ASYNC23 6 +#define CLK_MM1_DISP_DLI_ASYNC24 7 +#define CLK_MM1_DISP_DLI_ASYNC25 8 +#define CLK_MM1_DISP_DLI_ASYNC26 9 +#define CLK_MM1_DISP_DLI_ASYNC27 10 +#define CLK_MM1_DISP_DLI_ASYNC28 11 +#define CLK_MM1_DISP_RELAY0 12 +#define CLK_MM1_DISP_RELAY1 13 +#define CLK_MM1_DISP_RELAY2 14 +#define CLK_MM1_DISP_RELAY3 15 +#define CLK_MM1_DISP_DP_INTF0 16 +#define CLK_MM1_DISP_DP_INTF1 17 +#define CLK_MM1_DISP_DSC_WRAP0 18 +#define CLK_MM1_DISP_DSC_WRAP1 19 +#define CLK_MM1_DISP_DSC_WRAP2 20 +#define CLK_MM1_DISP_DSC_WRAP3 21 +#define CLK_MM1_DISP_DSI0 22 +#define CLK_MM1_DISP_DSI1 23 +#define CLK_MM1_DISP_DSI2 24 +#define CLK_MM1_DISP_DVO0 25 +#define CLK_MM1_DISP_GDMA0 26 +#define CLK_MM1_DISP_MERGE0 27 +#define CLK_MM1_DISP_MERGE1 28 +#define CLK_MM1_DISP_MERGE2 29 +#define CLK_MM1_DISP_ODDMR0 30 +#define CLK_MM1_DISP_POSTALIGN0 31 +#define CLK_MM1_DISP_DITHER2 32 +#define CLK_MM1_DISP_R2Y0 33 +#define CLK_MM1_DISP_SPLITTER0 34 +#define CLK_MM1_DISP_SPLITTER1 35 +#define CLK_MM1_DISP_SPLITTER2 36 +#define CLK_MM1_DISP_SPLITTER3 37 +#define CLK_MM1_DISP_VDCM0 38 +#define CLK_MM1_DISP_WDMA1 39 +#define CLK_MM1_DISP_WDMA2 40 +#define CLK_MM1_DISP_WDMA3 41 +#define CLK_MM1_DISP_WDMA4 42 +#define CLK_MM1_MDP_RDMA1 43 +#define CLK_MM1_SMI_LARB0 44 +#define CLK_MM1_MOD1 45 +#define CLK_MM1_MOD2 46 +#define CLK_MM1_MOD3 47 +#define CLK_MM1_MOD4 48 +#define CLK_MM1_MOD5 49 +#define CLK_MM1_MOD6 50 +#define CLK_MM1_CG0 51 +#define CLK_MM1_CG1 52 +#define CLK_MM1_CG2 53 +#define CLK_MM1_CG3 54 +#define CLK_MM1_CG4 55 +#define CLK_MM1_CG5 56 +#define CLK_MM1_CG6 57 +#define CLK_MM1_CG7 58 +#define CLK_MM1_F26M 59 + +/* OVLSYS_CONFIG */ +#define CLK_OVLSYS_CONFIG 0 +#define CLK_OVL_FAKE_ENG0 1 +#define CLK_OVL_FAKE_ENG1 2 +#define CLK_OVL_MUTEX0 3 +#define CLK_OVL_EXDMA0 4 +#define CLK_OVL_EXDMA1 5 +#define CLK_OVL_EXDMA2 6 +#define CLK_OVL_EXDMA3 7 +#define CLK_OVL_EXDMA4 8 +#define CLK_OVL_EXDMA5 9 +#define CLK_OVL_EXDMA6 10 +#define CLK_OVL_EXDMA7 11 +#define CLK_OVL_EXDMA8 12 +#define CLK_OVL_EXDMA9 13 +#define CLK_OVL_BLENDER0 14 +#define CLK_OVL_BLENDER1 15 +#define CLK_OVL_BLENDER2 16 +#define CLK_OVL_BLENDER3 17 +#define CLK_OVL_BLENDER4 18 +#define CLK_OVL_BLENDER5 19 +#define CLK_OVL_BLENDER6 20 +#define CLK_OVL_BLENDER7 21 +#define CLK_OVL_BLENDER8 22 +#define CLK_OVL_BLENDER9 23 +#define CLK_OVL_OUTPROC0 24 +#define CLK_OVL_OUTPROC1 25 +#define CLK_OVL_OUTPROC2 26 +#define CLK_OVL_OUTPROC3 27 +#define CLK_OVL_OUTPROC4 28 +#define CLK_OVL_OUTPROC5 29 +#define CLK_OVL_MDP_RSZ0 30 +#define CLK_OVL_MDP_RSZ1 31 +#define CLK_OVL_DISP_WDMA0 32 +#define CLK_OVL_DISP_WDMA1 33 +#define CLK_OVL_UFBC_WDMA0 34 +#define CLK_OVL_MDP_RDMA0 35 +#define CLK_OVL_MDP_RDMA1 36 +#define CLK_OVL_BWM0 37 +#define CLK_OVL_DLI0 38 +#define CLK_OVL_DLI1 39 +#define CLK_OVL_DLI2 40 +#define CLK_OVL_DLI3 41 +#define CLK_OVL_DLI4 42 +#define CLK_OVL_DLI5 43 +#define CLK_OVL_DLI6 44 +#define CLK_OVL_DLI7 45 +#define CLK_OVL_DLI8 46 +#define CLK_OVL_DLO0 47 +#define CLK_OVL_DLO1 48 +#define CLK_OVL_DLO2 49 +#define CLK_OVL_DLO3 50 +#define CLK_OVL_DLO4 51 +#define CLK_OVL_DLO5 52 +#define CLK_OVL_DLO6 53 +#define CLK_OVL_DLO7 54 +#define CLK_OVL_DLO8 55 +#define CLK_OVL_DLO9 56 +#define CLK_OVL_DLO10 57 +#define CLK_OVL_DLO11 58 +#define CLK_OVL_DLO12 59 +#define CLK_OVLSYS_RELAY0 60 +#define CLK_OVL_INLINEROT0 61 +#define CLK_OVL_SMI 62 +#define CLK_OVL_SMI_SMI 63 + + +/* OVLSYS1_CONFIG */ +#define CLK_OVL1_OVLSYS_CONFIG 0 +#define CLK_OVL1_OVL_FAKE_ENG0 1 +#define CLK_OVL1_OVL_FAKE_ENG1 2 +#define CLK_OVL1_OVL_MUTEX0 3 +#define CLK_OVL1_OVL_EXDMA0 4 +#define CLK_OVL1_OVL_EXDMA1 5 +#define CLK_OVL1_OVL_EXDMA2 6 +#define CLK_OVL1_OVL_EXDMA3 7 +#define CLK_OVL1_OVL_EXDMA4 8 +#define CLK_OVL1_OVL_EXDMA5 9 +#define CLK_OVL1_OVL_EXDMA6 10 +#define CLK_OVL1_OVL_EXDMA7 11 +#define CLK_OVL1_OVL_EXDMA8 12 +#define CLK_OVL1_OVL_EXDMA9 13 +#define CLK_OVL1_OVL_BLENDER0 14 +#define CLK_OVL1_OVL_BLENDER1 15 +#define CLK_OVL1_OVL_BLENDER2 16 +#define CLK_OVL1_OVL_BLENDER3 17 +#define CLK_OVL1_OVL_BLENDER4 18 +#define CLK_OVL1_OVL_BLENDER5 19 +#define CLK_OVL1_OVL_BLENDER6 20 +#define CLK_OVL1_OVL_BLENDER7 21 +#define CLK_OVL1_OVL_BLENDER8 22 +#define CLK_OVL1_OVL_BLENDER9 23 +#define CLK_OVL1_OVL_OUTPROC0 24 +#define CLK_OVL1_OVL_OUTPROC1 25 +#define CLK_OVL1_OVL_OUTPROC2 26 +#define CLK_OVL1_OVL_OUTPROC3 27 +#define CLK_OVL1_OVL_OUTPROC4 28 +#define CLK_OVL1_OVL_OUTPROC5 29 +#define CLK_OVL1_OVL_MDP_RSZ0 30 +#define CLK_OVL1_OVL_MDP_RSZ1 31 +#define CLK_OVL1_OVL_DISP_WDMA0 32 +#define CLK_OVL1_OVL_DISP_WDMA1 33 +#define CLK_OVL1_OVL_UFBC_WDMA0 34 +#define CLK_OVL1_OVL_MDP_RDMA0 35 +#define CLK_OVL1_OVL_MDP_RDMA1 36 +#define CLK_OVL1_OVL_BWM0 37 +#define CLK_OVL1_DLI0 38 +#define CLK_OVL1_DLI1 39 +#define CLK_OVL1_DLI2 40 +#define CLK_OVL1_DLI3 41 +#define CLK_OVL1_DLI4 42 +#define CLK_OVL1_DLI5 43 +#define CLK_OVL1_DLI6 44 +#define CLK_OVL1_DLI7 45 +#define CLK_OVL1_DLI8 46 +#define CLK_OVL1_DLO0 47 +#define CLK_OVL1_DLO1 48 +#define CLK_OVL1_DLO2 49 +#define CLK_OVL1_DLO3 50 +#define CLK_OVL1_DLO4 51 +#define CLK_OVL1_DLO5 52 +#define CLK_OVL1_DLO6 53 +#define CLK_OVL1_DLO7 54 +#define CLK_OVL1_DLO8 55 +#define CLK_OVL1_DLO9 56 +#define CLK_OVL1_DLO10 57 +#define CLK_OVL1_DLO11 58 +#define CLK_OVL1_DLO12 59 +#define CLK_OVL1_OVLSYS_RELAY0 60 +#define CLK_OVL1_OVL_INLINEROT0 61 +#define CLK_OVL1_SMI 62 + + +/* VDEC_SOC_GCON_BASE */ +#define CLK_VDE1_LARB1_CKEN 0 +#define CLK_VDE1_LAT_CKEN 1 +#define CLK_VDE1_LAT_ACTIVE 2 +#define CLK_VDE1_LAT_CKEN_ENG 3 +#define CLK_VDE1_VDEC_CKEN 4 +#define CLK_VDE1_VDEC_ACTIVE 5 +#define CLK_VDE1_VDEC_CKEN_ENG 6 +#define CLK_VDE1_VDEC_SOC_APTV_EN 7 +#define CLK_VDE1_VDEC_SOC_APTV_TOP_EN 8 +#define CLK_VDE1_VDEC_SOC_IPS_EN 9 + +/* VDEC_GCON_BASE */ +#define CLK_VDE2_LARB1_CKEN 0 +#define CLK_VDE2_LAT_CKEN 1 +#define CLK_VDE2_LAT_ACTIVE 2 +#define CLK_VDE2_LAT_CKEN_ENG 3 +#define CLK_VDE2_VDEC_CKEN 4 +#define CLK_VDE2_VDEC_ACTIVE 5 +#define CLK_VDE2_VDEC_CKEN_ENG 6 + +/* VENC_GCON */ +#define CLK_VEN1_CKE0_LARB 0 +#define CLK_VEN1_CKE1_VENC 1 +#define CLK_VEN1_CKE2_JPGENC 2 +#define CLK_VEN1_CKE3_JPGDEC 3 +#define CLK_VEN1_CKE4_JPGDEC_C1 4 +#define CLK_VEN1_CKE5_GALS 5 +#define CLK_VEN1_CKE29_VENC_ADAB_CTRL 6 +#define CLK_VEN1_CKE29_VENC_XPC_CTRL 7 +#define CLK_VEN1_CKE6_GALS_SRAM 8 +#define CLK_VEN1_RES_FLAT 9 + +/* VENC_GCON_CORE1 */ +#define CLK_VEN2_CKE0_LARB 0 +#define CLK_VEN2_CKE1_VENC 1 +#define CLK_VEN2_CKE2_JPGENC 2 +#define CLK_VEN2_CKE3_JPGDEC 3 +#define CLK_VEN2_CKE5_GALS 4 +#define CLK_VEN2_CKE29_VENC_XPC_CTRL 5 +#define CLK_VEN2_CKE6_GALS_SRAM 6 +#define CLK_VEN2_RES_FLAT 7 + +/* VENC_GCON_CORE2 */ +#define CLK_VEN_C2_CKE0_LARB 0 +#define CLK_VEN_C2_CKE1_VENC 1 +#define CLK_VEN_C2_CKE5_GALS 2 +#define CLK_VEN_C2_CKE29_VENC_XPC_CTRL 3 +#define CLK_VEN_C2_CKE6_GALS_SRAM 4 +#define CLK_VEN_C2_RES_FLAT 5 + +/* MDPSYS_CONFIG */ +#define CLK_MDP_MDP_MUTEX0 0 +#define CLK_MDP_SMI0 1 +#define CLK_MDP_SMI0_SMI 2 +#define CLK_MDP_APB_BUS 3 +#define CLK_MDP_MDP_RDMA0 4 +#define CLK_MDP_MDP_RDMA1 5 +#define CLK_MDP_MDP_RDMA2 6 +#define CLK_MDP_MDP_BIRSZ0 7 +#define CLK_MDP_MDP_HDR0 8 +#define CLK_MDP_MDP_AAL0 9 +#define CLK_MDP_MDP_RSZ0 10 +#define CLK_MDP_MDP_RSZ2 11 +#define CLK_MDP_MDP_TDSHP0 12 +#define CLK_MDP_MDP_COLOR0 13 +#define CLK_MDP_MDP_WROT0 14 +#define CLK_MDP_MDP_WROT1 15 +#define CLK_MDP_MDP_WROT2 16 +#define CLK_MDP_MDP_FAKE_ENG0 17 +#define CLK_MDP_APB_DB 18 +#define CLK_MDP_MDP_DLI_ASYNC0 19 +#define CLK_MDP_MDP_DLI_ASYNC1 20 +#define CLK_MDP_MDP_DLO_ASYNC0 21 +#define CLK_MDP_MDP_DLO_ASYNC1 22 +#define CLK_MDP_MDP_DLI_ASYNC2 23 +#define CLK_MDP_MDP_DLO_ASYNC2 24 +#define CLK_MDP_MDP_DLO_ASYNC3 25 +#define CLK_MDP_IMG_DL_ASYNC0 26 +#define CLK_MDP_MDP_RROT0 27 +#define CLK_MDP_MDP_MERGE0 28 +#define CLK_MDP_MDP_C3D0 29 +#define CLK_MDP_MDP_FG0 30 +#define CLK_MDP_MDP_CLA2 31 +#define CLK_MDP_MDP_DLO_ASYNC4 32 +#define CLK_MDP_VPP_RSZ0 33 +#define CLK_MDP_VPP_RSZ1 34 +#define CLK_MDP_MDP_DLO_ASYNC5 35 +#define CLK_MDP_IMG0 36 +#define CLK_MDP_F26M 37 +#define CLK_MDP_IMG_DL_RELAY0 38 +#define CLK_MDP_IMG_DL_RELAY1 39 + +/* MDPSYS1_CONFIG */ +#define CLK_MDP1_MDP_MUTEX0 0 +#define CLK_MDP1_SMI0 1 +#define CLK_MDP1_SMI0_SMI 2 +#define CLK_MDP1_APB_BUS 3 +#define CLK_MDP1_MDP_RDMA0 4 +#define CLK_MDP1_MDP_RDMA1 5 +#define CLK_MDP1_MDP_RDMA2 6 +#define CLK_MDP1_MDP_BIRSZ0 7 +#define CLK_MDP1_MDP_HDR0 8 +#define CLK_MDP1_MDP_AAL0 9 +#define CLK_MDP1_MDP_RSZ0 10 +#define CLK_MDP1_MDP_RSZ2 11 +#define CLK_MDP1_MDP_TDSHP0 12 +#define CLK_MDP1_MDP_COLOR0 13 +#define CLK_MDP1_MDP_WROT0 14 +#define CLK_MDP1_MDP_WROT1 15 +#define CLK_MDP1_MDP_WROT2 16 +#define CLK_MDP1_MDP_FAKE_ENG0 17 +#define CLK_MDP1_APB_DB 18 +#define CLK_MDP1_MDP_DLI_ASYNC0 19 +#define CLK_MDP1_MDP_DLI_ASYNC1 20 +#define CLK_MDP1_MDP_DLO_ASYNC0 21 +#define CLK_MDP1_MDP_DLO_ASYNC1 22 +#define CLK_MDP1_MDP_DLI_ASYNC2 23 +#define CLK_MDP1_MDP_DLO_ASYNC2 24 +#define CLK_MDP1_MDP_DLO_ASYNC3 25 +#define CLK_MDP1_IMG_DL_ASYNC0 26 +#define CLK_MDP1_MDP_RROT0 27 +#define CLK_MDP1_MDP_MERGE0 28 +#define CLK_MDP1_MDP_C3D0 29 +#define CLK_MDP1_MDP_FG0 30 +#define CLK_MDP1_MDP_CLA2 31 +#define CLK_MDP1_MDP_DLO_ASYNC4 32 +#define CLK_MDP1_VPP_RSZ0 33 +#define CLK_MDP1_VPP_RSZ1 34 +#define CLK_MDP1_MDP_DLO_ASYNC5 35 +#define CLK_MDP1_IMG0 36 +#define CLK_MDP1_F26M 37 +#define CLK_MDP1_IMG_DL_RELAY0 38 +#define CLK_MDP1_IMG_DL_RELAY1 39 + +/* DISP_VDISP_AO_CONFIG */ +#define CLK_MM_V_DISP_VDISP_AO_CONFIG 0 +#define CLK_MM_V_DISP_DPC 1 +#define CLK_MM_V_SMI_SUB_SOMM0 2 + +/* MFGPLL_PLL_CTRL */ +#define CLK_MFG_AO_MFGPLL 0 + +/* MFGPLL_SC0_PLL_CTRL */ +#define CLK_MFGSC0_AO_MFGPLL_SC0 0 + +/* MFGPLL_SC1_PLL_CTRL */ +#define CLK_MFGSC1_AO_MFGPLL_SC1 0 + +/* CCIPLL_PLL_CTRL */ +#define CLK_CCIPLL 0 + +/* ARMPLL_LL_PLL_CTRL */ +#define CLK_CPLL_ARMPLL_LL 0 + +/* ARMPLL_BL_PLL_CTRL */ +#define CLK_CPBL_ARMPLL_BL 0 + +/* ARMPLL_B_PLL_CTRL */ +#define CLK_CPB_ARMPLL_B 0 + +/* PTPPLL_PLL_CTRL */ +#define CLK_PTPPLL 0 + +#endif /* _DT_BINDINGS_CLK_MT8196_H */ diff --git a/include/dt-bindings/reset/mediatek,mt8196-resets.h b/include/dt-bindings/reset/mediatek,mt8196-resets.h new file mode 100644 index 000000000000..46ced0850d91 --- /dev/null +++ b/include/dt-bindings/reset/mediatek,mt8196-resets.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2025 Collabora Ltd. + * Author: AngeloGioacchino Del Regno + */ + +#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8196 +#define _DT_BINDINGS_RESET_CONTROLLER_MT8196 + +/* PEXTP0 resets */ +#define MT8196_PEXTP0_RST0_PCIE0_MAC 0 +#define MT8196_PEXTP0_RST0_PCIE0_PHY 1 + +/* PEXTP1 resets */ +#define MT8196_PEXTP1_RST0_PCIE1_MAC 0 +#define MT8196_PEXTP1_RST0_PCIE1_PHY 1 +#define MT8196_PEXTP1_RST0_PCIE2_MAC 2 +#define MT8196_PEXTP1_RST0_PCIE2_PHY 3 + +/* UFS resets */ +#define MT8196_UFSAO_RST0_UFS_MPHY 0 +#define MT8196_UFSAO_RST1_UFS_UNIPRO 1 +#define MT8196_UFSAO_RST1_UFS_CRYPTO 2 +#define MT8196_UFSAO_RST1_UFSHCI 3 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8196 */ From d78485d63b79dd896301439e57e3dea45db0b575 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:30 +0200 Subject: [PATCH 1844/2711] clk: mediatek: Add MT8196 apmixedsys clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 apmixedsys clock controller, which provides PLLs generated from SoC 26m. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 8 + drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt8196-apmixedsys.c | 204 +++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8196-apmixedsys.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 5f8e6d68fa14..1e0c6f177ecd 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1002,6 +1002,14 @@ config COMMON_CLK_MT8195_VENCSYS help This driver supports MediaTek MT8195 vencsys clocks. +config COMMON_CLK_MT8196 + tristate "Clock driver for MediaTek MT8196" + depends on ARM64 || COMPILE_TEST + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK + help + This driver supports MediaTek MT8196 basic clocks. + config COMMON_CLK_MT8365 tristate "Clock driver for MediaTek MT8365" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 6efec95406bd..6144fdce3f9a 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -150,6 +150,7 @@ obj-$(CONFIG_COMMON_CLK_MT8195_VDOSYS) += clk-mt8195-vdo0.o clk-mt8195-vdo1.o obj-$(CONFIG_COMMON_CLK_MT8195_VENCSYS) += clk-mt8195-venc.o obj-$(CONFIG_COMMON_CLK_MT8195_VPPSYS) += clk-mt8195-vpp0.o clk-mt8195-vpp1.o obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o +obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o diff --git a/drivers/clk/mediatek/clk-mt8196-apmixedsys.c b/drivers/clk/mediatek/clk-mt8196-apmixedsys.c new file mode 100644 index 000000000000..617f5449b88b --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-apmixedsys.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-pll.h" + +/* APMIXEDSYS PLL control register offsets */ +#define MAINPLL_CON0 0x250 +#define MAINPLL_CON1 0x254 +#define UNIVPLL_CON0 0x264 +#define UNIVPLL_CON1 0x268 +#define MSDCPLL_CON0 0x278 +#define MSDCPLL_CON1 0x27c +#define ADSPPLL_CON0 0x28c +#define ADSPPLL_CON1 0x290 +#define EMIPLL_CON0 0x2a0 +#define EMIPLL_CON1 0x2a4 +#define EMIPLL2_CON0 0x2b4 +#define EMIPLL2_CON1 0x2b8 +#define NET1PLL_CON0 0x2c8 +#define NET1PLL_CON1 0x2cc +#define SGMIIPLL_CON0 0x2dc +#define SGMIIPLL_CON1 0x2e0 + +/* APMIXEDSYS_GP2 PLL control register offsets*/ +#define MAINPLL2_CON0 0x250 +#define MAINPLL2_CON1 0x254 +#define UNIVPLL2_CON0 0x264 +#define UNIVPLL2_CON1 0x268 +#define MMPLL2_CON0 0x278 +#define MMPLL2_CON1 0x27c +#define IMGPLL_CON0 0x28c +#define IMGPLL_CON1 0x290 +#define TVDPLL1_CON0 0x2a0 +#define TVDPLL1_CON1 0x2a4 +#define TVDPLL2_CON0 0x2b4 +#define TVDPLL2_CON1 0x2b8 +#define TVDPLL3_CON0 0x2c8 +#define TVDPLL3_CON1 0x2cc + +#define PLLEN_ALL 0x080 +#define PLLEN_ALL_SET 0x084 +#define PLLEN_ALL_CLR 0x088 + +#define FENC_STATUS_CON0 0x03c + +#define MT8196_PLL_FMAX (3800UL * MHZ) +#define MT8196_PLL_FMIN (1500UL * MHZ) +#define MT8196_INTEGER_BITS 8 + +#define PLL_FENC(_id, _name, _reg, _fenc_sta_ofs, _fenc_sta_bit,\ + _flags, _pd_reg, _pd_shift, \ + _pcw_reg, _pcw_shift, _pcwbits, \ + _pll_en_bit) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .fenc_sta_ofs = _fenc_sta_ofs, \ + .fenc_sta_bit = _fenc_sta_bit, \ + .flags = _flags, \ + .fmax = MT8196_PLL_FMAX, \ + .fmin = MT8196_PLL_FMIN, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .pcwbits = _pcwbits, \ + .pcwibits = MT8196_INTEGER_BITS, \ + .en_reg = PLLEN_ALL, \ + .en_set_reg = PLLEN_ALL_SET, \ + .en_clr_reg = PLLEN_ALL_CLR, \ + .pll_en_bit = _pll_en_bit, \ + .ops = &mtk_pll_fenc_clr_set_ops, \ +} + +struct mtk_pll_desc { + const struct mtk_pll_data *clks; + size_t num_clks; +}; + +static const struct mtk_pll_data apmixed_plls[] = { + PLL_FENC(CLK_APMIXED_MAINPLL, "mainpll", MAINPLL_CON0, FENC_STATUS_CON0, + 7, PLL_AO, MAINPLL_CON1, 24, MAINPLL_CON1, 0, 22, 0), + PLL_FENC(CLK_APMIXED_UNIVPLL, "univpll", UNIVPLL_CON0, FENC_STATUS_CON0, + 6, 0, UNIVPLL_CON1, 24, UNIVPLL_CON1, 0, 22, 1), + PLL_FENC(CLK_APMIXED_MSDCPLL, "msdcpll", MSDCPLL_CON0, FENC_STATUS_CON0, + 5, 0, MSDCPLL_CON1, 24, MSDCPLL_CON1, 0, 22, 2), + PLL_FENC(CLK_APMIXED_ADSPPLL, "adsppll", ADSPPLL_CON0, FENC_STATUS_CON0, + 4, 0, ADSPPLL_CON1, 24, ADSPPLL_CON1, 0, 22, 3), + PLL_FENC(CLK_APMIXED_EMIPLL, "emipll", EMIPLL_CON0, FENC_STATUS_CON0, 3, + PLL_AO, EMIPLL_CON1, 24, EMIPLL_CON1, 0, 22, 4), + PLL_FENC(CLK_APMIXED_EMIPLL2, "emipll2", EMIPLL2_CON0, FENC_STATUS_CON0, + 2, PLL_AO, EMIPLL2_CON1, 24, EMIPLL2_CON1, 0, 22, 5), + PLL_FENC(CLK_APMIXED_NET1PLL, "net1pll", NET1PLL_CON0, FENC_STATUS_CON0, + 1, 0, NET1PLL_CON1, 24, NET1PLL_CON1, 0, 22, 6), + PLL_FENC(CLK_APMIXED_SGMIIPLL, "sgmiipll", SGMIIPLL_CON0, FENC_STATUS_CON0, + 0, 0, SGMIIPLL_CON1, 24, SGMIIPLL_CON1, 0, 22, 7), +}; + +static const struct mtk_pll_desc apmixed_desc = { + .clks = apmixed_plls, + .num_clks = ARRAY_SIZE(apmixed_plls), +}; + +static const struct mtk_pll_data apmixed2_plls[] = { + PLL_FENC(CLK_APMIXED2_MAINPLL2, "mainpll2", MAINPLL2_CON0, FENC_STATUS_CON0, + 6, 0, MAINPLL2_CON1, 24, MAINPLL2_CON1, 0, 22, 0), + PLL_FENC(CLK_APMIXED2_UNIVPLL2, "univpll2", UNIVPLL2_CON0, FENC_STATUS_CON0, + 5, 0, UNIVPLL2_CON1, 24, UNIVPLL2_CON1, 0, 22, 1), + PLL_FENC(CLK_APMIXED2_MMPLL2, "mmpll2", MMPLL2_CON0, FENC_STATUS_CON0, + 4, 0, MMPLL2_CON1, 24, MMPLL2_CON1, 0, 22, 2), + PLL_FENC(CLK_APMIXED2_IMGPLL, "imgpll", IMGPLL_CON0, FENC_STATUS_CON0, + 3, 0, IMGPLL_CON1, 24, IMGPLL_CON1, 0, 22, 3), + PLL_FENC(CLK_APMIXED2_TVDPLL1, "tvdpll1", TVDPLL1_CON0, FENC_STATUS_CON0, + 2, 0, TVDPLL1_CON1, 24, TVDPLL1_CON1, 0, 22, 4), + PLL_FENC(CLK_APMIXED2_TVDPLL2, "tvdpll2", TVDPLL2_CON0, FENC_STATUS_CON0, + 1, 0, TVDPLL2_CON1, 24, TVDPLL2_CON1, 0, 22, 5), + PLL_FENC(CLK_APMIXED2_TVDPLL3, "tvdpll3", TVDPLL3_CON0, FENC_STATUS_CON0, + 0, 0, TVDPLL3_CON1, 24, TVDPLL3_CON1, 0, 22, 6), +}; + +static const struct mtk_pll_desc apmixed2_desc = { + .clks = apmixed2_plls, + .num_clks = ARRAY_SIZE(apmixed2_plls), +}; + +static int clk_mt8196_apmixed_probe(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + const struct mtk_pll_desc *mcd; + int r; + + mcd = device_get_match_data(&pdev->dev); + if (!mcd) + return -EINVAL; + + clk_data = mtk_alloc_clk_data(mcd->num_clks); + if (!clk_data) + return -ENOMEM; + + r = mtk_clk_register_plls(node, mcd->clks, mcd->num_clks, clk_data); + if (r) + goto free_apmixed_data; + + r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (r) + goto unregister_plls; + + platform_set_drvdata(pdev, clk_data); + + return r; + +unregister_plls: + mtk_clk_unregister_plls(mcd->clks, mcd->num_clks, clk_data); +free_apmixed_data: + mtk_free_clk_data(clk_data); + return r; +} + +static void clk_mt8196_apmixed_remove(struct platform_device *pdev) +{ + const struct mtk_pll_desc *mcd = device_get_match_data(&pdev->dev); + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + + of_clk_del_provider(node); + mtk_clk_unregister_plls(mcd->clks, mcd->num_clks, clk_data); + mtk_free_clk_data(clk_data); +} + +static const struct of_device_id of_match_clk_mt8196_apmixed[] = { + { .compatible = "mediatek,mt8196-apmixedsys", .data = &apmixed_desc }, + { .compatible = "mediatek,mt8196-apmixedsys-gp2", + .data = &apmixed2_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_apmixed); + +static struct platform_driver clk_mt8196_apmixed_drv = { + .probe = clk_mt8196_apmixed_probe, + .remove = clk_mt8196_apmixed_remove, + .driver = { + .name = "clk-mt8196-apmixed", + .of_match_table = of_match_clk_mt8196_apmixed, + }, +}; +module_platform_driver(clk_mt8196_apmixed_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 apmixedsys clocks driver"); +MODULE_LICENSE("GPL"); From 895ab0134d64834b3f265a6cb5ed609c80876efb Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:31 +0200 Subject: [PATCH 1845/2711] clk: mediatek: Add MT8196 topckgen clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 topckgen clock controller, which provides muxes and dividers for clock selection in other IP blocks. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Makefile | 2 +- drivers/clk/mediatek/clk-mt8196-topckgen.c | 985 +++++++++++++++++++++ 2 files changed, 986 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mediatek/clk-mt8196-topckgen.c diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 6144fdce3f9a..ad61621b8c95 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -150,7 +150,7 @@ obj-$(CONFIG_COMMON_CLK_MT8195_VDOSYS) += clk-mt8195-vdo0.o clk-mt8195-vdo1.o obj-$(CONFIG_COMMON_CLK_MT8195_VENCSYS) += clk-mt8195-venc.o obj-$(CONFIG_COMMON_CLK_MT8195_VPPSYS) += clk-mt8195-vpp0.o clk-mt8195-vpp1.o obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o -obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o +obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o diff --git a/drivers/clk/mediatek/clk-mt8196-topckgen.c b/drivers/clk/mediatek/clk-mt8196-topckgen.c new file mode 100644 index 000000000000..6ace11ef6b69 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-topckgen.c @@ -0,0 +1,985 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-mux.h" + +/* MUX SEL REG */ +#define CLK_CFG_UPDATE 0x0004 +#define CLK_CFG_UPDATE1 0x0008 +#define CLK_CFG_UPDATE2 0x000c +#define CLK_CFG_0 0x0010 +#define CLK_CFG_0_SET 0x0014 +#define CLK_CFG_0_CLR 0x0018 +#define CLK_CFG_1 0x0020 +#define CLK_CFG_1_SET 0x0024 +#define CLK_CFG_1_CLR 0x0028 +#define CLK_CFG_2 0x0030 +#define CLK_CFG_2_SET 0x0034 +#define CLK_CFG_2_CLR 0x0038 +#define CLK_CFG_3 0x0040 +#define CLK_CFG_3_SET 0x0044 +#define CLK_CFG_3_CLR 0x0048 +#define CLK_CFG_4 0x0050 +#define CLK_CFG_4_SET 0x0054 +#define CLK_CFG_4_CLR 0x0058 +#define CLK_CFG_5 0x0060 +#define CLK_CFG_5_SET 0x0064 +#define CLK_CFG_5_CLR 0x0068 +#define CLK_CFG_6 0x0070 +#define CLK_CFG_6_SET 0x0074 +#define CLK_CFG_6_CLR 0x0078 +#define CLK_CFG_7 0x0080 +#define CLK_CFG_7_SET 0x0084 +#define CLK_CFG_7_CLR 0x0088 +#define CLK_CFG_8 0x0090 +#define CLK_CFG_8_SET 0x0094 +#define CLK_CFG_8_CLR 0x0098 +#define CLK_CFG_9 0x00a0 +#define CLK_CFG_9_SET 0x00a4 +#define CLK_CFG_9_CLR 0x00a8 +#define CLK_CFG_10 0x00b0 +#define CLK_CFG_10_SET 0x00b4 +#define CLK_CFG_10_CLR 0x00b8 +#define CLK_CFG_11 0x00c0 +#define CLK_CFG_11_SET 0x00c4 +#define CLK_CFG_11_CLR 0x00c8 +#define CLK_CFG_12 0x00d0 +#define CLK_CFG_12_SET 0x00d4 +#define CLK_CFG_12_CLR 0x00d8 +#define CLK_CFG_13 0x00e0 +#define CLK_CFG_13_SET 0x00e4 +#define CLK_CFG_13_CLR 0x00e8 +#define CLK_CFG_14 0x00f0 +#define CLK_CFG_14_SET 0x00f4 +#define CLK_CFG_14_CLR 0x00f8 +#define CLK_CFG_15 0x0100 +#define CLK_CFG_15_SET 0x0104 +#define CLK_CFG_15_CLR 0x0108 +#define CLK_CFG_16 0x0110 +#define CLK_CFG_16_SET 0x0114 +#define CLK_CFG_16_CLR 0x0118 +#define CLK_CFG_17 0x0120 +#define CLK_CFG_17_SET 0x0124 +#define CLK_CFG_17_CLR 0x0128 +#define CLK_CFG_18 0x0130 +#define CLK_CFG_18_SET 0x0134 +#define CLK_CFG_18_CLR 0x0138 +#define CLK_CFG_19 0x0140 +#define CLK_CFG_19_SET 0x0144 +#define CLK_CFG_19_CLR 0x0148 +#define CLK_AUDDIV_0 0x020c +#define CLK_FENC_STATUS_MON_0 0x0270 +#define CLK_FENC_STATUS_MON_1 0x0274 +#define CLK_FENC_STATUS_MON_2 0x0278 + +/* MUX SHIFT */ +#define TOP_MUX_AXI_SHIFT 0 +#define TOP_MUX_MEM_SUB_SHIFT 1 +#define TOP_MUX_IO_NOC_SHIFT 2 +#define TOP_MUX_PERI_AXI_SHIFT 3 +#define TOP_MUX_UFS_PEXTP0_AXI_SHIFT 4 +#define TOP_MUX_PEXTP1_USB_AXI_SHIFT 5 +#define TOP_MUX_PERI_FMEM_SUB_SHIFT 6 +#define TOP_MUX_UFS_PEXPT0_MEM_SUB_SHIFT 7 +#define TOP_MUX_PEXTP1_USB_MEM_SUB_SHIFT 8 +#define TOP_MUX_PERI_NOC_SHIFT 9 +#define TOP_MUX_EMI_N_SHIFT 10 +#define TOP_MUX_EMI_S_SHIFT 11 +#define TOP_MUX_AP2CONN_HOST_SHIFT 14 +#define TOP_MUX_ATB_SHIFT 15 +#define TOP_MUX_CIRQ_SHIFT 16 +#define TOP_MUX_PBUS_156M_SHIFT 17 +#define TOP_MUX_EFUSE_SHIFT 20 +#define TOP_MUX_MCU_L3GIC_SHIFT 21 +#define TOP_MUX_MCU_INFRA_SHIFT 22 +#define TOP_MUX_DSP_SHIFT 23 +#define TOP_MUX_MFG_REF_SHIFT 24 +#define TOP_MUX_MFG_EB_SHIFT 26 +#define TOP_MUX_UART_SHIFT 27 +#define TOP_MUX_SPI0_BCLK_SHIFT 28 +#define TOP_MUX_SPI1_BCLK_SHIFT 29 +#define TOP_MUX_SPI2_BCLK_SHIFT 30 +#define TOP_MUX_SPI3_BCLK_SHIFT 0 +#define TOP_MUX_SPI4_BCLK_SHIFT 1 +#define TOP_MUX_SPI5_BCLK_SHIFT 2 +#define TOP_MUX_SPI6_BCLK_SHIFT 3 +#define TOP_MUX_SPI7_BCLK_SHIFT 4 +#define TOP_MUX_MSDC30_1_SHIFT 7 +#define TOP_MUX_MSDC30_2_SHIFT 8 +#define TOP_MUX_DISP_PWM_SHIFT 9 +#define TOP_MUX_USB_TOP_1P_SHIFT 10 +#define TOP_MUX_SSUSB_XHCI_1P_SHIFT 11 +#define TOP_MUX_SSUSB_FMCNT_P1_SHIFT 12 +#define TOP_MUX_I2C_PERI_SHIFT 13 +#define TOP_MUX_I2C_EAST_SHIFT 14 +#define TOP_MUX_I2C_WEST_SHIFT 15 +#define TOP_MUX_I2C_NORTH_SHIFT 16 +#define TOP_MUX_AES_UFSFDE_SHIFT 17 +#define TOP_MUX_UFS_SHIFT 18 +#define TOP_MUX_AUD_1_SHIFT 21 +#define TOP_MUX_AUD_2_SHIFT 22 +#define TOP_MUX_ADSP_SHIFT 23 +#define TOP_MUX_ADSP_UARTHUB_B_SHIFT 24 +#define TOP_MUX_DPMAIF_MAIN_SHIFT 25 +#define TOP_MUX_PWM_SHIFT 26 +#define TOP_MUX_MCUPM_SHIFT 27 +#define TOP_MUX_SFLASH_SHIFT 28 +#define TOP_MUX_IPSEAST_SHIFT 29 +#define TOP_MUX_TL_SHIFT 0 +#define TOP_MUX_TL_P1_SHIFT 1 +#define TOP_MUX_TL_P2_SHIFT 2 +#define TOP_MUX_EMI_INTERFACE_546_SHIFT 3 +#define TOP_MUX_SDF_SHIFT 4 +#define TOP_MUX_UARTHUB_BCLK_SHIFT 5 +#define TOP_MUX_DPSW_CMP_26M_SHIFT 6 +#define TOP_MUX_SMAPCK_SHIFT 7 +#define TOP_MUX_SSR_PKA_SHIFT 8 +#define TOP_MUX_SSR_DMA_SHIFT 9 +#define TOP_MUX_SSR_KDF_SHIFT 10 +#define TOP_MUX_SSR_RNG_SHIFT 11 +#define TOP_MUX_SPU0_SHIFT 12 +#define TOP_MUX_SPU1_SHIFT 13 +#define TOP_MUX_DXCC_SHIFT 14 + +/* CKSTA REG */ +#define CKSTA_REG 0x01c8 +#define CKSTA_REG1 0x01cc +#define CKSTA_REG2 0x01d0 + +/* DIVIDER REG */ +#define CLK_AUDDIV_2 0x0214 +#define CLK_AUDDIV_3 0x0220 +#define CLK_AUDDIV_4 0x0224 +#define CLK_AUDDIV_5 0x0228 + +/* HW Voter REG */ +#define HWV_CG_0_SET 0x0000 +#define HWV_CG_0_CLR 0x0004 +#define HWV_CG_0_DONE 0x2c00 +#define HWV_CG_1_SET 0x0008 +#define HWV_CG_1_CLR 0x000c +#define HWV_CG_1_DONE 0x2c04 +#define HWV_CG_2_SET 0x0010 +#define HWV_CG_2_CLR 0x0014 +#define HWV_CG_2_DONE 0x2c08 +#define HWV_CG_3_SET 0x0018 +#define HWV_CG_3_CLR 0x001c +#define HWV_CG_3_DONE 0x2c0c +#define HWV_CG_4_SET 0x0020 +#define HWV_CG_4_CLR 0x0024 +#define HWV_CG_4_DONE 0x2c10 +#define HWV_CG_5_SET 0x0028 +#define HWV_CG_5_CLR 0x002c +#define HWV_CG_5_DONE 0x2c14 +#define HWV_CG_6_SET 0x0030 +#define HWV_CG_6_CLR 0x0034 +#define HWV_CG_6_DONE 0x2c18 +#define HWV_CG_7_SET 0x0038 +#define HWV_CG_7_CLR 0x003c +#define HWV_CG_7_DONE 0x2c1c +#define HWV_CG_8_SET 0x0040 +#define HWV_CG_8_CLR 0x0044 +#define HWV_CG_8_DONE 0x2c20 + +static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_TOP_MAINPLL_D3, "mainpll_d3", "mainpll", 1, 3), + FACTOR(CLK_TOP_MAINPLL_D4, "mainpll_d4", "mainpll", 1, 4), + FACTOR(CLK_TOP_MAINPLL_D4_D2, "mainpll_d4_d2", "mainpll", 1, 8), + FACTOR(CLK_TOP_MAINPLL_D4_D4, "mainpll_d4_d4", "mainpll", 1, 16), + FACTOR(CLK_TOP_MAINPLL_D4_D8, "mainpll_d4_d8", "mainpll", 1, 32), + FACTOR(CLK_TOP_MAINPLL_D5, "mainpll_d5", "mainpll", 1, 5), + FACTOR(CLK_TOP_MAINPLL_D5_D2, "mainpll_d5_d2", "mainpll", 1, 10), + FACTOR(CLK_TOP_MAINPLL_D5_D4, "mainpll_d5_d4", "mainpll", 1, 20), + FACTOR(CLK_TOP_MAINPLL_D5_D8, "mainpll_d5_d8", "mainpll", 1, 40), + FACTOR(CLK_TOP_MAINPLL_D6, "mainpll_d6", "mainpll", 1, 6), + FACTOR(CLK_TOP_MAINPLL_D6_D2, "mainpll_d6_d2", "mainpll", 1, 12), + FACTOR(CLK_TOP_MAINPLL_D7, "mainpll_d7", "mainpll", 1, 7), + FACTOR(CLK_TOP_MAINPLL_D7_D2, "mainpll_d7_d2", "mainpll", 1, 14), + FACTOR(CLK_TOP_MAINPLL_D7_D4, "mainpll_d7_d4", "mainpll", 1, 28), + FACTOR(CLK_TOP_MAINPLL_D7_D8, "mainpll_d7_d8", "mainpll", 1, 56), + FACTOR(CLK_TOP_MAINPLL_D9, "mainpll_d9", "mainpll", 1, 9), + FACTOR(CLK_TOP_UNIVPLL_D4, "univpll_d4", "univpll", 1, 4), + FACTOR(CLK_TOP_UNIVPLL_D4_D2, "univpll_d4_d2", "univpll", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_D4_D4, "univpll_d4_d4", "univpll", 1, 16), + FACTOR(CLK_TOP_UNIVPLL_D4_D8, "univpll_d4_d8", "univpll", 1, 32), + FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5), + FACTOR(CLK_TOP_UNIVPLL_D5_D2, "univpll_d5_d2", "univpll", 1, 10), + FACTOR(CLK_TOP_UNIVPLL_D5_D4, "univpll_d5_d4", "univpll", 1, 20), + FACTOR(CLK_TOP_UNIVPLL_D6, "univpll_d6", "univpll", 1, 6), + FACTOR(CLK_TOP_UNIVPLL_D6_D2, "univpll_d6_d2", "univpll", 1, 12), + FACTOR(CLK_TOP_UNIVPLL_D6_D4, "univpll_d6_d4", "univpll", 1, 24), + FACTOR(CLK_TOP_UNIVPLL_D6_D8, "univpll_d6_d8", "univpll", 1, 48), + FACTOR(CLK_TOP_UNIVPLL_D6_D16, "univpll_d6_d16", "univpll", 1, 96), + FACTOR(CLK_TOP_UNIVPLL_192M, "univpll_192m", "univpll", 1, 13), + FACTOR(CLK_TOP_UNIVPLL_192M_D4, "univpll_192m_d4", "univpll", 1, 52), + FACTOR(CLK_TOP_UNIVPLL_192M_D8, "univpll_192m_d8", "univpll", 1, 104), + FACTOR(CLK_TOP_UNIVPLL_192M_D16, "univpll_192m_d16", "univpll", 1, 208), + FACTOR(CLK_TOP_UNIVPLL_192M_D32, "univpll_192m_d32", "univpll", 1, 416), + FACTOR(CLK_TOP_UNIVPLL_192M_D10, "univpll_192m_d10", "univpll", 1, 130), + FACTOR(CLK_TOP_TVDPLL1_D2, "tvdpll1_d2", "tvdpll1", 1, 2), + FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2), + FACTOR(CLK_TOP_OSC_D2, "osc_d2", "ulposc", 1, 2), + FACTOR(CLK_TOP_OSC_D3, "osc_d3", "ulposc", 1, 3), + FACTOR(CLK_TOP_OSC_D4, "osc_d4", "ulposc", 1, 4), + FACTOR(CLK_TOP_OSC_D5, "osc_d5", "ulposc", 1, 5), + FACTOR(CLK_TOP_OSC_D7, "osc_d7", "ulposc", 1, 7), + FACTOR(CLK_TOP_OSC_D8, "osc_d8", "ulposc", 1, 8), + FACTOR(CLK_TOP_OSC_D10, "osc_d10", "ulposc", 1, 10), + FACTOR(CLK_TOP_OSC_D14, "osc_d14", "ulposc", 1, 14), + FACTOR(CLK_TOP_OSC_D20, "osc_d20", "ulposc", 1, 20), + FACTOR(CLK_TOP_OSC_D32, "osc_d32", "ulposc", 1, 32), + FACTOR(CLK_TOP_OSC_D40, "osc_d40", "ulposc", 1, 40), +}; + +static const char * const axi_parents[] = { + "clk26m", + "osc_d20", + "osc_d8", + "osc_d4", + "mainpll_d4_d4", + "mainpll_d7_d2" +}; + +static const char * const mem_sub_parents[] = { + "clk26m", + "osc_d20", + "osc_d4", + "univpll_d4_d4", + "osc_d3", + "mainpll_d5_d2", + "mainpll_d4_d2", + "mainpll_d6", + "mainpll_d5", + "univpll_d5", + "mainpll_d4", + "mainpll_d3" +}; + +static const char * const io_noc_parents[] = { + "clk26m", + "osc_d20", + "osc_d8", + "osc_d4", + "mainpll_d6_d2", + "mainpll_d9" +}; + +static const char * const shared_axi_parents[] = { + "clk26m", + "mainpll_d7_d8", + "mainpll_d5_d8", + "osc_d8", + "mainpll_d7_d4", + "mainpll_d5_d4", + "mainpll_d4_d4", + "mainpll_d7_d2" +}; + +static const char * const shared_sub_parents[] = { + "clk26m", + "mainpll_d5_d8", + "mainpll_d5_d4", + "osc_d4", + "univpll_d4_d4", + "mainpll_d5_d2", + "mainpll_d4_d2", + "mainpll_d6", + "mainpll_d5", + "univpll_d5", + "mainpll_d4" +}; + +static const char * const p_noc_parents[] = { + "clk26m", + "mainpll_d5_d8", + "mainpll_d5_d4", + "osc_d4", + "univpll_d4_d4", + "mainpll_d5_d2", + "mainpll_d4_d2", + "mainpll_d6", + "mainpll_d5", + "univpll_d5", + "mainpll_d4", + "mainpll_d3" +}; + +static const char * const emi_parents[] = { + "clk26m", + "osc_d4", + "mainpll_d5_d8", + "mainpll_d5_d4", + "mainpll_d4_d4", + "emipll1_ck" +}; + +static const char * const ap2conn_host_parents[] = { + "clk26m", + "mainpll_d7_d4" +}; + +static const char * const atb_parents[] = { + "clk26m", + "mainpll_d5_d2", + "mainpll_d4_d2", + "mainpll_d6" +}; + +static const char * const cirq_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d7_d4" +}; + +static const char * const pbus_156m_parents[] = { + "clk26m", + "mainpll_d7_d2", + "osc_d2", + "mainpll_d7" +}; + +static const char * const efuse_parents[] = { + "clk26m", + "osc_d20" +}; + +static const char * const mcu_l3gic_parents[] = { + "clk26m", + "osc_d8", + "mainpll_d4_d4", + "mainpll_d7_d2" +}; + +static const char * const mcu_infra_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d7_d2", + "mainpll_d5_d2", + "mainpll_d4_d2", + "mainpll_d9", + "mainpll_d6" +}; + +static const char * const dsp_parents[] = { + "clk26m", + "osc_d5", + "osc_d4", + "osc_d3", + "univpll_d6_d2", + "osc_d2", + "univpll_d5", + "osc" +}; + +static const char * const mfg_ref_parents[] = { + "clk26m", + "mainpll_d7_d2" +}; + +static const char * const mfg_eb_parents[] = { + "clk26m", + "mainpll_d7_d2", + "mainpll_d6_d2", + "mainpll_d5_d2" +}; + +static const char * const uart_parents[] = { + "clk26m", + "univpll_d6_d8", + "univpll_d6_d4", + "univpll_d6_d2" +}; + +static const char * const spi_b_parents[] = { + "clk26m", + "univpll_d6_d4", + "univpll_d5_d4", + "mainpll_d4_d4", + "univpll_d4_d4", + "mainpll_d6_d2", + "univpll_192m", + "univpll_d6_d2" +}; + +static const char * const msdc30_parents[] = { + "clk26m", + "univpll_d6_d4", + "mainpll_d6_d2", + "univpll_d6_d2", + "msdcpll_d2" +}; + +static const char * const disp_pwm_parents[] = { + "clk26m", + "osc_d32", + "osc_d8", + "univpll_d6_d4", + "univpll_d5_d4", + "osc_d4", + "mainpll_d4_d4" +}; + +static const char * const usb_1p_parents[] = { + "clk26m", + "univpll_d5_d4" +}; + +static const char * const usb_fmcnt_p1_parents[] = { + "clk26m", + "univpll_192m_d4" +}; + +static const char * const i2c_parents[] = { + "clk26m", + "mainpll_d4_d8", + "univpll_d5_d4", + "mainpll_d4_d4", + "univpll_d5_d2" +}; + +static const char * const aes_ufsfde_parents[] = { + "clk26m", + "mainpll_d4_d4", + "univpll_d6_d2", + "mainpll_d4_d2", + "univpll_d6", + "mainpll_d4" +}; + +static const char * const ufs_parents[] = { + "clk26m", + "mainpll_d4_d4", + "univpll_d6_d2", + "mainpll_d4_d2", + "univpll_d6", + "mainpll_d5", + "univpll_d5" +}; + +static const char * const aud_1_parents[] = { + "clk26m", + "vlp_apll1" +}; + +static const char * const aud_2_parents[] = { + "clk26m", + "vlp_apll2" +}; + +static const char * const adsp_parents[] = { + "clk26m", + "adsppll" +}; + +static const char * const adsp_uarthub_b_parents[] = { + "clk26m", + "univpll_d6_d4", + "univpll_d6_d2" +}; + +static const char * const dpmaif_main_parents[] = { + "clk26m", + "univpll_d4_d4", + "univpll_d5_d2", + "mainpll_d4_d2", + "univpll_d4_d2", + "mainpll_d6", + "univpll_d6", + "mainpll_d5", + "univpll_d5" +}; + +static const char * const pwm_parents[] = { + "clk26m", + "mainpll_d7_d4", + "univpll_d4_d8" +}; + +static const char * const mcupm_parents[] = { + "clk26m", + "mainpll_d7_d2", + "mainpll_d6_d2", + "univpll_d6_d2", + "mainpll_d5_d2" +}; + +static const char * const ipseast_parents[] = { + "clk26m", + "mainpll_d6", + "mainpll_d5", + "mainpll_d4", + "mainpll_d3" +}; + +static const char * const tl_parents[] = { + "clk26m", + "mainpll_d7_d4", + "mainpll_d4_d4", + "mainpll_d5_d2" +}; + +static const char * const md_emi_parents[] = { + "clk26m", + "mainpll_d4" +}; + +static const char * const sdf_parents[] = { + "clk26m", + "mainpll_d5_d2", + "mainpll_d4_d2", + "mainpll_d6", + "mainpll_d4", + "univpll_d4" +}; + +static const char * const uarthub_b_parents[] = { + "clk26m", + "univpll_d6_d4", + "univpll_d6_d2" +}; + +static const char * const dpsw_cmp_26m_parents[] = { + "clk26m", + "osc_d20" +}; + +static const char * const smapparents[] = { + "clk26m", + "mainpll_d4_d8" +}; + +static const char * const ssr_parents[] = { + "clk26m", + "mainpll_d4_d4", + "mainpll_d4_d2", + "mainpll_d7", + "mainpll_d6", + "mainpll_d5" +}; + +static const char * const ssr_kdf_parents[] = { + "clk26m", + "mainpll_d4_d4", + "mainpll_d4_d2", + "mainpll_d7" +}; + +static const char * const ssr_rng_parents[] = { + "clk26m", + "mainpll_d4_d4", + "mainpll_d5_d2", + "mainpll_d4_d2" +}; + +static const char * const spu_parents[] = { + "clk26m", + "mainpll_d4_d4", + "mainpll_d4_d2", + "mainpll_d7", + "mainpll_d6", + "mainpll_d5" +}; + +static const char * const dxcc_parents[] = { + "clk26m", + "mainpll_d4_d8", + "mainpll_d4_d4", + "mainpll_d4_d2" +}; + +static const char * const apll_m_parents[] = { + "aud_1", + "aud_2" +}; + +static const char * const sflash_parents[] = { + "clk26m", + "mainpll_d7_d8", + "univpll_d6_d8" +}; + +static const struct mtk_mux top_muxes[] = { + /* CLK_CFG_0 */ + MUX_CLR_SET_UPD(CLK_TOP_AXI, "axi", + axi_parents, CLK_CFG_0, CLK_CFG_0_SET, + CLK_CFG_0_CLR, 0, 3, + CLK_CFG_UPDATE, TOP_MUX_AXI_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_MEM_SUB, "mem_sub", + mem_sub_parents, CLK_CFG_0, CLK_CFG_0_SET, + CLK_CFG_0_CLR, 8, 4, + CLK_CFG_UPDATE, TOP_MUX_MEM_SUB_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_IO_NOC, "io_noc", + io_noc_parents, CLK_CFG_0, CLK_CFG_0_SET, + CLK_CFG_0_CLR, 16, 3, + CLK_CFG_UPDATE, TOP_MUX_IO_NOC_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_P_AXI, "p_axi", + shared_axi_parents, CLK_CFG_0, CLK_CFG_0_SET, + CLK_CFG_0_CLR, 24, 3, + CLK_CFG_UPDATE, TOP_MUX_PERI_AXI_SHIFT), + /* CLK_CFG_1 */ + MUX_CLR_SET_UPD(CLK_TOP_UFS_PEXTP0_AXI, "ufs_pextp0_axi", + shared_axi_parents, CLK_CFG_1, CLK_CFG_1_SET, + CLK_CFG_1_CLR, 0, 3, + CLK_CFG_UPDATE, TOP_MUX_UFS_PEXTP0_AXI_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_PEXTP1_USB_AXI, "pextp1_usb_axi", + shared_axi_parents, CLK_CFG_1, CLK_CFG_1_SET, + CLK_CFG_1_CLR, 8, 3, + CLK_CFG_UPDATE, TOP_MUX_PEXTP1_USB_AXI_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_P_FMEM_SUB, "p_fmem_sub", + shared_sub_parents, CLK_CFG_1, CLK_CFG_1_SET, + CLK_CFG_1_CLR, 16, 4, + CLK_CFG_UPDATE, TOP_MUX_PERI_FMEM_SUB_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_PEXPT0_MEM_SUB, "ufs_pexpt0_mem_sub", + shared_sub_parents, CLK_CFG_1, CLK_CFG_1_SET, + CLK_CFG_1_CLR, 24, 4, + CLK_CFG_UPDATE, TOP_MUX_UFS_PEXPT0_MEM_SUB_SHIFT), + /* CLK_CFG_2 */ + MUX_CLR_SET_UPD(CLK_TOP_PEXTP1_USB_MEM_SUB, "pextp1_usb_mem_sub", + shared_sub_parents, CLK_CFG_2, CLK_CFG_2_SET, + CLK_CFG_2_CLR, 0, 4, + CLK_CFG_UPDATE, TOP_MUX_PEXTP1_USB_MEM_SUB_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_P_NOC, "p_noc", + p_noc_parents, CLK_CFG_2, CLK_CFG_2_SET, + CLK_CFG_2_CLR, 8, 4, + CLK_CFG_UPDATE, TOP_MUX_PERI_NOC_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_EMI_N, "emi_n", + emi_parents, CLK_CFG_2, CLK_CFG_2_SET, + CLK_CFG_2_CLR, 16, 3, + CLK_CFG_UPDATE, TOP_MUX_EMI_N_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_EMI_S, "emi_s", + emi_parents, CLK_CFG_2, CLK_CFG_2_SET, + CLK_CFG_2_CLR, 24, 3, + CLK_CFG_UPDATE, TOP_MUX_EMI_S_SHIFT), + /* CLK_CFG_3 */ + MUX_CLR_SET_UPD(CLK_TOP_AP2CONN_HOST, "ap2conn_host", + ap2conn_host_parents, CLK_CFG_3, CLK_CFG_3_SET, + CLK_CFG_3_CLR, 16, 1, + CLK_CFG_UPDATE, TOP_MUX_AP2CONN_HOST_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_ATB, "atb", + atb_parents, CLK_CFG_3, CLK_CFG_3_SET, + CLK_CFG_3_CLR, 24, 2, + CLK_CFG_UPDATE, TOP_MUX_ATB_SHIFT), + /* CLK_CFG_4 */ + MUX_CLR_SET_UPD(CLK_TOP_CIRQ, "cirq", + cirq_parents, CLK_CFG_4, CLK_CFG_4_SET, + CLK_CFG_4_CLR, 0, 2, + CLK_CFG_UPDATE, TOP_MUX_CIRQ_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_PBUS_156M, "pbus_156m", + pbus_156m_parents, CLK_CFG_4, CLK_CFG_4_SET, + CLK_CFG_4_CLR, 8, 2, + CLK_CFG_UPDATE, TOP_MUX_PBUS_156M_SHIFT), + /* CLK_CFG_5 */ + MUX_CLR_SET_UPD(CLK_TOP_EFUSE, "efuse", + efuse_parents, CLK_CFG_5, CLK_CFG_5_SET, + CLK_CFG_5_CLR, 0, 1, + CLK_CFG_UPDATE, TOP_MUX_EFUSE_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_MCL3GIC, "mcu_l3gic", + mcu_l3gic_parents, CLK_CFG_5, CLK_CFG_5_SET, + CLK_CFG_5_CLR, 8, 2, + CLK_CFG_UPDATE, TOP_MUX_MCU_L3GIC_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_MCINFRA, "mcu_infra", + mcu_infra_parents, CLK_CFG_5, CLK_CFG_5_SET, + CLK_CFG_5_CLR, 16, 3, + CLK_CFG_UPDATE, TOP_MUX_MCU_INFRA_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_DSP, "dsp", + dsp_parents, CLK_CFG_5, CLK_CFG_5_SET, + CLK_CFG_5_CLR, 24, 3, + CLK_CFG_UPDATE, TOP_MUX_DSP_SHIFT), + /* CLK_CFG_6 */ + MUX_GATE_FENC_CLR_SET_UPD_FLAGS(CLK_TOP_MFG_REF, "mfg_ref", mfg_ref_parents, + NULL, ARRAY_SIZE(mfg_ref_parents), + CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, + 0, 1, 7, CLK_CFG_UPDATE, TOP_MUX_MFG_REF_SHIFT, + CLK_FENC_STATUS_MON_0, 7, CLK_IGNORE_UNUSED), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG_EB, "mfg_eb", + mfg_eb_parents, CLK_CFG_6, CLK_CFG_6_SET, + CLK_CFG_6_CLR, 16, 2, + 23, CLK_CFG_UPDATE, TOP_MUX_MFG_EB_SHIFT), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_UART, "uart", uart_parents, + CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, + HWV_CG_3_DONE, HWV_CG_3_SET, HWV_CG_3_CLR, + 24, 2, 31, CLK_CFG_UPDATE, TOP_MUX_UART_SHIFT, + CLK_FENC_STATUS_MON_0, 4), + /* CLK_CFG_7 */ + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_SPI0_BCLK, "spi0_b", spi_b_parents, + CLK_CFG_7, CLK_CFG_7_SET, CLK_CFG_7_CLR, + HWV_CG_4_DONE, HWV_CG_4_SET, HWV_CG_4_CLR, + 0, 3, 7, CLK_CFG_UPDATE, TOP_MUX_SPI0_BCLK_SHIFT, + CLK_FENC_STATUS_MON_0, 3), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_SPI1_BCLK, "spi1_b", spi_b_parents, + CLK_CFG_7, CLK_CFG_7_SET, CLK_CFG_7_CLR, + HWV_CG_4_DONE, HWV_CG_4_SET, HWV_CG_4_CLR, + 8, 3, 15, CLK_CFG_UPDATE, TOP_MUX_SPI1_BCLK_SHIFT, + CLK_FENC_STATUS_MON_0, 2), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_SPI2_BCLK, "spi2_b", spi_b_parents, + CLK_CFG_7, CLK_CFG_7_SET, CLK_CFG_7_CLR, + HWV_CG_4_DONE, HWV_CG_4_SET, HWV_CG_4_CLR, + 16, 3, 23, CLK_CFG_UPDATE, TOP_MUX_SPI2_BCLK_SHIFT, + CLK_FENC_STATUS_MON_0, 1), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_SPI3_BCLK, "spi3_b", spi_b_parents, + CLK_CFG_7, CLK_CFG_7_SET, CLK_CFG_7_CLR, + HWV_CG_4_DONE, HWV_CG_4_SET, HWV_CG_4_CLR, + 24, 3, 31, CLK_CFG_UPDATE1, TOP_MUX_SPI3_BCLK_SHIFT, + CLK_FENC_STATUS_MON_0, 0), + /* CLK_CFG_8 */ + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_SPI4_BCLK, "spi4_b", spi_b_parents, + CLK_CFG_8, CLK_CFG_8_SET, CLK_CFG_8_CLR, + HWV_CG_5_DONE, HWV_CG_5_SET, HWV_CG_5_CLR, + 0, 3, 7, CLK_CFG_UPDATE1, TOP_MUX_SPI4_BCLK_SHIFT, + CLK_FENC_STATUS_MON_1, 31), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_SPI5_BCLK, "spi5_b", spi_b_parents, + CLK_CFG_8, CLK_CFG_8_SET, CLK_CFG_8_CLR, + HWV_CG_5_DONE, HWV_CG_5_SET, HWV_CG_5_CLR, + 8, 3, 15, CLK_CFG_UPDATE1, TOP_MUX_SPI5_BCLK_SHIFT, + CLK_FENC_STATUS_MON_1, 30), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_SPI6_BCLK, "spi6_b", spi_b_parents, + CLK_CFG_8, CLK_CFG_8_SET, CLK_CFG_8_CLR, + HWV_CG_5_DONE, HWV_CG_5_SET, HWV_CG_5_CLR, + 16, 3, 23, CLK_CFG_UPDATE1, TOP_MUX_SPI6_BCLK_SHIFT, + CLK_FENC_STATUS_MON_1, 29), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_SPI7_BCLK, "spi7_b", spi_b_parents, + CLK_CFG_8, CLK_CFG_8_SET, CLK_CFG_8_CLR, + HWV_CG_5_DONE, HWV_CG_5_SET, HWV_CG_5_CLR, + 24, 3, 31, CLK_CFG_UPDATE1, TOP_MUX_SPI7_BCLK_SHIFT, + CLK_FENC_STATUS_MON_1, 28), + /* CLK_CFG_9 */ + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_MSDC30_1, "msdc30_1", msdc30_parents, + CLK_CFG_9, CLK_CFG_9_SET, CLK_CFG_9_CLR, + 16, 3, 23, CLK_CFG_UPDATE1, TOP_MUX_MSDC30_1_SHIFT, + CLK_FENC_STATUS_MON_1, 25), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_MSDC30_2, "msdc30_2", msdc30_parents, + CLK_CFG_9, CLK_CFG_9_SET, CLK_CFG_9_CLR, + 24, 3, 31, CLK_CFG_UPDATE1, TOP_MUX_MSDC30_2_SHIFT, + CLK_FENC_STATUS_MON_1, 24), + /* CLK_CFG_10 */ + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_DISP_PWM, "disp_pwm", disp_pwm_parents, + CLK_CFG_10, CLK_CFG_10_SET, CLK_CFG_10_CLR, + 0, 3, 7, CLK_CFG_UPDATE1, TOP_MUX_DISP_PWM_SHIFT, + CLK_FENC_STATUS_MON_1, 23), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_USB_TOP_1P, "usb_1p", usb_1p_parents, + CLK_CFG_10, CLK_CFG_10_SET, CLK_CFG_10_CLR, + 8, 1, 15, CLK_CFG_UPDATE1, TOP_MUX_USB_TOP_1P_SHIFT, + CLK_FENC_STATUS_MON_1, 22), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_USB_XHCI_1P, "usb_xhci_1p", usb_1p_parents, + CLK_CFG_10, CLK_CFG_10_SET, CLK_CFG_10_CLR, + 16, 1, 23, CLK_CFG_UPDATE1, TOP_MUX_SSUSB_XHCI_1P_SHIFT, + CLK_FENC_STATUS_MON_1, 21), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_USB_FMCNT_P1, "usb_fmcnt_p1", usb_fmcnt_p1_parents, + CLK_CFG_10, CLK_CFG_10_SET, CLK_CFG_10_CLR, + 24, 1, 31, CLK_CFG_UPDATE1, TOP_MUX_SSUSB_FMCNT_P1_SHIFT, + CLK_FENC_STATUS_MON_1, 20), + /* CLK_CFG_11 */ + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_I2C_P, "i2c_p", i2c_parents, + CLK_CFG_11, CLK_CFG_11_SET, CLK_CFG_11_CLR, + 0, 3, 7, CLK_CFG_UPDATE1, TOP_MUX_I2C_PERI_SHIFT, + CLK_FENC_STATUS_MON_1, 19), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_I2C_EAST, "i2c_east", i2c_parents, + CLK_CFG_11, CLK_CFG_11_SET, CLK_CFG_11_CLR, + 8, 3, 15, CLK_CFG_UPDATE1, TOP_MUX_I2C_EAST_SHIFT, + CLK_FENC_STATUS_MON_1, 18), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_I2C_WEST, "i2c_west", i2c_parents, + CLK_CFG_11, CLK_CFG_11_SET, CLK_CFG_11_CLR, + 16, 3, 23, CLK_CFG_UPDATE1, TOP_MUX_I2C_WEST_SHIFT, + CLK_FENC_STATUS_MON_1, 17), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_I2C_NORTH, "i2c_north", i2c_parents, + CLK_CFG_11, CLK_CFG_11_SET, CLK_CFG_11_CLR, + HWV_CG_6_DONE, HWV_CG_6_SET, HWV_CG_6_CLR, + 24, 3, 31, CLK_CFG_UPDATE1, TOP_MUX_I2C_NORTH_SHIFT, + CLK_FENC_STATUS_MON_1, 16), + /* CLK_CFG_12 */ + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_AES_UFSFDE, "aes_ufsfde", aes_ufsfde_parents, + CLK_CFG_12, CLK_CFG_12_SET, CLK_CFG_12_CLR, + 0, 3, 7, CLK_CFG_UPDATE1, TOP_MUX_AES_UFSFDE_SHIFT, + CLK_FENC_STATUS_MON_1, 15), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_UFS, "ufs", ufs_parents, + CLK_CFG_12, CLK_CFG_12_SET, CLK_CFG_12_CLR, + 8, 3, 15, CLK_CFG_UPDATE1, TOP_MUX_UFS_SHIFT, + CLK_FENC_STATUS_MON_1, 14), + /* CLK_CFG_13 */ + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_AUD_1, "aud_1", aud_1_parents, + CLK_CFG_13, CLK_CFG_13_SET, CLK_CFG_13_CLR, + 0, 1, 7, CLK_CFG_UPDATE1, TOP_MUX_AUD_1_SHIFT, + CLK_FENC_STATUS_MON_1, 11), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_AUD_2, "aud_2", aud_2_parents, + CLK_CFG_13, CLK_CFG_13_SET, CLK_CFG_13_CLR, + 8, 1, 15, CLK_CFG_UPDATE1, TOP_MUX_AUD_2_SHIFT, + CLK_FENC_STATUS_MON_1, 10), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_ADSP, "adsp", adsp_parents, + CLK_CFG_13, CLK_CFG_13_SET, CLK_CFG_13_CLR, + 16, 1, 23, CLK_CFG_UPDATE1, TOP_MUX_ADSP_SHIFT, + CLK_FENC_STATUS_MON_1, 9), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ADSP_UARTHUB_B, "adsp_uarthub_b", + adsp_uarthub_b_parents, CLK_CFG_13, CLK_CFG_13_SET, + CLK_CFG_13_CLR, 24, 2, 31, + CLK_CFG_UPDATE1, TOP_MUX_ADSP_UARTHUB_B_SHIFT), + /* CLK_CFG_14 */ + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_DPMAIF_MAIN, "dpmaif_main", dpmaif_main_parents, + CLK_CFG_14, CLK_CFG_14_SET, CLK_CFG_14_CLR, + 0, 4, 7, CLK_CFG_UPDATE1, TOP_MUX_DPMAIF_MAIN_SHIFT, + CLK_FENC_STATUS_MON_1, 7), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_PWM, "pwm", pwm_parents, + CLK_CFG_14, CLK_CFG_14_SET, CLK_CFG_14_CLR, + 8, 2, 15, CLK_CFG_UPDATE1, TOP_MUX_PWM_SHIFT, + CLK_FENC_STATUS_MON_1, 6), + MUX_CLR_SET_UPD(CLK_TOP_MCUPM, "mcupm", + mcupm_parents, CLK_CFG_14, CLK_CFG_14_SET, + CLK_CFG_14_CLR, 16, 3, + CLK_CFG_UPDATE1, TOP_MUX_MCUPM_SHIFT), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_SFLASH, "sflash", sflash_parents, + CLK_CFG_14, CLK_CFG_14_SET, CLK_CFG_14_CLR, + 24, 2, 31, CLK_CFG_UPDATE1, TOP_MUX_SFLASH_SHIFT, + CLK_FENC_STATUS_MON_1, 4), + /* CLK_CFG_15 */ + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_IPSEAST, "ipseast", ipseast_parents, + CLK_CFG_15, CLK_CFG_15_SET, CLK_CFG_15_CLR, + 0, 3, 7, CLK_CFG_UPDATE1, TOP_MUX_IPSEAST_SHIFT, + CLK_FENC_STATUS_MON_1, 3), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_TL, "tl", tl_parents, + CLK_CFG_15, CLK_CFG_15_SET, CLK_CFG_15_CLR, + 16, 2, 23, CLK_CFG_UPDATE2, TOP_MUX_TL_SHIFT, + CLK_FENC_STATUS_MON_1, 1), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_TL_P1, "tl_p1", tl_parents, + CLK_CFG_15, CLK_CFG_15_SET, CLK_CFG_15_CLR, + 24, 2, 31, CLK_CFG_UPDATE2, TOP_MUX_TL_P1_SHIFT, + CLK_FENC_STATUS_MON_1, 0), + /* CLK_CFG_16 */ + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP_TL_P2, "tl_p2", tl_parents, + CLK_CFG_16, CLK_CFG_16_SET, CLK_CFG_16_CLR, + 0, 2, 7, CLK_CFG_UPDATE2, TOP_MUX_TL_P2_SHIFT, + CLK_FENC_STATUS_MON_2, 31), + MUX_CLR_SET_UPD(CLK_TOP_EMI_INTERFACE_546, "emi_interface_546", + md_emi_parents, CLK_CFG_16, CLK_CFG_16_SET, + CLK_CFG_16_CLR, 8, 1, + CLK_CFG_UPDATE2, TOP_MUX_EMI_INTERFACE_546_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_SDF, "sdf", + sdf_parents, CLK_CFG_16, CLK_CFG_16_SET, + CLK_CFG_16_CLR, 16, 3, + CLK_CFG_UPDATE2, TOP_MUX_SDF_SHIFT), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP_UARTHUB_BCLK, "uarthub_b", uarthub_b_parents, + CLK_CFG_16, CLK_CFG_16_SET, CLK_CFG_16_CLR, + HWV_CG_7_DONE, HWV_CG_7_SET, HWV_CG_7_CLR, + 24, 2, 31, CLK_CFG_UPDATE2, TOP_MUX_UARTHUB_BCLK_SHIFT, + CLK_FENC_STATUS_MON_2, 28), + /* CLK_CFG_17 */ + MUX_CLR_SET_UPD(CLK_TOP_DPSW_CMP_26M, "dpsw_cmp_26m", + dpsw_cmp_26m_parents, CLK_CFG_17, CLK_CFG_17_SET, + CLK_CFG_17_CLR, 0, 1, + CLK_CFG_UPDATE2, TOP_MUX_DPSW_CMP_26M_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_SMAP, "smap", + smapparents, CLK_CFG_17, CLK_CFG_17_SET, + CLK_CFG_17_CLR, 8, 1, + CLK_CFG_UPDATE2, TOP_MUX_SMAPCK_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_SSR_PKA, "ssr_pka", + ssr_parents, CLK_CFG_17, CLK_CFG_17_SET, + CLK_CFG_17_CLR, 16, 3, + CLK_CFG_UPDATE2, TOP_MUX_SSR_PKA_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_SSR_DMA, "ssr_dma", + ssr_parents, CLK_CFG_17, CLK_CFG_17_SET, + CLK_CFG_17_CLR, 24, 3, + CLK_CFG_UPDATE2, TOP_MUX_SSR_DMA_SHIFT), + /* CLK_CFG_18 */ + MUX_CLR_SET_UPD(CLK_TOP_SSR_KDF, "ssr_kdf", + ssr_kdf_parents, CLK_CFG_18, CLK_CFG_18_SET, + CLK_CFG_18_CLR, 0, 2, + CLK_CFG_UPDATE2, TOP_MUX_SSR_KDF_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_SSR_RNG, "ssr_rng", + ssr_rng_parents, CLK_CFG_18, CLK_CFG_18_SET, + CLK_CFG_18_CLR, 8, 2, + CLK_CFG_UPDATE2, TOP_MUX_SSR_RNG_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_SPU0, "spu0", + spu_parents, CLK_CFG_18, CLK_CFG_18_SET, + CLK_CFG_18_CLR, 16, 3, + CLK_CFG_UPDATE2, TOP_MUX_SPU0_SHIFT), + MUX_CLR_SET_UPD(CLK_TOP_SPU1, "spu1", + spu_parents, CLK_CFG_18, CLK_CFG_18_SET, + CLK_CFG_18_CLR, 24, 3, + CLK_CFG_UPDATE2, TOP_MUX_SPU1_SHIFT), + /* CLK_CFG_19 */ + MUX_CLR_SET_UPD(CLK_TOP_DXCC, "dxcc", + dxcc_parents, CLK_CFG_19, CLK_CFG_19_SET, + CLK_CFG_19_CLR, 0, 2, + CLK_CFG_UPDATE2, TOP_MUX_DXCC_SHIFT), +}; + +static const struct mtk_composite top_aud_divs[] = { + /* CLK_AUDDIV_2 */ + MUX_DIV_GATE(CLK_TOP_APLL_I2SIN0, "apll_i2sin0_m", apll_m_parents, + CLK_AUDDIV_0, 16, 1, CLK_AUDDIV_2, 0, 8, CLK_AUDDIV_0, 0), + MUX_DIV_GATE(CLK_TOP_APLL_I2SIN1, "apll_i2sin1_m", apll_m_parents, + CLK_AUDDIV_0, 17, 1, CLK_AUDDIV_2, 8, 8, CLK_AUDDIV_0, 1), + MUX_DIV_GATE(CLK_TOP_APLL_I2SIN2, "apll_i2sin2_m", apll_m_parents, + CLK_AUDDIV_0, 18, 1, CLK_AUDDIV_2, 16, 8, CLK_AUDDIV_0, 2), + MUX_DIV_GATE(CLK_TOP_APLL_I2SIN3, "apll_i2sin3_m", apll_m_parents, + CLK_AUDDIV_0, 19, 1, CLK_AUDDIV_2, 24, 8, CLK_AUDDIV_0, 3), + /* CLK_AUDDIV_3 */ + MUX_DIV_GATE(CLK_TOP_APLL_I2SIN4, "apll_i2sin4_m", apll_m_parents, + CLK_AUDDIV_0, 20, 1, CLK_AUDDIV_3, 0, 8, CLK_AUDDIV_0, 4), + MUX_DIV_GATE(CLK_TOP_APLL_I2SIN6, "apll_i2sin6_m", apll_m_parents, + CLK_AUDDIV_0, 21, 1, CLK_AUDDIV_3, 8, 8, CLK_AUDDIV_0, 5), + MUX_DIV_GATE(CLK_TOP_APLL_I2SOUT0, "apll_i2sout0_m", apll_m_parents, + CLK_AUDDIV_0, 22, 1, CLK_AUDDIV_3, 16, 8, CLK_AUDDIV_0, 6), + MUX_DIV_GATE(CLK_TOP_APLL_I2SOUT1, "apll_i2sout1_m", apll_m_parents, + CLK_AUDDIV_0, 23, 1, CLK_AUDDIV_3, 24, 8, CLK_AUDDIV_0, 7), + /* CLK_AUDDIV_4 */ + MUX_DIV_GATE(CLK_TOP_APLL_I2SOUT2, "apll_i2sout2_m", apll_m_parents, + CLK_AUDDIV_0, 24, 1, CLK_AUDDIV_4, 0, 8, CLK_AUDDIV_0, 8), + MUX_DIV_GATE(CLK_TOP_APLL_I2SOUT3, "apll_i2sout3_m", apll_m_parents, + CLK_AUDDIV_0, 25, 1, CLK_AUDDIV_4, 8, 8, CLK_AUDDIV_0, 9), + MUX_DIV_GATE(CLK_TOP_APLL_I2SOUT4, "apll_i2sout4_m", apll_m_parents, + CLK_AUDDIV_0, 26, 1, CLK_AUDDIV_4, 16, 8, CLK_AUDDIV_0, 10), + MUX_DIV_GATE(CLK_TOP_APLL_I2SOUT6, "apll_i2sout6_m", apll_m_parents, + CLK_AUDDIV_0, 27, 1, CLK_AUDDIV_4, 24, 8, CLK_AUDDIV_0, 11), + /* CLK_AUDDIV_5 */ + MUX_DIV_GATE(CLK_TOP_APLL_FMI2S, "apll_fmi2s_m", apll_m_parents, + CLK_AUDDIV_0, 28, 1, CLK_AUDDIV_5, 0, 8, CLK_AUDDIV_0, 12), + MUX(CLK_TOP_APLL_TDMOUT, "apll_tdmout_m", + apll_m_parents, CLK_AUDDIV_0, 29, 1), + DIV_GATE(CLK_TOP_APLL12_DIV_TDMOUT_M, "apll12_div_tdmout_m", + "apll_tdmout_m", CLK_AUDDIV_0, + 13, CLK_AUDDIV_5, 8, 8), + DIV_GATE(CLK_TOP_APLL12_DIV_TDMOUT_B, "apll12_div_tdmout_b", + "apll_tdmout_m", CLK_AUDDIV_0, + 14, CLK_AUDDIV_5, 8, 16), +}; + +static const struct mtk_clk_desc topck_desc = { + .factor_clks = top_divs, + .num_factor_clks = ARRAY_SIZE(top_divs), + .mux_clks = top_muxes, + .num_mux_clks = ARRAY_SIZE(top_muxes), + .composite_clks = top_aud_divs, + .num_composite_clks = ARRAY_SIZE(top_aud_divs) +}; + +static const struct of_device_id of_match_clk_mt8196_ck[] = { + { .compatible = "mediatek,mt8196-topckgen", .data = &topck_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_ck); + +static struct platform_driver clk_mt8196_topck_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8196-topck", + .of_match_table = of_match_clk_mt8196_ck, + }, +}; + +MODULE_DESCRIPTION("MediaTek MT8196 top clock generators driver"); +module_platform_driver(clk_mt8196_topck_drv); +MODULE_LICENSE("GPL"); From b093e0f1709990666d75d3018db2d7b431678f2f Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:32 +0200 Subject: [PATCH 1846/2711] clk: mediatek: Add MT8196 topckgen2 clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 topckgen2 clock controller, which provides muxes and dividers for clock selection in other IP blocks. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Makefile | 3 +- drivers/clk/mediatek/clk-mt8196-topckgen2.c | 568 ++++++++++++++++++++ 2 files changed, 570 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mediatek/clk-mt8196-topckgen2.c diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index ad61621b8c95..c415453e02fd 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -150,7 +150,8 @@ obj-$(CONFIG_COMMON_CLK_MT8195_VDOSYS) += clk-mt8195-vdo0.o clk-mt8195-vdo1.o obj-$(CONFIG_COMMON_CLK_MT8195_VENCSYS) += clk-mt8195-venc.o obj-$(CONFIG_COMMON_CLK_MT8195_VPPSYS) += clk-mt8195-vpp0.o clk-mt8195-vpp1.o obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o -obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o +obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o \ + clk-mt8196-topckgen2.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o diff --git a/drivers/clk/mediatek/clk-mt8196-topckgen2.c b/drivers/clk/mediatek/clk-mt8196-topckgen2.c new file mode 100644 index 000000000000..6df93d7fbf91 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-topckgen2.c @@ -0,0 +1,568 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-mux.h" + +/* MUX SEL REG */ +#define CKSYS2_CLK_CFG_UPDATE 0x0004 +#define CKSYS2_CLK_CFG_0 0x0010 +#define CKSYS2_CLK_CFG_0_SET 0x0014 +#define CKSYS2_CLK_CFG_0_CLR 0x0018 +#define CKSYS2_CLK_CFG_1 0x0020 +#define CKSYS2_CLK_CFG_1_SET 0x0024 +#define CKSYS2_CLK_CFG_1_CLR 0x0028 +#define CKSYS2_CLK_CFG_2 0x0030 +#define CKSYS2_CLK_CFG_2_SET 0x0034 +#define CKSYS2_CLK_CFG_2_CLR 0x0038 +#define CKSYS2_CLK_CFG_3 0x0040 +#define CKSYS2_CLK_CFG_3_SET 0x0044 +#define CKSYS2_CLK_CFG_3_CLR 0x0048 +#define CKSYS2_CLK_CFG_4 0x0050 +#define CKSYS2_CLK_CFG_4_SET 0x0054 +#define CKSYS2_CLK_CFG_4_CLR 0x0058 +#define CKSYS2_CLK_CFG_5 0x0060 +#define CKSYS2_CLK_CFG_5_SET 0x0064 +#define CKSYS2_CLK_CFG_5_CLR 0x0068 +#define CKSYS2_CLK_CFG_6 0x0070 +#define CKSYS2_CLK_CFG_6_SET 0x0074 +#define CKSYS2_CLK_CFG_6_CLR 0x0078 +#define CKSYS2_CLK_FENC_STATUS_MON_0 0x0174 + +/* MUX SHIFT */ +#define TOP_MUX_SENINF0_SHIFT 0 +#define TOP_MUX_SENINF1_SHIFT 1 +#define TOP_MUX_SENINF2_SHIFT 2 +#define TOP_MUX_SENINF3_SHIFT 3 +#define TOP_MUX_SENINF4_SHIFT 4 +#define TOP_MUX_SENINF5_SHIFT 5 +#define TOP_MUX_IMG1_SHIFT 6 +#define TOP_MUX_IPE_SHIFT 7 +#define TOP_MUX_CAM_SHIFT 8 +#define TOP_MUX_CAMTM_SHIFT 9 +#define TOP_MUX_DPE_SHIFT 10 +#define TOP_MUX_VDEC_SHIFT 11 +#define TOP_MUX_CCUSYS_SHIFT 12 +#define TOP_MUX_CCUTM_SHIFT 13 +#define TOP_MUX_VENC_SHIFT 14 +#define TOP_MUX_DVO_SHIFT 15 +#define TOP_MUX_DVO_FAVT_SHIFT 16 +#define TOP_MUX_DP1_SHIFT 17 +#define TOP_MUX_DP0_SHIFT 18 +#define TOP_MUX_DISP_SHIFT 19 +#define TOP_MUX_MDP_SHIFT 20 +#define TOP_MUX_MMINFRA_SHIFT 21 +#define TOP_MUX_MMINFRA_SNOC_SHIFT 22 +#define TOP_MUX_MMUP_SHIFT 23 +#define TOP_MUX_MMINFRA_AO_SHIFT 26 + +/* HW Voter REG */ +#define HWV_CG_30_SET 0x0058 +#define HWV_CG_30_CLR 0x005c +#define HWV_CG_30_DONE 0x2c2c + +#define MM_HWV_CG_30_SET 0x00f0 +#define MM_HWV_CG_30_CLR 0x00f4 +#define MM_HWV_CG_30_DONE 0x2c78 +#define MM_HWV_CG_31_SET 0x00f8 +#define MM_HWV_CG_31_CLR 0x00fc +#define MM_HWV_CG_31_DONE 0x2c7c +#define MM_HWV_CG_32_SET 0x0100 +#define MM_HWV_CG_32_CLR 0x0104 +#define MM_HWV_CG_32_DONE 0x2c80 +#define MM_HWV_CG_33_SET 0x0108 +#define MM_HWV_CG_33_CLR 0x010c +#define MM_HWV_CG_33_DONE 0x2c84 +#define MM_HWV_CG_34_SET 0x0110 +#define MM_HWV_CG_34_CLR 0x0114 +#define MM_HWV_CG_34_DONE 0x2c88 +#define MM_HWV_CG_35_SET 0x0118 +#define MM_HWV_CG_35_CLR 0x011c +#define MM_HWV_CG_35_DONE 0x2c8c +#define MM_HWV_CG_36_SET 0x0120 +#define MM_HWV_CG_36_CLR 0x0124 +#define MM_HWV_CG_36_DONE 0x2c90 +#define MM_HWV_MUX_UPDATE_31_0 0x0240 + +static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_TOP2_MAINPLL2_D2, "mainpll2_d2", "mainpll2", 1, 2), + FACTOR(CLK_TOP2_MAINPLL2_D3, "mainpll2_d3", "mainpll2", 1, 3), + FACTOR(CLK_TOP2_MAINPLL2_D4, "mainpll2_d4", "mainpll2", 1, 4), + FACTOR(CLK_TOP2_MAINPLL2_D4_D2, "mainpll2_d4_d2", "mainpll2", 1, 8), + FACTOR(CLK_TOP2_MAINPLL2_D4_D4, "mainpll2_d4_d4", "mainpll2", 1, 16), + FACTOR(CLK_TOP2_MAINPLL2_D5, "mainpll2_d5", "mainpll2", 1, 5), + FACTOR(CLK_TOP2_MAINPLL2_D5_D2, "mainpll2_d5_d2", "mainpll2", 1, 10), + FACTOR(CLK_TOP2_MAINPLL2_D6, "mainpll2_d6", "mainpll2", 1, 6), + FACTOR(CLK_TOP2_MAINPLL2_D6_D2, "mainpll2_d6_d2", "mainpll2", 1, 12), + FACTOR(CLK_TOP2_MAINPLL2_D7, "mainpll2_d7", "mainpll2", 1, 7), + FACTOR(CLK_TOP2_MAINPLL2_D7_D2, "mainpll2_d7_d2", "mainpll2", 1, 14), + FACTOR(CLK_TOP2_MAINPLL2_D9, "mainpll2_d9", "mainpll2", 1, 9), + FACTOR(CLK_TOP2_UNIVPLL2_D3, "univpll2_d3", "univpll2", 1, 3), + FACTOR(CLK_TOP2_UNIVPLL2_D4, "univpll2_d4", "univpll2", 1, 4), + FACTOR(CLK_TOP2_UNIVPLL2_D4_D2, "univpll2_d4_d2", "univpll2", 1, 8), + FACTOR(CLK_TOP2_UNIVPLL2_D5, "univpll2_d5", "univpll2", 1, 5), + FACTOR(CLK_TOP2_UNIVPLL2_D5_D2, "univpll2_d5_d2", "univpll2", 1, 10), + FACTOR(CLK_TOP2_UNIVPLL2_D6, "univpll2_d6", "univpll2", 1, 6), + FACTOR(CLK_TOP2_UNIVPLL2_D6_D2, "univpll2_d6_d2", "univpll2", 1, 12), + FACTOR(CLK_TOP2_UNIVPLL2_D6_D4, "univpll2_d6_d4", "univpll2", 1, 24), + FACTOR(CLK_TOP2_UNIVPLL2_D7, "univpll2_d7", "univpll2", 1, 7), + FACTOR(CLK_TOP2_IMGPLL_D2, "imgpll_d2", "imgpll", 1, 2), + FACTOR(CLK_TOP2_IMGPLL_D4, "imgpll_d4", "imgpll", 1, 4), + FACTOR(CLK_TOP2_IMGPLL_D5, "imgpll_d5", "imgpll", 1, 5), + FACTOR(CLK_TOP2_IMGPLL_D5_D2, "imgpll_d5_d2", "imgpll", 1, 10), + FACTOR(CLK_TOP2_MMPLL2_D3, "mmpll2_d3", "mmpll2", 1, 3), + FACTOR(CLK_TOP2_MMPLL2_D4, "mmpll2_d4", "mmpll2", 1, 4), + FACTOR(CLK_TOP2_MMPLL2_D4_D2, "mmpll2_d4_d2", "mmpll2", 1, 8), + FACTOR(CLK_TOP2_MMPLL2_D5, "mmpll2_d5", "mmpll2", 1, 5), + FACTOR(CLK_TOP2_MMPLL2_D5_D2, "mmpll2_d5_d2", "mmpll2", 1, 10), + FACTOR(CLK_TOP2_MMPLL2_D6, "mmpll2_d6", "mmpll2", 1, 6), + FACTOR(CLK_TOP2_MMPLL2_D6_D2, "mmpll2_d6_d2", "mmpll2", 1, 12), + FACTOR(CLK_TOP2_MMPLL2_D7, "mmpll2_d7", "mmpll2", 1, 7), + FACTOR(CLK_TOP2_MMPLL2_D9, "mmpll2_d9", "mmpll2", 1, 9), + FACTOR(CLK_TOP2_TVDPLL1_D4, "tvdpll1_d4", "tvdpll1", 1, 4), + FACTOR(CLK_TOP2_TVDPLL1_D8, "tvdpll1_d8", "tvdpll1", 1, 8), + FACTOR(CLK_TOP2_TVDPLL1_D16, "tvdpll1_d16", "tvdpll1", 1, 16), + FACTOR(CLK_TOP2_TVDPLL2_D2, "tvdpll2_d2", "tvdpll2", 1, 2), + FACTOR(CLK_TOP2_TVDPLL2_D4, "tvdpll2_d4", "tvdpll2", 1, 4), + FACTOR(CLK_TOP2_TVDPLL2_D8, "tvdpll2_d8", "tvdpll2", 1, 8), + FACTOR(CLK_TOP2_TVDPLL2_D16, "tvdpll2_d16", "tvdpll2", 92, 1473), + FACTOR(CLK_TOP2_TVDPLL3_D2, "tvdpll3_d2", "tvdpll3", 1, 2), + FACTOR(CLK_TOP2_TVDPLL3_D4, "tvdpll3_d4", "tvdpll3", 1, 4), + FACTOR(CLK_TOP2_TVDPLL3_D8, "tvdpll3_d8", "tvdpll3", 1, 8), + FACTOR(CLK_TOP2_TVDPLL3_D16, "tvdpll3_d16", "tvdpll3", 92, 1473), +}; + +static const char * const seninf_parents[] = { + "clk26m", + "ck_osc_d10", + "ck_osc_d8", + "ck_osc_d5", + "ck_osc_d4", + "univpll2_d6_d2", + "mainpll2_d9", + "ck_osc_d2", + "mainpll2_d4_d2", + "univpll2_d4_d2", + "mmpll2_d4_d2", + "univpll2_d7", + "mainpll2_d6", + "mmpll2_d7", + "univpll2_d6", + "univpll2_d5" +}; + +static const char * const img1_parents[] = { + "clk26m", + "ck_osc_d4", + "ck_osc_d3", + "mmpll2_d6_d2", + "ck_osc_d2", + "imgpll_d5_d2", + "mmpll2_d5_d2", + "univpll2_d4_d2", + "mmpll2_d4_d2", + "mmpll2_d7", + "univpll2_d6", + "mmpll2_d6", + "univpll2_d5", + "mmpll2_d5", + "univpll2_d4", + "imgpll_d4" +}; + +static const char * const ipe_parents[] = { + "clk26m", + "ck_osc_d4", + "ck_osc_d3", + "ck_osc_d2", + "univpll2_d6", + "mmpll2_d6", + "univpll2_d5", + "imgpll_d5", + "ck_mainpll_d4", + "mmpll2_d5", + "imgpll_d4" +}; + +static const char * const cam_parents[] = { + "clk26m", + "ck_osc_d10", + "ck_osc_d4", + "ck_osc_d3", + "ck_osc_d2", + "mmpll2_d5_d2", + "univpll2_d4_d2", + "univpll2_d7", + "mmpll2_d7", + "univpll2_d6", + "mmpll2_d6", + "univpll2_d5", + "mmpll2_d5", + "univpll2_d4", + "imgpll_d4", + "mmpll2_d4" +}; + +static const char * const camtm_parents[] = { + "clk26m", + "univpll2_d6_d4", + "ck_osc_d4", + "ck_osc_d3", + "univpll2_d6_d2" +}; + +static const char * const dpe_parents[] = { + "clk26m", + "mmpll2_d5_d2", + "univpll2_d4_d2", + "mmpll2_d7", + "univpll2_d6", + "mmpll2_d6", + "univpll2_d5", + "mmpll2_d5", + "imgpll_d4", + "mmpll2_d4" +}; + +static const char * const vdec_parents[] = { + "clk26m", + "ck_mainpll_d5_d2", + "mainpll2_d4_d4", + "mainpll2_d7_d2", + "mainpll2_d6_d2", + "mainpll2_d5_d2", + "mainpll2_d9", + "mainpll2_d4_d2", + "mainpll2_d7", + "mainpll2_d6", + "univpll2_d6", + "mainpll2_d5", + "mainpll2_d4", + "imgpll_d2" +}; + +static const char * const ccusys_parents[] = { + "clk26m", + "ck_osc_d4", + "ck_osc_d3", + "ck_osc_d2", + "mmpll2_d5_d2", + "univpll2_d4_d2", + "mmpll2_d7", + "univpll2_d6", + "mmpll2_d6", + "univpll2_d5", + "mainpll2_d4", + "mainpll2_d3", + "univpll2_d3" +}; + +static const char * const ccutm_parents[] = { + "clk26m", + "univpll2_d6_d4", + "ck_osc_d4", + "ck_osc_d3", + "univpll2_d6_d2" +}; + +static const char * const venc_parents[] = { + "clk26m", + "mainpll2_d5_d2", + "univpll2_d5_d2", + "mainpll2_d4_d2", + "mmpll2_d9", + "univpll2_d4_d2", + "mmpll2_d4_d2", + "mainpll2_d6", + "univpll2_d6", + "mainpll2_d5", + "mmpll2_d6", + "univpll2_d5", + "mainpll2_d4", + "univpll2_d4", + "univpll2_d3" +}; + +static const char * const dp1_parents[] = { + "clk26m", + "tvdpll2_d16", + "tvdpll2_d8", + "tvdpll2_d4", + "tvdpll2_d2" +}; + +static const char * const dp0_parents[] = { + "clk26m", + "tvdpll1_d16", + "tvdpll1_d8", + "tvdpll1_d4", + "ck_tvdpll1_d2" +}; + +static const char * const disp_parents[] = { + "clk26m", + "ck_mainpll_d5_d2", + "ck_mainpll_d4_d2", + "ck_mainpll_d6", + "mainpll2_d5", + "mmpll2_d6", + "mainpll2_d4", + "univpll2_d4", + "mainpll2_d3" +}; + +static const char * const mdp_parents[] = { + "clk26m", + "ck_mainpll_d5_d2", + "mainpll2_d5_d2", + "mmpll2_d6_d2", + "mainpll2_d9", + "mainpll2_d4_d2", + "mainpll2_d7", + "mainpll2_d6", + "mainpll2_d5", + "mmpll2_d6", + "mainpll2_d4", + "univpll2_d4", + "mainpll2_d3" +}; + +static const char * const mminfra_parents[] = { + "clk26m", + "ck_osc_d4", + "ck_mainpll_d7_d2", + "ck_mainpll_d5_d2", + "ck_mainpll_d9", + "mmpll2_d6_d2", + "mainpll2_d4_d2", + "ck_mainpll_d6", + "univpll2_d6", + "mainpll2_d5", + "mmpll2_d6", + "univpll2_d5", + "mainpll2_d4", + "univpll2_d4", + "mainpll2_d3", + "univpll2_d3" +}; + +static const char * const mminfra_snoc_parents[] = { + "clk26m", + "ck_osc_d4", + "ck_mainpll_d7_d2", + "ck_mainpll_d9", + "ck_mainpll_d7", + "ck_mainpll_d6", + "mmpll2_d4_d2", + "ck_mainpll_d5", + "ck_mainpll_d4", + "univpll2_d4", + "mmpll2_d4", + "mainpll2_d3", + "univpll2_d3", + "mmpll2_d3", + "mainpll2_d2" +}; + +static const char * const mmup_parents[] = { + "clk26m", + "mainpll2_d6", + "mainpll2_d5", + "ck_osc_d2", + "ck_osc", + "ck_mainpll_d4", + "univpll2_d4", + "mainpll2_d3" +}; + +static const char * const mminfra_ao_parents[] = { + "clk26m", + "ck_osc_d4", + "ck_mainpll_d3" +}; + +static const char * const dvo_parents[] = { + "clk26m", + "tvdpll3_d16", + "tvdpll3_d8", + "tvdpll3_d4", + "tvdpll3_d2" +}; + +static const char * const dvo_favt_parents[] = { + "clk26m", + "tvdpll3_d16", + "tvdpll3_d8", + "tvdpll3_d4", + "vlp_apll1", + "vlp_apll2", + "tvdpll3_d2" +}; + +static const struct mtk_mux top_muxes[] = { + /* CKSYS2_CLK_CFG_0 */ + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_SENINF0, "seninf0", seninf_parents, + CKSYS2_CLK_CFG_0, CKSYS2_CLK_CFG_0_SET, CKSYS2_CLK_CFG_0_CLR, + MM_HWV_CG_30_DONE, MM_HWV_CG_30_SET, MM_HWV_CG_30_CLR, + 0, 4, 7, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_SENINF0_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 31), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_SENINF1, "seninf1", seninf_parents, + CKSYS2_CLK_CFG_0, CKSYS2_CLK_CFG_0_SET, CKSYS2_CLK_CFG_0_CLR, + MM_HWV_CG_30_DONE, MM_HWV_CG_30_SET, MM_HWV_CG_30_CLR, + 8, 4, 15, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_SENINF1_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 30), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_SENINF2, "seninf2", seninf_parents, + CKSYS2_CLK_CFG_0, CKSYS2_CLK_CFG_0_SET, CKSYS2_CLK_CFG_0_CLR, + MM_HWV_CG_30_DONE, MM_HWV_CG_30_SET, MM_HWV_CG_30_CLR, + 16, 4, 23, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_SENINF2_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 29), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_SENINF3, "seninf3", seninf_parents, + CKSYS2_CLK_CFG_0, CKSYS2_CLK_CFG_0_SET, CKSYS2_CLK_CFG_0_CLR, + MM_HWV_CG_30_DONE, MM_HWV_CG_30_SET, MM_HWV_CG_30_CLR, + 24, 4, 31, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_SENINF3_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 28), + /* CKSYS2_CLK_CFG_1 */ + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_SENINF4, "seninf4", seninf_parents, + CKSYS2_CLK_CFG_1, CKSYS2_CLK_CFG_1_SET, CKSYS2_CLK_CFG_1_CLR, + MM_HWV_CG_31_DONE, MM_HWV_CG_31_SET, MM_HWV_CG_31_CLR, + 0, 4, 7, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_SENINF4_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 27), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_SENINF5, "seninf5", seninf_parents, + CKSYS2_CLK_CFG_1, CKSYS2_CLK_CFG_1_SET, CKSYS2_CLK_CFG_1_CLR, + MM_HWV_CG_31_DONE, MM_HWV_CG_31_SET, MM_HWV_CG_31_CLR, + 8, 4, 15, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_SENINF5_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 26), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_IMG1, "img1", img1_parents, + CKSYS2_CLK_CFG_1, CKSYS2_CLK_CFG_1_SET, CKSYS2_CLK_CFG_1_CLR, + MM_HWV_CG_31_DONE, MM_HWV_CG_31_SET, MM_HWV_CG_31_CLR, + 16, 4, 23, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_IMG1_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 25), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_IPE, "ipe", ipe_parents, + CKSYS2_CLK_CFG_1, CKSYS2_CLK_CFG_1_SET, CKSYS2_CLK_CFG_1_CLR, + MM_HWV_CG_31_DONE, MM_HWV_CG_31_SET, MM_HWV_CG_31_CLR, + 24, 4, 31, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_IPE_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 24), + /* CKSYS2_CLK_CFG_2 */ + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_CAM, "cam", cam_parents, + CKSYS2_CLK_CFG_2, CKSYS2_CLK_CFG_2_SET, CKSYS2_CLK_CFG_2_CLR, + MM_HWV_CG_32_DONE, MM_HWV_CG_32_SET, MM_HWV_CG_32_CLR, + 0, 4, 7, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_CAM_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 23), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_CAMTM, "camtm", camtm_parents, + CKSYS2_CLK_CFG_2, CKSYS2_CLK_CFG_2_SET, CKSYS2_CLK_CFG_2_CLR, + MM_HWV_CG_32_DONE, MM_HWV_CG_32_SET, MM_HWV_CG_32_CLR, + 8, 3, 15, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_CAMTM_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 22), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_DPE, "dpe", dpe_parents, + CKSYS2_CLK_CFG_2, CKSYS2_CLK_CFG_2_SET, CKSYS2_CLK_CFG_2_CLR, + MM_HWV_CG_32_DONE, MM_HWV_CG_32_SET, MM_HWV_CG_32_CLR, + 16, 4, 23, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_DPE_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 21), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_VDEC, "vdec", vdec_parents, + CKSYS2_CLK_CFG_2, CKSYS2_CLK_CFG_2_SET, CKSYS2_CLK_CFG_2_CLR, + MM_HWV_CG_32_DONE, MM_HWV_CG_32_SET, MM_HWV_CG_32_CLR, + 24, 4, 31, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_VDEC_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 20), + /* CKSYS2_CLK_CFG_3 */ + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_CCUSYS, "ccusys", ccusys_parents, + CKSYS2_CLK_CFG_3, CKSYS2_CLK_CFG_3_SET, CKSYS2_CLK_CFG_3_CLR, + MM_HWV_CG_33_DONE, MM_HWV_CG_33_SET, MM_HWV_CG_33_CLR, + 0, 4, 7, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_CCUSYS_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 19), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_CCUTM, "ccutm", ccutm_parents, + CKSYS2_CLK_CFG_3, CKSYS2_CLK_CFG_3_SET, CKSYS2_CLK_CFG_3_CLR, + MM_HWV_CG_33_DONE, MM_HWV_CG_33_SET, MM_HWV_CG_33_CLR, + 8, 3, 15, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_CCUTM_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 18), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_VENC, "venc", venc_parents, + CKSYS2_CLK_CFG_3, CKSYS2_CLK_CFG_3_SET, CKSYS2_CLK_CFG_3_CLR, + MM_HWV_CG_33_DONE, MM_HWV_CG_33_SET, MM_HWV_CG_33_CLR, + 16, 4, 23, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_VENC_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 17), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP2_DVO, "dvo", dvo_parents, + CKSYS2_CLK_CFG_3, CKSYS2_CLK_CFG_3_SET, CKSYS2_CLK_CFG_3_CLR, + 24, 3, 31, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_DVO_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 16), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP2_DVO_FAVT, "dvo_favt", dvo_favt_parents, + CKSYS2_CLK_CFG_4, CKSYS2_CLK_CFG_4_SET, CKSYS2_CLK_CFG_4_CLR, + 0, 3, 7, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_DVO_FAVT_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 15), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP2_DP1, "dp1", dp1_parents, + CKSYS2_CLK_CFG_4, CKSYS2_CLK_CFG_4_SET, CKSYS2_CLK_CFG_4_CLR, + 8, 3, 15, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_DP1_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 14), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP2_DP0, "dp0", dp0_parents, + CKSYS2_CLK_CFG_4, CKSYS2_CLK_CFG_4_SET, CKSYS2_CLK_CFG_4_CLR, + 16, 3, 23, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_DP0_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 13), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_DISP, "disp", disp_parents, + CKSYS2_CLK_CFG_4, CKSYS2_CLK_CFG_4_SET, CKSYS2_CLK_CFG_4_CLR, + MM_HWV_CG_34_DONE, MM_HWV_CG_34_SET, MM_HWV_CG_34_CLR, + 24, 4, 31, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_DISP_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 12), + /* CKSYS2_CLK_CFG_5 */ + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_MDP, "mdp", mdp_parents, + CKSYS2_CLK_CFG_5, CKSYS2_CLK_CFG_5_SET, CKSYS2_CLK_CFG_5_CLR, + MM_HWV_CG_35_DONE, MM_HWV_CG_35_SET, MM_HWV_CG_35_CLR, + 0, 4, 7, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_MDP_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 11), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_MMINFRA, "mminfra", mminfra_parents, + CKSYS2_CLK_CFG_5, CKSYS2_CLK_CFG_5_SET, CKSYS2_CLK_CFG_5_CLR, + MM_HWV_CG_35_DONE, MM_HWV_CG_35_SET, MM_HWV_CG_35_CLR, + 8, 4, 15, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_MMINFRA_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 10), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_MMINFRA_SNOC, "mminfra_snoc", mminfra_snoc_parents, + CKSYS2_CLK_CFG_5, CKSYS2_CLK_CFG_5_SET, CKSYS2_CLK_CFG_5_CLR, + MM_HWV_CG_35_DONE, MM_HWV_CG_35_SET, MM_HWV_CG_35_CLR, + 16, 4, 23, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_MMINFRA_SNOC_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 9), + MUX_GATE_FENC_CLR_SET_UPD(CLK_TOP2_MMUP, "mmup", mmup_parents, + CKSYS2_CLK_CFG_5, CKSYS2_CLK_CFG_5_SET, CKSYS2_CLK_CFG_5_CLR, + 24, 3, 31, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_MMUP_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 8), + /* CKSYS2_CLK_CFG_6 */ + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_TOP2_MMINFRA_AO, "mminfra_ao", mminfra_ao_parents, + CKSYS2_CLK_CFG_6, CKSYS2_CLK_CFG_6_SET, CKSYS2_CLK_CFG_6_CLR, + MM_HWV_CG_36_DONE, MM_HWV_CG_36_SET, MM_HWV_CG_36_CLR, + 16, 2, 7, CKSYS2_CLK_CFG_UPDATE, TOP_MUX_MMINFRA_AO_SHIFT, + CKSYS2_CLK_FENC_STATUS_MON_0, 5), +}; + +static const struct mtk_clk_desc topck_desc = { + .factor_clks = top_divs, + .num_factor_clks = ARRAY_SIZE(top_divs), + .mux_clks = top_muxes, + .num_mux_clks = ARRAY_SIZE(top_muxes), +}; + +static const struct of_device_id of_match_clk_mt8196_ck[] = { + { .compatible = "mediatek,mt8196-topckgen-gp2", .data = &topck_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_ck); + +static struct platform_driver clk_mt8196_topck_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8196-topck2", + .of_match_table = of_match_clk_mt8196_ck, + }, +}; + +MODULE_DESCRIPTION("MediaTek MT8196 GP2 top clock generators driver"); +module_platform_driver(clk_mt8196_topck_drv); +MODULE_LICENSE("GPL"); From 2f8b3ae6f0cb189c067f18480caf4bd52e1cc21d Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:33 +0200 Subject: [PATCH 1847/2711] clk: mediatek: Add MT8196 vlpckgen clock support Add support for the MT8196 vlpckgen clock controller, which provides muxes and dividers for clock selection in other IP blocks. Reviewed-by: Chen-Yu Tsai Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Makefile | 2 +- drivers/clk/mediatek/clk-mt8196-vlpckgen.c | 725 +++++++++++++++++++++ 2 files changed, 726 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mediatek/clk-mt8196-vlpckgen.c diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index c415453e02fd..031e7ac38804 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -151,7 +151,7 @@ obj-$(CONFIG_COMMON_CLK_MT8195_VENCSYS) += clk-mt8195-venc.o obj-$(CONFIG_COMMON_CLK_MT8195_VPPSYS) += clk-mt8195-vpp0.o clk-mt8195-vpp1.o obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o \ - clk-mt8196-topckgen2.o + clk-mt8196-topckgen2.o clk-mt8196-vlpckgen.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o diff --git a/drivers/clk/mediatek/clk-mt8196-vlpckgen.c b/drivers/clk/mediatek/clk-mt8196-vlpckgen.c new file mode 100644 index 000000000000..d59a8a9d9855 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-vlpckgen.c @@ -0,0 +1,725 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-mux.h" +#include "clk-pll.h" + +/* MUX SEL REG */ +#define VLP_CLK_CFG_UPDATE 0x0004 +#define VLP_CLK_CFG_UPDATE1 0x0008 +#define VLP_CLK_CFG_0 0x0010 +#define VLP_CLK_CFG_0_SET 0x0014 +#define VLP_CLK_CFG_0_CLR 0x0018 +#define VLP_CLK_CFG_1 0x0020 +#define VLP_CLK_CFG_1_SET 0x0024 +#define VLP_CLK_CFG_1_CLR 0x0028 +#define VLP_CLK_CFG_2 0x0030 +#define VLP_CLK_CFG_2_SET 0x0034 +#define VLP_CLK_CFG_2_CLR 0x0038 +#define VLP_CLK_CFG_3 0x0040 +#define VLP_CLK_CFG_3_SET 0x0044 +#define VLP_CLK_CFG_3_CLR 0x0048 +#define VLP_CLK_CFG_4 0x0050 +#define VLP_CLK_CFG_4_SET 0x0054 +#define VLP_CLK_CFG_4_CLR 0x0058 +#define VLP_CLK_CFG_5 0x0060 +#define VLP_CLK_CFG_5_SET 0x0064 +#define VLP_CLK_CFG_5_CLR 0x0068 +#define VLP_CLK_CFG_6 0x0070 +#define VLP_CLK_CFG_6_SET 0x0074 +#define VLP_CLK_CFG_6_CLR 0x0078 +#define VLP_CLK_CFG_7 0x0080 +#define VLP_CLK_CFG_7_SET 0x0084 +#define VLP_CLK_CFG_7_CLR 0x0088 +#define VLP_CLK_CFG_8 0x0090 +#define VLP_CLK_CFG_8_SET 0x0094 +#define VLP_CLK_CFG_8_CLR 0x0098 +#define VLP_CLK_CFG_9 0x00a0 +#define VLP_CLK_CFG_9_SET 0x00a4 +#define VLP_CLK_CFG_9_CLR 0x00a8 +#define VLP_CLK_CFG_10 0x00b0 +#define VLP_CLK_CFG_10_SET 0x00b4 +#define VLP_CLK_CFG_10_CLR 0x00b8 +#define VLP_OCIC_FENC_STATUS_MON_0 0x039c +#define VLP_OCIC_FENC_STATUS_MON_1 0x03a0 + +/* MUX SHIFT */ +#define TOP_MUX_SCP_SHIFT 0 +#define TOP_MUX_SCP_SPI_SHIFT 1 +#define TOP_MUX_SCP_IIC_SHIFT 2 +#define TOP_MUX_SCP_IIC_HS_SHIFT 3 +#define TOP_MUX_PWRAP_ULPOSC_SHIFT 4 +#define TOP_MUX_SPMI_M_TIA_32K_SHIFT 5 +#define TOP_MUX_APXGPT_26M_B_SHIFT 6 +#define TOP_MUX_DPSW_SHIFT 7 +#define TOP_MUX_DPSW_CENTRAL_SHIFT 8 +#define TOP_MUX_SPMI_M_MST_SHIFT 9 +#define TOP_MUX_DVFSRC_SHIFT 10 +#define TOP_MUX_PWM_VLP_SHIFT 11 +#define TOP_MUX_AXI_VLP_SHIFT 12 +#define TOP_MUX_SYSTIMER_26M_SHIFT 13 +#define TOP_MUX_SSPM_SHIFT 14 +#define TOP_MUX_SRCK_SHIFT 15 +#define TOP_MUX_CAMTG0_SHIFT 16 +#define TOP_MUX_CAMTG1_SHIFT 17 +#define TOP_MUX_CAMTG2_SHIFT 18 +#define TOP_MUX_CAMTG3_SHIFT 19 +#define TOP_MUX_CAMTG4_SHIFT 20 +#define TOP_MUX_CAMTG5_SHIFT 21 +#define TOP_MUX_CAMTG6_SHIFT 22 +#define TOP_MUX_CAMTG7_SHIFT 23 +#define TOP_MUX_SSPM_26M_SHIFT 25 +#define TOP_MUX_ULPOSC_SSPM_SHIFT 26 +#define TOP_MUX_VLP_PBUS_26M_SHIFT 27 +#define TOP_MUX_DEBUG_ERR_FLAG_VLP_26M_SHIFT 28 +#define TOP_MUX_DPMSRDMA_SHIFT 29 +#define TOP_MUX_VLP_PBUS_156M_SHIFT 30 +#define TOP_MUX_SPM_SHIFT 0 +#define TOP_MUX_MMINFRA_VLP_SHIFT 1 +#define TOP_MUX_USB_TOP_SHIFT 2 +#define TOP_MUX_SSUSB_XHCI_SHIFT 3 +#define TOP_MUX_NOC_VLP_SHIFT 4 +#define TOP_MUX_AUDIO_H_SHIFT 5 +#define TOP_MUX_AUD_ENGEN1_SHIFT 6 +#define TOP_MUX_AUD_ENGEN2_SHIFT 7 +#define TOP_MUX_AUD_INTBUS_SHIFT 8 +#define TOP_MUX_SPU_VLP_26M_SHIFT 9 +#define TOP_MUX_SPU0_VLP_SHIFT 10 +#define TOP_MUX_SPU1_VLP_SHIFT 11 + +/* CKSTA REG */ +#define VLP_CKSTA_REG0 0x0250 +#define VLP_CKSTA_REG1 0x0254 + +/* HW Voter REG */ +#define HWV_CG_9_SET 0x0048 +#define HWV_CG_9_CLR 0x004c +#define HWV_CG_9_DONE 0x2c24 +#define HWV_CG_10_SET 0x0050 +#define HWV_CG_10_CLR 0x0054 +#define HWV_CG_10_DONE 0x2c28 + +/* PLL REG */ +#define VLP_AP_PLL_CON3 0x264 +#define VLP_APLL1_TUNER_CON0 0x2a4 +#define VLP_APLL2_TUNER_CON0 0x2a8 +#define VLP_APLL1_CON0 0x274 +#define VLP_APLL1_CON1 0x278 +#define VLP_APLL1_CON2 0x27c +#define VLP_APLL1_CON3 0x280 +#define VLP_APLL2_CON0 0x28c +#define VLP_APLL2_CON1 0x290 +#define VLP_APLL2_CON2 0x294 +#define VLP_APLL2_CON3 0x298 + +/* vlp apll1 tuner default value*/ +#define VLP_APLL1_TUNER_CON0_VALUE 0x6f28bd4d +/* vlp apll2 tuner default value + 1*/ +#define VLP_APLL2_TUNER_CON0_VALUE 0x78fd5265 + +#define VLP_PLLEN_ALL 0x080 +#define VLP_PLLEN_ALL_SET 0x084 +#define VLP_PLLEN_ALL_CLR 0x088 + +#define MT8196_PLL_FMAX (3800UL * MHZ) +#define MT8196_PLL_FMIN (1500UL * MHZ) +#define MT8196_INTEGER_BITS 8 + +#define PLL_FENC(_id, _name, _reg, _fenc_sta_ofs, _fenc_sta_bit,\ + _flags, _pd_reg, _pd_shift, \ + _pcw_reg, _pcw_shift, _pcwbits, \ + _pll_en_bit) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .fenc_sta_ofs = _fenc_sta_ofs, \ + .fenc_sta_bit = _fenc_sta_bit, \ + .flags = _flags, \ + .fmax = MT8196_PLL_FMAX, \ + .fmin = MT8196_PLL_FMIN, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .pcwbits = _pcwbits, \ + .pcwibits = MT8196_INTEGER_BITS, \ + .en_reg = VLP_PLLEN_ALL, \ + .en_set_reg = VLP_PLLEN_ALL_SET, \ + .en_clr_reg = VLP_PLLEN_ALL_CLR, \ + .pll_en_bit = _pll_en_bit, \ + .ops = &mtk_pll_fenc_clr_set_ops, \ +} + +static DEFINE_SPINLOCK(mt8196_clk_vlp_lock); + +static const struct mtk_fixed_factor vlp_divs[] = { + FACTOR(CLK_VLP_CLK26M, "vlp_clk26m", "clk26m", 1, 1), + FACTOR(CLK_VLP_APLL1_D4, "apll1_d4", "vlp_apll1", 1, 4), + FACTOR(CLK_VLP_APLL1_D8, "apll1_d8", "vlp_apll1", 1, 8), + FACTOR(CLK_VLP_APLL2_D4, "apll2_d4", "vlp_apll2", 1, 4), + FACTOR(CLK_VLP_APLL2_D8, "apll2_d8", "vlp_apll2", 1, 8), +}; + +static const char * const vlp_scp_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d6", + "mainpll_d4", + "mainpll_d3", + "vlp_apll1" +}; + +static const char * const vlp_scp_spi_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d7_d2", + "mainpll_d5_d2" +}; + +static const char * const vlp_scp_iic_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d5_d4", + "mainpll_d7_d2" +}; + +static const char * const vlp_scp_iic_hs_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d5_d4", + "mainpll_d7_d2", + "mainpll_d7" +}; + +static const char * const vlp_pwrap_ulposc_parents[] = { + "clk26m", + "osc_d20", + "osc_d14", + "osc_d10" +}; + +static const char * const vlp_spmi_32k_parents[] = { + "clk26m", + "clk32k", + "osc_d20", + "osc_d14", + "osc_d10" +}; + +static const char * const vlp_apxgpt_26m_b_parents[] = { + "clk26m", + "osc_d20" +}; + +static const char * const vlp_dpsw_parents[] = { + "clk26m", + "osc_d10", + "osc_d7", + "mainpll_d7_d4" +}; + +static const char * const vlp_dpsw_central_parents[] = { + "clk26m", + "osc_d10", + "osc_d7", + "mainpll_d7_d4" +}; + +static const char * const vlp_spmi_m_parents[] = { + "clk26m", + "osc_d20", + "osc_d14", + "osc_d10" +}; + +static const char * const vlp_dvfsrc_parents[] = { + "clk26m", + "osc_d20" +}; + +static const char * const vlp_pwm_vlp_parents[] = { + "clk26m", + "clk32k", + "osc_d20", + "osc_d8", + "mainpll_d4_d8" +}; + +static const char * const vlp_axi_vlp_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d7_d4", + "osc_d4", + "mainpll_d7_d2" +}; + +static const char * const vlp_systimer_26m_parents[] = { + "clk26m", + "osc_d20" +}; + +static const char * const vlp_sspm_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d5_d2", + "osc_d2", + "mainpll_d6" +}; + +static const char * const vlp_srck_parents[] = { + "clk26m", + "osc_d20" +}; + +static const char * const vlp_camtg0_1_parents[] = { + "clk26m", + "univpll_192m_d32", + "univpll_192m_d16", + "clk13m", + "osc_d40", + "osc_d32", + "univpll_192m_d10", + "univpll_192m_d8", + "univpll_d6_d16", + "ulposc3", + "osc_d20", + "ck2_tvdpll1_d16", + "univpll_d6_d8" +}; + +static const char * const vlp_camtg2_7_parents[] = { + "clk26m", + "univpll_192m_d32", + "univpll_192m_d16", + "clk13m", + "osc_d40", + "osc_d32", + "univpll_192m_d10", + "univpll_192m_d8", + "univpll_d6_d16", + "osc_d20", + "ck2_tvdpll1_d16", + "univpll_d6_d8" +}; + +static const char * const vlp_sspm_26m_parents[] = { + "clk26m", + "osc_d20" +}; + +static const char * const vlp_ulposc_sspm_parents[] = { + "clk26m", + "osc_d2", + "mainpll_d4_d2" +}; + +static const char * const vlp_vlp_pbus_26m_parents[] = { + "clk26m", + "osc_d20" +}; + +static const char * const vlp_debug_err_flag_parents[] = { + "clk26m", + "osc_d20" +}; + +static const char * const vlp_dpmsrdma_parents[] = { + "clk26m", + "mainpll_d7_d2" +}; + +static const char * const vlp_vlp_pbus_156m_parents[] = { + "clk26m", + "osc_d2", + "mainpll_d7_d2", + "mainpll_d7" +}; + +static const char * const vlp_spm_parents[] = { + "clk26m", + "mainpll_d7_d4" +}; + +static const char * const vlp_mminfra_parents[] = { + "clk26m", + "osc_d4", + "mainpll_d3" +}; + +static const char * const vlp_usb_parents[] = { + "clk26m", + "mainpll_d9" +}; + +static const char * const vlp_noc_vlp_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d9" +}; + +static const char * const vlp_audio_h_parents[] = { + "vlp_clk26m", + "vlp_apll1", + "vlp_apll2" +}; + +static const char * const vlp_aud_engen1_parents[] = { + "vlp_clk26m", + "apll1_d8", + "apll1_d4" +}; + +static const char * const vlp_aud_engen2_parents[] = { + "vlp_clk26m", + "apll2_d8", + "apll2_d4" +}; + +static const char * const vlp_aud_intbus_parents[] = { + "vlp_clk26m", + "mainpll_d7_d4", + "mainpll_d4_d4" +}; + +static const u8 vlp_aud_parent_index[] = { 1, 2, 3 }; + +static const char * const vlp_spvlp_26m_parents[] = { + "clk26m", + "osc_d20" +}; + +static const char * const vlp_spu0_vlp_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d4_d4", + "mainpll_d4_d2", + "mainpll_d7", + "mainpll_d6", + "mainpll_d5" +}; + +static const char * const vlp_spu1_vlp_parents[] = { + "clk26m", + "osc_d20", + "mainpll_d4_d4", + "mainpll_d4_d2", + "mainpll_d7", + "mainpll_d6", + "mainpll_d5" +}; + +static const struct mtk_mux vlp_muxes[] = { + /* VLP_CLK_CFG_0 */ + MUX_GATE_FENC_CLR_SET_UPD(CLK_VLP_SCP, "vlp_scp", vlp_scp_parents, + VLP_CLK_CFG_0, VLP_CLK_CFG_0_SET, VLP_CLK_CFG_0_CLR, + 0, 3, 7, VLP_CLK_CFG_UPDATE, TOP_MUX_SCP_SHIFT, + VLP_OCIC_FENC_STATUS_MON_0, 31), + MUX_CLR_SET_UPD(CLK_VLP_SCP_SPI, "vlp_scp_spi", + vlp_scp_spi_parents, VLP_CLK_CFG_0, VLP_CLK_CFG_0_SET, + VLP_CLK_CFG_0_CLR, 8, 2, + VLP_CLK_CFG_UPDATE, TOP_MUX_SCP_SPI_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_SCP_IIC, "vlp_scp_iic", + vlp_scp_iic_parents, VLP_CLK_CFG_0, VLP_CLK_CFG_0_SET, + VLP_CLK_CFG_0_CLR, 16, 2, + VLP_CLK_CFG_UPDATE, TOP_MUX_SCP_IIC_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_SCP_IIC_HS, "vlp_scp_iic_hs", + vlp_scp_iic_hs_parents, VLP_CLK_CFG_0, VLP_CLK_CFG_0_SET, + VLP_CLK_CFG_0_CLR, 24, 3, + VLP_CLK_CFG_UPDATE, TOP_MUX_SCP_IIC_HS_SHIFT), + /* VLP_CLK_CFG_1 */ + MUX_CLR_SET_UPD(CLK_VLP_PWRAP_ULPOSC, "vlp_pwrap_ulposc", + vlp_pwrap_ulposc_parents, VLP_CLK_CFG_1, VLP_CLK_CFG_1_SET, + VLP_CLK_CFG_1_CLR, 0, 2, + VLP_CLK_CFG_UPDATE, TOP_MUX_PWRAP_ULPOSC_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_SPMI_M_TIA_32K, "vlp_spmi_32k", + vlp_spmi_32k_parents, VLP_CLK_CFG_1, VLP_CLK_CFG_1_SET, + VLP_CLK_CFG_1_CLR, 8, 3, + VLP_CLK_CFG_UPDATE, TOP_MUX_SPMI_M_TIA_32K_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_APXGPT_26M_B, "vlp_apxgpt_26m_b", + vlp_apxgpt_26m_b_parents, VLP_CLK_CFG_1, VLP_CLK_CFG_1_SET, + VLP_CLK_CFG_1_CLR, 16, 1, + VLP_CLK_CFG_UPDATE, TOP_MUX_APXGPT_26M_B_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_DPSW, "vlp_dpsw", + vlp_dpsw_parents, VLP_CLK_CFG_1, VLP_CLK_CFG_1_SET, + VLP_CLK_CFG_1_CLR, 24, 2, + VLP_CLK_CFG_UPDATE, TOP_MUX_DPSW_SHIFT), + /* VLP_CLK_CFG_2 */ + MUX_CLR_SET_UPD(CLK_VLP_DPSW_CENTRAL, "vlp_dpsw_central", + vlp_dpsw_central_parents, VLP_CLK_CFG_2, VLP_CLK_CFG_2_SET, + VLP_CLK_CFG_2_CLR, 0, 2, + VLP_CLK_CFG_UPDATE, TOP_MUX_DPSW_CENTRAL_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_SPMI_M_MST, "vlp_spmi_m", + vlp_spmi_m_parents, VLP_CLK_CFG_2, VLP_CLK_CFG_2_SET, + VLP_CLK_CFG_2_CLR, 8, 2, + VLP_CLK_CFG_UPDATE, TOP_MUX_SPMI_M_MST_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_DVFSRC, "vlp_dvfsrc", + vlp_dvfsrc_parents, VLP_CLK_CFG_2, VLP_CLK_CFG_2_SET, + VLP_CLK_CFG_2_CLR, 16, 1, + VLP_CLK_CFG_UPDATE, TOP_MUX_DVFSRC_SHIFT), + MUX_GATE_FENC_CLR_SET_UPD(CLK_VLP_PWM_VLP, "vlp_pwm_vlp", vlp_pwm_vlp_parents, + VLP_CLK_CFG_2, VLP_CLK_CFG_2_SET, VLP_CLK_CFG_2_CLR, + 24, 3, 31, VLP_CLK_CFG_UPDATE, TOP_MUX_PWM_VLP_SHIFT, + VLP_OCIC_FENC_STATUS_MON_0, 20), + /* VLP_CLK_CFG_3 */ + MUX_CLR_SET_UPD(CLK_VLP_AXI_VLP, "vlp_axi_vlp", + vlp_axi_vlp_parents, VLP_CLK_CFG_3, VLP_CLK_CFG_3_SET, + VLP_CLK_CFG_3_CLR, 0, 3, + VLP_CLK_CFG_UPDATE, TOP_MUX_AXI_VLP_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_SYSTIMER_26M, "vlp_systimer_26m", + vlp_systimer_26m_parents, VLP_CLK_CFG_3, VLP_CLK_CFG_3_SET, + VLP_CLK_CFG_3_CLR, 8, 1, + VLP_CLK_CFG_UPDATE, TOP_MUX_SYSTIMER_26M_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_SSPM, "vlp_sspm", + vlp_sspm_parents, VLP_CLK_CFG_3, VLP_CLK_CFG_3_SET, + VLP_CLK_CFG_3_CLR, 16, 3, + VLP_CLK_CFG_UPDATE, TOP_MUX_SSPM_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_SRCK, "vlp_srck", + vlp_srck_parents, VLP_CLK_CFG_3, VLP_CLK_CFG_3_SET, + VLP_CLK_CFG_3_CLR, 24, 1, + VLP_CLK_CFG_UPDATE, TOP_MUX_SRCK_SHIFT), + /* VLP_CLK_CFG_4 */ + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG0, "vlp_camtg0", vlp_camtg0_1_parents, + VLP_CLK_CFG_4, VLP_CLK_CFG_4_SET, VLP_CLK_CFG_4_CLR, + HWV_CG_9_DONE, HWV_CG_9_SET, HWV_CG_9_CLR, + 0, 4, 7, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG0_SHIFT, + VLP_OCIC_FENC_STATUS_MON_0, 15), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG1, "vlp_camtg1", vlp_camtg0_1_parents, + VLP_CLK_CFG_4, VLP_CLK_CFG_4_SET, VLP_CLK_CFG_4_CLR, + HWV_CG_9_DONE, HWV_CG_9_SET, HWV_CG_9_CLR, + 8, 4, 15, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG1_SHIFT, + VLP_OCIC_FENC_STATUS_MON_0, 14), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG2, "vlp_camtg2", vlp_camtg2_7_parents, + VLP_CLK_CFG_4, VLP_CLK_CFG_4_SET, VLP_CLK_CFG_4_CLR, + HWV_CG_9_DONE, HWV_CG_9_SET, HWV_CG_9_CLR, + 16, 4, 23, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG2_SHIFT, + VLP_OCIC_FENC_STATUS_MON_0, 13), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG3, "vlp_camtg3", vlp_camtg2_7_parents, + VLP_CLK_CFG_4, VLP_CLK_CFG_4_SET, VLP_CLK_CFG_4_CLR, + HWV_CG_9_DONE, HWV_CG_9_SET, HWV_CG_9_CLR, + 24, 4, 31, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG3_SHIFT, + VLP_OCIC_FENC_STATUS_MON_0, 12), + /* VLP_CLK_CFG_5 */ + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG4, "vlp_camtg4", vlp_camtg2_7_parents, + VLP_CLK_CFG_5, VLP_CLK_CFG_5_SET, VLP_CLK_CFG_5_CLR, + HWV_CG_10_DONE, HWV_CG_10_SET, HWV_CG_10_CLR, + 0, 4, 7, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG4_SHIFT, + VLP_OCIC_FENC_STATUS_MON_0, 11), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG5, "vlp_camtg5", vlp_camtg2_7_parents, + VLP_CLK_CFG_5, VLP_CLK_CFG_5_SET, VLP_CLK_CFG_5_CLR, + HWV_CG_10_DONE, HWV_CG_10_SET, HWV_CG_10_CLR, + 8, 4, 15, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG5_SHIFT, + VLP_OCIC_FENC_STATUS_MON_0, 10), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG6, "vlp_camtg6", vlp_camtg2_7_parents, + VLP_CLK_CFG_5, VLP_CLK_CFG_5_SET, VLP_CLK_CFG_5_CLR, + HWV_CG_10_DONE, HWV_CG_10_SET, HWV_CG_10_CLR, + 16, 4, 23, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG6_SHIFT, + VLP_OCIC_FENC_STATUS_MON_0, 9), + MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG7, "vlp_camtg7", vlp_camtg2_7_parents, + VLP_CLK_CFG_5, VLP_CLK_CFG_5_SET, VLP_CLK_CFG_5_CLR, + HWV_CG_10_DONE, HWV_CG_10_SET, HWV_CG_10_CLR, + 24, 4, 31, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG7_SHIFT, + VLP_OCIC_FENC_STATUS_MON_0, 8), + /* VLP_CLK_CFG_6 */ + MUX_CLR_SET_UPD(CLK_VLP_SSPM_26M, "vlp_sspm_26m", + vlp_sspm_26m_parents, VLP_CLK_CFG_6, VLP_CLK_CFG_6_SET, + VLP_CLK_CFG_6_CLR, 8, 1, + VLP_CLK_CFG_UPDATE, TOP_MUX_SSPM_26M_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_ULPOSC_SSPM, "vlp_ulposc_sspm", + vlp_ulposc_sspm_parents, VLP_CLK_CFG_6, VLP_CLK_CFG_6_SET, + VLP_CLK_CFG_6_CLR, 16, 2, + VLP_CLK_CFG_UPDATE, TOP_MUX_ULPOSC_SSPM_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_VLP_PBUS_26M, "vlp_vlp_pbus_26m", + vlp_vlp_pbus_26m_parents, VLP_CLK_CFG_6, VLP_CLK_CFG_6_SET, + VLP_CLK_CFG_6_CLR, 24, 1, + VLP_CLK_CFG_UPDATE, TOP_MUX_VLP_PBUS_26M_SHIFT), + /* VLP_CLK_CFG_7 */ + MUX_CLR_SET_UPD(CLK_VLP_DEBUG_ERR_FLAG, "vlp_debug_err_flag", + vlp_debug_err_flag_parents, VLP_CLK_CFG_7, VLP_CLK_CFG_7_SET, + VLP_CLK_CFG_7_CLR, 0, 1, + VLP_CLK_CFG_UPDATE, TOP_MUX_DEBUG_ERR_FLAG_VLP_26M_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_DPMSRDMA, "vlp_dpmsrdma", + vlp_dpmsrdma_parents, VLP_CLK_CFG_7, VLP_CLK_CFG_7_SET, + VLP_CLK_CFG_7_CLR, 8, 1, + VLP_CLK_CFG_UPDATE, TOP_MUX_DPMSRDMA_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_VLP_PBUS_156M, "vlp_vlp_pbus_156m", + vlp_vlp_pbus_156m_parents, VLP_CLK_CFG_7, VLP_CLK_CFG_7_SET, + VLP_CLK_CFG_7_CLR, 16, 2, + VLP_CLK_CFG_UPDATE, TOP_MUX_VLP_PBUS_156M_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_SPM, "vlp_spm", + vlp_spm_parents, VLP_CLK_CFG_7, VLP_CLK_CFG_7_SET, + VLP_CLK_CFG_7_CLR, 24, 1, + VLP_CLK_CFG_UPDATE1, TOP_MUX_SPM_SHIFT), + /* VLP_CLK_CFG_8 */ + MUX_GATE_FENC_CLR_SET_UPD(CLK_VLP_MMINFRA, "vlp_mminfra", vlp_mminfra_parents, + VLP_CLK_CFG_8, VLP_CLK_CFG_8_SET, VLP_CLK_CFG_8_CLR, + 0, 2, 7, VLP_CLK_CFG_UPDATE1, TOP_MUX_MMINFRA_VLP_SHIFT, + VLP_OCIC_FENC_STATUS_MON_1, 31), + MUX_GATE_FENC_CLR_SET_UPD(CLK_VLP_USB_TOP, "vlp_usb", vlp_usb_parents, + VLP_CLK_CFG_8, VLP_CLK_CFG_8_SET, VLP_CLK_CFG_8_CLR, + 8, 1, 15, VLP_CLK_CFG_UPDATE1, TOP_MUX_USB_TOP_SHIFT, + VLP_OCIC_FENC_STATUS_MON_1, 30), + MUX_GATE_FENC_CLR_SET_UPD(CLK_VLP_USB_XHCI, "vlp_usb_xhci", vlp_usb_parents, + VLP_CLK_CFG_8, VLP_CLK_CFG_8_SET, VLP_CLK_CFG_8_CLR, + 16, 1, 23, VLP_CLK_CFG_UPDATE1, TOP_MUX_SSUSB_XHCI_SHIFT, + VLP_OCIC_FENC_STATUS_MON_1, 29), + MUX_CLR_SET_UPD(CLK_VLP_NOC_VLP, "vlp_noc_vlp", + vlp_noc_vlp_parents, VLP_CLK_CFG_8, VLP_CLK_CFG_8_SET, + VLP_CLK_CFG_8_CLR, 24, 2, + VLP_CLK_CFG_UPDATE1, TOP_MUX_NOC_VLP_SHIFT), + /* VLP_CLK_CFG_9 */ + MUX_GATE_FENC_CLR_SET_UPD_INDEXED(CLK_VLP_AUDIO_H, "vlp_audio_h", + vlp_audio_h_parents, vlp_aud_parent_index, + VLP_CLK_CFG_9, VLP_CLK_CFG_9_SET, VLP_CLK_CFG_9_CLR, + 0, 2, 7, VLP_CLK_CFG_UPDATE1, TOP_MUX_AUDIO_H_SHIFT, + VLP_OCIC_FENC_STATUS_MON_1, 27), + MUX_GATE_FENC_CLR_SET_UPD_INDEXED(CLK_VLP_AUD_ENGEN1, "vlp_aud_engen1", + vlp_aud_engen1_parents, vlp_aud_parent_index, + VLP_CLK_CFG_9, VLP_CLK_CFG_9_SET, VLP_CLK_CFG_9_CLR, + 8, 2, 15, VLP_CLK_CFG_UPDATE1, TOP_MUX_AUD_ENGEN1_SHIFT, + VLP_OCIC_FENC_STATUS_MON_1, 26), + MUX_GATE_FENC_CLR_SET_UPD_INDEXED(CLK_VLP_AUD_ENGEN2, "vlp_aud_engen2", + vlp_aud_engen2_parents, vlp_aud_parent_index, + VLP_CLK_CFG_9, VLP_CLK_CFG_9_SET, VLP_CLK_CFG_9_CLR, + 16, 2, 23, VLP_CLK_CFG_UPDATE1, TOP_MUX_AUD_ENGEN2_SHIFT, + VLP_OCIC_FENC_STATUS_MON_1, 25), + MUX_GATE_FENC_CLR_SET_UPD_INDEXED(CLK_VLP_AUD_INTBUS, "vlp_aud_intbus", + vlp_aud_intbus_parents, vlp_aud_parent_index, + VLP_CLK_CFG_9, VLP_CLK_CFG_9_SET, VLP_CLK_CFG_9_CLR, + 24, 2, 31, VLP_CLK_CFG_UPDATE1, TOP_MUX_AUD_INTBUS_SHIFT, + VLP_OCIC_FENC_STATUS_MON_1, 24), + /* VLP_CLK_CFG_10 */ + MUX_CLR_SET_UPD(CLK_VLP_SPVLP_26M, "vlp_spvlp_26m", + vlp_spvlp_26m_parents, VLP_CLK_CFG_10, VLP_CLK_CFG_10_SET, + VLP_CLK_CFG_10_CLR, 0, 1, + VLP_CLK_CFG_UPDATE1, TOP_MUX_SPU_VLP_26M_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_SPU0_VLP, "vlp_spu0_vlp", + vlp_spu0_vlp_parents, VLP_CLK_CFG_10, VLP_CLK_CFG_10_SET, + VLP_CLK_CFG_10_CLR, 8, 3, + VLP_CLK_CFG_UPDATE1, TOP_MUX_SPU0_VLP_SHIFT), + MUX_CLR_SET_UPD(CLK_VLP_SPU1_VLP, "vlp_spu1_vlp", + vlp_spu1_vlp_parents, VLP_CLK_CFG_10, VLP_CLK_CFG_10_SET, + VLP_CLK_CFG_10_CLR, 16, 3, + VLP_CLK_CFG_UPDATE1, TOP_MUX_SPU1_VLP_SHIFT), +}; + +static const struct mtk_pll_data vlp_plls[] = { + PLL_FENC(CLK_VLP_APLL1, "vlp_apll1", VLP_APLL1_CON0, 0x0358, 1, 0, + VLP_APLL1_CON1, 24, VLP_APLL1_CON2, 0, 32, 0), + PLL_FENC(CLK_VLP_APLL2, "vlp_apll2", VLP_APLL2_CON0, 0x0358, 0, 0, + VLP_APLL2_CON1, 24, VLP_APLL2_CON2, 0, 32, 1), +}; + +static const struct regmap_config vlpckgen_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x1000, + .fast_io = true, +}; + +static int clk_mt8196_vlp_probe(struct platform_device *pdev) +{ + static void __iomem *base; + struct clk_hw_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct regmap *regmap; + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(vlp_muxes) + + ARRAY_SIZE(vlp_plls) + + ARRAY_SIZE(vlp_divs)); + if (!clk_data) + return -ENOMEM; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(dev, base, &vlpckgen_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + r = mtk_clk_register_factors(vlp_divs, ARRAY_SIZE(vlp_divs), clk_data); + if (r) + goto free_clk_data; + + r = mtk_clk_register_muxes(&pdev->dev, vlp_muxes, ARRAY_SIZE(vlp_muxes), + node, &mt8196_clk_vlp_lock, clk_data); + if (r) + goto unregister_factors; + + r = mtk_clk_register_plls(node, vlp_plls, ARRAY_SIZE(vlp_plls), + clk_data); + if (r) + goto unregister_muxes; + + r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (r) + goto unregister_plls; + + platform_set_drvdata(pdev, clk_data); + + /* Initialize APLL tuner registers */ + regmap_write(regmap, VLP_APLL1_TUNER_CON0, VLP_APLL1_TUNER_CON0_VALUE); + regmap_write(regmap, VLP_APLL2_TUNER_CON0, VLP_APLL2_TUNER_CON0_VALUE); + + return r; + +unregister_plls: + mtk_clk_unregister_plls(vlp_plls, ARRAY_SIZE(vlp_plls), clk_data); +unregister_muxes: + mtk_clk_unregister_muxes(vlp_muxes, ARRAY_SIZE(vlp_muxes), clk_data); +unregister_factors: + mtk_clk_unregister_factors(vlp_divs, ARRAY_SIZE(vlp_divs), clk_data); +free_clk_data: + mtk_free_clk_data(clk_data); + + return r; +} + +static void clk_mt8196_vlp_remove(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + + of_clk_del_provider(node); + mtk_clk_unregister_plls(vlp_plls, ARRAY_SIZE(vlp_plls), clk_data); + mtk_clk_unregister_muxes(vlp_muxes, ARRAY_SIZE(vlp_muxes), clk_data); + mtk_clk_unregister_factors(vlp_divs, ARRAY_SIZE(vlp_divs), clk_data); + mtk_free_clk_data(clk_data); +} + +static const struct of_device_id of_match_clk_mt8196_vlp_ck[] = { + { .compatible = "mediatek,mt8196-vlpckgen" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_vlp_ck); + +static struct platform_driver clk_mt8196_vlp_drv = { + .probe = clk_mt8196_vlp_probe, + .remove = clk_mt8196_vlp_remove, + .driver = { + .name = "clk-mt8196-vlpck", + .of_match_table = of_match_clk_mt8196_vlp_ck, + }, +}; + +MODULE_DESCRIPTION("MediaTek MT8196 VLP clock generator driver"); +module_platform_driver(clk_mt8196_vlp_drv); +MODULE_LICENSE("GPL"); From 212779900009b7658acc191432236746145a1ac2 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:34 +0200 Subject: [PATCH 1848/2711] clk: mediatek: Add MT8196 peripheral clock support Add support for the MT8196 peripheral clock controller, which provides clock gate control for dma/flashif/msdc/pwm/spi/uart. Reviewed-by: Chen-Yu Tsai # CLK_OPS_PARENT_ENABLE change Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Makefile | 3 +- drivers/clk/mediatek/clk-mt8196-peri_ao.c | 142 ++++++++++++++++++++++ 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mediatek/clk-mt8196-peri_ao.c diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 031e7ac38804..8888ffd3d7ba 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -151,7 +151,8 @@ obj-$(CONFIG_COMMON_CLK_MT8195_VENCSYS) += clk-mt8195-venc.o obj-$(CONFIG_COMMON_CLK_MT8195_VPPSYS) += clk-mt8195-vpp0.o clk-mt8195-vpp1.o obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o \ - clk-mt8196-topckgen2.o clk-mt8196-vlpckgen.o + clk-mt8196-topckgen2.o clk-mt8196-vlpckgen.o \ + clk-mt8196-peri_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o diff --git a/drivers/clk/mediatek/clk-mt8196-peri_ao.c b/drivers/clk/mediatek/clk-mt8196-peri_ao.c new file mode 100644 index 000000000000..f227a86c5d60 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-peri_ao.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs peri_ao0_cg_regs = { + .set_ofs = 0x24, + .clr_ofs = 0x28, + .sta_ofs = 0x10, +}; + +static const struct mtk_gate_regs peri_ao1_cg_regs = { + .set_ofs = 0x2c, + .clr_ofs = 0x30, + .sta_ofs = 0x14, +}; + +static const struct mtk_gate_regs peri_ao1_hwv_regs = { + .set_ofs = 0x0008, + .clr_ofs = 0x000c, + .sta_ofs = 0x2c04, +}; + +static const struct mtk_gate_regs peri_ao2_cg_regs = { + .set_ofs = 0x34, + .clr_ofs = 0x38, + .sta_ofs = 0x18, +}; + +#define GATE_PERI_AO0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri_ao0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_PERI_AO1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri_ao1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_HWV_PERI_AO1(_id, _name, _parent, _shift) {\ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri_ao1_cg_regs, \ + .hwv_regs = &peri_ao1_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + } + +#define GATE_PERI_AO2(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri_ao2_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate peri_ao_clks[] = { + /* PERI_AO0 */ + GATE_PERI_AO0(CLK_PERI_AO_UART0_BCLK, "peri_ao_uart0_bclk", "uart", 0), + GATE_PERI_AO0(CLK_PERI_AO_UART1_BCLK, "peri_ao_uart1_bclk", "uart", 1), + GATE_PERI_AO0(CLK_PERI_AO_UART2_BCLK, "peri_ao_uart2_bclk", "uart", 2), + GATE_PERI_AO0(CLK_PERI_AO_UART3_BCLK, "peri_ao_uart3_bclk", "uart", 3), + GATE_PERI_AO0(CLK_PERI_AO_UART4_BCLK, "peri_ao_uart4_bclk", "uart", 4), + GATE_PERI_AO0(CLK_PERI_AO_UART5_BCLK, "peri_ao_uart5_bclk", "uart", 5), + GATE_PERI_AO0(CLK_PERI_AO_PWM_X16W_HCLK, "peri_ao_pwm_x16w", "p_axi", 12), + GATE_PERI_AO0(CLK_PERI_AO_PWM_X16W_BCLK, "peri_ao_pwm_x16w_bclk", "pwm", 13), + GATE_PERI_AO0(CLK_PERI_AO_PWM_PWM_BCLK0, "peri_ao_pwm_pwm_bclk0", "pwm", 14), + GATE_PERI_AO0(CLK_PERI_AO_PWM_PWM_BCLK1, "peri_ao_pwm_pwm_bclk1", "pwm", 15), + GATE_PERI_AO0(CLK_PERI_AO_PWM_PWM_BCLK2, "peri_ao_pwm_pwm_bclk2", "pwm", 16), + GATE_PERI_AO0(CLK_PERI_AO_PWM_PWM_BCLK3, "peri_ao_pwm_pwm_bclk3", "pwm", 17), + /* PERI_AO1 */ + GATE_HWV_PERI_AO1(CLK_PERI_AO_SPI0_BCLK, "peri_ao_spi0_bclk", "spi0_b", 0), + GATE_HWV_PERI_AO1(CLK_PERI_AO_SPI1_BCLK, "peri_ao_spi1_bclk", "spi1_b", 2), + GATE_HWV_PERI_AO1(CLK_PERI_AO_SPI2_BCLK, "peri_ao_spi2_bclk", "spi2_b", 3), + GATE_HWV_PERI_AO1(CLK_PERI_AO_SPI3_BCLK, "peri_ao_spi3_bclk", "spi3_b", 4), + GATE_HWV_PERI_AO1(CLK_PERI_AO_SPI4_BCLK, "peri_ao_spi4_bclk", "spi4_b", 5), + GATE_HWV_PERI_AO1(CLK_PERI_AO_SPI5_BCLK, "peri_ao_spi5_bclk", "spi5_b", 6), + GATE_HWV_PERI_AO1(CLK_PERI_AO_SPI6_BCLK, "peri_ao_spi6_bclk", "spi6_b", 7), + GATE_HWV_PERI_AO1(CLK_PERI_AO_SPI7_BCLK, "peri_ao_spi7_bclk", "spi7_b", 8), + GATE_PERI_AO1(CLK_PERI_AO_FLASHIF_FLASH, "peri_ao_flashif_flash", "peri_ao_flashif_27m", + 18), + GATE_PERI_AO1(CLK_PERI_AO_FLASHIF_27M, "peri_ao_flashif_27m", "sflash", 19), + GATE_PERI_AO1(CLK_PERI_AO_FLASHIF_DRAM, "peri_ao_flashif_dram", "p_axi", 20), + GATE_PERI_AO1(CLK_PERI_AO_FLASHIF_AXI, "peri_ao_flashif_axi", "peri_ao_flashif_dram", 21), + GATE_PERI_AO1(CLK_PERI_AO_FLASHIF_BCLK, "peri_ao_flashif_bclk", "p_axi", 22), + GATE_PERI_AO1(CLK_PERI_AO_AP_DMA_X32W_BCLK, "peri_ao_ap_dma_x32w_bclk", "p_axi", 26), + /* PERI_AO2 */ + GATE_PERI_AO2(CLK_PERI_AO_MSDC1_MSDC_SRC, "peri_ao_msdc1_msdc_src", "msdc30_1", 1), + GATE_PERI_AO2(CLK_PERI_AO_MSDC1_HCLK, "peri_ao_msdc1", "peri_ao_msdc1_axi", 2), + GATE_PERI_AO2(CLK_PERI_AO_MSDC1_AXI, "peri_ao_msdc1_axi", "p_axi", 3), + GATE_PERI_AO2(CLK_PERI_AO_MSDC1_HCLK_WRAP, "peri_ao_msdc1_h_wrap", "peri_ao_msdc1", 4), + GATE_PERI_AO2(CLK_PERI_AO_MSDC2_MSDC_SRC, "peri_ao_msdc2_msdc_src", "msdc30_2", 10), + GATE_PERI_AO2(CLK_PERI_AO_MSDC2_HCLK, "peri_ao_msdc2", "peri_ao_msdc2_axi", 11), + GATE_PERI_AO2(CLK_PERI_AO_MSDC2_AXI, "peri_ao_msdc2_axi", "p_axi", 12), + GATE_PERI_AO2(CLK_PERI_AO_MSDC2_HCLK_WRAP, "peri_ao_msdc2_h_wrap", "peri_ao_msdc2", 13), +}; + +static const struct mtk_clk_desc peri_ao_mcd = { + .clks = peri_ao_clks, + .num_clks = ARRAY_SIZE(peri_ao_clks), +}; + +static const struct of_device_id of_match_clk_mt8196_peri_ao[] = { + { .compatible = "mediatek,mt8196-pericfg-ao", .data = &peri_ao_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_peri_ao); + +static struct platform_driver clk_mt8196_peri_ao_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8196-peri-ao", + .of_match_table = of_match_clk_mt8196_peri_ao, + }, +}; + +MODULE_DESCRIPTION("MediaTek MT8196 pericfg_ao clock controller driver"); +module_platform_driver(clk_mt8196_peri_ao_drv); +MODULE_LICENSE("GPL"); From a74d5e835a9ff3ac56c01e6235e3122b0208ad30 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:35 +0200 Subject: [PATCH 1849/2711] clk: mediatek: Add MT8196 ufssys clock support Add support for the MT8196 ufssys clock controller, which provides clock gate control for UFS. Co-developed-by: AngeloGioacchino Del Regno Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 7 ++ drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt8196-ufs_ao.c | 108 +++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8196-ufs_ao.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 1e0c6f177ecd..d99c39a7f10e 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1010,6 +1010,13 @@ config COMMON_CLK_MT8196 help This driver supports MediaTek MT8196 basic clocks. +config COMMON_CLK_MT8196_UFSSYS + tristate "Clock driver for MediaTek MT8196 ufssys" + depends on COMMON_CLK_MT8196 + default COMMON_CLK_MT8196 + help + This driver supports MediaTek MT8196 ufssys clocks. + config COMMON_CLK_MT8365 tristate "Clock driver for MediaTek MT8365" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 8888ffd3d7ba..1a497de00846 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -153,6 +153,7 @@ obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o \ clk-mt8196-topckgen2.o clk-mt8196-vlpckgen.o \ clk-mt8196-peri_ao.o +obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o diff --git a/drivers/clk/mediatek/clk-mt8196-ufs_ao.c b/drivers/clk/mediatek/clk-mt8196-ufs_ao.c new file mode 100644 index 000000000000..0c04717b7b4b --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-ufs_ao.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +#define MT8196_UFSAO_RST0_SET_OFFSET 0x48 +#define MT8196_UFSAO_RST1_SET_OFFSET 0x148 + +static const struct mtk_gate_regs ufsao0_cg_regs = { + .set_ofs = 0x108, + .clr_ofs = 0x10c, + .sta_ofs = 0x104, +}; + +static const struct mtk_gate_regs ufsao1_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0xc, + .sta_ofs = 0x4, +}; + +#define GATE_UFSAO0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ufsao0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_UFSAO1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ufsao1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate ufsao_clks[] = { + /* UFSAO0 */ + GATE_UFSAO0(CLK_UFSAO_UFSHCI_UFS, "ufsao_ufshci_ufs", "ufs", 0), + GATE_UFSAO0(CLK_UFSAO_UFSHCI_AES, "ufsao_ufshci_aes", "aes_ufsfde", 1), + /* UFSAO1 */ + GATE_UFSAO1(CLK_UFSAO_UNIPRO_TX_SYM, "ufsao_unipro_tx_sym", "clk26m", 0), + GATE_UFSAO1(CLK_UFSAO_UNIPRO_RX_SYM0, "ufsao_unipro_rx_sym0", "clk26m", 1), + GATE_UFSAO1(CLK_UFSAO_UNIPRO_RX_SYM1, "ufsao_unipro_rx_sym1", "clk26m", 2), + GATE_UFSAO1(CLK_UFSAO_UNIPRO_SYS, "ufsao_unipro_sys", "ufs", 3), + GATE_UFSAO1(CLK_UFSAO_UNIPRO_SAP, "ufsao_unipro_sap", "clk26m", 4), + GATE_UFSAO1(CLK_UFSAO_PHY_SAP, "ufsao_phy_sap", "clk26m", 8), +}; + +static u16 ufsao_rst_ofs[] = { + MT8196_UFSAO_RST0_SET_OFFSET, + MT8196_UFSAO_RST1_SET_OFFSET +}; + +static u16 ufsao_rst_idx_map[] = { + [MT8196_UFSAO_RST0_UFS_MPHY] = 8, + [MT8196_UFSAO_RST1_UFS_UNIPRO] = 1 * RST_NR_PER_BANK + 0, + [MT8196_UFSAO_RST1_UFS_CRYPTO] = 1 * RST_NR_PER_BANK + 1, + [MT8196_UFSAO_RST1_UFSHCI] = 1 * RST_NR_PER_BANK + 2, +}; + +static const struct mtk_clk_rst_desc ufsao_rst_desc = { + .version = MTK_RST_SET_CLR, + .rst_bank_ofs = ufsao_rst_ofs, + .rst_bank_nr = ARRAY_SIZE(ufsao_rst_ofs), + .rst_idx_map = ufsao_rst_idx_map, + .rst_idx_map_nr = ARRAY_SIZE(ufsao_rst_idx_map), +}; + +static const struct mtk_clk_desc ufsao_mcd = { + .clks = ufsao_clks, + .num_clks = ARRAY_SIZE(ufsao_clks), + .rst_desc = &ufsao_rst_desc, +}; + +static const struct of_device_id of_match_clk_mt8196_ufs_ao[] = { + { .compatible = "mediatek,mt8196-ufscfg-ao", .data = &ufsao_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_ufs_ao); + +static struct platform_driver clk_mt8196_ufs_ao_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8196-ufs-ao", + .of_match_table = of_match_clk_mt8196_ufs_ao, + }, +}; + +module_platform_driver(clk_mt8196_ufs_ao_drv); +MODULE_DESCRIPTION("MediaTek MT8196 ufs_ao clocks driver"); +MODULE_LICENSE("GPL"); From c9b9a66bde91b84157243f8a6fe6ac524868c199 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:36 +0200 Subject: [PATCH 1850/2711] clk: mediatek: Add MT8196 pextpsys clock support Add support for the MT8196 pextpsys clock controller, which provides clock gate control for PCIe. Co-developed-by: AngeloGioacchino Del Regno Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai # CLK_OPS_PARENT_ENABLE removal Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 7 ++ drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt8196-pextp.c | 131 ++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8196-pextp.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index d99c39a7f10e..c977719046a4 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1010,6 +1010,13 @@ config COMMON_CLK_MT8196 help This driver supports MediaTek MT8196 basic clocks. +config COMMON_CLK_MT8196_PEXTPSYS + tristate "Clock driver for MediaTek MT8196 pextpsys" + depends on COMMON_CLK_MT8196 + default COMMON_CLK_MT8196 + help + This driver supports MediaTek MT8196 pextpsys clocks. + config COMMON_CLK_MT8196_UFSSYS tristate "Clock driver for MediaTek MT8196 ufssys" depends on COMMON_CLK_MT8196 diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 1a497de00846..88f7d8a229c2 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -153,6 +153,7 @@ obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o \ clk-mt8196-topckgen2.o clk-mt8196-vlpckgen.o \ clk-mt8196-peri_ao.o +obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o diff --git a/drivers/clk/mediatek/clk-mt8196-pextp.c b/drivers/clk/mediatek/clk-mt8196-pextp.c new file mode 100644 index 000000000000..3e505ecc4b6e --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-pextp.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" +#include "reset.h" + +#define MT8196_PEXTP_RST0_SET_OFFSET 0x8 + +static const struct mtk_gate_regs pext_cg_regs = { + .set_ofs = 0x18, + .clr_ofs = 0x1c, + .sta_ofs = 0x14, +}; + +#define GATE_PEXT(_id, _name, _parent, _shift) {\ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &pext_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr,\ + } + +static const struct mtk_gate pext_clks[] = { + GATE_PEXT(CLK_PEXT_PEXTP_MAC_P0_TL, "pext_pm0_tl", "tl", 0), + GATE_PEXT(CLK_PEXT_PEXTP_MAC_P0_REF, "pext_pm0_ref", "clk26m", 1), + GATE_PEXT(CLK_PEXT_PEXTP_PHY_P0_MCU_BUS, "pext_pp0_mcu_bus", "clk26m", 6), + GATE_PEXT(CLK_PEXT_PEXTP_PHY_P0_PEXTP_REF, "pext_pp0_pextp_ref", "clk26m", 7), + GATE_PEXT(CLK_PEXT_PEXTP_MAC_P0_AXI_250, "pext_pm0_axi_250", "ufs_pexpt0_mem_sub", 12), + GATE_PEXT(CLK_PEXT_PEXTP_MAC_P0_AHB_APB, "pext_pm0_ahb_apb", "ufs_pextp0_axi", 13), + GATE_PEXT(CLK_PEXT_PEXTP_MAC_P0_PL_P, "pext_pm0_pl_p", "clk26m", 14), + GATE_PEXT(CLK_PEXT_PEXTP_VLP_AO_P0_LP, "pext_pextp_vlp_ao_p0_lp", "clk26m", 19), +}; + +static u16 pext_rst_ofs[] = { MT8196_PEXTP_RST0_SET_OFFSET }; + +static u16 pext_rst_idx_map[] = { + [MT8196_PEXTP0_RST0_PCIE0_MAC] = 0, + [MT8196_PEXTP0_RST0_PCIE0_PHY] = 1, +}; + +static const struct mtk_clk_rst_desc pext_rst_desc = { + .version = MTK_RST_SET_CLR, + .rst_bank_ofs = pext_rst_ofs, + .rst_bank_nr = ARRAY_SIZE(pext_rst_ofs), + .rst_idx_map = pext_rst_idx_map, + .rst_idx_map_nr = ARRAY_SIZE(pext_rst_idx_map), +}; + +static const struct mtk_clk_desc pext_mcd = { + .clks = pext_clks, + .num_clks = ARRAY_SIZE(pext_clks), + .rst_desc = &pext_rst_desc, +}; + +static const struct mtk_gate pext1_clks[] = { + GATE_PEXT(CLK_PEXT1_PEXTP_MAC_P1_TL, "pext1_pm1_tl", "tl_p1", 0), + GATE_PEXT(CLK_PEXT1_PEXTP_MAC_P1_REF, "pext1_pm1_ref", "clk26m", 1), + GATE_PEXT(CLK_PEXT1_PEXTP_MAC_P2_TL, "pext1_pm2_tl", "tl_p2", 2), + GATE_PEXT(CLK_PEXT1_PEXTP_MAC_P2_REF, "pext1_pm2_ref", "clk26m", 3), + GATE_PEXT(CLK_PEXT1_PEXTP_PHY_P1_MCU_BUS, "pext1_pp1_mcu_bus", "clk26m", 8), + GATE_PEXT(CLK_PEXT1_PEXTP_PHY_P1_PEXTP_REF, "pext1_pp1_pextp_ref", "clk26m", 9), + GATE_PEXT(CLK_PEXT1_PEXTP_PHY_P2_MCU_BUS, "pext1_pp2_mcu_bus", "clk26m", 10), + GATE_PEXT(CLK_PEXT1_PEXTP_PHY_P2_PEXTP_REF, "pext1_pp2_pextp_ref", "clk26m", 11), + GATE_PEXT(CLK_PEXT1_PEXTP_MAC_P1_AXI_250, "pext1_pm1_axi_250", + "pextp1_usb_axi", 16), + GATE_PEXT(CLK_PEXT1_PEXTP_MAC_P1_AHB_APB, "pext1_pm1_ahb_apb", + "pextp1_usb_mem_sub", 17), + GATE_PEXT(CLK_PEXT1_PEXTP_MAC_P1_PL_P, "pext1_pm1_pl_p", "clk26m", 18), + GATE_PEXT(CLK_PEXT1_PEXTP_MAC_P2_AXI_250, "pext1_pm2_axi_250", + "pextp1_usb_axi", 19), + GATE_PEXT(CLK_PEXT1_PEXTP_MAC_P2_AHB_APB, "pext1_pm2_ahb_apb", + "pextp1_usb_mem_sub", 20), + GATE_PEXT(CLK_PEXT1_PEXTP_MAC_P2_PL_P, "pext1_pm2_pl_p", "clk26m", 21), + GATE_PEXT(CLK_PEXT1_PEXTP_VLP_AO_P1_LP, "pext1_pextp_vlp_ao_p1_lp", "clk26m", 26), + GATE_PEXT(CLK_PEXT1_PEXTP_VLP_AO_P2_LP, "pext1_pextp_vlp_ao_p2_lp", "clk26m", 27), +}; + +static u16 pext1_rst_idx_map[] = { + [MT8196_PEXTP1_RST0_PCIE1_MAC] = 0, + [MT8196_PEXTP1_RST0_PCIE1_PHY] = 1, + [MT8196_PEXTP1_RST0_PCIE2_MAC] = 8, + [MT8196_PEXTP1_RST0_PCIE2_PHY] = 9, +}; + +static const struct mtk_clk_rst_desc pext1_rst_desc = { + .version = MTK_RST_SET_CLR, + .rst_bank_ofs = pext_rst_ofs, + .rst_bank_nr = ARRAY_SIZE(pext_rst_ofs), + .rst_idx_map = pext1_rst_idx_map, + .rst_idx_map_nr = ARRAY_SIZE(pext1_rst_idx_map), +}; + +static const struct mtk_clk_desc pext1_mcd = { + .clks = pext1_clks, + .num_clks = ARRAY_SIZE(pext1_clks), + .rst_desc = &pext1_rst_desc, +}; + +static const struct of_device_id of_match_clk_mt8196_pextp[] = { + { .compatible = "mediatek,mt8196-pextp0cfg-ao", .data = &pext_mcd }, + { .compatible = "mediatek,mt8196-pextp1cfg-ao", .data = &pext1_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_pextp); + +static struct platform_driver clk_mt8196_pextp_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8196-pextp", + .of_match_table = of_match_clk_mt8196_pextp, + }, +}; + +module_platform_driver(clk_mt8196_pextp_drv); +MODULE_DESCRIPTION("MediaTek MT8196 PCIe transmit phy clocks driver"); +MODULE_LICENSE("GPL"); From 8f61d9d319915eb84511773dfa57fb0c60ead0f7 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:37 +0200 Subject: [PATCH 1851/2711] clk: mediatek: Add MT8196 I2C clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 I2C clock controller, which provides clock gate control for I2C. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 7 ++ drivers/clk/mediatek/Makefile | 1 + .../clk/mediatek/clk-mt8196-imp_iic_wrap.c | 118 ++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8196-imp_iic_wrap.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index c977719046a4..fe2697b64ef0 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1010,6 +1010,13 @@ config COMMON_CLK_MT8196 help This driver supports MediaTek MT8196 basic clocks. +config COMMON_CLK_MT8196_IMP_IIC_WRAP + tristate "Clock driver for MediaTek MT8196 imp_iic_wrap" + depends on COMMON_CLK_MT8196 + default COMMON_CLK_MT8196 + help + This driver supports MediaTek MT8196 i2c clocks. + config COMMON_CLK_MT8196_PEXTPSYS tristate "Clock driver for MediaTek MT8196 pextpsys" depends on COMMON_CLK_MT8196 diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 88f7d8a229c2..241e7f5e7316 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -153,6 +153,7 @@ obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o \ clk-mt8196-topckgen2.o clk-mt8196-vlpckgen.o \ clk-mt8196-peri_ao.o +obj-$(CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP) += clk-mt8196-imp_iic_wrap.o obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o diff --git a/drivers/clk/mediatek/clk-mt8196-imp_iic_wrap.c b/drivers/clk/mediatek/clk-mt8196-imp_iic_wrap.c new file mode 100644 index 000000000000..a63241671650 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-imp_iic_wrap.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs imp_cg_regs = { + .set_ofs = 0xe08, + .clr_ofs = 0xe04, + .sta_ofs = 0xe00, +}; + +#define GATE_IMP(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &imp_cg_regs, \ + .shift = _shift, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate impc_clks[] = { + GATE_IMP(CLK_IMPC_I2C11, "impc_i2c11", "i2c_p", 0), + GATE_IMP(CLK_IMPC_I2C12, "impc_i2c12", "i2c_p", 1), + GATE_IMP(CLK_IMPC_I2C13, "impc_i2c13", "i2c_p", 2), + GATE_IMP(CLK_IMPC_I2C14, "impc_i2c14", "i2c_p", 3), +}; + +static const struct mtk_clk_desc impc_mcd = { + .clks = impc_clks, + .num_clks = ARRAY_SIZE(impc_clks), +}; + +static const struct mtk_gate impe_clks[] = { + GATE_IMP(CLK_IMPE_I2C5, "impe_i2c5", "i2c_east", 0), +}; + +static const struct mtk_clk_desc impe_mcd = { + .clks = impe_clks, + .num_clks = ARRAY_SIZE(impe_clks), +}; + +static const struct mtk_gate_regs impn_hwv_regs = { + .set_ofs = 0x0000, + .clr_ofs = 0x0004, + .sta_ofs = 0x2c00, +}; + +#define GATE_HWV_IMPN(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &imp_cg_regs, \ + .hwv_regs = &impn_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +static const struct mtk_gate impn_clks[] = { + GATE_IMP(CLK_IMPN_I2C1, "impn_i2c1", "i2c_north", 0), + GATE_IMP(CLK_IMPN_I2C2, "impn_i2c2", "i2c_north", 1), + GATE_IMP(CLK_IMPN_I2C4, "impn_i2c4", "i2c_north", 2), + GATE_HWV_IMPN(CLK_IMPN_I2C7, "impn_i2c7", "i2c_north", 3), + GATE_IMP(CLK_IMPN_I2C8, "impn_i2c8", "i2c_north", 4), + GATE_IMP(CLK_IMPN_I2C9, "impn_i2c9", "i2c_north", 5), +}; + +static const struct mtk_clk_desc impn_mcd = { + .clks = impn_clks, + .num_clks = ARRAY_SIZE(impn_clks), +}; + +static const struct mtk_gate impw_clks[] = { + GATE_IMP(CLK_IMPW_I2C0, "impw_i2c0", "i2c_west", 0), + GATE_IMP(CLK_IMPW_I2C3, "impw_i2c3", "i2c_west", 1), + GATE_IMP(CLK_IMPW_I2C6, "impw_i2c6", "i2c_west", 2), + GATE_IMP(CLK_IMPW_I2C10, "impw_i2c10", "i2c_west", 3), +}; + +static const struct mtk_clk_desc impw_mcd = { + .clks = impw_clks, + .num_clks = ARRAY_SIZE(impw_clks), +}; + +static const struct of_device_id of_match_clk_mt8196_imp_iic_wrap[] = { + { .compatible = "mediatek,mt8196-imp-iic-wrap-c", .data = &impc_mcd }, + { .compatible = "mediatek,mt8196-imp-iic-wrap-e", .data = &impe_mcd }, + { .compatible = "mediatek,mt8196-imp-iic-wrap-n", .data = &impn_mcd }, + { .compatible = "mediatek,mt8196-imp-iic-wrap-w", .data = &impw_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_imp_iic_wrap); + +static struct platform_driver clk_mt8196_imp_iic_wrap_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8196-imp_iic_wrap", + .of_match_table = of_match_clk_mt8196_imp_iic_wrap, + }, +}; +module_platform_driver(clk_mt8196_imp_iic_wrap_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 I2C Wrapper clocks driver"); +MODULE_LICENSE("GPL"); From d4ecae56a8c7d3287a5bcdb2d65f7102ee580ab6 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:38 +0200 Subject: [PATCH 1852/2711] clk: mediatek: Add MT8196 mcu clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 mcu clock controller, which provides PLL control for MCU. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 7 ++ drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt8196-mcu.c | 167 ++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8196-mcu.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index fe2697b64ef0..8e5cdae80748 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1017,6 +1017,13 @@ config COMMON_CLK_MT8196_IMP_IIC_WRAP help This driver supports MediaTek MT8196 i2c clocks. +config COMMON_CLK_MT8196_MCUSYS + tristate "Clock driver for MediaTek MT8196 mcusys" + depends on COMMON_CLK_MT8196 + default COMMON_CLK_MT8196 + help + This driver supports MediaTek MT8196 mcusys clocks. + config COMMON_CLK_MT8196_PEXTPSYS tristate "Clock driver for MediaTek MT8196 pextpsys" depends on COMMON_CLK_MT8196 diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 241e7f5e7316..46358623c3e5 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -154,6 +154,7 @@ obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o clk-mt8196-topckgen2.o clk-mt8196-vlpckgen.o \ clk-mt8196-peri_ao.o obj-$(CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP) += clk-mt8196-imp_iic_wrap.o +obj-$(CONFIG_COMMON_CLK_MT8196_MCUSYS) += clk-mt8196-mcu.o obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o diff --git a/drivers/clk/mediatek/clk-mt8196-mcu.c b/drivers/clk/mediatek/clk-mt8196-mcu.c new file mode 100644 index 000000000000..5cbcc411ae73 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-mcu.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-pll.h" + +#define ARMPLL_LL_CON0 0x008 +#define ARMPLL_LL_CON1 0x00c +#define ARMPLL_LL_CON2 0x010 +#define ARMPLL_LL_CON3 0x014 +#define ARMPLL_BL_CON0 0x008 +#define ARMPLL_BL_CON1 0x00c +#define ARMPLL_BL_CON2 0x010 +#define ARMPLL_BL_CON3 0x014 +#define ARMPLL_B_CON0 0x008 +#define ARMPLL_B_CON1 0x00c +#define ARMPLL_B_CON2 0x010 +#define ARMPLL_B_CON3 0x014 +#define CCIPLL_CON0 0x008 +#define CCIPLL_CON1 0x00c +#define CCIPLL_CON2 0x010 +#define CCIPLL_CON3 0x014 +#define PTPPLL_CON0 0x008 +#define PTPPLL_CON1 0x00c +#define PTPPLL_CON2 0x010 +#define PTPPLL_CON3 0x014 + +#define MT8196_PLL_FMAX (3800UL * MHZ) +#define MT8196_PLL_FMIN (1500UL * MHZ) +#define MT8196_INTEGER_BITS 8 + +#define PLL(_id, _name, _reg, _en_reg, _en_mask, _pll_en_bit, \ + _flags, _rst_bar_mask, \ + _pd_reg, _pd_shift, _tuner_reg, \ + _tuner_en_reg, _tuner_en_bit, \ + _pcw_reg, _pcw_shift, _pcwbits) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .en_reg = _en_reg, \ + .en_mask = _en_mask, \ + .pll_en_bit = _pll_en_bit, \ + .flags = _flags, \ + .rst_bar_mask = _rst_bar_mask, \ + .fmax = MT8196_PLL_FMAX, \ + .fmin = MT8196_PLL_FMIN, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, \ + .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .pcwbits = _pcwbits, \ + .pcwibits = MT8196_INTEGER_BITS, \ + } + +static const struct mtk_pll_data cpu_bl_plls[] = { + PLL(CLK_CPBL_ARMPLL_BL, "armpll-bl", ARMPLL_BL_CON0, ARMPLL_BL_CON0, 0, + 0, PLL_AO, BIT(0), ARMPLL_BL_CON1, 24, 0, 0, 0, ARMPLL_BL_CON1, 0, 22), +}; + +static const struct mtk_pll_data cpu_b_plls[] = { + PLL(CLK_CPB_ARMPLL_B, "armpll-b", ARMPLL_B_CON0, ARMPLL_B_CON0, 0, 0, + PLL_AO, BIT(0), ARMPLL_B_CON1, 24, 0, 0, 0, ARMPLL_B_CON1, 0, 22), +}; + +static const struct mtk_pll_data cpu_ll_plls[] = { + PLL(CLK_CPLL_ARMPLL_LL, "armpll-ll", ARMPLL_LL_CON0, ARMPLL_LL_CON0, 0, + 0, PLL_AO, BIT(0), ARMPLL_LL_CON1, 24, 0, 0, 0, ARMPLL_LL_CON1, 0, 22), +}; + +static const struct mtk_pll_data cci_plls[] = { + PLL(CLK_CCIPLL, "ccipll", CCIPLL_CON0, CCIPLL_CON0, 0, 0, PLL_AO, + BIT(0), CCIPLL_CON1, 24, 0, 0, 0, CCIPLL_CON1, 0, 22), +}; + +static const struct mtk_pll_data ptp_plls[] = { + PLL(CLK_PTPPLL, "ptppll", PTPPLL_CON0, PTPPLL_CON0, 0, 0, PLL_AO, + BIT(0), PTPPLL_CON1, 24, 0, 0, 0, PTPPLL_CON1, 0, 22), +}; + +static const struct of_device_id of_match_clk_mt8196_mcu[] = { + { .compatible = "mediatek,mt8196-armpll-bl-pll-ctrl", + .data = &cpu_bl_plls }, + { .compatible = "mediatek,mt8196-armpll-b-pll-ctrl", + .data = &cpu_b_plls }, + { .compatible = "mediatek,mt8196-armpll-ll-pll-ctrl", + .data = &cpu_ll_plls }, + { .compatible = "mediatek,mt8196-ccipll-pll-ctrl", .data = &cci_plls }, + { .compatible = "mediatek,mt8196-ptppll-pll-ctrl", .data = &ptp_plls }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_mcu); + +static int clk_mt8196_mcu_probe(struct platform_device *pdev) +{ + const struct mtk_pll_data *plls; + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + const int num_plls = 1; + int r; + + plls = of_device_get_match_data(&pdev->dev); + if (!plls) + return -EINVAL; + + clk_data = mtk_alloc_clk_data(num_plls); + if (!clk_data) + return -ENOMEM; + + r = mtk_clk_register_plls(node, plls, num_plls, clk_data); + if (r) + goto free_clk_data; + + r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (r) + goto unregister_plls; + + platform_set_drvdata(pdev, clk_data); + + return r; + +unregister_plls: + mtk_clk_unregister_plls(plls, num_plls, clk_data); +free_clk_data: + mtk_free_clk_data(clk_data); + + return r; +} + +static void clk_mt8196_mcu_remove(struct platform_device *pdev) +{ + const struct mtk_pll_data *plls = of_device_get_match_data(&pdev->dev); + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + + of_clk_del_provider(node); + mtk_clk_unregister_plls(plls, 1, clk_data); + mtk_free_clk_data(clk_data); +} + +static struct platform_driver clk_mt8196_mcu_drv = { + .probe = clk_mt8196_mcu_probe, + .remove = clk_mt8196_mcu_remove, + .driver = { + .name = "clk-mt8196-mcu", + .of_match_table = of_match_clk_mt8196_mcu, + }, +}; +module_platform_driver(clk_mt8196_mcu_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 mcusys clocks driver"); +MODULE_LICENSE("GPL"); From 2a827a7a4c2d45c601d6e2539537c7363c6c8b36 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:39 +0200 Subject: [PATCH 1853/2711] clk: mediatek: Add MT8196 mdpsys clock support Add support for the MT8196 mdpsys clock controller, which provides clock gate control for MDP. Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai # CLK_OPS_PARENT_ENABLE removal Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 7 + drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt8196-mdpsys.c | 186 +++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8196-mdpsys.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 8e5cdae80748..68ac08cf8e82 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1024,6 +1024,13 @@ config COMMON_CLK_MT8196_MCUSYS help This driver supports MediaTek MT8196 mcusys clocks. +config COMMON_CLK_MT8196_MDPSYS + tristate "Clock driver for MediaTek MT8196 mdpsys" + depends on COMMON_CLK_MT8196 + default COMMON_CLK_MT8196 + help + This driver supports MediaTek MT8196 mdpsys clocks. + config COMMON_CLK_MT8196_PEXTPSYS tristate "Clock driver for MediaTek MT8196 pextpsys" depends on COMMON_CLK_MT8196 diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 46358623c3e5..d2d8bc43e45b 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -155,6 +155,7 @@ obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o clk-mt8196-peri_ao.o obj-$(CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP) += clk-mt8196-imp_iic_wrap.o obj-$(CONFIG_COMMON_CLK_MT8196_MCUSYS) += clk-mt8196-mcu.o +obj-$(CONFIG_COMMON_CLK_MT8196_MDPSYS) += clk-mt8196-mdpsys.o obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o diff --git a/drivers/clk/mediatek/clk-mt8196-mdpsys.c b/drivers/clk/mediatek/clk-mt8196-mdpsys.c new file mode 100644 index 000000000000..7667d88f0eb0 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-mdpsys.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs mdp0_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs mdp1_cg_regs = { + .set_ofs = 0x114, + .clr_ofs = 0x118, + .sta_ofs = 0x110, +}; + +static const struct mtk_gate_regs mdp2_cg_regs = { + .set_ofs = 0x124, + .clr_ofs = 0x128, + .sta_ofs = 0x120, +}; + +#define GATE_MDP0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mdp0_cg_regs, \ + .shift = _shift, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_MDP1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mdp1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_MDP2(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mdp2_cg_regs, \ + .shift = _shift, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate mdp1_clks[] = { + /* MDP1-0 */ + GATE_MDP0(CLK_MDP1_MDP_MUTEX0, "mdp1_mdp_mutex0", "mdp", 0), + GATE_MDP0(CLK_MDP1_SMI0, "mdp1_smi0", "mdp", 1), + GATE_MDP0(CLK_MDP1_APB_BUS, "mdp1_apb_bus", "mdp", 2), + GATE_MDP0(CLK_MDP1_MDP_RDMA0, "mdp1_mdp_rdma0", "mdp", 3), + GATE_MDP0(CLK_MDP1_MDP_RDMA1, "mdp1_mdp_rdma1", "mdp", 4), + GATE_MDP0(CLK_MDP1_MDP_RDMA2, "mdp1_mdp_rdma2", "mdp", 5), + GATE_MDP0(CLK_MDP1_MDP_BIRSZ0, "mdp1_mdp_birsz0", "mdp", 6), + GATE_MDP0(CLK_MDP1_MDP_HDR0, "mdp1_mdp_hdr0", "mdp", 7), + GATE_MDP0(CLK_MDP1_MDP_AAL0, "mdp1_mdp_aal0", "mdp", 8), + GATE_MDP0(CLK_MDP1_MDP_RSZ0, "mdp1_mdp_rsz0", "mdp", 9), + GATE_MDP0(CLK_MDP1_MDP_RSZ2, "mdp1_mdp_rsz2", "mdp", 10), + GATE_MDP0(CLK_MDP1_MDP_TDSHP0, "mdp1_mdp_tdshp0", "mdp", 11), + GATE_MDP0(CLK_MDP1_MDP_COLOR0, "mdp1_mdp_color0", "mdp", 12), + GATE_MDP0(CLK_MDP1_MDP_WROT0, "mdp1_mdp_wrot0", "mdp", 13), + GATE_MDP0(CLK_MDP1_MDP_WROT1, "mdp1_mdp_wrot1", "mdp", 14), + GATE_MDP0(CLK_MDP1_MDP_WROT2, "mdp1_mdp_wrot2", "mdp", 15), + GATE_MDP0(CLK_MDP1_MDP_FAKE_ENG0, "mdp1_mdp_fake_eng0", "mdp", 16), + GATE_MDP0(CLK_MDP1_APB_DB, "mdp1_apb_db", "mdp", 17), + GATE_MDP0(CLK_MDP1_MDP_DLI_ASYNC0, "mdp1_mdp_dli_async0", "mdp", 18), + GATE_MDP0(CLK_MDP1_MDP_DLI_ASYNC1, "mdp1_mdp_dli_async1", "mdp", 19), + GATE_MDP0(CLK_MDP1_MDP_DLO_ASYNC0, "mdp1_mdp_dlo_async0", "mdp", 20), + GATE_MDP0(CLK_MDP1_MDP_DLO_ASYNC1, "mdp1_mdp_dlo_async1", "mdp", 21), + GATE_MDP0(CLK_MDP1_MDP_DLI_ASYNC2, "mdp1_mdp_dli_async2", "mdp", 22), + GATE_MDP0(CLK_MDP1_MDP_DLO_ASYNC2, "mdp1_mdp_dlo_async2", "mdp", 23), + GATE_MDP0(CLK_MDP1_MDP_DLO_ASYNC3, "mdp1_mdp_dlo_async3", "mdp", 24), + GATE_MDP0(CLK_MDP1_IMG_DL_ASYNC0, "mdp1_img_dl_async0", "mdp", 25), + GATE_MDP0(CLK_MDP1_MDP_RROT0, "mdp1_mdp_rrot0", "mdp", 26), + GATE_MDP0(CLK_MDP1_MDP_MERGE0, "mdp1_mdp_merge0", "mdp", 27), + GATE_MDP0(CLK_MDP1_MDP_C3D0, "mdp1_mdp_c3d0", "mdp", 28), + GATE_MDP0(CLK_MDP1_MDP_FG0, "mdp1_mdp_fg0", "mdp", 29), + GATE_MDP0(CLK_MDP1_MDP_CLA2, "mdp1_mdp_cla2", "mdp", 30), + GATE_MDP0(CLK_MDP1_MDP_DLO_ASYNC4, "mdp1_mdp_dlo_async4", "mdp", 31), + /* MDP1-1 */ + GATE_MDP1(CLK_MDP1_VPP_RSZ0, "mdp1_vpp_rsz0", "mdp", 0), + GATE_MDP1(CLK_MDP1_VPP_RSZ1, "mdp1_vpp_rsz1", "mdp", 1), + GATE_MDP1(CLK_MDP1_MDP_DLO_ASYNC5, "mdp1_mdp_dlo_async5", "mdp", 2), + GATE_MDP1(CLK_MDP1_IMG0, "mdp1_img0", "mdp", 3), + GATE_MDP1(CLK_MDP1_F26M, "mdp1_f26m", "clk26m", 27), + /* MDP1-2 */ + GATE_MDP2(CLK_MDP1_IMG_DL_RELAY0, "mdp1_img_dl_relay0", "mdp", 0), + GATE_MDP2(CLK_MDP1_IMG_DL_RELAY1, "mdp1_img_dl_relay1", "mdp", 8), +}; + +static const struct mtk_clk_desc mdp1_mcd = { + .clks = mdp1_clks, + .num_clks = ARRAY_SIZE(mdp1_clks), + .need_runtime_pm = true, +}; + + +static const struct mtk_gate mdp_clks[] = { + /* MDP0 */ + GATE_MDP0(CLK_MDP_MDP_MUTEX0, "mdp_mdp_mutex0", "mdp", 0), + GATE_MDP0(CLK_MDP_SMI0, "mdp_smi0", "mdp", 1), + GATE_MDP0(CLK_MDP_APB_BUS, "mdp_apb_bus", "mdp", 2), + GATE_MDP0(CLK_MDP_MDP_RDMA0, "mdp_mdp_rdma0", "mdp", 3), + GATE_MDP0(CLK_MDP_MDP_RDMA1, "mdp_mdp_rdma1", "mdp", 4), + GATE_MDP0(CLK_MDP_MDP_RDMA2, "mdp_mdp_rdma2", "mdp", 5), + GATE_MDP0(CLK_MDP_MDP_BIRSZ0, "mdp_mdp_birsz0", "mdp", 6), + GATE_MDP0(CLK_MDP_MDP_HDR0, "mdp_mdp_hdr0", "mdp", 7), + GATE_MDP0(CLK_MDP_MDP_AAL0, "mdp_mdp_aal0", "mdp", 8), + GATE_MDP0(CLK_MDP_MDP_RSZ0, "mdp_mdp_rsz0", "mdp", 9), + GATE_MDP0(CLK_MDP_MDP_RSZ2, "mdp_mdp_rsz2", "mdp", 10), + GATE_MDP0(CLK_MDP_MDP_TDSHP0, "mdp_mdp_tdshp0", "mdp", 11), + GATE_MDP0(CLK_MDP_MDP_COLOR0, "mdp_mdp_color0", "mdp", 12), + GATE_MDP0(CLK_MDP_MDP_WROT0, "mdp_mdp_wrot0", "mdp", 13), + GATE_MDP0(CLK_MDP_MDP_WROT1, "mdp_mdp_wrot1", "mdp", 14), + GATE_MDP0(CLK_MDP_MDP_WROT2, "mdp_mdp_wrot2", "mdp", 15), + GATE_MDP0(CLK_MDP_MDP_FAKE_ENG0, "mdp_mdp_fake_eng0", "mdp", 16), + GATE_MDP0(CLK_MDP_APB_DB, "mdp_apb_db", "mdp", 17), + GATE_MDP0(CLK_MDP_MDP_DLI_ASYNC0, "mdp_mdp_dli_async0", "mdp", 18), + GATE_MDP0(CLK_MDP_MDP_DLI_ASYNC1, "mdp_mdp_dli_async1", "mdp", 19), + GATE_MDP0(CLK_MDP_MDP_DLO_ASYNC0, "mdp_mdp_dlo_async0", "mdp", 20), + GATE_MDP0(CLK_MDP_MDP_DLO_ASYNC1, "mdp_mdp_dlo_async1", "mdp", 21), + GATE_MDP0(CLK_MDP_MDP_DLI_ASYNC2, "mdp_mdp_dli_async2", "mdp", 22), + GATE_MDP0(CLK_MDP_MDP_DLO_ASYNC2, "mdp_mdp_dlo_async2", "mdp", 23), + GATE_MDP0(CLK_MDP_MDP_DLO_ASYNC3, "mdp_mdp_dlo_async3", "mdp", 24), + GATE_MDP0(CLK_MDP_IMG_DL_ASYNC0, "mdp_img_dl_async0", "mdp", 25), + GATE_MDP0(CLK_MDP_MDP_RROT0, "mdp_mdp_rrot0", "mdp", 26), + GATE_MDP0(CLK_MDP_MDP_MERGE0, "mdp_mdp_merge0", "mdp", 27), + GATE_MDP0(CLK_MDP_MDP_C3D0, "mdp_mdp_c3d0", "mdp", 28), + GATE_MDP0(CLK_MDP_MDP_FG0, "mdp_mdp_fg0", "mdp", 29), + GATE_MDP0(CLK_MDP_MDP_CLA2, "mdp_mdp_cla2", "mdp", 30), + GATE_MDP0(CLK_MDP_MDP_DLO_ASYNC4, "mdp_mdp_dlo_async4", "mdp", 31), + /* MDP1 */ + GATE_MDP1(CLK_MDP_VPP_RSZ0, "mdp_vpp_rsz0", "mdp", 0), + GATE_MDP1(CLK_MDP_VPP_RSZ1, "mdp_vpp_rsz1", "mdp", 1), + GATE_MDP1(CLK_MDP_MDP_DLO_ASYNC5, "mdp_mdp_dlo_async5", "mdp", 2), + GATE_MDP1(CLK_MDP_IMG0, "mdp_img0", "mdp", 3), + GATE_MDP1(CLK_MDP_F26M, "mdp_f26m", "clk26m", 27), + /* MDP2 */ + GATE_MDP2(CLK_MDP_IMG_DL_RELAY0, "mdp_img_dl_relay0", "mdp", 0), + GATE_MDP2(CLK_MDP_IMG_DL_RELAY1, "mdp_img_dl_relay1", "mdp", 8), +}; + +static const struct mtk_clk_desc mdp_mcd = { + .clks = mdp_clks, + .num_clks = ARRAY_SIZE(mdp_clks), + .need_runtime_pm = true, +}; + +static const struct of_device_id of_match_clk_mt8196_mdpsys[] = { + { .compatible = "mediatek,mt8196-mdpsys0", .data = &mdp_mcd }, + { .compatible = "mediatek,mt8196-mdpsys1", .data = &mdp1_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_mdpsys); + +static struct platform_driver clk_mt8196_mdpsys_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8196-mdpsys", + .of_match_table = of_match_clk_mt8196_mdpsys, + }, +}; +module_platform_driver(clk_mt8196_mdpsys_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 Multimedia Data Path clocks driver"); +MODULE_LICENSE("GPL"); From 03dc02f8c7dc6d9d0cebea5f289c7052483353dc Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:40 +0200 Subject: [PATCH 1854/2711] clk: mediatek: Add MT8196 mfg clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 mfg clock controller, which provides PLL control for the GPU. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 7 ++ drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt8196-mfg.c | 150 ++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8196-mfg.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 68ac08cf8e82..1990721ec418 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1031,6 +1031,13 @@ config COMMON_CLK_MT8196_MDPSYS help This driver supports MediaTek MT8196 mdpsys clocks. +config COMMON_CLK_MT8196_MFGCFG + tristate "Clock driver for MediaTek MT8196 mfgcfg" + depends on COMMON_CLK_MT8196 + default m + help + This driver supports MediaTek MT8196 mfgcfg clocks. + config COMMON_CLK_MT8196_PEXTPSYS tristate "Clock driver for MediaTek MT8196 pextpsys" depends on COMMON_CLK_MT8196 diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index d2d8bc43e45b..0040a3968858 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -156,6 +156,7 @@ obj-$(CONFIG_COMMON_CLK_MT8196) += clk-mt8196-apmixedsys.o clk-mt8196-topckgen.o obj-$(CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP) += clk-mt8196-imp_iic_wrap.o obj-$(CONFIG_COMMON_CLK_MT8196_MCUSYS) += clk-mt8196-mcu.o obj-$(CONFIG_COMMON_CLK_MT8196_MDPSYS) += clk-mt8196-mdpsys.o +obj-$(CONFIG_COMMON_CLK_MT8196_MFGCFG) += clk-mt8196-mfg.o obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o diff --git a/drivers/clk/mediatek/clk-mt8196-mfg.c b/drivers/clk/mediatek/clk-mt8196-mfg.c new file mode 100644 index 000000000000..ae1eb9de79ae --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-mfg.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-pll.h" + +#define MFGPLL_CON0 0x008 +#define MFGPLL_CON1 0x00c +#define MFGPLL_CON2 0x010 +#define MFGPLL_CON3 0x014 +#define MFGPLL_SC0_CON0 0x008 +#define MFGPLL_SC0_CON1 0x00c +#define MFGPLL_SC0_CON2 0x010 +#define MFGPLL_SC0_CON3 0x014 +#define MFGPLL_SC1_CON0 0x008 +#define MFGPLL_SC1_CON1 0x00c +#define MFGPLL_SC1_CON2 0x010 +#define MFGPLL_SC1_CON3 0x014 + +#define MT8196_PLL_FMAX (3800UL * MHZ) +#define MT8196_PLL_FMIN (1500UL * MHZ) +#define MT8196_INTEGER_BITS 8 + +#define PLL(_id, _name, _reg, _en_reg, _en_mask, _pll_en_bit, \ + _flags, _rst_bar_mask, \ + _pd_reg, _pd_shift, _tuner_reg, \ + _tuner_en_reg, _tuner_en_bit, \ + _pcw_reg, _pcw_shift, _pcwbits) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .en_reg = _en_reg, \ + .en_mask = _en_mask, \ + .pll_en_bit = _pll_en_bit, \ + .flags = _flags, \ + .rst_bar_mask = _rst_bar_mask, \ + .fmax = MT8196_PLL_FMAX, \ + .fmin = MT8196_PLL_FMIN, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, \ + .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .pcwbits = _pcwbits, \ + .pcwibits = MT8196_INTEGER_BITS, \ + } + +static const struct mtk_pll_data mfg_ao_plls[] = { + PLL(CLK_MFG_AO_MFGPLL, "mfgpll", MFGPLL_CON0, MFGPLL_CON0, 0, 0, 0, + BIT(0), MFGPLL_CON1, 24, 0, 0, 0, + MFGPLL_CON1, 0, 22), +}; + +static const struct mtk_pll_data mfgsc0_ao_plls[] = { + PLL(CLK_MFGSC0_AO_MFGPLL_SC0, "mfgpll-sc0", MFGPLL_SC0_CON0, + MFGPLL_SC0_CON0, 0, 0, 0, BIT(0), MFGPLL_SC0_CON1, 24, 0, 0, 0, + MFGPLL_SC0_CON1, 0, 22), +}; + +static const struct mtk_pll_data mfgsc1_ao_plls[] = { + PLL(CLK_MFGSC1_AO_MFGPLL_SC1, "mfgpll-sc1", MFGPLL_SC1_CON0, + MFGPLL_SC1_CON0, 0, 0, 0, BIT(0), MFGPLL_SC1_CON1, 24, 0, 0, 0, + MFGPLL_SC1_CON1, 0, 22), +}; + +static const struct of_device_id of_match_clk_mt8196_mfg[] = { + { .compatible = "mediatek,mt8196-mfgpll-pll-ctrl", + .data = &mfg_ao_plls }, + { .compatible = "mediatek,mt8196-mfgpll-sc0-pll-ctrl", + .data = &mfgsc0_ao_plls }, + { .compatible = "mediatek,mt8196-mfgpll-sc1-pll-ctrl", + .data = &mfgsc1_ao_plls }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_mfg); + +static int clk_mt8196_mfg_probe(struct platform_device *pdev) +{ + const struct mtk_pll_data *plls; + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + const int num_plls = 1; + int r; + + plls = of_device_get_match_data(&pdev->dev); + if (!plls) + return -EINVAL; + + clk_data = mtk_alloc_clk_data(num_plls); + if (!clk_data) + return -ENOMEM; + + r = mtk_clk_register_plls(node, plls, num_plls, clk_data); + if (r) + goto free_clk_data; + + r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (r) + goto unregister_plls; + + platform_set_drvdata(pdev, clk_data); + + return r; + +unregister_plls: + mtk_clk_unregister_plls(plls, num_plls, clk_data); +free_clk_data: + mtk_free_clk_data(clk_data); + + return r; +} + +static void clk_mt8196_mfg_remove(struct platform_device *pdev) +{ + const struct mtk_pll_data *plls = of_device_get_match_data(&pdev->dev); + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + + of_clk_del_provider(node); + mtk_clk_unregister_plls(plls, 1, clk_data); + mtk_free_clk_data(clk_data); +} + +static struct platform_driver clk_mt8196_mfg_drv = { + .probe = clk_mt8196_mfg_probe, + .remove = clk_mt8196_mfg_remove, + .driver = { + .name = "clk-mt8196-mfg", + .of_match_table = of_match_clk_mt8196_mfg, + }, +}; +module_platform_driver(clk_mt8196_mfg_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 GPU mfg clocks driver"); +MODULE_LICENSE("GPL"); From 91894f618838339d51c694bd788f16c9b056b1b0 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:41 +0200 Subject: [PATCH 1855/2711] clk: mediatek: Add MT8196 disp0 clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 disp0 clock controller, which provides clock gate control for the display system. It is integrated with the mtk-mmsys driver, which registers the disp0 clock driver via platform_device_register_data(). Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 7 + drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt8196-disp0.c | 170 ++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8196-disp0.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 1990721ec418..77e18bceae91 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1038,6 +1038,13 @@ config COMMON_CLK_MT8196_MFGCFG help This driver supports MediaTek MT8196 mfgcfg clocks. +config COMMON_CLK_MT8196_MMSYS + tristate "Clock driver for MediaTek MT8196 mmsys" + depends on COMMON_CLK_MT8196 + default m + help + This driver supports MediaTek MT8196 mmsys clocks. + config COMMON_CLK_MT8196_PEXTPSYS tristate "Clock driver for MediaTek MT8196 pextpsys" depends on COMMON_CLK_MT8196 diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 0040a3968858..a8c681f9fe64 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -157,6 +157,7 @@ obj-$(CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP) += clk-mt8196-imp_iic_wrap.o obj-$(CONFIG_COMMON_CLK_MT8196_MCUSYS) += clk-mt8196-mcu.o obj-$(CONFIG_COMMON_CLK_MT8196_MDPSYS) += clk-mt8196-mdpsys.o obj-$(CONFIG_COMMON_CLK_MT8196_MFGCFG) += clk-mt8196-mfg.o +obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o diff --git a/drivers/clk/mediatek/clk-mt8196-disp0.c b/drivers/clk/mediatek/clk-mt8196-disp0.c new file mode 100644 index 000000000000..9474aad26e92 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-disp0.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs mm0_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs mm0_hwv_regs = { + .set_ofs = 0x0020, + .clr_ofs = 0x0024, + .sta_ofs = 0x2c10, +}; + +static const struct mtk_gate_regs mm1_cg_regs = { + .set_ofs = 0x114, + .clr_ofs = 0x118, + .sta_ofs = 0x110, +}; + +static const struct mtk_gate_regs mm1_hwv_regs = { + .set_ofs = 0x0028, + .clr_ofs = 0x002c, + .sta_ofs = 0x2c14, +}; + +#define GATE_MM0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm0_cg_regs, \ + .shift = _shift, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + .ops = &mtk_clk_gate_ops_setclr,\ + } + +#define GATE_HWV_MM0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm0_cg_regs, \ + .hwv_regs = &mm0_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE \ + } + +#define GATE_MM1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm1_cg_regs, \ + .shift = _shift, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + .ops = &mtk_clk_gate_ops_setclr,\ + } + +#define GATE_HWV_MM1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm1_cg_regs, \ + .hwv_regs = &mm1_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +static const struct mtk_gate mm_clks[] = { + /* MM0 */ + GATE_HWV_MM0(CLK_MM_CONFIG, "mm_config", "disp", 0), + GATE_HWV_MM0(CLK_MM_DISP_MUTEX0, "mm_disp_mutex0", "disp", 1), + GATE_HWV_MM0(CLK_MM_DISP_AAL0, "mm_disp_aal0", "disp", 2), + GATE_HWV_MM0(CLK_MM_DISP_AAL1, "mm_disp_aal1", "disp", 3), + GATE_MM0(CLK_MM_DISP_C3D0, "mm_disp_c3d0", "disp", 4), + GATE_MM0(CLK_MM_DISP_C3D1, "mm_disp_c3d1", "disp", 5), + GATE_MM0(CLK_MM_DISP_C3D2, "mm_disp_c3d2", "disp", 6), + GATE_MM0(CLK_MM_DISP_C3D3, "mm_disp_c3d3", "disp", 7), + GATE_MM0(CLK_MM_DISP_CCORR0, "mm_disp_ccorr0", "disp", 8), + GATE_MM0(CLK_MM_DISP_CCORR1, "mm_disp_ccorr1", "disp", 9), + GATE_MM0(CLK_MM_DISP_CCORR2, "mm_disp_ccorr2", "disp", 10), + GATE_MM0(CLK_MM_DISP_CCORR3, "mm_disp_ccorr3", "disp", 11), + GATE_MM0(CLK_MM_DISP_CHIST0, "mm_disp_chist0", "disp", 12), + GATE_MM0(CLK_MM_DISP_CHIST1, "mm_disp_chist1", "disp", 13), + GATE_MM0(CLK_MM_DISP_COLOR0, "mm_disp_color0", "disp", 14), + GATE_MM0(CLK_MM_DISP_COLOR1, "mm_disp_color1", "disp", 15), + GATE_MM0(CLK_MM_DISP_DITHER0, "mm_disp_dither0", "disp", 16), + GATE_MM0(CLK_MM_DISP_DITHER1, "mm_disp_dither1", "disp", 17), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC0, "mm_disp_dli_async0", "disp", 18), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC1, "mm_disp_dli_async1", "disp", 19), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC2, "mm_disp_dli_async2", "disp", 20), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC3, "mm_disp_dli_async3", "disp", 21), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC4, "mm_disp_dli_async4", "disp", 22), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC5, "mm_disp_dli_async5", "disp", 23), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC6, "mm_disp_dli_async6", "disp", 24), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC7, "mm_disp_dli_async7", "disp", 25), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC8, "mm_disp_dli_async8", "disp", 26), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC9, "mm_disp_dli_async9", "disp", 27), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC10, "mm_disp_dli_async10", "disp", 28), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC11, "mm_disp_dli_async11", "disp", 29), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC12, "mm_disp_dli_async12", "disp", 30), + GATE_HWV_MM0(CLK_MM_DISP_DLI_ASYNC13, "mm_disp_dli_async13", "disp", 31), + /* MM1 */ + GATE_HWV_MM1(CLK_MM_DISP_DLI_ASYNC14, "mm_disp_dli_async14", "disp", 0), + GATE_HWV_MM1(CLK_MM_DISP_DLI_ASYNC15, "mm_disp_dli_async15", "disp", 1), + GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC0, "mm_disp_dlo_async0", "disp", 2), + GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC1, "mm_disp_dlo_async1", "disp", 3), + GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC2, "mm_disp_dlo_async2", "disp", 4), + GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC3, "mm_disp_dlo_async3", "disp", 5), + GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC4, "mm_disp_dlo_async4", "disp", 6), + GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC5, "mm_disp_dlo_async5", "disp", 7), + GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC6, "mm_disp_dlo_async6", "disp", 8), + GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC7, "mm_disp_dlo_async7", "disp", 9), + GATE_HWV_MM1(CLK_MM_DISP_DLO_ASYNC8, "mm_disp_dlo_async8", "disp", 10), + GATE_MM1(CLK_MM_DISP_GAMMA0, "mm_disp_gamma0", "disp", 11), + GATE_MM1(CLK_MM_DISP_GAMMA1, "mm_disp_gamma1", "disp", 12), + GATE_MM1(CLK_MM_MDP_AAL0, "mm_mdp_aal0", "disp", 13), + GATE_MM1(CLK_MM_MDP_AAL1, "mm_mdp_aal1", "disp", 14), + GATE_HWV_MM1(CLK_MM_MDP_RDMA0, "mm_mdp_rdma0", "disp", 15), + GATE_HWV_MM1(CLK_MM_DISP_POSTMASK0, "mm_disp_postmask0", "disp", 16), + GATE_HWV_MM1(CLK_MM_DISP_POSTMASK1, "mm_disp_postmask1", "disp", 17), + GATE_HWV_MM1(CLK_MM_MDP_RSZ0, "mm_mdp_rsz0", "disp", 18), + GATE_HWV_MM1(CLK_MM_MDP_RSZ1, "mm_mdp_rsz1", "disp", 19), + GATE_HWV_MM1(CLK_MM_DISP_SPR0, "mm_disp_spr0", "disp", 20), + GATE_MM1(CLK_MM_DISP_TDSHP0, "mm_disp_tdshp0", "disp", 21), + GATE_MM1(CLK_MM_DISP_TDSHP1, "mm_disp_tdshp1", "disp", 22), + GATE_HWV_MM1(CLK_MM_DISP_WDMA0, "mm_disp_wdma0", "disp", 23), + GATE_HWV_MM1(CLK_MM_DISP_Y2R0, "mm_disp_y2r0", "disp", 24), + GATE_HWV_MM1(CLK_MM_SMI_SUB_COMM0, "mm_ssc", "disp", 25), + GATE_HWV_MM1(CLK_MM_DISP_FAKE_ENG0, "mm_disp_fake_eng0", "disp", 26), +}; + +static const struct mtk_clk_desc mm_mcd = { + .clks = mm_clks, + .num_clks = ARRAY_SIZE(mm_clks), +}; + +static const struct platform_device_id clk_mt8196_disp0_id_table[] = { + { .name = "clk-mt8196-disp0", .driver_data = (kernel_ulong_t)&mm_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8196_disp0_id_table); + +static struct platform_driver clk_mt8196_disp0_drv = { + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, + .driver = { + .name = "clk-mt8196-disp0", + }, + .id_table = clk_mt8196_disp0_id_table, +}; +module_platform_driver(clk_mt8196_disp0_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 disp0 clocks driver"); +MODULE_LICENSE("GPL"); From e2d924746082ec2775f09c61279752aea0d670ac Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:42 +0200 Subject: [PATCH 1856/2711] clk: mediatek: Add MT8196 disp1 clock support Add support for the MT8196 disp1 clock controller, which provides clock gate control for the display system. It is integrated with the mtk-mmsys driver, which registers the disp1 clock driver via platform_device_register_data(). Reviewed-by: Chen-Yu Tsai # CLK_OPS_PARENT_ENABLE removal Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Makefile | 2 +- drivers/clk/mediatek/clk-mt8196-disp1.c | 170 ++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mediatek/clk-mt8196-disp1.c diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index a8c681f9fe64..fe5699411d8b 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -157,7 +157,7 @@ obj-$(CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP) += clk-mt8196-imp_iic_wrap.o obj-$(CONFIG_COMMON_CLK_MT8196_MCUSYS) += clk-mt8196-mcu.o obj-$(CONFIG_COMMON_CLK_MT8196_MDPSYS) += clk-mt8196-mdpsys.o obj-$(CONFIG_COMMON_CLK_MT8196_MFGCFG) += clk-mt8196-mfg.o -obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o +obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o clk-mt8196-disp1.o obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o diff --git a/drivers/clk/mediatek/clk-mt8196-disp1.c b/drivers/clk/mediatek/clk-mt8196-disp1.c new file mode 100644 index 000000000000..3bbec79a7010 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-disp1.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs mm10_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs mm10_hwv_regs = { + .set_ofs = 0x0010, + .clr_ofs = 0x0014, + .sta_ofs = 0x2c08, +}; + +static const struct mtk_gate_regs mm11_cg_regs = { + .set_ofs = 0x114, + .clr_ofs = 0x118, + .sta_ofs = 0x110, +}; + +static const struct mtk_gate_regs mm11_hwv_regs = { + .set_ofs = 0x0018, + .clr_ofs = 0x001c, + .sta_ofs = 0x2c0c, +}; + +#define GATE_MM10(_id, _name, _parent, _shift) {\ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm10_cg_regs, \ + .shift = _shift, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + .ops = &mtk_clk_gate_ops_setclr,\ + } + +#define GATE_HWV_MM10(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm10_cg_regs, \ + .hwv_regs = &mm10_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_MM11(_id, _name, _parent, _shift) {\ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm11_cg_regs, \ + .shift = _shift, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + .ops = &mtk_clk_gate_ops_setclr,\ + } + +#define GATE_HWV_MM11(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm11_cg_regs, \ + .hwv_regs = &mm11_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + } + +static const struct mtk_gate mm1_clks[] = { + /* MM10 */ + GATE_HWV_MM10(CLK_MM1_DISPSYS1_CONFIG, "mm1_dispsys1_config", "disp", 0), + GATE_HWV_MM10(CLK_MM1_DISPSYS1_S_CONFIG, "mm1_dispsys1_s_config", "disp", 1), + GATE_HWV_MM10(CLK_MM1_DISP_MUTEX0, "mm1_disp_mutex0", "disp", 2), + GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC20, "mm1_disp_dli_async20", "disp", 3), + GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC21, "mm1_disp_dli_async21", "disp", 4), + GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC22, "mm1_disp_dli_async22", "disp", 5), + GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC23, "mm1_disp_dli_async23", "disp", 6), + GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC24, "mm1_disp_dli_async24", "disp", 7), + GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC25, "mm1_disp_dli_async25", "disp", 8), + GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC26, "mm1_disp_dli_async26", "disp", 9), + GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC27, "mm1_disp_dli_async27", "disp", 10), + GATE_HWV_MM10(CLK_MM1_DISP_DLI_ASYNC28, "mm1_disp_dli_async28", "disp", 11), + GATE_HWV_MM10(CLK_MM1_DISP_RELAY0, "mm1_disp_relay0", "disp", 12), + GATE_HWV_MM10(CLK_MM1_DISP_RELAY1, "mm1_disp_relay1", "disp", 13), + GATE_HWV_MM10(CLK_MM1_DISP_RELAY2, "mm1_disp_relay2", "disp", 14), + GATE_HWV_MM10(CLK_MM1_DISP_RELAY3, "mm1_disp_relay3", "disp", 15), + GATE_HWV_MM10(CLK_MM1_DISP_DP_INTF0, "mm1_DP_CLK", "disp", 16), + GATE_HWV_MM10(CLK_MM1_DISP_DP_INTF1, "mm1_disp_dp_intf1", "disp", 17), + GATE_HWV_MM10(CLK_MM1_DISP_DSC_WRAP0, "mm1_disp_dsc_wrap0", "disp", 18), + GATE_HWV_MM10(CLK_MM1_DISP_DSC_WRAP1, "mm1_disp_dsc_wrap1", "disp", 19), + GATE_HWV_MM10(CLK_MM1_DISP_DSC_WRAP2, "mm1_disp_dsc_wrap2", "disp", 20), + GATE_HWV_MM10(CLK_MM1_DISP_DSC_WRAP3, "mm1_disp_dsc_wrap3", "disp", 21), + GATE_HWV_MM10(CLK_MM1_DISP_DSI0, "mm1_CLK0", "disp", 22), + GATE_HWV_MM10(CLK_MM1_DISP_DSI1, "mm1_CLK1", "disp", 23), + GATE_HWV_MM10(CLK_MM1_DISP_DSI2, "mm1_CLK2", "disp", 24), + GATE_HWV_MM10(CLK_MM1_DISP_DVO0, "mm1_disp_dvo0", "disp", 25), + GATE_HWV_MM10(CLK_MM1_DISP_GDMA0, "mm1_disp_gdma0", "disp", 26), + GATE_HWV_MM10(CLK_MM1_DISP_MERGE0, "mm1_disp_merge0", "disp", 27), + GATE_HWV_MM10(CLK_MM1_DISP_MERGE1, "mm1_disp_merge1", "disp", 28), + GATE_HWV_MM10(CLK_MM1_DISP_MERGE2, "mm1_disp_merge2", "disp", 29), + GATE_HWV_MM10(CLK_MM1_DISP_ODDMR0, "mm1_disp_oddmr0", "disp", 30), + GATE_HWV_MM10(CLK_MM1_DISP_POSTALIGN0, "mm1_disp_postalign0", "disp", 31), + /* MM11 */ + GATE_HWV_MM11(CLK_MM1_DISP_DITHER2, "mm1_disp_dither2", "disp", 0), + GATE_HWV_MM11(CLK_MM1_DISP_R2Y0, "mm1_disp_r2y0", "disp", 1), + GATE_HWV_MM11(CLK_MM1_DISP_SPLITTER0, "mm1_disp_splitter0", "disp", 2), + GATE_HWV_MM11(CLK_MM1_DISP_SPLITTER1, "mm1_disp_splitter1", "disp", 3), + GATE_HWV_MM11(CLK_MM1_DISP_SPLITTER2, "mm1_disp_splitter2", "disp", 4), + GATE_HWV_MM11(CLK_MM1_DISP_SPLITTER3, "mm1_disp_splitter3", "disp", 5), + GATE_HWV_MM11(CLK_MM1_DISP_VDCM0, "mm1_disp_vdcm0", "disp", 6), + GATE_HWV_MM11(CLK_MM1_DISP_WDMA1, "mm1_disp_wdma1", "disp", 7), + GATE_HWV_MM11(CLK_MM1_DISP_WDMA2, "mm1_disp_wdma2", "disp", 8), + GATE_HWV_MM11(CLK_MM1_DISP_WDMA3, "mm1_disp_wdma3", "disp", 9), + GATE_HWV_MM11(CLK_MM1_DISP_WDMA4, "mm1_disp_wdma4", "disp", 10), + GATE_HWV_MM11(CLK_MM1_MDP_RDMA1, "mm1_mdp_rdma1", "disp", 11), + GATE_HWV_MM11(CLK_MM1_SMI_LARB0, "mm1_smi_larb0", "disp", 12), + GATE_HWV_MM11(CLK_MM1_MOD1, "mm1_mod1", "clk26m", 13), + GATE_HWV_MM11(CLK_MM1_MOD2, "mm1_mod2", "clk26m", 14), + GATE_HWV_MM11(CLK_MM1_MOD3, "mm1_mod3", "clk26m", 15), + GATE_HWV_MM11(CLK_MM1_MOD4, "mm1_mod4", "dp0", 16), + GATE_HWV_MM11(CLK_MM1_MOD5, "mm1_mod5", "dp1", 17), + GATE_HWV_MM11(CLK_MM1_MOD6, "mm1_mod6", "dp1", 18), + GATE_HWV_MM11(CLK_MM1_CG0, "mm1_cg0", "disp", 20), + GATE_HWV_MM11(CLK_MM1_CG1, "mm1_cg1", "disp", 21), + GATE_HWV_MM11(CLK_MM1_CG2, "mm1_cg2", "disp", 22), + GATE_HWV_MM11(CLK_MM1_CG3, "mm1_cg3", "disp", 23), + GATE_HWV_MM11(CLK_MM1_CG4, "mm1_cg4", "disp", 24), + GATE_HWV_MM11(CLK_MM1_CG5, "mm1_cg5", "disp", 25), + GATE_HWV_MM11(CLK_MM1_CG6, "mm1_cg6", "disp", 26), + GATE_HWV_MM11(CLK_MM1_CG7, "mm1_cg7", "disp", 27), + GATE_HWV_MM11(CLK_MM1_F26M, "mm1_f26m_ck", "clk26m", 28), +}; + +static const struct mtk_clk_desc mm1_mcd = { + .clks = mm1_clks, + .num_clks = ARRAY_SIZE(mm1_clks), +}; + +static const struct platform_device_id clk_mt8196_disp1_id_table[] = { + { .name = "clk-mt8196-disp1", .driver_data = (kernel_ulong_t)&mm1_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8196_disp1_id_table); + +static struct platform_driver clk_mt8196_disp1_drv = { + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, + .driver = { + .name = "clk-mt8196-disp1", + }, + .id_table = clk_mt8196_disp1_id_table, +}; +module_platform_driver(clk_mt8196_disp1_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 disp1 clocks driver"); +MODULE_LICENSE("GPL"); From d4fb7e15a520bae2fae45f492f1e4dc34cdd5bba Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:43 +0200 Subject: [PATCH 1857/2711] clk: mediatek: Add MT8196 disp-ao clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 disp-ao clock controller, which provides clock gate control for the display system. It is integrated with the mtk-mmsys driver, which registers the disp-ao clock driver via platform_device_register_data(). Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Makefile | 2 +- drivers/clk/mediatek/clk-mt8196-vdisp_ao.c | 80 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mediatek/clk-mt8196-vdisp_ao.c diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index fe5699411d8b..5b8969ff1985 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -157,7 +157,7 @@ obj-$(CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP) += clk-mt8196-imp_iic_wrap.o obj-$(CONFIG_COMMON_CLK_MT8196_MCUSYS) += clk-mt8196-mcu.o obj-$(CONFIG_COMMON_CLK_MT8196_MDPSYS) += clk-mt8196-mdpsys.o obj-$(CONFIG_COMMON_CLK_MT8196_MFGCFG) += clk-mt8196-mfg.o -obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o clk-mt8196-disp1.o +obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o clk-mt8196-disp1.o clk-mt8196-vdisp_ao.o obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o diff --git a/drivers/clk/mediatek/clk-mt8196-vdisp_ao.c b/drivers/clk/mediatek/clk-mt8196-vdisp_ao.c new file mode 100644 index 000000000000..fddb69d1c3eb --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-vdisp_ao.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs mm_v_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs mm_v_hwv_regs = { + .set_ofs = 0x0030, + .clr_ofs = 0x0034, + .sta_ofs = 0x2c18, +}; + +#define GATE_MM_AO_V(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm_v_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE | \ + CLK_IS_CRITICAL, \ + } + +#define GATE_HWV_MM_V(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm_v_cg_regs, \ + .hwv_regs = &mm_v_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +static const struct mtk_gate mm_v_clks[] = { + GATE_HWV_MM_V(CLK_MM_V_DISP_VDISP_AO_CONFIG, "mm_v_disp_vdisp_ao_config", "disp", 0), + GATE_HWV_MM_V(CLK_MM_V_DISP_DPC, "mm_v_disp_dpc", "disp", 16), + GATE_MM_AO_V(CLK_MM_V_SMI_SUB_SOMM0, "mm_v_smi_sub_somm0", "disp", 2), +}; + +static const struct mtk_clk_desc mm_v_mcd = { + .clks = mm_v_clks, + .num_clks = ARRAY_SIZE(mm_v_clks), +}; + +static const struct of_device_id of_match_clk_mt8196_vdisp_ao[] = { + { .compatible = "mediatek,mt8196-vdisp-ao", .data = &mm_v_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_vdisp_ao); + +static struct platform_driver clk_mt8196_vdisp_ao_drv = { + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, + .driver = { + .name = "clk-mt8196-vdisp-ao", + .of_match_table = of_match_clk_mt8196_vdisp_ao, + }, +}; +module_platform_driver(clk_mt8196_vdisp_ao_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 vdisp_ao clocks driver"); +MODULE_LICENSE("GPL"); From e4be40b9a0c1a8ada21b6c7423e5c2f7be0e42fc Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:44 +0200 Subject: [PATCH 1858/2711] clk: mediatek: Add MT8196 ovl0 clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 ovl0 clock controller, which provides clock gate control for the display system. It is integrated with the mtk-mmsys driver, which registers the ovl0 clock driver via platform_device_register_data(). Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Makefile | 3 +- drivers/clk/mediatek/clk-mt8196-ovl0.c | 154 +++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mediatek/clk-mt8196-ovl0.c diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 5b8969ff1985..f42e29fcb19a 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -157,7 +157,8 @@ obj-$(CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP) += clk-mt8196-imp_iic_wrap.o obj-$(CONFIG_COMMON_CLK_MT8196_MCUSYS) += clk-mt8196-mcu.o obj-$(CONFIG_COMMON_CLK_MT8196_MDPSYS) += clk-mt8196-mdpsys.o obj-$(CONFIG_COMMON_CLK_MT8196_MFGCFG) += clk-mt8196-mfg.o -obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o clk-mt8196-disp1.o clk-mt8196-vdisp_ao.o +obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o clk-mt8196-disp1.o clk-mt8196-vdisp_ao.o \ + clk-mt8196-ovl0.o obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o diff --git a/drivers/clk/mediatek/clk-mt8196-ovl0.c b/drivers/clk/mediatek/clk-mt8196-ovl0.c new file mode 100644 index 000000000000..d4affd14d2c4 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-ovl0.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs ovl0_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs ovl0_hwv_regs = { + .set_ofs = 0x0060, + .clr_ofs = 0x0064, + .sta_ofs = 0x2c30, +}; + +static const struct mtk_gate_regs ovl1_cg_regs = { + .set_ofs = 0x114, + .clr_ofs = 0x118, + .sta_ofs = 0x110, +}; + +static const struct mtk_gate_regs ovl1_hwv_regs = { + .set_ofs = 0x0068, + .clr_ofs = 0x006c, + .sta_ofs = 0x2c34, +}; + +#define GATE_HWV_OVL0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ovl0_cg_regs, \ + .hwv_regs = &ovl0_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_HWV_OVL1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ovl1_cg_regs, \ + .hwv_regs = &ovl1_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +static const struct mtk_gate ovl_clks[] = { + /* OVL0 */ + GATE_HWV_OVL0(CLK_OVLSYS_CONFIG, "ovlsys_config", "disp", 0), + GATE_HWV_OVL0(CLK_OVL_FAKE_ENG0, "ovl_fake_eng0", "disp", 1), + GATE_HWV_OVL0(CLK_OVL_FAKE_ENG1, "ovl_fake_eng1", "disp", 2), + GATE_HWV_OVL0(CLK_OVL_MUTEX0, "ovl_mutex0", "disp", 3), + GATE_HWV_OVL0(CLK_OVL_EXDMA0, "ovl_exdma0", "disp", 4), + GATE_HWV_OVL0(CLK_OVL_EXDMA1, "ovl_exdma1", "disp", 5), + GATE_HWV_OVL0(CLK_OVL_EXDMA2, "ovl_exdma2", "disp", 6), + GATE_HWV_OVL0(CLK_OVL_EXDMA3, "ovl_exdma3", "disp", 7), + GATE_HWV_OVL0(CLK_OVL_EXDMA4, "ovl_exdma4", "disp", 8), + GATE_HWV_OVL0(CLK_OVL_EXDMA5, "ovl_exdma5", "disp", 9), + GATE_HWV_OVL0(CLK_OVL_EXDMA6, "ovl_exdma6", "disp", 10), + GATE_HWV_OVL0(CLK_OVL_EXDMA7, "ovl_exdma7", "disp", 11), + GATE_HWV_OVL0(CLK_OVL_EXDMA8, "ovl_exdma8", "disp", 12), + GATE_HWV_OVL0(CLK_OVL_EXDMA9, "ovl_exdma9", "disp", 13), + GATE_HWV_OVL0(CLK_OVL_BLENDER0, "ovl_blender0", "disp", 14), + GATE_HWV_OVL0(CLK_OVL_BLENDER1, "ovl_blender1", "disp", 15), + GATE_HWV_OVL0(CLK_OVL_BLENDER2, "ovl_blender2", "disp", 16), + GATE_HWV_OVL0(CLK_OVL_BLENDER3, "ovl_blender3", "disp", 17), + GATE_HWV_OVL0(CLK_OVL_BLENDER4, "ovl_blender4", "disp", 18), + GATE_HWV_OVL0(CLK_OVL_BLENDER5, "ovl_blender5", "disp", 19), + GATE_HWV_OVL0(CLK_OVL_BLENDER6, "ovl_blender6", "disp", 20), + GATE_HWV_OVL0(CLK_OVL_BLENDER7, "ovl_blender7", "disp", 21), + GATE_HWV_OVL0(CLK_OVL_BLENDER8, "ovl_blender8", "disp", 22), + GATE_HWV_OVL0(CLK_OVL_BLENDER9, "ovl_blender9", "disp", 23), + GATE_HWV_OVL0(CLK_OVL_OUTPROC0, "ovl_outproc0", "disp", 24), + GATE_HWV_OVL0(CLK_OVL_OUTPROC1, "ovl_outproc1", "disp", 25), + GATE_HWV_OVL0(CLK_OVL_OUTPROC2, "ovl_outproc2", "disp", 26), + GATE_HWV_OVL0(CLK_OVL_OUTPROC3, "ovl_outproc3", "disp", 27), + GATE_HWV_OVL0(CLK_OVL_OUTPROC4, "ovl_outproc4", "disp", 28), + GATE_HWV_OVL0(CLK_OVL_OUTPROC5, "ovl_outproc5", "disp", 29), + GATE_HWV_OVL0(CLK_OVL_MDP_RSZ0, "ovl_mdp_rsz0", "disp", 30), + GATE_HWV_OVL0(CLK_OVL_MDP_RSZ1, "ovl_mdp_rsz1", "disp", 31), + /* OVL1 */ + GATE_HWV_OVL1(CLK_OVL_DISP_WDMA0, "ovl_disp_wdma0", "disp", 0), + GATE_HWV_OVL1(CLK_OVL_DISP_WDMA1, "ovl_disp_wdma1", "disp", 1), + GATE_HWV_OVL1(CLK_OVL_UFBC_WDMA0, "ovl_ufbc_wdma0", "disp", 2), + GATE_HWV_OVL1(CLK_OVL_MDP_RDMA0, "ovl_mdp_rdma0", "disp", 3), + GATE_HWV_OVL1(CLK_OVL_MDP_RDMA1, "ovl_mdp_rdma1", "disp", 4), + GATE_HWV_OVL1(CLK_OVL_BWM0, "ovl_bwm0", "disp", 5), + GATE_HWV_OVL1(CLK_OVL_DLI0, "ovl_dli0", "disp", 6), + GATE_HWV_OVL1(CLK_OVL_DLI1, "ovl_dli1", "disp", 7), + GATE_HWV_OVL1(CLK_OVL_DLI2, "ovl_dli2", "disp", 8), + GATE_HWV_OVL1(CLK_OVL_DLI3, "ovl_dli3", "disp", 9), + GATE_HWV_OVL1(CLK_OVL_DLI4, "ovl_dli4", "disp", 10), + GATE_HWV_OVL1(CLK_OVL_DLI5, "ovl_dli5", "disp", 11), + GATE_HWV_OVL1(CLK_OVL_DLI6, "ovl_dli6", "disp", 12), + GATE_HWV_OVL1(CLK_OVL_DLI7, "ovl_dli7", "disp", 13), + GATE_HWV_OVL1(CLK_OVL_DLI8, "ovl_dli8", "disp", 14), + GATE_HWV_OVL1(CLK_OVL_DLO0, "ovl_dlo0", "disp", 15), + GATE_HWV_OVL1(CLK_OVL_DLO1, "ovl_dlo1", "disp", 16), + GATE_HWV_OVL1(CLK_OVL_DLO2, "ovl_dlo2", "disp", 17), + GATE_HWV_OVL1(CLK_OVL_DLO3, "ovl_dlo3", "disp", 18), + GATE_HWV_OVL1(CLK_OVL_DLO4, "ovl_dlo4", "disp", 19), + GATE_HWV_OVL1(CLK_OVL_DLO5, "ovl_dlo5", "disp", 20), + GATE_HWV_OVL1(CLK_OVL_DLO6, "ovl_dlo6", "disp", 21), + GATE_HWV_OVL1(CLK_OVL_DLO7, "ovl_dlo7", "disp", 22), + GATE_HWV_OVL1(CLK_OVL_DLO8, "ovl_dlo8", "disp", 23), + GATE_HWV_OVL1(CLK_OVL_DLO9, "ovl_dlo9", "disp", 24), + GATE_HWV_OVL1(CLK_OVL_DLO10, "ovl_dlo10", "disp", 25), + GATE_HWV_OVL1(CLK_OVL_DLO11, "ovl_dlo11", "disp", 26), + GATE_HWV_OVL1(CLK_OVL_DLO12, "ovl_dlo12", "disp", 27), + GATE_HWV_OVL1(CLK_OVLSYS_RELAY0, "ovlsys_relay0", "disp", 28), + GATE_HWV_OVL1(CLK_OVL_INLINEROT0, "ovl_inlinerot0", "disp", 29), + GATE_HWV_OVL1(CLK_OVL_SMI, "ovl_smi", "disp", 30), +}; + +static const struct mtk_clk_desc ovl_mcd = { + .clks = ovl_clks, + .num_clks = ARRAY_SIZE(ovl_clks), +}; + +static const struct platform_device_id clk_mt8196_ovl0_id_table[] = { + { .name = "clk-mt8196-ovl0", .driver_data = (kernel_ulong_t)&ovl_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8196_ovl0_id_table); + +static struct platform_driver clk_mt8196_ovl0_drv = { + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, + .driver = { + .name = "clk-mt8196-ovl0", + }, + .id_table = clk_mt8196_ovl0_id_table, +}; +module_platform_driver(clk_mt8196_ovl0_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 ovl0 clocks driver"); +MODULE_LICENSE("GPL"); From 1a7f3d32da3e5c8fb5079c354d9b04189704009b Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:45 +0200 Subject: [PATCH 1859/2711] clk: mediatek: Add MT8196 ovl1 clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 ovl1 clock controller, which provides clock gate control for the display system. It is integrated with the mtk-mmsys driver, which registers the ovl1 clock driver via platform_device_register_data(). Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Makefile | 2 +- drivers/clk/mediatek/clk-mt8196-ovl1.c | 154 +++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mediatek/clk-mt8196-ovl1.c diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index f42e29fcb19a..f3afd34311c8 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -158,7 +158,7 @@ obj-$(CONFIG_COMMON_CLK_MT8196_MCUSYS) += clk-mt8196-mcu.o obj-$(CONFIG_COMMON_CLK_MT8196_MDPSYS) += clk-mt8196-mdpsys.o obj-$(CONFIG_COMMON_CLK_MT8196_MFGCFG) += clk-mt8196-mfg.o obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o clk-mt8196-disp1.o clk-mt8196-vdisp_ao.o \ - clk-mt8196-ovl0.o + clk-mt8196-ovl0.o clk-mt8196-ovl1.o obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o diff --git a/drivers/clk/mediatek/clk-mt8196-ovl1.c b/drivers/clk/mediatek/clk-mt8196-ovl1.c new file mode 100644 index 000000000000..c8843d0d3ede --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-ovl1.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs ovl10_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs ovl10_hwv_regs = { + .set_ofs = 0x0050, + .clr_ofs = 0x0054, + .sta_ofs = 0x2c28, +}; + +static const struct mtk_gate_regs ovl11_cg_regs = { + .set_ofs = 0x114, + .clr_ofs = 0x118, + .sta_ofs = 0x110, +}; + +static const struct mtk_gate_regs ovl11_hwv_regs = { + .set_ofs = 0x0058, + .clr_ofs = 0x005c, + .sta_ofs = 0x2c2c, +}; + +#define GATE_HWV_OVL10(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ovl10_cg_regs, \ + .hwv_regs = &ovl10_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_HWV_OVL11(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ovl11_cg_regs, \ + .hwv_regs = &ovl11_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +static const struct mtk_gate ovl1_clks[] = { + /* OVL10 */ + GATE_HWV_OVL10(CLK_OVL1_OVLSYS_CONFIG, "ovl1_ovlsys_config", "disp", 0), + GATE_HWV_OVL10(CLK_OVL1_OVL_FAKE_ENG0, "ovl1_ovl_fake_eng0", "disp", 1), + GATE_HWV_OVL10(CLK_OVL1_OVL_FAKE_ENG1, "ovl1_ovl_fake_eng1", "disp", 2), + GATE_HWV_OVL10(CLK_OVL1_OVL_MUTEX0, "ovl1_ovl_mutex0", "disp", 3), + GATE_HWV_OVL10(CLK_OVL1_OVL_EXDMA0, "ovl1_ovl_exdma0", "disp", 4), + GATE_HWV_OVL10(CLK_OVL1_OVL_EXDMA1, "ovl1_ovl_exdma1", "disp", 5), + GATE_HWV_OVL10(CLK_OVL1_OVL_EXDMA2, "ovl1_ovl_exdma2", "disp", 6), + GATE_HWV_OVL10(CLK_OVL1_OVL_EXDMA3, "ovl1_ovl_exdma3", "disp", 7), + GATE_HWV_OVL10(CLK_OVL1_OVL_EXDMA4, "ovl1_ovl_exdma4", "disp", 8), + GATE_HWV_OVL10(CLK_OVL1_OVL_EXDMA5, "ovl1_ovl_exdma5", "disp", 9), + GATE_HWV_OVL10(CLK_OVL1_OVL_EXDMA6, "ovl1_ovl_exdma6", "disp", 10), + GATE_HWV_OVL10(CLK_OVL1_OVL_EXDMA7, "ovl1_ovl_exdma7", "disp", 11), + GATE_HWV_OVL10(CLK_OVL1_OVL_EXDMA8, "ovl1_ovl_exdma8", "disp", 12), + GATE_HWV_OVL10(CLK_OVL1_OVL_EXDMA9, "ovl1_ovl_exdma9", "disp", 13), + GATE_HWV_OVL10(CLK_OVL1_OVL_BLENDER0, "ovl1_ovl_blender0", "disp", 14), + GATE_HWV_OVL10(CLK_OVL1_OVL_BLENDER1, "ovl1_ovl_blender1", "disp", 15), + GATE_HWV_OVL10(CLK_OVL1_OVL_BLENDER2, "ovl1_ovl_blender2", "disp", 16), + GATE_HWV_OVL10(CLK_OVL1_OVL_BLENDER3, "ovl1_ovl_blender3", "disp", 17), + GATE_HWV_OVL10(CLK_OVL1_OVL_BLENDER4, "ovl1_ovl_blender4", "disp", 18), + GATE_HWV_OVL10(CLK_OVL1_OVL_BLENDER5, "ovl1_ovl_blender5", "disp", 19), + GATE_HWV_OVL10(CLK_OVL1_OVL_BLENDER6, "ovl1_ovl_blender6", "disp", 20), + GATE_HWV_OVL10(CLK_OVL1_OVL_BLENDER7, "ovl1_ovl_blender7", "disp", 21), + GATE_HWV_OVL10(CLK_OVL1_OVL_BLENDER8, "ovl1_ovl_blender8", "disp", 22), + GATE_HWV_OVL10(CLK_OVL1_OVL_BLENDER9, "ovl1_ovl_blender9", "disp", 23), + GATE_HWV_OVL10(CLK_OVL1_OVL_OUTPROC0, "ovl1_ovl_outproc0", "disp", 24), + GATE_HWV_OVL10(CLK_OVL1_OVL_OUTPROC1, "ovl1_ovl_outproc1", "disp", 25), + GATE_HWV_OVL10(CLK_OVL1_OVL_OUTPROC2, "ovl1_ovl_outproc2", "disp", 26), + GATE_HWV_OVL10(CLK_OVL1_OVL_OUTPROC3, "ovl1_ovl_outproc3", "disp", 27), + GATE_HWV_OVL10(CLK_OVL1_OVL_OUTPROC4, "ovl1_ovl_outproc4", "disp", 28), + GATE_HWV_OVL10(CLK_OVL1_OVL_OUTPROC5, "ovl1_ovl_outproc5", "disp", 29), + GATE_HWV_OVL10(CLK_OVL1_OVL_MDP_RSZ0, "ovl1_ovl_mdp_rsz0", "disp", 30), + GATE_HWV_OVL10(CLK_OVL1_OVL_MDP_RSZ1, "ovl1_ovl_mdp_rsz1", "disp", 31), + /* OVL11 */ + GATE_HWV_OVL11(CLK_OVL1_OVL_DISP_WDMA0, "ovl1_ovl_disp_wdma0", "disp", 0), + GATE_HWV_OVL11(CLK_OVL1_OVL_DISP_WDMA1, "ovl1_ovl_disp_wdma1", "disp", 1), + GATE_HWV_OVL11(CLK_OVL1_OVL_UFBC_WDMA0, "ovl1_ovl_ufbc_wdma0", "disp", 2), + GATE_HWV_OVL11(CLK_OVL1_OVL_MDP_RDMA0, "ovl1_ovl_mdp_rdma0", "disp", 3), + GATE_HWV_OVL11(CLK_OVL1_OVL_MDP_RDMA1, "ovl1_ovl_mdp_rdma1", "disp", 4), + GATE_HWV_OVL11(CLK_OVL1_OVL_BWM0, "ovl1_ovl_bwm0", "disp", 5), + GATE_HWV_OVL11(CLK_OVL1_DLI0, "ovl1_dli0", "disp", 6), + GATE_HWV_OVL11(CLK_OVL1_DLI1, "ovl1_dli1", "disp", 7), + GATE_HWV_OVL11(CLK_OVL1_DLI2, "ovl1_dli2", "disp", 8), + GATE_HWV_OVL11(CLK_OVL1_DLI3, "ovl1_dli3", "disp", 9), + GATE_HWV_OVL11(CLK_OVL1_DLI4, "ovl1_dli4", "disp", 10), + GATE_HWV_OVL11(CLK_OVL1_DLI5, "ovl1_dli5", "disp", 11), + GATE_HWV_OVL11(CLK_OVL1_DLI6, "ovl1_dli6", "disp", 12), + GATE_HWV_OVL11(CLK_OVL1_DLI7, "ovl1_dli7", "disp", 13), + GATE_HWV_OVL11(CLK_OVL1_DLI8, "ovl1_dli8", "disp", 14), + GATE_HWV_OVL11(CLK_OVL1_DLO0, "ovl1_dlo0", "disp", 15), + GATE_HWV_OVL11(CLK_OVL1_DLO1, "ovl1_dlo1", "disp", 16), + GATE_HWV_OVL11(CLK_OVL1_DLO2, "ovl1_dlo2", "disp", 17), + GATE_HWV_OVL11(CLK_OVL1_DLO3, "ovl1_dlo3", "disp", 18), + GATE_HWV_OVL11(CLK_OVL1_DLO4, "ovl1_dlo4", "disp", 19), + GATE_HWV_OVL11(CLK_OVL1_DLO5, "ovl1_dlo5", "disp", 20), + GATE_HWV_OVL11(CLK_OVL1_DLO6, "ovl1_dlo6", "disp", 21), + GATE_HWV_OVL11(CLK_OVL1_DLO7, "ovl1_dlo7", "disp", 22), + GATE_HWV_OVL11(CLK_OVL1_DLO8, "ovl1_dlo8", "disp", 23), + GATE_HWV_OVL11(CLK_OVL1_DLO9, "ovl1_dlo9", "disp", 24), + GATE_HWV_OVL11(CLK_OVL1_DLO10, "ovl1_dlo10", "disp", 25), + GATE_HWV_OVL11(CLK_OVL1_DLO11, "ovl1_dlo11", "disp", 26), + GATE_HWV_OVL11(CLK_OVL1_DLO12, "ovl1_dlo12", "disp", 27), + GATE_HWV_OVL11(CLK_OVL1_OVLSYS_RELAY0, "ovl1_ovlsys_relay0", "disp", 28), + GATE_HWV_OVL11(CLK_OVL1_OVL_INLINEROT0, "ovl1_ovl_inlinerot0", "disp", 29), + GATE_HWV_OVL11(CLK_OVL1_SMI, "ovl1_smi", "disp", 30), +}; + +static const struct mtk_clk_desc ovl1_mcd = { + .clks = ovl1_clks, + .num_clks = ARRAY_SIZE(ovl1_clks), +}; + +static const struct platform_device_id clk_mt8196_ovl1_id_table[] = { + { .name = "clk-mt8196-ovl1", .driver_data = (kernel_ulong_t)&ovl1_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8196_ovl1_id_table); + +static struct platform_driver clk_mt8196_ovl1_drv = { + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, + .driver = { + .name = "clk-mt8196-ovl1", + }, + .id_table = clk_mt8196_ovl1_id_table, +}; +module_platform_driver(clk_mt8196_ovl1_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 ovl1 clocks driver"); +MODULE_LICENSE("GPL"); From 32ce24a3131b07b4348281f9e34359cb45883b25 Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:46 +0200 Subject: [PATCH 1860/2711] clk: mediatek: Add MT8196 vdecsys clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 vdecsys clock controller, which provides clock gate control for the video decoder. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 7 + drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt8196-vdec.c | 253 +++++++++++++++++++++++++ 3 files changed, 261 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8196-vdec.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 77e18bceae91..939d7d27c0c8 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1059,6 +1059,13 @@ config COMMON_CLK_MT8196_UFSSYS help This driver supports MediaTek MT8196 ufssys clocks. +config COMMON_CLK_MT8196_VDECSYS + tristate "Clock driver for MediaTek MT8196 vdecsys" + depends on COMMON_CLK_MT8196 + default m + help + This driver supports MediaTek MT8196 vdecsys clocks. + config COMMON_CLK_MT8365 tristate "Clock driver for MediaTek MT8365" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index f3afd34311c8..131582b12783 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -161,6 +161,7 @@ obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o clk-mt8196-disp1.o c clk-mt8196-ovl0.o clk-mt8196-ovl1.o obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o +obj-$(CONFIG_COMMON_CLK_MT8196_VDECSYS) += clk-mt8196-vdec.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o diff --git a/drivers/clk/mediatek/clk-mt8196-vdec.c b/drivers/clk/mediatek/clk-mt8196-vdec.c new file mode 100644 index 000000000000..f8dcd84a2b58 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-vdec.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs vde20_cg_regs = { + .set_ofs = 0x0, + .clr_ofs = 0x4, + .sta_ofs = 0x0, +}; + +static const struct mtk_gate_regs vde20_hwv_regs = { + .set_ofs = 0x0088, + .clr_ofs = 0x008c, + .sta_ofs = 0x2c44, +}; + +static const struct mtk_gate_regs vde21_cg_regs = { + .set_ofs = 0x200, + .clr_ofs = 0x204, + .sta_ofs = 0x200, +}; + +static const struct mtk_gate_regs vde21_hwv_regs = { + .set_ofs = 0x0080, + .clr_ofs = 0x0084, + .sta_ofs = 0x2c40, +}; + +static const struct mtk_gate_regs vde22_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0xc, + .sta_ofs = 0x8, +}; + +static const struct mtk_gate_regs vde22_hwv_regs = { + .set_ofs = 0x0078, + .clr_ofs = 0x007c, + .sta_ofs = 0x2c3c, +}; + +#define GATE_HWV_VDE20(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vde20_cg_regs, \ + .hwv_regs = &vde20_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv,\ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_HWV_VDE21(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vde21_cg_regs, \ + .hwv_regs = &vde21_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv,\ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_HWV_VDE22(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vde22_cg_regs, \ + .hwv_regs = &vde22_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv,\ + .flags = CLK_OPS_PARENT_ENABLE | \ + CLK_IGNORE_UNUSED, \ + } + +static const struct mtk_gate vde2_clks[] = { + /* VDE20 */ + GATE_HWV_VDE20(CLK_VDE2_VDEC_CKEN, "vde2_vdec_cken", "vdec", 0), + GATE_HWV_VDE20(CLK_VDE2_VDEC_ACTIVE, "vde2_vdec_active", "vdec", 4), + GATE_HWV_VDE20(CLK_VDE2_VDEC_CKEN_ENG, "vde2_vdec_cken_eng", "vdec", 8), + /* VDE21 */ + GATE_HWV_VDE21(CLK_VDE2_LAT_CKEN, "vde2_lat_cken", "vdec", 0), + GATE_HWV_VDE21(CLK_VDE2_LAT_ACTIVE, "vde2_lat_active", "vdec", 4), + GATE_HWV_VDE21(CLK_VDE2_LAT_CKEN_ENG, "vde2_lat_cken_eng", "vdec", 8), + /* VDE22 */ + GATE_HWV_VDE22(CLK_VDE2_LARB1_CKEN, "vde2_larb1_cken", "vdec", 0), +}; + +static const struct mtk_clk_desc vde2_mcd = { + .clks = vde2_clks, + .num_clks = ARRAY_SIZE(vde2_clks), + .need_runtime_pm = true, +}; + +static const struct mtk_gate_regs vde10_hwv_regs = { + .set_ofs = 0x00a0, + .clr_ofs = 0x00a4, + .sta_ofs = 0x2c50, +}; + +static const struct mtk_gate_regs vde11_cg_regs = { + .set_ofs = 0x1e0, + .clr_ofs = 0x1e0, + .sta_ofs = 0x1e0, +}; + +static const struct mtk_gate_regs vde11_hwv_regs = { + .set_ofs = 0x00b0, + .clr_ofs = 0x00b4, + .sta_ofs = 0x2c58, +}; + +static const struct mtk_gate_regs vde12_cg_regs = { + .set_ofs = 0x1ec, + .clr_ofs = 0x1ec, + .sta_ofs = 0x1ec, +}; + +static const struct mtk_gate_regs vde12_hwv_regs = { + .set_ofs = 0x00a8, + .clr_ofs = 0x00ac, + .sta_ofs = 0x2c54, +}; + +static const struct mtk_gate_regs vde13_cg_regs = { + .set_ofs = 0x200, + .clr_ofs = 0x204, + .sta_ofs = 0x200, +}; + +static const struct mtk_gate_regs vde13_hwv_regs = { + .set_ofs = 0x0098, + .clr_ofs = 0x009c, + .sta_ofs = 0x2c4c, +}; + +static const struct mtk_gate_regs vde14_hwv_regs = { + .set_ofs = 0x0090, + .clr_ofs = 0x0094, + .sta_ofs = 0x2c48, +}; + +#define GATE_HWV_VDE10(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vde20_cg_regs, \ + .hwv_regs = &vde10_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv,\ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_HWV_VDE11(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vde11_cg_regs, \ + .hwv_regs = &vde11_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_HWV_VDE12(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vde12_cg_regs, \ + .hwv_regs = &vde12_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv, \ + .flags = CLK_OPS_PARENT_ENABLE \ + } + +#define GATE_HWV_VDE13(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vde13_cg_regs, \ + .hwv_regs = &vde13_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv,\ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_HWV_VDE14(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vde22_cg_regs, \ + .hwv_regs = &vde14_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv,\ + .flags = CLK_OPS_PARENT_ENABLE | \ + CLK_IGNORE_UNUSED, \ + } + +static const struct mtk_gate vde1_clks[] = { + /* VDE10 */ + GATE_HWV_VDE10(CLK_VDE1_VDEC_CKEN, "vde1_vdec_cken", "vdec", 0), + GATE_HWV_VDE10(CLK_VDE1_VDEC_ACTIVE, "vde1_vdec_active", "vdec", 4), + GATE_HWV_VDE10(CLK_VDE1_VDEC_CKEN_ENG, "vde1_vdec_cken_eng", "vdec", 8), + /* VDE11 */ + GATE_HWV_VDE11(CLK_VDE1_VDEC_SOC_IPS_EN, "vde1_vdec_soc_ips_en", "vdec", 0), + /* VDE12 */ + GATE_HWV_VDE12(CLK_VDE1_VDEC_SOC_APTV_EN, "vde1_aptv_en", "ck_tck_26m_mx9_ck", 0), + GATE_HWV_VDE12(CLK_VDE1_VDEC_SOC_APTV_TOP_EN, "vde1_aptv_topen", "ck_tck_26m_mx9_ck", 1), + /* VDE13 */ + GATE_HWV_VDE13(CLK_VDE1_LAT_CKEN, "vde1_lat_cken", "vdec", 0), + GATE_HWV_VDE13(CLK_VDE1_LAT_ACTIVE, "vde1_lat_active", "vdec", 4), + GATE_HWV_VDE13(CLK_VDE1_LAT_CKEN_ENG, "vde1_lat_cken_eng", "vdec", 8), + /* VDE14 */ + GATE_HWV_VDE14(CLK_VDE1_LARB1_CKEN, "vde1_larb1_cken", "vdec", 0), +}; + +static const struct mtk_clk_desc vde1_mcd = { + .clks = vde1_clks, + .num_clks = ARRAY_SIZE(vde1_clks), + .need_runtime_pm = true, +}; + +static const struct of_device_id of_match_clk_mt8196_vdec[] = { + { .compatible = "mediatek,mt8196-vdecsys", .data = &vde2_mcd }, + { .compatible = "mediatek,mt8196-vdecsys-soc", .data = &vde1_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_vdec); + +static struct platform_driver clk_mt8196_vdec_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8196-vdec", + .of_match_table = of_match_clk_mt8196_vdec, + }, +}; +module_platform_driver(clk_mt8196_vdec_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 Video Decoders clocks driver"); +MODULE_LICENSE("GPL"); From 2f66f069999dda4a44c5586805d468b8ac93ac1a Mon Sep 17 00:00:00 2001 From: Laura Nao Date: Mon, 15 Sep 2025 17:19:47 +0200 Subject: [PATCH 1861/2711] clk: mediatek: Add MT8196 vencsys clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the MT8196 vencsys clock controller, which provides clock gate control for the video encoder. Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 7 + drivers/clk/mediatek/Makefile | 1 + drivers/clk/mediatek/clk-mt8196-venc.c | 236 +++++++++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 drivers/clk/mediatek/clk-mt8196-venc.c diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 939d7d27c0c8..0e8dd82aa84e 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1066,6 +1066,13 @@ config COMMON_CLK_MT8196_VDECSYS help This driver supports MediaTek MT8196 vdecsys clocks. +config COMMON_CLK_MT8196_VENCSYS + tristate "Clock driver for MediaTek MT8196 vencsys" + depends on COMMON_CLK_MT8196 + default m + help + This driver supports MediaTek MT8196 vencsys clocks. + config COMMON_CLK_MT8365 tristate "Clock driver for MediaTek MT8365" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 131582b12783..d8736a060dbd 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -162,6 +162,7 @@ obj-$(CONFIG_COMMON_CLK_MT8196_MMSYS) += clk-mt8196-disp0.o clk-mt8196-disp1.o c obj-$(CONFIG_COMMON_CLK_MT8196_PEXTPSYS) += clk-mt8196-pextp.o obj-$(CONFIG_COMMON_CLK_MT8196_UFSSYS) += clk-mt8196-ufs_ao.o obj-$(CONFIG_COMMON_CLK_MT8196_VDECSYS) += clk-mt8196-vdec.o +obj-$(CONFIG_COMMON_CLK_MT8196_VENCSYS) += clk-mt8196-venc.o obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o diff --git a/drivers/clk/mediatek/clk-mt8196-venc.c b/drivers/clk/mediatek/clk-mt8196-venc.c new file mode 100644 index 000000000000..13e2e36e945f --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8196-venc.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 MediaTek Inc. + * Guangjie Song + * Copyright (c) 2025 Collabora Ltd. + * Laura Nao + */ +#include + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs ven10_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +static const struct mtk_gate_regs ven10_hwv_regs = { + .set_ofs = 0x00b8, + .clr_ofs = 0x00bc, + .sta_ofs = 0x2c5c, +}; + +static const struct mtk_gate_regs ven11_cg_regs = { + .set_ofs = 0x10, + .clr_ofs = 0x14, + .sta_ofs = 0x10, +}; + +static const struct mtk_gate_regs ven11_hwv_regs = { + .set_ofs = 0x00c0, + .clr_ofs = 0x00c4, + .sta_ofs = 0x2c60, +}; + +#define GATE_VEN10(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ven10_cg_regs, \ + .shift = _shift, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +#define GATE_HWV_VEN10_FLAGS(_id, _name, _parent, _shift, _flags) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ven10_cg_regs, \ + .hwv_regs = &ven10_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv, \ + .flags = (_flags) | \ + CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_HWV_VEN10(_id, _name, _parent, _shift) \ + GATE_HWV_VEN10_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_HWV_VEN11(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ven11_cg_regs, \ + .hwv_regs = &ven11_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv,\ + .flags = CLK_OPS_PARENT_ENABLE \ + } + +static const struct mtk_gate ven1_clks[] = { + /* VEN10 */ + GATE_HWV_VEN10(CLK_VEN1_CKE0_LARB, "ven1_larb", "venc", 0), + GATE_HWV_VEN10(CLK_VEN1_CKE1_VENC, "ven1_venc", "venc", 4), + GATE_VEN10(CLK_VEN1_CKE2_JPGENC, "ven1_jpgenc", "venc", 8), + GATE_VEN10(CLK_VEN1_CKE3_JPGDEC, "ven1_jpgdec", "venc", 12), + GATE_VEN10(CLK_VEN1_CKE4_JPGDEC_C1, "ven1_jpgdec_c1", "venc", 16), + GATE_HWV_VEN10(CLK_VEN1_CKE5_GALS, "ven1_gals", "venc", 28), + GATE_HWV_VEN10(CLK_VEN1_CKE29_VENC_ADAB_CTRL, "ven1_venc_adab_ctrl", + "venc", 29), + GATE_HWV_VEN10_FLAGS(CLK_VEN1_CKE29_VENC_XPC_CTRL, + "ven1_venc_xpc_ctrl", "venc", 30, + CLK_IGNORE_UNUSED), + GATE_HWV_VEN10(CLK_VEN1_CKE6_GALS_SRAM, "ven1_gals_sram", "venc", 31), + /* VEN11 */ + GATE_HWV_VEN11(CLK_VEN1_RES_FLAT, "ven1_res_flat", "venc", 0), +}; + +static const struct mtk_clk_desc ven1_mcd = { + .clks = ven1_clks, + .num_clks = ARRAY_SIZE(ven1_clks), + .need_runtime_pm = true, +}; + +static const struct mtk_gate_regs ven20_hwv_regs = { + .set_ofs = 0x00c8, + .clr_ofs = 0x00cc, + .sta_ofs = 0x2c64, +}; + +static const struct mtk_gate_regs ven21_hwv_regs = { + .set_ofs = 0x00d0, + .clr_ofs = 0x00d4, + .sta_ofs = 0x2c68, +}; + +#define GATE_VEN20(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ven10_cg_regs, \ + .shift = _shift, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +#define GATE_HWV_VEN20(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ven10_cg_regs, \ + .hwv_regs = &ven20_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv,\ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_HWV_VEN21(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ven11_cg_regs, \ + .hwv_regs = &ven21_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE \ + } + +static const struct mtk_gate ven2_clks[] = { + /* VEN20 */ + GATE_HWV_VEN20(CLK_VEN2_CKE0_LARB, "ven2_larb", "venc", 0), + GATE_HWV_VEN20(CLK_VEN2_CKE1_VENC, "ven2_venc", "venc", 4), + GATE_VEN20(CLK_VEN2_CKE2_JPGENC, "ven2_jpgenc", "venc", 8), + GATE_VEN20(CLK_VEN2_CKE3_JPGDEC, "ven2_jpgdec", "venc", 12), + GATE_HWV_VEN20(CLK_VEN2_CKE5_GALS, "ven2_gals", "venc", 28), + GATE_HWV_VEN20(CLK_VEN2_CKE29_VENC_XPC_CTRL, "ven2_venc_xpc_ctrl", "venc", 30), + GATE_HWV_VEN20(CLK_VEN2_CKE6_GALS_SRAM, "ven2_gals_sram", "venc", 31), + /* VEN21 */ + GATE_HWV_VEN21(CLK_VEN2_RES_FLAT, "ven2_res_flat", "venc", 0), +}; + +static const struct mtk_clk_desc ven2_mcd = { + .clks = ven2_clks, + .num_clks = ARRAY_SIZE(ven2_clks), + .need_runtime_pm = true, +}; + +static const struct mtk_gate_regs ven_c20_hwv_regs = { + .set_ofs = 0x00d8, + .clr_ofs = 0x00dc, + .sta_ofs = 0x2c6c, +}; + +static const struct mtk_gate_regs ven_c21_hwv_regs = { + .set_ofs = 0x00e0, + .clr_ofs = 0x00e4, + .sta_ofs = 0x2c70, +}; + +#define GATE_HWV_VEN_C20(_id, _name, _parent, _shift) {\ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ven10_cg_regs, \ + .hwv_regs = &ven_c20_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr_inv,\ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +#define GATE_HWV_VEN_C21(_id, _name, _parent, _shift) {\ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ven11_cg_regs, \ + .hwv_regs = &ven_c21_hwv_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_hwv_ops_setclr, \ + .flags = CLK_OPS_PARENT_ENABLE, \ + } + +static const struct mtk_gate ven_c2_clks[] = { + /* VEN_C20 */ + GATE_HWV_VEN_C20(CLK_VEN_C2_CKE0_LARB, "ven_c2_larb", "venc", 0), + GATE_HWV_VEN_C20(CLK_VEN_C2_CKE1_VENC, "ven_c2_venc", "venc", 4), + GATE_HWV_VEN_C20(CLK_VEN_C2_CKE5_GALS, "ven_c2_gals", "venc", 28), + GATE_HWV_VEN_C20(CLK_VEN_C2_CKE29_VENC_XPC_CTRL, "ven_c2_venc_xpc_ctrl", + "venc", 30), + GATE_HWV_VEN_C20(CLK_VEN_C2_CKE6_GALS_SRAM, "ven_c2_gals_sram", "venc", 31), + /* VEN_C21 */ + GATE_HWV_VEN_C21(CLK_VEN_C2_RES_FLAT, "ven_c2_res_flat", "venc", 0), +}; + +static const struct mtk_clk_desc ven_c2_mcd = { + .clks = ven_c2_clks, + .num_clks = ARRAY_SIZE(ven_c2_clks), + .need_runtime_pm = true, +}; + +static const struct of_device_id of_match_clk_mt8196_venc[] = { + { .compatible = "mediatek,mt8196-vencsys", .data = &ven1_mcd }, + { .compatible = "mediatek,mt8196-vencsys-c1", .data = &ven2_mcd }, + { .compatible = "mediatek,mt8196-vencsys-c2", .data = &ven_c2_mcd }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_venc); + +static struct platform_driver clk_mt8196_venc_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8196-venc", + .of_match_table = of_match_clk_mt8196_venc, + }, +}; +module_platform_driver(clk_mt8196_venc_drv); + +MODULE_DESCRIPTION("MediaTek MT8196 Video Encoders clocks driver"); +MODULE_LICENSE("GPL"); From bbcc60a43cf80c4d609bcddcb42bb5641066ac45 Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Fri, 12 Sep 2025 13:36:11 +0200 Subject: [PATCH 1862/2711] clk: st: flexgen: remove unused compatible Following B2120 boards removal in commit dee546e1adef ("ARM: sti: drop B2120 board support"), several compatibles are left unused. Remove them. Signed-off-by: Raphael Gallais-Pou Reviewed-by: Patrice Chotard Reviewed-by: Brian Masney Signed-off-by: Stephen Boyd --- drivers/clk/st/clk-flexgen.c | 80 ------------------------------------ 1 file changed, 80 deletions(-) diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c index 5292208c4dd8..e8e7626c76db 100644 --- a/drivers/clk/st/clk-flexgen.c +++ b/drivers/clk/st/clk-flexgen.c @@ -303,16 +303,6 @@ static const struct clkgen_data clkgen_video = { .mode = 1, }; -static const struct clkgen_clk_out clkgen_stih407_a0_clk_out[] = { - /* This clk needs to be on so that memory interface is accessible */ - { .name = "clk-ic-lmi0", .flags = CLK_IS_CRITICAL }, -}; - -static const struct clkgen_data clkgen_stih407_a0 = { - .outputs = clkgen_stih407_a0_clk_out, - .outputs_nb = ARRAY_SIZE(clkgen_stih407_a0_clk_out), -}; - static const struct clkgen_clk_out clkgen_stih410_a0_clk_out[] = { /* Those clks need to be on so that memory interface is accessible */ { .name = "clk-ic-lmi0", .flags = CLK_IS_CRITICAL }, @@ -324,51 +314,6 @@ static const struct clkgen_data clkgen_stih410_a0 = { .outputs_nb = ARRAY_SIZE(clkgen_stih410_a0_clk_out), }; -static const struct clkgen_clk_out clkgen_stih407_c0_clk_out[] = { - { .name = "clk-icn-gpu", }, - { .name = "clk-fdma", }, - { .name = "clk-nand", }, - { .name = "clk-hva", }, - { .name = "clk-proc-stfe", }, - { .name = "clk-proc-tp", }, - { .name = "clk-rx-icn-dmu", }, - { .name = "clk-rx-icn-hva", }, - /* This clk needs to be on to keep bus interconnect alive */ - { .name = "clk-icn-cpu", .flags = CLK_IS_CRITICAL }, - /* This clk needs to be on to keep bus interconnect alive */ - { .name = "clk-tx-icn-dmu", .flags = CLK_IS_CRITICAL }, - { .name = "clk-mmc-0", }, - { .name = "clk-mmc-1", }, - { .name = "clk-jpegdec", }, - /* This clk needs to be on to keep A9 running */ - { .name = "clk-ext2fa9", .flags = CLK_IS_CRITICAL }, - { .name = "clk-ic-bdisp-0", }, - { .name = "clk-ic-bdisp-1", }, - { .name = "clk-pp-dmu", }, - { .name = "clk-vid-dmu", }, - { .name = "clk-dss-lpc", }, - { .name = "clk-st231-aud-0", }, - { .name = "clk-st231-gp-1", }, - { .name = "clk-st231-dmu", }, - /* This clk needs to be on to keep bus interconnect alive */ - { .name = "clk-icn-lmi", .flags = CLK_IS_CRITICAL }, - { .name = "clk-tx-icn-disp-1", }, - /* This clk needs to be on to keep bus interconnect alive */ - { .name = "clk-icn-sbc", .flags = CLK_IS_CRITICAL }, - { .name = "clk-stfe-frc2", }, - { .name = "clk-eth-phy", }, - { .name = "clk-eth-ref-phyclk", }, - { .name = "clk-flash-promip", }, - { .name = "clk-main-disp", }, - { .name = "clk-aux-disp", }, - { .name = "clk-compo-dvp", }, -}; - -static const struct clkgen_data clkgen_stih407_c0 = { - .outputs = clkgen_stih407_c0_clk_out, - .outputs_nb = ARRAY_SIZE(clkgen_stih407_c0_clk_out), -}; - static const struct clkgen_clk_out clkgen_stih410_c0_clk_out[] = { { .name = "clk-icn-gpu", }, { .name = "clk-fdma", }, @@ -482,19 +427,6 @@ static const struct clkgen_data clkgen_stih418_c0 = { .outputs_nb = ARRAY_SIZE(clkgen_stih418_c0_clk_out), }; -static const struct clkgen_clk_out clkgen_stih407_d0_clk_out[] = { - { .name = "clk-pcm-0", }, - { .name = "clk-pcm-1", }, - { .name = "clk-pcm-2", }, - { .name = "clk-spdiff", }, -}; - -static const struct clkgen_data clkgen_stih407_d0 = { - .flags = CLK_SET_RATE_PARENT, - .outputs = clkgen_stih407_d0_clk_out, - .outputs_nb = ARRAY_SIZE(clkgen_stih407_d0_clk_out), -}; - static const struct clkgen_clk_out clkgen_stih410_d0_clk_out[] = { { .name = "clk-pcm-0", }, { .name = "clk-pcm-1", }, @@ -596,18 +528,10 @@ static const struct of_device_id flexgen_of_match[] = { .compatible = "st,flexgen-video", .data = &clkgen_video, }, - { - .compatible = "st,flexgen-stih407-a0", - .data = &clkgen_stih407_a0, - }, { .compatible = "st,flexgen-stih410-a0", .data = &clkgen_stih410_a0, }, - { - .compatible = "st,flexgen-stih407-c0", - .data = &clkgen_stih407_c0, - }, { .compatible = "st,flexgen-stih410-c0", .data = &clkgen_stih410_c0, @@ -616,10 +540,6 @@ static const struct of_device_id flexgen_of_match[] = { .compatible = "st,flexgen-stih418-c0", .data = &clkgen_stih418_c0, }, - { - .compatible = "st,flexgen-stih407-d0", - .data = &clkgen_stih407_d0, - }, { .compatible = "st,flexgen-stih410-d0", .data = &clkgen_stih410_d0, From b52297f6eb82e46ae5ecc34d270e7ed96eca0594 Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Fri, 12 Sep 2025 13:36:12 +0200 Subject: [PATCH 1863/2711] dt-bindings: clock: st: flexgen: remove deprecated compatibles st/stih407-clock.dtsi file has been removed in commit 65322c1daf51 ("clk: st: flexgen: remove unused compatible"). This file has three compatibles which are now dangling. Remove them from documentation. Signed-off-by: Raphael Gallais-Pou Reviewed-by: Brian Masney Reviewed-by: Patrice Chotard Acked-by: Rob Herring (Arm) Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/st/st,flexgen.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/st/st,flexgen.txt b/Documentation/devicetree/bindings/clock/st/st,flexgen.txt index c918075405ba..a9d1c19f30a3 100644 --- a/Documentation/devicetree/bindings/clock/st/st,flexgen.txt +++ b/Documentation/devicetree/bindings/clock/st/st,flexgen.txt @@ -64,12 +64,9 @@ Required properties: audio use case) "st,flexgen-video", "st,flexgen" (enable clock propagation on parent and activate synchronous mode) - "st,flexgen-stih407-a0" "st,flexgen-stih410-a0" - "st,flexgen-stih407-c0" "st,flexgen-stih410-c0" "st,flexgen-stih418-c0" - "st,flexgen-stih407-d0" "st,flexgen-stih410-d0" "st,flexgen-stih407-d2" "st,flexgen-stih418-d2" From 904bed39490cc112b4c66b2ab035e5325cdbfbb6 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 14 Aug 2025 11:53:15 +0800 Subject: [PATCH 1864/2711] clk: Sort include statements The clk core has its include statements in some random order. Clean it up before we add more. Signed-off-by: Chen-Yu Tsai Reviewed-by: Brian Masney Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index b821b2cdb155..2eb63d610cbb 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -6,21 +6,21 @@ * Standard functionality for the common clock API. See Documentation/driver-api/clk.rst */ +#include +#include #include #include -#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include #include -#include -#include #include #include -#include +#include +#include #include "clk.h" From 4bf2d2744e641886a1320bae7e8877f639a1c961 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 14 Aug 2025 11:53:16 +0800 Subject: [PATCH 1865/2711] clk: Use hashtable for global clk lookups A clk lookup using clk_core_lookup() is currently somewhat expensive since it has to walk the whole clk tree to find a match. This is extremely bad in the clk_core_init() function where it is used to look for clk name conflicts, which is always the worst case of walking the whole tree. Moreover, the number of clks checked increases as more clks are registered, causing each subsequent clk registration becoming slower. Add a hashtable for doing clk lookups to replace the tree walk method. On arm64 this increases kernel memory usage by 4 KB for the hashtable, and 16 bytes (2 pointers) for |struct hlist_node| in each clk. On a platform with around 800 clks, this reduces the time spent in clk_core_lookup() significantly: | PID 0 | kworker | | before | after | before | after | ------------------------------------------- avg | 203 us | 2.7 us | 123 us | 1.5 us | ------------------------------------------- min | 4.7 us | 2.3 us | 102 us | 0.9 us | ------------------------------------------- max | 867 us | 4.8 us | 237 us | 3.5 us | ------------------------------------------- culm | 109 ms | 1.5 ms | 21 ms | 0.3 ms | This in turn reduces the time spent in clk_hw_register(), and ultimately, boot time. On a different system with close to 700 clks, This reduces boot time by around 110 ms. While this doesn't seem like a lot, this helps in cases where minimizing boot time is important. Signed-off-by: Chen-Yu Tsai Tested-by: Brian Masney Reviewed-by: Brian Masney Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 50 +++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 2eb63d610cbb..85d2f2481acf 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,8 @@ #include #include #include +#include +#include #include "clk.h" @@ -33,6 +36,9 @@ static struct task_struct *enable_owner; static int prepare_refcnt; static int enable_refcnt; +#define CLK_HASH_BITS 9 +static DEFINE_HASHTABLE(clk_hashtable, CLK_HASH_BITS); + static HLIST_HEAD(clk_root_list); static HLIST_HEAD(clk_orphan_list); static LIST_HEAD(clk_notifier_list); @@ -87,6 +93,7 @@ struct clk_core { struct clk_duty duty; struct hlist_head children; struct hlist_node child_node; + struct hlist_node hashtable_node; struct hlist_head clks; unsigned int notifier_count; #ifdef CONFIG_DEBUG_FS @@ -395,45 +402,20 @@ struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw) } EXPORT_SYMBOL_GPL(clk_hw_get_parent); -static struct clk_core *__clk_lookup_subtree(const char *name, - struct clk_core *core) -{ - struct clk_core *child; - struct clk_core *ret; - - if (!strcmp(core->name, name)) - return core; - - hlist_for_each_entry(child, &core->children, child_node) { - ret = __clk_lookup_subtree(name, child); - if (ret) - return ret; - } - - return NULL; -} - static struct clk_core *clk_core_lookup(const char *name) { - struct clk_core *root_clk; - struct clk_core *ret; + struct clk_core *core; + u32 hash; if (!name) return NULL; - /* search the 'proper' clk tree first */ - hlist_for_each_entry(root_clk, &clk_root_list, child_node) { - ret = __clk_lookup_subtree(name, root_clk); - if (ret) - return ret; - } + hash = full_name_hash(NULL, name, strlen(name)); - /* if not found, then search the orphan tree */ - hlist_for_each_entry(root_clk, &clk_orphan_list, child_node) { - ret = __clk_lookup_subtree(name, root_clk); - if (ret) - return ret; - } + /* search the hashtable */ + hash_for_each_possible(clk_hashtable, core, hashtable_node, hash) + if (!strcmp(core->name, name)) + return core; return NULL; } @@ -4013,6 +3995,8 @@ static int __clk_core_init(struct clk_core *core) hlist_add_head(&core->child_node, &clk_orphan_list); core->orphan = true; } + hash_add(clk_hashtable, &core->hashtable_node, + full_name_hash(NULL, core->name, strlen(core->name))); /* * Set clk's accuracy. The preferred method is to use @@ -4089,6 +4073,7 @@ out: clk_pm_runtime_put(core); unlock: if (ret) { + hash_del(&core->hashtable_node); hlist_del_init(&core->child_node); core->hw->core = NULL; } @@ -4610,6 +4595,7 @@ void clk_unregister(struct clk *clk) clk_core_evict_parent_cache(clk->core); + hash_del(&clk->core->hashtable_node); hlist_del_init(&clk->core->child_node); if (clk->core->prepare_count) From 49f6c8b74d9a20c0dd16bd75c93b981a3d420a37 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Wed, 25 Jun 2025 11:07:24 +0200 Subject: [PATCH 1866/2711] dt-bindings: stm32: add STM32MP21 clocks and reset bindings Adds clock and reset binding entries for STM32MP21 SoC family. Signed-off-by: Nicolas Le Bayon Reviewed-by: Conor Dooley Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- .../bindings/clock/st,stm32mp21-rcc.yaml | 199 ++++++++ include/dt-bindings/clock/st,stm32mp21-rcc.h | 426 ++++++++++++++++++ include/dt-bindings/reset/st,stm32mp21-rcc.h | 138 ++++++ 3 files changed, 763 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/st,stm32mp21-rcc.yaml create mode 100644 include/dt-bindings/clock/st,stm32mp21-rcc.h create mode 100644 include/dt-bindings/reset/st,stm32mp21-rcc.h diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp21-rcc.yaml b/Documentation/devicetree/bindings/clock/st,stm32mp21-rcc.yaml new file mode 100644 index 000000000000..4368063c6709 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/st,stm32mp21-rcc.yaml @@ -0,0 +1,199 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/st,stm32mp21-rcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STM32MP21 Reset Clock Controller + +maintainers: + - Gabriel Fernandez + +description: | + The RCC hardware block is both a reset and a clock controller. + RCC makes also power management (resume/suspend). + + See also: + include/dt-bindings/clock/st,stm32mp21-rcc.h + include/dt-bindings/reset/st,stm32mp21-rcc.h + +properties: + compatible: + enum: + - st,stm32mp21-rcc + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + + clocks: + items: + - description: CK_SCMI_HSE High Speed External oscillator (8 to 48 MHz) + - description: CK_SCMI_HSI High Speed Internal oscillator (~ 64 MHz) + - description: CK_SCMI_MSI Low Power Internal oscillator (~ 4 MHz or ~ 16 MHz) + - description: CK_SCMI_LSE Low Speed External oscillator (32 KHz) + - description: CK_SCMI_LSI Low Speed Internal oscillator (~ 32 KHz) + - description: CK_SCMI_HSE_DIV2 CK_SCMI_HSE divided by 2 (could be gated) + - description: CK_SCMI_ICN_HS_MCU High Speed interconnect bus clock + - description: CK_SCMI_ICN_LS_MCU Low Speed interconnect bus clock + - description: CK_SCMI_ICN_SDMMC SDMMC interconnect bus clock + - description: CK_SCMI_ICN_DDR DDR interconnect bus clock + - description: CK_SCMI_ICN_DISPLAY Display interconnect bus clock + - description: CK_SCMI_ICN_HSL HSL interconnect bus clock + - description: CK_SCMI_ICN_NIC NIC interconnect bus clock + - description: CK_SCMI_FLEXGEN_07 flexgen clock 7 + - description: CK_SCMI_FLEXGEN_08 flexgen clock 8 + - description: CK_SCMI_FLEXGEN_09 flexgen clock 9 + - description: CK_SCMI_FLEXGEN_10 flexgen clock 10 + - description: CK_SCMI_FLEXGEN_11 flexgen clock 11 + - description: CK_SCMI_FLEXGEN_12 flexgen clock 12 + - description: CK_SCMI_FLEXGEN_13 flexgen clock 13 + - description: CK_SCMI_FLEXGEN_14 flexgen clock 14 + - description: CK_SCMI_FLEXGEN_16 flexgen clock 16 + - description: CK_SCMI_FLEXGEN_17 flexgen clock 17 + - description: CK_SCMI_FLEXGEN_18 flexgen clock 18 + - description: CK_SCMI_FLEXGEN_19 flexgen clock 19 + - description: CK_SCMI_FLEXGEN_20 flexgen clock 20 + - description: CK_SCMI_FLEXGEN_21 flexgen clock 21 + - description: CK_SCMI_FLEXGEN_22 flexgen clock 22 + - description: CK_SCMI_FLEXGEN_23 flexgen clock 23 + - description: CK_SCMI_FLEXGEN_24 flexgen clock 24 + - description: CK_SCMI_FLEXGEN_25 flexgen clock 25 + - description: CK_SCMI_FLEXGEN_26 flexgen clock 26 + - description: CK_SCMI_FLEXGEN_27 flexgen clock 27 + - description: CK_SCMI_FLEXGEN_29 flexgen clock 29 + - description: CK_SCMI_FLEXGEN_30 flexgen clock 30 + - description: CK_SCMI_FLEXGEN_31 flexgen clock 31 + - description: CK_SCMI_FLEXGEN_33 flexgen clock 33 + - description: CK_SCMI_FLEXGEN_36 flexgen clock 36 + - description: CK_SCMI_FLEXGEN_37 flexgen clock 37 + - description: CK_SCMI_FLEXGEN_38 flexgen clock 38 + - description: CK_SCMI_FLEXGEN_39 flexgen clock 39 + - description: CK_SCMI_FLEXGEN_40 flexgen clock 40 + - description: CK_SCMI_FLEXGEN_41 flexgen clock 41 + - description: CK_SCMI_FLEXGEN_42 flexgen clock 42 + - description: CK_SCMI_FLEXGEN_43 flexgen clock 43 + - description: CK_SCMI_FLEXGEN_44 flexgen clock 44 + - description: CK_SCMI_FLEXGEN_45 flexgen clock 45 + - description: CK_SCMI_FLEXGEN_46 flexgen clock 46 + - description: CK_SCMI_FLEXGEN_47 flexgen clock 47 + - description: CK_SCMI_FLEXGEN_48 flexgen clock 48 + - description: CK_SCMI_FLEXGEN_50 flexgen clock 50 + - description: CK_SCMI_FLEXGEN_51 flexgen clock 51 + - description: CK_SCMI_FLEXGEN_52 flexgen clock 52 + - description: CK_SCMI_FLEXGEN_53 flexgen clock 53 + - description: CK_SCMI_FLEXGEN_54 flexgen clock 54 + - description: CK_SCMI_FLEXGEN_55 flexgen clock 55 + - description: CK_SCMI_FLEXGEN_56 flexgen clock 56 + - description: CK_SCMI_FLEXGEN_57 flexgen clock 57 + - description: CK_SCMI_FLEXGEN_58 flexgen clock 58 + - description: CK_SCMI_FLEXGEN_61 flexgen clock 61 + - description: CK_SCMI_FLEXGEN_62 flexgen clock 62 + - description: CK_SCMI_FLEXGEN_63 flexgen clock 63 + - description: CK_SCMI_ICN_APB1 Peripheral bridge 1 + - description: CK_SCMI_ICN_APB2 Peripheral bridge 2 + - description: CK_SCMI_ICN_APB3 Peripheral bridge 3 + - description: CK_SCMI_ICN_APB4 Peripheral bridge 4 + - description: CK_SCMI_ICN_APB5 Peripheral bridge 5 + - description: CK_SCMI_ICN_APBDBG Peripheral bridge for debug + - description: CK_SCMI_TIMG1 Peripheral bridge for timer1 + - description: CK_SCMI_TIMG2 Peripheral bridge for timer2 + + access-controllers: + maxItems: 1 + +required: + - compatible + - reg + - '#clock-cells' + - '#reset-cells' + - clocks + +additionalProperties: false + +examples: + - | + #include + + clock-controller@44200000 { + compatible = "st,stm32mp21-rcc"; + reg = <0x44200000 0x10000>; + #clock-cells = <1>; + #reset-cells = <1>; + clocks = <&scmi_clk CK_SCMI_HSE>, + <&scmi_clk CK_SCMI_HSI>, + <&scmi_clk CK_SCMI_MSI>, + <&scmi_clk CK_SCMI_LSE>, + <&scmi_clk CK_SCMI_LSI>, + <&scmi_clk CK_SCMI_HSE_DIV2>, + <&scmi_clk CK_SCMI_ICN_HS_MCU>, + <&scmi_clk CK_SCMI_ICN_LS_MCU>, + <&scmi_clk CK_SCMI_ICN_SDMMC>, + <&scmi_clk CK_SCMI_ICN_DDR>, + <&scmi_clk CK_SCMI_ICN_DISPLAY>, + <&scmi_clk CK_SCMI_ICN_HSL>, + <&scmi_clk CK_SCMI_ICN_NIC>, + <&scmi_clk CK_SCMI_FLEXGEN_07>, + <&scmi_clk CK_SCMI_FLEXGEN_08>, + <&scmi_clk CK_SCMI_FLEXGEN_09>, + <&scmi_clk CK_SCMI_FLEXGEN_10>, + <&scmi_clk CK_SCMI_FLEXGEN_11>, + <&scmi_clk CK_SCMI_FLEXGEN_12>, + <&scmi_clk CK_SCMI_FLEXGEN_13>, + <&scmi_clk CK_SCMI_FLEXGEN_14>, + <&scmi_clk CK_SCMI_FLEXGEN_16>, + <&scmi_clk CK_SCMI_FLEXGEN_17>, + <&scmi_clk CK_SCMI_FLEXGEN_18>, + <&scmi_clk CK_SCMI_FLEXGEN_19>, + <&scmi_clk CK_SCMI_FLEXGEN_20>, + <&scmi_clk CK_SCMI_FLEXGEN_21>, + <&scmi_clk CK_SCMI_FLEXGEN_22>, + <&scmi_clk CK_SCMI_FLEXGEN_23>, + <&scmi_clk CK_SCMI_FLEXGEN_24>, + <&scmi_clk CK_SCMI_FLEXGEN_25>, + <&scmi_clk CK_SCMI_FLEXGEN_26>, + <&scmi_clk CK_SCMI_FLEXGEN_27>, + <&scmi_clk CK_SCMI_FLEXGEN_29>, + <&scmi_clk CK_SCMI_FLEXGEN_30>, + <&scmi_clk CK_SCMI_FLEXGEN_31>, + <&scmi_clk CK_SCMI_FLEXGEN_33>, + <&scmi_clk CK_SCMI_FLEXGEN_36>, + <&scmi_clk CK_SCMI_FLEXGEN_37>, + <&scmi_clk CK_SCMI_FLEXGEN_38>, + <&scmi_clk CK_SCMI_FLEXGEN_39>, + <&scmi_clk CK_SCMI_FLEXGEN_40>, + <&scmi_clk CK_SCMI_FLEXGEN_41>, + <&scmi_clk CK_SCMI_FLEXGEN_42>, + <&scmi_clk CK_SCMI_FLEXGEN_43>, + <&scmi_clk CK_SCMI_FLEXGEN_44>, + <&scmi_clk CK_SCMI_FLEXGEN_45>, + <&scmi_clk CK_SCMI_FLEXGEN_46>, + <&scmi_clk CK_SCMI_FLEXGEN_47>, + <&scmi_clk CK_SCMI_FLEXGEN_48>, + <&scmi_clk CK_SCMI_FLEXGEN_50>, + <&scmi_clk CK_SCMI_FLEXGEN_51>, + <&scmi_clk CK_SCMI_FLEXGEN_52>, + <&scmi_clk CK_SCMI_FLEXGEN_53>, + <&scmi_clk CK_SCMI_FLEXGEN_54>, + <&scmi_clk CK_SCMI_FLEXGEN_55>, + <&scmi_clk CK_SCMI_FLEXGEN_56>, + <&scmi_clk CK_SCMI_FLEXGEN_57>, + <&scmi_clk CK_SCMI_FLEXGEN_58>, + <&scmi_clk CK_SCMI_FLEXGEN_61>, + <&scmi_clk CK_SCMI_FLEXGEN_62>, + <&scmi_clk CK_SCMI_FLEXGEN_63>, + <&scmi_clk CK_SCMI_ICN_APB1>, + <&scmi_clk CK_SCMI_ICN_APB2>, + <&scmi_clk CK_SCMI_ICN_APB3>, + <&scmi_clk CK_SCMI_ICN_APB4>, + <&scmi_clk CK_SCMI_ICN_APB5>, + <&scmi_clk CK_SCMI_ICN_APBDBG>, + <&scmi_clk CK_SCMI_TIMG1>, + <&scmi_clk CK_SCMI_TIMG2>; + }; +... diff --git a/include/dt-bindings/clock/st,stm32mp21-rcc.h b/include/dt-bindings/clock/st,stm32mp21-rcc.h new file mode 100644 index 000000000000..054b785f2796 --- /dev/null +++ b/include/dt-bindings/clock/st,stm32mp21-rcc.h @@ -0,0 +1,426 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* + * Copyright (C) STMicroelectronics 2025 - All Rights Reserved + * Author: Gabriel Fernandez + */ + +#ifndef _DT_BINDINGS_STM32MP21_CLKS_H_ +#define _DT_BINDINGS_STM32MP21_CLKS_H_ + +/* INTERNAL/EXTERNAL OSCILLATORS */ +#define HSI_CK 0 +#define HSE_CK 1 +#define MSI_CK 2 +#define LSI_CK 3 +#define LSE_CK 4 +#define I2S_CK 5 +#define RTC_CK 6 +#define SPDIF_CK_SYMB 7 + +/* PLL CLOCKS */ +#define PLL1_CK 8 +#define PLL2_CK 9 +#define PLL4_CK 10 +#define PLL5_CK 11 +#define PLL6_CK 12 +#define PLL7_CK 13 +#define PLL8_CK 14 + +#define CK_CPU1 15 + +/* APB DIV CLOCKS */ +#define CK_ICN_APB1 16 +#define CK_ICN_APB2 17 +#define CK_ICN_APB3 18 +#define CK_ICN_APB4 19 +#define CK_ICN_APB5 20 +#define CK_ICN_APBDBG 21 + +/* GLOBAL TIMER */ +#define TIMG1_CK 22 +#define TIMG2_CK 23 + +/* FLEXGEN CLOCKS */ +#define CK_ICN_HS_MCU 24 +#define CK_ICN_SDMMC 25 +#define CK_ICN_DDR 26 +#define CK_ICN_DISPLAY 27 +#define CK_ICN_HSL 28 +#define CK_ICN_NIC 29 +#define CK_ICN_VID 30 +#define CK_FLEXGEN_07 31 +#define CK_FLEXGEN_08 32 +#define CK_FLEXGEN_09 33 +#define CK_FLEXGEN_10 34 +#define CK_FLEXGEN_11 35 +#define CK_FLEXGEN_12 36 +#define CK_FLEXGEN_13 37 +#define CK_FLEXGEN_14 38 +#define CK_FLEXGEN_15 39 +#define CK_FLEXGEN_16 40 +#define CK_FLEXGEN_17 41 +#define CK_FLEXGEN_18 42 +#define CK_FLEXGEN_19 43 +#define CK_FLEXGEN_20 44 +#define CK_FLEXGEN_21 45 +#define CK_FLEXGEN_22 46 +#define CK_FLEXGEN_23 47 +#define CK_FLEXGEN_24 48 +#define CK_FLEXGEN_25 49 +#define CK_FLEXGEN_26 50 +#define CK_FLEXGEN_27 51 +#define CK_FLEXGEN_28 52 +#define CK_FLEXGEN_29 53 +#define CK_FLEXGEN_30 54 +#define CK_FLEXGEN_31 55 +#define CK_FLEXGEN_32 56 +#define CK_FLEXGEN_33 57 +#define CK_FLEXGEN_34 58 +#define CK_FLEXGEN_35 59 +#define CK_FLEXGEN_36 60 +#define CK_FLEXGEN_37 61 +#define CK_FLEXGEN_38 62 +#define CK_FLEXGEN_39 63 +#define CK_FLEXGEN_40 64 +#define CK_FLEXGEN_41 65 +#define CK_FLEXGEN_42 66 +#define CK_FLEXGEN_43 67 +#define CK_FLEXGEN_44 68 +#define CK_FLEXGEN_45 69 +#define CK_FLEXGEN_46 70 +#define CK_FLEXGEN_47 71 +#define CK_FLEXGEN_48 72 +#define CK_FLEXGEN_49 73 +#define CK_FLEXGEN_50 74 +#define CK_FLEXGEN_51 75 +#define CK_FLEXGEN_52 76 +#define CK_FLEXGEN_53 77 +#define CK_FLEXGEN_54 78 +#define CK_FLEXGEN_55 79 +#define CK_FLEXGEN_56 80 +#define CK_FLEXGEN_57 81 +#define CK_FLEXGEN_58 82 +#define CK_FLEXGEN_59 83 +#define CK_FLEXGEN_60 84 +#define CK_FLEXGEN_61 85 +#define CK_FLEXGEN_62 86 +#define CK_FLEXGEN_63 87 + +/* LOW SPEED MCU CLOCK */ +#define CK_ICN_LS_MCU 88 + +#define CK_BUS_STM 89 +#define CK_BUS_FMC 90 +#define CK_BUS_ETH1 91 +#define CK_BUS_ETH2 92 +#define CK_BUS_DDRPHYC 93 +#define CK_BUS_SYSCPU1 94 +#define CK_BUS_HPDMA1 95 +#define CK_BUS_HPDMA2 96 +#define CK_BUS_HPDMA3 97 +#define CK_BUS_ADC1 98 +#define CK_BUS_ADC2 99 +#define CK_BUS_IPCC1 100 +#define CK_BUS_DCMIPSSI 101 +#define CK_BUS_CRC 102 +#define CK_BUS_MDF1 103 +#define CK_BUS_BKPSRAM 104 +#define CK_BUS_HASH1 105 +#define CK_BUS_HASH2 106 +#define CK_BUS_RNG1 107 +#define CK_BUS_RNG2 108 +#define CK_BUS_CRYP1 109 +#define CK_BUS_CRYP2 110 +#define CK_BUS_SAES 111 +#define CK_BUS_PKA 112 +#define CK_BUS_GPIOA 113 +#define CK_BUS_GPIOB 114 +#define CK_BUS_GPIOC 115 +#define CK_BUS_GPIOD 116 +#define CK_BUS_GPIOE 117 +#define CK_BUS_GPIOF 118 +#define CK_BUS_GPIOG 119 +#define CK_BUS_GPIOH 120 +#define CK_BUS_GPIOI 121 +#define CK_BUS_GPIOZ 122 +#define CK_BUS_RTC 124 +#define CK_BUS_LPUART1 125 +#define CK_BUS_LPTIM3 126 +#define CK_BUS_LPTIM4 127 +#define CK_BUS_LPTIM5 128 +#define CK_BUS_TIM2 129 +#define CK_BUS_TIM3 130 +#define CK_BUS_TIM4 131 +#define CK_BUS_TIM5 132 +#define CK_BUS_TIM6 133 +#define CK_BUS_TIM7 134 +#define CK_BUS_TIM10 135 +#define CK_BUS_TIM11 136 +#define CK_BUS_TIM12 137 +#define CK_BUS_TIM13 138 +#define CK_BUS_TIM14 139 +#define CK_BUS_LPTIM1 140 +#define CK_BUS_LPTIM2 141 +#define CK_BUS_SPI2 142 +#define CK_BUS_SPI3 143 +#define CK_BUS_SPDIFRX 144 +#define CK_BUS_USART2 145 +#define CK_BUS_USART3 146 +#define CK_BUS_UART4 147 +#define CK_BUS_UART5 148 +#define CK_BUS_I2C1 149 +#define CK_BUS_I2C2 150 +#define CK_BUS_I2C3 151 +#define CK_BUS_I3C1 152 +#define CK_BUS_I3C2 153 +#define CK_BUS_I3C3 154 +#define CK_BUS_TIM1 155 +#define CK_BUS_TIM8 156 +#define CK_BUS_TIM15 157 +#define CK_BUS_TIM16 158 +#define CK_BUS_TIM17 159 +#define CK_BUS_SAI1 160 +#define CK_BUS_SAI2 161 +#define CK_BUS_SAI3 162 +#define CK_BUS_SAI4 163 +#define CK_BUS_USART1 164 +#define CK_BUS_USART6 165 +#define CK_BUS_UART7 166 +#define CK_BUS_FDCAN 167 +#define CK_BUS_SPI1 168 +#define CK_BUS_SPI4 169 +#define CK_BUS_SPI5 170 +#define CK_BUS_SPI6 171 +#define CK_BUS_BSEC 172 +#define CK_BUS_IWDG1 173 +#define CK_BUS_IWDG2 174 +#define CK_BUS_IWDG3 175 +#define CK_BUS_IWDG4 176 +#define CK_BUS_WWDG1 177 +#define CK_BUS_VREF 178 +#define CK_BUS_DTS 179 +#define CK_BUS_SERC 180 +#define CK_BUS_HDP 181 +#define CK_BUS_DDRPERFM 182 +#define CK_BUS_OTG 183 +#define CK_BUS_LTDC 184 +#define CK_BUS_CSI 185 +#define CK_BUS_DCMIPP 186 +#define CK_BUS_DDRC 187 +#define CK_BUS_DDRCFG 188 +#define CK_BUS_STGEN 189 +#define CK_SYSDBG 190 +#define CK_KER_TIM2 191 +#define CK_KER_TIM3 192 +#define CK_KER_TIM4 193 +#define CK_KER_TIM5 194 +#define CK_KER_TIM6 195 +#define CK_KER_TIM7 196 +#define CK_KER_TIM10 197 +#define CK_KER_TIM11 198 +#define CK_KER_TIM12 199 +#define CK_KER_TIM13 200 +#define CK_KER_TIM14 201 +#define CK_KER_TIM1 202 +#define CK_KER_TIM8 203 +#define CK_KER_TIM15 204 +#define CK_KER_TIM16 205 +#define CK_KER_TIM17 206 +#define CK_BUS_SYSRAM 207 +#define CK_BUS_RETRAM 208 +#define CK_BUS_OSPI1 209 +#define CK_BUS_OTFD1 210 +#define CK_BUS_SRAM1 211 +#define CK_BUS_SDMMC1 212 +#define CK_BUS_SDMMC2 213 +#define CK_BUS_SDMMC3 214 +#define CK_BUS_DDR 215 +#define CK_BUS_RISAF4 216 +#define CK_BUS_USBHOHCI 217 +#define CK_BUS_USBHEHCI 218 +#define CK_KER_LPTIM1 219 +#define CK_KER_LPTIM2 220 +#define CK_KER_USART2 221 +#define CK_KER_UART4 222 +#define CK_KER_USART3 223 +#define CK_KER_UART5 224 +#define CK_KER_SPI2 225 +#define CK_KER_SPI3 226 +#define CK_KER_SPDIFRX 227 +#define CK_KER_I2C1 228 +#define CK_KER_I2C2 229 +#define CK_KER_I3C1 230 +#define CK_KER_I3C2 231 +#define CK_KER_I2C3 232 +#define CK_KER_I3C3 233 +#define CK_KER_SPI1 234 +#define CK_KER_SPI4 235 +#define CK_KER_SPI5 236 +#define CK_KER_SPI6 237 +#define CK_KER_USART1 238 +#define CK_KER_USART6 239 +#define CK_KER_UART7 240 +#define CK_KER_MDF1 241 +#define CK_KER_SAI1 242 +#define CK_KER_SAI2 243 +#define CK_KER_SAI3 244 +#define CK_KER_SAI4 245 +#define CK_KER_FDCAN 246 +#define CK_KER_CSI 247 +#define CK_KER_CSITXESC 248 +#define CK_KER_CSIPHY 249 +#define CK_KER_STGEN 250 +#define CK_KER_USB2PHY2EN 251 +#define CK_KER_LPUART1 252 +#define CK_KER_LPTIM3 253 +#define CK_KER_LPTIM4 254 +#define CK_KER_LPTIM5 255 +#define CK_KER_TSDBG 256 +#define CK_KER_TPIU 257 +#define CK_BUS_ETR 258 +#define CK_BUS_SYSATB 259 +#define CK_KER_ADC1 260 +#define CK_KER_ADC2 261 +#define CK_KER_OSPI1 262 +#define CK_KER_FMC 263 +#define CK_KER_SDMMC1 264 +#define CK_KER_SDMMC2 265 +#define CK_KER_SDMMC3 266 +#define CK_KER_ETH1 267 +#define CK_KER_ETH2 268 +#define CK_KER_ETH1PTP 269 +#define CK_KER_ETH2PTP 270 +#define CK_KER_USB2PHY1 271 +#define CK_KER_USB2PHY2 272 +#define CK_MCO1 273 +#define CK_MCO2 274 +#define CK_KER_DTS 275 +#define CK_ETH1_RX 276 +#define CK_ETH1_TX 277 +#define CK_ETH1_MAC 278 +#define CK_ETH2_RX 279 +#define CK_ETH2_TX 280 +#define CK_ETH2_MAC 281 +#define CK_ETH1_STP 282 +#define CK_ETH2_STP 283 +#define CK_KER_LTDC 284 +#define HSE_DIV2_CK 285 +#define CK_DBGMCU 286 +#define CK_DAP 287 +#define CK_KER_ETR 288 +#define CK_KER_STM 289 + +#define CK_SCMI_ICN_HS_MCU 0 +#define CK_SCMI_ICN_SDMMC 1 +#define CK_SCMI_ICN_DDR 2 +#define CK_SCMI_ICN_DISPLAY 3 +#define CK_SCMI_ICN_HSL 4 +#define CK_SCMI_ICN_NIC 5 +#define CK_SCMI_FLEXGEN_07 7 +#define CK_SCMI_FLEXGEN_08 8 +#define CK_SCMI_FLEXGEN_09 9 +#define CK_SCMI_FLEXGEN_10 10 +#define CK_SCMI_FLEXGEN_11 11 +#define CK_SCMI_FLEXGEN_12 12 +#define CK_SCMI_FLEXGEN_13 13 +#define CK_SCMI_FLEXGEN_14 14 +#define CK_SCMI_FLEXGEN_15 15 +#define CK_SCMI_FLEXGEN_16 16 +#define CK_SCMI_FLEXGEN_17 17 +#define CK_SCMI_FLEXGEN_18 18 +#define CK_SCMI_FLEXGEN_19 19 +#define CK_SCMI_FLEXGEN_20 20 +#define CK_SCMI_FLEXGEN_21 21 +#define CK_SCMI_FLEXGEN_22 22 +#define CK_SCMI_FLEXGEN_23 23 +#define CK_SCMI_FLEXGEN_24 24 +#define CK_SCMI_FLEXGEN_25 25 +#define CK_SCMI_FLEXGEN_26 26 +#define CK_SCMI_FLEXGEN_27 27 +#define CK_SCMI_FLEXGEN_28 28 +#define CK_SCMI_FLEXGEN_29 29 +#define CK_SCMI_FLEXGEN_30 30 +#define CK_SCMI_FLEXGEN_31 31 +#define CK_SCMI_FLEXGEN_32 32 +#define CK_SCMI_FLEXGEN_33 33 +#define CK_SCMI_FLEXGEN_34 34 +#define CK_SCMI_FLEXGEN_35 35 +#define CK_SCMI_FLEXGEN_36 36 +#define CK_SCMI_FLEXGEN_37 37 +#define CK_SCMI_FLEXGEN_38 38 +#define CK_SCMI_FLEXGEN_39 39 +#define CK_SCMI_FLEXGEN_40 40 +#define CK_SCMI_FLEXGEN_41 41 +#define CK_SCMI_FLEXGEN_42 42 +#define CK_SCMI_FLEXGEN_43 43 +#define CK_SCMI_FLEXGEN_44 44 +#define CK_SCMI_FLEXGEN_45 45 +#define CK_SCMI_FLEXGEN_46 46 +#define CK_SCMI_FLEXGEN_47 47 +#define CK_SCMI_FLEXGEN_48 48 +#define CK_SCMI_FLEXGEN_49 49 +#define CK_SCMI_FLEXGEN_50 50 +#define CK_SCMI_FLEXGEN_51 51 +#define CK_SCMI_FLEXGEN_52 52 +#define CK_SCMI_FLEXGEN_53 53 +#define CK_SCMI_FLEXGEN_54 54 +#define CK_SCMI_FLEXGEN_55 55 +#define CK_SCMI_FLEXGEN_56 56 +#define CK_SCMI_FLEXGEN_57 57 +#define CK_SCMI_FLEXGEN_58 58 +#define CK_SCMI_FLEXGEN_59 59 +#define CK_SCMI_FLEXGEN_60 60 +#define CK_SCMI_FLEXGEN_61 61 +#define CK_SCMI_FLEXGEN_62 62 +#define CK_SCMI_FLEXGEN_63 63 +#define CK_SCMI_ICN_LS_MCU 64 +#define CK_SCMI_HSE 65 +#define CK_SCMI_LSE 66 +#define CK_SCMI_HSI 67 +#define CK_SCMI_LSI 68 +#define CK_SCMI_MSI 69 +#define CK_SCMI_HSE_DIV2 70 +#define CK_SCMI_CPU1 71 +#define CK_SCMI_SYSCPU1 72 +#define CK_SCMI_PLL2 73 +#define CK_SCMI_RTC 74 +#define CK_SCMI_RTCCK 75 +#define CK_SCMI_ICN_APB1 76 +#define CK_SCMI_ICN_APB2 77 +#define CK_SCMI_ICN_APB3 78 +#define CK_SCMI_ICN_APB4 79 +#define CK_SCMI_ICN_APB5 80 +#define CK_SCMI_ICN_APBDBG 81 +#define CK_SCMI_TIMG1 82 +#define CK_SCMI_TIMG2 83 +#define CK_SCMI_BKPSRAM 84 +#define CK_SCMI_BSEC 85 +#define CK_SCMI_BUS_ETR 86 +#define CK_SCMI_FMC 87 +#define CK_SCMI_GPIOA 88 +#define CK_SCMI_GPIOB 89 +#define CK_SCMI_GPIOC 90 +#define CK_SCMI_GPIOD 91 +#define CK_SCMI_GPIOE 92 +#define CK_SCMI_GPIOF 93 +#define CK_SCMI_GPIOG 94 +#define CK_SCMI_GPIOH 95 +#define CK_SCMI_GPIOI 96 +#define CK_SCMI_GPIOZ 97 +#define CK_SCMI_HPDMA1 98 +#define CK_SCMI_HPDMA2 99 +#define CK_SCMI_HPDMA3 100 +#define CK_SCMI_IPCC1 101 +#define CK_SCMI_RETRAM 102 +#define CK_SCMI_SRAM1 103 +#define CK_SCMI_SYSRAM 104 +#define CK_SCMI_OSPI1 105 +#define CK_SCMI_TPIU 106 +#define CK_SCMI_SYSDBG 107 +#define CK_SCMI_SYSATB 108 +#define CK_SCMI_TSDBG 109 +#define CK_SCMI_BUS_STM 110 +#define CK_SCMI_KER_STM 111 +#define CK_SCMI_KER_ETR 112 + +#endif /* _DT_BINDINGS_STM32MP21_CLKS_H_ */ diff --git a/include/dt-bindings/reset/st,stm32mp21-rcc.h b/include/dt-bindings/reset/st,stm32mp21-rcc.h new file mode 100644 index 000000000000..6463bd73d025 --- /dev/null +++ b/include/dt-bindings/reset/st,stm32mp21-rcc.h @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* + * Copyright (C) STMicroelectronics 2025 - All Rights Reserved + * Author: Gabriel Fernandez + */ + +#ifndef _DT_BINDINGS_STM32MP21_RESET_H_ +#define _DT_BINDINGS_STM32MP21_RESET_H_ + +#define TIM1_R 0 +#define TIM2_R 1 +#define TIM3_R 2 +#define TIM4_R 3 +#define TIM5_R 4 +#define TIM6_R 5 +#define TIM7_R 6 +#define TIM8_R 7 +#define TIM10_R 8 +#define TIM11_R 9 +#define TIM12_R 10 +#define TIM13_R 11 +#define TIM14_R 12 +#define TIM15_R 13 +#define TIM16_R 14 +#define TIM17_R 15 +#define LPTIM1_R 16 +#define LPTIM2_R 17 +#define LPTIM3_R 18 +#define LPTIM4_R 19 +#define LPTIM5_R 20 +#define SPI1_R 21 +#define SPI2_R 22 +#define SPI3_R 23 +#define SPI4_R 24 +#define SPI5_R 25 +#define SPI6_R 26 +#define SPDIFRX_R 27 +#define USART1_R 28 +#define USART2_R 29 +#define USART3_R 30 +#define UART4_R 31 +#define UART5_R 32 +#define USART6_R 33 +#define UART7_R 34 +#define LPUART1_R 35 +#define I2C1_R 36 +#define I2C2_R 37 +#define I2C3_R 38 +#define SAI1_R 39 +#define SAI2_R 40 +#define SAI3_R 41 +#define SAI4_R 42 +#define MDF1_R 43 +#define FDCAN_R 44 +#define HDP_R 45 +#define ADC1_R 46 +#define ADC2_R 47 +#define ETH1_R 48 +#define ETH2_R 49 +#define USBH_R 50 +#define USB2PHY1_R 51 +#define USB2PHY2_R 52 +#define SDMMC1_R 53 +#define SDMMC1DLL_R 54 +#define SDMMC2_R 55 +#define SDMMC2DLL_R 56 +#define SDMMC3_R 57 +#define SDMMC3DLL_R 58 +#define LTDC_R 59 +#define CSI_R 60 +#define DCMIPP_R 61 +#define DCMIPSSI_R 62 +#define WWDG1_R 63 +#define VREF_R 64 +#define DTS_R 65 +#define CRC_R 66 +#define SERC_R 67 +#define I3C1_R 68 +#define I3C2_R 69 +#define I3C3_R 70 +#define IWDG2_KER_R 71 +#define IWDG4_KER_R 72 +#define RNG1_R 73 +#define RNG2_R 74 +#define PKA_R 75 +#define SAES_R 76 +#define HASH1_R 77 +#define HASH2_R 78 +#define CRYP1_R 79 +#define CRYP2_R 80 +#define OSPI1_R 81 +#define OSPI1DLL_R 82 +#define OTG_R 83 +#define FMC_R 84 +#define DBG_R 85 +#define GPIOA_R 86 +#define GPIOB_R 87 +#define GPIOC_R 88 +#define GPIOD_R 89 +#define GPIOE_R 90 +#define GPIOF_R 91 +#define GPIOG_R 92 +#define GPIOH_R 93 +#define GPIOI_R 94 +#define GPIOZ_R 95 +#define HPDMA1_R 96 +#define HPDMA2_R 97 +#define HPDMA3_R 98 +#define IPCC1_R 99 +#define C2_HOLDBOOT_R 100 +#define C1_HOLDBOOT_R 101 +#define C1_R 102 +#define C1P1POR_R 103 +#define C1P1_R 104 +#define C2_R 105 +#define SYS_R 106 +#define VSW_R 107 +#define C1MS_R 108 +#define DDRCP_R 109 +#define DDRCAPB_R 110 +#define DDRPHYCAPB_R 111 +#define DDRCFG_R 112 +#define DDR_R 113 +#define DDRPERFM_R 114 +#define IWDG1_SYS_R 116 +#define IWDG2_SYS_R 117 +#define IWDG3_SYS_R 118 +#define IWDG4_SYS_R 119 + +#define RST_SCMI_C1_R 0 +#define RST_SCMI_C2_R 1 +#define RST_SCMI_C1_HOLDBOOT_R 2 +#define RST_SCMI_C2_HOLDBOOT_R 3 +#define RST_SCMI_FMC 4 +#define RST_SCMI_OSPI1 5 +#define RST_SCMI_OSPI1DLL 6 + +#endif /* _DT_BINDINGS_STM32MP21_RESET_H_ */ From 37ae8501cdb0ac81521cfd850de4dd967561aae3 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Wed, 25 Jun 2025 11:07:25 +0200 Subject: [PATCH 1867/2711] clk: stm32: introduce clocks for STM32MP21 platform This driver is intended for the STM32MP21 clock family. Signed-off-by: Nicolas Le Bayon Reviewed-by: Alok Tiwari Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/stm32/Kconfig | 7 + drivers/clk/stm32/Makefile | 1 + drivers/clk/stm32/clk-stm32mp21.c | 1586 +++++++++++++++++++++++++++++ drivers/clk/stm32/stm32mp21_rcc.h | 651 ++++++++++++ 4 files changed, 2245 insertions(+) create mode 100644 drivers/clk/stm32/clk-stm32mp21.c create mode 100644 drivers/clk/stm32/stm32mp21_rcc.h diff --git a/drivers/clk/stm32/Kconfig b/drivers/clk/stm32/Kconfig index 4d2eb993ea08..5dbd75cde657 100644 --- a/drivers/clk/stm32/Kconfig +++ b/drivers/clk/stm32/Kconfig @@ -25,6 +25,13 @@ config COMMON_CLK_STM32MP157 help Support for stm32mp15x SoC family clocks. +config COMMON_CLK_STM32MP215 + bool "Clock driver for stm32mp21x clocks" + depends on ARM || ARM64 || COMPILE_TEST + default y + help + Support for stm32mp21x SoC family clocks + config COMMON_CLK_STM32MP257 bool "Clock driver for stm32mp25x clocks" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/stm32/Makefile b/drivers/clk/stm32/Makefile index 0a627164fcce..e04727b59449 100644 --- a/drivers/clk/stm32/Makefile +++ b/drivers/clk/stm32/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_COMMON_CLK_STM32MP135) += clk-stm32mp13.o clk-stm32-core.o reset-stm32.o obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o reset-stm32.o +obj-$(CONFIG_COMMON_CLK_STM32MP215) += clk-stm32mp21.o clk-stm32-core.o reset-stm32.o obj-$(CONFIG_COMMON_CLK_STM32MP257) += clk-stm32mp25.o clk-stm32-core.o reset-stm32.o diff --git a/drivers/clk/stm32/clk-stm32mp21.c b/drivers/clk/stm32/clk-stm32mp21.c new file mode 100644 index 000000000000..c8a37b716bd5 --- /dev/null +++ b/drivers/clk/stm32/clk-stm32mp21.c @@ -0,0 +1,1586 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) STMicroelectronics 2023 - All Rights Reserved + * Author: Gabriel Fernandez for STMicroelectronics. + */ + +#include +#include +#include +#include + +#include "clk-stm32-core.h" +#include "reset-stm32.h" +#include "stm32mp21_rcc.h" + +#include +#include + +/* Max clock binding value */ +#define STM32MP21_LAST_CLK CK_SCMI_KER_ETR + +/* Clock security definition */ +#define SECF_NONE -1 + +#define RCC_REG_SIZE 32 +#define RCC_SECCFGR(x) (((x) / RCC_REG_SIZE) * 0x4 + RCC_SECCFGR0) +#define RCC_CIDCFGR(x) ((x) * 0x8 + RCC_R0CIDCFGR) +#define RCC_SEMCR(x) ((x) * 0x8 + RCC_R0SEMCR) +#define RCC_CID1 1 + +/* Register: RIFSC_CIDCFGR */ +#define RCC_CIDCFGR_CFEN BIT(0) +#define RCC_CIDCFGR_SEM_EN BIT(1) +#define RCC_CIDCFGR_SEMWLC1_EN BIT(17) +#define RCC_CIDCFGR_SCID_MASK GENMASK(6, 4) + +/* Register: RIFSC_SEMCR */ +#define RCC_SEMCR_SEMCID_MASK GENMASK(6, 4) + +#define MP21_RIF_RCC_MCO1 108 +#define MP21_RIF_RCC_MCO2 109 + +#define SEC_RIFSC_FLAG BIT(31) +#define SEC_RIFSC(_id) ((_id) | SEC_RIFSC_FLAG) + +enum { + HSE, + HSI, + MSI, + LSE, + LSI, + HSE_DIV2, + ICN_HS_MCU, + ICN_LS_MCU, + ICN_SDMMC, + ICN_DDR, + ICN_DISPLAY, + ICN_HSL, + ICN_NIC, + FLEXGEN_07, + FLEXGEN_08, + FLEXGEN_09, + FLEXGEN_10, + FLEXGEN_11, + FLEXGEN_12, + FLEXGEN_13, + FLEXGEN_14, + FLEXGEN_16, + FLEXGEN_17, + FLEXGEN_18, + FLEXGEN_19, + FLEXGEN_20, + FLEXGEN_21, + FLEXGEN_22, + FLEXGEN_23, + FLEXGEN_24, + FLEXGEN_25, + FLEXGEN_26, + FLEXGEN_27, + FLEXGEN_29, + FLEXGEN_30, + FLEXGEN_31, + FLEXGEN_33, + FLEXGEN_36, + FLEXGEN_37, + FLEXGEN_38, + FLEXGEN_39, + FLEXGEN_40, + FLEXGEN_41, + FLEXGEN_42, + FLEXGEN_43, + FLEXGEN_44, + FLEXGEN_45, + FLEXGEN_46, + FLEXGEN_47, + FLEXGEN_48, + FLEXGEN_50, + FLEXGEN_51, + FLEXGEN_52, + FLEXGEN_53, + FLEXGEN_54, + FLEXGEN_55, + FLEXGEN_56, + FLEXGEN_57, + FLEXGEN_58, + FLEXGEN_61, + FLEXGEN_62, + FLEXGEN_63, + ICN_APB1, + ICN_APB2, + ICN_APB3, + ICN_APB4, + ICN_APB5, + ICN_APBDBG, + TIMG1, + TIMG2, +}; + +static const struct clk_parent_data adc1_src[] = { + { .index = FLEXGEN_46 }, + { .index = ICN_LS_MCU }, +}; + +static const struct clk_parent_data adc2_src[] = { + { .index = FLEXGEN_47 }, + { .index = ICN_LS_MCU }, + { .index = FLEXGEN_46 }, +}; + +static const struct clk_parent_data usb2phy1_src[] = { + { .index = FLEXGEN_57 }, + { .index = HSE_DIV2 }, +}; + +static const struct clk_parent_data usb2phy2_src[] = { + { .index = FLEXGEN_58 }, + { .index = HSE_DIV2 }, +}; + +static const struct clk_parent_data dts_src[] = { + { .index = HSI }, + { .index = HSE }, + { .index = MSI }, +}; + +static const struct clk_parent_data mco1_src[] = { + { .index = FLEXGEN_61 }, +}; + +static const struct clk_parent_data mco2_src[] = { + { .index = FLEXGEN_62 }, +}; + +enum enum_mux_cfg { + MUX_ADC1, + MUX_ADC2, + MUX_DTS, + MUX_MCO1, + MUX_MCO2, + MUX_USB2PHY1, + MUX_USB2PHY2, + MUX_NB +}; + +#define MUX_CFG(id, _offset, _shift, _width) \ + [id] = { \ + .offset = (_offset), \ + .shift = (_shift), \ + .width = (_width), \ + } + +static const struct stm32_mux_cfg stm32mp21_muxes[MUX_NB] = { + MUX_CFG(MUX_ADC1, RCC_ADC1CFGR, 12, 1), + MUX_CFG(MUX_ADC2, RCC_ADC2CFGR, 12, 2), + MUX_CFG(MUX_DTS, RCC_DTSCFGR, 12, 2), + MUX_CFG(MUX_MCO1, RCC_MCO1CFGR, 0, 1), + MUX_CFG(MUX_MCO2, RCC_MCO2CFGR, 0, 1), + MUX_CFG(MUX_USB2PHY1, RCC_USB2PHY1CFGR, 15, 1), + MUX_CFG(MUX_USB2PHY2, RCC_USB2PHY2CFGR, 15, 1), +}; + +enum enum_gate_cfg { + GATE_ADC1, + GATE_ADC2, + GATE_CRC, + GATE_CRYP1, + GATE_CRYP2, + GATE_CSI, + GATE_DCMIPP, + GATE_DCMIPSSI, + GATE_DDRPERFM, + GATE_DTS, + GATE_ETH1, + GATE_ETH1MAC, + GATE_ETH1RX, + GATE_ETH1STP, + GATE_ETH1TX, + GATE_ETH2, + GATE_ETH2MAC, + GATE_ETH2RX, + GATE_ETH2STP, + GATE_ETH2TX, + GATE_FDCAN, + GATE_HASH1, + GATE_HASH2, + GATE_HDP, + GATE_I2C1, + GATE_I2C2, + GATE_I2C3, + GATE_I3C1, + GATE_I3C2, + GATE_I3C3, + GATE_IWDG1, + GATE_IWDG2, + GATE_IWDG3, + GATE_IWDG4, + GATE_LPTIM1, + GATE_LPTIM2, + GATE_LPTIM3, + GATE_LPTIM4, + GATE_LPTIM5, + GATE_LPUART1, + GATE_LTDC, + GATE_MCO1, + GATE_MCO2, + GATE_MDF1, + GATE_OTG, + GATE_PKA, + GATE_RNG1, + GATE_RNG2, + GATE_SAES, + GATE_SAI1, + GATE_SAI2, + GATE_SAI3, + GATE_SAI4, + GATE_SDMMC1, + GATE_SDMMC2, + GATE_SDMMC3, + GATE_SERC, + GATE_SPDIFRX, + GATE_SPI1, + GATE_SPI2, + GATE_SPI3, + GATE_SPI4, + GATE_SPI5, + GATE_SPI6, + GATE_TIM1, + GATE_TIM10, + GATE_TIM11, + GATE_TIM12, + GATE_TIM13, + GATE_TIM14, + GATE_TIM15, + GATE_TIM16, + GATE_TIM17, + GATE_TIM2, + GATE_TIM3, + GATE_TIM4, + GATE_TIM5, + GATE_TIM6, + GATE_TIM7, + GATE_TIM8, + GATE_UART4, + GATE_UART5, + GATE_UART7, + GATE_USART1, + GATE_USART2, + GATE_USART3, + GATE_USART6, + GATE_USB2PHY1, + GATE_USB2PHY2, + GATE_USBH, + GATE_VREF, + GATE_WWDG1, + GATE_NB +}; + +#define GATE_CFG(id, _offset, _bit_idx, _offset_clr) \ + [id] = { \ + .offset = (_offset), \ + .bit_idx = (_bit_idx), \ + .set_clr = (_offset_clr), \ + } + +static const struct stm32_gate_cfg stm32mp21_gates[GATE_NB] = { + GATE_CFG(GATE_ADC1, RCC_ADC1CFGR, 1, 0), + GATE_CFG(GATE_ADC2, RCC_ADC2CFGR, 1, 0), + GATE_CFG(GATE_CRC, RCC_CRCCFGR, 1, 0), + GATE_CFG(GATE_CRYP1, RCC_CRYP1CFGR, 1, 0), + GATE_CFG(GATE_CRYP2, RCC_CRYP2CFGR, 1, 0), + GATE_CFG(GATE_CSI, RCC_CSICFGR, 1, 0), + GATE_CFG(GATE_DCMIPP, RCC_DCMIPPCFGR, 1, 0), + GATE_CFG(GATE_DCMIPSSI, RCC_DCMIPSSICFGR, 1, 0), + GATE_CFG(GATE_DDRPERFM, RCC_DDRPERFMCFGR, 1, 0), + GATE_CFG(GATE_DTS, RCC_DTSCFGR, 1, 0), + GATE_CFG(GATE_ETH1, RCC_ETH1CFGR, 5, 0), + GATE_CFG(GATE_ETH1MAC, RCC_ETH1CFGR, 1, 0), + GATE_CFG(GATE_ETH1RX, RCC_ETH1CFGR, 10, 0), + GATE_CFG(GATE_ETH1STP, RCC_ETH1CFGR, 4, 0), + GATE_CFG(GATE_ETH1TX, RCC_ETH1CFGR, 8, 0), + GATE_CFG(GATE_ETH2, RCC_ETH2CFGR, 5, 0), + GATE_CFG(GATE_ETH2MAC, RCC_ETH2CFGR, 1, 0), + GATE_CFG(GATE_ETH2RX, RCC_ETH2CFGR, 10, 0), + GATE_CFG(GATE_ETH2STP, RCC_ETH2CFGR, 4, 0), + GATE_CFG(GATE_ETH2TX, RCC_ETH2CFGR, 8, 0), + GATE_CFG(GATE_FDCAN, RCC_FDCANCFGR, 1, 0), + GATE_CFG(GATE_HASH1, RCC_HASH1CFGR, 1, 0), + GATE_CFG(GATE_HASH2, RCC_HASH2CFGR, 1, 0), + GATE_CFG(GATE_HDP, RCC_HDPCFGR, 1, 0), + GATE_CFG(GATE_I2C1, RCC_I2C1CFGR, 1, 0), + GATE_CFG(GATE_I2C2, RCC_I2C2CFGR, 1, 0), + GATE_CFG(GATE_I2C3, RCC_I2C3CFGR, 1, 0), + GATE_CFG(GATE_I3C1, RCC_I3C1CFGR, 1, 0), + GATE_CFG(GATE_I3C2, RCC_I3C2CFGR, 1, 0), + GATE_CFG(GATE_I3C3, RCC_I3C3CFGR, 1, 0), + GATE_CFG(GATE_IWDG1, RCC_IWDG1CFGR, 1, 0), + GATE_CFG(GATE_IWDG2, RCC_IWDG2CFGR, 1, 0), + GATE_CFG(GATE_IWDG3, RCC_IWDG3CFGR, 1, 0), + GATE_CFG(GATE_IWDG4, RCC_IWDG4CFGR, 1, 0), + GATE_CFG(GATE_LPTIM1, RCC_LPTIM1CFGR, 1, 0), + GATE_CFG(GATE_LPTIM2, RCC_LPTIM2CFGR, 1, 0), + GATE_CFG(GATE_LPTIM3, RCC_LPTIM3CFGR, 1, 0), + GATE_CFG(GATE_LPTIM4, RCC_LPTIM4CFGR, 1, 0), + GATE_CFG(GATE_LPTIM5, RCC_LPTIM5CFGR, 1, 0), + GATE_CFG(GATE_LPUART1, RCC_LPUART1CFGR, 1, 0), + GATE_CFG(GATE_LTDC, RCC_LTDCCFGR, 1, 0), + GATE_CFG(GATE_MCO1, RCC_MCO1CFGR, 8, 0), + GATE_CFG(GATE_MCO2, RCC_MCO2CFGR, 8, 0), + GATE_CFG(GATE_MDF1, RCC_MDF1CFGR, 1, 0), + GATE_CFG(GATE_OTG, RCC_OTGCFGR, 1, 0), + GATE_CFG(GATE_PKA, RCC_PKACFGR, 1, 0), + GATE_CFG(GATE_RNG1, RCC_RNG1CFGR, 1, 0), + GATE_CFG(GATE_RNG2, RCC_RNG2CFGR, 1, 0), + GATE_CFG(GATE_SAES, RCC_SAESCFGR, 1, 0), + GATE_CFG(GATE_SAI1, RCC_SAI1CFGR, 1, 0), + GATE_CFG(GATE_SAI2, RCC_SAI2CFGR, 1, 0), + GATE_CFG(GATE_SAI3, RCC_SAI3CFGR, 1, 0), + GATE_CFG(GATE_SAI4, RCC_SAI4CFGR, 1, 0), + GATE_CFG(GATE_SDMMC1, RCC_SDMMC1CFGR, 1, 0), + GATE_CFG(GATE_SDMMC2, RCC_SDMMC2CFGR, 1, 0), + GATE_CFG(GATE_SDMMC3, RCC_SDMMC3CFGR, 1, 0), + GATE_CFG(GATE_SERC, RCC_SERCCFGR, 1, 0), + GATE_CFG(GATE_SPDIFRX, RCC_SPDIFRXCFGR, 1, 0), + GATE_CFG(GATE_SPI1, RCC_SPI1CFGR, 1, 0), + GATE_CFG(GATE_SPI2, RCC_SPI2CFGR, 1, 0), + GATE_CFG(GATE_SPI3, RCC_SPI3CFGR, 1, 0), + GATE_CFG(GATE_SPI4, RCC_SPI4CFGR, 1, 0), + GATE_CFG(GATE_SPI5, RCC_SPI5CFGR, 1, 0), + GATE_CFG(GATE_SPI6, RCC_SPI6CFGR, 1, 0), + GATE_CFG(GATE_TIM1, RCC_TIM1CFGR, 1, 0), + GATE_CFG(GATE_TIM10, RCC_TIM10CFGR, 1, 0), + GATE_CFG(GATE_TIM11, RCC_TIM11CFGR, 1, 0), + GATE_CFG(GATE_TIM12, RCC_TIM12CFGR, 1, 0), + GATE_CFG(GATE_TIM13, RCC_TIM13CFGR, 1, 0), + GATE_CFG(GATE_TIM14, RCC_TIM14CFGR, 1, 0), + GATE_CFG(GATE_TIM15, RCC_TIM15CFGR, 1, 0), + GATE_CFG(GATE_TIM16, RCC_TIM16CFGR, 1, 0), + GATE_CFG(GATE_TIM17, RCC_TIM17CFGR, 1, 0), + GATE_CFG(GATE_TIM2, RCC_TIM2CFGR, 1, 0), + GATE_CFG(GATE_TIM3, RCC_TIM3CFGR, 1, 0), + GATE_CFG(GATE_TIM4, RCC_TIM4CFGR, 1, 0), + GATE_CFG(GATE_TIM5, RCC_TIM5CFGR, 1, 0), + GATE_CFG(GATE_TIM6, RCC_TIM6CFGR, 1, 0), + GATE_CFG(GATE_TIM7, RCC_TIM7CFGR, 1, 0), + GATE_CFG(GATE_TIM8, RCC_TIM8CFGR, 1, 0), + GATE_CFG(GATE_UART4, RCC_UART4CFGR, 1, 0), + GATE_CFG(GATE_UART5, RCC_UART5CFGR, 1, 0), + GATE_CFG(GATE_UART7, RCC_UART7CFGR, 1, 0), + GATE_CFG(GATE_USART1, RCC_USART1CFGR, 1, 0), + GATE_CFG(GATE_USART2, RCC_USART2CFGR, 1, 0), + GATE_CFG(GATE_USART3, RCC_USART3CFGR, 1, 0), + GATE_CFG(GATE_USART6, RCC_USART6CFGR, 1, 0), + GATE_CFG(GATE_USB2PHY1, RCC_USB2PHY1CFGR, 1, 0), + GATE_CFG(GATE_USB2PHY2, RCC_USB2PHY2CFGR, 1, 0), + GATE_CFG(GATE_USBH, RCC_USBHCFGR, 1, 0), + GATE_CFG(GATE_VREF, RCC_VREFCFGR, 1, 0), + GATE_CFG(GATE_WWDG1, RCC_WWDG1CFGR, 1, 0), +}; + +#define CLK_HW_INIT_INDEX(_name, _parent, _ops, _flags) \ + (&(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_data = (const struct clk_parent_data[]) { \ + { .index = _parent }, \ + }, \ + .num_parents = 1, \ + .ops = _ops, \ + }) + +/* ADC */ +static struct clk_stm32_gate ck_icn_p_adc1 = { + .gate_id = GATE_ADC1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_adc1", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_composite ck_ker_adc1 = { + .gate_id = GATE_ADC1, + .mux_id = MUX_ADC1, + .div_id = NO_STM32_DIV, + .hw.init = CLK_HW_INIT_PARENTS_DATA("ck_ker_adc1", adc1_src, &clk_stm32_composite_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_adc2 = { + .gate_id = GATE_ADC2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_adc2", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_composite ck_ker_adc2 = { + .gate_id = GATE_ADC2, + .mux_id = MUX_ADC2, + .div_id = NO_STM32_DIV, + .hw.init = CLK_HW_INIT_PARENTS_DATA("ck_ker_adc2", adc2_src, &clk_stm32_composite_ops, 0), +}; + +/* CSI-HOST */ +static struct clk_stm32_gate ck_icn_p_csi = { + .gate_id = GATE_CSI, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_csi", ICN_APB4, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_csi = { + .gate_id = GATE_CSI, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_csi", FLEXGEN_29, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_csitxesc = { + .gate_id = GATE_CSI, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_csitxesc", FLEXGEN_30, &clk_stm32_gate_ops, 0), +}; + +/* CSI-PHY */ +static struct clk_stm32_gate ck_ker_csiphy = { + .gate_id = GATE_CSI, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_csiphy", FLEXGEN_31, &clk_stm32_gate_ops, 0), +}; + +/* DCMIPP */ +static struct clk_stm32_gate ck_icn_p_dcmipp = { + .gate_id = GATE_DCMIPP, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_dcmipp", ICN_APB4, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_dcmipssi = { + .gate_id = GATE_DCMIPSSI, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_dcmipssi", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +/* DDRPERMF */ +static struct clk_stm32_gate ck_icn_p_ddrperfm = { + .gate_id = GATE_DDRPERFM, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_ddrperfm", ICN_APB4, &clk_stm32_gate_ops, 0), +}; + +/* CRC */ +static struct clk_stm32_gate ck_icn_p_crc = { + .gate_id = GATE_CRC, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_crc", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +/* CRYP */ +static struct clk_stm32_gate ck_icn_p_cryp1 = { + .gate_id = GATE_CRYP1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_cryp1", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_cryp2 = { + .gate_id = GATE_CRYP2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_cryp2", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +/* DBG & TRACE */ +/* Trace and debug clocks are managed by SCMI */ + +/* LTDC */ +static struct clk_stm32_gate ck_icn_p_ltdc = { + .gate_id = GATE_LTDC, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_ltdc", ICN_APB4, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_ltdc = { + .gate_id = GATE_LTDC, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_ltdc", FLEXGEN_27, &clk_stm32_gate_ops, + CLK_SET_RATE_PARENT), +}; + +/* DTS */ +static struct clk_stm32_composite ck_ker_dts = { + .gate_id = GATE_DTS, + .mux_id = MUX_DTS, + .div_id = NO_STM32_DIV, + .hw.init = CLK_HW_INIT_PARENTS_DATA("ck_ker_dts", dts_src, + &clk_stm32_composite_ops, 0), +}; + +/* ETHERNET */ +static struct clk_stm32_gate ck_icn_p_eth1 = { + .gate_id = GATE_ETH1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_eth1", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth1stp = { + .gate_id = GATE_ETH1STP, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth1stp", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth1 = { + .gate_id = GATE_ETH1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth1", FLEXGEN_54, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth1ptp = { + .gate_id = GATE_ETH1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth1ptp", FLEXGEN_56, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth1mac = { + .gate_id = GATE_ETH1MAC, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth1mac", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth1tx = { + .gate_id = GATE_ETH1TX, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth1tx", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth1rx = { + .gate_id = GATE_ETH1RX, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth1rx", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_eth2 = { + .gate_id = GATE_ETH2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_eth2", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth2stp = { + .gate_id = GATE_ETH2STP, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth2stp", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth2 = { + .gate_id = GATE_ETH2, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth2", FLEXGEN_55, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth2ptp = { + .gate_id = GATE_ETH2, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth2ptp", FLEXGEN_56, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth2mac = { + .gate_id = GATE_ETH2MAC, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth2mac", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth2tx = { + .gate_id = GATE_ETH2TX, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth2tx", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_eth2rx = { + .gate_id = GATE_ETH2RX, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_eth2rx", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +/* FDCAN */ +static struct clk_stm32_gate ck_icn_p_fdcan = { + .gate_id = GATE_FDCAN, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_fdcan", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_fdcan = { + .gate_id = GATE_FDCAN, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_fdcan", FLEXGEN_26, &clk_stm32_gate_ops, 0), +}; + +/* HASH */ +static struct clk_stm32_gate ck_icn_p_hash1 = { + .gate_id = GATE_HASH1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_hash1", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_hash2 = { + .gate_id = GATE_HASH2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_hash2", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +/* HDP */ +static struct clk_stm32_gate ck_icn_p_hdp = { + .gate_id = GATE_HDP, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_hdp", ICN_APB3, &clk_stm32_gate_ops, 0), +}; + +/* I2C */ +static struct clk_stm32_gate ck_icn_p_i2c1 = { + .gate_id = GATE_I2C1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_i2c1", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_i2c2 = { + .gate_id = GATE_I2C2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_i2c2", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_i2c3 = { + .gate_id = GATE_I2C3, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_i2c3", ICN_APB5, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_i2c1 = { + .gate_id = GATE_I2C1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_i2c1", FLEXGEN_13, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_i2c2 = { + .gate_id = GATE_I2C2, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_i2c2", FLEXGEN_13, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_i2c3 = { + .gate_id = GATE_I2C3, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_i2c3", FLEXGEN_38, &clk_stm32_gate_ops, 0), +}; + +/* I3C */ +static struct clk_stm32_gate ck_icn_p_i3c1 = { + .gate_id = GATE_I3C1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_i3c1", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_i3c2 = { + .gate_id = GATE_I3C2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_i3c2", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_i3c3 = { + .gate_id = GATE_I3C3, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_i3c3", ICN_APB5, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_i3c1 = { + .gate_id = GATE_I3C1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_i3c1", FLEXGEN_14, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_i3c2 = { + .gate_id = GATE_I3C2, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_i3c2", FLEXGEN_14, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_i3c3 = { + .gate_id = GATE_I3C3, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_i3c3", FLEXGEN_36, &clk_stm32_gate_ops, 0), +}; + +/* IWDG */ +static struct clk_stm32_gate ck_icn_p_iwdg1 = { + .gate_id = GATE_IWDG1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_iwdg1", ICN_APB3, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_iwdg2 = { + .gate_id = GATE_IWDG2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_iwdg2", ICN_APB3, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_iwdg3 = { + .gate_id = GATE_IWDG3, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_iwdg3", ICN_APB3, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_iwdg4 = { + .gate_id = GATE_IWDG4, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_iwdg4", ICN_APB3, &clk_stm32_gate_ops, 0), +}; + +/* LPTIM */ +static struct clk_stm32_gate ck_icn_p_lptim1 = { + .gate_id = GATE_LPTIM1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_lptim1", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_lptim2 = { + .gate_id = GATE_LPTIM2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_lptim2", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_lptim3 = { + .gate_id = GATE_LPTIM3, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_lptim3", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_lptim4 = { + .gate_id = GATE_LPTIM4, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_lptim4", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_lptim5 = { + .gate_id = GATE_LPTIM5, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_lptim5", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_lptim1 = { + .gate_id = GATE_LPTIM1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_lptim1", FLEXGEN_07, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_lptim2 = { + .gate_id = GATE_LPTIM2, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_lptim2", FLEXGEN_07, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_lptim3 = { + .gate_id = GATE_LPTIM3, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_lptim3", FLEXGEN_40, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_lptim4 = { + .gate_id = GATE_LPTIM4, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_lptim4", FLEXGEN_41, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_lptim5 = { + .gate_id = GATE_LPTIM5, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_lptim5", FLEXGEN_42, &clk_stm32_gate_ops, 0), +}; + +/* LPUART */ +static struct clk_stm32_gate ck_icn_p_lpuart1 = { + .gate_id = GATE_LPUART1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_lpuart1", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_lpuart1 = { + .gate_id = GATE_LPUART1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_lpuart1", FLEXGEN_39, &clk_stm32_gate_ops, 0), +}; + +/* MCO1 & MCO2 */ +static struct clk_stm32_composite ck_mco1 = { + .gate_id = GATE_MCO1, + .mux_id = MUX_MCO1, + .div_id = NO_STM32_DIV, + .hw.init = CLK_HW_INIT_PARENTS_DATA("ck_mco1", mco1_src, &clk_stm32_composite_ops, 0), +}; + +static struct clk_stm32_composite ck_mco2 = { + .gate_id = GATE_MCO2, + .mux_id = MUX_MCO2, + .div_id = NO_STM32_DIV, + .hw.init = CLK_HW_INIT_PARENTS_DATA("ck_mco2", mco2_src, &clk_stm32_composite_ops, 0), +}; + +/* MDF */ +static struct clk_stm32_gate ck_icn_p_mdf1 = { + .gate_id = GATE_MDF1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_mdf1", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_mdf1 = { + .gate_id = GATE_MDF1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_mdf1", FLEXGEN_21, &clk_stm32_gate_ops, 0), +}; + +/* OTG */ +static struct clk_stm32_gate ck_icn_m_otg = { + .gate_id = GATE_OTG, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_m_otg", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +/* PKA */ +static struct clk_stm32_gate ck_icn_p_pka = { + .gate_id = GATE_PKA, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_pka", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +/* RNG */ +static struct clk_stm32_gate ck_icn_p_rng1 = { + .gate_id = GATE_RNG1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_rng1", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_rng2 = { + .gate_id = GATE_RNG2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_rng2", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +/* SAES */ +static struct clk_stm32_gate ck_icn_p_saes = { + .gate_id = GATE_SAES, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_saes", ICN_LS_MCU, &clk_stm32_gate_ops, 0), +}; + +/* SAI */ +static struct clk_stm32_gate ck_icn_p_sai1 = { + .gate_id = GATE_SAI1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_sai1", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_sai2 = { + .gate_id = GATE_SAI2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_sai2", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_sai3 = { + .gate_id = GATE_SAI3, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_sai3", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_sai4 = { + .gate_id = GATE_SAI4, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_sai4", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_sai1 = { + .gate_id = GATE_SAI1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_sai1", FLEXGEN_22, &clk_stm32_gate_ops, + CLK_SET_RATE_PARENT), +}; + +static struct clk_stm32_gate ck_ker_sai2 = { + .gate_id = GATE_SAI2, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_sai2", FLEXGEN_23, &clk_stm32_gate_ops, + CLK_SET_RATE_PARENT), +}; + +static struct clk_stm32_gate ck_ker_sai3 = { + .gate_id = GATE_SAI3, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_sai3", FLEXGEN_24, &clk_stm32_gate_ops, + CLK_SET_RATE_PARENT), +}; + +static struct clk_stm32_gate ck_ker_sai4 = { + .gate_id = GATE_SAI4, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_sai4", FLEXGEN_25, &clk_stm32_gate_ops, + CLK_SET_RATE_PARENT), +}; + +/* SDMMC */ +static struct clk_stm32_gate ck_icn_m_sdmmc1 = { + .gate_id = GATE_SDMMC1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_m_sdmmc1", ICN_SDMMC, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_m_sdmmc2 = { + .gate_id = GATE_SDMMC2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_m_sdmmc2", ICN_SDMMC, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_m_sdmmc3 = { + .gate_id = GATE_SDMMC3, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_m_sdmmc3", ICN_SDMMC, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_sdmmc1 = { + .gate_id = GATE_SDMMC1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_sdmmc1", FLEXGEN_51, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_sdmmc2 = { + .gate_id = GATE_SDMMC2, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_sdmmc2", FLEXGEN_52, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_sdmmc3 = { + .gate_id = GATE_SDMMC3, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_sdmmc3", FLEXGEN_53, &clk_stm32_gate_ops, 0), +}; + +/* SERC */ +static struct clk_stm32_gate ck_icn_p_serc = { + .gate_id = GATE_SERC, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_serc", ICN_APB3, &clk_stm32_gate_ops, 0), +}; + +/* SPDIF */ +static struct clk_stm32_gate ck_icn_p_spdifrx = { + .gate_id = GATE_SPDIFRX, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_spdifrx", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_spdifrx = { + .gate_id = GATE_SPDIFRX, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_spdifrx", FLEXGEN_12, &clk_stm32_gate_ops, 0), +}; + +/* SPI */ +static struct clk_stm32_gate ck_icn_p_spi1 = { + .gate_id = GATE_SPI1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_spi1", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_spi2 = { + .gate_id = GATE_SPI2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_spi2", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_spi3 = { + .gate_id = GATE_SPI3, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_spi3", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_spi4 = { + .gate_id = GATE_SPI4, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_spi4", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_spi5 = { + .gate_id = GATE_SPI5, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_spi5", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_spi6 = { + .gate_id = GATE_SPI6, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_spi6", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_spi1 = { + .gate_id = GATE_SPI1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_spi1", FLEXGEN_16, &clk_stm32_gate_ops, + CLK_SET_RATE_PARENT), +}; + +static struct clk_stm32_gate ck_ker_spi2 = { + .gate_id = GATE_SPI2, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_spi2", FLEXGEN_10, &clk_stm32_gate_ops, + CLK_SET_RATE_PARENT), +}; + +static struct clk_stm32_gate ck_ker_spi3 = { + .gate_id = GATE_SPI3, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_spi3", FLEXGEN_11, &clk_stm32_gate_ops, + CLK_SET_RATE_PARENT), +}; + +static struct clk_stm32_gate ck_ker_spi4 = { + .gate_id = GATE_SPI4, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_spi4", FLEXGEN_17, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_spi5 = { + .gate_id = GATE_SPI5, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_spi5", FLEXGEN_17, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_spi6 = { + .gate_id = GATE_SPI6, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_spi6", FLEXGEN_37, &clk_stm32_gate_ops, 0), +}; + +/* Timers */ +static struct clk_stm32_gate ck_icn_p_tim2 = { + .gate_id = GATE_TIM2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim2", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim3 = { + .gate_id = GATE_TIM3, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim3", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim4 = { + .gate_id = GATE_TIM4, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim4", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim5 = { + .gate_id = GATE_TIM5, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim5", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim6 = { + .gate_id = GATE_TIM6, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim6", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim7 = { + .gate_id = GATE_TIM7, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim7", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim10 = { + .gate_id = GATE_TIM10, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim10", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim11 = { + .gate_id = GATE_TIM11, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim11", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim12 = { + .gate_id = GATE_TIM12, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim12", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim13 = { + .gate_id = GATE_TIM13, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim13", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim14 = { + .gate_id = GATE_TIM14, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim14", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim1 = { + .gate_id = GATE_TIM1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim1", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim8 = { + .gate_id = GATE_TIM8, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim8", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim15 = { + .gate_id = GATE_TIM15, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim15", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim16 = { + .gate_id = GATE_TIM16, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim16", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_tim17 = { + .gate_id = GATE_TIM17, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_tim17", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim2 = { + .gate_id = GATE_TIM2, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim2", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim3 = { + .gate_id = GATE_TIM3, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim3", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim4 = { + .gate_id = GATE_TIM4, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim4", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim5 = { + .gate_id = GATE_TIM5, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim5", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim6 = { + .gate_id = GATE_TIM6, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim6", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim7 = { + .gate_id = GATE_TIM7, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim7", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim10 = { + .gate_id = GATE_TIM10, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim10", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim11 = { + .gate_id = GATE_TIM11, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim11", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim12 = { + .gate_id = GATE_TIM12, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim12", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim13 = { + .gate_id = GATE_TIM13, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim13", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim14 = { + .gate_id = GATE_TIM14, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim14", TIMG1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim1 = { + .gate_id = GATE_TIM1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim1", TIMG2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim8 = { + .gate_id = GATE_TIM8, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim8", TIMG2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim15 = { + .gate_id = GATE_TIM15, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim15", TIMG2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim16 = { + .gate_id = GATE_TIM16, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim16", TIMG2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_tim17 = { + .gate_id = GATE_TIM17, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_tim17", TIMG2, &clk_stm32_gate_ops, 0), +}; + +/* UART/USART */ +static struct clk_stm32_gate ck_icn_p_usart2 = { + .gate_id = GATE_USART2, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_usart2", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_usart3 = { + .gate_id = GATE_USART3, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_usart3", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_uart4 = { + .gate_id = GATE_UART4, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_uart4", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_uart5 = { + .gate_id = GATE_UART5, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_uart5", ICN_APB1, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_usart1 = { + .gate_id = GATE_USART1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_usart1", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_usart6 = { + .gate_id = GATE_USART6, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_usart6", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_p_uart7 = { + .gate_id = GATE_UART7, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_uart7", ICN_APB2, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_usart2 = { + .gate_id = GATE_USART2, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_usart2", FLEXGEN_08, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_uart4 = { + .gate_id = GATE_UART4, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_uart4", FLEXGEN_08, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_usart3 = { + .gate_id = GATE_USART3, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_usart3", FLEXGEN_09, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_uart5 = { + .gate_id = GATE_UART5, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_uart5", FLEXGEN_09, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_usart1 = { + .gate_id = GATE_USART1, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_usart1", FLEXGEN_18, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_usart6 = { + .gate_id = GATE_USART6, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_usart6", FLEXGEN_19, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_ker_uart7 = { + .gate_id = GATE_UART7, + .hw.init = CLK_HW_INIT_INDEX("ck_ker_uart7", FLEXGEN_20, &clk_stm32_gate_ops, 0), +}; + +/* USB2PHY1 */ +static struct clk_stm32_composite ck_ker_usb2phy1 = { + .gate_id = GATE_USB2PHY1, + .mux_id = MUX_USB2PHY1, + .div_id = NO_STM32_DIV, + .hw.init = CLK_HW_INIT_PARENTS_DATA("ck_ker_usb2phy1", usb2phy1_src, + &clk_stm32_composite_ops, 0), +}; + +/* USBH */ +static struct clk_stm32_gate ck_icn_m_usbhehci = { + .gate_id = GATE_USBH, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_m_usbhehci", ICN_HSL, &clk_stm32_gate_ops, 0), +}; + +static struct clk_stm32_gate ck_icn_m_usbhohci = { + .gate_id = GATE_USBH, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_m_usbhohci", ICN_HSL, &clk_stm32_gate_ops, 0), +}; + +/* USB2PHY2 */ +static struct clk_stm32_composite ck_ker_usb2phy2_en = { + .gate_id = GATE_USB2PHY2, + .mux_id = MUX_USB2PHY2, + .div_id = NO_STM32_DIV, + .hw.init = CLK_HW_INIT_PARENTS_DATA("ck_ker_usb2phy2_en", usb2phy2_src, + &clk_stm32_composite_ops, 0), +}; + +/* VREF */ +static struct clk_stm32_gate ck_icn_p_vref = { + .gate_id = GATE_VREF, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_vref", ICN_APB3, &clk_stm32_gate_ops, 0), +}; + +/* WWDG */ +static struct clk_stm32_gate ck_icn_p_wwdg1 = { + .gate_id = GATE_WWDG1, + .hw.init = CLK_HW_INIT_INDEX("ck_icn_p_wwdg1", ICN_APB3, &clk_stm32_gate_ops, 0), +}; + +static int stm32_rcc_get_access(void __iomem *base, u32 index) +{ + u32 seccfgr, cidcfgr, semcr; + int bit, cid; + + bit = index % RCC_REG_SIZE; + + seccfgr = readl(base + RCC_SECCFGR(index)); + if (seccfgr & BIT(bit)) + return -EACCES; + + cidcfgr = readl(base + RCC_CIDCFGR(index)); + if (!(cidcfgr & RCC_CIDCFGR_CFEN)) + /* CID filtering is turned off: access granted */ + return 0; + + if (!(cidcfgr & RCC_CIDCFGR_SEM_EN)) { + /* Static CID mode */ + cid = FIELD_GET(RCC_CIDCFGR_SCID_MASK, cidcfgr); + if (cid != RCC_CID1) + return -EACCES; + return 0; + } + + /* Pass-list with semaphore mode */ + if (!(cidcfgr & RCC_CIDCFGR_SEMWLC1_EN)) + return -EACCES; + + semcr = readl(base + RCC_SEMCR(index)); + + cid = FIELD_GET(RCC_SEMCR_SEMCID_MASK, semcr); + if (cid != RCC_CID1) + return -EACCES; + + return 0; +} + +static int stm32mp21_check_security(struct device_node *np, void __iomem *base, + const struct clock_config *cfg) +{ + int ret = 0; + + if (cfg->sec_id != SECF_NONE) { + struct stm32_firewall firewall; + u32 index = (u32)cfg->sec_id; + + if (index & SEC_RIFSC_FLAG) { + ret = stm32_firewall_get_firewall(np, &firewall, 1); + if (ret) + return ret; + ret = stm32_firewall_grant_access_by_id(&firewall, index & ~SEC_RIFSC_FLAG); + } else { + ret = stm32_rcc_get_access(base, cfg->sec_id & ~SEC_RIFSC_FLAG); + } + } + + return ret; +} + +static const struct clock_config stm32mp21_clock_cfg[] = { + STM32_GATE_CFG(CK_BUS_ETH1, ck_icn_p_eth1, SEC_RIFSC(60)), + STM32_GATE_CFG(CK_BUS_ETH2, ck_icn_p_eth2, SEC_RIFSC(61)), + STM32_GATE_CFG(CK_BUS_ADC1, ck_icn_p_adc1, SEC_RIFSC(58)), + STM32_GATE_CFG(CK_BUS_ADC2, ck_icn_p_adc2, SEC_RIFSC(59)), + STM32_GATE_CFG(CK_BUS_CRC, ck_icn_p_crc, SEC_RIFSC(109)), + STM32_GATE_CFG(CK_BUS_MDF1, ck_icn_p_mdf1, SEC_RIFSC(54)), + STM32_GATE_CFG(CK_BUS_HASH1, ck_icn_p_hash1, SEC_RIFSC(96)), + STM32_GATE_CFG(CK_BUS_HASH2, ck_icn_p_hash2, SEC_RIFSC(97)), + STM32_GATE_CFG(CK_BUS_RNG1, ck_icn_p_rng1, SEC_RIFSC(92)), + STM32_GATE_CFG(CK_BUS_RNG2, ck_icn_p_rng2, SEC_RIFSC(93)), + STM32_GATE_CFG(CK_BUS_CRYP1, ck_icn_p_cryp1, SEC_RIFSC(98)), + STM32_GATE_CFG(CK_BUS_CRYP2, ck_icn_p_cryp2, SEC_RIFSC(99)), + STM32_GATE_CFG(CK_BUS_SAES, ck_icn_p_saes, SEC_RIFSC(95)), + STM32_GATE_CFG(CK_BUS_PKA, ck_icn_p_pka, SEC_RIFSC(94)), + STM32_GATE_CFG(CK_BUS_LPUART1, ck_icn_p_lpuart1, SEC_RIFSC(40)), + STM32_GATE_CFG(CK_BUS_LPTIM3, ck_icn_p_lptim3, SEC_RIFSC(19)), + STM32_GATE_CFG(CK_BUS_LPTIM4, ck_icn_p_lptim4, SEC_RIFSC(20)), + STM32_GATE_CFG(CK_BUS_LPTIM5, ck_icn_p_lptim5, SEC_RIFSC(21)), + STM32_GATE_CFG(CK_BUS_SDMMC1, ck_icn_m_sdmmc1, SEC_RIFSC(76)), + STM32_GATE_CFG(CK_BUS_SDMMC2, ck_icn_m_sdmmc2, SEC_RIFSC(77)), + STM32_GATE_CFG(CK_BUS_SDMMC3, ck_icn_m_sdmmc3, SEC_RIFSC(78)), + STM32_GATE_CFG(CK_BUS_USBHOHCI, ck_icn_m_usbhohci, SEC_RIFSC(63)), + STM32_GATE_CFG(CK_BUS_USBHEHCI, ck_icn_m_usbhehci, SEC_RIFSC(63)), + STM32_GATE_CFG(CK_BUS_OTG, ck_icn_m_otg, SEC_RIFSC(66)), + STM32_GATE_CFG(CK_BUS_TIM2, ck_icn_p_tim2, SEC_RIFSC(1)), + STM32_GATE_CFG(CK_BUS_TIM3, ck_icn_p_tim3, SEC_RIFSC(2)), + STM32_GATE_CFG(CK_BUS_TIM4, ck_icn_p_tim4, SEC_RIFSC(3)), + STM32_GATE_CFG(CK_BUS_TIM5, ck_icn_p_tim5, SEC_RIFSC(4)), + STM32_GATE_CFG(CK_BUS_TIM6, ck_icn_p_tim6, SEC_RIFSC(5)), + STM32_GATE_CFG(CK_BUS_TIM7, ck_icn_p_tim7, SEC_RIFSC(6)), + STM32_GATE_CFG(CK_BUS_TIM10, ck_icn_p_tim10, SEC_RIFSC(8)), + STM32_GATE_CFG(CK_BUS_TIM11, ck_icn_p_tim11, SEC_RIFSC(9)), + STM32_GATE_CFG(CK_BUS_TIM12, ck_icn_p_tim12, SEC_RIFSC(10)), + STM32_GATE_CFG(CK_BUS_TIM13, ck_icn_p_tim13, SEC_RIFSC(11)), + STM32_GATE_CFG(CK_BUS_TIM14, ck_icn_p_tim14, SEC_RIFSC(12)), + STM32_GATE_CFG(CK_BUS_LPTIM1, ck_icn_p_lptim1, SEC_RIFSC(17)), + STM32_GATE_CFG(CK_BUS_LPTIM2, ck_icn_p_lptim2, SEC_RIFSC(18)), + STM32_GATE_CFG(CK_BUS_SPI2, ck_icn_p_spi2, SEC_RIFSC(23)), + STM32_GATE_CFG(CK_BUS_SPI3, ck_icn_p_spi3, SEC_RIFSC(24)), + STM32_GATE_CFG(CK_BUS_SPDIFRX, ck_icn_p_spdifrx, SEC_RIFSC(30)), + STM32_GATE_CFG(CK_BUS_USART2, ck_icn_p_usart2, SEC_RIFSC(32)), + STM32_GATE_CFG(CK_BUS_USART3, ck_icn_p_usart3, SEC_RIFSC(33)), + STM32_GATE_CFG(CK_BUS_UART4, ck_icn_p_uart4, SEC_RIFSC(34)), + STM32_GATE_CFG(CK_BUS_UART5, ck_icn_p_uart5, SEC_RIFSC(35)), + STM32_GATE_CFG(CK_BUS_I2C1, ck_icn_p_i2c1, SEC_RIFSC(41)), + STM32_GATE_CFG(CK_BUS_I2C2, ck_icn_p_i2c2, SEC_RIFSC(42)), + STM32_GATE_CFG(CK_BUS_I2C3, ck_icn_p_i2c3, SEC_RIFSC(43)), + STM32_GATE_CFG(CK_BUS_I3C1, ck_icn_p_i3c1, SEC_RIFSC(114)), + STM32_GATE_CFG(CK_BUS_I3C2, ck_icn_p_i3c2, SEC_RIFSC(115)), + STM32_GATE_CFG(CK_BUS_I3C3, ck_icn_p_i3c3, SEC_RIFSC(116)), + STM32_GATE_CFG(CK_BUS_TIM1, ck_icn_p_tim1, SEC_RIFSC(0)), + STM32_GATE_CFG(CK_BUS_TIM8, ck_icn_p_tim8, SEC_RIFSC(7)), + STM32_GATE_CFG(CK_BUS_TIM15, ck_icn_p_tim15, SEC_RIFSC(13)), + STM32_GATE_CFG(CK_BUS_TIM16, ck_icn_p_tim16, SEC_RIFSC(14)), + STM32_GATE_CFG(CK_BUS_TIM17, ck_icn_p_tim17, SEC_RIFSC(15)), + STM32_GATE_CFG(CK_BUS_SAI1, ck_icn_p_sai1, SEC_RIFSC(49)), + STM32_GATE_CFG(CK_BUS_SAI2, ck_icn_p_sai2, SEC_RIFSC(50)), + STM32_GATE_CFG(CK_BUS_SAI3, ck_icn_p_sai3, SEC_RIFSC(51)), + STM32_GATE_CFG(CK_BUS_SAI4, ck_icn_p_sai4, SEC_RIFSC(52)), + STM32_GATE_CFG(CK_BUS_USART1, ck_icn_p_usart1, SEC_RIFSC(31)), + STM32_GATE_CFG(CK_BUS_USART6, ck_icn_p_usart6, SEC_RIFSC(36)), + STM32_GATE_CFG(CK_BUS_UART7, ck_icn_p_uart7, SEC_RIFSC(37)), + STM32_GATE_CFG(CK_BUS_FDCAN, ck_icn_p_fdcan, SEC_RIFSC(56)), + STM32_GATE_CFG(CK_BUS_SPI1, ck_icn_p_spi1, SEC_RIFSC(22)), + STM32_GATE_CFG(CK_BUS_SPI4, ck_icn_p_spi4, SEC_RIFSC(25)), + STM32_GATE_CFG(CK_BUS_SPI5, ck_icn_p_spi5, SEC_RIFSC(26)), + STM32_GATE_CFG(CK_BUS_SPI6, ck_icn_p_spi6, SEC_RIFSC(27)), + STM32_GATE_CFG(CK_BUS_IWDG1, ck_icn_p_iwdg1, SEC_RIFSC(100)), + STM32_GATE_CFG(CK_BUS_IWDG2, ck_icn_p_iwdg2, SEC_RIFSC(101)), + STM32_GATE_CFG(CK_BUS_IWDG3, ck_icn_p_iwdg3, SEC_RIFSC(102)), + STM32_GATE_CFG(CK_BUS_IWDG4, ck_icn_p_iwdg4, SEC_RIFSC(103)), + STM32_GATE_CFG(CK_BUS_WWDG1, ck_icn_p_wwdg1, SEC_RIFSC(104)), + STM32_GATE_CFG(CK_BUS_VREF, ck_icn_p_vref, SEC_RIFSC(106)), + STM32_GATE_CFG(CK_BUS_SERC, ck_icn_p_serc, SEC_RIFSC(110)), + STM32_GATE_CFG(CK_BUS_HDP, ck_icn_p_hdp, SEC_RIFSC(57)), + STM32_GATE_CFG(CK_BUS_LTDC, ck_icn_p_ltdc, SEC_RIFSC(80)), + STM32_GATE_CFG(CK_BUS_CSI, ck_icn_p_csi, SEC_RIFSC(86)), + STM32_GATE_CFG(CK_BUS_DCMIPP, ck_icn_p_dcmipp, SEC_RIFSC(87)), + STM32_GATE_CFG(CK_BUS_DCMIPSSI, ck_icn_p_dcmipssi, SEC_RIFSC(88)), + STM32_GATE_CFG(CK_BUS_DDRPERFM, ck_icn_p_ddrperfm, SEC_RIFSC(67)), + STM32_GATE_CFG(CK_KER_TIM2, ck_ker_tim2, SEC_RIFSC(1)), + STM32_GATE_CFG(CK_KER_TIM3, ck_ker_tim3, SEC_RIFSC(2)), + STM32_GATE_CFG(CK_KER_TIM4, ck_ker_tim4, SEC_RIFSC(3)), + STM32_GATE_CFG(CK_KER_TIM5, ck_ker_tim5, SEC_RIFSC(4)), + STM32_GATE_CFG(CK_KER_TIM6, ck_ker_tim6, SEC_RIFSC(5)), + STM32_GATE_CFG(CK_KER_TIM7, ck_ker_tim7, SEC_RIFSC(6)), + STM32_GATE_CFG(CK_KER_TIM10, ck_ker_tim10, SEC_RIFSC(8)), + STM32_GATE_CFG(CK_KER_TIM11, ck_ker_tim11, SEC_RIFSC(9)), + STM32_GATE_CFG(CK_KER_TIM12, ck_ker_tim12, SEC_RIFSC(10)), + STM32_GATE_CFG(CK_KER_TIM13, ck_ker_tim13, SEC_RIFSC(11)), + STM32_GATE_CFG(CK_KER_TIM14, ck_ker_tim14, SEC_RIFSC(12)), + STM32_GATE_CFG(CK_KER_TIM1, ck_ker_tim1, SEC_RIFSC(0)), + STM32_GATE_CFG(CK_KER_TIM8, ck_ker_tim8, SEC_RIFSC(7)), + STM32_GATE_CFG(CK_KER_TIM15, ck_ker_tim15, SEC_RIFSC(13)), + STM32_GATE_CFG(CK_KER_TIM16, ck_ker_tim16, SEC_RIFSC(14)), + STM32_GATE_CFG(CK_KER_TIM17, ck_ker_tim17, SEC_RIFSC(15)), + STM32_GATE_CFG(CK_KER_LPTIM1, ck_ker_lptim1, SEC_RIFSC(17)), + STM32_GATE_CFG(CK_KER_LPTIM2, ck_ker_lptim2, SEC_RIFSC(18)), + STM32_GATE_CFG(CK_KER_USART2, ck_ker_usart2, SEC_RIFSC(32)), + STM32_GATE_CFG(CK_KER_UART4, ck_ker_uart4, SEC_RIFSC(34)), + STM32_GATE_CFG(CK_KER_USART3, ck_ker_usart3, SEC_RIFSC(33)), + STM32_GATE_CFG(CK_KER_UART5, ck_ker_uart5, SEC_RIFSC(35)), + STM32_GATE_CFG(CK_KER_SPI2, ck_ker_spi2, SEC_RIFSC(23)), + STM32_GATE_CFG(CK_KER_SPI3, ck_ker_spi3, SEC_RIFSC(24)), + STM32_GATE_CFG(CK_KER_SPDIFRX, ck_ker_spdifrx, SEC_RIFSC(30)), + STM32_GATE_CFG(CK_KER_I2C1, ck_ker_i2c1, SEC_RIFSC(41)), + STM32_GATE_CFG(CK_KER_I2C2, ck_ker_i2c2, SEC_RIFSC(42)), + STM32_GATE_CFG(CK_KER_I3C1, ck_ker_i3c1, SEC_RIFSC(114)), + STM32_GATE_CFG(CK_KER_I3C2, ck_ker_i3c2, SEC_RIFSC(115)), + STM32_GATE_CFG(CK_KER_I2C3, ck_ker_i2c3, SEC_RIFSC(43)), + STM32_GATE_CFG(CK_KER_I3C3, ck_ker_i3c3, SEC_RIFSC(116)), + STM32_GATE_CFG(CK_KER_SPI1, ck_ker_spi1, SEC_RIFSC(22)), + STM32_GATE_CFG(CK_KER_SPI4, ck_ker_spi4, SEC_RIFSC(25)), + STM32_GATE_CFG(CK_KER_SPI5, ck_ker_spi5, SEC_RIFSC(26)), + STM32_GATE_CFG(CK_KER_SPI6, ck_ker_spi6, SEC_RIFSC(27)), + STM32_GATE_CFG(CK_KER_USART1, ck_ker_usart1, SEC_RIFSC(31)), + STM32_GATE_CFG(CK_KER_USART6, ck_ker_usart6, SEC_RIFSC(36)), + STM32_GATE_CFG(CK_KER_UART7, ck_ker_uart7, SEC_RIFSC(37)), + STM32_GATE_CFG(CK_KER_MDF1, ck_ker_mdf1, SEC_RIFSC(54)), + STM32_GATE_CFG(CK_KER_SAI1, ck_ker_sai1, SEC_RIFSC(49)), + STM32_GATE_CFG(CK_KER_SAI2, ck_ker_sai2, SEC_RIFSC(50)), + STM32_GATE_CFG(CK_KER_SAI3, ck_ker_sai3, SEC_RIFSC(51)), + STM32_GATE_CFG(CK_KER_SAI4, ck_ker_sai4, SEC_RIFSC(52)), + STM32_GATE_CFG(CK_KER_FDCAN, ck_ker_fdcan, SEC_RIFSC(56)), + STM32_GATE_CFG(CK_KER_CSI, ck_ker_csi, SEC_RIFSC(86)), + STM32_GATE_CFG(CK_KER_CSITXESC, ck_ker_csitxesc, SEC_RIFSC(86)), + STM32_GATE_CFG(CK_KER_CSIPHY, ck_ker_csiphy, SEC_RIFSC(86)), + STM32_GATE_CFG(CK_KER_LPUART1, ck_ker_lpuart1, SEC_RIFSC(40)), + STM32_GATE_CFG(CK_KER_LPTIM3, ck_ker_lptim3, SEC_RIFSC(19)), + STM32_GATE_CFG(CK_KER_LPTIM4, ck_ker_lptim4, SEC_RIFSC(20)), + STM32_GATE_CFG(CK_KER_LPTIM5, ck_ker_lptim5, SEC_RIFSC(21)), + STM32_GATE_CFG(CK_KER_SDMMC1, ck_ker_sdmmc1, SEC_RIFSC(76)), + STM32_GATE_CFG(CK_KER_SDMMC2, ck_ker_sdmmc2, SEC_RIFSC(77)), + STM32_GATE_CFG(CK_KER_SDMMC3, ck_ker_sdmmc3, SEC_RIFSC(78)), + STM32_GATE_CFG(CK_KER_ETH1, ck_ker_eth1, SEC_RIFSC(60)), + STM32_GATE_CFG(CK_ETH1_STP, ck_ker_eth1stp, SEC_RIFSC(60)), + STM32_GATE_CFG(CK_KER_ETH2, ck_ker_eth2, SEC_RIFSC(61)), + STM32_GATE_CFG(CK_ETH2_STP, ck_ker_eth2stp, SEC_RIFSC(61)), + STM32_GATE_CFG(CK_KER_ETH1PTP, ck_ker_eth1ptp, SEC_RIFSC(60)), + STM32_GATE_CFG(CK_KER_ETH2PTP, ck_ker_eth2ptp, SEC_RIFSC(61)), + STM32_GATE_CFG(CK_ETH1_MAC, ck_ker_eth1mac, SEC_RIFSC(60)), + STM32_GATE_CFG(CK_ETH1_TX, ck_ker_eth1tx, SEC_RIFSC(60)), + STM32_GATE_CFG(CK_ETH1_RX, ck_ker_eth1rx, SEC_RIFSC(60)), + STM32_GATE_CFG(CK_ETH2_MAC, ck_ker_eth2mac, SEC_RIFSC(61)), + STM32_GATE_CFG(CK_ETH2_TX, ck_ker_eth2tx, SEC_RIFSC(61)), + STM32_GATE_CFG(CK_ETH2_RX, ck_ker_eth2rx, SEC_RIFSC(61)), + STM32_COMPOSITE_CFG(CK_MCO1, ck_mco1, MP21_RIF_RCC_MCO1), + STM32_COMPOSITE_CFG(CK_MCO2, ck_mco2, MP21_RIF_RCC_MCO2), + STM32_COMPOSITE_CFG(CK_KER_ADC1, ck_ker_adc1, SEC_RIFSC(58)), + STM32_COMPOSITE_CFG(CK_KER_ADC2, ck_ker_adc2, SEC_RIFSC(59)), + STM32_COMPOSITE_CFG(CK_KER_USB2PHY1, ck_ker_usb2phy1, SEC_RIFSC(63)), + STM32_COMPOSITE_CFG(CK_KER_USB2PHY2EN, ck_ker_usb2phy2_en, SEC_RIFSC(66)), + STM32_COMPOSITE_CFG(CK_KER_DTS, ck_ker_dts, SEC_RIFSC(107)), + STM32_GATE_CFG(CK_KER_LTDC, ck_ker_ltdc, SEC_RIFSC(80)), +}; + +#define RESET_MP21(id, _offset, _bit_idx, _set_clr) \ + [id] = &(struct stm32_reset_cfg){ \ + .offset = (_offset), \ + .bit_idx = (_bit_idx), \ + .set_clr = (_set_clr), \ + } + +static const struct stm32_reset_cfg *stm32mp21_reset_cfg[] = { + RESET_MP21(TIM1_R, RCC_TIM1CFGR, 0, 0), + RESET_MP21(TIM2_R, RCC_TIM2CFGR, 0, 0), + RESET_MP21(TIM3_R, RCC_TIM3CFGR, 0, 0), + RESET_MP21(TIM4_R, RCC_TIM4CFGR, 0, 0), + RESET_MP21(TIM5_R, RCC_TIM5CFGR, 0, 0), + RESET_MP21(TIM6_R, RCC_TIM6CFGR, 0, 0), + RESET_MP21(TIM7_R, RCC_TIM7CFGR, 0, 0), + RESET_MP21(TIM8_R, RCC_TIM8CFGR, 0, 0), + RESET_MP21(TIM10_R, RCC_TIM10CFGR, 0, 0), + RESET_MP21(TIM11_R, RCC_TIM11CFGR, 0, 0), + RESET_MP21(TIM12_R, RCC_TIM12CFGR, 0, 0), + RESET_MP21(TIM13_R, RCC_TIM13CFGR, 0, 0), + RESET_MP21(TIM14_R, RCC_TIM14CFGR, 0, 0), + RESET_MP21(TIM15_R, RCC_TIM15CFGR, 0, 0), + RESET_MP21(TIM16_R, RCC_TIM16CFGR, 0, 0), + RESET_MP21(TIM17_R, RCC_TIM17CFGR, 0, 0), + RESET_MP21(LPTIM1_R, RCC_LPTIM1CFGR, 0, 0), + RESET_MP21(LPTIM2_R, RCC_LPTIM2CFGR, 0, 0), + RESET_MP21(LPTIM3_R, RCC_LPTIM3CFGR, 0, 0), + RESET_MP21(LPTIM4_R, RCC_LPTIM4CFGR, 0, 0), + RESET_MP21(LPTIM5_R, RCC_LPTIM5CFGR, 0, 0), + RESET_MP21(SPI1_R, RCC_SPI1CFGR, 0, 0), + RESET_MP21(SPI2_R, RCC_SPI2CFGR, 0, 0), + RESET_MP21(SPI3_R, RCC_SPI3CFGR, 0, 0), + RESET_MP21(SPI4_R, RCC_SPI4CFGR, 0, 0), + RESET_MP21(SPI5_R, RCC_SPI5CFGR, 0, 0), + RESET_MP21(SPI6_R, RCC_SPI6CFGR, 0, 0), + RESET_MP21(SPDIFRX_R, RCC_SPDIFRXCFGR, 0, 0), + RESET_MP21(USART1_R, RCC_USART1CFGR, 0, 0), + RESET_MP21(USART2_R, RCC_USART2CFGR, 0, 0), + RESET_MP21(USART3_R, RCC_USART3CFGR, 0, 0), + RESET_MP21(UART4_R, RCC_UART4CFGR, 0, 0), + RESET_MP21(UART5_R, RCC_UART5CFGR, 0, 0), + RESET_MP21(USART6_R, RCC_USART6CFGR, 0, 0), + RESET_MP21(UART7_R, RCC_UART7CFGR, 0, 0), + RESET_MP21(LPUART1_R, RCC_LPUART1CFGR, 0, 0), + RESET_MP21(I2C1_R, RCC_I2C1CFGR, 0, 0), + RESET_MP21(I2C2_R, RCC_I2C2CFGR, 0, 0), + RESET_MP21(I2C3_R, RCC_I2C3CFGR, 0, 0), + RESET_MP21(SAI1_R, RCC_SAI1CFGR, 0, 0), + RESET_MP21(SAI2_R, RCC_SAI2CFGR, 0, 0), + RESET_MP21(SAI3_R, RCC_SAI3CFGR, 0, 0), + RESET_MP21(SAI4_R, RCC_SAI4CFGR, 0, 0), + RESET_MP21(MDF1_R, RCC_MDF1CFGR, 0, 0), + RESET_MP21(FDCAN_R, RCC_FDCANCFGR, 0, 0), + RESET_MP21(HDP_R, RCC_HDPCFGR, 0, 0), + RESET_MP21(ADC1_R, RCC_ADC1CFGR, 0, 0), + RESET_MP21(ADC2_R, RCC_ADC2CFGR, 0, 0), + RESET_MP21(ETH1_R, RCC_ETH1CFGR, 0, 0), + RESET_MP21(ETH2_R, RCC_ETH2CFGR, 0, 0), + RESET_MP21(OTG_R, RCC_OTGCFGR, 0, 0), + RESET_MP21(USBH_R, RCC_USBHCFGR, 0, 0), + RESET_MP21(USB2PHY1_R, RCC_USB2PHY1CFGR, 0, 0), + RESET_MP21(USB2PHY2_R, RCC_USB2PHY2CFGR, 0, 0), + RESET_MP21(SDMMC1_R, RCC_SDMMC1CFGR, 0, 0), + RESET_MP21(SDMMC1DLL_R, RCC_SDMMC1CFGR, 16, 0), + RESET_MP21(SDMMC2_R, RCC_SDMMC2CFGR, 0, 0), + RESET_MP21(SDMMC2DLL_R, RCC_SDMMC2CFGR, 16, 0), + RESET_MP21(SDMMC3_R, RCC_SDMMC3CFGR, 0, 0), + RESET_MP21(SDMMC3DLL_R, RCC_SDMMC3CFGR, 16, 0), + RESET_MP21(LTDC_R, RCC_LTDCCFGR, 0, 0), + RESET_MP21(CSI_R, RCC_CSICFGR, 0, 0), + RESET_MP21(DCMIPP_R, RCC_DCMIPPCFGR, 0, 0), + RESET_MP21(DCMIPSSI_R, RCC_DCMIPSSICFGR, 0, 0), + RESET_MP21(WWDG1_R, RCC_WWDG1CFGR, 0, 0), + RESET_MP21(VREF_R, RCC_VREFCFGR, 0, 0), + RESET_MP21(DTS_R, RCC_DTSCFGR, 0, 0), + RESET_MP21(CRC_R, RCC_CRCCFGR, 0, 0), + RESET_MP21(SERC_R, RCC_SERCCFGR, 0, 0), + RESET_MP21(I3C1_R, RCC_I3C1CFGR, 0, 0), + RESET_MP21(I3C2_R, RCC_I3C2CFGR, 0, 0), + RESET_MP21(IWDG2_KER_R, RCC_IWDGC1CFGSETR, 18, 1), + RESET_MP21(IWDG4_KER_R, RCC_IWDGC2CFGSETR, 18, 1), + RESET_MP21(RNG1_R, RCC_RNG1CFGR, 0, 0), + RESET_MP21(RNG2_R, RCC_RNG2CFGR, 0, 0), + RESET_MP21(PKA_R, RCC_PKACFGR, 0, 0), + RESET_MP21(SAES_R, RCC_SAESCFGR, 0, 0), + RESET_MP21(HASH1_R, RCC_HASH1CFGR, 0, 0), + RESET_MP21(HASH2_R, RCC_HASH2CFGR, 0, 0), + RESET_MP21(CRYP1_R, RCC_CRYP1CFGR, 0, 0), + RESET_MP21(CRYP2_R, RCC_CRYP2CFGR, 0, 0), +}; + +static u16 stm32mp21_cpt_gate[GATE_NB]; + +static struct clk_stm32_clock_data stm32mp21_clock_data = { + .gate_cpt = stm32mp21_cpt_gate, + .gates = stm32mp21_gates, + .muxes = stm32mp21_muxes, +}; + +static struct clk_stm32_reset_data stm32mp21_reset_data = { + .reset_lines = stm32mp21_reset_cfg, + .nr_lines = ARRAY_SIZE(stm32mp21_reset_cfg), +}; + +static const struct stm32_rcc_match_data stm32mp21_data = { + .tab_clocks = stm32mp21_clock_cfg, + .num_clocks = ARRAY_SIZE(stm32mp21_clock_cfg), + .maxbinding = STM32MP21_LAST_CLK, + .clock_data = &stm32mp21_clock_data, + .reset_data = &stm32mp21_reset_data, + .check_security = &stm32mp21_check_security, +}; + +static const struct of_device_id stm32mp21_match_data[] = { + { .compatible = "st,stm32mp21-rcc", .data = &stm32mp21_data, }, + { } +}; +MODULE_DEVICE_TABLE(of, stm32mp21_match_data); + +static int stm32mp21_rcc_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + void __iomem *base; + + base = devm_platform_ioremap_resource(pdev, 0); + if (WARN_ON(IS_ERR(base))) + return PTR_ERR(base); + + return stm32_rcc_init(dev, stm32mp21_match_data, base); +} + +static struct platform_driver stm32mp21_rcc_clocks_driver = { + .driver = { + .name = "stm32mp21_rcc", + .of_match_table = stm32mp21_match_data, + }, + .probe = stm32mp21_rcc_clocks_probe, +}; + +static int __init stm32mp21_clocks_init(void) +{ + return platform_driver_register(&stm32mp21_rcc_clocks_driver); +} + +core_initcall(stm32mp21_clocks_init); + diff --git a/drivers/clk/stm32/stm32mp21_rcc.h b/drivers/clk/stm32/stm32mp21_rcc.h new file mode 100644 index 000000000000..df3ea921ffba --- /dev/null +++ b/drivers/clk/stm32/stm32mp21_rcc.h @@ -0,0 +1,651 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) STMicroelectronics 2025 - All Rights Reserved + * Author: Gabriel Fernandez for STMicroelectronics. + */ + +#ifndef STM32MP21_RCC_H +#define STM32MP21_RCC_H + +#define RCC_SECCFGR0 0x0 +#define RCC_SECCFGR1 0x4 +#define RCC_SECCFGR2 0x8 +#define RCC_SECCFGR3 0xC +#define RCC_PRIVCFGR0 0x10 +#define RCC_PRIVCFGR1 0x14 +#define RCC_PRIVCFGR2 0x18 +#define RCC_PRIVCFGR3 0x1C +#define RCC_RCFGLOCKR0 0x20 +#define RCC_RCFGLOCKR1 0x24 +#define RCC_RCFGLOCKR2 0x28 +#define RCC_RCFGLOCKR3 0x2C +#define RCC_R0CIDCFGR 0x30 +#define RCC_R0SEMCR 0x34 +#define RCC_R1CIDCFGR 0x38 +#define RCC_R1SEMCR 0x3C +#define RCC_R2CIDCFGR 0x40 +#define RCC_R2SEMCR 0x44 +#define RCC_R3CIDCFGR 0x48 +#define RCC_R3SEMCR 0x4C +#define RCC_R4CIDCFGR 0x50 +#define RCC_R4SEMCR 0x54 +#define RCC_R5CIDCFGR 0x58 +#define RCC_R5SEMCR 0x5C +#define RCC_R6CIDCFGR 0x60 +#define RCC_R6SEMCR 0x64 +#define RCC_R7CIDCFGR 0x68 +#define RCC_R7SEMCR 0x6C +#define RCC_R8CIDCFGR 0x70 +#define RCC_R8SEMCR 0x74 +#define RCC_R9CIDCFGR 0x78 +#define RCC_R9SEMCR 0x7C +#define RCC_R10CIDCFGR 0x80 +#define RCC_R10SEMCR 0x84 +#define RCC_R11CIDCFGR 0x88 +#define RCC_R11SEMCR 0x8C +#define RCC_R12CIDCFGR 0x90 +#define RCC_R12SEMCR 0x94 +#define RCC_R13CIDCFGR 0x98 +#define RCC_R13SEMCR 0x9C +#define RCC_R14CIDCFGR 0xA0 +#define RCC_R14SEMCR 0xA4 +#define RCC_R15CIDCFGR 0xA8 +#define RCC_R15SEMCR 0xAC +#define RCC_R16CIDCFGR 0xB0 +#define RCC_R16SEMCR 0xB4 +#define RCC_R17CIDCFGR 0xB8 +#define RCC_R17SEMCR 0xBC +#define RCC_R18CIDCFGR 0xC0 +#define RCC_R18SEMCR 0xC4 +#define RCC_R19CIDCFGR 0xC8 +#define RCC_R19SEMCR 0xCC +#define RCC_R20CIDCFGR 0xD0 +#define RCC_R20SEMCR 0xD4 +#define RCC_R21CIDCFGR 0xD8 +#define RCC_R21SEMCR 0xDC +#define RCC_R22CIDCFGR 0xE0 +#define RCC_R22SEMCR 0xE4 +#define RCC_R23CIDCFGR 0xE8 +#define RCC_R23SEMCR 0xEC +#define RCC_R24CIDCFGR 0xF0 +#define RCC_R24SEMCR 0xF4 +#define RCC_R25CIDCFGR 0xF8 +#define RCC_R25SEMCR 0xFC +#define RCC_R26CIDCFGR 0x100 +#define RCC_R26SEMCR 0x104 +#define RCC_R27CIDCFGR 0x108 +#define RCC_R27SEMCR 0x10C +#define RCC_R28CIDCFGR 0x110 +#define RCC_R28SEMCR 0x114 +#define RCC_R29CIDCFGR 0x118 +#define RCC_R29SEMCR 0x11C +#define RCC_R30CIDCFGR 0x120 +#define RCC_R30SEMCR 0x124 +#define RCC_R31CIDCFGR 0x128 +#define RCC_R31SEMCR 0x12C +#define RCC_R32CIDCFGR 0x130 +#define RCC_R32SEMCR 0x134 +#define RCC_R33CIDCFGR 0x138 +#define RCC_R33SEMCR 0x13C +#define RCC_R34CIDCFGR 0x140 +#define RCC_R34SEMCR 0x144 +#define RCC_R35CIDCFGR 0x148 +#define RCC_R35SEMCR 0x14C +#define RCC_R36CIDCFGR 0x150 +#define RCC_R36SEMCR 0x154 +#define RCC_R37CIDCFGR 0x158 +#define RCC_R37SEMCR 0x15C +#define RCC_R38CIDCFGR 0x160 +#define RCC_R38SEMCR 0x164 +#define RCC_R39CIDCFGR 0x168 +#define RCC_R39SEMCR 0x16C +#define RCC_R40CIDCFGR 0x170 +#define RCC_R40SEMCR 0x174 +#define RCC_R41CIDCFGR 0x178 +#define RCC_R41SEMCR 0x17C +#define RCC_R42CIDCFGR 0x180 +#define RCC_R42SEMCR 0x184 +#define RCC_R43CIDCFGR 0x188 +#define RCC_R43SEMCR 0x18C +#define RCC_R44CIDCFGR 0x190 +#define RCC_R44SEMCR 0x194 +#define RCC_R45CIDCFGR 0x198 +#define RCC_R45SEMCR 0x19C +#define RCC_R46CIDCFGR 0x1A0 +#define RCC_R46SEMCR 0x1A4 +#define RCC_R47CIDCFGR 0x1A8 +#define RCC_R47SEMCR 0x1AC +#define RCC_R48CIDCFGR 0x1B0 +#define RCC_R48SEMCR 0x1B4 +#define RCC_R49CIDCFGR 0x1B8 +#define RCC_R49SEMCR 0x1BC +#define RCC_R50CIDCFGR 0x1C0 +#define RCC_R50SEMCR 0x1C4 +#define RCC_R51CIDCFGR 0x1C8 +#define RCC_R51SEMCR 0x1CC +#define RCC_R52CIDCFGR 0x1D0 +#define RCC_R52SEMCR 0x1D4 +#define RCC_R53CIDCFGR 0x1D8 +#define RCC_R53SEMCR 0x1DC +#define RCC_R54CIDCFGR 0x1E0 +#define RCC_R54SEMCR 0x1E4 +#define RCC_R55CIDCFGR 0x1E8 +#define RCC_R55SEMCR 0x1EC +#define RCC_R56CIDCFGR 0x1F0 +#define RCC_R56SEMCR 0x1F4 +#define RCC_R57CIDCFGR 0x1F8 +#define RCC_R57SEMCR 0x1FC +#define RCC_R58CIDCFGR 0x200 +#define RCC_R58SEMCR 0x204 +#define RCC_R59CIDCFGR 0x208 +#define RCC_R59SEMCR 0x20C +#define RCC_R60CIDCFGR 0x210 +#define RCC_R60SEMCR 0x214 +#define RCC_R61CIDCFGR 0x218 +#define RCC_R61SEMCR 0x21C +#define RCC_R62CIDCFGR 0x220 +#define RCC_R62SEMCR 0x224 +#define RCC_R63CIDCFGR 0x228 +#define RCC_R63SEMCR 0x22C +#define RCC_R64CIDCFGR 0x230 +#define RCC_R64SEMCR 0x234 +#define RCC_R65CIDCFGR 0x238 +#define RCC_R65SEMCR 0x23C +#define RCC_R66CIDCFGR 0x240 +#define RCC_R66SEMCR 0x244 +#define RCC_R67CIDCFGR 0x248 +#define RCC_R67SEMCR 0x24C +#define RCC_R68CIDCFGR 0x250 +#define RCC_R68SEMCR 0x254 +#define RCC_R69CIDCFGR 0x258 +#define RCC_R69SEMCR 0x25C +#define RCC_R70CIDCFGR 0x260 +#define RCC_R70SEMCR 0x264 +#define RCC_R71CIDCFGR 0x268 +#define RCC_R71SEMCR 0x26C +#define RCC_R73CIDCFGR 0x278 +#define RCC_R73SEMCR 0x27C +#define RCC_R74CIDCFGR 0x280 +#define RCC_R74SEMCR 0x284 +#define RCC_R75CIDCFGR 0x288 +#define RCC_R75SEMCR 0x28C +#define RCC_R76CIDCFGR 0x290 +#define RCC_R76SEMCR 0x294 +#define RCC_R77CIDCFGR 0x298 +#define RCC_R77SEMCR 0x29C +#define RCC_R78CIDCFGR 0x2A0 +#define RCC_R78SEMCR 0x2A4 +#define RCC_R79CIDCFGR 0x2A8 +#define RCC_R79SEMCR 0x2AC +#define RCC_R83CIDCFGR 0x2C8 +#define RCC_R83SEMCR 0x2CC +#define RCC_R84CIDCFGR 0x2D0 +#define RCC_R84SEMCR 0x2D4 +#define RCC_R85CIDCFGR 0x2D8 +#define RCC_R85SEMCR 0x2DC +#define RCC_R86CIDCFGR 0x2E0 +#define RCC_R86SEMCR 0x2E4 +#define RCC_R87CIDCFGR 0x2E8 +#define RCC_R87SEMCR 0x2EC +#define RCC_R88CIDCFGR 0x2F0 +#define RCC_R88SEMCR 0x2F4 +#define RCC_R90CIDCFGR 0x300 +#define RCC_R90SEMCR 0x304 +#define RCC_R91CIDCFGR 0x308 +#define RCC_R91SEMCR 0x30C +#define RCC_R92CIDCFGR 0x310 +#define RCC_R92SEMCR 0x314 +#define RCC_R93CIDCFGR 0x318 +#define RCC_R93SEMCR 0x31C +#define RCC_R94CIDCFGR 0x320 +#define RCC_R94SEMCR 0x324 +#define RCC_R95CIDCFGR 0x328 +#define RCC_R95SEMCR 0x32C +#define RCC_R96CIDCFGR 0x330 +#define RCC_R96SEMCR 0x334 +#define RCC_R97CIDCFGR 0x338 +#define RCC_R97SEMCR 0x33C +#define RCC_R98CIDCFGR 0x340 +#define RCC_R98SEMCR 0x344 +#define RCC_R101CIDCFGR 0x358 +#define RCC_R101SEMCR 0x35C +#define RCC_R102CIDCFGR 0x360 +#define RCC_R102SEMCR 0x364 +#define RCC_R103CIDCFGR 0x368 +#define RCC_R103SEMCR 0x36C +#define RCC_R104CIDCFGR 0x370 +#define RCC_R104SEMCR 0x374 +#define RCC_R105CIDCFGR 0x378 +#define RCC_R105SEMCR 0x37C +#define RCC_R106CIDCFGR 0x380 +#define RCC_R106SEMCR 0x384 +#define RCC_R108CIDCFGR 0x390 +#define RCC_R108SEMCR 0x394 +#define RCC_R109CIDCFGR 0x398 +#define RCC_R109SEMCR 0x39C +#define RCC_R110CIDCFGR 0x3A0 +#define RCC_R110SEMCR 0x3A4 +#define RCC_R111CIDCFGR 0x3A8 +#define RCC_R111SEMCR 0x3AC +#define RCC_R112CIDCFGR 0x3B0 +#define RCC_R112SEMCR 0x3B4 +#define RCC_R113CIDCFGR 0x3B8 +#define RCC_R113SEMCR 0x3BC +#define RCC_GRSTCSETR 0x400 +#define RCC_C1RSTCSETR 0x404 +#define RCC_C2RSTCSETR 0x40C +#define RCC_HWRSTSCLRR 0x410 +#define RCC_C1HWRSTSCLRR 0x414 +#define RCC_C2HWRSTSCLRR 0x418 +#define RCC_C1BOOTRSTSSETR 0x41C +#define RCC_C1BOOTRSTSCLRR 0x420 +#define RCC_C2BOOTRSTSSETR 0x424 +#define RCC_C2BOOTRSTSCLRR 0x428 +#define RCC_C1SREQSETR 0x42C +#define RCC_C1SREQCLRR 0x430 +#define RCC_CPUBOOTCR 0x434 +#define RCC_STBYBOOTCR 0x438 +#define RCC_LEGBOOTCR 0x43C +#define RCC_BDCR 0x440 +#define RCC_RDCR 0x44C +#define RCC_C1MSRDCR 0x450 +#define RCC_PWRLPDLYCR 0x454 +#define RCC_C1CIESETR 0x458 +#define RCC_C1CIFCLRR 0x45C +#define RCC_C2CIESETR 0x460 +#define RCC_C2CIFCLRR 0x464 +#define RCC_IWDGC1FZSETR 0x468 +#define RCC_IWDGC1FZCLRR 0x46C +#define RCC_IWDGC1CFGSETR 0x470 +#define RCC_IWDGC1CFGCLRR 0x474 +#define RCC_IWDGC2FZSETR 0x478 +#define RCC_IWDGC2FZCLRR 0x47C +#define RCC_IWDGC2CFGSETR 0x480 +#define RCC_IWDGC2CFGCLRR 0x484 +#define RCC_MCO1CFGR 0x488 +#define RCC_MCO2CFGR 0x48C +#define RCC_OCENSETR 0x490 +#define RCC_OCENCLRR 0x494 +#define RCC_OCRDYR 0x498 +#define RCC_HSICFGR 0x49C +#define RCC_MSICFGR 0x4A0 +#define RCC_LSICR 0x4A4 +#define RCC_RTCDIVR 0x4A8 +#define RCC_APB1DIVR 0x4AC +#define RCC_APB2DIVR 0x4B0 +#define RCC_APB3DIVR 0x4B4 +#define RCC_APB4DIVR 0x4B8 +#define RCC_APB5DIVR 0x4BC +#define RCC_APBDBGDIVR 0x4C0 +#define RCC_TIMG1PRER 0x4C8 +#define RCC_TIMG2PRER 0x4CC +#define RCC_LSMCUDIVR 0x4D0 +#define RCC_DDRCPCFGR 0x4D4 +#define RCC_DDRCAPBCFGR 0x4D8 +#define RCC_DDRPHYCAPBCFGR 0x4DC +#define RCC_DDRPHYCCFGR 0x4E0 +#define RCC_DDRCFGR 0x4E4 +#define RCC_DDRITFCFGR 0x4E8 +#define RCC_SYSRAMCFGR 0x4F0 +#define RCC_SRAM1CFGR 0x4F8 +#define RCC_RETRAMCFGR 0x500 +#define RCC_BKPSRAMCFGR 0x504 +#define RCC_OSPI1CFGR 0x514 +#define RCC_FMCCFGR 0x51C +#define RCC_DBGCFGR 0x520 +#define RCC_STMCFGR 0x524 +#define RCC_ETRCFGR 0x528 +#define RCC_GPIOACFGR 0x52C +#define RCC_GPIOBCFGR 0x530 +#define RCC_GPIOCCFGR 0x534 +#define RCC_GPIODCFGR 0x538 +#define RCC_GPIOECFGR 0x53C +#define RCC_GPIOFCFGR 0x540 +#define RCC_GPIOGCFGR 0x544 +#define RCC_GPIOHCFGR 0x548 +#define RCC_GPIOICFGR 0x54C +#define RCC_GPIOZCFGR 0x558 +#define RCC_HPDMA1CFGR 0x55C +#define RCC_HPDMA2CFGR 0x560 +#define RCC_HPDMA3CFGR 0x564 +#define RCC_IPCC1CFGR 0x570 +#define RCC_RTCCFGR 0x578 +#define RCC_SYSCPU1CFGR 0x580 +#define RCC_BSECCFGR 0x584 +#define RCC_PLL2CFGR1 0x590 +#define RCC_PLL2CFGR2 0x594 +#define RCC_PLL2CFGR3 0x598 +#define RCC_PLL2CFGR4 0x59C +#define RCC_PLL2CFGR5 0x5A0 +#define RCC_PLL2CFGR6 0x5A8 +#define RCC_PLL2CFGR7 0x5AC +#define RCC_HSIFMONCR 0x5E0 +#define RCC_HSIFVALR 0x5E4 +#define RCC_MSIFMONCR 0x5E8 +#define RCC_MSIFVALR 0x5EC +#define RCC_TIM1CFGR 0x700 +#define RCC_TIM2CFGR 0x704 +#define RCC_TIM3CFGR 0x708 +#define RCC_TIM4CFGR 0x70C +#define RCC_TIM5CFGR 0x710 +#define RCC_TIM6CFGR 0x714 +#define RCC_TIM7CFGR 0x718 +#define RCC_TIM8CFGR 0x71C +#define RCC_TIM10CFGR 0x720 +#define RCC_TIM11CFGR 0x724 +#define RCC_TIM12CFGR 0x728 +#define RCC_TIM13CFGR 0x72C +#define RCC_TIM14CFGR 0x730 +#define RCC_TIM15CFGR 0x734 +#define RCC_TIM16CFGR 0x738 +#define RCC_TIM17CFGR 0x73C +#define RCC_LPTIM1CFGR 0x744 +#define RCC_LPTIM2CFGR 0x748 +#define RCC_LPTIM3CFGR 0x74C +#define RCC_LPTIM4CFGR 0x750 +#define RCC_LPTIM5CFGR 0x754 +#define RCC_SPI1CFGR 0x758 +#define RCC_SPI2CFGR 0x75C +#define RCC_SPI3CFGR 0x760 +#define RCC_SPI4CFGR 0x764 +#define RCC_SPI5CFGR 0x768 +#define RCC_SPI6CFGR 0x76C +#define RCC_SPDIFRXCFGR 0x778 +#define RCC_USART1CFGR 0x77C +#define RCC_USART2CFGR 0x780 +#define RCC_USART3CFGR 0x784 +#define RCC_UART4CFGR 0x788 +#define RCC_UART5CFGR 0x78C +#define RCC_USART6CFGR 0x790 +#define RCC_UART7CFGR 0x794 +#define RCC_LPUART1CFGR 0x7A0 +#define RCC_I2C1CFGR 0x7A4 +#define RCC_I2C2CFGR 0x7A8 +#define RCC_I2C3CFGR 0x7AC +#define RCC_SAI1CFGR 0x7C4 +#define RCC_SAI2CFGR 0x7C8 +#define RCC_SAI3CFGR 0x7CC +#define RCC_SAI4CFGR 0x7D0 +#define RCC_MDF1CFGR 0x7D8 +#define RCC_FDCANCFGR 0x7E0 +#define RCC_HDPCFGR 0x7E4 +#define RCC_ADC1CFGR 0x7E8 +#define RCC_ADC2CFGR 0x7EC +#define RCC_ETH1CFGR 0x7F0 +#define RCC_ETH2CFGR 0x7F4 +#define RCC_USBHCFGR 0x7FC +#define RCC_USB2PHY1CFGR 0x800 +#define RCC_OTGCFGR 0x808 +#define RCC_USB2PHY2CFGR 0x80C +#define RCC_STGENCFGR 0x824 +#define RCC_SDMMC1CFGR 0x830 +#define RCC_SDMMC2CFGR 0x834 +#define RCC_SDMMC3CFGR 0x838 +#define RCC_LTDCCFGR 0x840 +#define RCC_CSICFGR 0x858 +#define RCC_DCMIPPCFGR 0x85C +#define RCC_DCMIPSSICFGR 0x860 +#define RCC_RNG1CFGR 0x870 +#define RCC_RNG2CFGR 0x874 +#define RCC_PKACFGR 0x878 +#define RCC_SAESCFGR 0x87C +#define RCC_HASH1CFGR 0x880 +#define RCC_HASH2CFGR 0x884 +#define RCC_CRYP1CFGR 0x888 +#define RCC_CRYP2CFGR 0x88C +#define RCC_IWDG1CFGR 0x894 +#define RCC_IWDG2CFGR 0x898 +#define RCC_IWDG3CFGR 0x89C +#define RCC_IWDG4CFGR 0x8A0 +#define RCC_WWDG1CFGR 0x8A4 +#define RCC_VREFCFGR 0x8AC +#define RCC_DTSCFGR 0x8B0 +#define RCC_CRCCFGR 0x8B4 +#define RCC_SERCCFGR 0x8B8 +#define RCC_DDRPERFMCFGR 0x8C0 +#define RCC_I3C1CFGR 0x8C8 +#define RCC_I3C2CFGR 0x8CC +#define RCC_I3C3CFGR 0x8D0 +#define RCC_MUXSELCFGR 0x1000 +#define RCC_XBAR0CFGR 0x1018 +#define RCC_XBAR1CFGR 0x101C +#define RCC_XBAR2CFGR 0x1020 +#define RCC_XBAR3CFGR 0x1024 +#define RCC_XBAR4CFGR 0x1028 +#define RCC_XBAR5CFGR 0x102C +#define RCC_XBAR6CFGR 0x1030 +#define RCC_XBAR7CFGR 0x1034 +#define RCC_XBAR8CFGR 0x1038 +#define RCC_XBAR9CFGR 0x103C +#define RCC_XBAR10CFGR 0x1040 +#define RCC_XBAR11CFGR 0x1044 +#define RCC_XBAR12CFGR 0x1048 +#define RCC_XBAR13CFGR 0x104C +#define RCC_XBAR14CFGR 0x1050 +#define RCC_XBAR15CFGR 0x1054 +#define RCC_XBAR16CFGR 0x1058 +#define RCC_XBAR17CFGR 0x105C +#define RCC_XBAR18CFGR 0x1060 +#define RCC_XBAR19CFGR 0x1064 +#define RCC_XBAR20CFGR 0x1068 +#define RCC_XBAR21CFGR 0x106C +#define RCC_XBAR22CFGR 0x1070 +#define RCC_XBAR23CFGR 0x1074 +#define RCC_XBAR24CFGR 0x1078 +#define RCC_XBAR25CFGR 0x107C +#define RCC_XBAR26CFGR 0x1080 +#define RCC_XBAR27CFGR 0x1084 +#define RCC_XBAR28CFGR 0x1088 +#define RCC_XBAR29CFGR 0x108C +#define RCC_XBAR30CFGR 0x1090 +#define RCC_XBAR31CFGR 0x1094 +#define RCC_XBAR32CFGR 0x1098 +#define RCC_XBAR33CFGR 0x109C +#define RCC_XBAR34CFGR 0x10A0 +#define RCC_XBAR35CFGR 0x10A4 +#define RCC_XBAR36CFGR 0x10A8 +#define RCC_XBAR37CFGR 0x10AC +#define RCC_XBAR38CFGR 0x10B0 +#define RCC_XBAR39CFGR 0x10B4 +#define RCC_XBAR40CFGR 0x10B8 +#define RCC_XBAR41CFGR 0x10BC +#define RCC_XBAR42CFGR 0x10C0 +#define RCC_XBAR43CFGR 0x10C4 +#define RCC_XBAR44CFGR 0x10C8 +#define RCC_XBAR45CFGR 0x10CC +#define RCC_XBAR46CFGR 0x10D0 +#define RCC_XBAR47CFGR 0x10D4 +#define RCC_XBAR48CFGR 0x10D8 +#define RCC_XBAR49CFGR 0x10DC +#define RCC_XBAR50CFGR 0x10E0 +#define RCC_XBAR51CFGR 0x10E4 +#define RCC_XBAR52CFGR 0x10E8 +#define RCC_XBAR53CFGR 0x10EC +#define RCC_XBAR54CFGR 0x10F0 +#define RCC_XBAR55CFGR 0x10F4 +#define RCC_XBAR56CFGR 0x10F8 +#define RCC_XBAR57CFGR 0x10FC +#define RCC_XBAR58CFGR 0x1100 +#define RCC_XBAR59CFGR 0x1104 +#define RCC_XBAR60CFGR 0x1108 +#define RCC_XBAR61CFGR 0x110C +#define RCC_XBAR62CFGR 0x1110 +#define RCC_XBAR63CFGR 0x1114 +#define RCC_PREDIV0CFGR 0x1118 +#define RCC_PREDIV1CFGR 0x111C +#define RCC_PREDIV2CFGR 0x1120 +#define RCC_PREDIV3CFGR 0x1124 +#define RCC_PREDIV4CFGR 0x1128 +#define RCC_PREDIV5CFGR 0x112C +#define RCC_PREDIV6CFGR 0x1130 +#define RCC_PREDIV7CFGR 0x1134 +#define RCC_PREDIV8CFGR 0x1138 +#define RCC_PREDIV9CFGR 0x113C +#define RCC_PREDIV10CFGR 0x1140 +#define RCC_PREDIV11CFGR 0x1144 +#define RCC_PREDIV12CFGR 0x1148 +#define RCC_PREDIV13CFGR 0x114C +#define RCC_PREDIV14CFGR 0x1150 +#define RCC_PREDIV15CFGR 0x1154 +#define RCC_PREDIV16CFGR 0x1158 +#define RCC_PREDIV17CFGR 0x115C +#define RCC_PREDIV18CFGR 0x1160 +#define RCC_PREDIV19CFGR 0x1164 +#define RCC_PREDIV20CFGR 0x1168 +#define RCC_PREDIV21CFGR 0x116C +#define RCC_PREDIV22CFGR 0x1170 +#define RCC_PREDIV23CFGR 0x1174 +#define RCC_PREDIV24CFGR 0x1178 +#define RCC_PREDIV25CFGR 0x117C +#define RCC_PREDIV26CFGR 0x1180 +#define RCC_PREDIV27CFGR 0x1184 +#define RCC_PREDIV28CFGR 0x1188 +#define RCC_PREDIV29CFGR 0x118C +#define RCC_PREDIV30CFGR 0x1190 +#define RCC_PREDIV31CFGR 0x1194 +#define RCC_PREDIV32CFGR 0x1198 +#define RCC_PREDIV33CFGR 0x119C +#define RCC_PREDIV34CFGR 0x11A0 +#define RCC_PREDIV35CFGR 0x11A4 +#define RCC_PREDIV36CFGR 0x11A8 +#define RCC_PREDIV37CFGR 0x11AC +#define RCC_PREDIV38CFGR 0x11B0 +#define RCC_PREDIV39CFGR 0x11B4 +#define RCC_PREDIV40CFGR 0x11B8 +#define RCC_PREDIV41CFGR 0x11BC +#define RCC_PREDIV42CFGR 0x11C0 +#define RCC_PREDIV43CFGR 0x11C4 +#define RCC_PREDIV44CFGR 0x11C8 +#define RCC_PREDIV45CFGR 0x11CC +#define RCC_PREDIV46CFGR 0x11D0 +#define RCC_PREDIV47CFGR 0x11D4 +#define RCC_PREDIV48CFGR 0x11D8 +#define RCC_PREDIV49CFGR 0x11DC +#define RCC_PREDIV50CFGR 0x11E0 +#define RCC_PREDIV51CFGR 0x11E4 +#define RCC_PREDIV52CFGR 0x11E8 +#define RCC_PREDIV53CFGR 0x11EC +#define RCC_PREDIV54CFGR 0x11F0 +#define RCC_PREDIV55CFGR 0x11F4 +#define RCC_PREDIV56CFGR 0x11F8 +#define RCC_PREDIV57CFGR 0x11FC +#define RCC_PREDIV58CFGR 0x1200 +#define RCC_PREDIV59CFGR 0x1204 +#define RCC_PREDIV60CFGR 0x1208 +#define RCC_PREDIV61CFGR 0x120C +#define RCC_PREDIV62CFGR 0x1210 +#define RCC_PREDIV63CFGR 0x1214 +#define RCC_PREDIVSR1 0x1218 +#define RCC_PREDIVSR2 0x121C +#define RCC_FINDIV0CFGR 0x1224 +#define RCC_FINDIV1CFGR 0x1228 +#define RCC_FINDIV2CFGR 0x122C +#define RCC_FINDIV3CFGR 0x1230 +#define RCC_FINDIV4CFGR 0x1234 +#define RCC_FINDIV5CFGR 0x1238 +#define RCC_FINDIV6CFGR 0x123C +#define RCC_FINDIV7CFGR 0x1240 +#define RCC_FINDIV8CFGR 0x1244 +#define RCC_FINDIV9CFGR 0x1248 +#define RCC_FINDIV10CFGR 0x124C +#define RCC_FINDIV11CFGR 0x1250 +#define RCC_FINDIV12CFGR 0x1254 +#define RCC_FINDIV13CFGR 0x1258 +#define RCC_FINDIV14CFGR 0x125C +#define RCC_FINDIV15CFGR 0x1260 +#define RCC_FINDIV16CFGR 0x1264 +#define RCC_FINDIV17CFGR 0x1268 +#define RCC_FINDIV18CFGR 0x126C +#define RCC_FINDIV19CFGR 0x1270 +#define RCC_FINDIV20CFGR 0x1274 +#define RCC_FINDIV21CFGR 0x1278 +#define RCC_FINDIV22CFGR 0x127C +#define RCC_FINDIV23CFGR 0x1280 +#define RCC_FINDIV24CFGR 0x1284 +#define RCC_FINDIV25CFGR 0x1288 +#define RCC_FINDIV26CFGR 0x128C +#define RCC_FINDIV27CFGR 0x1290 +#define RCC_FINDIV28CFGR 0x1294 +#define RCC_FINDIV29CFGR 0x1298 +#define RCC_FINDIV30CFGR 0x129C +#define RCC_FINDIV31CFGR 0x12A0 +#define RCC_FINDIV32CFGR 0x12A4 +#define RCC_FINDIV33CFGR 0x12A8 +#define RCC_FINDIV34CFGR 0x12AC +#define RCC_FINDIV35CFGR 0x12B0 +#define RCC_FINDIV36CFGR 0x12B4 +#define RCC_FINDIV37CFGR 0x12B8 +#define RCC_FINDIV38CFGR 0x12BC +#define RCC_FINDIV39CFGR 0x12C0 +#define RCC_FINDIV40CFGR 0x12C4 +#define RCC_FINDIV41CFGR 0x12C8 +#define RCC_FINDIV42CFGR 0x12CC +#define RCC_FINDIV43CFGR 0x12D0 +#define RCC_FINDIV44CFGR 0x12D4 +#define RCC_FINDIV45CFGR 0x12D8 +#define RCC_FINDIV46CFGR 0x12DC +#define RCC_FINDIV47CFGR 0x12E0 +#define RCC_FINDIV48CFGR 0x12E4 +#define RCC_FINDIV49CFGR 0x12E8 +#define RCC_FINDIV50CFGR 0x12EC +#define RCC_FINDIV51CFGR 0x12F0 +#define RCC_FINDIV52CFGR 0x12F4 +#define RCC_FINDIV53CFGR 0x12F8 +#define RCC_FINDIV54CFGR 0x12FC +#define RCC_FINDIV55CFGR 0x1300 +#define RCC_FINDIV56CFGR 0x1304 +#define RCC_FINDIV57CFGR 0x1308 +#define RCC_FINDIV58CFGR 0x130C +#define RCC_FINDIV59CFGR 0x1310 +#define RCC_FINDIV60CFGR 0x1314 +#define RCC_FINDIV61CFGR 0x1318 +#define RCC_FINDIV62CFGR 0x131C +#define RCC_FINDIV63CFGR 0x1320 +#define RCC_FINDIVSR1 0x1324 +#define RCC_FINDIVSR2 0x1328 +#define RCC_FCALCOBS0CFGR 0x1340 +#define RCC_FCALCOBS1CFGR 0x1344 +#define RCC_FCALCREFCFGR 0x1348 +#define RCC_FCALCCR1 0x134C +#define RCC_FCALCCR2 0x1354 +#define RCC_FCALCSR 0x1358 +#define RCC_PLL4CFGR1 0x1360 +#define RCC_PLL4CFGR2 0x1364 +#define RCC_PLL4CFGR3 0x1368 +#define RCC_PLL4CFGR4 0x136C +#define RCC_PLL4CFGR5 0x1370 +#define RCC_PLL4CFGR6 0x1378 +#define RCC_PLL4CFGR7 0x137C +#define RCC_PLL5CFGR1 0x1388 +#define RCC_PLL5CFGR2 0x138C +#define RCC_PLL5CFGR3 0x1390 +#define RCC_PLL5CFGR4 0x1394 +#define RCC_PLL5CFGR5 0x1398 +#define RCC_PLL5CFGR6 0x13A0 +#define RCC_PLL5CFGR7 0x13A4 +#define RCC_PLL6CFGR1 0x13B0 +#define RCC_PLL6CFGR2 0x13B4 +#define RCC_PLL6CFGR3 0x13B8 +#define RCC_PLL6CFGR4 0x13BC +#define RCC_PLL6CFGR5 0x13C0 +#define RCC_PLL6CFGR6 0x13C8 +#define RCC_PLL6CFGR7 0x13CC +#define RCC_PLL7CFGR1 0x13D8 +#define RCC_PLL7CFGR2 0x13DC +#define RCC_PLL7CFGR3 0x13E0 +#define RCC_PLL7CFGR4 0x13E4 +#define RCC_PLL7CFGR5 0x13E8 +#define RCC_PLL7CFGR6 0x13F0 +#define RCC_PLL7CFGR7 0x13F4 +#define RCC_PLL8CFGR1 0x1400 +#define RCC_PLL8CFGR2 0x1404 +#define RCC_PLL8CFGR3 0x1408 +#define RCC_PLL8CFGR4 0x140C +#define RCC_PLL8CFGR5 0x1410 +#define RCC_PLL8CFGR6 0x1418 +#define RCC_PLL8CFGR7 0x141C +#define RCC_VERR 0xFFF4 +#define RCC_IDR 0xFFF8 +#define RCC_SIDR 0xFFFC + +#endif /* STM32MP21_RCC_H */ From 099760708aa37737663086ce28145f8d386564f3 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Wed, 25 Jun 2025 11:07:26 +0200 Subject: [PATCH 1868/2711] dt-bindings: stm32: cosmetic fixes for STM32MP25 clock and reset bindings - drop minItems from access-controllers - remove rcc label from example - fixes typos - remove double '::' from 'See also::' Acked-by: Conor Dooley Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/st,stm32mp25-rcc.yaml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml index 88e52f10d1ec..1e3b5d218bb0 100644 --- a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml +++ b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml @@ -11,9 +11,9 @@ maintainers: description: | The RCC hardware block is both a reset and a clock controller. - RCC makes also power management (resume/supend). + RCC makes also power management (resume/suspend). - See also:: + See also: include/dt-bindings/clock/st,stm32mp25-rcc.h include/dt-bindings/reset/st,stm32mp25-rcc.h @@ -38,7 +38,7 @@ properties: - description: CK_SCMI_MSI Low Power Internal oscillator (~ 4 MHz or ~ 16 MHz) - description: CK_SCMI_LSE Low Speed External oscillator (32 KHz) - description: CK_SCMI_LSI Low Speed Internal oscillator (~ 32 KHz) - - description: CK_SCMI_HSE_DIV2 CK_SCMI_HSE divided by 2 (coud be gated) + - description: CK_SCMI_HSE_DIV2 CK_SCMI_HSE divided by 2 (could be gated) - description: CK_SCMI_ICN_HS_MCU High Speed interconnect bus clock - description: CK_SCMI_ICN_LS_MCU Low Speed interconnect bus clock - description: CK_SCMI_ICN_SDMMC SDMMC interconnect bus clock @@ -108,15 +108,14 @@ properties: - description: CK_SCMI_ICN_APB2 Peripheral bridge 2 - description: CK_SCMI_ICN_APB3 Peripheral bridge 3 - description: CK_SCMI_ICN_APB4 Peripheral bridge 4 - - description: CK_SCMI_ICN_APBDBG Peripheral bridge for degub + - description: CK_SCMI_ICN_APBDBG Peripheral bridge for debug - description: CK_SCMI_TIMG1 Peripheral bridge for timer1 - description: CK_SCMI_TIMG2 Peripheral bridge for timer2 - description: CK_SCMI_PLL3 PLL3 clock - description: clk_dsi_txbyte DSI byte clock access-controllers: - minItems: 1 - maxItems: 2 + maxItems: 1 required: - compatible @@ -131,7 +130,7 @@ examples: - | #include - rcc: clock-controller@44200000 { + clock-controller@44200000 { compatible = "st,stm32mp25-rcc"; reg = <0x44200000 0x10000>; #clock-cells = <1>; From b92ef17f0c0b9ba8d913b092deee4d2914526007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Draszik?= Date: Wed, 30 Jul 2025 10:31:34 +0100 Subject: [PATCH 1869/2711] dt-bindings: clock: samsung,s2mps11: add s2mpg10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Samsung S2MPG10 clock controller is similar to the existing clock controllers supported by this binding. Register offsets / layout are slightly different, so it needs its own compatible. Acked-by: Stephen Boyd Acked-by: Rob Herring (Arm) Signed-off-by: André Draszik Signed-off-by: Stephen Boyd --- Documentation/devicetree/bindings/clock/samsung,s2mps11.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/samsung,s2mps11.yaml b/Documentation/devicetree/bindings/clock/samsung,s2mps11.yaml index d5296e6053a1..91d455155a60 100644 --- a/Documentation/devicetree/bindings/clock/samsung,s2mps11.yaml +++ b/Documentation/devicetree/bindings/clock/samsung,s2mps11.yaml @@ -25,6 +25,7 @@ description: | properties: compatible: enum: + - samsung,s2mpg10-clk - samsung,s2mps11-clk - samsung,s2mps13-clk # S2MPS13 and S2MPS15 - samsung,s2mps14-clk From 823699ccbf0f3794d89031f68385936eddaccf0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Draszik?= Date: Wed, 30 Jul 2025 10:31:35 +0100 Subject: [PATCH 1870/2711] clk: s2mps11: add support for S2MPG10 PMIC clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Samsung's S2MPG10 PMIC clock, which is similar to the existing PMIC clocks supported by this driver. S2MPG10 has three clock outputs @ 32kHz: AP, peri1 and peri2. Acked-by: Stephen Boyd Reviewed-by: Krzysztof Kozlowski Signed-off-by: André Draszik Signed-off-by: Stephen Boyd --- drivers/clk/clk-s2mps11.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index d4e9c3577b35..ff7ce12a5da6 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -140,6 +141,9 @@ static int s2mps11_clk_probe(struct platform_device *pdev) clk_data->num = S2MPS11_CLKS_NUM; switch (hwid) { + case S2MPG10: + s2mps11_reg = S2MPG10_PMIC_RTCBUF; + break; case S2MPS11X: s2mps11_reg = S2MPS11_REG_RTC_CTRL; break; @@ -221,6 +225,7 @@ static void s2mps11_clk_remove(struct platform_device *pdev) } static const struct platform_device_id s2mps11_clk_id[] = { + { "s2mpg10-clk", S2MPG10}, { "s2mps11-clk", S2MPS11X}, { "s2mps13-clk", S2MPS13X}, { "s2mps14-clk", S2MPS14X}, @@ -241,6 +246,9 @@ MODULE_DEVICE_TABLE(platform, s2mps11_clk_id); */ static const struct of_device_id s2mps11_dt_match[] __used = { { + .compatible = "samsung,s2mpg10-clk", + .data = (void *)S2MPG10, + }, { .compatible = "samsung,s2mps11-clk", .data = (void *)S2MPS11X, }, { From a787ab591c38ef790c733b60a3398c5da9a769a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duje=20Mihanovi=C4=87?= Date: Sat, 13 Sep 2025 23:12:50 +0200 Subject: [PATCH 1871/2711] clk: mmp: pxa1908: Instantiate power driver through auxiliary bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The power domain driver shares the APMU clock controller's registers. Instantiate the power domain driver through the APMU clock driver using the auxiliary bus. Also create a separate Kconfig entry for the PXA1908 clock driver to allow (de)selecting the driver at will and selecting CONFIG_AUXILIARY_BUS. Signed-off-by: Duje Mihanović Signed-off-by: Stephen Boyd --- MAINTAINERS | 2 ++ drivers/clk/Kconfig | 1 + drivers/clk/mmp/Kconfig | 10 ++++++++++ drivers/clk/mmp/Makefile | 5 ++++- drivers/clk/mmp/clk-pxa1908-apmu.c | 7 +++++++ 5 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mmp/Kconfig diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..860a221af295 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2869,7 +2869,9 @@ ARM/Marvell PXA1908 SOC support M: Duje Mihanović L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml F: arch/arm64/boot/dts/marvell/mmp/ +F: drivers/clk/mmp/Kconfig F: drivers/clk/mmp/clk-pxa1908*.c F: include/dt-bindings/clock/marvell,pxa1908.h diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 4d56475f94fc..68a9641fc649 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -511,6 +511,7 @@ source "drivers/clk/imx/Kconfig" source "drivers/clk/ingenic/Kconfig" source "drivers/clk/keystone/Kconfig" source "drivers/clk/mediatek/Kconfig" +source "drivers/clk/mmp/Kconfig" source "drivers/clk/meson/Kconfig" source "drivers/clk/mstar/Kconfig" source "drivers/clk/microchip/Kconfig" diff --git a/drivers/clk/mmp/Kconfig b/drivers/clk/mmp/Kconfig new file mode 100644 index 000000000000..b0d2fea3cda5 --- /dev/null +++ b/drivers/clk/mmp/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config COMMON_CLK_PXA1908 + bool "Clock driver for Marvell PXA1908" + depends on ARCH_MMP || COMPILE_TEST + depends on OF + default y if ARCH_MMP && ARM64 + select AUXILIARY_BUS + help + This driver supports the Marvell PXA1908 SoC clocks. diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile index 062cd87fa8dd..0a94f2f08563 100644 --- a/drivers/clk/mmp/Makefile +++ b/drivers/clk/mmp/Makefile @@ -11,4 +11,7 @@ obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o clk-pll.o pwr-island.o obj-$(CONFIG_COMMON_CLK_MMP2_AUDIO) += clk-audio.o -obj-$(CONFIG_ARCH_MMP) += clk-of-pxa1928.o clk-pxa1908-apbc.o clk-pxa1908-apbcp.o clk-pxa1908-apmu.o clk-pxa1908-mpmu.o +obj-$(CONFIG_COMMON_CLK_PXA1908) += clk-pxa1908-apbc.o clk-pxa1908-apbcp.o \ + clk-pxa1908-mpmu.o clk-pxa1908-apmu.o + +obj-$(CONFIG_ARCH_MMP) += clk-of-pxa1928.o diff --git a/drivers/clk/mmp/clk-pxa1908-apmu.c b/drivers/clk/mmp/clk-pxa1908-apmu.c index d3a070687fc5..7594a495a009 100644 --- a/drivers/clk/mmp/clk-pxa1908-apmu.c +++ b/drivers/clk/mmp/clk-pxa1908-apmu.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only +#include #include #include #include @@ -85,6 +86,7 @@ static void pxa1908_axi_periph_clk_init(struct pxa1908_clk_unit *pxa_unit) static int pxa1908_apmu_probe(struct platform_device *pdev) { struct pxa1908_clk_unit *pxa_unit; + struct auxiliary_device *adev; pxa_unit = devm_kzalloc(&pdev->dev, sizeof(*pxa_unit), GFP_KERNEL); if (!pxa_unit) @@ -94,6 +96,11 @@ static int pxa1908_apmu_probe(struct platform_device *pdev) if (IS_ERR(pxa_unit->base)) return PTR_ERR(pxa_unit->base); + adev = devm_auxiliary_device_create(&pdev->dev, "power", NULL); + if (IS_ERR(adev)) + return dev_err_probe(&pdev->dev, PTR_ERR(adev), + "Failed to register power controller\n"); + mmp_clk_init(pdev->dev.of_node, &pxa_unit->unit, APMU_NR_CLKS); pxa1908_axi_periph_clk_init(pxa_unit); From e0a94c6bb5b48c46ff4dd0533e79aacfda366b9f Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Tue, 29 Jul 2025 10:38:42 +0530 Subject: [PATCH 1872/2711] clk: xilinx: Optimize divisor search in clk_wzrd_get_divisors_ver() Optimise the clock wizard divisor calculation by eliminating the innermost loop over output divider o. Earlier there was an error that is returned if the WZRD_MIN_ERR is not achieved error is returned now it computes the best possible frequency. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Stephen Boyd --- drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 30 ++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c index 0295a13a811c..6af41d207ab5 100644 --- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c +++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c @@ -340,7 +340,7 @@ static int clk_wzrd_get_divisors_ver(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); - u64 vco_freq, freq, diff, vcomin, vcomax; + u64 vco_freq, freq, diff, vcomin, vcomax, best_diff = -1ULL; u32 m, d, o; u32 mmin, mmax, dmin, dmax, omin, omax; @@ -356,22 +356,26 @@ static int clk_wzrd_get_divisors_ver(struct clk_hw *hw, unsigned long rate, for (m = mmin; m <= mmax; m++) { for (d = dmin; d <= dmax; d++) { vco_freq = DIV_ROUND_CLOSEST((parent_rate * m), d); - if (vco_freq >= vcomin && vco_freq <= vcomax) { - for (o = omin; o <= omax; o++) { - freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o); - diff = abs(freq - rate); + if (vco_freq < vcomin || vco_freq > vcomax) + continue; - if (diff < WZRD_MIN_ERR) { - divider->m = m; - divider->d = d; - divider->o = o; - return 0; - } - } + o = DIV_ROUND_CLOSEST_ULL(vco_freq, rate); + if (o < omin || o > omax) + continue; + freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o); + diff = abs(freq - rate); + + if (diff < best_diff) { + best_diff = diff; + divider->m = m; + divider->d = d; + divider->o = o; + if (!diff) + return 0; } } } - return -EBUSY; + return 0; } static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate, From 7c2e86f7b5af93d0e78c16e4359318fe7797671d Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Fri, 5 Sep 2025 14:40:02 +0530 Subject: [PATCH 1873/2711] clk: clocking-wizard: Fix output clock register offset for Versal platforms The output clock register offset used in clk_wzrd_register_output_clocks was incorrectly referencing 0x3C instead of 0x38, which caused misconfiguration of output dividers on Versal platforms. Correcting the off-by-one error ensures proper configuration of output clocks. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Stephen Boyd --- drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c index 6af41d207ab5..d016f716d98c 100644 --- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c +++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c @@ -1112,7 +1112,7 @@ static int clk_wzrd_register_output_clocks(struct device *dev, int nr_outputs) (dev, clkout_name, clk_name, 0, clk_wzrd->base, - (WZRD_CLK_CFG_REG(is_versal, 3) + i * 8), + (WZRD_CLK_CFG_REG(is_versal, 2) + i * 8), WZRD_CLKOUT_DIVIDE_SHIFT, WZRD_CLKOUT_DIVIDE_WIDTH, CLK_DIVIDER_ONE_BASED | From 793e6b74806eea39da26f2fb7e4b640608d9598d Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Fri, 19 Sep 2025 14:26:42 +0000 Subject: [PATCH 1874/2711] dt-bindings: clock: loongson2: Add Loongson-2K0300 compatible Document the clock controller shipped in Loongson-2K0300 SoC, which generates various clock signals for SoC peripherals. Differing from previous generations of SoCs, LS2K0300 requires a 120MHz external clock input. Signed-off-by: Yao Zi Reviewed-by: Krzysztof Kozlowski Reviewed-by: Yanteng Si Signed-off-by: Stephen Boyd --- .../bindings/clock/loongson,ls2k-clk.yaml | 18 ++++++++-- include/dt-bindings/clock/loongson,ls2k-clk.h | 36 +++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/loongson,ls2k-clk.yaml b/Documentation/devicetree/bindings/clock/loongson,ls2k-clk.yaml index 4f79cdb417ab..c07ad1f85857 100644 --- a/Documentation/devicetree/bindings/clock/loongson,ls2k-clk.yaml +++ b/Documentation/devicetree/bindings/clock/loongson,ls2k-clk.yaml @@ -16,6 +16,7 @@ description: | properties: compatible: enum: + - loongson,ls2k0300-clk - loongson,ls2k0500-clk - loongson,ls2k-clk # This is for Loongson-2K1000 - loongson,ls2k2000-clk @@ -24,8 +25,7 @@ properties: maxItems: 1 clocks: - items: - - description: 100m ref + maxItems: 1 clock-names: items: @@ -38,11 +38,23 @@ properties: ID in its "clocks" phandle cell. See include/dt-bindings/clock/loongson,ls2k-clk.h for the full list of Loongson-2 SoC clock IDs. +allOf: + - if: + properties: + compatible: + contains: + const: loongson,ls2k0300-clk + then: + properties: + clock-names: false + else: + required: + - clock-names + required: - compatible - reg - clocks - - clock-names - '#clock-cells' additionalProperties: false diff --git a/include/dt-bindings/clock/loongson,ls2k-clk.h b/include/dt-bindings/clock/loongson,ls2k-clk.h index 4279ba595f1e..8cbb86b2cf1e 100644 --- a/include/dt-bindings/clock/loongson,ls2k-clk.h +++ b/include/dt-bindings/clock/loongson,ls2k-clk.h @@ -43,4 +43,40 @@ #define LOONGSON2_I2S_CLK 33 #define LOONGSON2_MISC_CLK 34 +#define LS2K0300_CLK_STABLE 0 +#define LS2K0300_NODE_PLL 1 +#define LS2K0300_DDR_PLL 2 +#define LS2K0300_PIX_PLL 3 +#define LS2K0300_CLK_THSENS 4 +#define LS2K0300_CLK_NODE_DIV 5 +#define LS2K0300_CLK_NODE_PLL_GATE 6 +#define LS2K0300_CLK_NODE_SCALE 7 +#define LS2K0300_CLK_NODE_GATE 8 +#define LS2K0300_CLK_GMAC_DIV 9 +#define LS2K0300_CLK_GMAC_GATE 10 +#define LS2K0300_CLK_I2S_DIV 11 +#define LS2K0300_CLK_I2S_SCALE 12 +#define LS2K0300_CLK_I2S_GATE 13 +#define LS2K0300_CLK_DDR_DIV 14 +#define LS2K0300_CLK_DDR_GATE 15 +#define LS2K0300_CLK_NET_DIV 16 +#define LS2K0300_CLK_NET_GATE 17 +#define LS2K0300_CLK_DEV_DIV 18 +#define LS2K0300_CLK_DEV_GATE 19 +#define LS2K0300_CLK_PIX_DIV 20 +#define LS2K0300_CLK_PIX_PLL_GATE 21 +#define LS2K0300_CLK_PIX_SCALE 22 +#define LS2K0300_CLK_PIX_GATE 23 +#define LS2K0300_CLK_GMACBP_DIV 24 +#define LS2K0300_CLK_GMACBP_GATE 25 +#define LS2K0300_CLK_USB_SCALE 26 +#define LS2K0300_CLK_USB_GATE 27 +#define LS2K0300_CLK_APB_SCALE 28 +#define LS2K0300_CLK_APB_GATE 29 +#define LS2K0300_CLK_BOOT_SCALE 30 +#define LS2K0300_CLK_BOOT_GATE 31 +#define LS2K0300_CLK_SDIO_SCALE 32 +#define LS2K0300_CLK_SDIO_GATE 33 +#define LS2K0300_CLK_GMAC_IN 34 + #endif From 499f81848ef3bdca53122e0c3758381f7cd40934 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Fri, 19 Sep 2025 14:26:43 +0000 Subject: [PATCH 1875/2711] clk: loongson2: Allow specifying clock flags for gate clock Some gate clocks need to be supplied with flags, e.g., it may be required to specify CLK_IS_CRTICAL for CPU clocks. Add a field to loongson2_clk_board_info for representing clock flags, and specify it when registering gate clocks. A new helper macro, CLK_GATE_FLAGS, is added to simplify definitions. Signed-off-by: Yao Zi Signed-off-by: Stephen Boyd --- drivers/clk/clk-loongson2.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-loongson2.c b/drivers/clk/clk-loongson2.c index 27e632edd484..cc3fb13e770f 100644 --- a/drivers/clk/clk-loongson2.c +++ b/drivers/clk/clk-loongson2.c @@ -50,6 +50,7 @@ struct loongson2_clk_board_info { const char *name; const char *parent_name; unsigned long fixed_rate; + unsigned long flags; u8 reg_offset; u8 div_shift; u8 div_width; @@ -105,6 +106,18 @@ struct loongson2_clk_board_info { .bit_idx = _bidx, \ } +#define CLK_GATE_FLAGS(_id, _name, _pname, _offset, _bidx, \ + _flags) \ + { \ + .id = _id, \ + .type = CLK_TYPE_GATE, \ + .name = _name, \ + .parent_name = _pname, \ + .reg_offset = _offset, \ + .bit_idx = _bidx, \ + .flags = _flags \ + } + #define CLK_FIXED(_id, _name, _pname, _rate) \ { \ .id = _id, \ @@ -332,7 +345,8 @@ static int loongson2_clk_probe(struct platform_device *pdev) &clp->clk_lock); break; case CLK_TYPE_GATE: - hw = devm_clk_hw_register_gate(dev, p->name, p->parent_name, 0, + hw = devm_clk_hw_register_gate(dev, p->name, p->parent_name, + p->flags, clp->base + p->reg_offset, p->bit_idx, 0, &clp->clk_lock); From 897117e35e180bc3f7346424c8b885ddb57fddc6 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Fri, 19 Sep 2025 14:26:44 +0000 Subject: [PATCH 1876/2711] clk: loongson2: Support scale clocks with an alternative mode LS2K0300 and LS2K1500 ship scale clocks with an alternative mode. There's one mode bit in clock configuration register indicating the operation mode. When mode bit is unset, the scale clock acts the same as previous generation of scale clocks. When it's set, a different equation for calculating result frequency, Fout = Fin / (scale + 1), is used. This patch adds frequency calculation support for the scale clock variant. A helper macro, CLK_SCALE_MODE, is added to simplify definitions. Signed-off-by: Yao Zi Signed-off-by: Stephen Boyd --- drivers/clk/clk-loongson2.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-loongson2.c b/drivers/clk/clk-loongson2.c index cc3fb13e770f..bba97270376c 100644 --- a/drivers/clk/clk-loongson2.c +++ b/drivers/clk/clk-loongson2.c @@ -42,6 +42,7 @@ struct loongson2_clk_data { u8 div_width; u8 mult_shift; u8 mult_width; + u8 bit_idx; }; struct loongson2_clk_board_info { @@ -96,6 +97,19 @@ struct loongson2_clk_board_info { .div_width = _dwidth, \ } +#define CLK_SCALE_MODE(_id, _name, _pname, _offset, \ + _dshift, _dwidth, _midx) \ + { \ + .id = _id, \ + .type = CLK_TYPE_SCALE, \ + .name = _name, \ + .parent_name = _pname, \ + .reg_offset = _offset, \ + .div_shift = _dshift, \ + .div_width = _dwidth, \ + .bit_idx = _midx + 1, \ + } + #define CLK_GATE(_id, _name, _pname, _offset, _bidx) \ { \ .id = _id, \ @@ -243,13 +257,18 @@ static const struct clk_ops loongson2_pll_recalc_ops = { static unsigned long loongson2_freqscale_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - u64 val, mult; + u64 val, scale; + u32 mode = 0; struct loongson2_clk_data *clk = to_loongson2_clk(hw); val = readq(clk->reg); - mult = loongson2_rate_part(val, clk->div_shift, clk->div_width) + 1; + scale = loongson2_rate_part(val, clk->div_shift, clk->div_width) + 1; - return div_u64((u64)parent_rate * mult, 8); + if (clk->bit_idx) + mode = val & BIT(clk->bit_idx - 1); + + return mode == 0 ? div_u64((u64)parent_rate * scale, 8) : + div_u64((u64)parent_rate, scale); } static const struct clk_ops loongson2_freqscale_recalc_ops = { @@ -284,6 +303,7 @@ static struct clk_hw *loongson2_clk_register(struct loongson2_clk_provider *clp, clk->div_width = cld->div_width; clk->mult_shift = cld->mult_shift; clk->mult_width = cld->mult_width; + clk->bit_idx = cld->bit_idx; clk->hw.init = &init; hw = &clk->hw; From 1ba5395c6ad0f40cd94792f737b2d19d6ec97e3c Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Fri, 19 Sep 2025 14:26:45 +0000 Subject: [PATCH 1877/2711] clk: loongson2: Allow zero divisors for dividers LS2K0300 and LS2K0500 ship divider clocks which allows zero divisors, in which case the divider acts the same as one is specified. Let's pass CLK_DIVIDER_ALLOW_ZERO when registering divider clocks to prepare for future introduction of these clocks. Signed-off-by: Yao Zi Signed-off-by: Stephen Boyd --- drivers/clk/clk-loongson2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-loongson2.c b/drivers/clk/clk-loongson2.c index bba97270376c..7a916c7d2718 100644 --- a/drivers/clk/clk-loongson2.c +++ b/drivers/clk/clk-loongson2.c @@ -361,7 +361,8 @@ static int loongson2_clk_probe(struct platform_device *pdev) p->parent_name, 0, clp->base + p->reg_offset, p->div_shift, p->div_width, - CLK_DIVIDER_ONE_BASED, + CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ALLOW_ZERO, &clp->clk_lock); break; case CLK_TYPE_GATE: From 158ddb87b13e6642dadaa16e3c4e9f5814825685 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Fri, 19 Sep 2025 14:26:46 +0000 Subject: [PATCH 1878/2711] clk: loongson2: Avoid hardcoding firmware name of the reference clock Loongson-2K0300 requires a reference clock with a frequency different from previous SoCs (120MHz v.s. 100MHz), thus hardcoding the firmware name of the reference clock as ref_100m isn't a good idea. This patch retrives the clock name of the reference clock dynamically during probe, avoiding the hardcoded pdata structure and preparing for support of future SoCs. Signed-off-by: Yao Zi Signed-off-by: Stephen Boyd --- drivers/clk/clk-loongson2.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/clk/clk-loongson2.c b/drivers/clk/clk-loongson2.c index 7a916c7d2718..52a9f1c2794a 100644 --- a/drivers/clk/clk-loongson2.c +++ b/drivers/clk/clk-loongson2.c @@ -13,10 +13,6 @@ #include #include -static const struct clk_parent_data pdata[] = { - { .fw_name = "ref_100m", }, -}; - enum loongson2_clk_type { CLK_TYPE_PLL, CLK_TYPE_SCALE, @@ -275,7 +271,8 @@ static const struct clk_ops loongson2_freqscale_recalc_ops = { .recalc_rate = loongson2_freqscale_recalc_rate, }; -static struct clk_hw *loongson2_clk_register(struct loongson2_clk_provider *clp, +static struct clk_hw *loongson2_clk_register(const char *parent, + struct loongson2_clk_provider *clp, const struct loongson2_clk_board_info *cld, const struct clk_ops *ops) { @@ -292,11 +289,7 @@ static struct clk_hw *loongson2_clk_register(struct loongson2_clk_provider *clp, init.ops = ops; init.flags = 0; init.num_parents = 1; - - if (!cld->parent_name) - init.parent_data = pdata; - else - init.parent_names = &cld->parent_name; + init.parent_names = &parent; clk->reg = clp->base + cld->reg_offset; clk->div_shift = cld->div_shift; @@ -321,11 +314,17 @@ static int loongson2_clk_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct loongson2_clk_provider *clp; const struct loongson2_clk_board_info *p, *data; + const char *refclk_name, *parent_name; data = device_get_match_data(dev); if (!data) return -EINVAL; + refclk_name = of_clk_get_parent_name(dev->of_node, 0); + if (IS_ERR(refclk_name)) + return dev_err_probe(dev, PTR_ERR(refclk_name), + "failed to get refclk name\n"); + for (p = data; p->name; p++) clks_num = max(clks_num, p->id + 1); @@ -347,18 +346,20 @@ static int loongson2_clk_probe(struct platform_device *pdev) for (i = 0; i < clks_num; i++) { p = &data[i]; + parent_name = p->parent_name ? p->parent_name : refclk_name; + switch (p->type) { case CLK_TYPE_PLL: - hw = loongson2_clk_register(clp, p, + hw = loongson2_clk_register(parent_name, clp, p, &loongson2_pll_recalc_ops); break; case CLK_TYPE_SCALE: - hw = loongson2_clk_register(clp, p, + hw = loongson2_clk_register(parent_name, clp, p, &loongson2_freqscale_recalc_ops); break; case CLK_TYPE_DIVIDER: hw = devm_clk_hw_register_divider(dev, p->name, - p->parent_name, 0, + parent_name, 0, clp->base + p->reg_offset, p->div_shift, p->div_width, CLK_DIVIDER_ONE_BASED | @@ -366,15 +367,15 @@ static int loongson2_clk_probe(struct platform_device *pdev) &clp->clk_lock); break; case CLK_TYPE_GATE: - hw = devm_clk_hw_register_gate(dev, p->name, p->parent_name, + hw = devm_clk_hw_register_gate(dev, p->name, parent_name, p->flags, clp->base + p->reg_offset, p->bit_idx, 0, &clp->clk_lock); break; case CLK_TYPE_FIXED: - hw = devm_clk_hw_register_fixed_rate_parent_data(dev, p->name, pdata, - 0, p->fixed_rate); + hw = devm_clk_hw_register_fixed_rate(dev, p->name, parent_name, + 0, p->fixed_rate); break; default: return dev_err_probe(dev, -EINVAL, "Invalid clk type\n"); From 74743c53a19fb7592ca0369f087015044ee4a571 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Fri, 19 Sep 2025 14:26:47 +0000 Subject: [PATCH 1879/2711] clk: loongson2: Add clock definitions for Loongson-2K0300 SoC The clock controller of Loongson-2K0300 consists of three PLLs, requires an 120MHz external reference clock to function, and generates clocks in various frequencies for SoC peripherals. Clock definitions for previous SoC generations could be reused for most clock hardwares. There're two gates marked as critical, clk_node_gate and clk_boot_gate, which supply the CPU cores and the system configuration bus. Disabling them leads to a SoC hang. Signed-off-by: Yao Zi Signed-off-by: Stephen Boyd --- drivers/clk/clk-loongson2.c | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/clk/clk-loongson2.c b/drivers/clk/clk-loongson2.c index 52a9f1c2794a..9c4c6c99db3e 100644 --- a/drivers/clk/clk-loongson2.c +++ b/drivers/clk/clk-loongson2.c @@ -137,6 +137,51 @@ struct loongson2_clk_board_info { .fixed_rate = _rate, \ } +static const struct loongson2_clk_board_info ls2k0300_clks[] = { + /* Reference Clock */ + CLK_PLL(LS2K0300_NODE_PLL, "pll_node", 0x00, 15, 9, 8, 7), + CLK_PLL(LS2K0300_DDR_PLL, "pll_ddr", 0x08, 15, 9, 8, 7), + CLK_PLL(LS2K0300_PIX_PLL, "pll_pix", 0x10, 15, 9, 8, 7), + CLK_FIXED(LS2K0300_CLK_STABLE, "clk_stable", NULL, 100000000), + CLK_FIXED(LS2K0300_CLK_THSENS, "clk_thsens", NULL, 10000000), + /* Node PLL */ + CLK_DIV(LS2K0300_CLK_NODE_DIV, "clk_node_div", "pll_node", 0x00, 24, 7), + CLK_DIV(LS2K0300_CLK_GMAC_DIV, "clk_gmac_div", "pll_node", 0x04, 0, 7), + CLK_DIV(LS2K0300_CLK_I2S_DIV, "clk_i2s_div", "pll_node", 0x04, 8, 7), + CLK_GATE(LS2K0300_CLK_NODE_PLL_GATE, "clk_node_pll_gate", "clk_node_div", 0x00, 0), + CLK_GATE(LS2K0300_CLK_GMAC_GATE, "clk_gmac_gate", "clk_gmac_div", 0x00, 1), + CLK_GATE(LS2K0300_CLK_I2S_GATE, "clk_i2s_gate", "clk_i2s_div", 0x00, 2), + CLK_GATE_FLAGS(LS2K0300_CLK_NODE_GATE, "clk_node_gate", "clk_node_scale", 0x24, 0, + CLK_IS_CRITICAL), + CLK_SCALE_MODE(LS2K0300_CLK_NODE_SCALE, "clk_node_scale", "clk_node_pll_gate", 0x20, 0, 3, + 3), + /* DDR PLL */ + CLK_DIV(LS2K0300_CLK_DDR_DIV, "clk_ddr_div", "pll_ddr", 0x08, 24, 7), + CLK_DIV(LS2K0300_CLK_NET_DIV, "clk_net_div", "pll_ddr", 0x0c, 0, 7), + CLK_DIV(LS2K0300_CLK_DEV_DIV, "clk_dev_div", "pll_ddr", 0x0c, 8, 7), + CLK_GATE(LS2K0300_CLK_NET_GATE, "clk_net_gate", "clk_net_div", 0x08, 1), + CLK_GATE(LS2K0300_CLK_DEV_GATE, "clk_dev_gate", "clk_dev_div", 0x08, 2), + CLK_GATE_FLAGS(LS2K0300_CLK_DDR_GATE, "clk_ddr_gate", "clk_ddr_div", 0x08, 0, + CLK_IS_CRITICAL), + /* PIX PLL */ + CLK_DIV(LS2K0300_CLK_PIX_DIV, "clk_pix_div", "pll_pix", 0x10, 24, 7), + CLK_DIV(LS2K0300_CLK_GMACBP_DIV, "clk_gmacbp_div", "pll_pix", 0x14, 0, 7), + CLK_GATE(LS2K0300_CLK_PIX_PLL_GATE, "clk_pix_pll_gate", "clk_pix_div", 0x10, 0), + CLK_GATE(LS2K0300_CLK_PIX_GATE, "clk_pix_gate", "clk_pix_scale", 0x24, 6), + CLK_GATE(LS2K0300_CLK_GMACBP_GATE, "clk_gmacbp_gate", "clk_gmacbp_div", 0x10, 1), + CLK_SCALE_MODE(LS2K0300_CLK_PIX_SCALE, "clk_pix_scale", "clk_pix_pll_gate", 0x20, 4, 3, 7), + /* clk_dev_gate */ + CLK_DIV(LS2K0300_CLK_SDIO_SCALE, "clk_sdio_scale", "clk_dev_gate", 0x20, 24, 4), + CLK_GATE(LS2K0300_CLK_USB_GATE, "clk_usb_gate", "clk_usb_scale", 0x24, 2), + CLK_GATE(LS2K0300_CLK_SDIO_GATE, "clk_sdio_gate", "clk_sdio_scale", 0x24, 4), + CLK_GATE(LS2K0300_CLK_APB_GATE, "clk_apb_gate", "clk_apb_scale", 0x24, 3), + CLK_GATE_FLAGS(LS2K0300_CLK_BOOT_GATE, "clk_boot_gate", "clk_boot_scale", 0x24, 1, + CLK_IS_CRITICAL), + CLK_SCALE_MODE(LS2K0300_CLK_USB_SCALE, "clk_usb_scale", "clk_dev_gate", 0x20, 12, 3, 15), + CLK_SCALE_MODE(LS2K0300_CLK_APB_SCALE, "clk_apb_scale", "clk_dev_gate", 0x20, 16, 3, 19), + CLK_SCALE_MODE(LS2K0300_CLK_BOOT_SCALE, "clk_boot_scale", "clk_dev_gate", 0x20, 8, 3, 11), +}; + static const struct loongson2_clk_board_info ls2k0500_clks[] = { CLK_PLL(LOONGSON2_NODE_PLL, "pll_node", 0, 16, 8, 8, 6), CLK_PLL(LOONGSON2_DDR_PLL, "pll_ddr", 0x8, 16, 8, 8, 6), @@ -393,6 +438,7 @@ static int loongson2_clk_probe(struct platform_device *pdev) } static const struct of_device_id loongson2_clk_match_table[] = { + { .compatible = "loongson,ls2k0300-clk", .data = &ls2k0300_clks }, { .compatible = "loongson,ls2k0500-clk", .data = &ls2k0500_clks }, { .compatible = "loongson,ls2k-clk", .data = &ls2k1000_clks }, { .compatible = "loongson,ls2k2000-clk", .data = &ls2k2000_clks }, From 1624dead9a4d288a594fdf19735ebfe4bb567cb8 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Sun, 6 Jul 2025 13:11:55 -0700 Subject: [PATCH 1880/2711] clk: nxp: Fix pll0 rate check condition in LPC18xx CGU driver The conditional check for the PLL0 multiplier 'm' used a logical AND instead of OR, making the range check ineffective. This patch replaces && with || to correctly reject invalid values of 'm' that are either less than or equal to 0 or greater than LPC18XX_PLL0_MSEL_MAX. This ensures proper bounds checking during clk rate setting and rounding. Fixes: b04e0b8fd544 ("clk: add lpc18xx cgu clk driver") Signed-off-by: Alok Tiwari [sboyd@kernel.org: 'm' is unsigned so remove < condition] Signed-off-by: Stephen Boyd --- drivers/clk/nxp/clk-lpc18xx-cgu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c index 30e0b283ca60..b9e204d63a97 100644 --- a/drivers/clk/nxp/clk-lpc18xx-cgu.c +++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c @@ -381,7 +381,7 @@ static int lpc18xx_pll0_determine_rate(struct clk_hw *hw, } m = DIV_ROUND_UP_ULL(req->best_parent_rate, req->rate * 2); - if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { + if (m == 0 || m > LPC18XX_PLL0_MSEL_MAX) { pr_warn("%s: unable to support rate %lu\n", __func__, req->rate); return -EINVAL; } @@ -404,7 +404,7 @@ static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate, } m = DIV_ROUND_UP_ULL(parent_rate, rate * 2); - if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { + if (m == 0 || m > LPC18XX_PLL0_MSEL_MAX) { pr_warn("%s: unable to support rate %lu\n", __func__, rate); return -EINVAL; } From 41bba99777be40924d99af117e8c220652c20ab6 Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sat, 30 Aug 2025 20:27:52 +0800 Subject: [PATCH 1881/2711] clk: ep93xx: Use int type to store negative error codes Change the 'ret' variable in ep93xx_uart_clock_init() from unsigned int to int, as it needs to store either negative error codes or zero. Storing the negative error codes in unsigned type, doesn't cause an issue at runtime but can be confusing. Additionally, assigning negative error codes to unsigned type may trigger a GCC warning when the -Wsign-conversion flag is enabled. No effect on runtime. Signed-off-by: Qianfeng Rong Signed-off-by: Stephen Boyd --- drivers/clk/clk-ep93xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-ep93xx.c b/drivers/clk/clk-ep93xx.c index 4bd8d6ecf6a2..a7dca023e00b 100644 --- a/drivers/clk/clk-ep93xx.c +++ b/drivers/clk/clk-ep93xx.c @@ -486,9 +486,10 @@ static const struct ep93xx_gate ep93xx_uarts[] = { static int ep93xx_uart_clock_init(struct ep93xx_clk_priv *priv) { struct clk_parent_data parent_data = { }; - unsigned int i, idx, ret, clk_uart_div; + unsigned int i, idx, clk_uart_div; struct ep93xx_clk *clk; u32 val; + int ret; regmap_read(priv->map, EP93XX_SYSCON_PWRCNT, &val); if (val & EP93XX_SYSCON_PWRCNT_UARTBAUD) From 49ef6491106209c595476fc122c3922dfd03253f Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Sat, 26 Apr 2025 15:54:28 +0300 Subject: [PATCH 1882/2711] clk: tegra: do not overallocate memory for bpmp clocks struct tegra_bpmp::clocks is a pointer to a dynamically allocated array of pointers to 'struct tegra_bpmp_clk'. But the size of the allocated area is calculated like it is an array containing actual 'struct tegra_bpmp_clk' objects - it's not true, there are just pointers. Found by Linux Verification Center (linuxtesting.org) with Svace static analysis tool. Fixes: 2db12b15c6f3 ("clk: tegra: Register clocks from root to leaf") Signed-off-by: Fedor Pchelkin Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-bpmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c index b2323cb8eddc..77a2586dbe00 100644 --- a/drivers/clk/tegra/clk-bpmp.c +++ b/drivers/clk/tegra/clk-bpmp.c @@ -635,7 +635,7 @@ static int tegra_bpmp_register_clocks(struct tegra_bpmp *bpmp, bpmp->num_clocks = count; - bpmp->clocks = devm_kcalloc(bpmp->dev, count, sizeof(struct tegra_bpmp_clk), GFP_KERNEL); + bpmp->clocks = devm_kcalloc(bpmp->dev, count, sizeof(*bpmp->clocks), GFP_KERNEL); if (!bpmp->clocks) return -ENOMEM; From 8ea304cff08f0605b425a3fb494ad47175214ea3 Mon Sep 17 00:00:00 2001 From: Ryan Chen Date: Wed, 17 Sep 2025 10:05:37 +0800 Subject: [PATCH 1883/2711] dt-bindings: clock: ast2700: modify soc0/1 clock define -add SOC0_CLK_AHBMUX: add SOC0_CLK_AHBMUX for ahb clock source divide. mpll-> ahb_mux -> div_table -> clk_ahb hpll-> -new add clock: SOC0_CLK_MPHYSRC: UFS MPHY clock source. SOC0_CLK_U2PHY_REFCLKSRC: USB2.0 phy clock reference source. SOC1_CLK_I3C: I3C clock source. Signed-off-by: Ryan Chen Acked-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/aspeed,ast2700-scu.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/dt-bindings/clock/aspeed,ast2700-scu.h b/include/dt-bindings/clock/aspeed,ast2700-scu.h index 63021af3caf5..bacf712e8e04 100644 --- a/include/dt-bindings/clock/aspeed,ast2700-scu.h +++ b/include/dt-bindings/clock/aspeed,ast2700-scu.h @@ -68,6 +68,9 @@ #define SCU0_CLK_GATE_UFSCLK 53 #define SCU0_CLK_GATE_EMMCCLK 54 #define SCU0_CLK_GATE_RVAS1CLK 55 +#define SCU0_CLK_U2PHY_REFCLKSRC 56 +#define SCU0_CLK_AHBMUX 57 +#define SCU0_CLK_MPHYSRC 58 /* SOC1 clk */ #define SCU1_CLKIN 0 @@ -159,5 +162,6 @@ #define SCU1_CLK_GATE_PORTCUSB2CLK 84 #define SCU1_CLK_GATE_PORTDUSB2CLK 85 #define SCU1_CLK_GATE_LTPI1TXCLK 86 +#define SCU1_CLK_I3C 87 #endif From decdff7db9d18a57a8581c5de3afd78a0a92aeac Mon Sep 17 00:00:00 2001 From: Ryan Chen Date: Wed, 17 Sep 2025 10:05:38 +0800 Subject: [PATCH 1884/2711] reset: aspeed: register AST2700 reset auxiliary bus device The AST2700 reset driver is registered as an auxiliary device due to reset and clock controller share the same register region. Signed-off-by: Ryan Chen Reviewed-by: Philipp Zabel Signed-off-by: Stephen Boyd --- drivers/reset/Kconfig | 7 + drivers/reset/Makefile | 1 + drivers/reset/reset-aspeed.c | 253 +++++++++++++++++++++++++++++++++++ 3 files changed, 261 insertions(+) create mode 100644 drivers/reset/reset-aspeed.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 635eef469ab7..78b7078478d4 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -22,6 +22,13 @@ config RESET_A10SR This option enables support for the external reset functions for peripheral PHYs on the Altera Arria10 System Resource Chip. +config RESET_ASPEED + tristate "ASPEED Reset Driver" + depends on ARCH_ASPEED || COMPILE_TEST + select AUXILIARY_BUS + help + This enables the reset controller driver for AST2700. + config RESET_ATH79 bool "AR71xx Reset Driver" if COMPILE_TEST default ATH79 diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index a917d2522e8d..f7934f9fb90b 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -6,6 +6,7 @@ obj-y += starfive/ obj-y += sti/ obj-y += tegra/ obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o +obj-$(CONFIG_RESET_ASPEED) += reset-aspeed.o obj-$(CONFIG_RESET_ATH79) += reset-ath79.o obj-$(CONFIG_RESET_AXS10X) += reset-axs10x.o obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o diff --git a/drivers/reset/reset-aspeed.c b/drivers/reset/reset-aspeed.c new file mode 100644 index 000000000000..dd2f860a69d7 --- /dev/null +++ b/drivers/reset/reset-aspeed.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 ASPEED Technology Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SCU0_RESET_CTRL1 0x200 +#define SCU0_RESET_CTRL2 0x220 +#define SCU1_RESET_CTRL1 0x200 +#define SCU1_RESET_CTRL2 0x220 +#define SCU1_PCIE3_CTRL 0x908 + +struct ast2700_reset_signal { + bool dedicated_clr; /* dedicated reset clr offset */ + u32 offset, bit; +}; + +struct aspeed_reset_info { + unsigned int nr_resets; + const struct ast2700_reset_signal *signal; +}; + +struct aspeed_reset { + struct reset_controller_dev rcdev; + struct aspeed_reset_info *info; + spinlock_t lock; /* Protect read-modify-write cycle */ + void __iomem *base; +}; + +static const struct ast2700_reset_signal ast2700_reset0_signals[] = { + [SCU0_RESET_SDRAM] = { true, SCU0_RESET_CTRL1, BIT(0) }, + [SCU0_RESET_DDRPHY] = { true, SCU0_RESET_CTRL1, BIT(1) }, + [SCU0_RESET_RSA] = { true, SCU0_RESET_CTRL1, BIT(2) }, + [SCU0_RESET_SHA3] = { true, SCU0_RESET_CTRL1, BIT(3) }, + [SCU0_RESET_HACE] = { true, SCU0_RESET_CTRL1, BIT(4) }, + [SCU0_RESET_SOC] = { true, SCU0_RESET_CTRL1, BIT(5) }, + [SCU0_RESET_VIDEO] = { true, SCU0_RESET_CTRL1, BIT(6) }, + [SCU0_RESET_2D] = { true, SCU0_RESET_CTRL1, BIT(7) }, + [SCU0_RESET_PCIS] = { true, SCU0_RESET_CTRL1, BIT(8) }, + [SCU0_RESET_RVAS0] = { true, SCU0_RESET_CTRL1, BIT(9) }, + [SCU0_RESET_RVAS1] = { true, SCU0_RESET_CTRL1, BIT(10) }, + [SCU0_RESET_SM3] = { true, SCU0_RESET_CTRL1, BIT(11) }, + [SCU0_RESET_SM4] = { true, SCU0_RESET_CTRL1, BIT(12) }, + [SCU0_RESET_CRT0] = { true, SCU0_RESET_CTRL1, BIT(13) }, + [SCU0_RESET_ECC] = { true, SCU0_RESET_CTRL1, BIT(14) }, + [SCU0_RESET_DP_PCI] = { true, SCU0_RESET_CTRL1, BIT(15) }, + [SCU0_RESET_UFS] = { true, SCU0_RESET_CTRL1, BIT(16) }, + [SCU0_RESET_EMMC] = { true, SCU0_RESET_CTRL1, BIT(17) }, + [SCU0_RESET_PCIE1RST] = { true, SCU0_RESET_CTRL1, BIT(18) }, + [SCU0_RESET_PCIE1RSTOE] = { true, SCU0_RESET_CTRL1, BIT(19) }, + [SCU0_RESET_PCIE0RST] = { true, SCU0_RESET_CTRL1, BIT(20) }, + [SCU0_RESET_PCIE0RSTOE] = { true, SCU0_RESET_CTRL1, BIT(21) }, + [SCU0_RESET_JTAG] = { true, SCU0_RESET_CTRL1, BIT(22) }, + [SCU0_RESET_MCTP0] = { true, SCU0_RESET_CTRL1, BIT(23) }, + [SCU0_RESET_MCTP1] = { true, SCU0_RESET_CTRL1, BIT(24) }, + [SCU0_RESET_XDMA0] = { true, SCU0_RESET_CTRL1, BIT(25) }, + [SCU0_RESET_XDMA1] = { true, SCU0_RESET_CTRL1, BIT(26) }, + [SCU0_RESET_H2X1] = { true, SCU0_RESET_CTRL1, BIT(27) }, + [SCU0_RESET_DP] = { true, SCU0_RESET_CTRL1, BIT(28) }, + [SCU0_RESET_DP_MCU] = { true, SCU0_RESET_CTRL1, BIT(29) }, + [SCU0_RESET_SSP] = { true, SCU0_RESET_CTRL1, BIT(30) }, + [SCU0_RESET_H2X0] = { true, SCU0_RESET_CTRL1, BIT(31) }, + [SCU0_RESET_PORTA_VHUB] = { true, SCU0_RESET_CTRL2, BIT(0) }, + [SCU0_RESET_PORTA_PHY3] = { true, SCU0_RESET_CTRL2, BIT(1) }, + [SCU0_RESET_PORTA_XHCI] = { true, SCU0_RESET_CTRL2, BIT(2) }, + [SCU0_RESET_PORTB_VHUB] = { true, SCU0_RESET_CTRL2, BIT(3) }, + [SCU0_RESET_PORTB_PHY3] = { true, SCU0_RESET_CTRL2, BIT(4) }, + [SCU0_RESET_PORTB_XHCI] = { true, SCU0_RESET_CTRL2, BIT(5) }, + [SCU0_RESET_PORTA_VHUB_EHCI] = { true, SCU0_RESET_CTRL2, BIT(6) }, + [SCU0_RESET_PORTB_VHUB_EHCI] = { true, SCU0_RESET_CTRL2, BIT(7) }, + [SCU0_RESET_UHCI] = { true, SCU0_RESET_CTRL2, BIT(8) }, + [SCU0_RESET_TSP] = { true, SCU0_RESET_CTRL2, BIT(9) }, + [SCU0_RESET_E2M0] = { true, SCU0_RESET_CTRL2, BIT(10) }, + [SCU0_RESET_E2M1] = { true, SCU0_RESET_CTRL2, BIT(11) }, + [SCU0_RESET_VLINK] = { true, SCU0_RESET_CTRL2, BIT(12) }, +}; + +static const struct ast2700_reset_signal ast2700_reset1_signals[] = { + [SCU1_RESET_LPC0] = { true, SCU1_RESET_CTRL1, BIT(0) }, + [SCU1_RESET_LPC1] = { true, SCU1_RESET_CTRL1, BIT(1) }, + [SCU1_RESET_MII] = { true, SCU1_RESET_CTRL1, BIT(2) }, + [SCU1_RESET_PECI] = { true, SCU1_RESET_CTRL1, BIT(3) }, + [SCU1_RESET_PWM] = { true, SCU1_RESET_CTRL1, BIT(4) }, + [SCU1_RESET_MAC0] = { true, SCU1_RESET_CTRL1, BIT(5) }, + [SCU1_RESET_MAC1] = { true, SCU1_RESET_CTRL1, BIT(6) }, + [SCU1_RESET_MAC2] = { true, SCU1_RESET_CTRL1, BIT(7) }, + [SCU1_RESET_ADC] = { true, SCU1_RESET_CTRL1, BIT(8) }, + [SCU1_RESET_SD] = { true, SCU1_RESET_CTRL1, BIT(9) }, + [SCU1_RESET_ESPI0] = { true, SCU1_RESET_CTRL1, BIT(10) }, + [SCU1_RESET_ESPI1] = { true, SCU1_RESET_CTRL1, BIT(11) }, + [SCU1_RESET_JTAG1] = { true, SCU1_RESET_CTRL1, BIT(12) }, + [SCU1_RESET_SPI0] = { true, SCU1_RESET_CTRL1, BIT(13) }, + [SCU1_RESET_SPI1] = { true, SCU1_RESET_CTRL1, BIT(14) }, + [SCU1_RESET_SPI2] = { true, SCU1_RESET_CTRL1, BIT(15) }, + [SCU1_RESET_I3C0] = { true, SCU1_RESET_CTRL1, BIT(16) }, + [SCU1_RESET_I3C1] = { true, SCU1_RESET_CTRL1, BIT(17) }, + [SCU1_RESET_I3C2] = { true, SCU1_RESET_CTRL1, BIT(18) }, + [SCU1_RESET_I3C3] = { true, SCU1_RESET_CTRL1, BIT(19) }, + [SCU1_RESET_I3C4] = { true, SCU1_RESET_CTRL1, BIT(20) }, + [SCU1_RESET_I3C5] = { true, SCU1_RESET_CTRL1, BIT(21) }, + [SCU1_RESET_I3C6] = { true, SCU1_RESET_CTRL1, BIT(22) }, + [SCU1_RESET_I3C7] = { true, SCU1_RESET_CTRL1, BIT(23) }, + [SCU1_RESET_I3C8] = { true, SCU1_RESET_CTRL1, BIT(24) }, + [SCU1_RESET_I3C9] = { true, SCU1_RESET_CTRL1, BIT(25) }, + [SCU1_RESET_I3C10] = { true, SCU1_RESET_CTRL1, BIT(26) }, + [SCU1_RESET_I3C11] = { true, SCU1_RESET_CTRL1, BIT(27) }, + [SCU1_RESET_I3C12] = { true, SCU1_RESET_CTRL1, BIT(28) }, + [SCU1_RESET_I3C13] = { true, SCU1_RESET_CTRL1, BIT(29) }, + [SCU1_RESET_I3C14] = { true, SCU1_RESET_CTRL1, BIT(30) }, + [SCU1_RESET_I3C15] = { true, SCU1_RESET_CTRL1, BIT(31) }, + [SCU1_RESET_MCU0] = { true, SCU1_RESET_CTRL2, BIT(0) }, + [SCU1_RESET_MCU1] = { true, SCU1_RESET_CTRL2, BIT(1) }, + [SCU1_RESET_H2A_SPI1] = { true, SCU1_RESET_CTRL2, BIT(2) }, + [SCU1_RESET_H2A_SPI2] = { true, SCU1_RESET_CTRL2, BIT(3) }, + [SCU1_RESET_UART0] = { true, SCU1_RESET_CTRL2, BIT(4) }, + [SCU1_RESET_UART1] = { true, SCU1_RESET_CTRL2, BIT(5) }, + [SCU1_RESET_UART2] = { true, SCU1_RESET_CTRL2, BIT(6) }, + [SCU1_RESET_UART3] = { true, SCU1_RESET_CTRL2, BIT(7) }, + [SCU1_RESET_I2C_FILTER] = { true, SCU1_RESET_CTRL2, BIT(8) }, + [SCU1_RESET_CALIPTRA] = { true, SCU1_RESET_CTRL2, BIT(9) }, + [SCU1_RESET_XDMA] = { true, SCU1_RESET_CTRL2, BIT(10) }, + [SCU1_RESET_FSI] = { true, SCU1_RESET_CTRL2, BIT(12) }, + [SCU1_RESET_CAN] = { true, SCU1_RESET_CTRL2, BIT(13) }, + [SCU1_RESET_MCTP] = { true, SCU1_RESET_CTRL2, BIT(14) }, + [SCU1_RESET_I2C] = { true, SCU1_RESET_CTRL2, BIT(15) }, + [SCU1_RESET_UART6] = { true, SCU1_RESET_CTRL2, BIT(16) }, + [SCU1_RESET_UART7] = { true, SCU1_RESET_CTRL2, BIT(17) }, + [SCU1_RESET_UART8] = { true, SCU1_RESET_CTRL2, BIT(18) }, + [SCU1_RESET_UART9] = { true, SCU1_RESET_CTRL2, BIT(19) }, + [SCU1_RESET_LTPI0] = { true, SCU1_RESET_CTRL2, BIT(20) }, + [SCU1_RESET_VGAL] = { true, SCU1_RESET_CTRL2, BIT(21) }, + [SCU1_RESET_LTPI1] = { true, SCU1_RESET_CTRL2, BIT(22) }, + [SCU1_RESET_ACE] = { true, SCU1_RESET_CTRL2, BIT(23) }, + [SCU1_RESET_E2M] = { true, SCU1_RESET_CTRL2, BIT(24) }, + [SCU1_RESET_UHCI] = { true, SCU1_RESET_CTRL2, BIT(25) }, + [SCU1_RESET_PORTC_USB2UART] = { true, SCU1_RESET_CTRL2, BIT(26) }, + [SCU1_RESET_PORTC_VHUB_EHCI] = { true, SCU1_RESET_CTRL2, BIT(27) }, + [SCU1_RESET_PORTD_USB2UART] = { true, SCU1_RESET_CTRL2, BIT(28) }, + [SCU1_RESET_PORTD_VHUB_EHCI] = { true, SCU1_RESET_CTRL2, BIT(29) }, + [SCU1_RESET_H2X] = { true, SCU1_RESET_CTRL2, BIT(30) }, + [SCU1_RESET_I3CDMA] = { true, SCU1_RESET_CTRL2, BIT(31) }, + [SCU1_RESET_PCIE2RST] = { false, SCU1_PCIE3_CTRL, BIT(0) }, +}; + +static inline struct aspeed_reset *to_aspeed_reset(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct aspeed_reset, rcdev); +} + +static int aspeed_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct aspeed_reset *rc = to_aspeed_reset(rcdev); + void __iomem *reg_offset = rc->base + rc->info->signal[id].offset; + + if (rc->info->signal[id].dedicated_clr) { + writel(rc->info->signal[id].bit, reg_offset); + } else { + guard(spinlock_irqsave)(&rc->lock); + writel(readl(reg_offset) & ~rc->info->signal[id].bit, reg_offset); + } + + return 0; +} + +static int aspeed_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct aspeed_reset *rc = to_aspeed_reset(rcdev); + void __iomem *reg_offset = rc->base + rc->info->signal[id].offset; + + if (rc->info->signal[id].dedicated_clr) { + writel(rc->info->signal[id].bit, reg_offset + 0x04); + } else { + guard(spinlock_irqsave)(&rc->lock); + writel(readl(reg_offset) | rc->info->signal[id].bit, reg_offset); + } + + return 0; +} + +static int aspeed_reset_status(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct aspeed_reset *rc = to_aspeed_reset(rcdev); + void __iomem *reg_offset = rc->base + rc->info->signal[id].offset; + + return (readl(reg_offset) & rc->info->signal[id].bit) ? 1 : 0; +} + +static const struct reset_control_ops aspeed_reset_ops = { + .assert = aspeed_reset_assert, + .deassert = aspeed_reset_deassert, + .status = aspeed_reset_status, +}; + +static int aspeed_reset_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct aspeed_reset *reset; + struct device *dev = &adev->dev; + + reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL); + if (!reset) + return -ENOMEM; + + spin_lock_init(&reset->lock); + + reset->info = (struct aspeed_reset_info *)id->driver_data; + reset->rcdev.owner = THIS_MODULE; + reset->rcdev.nr_resets = reset->info->nr_resets; + reset->rcdev.ops = &aspeed_reset_ops; + reset->rcdev.of_node = dev->parent->of_node; + reset->rcdev.dev = dev; + reset->rcdev.of_reset_n_cells = 1; + reset->base = (void __iomem *)adev->dev.platform_data; + + return devm_reset_controller_register(dev, &reset->rcdev); +} + +static const struct aspeed_reset_info ast2700_reset0_info = { + .nr_resets = ARRAY_SIZE(ast2700_reset0_signals), + .signal = ast2700_reset0_signals, +}; + +static const struct aspeed_reset_info ast2700_reset1_info = { + .nr_resets = ARRAY_SIZE(ast2700_reset1_signals), + .signal = ast2700_reset1_signals, +}; + +static const struct auxiliary_device_id aspeed_reset_ids[] = { + { .name = "clk_ast2700.reset0", .driver_data = (kernel_ulong_t)&ast2700_reset0_info }, + { .name = "clk_ast2700.reset1", .driver_data = (kernel_ulong_t)&ast2700_reset1_info }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, aspeed_reset_ids); + +static struct auxiliary_driver aspeed_reset_driver = { + .probe = aspeed_reset_probe, + .id_table = aspeed_reset_ids, +}; + +module_auxiliary_driver(aspeed_reset_driver); + +MODULE_AUTHOR("Ryan Chen "); +MODULE_DESCRIPTION("ASPEED SoC Reset Controller Driver"); +MODULE_LICENSE("GPL"); From 6df164e29bd4e6505c5a2e0e5f1e1f6957a16a42 Mon Sep 17 00:00:00 2001 From: Lei Lu Date: Mon, 11 Aug 2025 21:58:48 +0800 Subject: [PATCH 1885/2711] sunrpc: fix null pointer dereference on zero-length checksum In xdr_stream_decode_opaque_auth(), zero-length checksum.len causes checksum.data to be set to NULL. This triggers a NPD when accessing checksum.data in gss_krb5_verify_mic_v2(). This patch ensures that the value of checksum.len is not less than XDR_UNIT. Fixes: 0653028e8f1c ("SUNRPC: Convert gss_verify_header() to use xdr_stream") Cc: stable@kernel.org Signed-off-by: Lei Lu Signed-off-by: Chuck Lever --- net/sunrpc/auth_gss/svcauth_gss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index e82212f6b562..a8ec30759a18 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -724,7 +724,7 @@ svcauth_gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, rqstp->rq_auth_stat = rpc_autherr_badverf; return SVC_DENIED; } - if (flavor != RPC_AUTH_GSS) { + if (flavor != RPC_AUTH_GSS || checksum.len < XDR_UNIT) { rqstp->rq_auth_stat = rpc_autherr_badverf; return SVC_DENIED; } From c926f0298d3cdd25f1bfa019f5b74ed48796cef7 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 2 Jul 2025 19:33:44 -0400 Subject: [PATCH 1886/2711] NFSD: Relocate the fh_want_write() and fh_drop_write() helpers Clean up: these helpers are part of the NFSD file handle API. Relocate them to fs/nfsd/nfsfh.h. Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfsfh.h | 37 +++++++++++++++++++++++++++++++++++++ fs/nfsd/vfs.h | 20 -------------------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index 1cf979722521..6f5255d1c190 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -14,6 +14,8 @@ #include #include +#include "export.h" + /* * The file handle starts with a sequence of four-byte words. * The first word contains a version number (1) and three descriptor bytes @@ -271,6 +273,41 @@ static inline bool fh_fsid_match(const struct knfsd_fh *fh1, return true; } +/** + * fh_want_write - Get write access to an export + * @fhp: File handle of file to be written + * + * Caller must invoke fh_drop_write() when its write operation + * is complete. + * + * Returns 0 if the file handle's export can be written to. Otherwise + * the export is not prepared for updates, and the returned negative + * errno value reflects the reason for the failure. + */ +static inline int fh_want_write(struct svc_fh *fhp) +{ + int ret; + + if (fhp->fh_want_write) + return 0; + ret = mnt_want_write(fhp->fh_export->ex_path.mnt); + if (!ret) + fhp->fh_want_write = true; + return ret; +} + +/** + * fh_drop_write - Release write access on an export + * @fhp: File handle of file on which fh_want_write() was previously called + */ +static inline void fh_drop_write(struct svc_fh *fhp) +{ + if (fhp->fh_want_write) { + fhp->fh_want_write = false; + mnt_drop_write(fhp->fh_export->ex_path.mnt); + } +} + /** * knfsd_fh_hash - calculate the crc32 hash for the filehandle * @fh - pointer to filehandle diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index eff04959606f..4007dcbbbfef 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -160,26 +160,6 @@ __be32 nfsd_permission(struct svc_cred *cred, struct svc_export *exp, void nfsd_filp_close(struct file *fp); -static inline int fh_want_write(struct svc_fh *fh) -{ - int ret; - - if (fh->fh_want_write) - return 0; - ret = mnt_want_write(fh->fh_export->ex_path.mnt); - if (!ret) - fh->fh_want_write = true; - return ret; -} - -static inline void fh_drop_write(struct svc_fh *fh) -{ - if (fh->fh_want_write) { - fh->fh_want_write = false; - mnt_drop_write(fh->fh_export->ex_path.mnt); - } -} - static inline __be32 fh_getattr(const struct svc_fh *fh, struct kstat *stat) { u32 request_mask = STATX_BASIC_STATS; From c1f203e46c55ac063791bb893e30e5d14cabe1f6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 2 Jul 2025 19:33:45 -0400 Subject: [PATCH 1887/2711] NFSD: Move the fh_getattr() helper Clean up: The fh_getattr() function is part of NFSD's file handle API, so relocate it. I've made it an un-inlined function so that trace points and new functionality can easily be introduced. That increases the size of nfsd.ko by about a page on my x86_64 system (out of 26MB; compiled with -O2). Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfsfh.c | 23 +++++++++++++++++++++++ fs/nfsd/nfsfh.h | 1 + fs/nfsd/vfs.h | 13 ------------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 74cf1f4de174..f4c2fb3dd5d0 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -662,6 +662,29 @@ out_negative: return nfserr_serverfault; } +/** + * fh_getattr - Retrieve attributes on a local file + * @fhp: File handle of target file + * @stat: Caller-supplied kstat buffer to be filled in + * + * Returns nfs_ok on success, otherwise an NFS status code is + * returned. + */ +__be32 fh_getattr(const struct svc_fh *fhp, struct kstat *stat) +{ + struct path p = { + .mnt = fhp->fh_export->ex_path.mnt, + .dentry = fhp->fh_dentry, + }; + u32 request_mask = STATX_BASIC_STATS; + + if (fhp->fh_maxsize == NFS4_FHSIZE) + request_mask |= (STATX_BTIME | STATX_CHANGE_COOKIE); + + return nfserrno(vfs_getattr(&p, stat, request_mask, + AT_STATX_SYNC_AS_STAT)); +} + /** * fh_fill_pre_attrs - Fill in pre-op attributes * @fhp: file handle to be updated diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index 6f5255d1c190..5ef7191f8ad8 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -222,6 +222,7 @@ extern char * SVCFH_fmt(struct svc_fh *fhp); __be32 fh_verify(struct svc_rqst *, struct svc_fh *, umode_t, int); __be32 fh_verify_local(struct net *, struct svc_cred *, struct auth_domain *, struct svc_fh *, umode_t, int); +__be32 fh_getattr(const struct svc_fh *fhp, struct kstat *stat); __be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *); __be32 fh_update(struct svc_fh *); void fh_put(struct svc_fh *); diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 4007dcbbbfef..0c0292611c6d 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -160,17 +160,4 @@ __be32 nfsd_permission(struct svc_cred *cred, struct svc_export *exp, void nfsd_filp_close(struct file *fp); -static inline __be32 fh_getattr(const struct svc_fh *fh, struct kstat *stat) -{ - u32 request_mask = STATX_BASIC_STATS; - struct path p = {.mnt = fh->fh_export->ex_path.mnt, - .dentry = fh->fh_dentry}; - - if (fh->fh_maxsize == NFS4_FHSIZE) - request_mask |= (STATX_BTIME | STATX_CHANGE_COOKIE); - - return nfserrno(vfs_getattr(&p, stat, request_mask, - AT_STATX_SYNC_AS_STAT)); -} - #endif /* LINUX_NFSD_VFS_H */ From d9adbb6e10bf7d4223d3d521ede1b2052903bc5e Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 8 Jul 2025 14:14:53 -0400 Subject: [PATCH 1888/2711] sunrpc: delay pc_release callback until after the reply is sent The server-side sunrpc code currently calls pc_release before sending the reply. Change svc_process and svc_process_bc to call pc_release after sending the reply instead. Reviewed-by: NeilBrown Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- net/sunrpc/svc.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index b1fab3a69544..fc70e13b1cb9 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1426,8 +1426,6 @@ svc_process_common(struct svc_rqst *rqstp) /* Call the function that processes the request. */ rc = process.dispatch(rqstp); - if (procp->pc_release) - procp->pc_release(rqstp); xdr_finish_decode(xdr); if (!rc) @@ -1526,6 +1524,14 @@ static void svc_drop(struct svc_rqst *rqstp) trace_svc_drop(rqstp); } +static void svc_release_rqst(struct svc_rqst *rqstp) +{ + const struct svc_procedure *procp = rqstp->rq_procinfo; + + if (procp && procp->pc_release) + procp->pc_release(rqstp); +} + /** * svc_process - Execute one RPC transaction * @rqstp: RPC transaction context @@ -1565,9 +1571,12 @@ void svc_process(struct svc_rqst *rqstp) if (unlikely(*p != rpc_call)) goto out_baddir; - if (!svc_process_common(rqstp)) + if (!svc_process_common(rqstp)) { + svc_release_rqst(rqstp); goto out_drop; + } svc_send(rqstp); + svc_release_rqst(rqstp); return; out_baddir: @@ -1635,6 +1644,7 @@ void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp) if (!proc_error) { /* Processing error: drop the request */ xprt_free_bc_request(req); + svc_release_rqst(rqstp); return; } /* Finally, send the reply synchronously */ @@ -1648,6 +1658,7 @@ void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp) timeout.to_maxval = timeout.to_initval; memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); task = rpc_run_bc_task(req, &timeout); + svc_release_rqst(rqstp); if (IS_ERR(task)) return; From 2ee3a75e42081db3d951c0893f5d654f16d1c0e8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 18 Jul 2025 11:26:15 +1000 Subject: [PATCH 1889/2711] nfsd: discard nfsd_file_get_local() This interface was deprecated by commit e6f7e1487ab5 ("nfs_localio: simplify interface to nfsd for getting nfsd_file") and is now unused. So let's remove it. Signed-off-by: NeilBrown Reviewed-by: Mike Snitzer Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/filecache.c | 21 --------------------- fs/nfsd/filecache.h | 1 - fs/nfsd/localio.c | 1 - include/linux/nfslocalio.h | 1 - 4 files changed, 24 deletions(-) diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c index 732abf6b92a5..75bc48031c07 100644 --- a/fs/nfsd/filecache.c +++ b/fs/nfsd/filecache.c @@ -391,27 +391,6 @@ nfsd_file_put_local(struct nfsd_file __rcu **pnf) return net; } -/** - * nfsd_file_get_local - get nfsd_file reference and reference to net - * @nf: nfsd_file of which to put the reference - * - * Get reference to both the nfsd_file and nf->nf_net. - */ -struct nfsd_file * -nfsd_file_get_local(struct nfsd_file *nf) -{ - struct net *net = nf->nf_net; - - if (nfsd_net_try_get(net)) { - nf = nfsd_file_get(nf); - if (!nf) - nfsd_net_put(net); - } else { - nf = NULL; - } - return nf; -} - /** * nfsd_file_file - get the backing file of an nfsd_file * @nf: nfsd_file of which to access the backing file. diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h index 722b26c71e45..24ddf60e8434 100644 --- a/fs/nfsd/filecache.h +++ b/fs/nfsd/filecache.h @@ -63,7 +63,6 @@ int nfsd_file_cache_start_net(struct net *net); void nfsd_file_cache_shutdown_net(struct net *net); void nfsd_file_put(struct nfsd_file *nf); struct net *nfsd_file_put_local(struct nfsd_file __rcu **nf); -struct nfsd_file *nfsd_file_get_local(struct nfsd_file *nf); struct nfsd_file *nfsd_file_get(struct nfsd_file *nf); struct file *nfsd_file_file(struct nfsd_file *nf); void nfsd_file_close_inode_sync(struct inode *inode); diff --git a/fs/nfsd/localio.c b/fs/nfsd/localio.c index cb237f1b902a..269fa9391dc4 100644 --- a/fs/nfsd/localio.c +++ b/fs/nfsd/localio.c @@ -122,7 +122,6 @@ static const struct nfsd_localio_operations nfsd_localio_ops = { .nfsd_net_put = nfsd_net_put, .nfsd_open_local_fh = nfsd_open_local_fh, .nfsd_file_put_local = nfsd_file_put_local, - .nfsd_file_get_local = nfsd_file_get_local, .nfsd_file_file = nfsd_file_file, }; diff --git a/include/linux/nfslocalio.h b/include/linux/nfslocalio.h index 5c7c92659e73..59ea90bd136b 100644 --- a/include/linux/nfslocalio.h +++ b/include/linux/nfslocalio.h @@ -63,7 +63,6 @@ struct nfsd_localio_operations { struct nfsd_file __rcu **pnf, const fmode_t); struct net *(*nfsd_file_put_local)(struct nfsd_file __rcu **); - struct nfsd_file *(*nfsd_file_get_local)(struct nfsd_file *); struct file *(*nfsd_file_file)(struct nfsd_file *); } ____cacheline_aligned; From c97b737ef8f10f28424822c139e3b22b9e9bcc2b Mon Sep 17 00:00:00 2001 From: Sergey Bashirov Date: Fri, 18 Jul 2025 11:09:56 +0300 Subject: [PATCH 1890/2711] sunrpc: Change ret code of xdr_stream_decode_opaque_fixed Since the opaque is fixed in size, the caller already knows how many bytes were decoded, on success. Thus, xdr_stream_decode_opaque_fixed() doesn't need to return that value. And, xdr_stream_decode_u32 and _u64 both return zero on success. This patch simplifies the caller's error checking to avoid potential integer promotion issues. Suggested-by: Dan Carpenter Signed-off-by: Sergey Bashirov Signed-off-by: Chuck Lever --- include/linux/sunrpc/xdr.h | 4 ++-- .../xdrgen/templates/C/typedef/decoder/fixed_length_opaque.j2 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 8a9ec617cf66..8d354015d762 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -721,7 +721,7 @@ xdr_stream_decode_u64(struct xdr_stream *xdr, __u64 *ptr) * @len: size of buffer pointed to by @ptr * * Return values: - * On success, returns size of object stored in @ptr + * %0 on success * %-EBADMSG on XDR buffer overflow */ static inline ssize_t @@ -732,7 +732,7 @@ xdr_stream_decode_opaque_fixed(struct xdr_stream *xdr, void *ptr, size_t len) if (unlikely(!p)) return -EBADMSG; xdr_decode_opaque_fixed(p, ptr, len); - return len; + return 0; } /** diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/fixed_length_opaque.j2 index 8b4ff08c49e5..bdc7bd24ffb1 100644 --- a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/fixed_length_opaque.j2 +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/fixed_length_opaque.j2 @@ -13,5 +13,5 @@ xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr {% if annotate %} /* (fixed-length opaque) */ {% endif %} - return xdr_stream_decode_opaque_fixed(xdr, ptr, {{ size }}) >= 0; + return xdr_stream_decode_opaque_fixed(xdr, ptr, {{ size }}) == 0; }; From 832738e4b325b742940761e10487403f9aad13e8 Mon Sep 17 00:00:00 2001 From: Sergey Bashirov Date: Mon, 21 Jul 2025 17:48:55 +0300 Subject: [PATCH 1891/2711] NFSD: Rework encoding and decoding of nfsd4_deviceid Compilers may optimize the layout of C structures, so we should not rely on sizeof struct and memcpy to encode and decode XDR structures. The byte order of the fields should also be taken into account. This patch adds the correct functions to handle the deviceid4 structure and removes the pad field, which is currently not used by NFSD, from the runtime state. The server's byte order is preserved because the deviceid4 blob on the wire is only used as a cookie by the client. Signed-off-by: Sergey Bashirov Signed-off-by: Chuck Lever --- fs/nfsd/blocklayoutxdr.c | 7 ++----- fs/nfsd/flexfilelayoutxdr.c | 3 +-- fs/nfsd/nfs4layouts.c | 1 - fs/nfsd/nfs4xdr.c | 14 +------------- fs/nfsd/xdr4.h | 36 +++++++++++++++++++++++++++++++++++- 5 files changed, 39 insertions(+), 22 deletions(-) diff --git a/fs/nfsd/blocklayoutxdr.c b/fs/nfsd/blocklayoutxdr.c index bcf21fde9120..18de37ff2891 100644 --- a/fs/nfsd/blocklayoutxdr.c +++ b/fs/nfsd/blocklayoutxdr.c @@ -29,8 +29,7 @@ nfsd4_block_encode_layoutget(struct xdr_stream *xdr, *p++ = cpu_to_be32(len); *p++ = cpu_to_be32(1); /* we always return a single extent */ - p = xdr_encode_opaque_fixed(p, &b->vol_id, - sizeof(struct nfsd4_deviceid)); + p = svcxdr_encode_deviceid4(p, &b->vol_id); p = xdr_encode_hyper(p, b->foff); p = xdr_encode_hyper(p, b->len); p = xdr_encode_hyper(p, b->soff); @@ -156,9 +155,7 @@ nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, for (i = 0; i < nr_iomaps; i++) { struct pnfs_block_extent bex; - memcpy(&bex.vol_id, p, sizeof(struct nfsd4_deviceid)); - p += XDR_QUADLEN(sizeof(struct nfsd4_deviceid)); - + p = svcxdr_decode_deviceid4(p, &bex.vol_id); p = xdr_decode_hyper(p, &bex.foff); if (bex.foff & (block_size - 1)) { goto fail; diff --git a/fs/nfsd/flexfilelayoutxdr.c b/fs/nfsd/flexfilelayoutxdr.c index aeb71c10ff1b..f9f7e38cba13 100644 --- a/fs/nfsd/flexfilelayoutxdr.c +++ b/fs/nfsd/flexfilelayoutxdr.c @@ -54,8 +54,7 @@ nfsd4_ff_encode_layoutget(struct xdr_stream *xdr, *p++ = cpu_to_be32(1); /* single mirror */ *p++ = cpu_to_be32(1); /* single data server */ - p = xdr_encode_opaque_fixed(p, &fl->deviceid, - sizeof(struct nfsd4_deviceid)); + p = svcxdr_encode_deviceid4(p, &fl->deviceid); *p++ = cpu_to_be32(1); /* efficiency */ diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index aea905fcaf87..683bd1130afe 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -120,7 +120,6 @@ nfsd4_set_deviceid(struct nfsd4_deviceid *id, const struct svc_fh *fhp, id->fsid_idx = fhp->fh_export->ex_devid_map->idx; id->generation = device_generation; - id->pad = 0; return 0; } diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index ea91bad4eee2..2acc9abee668 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -587,18 +587,6 @@ nfsd4_decode_state_owner4(struct nfsd4_compoundargs *argp, } #ifdef CONFIG_NFSD_PNFS -static __be32 -nfsd4_decode_deviceid4(struct nfsd4_compoundargs *argp, - struct nfsd4_deviceid *devid) -{ - __be32 *p; - - p = xdr_inline_decode(argp->xdr, NFS4_DEVICEID4_SIZE); - if (!p) - return nfserr_bad_xdr; - memcpy(devid, p, sizeof(*devid)); - return nfs_ok; -} static __be32 nfsd4_decode_layoutupdate4(struct nfsd4_compoundargs *argp, @@ -1783,7 +1771,7 @@ nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, __be32 status; memset(gdev, 0, sizeof(*gdev)); - status = nfsd4_decode_deviceid4(argp, &gdev->gd_devid); + status = nfsd4_decode_deviceid4(argp->xdr, &gdev->gd_devid); if (status) return status; if (xdr_stream_decode_u32(argp->xdr, &gdev->gd_layout_type) < 0) diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index a23bc56051ca..e65b552bf5f5 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -595,9 +595,43 @@ struct nfsd4_reclaim_complete { struct nfsd4_deviceid { u64 fsid_idx; u32 generation; - u32 pad; }; +static inline __be32 * +svcxdr_encode_deviceid4(__be32 *p, const struct nfsd4_deviceid *devid) +{ + __be64 *q = (__be64 *)p; + + *q = (__force __be64)devid->fsid_idx; + p += 2; + *p++ = (__force __be32)devid->generation; + *p++ = xdr_zero; + return p; +} + +static inline __be32 * +svcxdr_decode_deviceid4(__be32 *p, struct nfsd4_deviceid *devid) +{ + __be64 *q = (__be64 *)p; + + devid->fsid_idx = (__force u64)(*q); + p += 2; + devid->generation = (__force u32)(*p++); + p++; /* NFSD does not use the remaining octets */ + return p; +} + +static inline __be32 +nfsd4_decode_deviceid4(struct xdr_stream *xdr, struct nfsd4_deviceid *devid) +{ + __be32 *p = xdr_inline_decode(xdr, NFS4_DEVICEID4_SIZE); + + if (unlikely(!p)) + return nfserr_bad_xdr; + svcxdr_decode_deviceid4(p, devid); + return nfs_ok; +} + struct nfsd4_layout_seg { u32 iomode; u64 offset; From 274365a51d88658fb51cca637ba579034e90a799 Mon Sep 17 00:00:00 2001 From: Sergey Bashirov Date: Tue, 15 Jul 2025 18:32:18 +0300 Subject: [PATCH 1892/2711] NFSD: Minor cleanup in layoutcommit processing Remove dprintk in nfsd4_layoutcommit. These are not needed in day to day usage, and the information is also available in Wireshark when capturing NFS traffic. Reviewed-by: Christoph Hellwig Signed-off-by: Sergey Bashirov Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 71b428efcbb5..04b8856d0615 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2492,18 +2492,12 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, inode = d_inode(current_fh->fh_dentry); nfserr = nfserr_inval; - if (new_size <= seg->offset) { - dprintk("pnfsd: last write before layout segment\n"); + if (new_size <= seg->offset) goto out; - } - if (new_size > seg->offset + seg->length) { - dprintk("pnfsd: last write beyond layout segment\n"); + if (new_size > seg->offset + seg->length) goto out; - } - if (!lcp->lc_newoffset && new_size > i_size_read(inode)) { - dprintk("pnfsd: layoutcommit beyond EOF\n"); + if (!lcp->lc_newoffset && new_size > i_size_read(inode)) goto out; - } nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lcp->lc_sid, false, lcp->lc_layout_type, From 6bf1be3399e2635805074954011cb55745569788 Mon Sep 17 00:00:00 2001 From: Sergey Bashirov Date: Tue, 15 Jul 2025 18:32:20 +0300 Subject: [PATCH 1893/2711] NFSD: Minor cleanup in layoutcommit decoding Use the appropriate xdr function to decode the lc_newoffset field, which is a boolean value. See RFC 8881, section 18.42.1. Signed-off-by: Sergey Bashirov Reviewed-by: Christoph Hellwig Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2acc9abee668..cbbb61fcdd49 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1802,7 +1802,7 @@ nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, status = nfsd4_decode_stateid4(argp, &lcp->lc_sid); if (status) return status; - if (xdr_stream_decode_u32(argp->xdr, &lcp->lc_newoffset) < 0) + if (xdr_stream_decode_bool(argp->xdr, &lcp->lc_newoffset) < 0) return nfserr_bad_xdr; if (lcp->lc_newoffset) { if (xdr_stream_decode_u64(argp->xdr, &lcp->lc_last_wr) < 0) From f963cf2b91a30b5614c514f3ad53ca124cb65280 Mon Sep 17 00:00:00 2001 From: Sergey Bashirov Date: Mon, 21 Jul 2025 21:40:55 +0300 Subject: [PATCH 1894/2711] NFSD: Implement large extent array support in pNFS When pNFS client in the block or scsi layout mode sends layoutcommit to MDS, a variable length array of modified extents is supplied within the request. This patch allows the server to accept such extent arrays if they do not fit within single memory page. The issue can be reproduced when writing to a 1GB file using FIO with O_DIRECT, 4K block and large I/O depth without preallocation of the file. In this case, the server returns NFSERR_BADXDR to the client. Co-developed-by: Konstantin Evtushenko Signed-off-by: Konstantin Evtushenko Signed-off-by: Sergey Bashirov Reviewed-by: Jeff Layton Reviewed-by: Christoph Hellwig Signed-off-by: Chuck Lever --- fs/nfsd/blocklayout.c | 20 ++++++---- fs/nfsd/blocklayoutxdr.c | 83 +++++++++++++++++++++++++++------------- fs/nfsd/blocklayoutxdr.h | 4 +- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfs4xdr.c | 11 +++--- fs/nfsd/pnfs.h | 1 + fs/nfsd/xdr4.h | 3 +- 7 files changed, 78 insertions(+), 46 deletions(-) diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c index 19078a043e85..4c936132eb44 100644 --- a/fs/nfsd/blocklayout.c +++ b/fs/nfsd/blocklayout.c @@ -173,16 +173,18 @@ nfsd4_block_proc_getdeviceinfo(struct super_block *sb, } static __be32 -nfsd4_block_proc_layoutcommit(struct inode *inode, +nfsd4_block_proc_layoutcommit(struct inode *inode, struct svc_rqst *rqstp, struct nfsd4_layoutcommit *lcp) { struct iomap *iomaps; int nr_iomaps; __be32 nfserr; - nfserr = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout, - lcp->lc_up_len, &iomaps, &nr_iomaps, - i_blocksize(inode)); + rqstp->rq_arg = lcp->lc_up_layout; + svcxdr_init_decode(rqstp); + + nfserr = nfsd4_block_decode_layoutupdate(&rqstp->rq_arg_stream, + &iomaps, &nr_iomaps, i_blocksize(inode)); if (nfserr != nfs_ok) return nfserr; @@ -313,16 +315,18 @@ nfsd4_scsi_proc_getdeviceinfo(struct super_block *sb, return nfserrno(nfsd4_block_get_device_info_scsi(sb, clp, gdp)); } static __be32 -nfsd4_scsi_proc_layoutcommit(struct inode *inode, +nfsd4_scsi_proc_layoutcommit(struct inode *inode, struct svc_rqst *rqstp, struct nfsd4_layoutcommit *lcp) { struct iomap *iomaps; int nr_iomaps; __be32 nfserr; - nfserr = nfsd4_scsi_decode_layoutupdate(lcp->lc_up_layout, - lcp->lc_up_len, &iomaps, &nr_iomaps, - i_blocksize(inode)); + rqstp->rq_arg = lcp->lc_up_layout; + svcxdr_init_decode(rqstp); + + nfserr = nfsd4_scsi_decode_layoutupdate(&rqstp->rq_arg_stream, + &iomaps, &nr_iomaps, i_blocksize(inode)); if (nfserr != nfs_ok) return nfserr; diff --git a/fs/nfsd/blocklayoutxdr.c b/fs/nfsd/blocklayoutxdr.c index 18de37ff2891..e50afe340737 100644 --- a/fs/nfsd/blocklayoutxdr.c +++ b/fs/nfsd/blocklayoutxdr.c @@ -113,8 +113,7 @@ nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr, /** * nfsd4_block_decode_layoutupdate - decode the block layout extent array - * @p: pointer to the xdr data - * @len: number of bytes to decode + * @xdr: subbuf set to the encoded array * @iomapp: pointer to store the decoded extent array * @nr_iomapsp: pointer to store the number of extents * @block_size: alignment of extent offset and length @@ -127,25 +126,24 @@ nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr, * * Return values: * %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid - * %nfserr_bad_xdr: The encoded array in @p is invalid + * %nfserr_bad_xdr: The encoded array in @xdr is invalid * %nfserr_inval: An unaligned extent found * %nfserr_delay: Failed to allocate memory for @iomapp */ __be32 -nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, +nfsd4_block_decode_layoutupdate(struct xdr_stream *xdr, struct iomap **iomapp, int *nr_iomapsp, u32 block_size) { struct iomap *iomaps; - u32 nr_iomaps, i; + u32 nr_iomaps, expected, len, i; + __be32 nfserr; - if (len < sizeof(u32)) - return nfserr_bad_xdr; - len -= sizeof(u32); - if (len % PNFS_BLOCK_EXTENT_SIZE) + if (xdr_stream_decode_u32(xdr, &nr_iomaps)) return nfserr_bad_xdr; - nr_iomaps = be32_to_cpup(p++); - if (nr_iomaps != len / PNFS_BLOCK_EXTENT_SIZE) + len = sizeof(__be32) + xdr_stream_remaining(xdr); + expected = sizeof(__be32) + nr_iomaps * PNFS_BLOCK_EXTENT_SIZE; + if (len != expected) return nfserr_bad_xdr; iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL); @@ -155,21 +153,44 @@ nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, for (i = 0; i < nr_iomaps; i++) { struct pnfs_block_extent bex; - p = svcxdr_decode_deviceid4(p, &bex.vol_id); - p = xdr_decode_hyper(p, &bex.foff); + if (nfsd4_decode_deviceid4(xdr, &bex.vol_id)) { + nfserr = nfserr_bad_xdr; + goto fail; + } + + if (xdr_stream_decode_u64(xdr, &bex.foff)) { + nfserr = nfserr_bad_xdr; + goto fail; + } if (bex.foff & (block_size - 1)) { + nfserr = nfserr_inval; + goto fail; + } + + if (xdr_stream_decode_u64(xdr, &bex.len)) { + nfserr = nfserr_bad_xdr; goto fail; } - p = xdr_decode_hyper(p, &bex.len); if (bex.len & (block_size - 1)) { + nfserr = nfserr_inval; + goto fail; + } + + if (xdr_stream_decode_u64(xdr, &bex.soff)) { + nfserr = nfserr_bad_xdr; goto fail; } - p = xdr_decode_hyper(p, &bex.soff); if (bex.soff & (block_size - 1)) { + nfserr = nfserr_inval; + goto fail; + } + + if (xdr_stream_decode_u32(xdr, &bex.es)) { + nfserr = nfserr_bad_xdr; goto fail; } - bex.es = be32_to_cpup(p++); if (bex.es != PNFS_BLOCK_READWRITE_DATA) { + nfserr = nfserr_inval; goto fail; } @@ -182,13 +203,12 @@ nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, return nfs_ok; fail: kfree(iomaps); - return nfserr_inval; + return nfserr; } /** * nfsd4_scsi_decode_layoutupdate - decode the scsi layout extent array - * @p: pointer to the xdr data - * @len: number of bytes to decode + * @xdr: subbuf set to the encoded array * @iomapp: pointer to store the decoded extent array * @nr_iomapsp: pointer to store the number of extents * @block_size: alignment of extent offset and length @@ -200,21 +220,22 @@ fail: * * Return values: * %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid - * %nfserr_bad_xdr: The encoded array in @p is invalid + * %nfserr_bad_xdr: The encoded array in @xdr is invalid * %nfserr_inval: An unaligned extent found * %nfserr_delay: Failed to allocate memory for @iomapp */ __be32 -nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, +nfsd4_scsi_decode_layoutupdate(struct xdr_stream *xdr, struct iomap **iomapp, int *nr_iomapsp, u32 block_size) { struct iomap *iomaps; - u32 nr_iomaps, expected, i; + u32 nr_iomaps, expected, len, i; + __be32 nfserr; - if (len < sizeof(u32)) + if (xdr_stream_decode_u32(xdr, &nr_iomaps)) return nfserr_bad_xdr; - nr_iomaps = be32_to_cpup(p++); + len = sizeof(__be32) + xdr_stream_remaining(xdr); expected = sizeof(__be32) + nr_iomaps * PNFS_SCSI_RANGE_SIZE; if (len != expected) return nfserr_bad_xdr; @@ -226,14 +247,22 @@ nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, for (i = 0; i < nr_iomaps; i++) { u64 val; - p = xdr_decode_hyper(p, &val); + if (xdr_stream_decode_u64(xdr, &val)) { + nfserr = nfserr_bad_xdr; + goto fail; + } if (val & (block_size - 1)) { + nfserr = nfserr_inval; goto fail; } iomaps[i].offset = val; - p = xdr_decode_hyper(p, &val); + if (xdr_stream_decode_u64(xdr, &val)) { + nfserr = nfserr_bad_xdr; + goto fail; + } if (val & (block_size - 1)) { + nfserr = nfserr_inval; goto fail; } iomaps[i].length = val; @@ -244,5 +273,5 @@ nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, return nfs_ok; fail: kfree(iomaps); - return nfserr_inval; + return nfserr; } diff --git a/fs/nfsd/blocklayoutxdr.h b/fs/nfsd/blocklayoutxdr.h index 15b3569f3d9a..7d25ef689671 100644 --- a/fs/nfsd/blocklayoutxdr.h +++ b/fs/nfsd/blocklayoutxdr.h @@ -54,9 +54,9 @@ __be32 nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr, const struct nfsd4_getdeviceinfo *gdp); __be32 nfsd4_block_encode_layoutget(struct xdr_stream *xdr, const struct nfsd4_layoutget *lgp); -__be32 nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, +__be32 nfsd4_block_decode_layoutupdate(struct xdr_stream *xdr, struct iomap **iomapp, int *nr_iomapsp, u32 block_size); -__be32 nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, +__be32 nfsd4_scsi_decode_layoutupdate(struct xdr_stream *xdr, struct iomap **iomapp, int *nr_iomapsp, u32 block_size); #endif /* _NFSD_BLOCKLAYOUTXDR_H */ diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 04b8856d0615..656b2e7d8840 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2520,7 +2520,7 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, lcp->lc_size_chg = false; } - nfserr = ops->proc_layoutcommit(inode, lcp); + nfserr = ops->proc_layoutcommit(inode, rqstp, lcp); nfs4_put_stid(&ls->ls_stid); out: return nfserr; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index cbbb61fcdd49..8b68f74a8cf0 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -592,6 +592,8 @@ static __be32 nfsd4_decode_layoutupdate4(struct nfsd4_compoundargs *argp, struct nfsd4_layoutcommit *lcp) { + u32 len; + if (xdr_stream_decode_u32(argp->xdr, &lcp->lc_layout_type) < 0) return nfserr_bad_xdr; if (lcp->lc_layout_type < LAYOUT_NFSV4_1_FILES) @@ -599,13 +601,10 @@ nfsd4_decode_layoutupdate4(struct nfsd4_compoundargs *argp, if (lcp->lc_layout_type >= LAYOUT_TYPE_MAX) return nfserr_bad_xdr; - if (xdr_stream_decode_u32(argp->xdr, &lcp->lc_up_len) < 0) + if (xdr_stream_decode_u32(argp->xdr, &len) < 0) + return nfserr_bad_xdr; + if (!xdr_stream_subsegment(argp->xdr, &lcp->lc_up_layout, len)) return nfserr_bad_xdr; - if (lcp->lc_up_len > 0) { - lcp->lc_up_layout = xdr_inline_decode(argp->xdr, lcp->lc_up_len); - if (!lcp->lc_up_layout) - return nfserr_bad_xdr; - } return nfs_ok; } diff --git a/fs/nfsd/pnfs.h b/fs/nfsd/pnfs.h index 925817f66917..dfd411d1f363 100644 --- a/fs/nfsd/pnfs.h +++ b/fs/nfsd/pnfs.h @@ -35,6 +35,7 @@ struct nfsd4_layout_ops { const struct nfsd4_layoutget *lgp); __be32 (*proc_layoutcommit)(struct inode *inode, + struct svc_rqst *rqstp, struct nfsd4_layoutcommit *lcp); void (*fence_client)(struct nfs4_layout_stateid *ls, diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index e65b552bf5f5..d4b48602b2b0 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -664,8 +664,7 @@ struct nfsd4_layoutcommit { u64 lc_last_wr; /* request */ struct timespec64 lc_mtime; /* request */ u32 lc_layout_type; /* request */ - u32 lc_up_len; /* layout length */ - void *lc_up_layout; /* decoded by callback */ + struct xdr_buf lc_up_layout; /* decoded by callback */ bool lc_size_chg; /* response */ u64 lc_newsize; /* response */ }; From d68886bae76a4b9b3484d23e5b7df086f940fa38 Mon Sep 17 00:00:00 2001 From: Sergey Bashirov Date: Mon, 21 Jul 2025 21:40:56 +0300 Subject: [PATCH 1895/2711] NFSD: Fix last write offset handling in layoutcommit The data type of loca_last_write_offset is newoffset4 and is switched on a boolean value, no_newoffset, that indicates if a previous write occurred or not. If no_newoffset is FALSE, an offset is not given. This means that client does not try to update the file size. Thus, server should not try to calculate new file size and check if it fits into the segment range. See RFC 8881, section 12.5.4.2. Sometimes the current incorrect logic may cause clients to hang when trying to sync an inode. If layoutcommit fails, the client marks the inode as dirty again. Fixes: 9cf514ccfacb ("nfsd: implement pNFS operations") Cc: stable@vger.kernel.org Co-developed-by: Konstantin Evtushenko Signed-off-by: Konstantin Evtushenko Signed-off-by: Sergey Bashirov Reviewed-by: Christoph Hellwig Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/blocklayout.c | 5 ++--- fs/nfsd/nfs4proc.c | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c index 4c936132eb44..0822d8a119c6 100644 --- a/fs/nfsd/blocklayout.c +++ b/fs/nfsd/blocklayout.c @@ -118,7 +118,6 @@ nfsd4_block_commit_blocks(struct inode *inode, struct nfsd4_layoutcommit *lcp, struct iomap *iomaps, int nr_iomaps) { struct timespec64 mtime = inode_get_mtime(inode); - loff_t new_size = lcp->lc_last_wr + 1; struct iattr iattr = { .ia_valid = 0 }; int error; @@ -128,9 +127,9 @@ nfsd4_block_commit_blocks(struct inode *inode, struct nfsd4_layoutcommit *lcp, iattr.ia_valid |= ATTR_ATIME | ATTR_CTIME | ATTR_MTIME; iattr.ia_atime = iattr.ia_ctime = iattr.ia_mtime = lcp->lc_mtime; - if (new_size > i_size_read(inode)) { + if (lcp->lc_size_chg) { iattr.ia_valid |= ATTR_SIZE; - iattr.ia_size = new_size; + iattr.ia_size = lcp->lc_newsize; } error = inode->i_sb->s_export_op->commit_blocks(inode, iomaps, diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 656b2e7d8840..7043fc475458 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2475,7 +2475,6 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, const struct nfsd4_layout_seg *seg = &lcp->lc_seg; struct svc_fh *current_fh = &cstate->current_fh; const struct nfsd4_layout_ops *ops; - loff_t new_size = lcp->lc_last_wr + 1; struct inode *inode; struct nfs4_layout_stateid *ls; __be32 nfserr; @@ -2491,13 +2490,21 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, goto out; inode = d_inode(current_fh->fh_dentry); - nfserr = nfserr_inval; - if (new_size <= seg->offset) - goto out; - if (new_size > seg->offset + seg->length) - goto out; - if (!lcp->lc_newoffset && new_size > i_size_read(inode)) - goto out; + lcp->lc_size_chg = false; + if (lcp->lc_newoffset) { + loff_t new_size = lcp->lc_last_wr + 1; + + nfserr = nfserr_inval; + if (new_size <= seg->offset) + goto out; + if (new_size > seg->offset + seg->length) + goto out; + + if (new_size > i_size_read(inode)) { + lcp->lc_size_chg = true; + lcp->lc_newsize = new_size; + } + } nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lcp->lc_sid, false, lcp->lc_layout_type, @@ -2513,13 +2520,6 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, /* LAYOUTCOMMIT does not require any serialization */ mutex_unlock(&ls->ls_mutex); - if (new_size > i_size_read(inode)) { - lcp->lc_size_chg = true; - lcp->lc_newsize = new_size; - } else { - lcp->lc_size_chg = false; - } - nfserr = ops->proc_layoutcommit(inode, rqstp, lcp); nfs4_put_stid(&ls->ls_stid); out: From 2990b5a47984c27873d165de9e88099deee95c8d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2025 09:24:30 -0400 Subject: [PATCH 1896/2711] nfsd: fix assignment of ia_ctime.tv_nsec on delegated mtime update The ia_ctime.tv_nsec field should be set to modify.nseconds. Fixes: 7e13f4f8d27d ("nfsd: handle delegated timestamps in SETATTR") Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 8b68f74a8cf0..52033e2d603e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -538,7 +538,7 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen, iattr->ia_mtime.tv_sec = modify.seconds; iattr->ia_mtime.tv_nsec = modify.nseconds; iattr->ia_ctime.tv_sec = modify.seconds; - iattr->ia_ctime.tv_nsec = modify.seconds; + iattr->ia_ctime.tv_nsec = modify.nseconds; iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME | ATTR_MTIME_SET | ATTR_DELEG; } From 5affb498e70bba3053b835c478a199bf92c99c4d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2025 09:24:31 -0400 Subject: [PATCH 1897/2711] nfsd: ignore ATTR_DELEG when checking ia_valid before notify_change() If the only flag left is ATTR_DELEG, then there are no changes to be made. Fixes: 7e13f4f8d27d ("nfsd: handle delegated timestamps in SETATTR") Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/vfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index edf050766e57..3cd3b9e069f4 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -467,7 +467,7 @@ static int __nfsd_setattr(struct dentry *dentry, struct iattr *iap) return 0; } - if (!iap->ia_valid) + if ((iap->ia_valid & ~ATTR_DELEG) == 0) return 0; /* From afc5b36e29b95fbd31a60b9630d148857e5e513d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2025 09:24:32 -0400 Subject: [PATCH 1898/2711] vfs: add ATTR_CTIME_SET flag When ATTR_ATIME_SET and ATTR_MTIME_SET are set in the ia_valid mask, the notify_change() logic takes that to mean that the request should set those values explicitly, and not override them with "now". With the advent of delegated timestamps, similar functionality is needed for the ctime. Add a ATTR_CTIME_SET flag, and use that to indicate that the ctime should be accepted as-is. Also, clean up the if statements to eliminate the extra negatives. In setattr_copy() and setattr_copy_mgtime() use inode_set_ctime_deleg() when ATTR_CTIME_SET is set, instead of basing the decision on ATTR_DELEG. Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/attr.c | 44 +++++++++++++++++++------------------------- include/linux/fs.h | 1 + 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/fs/attr.c b/fs/attr.c index 5425c1dbbff9..795f231d00e8 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -286,20 +286,12 @@ static void setattr_copy_mgtime(struct inode *inode, const struct iattr *attr) unsigned int ia_valid = attr->ia_valid; struct timespec64 now; - if (ia_valid & ATTR_CTIME) { - /* - * In the case of an update for a write delegation, we must respect - * the value in ia_ctime and not use the current time. - */ - if (ia_valid & ATTR_DELEG) - now = inode_set_ctime_deleg(inode, attr->ia_ctime); - else - now = inode_set_ctime_current(inode); - } else { - /* If ATTR_CTIME isn't set, then ATTR_MTIME shouldn't be either. */ - WARN_ON_ONCE(ia_valid & ATTR_MTIME); + if (ia_valid & ATTR_CTIME_SET) + now = inode_set_ctime_deleg(inode, attr->ia_ctime); + else if (ia_valid & ATTR_CTIME) + now = inode_set_ctime_current(inode); + else now = current_time(inode); - } if (ia_valid & ATTR_ATIME_SET) inode_set_atime_to_ts(inode, attr->ia_atime); @@ -359,12 +351,11 @@ void setattr_copy(struct mnt_idmap *idmap, struct inode *inode, inode_set_atime_to_ts(inode, attr->ia_atime); if (ia_valid & ATTR_MTIME) inode_set_mtime_to_ts(inode, attr->ia_mtime); - if (ia_valid & ATTR_CTIME) { - if (ia_valid & ATTR_DELEG) - inode_set_ctime_deleg(inode, attr->ia_ctime); - else - inode_set_ctime_to_ts(inode, attr->ia_ctime); - } + + if (ia_valid & ATTR_CTIME_SET) + inode_set_ctime_deleg(inode, attr->ia_ctime); + else if (ia_valid & ATTR_CTIME) + inode_set_ctime_to_ts(inode, attr->ia_ctime); } EXPORT_SYMBOL(setattr_copy); @@ -463,15 +454,18 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry, now = current_time(inode); - attr->ia_ctime = now; - if (!(ia_valid & ATTR_ATIME_SET)) - attr->ia_atime = now; - else + if (ia_valid & ATTR_ATIME_SET) attr->ia_atime = timestamp_truncate(attr->ia_atime, inode); - if (!(ia_valid & ATTR_MTIME_SET)) - attr->ia_mtime = now; else + attr->ia_atime = now; + if (ia_valid & ATTR_CTIME_SET) + attr->ia_ctime = timestamp_truncate(attr->ia_ctime, inode); + else + attr->ia_ctime = now; + if (ia_valid & ATTR_MTIME_SET) attr->ia_mtime = timestamp_truncate(attr->ia_mtime, inode); + else + attr->ia_mtime = now; if (ia_valid & ATTR_KILL_PRIV) { error = security_inode_need_killpriv(dentry); diff --git a/include/linux/fs.h b/include/linux/fs.h index 601d036a6c78..74f2bfc51926 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -238,6 +238,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define ATTR_ATIME_SET (1 << 7) #define ATTR_MTIME_SET (1 << 8) #define ATTR_FORCE (1 << 9) /* Not a change, but a change it */ +#define ATTR_CTIME_SET (1 << 10) #define ATTR_KILL_SUID (1 << 11) #define ATTR_KILL_SGID (1 << 12) #define ATTR_FILE (1 << 13) From c066ff58e5d6e5d7400e5fda0c33f95b8c37dd02 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2025 09:24:33 -0400 Subject: [PATCH 1899/2711] nfsd: use ATTR_CTIME_SET for delegated ctime updates Ensure that notify_change() doesn't clobber a delegated ctime update with current_time() by setting ATTR_CTIME_SET for those updates. Don't bother setting the timestamps in cb_getattr_update_times() in the non-delegated case. notify_change() will do that itself. Fixes: 7e13f4f8d27d ("nfsd: handle delegated timestamps in SETATTR") Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 6 +++--- fs/nfsd/nfs4xdr.c | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 88c347957da5..77eea2ad93cc 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -9167,7 +9167,6 @@ static bool set_cb_time(struct timespec64 *cb, const struct timespec64 *orig, static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation *dp) { struct inode *inode = d_inode(dentry); - struct timespec64 now = current_time(inode); struct nfs4_cb_fattr *ncf = &dp->dl_cb_fattr; struct iattr attrs = { }; int ret; @@ -9175,6 +9174,7 @@ static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation if (deleg_attrs_deleg(dp->dl_type)) { struct timespec64 atime = inode_get_atime(inode); struct timespec64 mtime = inode_get_mtime(inode); + struct timespec64 now = current_time(inode); attrs.ia_atime = ncf->ncf_cb_atime; attrs.ia_mtime = ncf->ncf_cb_mtime; @@ -9183,12 +9183,12 @@ static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation attrs.ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; if (set_cb_time(&attrs.ia_mtime, &mtime, &now)) { - attrs.ia_valid |= ATTR_CTIME | ATTR_MTIME | ATTR_MTIME_SET; + attrs.ia_valid |= ATTR_CTIME | ATTR_CTIME_SET | + ATTR_MTIME | ATTR_MTIME_SET; attrs.ia_ctime = attrs.ia_mtime; } } else { attrs.ia_valid |= ATTR_MTIME | ATTR_CTIME; - attrs.ia_mtime = attrs.ia_ctime = now; } if (!attrs.ia_valid) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 52033e2d603e..c0a3c6a7c8bb 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -539,7 +539,8 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen, iattr->ia_mtime.tv_nsec = modify.nseconds; iattr->ia_ctime.tv_sec = modify.seconds; iattr->ia_ctime.tv_nsec = modify.nseconds; - iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME | ATTR_MTIME_SET | ATTR_DELEG; + iattr->ia_valid |= ATTR_CTIME | ATTR_CTIME_SET | + ATTR_MTIME | ATTR_MTIME_SET | ATTR_DELEG; } /* request sanity: did attrlist4 contain the expected number of words? */ From 7663e963a51122792811811c8119fd55c9ab254a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2025 09:24:34 -0400 Subject: [PATCH 1900/2711] nfsd: track original timestamps in nfs4_delegation As Trond points out [1], the "original time" mentioned in RFC 9754 refers to the timestamps on the files at the time that the delegation was granted, and not the current timestamp of the file on the server. Store the current timestamps for the file in the nfs4_delegation when granting one. Add STATX_ATIME and STATX_MTIME to the request mask in nfs4_delegation_stat(). When granting OPEN_DELEGATE_READ_ATTRS_DELEG, do a nfs4_delegation_stat() and save the correct atime. If the stat() fails for any reason, fall back to granting a normal read deleg. [1]: https://lore.kernel.org/linux-nfs/47a4e40310e797f21b5137e847b06bb203d99e66.camel@kernel.org/ Fixes: 7e13f4f8d27d ("nfsd: handle delegated timestamps in SETATTR") Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 11 ++++++++--- fs/nfsd/state.h | 5 +++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 77eea2ad93cc..8737b721daf3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -6157,7 +6157,8 @@ nfs4_delegation_stat(struct nfs4_delegation *dp, struct svc_fh *currentfh, path.dentry = file_dentry(nf->nf_file); rc = vfs_getattr(&path, stat, - (STATX_MODE | STATX_SIZE | STATX_CTIME | STATX_CHANGE_COOKIE), + STATX_MODE | STATX_SIZE | STATX_ATIME | + STATX_MTIME | STATX_CTIME | STATX_CHANGE_COOKIE, AT_STATX_SYNC_AS_STAT); nfsd_file_put(nf); @@ -6274,10 +6275,14 @@ nfs4_open_delegation(struct svc_rqst *rqstp, struct nfsd4_open *open, OPEN_DELEGATE_WRITE; dp->dl_cb_fattr.ncf_cur_fsize = stat.size; dp->dl_cb_fattr.ncf_initial_cinfo = nfsd4_change_attribute(&stat); + dp->dl_atime = stat.atime; + dp->dl_ctime = stat.ctime; + dp->dl_mtime = stat.mtime; trace_nfsd_deleg_write(&dp->dl_stid.sc_stateid); } else { - open->op_delegate_type = deleg_ts ? OPEN_DELEGATE_READ_ATTRS_DELEG : - OPEN_DELEGATE_READ; + open->op_delegate_type = deleg_ts && nfs4_delegation_stat(dp, currentfh, &stat) ? + OPEN_DELEGATE_READ_ATTRS_DELEG : OPEN_DELEGATE_READ; + dp->dl_atime = stat.atime; trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid); } nfs4_put_stid(&dp->dl_stid); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 8adc2550129e..ce7c0d129ba3 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -224,6 +224,11 @@ struct nfs4_delegation { /* for CB_GETATTR */ struct nfs4_cb_fattr dl_cb_fattr; + + /* For delegated timestamps */ + struct timespec64 dl_atime; + struct timespec64 dl_mtime; + struct timespec64 dl_ctime; }; static inline bool deleg_is_read(u32 dl_type) From 3952f1cbcbc454b2cb639ddbf165c07068e90371 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2025 09:24:35 -0400 Subject: [PATCH 1901/2711] nfsd: fix SETATTR updates for delegated timestamps SETATTRs containing delegated timestamp updates are currently not being vetted properly. Since we no longer need to compare the timestamps vs. the current timestamps, move the vetting of delegated timestamps wholly into nfsd. Rename the set_cb_time() helper to nfsd4_vet_deleg_time(), and make it non-static. Add a new vet_deleg_attrs() helper that is called from nfsd4_setattr that uses nfsd4_vet_deleg_time() to properly validate the all the timestamps. If the validation indicates that the update should be skipped, unset the appropriate flags in ia_valid. Fixes: 7e13f4f8d27d ("nfsd: handle delegated timestamps in SETATTR") Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 31 ++++++++++++++++++++++++++++++- fs/nfsd/nfs4state.c | 24 +++++++++++------------- fs/nfsd/state.h | 3 +++ 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 7043fc475458..aacd912a5fbe 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1133,6 +1133,33 @@ nfsd4_secinfo_no_name_release(union nfsd4_op_u *u) exp_put(u->secinfo_no_name.sin_exp); } +/* + * Validate that the requested timestamps are within the acceptable range. If + * timestamp appears to be in the future, then it will be clamped to + * current_time(). + */ +static void +vet_deleg_attrs(struct nfsd4_setattr *setattr, struct nfs4_delegation *dp) +{ + struct timespec64 now = current_time(dp->dl_stid.sc_file->fi_inode); + struct iattr *iattr = &setattr->sa_iattr; + + if ((setattr->sa_bmval[2] & FATTR4_WORD2_TIME_DELEG_ACCESS) && + !nfsd4_vet_deleg_time(&iattr->ia_atime, &dp->dl_atime, &now)) + iattr->ia_valid &= ~(ATTR_ATIME | ATTR_ATIME_SET); + + if (setattr->sa_bmval[2] & FATTR4_WORD2_TIME_DELEG_MODIFY) { + if (nfsd4_vet_deleg_time(&iattr->ia_mtime, &dp->dl_mtime, &now)) { + iattr->ia_ctime = iattr->ia_mtime; + if (!nfsd4_vet_deleg_time(&iattr->ia_ctime, &dp->dl_ctime, &now)) + iattr->ia_valid &= ~(ATTR_CTIME | ATTR_CTIME_SET); + } else { + iattr->ia_valid &= ~(ATTR_CTIME | ATTR_CTIME_SET | + ATTR_MTIME | ATTR_MTIME_SET); + } + } +} + static __be32 nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) @@ -1170,8 +1197,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfs4_delegation *dp = delegstateid(st); /* Only for *_ATTRS_DELEG flavors */ - if (deleg_attrs_deleg(dp->dl_type)) + if (deleg_attrs_deleg(dp->dl_type)) { + vet_deleg_attrs(setattr, dp); status = nfs_ok; + } } } if (st) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 8737b721daf3..f2fd0cbe256b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -9135,25 +9135,25 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, } /** - * set_cb_time - vet and set the timespec for a cb_getattr update - * @cb: timestamp from the CB_GETATTR response + * nfsd4_vet_deleg_time - vet and set the timespec for a delegated timestamp update + * @req: timestamp from the client * @orig: original timestamp in the inode * @now: current time * - * Given a timestamp in a CB_GETATTR response, check it against the + * Given a timestamp from the client response, check it against the * current timestamp in the inode and the current time. Returns true * if the inode's timestamp needs to be updated, and false otherwise. - * @cb may also be changed if the timestamp needs to be clamped. + * @req may also be changed if the timestamp needs to be clamped. */ -static bool set_cb_time(struct timespec64 *cb, const struct timespec64 *orig, - const struct timespec64 *now) +bool nfsd4_vet_deleg_time(struct timespec64 *req, const struct timespec64 *orig, + const struct timespec64 *now) { /* * "When the time presented is before the original time, then the * update is ignored." Also no need to update if there is no change. */ - if (timespec64_compare(cb, orig) <= 0) + if (timespec64_compare(req, orig) <= 0) return false; /* @@ -9161,10 +9161,8 @@ static bool set_cb_time(struct timespec64 *cb, const struct timespec64 *orig, * clamp the new time to the current time, or it may * return NFS4ERR_DELAY to the client, allowing it to retry." */ - if (timespec64_compare(cb, now) > 0) { - /* clamp it */ - *cb = *now; - } + if (timespec64_compare(req, now) > 0) + *req = *now; return true; } @@ -9184,10 +9182,10 @@ static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation attrs.ia_atime = ncf->ncf_cb_atime; attrs.ia_mtime = ncf->ncf_cb_mtime; - if (set_cb_time(&attrs.ia_atime, &atime, &now)) + if (nfsd4_vet_deleg_time(&attrs.ia_atime, &atime, &now)) attrs.ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; - if (set_cb_time(&attrs.ia_mtime, &mtime, &now)) { + if (nfsd4_vet_deleg_time(&attrs.ia_mtime, &mtime, &now)) { attrs.ia_valid |= ATTR_CTIME | ATTR_CTIME_SET | ATTR_MTIME | ATTR_MTIME_SET; attrs.ia_ctime = attrs.ia_mtime; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index ce7c0d129ba3..bf9436cdb93c 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -247,6 +247,9 @@ static inline bool deleg_attrs_deleg(u32 dl_type) dl_type == OPEN_DELEGATE_WRITE_ATTRS_DELEG; } +bool nfsd4_vet_deleg_time(struct timespec64 *cb, const struct timespec64 *orig, + const struct timespec64 *now); + #define cb_to_delegation(cb) \ container_of(cb, struct nfs4_delegation, dl_recall) From b40b1ba37ad5b6099c426765c4bc327c08b390b9 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2025 09:24:36 -0400 Subject: [PATCH 1902/2711] nfsd: fix timestamp updates in CB_GETATTR When updating the local timestamps from CB_GETATTR, the updated values are not being properly vetted. Compare the update times vs. the saved times in the delegation rather than the current times in the inode. Also, ensure that the ctime is properly vetted vs. its original value. Fixes: 6ae30d6eb26b ("nfsd: add support for delegated timestamps") Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4state.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f2fd0cbe256b..205ee8cc6fa2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -9175,20 +9175,19 @@ static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation int ret; if (deleg_attrs_deleg(dp->dl_type)) { - struct timespec64 atime = inode_get_atime(inode); - struct timespec64 mtime = inode_get_mtime(inode); struct timespec64 now = current_time(inode); attrs.ia_atime = ncf->ncf_cb_atime; attrs.ia_mtime = ncf->ncf_cb_mtime; - if (nfsd4_vet_deleg_time(&attrs.ia_atime, &atime, &now)) + if (nfsd4_vet_deleg_time(&attrs.ia_atime, &dp->dl_atime, &now)) attrs.ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; - if (nfsd4_vet_deleg_time(&attrs.ia_mtime, &mtime, &now)) { - attrs.ia_valid |= ATTR_CTIME | ATTR_CTIME_SET | - ATTR_MTIME | ATTR_MTIME_SET; + if (nfsd4_vet_deleg_time(&attrs.ia_mtime, &dp->dl_mtime, &now)) { + attrs.ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; attrs.ia_ctime = attrs.ia_mtime; + if (nfsd4_vet_deleg_time(&attrs.ia_ctime, &dp->dl_ctime, &now)) + attrs.ia_valid |= ATTR_CTIME | ATTR_CTIME_SET; } } else { attrs.ia_valid |= ATTR_MTIME | ATTR_CTIME; From e5e9b24ab8fa9e899d6627123d7d5ba0c317d267 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2025 09:24:37 -0400 Subject: [PATCH 1903/2711] nfsd: freeze c/mtime updates with outstanding WRITE_ATTRS delegation Instead of allowing the ctime to roll backward with a WRITE_ATTRS delegation, set FMODE_NOCMTIME on the file and have it skip mtime and ctime updates. It is possible that the client will never send a SETATTR to set the times before returning the delegation. Add two new bools to struct nfs4_delegation: dl_written: tracks whether the file has been written since the delegation was granted. This is set in the WRITE and LAYOUTCOMMIT handlers. dl_setattr: tracks whether the client has sent at least one valid mtime that can also update the ctime in a SETATTR. When unlocking the lease for the delegation, clear FMODE_NOCMTIME. If the file has been written, but no setattr for the delegated mtime and ctime has been done, update the timestamps to current_time(). Suggested-by: NeilBrown Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 26 ++++++++++++++++++++++++-- fs/nfsd/nfs4state.c | 42 ++++++++++++++++++++++++++++++++++++++++++ fs/nfsd/state.h | 4 +++- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index aacd912a5fbe..bfebe6e25638 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1151,7 +1151,9 @@ vet_deleg_attrs(struct nfsd4_setattr *setattr, struct nfs4_delegation *dp) if (setattr->sa_bmval[2] & FATTR4_WORD2_TIME_DELEG_MODIFY) { if (nfsd4_vet_deleg_time(&iattr->ia_mtime, &dp->dl_mtime, &now)) { iattr->ia_ctime = iattr->ia_mtime; - if (!nfsd4_vet_deleg_time(&iattr->ia_ctime, &dp->dl_ctime, &now)) + if (nfsd4_vet_deleg_time(&iattr->ia_ctime, &dp->dl_ctime, &now)) + dp->dl_setattr = true; + else iattr->ia_valid &= ~(ATTR_CTIME | ATTR_CTIME_SET); } else { iattr->ia_valid &= ~(ATTR_CTIME | ATTR_CTIME_SET | @@ -1238,12 +1240,26 @@ out: return status; } +static void nfsd4_file_mark_deleg_written(struct nfs4_file *fi) +{ + spin_lock(&fi->fi_lock); + if (!list_empty(&fi->fi_delegations)) { + struct nfs4_delegation *dp = list_first_entry(&fi->fi_delegations, + struct nfs4_delegation, dl_perfile); + + if (dp->dl_type == OPEN_DELEGATE_WRITE_ATTRS_DELEG) + dp->dl_written = true; + } + spin_unlock(&fi->fi_lock); +} + static __be32 nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) { struct nfsd4_write *write = &u->write; stateid_t *stateid = &write->wr_stateid; + struct nfs4_stid *stid = NULL; struct nfsd_file *nf = NULL; __be32 status = nfs_ok; unsigned long cnt; @@ -1256,10 +1272,15 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, trace_nfsd_write_start(rqstp, &cstate->current_fh, write->wr_offset, cnt); status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, - stateid, WR_STATE, &nf, NULL); + stateid, WR_STATE, &nf, &stid); if (status) return status; + if (stid) { + nfsd4_file_mark_deleg_written(stid->sc_file); + nfs4_put_stid(stid); + } + write->wr_how_written = write->wr_stable_how; status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf, write->wr_offset, &write->wr_payload, @@ -2550,6 +2571,7 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, mutex_unlock(&ls->ls_mutex); nfserr = ops->proc_layoutcommit(inode, rqstp, lcp); + nfsd4_file_mark_deleg_written(ls->ls_stid.sc_file); nfs4_put_stid(&ls->ls_stid); out: return nfserr; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 205ee8cc6fa2..81fa7cc6c77b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1222,6 +1222,42 @@ static void put_deleg_file(struct nfs4_file *fp) nfs4_file_put_access(fp, NFS4_SHARE_ACCESS_READ); } +static void nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct file *f) +{ + struct iattr ia = { .ia_valid = ATTR_ATIME | ATTR_CTIME | ATTR_MTIME }; + struct inode *inode = file_inode(f); + int ret; + + /* don't do anything if FMODE_NOCMTIME isn't set */ + if ((READ_ONCE(f->f_mode) & FMODE_NOCMTIME) == 0) + return; + + spin_lock(&f->f_lock); + f->f_mode &= ~FMODE_NOCMTIME; + spin_unlock(&f->f_lock); + + /* was it never written? */ + if (!dp->dl_written) + return; + + /* did it get a setattr for the timestamps at some point? */ + if (dp->dl_setattr) + return; + + /* Stamp everything to "now" */ + inode_lock(inode); + ret = notify_change(&nop_mnt_idmap, f->f_path.dentry, &ia, NULL); + inode_unlock(inode); + if (ret) { + struct inode *inode = file_inode(f); + + pr_notice_ratelimited("Unable to update timestamps on inode %02x:%02x:%lu: %d\n", + MAJOR(inode->i_sb->s_dev), + MINOR(inode->i_sb->s_dev), + inode->i_ino, ret); + } +} + static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) { struct nfs4_file *fp = dp->dl_stid.sc_file; @@ -1229,6 +1265,7 @@ static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) WARN_ON_ONCE(!fp->fi_delegees); + nfsd4_finalize_deleg_timestamps(dp, nf->nf_file); kernel_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp); put_deleg_file(fp); } @@ -6265,6 +6302,8 @@ nfs4_open_delegation(struct svc_rqst *rqstp, struct nfsd4_open *open, memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) { + struct file *f = dp->dl_stid.sc_file->fi_deleg_file->nf_file; + if (!nfsd4_add_rdaccess_to_wrdeleg(rqstp, open, fh, stp) || !nfs4_delegation_stat(dp, currentfh, &stat)) { nfs4_put_stid(&dp->dl_stid); @@ -6278,6 +6317,9 @@ nfs4_open_delegation(struct svc_rqst *rqstp, struct nfsd4_open *open, dp->dl_atime = stat.atime; dp->dl_ctime = stat.ctime; dp->dl_mtime = stat.mtime; + spin_lock(&f->f_lock); + f->f_mode |= FMODE_NOCMTIME; + spin_unlock(&f->f_lock); trace_nfsd_deleg_write(&dp->dl_stid.sc_stateid); } else { open->op_delegate_type = deleg_ts && nfs4_delegation_stat(dp, currentfh, &stat) ? diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index bf9436cdb93c..b6ac0f37e9cd 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -217,10 +217,12 @@ struct nfs4_delegation { struct nfs4_clnt_odstate *dl_clnt_odstate; time64_t dl_time; u32 dl_type; -/* For recall: */ + /* For recall: */ int dl_retries; struct nfsd4_callback dl_recall; bool dl_recalled; + bool dl_written; + bool dl_setattr; /* for CB_GETATTR */ struct nfs4_cb_fattr dl_cb_fattr; From 6ecdfd7aa8e30e16193d4ee07bcb3f1216dbc358 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 29 Jul 2025 14:07:09 +0100 Subject: [PATCH 1904/2711] lockd: Remove space before newline There is an extraneous space before a newline in a dprintk message. Remove the space. Signed-off-by: Colin Ian King Signed-off-by: Chuck Lever --- fs/lockd/svclock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index c1315df4b350..a31dc9588eb8 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -980,7 +980,7 @@ nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status) struct file_lock *fl; int error; - dprintk("grant_reply: looking for cookie %x, s=%d \n", + dprintk("grant_reply: looking for cookie %x, s=%d\n", *(unsigned int *)(cookie->data), status); if (!(block = nlmsvc_find_block(cookie))) return; From 17695d72d0b192bb471a699483dd6c6c2576c57d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 4 Aug 2025 22:46:59 +0000 Subject: [PATCH 1905/2711] nfsd: Replace open-coded conversion of bytes to hex Since the Linux kernel's sprintf() has conversion to hex built-in via "%*phN", delete md5_to_hex() and just use that. Also add an explicit array bound to the dname parameter of nfs4_make_rec_clidname() to make its size clear. No functional change. Reviewed-by: Jeff Layton Signed-off-by: Eric Biggers Signed-off-by: Chuck Lever --- fs/nfsd/nfs4recover.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 2231192ec33f..54f5e5392ef9 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -92,22 +92,8 @@ nfs4_reset_creds(const struct cred *original) put_cred(revert_creds(original)); } -static void -md5_to_hex(char *out, char *md5) -{ - int i; - - for (i=0; i<16; i++) { - unsigned char c = md5[i]; - - *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); - *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); - } - *out = '\0'; -} - static int -nfs4_make_rec_clidname(char *dname, const struct xdr_netobj *clname) +nfs4_make_rec_clidname(char dname[HEXDIR_LEN], const struct xdr_netobj *clname) { struct xdr_netobj cksum; struct crypto_shash *tfm; @@ -133,7 +119,7 @@ nfs4_make_rec_clidname(char *dname, const struct xdr_netobj *clname) if (status) goto out; - md5_to_hex(dname, cksum.data); + sprintf(dname, "%*phN", 16, cksum.data); status = 0; out: From 9ebcd022a34388bd3c37c6a11c1a9d49d5394eb2 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 4 Aug 2025 22:47:00 +0000 Subject: [PATCH 1906/2711] nfsd: Eliminate an allocation in nfs4_make_rec_clidname() Since MD5 digests are fixed-size, make nfs4_make_rec_clidname() store the digest in a stack buffer instead of a dynamically allocated buffer. Use MD5_DIGEST_SIZE instead of a hard-coded value, both in nfs4_make_rec_clidname() and in the definition of HEXDIR_LEN. Signed-off-by: Eric Biggers Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/nfs4recover.c | 15 ++++----------- fs/nfsd/state.h | 4 +++- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 54f5e5392ef9..e2b9472e5c78 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -95,7 +95,7 @@ nfs4_reset_creds(const struct cred *original) static int nfs4_make_rec_clidname(char dname[HEXDIR_LEN], const struct xdr_netobj *clname) { - struct xdr_netobj cksum; + u8 digest[MD5_DIGEST_SIZE]; struct crypto_shash *tfm; int status; @@ -107,23 +107,16 @@ nfs4_make_rec_clidname(char dname[HEXDIR_LEN], const struct xdr_netobj *clname) goto out_no_tfm; } - cksum.len = crypto_shash_digestsize(tfm); - cksum.data = kmalloc(cksum.len, GFP_KERNEL); - if (cksum.data == NULL) { - status = -ENOMEM; - goto out; - } - status = crypto_shash_tfm_digest(tfm, clname->data, clname->len, - cksum.data); + digest); if (status) goto out; - sprintf(dname, "%*phN", 16, cksum.data); + static_assert(HEXDIR_LEN == 2 * MD5_DIGEST_SIZE + 1); + sprintf(dname, "%*phN", MD5_DIGEST_SIZE, digest); status = 0; out: - kfree(cksum.data); crypto_free_shash(tfm); out_no_tfm: return status; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index b6ac0f37e9cd..1e736f402426 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -35,6 +35,7 @@ #ifndef _NFSD4_STATE_H #define _NFSD4_STATE_H +#include #include #include #include @@ -391,7 +392,8 @@ struct nfsd4_sessionid { u32 reserved; }; -#define HEXDIR_LEN 33 /* hex version of 16 byte md5 of cl_name plus '\0' */ +/* Length of MD5 digest as hex, plus terminating '\0' */ +#define HEXDIR_LEN (2 * MD5_DIGEST_SIZE + 1) /* * State Meaning Where set From ab1c282c010c4f327bd7addc3c0035fd8e3c1721 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 6 Aug 2025 03:10:01 +0200 Subject: [PATCH 1907/2711] NFSD: Fix destination buffer size in nfsd4_ssc_setup_dul() Commit 5304877936c0 ("NFSD: Fix strncpy() fortify warning") replaced strncpy(,, sizeof(..)) with strlcpy(,, sizeof(..) - 1), but strlcpy() already guaranteed NUL-termination of the destination buffer and subtracting one byte potentially truncated the source string. The incorrect size was then carried over in commit 72f78ae00a8e ("NFSD: move from strlcpy with unused retval to strscpy") when switching from strlcpy() to strscpy(). Fix this off-by-one error by using the full size of the destination buffer again. Cc: stable@vger.kernel.org Fixes: 5304877936c0 ("NFSD: Fix strncpy() fortify warning") Signed-off-by: Thorsten Blum Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index bfebe6e25638..d7c58aa64f06 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1519,7 +1519,7 @@ try_again: return 0; } if (work) { - strscpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr) - 1); + strscpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr)); refcount_set(&work->nsui_refcnt, 2); work->nsui_busy = true; list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list); From e4f574ca9c6dfa66695bb054ff5df43ecea873ec Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Wed, 6 Aug 2025 15:15:43 -0400 Subject: [PATCH 1908/2711] nfsd: decouple the xprtsec policy check from check_nfsd_access() A while back I had reported that an NFSv3 client could successfully mount using '-o xprtsec=none' an export that had been exported with 'xprtsec=tls:mtls'. By "successfully" I mean that the mount command would succeed and the mount would show up in /proc/mount. Attempting to do anything futher with the mount would be met with NFS3ERR_ACCES. This was fixed (albeit accidentally) by commit bb4f07f2409c ("nfsd: Fix NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT") and was subsequently re-broken by commit 0813c5f01249 ("nfsd: fix access checking for NLM under XPRTSEC policies"). Transport Layer Security isn't an RPC security flavor or pseudo-flavor, so we shouldn't be conflating them when determining whether the access checks can be bypassed. Split check_nfsd_access() into two helpers, and have __fh_verify() call the helpers directly since __fh_verify() has logic that allows one or both of the checks to be skipped. All other sites will continue to call check_nfsd_access(). Link: https://lore.kernel.org/linux-nfs/ZjO3Qwf_G87yNXb2@aion/ Fixes: 9280c5774314 ("NFSD: Handle new xprtsec= export option") Cc: stable@vger.kernel.org Signed-off-by: Scott Mayhew Signed-off-by: Chuck Lever --- fs/nfsd/export.c | 82 +++++++++++++++++++++++++++++++++--------------- fs/nfsd/export.h | 3 ++ fs/nfsd/nfsfh.c | 24 +++++++++++++- 3 files changed, 83 insertions(+), 26 deletions(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index cadfc2bae60e..95b5681152c4 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1082,50 +1082,62 @@ static struct svc_export *exp_find(struct cache_detail *cd, } /** - * check_nfsd_access - check if access to export is allowed. + * check_xprtsec_policy - check if access to export is allowed by the + * xprtsec policy * @exp: svc_export that is being accessed. - * @rqstp: svc_rqst attempting to access @exp (will be NULL for LOCALIO). - * @may_bypass_gss: reduce strictness of authorization check + * @rqstp: svc_rqst attempting to access @exp. + * + * Helper function for check_nfsd_access(). Note that callers should be + * using check_nfsd_access() instead of calling this function directly. The + * one exception is __fh_verify() since it has logic that may result in one + * or both of the helpers being skipped. * * Return values: * %nfs_ok if access is granted, or * %nfserr_wrongsec if access is denied */ -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, - bool may_bypass_gss) +__be32 check_xprtsec_policy(struct svc_export *exp, struct svc_rqst *rqstp) { - struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors; - struct svc_xprt *xprt; - - /* - * If rqstp is NULL, this is a LOCALIO request which will only - * ever use a filehandle/credential pair for which access has - * been affirmed (by ACCESS or OPEN NFS requests) over the - * wire. So there is no need for further checks here. - */ - if (!rqstp) - return nfs_ok; - - xprt = rqstp->rq_xprt; + struct svc_xprt *xprt = rqstp->rq_xprt; if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_NONE) { if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags)) - goto ok; + return nfs_ok; } if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_TLS) { if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) && !test_bit(XPT_PEER_AUTH, &xprt->xpt_flags)) - goto ok; + return nfs_ok; } if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_MTLS) { if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) && test_bit(XPT_PEER_AUTH, &xprt->xpt_flags)) - goto ok; + return nfs_ok; } - if (!may_bypass_gss) - goto denied; + return nfserr_wrongsec; +} + +/** + * check_security_flavor - check if access to export is allowed by the + * security flavor + * @exp: svc_export that is being accessed. + * @rqstp: svc_rqst attempting to access @exp. + * @may_bypass_gss: reduce strictness of authorization check + * + * Helper function for check_nfsd_access(). Note that callers should be + * using check_nfsd_access() instead of calling this function directly. The + * one exception is __fh_verify() since it has logic that may result in one + * or both of the helpers being skipped. + * + * Return values: + * %nfs_ok if access is granted, or + * %nfserr_wrongsec if access is denied + */ +__be32 check_security_flavor(struct svc_export *exp, struct svc_rqst *rqstp, + bool may_bypass_gss) +{ + struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors; -ok: /* legacy gss-only clients are always OK: */ if (exp->ex_client == rqstp->rq_gssclient) return nfs_ok; @@ -1167,10 +1179,30 @@ ok: } } -denied: return nfserr_wrongsec; } +/** + * check_nfsd_access - check if access to export is allowed. + * @exp: svc_export that is being accessed. + * @rqstp: svc_rqst attempting to access @exp. + * @may_bypass_gss: reduce strictness of authorization check + * + * Return values: + * %nfs_ok if access is granted, or + * %nfserr_wrongsec if access is denied + */ +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, + bool may_bypass_gss) +{ + __be32 status; + + status = check_xprtsec_policy(exp, rqstp); + if (status != nfs_ok) + return status; + return check_security_flavor(exp, rqstp, may_bypass_gss); +} + /* * Uses rq_client and rq_gssclient to find an export; uses rq_client (an * auth_unix client) if it's available and has secinfo information; diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h index b9c0adb3ce09..ef5581911d5b 100644 --- a/fs/nfsd/export.h +++ b/fs/nfsd/export.h @@ -101,6 +101,9 @@ struct svc_expkey { struct svc_cred; int nfsexp_flags(struct svc_cred *cred, struct svc_export *exp); +__be32 check_xprtsec_policy(struct svc_export *exp, struct svc_rqst *rqstp); +__be32 check_security_flavor(struct svc_export *exp, struct svc_rqst *rqstp, + bool may_bypass_gss); __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss); diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index f4c2fb3dd5d0..062cfc18d8c6 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -364,10 +364,30 @@ __fh_verify(struct svc_rqst *rqstp, if (error) goto out; + /* + * If rqstp is NULL, this is a LOCALIO request which will only + * ever use a filehandle/credential pair for which access has + * been affirmed (by ACCESS or OPEN NFS requests) over the + * wire. Skip both the xprtsec policy and the security flavor + * checks. + */ + if (!rqstp) + goto check_permissions; + if ((access & NFSD_MAY_NLM) && (exp->ex_flags & NFSEXP_NOAUTHNLM)) /* NLM is allowed to fully bypass authentication */ goto out; + /* + * NLM is allowed to bypass the xprtsec policy check because lockd + * doesn't support xprtsec. + */ + if (!(access & NFSD_MAY_NLM)) { + error = check_xprtsec_policy(exp, rqstp); + if (error) + goto out; + } + if (access & NFSD_MAY_BYPASS_GSS) may_bypass_gss = true; /* @@ -379,13 +399,15 @@ __fh_verify(struct svc_rqst *rqstp, && exp->ex_path.dentry == dentry) may_bypass_gss = true; - error = check_nfsd_access(exp, rqstp, may_bypass_gss); + error = check_security_flavor(exp, rqstp, may_bypass_gss); if (error) goto out; + /* During LOCALIO call to fh_verify will be called with a NULL rqstp */ if (rqstp) svc_xprt_set_valid(rqstp->rq_xprt); +check_permissions: /* Finally, check access permissions. */ error = nfsd_permission(cred, exp, dentry, access); out: From a9a15ba23efc4d6d34127e8d175ae63a95434f58 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 11 Aug 2025 10:37:07 -0400 Subject: [PATCH 1909/2711] sunrpc: fix pr_notice in svc_tcp_sendto() to show correct length This pr_notice() is confusing since it only prints xdr->len, which doesn't include the 4-byte record marker. That can make it sometimes look like the socket sent more than was requested if it's short by just a few bytes. Add sizeof(marker) to the size and fix the format accordingly. Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- net/sunrpc/svcsock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index e2c5e0e626f9..1afaeb45d6a3 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1293,10 +1293,10 @@ out_notconn: mutex_unlock(&xprt->xpt_mutex); return -ENOTCONN; out_close: - pr_notice("rpc-srv/tcp: %s: %s %d when sending %d bytes - shutting down socket\n", + pr_notice("rpc-srv/tcp: %s: %s %d when sending %zu bytes - shutting down socket\n", xprt->xpt_server->sv_name, (err < 0) ? "got error" : "sent", - (err < 0) ? err : sent, xdr->len); + (err < 0) ? err : sent, xdr->len + sizeof(marker)); svc_xprt_deferred_close(xprt); mutex_unlock(&xprt->xpt_mutex); return -EAGAIN; From 7569065fb123f8428cb9d29939dd16d43d4b50c4 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 11 Aug 2025 10:37:08 -0400 Subject: [PATCH 1910/2711] sunrpc: eliminate return pointer in svc_tcp_sendmsg() Return a positive value if something was sent, or a negative error code. Eliminate the "err" variable in the only caller as well. Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- net/sunrpc/svcsock.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 1afaeb45d6a3..c0d5a27ba674 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1224,7 +1224,7 @@ err_noclose: * that the pages backing @xdr are unchanging. */ static int svc_tcp_sendmsg(struct svc_sock *svsk, struct svc_rqst *rqstp, - rpc_fraghdr marker, int *sentp) + rpc_fraghdr marker) { struct msghdr msg = { .msg_flags = MSG_SPLICE_PAGES, @@ -1233,8 +1233,6 @@ static int svc_tcp_sendmsg(struct svc_sock *svsk, struct svc_rqst *rqstp, void *buf; int ret; - *sentp = 0; - /* The stream record marker is copied into a temporary page * fragment buffer so that it can be included in rq_bvec. */ @@ -1252,10 +1250,7 @@ static int svc_tcp_sendmsg(struct svc_sock *svsk, struct svc_rqst *rqstp, 1 + count, sizeof(marker) + rqstp->rq_res.len); ret = sock_sendmsg(svsk->sk_sock, &msg); page_frag_free(buf); - if (ret < 0) - return ret; - *sentp += ret; - return 0; + return ret; } /** @@ -1274,7 +1269,7 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp) struct xdr_buf *xdr = &rqstp->rq_res; rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT | (u32)xdr->len); - int sent, err; + int sent; svc_tcp_release_ctxt(xprt, rqstp->rq_xprt_ctxt); rqstp->rq_xprt_ctxt = NULL; @@ -1282,9 +1277,9 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp) mutex_lock(&xprt->xpt_mutex); if (svc_xprt_is_dead(xprt)) goto out_notconn; - err = svc_tcp_sendmsg(svsk, rqstp, marker, &sent); - trace_svcsock_tcp_send(xprt, err < 0 ? (long)err : sent); - if (err < 0 || sent != (xdr->len + sizeof(marker))) + sent = svc_tcp_sendmsg(svsk, rqstp, marker); + trace_svcsock_tcp_send(xprt, sent); + if (sent < 0 || sent != (xdr->len + sizeof(marker))) goto out_close; mutex_unlock(&xprt->xpt_mutex); return sent; @@ -1295,8 +1290,8 @@ out_notconn: out_close: pr_notice("rpc-srv/tcp: %s: %s %d when sending %zu bytes - shutting down socket\n", xprt->xpt_server->sv_name, - (err < 0) ? "got error" : "sent", - (err < 0) ? err : sent, xdr->len + sizeof(marker)); + (sent < 0) ? "got error" : "sent", + sent, xdr->len + sizeof(marker)); svc_xprt_deferred_close(xprt); mutex_unlock(&xprt->xpt_mutex); return -EAGAIN; From f64397e04b4d094319a8f72bb1b82e4d2e3672ae Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Mon, 18 Aug 2025 18:03:20 +0800 Subject: [PATCH 1911/2711] NFSD: Drop redundant conversion to bool The result of integer comparison already evaluates to bool. No need for explicit conversion. Signed-off-by: Xichao Zhao Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/debugfs.c b/fs/nfsd/debugfs.c index 84b0c8b559dc..f07d790d56aa 100644 --- a/fs/nfsd/debugfs.c +++ b/fs/nfsd/debugfs.c @@ -26,7 +26,7 @@ static int nfsd_dsr_get(void *data, u64 *val) static int nfsd_dsr_set(void *data, u64 val) { - nfsd_disable_splice_read = (val > 0) ? true : false; + nfsd_disable_splice_read = (val > 0); return 0; } From 898374fdd7f06fa4c4a66e8be3135efeae6128d5 Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Tue, 19 Aug 2025 14:04:02 -0400 Subject: [PATCH 1912/2711] nfsd: unregister with rpcbind when deleting a transport When a listener is added, a part of creation of transport also registers program/port with rpcbind. However, when the listener is removed, while transport goes away, rpcbind still has the entry for that port/type. When deleting the transport, unregister with rpcbind when appropriate. ---v2 created a new xpt_flag XPT_RPCB_UNREG to mark TCP and UDP transport and at xprt destroy send rpcbind unregister if flag set. Suggested-by: Chuck Lever Fixes: d093c9089260 ("nfsd: fix management of listener transports") Cc: stable@vger.kernel.org Signed-off-by: Olga Kornievskaia Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- include/linux/sunrpc/svc_xprt.h | 3 +++ net/sunrpc/svc_xprt.c | 13 +++++++++++++ net/sunrpc/svcsock.c | 2 ++ 3 files changed, 18 insertions(+) diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 369a89aea186..2b886f7eb295 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -104,6 +104,9 @@ enum { * it has access to. It is NOT counted * in ->sv_tmpcnt. */ + XPT_RPCB_UNREG, /* transport that needs unregistering + * with rpcbind (TCP, UDP) on destroy + */ }; /* diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 8b1837228799..b800d704d807 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -1014,6 +1014,19 @@ static void svc_delete_xprt(struct svc_xprt *xprt) struct svc_serv *serv = xprt->xpt_server; struct svc_deferred_req *dr; + /* unregister with rpcbind for when transport type is TCP or UDP. + */ + if (test_bit(XPT_RPCB_UNREG, &xprt->xpt_flags)) { + struct svc_sock *svsk = container_of(xprt, struct svc_sock, + sk_xprt); + struct socket *sock = svsk->sk_sock; + + if (svc_register(serv, xprt->xpt_net, sock->sk->sk_family, + sock->sk->sk_protocol, 0) < 0) + pr_warn("failed to unregister %s with rpcbind\n", + xprt->xpt_class->xcl_name); + } + if (test_and_set_bit(XPT_DEAD, &xprt->xpt_flags)) return; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index c0d5a27ba674..7b90abc5cf0e 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -836,6 +836,7 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) /* data might have come in before data_ready set up */ set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags); + set_bit(XPT_RPCB_UNREG, &svsk->sk_xprt.xpt_flags); /* make sure we get destination address info */ switch (svsk->sk_sk->sk_family) { @@ -1350,6 +1351,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) if (sk->sk_state == TCP_LISTEN) { strcpy(svsk->sk_xprt.xpt_remotebuf, "listener"); set_bit(XPT_LISTENER, &svsk->sk_xprt.xpt_flags); + set_bit(XPT_RPCB_UNREG, &svsk->sk_xprt.xpt_flags); sk->sk_data_ready = svc_tcp_listen_data_ready; set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags); } else { From dd9adfa0da2b0dac4c0abdae4bdb88c366bd83d5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 20 Aug 2025 10:27:27 -0400 Subject: [PATCH 1913/2711] NFS: Remove rpcbind cleanup for NFSv4.0 callback The NFS client's NFSv4.0 callback listeners are created with SVC_SOCK_ANONYMOUS, therefore svc_setup_socket() does not register them with the client's rpcbind service. And, note that nfs_callback_down_net() does not call svc_rpcb_cleanup() at all when shutting down the callback server. Even if svc_setup_socket() were to attempt to register or unregister these sockets, the callback service has vs_hidden set, which shunts the rpcbind upcalls. The svc_rpcb_cleanup() error flow was introduced by commit c946556b8749 ("NFS: move per-net callback thread initialization to nfs_callback_up_net()"). It doesn't appear in the code that was relocated by that commit. Therefore, there is no need to call svc_rpcb_cleanup() when listener creation fails during callback server start-up. Signed-off-by: Chuck Lever --- fs/nfs/callback.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 86bdc7d23fb9..511f80878809 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -153,7 +153,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, ret = svc_bind(serv, net); if (ret < 0) { printk(KERN_WARNING "NFS: bind callback service failed\n"); - goto err_bind; + goto err; } ret = 0; @@ -166,13 +166,11 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, if (ret < 0) { printk(KERN_ERR "NFS: callback service start failed\n"); - goto err_socks; + goto err; } return 0; -err_socks: - svc_rpcb_cleanup(serv, net); -err_bind: +err: nn->cb_users[minorversion]--; dprintk("NFS: Couldn't create callback socket: err = %d; " "net = %x\n", ret, net->ns.inum); From d73d06dac604043b94a5f18ebb6a69da1b867702 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 20 Aug 2025 10:27:28 -0400 Subject: [PATCH 1914/2711] SUNRPC: Move the svc_rpcb_cleanup() call sites Clean up: because svc_rpcb_cleanup() and svc_xprt_destroy_all() are always invoked in pairs, we can deduplicate code by moving the svc_rpcb_cleanup() call sites into svc_xprt_destroy_all(). Tested-by: Olga Kornievskaia Signed-off-by: Chuck Lever --- fs/lockd/svc.c | 6 ++---- fs/nfs/callback.c | 2 +- fs/nfsd/nfsctl.c | 2 +- fs/nfsd/nfssvc.c | 7 ++----- include/linux/sunrpc/svc_xprt.h | 3 ++- net/sunrpc/svc.c | 1 - net/sunrpc/svc_xprt.c | 7 ++++++- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index e80262a51884..d68afa196535 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -216,8 +216,7 @@ out_err: if (warned++ == 0) printk(KERN_WARNING "lockd_up: makesock failed, error=%d\n", err); - svc_xprt_destroy_all(serv, net); - svc_rpcb_cleanup(serv, net); + svc_xprt_destroy_all(serv, net, true); return err; } @@ -255,8 +254,7 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) nlm_shutdown_hosts_net(net); cancel_delayed_work_sync(&ln->grace_period_end); locks_end_grace(&ln->lockd_manager); - svc_xprt_destroy_all(serv, net); - svc_rpcb_cleanup(serv, net); + svc_xprt_destroy_all(serv, net, true); } } else { pr_err("%s: no users! net=%x\n", diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 511f80878809..c8b837006bb2 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -136,7 +136,7 @@ static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struc return; dprintk("NFS: destroy per-net callback data; net=%x\n", net->ns.inum); - svc_xprt_destroy_all(serv, net); + svc_xprt_destroy_all(serv, net, false); } static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index bc6b776fc657..63d52edcad72 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1993,7 +1993,7 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info) * remaining listeners and recreate the list. */ if (delete) - svc_xprt_destroy_all(serv, net); + svc_xprt_destroy_all(serv, net, false); /* walk list of addrs again, open any that still don't exist */ nlmsg_for_each_attr_type(attr, NFSD_A_SERVER_SOCK_ADDR, info->nlhdr, diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 82b0111ac469..7057ddd7a0a8 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -535,16 +535,13 @@ void nfsd_destroy_serv(struct net *net) #endif } - svc_xprt_destroy_all(serv, net); - /* * write_ports can create the server without actually starting - * any threads--if we get shut down before any threads are + * any threads. If we get shut down before any threads are * started, then nfsd_destroy_serv will be run before any of this * other initialization has been done except the rpcb information. */ - svc_rpcb_cleanup(serv, net); - + svc_xprt_destroy_all(serv, net, true); nfsd_shutdown_net(net); svc_destroy(&serv); } diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 2b886f7eb295..da2a2531e110 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -168,7 +168,8 @@ int svc_xprt_create(struct svc_serv *serv, const char *xprt_name, struct net *net, const int family, const unsigned short port, int flags, const struct cred *cred); -void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net); +void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net, + bool unregister); void svc_xprt_received(struct svc_xprt *xprt); void svc_xprt_enqueue(struct svc_xprt *xprt); void svc_xprt_put(struct svc_xprt *xprt); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index fc70e13b1cb9..cb4010e2dc0c 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -436,7 +436,6 @@ void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net) svc_unregister(serv, net); rpcb_put_local(net); } -EXPORT_SYMBOL_GPL(svc_rpcb_cleanup); static int svc_uses_rpcbind(struct svc_serv *serv) { diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index b800d704d807..6973184ff667 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -1115,6 +1115,7 @@ static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net) * svc_xprt_destroy_all - Destroy transports associated with @serv * @serv: RPC service to be shut down * @net: target network namespace + * @unregister: true if it is OK to unregister the destroyed xprts * * Server threads may still be running (especially in the case where the * service is still running in other network namespaces). @@ -1127,7 +1128,8 @@ static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net) * threads, we may need to wait a little while and then check again to * see if they're done. */ -void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net) +void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net, + bool unregister) { int delay = 0; @@ -1137,6 +1139,9 @@ void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net) svc_clean_up_xprts(serv, net); msleep(delay++); } + + if (unregister) + svc_rpcb_cleanup(serv, net); } EXPORT_SYMBOL_GPL(svc_xprt_destroy_all); From fb340bfd48bcc3a51d35be1fe2a2db290092d4ea Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 21 Aug 2025 10:53:20 -0400 Subject: [PATCH 1915/2711] NFSD: Delay adding new entries to LRU Neil Brown observes: > I would not include RC_INPROG entries in the lru at all - they are > always ignored, and will be added when they are switched to > RCU_DONE. I also removed a stale comment. Suggested-by: NeilBrown Reviewed-by: NeilBrown Signed-off-by: Chuck Lever --- fs/nfsd/nfscache.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index ba9d326b3de6..d929c8c63bd9 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -237,10 +237,6 @@ void nfsd_reply_cache_shutdown(struct nfsd_net *nn) } -/* - * Move cache entry to end of LRU list, and queue the cleaner to run if it's - * not already scheduled. - */ static void lru_put_end(struct nfsd_drc_bucket *b, struct nfsd_cacherep *rp) { @@ -272,13 +268,6 @@ nfsd_prune_bucket_locked(struct nfsd_net *nn, struct nfsd_drc_bucket *b, /* The bucket LRU is ordered oldest-first. */ list_for_each_entry_safe(rp, tmp, &b->lru_head, c_lru) { - /* - * Don't free entries attached to calls that are still - * in-progress, but do keep scanning the list. - */ - if (rp->c_state == RC_INPROG) - continue; - if (atomic_read(&nn->num_drc_entries) <= nn->max_drc_entries && time_before(expiry, rp->c_timestamp)) break; @@ -453,8 +442,6 @@ out: nn->longest_chain_cachesize, atomic_read(&nn->num_drc_entries)); } - - lru_put_end(b, ret); return ret; } From 8ddd06be9a9e2b9f4af9b337150af834862331ef Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 21 Aug 2025 10:53:21 -0400 Subject: [PATCH 1916/2711] NFSD: Reduce DRC bucket size The common case is that a DRC lookup will not find the XID in the bucket. Reduce the amount of pointer chasing during the lookup by keeping fewer entries in each hash bucket. Changing the bucket size constant forces the size of the DRC hash table to increase, and the height of each bucket r-b tree to be reduced. Signed-off-by: Chuck Lever --- fs/nfsd/nfscache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index d929c8c63bd9..ab13ee9c7fd8 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -27,7 +27,7 @@ * cache size, the idea being that when the cache is at its maximum number * of entries, then this should be the average number of entries per bucket. */ -#define TARGET_BUCKET_SIZE 64 +#define TARGET_BUCKET_SIZE 8 struct nfsd_drc_bucket { struct rb_root rb_head; From a082e4b4d08a4a0e656d90c2c05da85f23e6d0c9 Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Thu, 21 Aug 2025 16:31:46 -0400 Subject: [PATCH 1917/2711] nfsd: nfserr_jukebox in nlm_fopen should lead to a retry When v3 NLM request finds a conflicting delegation, it triggers a delegation recall and nfsd_open fails with EAGAIN. nfsd_open then translates EAGAIN into nfserr_jukebox. In nlm_fopen, instead of returning nlm_failed for when there is a conflicting delegation, drop this NLM request so that the client retries. Once delegation is recalled and if a local lock is claimed, a retry would lead to nfsd returning a nlm_lck_blocked error or a successful nlm lock. Fixes: d343fce148a4 ("[PATCH] knfsd: Allow lockd to drop replies as appropriate") Cc: stable@vger.kernel.org # v6.6 Signed-off-by: Olga Kornievskaia Signed-off-by: Chuck Lever --- fs/nfsd/lockd.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index edc9f75dc75c..6b042218668b 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -57,6 +57,21 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp, switch (nfserr) { case nfs_ok: return 0; + case nfserr_jukebox: + /* this error can indicate a presence of a conflicting + * delegation to an NLM lock request. Options are: + * (1) For now, drop this request and make the client + * retry. When delegation is returned, client's lock retry + * will complete. + * (2) NLM4_DENIED as per "spec" signals to the client + * that the lock is unavailable now but client can retry. + * Linux client implementation does not. It treats + * NLM4_DENIED same as NLM4_FAILED and errors the request. + * (3) For the future, treat this as blocked lock and try + * to callback when the delegation is returned but might + * not have a proper lock request to block on. + */ + fallthrough; case nfserr_dropit: return nlm_drop_reply; case nfserr_stale: From 13289ed501bad7a37ccbfa8581961d2e9dd4aea3 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 3 Aug 2025 14:21:30 -0700 Subject: [PATCH 1918/2711] nfsd: Don't force CRYPTO_LIB_SHA256 to be built-in Now that nfsd is accessing SHA-256 via the library API instead of via crypto_shash, there is a direct symbol dependency on the SHA-256 code and there is no benefit to be gained from forcing it to be built-in. Therefore, select CRYPTO_LIB_SHA256 from NFSD (conditional on NFSD_V4) instead of from NFSD_V4, so that it can be 'm' if NFSD is 'm'. Signed-off-by: Eric Biggers Reviewed-by: Jeff Layton Signed-off-by: Chuck Lever --- fs/nfsd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 879e0b104d1c..e134dce45e35 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -5,6 +5,7 @@ config NFSD depends on FILE_LOCKING depends on FSNOTIFY select CRC32 + select CRYPTO_LIB_SHA256 if NFSD_V4 select LOCKD select SUNRPC select EXPORTFS @@ -77,7 +78,6 @@ config NFSD_V4 select FS_POSIX_ACL select RPCSEC_GSS_KRB5 select CRYPTO - select CRYPTO_LIB_SHA256 select CRYPTO_MD5 select GRACE_PERIOD select NFS_V4_2_SSC_HELPER if NFS_V4_2 From 6c15463c4511d26f2a820f63f5b76624a71afc44 Mon Sep 17 00:00:00 2001 From: Xichao Zhao Date: Tue, 12 Aug 2025 19:33:59 +0800 Subject: [PATCH 1919/2711] sunrpc: fix "occurence"->"occurrence" Trivial fix to spelling mistake in comment text. Signed-off-by: Xichao Zhao Reviewed-by: Joe Damato Signed-off-by: Chuck Lever --- net/sunrpc/sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c index 09434e1143c5..8b01b7ae2690 100644 --- a/net/sunrpc/sysfs.c +++ b/net/sunrpc/sysfs.c @@ -389,7 +389,7 @@ static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj, saddr = (struct sockaddr *)&xprt->addr; port = rpc_get_port(saddr); - /* buf_len is the len until the first occurence of either + /* buf_len is the len until the first occurrence of either * '\n' or '\0' */ buf_len = strcspn(buf, "\n"); From 302c04110f0ce70d25add2496b521132548cd408 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Sat, 20 Sep 2025 20:53:12 +0800 Subject: [PATCH 1920/2711] sparc: fix error handling in scan_one_device() Once of_device_register() failed, we should call put_device() to decrement reference count for cleanup. Or it could cause memory leak. So fix this by calling put_device(), then the name can be freed in kobject_cleanup(). Calling path: of_device_register() -> of_device_add() -> device_add(). As comment of device_add() says, 'if device_add() succeeds, you should call device_del() when you want to get rid of it. If device_add() has not succeeded, use only put_device() to drop the reference count'. Found by code review. Cc: stable@vger.kernel.org Fixes: cf44bbc26cf1 ("[SPARC]: Beginnings of generic of_device framework.") Signed-off-by: Ma Ke Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/kernel/of_device_32.c | 1 + arch/sparc/kernel/of_device_64.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/sparc/kernel/of_device_32.c b/arch/sparc/kernel/of_device_32.c index 06012e68bdca..284a4cafa432 100644 --- a/arch/sparc/kernel/of_device_32.c +++ b/arch/sparc/kernel/of_device_32.c @@ -387,6 +387,7 @@ static struct platform_device * __init scan_one_device(struct device_node *dp, if (of_device_register(op)) { printk("%pOF: Could not register of device.\n", dp); + put_device(&op->dev); kfree(op); op = NULL; } diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c index f98c2901f335..f53092b07b9e 100644 --- a/arch/sparc/kernel/of_device_64.c +++ b/arch/sparc/kernel/of_device_64.c @@ -677,6 +677,7 @@ static struct platform_device * __init scan_one_device(struct device_node *dp, if (of_device_register(op)) { printk("%pOF: Could not register of device.\n", dp); + put_device(&op->dev); kfree(op); op = NULL; } From 4f152338e384a3a47dd61909e1457539fa93f5a4 Mon Sep 17 00:00:00 2001 From: Nagarjuna Kristam Date: Thu, 11 Sep 2025 11:30:22 +0200 Subject: [PATCH 1921/2711] PCI: tegra194: Fix duplicate PLL disable in pex_ep_event_pex_rst_assert() During PERST# assertion tegra_pcie_bpmp_set_pll_state() is currently called twice. pex_ep_event_pex_rst_assert() should do the opposite of pex_ep_event_pex_rst_deassert(), so it is obvious that the duplicate tegra_pcie_bpmp_set_pll_state() is a mistake, and that the duplicate tegra_pcie_bpmp_set_pll_state() call should instead be a call to tegra_pcie_bpmp_set_ctrl_state(). With this, the uninitialization sequence also matches that of tegra_pcie_unconfig_controller(). Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") Signed-off-by: Nagarjuna Kristam [cassel: improve commit log] Signed-off-by: Niklas Cassel Link: https://patch.msgid.link/20250911093021.1454385-2-cassel@kernel.org [mani: added Fixes tag] Signed-off-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 4f26086f25da..0c0734aa14b6 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1722,9 +1722,9 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) ret); } - ret = tegra_pcie_bpmp_set_pll_state(pcie, false); + ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false); if (ret) - dev_err(pcie->dev, "Failed to turn off UPHY: %d\n", ret); + dev_err(pcie->dev, "Failed to disable controller: %d\n", ret); pcie->ep_state = EP_STATE_DISABLED; dev_dbg(pcie->dev, "Uninitialization of endpoint is completed\n"); From f145845d8348c9b6288df41cb7904fd9fde566dc Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 19 Sep 2025 17:35:31 -0500 Subject: [PATCH 1922/2711] dt-bindings: ata: apm,xgene-ahci: Add apm,xgene-ahci-v2 support The "apm,xgene-ahci-v2" compatible has been in use for a long time, but was undocumented. It doesn't require clocks or phys. Remove the "apm,xgene-ahci-pcie" compatible which isn't used anywhere while we're here. Signed-off-by: Rob Herring (Arm) Signed-off-by: Damien Le Moal --- .../bindings/ata/apm,xgene-ahci.yaml | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/ata/apm,xgene-ahci.yaml b/Documentation/devicetree/bindings/ata/apm,xgene-ahci.yaml index 7dc942808656..dc631381f9e1 100644 --- a/Documentation/devicetree/bindings/ata/apm,xgene-ahci.yaml +++ b/Documentation/devicetree/bindings/ata/apm,xgene-ahci.yaml @@ -9,14 +9,11 @@ title: APM X-Gene 6.0 Gb/s SATA host controller maintainers: - Rob Herring -allOf: - - $ref: ahci-common.yaml# - properties: compatible: enum: - apm,xgene-ahci - - apm,xgene-ahci-pcie + - apm,xgene-ahci-v2 reg: minItems: 4 @@ -35,12 +32,22 @@ properties: required: - compatible - - clocks - - phys - - phy-names unevaluatedProperties: false +allOf: + - $ref: ahci-common.yaml# + - if: + properties: + compatible: + contains: + const: apm,xgene-ahci + then: + required: + - clocks + - phys + - phy-names + examples: - | sata@1a400000 { From 110be46f5afe27b66caa2d12473a84cd397b1925 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 20 Aug 2025 18:02:33 +0200 Subject: [PATCH 1923/2711] remoteproc: qcom: q6v5: Avoid disabling handover IRQ twice enable_irq() and disable_irq() are reference counted, so we must make sure that each enable_irq() is always paired with a single disable_irq(). If we call disable_irq() twice followed by just a single enable_irq(), the IRQ will remain disabled forever. For the error handling path in qcom_q6v5_wait_for_start(), disable_irq() will end up being called twice, because disable_irq() also happens in qcom_q6v5_unprepare() when rolling back the call to qcom_q6v5_prepare(). Fix this by dropping disable_irq() in qcom_q6v5_wait_for_start(). Since qcom_q6v5_prepare() is the function that calls enable_irq(), it makes more sense to have the rollback handled always by qcom_q6v5_unprepare(). Fixes: 3b415c8fb263 ("remoteproc: q6v5: Extract common resource handling") Reviewed-by: Dmitry Baryshkov Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20250820-rproc-qcom-q6v5-fixes-v2-1-910b1a3aff71@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index 4ee5e67a9f03..769c6d6d6a73 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -156,9 +156,6 @@ int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout) int ret; ret = wait_for_completion_timeout(&q6v5->start_done, timeout); - if (!ret) - disable_irq(q6v5->handover_irq); - return !ret ? -ETIMEDOUT : 0; } EXPORT_SYMBOL_GPL(qcom_q6v5_wait_for_start); From 54898664e1eb6b5b3e6cdd9343c6eb15da776153 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 20 Aug 2025 18:02:34 +0200 Subject: [PATCH 1924/2711] remoteproc: qcom: q6v5: Avoid handling handover twice A remoteproc could theoretically signal handover twice. This is unexpected and would break the reference counting for the handover resources (power domains, clocks, regulators, etc), so add a check to prevent that from happening. Reviewed-by: Dmitry Baryshkov Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20250820-rproc-qcom-q6v5-fixes-v2-2-910b1a3aff71@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index 769c6d6d6a73..58d5b85e58cd 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -164,6 +164,11 @@ static irqreturn_t q6v5_handover_interrupt(int irq, void *data) { struct qcom_q6v5 *q6v5 = data; + if (q6v5->handover_issued) { + dev_err(q6v5->dev, "Handover signaled, but it already happened\n"); + return IRQ_HANDLED; + } + if (q6v5->handover) q6v5->handover(q6v5); From 142964960c7c35de5c5f7bdd61c32699de693630 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 20 Aug 2025 18:02:35 +0200 Subject: [PATCH 1925/2711] remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E The ADSP firmware on X1E has separate firmware binaries for the main firmware and the DTB. The same applies for the "lite" firmware loaded by the boot firmware. When preparing to load the new ADSP firmware we shutdown the lite_pas_id for the main firmware, but we don't shutdown the corresponding lite pas_id for the DTB. The fact that we're leaving it "running" forever becomes obvious if you try to reuse (or just access) the memory region used by the "lite" firmware: The &adsp_boot_mem is accessible, but accessing the &adsp_boot_dtb_mem results in a crash. We don't support reusing the memory regions currently, but nevertheless we should not keep part of the lite firmware running. Fix this by adding the lite_dtb_pas_id and shutting it down as well. We don't have a way to detect if the lite firmware is actually running yet, so ignore the return status of qcom_scm_pas_shutdown() for now. This was already the case before, the assignment to "ret" is not used anywhere. Fixes: 62210f7509e1 ("remoteproc: qcom_q6v5_pas: Unload lite firmware on ADSP") Reviewed-by: Dmitry Baryshkov Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20250820-rproc-qcom-q6v5-fixes-v2-3-910b1a3aff71@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 6fe5ae0a9eb1..2799e7191876 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -42,6 +42,7 @@ struct qcom_pas_data { int pas_id; int dtb_pas_id; int lite_pas_id; + int lite_dtb_pas_id; unsigned int minidump_id; bool auto_boot; bool decrypt_shutdown; @@ -80,6 +81,7 @@ struct qcom_pas { int pas_id; int dtb_pas_id; int lite_pas_id; + int lite_dtb_pas_id; unsigned int minidump_id; int crash_reason_smem; unsigned int smem_host_id; @@ -226,6 +228,8 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) if (pas->lite_pas_id) ret = qcom_scm_pas_shutdown(pas->lite_pas_id); + if (pas->lite_dtb_pas_id) + qcom_scm_pas_shutdown(pas->lite_dtb_pas_id); if (pas->dtb_pas_id) { ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev); @@ -722,6 +726,7 @@ static int qcom_pas_probe(struct platform_device *pdev) pas->minidump_id = desc->minidump_id; pas->pas_id = desc->pas_id; pas->lite_pas_id = desc->lite_pas_id; + pas->lite_dtb_pas_id = desc->lite_dtb_pas_id; pas->info_name = desc->sysmon_name; pas->smem_host_id = desc->smem_host_id; pas->decrypt_shutdown = desc->decrypt_shutdown; @@ -1085,6 +1090,7 @@ static const struct qcom_pas_data x1e80100_adsp_resource = { .pas_id = 1, .dtb_pas_id = 0x24, .lite_pas_id = 0x1f, + .lite_dtb_pas_id = 0x29, .minidump_id = 5, .auto_boot = true, .proxy_pd_names = (char*[]){ From 1ae4e2dbf4cbf7c1ab2bdc89af1dc1a6af4106b3 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 20 Aug 2025 18:02:36 +0200 Subject: [PATCH 1926/2711] remoteproc: qcom: pas: Drop redundant assignment to ret We don't have a way to detect if the lite firmware is actually running yet, so we should ignore the return status of qcom_scm_pas_shutdown() for now. The assignment to "ret" is not used anywhere, so just drop it. Signed-off-by: Stephan Gerhold Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250820-rproc-qcom-q6v5-fixes-v2-4-910b1a3aff71@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 2799e7191876..e6fc1a6e3d9e 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -227,7 +227,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) pas->firmware = fw; if (pas->lite_pas_id) - ret = qcom_scm_pas_shutdown(pas->lite_pas_id); + qcom_scm_pas_shutdown(pas->lite_pas_id); if (pas->lite_dtb_pas_id) qcom_scm_pas_shutdown(pas->lite_dtb_pas_id); From f0c260f175510e7e8a518e8e09bd57a96188f108 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Thu, 18 Sep 2025 13:04:47 +0530 Subject: [PATCH 1927/2711] ntb_hw_amd: Update amd_ntb_get_link_status to support latest generation secondary topology In the NTB secondary topology configuration of the latest generation, the device behaves like an endpoint. Hence, add endpoint support and update amd_ntb_get_link_status to accommodate endpoint devices. Co-developed-by: Sanath S Signed-off-by: Sanath S Signed-off-by: Basavaraj Natikar Reviewed-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/hw/amd/ntb_hw_amd.c | 18 +++++++++++++++++- drivers/ntb/hw/amd/ntb_hw_amd.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c index 63ceed89b62e..1a163596ddf5 100644 --- a/drivers/ntb/hw/amd/ntb_hw_amd.c +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c @@ -197,13 +197,22 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx, static int amd_ntb_get_link_status(struct amd_ntb_dev *ndev) { - struct pci_dev *pdev = NULL; + struct pci_dev *pdev = ndev->ntb.pdev; struct pci_dev *pci_swds = NULL; struct pci_dev *pci_swus = NULL; u32 stat; int rc; if (ndev->ntb.topo == NTB_TOPO_SEC) { + if (ndev->dev_data->is_endpoint) { + rc = pcie_capability_read_dword(pdev, PCI_EXP_LNKCTL, &stat); + if (rc) + return rc; + + ndev->lnk_sta = stat; + return 0; + } + /* Locate the pointer to Downstream Switch for this device */ pci_swds = pci_upstream_bridge(ndev->ntb.pdev); if (pci_swds) { @@ -1311,6 +1320,11 @@ static const struct ntb_dev_data dev_data[] = { .mw_count = 2, .mw_idx = 2, }, + { /* for device 0x17d7 */ + .mw_count = 2, + .mw_idx = 2, + .is_endpoint = true, + }, }; static const struct pci_device_id amd_ntb_pci_tbl[] = { @@ -1319,6 +1333,8 @@ static const struct pci_device_id amd_ntb_pci_tbl[] = { { PCI_VDEVICE(AMD, 0x14c0), (kernel_ulong_t)&dev_data[1] }, { PCI_VDEVICE(AMD, 0x14c3), (kernel_ulong_t)&dev_data[1] }, { PCI_VDEVICE(AMD, 0x155a), (kernel_ulong_t)&dev_data[1] }, + { PCI_VDEVICE(AMD, 0x17d4), (kernel_ulong_t)&dev_data[1] }, + { PCI_VDEVICE(AMD, 0x17d7), (kernel_ulong_t)&dev_data[2] }, { PCI_VDEVICE(HYGON, 0x145b), (kernel_ulong_t)&dev_data[0] }, { 0, } }; diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.h b/drivers/ntb/hw/amd/ntb_hw_amd.h index 5f337b1572a0..e8c3165fa38b 100644 --- a/drivers/ntb/hw/amd/ntb_hw_amd.h +++ b/drivers/ntb/hw/amd/ntb_hw_amd.h @@ -168,6 +168,7 @@ enum { struct ntb_dev_data { const unsigned char mw_count; const unsigned int mw_idx; + const bool is_endpoint; }; struct amd_ntb_dev; From eb4431bf8823cc55be6c705c122980be0690a904 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Thu, 18 Sep 2025 13:04:48 +0530 Subject: [PATCH 1928/2711] MAINTAINERS: Update for the NTB AMD driver maintainer Adding myself to the maintainers list for the ntb_hw_amd driver. Signed-off-by: Basavaraj Natikar Reviewed-by: Dave Jiang Signed-off-by: Jon Mason --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..3210b975e46b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18027,6 +18027,7 @@ F: Documentation/core-api/symbol-namespaces.rst F: scripts/nsdeps NTB AMD DRIVER +M: Basavaraj Natikar M: Shyam Sundar S K L: ntb@lists.linux.dev S: Supported From 3db835dd8f9a78e9709cb48b77d89b41792e9281 Mon Sep 17 00:00:00 2001 From: fuyuanli Date: Mon, 25 Aug 2025 17:15:08 +0800 Subject: [PATCH 1929/2711] ntb: Add mutex to make link_event_callback executed linearly. Since the CPU selected by schedule_work is uncertain, multiple link_event callbacks may be executed at same time. For example, after peer's link is up, it is down quickly before local link_work completed. If link_cleanup is added to the workqueue of another CPU, then link_work and link_cleanup may be executed at the same time. So add a mutex to prevent them from being executed concurrently. Signed-off-by: fuyuanli Reviewed-by: Logan Gunthorpe Reviewed-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 4f775c3e218f..eb875e3db2e3 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -59,6 +59,7 @@ #include #include #include +#include #include "linux/ntb.h" #include "linux/ntb_transport.h" @@ -241,6 +242,9 @@ struct ntb_transport_ctx { struct work_struct link_cleanup; struct dentry *debugfs_node_dir; + + /* Make sure workq of link event be executed serially */ + struct mutex link_event_lock; }; enum { @@ -1024,6 +1028,7 @@ static void ntb_transport_link_cleanup_work(struct work_struct *work) struct ntb_transport_ctx *nt = container_of(work, struct ntb_transport_ctx, link_cleanup); + guard(mutex)(&nt->link_event_lock); ntb_transport_link_cleanup(nt); } @@ -1047,6 +1052,8 @@ static void ntb_transport_link_work(struct work_struct *work) u32 val; int rc = 0, i, spad; + guard(mutex)(&nt->link_event_lock); + /* send the local info, in the opposite order of the way we read it */ if (nt->use_msi) { From 5ad865862a0fd349163243e1834ed98ba9b81905 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 2 Jul 2025 18:48:33 +0200 Subject: [PATCH 1930/2711] NTB: epf: Allow arbitrary BAR mapping The NTB epf host driver assumes the BAR number associated with a memory window is just incremented from the BAR number associated with MW1. This seems to have been enough so far but this is not really how the endpoint side work and the two could easily become mis-aligned. ntb_epf_mw_to_bar() even assumes that the BAR number is the memory window index + 2, which means the function only returns a proper result if BAR_2 is associated with MW1. Instead, fully describe and allow arbitrary NTB BAR mapping. Signed-off-by: Jerome Brunet Signed-off-by: Jon Mason --- drivers/ntb/hw/epf/ntb_hw_epf.c | 103 ++++++++++++++++---------------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/drivers/ntb/hw/epf/ntb_hw_epf.c b/drivers/ntb/hw/epf/ntb_hw_epf.c index 00f0e78f685b..2b51156e01b0 100644 --- a/drivers/ntb/hw/epf/ntb_hw_epf.c +++ b/drivers/ntb/hw/epf/ntb_hw_epf.c @@ -49,6 +49,7 @@ #define NTB_EPF_COMMAND_TIMEOUT 1000 /* 1 Sec */ enum pci_barno { + NO_BAR = -1, BAR_0, BAR_1, BAR_2, @@ -57,16 +58,26 @@ enum pci_barno { BAR_5, }; +enum epf_ntb_bar { + BAR_CONFIG, + BAR_PEER_SPAD, + BAR_DB, + BAR_MW1, + BAR_MW2, + BAR_MW3, + BAR_MW4, + NTB_BAR_NUM, +}; + +#define NTB_EPF_MAX_MW_COUNT (NTB_BAR_NUM - BAR_MW1) + struct ntb_epf_dev { struct ntb_dev ntb; struct device *dev; /* Mutex to protect providing commands to NTB EPF */ struct mutex cmd_lock; - enum pci_barno ctrl_reg_bar; - enum pci_barno peer_spad_reg_bar; - enum pci_barno db_reg_bar; - enum pci_barno mw_bar; + const enum pci_barno *barno_map; unsigned int mw_count; unsigned int spad_count; @@ -85,17 +96,6 @@ struct ntb_epf_dev { #define ntb_ndev(__ntb) container_of(__ntb, struct ntb_epf_dev, ntb) -struct ntb_epf_data { - /* BAR that contains both control region and self spad region */ - enum pci_barno ctrl_reg_bar; - /* BAR that contains peer spad region */ - enum pci_barno peer_spad_reg_bar; - /* BAR that contains Doorbell region and Memory window '1' */ - enum pci_barno db_reg_bar; - /* BAR that contains memory windows*/ - enum pci_barno mw_bar; -}; - static int ntb_epf_send_command(struct ntb_epf_dev *ndev, u32 command, u32 argument) { @@ -144,7 +144,7 @@ static int ntb_epf_mw_to_bar(struct ntb_epf_dev *ndev, int idx) return -EINVAL; } - return idx + 2; + return ndev->barno_map[BAR_MW1 + idx]; } static int ntb_epf_mw_count(struct ntb_dev *ntb, int pidx) @@ -413,7 +413,9 @@ static int ntb_epf_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx, return -EINVAL; } - bar = idx + ndev->mw_bar; + bar = ntb_epf_mw_to_bar(ndev, idx); + if (bar < 0) + return bar; mw_size = pci_resource_len(ntb->pdev, bar); @@ -455,7 +457,9 @@ static int ntb_epf_peer_mw_get_addr(struct ntb_dev *ntb, int idx, if (idx == 0) offset = readl(ndev->ctrl_reg + NTB_EPF_MW1_OFFSET); - bar = idx + ndev->mw_bar; + bar = ntb_epf_mw_to_bar(ndev, idx); + if (bar < 0) + return bar; if (base) *base = pci_resource_start(ndev->ntb.pdev, bar) + offset; @@ -560,6 +564,11 @@ static int ntb_epf_init_dev(struct ntb_epf_dev *ndev) ndev->mw_count = readl(ndev->ctrl_reg + NTB_EPF_MW_COUNT); ndev->spad_count = readl(ndev->ctrl_reg + NTB_EPF_SPAD_COUNT); + if (ndev->mw_count > NTB_EPF_MAX_MW_COUNT) { + dev_err(dev, "Unsupported MW count: %u\n", ndev->mw_count); + return -EINVAL; + } + return 0; } @@ -596,14 +605,15 @@ static int ntb_epf_init_pci(struct ntb_epf_dev *ndev, dev_warn(&pdev->dev, "Cannot DMA highmem\n"); } - ndev->ctrl_reg = pci_iomap(pdev, ndev->ctrl_reg_bar, 0); + ndev->ctrl_reg = pci_iomap(pdev, ndev->barno_map[BAR_CONFIG], 0); if (!ndev->ctrl_reg) { ret = -EIO; goto err_pci_regions; } - if (ndev->peer_spad_reg_bar) { - ndev->peer_spad_reg = pci_iomap(pdev, ndev->peer_spad_reg_bar, 0); + if (ndev->barno_map[BAR_PEER_SPAD] != ndev->barno_map[BAR_CONFIG]) { + ndev->peer_spad_reg = pci_iomap(pdev, + ndev->barno_map[BAR_PEER_SPAD], 0); if (!ndev->peer_spad_reg) { ret = -EIO; goto err_pci_regions; @@ -614,7 +624,7 @@ static int ntb_epf_init_pci(struct ntb_epf_dev *ndev, ndev->peer_spad_reg = ndev->ctrl_reg + spad_off + spad_sz; } - ndev->db_reg = pci_iomap(pdev, ndev->db_reg_bar, 0); + ndev->db_reg = pci_iomap(pdev, ndev->barno_map[BAR_DB], 0); if (!ndev->db_reg) { ret = -EIO; goto err_pci_regions; @@ -659,12 +669,7 @@ static void ntb_epf_cleanup_isr(struct ntb_epf_dev *ndev) static int ntb_epf_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - enum pci_barno peer_spad_reg_bar = BAR_1; - enum pci_barno ctrl_reg_bar = BAR_0; - enum pci_barno db_reg_bar = BAR_2; - enum pci_barno mw_bar = BAR_2; struct device *dev = &pdev->dev; - struct ntb_epf_data *data; struct ntb_epf_dev *ndev; int ret; @@ -675,18 +680,10 @@ static int ntb_epf_pci_probe(struct pci_dev *pdev, if (!ndev) return -ENOMEM; - data = (struct ntb_epf_data *)id->driver_data; - if (data) { - peer_spad_reg_bar = data->peer_spad_reg_bar; - ctrl_reg_bar = data->ctrl_reg_bar; - db_reg_bar = data->db_reg_bar; - mw_bar = data->mw_bar; - } + ndev->barno_map = (const enum pci_barno *)id->driver_data; + if (!ndev->barno_map) + return -EINVAL; - ndev->peer_spad_reg_bar = peer_spad_reg_bar; - ndev->ctrl_reg_bar = ctrl_reg_bar; - ndev->db_reg_bar = db_reg_bar; - ndev->mw_bar = mw_bar; ndev->dev = dev; ntb_epf_init_struct(ndev, pdev); @@ -730,30 +727,36 @@ static void ntb_epf_pci_remove(struct pci_dev *pdev) ntb_epf_deinit_pci(ndev); } -static const struct ntb_epf_data j721e_data = { - .ctrl_reg_bar = BAR_0, - .peer_spad_reg_bar = BAR_1, - .db_reg_bar = BAR_2, - .mw_bar = BAR_2, +static const enum pci_barno j721e_map[NTB_BAR_NUM] = { + [BAR_CONFIG] = BAR_0, + [BAR_PEER_SPAD] = BAR_1, + [BAR_DB] = BAR_2, + [BAR_MW1] = BAR_2, + [BAR_MW2] = BAR_3, + [BAR_MW3] = BAR_4, + [BAR_MW4] = BAR_5 }; -static const struct ntb_epf_data mx8_data = { - .ctrl_reg_bar = BAR_0, - .peer_spad_reg_bar = BAR_0, - .db_reg_bar = BAR_2, - .mw_bar = BAR_4, +static const enum pci_barno mx8_map[NTB_BAR_NUM] = { + [BAR_CONFIG] = BAR_0, + [BAR_PEER_SPAD] = BAR_0, + [BAR_DB] = BAR_2, + [BAR_MW1] = BAR_4, + [BAR_MW2] = BAR_5, + [BAR_MW3] = NO_BAR, + [BAR_MW4] = NO_BAR }; static const struct pci_device_id ntb_epf_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E), .class = PCI_CLASS_MEMORY_RAM << 8, .class_mask = 0xffff00, - .driver_data = (kernel_ulong_t)&j721e_data, + .driver_data = (kernel_ulong_t)j721e_map, }, { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x0809), .class = PCI_CLASS_MEMORY_RAM << 8, .class_mask = 0xffff00, - .driver_data = (kernel_ulong_t)&mx8_data, + .driver_data = (kernel_ulong_t)mx8_map, }, { }, }; From 006824a1cb3bd4001745a2b1cc83c43fad522851 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 2 Jul 2025 18:48:34 +0200 Subject: [PATCH 1931/2711] NTB: epf: Add Renesas rcar support Add virtual non-transparent bridge support for Renesas rcar platform Reviewed-by: Frank Li Signed-off-by: Jerome Brunet Signed-off-by: Jon Mason --- drivers/ntb/hw/epf/ntb_hw_epf.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/ntb/hw/epf/ntb_hw_epf.c b/drivers/ntb/hw/epf/ntb_hw_epf.c index 2b51156e01b0..d3ecf25a5162 100644 --- a/drivers/ntb/hw/epf/ntb_hw_epf.c +++ b/drivers/ntb/hw/epf/ntb_hw_epf.c @@ -747,6 +747,16 @@ static const enum pci_barno mx8_map[NTB_BAR_NUM] = { [BAR_MW4] = NO_BAR }; +static const enum pci_barno rcar_barno[NTB_BAR_NUM] = { + [BAR_CONFIG] = BAR_0, + [BAR_PEER_SPAD] = BAR_0, + [BAR_DB] = BAR_4, + [BAR_MW1] = BAR_2, + [BAR_MW2] = NO_BAR, + [BAR_MW3] = NO_BAR, + [BAR_MW4] = NO_BAR, +}; + static const struct pci_device_id ntb_epf_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E), @@ -758,6 +768,11 @@ static const struct pci_device_id ntb_epf_pci_tbl[] = { .class = PCI_CLASS_MEMORY_RAM << 8, .class_mask = 0xffff00, .driver_data = (kernel_ulong_t)mx8_map, }, + { + PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0030), + .class = PCI_CLASS_MEMORY_RAM << 8, .class_mask = 0xffff00, + .driver_data = (kernel_ulong_t)rcar_barno, + }, { }, }; From e8f85d7884e0890ea43aa36396bcaf8a2659c2ac Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 18 Sep 2025 17:46:39 -0700 Subject: [PATCH 1932/2711] KVM: x86: Don't treat ENTER and LEAVE as branches, because they aren't Remove the IsBranch flag from ENTER and LEAVE in KVM's emulator, as ENTER and LEAVE are stack operations, not branches. Add forced emulation of said instructions to the PMU counters test to prove that KVM diverges from hardware, and to guard against regressions. Opportunistically add a missing "1 MOV" to the selftest comment regarding the number of instructions per loop, which commit 7803339fa929 ("KVM: selftests: Use data load to trigger LLC references/misses in Intel PMU") forgot to add. Fixes: 018d70ffcfec ("KVM: x86: Update vPMCs when retiring branch instructions") Cc: Jim Mattson Reviewed-by: Jim Mattson Reviewed-by: Chao Gao Link: https://lore.kernel.org/r/20250919004639.1360453-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/emulate.c | 4 ++-- tools/testing/selftests/kvm/x86/pmu_counters_test.c | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 542d3664afa3..23929151a5b8 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -4330,8 +4330,8 @@ static const struct opcode opcode_table[256] = { I(DstReg | SrcMemFAddr | ModRM | No64 | Src2DS, em_lseg), G(ByteOp, group11), G(0, group11), /* 0xC8 - 0xCF */ - I(Stack | SrcImmU16 | Src2ImmByte | IsBranch, em_enter), - I(Stack | IsBranch, em_leave), + I(Stack | SrcImmU16 | Src2ImmByte, em_enter), + I(Stack, em_leave), I(ImplicitOps | SrcImmU16 | IsBranch, em_ret_far_imm), I(ImplicitOps | IsBranch, em_ret_far), D(ImplicitOps | IsBranch), DI(SrcImmByte | IsBranch, intn), diff --git a/tools/testing/selftests/kvm/x86/pmu_counters_test.c b/tools/testing/selftests/kvm/x86/pmu_counters_test.c index 8aaaf25b6111..881cce1c81b8 100644 --- a/tools/testing/selftests/kvm/x86/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86/pmu_counters_test.c @@ -14,10 +14,10 @@ #define NUM_BRANCH_INSNS_RETIRED (NUM_LOOPS) /* - * Number of instructions in each loop. 1 CLFLUSH/CLFLUSHOPT/NOP, 1 MFENCE, - * 1 LOOP. + * Number of instructions in each loop. 1 ENTER, 1 CLFLUSH/CLFLUSHOPT/NOP, + * 1 MFENCE, 1 MOV, 1 LEAVE, 1 LOOP. */ -#define NUM_INSNS_PER_LOOP 4 +#define NUM_INSNS_PER_LOOP 6 /* * Number of "extra" instructions that will be counted, i.e. the number of @@ -210,9 +210,11 @@ do { \ __asm__ __volatile__("wrmsr\n\t" \ " mov $" __stringify(NUM_LOOPS) ", %%ecx\n\t" \ "1:\n\t" \ + FEP "enter $0, $0\n\t" \ clflush "\n\t" \ "mfence\n\t" \ "mov %[m], %%eax\n\t" \ + FEP "leave\n\t" \ FEP "loop 1b\n\t" \ FEP "mov %%edi, %%ecx\n\t" \ FEP "xor %%eax, %%eax\n\t" \ From 299fad4133677b845ce962f78c9cf75bded63f61 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 8 Sep 2025 22:19:15 -0500 Subject: [PATCH 1933/2711] PCI/PM: Skip resuming to D0 if device is disconnected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a device is surprise-removed (e.g., due to a dock unplug), the PCI core unconfigures all downstream devices and sets their error state to pci_channel_io_perm_failure. This marks them as disconnected via pci_dev_is_disconnected(). During device removal, the runtime PM framework may attempt to resume the device to D0 via pm_runtime_get_sync(), which calls into pci_power_up(). Since the device is already disconnected, this resume attempt is unnecessary and results in a predictable errors like this, typically when undocking from a TBT3 or USB4 dock with PCIe tunneling: pci 0000:01:00.0: Unable to change power state from D3cold to D0, device inaccessible Avoid powering up disconnected devices by checking their status early in pci_power_up() and returning -EIO. Suggested-by: Lukas Wunner Signed-off-by: Mario Limonciello [bhelgaas: add typical message] Signed-off-by: Bjorn Helgaas Reviewed-by: Lukas Wunner Reviewed-by: Ilpo Järvinen Acked-by: Rafael J. Wysocki Link: https://patch.msgid.link/20250909031916.4143121-1-superm1@kernel.org --- drivers/pci/pci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b0f4d98036cd..036511f5b262 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1374,6 +1374,11 @@ int pci_power_up(struct pci_dev *dev) return -EIO; } + if (pci_dev_is_disconnected(dev)) { + dev->current_state = PCI_D3cold; + return -EIO; + } + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); if (PCI_POSSIBLE_ERROR(pmcsr)) { pci_err(dev, "Unable to change power state from %s to D0, device inaccessible\n", From 86bcd23df9cec9c2df520ae0982033e301d3c184 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Tue, 9 Sep 2025 07:39:52 +0700 Subject: [PATCH 1934/2711] KVM: x86: Fix hypercalls docs section number order Commit 4180bf1b655a79 ("KVM: X86: Implement "send IPI" hypercall") documents KVM_HC_SEND_IPI hypercall, yet its section number duplicates KVM_HC_CLOCK_PAIRING one (which both are 6th). Fix the numbering order so that the former should be 7th. Fixes: 4180bf1b655a ("KVM: X86: Implement "send IPI" hypercall") Signed-off-by: Bagas Sanjaya Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20250909003952.10314-1-bagasdotme@gmail.com Signed-off-by: Sean Christopherson --- Documentation/virt/kvm/x86/hypercalls.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/virt/kvm/x86/hypercalls.rst b/Documentation/virt/kvm/x86/hypercalls.rst index 10db7924720f..521ecf9a8a36 100644 --- a/Documentation/virt/kvm/x86/hypercalls.rst +++ b/Documentation/virt/kvm/x86/hypercalls.rst @@ -137,7 +137,7 @@ compute the CLOCK_REALTIME for its clock, at the same instant. Returns KVM_EOPNOTSUPP if the host does not use TSC clocksource, or if clock type is different than KVM_CLOCK_PAIRING_WALLCLOCK. -6. KVM_HC_SEND_IPI +7. KVM_HC_SEND_IPI ------------------ :Architecture: x86 @@ -158,7 +158,7 @@ corresponds to the APIC ID a2+1, and so on. Returns the number of CPUs to which the IPIs were delivered successfully. -7. KVM_HC_SCHED_YIELD +8. KVM_HC_SCHED_YIELD --------------------- :Architecture: x86 @@ -170,7 +170,7 @@ a0: destination APIC ID :Usage example: When sending a call-function IPI-many to vCPUs, yield if any of the IPI target vCPUs was preempted. -8. KVM_HC_MAP_GPA_RANGE +9. KVM_HC_MAP_GPA_RANGE ------------------------- :Architecture: x86 :Status: active From 5b87014e999903b63c6416183446bcc18aabe5ef Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Mon, 15 Sep 2025 15:43:16 -0500 Subject: [PATCH 1935/2711] x86/acpi/cstate: Remove open coded check for cpu_feature_enabled() acpi_processor_power_init_bm_check() has an open coded implementation of cpu_feature_enabled() to detect X86_FEATURE_ZEN. Switch to using cpu_feature_enabled(). Signed-off-by: Mario Limonciello (AMD) Signed-off-by: Rafael J. Wysocki --- arch/x86/kernel/acpi/cstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c index 8698d66563ed..0281703da5e2 100644 --- a/arch/x86/kernel/acpi/cstate.c +++ b/arch/x86/kernel/acpi/cstate.c @@ -89,7 +89,7 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, */ flags->bm_control = 0; } - if (c->x86_vendor == X86_VENDOR_AMD && c->x86 >= 0x17) { + if (cpu_feature_enabled(X86_FEATURE_ZEN)) { /* * For all AMD Zen or newer CPUs that support C3, caches * should not be flushed by software while entering C3 From bee278e18e641a4bc11513b0fa8f5eb2667b8a32 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 18 Sep 2025 23:20:26 +0200 Subject: [PATCH 1936/2711] dt-bindings: embedded-controller: Add Lenovo Thinkpad T14s EC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add binding for the EC found in the Thinkpad T14s Gen6 Snapdragon, which is based on the Qualcomm X1 Elite. Some of the system LEDs and extra keys are only accessible via the EC. Reviewed-by: Bryan O'Donoghue Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250918-thinkpad-t14s-ec-v5-1-ac0bc6382c5c@collabora.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../lenovo,thinkpad-t14s-ec.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/embedded-controller/lenovo,thinkpad-t14s-ec.yaml diff --git a/Documentation/devicetree/bindings/embedded-controller/lenovo,thinkpad-t14s-ec.yaml b/Documentation/devicetree/bindings/embedded-controller/lenovo,thinkpad-t14s-ec.yaml new file mode 100644 index 000000000000..c87ccb5b3086 --- /dev/null +++ b/Documentation/devicetree/bindings/embedded-controller/lenovo,thinkpad-t14s-ec.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/embedded-controller/lenovo,thinkpad-t14s-ec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lenovo Thinkpad T14s Embedded Controller + +maintainers: + - Sebastian Reichel + +description: + The Qualcomm Snapdragon-based Lenovo Thinkpad T14s has an Embedded Controller + (EC) which handles things such as keyboard backlight, LEDs or non-standard + keys. + +properties: + compatible: + const: lenovo,thinkpad-t14s-ec + + reg: + const: 0x28 + + interrupts: + maxItems: 1 + + wakeup-source: true + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - |+ + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + embedded-controller@28 { + compatible = "lenovo,thinkpad-t14s-ec"; + reg = <0x28>; + interrupts-extended = <&tlmm 66 IRQ_TYPE_LEVEL_LOW>; + wakeup-source; + }; + }; +... From 143ddfa169bbb733275b1a720bafd5a4366b3d89 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 19 Sep 2025 16:50:37 +0200 Subject: [PATCH 1937/2711] rcu: replace use of system_wq with system_percpu_wq Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. system_wq is a per-CPU worqueue, yet nothing in its name tells about that CPU affinity constraint, which is very often not required by users. Make it clear by adding a system_percpu_wq. The old wq will be kept for a few release cylces. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Reviewed-by: Frederic Weisbecker Signed-off-by: Paul E. McKenney --- kernel/rcu/tasks.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h index f92443561d36..2dc044fd126e 100644 --- a/kernel/rcu/tasks.h +++ b/kernel/rcu/tasks.h @@ -553,13 +553,13 @@ static void rcu_tasks_invoke_cbs(struct rcu_tasks *rtp, struct rcu_tasks_percpu rtpcp_next = rtp->rtpcp_array[index]; if (rtpcp_next->cpu < smp_load_acquire(&rtp->percpu_dequeue_lim)) { cpuwq = rcu_cpu_beenfullyonline(rtpcp_next->cpu) ? rtpcp_next->cpu : WORK_CPU_UNBOUND; - queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work); + queue_work_on(cpuwq, system_percpu_wq, &rtpcp_next->rtp_work); index++; if (index < num_possible_cpus()) { rtpcp_next = rtp->rtpcp_array[index]; if (rtpcp_next->cpu < smp_load_acquire(&rtp->percpu_dequeue_lim)) { cpuwq = rcu_cpu_beenfullyonline(rtpcp_next->cpu) ? rtpcp_next->cpu : WORK_CPU_UNBOUND; - queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work); + queue_work_on(cpuwq, system_percpu_wq, &rtpcp_next->rtp_work); } } } From 499d48f75b230522f4aa5aa4b9cc3c5b1594e1af Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 19 Sep 2025 16:50:38 +0200 Subject: [PATCH 1938/2711] rcu: WQ_PERCPU added to alloc_workqueue users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. alloc_workqueue() treats all queues as per-CPU by default, while unbound workqueues must opt-in via WQ_UNBOUND. This default is suboptimal: most workloads benefit from unbound queues, allowing the scheduler to place worker threads where they’re needed and reducing noise when CPUs are isolated. This patch adds a new WQ_PERCPU flag to explicitly request the use of the per-CPU behavior. Both flags coexist for one release cycle to allow callers to transition their calls. Once migration is complete, WQ_UNBOUND can be removed and unbound will become the implicit default. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. All existing users have been updated accordingly. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Reviewed-by: Frederic Weisbecker Signed-off-by: Paul E. McKenney --- kernel/rcu/tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 1291e0761d70..01e76c6b2c13 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -4890,7 +4890,7 @@ void __init rcu_init(void) rcutree_online_cpu(cpu); /* Create workqueue for Tree SRCU and for expedited GPs. */ - rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_MEM_RECLAIM, 0); + rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_MEM_RECLAIM | WQ_PERCPU, 0); WARN_ON(!rcu_gp_wq); sync_wq = alloc_workqueue("sync_wq", WQ_MEM_RECLAIM, 0); From 82c427bc935aa5b91d0cabbbc062e71132be2bb8 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 19 Sep 2025 16:50:39 +0200 Subject: [PATCH 1939/2711] rcu: WQ_UNBOUND added to sync_wq workqueue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. alloc_workqueue() treats all queues as per-CPU by default, while unbound workqueues must opt-in via WQ_UNBOUND. This default is suboptimal: most workloads benefit from unbound queues, allowing the scheduler to place worker threads where they’re needed and reducing noise when CPUs are isolated. This change add the WQ_UNBOUND flag to sync_wq, to make explicit this workqueue can be unbound and that it does not benefit from per-cpu work. Once migration is complete, WQ_UNBOUND can be removed and unbound will become the implicit default. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Reviewed-by: Frederic Weisbecker Signed-off-by: Paul E. McKenney --- kernel/rcu/tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 01e76c6b2c13..31690ffa452a 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -4893,7 +4893,7 @@ void __init rcu_init(void) rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_MEM_RECLAIM | WQ_PERCPU, 0); WARN_ON(!rcu_gp_wq); - sync_wq = alloc_workqueue("sync_wq", WQ_MEM_RECLAIM, 0); + sync_wq = alloc_workqueue("sync_wq", WQ_MEM_RECLAIM | WQ_UNBOUND, 0); WARN_ON(!sync_wq); /* Respect if explicitly disabled via a boot parameter. */ From 7fdd04e15ad79cc2294b9e722d6282357da0b53a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 16 Jul 2025 14:38:30 -0500 Subject: [PATCH 1940/2711] coresight: tnoc: Fix a NULL vs IS_ERR() bug in probe The devm_ioremap_resource() function returns error pointers on error. It never returns NULL. Update the error checking to match. Fixes: e54a52a28a36 ("coresight: add coresight Trace Network On Chip driver") Signed-off-by: Dan Carpenter Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/7bd9fae8-a15f-412a-8800-ce47acf0b5ce@sabinyo.mountain --- drivers/hwtracing/coresight/coresight-tnoc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c index 0e4164707eea..d542df46ea39 100644 --- a/drivers/hwtracing/coresight/coresight-tnoc.c +++ b/drivers/hwtracing/coresight/coresight-tnoc.c @@ -183,8 +183,8 @@ static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id) dev_set_drvdata(dev, drvdata); drvdata->base = devm_ioremap_resource(dev, &adev->res); - if (!drvdata->base) - return -ENOMEM; + if (IS_ERR(drvdata->base)) + return PTR_ERR(drvdata->base); spin_lock_init(&drvdata->spinlock); From 21dd3f8bc24b6adc57f09fff5430b0039dd00492 Mon Sep 17 00:00:00 2001 From: Yeoreum Yun Date: Wed, 11 Jun 2025 11:30:25 +0100 Subject: [PATCH 1941/2711] coresight: fix indentation error in cscfg_remove_owned_csdev_configs() Fix wrong indentation in cscfg_remove_owned_csdev_configs() Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202506102238.XQfScl5x-lkp@intel.com/ Fixes: 53b9e2659719 ("coresight: holding cscfg_csdev_lock while removing cscfg from csdev") Signed-off-by: Yeoreum Yun Reviewed-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250611103025.939020-1-yeoreum.yun@arm.com --- drivers/hwtracing/coresight/coresight-syscfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 83dad24e0116..6836b05986e8 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -395,7 +395,7 @@ static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, voi if (list_empty(&csdev->config_csdev_list)) return; - guard(raw_spinlock_irqsave)(&csdev->cscfg_csdev_lock); + guard(raw_spinlock_irqsave)(&csdev->cscfg_csdev_lock); list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) { if (config_csdev->config_desc->load_owner == load_owner) From dcdc42f5dcf9b9197c51246c62966e2d54a033d8 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Tue, 12 Aug 2025 01:24:45 -0700 Subject: [PATCH 1942/2711] coresight-etm4x: Conditionally access register TRCEXTINSELR The TRCEXTINSELR is only implemented if TRCIDR5.NUMEXTINSEL > 0. To avoid invalid accesses, introduce a check on numextinsel (derived from TRCIDR5[11:9]) before reading or writing to this register. Fixes: f5bd523690d2 ("coresight: etm4x: Convert all register accesses") Signed-off-by: Yuanfang Zhang Reviewed-by: James Clark Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250812-trcextinselr_issue-v2-1-e6eb121dfcf4@oss.qualcomm.com --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 11 ++++++++--- drivers/hwtracing/coresight/coresight-etm4x.h | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index cbea200489c8..b4f1834a1af1 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -529,7 +529,8 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata) etm4x_relaxed_write32(csa, config->seq_rst, TRCSEQRSTEVR); etm4x_relaxed_write32(csa, config->seq_state, TRCSEQSTR); } - etm4x_relaxed_write32(csa, config->ext_inp, TRCEXTINSELR); + if (drvdata->numextinsel) + etm4x_relaxed_write32(csa, config->ext_inp, TRCEXTINSELR); for (i = 0; i < drvdata->nr_cntr; i++) { etm4x_relaxed_write32(csa, config->cntrldvr[i], TRCCNTRLDVRn(i)); etm4x_relaxed_write32(csa, config->cntr_ctrl[i], TRCCNTCTLRn(i)); @@ -1424,6 +1425,7 @@ static void etm4_init_arch_data(void *info) etmidr5 = etm4x_relaxed_read32(csa, TRCIDR5); /* NUMEXTIN, bits[8:0] number of external inputs implemented */ drvdata->nr_ext_inp = FIELD_GET(TRCIDR5_NUMEXTIN_MASK, etmidr5); + drvdata->numextinsel = FIELD_GET(TRCIDR5_NUMEXTINSEL_MASK, etmidr5); /* TRACEIDSIZE, bits[21:16] indicates the trace ID width */ drvdata->trcid_size = FIELD_GET(TRCIDR5_TRACEIDSIZE_MASK, etmidr5); /* ATBTRIG, bit[22] implementation can support ATB triggers? */ @@ -1853,7 +1855,9 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) state->trcseqrstevr = etm4x_read32(csa, TRCSEQRSTEVR); state->trcseqstr = etm4x_read32(csa, TRCSEQSTR); } - state->trcextinselr = etm4x_read32(csa, TRCEXTINSELR); + + if (drvdata->numextinsel) + state->trcextinselr = etm4x_read32(csa, TRCEXTINSELR); for (i = 0; i < drvdata->nr_cntr; i++) { state->trccntrldvr[i] = etm4x_read32(csa, TRCCNTRLDVRn(i)); @@ -1985,7 +1989,8 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata) etm4x_relaxed_write32(csa, state->trcseqrstevr, TRCSEQRSTEVR); etm4x_relaxed_write32(csa, state->trcseqstr, TRCSEQSTR); } - etm4x_relaxed_write32(csa, state->trcextinselr, TRCEXTINSELR); + if (drvdata->numextinsel) + etm4x_relaxed_write32(csa, state->trcextinselr, TRCEXTINSELR); for (i = 0; i < drvdata->nr_cntr; i++) { etm4x_relaxed_write32(csa, state->trccntrldvr[i], TRCCNTRLDVRn(i)); diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index ac649515054d..823914fefa90 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -162,6 +162,7 @@ #define TRCIDR4_NUMVMIDC_MASK GENMASK(31, 28) #define TRCIDR5_NUMEXTIN_MASK GENMASK(8, 0) +#define TRCIDR5_NUMEXTINSEL_MASK GENMASK(11, 9) #define TRCIDR5_TRACEIDSIZE_MASK GENMASK(21, 16) #define TRCIDR5_ATBTRIG BIT(22) #define TRCIDR5_LPOVERRIDE BIT(23) @@ -999,6 +1000,7 @@ struct etmv4_drvdata { u8 nr_cntr; u8 nr_ext_inp; u8 numcidc; + u8 numextinsel; u8 numvmidc; u8 nrseqstate; u8 nr_event; From 8a79026926b329d4ab0c6d0921373a80ec8aab6e Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 31 Jul 2025 13:23:37 +0100 Subject: [PATCH 1943/2711] coresight: tmc: Support atclk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The atclk is an optional clock for the CoreSight TMC, but the driver misses to initialize it. In most cases, TMC shares the atclk clock with other CoreSight components. Since these components enable the clock before the TMC device is initialized, the TMC continues properly, which is why we don’t observe any lockup issues. This change enables atclk in probe of the TMC driver. Given the clock is optional, it is possible to return NULL if the clock does not exist. IS_ERR() is tolerant for this case. Dynamically disable and enable atclk during suspend and resume. The clock pointers will never be error values if the driver has successfully probed, and the case of a NULL pointer case will be handled by the clock core layer. The driver data is always valid after probe. Therefore, remove the related checks. Also in the resume flow adds error handling. Fixes: bc4bf7fe98da ("coresight-tmc: add CoreSight TMC driver") Reviewed-by: Anshuman Khandual Reviewed-by: Yeoreum Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-1-1dfe10bb3f6f@arm.com --- .../hwtracing/coresight/coresight-tmc-core.c | 22 ++++++++++++++----- drivers/hwtracing/coresight/coresight-tmc.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index be964656be93..85ba037c27f7 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -779,6 +779,10 @@ static int __tmc_probe(struct device *dev, struct resource *res) struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL; + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); + ret = -ENOMEM; /* Validity for the resource is already checked by the AMBA core */ @@ -1010,18 +1014,26 @@ static int tmc_runtime_suspend(struct device *dev) { struct tmc_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk); + return 0; } static int tmc_runtime_resume(struct device *dev) { struct tmc_drvdata *drvdata = dev_get_drvdata(dev); + int ret; - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); - return 0; + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret; + + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 6541a27a018e..cbb4ba439158 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -210,6 +210,7 @@ struct tmc_resrv_buf { /** * struct tmc_drvdata - specifics associated to an TMC component + * @atclk: optional clock for the core parts of the TMC. * @pclk: APB clock if present, otherwise NULL * @base: memory mapped base address for this component. * @csdev: component vitals needed by the framework. @@ -244,6 +245,7 @@ struct tmc_resrv_buf { * Used by ETR/ETF. */ struct tmc_drvdata { + struct clk *atclk; struct clk *pclk; void __iomem *base; struct coresight_device *csdev; From 5483624effea2e893dc0df6248253a6a2a085451 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 31 Jul 2025 13:23:38 +0100 Subject: [PATCH 1944/2711] coresight: catu: Support atclk The atclk is an optional clock for the CoreSight CATU, but the driver misses to initialize it. This change enables atclk in probe of the CATU driver, and dynamically control the clock during suspend and resume. The checks for driver data and clocks in suspend and resume are not needed, remove them. Add error handling in the resume function. Fixes: fcacb5c154ba ("coresight: Introduce support for Coresight Address Translation Unit") Reviewed-by: Anshuman Khandual Reviewed-by: Yeoreum Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-2-1dfe10bb3f6f@arm.com --- drivers/hwtracing/coresight/coresight-catu.c | 22 +++++++++++++++----- drivers/hwtracing/coresight/coresight-catu.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index 5058432233da..af2a55f0c907 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -520,6 +520,10 @@ static int __catu_probe(struct device *dev, struct resource *res) struct coresight_platform_data *pdata = NULL; void __iomem *base; + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); + catu_desc.name = coresight_alloc_device_name(&catu_devs, dev); if (!catu_desc.name) return -ENOMEM; @@ -668,18 +672,26 @@ static int catu_runtime_suspend(struct device *dev) { struct catu_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk); + return 0; } static int catu_runtime_resume(struct device *dev) { struct catu_drvdata *drvdata = dev_get_drvdata(dev); + int ret; - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); - return 0; + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret; + + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif diff --git a/drivers/hwtracing/coresight/coresight-catu.h b/drivers/hwtracing/coresight/coresight-catu.h index 755776cd19c5..6e6b7aac206d 100644 --- a/drivers/hwtracing/coresight/coresight-catu.h +++ b/drivers/hwtracing/coresight/coresight-catu.h @@ -62,6 +62,7 @@ struct catu_drvdata { struct clk *pclk; + struct clk *atclk; void __iomem *base; struct coresight_device *csdev; int irq; From 40c0cdc9cbbebae9f43bef1cab9ce152318d0cce Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 31 Jul 2025 13:23:39 +0100 Subject: [PATCH 1945/2711] coresight: etm4x: Support atclk The atclk is an optional clock for the CoreSight ETMv4, but the driver misses to initialize it. This change enables atclk in probe of the ETMv4 driver, and dynamically control the clock during suspend and resume. No need to check the driver data and clock pointer in the runtime suspend and resume, so remove checks. And add error handling in the resume function. Add a minor fix to the comment format when adding the atclk field. Fixes: 2e1cdfe184b5 ("coresight-etm4x: Adding CoreSight ETM4x driver") Reviewed-by: Anshuman Khandual Reviewed-by: Yeoreum Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-3-1dfe10bb3f6f@arm.com --- .../coresight/coresight-etm4x-core.c | 20 ++++++++++++++----- drivers/hwtracing/coresight/coresight-etm4x.h | 4 +++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index b4f1834a1af1..81f20a167e00 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2221,6 +2221,10 @@ static int etm4_probe(struct device *dev) if (WARN_ON(!drvdata)) return -ENOMEM; + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); + if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE) pm_save_enable = coresight_loses_context_with_cpu(dev) ? PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER; @@ -2469,8 +2473,8 @@ static int etm4_runtime_suspend(struct device *dev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata->pclk && !IS_ERR(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk); return 0; } @@ -2478,11 +2482,17 @@ static int etm4_runtime_suspend(struct device *dev) static int etm4_runtime_resume(struct device *dev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); + int ret; - if (drvdata->pclk && !IS_ERR(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret; - return 0; + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index 823914fefa90..13ec9ecef46f 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -920,7 +920,8 @@ struct etmv4_save_state { /** * struct etm4_drvdata - specifics associated to an ETM component - * @pclk APB clock if present, otherwise NULL + * @pclk: APB clock if present, otherwise NULL + * @atclk: Optional clock for the core parts of the ETMv4. * @base: Memory mapped base address for this component. * @csdev: Component vitals needed by the framework. * @spinlock: Only one at a time pls. @@ -989,6 +990,7 @@ struct etmv4_save_state { */ struct etmv4_drvdata { struct clk *pclk; + struct clk *atclk; void __iomem *base; struct coresight_device *csdev; raw_spinlock_t spinlock; From 1abc1b212effe920f4729353880c8e03f1d76b4b Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 31 Jul 2025 13:23:40 +0100 Subject: [PATCH 1946/2711] coresight: Appropriately disable programming clocks Some CoreSight components have programming clocks (pclk) and are enabled using clk_get() and clk_prepare_enable(). However, in many cases, these clocks are not disabled when modules exit and only released by clk_put(). To fix the issue, this commit refactors programming clock by replacing clk_get() and clk_prepare_enable() with devm_clk_get_optional_enabled() for enabling APB clock. If the "apb_pclk" clock is not found, a NULL pointer is returned, and the function proceeds to attempt enabling the "apb" clock. Since ACPI platforms rely on firmware to manage clocks, returning a NULL pointer in this case leaves clock management to the firmware rather than the driver. This effectively avoids a clock imbalance issue during module removal - where the clock could be disabled twice: once during the ACPI runtime suspend and again during the devm resource release. Callers are updated to reuse the returned error value. With the change, programming clocks are managed as resources in driver model layer, allowing clock cleanup to be handled automatically. As a result, manual cleanup operations are no longer needed and are removed from the Coresight drivers. Fixes: 73d779a03a76 ("coresight: etm4x: Change etm4_platform_driver driver for MMIO devices") Reviewed-by: Yeoreum Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-4-1dfe10bb3f6f@arm.com --- drivers/hwtracing/coresight/coresight-catu.c | 9 ++------ .../hwtracing/coresight/coresight-cpu-debug.c | 6 +---- .../hwtracing/coresight/coresight-ctcu-core.c | 10 ++------- .../coresight/coresight-etm4x-core.c | 9 ++------ .../hwtracing/coresight/coresight-funnel.c | 6 +---- .../coresight/coresight-replicator.c | 6 +---- drivers/hwtracing/coresight/coresight-stm.c | 4 +--- .../hwtracing/coresight/coresight-tmc-core.c | 4 +--- drivers/hwtracing/coresight/coresight-tpiu.c | 4 +--- include/linux/coresight.h | 22 ++++++++----------- 10 files changed, 21 insertions(+), 59 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index af2a55f0c907..4c345ff2cff1 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -636,7 +636,7 @@ static int catu_platform_probe(struct platform_device *pdev) drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); @@ -645,11 +645,8 @@ static int catu_platform_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, drvdata); ret = __catu_probe(&pdev->dev, res); pm_runtime_put(&pdev->dev); - if (ret) { + if (ret) pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); - } return ret; } @@ -663,8 +660,6 @@ static void catu_platform_remove(struct platform_device *pdev) __catu_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); } #ifdef CONFIG_PM diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index a871d997330b..e39dfb886688 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -699,7 +699,7 @@ static int debug_platform_probe(struct platform_device *pdev) drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk); dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); @@ -710,8 +710,6 @@ static int debug_platform_probe(struct platform_device *pdev) if (ret) { pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); } return ret; } @@ -725,8 +723,6 @@ static void debug_platform_remove(struct platform_device *pdev) __debug_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); } #ifdef CONFIG_ACPI diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c index c6bafc96db96..de279efe3405 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu-core.c +++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c @@ -209,7 +209,7 @@ static int ctcu_probe(struct platform_device *pdev) drvdata->apb_clk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->apb_clk)) - return -ENODEV; + return PTR_ERR(drvdata->apb_clk); cfgs = of_device_get_match_data(dev); if (cfgs) { @@ -233,12 +233,8 @@ static int ctcu_probe(struct platform_device *pdev) desc.access = CSDEV_ACCESS_IOMEM(base); drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) { - if (!IS_ERR_OR_NULL(drvdata->apb_clk)) - clk_put(drvdata->apb_clk); - + if (IS_ERR(drvdata->csdev)) return PTR_ERR(drvdata->csdev); - } return 0; } @@ -275,8 +271,6 @@ static void ctcu_platform_remove(struct platform_device *pdev) ctcu_remove(pdev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->apb_clk)) - clk_put(drvdata->apb_clk); } #ifdef CONFIG_PM diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 81f20a167e00..4b98a7bf4cb7 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2309,14 +2309,12 @@ static int etm4_probe_platform_dev(struct platform_device *pdev) drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk); if (res) { drvdata->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(drvdata->base)) { - clk_put(drvdata->pclk); + if (IS_ERR(drvdata->base)) return PTR_ERR(drvdata->base); - } } dev_set_drvdata(&pdev->dev, drvdata); @@ -2423,9 +2421,6 @@ static void etm4_remove_platform_dev(struct platform_device *pdev) if (drvdata) etm4_remove_dev(drvdata); pm_runtime_disable(&pdev->dev); - - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); } static const struct amba_id etm4_ids[] = { diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index b1922dbe9292..36fc4e991458 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -240,7 +240,7 @@ static int funnel_probe(struct device *dev, struct resource *res) drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk); /* * Map the device base for dynamic-funnel, which has been @@ -284,8 +284,6 @@ static int funnel_probe(struct device *dev, struct resource *res) out_disable_clk: if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) clk_disable_unprepare(drvdata->atclk); - if (ret && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); return ret; } @@ -355,8 +353,6 @@ static void funnel_platform_remove(struct platform_device *pdev) funnel_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); } static const struct of_device_id funnel_match[] = { diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 06efd2b01a0f..6dd24eb10a94 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -247,7 +247,7 @@ static int replicator_probe(struct device *dev, struct resource *res) drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk); /* * Map the device base for dynamic-replicator, which has been @@ -296,8 +296,6 @@ static int replicator_probe(struct device *dev, struct resource *res) out_disable_clk: if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) clk_disable_unprepare(drvdata->atclk); - if (ret && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); return ret; } @@ -335,8 +333,6 @@ static void replicator_platform_remove(struct platform_device *pdev) replicator_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); } #ifdef CONFIG_PM diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 464b0c85c3f7..f2de16e4d3b4 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -851,7 +851,7 @@ static int __stm_probe(struct device *dev, struct resource *res) drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk); dev_set_drvdata(dev, drvdata); base = devm_ioremap_resource(dev, res); @@ -1033,8 +1033,6 @@ static void stm_platform_remove(struct platform_device *pdev) __stm_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); } #ifdef CONFIG_ACPI diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 85ba037c27f7..519f22542807 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -981,7 +981,7 @@ static int tmc_platform_probe(struct platform_device *pdev) drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk); dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); @@ -1005,8 +1005,6 @@ static void tmc_platform_remove(struct platform_device *pdev) __tmc_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); } #ifdef CONFIG_PM diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 3e0159288428..b2559c6fac6d 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -153,7 +153,7 @@ static int __tpiu_probe(struct device *dev, struct resource *res) drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) - return -ENODEV; + return PTR_ERR(drvdata->pclk); dev_set_drvdata(dev, drvdata); /* Validity for the resource is already checked by the AMBA core */ @@ -293,8 +293,6 @@ static void tpiu_platform_remove(struct platform_device *pdev) __tpiu_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!IS_ERR_OR_NULL(drvdata->pclk)) - clk_put(drvdata->pclk); } #ifdef CONFIG_ACPI diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 4ac65c68bbf4..1e652e157841 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -6,6 +6,7 @@ #ifndef _LINUX_CORESIGHT_H #define _LINUX_CORESIGHT_H +#include #include #include #include @@ -480,26 +481,21 @@ static inline bool is_coresight_device(void __iomem *base) * Returns: * * clk - Clock is found and enabled - * NULL - clock is not found + * NULL - Clock is controlled by firmware (ACPI device only) * ERROR - Clock is found but failed to enable */ static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) { struct clk *pclk; - int ret; - pclk = clk_get(dev, "apb_pclk"); - if (IS_ERR(pclk)) { - pclk = clk_get(dev, "apb"); - if (IS_ERR(pclk)) - return NULL; - } + /* Firmware controls clocks for an ACPI device. */ + if (has_acpi_companion(dev)) + return NULL; + + pclk = devm_clk_get_optional_enabled(dev, "apb_pclk"); + if (!pclk) + pclk = devm_clk_get_optional_enabled(dev, "apb"); - ret = clk_prepare_enable(pclk); - if (ret) { - clk_put(pclk); - return ERR_PTR(ret); - } return pclk; } From a8f2d480f19d912f15dbac7038cd578d6b8b4d74 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 31 Jul 2025 13:23:41 +0100 Subject: [PATCH 1947/2711] coresight: Appropriately disable trace bus clocks Some CoreSight components have trace bus clocks 'atclk' and are enabled using clk_prepare_enable(). These clocks are not disabled when modules exit. As atclk is optional, use devm_clk_get_optional_enabled() to manage it. The benefit is the driver model layer can automatically disable and release clocks. Check the returned value with IS_ERR() to detect errors but leave the NULL pointer case if the clock is not found. And remove the error handling codes which are no longer needed. Fixes: d1839e687773 ("coresight: etm: retrieve and handle atclk") Reviewed-by: Anshuman Khandual Reviewed-by: Yeoreum Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-5-1dfe10bb3f6f@arm.com --- drivers/hwtracing/coresight/coresight-etb10.c | 10 +++--- .../coresight/coresight-etm3x-core.c | 9 ++--- .../hwtracing/coresight/coresight-funnel.c | 36 ++++++------------- .../coresight/coresight-replicator.c | 34 ++++++------------ drivers/hwtracing/coresight/coresight-stm.c | 9 ++--- drivers/hwtracing/coresight/coresight-tpiu.c | 10 ++---- 6 files changed, 34 insertions(+), 74 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index d5efb085b30d..8e81b41eb222 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -730,12 +730,10 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata) return -ENOMEM; - drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); + dev_set_drvdata(dev, drvdata); /* validity for the resource is already checked by the AMBA core */ diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index 1c6204e14422..baba2245b1df 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -832,12 +832,9 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&drvdata->spinlock); - drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); drvdata->cpu = coresight_get_cpu(dev); if (drvdata->cpu < 0) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 36fc4e991458..b044a4125310 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -213,7 +213,6 @@ ATTRIBUTE_GROUPS(coresight_funnel); static int funnel_probe(struct device *dev, struct resource *res) { - int ret; void __iomem *base; struct coresight_platform_data *pdata = NULL; struct funnel_drvdata *drvdata; @@ -231,12 +230,9 @@ static int funnel_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM; - drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) @@ -248,10 +244,8 @@ static int funnel_probe(struct device *dev, struct resource *res) */ if (res) { base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto out_disable_clk; - } + if (IS_ERR(base)) + return PTR_ERR(base); drvdata->base = base; desc.groups = coresight_funnel_groups; desc.access = CSDEV_ACCESS_IOMEM(base); @@ -261,10 +255,9 @@ static int funnel_probe(struct device *dev, struct resource *res) dev_set_drvdata(dev, drvdata); pdata = coresight_get_platform_data(dev); - if (IS_ERR(pdata)) { - ret = PTR_ERR(pdata); - goto out_disable_clk; - } + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + dev->platform_data = pdata; raw_spin_lock_init(&drvdata->spinlock); @@ -274,17 +267,10 @@ static int funnel_probe(struct device *dev, struct resource *res) desc.pdata = pdata; desc.dev = dev; drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) { - ret = PTR_ERR(drvdata->csdev); - goto out_disable_clk; - } + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev); - ret = 0; - -out_disable_clk: - if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); - return ret; + return 0; } static int funnel_remove(struct device *dev) diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 6dd24eb10a94..9e8bd36e7a9a 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -219,7 +219,6 @@ static const struct attribute_group *replicator_groups[] = { static int replicator_probe(struct device *dev, struct resource *res) { - int ret = 0; struct coresight_platform_data *pdata = NULL; struct replicator_drvdata *drvdata; struct coresight_desc desc = { 0 }; @@ -238,12 +237,9 @@ static int replicator_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM; - drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) @@ -255,10 +251,8 @@ static int replicator_probe(struct device *dev, struct resource *res) */ if (res) { base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto out_disable_clk; - } + if (IS_ERR(base)) + return PTR_ERR(base); drvdata->base = base; desc.groups = replicator_groups; desc.access = CSDEV_ACCESS_IOMEM(base); @@ -272,10 +266,8 @@ static int replicator_probe(struct device *dev, struct resource *res) dev_set_drvdata(dev, drvdata); pdata = coresight_get_platform_data(dev); - if (IS_ERR(pdata)) { - ret = PTR_ERR(pdata); - goto out_disable_clk; - } + if (IS_ERR(pdata)) + return PTR_ERR(pdata); dev->platform_data = pdata; raw_spin_lock_init(&drvdata->spinlock); @@ -286,17 +278,11 @@ static int replicator_probe(struct device *dev, struct resource *res) desc.dev = dev; drvdata->csdev = coresight_register(&desc); - if (IS_ERR(drvdata->csdev)) { - ret = PTR_ERR(drvdata->csdev); - goto out_disable_clk; - } + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev); replicator_reset(drvdata); - -out_disable_clk: - if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); - return ret; + return 0; } static int replicator_remove(struct device *dev) diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index f2de16e4d3b4..275d67b91dfd 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -842,12 +842,9 @@ static int __stm_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM; - drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index b2559c6fac6d..8d6179c83e5d 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -128,7 +128,6 @@ static const struct coresight_ops tpiu_cs_ops = { static int __tpiu_probe(struct device *dev, struct resource *res) { - int ret; void __iomem *base; struct coresight_platform_data *pdata = NULL; struct tpiu_drvdata *drvdata; @@ -144,12 +143,9 @@ static int __tpiu_probe(struct device *dev, struct resource *res) spin_lock_init(&drvdata->spinlock); - drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); drvdata->pclk = coresight_get_enable_apb_pclk(dev); if (IS_ERR(drvdata->pclk)) From d091c6312561821f216ced63a7ad17c946b6d335 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 31 Jul 2025 13:23:42 +0100 Subject: [PATCH 1948/2711] coresight: Avoid enable programming clock duplicately The programming clock is enabled by AMBA bus driver before a dynamic probe. As a result, a CoreSight driver may redundantly enable the same clock. To avoid this, add a check for device type and skip enabling the programming clock for AMBA devices. The returned NULL pointer will be tolerated by the drivers. Fixes: 73d779a03a76 ("coresight: etm4x: Change etm4_platform_driver driver for MMIO devices") Reviewed-by: Anshuman Khandual Reviewed-by: Yeoreum Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-6-1dfe10bb3f6f@arm.com --- include/linux/coresight.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 1e652e157841..bb49080ec8f9 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -481,20 +481,23 @@ static inline bool is_coresight_device(void __iomem *base) * Returns: * * clk - Clock is found and enabled - * NULL - Clock is controlled by firmware (ACPI device only) + * NULL - Clock is controlled by firmware (ACPI device only) or when managed + * by the AMBA bus driver instead * ERROR - Clock is found but failed to enable */ static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) { - struct clk *pclk; + struct clk *pclk = NULL; /* Firmware controls clocks for an ACPI device. */ if (has_acpi_companion(dev)) return NULL; - pclk = devm_clk_get_optional_enabled(dev, "apb_pclk"); - if (!pclk) - pclk = devm_clk_get_optional_enabled(dev, "apb"); + if (!dev_is_amba(dev)) { + pclk = devm_clk_get_optional_enabled(dev, "apb_pclk"); + if (!pclk) + pclk = devm_clk_get_optional_enabled(dev, "apb"); + } return pclk; } From fbe7514a7912959e384acf108931ac1bfbb16466 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 31 Jul 2025 13:23:43 +0100 Subject: [PATCH 1949/2711] coresight: Consolidate clock enabling CoreSight drivers enable pclk and atclk conditionally. For example, pclk is only enabled in the static probe, while atclk is an optional clock that it is enabled for both dynamic and static probes, if it is present. In the current CoreSight drivers, these two clocks are initialized separately. This causes complex and duplicate codes. CoreSight drivers are refined so that clocks are initialized in one go. For this purpose, this commit renames coresight_get_enable_apb_pclk() to coresight_get_enable_clocks() and encapsulates clock initialization logic: - If a clock is initialized successfully, its clock pointer is assigned to the double pointer passed as an argument. - For ACPI devices, clocks are controlled by firmware, directly bail out. - Skip enabling pclk for an AMBA device. - If atclk is not found, the corresponding double pointer is set to NULL. The function returns Success (0) to guide callers can proceed with no error. - Otherwise, an error number is returned for failures. The function became complex, move it from the header to the CoreSight core layer and the symbol is exported. Added comments for recording details. Suggested-by: Suzuki K Poulose Reviewed-by: Anshuman Khandual Reviewed-by: Yeoreum Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-7-1dfe10bb3f6f@arm.com --- drivers/hwtracing/coresight/coresight-catu.c | 10 ++-- drivers/hwtracing/coresight/coresight-core.c | 48 +++++++++++++++++++ .../hwtracing/coresight/coresight-cpu-debug.c | 8 ++-- .../hwtracing/coresight/coresight-ctcu-core.c | 8 ++-- .../coresight/coresight-etm4x-core.c | 11 ++--- .../hwtracing/coresight/coresight-funnel.c | 11 ++--- .../coresight/coresight-replicator.c | 11 ++--- drivers/hwtracing/coresight/coresight-stm.c | 9 ++-- .../hwtracing/coresight/coresight-tmc-core.c | 10 ++-- drivers/hwtracing/coresight/coresight-tpiu.c | 10 ++-- include/linux/coresight.h | 30 +----------- 11 files changed, 83 insertions(+), 83 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index 4c345ff2cff1..0f476a0cbd74 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -520,9 +520,9 @@ static int __catu_probe(struct device *dev, struct resource *res) struct coresight_platform_data *pdata = NULL; void __iomem *base; - drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret; catu_desc.name = coresight_alloc_device_name(&catu_devs, dev); if (!catu_desc.name) @@ -634,10 +634,6 @@ static int catu_platform_probe(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); - pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 1accd7cbd54b..3267192f0c1c 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -3,6 +3,7 @@ * Copyright (c) 2012, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -1700,6 +1701,53 @@ int coresight_etm_get_trace_id(struct coresight_device *csdev, enum cs_mode mode } EXPORT_SYMBOL_GPL(coresight_etm_get_trace_id); +/* + * Attempt to find and enable programming clock (pclk) and trace clock (atclk) + * for the given device. + * + * For ACPI devices, clocks are controlled by firmware, so bail out early in + * this case. Also, skip enabling pclk if the clock is managed by the AMBA + * bus driver instead. + * + * atclk is an optional clock, it will be only enabled when it is existed. + * Otherwise, a NULL pointer will be returned to caller. + * + * Returns: '0' on Success; Error code otherwise. + */ +int coresight_get_enable_clocks(struct device *dev, struct clk **pclk, + struct clk **atclk) +{ + WARN_ON(!pclk); + + if (has_acpi_companion(dev)) + return 0; + + if (!dev_is_amba(dev)) { + /* + * "apb_pclk" is the default clock name for an Arm Primecell + * peripheral, while "apb" is used only by the CTCU driver. + * + * For easier maintenance, CoreSight drivers should use + * "apb_pclk" as the programming clock name. + */ + *pclk = devm_clk_get_optional_enabled(dev, "apb_pclk"); + if (!*pclk) + *pclk = devm_clk_get_optional_enabled(dev, "apb"); + if (IS_ERR(*pclk)) + return PTR_ERR(*pclk); + } + + /* Initialization of atclk is skipped if it is a NULL pointer. */ + if (atclk) { + *atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(*atclk)) + return PTR_ERR(*atclk); + } + + return 0; +} +EXPORT_SYMBOL_GPL(coresight_get_enable_clocks); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Pratik Patel "); MODULE_AUTHOR("Mathieu Poirier "); diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index e39dfb886688..5f6db2fb95d4 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -566,6 +566,10 @@ static int __debug_probe(struct device *dev, struct resource *res) void __iomem *base; int ret; + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, NULL); + if (ret) + return ret; + drvdata->cpu = coresight_get_cpu(dev); if (drvdata->cpu < 0) return drvdata->cpu; @@ -697,10 +701,6 @@ static int debug_platform_probe(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); - dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c index de279efe3405..75b5114ef652 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu-core.c +++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c @@ -188,7 +188,7 @@ static int ctcu_probe(struct platform_device *pdev) const struct ctcu_config *cfgs; struct ctcu_drvdata *drvdata; void __iomem *base; - int i; + int i, ret; desc.name = coresight_alloc_device_name(&ctcu_devs, dev); if (!desc.name) @@ -207,9 +207,9 @@ static int ctcu_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - drvdata->apb_clk = coresight_get_enable_apb_pclk(dev); - if (IS_ERR(drvdata->apb_clk)) - return PTR_ERR(drvdata->apb_clk); + ret = coresight_get_enable_clocks(dev, &drvdata->apb_clk, NULL); + if (ret) + return ret; cfgs = of_device_get_match_data(dev); if (cfgs) { diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 4b98a7bf4cb7..020f070bf17d 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2217,13 +2217,14 @@ static int etm4_probe(struct device *dev) struct csdev_access access = { 0 }; struct etm4_init_arg init_arg = { 0 }; struct etm4_init_arg *delayed; + int ret; if (WARN_ON(!drvdata)) return -ENOMEM; - drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret; if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE) pm_save_enable = coresight_loses_context_with_cpu(dev) ? @@ -2307,10 +2308,6 @@ static int etm4_probe_platform_dev(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); - if (res) { drvdata->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(drvdata->base)) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index b044a4125310..02e0dc678a32 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -217,6 +217,7 @@ static int funnel_probe(struct device *dev, struct resource *res) struct coresight_platform_data *pdata = NULL; struct funnel_drvdata *drvdata; struct coresight_desc desc = { 0 }; + int ret; if (is_of_node(dev_fwnode(dev)) && of_device_is_compatible(dev->of_node, "arm,coresight-funnel")) @@ -230,13 +231,9 @@ static int funnel_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM; - drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); - - drvdata->pclk = coresight_get_enable_apb_pclk(dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret; /* * Map the device base for dynamic-funnel, which has been diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 9e8bd36e7a9a..f1bbd12e63e0 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -223,6 +223,7 @@ static int replicator_probe(struct device *dev, struct resource *res) struct replicator_drvdata *drvdata; struct coresight_desc desc = { 0 }; void __iomem *base; + int ret; if (is_of_node(dev_fwnode(dev)) && of_device_is_compatible(dev->of_node, "arm,coresight-replicator")) @@ -237,13 +238,9 @@ static int replicator_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM; - drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); - - drvdata->pclk = coresight_get_enable_apb_pclk(dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret; /* * Map the device base for dynamic-replicator, which has been diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 275d67b91dfd..23ba33ac4d2e 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -842,13 +842,10 @@ static int __stm_probe(struct device *dev, struct resource *res) if (!drvdata) return -ENOMEM; - drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret; - drvdata->pclk = coresight_get_enable_apb_pclk(dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); dev_set_drvdata(dev, drvdata); base = devm_ioremap_resource(dev, res); diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 519f22542807..25c987e2d114 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -779,9 +779,9 @@ static int __tmc_probe(struct device *dev, struct resource *res) struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL; - drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret; ret = -ENOMEM; @@ -979,10 +979,6 @@ static int tmc_platform_probe(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); - dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 8d6179c83e5d..5e47d761e1c4 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -132,6 +132,7 @@ static int __tpiu_probe(struct device *dev, struct resource *res) struct coresight_platform_data *pdata = NULL; struct tpiu_drvdata *drvdata; struct coresight_desc desc = { 0 }; + int ret; desc.name = coresight_alloc_device_name(&tpiu_devs, dev); if (!desc.name) @@ -143,13 +144,10 @@ static int __tpiu_probe(struct device *dev, struct resource *res) spin_lock_init(&drvdata->spinlock); - drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); - if (IS_ERR(drvdata->atclk)) - return PTR_ERR(drvdata->atclk); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); + if (ret) + return ret; - drvdata->pclk = coresight_get_enable_apb_pclk(dev); - if (IS_ERR(drvdata->pclk)) - return PTR_ERR(drvdata->pclk); dev_set_drvdata(dev, drvdata); /* Validity for the resource is already checked by the AMBA core */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index bb49080ec8f9..6de59ce8ef8c 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -6,7 +6,6 @@ #ifndef _LINUX_CORESIGHT_H #define _LINUX_CORESIGHT_H -#include #include #include #include @@ -475,33 +474,6 @@ static inline bool is_coresight_device(void __iomem *base) return cid == CORESIGHT_CID; } -/* - * Attempt to find and enable "APB clock" for the given device - * - * Returns: - * - * clk - Clock is found and enabled - * NULL - Clock is controlled by firmware (ACPI device only) or when managed - * by the AMBA bus driver instead - * ERROR - Clock is found but failed to enable - */ -static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) -{ - struct clk *pclk = NULL; - - /* Firmware controls clocks for an ACPI device. */ - if (has_acpi_companion(dev)) - return NULL; - - if (!dev_is_amba(dev)) { - pclk = devm_clk_get_optional_enabled(dev, "apb_pclk"); - if (!pclk) - pclk = devm_clk_get_optional_enabled(dev, "apb"); - } - - return pclk; -} - #define CORESIGHT_PIDRn(i) (0xFE0 + ((i) * 4)) static inline u32 coresight_get_pid(struct csdev_access *csa) @@ -732,4 +704,6 @@ void coresight_remove_driver(struct amba_driver *amba_drv, struct platform_driver *pdev_drv); int coresight_etm_get_trace_id(struct coresight_device *csdev, enum cs_mode mode, struct coresight_device *sink); +int coresight_get_enable_clocks(struct device *dev, struct clk **pclk, + struct clk **atclk); #endif /* _LINUX_COREISGHT_H */ From ba6b61fa21aa44a5634f2dbf78ee6817d3196fc4 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 31 Jul 2025 13:23:44 +0100 Subject: [PATCH 1950/2711] coresight: Refactor driver data allocation The driver data no longer needs to be allocated separately in the static and dynamic probes. Moved the allocation into the low-level functions to avoid code duplication. Reviewed-by: Anshuman Khandual Reviewed-by: Yeoreum Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-8-1dfe10bb3f6f@arm.com --- drivers/hwtracing/coresight/coresight-catu.c | 20 +++++++----------- .../hwtracing/coresight/coresight-cpu-debug.c | 21 +++++++------------ .../hwtracing/coresight/coresight-tmc-core.c | 20 +++++++----------- 3 files changed, 21 insertions(+), 40 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index 0f476a0cbd74..a3ccb7034ae1 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -515,11 +515,17 @@ static int __catu_probe(struct device *dev, struct resource *res) { int ret = 0; u32 dma_mask; - struct catu_drvdata *drvdata = dev_get_drvdata(dev); + struct catu_drvdata *drvdata; struct coresight_desc catu_desc; struct coresight_platform_data *pdata = NULL; void __iomem *base; + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + dev_set_drvdata(dev, drvdata); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); if (ret) return ret; @@ -580,14 +586,8 @@ out: static int catu_probe(struct amba_device *adev, const struct amba_id *id) { - struct catu_drvdata *drvdata; int ret; - drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - amba_set_drvdata(adev, drvdata); ret = __catu_probe(&adev->dev, &adev->res); if (!ret) pm_runtime_put(&adev->dev); @@ -627,18 +627,12 @@ static struct amba_driver catu_driver = { static int catu_platform_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct catu_drvdata *drvdata; int ret = 0; - drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - dev_set_drvdata(&pdev->dev, drvdata); ret = __catu_probe(&pdev->dev, res); pm_runtime_put(&pdev->dev); if (ret) diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 5f6db2fb95d4..3edfb5d3d020 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -562,10 +562,16 @@ static void debug_func_exit(void) static int __debug_probe(struct device *dev, struct resource *res) { - struct debug_drvdata *drvdata = dev_get_drvdata(dev); + struct debug_drvdata *drvdata; void __iomem *base; int ret; + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + dev_set_drvdata(dev, drvdata); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, NULL); if (ret) return ret; @@ -629,13 +635,6 @@ err: static int debug_probe(struct amba_device *adev, const struct amba_id *id) { - struct debug_drvdata *drvdata; - - drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - amba_set_drvdata(adev, drvdata); return __debug_probe(&adev->dev, &adev->res); } @@ -694,14 +693,8 @@ static struct amba_driver debug_driver = { static int debug_platform_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct debug_drvdata *drvdata; int ret = 0; - drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 25c987e2d114..36599c431be6 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -775,10 +775,16 @@ static int __tmc_probe(struct device *dev, struct resource *res) u32 devid; void __iomem *base; struct coresight_platform_data *pdata = NULL; - struct tmc_drvdata *drvdata = dev_get_drvdata(dev); + struct tmc_drvdata *drvdata; struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL; + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + dev_set_drvdata(dev, drvdata); + ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk); if (ret) return ret; @@ -888,14 +894,8 @@ out: static int tmc_probe(struct amba_device *adev, const struct amba_id *id) { - struct tmc_drvdata *drvdata; int ret; - drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - amba_set_drvdata(adev, drvdata); ret = __tmc_probe(&adev->dev, &adev->res); if (!ret) pm_runtime_put(&adev->dev); @@ -972,14 +972,8 @@ static struct amba_driver tmc_driver = { static int tmc_platform_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct tmc_drvdata *drvdata; int ret = 0; - drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); From 7b20a4fac7c82c0aed6beb22a8523df28361b1ad Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 31 Jul 2025 13:23:45 +0100 Subject: [PATCH 1951/2711] coresight: Make clock sequence consistent Since atclk is enabled after pclk during the probe phase, this commit maintains the same sequence for the runtime resume flow. Reviewed-by: Anshuman Khandual Reviewed-by: Yeoreum Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-9-1dfe10bb3f6f@arm.com --- drivers/hwtracing/coresight/coresight-funnel.c | 6 +++--- drivers/hwtracing/coresight/coresight-replicator.c | 6 +++--- drivers/hwtracing/coresight/coresight-stm.c | 6 +++--- drivers/hwtracing/coresight/coresight-tpiu.c | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 02e0dc678a32..9dcfc5ce8845 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -297,11 +297,11 @@ static int funnel_runtime_resume(struct device *dev) { struct funnel_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk); + + if (drvdata && !IS_ERR(drvdata->atclk)) + clk_prepare_enable(drvdata->atclk); return 0; } #endif diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index f1bbd12e63e0..e53095603b0c 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -335,11 +335,11 @@ static int replicator_runtime_resume(struct device *dev) { struct replicator_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk); + + if (drvdata && !IS_ERR(drvdata->atclk)) + clk_prepare_enable(drvdata->atclk); return 0; } #endif diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 23ba33ac4d2e..7b1e289f17ab 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -969,11 +969,11 @@ static int stm_runtime_resume(struct device *dev) { struct stm_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk); + + if (drvdata && !IS_ERR(drvdata->atclk)) + clk_prepare_enable(drvdata->atclk); return 0; } #endif diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 5e47d761e1c4..1c5c2a829714 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -218,11 +218,11 @@ static int tpiu_runtime_resume(struct device *dev) { struct tpiu_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) clk_prepare_enable(drvdata->pclk); + + if (drvdata && !IS_ERR(drvdata->atclk)) + clk_prepare_enable(drvdata->atclk); return 0; } #endif From dc783892cca69e721f81d54293dac6286134abfe Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 31 Jul 2025 13:23:46 +0100 Subject: [PATCH 1952/2711] coresight: Refactor runtime PM The validation for driver data pointers and clock pointers are redundant in the runtime PM callbacks. After a driver's probing, its driver data and clocks have been initialized successfully, this ensures it is safe to access driver data and clocks in the runtime PM callbacks. A corner case is a clock pointer is NULL, in this case, the clock core layer can handle it properly. So remove these redundant checking. In runtime resume, respect values returned from clock function and add error handling. Reviewed-by: Anshuman Khandual Reviewed-by: Yeoreum Yun Tested-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-10-1dfe10bb3f6f@arm.com --- .../hwtracing/coresight/coresight-cpu-debug.c | 8 +++---- .../hwtracing/coresight/coresight-ctcu-core.c | 8 ++----- drivers/hwtracing/coresight/coresight-etb10.c | 8 ++----- .../coresight/coresight-etm3x-core.c | 8 ++----- .../hwtracing/coresight/coresight-funnel.c | 21 ++++++++++--------- .../coresight/coresight-replicator.c | 20 ++++++++++-------- drivers/hwtracing/coresight/coresight-stm.c | 20 ++++++++++-------- drivers/hwtracing/coresight/coresight-tpiu.c | 20 ++++++++++-------- 8 files changed, 53 insertions(+), 60 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 3edfb5d3d020..5f21366406aa 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -731,8 +731,8 @@ static int debug_runtime_suspend(struct device *dev) { struct debug_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); + clk_disable_unprepare(drvdata->pclk); + return 0; } @@ -740,9 +740,7 @@ static int debug_runtime_resume(struct device *dev) { struct debug_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); - return 0; + return clk_prepare_enable(drvdata->pclk); } #endif diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c index 75b5114ef652..c586495e9a08 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu-core.c +++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c @@ -278,8 +278,7 @@ static int ctcu_runtime_suspend(struct device *dev) { struct ctcu_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR_OR_NULL(drvdata->apb_clk)) - clk_disable_unprepare(drvdata->apb_clk); + clk_disable_unprepare(drvdata->apb_clk); return 0; } @@ -288,10 +287,7 @@ static int ctcu_runtime_resume(struct device *dev) { struct ctcu_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR_OR_NULL(drvdata->apb_clk)) - clk_prepare_enable(drvdata->apb_clk); - - return 0; + return clk_prepare_enable(drvdata->apb_clk); } #endif diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 8e81b41eb222..35db1b6093d1 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -809,8 +809,7 @@ static int etb_runtime_suspend(struct device *dev) { struct etb_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk); return 0; } @@ -819,10 +818,7 @@ static int etb_runtime_resume(struct device *dev) { struct etb_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - - return 0; + return clk_prepare_enable(drvdata->atclk); } #endif diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index baba2245b1df..45630a1cd32f 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -925,8 +925,7 @@ static int etm_runtime_suspend(struct device *dev) { struct etm_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk); return 0; } @@ -935,10 +934,7 @@ static int etm_runtime_resume(struct device *dev) { struct etm_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - - return 0; + return clk_prepare_enable(drvdata->atclk); } #endif diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 9dcfc5ce8845..3b248e54471a 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -284,11 +284,8 @@ static int funnel_runtime_suspend(struct device *dev) { struct funnel_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); - - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk); return 0; } @@ -296,13 +293,17 @@ static int funnel_runtime_suspend(struct device *dev) static int funnel_runtime_resume(struct device *dev) { struct funnel_drvdata *drvdata = dev_get_drvdata(dev); + int ret; - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret; - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - return 0; + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index e53095603b0c..e6472658235d 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -323,24 +323,26 @@ static int replicator_runtime_suspend(struct device *dev) { struct replicator_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); return 0; } static int replicator_runtime_resume(struct device *dev) { struct replicator_drvdata *drvdata = dev_get_drvdata(dev); + int ret; - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret; - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - return 0; + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 7b1e289f17ab..e68529bf89c9 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -957,24 +957,26 @@ static int stm_runtime_suspend(struct device *dev) { struct stm_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); return 0; } static int stm_runtime_resume(struct device *dev) { struct stm_drvdata *drvdata = dev_get_drvdata(dev); + int ret; - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret; - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - return 0; + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 1c5c2a829714..9463afdbda8a 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -206,24 +206,26 @@ static int tpiu_runtime_suspend(struct device *dev) { struct tpiu_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->pclk); - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_disable_unprepare(drvdata->pclk); return 0; } static int tpiu_runtime_resume(struct device *dev) { struct tpiu_drvdata *drvdata = dev_get_drvdata(dev); + int ret; - if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) - clk_prepare_enable(drvdata->pclk); + ret = clk_prepare_enable(drvdata->pclk); + if (ret) + return ret; - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - return 0; + ret = clk_prepare_enable(drvdata->atclk); + if (ret) + clk_disable_unprepare(drvdata->pclk); + + return ret; } #endif From 8a55c161f7f9c1aa1c70611b39830d51c83ef36d Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 4 Sep 2025 15:13:52 +0100 Subject: [PATCH 1953/2711] coresight: trbe: Return NULL pointer for allocation failures When the TRBE driver fails to allocate a buffer, it currently returns the error code "-ENOMEM". However, the caller etm_setup_aux() only checks for a NULL pointer, so it misses the error. As a result, the driver continues and eventually causes a kernel panic. Fix this by returning a NULL pointer from arm_trbe_alloc_buffer() on allocation failures. This allows that the callers can properly handle the failure. Fixes: 3fbf7f011f24 ("coresight: sink: Add TRBE driver") Reported-by: Tamas Zsoldos Signed-off-by: Leo Yan Reviewed-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250904-cs_etm_auxsetup_fix_error_handling-v2-1-a502d0bafb95@arm.com --- drivers/hwtracing/coresight/coresight-trbe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c index 10f3fb401edf..8f9bbef71f23 100644 --- a/drivers/hwtracing/coresight/coresight-trbe.c +++ b/drivers/hwtracing/coresight/coresight-trbe.c @@ -748,12 +748,12 @@ static void *arm_trbe_alloc_buffer(struct coresight_device *csdev, buf = kzalloc_node(sizeof(*buf), GFP_KERNEL, trbe_alloc_node(event)); if (!buf) - return ERR_PTR(-ENOMEM); + return NULL; pglist = kcalloc(nr_pages, sizeof(*pglist), GFP_KERNEL); if (!pglist) { kfree(buf); - return ERR_PTR(-ENOMEM); + return NULL; } for (i = 0; i < nr_pages; i++) @@ -763,7 +763,7 @@ static void *arm_trbe_alloc_buffer(struct coresight_device *csdev, if (!buf->trbe_base) { kfree(pglist); kfree(buf); - return ERR_PTR(-ENOMEM); + return NULL; } buf->trbe_limit = buf->trbe_base + nr_pages * PAGE_SIZE; buf->trbe_write = buf->trbe_base; From 43e0a92c04de7c822f6104abc73caa4a857b4a02 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Sat, 6 Sep 2025 07:53:04 +0800 Subject: [PATCH 1954/2711] coresight: tpda: fix the logic to setup the element size Some TPDM devices support both CMB and DSB datasets, requiring the system to enable the port with both corresponding element sizes. Currently, the logic treats tpdm_read_element_size as successful if the CMB element size is retrieved correctly, regardless of whether the DSB element size is obtained. This behavior causes issues when parsing data from TPDM devices that depend on both element sizes. To address this, the function should explicitly fail if the DSB element size cannot be read correctly. Fixes: e6d7f5252f73 ("coresight-tpda: Add support to configure CMB element") Reviewed-by: James Clark Signed-off-by: Jie Gan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250906-fix_element_size_issue-v2-1-dbb0ac2541a9@oss.qualcomm.com --- drivers/hwtracing/coresight/coresight-tpda.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index 0633f04beb24..333b3cb23685 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -71,6 +71,8 @@ static int tpdm_read_element_size(struct tpda_drvdata *drvdata, if (tpdm_data->dsb) { rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), "qcom,dsb-element-bits", &drvdata->dsb_esize); + if (rc) + goto out; } if (tpdm_data->cmb) { @@ -78,6 +80,7 @@ static int tpdm_read_element_size(struct tpda_drvdata *drvdata, "qcom,cmb-element-bits", &drvdata->cmb_esize); } +out: if (rc) dev_warn_once(&csdev->dev, "Failed to read TPDM Element size: %d\n", rc); From 70714eb7243eaf333d23501d4c7bdd9daf011c01 Mon Sep 17 00:00:00 2001 From: Lin Yujun Date: Mon, 8 Sep 2025 20:20:22 +0800 Subject: [PATCH 1955/2711] coresight: Fix incorrect handling for return value of devm_kzalloc The return value of devm_kzalloc could be an null pointer, use "!desc.pdata" to fix incorrect handling return value of devm_kzalloc. Fixes: 4277f035d227 ("coresight: trbe: Add a representative coresight_platform_data for TRBE") Signed-off-by: Lin Yujun Reviewed-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250908122022.1315399-1-linyujun809@h-partners.com --- drivers/hwtracing/coresight/coresight-trbe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c index 8f9bbef71f23..7a226316c48f 100644 --- a/drivers/hwtracing/coresight/coresight-trbe.c +++ b/drivers/hwtracing/coresight/coresight-trbe.c @@ -1280,7 +1280,7 @@ static void arm_trbe_register_coresight_cpu(struct trbe_drvdata *drvdata, int cp * into the device for that purpose. */ desc.pdata = devm_kzalloc(dev, sizeof(*desc.pdata), GFP_KERNEL); - if (IS_ERR(desc.pdata)) + if (!desc.pdata) goto cpu_clear; desc.type = CORESIGHT_DEV_TYPE_SINK; From 28a272d8eb9fb8a1fa3ef27f665c04d47d74e037 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Thu, 14 Aug 2025 02:00:13 -0700 Subject: [PATCH 1956/2711] coresight: tnoc: add new AMBA ID to support Trace Noc V2 Add the new AMBA ID 0x001f0c00 to support Trace Noc V2 instances. Signed-off-by: Yuanfang Zhang Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250814-tnoc_v2-v1-1-3285e37280c9@oss.qualcomm.com --- drivers/hwtracing/coresight/coresight-tnoc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c index d542df46ea39..ff9a0a9cfe96 100644 --- a/drivers/hwtracing/coresight/coresight-tnoc.c +++ b/drivers/hwtracing/coresight/coresight-tnoc.c @@ -222,6 +222,10 @@ static struct amba_id trace_noc_ids[] = { .id = 0x000f0c00, .mask = 0x00ffff00, }, + { + .id = 0x001f0c00, + .mask = 0x00ffff00, + }, {}, }; MODULE_DEVICE_TABLE(amba, trace_noc_ids); From 1ad38ef4dbccee28b9b50e315a2d4d9ca5f7ee09 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Sat, 16 Aug 2025 00:25:28 -0700 Subject: [PATCH 1957/2711] dt-bindings: arm: Add label in the coresight components Current name of coresight component's folder consists of prefix of the device and the id in the device list. When run 'ls' command, we can get the register address of the device. Take CTI for example, if we want to set the config for modem CTI, but we can't know which CTI is modem CTI from all current information. cti_sys0 -> ../../../devices/platform/soc@0/138f0000.cti/cti_sys0 cti_sys1 -> ../../../devices/platform/soc@0/13900000.cti/cti_sys1 Add label to show hardware context information of each coresight device. There will be a sysfs node label in each device folder. cat /sys/bus/coresight/devices/cti_sys0/label Signed-off-by: Mao Jinlong Reviewed-by: Krzysztof Kozlowski Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250816072529.3716968-2-quic_jinlmao@quicinc.com --- Documentation/devicetree/bindings/arm/arm,coresight-cti.yaml | 4 ++++ .../devicetree/bindings/arm/arm,coresight-dummy-sink.yaml | 4 ++++ .../devicetree/bindings/arm/arm,coresight-dummy-source.yaml | 4 ++++ .../devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml | 4 ++++ .../bindings/arm/arm,coresight-dynamic-replicator.yaml | 4 ++++ .../devicetree/bindings/arm/arm,coresight-etb10.yaml | 4 ++++ Documentation/devicetree/bindings/arm/arm,coresight-etm.yaml | 4 ++++ .../devicetree/bindings/arm/arm,coresight-static-funnel.yaml | 4 ++++ .../bindings/arm/arm,coresight-static-replicator.yaml | 4 ++++ Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml | 4 ++++ Documentation/devicetree/bindings/arm/arm,coresight-tpiu.yaml | 4 ++++ .../devicetree/bindings/arm/qcom,coresight-ctcu.yaml | 4 ++++ .../devicetree/bindings/arm/qcom,coresight-remote-etm.yaml | 4 ++++ .../devicetree/bindings/arm/qcom,coresight-tpda.yaml | 4 ++++ .../devicetree/bindings/arm/qcom,coresight-tpdm.yaml | 4 ++++ 15 files changed, 60 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-cti.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-cti.yaml index 2d5545a2b49c..2a91670ccb8c 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-cti.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-cti.yaml @@ -98,6 +98,10 @@ properties: power-domains: maxItems: 1 + label: + description: + Description of a coresight device. + arm,cti-ctm-id: $ref: /schemas/types.yaml#/definitions/uint32 description: diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dummy-sink.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dummy-sink.yaml index 08b89b62c505..ed091dc0c10a 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-dummy-sink.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-dummy-sink.yaml @@ -39,6 +39,10 @@ properties: enum: - arm,coresight-dummy-sink + label: + description: + Description of a coresight device. + in-ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml index 742dc4e25d3b..78337be42b55 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml @@ -38,6 +38,10 @@ properties: enum: - arm,coresight-dummy-source + label: + description: + Description of a coresight device. + arm,static-trace-id: description: If dummy source needs static id support, use this to set trace id. $ref: /schemas/types.yaml#/definitions/uint32 diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml index 44a1041cb0fc..b74db15e5f8a 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-funnel.yaml @@ -57,6 +57,10 @@ properties: power-domains: maxItems: 1 + label: + description: + Description of a coresight device. + in-ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml index 03792e9bd97a..17ea936b796f 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-dynamic-replicator.yaml @@ -54,6 +54,10 @@ properties: - const: apb_pclk - const: atclk + label: + description: + Description of a coresight device. + power-domains: maxItems: 1 diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-etb10.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-etb10.yaml index 90679788e0bf..892df7aca1ac 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-etb10.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-etb10.yaml @@ -54,6 +54,10 @@ properties: - const: apb_pclk - const: atclk + label: + description: + Description of a coresight device. + power-domains: maxItems: 1 diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-etm.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-etm.yaml index 01200f67504a..71f2e1ed27e5 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-etm.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-etm.yaml @@ -85,6 +85,10 @@ properties: CPU powers down the coresight component also powers down and loses its context. + label: + description: + Description of a coresight device. + arm,cp14: type: boolean description: diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-static-funnel.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-static-funnel.yaml index cc8c3baa79b4..9598a3d0a95b 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-static-funnel.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-static-funnel.yaml @@ -30,6 +30,10 @@ properties: power-domains: maxItems: 1 + label: + description: + Description of a coresight device. + in-ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml index 0c1017affbad..b81851b26c74 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml @@ -43,6 +43,10 @@ properties: - const: dbg_trc - const: dbg_apb + label: + description: + Description of a coresight device. + in-ports: $ref: /schemas/graph.yaml#/properties/ports additionalProperties: false diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml index 4787d7c6bac2..96dd5b5f771a 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-tmc.yaml @@ -55,6 +55,10 @@ properties: - const: apb_pclk - const: atclk + label: + description: + Description of a coresight device. + iommus: maxItems: 1 diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-tpiu.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-tpiu.yaml index 61a0cdc27745..a207f6899e67 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-tpiu.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-tpiu.yaml @@ -54,6 +54,10 @@ properties: - const: apb_pclk - const: atclk + label: + description: + Description of a coresight device. + power-domains: maxItems: 1 diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml index 843b52eaf872..c969c16c21ef 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-ctcu.yaml @@ -39,6 +39,10 @@ properties: items: - const: apb + label: + description: + Description of a coresight device. + in-ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml index 4fd5752978cd..ffe613efeabe 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml @@ -20,6 +20,10 @@ properties: compatible: const: qcom,coresight-remote-etm + label: + description: + Description of a coresight device. + out-ports: $ref: /schemas/graph.yaml#/properties/ports additionalProperties: false diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml index 5ed40f21b8eb..a48c9ac3eaa9 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml @@ -64,6 +64,10 @@ properties: items: - const: apb_pclk + label: + description: + Description of a coresight device. + in-ports: description: | Input connections from TPDM to TPDA diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml index 07d21a3617f5..4edc47483851 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml @@ -76,6 +76,10 @@ properties: minimum: 0 maximum: 32 + label: + description: + Description of a coresight device. + clocks: maxItems: 1 From 01f96b812526a2c8dcd5c0e510dda37e09ec8bcd Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Sat, 16 Aug 2025 00:25:29 -0700 Subject: [PATCH 1958/2711] coresight: Add label sysfs node support For some coresight components like CTI and TPDM, there could be numerous of them. From the node name, we can only get the type and register address of the component. We can't identify the HW or the system the component belongs to. Add label sysfs node support for showing the intuitive name of the device. Signed-off-by: Mao Jinlong Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20250816072529.3716968-3-quic_jinlmao@quicinc.com --- .../testing/sysfs-bus-coresight-devices-cti | 6 ++ .../sysfs-bus-coresight-devices-dummy-source | 6 ++ .../testing/sysfs-bus-coresight-devices-etb10 | 6 ++ .../testing/sysfs-bus-coresight-devices-etm3x | 6 ++ .../testing/sysfs-bus-coresight-devices-etm4x | 6 ++ .../sysfs-bus-coresight-devices-funnel | 6 ++ .../testing/sysfs-bus-coresight-devices-stm | 6 ++ .../testing/sysfs-bus-coresight-devices-tmc | 6 ++ .../testing/sysfs-bus-coresight-devices-tpdm | 6 ++ .../testing/sysfs-bus-coresight-devices-trbe | 6 ++ drivers/hwtracing/coresight/coresight-sysfs.c | 71 ++++++++++++++++++- 11 files changed, 129 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti b/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti index a97b70f588da..a2aef7f5a6d7 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-cti @@ -239,3 +239,9 @@ Date: March 2020 KernelVersion: 5.7 Contact: Mike Leach or Mathieu Poirier Description: (Write) Clear all channel / trigger programming. + +What: /sys/bus/coresight/devices//label +Date: Aug 2025 +KernelVersion 6.18 +Contact: Mao Jinlong +Description: (Read) Show hardware context information of device. diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-dummy-source b/Documentation/ABI/testing/sysfs-bus-coresight-devices-dummy-source index 0830661ef656..321e3ee1fc9d 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-dummy-source +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-dummy-source @@ -13,3 +13,9 @@ KernelVersion: 6.14 Contact: Mao Jinlong Description: (R) Show the trace ID that will appear in the trace stream coming from this trace entity. + +What: /sys/bus/coresight/devices/dummy_source/label +Date: Aug 2025 +KernelVersion 6.18 +Contact: Mao Jinlong +Description: (Read) Show hardware context information of device. diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etb10 b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etb10 index 9a383f6a74eb..f30526949687 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etb10 +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etb10 @@ -19,6 +19,12 @@ Description: (RW) Disables write access to the Trace RAM by stopping the into the Trace RAM following the trigger event is equal to the value stored in this register+1 (from ARM ETB-TRM). +What: /sys/bus/coresight/devices/.etb/label +Date: Aug 2025 +KernelVersion 6.18 +Contact: Mao Jinlong +Description: (Read) Show hardware context information of device. + What: /sys/bus/coresight/devices/.etb/mgmt/rdp Date: March 2016 KernelVersion: 4.7 diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x index 271b57c571aa..245c322c91f1 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x @@ -251,6 +251,12 @@ KernelVersion: 4.4 Contact: Mathieu Poirier Description: (RO) Holds the cpu number this tracer is affined to. +What: /sys/bus/coresight/devices/.[etm|ptm]/label +Date: Aug 2025 +KernelVersion 6.18 +Contact: Mao Jinlong +Description: (Read) Show hardware context information of device. + What: /sys/bus/coresight/devices/.[etm|ptm]/mgmt/etmccr Date: September 2015 KernelVersion: 4.4 diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x index a0425d70d009..6f19a6a5f2e1 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x @@ -329,6 +329,12 @@ Contact: Mathieu Poirier Description: (RW) Access the selected single show PE comparator control register. +What: /sys/bus/coresight/devices/etm/label +Date: Aug 2025 +KernelVersion 6.18 +Contact: Mao Jinlong +Description: (Read) Show hardware context information of device. + What: /sys/bus/coresight/devices/etm/mgmt/trcoslsr Date: April 2015 KernelVersion: 4.01 diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-funnel b/Documentation/ABI/testing/sysfs-bus-coresight-devices-funnel index d75acda5e1b3..86938e9bbcde 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-funnel +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-funnel @@ -10,3 +10,9 @@ Date: November 2014 KernelVersion: 3.19 Contact: Mathieu Poirier Description: (RW) Defines input port priority order. + +What: /sys/bus/coresight/devices/.funnel/label +Date: Aug 2025 +KernelVersion 6.18 +Contact: Mao Jinlong +Description: (Read) Show hardware context information of device. diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-stm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-stm index 53e1f4815d64..848e2ffc1480 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-stm +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-stm @@ -51,3 +51,9 @@ KernelVersion: 4.7 Contact: Mathieu Poirier Description: (RW) Holds the trace ID that will appear in the trace stream coming from this trace entity. + +What: /sys/bus/coresight/devices/.stm/label +Date: Aug 2025 +KernelVersion 6.18 +Contact: Mao Jinlong +Description: (Read) Show hardware context information of device. diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc index 339cec3b2f1a..55e298b9c4a4 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc @@ -107,3 +107,9 @@ Contact: Anshuman Khandual Description: (RW) Current Coresight TMC-ETR buffer mode selected. But user could only provide a mode which is supported for a given ETR device. This file is available only for TMC ETR devices. + +What: /sys/bus/coresight/devices/.tmc/label +Date: Aug 2025 +KernelVersion 6.18 +Contact: Mao Jinlong +Description: (Read) Show hardware context information of device. diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm index a341b08ae70b..98f1c6545027 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm @@ -272,3 +272,9 @@ KernelVersion 6.15 Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) Description: (RW) Set/Get the enablement of the individual lane. + +What: /sys/bus/coresight/devices//label +Date: Aug 2025 +KernelVersion 6.18 +Contact: Mao Jinlong +Description: (Read) Show hardware context information of device. diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-trbe b/Documentation/ABI/testing/sysfs-bus-coresight-devices-trbe index ad3bbc6fa751..8a4b749ed26e 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-trbe +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-trbe @@ -12,3 +12,9 @@ Contact: Anshuman Khandual Description: (Read) Shows if TRBE updates in the memory are with access and dirty flag updates as well. This value is fetched from the TRBIDR register. + +What: /sys/bus/coresight/devices/trbe/label +Date: Aug 2025 +KernelVersion 6.18 +Contact: Mao Jinlong +Description: (Read) Show hardware context information of device. diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c index feadaf065b53..5e52324aa9ac 100644 --- a/drivers/hwtracing/coresight/coresight-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-sysfs.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "coresight-priv.h" #include "coresight-trace-id.h" @@ -371,17 +372,81 @@ static ssize_t enable_source_store(struct device *dev, } static DEVICE_ATTR_RW(enable_source); +static ssize_t label_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + const char *str; + int ret; + + ret = fwnode_property_read_string(dev_fwnode(dev), "label", &str); + if (ret == 0) + return sysfs_emit(buf, "%s\n", str); + else + return ret; +} +static DEVICE_ATTR_RO(label); + +static umode_t label_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + + if (attr == &dev_attr_label.attr) { + if (fwnode_property_present(dev_fwnode(dev), "label")) + return attr->mode; + else + return 0; + } + + return attr->mode; +} + static struct attribute *coresight_sink_attrs[] = { &dev_attr_enable_sink.attr, + &dev_attr_label.attr, NULL, }; -ATTRIBUTE_GROUPS(coresight_sink); + +static struct attribute_group coresight_sink_group = { + .attrs = coresight_sink_attrs, + .is_visible = label_is_visible, +}; +__ATTRIBUTE_GROUPS(coresight_sink); static struct attribute *coresight_source_attrs[] = { &dev_attr_enable_source.attr, + &dev_attr_label.attr, NULL, }; -ATTRIBUTE_GROUPS(coresight_source); + +static struct attribute_group coresight_source_group = { + .attrs = coresight_source_attrs, + .is_visible = label_is_visible, +}; +__ATTRIBUTE_GROUPS(coresight_source); + +static struct attribute *coresight_link_attrs[] = { + &dev_attr_label.attr, + NULL, +}; + +static struct attribute_group coresight_link_group = { + .attrs = coresight_link_attrs, + .is_visible = label_is_visible, +}; +__ATTRIBUTE_GROUPS(coresight_link); + +static struct attribute *coresight_helper_attrs[] = { + &dev_attr_label.attr, + NULL, +}; + +static struct attribute_group coresight_helper_group = { + .attrs = coresight_helper_attrs, + .is_visible = label_is_visible, +}; +__ATTRIBUTE_GROUPS(coresight_helper); const struct device_type coresight_dev_type[] = { [CORESIGHT_DEV_TYPE_SINK] = { @@ -390,6 +455,7 @@ const struct device_type coresight_dev_type[] = { }, [CORESIGHT_DEV_TYPE_LINK] = { .name = "link", + .groups = coresight_link_groups, }, [CORESIGHT_DEV_TYPE_LINKSINK] = { .name = "linksink", @@ -401,6 +467,7 @@ const struct device_type coresight_dev_type[] = { }, [CORESIGHT_DEV_TYPE_HELPER] = { .name = "helper", + .groups = coresight_helper_groups, } }; /* Ensure the enum matches the names and groups */ From 17a1a107d0e96c1b7eef875de46f1d953c557f88 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 23 Sep 2025 09:04:58 -0400 Subject: [PATCH 1959/2711] tracing: Replace syscall RCU pointer assignment with READ/WRITE_ONCE() The syscall events are pseudo events that hook to the raw syscalls. The ftrace_syscall_enter/exit() callback is called by the raw_syscall enter/exit tracepoints respectively whenever any of the syscall events are enabled. The trace_array has an array of syscall "files" that correspond to the system calls based on their __NR_SYSCALL number. The array is read and if there's a pointer to a trace_event_file then it is considered enabled and if it is NULL that syscall event is considered disabled. Currently it uses an rcu_dereference_sched() to get this pointer and a rcu_assign_ptr() or RCU_INIT_POINTER() to write to it. This is unnecessary as the file pointer will not go away outside the synchronization of the tracepoint logic itself. And this code adds no extra RCU synchronization that uses this. Replace these functions with a simple READ_ONCE() and WRITE_ONCE() which is all they need. This will also allow this code to not depend on preemption being disabled as system call tracepoints are now allowed to fault. Cc: Masami Hiramatsu Cc: Mark Rutland Cc: Mathieu Desnoyers Cc: Andrew Morton Cc: Peter Zijlstra Cc: Namhyung Kim Cc: Takaya Saeki Cc: Tom Zanussi Cc: Thomas Gleixner Cc: Ian Rogers Cc: Douglas Raillard Link: https://lore.kernel.org/20250923130713.594320290@kernel.org Reviewed-by: Paul E. McKenney Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace.h | 4 ++-- kernel/trace/trace_syscalls.c | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 5f4bed5842f9..85eabb454bee 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -380,8 +380,8 @@ struct trace_array { #ifdef CONFIG_FTRACE_SYSCALLS int sys_refcount_enter; int sys_refcount_exit; - struct trace_event_file __rcu *enter_syscall_files[NR_syscalls]; - struct trace_event_file __rcu *exit_syscall_files[NR_syscalls]; + struct trace_event_file *enter_syscall_files[NR_syscalls]; + struct trace_event_file *exit_syscall_files[NR_syscalls]; #endif int stop_count; int clock_id; diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 46aab0ab9350..3a0b65f89130 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -310,8 +310,7 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) if (syscall_nr < 0 || syscall_nr >= NR_syscalls) return; - /* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE) */ - trace_file = rcu_dereference_sched(tr->enter_syscall_files[syscall_nr]); + trace_file = READ_ONCE(tr->enter_syscall_files[syscall_nr]); if (!trace_file) return; @@ -356,8 +355,7 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) if (syscall_nr < 0 || syscall_nr >= NR_syscalls) return; - /* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE()) */ - trace_file = rcu_dereference_sched(tr->exit_syscall_files[syscall_nr]); + trace_file = READ_ONCE(tr->exit_syscall_files[syscall_nr]); if (!trace_file) return; @@ -393,7 +391,7 @@ static int reg_event_syscall_enter(struct trace_event_file *file, if (!tr->sys_refcount_enter) ret = register_trace_sys_enter(ftrace_syscall_enter, tr); if (!ret) { - rcu_assign_pointer(tr->enter_syscall_files[num], file); + WRITE_ONCE(tr->enter_syscall_files[num], file); tr->sys_refcount_enter++; } mutex_unlock(&syscall_trace_lock); @@ -411,7 +409,7 @@ static void unreg_event_syscall_enter(struct trace_event_file *file, return; mutex_lock(&syscall_trace_lock); tr->sys_refcount_enter--; - RCU_INIT_POINTER(tr->enter_syscall_files[num], NULL); + WRITE_ONCE(tr->enter_syscall_files[num], NULL); if (!tr->sys_refcount_enter) unregister_trace_sys_enter(ftrace_syscall_enter, tr); mutex_unlock(&syscall_trace_lock); @@ -431,7 +429,7 @@ static int reg_event_syscall_exit(struct trace_event_file *file, if (!tr->sys_refcount_exit) ret = register_trace_sys_exit(ftrace_syscall_exit, tr); if (!ret) { - rcu_assign_pointer(tr->exit_syscall_files[num], file); + WRITE_ONCE(tr->exit_syscall_files[num], file); tr->sys_refcount_exit++; } mutex_unlock(&syscall_trace_lock); @@ -449,7 +447,7 @@ static void unreg_event_syscall_exit(struct trace_event_file *file, return; mutex_lock(&syscall_trace_lock); tr->sys_refcount_exit--; - RCU_INIT_POINTER(tr->exit_syscall_files[num], NULL); + WRITE_ONCE(tr->exit_syscall_files[num], NULL); if (!tr->sys_refcount_exit) unregister_trace_sys_exit(ftrace_syscall_exit, tr); mutex_unlock(&syscall_trace_lock); From 3add2d34bdfb1caab1d3f28ba0160f52dcff9353 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 23 Sep 2025 09:04:59 -0400 Subject: [PATCH 1960/2711] tracing: Have syscall trace events show "0x" for values greater than 10 Currently the syscall trace events show each value as hexadecimal, but without adding "0x" it can be confusing: sys_write(fd: 4, buf: 0x55c4a1fa9270, count: 44) Looks like the above write wrote 44 bytes, when in reality it wrote 68 bytes. Add a "0x" for all values greater or equal to 10 to remove the ambiguity. For values less than 10, leave off the "0x" as that just adds noise to the output. Also change the iterator to check if "i" is nonzero and print the ", " delimiter at the start, then adding the logic to the trace_seq_printf() at the end. Cc: Masami Hiramatsu Cc: Mark Rutland Cc: Mathieu Desnoyers Cc: Andrew Morton Cc: Peter Zijlstra Cc: Namhyung Kim Cc: Takaya Saeki Cc: Tom Zanussi Cc: Thomas Gleixner Cc: Ian Rogers Cc: Douglas Raillard Link: https://lore.kernel.org/20250923130713.764558957@kernel.org Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace_syscalls.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 3a0b65f89130..0f932b22f9ec 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -153,14 +153,20 @@ print_syscall_enter(struct trace_iterator *iter, int flags, if (trace_seq_has_overflowed(s)) goto end; + if (i) + trace_seq_puts(s, ", "); + /* parameter types */ if (tr && tr->trace_flags & TRACE_ITER_VERBOSE) trace_seq_printf(s, "%s ", entry->types[i]); /* parameter values */ - trace_seq_printf(s, "%s: %lx%s", entry->args[i], - trace->args[i], - i == entry->nb_args - 1 ? "" : ", "); + if (trace->args[i] < 10) + trace_seq_printf(s, "%s: %lu", entry->args[i], + trace->args[i]); + else + trace_seq_printf(s, "%s: 0x%lx", entry->args[i], + trace->args[i]); } trace_seq_putc(s, ')'); From 09da59344a5a2abb5b2f209cf149421d7d105ebc Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Sun, 17 Aug 2025 16:47:25 +0800 Subject: [PATCH 1961/2711] tracing: Use vmalloc_array() to improve code Remove array_size() calls and replace vmalloc() with vmalloc_array() in tracing_map_sort_entries(). vmalloc_array() is optimized better, uses fewer instructions, and handles overflow more concisely[1]. [1]: https://lore.kernel.org/lkml/abc66ec5-85a4-47e1-9759-2f60ab111971@vivo.com/ Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Link: https://lore.kernel.org/20250817084725.59477-1-rongqianfeng@vivo.com Signed-off-by: Qianfeng Rong Signed-off-by: Steven Rostedt (Google) --- kernel/trace/tracing_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/tracing_map.c b/kernel/trace/tracing_map.c index 1921ade45be3..7f8da4dab69d 100644 --- a/kernel/trace/tracing_map.c +++ b/kernel/trace/tracing_map.c @@ -1076,7 +1076,7 @@ int tracing_map_sort_entries(struct tracing_map *map, struct tracing_map_sort_entry *sort_entry, **entries; int i, n_entries, ret; - entries = vmalloc(array_size(sizeof(sort_entry), map->max_elts)); + entries = vmalloc_array(map->max_elts, sizeof(sort_entry)); if (!entries) return -ENOMEM; From 1d67d67a8c88db99ebf5b1323c238929c5fa8483 Mon Sep 17 00:00:00 2001 From: Fushuai Wang Date: Mon, 11 Aug 2025 14:41:58 +0800 Subject: [PATCH 1962/2711] tracing/osnoise: Use for_each_online_cpu() instead of for_each_cpu() Replace the opencoded for_each_cpu(cpu, cpu_online_mask) loop with the more readable and equivalent for_each_online_cpu(cpu) macro. Link: https://lore.kernel.org/20250811064158.2456-1-wangfushuai@baidu.com Signed-off-by: Fushuai Wang Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace_osnoise.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace_osnoise.c b/kernel/trace/trace_osnoise.c index fd259da0aa64..4cb464894faf 100644 --- a/kernel/trace/trace_osnoise.c +++ b/kernel/trace/trace_osnoise.c @@ -271,7 +271,7 @@ static inline void tlat_var_reset(void) * So far, all the values are initialized as 0, so * zeroing the structure is perfect. */ - for_each_cpu(cpu, cpu_online_mask) { + for_each_online_cpu(cpu) { tlat_var = per_cpu_ptr(&per_cpu_timerlat_var, cpu); if (tlat_var->kthread) hrtimer_cancel(&tlat_var->timer); @@ -295,7 +295,7 @@ static inline void osn_var_reset(void) * So far, all the values are initialized as 0, so * zeroing the structure is perfect. */ - for_each_cpu(cpu, cpu_online_mask) { + for_each_online_cpu(cpu) { osn_var = per_cpu_ptr(&per_cpu_osnoise_var, cpu); memset(osn_var, 0, sizeof(*osn_var)); } From ade2105e748f85eb026d26701091213855aea633 Mon Sep 17 00:00:00 2001 From: Elijah Wright Date: Wed, 20 Aug 2025 22:39:07 -0700 Subject: [PATCH 1963/2711] tracing: Move buffer in trace_seq to end of struct TRACE_SEQ_BUFFER_SIZE is dependent on the architecture for its size. on 64-bit systems, it is 8148 bytes. forced 8-byte alignment in size_t and seq_buf means that trace_seq is 8200 bytes on 64-bit systems. moving the buffer to the end of the struct fixes the issue. there shouldn't be any side effects, i.e. pointer arithmetic on trace_seq Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Link: https://lore.kernel.org/20250821053917.23301-1-git@elijahs.space Signed-off-by: Elijah Wright Signed-off-by: Steven Rostedt (Google) --- include/linux/trace_seq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h index a93ed5ac3226..557780fe1c77 100644 --- a/include/linux/trace_seq.h +++ b/include/linux/trace_seq.h @@ -21,10 +21,10 @@ (sizeof(struct seq_buf) + sizeof(size_t) + sizeof(int))) struct trace_seq { - char buffer[TRACE_SEQ_BUFFER_SIZE]; struct seq_buf seq; size_t readpos; int full; + char buffer[TRACE_SEQ_BUFFER_SIZE]; }; static inline void From 8613a55ac57baf40e54633eab00c820515196113 Mon Sep 17 00:00:00 2001 From: Liao Yuanhong Date: Mon, 25 Aug 2025 20:31:59 +0800 Subject: [PATCH 1964/2711] tracing: Remove redundant 0 value initialization The saved_cmdlines_buffer struct is already zeroed by memset(). It's redundant to initialize s->cmdline_idx to 0. Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Link: https://lore.kernel.org/20250825123200.306272-1-liaoyuanhong@vivo.com Signed-off-by: Liao Yuanhong Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace_sched_switch.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c index cb49f7279dc8..518dfc74347a 100644 --- a/kernel/trace/trace_sched_switch.c +++ b/kernel/trace/trace_sched_switch.c @@ -224,7 +224,6 @@ static struct saved_cmdlines_buffer *allocate_cmdlines_buffer(unsigned int val) /* Place map_cmdline_to_pid array right after saved_cmdlines */ s->map_cmdline_to_pid = (unsigned *)&s->saved_cmdlines[val * TASK_COMM_LEN]; - s->cmdline_idx = 0; memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP, sizeof(s->map_pid_to_cmdline)); memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP, From 70bd70c303ad4a00b299cb2468bc6475ff90b5b1 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 5 Sep 2025 11:10:40 +0200 Subject: [PATCH 1965/2711] tracing: replace use of system_wq with system_percpu_wq Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. system_wq is a per-CPU worqueue, yet nothing in its name tells about that CPU affinity constraint, which is very often not required by users. Make it clear by adding a system_percpu_wq. queue_work() / queue_delayed_work() mod_delayed_work() will now use the new per-cpu wq: whether the user still stick on the old name a warn will be printed along a wq redirect to the new one. This patch add the new system_percpu_wq except for mm, fs and net subsystem, whom are handled in separated patches. The old wq will be kept for a few release cylces. Cc: Lai Jiangshan Cc: Frederic Weisbecker Cc: Sebastian Andrzej Siewior Cc: Michal Hocko Cc: Masami Hiramatsu Link: https://lore.kernel.org/20250905091040.109772-2-marco.crivellari@suse.com Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace_events_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c index af42aaa3d172..3169182229ad 100644 --- a/kernel/trace/trace_events_user.c +++ b/kernel/trace/trace_events_user.c @@ -835,7 +835,7 @@ void user_event_mm_remove(struct task_struct *t) * so we use a work queue after call_rcu() to run within. */ INIT_RCU_WORK(&mm->put_rwork, delayed_user_event_mm_put); - queue_rcu_work(system_wq, &mm->put_rwork); + queue_rcu_work(system_percpu_wq, &mm->put_rwork); } void user_event_mm_dup(struct task_struct *t, struct user_event_mm *old_mm) From 67600ccfc4f38ebd331b9332ac94717bfbc87ea7 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Tue, 23 Sep 2025 13:13:57 +0800 Subject: [PATCH 1966/2711] thunderbolt: Fix use-after-free in tb_dp_dprx_work The original code relies on cancel_delayed_work() in tb_dp_dprx_stop(), which does not ensure that the delayed work item tunnel->dprx_work has fully completed if it was already running. This leads to use-after-free scenarios where tb_tunnel is deallocated by tb_tunnel_put(), while tunnel->dprx_work remains active and attempts to dereference tb_tunnel in tb_dp_dprx_work(). A typical race condition is illustrated below: CPU 0 | CPU 1 tb_dp_tunnel_active() | tb_deactivate_and_free_tunnel()| tb_dp_dprx_start() tb_tunnel_deactivate() | queue_delayed_work() tb_dp_activate() | tb_dp_dprx_stop() | tb_dp_dprx_work() //delayed worker cancel_delayed_work() | tb_tunnel_put(tunnel); | | tunnel = container_of(...); //UAF | tunnel-> //UAF Replacing cancel_delayed_work() with cancel_delayed_work_sync() is not feasible as it would introduce a deadlock: both tb_dp_dprx_work() and the cleanup path acquire tb->lock, and cancel_delayed_work_sync() would wait indefinitely for the work item that cannot proceed. Instead, implement proper reference counting: - If cancel_delayed_work() returns true (work is pending), we release the reference in the stop function. - If it returns false (work is executing or already completed), the reference is released in delayed work function itself. This ensures the tb_tunnel remains valid during work item execution while preventing memory leaks. This bug was found by static analysis. Fixes: d6d458d42e1e ("thunderbolt: Handle DisplayPort tunnel activation asynchronously") Cc: stable@vger.kernel.org Signed-off-by: Duoming Zhou Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tunnel.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index 850d9b107abd..bfa0607b5574 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -1079,6 +1079,7 @@ static void tb_dp_dprx_work(struct work_struct *work) if (tunnel->callback) tunnel->callback(tunnel, tunnel->callback_data); + tb_tunnel_put(tunnel); } static int tb_dp_dprx_start(struct tb_tunnel *tunnel) @@ -1106,8 +1107,8 @@ static void tb_dp_dprx_stop(struct tb_tunnel *tunnel) if (tunnel->dprx_started) { tunnel->dprx_started = false; tunnel->dprx_canceled = true; - cancel_delayed_work(&tunnel->dprx_work); - tb_tunnel_put(tunnel); + if (cancel_delayed_work(&tunnel->dprx_work)) + tb_tunnel_put(tunnel); } } From 7109f51bcc80b79a8f31e50fa5c96a20c54197d9 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 23 Sep 2025 23:37:08 +0800 Subject: [PATCH 1967/2711] LoongArch: KVM: Add PTW feature detection on new hardware With new Loongson-3A6000/3C6000 hardware platforms (or later), hardware page table walking (PTW) feature is supported on host. So here add this feature detection on KVM host. Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/include/uapi/asm/kvm.h | 1 + arch/loongarch/kvm/vcpu.c | 2 ++ arch/loongarch/kvm/vm.c | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h index 5f354f5c6847..57ba1a563bb1 100644 --- a/arch/loongarch/include/uapi/asm/kvm.h +++ b/arch/loongarch/include/uapi/asm/kvm.h @@ -103,6 +103,7 @@ struct kvm_fpu { #define KVM_LOONGARCH_VM_FEAT_PMU 5 #define KVM_LOONGARCH_VM_FEAT_PV_IPI 6 #define KVM_LOONGARCH_VM_FEAT_PV_STEALTIME 7 +#define KVM_LOONGARCH_VM_FEAT_PTW 8 /* Device Control API on vcpu fd */ #define KVM_LOONGARCH_VCPU_CPUCFG 0 diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c index ce478151466c..9c802f7103c6 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -680,6 +680,8 @@ static int _kvm_get_cpucfg_mask(int id, u64 *v) *v |= CPUCFG2_ARMBT; if (cpu_has_lbt_mips) *v |= CPUCFG2_MIPSBT; + if (cpu_has_ptw) + *v |= CPUCFG2_PTW; return 0; case LOONGARCH_CPUCFG3: diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c index edccfc8c9cd8..a49b1c1a3dd1 100644 --- a/arch/loongarch/kvm/vm.c +++ b/arch/loongarch/kvm/vm.c @@ -146,6 +146,10 @@ static int kvm_vm_feature_has_attr(struct kvm *kvm, struct kvm_device_attr *attr if (kvm_pvtime_supported()) return 0; return -ENXIO; + case KVM_LOONGARCH_VM_FEAT_PTW: + if (cpu_has_ptw) + return 0; + return -ENXIO; default: return -ENXIO; } From 80edf90831a2c129db478b1e72b27839602b72ea Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 23 Sep 2025 23:37:08 +0800 Subject: [PATCH 1968/2711] LoongArch: KVM: Add sign extension with kernel MMIO read emulation Function kvm_complete_mmio_read() is to add sign extension with MMIO read emulation, it is used in user space MMIO read completion now. Also it should be used in kernel MMIO read emulation. Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/exit.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c index 6c9c7de7226b..45833fbe16bf 100644 --- a/arch/loongarch/kvm/exit.c +++ b/arch/loongarch/kvm/exit.c @@ -468,6 +468,8 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst) if (ret == EMULATE_DO_MMIO) { trace_kvm_mmio(KVM_TRACE_MMIO_READ, run->mmio.len, run->mmio.phys_addr, NULL); + vcpu->arch.io_gpr = rd; /* Set for kvm_complete_mmio_read() use */ + /* * If mmio device such as PCH-PIC is emulated in KVM, * it need not return to user space to handle the mmio @@ -475,16 +477,15 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst) */ idx = srcu_read_lock(&vcpu->kvm->srcu); ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, vcpu->arch.badv, - run->mmio.len, &vcpu->arch.gprs[rd]); + run->mmio.len, run->mmio.data); srcu_read_unlock(&vcpu->kvm->srcu, idx); if (!ret) { + kvm_complete_mmio_read(vcpu, run); update_pc(&vcpu->arch); vcpu->mmio_needed = 0; return EMULATE_DONE; } - /* Set for kvm_complete_mmio_read() use */ - vcpu->arch.io_gpr = rd; run->mmio.is_write = 0; vcpu->mmio_is_write = 0; return EMULATE_DO_MMIO; From 44598fe77663da1fdd59c2b01fc317afcb7bc753 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 23 Sep 2025 23:37:08 +0800 Subject: [PATCH 1969/2711] LoongArch: KVM: Add sign extension with kernel IOCSR read emulation Function kvm_complete_iocsr_read() is to add sign extension with IOCSR read emulation, it is used in user space IOCSR read completion now. Also it should be used in kernel IOCSR read emulation. Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/exit.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c index 45833fbe16bf..cb493980d874 100644 --- a/arch/loongarch/kvm/exit.c +++ b/arch/loongarch/kvm/exit.c @@ -218,16 +218,16 @@ int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu) } trace_kvm_iocsr(KVM_TRACE_IOCSR_WRITE, run->iocsr_io.len, addr, val); } else { + vcpu->arch.io_gpr = rd; /* Set register id for iocsr read completion */ idx = srcu_read_lock(&vcpu->kvm->srcu); - ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, run->iocsr_io.len, val); + ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, + run->iocsr_io.len, run->iocsr_io.data); srcu_read_unlock(&vcpu->kvm->srcu, idx); - if (ret == 0) + if (ret == 0) { + kvm_complete_iocsr_read(vcpu, run); ret = EMULATE_DONE; - else { + } else ret = EMULATE_DO_IOCSR; - /* Save register id for iocsr read completion */ - vcpu->arch.io_gpr = rd; - } trace_kvm_iocsr(KVM_TRACE_IOCSR_READ, run->iocsr_io.len, addr, NULL); } From 1cf7b2881d832f05b31ec06484774604676189e2 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 23 Sep 2025 23:37:08 +0800 Subject: [PATCH 1970/2711] LoongArch: KVM: Add implementation with IOCSR_IPI_SET IPI IOCSR register IOCSR_IPI_SET can send ipi interrupt to other vCPUs, but it can also send an interrupt to vCPU itself. Indeed there are such operations on Linux as arch_irq_work_raise() which will send ipi message to vCPU itself. Here add implementation of write operation with IOCSR_IPI_SET register. Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/ipi.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index 5a8481dda052..e339b6c7b0c3 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -7,12 +7,25 @@ #include #include +static void ipi_set(struct kvm_vcpu *vcpu, uint32_t data) +{ + uint32_t status; + struct kvm_interrupt irq; + + spin_lock(&vcpu->arch.ipi_state.lock); + status = vcpu->arch.ipi_state.status; + vcpu->arch.ipi_state.status |= data; + spin_unlock(&vcpu->arch.ipi_state.lock); + if ((status == 0) && data) { + irq.irq = LARCH_INT_IPI; + kvm_vcpu_ioctl_interrupt(vcpu, &irq); + } +} + static void ipi_send(struct kvm *kvm, uint64_t data) { - int cpu, action; - uint32_t status; + int cpu; struct kvm_vcpu *vcpu; - struct kvm_interrupt irq; cpu = ((data & 0xffffffff) >> 16) & 0x3ff; vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); @@ -21,15 +34,7 @@ static void ipi_send(struct kvm *kvm, uint64_t data) return; } - action = BIT(data & 0x1f); - spin_lock(&vcpu->arch.ipi_state.lock); - status = vcpu->arch.ipi_state.status; - vcpu->arch.ipi_state.status |= action; - spin_unlock(&vcpu->arch.ipi_state.lock); - if (status == 0) { - irq.irq = LARCH_INT_IPI; - kvm_vcpu_ioctl_interrupt(vcpu, &irq); - } + ipi_set(vcpu, BIT(data & 0x1f)); } static void ipi_clear(struct kvm_vcpu *vcpu, uint64_t data) @@ -231,7 +236,7 @@ static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, cons spin_unlock(&vcpu->arch.ipi_state.lock); break; case IOCSR_IPI_SET: - ret = -EINVAL; + ipi_set(vcpu, data); break; case IOCSR_IPI_CLEAR: /* Just clear the status of the current vcpu */ @@ -250,10 +255,10 @@ static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, cons ipi_send(vcpu->kvm, data); break; case IOCSR_MAIL_SEND: - ret = mail_send(vcpu->kvm, *(uint64_t *)val); + ret = mail_send(vcpu->kvm, data); break; case IOCSR_ANY_SEND: - ret = any_send(vcpu->kvm, *(uint64_t *)val); + ret = any_send(vcpu->kvm, data); break; default: kvm_err("%s: unknown addr: %llx\n", __func__, addr); From 3da2b0d439aa4eccc2a65e87f0bb280595d91ffe Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 23 Sep 2025 23:37:09 +0800 Subject: [PATCH 1971/2711] LoongArch: KVM: Access mailbox directly in mail_send() With function mail_send(), it is to write mailbox of other VCPUs. Existing simple APIs read_mailbox()/write_mailbox() can be used directly rather than send command on IOCSR address. Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/ipi.c | 45 ++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index e339b6c7b0c3..05cefd29282e 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -101,6 +101,34 @@ static void write_mailbox(struct kvm_vcpu *vcpu, int offset, uint64_t data, int spin_unlock(&vcpu->arch.ipi_state.lock); } +static int mail_send(struct kvm *kvm, uint64_t data) +{ + int i, cpu, mailbox, offset; + uint32_t val = 0, mask = 0; + struct kvm_vcpu *vcpu; + + cpu = ((data & 0xffffffff) >> 16) & 0x3ff; + vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); + if (unlikely(vcpu == NULL)) { + kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + return -EINVAL; + } + mailbox = ((data & 0xffffffff) >> 2) & 0x7; + offset = IOCSR_IPI_BUF_20 + mailbox * 4; + if ((data >> 27) & 0xf) { + val = read_mailbox(vcpu, offset, 4); + for (i = 0; i < 4; i++) + if (data & (BIT(27 + i))) + mask |= (0xff << (i * 8)); + val &= mask; + } + + val |= ((uint32_t)(data >> 32) & ~mask); + write_mailbox(vcpu, offset, val, 4); + + return 0; +} + static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) { int i, idx, ret; @@ -137,23 +165,6 @@ static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) return ret; } -static int mail_send(struct kvm *kvm, uint64_t data) -{ - int cpu, mailbox, offset; - struct kvm_vcpu *vcpu; - - cpu = ((data & 0xffffffff) >> 16) & 0x3ff; - vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); - if (unlikely(vcpu == NULL)) { - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); - return -EINVAL; - } - mailbox = ((data & 0xffffffff) >> 2) & 0x7; - offset = IOCSR_IPI_BASE + IOCSR_IPI_BUF_20 + mailbox * 4; - - return send_ipi_data(vcpu, offset, data); -} - static int any_send(struct kvm *kvm, uint64_t data) { int cpu, offset; From 2f412eb7650c369744420cc2d06404fe3f1fb79f Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 23 Sep 2025 23:37:09 +0800 Subject: [PATCH 1972/2711] LoongArch: KVM: Set version information at initial stage Register PCH_PIC_INT_ID constains version and supported irq number information, and it is a read only register. The detailed value can be set at initial stage, rather than read callback. Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/include/asm/kvm_pch_pic.h | 15 ++++++++++++- arch/loongarch/kvm/intc/pch_pic.c | 27 ++++++++++++++++-------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/arch/loongarch/include/asm/kvm_pch_pic.h b/arch/loongarch/include/asm/kvm_pch_pic.h index e6df6a4c1c70..7f33a3039272 100644 --- a/arch/loongarch/include/asm/kvm_pch_pic.h +++ b/arch/loongarch/include/asm/kvm_pch_pic.h @@ -34,13 +34,26 @@ #define PCH_PIC_INT_ISR_END 0x3af #define PCH_PIC_POLARITY_START 0x3e0 #define PCH_PIC_POLARITY_END 0x3e7 -#define PCH_PIC_INT_ID_VAL 0x7000000UL +#define PCH_PIC_INT_ID_VAL 0x7UL #define PCH_PIC_INT_ID_VER 0x1UL +union pch_pic_id { + struct { + uint8_t reserved_0[3]; + uint8_t id; + uint8_t version; + uint8_t reserved_1; + uint8_t irq_num; + uint8_t reserved_2; + } desc; + uint64_t data; +}; + struct loongarch_pch_pic { spinlock_t lock; struct kvm *kvm; struct kvm_io_device device; + union pch_pic_id id; uint64_t mask; /* 1:disable irq, 0:enable irq */ uint64_t htmsi_en; /* 1:msi */ uint64_t edge; /* 1:edge triggered, 0:level triggered */ diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index baf3b4faf7ea..f41ef8c42ece 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -120,20 +120,13 @@ static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int l { int offset, index, ret = 0; u32 data = 0; - u64 int_id = 0; offset = addr - s->pch_pic_base; spin_lock(&s->lock); switch (offset) { case PCH_PIC_INT_ID_START ... PCH_PIC_INT_ID_END: - /* int id version */ - int_id |= (u64)PCH_PIC_INT_ID_VER << 32; - /* irq number */ - int_id |= (u64)31 << (32 + 16); - /* int id value */ - int_id |= PCH_PIC_INT_ID_VAL; - *(u64 *)val = int_id; + *(u64 *)val = s->id.data; break; case PCH_PIC_MASK_START ... PCH_PIC_MASK_END: offset -= PCH_PIC_MASK_START; @@ -484,7 +477,7 @@ static int kvm_setup_default_irq_routing(struct kvm *kvm) static int kvm_pch_pic_create(struct kvm_device *dev, u32 type) { - int ret; + int i, ret, irq_num; struct kvm *kvm = dev->kvm; struct loongarch_pch_pic *s; @@ -500,6 +493,22 @@ static int kvm_pch_pic_create(struct kvm_device *dev, u32 type) if (!s) return -ENOMEM; + /* + * Interrupt controller identification register 1 + * Bit 24-31 Interrupt Controller ID + * Interrupt controller identification register 2 + * Bit 0-7 Interrupt Controller version number + * Bit 16-23 The number of interrupt sources supported + */ + irq_num = 32; + s->mask = -1UL; + s->id.desc.id = PCH_PIC_INT_ID_VAL; + s->id.desc.version = PCH_PIC_INT_ID_VER; + s->id.desc.irq_num = irq_num - 1; + for (i = 0; i < irq_num; i++) { + s->route_entry[i] = 1; + s->htmsi_vector[i] = i; + } spin_lock_init(&s->lock); s->kvm = kvm; kvm->arch.pch_pic = s; From eb626c7704dc9dbc2eee2c2bee281992d36de6da Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 23 Sep 2025 23:37:09 +0800 Subject: [PATCH 1973/2711] LoongArch: KVM: Add IRR and ISR register read emulation With LS7A user manual, there are registers PCH_PIC_INT_IRR_START and PCH_PIC_INT_ISR_START. So add read access emulation in function loongarch_pch_pic_read() here. Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/pch_pic.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index f41ef8c42ece..c19cf9d7b08a 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -168,6 +168,12 @@ static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int l /* we only use defalut value 0: high level triggered */ *(u32 *)val = 0; break; + case PCH_PIC_INT_IRR_START: + data = s->irr; + break; + case PCH_PIC_INT_ISR_START: + data = s->isr; + break; default: ret = -EINVAL; } From f8a73df503f5145317de992b94df603ed97e2f86 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 23 Sep 2025 23:37:09 +0800 Subject: [PATCH 1974/2711] LoongArch: KVM: Add different length support in loongarch_pch_pic_read() With function loongarch_pch_pic_read(), currently it is hardcoded length for different registers, and the length comes from exising linux pch_pic driver code. But in theory, all length 1/2/4/8 should be supported for all the registers, here add different length support about register read emulation in function loongarch_pch_pic_read(). Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/pch_pic.c | 42 ++++++++++++++----------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index c19cf9d7b08a..be63901ab7ab 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -118,55 +118,45 @@ static u32 pch_pic_write_reg(u64 *s, int high, u32 v) static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val) { - int offset, index, ret = 0; - u32 data = 0; + int ret = 0, offset; + u64 data = 0; + void *ptemp; offset = addr - s->pch_pic_base; + offset -= offset & 7; spin_lock(&s->lock); switch (offset) { case PCH_PIC_INT_ID_START ... PCH_PIC_INT_ID_END: - *(u64 *)val = s->id.data; + data = s->id.data; break; case PCH_PIC_MASK_START ... PCH_PIC_MASK_END: - offset -= PCH_PIC_MASK_START; - index = offset >> 2; - /* read mask reg */ - data = pch_pic_read_reg(&s->mask, index); - *(u32 *)val = data; + data = s->mask; break; case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END: - offset -= PCH_PIC_HTMSI_EN_START; - index = offset >> 2; /* read htmsi enable reg */ - data = pch_pic_read_reg(&s->htmsi_en, index); - *(u32 *)val = data; + data = s->htmsi_en; break; case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END: - offset -= PCH_PIC_EDGE_START; - index = offset >> 2; /* read edge enable reg */ - data = pch_pic_read_reg(&s->edge, index); - *(u32 *)val = data; + data = s->edge; break; case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END: case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END: /* we only use default mode: fixed interrupt distribution mode */ - *(u32 *)val = 0; break; case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END: /* only route to int0: eiointc */ - *(u8 *)val = 1; + ptemp = s->route_entry + (offset - PCH_PIC_ROUTE_ENTRY_START); + data = *(u64 *)ptemp; break; case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END: - offset -= PCH_PIC_HTMSI_VEC_START; /* read htmsi vector */ - data = s->htmsi_vector[offset]; - *(u8 *)val = data; + ptemp = s->htmsi_vector + (offset - PCH_PIC_HTMSI_VEC_START); + data = *(u64 *)ptemp; break; case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END: - /* we only use defalut value 0: high level triggered */ - *(u32 *)val = 0; + data = s->polarity; break; case PCH_PIC_INT_IRR_START: data = s->irr; @@ -179,6 +169,12 @@ static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int l } spin_unlock(&s->lock); + if (ret == 0) { + offset = (addr - s->pch_pic_base) & 7; + data = data >> (offset * 8); + memcpy(val, &data, len); + } + return ret; } From f851fdd895dea69e23acc80262da0b8f9e4d04ad Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 23 Sep 2025 23:37:26 +0800 Subject: [PATCH 1975/2711] LoongArch: KVM: Add different length support in loongarch_pch_pic_write() With function loongarch_pch_pic_write(), currently there is only four bytes register write support. But in theory, all length 1/2/4/8 should be supported for all the registers, here add different length support about register write emulation in function loongarch_pch_pic_write(). Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/pch_pic.c | 155 ++++++++++-------------------- 1 file changed, 52 insertions(+), 103 deletions(-) diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index be63901ab7ab..f464f1f5a67a 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -77,45 +77,6 @@ void pch_msi_set_irq(struct kvm *kvm, int irq, int level) eiointc_set_irq(kvm->arch.eiointc, irq, level); } -/* - * pch pic register is 64-bit, but it is accessed by 32-bit, - * so we use high to get whether low or high 32 bits we want - * to read. - */ -static u32 pch_pic_read_reg(u64 *s, int high) -{ - u64 val = *s; - - /* read the high 32 bits when high is 1 */ - return high ? (u32)(val >> 32) : (u32)val; -} - -/* - * pch pic register is 64-bit, but it is accessed by 32-bit, - * so we use high to get whether low or high 32 bits we want - * to write. - */ -static u32 pch_pic_write_reg(u64 *s, int high, u32 v) -{ - u64 val = *s, data = v; - - if (high) { - /* - * Clear val high 32 bits - * Write the high 32 bits when the high is 1 - */ - *s = (val << 32 >> 32) | (data << 32); - val >>= 32; - } else - /* - * Clear val low 32 bits - * Write the low 32 bits when the high is 0 - */ - *s = (val >> 32 << 32) | v; - - return (u32)val; -} - static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val) { int ret = 0, offset; @@ -205,81 +166,69 @@ static int kvm_pch_pic_read(struct kvm_vcpu *vcpu, static int loongarch_pch_pic_write(struct loongarch_pch_pic *s, gpa_t addr, int len, const void *val) { - int ret; - u32 old, data, offset, index; - u64 irq; + int ret = 0, offset; + u64 old, data, mask; + void *ptemp; - ret = 0; - data = *(u32 *)val; - offset = addr - s->pch_pic_base; + switch (len) { + case 1: + data = *(u8 *)val; + mask = 0xFF; + break; + case 2: + data = *(u16 *)val; + mask = USHRT_MAX; + break; + case 4: + data = *(u32 *)val; + mask = UINT_MAX; + break; + case 8: + default: + data = *(u64 *)val; + mask = ULONG_MAX; + break; + } + + offset = (addr - s->pch_pic_base) & 7; + mask = mask << (offset * 8); + data = data << (offset * 8); + offset = (addr - s->pch_pic_base) - offset; spin_lock(&s->lock); switch (offset) { - case PCH_PIC_MASK_START ... PCH_PIC_MASK_END: - offset -= PCH_PIC_MASK_START; - /* get whether high or low 32 bits we want to write */ - index = offset >> 2; - old = pch_pic_write_reg(&s->mask, index, data); - /* enable irq when mask value change to 0 */ - irq = (old & ~data) << (32 * index); - pch_pic_update_batch_irqs(s, irq, 1); - /* disable irq when mask value change to 1 */ - irq = (~old & data) << (32 * index); - pch_pic_update_batch_irqs(s, irq, 0); + case PCH_PIC_MASK_START: + old = s->mask; + s->mask = (old & ~mask) | data; + if (old & ~data) + pch_pic_update_batch_irqs(s, old & ~data, 1); + if (~old & data) + pch_pic_update_batch_irqs(s, ~old & data, 0); break; - case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END: - offset -= PCH_PIC_HTMSI_EN_START; - index = offset >> 2; - pch_pic_write_reg(&s->htmsi_en, index, data); + case PCH_PIC_HTMSI_EN_START: + s->htmsi_en = (s->htmsi_en & ~mask) | data; break; - case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END: - offset -= PCH_PIC_EDGE_START; - index = offset >> 2; - /* 1: edge triggered, 0: level triggered */ - pch_pic_write_reg(&s->edge, index, data); + case PCH_PIC_EDGE_START: + s->edge = (s->edge & ~mask) | data; break; - case PCH_PIC_CLEAR_START ... PCH_PIC_CLEAR_END: - offset -= PCH_PIC_CLEAR_START; - index = offset >> 2; - /* write 1 to clear edge irq */ - old = pch_pic_read_reg(&s->irr, index); - /* - * get the irq bitmap which is edge triggered and - * already set and to be cleared - */ - irq = old & pch_pic_read_reg(&s->edge, index) & data; - /* write irr to the new state where irqs have been cleared */ - pch_pic_write_reg(&s->irr, index, old & ~irq); - /* update cleared irqs */ - pch_pic_update_batch_irqs(s, irq, 0); + case PCH_PIC_POLARITY_START: + s->polarity = (s->polarity & ~mask) | data; break; - case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END: - offset -= PCH_PIC_AUTO_CTRL0_START; - index = offset >> 2; - /* we only use default mode: fixed interrupt distribution mode */ - pch_pic_write_reg(&s->auto_ctrl0, index, 0); - break; - case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END: - offset -= PCH_PIC_AUTO_CTRL1_START; - index = offset >> 2; - /* we only use default mode: fixed interrupt distribution mode */ - pch_pic_write_reg(&s->auto_ctrl1, index, 0); - break; - case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END: - offset -= PCH_PIC_ROUTE_ENTRY_START; - /* only route to int0: eiointc */ - s->route_entry[offset] = 1; + case PCH_PIC_CLEAR_START: + old = s->irr & s->edge & data; + if (old) { + s->irr &= ~old; + pch_pic_update_batch_irqs(s, old, 0); + } break; case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END: - /* route table to eiointc */ - offset -= PCH_PIC_HTMSI_VEC_START; - s->htmsi_vector[offset] = (u8)data; + ptemp = s->htmsi_vector + (offset - PCH_PIC_HTMSI_VEC_START); + *(u64 *)ptemp = (*(u64 *)ptemp & ~mask) | data; break; - case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END: - offset -= PCH_PIC_POLARITY_START; - index = offset >> 2; - /* we only use defalut value 0: high level triggered */ - pch_pic_write_reg(&s->polarity, index, 0); + /* Not implemented */ + case PCH_PIC_AUTO_CTRL0_START: + case PCH_PIC_AUTO_CTRL1_START: + case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END: break; default: ret = -EINVAL; From 77336b918f59b9c715d1f752149557a05e0bc0bc Mon Sep 17 00:00:00 2001 From: "Yury Norov (NVIDIA)" Date: Tue, 23 Sep 2025 23:37:26 +0800 Subject: [PATCH 1976/2711] LoongArch: KVM: Rework pch_pic_update_batch_irqs() Use proper bitmap API and drop all the housekeeping code. Reviewed-by: Bibo Mao Signed-off-by: Yury Norov (NVIDIA) Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/pch_pic.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index f464f1f5a67a..a698a73de399 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -35,16 +35,11 @@ static void pch_pic_update_irq(struct loongarch_pch_pic *s, int irq, int level) /* update batch irqs, the irq_mask is a bitmap of irqs */ static void pch_pic_update_batch_irqs(struct loongarch_pch_pic *s, u64 irq_mask, int level) { - int irq, bits; + unsigned int irq; + DECLARE_BITMAP(irqs, 64) = { BITMAP_FROM_U64(irq_mask) }; - /* find each irq by irqs bitmap and update each irq */ - bits = sizeof(irq_mask) * 8; - irq = find_first_bit((void *)&irq_mask, bits); - while (irq < bits) { + for_each_set_bit(irq, irqs, 64) pch_pic_update_irq(s, irq, level); - bitmap_clear((void *)&irq_mask, irq, 1); - irq = find_first_bit((void *)&irq_mask, bits); - } } /* called when a irq is triggered in pch pic */ From 66e2d96b1c5875122bfb94239989d832ccf51477 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 23 Sep 2025 23:37:26 +0800 Subject: [PATCH 1977/2711] LoongArch: KVM: Move kvm_iocsr tracepoint out of generic code The tracepoint kvm_iocsr is only used by the loongarch architecture. As trace events can take up to 5K of memory, move this tracepoint into the LoongArch specific tracing file so that it doesn't waste memory for all other architectures. Reviewed-by: Bibo Mao Signed-off-by: Steven Rostedt (Google) Signed-off-by: Huacai Chen --- arch/loongarch/kvm/trace.h | 35 +++++++++++++++++++++++++++++++++++ include/trace/events/kvm.h | 35 ----------------------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/arch/loongarch/kvm/trace.h b/arch/loongarch/kvm/trace.h index 145514dab6d5..3467ee22b704 100644 --- a/arch/loongarch/kvm/trace.h +++ b/arch/loongarch/kvm/trace.h @@ -161,6 +161,41 @@ TRACE_EVENT(kvm_aux, __entry->pc) ); +#define KVM_TRACE_IOCSR_READ_UNSATISFIED 0 +#define KVM_TRACE_IOCSR_READ 1 +#define KVM_TRACE_IOCSR_WRITE 2 + +#define kvm_trace_symbol_iocsr \ + { KVM_TRACE_IOCSR_READ_UNSATISFIED, "unsatisfied-read" }, \ + { KVM_TRACE_IOCSR_READ, "read" }, \ + { KVM_TRACE_IOCSR_WRITE, "write" } + +TRACE_EVENT(kvm_iocsr, + TP_PROTO(int type, int len, u64 gpa, void *val), + TP_ARGS(type, len, gpa, val), + + TP_STRUCT__entry( + __field( u32, type ) + __field( u32, len ) + __field( u64, gpa ) + __field( u64, val ) + ), + + TP_fast_assign( + __entry->type = type; + __entry->len = len; + __entry->gpa = gpa; + __entry->val = 0; + if (val) + memcpy(&__entry->val, val, + min_t(u32, sizeof(__entry->val), len)); + ), + + TP_printk("iocsr %s len %u gpa 0x%llx val 0x%llx", + __print_symbolic(__entry->type, kvm_trace_symbol_iocsr), + __entry->len, __entry->gpa, __entry->val) +); + TRACE_EVENT(kvm_vpid_change, TP_PROTO(struct kvm_vcpu *vcpu, unsigned long vpid), TP_ARGS(vcpu, vpid), diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h index 8b7252b8d751..b282e3a86769 100644 --- a/include/trace/events/kvm.h +++ b/include/trace/events/kvm.h @@ -156,41 +156,6 @@ TRACE_EVENT(kvm_mmio, __entry->len, __entry->gpa, __entry->val) ); -#define KVM_TRACE_IOCSR_READ_UNSATISFIED 0 -#define KVM_TRACE_IOCSR_READ 1 -#define KVM_TRACE_IOCSR_WRITE 2 - -#define kvm_trace_symbol_iocsr \ - { KVM_TRACE_IOCSR_READ_UNSATISFIED, "unsatisfied-read" }, \ - { KVM_TRACE_IOCSR_READ, "read" }, \ - { KVM_TRACE_IOCSR_WRITE, "write" } - -TRACE_EVENT(kvm_iocsr, - TP_PROTO(int type, int len, u64 gpa, void *val), - TP_ARGS(type, len, gpa, val), - - TP_STRUCT__entry( - __field( u32, type ) - __field( u32, len ) - __field( u64, gpa ) - __field( u64, val ) - ), - - TP_fast_assign( - __entry->type = type; - __entry->len = len; - __entry->gpa = gpa; - __entry->val = 0; - if (val) - memcpy(&__entry->val, val, - min_t(u32, sizeof(__entry->val), len)); - ), - - TP_printk("iocsr %s len %u gpa 0x%llx val 0x%llx", - __print_symbolic(__entry->type, kvm_trace_symbol_iocsr), - __entry->len, __entry->gpa, __entry->val) -); - #define kvm_fpu_load_symbol \ {0, "unload"}, \ {1, "load"} From 210b09fa428c078c44951170fe69234c880a05f6 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Fri, 19 Sep 2025 14:46:44 -0700 Subject: [PATCH 1978/2711] KVM: selftests: Add timing_info bit support in vmx_pmu_caps_test A new bit PERF_CAPABILITIES[17] called "PEBS_TIMING_INFO" bit is added to indicated if PEBS supports to record timing information in a new "Retried Latency" field. Since KVM requires user can only set host consistent PEBS capabilities, otherwise the PERF_CAPABILITIES setting would fail, add pebs_timing_info into the "immutable_caps" to block host inconsistent PEBS configuration and cause errors. Opportunistically drop the anythread_deprecated bit. It isn't and likely never was a PERF_CAPABILITIES flag, the test's definition snuck in when the union was copy+pasted from the kernel's definition. Signed-off-by: Dapeng Mi Tested-by: Yi Lai [sean: call out anythread_deprecated change] Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20250919214648.1585683-2-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c index a1f5ff45d518..f8deea220156 100644 --- a/tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c @@ -29,7 +29,7 @@ static union perf_capabilities { u64 pebs_baseline:1; u64 perf_metrics:1; u64 pebs_output_pt_available:1; - u64 anythread_deprecated:1; + u64 pebs_timing_info:1; }; u64 capabilities; } host_cap; @@ -44,6 +44,7 @@ static const union perf_capabilities immutable_caps = { .pebs_arch_reg = 1, .pebs_format = -1, .pebs_baseline = 1, + .pebs_timing_info = 1, }; static const union perf_capabilities format_caps = { From 571fc2833ed0195d016c96e003b3611e95e40f09 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 14:46:45 -0700 Subject: [PATCH 1979/2711] KVM: selftests: Track unavailable_mask for PMU events as 32-bit value Track the mask of "unavailable" PMU events as a 32-bit value. While bits 31:9 are currently reserved, silently truncating those bits is unnecessary and asking for missed coverage. To avoid running afoul of the sanity check in vcpu_set_cpuid_property(), explicitly adjust the mask based on the non-reserved bits as reported by KVM's supported CPUID. Opportunistically update the "all ones" testcase to pass -1u instead of 0xff. Reviewed-by: Dapeng Mi Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20250919214648.1585683-3-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86/pmu_counters_test.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/pmu_counters_test.c b/tools/testing/selftests/kvm/x86/pmu_counters_test.c index 8aaaf25b6111..1ef038c4c73f 100644 --- a/tools/testing/selftests/kvm/x86/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86/pmu_counters_test.c @@ -311,7 +311,7 @@ static void guest_test_arch_events(void) } static void test_arch_events(uint8_t pmu_version, uint64_t perf_capabilities, - uint8_t length, uint8_t unavailable_mask) + uint8_t length, uint32_t unavailable_mask) { struct kvm_vcpu *vcpu; struct kvm_vm *vm; @@ -320,6 +320,9 @@ static void test_arch_events(uint8_t pmu_version, uint64_t perf_capabilities, if (!pmu_version) return; + unavailable_mask &= GENMASK(X86_PROPERTY_PMU_EVENTS_MASK.hi_bit, + X86_PROPERTY_PMU_EVENTS_MASK.lo_bit); + vm = pmu_vm_create_with_one_vcpu(&vcpu, guest_test_arch_events, pmu_version, perf_capabilities); @@ -630,7 +633,7 @@ static void test_intel_counters(void) */ for (j = 0; j <= NR_INTEL_ARCH_EVENTS + 1; j++) { test_arch_events(v, perf_caps[i], j, 0); - test_arch_events(v, perf_caps[i], j, 0xff); + test_arch_events(v, perf_caps[i], j, -1u); for (k = 0; k < NR_INTEL_ARCH_EVENTS; k++) test_arch_events(v, perf_caps[i], j, BIT(k)); From 1fcd3053aa1a6d4c417450c92ddb960b9edb1bf1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 14:46:46 -0700 Subject: [PATCH 1980/2711] KVM: selftests: Reduce number of "unavailable PMU events" combos tested Reduce the number of combinations of unavailable PMU events masks that are testing by the PMU counters test. In reality, testing every possible combination isn't all that interesting, and certainly not worth the tens of seconds (or worse, minutes) of runtime. Fully testing the N^2 space will be especially problematic in the near future, as 5! new arch events are on their way. Use alternating bit patterns (and 0 and -1u) in the hopes that _if_ there is ever a KVM bug, it's not something horribly convoluted that shows up only with a super specific pattern/value. Reported-by: Dapeng Mi Reviewed-by: Dapeng Mi Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20250919214648.1585683-4-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86/pmu_counters_test.c | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/pmu_counters_test.c b/tools/testing/selftests/kvm/x86/pmu_counters_test.c index 1ef038c4c73f..c6987a9b65bf 100644 --- a/tools/testing/selftests/kvm/x86/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86/pmu_counters_test.c @@ -577,6 +577,26 @@ static void test_intel_counters(void) PMU_CAP_FW_WRITES, }; + /* + * To keep the total runtime reasonable, test only a handful of select, + * semi-arbitrary values for the mask of unavailable PMU events. Test + * 0 (all events available) and all ones (no events available) as well + * as alternating bit sequencues, e.g. to detect if KVM is checking the + * wrong bit(s). + */ + const uint32_t unavailable_masks[] = { + 0x0, + 0xffffffffu, + 0xaaaaaaaau, + 0x55555555u, + 0xf0f0f0f0u, + 0x0f0f0f0fu, + 0xa0a0a0a0u, + 0x0a0a0a0au, + 0x50505050u, + 0x05050505u, + }; + /* * Test up to PMU v5, which is the current maximum version defined by * Intel, i.e. is the last version that is guaranteed to be backwards @@ -614,16 +634,7 @@ static void test_intel_counters(void) pr_info("Testing arch events, PMU version %u, perf_caps = %lx\n", v, perf_caps[i]); - /* - * To keep the total runtime reasonable, test every - * possible non-zero, non-reserved bitmap combination - * only with the native PMU version and the full bit - * vector length. - */ - if (v == pmu_version) { - for (k = 1; k < (BIT(NR_INTEL_ARCH_EVENTS) - 1); k++) - test_arch_events(v, perf_caps[i], NR_INTEL_ARCH_EVENTS, k); - } + /* * Test single bits for all PMU version and lengths up * the number of events +1 (to verify KVM doesn't do @@ -632,11 +643,8 @@ static void test_intel_counters(void) * ones i.e. all events being available and unavailable. */ for (j = 0; j <= NR_INTEL_ARCH_EVENTS + 1; j++) { - test_arch_events(v, perf_caps[i], j, 0); - test_arch_events(v, perf_caps[i], j, -1u); - - for (k = 0; k < NR_INTEL_ARCH_EVENTS; k++) - test_arch_events(v, perf_caps[i], j, BIT(k)); + for (k = 1; k < ARRAY_SIZE(unavailable_masks); k++) + test_arch_events(v, perf_caps[i], j, unavailable_masks[k]); } pr_info("Testing GP counters, PMU version %u, perf_caps = %lx\n", From 2922b595886575ebef46e65a0d4c8a857c5cd464 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Fri, 19 Sep 2025 14:46:47 -0700 Subject: [PATCH 1981/2711] KVM: selftests: Validate more arch-events in pmu_counters_test Add support for 5 new architectural events (4 topdown level 1 metrics events and LBR inserts event) that will first show up in Intel's Clearwater Forest CPUs. Detailed info about the new events can be found in SDM section 21.2.7 "Pre-defined Architectural Performance Events". Signed-off-by: Dapeng Mi Tested-by: Yi Lai [sean: drop "unavailable_mask" changes] Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20250919214648.1585683-5-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/x86/pmu.h | 10 ++++++++++ tools/testing/selftests/kvm/include/x86/processor.h | 7 ++++++- tools/testing/selftests/kvm/lib/x86/pmu.c | 5 +++++ tools/testing/selftests/kvm/x86/pmu_counters_test.c | 8 ++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/include/x86/pmu.h b/tools/testing/selftests/kvm/include/x86/pmu.h index 3c10c4dc0ae8..2aabda2da002 100644 --- a/tools/testing/selftests/kvm/include/x86/pmu.h +++ b/tools/testing/selftests/kvm/include/x86/pmu.h @@ -61,6 +61,11 @@ #define INTEL_ARCH_BRANCHES_RETIRED RAW_EVENT(0xc4, 0x00) #define INTEL_ARCH_BRANCHES_MISPREDICTED RAW_EVENT(0xc5, 0x00) #define INTEL_ARCH_TOPDOWN_SLOTS RAW_EVENT(0xa4, 0x01) +#define INTEL_ARCH_TOPDOWN_BE_BOUND RAW_EVENT(0xa4, 0x02) +#define INTEL_ARCH_TOPDOWN_BAD_SPEC RAW_EVENT(0x73, 0x00) +#define INTEL_ARCH_TOPDOWN_FE_BOUND RAW_EVENT(0x9c, 0x01) +#define INTEL_ARCH_TOPDOWN_RETIRING RAW_EVENT(0xc2, 0x02) +#define INTEL_ARCH_LBR_INSERTS RAW_EVENT(0xe4, 0x01) #define AMD_ZEN_CORE_CYCLES RAW_EVENT(0x76, 0x00) #define AMD_ZEN_INSTRUCTIONS_RETIRED RAW_EVENT(0xc0, 0x00) @@ -80,6 +85,11 @@ enum intel_pmu_architectural_events { INTEL_ARCH_BRANCHES_RETIRED_INDEX, INTEL_ARCH_BRANCHES_MISPREDICTED_INDEX, INTEL_ARCH_TOPDOWN_SLOTS_INDEX, + INTEL_ARCH_TOPDOWN_BE_BOUND_INDEX, + INTEL_ARCH_TOPDOWN_BAD_SPEC_INDEX, + INTEL_ARCH_TOPDOWN_FE_BOUND_INDEX, + INTEL_ARCH_TOPDOWN_RETIRING_INDEX, + INTEL_ARCH_LBR_INSERTS_INDEX, NR_INTEL_ARCH_EVENTS, }; diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h index efcc4b1de523..e8bad89fbb7f 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -265,7 +265,7 @@ struct kvm_x86_cpu_property { #define X86_PROPERTY_PMU_NR_GP_COUNTERS KVM_X86_CPU_PROPERTY(0xa, 0, EAX, 8, 15) #define X86_PROPERTY_PMU_GP_COUNTERS_BIT_WIDTH KVM_X86_CPU_PROPERTY(0xa, 0, EAX, 16, 23) #define X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH KVM_X86_CPU_PROPERTY(0xa, 0, EAX, 24, 31) -#define X86_PROPERTY_PMU_EVENTS_MASK KVM_X86_CPU_PROPERTY(0xa, 0, EBX, 0, 7) +#define X86_PROPERTY_PMU_EVENTS_MASK KVM_X86_CPU_PROPERTY(0xa, 0, EBX, 0, 12) #define X86_PROPERTY_PMU_FIXED_COUNTERS_BITMASK KVM_X86_CPU_PROPERTY(0xa, 0, ECX, 0, 31) #define X86_PROPERTY_PMU_NR_FIXED_COUNTERS KVM_X86_CPU_PROPERTY(0xa, 0, EDX, 0, 4) #define X86_PROPERTY_PMU_FIXED_COUNTERS_BIT_WIDTH KVM_X86_CPU_PROPERTY(0xa, 0, EDX, 5, 12) @@ -332,6 +332,11 @@ struct kvm_x86_pmu_feature { #define X86_PMU_FEATURE_BRANCH_INSNS_RETIRED KVM_X86_PMU_FEATURE(EBX, 5) #define X86_PMU_FEATURE_BRANCHES_MISPREDICTED KVM_X86_PMU_FEATURE(EBX, 6) #define X86_PMU_FEATURE_TOPDOWN_SLOTS KVM_X86_PMU_FEATURE(EBX, 7) +#define X86_PMU_FEATURE_TOPDOWN_BE_BOUND KVM_X86_PMU_FEATURE(EBX, 8) +#define X86_PMU_FEATURE_TOPDOWN_BAD_SPEC KVM_X86_PMU_FEATURE(EBX, 9) +#define X86_PMU_FEATURE_TOPDOWN_FE_BOUND KVM_X86_PMU_FEATURE(EBX, 10) +#define X86_PMU_FEATURE_TOPDOWN_RETIRING KVM_X86_PMU_FEATURE(EBX, 11) +#define X86_PMU_FEATURE_LBR_INSERTS KVM_X86_PMU_FEATURE(EBX, 12) #define X86_PMU_FEATURE_INSNS_RETIRED_FIXED KVM_X86_PMU_FEATURE(ECX, 0) #define X86_PMU_FEATURE_CPU_CYCLES_FIXED KVM_X86_PMU_FEATURE(ECX, 1) diff --git a/tools/testing/selftests/kvm/lib/x86/pmu.c b/tools/testing/selftests/kvm/lib/x86/pmu.c index f31f0427c17c..5ab44bf54773 100644 --- a/tools/testing/selftests/kvm/lib/x86/pmu.c +++ b/tools/testing/selftests/kvm/lib/x86/pmu.c @@ -19,6 +19,11 @@ const uint64_t intel_pmu_arch_events[] = { INTEL_ARCH_BRANCHES_RETIRED, INTEL_ARCH_BRANCHES_MISPREDICTED, INTEL_ARCH_TOPDOWN_SLOTS, + INTEL_ARCH_TOPDOWN_BE_BOUND, + INTEL_ARCH_TOPDOWN_BAD_SPEC, + INTEL_ARCH_TOPDOWN_FE_BOUND, + INTEL_ARCH_TOPDOWN_RETIRING, + INTEL_ARCH_LBR_INSERTS, }; kvm_static_assert(ARRAY_SIZE(intel_pmu_arch_events) == NR_INTEL_ARCH_EVENTS); diff --git a/tools/testing/selftests/kvm/x86/pmu_counters_test.c b/tools/testing/selftests/kvm/x86/pmu_counters_test.c index c6987a9b65bf..24599d98f898 100644 --- a/tools/testing/selftests/kvm/x86/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86/pmu_counters_test.c @@ -75,6 +75,11 @@ static struct kvm_intel_pmu_event intel_event_to_feature(uint8_t idx) [INTEL_ARCH_BRANCHES_RETIRED_INDEX] = { X86_PMU_FEATURE_BRANCH_INSNS_RETIRED, X86_PMU_FEATURE_NULL }, [INTEL_ARCH_BRANCHES_MISPREDICTED_INDEX] = { X86_PMU_FEATURE_BRANCHES_MISPREDICTED, X86_PMU_FEATURE_NULL }, [INTEL_ARCH_TOPDOWN_SLOTS_INDEX] = { X86_PMU_FEATURE_TOPDOWN_SLOTS, X86_PMU_FEATURE_TOPDOWN_SLOTS_FIXED }, + [INTEL_ARCH_TOPDOWN_BE_BOUND_INDEX] = { X86_PMU_FEATURE_TOPDOWN_BE_BOUND, X86_PMU_FEATURE_NULL }, + [INTEL_ARCH_TOPDOWN_BAD_SPEC_INDEX] = { X86_PMU_FEATURE_TOPDOWN_BAD_SPEC, X86_PMU_FEATURE_NULL }, + [INTEL_ARCH_TOPDOWN_FE_BOUND_INDEX] = { X86_PMU_FEATURE_TOPDOWN_FE_BOUND, X86_PMU_FEATURE_NULL }, + [INTEL_ARCH_TOPDOWN_RETIRING_INDEX] = { X86_PMU_FEATURE_TOPDOWN_RETIRING, X86_PMU_FEATURE_NULL }, + [INTEL_ARCH_LBR_INSERTS_INDEX] = { X86_PMU_FEATURE_LBR_INSERTS, X86_PMU_FEATURE_NULL }, }; kvm_static_assert(ARRAY_SIZE(__intel_event_to_feature) == NR_INTEL_ARCH_EVENTS); @@ -171,9 +176,12 @@ static void guest_assert_event_count(uint8_t idx, uint32_t pmc, uint32_t pmc_msr fallthrough; case INTEL_ARCH_CPU_CYCLES_INDEX: case INTEL_ARCH_REFERENCE_CYCLES_INDEX: + case INTEL_ARCH_TOPDOWN_BE_BOUND_INDEX: + case INTEL_ARCH_TOPDOWN_FE_BOUND_INDEX: GUEST_ASSERT_NE(count, 0); break; case INTEL_ARCH_TOPDOWN_SLOTS_INDEX: + case INTEL_ARCH_TOPDOWN_RETIRING_INDEX: __GUEST_ASSERT(count >= NUM_INSNS_RETIRED, "Expected top-down slots >= %u, got count = %lu", NUM_INSNS_RETIRED, count); From c435978e4ffe87c6baee1290118039187eafc698 Mon Sep 17 00:00:00 2001 From: dongsheng Date: Fri, 19 Sep 2025 14:46:48 -0700 Subject: [PATCH 1982/2711] KVM: selftests: Handle Intel Atom errata that leads to PMU event overcount Add a PMU errata framework and use it to relax precise event counts on Atom platforms that overcount "Instruction Retired" and "Branch Instruction Retired" events, as the overcount issues on VM-Exit/VM-Entry are impossible to prevent from userspace, e.g. the test can't prevent host IRQs. Setup errata during early initialization and automatically sync the mask to VMs so that tests can check for errata without having to manually manage host=>guest variables. For Intel Atom CPUs, the PMU events "Instruction Retired" or "Branch Instruction Retired" may be overcounted for some certain instructions, like FAR CALL/JMP, RETF, IRET, VMENTRY/VMEXIT/VMPTRLD and complex SGX/SMX/CSTATE instructions/flows. The detailed information can be found in the errata (section SRF7): https://edc.intel.com/content/www/us/en/design/products-and-solutions/processors-and-chipsets/sierra-forest/xeon-6700-series-processor-with-e-cores-specification-update/errata-details/ For the Atom platforms before Sierra Forest (including Sierra Forest), Both 2 events "Instruction Retired" and "Branch Instruction Retired" would be overcounted on these certain instructions, but for Clearwater Forest only "Instruction Retired" event is overcounted on these instructions. Signed-off-by: dongsheng Co-developed-by: Dapeng Mi Signed-off-by: Dapeng Mi Tested-by: Yi Lai Co-developed-by: Sean Christopherson Reviewed-by: Dapeng Mi Tested-by: Dapeng Mi Link: https://lore.kernel.org/r/20250919214648.1585683-6-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/x86/pmu.h | 16 +++++++ tools/testing/selftests/kvm/lib/x86/pmu.c | 44 +++++++++++++++++++ .../testing/selftests/kvm/lib/x86/processor.c | 4 ++ .../selftests/kvm/x86/pmu_counters_test.c | 12 ++++- .../selftests/kvm/x86/pmu_event_filter_test.c | 4 +- 5 files changed, 77 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86/pmu.h b/tools/testing/selftests/kvm/include/x86/pmu.h index 2aabda2da002..72575eadb63a 100644 --- a/tools/testing/selftests/kvm/include/x86/pmu.h +++ b/tools/testing/selftests/kvm/include/x86/pmu.h @@ -5,8 +5,11 @@ #ifndef SELFTEST_KVM_PMU_H #define SELFTEST_KVM_PMU_H +#include #include +#include + #define KVM_PMU_EVENT_FILTER_MAX_EVENTS 300 /* @@ -104,4 +107,17 @@ enum amd_pmu_zen_events { extern const uint64_t intel_pmu_arch_events[]; extern const uint64_t amd_pmu_zen_events[]; +enum pmu_errata { + INSTRUCTIONS_RETIRED_OVERCOUNT, + BRANCHES_RETIRED_OVERCOUNT, +}; +extern uint64_t pmu_errata_mask; + +void kvm_init_pmu_errata(void); + +static inline bool this_pmu_has_errata(enum pmu_errata errata) +{ + return pmu_errata_mask & BIT_ULL(errata); +} + #endif /* SELFTEST_KVM_PMU_H */ diff --git a/tools/testing/selftests/kvm/lib/x86/pmu.c b/tools/testing/selftests/kvm/lib/x86/pmu.c index 5ab44bf54773..34cb57d1d671 100644 --- a/tools/testing/selftests/kvm/lib/x86/pmu.c +++ b/tools/testing/selftests/kvm/lib/x86/pmu.c @@ -8,6 +8,7 @@ #include #include "kvm_util.h" +#include "processor.h" #include "pmu.h" const uint64_t intel_pmu_arch_events[] = { @@ -34,3 +35,46 @@ const uint64_t amd_pmu_zen_events[] = { AMD_ZEN_BRANCHES_MISPREDICTED, }; kvm_static_assert(ARRAY_SIZE(amd_pmu_zen_events) == NR_AMD_ZEN_EVENTS); + +/* + * For Intel Atom CPUs, the PMU events "Instruction Retired" or + * "Branch Instruction Retired" may be overcounted for some certain + * instructions, like FAR CALL/JMP, RETF, IRET, VMENTRY/VMEXIT/VMPTRLD + * and complex SGX/SMX/CSTATE instructions/flows. + * + * The detailed information can be found in the errata (section SRF7): + * https://edc.intel.com/content/www/us/en/design/products-and-solutions/processors-and-chipsets/sierra-forest/xeon-6700-series-processor-with-e-cores-specification-update/errata-details/ + * + * For the Atom platforms before Sierra Forest (including Sierra Forest), + * Both 2 events "Instruction Retired" and "Branch Instruction Retired" would + * be overcounted on these certain instructions, but for Clearwater Forest + * only "Instruction Retired" event is overcounted on these instructions. + */ +static uint64_t get_pmu_errata(void) +{ + if (!this_cpu_is_intel()) + return 0; + + if (this_cpu_family() != 0x6) + return 0; + + switch (this_cpu_model()) { + case 0xDD: /* Clearwater Forest */ + return BIT_ULL(INSTRUCTIONS_RETIRED_OVERCOUNT); + case 0xAF: /* Sierra Forest */ + case 0x4D: /* Avaton, Rangely */ + case 0x5F: /* Denverton */ + case 0x86: /* Jacobsville */ + return BIT_ULL(INSTRUCTIONS_RETIRED_OVERCOUNT) | + BIT_ULL(BRANCHES_RETIRED_OVERCOUNT); + default: + return 0; + } +} + +uint64_t pmu_errata_mask; + +void kvm_init_pmu_errata(void) +{ + pmu_errata_mask = get_pmu_errata(); +} diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index 3b63c99f7b96..4402d2e1ea69 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -6,6 +6,7 @@ #include "linux/bitmap.h" #include "test_util.h" #include "kvm_util.h" +#include "pmu.h" #include "processor.h" #include "sev.h" @@ -638,6 +639,7 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm) sync_global_to_guest(vm, host_cpu_is_intel); sync_global_to_guest(vm, host_cpu_is_amd); sync_global_to_guest(vm, is_forced_emulation_enabled); + sync_global_to_guest(vm, pmu_errata_mask); if (is_sev_vm(vm)) { struct kvm_sev_init init = { 0 }; @@ -1269,6 +1271,8 @@ void kvm_selftest_arch_init(void) host_cpu_is_intel = this_cpu_is_intel(); host_cpu_is_amd = this_cpu_is_amd(); is_forced_emulation_enabled = kvm_is_forced_emulation_enabled(); + + kvm_init_pmu_errata(); } bool sys_clocksource_is_based_on_tsc(void) diff --git a/tools/testing/selftests/kvm/x86/pmu_counters_test.c b/tools/testing/selftests/kvm/x86/pmu_counters_test.c index 24599d98f898..eb6c12a2cdd4 100644 --- a/tools/testing/selftests/kvm/x86/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86/pmu_counters_test.c @@ -163,10 +163,18 @@ static void guest_assert_event_count(uint8_t idx, uint32_t pmc, uint32_t pmc_msr switch (idx) { case INTEL_ARCH_INSTRUCTIONS_RETIRED_INDEX: - GUEST_ASSERT_EQ(count, NUM_INSNS_RETIRED); + /* Relax precise count check due to VM-EXIT/VM-ENTRY overcount issue */ + if (this_pmu_has_errata(INSTRUCTIONS_RETIRED_OVERCOUNT)) + GUEST_ASSERT(count >= NUM_INSNS_RETIRED); + else + GUEST_ASSERT_EQ(count, NUM_INSNS_RETIRED); break; case INTEL_ARCH_BRANCHES_RETIRED_INDEX: - GUEST_ASSERT_EQ(count, NUM_BRANCH_INSNS_RETIRED); + /* Relax precise count check due to VM-EXIT/VM-ENTRY overcount issue */ + if (this_pmu_has_errata(BRANCHES_RETIRED_OVERCOUNT)) + GUEST_ASSERT(count >= NUM_BRANCH_INSNS_RETIRED); + else + GUEST_ASSERT_EQ(count, NUM_BRANCH_INSNS_RETIRED); break; case INTEL_ARCH_LLC_REFERENCES_INDEX: case INTEL_ARCH_LLC_MISSES_INDEX: diff --git a/tools/testing/selftests/kvm/x86/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86/pmu_event_filter_test.c index c15513cd74d1..1c5b7611db24 100644 --- a/tools/testing/selftests/kvm/x86/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86/pmu_event_filter_test.c @@ -214,8 +214,10 @@ static void remove_event(struct __kvm_pmu_event_filter *f, uint64_t event) do { \ uint64_t br = pmc_results.branches_retired; \ uint64_t ir = pmc_results.instructions_retired; \ + bool br_matched = this_pmu_has_errata(BRANCHES_RETIRED_OVERCOUNT) ? \ + br >= NUM_BRANCHES : br == NUM_BRANCHES; \ \ - if (br && br != NUM_BRANCHES) \ + if (br && !br_matched) \ pr_info("%s: Branch instructions retired = %lu (expected %u)\n", \ __func__, br, NUM_BRANCHES); \ TEST_ASSERT(br, "%s: Branch instructions retired = %lu (expected > 0)", \ From ff86b48d4ce3bdd8d2353c166e4c905f92cddd78 Mon Sep 17 00:00:00 2001 From: Sukrut Heroorkar Date: Mon, 8 Sep 2025 23:05:46 +0200 Subject: [PATCH 1983/2711] selftests/kvm: remove stale TODO in xapic_state_test The TODO about using the number of vCPUs instead of vcpu.id + 1 was already addressed by commit 376bc1b458c9 ("KVM: selftests: Don't assume vcpu->id is '0' in xAPIC state test"). The comment is now stale and can be removed. Signed-off-by: Sukrut Heroorkar Link: https://lore.kernel.org/r/20250908210547.12748-1-hsukrut3@gmail.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86/xapic_state_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/xapic_state_test.c b/tools/testing/selftests/kvm/x86/xapic_state_test.c index fdebff1165c7..3b4814c55722 100644 --- a/tools/testing/selftests/kvm/x86/xapic_state_test.c +++ b/tools/testing/selftests/kvm/x86/xapic_state_test.c @@ -120,8 +120,8 @@ static void test_icr(struct xapic_vcpu *x) __test_icr(x, icr | i); /* - * Send all flavors of IPIs to non-existent vCPUs. TODO: use number of - * vCPUs, not vcpu.id + 1. Arbitrarily use vector 0xff. + * Send all flavors of IPIs to non-existent vCPUs. Arbitrarily use + * vector 0xff. */ icr = APIC_INT_ASSERT | 0xff; for (i = 0; i < 0xff; i++) { From df1f294013da715f32521b3d0a69773e660a1af5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:51 -0700 Subject: [PATCH 1984/2711] KVM: selftests: Add ex_str() to print human friendly name of exception vectors Steal exception_mnemonic() from KVM-Unit-Tests as ex_str() (to keep line lengths reasonable) and use it in assert messages that currently print the raw vector number. Co-developed-by: Chao Gao Signed-off-by: Chao Gao Link: https://lore.kernel.org/r/20250919223258.1604852-45-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/x86/processor.h | 2 ++ .../testing/selftests/kvm/lib/x86/processor.c | 33 +++++++++++++++++++ .../selftests/kvm/x86/hyperv_features.c | 16 ++++----- .../selftests/kvm/x86/monitor_mwait_test.c | 8 ++--- .../selftests/kvm/x86/pmu_counters_test.c | 4 +-- .../selftests/kvm/x86/vmx_pmu_caps_test.c | 4 +-- .../selftests/kvm/x86/xcr0_cpuid_test.c | 12 +++---- 7 files changed, 57 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h index e8bad89fbb7f..fbe875eafca5 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -34,6 +34,8 @@ extern uint64_t guest_tsc_khz; #define NMI_VECTOR 0x02 +const char *ex_str(int vector); + #define X86_EFLAGS_FIXED (1u << 1) #define X86_CR4_VME (1ul << 0) diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index 4402d2e1ea69..33b0c436b006 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -24,6 +24,39 @@ bool host_cpu_is_intel; bool is_forced_emulation_enabled; uint64_t guest_tsc_khz; +const char *ex_str(int vector) +{ + switch (vector) { +#define VEC_STR(v) case v##_VECTOR: return "#" #v + case DE_VECTOR: return "no exception"; + case KVM_MAGIC_DE_VECTOR: return "#DE"; + VEC_STR(DB); + VEC_STR(NMI); + VEC_STR(BP); + VEC_STR(OF); + VEC_STR(BR); + VEC_STR(UD); + VEC_STR(NM); + VEC_STR(DF); + VEC_STR(TS); + VEC_STR(NP); + VEC_STR(SS); + VEC_STR(GP); + VEC_STR(PF); + VEC_STR(MF); + VEC_STR(AC); + VEC_STR(MC); + VEC_STR(XM); + VEC_STR(VE); + VEC_STR(CP); + VEC_STR(HV); + VEC_STR(VC); + VEC_STR(SX); + default: return "#??"; +#undef VEC_STR + } +} + static void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent) { fprintf(stream, "%*srax: 0x%.16llx rbx: 0x%.16llx " diff --git a/tools/testing/selftests/kvm/x86/hyperv_features.c b/tools/testing/selftests/kvm/x86/hyperv_features.c index 068e9c69710d..99d327084172 100644 --- a/tools/testing/selftests/kvm/x86/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86/hyperv_features.c @@ -54,12 +54,12 @@ static void guest_msr(struct msr_data *msr) if (msr->fault_expected) __GUEST_ASSERT(vector == GP_VECTOR, - "Expected #GP on %sMSR(0x%x), got vector '0x%x'", - msr->write ? "WR" : "RD", msr->idx, vector); + "Expected #GP on %sMSR(0x%x), got %s", + msr->write ? "WR" : "RD", msr->idx, ex_str(vector)); else __GUEST_ASSERT(!vector, - "Expected success on %sMSR(0x%x), got vector '0x%x'", - msr->write ? "WR" : "RD", msr->idx, vector); + "Expected success on %sMSR(0x%x), got %s", + msr->write ? "WR" : "RD", msr->idx, ex_str(vector)); if (vector || is_write_only_msr(msr->idx)) goto done; @@ -102,12 +102,12 @@ static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) vector = __hyperv_hypercall(hcall->control, input, output, &res); if (hcall->ud_expected) { __GUEST_ASSERT(vector == UD_VECTOR, - "Expected #UD for control '%lu', got vector '0x%x'", - hcall->control, vector); + "Expected #UD for control '%lu', got %s", + hcall->control, ex_str(vector)); } else { __GUEST_ASSERT(!vector, - "Expected no exception for control '%lu', got vector '0x%x'", - hcall->control, vector); + "Expected no exception for control '%lu', got %s", + hcall->control, ex_str(vector)); GUEST_ASSERT_EQ(res, hcall->expect); } diff --git a/tools/testing/selftests/kvm/x86/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86/monitor_mwait_test.c index 0eb371c62ab8..e45c028d2a7e 100644 --- a/tools/testing/selftests/kvm/x86/monitor_mwait_test.c +++ b/tools/testing/selftests/kvm/x86/monitor_mwait_test.c @@ -30,12 +30,12 @@ do { \ \ if (fault_wanted) \ __GUEST_ASSERT((vector) == UD_VECTOR, \ - "Expected #UD on " insn " for testcase '0x%x', got '0x%x'", \ - testcase, vector); \ + "Expected #UD on " insn " for testcase '0x%x', got %s", \ + testcase, ex_str(vector)); \ else \ __GUEST_ASSERT(!(vector), \ - "Expected success on " insn " for testcase '0x%x', got '0x%x'", \ - testcase, vector); \ + "Expected success on " insn " for testcase '0x%x', got %s", \ + testcase, ex_str(vector)); \ } while (0) static void guest_monitor_wait(void *arg) diff --git a/tools/testing/selftests/kvm/x86/pmu_counters_test.c b/tools/testing/selftests/kvm/x86/pmu_counters_test.c index eb6c12a2cdd4..bb215230cc8a 100644 --- a/tools/testing/selftests/kvm/x86/pmu_counters_test.c +++ b/tools/testing/selftests/kvm/x86/pmu_counters_test.c @@ -363,8 +363,8 @@ static void test_arch_events(uint8_t pmu_version, uint64_t perf_capabilities, #define GUEST_ASSERT_PMC_MSR_ACCESS(insn, msr, expect_gp, vector) \ __GUEST_ASSERT(expect_gp ? vector == GP_VECTOR : !vector, \ - "Expected %s on " #insn "(0x%x), got vector %u", \ - expect_gp ? "#GP" : "no fault", msr, vector) \ + "Expected %s on " #insn "(0x%x), got %s", \ + expect_gp ? "#GP" : "no fault", msr, ex_str(vector)) \ #define GUEST_ASSERT_PMC_VALUE(insn, msr, val, expected) \ __GUEST_ASSERT(val == expected, \ diff --git a/tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c index f8deea220156..7ff6f62e20a3 100644 --- a/tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c @@ -57,8 +57,8 @@ static void guest_test_perf_capabilities_gp(uint64_t val) uint8_t vector = wrmsr_safe(MSR_IA32_PERF_CAPABILITIES, val); __GUEST_ASSERT(vector == GP_VECTOR, - "Expected #GP for value '0x%lx', got vector '0x%x'", - val, vector); + "Expected #GP for value '0x%lx', got %s", + val, ex_str(vector)); } static void guest_code(uint64_t current_val) diff --git a/tools/testing/selftests/kvm/x86/xcr0_cpuid_test.c b/tools/testing/selftests/kvm/x86/xcr0_cpuid_test.c index c8a5c5e51661..d038c1571729 100644 --- a/tools/testing/selftests/kvm/x86/xcr0_cpuid_test.c +++ b/tools/testing/selftests/kvm/x86/xcr0_cpuid_test.c @@ -81,13 +81,13 @@ static void guest_code(void) vector = xsetbv_safe(0, XFEATURE_MASK_FP); __GUEST_ASSERT(!vector, - "Expected success on XSETBV(FP), got vector '0x%x'", - vector); + "Expected success on XSETBV(FP), got %s", + ex_str(vector)); vector = xsetbv_safe(0, supported_xcr0); __GUEST_ASSERT(!vector, - "Expected success on XSETBV(0x%lx), got vector '0x%x'", - supported_xcr0, vector); + "Expected success on XSETBV(0x%lx), got %s", + supported_xcr0, ex_str(vector)); for (i = 0; i < 64; i++) { if (supported_xcr0 & BIT_ULL(i)) @@ -95,8 +95,8 @@ static void guest_code(void) vector = xsetbv_safe(0, supported_xcr0 | BIT_ULL(i)); __GUEST_ASSERT(vector == GP_VECTOR, - "Expected #GP on XSETBV(0x%llx), supported XCR0 = %lx, got vector '0x%x'", - BIT_ULL(i), supported_xcr0, vector); + "Expected #GP on XSETBV(0x%llx), supported XCR0 = %lx, got %s", + BIT_ULL(i), supported_xcr0, ex_str(vector)); } GUEST_DONE(); From e0ff302b79c54567eb6b8f609e76c633978ff06d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:08 -0700 Subject: [PATCH 1985/2711] KVM: SEV: Rename kvm_ghcb_get_sw_exit_code() to kvm_get_cached_sw_exit_code() Rename kvm_ghcb_get_sw_exit_code() to kvm_get_cached_sw_exit_code() to make it clear that KVM is getting the cached value, not reading directly from the guest-controlled GHCB. More importantly, vacating kvm_ghcb_get_sw_exit_code() will allow adding a KVM-specific macro-built kvm_ghcb_get_##field() helper to read values from the GHCB. No functional change intended. Reviewed-by: Tom Lendacky Link: https://lore.kernel.org/r/20250919223258.1604852-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index a95b862afa23..5456a71f9504 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -3220,7 +3220,7 @@ skip_vmsa_free: kvfree(svm->sev_es.ghcb_sa); } -static u64 kvm_ghcb_get_sw_exit_code(struct vmcb_control_area *control) +static u64 kvm_get_cached_sw_exit_code(struct vmcb_control_area *control) { return (((u64)control->exit_code_hi) << 32) | control->exit_code; } @@ -3246,7 +3246,7 @@ static void dump_ghcb(struct vcpu_svm *svm) */ pr_err("GHCB (GPA=%016llx) snapshot:\n", svm->vmcb->control.ghcb_gpa); pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_code", - kvm_ghcb_get_sw_exit_code(control), kvm_ghcb_sw_exit_code_is_valid(svm)); + kvm_get_cached_sw_exit_code(control), kvm_ghcb_sw_exit_code_is_valid(svm)); pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_1", control->exit_info_1, kvm_ghcb_sw_exit_info_1_is_valid(svm)); pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_2", @@ -3335,7 +3335,7 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm) * Retrieve the exit code now even though it may not be marked valid * as it could help with debugging. */ - exit_code = kvm_ghcb_get_sw_exit_code(control); + exit_code = kvm_get_cached_sw_exit_code(control); /* Only GHCB Usage code 0 is supported */ if (svm->sev_es.ghcb->ghcb_usage) { @@ -4340,7 +4340,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) svm_vmgexit_success(svm, 0); - exit_code = kvm_ghcb_get_sw_exit_code(control); + exit_code = kvm_get_cached_sw_exit_code(control); switch (exit_code) { case SVM_VMGEXIT_MMIO_READ: ret = setup_vmgexit_scratch(svm, true, control->exit_info_2); From bd5f500d23170e5bde59ce97da523048b66a8183 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:09 -0700 Subject: [PATCH 1986/2711] KVM: SEV: Read save fields from GHCB exactly once Wrap all reads of GHCB save fields with READ_ONCE() via a KVM-specific GHCB get() utility to help guard against TOCTOU bugs. Using READ_ONCE() doesn't completely prevent such bugs, e.g. doesn't prevent KVM from redoing get() after checking the initial value, but at least addresses all potential TOCTOU issues in the current KVM code base. To prevent unintentional use of the generic helpers, take only @svm for the kvm_ghcb_get_xxx() helpers and retrieve the ghcb instead of explicitly passing it in. Opportunistically reduce the indentation of the macro-defined helpers and clean up the alignment. Fixes: 4e15a0ddc3ff ("KVM: SEV: snapshot the GHCB before accessing it") Reviewed-by: Tom Lendacky Link: https://lore.kernel.org/r/20250919223258.1604852-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 22 +++++++++++----------- arch/x86/kvm/svm/svm.h | 25 +++++++++++++++---------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 5456a71f9504..a2076ab3fe71 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -3299,26 +3299,26 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm) BUILD_BUG_ON(sizeof(svm->sev_es.valid_bitmap) != sizeof(ghcb->save.valid_bitmap)); memcpy(&svm->sev_es.valid_bitmap, &ghcb->save.valid_bitmap, sizeof(ghcb->save.valid_bitmap)); - vcpu->arch.regs[VCPU_REGS_RAX] = kvm_ghcb_get_rax_if_valid(svm, ghcb); - vcpu->arch.regs[VCPU_REGS_RBX] = kvm_ghcb_get_rbx_if_valid(svm, ghcb); - vcpu->arch.regs[VCPU_REGS_RCX] = kvm_ghcb_get_rcx_if_valid(svm, ghcb); - vcpu->arch.regs[VCPU_REGS_RDX] = kvm_ghcb_get_rdx_if_valid(svm, ghcb); - vcpu->arch.regs[VCPU_REGS_RSI] = kvm_ghcb_get_rsi_if_valid(svm, ghcb); + vcpu->arch.regs[VCPU_REGS_RAX] = kvm_ghcb_get_rax_if_valid(svm); + vcpu->arch.regs[VCPU_REGS_RBX] = kvm_ghcb_get_rbx_if_valid(svm); + vcpu->arch.regs[VCPU_REGS_RCX] = kvm_ghcb_get_rcx_if_valid(svm); + vcpu->arch.regs[VCPU_REGS_RDX] = kvm_ghcb_get_rdx_if_valid(svm); + vcpu->arch.regs[VCPU_REGS_RSI] = kvm_ghcb_get_rsi_if_valid(svm); - svm->vmcb->save.cpl = kvm_ghcb_get_cpl_if_valid(svm, ghcb); + svm->vmcb->save.cpl = kvm_ghcb_get_cpl_if_valid(svm); if (kvm_ghcb_xcr0_is_valid(svm)) { - vcpu->arch.xcr0 = ghcb_get_xcr0(ghcb); + vcpu->arch.xcr0 = kvm_ghcb_get_xcr0(svm); vcpu->arch.cpuid_dynamic_bits_dirty = true; } /* Copy the GHCB exit information into the VMCB fields */ - exit_code = ghcb_get_sw_exit_code(ghcb); + exit_code = kvm_ghcb_get_sw_exit_code(svm); control->exit_code = lower_32_bits(exit_code); control->exit_code_hi = upper_32_bits(exit_code); - control->exit_info_1 = ghcb_get_sw_exit_info_1(ghcb); - control->exit_info_2 = ghcb_get_sw_exit_info_2(ghcb); - svm->sev_es.sw_scratch = kvm_ghcb_get_sw_scratch_if_valid(svm, ghcb); + control->exit_info_1 = kvm_ghcb_get_sw_exit_info_1(svm); + control->exit_info_2 = kvm_ghcb_get_sw_exit_info_2(svm); + svm->sev_es.sw_scratch = kvm_ghcb_get_sw_scratch_if_valid(svm); /* Clear the valid entries fields */ memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap)); diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 3c7f208b7935..10d5cbc259e1 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -913,16 +913,21 @@ void __svm_sev_es_vcpu_run(struct vcpu_svm *svm, bool spec_ctrl_intercepted, void __svm_vcpu_run(struct vcpu_svm *svm, bool spec_ctrl_intercepted); #define DEFINE_KVM_GHCB_ACCESSORS(field) \ - static __always_inline bool kvm_ghcb_##field##_is_valid(const struct vcpu_svm *svm) \ - { \ - return test_bit(GHCB_BITMAP_IDX(field), \ - (unsigned long *)&svm->sev_es.valid_bitmap); \ - } \ - \ - static __always_inline u64 kvm_ghcb_get_##field##_if_valid(struct vcpu_svm *svm, struct ghcb *ghcb) \ - { \ - return kvm_ghcb_##field##_is_valid(svm) ? ghcb->save.field : 0; \ - } \ +static __always_inline u64 kvm_ghcb_get_##field(struct vcpu_svm *svm) \ +{ \ + return READ_ONCE(svm->sev_es.ghcb->save.field); \ +} \ + \ +static __always_inline bool kvm_ghcb_##field##_is_valid(const struct vcpu_svm *svm) \ +{ \ + return test_bit(GHCB_BITMAP_IDX(field), \ + (unsigned long *)&svm->sev_es.valid_bitmap); \ +} \ + \ +static __always_inline u64 kvm_ghcb_get_##field##_if_valid(struct vcpu_svm *svm) \ +{ \ + return kvm_ghcb_##field##_is_valid(svm) ? kvm_ghcb_get_##field(svm) : 0; \ +} DEFINE_KVM_GHCB_ACCESSORS(cpl) DEFINE_KVM_GHCB_ACCESSORS(rax) From 4135a9a8ccba2b685f2301429ea765fa0f78eb89 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:10 -0700 Subject: [PATCH 1987/2711] KVM: SEV: Validate XCR0 provided by guest in GHCB Use __kvm_set_xcr() to propagate XCR0 changes from the GHCB to KVM's software model in order to validate the new XCR0 against KVM's view of the supported XCR0. Allowing garbage is thankfully mostly benign, as kvm_load_{guest,host}_xsave_state() bail early for vCPUs with protected state, xstate_required_size() will simply provide garbage back to the guest, and attempting to save/restore the bad value via KVM_{G,S}ET_XCRS will only harm the guest (setting XCR0 will fail). However, allowing the guest to put junk into a field that KVM assumes is valid is a CVE waiting to happen. And as a bonus, using the proper API eliminates the ugly open coding of setting arch.cpuid_dynamic_bits_dirty. Simply ignore bad values, as either the guest managed to get an unsupported value into hardware, or the guest is misbehaving and providing pure garbage. In either case, KVM can't fix the broken guest. Note, using __kvm_set_xcr() also avoids recomputing dynamic CPUID bits if XCR0 isn't actually changing (relatively to KVM's previous snapshot). Cc: Tom Lendacky Fixes: 291bd20d5d88 ("KVM: SVM: Add initial support for a VMGEXIT VMEXIT") Reviewed-by: Tom Lendacky Link: https://lore.kernel.org/r/20250919223258.1604852-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/svm/sev.c | 6 ++---- arch/x86/kvm/x86.c | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f19a76d3ca0e..822a5596a4a0 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2187,6 +2187,7 @@ int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val); unsigned long kvm_get_dr(struct kvm_vcpu *vcpu, int dr); unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu); void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw); +int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr); int kvm_emulate_xsetbv(struct kvm_vcpu *vcpu); int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr); diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index a2076ab3fe71..d2ffacd43234 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -3307,10 +3307,8 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm) svm->vmcb->save.cpl = kvm_ghcb_get_cpl_if_valid(svm); - if (kvm_ghcb_xcr0_is_valid(svm)) { - vcpu->arch.xcr0 = kvm_ghcb_get_xcr0(svm); - vcpu->arch.cpuid_dynamic_bits_dirty = true; - } + if (kvm_ghcb_xcr0_is_valid(svm)) + __kvm_set_xcr(vcpu, 0, kvm_ghcb_get_xcr0(svm)); /* Copy the GHCB exit information into the VMCB fields */ exit_code = kvm_ghcb_get_sw_exit_code(svm); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a1c49bc681c4..1d7faf8bc785 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1237,7 +1237,7 @@ static inline u64 kvm_guest_supported_xfd(struct kvm_vcpu *vcpu) } #endif -static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr) +int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr) { u64 xcr0 = xcr; u64 old_xcr0 = vcpu->arch.xcr0; @@ -1281,6 +1281,7 @@ static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr) vcpu->arch.cpuid_dynamic_bits_dirty = true; return 0; } +EXPORT_SYMBOL_GPL(__kvm_set_xcr); int kvm_emulate_xsetbv(struct kvm_vcpu *vcpu) { From 5b66e335ead6472f336b4d7d9cbf14488b844f27 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 14:16:49 -0700 Subject: [PATCH 1988/2711] KVM: SEV: Reject non-positive effective lengths during LAUNCH_UPDATE Check for an invalid length during LAUNCH_UPDATE at the start of snp_launch_update() instead of subtly relying on kvm_gmem_populate() to detect the bad state. Code that directly handles userspace input absolutely should sanitize those inputs; failure to do so is asking for bugs where KVM consumes an invalid "npages". Keep the check in gmem, but wrap it in a WARN to flag any bad usage by the caller. Note, this is technically an ABI change as KVM would previously allow a length of '0'. But allowing a length of '0' is nonsensical and creates pointless conundrums in KVM. E.g. an empty range is arguably neither private nor shared, but LAUNCH_UPDATE will fail if the starting gpa can't be made private. In practice, no known or well-behaved VMM passes a length of '0'. Note #2, the PAGE_ALIGNED(params.len) check ensures that lengths between 1 and 4095 (inclusive) are also rejected, i.e. that KVM won't end up with npages=0 when doing "npages = params.len / PAGE_SIZE". Cc: Thomas Lendacky Cc: Michael Roth Reviewed-by: Tom Lendacky Link: https://lore.kernel.org/r/20250919211649.1575654-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 2 +- virt/kvm/guest_memfd.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index d2ffacd43234..019d920fe442 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2353,7 +2353,7 @@ static int snp_launch_update(struct kvm *kvm, struct kvm_sev_cmd *argp) pr_debug("%s: GFN start 0x%llx length 0x%llx type %d flags %d\n", __func__, params.gfn_start, params.len, params.type, params.flags); - if (!PAGE_ALIGNED(params.len) || params.flags || + if (!params.len || !PAGE_ALIGNED(params.len) || params.flags || (params.type != KVM_SEV_SNP_PAGE_TYPE_NORMAL && params.type != KVM_SEV_SNP_PAGE_TYPE_ZERO && params.type != KVM_SEV_SNP_PAGE_TYPE_UNMEASURED && diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c index 7d85cc33c0bb..79552467add5 100644 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@ -639,7 +639,8 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long long i; lockdep_assert_held(&kvm->slots_lock); - if (npages < 0) + + if (WARN_ON_ONCE(npages <= 0)) return -EINVAL; slot = gfn_to_memslot(kvm, start_gfn); From 9bc366350734246301b090802fc71f9924daad39 Mon Sep 17 00:00:00 2001 From: Hou Wenlong Date: Tue, 23 Sep 2025 08:37:37 -0700 Subject: [PATCH 1989/2711] KVM: x86: Add helper to retrieve current value of user return MSR In the user return MSR support, the cached value is always the hardware value of the specific MSR. Therefore, add a helper to retrieve the cached value, which can replace the need for RDMSR, for example, to allow SEV-ES guests to restore the correct host hardware value without using RDMSR. Cc: stable@vger.kernel.org Signed-off-by: Hou Wenlong [sean: drop "cache" from the name, make it a one-liner, tag for stable] Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250923153738.1875174-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/x86.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 822a5596a4a0..0d6a4af79b78 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2357,6 +2357,7 @@ int kvm_add_user_return_msr(u32 msr); int kvm_find_user_return_msr(u32 msr); int kvm_set_user_return_msr(unsigned index, u64 val, u64 mask); void kvm_user_return_msr_update_cache(unsigned int index, u64 val); +u64 kvm_get_user_return_msr(unsigned int slot); static inline bool kvm_is_supported_user_return_msr(u32 msr) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1d7faf8bc785..5ac2183b9993 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -677,6 +677,12 @@ void kvm_user_return_msr_update_cache(unsigned int slot, u64 value) } EXPORT_SYMBOL_GPL(kvm_user_return_msr_update_cache); +u64 kvm_get_user_return_msr(unsigned int slot) +{ + return this_cpu_ptr(user_return_msrs)->values[slot].curr; +} +EXPORT_SYMBOL_GPL(kvm_get_user_return_msr); + static void drop_user_return_notifiers(void) { struct kvm_user_return_msrs *msrs = this_cpu_ptr(user_return_msrs); From 29da8c823abffdacb71c7c07ec48fcf9eb38757c Mon Sep 17 00:00:00 2001 From: Hou Wenlong Date: Tue, 23 Sep 2025 08:37:38 -0700 Subject: [PATCH 1990/2711] KVM: SVM: Re-load current, not host, TSC_AUX on #VMEXIT from SEV-ES guest Prior to running an SEV-ES guest, set TSC_AUX in the host save area to the current value in hardware, as tracked by the user return infrastructure, instead of always loading the host's desired value for the CPU. If the pCPU is also running a non-SEV-ES vCPU, loading the host's value on #VMEXIT could clobber the other vCPU's value, e.g. if the SEV-ES vCPU preempted the non-SEV-ES vCPU, in which case KVM expects the other vCPU's TSC_AUX value to be resident in hardware. Note, unlike TDX, which blindly _zeroes_ TSC_AUX on TD-Exit, SEV-ES CPUs can load an arbitrary value. Stuff the current value in the host save area instead of refreshing the user return cache so that KVM doesn't need to track whether or not the vCPU actually enterred the guest and thus loaded TSC_AUX from the host save area. Opportunistically tag tsc_aux_uret_slot as read-only after init to guard against unexpected modifications, and to make it obvious that using the variable in sev_es_prepare_switch_to_guest() is safe. Fixes: 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support for virtualized TSC_AUX") Cc: stable@vger.kernel.org Suggested-by: Lai Jiangshan Signed-off-by: Hou Wenlong [sean: handle the SEV-ES case in sev_es_prepare_switch_to_guest()] Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250923153738.1875174-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 10 ++++++++++ arch/x86/kvm/svm/svm.c | 25 ++++++------------------- arch/x86/kvm/svm/svm.h | 2 ++ 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 019d920fe442..5529e4c3362b 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -4666,6 +4666,16 @@ void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_are hostsa->dr2_addr_mask = amd_get_dr_addr_mask(2); hostsa->dr3_addr_mask = amd_get_dr_addr_mask(3); } + + /* + * TSC_AUX is always virtualized for SEV-ES guests when the feature is + * available, i.e. TSC_AUX is loaded on #VMEXIT from the host save area. + * Set the save area to the current hardware value, i.e. the current + * user return value, so that the correct value is restored on #VMEXIT. + */ + if (cpu_feature_enabled(X86_FEATURE_V_TSC_AUX) && + !WARN_ON_ONCE(tsc_aux_uret_slot < 0)) + hostsa->tsc_aux = kvm_get_user_return_msr(tsc_aux_uret_slot); } void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index b237b4081c91..6f486fb82144 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -195,7 +195,7 @@ static DEFINE_MUTEX(vmcb_dump_mutex); * RDTSCP and RDPID are not used in the kernel, specifically to allow KVM to * defer the restoration of TSC_AUX until the CPU returns to userspace. */ -static int tsc_aux_uret_slot __read_mostly = -1; +int tsc_aux_uret_slot __ro_after_init = -1; static int get_npt_level(void) { @@ -577,18 +577,6 @@ static int svm_enable_virtualization_cpu(void) amd_pmu_enable_virt(); - /* - * If TSC_AUX virtualization is supported, TSC_AUX becomes a swap type - * "B" field (see sev_es_prepare_switch_to_guest()) for SEV-ES guests. - * Since Linux does not change the value of TSC_AUX once set, prime the - * TSC_AUX field now to avoid a RDMSR on every vCPU run. - */ - if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) { - u32 __maybe_unused msr_hi; - - rdmsr(MSR_TSC_AUX, sev_es_host_save_area(sd)->tsc_aux, msr_hi); - } - return 0; } @@ -1406,10 +1394,10 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu) __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); /* - * TSC_AUX is always virtualized for SEV-ES guests when the feature is - * available. The user return MSR support is not required in this case - * because TSC_AUX is restored on #VMEXIT from the host save area - * (which has been initialized in svm_enable_virtualization_cpu()). + * TSC_AUX is always virtualized (context switched by hardware) for + * SEV-ES guests when the feature is available. For non-SEV-ES guests, + * context switch TSC_AUX via the user_return MSR infrastructure (not + * all CPUs support TSC_AUX virtualization). */ if (likely(tsc_aux_uret_slot >= 0) && (!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm))) @@ -3004,8 +2992,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) * TSC_AUX is always virtualized for SEV-ES guests when the * feature is available. The user return MSR support is not * required in this case because TSC_AUX is restored on #VMEXIT - * from the host save area (which has been initialized in - * svm_enable_virtualization_cpu()). + * from the host save area. */ if (boot_cpu_has(X86_FEATURE_V_TSC_AUX) && sev_es_guest(vcpu->kvm)) break; diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 10d5cbc259e1..ec3fb318ca83 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -52,6 +52,8 @@ extern bool x2avic_enabled; extern bool vnmi; extern int lbrv; +extern int tsc_aux_uret_slot __ro_after_init; + /* * Clean bits in VMCB. * VMCB_ALL_CLEAN_MASK might also need to From 44bfe1f0490d5620c7962ab7384797672b4c4293 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 14:59:28 -0700 Subject: [PATCH 1991/2711] KVM: SVM: Make svm_x86_ops globally visible, clean up on-HyperV usage Make svm_x86_ops globally visible in anticipation of modifying the struct in avic.c, and clean up the KVM-on-HyperV usage, as declaring _and using_ a local variable in a header that's only defined in one specific .c-file is all kinds of ugly. Opportunistically make svm_hv_enable_l2_tlb_flush() local to svm_onhyperv.c, as the only reason it was visible was due to the aforementioned shenanigans in svm_onhyperv.h. Alternatively, svm_x86_ops could be explicitly passed to svm_hv_hardware_setup() as a parameter. While that approach is slightly safer, e.g. avoids "hidden" updates, for better or worse, the Intel side of KVM has already chosen to expose vt_x86_ops (and vt_init_ops). Given that svm_x86_ops is only truly consumed by kvm_ops_update, the odds of a "hidden" update causing problems are extremely low. So, absent a strong reason to rework the VMX/TDX code, make svm_x86_ops visible, as having all updates use exactly "svm_x86_ops." is advantageous in its own right. No functional change intended. Link: https://lore.kernel.org/r/20250919215934.1590410-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 2 +- arch/x86/kvm/svm/svm.h | 2 ++ arch/x86/kvm/svm/svm_onhyperv.c | 28 +++++++++++++++++++++++++++- arch/x86/kvm/svm/svm_onhyperv.h | 31 +------------------------------ 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 6f486fb82144..bfbd34818412 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5012,7 +5012,7 @@ static void *svm_alloc_apic_backing_page(struct kvm_vcpu *vcpu) return page_address(page); } -static struct kvm_x86_ops svm_x86_ops __initdata = { +struct kvm_x86_ops svm_x86_ops __initdata = { .name = KBUILD_MODNAME, .check_processor_compatibility = svm_check_processor_compat, diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index ec3fb318ca83..bc46a3539487 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -54,6 +54,8 @@ extern int lbrv; extern int tsc_aux_uret_slot __ro_after_init; +extern struct kvm_x86_ops svm_x86_ops __initdata; + /* * Clean bits in VMCB. * VMCB_ALL_CLEAN_MASK might also need to diff --git a/arch/x86/kvm/svm/svm_onhyperv.c b/arch/x86/kvm/svm/svm_onhyperv.c index 3971b3ea5d04..a8e78c0e5956 100644 --- a/arch/x86/kvm/svm/svm_onhyperv.c +++ b/arch/x86/kvm/svm/svm_onhyperv.c @@ -15,7 +15,7 @@ #include "kvm_onhyperv.h" #include "svm_onhyperv.h" -int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu) +static int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu) { struct hv_vmcb_enlightenments *hve; hpa_t partition_assist_page = hv_get_partition_assist_page(vcpu); @@ -35,3 +35,29 @@ int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu) return 0; } +__init void svm_hv_hardware_setup(void) +{ + if (npt_enabled && + ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB) { + pr_info(KBUILD_MODNAME ": Hyper-V enlightened NPT TLB flush enabled\n"); + svm_x86_ops.flush_remote_tlbs = hv_flush_remote_tlbs; + svm_x86_ops.flush_remote_tlbs_range = hv_flush_remote_tlbs_range; + } + + if (ms_hyperv.nested_features & HV_X64_NESTED_DIRECT_FLUSH) { + int cpu; + + pr_info(KBUILD_MODNAME ": Hyper-V Direct TLB Flush enabled\n"); + for_each_online_cpu(cpu) { + struct hv_vp_assist_page *vp_ap = + hv_get_vp_assist_page(cpu); + + if (!vp_ap) + continue; + + vp_ap->nested_control.features.directhypercall = 1; + } + svm_x86_ops.enable_l2_tlb_flush = + svm_hv_enable_l2_tlb_flush; + } +} diff --git a/arch/x86/kvm/svm/svm_onhyperv.h b/arch/x86/kvm/svm/svm_onhyperv.h index f85bc617ffe4..08f14e6f195c 100644 --- a/arch/x86/kvm/svm/svm_onhyperv.h +++ b/arch/x86/kvm/svm/svm_onhyperv.h @@ -13,9 +13,7 @@ #include "kvm_onhyperv.h" #include "svm/hyperv.h" -static struct kvm_x86_ops svm_x86_ops; - -int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu); +__init void svm_hv_hardware_setup(void); static inline bool svm_hv_is_enlightened_tlb_enabled(struct kvm_vcpu *vcpu) { @@ -40,33 +38,6 @@ static inline void svm_hv_init_vmcb(struct vmcb *vmcb) hve->hv_enlightenments_control.msr_bitmap = 1; } -static inline __init void svm_hv_hardware_setup(void) -{ - if (npt_enabled && - ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB) { - pr_info(KBUILD_MODNAME ": Hyper-V enlightened NPT TLB flush enabled\n"); - svm_x86_ops.flush_remote_tlbs = hv_flush_remote_tlbs; - svm_x86_ops.flush_remote_tlbs_range = hv_flush_remote_tlbs_range; - } - - if (ms_hyperv.nested_features & HV_X64_NESTED_DIRECT_FLUSH) { - int cpu; - - pr_info(KBUILD_MODNAME ": Hyper-V Direct TLB Flush enabled\n"); - for_each_online_cpu(cpu) { - struct hv_vp_assist_page *vp_ap = - hv_get_vp_assist_page(cpu); - - if (!vp_ap) - continue; - - vp_ap->nested_control.features.directhypercall = 1; - } - svm_x86_ops.enable_l2_tlb_flush = - svm_hv_enable_l2_tlb_flush; - } -} - static inline void svm_hv_vmcb_dirty_nested_enlightenments( struct kvm_vcpu *vcpu) { From eb44ea6a7aace13becd8d99905284ad272b3bd98 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 14:59:29 -0700 Subject: [PATCH 1992/2711] KVM: SVM: Move x2AVIC MSR interception helper to avic.c Move svm_set_x2apic_msr_interception() to avic.c as it's only relevant when x2AVIC is enabled/supported and only called by AVIC code. In addition to scoping AVIC code to avic.c, this will allow burying the global x2avic_enabled variable in avic. Opportunistically rename the helper to explicitly scope it to "avic". No functional change intended. Reviewed-by: Naveen N Rao (AMD) Tested-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/20250919215934.1590410-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/avic.c | 57 ++++++++++++++++++++++++++++++++++++++--- arch/x86/kvm/svm/svm.c | 49 ----------------------------------- arch/x86/kvm/svm/svm.h | 1 - 3 files changed, 54 insertions(+), 53 deletions(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index a34c5c3b164e..478a18208a76 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -79,6 +79,57 @@ static bool next_vm_id_wrapped = 0; static DEFINE_SPINLOCK(svm_vm_data_hash_lock); bool x2avic_enabled; + +static void avic_set_x2apic_msr_interception(struct vcpu_svm *svm, + bool intercept) +{ + static const u32 x2avic_passthrough_msrs[] = { + X2APIC_MSR(APIC_ID), + X2APIC_MSR(APIC_LVR), + X2APIC_MSR(APIC_TASKPRI), + X2APIC_MSR(APIC_ARBPRI), + X2APIC_MSR(APIC_PROCPRI), + X2APIC_MSR(APIC_EOI), + X2APIC_MSR(APIC_RRR), + X2APIC_MSR(APIC_LDR), + X2APIC_MSR(APIC_DFR), + X2APIC_MSR(APIC_SPIV), + X2APIC_MSR(APIC_ISR), + X2APIC_MSR(APIC_TMR), + X2APIC_MSR(APIC_IRR), + X2APIC_MSR(APIC_ESR), + X2APIC_MSR(APIC_ICR), + X2APIC_MSR(APIC_ICR2), + + /* + * Note! Always intercept LVTT, as TSC-deadline timer mode + * isn't virtualized by hardware, and the CPU will generate a + * #GP instead of a #VMEXIT. + */ + X2APIC_MSR(APIC_LVTTHMR), + X2APIC_MSR(APIC_LVTPC), + X2APIC_MSR(APIC_LVT0), + X2APIC_MSR(APIC_LVT1), + X2APIC_MSR(APIC_LVTERR), + X2APIC_MSR(APIC_TMICT), + X2APIC_MSR(APIC_TMCCT), + X2APIC_MSR(APIC_TDCR), + }; + int i; + + if (intercept == svm->x2avic_msrs_intercepted) + return; + + if (!x2avic_enabled) + return; + + for (i = 0; i < ARRAY_SIZE(x2avic_passthrough_msrs); i++) + svm_set_intercept_for_msr(&svm->vcpu, x2avic_passthrough_msrs[i], + MSR_TYPE_RW, intercept); + + svm->x2avic_msrs_intercepted = intercept; +} + static void avic_activate_vmcb(struct vcpu_svm *svm) { struct vmcb *vmcb = svm->vmcb01.ptr; @@ -99,7 +150,7 @@ static void avic_activate_vmcb(struct vcpu_svm *svm) vmcb->control.int_ctl |= X2APIC_MODE_MASK; vmcb->control.avic_physical_id |= X2AVIC_MAX_PHYSICAL_ID; /* Disabling MSR intercept for x2APIC registers */ - svm_set_x2apic_msr_interception(svm, false); + avic_set_x2apic_msr_interception(svm, false); } else { /* * Flush the TLB, the guest may have inserted a non-APIC @@ -110,7 +161,7 @@ static void avic_activate_vmcb(struct vcpu_svm *svm) /* For xAVIC and hybrid-xAVIC modes */ vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID; /* Enabling MSR intercept for x2APIC registers */ - svm_set_x2apic_msr_interception(svm, true); + avic_set_x2apic_msr_interception(svm, true); } } @@ -130,7 +181,7 @@ static void avic_deactivate_vmcb(struct vcpu_svm *svm) return; /* Enabling MSR intercept for x2APIC registers */ - svm_set_x2apic_msr_interception(svm, true); + avic_set_x2apic_msr_interception(svm, true); } /* Note: diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index bfbd34818412..44032c78aab0 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -724,55 +724,6 @@ static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu) svm_set_intercept_for_msr(vcpu, MSR_IA32_DEBUGCTLMSR, MSR_TYPE_RW, intercept); } -void svm_set_x2apic_msr_interception(struct vcpu_svm *svm, bool intercept) -{ - static const u32 x2avic_passthrough_msrs[] = { - X2APIC_MSR(APIC_ID), - X2APIC_MSR(APIC_LVR), - X2APIC_MSR(APIC_TASKPRI), - X2APIC_MSR(APIC_ARBPRI), - X2APIC_MSR(APIC_PROCPRI), - X2APIC_MSR(APIC_EOI), - X2APIC_MSR(APIC_RRR), - X2APIC_MSR(APIC_LDR), - X2APIC_MSR(APIC_DFR), - X2APIC_MSR(APIC_SPIV), - X2APIC_MSR(APIC_ISR), - X2APIC_MSR(APIC_TMR), - X2APIC_MSR(APIC_IRR), - X2APIC_MSR(APIC_ESR), - X2APIC_MSR(APIC_ICR), - X2APIC_MSR(APIC_ICR2), - - /* - * Note! Always intercept LVTT, as TSC-deadline timer mode - * isn't virtualized by hardware, and the CPU will generate a - * #GP instead of a #VMEXIT. - */ - X2APIC_MSR(APIC_LVTTHMR), - X2APIC_MSR(APIC_LVTPC), - X2APIC_MSR(APIC_LVT0), - X2APIC_MSR(APIC_LVT1), - X2APIC_MSR(APIC_LVTERR), - X2APIC_MSR(APIC_TMICT), - X2APIC_MSR(APIC_TMCCT), - X2APIC_MSR(APIC_TDCR), - }; - int i; - - if (intercept == svm->x2avic_msrs_intercepted) - return; - - if (!x2avic_enabled) - return; - - for (i = 0; i < ARRAY_SIZE(x2avic_passthrough_msrs); i++) - svm_set_intercept_for_msr(&svm->vcpu, x2avic_passthrough_msrs[i], - MSR_TYPE_RW, intercept); - - svm->x2avic_msrs_intercepted = intercept; -} - void svm_vcpu_free_msrpm(void *msrpm) { __free_pages(virt_to_page(msrpm), get_order(MSRPM_SIZE)); diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index bc46a3539487..cb1d26cb5113 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -703,7 +703,6 @@ void svm_set_gif(struct vcpu_svm *svm, bool value); int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code); void set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr, int read, int write); -void svm_set_x2apic_msr_interception(struct vcpu_svm *svm, bool disable); void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode, int trig_mode, int vec); From a9095e4fc4368052593c84472a8d374fefd3df71 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 14:59:30 -0700 Subject: [PATCH 1993/2711] KVM: SVM: Update "APICv in x2APIC without x2AVIC" in avic.c, not svm.c Set the "allow_apicv_in_x2apic_without_x2apic_virtualization" flag as part of avic_hardware_setup() instead of handling in svm_hardware_setup(), and make x2avic_enabled local to avic.c (setting the flag was the only use in svm.c). Tag avic_hardware_setup() with __init as necessary (it should have been tagged __init long ago). No functional change intended (aside from the side effects of tagging avic_hardware_setup() with __init). Acked-by: Naveen N Rao (AMD) Tested-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/20250919215934.1590410-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/avic.c | 6 ++++-- arch/x86/kvm/svm/svm.c | 2 -- arch/x86/kvm/svm/svm.h | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 478a18208a76..b4577401ce5f 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -77,7 +77,7 @@ static DEFINE_HASHTABLE(svm_vm_data_hash, SVM_VM_DATA_HASH_BITS); static u32 next_vm_id = 0; static bool next_vm_id_wrapped = 0; static DEFINE_SPINLOCK(svm_vm_data_hash_lock); -bool x2avic_enabled; +static bool x2avic_enabled; static void avic_set_x2apic_msr_interception(struct vcpu_svm *svm, @@ -1147,7 +1147,7 @@ void avic_vcpu_unblocking(struct kvm_vcpu *vcpu) * - Hypervisor can support both xAVIC and x2AVIC in the same guest. * - The mode can be switched at run-time. */ -bool avic_hardware_setup(void) +bool __init avic_hardware_setup(void) { if (!npt_enabled) return false; @@ -1182,6 +1182,8 @@ bool avic_hardware_setup(void) x2avic_enabled = boot_cpu_has(X86_FEATURE_X2AVIC); if (x2avic_enabled) pr_info("x2AVIC enabled\n"); + else + svm_x86_ops.allow_apicv_in_x2apic_without_x2apic_virtualization = true; /* * Disable IPI virtualization for AMD Family 17h CPUs (Zen1 and Zen2) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 44032c78aab0..3fd2f4097a3b 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5337,8 +5337,6 @@ static __init int svm_hardware_setup(void) svm_x86_ops.vcpu_blocking = NULL; svm_x86_ops.vcpu_unblocking = NULL; svm_x86_ops.vcpu_get_apicv_inhibit_reasons = NULL; - } else if (!x2avic_enabled) { - svm_x86_ops.allow_apicv_in_x2apic_without_x2apic_virtualization = true; } if (vls) { diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index cb1d26cb5113..739f4f52f46d 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -48,7 +48,6 @@ extern bool npt_enabled; extern int nrips; extern int vgif; extern bool intercept_smi; -extern bool x2avic_enabled; extern bool vnmi; extern int lbrv; @@ -804,7 +803,7 @@ extern struct kvm_x86_nested_ops svm_nested_ops; BIT(APICV_INHIBIT_REASON_PHYSICAL_ID_TOO_BIG) \ ) -bool avic_hardware_setup(void); +bool __init avic_hardware_setup(void); int avic_ga_log_notifier(u32 ga_tag); void avic_vm_destroy(struct kvm *kvm); int avic_vm_init(struct kvm *kvm); From ce4253e21fa8a4468474e26884196770cb560eae Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 14:59:31 -0700 Subject: [PATCH 1994/2711] KVM: SVM: Always print "AVIC enabled" separately, even when force enabled Print the customary "AVIC enabled" informational message even when AVIC is force enabled on a system that doesn't advertise supported for AVIC in CPUID, as not printing the standard message can confuse users and tools. Opportunistically clean up the scary message when AVIC is force enabled, but keep it as separate message so that it is printed at level "warn", versus the standard message only being printed for level "info". Suggested-by: Naveen N Rao (AMD) Reviewed-by: Naveen N Rao (AMD) Tested-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/20250919215934.1590410-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/avic.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index b4577401ce5f..b8b73c4103c6 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -1167,16 +1167,15 @@ bool __init avic_hardware_setup(void) return false; } - if (boot_cpu_has(X86_FEATURE_AVIC)) { - pr_info("AVIC enabled\n"); - } else if (force_avic) { - /* - * Some older systems does not advertise AVIC support. - * See Revision Guide for specific AMD processor for more detail. - */ - pr_warn("AVIC is not supported in CPUID but force enabled"); - pr_warn("Your system might crash and burn"); - } + /* + * Print a scary message if AVIC is force enabled to make it abundantly + * clear that ignoring CPUID could have repercussions. See Revision + * Guide for specific AMD processor for more details. + */ + if (!boot_cpu_has(X86_FEATURE_AVIC)) + pr_warn("AVIC unsupported in CPUID but force enabled, your system might crash and burn\n"); + + pr_info("AVIC enabled\n"); /* AVIC is a prerequisite for x2AVIC. */ x2avic_enabled = boot_cpu_has(X86_FEATURE_X2AVIC); From ad65dca2ca4cf8c377135362c0c1e031ad92019d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 14:59:32 -0700 Subject: [PATCH 1995/2711] KVM: SVM: Don't advise the user to do force_avic=y (when x2AVIC is detected) Don't advise the end user to try to force enable AVIC when x2AVIC is reported as supported in CPUID, as forcefully enabling AVIC isn't something that should be done lightly. E.g. some Zen4 client systems hide AVIC but leave x2AVIC behind, and while such a configuration is indeed due to buggy firmware in the sense the reporting x2AVIC without AVIC is nonsensical, KVM has no idea _why_ firmware disabled AVIC in the first place. Suggesting that the user try to run with force_avic=y is sketchy even if the user explicitly tries to enable AVIC, and will be downright irresponsible once KVM starts enabling AVIC by default. Alternatively, KVM could print the message only when the user explicitly asks for AVIC, but running with force_avic=y isn't something that should be encouraged for random users. force_avic is a useful knob for developers and perhaps even advanced users, but isn't something that KVM should advertise broadly. Opportunistically append a newline to the pr_warn() so that it prints out immediately, and tweak the message to say that AVIC is unsupported instead of disabled (disabled suggests that the kernel/KVM is somehow responsible). Suggested-by: Naveen N Rao (AMD) Reviewed-by: Naveen N Rao (AMD) Tested-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/20250919215934.1590410-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/avic.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index b8b73c4103c6..35dde7d89f56 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -1154,10 +1154,8 @@ bool __init avic_hardware_setup(void) /* AVIC is a prerequisite for x2AVIC. */ if (!boot_cpu_has(X86_FEATURE_AVIC) && !force_avic) { - if (boot_cpu_has(X86_FEATURE_X2AVIC)) { - pr_warn(FW_BUG "Cannot support x2AVIC due to AVIC is disabled"); - pr_warn(FW_BUG "Try enable AVIC using force_avic option"); - } + if (boot_cpu_has(X86_FEATURE_X2AVIC)) + pr_warn(FW_BUG "Cannot enable x2AVIC, AVIC is unsupported\n"); return false; } From b14665353162db70e445aacdd18b0566edba00c2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 14:59:33 -0700 Subject: [PATCH 1996/2711] KVM: SVM: Move global "avic" variable to avic.c Move "avic" to avic.c so that it's colocated with the other AVIC specific globals and module params, and so that avic_hardware_setup() is a bit more self-contained, e.g. similar to sev_hardware_setup(). Deliberately set enable_apicv in svm.c as it's already globally visible (defined by kvm.ko, not by kvm-amd.ko), and to clearly capture the dependency on enable_apicv being initialized (svm_hardware_setup() clears several AVIC-specific hooks when enable_apicv is disabled). Alternatively, clearing of the hooks (and enable_ipiv) could be moved to avic_hardware_setup(), but that's not obviously better, e.g. it's helpful to isolate the setting of enable_apicv when reading code from the generic x86 side of the world. No functional change intended. Acked-by: Naveen N Rao (AMD) Tested-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/20250919215934.1590410-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/avic.c | 33 +++++++++++++++++++++++++-------- arch/x86/kvm/svm/svm.c | 11 +---------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 35dde7d89f56..ec214062d136 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -64,6 +64,14 @@ static_assert(__AVIC_GATAG(AVIC_VM_ID_MASK, AVIC_VCPU_IDX_MASK) == -1u); +/* + * enable / disable AVIC. Because the defaults differ for APICv + * support between VMX and SVM we cannot use module_param_named. + */ +static bool avic; +module_param(avic, bool, 0444); +module_param(enable_ipiv, bool, 0444); + static bool force_avic; module_param_unsafe(force_avic, bool, 0444); @@ -1141,15 +1149,9 @@ void avic_vcpu_unblocking(struct kvm_vcpu *vcpu) avic_vcpu_load(vcpu, vcpu->cpu); } -/* - * Note: - * - The module param avic enable both xAPIC and x2APIC mode. - * - Hypervisor can support both xAVIC and x2AVIC in the same guest. - * - The mode can be switched at run-time. - */ -bool __init avic_hardware_setup(void) +static bool __init avic_want_avic_enabled(void) { - if (!npt_enabled) + if (!avic || !npt_enabled) return false; /* AVIC is a prerequisite for x2AVIC. */ @@ -1173,6 +1175,21 @@ bool __init avic_hardware_setup(void) if (!boot_cpu_has(X86_FEATURE_AVIC)) pr_warn("AVIC unsupported in CPUID but force enabled, your system might crash and burn\n"); + return true; +} + +/* + * Note: + * - The module param avic enable both xAPIC and x2APIC mode. + * - Hypervisor can support both xAVIC and x2AVIC in the same guest. + * - The mode can be switched at run-time. + */ +bool __init avic_hardware_setup(void) +{ + avic = avic_want_avic_enabled(); + if (!avic) + return false; + pr_info("AVIC enabled\n"); /* AVIC is a prerequisite for x2AVIC. */ diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 3fd2f4097a3b..748881a3dedb 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -158,14 +158,6 @@ module_param(lbrv, int, 0444); static int tsc_scaling = true; module_param(tsc_scaling, int, 0444); -/* - * enable / disable AVIC. Because the defaults differ for APICv - * support between VMX and SVM we cannot use module_param_named. - */ -static bool avic; -module_param(avic, bool, 0444); -module_param(enable_ipiv, bool, 0444); - module_param(enable_device_posted_irqs, bool, 0444); bool __read_mostly dump_invalid_vmcb; @@ -5330,8 +5322,7 @@ static __init int svm_hardware_setup(void) goto err; } - enable_apicv = avic = avic && avic_hardware_setup(); - + enable_apicv = avic_hardware_setup(); if (!enable_apicv) { enable_ipiv = false; svm_x86_ops.vcpu_blocking = NULL; From ca2967de5a5b098b43c5ad665672945ce7e7d4f7 Mon Sep 17 00:00:00 2001 From: Naveen N Rao Date: Fri, 19 Sep 2025 14:59:34 -0700 Subject: [PATCH 1997/2711] KVM: SVM: Enable AVIC by default for Zen4+ if x2AVIC is support AVIC and x2AVIC are fully functional since Zen 4, with no known hardware errata. Enable AVIC and x2AVIC by default on Zen4+ so long as x2AVIC is supported (to avoid enabling partial support for APIC virtualization by default). Internally, convert "avic" to an integer so that KVM can identify if the user has asked to explicitly enable or disable AVIC, i.e. so that KVM doesn't override an explicit 'y' from the user. Arbitrarily use -1 to denote auto-mode, and accept the string "auto" for the module param in addition to standard boolean values, i.e. continue to allow the user to configure the "avic" module parameter to explicitly enable/disable AVIC. To again maintain backward compatibility with a standard boolean param, set KERNEL_PARAM_OPS_FL_NOARG, which tells the params infrastructure to allow empty values for %true, i.e. to interpret a bare "avic" as "avic=y". Take care to check for a NULL @val when looking for "auto"! Lastly, always print "avic" as a boolean, since auto-mode is resolved during module initialization, i.e. the user should never see "auto" in sysfs. Signed-off-by: Naveen N Rao (AMD) Tested-by: Naveen N Rao (AMD) Co-developed-by: Sean Christopherson Link: https://lore.kernel.org/r/20250919215934.1590410-8-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/avic.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index ec214062d136..f286b5706d7c 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -64,12 +64,32 @@ static_assert(__AVIC_GATAG(AVIC_VM_ID_MASK, AVIC_VCPU_IDX_MASK) == -1u); +#define AVIC_AUTO_MODE -1 + +static int avic_param_set(const char *val, const struct kernel_param *kp) +{ + if (val && sysfs_streq(val, "auto")) { + *(int *)kp->arg = AVIC_AUTO_MODE; + return 0; + } + + return param_set_bint(val, kp); +} + +static const struct kernel_param_ops avic_ops = { + .flags = KERNEL_PARAM_OPS_FL_NOARG, + .set = avic_param_set, + .get = param_get_bool, +}; + /* - * enable / disable AVIC. Because the defaults differ for APICv - * support between VMX and SVM we cannot use module_param_named. + * Enable / disable AVIC. In "auto" mode (default behavior), AVIC is enabled + * for Zen4+ CPUs with x2AVIC (and all other criteria for enablement are met). */ -static bool avic; -module_param(avic, bool, 0444); +static int avic = AVIC_AUTO_MODE; +module_param_cb(avic, &avic_ops, &avic, 0444); +__MODULE_PARM_TYPE(avic, "bool"); + module_param(enable_ipiv, bool, 0444); static bool force_avic; @@ -1151,6 +1171,18 @@ void avic_vcpu_unblocking(struct kvm_vcpu *vcpu) static bool __init avic_want_avic_enabled(void) { + /* + * In "auto" mode, enable AVIC by default for Zen4+ if x2AVIC is + * supported (to avoid enabling partial support by default, and because + * x2AVIC should be supported by all Zen4+ CPUs). Explicitly check for + * family 0x19 and later (Zen5+), as the kernel's synthetic ZenX flags + * aren't inclusive of previous generations, i.e. the kernel will set + * at most one ZenX feature flag. + */ + if (avic == AVIC_AUTO_MODE) + avic = boot_cpu_has(X86_FEATURE_X2AVIC) && + (boot_cpu_data.x86 > 0x19 || cpu_feature_enabled(X86_FEATURE_ZEN4)); + if (!avic || !npt_enabled) return false; From 06f2969c6a1237f05f8ba4324b6ddc2570a808d0 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:11 -0700 Subject: [PATCH 1998/2711] KVM: x86: Introduce KVM_{G,S}ET_ONE_REG uAPIs support Enable KVM_{G,S}ET_ONE_REG uAPIs so that userspace can access MSRs and other non-MSR registers through them, along with support for KVM_GET_REG_LIST to enumerate support for KVM-defined registers. This is in preparation for allowing userspace to read/write the guest SSP register, which is needed for the upcoming CET virtualization support. Currently, two types of registers are supported: KVM_X86_REG_TYPE_MSR and KVM_X86_REG_TYPE_KVM. All MSRs are in the former type; the latter type is added for registers that lack existing KVM uAPIs to access them. The "KVM" in the name is intended to be vague to give KVM flexibility to include other potential registers. More precise names like "SYNTHETIC" and "SYNTHETIC_MSR" were considered, but were deemed too confusing (e.g. can be conflated with synthetic guest-visible MSRs) and may put KVM into a corner (e.g. if KVM wants to change how a KVM-defined register is modeled internally). Enumerate only KVM-defined registers in KVM_GET_REG_LIST to avoid duplicating KVM_GET_MSR_INDEX_LIST, and so that KVM can return _only_ registers that are fully supported (KVM_GET_REG_LIST is vCPU-scoped, i.e. can be precise, whereas KVM_GET_MSR_INDEX_LIST is system-scoped). Suggested-by: Sean Christopherson Signed-off-by: Yang Weijiang Link: https://lore.kernel.org/all/20240219074733.122080-18-weijiang.yang@intel.com [1] Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Co-developed-by: Sean Christopherson Link: https://lore.kernel.org/r/20250919223258.1604852-5-seanjc@google.com Signed-off-by: Sean Christopherson --- Documentation/virt/kvm/api.rst | 6 +- arch/x86/include/uapi/asm/kvm.h | 26 +++++++++ arch/x86/kvm/x86.c | 100 ++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 1 deletion(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index b3f2395a62d1..0e82fc5abd7b 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -2908,6 +2908,8 @@ such as set vcpu counter or reset vcpu, and they have the following id bit patte 0x9030 0000 0002 +x86 MSR registers have the following id bit patterns:: + 0x2030 0002 4.69 KVM_GET_ONE_REG -------------------- @@ -3588,7 +3590,7 @@ VCPU matching underlying host. --------------------- :Capability: basic -:Architectures: arm64, mips, riscv +:Architectures: arm64, mips, riscv, x86 (if KVM_CAP_ONE_REG) :Type: vcpu ioctl :Parameters: struct kvm_reg_list (in/out) :Returns: 0 on success; -1 on error @@ -3631,6 +3633,8 @@ Note that s390 does not support KVM_GET_REG_LIST for historical reasons - KVM_REG_S390_GBEA +Note, for x86, all MSRs enumerated by KVM_GET_MSR_INDEX_LIST are supported as +type KVM_X86_REG_TYPE_MSR, but are NOT enumerated via KVM_GET_REG_LIST. 4.85 KVM_ARM_SET_DEVICE_ADDR (deprecated) ----------------------------------------- diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 0f15d683817d..aae1033c8afa 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -411,6 +411,32 @@ struct kvm_xcrs { __u64 padding[16]; }; +#define KVM_X86_REG_TYPE_MSR 2 +#define KVM_X86_REG_TYPE_KVM 3 + +#define KVM_X86_KVM_REG_SIZE(reg) \ +({ \ + reg == KVM_REG_GUEST_SSP ? KVM_REG_SIZE_U64 : 0; \ +}) + +#define KVM_X86_REG_TYPE_SIZE(type, reg) \ +({ \ + __u64 type_size = (__u64)type << 32; \ + \ + type_size |= type == KVM_X86_REG_TYPE_MSR ? KVM_REG_SIZE_U64 : \ + type == KVM_X86_REG_TYPE_KVM ? KVM_X86_KVM_REG_SIZE(reg) : \ + 0; \ + type_size; \ +}) + +#define KVM_X86_REG_ID(type, index) \ + (KVM_REG_X86 | KVM_X86_REG_TYPE_SIZE(type, index) | index) + +#define KVM_X86_REG_MSR(index) \ + KVM_X86_REG_ID(KVM_X86_REG_TYPE_MSR, index) +#define KVM_X86_REG_KVM(index) \ + KVM_X86_REG_ID(KVM_X86_REG_TYPE_KVM, index) + #define KVM_SYNC_X86_REGS (1UL << 0) #define KVM_SYNC_X86_SREGS (1UL << 1) #define KVM_SYNC_X86_EVENTS (1UL << 2) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f718834bc00b..bc245e0b0443 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4735,6 +4735,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_IRQFD_RESAMPLE: case KVM_CAP_MEMORY_FAULT_INFO: case KVM_CAP_X86_GUEST_MODE: + case KVM_CAP_ONE_REG: r = 1; break; case KVM_CAP_PRE_FAULT_MEMORY: @@ -5913,6 +5914,98 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, } } +struct kvm_x86_reg_id { + __u32 index; + __u8 type; + __u8 rsvd1; + __u8 rsvd2:4; + __u8 size:4; + __u8 x86; +}; + +static int kvm_translate_kvm_reg(struct kvm_x86_reg_id *reg) +{ + return -EINVAL; +} + +static int kvm_get_one_msr(struct kvm_vcpu *vcpu, u32 msr, u64 __user *user_val) +{ + u64 val; + + if (do_get_msr(vcpu, msr, &val)) + return -EINVAL; + + if (put_user(val, user_val)) + return -EFAULT; + + return 0; +} + +static int kvm_set_one_msr(struct kvm_vcpu *vcpu, u32 msr, u64 __user *user_val) +{ + u64 val; + + if (get_user(val, user_val)) + return -EFAULT; + + if (do_set_msr(vcpu, msr, &val)) + return -EINVAL; + + return 0; +} + +static int kvm_get_set_one_reg(struct kvm_vcpu *vcpu, unsigned int ioctl, + void __user *argp) +{ + struct kvm_one_reg one_reg; + struct kvm_x86_reg_id *reg; + u64 __user *user_val; + int r; + + if (copy_from_user(&one_reg, argp, sizeof(one_reg))) + return -EFAULT; + + if ((one_reg.id & KVM_REG_ARCH_MASK) != KVM_REG_X86) + return -EINVAL; + + reg = (struct kvm_x86_reg_id *)&one_reg.id; + if (reg->rsvd1 || reg->rsvd2) + return -EINVAL; + + if (reg->type == KVM_X86_REG_TYPE_KVM) { + r = kvm_translate_kvm_reg(reg); + if (r) + return r; + } + + if (reg->type != KVM_X86_REG_TYPE_MSR) + return -EINVAL; + + if ((one_reg.id & KVM_REG_SIZE_MASK) != KVM_REG_SIZE_U64) + return -EINVAL; + + guard(srcu)(&vcpu->kvm->srcu); + + user_val = u64_to_user_ptr(one_reg.addr); + if (ioctl == KVM_GET_ONE_REG) + r = kvm_get_one_msr(vcpu, reg->index, user_val); + else + r = kvm_set_one_msr(vcpu, reg->index, user_val); + + return r; +} + +static int kvm_get_reg_list(struct kvm_vcpu *vcpu, + struct kvm_reg_list __user *user_list) +{ + u64 nr_regs = 0; + + if (put_user(nr_regs, &user_list->n)) + return -EFAULT; + + return 0; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -6029,6 +6122,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp, srcu_read_unlock(&vcpu->kvm->srcu, idx); break; } + case KVM_GET_ONE_REG: + case KVM_SET_ONE_REG: + r = kvm_get_set_one_reg(vcpu, ioctl, argp); + break; + case KVM_GET_REG_LIST: + r = kvm_get_reg_list(vcpu, argp); + break; case KVM_TPR_ACCESS_REPORTING: { struct kvm_tpr_access_ctl tac; From c0a5f298912222f3bb4e8f5dc67c6a1f0e93d83f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:12 -0700 Subject: [PATCH 1999/2711] KVM: x86: Report XSS as to-be-saved if there are supported features Add MSR_IA32_XSS to list of MSRs reported to userspace if supported_xss is non-zero, i.e. KVM supports at least one XSS based feature. Before enabling CET virtualization series, guest IA32_MSR_XSS is guaranteed to be 0, i.e., XSAVES/XRSTORS is executed in non-root mode with XSS == 0, which equals to the effect of XSAVE/XRSTOR. Signed-off-by: Yang Weijiang Reviewed-by: Maxim Levitsky Reviewed-by: Chao Gao Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Reviewed-by: Xiaoyao Li Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bc245e0b0443..757878a222a7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -332,7 +332,7 @@ static const u32 msrs_to_save_base[] = { MSR_IA32_RTIT_ADDR3_A, MSR_IA32_RTIT_ADDR3_B, MSR_IA32_UMWAIT_CONTROL, - MSR_IA32_XFD, MSR_IA32_XFD_ERR, + MSR_IA32_XFD, MSR_IA32_XFD_ERR, MSR_IA32_XSS, }; static const u32 msrs_to_save_pmu[] = { @@ -7503,6 +7503,10 @@ static void kvm_probe_msr_to_save(u32 msr_index) if (!(kvm_get_arch_capabilities() & ARCH_CAP_TSX_CTRL_MSR)) return; break; + case MSR_IA32_XSS: + if (!kvm_caps.supported_xss) + return; + break; default: break; } From 338543cbe033e56dcc8c13adcdf6c228953c0829 Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Fri, 19 Sep 2025 15:32:13 -0700 Subject: [PATCH 2000/2711] KVM: x86: Check XSS validity against guest CPUIDs Maintain per-guest valid XSS bits and check XSS validity against them rather than against KVM capabilities. This is to prevent bits that are supported by KVM but not supported for a guest from being set. Opportunistically return KVM_MSR_RET_UNSUPPORTED on IA32_XSS MSR accesses if guest CPUID doesn't enumerate X86_FEATURE_XSAVES. Since KVM_MSR_RET_UNSUPPORTED takes care of host_initiated cases, drop the host_initiated check. Signed-off-by: Chao Gao Reviewed-by: Xiaoyao Li Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 3 ++- arch/x86/kvm/cpuid.c | 12 ++++++++++++ arch/x86/kvm/x86.c | 7 +++---- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index b1e2a2e033f0..5865c9b77b6d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -815,7 +815,6 @@ struct kvm_vcpu_arch { bool at_instruction_boundary; bool tpr_access_reporting; bool xfd_no_write_intercept; - u64 ia32_xss; u64 microcode_version; u64 arch_capabilities; u64 perf_capabilities; @@ -876,6 +875,8 @@ struct kvm_vcpu_arch { u64 xcr0; u64 guest_supported_xcr0; + u64 ia32_xss; + u64 guest_supported_xss; struct kvm_pio_request pio; void *pio_data; diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index efee08fad72e..6b8b5d8b13cc 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -263,6 +263,17 @@ static u64 cpuid_get_supported_xcr0(struct kvm_vcpu *vcpu) return (best->eax | ((u64)best->edx << 32)) & kvm_caps.supported_xcr0; } +static u64 cpuid_get_supported_xss(struct kvm_vcpu *vcpu) +{ + struct kvm_cpuid_entry2 *best; + + best = kvm_find_cpuid_entry_index(vcpu, 0xd, 1); + if (!best) + return 0; + + return (best->ecx | ((u64)best->edx << 32)) & kvm_caps.supported_xss; +} + static __always_inline void kvm_update_feature_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *entry, unsigned int x86_feature, @@ -424,6 +435,7 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) } vcpu->arch.guest_supported_xcr0 = cpuid_get_supported_xcr0(vcpu); + vcpu->arch.guest_supported_xss = cpuid_get_supported_xss(vcpu); vcpu->arch.pv_cpuid.features = kvm_apply_cpuid_pv_features_quirk(vcpu); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 757878a222a7..6ae12e8c9d05 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3984,15 +3984,14 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) } break; case MSR_IA32_XSS: - if (!msr_info->host_initiated && - !guest_cpuid_has(vcpu, X86_FEATURE_XSAVES)) - return 1; + if (!guest_cpuid_has(vcpu, X86_FEATURE_XSAVES)) + return KVM_MSR_RET_UNSUPPORTED; /* * KVM supports exposing PT to the guest, but does not support * IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than * XSAVES/XRSTORS to save/restore PT MSRs. */ - if (data & ~kvm_caps.supported_xss) + if (data & ~vcpu->arch.guest_supported_xss) return 1; vcpu->arch.ia32_xss = data; vcpu->arch.cpuid_dynamic_bits_dirty = true; From 9622e116d0d25f1ddc47bf0328612cc7d87d20f2 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:14 -0700 Subject: [PATCH 2001/2711] KVM: x86: Refresh CPUID on write to guest MSR_IA32_XSS Update CPUID.(EAX=0DH,ECX=1).EBX to reflect current required xstate size due to XSS MSR modification. CPUID(EAX=0DH,ECX=1).EBX reports the required storage size of all enabled xstate features in (XCR0 | IA32_XSS). The CPUID value can be used by guest before allocate sufficient xsave buffer. Note, KVM does not yet support any XSS based features, i.e. supported_xss is guaranteed to be zero at this time. Opportunistically skip CPUID updates if XSS value doesn't change. Suggested-by: Sean Christopherson Co-developed-by: Zhang Yi Z Signed-off-by: Zhang Yi Z Signed-off-by: Yang Weijiang Reviewed-by: Maxim Levitsky Reviewed-by: Chao Gao Reviewed-by: Xiaoyao Li Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-8-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/cpuid.c | 3 ++- arch/x86/kvm/x86.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 6b8b5d8b13cc..32fde9e80c28 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -316,7 +316,8 @@ static void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) best = kvm_find_cpuid_entry_index(vcpu, 0xD, 1); if (best && (cpuid_entry_has(best, X86_FEATURE_XSAVES) || cpuid_entry_has(best, X86_FEATURE_XSAVEC))) - best->ebx = xstate_required_size(vcpu->arch.xcr0, true); + best->ebx = xstate_required_size(vcpu->arch.xcr0 | + vcpu->arch.ia32_xss, true); } static bool kvm_cpuid_has_hyperv(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6ae12e8c9d05..d142cbc71aaa 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3993,6 +3993,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) */ if (data & ~vcpu->arch.guest_supported_xss) return 1; + if (vcpu->arch.ia32_xss == data) + break; vcpu->arch.ia32_xss = data; vcpu->arch.cpuid_dynamic_bits_dirty = true; break; From 779ed05511f2931b89fcd0087aba2fcca8890715 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:15 -0700 Subject: [PATCH 2002/2711] KVM: x86: Initialize kvm_caps.supported_xss Set original kvm_caps.supported_xss to (host_xss & KVM_SUPPORTED_XSS) if XSAVES is supported. host_xss contains the host supported xstate feature bits for thread FPU context switch, KVM_SUPPORTED_XSS includes all KVM enabled XSS feature bits, the resulting value represents the supervisor xstates that are available to guest and are backed by host FPU framework for swapping {guest,host} XSAVE-managed registers/MSRs. [sean: relocate and enhance comment about PT / XSS[8] ] Signed-off-by: Yang Weijiang Reviewed-by: Maxim Levitsky Reviewed-by: Chao Gao Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Reviewed-by: Xiaoyao Li Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-9-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d142cbc71aaa..831c5e488de3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -217,6 +217,14 @@ static struct kvm_user_return_msrs __percpu *user_return_msrs; | XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \ | XFEATURE_MASK_PKRU | XFEATURE_MASK_XTILE) +/* + * Note, KVM supports exposing PT to the guest, but does not support context + * switching PT via XSTATE (KVM's PT virtualization relies on perf; swapping + * PT via guest XSTATE would clobber perf state), i.e. KVM doesn't support + * IA32_XSS[bit 8] (guests can/must use RDMSR/WRMSR to save/restore PT MSRs). + */ +#define KVM_SUPPORTED_XSS 0 + bool __read_mostly allow_smaller_maxphyaddr = 0; EXPORT_SYMBOL_GPL(allow_smaller_maxphyaddr); @@ -3986,11 +3994,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_IA32_XSS: if (!guest_cpuid_has(vcpu, X86_FEATURE_XSAVES)) return KVM_MSR_RET_UNSUPPORTED; - /* - * KVM supports exposing PT to the guest, but does not support - * IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than - * XSAVES/XRSTORS to save/restore PT MSRs. - */ + if (data & ~vcpu->arch.guest_supported_xss) return 1; if (vcpu->arch.ia32_xss == data) @@ -9822,14 +9826,17 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) kvm_host.xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); kvm_caps.supported_xcr0 = kvm_host.xcr0 & KVM_SUPPORTED_XCR0; } + + if (boot_cpu_has(X86_FEATURE_XSAVES)) { + rdmsrq(MSR_IA32_XSS, kvm_host.xss); + kvm_caps.supported_xss = kvm_host.xss & KVM_SUPPORTED_XSS; + } + kvm_caps.supported_quirks = KVM_X86_VALID_QUIRKS; kvm_caps.inapplicable_quirks = KVM_X86_CONDITIONAL_QUIRKS; rdmsrq_safe(MSR_EFER, &kvm_host.efer); - if (boot_cpu_has(X86_FEATURE_XSAVES)) - rdmsrq(MSR_IA32_XSS, kvm_host.xss); - kvm_init_pmu_capability(ops->pmu_ops); if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) From e44eb58334bbc28d790ed2851385cc86ea76dc12 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:16 -0700 Subject: [PATCH 2003/2711] KVM: x86: Load guest FPU state when access XSAVE-managed MSRs Load the guest's FPU state if userspace is accessing MSRs whose values are managed by XSAVES. Introduce two helpers, kvm_{get,set}_xstate_msr(), to facilitate access to such kind of MSRs. If MSRs supported in kvm_caps.supported_xss are passed through to guest, the guest MSRs are swapped with host's before vCPU exits to userspace and after it reenters kernel before next VM-entry. Because the modified code is also used for the KVM_GET_MSRS device ioctl(), explicitly check @vcpu is non-null before attempting to load guest state. The XSAVE-managed MSRs cannot be retrieved via the device ioctl() without loading guest FPU state (which doesn't exist). Note that guest_cpuid_has() is not queried as host userspace is allowed to access MSRs that have not been exposed to the guest, e.g. it might do KVM_SET_MSRS prior to KVM_SET_CPUID2. The two helpers are put here in order to manifest accessing xsave-managed MSRs requires special check and handling to guarantee the correctness of read/write to the MSRs. Co-developed-by: Yang Weijiang Signed-off-by: Yang Weijiang Reviewed-by: Maxim Levitsky Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao [sean: drop S_CET, add big comment, move accessors to x86.c] Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Reviewed-by: Xin Li (Intel) Link: https://lore.kernel.org/r/20250919223258.1604852-10-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 87 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 831c5e488de3..c2e11f3d50fb 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -136,6 +136,9 @@ static int __set_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2); static void __get_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2); static DEFINE_MUTEX(vendor_module_lock); +static void kvm_load_guest_fpu(struct kvm_vcpu *vcpu); +static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu); + struct kvm_x86_ops kvm_x86_ops __read_mostly; #define KVM_X86_OP(func) \ @@ -3801,6 +3804,67 @@ static void record_steal_time(struct kvm_vcpu *vcpu) mark_page_dirty_in_slot(vcpu->kvm, ghc->memslot, gpa_to_gfn(ghc->gpa)); } +/* + * Returns true if the MSR in question is managed via XSTATE, i.e. is context + * switched with the rest of guest FPU state. Note! S_CET is _not_ context + * switched via XSTATE even though it _is_ saved/restored via XSAVES/XRSTORS. + * Because S_CET is loaded on VM-Enter and VM-Exit via dedicated VMCS fields, + * the value saved/restored via XSTATE is always the host's value. That detail + * is _extremely_ important, as the guest's S_CET must _never_ be resident in + * hardware while executing in the host. Loading guest values for U_CET and + * PL[0-3]_SSP while executing in the kernel is safe, as U_CET is specific to + * userspace, and PL[0-3]_SSP are only consumed when transitioning to lower + * privilege levels, i.e. are effectively only consumed by userspace as well. + */ +static bool is_xstate_managed_msr(struct kvm_vcpu *vcpu, u32 msr) +{ + if (!vcpu) + return false; + + switch (msr) { + case MSR_IA32_U_CET: + return guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) || + guest_cpu_cap_has(vcpu, X86_FEATURE_IBT); + case MSR_IA32_PL0_SSP ... MSR_IA32_PL3_SSP: + return guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK); + default: + return false; + } +} + +/* + * Lock (and if necessary, re-load) the guest FPU, i.e. XSTATE, and access an + * MSR that is managed via XSTATE. Note, the caller is responsible for doing + * the initial FPU load, this helper only ensures that guest state is resident + * in hardware (the kernel can load its FPU state in IRQ context). + */ +static __always_inline void kvm_access_xstate_msr(struct kvm_vcpu *vcpu, + struct msr_data *msr_info, + int access) +{ + BUILD_BUG_ON(access != MSR_TYPE_R && access != MSR_TYPE_W); + + KVM_BUG_ON(!is_xstate_managed_msr(vcpu, msr_info->index), vcpu->kvm); + KVM_BUG_ON(!vcpu->arch.guest_fpu.fpstate->in_use, vcpu->kvm); + + kvm_fpu_get(); + if (access == MSR_TYPE_R) + rdmsrq(msr_info->index, msr_info->data); + else + wrmsrq(msr_info->index, msr_info->data); + kvm_fpu_put(); +} + +static __maybe_unused void kvm_set_xstate_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) +{ + kvm_access_xstate_msr(vcpu, msr_info, MSR_TYPE_W); +} + +static __maybe_unused void kvm_get_xstate_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) +{ + kvm_access_xstate_msr(vcpu, msr_info, MSR_TYPE_R); +} + int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { u32 msr = msr_info->index; @@ -4551,11 +4615,25 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs, int (*do_msr)(struct kvm_vcpu *vcpu, unsigned index, u64 *data)) { + bool fpu_loaded = false; int i; - for (i = 0; i < msrs->nmsrs; ++i) + for (i = 0; i < msrs->nmsrs; ++i) { + /* + * If userspace is accessing one or more XSTATE-managed MSRs, + * temporarily load the guest's FPU state so that the guest's + * MSR value(s) is resident in hardware and thus can be accessed + * via RDMSR/WRMSR. + */ + if (!fpu_loaded && is_xstate_managed_msr(vcpu, entries[i].index)) { + kvm_load_guest_fpu(vcpu); + fpu_loaded = true; + } if (do_msr(vcpu, entries[i].index, &entries[i].data)) break; + } + if (fpu_loaded) + kvm_put_guest_fpu(vcpu); return i; } @@ -5965,6 +6043,7 @@ static int kvm_get_set_one_reg(struct kvm_vcpu *vcpu, unsigned int ioctl, struct kvm_one_reg one_reg; struct kvm_x86_reg_id *reg; u64 __user *user_val; + bool load_fpu; int r; if (copy_from_user(&one_reg, argp, sizeof(one_reg))) @@ -5991,12 +6070,18 @@ static int kvm_get_set_one_reg(struct kvm_vcpu *vcpu, unsigned int ioctl, guard(srcu)(&vcpu->kvm->srcu); + load_fpu = is_xstate_managed_msr(vcpu, reg->index); + if (load_fpu) + kvm_load_guest_fpu(vcpu); + user_val = u64_to_user_ptr(one_reg.addr); if (ioctl == KVM_GET_ONE_REG) r = kvm_get_one_msr(vcpu, reg->index, user_val); else r = kvm_set_one_msr(vcpu, reg->index, user_val); + if (load_fpu) + kvm_put_guest_fpu(vcpu); return r; } From 586ef9dcbb28fc0bc6beb496e6dc8a54276e7a32 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:17 -0700 Subject: [PATCH 2004/2711] KVM: x86: Add fault checks for guest CR4.CET setting Check potential faults for CR4.CET setting per Intel SDM requirements. CET can be enabled if and only if CR0.WP == 1, i.e. setting CR4.CET == 1 faults if CR0.WP == 0 and setting CR0.WP == 0 fails if CR4.CET == 1. Signed-off-by: Yang Weijiang Reviewed-by: Chao Gao Reviewed-by: Maxim Levitsky Reviewed-by: Xiaoyao Li Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Co-developed-by: Sean Christopherson Link: https://lore.kernel.org/r/20250919223258.1604852-11-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c2e11f3d50fb..6d67c969e18a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1176,6 +1176,9 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) (is_64_bit_mode(vcpu) || kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE))) return 1; + if (!(cr0 & X86_CR0_WP) && kvm_is_cr4_bit_set(vcpu, X86_CR4_CET)) + return 1; + kvm_x86_call(set_cr0)(vcpu, cr0); kvm_post_set_cr0(vcpu, old_cr0, cr0); @@ -1376,6 +1379,9 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) return 1; } + if ((cr4 & X86_CR4_CET) && !kvm_is_cr0_bit_set(vcpu, X86_CR0_WP)) + return 1; + kvm_x86_call(set_cr4)(vcpu, cr4); kvm_post_set_cr4(vcpu, old_cr4, cr4); From 6a11c860d8a4aa1c7351246bd1ee7b41f26399b6 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:18 -0700 Subject: [PATCH 2005/2711] KVM: x86: Report KVM supported CET MSRs as to-be-saved Add CET MSRs to the list of MSRs reported to userspace if the feature, i.e. IBT or SHSTK, associated with the MSRs is supported by KVM. Suggested-by: Chao Gao Signed-off-by: Yang Weijiang Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-12-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6d67c969e18a..5f23d2d2731d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -344,6 +344,10 @@ static const u32 msrs_to_save_base[] = { MSR_IA32_UMWAIT_CONTROL, MSR_IA32_XFD, MSR_IA32_XFD_ERR, MSR_IA32_XSS, + + MSR_IA32_U_CET, MSR_IA32_S_CET, + MSR_IA32_PL0_SSP, MSR_IA32_PL1_SSP, MSR_IA32_PL2_SSP, + MSR_IA32_PL3_SSP, MSR_IA32_INT_SSP_TAB, }; static const u32 msrs_to_save_pmu[] = { @@ -7603,6 +7607,20 @@ static void kvm_probe_msr_to_save(u32 msr_index) if (!kvm_caps.supported_xss) return; break; + case MSR_IA32_U_CET: + case MSR_IA32_S_CET: + if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK) && + !kvm_cpu_cap_has(X86_FEATURE_IBT)) + return; + break; + case MSR_IA32_INT_SSP_TAB: + if (!kvm_cpu_cap_has(X86_FEATURE_LM)) + return; + fallthrough; + case MSR_IA32_PL0_SSP ... MSR_IA32_PL3_SSP: + if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK)) + return; + break; default: break; } From d6c387fc396b3d2c5aa00cb5b46f6401fb86bb43 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:19 -0700 Subject: [PATCH 2006/2711] KVM: VMX: Introduce CET VMCS fields and control bits Control-flow Enforcement Technology (CET) is a kind of CPU feature used to prevent Return/CALL/Jump-Oriented Programming (ROP/COP/JOP) attacks. It provides two sub-features(SHSTK,IBT) to defend against ROP/COP/JOP style control-flow subversion attacks. Shadow Stack (SHSTK): A shadow stack is a second stack used exclusively for control transfer operations. The shadow stack is separate from the data/normal stack and can be enabled individually in user and kernel mode. When shadow stack is enabled, CALL pushes the return address on both the data and shadow stack. RET pops the return address from both stacks and compares them. If the return addresses from the two stacks do not match, the processor generates a #CP. Indirect Branch Tracking (IBT): IBT introduces instruction(ENDBRANCH)to mark valid target addresses of indirect branches (CALL, JMP etc...). If an indirect branch is executed and the next instruction is _not_ an ENDBRANCH, the processor generates a #CP. These instruction behaves as a NOP on platforms that have no CET. Several new CET MSRs are defined to support CET: MSR_IA32_{U,S}_CET: CET settings for {user,supervisor} CET respectively. MSR_IA32_PL{0,1,2,3}_SSP: SHSTK pointer linear address for CPL{0,1,2,3}. MSR_IA32_INT_SSP_TAB: Linear address of SHSTK pointer table, whose entry is indexed by IST of interrupt gate desc. Two XSAVES state bits are introduced for CET: IA32_XSS:[bit 11]: Control saving/restoring user mode CET states IA32_XSS:[bit 12]: Control saving/restoring supervisor mode CET states. Six VMCS fields are introduced for CET: {HOST,GUEST}_S_CET: Stores CET settings for kernel mode. {HOST,GUEST}_SSP: Stores current active SSP. {HOST,GUEST}_INTR_SSP_TABLE: Stores current active MSR_IA32_INT_SSP_TAB. On Intel platforms, two additional bits are defined in VM_EXIT and VM_ENTRY control fields: If VM_EXIT_LOAD_CET_STATE = 1, host CET states are loaded from following VMCS fields at VM-Exit: HOST_S_CET HOST_SSP HOST_INTR_SSP_TABLE If VM_ENTRY_LOAD_CET_STATE = 1, guest CET states are loaded from following VMCS fields at VM-Entry: GUEST_S_CET GUEST_SSP GUEST_INTR_SSP_TABLE Co-developed-by: Zhang Yi Z Signed-off-by: Zhang Yi Z Signed-off-by: Yang Weijiang Reviewed-by: Chao Gao Reviewed-by: Maxim Levitsky Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-13-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/vmx.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index cca7d6641287..ce10a7e2d3d9 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -106,6 +106,7 @@ #define VM_EXIT_CLEAR_BNDCFGS 0x00800000 #define VM_EXIT_PT_CONCEAL_PIP 0x01000000 #define VM_EXIT_CLEAR_IA32_RTIT_CTL 0x02000000 +#define VM_EXIT_LOAD_CET_STATE 0x10000000 #define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR 0x00036dff @@ -119,6 +120,7 @@ #define VM_ENTRY_LOAD_BNDCFGS 0x00010000 #define VM_ENTRY_PT_CONCEAL_PIP 0x00020000 #define VM_ENTRY_LOAD_IA32_RTIT_CTL 0x00040000 +#define VM_ENTRY_LOAD_CET_STATE 0x00100000 #define VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR 0x000011ff @@ -369,6 +371,9 @@ enum vmcs_field { GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, GUEST_SYSENTER_ESP = 0x00006824, GUEST_SYSENTER_EIP = 0x00006826, + GUEST_S_CET = 0x00006828, + GUEST_SSP = 0x0000682a, + GUEST_INTR_SSP_TABLE = 0x0000682c, HOST_CR0 = 0x00006c00, HOST_CR3 = 0x00006c02, HOST_CR4 = 0x00006c04, @@ -381,6 +386,9 @@ enum vmcs_field { HOST_IA32_SYSENTER_EIP = 0x00006c12, HOST_RSP = 0x00006c14, HOST_RIP = 0x00006c16, + HOST_S_CET = 0x00006c18, + HOST_SSP = 0x00006c1a, + HOST_INTR_SSP_TABLE = 0x00006c1c }; /* From 9d6812d415358372aaaf1dfe95bc30d11e4e95db Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:20 -0700 Subject: [PATCH 2007/2711] KVM: x86: Enable guest SSP read/write interface with new uAPIs Add a KVM-defined ONE_REG register, KVM_REG_GUEST_SSP, to let userspace save and restore the guest's Shadow Stack Pointer (SSP). On both Intel and AMD, SSP is a hardware register that can only be accessed by software via dedicated ISA (e.g. RDSSP) or via VMCS/VMCB fields (used by hardware to context switch SSP at entry/exit). As a result, SSP doesn't fit in any of KVM's existing interfaces for saving/restoring state. Internally, treat SSP as a fake/synthetic MSR, as the semantics of writes to SSP follow that of several other Shadow Stack MSRs, e.g. the PLx_SSP MSRs. Use a translation layer to hide the KVM-internal MSR index so that the arbitrary index doesn't become ABI, e.g. so that KVM can rework its implementation as needed, so long as the ONE_REG ABI is maintained. Explicitly reject accesses to SSP if the vCPU doesn't have Shadow Stack support to avoid running afoul of ignore_msrs, which unfortunately applies to host-initiated accesses (which is a discussion for another day). I.e. ensure consistent behavior for KVM-defined registers irrespective of ignore_msrs. Link: https://lore.kernel.org/all/aca9d389-f11e-4811-90cf-d98e345a5cc2@intel.com Suggested-by: Sean Christopherson Signed-off-by: Yang Weijiang Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-14-seanjc@google.com Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- Documentation/virt/kvm/api.rst | 8 +++++++ arch/x86/include/uapi/asm/kvm.h | 3 +++ arch/x86/kvm/x86.c | 37 +++++++++++++++++++++++++++++---- arch/x86/kvm/x86.h | 10 +++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 0e82fc5abd7b..fac1774031ee 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -2911,6 +2911,14 @@ such as set vcpu counter or reset vcpu, and they have the following id bit patte x86 MSR registers have the following id bit patterns:: 0x2030 0002 +Following are the KVM-defined registers for x86: + +======================= ========= ============================================= + Encoding Register Description +======================= ========= ============================================= + 0x2030 0003 0000 0000 SSP Shadow Stack Pointer +======================= ========= ============================================= + 4.69 KVM_GET_ONE_REG -------------------- diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index aae1033c8afa..467116186e71 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -437,6 +437,9 @@ struct kvm_xcrs { #define KVM_X86_REG_KVM(index) \ KVM_X86_REG_ID(KVM_X86_REG_TYPE_KVM, index) +/* KVM-defined registers starting from 0 */ +#define KVM_REG_GUEST_SSP 0 + #define KVM_SYNC_X86_REGS (1UL << 0) #define KVM_SYNC_X86_SREGS (1UL << 1) #define KVM_SYNC_X86_EVENTS (1UL << 2) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5f23d2d2731d..d85bb723f25a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6016,9 +6016,27 @@ struct kvm_x86_reg_id { __u8 x86; }; -static int kvm_translate_kvm_reg(struct kvm_x86_reg_id *reg) +static int kvm_translate_kvm_reg(struct kvm_vcpu *vcpu, + struct kvm_x86_reg_id *reg) { - return -EINVAL; + switch (reg->index) { + case KVM_REG_GUEST_SSP: + /* + * FIXME: If host-initiated accesses are ever exempted from + * ignore_msrs (in kvm_do_msr_access()), drop this manual check + * and rely on KVM's standard checks to reject accesses to regs + * that don't exist. + */ + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) + return -EINVAL; + + reg->type = KVM_X86_REG_TYPE_MSR; + reg->index = MSR_KVM_INTERNAL_GUEST_SSP; + break; + default: + return -EINVAL; + } + return 0; } static int kvm_get_one_msr(struct kvm_vcpu *vcpu, u32 msr, u64 __user *user_val) @@ -6067,7 +6085,7 @@ static int kvm_get_set_one_reg(struct kvm_vcpu *vcpu, unsigned int ioctl, return -EINVAL; if (reg->type == KVM_X86_REG_TYPE_KVM) { - r = kvm_translate_kvm_reg(reg); + r = kvm_translate_kvm_reg(vcpu, reg); if (r) return r; } @@ -6098,11 +6116,22 @@ static int kvm_get_set_one_reg(struct kvm_vcpu *vcpu, unsigned int ioctl, static int kvm_get_reg_list(struct kvm_vcpu *vcpu, struct kvm_reg_list __user *user_list) { - u64 nr_regs = 0; + u64 nr_regs = guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) ? 1 : 0; + u64 user_nr_regs; + + if (get_user(user_nr_regs, &user_list->n)) + return -EFAULT; if (put_user(nr_regs, &user_list->n)) return -EFAULT; + if (user_nr_regs < nr_regs) + return -E2BIG; + + if (nr_regs && + put_user(KVM_X86_REG_KVM(KVM_REG_GUEST_SSP), &user_list->reg[0])) + return -EFAULT; + return 0; } diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 786e36fcd0fb..a7c9c72fca93 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -101,6 +101,16 @@ do { \ #define KVM_SVM_DEFAULT_PLE_WINDOW_MAX USHRT_MAX #define KVM_SVM_DEFAULT_PLE_WINDOW 3000 +/* + * KVM's internal, non-ABI indices for synthetic MSRs. The values themselves + * are arbitrary and have no meaning, the only requirement is that they don't + * conflict with "real" MSRs that KVM supports. Use values at the upper end + * of KVM's reserved paravirtual MSR range to minimize churn, i.e. these values + * will be usable until KVM exhausts its supply of paravirtual MSR indices. + */ + +#define MSR_KVM_INTERNAL_GUEST_SSP 0x4b564dff + static inline unsigned int __grow_ple_window(unsigned int val, unsigned int base, unsigned int modifier, unsigned int max) { From 8b59d0275c964bcbe573dde46bd3c1f20ed2d2bd Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:21 -0700 Subject: [PATCH 2008/2711] KVM: VMX: Emulate read and write to CET MSRs Add emulation interface for CET MSR access. The emulation code is split into common part and vendor specific part. The former does common checks for MSRs, e.g., accessibility, data validity etc., then passes operation to either XSAVE-managed MSRs via the helpers or CET VMCS fields. SSP can only be read via RDSSP. Writing even requires destructive and potentially faulting operations such as SAVEPREVSSP/RSTORSSP or SETSSBSY/CLRSSBSY. Let the host use a pseudo-MSR that is just a wrapper for the GUEST_SSP field of the VMCS. Suggested-by: Sean Christopherson Signed-off-by: Yang Weijiang Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao [sean: drop call to kvm_set_xstate_msr() for S_CET, consolidate code] Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-15-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 18 ++++++++++++ arch/x86/kvm/x86.c | 64 ++++++++++++++++++++++++++++++++++++++++-- arch/x86/kvm/x86.h | 23 +++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index d2fa64bddb57..62bf93dc0825 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2093,6 +2093,15 @@ int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) else msr_info->data = vmx->pt_desc.guest.addr_a[index / 2]; break; + case MSR_IA32_S_CET: + msr_info->data = vmcs_readl(GUEST_S_CET); + break; + case MSR_KVM_INTERNAL_GUEST_SSP: + msr_info->data = vmcs_readl(GUEST_SSP); + break; + case MSR_IA32_INT_SSP_TAB: + msr_info->data = vmcs_readl(GUEST_INTR_SSP_TABLE); + break; case MSR_IA32_DEBUGCTLMSR: msr_info->data = vmx_guest_debugctl_read(); break; @@ -2411,6 +2420,15 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) else vmx->pt_desc.guest.addr_a[index / 2] = data; break; + case MSR_IA32_S_CET: + vmcs_writel(GUEST_S_CET, data); + break; + case MSR_KVM_INTERNAL_GUEST_SSP: + vmcs_writel(GUEST_SSP, data); + break; + case MSR_IA32_INT_SSP_TAB: + vmcs_writel(GUEST_INTR_SSP_TABLE, data); + break; case MSR_IA32_PERF_CAPABILITIES: if (data & PERF_CAP_LBR_FMT) { if ((data & PERF_CAP_LBR_FMT) != diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d85bb723f25a..54d280fe9a4b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1890,6 +1890,44 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data, data = (u32)data; break; + case MSR_IA32_U_CET: + case MSR_IA32_S_CET: + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) && + !guest_cpu_cap_has(vcpu, X86_FEATURE_IBT)) + return KVM_MSR_RET_UNSUPPORTED; + if (!kvm_is_valid_u_s_cet(vcpu, data)) + return 1; + break; + case MSR_KVM_INTERNAL_GUEST_SSP: + if (!host_initiated) + return 1; + fallthrough; + /* + * Note that the MSR emulation here is flawed when a vCPU + * doesn't support the Intel 64 architecture. The expected + * architectural behavior in this case is that the upper 32 + * bits do not exist and should always read '0'. However, + * because the actual hardware on which the virtual CPU is + * running does support Intel 64, XRSTORS/XSAVES in the + * guest could observe behavior that violates the + * architecture. Intercepting XRSTORS/XSAVES for this + * special case isn't deemed worthwhile. + */ + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) + return KVM_MSR_RET_UNSUPPORTED; + /* + * MSR_IA32_INT_SSP_TAB is not present on processors that do + * not support Intel 64 architecture. + */ + if (index == MSR_IA32_INT_SSP_TAB && !guest_cpu_cap_has(vcpu, X86_FEATURE_LM)) + return KVM_MSR_RET_UNSUPPORTED; + if (is_noncanonical_msr_address(data, vcpu)) + return 1; + /* All SSP MSRs except MSR_IA32_INT_SSP_TAB must be 4-byte aligned */ + if (index != MSR_IA32_INT_SSP_TAB && !IS_ALIGNED(data, 4)) + return 1; + break; } msr.data = data; @@ -1934,6 +1972,20 @@ static int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, !guest_cpu_cap_has(vcpu, X86_FEATURE_RDPID)) return 1; break; + case MSR_IA32_U_CET: + case MSR_IA32_S_CET: + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) && + !guest_cpu_cap_has(vcpu, X86_FEATURE_IBT)) + return KVM_MSR_RET_UNSUPPORTED; + break; + case MSR_KVM_INTERNAL_GUEST_SSP: + if (!host_initiated) + return 1; + fallthrough; + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) + return KVM_MSR_RET_UNSUPPORTED; + break; } msr.index = index; @@ -3865,12 +3917,12 @@ static __always_inline void kvm_access_xstate_msr(struct kvm_vcpu *vcpu, kvm_fpu_put(); } -static __maybe_unused void kvm_set_xstate_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) +static void kvm_set_xstate_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { kvm_access_xstate_msr(vcpu, msr_info, MSR_TYPE_W); } -static __maybe_unused void kvm_get_xstate_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) +static void kvm_get_xstate_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { kvm_access_xstate_msr(vcpu, msr_info, MSR_TYPE_R); } @@ -4256,6 +4308,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.guest_fpu.xfd_err = data; break; #endif + case MSR_IA32_U_CET: + case MSR_IA32_PL0_SSP ... MSR_IA32_PL3_SSP: + kvm_set_xstate_msr(vcpu, msr_info); + break; default: if (kvm_pmu_is_valid_msr(vcpu, msr)) return kvm_pmu_set_msr(vcpu, msr_info); @@ -4605,6 +4661,10 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = vcpu->arch.guest_fpu.xfd_err; break; #endif + case MSR_IA32_U_CET: + case MSR_IA32_PL0_SSP ... MSR_IA32_PL3_SSP: + kvm_get_xstate_msr(vcpu, msr_info); + break; default: if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) return kvm_pmu_get_msr(vcpu, msr_info); diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index a7c9c72fca93..076eccba0f7e 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -710,4 +710,27 @@ int ____kvm_emulate_hypercall(struct kvm_vcpu *vcpu, int cpl, int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); +#define CET_US_RESERVED_BITS GENMASK(9, 6) +#define CET_US_SHSTK_MASK_BITS GENMASK(1, 0) +#define CET_US_IBT_MASK_BITS (GENMASK_ULL(5, 2) | GENMASK_ULL(63, 10)) +#define CET_US_LEGACY_BITMAP_BASE(data) ((data) >> 12) + +static inline bool kvm_is_valid_u_s_cet(struct kvm_vcpu *vcpu, u64 data) +{ + if (data & CET_US_RESERVED_BITS) + return false; + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) && + (data & CET_US_SHSTK_MASK_BITS)) + return false; + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_IBT) && + (data & CET_US_IBT_MASK_BITS)) + return false; + if (!IS_ALIGNED(CET_US_LEGACY_BITMAP_BASE(data), 4)) + return false; + /* IBT can be suppressed iff the TRACKER isn't WAIT_ENDBR. */ + if ((data & CET_SUPPRESS) && (data & CET_WAIT_ENDBR)) + return false; + + return true; +} #endif From 1a61bd0d126abbf01c384c44b46bcdd4ef495850 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:22 -0700 Subject: [PATCH 2009/2711] KVM: x86: Save and reload SSP to/from SMRAM Save CET SSP to SMRAM on SMI and reload it on RSM. KVM emulates HW arch behavior when guest enters/leaves SMM mode,i.e., save registers to SMRAM at the entry of SMM and reload them at the exit to SMM. Per SDM, SSP is one of such registers on 64-bit Arch, and add the support for SSP. Suggested-by: Sean Christopherson Signed-off-by: Yang Weijiang Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-16-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/smm.c | 8 ++++++++ arch/x86/kvm/smm.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/smm.c b/arch/x86/kvm/smm.c index 5dd8a1646800..b0b14ba37f9a 100644 --- a/arch/x86/kvm/smm.c +++ b/arch/x86/kvm/smm.c @@ -269,6 +269,10 @@ static void enter_smm_save_state_64(struct kvm_vcpu *vcpu, enter_smm_save_seg_64(vcpu, &smram->gs, VCPU_SREG_GS); smram->int_shadow = kvm_x86_call(get_interrupt_shadow)(vcpu); + + if (guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) && + kvm_msr_read(vcpu, MSR_KVM_INTERNAL_GUEST_SSP, &smram->ssp)) + kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); } #endif @@ -558,6 +562,10 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, kvm_x86_call(set_interrupt_shadow)(vcpu, 0); ctxt->interruptibility = (u8)smstate->int_shadow; + if (guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) && + kvm_msr_write(vcpu, MSR_KVM_INTERNAL_GUEST_SSP, smstate->ssp)) + return X86EMUL_UNHANDLEABLE; + return X86EMUL_CONTINUE; } #endif diff --git a/arch/x86/kvm/smm.h b/arch/x86/kvm/smm.h index 551703fbe200..db3c88f16138 100644 --- a/arch/x86/kvm/smm.h +++ b/arch/x86/kvm/smm.h @@ -116,8 +116,8 @@ struct kvm_smram_state_64 { u32 smbase; u32 reserved4[5]; - /* ssp and svm_* fields below are not implemented by KVM */ u64 ssp; + /* svm_* fields below are not implemented by KVM */ u64 svm_guest_pat; u64 svm_host_efer; u64 svm_host_cr4; From 25f3840483e6c69e4d1a689cf3edc70f93604f2a Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:23 -0700 Subject: [PATCH 2010/2711] KVM: VMX: Set up interception for CET MSRs Disable interception for CET MSRs that can be accessed via XSAVES/XRSTORS, and exist accordingly to CPUID, as accesses through XSTATE aren't subject to MSR interception checks, i.e. can't be intercepted without intercepting and emulating XSAVES/XRSTORS, and KVM doesn't support emulating XSAVE/XRSTOR instructions. Don't condition interception on the guest actually having XSAVES as there is no benefit to intercepting the accesses (when the MSRs exist). The MSRs in question are either context switched by the CPU on VM-Enter/VM-Exit or by KVM via XSAVES/XRSTORS (KVM requires XSAVES to virtualization SHSTK), i.e. KVM is going to load guest values into hardware irrespective of guest XSAVES support. Suggested-by: Sean Christopherson Signed-off-by: Yang Weijiang Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Reviewed-by: Xin Li (Intel) Link: https://lore.kernel.org/r/20250919223258.1604852-17-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 62bf93dc0825..bde768c7111f 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4088,6 +4088,8 @@ void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu) static void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu) { + bool intercept; + if (!cpu_has_vmx_msr_bitmap()) return; @@ -4133,6 +4135,23 @@ static void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu) vmx_set_intercept_for_msr(vcpu, MSR_IA32_FLUSH_CMD, MSR_TYPE_W, !guest_cpu_cap_has(vcpu, X86_FEATURE_FLUSH_L1D)); + if (kvm_cpu_cap_has(X86_FEATURE_SHSTK)) { + intercept = !guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK); + + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL0_SSP, MSR_TYPE_RW, intercept); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL1_SSP, MSR_TYPE_RW, intercept); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL2_SSP, MSR_TYPE_RW, intercept); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL3_SSP, MSR_TYPE_RW, intercept); + } + + if (kvm_cpu_cap_has(X86_FEATURE_SHSTK) || kvm_cpu_cap_has(X86_FEATURE_IBT)) { + intercept = !guest_cpu_cap_has(vcpu, X86_FEATURE_IBT) && + !guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK); + + vmx_set_intercept_for_msr(vcpu, MSR_IA32_U_CET, MSR_TYPE_RW, intercept); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, MSR_TYPE_RW, intercept); + } + /* * x2APIC and LBR MSR intercepts are modified on-demand and cannot be * filtered by userspace. From 584ba3ffb9843fd12d3b4a33cfe056e2264392a0 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:24 -0700 Subject: [PATCH 2011/2711] KVM: VMX: Set host constant supervisor states to VMCS fields Save constant values to HOST_{S_CET,SSP,INTR_SSP_TABLE} field explicitly. Kernel IBT is supported and the setting in MSR_IA32_S_CET is static after post-boot(The exception is BIOS call case but vCPU thread never across it) and KVM doesn't need to refresh HOST_S_CET field before every VM-Enter/ VM-Exit sequence. Host supervisor shadow stack is not enabled now and SSP is not accessible to kernel mode, thus it's safe to set host IA32_INT_SSP_TAB/SSP VMCS field to 0s. When shadow stack is enabled for CPL3, SSP is reloaded from PL3_SSP before it exits to userspace. Check SDM Vol 2A/B Chapter 3/4 for SYSCALL/ SYSRET/SYSENTER SYSEXIT/RDSSP/CALL etc. Prevent KVM module loading if host supervisor shadow stack SHSTK_EN is set in MSR_IA32_S_CET as KVM cannot co-exit with it correctly. Suggested-by: Sean Christopherson Suggested-by: Chao Gao Signed-off-by: Yang Weijiang Reviewed-by: Maxim Levitsky Reviewed-by: Chao Gao Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao [sean: snapshot host S_CET if SHSTK *or* IBT is supported] Reviewed-by: Xiaoyao Li Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-18-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/capabilities.h | 4 ++++ arch/x86/kvm/vmx/vmx.c | 15 +++++++++++++++ arch/x86/kvm/x86.c | 12 ++++++++++++ arch/x86/kvm/x86.h | 1 + 4 files changed, 32 insertions(+) diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h index f614428dbeda..59c83888bdc0 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -100,6 +100,10 @@ static inline bool cpu_has_load_perf_global_ctrl(void) return vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; } +static inline bool cpu_has_load_cet_ctrl(void) +{ + return (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_CET_STATE); +} static inline bool cpu_has_vmx_mpx(void) { return vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_BNDCFGS; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index bde768c7111f..4ab066a3c22f 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4312,6 +4312,21 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx) if (cpu_has_load_ia32_efer()) vmcs_write64(HOST_IA32_EFER, kvm_host.efer); + + /* + * Supervisor shadow stack is not enabled on host side, i.e., + * host IA32_S_CET.SHSTK_EN bit is guaranteed to 0 now, per SDM + * description(RDSSP instruction), SSP is not readable in CPL0, + * so resetting the two registers to 0s at VM-Exit does no harm + * to kernel execution. When execution flow exits to userspace, + * SSP is reloaded from IA32_PL3_SSP. Check SDM Vol.2A/B Chapter + * 3 and 4 for details. + */ + if (cpu_has_load_cet_ctrl()) { + vmcs_writel(HOST_S_CET, kvm_host.s_cet); + vmcs_writel(HOST_SSP, 0); + vmcs_writel(HOST_INTR_SSP_TABLE, 0); + } } void set_cr4_guest_host_mask(struct vcpu_vmx *vmx) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 54d280fe9a4b..0050509a7de2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9997,6 +9997,18 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) return -EIO; } + if (boot_cpu_has(X86_FEATURE_SHSTK) || boot_cpu_has(X86_FEATURE_IBT)) { + rdmsrq(MSR_IA32_S_CET, kvm_host.s_cet); + /* + * Linux doesn't yet support supervisor shadow stacks (SSS), so + * KVM doesn't save/restore the associated MSRs, i.e. KVM may + * clobber the host values. Yell and refuse to load if SSS is + * unexpectedly enabled, e.g. to avoid crashing the host. + */ + if (WARN_ON_ONCE(kvm_host.s_cet & CET_SHSTK_EN)) + return -EIO; + } + memset(&kvm_caps, 0, sizeof(kvm_caps)); x86_emulator_cache = kvm_alloc_emulator_cache(); diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 076eccba0f7e..65cbd454c4f1 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -50,6 +50,7 @@ struct kvm_host_values { u64 efer; u64 xcr0; u64 xss; + u64 s_cet; u64 arch_capabilities; }; From 57c3db7e2e26970ee3630a25913368f849ea803a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:25 -0700 Subject: [PATCH 2012/2711] KVM: x86: Don't emulate instructions affected by CET features Don't emulate branch instructions, e.g. CALL/RET/JMP etc., that are affected by Shadow Stacks and/or Indirect Branch Tracking when said features are enabled in the guest, as fully emulating CET would require significant complexity for no practical benefit (KVM shouldn't need to emulate branch instructions on modern hosts). Simply doing nothing isn't an option as that would allow a malicious entity to subvert CET protections via the emulator. To detect instructions that are subject to IBT or affect IBT state, use the existing IsBranch flag along with the source operand type to detect indirect branches, and the existing NearBranch flag to detect far JMPs and CALLs, all of which are effectively indirect. Explicitly check for emulation of IRET, FAR RET (IMM), and SYSEXIT (the ret-like far branches) instead of adding another flag, e.g. IsRet, as it's unlikely the emulator will ever need to check for return-like instructions outside of this one specific flow. Use an allow-list instead of a deny-list because (a) it's a shorter list and (b) so that a missed entry gets a false positive, not a false negative (i.e. reject emulation instead of clobbering CET state). For Shadow Stacks, explicitly track instructions that directly affect the current SSP, as KVM's emulator doesn't have existing flags that can be used to precisely detect such instructions. Alternatively, the em_xxx() helpers could directly check for ShadowStack interactions, but using a dedicated flag is arguably easier to audit, and allows for handling both IBT and SHSTK in one fell swoop. Note! On far transfers, do NOT consult the current privilege level and instead treat SHSTK/IBT as being enabled if they're enabled for User *or* Supervisor mode. On inter-privilege level far transfers, SHSTK and IBT can be in play for the target privilege level, i.e. checking the current privilege could get a false negative, and KVM doesn't know the target privilege level until emulation gets under way. Note #2, FAR JMP from 64-bit mode to compatibility mode interacts with the current SSP, but only to ensure SSP[63:32] == 0. Don't tag FAR JMP as SHSTK, which would be rather confusing and would result in FAR JMP being rejected unnecessarily the vast majority of the time (ignoring that it's unlikely to ever be emulated). A future commit will add the #GP(0) check for the specific FAR JMP scenario. Note #3, task switches also modify SSP and so need to be rejected. That too will be addressed in a future commit. Suggested-by: Chao Gao Originally-by: Yang Weijiang Cc: Mathias Krause Cc: John Allen Cc: Rick Edgecombe Reviewed-by: Chao Gao Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-19-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/emulate.c | 115 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 102 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 23929151a5b8..48b067b179e0 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -178,6 +178,7 @@ #define IncSP ((u64)1 << 54) /* SP is incremented before ModRM calc */ #define TwoMemOp ((u64)1 << 55) /* Instruction has two memory operand */ #define IsBranch ((u64)1 << 56) /* Instruction is considered a branch. */ +#define ShadowStack ((u64)1 << 57) /* Instruction affects Shadow Stacks. */ #define DstXacc (DstAccLo | SrcAccHi | SrcWrite) @@ -4068,8 +4069,8 @@ static const struct opcode group4[] = { static const struct opcode group5[] = { F(DstMem | SrcNone | Lock, em_inc), F(DstMem | SrcNone | Lock, em_dec), - I(SrcMem | NearBranch | IsBranch, em_call_near_abs), - I(SrcMemFAddr | ImplicitOps | IsBranch, em_call_far), + I(SrcMem | NearBranch | IsBranch | ShadowStack, em_call_near_abs), + I(SrcMemFAddr | ImplicitOps | IsBranch | ShadowStack, em_call_far), I(SrcMem | NearBranch | IsBranch, em_jmp_abs), I(SrcMemFAddr | ImplicitOps | IsBranch, em_jmp_far), I(SrcMem | Stack | TwoMemOp, em_push), D(Undefined), @@ -4304,7 +4305,7 @@ static const struct opcode opcode_table[256] = { DI(SrcAcc | DstReg, pause), X7(D(SrcAcc | DstReg)), /* 0x98 - 0x9F */ D(DstAcc | SrcNone), I(ImplicitOps | SrcAcc, em_cwd), - I(SrcImmFAddr | No64 | IsBranch, em_call_far), N, + I(SrcImmFAddr | No64 | IsBranch | ShadowStack, em_call_far), N, II(ImplicitOps | Stack, em_pushf, pushf), II(ImplicitOps | Stack, em_popf, popf), I(ImplicitOps, em_sahf), I(ImplicitOps, em_lahf), @@ -4324,19 +4325,19 @@ static const struct opcode opcode_table[256] = { X8(I(DstReg | SrcImm64 | Mov, em_mov)), /* 0xC0 - 0xC7 */ G(ByteOp | Src2ImmByte, group2), G(Src2ImmByte, group2), - I(ImplicitOps | NearBranch | SrcImmU16 | IsBranch, em_ret_near_imm), - I(ImplicitOps | NearBranch | IsBranch, em_ret), + I(ImplicitOps | NearBranch | SrcImmU16 | IsBranch | ShadowStack, em_ret_near_imm), + I(ImplicitOps | NearBranch | IsBranch | ShadowStack, em_ret), I(DstReg | SrcMemFAddr | ModRM | No64 | Src2ES, em_lseg), I(DstReg | SrcMemFAddr | ModRM | No64 | Src2DS, em_lseg), G(ByteOp, group11), G(0, group11), /* 0xC8 - 0xCF */ I(Stack | SrcImmU16 | Src2ImmByte, em_enter), I(Stack, em_leave), - I(ImplicitOps | SrcImmU16 | IsBranch, em_ret_far_imm), - I(ImplicitOps | IsBranch, em_ret_far), - D(ImplicitOps | IsBranch), DI(SrcImmByte | IsBranch, intn), + I(ImplicitOps | SrcImmU16 | IsBranch | ShadowStack, em_ret_far_imm), + I(ImplicitOps | IsBranch | ShadowStack, em_ret_far), + D(ImplicitOps | IsBranch), DI(SrcImmByte | IsBranch | ShadowStack, intn), D(ImplicitOps | No64 | IsBranch), - II(ImplicitOps | IsBranch, em_iret, iret), + II(ImplicitOps | IsBranch | ShadowStack, em_iret, iret), /* 0xD0 - 0xD7 */ G(Src2One | ByteOp, group2), G(Src2One, group2), G(Src2CL | ByteOp, group2), G(Src2CL, group2), @@ -4352,7 +4353,7 @@ static const struct opcode opcode_table[256] = { I2bvIP(SrcImmUByte | DstAcc, em_in, in, check_perm_in), I2bvIP(SrcAcc | DstImmUByte, em_out, out, check_perm_out), /* 0xE8 - 0xEF */ - I(SrcImm | NearBranch | IsBranch, em_call), + I(SrcImm | NearBranch | IsBranch | ShadowStack, em_call), D(SrcImm | ImplicitOps | NearBranch | IsBranch), I(SrcImmFAddr | No64 | IsBranch, em_jmp_far), D(SrcImmByte | ImplicitOps | NearBranch | IsBranch), @@ -4371,7 +4372,7 @@ static const struct opcode opcode_table[256] = { static const struct opcode twobyte_table[256] = { /* 0x00 - 0x0F */ G(0, group6), GD(0, &group7), N, N, - N, I(ImplicitOps | EmulateOnUD | IsBranch, em_syscall), + N, I(ImplicitOps | EmulateOnUD | IsBranch | ShadowStack, em_syscall), II(ImplicitOps | Priv, em_clts, clts), N, DI(ImplicitOps | Priv, invd), DI(ImplicitOps | Priv, wbinvd), N, N, N, D(ImplicitOps | ModRM | SrcMem | NoAccess), N, N, @@ -4402,8 +4403,8 @@ static const struct opcode twobyte_table[256] = { IIP(ImplicitOps, em_rdtsc, rdtsc, check_rdtsc), II(ImplicitOps | Priv, em_rdmsr, rdmsr), IIP(ImplicitOps, em_rdpmc, rdpmc, check_rdpmc), - I(ImplicitOps | EmulateOnUD | IsBranch, em_sysenter), - I(ImplicitOps | Priv | EmulateOnUD | IsBranch, em_sysexit), + I(ImplicitOps | EmulateOnUD | IsBranch | ShadowStack, em_sysenter), + I(ImplicitOps | Priv | EmulateOnUD | IsBranch | ShadowStack, em_sysexit), N, N, N, N, N, N, N, N, N, N, /* 0x40 - 0x4F */ @@ -4514,6 +4515,60 @@ static const struct opcode opcode_map_0f_38[256] = { #undef I2bvIP #undef I6ALU +static bool is_shstk_instruction(struct x86_emulate_ctxt *ctxt) +{ + return ctxt->d & ShadowStack; +} + +static bool is_ibt_instruction(struct x86_emulate_ctxt *ctxt) +{ + u64 flags = ctxt->d; + + if (!(flags & IsBranch)) + return false; + + /* + * All far JMPs and CALLs (including SYSCALL, SYSENTER, and INTn) are + * indirect and thus affect IBT state. All far RETs (including SYSEXIT + * and IRET) are protected via Shadow Stacks and thus don't affect IBT + * state. IRET #GPs when returning to virtual-8086 and IBT or SHSTK is + * enabled, but that should be handled by IRET emulation (in the very + * unlikely scenario that KVM adds support for fully emulating IRET). + */ + if (!(flags & NearBranch)) + return ctxt->execute != em_iret && + ctxt->execute != em_ret_far && + ctxt->execute != em_ret_far_imm && + ctxt->execute != em_sysexit; + + switch (flags & SrcMask) { + case SrcReg: + case SrcMem: + case SrcMem16: + case SrcMem32: + return true; + case SrcMemFAddr: + case SrcImmFAddr: + /* Far branches should be handled above. */ + WARN_ON_ONCE(1); + return true; + case SrcNone: + case SrcImm: + case SrcImmByte: + /* + * Note, ImmU16 is used only for the stack adjustment operand on ENTER + * and RET instructions. ENTER isn't a branch and RET FAR is handled + * by the NearBranch check above. RET itself isn't an indirect branch. + */ + case SrcImmU16: + return false; + default: + WARN_ONCE(1, "Unexpected Src operand '%llx' on branch", + flags & SrcMask); + return false; + } +} + static unsigned imm_size(struct x86_emulate_ctxt *ctxt) { unsigned size; @@ -4943,6 +4998,40 @@ done_prefixes: ctxt->execute = opcode.u.execute; + /* + * Reject emulation if KVM might need to emulate shadow stack updates + * and/or indirect branch tracking enforcement, which the emulator + * doesn't support. + */ + if ((is_ibt_instruction(ctxt) || is_shstk_instruction(ctxt)) && + ctxt->ops->get_cr(ctxt, 4) & X86_CR4_CET) { + u64 u_cet = 0, s_cet = 0; + + /* + * Check both User and Supervisor on far transfers as inter- + * privilege level transfers are impacted by CET at the target + * privilege level, and that is not known at this time. The + * expectation is that the guest will not require emulation of + * any CET-affected instructions at any privilege level. + */ + if (!(ctxt->d & NearBranch)) + u_cet = s_cet = CET_SHSTK_EN | CET_ENDBR_EN; + else if (ctxt->ops->cpl(ctxt) == 3) + u_cet = CET_SHSTK_EN | CET_ENDBR_EN; + else + s_cet = CET_SHSTK_EN | CET_ENDBR_EN; + + if ((u_cet && ctxt->ops->get_msr(ctxt, MSR_IA32_U_CET, &u_cet)) || + (s_cet && ctxt->ops->get_msr(ctxt, MSR_IA32_S_CET, &s_cet))) + return EMULATION_FAILED; + + if ((u_cet | s_cet) & CET_SHSTK_EN && is_shstk_instruction(ctxt)) + return EMULATION_FAILED; + + if ((u_cet | s_cet) & CET_ENDBR_EN && is_ibt_instruction(ctxt)) + return EMULATION_FAILED; + } + if (unlikely(emulation_type & EMULTYPE_TRAP_UD) && likely(!(ctxt->d & EmulateOnUD))) return EMULATION_FAILED; From 82c0ec02825814e1ef332d635d3441b07c05b1c9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:26 -0700 Subject: [PATCH 2013/2711] KVM: x86: Don't emulate task switches when IBT or SHSTK is enabled Exit to userspace with KVM_INTERNAL_ERROR_EMULATION if the guest triggers task switch emulation with Indirect Branch Tracking or Shadow Stacks enabled, as attempting to do the right thing would require non-trivial effort and complexity, KVM doesn't support emulating CET generally, and it's extremely unlikely that any guest will do task switches while also utilizing CET. Defer taking on the complexity until someone cares enough to put in the time and effort to add support. Per the SDM: If shadow stack is enabled, then the SSP of the task is located at the 4 bytes at offset 104 in the 32-bit TSS and is used by the processor to establish the SSP when a task switch occurs from a task associated with this TSS. Note that the processor does not write the SSP of the task initiating the task switch to the TSS of that task, and instead the SSP of the previous task is pushed onto the shadow stack of the new task. Note, per the SDM's pseudocode on TASK SWITCHING, IBT state for the new privilege level is updated. To keep things simple, check both S_CET and U_CET (again, anyone that wants more precise checking can have the honor of implementing support). Reported-by: Binbin Wu Closes: https://lore.kernel.org/all/819bd98b-2a60-4107-8e13-41f1e4c706b1@linux.intel.com Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-20-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0050509a7de2..31aaff9db083 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -12175,6 +12175,25 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index, struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt; int ret; + if (kvm_is_cr4_bit_set(vcpu, X86_CR4_CET)) { + u64 u_cet, s_cet; + + /* + * Check both User and Supervisor on task switches as inter- + * privilege level task switches are impacted by CET at both + * the current privilege level and the new privilege level, and + * that information is not known at this time. The expectation + * is that the guest won't require emulation of task switches + * while using IBT or Shadow Stacks. + */ + if (__kvm_emulate_msr_read(vcpu, MSR_IA32_U_CET, &u_cet) || + __kvm_emulate_msr_read(vcpu, MSR_IA32_S_CET, &s_cet)) + goto unhandled_task_switch; + + if ((u_cet | s_cet) & (CET_ENDBR_EN | CET_SHSTK_EN)) + goto unhandled_task_switch; + } + init_emulate_ctxt(vcpu); ret = emulator_task_switch(ctxt, tss_selector, idt_index, reason, @@ -12184,17 +12203,19 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index, * Report an error userspace if MMIO is needed, as KVM doesn't support * MMIO during a task switch (or any other complex operation). */ - if (ret || vcpu->mmio_needed) { - vcpu->mmio_needed = false; - vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; - vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; - vcpu->run->internal.ndata = 0; - return 0; - } + if (ret || vcpu->mmio_needed) + goto unhandled_task_switch; kvm_rip_write(vcpu, ctxt->eip); kvm_set_rflags(vcpu, ctxt->eflags); return 1; + +unhandled_task_switch: + vcpu->mmio_needed = false; + vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; + vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; + vcpu->run->internal.ndata = 0; + return 0; } EXPORT_SYMBOL_GPL(kvm_task_switch); From d4c03f63957c66bc95f5f33052f8b4be804631c3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:27 -0700 Subject: [PATCH 2014/2711] KVM: x86: Emulate SSP[63:32]!=0 #GP(0) for FAR JMP to 32-bit mode Emulate the Shadow Stack restriction that the current SSP must be a 32-bit value on a FAR JMP from 64-bit mode to compatibility mode. From the SDM's pseudocode for FAR JMP: IF ShadowStackEnabled(CPL) IF (IA32_EFER.LMA and DEST(segment selector).L) = 0 (* If target is legacy or compatibility mode then the SSP must be in low 4GB *) IF (SSP & 0xFFFFFFFF00000000 != 0); THEN #GP(0); FI; FI; FI; Note, only the current CPL needs to be considered, as FAR JMP can't be used for inter-privilege level transfers, and KVM rejects emulation of all other far branch instructions when Shadow Stacks are enabled. To give the emulator access to GUEST_SSP, special case handling MSR_KVM_INTERNAL_GUEST_SSP in emulator_get_msr() to treat the access as a host access (KVM doesn't allow guest accesses to internal "MSRs"). The ->get_msr() API is only used for implicit accesses from the emulator, i.e. is only used with hardcoded MSR indices, and so any access to MSR_KVM_INTERNAL_GUEST_SSP is guaranteed to be from KVM, i.e. not from the guest via RDMSR. Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-21-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/emulate.c | 35 +++++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 9 +++++++++ 2 files changed, 44 insertions(+) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 48b067b179e0..59f93f68718a 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1554,6 +1554,37 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, return linear_write_system(ctxt, addr, desc, sizeof(*desc)); } +static bool emulator_is_ssp_invalid(struct x86_emulate_ctxt *ctxt, u8 cpl) +{ + const u32 MSR_IA32_X_CET = cpl == 3 ? MSR_IA32_U_CET : MSR_IA32_S_CET; + u64 efer = 0, cet = 0, ssp = 0; + + if (!(ctxt->ops->get_cr(ctxt, 4) & X86_CR4_CET)) + return false; + + if (ctxt->ops->get_msr(ctxt, MSR_EFER, &efer)) + return true; + + /* SSP is guaranteed to be valid if the vCPU was already in 32-bit mode. */ + if (!(efer & EFER_LMA)) + return false; + + if (ctxt->ops->get_msr(ctxt, MSR_IA32_X_CET, &cet)) + return true; + + if (!(cet & CET_SHSTK_EN)) + return false; + + if (ctxt->ops->get_msr(ctxt, MSR_KVM_INTERNAL_GUEST_SSP, &ssp)) + return true; + + /* + * On transfer from 64-bit mode to compatibility mode, SSP[63:32] must + * be 0, i.e. SSP must be a 32-bit value outside of 64-bit mode. + */ + return ssp >> 32; +} + static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, u16 selector, int seg, u8 cpl, enum x86_transfer_type transfer, @@ -1694,6 +1725,10 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (efer & EFER_LMA) goto exception; } + if (!seg_desc.l && emulator_is_ssp_invalid(ctxt, cpl)) { + err_code = 0; + goto exception; + } /* CS(RPL) <- CPL */ selector = (selector & 0xfffc) | cpl; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 31aaff9db083..0a4e58dddf36 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8741,6 +8741,15 @@ static int emulator_set_msr_with_filter(struct x86_emulate_ctxt *ctxt, static int emulator_get_msr(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata) { + /* + * Treat emulator accesses to the current shadow stack pointer as host- + * initiated, as they aren't true MSR accesses (SSP is a "just a reg"), + * and this API is used only for implicit accesses, i.e. not RDMSR, and + * so the index is fully KVM-controlled. + */ + if (unlikely(msr_index == MSR_KVM_INTERNAL_GUEST_SSP)) + return kvm_msr_read(emul_to_vcpu(ctxt), msr_index, pdata); + return __kvm_emulate_msr_read(emul_to_vcpu(ctxt), msr_index, pdata); } From 296599346c671f31854d674db2891ff2e1654b6a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:28 -0700 Subject: [PATCH 2015/2711] KVM: x86/mmu: WARN on attempt to check permissions for Shadow Stack #PF Add PFERR_SS_MASK, a.k.a. Shadow Stack access, and WARN if KVM attempts to check permissions for a Shadow Stack access as KVM hasn't been taught to understand the magic Writable=0,Dirty=1 combination that is required for Shadow Stack accesses, and likely will never learn. There are no plans to support Shadow Stacks with the Shadow MMU, and the emulator rejects all instructions that affect Shadow Stacks, i.e. it should be impossible for KVM to observe a #PF due to a shadow stack access. Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-22-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/mmu.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 5865c9b77b6d..e8d74e949f91 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -267,6 +267,7 @@ enum x86_intercept_stage; #define PFERR_RSVD_MASK BIT(3) #define PFERR_FETCH_MASK BIT(4) #define PFERR_PK_MASK BIT(5) +#define PFERR_SS_MASK BIT(6) #define PFERR_SGX_MASK BIT(15) #define PFERR_GUEST_RMP_MASK BIT_ULL(31) #define PFERR_GUEST_FINAL_MASK BIT_ULL(32) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index b4b6860ab971..f63074048ec6 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -212,7 +212,7 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, fault = (mmu->permissions[index] >> pte_access) & 1; - WARN_ON(pfec & (PFERR_PK_MASK | PFERR_RSVD_MASK)); + WARN_ON_ONCE(pfec & (PFERR_PK_MASK | PFERR_SS_MASK | PFERR_RSVD_MASK)); if (unlikely(mmu->pkru_mask)) { u32 pkru_bits, offset; From 843af0f2e4617db197034b27a9a658a59271f19f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:29 -0700 Subject: [PATCH 2016/2711] KVM: x86/mmu: Pretty print PK, SS, and SGX flags in MMU tracepoints Add PK (Protection Keys), SS (Shadow Stacks), and SGX (Software Guard Extensions) to the set of #PF error flags handled via kvm_mmu_trace_pferr_flags. While KVM doesn't expect PK or SS #PFs in particular, pretty print their names instead of the raw hex value saves the user from having to go spelunking in the SDM to figure out what's going on. Reviewed-by: Xiaoyao Li Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-23-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/mmutrace.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kvm/mmu/mmutrace.h b/arch/x86/kvm/mmu/mmutrace.h index f35a830ce469..764e3015d021 100644 --- a/arch/x86/kvm/mmu/mmutrace.h +++ b/arch/x86/kvm/mmu/mmutrace.h @@ -51,6 +51,9 @@ { PFERR_PRESENT_MASK, "P" }, \ { PFERR_WRITE_MASK, "W" }, \ { PFERR_USER_MASK, "U" }, \ + { PFERR_PK_MASK, "PK" }, \ + { PFERR_SS_MASK, "SS" }, \ + { PFERR_SGX_MASK, "SGX" }, \ { PFERR_RSVD_MASK, "RSVD" }, \ { PFERR_FETCH_MASK, "F" } From b3744c59ebc5f2697d62844149c1a1c0e274ead0 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:30 -0700 Subject: [PATCH 2017/2711] KVM: x86: Allow setting CR4.CET if IBT or SHSTK is supported Drop X86_CR4_CET from CR4_RESERVED_BITS and instead mark CET as reserved if and only if IBT *and* SHSTK are unsupported, i.e. allow CR4.CET to be set if IBT or SHSTK is supported. This creates a virtualization hole if the CPU supports both IBT and SHSTK, but the kernel or vCPU model only supports one of the features. However, it's entirely legal for a CPU to have only one of IBT or SHSTK, i.e. the hole is a flaw in the architecture, not in KVM. More importantly, so long as KVM is careful to initialize and context switch both IBT and SHSTK state (when supported in hardware) if either feature is exposed to the guest, a misbehaving guest can only harm itself. E.g. VMX initializes host CET VMCS fields based solely on hardware capabilities. Signed-off-by: Yang Weijiang Signed-off-by: Mathias Krause Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao [sean: split to separate patch, write changelog] Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-24-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/x86.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index e8d74e949f91..2f14bdc859fd 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -142,7 +142,7 @@ | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \ | X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_VMXE \ | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP \ - | X86_CR4_LAM_SUP)) + | X86_CR4_LAM_SUP | X86_CR4_CET)) #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 65cbd454c4f1..f3dc77f006f9 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -680,6 +680,9 @@ static inline bool __kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) __reserved_bits |= X86_CR4_PCIDE; \ if (!__cpu_has(__c, X86_FEATURE_LAM)) \ __reserved_bits |= X86_CR4_LAM_SUP; \ + if (!__cpu_has(__c, X86_FEATURE_SHSTK) && \ + !__cpu_has(__c, X86_FEATURE_IBT)) \ + __reserved_bits |= X86_CR4_CET; \ __reserved_bits; \ }) From 19e6e083f3f9e4ac1794273d72dfb59d19a0fc69 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:31 -0700 Subject: [PATCH 2018/2711] KVM: nVMX: Always forward XSAVES/XRSTORS exits from L2 to L1 Unconditionally forward XSAVES/XRSTORS VM-Exits from L2 to L1, as KVM doesn't utilize the XSS-bitmap (KVM relies on controlling the XSS value in hardware to prevent unauthorized access to XSAVES state). KVM always loads vmcs02 with vmcs12's bitmap, and so any exit _must_ be due to vmcs12's XSS-bitmap. Drop the comment about XSS never being non-zero in anticipation of enabling CET_KERNEL and CET_USER support. Opportunistically WARN if XSAVES is not enabled for L2, as the CPU is supposed to generate #UD before checking the XSS-bitmap. Reviewed-by: Xiaoyao Li Reviewed-by: Chao Gao Link: https://lore.kernel.org/r/20250919223258.1604852-25-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/nested.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 2156c9a854f4..846c07380eac 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -6570,14 +6570,17 @@ static bool nested_vmx_l1_wants_exit(struct kvm_vcpu *vcpu, return nested_cpu_has2(vmcs12, SECONDARY_EXEC_WBINVD_EXITING); case EXIT_REASON_XSETBV: return true; - case EXIT_REASON_XSAVES: case EXIT_REASON_XRSTORS: + case EXIT_REASON_XSAVES: + case EXIT_REASON_XRSTORS: /* - * This should never happen, since it is not possible to - * set XSS to a non-zero value---neither in L1 nor in L2. - * If if it were, XSS would have to be checked against - * the XSS exit bitmap in vmcs12. + * Always forward XSAVES/XRSTORS to L1 as KVM doesn't utilize + * XSS-bitmap, and always loads vmcs02 with vmcs12's XSS-bitmap + * verbatim, i.e. any exit is due to L1's bitmap. WARN if + * XSAVES isn't enabled, as the CPU is supposed to inject #UD + * in that case, before consulting the XSS-bitmap. */ - return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_XSAVES); + WARN_ON_ONCE(!nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_XSAVES)); + return true; case EXIT_REASON_UMWAIT: case EXIT_REASON_TPAUSE: return nested_cpu_has2(vmcs12, From 69cc3e886582891f9c4d5830f18a2664a7f7cf7c Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:32 -0700 Subject: [PATCH 2019/2711] KVM: x86: Add XSS support for CET_KERNEL and CET_USER Add CET_KERNEL and CET_USER to KVM's set of supported XSS bits when IBT *or* SHSTK is supported. Like CR4.CET, XFEATURE support for IBT and SHSTK are bundle together under the CET umbrella, and thus prone to virtualization holes if KVM or the guest supports only one of IBT or SHSTK, but hardware supports both. However, again like CR4.CET, such virtualization holes are benign from the host's perspective so long as KVM takes care to always honor the "or" logic. Require CET_KERNEL and CET_USER to come as a pair, and refuse to support IBT or SHSTK if one (or both) features is missing, as the (host) kernel expects them to come as a pair, i.e. may get confused and corrupt state if only one of CET_KERNEL or CET_USER is supported. Signed-off-by: Yang Weijiang Signed-off-by: Mathias Krause Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao [sean: split to separate patch, write changelog, add XFEATURE_MASK_CET_ALL] Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-26-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0a4e58dddf36..8b4c69330a87 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -220,13 +220,14 @@ static struct kvm_user_return_msrs __percpu *user_return_msrs; | XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \ | XFEATURE_MASK_PKRU | XFEATURE_MASK_XTILE) +#define XFEATURE_MASK_CET_ALL (XFEATURE_MASK_CET_USER | XFEATURE_MASK_CET_KERNEL) /* * Note, KVM supports exposing PT to the guest, but does not support context * switching PT via XSTATE (KVM's PT virtualization relies on perf; swapping * PT via guest XSTATE would clobber perf state), i.e. KVM doesn't support * IA32_XSS[bit 8] (guests can/must use RDMSR/WRMSR to save/restore PT MSRs). */ -#define KVM_SUPPORTED_XSS 0 +#define KVM_SUPPORTED_XSS (XFEATURE_MASK_CET_ALL) bool __read_mostly allow_smaller_maxphyaddr = 0; EXPORT_SYMBOL_GPL(allow_smaller_maxphyaddr); @@ -10104,6 +10105,16 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES)) kvm_caps.supported_xss = 0; + if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK) && + !kvm_cpu_cap_has(X86_FEATURE_IBT)) + kvm_caps.supported_xss &= ~XFEATURE_MASK_CET_ALL; + + if ((kvm_caps.supported_xss & XFEATURE_MASK_CET_ALL) != XFEATURE_MASK_CET_ALL) { + kvm_cpu_cap_clear(X86_FEATURE_SHSTK); + kvm_cpu_cap_clear(X86_FEATURE_IBT); + kvm_caps.supported_xss &= ~XFEATURE_MASK_CET_ALL; + } + if (kvm_caps.has_tsc_control) { /* * Make sure the user can only configure tsc_khz values that @@ -12772,10 +12783,11 @@ static void kvm_xstate_reset(struct kvm_vcpu *vcpu, bool init_event) /* * On INIT, only select XSTATE components are zeroed, most components * are unchanged. Currently, the only components that are zeroed and - * supported by KVM are MPX related. + * supported by KVM are MPX and CET related. */ xfeatures_mask = (kvm_caps.supported_xcr0 | kvm_caps.supported_xss) & - (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); + (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR | + XFEATURE_MASK_CET_ALL); if (!xfeatures_mask) return; From 1f6f68fcfe43cf26fc0a98fe14e0454cc5c75416 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:33 -0700 Subject: [PATCH 2020/2711] KVM: x86: Disable support for Shadow Stacks if TDP is disabled Make TDP a hard requirement for Shadow Stacks, as there are no plans to add Shadow Stack support to the Shadow MMU. E.g. KVM hasn't been taught to understand the magic Writable=0,Dirty=1 combination that is required for Shadow Stack accesses, and so enabling Shadow Stacks when using shadow paging will put the guest into an infinite #PF loop (KVM thinks the shadow page tables have a valid mapping, hardware says otherwise). Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-27-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/cpuid.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 32fde9e80c28..499c86bd457e 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -955,6 +955,14 @@ void kvm_set_cpu_caps(void) if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE)) kvm_cpu_cap_clear(X86_FEATURE_PKU); + /* + * Shadow Stacks aren't implemented in the Shadow MMU. Shadow Stack + * accesses require "magic" Writable=0,Dirty=1 protection, which KVM + * doesn't know how to emulate or map. + */ + if (!tdp_enabled) + kvm_cpu_cap_clear(X86_FEATURE_SHSTK); + kvm_cpu_cap_init(CPUID_7_EDX, F(AVX512_4VNNIW), F(AVX512_4FMAPS), From f705de12a22c945f55d51baec4ea495aedc5ebd7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 22 Sep 2025 11:47:43 -0700 Subject: [PATCH 2021/2711] KVM: x86: Initialize allow_smaller_maxphyaddr earlier in setup Initialize allow_smaller_maxphyaddr during hardware setup as soon as KVM knows whether or not TDP will be utilized. To avoid having to teach KVM's emulator all about CET, KVM's upcoming CET virtualization support will be mutually exclusive with allow_smaller_maxphyaddr, i.e. will disable SHSTK and IBT if allow_smaller_maxphyaddr is enabled. In general, allow_smaller_maxphyaddr should be initialized as soon as possible since it's globally visible while its only input is whether or not EPT/NPT is enabled. I.e. there's effectively zero risk of setting allow_smaller_maxphyaddr too early, and substantial risk of setting it too late. Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250922184743.1745778-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 30 +++++++++++++++--------------- arch/x86/kvm/vmx/vmx.c | 16 ++++++++-------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index d092102fe1cb..d20e5917b0fe 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5370,6 +5370,21 @@ static __init int svm_hardware_setup(void) get_npt_level(), PG_LEVEL_1G); pr_info("Nested Paging %s\n", str_enabled_disabled(npt_enabled)); + /* + * It seems that on AMD processors PTE's accessed bit is + * being set by the CPU hardware before the NPF vmexit. + * This is not expected behaviour and our tests fail because + * of it. + * A workaround here is to disable support for + * GUEST_MAXPHYADDR < HOST_MAXPHYADDR if NPT is enabled. + * In this case userspace can know if there is support using + * KVM_CAP_SMALLER_MAXPHYADDR extension and decide how to handle + * it + * If future AMD CPU models change the behaviour described above, + * this variable can be changed accordingly + */ + allow_smaller_maxphyaddr = !npt_enabled; + /* Setup shadow_me_value and shadow_me_mask */ kvm_mmu_set_me_spte_mask(sme_me_mask, sme_me_mask); @@ -5449,21 +5464,6 @@ static __init int svm_hardware_setup(void) svm_set_cpu_caps(); - /* - * It seems that on AMD processors PTE's accessed bit is - * being set by the CPU hardware before the NPF vmexit. - * This is not expected behaviour and our tests fail because - * of it. - * A workaround here is to disable support for - * GUEST_MAXPHYADDR < HOST_MAXPHYADDR if NPT is enabled. - * In this case userspace can know if there is support using - * KVM_CAP_SMALLER_MAXPHYADDR extension and decide how to handle - * it - * If future AMD CPU models change the behaviour described above, - * this variable can be changed accordingly - */ - allow_smaller_maxphyaddr = !npt_enabled; - kvm_caps.inapplicable_quirks &= ~KVM_X86_QUIRK_CD_NW_CLEARED; return 0; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 4ab066a3c22f..4d775983506e 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8436,6 +8436,14 @@ __init int vmx_hardware_setup(void) return -EOPNOTSUPP; } + /* + * Shadow paging doesn't have a (further) performance penalty + * from GUEST_MAXPHYADDR < HOST_MAXPHYADDR so enable it + * by default + */ + if (!enable_ept) + allow_smaller_maxphyaddr = true; + if (!cpu_has_vmx_ept_ad_bits() || !enable_ept) enable_ept_ad_bits = 0; @@ -8665,14 +8673,6 @@ int __init vmx_init(void) vmx_check_vmcs12_offsets(); - /* - * Shadow paging doesn't have a (further) performance penalty - * from GUEST_MAXPHYADDR < HOST_MAXPHYADDR so enable it - * by default - */ - if (!enable_ept) - allow_smaller_maxphyaddr = true; - return 0; err_l1d_flush: From 343acdd158a55dab1cfb0d209cd1d70b0cabb8b2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:34 -0700 Subject: [PATCH 2022/2711] KVM: x86: Disable support for IBT and SHSTK if allow_smaller_maxphyaddr is true Make IBT and SHSTK virtualization mutually exclusive with "officially" supporting setups with guest.MAXPHYADDR < host.MAXPHYADDR, i.e. if the allow_smaller_maxphyaddr module param is set. Running a guest with a smaller MAXPHYADDR requires intercepting #PF, and can also trigger emulation of arbitrary instructions. Intercepting and reacting to #PFs doesn't play nice with SHSTK, as KVM's MMU hasn't been taught to handle Shadow Stack accesses, and emulating arbitrary instructions doesn't play nice with IBT or SHSTK, as KVM's emulator doesn't handle the various side effects, e.g. doesn't enforce end-branch markers or model Shadow Stack updates. Note, hiding IBT and SHSTK based solely on allow_smaller_maxphyaddr is overkill, as allow_smaller_maxphyaddr is only problematic if the guest is actually configured to have a smaller MAXPHYADDR. However, KVM's ABI doesn't provide a way to express that IBT and SHSTK may break if enabled in conjunction with guest.MAXPHYADDR < host.MAXPHYADDR. I.e. the alternative is to do nothing in KVM and instead update documentation and hope KVM users are thorough readers. Go with the conservative-but-correct approach; worst case scenario, this restriction can be dropped if there's a strong use case for enabling CET on hosts with allow_smaller_maxphyaddr. Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-28-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/cpuid.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 499c86bd457e..b0731304bd79 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -982,6 +982,16 @@ void kvm_set_cpu_caps(void) F(FLUSH_L1D), ); + /* + * Disable support for IBT and SHSTK if KVM is configured to emulate + * accesses to reserved GPAs, as KVM's emulator doesn't support IBT or + * SHSTK, nor does KVM handle Shadow Stack #PFs (see above). + */ + if (allow_smaller_maxphyaddr) { + kvm_cpu_cap_clear(X86_FEATURE_SHSTK); + kvm_cpu_cap_clear(X86_FEATURE_IBT); + } + if (boot_cpu_has(X86_FEATURE_AMD_IBPB_RET) && boot_cpu_has(X86_FEATURE_AMD_IBPB) && boot_cpu_has(X86_FEATURE_AMD_IBRS)) From e140467bbdafff84f1f346a7c59f404cd9782b82 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:35 -0700 Subject: [PATCH 2023/2711] KVM: x86: Enable CET virtualization for VMX and advertise to userspace Add support for the LOAD_CET_STATE VM-Enter and VM-Exit controls, the CET XFEATURE bits in XSS, and advertise support for IBT and SHSTK to userspace. Explicitly clear IBT and SHSTK onn SVM, as additional work is needed to enable CET on SVM, e.g. to context switch S_CET and other state. Disable KVM CET feature if unrestricted_guest is unsupported/disabled as KVM does not support emulating CET, as running without Unrestricted Guest can result in KVM emulating large swaths of guest code. While it's highly unlikely any guest will trigger emulation while also utilizing IBT or SHSTK, there's zero reason to allow CET without Unrestricted Guest as that combination should only be possible when explicitly disabling unrestricted_guest for testing purposes. Disable CET if VMX_BASIC[bit56] == 0, i.e. if hardware strictly enforces the presence of an Error Code based on exception vector, as attempting to inject a #CP with an Error Code (#CP architecturally has an Error Code) will fail due to the #CP vector historically not having an Error Code. Clear S_CET and SSP-related VMCS on "reset" to emulate the architectural of CET MSRs and SSP being reset to 0 after RESET, power-up and INIT. Note, KVM already clears guest CET state that is managed via XSTATE in kvm_xstate_reset(). Signed-off-by: Yang Weijiang Signed-off-by: Mathias Krause Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao [sean: move some bits to separate patches, massage changelog] Reviewed-by: Binbin Wu Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250919223258.1604852-29-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/vmx.h | 1 + arch/x86/kvm/cpuid.c | 2 ++ arch/x86/kvm/svm/svm.c | 4 ++++ arch/x86/kvm/vmx/capabilities.h | 5 +++++ arch/x86/kvm/vmx/vmx.c | 30 +++++++++++++++++++++++++++++- arch/x86/kvm/vmx/vmx.h | 6 ++++-- 6 files changed, 45 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index ce10a7e2d3d9..c85c50019523 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -134,6 +134,7 @@ #define VMX_BASIC_DUAL_MONITOR_TREATMENT BIT_ULL(49) #define VMX_BASIC_INOUT BIT_ULL(54) #define VMX_BASIC_TRUE_CTLS BIT_ULL(55) +#define VMX_BASIC_NO_HW_ERROR_CODE_CC BIT_ULL(56) static inline u32 vmx_basic_vmcs_revision_id(u64 vmx_basic) { diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index b0731304bd79..d290dbc96831 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -946,6 +946,7 @@ void kvm_set_cpu_caps(void) VENDOR_F(WAITPKG), F(SGX_LC), F(BUS_LOCK_DETECT), + X86_64_F(SHSTK), ); /* @@ -980,6 +981,7 @@ void kvm_set_cpu_caps(void) F(AMX_INT8), F(AMX_BF16), F(FLUSH_L1D), + F(IBT), ); /* diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index d20e5917b0fe..ff4925a7bf96 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5222,6 +5222,10 @@ static __init void svm_set_cpu_caps(void) kvm_caps.supported_perf_cap = 0; kvm_caps.supported_xss = 0; + /* KVM doesn't yet support CET virtualization for SVM. */ + kvm_cpu_cap_clear(X86_FEATURE_SHSTK); + kvm_cpu_cap_clear(X86_FEATURE_IBT); + /* CPUID 0x80000001 and 0x8000000A (SVM features) */ if (nested) { kvm_cpu_cap_set(X86_FEATURE_SVM); diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h index 59c83888bdc0..02aadb9d730e 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -73,6 +73,11 @@ static inline bool cpu_has_vmx_basic_inout(void) return vmcs_config.basic & VMX_BASIC_INOUT; } +static inline bool cpu_has_vmx_basic_no_hw_errcode_cc(void) +{ + return vmcs_config.basic & VMX_BASIC_NO_HW_ERROR_CODE_CC; +} + static inline bool cpu_has_virtual_nmis(void) { return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS && diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 4d775983506e..dfa6c5cd2d5c 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2602,6 +2602,7 @@ static int setup_vmcs_config(struct vmcs_config *vmcs_conf, { VM_ENTRY_LOAD_IA32_EFER, VM_EXIT_LOAD_IA32_EFER }, { VM_ENTRY_LOAD_BNDCFGS, VM_EXIT_CLEAR_BNDCFGS }, { VM_ENTRY_LOAD_IA32_RTIT_CTL, VM_EXIT_CLEAR_IA32_RTIT_CTL }, + { VM_ENTRY_LOAD_CET_STATE, VM_EXIT_LOAD_CET_STATE }, }; memset(vmcs_conf, 0, sizeof(*vmcs_conf)); @@ -4868,6 +4869,14 @@ void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ + if (kvm_cpu_cap_has(X86_FEATURE_SHSTK)) { + vmcs_writel(GUEST_SSP, 0); + vmcs_writel(GUEST_INTR_SSP_TABLE, 0); + } + if (kvm_cpu_cap_has(X86_FEATURE_IBT) || + kvm_cpu_cap_has(X86_FEATURE_SHSTK)) + vmcs_writel(GUEST_S_CET, 0); + kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu); vpid_sync_context(vmx->vpid); @@ -6335,6 +6344,10 @@ void dump_vmcs(struct kvm_vcpu *vcpu) if (vmcs_read32(VM_EXIT_MSR_STORE_COUNT) > 0) vmx_dump_msrs("guest autostore", &vmx->msr_autostore.guest); + if (vmentry_ctl & VM_ENTRY_LOAD_CET_STATE) + pr_err("S_CET = 0x%016lx, SSP = 0x%016lx, SSP TABLE = 0x%016lx\n", + vmcs_readl(GUEST_S_CET), vmcs_readl(GUEST_SSP), + vmcs_readl(GUEST_INTR_SSP_TABLE)); pr_err("*** Host State ***\n"); pr_err("RIP = 0x%016lx RSP = 0x%016lx\n", vmcs_readl(HOST_RIP), vmcs_readl(HOST_RSP)); @@ -6365,6 +6378,10 @@ void dump_vmcs(struct kvm_vcpu *vcpu) vmcs_read64(HOST_IA32_PERF_GLOBAL_CTRL)); if (vmcs_read32(VM_EXIT_MSR_LOAD_COUNT) > 0) vmx_dump_msrs("host autoload", &vmx->msr_autoload.host); + if (vmexit_ctl & VM_EXIT_LOAD_CET_STATE) + pr_err("S_CET = 0x%016lx, SSP = 0x%016lx, SSP TABLE = 0x%016lx\n", + vmcs_readl(HOST_S_CET), vmcs_readl(HOST_SSP), + vmcs_readl(HOST_INTR_SSP_TABLE)); pr_err("*** Control State ***\n"); pr_err("CPUBased=0x%08x SecondaryExec=0x%08x TertiaryExec=0x%016llx\n", @@ -7946,7 +7963,6 @@ static __init void vmx_set_cpu_caps(void) kvm_cpu_cap_set(X86_FEATURE_UMIP); /* CPUID 0xD.1 */ - kvm_caps.supported_xss = 0; if (!cpu_has_vmx_xsaves()) kvm_cpu_cap_clear(X86_FEATURE_XSAVES); @@ -7958,6 +7974,18 @@ static __init void vmx_set_cpu_caps(void) if (cpu_has_vmx_waitpkg()) kvm_cpu_cap_check_and_set(X86_FEATURE_WAITPKG); + + /* + * Disable CET if unrestricted_guest is unsupported as KVM doesn't + * enforce CET HW behaviors in emulator. On platforms with + * VMX_BASIC[bit56] == 0, inject #CP at VMX entry with error code + * fails, so disable CET in this case too. + */ + if (!cpu_has_load_cet_ctrl() || !enable_unrestricted_guest || + !cpu_has_vmx_basic_no_hw_errcode_cc()) { + kvm_cpu_cap_clear(X86_FEATURE_SHSTK); + kvm_cpu_cap_clear(X86_FEATURE_IBT); + } } static bool vmx_is_io_intercepted(struct kvm_vcpu *vcpu, diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 23d6e89b96f2..af8224e074ee 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -484,7 +484,8 @@ static inline u8 vmx_get_rvi(void) VM_ENTRY_LOAD_IA32_EFER | \ VM_ENTRY_LOAD_BNDCFGS | \ VM_ENTRY_PT_CONCEAL_PIP | \ - VM_ENTRY_LOAD_IA32_RTIT_CTL) + VM_ENTRY_LOAD_IA32_RTIT_CTL | \ + VM_ENTRY_LOAD_CET_STATE) #define __KVM_REQUIRED_VMX_VM_EXIT_CONTROLS \ (VM_EXIT_SAVE_DEBUG_CONTROLS | \ @@ -506,7 +507,8 @@ static inline u8 vmx_get_rvi(void) VM_EXIT_LOAD_IA32_EFER | \ VM_EXIT_CLEAR_BNDCFGS | \ VM_EXIT_PT_CONCEAL_PIP | \ - VM_EXIT_CLEAR_IA32_RTIT_CTL) + VM_EXIT_CLEAR_IA32_RTIT_CTL | \ + VM_EXIT_LOAD_CET_STATE) #define KVM_REQUIRED_VMX_PIN_BASED_VM_EXEC_CONTROL \ (PIN_BASED_EXT_INTR_MASK | \ From f7336d47be53d0da1e74143b8befea8c0176f3cc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:36 -0700 Subject: [PATCH 2024/2711] KVM: VMX: Configure nested capabilities after CPU capabilities Swap the order between configuring nested VMX capabilities and base CPU capabilities, so that nested VMX support can be conditioned on core KVM support, e.g. to allow conditioning support for LOAD_CET_STATE on the presence of IBT or SHSTK. Because the sanity checks on nested VMX config performed by vmx_check_processor_compat() run _after_ vmx_hardware_setup(), any use of kvm_cpu_cap_has() when configuring nested VMX support will lead to failures in vmx_check_processor_compat(). While swapping the order of two (or more) configuration flows can lead to a game of whack-a-mole, in this case nested support inarguably should be done after base support. KVM should never condition base support on nested support, because nested support is fully optional, while obviously it's desirable to condition nested support on base support. And there's zero evidence the current ordering was intentional, e.g. commit 66a6950f9995 ("KVM: x86: Introduce kvm_cpu_caps to replace runtime CPUID masking") likely placed the call to kvm_set_cpu_caps() after nested setup because it looked pretty. Reviewed-by: Chao Gao Link: https://lore.kernel.org/r/20250919223258.1604852-30-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index dfa6c5cd2d5c..c4b07124689d 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8597,6 +8597,13 @@ __init int vmx_hardware_setup(void) setup_default_sgx_lepubkeyhash(); + vmx_set_cpu_caps(); + + /* + * Configure nested capabilities after core CPU capabilities so that + * nested support can be conditional on base support, e.g. so that KVM + * can hide/show features based on kvm_cpu_cap_has(). + */ if (nested) { nested_vmx_setup_ctls_msrs(&vmcs_config, vmx_capability.ept); @@ -8605,8 +8612,6 @@ __init int vmx_hardware_setup(void) return r; } - vmx_set_cpu_caps(); - r = alloc_kvm_area(); if (r && nested) nested_vmx_hardware_unsetup(); From 033cc166f02920b193f7ec989083bce1a20e9abf Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:37 -0700 Subject: [PATCH 2025/2711] KVM: nVMX: Virtualize NO_HW_ERROR_CODE_CC for L1 event injection to L2 Per SDM description(Vol.3D, Appendix A.1): "If bit 56 is read as 1, software can use VM entry to deliver a hardware exception with or without an error code, regardless of vector" Modify has_error_code check before inject events to nested guest. Only enforce the check when guest is in real mode, the exception is not hard exception and the platform doesn't enumerate bit56 in VMX_BASIC, in all other case ignore the check to make the logic consistent with SDM. Signed-off-by: Yang Weijiang Reviewed-by: Maxim Levitsky Reviewed-by: Chao Gao Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-31-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/nested.c | 27 ++++++++++++++++++--------- arch/x86/kvm/vmx/nested.h | 5 +++++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 846c07380eac..b644f4599f70 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -1272,9 +1272,10 @@ static int vmx_restore_vmx_basic(struct vcpu_vmx *vmx, u64 data) { const u64 feature_bits = VMX_BASIC_DUAL_MONITOR_TREATMENT | VMX_BASIC_INOUT | - VMX_BASIC_TRUE_CTLS; + VMX_BASIC_TRUE_CTLS | + VMX_BASIC_NO_HW_ERROR_CODE_CC; - const u64 reserved_bits = GENMASK_ULL(63, 56) | + const u64 reserved_bits = GENMASK_ULL(63, 57) | GENMASK_ULL(47, 45) | BIT_ULL(31); @@ -2949,7 +2950,6 @@ static int nested_check_vm_entry_controls(struct kvm_vcpu *vcpu, u8 vector = intr_info & INTR_INFO_VECTOR_MASK; u32 intr_type = intr_info & INTR_INFO_INTR_TYPE_MASK; bool has_error_code = intr_info & INTR_INFO_DELIVER_CODE_MASK; - bool should_have_error_code; bool urg = nested_cpu_has2(vmcs12, SECONDARY_EXEC_UNRESTRICTED_GUEST); bool prot_mode = !urg || vmcs12->guest_cr0 & X86_CR0_PE; @@ -2966,12 +2966,19 @@ static int nested_check_vm_entry_controls(struct kvm_vcpu *vcpu, CC(intr_type == INTR_TYPE_OTHER_EVENT && vector != 0)) return -EINVAL; - /* VM-entry interruption-info field: deliver error code */ - should_have_error_code = - intr_type == INTR_TYPE_HARD_EXCEPTION && prot_mode && - x86_exception_has_error_code(vector); - if (CC(has_error_code != should_have_error_code)) - return -EINVAL; + /* + * Cannot deliver error code in real mode or if the interrupt + * type is not hardware exception. For other cases, do the + * consistency check only if the vCPU doesn't enumerate + * VMX_BASIC_NO_HW_ERROR_CODE_CC. + */ + if (!prot_mode || intr_type != INTR_TYPE_HARD_EXCEPTION) { + if (CC(has_error_code)) + return -EINVAL; + } else if (!nested_cpu_has_no_hw_errcode_cc(vcpu)) { + if (CC(has_error_code != x86_exception_has_error_code(vector))) + return -EINVAL; + } /* VM-entry exception error code */ if (CC(has_error_code && @@ -7217,6 +7224,8 @@ static void nested_vmx_setup_basic(struct nested_vmx_msrs *msrs) msrs->basic |= VMX_BASIC_TRUE_CTLS; if (cpu_has_vmx_basic_inout()) msrs->basic |= VMX_BASIC_INOUT; + if (cpu_has_vmx_basic_no_hw_errcode_cc()) + msrs->basic |= VMX_BASIC_NO_HW_ERROR_CODE_CC; } static void nested_vmx_setup_cr_fixed(struct nested_vmx_msrs *msrs) diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index 6eedcfc91070..983484d42ebf 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -309,6 +309,11 @@ static inline bool nested_cr4_valid(struct kvm_vcpu *vcpu, unsigned long val) __kvm_is_valid_cr4(vcpu, val); } +static inline bool nested_cpu_has_no_hw_errcode_cc(struct kvm_vcpu *vcpu) +{ + return to_vmx(vcpu)->nested.msrs.basic & VMX_BASIC_NO_HW_ERROR_CODE_CC; +} + /* No difference in the restrictions on guest and host CR4 in VMX operation. */ #define nested_guest_cr4_valid nested_cr4_valid #define nested_host_cr4_valid nested_cr4_valid From 625884996bff1b25a39834fa4935d695d71ef1b1 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Fri, 19 Sep 2025 15:32:38 -0700 Subject: [PATCH 2026/2711] KVM: nVMX: Prepare for enabling CET support for nested guest Set up CET MSRs, related VM_ENTRY/EXIT control bits and fixed CR4 setting to enable CET for nested VM. vmcs12 and vmcs02 needs to be synced when L2 exits to L1 or when L1 wants to resume L2, that way correct CET states can be observed by one another. Please note that consistency checks regarding CET state during VM-Entry will be added later to prevent this patch from becoming too large. Advertising the new CET VM_ENTRY/EXIT control bits are also be deferred until after the consistency checks are added. Signed-off-by: Yang Weijiang Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Xin Li (Intel) Tested-by: Xin Li (Intel) Link: https://lore.kernel.org/r/20250919223258.1604852-32-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/nested.c | 77 +++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/vmx/vmcs12.c | 6 +++ arch/x86/kvm/vmx/vmcs12.h | 14 ++++++- arch/x86/kvm/vmx/vmx.c | 2 + arch/x86/kvm/vmx/vmx.h | 3 ++ 5 files changed, 101 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index b644f4599f70..11e5d3569933 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -721,6 +721,24 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu, nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0, MSR_IA32_MPERF, MSR_TYPE_R); + nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0, + MSR_IA32_U_CET, MSR_TYPE_RW); + + nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0, + MSR_IA32_S_CET, MSR_TYPE_RW); + + nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0, + MSR_IA32_PL0_SSP, MSR_TYPE_RW); + + nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0, + MSR_IA32_PL1_SSP, MSR_TYPE_RW); + + nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0, + MSR_IA32_PL2_SSP, MSR_TYPE_RW); + + nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0, + MSR_IA32_PL3_SSP, MSR_TYPE_RW); + kvm_vcpu_unmap(vcpu, &map); vmx->nested.force_msr_bitmap_recalc = false; @@ -2521,6 +2539,32 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0 } } +static void vmcs_read_cet_state(struct kvm_vcpu *vcpu, u64 *s_cet, + u64 *ssp, u64 *ssp_tbl) +{ + if (guest_cpu_cap_has(vcpu, X86_FEATURE_IBT) || + guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) + *s_cet = vmcs_readl(GUEST_S_CET); + + if (guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) { + *ssp = vmcs_readl(GUEST_SSP); + *ssp_tbl = vmcs_readl(GUEST_INTR_SSP_TABLE); + } +} + +static void vmcs_write_cet_state(struct kvm_vcpu *vcpu, u64 s_cet, + u64 ssp, u64 ssp_tbl) +{ + if (guest_cpu_cap_has(vcpu, X86_FEATURE_IBT) || + guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) + vmcs_writel(GUEST_S_CET, s_cet); + + if (guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) { + vmcs_writel(GUEST_SSP, ssp); + vmcs_writel(GUEST_INTR_SSP_TABLE, ssp_tbl); + } +} + static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) { struct hv_enlightened_vmcs *hv_evmcs = nested_vmx_evmcs(vmx); @@ -2637,6 +2681,10 @@ static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr); vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr); + if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_CET_STATE) + vmcs_write_cet_state(&vmx->vcpu, vmcs12->guest_s_cet, + vmcs12->guest_ssp, vmcs12->guest_ssp_tbl); + set_cr4_guest_host_mask(vmx); } @@ -2676,6 +2724,13 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, kvm_set_dr(vcpu, 7, vcpu->arch.dr7); vmx_guest_debugctl_write(vcpu, vmx->nested.pre_vmenter_debugctl); } + + if (!vmx->nested.nested_run_pending || + !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_CET_STATE)) + vmcs_write_cet_state(vcpu, vmx->nested.pre_vmenter_s_cet, + vmx->nested.pre_vmenter_ssp, + vmx->nested.pre_vmenter_ssp_tbl); + if (kvm_mpx_supported() && (!vmx->nested.nested_run_pending || !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS))) vmcs_write64(GUEST_BNDCFGS, vmx->nested.pre_vmenter_bndcfgs); @@ -3551,6 +3606,12 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS))) vmx->nested.pre_vmenter_bndcfgs = vmcs_read64(GUEST_BNDCFGS); + if (!vmx->nested.nested_run_pending || + !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_CET_STATE)) + vmcs_read_cet_state(vcpu, &vmx->nested.pre_vmenter_s_cet, + &vmx->nested.pre_vmenter_ssp, + &vmx->nested.pre_vmenter_ssp_tbl); + /* * Overwrite vmcs01.GUEST_CR3 with L1's CR3 if EPT is disabled *and* * nested early checks are disabled. In the event of a "late" VM-Fail, @@ -4634,6 +4695,10 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_IA32_EFER) vmcs12->guest_ia32_efer = vcpu->arch.efer; + + vmcs_read_cet_state(&vmx->vcpu, &vmcs12->guest_s_cet, + &vmcs12->guest_ssp, + &vmcs12->guest_ssp_tbl); } /* @@ -4759,6 +4824,18 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, if (vmcs12->vm_exit_controls & VM_EXIT_CLEAR_BNDCFGS) vmcs_write64(GUEST_BNDCFGS, 0); + /* + * Load CET state from host state if VM_EXIT_LOAD_CET_STATE is set. + * otherwise CET state should be retained across VM-exit, i.e., + * guest values should be propagated from vmcs12 to vmcs01. + */ + if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_CET_STATE) + vmcs_write_cet_state(vcpu, vmcs12->host_s_cet, vmcs12->host_ssp, + vmcs12->host_ssp_tbl); + else + vmcs_write_cet_state(vcpu, vmcs12->guest_s_cet, vmcs12->guest_ssp, + vmcs12->guest_ssp_tbl); + if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT) { vmcs_write64(GUEST_IA32_PAT, vmcs12->host_ia32_pat); vcpu->arch.pat = vmcs12->host_ia32_pat; diff --git a/arch/x86/kvm/vmx/vmcs12.c b/arch/x86/kvm/vmx/vmcs12.c index 106a72c923ca..4233b5ca9461 100644 --- a/arch/x86/kvm/vmx/vmcs12.c +++ b/arch/x86/kvm/vmx/vmcs12.c @@ -139,6 +139,9 @@ const unsigned short vmcs12_field_offsets[] = { FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions), FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp), FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip), + FIELD(GUEST_S_CET, guest_s_cet), + FIELD(GUEST_SSP, guest_ssp), + FIELD(GUEST_INTR_SSP_TABLE, guest_ssp_tbl), FIELD(HOST_CR0, host_cr0), FIELD(HOST_CR3, host_cr3), FIELD(HOST_CR4, host_cr4), @@ -151,5 +154,8 @@ const unsigned short vmcs12_field_offsets[] = { FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip), FIELD(HOST_RSP, host_rsp), FIELD(HOST_RIP, host_rip), + FIELD(HOST_S_CET, host_s_cet), + FIELD(HOST_SSP, host_ssp), + FIELD(HOST_INTR_SSP_TABLE, host_ssp_tbl), }; const unsigned int nr_vmcs12_fields = ARRAY_SIZE(vmcs12_field_offsets); diff --git a/arch/x86/kvm/vmx/vmcs12.h b/arch/x86/kvm/vmx/vmcs12.h index 56fd150a6f24..4ad6b16525b9 100644 --- a/arch/x86/kvm/vmx/vmcs12.h +++ b/arch/x86/kvm/vmx/vmcs12.h @@ -117,7 +117,13 @@ struct __packed vmcs12 { natural_width host_ia32_sysenter_eip; natural_width host_rsp; natural_width host_rip; - natural_width paddingl[8]; /* room for future expansion */ + natural_width host_s_cet; + natural_width host_ssp; + natural_width host_ssp_tbl; + natural_width guest_s_cet; + natural_width guest_ssp; + natural_width guest_ssp_tbl; + natural_width paddingl[2]; /* room for future expansion */ u32 pin_based_vm_exec_control; u32 cpu_based_vm_exec_control; u32 exception_bitmap; @@ -294,6 +300,12 @@ static inline void vmx_check_vmcs12_offsets(void) CHECK_OFFSET(host_ia32_sysenter_eip, 656); CHECK_OFFSET(host_rsp, 664); CHECK_OFFSET(host_rip, 672); + CHECK_OFFSET(host_s_cet, 680); + CHECK_OFFSET(host_ssp, 688); + CHECK_OFFSET(host_ssp_tbl, 696); + CHECK_OFFSET(guest_s_cet, 704); + CHECK_OFFSET(guest_ssp, 712); + CHECK_OFFSET(guest_ssp_tbl, 720); CHECK_OFFSET(pin_based_vm_exec_control, 744); CHECK_OFFSET(cpu_based_vm_exec_control, 748); CHECK_OFFSET(exception_bitmap, 752); diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index c4b07124689d..ad5981ff7097 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7735,6 +7735,8 @@ static void nested_vmx_cr_fixed1_bits_update(struct kvm_vcpu *vcpu) cr4_fixed1_update(X86_CR4_PKE, ecx, feature_bit(PKU)); cr4_fixed1_update(X86_CR4_UMIP, ecx, feature_bit(UMIP)); cr4_fixed1_update(X86_CR4_LA57, ecx, feature_bit(LA57)); + cr4_fixed1_update(X86_CR4_CET, ecx, feature_bit(SHSTK)); + cr4_fixed1_update(X86_CR4_CET, edx, feature_bit(IBT)); entry = kvm_find_cpuid_entry_index(vcpu, 0x7, 1); cr4_fixed1_update(X86_CR4_LAM_SUP, eax, feature_bit(LAM)); diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index af8224e074ee..ea93121029f9 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -181,6 +181,9 @@ struct nested_vmx { */ u64 pre_vmenter_debugctl; u64 pre_vmenter_bndcfgs; + u64 pre_vmenter_s_cet; + u64 pre_vmenter_ssp; + u64 pre_vmenter_ssp_tbl; /* to migrate it to L1 if L2 writes to L1's CR8 directly */ int l1_tpr_threshold; From 8060b2bd2dd05a19ad7ec248489d374f2bd2b057 Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Fri, 19 Sep 2025 15:32:39 -0700 Subject: [PATCH 2027/2711] KVM: nVMX: Add consistency checks for CR0.WP and CR4.CET Add consistency checks for CR4.CET and CR0.WP in guest-state or host-state area in the VMCS12. This ensures that configurations with CR4.CET set and CR0.WP not set result in VM-entry failure, aligning with architectural behavior. Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-33-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/nested.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 11e5d3569933..51c50ce9e011 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -3110,6 +3110,9 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu, CC(!kvm_vcpu_is_legal_cr3(vcpu, vmcs12->host_cr3))) return -EINVAL; + if (CC(vmcs12->host_cr4 & X86_CR4_CET && !(vmcs12->host_cr0 & X86_CR0_WP))) + return -EINVAL; + if (CC(is_noncanonical_msr_address(vmcs12->host_ia32_sysenter_esp, vcpu)) || CC(is_noncanonical_msr_address(vmcs12->host_ia32_sysenter_eip, vcpu))) return -EINVAL; @@ -3224,6 +3227,9 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu, CC(!nested_guest_cr4_valid(vcpu, vmcs12->guest_cr4))) return -EINVAL; + if (CC(vmcs12->guest_cr4 & X86_CR4_CET && !(vmcs12->guest_cr0 & X86_CR0_WP))) + return -EINVAL; + if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) && (CC(!kvm_dr7_valid(vmcs12->guest_dr7)) || CC(!vmx_is_valid_debugctl(vcpu, vmcs12->guest_ia32_debugctl, false)))) From 62f7533a6b3aad9d39c6098dbc3d8e7daeda9399 Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Fri, 19 Sep 2025 15:32:40 -0700 Subject: [PATCH 2028/2711] KVM: nVMX: Add consistency checks for CET states Introduce consistency checks for CET states during nested VM-entry. A VMCS contains both guest and host CET states, each comprising the IA32_S_CET MSR, SSP, and IA32_INTERRUPT_SSP_TABLE_ADDR MSR. Various checks are applied to CET states during VM-entry as documented in SDM Vol3 Chapter "VM ENTRIES". Implement all these checks during nested VM-entry to emulate the architectural behavior. In summary, there are three kinds of checks on guest/host CET states during VM-entry: A. Checks applied to both guest states and host states: * The IA32_S_CET field must not set any reserved bits; bits 10 (SUPPRESS) and 11 (TRACKER) cannot both be set. * SSP should not have bits 1:0 set. * The IA32_INTERRUPT_SSP_TABLE_ADDR field must be canonical. B. Checks applied to host states only * IA32_S_CET MSR and SSP must be canonical if the CPU enters 64-bit mode after VM-exit. Otherwise, IA32_S_CET and SSP must have their higher 32 bits cleared. C. Checks applied to guest states only: * IA32_S_CET MSR and SSP are not required to be canonical (i.e., 63:N-1 are identical, where N is the CPU's maximum linear-address width). But, bits 63:N of SSP must be identical. Tested-by: Mathias Krause Tested-by: John Allen Tested-by: Rick Edgecombe Signed-off-by: Chao Gao Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-34-seanjc@google.com [sean: have common helper return 0/-EINVAL, not true/false] Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/nested.c | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 51c50ce9e011..a7bd6fc95057 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -3100,6 +3100,16 @@ static bool is_l1_noncanonical_address_on_vmexit(u64 la, struct vmcs12 *vmcs12) return !__is_canonical_address(la, l1_address_bits_on_exit); } +static int nested_vmx_check_cet_state_common(struct kvm_vcpu *vcpu, u64 s_cet, + u64 ssp, u64 ssp_tbl) +{ + if (CC(!kvm_is_valid_u_s_cet(vcpu, s_cet)) || CC(!IS_ALIGNED(ssp, 4)) || + CC(is_noncanonical_msr_address(ssp_tbl, vcpu))) + return -EINVAL; + + return 0; +} + static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { @@ -3169,6 +3179,27 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu, return -EINVAL; } + if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_CET_STATE) { + if (nested_vmx_check_cet_state_common(vcpu, vmcs12->host_s_cet, + vmcs12->host_ssp, + vmcs12->host_ssp_tbl)) + return -EINVAL; + + /* + * IA32_S_CET and SSP must be canonical if the host will + * enter 64-bit mode after VM-exit; otherwise, higher + * 32-bits must be all 0s. + */ + if (ia32e) { + if (CC(is_noncanonical_msr_address(vmcs12->host_s_cet, vcpu)) || + CC(is_noncanonical_msr_address(vmcs12->host_ssp, vcpu))) + return -EINVAL; + } else { + if (CC(vmcs12->host_s_cet >> 32) || CC(vmcs12->host_ssp >> 32)) + return -EINVAL; + } + } + return 0; } @@ -3279,6 +3310,23 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu, CC((vmcs12->guest_bndcfgs & MSR_IA32_BNDCFGS_RSVD)))) return -EINVAL; + if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_CET_STATE) { + if (nested_vmx_check_cet_state_common(vcpu, vmcs12->guest_s_cet, + vmcs12->guest_ssp, + vmcs12->guest_ssp_tbl)) + return -EINVAL; + + /* + * Guest SSP must have 63:N bits identical, rather than + * be canonical (i.e., 63:N-1 bits identical), where N is + * the CPU's maximum linear-address width. Similar to + * is_noncanonical_msr_address(), use the host's + * linear-address width. + */ + if (CC(!__is_canonical_address(vmcs12->guest_ssp, max_host_virt_addr_bits() + 1))) + return -EINVAL; + } + if (nested_check_guest_non_reg_state(vmcs12)) return -EINVAL; From 42ae6448531b5106e9f29794992856e94a52b5cb Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Fri, 19 Sep 2025 15:32:41 -0700 Subject: [PATCH 2029/2711] KVM: nVMX: Advertise new VM-Entry/Exit control bits for CET state Advertise the LOAD_CET_STATE VM-Entry/Exit control bits in the nested VMX MSRS, as all nested support for CET virtualization, including consistency checks, is in place. Advertise support if and only if KVM supports at least one of IBT or SHSTK. While it's userspace's responsibility to provide a consistent CPU model to the guest, that doesn't mean KVM should set userspace up to fail. Note, the existing {CLEAR,LOAD}_BNDCFGS behavior predates KVM_X86_QUIRK_STUFF_FEATURE_MSRS, i.e. KVM "solved" the inconsistent CPU model problem by overwriting the VMX MSRs provided by userspace. Signed-off-by: Chao Gao Link: https://lore.kernel.org/r/20250919223258.1604852-35-seanjc@google.com Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/nested.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index a7bd6fc95057..76271962cb70 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -7179,13 +7179,17 @@ static void nested_vmx_setup_exit_ctls(struct vmcs_config *vmcs_conf, VM_EXIT_HOST_ADDR_SPACE_SIZE | #endif VM_EXIT_LOAD_IA32_PAT | VM_EXIT_SAVE_IA32_PAT | - VM_EXIT_CLEAR_BNDCFGS; + VM_EXIT_CLEAR_BNDCFGS | VM_EXIT_LOAD_CET_STATE; msrs->exit_ctls_high |= VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | VM_EXIT_LOAD_IA32_EFER | VM_EXIT_SAVE_IA32_EFER | VM_EXIT_SAVE_VMX_PREEMPTION_TIMER | VM_EXIT_ACK_INTR_ON_EXIT | VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL; + if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK) && + !kvm_cpu_cap_has(X86_FEATURE_IBT)) + msrs->exit_ctls_high &= ~VM_EXIT_LOAD_CET_STATE; + /* We support free control of debug control saving. */ msrs->exit_ctls_low &= ~VM_EXIT_SAVE_DEBUG_CONTROLS; } @@ -7201,11 +7205,16 @@ static void nested_vmx_setup_entry_ctls(struct vmcs_config *vmcs_conf, #ifdef CONFIG_X86_64 VM_ENTRY_IA32E_MODE | #endif - VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_LOAD_BNDCFGS; + VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_LOAD_BNDCFGS | + VM_ENTRY_LOAD_CET_STATE; msrs->entry_ctls_high |= (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | VM_ENTRY_LOAD_IA32_EFER | VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL); + if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK) && + !kvm_cpu_cap_has(X86_FEATURE_IBT)) + msrs->entry_ctls_high &= ~VM_ENTRY_LOAD_CET_STATE; + /* We support free control of debug control loading. */ msrs->entry_ctls_low &= ~VM_ENTRY_LOAD_DEBUG_CONTROLS; } From 48b2ec0d540c29cebb5119dd2b8e8e7369bc409c Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 19 Sep 2025 15:32:42 -0700 Subject: [PATCH 2030/2711] KVM: SVM: Emulate reads and writes to shadow stack MSRs Emulate shadow stack MSR access by reading and writing to the corresponding fields in the VMCB. Signed-off-by: John Allen [sean: mark VMCB_CET dirty/clean as appropriate] Link: https://lore.kernel.org/r/20250919223258.1604852-36-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 21 +++++++++++++++++++++ arch/x86/kvm/svm/svm.h | 3 ++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index ff4925a7bf96..b977ea4a46e7 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -2767,6 +2767,15 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (guest_cpuid_is_intel_compatible(vcpu)) msr_info->data |= (u64)svm->sysenter_esp_hi << 32; break; + case MSR_IA32_S_CET: + msr_info->data = svm->vmcb->save.s_cet; + break; + case MSR_IA32_INT_SSP_TAB: + msr_info->data = svm->vmcb->save.isst_addr; + break; + case MSR_KVM_INTERNAL_GUEST_SSP: + msr_info->data = svm->vmcb->save.ssp; + break; case MSR_TSC_AUX: msr_info->data = svm->tsc_aux; break; @@ -2999,6 +3008,18 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) svm->vmcb01.ptr->save.sysenter_esp = (u32)data; svm->sysenter_esp_hi = guest_cpuid_is_intel_compatible(vcpu) ? (data >> 32) : 0; break; + case MSR_IA32_S_CET: + svm->vmcb->save.s_cet = data; + vmcb_mark_dirty(svm->vmcb01.ptr, VMCB_CET); + break; + case MSR_IA32_INT_SSP_TAB: + svm->vmcb->save.isst_addr = data; + vmcb_mark_dirty(svm->vmcb01.ptr, VMCB_CET); + break; + case MSR_KVM_INTERNAL_GUEST_SSP: + svm->vmcb->save.ssp = data; + vmcb_mark_dirty(svm->vmcb01.ptr, VMCB_CET); + break; case MSR_TSC_AUX: /* * TSC_AUX is always virtualized for SEV-ES guests when the diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 10d5cbc259e1..37de6a4a2665 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -74,6 +74,7 @@ enum { * AVIC PHYSICAL_TABLE pointer, * AVIC LOGICAL_TABLE pointer */ + VMCB_CET, /* S_CET, SSP, ISST_ADDR */ VMCB_SW = 31, /* Reserved for hypervisor/software use */ }; @@ -82,7 +83,7 @@ enum { (1U << VMCB_ASID) | (1U << VMCB_INTR) | \ (1U << VMCB_NPT) | (1U << VMCB_CR) | (1U << VMCB_DR) | \ (1U << VMCB_DT) | (1U << VMCB_SEG) | (1U << VMCB_CR2) | \ - (1U << VMCB_LBR) | (1U << VMCB_AVIC) | \ + (1U << VMCB_LBR) | (1U << VMCB_AVIC) | (1U << VMCB_CET) | \ (1U << VMCB_SW)) /* TPR and CR2 are always written before VMRUN */ From c5ba49458513bd1ecd669d4ec7124e788b19347c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:43 -0700 Subject: [PATCH 2031/2711] KVM: nSVM: Save/load CET Shadow Stack state to/from vmcb12/vmcb02 Transfer the three CET Shadow Stack VMCB fields (S_CET, ISST_ADDR, and SSP) on VMRUN, #VMEXIT, and loading nested state (saving nested state simply copies the entire save area). SVM doesn't provide a way to disallow L1 from enabling Shadow Stacks for L2, i.e. KVM *must* provide nested support before advertising SHSTK to userspace. Link: https://lore.kernel.org/r/20250919223258.1604852-37-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/nested.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 826473f2d7c7..a6443feab252 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -636,6 +636,14 @@ static void nested_vmcb02_prepare_save(struct vcpu_svm *svm, struct vmcb *vmcb12 vmcb_mark_dirty(vmcb02, VMCB_DT); } + if (guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) && + (unlikely(new_vmcb12 || vmcb_is_dirty(vmcb12, VMCB_CET)))) { + vmcb02->save.s_cet = vmcb12->save.s_cet; + vmcb02->save.isst_addr = vmcb12->save.isst_addr; + vmcb02->save.ssp = vmcb12->save.ssp; + vmcb_mark_dirty(vmcb02, VMCB_CET); + } + kvm_set_rflags(vcpu, vmcb12->save.rflags | X86_EFLAGS_FIXED); svm_set_efer(vcpu, svm->nested.save.efer); @@ -1044,6 +1052,12 @@ void svm_copy_vmrun_state(struct vmcb_save_area *to_save, to_save->rsp = from_save->rsp; to_save->rip = from_save->rip; to_save->cpl = 0; + + if (kvm_cpu_cap_has(X86_FEATURE_SHSTK)) { + to_save->s_cet = from_save->s_cet; + to_save->isst_addr = from_save->isst_addr; + to_save->ssp = from_save->ssp; + } } void svm_copy_vmloadsave_state(struct vmcb *to_vmcb, struct vmcb *from_vmcb) @@ -1111,6 +1125,12 @@ int nested_svm_vmexit(struct vcpu_svm *svm) vmcb12->save.dr6 = svm->vcpu.arch.dr6; vmcb12->save.cpl = vmcb02->save.cpl; + if (guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) { + vmcb12->save.s_cet = vmcb02->save.s_cet; + vmcb12->save.isst_addr = vmcb02->save.isst_addr; + vmcb12->save.ssp = vmcb02->save.ssp; + } + vmcb12->control.int_state = vmcb02->control.int_state; vmcb12->control.exit_code = vmcb02->control.exit_code; vmcb12->control.exit_code_hi = vmcb02->control.exit_code_hi; From c7586aa3bed4969cc7345940e5a331efd614f41d Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 19 Sep 2025 15:32:44 -0700 Subject: [PATCH 2032/2711] KVM: SVM: Update dump_vmcb with shadow stack save area additions Add shadow stack VMCB fields to dump_vmcb. PL0_SSP, PL1_SSP, PL2_SSP, PL3_SSP, and U_CET are part of the SEV-ES save area and are encrypted, but can be decrypted and dumped if the guest policy allows debugging. Reviewed-by: Maxim Levitsky Signed-off-by: John Allen Link: https://lore.kernel.org/r/20250919223258.1604852-38-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index b977ea4a46e7..bea8bfea74f9 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3410,6 +3410,10 @@ static void dump_vmcb(struct kvm_vcpu *vcpu) "rip:", save->rip, "rflags:", save->rflags); pr_err("%-15s %016llx %-13s %016llx\n", "rsp:", save->rsp, "rax:", save->rax); + pr_err("%-15s %016llx %-13s %016llx\n", + "s_cet:", save->s_cet, "ssp:", save->ssp); + pr_err("%-15s %016llx\n", + "isst_addr:", save->isst_addr); pr_err("%-15s %016llx %-13s %016llx\n", "star:", save01->star, "lstar:", save01->lstar); pr_err("%-15s %016llx %-13s %016llx\n", @@ -3434,6 +3438,13 @@ static void dump_vmcb(struct kvm_vcpu *vcpu) pr_err("%-15s %016llx\n", "sev_features", vmsa->sev_features); + pr_err("%-15s %016llx %-13s %016llx\n", + "pl0_ssp:", vmsa->pl0_ssp, "pl1_ssp:", vmsa->pl1_ssp); + pr_err("%-15s %016llx %-13s %016llx\n", + "pl2_ssp:", vmsa->pl2_ssp, "pl3_ssp:", vmsa->pl3_ssp); + pr_err("%-15s %016llx\n", + "u_cet:", vmsa->u_cet); + pr_err("%-15s %016llx %-13s %016llx\n", "rax:", vmsa->rax, "rbx:", vmsa->rbx); pr_err("%-15s %016llx %-13s %016llx\n", From 38c46bdbf99812a07a8a7ef48718f0a03acd8a8a Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 19 Sep 2025 15:32:45 -0700 Subject: [PATCH 2033/2711] KVM: SVM: Pass through shadow stack MSRs as appropriate Pass through XSAVE managed CET MSRs on SVM when KVM supports shadow stack. These cannot be intercepted without also intercepting XSAVE which would likely cause unacceptable performance overhead. MSR_IA32_INT_SSP_TAB is not managed by XSAVE, so it is intercepted. Reviewed-by: Chao Gao Signed-off-by: John Allen Link: https://lore.kernel.org/r/20250919223258.1604852-39-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index bea8bfea74f9..1c1792f6a65c 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -844,6 +844,17 @@ static void svm_recalc_msr_intercepts(struct kvm_vcpu *vcpu) svm_disable_intercept_for_msr(vcpu, MSR_IA32_MPERF, MSR_TYPE_R); } + if (kvm_cpu_cap_has(X86_FEATURE_SHSTK)) { + bool shstk_enabled = guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK); + + svm_set_intercept_for_msr(vcpu, MSR_IA32_U_CET, MSR_TYPE_RW, !shstk_enabled); + svm_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, MSR_TYPE_RW, !shstk_enabled); + svm_set_intercept_for_msr(vcpu, MSR_IA32_PL0_SSP, MSR_TYPE_RW, !shstk_enabled); + svm_set_intercept_for_msr(vcpu, MSR_IA32_PL1_SSP, MSR_TYPE_RW, !shstk_enabled); + svm_set_intercept_for_msr(vcpu, MSR_IA32_PL2_SSP, MSR_TYPE_RW, !shstk_enabled); + svm_set_intercept_for_msr(vcpu, MSR_IA32_PL3_SSP, MSR_TYPE_RW, !shstk_enabled); + } + if (sev_es_guest(vcpu->kvm)) sev_es_recalc_msr_intercepts(vcpu); From b5fa221f7b08ca145b0357b77b90dcc998278967 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:46 -0700 Subject: [PATCH 2034/2711] KVM: SEV: Synchronize MSR_IA32_XSS from the GHCB when it's valid Synchronize XSS from the GHCB to KVM's internal tracking if the guest marks XSS as valid on a #VMGEXIT. Like XCR0, KVM needs an up-to-date copy of XSS in order to compute the required XSTATE size when emulating CPUID.0xD.0x1 for the guest. Treat the incoming XSS change as an emulated write, i.e. validatate the guest-provided value, to avoid letting the guest load garbage into KVM's tracking. Simply ignore bad values, as either the guest managed to get an unsupported value into hardware, or the guest is misbehaving and providing pure garbage. In either case, KVM can't fix the broken guest. Explicitly allow access to XSS at all times, as KVM needs to ensure its copy of XSS stays up-to-date. E.g. KVM supports migration of SEV-ES guests and so needs to allow the host to save/restore XSS, otherwise a guest that *knows* its XSS hasn't change could get stale/bad CPUID emulation if the guest doesn't provide XSS in the GHCB on every exit. This creates a hypothetical problem where a guest could request emulation of RDMSR or WRMSR on XSS, but arguably that's not even a problem, e.g. it would be entirely reasonable for a guest to request "emulation" as a way to inform the hypervisor that its XSS value has been modified. Note, emulating the change as an MSR write also takes care of side effects, e.g. marking dynamic CPUID bits as dirty. Suggested-by: John Allen base-commit: 14298d819d5a6b7180a4089e7d2121ca3551dc6c Link: https://lore.kernel.org/r/20250919223258.1604852-40-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 3 +++ arch/x86/kvm/svm/svm.c | 4 ++-- arch/x86/kvm/svm/svm.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index d2ffacd43234..7971e2a4ddd5 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -3310,6 +3310,9 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm) if (kvm_ghcb_xcr0_is_valid(svm)) __kvm_set_xcr(vcpu, 0, kvm_ghcb_get_xcr0(svm)); + if (kvm_ghcb_xss_is_valid(svm)) + __kvm_emulate_msr_write(vcpu, MSR_IA32_XSS, kvm_ghcb_get_xss(svm)); + /* Copy the GHCB exit information into the VMCB fields */ exit_code = kvm_ghcb_get_sw_exit_code(svm); control->exit_code = lower_32_bits(exit_code); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 1c1792f6a65c..8ca6ef4b35c1 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -2721,8 +2721,8 @@ static int svm_get_feature_msr(u32 msr, u64 *data) static bool sev_es_prevent_msr_access(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { - return sev_es_guest(vcpu->kvm) && - vcpu->arch.guest_state_protected && + return sev_es_guest(vcpu->kvm) && vcpu->arch.guest_state_protected && + msr_info->index != MSR_IA32_XSS && !msr_write_intercepted(vcpu, msr_info->index); } diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 37de6a4a2665..99ce9b95f782 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -941,5 +941,6 @@ DEFINE_KVM_GHCB_ACCESSORS(sw_exit_info_1) DEFINE_KVM_GHCB_ACCESSORS(sw_exit_info_2) DEFINE_KVM_GHCB_ACCESSORS(sw_scratch) DEFINE_KVM_GHCB_ACCESSORS(xcr0) +DEFINE_KVM_GHCB_ACCESSORS(xss) #endif From 8db428fd5229ba509d515af10d7f33d7d4a54bfe Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 19 Sep 2025 15:32:47 -0700 Subject: [PATCH 2035/2711] KVM: SVM: Enable shadow stack virtualization for SVM Remove the explicit clearing of shadow stack CPU capabilities. Reviewed-by: Chao Gao Signed-off-by: John Allen Link: https://lore.kernel.org/r/20250919223258.1604852-41-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 8ca6ef4b35c1..6068c99bca95 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5263,10 +5263,7 @@ static __init void svm_set_cpu_caps(void) kvm_set_cpu_caps(); kvm_caps.supported_perf_cap = 0; - kvm_caps.supported_xss = 0; - /* KVM doesn't yet support CET virtualization for SVM. */ - kvm_cpu_cap_clear(X86_FEATURE_SHSTK); kvm_cpu_cap_clear(X86_FEATURE_IBT); /* CPUID 0x80000001 and 0x8000000A (SVM features) */ From d37cc4819a489bfe32008e50e3a76eb967d95d42 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:48 -0700 Subject: [PATCH 2036/2711] KVM: x86: Add human friendly formatting for #XM, and #VE Add XM_VECTOR and VE_VECTOR pretty-printing for trace_kvm_inj_exception(). Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-42-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/trace.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index 57d79fd31df0..06da19b370c5 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -461,8 +461,8 @@ TRACE_EVENT(kvm_inj_virq, #define kvm_trace_sym_exc \ EXS(DE), EXS(DB), EXS(BP), EXS(OF), EXS(BR), EXS(UD), EXS(NM), \ - EXS(DF), EXS(TS), EXS(NP), EXS(SS), EXS(GP), EXS(PF), \ - EXS(MF), EXS(AC), EXS(MC) + EXS(DF), EXS(TS), EXS(NP), EXS(SS), EXS(GP), EXS(PF), EXS(MF), \ + EXS(AC), EXS(MC), EXS(XM), EXS(VE) /* * Tracepoint for kvm interrupt injection: From f2f5519aa4e3ec4e42b009338f773bebb0bfd8a3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:49 -0700 Subject: [PATCH 2037/2711] KVM: x86: Define Control Protection Exception (#CP) vector Add a CP_VECTOR definition for CET's Control Protection Exception (#CP), along with human friendly formatting for trace_kvm_inj_exception(). Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-43-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/uapi/asm/kvm.h | 1 + arch/x86/kvm/trace.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 467116186e71..73e0e88a0a54 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -35,6 +35,7 @@ #define MC_VECTOR 18 #define XM_VECTOR 19 #define VE_VECTOR 20 +#define CP_VECTOR 21 /* Select x86 specific features in */ #define __KVM_HAVE_PIT diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index 06da19b370c5..322913dda626 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -462,7 +462,7 @@ TRACE_EVENT(kvm_inj_virq, #define kvm_trace_sym_exc \ EXS(DE), EXS(DB), EXS(BP), EXS(OF), EXS(BR), EXS(UD), EXS(NM), \ EXS(DF), EXS(TS), EXS(NP), EXS(SS), EXS(GP), EXS(PF), EXS(MF), \ - EXS(AC), EXS(MC), EXS(XM), EXS(VE) + EXS(AC), EXS(MC), EXS(XM), EXS(VE), EXS(CP) /* * Tracepoint for kvm interrupt injection: From fddd07626baa419c259ad5f3537a57188b5bb415 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:50 -0700 Subject: [PATCH 2038/2711] KVM: x86: Define AMD's #HV, #VC, and #SX exception vectors Add {HV,CP,SX}_VECTOR definitions for AMD's Hypervisor Injection Exception, VMM Communication Exception, and SVM Security Exception vectors, along with human friendly formatting for trace_kvm_inj_exception(). Note, KVM is all but guaranteed to never observe or inject #SX, and #HV is also unlikely to go unused. Add the architectural collateral mostly for completeness, and on the off chance that hardware goes off the rails. Link: https://lore.kernel.org/r/20250919223258.1604852-44-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/uapi/asm/kvm.h | 4 ++++ arch/x86/kvm/trace.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 73e0e88a0a54..d420c9c066d4 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -37,6 +37,10 @@ #define VE_VECTOR 20 #define CP_VECTOR 21 +#define HV_VECTOR 28 +#define VC_VECTOR 29 +#define SX_VECTOR 30 + /* Select x86 specific features in */ #define __KVM_HAVE_PIT #define __KVM_HAVE_IOAPIC diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index 322913dda626..e79bc9cb7162 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -462,7 +462,8 @@ TRACE_EVENT(kvm_inj_virq, #define kvm_trace_sym_exc \ EXS(DE), EXS(DB), EXS(BP), EXS(OF), EXS(BR), EXS(UD), EXS(NM), \ EXS(DF), EXS(TS), EXS(NP), EXS(SS), EXS(GP), EXS(PF), EXS(MF), \ - EXS(AC), EXS(MC), EXS(XM), EXS(VE), EXS(CP) + EXS(AC), EXS(MC), EXS(XM), EXS(VE), EXS(CP), \ + EXS(HV), EXS(VC), EXS(SX) /* * Tracepoint for kvm interrupt injection: From 9c38ddb3df94acdc86485c7073610f01655309f9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:52 -0700 Subject: [PATCH 2039/2711] KVM: selftests: Add an MSR test to exercise guest/host and read/write Add a selftest to verify reads and writes to various MSRs, from both the guest and host, and expect success/failure based on whether or not the vCPU supports the MSR according to supported CPUID. Note, this test is extremely similar to KVM-Unit-Test's "msr" test, but provides more coverage with respect to host accesses, and will be extended to provide addition testing of CPUID-based features, save/restore lists, and KVM_{G,S}ET_ONE_REG, all which are extremely difficult to validate in KUT. If kvm.ignore_msrs=true, skip the unsupported and reserved testcases as KVM's ABI is a mess; what exactly is supposed to be ignored, and when, varies wildly. Reviewed-by: Chao Gao Link: https://lore.kernel.org/r/20250919223258.1604852-46-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../selftests/kvm/include/x86/processor.h | 5 + tools/testing/selftests/kvm/x86/msrs_test.c | 322 ++++++++++++++++++ 3 files changed, 328 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/msrs_test.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index f6fe7a07a0a2..e6e410b938b9 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -87,6 +87,7 @@ TEST_GEN_PROGS_x86 += x86/kvm_clock_test TEST_GEN_PROGS_x86 += x86/kvm_pv_test TEST_GEN_PROGS_x86 += x86/kvm_buslock_test TEST_GEN_PROGS_x86 += x86/monitor_mwait_test +TEST_GEN_PROGS_x86 += x86/msrs_test TEST_GEN_PROGS_x86 += x86/nested_emulation_test TEST_GEN_PROGS_x86 += x86/nested_exceptions_test TEST_GEN_PROGS_x86 += x86/platform_info_test diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h index fbe875eafca5..51cd84b9ca66 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -1362,6 +1362,11 @@ static inline bool kvm_is_unrestricted_guest_enabled(void) return get_kvm_intel_param_bool("unrestricted_guest"); } +static inline bool kvm_is_ignore_msrs(void) +{ + return get_kvm_param_bool("ignore_msrs"); +} + uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr, int *level); uint64_t *vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr); diff --git a/tools/testing/selftests/kvm/x86/msrs_test.c b/tools/testing/selftests/kvm/x86/msrs_test.c new file mode 100644 index 000000000000..345a39030a0a --- /dev/null +++ b/tools/testing/selftests/kvm/x86/msrs_test.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include + +#include + +#include "kvm_util.h" +#include "processor.h" + +/* Use HYPERVISOR for MSRs that are emulated unconditionally (as is HYPERVISOR). */ +#define X86_FEATURE_NONE X86_FEATURE_HYPERVISOR + +struct kvm_msr { + const struct kvm_x86_cpu_feature feature; + const struct kvm_x86_cpu_feature feature2; + const char *name; + const u64 reset_val; + const u64 write_val; + const u64 rsvd_val; + const u32 index; +}; + +#define ____MSR_TEST(msr, str, val, rsvd, reset, feat, f2) \ +{ \ + .index = msr, \ + .name = str, \ + .write_val = val, \ + .rsvd_val = rsvd, \ + .reset_val = reset, \ + .feature = X86_FEATURE_ ##feat, \ + .feature2 = X86_FEATURE_ ##f2, \ +} + +#define __MSR_TEST(msr, str, val, rsvd, reset, feat) \ + ____MSR_TEST(msr, str, val, rsvd, reset, feat, feat) + +#define MSR_TEST_NON_ZERO(msr, val, rsvd, reset, feat) \ + __MSR_TEST(msr, #msr, val, rsvd, reset, feat) + +#define MSR_TEST(msr, val, rsvd, feat) \ + __MSR_TEST(msr, #msr, val, rsvd, 0, feat) + +#define MSR_TEST2(msr, val, rsvd, feat, f2) \ + ____MSR_TEST(msr, #msr, val, rsvd, 0, feat, f2) + +/* + * Note, use a page aligned value for the canonical value so that the value + * is compatible with MSRs that use bits 11:0 for things other than addresses. + */ +static const u64 canonical_val = 0x123456789000ull; + +/* + * Arbitrary value with bits set in every byte, but not all bits set. This is + * also a non-canonical value, but that's coincidental (any 64-bit value with + * an alternating 0s/1s pattern will be non-canonical). + */ +static const u64 u64_val = 0xaaaa5555aaaa5555ull; + +#define MSR_TEST_CANONICAL(msr, feat) \ + __MSR_TEST(msr, #msr, canonical_val, NONCANONICAL, 0, feat) + +/* + * The main struct must be scoped to a function due to the use of structures to + * define features. For the global structure, allocate enough space for the + * foreseeable future without getting too ridiculous, to minimize maintenance + * costs (bumping the array size every time an MSR is added is really annoying). + */ +static struct kvm_msr msrs[128]; +static int idx; + +static bool ignore_unsupported_msrs; + +static u64 fixup_rdmsr_val(u32 msr, u64 want) +{ + /* + * AMD CPUs drop bits 63:32 on some MSRs that Intel CPUs support. KVM + * is supposed to emulate that behavior based on guest vendor model + * (which is the same as the host vendor model for this test). + */ + if (!host_cpu_is_amd) + return want; + + switch (msr) { + case MSR_IA32_SYSENTER_ESP: + case MSR_IA32_SYSENTER_EIP: + case MSR_TSC_AUX: + return want & GENMASK_ULL(31, 0); + default: + return want; + } +} + +static void __rdmsr(u32 msr, u64 want) +{ + u64 val; + u8 vec; + + vec = rdmsr_safe(msr, &val); + __GUEST_ASSERT(!vec, "Unexpected %s on RDMSR(0x%x)", ex_str(vec), msr); + + __GUEST_ASSERT(val == want, "Wanted 0x%lx from RDMSR(0x%x), got 0x%lx", + want, msr, val); +} + +static void __wrmsr(u32 msr, u64 val) +{ + u8 vec; + + vec = wrmsr_safe(msr, val); + __GUEST_ASSERT(!vec, "Unexpected %s on WRMSR(0x%x, 0x%lx)", + ex_str(vec), msr, val); + __rdmsr(msr, fixup_rdmsr_val(msr, val)); +} + +static void guest_test_supported_msr(const struct kvm_msr *msr) +{ + __rdmsr(msr->index, msr->reset_val); + __wrmsr(msr->index, msr->write_val); + GUEST_SYNC(fixup_rdmsr_val(msr->index, msr->write_val)); + + __rdmsr(msr->index, msr->reset_val); +} + +static void guest_test_unsupported_msr(const struct kvm_msr *msr) +{ + u64 val; + u8 vec; + + /* + * KVM's ABI with respect to ignore_msrs is a mess and largely beyond + * repair, just skip the unsupported MSR tests. + */ + if (ignore_unsupported_msrs) + goto skip_wrmsr_gp; + + if (this_cpu_has(msr->feature2)) + goto skip_wrmsr_gp; + + vec = rdmsr_safe(msr->index, &val); + __GUEST_ASSERT(vec == GP_VECTOR, "Wanted #GP on RDMSR(0x%x), got %s", + msr->index, ex_str(vec)); + + vec = wrmsr_safe(msr->index, msr->write_val); + __GUEST_ASSERT(vec == GP_VECTOR, "Wanted #GP on WRMSR(0x%x, 0x%lx), got %s", + msr->index, msr->write_val, ex_str(vec)); + +skip_wrmsr_gp: + GUEST_SYNC(0); +} + +void guest_test_reserved_val(const struct kvm_msr *msr) +{ + /* Skip reserved value checks as well, ignore_msrs is trully a mess. */ + if (ignore_unsupported_msrs) + return; + + /* + * If the CPU will truncate the written value (e.g. SYSENTER on AMD), + * expect success and a truncated value, not #GP. + */ + if (!this_cpu_has(msr->feature) || + msr->rsvd_val == fixup_rdmsr_val(msr->index, msr->rsvd_val)) { + u8 vec = wrmsr_safe(msr->index, msr->rsvd_val); + + __GUEST_ASSERT(vec == GP_VECTOR, + "Wanted #GP on WRMSR(0x%x, 0x%lx), got %s", + msr->index, msr->rsvd_val, ex_str(vec)); + } else { + __wrmsr(msr->index, msr->rsvd_val); + __wrmsr(msr->index, msr->reset_val); + } +} + +static void guest_main(void) +{ + for (;;) { + const struct kvm_msr *msr = &msrs[READ_ONCE(idx)]; + + if (this_cpu_has(msr->feature)) + guest_test_supported_msr(msr); + else + guest_test_unsupported_msr(msr); + + if (msr->rsvd_val) + guest_test_reserved_val(msr); + + GUEST_SYNC(msr->reset_val); + } +} + +static void host_test_msr(struct kvm_vcpu *vcpu, u64 guest_val) +{ + u64 reset_val = msrs[idx].reset_val; + u32 msr = msrs[idx].index; + u64 val; + + if (!kvm_cpu_has(msrs[idx].feature)) + return; + + val = vcpu_get_msr(vcpu, msr); + TEST_ASSERT(val == guest_val, "Wanted 0x%lx from get_msr(0x%x), got 0x%lx", + guest_val, msr, val); + + vcpu_set_msr(vcpu, msr, reset_val); + + val = vcpu_get_msr(vcpu, msr); + TEST_ASSERT(val == reset_val, "Wanted 0x%lx from get_msr(0x%x), got 0x%lx", + reset_val, msr, val); +} + +static void do_vcpu_run(struct kvm_vcpu *vcpu) +{ + struct ucall uc; + + for (;;) { + vcpu_run(vcpu); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + host_test_msr(vcpu, uc.args[1]); + return; + case UCALL_PRINTF: + pr_info("%s", uc.buffer); + break; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + case UCALL_DONE: + TEST_FAIL("Unexpected UCALL_DONE"); + default: + TEST_FAIL("Unexpected ucall: %lu", uc.cmd); + } + } +} + +static void vcpus_run(struct kvm_vcpu **vcpus, const int NR_VCPUS) +{ + int i; + + for (i = 0; i < NR_VCPUS; i++) + do_vcpu_run(vcpus[i]); +} + +#define MISC_ENABLES_RESET_VAL (MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL | MSR_IA32_MISC_ENABLE_BTS_UNAVAIL) + +static void test_msrs(void) +{ + const struct kvm_msr __msrs[] = { + MSR_TEST_NON_ZERO(MSR_IA32_MISC_ENABLE, + MISC_ENABLES_RESET_VAL | MSR_IA32_MISC_ENABLE_FAST_STRING, + MSR_IA32_MISC_ENABLE_FAST_STRING, MISC_ENABLES_RESET_VAL, NONE), + MSR_TEST_NON_ZERO(MSR_IA32_CR_PAT, 0x07070707, 0, 0x7040600070406, NONE), + + /* + * TSC_AUX is supported if RDTSCP *or* RDPID is supported. Add + * entries for each features so that TSC_AUX doesn't exists for + * the "unsupported" vCPU, and obviously to test both cases. + */ + MSR_TEST2(MSR_TSC_AUX, 0x12345678, u64_val, RDTSCP, RDPID), + MSR_TEST2(MSR_TSC_AUX, 0x12345678, u64_val, RDPID, RDTSCP), + + MSR_TEST(MSR_IA32_SYSENTER_CS, 0x1234, 0, NONE), + /* + * SYSENTER_{ESP,EIP} are technically non-canonical on Intel, + * but KVM doesn't emulate that behavior on emulated writes, + * i.e. this test will observe different behavior if the MSR + * writes are handed by hardware vs. KVM. KVM's behavior is + * intended (though far from ideal), so don't bother testing + * non-canonical values. + */ + MSR_TEST(MSR_IA32_SYSENTER_ESP, canonical_val, 0, NONE), + MSR_TEST(MSR_IA32_SYSENTER_EIP, canonical_val, 0, NONE), + + MSR_TEST_CANONICAL(MSR_FS_BASE, LM), + MSR_TEST_CANONICAL(MSR_GS_BASE, LM), + MSR_TEST_CANONICAL(MSR_KERNEL_GS_BASE, LM), + MSR_TEST_CANONICAL(MSR_LSTAR, LM), + MSR_TEST_CANONICAL(MSR_CSTAR, LM), + MSR_TEST(MSR_SYSCALL_MASK, 0xffffffff, 0, LM), + + MSR_TEST_CANONICAL(MSR_IA32_PL0_SSP, SHSTK), + MSR_TEST(MSR_IA32_PL0_SSP, canonical_val, canonical_val | 1, SHSTK), + MSR_TEST_CANONICAL(MSR_IA32_PL1_SSP, SHSTK), + MSR_TEST(MSR_IA32_PL1_SSP, canonical_val, canonical_val | 1, SHSTK), + MSR_TEST_CANONICAL(MSR_IA32_PL2_SSP, SHSTK), + MSR_TEST(MSR_IA32_PL2_SSP, canonical_val, canonical_val | 1, SHSTK), + MSR_TEST_CANONICAL(MSR_IA32_PL3_SSP, SHSTK), + MSR_TEST(MSR_IA32_PL3_SSP, canonical_val, canonical_val | 1, SHSTK), + }; + + /* + * Create two vCPUs, but run them on the same task, to validate KVM's + * context switching of MSR state. Don't pin the task to a pCPU to + * also validate KVM's handling of cross-pCPU migration. + */ + const int NR_VCPUS = 2; + struct kvm_vcpu *vcpus[NR_VCPUS]; + struct kvm_vm *vm; + + kvm_static_assert(sizeof(__msrs) <= sizeof(msrs)); + kvm_static_assert(ARRAY_SIZE(__msrs) <= ARRAY_SIZE(msrs)); + memcpy(msrs, __msrs, sizeof(__msrs)); + + ignore_unsupported_msrs = kvm_is_ignore_msrs(); + + vm = vm_create_with_vcpus(NR_VCPUS, guest_main, vcpus); + + sync_global_to_guest(vm, msrs); + sync_global_to_guest(vm, ignore_unsupported_msrs); + + for (idx = 0; idx < ARRAY_SIZE(__msrs); idx++) { + sync_global_to_guest(vm, idx); + + vcpus_run(vcpus, NR_VCPUS); + vcpus_run(vcpus, NR_VCPUS); + } + + kvm_vm_free(vm); +} + +int main(void) +{ + test_msrs(); +} From 27c41353064f9fdec9276e6b8e618b01110ef282 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:53 -0700 Subject: [PATCH 2040/2711] KVM: selftests: Add support for MSR_IA32_{S,U}_CET to MSRs test Extend the MSRs test to support {S,U}_CET, which are a bit of a pain to handled due to the MSRs existing if IBT *or* SHSTK is supported. To deal with Intel's wonderful decision to bundle IBT and SHSTK under CET, track the second feature, but skip only RDMSR #GP tests to avoid false failures when running on a CPU with only one of IBT or SHSTK (the WRMSR #GP tests are still valid since the enable bits are per-feature). Reviewed-by: Chao Gao Link: https://lore.kernel.org/r/20250919223258.1604852-47-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86/msrs_test.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/msrs_test.c b/tools/testing/selftests/kvm/x86/msrs_test.c index 345a39030a0a..1efaebb986c4 100644 --- a/tools/testing/selftests/kvm/x86/msrs_test.c +++ b/tools/testing/selftests/kvm/x86/msrs_test.c @@ -132,13 +132,26 @@ static void guest_test_unsupported_msr(const struct kvm_msr *msr) if (ignore_unsupported_msrs) goto skip_wrmsr_gp; - if (this_cpu_has(msr->feature2)) - goto skip_wrmsr_gp; + /* + * {S,U}_CET exist if IBT or SHSTK is supported, but with bits that are + * writable only if their associated feature is supported. Skip the + * RDMSR #GP test if the secondary feature is supported, but perform + * the WRMSR #GP test as the to-be-written value is tied to the primary + * feature. For all other MSRs, simply do nothing. + */ + if (this_cpu_has(msr->feature2)) { + if (msr->index != MSR_IA32_U_CET && + msr->index != MSR_IA32_S_CET) + goto skip_wrmsr_gp; + + goto skip_rdmsr_gp; + } vec = rdmsr_safe(msr->index, &val); __GUEST_ASSERT(vec == GP_VECTOR, "Wanted #GP on RDMSR(0x%x), got %s", msr->index, ex_str(vec)); +skip_rdmsr_gp: vec = wrmsr_safe(msr->index, msr->write_val); __GUEST_ASSERT(vec == GP_VECTOR, "Wanted #GP on WRMSR(0x%x, 0x%lx), got %s", msr->index, msr->write_val, ex_str(vec)); @@ -276,6 +289,10 @@ static void test_msrs(void) MSR_TEST_CANONICAL(MSR_CSTAR, LM), MSR_TEST(MSR_SYSCALL_MASK, 0xffffffff, 0, LM), + MSR_TEST2(MSR_IA32_S_CET, CET_SHSTK_EN, CET_RESERVED, SHSTK, IBT), + MSR_TEST2(MSR_IA32_S_CET, CET_ENDBR_EN, CET_RESERVED, IBT, SHSTK), + MSR_TEST2(MSR_IA32_U_CET, CET_SHSTK_EN, CET_RESERVED, SHSTK, IBT), + MSR_TEST2(MSR_IA32_U_CET, CET_ENDBR_EN, CET_RESERVED, IBT, SHSTK), MSR_TEST_CANONICAL(MSR_IA32_PL0_SSP, SHSTK), MSR_TEST(MSR_IA32_PL0_SSP, canonical_val, canonical_val | 1, SHSTK), MSR_TEST_CANONICAL(MSR_IA32_PL1_SSP, SHSTK), From a8b9cca99cf454799ef799f8af9bdb55389cfd94 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:54 -0700 Subject: [PATCH 2041/2711] KVM: selftests: Extend MSRs test to validate vCPUs without supported features Add a third vCPUs to the MSRs test that runs with all features disabled in the vCPU's CPUID model, to verify that KVM does the right thing with respect to emulating accesses to MSRs that shouldn't exist. Use the same VM to verify that KVM is honoring the vCPU model, e.g. isn't looking at per-VM state when emulating MSR accesses. Link: https://lore.kernel.org/r/20250919223258.1604852-48-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86/msrs_test.c | 28 ++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/msrs_test.c b/tools/testing/selftests/kvm/x86/msrs_test.c index 1efaebb986c4..ec94c70b3f06 100644 --- a/tools/testing/selftests/kvm/x86/msrs_test.c +++ b/tools/testing/selftests/kvm/x86/msrs_test.c @@ -303,12 +303,17 @@ static void test_msrs(void) MSR_TEST(MSR_IA32_PL3_SSP, canonical_val, canonical_val | 1, SHSTK), }; + const struct kvm_x86_cpu_feature feat_none = X86_FEATURE_NONE; + const struct kvm_x86_cpu_feature feat_lm = X86_FEATURE_LM; + /* - * Create two vCPUs, but run them on the same task, to validate KVM's + * Create three vCPUs, but run them on the same task, to validate KVM's * context switching of MSR state. Don't pin the task to a pCPU to - * also validate KVM's handling of cross-pCPU migration. + * also validate KVM's handling of cross-pCPU migration. Use the full + * set of features for the first two vCPUs, but clear all features in + * third vCPU in order to test both positive and negative paths. */ - const int NR_VCPUS = 2; + const int NR_VCPUS = 3; struct kvm_vcpu *vcpus[NR_VCPUS]; struct kvm_vm *vm; @@ -323,6 +328,23 @@ static void test_msrs(void) sync_global_to_guest(vm, msrs); sync_global_to_guest(vm, ignore_unsupported_msrs); + /* + * Clear features in the "unsupported features" vCPU. This needs to be + * done before the first vCPU run as KVM's ABI is that guest CPUID is + * immutable once the vCPU has been run. + */ + for (idx = 0; idx < ARRAY_SIZE(__msrs); idx++) { + /* + * Don't clear LM; selftests are 64-bit only, and KVM doesn't + * honor LM=0 for MSRs that are supposed to exist if and only + * if the vCPU is a 64-bit model. Ditto for NONE; clearing a + * fake feature flag will result in false failures. + */ + if (memcmp(&msrs[idx].feature, &feat_lm, sizeof(feat_lm)) && + memcmp(&msrs[idx].feature, &feat_none, sizeof(feat_none))) + vcpu_clear_cpuid_feature(vcpus[2], msrs[idx].feature); + } + for (idx = 0; idx < ARRAY_SIZE(__msrs); idx++) { sync_global_to_guest(vm, idx); From 80c2b6d8e7bb194744f5fdfc4f0560e053ababda Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:55 -0700 Subject: [PATCH 2042/2711] KVM: selftests: Add KVM_{G,S}ET_ONE_REG coverage to MSRs test When KVM_{G,S}ET_ONE_REG are supported, verify that MSRs can be accessed via ONE_REG and through the dedicated MSR ioctls. For simplicity, run the test twice, e.g. instead of trying to get MSR values into the exact right state when switching write methods. Reviewed-by: Chao Gao Link: https://lore.kernel.org/r/20250919223258.1604852-49-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86/msrs_test.c | 22 ++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86/msrs_test.c b/tools/testing/selftests/kvm/x86/msrs_test.c index ec94c70b3f06..680d381d1bf7 100644 --- a/tools/testing/selftests/kvm/x86/msrs_test.c +++ b/tools/testing/selftests/kvm/x86/msrs_test.c @@ -200,6 +200,9 @@ static void guest_main(void) } } +static bool has_one_reg; +static bool use_one_reg; + static void host_test_msr(struct kvm_vcpu *vcpu, u64 guest_val) { u64 reset_val = msrs[idx].reset_val; @@ -213,11 +216,21 @@ static void host_test_msr(struct kvm_vcpu *vcpu, u64 guest_val) TEST_ASSERT(val == guest_val, "Wanted 0x%lx from get_msr(0x%x), got 0x%lx", guest_val, msr, val); - vcpu_set_msr(vcpu, msr, reset_val); + if (use_one_reg) + vcpu_set_reg(vcpu, KVM_X86_REG_MSR(msr), reset_val); + else + vcpu_set_msr(vcpu, msr, reset_val); val = vcpu_get_msr(vcpu, msr); TEST_ASSERT(val == reset_val, "Wanted 0x%lx from get_msr(0x%x), got 0x%lx", reset_val, msr, val); + + if (!has_one_reg) + return; + + val = vcpu_get_reg(vcpu, KVM_X86_REG_MSR(msr)); + TEST_ASSERT(val == reset_val, "Wanted 0x%lx from get_reg(0x%x), got 0x%lx", + reset_val, msr, val); } static void do_vcpu_run(struct kvm_vcpu *vcpu) @@ -357,5 +370,12 @@ static void test_msrs(void) int main(void) { + has_one_reg = kvm_has_cap(KVM_CAP_ONE_REG); + test_msrs(); + + if (has_one_reg) { + use_one_reg = true; + test_msrs(); + } } From 3469fd203bac201ad67d9586041689c4c6a87882 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:56 -0700 Subject: [PATCH 2043/2711] KVM: selftests: Add coverage for KVM-defined registers in MSRs test Add test coverage for the KVM-defined GUEST_SSP "register" in the MSRs test. While _KVM's_ goal is to not tie the uAPI of KVM-defined registers to any particular internal implementation, i.e. to not commit in uAPI to handling GUEST_SSP as an MSR, treating GUEST_SSP as an MSR for testing purposes is a-ok and is a naturally fit given the semantics of SSP. Reviewed-by: Chao Gao Link: https://lore.kernel.org/r/20250919223258.1604852-50-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86/msrs_test.c | 97 ++++++++++++++++++++- 1 file changed, 94 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/msrs_test.c b/tools/testing/selftests/kvm/x86/msrs_test.c index 680d381d1bf7..54ef9c539eb3 100644 --- a/tools/testing/selftests/kvm/x86/msrs_test.c +++ b/tools/testing/selftests/kvm/x86/msrs_test.c @@ -17,9 +17,10 @@ struct kvm_msr { const u64 write_val; const u64 rsvd_val; const u32 index; + const bool is_kvm_defined; }; -#define ____MSR_TEST(msr, str, val, rsvd, reset, feat, f2) \ +#define ____MSR_TEST(msr, str, val, rsvd, reset, feat, f2, is_kvm) \ { \ .index = msr, \ .name = str, \ @@ -28,10 +29,11 @@ struct kvm_msr { .reset_val = reset, \ .feature = X86_FEATURE_ ##feat, \ .feature2 = X86_FEATURE_ ##f2, \ + .is_kvm_defined = is_kvm, \ } #define __MSR_TEST(msr, str, val, rsvd, reset, feat) \ - ____MSR_TEST(msr, str, val, rsvd, reset, feat, feat) + ____MSR_TEST(msr, str, val, rsvd, reset, feat, feat, false) #define MSR_TEST_NON_ZERO(msr, val, rsvd, reset, feat) \ __MSR_TEST(msr, #msr, val, rsvd, reset, feat) @@ -40,7 +42,7 @@ struct kvm_msr { __MSR_TEST(msr, #msr, val, rsvd, 0, feat) #define MSR_TEST2(msr, val, rsvd, feat, f2) \ - ____MSR_TEST(msr, #msr, val, rsvd, 0, feat, f2) + ____MSR_TEST(msr, #msr, val, rsvd, 0, feat, f2, false) /* * Note, use a page aligned value for the canonical value so that the value @@ -58,6 +60,9 @@ static const u64 u64_val = 0xaaaa5555aaaa5555ull; #define MSR_TEST_CANONICAL(msr, feat) \ __MSR_TEST(msr, #msr, canonical_val, NONCANONICAL, 0, feat) +#define MSR_TEST_KVM(msr, val, rsvd, feat) \ + ____MSR_TEST(KVM_REG_ ##msr, #msr, val, rsvd, 0, feat, feat, true) + /* * The main struct must be scoped to a function due to the use of structures to * define features. For the global structure, allocate enough space for the @@ -203,6 +208,83 @@ static void guest_main(void) static bool has_one_reg; static bool use_one_reg; +#define KVM_X86_MAX_NR_REGS 1 + +static bool vcpu_has_reg(struct kvm_vcpu *vcpu, u64 reg) +{ + struct { + struct kvm_reg_list list; + u64 regs[KVM_X86_MAX_NR_REGS]; + } regs = {}; + int r, i; + + /* + * If KVM_GET_REG_LIST succeeds with n=0, i.e. there are no supported + * regs, then the vCPU obviously doesn't support the reg. + */ + r = __vcpu_ioctl(vcpu, KVM_GET_REG_LIST, ®s.list); + if (!r) + return false; + + TEST_ASSERT_EQ(errno, E2BIG); + + /* + * KVM x86 is expected to support enumerating a relative small number + * of regs. The majority of registers supported by KVM_{G,S}ET_ONE_REG + * are enumerated via other ioctls, e.g. KVM_GET_MSR_INDEX_LIST. For + * simplicity, hardcode the maximum number of regs and manually update + * the test as necessary. + */ + TEST_ASSERT(regs.list.n <= KVM_X86_MAX_NR_REGS, + "KVM reports %llu regs, test expects at most %u regs, stale test?", + regs.list.n, KVM_X86_MAX_NR_REGS); + + vcpu_ioctl(vcpu, KVM_GET_REG_LIST, ®s.list); + for (i = 0; i < regs.list.n; i++) { + if (regs.regs[i] == reg) + return true; + } + + return false; +} + +static void host_test_kvm_reg(struct kvm_vcpu *vcpu) +{ + bool has_reg = vcpu_cpuid_has(vcpu, msrs[idx].feature); + u64 reset_val = msrs[idx].reset_val; + u64 write_val = msrs[idx].write_val; + u64 rsvd_val = msrs[idx].rsvd_val; + u32 reg = msrs[idx].index; + u64 val; + int r; + + if (!use_one_reg) + return; + + TEST_ASSERT_EQ(vcpu_has_reg(vcpu, KVM_X86_REG_KVM(reg)), has_reg); + + if (!has_reg) { + r = __vcpu_get_reg(vcpu, KVM_X86_REG_KVM(reg), &val); + TEST_ASSERT(r && errno == EINVAL, + "Expected failure on get_reg(0x%x)", reg); + rsvd_val = 0; + goto out; + } + + val = vcpu_get_reg(vcpu, KVM_X86_REG_KVM(reg)); + TEST_ASSERT(val == reset_val, "Wanted 0x%lx from get_reg(0x%x), got 0x%lx", + reset_val, reg, val); + + vcpu_set_reg(vcpu, KVM_X86_REG_KVM(reg), write_val); + val = vcpu_get_reg(vcpu, KVM_X86_REG_KVM(reg)); + TEST_ASSERT(val == write_val, "Wanted 0x%lx from get_reg(0x%x), got 0x%lx", + write_val, reg, val); + +out: + r = __vcpu_set_reg(vcpu, KVM_X86_REG_KVM(reg), rsvd_val); + TEST_ASSERT(r, "Expected failure on set_reg(0x%x, 0x%lx)", reg, rsvd_val); +} + static void host_test_msr(struct kvm_vcpu *vcpu, u64 guest_val) { u64 reset_val = msrs[idx].reset_val; @@ -314,6 +396,8 @@ static void test_msrs(void) MSR_TEST(MSR_IA32_PL2_SSP, canonical_val, canonical_val | 1, SHSTK), MSR_TEST_CANONICAL(MSR_IA32_PL3_SSP, SHSTK), MSR_TEST(MSR_IA32_PL3_SSP, canonical_val, canonical_val | 1, SHSTK), + + MSR_TEST_KVM(GUEST_SSP, canonical_val, NONCANONICAL, SHSTK), }; const struct kvm_x86_cpu_feature feat_none = X86_FEATURE_NONE; @@ -329,6 +413,7 @@ static void test_msrs(void) const int NR_VCPUS = 3; struct kvm_vcpu *vcpus[NR_VCPUS]; struct kvm_vm *vm; + int i; kvm_static_assert(sizeof(__msrs) <= sizeof(msrs)); kvm_static_assert(ARRAY_SIZE(__msrs) <= ARRAY_SIZE(msrs)); @@ -359,6 +444,12 @@ static void test_msrs(void) } for (idx = 0; idx < ARRAY_SIZE(__msrs); idx++) { + if (msrs[idx].is_kvm_defined) { + for (i = 0; i < NR_VCPUS; i++) + host_test_kvm_reg(vcpus[i]); + continue; + } + sync_global_to_guest(vm, idx); vcpus_run(vcpus, NR_VCPUS); From 947ab90c91983c965acb994455734aae19317596 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 19 Sep 2025 15:32:57 -0700 Subject: [PATCH 2044/2711] KVM: selftests: Verify MSRs are (not) in save/restore list when (un)supported Add a check in the MSRs test to verify that KVM's reported support for MSRs with feature bits is consistent between KVM's MSR save/restore lists and KVM's supported CPUID. To deal with Intel's wonderful decision to bundle IBT and SHSTK under CET, track the "second" feature to avoid false failures when running on a CPU with only one of IBT or SHSTK. Reviewed-by: Chao Gao Link: https://lore.kernel.org/r/20250919223258.1604852-51-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86/msrs_test.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86/msrs_test.c b/tools/testing/selftests/kvm/x86/msrs_test.c index 54ef9c539eb3..40d918aedce6 100644 --- a/tools/testing/selftests/kvm/x86/msrs_test.c +++ b/tools/testing/selftests/kvm/x86/msrs_test.c @@ -444,12 +444,29 @@ static void test_msrs(void) } for (idx = 0; idx < ARRAY_SIZE(__msrs); idx++) { - if (msrs[idx].is_kvm_defined) { + struct kvm_msr *msr = &msrs[idx]; + + if (msr->is_kvm_defined) { for (i = 0; i < NR_VCPUS; i++) host_test_kvm_reg(vcpus[i]); continue; } + /* + * Verify KVM_GET_SUPPORTED_CPUID and KVM_GET_MSR_INDEX_LIST + * are consistent with respect to MSRs whose existence is + * enumerated via CPUID. Skip the check for FS/GS.base MSRs, + * as they aren't reported in the save/restore list since their + * state is managed via SREGS. + */ + TEST_ASSERT(msr->index == MSR_FS_BASE || msr->index == MSR_GS_BASE || + kvm_msr_is_in_save_restore_list(msr->index) == + (kvm_cpu_has(msr->feature) || kvm_cpu_has(msr->feature2)), + "%s %s in save/restore list, but %s according to CPUID", msr->name, + kvm_msr_is_in_save_restore_list(msr->index) ? "is" : "isn't", + (kvm_cpu_has(msr->feature) || kvm_cpu_has(msr->feature2)) ? + "supported" : "unsupported"); + sync_global_to_guest(vm, idx); vcpus_run(vcpus, NR_VCPUS); From d292035fb5d209b78beda356a2a9720154bd7c00 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Fri, 19 Sep 2025 15:32:58 -0700 Subject: [PATCH 2045/2711] KVM: VMX: Make CR4.CET a guest owned bit Make CR4.CET a guest-owned bit under VMX by extending KVM_POSSIBLE_CR4_GUEST_BITS accordingly. There's no need to intercept changes to CR4.CET, as it's neither included in KVM's MMU role bits, nor does KVM specifically care about the actual value of a (nested) guest's CR4.CET value, beside for enforcing architectural constraints, i.e. make sure that CR0.WP=1 if CR4.CET=1. Intercepting writes to CR4.CET is particularly bad for grsecurity kernels with KERNEXEC or, even worse, KERNSEAL enabled. These features heavily make use of read-only kernel objects and use a cpu-local CR0.WP toggle to override it, when needed. Under a CET-enabled kernel, this also requires toggling CR4.CET, hence the motivation to make it guest-owned. Using the old test from [1] gives the following runtime numbers (perf stat -r 5 ssdd 10 50000): * grsec guest on linux-6.16-rc5 + cet patches: 2.4647 +- 0.0706 seconds time elapsed ( +- 2.86% ) * grsec guest on linux-6.16-rc5 + cet patches + CR4.CET guest-owned: 1.5648 +- 0.0240 seconds time elapsed ( +- 1.53% ) Not only does not intercepting CR4.CET make the test run ~35% faster, it's also more stable with less fluctuation due to fewer VMEXITs. Therefore, make CR4.CET a guest-owned bit where possible. This change is VMX-specific, as SVM has no such fine-grained control register intercept control. If KVM's assumptions regarding MMU role handling wrt. a guest's CR4.CET value ever change, the BUILD_BUG_ON()s related to KVM_MMU_CR4_ROLE_BITS and KVM_POSSIBLE_CR4_GUEST_BITS will catch that early. Link: https://lore.kernel.org/kvm/20230322013731.102955-1-minipli@grsecurity.net/ [1] Reviewed-by: Chao Gao Signed-off-by: Mathias Krause Reviewed-by: Binbin Wu Link: https://lore.kernel.org/r/20250919223258.1604852-52-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/kvm_cache_regs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h index 36a8786db291..8ddb01191d6f 100644 --- a/arch/x86/kvm/kvm_cache_regs.h +++ b/arch/x86/kvm/kvm_cache_regs.h @@ -7,7 +7,8 @@ #define KVM_POSSIBLE_CR0_GUEST_BITS (X86_CR0_TS | X86_CR0_WP) #define KVM_POSSIBLE_CR4_GUEST_BITS \ (X86_CR4_PVI | X86_CR4_DE | X86_CR4_PCE | X86_CR4_OSFXSR \ - | X86_CR4_OSXMMEXCPT | X86_CR4_PGE | X86_CR4_TSD | X86_CR4_FSGSBASE) + | X86_CR4_OSXMMEXCPT | X86_CR4_PGE | X86_CR4_TSD | X86_CR4_FSGSBASE \ + | X86_CR4_CET) #define X86_CR0_PDPTR_BITS (X86_CR0_CD | X86_CR0_NW | X86_CR0_PG) #define X86_CR4_TLBFLUSH_BITS (X86_CR4_PGE | X86_CR4_PCIDE | X86_CR4_PAE | X86_CR4_SMEP) From d41e075b077142bb9ae5df40b9ddf9fd7821a811 Mon Sep 17 00:00:00 2001 From: Zhen Ni Date: Tue, 23 Sep 2025 19:21:09 +0800 Subject: [PATCH 2046/2711] remoteproc: pru: Fix potential NULL pointer dereference in pru_rproc_set_ctable() pru_rproc_set_ctable() accessed rproc->priv before the IS_ERR_OR_NULL check, which could lead to a null pointer dereference. Move the pru assignment, ensuring we never dereference a NULL rproc pointer. Fixes: 102853400321 ("remoteproc: pru: Add pru_rproc_set_ctable() function") Cc: stable@vger.kernel.org Signed-off-by: Zhen Ni Link: https://lore.kernel.org/r/20250923112109.1165126-1-zhen.ni@easystack.cn Signed-off-by: Mathieu Poirier --- drivers/remoteproc/pru_rproc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index 842e4b6cc5f9..5e3eb7b86a0e 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -340,7 +340,7 @@ EXPORT_SYMBOL_GPL(pru_rproc_put); */ int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr) { - struct pru_rproc *pru = rproc->priv; + struct pru_rproc *pru; unsigned int reg; u32 mask, set; u16 idx; @@ -352,6 +352,7 @@ int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr) if (!rproc->dev.parent || !is_pru_rproc(rproc->dev.parent)) return -ENODEV; + pru = rproc->priv; /* pointer is 16 bit and index is 8-bit so mask out the rest */ idx_mask = (c >= PRU_C28) ? 0xFFFF : 0xFF; From f3ac2ff14834a0aa056ee3ae0e4b8c641c579961 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 22 Sep 2025 21:46:44 +0530 Subject: [PATCH 2047/2711] PCI/ASPM: Enable all ClockPM and ASPM states for devicetree platforms So far, the PCI subsystem has honored the ASPM and Clock PM states set by the BIOS (through LNKCTL) during device initialization, if it relies on the default state selected using: * Kconfig: CONFIG_PCIEASPM_DEFAULT=y, or * cmdline: "pcie_aspm=off", or * FADT: ACPI_FADT_NO_ASPM This was done conservatively to avoid issues with the buggy devices that advertise ASPM capabilities, but behave erratically if the ASPM states are enabled. So the PCI subsystem ended up trusting the BIOS to enable only the ASPM states that were known to work for the devices. But this turned out to be a problem for devicetree platforms, especially the ARM based devicetree platforms powering Embedded and *some* Compute devices as they tend to run without any standard BIOS. So the ASPM states on these platforms were left disabled during boot and the PCI subsystem never bothered to enable them, unless the user has forcefully enabled the ASPM states through Kconfig, cmdline, and sysfs or the device drivers themselves, enabling the ASPM states through pci_enable_link_state() APIs. This caused runtime power issues on those platforms. So a couple of approaches were tried to mitigate this BIOS dependency without user intervention by enabling the ASPM states in the PCI controller drivers after device enumeration, and overriding the ASPM/Clock PM states by the PCI controller drivers through an API before enumeration. But it has been concluded that none of these mitigations should really be required and the PCI subsystem should enable the ASPM states advertised by the devices without relying on BIOS or the PCI controller drivers. If any device is found to be misbehaving after enabling ASPM states that they advertised, then those devices should be quirked to disable the problematic ASPM/Clock PM states. In an effort to do so, start by overriding the ASPM and Clock PM states set by the BIOS for devicetree platforms first. Separate helper functions are introduced to override the BIOS set states by enabling all of them if of_have_populated_dt() returns true. To aid debugging, print the overridden ASPM and Clock PM states as well. In the future, these helpers could be extended to allow other platforms like VMD, newer ACPI systems with a cutoff year etc... to follow the path. Link: https://lore.kernel.org/linux-pci/20250828204345.GA958461@bhelgaas Suggested-by: Bjorn Helgaas Signed-off-by: Manivannan Sadhasivam [bhelgaas: tweak comments and dmesg logs] Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250922-pci-dt-aspm-v2-1-2a65cf84e326@oss.qualcomm.com --- drivers/pci/pcie/aspm.c | 45 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 919a05b97647..7cc8281e7011 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -235,13 +236,15 @@ struct pcie_link_state { u32 aspm_support:7; /* Supported ASPM state */ u32 aspm_enabled:7; /* Enabled ASPM state */ u32 aspm_capable:7; /* Capable ASPM state with latency */ - u32 aspm_default:7; /* Default ASPM state by BIOS */ + u32 aspm_default:7; /* Default ASPM state by BIOS or + override */ u32 aspm_disable:7; /* Disabled ASPM state */ /* Clock PM state */ u32 clkpm_capable:1; /* Clock PM capable? */ u32 clkpm_enabled:1; /* Current Clock PM state */ - u32 clkpm_default:1; /* Default Clock PM state by BIOS */ + u32 clkpm_default:1; /* Default Clock PM state by BIOS or + override */ u32 clkpm_disable:1; /* Clock PM disabled */ }; @@ -373,6 +376,18 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable) pcie_set_clkpm_nocheck(link, enable); } +static void pcie_clkpm_override_default_link_state(struct pcie_link_state *link, + int enabled) +{ + struct pci_dev *pdev = link->downstream; + + /* For devicetree platforms, enable ClockPM by default */ + if (of_have_populated_dt() && !enabled) { + link->clkpm_default = 1; + pci_info(pdev, "ASPM: DT platform, enabling ClockPM\n"); + } +} + static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) { int capable = 1, enabled = 1; @@ -395,6 +410,7 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) } link->clkpm_enabled = enabled; link->clkpm_default = enabled; + pcie_clkpm_override_default_link_state(link, enabled); link->clkpm_capable = capable; link->clkpm_disable = blacklist ? 1 : 0; } @@ -788,6 +804,29 @@ static void aspm_l1ss_init(struct pcie_link_state *link) aspm_calc_l12_info(link, parent_l1ss_cap, child_l1ss_cap); } +#define FLAG(x, y, d) (((x) & (PCIE_LINK_STATE_##y)) ? d : "") + +static void pcie_aspm_override_default_link_state(struct pcie_link_state *link) +{ + struct pci_dev *pdev = link->downstream; + u32 override; + + /* For devicetree platforms, enable all ASPM states by default */ + if (of_have_populated_dt()) { + link->aspm_default = PCIE_LINK_STATE_ASPM_ALL; + override = link->aspm_default & ~link->aspm_enabled; + if (override) + pci_info(pdev, "ASPM: DT platform, enabling%s%s%s%s%s%s%s\n", + FLAG(override, L0S_UP, " L0s-up"), + FLAG(override, L0S_DW, " L0s-dw"), + FLAG(override, L1, " L1"), + FLAG(override, L1_1, " ASPM-L1.1"), + FLAG(override, L1_2, " ASPM-L1.2"), + FLAG(override, L1_1_PCIPM, " PCI-PM-L1.1"), + FLAG(override, L1_2_PCIPM, " PCI-PM-L1.2")); + } +} + static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) { struct pci_dev *child = link->downstream, *parent = link->pdev; @@ -868,6 +907,8 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) /* Save default state */ link->aspm_default = link->aspm_enabled; + pcie_aspm_override_default_link_state(link); + /* Setup initial capable state. Will be updated later */ link->aspm_capable = link->aspm_support; From a729c16646198872e345bf6c48dbe540ad8a9753 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 22 Sep 2025 21:46:45 +0530 Subject: [PATCH 2048/2711] PCI: qcom: Remove custom ASPM enablement code Since the PCI subsystem has started enabling all ASPM states for all devicetree based platforms, the ASPM enablement code from this driver can now be dropped. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250922-pci-dt-aspm-v2-2-2a65cf84e326@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-qcom.c | 32 -------------------------- 1 file changed, 32 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 294babe1816e..a1c4a9c31f92 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -247,7 +247,6 @@ struct qcom_pcie_ops { int (*get_resources)(struct qcom_pcie *pcie); int (*init)(struct qcom_pcie *pcie); int (*post_init)(struct qcom_pcie *pcie); - void (*host_post_init)(struct qcom_pcie *pcie); void (*deinit)(struct qcom_pcie *pcie); void (*ltssm_enable)(struct qcom_pcie *pcie); int (*config_sid)(struct qcom_pcie *pcie); @@ -1040,25 +1039,6 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) return 0; } -static int qcom_pcie_enable_aspm(struct pci_dev *pdev, void *userdata) -{ - /* - * Downstream devices need to be in D0 state before enabling PCI PM - * substates. - */ - pci_set_power_state_locked(pdev, PCI_D0); - pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL); - - return 0; -} - -static void qcom_pcie_host_post_init_2_7_0(struct qcom_pcie *pcie) -{ - struct dw_pcie_rp *pp = &pcie->pci->pp; - - pci_walk_bus(pp->bridge->bus, qcom_pcie_enable_aspm, NULL); -} - static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie) { struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0; @@ -1358,19 +1338,9 @@ static void qcom_pcie_host_deinit(struct dw_pcie_rp *pp) pcie->cfg->ops->deinit(pcie); } -static void qcom_pcie_host_post_init(struct dw_pcie_rp *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct qcom_pcie *pcie = to_qcom_pcie(pci); - - if (pcie->cfg->ops->host_post_init) - pcie->cfg->ops->host_post_init(pcie); -} - static const struct dw_pcie_host_ops qcom_pcie_dw_ops = { .init = qcom_pcie_host_init, .deinit = qcom_pcie_host_deinit, - .post_init = qcom_pcie_host_post_init, }; /* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */ @@ -1432,7 +1402,6 @@ static const struct qcom_pcie_ops ops_1_9_0 = { .get_resources = qcom_pcie_get_resources_2_7_0, .init = qcom_pcie_init_2_7_0, .post_init = qcom_pcie_post_init_2_7_0, - .host_post_init = qcom_pcie_host_post_init_2_7_0, .deinit = qcom_pcie_deinit_2_7_0, .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, .config_sid = qcom_pcie_config_sid_1_9_0, @@ -1443,7 +1412,6 @@ static const struct qcom_pcie_ops ops_1_21_0 = { .get_resources = qcom_pcie_get_resources_2_7_0, .init = qcom_pcie_init_2_7_0, .post_init = qcom_pcie_post_init_2_7_0, - .host_post_init = qcom_pcie_host_post_init_2_7_0, .deinit = qcom_pcie_deinit_2_7_0, .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, }; From 492263fd564c882a7170a58d3dffb4574de042d4 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:38:57 +0530 Subject: [PATCH 2049/2711] dt-bindings: mailbox: Add bindings for RPMI shared memory transport Add device tree bindings for the common RISC-V Platform Management Interface (RPMI) shared memory transport as a mailbox controller. Reviewed-by: Conor Dooley Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-2-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- .../mailbox/riscv,rpmi-shmem-mbox.yaml | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 Documentation/devicetree/bindings/mailbox/riscv,rpmi-shmem-mbox.yaml diff --git a/Documentation/devicetree/bindings/mailbox/riscv,rpmi-shmem-mbox.yaml b/Documentation/devicetree/bindings/mailbox/riscv,rpmi-shmem-mbox.yaml new file mode 100644 index 000000000000..3aabc52a0c03 --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/riscv,rpmi-shmem-mbox.yaml @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mailbox/riscv,rpmi-shmem-mbox.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V Platform Management Interface (RPMI) shared memory mailbox + +maintainers: + - Anup Patel + +description: | + The RISC-V Platform Management Interface (RPMI) [1] defines a common shared + memory based RPMI transport. This RPMI shared memory transport integrates as + mailbox controller in the SBI implementation or supervisor software whereas + each RPMI service group is mailbox client in the SBI implementation and + supervisor software. + + =========================================== + References + =========================================== + + [1] RISC-V Platform Management Interface (RPMI) v1.0 (or higher) + https://github.com/riscv-non-isa/riscv-rpmi/releases + +properties: + compatible: + const: riscv,rpmi-shmem-mbox + + reg: + minItems: 2 + items: + - description: A2P request queue base address + - description: P2A acknowledgment queue base address + - description: P2A request queue base address + - description: A2P acknowledgment queue base address + - description: A2P doorbell address + + reg-names: + minItems: 2 + items: + - const: a2p-req + - const: p2a-ack + - enum: [ p2a-req, a2p-doorbell ] + - const: a2p-ack + - const: a2p-doorbell + + interrupts: + maxItems: 1 + description: + The RPMI shared memory transport supports P2A doorbell as a wired + interrupt and this property specifies the interrupt source. + + msi-parent: + description: + The RPMI shared memory transport supports P2A doorbell as a system MSI + and this property specifies the target MSI controller. + + riscv,slot-size: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 64 + description: + Power-of-2 RPMI slot size of the RPMI shared memory transport. + + riscv,a2p-doorbell-value: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0x1 + description: + Value written to the 32-bit A2P doorbell register. + + riscv,p2a-doorbell-sysmsi-index: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The RPMI shared memory transport supports P2A doorbell as a system MSI + and this property specifies system MSI index to be used for configuring + the P2A doorbell MSI. + + "#mbox-cells": + const: 1 + description: + The first cell specifies RPMI service group ID. + +required: + - compatible + - reg + - reg-names + - riscv,slot-size + - "#mbox-cells" + +anyOf: + - required: + - interrupts + - required: + - msi-parent + +additionalProperties: false + +examples: + - | + // Example 1 (RPMI shared memory with only 2 queues): + mailbox@10080000 { + compatible = "riscv,rpmi-shmem-mbox"; + reg = <0x10080000 0x10000>, + <0x10090000 0x10000>; + reg-names = "a2p-req", "p2a-ack"; + msi-parent = <&imsic_mlevel>; + riscv,slot-size = <64>; + #mbox-cells = <1>; + }; + - | + // Example 2 (RPMI shared memory with only 4 queues): + mailbox@10001000 { + compatible = "riscv,rpmi-shmem-mbox"; + reg = <0x10001000 0x800>, + <0x10001800 0x800>, + <0x10002000 0x800>, + <0x10002800 0x800>, + <0x10003000 0x4>; + reg-names = "a2p-req", "p2a-ack", "p2a-req", "a2p-ack", "a2p-doorbell"; + msi-parent = <&imsic_mlevel>; + riscv,slot-size = <64>; + riscv,a2p-doorbell-value = <0x00008000>; + #mbox-cells = <1>; + }; From 0e0ba0ecec3d6e819e0c2348331ff99afe2eb5d5 Mon Sep 17 00:00:00 2001 From: Xiaowei Li Date: Wed, 24 Sep 2025 11:16:50 +0800 Subject: [PATCH 2050/2711] USB: serial: option: add SIMCom 8230C compositions Add support for SIMCom 8230C which is based on Qualcomm SDX35 chip. USB Device Listings: 0x9071: tty (DM) + tty (NMEA) + tty (AT) + rmnet (QMI mode) + adb T: Bus=01 Lev=01 Prnt=01 Port=05 Cnt=02 Dev#= 10 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1e0e ProdID=9071 Rev= 5.15 S: Manufacturer=SIMCOM S: Product=SDXBAAGHA-IDP _SN:D744C4C5 S: SerialNumber=0123456789ABCDEF C:* #Ifs= 5 Cfg#= 1 Atr=a0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=50 Driver=qmi_wwan E: Ad=86(I) Atr=03(Int.) MxPS= 8 Ivl=32ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms 0x9078: tty (DM) + tty (NMEA) + tty (AT) + ECM + adb T: Bus=01 Lev=01 Prnt=01 Port=05 Cnt=02 Dev#= 9 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1e0e ProdID=9078 Rev= 5.15 S: Manufacturer=SIMCOM S: Product=SDXBAAGHA-IDP _SN:D744C4C5 S: SerialNumber=0123456789ABCDEF C:* #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=06 Prot=00 Driver=cdc_ether E: Ad=86(I) Atr=03(Int.) MxPS= 16 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=00 Driver=cdc_ether I:* If#= 4 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=cdc_ether E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms 0x907b: RNDIS + tty (DM) + tty (NMEA) + tty (AT) + adb T: Bus=01 Lev=01 Prnt=01 Port=05 Cnt=02 Dev#= 8 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1e0e ProdID=907b Rev= 5.15 S: Manufacturer=SIMCOM S: Product=SDXBAAGHA-IDP _SN:D744C4C5 S: SerialNumber=0123456789ABCDEF C:* #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA A: FirstIf#= 0 IfCount= 2 Cls=ef(misc ) Sub=04 Prot=01 I:* If#= 0 Alt= 0 #EPs= 1 Cls=ef(misc ) Sub=04 Prot=01 Driver=rndis_host E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=rndis_host E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms Signed-off-by: Xiaowei Li Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold --- drivers/usb/serial/option.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e5cd33093423..e62e6422de26 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2097,6 +2097,12 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9003, 0xff) }, /* Simcom SIM7500/SIM7600 MBIM mode */ { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9011, 0xff), /* Simcom SIM7500/SIM7600 RNDIS mode */ .driver_info = RSVD(7) }, + { USB_DEVICE(0x1e0e, 0x9071), /* Simcom SIM8230 RMNET mode */ + .driver_info = RSVD(3) | RSVD(4) }, + { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9078, 0xff), /* Simcom SIM8230 ECM mode */ + .driver_info = RSVD(5) }, + { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x907b, 0xff), /* Simcom SIM8230 RNDIS mode */ + .driver_info = RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9205, 0xff) }, /* Simcom SIM7070/SIM7080/SIM7090 AT+ECM mode */ { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9206, 0xff) }, /* Simcom SIM7070/SIM7080/SIM7090 AT-only mode */ { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), From d335230cb29b7f578dba0b770d97cd320c83892b Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 23 Sep 2025 00:29:40 +0300 Subject: [PATCH 2051/2711] HID: playstation: Update SP preamp gain comment line Adjusting speaker pre-amp gain to 0x2 indicates +6dB, hence update the related comment line accordingly. Suggested-by: Roderick Colenbrander Signed-off-by: Cristian Ciocaltea Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index d2bee1a314b1..e03ab8a92bca 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -1372,7 +1372,7 @@ static void dualsense_output_worker(struct work_struct *work) */ common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_SPEAKER_VOLUME_ENABLE; common->speaker_volume = 0x64; - /* Set SP preamp gain to ~30% */ + /* Set SP preamp gain to +6dB */ common->valid_flag1 = DS_OUTPUT_VALID_FLAG1_AUDIO_CONTROL2_ENABLE; common->audio_control2 = FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS2_SP_PREAMP_GAIN, 0x2); From 3969f77f5dd5c69d513a33f350128e61e0e1ab00 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 23 Sep 2025 00:29:41 +0300 Subject: [PATCH 2052/2711] HID: playstation: Silence sparse warnings for locking context imbalances It seems sparse has some difficulties with guard() handling or when mixing it with scoped_guard(), as it shows a bunch lock related warnings: hid-playstation.c:1230:32: warning: context imbalance in 'dualsense_player_led_set_brightness' - wrong count at exit hid-playstation.c:1414:12: warning: context imbalance in 'dualsense_parse_report' - wrong count at exit hid-playstation.c:1615:12: warning: context imbalance in 'dualsense_play_effect' - different lock contexts for basic block hid-playstation.c:1668:13: warning: context imbalance in 'dualsense_set_lightbar' - wrong count at exit hid-playstation.c:1680:13: warning: context imbalance in 'dualsense_set_player_leds' - wrong count at exit hid-playstation.c:2185:33: warning: context imbalance in 'dualshock4_led_set_blink' - wrong count at exit hid-playstation.c:2226:33: warning: context imbalance in 'dualshock4_led_set_brightness' - wrong count at exit hid-playstation.c:2596:12: warning: context imbalance in 'dualshock4_play_effect' - different lock contexts for basic block hid-playstation.c:2634:13: warning: context imbalance in 'dualshock4_set_bt_poll_interval' - wrong count at exit hid-playstation.c:2642:13: warning: context imbalance in 'dualshock4_set_default_lightbar_colors' - wrong count at exit Silent them by switching from guard() to scoped_guard() in {dualsense|dualshock4}_schedule_work(). Reported-by: Benjamin Tissoires Suggested-by: Benjamin Tissoires Signed-off-by: Cristian Ciocaltea Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index e03ab8a92bca..87038dacebe7 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -1274,9 +1274,10 @@ static void dualsense_init_output_report(struct dualsense *ds, static inline void dualsense_schedule_work(struct dualsense *ds) { - guard(spinlock_irqsave)(&ds->base.lock); - if (ds->output_worker_initialized) - schedule_work(&ds->output_worker); + /* Using scoped_guard() instead of guard() to make sparse happy */ + scoped_guard(spinlock_irqsave, &ds->base.lock) + if (ds->output_worker_initialized) + schedule_work(&ds->output_worker); } /* @@ -2626,9 +2627,10 @@ static void dualshock4_remove(struct ps_device *ps_dev) static inline void dualshock4_schedule_work(struct dualshock4 *ds4) { - guard(spinlock_irqsave)(&ds4->base.lock); - if (ds4->output_worker_initialized) - schedule_work(&ds4->output_worker); + /* Using scoped_guard() instead of guard() to make sparse happy */ + scoped_guard(spinlock_irqsave, &ds4->base.lock) + if (ds4->output_worker_initialized) + schedule_work(&ds4->output_worker); } static void dualshock4_set_bt_poll_interval(struct dualshock4 *ds4, u8 interval) From 8aa035a8407f6b6e999afa33839e38267fdc8790 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 23 Sep 2025 00:29:42 +0300 Subject: [PATCH 2053/2711] HID: playstation: Switch to scoped_guard() in {dualsense|dualshock4}_output_worker() Those functions were initially excepted from using the scoped_guard() infrastructure as they contain too many long statements, while adding yet another level of indentation seemed to lower readability without bringing an immediate benefit. However, consistency should be more important, hence do the switch and get rid of the remaining explicit acquires & releases of the spinlocks. Signed-off-by: Cristian Ciocaltea Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 258 +++++++++++++++++----------------- 1 file changed, 130 insertions(+), 128 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 87038dacebe7..63f6eb9030d1 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -1308,107 +1308,112 @@ static void dualsense_output_worker(struct work_struct *work) struct dualsense *ds = container_of(work, struct dualsense, output_worker); struct dualsense_output_report report; struct dualsense_output_report_common *common; - unsigned long flags; dualsense_init_output_report(ds, &report, ds->output_report_dmabuf); common = report.common; - spin_lock_irqsave(&ds->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds->base.lock) { + if (ds->update_rumble) { + /* Select classic rumble style haptics and enable it. */ + common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT; + if (ds->use_vibration_v2) + common->valid_flag2 |= DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2; + else + common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION; + common->motor_left = ds->motor_left; + common->motor_right = ds->motor_right; + ds->update_rumble = false; + } - if (ds->update_rumble) { - /* Select classic rumble style haptics and enable it. */ - common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT; - if (ds->use_vibration_v2) - common->valid_flag2 |= DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2; - else - common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION; - common->motor_left = ds->motor_left; - common->motor_right = ds->motor_right; - ds->update_rumble = false; - } + if (ds->update_lightbar) { + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE; + common->lightbar_red = ds->lightbar_red; + common->lightbar_green = ds->lightbar_green; + common->lightbar_blue = ds->lightbar_blue; - if (ds->update_lightbar) { - common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE; - common->lightbar_red = ds->lightbar_red; - common->lightbar_green = ds->lightbar_green; - common->lightbar_blue = ds->lightbar_blue; + ds->update_lightbar = false; + } - ds->update_lightbar = false; - } + if (ds->update_player_leds) { + common->valid_flag1 |= + DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE; + common->player_leds = ds->player_leds_state; - if (ds->update_player_leds) { - common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE; - common->player_leds = ds->player_leds_state; + ds->update_player_leds = false; + } - ds->update_player_leds = false; - } + if (ds->plugged_state != ds->prev_plugged_state) { + u8 val = ds->plugged_state & DS_STATUS1_HP_DETECT; - if (ds->plugged_state != ds->prev_plugged_state) { - u8 val = ds->plugged_state & DS_STATUS1_HP_DETECT; - - if (val != (ds->prev_plugged_state & DS_STATUS1_HP_DETECT)) { - common->valid_flag0 = DS_OUTPUT_VALID_FLAG0_AUDIO_CONTROL_ENABLE; - /* - * _--------> Output path setup in audio_flag0 - * / _------> Headphone (HP) Left channel sink - * | / _----> Headphone (HP) Right channel sink - * | | / _--> Internal Speaker (SP) sink - * | | | / - * | | | | L/R - Left/Right channel source - * 0 L-R X X - Unrouted (muted) channel source - * 1 L-L X - * 2 L-L R - * 3 X-X R - */ - if (val) { - /* Mute SP and route L+R channels to HP */ - common->audio_control = 0; - } else { - /* Mute HP and route R channel to SP */ - common->audio_control = - FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS_OUTPUT_PATH_SEL, 0x3); + if (val != (ds->prev_plugged_state & DS_STATUS1_HP_DETECT)) { + common->valid_flag0 = DS_OUTPUT_VALID_FLAG0_AUDIO_CONTROL_ENABLE; /* - * Set SP hardware volume to 100%. - * Note the accepted range seems to be [0x3d..0x64] + * _--------> Output path setup in audio_flag0 + * / _------> Headphone (HP) Left channel sink + * | / _----> Headphone (HP) Right channel sink + * | | / _--> Internal Speaker (SP) sink + * | | | / + * | | | | L/R - Left/Right channel source + * 0 L-R X X - Unrouted (muted) channel source + * 1 L-L X + * 2 L-L R + * 3 X-X R */ - common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_SPEAKER_VOLUME_ENABLE; - common->speaker_volume = 0x64; - /* Set SP preamp gain to +6dB */ - common->valid_flag1 = DS_OUTPUT_VALID_FLAG1_AUDIO_CONTROL2_ENABLE; - common->audio_control2 = - FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS2_SP_PREAMP_GAIN, 0x2); + if (val) { + /* Mute SP and route L+R channels to HP */ + common->audio_control = 0; + } else { + /* Mute HP and route R channel to SP */ + common->audio_control = + FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS_OUTPUT_PATH_SEL, + 0x3); + /* + * Set SP hardware volume to 100%. + * Note the accepted range seems to be [0x3d..0x64] + */ + common->valid_flag0 |= + DS_OUTPUT_VALID_FLAG0_SPEAKER_VOLUME_ENABLE; + common->speaker_volume = 0x64; + /* Set SP preamp gain to +6dB */ + common->valid_flag1 = + DS_OUTPUT_VALID_FLAG1_AUDIO_CONTROL2_ENABLE; + common->audio_control2 = + FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS2_SP_PREAMP_GAIN, + 0x2); + } + + input_report_switch(ds->jack, SW_HEADPHONE_INSERT, val); } - input_report_switch(ds->jack, SW_HEADPHONE_INSERT, val); + val = ds->plugged_state & DS_STATUS1_MIC_DETECT; + if (val != (ds->prev_plugged_state & DS_STATUS1_MIC_DETECT)) + input_report_switch(ds->jack, SW_MICROPHONE_INSERT, val); + + input_sync(ds->jack); + ds->prev_plugged_state = ds->plugged_state; } - val = ds->plugged_state & DS_STATUS1_MIC_DETECT; - if (val != (ds->prev_plugged_state & DS_STATUS1_MIC_DETECT)) - input_report_switch(ds->jack, SW_MICROPHONE_INSERT, val); + if (ds->update_mic_mute) { + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE; + common->mute_button_led = ds->mic_muted; - input_sync(ds->jack); - ds->prev_plugged_state = ds->plugged_state; - } + if (ds->mic_muted) { + /* Disable microphone */ + common->valid_flag1 |= + DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE; + common->power_save_control |= DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE; + } else { + /* Enable microphone */ + common->valid_flag1 |= + DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE; + common->power_save_control &= + ~DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE; + } - if (ds->update_mic_mute) { - common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE; - common->mute_button_led = ds->mic_muted; - - if (ds->mic_muted) { - /* Disable microphone */ - common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE; - common->power_save_control |= DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE; - } else { - /* Enable microphone */ - common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE; - common->power_save_control &= ~DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE; + ds->update_mic_mute = false; } - - ds->update_mic_mute = false; } - spin_unlock_irqrestore(&ds->base.lock, flags); - dualsense_send_output_report(ds, &report); } @@ -2264,61 +2269,58 @@ static void dualshock4_output_worker(struct work_struct *work) struct dualshock4 *ds4 = container_of(work, struct dualshock4, output_worker); struct dualshock4_output_report report; struct dualshock4_output_report_common *common; - unsigned long flags; dualshock4_init_output_report(ds4, &report, ds4->output_report_dmabuf); common = report.common; - spin_lock_irqsave(&ds4->base.lock, flags); - - /* - * Some 3rd party gamepads expect updates to rumble and lightbar - * together, and setting one may cancel the other. - * - * Let's maximise compatibility by always sending rumble and lightbar - * updates together, even when only one has been scheduled, resulting - * in: - * - * ds4->valid_flag0 >= 0x03 - * - * Hopefully this will maximise compatibility with third-party pads. - * - * Any further update bits, such as 0x04 for lightbar blinking, will - * be or'd on top of this like before. - */ - if (ds4->update_rumble || ds4->update_lightbar) { - ds4->update_rumble = true; /* 0x01 */ - ds4->update_lightbar = true; /* 0x02 */ - } - - if (ds4->update_rumble) { - /* Select classic rumble style haptics and enable it. */ - common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_MOTOR; - common->motor_left = ds4->motor_left; - common->motor_right = ds4->motor_right; - ds4->update_rumble = false; - } - - if (ds4->update_lightbar) { - common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED; - /* Compatible behavior with hid-sony, which used a dummy global LED to - * allow enabling/disabling the lightbar. The global LED maps to - * lightbar_enabled. + scoped_guard(spinlock_irqsave, &ds4->base.lock) { + /* + * Some 3rd party gamepads expect updates to rumble and lightbar + * together, and setting one may cancel the other. + * + * Let's maximise compatibility by always sending rumble and lightbar + * updates together, even when only one has been scheduled, resulting + * in: + * + * ds4->valid_flag0 >= 0x03 + * + * Hopefully this will maximise compatibility with third-party pads. + * + * Any further update bits, such as 0x04 for lightbar blinking, will + * be or'd on top of this like before. */ - common->lightbar_red = ds4->lightbar_enabled ? ds4->lightbar_red : 0; - common->lightbar_green = ds4->lightbar_enabled ? ds4->lightbar_green : 0; - common->lightbar_blue = ds4->lightbar_enabled ? ds4->lightbar_blue : 0; - ds4->update_lightbar = false; - } + if (ds4->update_rumble || ds4->update_lightbar) { + ds4->update_rumble = true; /* 0x01 */ + ds4->update_lightbar = true; /* 0x02 */ + } - if (ds4->update_lightbar_blink) { - common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED_BLINK; - common->lightbar_blink_on = ds4->lightbar_blink_on; - common->lightbar_blink_off = ds4->lightbar_blink_off; - ds4->update_lightbar_blink = false; - } + if (ds4->update_rumble) { + /* Select classic rumble style haptics and enable it. */ + common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_MOTOR; + common->motor_left = ds4->motor_left; + common->motor_right = ds4->motor_right; + ds4->update_rumble = false; + } - spin_unlock_irqrestore(&ds4->base.lock, flags); + if (ds4->update_lightbar) { + common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED; + /* Compatible behavior with hid-sony, which used a dummy global LED to + * allow enabling/disabling the lightbar. The global LED maps to + * lightbar_enabled. + */ + common->lightbar_red = ds4->lightbar_enabled ? ds4->lightbar_red : 0; + common->lightbar_green = ds4->lightbar_enabled ? ds4->lightbar_green : 0; + common->lightbar_blue = ds4->lightbar_enabled ? ds4->lightbar_blue : 0; + ds4->update_lightbar = false; + } + + if (ds4->update_lightbar_blink) { + common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED_BLINK; + common->lightbar_blink_on = ds4->lightbar_blink_on; + common->lightbar_blink_off = ds4->lightbar_blink_off; + ds4->update_lightbar_blink = false; + } + } /* Bluetooth packets need additional flags as well as a CRC in the last 4 bytes. */ if (report.bt) { From e7e2296b0ecf9b6e934f7a1118cee91d4d486a84 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 25 Aug 2025 15:18:05 -0300 Subject: [PATCH 2054/2711] rust: usb: add basic USB abstractions Add basic USB abstractions, consisting of usb::{Device, Interface, Driver, Adapter, DeviceId} and the module_usb_driver macro. This is the first step in being able to write USB device drivers, which paves the way for USB media drivers - for example - among others. This initial support will then be used by a subsequent sample driver, which constitutes the only user of the USB abstractions so far. Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250825-b4-usb-v1-1-7aa024de7ae8@collabora.com [ force USB = y for now - gregkh ] Signed-off-by: Greg Kroah-Hartman --- rust/bindings/bindings_helper.h | 1 + rust/helpers/helpers.c | 1 + rust/helpers/usb.c | 8 + rust/kernel/lib.rs | 2 + rust/kernel/usb.rs | 457 ++++++++++++++++++++++++++++++++ 5 files changed, 469 insertions(+) create mode 100644 rust/helpers/usb.c create mode 100644 rust/kernel/usb.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 9b3a4ab95818..41cd42cd286f 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -74,6 +74,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 8e8277bdddca..04103ab1a349 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -48,6 +48,7 @@ #include "task.c" #include "time.c" #include "uaccess.c" +#include "usb.c" #include "vmalloc.c" #include "wait.c" #include "workqueue.c" diff --git a/rust/helpers/usb.c b/rust/helpers/usb.c new file mode 100644 index 000000000000..fb2aad0cbf4d --- /dev/null +++ b/rust/helpers/usb.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +struct usb_device *rust_helper_interface_to_usbdev(struct usb_interface *intf) +{ + return interface_to_usbdev(intf); +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 99dbb7b2812e..004ca70b816d 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -127,6 +127,8 @@ pub mod time; pub mod tracepoint; pub mod transmute; pub mod types; +#[cfg(CONFIG_USB = "y")] +pub mod usb; pub mod uaccess; pub mod workqueue; pub mod xarray; diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs new file mode 100644 index 000000000000..8899e7520b58 --- /dev/null +++ b/rust/kernel/usb.rs @@ -0,0 +1,457 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (C) 2025 Collabora Ltd. + +//! Abstractions for the USB bus. +//! +//! C header: [`include/linux/usb.h`](srctree/include/linux/usb.h) + +use crate::{ + bindings, device, + device_id::{RawDeviceId, RawDeviceIdIndex}, + driver, + error::{from_result, to_result, Result}, + prelude::*, + str::CStr, + types::{AlwaysRefCounted, Opaque}, + ThisModule, +}; +use core::{marker::PhantomData, mem::MaybeUninit, ptr::NonNull}; + +/// An adapter for the registration of USB drivers. +pub struct Adapter(T); + +// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if +// a preceding call to `register` has been successful. +unsafe impl driver::RegistrationOps for Adapter { + type RegType = bindings::usb_driver; + + unsafe fn register( + udrv: &Opaque, + name: &'static CStr, + module: &'static ThisModule, + ) -> Result { + // SAFETY: It's safe to set the fields of `struct usb_driver` on initialization. + unsafe { + (*udrv.get()).name = name.as_char_ptr(); + (*udrv.get()).probe = Some(Self::probe_callback); + (*udrv.get()).disconnect = Some(Self::disconnect_callback); + (*udrv.get()).id_table = T::ID_TABLE.as_ptr(); + } + + // SAFETY: `udrv` is guaranteed to be a valid `RegType`. + to_result(unsafe { + bindings::usb_register_driver(udrv.get(), module.0, name.as_char_ptr()) + }) + } + + unsafe fn unregister(udrv: &Opaque) { + // SAFETY: `udrv` is guaranteed to be a valid `RegType`. + unsafe { bindings::usb_deregister(udrv.get()) }; + } +} + +impl Adapter { + extern "C" fn probe_callback( + intf: *mut bindings::usb_interface, + id: *const bindings::usb_device_id, + ) -> kernel::ffi::c_int { + // SAFETY: The USB core only ever calls the probe callback with a valid pointer to a + // `struct usb_interface` and `struct usb_device_id`. + // + // INVARIANT: `intf` is valid for the duration of `probe_callback()`. + let intf = unsafe { &*intf.cast::>() }; + + from_result(|| { + // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct usb_device_id` and + // does not add additional invariants, so it's safe to transmute. + let id = unsafe { &*id.cast::() }; + + let info = T::ID_TABLE.info(id.index()); + let data = T::probe(intf, id, info)?; + + let dev: &device::Device = intf.as_ref(); + dev.set_drvdata(data); + Ok(0) + }) + } + + extern "C" fn disconnect_callback(intf: *mut bindings::usb_interface) { + // SAFETY: The USB core only ever calls the disconnect callback with a valid pointer to a + // `struct usb_interface`. + // + // INVARIANT: `intf` is valid for the duration of `disconnect_callback()`. + let intf = unsafe { &*intf.cast::>() }; + + let dev: &device::Device = intf.as_ref(); + + // SAFETY: `disconnect_callback` is only ever called after a successful call to + // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called + // and stored a `Pin>`. + let data = unsafe { dev.drvdata_obtain::>>() }; + + T::disconnect(intf, data.as_ref()); + } +} + +/// Abstraction for the USB device ID structure, i.e. [`struct usb_device_id`]. +/// +/// [`struct usb_device_id`]: https://docs.kernel.org/driver-api/basics.html#c.usb_device_id +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct DeviceId(bindings::usb_device_id); + +impl DeviceId { + /// Equivalent to C's `USB_DEVICE` macro. + pub const fn from_id(vendor: u16, product: u16) -> Self { + Self(bindings::usb_device_id { + match_flags: bindings::USB_DEVICE_ID_MATCH_DEVICE as u16, + idVendor: vendor, + idProduct: product, + // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. + ..unsafe { MaybeUninit::zeroed().assume_init() } + }) + } + + /// Equivalent to C's `USB_DEVICE_VER` macro. + pub const fn from_device_ver(vendor: u16, product: u16, bcd_lo: u16, bcd_hi: u16) -> Self { + Self(bindings::usb_device_id { + match_flags: bindings::USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION as u16, + idVendor: vendor, + idProduct: product, + bcdDevice_lo: bcd_lo, + bcdDevice_hi: bcd_hi, + // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. + ..unsafe { MaybeUninit::zeroed().assume_init() } + }) + } + + /// Equivalent to C's `USB_DEVICE_INFO` macro. + pub const fn from_device_info(class: u8, subclass: u8, protocol: u8) -> Self { + Self(bindings::usb_device_id { + match_flags: bindings::USB_DEVICE_ID_MATCH_DEV_INFO as u16, + bDeviceClass: class, + bDeviceSubClass: subclass, + bDeviceProtocol: protocol, + // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. + ..unsafe { MaybeUninit::zeroed().assume_init() } + }) + } + + /// Equivalent to C's `USB_INTERFACE_INFO` macro. + pub const fn from_interface_info(class: u8, subclass: u8, protocol: u8) -> Self { + Self(bindings::usb_device_id { + match_flags: bindings::USB_DEVICE_ID_MATCH_INT_INFO as u16, + bInterfaceClass: class, + bInterfaceSubClass: subclass, + bInterfaceProtocol: protocol, + // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. + ..unsafe { MaybeUninit::zeroed().assume_init() } + }) + } + + /// Equivalent to C's `USB_DEVICE_INTERFACE_CLASS` macro. + pub const fn from_device_interface_class(vendor: u16, product: u16, class: u8) -> Self { + Self(bindings::usb_device_id { + match_flags: (bindings::USB_DEVICE_ID_MATCH_DEVICE + | bindings::USB_DEVICE_ID_MATCH_INT_CLASS) as u16, + idVendor: vendor, + idProduct: product, + bInterfaceClass: class, + // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. + ..unsafe { MaybeUninit::zeroed().assume_init() } + }) + } + + /// Equivalent to C's `USB_DEVICE_INTERFACE_PROTOCOL` macro. + pub const fn from_device_interface_protocol(vendor: u16, product: u16, protocol: u8) -> Self { + Self(bindings::usb_device_id { + match_flags: (bindings::USB_DEVICE_ID_MATCH_DEVICE + | bindings::USB_DEVICE_ID_MATCH_INT_PROTOCOL) as u16, + idVendor: vendor, + idProduct: product, + bInterfaceProtocol: protocol, + // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. + ..unsafe { MaybeUninit::zeroed().assume_init() } + }) + } + + /// Equivalent to C's `USB_DEVICE_INTERFACE_NUMBER` macro. + pub const fn from_device_interface_number(vendor: u16, product: u16, number: u8) -> Self { + Self(bindings::usb_device_id { + match_flags: (bindings::USB_DEVICE_ID_MATCH_DEVICE + | bindings::USB_DEVICE_ID_MATCH_INT_NUMBER) as u16, + idVendor: vendor, + idProduct: product, + bInterfaceNumber: number, + // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. + ..unsafe { MaybeUninit::zeroed().assume_init() } + }) + } + + /// Equivalent to C's `USB_DEVICE_AND_INTERFACE_INFO` macro. + pub const fn from_device_and_interface_info( + vendor: u16, + product: u16, + class: u8, + subclass: u8, + protocol: u8, + ) -> Self { + Self(bindings::usb_device_id { + match_flags: (bindings::USB_DEVICE_ID_MATCH_INT_INFO + | bindings::USB_DEVICE_ID_MATCH_DEVICE) as u16, + idVendor: vendor, + idProduct: product, + bInterfaceClass: class, + bInterfaceSubClass: subclass, + bInterfaceProtocol: protocol, + // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. + ..unsafe { MaybeUninit::zeroed().assume_init() } + }) + } +} + +// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `usb_device_id` and does not add +// additional invariants, so it's safe to transmute to `RawType`. +unsafe impl RawDeviceId for DeviceId { + type RawType = bindings::usb_device_id; +} + +// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_info` field. +unsafe impl RawDeviceIdIndex for DeviceId { + const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::usb_device_id, driver_info); + + fn index(&self) -> usize { + self.0.driver_info + } +} + +/// [`IdTable`](kernel::device_id::IdTable) type for USB. +pub type IdTable = &'static dyn kernel::device_id::IdTable; + +/// Create a USB `IdTable` with its alias for modpost. +#[macro_export] +macro_rules! usb_device_table { + ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { + const $table_name: $crate::device_id::IdArray< + $crate::usb::DeviceId, + $id_info_type, + { $table_data.len() }, + > = $crate::device_id::IdArray::new($table_data); + + $crate::module_device_table!("usb", $module_table_name, $table_name); + }; +} + +/// The USB driver trait. +/// +/// # Examples +/// +///``` +/// # use kernel::{bindings, device::Core, usb}; +/// use kernel::prelude::*; +/// +/// struct MyDriver; +/// +/// kernel::usb_device_table!( +/// USB_TABLE, +/// MODULE_USB_TABLE, +/// ::IdInfo, +/// [ +/// (usb::DeviceId::from_id(0x1234, 0x5678), ()), +/// (usb::DeviceId::from_id(0xabcd, 0xef01), ()), +/// ] +/// ); +/// +/// impl usb::Driver for MyDriver { +/// type IdInfo = (); +/// const ID_TABLE: usb::IdTable = &USB_TABLE; +/// +/// fn probe( +/// _interface: &usb::Interface, +/// _id: &usb::DeviceId, +/// _info: &Self::IdInfo, +/// ) -> Result>> { +/// Err(ENODEV) +/// } +/// +/// fn disconnect(_interface: &usb::Interface, _data: Pin<&Self>) {} +/// } +///``` +pub trait Driver { + /// The type holding information about each one of the device ids supported by the driver. + type IdInfo: 'static; + + /// The table of device ids supported by the driver. + const ID_TABLE: IdTable; + + /// USB driver probe. + /// + /// Called when a new USB interface is bound to this driver. + /// Implementers should attempt to initialize the interface here. + fn probe( + interface: &Interface, + id: &DeviceId, + id_info: &Self::IdInfo, + ) -> Result>>; + + /// USB driver disconnect. + /// + /// Called when the USB interface is about to be unbound from this driver. + fn disconnect(interface: &Interface, data: Pin<&Self>); +} + +/// A USB interface. +/// +/// This structure represents the Rust abstraction for a C [`struct usb_interface`]. +/// The implementation abstracts the usage of a C [`struct usb_interface`] passed +/// in from the C side. +/// +/// # Invariants +/// +/// An [`Interface`] instance represents a valid [`struct usb_interface`] created +/// by the C portion of the kernel. +/// +/// [`struct usb_interface`]: https://www.kernel.org/doc/html/latest/driver-api/usb/usb.html#c.usb_interface +#[repr(transparent)] +pub struct Interface( + Opaque, + PhantomData, +); + +impl Interface { + fn as_raw(&self) -> *mut bindings::usb_interface { + self.0.get() + } +} + +// SAFETY: `Interface` is a transparent wrapper of a type that doesn't depend on +// `Interface`'s generic argument. +kernel::impl_device_context_deref!(unsafe { Interface }); +kernel::impl_device_context_into_aref!(Interface); + +impl AsRef> for Interface { + fn as_ref(&self) -> &device::Device { + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid + // `struct usb_interface`. + let dev = unsafe { &raw mut ((*self.as_raw()).dev) }; + + // SAFETY: `dev` points to a valid `struct device`. + unsafe { device::Device::from_raw(dev) } + } +} + +impl AsRef> for Interface { + fn as_ref(&self) -> &Device { + // SAFETY: `self.as_raw()` is valid by the type invariants. For a valid interface, + // the helper should always return a valid USB device pointer. + let usb_dev = unsafe { bindings::interface_to_usbdev(self.as_raw()) }; + + // SAFETY: The helper returns a valid interface pointer that shares the + // same `DeviceContext`. + unsafe { &*(usb_dev.cast()) } + } +} + +// SAFETY: Instances of `Interface` are always reference-counted. +unsafe impl AlwaysRefCounted for Interface { + fn inc_ref(&self) { + // SAFETY: The invariants of `Interface` guarantee that `self.as_raw()` + // returns a valid `struct usb_interface` pointer, for which we will + // acquire a new refcount. + unsafe { bindings::usb_get_intf(self.as_raw()) }; + } + + unsafe fn dec_ref(obj: NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is non-zero. + unsafe { bindings::usb_put_intf(obj.cast().as_ptr()) } + } +} + +// SAFETY: A `Interface` is always reference-counted and can be released from any thread. +unsafe impl Send for Interface {} + +// SAFETY: It is safe to send a &Interface to another thread because we do not +// allow any mutation through a shared reference. +unsafe impl Sync for Interface {} + +/// A USB device. +/// +/// This structure represents the Rust abstraction for a C [`struct usb_device`]. +/// The implementation abstracts the usage of a C [`struct usb_device`] passed in +/// from the C side. +/// +/// # Invariants +/// +/// A [`Device`] instance represents a valid [`struct usb_device`] created by the C portion of the +/// kernel. +/// +/// [`struct usb_device`]: https://www.kernel.org/doc/html/latest/driver-api/usb/usb.html#c.usb_device +#[repr(transparent)] +pub struct Device( + Opaque, + PhantomData, +); + +impl Device { + fn as_raw(&self) -> *mut bindings::usb_device { + self.0.get() + } +} + +// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic +// argument. +kernel::impl_device_context_deref!(unsafe { Device }); +kernel::impl_device_context_into_aref!(Device); + +// SAFETY: Instances of `Device` are always reference-counted. +unsafe impl AlwaysRefCounted for Device { + fn inc_ref(&self) { + // SAFETY: The invariants of `Device` guarantee that `self.as_raw()` + // returns a valid `struct usb_device` pointer, for which we will + // acquire a new refcount. + unsafe { bindings::usb_get_dev(self.as_raw()) }; + } + + unsafe fn dec_ref(obj: NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is non-zero. + unsafe { bindings::usb_put_dev(obj.cast().as_ptr()) } + } +} + +impl AsRef> for Device { + fn as_ref(&self) -> &device::Device { + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid + // `struct usb_device`. + let dev = unsafe { &raw mut ((*self.as_raw()).dev) }; + + // SAFETY: `dev` points to a valid `struct device`. + unsafe { device::Device::from_raw(dev) } + } +} + +// SAFETY: A `Device` is always reference-counted and can be released from any thread. +unsafe impl Send for Device {} + +// SAFETY: It is safe to send a &Device to another thread because we do not +// allow any mutation through a shared reference. +unsafe impl Sync for Device {} + +/// Declares a kernel module that exposes a single USB driver. +/// +/// # Examples +/// +/// ```ignore +/// module_usb_driver! { +/// type: MyDriver, +/// name: "Module name", +/// author: ["Author name"], +/// description: "Description", +/// license: "GPL v2", +/// } +/// ``` +#[macro_export] +macro_rules! module_usb_driver { + ($($f:tt)*) => { + $crate::module_driver!(, $crate::usb::Adapter, { $($f)* }); + } +} From cc80dbb73b5d0c75b105e5214f34e1360670e0a5 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 25 Aug 2025 15:18:06 -0300 Subject: [PATCH 2055/2711] samples: rust: add a USB driver sample In light of the newly-added Rust abstractions for USB devices and drivers, add a sample USB rust driver that serves both to showcase what is currently supported, as well as be the only user of the USB abstractions for now. Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250825-b4-usb-v1-2-7aa024de7ae8@collabora.com [ force USB = y for now - gregkh ] Signed-off-by: Greg Kroah-Hartman --- samples/rust/Kconfig | 11 ++++++++ samples/rust/Makefile | 1 + samples/rust/rust_driver_usb.rs | 47 +++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 samples/rust/rust_driver_usb.rs diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index 7f7371a004ee..6d6e4d8c88cb 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -83,6 +83,17 @@ config SAMPLE_RUST_DRIVER_PLATFORM If unsure, say N. +config SAMPLE_RUST_DRIVER_USB + tristate "USB Driver" + depends on USB = y + help + This option builds the Rust USB driver sample. + + To compile this as a module, choose M here: + the module will be called rust_driver_usb. + + If unsure, say N. + config SAMPLE_RUST_DRIVER_FAUX tristate "Faux Driver" help diff --git a/samples/rust/Makefile b/samples/rust/Makefile index bd2faad63b4f..4e7df8a5cd27 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o obj-$(CONFIG_SAMPLE_RUST_DMA) += rust_dma.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o +obj-$(CONFIG_SAMPLE_RUST_DRIVER_USB) += rust_driver_usb.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) += rust_driver_faux.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY) += rust_driver_auxiliary.o obj-$(CONFIG_SAMPLE_RUST_CONFIGFS) += rust_configfs.o diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb.rs new file mode 100644 index 000000000000..5c396f421de7 --- /dev/null +++ b/samples/rust/rust_driver_usb.rs @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: Copyright (C) 2025 Collabora Ltd. + +//! Rust USB driver sample. + +use kernel::{device, device::Core, prelude::*, sync::aref::ARef, usb}; + +struct SampleDriver { + _intf: ARef, +} + +kernel::usb_device_table!( + USB_TABLE, + MODULE_USB_TABLE, + ::IdInfo, + [(usb::DeviceId::from_id(0x1234, 0x5678), ()),] +); + +impl usb::Driver for SampleDriver { + type IdInfo = (); + const ID_TABLE: usb::IdTable = &USB_TABLE; + + fn probe( + intf: &usb::Interface, + _id: &usb::DeviceId, + _info: &Self::IdInfo, + ) -> Result>> { + let dev: &device::Device = intf.as_ref(); + dev_info!(dev, "Rust USB driver sample probed\n"); + + let drvdata = KBox::new(Self { _intf: intf.into() }, GFP_KERNEL)?; + Ok(drvdata.into()) + } + + fn disconnect(intf: &usb::Interface, _data: Pin<&Self>) { + let dev: &device::Device = intf.as_ref(); + dev_info!(dev, "Rust USB driver sample disconnected\n"); + } +} + +kernel::module_usb_driver! { + type: SampleDriver, + name: "rust_driver_usb", + authors: ["Daniel Almeida"], + description: "Rust USB driver sample", + license: "GPL v2", +} From b640d42a6ac9ba01abe65ec34f7c73aaf6758ab8 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 22 Sep 2025 16:08:24 +0200 Subject: [PATCH 2056/2711] PCI: tegra194: Fix broken tegra_pcie_ep_raise_msi_irq() The pci_epc_raise_irq() supplies a MSI or MSI-X interrupt number in range (1-N), as per the pci_epc_raise_irq() kdoc, where N is 32 for MSI. But tegra_pcie_ep_raise_msi_irq() incorrectly uses the interrupt number as the MSI vector. This causes wrong MSI vector to be triggered, leading to the failure of PCI endpoint Kselftest MSI_TEST test case. To fix this issue, convert the interrupt number to MSI vector. Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250922140822.519796-6-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 0e413857649f..a00d5b9cd871 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1955,10 +1955,10 @@ static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq) static int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq) { - if (unlikely(irq > 31)) + if (unlikely(irq > 32)) return -EINVAL; - appl_writel(pcie, BIT(irq), APPL_MSI_CTRL_1); + appl_writel(pcie, BIT(irq - 1), APPL_MSI_CTRL_1); return 0; } From 82f1cc171ce95544c024837c20a54d1954a67a76 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 24 Sep 2025 21:50:52 +0530 Subject: [PATCH 2057/2711] PCI: tegra194: Set pci_epc_features::msi_capable to true Since the driver supports MSI, set the flag to true. This helps pci_endpoint_test to use the optimal IRQ type when using PCITEST_IRQ_TYPE_AUTO. Signed-off-by: Niklas Cassel [mani: splitted this change from the bug fix] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250922140822.519796-6-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-tegra194.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index a00d5b9cd871..fe418b9bfbb4 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1998,6 +1998,7 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, static const struct pci_epc_features tegra_pcie_epc_features = { .linkup_notifier = true, + .msi_capable = true, .bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M, .only_64bit = true, }, .bar[BAR_1] = { .type = BAR_RESERVED, }, From 7326348209a0079a83c7bd7963a0e32d26af61c8 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:31 -0700 Subject: [PATCH 2058/2711] KVM: arm64: selftests: Provide kvm_arch_vm_post_create() in library code In order to compel the default usage of EL2 in selftests, move kvm_arch_vm_post_create() to library code and expose an opt-in for using MTE by default. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- .../testing/selftests/kvm/arm64/set_id_regs.c | 19 +++++-------------- .../selftests/kvm/include/arm64/processor.h | 2 ++ .../selftests/kvm/lib/arm64/processor.c | 13 +++++++++++++ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c index 189321e96925..a2d367a2c93c 100644 --- a/tools/testing/selftests/kvm/arm64/set_id_regs.c +++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c @@ -15,8 +15,6 @@ #include "test_util.h" #include -bool have_cap_arm_mte; - enum ftr_type { FTR_EXACT, /* Use a predefined safe value */ FTR_LOWER_SAFE, /* Smaller value is safe */ @@ -568,7 +566,9 @@ static void test_user_set_mte_reg(struct kvm_vcpu *vcpu) uint64_t mte_frac; int idx, err; - if (!have_cap_arm_mte) { + val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1)); + mte = FIELD_GET(ID_AA64PFR1_EL1_MTE, val); + if (!mte) { ksft_test_result_skip("MTE capability not supported, nothing to test\n"); return; } @@ -593,9 +593,6 @@ static void test_user_set_mte_reg(struct kvm_vcpu *vcpu) * from unsupported (0xF) to supported (0). * */ - val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1)); - - mte = FIELD_GET(ID_AA64PFR1_EL1_MTE, val); mte_frac = FIELD_GET(ID_AA64PFR1_EL1_MTE_frac, val); if (mte != ID_AA64PFR1_EL1_MTE_MTE2 || mte_frac != ID_AA64PFR1_EL1_MTE_frac_NI) { @@ -750,14 +747,6 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu) ksft_test_result_pass("%s\n", __func__); } -void kvm_arch_vm_post_create(struct kvm_vm *vm) -{ - if (vm_check_cap(vm, KVM_CAP_ARM_MTE)) { - vm_enable_cap(vm, KVM_CAP_ARM_MTE, 0); - have_cap_arm_mte = true; - } -} - int main(void) { struct kvm_vcpu *vcpu; @@ -769,6 +758,8 @@ int main(void) TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_WRITABLE_IMP_ID_REGS)); + test_wants_mte(); + vm = vm_create(1); vm_enable_cap(vm, KVM_CAP_ARM_WRITABLE_IMP_ID_REGS, 0); vcpu = vm_vcpu_add(vm, 0, guest_code); diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h index 255fed769a8a..8370fc94041d 100644 --- a/tools/testing/selftests/kvm/include/arm64/processor.h +++ b/tools/testing/selftests/kvm/include/arm64/processor.h @@ -300,4 +300,6 @@ void smccc_smc(uint32_t function_id, uint64_t arg0, uint64_t arg1, /* Execute a Wait For Interrupt instruction. */ void wfi(void); +void test_wants_mte(void); + #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index eb115123d741..caed1998c7b3 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -653,3 +653,16 @@ void wfi(void) { asm volatile("wfi"); } + +static bool request_mte; + +void test_wants_mte(void) +{ + request_mte = true; +} + +void kvm_arch_vm_post_create(struct kvm_vm *vm) +{ + if (request_mte && vm_check_cap(vm, KVM_CAP_ARM_MTE)) + vm_enable_cap(vm, KVM_CAP_ARM_MTE, 0); +} From a5022da5f9a3a791ff2caf5fe3789561ae687747 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:32 -0700 Subject: [PATCH 2059/2711] KVM: arm64: selftests: Initialize VGICv3 only once vgic_v3_setup() unnecessarily initializes the vgic twice. Keep the initialization after configuring MMIO frames and get rid of the other. Signed-off-by: Oliver Upton Reviewed-by: Zenghui Yu Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/lib/arm64/vgic.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/arm64/vgic.c b/tools/testing/selftests/kvm/lib/arm64/vgic.c index 4427f43f73ea..64e793795563 100644 --- a/tools/testing/selftests/kvm/lib/arm64/vgic.c +++ b/tools/testing/selftests/kvm/lib/arm64/vgic.c @@ -56,9 +56,6 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs) kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, &nr_irqs); - kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); - attr = GICD_BASE_GPA; kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_DIST, &attr); From b712afa7a1cdb787f311f51c04df81fc6f026368 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:33 -0700 Subject: [PATCH 2060/2711] KVM: arm64: selftests: Add helper to check for VGICv3 support Introduce a proper predicate for probing VGICv3 by performing a 'test' creation of the device on a dummy VM. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/arm64/arch_timer.c | 3 ++- .../selftests/kvm/arm64/arch_timer_edge_cases.c | 3 ++- tools/testing/selftests/kvm/arm64/vgic_irq.c | 3 ++- tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c | 4 ++-- .../testing/selftests/kvm/arm64/vpmu_counter_access.c | 3 +-- tools/testing/selftests/kvm/include/arm64/vgic.h | 1 + tools/testing/selftests/kvm/lib/arm64/vgic.c | 11 +++++++++++ 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/arch_timer.c b/tools/testing/selftests/kvm/arm64/arch_timer.c index eeba1cc87ff8..aaf4285f832a 100644 --- a/tools/testing/selftests/kvm/arm64/arch_timer.c +++ b/tools/testing/selftests/kvm/arm64/arch_timer.c @@ -184,6 +184,8 @@ struct kvm_vm *test_vm_create(void) unsigned int i; int nr_vcpus = test_args.nr_vcpus; + TEST_REQUIRE(kvm_supports_vgic_v3()); + vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus); vm_init_descriptor_tables(vm); @@ -205,7 +207,6 @@ struct kvm_vm *test_vm_create(void) test_init_timer_irq(vm); gic_fd = vgic_v3_setup(vm, nr_vcpus, 64); - __TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3"); /* Make all the test's cmdline args visible to the guest */ sync_global_to_guest(vm, test_args); diff --git a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c index ce74d069cb7b..d349d80d8418 100644 --- a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c +++ b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c @@ -952,7 +952,6 @@ static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu, test_init_timer_irq(*vm, *vcpu); gic_fd = vgic_v3_setup(*vm, 1, 64); - __TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3"); sync_global_to_guest(*vm, test_args); sync_global_to_guest(*vm, CVAL_MAX); @@ -1042,6 +1041,8 @@ int main(int argc, char *argv[]) /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); + TEST_REQUIRE(kvm_supports_vgic_v3()); + if (!parse_args(argc, argv)) exit(KSFT_SKIP); diff --git a/tools/testing/selftests/kvm/arm64/vgic_irq.c b/tools/testing/selftests/kvm/arm64/vgic_irq.c index a09dd423c2d7..9fc9e8e44ecd 100644 --- a/tools/testing/selftests/kvm/arm64/vgic_irq.c +++ b/tools/testing/selftests/kvm/arm64/vgic_irq.c @@ -752,7 +752,6 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) vcpu_args_set(vcpu, 1, args_gva); gic_fd = vgic_v3_setup(vm, 1, nr_irqs); - __TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3, skipping"); vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT, guest_irq_handlers[args.eoi_split][args.level_sensitive]); @@ -802,6 +801,8 @@ int main(int argc, char **argv) int opt; bool eoi_split = false; + TEST_REQUIRE(kvm_supports_vgic_v3()); + while ((opt = getopt(argc, argv, "hn:e:l:")) != -1) { switch (opt) { case 'n': diff --git a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c index fc4fe52fb6f8..cc2b21d374af 100644 --- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c +++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c @@ -215,8 +215,6 @@ static void setup_test_data(void) static void setup_gic(void) { gic_fd = vgic_v3_setup(vm, test_data.nr_cpus, 64); - __TEST_REQUIRE(gic_fd >= 0, "Failed to create GICv3"); - its_fd = vgic_its_setup(vm); } @@ -374,6 +372,8 @@ int main(int argc, char **argv) u32 nr_threads; int c; + TEST_REQUIRE(kvm_supports_vgic_v3()); + while ((c = getopt(argc, argv, "hv:d:e:i:")) != -1) { switch (c) { case 'v': diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c index a0c4ab839155..01f61657de45 100644 --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c @@ -436,8 +436,6 @@ static void create_vpmu_vm(void *guest_code) vpmu_vm.vcpu = aarch64_vcpu_add(vpmu_vm.vm, 0, &init, guest_code); vcpu_init_descriptor_tables(vpmu_vm.vcpu); vpmu_vm.gic_fd = vgic_v3_setup(vpmu_vm.vm, 1, 64); - __TEST_REQUIRE(vpmu_vm.gic_fd >= 0, - "Failed to create vgic-v3, skipping"); /* Make sure that PMUv3 support is indicated in the ID register */ dfr0 = vcpu_get_reg(vpmu_vm.vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1)); @@ -634,6 +632,7 @@ int main(void) uint64_t i, pmcr_n; TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3)); + TEST_REQUIRE(kvm_supports_vgic_v3()); pmcr_n = get_pmcr_n_limit(); for (i = 0; i <= pmcr_n; i++) { diff --git a/tools/testing/selftests/kvm/include/arm64/vgic.h b/tools/testing/selftests/kvm/include/arm64/vgic.h index c481d0c00a5d..b858fa8195b4 100644 --- a/tools/testing/selftests/kvm/include/arm64/vgic.h +++ b/tools/testing/selftests/kvm/include/arm64/vgic.h @@ -16,6 +16,7 @@ ((uint64_t)(flags) << 12) | \ index) +bool kvm_supports_vgic_v3(void); int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs); #define VGIC_MAX_RESERVED 1023 diff --git a/tools/testing/selftests/kvm/lib/arm64/vgic.c b/tools/testing/selftests/kvm/lib/arm64/vgic.c index 64e793795563..661744c6532e 100644 --- a/tools/testing/selftests/kvm/lib/arm64/vgic.c +++ b/tools/testing/selftests/kvm/lib/arm64/vgic.c @@ -15,6 +15,17 @@ #include "gic.h" #include "gic_v3.h" +bool kvm_supports_vgic_v3(void) +{ + struct kvm_vm *vm = vm_create_barebones(); + int r; + + r = __kvm_test_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3); + kvm_vm_free(vm); + + return !r; +} + /* * vGIC-v3 default host setup * From b8daa7ceac1c56e39b6ef4e62510a7d846511695 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:34 -0700 Subject: [PATCH 2061/2711] KVM: arm64: selftests: Add unsanitised helpers for VGICv3 creation vgic_v3_setup() has a good bit of sanity checking internally to ensure that vCPUs have actually been created and match the dimensioning of the vgic itself. Spin off an unsanitised setup and initialization helper so vgic initialization can be wired in around a 'default' VM's vCPU creation. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- .../selftests/kvm/include/arm64/vgic.h | 2 + tools/testing/selftests/kvm/lib/arm64/vgic.c | 52 ++++++++++++------- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/kvm/include/arm64/vgic.h b/tools/testing/selftests/kvm/include/arm64/vgic.h index b858fa8195b4..688beccc9436 100644 --- a/tools/testing/selftests/kvm/include/arm64/vgic.h +++ b/tools/testing/selftests/kvm/include/arm64/vgic.h @@ -17,6 +17,8 @@ index) bool kvm_supports_vgic_v3(void); +int __vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs); +void __vgic_v3_init(int fd); int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs); #define VGIC_MAX_RESERVED 1023 diff --git a/tools/testing/selftests/kvm/lib/arm64/vgic.c b/tools/testing/selftests/kvm/lib/arm64/vgic.c index 661744c6532e..d0f7bd0984b8 100644 --- a/tools/testing/selftests/kvm/lib/arm64/vgic.c +++ b/tools/testing/selftests/kvm/lib/arm64/vgic.c @@ -41,24 +41,11 @@ bool kvm_supports_vgic_v3(void) * redistributor regions of the guest. Since it depends on the number of * vCPUs for the VM, it must be called after all the vCPUs have been created. */ -int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs) +int __vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs) { int gic_fd; uint64_t attr; - struct list_head *iter; - unsigned int nr_gic_pages, nr_vcpus_created = 0; - - TEST_ASSERT(nr_vcpus, "Number of vCPUs cannot be empty"); - - /* - * Make sure that the caller is infact calling this - * function after all the vCPUs are added. - */ - list_for_each(iter, &vm->vcpus) - nr_vcpus_created++; - TEST_ASSERT(nr_vcpus == nr_vcpus_created, - "Number of vCPUs requested (%u) doesn't match with the ones created for the VM (%u)", - nr_vcpus, nr_vcpus_created); + unsigned int nr_gic_pages; /* Distributor setup */ gic_fd = __kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3); @@ -81,12 +68,41 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs) KVM_VGIC_V3_REDIST_SIZE * nr_vcpus); virt_map(vm, GICR_BASE_GPA, GICR_BASE_GPA, nr_gic_pages); - kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); - return gic_fd; } +void __vgic_v3_init(int fd) +{ + kvm_device_attr_set(fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); +} + +int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs) +{ + unsigned int nr_vcpus_created = 0; + struct list_head *iter; + int fd; + + TEST_ASSERT(nr_vcpus, "Number of vCPUs cannot be empty"); + + /* + * Make sure that the caller is infact calling this + * function after all the vCPUs are added. + */ + list_for_each(iter, &vm->vcpus) + nr_vcpus_created++; + TEST_ASSERT(nr_vcpus == nr_vcpus_created, + "Number of vCPUs requested (%u) doesn't match with the ones created for the VM (%u)", + nr_vcpus, nr_vcpus_created); + + fd = __vgic_v3_setup(vm, nr_vcpus, nr_irqs); + if (fd < 0) + return fd; + + __vgic_v3_init(fd); + return fd; +} + /* should only work for level sensitive interrupts */ int _kvm_irq_set_level_info(int gic_fd, uint32_t intid, int level) { From 8911c7dbc607212bf3dfc963004b062588c0ab38 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:35 -0700 Subject: [PATCH 2062/2711] KVM: arm64: selftests: Create a VGICv3 for 'default' VMs Start creating a VGICv3 by default unless explicitly opted-out by the test. While having an interrupt controller is nice, the real benefit here is clearing a hurdle for EL2 VMs which mandate the presence of a VGIC. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- .../testing/selftests/kvm/arm64/arch_timer.c | 4 --- .../kvm/arm64/arch_timer_edge_cases.c | 4 --- .../testing/selftests/kvm/arm64/no-vgic-v3.c | 2 ++ tools/testing/selftests/kvm/arm64/psci_test.c | 1 + .../testing/selftests/kvm/arm64/set_id_regs.c | 1 + .../selftests/kvm/arm64/smccc_filter.c | 1 + tools/testing/selftests/kvm/arm64/vgic_init.c | 2 ++ tools/testing/selftests/kvm/arm64/vgic_irq.c | 1 + .../selftests/kvm/arm64/vgic_lpi_stress.c | 4 +-- .../selftests/kvm/arm64/vpmu_counter_access.c | 5 ++- .../selftests/kvm/dirty_log_perf_test.c | 35 ------------------- tools/testing/selftests/kvm/dirty_log_test.c | 1 + .../kvm/include/arm64/kvm_util_arch.h | 5 ++- .../selftests/kvm/include/arm64/processor.h | 1 + .../testing/selftests/kvm/include/kvm_util.h | 4 ++- .../selftests/kvm/lib/arm64/processor.c | 26 +++++++++++++- tools/testing/selftests/kvm/lib/kvm_util.c | 15 ++++++-- .../testing/selftests/kvm/lib/x86/processor.c | 2 +- tools/testing/selftests/kvm/s390/cmma_test.c | 2 +- 19 files changed, 60 insertions(+), 56 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/arch_timer.c b/tools/testing/selftests/kvm/arm64/arch_timer.c index aaf4285f832a..c753013319bc 100644 --- a/tools/testing/selftests/kvm/arm64/arch_timer.c +++ b/tools/testing/selftests/kvm/arm64/arch_timer.c @@ -176,8 +176,6 @@ static void test_init_timer_irq(struct kvm_vm *vm) pr_debug("ptimer_irq: %d; vtimer_irq: %d\n", ptimer_irq, vtimer_irq); } -static int gic_fd; - struct kvm_vm *test_vm_create(void) { struct kvm_vm *vm; @@ -206,7 +204,6 @@ struct kvm_vm *test_vm_create(void) vcpu_init_descriptor_tables(vcpus[i]); test_init_timer_irq(vm); - gic_fd = vgic_v3_setup(vm, nr_vcpus, 64); /* Make all the test's cmdline args visible to the guest */ sync_global_to_guest(vm, test_args); @@ -216,6 +213,5 @@ struct kvm_vm *test_vm_create(void) void test_vm_cleanup(struct kvm_vm *vm) { - close(gic_fd); kvm_vm_free(vm); } diff --git a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c index d349d80d8418..5c60262f4c2e 100644 --- a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c +++ b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c @@ -935,8 +935,6 @@ static void test_init_timer_irq(struct kvm_vm *vm, struct kvm_vcpu *vcpu) pr_debug("ptimer_irq: %d; vtimer_irq: %d\n", ptimer_irq, vtimer_irq); } -static int gic_fd; - static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu, enum arch_timer timer) { @@ -951,7 +949,6 @@ static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu, vcpu_args_set(*vcpu, 1, timer); test_init_timer_irq(*vm, *vcpu); - gic_fd = vgic_v3_setup(*vm, 1, 64); sync_global_to_guest(*vm, test_args); sync_global_to_guest(*vm, CVAL_MAX); @@ -960,7 +957,6 @@ static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu, static void test_vm_cleanup(struct kvm_vm *vm) { - close(gic_fd); kvm_vm_free(vm); } diff --git a/tools/testing/selftests/kvm/arm64/no-vgic-v3.c b/tools/testing/selftests/kvm/arm64/no-vgic-v3.c index f222538e6084..152c34776981 100644 --- a/tools/testing/selftests/kvm/arm64/no-vgic-v3.c +++ b/tools/testing/selftests/kvm/arm64/no-vgic-v3.c @@ -163,6 +163,8 @@ int main(int argc, char *argv[]) struct kvm_vm *vm; uint64_t pfr0; + test_disable_default_vgic(); + vm = vm_create_with_one_vcpu(&vcpu, NULL); pfr0 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1)); __TEST_REQUIRE(FIELD_GET(ID_AA64PFR0_EL1_GIC, pfr0), diff --git a/tools/testing/selftests/kvm/arm64/psci_test.c b/tools/testing/selftests/kvm/arm64/psci_test.c index ab491ee9e5f7..cf208390fd0e 100644 --- a/tools/testing/selftests/kvm/arm64/psci_test.c +++ b/tools/testing/selftests/kvm/arm64/psci_test.c @@ -95,6 +95,7 @@ static struct kvm_vm *setup_vm(void *guest_code, struct kvm_vcpu **source, *source = aarch64_vcpu_add(vm, 0, &init, guest_code); *target = aarch64_vcpu_add(vm, 1, &init, guest_code); + kvm_arch_vm_finalize_vcpus(vm); return vm; } diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c index a2d367a2c93c..77718628facf 100644 --- a/tools/testing/selftests/kvm/arm64/set_id_regs.c +++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c @@ -763,6 +763,7 @@ int main(void) vm = vm_create(1); vm_enable_cap(vm, KVM_CAP_ARM_WRITABLE_IMP_ID_REGS, 0); vcpu = vm_vcpu_add(vm, 0, guest_code); + kvm_arch_vm_finalize_vcpus(vm); /* Check for AARCH64 only system */ val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1)); diff --git a/tools/testing/selftests/kvm/arm64/smccc_filter.c b/tools/testing/selftests/kvm/arm64/smccc_filter.c index 2d189f3da228..eb5551d21dbe 100644 --- a/tools/testing/selftests/kvm/arm64/smccc_filter.c +++ b/tools/testing/selftests/kvm/arm64/smccc_filter.c @@ -73,6 +73,7 @@ static struct kvm_vm *setup_vm(struct kvm_vcpu **vcpu) init.features[0] |= (1 << KVM_ARM_VCPU_PSCI_0_2); *vcpu = aarch64_vcpu_add(vm, 0, &init, guest_main); + kvm_arch_vm_finalize_vcpus(vm); return vm; } diff --git a/tools/testing/selftests/kvm/arm64/vgic_init.c b/tools/testing/selftests/kvm/arm64/vgic_init.c index a8e0f46bc0ab..8d6d3a4ae4db 100644 --- a/tools/testing/selftests/kvm/arm64/vgic_init.c +++ b/tools/testing/selftests/kvm/arm64/vgic_init.c @@ -994,6 +994,8 @@ int main(int ac, char **av) int pa_bits; int cnt_impl = 0; + test_disable_default_vgic(); + pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits; max_phys_size = 1ULL << pa_bits; diff --git a/tools/testing/selftests/kvm/arm64/vgic_irq.c b/tools/testing/selftests/kvm/arm64/vgic_irq.c index 9fc9e8e44ecd..6338f5bbdb70 100644 --- a/tools/testing/selftests/kvm/arm64/vgic_irq.c +++ b/tools/testing/selftests/kvm/arm64/vgic_irq.c @@ -802,6 +802,7 @@ int main(int argc, char **argv) bool eoi_split = false; TEST_REQUIRE(kvm_supports_vgic_v3()); + test_disable_default_vgic(); while ((opt = getopt(argc, argv, "hn:e:l:")) != -1) { switch (opt) { diff --git a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c index cc2b21d374af..87922a89b134 100644 --- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c +++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c @@ -27,7 +27,7 @@ static vm_paddr_t gpa_base; static struct kvm_vm *vm; static struct kvm_vcpu **vcpus; -static int gic_fd, its_fd; +static int its_fd; static struct test_data { bool request_vcpus_stop; @@ -214,7 +214,6 @@ static void setup_test_data(void) static void setup_gic(void) { - gic_fd = vgic_v3_setup(vm, test_data.nr_cpus, 64); its_fd = vgic_its_setup(vm); } @@ -353,7 +352,6 @@ static void setup_vm(void) static void destroy_vm(void) { close(its_fd); - close(gic_fd); kvm_vm_free(vm); free(vcpus); } diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c index 01f61657de45..4a7e8e85a1b8 100644 --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c @@ -28,7 +28,6 @@ struct vpmu_vm { struct kvm_vm *vm; struct kvm_vcpu *vcpu; - int gic_fd; }; static struct vpmu_vm vpmu_vm; @@ -435,7 +434,8 @@ static void create_vpmu_vm(void *guest_code) init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3); vpmu_vm.vcpu = aarch64_vcpu_add(vpmu_vm.vm, 0, &init, guest_code); vcpu_init_descriptor_tables(vpmu_vm.vcpu); - vpmu_vm.gic_fd = vgic_v3_setup(vpmu_vm.vm, 1, 64); + + kvm_arch_vm_finalize_vcpus(vpmu_vm.vm); /* Make sure that PMUv3 support is indicated in the ID register */ dfr0 = vcpu_get_reg(vpmu_vm.vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1)); @@ -451,7 +451,6 @@ static void create_vpmu_vm(void *guest_code) static void destroy_vpmu_vm(void) { - close(vpmu_vm.gic_fd); kvm_vm_free(vpmu_vm.vm); } diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c index e79817bd0e29..0a1ea1d1e2d8 100644 --- a/tools/testing/selftests/kvm/dirty_log_perf_test.c +++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c @@ -20,38 +20,6 @@ #include "guest_modes.h" #include "ucall_common.h" -#ifdef __aarch64__ -#include "arm64/vgic.h" - -static int gic_fd; - -static void arch_setup_vm(struct kvm_vm *vm, unsigned int nr_vcpus) -{ - /* - * The test can still run even if hardware does not support GICv3, as it - * is only an optimization to reduce guest exits. - */ - gic_fd = vgic_v3_setup(vm, nr_vcpus, 64); -} - -static void arch_cleanup_vm(struct kvm_vm *vm) -{ - if (gic_fd > 0) - close(gic_fd); -} - -#else /* __aarch64__ */ - -static void arch_setup_vm(struct kvm_vm *vm, unsigned int nr_vcpus) -{ -} - -static void arch_cleanup_vm(struct kvm_vm *vm) -{ -} - -#endif - /* How many host loops to run by default (one KVM_GET_DIRTY_LOG for each loop)*/ #define TEST_HOST_LOOP_N 2UL @@ -166,8 +134,6 @@ static void run_test(enum vm_guest_mode mode, void *arg) vm_enable_cap(vm, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, dirty_log_manual_caps); - arch_setup_vm(vm, nr_vcpus); - /* Start the iterations */ iteration = 0; host_quit = false; @@ -285,7 +251,6 @@ static void run_test(enum vm_guest_mode mode, void *arg) } memstress_free_bitmaps(bitmaps, p->slots); - arch_cleanup_vm(vm); memstress_destroy_vm(vm); } diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 23593d9eeba9..d58a641b0e6a 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -585,6 +585,7 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, struct kvm_vcpu **vcpu, log_mode_create_vm_done(vm); *vcpu = vm_vcpu_add(vm, 0, guest_code); + kvm_arch_vm_finalize_vcpus(vm); return vm; } diff --git a/tools/testing/selftests/kvm/include/arm64/kvm_util_arch.h b/tools/testing/selftests/kvm/include/arm64/kvm_util_arch.h index e43a57d99b56..b973bb2c64a6 100644 --- a/tools/testing/selftests/kvm/include/arm64/kvm_util_arch.h +++ b/tools/testing/selftests/kvm/include/arm64/kvm_util_arch.h @@ -2,6 +2,9 @@ #ifndef SELFTEST_KVM_UTIL_ARCH_H #define SELFTEST_KVM_UTIL_ARCH_H -struct kvm_vm_arch {}; +struct kvm_vm_arch { + bool has_gic; + int gic_fd; +}; #endif // SELFTEST_KVM_UTIL_ARCH_H diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h index 8370fc94041d..8c066ba1deb5 100644 --- a/tools/testing/selftests/kvm/include/arm64/processor.h +++ b/tools/testing/selftests/kvm/include/arm64/processor.h @@ -301,5 +301,6 @@ void smccc_smc(uint32_t function_id, uint64_t arg0, uint64_t arg1, void wfi(void); void test_wants_mte(void); +void test_disable_default_vgic(void); #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 23a506d7eca3..3ab1fffbc3f2 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -1257,7 +1257,9 @@ static inline int __vm_disable_nx_huge_pages(struct kvm_vm *vm) */ void kvm_selftest_arch_init(void); -void kvm_arch_vm_post_create(struct kvm_vm *vm); +void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus); +void kvm_arch_vm_finalize_vcpus(struct kvm_vm *vm); +void kvm_arch_vm_release(struct kvm_vm *vm); bool vm_is_gpa_protected(struct kvm_vm *vm, vm_paddr_t paddr); diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index caed1998c7b3..de77d9a7e0cd 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -12,6 +12,7 @@ #include "kvm_util.h" #include "processor.h" #include "ucall_common.h" +#include "vgic.h" #include #include @@ -655,14 +656,37 @@ void wfi(void) } static bool request_mte; +static bool request_vgic = true; void test_wants_mte(void) { request_mte = true; } -void kvm_arch_vm_post_create(struct kvm_vm *vm) +void test_disable_default_vgic(void) +{ + request_vgic = false; +} + +void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus) { if (request_mte && vm_check_cap(vm, KVM_CAP_ARM_MTE)) vm_enable_cap(vm, KVM_CAP_ARM_MTE, 0); + + if (request_vgic && kvm_supports_vgic_v3()) { + vm->arch.gic_fd = __vgic_v3_setup(vm, nr_vcpus, 64); + vm->arch.has_gic = true; + } +} + +void kvm_arch_vm_finalize_vcpus(struct kvm_vm *vm) +{ + if (vm->arch.has_gic) + __vgic_v3_init(vm->arch.gic_fd); +} + +void kvm_arch_vm_release(struct kvm_vm *vm) +{ + if (vm->arch.has_gic) + close(vm->arch.gic_fd); } diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index c3f5142b0a54..67f32d41a59c 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -517,7 +517,7 @@ struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus, guest_rng = new_guest_random_state(guest_random_seed); sync_global_to_guest(vm, guest_rng); - kvm_arch_vm_post_create(vm); + kvm_arch_vm_post_create(vm, nr_runnable_vcpus); return vm; } @@ -555,6 +555,7 @@ struct kvm_vm *__vm_create_with_vcpus(struct vm_shape shape, uint32_t nr_vcpus, for (i = 0; i < nr_vcpus; ++i) vcpus[i] = vm_vcpu_add(vm, i, guest_code); + kvm_arch_vm_finalize_vcpus(vm); return vm; } @@ -805,6 +806,8 @@ void kvm_vm_release(struct kvm_vm *vmp) /* Free cached stats metadata and close FD */ kvm_stats_release(&vmp->stats); + + kvm_arch_vm_release(vmp); } static void __vm_mem_region_delete(struct kvm_vm *vm, @@ -2330,7 +2333,15 @@ void kvm_get_stat(struct kvm_binary_stats *stats, const char *name, TEST_FAIL("Unable to find stat '%s'", name); } -__weak void kvm_arch_vm_post_create(struct kvm_vm *vm) +__weak void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus) +{ +} + +__weak void kvm_arch_vm_finalize_vcpus(struct kvm_vm *vm) +{ +} + +__weak void kvm_arch_vm_release(struct kvm_vm *vm) { } diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index d4c19ac885a9..bff75aa341bf 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -625,7 +625,7 @@ void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) REPORT_GUEST_ASSERT(uc); } -void kvm_arch_vm_post_create(struct kvm_vm *vm) +void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus) { int r; diff --git a/tools/testing/selftests/kvm/s390/cmma_test.c b/tools/testing/selftests/kvm/s390/cmma_test.c index 85cc8c18d6e7..e39a724fe860 100644 --- a/tools/testing/selftests/kvm/s390/cmma_test.c +++ b/tools/testing/selftests/kvm/s390/cmma_test.c @@ -145,7 +145,7 @@ static void finish_vm_setup(struct kvm_vm *vm) slot0 = memslot2region(vm, 0); ucall_init(vm, slot0->region.guest_phys_addr + slot0->region.memory_size); - kvm_arch_vm_post_create(vm); + kvm_arch_vm_post_create(vm, 0); } static struct kvm_vm *create_vm_two_memslots(void) From 1c9604ba234711ca759f1147f2fbc7a94a5a486d Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:36 -0700 Subject: [PATCH 2063/2711] KVM: arm64: selftests: Alias EL1 registers to EL2 counterparts FEAT_VHE has the somewhat nice property of implicitly redirecting EL1 register aliases to their corresponding EL2 representations when E2H=1. Unfortunately, there's no such abstraction for userspace and EL2 registers are always accessed by their canonical encoding. Introduce a helper that applies EL2 redirections to sysregs and use aggressive inlining to catch misuse at compile time. Go a little past the architectural definition for ease of use for test authors (e.g. the stack pointer). Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- .../selftests/kvm/arm64/vpmu_counter_access.c | 4 +- .../selftests/kvm/include/arm64/processor.h | 54 +++++++++++++++++++ .../testing/selftests/kvm/include/kvm_util.h | 3 ++ .../selftests/kvm/lib/arm64/processor.c | 19 +++---- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c index 4a7e8e85a1b8..36a3a8b4e0b5 100644 --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c @@ -517,7 +517,7 @@ static void run_access_test(uint64_t pmcr_n) vcpu = vpmu_vm.vcpu; /* Save the initial sp to restore them later to run the guest again */ - sp = vcpu_get_reg(vcpu, ARM64_CORE_REG(sp_el1)); + sp = vcpu_get_reg(vcpu, ctxt_reg_alias(vcpu, SYS_SP_EL1)); run_vcpu(vcpu, pmcr_n); @@ -529,7 +529,7 @@ static void run_access_test(uint64_t pmcr_n) init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3); aarch64_vcpu_setup(vcpu, &init); vcpu_init_descriptor_tables(vcpu); - vcpu_set_reg(vcpu, ARM64_CORE_REG(sp_el1), sp); + vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_SP_EL1), sp); vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); run_vcpu(vcpu, pmcr_n); diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h index 8c066ba1deb5..5a4b29c1b965 100644 --- a/tools/testing/selftests/kvm/include/arm64/processor.h +++ b/tools/testing/selftests/kvm/include/arm64/processor.h @@ -303,4 +303,58 @@ void wfi(void); void test_wants_mte(void); void test_disable_default_vgic(void); +static bool vcpu_has_el2(struct kvm_vcpu *vcpu) +{ + return vcpu->init.features[0] & BIT(KVM_ARM_VCPU_HAS_EL2); +} + +#define MAPPED_EL2_SYSREG(el2, el1) \ + case SYS_##el1: \ + if (vcpu_has_el2(vcpu)) \ + alias = SYS_##el2; \ + break + + +static __always_inline u64 ctxt_reg_alias(struct kvm_vcpu *vcpu, u32 encoding) +{ + u32 alias = encoding; + + BUILD_BUG_ON(!__builtin_constant_p(encoding)); + + switch (encoding) { + MAPPED_EL2_SYSREG(SCTLR_EL2, SCTLR_EL1); + MAPPED_EL2_SYSREG(CPTR_EL2, CPACR_EL1); + MAPPED_EL2_SYSREG(TTBR0_EL2, TTBR0_EL1); + MAPPED_EL2_SYSREG(TTBR1_EL2, TTBR1_EL1); + MAPPED_EL2_SYSREG(TCR_EL2, TCR_EL1); + MAPPED_EL2_SYSREG(VBAR_EL2, VBAR_EL1); + MAPPED_EL2_SYSREG(AFSR0_EL2, AFSR0_EL1); + MAPPED_EL2_SYSREG(AFSR1_EL2, AFSR1_EL1); + MAPPED_EL2_SYSREG(ESR_EL2, ESR_EL1); + MAPPED_EL2_SYSREG(FAR_EL2, FAR_EL1); + MAPPED_EL2_SYSREG(MAIR_EL2, MAIR_EL1); + MAPPED_EL2_SYSREG(TCR2_EL2, TCR2_EL1); + MAPPED_EL2_SYSREG(PIR_EL2, PIR_EL1); + MAPPED_EL2_SYSREG(PIRE0_EL2, PIRE0_EL1); + MAPPED_EL2_SYSREG(POR_EL2, POR_EL1); + MAPPED_EL2_SYSREG(AMAIR_EL2, AMAIR_EL1); + MAPPED_EL2_SYSREG(ELR_EL2, ELR_EL1); + MAPPED_EL2_SYSREG(SPSR_EL2, SPSR_EL1); + MAPPED_EL2_SYSREG(ZCR_EL2, ZCR_EL1); + MAPPED_EL2_SYSREG(CONTEXTIDR_EL2, CONTEXTIDR_EL1); + MAPPED_EL2_SYSREG(SCTLR2_EL2, SCTLR2_EL1); + MAPPED_EL2_SYSREG(CNTHCTL_EL2, CNTKCTL_EL1); + case SYS_SP_EL1: + if (!vcpu_has_el2(vcpu)) + return ARM64_CORE_REG(sp_el1); + + alias = SYS_SP_EL2; + break; + default: + BUILD_BUG(); + } + + return KVM_ARM64_SYS_REG(alias); +} + #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 3ab1fffbc3f2..11b6c5aa3f12 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -63,6 +63,9 @@ struct kvm_vcpu { struct kvm_run *run; #ifdef __x86_64__ struct kvm_cpuid2 *cpuid; +#endif +#ifdef __aarch64__ + struct kvm_vcpu_init init; #endif struct kvm_binary_stats stats; struct kvm_dirty_gfn *dirty_gfns; diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index de77d9a7e0cd..311660a9f655 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -283,15 +283,16 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init) } vcpu_ioctl(vcpu, KVM_ARM_VCPU_INIT, init); + vcpu->init = *init; /* * Enable FP/ASIMD to avoid trapping when accessing Q0-Q15 * registers, which the variable argument list macros do. */ - vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CPACR_EL1), 3 << 20); + vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_CPACR_EL1), 3 << 20); - sctlr_el1 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1)); - tcr_el1 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1)); + sctlr_el1 = vcpu_get_reg(vcpu, ctxt_reg_alias(vcpu, SYS_SCTLR_EL1)); + tcr_el1 = vcpu_get_reg(vcpu, ctxt_reg_alias(vcpu, SYS_TCR_EL1)); /* Configure base granule size */ switch (vm->mode) { @@ -358,10 +359,10 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init) if (use_lpa2_pte_format(vm)) tcr_el1 |= TCR_DS; - vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1); - vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1); - vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MAIR_EL1), DEFAULT_MAIR_EL1); - vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TTBR0_EL1), ttbr0_el1); + vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_SCTLR_EL1), sctlr_el1); + vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_TCR_EL1), tcr_el1); + vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_MAIR_EL1), DEFAULT_MAIR_EL1); + vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_TTBR0_EL1), ttbr0_el1); vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TPIDR_EL1), vcpu->id); } @@ -396,7 +397,7 @@ static struct kvm_vcpu *__aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, aarch64_vcpu_setup(vcpu, init); - vcpu_set_reg(vcpu, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); + vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_SP_EL1), stack_vaddr + stack_size); return vcpu; } @@ -466,7 +467,7 @@ void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu) { extern char vectors; - vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_VBAR_EL1), (uint64_t)&vectors); + vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_VBAR_EL1), (uint64_t)&vectors); } void route_exception(struct ex_regs *regs, int vector) From a1b91ac2381d86aa47b7109bbcde0c71e775f6d9 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:37 -0700 Subject: [PATCH 2064/2711] KVM: arm64: selftests: Provide helper for getting default vCPU target The default vCPU target in KVM selftests is pretty boring in that it doesn't enable any vCPU features. Expose a helper for getting the default target to prepare for cramming in more features. Call KVM_ARM_PREFERRED_TARGET directly from get-reg-list as it needs fine-grained control over feature flags. Signed-off-by: Oliver Upton Reviewed-by: Itaru Kitayama Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/arm64/psci_test.c | 2 +- .../testing/selftests/kvm/arm64/smccc_filter.c | 2 +- .../selftests/kvm/arm64/vpmu_counter_access.c | 4 ++-- tools/testing/selftests/kvm/get-reg-list.c | 9 ++++++--- .../selftests/kvm/include/arm64/processor.h | 2 ++ .../testing/selftests/kvm/lib/arm64/processor.c | 17 +++++++++++------ 6 files changed, 23 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/psci_test.c b/tools/testing/selftests/kvm/arm64/psci_test.c index cf208390fd0e..0d4680da66d1 100644 --- a/tools/testing/selftests/kvm/arm64/psci_test.c +++ b/tools/testing/selftests/kvm/arm64/psci_test.c @@ -89,7 +89,7 @@ static struct kvm_vm *setup_vm(void *guest_code, struct kvm_vcpu **source, vm = vm_create(2); - vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init); + kvm_get_default_vcpu_target(vm, &init); init.features[0] |= (1 << KVM_ARM_VCPU_PSCI_0_2); *source = aarch64_vcpu_add(vm, 0, &init, guest_code); diff --git a/tools/testing/selftests/kvm/arm64/smccc_filter.c b/tools/testing/selftests/kvm/arm64/smccc_filter.c index eb5551d21dbe..a8e22d866ea7 100644 --- a/tools/testing/selftests/kvm/arm64/smccc_filter.c +++ b/tools/testing/selftests/kvm/arm64/smccc_filter.c @@ -64,7 +64,7 @@ static struct kvm_vm *setup_vm(struct kvm_vcpu **vcpu) struct kvm_vm *vm; vm = vm_create(1); - vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init); + kvm_get_default_vcpu_target(vm, &init); /* * Enable in-kernel emulation of PSCI to ensure that calls are denied diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c index 36a3a8b4e0b5..2a8f31c8e59f 100644 --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c @@ -430,7 +430,7 @@ static void create_vpmu_vm(void *guest_code) } /* Create vCPU with PMUv3 */ - vm_ioctl(vpmu_vm.vm, KVM_ARM_PREFERRED_TARGET, &init); + kvm_get_default_vcpu_target(vpmu_vm.vm, &init); init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3); vpmu_vm.vcpu = aarch64_vcpu_add(vpmu_vm.vm, 0, &init, guest_code); vcpu_init_descriptor_tables(vpmu_vm.vcpu); @@ -525,7 +525,7 @@ static void run_access_test(uint64_t pmcr_n) * Reset and re-initialize the vCPU, and run the guest code again to * check if PMCR_EL0.N is preserved. */ - vm_ioctl(vpmu_vm.vm, KVM_ARM_PREFERRED_TARGET, &init); + kvm_get_default_vcpu_target(vpmu_vm.vm, &init); init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3); aarch64_vcpu_setup(vcpu, &init); vcpu_init_descriptor_tables(vcpu); diff --git a/tools/testing/selftests/kvm/get-reg-list.c b/tools/testing/selftests/kvm/get-reg-list.c index 91f05f78e824..f4644c9d2d3b 100644 --- a/tools/testing/selftests/kvm/get-reg-list.c +++ b/tools/testing/selftests/kvm/get-reg-list.c @@ -116,10 +116,13 @@ void __weak finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) } #ifdef __aarch64__ -static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init) +static void prepare_vcpu_init(struct kvm_vm *vm, struct vcpu_reg_list *c, + struct kvm_vcpu_init *init) { struct vcpu_reg_sublist *s; + vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, init); + for_each_sublist(c, s) if (s->capability) init->features[s->feature / 32] |= 1 << (s->feature % 32); @@ -127,10 +130,10 @@ static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *ini static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm_vm *vm) { - struct kvm_vcpu_init init = { .target = -1, }; + struct kvm_vcpu_init init; struct kvm_vcpu *vcpu; - prepare_vcpu_init(c, &init); + prepare_vcpu_init(vm, c, &init); vcpu = __vm_vcpu_add(vm, 0); aarch64_vcpu_setup(vcpu, &init); diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h index 5a4b29c1b965..87f50efed720 100644 --- a/tools/testing/selftests/kvm/include/arm64/processor.h +++ b/tools/testing/selftests/kvm/include/arm64/processor.h @@ -357,4 +357,6 @@ static __always_inline u64 ctxt_reg_alias(struct kvm_vcpu *vcpu, u32 encoding) return KVM_ARM64_SYS_REG(alias); } +void kvm_get_default_vcpu_target(struct kvm_vm *vm, struct kvm_vcpu_init *init); + #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index 311660a9f655..5ae65fefd48c 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -267,19 +267,24 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) } } +void kvm_get_default_vcpu_target(struct kvm_vm *vm, struct kvm_vcpu_init *init) +{ + struct kvm_vcpu_init preferred = {}; + + vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &preferred); + + *init = preferred; +} + void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init) { struct kvm_vcpu_init default_init = { .target = -1, }; struct kvm_vm *vm = vcpu->vm; uint64_t sctlr_el1, tcr_el1, ttbr0_el1; - if (!init) + if (!init) { + kvm_get_default_vcpu_target(vm, &default_init); init = &default_init; - - if (init->target == -1) { - struct kvm_vcpu_init preferred; - vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &preferred); - init->target = preferred.target; } vcpu_ioctl(vcpu, KVM_ARM_VCPU_INIT, init); From d72543ac728ae4a4708cbefad2761df84599c268 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:38 -0700 Subject: [PATCH 2065/2711] KVM: arm64: selftests: Select SMCCC conduit based on current EL HVCs are taken within the VM when EL2 is in use. Ensure tests use the SMC instruction when running at EL2 to interact with the host. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/arm64/hypercalls.c | 2 +- tools/testing/selftests/kvm/arm64/kvm-uuid.c | 2 +- tools/testing/selftests/kvm/arm64/psci_test.c | 10 +++++----- .../testing/selftests/kvm/include/arm64/processor.h | 13 +++++++++++++ tools/testing/selftests/kvm/steal_time.c | 2 +- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/hypercalls.c b/tools/testing/selftests/kvm/arm64/hypercalls.c index 44cfcf8a7f46..bf038a0371f4 100644 --- a/tools/testing/selftests/kvm/arm64/hypercalls.c +++ b/tools/testing/selftests/kvm/arm64/hypercalls.c @@ -108,7 +108,7 @@ static void guest_test_hvc(const struct test_hvc_info *hc_info) for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) { memset(&res, 0, sizeof(res)); - smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res); + do_smccc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res); switch (stage) { case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: diff --git a/tools/testing/selftests/kvm/arm64/kvm-uuid.c b/tools/testing/selftests/kvm/arm64/kvm-uuid.c index af9581b860f1..b5be9133535a 100644 --- a/tools/testing/selftests/kvm/arm64/kvm-uuid.c +++ b/tools/testing/selftests/kvm/arm64/kvm-uuid.c @@ -25,7 +25,7 @@ static void guest_code(void) { struct arm_smccc_res res = {}; - smccc_hvc(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0, 0, 0, 0, 0, 0, 0, &res); + do_smccc(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0, 0, 0, 0, 0, 0, 0, &res); __GUEST_ASSERT(res.a0 == ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 && res.a1 == ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 && diff --git a/tools/testing/selftests/kvm/arm64/psci_test.c b/tools/testing/selftests/kvm/arm64/psci_test.c index 0d4680da66d1..98e49f710aef 100644 --- a/tools/testing/selftests/kvm/arm64/psci_test.c +++ b/tools/testing/selftests/kvm/arm64/psci_test.c @@ -27,7 +27,7 @@ static uint64_t psci_cpu_on(uint64_t target_cpu, uint64_t entry_addr, { struct arm_smccc_res res; - smccc_hvc(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_addr, context_id, + do_smccc(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_addr, context_id, 0, 0, 0, 0, &res); return res.a0; @@ -38,7 +38,7 @@ static uint64_t psci_affinity_info(uint64_t target_affinity, { struct arm_smccc_res res; - smccc_hvc(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, lowest_affinity_level, + do_smccc(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, lowest_affinity_level, 0, 0, 0, 0, 0, &res); return res.a0; @@ -48,7 +48,7 @@ static uint64_t psci_system_suspend(uint64_t entry_addr, uint64_t context_id) { struct arm_smccc_res res; - smccc_hvc(PSCI_1_0_FN64_SYSTEM_SUSPEND, entry_addr, context_id, + do_smccc(PSCI_1_0_FN64_SYSTEM_SUSPEND, entry_addr, context_id, 0, 0, 0, 0, 0, &res); return res.a0; @@ -58,7 +58,7 @@ static uint64_t psci_system_off2(uint64_t type, uint64_t cookie) { struct arm_smccc_res res; - smccc_hvc(PSCI_1_3_FN64_SYSTEM_OFF2, type, cookie, 0, 0, 0, 0, 0, &res); + do_smccc(PSCI_1_3_FN64_SYSTEM_OFF2, type, cookie, 0, 0, 0, 0, 0, &res); return res.a0; } @@ -67,7 +67,7 @@ static uint64_t psci_features(uint32_t func_id) { struct arm_smccc_res res; - smccc_hvc(PSCI_1_0_FN_PSCI_FEATURES, func_id, 0, 0, 0, 0, 0, 0, &res); + do_smccc(PSCI_1_0_FN_PSCI_FEATURES, func_id, 0, 0, 0, 0, 0, 0, &res); return res.a0; } diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h index 87f50efed720..f037c1bb8e63 100644 --- a/tools/testing/selftests/kvm/include/arm64/processor.h +++ b/tools/testing/selftests/kvm/include/arm64/processor.h @@ -359,4 +359,17 @@ static __always_inline u64 ctxt_reg_alias(struct kvm_vcpu *vcpu, u32 encoding) void kvm_get_default_vcpu_target(struct kvm_vm *vm, struct kvm_vcpu_init *init); +static inline unsigned int get_current_el(void) +{ + return (read_sysreg(CurrentEL) >> 2) & 0x3; +} + +#define do_smccc(...) \ +do { \ + if (get_current_el() == 2) \ + smccc_smc(__VA_ARGS__); \ + else \ + smccc_hvc(__VA_ARGS__); \ +} while (0) + #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index cce2520af720..8edc1fca345b 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -118,7 +118,7 @@ static int64_t smccc(uint32_t func, uint64_t arg) { struct arm_smccc_res res; - smccc_hvc(func, arg, 0, 0, 0, 0, 0, 0, &res); + do_smccc(func, arg, 0, 0, 0, 0, 0, 0, &res); return res.a0; } From 0910778e49c6639d265ab2d7a47d0b461b8e2963 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:39 -0700 Subject: [PATCH 2066/2711] KVM: arm64: selftests: Use hyp timer IRQs when test runs at EL2 Arch timer registers are redirected to their hypervisor counterparts when running in VHE EL2. This is great, except for the fact that the hypervisor timers use different PPIs. Use the correct INTIDs when that is the case. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- .../testing/selftests/kvm/arm64/arch_timer.c | 6 ++--- .../kvm/arm64/arch_timer_edge_cases.c | 6 ++--- .../selftests/kvm/include/arm64/arch_timer.h | 24 +++++++++++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/arch_timer.c b/tools/testing/selftests/kvm/arm64/arch_timer.c index c753013319bc..d592a4515399 100644 --- a/tools/testing/selftests/kvm/arm64/arch_timer.c +++ b/tools/testing/selftests/kvm/arm64/arch_timer.c @@ -165,10 +165,8 @@ static void guest_code(void) static void test_init_timer_irq(struct kvm_vm *vm) { /* Timer initid should be same for all the vCPUs, so query only vCPU-0 */ - vcpu_device_attr_get(vcpus[0], KVM_ARM_VCPU_TIMER_CTRL, - KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq); - vcpu_device_attr_get(vcpus[0], KVM_ARM_VCPU_TIMER_CTRL, - KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq); + ptimer_irq = vcpu_get_ptimer_irq(vcpus[0]); + vtimer_irq = vcpu_get_vtimer_irq(vcpus[0]); sync_global_to_guest(vm, ptimer_irq); sync_global_to_guest(vm, vtimer_irq); diff --git a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c index 5c60262f4c2e..91906414a474 100644 --- a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c +++ b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c @@ -924,10 +924,8 @@ static void test_run(struct kvm_vm *vm, struct kvm_vcpu *vcpu) static void test_init_timer_irq(struct kvm_vm *vm, struct kvm_vcpu *vcpu) { - vcpu_device_attr_get(vcpu, KVM_ARM_VCPU_TIMER_CTRL, - KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq); - vcpu_device_attr_get(vcpu, KVM_ARM_VCPU_TIMER_CTRL, - KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq); + ptimer_irq = vcpu_get_ptimer_irq(vcpu); + vtimer_irq = vcpu_get_vtimer_irq(vcpu); sync_global_to_guest(vm, ptimer_irq); sync_global_to_guest(vm, vtimer_irq); diff --git a/tools/testing/selftests/kvm/include/arm64/arch_timer.h b/tools/testing/selftests/kvm/include/arm64/arch_timer.h index bf461de34785..e2c4e9f0010f 100644 --- a/tools/testing/selftests/kvm/include/arm64/arch_timer.h +++ b/tools/testing/selftests/kvm/include/arm64/arch_timer.h @@ -155,4 +155,28 @@ static inline void timer_set_next_tval_ms(enum arch_timer timer, uint32_t msec) timer_set_tval(timer, msec_to_cycles(msec)); } +static inline u32 vcpu_get_vtimer_irq(struct kvm_vcpu *vcpu) +{ + u32 intid; + u64 attr; + + attr = vcpu_has_el2(vcpu) ? KVM_ARM_VCPU_TIMER_IRQ_HVTIMER : + KVM_ARM_VCPU_TIMER_IRQ_VTIMER; + vcpu_device_attr_get(vcpu, KVM_ARM_VCPU_TIMER_CTRL, attr, &intid); + + return intid; +} + +static inline u32 vcpu_get_ptimer_irq(struct kvm_vcpu *vcpu) +{ + u32 intid; + u64 attr; + + attr = vcpu_has_el2(vcpu) ? KVM_ARM_VCPU_TIMER_IRQ_HPTIMER : + KVM_ARM_VCPU_TIMER_IRQ_PTIMER; + vcpu_device_attr_get(vcpu, KVM_ARM_VCPU_TIMER_CTRL, attr, &intid); + + return intid; +} + #endif /* SELFTEST_KVM_ARCH_TIMER_H */ From 7ae44d1cdad8a2483465373b9c9e91f0461ca9b2 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:40 -0700 Subject: [PATCH 2067/2711] KVM: arm64: selftests: Use the vCPU attr for setting nr of PMU counters Configuring the number of implemented counters via PMCR_EL0.N was a bad idea in retrospect as it interacts poorly with nested. Migrate the selftest to use the vCPU attribute instead of the KVM_SET_ONE_REG mechanism. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- .../selftests/kvm/arm64/vpmu_counter_access.c | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c index 2a8f31c8e59f..ae36325c022f 100644 --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c @@ -44,11 +44,6 @@ static uint64_t get_pmcr_n(uint64_t pmcr) return FIELD_GET(ARMV8_PMU_PMCR_N, pmcr); } -static void set_pmcr_n(uint64_t *pmcr, uint64_t pmcr_n) -{ - u64p_replace_bits((__u64 *) pmcr, pmcr_n, ARMV8_PMU_PMCR_N); -} - static uint64_t get_counters_mask(uint64_t n) { uint64_t mask = BIT(ARMV8_PMU_CYCLE_IDX); @@ -414,10 +409,6 @@ static void create_vpmu_vm(void *guest_code) .attr = KVM_ARM_VCPU_PMU_V3_IRQ, .addr = (uint64_t)&irq, }; - struct kvm_device_attr init_attr = { - .group = KVM_ARM_VCPU_PMU_V3_CTRL, - .attr = KVM_ARM_VCPU_PMU_V3_INIT, - }; /* The test creates the vpmu_vm multiple times. Ensure a clean state */ memset(&vpmu_vm, 0, sizeof(vpmu_vm)); @@ -444,9 +435,7 @@ static void create_vpmu_vm(void *guest_code) pmuver >= ID_AA64DFR0_EL1_PMUVer_IMP, "Unexpected PMUVER (0x%x) on the vCPU with PMUv3", pmuver); - /* Initialize vPMU */ vcpu_ioctl(vpmu_vm.vcpu, KVM_SET_DEVICE_ATTR, &irq_attr); - vcpu_ioctl(vpmu_vm.vcpu, KVM_SET_DEVICE_ATTR, &init_attr); } static void destroy_vpmu_vm(void) @@ -472,33 +461,28 @@ static void run_vcpu(struct kvm_vcpu *vcpu, uint64_t pmcr_n) } } -static void test_create_vpmu_vm_with_pmcr_n(uint64_t pmcr_n, bool expect_fail) +static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool expect_fail) { struct kvm_vcpu *vcpu; - uint64_t pmcr, pmcr_orig; + unsigned int prev; + int ret; create_vpmu_vm(guest_code); vcpu = vpmu_vm.vcpu; - pmcr_orig = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0)); - pmcr = pmcr_orig; + prev = get_pmcr_n(vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0))); - /* - * Setting a larger value of PMCR.N should not modify the field, and - * return a success. - */ - set_pmcr_n(&pmcr, pmcr_n); - vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0), pmcr); - pmcr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0)); + ret = __vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS, &nr_counters); if (expect_fail) - TEST_ASSERT(pmcr_orig == pmcr, - "PMCR.N modified by KVM to a larger value (PMCR: 0x%lx) for pmcr_n: 0x%lx", - pmcr, pmcr_n); + TEST_ASSERT(ret && errno == EINVAL, + "Setting more PMU counters (%u) than available (%u) unexpectedly succeeded", + nr_counters, prev); else - TEST_ASSERT(pmcr_n == get_pmcr_n(pmcr), - "Failed to update PMCR.N to %lu (received: %lu)", - pmcr_n, get_pmcr_n(pmcr)); + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret)); + + vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, KVM_ARM_VCPU_PMU_V3_INIT, NULL); } /* @@ -513,7 +497,7 @@ static void run_access_test(uint64_t pmcr_n) pr_debug("Test with pmcr_n %lu\n", pmcr_n); - test_create_vpmu_vm_with_pmcr_n(pmcr_n, false); + test_create_vpmu_vm_with_nr_counters(pmcr_n, false); vcpu = vpmu_vm.vcpu; /* Save the initial sp to restore them later to run the guest again */ @@ -554,7 +538,7 @@ static void run_pmregs_validity_test(uint64_t pmcr_n) uint64_t set_reg_id, clr_reg_id, reg_val; uint64_t valid_counters_mask, max_counters_mask; - test_create_vpmu_vm_with_pmcr_n(pmcr_n, false); + test_create_vpmu_vm_with_nr_counters(pmcr_n, false); vcpu = vpmu_vm.vcpu; valid_counters_mask = get_counters_mask(pmcr_n); @@ -608,7 +592,7 @@ static void run_error_test(uint64_t pmcr_n) { pr_debug("Error test with pmcr_n %lu (larger than the host)\n", pmcr_n); - test_create_vpmu_vm_with_pmcr_n(pmcr_n, true); + test_create_vpmu_vm_with_nr_counters(pmcr_n, true); destroy_vpmu_vm(); } @@ -626,12 +610,25 @@ static uint64_t get_pmcr_n_limit(void) return get_pmcr_n(pmcr); } +static bool kvm_supports_nr_counters_attr(void) +{ + bool supported; + + create_vpmu_vm(NULL); + supported = !__vcpu_has_device_attr(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS); + destroy_vpmu_vm(); + + return supported; +} + int main(void) { uint64_t i, pmcr_n; TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3)); TEST_REQUIRE(kvm_supports_vgic_v3()); + TEST_REQUIRE(kvm_supports_nr_counters_attr()); pmcr_n = get_pmcr_n_limit(); for (i = 0; i <= pmcr_n; i++) { From 05c93cbe6653e7e77567962aa6533b618df5e19f Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:41 -0700 Subject: [PATCH 2068/2711] KVM: arm64: selftests: Initialize HCR_EL2 Initialize HCR_EL2 such that EL2&0 is considered 'InHost', allowing the use of (mostly) unmodified EL1 selftests at EL2. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/lib/arm64/processor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index 5ae65fefd48c..4339de2fc482 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -369,6 +369,12 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init) vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_MAIR_EL1), DEFAULT_MAIR_EL1); vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_TTBR0_EL1), ttbr0_el1); vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TPIDR_EL1), vcpu->id); + + if (!vcpu_has_el2(vcpu)) + return; + + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_HCR_EL2), + HCR_EL2_RW | HCR_EL2_TGE | HCR_EL2_E2H); } void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent) From 2de21fb62387459f762c93eec3d04e4f7540b952 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:42 -0700 Subject: [PATCH 2069/2711] KVM: arm64: selftests: Enable EL2 by default Take advantage of VHE to implicitly promote KVM selftests to run at EL2 with only slight modification. Update the smccc_filter test to account for this now that the EL2-ness of a VM is visible to tests. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/arm64/smccc_filter.c | 14 +++++++++++++- .../selftests/kvm/include/arm64/processor.h | 1 + tools/testing/selftests/kvm/lib/arm64/processor.c | 12 ++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/arm64/smccc_filter.c b/tools/testing/selftests/kvm/arm64/smccc_filter.c index a8e22d866ea7..1763b9d45400 100644 --- a/tools/testing/selftests/kvm/arm64/smccc_filter.c +++ b/tools/testing/selftests/kvm/arm64/smccc_filter.c @@ -22,8 +22,20 @@ enum smccc_conduit { SMC_INSN, }; +static bool test_runs_at_el2(void) +{ + struct kvm_vm *vm = vm_create(1); + struct kvm_vcpu_init init; + + kvm_get_default_vcpu_target(vm, &init); + kvm_vm_free(vm); + + return init.features[0] & BIT(KVM_ARM_VCPU_HAS_EL2); +} + #define for_each_conduit(conduit) \ - for (conduit = HVC_INSN; conduit <= SMC_INSN; conduit++) + for (conduit = test_runs_at_el2() ? SMC_INSN : HVC_INSN; \ + conduit <= SMC_INSN; conduit++) static void guest_main(uint32_t func_id, enum smccc_conduit conduit) { diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h index f037c1bb8e63..b6b86e2cd59c 100644 --- a/tools/testing/selftests/kvm/include/arm64/processor.h +++ b/tools/testing/selftests/kvm/include/arm64/processor.h @@ -303,6 +303,7 @@ void wfi(void); void test_wants_mte(void); void test_disable_default_vgic(void); +bool vm_supports_el2(struct kvm_vm *vm); static bool vcpu_has_el2(struct kvm_vcpu *vcpu) { return vcpu->init.features[0] & BIT(KVM_ARM_VCPU_HAS_EL2); diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index 4339de2fc482..74324915b41e 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -267,11 +267,23 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) } } +bool vm_supports_el2(struct kvm_vm *vm) +{ + const char *value = getenv("NV"); + + if (value && *value == '0') + return false; + + return vm_check_cap(vm, KVM_CAP_ARM_EL2) && vm->arch.has_gic; +} + void kvm_get_default_vcpu_target(struct kvm_vm *vm, struct kvm_vcpu_init *init) { struct kvm_vcpu_init preferred = {}; vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &preferred); + if (vm_supports_el2(vm)) + preferred.features[0] |= BIT(KVM_ARM_VCPU_HAS_EL2); *init = preferred; } From f677b0efa93ce0afb127ccffb8aaf708045fcf10 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 17 Sep 2025 14:20:43 -0700 Subject: [PATCH 2070/2711] KVM: arm64: selftests: Add basic test for running in VHE EL2 Add an embarrassingly simple selftest for sanity checking KVM's VHE EL2 and test that the ID register bits are consistent with HCR_EL2.E2H being RES1. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/Makefile.kvm | 1 + tools/testing/selftests/kvm/arm64/hello_el2.c | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tools/testing/selftests/kvm/arm64/hello_el2.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 41b40c676d7f..5d59267d4089 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -156,6 +156,7 @@ TEST_GEN_PROGS_arm64 = $(TEST_GEN_PROGS_COMMON) TEST_GEN_PROGS_arm64 += arm64/aarch32_id_regs TEST_GEN_PROGS_arm64 += arm64/arch_timer_edge_cases TEST_GEN_PROGS_arm64 += arm64/debug-exceptions +TEST_GEN_PROGS_arm64 += arm64/hello_el2 TEST_GEN_PROGS_arm64 += arm64/host_sve TEST_GEN_PROGS_arm64 += arm64/hypercalls TEST_GEN_PROGS_arm64 += arm64/external_aborts diff --git a/tools/testing/selftests/kvm/arm64/hello_el2.c b/tools/testing/selftests/kvm/arm64/hello_el2.c new file mode 100644 index 000000000000..3c1f44e43f65 --- /dev/null +++ b/tools/testing/selftests/kvm/arm64/hello_el2.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * hello_el2 - Basic KVM selftest for VM running at EL2 with E2H=RES1 + * + * Copyright 2025 Google LLC + */ +#include "kvm_util.h" +#include "processor.h" +#include "test_util.h" +#include "ucall.h" + +#include + +static void guest_code(void) +{ + u64 mmfr1 = read_sysreg_s(SYS_ID_AA64MMFR1_EL1); + u64 mmfr4 = read_sysreg_s(SYS_ID_AA64MMFR4_EL1); + + GUEST_ASSERT_EQ(get_current_el(), 2); + GUEST_ASSERT(read_sysreg(hcr_el2) & HCR_EL2_E2H); + GUEST_ASSERT_EQ(SYS_FIELD_GET(ID_AA64MMFR1_EL1, VH, mmfr1), + ID_AA64MMFR1_EL1_VH_IMP); + GUEST_ASSERT_EQ(SYS_FIELD_GET(ID_AA64MMFR4_EL1, E2H0, mmfr4), + ID_AA64MMFR4_EL1_E2H0_NI_NV1); + + GUEST_DONE(); +} + +int main(void) +{ + struct kvm_vcpu_init init; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct ucall uc; + + TEST_REQUIRE(kvm_check_cap(KVM_CAP_ARM_EL2)); + + vm = vm_create(1); + + kvm_get_default_vcpu_target(vm, &init); + init.features[0] |= BIT(KVM_ARM_VCPU_HAS_EL2); + vcpu = aarch64_vcpu_add(vm, 0, &init, guest_code); + kvm_arch_vm_finalize_vcpus(vm); + + vcpu_run(vcpu); + switch (get_ucall(vcpu, &uc)) { + case UCALL_DONE: + break; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + default: + TEST_FAIL("Unhandled ucall: %ld\n", uc.cmd); + } + + kvm_vm_free(vm); + return 0; +} From 75b2fdc1a82195997cab4836f9e511cbe8c8eb52 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Tue, 23 Sep 2025 10:30:06 -0700 Subject: [PATCH 2071/2711] KVM: arm64: selftests: Cope with arch silliness in EL2 selftest Implementations without FEAT_FGT aren't required to trap the entire ID register space when HCR_EL2.TID3 is set. This is a terrible idea, as the hypervisor may need to advertise the absence of a feature to the VM using a negative value in a signed field, FEAT_E2H0 being a great example of this. Cope with uncooperative implementations in the EL2 selftest by accepting a zero value when FEAT_FGT is absent and otherwise only tolerating the expected nonzero value. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/arm64/hello_el2.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/hello_el2.c b/tools/testing/selftests/kvm/arm64/hello_el2.c index 3c1f44e43f65..bbe6862c6ab1 100644 --- a/tools/testing/selftests/kvm/arm64/hello_el2.c +++ b/tools/testing/selftests/kvm/arm64/hello_el2.c @@ -13,15 +13,28 @@ static void guest_code(void) { + u64 mmfr0 = read_sysreg_s(SYS_ID_AA64MMFR0_EL1); u64 mmfr1 = read_sysreg_s(SYS_ID_AA64MMFR1_EL1); u64 mmfr4 = read_sysreg_s(SYS_ID_AA64MMFR4_EL1); + u8 e2h0 = SYS_FIELD_GET(ID_AA64MMFR4_EL1, E2H0, mmfr4); GUEST_ASSERT_EQ(get_current_el(), 2); GUEST_ASSERT(read_sysreg(hcr_el2) & HCR_EL2_E2H); GUEST_ASSERT_EQ(SYS_FIELD_GET(ID_AA64MMFR1_EL1, VH, mmfr1), ID_AA64MMFR1_EL1_VH_IMP); - GUEST_ASSERT_EQ(SYS_FIELD_GET(ID_AA64MMFR4_EL1, E2H0, mmfr4), - ID_AA64MMFR4_EL1_E2H0_NI_NV1); + + /* + * Traps of the complete ID register space are IMPDEF without FEAT_FGT, + * which is really annoying to deal with in KVM describing E2H as RES1. + * + * If the implementation doesn't honor the trap then expect the register + * to return all zeros. + */ + if (e2h0 == ID_AA64MMFR4_EL1_E2H0_IMP) + GUEST_ASSERT_EQ(SYS_FIELD_GET(ID_AA64MMFR0_EL1, FGT, mmfr0), + ID_AA64MMFR0_EL1_FGT_NI); + else + GUEST_ASSERT_EQ(e2h0, ID_AA64MMFR4_EL1_E2H0_NI_NV1); GUEST_DONE(); } From 5a070fc376babc7efdc8288b97431e43e18f4646 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 20 Sep 2025 20:51:59 +0100 Subject: [PATCH 2072/2711] KVM: arm64: selftests: Remove a duplicate register listing in set_id_regs Currently we list the main set of registers with bits we test three times, once in the test_regs array which is used at runtime, once in the guest code and once in a list of ARRAY_SIZE() operations we use to tell kselftest how many tests we plan to execute. This is needlessly fiddly, when adding new registers as the test_cnt calculation is formatted with two registers per line. Instead count the number of bitfields in the register arrays at runtime. The existing code subtracts ARRAY_SIZE(test_regs) from the number of tests to account for the terminating FTR_REG_END entries in the per register arrays, the new code accounts for this when enumerating. Signed-off-by: Mark Brown Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/arm64/set_id_regs.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c index 77718628facf..788d88c08cc7 100644 --- a/tools/testing/selftests/kvm/arm64/set_id_regs.c +++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c @@ -753,7 +753,7 @@ int main(void) struct kvm_vm *vm; bool aarch64_only; uint64_t val, el0; - int test_cnt; + int test_cnt, i, j; TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_WRITABLE_IMP_ID_REGS)); @@ -772,13 +772,10 @@ int main(void) ksft_print_header(); - test_cnt = ARRAY_SIZE(ftr_id_aa64dfr0_el1) + ARRAY_SIZE(ftr_id_dfr0_el1) + - ARRAY_SIZE(ftr_id_aa64isar0_el1) + ARRAY_SIZE(ftr_id_aa64isar1_el1) + - ARRAY_SIZE(ftr_id_aa64isar2_el1) + ARRAY_SIZE(ftr_id_aa64pfr0_el1) + - ARRAY_SIZE(ftr_id_aa64pfr1_el1) + ARRAY_SIZE(ftr_id_aa64mmfr0_el1) + - ARRAY_SIZE(ftr_id_aa64mmfr1_el1) + ARRAY_SIZE(ftr_id_aa64mmfr2_el1) + - ARRAY_SIZE(ftr_id_aa64mmfr3_el1) + ARRAY_SIZE(ftr_id_aa64zfr0_el1) - - ARRAY_SIZE(test_regs) + 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST; + test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST; + for (i = 0; i < ARRAY_SIZE(test_regs); i++) + for (j = 0; test_regs[i].ftr_bits[j].type != FTR_END; j++) + test_cnt++; ksft_set_plan(test_cnt); From b02a2c060b657296c080cff1b54ee4e9e650811c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 20 Sep 2025 20:52:00 +0100 Subject: [PATCH 2073/2711] KVM: arm64: selftests: Cover ID_AA64ISAR3_EL1 in set_id_regs We have a couple of writable bitfields in ID_AA64ISAR3_EL1 but the set_id_regs selftest does not cover this register at all, add coverage. Signed-off-by: Mark Brown Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier --- tools/testing/selftests/kvm/arm64/set_id_regs.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c index 788d88c08cc7..898df554a58d 100644 --- a/tools/testing/selftests/kvm/arm64/set_id_regs.c +++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c @@ -123,6 +123,13 @@ static const struct reg_ftr_bits ftr_id_aa64isar2_el1[] = { REG_FTR_END, }; +static const struct reg_ftr_bits ftr_id_aa64isar3_el1[] = { + REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR3_EL1, FPRCVT, 0), + REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR3_EL1, LSFE, 0), + REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR3_EL1, FAMINMAX, 0), + REG_FTR_END, +}; + static const struct reg_ftr_bits ftr_id_aa64pfr0_el1[] = { REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, CSV3, 0), REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, CSV2, 0), @@ -219,6 +226,7 @@ static struct test_feature_reg test_regs[] = { TEST_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0_el1), TEST_REG(SYS_ID_AA64ISAR1_EL1, ftr_id_aa64isar1_el1), TEST_REG(SYS_ID_AA64ISAR2_EL1, ftr_id_aa64isar2_el1), + TEST_REG(SYS_ID_AA64ISAR3_EL1, ftr_id_aa64isar3_el1), TEST_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0_el1), TEST_REG(SYS_ID_AA64PFR1_EL1, ftr_id_aa64pfr1_el1), TEST_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0_el1), @@ -237,6 +245,7 @@ static void guest_code(void) GUEST_REG_SYNC(SYS_ID_AA64ISAR0_EL1); GUEST_REG_SYNC(SYS_ID_AA64ISAR1_EL1); GUEST_REG_SYNC(SYS_ID_AA64ISAR2_EL1); + GUEST_REG_SYNC(SYS_ID_AA64ISAR3_EL1); GUEST_REG_SYNC(SYS_ID_AA64PFR0_EL1); GUEST_REG_SYNC(SYS_ID_AA64MMFR0_EL1); GUEST_REG_SYNC(SYS_ID_AA64MMFR1_EL1); From 48991e4935078b05f80616c75d1ee2ea3ae18e58 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 24 Sep 2025 09:57:11 -0700 Subject: [PATCH 2074/2711] PCI/sysfs: Ensure devices are powered for config reads The "max_link_width", "current_link_speed", "current_link_width", "secondary_bus_number", and "subordinate_bus_number" sysfs files all access config registers, but they don't check the runtime PM state. If the device is in D3cold or a parent bridge is suspended, we may see -EINVAL, bogus values, or worse, depending on implementation details. Wrap these access in pci_config_pm_runtime_{get,put}() like most of the rest of the similar sysfs attributes. Notably, "max_link_speed" does not access config registers; it returns a cached value since d2bd39c0456b ("PCI: Store all PCIe Supported Link Speeds"). Fixes: 56c1af4606f0 ("PCI: Add sysfs max_link_speed/width, current_link_speed/width, etc") Signed-off-by: Brian Norris Signed-off-by: Brian Norris Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250924095711.v2.1.Ibb5b6ca1e2c059e04ec53140cd98a44f2684c668@changeid --- drivers/pci/pci-sysfs.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5eea14c1f7f5..2b231ef1dac9 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -201,8 +201,14 @@ static ssize_t max_link_width_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); + ssize_t ret; - return sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev)); + /* We read PCI_EXP_LNKCAP, so we need the device to be accessible. */ + pci_config_pm_runtime_get(pdev); + ret = sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev)); + pci_config_pm_runtime_put(pdev); + + return ret; } static DEVICE_ATTR_RO(max_link_width); @@ -214,7 +220,10 @@ static ssize_t current_link_speed_show(struct device *dev, int err; enum pci_bus_speed speed; + pci_config_pm_runtime_get(pci_dev); err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat); + pci_config_pm_runtime_put(pci_dev); + if (err) return -EINVAL; @@ -231,7 +240,10 @@ static ssize_t current_link_width_show(struct device *dev, u16 linkstat; int err; + pci_config_pm_runtime_get(pci_dev); err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat); + pci_config_pm_runtime_put(pci_dev); + if (err) return -EINVAL; @@ -247,7 +259,10 @@ static ssize_t secondary_bus_number_show(struct device *dev, u8 sec_bus; int err; + pci_config_pm_runtime_get(pci_dev); err = pci_read_config_byte(pci_dev, PCI_SECONDARY_BUS, &sec_bus); + pci_config_pm_runtime_put(pci_dev); + if (err) return -EINVAL; @@ -263,7 +278,10 @@ static ssize_t subordinate_bus_number_show(struct device *dev, u8 sub_bus; int err; + pci_config_pm_runtime_get(pci_dev); err = pci_read_config_byte(pci_dev, PCI_SUBORDINATE_BUS, &sub_bus); + pci_config_pm_runtime_put(pci_dev); + if (err) return -EINVAL; From 42f9c66a6d0cc45758dab77233c5460e1cf003df Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 22 Sep 2025 16:08:25 +0200 Subject: [PATCH 2075/2711] PCI: tegra194: Reset BARs when running in PCIe endpoint mode Tegra already defines all BARs except BAR0 as BAR_RESERVED. This is sufficient for pci-epf-test to not allocate backing memory and to not call set_bar() for those BARs. However, marking a BAR as BAR_RESERVED does not mean that the BAR gets disabled. The host side driver, pci_endpoint_test, simply does an ioremap for all enabled BARs and will run tests against all enabled BARs, so it will run tests against the BARs marked as BAR_RESERVED. After running the BAR tests (which will write to all enabled BARs), the inbound address translation is broken. This is because the tegra controller exposes the ATU Port Logic Structure in BAR4, so when BAR4 is written, the inbound address translation settings get overwritten. To avoid this, implement the dw_pcie_ep_ops .init() callback and start off by disabling all BARs (pci-epf-test will later enable/configure BARs that are not defined as BAR_RESERVED). This matches the behavior of other PCIe endpoint drivers: dra7xx, imx6, layerscape-ep, artpec6, dw-rockchip, qcom-ep, rcar-gen4, and uniphier-ep. With this, the PCI endpoint kselftest test case CONSECUTIVE_BAR_TEST (which was specifically made to detect address translation issues) passes. Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250922140822.519796-7-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-tegra194.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index fe418b9bfbb4..359d92dca86a 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1941,6 +1941,15 @@ static irqreturn_t tegra_pcie_ep_pex_rst_irq(int irq, void *arg) return IRQ_HANDLED; } +static void tegra_pcie_ep_init(struct dw_pcie_ep *ep) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + enum pci_barno bar; + + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) + dw_pcie_ep_reset_bar(pci, bar); +}; + static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq) { /* Tegra194 supports only INTA */ @@ -2016,6 +2025,7 @@ tegra_pcie_ep_get_features(struct dw_pcie_ep *ep) } static const struct dw_pcie_ep_ops pcie_ep_ops = { + .init = tegra_pcie_ep_init, .raise_irq = tegra_pcie_ep_raise_irq, .get_features = tegra_pcie_ep_get_features, }; From f8c9ad46b00453a8c075453f3745f8d263f44834 Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Mon, 22 Sep 2025 16:08:26 +0200 Subject: [PATCH 2076/2711] PCI: tegra194: Handle errors in BPMP response The return value from tegra_bpmp_transfer() indicates the success or failure of the IPC transaction with BPMP. If the transaction succeeded, we also need to check the actual command's result code. If we don't have error handling for tegra_bpmp_transfer(), we will set the pcie->ep_state to EP_STATE_ENABLED even when the tegra_bpmp_transfer() command fails. Thus, the pcie->ep_state will get out of sync with reality, and any further PERST# assert + deassert will be a no-op and will not trigger the hardware initialization sequence. This is because pex_ep_event_pex_rst_deassert() checks the current pcie->ep_state, and does nothing if the current state is already EP_STATE_ENABLED. Thus, it is important to have error handling for tegra_bpmp_transfer(), such that the pcie->ep_state can not get out of sync with reality, so that we will try to initialize the hardware not only during the first PERST# assert + deassert, but also during any succeeding PERST# assert + deassert. One example where this fix is needed is when using a rock5b as host. During the initial PERST# assert + deassert (triggered by the bootloader on the rock5b) pex_ep_event_pex_rst_deassert() will get called, but for some unknown reason, the tegra_bpmp_transfer() call to initialize the PHY fails. Once Linux has been loaded on the rock5b, the PCIe driver will once again assert + deassert PERST#. However, without tegra_bpmp_transfer() error handling, this second PERST# assert + deassert will not trigger the hardware initialization sequence. With tegra_bpmp_transfer() error handling, the second PERST# assert + deassert will once again trigger the hardware to be initialized and this time the tegra_bpmp_transfer() succeeds. Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") Signed-off-by: Vidya Sagar [cassel: improve commit log] Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Jon Hunter Acked-by: Thierry Reding Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250922140822.519796-8-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-tegra194.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 359d92dca86a..d71053fa4365 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1214,6 +1214,7 @@ static int tegra_pcie_bpmp_set_ctrl_state(struct tegra_pcie_dw *pcie, struct mrq_uphy_response resp; struct tegra_bpmp_message msg; struct mrq_uphy_request req; + int err; /* * Controller-5 doesn't need to have its state set by BPMP-FW in @@ -1236,7 +1237,13 @@ static int tegra_pcie_bpmp_set_ctrl_state(struct tegra_pcie_dw *pcie, msg.rx.data = &resp; msg.rx.size = sizeof(resp); - return tegra_bpmp_transfer(pcie->bpmp, &msg); + err = tegra_bpmp_transfer(pcie->bpmp, &msg); + if (err) + return err; + if (msg.rx.ret) + return -EINVAL; + + return 0; } static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, @@ -1245,6 +1252,7 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, struct mrq_uphy_response resp; struct tegra_bpmp_message msg; struct mrq_uphy_request req; + int err; memset(&req, 0, sizeof(req)); memset(&resp, 0, sizeof(resp)); @@ -1264,7 +1272,13 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, msg.rx.data = &resp; msg.rx.size = sizeof(resp); - return tegra_bpmp_transfer(pcie->bpmp, &msg); + err = tegra_bpmp_transfer(pcie->bpmp, &msg); + if (err) + return err; + if (msg.rx.ret) + return -EINVAL; + + return 0; } static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) From 7b1f8e7671ebe3cd8899aef17db870e9eba938a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Neusch=C3=A4fer?= Date: Tue, 23 Sep 2025 02:14:50 +0200 Subject: [PATCH 2077/2711] Input: ps2-gpio - fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "The data line must be sampled" makes much more sense than what was previously written, and given that "s" and "d" are neighbors on the QWERTY keybord, it was probably a typo. Signed-off-by: J. Neuschäfer Link: https://lore.kernel.org/r/20250923-ps2-typo-v1-1-03d2468acc32@posteo.net Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ps2-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/serio/ps2-gpio.c b/drivers/input/serio/ps2-gpio.c index 93769910ce24..46fb7667b244 100644 --- a/drivers/input/serio/ps2-gpio.c +++ b/drivers/input/serio/ps2-gpio.c @@ -50,7 +50,7 @@ * interrupt interval should be ~60us. Let's allow +/- 20us for frequency * deviations and interrupt latency. * - * The data line must be samples after ~30us to 50us after the falling edge, + * The data line must be sampled after ~30us to 50us after the falling edge, * since the device updates the data line at the rising edge. * * ___ ______ ______ ______ ___ From cf6f234d7dfbbb13197eb71e7716412d4e30988d Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Tue, 23 Sep 2025 16:37:34 +0200 Subject: [PATCH 2078/2711] dt-bindings: touchscreen: add debounce-delay-us property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for glitch delay configuration. A detected signal is valid only if it remains stable longer than the configured delay; otherwise, it is considered a glitch. This property was introduced for the i.MX6UL touchscreen controller (TSC), which provides a hardware deglitch filter with four thresholds depending on the IPG clock frequency. In this use case, the IPG clock rate is 66 MHz, resulting in thresholds of 124 µs, 62 µs, 31 µs, and 15 µs, which requires a property with microsecond-level resolution. Signed-off-by: Dario Binacchi Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250923143746.2857292-4-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/touchscreen.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml index 3e3572aa483a..7023e8c73a7b 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml @@ -206,6 +206,10 @@ properties: unevaluatedProperties: false + debounce-delay-us: + description: Minimum duration in microseconds a signal must remain stable + to be considered valid. + dependencies: touchscreen-size-x: [ touchscreen-size-y ] touchscreen-size-y: [ touchscreen-size-x ] From 3fccd1f9552dd073915b0a69d43cc03c582ce79b Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Tue, 23 Sep 2025 16:37:35 +0200 Subject: [PATCH 2079/2711] dt-bindings: touchscreen: fsl,imx6ul-tsc: support glitch thresold Support the debounce-delay-us property. Drivers must convert this value to IPG clock cycles and map it to one of the four discrete thresholds exposed by the TSC_DEBUG_MODE2 register: 0: 8191 IPG cycles 1: 4095 IPG cycles 2: 2047 IPG cycles 3: 1023 IPG cycles Signed-off-by: Dario Binacchi Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250923143746.2857292-5-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/fsl,imx6ul-tsc.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/fsl,imx6ul-tsc.yaml b/Documentation/devicetree/bindings/input/touchscreen/fsl,imx6ul-tsc.yaml index 678756ad0f92..a99280aefcbe 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/fsl,imx6ul-tsc.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/fsl,imx6ul-tsc.yaml @@ -62,6 +62,20 @@ properties: description: Number of data samples which are averaged for each read. enum: [ 1, 4, 8, 16, 32 ] + debounce-delay-us: + description: | + Minimum duration in microseconds a signal must remain stable + to be considered valid. + + Drivers must convert this value to IPG clock cycles and map + it to one of the four discrete thresholds exposed by the + TSC_DEBUG_MODE2 register: + + 0: 8191 IPG cycles + 1: 4095 IPG cycles + 2: 2047 IPG cycles + 3: 1023 IPG cycles + required: - compatible - reg From 5042e57d39719e531f3e122f12bf320869e84782 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Tue, 23 Sep 2025 16:37:37 +0200 Subject: [PATCH 2080/2711] Input: imx6ul_tsc - set glitch threshold by DTS property Set the glitch threshold by DTS property and keep the existing default behavior if the 'debounce-delay-us' is not present. Signed-off-by: Dario Binacchi Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250923143746.2857292-7-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imx6ul_tsc.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index e2c59cc7c82c..85f697de2b7e 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -79,7 +79,7 @@ #define MEASURE_SIG_EN BIT(0) #define VALID_SIG_EN BIT(8) #define DE_GLITCH_MASK GENMASK(30, 29) -#define DE_GLITCH_2 0x02 +#define DE_GLITCH_DEF 0x02 #define START_SENSE BIT(12) #define TSC_DISABLE BIT(16) #define DETECT_MODE 0x2 @@ -98,6 +98,7 @@ struct imx6ul_tsc { u32 pre_charge_time; bool average_enable; u32 average_select; + u32 de_glitch; struct completion completion; }; @@ -205,7 +206,7 @@ static void imx6ul_tsc_set(struct imx6ul_tsc *tsc) basic_setting |= AUTO_MEASURE; writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETTING); - debug_mode2 = FIELD_PREP(DE_GLITCH_MASK, DE_GLITCH_2); + debug_mode2 = FIELD_PREP(DE_GLITCH_MASK, tsc->de_glitch); writel(debug_mode2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2); writel(tsc->pre_charge_time, tsc->tsc_regs + REG_TSC_PRE_CHARGE_TIME); @@ -391,6 +392,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) int tsc_irq; int adc_irq; u32 average_samples; + u32 de_glitch; tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL); if (!tsc) @@ -513,6 +515,25 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) return -EINVAL; } + err = of_property_read_u32(np, "debounce-delay-us", &de_glitch); + if (err) { + tsc->de_glitch = DE_GLITCH_DEF; + } else { + u64 cycles; + unsigned long rate = clk_get_rate(tsc->tsc_clk); + + cycles = DIV64_U64_ROUND_UP((u64)de_glitch * rate, USEC_PER_SEC); + + if (cycles <= 0x3ff) + tsc->de_glitch = 3; + else if (cycles <= 0x7ff) + tsc->de_glitch = 2; + else if (cycles <= 0xfff) + tsc->de_glitch = 1; + else + tsc->de_glitch = 0; + } + err = input_register_device(tsc->input); if (err) { dev_err(&pdev->dev, From 581b4da1f73c9e0caf9b7d0a46d1b5a0b36fbe20 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:38:58 +0530 Subject: [PATCH 2081/2711] dt-bindings: mailbox: Add bindings for RISC-V SBI MPXY extension Add device tree bindings for the RISC-V SBI Message Proxy (MPXY) extension as a mailbox controller. Reviewed-by: Conor Dooley Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-3-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- .../bindings/mailbox/riscv,sbi-mpxy-mbox.yaml | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/mailbox/riscv,sbi-mpxy-mbox.yaml diff --git a/Documentation/devicetree/bindings/mailbox/riscv,sbi-mpxy-mbox.yaml b/Documentation/devicetree/bindings/mailbox/riscv,sbi-mpxy-mbox.yaml new file mode 100644 index 000000000000..061437a0b45a --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/riscv,sbi-mpxy-mbox.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mailbox/riscv,sbi-mpxy-mbox.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V SBI Message Proxy (MPXY) extension based mailbox + +maintainers: + - Anup Patel + +description: | + The RISC-V SBI Message Proxy (MPXY) extension [1] allows supervisor + software to send messages through the SBI implementation (M-mode + firmware or HS-mode hypervisor). The underlying message protocol + and message format used by the supervisor software could be some + other standard protocol compatible with the SBI MPXY extension + (such as RISC-V Platform Management Interface (RPMI) [2]). + + =========================================== + References + =========================================== + + [1] RISC-V Supervisor Binary Interface (SBI) v3.0 (or higher) + https://github.com/riscv-non-isa/riscv-sbi-doc/releases + + [2] RISC-V Platform Management Interface (RPMI) v1.0 (or higher) + https://github.com/riscv-non-isa/riscv-rpmi/releases + +properties: + compatible: + const: riscv,sbi-mpxy-mbox + + "#mbox-cells": + const: 2 + description: + The first cell specifies channel_id of the SBI MPXY channel, + the second cell specifies MSG_PROT_ID of the SBI MPXY channel + +required: + - compatible + - "#mbox-cells" + +additionalProperties: false + +examples: + - | + mailbox { + compatible = "riscv,sbi-mpxy-mbox"; + #mbox-cells = <2>; + }; From 508da38677a67ed9aa87c3cf32807284f293c304 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:38:59 +0530 Subject: [PATCH 2082/2711] RISC-V: Add defines for the SBI message proxy extension Add defines for the new SBI message proxy extension which is part of the SBI v3.0 specification. Reviewed-by: Atish Patra Reviewed-by: Andy Shevchenko Co-developed-by: Rahul Pathak Signed-off-by: Rahul Pathak Signed-off-by: Anup Patel Link: https://lore.kernel.org/r/20250818040920.272664-4-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/sbi.h | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 341e74238aa0..c19e5c7383a6 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -36,6 +36,7 @@ enum sbi_ext_id { SBI_EXT_STA = 0x535441, SBI_EXT_NACL = 0x4E41434C, SBI_EXT_FWFT = 0x46574654, + SBI_EXT_MPXY = 0x4D505859, /* Experimentals extensions must lie within this range */ SBI_EXT_EXPERIMENTAL_START = 0x08000000, @@ -430,6 +431,67 @@ enum sbi_fwft_feature_t { #define SBI_FWFT_SET_FLAG_LOCK BIT(0) +enum sbi_ext_mpxy_fid { + SBI_EXT_MPXY_GET_SHMEM_SIZE, + SBI_EXT_MPXY_SET_SHMEM, + SBI_EXT_MPXY_GET_CHANNEL_IDS, + SBI_EXT_MPXY_READ_ATTRS, + SBI_EXT_MPXY_WRITE_ATTRS, + SBI_EXT_MPXY_SEND_MSG_WITH_RESP, + SBI_EXT_MPXY_SEND_MSG_WITHOUT_RESP, + SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS, +}; + +enum sbi_mpxy_attribute_id { + /* Standard channel attributes managed by MPXY framework */ + SBI_MPXY_ATTR_MSG_PROT_ID = 0x00000000, + SBI_MPXY_ATTR_MSG_PROT_VER = 0x00000001, + SBI_MPXY_ATTR_MSG_MAX_LEN = 0x00000002, + SBI_MPXY_ATTR_MSG_SEND_TIMEOUT = 0x00000003, + SBI_MPXY_ATTR_MSG_COMPLETION_TIMEOUT = 0x00000004, + SBI_MPXY_ATTR_CHANNEL_CAPABILITY = 0x00000005, + SBI_MPXY_ATTR_SSE_EVENT_ID = 0x00000006, + SBI_MPXY_ATTR_MSI_CONTROL = 0x00000007, + SBI_MPXY_ATTR_MSI_ADDR_LO = 0x00000008, + SBI_MPXY_ATTR_MSI_ADDR_HI = 0x00000009, + SBI_MPXY_ATTR_MSI_DATA = 0x0000000A, + SBI_MPXY_ATTR_EVENTS_STATE_CONTROL = 0x0000000B, + SBI_MPXY_ATTR_STD_ATTR_MAX_IDX, + /* + * Message protocol specific attributes, managed by + * the message protocol specification. + */ + SBI_MPXY_ATTR_MSGPROTO_ATTR_START = 0x80000000, + SBI_MPXY_ATTR_MSGPROTO_ATTR_END = 0xffffffff +}; + +/* Possible values of MSG_PROT_ID attribute as-per SBI v3.0 (or higher) */ +enum sbi_mpxy_msgproto_id { + SBI_MPXY_MSGPROTO_RPMI_ID = 0x0, +}; + +/* RPMI message protocol specific MPXY attributes */ +enum sbi_mpxy_rpmi_attribute_id { + SBI_MPXY_RPMI_ATTR_SERVICEGROUP_ID = SBI_MPXY_ATTR_MSGPROTO_ATTR_START, + SBI_MPXY_RPMI_ATTR_SERVICEGROUP_VERSION, + SBI_MPXY_RPMI_ATTR_IMPL_ID, + SBI_MPXY_RPMI_ATTR_IMPL_VERSION, + SBI_MPXY_RPMI_ATTR_MAX_ID +}; + +/* Encoding of MSG_PROT_VER attribute */ +#define SBI_MPXY_MSG_PROT_VER_MAJOR(__ver) upper_16_bits(__ver) +#define SBI_MPXY_MSG_PROT_VER_MINOR(__ver) lower_16_bits(__ver) +#define SBI_MPXY_MSG_PROT_MKVER(__maj, __min) (((u32)(__maj) << 16) | (u16)(__min)) + +/* Capabilities available through CHANNEL_CAPABILITY attribute */ +#define SBI_MPXY_CHAN_CAP_MSI BIT(0) +#define SBI_MPXY_CHAN_CAP_SSE BIT(1) +#define SBI_MPXY_CHAN_CAP_EVENTS_STATE BIT(2) +#define SBI_MPXY_CHAN_CAP_SEND_WITH_RESP BIT(3) +#define SBI_MPXY_CHAN_CAP_SEND_WITHOUT_RESP BIT(4) +#define SBI_MPXY_CHAN_CAP_GET_NOTIFICATIONS BIT(5) + /* SBI spec version fields */ #define SBI_SPEC_VERSION_DEFAULT 0x1 #define SBI_SPEC_VERSION_MAJOR_SHIFT 24 From 340974c4f709ce8142a672ab11f1889dff94d6dc Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:00 +0530 Subject: [PATCH 2083/2711] mailbox: Add common header for RPMI messages sent via mailbox The RPMI based mailbox controller drivers and mailbox clients need to share defines related to RPMI messages over mailbox interface so add a common header for this purpose. Acked-by: Jassi Brar Co-developed-by: Rahul Pathak Signed-off-by: Rahul Pathak Signed-off-by: Anup Patel Link: https://lore.kernel.org/r/20250818040920.272664-5-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- include/linux/mailbox/riscv-rpmi-message.h | 214 +++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 include/linux/mailbox/riscv-rpmi-message.h diff --git a/include/linux/mailbox/riscv-rpmi-message.h b/include/linux/mailbox/riscv-rpmi-message.h new file mode 100644 index 000000000000..c3a98fc12c0a --- /dev/null +++ b/include/linux/mailbox/riscv-rpmi-message.h @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2025 Ventana Micro Systems Inc. */ + +#ifndef _LINUX_RISCV_RPMI_MESSAGE_H_ +#define _LINUX_RISCV_RPMI_MESSAGE_H_ + +#include +#include +#include +#include + +/* RPMI version encode/decode macros */ +#define RPMI_VER_MAJOR(__ver) upper_16_bits(__ver) +#define RPMI_VER_MINOR(__ver) lower_16_bits(__ver) +#define RPMI_MKVER(__maj, __min) (((u32)(__maj) << 16) | (u16)(__min)) + +/* RPMI message header */ +struct rpmi_message_header { + __le16 servicegroup_id; + u8 service_id; + u8 flags; + __le16 datalen; + __le16 token; +}; + +/* RPMI message */ +struct rpmi_message { + struct rpmi_message_header header; + u8 data[]; +}; + +/* RPMI notification event */ +struct rpmi_notification_event { + __le16 event_datalen; + u8 event_id; + u8 reserved; + u8 event_data[]; +}; + +/* RPMI error codes */ +enum rpmi_error_codes { + RPMI_SUCCESS = 0, + RPMI_ERR_FAILED = -1, + RPMI_ERR_NOTSUPP = -2, + RPMI_ERR_INVALID_PARAM = -3, + RPMI_ERR_DENIED = -4, + RPMI_ERR_INVALID_ADDR = -5, + RPMI_ERR_ALREADY = -6, + RPMI_ERR_EXTENSION = -7, + RPMI_ERR_HW_FAULT = -8, + RPMI_ERR_BUSY = -9, + RPMI_ERR_INVALID_STATE = -10, + RPMI_ERR_BAD_RANGE = -11, + RPMI_ERR_TIMEOUT = -12, + RPMI_ERR_IO = -13, + RPMI_ERR_NO_DATA = -14, + RPMI_ERR_RESERVED_START = -15, + RPMI_ERR_RESERVED_END = -127, + RPMI_ERR_VENDOR_START = -128, +}; + +static inline int rpmi_to_linux_error(int rpmi_error) +{ + switch (rpmi_error) { + case RPMI_SUCCESS: + return 0; + case RPMI_ERR_INVALID_PARAM: + case RPMI_ERR_BAD_RANGE: + case RPMI_ERR_INVALID_STATE: + return -EINVAL; + case RPMI_ERR_DENIED: + return -EPERM; + case RPMI_ERR_INVALID_ADDR: + case RPMI_ERR_HW_FAULT: + return -EFAULT; + case RPMI_ERR_ALREADY: + return -EALREADY; + case RPMI_ERR_BUSY: + return -EBUSY; + case RPMI_ERR_TIMEOUT: + return -ETIMEDOUT; + case RPMI_ERR_IO: + return -ECOMM; + case RPMI_ERR_FAILED: + case RPMI_ERR_NOTSUPP: + case RPMI_ERR_NO_DATA: + case RPMI_ERR_EXTENSION: + default: + return -EOPNOTSUPP; + } +} + +/* RPMI Linux mailbox attribute IDs */ +enum rpmi_mbox_attribute_id { + RPMI_MBOX_ATTR_SPEC_VERSION, + RPMI_MBOX_ATTR_MAX_MSG_DATA_SIZE, + RPMI_MBOX_ATTR_SERVICEGROUP_ID, + RPMI_MBOX_ATTR_SERVICEGROUP_VERSION, + RPMI_MBOX_ATTR_IMPL_ID, + RPMI_MBOX_ATTR_IMPL_VERSION, + RPMI_MBOX_ATTR_MAX_ID +}; + +/* RPMI Linux mailbox message types */ +enum rpmi_mbox_message_type { + RPMI_MBOX_MSG_TYPE_GET_ATTRIBUTE, + RPMI_MBOX_MSG_TYPE_SET_ATTRIBUTE, + RPMI_MBOX_MSG_TYPE_SEND_WITH_RESPONSE, + RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE, + RPMI_MBOX_MSG_TYPE_NOTIFICATION_EVENT, + RPMI_MBOX_MSG_MAX_TYPE +}; + +/* RPMI Linux mailbox message instance */ +struct rpmi_mbox_message { + enum rpmi_mbox_message_type type; + union { + struct { + enum rpmi_mbox_attribute_id id; + u32 value; + } attr; + + struct { + u32 service_id; + void *request; + unsigned long request_len; + void *response; + unsigned long max_response_len; + unsigned long out_response_len; + } data; + + struct { + u16 event_datalen; + u8 event_id; + u8 *event_data; + } notif; + }; + int error; +}; + +/* RPMI Linux mailbox message helper routines */ +static inline void rpmi_mbox_init_get_attribute(struct rpmi_mbox_message *msg, + enum rpmi_mbox_attribute_id id) +{ + msg->type = RPMI_MBOX_MSG_TYPE_GET_ATTRIBUTE; + msg->attr.id = id; + msg->attr.value = 0; + msg->error = 0; +} + +static inline void rpmi_mbox_init_set_attribute(struct rpmi_mbox_message *msg, + enum rpmi_mbox_attribute_id id, + u32 value) +{ + msg->type = RPMI_MBOX_MSG_TYPE_SET_ATTRIBUTE; + msg->attr.id = id; + msg->attr.value = value; + msg->error = 0; +} + +static inline void rpmi_mbox_init_send_with_response(struct rpmi_mbox_message *msg, + u32 service_id, + void *request, + unsigned long request_len, + void *response, + unsigned long max_response_len) +{ + msg->type = RPMI_MBOX_MSG_TYPE_SEND_WITH_RESPONSE; + msg->data.service_id = service_id; + msg->data.request = request; + msg->data.request_len = request_len; + msg->data.response = response; + msg->data.max_response_len = max_response_len; + msg->data.out_response_len = 0; + msg->error = 0; +} + +static inline void rpmi_mbox_init_send_without_response(struct rpmi_mbox_message *msg, + u32 service_id, + void *request, + unsigned long request_len) +{ + msg->type = RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE; + msg->data.service_id = service_id; + msg->data.request = request; + msg->data.request_len = request_len; + msg->data.response = NULL; + msg->data.max_response_len = 0; + msg->data.out_response_len = 0; + msg->error = 0; +} + +static inline void *rpmi_mbox_get_msg_response(struct rpmi_mbox_message *msg) +{ + return msg ? msg->data.response : NULL; +} + +static inline int rpmi_mbox_send_message(struct mbox_chan *chan, + struct rpmi_mbox_message *msg) +{ + int ret; + + /* Send message for the underlying mailbox channel */ + ret = mbox_send_message(chan, msg); + if (ret < 0) + return ret; + + /* Explicitly signal txdone for mailbox channel */ + ret = msg->error; + mbox_client_txdone(chan, ret); + return ret; +} + +#endif /* _LINUX_RISCV_RPMI_MESSAGE_H_ */ From 15c5867b0ae6a47914b45daf3b64e2d2aceb4ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Wed, 24 Sep 2025 16:56:41 +0300 Subject: [PATCH 2084/2711] PCI: Don't print stale information about resource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pbus_size_mem() logs the bridge window resource using pci_info() before the start and end fields of the resource have been updated which then prints stale information. Set resource addresses earlier to make understanding logs easier. Regrettably, this results in setting the addresses multiple times but that seems unavoidable. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250924135641.3399-1-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index d264f16772b9..362ad108794d 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1317,6 +1317,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, resource_size_t children_add_align = 0; resource_size_t add_align = 0; resource_size_t relaxed_align; + resource_size_t old_size; if (!b_res) return; @@ -1387,20 +1388,24 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, } } + old_size = resource_size(b_res); win_align = window_alignment(bus, b_res->flags); min_align = calculate_mem_align(aligns, max_order); min_align = max(min_align, win_align); - size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), min_align); + size0 = calculate_memsize(size, min_size, 0, 0, old_size, min_align); - if (size0) + if (size0) { + resource_set_range(b_res, min_align, size0); b_res->flags &= ~IORESOURCE_DISABLED; + } if (bus->self && size0 && !pbus_upstream_space_available(bus, b_res, size0, min_align)) { relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); relaxed_align = max(relaxed_align, win_align); min_align = min(min_align, relaxed_align); - size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), win_align); + size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); + resource_set_range(b_res, min_align, size0); pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n", b_res, &bus->busn_res); } @@ -1408,7 +1413,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, if (realloc_head && (add_size > 0 || children_add_size > 0)) { add_align = max(min_align, add_align); size1 = calculate_memsize(size, min_size, add_size, children_add_size, - resource_size(b_res), add_align); + old_size, add_align); if (bus->self && size1 && !pbus_upstream_space_available(bus, b_res, size1, add_align)) { @@ -1416,7 +1421,7 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, relaxed_align = max(relaxed_align, win_align); min_align = min(min_align, relaxed_align); size1 = calculate_memsize(size, min_size, add_size, children_add_size, - resource_size(b_res), win_align); + old_size, win_align); pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n", b_res, &bus->busn_res); From ba879dfc0574878f3e08f217b2b4fdf845c426c0 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:01 +0530 Subject: [PATCH 2085/2711] mailbox: Allow controller specific mapping using fwnode Introduce optional fw_node() callback which allows a mailbox controller driver to provide controller specific mapping using fwnode. The Linux OF framework already implements fwnode operations for the Linux DD framework so the fw_xlate() callback works fine with device tree as well. Acked-by: Jassi Brar Reviewed-by: Andy Shevchenko Signed-off-by: Anup Patel Link: https://lore.kernel.org/r/20250818040920.272664-6-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/mailbox/mailbox.c | 65 ++++++++++++++++++------------ include/linux/mailbox_controller.h | 3 ++ 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 5cd8ae222073..2acc6ec229a4 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "mailbox.h" @@ -383,34 +384,56 @@ EXPORT_SYMBOL_GPL(mbox_bind_client); */ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index) { - struct device *dev = cl->dev; + struct fwnode_reference_args fwspec; + struct fwnode_handle *fwnode; struct mbox_controller *mbox; struct of_phandle_args spec; struct mbox_chan *chan; + struct device *dev; + unsigned int i; int ret; - if (!dev || !dev->of_node) { - pr_debug("%s: No owner device node\n", __func__); + dev = cl->dev; + if (!dev) { + pr_debug("No owner device\n"); return ERR_PTR(-ENODEV); } - ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells", - index, &spec); + fwnode = dev_fwnode(dev); + if (!fwnode) { + dev_dbg(dev, "No owner fwnode\n"); + return ERR_PTR(-ENODEV); + } + + ret = fwnode_property_get_reference_args(fwnode, "mboxes", "#mbox-cells", + 0, index, &fwspec); if (ret) { - dev_err(dev, "%s: can't parse \"mboxes\" property\n", __func__); + dev_err(dev, "%s: can't parse \"%s\" property\n", __func__, "mboxes"); return ERR_PTR(ret); } + spec.np = to_of_node(fwspec.fwnode); + spec.args_count = fwspec.nargs; + for (i = 0; i < spec.args_count; i++) + spec.args[i] = fwspec.args[i]; + scoped_guard(mutex, &con_mutex) { chan = ERR_PTR(-EPROBE_DEFER); - list_for_each_entry(mbox, &mbox_cons, node) - if (mbox->dev->of_node == spec.np) { - chan = mbox->of_xlate(mbox, &spec); - if (!IS_ERR(chan)) - break; + list_for_each_entry(mbox, &mbox_cons, node) { + if (device_match_fwnode(mbox->dev, fwspec.fwnode)) { + if (mbox->fw_xlate) { + chan = mbox->fw_xlate(mbox, &fwspec); + if (!IS_ERR(chan)) + break; + } else if (mbox->of_xlate) { + chan = mbox->of_xlate(mbox, &spec); + if (!IS_ERR(chan)) + break; + } } + } - of_node_put(spec.np); + fwnode_handle_put(fwspec.fwnode); if (IS_ERR(chan)) return chan; @@ -427,15 +450,8 @@ EXPORT_SYMBOL_GPL(mbox_request_channel); struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl, const char *name) { - struct device_node *np = cl->dev->of_node; - int index; + int index = device_property_match_string(cl->dev, "mbox-names", name); - if (!np) { - dev_err(cl->dev, "%s() currently only supports DT\n", __func__); - return ERR_PTR(-EINVAL); - } - - index = of_property_match_string(np, "mbox-names", name); if (index < 0) { dev_err(cl->dev, "%s() could not locate channel named \"%s\"\n", __func__, name); @@ -470,9 +486,8 @@ void mbox_free_channel(struct mbox_chan *chan) } EXPORT_SYMBOL_GPL(mbox_free_channel); -static struct mbox_chan * -of_mbox_index_xlate(struct mbox_controller *mbox, - const struct of_phandle_args *sp) +static struct mbox_chan *fw_mbox_index_xlate(struct mbox_controller *mbox, + const struct fwnode_reference_args *sp) { int ind = sp->args[0]; @@ -523,8 +538,8 @@ int mbox_controller_register(struct mbox_controller *mbox) spin_lock_init(&chan->lock); } - if (!mbox->of_xlate) - mbox->of_xlate = of_mbox_index_xlate; + if (!mbox->fw_xlate && !mbox->of_xlate) + mbox->fw_xlate = fw_mbox_index_xlate; scoped_guard(mutex, &con_mutex) list_add_tail(&mbox->node, &mbox_cons); diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h index ad01c4082358..80a427c7ca29 100644 --- a/include/linux/mailbox_controller.h +++ b/include/linux/mailbox_controller.h @@ -66,6 +66,7 @@ struct mbox_chan_ops { * no interrupt rises. Ignored if 'txdone_irq' is set. * @txpoll_period: If 'txdone_poll' is in effect, the API polls for * last TX's status after these many millisecs + * @fw_xlate: Controller driver specific mapping of channel via fwnode * @of_xlate: Controller driver specific mapping of channel via DT * @poll_hrt: API private. hrtimer used to poll for TXDONE on all * channels. @@ -79,6 +80,8 @@ struct mbox_controller { bool txdone_irq; bool txdone_poll; unsigned txpoll_period; + struct mbox_chan *(*fw_xlate)(struct mbox_controller *mbox, + const struct fwnode_reference_args *sp); struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox, const struct of_phandle_args *sp); /* Internal to API */ From 6f01c24f3a7525e953d514367a6d91b39c8f1f6a Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:02 +0530 Subject: [PATCH 2086/2711] byteorder: Add memcpy_to_le32() and memcpy_from_le32() Add common memcpy APIs for copying u32 array to/from __le32 array. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Anup Patel Reviewed-by: Linus Walleij Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-7-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- include/linux/byteorder/generic.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h index c9a4c96c9943..b3705e8bbe2b 100644 --- a/include/linux/byteorder/generic.h +++ b/include/linux/byteorder/generic.h @@ -173,6 +173,22 @@ static inline void cpu_to_le32_array(u32 *buf, unsigned int words) } } +static inline void memcpy_from_le32(u32 *dst, const __le32 *src, size_t words) +{ + size_t i; + + for (i = 0; i < words; i++) + dst[i] = le32_to_cpu(src[i]); +} + +static inline void memcpy_to_le32(__le32 *dst, const u32 *src, size_t words) +{ + size_t i; + + for (i = 0; i < words; i++) + dst[i] = cpu_to_le32(src[i]); +} + static inline void be16_add_cpu(__be16 *var, u16 val) { *var = cpu_to_be16(be16_to_cpu(*var) + val); From bf3022a4eb119c6b4e3424d6b19d8bfdfbc9bb57 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:03 +0530 Subject: [PATCH 2087/2711] mailbox: Add RISC-V SBI message proxy (MPXY) based mailbox driver Add a mailbox controller driver for the new SBI message proxy extension which is part of the SBI v3.0 specification. Acked-by: Jassi Brar Co-developed-by: Rahul Pathak Signed-off-by: Rahul Pathak Signed-off-by: Anup Patel Link: https://lore.kernel.org/r/20250818040920.272664-8-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/mailbox/Kconfig | 11 + drivers/mailbox/Makefile | 2 + drivers/mailbox/riscv-sbi-mpxy-mbox.c | 994 ++++++++++++++++++++++++++ 3 files changed, 1007 insertions(+) create mode 100644 drivers/mailbox/riscv-sbi-mpxy-mbox.c diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 02432d4a5ccd..c488725aa2a5 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -369,4 +369,15 @@ config BCM74110_MAILBOX processor and coprocessor that handles various power management task and more. +config RISCV_SBI_MPXY_MBOX + tristate "RISC-V SBI Message Proxy (MPXY) Mailbox" + depends on RISCV_SBI + default RISCV + help + Mailbox driver implementation for RISC-V SBI Message Proxy (MPXY) + extension. This mailbox driver is used to send messages to the + remote processor through the SBI implementation (M-mode firmware + or HS-mode hypervisor). Say Y here if you want to have this support. + If unsure say N. + endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 98a68f838486..f9a11f5639aa 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -78,3 +78,5 @@ obj-$(CONFIG_THEAD_TH1520_MBOX) += mailbox-th1520.o obj-$(CONFIG_CIX_MBOX) += cix-mailbox.o obj-$(CONFIG_BCM74110_MAILBOX) += bcm74110-mailbox.o + +obj-$(CONFIG_RISCV_SBI_MPXY_MBOX) += riscv-sbi-mpxy-mbox.o diff --git a/drivers/mailbox/riscv-sbi-mpxy-mbox.c b/drivers/mailbox/riscv-sbi-mpxy-mbox.c new file mode 100644 index 000000000000..21404baa6df0 --- /dev/null +++ b/drivers/mailbox/riscv-sbi-mpxy-mbox.c @@ -0,0 +1,994 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RISC-V SBI Message Proxy (MPXY) mailbox controller driver + * + * Copyright (C) 2025 Ventana Micro Systems Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ====== SBI MPXY extension data structures ====== */ + +/* SBI MPXY MSI related channel attributes */ +struct sbi_mpxy_msi_info { + /* Lower 32-bits of the MSI target address */ + u32 msi_addr_lo; + /* Upper 32-bits of the MSI target address */ + u32 msi_addr_hi; + /* MSI data value */ + u32 msi_data; +}; + +/* + * SBI MPXY standard channel attributes. + * + * NOTE: The sequence of attribute fields are as-per the + * defined sequence in the attribute table in spec (or + * as-per the enum sbi_mpxy_attribute_id). + */ +struct sbi_mpxy_channel_attrs { + /* Message protocol ID */ + u32 msg_proto_id; + /* Message protocol version */ + u32 msg_proto_version; + /* Message protocol maximum message length */ + u32 msg_max_len; + /* Message protocol message send timeout in microseconds */ + u32 msg_send_timeout; + /* Message protocol message completion timeout in microseconds */ + u32 msg_completion_timeout; + /* Bit array for channel capabilities */ + u32 capability; + /* SSE event ID */ + u32 sse_event_id; + /* MSI enable/disable control knob */ + u32 msi_control; + /* Channel MSI info */ + struct sbi_mpxy_msi_info msi_info; + /* Events state control */ + u32 events_state_ctrl; +}; + +/* + * RPMI specific SBI MPXY channel attributes. + * + * NOTE: The sequence of attribute fields are as-per the + * defined sequence in the attribute table in spec (or + * as-per the enum sbi_mpxy_rpmi_attribute_id). + */ +struct sbi_mpxy_rpmi_channel_attrs { + /* RPMI service group ID */ + u32 servicegroup_id; + /* RPMI service group version */ + u32 servicegroup_version; + /* RPMI implementation ID */ + u32 impl_id; + /* RPMI implementation version */ + u32 impl_version; +}; + +/* SBI MPXY channel IDs data in shared memory */ +struct sbi_mpxy_channel_ids_data { + /* Remaining number of channel ids */ + __le32 remaining; + /* Returned channel ids in current function call */ + __le32 returned; + /* Returned channel id array */ + __le32 channel_array[]; +}; + +/* SBI MPXY notification data in shared memory */ +struct sbi_mpxy_notification_data { + /* Remaining number of notification events */ + __le32 remaining; + /* Number of notification events returned */ + __le32 returned; + /* Number of notification events lost */ + __le32 lost; + /* Reserved for future use */ + __le32 reserved; + /* Returned channel id array */ + u8 events_data[]; +}; + +/* ====== MPXY data structures & helper routines ====== */ + +/* MPXY Per-CPU or local context */ +struct mpxy_local { + /* Shared memory base address */ + void *shmem; + /* Shared memory physical address */ + phys_addr_t shmem_phys_addr; + /* Flag representing whether shared memory is active or not */ + bool shmem_active; +}; + +static DEFINE_PER_CPU(struct mpxy_local, mpxy_local); +static unsigned long mpxy_shmem_size; +static bool mpxy_shmem_init_done; + +static int mpxy_get_channel_count(u32 *channel_count) +{ + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); + struct sbi_mpxy_channel_ids_data *sdata = mpxy->shmem; + u32 remaining, returned; + struct sbiret sret; + + if (!mpxy->shmem_active) + return -ENODEV; + if (!channel_count) + return -EINVAL; + + get_cpu(); + + /* Get the remaining and returned fields to calculate total */ + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_CHANNEL_IDS, + 0, 0, 0, 0, 0, 0); + if (sret.error) + goto err_put_cpu; + + remaining = le32_to_cpu(sdata->remaining); + returned = le32_to_cpu(sdata->returned); + *channel_count = remaining + returned; + +err_put_cpu: + put_cpu(); + return sbi_err_map_linux_errno(sret.error); +} + +static int mpxy_get_channel_ids(u32 channel_count, u32 *channel_ids) +{ + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); + struct sbi_mpxy_channel_ids_data *sdata = mpxy->shmem; + u32 remaining, returned, count, start_index = 0; + struct sbiret sret; + + if (!mpxy->shmem_active) + return -ENODEV; + if (!channel_count || !channel_ids) + return -EINVAL; + + get_cpu(); + + do { + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_CHANNEL_IDS, + start_index, 0, 0, 0, 0, 0); + if (sret.error) + goto err_put_cpu; + + remaining = le32_to_cpu(sdata->remaining); + returned = le32_to_cpu(sdata->returned); + + count = returned < (channel_count - start_index) ? + returned : (channel_count - start_index); + memcpy_from_le32(&channel_ids[start_index], sdata->channel_array, count); + start_index += count; + } while (remaining && start_index < channel_count); + +err_put_cpu: + put_cpu(); + return sbi_err_map_linux_errno(sret.error); +} + +static int mpxy_read_attrs(u32 channel_id, u32 base_attrid, u32 attr_count, + u32 *attrs_buf) +{ + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); + struct sbiret sret; + + if (!mpxy->shmem_active) + return -ENODEV; + if (!attr_count || !attrs_buf) + return -EINVAL; + + get_cpu(); + + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_READ_ATTRS, + channel_id, base_attrid, attr_count, 0, 0, 0); + if (sret.error) + goto err_put_cpu; + + memcpy_from_le32(attrs_buf, (__le32 *)mpxy->shmem, attr_count); + +err_put_cpu: + put_cpu(); + return sbi_err_map_linux_errno(sret.error); +} + +static int mpxy_write_attrs(u32 channel_id, u32 base_attrid, u32 attr_count, + u32 *attrs_buf) +{ + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); + struct sbiret sret; + + if (!mpxy->shmem_active) + return -ENODEV; + if (!attr_count || !attrs_buf) + return -EINVAL; + + get_cpu(); + + memcpy_to_le32((__le32 *)mpxy->shmem, attrs_buf, attr_count); + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_WRITE_ATTRS, + channel_id, base_attrid, attr_count, 0, 0, 0); + + put_cpu(); + return sbi_err_map_linux_errno(sret.error); +} + +static int mpxy_send_message_with_resp(u32 channel_id, u32 msg_id, + void *tx, unsigned long tx_len, + void *rx, unsigned long max_rx_len, + unsigned long *rx_len) +{ + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); + unsigned long rx_bytes; + struct sbiret sret; + + if (!mpxy->shmem_active) + return -ENODEV; + if (!tx && tx_len) + return -EINVAL; + + get_cpu(); + + /* Message protocols allowed to have no data in messages */ + if (tx_len) + memcpy(mpxy->shmem, tx, tx_len); + + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SEND_MSG_WITH_RESP, + channel_id, msg_id, tx_len, 0, 0, 0); + if (rx && !sret.error) { + rx_bytes = sret.value; + if (rx_bytes > max_rx_len) { + put_cpu(); + return -ENOSPC; + } + + memcpy(rx, mpxy->shmem, rx_bytes); + if (rx_len) + *rx_len = rx_bytes; + } + + put_cpu(); + return sbi_err_map_linux_errno(sret.error); +} + +static int mpxy_send_message_without_resp(u32 channel_id, u32 msg_id, + void *tx, unsigned long tx_len) +{ + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); + struct sbiret sret; + + if (!mpxy->shmem_active) + return -ENODEV; + if (!tx && tx_len) + return -EINVAL; + + get_cpu(); + + /* Message protocols allowed to have no data in messages */ + if (tx_len) + memcpy(mpxy->shmem, tx, tx_len); + + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SEND_MSG_WITHOUT_RESP, + channel_id, msg_id, tx_len, 0, 0, 0); + + put_cpu(); + return sbi_err_map_linux_errno(sret.error); +} + +static int mpxy_get_notifications(u32 channel_id, + struct sbi_mpxy_notification_data *notif_data, + unsigned long *events_data_len) +{ + struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local); + struct sbiret sret; + + if (!mpxy->shmem_active) + return -ENODEV; + if (!notif_data || !events_data_len) + return -EINVAL; + + get_cpu(); + + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS, + channel_id, 0, 0, 0, 0, 0); + if (sret.error) + goto err_put_cpu; + + memcpy(notif_data, mpxy->shmem, sret.value + 16); + *events_data_len = sret.value; + +err_put_cpu: + put_cpu(); + return sbi_err_map_linux_errno(sret.error); +} + +static int mpxy_get_shmem_size(unsigned long *shmem_size) +{ + struct sbiret sret; + + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_SHMEM_SIZE, + 0, 0, 0, 0, 0, 0); + if (sret.error) + return sbi_err_map_linux_errno(sret.error); + if (shmem_size) + *shmem_size = sret.value; + return 0; +} + +static int mpxy_setup_shmem(unsigned int cpu) +{ + struct page *shmem_page; + struct mpxy_local *mpxy; + struct sbiret sret; + + mpxy = per_cpu_ptr(&mpxy_local, cpu); + if (mpxy->shmem_active) + return 0; + + shmem_page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(mpxy_shmem_size)); + if (!shmem_page) + return -ENOMEM; + + /* + * Linux setup of shmem is done in mpxy OVERWRITE mode. + * flags[1:0] = 00b + */ + sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SET_SHMEM, + page_to_phys(shmem_page), 0, 0, 0, 0, 0); + if (sret.error) { + free_pages((unsigned long)page_to_virt(shmem_page), + get_order(mpxy_shmem_size)); + return sbi_err_map_linux_errno(sret.error); + } + + mpxy->shmem = page_to_virt(shmem_page); + mpxy->shmem_phys_addr = page_to_phys(shmem_page); + mpxy->shmem_active = true; + + return 0; +} + +/* ====== MPXY mailbox data structures ====== */ + +/* MPXY mailbox channel */ +struct mpxy_mbox_channel { + struct mpxy_mbox *mbox; + u32 channel_id; + struct sbi_mpxy_channel_attrs attrs; + struct sbi_mpxy_rpmi_channel_attrs rpmi_attrs; + struct sbi_mpxy_notification_data *notif; + u32 max_xfer_len; + bool have_events_state; + u32 msi_index; + u32 msi_irq; + bool started; +}; + +/* MPXY mailbox */ +struct mpxy_mbox { + struct device *dev; + u32 channel_count; + struct mpxy_mbox_channel *channels; + u32 msi_count; + struct mpxy_mbox_channel **msi_index_to_channel; + struct mbox_controller controller; +}; + +/* ====== MPXY RPMI processing ====== */ + +static void mpxy_mbox_send_rpmi_data(struct mpxy_mbox_channel *mchan, + struct rpmi_mbox_message *msg) +{ + msg->error = 0; + switch (msg->type) { + case RPMI_MBOX_MSG_TYPE_GET_ATTRIBUTE: + switch (msg->attr.id) { + case RPMI_MBOX_ATTR_SPEC_VERSION: + msg->attr.value = mchan->attrs.msg_proto_version; + break; + case RPMI_MBOX_ATTR_MAX_MSG_DATA_SIZE: + msg->attr.value = mchan->max_xfer_len; + break; + case RPMI_MBOX_ATTR_SERVICEGROUP_ID: + msg->attr.value = mchan->rpmi_attrs.servicegroup_id; + break; + case RPMI_MBOX_ATTR_SERVICEGROUP_VERSION: + msg->attr.value = mchan->rpmi_attrs.servicegroup_version; + break; + case RPMI_MBOX_ATTR_IMPL_ID: + msg->attr.value = mchan->rpmi_attrs.impl_id; + break; + case RPMI_MBOX_ATTR_IMPL_VERSION: + msg->attr.value = mchan->rpmi_attrs.impl_version; + break; + default: + msg->error = -EOPNOTSUPP; + break; + } + break; + case RPMI_MBOX_MSG_TYPE_SET_ATTRIBUTE: + /* None of the RPMI linux mailbox attributes are writeable */ + msg->error = -EOPNOTSUPP; + break; + case RPMI_MBOX_MSG_TYPE_SEND_WITH_RESPONSE: + if ((!msg->data.request && msg->data.request_len) || + (msg->data.request && msg->data.request_len > mchan->max_xfer_len) || + (!msg->data.response && msg->data.max_response_len)) { + msg->error = -EINVAL; + break; + } + if (!(mchan->attrs.capability & SBI_MPXY_CHAN_CAP_SEND_WITH_RESP)) { + msg->error = -EIO; + break; + } + msg->error = mpxy_send_message_with_resp(mchan->channel_id, + msg->data.service_id, + msg->data.request, + msg->data.request_len, + msg->data.response, + msg->data.max_response_len, + &msg->data.out_response_len); + break; + case RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE: + if ((!msg->data.request && msg->data.request_len) || + (msg->data.request && msg->data.request_len > mchan->max_xfer_len)) { + msg->error = -EINVAL; + break; + } + if (!(mchan->attrs.capability & SBI_MPXY_CHAN_CAP_SEND_WITHOUT_RESP)) { + msg->error = -EIO; + break; + } + msg->error = mpxy_send_message_without_resp(mchan->channel_id, + msg->data.service_id, + msg->data.request, + msg->data.request_len); + break; + default: + msg->error = -EOPNOTSUPP; + break; + } +} + +static void mpxy_mbox_peek_rpmi_data(struct mbox_chan *chan, + struct mpxy_mbox_channel *mchan, + struct sbi_mpxy_notification_data *notif, + unsigned long events_data_len) +{ + struct rpmi_notification_event *event; + struct rpmi_mbox_message msg; + unsigned long pos = 0; + + while (pos < events_data_len && (events_data_len - pos) <= sizeof(*event)) { + event = (struct rpmi_notification_event *)(notif->events_data + pos); + + msg.type = RPMI_MBOX_MSG_TYPE_NOTIFICATION_EVENT; + msg.notif.event_datalen = le16_to_cpu(event->event_datalen); + msg.notif.event_id = event->event_id; + msg.notif.event_data = event->event_data; + msg.error = 0; + + mbox_chan_received_data(chan, &msg); + pos += sizeof(*event) + msg.notif.event_datalen; + } +} + +static int mpxy_mbox_read_rpmi_attrs(struct mpxy_mbox_channel *mchan) +{ + return mpxy_read_attrs(mchan->channel_id, + SBI_MPXY_ATTR_MSGPROTO_ATTR_START, + sizeof(mchan->rpmi_attrs) / sizeof(u32), + (u32 *)&mchan->rpmi_attrs); +} + +/* ====== MPXY mailbox callbacks ====== */ + +static int mpxy_mbox_send_data(struct mbox_chan *chan, void *data) +{ + struct mpxy_mbox_channel *mchan = chan->con_priv; + + if (mchan->attrs.msg_proto_id == SBI_MPXY_MSGPROTO_RPMI_ID) { + mpxy_mbox_send_rpmi_data(mchan, data); + return 0; + } + + return -EOPNOTSUPP; +} + +static bool mpxy_mbox_peek_data(struct mbox_chan *chan) +{ + struct mpxy_mbox_channel *mchan = chan->con_priv; + struct sbi_mpxy_notification_data *notif = mchan->notif; + bool have_notifications = false; + unsigned long data_len; + int rc; + + if (!(mchan->attrs.capability & SBI_MPXY_CHAN_CAP_GET_NOTIFICATIONS)) + return false; + + do { + rc = mpxy_get_notifications(mchan->channel_id, notif, &data_len); + if (rc || !data_len) + break; + + if (mchan->attrs.msg_proto_id == SBI_MPXY_MSGPROTO_RPMI_ID) + mpxy_mbox_peek_rpmi_data(chan, mchan, notif, data_len); + + have_notifications = true; + } while (1); + + return have_notifications; +} + +static irqreturn_t mpxy_mbox_irq_thread(int irq, void *dev_id) +{ + mpxy_mbox_peek_data(dev_id); + return IRQ_HANDLED; +} + +static int mpxy_mbox_setup_msi(struct mbox_chan *chan, + struct mpxy_mbox_channel *mchan) +{ + struct device *dev = mchan->mbox->dev; + int rc; + + /* Do nothing if MSI not supported */ + if (mchan->msi_irq == U32_MAX) + return 0; + + /* Fail if MSI already enabled */ + if (mchan->attrs.msi_control) + return -EALREADY; + + /* Request channel MSI handler */ + rc = request_threaded_irq(mchan->msi_irq, NULL, mpxy_mbox_irq_thread, + 0, dev_name(dev), chan); + if (rc) { + dev_err(dev, "failed to request MPXY channel 0x%x IRQ\n", + mchan->channel_id); + return rc; + } + + /* Enable channel MSI control */ + mchan->attrs.msi_control = 1; + rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_CONTROL, + 1, &mchan->attrs.msi_control); + if (rc) { + dev_err(dev, "enable MSI control failed for MPXY channel 0x%x\n", + mchan->channel_id); + mchan->attrs.msi_control = 0; + free_irq(mchan->msi_irq, chan); + return rc; + } + + return 0; +} + +static void mpxy_mbox_cleanup_msi(struct mbox_chan *chan, + struct mpxy_mbox_channel *mchan) +{ + struct device *dev = mchan->mbox->dev; + int rc; + + /* Do nothing if MSI not supported */ + if (mchan->msi_irq == U32_MAX) + return; + + /* Do nothing if MSI already disabled */ + if (!mchan->attrs.msi_control) + return; + + /* Disable channel MSI control */ + mchan->attrs.msi_control = 0; + rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_CONTROL, + 1, &mchan->attrs.msi_control); + if (rc) { + dev_err(dev, "disable MSI control failed for MPXY channel 0x%x\n", + mchan->channel_id); + } + + /* Free channel MSI handler */ + free_irq(mchan->msi_irq, chan); +} + +static int mpxy_mbox_setup_events(struct mpxy_mbox_channel *mchan) +{ + struct device *dev = mchan->mbox->dev; + int rc; + + /* Do nothing if events state not supported */ + if (!mchan->have_events_state) + return 0; + + /* Fail if events state already enabled */ + if (mchan->attrs.events_state_ctrl) + return -EALREADY; + + /* Enable channel events state */ + mchan->attrs.events_state_ctrl = 1; + rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_EVENTS_STATE_CONTROL, + 1, &mchan->attrs.events_state_ctrl); + if (rc) { + dev_err(dev, "enable events state failed for MPXY channel 0x%x\n", + mchan->channel_id); + mchan->attrs.events_state_ctrl = 0; + return rc; + } + + return 0; +} + +static void mpxy_mbox_cleanup_events(struct mpxy_mbox_channel *mchan) +{ + struct device *dev = mchan->mbox->dev; + int rc; + + /* Do nothing if events state not supported */ + if (!mchan->have_events_state) + return; + + /* Do nothing if events state already disabled */ + if (!mchan->attrs.events_state_ctrl) + return; + + /* Disable channel events state */ + mchan->attrs.events_state_ctrl = 0; + rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_EVENTS_STATE_CONTROL, + 1, &mchan->attrs.events_state_ctrl); + if (rc) + dev_err(dev, "disable events state failed for MPXY channel 0x%x\n", + mchan->channel_id); +} + +static int mpxy_mbox_startup(struct mbox_chan *chan) +{ + struct mpxy_mbox_channel *mchan = chan->con_priv; + int rc; + + if (mchan->started) + return -EALREADY; + + /* Setup channel MSI */ + rc = mpxy_mbox_setup_msi(chan, mchan); + if (rc) + return rc; + + /* Setup channel notification events */ + rc = mpxy_mbox_setup_events(mchan); + if (rc) { + mpxy_mbox_cleanup_msi(chan, mchan); + return rc; + } + + /* Mark the channel as started */ + mchan->started = true; + + return 0; +} + +static void mpxy_mbox_shutdown(struct mbox_chan *chan) +{ + struct mpxy_mbox_channel *mchan = chan->con_priv; + + if (!mchan->started) + return; + + /* Mark the channel as stopped */ + mchan->started = false; + + /* Cleanup channel notification events */ + mpxy_mbox_cleanup_events(mchan); + + /* Cleanup channel MSI */ + mpxy_mbox_cleanup_msi(chan, mchan); +} + +static const struct mbox_chan_ops mpxy_mbox_ops = { + .send_data = mpxy_mbox_send_data, + .peek_data = mpxy_mbox_peek_data, + .startup = mpxy_mbox_startup, + .shutdown = mpxy_mbox_shutdown, +}; + +/* ====== MPXY platform driver ===== */ + +static void mpxy_mbox_msi_write(struct msi_desc *desc, struct msi_msg *msg) +{ + struct device *dev = msi_desc_to_dev(desc); + struct mpxy_mbox *mbox = dev_get_drvdata(dev); + struct mpxy_mbox_channel *mchan; + struct sbi_mpxy_msi_info *minfo; + int rc; + + mchan = mbox->msi_index_to_channel[desc->msi_index]; + if (!mchan) { + dev_warn(dev, "MPXY channel not available for MSI index %d\n", + desc->msi_index); + return; + } + + minfo = &mchan->attrs.msi_info; + minfo->msi_addr_lo = msg->address_lo; + minfo->msi_addr_hi = msg->address_hi; + minfo->msi_data = msg->data; + + rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_ADDR_LO, + sizeof(*minfo) / sizeof(u32), (u32 *)minfo); + if (rc) { + dev_warn(dev, "failed to write MSI info for MPXY channel 0x%x\n", + mchan->channel_id); + } +} + +static struct mbox_chan *mpxy_mbox_fw_xlate(struct mbox_controller *ctlr, + const struct fwnode_reference_args *pa) +{ + struct mpxy_mbox *mbox = container_of(ctlr, struct mpxy_mbox, controller); + struct mpxy_mbox_channel *mchan; + u32 i; + + if (pa->nargs != 2) + return ERR_PTR(-EINVAL); + + for (i = 0; i < mbox->channel_count; i++) { + mchan = &mbox->channels[i]; + if (mchan->channel_id == pa->args[0] && + mchan->attrs.msg_proto_id == pa->args[1]) + return &mbox->controller.chans[i]; + } + + return ERR_PTR(-ENOENT); +} + +static int mpxy_mbox_populate_channels(struct mpxy_mbox *mbox) +{ + u32 i, *channel_ids __free(kfree) = NULL; + struct mpxy_mbox_channel *mchan; + int rc; + + /* Find-out of number of channels */ + rc = mpxy_get_channel_count(&mbox->channel_count); + if (rc) + return dev_err_probe(mbox->dev, rc, "failed to get number of MPXY channels\n"); + if (!mbox->channel_count) + return dev_err_probe(mbox->dev, -ENODEV, "no MPXY channels available\n"); + + /* Allocate and fetch all channel IDs */ + channel_ids = kcalloc(mbox->channel_count, sizeof(*channel_ids), GFP_KERNEL); + if (!channel_ids) + return -ENOMEM; + rc = mpxy_get_channel_ids(mbox->channel_count, channel_ids); + if (rc) + return dev_err_probe(mbox->dev, rc, "failed to get MPXY channel IDs\n"); + + /* Populate all channels */ + mbox->channels = devm_kcalloc(mbox->dev, mbox->channel_count, + sizeof(*mbox->channels), GFP_KERNEL); + if (!mbox->channels) + return -ENOMEM; + for (i = 0; i < mbox->channel_count; i++) { + mchan = &mbox->channels[i]; + mchan->mbox = mbox; + mchan->channel_id = channel_ids[i]; + + rc = mpxy_read_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSG_PROT_ID, + sizeof(mchan->attrs) / sizeof(u32), + (u32 *)&mchan->attrs); + if (rc) { + return dev_err_probe(mbox->dev, rc, + "MPXY channel 0x%x read attrs failed\n", + mchan->channel_id); + } + + if (mchan->attrs.msg_proto_id == SBI_MPXY_MSGPROTO_RPMI_ID) { + rc = mpxy_mbox_read_rpmi_attrs(mchan); + if (rc) { + return dev_err_probe(mbox->dev, rc, + "MPXY channel 0x%x read RPMI attrs failed\n", + mchan->channel_id); + } + } + + mchan->notif = devm_kzalloc(mbox->dev, mpxy_shmem_size, GFP_KERNEL); + if (!mchan->notif) + return -ENOMEM; + + mchan->max_xfer_len = min(mpxy_shmem_size, mchan->attrs.msg_max_len); + + if ((mchan->attrs.capability & SBI_MPXY_CHAN_CAP_GET_NOTIFICATIONS) && + (mchan->attrs.capability & SBI_MPXY_CHAN_CAP_EVENTS_STATE)) + mchan->have_events_state = true; + + if ((mchan->attrs.capability & SBI_MPXY_CHAN_CAP_GET_NOTIFICATIONS) && + (mchan->attrs.capability & SBI_MPXY_CHAN_CAP_MSI)) + mchan->msi_index = mbox->msi_count++; + else + mchan->msi_index = U32_MAX; + mchan->msi_irq = U32_MAX; + } + + return 0; +} + +static int mpxy_mbox_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mpxy_mbox_channel *mchan; + struct mpxy_mbox *mbox; + int msi_idx, rc; + u32 i; + + /* + * Initialize MPXY shared memory only once. This also ensures + * that SBI MPXY mailbox is probed only once. + */ + if (mpxy_shmem_init_done) { + dev_err(dev, "SBI MPXY mailbox already initialized\n"); + return -EALREADY; + } + + /* Probe for SBI MPXY extension */ + if (sbi_spec_version < sbi_mk_version(1, 0) || + sbi_probe_extension(SBI_EXT_MPXY) <= 0) { + dev_info(dev, "SBI MPXY extension not available\n"); + return -ENODEV; + } + + /* Find-out shared memory size */ + rc = mpxy_get_shmem_size(&mpxy_shmem_size); + if (rc) + return dev_err_probe(dev, rc, "failed to get MPXY shared memory size\n"); + + /* + * Setup MPXY shared memory on each CPU + * + * Note: Don't cleanup MPXY shared memory upon CPU power-down + * because the RPMI System MSI irqchip driver needs it to be + * available when migrating IRQs in CPU power-down path. + */ + cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/sbi-mpxy-shmem", + mpxy_setup_shmem, NULL); + + /* Mark as MPXY shared memory initialization done */ + mpxy_shmem_init_done = true; + + /* Allocate mailbox instance */ + mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); + if (!mbox) + return -ENOMEM; + mbox->dev = dev; + platform_set_drvdata(pdev, mbox); + + /* Populate mailbox channels */ + rc = mpxy_mbox_populate_channels(mbox); + if (rc) + return rc; + + /* Initialize mailbox controller */ + mbox->controller.txdone_irq = false; + mbox->controller.txdone_poll = false; + mbox->controller.ops = &mpxy_mbox_ops; + mbox->controller.dev = dev; + mbox->controller.num_chans = mbox->channel_count; + mbox->controller.fw_xlate = mpxy_mbox_fw_xlate; + mbox->controller.chans = devm_kcalloc(dev, mbox->channel_count, + sizeof(*mbox->controller.chans), + GFP_KERNEL); + if (!mbox->controller.chans) + return -ENOMEM; + for (i = 0; i < mbox->channel_count; i++) + mbox->controller.chans[i].con_priv = &mbox->channels[i]; + + /* Setup MSIs for mailbox (if required) */ + if (mbox->msi_count) { + /* + * The device MSI domain for platform devices on RISC-V architecture + * is only available after the MSI controller driver is probed so, + * explicitly configure here. + */ + if (!dev_get_msi_domain(dev)) { + /* + * The device MSI domain for OF devices is only set at the + * time of populating/creating OF device. If the device MSI + * domain is discovered later after the OF device is created + * then we need to set it explicitly before using any platform + * MSI functions. + */ + if (dev_of_node(dev)) + of_msi_configure(dev, dev_of_node(dev)); + + if (!dev_get_msi_domain(dev)) + return -EPROBE_DEFER; + } + + mbox->msi_index_to_channel = devm_kcalloc(dev, mbox->msi_count, + sizeof(*mbox->msi_index_to_channel), + GFP_KERNEL); + if (!mbox->msi_index_to_channel) + return -ENOMEM; + + for (msi_idx = 0; msi_idx < mbox->msi_count; msi_idx++) { + for (i = 0; i < mbox->channel_count; i++) { + mchan = &mbox->channels[i]; + if (mchan->msi_index == msi_idx) { + mbox->msi_index_to_channel[msi_idx] = mchan; + break; + } + } + } + + rc = platform_device_msi_init_and_alloc_irqs(dev, mbox->msi_count, + mpxy_mbox_msi_write); + if (rc) { + return dev_err_probe(dev, rc, "Failed to allocate %d MSIs\n", + mbox->msi_count); + } + + for (i = 0; i < mbox->channel_count; i++) { + mchan = &mbox->channels[i]; + if (mchan->msi_index == U32_MAX) + continue; + mchan->msi_irq = msi_get_virq(dev, mchan->msi_index); + } + } + + /* Register mailbox controller */ + rc = devm_mbox_controller_register(dev, &mbox->controller); + if (rc) { + dev_err_probe(dev, rc, "Registering SBI MPXY mailbox failed\n"); + if (mbox->msi_count) + platform_device_msi_free_irqs_all(dev); + return rc; + } + + dev_info(dev, "mailbox registered with %d channels\n", + mbox->channel_count); + return 0; +} + +static void mpxy_mbox_remove(struct platform_device *pdev) +{ + struct mpxy_mbox *mbox = platform_get_drvdata(pdev); + + if (mbox->msi_count) + platform_device_msi_free_irqs_all(mbox->dev); +} + +static const struct of_device_id mpxy_mbox_of_match[] = { + { .compatible = "riscv,sbi-mpxy-mbox" }, + {} +}; +MODULE_DEVICE_TABLE(of, mpxy_mbox_of_match); + +static struct platform_driver mpxy_mbox_driver = { + .driver = { + .name = "riscv-sbi-mpxy-mbox", + .of_match_table = mpxy_mbox_of_match, + }, + .probe = mpxy_mbox_probe, + .remove = mpxy_mbox_remove, +}; +module_platform_driver(mpxy_mbox_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Anup Patel "); +MODULE_DESCRIPTION("RISC-V SBI MPXY mailbox controller driver"); From 67c9b685c7f8f19b2f449fdd5fb6a0a0c39f429a Mon Sep 17 00:00:00 2001 From: Oleh Kuzhylnyi Date: Wed, 24 Sep 2025 21:42:47 -0700 Subject: [PATCH 2088/2711] dt-bindings: input: touchscreen: add hynitron cst816x series Add documentation for Hynitron CST816x series touchscreen bindings. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Oleh Kuzhylnyi Link: https://lore.kernel.org/r/20250921125939.249788-1-kuzhylol@gmail.com Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/hynitron,cst816x.yaml | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/hynitron,cst816x.yaml diff --git a/Documentation/devicetree/bindings/input/touchscreen/hynitron,cst816x.yaml b/Documentation/devicetree/bindings/input/touchscreen/hynitron,cst816x.yaml new file mode 100644 index 000000000000..72d4da636881 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/hynitron,cst816x.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/hynitron,cst816x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Hynitron CST816x Series Capacitive Touch controller + +maintainers: + - Oleh Kuzhylnyi + +description: | + Bindings for CST816x high performance self-capacitance touch chip series + with single point gesture and real two-point operation. + +properties: + compatible: + enum: + - hynitron,cst816s + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + linux,keycodes: + minItems: 1 + items: + - description: Slide up gesture + - description: Slide down gesture + - description: Slide left gesture + - description: Slide right gesture + - description: Long press gesture + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + touchscreen@15 { + compatible = "hynitron,cst816s"; + reg = <0x15>; + interrupt-parent = <&gpio0>; + interrupts = <4 IRQ_TYPE_EDGE_RISING>; + reset-gpios = <&gpio 17 GPIO_ACTIVE_LOW>; + linux,keycodes = , , , , + ; + }; + }; + +... From c87a819bec86f9aff695caf79d672082bb123451 Mon Sep 17 00:00:00 2001 From: Oleh Kuzhylnyi Date: Wed, 24 Sep 2025 21:43:14 -0700 Subject: [PATCH 2089/2711] Input: add driver for Hynitron CST816x series MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce support for the Hynitron CST816x series touchscreen controller used for 240×240 1.28-inch Round LCD Display Module manufactured by Waveshare Electronics. The driver is designed based on an Arduino implementation marked as under MIT License. This driver is written for a particular round display based on the CST816S controller, which is not compatiable with existing driver for Hynitron controllers. Signed-off-by: Oleh Kuzhylnyi Link: https://lore.kernel.org/r/20250921125939.249788-2-kuzhylol@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/hynitron-cst816x.c | 253 +++++++++++++++++++ 3 files changed, 266 insertions(+) create mode 100644 drivers/input/touchscreen/hynitron-cst816x.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 762d71f79abd..7d5b72ee07fa 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -475,6 +475,18 @@ config TOUCHSCREEN_HYNITRON_CSTXXX To compile this driver as a module, choose M here: the module will be called hynitron-cstxxx. +config TOUCHSCREEN_HYNITRON_CST816X + tristate "Hynitron CST816x touchscreen" + depends on I2C + help + Say Y here if you have a touchscreen using a Hynitron + CST816x series touchscreen controller. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called hynitron-cst816x. + config TOUCHSCREEN_ILI210X tristate "Ilitek ILI210X based touchscreen" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 1e7c2f324e12..ab9abd151078 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI) += goodix_berlin_spi.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX852X) += himax_hx852x.o obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o +obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CST816X) += hynitron-cst816x.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o obj-$(CONFIG_TOUCHSCREEN_IMAGIS) += imagis.o diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c new file mode 100644 index 000000000000..b64d7928e18f --- /dev/null +++ b/drivers/input/touchscreen/hynitron-cst816x.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for I2C connected Hynitron CST816x Series Touchscreen + * + * Copyright (C) 2025 Oleh Kuzhylnyi + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CST816X_RD_REG 0x01 +#define CST816X_NUM_KEYS 5 + +struct cst816x_touch { + u8 gest; + u8 active; + u16 abs_x; + u16 abs_y; +} __packed; + +struct cst816x_priv { + struct i2c_client *client; + struct gpio_desc *reset; + struct input_dev *input; + unsigned int keycode[CST816X_NUM_KEYS]; + unsigned int keycodemax; +}; + +static int cst816x_parse_keycodes(struct device *dev, struct cst816x_priv *priv) +{ + int count; + int error; + + if (device_property_present(dev, "linux,keycodes")) { + count = device_property_count_u32(dev, "linux,keycodes"); + if (count < 0) { + error = count; + dev_err(dev, "failed to count keys: %d\n", error); + return error; + } else if (count > ARRAY_SIZE(priv->keycode)) { + dev_err(dev, "too many keys defined: %d\n", count); + return -EINVAL; + } + priv->keycodemax = count; + + error = device_property_read_u32_array(dev, "linux,keycodes", + priv->keycode, + priv->keycodemax); + if (error) { + dev_err(dev, "failed to read keycodes: %d\n", error); + return error; + } + } + + return 0; +} + +static int cst816x_i2c_read_register(struct cst816x_priv *priv, u8 reg, + void *buf, size_t len) +{ + struct i2c_msg xfer[] = { + { + .addr = priv->client->addr, + .flags = 0, + .buf = ®, + .len = sizeof(reg), + }, + { + .addr = priv->client->addr, + .flags = I2C_M_RD, + .buf = buf, + .len = len, + }, + }; + int error; + int ret; + + ret = i2c_transfer(priv->client->adapter, xfer, ARRAY_SIZE(xfer)); + if (ret != ARRAY_SIZE(xfer)) { + error = ret < 0 ? ret : -EIO; + dev_err(&priv->client->dev, "i2c rx err: %d\n", error); + return error; + } + + return 0; +} + +static u8 cst816x_gest_idx(u8 gest) +{ + u8 index; + + switch (gest) { + case 0x01: /* Slide up gesture */ + case 0x02: /* Slide down gesture */ + case 0x03: /* Slide left gesture */ + case 0x04: /* Slide right gesture */ + index = gest; + break; + case 0x0c: /* Long press gesture */ + default: + index = CST816X_NUM_KEYS; + break; + } + + return index - 1; +} + +static bool cst816x_process_touch(struct cst816x_priv *priv, + struct cst816x_touch *tch) +{ + if (cst816x_i2c_read_register(priv, CST816X_RD_REG, tch, sizeof(*tch))) + return false; + + tch->abs_x = get_unaligned_be16(&tch->abs_x) & GENMASK(11, 0); + tch->abs_y = get_unaligned_be16(&tch->abs_y) & GENMASK(11, 0); + + dev_dbg(&priv->client->dev, "x: %u, y: %u, t: %u, g: 0x%x\n", + tch->abs_x, tch->abs_y, tch->active, tch->gest); + + return true; +} + +static int cst816x_register_input(struct cst816x_priv *priv) +{ + priv->input = devm_input_allocate_device(&priv->client->dev); + if (!priv->input) + return -ENOMEM; + + priv->input->name = "Hynitron CST816x Series Touchscreen"; + priv->input->phys = "input/ts"; + priv->input->id.bustype = BUS_I2C; + + input_set_drvdata(priv->input, priv); + + input_set_abs_params(priv->input, ABS_X, 0, 240, 0, 0); + input_set_abs_params(priv->input, ABS_Y, 0, 240, 0, 0); + input_set_capability(priv->input, EV_KEY, BTN_TOUCH); + + priv->input->keycode = priv->keycode; + priv->input->keycodesize = sizeof(priv->keycode[0]); + priv->input->keycodemax = priv->keycodemax; + + for (int i = 0; i < priv->keycodemax; i++) { + if (priv->keycode[i] == KEY_RESERVED) + continue; + + input_set_capability(priv->input, EV_KEY, priv->keycode[i]); + } + + return input_register_device(priv->input); +} + +static void cst816x_reset(struct cst816x_priv *priv) +{ + gpiod_set_value_cansleep(priv->reset, 1); + msleep(50); + gpiod_set_value_cansleep(priv->reset, 0); + msleep(100); +} + +static irqreturn_t cst816x_irq_cb(int irq, void *cookie) +{ + struct cst816x_priv *priv = cookie; + struct cst816x_touch tch; + + if (!cst816x_process_touch(priv, &tch)) + return IRQ_HANDLED; + + input_report_abs(priv->input, ABS_X, tch.abs_x); + input_report_abs(priv->input, ABS_Y, tch.abs_y); + + if (tch.gest) + input_report_key(priv->input, + priv->keycode[cst816x_gest_idx(tch.gest)], + tch.active); + + input_report_key(priv->input, BTN_TOUCH, tch.active); + + input_sync(priv->input); + + return IRQ_HANDLED; +} + +static int cst816x_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct cst816x_priv *priv; + int error; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->client = client; + + priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(priv->reset)) + return dev_err_probe(dev, PTR_ERR(priv->reset), + "gpio reset request failed\n"); + + if (priv->reset) + cst816x_reset(priv); + + error = cst816x_parse_keycodes(dev, priv); + if (error) + dev_warn(dev, "no gestures found in dt\n"); + + error = cst816x_register_input(priv); + if (error) + return dev_err_probe(dev, error, "input register failed\n"); + + error = devm_request_threaded_irq(dev, client->irq, + NULL, cst816x_irq_cb, IRQF_ONESHOT, + dev_driver_string(dev), priv); + if (error) + return dev_err_probe(dev, error, "irq request failed\n"); + + return 0; +} + +static const struct i2c_device_id cst816x_id[] = { + { .name = "cst816s", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cst816x_id); + +static const struct of_device_id cst816x_of_match[] = { + { .compatible = "hynitron,cst816s", }, + { } +}; +MODULE_DEVICE_TABLE(of, cst816x_of_match); + +static struct i2c_driver cst816x_driver = { + .driver = { + .name = "cst816x", + .of_match_table = cst816x_of_match, + }, + .id_table = cst816x_id, + .probe = cst816x_probe, +}; + +module_i2c_driver(cst816x_driver); + +MODULE_AUTHOR("Oleh Kuzhylnyi "); +MODULE_DESCRIPTION("Hynitron CST816x Series Touchscreen Driver"); +MODULE_LICENSE("GPL"); From 95e6b0af80525d14cb35fc664dd3ce5d5756dac1 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 9 Sep 2025 07:59:51 -0700 Subject: [PATCH 2090/2711] dt-bindings: input: pm8941-pwrkey: Document wakeup-source property The 'resin' keys (usually connected to a volume-down button) are generally not supposed to wake up the device from suspend, so explicitly document a wakeup-source property to enable this wakeup behavior. For 'pwrkey' the default stays that pressing the button does wake up the device from suspend. Signed-off-by: Luca Weiss Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250909-resin-wakeup-v1-1-46159940e02b@lucaweiss.eu Signed-off-by: Dmitry Torokhov --- .../bindings/input/qcom,pm8941-pwrkey.yaml | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml index 72006a14fd41..f978cf965a4d 100644 --- a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml +++ b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml @@ -10,9 +10,6 @@ maintainers: - Courtney Cavin - Vinod Koul -allOf: - - $ref: input.yaml# - properties: compatible: enum: @@ -36,12 +33,30 @@ properties: configured for pull up. $ref: /schemas/types.yaml#/definitions/flag + wakeup-source: + description: + Button can wake-up the system. Only applicable for 'resin', 'pwrkey' + always wakes the system by default. + linux,code: description: The input key-code associated with the power key. Use the linux event codes defined in include/dt-bindings/input/linux-event-codes.h. When property is omitted KEY_POWER is assumed. +allOf: + - $ref: input.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8941-pwrkey + - qcom,pmk8350-pwrkey + then: + properties: + wakeup-source: false + required: - compatible - interrupts From 9712fe00a7728c64be7e51f05162aafea231a929 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 9 Sep 2025 08:02:14 -0700 Subject: [PATCH 2091/2711] Input: pm8941-pwrkey - disable wakeup for resin by default 'Resin' (*Res*et *In*put) is usually connected to a volume down button on devices, which is usually not expected to wake up the device from suspend. On the other hand, pwrkey should keep wakeup on. So do not enable wakeup for resin unless the "wakeup-source" property is specified in devicetree. Note, that this does change behavior by turning off wakeup by default for 'resin' and requiring a new dt property to be added to turn it on again. But since this is not expected behavior in the first place, and most users will not expect this, I'd argue this change is acceptable. Signed-off-by: Luca Weiss Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250909-resin-wakeup-v1-2-46159940e02b@lucaweiss.eu Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pm8941-pwrkey.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c index d952c16f2458..53249d2c081f 100644 --- a/drivers/input/misc/pm8941-pwrkey.c +++ b/drivers/input/misc/pm8941-pwrkey.c @@ -60,6 +60,7 @@ struct pm8941_data { bool supports_ps_hold_poff_config; bool supports_debounce_config; bool has_pon_pbs; + bool wakeup_source_default; const char *name; const char *phys; }; @@ -245,7 +246,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops, static int pm8941_pwrkey_probe(struct platform_device *pdev) { struct pm8941_pwrkey *pwrkey; - bool pull_up; + bool pull_up, wakeup; struct device *parent; struct device_node *regmap_node; const __be32 *addr; @@ -402,8 +403,11 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev) } } + wakeup = pwrkey->data->wakeup_source_default || + of_property_read_bool(pdev->dev.of_node, "wakeup-source"); + platform_set_drvdata(pdev, pwrkey); - device_init_wakeup(&pdev->dev, 1); + device_init_wakeup(&pdev->dev, wakeup); return 0; } @@ -424,6 +428,7 @@ static const struct pm8941_data pwrkey_data = { .supports_ps_hold_poff_config = true, .supports_debounce_config = true, .has_pon_pbs = false, + .wakeup_source_default = true, }; static const struct pm8941_data resin_data = { @@ -434,6 +439,7 @@ static const struct pm8941_data resin_data = { .supports_ps_hold_poff_config = true, .supports_debounce_config = true, .has_pon_pbs = false, + .wakeup_source_default = false, }; static const struct pm8941_data pon_gen3_pwrkey_data = { @@ -443,6 +449,7 @@ static const struct pm8941_data pon_gen3_pwrkey_data = { .supports_ps_hold_poff_config = false, .supports_debounce_config = false, .has_pon_pbs = true, + .wakeup_source_default = true, }; static const struct pm8941_data pon_gen3_resin_data = { @@ -452,6 +459,7 @@ static const struct pm8941_data pon_gen3_resin_data = { .supports_ps_hold_poff_config = false, .supports_debounce_config = false, .has_pon_pbs = true, + .wakeup_source_default = false, }; static const struct of_device_id pm8941_pwr_key_id_table[] = { From a084c3c4a2674f156031eb04e785986c2744aca8 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Thu, 25 Sep 2025 11:31:23 +0800 Subject: [PATCH 2092/2711] drivers/perf: hisi: Add tt_core_deprecated for compatibility Previously tt_core is defined as config1:0-7 which may not cover all the CPUs sharing L3C on platforms with more than 8 CPUs in a L3C. In order to support such platforms extend tt_core to 16 bits, since no spare space in config1, tt_core was moved to config2:0-15. Though linux expects the users to retrieve the control encoding from sysfs first for each option, it's possible if user doesn't follow this and hardcoded tt_core in config1. So add an option tt_core_deprecated for config1:0-7 for backward compatibility. Signed-off-by: Yicong Yang Signed-off-by: Will Deacon --- Documentation/admin-guide/perf/hisi-pmu.rst | 4 +++ drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 33 +++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/Documentation/admin-guide/perf/hisi-pmu.rst b/Documentation/admin-guide/perf/hisi-pmu.rst index c4c2cbbf88cb..0017f8ddeb75 100644 --- a/Documentation/admin-guide/perf/hisi-pmu.rst +++ b/Documentation/admin-guide/perf/hisi-pmu.rst @@ -66,6 +66,10 @@ specified as a bitmap:: This will only count the operations from core/thread 0 and 1 in this cluster. +User should not use tt_core_deprecated to specify the core/thread filtering. +This option is provided for backward compatiblility and only support 8bit +which may not cover all the core/thread sharing L3C. + 2. Tracetag allow the user to chose to count only read, write or atomic operations via the tt_req parameeter in perf. The default value counts all operations. tt_req is 3bits, 3'b100 represents read operations, 3'b101 diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c index bbd81a43047d..f963e4f9e552 100644 --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c @@ -57,6 +57,11 @@ #define L3C_V2_NR_EVENTS 0xFF HISI_PMU_EVENT_ATTR_EXTRACTOR(ext, config, 17, 16); +/* + * Remain the config1:0-7 for backward compatibility if some existing users + * hardcode the config1:0-7 directly without parsing the sysfs attribute. + */ +HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_core_deprecated, config1, 7, 0); HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_req, config1, 10, 8); HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_cfg, config1, 15, 11); HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 16, 16); @@ -95,6 +100,21 @@ static bool support_ext(struct hisi_l3c_pmu *pmu) return l3c_pmu_ext->support_ext; } +/* + * tt_core was extended to cover all the CPUs sharing the L3 and was moved from + * config1:0-7 to config2:0-*. Try it first and fallback to tt_core_deprecated + * if user's still using the deprecated one. + */ +static u32 hisi_l3c_pmu_get_tt_core(struct perf_event *event) +{ + u32 core = hisi_get_tt_core(event); + + if (core) + return core; + + return hisi_get_tt_core_deprecated(event); +} + static int hisi_l3c_pmu_get_event_idx(struct perf_event *event) { struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu); @@ -259,7 +279,7 @@ static void hisi_l3c_pmu_clear_ds(struct perf_event *event) static void hisi_l3c_pmu_config_core_tracetag(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; - u32 core = hisi_get_tt_core(event); + u32 core = hisi_l3c_pmu_get_tt_core(event); if (core) { u32 val; @@ -280,7 +300,7 @@ static void hisi_l3c_pmu_config_core_tracetag(struct perf_event *event) static void hisi_l3c_pmu_clear_core_tracetag(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; - u32 core = hisi_get_tt_core(event); + u32 core = hisi_l3c_pmu_get_tt_core(event); if (core) { u32 val; @@ -300,7 +320,7 @@ static void hisi_l3c_pmu_clear_core_tracetag(struct perf_event *event) static bool hisi_l3c_pmu_have_filter(struct perf_event *event) { - return hisi_get_tt_req(event) || hisi_get_tt_core(event) || + return hisi_get_tt_req(event) || hisi_l3c_pmu_get_tt_core(event) || hisi_get_datasrc_cfg(event) || hisi_get_datasrc_skt(event); } @@ -331,6 +351,9 @@ static int hisi_l3c_pmu_check_filter(struct perf_event *event) if (ext < 0 || ext > hisi_l3c_pmu->ext_num) return -EINVAL; + if (hisi_get_tt_core(event) && hisi_get_tt_core_deprecated(event)) + return -EINVAL; + return 0; } @@ -602,10 +625,11 @@ static const struct attribute_group hisi_l3c_pmu_v1_format_group = { static struct attribute *hisi_l3c_pmu_v2_format_attr[] = { HISI_PMU_FORMAT_ATTR(event, "config:0-7"), - HISI_PMU_FORMAT_ATTR(tt_core, "config2:0-15"), + HISI_PMU_FORMAT_ATTR(tt_core_deprecated, "config1:0-7"), HISI_PMU_FORMAT_ATTR(tt_req, "config1:8-10"), HISI_PMU_FORMAT_ATTR(datasrc_cfg, "config1:11-15"), HISI_PMU_FORMAT_ATTR(datasrc_skt, "config1:16"), + HISI_PMU_FORMAT_ATTR(tt_core, "config2:0-15"), NULL }; @@ -617,6 +641,7 @@ static const struct attribute_group hisi_l3c_pmu_v2_format_group = { static struct attribute *hisi_l3c_pmu_v3_format_attr[] = { HISI_PMU_FORMAT_ATTR(event, "config:0-7"), HISI_PMU_FORMAT_ATTR(ext, "config:16-17"), + HISI_PMU_FORMAT_ATTR(tt_core_deprecated, "config1:0-7"), HISI_PMU_FORMAT_ATTR(tt_req, "config1:8-10"), HISI_PMU_FORMAT_ATTR(tt_core, "config2:0-15"), NULL From c584a1c7c8a192c13637bc51c7b63a9f15fe6474 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 25 Sep 2025 14:42:40 +0200 Subject: [PATCH 2093/2711] USB: disable rust bindings from the build for now The rust USB bindings as submitted are a good start, but they don't really seem to be correct in a number of minor places, so just disable them from the build entirely at this point in time. When they are ready to be re-enabled, this commit can be reverted. Acked-by: Daniel Almeida Signed-off-by: Greg Kroah-Hartman --- rust/bindings/bindings_helper.h | 1 - rust/helpers/helpers.c | 1 - rust/kernel/lib.rs | 2 -- samples/rust/Kconfig | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 41cd42cd286f..9b3a4ab95818 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -74,7 +74,6 @@ #include #include #include -#include #include #include #include diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 04103ab1a349..8e8277bdddca 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -48,7 +48,6 @@ #include "task.c" #include "time.c" #include "uaccess.c" -#include "usb.c" #include "vmalloc.c" #include "wait.c" #include "workqueue.c" diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 004ca70b816d..99dbb7b2812e 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -127,8 +127,6 @@ pub mod time; pub mod tracepoint; pub mod transmute; pub mod types; -#[cfg(CONFIG_USB = "y")] -pub mod usb; pub mod uaccess; pub mod workqueue; pub mod xarray; diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index 6d6e4d8c88cb..865a62a93ddc 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -85,7 +85,7 @@ config SAMPLE_RUST_DRIVER_PLATFORM config SAMPLE_RUST_DRIVER_USB tristate "USB Driver" - depends on USB = y + depends on USB = y && BROKEN help This option builds the Rust USB driver sample. From 195a1b7d8388c0ec2969a39324feb8bebf9bb907 Mon Sep 17 00:00:00 2001 From: Yang Shi Date: Thu, 18 Sep 2025 09:23:49 -0700 Subject: [PATCH 2094/2711] arm64: kprobes: call set_memory_rox() for kprobe page The kprobe page is allocated by execmem allocator with ROX permission. It needs to call set_memory_rox() to set proper permission for the direct map too. It was missed. Fixes: 10d5e97c1bf8 ("arm64: use PAGE_KERNEL_ROX directly in alloc_insn_page") Cc: Signed-off-by: Yang Shi Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/kernel/probes/kprobes.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c index 0c5d408afd95..8ab6104a4883 100644 --- a/arch/arm64/kernel/probes/kprobes.c +++ b/arch/arm64/kernel/probes/kprobes.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) "kprobes: " fmt +#include #include #include #include @@ -41,6 +42,17 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); static void __kprobes post_kprobe_handler(struct kprobe *, struct kprobe_ctlblk *, struct pt_regs *); +void *alloc_insn_page(void) +{ + void *addr; + + addr = execmem_alloc(EXECMEM_KPROBES, PAGE_SIZE); + if (!addr) + return NULL; + set_memory_rox((unsigned long)addr, 1); + return addr; +} + static void __kprobes arch_prepare_ss_slot(struct kprobe *p) { kprobe_opcode_t *addr = p->ainsn.xol_insn; From fd2f74f8f3d3c1a524637caf5bead9757fae4332 Mon Sep 17 00:00:00 2001 From: Feng Yang Date: Thu, 25 Sep 2025 10:08:22 +0800 Subject: [PATCH 2095/2711] tracing: Fix the bug where bpf_get_stackid returns -EFAULT on the ARM64 When using bpf_program__attach_kprobe_multi_opts on ARM64 to hook a BPF program that contains the bpf_get_stackid function, the BPF program fails to obtain the stack trace and returns -EFAULT. This is because ftrace_partial_regs omits the configuration of the pstate register, leaving pstate at the default value of 0. When get_perf_callchain executes, it uses user_mode(regs) to determine whether it is in kernel mode. This leads to a misjudgment that the code is in user mode, so perf_callchain_kernel is not executed and the function returns directly. As a result, trace->nr becomes 0, and finally -EFAULT is returned. Therefore, the assignment of the pstate register is added here. Fixes: b9b55c8912ce ("tracing: Add ftrace_partial_regs() for converting ftrace_regs to pt_regs") Closes: https://lore.kernel.org/bpf/20250919071902.554223-1-yangfeng59949@163.com/ Signed-off-by: Feng Yang Tested-by: Jiri Olsa Acked-by: Masami Hiramatsu (Google) Signed-off-by: Will Deacon --- arch/arm64/include/asm/ftrace.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h index bfe3ce9df197..ba7cf7fec5e9 100644 --- a/arch/arm64/include/asm/ftrace.h +++ b/arch/arm64/include/asm/ftrace.h @@ -153,6 +153,7 @@ ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs) regs->pc = afregs->pc; regs->regs[29] = afregs->fp; regs->regs[30] = afregs->lr; + regs->pstate = PSR_MODE_EL1h; return regs; } From c96992a24beca0768c1c42ad25d6a466e17ec70f Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Tue, 23 Sep 2025 16:56:51 +0530 Subject: [PATCH 2096/2711] PCI: dwc: Add support for ELBI resource mapping External Local Bus Interface (ELBI) is an optional register space for all DWC IPs containing the vendor specific registers. There is no need for the vendor glue drivers to fetch and map the ELBI region separately. Hence, optionally fetch and map the resource from DT in the DWC core. This also warrants dropping the corresponding code from glue drivers. Hence, drop the ELBI resource fetch and map logic from glue drivers and convert them to use 'dw_pci::elbi_base'. Note that the pcie-qcom-ep driver used devm_pci_remap_cfg_resource() to map the ELBI resource previously. But it was a mistake since devm_pci_remap_cfg_resource() should only be used for mapping the PCIe config space region as it maps the region as Non-Posted. As ELBI is used to hold vendor specific registers, there is no need to map the region as Non-Posted. With this conversion, the region will get mapped as normal MMIO memory. Suggested-by: Manivannan Sadhasivam Signed-off-by: Krishna Chaitanya Chundru [mani: removed elbi override, converted glue drivers and reworded description] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250923-controller-dwc-ecam-v10-1-e84390ba75fa@kernel.org --- drivers/pci/controller/dwc/pci-exynos.c | 62 ++++++++++---------- drivers/pci/controller/dwc/pcie-designware.c | 8 +++ drivers/pci/controller/dwc/pcie-designware.h | 1 + drivers/pci/controller/dwc/pcie-qcom-ep.c | 15 +---- drivers/pci/controller/dwc/pcie-qcom.c | 16 +++-- 5 files changed, 50 insertions(+), 52 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 1f0e98d07109..0bb7d4f5d784 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -53,7 +53,6 @@ struct exynos_pcie { struct dw_pcie pci; - void __iomem *elbi_base; struct clk_bulk_data *clks; struct phy *phy; struct regulator_bulk_data supplies[2]; @@ -71,73 +70,78 @@ static u32 exynos_pcie_readl(void __iomem *base, u32 reg) static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on) { + struct dw_pcie *pci = &ep->pci; u32 val; - val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC); + val = exynos_pcie_readl(pci->elbi_base, PCIE_ELBI_SLV_AWMISC); if (on) val |= PCIE_ELBI_SLV_DBI_ENABLE; else val &= ~PCIE_ELBI_SLV_DBI_ENABLE; - exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC); + exynos_pcie_writel(pci->elbi_base, val, PCIE_ELBI_SLV_AWMISC); } static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on) { + struct dw_pcie *pci = &ep->pci; u32 val; - val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC); + val = exynos_pcie_readl(pci->elbi_base, PCIE_ELBI_SLV_ARMISC); if (on) val |= PCIE_ELBI_SLV_DBI_ENABLE; else val &= ~PCIE_ELBI_SLV_DBI_ENABLE; - exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC); + exynos_pcie_writel(pci->elbi_base, val, PCIE_ELBI_SLV_ARMISC); } static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep) { + struct dw_pcie *pci = &ep->pci; u32 val; - val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET); + val = exynos_pcie_readl(pci->elbi_base, PCIE_CORE_RESET); val &= ~PCIE_CORE_RESET_ENABLE; - exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET); - exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET); - exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET); + exynos_pcie_writel(pci->elbi_base, val, PCIE_CORE_RESET); + exynos_pcie_writel(pci->elbi_base, 0, PCIE_STICKY_RESET); + exynos_pcie_writel(pci->elbi_base, 0, PCIE_NONSTICKY_RESET); } static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep) { + struct dw_pcie *pci = &ep->pci; u32 val; - val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET); + val = exynos_pcie_readl(pci->elbi_base, PCIE_CORE_RESET); val |= PCIE_CORE_RESET_ENABLE; - exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET); - exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET); - exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET); - exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET); - exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET); + exynos_pcie_writel(pci->elbi_base, val, PCIE_CORE_RESET); + exynos_pcie_writel(pci->elbi_base, 1, PCIE_STICKY_RESET); + exynos_pcie_writel(pci->elbi_base, 1, PCIE_NONSTICKY_RESET); + exynos_pcie_writel(pci->elbi_base, 1, PCIE_APP_INIT_RESET); + exynos_pcie_writel(pci->elbi_base, 0, PCIE_APP_INIT_RESET); } static int exynos_pcie_start_link(struct dw_pcie *pci) { - struct exynos_pcie *ep = to_exynos_pcie(pci); u32 val; - val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE); + val = exynos_pcie_readl(pci->elbi_base, PCIE_SW_WAKE); val &= ~PCIE_BUS_EN; - exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE); + exynos_pcie_writel(pci->elbi_base, val, PCIE_SW_WAKE); /* assert LTSSM enable */ - exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE, + exynos_pcie_writel(pci->elbi_base, PCIE_ELBI_LTSSM_ENABLE, PCIE_APP_LTSSM_ENABLE); return 0; } static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep) { - u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE); + struct dw_pcie *pci = &ep->pci; - exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE); + u32 val = exynos_pcie_readl(pci->elbi_base, PCIE_IRQ_PULSE); + + exynos_pcie_writel(pci->elbi_base, val, PCIE_IRQ_PULSE); } static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) @@ -150,12 +154,14 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep) { + struct dw_pcie *pci = &ep->pci; + u32 val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | IRQ_INTC_ASSERT | IRQ_INTD_ASSERT; - exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE); - exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_LEVEL); - exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_SPECIAL); + exynos_pcie_writel(pci->elbi_base, val, PCIE_IRQ_EN_PULSE); + exynos_pcie_writel(pci->elbi_base, 0, PCIE_IRQ_EN_LEVEL); + exynos_pcie_writel(pci->elbi_base, 0, PCIE_IRQ_EN_SPECIAL); } static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, @@ -211,8 +217,7 @@ static struct pci_ops exynos_pci_ops = { static bool exynos_pcie_link_up(struct dw_pcie *pci) { - struct exynos_pcie *ep = to_exynos_pcie(pci); - u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP); + u32 val = exynos_pcie_readl(pci->elbi_base, PCIE_ELBI_RDLH_LINKUP); return val & PCIE_ELBI_XMLH_LINKUP; } @@ -295,11 +300,6 @@ static int exynos_pcie_probe(struct platform_device *pdev) if (IS_ERR(ep->phy)) return PTR_ERR(ep->phy); - /* External Local Bus interface (ELBI) registers */ - ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi"); - if (IS_ERR(ep->elbi_base)) - return PTR_ERR(ep->elbi_base); - ret = devm_clk_bulk_get_all_enabled(dev, &ep->clks); if (ret < 0) return ret; diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 89aad5a08928..93da8a26c931 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -167,6 +167,14 @@ int dw_pcie_get_resources(struct dw_pcie *pci) } } + /* ELBI is an optional resource */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi"); + if (res) { + pci->elbi_base = devm_ioremap_resource(pci->dev, res); + if (IS_ERR(pci->elbi_base)) + return PTR_ERR(pci->elbi_base); + } + /* LLDD is supposed to manually switch the clocks and resets state */ if (dw_pcie_cap_is(pci, REQ_RES)) { ret = dw_pcie_get_clocks(pci); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 2418214730e4..9eb3c4c762dd 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -491,6 +491,7 @@ struct dw_pcie { resource_size_t dbi_phys_addr; void __iomem *dbi_base2; void __iomem *atu_base; + void __iomem *elbi_base; resource_size_t atu_phys_addr; size_t atu_size; resource_size_t parent_bus_offset; diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index aaf060bf39d4..d7a7e278f682 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -179,7 +179,6 @@ struct qcom_pcie_ep_cfg { * struct qcom_pcie_ep - Qualcomm PCIe Endpoint Controller * @pci: Designware PCIe controller struct * @parf: Qualcomm PCIe specific PARF register base - * @elbi: Designware PCIe specific ELBI register base * @mmio: MMIO register base * @perst_map: PERST regmap * @mmio_res: MMIO region resource @@ -202,7 +201,6 @@ struct qcom_pcie_ep { struct dw_pcie pci; void __iomem *parf; - void __iomem *elbi; void __iomem *mmio; struct regmap *perst_map; struct resource *mmio_res; @@ -267,10 +265,9 @@ static void qcom_pcie_ep_configure_tcsr(struct qcom_pcie_ep *pcie_ep) static bool qcom_pcie_dw_link_up(struct dw_pcie *pci) { - struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci); u32 reg; - reg = readl_relaxed(pcie_ep->elbi + ELBI_SYS_STTS); + reg = readl_relaxed(pci->elbi_base + ELBI_SYS_STTS); return reg & XMLH_LINK_UP; } @@ -294,16 +291,15 @@ static void qcom_pcie_dw_stop_link(struct dw_pcie *pci) static void qcom_pcie_dw_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size, u32 val) { - struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci); int ret; - writel(1, pcie_ep->elbi + ELBI_CS2_ENABLE); + writel(1, pci->elbi_base + ELBI_CS2_ENABLE); ret = dw_pcie_write(pci->dbi_base2 + reg, size, val); if (ret) dev_err(pci->dev, "Failed to write DBI2 register (0x%x): %d\n", reg, ret); - writel(0, pcie_ep->elbi + ELBI_CS2_ENABLE); + writel(0, pci->elbi_base + ELBI_CS2_ENABLE); } static void qcom_pcie_ep_icc_update(struct qcom_pcie_ep *pcie_ep) @@ -583,11 +579,6 @@ static int qcom_pcie_ep_get_io_resources(struct platform_device *pdev, return PTR_ERR(pci->dbi_base); pci->dbi_base2 = pci->dbi_base; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi"); - pcie_ep->elbi = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pcie_ep->elbi)) - return PTR_ERR(pcie_ep->elbi); - pcie_ep->mmio_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mmio"); if (!pcie_ep->mmio_res) { diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 15d71109a2f7..c48a20602d7f 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -276,7 +276,6 @@ struct qcom_pcie_port { struct qcom_pcie { struct dw_pcie *pci; void __iomem *parf; /* DT parf */ - void __iomem *elbi; /* DT elbi */ void __iomem *mhi; union qcom_pcie_resources res; struct icc_path *icc_mem; @@ -409,12 +408,17 @@ static void qcom_pcie_configure_dbi_atu_base(struct qcom_pcie *pcie) static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie) { + struct dw_pcie *pci = pcie->pci; u32 val; + if (!pci->elbi_base) { + dev_err(pci->dev, "ELBI is not present\n"); + return; + } /* enable link training */ - val = readl(pcie->elbi + ELBI_SYS_CTRL); + val = readl(pci->elbi_base + ELBI_SYS_CTRL); val |= ELBI_SYS_CTRL_LT_ENABLE; - writel(val, pcie->elbi + ELBI_SYS_CTRL); + writel(val, pci->elbi_base + ELBI_SYS_CTRL); } static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie) @@ -1847,12 +1851,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) goto err_pm_runtime_put; } - pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi"); - if (IS_ERR(pcie->elbi)) { - ret = PTR_ERR(pcie->elbi); - goto err_pm_runtime_put; - } - /* MHI region is optional */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mhi"); if (res) { From f6fd357f7afbeb34a633e5688a23b9d7eb49d558 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Tue, 23 Sep 2025 16:56:52 +0530 Subject: [PATCH 2097/2711] PCI: dwc: Prepare the driver for enabling ECAM mechanism using iATU 'CFG Shift Feature' In order to enable PCIe ECAM mechanism in DWC driver as per the 'CFG Shift Feature' documented in Designware databook r5.20a, sec 3.10.10.3, prepare the driver to handle the one time iATU setup and creating ECAM window. Signed-off-by: Krishna Chaitanya Chundru [mani: splitted the preparatory code into a separate commit for bisectability] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250923-controller-dwc-ecam-v10-2-e84390ba75fa@kernel.org --- drivers/pci/controller/dwc/Kconfig | 1 + .../pci/controller/dwc/pcie-designware-host.c | 116 +++++++++++++++--- drivers/pci/controller/dwc/pcie-designware.c | 2 +- drivers/pci/controller/dwc/pcie-designware.h | 5 + 4 files changed, 109 insertions(+), 15 deletions(-) diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index deafc512b079..dc0271203909 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -20,6 +20,7 @@ config PCIE_DW_HOST bool select PCIE_DW select IRQ_MSI_LIB + select PCI_HOST_COMMON config PCIE_DW_EP bool diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 952f8594b501..94e0fe11a0b0 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -413,6 +413,67 @@ static void dw_pcie_host_request_msg_tlp_res(struct dw_pcie_rp *pp) } } +static int dw_pcie_config_ecam_iatu(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct dw_pcie_ob_atu_cfg atu = {0}; + resource_size_t bus_range_max; + struct resource_entry *bus; + int ret; + + bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS); + + /* + * Root bus under the host bridge doesn't require any iATU configuration + * as DBI region will be used to access root bus config space. + * Immediate bus under Root Bus, needs type 0 iATU configuration and + * remaining buses need type 1 iATU configuration. + */ + atu.index = 0; + atu.type = PCIE_ATU_TYPE_CFG0; + atu.parent_bus_addr = pp->cfg0_base + SZ_1M; + /* 1MiB is to cover 1 (bus) * 32 (devices) * 8 (functions) */ + atu.size = SZ_1M; + atu.ctrl2 = PCIE_ATU_CFG_SHIFT_MODE_ENABLE; + ret = dw_pcie_prog_outbound_atu(pci, &atu); + if (ret) + return ret; + + bus_range_max = resource_size(bus->res); + + if (bus_range_max < 2) + return 0; + + /* Configure remaining buses in type 1 iATU configuration */ + atu.index = 1; + atu.type = PCIE_ATU_TYPE_CFG1; + atu.parent_bus_addr = pp->cfg0_base + SZ_2M; + atu.size = (SZ_1M * bus_range_max) - SZ_2M; + atu.ctrl2 = PCIE_ATU_CFG_SHIFT_MODE_ENABLE; + + return dw_pcie_prog_outbound_atu(pci, &atu); +} + +static int dw_pcie_create_ecam_window(struct dw_pcie_rp *pp, struct resource *res) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct device *dev = pci->dev; + struct resource_entry *bus; + + bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS); + if (!bus) + return -ENODEV; + + pp->cfg = pci_ecam_create(dev, res, bus->res, &pci_generic_ecam_ops); + if (IS_ERR(pp->cfg)) + return PTR_ERR(pp->cfg); + + pci->dbi_base = pp->cfg->win; + pci->dbi_phys_addr = res->start; + + return 0; +} + static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -422,10 +483,6 @@ static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp) struct resource *res; int ret; - ret = dw_pcie_get_resources(pci); - if (ret) - return ret; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); if (!res) { dev_err(dev, "Missing \"config\" reg space\n"); @@ -435,9 +492,31 @@ static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp) pp->cfg0_size = resource_size(res); pp->cfg0_base = res->start; - pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pp->va_cfg0_base)) - return PTR_ERR(pp->va_cfg0_base); + if (pp->ecam_enabled) { + ret = dw_pcie_create_ecam_window(pp, res); + if (ret) + return ret; + + pp->bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops; + pp->bridge->sysdata = pp->cfg; + pp->cfg->priv = pp; + } else { + pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(pp->va_cfg0_base)) + return PTR_ERR(pp->va_cfg0_base); + + /* Set default bus ops */ + pp->bridge->ops = &dw_pcie_ops; + pp->bridge->child_ops = &dw_child_pcie_ops; + pp->bridge->sysdata = pp; + } + + ret = dw_pcie_get_resources(pci); + if (ret) { + if (pp->cfg) + pci_ecam_free(pp->cfg); + return ret; + } /* Get the I/O range from DT */ win = resource_list_first_type(&pp->bridge->windows, IORESOURCE_IO); @@ -476,14 +555,10 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) if (ret) return ret; - /* Set default bus ops */ - bridge->ops = &dw_pcie_ops; - bridge->child_ops = &dw_child_pcie_ops; - if (pp->ops->init) { ret = pp->ops->init(pp); if (ret) - return ret; + goto err_free_ecam; } if (pci_msi_enabled()) { @@ -525,6 +600,14 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) if (ret) goto err_free_msi; + if (pp->ecam_enabled) { + ret = dw_pcie_config_ecam_iatu(pp); + if (ret) { + dev_err(dev, "Failed to configure iATU in ECAM mode\n"); + goto err_free_msi; + } + } + /* * Allocate the resource for MSG TLP before programming the iATU * outbound window in dw_pcie_setup_rc(). Since the allocation depends @@ -560,8 +643,6 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) /* Ignore errors, the link may come up later */ dw_pcie_wait_for_link(pci); - bridge->sysdata = pp; - ret = pci_host_probe(bridge); if (ret) goto err_stop_link; @@ -587,6 +668,10 @@ err_deinit_host: if (pp->ops->deinit) pp->ops->deinit(pp); +err_free_ecam: + if (pp->cfg) + pci_ecam_free(pp->cfg); + return ret; } EXPORT_SYMBOL_GPL(dw_pcie_host_init); @@ -609,6 +694,9 @@ void dw_pcie_host_deinit(struct dw_pcie_rp *pp) if (pp->ops->deinit) pp->ops->deinit(pp); + + if (pp->cfg) + pci_ecam_free(pp->cfg); } EXPORT_SYMBOL_GPL(dw_pcie_host_deinit); diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 93da8a26c931..ee8caae1edbd 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -575,7 +575,7 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, val = dw_pcie_enable_ecrc(val); dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL1, val); - val = PCIE_ATU_ENABLE; + val = PCIE_ATU_ENABLE | atu->ctrl2; if (atu->type == PCIE_ATU_TYPE_MSG) { /* The data-less messages only for now */ val |= PCIE_ATU_INHIBIT_PAYLOAD | atu->code; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 9eb3c4c762dd..779868e8fa8f 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -168,6 +169,7 @@ #define PCIE_ATU_REGION_CTRL2 0x004 #define PCIE_ATU_ENABLE BIT(31) #define PCIE_ATU_BAR_MODE_ENABLE BIT(30) +#define PCIE_ATU_CFG_SHIFT_MODE_ENABLE BIT(28) #define PCIE_ATU_INHIBIT_PAYLOAD BIT(22) #define PCIE_ATU_FUNC_NUM_MATCH_EN BIT(19) #define PCIE_ATU_LOWER_BASE 0x008 @@ -386,6 +388,7 @@ struct dw_pcie_ob_atu_cfg { u8 func_no; u8 code; u8 routing; + u32 ctrl2; u64 parent_bus_addr; u64 pci_addr; u64 size; @@ -424,6 +427,8 @@ struct dw_pcie_rp { struct resource *msg_res; bool use_linkup_irq; struct pci_eq_presets presets; + struct pci_config_window *cfg; + bool ecam_enabled; }; struct dw_pcie_ep_ops { From 4660e50cf81800f82eeecf743ad1e3e97ab72190 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Tue, 23 Sep 2025 16:56:53 +0530 Subject: [PATCH 2098/2711] PCI: qcom: Prepare for the DWC ECAM enablement To support the DWC ECAM mechanism, prepare the driver by performing below configurations: 1. Since the ELBI region will be covered by the ECAM 'config' space, override the 'elbi_base' with the address derived from 'dbi_base' and the offset from PARF_SLV_DBI_ELBI register. 2. Block the transactions from the host bridge to devices other than Root Port on the root bus to return all F's. This is required when the 'CFG Shift Feature' of iATU is enabled. Signed-off-by: Krishna Chaitanya Chundru [mani: code split, reworded subject/description and comments] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250923-controller-dwc-ecam-v10-3-e84390ba75fa@kernel.org --- drivers/pci/controller/dwc/pcie-qcom.c | 68 ++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index c48a20602d7f..e6d2a6b0c087 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -55,6 +55,7 @@ #define PARF_AXI_MSTR_WR_ADDR_HALT_V2 0x1a8 #define PARF_Q2A_FLUSH 0x1ac #define PARF_LTSSM 0x1b0 +#define PARF_SLV_DBI_ELBI 0x1b4 #define PARF_INT_ALL_STATUS 0x224 #define PARF_INT_ALL_CLEAR 0x228 #define PARF_INT_ALL_MASK 0x22c @@ -64,6 +65,16 @@ #define PARF_DBI_BASE_ADDR_V2_HI 0x354 #define PARF_SLV_ADDR_SPACE_SIZE_V2 0x358 #define PARF_SLV_ADDR_SPACE_SIZE_V2_HI 0x35c +#define PARF_BLOCK_SLV_AXI_WR_BASE 0x360 +#define PARF_BLOCK_SLV_AXI_WR_BASE_HI 0x364 +#define PARF_BLOCK_SLV_AXI_WR_LIMIT 0x368 +#define PARF_BLOCK_SLV_AXI_WR_LIMIT_HI 0x36c +#define PARF_BLOCK_SLV_AXI_RD_BASE 0x370 +#define PARF_BLOCK_SLV_AXI_RD_BASE_HI 0x374 +#define PARF_BLOCK_SLV_AXI_RD_LIMIT 0x378 +#define PARF_BLOCK_SLV_AXI_RD_LIMIT_HI 0x37c +#define PARF_ECAM_BASE 0x380 +#define PARF_ECAM_BASE_HI 0x384 #define PARF_NO_SNOOP_OVERRIDE 0x3d4 #define PARF_ATU_BASE_ADDR 0x634 #define PARF_ATU_BASE_ADDR_HI 0x638 @@ -87,6 +98,7 @@ /* PARF_SYS_CTRL register fields */ #define MAC_PHY_POWERDOWN_IN_P2_D_MUX_EN BIT(29) +#define PCIE_ECAM_BLOCKER_EN BIT(26) #define MST_WAKEUP_EN BIT(13) #define SLV_WAKEUP_EN BIT(12) #define MSTR_ACLK_CGC_DIS BIT(10) @@ -134,6 +146,9 @@ /* PARF_LTSSM register fields */ #define LTSSM_EN BIT(8) +/* PARF_SLV_DBI_ELBI */ +#define SLV_DBI_ELBI_ADDR_BASE GENMASK(11, 0) + /* PARF_INT_ALL_{STATUS/CLEAR/MASK} register fields */ #define PARF_INT_ALL_LINK_UP BIT(13) #define PARF_INT_MSI_DEV_0_7 GENMASK(30, 23) @@ -312,6 +327,47 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) qcom_perst_assert(pcie, false); } +static void qcom_pci_config_ecam(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct qcom_pcie *pcie = to_qcom_pcie(pci); + u64 addr, addr_end; + u32 val; + + writel_relaxed(lower_32_bits(pci->dbi_phys_addr), pcie->parf + PARF_ECAM_BASE); + writel_relaxed(upper_32_bits(pci->dbi_phys_addr), pcie->parf + PARF_ECAM_BASE_HI); + + /* + * The only device on the root bus is a single Root Port. If we try to + * access any devices other than Device/Function 00.0 on Bus 0, the TLP + * will go outside of the controller to the PCI bus. But with CFG Shift + * Feature (ECAM) enabled in iATU, there is no guarantee that the + * response is going to be all F's. Hence, to make sure that the + * requester gets all F's response for accesses other than the Root + * Port, configure iATU to block the transactions starting from + * function 1 of the root bus to the end of the root bus (i.e., from + * dbi_base + 4KB to dbi_base + 1MB). + */ + addr = pci->dbi_phys_addr + SZ_4K; + writel_relaxed(lower_32_bits(addr), pcie->parf + PARF_BLOCK_SLV_AXI_WR_BASE); + writel_relaxed(upper_32_bits(addr), pcie->parf + PARF_BLOCK_SLV_AXI_WR_BASE_HI); + + writel_relaxed(lower_32_bits(addr), pcie->parf + PARF_BLOCK_SLV_AXI_RD_BASE); + writel_relaxed(upper_32_bits(addr), pcie->parf + PARF_BLOCK_SLV_AXI_RD_BASE_HI); + + addr_end = pci->dbi_phys_addr + SZ_1M - 1; + + writel_relaxed(lower_32_bits(addr_end), pcie->parf + PARF_BLOCK_SLV_AXI_WR_LIMIT); + writel_relaxed(upper_32_bits(addr_end), pcie->parf + PARF_BLOCK_SLV_AXI_WR_LIMIT_HI); + + writel_relaxed(lower_32_bits(addr_end), pcie->parf + PARF_BLOCK_SLV_AXI_RD_LIMIT); + writel_relaxed(upper_32_bits(addr_end), pcie->parf + PARF_BLOCK_SLV_AXI_RD_LIMIT_HI); + + val = readl_relaxed(pcie->parf + PARF_SYS_CTRL); + val |= PCIE_ECAM_BLOCKER_EN; + writel_relaxed(val, pcie->parf + PARF_SYS_CTRL); +} + static int qcom_pcie_start_link(struct dw_pcie *pci) { struct qcom_pcie *pcie = to_qcom_pcie(pci); @@ -1284,6 +1340,7 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct qcom_pcie *pcie = to_qcom_pcie(pci); + u16 offset; int ret; qcom_ep_reset_assert(pcie); @@ -1292,6 +1349,17 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) if (ret) return ret; + if (pp->ecam_enabled) { + /* + * Override ELBI when ECAM is enabled, as when ECAM is enabled, + * ELBI moves under the 'config' space. + */ + offset = FIELD_GET(SLV_DBI_ELBI_ADDR_BASE, readl(pcie->parf + PARF_SLV_DBI_ELBI)); + pci->elbi_base = pci->dbi_base + offset; + + qcom_pci_config_ecam(pp); + } + ret = qcom_pcie_phy_power_on(pcie); if (ret) goto err_deinit; From 0da48c5b2fa731b21bc523c82d927399a1e508b0 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Tue, 23 Sep 2025 16:56:54 +0530 Subject: [PATCH 2099/2711] PCI: dwc: Support ECAM mechanism by enabling iATU 'CFG Shift Feature' Designware databook r5.20a, sec 3.10.10.3 documents the 'CFG Shift Feature' of the internal Address Translation Unit (iATU). When this feature is enabled, it shifts/maps the BDF contained in the bits [27:12] of the target address in MEM TLP to become BDF of the CFG TLP. This essentially implements the Enhanced Configuration Address Mapping (ECAM) mechanism as defined in PCIe r6.0, sec 7.2.2. Currently, the driver is not making use of this CFG shift feature, thereby creating the iATU outbound map for each config access to the devices, causing latency and wasting CPU cycles. So to avoid this, configure the controller to enable CFG shift feature by enabling the 'CFG Shift' bit of the 'iATU Control 2 Register'. As a result of enabling CFG shift (ECAM), there is no longer a need to map the DBI register space separately as the DBI region falls under the 'config' space used for ECAM (as DBI is used to access the Root Port). For enabling ECAM using CFG shift, the platform has to satisfy following requirements: 1. Size of the 'config' memory space to be used as ECAM memory should be able to accommodate the number of buses defined in the 'bus-range' property of the host bridge DT node. 2. The 'config' memory space should be 256 MiB aligned. This requirement comes from PCIe r6.0, sec 7.2.2, which says the base address of ECAM memory should be aligned to a 2^(n+20) byte address boundary. For the DWC cores, n is 8, so this results in 2^28 byte alignment requirement. It should be noted that some DWC vendor glue drivers like pcie-al may use their own ECAM mechanism. For those controllers, set 'dw_pcie_rp::native_ecam' flag and skip enabling the CFG Shift feature in the DWC core. Signed-off-by: Krishna Chaitanya Chundru [mani: code split, reworded subject/description, comment, native_ecam flag] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250923-controller-dwc-ecam-v10-4-e84390ba75fa@kernel.org --- drivers/pci/controller/dwc/pcie-al.c | 1 + .../pci/controller/dwc/pcie-designware-host.c | 32 +++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.h | 1 + 3 files changed, 34 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-al.c b/drivers/pci/controller/dwc/pcie-al.c index 643115f74092..345c281c74fe 100644 --- a/drivers/pci/controller/dwc/pcie-al.c +++ b/drivers/pci/controller/dwc/pcie-al.c @@ -352,6 +352,7 @@ static int al_pcie_probe(struct platform_device *pdev) return -ENOENT; } al_pcie->ecam_size = resource_size(ecam_res); + pci->pp.native_ecam = true; controller_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "controller"); diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 94e0fe11a0b0..20c9333bcb1c 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -8,6 +8,7 @@ * Author: Jingoo Han */ +#include #include #include #include @@ -32,6 +33,8 @@ static struct pci_ops dw_child_pcie_ops; MSI_FLAG_PCI_MSIX | \ MSI_GENERIC_FLAGS_MASK) +#define IS_256MB_ALIGNED(x) IS_ALIGNED(x, SZ_256M) + static const struct msi_parent_ops dw_pcie_msi_parent_ops = { .required_flags = DW_PCIE_MSI_FLAGS_REQUIRED, .supported_flags = DW_PCIE_MSI_FLAGS_SUPPORTED, @@ -474,6 +477,34 @@ static int dw_pcie_create_ecam_window(struct dw_pcie_rp *pp, struct resource *re return 0; } +static bool dw_pcie_ecam_enabled(struct dw_pcie_rp *pp, struct resource *config_res) +{ + struct resource *bus_range; + u64 nr_buses; + + /* Vendor glue drivers may implement their own ECAM mechanism */ + if (pp->native_ecam) + return false; + + /* + * PCIe spec r6.0, sec 7.2.2 mandates the base address used for ECAM to + * be aligned on a 2^(n+20) byte boundary, where n is the number of bits + * used for representing 'bus' in BDF. Since the DWC cores always use 8 + * bits for representing 'bus', the base address has to be aligned to + * 2^28 byte boundary, which is 256 MiB. + */ + if (!IS_256MB_ALIGNED(config_res->start)) + return false; + + bus_range = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS)->res; + if (!bus_range) + return false; + + nr_buses = resource_size(config_res) >> PCIE_ECAM_BUS_SHIFT; + + return nr_buses >= resource_size(bus_range); +} + static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -492,6 +523,7 @@ static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp) pp->cfg0_size = resource_size(res); pp->cfg0_base = res->start; + pp->ecam_enabled = dw_pcie_ecam_enabled(pp, res); if (pp->ecam_enabled) { ret = dw_pcie_create_ecam_window(pp, res); if (ret) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 779868e8fa8f..625320565360 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -429,6 +429,7 @@ struct dw_pcie_rp { struct pci_eq_presets presets; struct pci_config_window *cfg; bool ecam_enabled; + bool native_ecam; }; struct dw_pcie_ep_ops { From 200b0d25084d6e99f9f08229283b14b60a84c657 Mon Sep 17 00:00:00 2001 From: Kevin Brodsky Date: Fri, 12 Sep 2025 08:39:08 +0100 Subject: [PATCH 2100/2711] arm64: mm: Move KPTI helpers to mmu.c create_kpti_ng_temp_pgd() is currently defined (as an alias) in mmu.c without matching declaration in a header; instead cpufeature.c makes its own declaration. This is clearly not pretty, and as commit ceca927c86e6 ("arm64: mm: Fix CFI failure due to kpti_ng_pgd_alloc function signature") showed, it also makes it very easy for the prototypes to go out of sync. All this would be much simpler if kpti_install_ng_mappings() and associated functions lived in mmu.c, where they logically belong. This is what this patch does: - Move kpti_install_ng_mappings() and associated functions from cpufeature.c to mmu.c, add a declaration to - Remove create_kpti_ng_temp_pgd() and just call __create_pgd_mapping_locked() directly instead - Mark all these functions __init - Move __initdata after kpti_ng_temp_alloc (as suggested by checkpatch) Reviewed-by: Ryan Roberts Reviewed-by: Ard Biesheuvel Reviewed-by: Anshuman Khandual Signed-off-by: Kevin Brodsky Reviewed-by: Yeoreum Yun [will: Fix conflicts with init_idmap_kpti_bbml2_flag()] Signed-off-by: Will Deacon --- arch/arm64/include/asm/mmu.h | 7 ++- arch/arm64/kernel/cpufeature.c | 98 ---------------------------------- arch/arm64/mm/mmu.c | 98 ++++++++++++++++++++++++++++++---- 3 files changed, 94 insertions(+), 109 deletions(-) diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index ff6fd0bbd7d2..78a4dbf75e60 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -79,7 +79,6 @@ extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, extern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot); extern void mark_linear_text_alias_ro(void); extern int split_kernel_leaf_mapping(unsigned long start, unsigned long end); -extern void init_idmap_kpti_bbml2_flag(void); extern void linear_map_maybe_split_to_ptes(void); /* @@ -107,5 +106,11 @@ static inline bool kaslr_requires_kpti(void) return true; } +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +void kpti_install_ng_mappings(void); +#else +static inline void kpti_install_ng_mappings(void) {} +#endif + #endif /* !__ASSEMBLY__ */ #endif diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 10362b296f2d..ecb83ab0700e 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1941,104 +1941,6 @@ static bool has_pmuv3(const struct arm64_cpu_capabilities *entry, int scope) } #endif -#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 -#define KPTI_NG_TEMP_VA (-(1UL << PMD_SHIFT)) - -extern -void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt, - phys_addr_t size, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(enum pgtable_type), int flags); - -static phys_addr_t __initdata kpti_ng_temp_alloc; - -static phys_addr_t __init kpti_ng_pgd_alloc(enum pgtable_type type) -{ - kpti_ng_temp_alloc -= PAGE_SIZE; - return kpti_ng_temp_alloc; -} - -static int __init __kpti_install_ng_mappings(void *__unused) -{ - typedef void (kpti_remap_fn)(int, int, phys_addr_t, unsigned long); - extern kpti_remap_fn idmap_kpti_install_ng_mappings; - kpti_remap_fn *remap_fn; - - int cpu = smp_processor_id(); - int levels = CONFIG_PGTABLE_LEVELS; - int order = order_base_2(levels); - u64 kpti_ng_temp_pgd_pa = 0; - pgd_t *kpti_ng_temp_pgd; - u64 alloc = 0; - - if (levels == 5 && !pgtable_l5_enabled()) - levels = 4; - else if (levels == 4 && !pgtable_l4_enabled()) - levels = 3; - - remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings); - - if (!cpu) { - alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order); - kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE); - kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd); - - // - // Create a minimal page table hierarchy that permits us to map - // the swapper page tables temporarily as we traverse them. - // - // The physical pages are laid out as follows: - // - // +--------+-/-------+-/------ +-/------ +-\\\--------+ - // : PTE[] : | PMD[] : | PUD[] : | P4D[] : ||| PGD[] : - // +--------+-\-------+-\------ +-\------ +-///--------+ - // ^ - // The first page is mapped into this hierarchy at a PMD_SHIFT - // aligned virtual address, so that we can manipulate the PTE - // level entries while the mapping is active. The first entry - // covers the PTE[] page itself, the remaining entries are free - // to be used as a ad-hoc fixmap. - // - create_kpti_ng_temp_pgd(kpti_ng_temp_pgd, __pa(alloc), - KPTI_NG_TEMP_VA, PAGE_SIZE, PAGE_KERNEL, - kpti_ng_pgd_alloc, 0); - } - - cpu_install_idmap(); - remap_fn(cpu, num_online_cpus(), kpti_ng_temp_pgd_pa, KPTI_NG_TEMP_VA); - cpu_uninstall_idmap(); - - if (!cpu) { - free_pages(alloc, order); - arm64_use_ng_mappings = true; - } - - return 0; -} - -static void __init kpti_install_ng_mappings(void) -{ - /* Check whether KPTI is going to be used */ - if (!arm64_kernel_unmapped_at_el0()) - return; - - /* - * We don't need to rewrite the page-tables if either we've done - * it already or we have KASLR enabled and therefore have not - * created any global mappings at all. - */ - if (arm64_use_ng_mappings) - return; - - init_idmap_kpti_bbml2_flag(); - stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask); -} - -#else -static inline void kpti_install_ng_mappings(void) -{ -} -#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ - static void cpu_enable_kpti(struct arm64_cpu_capabilities const *cap) { if (__this_cpu_read(this_cpu_vector) == vectors) { diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 3a444a5fe469..38a8a775a1db 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -470,14 +470,6 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, mutex_unlock(&fixmap_lock); } -#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 -extern __alias(__create_pgd_mapping_locked) -void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt, - phys_addr_t size, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(enum pgtable_type), - int flags); -#endif - #define INVALID_PHYS_ADDR (-1ULL) static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm, gfp_t gfp, @@ -823,7 +815,7 @@ static bool linear_map_requires_bbml2 __initdata; u32 idmap_kpti_bbml2_flag; -void __init init_idmap_kpti_bbml2_flag(void) +static void __init init_idmap_kpti_bbml2_flag(void) { WRITE_ONCE(idmap_kpti_bbml2_flag, 1); /* Must be visible to other CPUs before stop_machine() is called. */ @@ -1135,7 +1127,93 @@ static void __init declare_vma(struct vm_struct *vma, } #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 -static pgprot_t kernel_exec_prot(void) +#define KPTI_NG_TEMP_VA (-(1UL << PMD_SHIFT)) + +static phys_addr_t kpti_ng_temp_alloc __initdata; + +static phys_addr_t __init kpti_ng_pgd_alloc(enum pgtable_type type) +{ + kpti_ng_temp_alloc -= PAGE_SIZE; + return kpti_ng_temp_alloc; +} + +static int __init __kpti_install_ng_mappings(void *__unused) +{ + typedef void (kpti_remap_fn)(int, int, phys_addr_t, unsigned long); + extern kpti_remap_fn idmap_kpti_install_ng_mappings; + kpti_remap_fn *remap_fn; + + int cpu = smp_processor_id(); + int levels = CONFIG_PGTABLE_LEVELS; + int order = order_base_2(levels); + u64 kpti_ng_temp_pgd_pa = 0; + pgd_t *kpti_ng_temp_pgd; + u64 alloc = 0; + + if (levels == 5 && !pgtable_l5_enabled()) + levels = 4; + else if (levels == 4 && !pgtable_l4_enabled()) + levels = 3; + + remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings); + + if (!cpu) { + alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order); + kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE); + kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd); + + // + // Create a minimal page table hierarchy that permits us to map + // the swapper page tables temporarily as we traverse them. + // + // The physical pages are laid out as follows: + // + // +--------+-/-------+-/------ +-/------ +-\\\--------+ + // : PTE[] : | PMD[] : | PUD[] : | P4D[] : ||| PGD[] : + // +--------+-\-------+-\------ +-\------ +-///--------+ + // ^ + // The first page is mapped into this hierarchy at a PMD_SHIFT + // aligned virtual address, so that we can manipulate the PTE + // level entries while the mapping is active. The first entry + // covers the PTE[] page itself, the remaining entries are free + // to be used as a ad-hoc fixmap. + // + __create_pgd_mapping_locked(kpti_ng_temp_pgd, __pa(alloc), + KPTI_NG_TEMP_VA, PAGE_SIZE, PAGE_KERNEL, + kpti_ng_pgd_alloc, 0); + } + + cpu_install_idmap(); + remap_fn(cpu, num_online_cpus(), kpti_ng_temp_pgd_pa, KPTI_NG_TEMP_VA); + cpu_uninstall_idmap(); + + if (!cpu) { + free_pages(alloc, order); + arm64_use_ng_mappings = true; + } + + return 0; +} + +void __init kpti_install_ng_mappings(void) +{ + /* Check whether KPTI is going to be used */ + if (!arm64_kernel_unmapped_at_el0()) + return; + + /* + * We don't need to rewrite the page-tables if either we've done + * it already or we have KASLR enabled and therefore have not + * created any global mappings at all. + */ + if (arm64_use_ng_mappings) + return; + + init_idmap_kpti_bbml2_flag(); + stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask); +} + +static pgprot_t __init kernel_exec_prot(void) { return rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC; } From 0a8f173d9dad13930d5888505dc4c4fd6a1d4262 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 9 Sep 2025 18:26:24 +0200 Subject: [PATCH 2101/2711] PCI: rcar-host: Drop PMSR spinlock The pmsr_lock spinlock used to be necessary to synchronize access to the PMSR register, because that access could have been triggered from either config space access in rcar_pcie_config_access() or an exception handler rcar_pcie_aarch32_abort_handler(). The rcar_pcie_aarch32_abort_handler() case is no longer applicable since commit 6e36203bc14c ("PCI: rcar: Use PCI_SET_ERROR_RESPONSE after read which triggered an exception"), which performs more accurate, controlled invocation of the exception, and a fixup. This leaves rcar_pcie_config_access() as the only call site from which rcar_pcie_wakeup() is called. The rcar_pcie_config_access() can only be called from the controller struct pci_ops .read and .write callbacks, and those are serialized in drivers/pci/access.c using raw spinlock 'pci_lock' . It should be noted that CONFIG_PCI_LOCKLESS_CONFIG is never set on this platform. Since the 'pci_lock' is a raw spinlock , and the 'pmsr_lock' is not a raw spinlock, this constellation triggers 'BUG: Invalid wait context' with CONFIG_PROVE_RAW_LOCK_NESTING=y . Remove the pmsr_lock to fix the locking. Fixes: a115b1bd3af0 ("PCI: rcar: Add L1 link state fix into data abort hook") Reported-by: Duy Nguyen Reported-by: Thuan Nguyen Signed-off-by: Marek Vasut Signed-off-by: Manivannan Sadhasivam Reviewed-by: Geert Uytterhoeven Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250909162707.13927-1-marek.vasut+renesas@mailbox.org --- drivers/pci/controller/pcie-rcar-host.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c index 4780e0109e58..625a00f3b223 100644 --- a/drivers/pci/controller/pcie-rcar-host.c +++ b/drivers/pci/controller/pcie-rcar-host.c @@ -52,20 +52,13 @@ struct rcar_pcie_host { int (*phy_init_fn)(struct rcar_pcie_host *host); }; -static DEFINE_SPINLOCK(pmsr_lock); - static int rcar_pcie_wakeup(struct device *pcie_dev, void __iomem *pcie_base) { - unsigned long flags; u32 pmsr, val; int ret = 0; - spin_lock_irqsave(&pmsr_lock, flags); - - if (!pcie_base || pm_runtime_suspended(pcie_dev)) { - ret = -EINVAL; - goto unlock_exit; - } + if (!pcie_base || pm_runtime_suspended(pcie_dev)) + return -EINVAL; pmsr = readl(pcie_base + PMSR); @@ -87,8 +80,6 @@ static int rcar_pcie_wakeup(struct device *pcie_dev, void __iomem *pcie_base) writel(L1FAEG | PMEL1RX, pcie_base + PMSR); } -unlock_exit: - spin_unlock_irqrestore(&pmsr_lock, flags); return ret; } From db155b7c7c85b5f14edec21e164001a168581ffb Mon Sep 17 00:00:00 2001 From: Sergey Bashirov Date: Mon, 25 Aug 2025 16:11:02 +0300 Subject: [PATCH 2102/2711] NFSD: Disallow layoutget during grace period When the server is recovering from a reboot and is in a grace period, any operation that may result in deletion or reallocation of block extents should not be allowed. See RFC 8881, section 18.43.3. If multiple clients write data to the same file, rebooting the server during writing may result in file corruption. In the worst case, the exported XFS may also become corrupted. Observed this behavior while testing pNFS block volume setup. Co-developed-by: Konstantin Evtushenko Signed-off-by: Konstantin Evtushenko Signed-off-by: Sergey Bashirov Signed-off-by: Chuck Lever --- fs/nfsd/nfs4proc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index d7c58aa64f06..2dc8910f8f72 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2435,6 +2435,7 @@ static __be32 nfsd4_layoutget(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) { + struct net *net = SVC_NET(rqstp); struct nfsd4_layoutget *lgp = &u->layoutget; struct svc_fh *current_fh = &cstate->current_fh; const struct nfsd4_layout_ops *ops; @@ -2486,6 +2487,10 @@ nfsd4_layoutget(struct svc_rqst *rqstp, if (lgp->lg_seg.length == 0) goto out; + nfserr = nfserr_grace; + if (locks_in_grace(net)) + goto out; + nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lgp->lg_sid, true, lgp->lg_layout_type, &ls); if (nfserr) { From e40b984b6c4ce3f80814f39f86f87b2a48f2e662 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 2 Sep 2025 15:15:46 +0300 Subject: [PATCH 2103/2711] usb: vhci-hcd: Prevent suspending virtually attached devices The VHCI platform driver aims to forbid entering system suspend when at least one of the virtual USB ports are bound to an active USB/IP connection. However, in some cases, the detection logic doesn't work reliably, i.e. when all devices attached to the virtual root hub have been already suspended, leading to a broken suspend state, with unrecoverable resume. Ensure the virtually attached devices do not enter suspend by setting the syscore PM flag. Note this is currently limited to the client side only, since the server side doesn't implement system suspend prevention. Fixes: 04679b3489e0 ("Staging: USB/IP: add client driver") Signed-off-by: Cristian Ciocaltea Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250902-vhci-hcd-suspend-fix-v3-1-864e4e833559@collabora.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vhci_hcd.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index e70fba9f55d6..0d6c10a8490c 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -765,6 +765,17 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag ctrlreq->wValue, vdev->rhport); vdev->udev = usb_get_dev(urb->dev); + /* + * NOTE: A similar operation has been done via + * USB_REQ_GET_DESCRIPTOR handler below, which is + * supposed to always precede USB_REQ_SET_ADDRESS. + * + * It's not entirely clear if operating on a different + * usb_device instance here is a real possibility, + * otherwise this call and vdev->udev assignment above + * should be dropped. + */ + dev_pm_syscore_device(&vdev->udev->dev, true); usb_put_dev(old); spin_lock(&vdev->ud.lock); @@ -785,6 +796,17 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag "Not yet?:Get_Descriptor to device 0 (get max pipe size)\n"); vdev->udev = usb_get_dev(urb->dev); + /* + * Set syscore PM flag for the virtually attached + * devices to ensure they will not enter suspend on + * the client side. + * + * Note this doesn't have any impact on the physical + * devices attached to the host system on the server + * side, hence there is no need to undo the operation + * on disconnect. + */ + dev_pm_syscore_device(&vdev->udev->dev, true); usb_put_dev(old); goto out; From 0020839be034cf1c57ebdf8af8c9e4f697055db6 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 23 Sep 2025 10:40:12 -0700 Subject: [PATCH 2104/2711] nvdimm: Introduce guard() for nvdimm_bus_lock Converting nvdimm_bus_lock/unlock to guard() to clean up usage of gotos for error handling and avoid future mistakes of missed unlock on error paths. Link: https://lore.kernel.org/linux-cxl/20250917163623.00004a3c@huawei.com/ Suggested-by: Jonathan Cameron Signed-off-by: Dave Jiang Acked-by: Dan Williams Signed-off-by: Ira Weiny --- drivers/nvdimm/badrange.c | 3 +- drivers/nvdimm/btt_devs.c | 24 +++---- drivers/nvdimm/bus.c | 6 +- drivers/nvdimm/claim.c | 7 +- drivers/nvdimm/core.c | 17 +++-- drivers/nvdimm/dax_devs.c | 12 ++-- drivers/nvdimm/dimm.c | 5 +- drivers/nvdimm/dimm_devs.c | 48 +++++-------- drivers/nvdimm/namespace_devs.c | 119 ++++++++++++++++---------------- drivers/nvdimm/nd.h | 3 + drivers/nvdimm/pfn_devs.c | 61 +++++++--------- drivers/nvdimm/region.c | 14 ++-- drivers/nvdimm/region_devs.c | 118 ++++++++++++++----------------- drivers/nvdimm/security.c | 10 +-- 14 files changed, 195 insertions(+), 252 deletions(-) diff --git a/drivers/nvdimm/badrange.c b/drivers/nvdimm/badrange.c index ee478ccde7c6..36c626db459a 100644 --- a/drivers/nvdimm/badrange.c +++ b/drivers/nvdimm/badrange.c @@ -278,8 +278,7 @@ void nvdimm_badblocks_populate(struct nd_region *nd_region, } nvdimm_bus = walk_to_nvdimm_bus(&nd_region->dev); - nvdimm_bus_lock(&nvdimm_bus->dev); + guard(nvdimm_bus)(&nvdimm_bus->dev); badblocks_populate(&nvdimm_bus->badrange, bb, range); - nvdimm_bus_unlock(&nvdimm_bus->dev); } EXPORT_SYMBOL_GPL(nvdimm_badblocks_populate); diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c index 497fd434a6a1..b3279b86bbfd 100644 --- a/drivers/nvdimm/btt_devs.c +++ b/drivers/nvdimm/btt_devs.c @@ -50,14 +50,12 @@ static ssize_t sector_size_store(struct device *dev, struct nd_btt *nd_btt = to_nd_btt(dev); ssize_t rc; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); rc = nd_size_select_store(dev, buf, &nd_btt->lbasize, btt_lbasize_supported); dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, buf[len - 1] == '\n' ? "" : "\n"); - nvdimm_bus_unlock(dev); - device_unlock(dev); return rc ? rc : len; } @@ -93,13 +91,10 @@ static ssize_t namespace_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_btt *nd_btt = to_nd_btt(dev); - ssize_t rc; - nvdimm_bus_lock(dev); - rc = sprintf(buf, "%s\n", nd_btt->ndns + guard(nvdimm_bus)(dev); + return sprintf(buf, "%s\n", nd_btt->ndns ? dev_name(&nd_btt->ndns->dev) : ""); - nvdimm_bus_unlock(dev); - return rc; } static ssize_t namespace_store(struct device *dev, @@ -108,13 +103,11 @@ static ssize_t namespace_store(struct device *dev, struct nd_btt *nd_btt = to_nd_btt(dev); ssize_t rc; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); rc = nd_namespace_store(dev, &nd_btt->ndns, buf, len); dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, buf[len - 1] == '\n' ? "" : "\n"); - nvdimm_bus_unlock(dev); - device_unlock(dev); return rc; } @@ -351,9 +344,8 @@ int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns) return -ENODEV; } - nvdimm_bus_lock(&ndns->dev); - btt_dev = __nd_btt_create(nd_region, 0, NULL, ndns); - nvdimm_bus_unlock(&ndns->dev); + scoped_guard(nvdimm_bus, &ndns->dev) + btt_dev = __nd_btt_create(nd_region, 0, NULL, ndns); if (!btt_dev) return -ENOMEM; btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL); diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 0ccf4a9e523a..e57d5677d44b 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -64,17 +64,15 @@ static struct module *to_bus_provider(struct device *dev) static void nvdimm_bus_probe_start(struct nvdimm_bus *nvdimm_bus) { - nvdimm_bus_lock(&nvdimm_bus->dev); + guard(nvdimm_bus)(&nvdimm_bus->dev); nvdimm_bus->probe_active++; - nvdimm_bus_unlock(&nvdimm_bus->dev); } static void nvdimm_bus_probe_end(struct nvdimm_bus *nvdimm_bus) { - nvdimm_bus_lock(&nvdimm_bus->dev); + guard(nvdimm_bus)(&nvdimm_bus->dev); if (--nvdimm_bus->probe_active == 0) wake_up(&nvdimm_bus->wait); - nvdimm_bus_unlock(&nvdimm_bus->dev); } static int nvdimm_bus_probe(struct device *dev) diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index 51614651d2e7..309cd2cddb0e 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -34,11 +34,10 @@ void nd_detach_ndns(struct device *dev, if (!ndns) return; - get_device(&ndns->dev); - nvdimm_bus_lock(&ndns->dev); + + struct device *ndev __free(put_device) = get_device(&ndns->dev); + guard(nvdimm_bus)(ndev); __nd_detach_ndns(dev, _ndns); - nvdimm_bus_unlock(&ndns->dev); - put_device(&ndns->dev); } bool __nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach, diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index eaa796629c27..5ba204113fe1 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c @@ -141,9 +141,8 @@ static void nvdimm_map_put(void *data) struct nvdimm_map *nvdimm_map = data; struct nvdimm_bus *nvdimm_bus = nvdimm_map->nvdimm_bus; - nvdimm_bus_lock(&nvdimm_bus->dev); + guard(nvdimm_bus)(&nvdimm_bus->dev); kref_put(&nvdimm_map->kref, nvdimm_map_release); - nvdimm_bus_unlock(&nvdimm_bus->dev); } /** @@ -158,13 +157,13 @@ void *devm_nvdimm_memremap(struct device *dev, resource_size_t offset, { struct nvdimm_map *nvdimm_map; - nvdimm_bus_lock(dev); - nvdimm_map = find_nvdimm_map(dev, offset); - if (!nvdimm_map) - nvdimm_map = alloc_nvdimm_map(dev, offset, size, flags); - else - kref_get(&nvdimm_map->kref); - nvdimm_bus_unlock(dev); + scoped_guard(nvdimm_bus, dev) { + nvdimm_map = find_nvdimm_map(dev, offset); + if (!nvdimm_map) + nvdimm_map = alloc_nvdimm_map(dev, offset, size, flags); + else + kref_get(&nvdimm_map->kref); + } if (!nvdimm_map) return NULL; diff --git a/drivers/nvdimm/dax_devs.c b/drivers/nvdimm/dax_devs.c index 37b743acbb7b..ba4c409ede65 100644 --- a/drivers/nvdimm/dax_devs.c +++ b/drivers/nvdimm/dax_devs.c @@ -104,12 +104,12 @@ int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns) return -ENODEV; } - nvdimm_bus_lock(&ndns->dev); - nd_dax = nd_dax_alloc(nd_region); - dax_dev = nd_dax_devinit(nd_dax, ndns); - nvdimm_bus_unlock(&ndns->dev); - if (!dax_dev) - return -ENOMEM; + scoped_guard(nvdimm_bus, &ndns->dev) { + nd_dax = nd_dax_alloc(nd_region); + dax_dev = nd_dax_devinit(nd_dax, ndns); + if (!dax_dev) + return -ENOMEM; + } pfn_sb = devm_kmalloc(dev, sizeof(*pfn_sb), GFP_KERNEL); nd_pfn = &nd_dax->nd_pfn; nd_pfn->pfn_sb = pfn_sb; diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 91d9163ee303..2f6c26cc6a3e 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c @@ -117,9 +117,8 @@ static void nvdimm_remove(struct device *dev) { struct nvdimm_drvdata *ndd = dev_get_drvdata(dev); - nvdimm_bus_lock(dev); - dev_set_drvdata(dev, NULL); - nvdimm_bus_unlock(dev); + scoped_guard(nvdimm_bus, dev) + dev_set_drvdata(dev, NULL); put_ndd(ndd); } diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 21498d461fde..e1349ef5f8fd 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -226,10 +226,10 @@ void nvdimm_drvdata_release(struct kref *kref) struct resource *res, *_r; dev_dbg(dev, "trace\n"); - nvdimm_bus_lock(dev); - for_each_dpa_resource_safe(ndd, res, _r) - nvdimm_free_dpa(ndd, res); - nvdimm_bus_unlock(dev); + scoped_guard(nvdimm_bus, dev) { + for_each_dpa_resource_safe(ndd, res, _r) + nvdimm_free_dpa(ndd, res); + } kvfree(ndd->data); kfree(ndd); @@ -319,23 +319,20 @@ static DEVICE_ATTR_RO(state); static ssize_t __available_slots_show(struct nvdimm_drvdata *ndd, char *buf) { struct device *dev; - ssize_t rc; u32 nfree; if (!ndd) return -ENXIO; dev = ndd->dev; - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); nfree = nd_label_nfree(ndd); if (nfree - 1 > nfree) { dev_WARN_ONCE(dev, 1, "we ate our last label?\n"); nfree = 0; } else nfree--; - rc = sprintf(buf, "%d\n", nfree); - nvdimm_bus_unlock(dev); - return rc; + return sprintf(buf, "%d\n", nfree); } static ssize_t available_slots_show(struct device *dev, @@ -388,21 +385,15 @@ static ssize_t security_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - ssize_t rc; - /* * Require all userspace triggered security management to be * done while probing is idle and the DIMM is not in active use * in any region. */ - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); wait_nvdimm_bus_probe_idle(dev); - rc = nvdimm_security_store(dev, buf, len); - nvdimm_bus_unlock(dev); - device_unlock(dev); - - return rc; + return nvdimm_security_store(dev, buf, len); } static DEVICE_ATTR_RW(security); @@ -454,9 +445,8 @@ static ssize_t result_show(struct device *dev, struct device_attribute *attr, ch if (!nvdimm->fw_ops) return -EOPNOTSUPP; - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); result = nvdimm->fw_ops->activate_result(nvdimm); - nvdimm_bus_unlock(dev); switch (result) { case NVDIMM_FWA_RESULT_NONE: @@ -483,9 +473,8 @@ static ssize_t activate_show(struct device *dev, struct device_attribute *attr, if (!nvdimm->fw_ops) return -EOPNOTSUPP; - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); state = nvdimm->fw_ops->activate_state(nvdimm); - nvdimm_bus_unlock(dev); switch (state) { case NVDIMM_FWA_IDLE: @@ -516,9 +505,8 @@ static ssize_t activate_store(struct device *dev, struct device_attribute *attr, else return -EINVAL; - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); rc = nvdimm->fw_ops->arm(nvdimm, arg); - nvdimm_bus_unlock(dev); if (rc < 0) return rc; @@ -545,9 +533,8 @@ static umode_t nvdimm_firmware_visible(struct kobject *kobj, struct attribute *a if (!nvdimm->fw_ops) return 0; - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); cap = nd_desc->fw_ops->capability(nd_desc); - nvdimm_bus_unlock(dev); if (cap < NVDIMM_FWA_CAP_QUIESCE) return 0; @@ -641,11 +628,10 @@ void nvdimm_delete(struct nvdimm *nvdimm) bool dev_put = false; /* We are shutting down. Make state frozen artificially. */ - nvdimm_bus_lock(dev); - set_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags); - if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags)) - dev_put = true; - nvdimm_bus_unlock(dev); + scoped_guard(nvdimm_bus, dev) { + set_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags); + dev_put = test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags); + } cancel_delayed_work_sync(&nvdimm->dwork); if (dev_put) put_device(dev); diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 53bce1fa376e..a5edcacfe46d 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -264,15 +264,13 @@ static ssize_t alt_name_store(struct device *dev, struct nd_region *nd_region = to_nd_region(dev->parent); ssize_t rc; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); wait_nvdimm_bus_probe_idle(dev); rc = __alt_name_store(dev, buf, len); if (rc >= 0) rc = nd_namespace_label_update(nd_region, dev); dev_dbg(dev, "%s(%zd)\n", rc < 0 ? "fail " : "", rc); - nvdimm_bus_unlock(dev); - device_unlock(dev); return rc < 0 ? rc : len; } @@ -849,8 +847,8 @@ static ssize_t size_store(struct device *dev, if (rc) return rc; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); wait_nvdimm_bus_probe_idle(dev); rc = __size_store(dev, val); if (rc >= 0) @@ -866,9 +864,6 @@ static ssize_t size_store(struct device *dev, dev_dbg(dev, "%llx %s (%d)\n", val, rc < 0 ? "fail" : "success", rc); - nvdimm_bus_unlock(dev); - device_unlock(dev); - return rc < 0 ? rc : len; } @@ -891,13 +886,8 @@ resource_size_t __nvdimm_namespace_capacity(struct nd_namespace_common *ndns) resource_size_t nvdimm_namespace_capacity(struct nd_namespace_common *ndns) { - resource_size_t size; - - nvdimm_bus_lock(&ndns->dev); - size = __nvdimm_namespace_capacity(ndns); - nvdimm_bus_unlock(&ndns->dev); - - return size; + guard(nvdimm_bus)(&ndns->dev); + return __nvdimm_namespace_capacity(ndns); } EXPORT_SYMBOL(nvdimm_namespace_capacity); @@ -1044,8 +1034,8 @@ static ssize_t uuid_store(struct device *dev, } else return -ENXIO; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); wait_nvdimm_bus_probe_idle(dev); if (to_ndns(dev)->claim) rc = -EBUSY; @@ -1059,8 +1049,6 @@ static ssize_t uuid_store(struct device *dev, kfree(uuid); dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, buf[len - 1] == '\n' ? "" : "\n"); - nvdimm_bus_unlock(dev); - device_unlock(dev); return rc < 0 ? rc : len; } @@ -1119,20 +1107,30 @@ static ssize_t sector_size_store(struct device *dev, } else return -ENXIO; - device_lock(dev); - nvdimm_bus_lock(dev); - if (to_ndns(dev)->claim) - rc = -EBUSY; - if (rc >= 0) - rc = nd_size_select_store(dev, buf, lbasize, supported); - if (rc >= 0) - rc = nd_namespace_label_update(nd_region, dev); - dev_dbg(dev, "result: %zd %s: %s%s", rc, rc < 0 ? "tried" : "wrote", - buf, buf[len - 1] == '\n' ? "" : "\n"); - nvdimm_bus_unlock(dev); - device_unlock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); + if (to_ndns(dev)->claim) { + dev_dbg(dev, "namespace %s already claimed\n", dev_name(dev)); + return -EBUSY; + } - return rc ? rc : len; + rc = nd_size_select_store(dev, buf, lbasize, supported); + if (rc < 0) { + dev_dbg(dev, "size select fail: %zd tried: %s%s", rc, + buf, buf[len - 1] == '\n' ? "" : "\n"); + return rc; + } + + rc = nd_namespace_label_update(nd_region, dev); + if (rc < 0) { + dev_dbg(dev, "label update fail: %zd tried: %s%s", + rc, buf, buf[len - 1] == '\n' ? "" : "\n"); + return rc; + } + + dev_dbg(dev, "wrote: %s%s", buf, buf[len - 1] == '\n' ? "" : "\n"); + + return len; } static DEVICE_ATTR_RW(sector_size); @@ -1145,7 +1143,7 @@ static ssize_t dpa_extents_show(struct device *dev, int count = 0, i; u32 flags = 0; - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); if (is_namespace_pmem(dev)) { struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev); @@ -1154,7 +1152,7 @@ static ssize_t dpa_extents_show(struct device *dev, } if (!uuid) - goto out; + return sprintf(buf, "%d\n", count); nd_label_gen_id(&label_id, uuid, flags); for (i = 0; i < nd_region->ndr_mappings; i++) { @@ -1166,8 +1164,6 @@ static ssize_t dpa_extents_show(struct device *dev, if (strcmp(res->name, label_id.id) == 0) count++; } - out: - nvdimm_bus_unlock(dev); return sprintf(buf, "%d\n", count); } @@ -1279,15 +1275,13 @@ static ssize_t holder_class_store(struct device *dev, struct nd_region *nd_region = to_nd_region(dev->parent); int rc; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); wait_nvdimm_bus_probe_idle(dev); rc = __holder_class_store(dev, buf); if (rc >= 0) rc = nd_namespace_label_update(nd_region, dev); dev_dbg(dev, "%s(%d)\n", rc < 0 ? "fail " : "", rc); - nvdimm_bus_unlock(dev); - device_unlock(dev); return rc < 0 ? rc : len; } @@ -2152,31 +2146,38 @@ out: nd_region); } +static int create_relevant_namespaces(struct nd_region *nd_region, int *type, + struct device ***devs) +{ + int rc; + + guard(nvdimm_bus)(&nd_region->dev); + rc = init_active_labels(nd_region); + if (rc) + return rc; + + *type = nd_region_to_nstype(nd_region); + switch (*type) { + case ND_DEVICE_NAMESPACE_IO: + *devs = create_namespace_io(nd_region); + break; + case ND_DEVICE_NAMESPACE_PMEM: + *devs = create_namespaces(nd_region); + break; + } + + return 0; +} + int nd_region_register_namespaces(struct nd_region *nd_region, int *err) { struct device **devs = NULL; int i, rc = 0, type; *err = 0; - nvdimm_bus_lock(&nd_region->dev); - rc = init_active_labels(nd_region); - if (rc) { - nvdimm_bus_unlock(&nd_region->dev); + rc = create_relevant_namespaces(nd_region, &type, &devs); + if (rc) return rc; - } - - type = nd_region_to_nstype(nd_region); - switch (type) { - case ND_DEVICE_NAMESPACE_IO: - devs = create_namespace_io(nd_region); - break; - case ND_DEVICE_NAMESPACE_PMEM: - devs = create_namespaces(nd_region); - break; - default: - break; - } - nvdimm_bus_unlock(&nd_region->dev); if (!devs) return -ENODEV; diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index cc5c8f3f81e8..b199eea3260e 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -632,6 +632,9 @@ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region, u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region); void nvdimm_bus_lock(struct device *dev); void nvdimm_bus_unlock(struct device *dev); +DEFINE_GUARD(nvdimm_bus, struct device *, + if (_T) nvdimm_bus_lock(_T), if (_T) nvdimm_bus_unlock(_T)); + bool is_nvdimm_bus_locked(struct device *dev); void nvdimm_check_and_set_ro(struct gendisk *disk); void nvdimm_drvdata_release(struct kref *kref); diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index 8f3e816e805d..42b172fc5576 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -56,30 +56,26 @@ static ssize_t mode_store(struct device *dev, { struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); ssize_t rc = 0; + size_t n = len - 1; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); if (dev->driver) - rc = -EBUSY; - else { - size_t n = len - 1; + return -EBUSY; - if (strncmp(buf, "pmem\n", n) == 0 - || strncmp(buf, "pmem", n) == 0) { - nd_pfn->mode = PFN_MODE_PMEM; - } else if (strncmp(buf, "ram\n", n) == 0 - || strncmp(buf, "ram", n) == 0) - nd_pfn->mode = PFN_MODE_RAM; - else if (strncmp(buf, "none\n", n) == 0 - || strncmp(buf, "none", n) == 0) - nd_pfn->mode = PFN_MODE_NONE; - else - rc = -EINVAL; - } + if (strncmp(buf, "pmem\n", n) == 0 + || strncmp(buf, "pmem", n) == 0) { + nd_pfn->mode = PFN_MODE_PMEM; + } else if (strncmp(buf, "ram\n", n) == 0 + || strncmp(buf, "ram", n) == 0) + nd_pfn->mode = PFN_MODE_RAM; + else if (strncmp(buf, "none\n", n) == 0 + || strncmp(buf, "none", n) == 0) + nd_pfn->mode = PFN_MODE_NONE; + else + rc = -EINVAL; dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, buf[len - 1] == '\n' ? "" : "\n"); - nvdimm_bus_unlock(dev); - device_unlock(dev); return rc ? rc : len; } @@ -125,14 +121,12 @@ static ssize_t align_store(struct device *dev, unsigned long aligns[MAX_NVDIMM_ALIGN] = { [0] = 0, }; ssize_t rc; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); rc = nd_size_select_store(dev, buf, &nd_pfn->align, nd_pfn_supported_alignments(aligns)); dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, buf[len - 1] == '\n' ? "" : "\n"); - nvdimm_bus_unlock(dev); - device_unlock(dev); return rc ? rc : len; } @@ -168,13 +162,10 @@ static ssize_t namespace_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); - ssize_t rc; - nvdimm_bus_lock(dev); - rc = sprintf(buf, "%s\n", nd_pfn->ndns + guard(nvdimm_bus)(dev); + return sprintf(buf, "%s\n", nd_pfn->ndns ? dev_name(&nd_pfn->ndns->dev) : ""); - nvdimm_bus_unlock(dev); - return rc; } static ssize_t namespace_store(struct device *dev, @@ -183,13 +174,11 @@ static ssize_t namespace_store(struct device *dev, struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); ssize_t rc; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); rc = nd_namespace_store(dev, &nd_pfn->ndns, buf, len); dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, buf[len - 1] == '\n' ? "" : "\n"); - nvdimm_bus_unlock(dev); - device_unlock(dev); return rc; } @@ -639,10 +628,10 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns) return -ENODEV; } - nvdimm_bus_lock(&ndns->dev); - nd_pfn = nd_pfn_alloc(nd_region); - pfn_dev = nd_pfn_devinit(nd_pfn, ndns); - nvdimm_bus_unlock(&ndns->dev); + scoped_guard(nvdimm_bus, &ndns->dev) { + nd_pfn = nd_pfn_alloc(nd_region); + pfn_dev = nd_pfn_devinit(nd_pfn, ndns); + } if (!pfn_dev) return -ENOMEM; pfn_sb = devm_kmalloc(dev, sizeof(*pfn_sb), GFP_KERNEL); diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c index 68a26002f8b9..cd9b52040d7b 100644 --- a/drivers/nvdimm/region.c +++ b/drivers/nvdimm/region.c @@ -87,13 +87,13 @@ static void nd_region_remove(struct device *dev) device_for_each_child(dev, NULL, child_unregister); /* flush attribute readers and disable */ - nvdimm_bus_lock(dev); - nd_region->ns_seed = NULL; - nd_region->btt_seed = NULL; - nd_region->pfn_seed = NULL; - nd_region->dax_seed = NULL; - dev_set_drvdata(dev, NULL); - nvdimm_bus_unlock(dev); + scoped_guard(nvdimm_bus, dev) { + nd_region->ns_seed = NULL; + nd_region->btt_seed = NULL; + nd_region->pfn_seed = NULL; + nd_region->dax_seed = NULL; + dev_set_drvdata(dev, NULL); + } /* * Note, this assumes device_lock() context to not race diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index de1ee5ebc851..a5ceaf5db595 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -102,31 +102,44 @@ out: return 0; } -int nd_region_activate(struct nd_region *nd_region) +static int get_flush_data(struct nd_region *nd_region, size_t *size, int *num_flush) { - int i, j, rc, num_flush = 0; - struct nd_region_data *ndrd; - struct device *dev = &nd_region->dev; size_t flush_data_size = sizeof(void *); + int _num_flush = 0; + int i; - nvdimm_bus_lock(&nd_region->dev); + guard(nvdimm_bus)(&nd_region->dev); for (i = 0; i < nd_region->ndr_mappings; i++) { struct nd_mapping *nd_mapping = &nd_region->mapping[i]; struct nvdimm *nvdimm = nd_mapping->nvdimm; - if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { - nvdimm_bus_unlock(&nd_region->dev); + if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) return -EBUSY; - } /* at least one null hint slot per-dimm for the "no-hint" case */ flush_data_size += sizeof(void *); - num_flush = min_not_zero(num_flush, nvdimm->num_flush); + _num_flush = min_not_zero(_num_flush, nvdimm->num_flush); if (!nvdimm->num_flush) continue; flush_data_size += nvdimm->num_flush * sizeof(void *); } - nvdimm_bus_unlock(&nd_region->dev); + + *size = flush_data_size; + *num_flush = _num_flush; + + return 0; +} + +int nd_region_activate(struct nd_region *nd_region) +{ + int i, j, rc, num_flush; + struct nd_region_data *ndrd; + struct device *dev = &nd_region->dev; + size_t flush_data_size; + + rc = get_flush_data(nd_region, &flush_data_size, &num_flush); + if (rc) + return rc; rc = nd_region_invalidate_memregion(nd_region); if (rc) @@ -327,8 +340,8 @@ static ssize_t set_cookie_show(struct device *dev, * the v1.1 namespace label cookie definition. To read all this * data we need to wait for probing to settle. */ - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); wait_nvdimm_bus_probe_idle(dev); if (nd_region->ndr_mappings) { struct nd_mapping *nd_mapping = &nd_region->mapping[0]; @@ -343,8 +356,6 @@ static ssize_t set_cookie_show(struct device *dev, nsindex)); } } - nvdimm_bus_unlock(dev); - device_unlock(dev); if (rc) return rc; @@ -393,7 +404,6 @@ static ssize_t available_size_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_region *nd_region = to_nd_region(dev); - unsigned long long available = 0; /* * Flush in-flight updates and grab a snapshot of the available @@ -401,14 +411,11 @@ static ssize_t available_size_show(struct device *dev, * memory nvdimm_bus_lock() is dropped, but that's userspace's * problem to not race itself. */ - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); wait_nvdimm_bus_probe_idle(dev); - available = nd_region_available_dpa(nd_region); - nvdimm_bus_unlock(dev); - device_unlock(dev); - return sprintf(buf, "%llu\n", available); + return sprintf(buf, "%llu\n", nd_region_available_dpa(nd_region)); } static DEVICE_ATTR_RO(available_size); @@ -416,16 +423,12 @@ static ssize_t max_available_extent_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_region *nd_region = to_nd_region(dev); - unsigned long long available = 0; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); wait_nvdimm_bus_probe_idle(dev); - available = nd_region_allocatable_dpa(nd_region); - nvdimm_bus_unlock(dev); - device_unlock(dev); - return sprintf(buf, "%llu\n", available); + return sprintf(buf, "%llu\n", nd_region_allocatable_dpa(nd_region)); } static DEVICE_ATTR_RO(max_available_extent); @@ -433,16 +436,12 @@ static ssize_t init_namespaces_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_region_data *ndrd = dev_get_drvdata(dev); - ssize_t rc; - nvdimm_bus_lock(dev); - if (ndrd) - rc = sprintf(buf, "%d/%d\n", ndrd->ns_active, ndrd->ns_count); - else - rc = -ENXIO; - nvdimm_bus_unlock(dev); + guard(nvdimm_bus)(dev); + if (!ndrd) + return -ENXIO; - return rc; + return sprintf(buf, "%d/%d\n", ndrd->ns_active, ndrd->ns_count); } static DEVICE_ATTR_RO(init_namespaces); @@ -450,15 +449,12 @@ static ssize_t namespace_seed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_region *nd_region = to_nd_region(dev); - ssize_t rc; - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); if (nd_region->ns_seed) - rc = sprintf(buf, "%s\n", dev_name(nd_region->ns_seed)); - else - rc = sprintf(buf, "\n"); - nvdimm_bus_unlock(dev); - return rc; + return sprintf(buf, "%s\n", dev_name(nd_region->ns_seed)); + + return sprintf(buf, "\n"); } static DEVICE_ATTR_RO(namespace_seed); @@ -466,16 +462,12 @@ static ssize_t btt_seed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_region *nd_region = to_nd_region(dev); - ssize_t rc; - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); if (nd_region->btt_seed) - rc = sprintf(buf, "%s\n", dev_name(nd_region->btt_seed)); - else - rc = sprintf(buf, "\n"); - nvdimm_bus_unlock(dev); + return sprintf(buf, "%s\n", dev_name(nd_region->btt_seed)); - return rc; + return sprintf(buf, "\n"); } static DEVICE_ATTR_RO(btt_seed); @@ -483,16 +475,12 @@ static ssize_t pfn_seed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_region *nd_region = to_nd_region(dev); - ssize_t rc; - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); if (nd_region->pfn_seed) - rc = sprintf(buf, "%s\n", dev_name(nd_region->pfn_seed)); - else - rc = sprintf(buf, "\n"); - nvdimm_bus_unlock(dev); + return sprintf(buf, "%s\n", dev_name(nd_region->pfn_seed)); - return rc; + return sprintf(buf, "\n"); } static DEVICE_ATTR_RO(pfn_seed); @@ -500,16 +488,12 @@ static ssize_t dax_seed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_region *nd_region = to_nd_region(dev); - ssize_t rc; - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); if (nd_region->dax_seed) - rc = sprintf(buf, "%s\n", dev_name(nd_region->dax_seed)); - else - rc = sprintf(buf, "\n"); - nvdimm_bus_unlock(dev); + return sprintf(buf, "%s\n", dev_name(nd_region->dax_seed)); - return rc; + return sprintf(buf, "\n"); } static DEVICE_ATTR_RO(dax_seed); @@ -581,9 +565,8 @@ static ssize_t align_store(struct device *dev, * times ensure it does not change for the duration of the * allocation. */ - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); nd_region->align = val; - nvdimm_bus_unlock(dev); return len; } @@ -890,7 +873,7 @@ void nd_mapping_free_labels(struct nd_mapping *nd_mapping) */ void nd_region_advance_seeds(struct nd_region *nd_region, struct device *dev) { - nvdimm_bus_lock(dev); + guard(nvdimm_bus)(dev); if (nd_region->ns_seed == dev) { nd_region_create_ns_seed(nd_region); } else if (is_nd_btt(dev)) { @@ -915,7 +898,6 @@ void nd_region_advance_seeds(struct nd_region *nd_region, struct device *dev) if (nd_region->ns_seed == &nd_dax->nd_pfn.ndns->dev) nd_region_create_ns_seed(nd_region); } - nvdimm_bus_unlock(dev); } /** diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index a03e3c45f297..4adce8c38870 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c @@ -219,12 +219,9 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) int nvdimm_security_unlock(struct device *dev) { struct nvdimm *nvdimm = to_nvdimm(dev); - int rc; - nvdimm_bus_lock(dev); - rc = __nvdimm_security_unlock(nvdimm); - nvdimm_bus_unlock(dev); - return rc; + guard(nvdimm_bus)(dev); + return __nvdimm_security_unlock(nvdimm); } static int check_security_state(struct nvdimm *nvdimm) @@ -490,9 +487,8 @@ void nvdimm_security_overwrite_query(struct work_struct *work) struct nvdimm *nvdimm = container_of(work, typeof(*nvdimm), dwork.work); - nvdimm_bus_lock(&nvdimm->dev); + guard(nvdimm_bus)(&nvdimm->dev); __nvdimm_security_overwrite_query(nvdimm); - nvdimm_bus_unlock(&nvdimm->dev); } #define OPS \ From 88506435d9d4148e31341a2be9492004df9f7611 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 23 Sep 2025 10:40:13 -0700 Subject: [PATCH 2105/2711] nvdimm: Clean up __nd_ioctl() and remove gotos Utilize scoped based resource management to clean up the code and and remove gotos for the __nd_ioctl() function. Change allocation of 'buf' to use kvzalloc() in order to use vmalloc() memory when needed and also zero out the allocated memory. Signed-off-by: Dave Jiang Reviewed-by: Dan Williams Signed-off-by: Ira Weiny --- drivers/nvdimm/bus.c | 65 +++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index e57d5677d44b..ad3a0493f474 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -5,7 +5,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include -#include +#include #include #include #include @@ -1029,14 +1029,12 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, unsigned int cmd = _IOC_NR(ioctl_cmd); struct device *dev = &nvdimm_bus->dev; void __user *p = (void __user *) arg; - char *out_env = NULL, *in_env = NULL; const char *cmd_name, *dimm_name; u32 in_len = 0, out_len = 0; unsigned int func = cmd; unsigned long cmd_mask; struct nd_cmd_pkg pkg; int rc, i, cmd_rc; - void *buf = NULL; u64 buf_len = 0; if (nvdimm) { @@ -1095,7 +1093,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, } /* process an input envelope */ - in_env = kzalloc(ND_CMD_MAX_ENVELOPE, GFP_KERNEL); + char *in_env __free(kfree) = kzalloc(ND_CMD_MAX_ENVELOPE, GFP_KERNEL); if (!in_env) return -ENOMEM; for (i = 0; i < desc->in_num; i++) { @@ -1105,17 +1103,14 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, if (in_size == UINT_MAX) { dev_err(dev, "%s:%s unknown input size cmd: %s field: %d\n", __func__, dimm_name, cmd_name, i); - rc = -ENXIO; - goto out; + return -ENXIO; } if (in_len < ND_CMD_MAX_ENVELOPE) copy = min_t(u32, ND_CMD_MAX_ENVELOPE - in_len, in_size); else copy = 0; - if (copy && copy_from_user(&in_env[in_len], p + in_len, copy)) { - rc = -EFAULT; - goto out; - } + if (copy && copy_from_user(&in_env[in_len], p + in_len, copy)) + return -EFAULT; in_len += in_size; } @@ -1127,11 +1122,9 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, } /* process an output envelope */ - out_env = kzalloc(ND_CMD_MAX_ENVELOPE, GFP_KERNEL); - if (!out_env) { - rc = -ENOMEM; - goto out; - } + char *out_env __free(kfree) = kzalloc(ND_CMD_MAX_ENVELOPE, GFP_KERNEL); + if (!out_env) + return -ENOMEM; for (i = 0; i < desc->out_num; i++) { u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, @@ -1141,8 +1134,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, if (out_size == UINT_MAX) { dev_dbg(dev, "%s unknown output size cmd: %s field: %d\n", dimm_name, cmd_name, i); - rc = -EFAULT; - goto out; + return -EFAULT; } if (out_len < ND_CMD_MAX_ENVELOPE) copy = min_t(u32, ND_CMD_MAX_ENVELOPE - out_len, out_size); @@ -1150,8 +1142,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, copy = 0; if (copy && copy_from_user(&out_env[out_len], p + in_len + out_len, copy)) { - rc = -EFAULT; - goto out; + return -EFAULT; } out_len += out_size; } @@ -1160,30 +1151,25 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, if (buf_len > ND_IOCTL_MAX_BUFLEN) { dev_dbg(dev, "%s cmd: %s buf_len: %llu > %d\n", dimm_name, cmd_name, buf_len, ND_IOCTL_MAX_BUFLEN); - rc = -EINVAL; - goto out; + return -EINVAL; } - buf = vmalloc(buf_len); - if (!buf) { - rc = -ENOMEM; - goto out; - } + void *buf __free(kvfree) = kvzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; - if (copy_from_user(buf, p, buf_len)) { - rc = -EFAULT; - goto out; - } + if (copy_from_user(buf, p, buf_len)) + return -EFAULT; - device_lock(dev); - nvdimm_bus_lock(dev); + guard(device)(dev); + guard(nvdimm_bus)(dev); rc = nd_cmd_clear_to_send(nvdimm_bus, nvdimm, func, buf); if (rc) - goto out_unlock; + return rc; rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len, &cmd_rc); if (rc < 0) - goto out_unlock; + return rc; if (!nvdimm && cmd == ND_CMD_CLEAR_ERROR && cmd_rc >= 0) { struct nd_cmd_clear_error *clear_err = buf; @@ -1193,16 +1179,9 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, } if (copy_to_user(p, buf, buf_len)) - rc = -EFAULT; + return -EFAULT; -out_unlock: - nvdimm_bus_unlock(dev); - device_unlock(dev); -out: - kfree(in_env); - kfree(out_env); - vfree(buf); - return rc; + return 0; } enum nd_ioctl_mode { From a9e6aa994917ee602798bbb03180a194b37865bb Mon Sep 17 00:00:00 2001 From: Guangshuo Li Date: Thu, 25 Sep 2025 14:44:48 +0800 Subject: [PATCH 2106/2711] nvdimm: ndtest: Return -ENOMEM if devm_kcalloc() fails in ndtest_probe() devm_kcalloc() may fail. ndtest_probe() allocates three DMA address arrays (dcr_dma, label_dma, dimm_dma) and later unconditionally uses them in ndtest_nvdimm_init(), which can lead to a NULL pointer dereference under low-memory conditions. Check all three allocations and return -ENOMEM if any allocation fails, jumping to the common error path. Do not emit an extra error message since the allocator already warns on allocation failure. Fixes: 9399ab61ad82 ("ndtest: Add dimms to the two buses") Cc: stable@vger.kernel.org Signed-off-by: Guangshuo Li Reviewed-by: Alison Schofield Reviewed-by: Ira Weiny Reviewed-by: Dave Jiang Signed-off-by: Ira Weiny --- tools/testing/nvdimm/test/ndtest.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/testing/nvdimm/test/ndtest.c b/tools/testing/nvdimm/test/ndtest.c index 68a064ce598c..8e3b6be53839 100644 --- a/tools/testing/nvdimm/test/ndtest.c +++ b/tools/testing/nvdimm/test/ndtest.c @@ -850,11 +850,22 @@ static int ndtest_probe(struct platform_device *pdev) p->dcr_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, sizeof(dma_addr_t), GFP_KERNEL); + if (!p->dcr_dma) { + rc = -ENOMEM; + goto err; + } p->label_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, sizeof(dma_addr_t), GFP_KERNEL); + if (!p->label_dma) { + rc = -ENOMEM; + goto err; + } p->dimm_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, sizeof(dma_addr_t), GFP_KERNEL); - + if (!p->dimm_dma) { + rc = -ENOMEM; + goto err; + } rc = ndtest_nvdimm_init(p); if (rc) goto err; From b0b255d6b86dd1f2618a1402d6cbdcec1be0c589 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Thu, 25 Sep 2025 17:31:33 +0200 Subject: [PATCH 2107/2711] dt-bindings: touchscreen: convert eeti bindings to json schema Convert EETI touchscreen controller device tree binding to json-schema. Signed-off-by: Dario Binacchi Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250925153144.4082786-1-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/eeti,exc3000.yaml | 16 ++++++++-- .../bindings/input/touchscreen/eeti.txt | 30 ------------------- 2 files changed, 14 insertions(+), 32 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/eeti.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml b/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml index d19b07d4cfd4..930c70104b3f 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml @@ -16,12 +16,14 @@ properties: - const: eeti,exc80h60 - const: eeti,exc80h84 - const: eeti,egalax_ts # Do NOT use for new binding + - const: eeti,exc3000-i2c + deprecated: true - items: - enum: - eeti,exc81w32 - const: eeti,exc80h84 reg: - enum: [0x4, 0x2a] + enum: [0x4, 0xa, 0x2a] interrupts: maxItems: 1 reset-gpios: @@ -30,6 +32,12 @@ properties: maxItems: 1 vdd-supply: description: Power supply regulator for the chip + attn-gpios: + deprecated: true + maxItems: 1 + description: Phandle to a GPIO to check whether interrupt is still + latched. This is necessary for platforms that lack + support for level-triggered IRQs. touchscreen-size-x: true touchscreen-size-y: true touchscreen-inverted-x: true @@ -51,7 +59,9 @@ allOf: compatible: not: contains: - const: eeti,egalax_ts + enum: + - eeti,egalax_ts + - eeti,exc3000-i2c then: properties: reg: @@ -59,6 +69,8 @@ allOf: wakeup-gpios: false + attn-gpios: false + required: - touchscreen-size-x - touchscreen-size-y diff --git a/Documentation/devicetree/bindings/input/touchscreen/eeti.txt b/Documentation/devicetree/bindings/input/touchscreen/eeti.txt deleted file mode 100644 index 32b3712c916e..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/eeti.txt +++ /dev/null @@ -1,30 +0,0 @@ -Bindings for EETI touchscreen controller - -Required properties: -- compatible: should be "eeti,exc3000-i2c" -- reg: I2C address of the chip. Should be set to <0xa> -- interrupts: interrupt to which the chip is connected - -Optional properties: -- attn-gpios: A handle to a GPIO to check whether interrupt is still - latched. This is necessary for platforms that lack - support for level-triggered IRQs. - -The following optional properties described in touchscreen.txt are -also supported: - -- touchscreen-inverted-x -- touchscreen-inverted-y -- touchscreen-swapped-x-y - -Example: - -i2c-master { - touchscreen@a { - compatible = "eeti,exc3000-i2c"; - reg = <0xa>; - interrupt-parent = <&gpio>; - interrupts = <123 IRQ_TYPE_EDGE_RISING>; - attn-gpios = <&gpio 123 GPIO_ACTIVE_HIGH>; - }; -}; From 6b4896e404c7053cf09a6f58fd09684262fab6dd Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Thu, 25 Sep 2025 17:31:34 +0200 Subject: [PATCH 2108/2711] dt-bindings: arm: bcm: raspberrypi,bcm2835-firmware: Add touchscreen child node Convert Raspberry Pi firmware 7" touchscreen controller device tree binding to json-schema. Signed-off-by: Dario Binacchi Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250925153144.4082786-2-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- .../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 28 +++++++++++++++++++ .../touchscreen/raspberrypi,firmware-ts.txt | 26 ----------------- 2 files changed, 28 insertions(+), 26 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/raspberrypi,firmware-ts.txt diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml index 1f84407a73e4..8349c0a854d9 100644 --- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml @@ -103,6 +103,28 @@ properties: - compatible - "#pwm-cells" + touchscreen: + type: object + $ref: /schemas/input/touchscreen/touchscreen.yaml# + additionalProperties: false + + properties: + compatible: + const: raspberrypi,firmware-ts + + firmware: + deprecated: true + description: Phandle to RPi's firmware device node. + + touchscreen-size-x: true + touchscreen-size-y: true + touchscreen-inverted-x: true + touchscreen-inverted-y: true + touchscreen-swapped-x-y: true + + required: + - compatible + required: - compatible - mboxes @@ -135,5 +157,11 @@ examples: compatible = "raspberrypi,firmware-poe-pwm"; #pwm-cells = <2>; }; + + ts: touchscreen { + compatible = "raspberrypi,firmware-ts"; + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; + }; }; ... diff --git a/Documentation/devicetree/bindings/input/touchscreen/raspberrypi,firmware-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/raspberrypi,firmware-ts.txt deleted file mode 100644 index 2a1af240ccc3..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/raspberrypi,firmware-ts.txt +++ /dev/null @@ -1,26 +0,0 @@ -Raspberry Pi firmware based 7" touchscreen -===================================== - -Required properties: - - compatible: "raspberrypi,firmware-ts" - -Optional properties: - - firmware: Reference to RPi's firmware device node - - touchscreen-size-x: See touchscreen.txt - - touchscreen-size-y: See touchscreen.txt - - touchscreen-inverted-x: See touchscreen.txt - - touchscreen-inverted-y: See touchscreen.txt - - touchscreen-swapped-x-y: See touchscreen.txt - -Example: - -firmware: firmware-rpi { - compatible = "raspberrypi,bcm2835-firmware"; - mboxes = <&mailbox>; - - ts: touchscreen { - compatible = "raspberrypi,firmware-ts"; - touchscreen-size-x = <800>; - touchscreen-size-y = <480>; - }; -}; From 2728e71ad67810fea8346fb800c647b66a25162d Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Thu, 25 Sep 2025 17:31:35 +0200 Subject: [PATCH 2109/2711] dt-bindings: touchscreen: remove touchscreen.txt With commit 1d6204e2f51f ("dt-bindings: touchscreen: Add touchscreen schema") touchscreen.txt is no longer needed, and since no other file refers to it, it can be safely removed. Signed-off-by: Dario Binacchi Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250925153144.4082786-3-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/touchscreen.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt deleted file mode 100644 index e1adb902d503..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt +++ /dev/null @@ -1 +0,0 @@ -See touchscreen.yaml From 54e184f0f5f34b0cd18623117150b52444ab6433 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:04 +0530 Subject: [PATCH 2110/2711] dt-bindings: clock: Add RPMI clock service message proxy bindings Add device tree bindings for the RPMI clock service group based message proxy implemented by the SBI implementation (machine mode firmware or hypervisor). The RPMI clock service group is defined by the RISC-V platform management interface (RPMI) specification. Reviewed-by: Conor Dooley Signed-off-by: Anup Patel Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20250818040920.272664-9-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- .../bindings/clock/riscv,rpmi-mpxy-clock.yaml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/riscv,rpmi-mpxy-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/riscv,rpmi-mpxy-clock.yaml b/Documentation/devicetree/bindings/clock/riscv,rpmi-mpxy-clock.yaml new file mode 100644 index 000000000000..76f2a1b3d30d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/riscv,rpmi-mpxy-clock.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/riscv,rpmi-mpxy-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V RPMI clock service group based message proxy + +maintainers: + - Anup Patel + +description: | + The RISC-V Platform Management Interface (RPMI) [1] defines a + messaging protocol which is modular and extensible. The supervisor + software can send/receive RPMI messages via SBI MPXY extension [2] + or some dedicated supervisor-mode RPMI transport. + + The RPMI specification [1] defines clock service group for accessing + system clocks managed by a platform microcontroller. The SBI implementation + (machine mode firmware or hypervisor) can implement an SBI MPXY channel + to allow RPMI clock service group access to the supervisor software. + + =========================================== + References + =========================================== + + [1] RISC-V Platform Management Interface (RPMI) v1.0 (or higher) + https://github.com/riscv-non-isa/riscv-rpmi/releases + + [2] RISC-V Supervisor Binary Interface (SBI) v3.0 (or higher) + https://github.com/riscv-non-isa/riscv-sbi-doc/releases + +properties: + compatible: + description: + Intended for use by the SBI implementation. + const: riscv,rpmi-mpxy-clock + + mboxes: + maxItems: 1 + description: + Mailbox channel of the underlying RPMI transport. + + riscv,sbi-mpxy-channel-id: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The SBI MPXY channel id to be used for providing RPMI access to + the supervisor software. + +required: + - compatible + - mboxes + - riscv,sbi-mpxy-channel-id + +additionalProperties: false + +examples: + - | + clock-service { + compatible = "riscv,rpmi-mpxy-clock"; + mboxes = <&rpmi_shmem_mbox 0x8>; + riscv,sbi-mpxy-channel-id = <0x1000>; + }; +... From b385830290b417c7708e2db7c0e34a0b3e7297bf Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:05 +0530 Subject: [PATCH 2111/2711] dt-bindings: clock: Add RPMI clock service controller bindings Add device tree bindings for the RPMI clock service group based controller for the supervisor software. The RPMI clock service group is defined by the RISC-V platform management interface (RPMI) specification. Reviewed-by: Conor Dooley Reviewed-by: Stephen Boyd Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-10-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- .../bindings/clock/riscv,rpmi-clock.yaml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/riscv,rpmi-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/riscv,rpmi-clock.yaml b/Documentation/devicetree/bindings/clock/riscv,rpmi-clock.yaml new file mode 100644 index 000000000000..5d62bf8215c8 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/riscv,rpmi-clock.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/riscv,rpmi-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V RPMI clock service group based clock controller + +maintainers: + - Anup Patel + +description: | + The RISC-V Platform Management Interface (RPMI) [1] defines a + messaging protocol which is modular and extensible. The supervisor + software can send/receive RPMI messages via SBI MPXY extension [2] + or some dedicated supervisor-mode RPMI transport. + + The RPMI specification [1] defines clock service group for accessing + system clocks managed by a platform microcontroller. The supervisor + software can access RPMI clock service group via SBI MPXY channel or + some dedicated supervisor-mode RPMI transport. + + =========================================== + References + =========================================== + + [1] RISC-V Platform Management Interface (RPMI) v1.0 (or higher) + https://github.com/riscv-non-isa/riscv-rpmi/releases + + [2] RISC-V Supervisor Binary Interface (SBI) v3.0 (or higher) + https://github.com/riscv-non-isa/riscv-sbi-doc/releases + +properties: + compatible: + description: + Intended for use by the supervisor software. + const: riscv,rpmi-clock + + mboxes: + maxItems: 1 + description: + Mailbox channel of the underlying RPMI transport or SBI message proxy channel. + + "#clock-cells": + const: 1 + description: + Platform specific CLOCK_ID as defined by the RISC-V Platform Management + Interface (RPMI) specification. + +required: + - compatible + - mboxes + - "#clock-cells" + +additionalProperties: false + +examples: + - | + clock-controller { + compatible = "riscv,rpmi-clock"; + mboxes = <&mpxy_mbox 0x1000 0x0>; + #clock-cells = <1>; + }; +... From 5ba9f520f41a33c99fd5d1eb81b5650ed3517b88 Mon Sep 17 00:00:00 2001 From: Rahul Pathak Date: Mon, 18 Aug 2025 09:39:06 +0530 Subject: [PATCH 2112/2711] clk: Add clock driver for the RISC-V RPMI clock service group The RPMI specification defines a clock service group which can be accessed via SBI MPXY extension or dedicated S-mode RPMI transport. Add mailbox client based clock driver for the RISC-V RPMI clock service group. Reviewed-by: Stephen Boyd Reviewed-by: Andy Shevchenko Co-developed-by: Anup Patel Signed-off-by: Anup Patel Signed-off-by: Rahul Pathak Link: https://lore.kernel.org/r/20250818040920.272664-11-apatel@ventanamicro.com [pjw@kernel.org: converted rpmi_clkrate_u64 macro to a function; replaced bare constant with a macro] Signed-off-by: Paul Walmsley --- drivers/clk/Kconfig | 8 + drivers/clk/Makefile | 1 + drivers/clk/clk-rpmi.c | 620 +++++++++++++++++++++ include/linux/mailbox/riscv-rpmi-message.h | 16 + 4 files changed, 645 insertions(+) create mode 100644 drivers/clk/clk-rpmi.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 4d56475f94fc..4d51fa589c1e 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -501,6 +501,14 @@ config COMMON_CLK_SP7021 Not all features of the PLL are currently supported by the driver. +config COMMON_CLK_RPMI + tristate "Clock driver based on RISC-V RPMI" + depends on MAILBOX + default RISCV + help + Support for clocks based on the clock service group defined by + the RISC-V platform management interface (RPMI) specification. + source "drivers/clk/actions/Kconfig" source "drivers/clk/analogbits/Kconfig" source "drivers/clk/baikal-t1/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 18ed29cfdc11..b74a1767ca27 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o obj-$(CONFIG_COMMON_CLK_RP1) += clk-rp1.o +obj-$(CONFIG_COMMON_CLK_RPMI) += clk-rpmi.o obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o diff --git a/drivers/clk/clk-rpmi.c b/drivers/clk/clk-rpmi.c new file mode 100644 index 000000000000..921296aafa68 --- /dev/null +++ b/drivers/clk/clk-rpmi.c @@ -0,0 +1,620 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RISC-V MPXY Based Clock Driver + * + * Copyright (C) 2025 Ventana Micro Systems Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RPMI_CLK_DISCRETE_MAX_NUM_RATES 16 +#define RPMI_CLK_NAME_LEN 16 + +#define to_rpmi_clk(clk) container_of(clk, struct rpmi_clk, hw) + +enum rpmi_clk_config { + RPMI_CLK_DISABLE = 0, + RPMI_CLK_ENABLE = 1, + RPMI_CLK_CONFIG_MAX_IDX +}; + +#define RPMI_CLK_TYPE_MASK GENMASK(1, 0) +enum rpmi_clk_type { + RPMI_CLK_DISCRETE = 0, + RPMI_CLK_LINEAR = 1, + RPMI_CLK_TYPE_MAX_IDX +}; + +struct rpmi_clk_context { + struct device *dev; + struct mbox_chan *chan; + struct mbox_client client; + u32 max_msg_data_size; +}; + +/* + * rpmi_clk_rates represents the rates format + * as specified by the RPMI specification. + * No other data format (e.g., struct linear_range) + * is required to avoid to and from conversion. + */ +union rpmi_clk_rates { + u64 discrete[RPMI_CLK_DISCRETE_MAX_NUM_RATES]; + struct { + u64 min; + u64 max; + u64 step; + } linear; +}; + +struct rpmi_clk { + struct rpmi_clk_context *context; + u32 id; + u32 num_rates; + u32 transition_latency; + enum rpmi_clk_type type; + union rpmi_clk_rates *rates; + char name[RPMI_CLK_NAME_LEN]; + struct clk_hw hw; +}; + +struct rpmi_clk_rate_discrete { + __le32 lo; + __le32 hi; +}; + +struct rpmi_clk_rate_linear { + __le32 min_lo; + __le32 min_hi; + __le32 max_lo; + __le32 max_hi; + __le32 step_lo; + __le32 step_hi; +}; + +struct rpmi_get_num_clocks_rx { + __le32 status; + __le32 num_clocks; +}; + +struct rpmi_get_attrs_tx { + __le32 clkid; +}; + +struct rpmi_get_attrs_rx { + __le32 status; + __le32 flags; + __le32 num_rates; + __le32 transition_latency; + char name[RPMI_CLK_NAME_LEN]; +}; + +struct rpmi_get_supp_rates_tx { + __le32 clkid; + __le32 clk_rate_idx; +}; + +struct rpmi_get_supp_rates_rx { + __le32 status; + __le32 flags; + __le32 remaining; + __le32 returned; + __le32 rates[]; +}; + +struct rpmi_get_rate_tx { + __le32 clkid; +}; + +struct rpmi_get_rate_rx { + __le32 status; + __le32 lo; + __le32 hi; +}; + +struct rpmi_set_rate_tx { + __le32 clkid; + __le32 flags; + __le32 lo; + __le32 hi; +}; + +struct rpmi_set_rate_rx { + __le32 status; +}; + +struct rpmi_set_config_tx { + __le32 clkid; + __le32 config; +}; + +struct rpmi_set_config_rx { + __le32 status; +}; + +static inline u64 rpmi_clkrate_u64(u32 __hi, u32 __lo) +{ + return (((u64)(__hi) << 32) | (u32)(__lo)); +} + +static u32 rpmi_clk_get_num_clocks(struct rpmi_clk_context *context) +{ + struct rpmi_get_num_clocks_rx rx, *resp; + struct rpmi_mbox_message msg; + int ret; + + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_GET_NUM_CLOCKS, + NULL, 0, &rx, sizeof(rx)); + + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return 0; + + resp = rpmi_mbox_get_msg_response(&msg); + if (!resp || resp->status) + return 0; + + return le32_to_cpu(resp->num_clocks); +} + +static int rpmi_clk_get_attrs(u32 clkid, struct rpmi_clk *rpmi_clk) +{ + struct rpmi_clk_context *context = rpmi_clk->context; + struct rpmi_mbox_message msg; + struct rpmi_get_attrs_tx tx; + struct rpmi_get_attrs_rx rx, *resp; + u8 format; + int ret; + + tx.clkid = cpu_to_le32(clkid); + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_GET_ATTRIBUTES, + &tx, sizeof(tx), &rx, sizeof(rx)); + + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return ret; + + resp = rpmi_mbox_get_msg_response(&msg); + if (!resp) + return -EINVAL; + if (resp->status) + return rpmi_to_linux_error(le32_to_cpu(resp->status)); + + rpmi_clk->id = clkid; + rpmi_clk->num_rates = le32_to_cpu(resp->num_rates); + rpmi_clk->transition_latency = le32_to_cpu(resp->transition_latency); + strscpy(rpmi_clk->name, resp->name, RPMI_CLK_NAME_LEN); + + format = le32_to_cpu(resp->flags) & RPMI_CLK_TYPE_MASK; + if (format >= RPMI_CLK_TYPE_MAX_IDX) + return -EINVAL; + + rpmi_clk->type = format; + + return 0; +} + +static int rpmi_clk_get_supported_rates(u32 clkid, struct rpmi_clk *rpmi_clk) +{ + struct rpmi_clk_context *context = rpmi_clk->context; + struct rpmi_clk_rate_discrete *rate_discrete; + struct rpmi_clk_rate_linear *rate_linear; + struct rpmi_get_supp_rates_tx tx; + struct rpmi_get_supp_rates_rx *resp; + struct rpmi_mbox_message msg; + size_t clk_rate_idx; + int ret, rateidx, j; + + tx.clkid = cpu_to_le32(clkid); + tx.clk_rate_idx = 0; + + /* + * Make sure we allocate rx buffer sufficient to be accommodate all + * the rates sent in one RPMI message. + */ + struct rpmi_get_supp_rates_rx *rx __free(kfree) = + kzalloc(context->max_msg_data_size, GFP_KERNEL); + if (!rx) + return -ENOMEM; + + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_GET_SUPPORTED_RATES, + &tx, sizeof(tx), rx, context->max_msg_data_size); + + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return ret; + + resp = rpmi_mbox_get_msg_response(&msg); + if (!resp) + return -EINVAL; + if (resp->status) + return rpmi_to_linux_error(le32_to_cpu(resp->status)); + if (!le32_to_cpu(resp->returned)) + return -EINVAL; + + if (rpmi_clk->type == RPMI_CLK_DISCRETE) { + rate_discrete = (struct rpmi_clk_rate_discrete *)resp->rates; + + for (rateidx = 0; rateidx < le32_to_cpu(resp->returned); rateidx++) { + rpmi_clk->rates->discrete[rateidx] = + rpmi_clkrate_u64(le32_to_cpu(rate_discrete[rateidx].hi), + le32_to_cpu(rate_discrete[rateidx].lo)); + } + + /* + * Keep sending the request message until all + * the rates are received. + */ + clk_rate_idx = 0; + while (le32_to_cpu(resp->remaining)) { + clk_rate_idx += le32_to_cpu(resp->returned); + tx.clk_rate_idx = cpu_to_le32(clk_rate_idx); + + rpmi_mbox_init_send_with_response(&msg, + RPMI_CLK_SRV_GET_SUPPORTED_RATES, + &tx, sizeof(tx), + rx, context->max_msg_data_size); + + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return ret; + + resp = rpmi_mbox_get_msg_response(&msg); + if (!resp) + return -EINVAL; + if (resp->status) + return rpmi_to_linux_error(le32_to_cpu(resp->status)); + if (!le32_to_cpu(resp->returned)) + return -EINVAL; + + for (j = 0; j < le32_to_cpu(resp->returned); j++) { + if (rateidx >= clk_rate_idx + le32_to_cpu(resp->returned)) + break; + rpmi_clk->rates->discrete[rateidx++] = + rpmi_clkrate_u64(le32_to_cpu(rate_discrete[j].hi), + le32_to_cpu(rate_discrete[j].lo)); + } + } + } else if (rpmi_clk->type == RPMI_CLK_LINEAR) { + rate_linear = (struct rpmi_clk_rate_linear *)resp->rates; + + rpmi_clk->rates->linear.min = rpmi_clkrate_u64(le32_to_cpu(rate_linear->min_hi), + le32_to_cpu(rate_linear->min_lo)); + rpmi_clk->rates->linear.max = rpmi_clkrate_u64(le32_to_cpu(rate_linear->max_hi), + le32_to_cpu(rate_linear->max_lo)); + rpmi_clk->rates->linear.step = rpmi_clkrate_u64(le32_to_cpu(rate_linear->step_hi), + le32_to_cpu(rate_linear->step_lo)); + } + + return 0; +} + +static unsigned long rpmi_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rpmi_clk *rpmi_clk = to_rpmi_clk(hw); + struct rpmi_clk_context *context = rpmi_clk->context; + struct rpmi_mbox_message msg; + struct rpmi_get_rate_tx tx; + struct rpmi_get_rate_rx rx, *resp; + int ret; + + tx.clkid = cpu_to_le32(rpmi_clk->id); + + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_GET_RATE, + &tx, sizeof(tx), &rx, sizeof(rx)); + + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return ret; + + resp = rpmi_mbox_get_msg_response(&msg); + if (!resp) + return -EINVAL; + if (resp->status) + return rpmi_to_linux_error(le32_to_cpu(resp->status)); + + return rpmi_clkrate_u64(le32_to_cpu(resp->hi), le32_to_cpu(resp->lo)); +} + +static int rpmi_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct rpmi_clk *rpmi_clk = to_rpmi_clk(hw); + u64 fmin, fmax, ftmp; + + /* + * Keep the requested rate if the clock format + * is of discrete type. Let the platform which + * is actually controlling the clock handle that. + */ + if (rpmi_clk->type == RPMI_CLK_DISCRETE) + return 0; + + fmin = rpmi_clk->rates->linear.min; + fmax = rpmi_clk->rates->linear.max; + + if (req->rate <= fmin) { + req->rate = fmin; + return 0; + } else if (req->rate >= fmax) { + req->rate = fmax; + return 0; + } + + ftmp = req->rate - fmin; + ftmp += rpmi_clk->rates->linear.step - 1; + do_div(ftmp, rpmi_clk->rates->linear.step); + + req->rate = ftmp * rpmi_clk->rates->linear.step + fmin; + + return 0; +} + +static int rpmi_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct rpmi_clk *rpmi_clk = to_rpmi_clk(hw); + struct rpmi_clk_context *context = rpmi_clk->context; + struct rpmi_mbox_message msg; + struct rpmi_set_rate_tx tx; + struct rpmi_set_rate_rx rx, *resp; + int ret; + + tx.clkid = cpu_to_le32(rpmi_clk->id); + tx.lo = cpu_to_le32(lower_32_bits(rate)); + tx.hi = cpu_to_le32(upper_32_bits(rate)); + + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_SET_RATE, + &tx, sizeof(tx), &rx, sizeof(rx)); + + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return ret; + + resp = rpmi_mbox_get_msg_response(&msg); + if (!resp) + return -EINVAL; + if (resp->status) + return rpmi_to_linux_error(le32_to_cpu(resp->status)); + + return 0; +} + +static int rpmi_clk_enable(struct clk_hw *hw) +{ + struct rpmi_clk *rpmi_clk = to_rpmi_clk(hw); + struct rpmi_clk_context *context = rpmi_clk->context; + struct rpmi_mbox_message msg; + struct rpmi_set_config_tx tx; + struct rpmi_set_config_rx rx, *resp; + int ret; + + tx.config = cpu_to_le32(RPMI_CLK_ENABLE); + tx.clkid = cpu_to_le32(rpmi_clk->id); + + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_SET_CONFIG, + &tx, sizeof(tx), &rx, sizeof(rx)); + + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return ret; + + resp = rpmi_mbox_get_msg_response(&msg); + if (!resp) + return -EINVAL; + if (resp->status) + return rpmi_to_linux_error(le32_to_cpu(resp->status)); + + return 0; +} + +static void rpmi_clk_disable(struct clk_hw *hw) +{ + struct rpmi_clk *rpmi_clk = to_rpmi_clk(hw); + struct rpmi_clk_context *context = rpmi_clk->context; + struct rpmi_mbox_message msg; + struct rpmi_set_config_tx tx; + struct rpmi_set_config_rx rx; + + tx.config = cpu_to_le32(RPMI_CLK_DISABLE); + tx.clkid = cpu_to_le32(rpmi_clk->id); + + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_SET_CONFIG, + &tx, sizeof(tx), &rx, sizeof(rx)); + + rpmi_mbox_send_message(context->chan, &msg); +} + +static const struct clk_ops rpmi_clk_ops = { + .recalc_rate = rpmi_clk_recalc_rate, + .determine_rate = rpmi_clk_determine_rate, + .set_rate = rpmi_clk_set_rate, + .prepare = rpmi_clk_enable, + .unprepare = rpmi_clk_disable, +}; + +static struct clk_hw *rpmi_clk_enumerate(struct rpmi_clk_context *context, u32 clkid) +{ + struct device *dev = context->dev; + unsigned long min_rate, max_rate; + union rpmi_clk_rates *rates; + struct rpmi_clk *rpmi_clk; + struct clk_init_data init = {}; + struct clk_hw *clk_hw; + int ret; + + rates = devm_kzalloc(dev, sizeof(*rates), GFP_KERNEL); + if (!rates) + return ERR_PTR(-ENOMEM); + + rpmi_clk = devm_kzalloc(dev, sizeof(*rpmi_clk), GFP_KERNEL); + if (!rpmi_clk) + return ERR_PTR(-ENOMEM); + + rpmi_clk->context = context; + rpmi_clk->rates = rates; + + ret = rpmi_clk_get_attrs(clkid, rpmi_clk); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to get clk-%u attributes\n", + clkid); + + ret = rpmi_clk_get_supported_rates(clkid, rpmi_clk); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Get supported rates failed for clk-%u\n", + clkid); + + init.flags = CLK_GET_RATE_NOCACHE; + init.num_parents = 0; + init.ops = &rpmi_clk_ops; + init.name = rpmi_clk->name; + clk_hw = &rpmi_clk->hw; + clk_hw->init = &init; + + ret = devm_clk_hw_register(dev, clk_hw); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Unable to register clk-%u\n", + clkid); + + if (rpmi_clk->type == RPMI_CLK_DISCRETE) { + min_rate = rpmi_clk->rates->discrete[0]; + max_rate = rpmi_clk->rates->discrete[rpmi_clk->num_rates - 1]; + } else { + min_rate = rpmi_clk->rates->linear.min; + max_rate = rpmi_clk->rates->linear.max; + } + + clk_hw_set_rate_range(clk_hw, min_rate, max_rate); + + return clk_hw; +} + +static void rpmi_clk_mbox_chan_release(void *data) +{ + struct mbox_chan *chan = data; + + mbox_free_channel(chan); +} + +static int rpmi_clk_probe(struct platform_device *pdev) +{ + int ret; + unsigned int num_clocks, i; + struct clk_hw_onecell_data *clk_data; + struct rpmi_clk_context *context; + struct rpmi_mbox_message msg; + struct clk_hw *hw_ptr; + struct device *dev = &pdev->dev; + + context = devm_kzalloc(dev, sizeof(*context), GFP_KERNEL); + if (!context) + return -ENOMEM; + context->dev = dev; + platform_set_drvdata(pdev, context); + + context->client.dev = context->dev; + context->client.rx_callback = NULL; + context->client.tx_block = false; + context->client.knows_txdone = true; + context->client.tx_tout = 0; + + context->chan = mbox_request_channel(&context->client, 0); + if (IS_ERR(context->chan)) + return PTR_ERR(context->chan); + + ret = devm_add_action_or_reset(dev, rpmi_clk_mbox_chan_release, context->chan); + if (ret) + return dev_err_probe(dev, ret, "Failed to add rpmi mbox channel cleanup\n"); + + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SPEC_VERSION); + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return dev_err_probe(dev, ret, "Failed to get spec version\n"); + if (msg.attr.value < RPMI_MKVER(1, 0)) { + return dev_err_probe(dev, -EINVAL, + "msg protocol version mismatch, expected 0x%x, found 0x%x\n", + RPMI_MKVER(1, 0), msg.attr.value); + } + + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SERVICEGROUP_ID); + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return dev_err_probe(dev, ret, "Failed to get service group ID\n"); + if (msg.attr.value != RPMI_SRVGRP_CLOCK) { + return dev_err_probe(dev, -EINVAL, + "service group match failed, expected 0x%x, found 0x%x\n", + RPMI_SRVGRP_CLOCK, msg.attr.value); + } + + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SERVICEGROUP_VERSION); + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return dev_err_probe(dev, ret, "Failed to get service group version\n"); + if (msg.attr.value < RPMI_MKVER(1, 0)) { + return dev_err_probe(dev, -EINVAL, + "service group version failed, expected 0x%x, found 0x%x\n", + RPMI_MKVER(1, 0), msg.attr.value); + } + + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_MAX_MSG_DATA_SIZE); + ret = rpmi_mbox_send_message(context->chan, &msg); + if (ret) + return dev_err_probe(dev, ret, "Failed to get max message data size\n"); + + context->max_msg_data_size = msg.attr.value; + num_clocks = rpmi_clk_get_num_clocks(context); + if (!num_clocks) + return dev_err_probe(dev, -ENODEV, "No clocks found\n"); + + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, num_clocks), + GFP_KERNEL); + if (!clk_data) + return dev_err_probe(dev, -ENOMEM, "No memory for clock data\n"); + clk_data->num = num_clocks; + + for (i = 0; i < clk_data->num; i++) { + hw_ptr = rpmi_clk_enumerate(context, i); + if (IS_ERR(hw_ptr)) { + return dev_err_probe(dev, PTR_ERR(hw_ptr), + "Failed to register clk-%d\n", i); + } + clk_data->hws[i] = hw_ptr; + } + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); + if (ret) + return dev_err_probe(dev, ret, "Failed to register clock HW provider\n"); + + return 0; +} + +static const struct of_device_id rpmi_clk_of_match[] = { + { .compatible = "riscv,rpmi-clock" }, + { } +}; +MODULE_DEVICE_TABLE(of, rpmi_clk_of_match); + +static struct platform_driver rpmi_clk_driver = { + .driver = { + .name = "riscv-rpmi-clock", + .of_match_table = rpmi_clk_of_match, + }, + .probe = rpmi_clk_probe, +}; +module_platform_driver(rpmi_clk_driver); + +MODULE_AUTHOR("Rahul Pathak "); +MODULE_DESCRIPTION("Clock Driver based on RPMI message protocol"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mailbox/riscv-rpmi-message.h b/include/linux/mailbox/riscv-rpmi-message.h index c3a98fc12c0a..8176d33747fe 100644 --- a/include/linux/mailbox/riscv-rpmi-message.h +++ b/include/linux/mailbox/riscv-rpmi-message.h @@ -90,6 +90,22 @@ static inline int rpmi_to_linux_error(int rpmi_error) } } +/* RPMI service group IDs */ +#define RPMI_SRVGRP_CLOCK 0x00008 + +/* RPMI clock service IDs */ +enum rpmi_clock_service_id { + RPMI_CLK_SRV_ENABLE_NOTIFICATION = 0x01, + RPMI_CLK_SRV_GET_NUM_CLOCKS = 0x02, + RPMI_CLK_SRV_GET_ATTRIBUTES = 0x03, + RPMI_CLK_SRV_GET_SUPPORTED_RATES = 0x04, + RPMI_CLK_SRV_SET_CONFIG = 0x05, + RPMI_CLK_SRV_GET_CONFIG = 0x06, + RPMI_CLK_SRV_SET_RATE = 0x07, + RPMI_CLK_SRV_GET_RATE = 0x08, + RPMI_CLK_SRV_ID_MAX_COUNT +}; + /* RPMI Linux mailbox attribute IDs */ enum rpmi_mbox_attribute_id { RPMI_MBOX_ATTR_SPEC_VERSION, From a72ab2514b7c8e8203c551310166f4c72262ff43 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:07 +0530 Subject: [PATCH 2113/2711] dt-bindings: Add RPMI system MSI message proxy bindings Add device tree bindings for the RPMI system MSI service group based message proxy implemented by the SBI implementation (machine mode firmware or hypervisor). The RPMI system MSI service group is defined by the RISC-V platform management interface (RPMI) specification. Reviewed-by: Atish Patra Reviewed-by: Conor Dooley Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-12-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- .../riscv,rpmi-mpxy-system-msi.yaml | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/riscv,rpmi-mpxy-system-msi.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,rpmi-mpxy-system-msi.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,rpmi-mpxy-system-msi.yaml new file mode 100644 index 000000000000..1991f5c7446a --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,rpmi-mpxy-system-msi.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/riscv,rpmi-mpxy-system-msi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V RPMI system MSI service group based message proxy + +maintainers: + - Anup Patel + +description: | + The RISC-V Platform Management Interface (RPMI) [1] defines a + messaging protocol which is modular and extensible. The supervisor + software can send/receive RPMI messages via SBI MPXY extension [2] + or some dedicated supervisor-mode RPMI transport. + + The RPMI specification [1] defines system MSI service group which + allow application processors to receive MSIs upon system events + such as P2A doorbell, graceful shutdown/reboot request, CPU hotplug + event, memory hotplug event, etc from the platform microcontroller. + The SBI implementation (machine mode firmware or hypervisor) can + implement an SBI MPXY channel to allow RPMI system MSI service + group access to the supervisor software. + + =========================================== + References + =========================================== + + [1] RISC-V Platform Management Interface (RPMI) v1.0 (or higher) + https://github.com/riscv-non-isa/riscv-rpmi/releases + + [2] RISC-V Supervisor Binary Interface (SBI) v3.0 (or higher) + https://github.com/riscv-non-isa/riscv-sbi-doc/releases + +properties: + compatible: + description: + Intended for use by the SBI implementation. + const: riscv,rpmi-mpxy-system-msi + + mboxes: + maxItems: 1 + description: + Mailbox channel of the underlying RPMI transport. + + riscv,sbi-mpxy-channel-id: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The SBI MPXY channel id to be used for providing RPMI access to + the supervisor software. + +required: + - compatible + - mboxes + - riscv,sbi-mpxy-channel-id + +additionalProperties: false + +examples: + - | + interrupt-controller { + compatible = "riscv,rpmi-mpxy-system-msi"; + mboxes = <&rpmi_shmem_mbox 0x2>; + riscv,sbi-mpxy-channel-id = <0x2000>; + }; +... From 3e6cf38486005831e063fd0d943a46bc8434e732 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:08 +0530 Subject: [PATCH 2114/2711] dt-bindings: Add RPMI system MSI interrupt controller bindings Add device tree bindings for the RPMI system MSI service group based interrupt controller for the supervisor software. The RPMI system MSI service group is defined by the RISC-V platform management interface (RPMI) specification. Reviewed-by: Atish Patra Reviewed-by: Conor Dooley Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-13-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- .../riscv,rpmi-system-msi.yaml | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/riscv,rpmi-system-msi.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,rpmi-system-msi.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,rpmi-system-msi.yaml new file mode 100644 index 000000000000..b10a0532e586 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,rpmi-system-msi.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/riscv,rpmi-system-msi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V RPMI system MSI service group based interrupt controller + +maintainers: + - Anup Patel + +description: | + The RISC-V Platform Management Interface (RPMI) [1] defines a + messaging protocol which is modular and extensible. The supervisor + software can send/receive RPMI messages via SBI MPXY extension [2] + or some dedicated supervisor-mode RPMI transport. + + The RPMI specification [1] defines system MSI service group which + allow application processors to receive MSIs upon system events + such as P2A doorbell, graceful shutdown/reboot request, CPU hotplug + event, memory hotplug event, etc from the platform microcontroller. + The supervisor software can access RPMI system MSI service group via + SBI MPXY channel or some dedicated supervisor-mode RPMI transport. + + =========================================== + References + =========================================== + + [1] RISC-V Platform Management Interface (RPMI) v1.0 (or higher) + https://github.com/riscv-non-isa/riscv-rpmi/releases + + [2] RISC-V Supervisor Binary Interface (SBI) v3.0 (or higher) + https://github.com/riscv-non-isa/riscv-sbi-doc/releases + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + +properties: + compatible: + description: + Intended for use by the supervisor software. + const: riscv,rpmi-system-msi + + mboxes: + maxItems: 1 + description: + Mailbox channel of the underlying RPMI transport or SBI message proxy channel. + + msi-parent: true + + interrupt-controller: true + + "#interrupt-cells": + const: 1 + +required: + - compatible + - mboxes + - msi-parent + - interrupt-controller + - "#interrupt-cells" + +additionalProperties: false + +examples: + - | + interrupt-controller { + compatible = "riscv,rpmi-system-msi"; + mboxes = <&mpxy_mbox 0x2000 0x0>; + msi-parent = <&imsic_slevel>; + interrupt-controller; + #interrupt-cells = <1>; + }; +... From aa43953e862c031ff66e44353c88beb7a449e80d Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:09 +0530 Subject: [PATCH 2115/2711] irqchip: Add driver for the RPMI system MSI service group The RPMI specification defines a system MSI service group which allows application processors to receive MSIs upon system events such as graceful shutdown/reboot request, CPU hotplug event, memory hotplug event, etc. Add an irqchip driver for the RISC-V RPMI system MSI service group to directly receive system MSIs in Linux kernel. Reviewed-by: Thomas Gleixner Signed-off-by: Anup Patel Link: https://lore.kernel.org/r/20250818040920.272664-14-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/irqchip/Kconfig | 7 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-riscv-rpmi-sysmsi.c | 287 +++++++++++++++++++++ include/linux/mailbox/riscv-rpmi-message.h | 13 + 4 files changed, 308 insertions(+) create mode 100644 drivers/irqchip/irq-riscv-rpmi-sysmsi.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 6d12c6ab9ea4..e047ba36df16 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -634,6 +634,13 @@ config RISCV_IMSIC select GENERIC_MSI_IRQ select IRQ_MSI_LIB +config RISCV_RPMI_SYSMSI + bool + depends on MAILBOX + select IRQ_DOMAIN_HIERARCHY + select GENERIC_MSI_IRQ + default RISCV + config SIFIVE_PLIC bool depends on RISCV diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 93e3ced023bb..3de083f5484c 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -106,6 +106,7 @@ obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o obj-$(CONFIG_RISCV_APLIC) += irq-riscv-aplic-main.o irq-riscv-aplic-direct.o obj-$(CONFIG_RISCV_APLIC_MSI) += irq-riscv-aplic-msi.o obj-$(CONFIG_RISCV_IMSIC) += irq-riscv-imsic-state.o irq-riscv-imsic-early.o irq-riscv-imsic-platform.o +obj-$(CONFIG_RISCV_RPMI_SYSMSI) += irq-riscv-rpmi-sysmsi.o obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o obj-$(CONFIG_STARFIVE_JH8100_INTC) += irq-starfive-jh8100-intc.o obj-$(CONFIG_ACLINT_SSWI) += irq-aclint-sswi.o diff --git a/drivers/irqchip/irq-riscv-rpmi-sysmsi.c b/drivers/irqchip/irq-riscv-rpmi-sysmsi.c new file mode 100644 index 000000000000..92e8847dfccc --- /dev/null +++ b/drivers/irqchip/irq-riscv-rpmi-sysmsi.c @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2025 Ventana Micro Systems Inc. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rpmi_sysmsi_get_attrs_rx { + __le32 status; + __le32 sys_num_msi; + __le32 flag0; + __le32 flag1; +}; + +#define RPMI_SYSMSI_MSI_ATTRIBUTES_FLAG0_PREF_PRIV BIT(0) + +struct rpmi_sysmsi_set_msi_state_tx { + __le32 sys_msi_index; + __le32 sys_msi_state; +}; + +struct rpmi_sysmsi_set_msi_state_rx { + __le32 status; +}; + +#define RPMI_SYSMSI_MSI_STATE_ENABLE BIT(0) +#define RPMI_SYSMSI_MSI_STATE_PENDING BIT(1) + +struct rpmi_sysmsi_set_msi_target_tx { + __le32 sys_msi_index; + __le32 sys_msi_address_low; + __le32 sys_msi_address_high; + __le32 sys_msi_data; +}; + +struct rpmi_sysmsi_set_msi_target_rx { + __le32 status; +}; + +struct rpmi_sysmsi_priv { + struct device *dev; + struct mbox_client client; + struct mbox_chan *chan; + u32 nr_irqs; + u32 gsi_base; +}; + +static int rpmi_sysmsi_get_num_msi(struct rpmi_sysmsi_priv *priv) +{ + struct rpmi_sysmsi_get_attrs_rx rx; + struct rpmi_mbox_message msg; + int ret; + + rpmi_mbox_init_send_with_response(&msg, RPMI_SYSMSI_SRV_GET_ATTRIBUTES, + NULL, 0, &rx, sizeof(rx)); + ret = rpmi_mbox_send_message(priv->chan, &msg); + if (ret) + return ret; + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + return le32_to_cpu(rx.sys_num_msi); +} + +static int rpmi_sysmsi_set_msi_state(struct rpmi_sysmsi_priv *priv, + u32 sys_msi_index, u32 sys_msi_state) +{ + struct rpmi_sysmsi_set_msi_state_tx tx; + struct rpmi_sysmsi_set_msi_state_rx rx; + struct rpmi_mbox_message msg; + int ret; + + tx.sys_msi_index = cpu_to_le32(sys_msi_index); + tx.sys_msi_state = cpu_to_le32(sys_msi_state); + rpmi_mbox_init_send_with_response(&msg, RPMI_SYSMSI_SRV_SET_MSI_STATE, + &tx, sizeof(tx), &rx, sizeof(rx)); + ret = rpmi_mbox_send_message(priv->chan, &msg); + if (ret) + return ret; + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + return 0; +} + +static int rpmi_sysmsi_set_msi_target(struct rpmi_sysmsi_priv *priv, + u32 sys_msi_index, struct msi_msg *m) +{ + struct rpmi_sysmsi_set_msi_target_tx tx; + struct rpmi_sysmsi_set_msi_target_rx rx; + struct rpmi_mbox_message msg; + int ret; + + tx.sys_msi_index = cpu_to_le32(sys_msi_index); + tx.sys_msi_address_low = cpu_to_le32(m->address_lo); + tx.sys_msi_address_high = cpu_to_le32(m->address_hi); + tx.sys_msi_data = cpu_to_le32(m->data); + rpmi_mbox_init_send_with_response(&msg, RPMI_SYSMSI_SRV_SET_MSI_TARGET, + &tx, sizeof(tx), &rx, sizeof(rx)); + ret = rpmi_mbox_send_message(priv->chan, &msg); + if (ret) + return ret; + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + return 0; +} + +static void rpmi_sysmsi_irq_mask(struct irq_data *d) +{ + struct rpmi_sysmsi_priv *priv = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + int ret; + + ret = rpmi_sysmsi_set_msi_state(priv, hwirq, 0); + if (ret) + dev_warn(priv->dev, "Failed to mask hwirq %lu (error %d)\n", hwirq, ret); + irq_chip_mask_parent(d); +} + +static void rpmi_sysmsi_irq_unmask(struct irq_data *d) +{ + struct rpmi_sysmsi_priv *priv = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + int ret; + + irq_chip_unmask_parent(d); + ret = rpmi_sysmsi_set_msi_state(priv, hwirq, RPMI_SYSMSI_MSI_STATE_ENABLE); + if (ret) + dev_warn(priv->dev, "Failed to unmask hwirq %lu (error %d)\n", hwirq, ret); +} + +static void rpmi_sysmsi_write_msg(struct irq_data *d, struct msi_msg *msg) +{ + struct rpmi_sysmsi_priv *priv = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + int ret; + + /* For zeroed MSI, do nothing as of now */ + if (!msg->address_hi && !msg->address_lo && !msg->data) + return; + + ret = rpmi_sysmsi_set_msi_target(priv, hwirq, msg); + if (ret) + dev_warn(priv->dev, "Failed to set target for hwirq %lu (error %d)\n", hwirq, ret); +} + +static void rpmi_sysmsi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) +{ + arg->desc = desc; + arg->hwirq = desc->data.icookie.value; +} + +static int rpmi_sysmsi_translate(struct irq_domain *d, struct irq_fwspec *fwspec, + unsigned long *hwirq, unsigned int *type) +{ + struct msi_domain_info *info = d->host_data; + struct rpmi_sysmsi_priv *priv = info->data; + + if (WARN_ON(fwspec->param_count < 1)) + return -EINVAL; + + /* For DT, gsi_base is always zero. */ + *hwirq = fwspec->param[0] - priv->gsi_base; + *type = IRQ_TYPE_NONE; + return 0; +} + +static const struct msi_domain_template rpmi_sysmsi_template = { + .chip = { + .name = "RPMI-SYSMSI", + .irq_mask = rpmi_sysmsi_irq_mask, + .irq_unmask = rpmi_sysmsi_irq_unmask, +#ifdef CONFIG_SMP + .irq_set_affinity = irq_chip_set_affinity_parent, +#endif + .irq_write_msi_msg = rpmi_sysmsi_write_msg, + .flags = IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_MASK_ON_SUSPEND, + }, + + .ops = { + .set_desc = rpmi_sysmsi_set_desc, + .msi_translate = rpmi_sysmsi_translate, + }, + + .info = { + .bus_token = DOMAIN_BUS_WIRED_TO_MSI, + .flags = MSI_FLAG_USE_DEV_FWNODE, + .handler = handle_simple_irq, + .handler_name = "simple", + }, +}; + +static int rpmi_sysmsi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rpmi_sysmsi_priv *priv; + int rc; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dev = dev; + + /* Setup mailbox client */ + priv->client.dev = priv->dev; + priv->client.rx_callback = NULL; + priv->client.tx_block = false; + priv->client.knows_txdone = true; + priv->client.tx_tout = 0; + + /* Request mailbox channel */ + priv->chan = mbox_request_channel(&priv->client, 0); + if (IS_ERR(priv->chan)) + return PTR_ERR(priv->chan); + + /* Get number of system MSIs */ + rc = rpmi_sysmsi_get_num_msi(priv); + if (rc < 1) { + mbox_free_channel(priv->chan); + if (rc) + return dev_err_probe(dev, rc, "Failed to get number of system MSIs\n"); + else + return dev_err_probe(dev, -ENODEV, "No system MSIs found\n"); + } + priv->nr_irqs = rc; + + /* + * The device MSI domain for platform devices on RISC-V architecture + * is only available after the MSI controller driver is probed so, + * explicitly configure here. + */ + if (!dev_get_msi_domain(dev)) { + /* + * The device MSI domain for OF devices is only set at the + * time of populating/creating OF device. If the device MSI + * domain is discovered later after the OF device is created + * then we need to set it explicitly before using any platform + * MSI functions. + */ + if (dev_of_node(dev)) + of_msi_configure(dev, dev_of_node(dev)); + + if (!dev_get_msi_domain(dev)) { + mbox_free_channel(priv->chan); + return -EPROBE_DEFER; + } + } + + if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN, + &rpmi_sysmsi_template, + priv->nr_irqs, priv, priv)) { + mbox_free_channel(priv->chan); + return dev_err_probe(dev, -ENOMEM, "failed to create MSI irq domain\n"); + } + + dev_info(dev, "%u system MSIs registered\n", priv->nr_irqs); + return 0; +} + +static const struct of_device_id rpmi_sysmsi_match[] = { + { .compatible = "riscv,rpmi-system-msi" }, + {} +}; + +static struct platform_driver rpmi_sysmsi_driver = { + .driver = { + .name = "rpmi-sysmsi", + .of_match_table = rpmi_sysmsi_match, + }, + .probe = rpmi_sysmsi_probe, +}; +builtin_platform_driver(rpmi_sysmsi_driver); diff --git a/include/linux/mailbox/riscv-rpmi-message.h b/include/linux/mailbox/riscv-rpmi-message.h index 8176d33747fe..e135c6564d0c 100644 --- a/include/linux/mailbox/riscv-rpmi-message.h +++ b/include/linux/mailbox/riscv-rpmi-message.h @@ -91,6 +91,7 @@ static inline int rpmi_to_linux_error(int rpmi_error) } /* RPMI service group IDs */ +#define RPMI_SRVGRP_SYSTEM_MSI 0x00002 #define RPMI_SRVGRP_CLOCK 0x00008 /* RPMI clock service IDs */ @@ -106,6 +107,18 @@ enum rpmi_clock_service_id { RPMI_CLK_SRV_ID_MAX_COUNT }; +/* RPMI system MSI service IDs */ +enum rpmi_sysmsi_service_id { + RPMI_SYSMSI_SRV_ENABLE_NOTIFICATION = 0x01, + RPMI_SYSMSI_SRV_GET_ATTRIBUTES = 0x02, + RPMI_SYSMSI_SRV_GET_MSI_ATTRIBUTES = 0x03, + RPMI_SYSMSI_SRV_SET_MSI_STATE = 0x04, + RPMI_SYSMSI_SRV_GET_MSI_STATE = 0x05, + RPMI_SYSMSI_SRV_SET_MSI_TARGET = 0x06, + RPMI_SYSMSI_SRV_GET_MSI_TARGET = 0x07, + RPMI_SYSMSI_SRV_ID_MAX_COUNT +}; + /* RPMI Linux mailbox attribute IDs */ enum rpmi_mbox_attribute_id { RPMI_MBOX_ATTR_SPEC_VERSION, From a43ac325c7cbbfe72bdf9178059b3ee9f5a2c7dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Wed, 24 Sep 2025 16:42:27 +0300 Subject: [PATCH 2116/2711] PCI: Set up bridge resources earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bridge windows are read twice from PCI Config Space, the first time from pci_read_bridge_windows(), which does not set up the device's resources. This causes problems down the road as child resources of the bridge cannot check whether they reside within the bridge window or not. Set up the bridge windows already in pci_read_bridge_windows(). Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250924134228.1663-2-ilpo.jarvinen@linux.intel.com --- drivers/pci/probe.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index eaeb66bec433..86a83ab043d2 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -537,10 +537,14 @@ static void pci_read_bridge_windows(struct pci_dev *bridge) } if (io) { bridge->io_window = 1; - pci_read_bridge_io(bridge, &res, true); + pci_read_bridge_io(bridge, + pci_resource_n(bridge, PCI_BRIDGE_IO_WINDOW), + true); } - pci_read_bridge_mmio(bridge, &res, true); + pci_read_bridge_mmio(bridge, + pci_resource_n(bridge, PCI_BRIDGE_MEM_WINDOW), + true); /* * DECchip 21050 pass 2 errata: the bridge may miss an address @@ -578,7 +582,10 @@ static void pci_read_bridge_windows(struct pci_dev *bridge) bridge->pref_64_window = 1; } - pci_read_bridge_mmio_pref(bridge, &res, true); + pci_read_bridge_mmio_pref(bridge, + pci_resource_n(bridge, + PCI_BRIDGE_PREF_MEM_WINDOW), + true); } void pci_read_bridge_bases(struct pci_bus *child) From e121be784d35e2950652b46258a87381e00270ab Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Aug 2025 09:39:10 +0530 Subject: [PATCH 2117/2711] ACPI: property: Refactor acpi_fwnode_get_reference_args() to support nargs_prop Currently, acpi_fwnode_get_reference_args() delegates to the internal function __acpi_node_get_property_reference() to retrieve property references. However, this function does not handle the nargs_prop (cells property) parameter, and instead expects the number of arguments (nargs) to be known or hardcoded. As a result, when fwnode_property_get_reference_args() is used with a valid nargs_prop, the ACPI backend ignores it, whereas the Device Tree (DT) backend uses the #*-cells property from the reference node to determine the number of arguments dynamically. To support the nargs_prop in ACPI, refactor the code as follows: - Move the implementation from __acpi_node_get_property_reference() into acpi_fwnode_get_reference_args(). - Update __acpi_node_get_property_reference() to call the (now updated) acpi_fwnode_get_reference_args() passing NULL as nargs_prop to keep the behavior of __acpi_node_get_property_reference() intact. Acked-by: Rafael J. Wysocki Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Sunil V L Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-15-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/acpi/property.c | 101 ++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 436019d96027..d4863746fb11 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -882,45 +882,10 @@ static struct fwnode_handle *acpi_parse_string_ref(const struct fwnode_handle *f return &dn->fwnode; } -/** - * __acpi_node_get_property_reference - returns handle to the referenced object - * @fwnode: Firmware node to get the property from - * @propname: Name of the property - * @index: Index of the reference to return - * @num_args: Maximum number of arguments after each reference - * @args: Location to store the returned reference with optional arguments - * (may be NULL) - * - * Find property with @name, verifify that it is a package containing at least - * one object reference and if so, store the ACPI device object pointer to the - * target object in @args->adev. If the reference includes arguments, store - * them in the @args->args[] array. - * - * If there's more than one reference in the property value package, @index is - * used to select the one to return. - * - * It is possible to leave holes in the property value set like in the - * example below: - * - * Package () { - * "cs-gpios", - * Package () { - * ^GPIO, 19, 0, 0, - * ^GPIO, 20, 0, 0, - * 0, - * ^GPIO, 21, 0, 0, - * } - * } - * - * Calling this function with index %2 or index %3 return %-ENOENT. If the - * property does not contain any more values %-ENOENT is returned. The NULL - * entry must be single integer and preferably contain value %0. - * - * Return: %0 on success, negative error code on failure. - */ -int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, - const char *propname, size_t index, size_t num_args, - struct fwnode_reference_args *args) +static int acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, + const char *propname, const char *nargs_prop, + unsigned int args_count, unsigned int index, + struct fwnode_reference_args *args) { const union acpi_object *element, *end; const union acpi_object *obj; @@ -999,7 +964,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, ret = acpi_get_ref_args(idx == index ? args : NULL, acpi_fwnode_handle(device), - &element, end, num_args); + &element, end, args_count); if (ret < 0) return ret; @@ -1017,7 +982,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, ret = acpi_get_ref_args(idx == index ? args : NULL, ref_fwnode, &element, end, - num_args); + args_count); if (ret < 0) return ret; @@ -1039,6 +1004,50 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, return -ENOENT; } + +/** + * __acpi_node_get_property_reference - returns handle to the referenced object + * @fwnode: Firmware node to get the property from + * @propname: Name of the property + * @index: Index of the reference to return + * @num_args: Maximum number of arguments after each reference + * @args: Location to store the returned reference with optional arguments + * (may be NULL) + * + * Find property with @name, verifify that it is a package containing at least + * one object reference and if so, store the ACPI device object pointer to the + * target object in @args->adev. If the reference includes arguments, store + * them in the @args->args[] array. + * + * If there's more than one reference in the property value package, @index is + * used to select the one to return. + * + * It is possible to leave holes in the property value set like in the + * example below: + * + * Package () { + * "cs-gpios", + * Package () { + * ^GPIO, 19, 0, 0, + * ^GPIO, 20, 0, 0, + * 0, + * ^GPIO, 21, 0, 0, + * } + * } + * + * Calling this function with index %2 or index %3 return %-ENOENT. If the + * property does not contain any more values %-ENOENT is returned. The NULL + * entry must be single integer and preferably contain value %0. + * + * Return: %0 on success, negative error code on failure. + */ +int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, + const char *propname, size_t index, + size_t num_args, + struct fwnode_reference_args *args) +{ + return acpi_fwnode_get_reference_args(fwnode, propname, NULL, index, num_args, args); +} EXPORT_SYMBOL_GPL(__acpi_node_get_property_reference); static int acpi_data_prop_read_single(const struct acpi_device_data *data, @@ -1558,16 +1567,6 @@ acpi_fwnode_property_read_string_array(const struct fwnode_handle *fwnode, val, nval); } -static int -acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, - const char *prop, const char *nargs_prop, - unsigned int args_count, unsigned int index, - struct fwnode_reference_args *args) -{ - return __acpi_node_get_property_reference(fwnode, prop, index, - args_count, args); -} - static const char *acpi_fwnode_get_name(const struct fwnode_handle *fwnode) { const struct acpi_device *adev; From 8795b70581770657cd5ead3c965348f05242580f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 19 Sep 2025 15:45:58 +0200 Subject: [PATCH 2118/2711] PCI: rcar-gen4: Add missing 1ms delay after PWR reset assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R-Car V4H Reference Manual R19UH0186EJ0130 Rev.1.30 Apr. 21, 2025 page 585 Figure 9.3.2 Software Reset flow (B) indicates that for peripherals in HSC domain, after reset has been asserted by writing a matching reset bit into register SRCR, it is mandatory to wait 1ms. Because it is the controller driver which can determine whether or not the controller is in HSC domain based on its compatible string, add the missing delay in the controller driver. This 1ms delay is documented on R-Car V4H and V4M; it is currently unclear whether S4 is affected as well. This patch does apply the extra delay on R-Car S4 as well. Fixes: 0d0c551011df ("PCI: rcar-gen4: Add R-Car Gen4 PCIe controller support for host mode") Suggested-by: Geert Uytterhoeven Signed-off-by: Marek Vasut [mani: added the missing r-b tag from Krzysztof] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Geert Uytterhoeven Reviewed-by: Krzysztof Wilczyński Link: https://patch.msgid.link/20250919134644.208098-1-marek.vasut+renesas@mailbox.org --- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index 366e21bffcbe..f996e96be1d7 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -182,8 +182,17 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar) return ret; } - if (!reset_control_status(dw->core_rsts[DW_PCIE_PWR_RST].rstc)) + if (!reset_control_status(dw->core_rsts[DW_PCIE_PWR_RST].rstc)) { reset_control_assert(dw->core_rsts[DW_PCIE_PWR_RST].rstc); + /* + * R-Car V4H Reference Manual R19UH0186EJ0130 Rev.1.30 Apr. + * 21, 2025 page 585 Figure 9.3.2 Software Reset flow (B) + * indicates that for peripherals in HSC domain, after + * reset has been asserted by writing a matching reset bit + * into register SRCR, it is mandatory to wait 1ms. + */ + fsleep(1000); + } val = readl(rcar->base + PCIEMSR0); if (rcar->drvdata->mode == DW_PCIE_RC_TYPE) { From 0056d29f8c1b13d7e60d60cdb159767ac8f6a883 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 24 Sep 2025 02:55:45 +0200 Subject: [PATCH 2119/2711] PCI: rcar-gen4: Assure reset occurs before DBI access Assure the reset is latched and the core is ready for DBI access. On R-Car V4H, the PCIe reset is asynchronous and does not take effect immediately, but needs a short time to complete. In case DBI access happens in that short time, that access generates an SError. Make sure that condition can never happen, read back the state of the reset, which should turn the asynchronous reset into a synchronous one, and wait a little over 1ms to add additional safety margin. Fixes: 0d0c551011df ("PCI: rcar-gen4: Add R-Car Gen4 PCIe controller support for host mode") Signed-off-by: Marek Vasut Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Tested-by: Geert Uytterhoeven Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250924005610.96484-1-marek.vasut+renesas@mailbox.org --- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index f996e96be1d7..cc03dd421de8 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -213,6 +213,19 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar) if (ret) goto err_unprepare; + /* + * Assure the reset is latched and the core is ready for DBI access. + * On R-Car V4H, the PCIe reset is asynchronous and does not take + * effect immediately, but needs a short time to complete. In case + * DBI access happens in that short time, that access generates an + * SError. To make sure that condition can never happen, read back the + * state of the reset, which should turn the asynchronous reset into + * synchronous one, and wait a little over 1ms to add additional + * safety margin. + */ + reset_control_status(dw->core_rsts[DW_PCIE_PWR_RST].rstc); + fsleep(1000); + if (rcar->drvdata->additional_common_init) rcar->drvdata->additional_common_init(rcar); From 2bdf1d428f48e1077791bb7f88fd00262118256d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 16 Sep 2025 01:58:40 +0200 Subject: [PATCH 2120/2711] PCI: rcar-gen4: Fix inverted break condition in PHY initialization R-Car V4H Reference Manual R19UH0186EJ0130 Rev.1.30 Apr. 21, 2025 page 4581 Figure 104.3b Initial Setting of PCIEC(example), third quarter of the figure indicates that register 0xf8 should be polled until bit 18 becomes set to 1. Register 0xf8, bit 18 is 0 immediately after write to PCIERSTCTRL1 and is set to 1 in less than 1 ms afterward. The current readl_poll_timeout() break condition is inverted and returns when register 0xf8, bit 18 is set to 0, which in most cases means immediately. In case CONFIG_DEBUG_LOCK_ALLOC=y, the timing changes just enough for the first readl_poll_timeout() poll to already read register 0xf8, bit 18 as 1 and afterward never read register 0xf8, bit 18 as 0, which leads to timeout and failure to start the PCIe controller. Fix this by inverting the poll condition to match the reference manual initialization sequence. Fixes: faf5a975ee3b ("PCI: rcar-gen4: Add support for R-Car V4H") Signed-off-by: Marek Vasut Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Tested-by: Geert Uytterhoeven Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250915235910.47768-1-marek.vasut+renesas@mailbox.org --- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index cc03dd421de8..1ac71ee0ac25 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -733,7 +733,7 @@ static int rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable val &= ~APP_HOLD_PHY_RST; writel(val, rcar->base + PCIERSTCTRL1); - ret = readl_poll_timeout(rcar->phy_base + 0x0f8, val, !(val & BIT(18)), 100, 10000); + ret = readl_poll_timeout(rcar->phy_base + 0x0f8, val, val & BIT(18), 100, 10000); if (ret < 0) return ret; From 26fda92d3b56bf44a02bcb4001c5a5548e0ae8ee Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 22 Sep 2025 17:07:48 +0200 Subject: [PATCH 2121/2711] PCI: tegra: Convert struct tegra_msi mask_lock into raw spinlock The tegra_msi_irq_unmask() function may be called from a PCI driver request_threaded_irq() function. This triggers kernel/irq/manage.c __setup_irq() which locks raw spinlock &desc->lock descriptor lock and with that descriptor lock held, calls tegra_msi_irq_unmask(). Since the &desc->lock descriptor lock is a raw spinlock, and the tegra_msi .mask_lock is not a raw spinlock, this setup triggers 'BUG: Invalid wait context' with CONFIG_PROVE_RAW_LOCK_NESTING=y. Use scoped_guard() to simplify the locking. Fixes: 2c99e55f7955 ("PCI: tegra: Convert to MSI domains") Reported-by: Geert Uytterhoeven Closes: https://patchwork.kernel.org/project/linux-pci/patch/20250909162707.13927-2-marek.vasut+renesas@mailbox.org/#26574451 Signed-off-by: Marek Vasut Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250922150811.88450-1-marek.vasut+renesas@mailbox.org --- drivers/pci/controller/pci-tegra.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index bb88767a3797..942ddfca3bf6 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include @@ -270,7 +271,7 @@ struct tegra_msi { DECLARE_BITMAP(used, INT_PCI_MSI_NR); struct irq_domain *domain; struct mutex map_lock; - spinlock_t mask_lock; + raw_spinlock_t mask_lock; void *virt; dma_addr_t phys; int irq; @@ -1581,14 +1582,13 @@ static void tegra_msi_irq_mask(struct irq_data *d) struct tegra_msi *msi = irq_data_get_irq_chip_data(d); struct tegra_pcie *pcie = msi_to_pcie(msi); unsigned int index = d->hwirq / 32; - unsigned long flags; u32 value; - spin_lock_irqsave(&msi->mask_lock, flags); - value = afi_readl(pcie, AFI_MSI_EN_VEC(index)); - value &= ~BIT(d->hwirq % 32); - afi_writel(pcie, value, AFI_MSI_EN_VEC(index)); - spin_unlock_irqrestore(&msi->mask_lock, flags); + scoped_guard(raw_spinlock_irqsave, &msi->mask_lock) { + value = afi_readl(pcie, AFI_MSI_EN_VEC(index)); + value &= ~BIT(d->hwirq % 32); + afi_writel(pcie, value, AFI_MSI_EN_VEC(index)); + } } static void tegra_msi_irq_unmask(struct irq_data *d) @@ -1596,14 +1596,13 @@ static void tegra_msi_irq_unmask(struct irq_data *d) struct tegra_msi *msi = irq_data_get_irq_chip_data(d); struct tegra_pcie *pcie = msi_to_pcie(msi); unsigned int index = d->hwirq / 32; - unsigned long flags; u32 value; - spin_lock_irqsave(&msi->mask_lock, flags); - value = afi_readl(pcie, AFI_MSI_EN_VEC(index)); - value |= BIT(d->hwirq % 32); - afi_writel(pcie, value, AFI_MSI_EN_VEC(index)); - spin_unlock_irqrestore(&msi->mask_lock, flags); + scoped_guard(raw_spinlock_irqsave, &msi->mask_lock) { + value = afi_readl(pcie, AFI_MSI_EN_VEC(index)); + value |= BIT(d->hwirq % 32); + afi_writel(pcie, value, AFI_MSI_EN_VEC(index)); + } } static void tegra_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) @@ -1711,7 +1710,7 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie) int err; mutex_init(&msi->map_lock); - spin_lock_init(&msi->mask_lock); + raw_spin_lock_init(&msi->mask_lock); if (IS_ENABLED(CONFIG_PCI_MSI)) { err = tegra_allocate_domains(msi); From e1bd928479fb1fa60e9034b0fdb1ab9f3fa92f33 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 22 Sep 2025 13:40:57 +0530 Subject: [PATCH 2122/2711] PCI: tegra194: Rename 'root_bus' to 'root_port_bus' in tegra_pcie_downstream_dev_to_D0() In tegra_pcie_downstream_dev_to_D0(), PCI devices are transitioned to D0 state. For iterating over the devices, first the downstream bus of the Root Port is searched from the root bus. But the name of the variable that holds the Root Port downstream bus is named as 'root_bus', which is wrong. Rename the variable to 'root_port_bus'. Also, move the comment on 'bringing the devices to D0' to where the state is set exactly. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250922081057.15209-1-mani@kernel.org --- drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 0c0734aa14b6..dac069fb1a16 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1270,7 +1270,7 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) { struct dw_pcie_rp *pp = &pcie->pci.pp; - struct pci_bus *child, *root_bus = NULL; + struct pci_bus *child, *root_port_bus = NULL; struct pci_dev *pdev; /* @@ -1283,19 +1283,19 @@ static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) */ list_for_each_entry(child, &pp->bridge->bus->children, node) { - /* Bring downstream devices to D0 if they are not already in */ if (child->parent == pp->bridge->bus) { - root_bus = child; + root_port_bus = child; break; } } - if (!root_bus) { - dev_err(pcie->dev, "Failed to find downstream devices\n"); + if (!root_port_bus) { + dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n"); return; } - list_for_each_entry(pdev, &root_bus->devices, bus_list) { + /* Bring downstream devices to D0 if they are not already in */ + list_for_each_entry(pdev, &root_port_bus->devices, bus_list) { if (PCI_SLOT(pdev->devfn) == 0) { if (pci_set_power_state(pdev, PCI_D0)) dev_err(pcie->dev, From 5ed35b4d490d8735021cce9b715b62a418310864 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 9 Sep 2025 18:26:25 +0200 Subject: [PATCH 2123/2711] PCI: rcar-host: Convert struct rcar_msi mask_lock into raw spinlock The rcar_msi_irq_unmask() function may be called from a PCI driver request_threaded_irq() function. This triggers kernel/irq/manage.c __setup_irq() which locks raw spinlock &desc->lock descriptor lock and with that descriptor lock held, calls rcar_msi_irq_unmask(). Since the &desc->lock descriptor lock is a raw spinlock, and the rcar_msi .mask_lock is not a raw spinlock, this setup triggers 'BUG: Invalid wait context' with CONFIG_PROVE_RAW_LOCK_NESTING=y. Use scoped_guard() to simplify the locking. Fixes: 83ed8d4fa656 ("PCI: rcar: Convert to MSI domains") Reported-by: Duy Nguyen Reported-by: Thuan Nguyen Signed-off-by: Marek Vasut Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Geert Uytterhoeven Acked-by: Marc Zyngier Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250909162707.13927-2-marek.vasut+renesas@mailbox.org --- drivers/pci/controller/pcie-rcar-host.c | 27 ++++++++++++------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c index 625a00f3b223..213028052aa5 100644 --- a/drivers/pci/controller/pcie-rcar-host.c +++ b/drivers/pci/controller/pcie-rcar-host.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -38,7 +39,7 @@ struct rcar_msi { DECLARE_BITMAP(used, INT_PCI_MSI_NR); struct irq_domain *domain; struct mutex map_lock; - spinlock_t mask_lock; + raw_spinlock_t mask_lock; int irq1; int irq2; }; @@ -602,28 +603,26 @@ static void rcar_msi_irq_mask(struct irq_data *d) { struct rcar_msi *msi = irq_data_get_irq_chip_data(d); struct rcar_pcie *pcie = &msi_to_host(msi)->pcie; - unsigned long flags; u32 value; - spin_lock_irqsave(&msi->mask_lock, flags); - value = rcar_pci_read_reg(pcie, PCIEMSIIER); - value &= ~BIT(d->hwirq); - rcar_pci_write_reg(pcie, value, PCIEMSIIER); - spin_unlock_irqrestore(&msi->mask_lock, flags); + scoped_guard(raw_spinlock_irqsave, &msi->mask_lock) { + value = rcar_pci_read_reg(pcie, PCIEMSIIER); + value &= ~BIT(d->hwirq); + rcar_pci_write_reg(pcie, value, PCIEMSIIER); + } } static void rcar_msi_irq_unmask(struct irq_data *d) { struct rcar_msi *msi = irq_data_get_irq_chip_data(d); struct rcar_pcie *pcie = &msi_to_host(msi)->pcie; - unsigned long flags; u32 value; - spin_lock_irqsave(&msi->mask_lock, flags); - value = rcar_pci_read_reg(pcie, PCIEMSIIER); - value |= BIT(d->hwirq); - rcar_pci_write_reg(pcie, value, PCIEMSIIER); - spin_unlock_irqrestore(&msi->mask_lock, flags); + scoped_guard(raw_spinlock_irqsave, &msi->mask_lock) { + value = rcar_pci_read_reg(pcie, PCIEMSIIER); + value |= BIT(d->hwirq); + rcar_pci_write_reg(pcie, value, PCIEMSIIER); + } } static void rcar_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) @@ -736,7 +735,7 @@ static int rcar_pcie_enable_msi(struct rcar_pcie_host *host) int err; mutex_init(&msi->map_lock); - spin_lock_init(&msi->mask_lock); + raw_spin_lock_init(&msi->mask_lock); err = of_address_to_resource(dev->of_node, 0, &res); if (err) From 159c86f306ea20c019b36fc998e2677008183c04 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Aug 2025 09:39:11 +0530 Subject: [PATCH 2124/2711] ACPI: Add support for nargs_prop in acpi_fwnode_get_reference_args() Currently, ACPI does not support the use of a nargs_prop (e.g., associated with a reference in fwnode_property_get_reference_args(). Instead, ACPI expects the number of arguments (nargs) to be explicitly passed or known. This behavior diverges from Open Firmware (OF), which allows the use of a #*-cells property in the referenced node to determine the number of arguments. Since fwnode_property_get_reference_args() is a common interface used across both OF and ACPI firmware paradigms, it is desirable to have a unified calling convention that works seamlessly for both. Add the support for ACPI to parse a nargs_prop from the referenced fwnode, aligning its behavior with the OF backend. This allows drivers and subsystems using fwnode_property_get_reference_args() to work in a firmware-agnostic way without having to hardcode or special-case argument counts for ACPI. Acked-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Signed-off-by: Sunil V L Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-16-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/acpi/property.c | 29 +++++++++++++++++++++++++---- drivers/base/property.c | 2 +- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index d4863746fb11..e92402deee77 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -804,13 +804,35 @@ acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode, return NULL; } +static unsigned int acpi_fwnode_get_args_count(struct fwnode_handle *fwnode, + const char *nargs_prop) +{ + const struct acpi_device_data *data; + const union acpi_object *obj; + int ret; + + data = acpi_device_data_of_node(fwnode); + if (!data) + return 0; + + ret = acpi_data_get_property(data, nargs_prop, ACPI_TYPE_INTEGER, &obj); + if (ret) + return 0; + + return obj->integer.value; +} + static int acpi_get_ref_args(struct fwnode_reference_args *args, struct fwnode_handle *ref_fwnode, + const char *nargs_prop, const union acpi_object **element, const union acpi_object *end, size_t num_args) { u32 nargs = 0, i; + if (nargs_prop) + num_args = acpi_fwnode_get_args_count(ref_fwnode, nargs_prop); + /* * Assume the following integer elements are all args. Stop counting on * the first reference (possibly represented as a string) or end of the @@ -961,10 +983,10 @@ static int acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, return -EINVAL; element++; - ret = acpi_get_ref_args(idx == index ? args : NULL, acpi_fwnode_handle(device), - &element, end, args_count); + nargs_prop, &element, end, + args_count); if (ret < 0) return ret; @@ -979,9 +1001,8 @@ static int acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, return -EINVAL; element++; - ret = acpi_get_ref_args(idx == index ? args : NULL, - ref_fwnode, &element, end, + ref_fwnode, nargs_prop, &element, end, args_count); if (ret < 0) return ret; diff --git a/drivers/base/property.c b/drivers/base/property.c index f626d5bbe806..6a63860579dd 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -578,7 +578,7 @@ EXPORT_SYMBOL_GPL(fwnode_property_match_property_string); * @prop: The name of the property * @nargs_prop: The name of the property telling the number of * arguments in the referred node. NULL if @nargs is known, - * otherwise @nargs is ignored. Only relevant on OF. + * otherwise @nargs is ignored. * @nargs: Number of arguments. Ignored if @nargs_prop is non-NULL. * @index: Index of the reference, from zero onwards. * @args: Result structure with reference and integer arguments. From 4215d1cf59e4b272755f4277a05cd5967935a704 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Aug 2025 09:39:12 +0530 Subject: [PATCH 2125/2711] ACPI: scan: Update honor list for RPMI System MSI The RPMI System MSI interrupt controller (just like PLIC and APLIC) needs to probed prior to devices like GED which use interrupts provided by it. Also, it has dependency on the SBI MPXY mailbox device. Add HIDs of RPMI System MSI and SBI MPXY mailbox devices to the honor list so that those dependencies are handled. Reviewed-by: Atish Patra Reviewed-by: Andy Shevchenko Acked-by: Rafael J. Wysocki Signed-off-by: Sunil V L Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-17-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/acpi/scan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fb1fe9f3b1a3..54181b03b345 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -858,6 +858,8 @@ static const char * const acpi_honor_dep_ids[] = { "INTC10CF", /* IVSC (MTL) driver must be loaded to allow i2c access to camera sensors */ "RSCV0001", /* RISC-V PLIC */ "RSCV0002", /* RISC-V APLIC */ + "RSCV0005", /* RISC-V SBI MPXY MBOX */ + "RSCV0006", /* RISC-V RPMI SYSMSI */ "PNP0C0F", /* PCI Link Device */ NULL }; From 694b2ef1e73c5eea6d7bd112894f465a9c4e42d5 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Aug 2025 09:39:13 +0530 Subject: [PATCH 2126/2711] ACPI: RISC-V: Create interrupt controller list in sorted order Currently, the interrupt controller list is created without any order. Create the list sorted with the GSI base of the interrupt controllers. Signed-off-by: Sunil V L Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-18-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/acpi/riscv/irq.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c index cced960c2aef..33c073e2e71d 100644 --- a/drivers/acpi/riscv/irq.c +++ b/drivers/acpi/riscv/irq.c @@ -115,7 +115,7 @@ struct fwnode_handle *riscv_acpi_get_gsi_domain_id(u32 gsi) static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr_idcs, u32 id, u32 type) { - struct riscv_ext_intc_list *ext_intc_element; + struct riscv_ext_intc_list *ext_intc_element, *node; ext_intc_element = kzalloc(sizeof(*ext_intc_element), GFP_KERNEL); if (!ext_intc_element) @@ -125,7 +125,12 @@ static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr ext_intc_element->nr_irqs = nr_irqs; ext_intc_element->nr_idcs = nr_idcs; ext_intc_element->id = id; - list_add_tail(&ext_intc_element->list, &ext_intc_list); + list_for_each_entry(node, &ext_intc_list, list) { + if (node->gsi_base < ext_intc_element->gsi_base) + break; + } + + list_add_tail(&ext_intc_element->list, &node->list); return 0; } From 4d185fdeef67d0c2c5d4a142392cf1ade3786dd2 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Aug 2025 09:39:14 +0530 Subject: [PATCH 2127/2711] ACPI: RISC-V: Add support to update gsi range Some RISC-V interrupt controllers like RPMI based system MSI interrupt controllers do not have MADT entry defined. These interrupt controllers exist only in the namespace. ACPI spec defines _GSB method to get the GSI base of the interrupt controller, However, there is no such standard method to get the GSI range. To support such interrupt controllers, set the GSI range of such interrupt controllers to non-overlapping range and provide API for interrupt controller driver to update it with proper value. Signed-off-by: Sunil V L Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-19-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/irq.h | 5 +++++ drivers/acpi/riscv/irq.c | 38 ++++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h index 59c975f750c9..7ec592fe430a 100644 --- a/arch/riscv/include/asm/irq.h +++ b/arch/riscv/include/asm/irq.h @@ -42,6 +42,7 @@ unsigned long acpi_rintc_ext_parent_to_hartid(unsigned int plic_id, unsigned int unsigned int acpi_rintc_get_plic_nr_contexts(unsigned int plic_id); unsigned int acpi_rintc_get_plic_context(unsigned int plic_id, unsigned int ctxt_idx); int __init acpi_rintc_get_imsic_mmio_info(u32 index, struct resource *res); +int riscv_acpi_update_gsi_range(u32 gsi_base, u32 nr_irqs); #else static inline int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base, @@ -76,6 +77,10 @@ static inline int __init acpi_rintc_get_imsic_mmio_info(u32 index, struct resour return 0; } +static inline int riscv_acpi_update_gsi_range(u32 gsi_base, u32 nr_irqs) +{ + return -ENODEV; +} #endif /* CONFIG_ACPI */ #endif /* _ASM_RISCV_IRQ_H */ diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c index 33c073e2e71d..cc1928422418 100644 --- a/drivers/acpi/riscv/irq.c +++ b/drivers/acpi/riscv/irq.c @@ -10,6 +10,8 @@ #include "init.h" +#define RISCV_ACPI_INTC_FLAG_PENDING BIT(0) + struct riscv_ext_intc_list { acpi_handle handle; u32 gsi_base; @@ -17,6 +19,7 @@ struct riscv_ext_intc_list { u32 nr_idcs; u32 id; u32 type; + u32 flag; struct list_head list; }; @@ -69,6 +72,22 @@ static acpi_status riscv_acpi_update_gsi_handle(u32 gsi_base, acpi_handle handle return AE_NOT_FOUND; } +int riscv_acpi_update_gsi_range(u32 gsi_base, u32 nr_irqs) +{ + struct riscv_ext_intc_list *ext_intc_element; + + list_for_each_entry(ext_intc_element, &ext_intc_list, list) { + if (gsi_base == ext_intc_element->gsi_base && + (ext_intc_element->flag & RISCV_ACPI_INTC_FLAG_PENDING)) { + ext_intc_element->nr_irqs = nr_irqs; + ext_intc_element->flag &= ~RISCV_ACPI_INTC_FLAG_PENDING; + return 0; + } + } + + return -ENODEV; +} + int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base, u32 *id, u32 *nr_irqs, u32 *nr_idcs) { @@ -115,14 +134,22 @@ struct fwnode_handle *riscv_acpi_get_gsi_domain_id(u32 gsi) static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr_idcs, u32 id, u32 type) { - struct riscv_ext_intc_list *ext_intc_element, *node; + struct riscv_ext_intc_list *ext_intc_element, *node, *prev; ext_intc_element = kzalloc(sizeof(*ext_intc_element), GFP_KERNEL); if (!ext_intc_element) return -ENOMEM; ext_intc_element->gsi_base = gsi_base; - ext_intc_element->nr_irqs = nr_irqs; + + /* If nr_irqs is zero, indicate it in flag and set to max range possible */ + if (nr_irqs) { + ext_intc_element->nr_irqs = nr_irqs; + } else { + ext_intc_element->flag |= RISCV_ACPI_INTC_FLAG_PENDING; + ext_intc_element->nr_irqs = U32_MAX - ext_intc_element->gsi_base; + } + ext_intc_element->nr_idcs = nr_idcs; ext_intc_element->id = id; list_for_each_entry(node, &ext_intc_list, list) { @@ -130,6 +157,13 @@ static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr break; } + /* Adjust the previous node's GSI range if that has pending registration */ + prev = list_prev_entry(node, list); + if (!list_entry_is_head(prev, &ext_intc_list, list)) { + if (prev->flag & RISCV_ACPI_INTC_FLAG_PENDING) + prev->nr_irqs = ext_intc_element->gsi_base - prev->gsi_base; + } + list_add_tail(&ext_intc_element->list, &node->list); return 0; } From bb96fb5a799a128bb478e1ea3dab25a484aadf63 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Aug 2025 09:39:15 +0530 Subject: [PATCH 2128/2711] ACPI: RISC-V: Add RPMI System MSI to GSI mapping The RPMI System MSI device will provide GSIs to downstream devices (such as GED) so add it to the RISC-V GSI to fwnode mapping. Signed-off-by: Sunil V L Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-20-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/irq.h | 1 + drivers/acpi/riscv/irq.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h index 7ec592fe430a..e29ded3416b4 100644 --- a/arch/riscv/include/asm/irq.h +++ b/arch/riscv/include/asm/irq.h @@ -32,6 +32,7 @@ enum riscv_irqchip_type { ACPI_RISCV_IRQCHIP_IMSIC = 0x01, ACPI_RISCV_IRQCHIP_PLIC = 0x02, ACPI_RISCV_IRQCHIP_APLIC = 0x03, + ACPI_RISCV_IRQCHIP_SMSI = 0x04, }; int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base, diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c index cc1928422418..d9a2154d6c6a 100644 --- a/drivers/acpi/riscv/irq.c +++ b/drivers/acpi/riscv/irq.c @@ -168,6 +168,33 @@ static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr return 0; } +static acpi_status __init riscv_acpi_create_gsi_map_smsi(acpi_handle handle, u32 level, + void *context, void **return_value) +{ + acpi_status status; + u64 gbase; + + if (!acpi_has_method(handle, "_GSB")) { + acpi_handle_err(handle, "_GSB method not found\n"); + return AE_ERROR; + } + + status = acpi_evaluate_integer(handle, "_GSB", NULL, &gbase); + if (ACPI_FAILURE(status)) { + acpi_handle_err(handle, "failed to evaluate _GSB method\n"); + return status; + } + + riscv_acpi_register_ext_intc(gbase, 0, 0, 0, ACPI_RISCV_IRQCHIP_SMSI); + status = riscv_acpi_update_gsi_handle((u32)gbase, handle); + if (ACPI_FAILURE(status)) { + acpi_handle_err(handle, "failed to find the GSI mapping entry\n"); + return status; + } + + return AE_OK; +} + static acpi_status __init riscv_acpi_create_gsi_map(acpi_handle handle, u32 level, void *context, void **return_value) { @@ -222,6 +249,9 @@ void __init riscv_acpi_init_gsi_mapping(void) if (acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, riscv_acpi_aplic_parse_madt, 0) > 0) acpi_get_devices("RSCV0002", riscv_acpi_create_gsi_map, NULL, NULL); + + /* Unlike PLIC/APLIC, SYSMSI doesn't have MADT */ + acpi_get_devices("RSCV0006", riscv_acpi_create_gsi_map_smsi, NULL, NULL); } static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi) From 3f5d7a5c05b4d5ac011223359f15fb140125894b Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Aug 2025 09:39:16 +0530 Subject: [PATCH 2129/2711] irqchip/irq-riscv-imsic-early: Export imsic_acpi_get_fwnode() ACPI based loadable drivers which need MSIs will also need imsic_acpi_get_fwnode() to update the device MSI domain so export this function. Reviewed-by: Thomas Gleixner Signed-off-by: Sunil V L Signed-off-by: Anup Patel Link: https://lore.kernel.org/r/20250818040920.272664-21-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/irqchip/irq-riscv-imsic-early.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c index 2709cacf4855..2c4c682627b8 100644 --- a/drivers/irqchip/irq-riscv-imsic-early.c +++ b/drivers/irqchip/irq-riscv-imsic-early.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) "riscv-imsic: " fmt #include #include +#include #include #include #include @@ -233,6 +234,7 @@ struct fwnode_handle *imsic_acpi_get_fwnode(struct device *dev) { return imsic_acpi_fwnode; } +EXPORT_SYMBOL_GPL(imsic_acpi_get_fwnode); static int __init imsic_early_acpi_init(union acpi_subtable_headers *header, const unsigned long end) From 7e64042fdbacc04adce0caf4a0718bf2c4b2045f Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Aug 2025 09:39:17 +0530 Subject: [PATCH 2130/2711] mailbox/riscv-sbi-mpxy: Add ACPI support Add ACPI support for the RISC-V SBI message proxy (MPXY) based mailbox driver. Acked-by: Jassi Brar Signed-off-by: Sunil V L Signed-off-by: Anup Patel Link: https://lore.kernel.org/r/20250818040920.272664-22-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/mailbox/riscv-sbi-mpxy-mbox.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/mailbox/riscv-sbi-mpxy-mbox.c b/drivers/mailbox/riscv-sbi-mpxy-mbox.c index 21404baa6df0..7c9c006b7244 100644 --- a/drivers/mailbox/riscv-sbi-mpxy-mbox.c +++ b/drivers/mailbox/riscv-sbi-mpxy-mbox.c @@ -5,9 +5,11 @@ * Copyright (C) 2025 Ventana Micro Systems Inc. */ +#include #include #include #include +#include #include #include #include @@ -906,6 +908,8 @@ static int mpxy_mbox_probe(struct platform_device *pdev) * explicitly configure here. */ if (!dev_get_msi_domain(dev)) { + struct fwnode_handle *fwnode = dev_fwnode(dev); + /* * The device MSI domain for OF devices is only set at the * time of populating/creating OF device. If the device MSI @@ -913,8 +917,15 @@ static int mpxy_mbox_probe(struct platform_device *pdev) * then we need to set it explicitly before using any platform * MSI functions. */ - if (dev_of_node(dev)) + if (is_of_node(fwnode)) { of_msi_configure(dev, dev_of_node(dev)); + } else if (is_acpi_device_node(fwnode)) { + struct irq_domain *msi_domain; + + msi_domain = irq_find_matching_fwnode(imsic_acpi_get_fwnode(dev), + DOMAIN_BUS_PLATFORM_MSI); + dev_set_msi_domain(dev, msi_domain); + } if (!dev_get_msi_domain(dev)) return -EPROBE_DEFER; @@ -960,6 +971,13 @@ static int mpxy_mbox_probe(struct platform_device *pdev) return rc; } +#ifdef CONFIG_ACPI + struct acpi_device *adev = ACPI_COMPANION(dev); + + if (adev) + acpi_dev_clear_dependencies(adev); +#endif + dev_info(dev, "mailbox registered with %d channels\n", mbox->channel_count); return 0; @@ -979,10 +997,17 @@ static const struct of_device_id mpxy_mbox_of_match[] = { }; MODULE_DEVICE_TABLE(of, mpxy_mbox_of_match); +static const struct acpi_device_id mpxy_mbox_acpi_match[] = { + { "RSCV0005" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, mpxy_mbox_acpi_match); + static struct platform_driver mpxy_mbox_driver = { .driver = { .name = "riscv-sbi-mpxy-mbox", .of_match_table = mpxy_mbox_of_match, + .acpi_match_table = mpxy_mbox_acpi_match, }, .probe = mpxy_mbox_probe, .remove = mpxy_mbox_remove, From 4752b0cfbc37a4e62e583bd8723b1fc2fe8df319 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Aug 2025 09:39:18 +0530 Subject: [PATCH 2131/2711] irqchip/riscv-rpmi-sysmsi: Add ACPI support Add ACPI support for the RISC-V RPMI system MSI based irqchip driver. Reviewed-by: Thomas Gleixner Signed-off-by: Sunil V L Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-23-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- drivers/irqchip/Kconfig | 2 +- drivers/irqchip/irq-riscv-rpmi-sysmsi.c | 47 +++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index e047ba36df16..a61c6dc63c29 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -636,7 +636,7 @@ config RISCV_IMSIC config RISCV_RPMI_SYSMSI bool - depends on MAILBOX + depends on RISCV && MAILBOX select IRQ_DOMAIN_HIERARCHY select GENERIC_MSI_IRQ default RISCV diff --git a/drivers/irqchip/irq-riscv-rpmi-sysmsi.c b/drivers/irqchip/irq-riscv-rpmi-sysmsi.c index 92e8847dfccc..5c74c561ce31 100644 --- a/drivers/irqchip/irq-riscv-rpmi-sysmsi.c +++ b/drivers/irqchip/irq-riscv-rpmi-sysmsi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2025 Ventana Micro Systems Inc. */ +#include #include #include #include @@ -9,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -209,6 +211,8 @@ static int rpmi_sysmsi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rpmi_sysmsi_priv *priv; + struct fwnode_handle *fwnode; + u32 id; int rc; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -239,6 +243,22 @@ static int rpmi_sysmsi_probe(struct platform_device *pdev) } priv->nr_irqs = rc; + fwnode = dev_fwnode(dev); + if (is_acpi_node(fwnode)) { + u32 nr_irqs; + + rc = riscv_acpi_get_gsi_info(fwnode, &priv->gsi_base, &id, + &nr_irqs, NULL); + if (rc) { + dev_err(dev, "failed to find GSI mapping\n"); + return rc; + } + + /* Update with actual GSI range */ + if (nr_irqs != priv->nr_irqs) + riscv_acpi_update_gsi_range(priv->gsi_base, priv->nr_irqs); + } + /* * The device MSI domain for platform devices on RISC-V architecture * is only available after the MSI controller driver is probed so, @@ -252,8 +272,15 @@ static int rpmi_sysmsi_probe(struct platform_device *pdev) * then we need to set it explicitly before using any platform * MSI functions. */ - if (dev_of_node(dev)) + if (is_of_node(fwnode)) { of_msi_configure(dev, dev_of_node(dev)); + } else if (is_acpi_device_node(fwnode)) { + struct irq_domain *msi_domain; + + msi_domain = irq_find_matching_fwnode(imsic_acpi_get_fwnode(dev), + DOMAIN_BUS_PLATFORM_MSI); + dev_set_msi_domain(dev, msi_domain); + } if (!dev_get_msi_domain(dev)) { mbox_free_channel(priv->chan); @@ -268,6 +295,13 @@ static int rpmi_sysmsi_probe(struct platform_device *pdev) return dev_err_probe(dev, -ENOMEM, "failed to create MSI irq domain\n"); } +#ifdef CONFIG_ACPI + struct acpi_device *adev = ACPI_COMPANION(dev); + + if (adev) + acpi_dev_clear_dependencies(adev); +#endif + dev_info(dev, "%u system MSIs registered\n", priv->nr_irqs); return 0; } @@ -277,10 +311,17 @@ static const struct of_device_id rpmi_sysmsi_match[] = { {} }; +static const struct acpi_device_id acpi_rpmi_sysmsi_match[] = { + { "RSCV0006" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, acpi_rpmi_sysmsi_match); + static struct platform_driver rpmi_sysmsi_driver = { .driver = { - .name = "rpmi-sysmsi", - .of_match_table = rpmi_sysmsi_match, + .name = "rpmi-sysmsi", + .of_match_table = rpmi_sysmsi_match, + .acpi_match_table = acpi_rpmi_sysmsi_match, }, .probe = rpmi_sysmsi_probe, }; From f30d7ccd13f01aa6224a2de62562f63c7a298a7e Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:19 +0530 Subject: [PATCH 2132/2711] RISC-V: Enable GPIO keyboard and event device in RV64 defconfig The GPIO keyboard and event device can be used to receive graceful shutdown or reboot input keys so let us enable it by default for RV64 (just like ARM64). Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-24-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- arch/riscv/configs/defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index 7b5eed17611a..021baecb253a 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig @@ -139,6 +139,8 @@ CONFIG_MICREL_PHY=y CONFIG_MICROSEMI_PHY=y CONFIG_MOTORCOMM_PHY=y CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y CONFIG_KEYBOARD_SUN4I_LRADC=m CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y From 67b876663ecee3a74be3bb1ad358d309fcaec6b1 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 18 Aug 2025 09:39:20 +0530 Subject: [PATCH 2133/2711] MAINTAINERS: Add entry for RISC-V RPMI and MPXY drivers Add Rahul and myself as maintainers for RISC-V RPMI and MPXY drivers. Signed-off-by: Anup Patel Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20250818040920.272664-25-apatel@ventanamicro.com Signed-off-by: Paul Walmsley --- MAINTAINERS | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa4..858de646632a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21700,6 +21700,21 @@ F: drivers/perf/riscv_pmu.c F: drivers/perf/riscv_pmu_legacy.c F: drivers/perf/riscv_pmu_sbi.c +RISC-V RPMI AND MPXY DRIVERS +M: Rahul Pathak +M: Anup Patel +L: linux-riscv@lists.infradead.org +F: Documentation/devicetree/bindings/clock/riscv,rpmi-clock.yaml +F: Documentation/devicetree/bindings/clock/riscv,rpmi-mpxy-clock.yaml +F: Documentation/devicetree/bindings/interrupt-controller/riscv,rpmi-mpxy-system-msi.yaml +F: Documentation/devicetree/bindings/interrupt-controller/riscv,rpmi-system-msi.yaml +F: Documentation/devicetree/bindings/mailbox/riscv,rpmi-shmem-mbox.yaml +F: Documentation/devicetree/bindings/mailbox/riscv,sbi-mpxy-mbox.yaml +F: drivers/clk/clk-rpmi.c +F: drivers/irqchip/irq-riscv-rpmi-sysmsi.c +F: drivers/mailbox/riscv-sbi-mpxy-mbox.c +F: include/linux/mailbox/riscv-rpmi-message.h + RISC-V SPACEMIT SoC Support M: Yixun Lan L: linux-riscv@lists.infradead.org From 21c3896b471aafe906f35e8d5a2dbf713754079e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 29 Jul 2025 15:15:35 +0200 Subject: [PATCH 2134/2711] ACPI: support BGRT table on RISC-V The BGRT table is used to display a vendor logo in the boot process. There is no good reason why RISC-V should not support it. Remove the architecture constraint. Signed-off-by: Heinrich Schuchardt Acked-by: Rafael J. Wysocki Reviewed-by: Sunil V L Link: https://lore.kernel.org/r/20250729131535.522205-3-heinrich.schuchardt@canonical.com Signed-off-by: Paul Walmsley --- drivers/acpi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index b594780a57d7..1e448e9c51f2 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -461,7 +461,7 @@ config ACPI_HED config ACPI_BGRT bool "Boottime Graphics Resource Table support" - depends on EFI && (X86 || ARM64 || LOONGARCH) + depends on EFI help This driver adds support for exposing the ACPI Boottime Graphics Resource Table, which allows the operating system to obtain From f12140f21acba1499e55cc0220d7c1fe518de369 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Thu, 25 Sep 2025 20:59:26 +0200 Subject: [PATCH 2135/2711] rust: usb: don't retain device context for the interface parent When deriving the parent USB device (struct usb_device) from a USB interface (struct usb_interface), do not retain the device context. For the Bound context, as pointed out by Alan in [1], it is not guaranteed that the parent USB device is always bound when the interface is bound. The bigger problem, however, is that we can't infer the Core context, since eventually it indicates that the device lock is held. However, there is no guarantee that if the device lock of the interface is held, also the device lock of the parent USB device is held. Hence, fix this by not inferring any device context information; while at it, fix up the (affected) safety comments. Link: https://lore.kernel.org/all/0ff2a825-1115-426a-a6f9-df544cd0c5fc@rowland.harvard.edu/ [1] Fixes: e7e2296b0ecf ("rust: usb: add basic USB abstractions") Signed-off-by: Danilo Krummrich Link: https://lore.kernel.org/r/20250925190400.144699-1-dakr@kernel.org Signed-off-by: Greg Kroah-Hartman --- rust/kernel/usb.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 8899e7520b58..955fd93b6f52 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -340,14 +340,13 @@ impl AsRef> for Interface { } } -impl AsRef> for Interface { - fn as_ref(&self) -> &Device { - // SAFETY: `self.as_raw()` is valid by the type invariants. For a valid interface, - // the helper should always return a valid USB device pointer. +impl AsRef for Interface { + fn as_ref(&self) -> &Device { + // SAFETY: `self.as_raw()` is valid by the type invariants. let usb_dev = unsafe { bindings::interface_to_usbdev(self.as_raw()) }; - // SAFETY: The helper returns a valid interface pointer that shares the - // same `DeviceContext`. + // SAFETY: For a valid `struct usb_interface` pointer, the above call to + // `interface_to_usbdev()` guarantees to return a valid pointer to a `struct usb_device`. unsafe { &*(usb_dev.cast()) } } } From 22d693e45d4a4513bd99489a4e50b81cc0175b21 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Thu, 25 Sep 2025 20:59:27 +0200 Subject: [PATCH 2136/2711] rust: usb: keep usb::Device private for now The USB abstractions target to support USB interface drivers. While internally the abstraction has to deal with the interface's parent USB device, there shouldn't be a need for users to deal with the parent USB device directly. Functions, such as for preparing and sending USB URBs, can be implemented for the usb::Interface structure directly. Whether this internal implementation has to deal with the parent USB device can remain transparent to USB interface drivers. Hence, keep the usb::Device structure private for now, in order to avoid confusion for users and to make it less likely to accidentally expose APIs with unnecessary indirections. Should we start supporting USB device drivers, or need it for any other reason we do not foresee yet, it should be trivial to make it public again. Signed-off-by: Danilo Krummrich Link: https://lore.kernel.org/r/20250925190400.144699-2-dakr@kernel.org Signed-off-by: Greg Kroah-Hartman --- rust/kernel/usb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 955fd93b6f52..14ddb711bab3 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -386,7 +386,7 @@ unsafe impl Sync for Interface {} /// /// [`struct usb_device`]: https://www.kernel.org/doc/html/latest/driver-api/usb/usb.html#c.usb_device #[repr(transparent)] -pub struct Device( +struct Device( Opaque, PhantomData, ); From dff4f9ff5d7f289e4545cc936362e01ed3252742 Mon Sep 17 00:00:00 2001 From: Anderson Nascimento Date: Mon, 8 Sep 2025 09:49:02 -0300 Subject: [PATCH 2137/2711] btrfs: avoid potential out-of-bounds in btrfs_encode_fh() The function btrfs_encode_fh() does not properly account for the three cases it handles. Before writing to the file handle (fh), the function only returns to the user BTRFS_FID_SIZE_NON_CONNECTABLE (5 dwords, 20 bytes) or BTRFS_FID_SIZE_CONNECTABLE (8 dwords, 32 bytes). However, when a parent exists and the root ID of the parent and the inode are different, the function writes BTRFS_FID_SIZE_CONNECTABLE_ROOT (10 dwords, 40 bytes). If *max_len is not large enough, this write goes out of bounds because BTRFS_FID_SIZE_CONNECTABLE_ROOT is greater than BTRFS_FID_SIZE_CONNECTABLE originally returned. This results in an 8-byte out-of-bounds write at fid->parent_root_objectid = parent_root_id. A previous attempt to fix this issue was made but was lost. https://lore.kernel.org/all/4CADAEEC020000780001B32C@vpn.id2.novell.com/ Although this issue does not seem to be easily triggerable, it is a potential memory corruption bug that should be fixed. This patch resolves the issue by ensuring the function returns the appropriate size for all three cases and validates that *max_len is large enough before writing any data. Fixes: be6e8dc0ba84 ("NFS support for btrfs - v3") CC: stable@vger.kernel.org # 3.0+ Signed-off-by: Anderson Nascimento Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/export.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c index d062ac521051..230d9326b685 100644 --- a/fs/btrfs/export.c +++ b/fs/btrfs/export.c @@ -23,7 +23,11 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, int type; if (parent && (len < BTRFS_FID_SIZE_CONNECTABLE)) { - *max_len = BTRFS_FID_SIZE_CONNECTABLE; + if (btrfs_root_id(BTRFS_I(inode)->root) != + btrfs_root_id(BTRFS_I(parent)->root)) + *max_len = BTRFS_FID_SIZE_CONNECTABLE_ROOT; + else + *max_len = BTRFS_FID_SIZE_CONNECTABLE; return FILEID_INVALID; } else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) { *max_len = BTRFS_FID_SIZE_NON_CONNECTABLE; @@ -45,6 +49,8 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, parent_root_id = btrfs_root_id(BTRFS_I(parent)->root); if (parent_root_id != fid->root_objectid) { + if (*max_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT) + return FILEID_INVALID; fid->parent_root_objectid = parent_root_id; len = BTRFS_FID_SIZE_CONNECTABLE_ROOT; type = FILEID_BTRFS_WITH_PARENT_ROOT; From 60b7ab6ce030939d86c26f591967fbe7938b05da Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 18 Sep 2025 23:20:27 +0200 Subject: [PATCH 2138/2711] platform: arm64: thinkpad-t14s-ec: new driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce EC driver for the ThinkPad T14s Gen6 Snapdragon, which is in theory compatible with ThinkPad ACPI. On Linux the system is booted with device tree, which is not supported by the ThinkPad ACPI driver (drivers/platform/x86/lenovo/thinkpad_acpi.c). Also most of the hardware compatibility is handled via ACPI tables, which are obviously not used when booting via device tree. Thus adding DT compatibility to the existing driver is not worth it as there is almost no code sharing. The driver currently exposes features, which are not available via other means: * Extra Keys * System LEDs * Keyboard Backlight Control The driver has been developed by reading the ACPI DSDT. There are some more features around thermal control, which are not yet supported by the driver. The speaker mute and mic mute LEDs need some additional changes in the ALSA UCM to be set automatically. Tested-by: Neil Armstrong # on Thinkpad T14S OLED Reviewed-by: Bryan O'Donoghue Signed-off-by: Sebastian Reichel Link: https://patch.msgid.link/20250918-thinkpad-t14s-ec-v5-2-ac0bc6382c5c@collabora.com [ij: folded in patch from Chen Ni ] Link: https://patch.msgid.link/20250926091302.817919-1-nichen@iscas.ac.cn [ij: folded in patch from Lukas Bulwahn ] Link: https://patch.msgid.link/20250926071859.138396-1-lukas.bulwahn@redhat.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- MAINTAINERS | 6 + drivers/platform/arm64/Kconfig | 20 + drivers/platform/arm64/Makefile | 1 + drivers/platform/arm64/lenovo-thinkpad-t14s.c | 616 ++++++++++++++++++ 4 files changed, 643 insertions(+) create mode 100644 drivers/platform/arm64/lenovo-thinkpad-t14s.c diff --git a/MAINTAINERS b/MAINTAINERS index df1bb6be63f9..48b6b60fd56d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25071,6 +25071,12 @@ W: http://thinkwiki.org/wiki/Ibm-acpi T: git git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git F: drivers/platform/x86/lenovo/thinkpad_acpi.c +THINKPAD T14S EMBEDDED CONTROLLER DRIVER +M: Sebastian Reichel +S: Maintained +F: Documentation/devicetree/bindings/embedded-controller/lenovo,thinkpad-t14s-ec.yaml +F: drivers/platform/arm64/lenovo-thinkpad-t14s.c + THINKPAD LMI DRIVER M: Mark Pearson L: platform-driver-x86@vger.kernel.org diff --git a/drivers/platform/arm64/Kconfig b/drivers/platform/arm64/Kconfig index 06288aebc559..10f905d7d6bf 100644 --- a/drivers/platform/arm64/Kconfig +++ b/drivers/platform/arm64/Kconfig @@ -70,4 +70,24 @@ config EC_LENOVO_YOGA_C630 Say M or Y here to include this support. +config EC_LENOVO_THINKPAD_T14S + tristate "Lenovo Thinkpad T14s Embedded Controller driver" + depends on ARCH_QCOM || COMPILE_TEST + depends on I2C + depends on INPUT + select INPUT_SPARSEKMAP + select LEDS_CLASS + select NEW_LEDS + select SND_CTL_LED if SND + help + Driver for the Embedded Controller in the Qualcomm Snapdragon-based + Lenovo Thinkpad T14s, which provides access to keyboard backlight + and status LEDs. + + This driver provides support for the mentioned laptop where this + information is not properly exposed via the standard Qualcomm + devices. + + Say M or Y here to include this support. + endif # ARM64_PLATFORM_DEVICES diff --git a/drivers/platform/arm64/Makefile b/drivers/platform/arm64/Makefile index 46a99eba3264..60c131cff6a1 100644 --- a/drivers/platform/arm64/Makefile +++ b/drivers/platform/arm64/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_EC_ACER_ASPIRE1) += acer-aspire1-ec.o obj-$(CONFIG_EC_HUAWEI_GAOKUN) += huawei-gaokun-ec.o obj-$(CONFIG_EC_LENOVO_YOGA_C630) += lenovo-yoga-c630.o +obj-$(CONFIG_EC_LENOVO_THINKPAD_T14S) += lenovo-thinkpad-t14s.o diff --git a/drivers/platform/arm64/lenovo-thinkpad-t14s.c b/drivers/platform/arm64/lenovo-thinkpad-t14s.c new file mode 100644 index 000000000000..1d5d11adaf32 --- /dev/null +++ b/drivers/platform/arm64/lenovo-thinkpad-t14s.c @@ -0,0 +1,616 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Sebastian Reichel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define T14S_EC_CMD_ECRD 0x02 +#define T14S_EC_CMD_ECWR 0x03 +#define T14S_EC_CMD_EVT 0xf0 + +#define T14S_EC_REG_LED 0x0c +#define T14S_EC_REG_KBD_BL1 0x0d +#define T14S_EC_REG_KBD_BL2 0xe1 +#define T14S_EC_KBD_BL1_MASK GENMASK_U8(7, 6) +#define T14S_EC_KBD_BL2_MASK GENMASK_U8(3, 2) +#define T14S_EC_REG_AUD 0x30 +#define T14S_EC_MIC_MUTE_LED BIT(5) +#define T14S_EC_SPK_MUTE_LED BIT(6) + +#define T14S_EC_EVT_NONE 0x00 +#define T14S_EC_EVT_KEY_FN_4 0x13 +#define T14S_EC_EVT_KEY_FN_F7 0x16 +#define T14S_EC_EVT_KEY_FN_SPACE 0x1f +#define T14S_EC_EVT_KEY_TP_DOUBLE_TAP 0x20 +#define T14S_EC_EVT_AC_CONNECTED 0x26 +#define T14S_EC_EVT_AC_DISCONNECTED 0x27 +#define T14S_EC_EVT_KEY_POWER 0x28 +#define T14S_EC_EVT_LID_OPEN 0x2a +#define T14S_EC_EVT_LID_CLOSED 0x2b +#define T14S_EC_EVT_THERMAL_TZ40 0x5c +#define T14S_EC_EVT_THERMAL_TZ42 0x5d +#define T14S_EC_EVT_THERMAL_TZ39 0x5e +#define T14S_EC_EVT_KEY_FN_F12 0x62 +#define T14S_EC_EVT_KEY_FN_TAB 0x63 +#define T14S_EC_EVT_KEY_FN_F8 0x64 +#define T14S_EC_EVT_KEY_FN_F10 0x65 +#define T14S_EC_EVT_KEY_FN_F4 0x6a +#define T14S_EC_EVT_KEY_FN_D 0x6b +#define T14S_EC_EVT_KEY_FN_T 0x6c +#define T14S_EC_EVT_KEY_FN_H 0x6d +#define T14S_EC_EVT_KEY_FN_M 0x6e +#define T14S_EC_EVT_KEY_FN_L 0x6f +#define T14S_EC_EVT_KEY_FN_RIGHT_SHIFT 0x71 +#define T14S_EC_EVT_KEY_FN_ESC 0x74 +#define T14S_EC_EVT_KEY_FN_N 0x79 +#define T14S_EC_EVT_KEY_FN_F11 0x7a +#define T14S_EC_EVT_KEY_FN_G 0x7e + +/* Hardware LED blink rate is 1 Hz (500ms off, 500ms on) */ +#define T14S_EC_BLINK_RATE_ON_OFF_MS 500 + +/* + * Add a virtual offset on all key event codes for sparse keymap handling, + * since the sparse keymap infrastructure does not map some raw key event + * codes used by the EC. For example 0x16 (T14S_EC_EVT_KEY_FN_F7) is mapped + * to KEY_MUTE if no offset is applied. + */ +#define T14S_EC_KEY_EVT_OFFSET 0x1000 +#define T14S_EC_KEY_ENTRY(key, value) \ + { KE_KEY, T14S_EC_KEY_EVT_OFFSET + T14S_EC_EVT_KEY_##key, { value } } + +enum t14s_ec_led_status_t { + T14S_EC_LED_OFF = 0x00, + T14S_EC_LED_ON = 0x80, + T14S_EC_LED_BLINK = 0xc0, +}; + +struct t14s_ec_led_classdev { + struct led_classdev led_classdev; + int led; + enum t14s_ec_led_status_t cache; + struct t14s_ec *ec; +}; + +struct t14s_ec { + struct regmap *regmap; + struct device *dev; + struct t14s_ec_led_classdev led_pwr_btn; + struct t14s_ec_led_classdev led_chrg_orange; + struct t14s_ec_led_classdev led_chrg_white; + struct t14s_ec_led_classdev led_lid_logo_dot; + struct led_classdev kbd_backlight; + struct led_classdev led_mic_mute; + struct led_classdev led_spk_mute; + struct input_dev *inputdev; +}; + +static const struct regmap_config t14s_ec_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, +}; + +static int t14s_ec_write(void *context, unsigned int reg, + unsigned int val) +{ + struct t14s_ec *ec = context; + struct i2c_client *client = to_i2c_client(ec->dev); + u8 buf[5] = {T14S_EC_CMD_ECWR, reg, 0x00, 0x01, val}; + int ret; + + ret = i2c_master_send(client, buf, sizeof(buf)); + if (ret < 0) + return ret; + + return 0; +} + +static int t14s_ec_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct t14s_ec *ec = context; + struct i2c_client *client = to_i2c_client(ec->dev); + u8 buf[4] = {T14S_EC_CMD_ECRD, reg, 0x00, 0x01}; + struct i2c_msg request, response; + u8 result; + int ret; + + request.addr = client->addr; + request.flags = I2C_M_STOP; + request.len = sizeof(buf); + request.buf = buf; + response.addr = client->addr; + response.flags = I2C_M_RD; + response.len = 1; + response.buf = &result; + + i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); + + ret = __i2c_transfer(client->adapter, &request, 1); + if (ret < 0) + goto out; + + ret = __i2c_transfer(client->adapter, &response, 1); + if (ret < 0) + goto out; + + *val = result; + ret = 0; + +out: + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); + return ret; +} + +static const struct regmap_bus t14s_ec_regmap_bus = { + .reg_write = t14s_ec_write, + .reg_read = t14s_ec_read, +}; + +static int t14s_ec_read_evt(struct t14s_ec *ec, u8 *val) +{ + struct i2c_client *client = to_i2c_client(ec->dev); + u8 buf[4] = {T14S_EC_CMD_EVT, 0x00, 0x00, 0x01}; + struct i2c_msg request, response; + int ret; + + request.addr = client->addr; + request.flags = I2C_M_STOP; + request.len = sizeof(buf); + request.buf = buf; + response.addr = client->addr; + response.flags = I2C_M_RD; + response.len = 1; + response.buf = val; + + i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); + + ret = __i2c_transfer(client->adapter, &request, 1); + if (ret < 0) + goto out; + + ret = __i2c_transfer(client->adapter, &response, 1); + if (ret < 0) + goto out; + + ret = 0; + +out: + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); + return ret; +} + +static int t14s_led_set_status(struct t14s_ec *ec, + struct t14s_ec_led_classdev *led, + const enum t14s_ec_led_status_t ledstatus) +{ + int ret; + + ret = regmap_write(ec->regmap, T14S_EC_REG_LED, + led->led | ledstatus); + if (ret < 0) + return ret; + + led->cache = ledstatus; + return 0; +} + +static int t14s_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct t14s_ec_led_classdev *led = container_of(led_cdev, + struct t14s_ec_led_classdev, led_classdev); + enum t14s_ec_led_status_t new_state; + + if (brightness == LED_OFF) + new_state = T14S_EC_LED_OFF; + else if (led->cache == T14S_EC_LED_BLINK) + new_state = T14S_EC_LED_BLINK; + else + new_state = T14S_EC_LED_ON; + + return t14s_led_set_status(led->ec, led, new_state); +} + +static int t14s_led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct t14s_ec_led_classdev *led = container_of(led_cdev, + struct t14s_ec_led_classdev, led_classdev); + + if (*delay_on == 0 && *delay_off == 0) { + /* Userspace does not provide a blink rate; we can choose it */ + *delay_on = T14S_EC_BLINK_RATE_ON_OFF_MS; + *delay_off = T14S_EC_BLINK_RATE_ON_OFF_MS; + } else if ((*delay_on != T14S_EC_BLINK_RATE_ON_OFF_MS) || + (*delay_off != T14S_EC_BLINK_RATE_ON_OFF_MS)) + return -EINVAL; + + return t14s_led_set_status(led->ec, led, T14S_EC_LED_BLINK); +} + +static int t14s_init_led(struct t14s_ec *ec, struct t14s_ec_led_classdev *led, + u8 id, const char *name) +{ + led->led_classdev.name = name; + led->led_classdev.flags = LED_RETAIN_AT_SHUTDOWN; + led->led_classdev.max_brightness = 1; + led->led_classdev.brightness_set_blocking = t14s_led_brightness_set; + led->led_classdev.blink_set = t14s_led_blink_set; + led->ec = ec; + led->led = id; + + return devm_led_classdev_register(ec->dev, &led->led_classdev); +} + +static int t14s_leds_probe(struct t14s_ec *ec) +{ + int ret; + + ret = t14s_init_led(ec, &ec->led_pwr_btn, 0, "platform::power"); + if (ret) + return ret; + + ret = t14s_init_led(ec, &ec->led_chrg_orange, 1, + "platform:amber:battery-charging"); + if (ret) + return ret; + + ret = t14s_init_led(ec, &ec->led_chrg_white, 2, + "platform:white:battery-full"); + if (ret) + return ret; + + ret = t14s_init_led(ec, &ec->led_lid_logo_dot, 10, + "platform::lid_logo_dot"); + if (ret) + return ret; + + return 0; +} + +static int t14s_kbd_bl_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec, + kbd_backlight); + int ret; + u8 val; + + val = FIELD_PREP(T14S_EC_KBD_BL1_MASK, brightness); + ret = regmap_update_bits(ec->regmap, T14S_EC_REG_KBD_BL1, + T14S_EC_KBD_BL1_MASK, val); + if (ret < 0) + return ret; + + val = FIELD_PREP(T14S_EC_KBD_BL2_MASK, brightness); + ret = regmap_update_bits(ec->regmap, T14S_EC_REG_KBD_BL2, + T14S_EC_KBD_BL2_MASK, val); + if (ret < 0) + return ret; + + return 0; +} + +static enum led_brightness t14s_kbd_bl_get(struct led_classdev *led_cdev) +{ + struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec, + kbd_backlight); + unsigned int val; + int ret; + + ret = regmap_read(ec->regmap, T14S_EC_REG_KBD_BL1, &val); + if (ret < 0) + return ret; + + return FIELD_GET(T14S_EC_KBD_BL1_MASK, val); +} + +static void t14s_kbd_bl_update(struct t14s_ec *ec) +{ + enum led_brightness brightness = t14s_kbd_bl_get(&ec->kbd_backlight); + + led_classdev_notify_brightness_hw_changed(&ec->kbd_backlight, brightness); +} + +static int t14s_kbd_backlight_probe(struct t14s_ec *ec) +{ + ec->kbd_backlight.name = "platform::kbd_backlight"; + ec->kbd_backlight.flags = LED_BRIGHT_HW_CHANGED; + ec->kbd_backlight.max_brightness = 2; + ec->kbd_backlight.brightness_set_blocking = t14s_kbd_bl_set; + ec->kbd_backlight.brightness_get = t14s_kbd_bl_get; + + return devm_led_classdev_register(ec->dev, &ec->kbd_backlight); +} + +static enum led_brightness t14s_audio_led_get(struct t14s_ec *ec, u8 led_bit) +{ + unsigned int val; + int ret; + + ret = regmap_read(ec->regmap, T14S_EC_REG_AUD, &val); + if (ret < 0) + return ret; + + return !!(val & led_bit) ? LED_ON : LED_OFF; +} + +static enum led_brightness t14s_audio_led_set(struct t14s_ec *ec, + u8 led_mask, + enum led_brightness brightness) +{ + return regmap_assign_bits(ec->regmap, T14S_EC_REG_AUD, led_mask, brightness > 0); +} + +static enum led_brightness t14s_mic_mute_led_get(struct led_classdev *led_cdev) +{ + struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec, + led_mic_mute); + + return t14s_audio_led_get(ec, T14S_EC_MIC_MUTE_LED); +} + +static int t14s_mic_mute_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec, + led_mic_mute); + + return t14s_audio_led_set(ec, T14S_EC_MIC_MUTE_LED, brightness); +} + +static enum led_brightness t14s_spk_mute_led_get(struct led_classdev *led_cdev) +{ + struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec, + led_spk_mute); + + return t14s_audio_led_get(ec, T14S_EC_SPK_MUTE_LED); +} + +static int t14s_spk_mute_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec, + led_spk_mute); + + return t14s_audio_led_set(ec, T14S_EC_SPK_MUTE_LED, brightness); +} + +static int t14s_kbd_audio_led_probe(struct t14s_ec *ec) +{ + int ret; + + ec->led_mic_mute.name = "platform::micmute"; + ec->led_mic_mute.max_brightness = 1; + ec->led_mic_mute.default_trigger = "audio-micmute"; + ec->led_mic_mute.brightness_set_blocking = t14s_mic_mute_led_set; + ec->led_mic_mute.brightness_get = t14s_mic_mute_led_get; + + ec->led_spk_mute.name = "platform::mute"; + ec->led_spk_mute.max_brightness = 1; + ec->led_spk_mute.default_trigger = "audio-mute"; + ec->led_spk_mute.brightness_set_blocking = t14s_spk_mute_led_set; + ec->led_spk_mute.brightness_get = t14s_spk_mute_led_get; + + ret = devm_led_classdev_register(ec->dev, &ec->led_mic_mute); + if (ret) + return ret; + + return devm_led_classdev_register(ec->dev, &ec->led_spk_mute); +} + +static const struct key_entry t14s_keymap[] = { + T14S_EC_KEY_ENTRY(FN_4, KEY_SLEEP), + T14S_EC_KEY_ENTRY(FN_N, KEY_VENDOR), + T14S_EC_KEY_ENTRY(FN_F4, KEY_MICMUTE), + T14S_EC_KEY_ENTRY(FN_F7, KEY_SWITCHVIDEOMODE), + T14S_EC_KEY_ENTRY(FN_F8, KEY_PERFORMANCE), + T14S_EC_KEY_ENTRY(FN_F10, KEY_SELECTIVE_SCREENSHOT), + T14S_EC_KEY_ENTRY(FN_F11, KEY_LINK_PHONE), + T14S_EC_KEY_ENTRY(FN_F12, KEY_BOOKMARKS), + T14S_EC_KEY_ENTRY(FN_SPACE, KEY_KBDILLUMTOGGLE), + T14S_EC_KEY_ENTRY(FN_ESC, KEY_FN_ESC), + T14S_EC_KEY_ENTRY(FN_TAB, KEY_ZOOM), + T14S_EC_KEY_ENTRY(FN_RIGHT_SHIFT, KEY_FN_RIGHT_SHIFT), + T14S_EC_KEY_ENTRY(TP_DOUBLE_TAP, KEY_PROG4), + { KE_END } +}; + +static int t14s_input_probe(struct t14s_ec *ec) +{ + int ret; + + ec->inputdev = devm_input_allocate_device(ec->dev); + if (!ec->inputdev) + return -ENOMEM; + + ec->inputdev->name = "ThinkPad Extra Buttons"; + ec->inputdev->phys = "thinkpad/input0"; + ec->inputdev->id.bustype = BUS_HOST; + ec->inputdev->dev.parent = ec->dev; + + ret = sparse_keymap_setup(ec->inputdev, t14s_keymap, NULL); + if (ret) + return ret; + + return input_register_device(ec->inputdev); +} + +static irqreturn_t t14s_ec_irq_handler(int irq, void *data) +{ + struct t14s_ec *ec = data; + int ret; + u8 val; + + ret = t14s_ec_read_evt(ec, &val); + if (ret < 0) { + dev_err(ec->dev, "Failed to read event\n"); + return IRQ_HANDLED; + } + + switch (val) { + case T14S_EC_EVT_NONE: + break; + case T14S_EC_EVT_KEY_FN_SPACE: + t14s_kbd_bl_update(ec); + fallthrough; + case T14S_EC_EVT_KEY_FN_F4: + case T14S_EC_EVT_KEY_FN_F7: + case T14S_EC_EVT_KEY_FN_4: + case T14S_EC_EVT_KEY_FN_F8: + case T14S_EC_EVT_KEY_FN_F12: + case T14S_EC_EVT_KEY_FN_TAB: + case T14S_EC_EVT_KEY_FN_F10: + case T14S_EC_EVT_KEY_FN_N: + case T14S_EC_EVT_KEY_FN_F11: + case T14S_EC_EVT_KEY_FN_ESC: + case T14S_EC_EVT_KEY_FN_RIGHT_SHIFT: + case T14S_EC_EVT_KEY_TP_DOUBLE_TAP: + sparse_keymap_report_event(ec->inputdev, + T14S_EC_KEY_EVT_OFFSET + val, 1, true); + break; + case T14S_EC_EVT_AC_CONNECTED: + dev_dbg(ec->dev, "AC connected\n"); + break; + case T14S_EC_EVT_AC_DISCONNECTED: + dev_dbg(ec->dev, "AC disconnected\n"); + break; + case T14S_EC_EVT_KEY_POWER: + dev_dbg(ec->dev, "power button\n"); + break; + case T14S_EC_EVT_LID_OPEN: + dev_dbg(ec->dev, "LID open\n"); + break; + case T14S_EC_EVT_LID_CLOSED: + dev_dbg(ec->dev, "LID closed\n"); + break; + case T14S_EC_EVT_THERMAL_TZ40: + dev_dbg(ec->dev, "Thermal Zone 40 Status Change Event (CPU/GPU)\n"); + break; + case T14S_EC_EVT_THERMAL_TZ42: + dev_dbg(ec->dev, "Thermal Zone 42 Status Change Event (Battery)\n"); + break; + case T14S_EC_EVT_THERMAL_TZ39: + dev_dbg(ec->dev, "Thermal Zone 39 Status Change Event (CPU/GPU)\n"); + break; + case T14S_EC_EVT_KEY_FN_G: + dev_dbg(ec->dev, "FN + G - toggle double-tapping\n"); + break; + case T14S_EC_EVT_KEY_FN_L: + dev_dbg(ec->dev, "FN + L - low performance mode\n"); + break; + case T14S_EC_EVT_KEY_FN_M: + dev_dbg(ec->dev, "FN + M - medium performance mode\n"); + break; + case T14S_EC_EVT_KEY_FN_H: + dev_dbg(ec->dev, "FN + H - high performance mode\n"); + break; + case T14S_EC_EVT_KEY_FN_T: + dev_dbg(ec->dev, "FN + T - toggle intelligent cooling mode\n"); + break; + case T14S_EC_EVT_KEY_FN_D: + dev_dbg(ec->dev, "FN + D - toggle privacy guard mode\n"); + break; + default: + dev_info(ec->dev, "Unknown EC event: 0x%02x\n", val); + break; + } + + return IRQ_HANDLED; +} + +static int t14s_ec_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct t14s_ec *ec; + int ret; + + ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); + if (!ec) + return -ENOMEM; + + ec->dev = dev; + + ec->regmap = devm_regmap_init(dev, &t14s_ec_regmap_bus, + ec, &t14s_ec_regmap_config); + if (IS_ERR(ec->regmap)) + return dev_err_probe(dev, PTR_ERR(ec->regmap), + "Failed to init regmap\n"); + + ret = devm_request_threaded_irq(dev, client->irq, NULL, + t14s_ec_irq_handler, + IRQF_ONESHOT, dev_name(dev), ec); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get IRQ\n"); + + ret = t14s_leds_probe(ec); + if (ret < 0) + return ret; + + ret = t14s_kbd_backlight_probe(ec); + if (ret < 0) + return ret; + + ret = t14s_kbd_audio_led_probe(ec); + if (ret < 0) + return ret; + + ret = t14s_input_probe(ec); + if (ret < 0) + return ret; + + /* + * Disable wakeup support by default, because the driver currently does + * not support masking any events and the laptop should not wake up when + * the LID is closed. + */ + device_wakeup_disable(dev); + + return 0; +} + +static const struct of_device_id t14s_ec_of_match[] = { + { .compatible = "lenovo,thinkpad-t14s-ec" }, + {} +}; +MODULE_DEVICE_TABLE(of, t14s_ec_of_match); + +static const struct i2c_device_id t14s_ec_i2c_id_table[] = { + { "thinkpad-t14s-ec", }, + {} +}; +MODULE_DEVICE_TABLE(i2c, t14s_ec_i2c_id_table); + +static struct i2c_driver t14s_ec_i2c_driver = { + .driver = { + .name = "thinkpad-t14s-ec", + .of_match_table = t14s_ec_of_match, + }, + .probe = t14s_ec_probe, + .id_table = t14s_ec_i2c_id_table, +}; +module_i2c_driver(t14s_ec_i2c_driver); + +MODULE_AUTHOR("Sebastian Reichel "); +MODULE_DESCRIPTION("Lenovo Thinkpad T14s Embedded Controller"); +MODULE_LICENSE("GPL"); From a90a8ea288ef823621ccb9f786bd9d9ac1913ad9 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 18 Sep 2025 23:20:28 +0200 Subject: [PATCH 2139/2711] arm64: dts: qcom: x1e80100-t14s: add EC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Describe ThinkPad Embedded Controller in the T14s device tree, which adds LED and special key support. Tested-by: Neil Armstrong # on Thinkpad T14S OLED Reviewed-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Signed-off-by: Sebastian Reichel Link: https://patch.msgid.link/20250918-thinkpad-t14s-ec-v5-3-ac0bc6382c5c@collabora.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../qcom/x1e78100-lenovo-thinkpad-t14s.dtsi | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi index ac1dddf27da3..f70489aba870 100644 --- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi @@ -887,6 +887,24 @@ }; }; +&i2c6 { + clock-frequency = <400000>; + + status = "okay"; + + embedded-controller@28 { + compatible = "lenovo,thinkpad-t14s-ec"; + reg = <0x28>; + + interrupts-extended = <&tlmm 66 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-0 = <&ec_int_n_default>; + pinctrl-names = "default"; + + wakeup-source; + }; +}; + &i2c7 { clock-frequency = <400000>; @@ -1267,6 +1285,12 @@ <72 2>, /* Secure EC I2C connection (?) */ <238 1>; /* UFS Reset */ + ec_int_n_default: ec-int-n-state { + pins = "gpio66"; + function = "gpio"; + bias-disable; + }; + eusb3_reset_n: eusb3-reset-n-state { pins = "gpio6"; function = "gpio"; From e3b1320be6fed2ceabce08ba8cea0b3067ef40a9 Mon Sep 17 00:00:00 2001 From: Xi Pardee Date: Tue, 16 Sep 2025 12:13:32 -0700 Subject: [PATCH 2140/2711] platform/x86:intel/pmc: Replace dev_warn() with dev_dbg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace dev_warn() with dev_dbg() to reduce unnecessary warning messages. When the low power mode priority register contains invalid data, the Intel PMC Core driver can still utilize the default priority list. This scenario is more suited for debug information rather than warning. Signed-off-by: Xi Pardee Link: https://patch.msgid.link/20250916191339.1748512-1-xi.pardee@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/pmc/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index de2dbf4ad65e..5729810e5a48 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -1244,7 +1244,7 @@ void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev) for (mode = 0; mode < LPM_MAX_NUM_MODES; mode++) pri_order[mode_order[mode]] = mode; else - dev_warn(&pmcdev->pdev->dev, + dev_dbg(&pmcdev->pdev->dev, "Assuming a default substate order for this platform\n"); /* From b40088bfdb8bcac165f55bb16b2ea24caa351234 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:06:54 +0200 Subject: [PATCH 2141/2711] platform/x86: x86-android-tablets: convert Goodix devices to GPIO references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that gpiolib supports software nodes to describe GPIOs, switch the driver away from using GPIO lookup tables for Goodix touchscreens to using PROPERTY_ENTRY_GPIO() to keep all touchscreen properties together. Since the tablets are using either Baytrail or Cherryview GPIO controllers x86_dev_info structure has been extended to carry gpiochip type information so that the code can instantiate correct set of software nodes representing the GPIO chip. Because this adds a new point of failure in x86_android_tablet_probe(), x86_android_tablet_remove() is rearranged to handle cases where battery swnode has not been registered yet, and registering of GPIO lookup tables is moved earlier as it can not fail. Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-2-hansg@kernel.org Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/asus.c | 23 ++++--- .../platform/x86/x86-android-tablets/core.c | 69 ++++++++++++++++--- .../platform/x86/x86-android-tablets/lenovo.c | 23 ++++--- .../platform/x86/x86-android-tablets/other.c | 37 ++-------- .../x86-android-tablets/x86-android-tablets.h | 11 +++ 5 files changed, 105 insertions(+), 58 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/asus.c b/drivers/platform/x86/x86-android-tablets/asus.c index 97cd14c1fd23..6c4468f4004b 100644 --- a/drivers/platform/x86/x86-android-tablets/asus.c +++ b/drivers/platform/x86/x86-android-tablets/asus.c @@ -9,6 +9,7 @@ */ #include +#include #include #include @@ -77,6 +78,16 @@ static const struct software_node asus_me176c_ug3105_node = { .properties = asus_me176c_ug3105_props, }; +static const struct property_entry asus_me176c_touchscreen_props[] = { + PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[0], 60, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("irq-gpios", &baytrail_gpiochip_nodes[2], 28, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node asus_me176c_touchscreen_node = { + .properties = asus_me176c_touchscreen_props, +}; + static const struct x86_i2c_client_info asus_me176c_i2c_clients[] __initconst = { { /* bq24297 battery charger */ @@ -132,6 +143,7 @@ static const struct x86_i2c_client_info asus_me176c_i2c_clients[] __initconst = .type = "GDIX1001:00", .addr = 0x14, .dev_name = "goodix_ts", + .swnode = &asus_me176c_touchscreen_node, }, .adapter_path = "\\_SB_.I2C6", .irq_data = { @@ -152,18 +164,8 @@ static const struct x86_serdev_info asus_me176c_serdevs[] __initconst = { }, }; -static struct gpiod_lookup_table asus_me176c_goodix_gpios = { - .dev_id = "i2c-goodix_ts", - .table = { - GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FC:02", 28, "irq", GPIO_ACTIVE_HIGH), - { } - }, -}; - static struct gpiod_lookup_table * const asus_me176c_gpios[] = { &int3496_gpo2_pin22_gpios, - &asus_me176c_goodix_gpios, NULL }; @@ -179,6 +181,7 @@ const struct x86_dev_info asus_me176c_info __initconst = { .gpiod_lookup_tables = asus_me176c_gpios, .bat_swnode = &generic_lipo_hv_4v35_battery_node, .modules = bq24190_modules, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; /* Asus TF103C tablets have an Android factory image with everything hardcoded */ diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index db76ba3abd7b..7b5942010c78 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -155,6 +155,7 @@ static struct serdev_device **serdevs; static struct gpio_keys_button *buttons; static struct gpiod_lookup_table * const *gpiod_lookup_tables; static const struct software_node *bat_swnode; +static const struct software_node **gpiochip_node_group; static void (*exit_handler)(void); static __init struct i2c_adapter * @@ -330,6 +331,34 @@ put_ctrl_dev: return ret; } +const struct software_node baytrail_gpiochip_nodes[] = { + { .name = "INT33FC:00" }, + { .name = "INT33FC:01" }, + { .name = "INT33FC:02" }, +}; + +static const struct software_node *baytrail_gpiochip_node_group[] = { + &baytrail_gpiochip_nodes[0], + &baytrail_gpiochip_nodes[1], + &baytrail_gpiochip_nodes[2], + NULL +}; + +const struct software_node cherryview_gpiochip_nodes[] = { + { .name = "INT33FF:00" }, + { .name = "INT33FF:01" }, + { .name = "INT33FF:02" }, + { .name = "INT33FF:03" }, +}; + +static const struct software_node *cherryview_gpiochip_node_group[] = { + &cherryview_gpiochip_nodes[0], + &cherryview_gpiochip_nodes[1], + &cherryview_gpiochip_nodes[2], + &cherryview_gpiochip_nodes[3], + NULL +}; + static void x86_android_tablet_remove(struct platform_device *pdev) { int i; @@ -360,10 +389,14 @@ static void x86_android_tablet_remove(struct platform_device *pdev) if (exit_handler) exit_handler(); + if (bat_swnode) + software_node_unregister(bat_swnode); + + if (gpiochip_node_group) + software_node_unregister_node_group(gpiochip_node_group); + for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) gpiod_remove_lookup_table(gpiod_lookup_tables[i]); - - software_node_unregister(bat_swnode); } static __init int x86_android_tablet_probe(struct platform_device *pdev) @@ -387,16 +420,36 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev) for (i = 0; dev_info->modules && dev_info->modules[i]; i++) request_module(dev_info->modules[i]); - bat_swnode = dev_info->bat_swnode; - if (bat_swnode) { - ret = software_node_register(bat_swnode); + gpiod_lookup_tables = dev_info->gpiod_lookup_tables; + for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) + gpiod_add_lookup_table(gpiod_lookup_tables[i]); + + switch (dev_info->gpiochip_type) { + case X86_GPIOCHIP_BAYTRAIL: + gpiochip_node_group = baytrail_gpiochip_node_group; + break; + case X86_GPIOCHIP_CHERRYVIEW: + gpiochip_node_group = cherryview_gpiochip_node_group; + break; + case X86_GPIOCHIP_UNSPECIFIED: + gpiochip_node_group = NULL; + break; + } + + if (gpiochip_node_group) { + ret = software_node_register_node_group(gpiochip_node_group); if (ret) return ret; } - gpiod_lookup_tables = dev_info->gpiod_lookup_tables; - for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) - gpiod_add_lookup_table(gpiod_lookup_tables[i]); + if (dev_info->bat_swnode) { + ret = software_node_register(dev_info->bat_swnode); + if (ret) { + x86_android_tablet_remove(pdev); + return ret; + } + bat_swnode = dev_info->bat_swnode; + } if (dev_info->init) { ret = dev_info->init(&pdev->dev); diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 1241a97cda39..22fe76ef5b5a 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -61,6 +62,16 @@ static struct lp855x_platform_data lenovo_lp8557_reg_only_pdata = { /* Lenovo Yoga Book X90F / X90L's Android factory image has everything hardcoded */ +static const struct property_entry lenovo_yb1_x90_goodix_props[] = { + PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[1], 53, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("irq-gpios", &cherryview_gpiochip_nodes[1], 56, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node lenovo_yb1_x90_goodix_node = { + .properties = lenovo_yb1_x90_goodix_props, +}; + static const struct property_entry lenovo_yb1_x90_wacom_props[] = { PROPERTY_ENTRY_U32("hid-descr-addr", 0x0001), PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 150), @@ -108,6 +119,7 @@ static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst .type = "GDIX1001:00", .addr = 0x14, .dev_name = "goodix_ts", + .swnode = &lenovo_yb1_x90_goodix_node, }, .adapter_path = "\\_SB_.PCI0.I2C2", .irq_data = { @@ -198,15 +210,6 @@ static const struct x86_gpio_button lenovo_yb1_x90_lid __initconst = { .pin = 19, }; -static struct gpiod_lookup_table lenovo_yb1_x90_goodix_gpios = { - .dev_id = "i2c-goodix_ts", - .table = { - GPIO_LOOKUP("INT33FF:01", 53, "reset", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FF:01", 56, "irq", GPIO_ACTIVE_HIGH), - { } - }, -}; - static struct gpiod_lookup_table lenovo_yb1_x90_hideep_gpios = { .dev_id = "i2c-hideep_ts", .table = { @@ -225,7 +228,6 @@ static struct gpiod_lookup_table lenovo_yb1_x90_wacom_gpios = { static struct gpiod_lookup_table * const lenovo_yb1_x90_gpios[] = { &lenovo_yb1_x90_hideep_gpios, - &lenovo_yb1_x90_goodix_gpios, &lenovo_yb1_x90_wacom_gpios, NULL }; @@ -259,6 +261,7 @@ const struct x86_dev_info lenovo_yogabook_x90_info __initconst = { .gpio_button = &lenovo_yb1_x90_lid, .gpio_button_count = 1, .gpiod_lookup_tables = lenovo_yb1_x90_gpios, + .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, .init = lenovo_yb1_x90_init, }; diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index f7bd9f863c85..e3907812c8bc 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -297,6 +298,8 @@ static const struct software_node medion_lifetab_s10346_accel_node = { static const struct property_entry medion_lifetab_s10346_touchscreen_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("irq-gpios", &baytrail_gpiochip_nodes[2], 3, GPIO_ACTIVE_HIGH), { } }; @@ -340,24 +343,10 @@ static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __in }, }; -static struct gpiod_lookup_table medion_lifetab_s10346_goodix_gpios = { - .dev_id = "i2c-goodix_ts", - .table = { - GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH), - { } - }, -}; - -static struct gpiod_lookup_table * const medion_lifetab_s10346_gpios[] = { - &medion_lifetab_s10346_goodix_gpios, - NULL -}; - const struct x86_dev_info medion_lifetab_s10346_info __initconst = { .i2c_client_info = medion_lifetab_s10346_i2c_clients, .i2c_client_count = ARRAY_SIZE(medion_lifetab_s10346_i2c_clients), - .gpiod_lookup_tables = medion_lifetab_s10346_gpios, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; /* Nextbook Ares 8 (BYT) tablets have an Android factory image with everything hardcoded */ @@ -543,6 +532,8 @@ static const struct property_entry whitelabel_tm800a550l_goodix_props[] = { PROPERTY_ENTRY_STRING("firmware-name", "gt912-tm800a550l.fw"), PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-tm800a550l.cfg"), PROPERTY_ENTRY_U32("goodix,main-clk", 54), + PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("irq-gpios", &baytrail_gpiochip_nodes[2], 3, GPIO_ACTIVE_HIGH), { } }; @@ -578,24 +569,10 @@ static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __in }, }; -static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = { - .dev_id = "i2c-goodix_ts", - .table = { - GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH), - { } - }, -}; - -static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = { - &whitelabel_tm800a550l_goodix_gpios, - NULL -}; - const struct x86_dev_info whitelabel_tm800a550l_info __initconst = { .i2c_client_info = whitelabel_tm800a550l_i2c_clients, .i2c_client_count = ARRAY_SIZE(whitelabel_tm800a550l_i2c_clients), - .gpiod_lookup_tables = whitelabel_tm800a550l_gpios, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; /* diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index dcf8d49e3b5f..a54d09408866 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -32,6 +32,12 @@ enum x86_acpi_irq_type { X86_ACPI_IRQ_TYPE_PMIC, }; +enum x86_gpiochip_type { + X86_GPIOCHIP_UNSPECIFIED = 0, + X86_GPIOCHIP_BAYTRAIL, + X86_GPIOCHIP_CHERRYVIEW, +}; + struct x86_acpi_irq_data { char *chip; /* GPIO chip label (GPIOINT) or PMIC ACPI path (PMIC) */ enum x86_acpi_irq_type type; @@ -99,6 +105,7 @@ struct x86_dev_info { int (*init)(struct device *dev); void (*exit)(void); bool use_pci; + enum x86_gpiochip_type gpiochip_type; }; int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id, @@ -106,6 +113,10 @@ int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id, struct gpio_desc **desc); int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data); +/* Software nodes representing GPIO chips used by various tablets */ +extern const struct software_node baytrail_gpiochip_nodes[]; +extern const struct software_node cherryview_gpiochip_nodes[]; + /* * Extern declarations of x86_dev_info structs so there can be a single * MODULE_DEVICE_TABLE(dmi, ...), while splitting the board descriptions. From c5f7d46d52e24e500cfb036f0cfc2e1e596bdf8d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:06:55 +0200 Subject: [PATCH 2142/2711] platform/x86: x86-android-tablets: convert Wacom devices to GPIO references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that gpiolib supports software nodes to describe GPIOs, switch the driver away from using GPIO lookup tables for Wacom touchscreens to using PROPERTY_ENTRY_GPIO() to keep all touchscreen properties together. Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-3-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/x86-android-tablets/lenovo.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 22fe76ef5b5a..f8d261d37284 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -75,6 +75,7 @@ static const struct software_node lenovo_yb1_x90_goodix_node = { static const struct property_entry lenovo_yb1_x90_wacom_props[] = { PROPERTY_ENTRY_U32("hid-descr-addr", 0x0001), PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 150), + PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[0], 82, GPIO_ACTIVE_LOW), { } }; @@ -218,17 +219,8 @@ static struct gpiod_lookup_table lenovo_yb1_x90_hideep_gpios = { }, }; -static struct gpiod_lookup_table lenovo_yb1_x90_wacom_gpios = { - .dev_id = "i2c-wacom", - .table = { - GPIO_LOOKUP("INT33FF:00", 82, "reset", GPIO_ACTIVE_LOW), - { } - }, -}; - static struct gpiod_lookup_table * const lenovo_yb1_x90_gpios[] = { &lenovo_yb1_x90_hideep_gpios, - &lenovo_yb1_x90_wacom_gpios, NULL }; From 40949a3f0ed50bd50aa83629de73b88d13956ce7 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:06:56 +0200 Subject: [PATCH 2143/2711] platform/x86: x86-android-tablets: convert HiDeep devices to GPIO references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that gpiolib supports software nodes to describe GPIOs, switch the driver away from using GPIO lookup tables for HiDeep touchscreens to using PROPERTY_ENTRY_GPIO() to keep all touchscreen properties together. Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-4-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/lenovo.c | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index f8d261d37284..49388266201b 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -97,6 +97,7 @@ static const struct property_entry lenovo_yb1_x90_hideep_ts_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-y", 1920), PROPERTY_ENTRY_U32("touchscreen-max-pressure", 16384), PROPERTY_ENTRY_BOOL("hideep,force-native-protocol"), + PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[0], 7, GPIO_ACTIVE_LOW), { } }; @@ -211,19 +212,6 @@ static const struct x86_gpio_button lenovo_yb1_x90_lid __initconst = { .pin = 19, }; -static struct gpiod_lookup_table lenovo_yb1_x90_hideep_gpios = { - .dev_id = "i2c-hideep_ts", - .table = { - GPIO_LOOKUP("INT33FF:00", 7, "reset", GPIO_ACTIVE_LOW), - { } - }, -}; - -static struct gpiod_lookup_table * const lenovo_yb1_x90_gpios[] = { - &lenovo_yb1_x90_hideep_gpios, - NULL -}; - static int __init lenovo_yb1_x90_init(struct device *dev) { /* Enable the regulators used by the touchscreens */ @@ -252,7 +240,6 @@ const struct x86_dev_info lenovo_yogabook_x90_info __initconst = { .serdev_count = ARRAY_SIZE(lenovo_yb1_x90_serdevs), .gpio_button = &lenovo_yb1_x90_lid, .gpio_button_count = 1, - .gpiod_lookup_tables = lenovo_yb1_x90_gpios, .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, .init = lenovo_yb1_x90_init, }; @@ -819,6 +806,7 @@ static const struct property_entry lenovo_yt3_hideep_ts_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 1600), PROPERTY_ENTRY_U32("touchscreen-size-y", 2560), PROPERTY_ENTRY_U32("touchscreen-max-pressure", 255), + PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[0], 7, GPIO_ACTIVE_LOW), { } }; @@ -1008,14 +996,6 @@ static int __init lenovo_yt3_init(struct device *dev) return 0; } -static struct gpiod_lookup_table lenovo_yt3_hideep_gpios = { - .dev_id = "i2c-hideep_ts", - .table = { - GPIO_LOOKUP("INT33FF:00", 7, "reset", GPIO_ACTIVE_LOW), - { } - }, -}; - static struct gpiod_lookup_table lenovo_yt3_wm5102_gpios = { .dev_id = "spi1.0", .table = { @@ -1028,7 +1008,6 @@ static struct gpiod_lookup_table lenovo_yt3_wm5102_gpios = { }; static struct gpiod_lookup_table * const lenovo_yt3_gpios[] = { - &lenovo_yt3_hideep_gpios, &lenovo_yt3_wm5102_gpios, NULL }; @@ -1039,5 +1018,6 @@ const struct x86_dev_info lenovo_yt3_info __initconst = { .spi_dev_info = lenovo_yt3_spi_devs, .spi_dev_count = ARRAY_SIZE(lenovo_yt3_spi_devs), .gpiod_lookup_tables = lenovo_yt3_gpios, + .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, .init = lenovo_yt3_init, }; From f6fd6e7bdbb89cfcbc6c889d9571d8efa7373ac7 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:06:57 +0200 Subject: [PATCH 2144/2711] platform/x86: x86-android-tablets: convert Novatek devices to GPIO references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that gpiolib supports software nodes to describe GPIOs, switch the driver away from using GPIO lookup tables for Novatek touchscreens to using PROPERTY_ENTRY_GPIO() to keep all touchscreen properties together. Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-5-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/other.c | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index e3907812c8bc..95c5001004a1 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -38,6 +38,15 @@ static const struct software_node acer_b1_750_bma250e_node = { .properties = acer_b1_750_bma250e_props, }; +static const struct property_entry acer_b1_750_novatek_props[] = { + PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node acer_b1_750_novatek_node = { + .properties = acer_b1_750_novatek_props, +}; + static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = { { /* Novatek NVT-ts touchscreen */ @@ -45,6 +54,7 @@ static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = .type = "nt11205-ts", .addr = 0x34, .dev_name = "NVT-ts", + .swnode = &acer_b1_750_novatek_node, }, .adapter_path = "\\_SB_.I2C4", .irq_data = { @@ -74,16 +84,7 @@ static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = }, }; -static struct gpiod_lookup_table acer_b1_750_nvt_ts_gpios = { - .dev_id = "i2c-NVT-ts", - .table = { - GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW), - { } - }, -}; - static struct gpiod_lookup_table * const acer_b1_750_gpios[] = { - &acer_b1_750_nvt_ts_gpios, &int3496_reference_gpios, NULL }; @@ -94,6 +95,7 @@ const struct x86_dev_info acer_b1_750_info __initconst = { .pdev_info = int3496_pdevs, .pdev_count = 1, .gpiod_lookup_tables = acer_b1_750_gpios, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; /* From e4a7488717688a9821c44f3b6023c94b95f6979a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:06:58 +0200 Subject: [PATCH 2145/2711] platform/x86: x86-android-tablets: convert EDT devices to GPIO references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that gpiolib supports software nodes to describe GPIOs, switch the driver away from using GPIO lookup tables for EDT touchscreens to using PROPERTY_ENTRY_GPIO() to keep all touchscreen properties together. Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-6-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/other.c | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index 95c5001004a1..0f3cc0ea877e 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -436,6 +436,17 @@ static const struct software_node nextbook_ares8a_accel_node = { .properties = nextbook_ares8a_accel_props, }; +static const struct property_entry nextbook_ares8a_ft5416_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 800), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), + PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[1], 25, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node nextbook_ares8a_ft5416_node = { + .properties = nextbook_ares8a_ft5416_props, +}; + static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initconst = { { /* Freescale MMA8653FC accelerometer */ @@ -452,7 +463,7 @@ static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initcons .type = "edt-ft5x06", .addr = 0x38, .dev_name = "ft5416", - .swnode = &nextbook_ares8_touchscreen_node, + .swnode = &nextbook_ares8a_ft5416_node, }, .adapter_path = "\\_SB_.PCI0.I2C6", .irq_data = { @@ -466,23 +477,10 @@ static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initcons }, }; -static struct gpiod_lookup_table nextbook_ares8a_ft5416_gpios = { - .dev_id = "i2c-ft5416", - .table = { - GPIO_LOOKUP("INT33FF:01", 25, "reset", GPIO_ACTIVE_LOW), - { } - }, -}; - -static struct gpiod_lookup_table * const nextbook_ares8a_gpios[] = { - &nextbook_ares8a_ft5416_gpios, - NULL -}; - const struct x86_dev_info nextbook_ares8a_info __initconst = { .i2c_client_info = nextbook_ares8a_i2c_clients, .i2c_client_count = ARRAY_SIZE(nextbook_ares8a_i2c_clients), - .gpiod_lookup_tables = nextbook_ares8a_gpios, + .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, }; /* From ef64ca079345046c306153cacb63a58354819eb0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:06:59 +0200 Subject: [PATCH 2146/2711] platform/x86: x86-android-tablets: convert int3496 devices to GPIO references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that gpiolib supports software nodes to describe GPIOs, switch the driver away from using GPIO lookup tables for int3496 devices to using PROPERTY_ENTRY_GPIO(). Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-7-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/asus.c | 37 ++++++++----------- .../platform/x86/x86-android-tablets/lenovo.c | 24 +++++++----- .../platform/x86/x86-android-tablets/other.c | 13 +------ .../x86/x86-android-tablets/shared-psy-info.c | 22 +++++------ .../x86/x86-android-tablets/shared-psy-info.h | 2 - 5 files changed, 43 insertions(+), 55 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/asus.c b/drivers/platform/x86/x86-android-tablets/asus.c index 6c4468f4004b..ce581d161551 100644 --- a/drivers/platform/x86/x86-android-tablets/asus.c +++ b/drivers/platform/x86/x86-android-tablets/asus.c @@ -17,11 +17,17 @@ #include "x86-android-tablets.h" /* Asus ME176C and TF103C tablets shared data */ -static struct gpiod_lookup_table int3496_gpo2_pin22_gpios = { - .dev_id = "intel-int3496", - .table = { - GPIO_LOOKUP("INT33FC:02", 22, "id", GPIO_ACTIVE_HIGH), - { } +static const struct property_entry asus_me176c_tf103c_int3496_props[] __initconst = { + PROPERTY_ENTRY_GPIO("id-gpios", &baytrail_gpiochip_nodes[2], 22, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct platform_device_info asus_me176c_tf103c_pdevs[] __initconst = { + { + /* For micro USB ID pin handling */ + .name = "intel-int3496", + .id = PLATFORM_DEVID_NONE, + .properties = asus_me176c_tf103c_int3496_props, }, }; @@ -164,21 +170,15 @@ static const struct x86_serdev_info asus_me176c_serdevs[] __initconst = { }, }; -static struct gpiod_lookup_table * const asus_me176c_gpios[] = { - &int3496_gpo2_pin22_gpios, - NULL -}; - const struct x86_dev_info asus_me176c_info __initconst = { .i2c_client_info = asus_me176c_i2c_clients, .i2c_client_count = ARRAY_SIZE(asus_me176c_i2c_clients), - .pdev_info = int3496_pdevs, - .pdev_count = 1, + .pdev_info = asus_me176c_tf103c_pdevs, + .pdev_count = ARRAY_SIZE(asus_me176c_tf103c_pdevs), .serdev_info = asus_me176c_serdevs, .serdev_count = ARRAY_SIZE(asus_me176c_serdevs), .gpio_button = &asus_me176c_tf103c_lid, .gpio_button_count = 1, - .gpiod_lookup_tables = asus_me176c_gpios, .bat_swnode = &generic_lipo_hv_4v35_battery_node, .modules = bq24190_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, @@ -296,19 +296,14 @@ static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst = }, }; -static struct gpiod_lookup_table * const asus_tf103c_gpios[] = { - &int3496_gpo2_pin22_gpios, - NULL -}; - const struct x86_dev_info asus_tf103c_info __initconst = { .i2c_client_info = asus_tf103c_i2c_clients, .i2c_client_count = ARRAY_SIZE(asus_tf103c_i2c_clients), - .pdev_info = int3496_pdevs, - .pdev_count = 1, + .pdev_info = asus_me176c_tf103c_pdevs, + .pdev_count = ARRAY_SIZE(asus_me176c_tf103c_pdevs), .gpio_button = &asus_me176c_tf103c_lid, .gpio_button_count = 1, - .gpiod_lookup_tables = asus_tf103c_gpios, .bat_swnode = &generic_lipo_4v2_battery_node, .modules = bq24190_modules, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 49388266201b..db6337671357 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -366,12 +366,18 @@ static struct x86_i2c_client_info lenovo_yoga_tab2_830_1050_i2c_clients[] __init }, }; -static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_int3496_gpios = { - .dev_id = "intel-int3496", - .table = { - GPIO_LOOKUP("INT33FC:02", 1, "mux", GPIO_ACTIVE_LOW), - GPIO_LOOKUP("INT33FC:02", 24, "id", GPIO_ACTIVE_HIGH), - { } +static const struct property_entry lenovo_yoga_tab2_830_1050_int3496_props[] __initconst = { + PROPERTY_ENTRY_GPIO("mux-gpios", &baytrail_gpiochip_nodes[2], 1, GPIO_ACTIVE_LOW), + PROPERTY_ENTRY_GPIO("id-gpios", &baytrail_gpiochip_nodes[2], 24, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct platform_device_info lenovo_yoga_tab2_830_1050_pdevs[] __initconst = { + { + /* For micro USB ID pin handling */ + .name = "intel-int3496", + .id = PLATFORM_DEVID_NONE, + .properties = lenovo_yoga_tab2_830_1050_int3496_props, }, }; @@ -389,7 +395,6 @@ static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_codec_gpios = { }; static struct gpiod_lookup_table * const lenovo_yoga_tab2_830_1050_gpios[] = { - &lenovo_yoga_tab2_830_1050_int3496_gpios, &lenovo_yoga_tab2_830_1050_codec_gpios, NULL }; @@ -400,13 +405,14 @@ static void lenovo_yoga_tab2_830_1050_exit(void); const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { .i2c_client_info = lenovo_yoga_tab2_830_1050_i2c_clients, .i2c_client_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients), - .pdev_info = int3496_pdevs, - .pdev_count = 1, + .pdev_info = lenovo_yoga_tab2_830_1050_pdevs, + .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_pdevs), .gpio_button = &lenovo_yoga_tab2_830_1050_lid, .gpio_button_count = 1, .gpiod_lookup_tables = lenovo_yoga_tab2_830_1050_gpios, .bat_swnode = &generic_lipo_hv_4v35_battery_node, .modules = bq24190_modules, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, .init = lenovo_yoga_tab2_830_1050_init, .exit = lenovo_yoga_tab2_830_1050_exit, }; diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index 0f3cc0ea877e..2f12b68080ba 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -84,17 +84,11 @@ static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = }, }; -static struct gpiod_lookup_table * const acer_b1_750_gpios[] = { - &int3496_reference_gpios, - NULL -}; - const struct x86_dev_info acer_b1_750_info __initconst = { .i2c_client_info = acer_b1_750_i2c_clients, .i2c_client_count = ARRAY_SIZE(acer_b1_750_i2c_clients), .pdev_info = int3496_pdevs, .pdev_count = 1, - .gpiod_lookup_tables = acer_b1_750_gpios, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; @@ -407,17 +401,12 @@ static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst }, }; -static struct gpiod_lookup_table * const nextbook_ares8_gpios[] = { - &int3496_reference_gpios, - NULL -}; - const struct x86_dev_info nextbook_ares8_info __initconst = { .i2c_client_info = nextbook_ares8_i2c_clients, .i2c_client_count = ARRAY_SIZE(nextbook_ares8_i2c_clients), .pdev_info = int3496_pdevs, .pdev_count = 1, - .gpiod_lookup_tables = nextbook_ares8_gpios, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; /* Nextbook Ares 8A (CHT) tablets have an Android factory image with everything hardcoded */ diff --git a/drivers/platform/x86/x86-android-tablets/shared-psy-info.c b/drivers/platform/x86/x86-android-tablets/shared-psy-info.c index fe34cedb6257..6ebe282bda6e 100644 --- a/drivers/platform/x86/x86-android-tablets/shared-psy-info.c +++ b/drivers/platform/x86/x86-android-tablets/shared-psy-info.c @@ -9,12 +9,14 @@ */ #include +#include #include #include #include #include #include "shared-psy-info.h" +#include "x86-android-tablets.h" /* Generic / shared charger / battery settings */ const char * const tusb1211_chg_det_psy[] = { "tusb1211-charger-detect" }; @@ -156,21 +158,19 @@ const char * const bq24190_modules[] __initconst = { NULL }; -/* Generic platform device array and GPIO lookup table for micro USB ID pin handling */ +static const struct property_entry int3496_reference_props[] __initconst = { + PROPERTY_ENTRY_GPIO("vbus-gpios", &baytrail_gpiochip_nodes[1], 15, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("mux-gpios", &baytrail_gpiochip_nodes[2], 1, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("id-gpios", &baytrail_gpiochip_nodes[2], 18, GPIO_ACTIVE_HIGH), + { } +}; + +/* Generic pdevs array and gpio-lookups for micro USB ID pin handling */ const struct platform_device_info int3496_pdevs[] __initconst = { { /* For micro USB ID pin handling */ .name = "intel-int3496", .id = PLATFORM_DEVID_NONE, - }, -}; - -struct gpiod_lookup_table int3496_reference_gpios = { - .dev_id = "intel-int3496", - .table = { - GPIO_LOOKUP("INT33FC:01", 15, "vbus", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FC:02", 1, "mux", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FC:02", 18, "id", GPIO_ACTIVE_HIGH), - { } + .properties = int3496_reference_props, }, }; diff --git a/drivers/platform/x86/x86-android-tablets/shared-psy-info.h b/drivers/platform/x86/x86-android-tablets/shared-psy-info.h index bcf9845ad275..b9cbc291aa4d 100644 --- a/drivers/platform/x86/x86-android-tablets/shared-psy-info.h +++ b/drivers/platform/x86/x86-android-tablets/shared-psy-info.h @@ -11,7 +11,6 @@ #define __PDX86_SHARED_PSY_INFO_H struct bq24190_platform_data; -struct gpiod_lookup_table; struct platform_device_info; struct software_node; @@ -28,6 +27,5 @@ extern struct bq24190_platform_data bq24190_pdata; extern const char * const bq24190_modules[]; extern const struct platform_device_info int3496_pdevs[]; -extern struct gpiod_lookup_table int3496_reference_gpios; #endif From 0536b0372927e2ab4073ee84c9d0bd9c2105c7b2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:07:00 +0200 Subject: [PATCH 2147/2711] platform/x86: x86-android-tablets: convert wm1502 devices to GPIO references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that gpiolib supports software nodes to describe GPIOs, switch the driver away from using GPIO lookup tables for wm1502 devices to using PROPERTY_ENTRY_GPIO(). Adding a swnode to the yt3 spi device changes the name of the SPI/codec device and the sound/soc/intel/boards/bytcr_wm5102.c machine driver looks up the code by name, update the machine driver to use the new name. Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-8-hansg@kernel.org Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/lenovo.c | 107 ++++++++++++------ sound/soc/intel/boards/bytcr_wm5102.c | 2 +- 2 files changed, 76 insertions(+), 33 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index db6337671357..aaa946bb1e7c 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -60,6 +60,14 @@ static struct lp855x_platform_data lenovo_lp8557_reg_only_pdata = { .initial_brightness = 128, }; +static const struct software_node arizona_gpiochip_node = { + .name = "arizona", +}; + +static const struct software_node crystalcove_gpiochip_node = { + .name = "gpio_crystalcove", +}; + /* Lenovo Yoga Book X90F / X90L's Android factory image has everything hardcoded */ static const struct property_entry lenovo_yb1_x90_goodix_props[] = { @@ -383,19 +391,26 @@ static const struct platform_device_info lenovo_yoga_tab2_830_1050_pdevs[] __ini #define LENOVO_YOGA_TAB2_830_1050_CODEC_NAME "spi-10WM5102:00" -static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_codec_gpios = { - .dev_id = LENOVO_YOGA_TAB2_830_1050_CODEC_NAME, - .table = { - GPIO_LOOKUP("gpio_crystalcove", 3, "reset", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FC:01", 23, "wlf,ldoena", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("arizona", 2, "wlf,spkvdd-ena", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("arizona", 4, "wlf,micd-pol", GPIO_ACTIVE_LOW), - { } - }, +static const struct property_entry lenovo_yoga_tab2_830_1050_wm1502_props[] = { + PROPERTY_ENTRY_GPIO("reset-gpios", + &crystalcove_gpiochip_node, 3, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("wlf,ldoena-gpios", + &baytrail_gpiochip_nodes[1], 23, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("wlf,spkvdd-ena-gpios", + &arizona_gpiochip_node, 2, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("wlf,micd-pol-gpios", + &arizona_gpiochip_node, 4, GPIO_ACTIVE_LOW), + { } }; -static struct gpiod_lookup_table * const lenovo_yoga_tab2_830_1050_gpios[] = { - &lenovo_yoga_tab2_830_1050_codec_gpios, +static const struct software_node lenovo_yoga_tab2_830_1050_wm5102 = { + .properties = lenovo_yoga_tab2_830_1050_wm1502_props, +}; + +static const struct software_node *lenovo_yoga_tab2_830_1050_swnodes[] = { + &crystalcove_gpiochip_node, + &arizona_gpiochip_node, + &lenovo_yoga_tab2_830_1050_wm5102, NULL }; @@ -409,7 +424,6 @@ const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_pdevs), .gpio_button = &lenovo_yoga_tab2_830_1050_lid, .gpio_button_count = 1, - .gpiod_lookup_tables = lenovo_yoga_tab2_830_1050_gpios, .bat_swnode = &generic_lipo_hv_4v35_battery_node, .modules = bq24190_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, @@ -469,6 +483,7 @@ static const struct pinctrl_map lenovo_yoga_tab2_830_1050_codec_pinctrl_map = PIN_MAP_MUX_GROUP(LENOVO_YOGA_TAB2_830_1050_CODEC_NAME, "codec_32khz_clk", "INT33FC:02", "pmu_clk2_grp", "pmu_clk"); +static struct device *lenovo_yoga_tab2_830_1050_codec_dev; static struct pinctrl *lenovo_yoga_tab2_830_1050_codec_pinctrl; static struct sys_off_handler *lenovo_yoga_tab2_830_1050_sys_off_handler; @@ -495,12 +510,26 @@ static int __init lenovo_yoga_tab2_830_1050_init_codec(void) goto err_unregister_mappings; } - /* We're done with the codec_dev now */ - put_device(codec_dev); + ret = software_node_register_node_group(lenovo_yoga_tab2_830_1050_swnodes); + if (ret) { + ret = dev_err_probe(codec_dev, ret, "registering software nodes\n"); + goto err_put_pinctrl; + } + ret = device_add_software_node(codec_dev, &lenovo_yoga_tab2_830_1050_wm5102); + if (ret) { + ret = dev_err_probe(codec_dev, ret, "adding software node\n"); + goto err_unregister_swnodes; + } + + lenovo_yoga_tab2_830_1050_codec_dev = codec_dev; lenovo_yoga_tab2_830_1050_codec_pinctrl = pinctrl; return 0; +err_unregister_swnodes: + software_node_unregister_node_group(lenovo_yoga_tab2_830_1050_swnodes); +err_put_pinctrl: + pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl); err_unregister_mappings: pinctrl_unregister_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map); err_put_device: @@ -548,6 +577,12 @@ static void lenovo_yoga_tab2_830_1050_exit(void) { unregister_sys_off_handler(lenovo_yoga_tab2_830_1050_sys_off_handler); + if (lenovo_yoga_tab2_830_1050_codec_dev) { + device_remove_software_node(lenovo_yoga_tab2_830_1050_codec_dev); + put_device(lenovo_yoga_tab2_830_1050_codec_dev); + software_node_unregister_node_group(lenovo_yoga_tab2_830_1050_swnodes); + } + if (lenovo_yoga_tab2_830_1050_codec_pinctrl) { pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl); pinctrl_unregister_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map); @@ -750,7 +785,6 @@ static struct gpiod_lookup_table lenovo_yoga_tab2_1380_fc_gpios = { }; static struct gpiod_lookup_table * const lenovo_yoga_tab2_1380_gpios[] = { - &lenovo_yoga_tab2_830_1050_codec_gpios, &lenovo_yoga_tab2_1380_fc_gpios, NULL }; @@ -947,12 +981,34 @@ static struct arizona_pdata lenovo_yt3_wm5102_pdata = { }, }; +static const struct property_entry lenovo_yt3_wm1502_props[] = { + PROPERTY_ENTRY_GPIO("wlf,spkvdd-ena-gpios", + &cherryview_gpiochip_nodes[0], 75, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("wlf,ldoena-gpios", + &cherryview_gpiochip_nodes[0], 81, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[0], 82, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("wlf,micd-pol-gpios", &arizona_gpiochip_node, 2, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node lenovo_yt3_wm5102 = { + .properties = lenovo_yt3_wm1502_props, + .name = "wm5102", +}; + +static const struct software_node *lenovo_yt3_swnodes[] = { + &arizona_gpiochip_node, + &lenovo_yt3_wm5102, + NULL +}; + static const struct x86_spi_dev_info lenovo_yt3_spi_devs[] __initconst = { { /* WM5102 codec */ .board_info = { .modalias = "wm5102", .platform_data = &lenovo_yt3_wm5102_pdata, + .swnode = &lenovo_yt3_wm5102, .max_speed_hz = 5000000, }, .ctrl_path = "\\_SB_.PCI0.SPI1", @@ -999,31 +1055,18 @@ static int __init lenovo_yt3_init(struct device *dev) intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0x9b, 0x02, 0xff); intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0xa0, 0x02, 0xff); + ret = software_node_register_node_group(lenovo_yt3_swnodes); + if (ret) + return dev_err_probe(dev, ret, "registering software nodes\n"); + return 0; } -static struct gpiod_lookup_table lenovo_yt3_wm5102_gpios = { - .dev_id = "spi1.0", - .table = { - GPIO_LOOKUP("INT33FF:00", 75, "wlf,spkvdd-ena", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FF:00", 81, "wlf,ldoena", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FF:00", 82, "reset", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("arizona", 2, "wlf,micd-pol", GPIO_ACTIVE_HIGH), - { } - }, -}; - -static struct gpiod_lookup_table * const lenovo_yt3_gpios[] = { - &lenovo_yt3_wm5102_gpios, - NULL -}; - const struct x86_dev_info lenovo_yt3_info __initconst = { .i2c_client_info = lenovo_yt3_i2c_clients, .i2c_client_count = ARRAY_SIZE(lenovo_yt3_i2c_clients), .spi_dev_info = lenovo_yt3_spi_devs, .spi_dev_count = ARRAY_SIZE(lenovo_yt3_spi_devs), - .gpiod_lookup_tables = lenovo_yt3_gpios, .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, .init = lenovo_yt3_init, }; diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index a6dfbcfdf74e..da0fdb8d677d 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -552,7 +552,7 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev) acpi_dev_put(adev); } else { /* Special case for when the codec is missing from the DSTD */ - strscpy(codec_name, "spi1.0", sizeof(codec_name)); + strscpy(codec_name, "spi-wm5102", sizeof(codec_name)); } codec_dev = bus_find_device_by_name(&spi_bus_type, NULL, codec_name); From 0a2f13e2747b14ee4c30d9c479dbe0a5a1d11c89 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:07:01 +0200 Subject: [PATCH 2148/2711] platform/x86: x86-android-tablets: convert HID-I2C devices to GPIO references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that gpiolib supports software nodes to describe GPIOs, switch the driver away from using GPIO lookup tables for HID-I2C touchscreens to using PROPERTY_ENTRY_GPIO() to keep all touchscreen properties together. Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-9-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/other.c | 32 +++---------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index 2f12b68080ba..5309831243b3 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -571,6 +571,7 @@ const struct x86_dev_info whitelabel_tm800a550l_info __initconst = { static const struct property_entry vexia_edu_atla10_5v_touchscreen_props[] = { PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000), PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120), + PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_LOW), { } }; @@ -605,23 +606,10 @@ static const struct x86_i2c_client_info vexia_edu_atla10_5v_i2c_clients[] __init } }; -static struct gpiod_lookup_table vexia_edu_atla10_5v_ft5416_gpios = { - .dev_id = "i2c-FTSC1000", - .table = { - GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW), - { } - }, -}; - -static struct gpiod_lookup_table * const vexia_edu_atla10_5v_gpios[] = { - &vexia_edu_atla10_5v_ft5416_gpios, - NULL -}; - const struct x86_dev_info vexia_edu_atla10_5v_info __initconst = { .i2c_client_info = vexia_edu_atla10_5v_i2c_clients, .i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_5v_i2c_clients), - .gpiod_lookup_tables = vexia_edu_atla10_5v_gpios, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; /* @@ -657,6 +645,7 @@ static const struct software_node vexia_edu_atla10_9v_accel_node = { static const struct property_entry vexia_edu_atla10_9v_touchscreen_props[] = { PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000), PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120), + PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[0], 60, GPIO_ACTIVE_LOW), { } }; @@ -749,19 +738,6 @@ static const struct x86_serdev_info vexia_edu_atla10_9v_serdevs[] __initconst = }, }; -static struct gpiod_lookup_table vexia_edu_atla10_9v_ft5416_gpios = { - .dev_id = "i2c-FTSC1000", - .table = { - GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_LOW), - { } - }, -}; - -static struct gpiod_lookup_table * const vexia_edu_atla10_9v_gpios[] = { - &vexia_edu_atla10_9v_ft5416_gpios, - NULL -}; - static int __init vexia_edu_atla10_9v_init(struct device *dev) { struct pci_dev *pdev; @@ -791,9 +767,9 @@ const struct x86_dev_info vexia_edu_atla10_9v_info __initconst = { .i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_9v_i2c_clients), .serdev_info = vexia_edu_atla10_9v_serdevs, .serdev_count = ARRAY_SIZE(vexia_edu_atla10_9v_serdevs), - .gpiod_lookup_tables = vexia_edu_atla10_9v_gpios, .init = vexia_edu_atla10_9v_init, .use_pci = true, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; /* From 27d3e7351eea6fe2e967ea6028143e04f5914f0d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:07:02 +0200 Subject: [PATCH 2149/2711] platform/x86: x86-android-tablets: convert Yoga Tab2 fast charger to GPIO references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that gpiolib supports software nodes to describe GPIOs, switch the driver away from using GPIO lookup tables for the fast charger device to using PROPERTY_ENTRY_GPIO(). Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-10-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../lenovo/yoga-tab2-pro-1380-fastcharger.c | 5 ++++ .../platform/x86/x86-android-tablets/lenovo.c | 23 +++++++------------ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/platform/x86/lenovo/yoga-tab2-pro-1380-fastcharger.c b/drivers/platform/x86/lenovo/yoga-tab2-pro-1380-fastcharger.c index 1b33c977f6d7..8551ab4d2c7d 100644 --- a/drivers/platform/x86/lenovo/yoga-tab2-pro-1380-fastcharger.c +++ b/drivers/platform/x86/lenovo/yoga-tab2-pro-1380-fastcharger.c @@ -255,6 +255,11 @@ static int yt2_1380_fc_pdev_probe(struct platform_device *pdev) if (!serdev) return -ENOMEM; + /* Propagate pdev-fwnode set by x86-android-tablets to serdev */ + device_set_node(&serdev->dev, dev_fwnode(&pdev->dev)); + /* The fwnode is a managed node, so it will be auto-put on serdev_device_put() */ + fwnode_handle_get(dev_fwnode(&serdev->dev)); + ret = serdev_device_add(serdev); if (ret) { serdev_device_put(serdev); diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index aaa946bb1e7c..7d1808a3437f 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -741,11 +741,18 @@ static const struct x86_i2c_client_info lenovo_yoga_tab2_1380_i2c_clients[] __in } }; +static const struct property_entry lenovo_yoga_tab2_1380_fc_props[] __initconst = { + PROPERTY_ENTRY_GPIO("uart3_txd-gpios", &baytrail_gpiochip_nodes[0], 57, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("uart3_rxd-gpios", &baytrail_gpiochip_nodes[0], 61, GPIO_ACTIVE_HIGH), + { } +}; + static const struct platform_device_info lenovo_yoga_tab2_1380_pdevs[] __initconst = { { /* For the Tablet 2 Pro 1380's custom fast charging driver */ .name = "lenovo-yoga-tab2-pro-1380-fastcharger", .id = PLATFORM_DEVID_NONE, + .properties = lenovo_yoga_tab2_1380_fc_props, }, }; @@ -775,20 +782,6 @@ static int __init lenovo_yoga_tab2_1380_init(struct device *dev) return 0; } -static struct gpiod_lookup_table lenovo_yoga_tab2_1380_fc_gpios = { - .dev_id = "serial0-0", - .table = { - GPIO_LOOKUP("INT33FC:00", 57, "uart3_txd", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FC:00", 61, "uart3_rxd", GPIO_ACTIVE_HIGH), - { } - }, -}; - -static struct gpiod_lookup_table * const lenovo_yoga_tab2_1380_gpios[] = { - &lenovo_yoga_tab2_1380_fc_gpios, - NULL -}; - const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { .i2c_client_info = lenovo_yoga_tab2_1380_i2c_clients, .i2c_client_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_i2c_clients), @@ -796,9 +789,9 @@ const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_pdevs), .gpio_button = &lenovo_yoga_tab2_830_1050_lid, .gpio_button_count = 1, - .gpiod_lookup_tables = lenovo_yoga_tab2_1380_gpios, .bat_swnode = &generic_lipo_hv_4v35_battery_node, .modules = lenovo_yoga_tab2_1380_modules, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, .init = lenovo_yoga_tab2_1380_init, .exit = lenovo_yoga_tab2_830_1050_exit, }; From 74ff0b6f3ac245287dbff0bab9ff55db4323acc5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:07:03 +0200 Subject: [PATCH 2150/2711] platform/x86: x86-android-tablets: remove support for GPIO lookup tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that everything that used the lookup tables has been switched to using property entries to describe GPIOs, we can remove support for registering and unregistering the lookup tables. Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-11-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/x86-android-tablets/core.c | 8 -------- .../x86/x86-android-tablets/x86-android-tablets.h | 2 -- 2 files changed, 10 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index 7b5942010c78..1eb59c999baf 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -153,7 +153,6 @@ static struct spi_device **spi_devs; static struct platform_device **pdevs; static struct serdev_device **serdevs; static struct gpio_keys_button *buttons; -static struct gpiod_lookup_table * const *gpiod_lookup_tables; static const struct software_node *bat_swnode; static const struct software_node **gpiochip_node_group; static void (*exit_handler)(void); @@ -394,9 +393,6 @@ static void x86_android_tablet_remove(struct platform_device *pdev) if (gpiochip_node_group) software_node_unregister_node_group(gpiochip_node_group); - - for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) - gpiod_remove_lookup_table(gpiod_lookup_tables[i]); } static __init int x86_android_tablet_probe(struct platform_device *pdev) @@ -420,10 +416,6 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev) for (i = 0; dev_info->modules && dev_info->modules[i]; i++) request_module(dev_info->modules[i]); - gpiod_lookup_tables = dev_info->gpiod_lookup_tables; - for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) - gpiod_add_lookup_table(gpiod_lookup_tables[i]); - switch (dev_info->gpiochip_type) { case X86_GPIOCHIP_BAYTRAIL: gpiochip_node_group = baytrail_gpiochip_node_group; diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index a54d09408866..d037e3962a51 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -17,7 +17,6 @@ #include struct gpio_desc; -struct gpiod_lookup_table; struct platform_device_info; struct software_node; @@ -91,7 +90,6 @@ struct x86_gpio_button { struct x86_dev_info { const char * const *modules; const struct software_node *bat_swnode; - struct gpiod_lookup_table * const *gpiod_lookup_tables; const struct x86_i2c_client_info *i2c_client_info; const struct x86_spi_dev_info *spi_dev_info; const struct platform_device_info *pdev_info; From 6564e5d2ea06b262d3e87785693fd3e8903bef03 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 20 Sep 2025 22:07:04 +0200 Subject: [PATCH 2151/2711] platform/x86: x86-android-tablets: convert gpio_keys devices to GPIO references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that gpiolib supports software nodes to describe GPIOs, switch the driver away from using GPIO lookup tables for gpio_keys devices to using PROPERTY_ENTRY_GPIO(). Signed-off-by: Dmitry Torokhov Tested-by: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-12-hansg@kernel.org Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/asus.c | 42 ++++-- .../platform/x86/x86-android-tablets/core.c | 44 ++---- .../platform/x86/x86-android-tablets/lenovo.c | 79 ++++++---- .../platform/x86/x86-android-tablets/other.c | 138 +++++++++++------- .../x86-android-tablets/x86-android-tablets.h | 10 +- 5 files changed, 177 insertions(+), 136 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/asus.c b/drivers/platform/x86/x86-android-tablets/asus.c index ce581d161551..91245f1bfd87 100644 --- a/drivers/platform/x86/x86-android-tablets/asus.c +++ b/drivers/platform/x86/x86-android-tablets/asus.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include "shared-psy-info.h" @@ -31,17 +31,29 @@ static const struct platform_device_info asus_me176c_tf103c_pdevs[] __initconst }, }; -static const struct x86_gpio_button asus_me176c_tf103c_lid __initconst = { - .button = { - .code = SW_LID, - .active_low = true, - .desc = "lid_sw", - .type = EV_SW, - .wakeup = true, - .debounce_interval = 50, - }, - .chip = "INT33FC:02", - .pin = 12, +static const struct software_node asus_me176c_tf103c_gpio_keys_node = { + .name = "lid_sw", +}; + +static const struct property_entry asus_me176c_tf103c_lid_props[] = { + PROPERTY_ENTRY_U32("linux,input-type", EV_SW), + PROPERTY_ENTRY_U32("linux,code", SW_LID), + PROPERTY_ENTRY_STRING("label", "lid_sw"), + PROPERTY_ENTRY_GPIO("gpios", &baytrail_gpiochip_nodes[2], 12, GPIO_ACTIVE_LOW), + PROPERTY_ENTRY_U32("debounce-interval", 50), + PROPERTY_ENTRY_BOOL("wakeup-source"), + { } +}; + +static const struct software_node asus_me176c_tf103c_lid_node = { + .parent = &asus_me176c_tf103c_gpio_keys_node, + .properties = asus_me176c_tf103c_lid_props, +}; + +static const struct software_node *asus_me176c_tf103c_lid_swnodes[] = { + &asus_me176c_tf103c_gpio_keys_node, + &asus_me176c_tf103c_lid_node, + NULL }; /* Asus ME176C tablets have an Android factory image with everything hardcoded */ @@ -177,8 +189,7 @@ const struct x86_dev_info asus_me176c_info __initconst = { .pdev_count = ARRAY_SIZE(asus_me176c_tf103c_pdevs), .serdev_info = asus_me176c_serdevs, .serdev_count = ARRAY_SIZE(asus_me176c_serdevs), - .gpio_button = &asus_me176c_tf103c_lid, - .gpio_button_count = 1, + .gpio_button_swnodes = asus_me176c_tf103c_lid_swnodes, .bat_swnode = &generic_lipo_hv_4v35_battery_node, .modules = bq24190_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, @@ -301,8 +312,7 @@ const struct x86_dev_info asus_tf103c_info __initconst = { .i2c_client_count = ARRAY_SIZE(asus_tf103c_i2c_clients), .pdev_info = asus_me176c_tf103c_pdevs, .pdev_count = ARRAY_SIZE(asus_me176c_tf103c_pdevs), - .gpio_button = &asus_me176c_tf103c_lid, - .gpio_button_count = 1, + .gpio_button_swnodes = asus_me176c_tf103c_lid_swnodes, .bat_swnode = &generic_lipo_4v2_battery_node, .modules = bq24190_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index 1eb59c999baf..955a2c83a9bf 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -152,7 +152,7 @@ static struct i2c_client **i2c_clients; static struct spi_device **spi_devs; static struct platform_device **pdevs; static struct serdev_device **serdevs; -static struct gpio_keys_button *buttons; +static const struct software_node **gpio_button_swnodes; static const struct software_node *bat_swnode; static const struct software_node **gpiochip_node_group; static void (*exit_handler)(void); @@ -373,7 +373,6 @@ static void x86_android_tablet_remove(struct platform_device *pdev) platform_device_unregister(pdevs[i]); kfree(pdevs); - kfree(buttons); for (i = spi_dev_count - 1; i >= 0; i--) spi_unregister_device(spi_devs[i]); @@ -388,6 +387,9 @@ static void x86_android_tablet_remove(struct platform_device *pdev) if (exit_handler) exit_handler(); + if (gpio_button_swnodes) + software_node_unregister_node_group(gpio_button_swnodes); + if (bat_swnode) software_node_unregister(bat_swnode); @@ -514,38 +516,22 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev) } } - if (dev_info->gpio_button_count) { - struct gpio_keys_platform_data pdata = { }; - struct gpio_desc *gpiod; + if (dev_info->gpio_button_swnodes) { + struct platform_device_info button_info = { + .name = "gpio-keys", + .id = PLATFORM_DEVID_AUTO, + }; - buttons = kcalloc(dev_info->gpio_button_count, sizeof(*buttons), GFP_KERNEL); - if (!buttons) { + ret = software_node_register_node_group(dev_info->gpio_button_swnodes); + if (ret < 0) { x86_android_tablet_remove(pdev); - return -ENOMEM; + return ret; } - for (i = 0; i < dev_info->gpio_button_count; i++) { - ret = x86_android_tablet_get_gpiod(dev_info->gpio_button[i].chip, - dev_info->gpio_button[i].pin, - dev_info->gpio_button[i].button.desc, - false, GPIOD_IN, &gpiod); - if (ret < 0) { - x86_android_tablet_remove(pdev); - return ret; - } + gpio_button_swnodes = dev_info->gpio_button_swnodes; - buttons[i] = dev_info->gpio_button[i].button; - buttons[i].gpio = desc_to_gpio(gpiod); - /* Release GPIO descriptor so that gpio-keys can request it */ - devm_gpiod_put(&x86_android_tablet_device->dev, gpiod); - } - - pdata.buttons = buttons; - pdata.nbuttons = dev_info->gpio_button_count; - - pdevs[pdev_count] = platform_device_register_data(&pdev->dev, "gpio-keys", - PLATFORM_DEVID_AUTO, - &pdata, sizeof(pdata)); + button_info.fwnode = software_node_fwnode(dev_info->gpio_button_swnodes[0]); + pdevs[pdev_count] = platform_device_register_full(&button_info); if (IS_ERR(pdevs[pdev_count])) { ret = PTR_ERR(pdevs[pdev_count]); x86_android_tablet_remove(pdev); diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 7d1808a3437f..9a28216642c3 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -207,17 +208,34 @@ static const struct x86_serdev_info lenovo_yb1_x90_serdevs[] __initconst = { }, }; -static const struct x86_gpio_button lenovo_yb1_x90_lid __initconst = { - .button = { - .code = SW_LID, - .active_low = true, - .desc = "lid_sw", - .type = EV_SW, - .wakeup = true, - .debounce_interval = 50, - }, - .chip = "INT33FF:02", - .pin = 19, +/* + * Software node attached to gpio-keys device representing the LID and + * serving as a parent to software nodes representing individual keys/buttons + * as required by the device tree binding. + */ +static const struct software_node lenovo_lid_gpio_keys_node = { + .name = "lid_sw", +}; + +static const struct property_entry lenovo_yb1_x90_lid_props[] = { + PROPERTY_ENTRY_U32("linux,input-type", EV_SW), + PROPERTY_ENTRY_U32("linux,code", SW_LID), + PROPERTY_ENTRY_STRING("label", "lid_sw"), + PROPERTY_ENTRY_GPIO("gpios", &cherryview_gpiochip_nodes[2], 19, GPIO_ACTIVE_LOW), + PROPERTY_ENTRY_U32("debounce-interval", 50), + PROPERTY_ENTRY_BOOL("wakeup-source"), + { } +}; + +static const struct software_node lenovo_yb1_x90_lid_node = { + .parent = &lenovo_lid_gpio_keys_node, + .properties = lenovo_yb1_x90_lid_props, +}; + +static const struct software_node *lenovo_yb1_x90_lid_swnodes[] = { + &lenovo_lid_gpio_keys_node, + &lenovo_yb1_x90_lid_node, + NULL }; static int __init lenovo_yb1_x90_init(struct device *dev) @@ -246,8 +264,7 @@ const struct x86_dev_info lenovo_yogabook_x90_info __initconst = { .pdev_count = ARRAY_SIZE(lenovo_yb1_x90_pdevs), .serdev_info = lenovo_yb1_x90_serdevs, .serdev_count = ARRAY_SIZE(lenovo_yb1_x90_serdevs), - .gpio_button = &lenovo_yb1_x90_lid, - .gpio_button_count = 1, + .gpio_button_swnodes = lenovo_yb1_x90_lid_swnodes, .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, .init = lenovo_yb1_x90_init, }; @@ -284,17 +301,25 @@ static const struct software_node lenovo_yoga_tab2_830_1050_bq24190_node = { .properties = lenovo_yoga_tab2_830_1050_bq24190_props, }; -static const struct x86_gpio_button lenovo_yoga_tab2_830_1050_lid __initconst = { - .button = { - .code = SW_LID, - .active_low = true, - .desc = "lid_sw", - .type = EV_SW, - .wakeup = true, - .debounce_interval = 50, - }, - .chip = "INT33FC:02", - .pin = 26, +static const struct property_entry lenovo_yoga_tab2_830_1050_lid_props[] = { + PROPERTY_ENTRY_U32("linux,input-type", EV_SW), + PROPERTY_ENTRY_U32("linux,code", SW_LID), + PROPERTY_ENTRY_STRING("label", "lid_sw"), + PROPERTY_ENTRY_GPIO("gpios", &baytrail_gpiochip_nodes[2], 26, GPIO_ACTIVE_LOW), + PROPERTY_ENTRY_U32("debounce-interval", 50), + PROPERTY_ENTRY_BOOL("wakeup-source"), + { } +}; + +static const struct software_node lenovo_yoga_tab2_830_1050_lid_node = { + .parent = &lenovo_lid_gpio_keys_node, + .properties = lenovo_yoga_tab2_830_1050_lid_props, +}; + +static const struct software_node *lenovo_yoga_tab2_830_1050_lid_swnodes[] = { + &lenovo_lid_gpio_keys_node, + &lenovo_yoga_tab2_830_1050_lid_node, + NULL }; /* This gets filled by lenovo_yoga_tab2_830_1050_init() */ @@ -422,8 +447,7 @@ const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { .i2c_client_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients), .pdev_info = lenovo_yoga_tab2_830_1050_pdevs, .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_pdevs), - .gpio_button = &lenovo_yoga_tab2_830_1050_lid, - .gpio_button_count = 1, + .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, .bat_swnode = &generic_lipo_hv_4v35_battery_node, .modules = bq24190_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, @@ -787,8 +811,7 @@ const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { .i2c_client_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_i2c_clients), .pdev_info = lenovo_yoga_tab2_1380_pdevs, .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_pdevs), - .gpio_button = &lenovo_yoga_tab2_830_1050_lid, - .gpio_button_count = 1, + .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, .bat_swnode = &generic_lipo_hv_4v35_battery_node, .modules = lenovo_yoga_tab2_1380_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index 5309831243b3..1362f4167e3d 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -98,22 +98,32 @@ const struct x86_dev_info acer_b1_750_info __initconst = { * which is not described in the ACPI tables in anyway. * Use the x86-android-tablets infra to create a gpio-keys device for this. */ -static const struct x86_gpio_button advantech_mica_071_button __initconst = { - .button = { - .code = KEY_PROG1, - .active_low = true, - .desc = "prog1_key", - .type = EV_KEY, - .wakeup = false, - .debounce_interval = 50, - }, - .chip = "INT33FC:00", - .pin = 2, +static const struct software_node advantech_mica_071_gpio_keys_node = { + .name = "prog1_key", +}; + +static const struct property_entry advantech_mica_071_prog1_key_props[] = { + PROPERTY_ENTRY_U32("linux,code", KEY_PROG1), + PROPERTY_ENTRY_STRING("label", "prog1_key"), + PROPERTY_ENTRY_GPIO("gpios", &baytrail_gpiochip_nodes[0], 2, GPIO_ACTIVE_LOW), + PROPERTY_ENTRY_U32("debounce-interval", 50), + { } +}; + +static const struct software_node advantech_mica_071_prog1_key_node = { + .parent = &advantech_mica_071_gpio_keys_node, + .properties = advantech_mica_071_prog1_key_props, +}; + +static const struct software_node *advantech_mica_071_button_swnodes[] = { + &advantech_mica_071_gpio_keys_node, + &advantech_mica_071_prog1_key_node, + NULL }; const struct x86_dev_info advantech_mica_071_info __initconst = { - .gpio_button = &advantech_mica_071_button, - .gpio_button_count = 1, + .gpio_button_swnodes = advantech_mica_071_button_swnodes, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; /* @@ -209,36 +219,46 @@ const struct x86_dev_info chuwi_hi8_info __initconst = { * in the button row with the power + volume-buttons labeled P and F. * Use the x86-android-tablets infra to create a gpio-keys device for these. */ -static const struct x86_gpio_button cyberbook_t116_buttons[] __initconst = { - { - .button = { - .code = KEY_PROG1, - .active_low = true, - .desc = "prog1_key", - .type = EV_KEY, - .wakeup = false, - .debounce_interval = 50, - }, - .chip = "INT33FF:00", - .pin = 30, - }, - { - .button = { - .code = KEY_PROG2, - .active_low = true, - .desc = "prog2_key", - .type = EV_KEY, - .wakeup = false, - .debounce_interval = 50, - }, - .chip = "INT33FF:03", - .pin = 48, - }, +static const struct software_node cyberbook_t116_gpio_keys_node = { + .name = "prog_keys", +}; + +static const struct property_entry cyberbook_t116_prog1_key_props[] = { + PROPERTY_ENTRY_U32("linux,code", KEY_PROG1), + PROPERTY_ENTRY_STRING("label", "prog1_key"), + PROPERTY_ENTRY_GPIO("gpios", &cherryview_gpiochip_nodes[0], 30, GPIO_ACTIVE_LOW), + PROPERTY_ENTRY_U32("debounce-interval", 50), + { } +}; + +static const struct software_node cyberbook_t116_prog1_key_node = { + .parent = &cyberbook_t116_gpio_keys_node, + .properties = cyberbook_t116_prog1_key_props, +}; + +static const struct property_entry cyberbook_t116_prog2_key_props[] = { + PROPERTY_ENTRY_U32("linux,code", KEY_PROG2), + PROPERTY_ENTRY_STRING("label", "prog2_key"), + PROPERTY_ENTRY_GPIO("gpios", &cherryview_gpiochip_nodes[3], 48, GPIO_ACTIVE_LOW), + PROPERTY_ENTRY_U32("debounce-interval", 50), + { } +}; + +static const struct software_node cyberbook_t116_prog2_key_node = { + .parent = &cyberbook_t116_gpio_keys_node, + .properties = cyberbook_t116_prog2_key_props, +}; + +static const struct software_node *cyberbook_t116_buttons_swnodes[] = { + &cyberbook_t116_gpio_keys_node, + &cyberbook_t116_prog1_key_node, + &cyberbook_t116_prog2_key_node, + NULL }; const struct x86_dev_info cyberbook_t116_info __initconst = { - .gpio_button = cyberbook_t116_buttons, - .gpio_button_count = ARRAY_SIZE(cyberbook_t116_buttons), + .gpio_button_swnodes = cyberbook_t116_buttons_swnodes, + .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, }; #define CZC_EC_EXTRA_PORT 0x68 @@ -478,22 +498,32 @@ const struct x86_dev_info nextbook_ares8a_info __initconst = { * This button has a WMI interface, but that is broken. Instead of trying to * use the broken WMI interface, instantiate a gpio-keys device for this. */ -static const struct x86_gpio_button peaq_c1010_button __initconst = { - .button = { - .code = KEY_SOUND, - .active_low = true, - .desc = "dolby_key", - .type = EV_KEY, - .wakeup = false, - .debounce_interval = 50, - }, - .chip = "INT33FC:00", - .pin = 3, +static const struct software_node peaq_c1010_gpio_keys_node = { + .name = "gpio_keys", +}; + +static const struct property_entry peaq_c1010_dolby_key_props[] = { + PROPERTY_ENTRY_U32("linux,code", KEY_SOUND), + PROPERTY_ENTRY_STRING("label", "dolby_key"), + PROPERTY_ENTRY_GPIO("gpios", &baytrail_gpiochip_nodes[0], 3, GPIO_ACTIVE_LOW), + PROPERTY_ENTRY_U32("debounce-interval", 50), + { } +}; + +static const struct software_node peaq_c1010_dolby_key_node = { + .parent = &peaq_c1010_gpio_keys_node, + .properties = peaq_c1010_dolby_key_props, +}; + +static const struct software_node *peaq_c1010_button_swnodes[] = { + &peaq_c1010_gpio_keys_node, + &peaq_c1010_dolby_key_node, + NULL }; const struct x86_dev_info peaq_c1010_info __initconst = { - .gpio_button = &peaq_c1010_button, - .gpio_button_count = 1, + .gpio_button_swnodes = peaq_c1010_button_swnodes, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; /* diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index d037e3962a51..f4a67a9b74ea 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -11,7 +11,6 @@ #define __PDX86_X86_ANDROID_TABLETS_H #include -#include #include #include #include @@ -81,12 +80,6 @@ struct x86_serdev_info { const char *serdev_hid; }; -struct x86_gpio_button { - struct gpio_keys_button button; - const char *chip; - int pin; -}; - struct x86_dev_info { const char * const *modules; const struct software_node *bat_swnode; @@ -94,12 +87,11 @@ struct x86_dev_info { const struct x86_spi_dev_info *spi_dev_info; const struct platform_device_info *pdev_info; const struct x86_serdev_info *serdev_info; - const struct x86_gpio_button *gpio_button; + const struct software_node **gpio_button_swnodes; int i2c_client_count; int spi_dev_count; int pdev_count; int serdev_count; - int gpio_button_count; int (*init)(struct device *dev); void (*exit)(void); bool use_pci; From a0133db5cdc02a8b6588558ebd4ca423c2f8c8bc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2025 22:07:05 +0200 Subject: [PATCH 2152/2711] platform/x86: x86-android-tablets: replace bat_swnode with swnode_group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we are using software-nodes are used in more places it is useful to have a more generic mechanism to have the core code register software-nodes. Replace the bat_swnode registration mechanism with a more generic swnode_group registration mechanism. Reviewed-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-13-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/x86-android-tablets/asus.c | 4 ++-- drivers/platform/x86/x86-android-tablets/core.c | 12 ++++++------ drivers/platform/x86/x86-android-tablets/lenovo.c | 4 ++-- .../x86/x86-android-tablets/shared-psy-info.c | 10 ++++++++++ .../x86/x86-android-tablets/shared-psy-info.h | 4 ++++ .../x86/x86-android-tablets/x86-android-tablets.h | 2 +- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/asus.c b/drivers/platform/x86/x86-android-tablets/asus.c index 91245f1bfd87..39eb2f9dc031 100644 --- a/drivers/platform/x86/x86-android-tablets/asus.c +++ b/drivers/platform/x86/x86-android-tablets/asus.c @@ -190,7 +190,7 @@ const struct x86_dev_info asus_me176c_info __initconst = { .serdev_info = asus_me176c_serdevs, .serdev_count = ARRAY_SIZE(asus_me176c_serdevs), .gpio_button_swnodes = asus_me176c_tf103c_lid_swnodes, - .bat_swnode = &generic_lipo_hv_4v35_battery_node, + .swnode_group = generic_lipo_hv_4v35_battery_swnodes, .modules = bq24190_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; @@ -313,7 +313,7 @@ const struct x86_dev_info asus_tf103c_info __initconst = { .pdev_info = asus_me176c_tf103c_pdevs, .pdev_count = ARRAY_SIZE(asus_me176c_tf103c_pdevs), .gpio_button_swnodes = asus_me176c_tf103c_lid_swnodes, - .bat_swnode = &generic_lipo_4v2_battery_node, + .swnode_group = generic_lipo_4v2_battery_swnodes, .modules = bq24190_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, }; diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index 955a2c83a9bf..5675e888d84f 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -153,7 +153,7 @@ static struct spi_device **spi_devs; static struct platform_device **pdevs; static struct serdev_device **serdevs; static const struct software_node **gpio_button_swnodes; -static const struct software_node *bat_swnode; +static const struct software_node **swnode_group; static const struct software_node **gpiochip_node_group; static void (*exit_handler)(void); @@ -390,8 +390,8 @@ static void x86_android_tablet_remove(struct platform_device *pdev) if (gpio_button_swnodes) software_node_unregister_node_group(gpio_button_swnodes); - if (bat_swnode) - software_node_unregister(bat_swnode); + if (swnode_group) + software_node_unregister_node_group(swnode_group); if (gpiochip_node_group) software_node_unregister_node_group(gpiochip_node_group); @@ -436,13 +436,13 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev) return ret; } - if (dev_info->bat_swnode) { - ret = software_node_register(dev_info->bat_swnode); + if (dev_info->swnode_group) { + ret = software_node_register_node_group(dev_info->swnode_group); if (ret) { x86_android_tablet_remove(pdev); return ret; } - bat_swnode = dev_info->bat_swnode; + swnode_group = dev_info->swnode_group; } if (dev_info->init) { diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 9a28216642c3..66617f6ff13e 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -448,7 +448,7 @@ const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { .pdev_info = lenovo_yoga_tab2_830_1050_pdevs, .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_pdevs), .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, - .bat_swnode = &generic_lipo_hv_4v35_battery_node, + .swnode_group = generic_lipo_hv_4v35_battery_swnodes, .modules = bq24190_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, .init = lenovo_yoga_tab2_830_1050_init, @@ -812,7 +812,7 @@ const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { .pdev_info = lenovo_yoga_tab2_1380_pdevs, .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_pdevs), .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, - .bat_swnode = &generic_lipo_hv_4v35_battery_node, + .swnode_group = generic_lipo_hv_4v35_battery_swnodes, .modules = lenovo_yoga_tab2_1380_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, .init = lenovo_yoga_tab2_1380_init, diff --git a/drivers/platform/x86/x86-android-tablets/shared-psy-info.c b/drivers/platform/x86/x86-android-tablets/shared-psy-info.c index 6ebe282bda6e..62f41c14e6ba 100644 --- a/drivers/platform/x86/x86-android-tablets/shared-psy-info.c +++ b/drivers/platform/x86/x86-android-tablets/shared-psy-info.c @@ -113,6 +113,11 @@ const struct software_node generic_lipo_4v2_battery_node = { .properties = generic_lipo_4v2_battery_props, }; +const struct software_node *generic_lipo_4v2_battery_swnodes[] = { + &generic_lipo_4v2_battery_node, + NULL +}; + /* LiPo HighVoltage (max 4.35V) settings used by most devs with a HV battery */ static const struct property_entry generic_lipo_hv_4v35_battery_props[] = { PROPERTY_ENTRY_STRING("compatible", "simple-battery"), @@ -133,6 +138,11 @@ const struct software_node generic_lipo_hv_4v35_battery_node = { .properties = generic_lipo_hv_4v35_battery_props, }; +const struct software_node *generic_lipo_hv_4v35_battery_swnodes[] = { + &generic_lipo_hv_4v35_battery_node, + NULL +}; + /* For enabling the bq24190 5V boost based on id-pin */ static struct regulator_consumer_supply intel_int3496_consumer = { .supply = "vbus", diff --git a/drivers/platform/x86/x86-android-tablets/shared-psy-info.h b/drivers/platform/x86/x86-android-tablets/shared-psy-info.h index b9cbc291aa4d..e5ba1c65d62b 100644 --- a/drivers/platform/x86/x86-android-tablets/shared-psy-info.h +++ b/drivers/platform/x86/x86-android-tablets/shared-psy-info.h @@ -20,8 +20,12 @@ extern const char * const bq25890_psy[]; extern const struct software_node fg_bq24190_supply_node; extern const struct software_node fg_bq25890_supply_node; + extern const struct software_node generic_lipo_4v2_battery_node; +extern const struct software_node *generic_lipo_4v2_battery_swnodes[]; + extern const struct software_node generic_lipo_hv_4v35_battery_node; +extern const struct software_node *generic_lipo_hv_4v35_battery_swnodes[]; extern struct bq24190_platform_data bq24190_pdata; extern const char * const bq24190_modules[]; diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index f4a67a9b74ea..4bf4bcdf50c0 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -82,7 +82,7 @@ struct x86_serdev_info { struct x86_dev_info { const char * const *modules; - const struct software_node *bat_swnode; + const struct software_node **swnode_group; const struct x86_i2c_client_info *i2c_client_info; const struct x86_spi_dev_info *spi_dev_info; const struct platform_device_info *pdev_info; From 936ddb5398909d9e1255627386bc090ec8943558 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2025 22:07:06 +0200 Subject: [PATCH 2153/2711] platform/x86: x86-android-tablets: use swnode_group instead of manual registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace manually calling software_node_register_node_group() from init() with the new swnode_group registration mechanism. Note this also fixes a missing software_node_unregister_node_group() for lenovo_yt3_swnodes. Reviewed-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-14-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/lenovo.c | 21 +++++-------------- .../platform/x86/x86-android-tablets/other.c | 14 ++----------- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 66617f6ff13e..1f325b2947ab 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -436,6 +436,7 @@ static const struct software_node *lenovo_yoga_tab2_830_1050_swnodes[] = { &crystalcove_gpiochip_node, &arizona_gpiochip_node, &lenovo_yoga_tab2_830_1050_wm5102, + &generic_lipo_hv_4v35_battery_node, NULL }; @@ -448,7 +449,7 @@ const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { .pdev_info = lenovo_yoga_tab2_830_1050_pdevs, .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_pdevs), .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, - .swnode_group = generic_lipo_hv_4v35_battery_swnodes, + .swnode_group = lenovo_yoga_tab2_830_1050_swnodes, .modules = bq24190_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, .init = lenovo_yoga_tab2_830_1050_init, @@ -534,24 +535,16 @@ static int __init lenovo_yoga_tab2_830_1050_init_codec(void) goto err_unregister_mappings; } - ret = software_node_register_node_group(lenovo_yoga_tab2_830_1050_swnodes); - if (ret) { - ret = dev_err_probe(codec_dev, ret, "registering software nodes\n"); - goto err_put_pinctrl; - } - ret = device_add_software_node(codec_dev, &lenovo_yoga_tab2_830_1050_wm5102); if (ret) { ret = dev_err_probe(codec_dev, ret, "adding software node\n"); - goto err_unregister_swnodes; + goto err_put_pinctrl; } lenovo_yoga_tab2_830_1050_codec_dev = codec_dev; lenovo_yoga_tab2_830_1050_codec_pinctrl = pinctrl; return 0; -err_unregister_swnodes: - software_node_unregister_node_group(lenovo_yoga_tab2_830_1050_swnodes); err_put_pinctrl: pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl); err_unregister_mappings: @@ -604,7 +597,6 @@ static void lenovo_yoga_tab2_830_1050_exit(void) if (lenovo_yoga_tab2_830_1050_codec_dev) { device_remove_software_node(lenovo_yoga_tab2_830_1050_codec_dev); put_device(lenovo_yoga_tab2_830_1050_codec_dev); - software_node_unregister_node_group(lenovo_yoga_tab2_830_1050_swnodes); } if (lenovo_yoga_tab2_830_1050_codec_pinctrl) { @@ -812,7 +804,7 @@ const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { .pdev_info = lenovo_yoga_tab2_1380_pdevs, .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_pdevs), .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, - .swnode_group = generic_lipo_hv_4v35_battery_swnodes, + .swnode_group = lenovo_yoga_tab2_830_1050_swnodes, .modules = lenovo_yoga_tab2_1380_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, .init = lenovo_yoga_tab2_1380_init, @@ -1071,10 +1063,6 @@ static int __init lenovo_yt3_init(struct device *dev) intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0x9b, 0x02, 0xff); intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0xa0, 0x02, 0xff); - ret = software_node_register_node_group(lenovo_yt3_swnodes); - if (ret) - return dev_err_probe(dev, ret, "registering software nodes\n"); - return 0; } @@ -1083,6 +1071,7 @@ const struct x86_dev_info lenovo_yt3_info __initconst = { .i2c_client_count = ARRAY_SIZE(lenovo_yt3_i2c_clients), .spi_dev_info = lenovo_yt3_spi_devs, .spi_dev_count = ARRAY_SIZE(lenovo_yt3_spi_devs), + .swnode_group = lenovo_yt3_swnodes, .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, .init = lenovo_yt3_init, }; diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index 1362f4167e3d..174f02322e52 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -895,7 +895,6 @@ static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev, static int __init xiaomi_mipad2_init(struct device *dev) { struct led_classdev *led_cdev; - int ret; xiaomi_mipad2_led_pwm = devm_pwm_get(dev, "pwm_soc_lpss_2"); if (IS_ERR(xiaomi_mipad2_led_pwm)) @@ -912,16 +911,7 @@ static int __init xiaomi_mipad2_init(struct device *dev) /* Turn LED off during suspend */ led_cdev->flags = LED_CORE_SUSPENDRESUME; - ret = devm_led_classdev_register(dev, led_cdev); - if (ret) - return dev_err_probe(dev, ret, "registering LED\n"); - - return software_node_register_node_group(ktd2026_node_group); -} - -static void xiaomi_mipad2_exit(void) -{ - software_node_unregister_node_group(ktd2026_node_group); + return devm_led_classdev_register(dev, led_cdev); } /* @@ -956,6 +946,6 @@ static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst const struct x86_dev_info xiaomi_mipad2_info __initconst = { .i2c_client_info = xiaomi_mipad2_i2c_clients, .i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients), + .swnode_group = ktd2026_node_group, .init = xiaomi_mipad2_init, - .exit = xiaomi_mipad2_exit, }; From 2bb596a7d2375d2a2218b0cc5b028f0f86e9fed9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2025 22:07:07 +0200 Subject: [PATCH 2154/2711] platform/x86: x86-android-tablets: Simplify node-group [un]registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit software_node_register_node_group() / software_node_unregister_node_group() both accept a NULL node-group as argument. So there is no need to check for the node-group being NULL before calling these functions, remove the checks to simplify the code. Note the "if (gpio_button_swnodes)" check for registering is kept because that also guards the creation of a gpio-button platform-device. Suggested-by: Andy Shevchenko Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250920200713.20193-15-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/core.c | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index 5675e888d84f..d0638664d1da 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -387,14 +387,9 @@ static void x86_android_tablet_remove(struct platform_device *pdev) if (exit_handler) exit_handler(); - if (gpio_button_swnodes) - software_node_unregister_node_group(gpio_button_swnodes); - - if (swnode_group) - software_node_unregister_node_group(swnode_group); - - if (gpiochip_node_group) - software_node_unregister_node_group(gpiochip_node_group); + software_node_unregister_node_group(gpio_button_swnodes); + software_node_unregister_node_group(swnode_group); + software_node_unregister_node_group(gpiochip_node_group); } static __init int x86_android_tablet_probe(struct platform_device *pdev) @@ -430,20 +425,16 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev) break; } - if (gpiochip_node_group) { - ret = software_node_register_node_group(gpiochip_node_group); - if (ret) - return ret; - } + ret = software_node_register_node_group(gpiochip_node_group); + if (ret) + return ret; - if (dev_info->swnode_group) { - ret = software_node_register_node_group(dev_info->swnode_group); - if (ret) { - x86_android_tablet_remove(pdev); - return ret; - } - swnode_group = dev_info->swnode_group; + ret = software_node_register_node_group(dev_info->swnode_group); + if (ret) { + x86_android_tablet_remove(pdev); + return ret; } + swnode_group = dev_info->swnode_group; if (dev_info->init) { ret = dev_info->init(&pdev->dev); From e5e12fab129458b32f76ac6019132661f1f1737c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2025 22:07:08 +0200 Subject: [PATCH 2155/2711] platform/x86: x86-android-tablets: Update my email address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hdegoede@redhat.com will stop working soon, replace it with my kernel.org address. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-16-hansg@kernel.org Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/x86-android-tablets/asus.c | 2 +- drivers/platform/x86/x86-android-tablets/core.c | 4 ++-- drivers/platform/x86/x86-android-tablets/dmi.c | 2 +- drivers/platform/x86/x86-android-tablets/lenovo.c | 2 +- drivers/platform/x86/x86-android-tablets/other.c | 2 +- drivers/platform/x86/x86-android-tablets/shared-psy-info.c | 2 +- drivers/platform/x86/x86-android-tablets/shared-psy-info.h | 2 +- drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c | 2 +- .../platform/x86/x86-android-tablets/x86-android-tablets.h | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/asus.c b/drivers/platform/x86/x86-android-tablets/asus.c index 39eb2f9dc031..7d29c7654d21 100644 --- a/drivers/platform/x86/x86-android-tablets/asus.c +++ b/drivers/platform/x86/x86-android-tablets/asus.c @@ -5,7 +5,7 @@ * devices typically have a bunch of things hardcoded, rather than specified * in their DSDT. * - * Copyright (C) 2021-2023 Hans de Goede + * Copyright (C) 2021-2023 Hans de Goede */ #include diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index d0638664d1da..a8e9fa97b676 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -5,7 +5,7 @@ * devices typically have a bunch of things hardcoded, rather than specified * in their DSDT. * - * Copyright (C) 2021-2023 Hans de Goede + * Copyright (C) 2021-2023 Hans de Goede */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -558,6 +558,6 @@ static void __exit x86_android_tablet_exit(void) } module_exit(x86_android_tablet_exit); -MODULE_AUTHOR("Hans de Goede "); +MODULE_AUTHOR("Hans de Goede "); MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/x86-android-tablets/dmi.c b/drivers/platform/x86/x86-android-tablets/dmi.c index 278c6d151dc4..ebba7400d5c9 100644 --- a/drivers/platform/x86/x86-android-tablets/dmi.c +++ b/drivers/platform/x86/x86-android-tablets/dmi.c @@ -5,7 +5,7 @@ * devices typically have a bunch of things hardcoded, rather than specified * in their DSDT. * - * Copyright (C) 2021-2023 Hans de Goede + * Copyright (C) 2021-2023 Hans de Goede */ #include diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 1f325b2947ab..832be02495b5 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -5,7 +5,7 @@ * devices typically have a bunch of things hardcoded, rather than specified * in their DSDT. * - * Copyright (C) 2021-2023 Hans de Goede + * Copyright (C) 2021-2023 Hans de Goede */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index 174f02322e52..bc473979e4f6 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -5,7 +5,7 @@ * devices typically have a bunch of things hardcoded, rather than specified * in their DSDT. * - * Copyright (C) 2021-2023 Hans de Goede + * Copyright (C) 2021-2023 Hans de Goede */ #include diff --git a/drivers/platform/x86/x86-android-tablets/shared-psy-info.c b/drivers/platform/x86/x86-android-tablets/shared-psy-info.c index 62f41c14e6ba..29fc466f76fe 100644 --- a/drivers/platform/x86/x86-android-tablets/shared-psy-info.c +++ b/drivers/platform/x86/x86-android-tablets/shared-psy-info.c @@ -5,7 +5,7 @@ * devices typically have a bunch of things hardcoded, rather than specified * in their DSDT. * - * Copyright (C) 2021-2023 Hans de Goede + * Copyright (C) 2021-2023 Hans de Goede */ #include diff --git a/drivers/platform/x86/x86-android-tablets/shared-psy-info.h b/drivers/platform/x86/x86-android-tablets/shared-psy-info.h index e5ba1c65d62b..149befba3330 100644 --- a/drivers/platform/x86/x86-android-tablets/shared-psy-info.h +++ b/drivers/platform/x86/x86-android-tablets/shared-psy-info.h @@ -5,7 +5,7 @@ * devices typically have a bunch of things hardcoded, rather than specified * in their DSDT. * - * Copyright (C) 2021-2023 Hans de Goede + * Copyright (C) 2021-2023 Hans de Goede */ #ifndef __PDX86_SHARED_PSY_INFO_H #define __PDX86_SHARED_PSY_INFO_H diff --git a/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c b/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c index 5d02af1c5aaa..2f8cd8d9e0ab 100644 --- a/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c +++ b/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c @@ -256,6 +256,6 @@ static struct i2c_driver atla10_ec_driver = { }; module_i2c_driver(atla10_ec_driver); -MODULE_AUTHOR("Hans de Goede "); +MODULE_AUTHOR("Hans de Goede "); MODULE_DESCRIPTION("Battery driver for Vexia EDU ATLA 10 tablet EC"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index 4bf4bcdf50c0..8e7d04bcb3f8 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -5,7 +5,7 @@ * devices typically have a bunch of things hardcoded, rather than specified * in their DSDT. * - * Copyright (C) 2021-2023 Hans de Goede + * Copyright (C) 2021-2023 Hans de Goede */ #ifndef __PDX86_X86_ANDROID_TABLETS_H #define __PDX86_X86_ANDROID_TABLETS_H From d4bc149653d33d373c90b6dcdcc51fb55b296c7f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2025 22:07:09 +0200 Subject: [PATCH 2156/2711] platform/x86: x86-android-tablets: Move Acer info to its own file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acer has several x86 based Android tablets which need x86-android-tablets support to work around their broken ACPI tables. At the moment x86-android-tablets only support one model, move this to its own file before adding support for more models to avoid needing to move more code around later. Reviewed-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-17-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/Makefile | 2 +- .../platform/x86/x86-android-tablets/acer.c | 87 +++++++++++++++++++ .../platform/x86/x86-android-tablets/other.c | 70 --------------- 3 files changed, 88 insertions(+), 71 deletions(-) create mode 100644 drivers/platform/x86/x86-android-tablets/acer.c diff --git a/drivers/platform/x86/x86-android-tablets/Makefile b/drivers/platform/x86/x86-android-tablets/Makefile index 313be30548bc..a2cf8cbdb351 100644 --- a/drivers/platform/x86/x86-android-tablets/Makefile +++ b/drivers/platform/x86/x86-android-tablets/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_X86_ANDROID_TABLETS) += vexia_atla10_ec.o obj-$(CONFIG_X86_ANDROID_TABLETS) += x86-android-tablets.o x86-android-tablets-y := core.o dmi.o shared-psy-info.o \ - asus.o lenovo.o other.o + acer.o asus.o lenovo.o other.o diff --git a/drivers/platform/x86/x86-android-tablets/acer.c b/drivers/platform/x86/x86-android-tablets/acer.c new file mode 100644 index 000000000000..e5850da8037a --- /dev/null +++ b/drivers/platform/x86/x86-android-tablets/acer.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Board info for Acer X86 tablets which ship with Android as the factory image + * and which have broken DSDT tables. The factory kernels shipped on these + * devices typically have a bunch of things hardcoded, rather than specified + * in their DSDT. + * + * Copyright (C) 2021-2025 Hans de Goede + */ + +#include +#include +#include +#include + +#include "shared-psy-info.h" +#include "x86-android-tablets.h" + +/* Acer Iconia One 7 B1-750 has an Android factory image with everything hardcoded */ +static const char * const acer_b1_750_mount_matrix[] = { + "-1", "0", "0", + "0", "1", "0", + "0", "0", "1" +}; + +static const struct property_entry acer_b1_750_bma250e_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", acer_b1_750_mount_matrix), + { } +}; + +static const struct software_node acer_b1_750_bma250e_node = { + .properties = acer_b1_750_bma250e_props, +}; + +static const struct property_entry acer_b1_750_novatek_props[] = { + PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node acer_b1_750_novatek_node = { + .properties = acer_b1_750_novatek_props, +}; + +static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = { + { + /* Novatek NVT-ts touchscreen */ + .board_info = { + .type = "nt11205-ts", + .addr = 0x34, + .dev_name = "NVT-ts", + .swnode = &acer_b1_750_novatek_node, + }, + .adapter_path = "\\_SB_.I2C4", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_GPIOINT, + .chip = "INT33FC:02", + .index = 3, + .trigger = ACPI_EDGE_SENSITIVE, + .polarity = ACPI_ACTIVE_LOW, + .con_id = "NVT-ts_irq", + }, + }, { + /* BMA250E accelerometer */ + .board_info = { + .type = "bma250e", + .addr = 0x18, + .swnode = &acer_b1_750_bma250e_node, + }, + .adapter_path = "\\_SB_.I2C3", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_GPIOINT, + .chip = "INT33FC:02", + .index = 25, + .trigger = ACPI_LEVEL_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + .con_id = "bma250e_irq", + }, + }, +}; + +const struct x86_dev_info acer_b1_750_info __initconst = { + .i2c_client_info = acer_b1_750_i2c_clients, + .i2c_client_count = ARRAY_SIZE(acer_b1_750_i2c_clients), + .pdev_info = int3496_pdevs, + .pdev_count = 1, + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, +}; diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index bc473979e4f6..ea7a01d7ccb4 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -22,76 +22,6 @@ #include "shared-psy-info.h" #include "x86-android-tablets.h" -/* Acer Iconia One 7 B1-750 has an Android factory image with everything hardcoded */ -static const char * const acer_b1_750_mount_matrix[] = { - "-1", "0", "0", - "0", "1", "0", - "0", "0", "1" -}; - -static const struct property_entry acer_b1_750_bma250e_props[] = { - PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", acer_b1_750_mount_matrix), - { } -}; - -static const struct software_node acer_b1_750_bma250e_node = { - .properties = acer_b1_750_bma250e_props, -}; - -static const struct property_entry acer_b1_750_novatek_props[] = { - PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_LOW), - { } -}; - -static const struct software_node acer_b1_750_novatek_node = { - .properties = acer_b1_750_novatek_props, -}; - -static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = { - { - /* Novatek NVT-ts touchscreen */ - .board_info = { - .type = "nt11205-ts", - .addr = 0x34, - .dev_name = "NVT-ts", - .swnode = &acer_b1_750_novatek_node, - }, - .adapter_path = "\\_SB_.I2C4", - .irq_data = { - .type = X86_ACPI_IRQ_TYPE_GPIOINT, - .chip = "INT33FC:02", - .index = 3, - .trigger = ACPI_EDGE_SENSITIVE, - .polarity = ACPI_ACTIVE_LOW, - .con_id = "NVT-ts_irq", - }, - }, { - /* BMA250E accelerometer */ - .board_info = { - .type = "bma250e", - .addr = 0x18, - .swnode = &acer_b1_750_bma250e_node, - }, - .adapter_path = "\\_SB_.I2C3", - .irq_data = { - .type = X86_ACPI_IRQ_TYPE_GPIOINT, - .chip = "INT33FC:02", - .index = 25, - .trigger = ACPI_LEVEL_SENSITIVE, - .polarity = ACPI_ACTIVE_HIGH, - .con_id = "bma250e_irq", - }, - }, -}; - -const struct x86_dev_info acer_b1_750_info __initconst = { - .i2c_client_info = acer_b1_750_i2c_clients, - .i2c_client_count = ARRAY_SIZE(acer_b1_750_i2c_clients), - .pdev_info = int3496_pdevs, - .pdev_count = 1, - .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, -}; - /* * Advantech MICA-071 * This is a standard Windows tablet, but it has an extra "quick launch" button From 6564d3e1a46b12990a02dafa948b311a45bc4991 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2025 22:07:10 +0200 Subject: [PATCH 2157/2711] platform/x86: x86-android-tablets: Add support for Acer A1-840 tablet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the Acer Iconia One 8 A1-840 (non FHD version) tablet. This tablet has the usual issues for tablets shipped with Android as factory OS. The DSDT is broken in various ways, so i2c_clients for various devices as well as the INT3496 platform-device for OTG extcon handling need to be instantiated manually by x86-android-tablets. This tablet is special in that it is the first time a Bay Trail device has been found to use the Dollar Cove TI PMIC and the first time that the PMIC's Coulomb Counter is used as fuel-gauge. So far this PMIC has only been used together with Cherry Trail SoCs and always in combination with a separate full-featured fuel-gauge IC. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-18-hansg@kernel.org Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/acer.c | 160 ++++++++++++++++++ .../platform/x86/x86-android-tablets/dmi.c | 10 ++ .../x86-android-tablets/x86-android-tablets.h | 1 + 3 files changed, 171 insertions(+) diff --git a/drivers/platform/x86/x86-android-tablets/acer.c b/drivers/platform/x86/x86-android-tablets/acer.c index e5850da8037a..d48c70ffd992 100644 --- a/drivers/platform/x86/x86-android-tablets/acer.c +++ b/drivers/platform/x86/x86-android-tablets/acer.c @@ -16,6 +16,166 @@ #include "shared-psy-info.h" #include "x86-android-tablets.h" +/* Acer Iconia One 8 A1-840 (non FHD version) */ +static const struct property_entry acer_a1_840_bq24190_props[] = { + PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_4v2_battery_node), + PROPERTY_ENTRY_BOOL("omit-battery-class"), + PROPERTY_ENTRY_BOOL("disable-reset"), + { } +}; + +static const struct software_node acer_a1_840_bq24190_node = { + .properties = acer_a1_840_bq24190_props, +}; + +static const struct property_entry acer_a1_840_touchscreen_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 800), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), + PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node acer_a1_840_touchscreen_node = { + .properties = acer_a1_840_touchscreen_props, +}; + +static const struct x86_i2c_client_info acer_a1_840_i2c_clients[] __initconst = { + { + /* BQ24297 charger IC */ + .board_info = { + .type = "bq24297", + .addr = 0x6b, + .dev_name = "bq24297", + .swnode = &acer_a1_840_bq24190_node, + .platform_data = &bq24190_pdata, + }, + .adapter_path = "\\_SB_.I2C1", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_GPIOINT, + .chip = "INT33FC:02", + .index = 2, + .trigger = ACPI_EDGE_SENSITIVE, + .polarity = ACPI_ACTIVE_LOW, + .con_id = "bq24297_irq", + }, + }, { + /* MPU6515 sensors */ + .board_info = { + .type = "mpu6515", + .addr = 0x69, + .dev_name = "mpu6515", + }, + .adapter_path = "\\_SB_.I2C3", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_APIC, + .index = 0x47, + .trigger = ACPI_EDGE_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + }, + }, { + /* FT5416 touchscreen controller */ + .board_info = { + .type = "edt-ft5x06", + .addr = 0x38, + .dev_name = "ft5416", + .swnode = &acer_a1_840_touchscreen_node, + }, + .adapter_path = "\\_SB_.I2C4", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_APIC, + .index = 0x45, + .trigger = ACPI_EDGE_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + }, + } +}; + +static const struct property_entry acer_a1_840_int3496_props[] __initconst = { + PROPERTY_ENTRY_GPIO("mux-gpios", &baytrail_gpiochip_nodes[2], 1, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("id-gpios", &baytrail_gpiochip_nodes[2], 18, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct platform_device_info acer_a1_840_pdevs[] __initconst = { + { + /* For micro USB ID pin handling */ + .name = "intel-int3496", + .id = PLATFORM_DEVID_NONE, + .properties = acer_a1_840_int3496_props, + }, +}; + +/* Properties for the Dollar Cove TI PMIC battery MFD child used as fuel-gauge */ +static const struct property_entry acer_a1_840_fg_props[] = { + PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_4v2_battery_node), + PROPERTY_ENTRY_STRING_ARRAY_LEN("supplied-from", bq24190_psy, 1), + PROPERTY_ENTRY_GPIO("charged-gpios", &baytrail_gpiochip_nodes[2], 10, GPIO_ACTIVE_HIGH), + { } +}; + +static struct device *acer_a1_840_fg_dev; +static struct fwnode_handle *acer_a1_840_fg_node; + +static int __init acer_a1_840_init(struct device *dev) +{ + int ret; + + acer_a1_840_fg_dev = bus_find_device_by_name(&platform_bus_type, NULL, "chtdc_ti_battery"); + if (!acer_a1_840_fg_dev) + return dev_err_probe(dev, -EPROBE_DEFER, "getting chtdc_ti_battery dev\n"); + + acer_a1_840_fg_node = fwnode_create_software_node(acer_a1_840_fg_props, NULL); + if (IS_ERR(acer_a1_840_fg_node)) { + ret = PTR_ERR(acer_a1_840_fg_node); + goto err_put; + } + + ret = device_add_software_node(acer_a1_840_fg_dev, + to_software_node(acer_a1_840_fg_node)); + if (ret) + goto err_put; + + return 0; + +err_put: + fwnode_handle_put(acer_a1_840_fg_node); + acer_a1_840_fg_node = NULL; + put_device(acer_a1_840_fg_dev); + acer_a1_840_fg_dev = NULL; + return ret; +} + +static void acer_a1_840_exit(void) +{ + device_remove_software_node(acer_a1_840_fg_dev); + /* + * Skip fwnode_handle_put(acer_a1_840_fg_node), instead leak the node. + * The intel_dc_ti_battery driver may still reference the strdup-ed + * "supplied-from" string. This string will be free-ed if the node + * is released. + */ + acer_a1_840_fg_node = NULL; + put_device(acer_a1_840_fg_dev); + acer_a1_840_fg_dev = NULL; +} + +static const char * const acer_a1_840_modules[] __initconst = { + "bq24190_charger", /* For the Vbus regulator for intel-int3496 */ + NULL +}; + +const struct x86_dev_info acer_a1_840_info __initconst = { + .i2c_client_info = acer_a1_840_i2c_clients, + .i2c_client_count = ARRAY_SIZE(acer_a1_840_i2c_clients), + .pdev_info = acer_a1_840_pdevs, + .pdev_count = ARRAY_SIZE(acer_a1_840_pdevs), + .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, + .swnode_group = generic_lipo_4v2_battery_swnodes, + .modules = acer_a1_840_modules, + .init = acer_a1_840_init, + .exit = acer_a1_840_exit, +}; + /* Acer Iconia One 7 B1-750 has an Android factory image with everything hardcoded */ static const char * const acer_b1_750_mount_matrix[] = { "-1", "0", "0", diff --git a/drivers/platform/x86/x86-android-tablets/dmi.c b/drivers/platform/x86/x86-android-tablets/dmi.c index ebba7400d5c9..4a5720d6fc1d 100644 --- a/drivers/platform/x86/x86-android-tablets/dmi.c +++ b/drivers/platform/x86/x86-android-tablets/dmi.c @@ -16,6 +16,16 @@ #include "x86-android-tablets.h" const struct dmi_system_id x86_android_tablet_ids[] __initconst = { + { + /* Acer Iconia One 8 A1-840 (non FHD version) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Above strings are too generic also match BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "04/01/2014"), + }, + .driver_data = (void *)&acer_a1_840_info, + }, { /* Acer Iconia One 7 B1-750 */ .matches = { diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index 8e7d04bcb3f8..2498390958ad 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -111,6 +111,7 @@ extern const struct software_node cherryview_gpiochip_nodes[]; * Extern declarations of x86_dev_info structs so there can be a single * MODULE_DEVICE_TABLE(dmi, ...), while splitting the board descriptions. */ +extern const struct x86_dev_info acer_a1_840_info; extern const struct x86_dev_info acer_b1_750_info; extern const struct x86_dev_info advantech_mica_071_info; extern const struct x86_dev_info asus_me176c_info; From 6b4bc1451c23f9e41c544c0f6aa8fea048492611 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2025 22:07:11 +0200 Subject: [PATCH 2158/2711] platform/x86: x86-android-tablets: Simplify lenovo_yoga_tab2_830_1050_exit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lenovo_yoga_tab2_830_1050_exit() only gets called after a successful lenovo_yoga_tab2_830_1050_init() call so there is no need to check if lenovo_yoga_tab2_830_1050_codec_[dev|pinctrl] are set. Also change the exit() order to be the exact reverse of init(). Reviewed-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-19-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/x86-android-tablets/lenovo.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 832be02495b5..08cabaa5e0c0 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -594,15 +594,10 @@ static void lenovo_yoga_tab2_830_1050_exit(void) { unregister_sys_off_handler(lenovo_yoga_tab2_830_1050_sys_off_handler); - if (lenovo_yoga_tab2_830_1050_codec_dev) { - device_remove_software_node(lenovo_yoga_tab2_830_1050_codec_dev); - put_device(lenovo_yoga_tab2_830_1050_codec_dev); - } - - if (lenovo_yoga_tab2_830_1050_codec_pinctrl) { - pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl); - pinctrl_unregister_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map); - } + device_remove_software_node(lenovo_yoga_tab2_830_1050_codec_dev); + pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl); + pinctrl_unregister_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map); + put_device(lenovo_yoga_tab2_830_1050_codec_dev); } /* From 83fdf93f4bf45bda99c292c550ff299e2c249b1f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2025 22:07:12 +0200 Subject: [PATCH 2159/2711] platform/x86: x86-android-tablets: Fix modules lists for Lenovo devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2 fixes for Lenovo tablets: - The bq24190 charger on the Lenovo Yoga Tab2 830/1050 devices does not use the crystal-cove PMIC charger IRQ, so these shouldn't use bq24190_modules as that includes "intel_crystal_cove_charger" - Both the Tab2 and the Tab3 devices have a SPI audio-codec which init() attaches properties to, resp. the whole SPI device gets instantiated by the x86-android-tablets code. This requires the "spi_pxa2xx_platform" module to be loaded before init() runs Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-20-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../platform/x86/x86-android-tablets/lenovo.c | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 08cabaa5e0c0..e3d3a8290949 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -443,6 +443,12 @@ static const struct software_node *lenovo_yoga_tab2_830_1050_swnodes[] = { static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev); static void lenovo_yoga_tab2_830_1050_exit(void); +static const char * const lenovo_yoga_tab2_modules[] __initconst = { + "spi_pxa2xx_platform", /* For the SPI codec device */ + "bq24190_charger", /* For the Vbus regulator for int3496/lc824206xa */ + NULL +}; + const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { .i2c_client_info = lenovo_yoga_tab2_830_1050_i2c_clients, .i2c_client_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients), @@ -450,7 +456,7 @@ const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_pdevs), .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, .swnode_group = lenovo_yoga_tab2_830_1050_swnodes, - .modules = bq24190_modules, + .modules = lenovo_yoga_tab2_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, .init = lenovo_yoga_tab2_830_1050_init, .exit = lenovo_yoga_tab2_830_1050_exit, @@ -767,11 +773,6 @@ static const struct platform_device_info lenovo_yoga_tab2_1380_pdevs[] __initcon }, }; -static const char * const lenovo_yoga_tab2_1380_modules[] __initconst = { - "bq24190_charger", /* For the Vbus regulator for lc824206xa */ - NULL -}; - static int __init lenovo_yoga_tab2_1380_init(struct device *dev) { int ret; @@ -800,7 +801,7 @@ const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_pdevs), .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, .swnode_group = lenovo_yoga_tab2_830_1050_swnodes, - .modules = lenovo_yoga_tab2_1380_modules, + .modules = lenovo_yoga_tab2_modules, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, .init = lenovo_yoga_tab2_1380_init, .exit = lenovo_yoga_tab2_830_1050_exit, @@ -1061,12 +1062,18 @@ static int __init lenovo_yt3_init(struct device *dev) return 0; } +static const char * const lenovo_yt3_modules[] __initconst = { + "spi_pxa2xx_platform", /* For the SPI codec device */ + NULL +}; + const struct x86_dev_info lenovo_yt3_info __initconst = { .i2c_client_info = lenovo_yt3_i2c_clients, .i2c_client_count = ARRAY_SIZE(lenovo_yt3_i2c_clients), .spi_dev_info = lenovo_yt3_spi_devs, .spi_dev_count = ARRAY_SIZE(lenovo_yt3_spi_devs), .swnode_group = lenovo_yt3_swnodes, + .modules = lenovo_yt3_modules, .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, .init = lenovo_yt3_init, }; From 01fd7cf3534aa107797d130f461ba7bcad30414d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 20 Sep 2025 22:07:13 +0200 Subject: [PATCH 2160/2711] platform/x86: x86-android-tablets: Stop using EPROBE_DEFER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the x86-android-tablets code uses platform_create_bundle() it cannot use EPROBE_DEFER and the driver-core will translate EPROBE_DEFER to ENXIO. Stop using EPROBE_DEFER instead log an error and return ENODEV, or for non-fatal cases log a warning and return 0. Reviewed-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250920200713.20193-21-hansg@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/x86-android-tablets/core.c | 6 ++++-- drivers/platform/x86/x86-android-tablets/other.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index a8e9fa97b676..6588fae30356 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -276,8 +276,10 @@ get_serdev_controller_by_pci_parent(const struct x86_serdev_info *info) struct pci_dev *pdev; pdev = pci_get_domain_bus_and_slot(0, 0, info->ctrl.pci.devfn); - if (!pdev) - return ERR_PTR(-EPROBE_DEFER); + if (!pdev) { + pr_err("error could not get PCI serdev at devfn 0x%02x\n", info->ctrl.pci.devfn); + return ERR_PTR(-ENODEV); + } /* This puts our reference on pdev and returns a ref on the ctrl */ return get_serdev_controller_from_parent(&pdev->dev, 0, info->ctrl_devname); diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index ea7a01d7ccb4..7532af2d72d1 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -711,8 +711,10 @@ static int __init vexia_edu_atla10_9v_init(struct device *dev) /* Reprobe the SDIO controller to enumerate the now enabled Wifi module */ pdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x11, 0)); - if (!pdev) - return -EPROBE_DEFER; + if (!pdev) { + pr_warn("Could not get PCI SDIO at devfn 0x%02x\n", PCI_DEVFN(0x11, 0)); + return 0; + } ret = device_reprobe(&pdev->dev); if (ret) From 4e0bcbd270e88800c4432715edd47964a080e52e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 10 Aug 2025 21:31:37 -0700 Subject: [PATCH 2161/2711] platform/x86: barco-p50-gpio: use software nodes for gpio-leds/keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation of dropping support for legacy GPIO API from gpio-keys switch the driver to use software nodes/properties to describe GPIO-connected LED and button. Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/2meuzip4qnxvle4bwk4hbow4j34ii3cwb46xd5inq5btif5mjg@iiygy6ir7vtr Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/barco-p50-gpio.c | 104 +++++++++++++++----------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/drivers/platform/x86/barco-p50-gpio.c b/drivers/platform/x86/barco-p50-gpio.c index 28012eebdb10..6f13e81f98fb 100644 --- a/drivers/platform/x86/barco-p50-gpio.c +++ b/drivers/platform/x86/barco-p50-gpio.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -18,10 +19,11 @@ #include #include #include -#include #include #include -#include +#include +#include +#include #define DRIVER_NAME "barco-p50-gpio" @@ -78,44 +80,57 @@ static const char * const gpio_names[] = { [P50_GPIO_LINE_BTN] = "identify-button", }; - -static struct gpiod_lookup_table p50_gpio_led_table = { - .dev_id = "leds-gpio", - .table = { - GPIO_LOOKUP_IDX(DRIVER_NAME, P50_GPIO_LINE_LED, NULL, 0, GPIO_ACTIVE_HIGH), - {} - } +static const struct software_node gpiochip_node = { + .name = DRIVER_NAME, }; /* GPIO LEDs */ -static struct gpio_led leds[] = { - { .name = "identify" } +static const struct software_node gpio_leds_node = { + .name = "gpio-leds-identify", }; -static struct gpio_led_platform_data leds_pdata = { - .num_leds = ARRAY_SIZE(leds), - .leds = leds, +static const struct property_entry identify_led_props[] = { + PROPERTY_ENTRY_GPIO("gpios", &gpiochip_node, P50_GPIO_LINE_LED, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node identify_led_node = { + .parent = &gpio_leds_node, + .name = "identify", + .properties = identify_led_props, }; /* GPIO keyboard */ -static struct gpio_keys_button buttons[] = { - { - .code = KEY_VENDOR, - .gpio = P50_GPIO_LINE_BTN, - .active_low = 1, - .type = EV_KEY, - .value = 1, - }, +static const struct property_entry gpio_keys_props[] = { + PROPERTY_ENTRY_STRING("label", "identify"), + PROPERTY_ENTRY_U32("poll-interval", 100), + { } }; -static struct gpio_keys_platform_data keys_pdata = { - .buttons = buttons, - .nbuttons = ARRAY_SIZE(buttons), - .poll_interval = 100, - .rep = 0, - .name = "identify", +static const struct software_node gpio_keys_node = { + .name = "gpio-keys-identify", + .properties = gpio_keys_props, }; +static struct property_entry vendor_key_props[] = { + PROPERTY_ENTRY_U32("linux,code", KEY_VENDOR), + PROPERTY_ENTRY_GPIO("gpios", &gpiochip_node, P50_GPIO_LINE_BTN, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node vendor_key_node = { + .parent = &gpio_keys_node, + .properties = vendor_key_props, +}; + +static const struct software_node *p50_swnodes[] = { + &gpiochip_node, + &gpio_leds_node, + &identify_led_node, + &gpio_keys_node, + &vendor_key_node, + NULL +}; /* low level access routines */ @@ -285,6 +300,16 @@ static int p50_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) static int p50_gpio_probe(struct platform_device *pdev) { + struct platform_device_info key_info = { + .name = "gpio-keys-polled", + .id = PLATFORM_DEVID_NONE, + .parent = &pdev->dev, + }; + struct platform_device_info led_info = { + .name = "leds-gpio", + .id = PLATFORM_DEVID_NONE, + .parent = &pdev->dev, + }; struct p50_gpio *p50; struct resource *res; int ret; @@ -339,25 +364,20 @@ static int p50_gpio_probe(struct platform_device *pdev) return ret; } - gpiod_add_lookup_table(&p50_gpio_led_table); - - p50->leds_pdev = platform_device_register_data(&pdev->dev, - "leds-gpio", PLATFORM_DEVID_NONE, &leds_pdata, sizeof(leds_pdata)); + ret = software_node_register_node_group(p50_swnodes); + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to register software nodes"); + led_info.fwnode = software_node_fwnode(&gpio_leds_node); + p50->leds_pdev = platform_device_register_full(&led_info); if (IS_ERR(p50->leds_pdev)) { ret = PTR_ERR(p50->leds_pdev); dev_err(&pdev->dev, "Could not register leds-gpio: %d\n", ret); goto err_leds; } - /* gpio-keys-polled uses old-style gpio interface, pass the right identifier */ - buttons[0].gpio += p50->gc.base; - - p50->keys_pdev = - platform_device_register_data(&pdev->dev, "gpio-keys-polled", - PLATFORM_DEVID_NONE, - &keys_pdata, sizeof(keys_pdata)); - + key_info.fwnode = software_node_fwnode(&gpio_keys_node); + p50->keys_pdev = platform_device_register_full(&key_info); if (IS_ERR(p50->keys_pdev)) { ret = PTR_ERR(p50->keys_pdev); dev_err(&pdev->dev, "Could not register gpio-keys-polled: %d\n", ret); @@ -369,7 +389,7 @@ static int p50_gpio_probe(struct platform_device *pdev) err_keys: platform_device_unregister(p50->leds_pdev); err_leds: - gpiod_remove_lookup_table(&p50_gpio_led_table); + software_node_unregister_node_group(p50_swnodes); return ret; } @@ -381,7 +401,7 @@ static void p50_gpio_remove(struct platform_device *pdev) platform_device_unregister(p50->keys_pdev); platform_device_unregister(p50->leds_pdev); - gpiod_remove_lookup_table(&p50_gpio_led_table); + software_node_unregister_node_group(p50_swnodes); } static struct platform_driver p50_gpio_driver = { From a2a815233c3068e3d41e15ee4dc4c19f256840df Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 11 Aug 2025 15:47:09 -0700 Subject: [PATCH 2162/2711] platform/x86: meraki-mx100: Use static device properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the Meraki MX100 board driver to use software nodes and static device properties to describe the on-board LEDs and reset button. This moves away from the legacy gpiod_lookup_table and platform_data mechanisms, allowing consumer drivers like leds-gpio and gpio-keys to rely on the unified device properties interface instead of board-specific data. Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/dzecghqrsrbe74akboqih7xculdm53rbhxa7dimt2ysdevyskd@hxhd2j3vnlt5 Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/meraki-mx100.c | 404 ++++++++++++++++++---------- 1 file changed, 262 insertions(+), 142 deletions(-) diff --git a/drivers/platform/x86/meraki-mx100.c b/drivers/platform/x86/meraki-mx100.c index 3751ed36a980..8c5276d98512 100644 --- a/drivers/platform/x86/meraki-mx100.c +++ b/drivers/platform/x86/meraki-mx100.c @@ -15,135 +15,256 @@ #include #include -#include #include -#include +#include +#include #include #include -#include #include #include +#include #define TINK_GPIO_DRIVER_NAME "gpio_ich" +static const struct software_node gpio_ich_node = { + .name = TINK_GPIO_DRIVER_NAME, +}; + /* LEDs */ -static const struct gpio_led tink_leds[] = { - { - .name = "mx100:green:internet", - .default_trigger = "default-on", - }, - { - .name = "mx100:green:lan2", - }, - { - .name = "mx100:green:lan3", - }, - { - .name = "mx100:green:lan4", - }, - { - .name = "mx100:green:lan5", - }, - { - .name = "mx100:green:lan6", - }, - { - .name = "mx100:green:lan7", - }, - { - .name = "mx100:green:lan8", - }, - { - .name = "mx100:green:lan9", - }, - { - .name = "mx100:green:lan10", - }, - { - .name = "mx100:green:lan11", - }, - { - .name = "mx100:green:ha", - }, - { - .name = "mx100:orange:ha", - }, - { - .name = "mx100:green:usb", - }, - { - .name = "mx100:orange:usb", - }, +static const struct software_node tink_gpio_leds_node = { + .name = "meraki-mx100-leds", }; -static const struct gpio_led_platform_data tink_leds_pdata = { - .num_leds = ARRAY_SIZE(tink_leds), - .leds = tink_leds, +static const struct property_entry tink_internet_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:internet"), + PROPERTY_ENTRY_STRING("linux,default-trigger", "default-on"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 11, GPIO_ACTIVE_LOW), + { } }; -static struct gpiod_lookup_table tink_leds_table = { - .dev_id = "leds-gpio", - .table = { - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 11, - NULL, 0, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 18, - NULL, 1, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 20, - NULL, 2, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 22, - NULL, 3, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 23, - NULL, 4, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 32, - NULL, 5, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 34, - NULL, 6, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 35, - NULL, 7, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 36, - NULL, 8, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 37, - NULL, 9, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 48, - NULL, 10, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 16, - NULL, 11, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 7, - NULL, 12, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 21, - NULL, 13, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 19, - NULL, 14, GPIO_ACTIVE_LOW), - {} /* Terminating entry */ - } +static const struct software_node tink_internet_led_node = { + .name = "internet-led", + .parent = &tink_gpio_leds_node, + .properties = tink_internet_led_props, +}; + +static const struct property_entry tink_lan2_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:lan2"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 18, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node tink_lan2_led_node = { + .name = "lan2-led", + .parent = &tink_gpio_leds_node, + .properties = tink_lan2_led_props, +}; + +static const struct property_entry tink_lan3_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:lan3"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 20, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node tink_lan3_led_node = { + .name = "lan3-led", + .parent = &tink_gpio_leds_node, + .properties = tink_lan3_led_props, +}; + +static const struct property_entry tink_lan4_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:lan4"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 22, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node tink_lan4_led_node = { + .name = "lan4-led", + .parent = &tink_gpio_leds_node, + .properties = tink_lan4_led_props, +}; + +static const struct property_entry tink_lan5_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:lan5"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 23, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node tink_lan5_led_node = { + .name = "lan5-led", + .parent = &tink_gpio_leds_node, + .properties = tink_lan5_led_props, +}; + +static const struct property_entry tink_lan6_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:lan6"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 32, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node tink_lan6_led_node = { + .name = "lan6-led", + .parent = &tink_gpio_leds_node, + .properties = tink_lan6_led_props, +}; + +static const struct property_entry tink_lan7_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:lan7"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 34, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node tink_lan7_led_node = { + .name = "lan7-led", + .parent = &tink_gpio_leds_node, + .properties = tink_lan7_led_props, +}; + +static const struct property_entry tink_lan8_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:lan8"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 35, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node tink_lan8_led_node = { + .name = "lan8-led", + .parent = &tink_gpio_leds_node, + .properties = tink_lan8_led_props, +}; + +static const struct property_entry tink_lan9_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:lan9"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 36, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node tink_lan9_led_node = { + .name = "lan9-led", + .parent = &tink_gpio_leds_node, + .properties = tink_lan9_led_props, +}; + +static const struct property_entry tink_lan10_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:lan10"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 37, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node tink_lan10_led_node = { + .name = "lan10-led", + .parent = &tink_gpio_leds_node, + .properties = tink_lan10_led_props, +}; + +static const struct property_entry tink_lan11_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:lan11"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 48, GPIO_ACTIVE_HIGH), + { } +}; + +static const struct software_node tink_lan11_led_node = { + .name = "lan11-led", + .parent = &tink_gpio_leds_node, + .properties = tink_lan11_led_props, +}; + +static const struct property_entry tink_ha_green_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:ha"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 16, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node tink_ha_green_led_node = { + .name = "ha-green-led", + .parent = &tink_gpio_leds_node, + .properties = tink_ha_green_led_props, +}; + +static const struct property_entry tink_ha_orange_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:orange:ha"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 7, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node tink_ha_orange_led_node = { + .name = "ha-orange-led", + .parent = &tink_gpio_leds_node, + .properties = tink_ha_orange_led_props, +}; + +static const struct property_entry tink_usb_green_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:green:usb"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 21, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node tink_usb_green_led_node = { + .name = "usb-green-led", + .parent = &tink_gpio_leds_node, + .properties = tink_usb_green_led_props, +}; + +static const struct property_entry tink_usb_orange_led_props[] = { + PROPERTY_ENTRY_STRING("label", "mx100:orange:usb"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 19, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node tink_usb_orange_led_node = { + .name = "usb-orange-led", + .parent = &tink_gpio_leds_node, + .properties = tink_usb_orange_led_props, }; /* Reset Button */ -static struct gpio_keys_button tink_buttons[] = { - { - .desc = "Reset", - .type = EV_KEY, - .code = KEY_RESTART, - .active_low = 1, - .debounce_interval = 100, - }, +static const struct property_entry tink_gpio_keys_props[] = { + PROPERTY_ENTRY_U32("poll-interval", 20), + { } }; -static const struct gpio_keys_platform_data tink_buttons_pdata = { - .buttons = tink_buttons, - .nbuttons = ARRAY_SIZE(tink_buttons), - .poll_interval = 20, - .rep = 0, - .name = "mx100-keys", +static const struct software_node tink_gpio_keys_node = { + .name = "mx100-keys", + .properties = tink_gpio_keys_props, }; -static struct gpiod_lookup_table tink_keys_table = { - .dev_id = "gpio-keys-polled", - .table = { - GPIO_LOOKUP_IDX(TINK_GPIO_DRIVER_NAME, 60, - NULL, 0, GPIO_ACTIVE_LOW), - {} /* Terminating entry */ - } +static const struct property_entry tink_reset_key_props[] = { + PROPERTY_ENTRY_U32("linux,code", KEY_RESTART), + PROPERTY_ENTRY_STRING("label", "Reset"), + PROPERTY_ENTRY_GPIO("gpios", &gpio_ich_node, 60, GPIO_ACTIVE_LOW), + PROPERTY_ENTRY_U32("linux,input-type", EV_KEY), + PROPERTY_ENTRY_U32("debounce-interval", 100), + { } +}; + +static const struct software_node tink_reset_key_node = { + .name = "reset", + .parent = &tink_gpio_keys_node, + .properties = tink_reset_key_props, +}; + +static const struct software_node *tink_swnodes[] = { + &gpio_ich_node, + /* LEDs nodes */ + &tink_gpio_leds_node, + &tink_internet_led_node, + &tink_lan2_led_node, + &tink_lan3_led_node, + &tink_lan4_led_node, + &tink_lan5_led_node, + &tink_lan6_led_node, + &tink_lan7_led_node, + &tink_lan8_led_node, + &tink_lan9_led_node, + &tink_lan10_led_node, + &tink_lan11_led_node, + &tink_ha_green_led_node, + &tink_ha_orange_led_node, + &tink_usb_green_led_node, + &tink_usb_orange_led_node, + /* Keys nodes */ + &tink_gpio_keys_node, + &tink_reset_key_node, + NULL }; /* Board setup */ @@ -161,22 +282,17 @@ MODULE_DEVICE_TABLE(dmi, tink_systems); static struct platform_device *tink_leds_pdev; static struct platform_device *tink_keys_pdev; -static struct platform_device * __init tink_create_dev( - const char *name, const void *pdata, size_t sz) -{ - struct platform_device *pdev; - - pdev = platform_device_register_data(NULL, - name, PLATFORM_DEVID_NONE, pdata, sz); - if (IS_ERR(pdev)) - pr_err("failed registering %s: %ld\n", name, PTR_ERR(pdev)); - - return pdev; -} - static int __init tink_board_init(void) { - int ret; + struct platform_device_info keys_info = { + .name = "gpio-keys-polled", + .id = PLATFORM_DEVID_NONE, + }; + struct platform_device_info leds_info = { + .name = "leds-gpio", + .id = PLATFORM_DEVID_NONE, + }; + int err; if (!dmi_first_match(tink_systems)) return -ENODEV; @@ -188,30 +304,35 @@ static int __init tink_board_init(void) */ outl(inl(0x530) | BIT(28), 0x530); - gpiod_add_lookup_table(&tink_leds_table); - gpiod_add_lookup_table(&tink_keys_table); - - tink_leds_pdev = tink_create_dev("leds-gpio", - &tink_leds_pdata, sizeof(tink_leds_pdata)); - if (IS_ERR(tink_leds_pdev)) { - ret = PTR_ERR(tink_leds_pdev); - goto err; + err = software_node_register_node_group(tink_swnodes); + if (err) { + pr_err("failed to register software nodes: %d\n", err); + return err; } - tink_keys_pdev = tink_create_dev("gpio-keys-polled", - &tink_buttons_pdata, sizeof(tink_buttons_pdata)); + leds_info.fwnode = software_node_fwnode(&tink_gpio_leds_node); + tink_leds_pdev = platform_device_register_full(&leds_info); + if (IS_ERR(tink_leds_pdev)) { + err = PTR_ERR(tink_leds_pdev); + pr_err("failed to create LED device: %d\n", err); + goto err_unregister_swnodes; + } + + keys_info.fwnode = software_node_fwnode(&tink_gpio_keys_node); + tink_keys_pdev = platform_device_register_full(&keys_info); if (IS_ERR(tink_keys_pdev)) { - ret = PTR_ERR(tink_keys_pdev); - platform_device_unregister(tink_leds_pdev); - goto err; + err = PTR_ERR(tink_keys_pdev); + pr_err("failed to create key device: %d\n", err); + goto err_unregister_leds; } return 0; -err: - gpiod_remove_lookup_table(&tink_keys_table); - gpiod_remove_lookup_table(&tink_leds_table); - return ret; +err_unregister_leds: + platform_device_unregister(tink_leds_pdev); +err_unregister_swnodes: + software_node_unregister_node_group(tink_swnodes); + return err; } module_init(tink_board_init); @@ -219,8 +340,7 @@ static void __exit tink_board_exit(void) { platform_device_unregister(tink_keys_pdev); platform_device_unregister(tink_leds_pdev); - gpiod_remove_lookup_table(&tink_keys_table); - gpiod_remove_lookup_table(&tink_leds_table); + software_node_unregister_node_group(tink_swnodes); } module_exit(tink_board_exit); From b8754092dfed4fc2fcdb0de32a029ba8f9b464b6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 11 Aug 2025 15:50:05 -0700 Subject: [PATCH 2163/2711] platform/x86: pcengines-apuv2: Use static device properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the PC Engines APUv2/v3 board driver to use software nodes and static device properties for its on-board LEDs and front button. This change replaces the legacy gpiod_lookup_table and platform_data with a modern software node implementation, which allows the leds-gpio and gpio-keys drivers to use the standard device properties API. Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/yaaegm5z2vtkl6ci5jpfnv42aywfjtoqw3bjgtli43ypask2r6@a7gg37rwkpx2 Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/pcengines-apuv2.c | 196 +++++++++++++++---------- 1 file changed, 120 insertions(+), 76 deletions(-) diff --git a/drivers/platform/x86/pcengines-apuv2.c b/drivers/platform/x86/pcengines-apuv2.c index 3aa63b18a2e1..3b086863c6ac 100644 --- a/drivers/platform/x86/pcengines-apuv2.c +++ b/drivers/platform/x86/pcengines-apuv2.c @@ -12,13 +12,13 @@ #include #include +#include +#include +#include #include -#include #include #include -#include -#include -#include +#include #include /* @@ -72,60 +72,91 @@ static const struct amd_fch_gpio_pdata board_apu2 = { .gpio_names = apu2_gpio_names, }; +static const struct software_node apu2_gpiochip_node = { + .name = AMD_FCH_GPIO_DRIVER_NAME, +}; + /* GPIO LEDs device */ - -static const struct gpio_led apu2_leds[] = { - { .name = "apu:green:1" }, - { .name = "apu:green:2" }, - { .name = "apu:green:3" }, +static const struct software_node apu2_leds_node = { + .name = "apu2-leds", }; -static const struct gpio_led_platform_data apu2_leds_pdata = { - .num_leds = ARRAY_SIZE(apu2_leds), - .leds = apu2_leds, +static const struct property_entry apu2_led1_props[] = { + PROPERTY_ENTRY_STRING("label", "apu:green:1"), + PROPERTY_ENTRY_GPIO("gpios", &apu2_gpiochip_node, + APU2_GPIO_LINE_LED1, GPIO_ACTIVE_LOW), + { } }; -static struct gpiod_lookup_table gpios_led_table = { - .dev_id = "leds-gpio", - .table = { - GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED1, - NULL, 0, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED2, - NULL, 1, GPIO_ACTIVE_LOW), - GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED3, - NULL, 2, GPIO_ACTIVE_LOW), - {} /* Terminating entry */ - } +static const struct software_node apu2_led1_swnode = { + .name = "led-1", + .parent = &apu2_leds_node, + .properties = apu2_led1_props, +}; + +static const struct property_entry apu2_led2_props[] = { + PROPERTY_ENTRY_STRING("label", "apu:green:2"), + PROPERTY_ENTRY_GPIO("gpios", &apu2_gpiochip_node, + APU2_GPIO_LINE_LED2, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node apu2_led2_swnode = { + .name = "led-2", + .parent = &apu2_leds_node, + .properties = apu2_led2_props, +}; + +static const struct property_entry apu2_led3_props[] = { + PROPERTY_ENTRY_STRING("label", "apu:green:3"), + PROPERTY_ENTRY_GPIO("gpios", &apu2_gpiochip_node, + APU2_GPIO_LINE_LED3, GPIO_ACTIVE_LOW), + { } +}; + +static const struct software_node apu2_led3_swnode = { + .name = "led-3", + .parent = &apu2_leds_node, + .properties = apu2_led3_props, }; /* GPIO keyboard device */ - -static struct gpio_keys_button apu2_keys_buttons[] = { - { - .code = KEY_RESTART, - .active_low = 1, - .desc = "front button", - .type = EV_KEY, - .debounce_interval = 10, - .value = 1, - }, +static const struct property_entry apu2_keys_props[] = { + PROPERTY_ENTRY_U32("poll-interval", 100), + { } }; -static const struct gpio_keys_platform_data apu2_keys_pdata = { - .buttons = apu2_keys_buttons, - .nbuttons = ARRAY_SIZE(apu2_keys_buttons), - .poll_interval = 100, - .rep = 0, - .name = "apu2-keys", +static const struct software_node apu2_keys_node = { + .name = "apu2-keys", + .properties = apu2_keys_props, }; -static struct gpiod_lookup_table gpios_key_table = { - .dev_id = "gpio-keys-polled", - .table = { - GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_MODESW, - NULL, 0, GPIO_ACTIVE_LOW), - {} /* Terminating entry */ - } +static const struct property_entry apu2_front_button_props[] = { + PROPERTY_ENTRY_STRING("label", "front button"), + PROPERTY_ENTRY_U32("linux,code", KEY_RESTART), + PROPERTY_ENTRY_GPIO("gpios", &apu2_gpiochip_node, + APU2_GPIO_LINE_MODESW, GPIO_ACTIVE_LOW), + PROPERTY_ENTRY_U32("debounce-interval", 10), + { } +}; + +static const struct software_node apu2_front_button_swnode = { + .name = "front-button", + .parent = &apu2_keys_node, + .properties = apu2_front_button_props, +}; + +static const struct software_node *apu2_swnodes[] = { + &apu2_gpiochip_node, + /* LEDs nodes */ + &apu2_leds_node, + &apu2_led1_swnode, + &apu2_led2_swnode, + &apu2_led3_swnode, + /* Keys nodes */ + &apu2_keys_node, + &apu2_front_button_swnode, + NULL }; /* Board setup */ @@ -222,23 +253,25 @@ static struct platform_device *apu_gpio_pdev; static struct platform_device *apu_leds_pdev; static struct platform_device *apu_keys_pdev; -static struct platform_device * __init apu_create_pdev( - const char *name, - const void *pdata, - size_t sz) +static struct platform_device * __init apu_create_pdev(const char *name, + const void *data, size_t size, + const struct software_node *swnode) { + struct platform_device_info pdev_info = { + .name = name, + .id = PLATFORM_DEVID_NONE, + .data = data, + .size_data = size, + .fwnode = software_node_fwnode(swnode), + }; struct platform_device *pdev; + int err; - pdev = platform_device_register_resndata(NULL, - name, - PLATFORM_DEVID_NONE, - NULL, - 0, - pdata, - sz); + pdev = platform_device_register_full(&pdev_info); - if (IS_ERR(pdev)) - pr_err("failed registering %s: %ld\n", name, PTR_ERR(pdev)); + err = PTR_ERR_OR_ZERO(pdev); + if (err) + pr_err("failed registering %s: %d\n", name, err); return pdev; } @@ -246,6 +279,7 @@ static struct platform_device * __init apu_create_pdev( static int __init apu_board_init(void) { const struct dmi_system_id *id; + int err; id = dmi_first_match(apu_gpio_dmi_table); if (!id) { @@ -253,35 +287,45 @@ static int __init apu_board_init(void) return -ENODEV; } - gpiod_add_lookup_table(&gpios_led_table); - gpiod_add_lookup_table(&gpios_key_table); + err = software_node_register_node_group(apu2_swnodes); + if (err) { + pr_err("failed to register software nodes: %d\n", err); + return err; + } - apu_gpio_pdev = apu_create_pdev( - AMD_FCH_GPIO_DRIVER_NAME, - id->driver_data, - sizeof(struct amd_fch_gpio_pdata)); + apu_gpio_pdev = apu_create_pdev(AMD_FCH_GPIO_DRIVER_NAME, + id->driver_data, sizeof(struct amd_fch_gpio_pdata), NULL); + err = PTR_ERR_OR_ZERO(apu_gpio_pdev); + if (err) + goto err_unregister_swnodes; - apu_leds_pdev = apu_create_pdev( - "leds-gpio", - &apu2_leds_pdata, - sizeof(apu2_leds_pdata)); + apu_leds_pdev = apu_create_pdev("leds-gpio", NULL, 0, &apu2_leds_node); + err = PTR_ERR_OR_ZERO(apu_leds_pdev); + if (err) + goto err_unregister_gpio; - apu_keys_pdev = apu_create_pdev( - "gpio-keys-polled", - &apu2_keys_pdata, - sizeof(apu2_keys_pdata)); + apu_keys_pdev = apu_create_pdev("gpio-keys-polled", NULL, 0, &apu2_keys_node); + err = PTR_ERR_OR_ZERO(apu_keys_pdev); + if (err) + goto err_unregister_leds; return 0; + +err_unregister_leds: + platform_device_unregister(apu_leds_pdev); +err_unregister_gpio: + platform_device_unregister(apu_gpio_pdev); +err_unregister_swnodes: + software_node_unregister_node_group(apu2_swnodes); + return err; } static void __exit apu_board_exit(void) { - gpiod_remove_lookup_table(&gpios_led_table); - gpiod_remove_lookup_table(&gpios_key_table); - platform_device_unregister(apu_keys_pdev); platform_device_unregister(apu_leds_pdev); platform_device_unregister(apu_gpio_pdev); + software_node_unregister_node_group(apu2_swnodes); } module_init(apu_board_init); From cb0c5a60a6f7dd7f35fa5b46fd04dfb66b37fc1e Mon Sep 17 00:00:00 2001 From: Gopi Krishna Menon Date: Fri, 26 Sep 2025 10:06:12 +0530 Subject: [PATCH 2164/2711] docs: perf: Fujitsu: Fix htmldocs build warnings and errors Running "make htmldocs" generates the following build errors and warnings for fujitsu_uncore_pmu.rst: Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst:20: ERROR: Unexpected indentation. Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst:23: WARNING: Block quote ends without a blank line; unexpected unindent. Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst:28: ERROR: Unexpected indentation. Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst:29: WARNING: Block quote ends without a blank line; unexpected unindent. Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst:81: ERROR: Unexpected indentation. Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst:82: WARNING: Block quote ends without a blank line; unexpected unindent. Add blank line before bullet lists, block quotes to fix build errors, resolve warnings and properly render perf commands as code blocks. Signed-off-by: Gopi Krishna Menon Reviewed-by: Koichi Okuno Fixes: bad11557eed2 ("perf: Fujitsu: Add the Uncore PMU driver") Reviewed-by: Bagas Sanjaya Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Will Deacon --- Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst b/Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst index 46595b788d3a..2ec0249e37b6 100644 --- a/Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst +++ b/Documentation/admin-guide/perf/fujitsu_uncore_pmu.rst @@ -15,15 +15,19 @@ The driver provides a description of its available events and configuration options in sysfs, see /sys/bus/event_sources/devices/mac_iod_mac_ch/ and /sys/bus/event_sources/devices/pci_iod_pci/. This driver exports: + - formats, used by perf user space and other tools to configure events - events, used by perf user space and other tools to create events - symbolically, e.g.: + symbolically, e.g.:: + perf stat -a -e mac_iod0_mac0_ch0/event=0x21/ ls perf stat -a -e pci_iod0_pci0/event=0x24/ ls + - cpumask, used by perf user space and other tools to know on which CPUs to open the events This driver supports the following events for MAC: + - cycles This event counts MAC cycles at MAC frequency. - read-count @@ -77,6 +81,7 @@ Examples for use with perf:: perf stat -e mac_iod0_mac0_ch0/ea-mac/ ls And, this driver supports the following events for PCI: + - pci-port0-cycles This event counts PCI cycles at PCI frequency in port0. - pci-port0-read-count From 4d164e08cd8457ebcd5346f612ac2c04e80b6bea Mon Sep 17 00:00:00 2001 From: John Ogness Date: Fri, 26 Sep 2025 00:55:59 +0206 Subject: [PATCH 2165/2711] printk: ringbuffer: Fix data block max size check Currently data_check_size() limits data blocks to a maximum size of the full buffer minus an ID (long integer): max_size <= DATA_SIZE(data_ring) - sizeof(long) However, this is not an appropriate limit due to the nature of wrapping data blocks. For example, if a data block is larger than half the buffer: size = (DATA_SIZE(data_ring) / 2) + 8 and begins exactly in the middle of the buffer, then: - the data block will wrap - the ID will be stored at exactly half of the buffer - the record data begins at the beginning of the buffer - the record data ends 8 bytes _past_ exactly half of the buffer The record overwrites itself, i.e. needs more space than the full buffer! Luckily printk() is not vulnerable to this problem because truncate_msg() limits printk-messages to 1/4 of the ringbuffer. Indeed, by adjusting the printk_ringbuffer KUnit test, which does not use printk() and its truncate_msg() check, it is easy to see that the ringbuffer becomes corrupted for records larger than half the buffer size. The corruption occurs because data_push_tail() expects it will never be requested to push the tail beyond the head. Avoid this problem by adjusting data_check_size() to limit record sizes to half the buffer size. Also add WARN_ON_ONCE() before relevant data_push_tail() calls to validate that there are no such illegal requests. WARN_ON_ONCE() is used, rather than just adding extra checks to data_push_tail() because it is considered a bug to attempt such illegal actions. Link: https://lore.kernel.org/lkml/aMLrGCQSyC8odlFZ@pathway.suse.cz Signed-off-by: John Ogness Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek --- kernel/printk/printk_ringbuffer.c | 43 +++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c index d9fb053cff67..96df860e6f7c 100644 --- a/kernel/printk/printk_ringbuffer.c +++ b/kernel/printk/printk_ringbuffer.c @@ -393,25 +393,21 @@ static unsigned int to_blk_size(unsigned int size) * Sanity checker for reserve size. The ringbuffer code assumes that a data * block does not exceed the maximum possible size that could fit within the * ringbuffer. This function provides that basic size check so that the - * assumption is safe. + * assumption is safe. In particular, it guarantees that data_push_tail() will + * never attempt to push the tail beyond the head. */ static bool data_check_size(struct prb_data_ring *data_ring, unsigned int size) { - struct prb_data_block *db = NULL; - + /* Data-less blocks take no space. */ if (size == 0) return true; /* - * Ensure the alignment padded size could possibly fit in the data - * array. The largest possible data block must still leave room for - * at least the ID of the next block. + * If data blocks were allowed to be larger than half the data ring + * size, a wrapping data block could require more space than the full + * ringbuffer. */ - size = to_blk_size(size); - if (size > DATA_SIZE(data_ring) - sizeof(db->id)) - return false; - - return true; + return to_blk_size(size) <= DATA_SIZE(data_ring) / 2; } /* Query the state of a descriptor. */ @@ -1051,8 +1047,17 @@ static char *data_alloc(struct printk_ringbuffer *rb, unsigned int size, do { next_lpos = get_next_lpos(data_ring, begin_lpos, size); - if (!data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) { - /* Failed to allocate, specify a data-less block. */ + /* + * data_check_size() prevents data block allocation that could + * cause illegal ringbuffer states. But double check that the + * used space will not be bigger than the ring buffer. Wrapped + * messages need to reserve more space, see get_next_lpos(). + * + * Specify a data-less block when the check or the allocation + * fails. + */ + if (WARN_ON_ONCE(next_lpos - begin_lpos > DATA_SIZE(data_ring)) || + !data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) { blk_lpos->begin = FAILED_LPOS; blk_lpos->next = FAILED_LPOS; return NULL; @@ -1140,8 +1145,18 @@ static char *data_realloc(struct printk_ringbuffer *rb, unsigned int size, return &blk->data[0]; } - if (!data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) + /* + * data_check_size() prevents data block reallocation that could + * cause illegal ringbuffer states. But double check that the + * new used space will not be bigger than the ring buffer. Wrapped + * messages need to reserve more space, see get_next_lpos(). + * + * Specify failure when the check or the allocation fails. + */ + if (WARN_ON_ONCE(next_lpos - blk_lpos->begin > DATA_SIZE(data_ring)) || + !data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) { return NULL; + } /* The memory barrier involvement is the same as data_alloc:A. */ if (!atomic_long_try_cmpxchg(&data_ring->head_lpos, &head_lpos, From 8b9f128947dd72e0fcf256088a673abac9b720bf Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Tue, 23 Sep 2025 12:04:33 -0500 Subject: [PATCH 2166/2711] vfio/pci: Fix INTx handling on legacy non-PCI 2.3 devices PCI devices prior to PCI 2.3 both use level interrupts and do not support interrupt masking, leading to a failure when passed through to a KVM guest on at least the ppc64 platform. This failure manifests as receiving and acknowledging a single interrupt in the guest, while the device continues to assert the level interrupt indicating a need for further servicing. When lazy IRQ masking is used on DisINTx- (non-PCI 2.3) hardware, the following sequence occurs: * Level IRQ assertion on device * IRQ marked disabled in kernel * Host interrupt handler exits without clearing the interrupt on the device * Eventfd is delivered to userspace * Guest processes IRQ and clears device interrupt * Device de-asserts INTx, then re-asserts INTx while the interrupt is masked * Newly asserted interrupt acknowledged by kernel VMM without being handled * Software mask removed by VFIO driver * Device INTx still asserted, host controller does not see new edge after EOI The behavior is now platform-dependent. Some platforms (amd64) will continue to spew IRQs for as long as the INTX line remains asserted, therefore the IRQ will be handled by the host as soon as the mask is dropped. Others (ppc64) will only send the one request, and if it is not handled no further interrupts will be sent. The former behavior theoretically leaves the system vulnerable to interrupt storm, and the latter will result in the device stalling after receiving exactly one interrupt in the guest. Work around this by disabling lazy IRQ masking for DisINTx- INTx devices. Signed-off-by: Timothy Pearson Link: https://lore.kernel.org/r/333803015.1744464.1758647073336.JavaMail.zimbra@raptorengineeringinc.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_intrs.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 00583909b380..30d3e921cb0d 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -304,9 +304,14 @@ static int vfio_intx_enable(struct vfio_pci_core_device *vdev, vdev->irq_type = VFIO_PCI_INTX_IRQ_INDEX; + if (!vdev->pci_2_3) + irq_set_status_flags(pdev->irq, IRQ_DISABLE_UNLAZY); + ret = request_irq(pdev->irq, vfio_intx_handler, irqflags, ctx->name, ctx); if (ret) { + if (!vdev->pci_2_3) + irq_clear_status_flags(pdev->irq, IRQ_DISABLE_UNLAZY); vdev->irq_type = VFIO_PCI_NUM_IRQS; kfree(name); vfio_irq_ctx_free(vdev, ctx, 0); @@ -352,6 +357,8 @@ static void vfio_intx_disable(struct vfio_pci_core_device *vdev) vfio_virqfd_disable(&ctx->unmask); vfio_virqfd_disable(&ctx->mask); free_irq(pdev->irq, ctx); + if (!vdev->pci_2_3) + irq_clear_status_flags(pdev->irq, IRQ_DISABLE_UNLAZY); if (ctx->trigger) eventfd_ctx_put(ctx->trigger); kfree(ctx->name); From 407aa63018d15c35a34938633868e61174d2ef6e Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Thu, 25 Sep 2025 12:09:35 -0500 Subject: [PATCH 2167/2711] vfio/nvgrace-gpu: Add GB300 SKU to the devid table GB300 is NVIDIA's Grace Blackwell Ultra Superchip. Add the GB300 SKU device-id to nvgrace_gpu_vfio_pci_table. Signed-off-by: Tushar Dave Reviewed-by: Ankit Agrawal Link: https://lore.kernel.org/r/20250925170935.121587-1-tdave@nvidia.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/nvgrace-gpu/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c index 0adaa6150252..e346392b72f6 100644 --- a/drivers/vfio/pci/nvgrace-gpu/main.c +++ b/drivers/vfio/pci/nvgrace-gpu/main.c @@ -995,6 +995,8 @@ static const struct pci_device_id nvgrace_gpu_vfio_pci_table[] = { { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_NVIDIA, 0x2348) }, /* GB200 SKU */ { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_NVIDIA, 0x2941) }, + /* GB300 SKU */ + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_NVIDIA, 0x31C2) }, {} }; From dc356bf3c173a69d4b6f6ee6221cd21c6500fc65 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 5 Aug 2025 11:25:40 +0200 Subject: [PATCH 2168/2711] sparc: Drop the "-ansi" from the asflags In the very early kernel 1.x days, assembler files were pre-processed with the "-traditional" flag. With kernel 1.1.85, the sparc subsystem was changed to use "-ansi" instead while the other parts of the kernel continued to use "-traditional". That "-traditional" got removed from the other architectures in the course of time, but the sparc part kept the "-ansi" until today. This is bad since it comes with some disadvantages nowadays: You have to make sure to not include any header that contains a "//" C++ comment by accident (there are now some in the tree that use these for SPDX identifiers for example), and with "-ansi" we also do not get the pre-defined __ASSEMBLER__ macro which we'd like to use instead of the kernel-only __ASSEMBLY__ macro in the future. Since there does not seem to be any compelling reason anymore to use "-ansi" nowadays, let's simply drop the "-ansi" flag from the sparc subsystem now to get rid of those disadvantages. Signed-off-by: Thomas Huth Reviewed-by: Arnd Bergmann Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/kernel/Makefile | 2 -- arch/sparc/lib/Makefile | 2 +- arch/sparc/mm/Makefile | 2 -- arch/sparc/prom/Makefile | 1 - 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 36f2727e1445..22170d4f8e06 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -4,8 +4,6 @@ # Makefile for the linux kernel. # -asflags-y := -ansi - # Undefine sparc when processing vmlinux.lds - it is used # And teach CPP we are doing $(BITS) builds (for this case) CPPFLAGS_vmlinux.lds := -Usparc -m$(BITS) diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index ee5091dd67ed..783bdec0d7be 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for Sparc library files.. # -asflags-y := -ansi -DST_DIV0=0x02 +asflags-y := -DST_DIV0=0x02 lib-$(CONFIG_SPARC32) += ashrdi3.o lib-$(CONFIG_SPARC32) += memcpy.o memset.o diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile index 2d1752108d77..e9d232561c82 100644 --- a/arch/sparc/mm/Makefile +++ b/arch/sparc/mm/Makefile @@ -2,8 +2,6 @@ # Makefile for the linux Sparc-specific parts of the memory manager. # -asflags-y := -ansi - obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o obj-y += fault_$(BITS).o obj-y += init_$(BITS).o diff --git a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile index a1adc75d8055..92db8bb4ad4c 100644 --- a/arch/sparc/prom/Makefile +++ b/arch/sparc/prom/Makefile @@ -2,7 +2,6 @@ # Makefile for the Sun Boot PROM interface library under # Linux. # -asflags := -ansi lib-y := bootstr_$(BITS).o lib-y += init_$(BITS).o From d6fb6511de74bd0d4cb4cabddae9b31d533af1c1 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 14 Mar 2025 08:10:04 +0100 Subject: [PATCH 2169/2711] sparc: Replace __ASSEMBLY__ with __ASSEMBLER__ in uapi headers __ASSEMBLY__ is only defined by the Makefile of the kernel, so this is not really useful for uapi headers (unless the userspace Makefile defines it, too). Let's switch to __ASSEMBLER__ which gets set automatically by the compiler when compiling assembly code. This is a completely mechanical patch (done with a simple "sed -i" statement). Cc: David S. Miller Cc: Andreas Larsson Cc: sparclinux@vger.kernel.org Signed-off-by: Thomas Huth Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/include/uapi/asm/ptrace.h | 24 ++++++++++++------------ arch/sparc/include/uapi/asm/signal.h | 4 ++-- arch/sparc/include/uapi/asm/traps.h | 4 ++-- arch/sparc/include/uapi/asm/utrap.h | 4 ++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/sparc/include/uapi/asm/ptrace.h b/arch/sparc/include/uapi/asm/ptrace.h index abe640037a55..2eb677f4eb6a 100644 --- a/arch/sparc/include/uapi/asm/ptrace.h +++ b/arch/sparc/include/uapi/asm/ptrace.h @@ -15,7 +15,7 @@ */ #define PT_REGS_MAGIC 0x57ac6c00 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -88,7 +88,7 @@ struct sparc_trapf { unsigned long _unused; struct pt_regs *regs; }; -#endif /* (!__ASSEMBLY__) */ +#endif /* (!__ASSEMBLER__) */ #else /* 32 bit sparc */ @@ -97,7 +97,7 @@ struct sparc_trapf { /* This struct defines the way the registers are stored on the * stack during a system call and basically all traps. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -125,11 +125,11 @@ struct sparc_stackf { unsigned long xargs[6]; unsigned long xxargs[1]; }; -#endif /* (!__ASSEMBLY__) */ +#endif /* (!__ASSEMBLER__) */ #endif /* (defined(__sparc__) && defined(__arch64__))*/ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define TRACEREG_SZ sizeof(struct pt_regs) #define STACKFRAME_SZ sizeof(struct sparc_stackf) @@ -137,7 +137,7 @@ struct sparc_stackf { #define TRACEREG32_SZ sizeof(struct pt_regs32) #define STACKFRAME32_SZ sizeof(struct sparc_stackf32) -#endif /* (!__ASSEMBLY__) */ +#endif /* (!__ASSEMBLER__) */ #define UREG_G0 0 #define UREG_G1 1 @@ -161,30 +161,30 @@ struct sparc_stackf { #if defined(__sparc__) && defined(__arch64__) /* 64 bit sparc */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ -#else /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ /* For assembly code. */ #define TRACEREG_SZ 0xa0 #define STACKFRAME_SZ 0xc0 #define TRACEREG32_SZ 0x50 #define STACKFRAME32_SZ 0x60 -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #else /* (defined(__sparc__) && defined(__arch64__)) */ /* 32 bit sparc */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ -#else /* (!__ASSEMBLY__) */ +#else /* (!__ASSEMBLER__) */ /* For assembly code. */ #define TRACEREG_SZ 0x50 #define STACKFRAME_SZ 0x60 -#endif /* (!__ASSEMBLY__) */ +#endif /* (!__ASSEMBLER__) */ #endif /* (defined(__sparc__) && defined(__arch64__)) */ diff --git a/arch/sparc/include/uapi/asm/signal.h b/arch/sparc/include/uapi/asm/signal.h index b61382924725..9c64d7cb85c2 100644 --- a/arch/sparc/include/uapi/asm/signal.h +++ b/arch/sparc/include/uapi/asm/signal.h @@ -105,7 +105,7 @@ #define __old_sigaction32 sigaction32 #endif -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef unsigned long __old_sigset_t; /* at least 32 bits */ @@ -176,6 +176,6 @@ typedef struct sigaltstack { } stack_t; -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* _UAPI__SPARC_SIGNAL_H */ diff --git a/arch/sparc/include/uapi/asm/traps.h b/arch/sparc/include/uapi/asm/traps.h index 930db746f8bd..43fe5b8fe8be 100644 --- a/arch/sparc/include/uapi/asm/traps.h +++ b/arch/sparc/include/uapi/asm/traps.h @@ -10,8 +10,8 @@ #define NUM_SPARC_TRAPS 255 -#ifndef __ASSEMBLY__ -#endif /* !(__ASSEMBLY__) */ +#ifndef __ASSEMBLER__ +#endif /* !(__ASSEMBLER__) */ /* For patching the trap table at boot time, we need to know how to * form various common Sparc instructions. Thus these macros... diff --git a/arch/sparc/include/uapi/asm/utrap.h b/arch/sparc/include/uapi/asm/utrap.h index d890b7fc6e83..a489b08b6a33 100644 --- a/arch/sparc/include/uapi/asm/utrap.h +++ b/arch/sparc/include/uapi/asm/utrap.h @@ -44,9 +44,9 @@ #define UTH_NOCHANGE (-1) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef int utrap_entry_t; typedef void *utrap_handler_t; -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* !(__ASM_SPARC64_PROCESSOR_H) */ From 3b1307e1cd1224a063a1791d213dfdd35b05a38a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 14 Mar 2025 08:10:05 +0100 Subject: [PATCH 2170/2711] sparc: Replace __ASSEMBLY__ with __ASSEMBLER__ in non-uapi headers While the GCC and Clang compilers already define __ASSEMBLER__ automatically when compiling assembly code, __ASSEMBLY__ is a macro that only gets defined by the Makefiles in the kernel. This can be very confusing when switching between userspace and kernelspace coding, or when dealing with uapi headers that rather should use __ASSEMBLER__ instead. So let's standardize on the __ASSEMBLER__ macro that is provided by the compilers now. This is a completely mechanical patch (done with a simple "sed -i" statement). Cc: David S. Miller Cc: Andreas Larsson Cc: sparclinux@vger.kernel.org Signed-off-by: Thomas Huth Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/include/asm/adi_64.h | 4 +- arch/sparc/include/asm/auxio.h | 4 +- arch/sparc/include/asm/auxio_32.h | 4 +- arch/sparc/include/asm/auxio_64.h | 4 +- arch/sparc/include/asm/cacheflush_64.h | 4 +- arch/sparc/include/asm/cpudata.h | 4 +- arch/sparc/include/asm/cpudata_64.h | 4 +- arch/sparc/include/asm/delay_64.h | 4 +- arch/sparc/include/asm/ftrace.h | 2 +- arch/sparc/include/asm/hvtramp.h | 2 +- arch/sparc/include/asm/hypervisor.h | 92 ++++++++++++------------- arch/sparc/include/asm/irqflags_32.h | 4 +- arch/sparc/include/asm/irqflags_64.h | 4 +- arch/sparc/include/asm/jump_label.h | 4 +- arch/sparc/include/asm/kdebug_32.h | 4 +- arch/sparc/include/asm/leon.h | 8 +-- arch/sparc/include/asm/leon_amba.h | 6 +- arch/sparc/include/asm/mman.h | 4 +- arch/sparc/include/asm/mmu_64.h | 4 +- arch/sparc/include/asm/mmu_context_32.h | 4 +- arch/sparc/include/asm/mmu_context_64.h | 4 +- arch/sparc/include/asm/mxcc.h | 4 +- arch/sparc/include/asm/obio.h | 4 +- arch/sparc/include/asm/openprom.h | 4 +- arch/sparc/include/asm/page_32.h | 8 +-- arch/sparc/include/asm/page_64.h | 8 +-- arch/sparc/include/asm/pcic.h | 2 +- arch/sparc/include/asm/pgtable_32.h | 4 +- arch/sparc/include/asm/pgtable_64.h | 8 +-- arch/sparc/include/asm/pgtsrmmu.h | 6 +- arch/sparc/include/asm/processor_64.h | 10 +-- arch/sparc/include/asm/psr.h | 4 +- arch/sparc/include/asm/ptrace.h | 12 ++-- arch/sparc/include/asm/ross.h | 4 +- arch/sparc/include/asm/sbi.h | 4 +- arch/sparc/include/asm/sigcontext.h | 4 +- arch/sparc/include/asm/signal.h | 6 +- arch/sparc/include/asm/smp_32.h | 8 +-- arch/sparc/include/asm/smp_64.h | 8 +-- arch/sparc/include/asm/spinlock_32.h | 4 +- arch/sparc/include/asm/spinlock_64.h | 4 +- arch/sparc/include/asm/spitfire.h | 4 +- arch/sparc/include/asm/starfire.h | 2 +- arch/sparc/include/asm/thread_info_32.h | 4 +- arch/sparc/include/asm/thread_info_64.h | 12 ++-- arch/sparc/include/asm/trap_block.h | 4 +- arch/sparc/include/asm/traps.h | 4 +- arch/sparc/include/asm/tsb.h | 2 +- arch/sparc/include/asm/ttable.h | 2 +- arch/sparc/include/asm/turbosparc.h | 4 +- arch/sparc/include/asm/upa.h | 4 +- arch/sparc/include/asm/vaddrs.h | 2 +- arch/sparc/include/asm/viking.h | 4 +- arch/sparc/include/asm/visasm.h | 2 +- drivers/char/hw_random/n2rng.h | 4 +- 55 files changed, 172 insertions(+), 172 deletions(-) diff --git a/arch/sparc/include/asm/adi_64.h b/arch/sparc/include/asm/adi_64.h index 4301c6fd87f7..0c066fdab696 100644 --- a/arch/sparc/include/asm/adi_64.h +++ b/arch/sparc/include/asm/adi_64.h @@ -9,7 +9,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct adi_caps { __u64 blksz; @@ -41,6 +41,6 @@ static inline unsigned long adi_nbits(void) return adi_state.caps.nbits; } -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* !(__ASM_SPARC64_ADI_H) */ diff --git a/arch/sparc/include/asm/auxio.h b/arch/sparc/include/asm/auxio.h index a2681052e900..d0a933ed0d04 100644 --- a/arch/sparc/include/asm/auxio.h +++ b/arch/sparc/include/asm/auxio.h @@ -2,11 +2,11 @@ #ifndef ___ASM_SPARC_AUXIO_H #define ___ASM_SPARC_AUXIO_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ extern void __iomem *auxio_register; -#endif /* ifndef __ASSEMBLY__ */ +#endif /* ifndef __ASSEMBLER__ */ #if defined(__sparc__) && defined(__arch64__) #include diff --git a/arch/sparc/include/asm/auxio_32.h b/arch/sparc/include/asm/auxio_32.h index 852457c7a265..db58fa28de9e 100644 --- a/arch/sparc/include/asm/auxio_32.h +++ b/arch/sparc/include/asm/auxio_32.h @@ -29,7 +29,7 @@ #define AUXIO_FLPY_EJCT 0x02 /* Eject floppy disk. Write only. */ #define AUXIO_LED 0x01 /* On if set, off if unset. Read/Write */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * NOTE: these routines are implementation dependent-- @@ -75,7 +75,7 @@ do { \ } \ } while (0) -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ /* AUXIO2 (Power Off Control) */ diff --git a/arch/sparc/include/asm/auxio_64.h b/arch/sparc/include/asm/auxio_64.h index ae1ed41987db..8a4ae07daf16 100644 --- a/arch/sparc/include/asm/auxio_64.h +++ b/arch/sparc/include/asm/auxio_64.h @@ -74,7 +74,7 @@ #define AUXIO_PCIO_CPWR_OFF 0x02 /* Courtesy Power Off */ #define AUXIO_PCIO_SPWR_OFF 0x01 /* System Power Off */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define AUXIO_LTE_ON 1 #define AUXIO_LTE_OFF 0 @@ -94,6 +94,6 @@ void auxio_set_lte(int on); */ void auxio_set_led(int on); -#endif /* ifndef __ASSEMBLY__ */ +#endif /* ifndef __ASSEMBLER__ */ #endif /* !(_SPARC64_AUXIO_H) */ diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h index 2b1261b77ecd..06092572c045 100644 --- a/arch/sparc/include/asm/cacheflush_64.h +++ b/arch/sparc/include/asm/cacheflush_64.h @@ -4,7 +4,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -78,6 +78,6 @@ void flush_ptrace_access(struct vm_area_struct *, struct page *, #define flush_cache_vmap_early(start, end) do { } while (0) #define flush_cache_vunmap(start, end) do { } while (0) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* _SPARC64_CACHEFLUSH_H */ diff --git a/arch/sparc/include/asm/cpudata.h b/arch/sparc/include/asm/cpudata.h index d213165ee713..67022a153023 100644 --- a/arch/sparc/include/asm/cpudata.h +++ b/arch/sparc/include/asm/cpudata.h @@ -2,14 +2,14 @@ #ifndef ___ASM_SPARC_CPUDATA_H #define ___ASM_SPARC_CPUDATA_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include extern const struct seq_operations cpuinfo_op; -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #if defined(__sparc__) && defined(__arch64__) #include diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h index 9c3fc03abe9a..056b3c0e7ef9 100644 --- a/arch/sparc/include/asm/cpudata_64.h +++ b/arch/sparc/include/asm/cpudata_64.h @@ -7,7 +7,7 @@ #ifndef _SPARC64_CPUDATA_H #define _SPARC64_CPUDATA_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef struct { /* Dcache line 1 */ @@ -35,7 +35,7 @@ DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); #define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) #define local_cpu_data() (*this_cpu_ptr(&__cpu_data)) -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #include diff --git a/arch/sparc/include/asm/delay_64.h b/arch/sparc/include/asm/delay_64.h index 22213b1c119d..5de5b5f23188 100644 --- a/arch/sparc/include/asm/delay_64.h +++ b/arch/sparc/include/asm/delay_64.h @@ -7,12 +7,12 @@ #ifndef _SPARC64_DELAY_H #define _SPARC64_DELAY_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ void __delay(unsigned long loops); void udelay(unsigned long usecs); #define mdelay(n) udelay((n) * 1000) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* _SPARC64_DELAY_H */ diff --git a/arch/sparc/include/asm/ftrace.h b/arch/sparc/include/asm/ftrace.h index e284394cb3aa..f7c9036199c5 100644 --- a/arch/sparc/include/asm/ftrace.h +++ b/arch/sparc/include/asm/ftrace.h @@ -6,7 +6,7 @@ #define MCOUNT_ADDR ((unsigned long)(_mcount)) #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ void _mcount(void); #endif diff --git a/arch/sparc/include/asm/hvtramp.h b/arch/sparc/include/asm/hvtramp.h index ce2453ea4f2b..8cf7a54fa528 100644 --- a/arch/sparc/include/asm/hvtramp.h +++ b/arch/sparc/include/asm/hvtramp.h @@ -2,7 +2,7 @@ #ifndef _SPARC64_HVTRAP_H #define _SPARC64_HVTRAP_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include diff --git a/arch/sparc/include/asm/hypervisor.h b/arch/sparc/include/asm/hypervisor.h index f220edcf17c7..94ac56d43746 100644 --- a/arch/sparc/include/asm/hypervisor.h +++ b/arch/sparc/include/asm/hypervisor.h @@ -102,7 +102,7 @@ */ #define HV_FAST_MACH_EXIT 0x00 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ void sun4v_mach_exit(unsigned long exit_code); #endif @@ -131,7 +131,7 @@ void sun4v_mach_exit(unsigned long exit_code); */ #define HV_FAST_MACH_DESC 0x01 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_mach_desc(unsigned long buffer_pa, unsigned long buf_len, unsigned long *real_buf_len); @@ -152,7 +152,7 @@ unsigned long sun4v_mach_desc(unsigned long buffer_pa, */ #define HV_FAST_MACH_SIR 0x02 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ void sun4v_mach_sir(void); #endif @@ -208,7 +208,7 @@ void sun4v_mach_sir(void); */ #define HV_FAST_MACH_SET_WATCHDOG 0x05 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_mach_set_watchdog(unsigned long timeout, unsigned long *orig_timeout); #endif @@ -254,7 +254,7 @@ unsigned long sun4v_mach_set_watchdog(unsigned long timeout, */ #define HV_FAST_CPU_START 0x10 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_cpu_start(unsigned long cpuid, unsigned long pc, unsigned long rtba, @@ -282,7 +282,7 @@ unsigned long sun4v_cpu_start(unsigned long cpuid, */ #define HV_FAST_CPU_STOP 0x11 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_cpu_stop(unsigned long cpuid); #endif @@ -299,7 +299,7 @@ unsigned long sun4v_cpu_stop(unsigned long cpuid); */ #define HV_FAST_CPU_YIELD 0x12 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_cpu_yield(void); #endif @@ -317,7 +317,7 @@ unsigned long sun4v_cpu_yield(void); */ #define HV_FAST_CPU_POKE 0x13 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_cpu_poke(unsigned long cpuid); #endif @@ -363,7 +363,7 @@ unsigned long sun4v_cpu_poke(unsigned long cpuid); #define HV_CPU_QUEUE_RES_ERROR 0x3e #define HV_CPU_QUEUE_NONRES_ERROR 0x3f -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_cpu_qconf(unsigned long type, unsigned long queue_paddr, unsigned long num_queue_entries); @@ -416,7 +416,7 @@ unsigned long sun4v_cpu_qconf(unsigned long type, */ #define HV_FAST_CPU_MONDO_SEND 0x42 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_cpu_mondo_send(unsigned long cpu_count, unsigned long cpu_list_pa, unsigned long mondo_block_pa); @@ -449,7 +449,7 @@ unsigned long sun4v_cpu_mondo_send(unsigned long cpu_count, #define HV_CPU_STATE_RUNNING 0x02 #define HV_CPU_STATE_ERROR 0x03 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ long sun4v_cpu_state(unsigned long cpuid); #endif @@ -485,7 +485,7 @@ long sun4v_cpu_state(unsigned long cpuid); * * Layout of a TSB description for mmu_tsb_ctx{,non}0() calls. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct hv_tsb_descr { unsigned short pgsz_idx; unsigned short assoc; @@ -536,7 +536,7 @@ struct hv_tsb_descr { * The fault status block is a multiple of 64-bytes and must be aligned * on a 64-byte boundary. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct hv_fault_status { unsigned long i_fault_type; unsigned long i_fault_addr; @@ -651,7 +651,7 @@ struct hv_fault_status { */ #define HV_FAST_MMU_TSB_CTX0 0x20 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_mmu_tsb_ctx0(unsigned long num_descriptions, unsigned long tsb_desc_ra); #endif @@ -736,7 +736,7 @@ unsigned long sun4v_mmu_tsb_ctx0(unsigned long num_descriptions, */ #define HV_FAST_MMU_DEMAP_ALL 0x24 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ void sun4v_mmu_demap_all(void); #endif @@ -766,7 +766,7 @@ void sun4v_mmu_demap_all(void); */ #define HV_FAST_MMU_MAP_PERM_ADDR 0x25 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_mmu_map_perm_addr(unsigned long vaddr, unsigned long set_to_zero, unsigned long tte, @@ -990,7 +990,7 @@ unsigned long sun4v_mmu_map_perm_addr(unsigned long vaddr, */ #define HV_CCB_SUBMIT 0x34 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_ccb_submit(unsigned long ccb_buf, unsigned long len, unsigned long flags, @@ -1035,7 +1035,7 @@ unsigned long sun4v_ccb_submit(unsigned long ccb_buf, */ #define HV_CCB_INFO 0x35 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_ccb_info(unsigned long ca, void *info_arr); #endif @@ -1069,7 +1069,7 @@ unsigned long sun4v_ccb_info(unsigned long ca, */ #define HV_CCB_KILL 0x36 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_ccb_kill(unsigned long ca, void *kill_status); #endif @@ -1104,7 +1104,7 @@ unsigned long sun4v_ccb_kill(unsigned long ca, */ #define HV_FAST_TOD_GET 0x50 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_tod_get(unsigned long *time); #endif @@ -1121,7 +1121,7 @@ unsigned long sun4v_tod_get(unsigned long *time); */ #define HV_FAST_TOD_SET 0x51 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_tod_set(unsigned long time); #endif @@ -1197,7 +1197,7 @@ unsigned long sun4v_tod_set(unsigned long time); */ #define HV_FAST_CONS_WRITE 0x63 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ long sun4v_con_getchar(long *status); long sun4v_con_putchar(long c); long sun4v_con_read(unsigned long buffer, @@ -1239,7 +1239,7 @@ unsigned long sun4v_con_write(unsigned long buffer, #define HV_SOFT_STATE_NORMAL 0x01 #define HV_SOFT_STATE_TRANSITION 0x02 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_mach_set_soft_state(unsigned long soft_state, unsigned long msg_string_ra); #endif @@ -1318,7 +1318,7 @@ unsigned long sun4v_mach_set_soft_state(unsigned long soft_state, */ #define HV_FAST_SVC_CLRSTATUS 0x84 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_svc_send(unsigned long svc_id, unsigned long buffer, unsigned long buffer_size, @@ -1348,7 +1348,7 @@ unsigned long sun4v_svc_clrstatus(unsigned long svc_id, * start (offset 0) of the trap trace buffer, and is described as * follows: */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct hv_trap_trace_control { unsigned long head_offset; unsigned long tail_offset; @@ -1367,7 +1367,7 @@ struct hv_trap_trace_control { * * Each trap trace buffer entry is laid out as follows: */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct hv_trap_trace_entry { unsigned char type; /* Hypervisor or guest entry? */ unsigned char hpstate; /* Hyper-privileged state */ @@ -1617,7 +1617,7 @@ struct hv_trap_trace_entry { */ #define HV_FAST_INTR_DEVINO2SYSINO 0xa0 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_devino_to_sysino(unsigned long devhandle, unsigned long devino); #endif @@ -1635,7 +1635,7 @@ unsigned long sun4v_devino_to_sysino(unsigned long devhandle, */ #define HV_FAST_INTR_GETENABLED 0xa1 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_intr_getenabled(unsigned long sysino); #endif @@ -1651,7 +1651,7 @@ unsigned long sun4v_intr_getenabled(unsigned long sysino); */ #define HV_FAST_INTR_SETENABLED 0xa2 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_intr_setenabled(unsigned long sysino, unsigned long intr_enabled); #endif @@ -1668,7 +1668,7 @@ unsigned long sun4v_intr_setenabled(unsigned long sysino, */ #define HV_FAST_INTR_GETSTATE 0xa3 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_intr_getstate(unsigned long sysino); #endif @@ -1688,7 +1688,7 @@ unsigned long sun4v_intr_getstate(unsigned long sysino); */ #define HV_FAST_INTR_SETSTATE 0xa4 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_intr_setstate(unsigned long sysino, unsigned long intr_state); #endif @@ -1706,7 +1706,7 @@ unsigned long sun4v_intr_setstate(unsigned long sysino, unsigned long intr_state */ #define HV_FAST_INTR_GETTARGET 0xa5 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_intr_gettarget(unsigned long sysino); #endif @@ -1723,7 +1723,7 @@ unsigned long sun4v_intr_gettarget(unsigned long sysino); */ #define HV_FAST_INTR_SETTARGET 0xa6 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_intr_settarget(unsigned long sysino, unsigned long cpuid); #endif @@ -1807,7 +1807,7 @@ unsigned long sun4v_intr_settarget(unsigned long sysino, unsigned long cpuid); */ #define HV_FAST_VINTR_SET_TARGET 0xae -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_vintr_get_cookie(unsigned long dev_handle, unsigned long dev_ino, unsigned long *cookie); @@ -3047,7 +3047,7 @@ unsigned long sun4v_vintr_set_target(unsigned long dev_handle, #define LDC_MTE_SZ64K 0x0000000000000001 /* 64K page */ #define LDC_MTE_SZ8K 0x0000000000000000 /* 8K page */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct ldc_mtable_entry { unsigned long mte; unsigned long cookie; @@ -3130,7 +3130,7 @@ struct ldc_mtable_entry { */ #define HV_FAST_LDC_REVOKE 0xef -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_ldc_tx_qconf(unsigned long channel, unsigned long ra, unsigned long num_entries); @@ -3230,7 +3230,7 @@ unsigned long sun4v_ldc_revoke(unsigned long channel, #define HV_FAST_N2_GET_PERFREG 0x104 #define HV_FAST_N2_SET_PERFREG 0x105 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_niagara_getperf(unsigned long reg, unsigned long *val); unsigned long sun4v_niagara_setperf(unsigned long reg, @@ -3247,7 +3247,7 @@ unsigned long sun4v_niagara2_setperf(unsigned long reg, * a buffer where these statistics can be collected. It is continually * updated once configured. The layout is as follows: */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct hv_mmu_statistics { unsigned long immu_tsb_hits_ctx0_8k_tte; unsigned long immu_tsb_ticks_ctx0_8k_tte; @@ -3332,7 +3332,7 @@ struct hv_mmu_statistics { */ #define HV_FAST_MMUSTAT_INFO 0x103 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_mmustat_conf(unsigned long ra, unsigned long *orig_ra); unsigned long sun4v_mmustat_info(unsigned long *ra); #endif @@ -3343,7 +3343,7 @@ unsigned long sun4v_mmustat_info(unsigned long *ra); #define HV_NCS_QCONF 0x01 #define HV_NCS_QTAIL_UPDATE 0x02 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct hv_ncs_queue_entry { /* MAU Control Register */ unsigned long mau_control; @@ -3422,7 +3422,7 @@ struct hv_ncs_qtail_update_arg { */ #define HV_FAST_NCS_REQUEST 0x110 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_ncs_request(unsigned long request, unsigned long arg_ra, unsigned long arg_size); @@ -3433,7 +3433,7 @@ unsigned long sun4v_ncs_request(unsigned long request, #define HV_FAST_REBOOT_DATA_SET 0x172 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_reboot_data_set(unsigned long ra, unsigned long len); #endif @@ -3441,7 +3441,7 @@ unsigned long sun4v_reboot_data_set(unsigned long ra, #define HV_FAST_VT_GET_PERFREG 0x184 #define HV_FAST_VT_SET_PERFREG 0x185 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_vt_get_perfreg(unsigned long reg_num, unsigned long *reg_val); unsigned long sun4v_vt_set_perfreg(unsigned long reg_num, @@ -3451,7 +3451,7 @@ unsigned long sun4v_vt_set_perfreg(unsigned long reg_num, #define HV_FAST_T5_GET_PERFREG 0x1a8 #define HV_FAST_T5_SET_PERFREG 0x1a9 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_t5_get_perfreg(unsigned long reg_num, unsigned long *reg_val); unsigned long sun4v_t5_set_perfreg(unsigned long reg_num, @@ -3462,7 +3462,7 @@ unsigned long sun4v_t5_set_perfreg(unsigned long reg_num, #define HV_FAST_M7_GET_PERFREG 0x43 #define HV_FAST_M7_SET_PERFREG 0x44 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_m7_get_perfreg(unsigned long reg_num, unsigned long *reg_val); unsigned long sun4v_m7_set_perfreg(unsigned long reg_num, @@ -3506,7 +3506,7 @@ unsigned long sun4v_m7_set_perfreg(unsigned long reg_num, #define HV_GRP_T5_CPU 0x0211 #define HV_GRP_DIAG 0x0300 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ unsigned long sun4v_get_version(unsigned long group, unsigned long *major, unsigned long *minor); diff --git a/arch/sparc/include/asm/irqflags_32.h b/arch/sparc/include/asm/irqflags_32.h index 7ca3eaf3dace..f5f20774faac 100644 --- a/arch/sparc/include/asm/irqflags_32.h +++ b/arch/sparc/include/asm/irqflags_32.h @@ -11,7 +11,7 @@ #ifndef _ASM_IRQFLAGS_H #define _ASM_IRQFLAGS_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -43,6 +43,6 @@ static inline notrace bool arch_irqs_disabled(void) return arch_irqs_disabled_flags(arch_local_save_flags()); } -#endif /* (__ASSEMBLY__) */ +#endif /* (__ASSEMBLER__) */ #endif /* !(_ASM_IRQFLAGS_H) */ diff --git a/arch/sparc/include/asm/irqflags_64.h b/arch/sparc/include/asm/irqflags_64.h index c29ed571ae49..0071566c2c22 100644 --- a/arch/sparc/include/asm/irqflags_64.h +++ b/arch/sparc/include/asm/irqflags_64.h @@ -13,7 +13,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static inline notrace unsigned long arch_local_save_flags(void) { @@ -93,6 +93,6 @@ static inline notrace unsigned long arch_local_irq_save(void) return flags; } -#endif /* (__ASSEMBLY__) */ +#endif /* (__ASSEMBLER__) */ #endif /* !(_ASM_IRQFLAGS_H) */ diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h index 2718cbea826a..f49d1e6104e1 100644 --- a/arch/sparc/include/asm/jump_label.h +++ b/arch/sparc/include/asm/jump_label.h @@ -2,7 +2,7 @@ #ifndef _ASM_SPARC_JUMP_LABEL_H #define _ASM_SPARC_JUMP_LABEL_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -48,5 +48,5 @@ struct jump_entry { jump_label_t key; }; -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/sparc/include/asm/kdebug_32.h b/arch/sparc/include/asm/kdebug_32.h index 763d423823bd..7627701a032c 100644 --- a/arch/sparc/include/asm/kdebug_32.h +++ b/arch/sparc/include/asm/kdebug_32.h @@ -19,7 +19,7 @@ #define DEBUG_BP_TRAP 126 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* The debug vector is passed in %o1 at boot time. It is a pointer to * a structure in the debuggers address space. Here is its format. */ @@ -64,7 +64,7 @@ enum die_val { DIE_OOPS, }; -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ /* Some nice offset defines for assembler code. */ #define KDEBUG_ENTRY_OFF 0x0 diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h index c1e05e4ab9e3..053a24b67aed 100644 --- a/arch/sparc/include/asm/leon.h +++ b/arch/sparc/include/asm/leon.h @@ -59,7 +59,7 @@ #define ASI_LEON3_SYSCTRL_CFG_SNOOPING (1 << 27) #define ASI_LEON3_SYSCTRL_CFG_SSIZE(c) (1 << ((c >> 20) & 0xf)) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* do a physical address bypass write, i.e. for 0x80000000 */ static inline void leon_store_reg(unsigned long paddr, unsigned long value) @@ -132,7 +132,7 @@ static inline int sparc_leon3_cpuid(void) return sparc_leon3_asr17() >> 28; } -#endif /*!__ASSEMBLY__*/ +#endif /*!__ASSEMBLER__*/ #ifdef CONFIG_SMP # define LEON3_IRQ_IPI_DEFAULT 13 @@ -194,7 +194,7 @@ static inline int sparc_leon3_cpuid(void) #define LEON2_CCR_DSETS_MASK 0x03000000UL #define LEON2_CFG_SSIZE_MASK 0x00007000UL -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct vm_area_struct; unsigned long leon_swprobe(unsigned long vaddr, unsigned long *paddr); @@ -247,7 +247,7 @@ extern int leon_ipi_irq; #endif /* CONFIG_SMP */ -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ /* macros used in leon_mm.c */ #define PFN(x) ((x) >> PAGE_SHIFT) diff --git a/arch/sparc/include/asm/leon_amba.h b/arch/sparc/include/asm/leon_amba.h index 6433a93f5126..2ff5714d7a63 100644 --- a/arch/sparc/include/asm/leon_amba.h +++ b/arch/sparc/include/asm/leon_amba.h @@ -8,7 +8,7 @@ #ifndef LEON_AMBA_H_INCLUDE #define LEON_AMBA_H_INCLUDE -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct amba_prom_registers { unsigned int phys_addr; /* The physical address of this register */ @@ -89,7 +89,7 @@ struct amba_prom_registers { #define LEON3_GPTIMER_CONFIG_NRTIMERS(c) ((c)->config & 0x7) #define LEON3_GPTIMER_CTRL_ISPENDING(r) (((r)&LEON3_GPTIMER_CTRL_PENDING) ? 1 : 0) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct leon3_irqctrl_regs_map { u32 ilevel; @@ -189,7 +189,7 @@ extern int leon_debug_irqout; extern unsigned long leon3_gptimer_irq; extern unsigned int sparc_leon_eirq; -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #define LEON3_IO_AREA 0xfff00000 #define LEON3_CONF_AREA 0xff000 diff --git a/arch/sparc/include/asm/mman.h b/arch/sparc/include/asm/mman.h index 3e4bac33be81..a8bae8ad243a 100644 --- a/arch/sparc/include/asm/mman.h +++ b/arch/sparc/include/asm/mman.h @@ -4,7 +4,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define arch_mmap_check(addr,len,flags) sparc_mmap_check(addr,len) int sparc_mmap_check(unsigned long addr, unsigned long len); @@ -87,5 +87,5 @@ static inline bool arch_validate_flags(vm_flags_t vm_flags) } #endif /* CONFIG_SPARC64 */ -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __SPARC_MMAN_H__ */ diff --git a/arch/sparc/include/asm/mmu_64.h b/arch/sparc/include/asm/mmu_64.h index 7e2704c770e9..4eeb938f3e61 100644 --- a/arch/sparc/include/asm/mmu_64.h +++ b/arch/sparc/include/asm/mmu_64.h @@ -59,7 +59,7 @@ #define CTX_HWBITS(__ctx) ((__ctx.sparc64_ctx_val) & CTX_HW_MASK) #define CTX_NRBITS(__ctx) ((__ctx.sparc64_ctx_val) & CTX_NR_MASK) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define TSB_ENTRY_ALIGNMENT 16 @@ -117,7 +117,7 @@ typedef struct { spinlock_t tag_lock; } mm_context_t; -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #define TSB_CONFIG_TSB 0x00 #define TSB_CONFIG_RSS_LIMIT 0x08 diff --git a/arch/sparc/include/asm/mmu_context_32.h b/arch/sparc/include/asm/mmu_context_32.h index 509043f81560..d9ff73f776f9 100644 --- a/arch/sparc/include/asm/mmu_context_32.h +++ b/arch/sparc/include/asm/mmu_context_32.h @@ -2,7 +2,7 @@ #ifndef __SPARC_MMU_CONTEXT_H #define __SPARC_MMU_CONTEXT_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include @@ -29,6 +29,6 @@ void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, #include -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(__SPARC_MMU_CONTEXT_H) */ diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index 08160bf9a0f4..78bbacc14d2d 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h @@ -4,7 +4,7 @@ /* Derived heavily from Linus's Alpha/AXP ASN code... */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -193,6 +193,6 @@ static inline unsigned long mm_untag_mask(struct mm_struct *mm) #include -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(__SPARC64_MMU_CONTEXT_H) */ diff --git a/arch/sparc/include/asm/mxcc.h b/arch/sparc/include/asm/mxcc.h index 3a2561bea4dd..bd6339dcf693 100644 --- a/arch/sparc/include/asm/mxcc.h +++ b/arch/sparc/include/asm/mxcc.h @@ -84,7 +84,7 @@ * MID: The moduleID of the cpu your read this from. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static inline void mxcc_set_stream_src(unsigned long *paddr) { @@ -133,6 +133,6 @@ static inline void mxcc_set_creg(unsigned long mxcc_control) "i" (ASI_M_MXCC)); } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* !(_SPARC_MXCC_H) */ diff --git a/arch/sparc/include/asm/obio.h b/arch/sparc/include/asm/obio.h index 1b151f738b00..f1ad7f7bcac2 100644 --- a/arch/sparc/include/asm/obio.h +++ b/arch/sparc/include/asm/obio.h @@ -97,7 +97,7 @@ #define CC_EREG 0x1F00E00 /* Error code register */ #define CC_CID 0x1F00F04 /* Component ID */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static inline int bw_get_intr_mask(int sbus_level) { @@ -221,6 +221,6 @@ static inline void cc_set_igen(unsigned int gen) "i" (ASI_M_MXCC)); } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* !(_SPARC_OBIO_H) */ diff --git a/arch/sparc/include/asm/openprom.h b/arch/sparc/include/asm/openprom.h index 69545b3e5454..ce68000dffac 100644 --- a/arch/sparc/include/asm/openprom.h +++ b/arch/sparc/include/asm/openprom.h @@ -11,7 +11,7 @@ /* Empirical constants... */ #define LINUX_OPPROM_MAGIC 0x10010407 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include /* V0 prom device operations. */ @@ -275,6 +275,6 @@ struct linux_prom_pci_intmask { unsigned int interrupt; }; -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(__SPARC_OPENPROM_H) */ diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h index 9954254ea569..c1bccbedf567 100644 --- a/arch/sparc/include/asm/page_32.h +++ b/arch/sparc/include/asm/page_32.h @@ -13,7 +13,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) @@ -108,14 +108,14 @@ typedef pte_t *pgtable_t; #define TASK_UNMAPPED_BASE 0x50000000 -#else /* !(__ASSEMBLY__) */ +#else /* !(__ASSEMBLER__) */ #define __pgprot(x) (x) -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #define PAGE_OFFSET 0xf0000000 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ extern unsigned long phys_base; extern unsigned long pfn_base; #endif diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h index 2a68ff5b6eab..d764d8a8586b 100644 --- a/arch/sparc/include/asm/page_64.h +++ b/arch/sparc/include/asm/page_64.h @@ -30,7 +30,7 @@ #define HUGE_MAX_HSTATE 5 #endif -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) struct pt_regs; @@ -128,7 +128,7 @@ extern unsigned long sparc64_va_hole_bottom; extern unsigned long PAGE_OFFSET; -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ /* The maximum number of physical memory address bits we support. The * largest value we can support is whatever "KPGD_SHIFT + KPTE_BITS" @@ -139,7 +139,7 @@ extern unsigned long PAGE_OFFSET; #define ILOG2_4MB 22 #define ILOG2_256MB 28 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) @@ -153,7 +153,7 @@ extern unsigned long PAGE_OFFSET; #define virt_to_phys __pa #define phys_to_virt __va -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #include diff --git a/arch/sparc/include/asm/pcic.h b/arch/sparc/include/asm/pcic.h index 238376b1ffcc..fb5ed6a59535 100644 --- a/arch/sparc/include/asm/pcic.h +++ b/arch/sparc/include/asm/pcic.h @@ -8,7 +8,7 @@ #ifndef __SPARC_PCIC_H #define __SPARC_PCIC_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index 7c199c003ffe..f1538a48484a 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h @@ -21,7 +21,7 @@ #define PGDIR_MASK (~(PGDIR_SIZE-1)) #define PGDIR_ALIGN(__addr) (((__addr) + ~PGDIR_MASK) & PGDIR_MASK) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -423,7 +423,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma, __changed; \ }) -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #define VMALLOC_START _AC(0xfe600000,UL) #define VMALLOC_END _AC(0xffc00000,UL) diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 669cd02469a1..64b85ff9c766 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -79,7 +79,7 @@ #error PMD_SHIFT must equal HPAGE_SHIFT for transparent huge pages. #endif -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ extern unsigned long VMALLOC_END; @@ -106,7 +106,7 @@ bool kern_addr_valid(unsigned long addr); pr_err("%s:%d: bad pgd %p(%016lx) seen at (%pS)\n", \ __FILE__, __LINE__, &(e), pgd_val(e), __builtin_return_address(0)) -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ /* PTE bits which are the same in SUN4U and SUN4V format. */ #define _PAGE_VALID _AC(0x8000000000000000,UL) /* Valid TTE */ @@ -191,7 +191,7 @@ bool kern_addr_valid(unsigned long addr); /* We borrow bit 20 to store the exclusive marker in swap PTEs. */ #define _PAGE_SWP_EXCLUSIVE _AC(0x0000000000100000, UL) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ pte_t mk_pte_io(unsigned long, pgprot_t, int, unsigned long); @@ -1177,6 +1177,6 @@ extern unsigned long pte_leaf_size(pte_t pte); #endif /* CONFIG_HUGETLB_PAGE */ -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(_SPARC64_PGTABLE_H) */ diff --git a/arch/sparc/include/asm/pgtsrmmu.h b/arch/sparc/include/asm/pgtsrmmu.h index 18e68d43f036..a265822a475e 100644 --- a/arch/sparc/include/asm/pgtsrmmu.h +++ b/arch/sparc/include/asm/pgtsrmmu.h @@ -10,7 +10,7 @@ #include -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #include /* TI_UWINMASK for WINDOW_FLUSH */ #endif @@ -97,7 +97,7 @@ bne 99b; \ restore %g0, %g0, %g0; -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ extern unsigned long last_valid_pfn; /* This makes sense. Honest it does - Anton */ @@ -136,6 +136,6 @@ srmmu_get_pte (unsigned long addr) return entry; } -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(_SPARC_PGTSRMMU_H) */ diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h index 0a0d5c3d184c..321859454ca4 100644 --- a/arch/sparc/include/asm/processor_64.h +++ b/arch/sparc/include/asm/processor_64.h @@ -21,7 +21,7 @@ * XXX No longer using virtual page tables, kill this upper limit... */ #define VA_BITS 44 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define VPTE_SIZE (1UL << (VA_BITS - PAGE_SHIFT + 3)) #else #define VPTE_SIZE (1 << (VA_BITS - PAGE_SHIFT + 3)) @@ -45,7 +45,7 @@ #endif -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* The Sparc processor specific thread struct. */ /* XXX This should die, everything can go into thread_info now. */ @@ -62,7 +62,7 @@ struct thread_struct { #endif }; -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #ifndef CONFIG_DEBUG_SPINLOCK #define INIT_THREAD { \ @@ -75,7 +75,7 @@ struct thread_struct { } #endif /* !(CONFIG_DEBUG_SPINLOCK) */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -242,6 +242,6 @@ static inline void prefetchw(const void *x) int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap); -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(__ASM_SPARC64_PROCESSOR_H) */ diff --git a/arch/sparc/include/asm/psr.h b/arch/sparc/include/asm/psr.h index 65127ce565ab..5af50ccda023 100644 --- a/arch/sparc/include/asm/psr.h +++ b/arch/sparc/include/asm/psr.h @@ -14,7 +14,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* Get the %psr register. */ static inline unsigned int get_psr(void) { @@ -63,6 +63,6 @@ static inline unsigned int get_fsr(void) return fsr; } -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(__LINUX_SPARC_PSR_H) */ diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h index d1419e669027..8adf3fd2f00f 100644 --- a/arch/sparc/include/asm/ptrace.h +++ b/arch/sparc/include/asm/ptrace.h @@ -5,7 +5,7 @@ #include #if defined(__sparc__) && defined(__arch64__) -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -113,10 +113,10 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) { return regs->u_regs[UREG_I6]; } -#else /* __ASSEMBLY__ */ -#endif /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ +#endif /* __ASSEMBLER__ */ #else /* (defined(__sparc__) && defined(__arch64__)) */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include static inline bool pt_regs_is_syscall(struct pt_regs *regs) @@ -144,8 +144,8 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs) #define instruction_pointer(regs) ((regs)->pc) #define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP]) unsigned long profile_pc(struct pt_regs *); -#else /* (!__ASSEMBLY__) */ -#endif /* (!__ASSEMBLY__) */ +#else /* (!__ASSEMBLER__) */ +#endif /* (!__ASSEMBLER__) */ #endif /* (defined(__sparc__) && defined(__arch64__)) */ #define STACK_BIAS 2047 diff --git a/arch/sparc/include/asm/ross.h b/arch/sparc/include/asm/ross.h index 79a54d66a2c0..53a42b37495d 100644 --- a/arch/sparc/include/asm/ross.h +++ b/arch/sparc/include/asm/ross.h @@ -95,7 +95,7 @@ #define HYPERSPARC_ICCR_FTD 0x00000002 #define HYPERSPARC_ICCR_ICE 0x00000001 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static inline unsigned int get_ross_icr(void) { @@ -187,6 +187,6 @@ static inline void hyper_flush_cache_page(unsigned long page) } } -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(_SPARC_ROSS_H) */ diff --git a/arch/sparc/include/asm/sbi.h b/arch/sparc/include/asm/sbi.h index 4d6026c1e446..861f85b5bf9b 100644 --- a/arch/sparc/include/asm/sbi.h +++ b/arch/sparc/include/asm/sbi.h @@ -64,7 +64,7 @@ struct sbi_regs { */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static inline int acquire_sbi(int devid, int mask) { @@ -111,6 +111,6 @@ static inline void set_sbi_ctl(int devid, int cfgno, int cfg) "i" (ASI_M_CTL)); } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* !(_SPARC_SBI_H) */ diff --git a/arch/sparc/include/asm/sigcontext.h b/arch/sparc/include/asm/sigcontext.h index ee05f9d2bcf2..200f95144fd2 100644 --- a/arch/sparc/include/asm/sigcontext.h +++ b/arch/sparc/include/asm/sigcontext.h @@ -5,7 +5,7 @@ #include #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define __SUNOS_MAXWIN 31 @@ -104,6 +104,6 @@ typedef struct { #endif /* (CONFIG_SPARC64) */ -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(__SPARC_SIGCONTEXT_H) */ diff --git a/arch/sparc/include/asm/signal.h b/arch/sparc/include/asm/signal.h index 28f81081e37d..d93fe93544ec 100644 --- a/arch/sparc/include/asm/signal.h +++ b/arch/sparc/include/asm/signal.h @@ -2,16 +2,16 @@ #ifndef __SPARC_SIGNAL_H #define __SPARC_SIGNAL_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include #endif #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define __ARCH_HAS_KA_RESTORER #define __ARCH_HAS_SA_RESTORER -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(__SPARC_SIGNAL_H) */ diff --git a/arch/sparc/include/asm/smp_32.h b/arch/sparc/include/asm/smp_32.h index 2cf7971d7f6c..9c6ed98fbaf1 100644 --- a/arch/sparc/include/asm/smp_32.h +++ b/arch/sparc/include/asm/smp_32.h @@ -10,15 +10,15 @@ #include #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #ifdef CONFIG_SMP -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -105,7 +105,7 @@ int hard_smp_processor_id(void); void smp_setup_cpu_possible_map(void); -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ /* Sparc specific messages. */ #define MSG_CROSS_CALL 0x0005 /* run func on cpus */ diff --git a/arch/sparc/include/asm/smp_64.h b/arch/sparc/include/asm/smp_64.h index 0964fede0b2c..759fb4a9530e 100644 --- a/arch/sparc/include/asm/smp_64.h +++ b/arch/sparc/include/asm/smp_64.h @@ -12,16 +12,16 @@ #include #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #ifdef CONFIG_SMP -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* * Private routines/data @@ -68,7 +68,7 @@ int __cpu_disable(void); void __cpu_die(unsigned int cpu); #endif -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #else diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h index bc5aa6f61676..6d6d261bf8d2 100644 --- a/arch/sparc/include/asm/spinlock_32.h +++ b/arch/sparc/include/asm/spinlock_32.h @@ -7,7 +7,7 @@ #ifndef __SPARC_SPINLOCK_H #define __SPARC_SPINLOCK_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -183,6 +183,6 @@ static inline int __arch_read_trylock(arch_rwlock_t *rw) res; \ }) -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* __SPARC_SPINLOCK_H */ diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h index 3a9a0b0c7465..13cd15d346be 100644 --- a/arch/sparc/include/asm/spinlock_64.h +++ b/arch/sparc/include/asm/spinlock_64.h @@ -7,13 +7,13 @@ #ifndef __SPARC64_SPINLOCK_H #define __SPARC64_SPINLOCK_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include #include #include -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(__SPARC64_SPINLOCK_H) */ diff --git a/arch/sparc/include/asm/spitfire.h b/arch/sparc/include/asm/spitfire.h index e9b7d25b29fa..79b9dd5e9ac6 100644 --- a/arch/sparc/include/asm/spitfire.h +++ b/arch/sparc/include/asm/spitfire.h @@ -68,7 +68,7 @@ #define CPU_ID_M8 ('8') #define CPU_ID_SONOMA1 ('N') -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ enum ultra_tlb_layout { spitfire = 0, @@ -363,6 +363,6 @@ static inline void cheetah_put_itlb_data(int entry, unsigned long data) "i" (ASI_ITLB_DATA_ACCESS)); } -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* CONFIG_SPARC64 */ #endif /* !(_SPARC64_SPITFIRE_H) */ diff --git a/arch/sparc/include/asm/starfire.h b/arch/sparc/include/asm/starfire.h index fb1a8c499cb0..8e511ed78775 100644 --- a/arch/sparc/include/asm/starfire.h +++ b/arch/sparc/include/asm/starfire.h @@ -8,7 +8,7 @@ #ifndef _SPARC64_STARFIRE_H #define _SPARC64_STARFIRE_H -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ extern int this_is_starfire; diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h index 45b4955b253f..fdaf7b171e0a 100644 --- a/arch/sparc/include/asm/thread_info_32.h +++ b/arch/sparc/include/asm/thread_info_32.h @@ -14,7 +14,7 @@ #ifdef __KERNEL__ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -72,7 +72,7 @@ register struct thread_info *current_thread_info_reg asm("g6"); */ #define THREAD_SIZE_ORDER 1 -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ /* Size of kernel stack for each process */ #define THREAD_SIZE (2 * PAGE_SIZE) diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h index 1a44372e2bc0..c8a73dff27f8 100644 --- a/arch/sparc/include/asm/thread_info_64.h +++ b/arch/sparc/include/asm/thread_info_64.h @@ -26,7 +26,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include #include @@ -64,7 +64,7 @@ struct thread_info { __attribute__ ((aligned(64))); }; -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ /* offsets into the thread_info struct for assembly code access */ #define TI_TASK 0x00000000 @@ -110,7 +110,7 @@ struct thread_info { /* * macros/functions for gaining access to the thread information structure */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define INIT_THREAD_INFO(tsk) \ { \ @@ -150,7 +150,7 @@ extern struct thread_info *current_thread_info(void); #define set_thread_fpdepth(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH] = (val)) #define get_thread_wsaved() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED]) #define set_thread_wsaved(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED] = (val)) -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ /* * Thread information flags, only 16 bits are available as we encode @@ -228,14 +228,14 @@ extern struct thread_info *current_thread_info(void); * Note that there are only 8 bits available. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #define thread32_stack_is_64bit(__SP) (((__SP) & 0x1) != 0) #define test_thread_64bit_stack(__SP) \ ((test_thread_flag(TIF_32BIT) && !thread32_stack_is_64bit(__SP)) ? \ false : true) -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __KERNEL__ */ diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h index ace0d48e837e..6cf2a60a0156 100644 --- a/arch/sparc/include/asm/trap_block.h +++ b/arch/sparc/include/asm/trap_block.h @@ -7,7 +7,7 @@ #include #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* Trap handling code needs to get at a few critical values upon * trap entry and to process TSB misses. These cannot be in the @@ -91,7 +91,7 @@ extern struct sun4v_2insn_patch_entry __sun_m7_2insn_patch, __sun_m7_2insn_patch_end; -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #define TRAP_PER_CPU_THREAD 0x00 #define TRAP_PER_CPU_PGD_PADDR 0x08 diff --git a/arch/sparc/include/asm/traps.h b/arch/sparc/include/asm/traps.h index 2fba2602ba69..e4e10b0e7887 100644 --- a/arch/sparc/include/asm/traps.h +++ b/arch/sparc/include/asm/traps.h @@ -9,7 +9,7 @@ #include -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* This is for V8 compliant Sparc CPUS */ struct tt_entry { unsigned long inst_one; @@ -21,5 +21,5 @@ struct tt_entry { /* We set this to _start in system setup. */ extern struct tt_entry *sparc_ttable; -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* !(_SPARC_TRAPS_H) */ diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h index 522a677e050d..239be259e166 100644 --- a/arch/sparc/include/asm/tsb.h +++ b/arch/sparc/include/asm/tsb.h @@ -59,7 +59,7 @@ * The kernel TSB is locked into the TLB by virtue of being in the * kernel image, so we don't play these games for swapper_tsb access. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct tsb_ldquad_phys_patch_entry { unsigned int addr; unsigned int sun4u_insn; diff --git a/arch/sparc/include/asm/ttable.h b/arch/sparc/include/asm/ttable.h index 8f6469408019..b32d3068cce1 100644 --- a/arch/sparc/include/asm/ttable.h +++ b/arch/sparc/include/asm/ttable.h @@ -5,7 +5,7 @@ #include #include -#ifdef __ASSEMBLY__ +#ifdef __ASSEMBLER__ #include #endif diff --git a/arch/sparc/include/asm/turbosparc.h b/arch/sparc/include/asm/turbosparc.h index 23df777f9cea..5f73263b6ded 100644 --- a/arch/sparc/include/asm/turbosparc.h +++ b/arch/sparc/include/asm/turbosparc.h @@ -57,7 +57,7 @@ #define TURBOSPARC_WTENABLE 0x00000020 /* Write thru for dcache */ #define TURBOSPARC_SNENABLE 0x40000000 /* DVMA snoop enable */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* Bits [13:5] select one of 512 instruction cache tags */ static inline void turbosparc_inv_insn_tag(unsigned long addr) @@ -121,6 +121,6 @@ static inline unsigned long turbosparc_get_ccreg(void) return regval; } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* !(_SPARC_TURBOSPARC_H) */ diff --git a/arch/sparc/include/asm/upa.h b/arch/sparc/include/asm/upa.h index 782691b30f54..b1df3a7f40ed 100644 --- a/arch/sparc/include/asm/upa.h +++ b/arch/sparc/include/asm/upa.h @@ -24,7 +24,7 @@ #define UPA_PORTID_ID 0x000000000000ffff /* Module Identification bits */ /* UPA I/O space accessors */ -#if defined(__KERNEL__) && !defined(__ASSEMBLY__) +#if defined(__KERNEL__) && !defined(__ASSEMBLER__) static inline unsigned char _upa_readb(unsigned long addr) { unsigned char ret; @@ -105,6 +105,6 @@ static inline void _upa_writeq(unsigned long q, unsigned long addr) #define upa_writew(__w, __addr) (_upa_writew((__w), (unsigned long)(__addr))) #define upa_writel(__l, __addr) (_upa_writel((__l), (unsigned long)(__addr))) #define upa_writeq(__q, __addr) (_upa_writeq((__q), (unsigned long)(__addr))) -#endif /* __KERNEL__ && !__ASSEMBLY__ */ +#endif /* __KERNEL__ && !__ASSEMBLER__ */ #endif /* !(_SPARC64_UPA_H) */ diff --git a/arch/sparc/include/asm/vaddrs.h b/arch/sparc/include/asm/vaddrs.h index 4fec0341e2a8..da567600c897 100644 --- a/arch/sparc/include/asm/vaddrs.h +++ b/arch/sparc/include/asm/vaddrs.h @@ -31,7 +31,7 @@ */ #define SRMMU_NOCACHE_ALCRATIO 64 /* 256 pages per 64MB of system RAM */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ #include enum fixed_addresses { diff --git a/arch/sparc/include/asm/viking.h b/arch/sparc/include/asm/viking.h index 08ffc605035f..bbb714de43c4 100644 --- a/arch/sparc/include/asm/viking.h +++ b/arch/sparc/include/asm/viking.h @@ -110,7 +110,7 @@ #define VIKING_PTAG_DIRTY 0x00010000 /* Block has been modified */ #define VIKING_PTAG_SHARED 0x00000100 /* Shared with some other cache */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static inline void viking_flush_icache(void) { @@ -250,6 +250,6 @@ static inline unsigned long viking_hwprobe(unsigned long vaddr) return val; } -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* !(_SPARC_VIKING_H) */ diff --git a/arch/sparc/include/asm/visasm.h b/arch/sparc/include/asm/visasm.h index 7903e84e09e0..71eb4e9afb3e 100644 --- a/arch/sparc/include/asm/visasm.h +++ b/arch/sparc/include/asm/visasm.h @@ -45,7 +45,7 @@ #define VISExitHalfFast \ wr %o5, 0, %fprs; -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ static inline void save_and_clear_fpu(void) { __asm__ __volatile__ ( " rd %%fprs, %%o5\n" diff --git a/drivers/char/hw_random/n2rng.h b/drivers/char/hw_random/n2rng.h index 9a870f5dc371..7612f15a261f 100644 --- a/drivers/char/hw_random/n2rng.h +++ b/drivers/char/hw_random/n2rng.h @@ -48,7 +48,7 @@ #define HV_RNG_NUM_CONTROL 4 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ extern unsigned long sun4v_rng_get_diag_ctl(void); extern unsigned long sun4v_rng_ctl_read_v1(unsigned long ctl_regs_ra, unsigned long *state, @@ -147,6 +147,6 @@ struct n2rng { #define N2RNG_BUSY_LIMIT 100 #define N2RNG_HCHECK_LIMIT 100 -#endif /* !(__ASSEMBLY__) */ +#endif /* !(__ASSEMBLER__) */ #endif /* _N2RNG_H */ From 59d94ea8901cdab47dc65cabc790597eef99944f Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 22 Sep 2025 23:03:50 +0200 Subject: [PATCH 2171/2711] sparc: PCI: Replace deprecated strcpy() with strscpy() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/kernel/pcic.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 25fe0a061732..f894ae79e78a 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include /* for cache flushing. */ @@ -352,7 +353,7 @@ int __init pcic_probe(void) pbm = &pcic->pbm; pbm->prom_node = node; prom_getstring(node, "name", namebuf, 63); namebuf[63] = 0; - strcpy(pbm->prom_name, namebuf); + strscpy(pbm->prom_name, namebuf); { extern int pcic_nmi_trap_patch[4]; @@ -477,7 +478,7 @@ static void pcic_map_pci_device(struct linux_pcic *pcic, int j; if (node == 0 || node == -1) { - strcpy(namebuf, "???"); + strscpy(namebuf, "???"); } else { prom_getstring(node, "name", namebuf, 63); namebuf[63] = 0; } @@ -536,7 +537,7 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) char namebuf[64]; if (node == 0 || node == -1) { - strcpy(namebuf, "???"); + strscpy(namebuf, "???"); } else { prom_getstring(node, "name", namebuf, sizeof(namebuf)); } From 8ebfe29b710ba0c40531089ce649d0e4a776125a Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 22 Sep 2025 23:03:51 +0200 Subject: [PATCH 2172/2711] sparc: parport: Replace deprecated strcpy() with strscpy() in ecpp_probe() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/include/asm/parport_64.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/sparc/include/asm/parport_64.h b/arch/sparc/include/asm/parport_64.h index 3068809ef9ad..78f14d6620bf 100644 --- a/arch/sparc/include/asm/parport_64.h +++ b/arch/sparc/include/asm/parport_64.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -149,7 +150,7 @@ static int ecpp_probe(struct platform_device *op) sparc_ebus_dmas[slot].info.callback = NULL; sparc_ebus_dmas[slot].info.client_cookie = NULL; sparc_ebus_dmas[slot].info.irq = 0xdeadbeef; - strcpy(sparc_ebus_dmas[slot].info.name, "parport"); + strscpy(sparc_ebus_dmas[slot].info.name, "parport"); if (ebus_dma_register(&sparc_ebus_dmas[slot].info)) goto out_unmap_regs; From c7ae5d73b7af5723e7590015a570cd3cd397290b Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 22 Sep 2025 23:03:52 +0200 Subject: [PATCH 2173/2711] sparc: floppy: Replace deprecated strcpy() with strscpy() in sun_floppy_init() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/include/asm/floppy_64.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/sparc/include/asm/floppy_64.h b/arch/sparc/include/asm/floppy_64.h index b0f633ce3518..8d3ce6506607 100644 --- a/arch/sparc/include/asm/floppy_64.h +++ b/arch/sparc/include/asm/floppy_64.h @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -618,7 +619,7 @@ static unsigned long __init sun_floppy_init(void) sun_pci_fd_ebus_dma.callback = sun_pci_fd_dma_callback; sun_pci_fd_ebus_dma.client_cookie = NULL; sun_pci_fd_ebus_dma.irq = FLOPPY_IRQ; - strcpy(sun_pci_fd_ebus_dma.name, "floppy"); + strscpy(sun_pci_fd_ebus_dma.name, "floppy"); if (ebus_dma_register(&sun_pci_fd_ebus_dma)) return 0; From 9040d7c77e4d920c190ee2154d76e9daf4406de6 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 22 Sep 2025 23:03:53 +0200 Subject: [PATCH 2174/2711] sparc64: Replace deprecated strcpy() with strscpy() in prom_nextprop() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/prom/tree_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/prom/tree_64.c b/arch/sparc/prom/tree_64.c index 88793e5b0ab5..7388339bbd7e 100644 --- a/arch/sparc/prom/tree_64.c +++ b/arch/sparc/prom/tree_64.c @@ -272,7 +272,7 @@ char *prom_nextprop(phandle node, const char *oprop, char *buffer) return buffer; } if (oprop == buffer) { - strcpy (buf, oprop); + strscpy(buf, oprop); oprop = buf; } From dcdba5966c1ef9a6890e03fdaaf1bd1a5b66ee75 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 22 Sep 2025 23:03:54 +0200 Subject: [PATCH 2175/2711] sparc: Replace deprecated strcpy() with strscpy() in domain services driver strcpy() is deprecated; use strscpy() instead. In ldom_set_var(), use pr_err() instead of printk(KERN_ERR) to silence a checkpatch warning. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/kernel/ds.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index ffdc15588ac2..f7fc6f2af2f2 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c @@ -781,14 +781,17 @@ void ldom_set_var(const char *var, const char *value) } pkt; char *base, *p; int msg_len, loops; + size_t var_len, value_len; - if (strlen(var) + strlen(value) + 2 > - sizeof(pkt) - sizeof(pkt.header)) { - printk(KERN_ERR PFX - "contents length: %zu, which more than max: %lu," - "so could not set (%s) variable to (%s).\n", - strlen(var) + strlen(value) + 2, - sizeof(pkt) - sizeof(pkt.header), var, value); + var_len = strlen(var) + 1; + value_len = strlen(value) + 1; + + if (var_len + value_len > sizeof(pkt) - sizeof(pkt.header)) { + pr_err(PFX + "contents length: %zu, which more than max: %lu," + "so could not set (%s) variable to (%s).\n", + var_len + value_len, + sizeof(pkt) - sizeof(pkt.header), var, value); return; } @@ -797,10 +800,10 @@ void ldom_set_var(const char *var, const char *value) pkt.header.data.handle = cp->handle; pkt.header.msg.hdr.type = DS_VAR_SET_REQ; base = p = &pkt.header.msg.name_and_value[0]; - strcpy(p, var); - p += strlen(var) + 1; - strcpy(p, value); - p += strlen(value) + 1; + strscpy(p, var, var_len); + p += var_len; + strscpy(p, value, value_len); + p += value_len; msg_len = (sizeof(struct ds_data) + sizeof(struct ds_var_set_msg) + @@ -910,7 +913,7 @@ static int register_services(struct ds_info *dp) pbuf.req.handle = cp->handle; pbuf.req.major = 1; pbuf.req.minor = 0; - strcpy(pbuf.id_buf, cp->service_id); + strscpy(pbuf.id_buf, cp->service_id); err = __ds_send(lp, &pbuf, msg_len); if (err > 0) From b7b2c2f7e8848299c5cc8c596c49e90b0a39a3db Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 22 Sep 2025 23:03:55 +0200 Subject: [PATCH 2176/2711] sparc: Replace deprecated strcpy() with strscpy() in prom_32.c strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/kernel/prom_32.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/sparc/kernel/prom_32.c b/arch/sparc/kernel/prom_32.c index a67dd67f10c8..cd94f1e8d644 100644 --- a/arch/sparc/kernel/prom_32.c +++ b/arch/sparc/kernel/prom_32.c @@ -187,14 +187,16 @@ char * __init build_path_component(struct device_node *dp) { const char *name = of_get_property(dp, "name", NULL); char tmp_buf[64], *n; + size_t n_sz; tmp_buf[0] = '\0'; __build_path_component(dp, tmp_buf); if (tmp_buf[0] == '\0') - strcpy(tmp_buf, name); + strscpy(tmp_buf, name); - n = prom_early_alloc(strlen(tmp_buf) + 1); - strcpy(n, tmp_buf); + n_sz = strlen(tmp_buf) + 1; + n = prom_early_alloc(n_sz); + strscpy(n, tmp_buf, n_sz); return n; } @@ -204,13 +206,14 @@ extern void restore_current(void); void __init of_console_init(void) { char *msg = "OF stdout device is: %s\n"; + const size_t of_console_path_sz = 256; struct device_node *dp; unsigned long flags; const char *type; phandle node; int skip, tmp, fd; - of_console_path = prom_early_alloc(256); + of_console_path = prom_early_alloc(of_console_path_sz); switch (prom_vers) { case PROM_V0: @@ -297,7 +300,7 @@ void __init of_console_init(void) prom_printf("No stdout-path in root node.\n"); prom_halt(); } - strcpy(of_console_path, path); + strscpy(of_console_path, path, of_console_path_sz); } break; } From 79f76dfb4ee299eaba9be8c17d59e146a54e6752 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 22 Sep 2025 23:03:56 +0200 Subject: [PATCH 2177/2711] sparc64: Replace deprecated strcpy() with strscpy() in build_path_component() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/kernel/prom_64.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c index ba82884cb92a..aa4799cbb9c1 100644 --- a/arch/sparc/kernel/prom_64.c +++ b/arch/sparc/kernel/prom_64.c @@ -361,14 +361,16 @@ char * __init build_path_component(struct device_node *dp) { const char *name = of_get_property(dp, "name", NULL); char tmp_buf[64], *n; + size_t n_sz; tmp_buf[0] = '\0'; __build_path_component(dp, tmp_buf); if (tmp_buf[0] == '\0') - strcpy(tmp_buf, name); + strscpy(tmp_buf, name); - n = prom_early_alloc(strlen(tmp_buf) + 1); - strcpy(n, tmp_buf); + n_sz = strlen(tmp_buf) + 1; + n = prom_early_alloc(n_sz); + strscpy(n, tmp_buf, n_sz); return n; } From fe0126702a40b2f3d315bc943ef10dc2f707e29d Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 22 Sep 2025 23:03:57 +0200 Subject: [PATCH 2178/2711] sparc: Replace deprecated strcpy() with strscpy() in handle_nextprop_quirks() strcpy() is deprecated; use strscpy() instead. No functional changes intended. Link: https://github.com/KSPP/linux/issues/88 Signed-off-by: Thorsten Blum Reviewed-by: Andreas Larsson Signed-off-by: Andreas Larsson --- arch/sparc/kernel/prom_common.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c index c9ec70888a39..d258fd10db01 100644 --- a/arch/sparc/kernel/prom_common.c +++ b/arch/sparc/kernel/prom_common.c @@ -120,11 +120,14 @@ EXPORT_SYMBOL(of_find_in_proplist); */ static int __init handle_nextprop_quirks(char *buf, const char *name) { - if (!name || strlen(name) == 0) + size_t name_len; + + name_len = name ? strlen(name) : 0; + if (name_len == 0) return -1; #ifdef CONFIG_SPARC32 - strcpy(buf, name); + strscpy(buf, name, name_len + 1); #endif return 0; } From 05703271c3cdcc0f2a8cf6ebdc45892b8ca83520 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Tue, 26 Aug 2025 10:52:08 +0200 Subject: [PATCH 2179/2711] PCI/IOV: Add PCI rescan-remove locking when enabling/disabling SR-IOV Before disabling SR-IOV via config space accesses to the parent PF, sriov_disable() first removes the PCI devices representing the VFs. Since commit 9d16947b7583 ("PCI: Add global pci_lock_rescan_remove()") such removal operations are serialized against concurrent remove and rescan using the pci_rescan_remove_lock. No such locking was ever added in sriov_disable() however. In particular when commit 18f9e9d150fc ("PCI/IOV: Factor out sriov_add_vfs()") factored out the PCI device removal into sriov_del_vfs() there was still no locking around the pci_iov_remove_virtfn() calls. On s390 the lack of serialization in sriov_disable() may cause double remove and list corruption with the below (amended) trace being observed: PSW: 0704c00180000000 0000000c914e4b38 (klist_put+56) GPRS: 000003800313fb48 0000000000000000 0000000100000001 0000000000000001 00000000f9b520a8 0000000000000000 0000000000002fbd 00000000f4cc9480 0000000000000001 0000000000000000 0000000000000000 0000000180692828 00000000818e8000 000003800313fe2c 000003800313fb20 000003800313fad8 #0 [3800313fb20] device_del at c9158ad5c #1 [3800313fb88] pci_remove_bus_device at c915105ba #2 [3800313fbd0] pci_iov_remove_virtfn at c9152f198 #3 [3800313fc28] zpci_iov_remove_virtfn at c90fb67c0 #4 [3800313fc60] zpci_bus_remove_device at c90fb6104 #5 [3800313fca0] __zpci_event_availability at c90fb3dca #6 [3800313fd08] chsc_process_sei_nt0 at c918fe4a2 #7 [3800313fd60] crw_collect_info at c91905822 #8 [3800313fe10] kthread at c90feb390 #9 [3800313fe68] __ret_from_fork at c90f6aa64 #10 [3800313fe98] ret_from_fork at c9194f3f2. This is because in addition to sriov_disable() removing the VFs, the platform also generates hot-unplug events for the VFs. This being the reverse operation to the hotplug events generated by sriov_enable() and handled via pdev->no_vf_scan. And while the event processing takes pci_rescan_remove_lock and checks whether the struct pci_dev still exists, the lack of synchronization makes this checking racy. Other races may also be possible of course though given that this lack of locking persisted so long observable races seem very rare. Even on s390 the list corruption was only observed with certain devices since the platform events are only triggered by config accesses after the removal, so as long as the removal finished synchronously they would not race. Either way the locking is missing so fix this by adding it to the sriov_del_vfs() helper. Just like PCI rescan-remove, locking is also missing in sriov_add_vfs() including for the error case where pci_stop_and_remove_bus_device() is called without the PCI rescan-remove lock being held. Even in the non-error case, adding new PCI devices and buses should be serialized via the PCI rescan-remove lock. Add the necessary locking. Fixes: 18f9e9d150fc ("PCI/IOV: Factor out sriov_add_vfs()") Signed-off-by: Niklas Schnelle Signed-off-by: Bjorn Helgaas Reviewed-by: Benjamin Block Reviewed-by: Farhan Ali Reviewed-by: Julian Ruess Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250826-pci_fix_sriov_disable-v1-1-2d0bc938f2a3@linux.ibm.com --- drivers/pci/iov.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index ac4375954c94..77dee43b7858 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -629,15 +629,18 @@ static int sriov_add_vfs(struct pci_dev *dev, u16 num_vfs) if (dev->no_vf_scan) return 0; + pci_lock_rescan_remove(); for (i = 0; i < num_vfs; i++) { rc = pci_iov_add_virtfn(dev, i); if (rc) goto failed; } + pci_unlock_rescan_remove(); return 0; failed: while (i--) pci_iov_remove_virtfn(dev, i); + pci_unlock_rescan_remove(); return rc; } @@ -762,8 +765,10 @@ static void sriov_del_vfs(struct pci_dev *dev) struct pci_sriov *iov = dev->sriov; int i; + pci_lock_rescan_remove(); for (i = 0; i < iov->num_VFs; i++) pci_iov_remove_virtfn(dev, i); + pci_unlock_rescan_remove(); } static void sriov_disable(struct pci_dev *dev) From 60e7b5aa85712f7f2fc75b2e9d28444de88ab47f Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Tue, 26 Aug 2025 10:52:09 +0200 Subject: [PATCH 2180/2711] PCI: Add lockdep assertion in pci_stop_and_remove_bus_device() Removing a PCI devices requires holding pci_rescan_remove_lock. Prompted by this being missed in sriov_disable() and going unnoticed since its inception, add a lockdep assert so this doesn't get missed again in the future. Signed-off-by: Niklas Schnelle Signed-off-by: Bjorn Helgaas Reviewed-by: Benjamin Block Reviewed-by: Julian Ruess Link: https://patch.msgid.link/20250826-pci_fix_sriov_disable-v1-2-2d0bc938f2a3@linux.ibm.com --- drivers/pci/pci.h | 2 ++ drivers/pci/probe.c | 2 +- drivers/pci/remove.c | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 34f65d69662e..1ad2e3ab147f 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -84,6 +84,8 @@ struct pcie_tlp_log; extern const unsigned char pcie_link_speed[]; extern bool pci_early_dump; +extern struct mutex pci_rescan_remove_lock; + bool pcie_cap_has_lnkctl(const struct pci_dev *dev); bool pcie_cap_has_lnkctl2(const struct pci_dev *dev); bool pcie_cap_has_rtctl(const struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f41128f91ca7..2b35bb39ab03 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -3469,7 +3469,7 @@ EXPORT_SYMBOL_GPL(pci_rescan_bus); * pci_rescan_bus(), pci_rescan_bus_bridge_resize() and PCI device removal * routines should always be executed under this mutex. */ -static DEFINE_MUTEX(pci_rescan_remove_lock); +DEFINE_MUTEX(pci_rescan_remove_lock); void pci_lock_rescan_remove(void) { diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 445afdfa6498..0b9a609392ce 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -138,6 +138,7 @@ static void pci_remove_bus_device(struct pci_dev *dev) */ void pci_stop_and_remove_bus_device(struct pci_dev *dev) { + lockdep_assert_held(&pci_rescan_remove_lock); pci_stop_bus_device(dev); pci_remove_bus_device(dev); } From cef730075cfe2b2091e3c94471cc0a78405401d5 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 26 Sep 2025 14:22:45 +0200 Subject: [PATCH 2181/2711] PCI: dwc: Support 16-lane operation Some hosts support 16 lanes of PCIe. Make num-lanes accept that number. Signed-off-by: Konrad Dybcio Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250926-topic-pcie_16ln-v1-1-c249acc18790@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-designware.c | 3 +++ drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 89aad5a08928..42e4d8efba81 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -841,6 +841,9 @@ static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes) case 8: plc |= PORT_LINK_MODE_8_LANES; break; + case 16: + plc |= PORT_LINK_MODE_16_LANES; + break; default: dev_err(pci->dev, "num-lanes %u: invalid value\n", num_lanes); return; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 00f52d472dcd..ed0cbb038038 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -90,6 +90,7 @@ #define PORT_LINK_MODE_2_LANES PORT_LINK_MODE(0x3) #define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7) #define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf) +#define PORT_LINK_MODE_16_LANES PORT_LINK_MODE(0x1f) #define PCIE_PORT_LANE_SKEW 0x714 #define PORT_LANE_SKEW_INSERT_MASK GENMASK(23, 0) From 96a17ed17b369109b662b40345df961b412c1cd3 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Fri, 19 Sep 2025 19:53:25 +0530 Subject: [PATCH 2182/2711] dt-bindings: PCI: qcom,pcie-x1e80100: Set clocks minItems for the fifth Glymur PCIe Controller On the Qualcomm Glymur platform, the fifth PCIe host is compatible with the DWC controller present on the X1E80100 platform, but does not have cnoc_sf_axi clock. Hence, set minItems of clocks and clock-names to six. Signed-off-by: Qiang Yu Signed-off-by: Pankaj Patil Signed-off-by: Bjorn Helgaas Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250919142325.1090059-1-pankaj.patil@oss.qualcomm.com --- Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml index 257068a18264..61581ffbfb24 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml @@ -32,10 +32,11 @@ properties: - const: mhi # MHI registers clocks: - minItems: 7 + minItems: 6 maxItems: 7 clock-names: + minItems: 6 items: - const: aux # Auxiliary clock - const: cfg # Configuration clock From 344823886eafe5fe17ed788b00e463666c2183b4 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Sat, 6 Sep 2025 21:23:19 -0500 Subject: [PATCH 2183/2711] tools/rtla: Consolidate common parameters into shared structure timerlat_params and osnoise_params structures contain 15 identical fields. Introduce a new header common.h and define a common_params structure to consolidate shared fields, reduce code duplication, and enhance maintainability. Cc: John Kacur Link: https://lore.kernel.org/20250907022325.243930-2-crwood@redhat.com Reviewed-by: Tomas Glozar Signed-off-by: Costa Shulyupin Signed-off-by: Crystal Wood Signed-off-by: Steven Rostedt (Google) --- tools/tracing/rtla/src/common.h | 30 +++++++ tools/tracing/rtla/src/osnoise.c | 20 ++--- tools/tracing/rtla/src/osnoise.h | 19 +---- tools/tracing/rtla/src/osnoise_hist.c | 92 ++++++++++---------- tools/tracing/rtla/src/osnoise_top.c | 80 ++++++++--------- tools/tracing/rtla/src/timerlat.c | 24 +++--- tools/tracing/rtla/src/timerlat.h | 18 +--- tools/tracing/rtla/src/timerlat_bpf.c | 4 +- tools/tracing/rtla/src/timerlat_hist.c | 113 +++++++++++++------------ tools/tracing/rtla/src/timerlat_top.c | 105 +++++++++++------------ 10 files changed, 253 insertions(+), 252 deletions(-) create mode 100644 tools/tracing/rtla/src/common.h diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h new file mode 100644 index 000000000000..0a44cfaa7c0b --- /dev/null +++ b/tools/tracing/rtla/src/common.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#pragma once + +#include "utils.h" + +/* + * common_params - Parameters shared between timerlat_params and osnoise_params + */ +struct common_params { + /* trace configuration */ + char *cpus; + cpu_set_t monitored_cpus; + struct trace_events *events; + int buffer_size; + + /* Timing parameters */ + int warmup; + long long stop_us; + long long stop_total_us; + int sleep_time; + int duration; + + /* Scheduling parameters */ + int set_sched; + struct sched_attr sched_param; + int cgroup; + char *cgroup_name; + int hk_cpus; + cpu_set_t hk_cpu_set; +}; diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c index 2dc3e4539e99..06ae7437c2c7 100644 --- a/tools/tracing/rtla/src/osnoise.c +++ b/tools/tracing/rtla/src/osnoise.c @@ -1127,10 +1127,10 @@ osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) { int retval; - if (!params->sleep_time) - params->sleep_time = 1; + if (!params->common.sleep_time) + params->common.sleep_time = 1; - retval = osnoise_set_cpus(tool->context, params->cpus ? params->cpus : "all"); + retval = osnoise_set_cpus(tool->context, params->common.cpus ? params->common.cpus : "all"); if (retval) { err_msg("Failed to apply CPUs config\n"); goto out_err; @@ -1151,13 +1151,13 @@ osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) goto out_err; } - retval = osnoise_set_stop_us(tool->context, params->stop_us); + retval = osnoise_set_stop_us(tool->context, params->common.stop_us); if (retval) { err_msg("Failed to set stop us\n"); goto out_err; } - retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); + retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us); if (retval) { err_msg("Failed to set stop total us\n"); goto out_err; @@ -1169,14 +1169,14 @@ osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) goto out_err; } - if (params->hk_cpus) { - retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set), - ¶ms->hk_cpu_set); + if (params->common.hk_cpus) { + retval = sched_setaffinity(getpid(), sizeof(params->common.hk_cpu_set), + ¶ms->common.hk_cpu_set); if (retval == -1) { err_msg("Failed to set rtla to the house keeping CPUs\n"); goto out_err; } - } else if (params->cpus) { + } else if (params->common.cpus) { /* * Even if the user do not set a house-keeping CPU, try to * move rtla to a CPU set different to the one where the user @@ -1184,7 +1184,7 @@ osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) * * No need to check results as this is an automatic attempt. */ - auto_house_keeping(¶ms->monitored_cpus); + auto_house_keeping(¶ms->common.monitored_cpus); } retval = osnoise_set_workload(tool->context, true); diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h index ac1c99910744..0386bb50ffa1 100644 --- a/tools/tracing/rtla/src/osnoise.h +++ b/tools/tracing/rtla/src/osnoise.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #pragma once -#include "utils.h" +#include "common.h" #include "trace.h" enum osnoise_mode { @@ -10,26 +10,11 @@ enum osnoise_mode { }; struct osnoise_params { - /* Common params */ - char *cpus; - cpu_set_t monitored_cpus; + struct common_params common; char *trace_output; - char *cgroup_name; unsigned long long runtime; unsigned long long period; long long threshold; - long long stop_us; - long long stop_total_us; - int sleep_time; - int duration; - int set_sched; - int cgroup; - int hk_cpus; - cpu_set_t hk_cpu_set; - struct sched_attr sched_param; - struct trace_events *events; - int warmup; - int buffer_size; union { struct { /* top only */ diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index 8d579bcee709..3fb9bb553498 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -243,7 +243,7 @@ static void osnoise_hist_header(struct osnoise_tool *tool) trace_seq_printf(s, "Index"); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].count) @@ -274,7 +274,7 @@ osnoise_print_summary(struct osnoise_params *params, trace_seq_printf(trace->seq, "count:"); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].count) @@ -288,7 +288,7 @@ osnoise_print_summary(struct osnoise_params *params, trace_seq_printf(trace->seq, "min: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].count) @@ -303,7 +303,7 @@ osnoise_print_summary(struct osnoise_params *params, trace_seq_printf(trace->seq, "avg: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].count) @@ -321,7 +321,7 @@ osnoise_print_summary(struct osnoise_params *params, trace_seq_printf(trace->seq, "max: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].count) @@ -357,7 +357,7 @@ osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *tool) bucket * data->bucket_size); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].count) @@ -395,7 +395,7 @@ osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *tool) trace_seq_printf(trace->seq, "over: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].count) @@ -537,7 +537,7 @@ static struct osnoise_params switch (c) { case 'a': /* set sample stop to auto_thresh */ - params->stop_us = get_llong_from_str(optarg); + params->common.stop_us = get_llong_from_str(optarg); /* set sample threshold to 1 */ params->threshold = 1; @@ -552,27 +552,27 @@ static struct osnoise_params osnoise_hist_usage("Bucket size needs to be > 0 and <= 1000000\n"); break; case 'c': - retval = parse_cpu_set(optarg, ¶ms->monitored_cpus); + retval = parse_cpu_set(optarg, ¶ms->common.monitored_cpus); if (retval) osnoise_hist_usage("\nInvalid -c cpu list\n"); - params->cpus = optarg; + params->common.cpus = optarg; break; case 'C': - params->cgroup = 1; + params->common.cgroup = 1; if (!optarg) { /* will inherit this cgroup */ - params->cgroup_name = NULL; + params->common.cgroup_name = NULL; } else if (*optarg == '=') { /* skip the = */ - params->cgroup_name = ++optarg; + params->common.cgroup_name = ++optarg; } break; case 'D': config_debug = 1; break; case 'd': - params->duration = parse_seconds_duration(optarg); - if (!params->duration) + params->common.duration = parse_seconds_duration(optarg); + if (!params->common.duration) osnoise_hist_usage("Invalid -D duration\n"); break; case 'e': @@ -582,10 +582,10 @@ static struct osnoise_params exit(EXIT_FAILURE); } - if (params->events) - tevent->next = params->events; + if (params->common.events) + tevent->next = params->common.events; - params->events = tevent; + params->common.events = tevent; break; case 'E': params->entries = get_llong_from_str(optarg); @@ -597,8 +597,8 @@ static struct osnoise_params osnoise_hist_usage(NULL); break; case 'H': - params->hk_cpus = 1; - retval = parse_cpu_set(optarg, ¶ms->hk_cpu_set); + params->common.hk_cpus = 1; + retval = parse_cpu_set(optarg, ¶ms->common.hk_cpu_set); if (retval) { err_msg("Error parsing house keeping CPUs\n"); exit(EXIT_FAILURE); @@ -610,10 +610,10 @@ static struct osnoise_params osnoise_hist_usage("Period longer than 10 s\n"); break; case 'P': - retval = parse_prio(optarg, ¶ms->sched_param); + retval = parse_prio(optarg, ¶ms->common.sched_param); if (retval == -1) osnoise_hist_usage("Invalid -P priority"); - params->set_sched = 1; + params->common.set_sched = 1; break; case 'r': params->runtime = get_llong_from_str(optarg); @@ -621,10 +621,10 @@ static struct osnoise_params osnoise_hist_usage("Runtime shorter than 100 us\n"); break; case 's': - params->stop_us = get_llong_from_str(optarg); + params->common.stop_us = get_llong_from_str(optarg); break; case 'S': - params->stop_total_us = get_llong_from_str(optarg); + params->common.stop_total_us = get_llong_from_str(optarg); break; case 'T': params->threshold = get_llong_from_str(optarg); @@ -653,8 +653,8 @@ static struct osnoise_params params->with_zeros = 1; break; case '4': /* trigger */ - if (params->events) { - retval = trace_event_add_trigger(params->events, optarg); + if (params->common.events) { + retval = trace_event_add_trigger(params->common.events, optarg); if (retval) { err_msg("Error adding trigger %s\n", optarg); exit(EXIT_FAILURE); @@ -664,8 +664,8 @@ static struct osnoise_params } break; case '5': /* filter */ - if (params->events) { - retval = trace_event_add_filter(params->events, optarg); + if (params->common.events) { + retval = trace_event_add_filter(params->common.events, optarg); if (retval) { err_msg("Error adding filter %s\n", optarg); exit(EXIT_FAILURE); @@ -675,10 +675,10 @@ static struct osnoise_params } break; case '6': - params->warmup = get_llong_from_str(optarg); + params->common.warmup = get_llong_from_str(optarg); break; case '7': - params->buffer_size = get_llong_from_str(optarg); + params->common.buffer_size = get_llong_from_str(optarg); break; default: osnoise_hist_usage("Invalid option"); @@ -755,9 +755,9 @@ static void osnoise_hist_set_signals(struct osnoise_params *params) { signal(SIGINT, stop_hist); - if (params->duration) { + if (params->common.duration) { signal(SIGALRM, stop_hist); - alarm(params->duration); + alarm(params->common.duration); } } @@ -798,16 +798,16 @@ int osnoise_hist_main(int argc, char *argv[]) if (retval) goto out_destroy; - if (params->set_sched) { - retval = set_comm_sched_attr("osnoise/", ¶ms->sched_param); + if (params->common.set_sched) { + retval = set_comm_sched_attr("osnoise/", ¶ms->common.sched_param); if (retval) { err_msg("Failed to set sched parameters\n"); goto out_free; } } - if (params->cgroup) { - retval = set_comm_cgroup("timerlat/", params->cgroup_name); + if (params->common.cgroup) { + retval = set_comm_cgroup("timerlat/", params->common.cgroup_name); if (!retval) { err_msg("Failed to move threads to cgroup\n"); goto out_free; @@ -821,14 +821,14 @@ int osnoise_hist_main(int argc, char *argv[]) goto out_free; } - if (params->events) { - retval = trace_events_enable(&record->trace, params->events); + if (params->common.events) { + retval = trace_events_enable(&record->trace, params->common.events); if (retval) goto out_hist; } - if (params->buffer_size > 0) { - retval = trace_set_buffer_size(&record->trace, params->buffer_size); + if (params->common.buffer_size > 0) { + retval = trace_set_buffer_size(&record->trace, params->common.buffer_size); if (retval) goto out_hist; } @@ -845,9 +845,9 @@ int osnoise_hist_main(int argc, char *argv[]) trace_instance_start(&record->trace); trace_instance_start(trace); - if (params->warmup > 0) { - debug_msg("Warming up for %d seconds\n", params->warmup); - sleep(params->warmup); + if (params->common.warmup > 0) { + debug_msg("Warming up for %d seconds\n", params->common.warmup); + sleep(params->common.warmup); if (stop_tracing) goto out_hist; @@ -868,7 +868,7 @@ int osnoise_hist_main(int argc, char *argv[]) osnoise_hist_set_signals(params); while (!stop_tracing) { - sleep(params->sleep_time); + sleep(params->common.sleep_time); retval = tracefs_iterate_raw_events(trace->tep, trace->inst, @@ -899,8 +899,8 @@ int osnoise_hist_main(int argc, char *argv[]) } out_hist: - trace_events_destroy(&record->trace, params->events); - params->events = NULL; + trace_events_destroy(&record->trace, params->common.events); + params->common.events = NULL; out_free: osnoise_free_histogram(tool->data); out_destroy: diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 2c12780c8aa9..ad5daa8210aa 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -238,7 +238,7 @@ osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *top) osnoise_top_header(top); for (i = 0; i < nr_cpus; i++) { - if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) continue; osnoise_top_print(top, i); } @@ -377,7 +377,7 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) switch (c) { case 'a': /* set sample stop to auto_thresh */ - params->stop_us = get_llong_from_str(optarg); + params->common.stop_us = get_llong_from_str(optarg); /* set sample threshold to 1 */ params->threshold = 1; @@ -387,27 +387,27 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) break; case 'c': - retval = parse_cpu_set(optarg, ¶ms->monitored_cpus); + retval = parse_cpu_set(optarg, ¶ms->common.monitored_cpus); if (retval) osnoise_top_usage(params, "\nInvalid -c cpu list\n"); - params->cpus = optarg; + params->common.cpus = optarg; break; case 'C': - params->cgroup = 1; + params->common.cgroup = 1; if (!optarg) { /* will inherit this cgroup */ - params->cgroup_name = NULL; + params->common.cgroup_name = NULL; } else if (*optarg == '=') { /* skip the = */ - params->cgroup_name = ++optarg; + params->common.cgroup_name = ++optarg; } break; case 'D': config_debug = 1; break; case 'd': - params->duration = parse_seconds_duration(optarg); - if (!params->duration) + params->common.duration = parse_seconds_duration(optarg); + if (!params->common.duration) osnoise_top_usage(params, "Invalid -d duration\n"); break; case 'e': @@ -417,9 +417,9 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) exit(EXIT_FAILURE); } - if (params->events) - tevent->next = params->events; - params->events = tevent; + if (params->common.events) + tevent->next = params->common.events; + params->common.events = tevent; break; case 'h': @@ -427,8 +427,8 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) osnoise_top_usage(params, NULL); break; case 'H': - params->hk_cpus = 1; - retval = parse_cpu_set(optarg, ¶ms->hk_cpu_set); + params->common.hk_cpus = 1; + retval = parse_cpu_set(optarg, ¶ms->common.hk_cpu_set); if (retval) { err_msg("Error parsing house keeping CPUs\n"); exit(EXIT_FAILURE); @@ -440,10 +440,10 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) osnoise_top_usage(params, "Period longer than 10 s\n"); break; case 'P': - retval = parse_prio(optarg, ¶ms->sched_param); + retval = parse_prio(optarg, ¶ms->common.sched_param); if (retval == -1) osnoise_top_usage(params, "Invalid -P priority"); - params->set_sched = 1; + params->common.set_sched = 1; break; case 'q': params->quiet = 1; @@ -454,10 +454,10 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) osnoise_top_usage(params, "Runtime shorter than 100 us\n"); break; case 's': - params->stop_us = get_llong_from_str(optarg); + params->common.stop_us = get_llong_from_str(optarg); break; case 'S': - params->stop_total_us = get_llong_from_str(optarg); + params->common.stop_total_us = get_llong_from_str(optarg); break; case 't': if (optarg) { @@ -474,8 +474,8 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) params->threshold = get_llong_from_str(optarg); break; case '0': /* trigger */ - if (params->events) { - retval = trace_event_add_trigger(params->events, optarg); + if (params->common.events) { + retval = trace_event_add_trigger(params->common.events, optarg); if (retval) { err_msg("Error adding trigger %s\n", optarg); exit(EXIT_FAILURE); @@ -485,8 +485,8 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) } break; case '1': /* filter */ - if (params->events) { - retval = trace_event_add_filter(params->events, optarg); + if (params->common.events) { + retval = trace_event_add_filter(params->common.events, optarg); if (retval) { err_msg("Error adding filter %s\n", optarg); exit(EXIT_FAILURE); @@ -496,10 +496,10 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) } break; case '2': - params->warmup = get_llong_from_str(optarg); + params->common.warmup = get_llong_from_str(optarg); break; case '3': - params->buffer_size = get_llong_from_str(optarg); + params->common.buffer_size = get_llong_from_str(optarg); break; default: osnoise_top_usage(params, "Invalid option"); @@ -583,9 +583,9 @@ static void stop_top(int sig) static void osnoise_top_set_signals(struct osnoise_params *params) { signal(SIGINT, stop_top); - if (params->duration) { + if (params->common.duration) { signal(SIGALRM, stop_top); - alarm(params->duration); + alarm(params->common.duration); } } @@ -622,16 +622,16 @@ int osnoise_top_main(int argc, char **argv) goto out_free; } - if (params->set_sched) { - retval = set_comm_sched_attr("osnoise/", ¶ms->sched_param); + if (params->common.set_sched) { + retval = set_comm_sched_attr("osnoise/", ¶ms->common.sched_param); if (retval) { err_msg("Failed to set sched parameters\n"); goto out_free; } } - if (params->cgroup) { - retval = set_comm_cgroup("osnoise/", params->cgroup_name); + if (params->common.cgroup) { + retval = set_comm_cgroup("osnoise/", params->common.cgroup_name); if (!retval) { err_msg("Failed to move threads to cgroup\n"); goto out_free; @@ -645,14 +645,14 @@ int osnoise_top_main(int argc, char **argv) goto out_free; } - if (params->events) { - retval = trace_events_enable(&record->trace, params->events); + if (params->common.events) { + retval = trace_events_enable(&record->trace, params->common.events); if (retval) goto out_top; } - if (params->buffer_size > 0) { - retval = trace_set_buffer_size(&record->trace, params->buffer_size); + if (params->common.buffer_size > 0) { + retval = trace_set_buffer_size(&record->trace, params->common.buffer_size); if (retval) goto out_top; } @@ -669,9 +669,9 @@ int osnoise_top_main(int argc, char **argv) trace_instance_start(&record->trace); trace_instance_start(trace); - if (params->warmup > 0) { - debug_msg("Warming up for %d seconds\n", params->warmup); - sleep(params->warmup); + if (params->common.warmup > 0) { + debug_msg("Warming up for %d seconds\n", params->common.warmup); + sleep(params->common.warmup); if (stop_tracing) goto out_top; @@ -692,7 +692,7 @@ int osnoise_top_main(int argc, char **argv) osnoise_top_set_signals(params); while (!stop_tracing) { - sleep(params->sleep_time); + sleep(params->common.sleep_time); retval = tracefs_iterate_raw_events(trace->tep, trace->inst, @@ -725,8 +725,8 @@ int osnoise_top_main(int argc, char **argv) } out_top: - trace_events_destroy(&record->trace, params->events); - params->events = NULL; + trace_events_destroy(&record->trace, params->common.events); + params->common.events = NULL; out_free: osnoise_free_top(tool->data); osnoise_destroy_tool(record); diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c index 63d6d43eafff..0b2f03e1e612 100644 --- a/tools/tracing/rtla/src/timerlat.c +++ b/tools/tracing/rtla/src/timerlat.c @@ -26,18 +26,18 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) { int retval, i; - if (!params->sleep_time) - params->sleep_time = 1; + if (!params->common.sleep_time) + params->common.sleep_time = 1; - retval = osnoise_set_cpus(tool->context, params->cpus ? params->cpus : "all"); + retval = osnoise_set_cpus(tool->context, params->common.cpus ? params->common.cpus : "all"); if (retval) { err_msg("Failed to apply CPUs config\n"); goto out_err; } - if (!params->cpus) { + if (!params->common.cpus) { for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) - CPU_SET(i, ¶ms->monitored_cpus); + CPU_SET(i, ¶ms->common.monitored_cpus); } if (params->mode != TRACING_MODE_BPF) { @@ -45,13 +45,13 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) * In tracefs and mixed mode, timerlat tracer handles stopping * on threshold */ - retval = osnoise_set_stop_us(tool->context, params->stop_us); + retval = osnoise_set_stop_us(tool->context, params->common.stop_us); if (retval) { err_msg("Failed to set stop us\n"); goto out_err; } - retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); + retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us); if (retval) { err_msg("Failed to set stop total us\n"); goto out_err; @@ -75,14 +75,14 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) goto out_err; } - if (params->hk_cpus) { - retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set), - ¶ms->hk_cpu_set); + if (params->common.hk_cpus) { + retval = sched_setaffinity(getpid(), sizeof(params->common.hk_cpu_set), + ¶ms->common.hk_cpu_set); if (retval == -1) { err_msg("Failed to set rtla to the house keeping CPUs\n"); goto out_err; } - } else if (params->cpus) { + } else if (params->common.cpus) { /* * Even if the user do not set a house-keeping CPU, try to * move rtla to a CPU set different to the one where the user @@ -90,7 +90,7 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) * * No need to check results as this is an automatic attempt. */ - auto_house_keeping(¶ms->monitored_cpus); + auto_house_keeping(¶ms->common.monitored_cpus); } /* diff --git a/tools/tracing/rtla/src/timerlat.h b/tools/tracing/rtla/src/timerlat.h index bc55ed04fc96..dd9e0f05bdad 100644 --- a/tools/tracing/rtla/src/timerlat.h +++ b/tools/tracing/rtla/src/timerlat.h @@ -20,33 +20,17 @@ enum timerlat_tracing_mode { }; struct timerlat_params { - /* Common params */ - char *cpus; - cpu_set_t monitored_cpus; - char *cgroup_name; - unsigned long long runtime; - long long stop_us; - long long stop_total_us; + struct common_params common; long long timerlat_period_us; long long print_stack; - int sleep_time; int output_divisor; - int duration; - int set_sched; int dma_latency; int no_aa; int dump_tasks; - int cgroup; - int hk_cpus; int user_workload; int kernel_workload; int user_data; - int warmup; - int buffer_size; int deepest_idle_state; - cpu_set_t hk_cpu_set; - struct sched_attr sched_param; - struct trace_events *events; enum timerlat_tracing_mode mode; struct actions threshold_actions; diff --git a/tools/tracing/rtla/src/timerlat_bpf.c b/tools/tracing/rtla/src/timerlat_bpf.c index 1666215dd687..a6c77ac55e00 100644 --- a/tools/tracing/rtla/src/timerlat_bpf.c +++ b/tools/tracing/rtla/src/timerlat_bpf.c @@ -23,8 +23,8 @@ int timerlat_bpf_init(struct timerlat_params *params) /* Pass common options */ bpf->rodata->output_divisor = params->output_divisor; bpf->rodata->entries = params->entries; - bpf->rodata->irq_threshold = params->stop_us; - bpf->rodata->thread_threshold = params->stop_total_us; + bpf->rodata->irq_threshold = params->common.stop_us; + bpf->rodata->thread_threshold = params->common.stop_total_us; bpf->rodata->aa_only = params->aa_only; if (params->entries != 0) { diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index 9baea1b251ed..a3de644f2b75 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -303,7 +303,7 @@ static void timerlat_hist_header(struct osnoise_tool *tool) trace_seq_printf(s, "Index"); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) @@ -357,7 +357,7 @@ timerlat_print_summary(struct timerlat_params *params, trace_seq_printf(trace->seq, "count:"); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) @@ -381,7 +381,7 @@ timerlat_print_summary(struct timerlat_params *params, trace_seq_printf(trace->seq, "min: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) @@ -411,7 +411,7 @@ timerlat_print_summary(struct timerlat_params *params, trace_seq_printf(trace->seq, "avg: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) @@ -441,7 +441,7 @@ timerlat_print_summary(struct timerlat_params *params, trace_seq_printf(trace->seq, "max: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) @@ -488,7 +488,7 @@ timerlat_print_stats_all(struct timerlat_params *params, sum.min_user = ~0; for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) @@ -636,7 +636,7 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) bucket * data->bucket_size); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) @@ -676,7 +676,7 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) trace_seq_printf(trace->seq, "over: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { - if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(cpu, ¶ms->common.monitored_cpus)) continue; if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) @@ -867,8 +867,8 @@ static struct timerlat_params auto_thresh = get_llong_from_str(optarg); /* set thread stop to auto_thresh */ - params->stop_total_us = auto_thresh; - params->stop_us = auto_thresh; + params->common.stop_total_us = auto_thresh; + params->common.stop_us = auto_thresh; /* get stack trace */ params->print_stack = auto_thresh; @@ -878,19 +878,19 @@ static struct timerlat_params break; case 'c': - retval = parse_cpu_set(optarg, ¶ms->monitored_cpus); + retval = parse_cpu_set(optarg, ¶ms->common.monitored_cpus); if (retval) timerlat_hist_usage("\nInvalid -c cpu list\n"); - params->cpus = optarg; + params->common.cpus = optarg; break; case 'C': - params->cgroup = 1; + params->common.cgroup = 1; if (!optarg) { /* will inherit this cgroup */ - params->cgroup_name = NULL; + params->common.cgroup_name = NULL; } else if (*optarg == '=') { /* skip the = */ - params->cgroup_name = ++optarg; + params->common.cgroup_name = ++optarg; } break; case 'b': @@ -902,8 +902,8 @@ static struct timerlat_params config_debug = 1; break; case 'd': - params->duration = parse_seconds_duration(optarg); - if (!params->duration) + params->common.duration = parse_seconds_duration(optarg); + if (!params->common.duration) timerlat_hist_usage("Invalid -D duration\n"); break; case 'e': @@ -913,10 +913,10 @@ static struct timerlat_params exit(EXIT_FAILURE); } - if (params->events) - tevent->next = params->events; + if (params->common.events) + tevent->next = params->common.events; - params->events = tevent; + params->common.events = tevent; break; case 'E': params->entries = get_llong_from_str(optarg); @@ -928,15 +928,15 @@ static struct timerlat_params timerlat_hist_usage(NULL); break; case 'H': - params->hk_cpus = 1; - retval = parse_cpu_set(optarg, ¶ms->hk_cpu_set); + params->common.hk_cpus = 1; + retval = parse_cpu_set(optarg, ¶ms->common.hk_cpu_set); if (retval) { err_msg("Error parsing house keeping CPUs\n"); exit(EXIT_FAILURE); } break; case 'i': - params->stop_us = get_llong_from_str(optarg); + params->common.stop_us = get_llong_from_str(optarg); break; case 'k': params->kernel_workload = 1; @@ -950,16 +950,16 @@ static struct timerlat_params timerlat_hist_usage("Period longer than 1 s\n"); break; case 'P': - retval = parse_prio(optarg, ¶ms->sched_param); + retval = parse_prio(optarg, ¶ms->common.sched_param); if (retval == -1) timerlat_hist_usage("Invalid -P priority"); - params->set_sched = 1; + params->common.set_sched = 1; break; case 's': params->print_stack = get_llong_from_str(optarg); break; case 'T': - params->stop_total_us = get_llong_from_str(optarg); + params->common.stop_total_us = get_llong_from_str(optarg); break; case 't': if (optarg) { @@ -997,8 +997,8 @@ static struct timerlat_params params->with_zeros = 1; break; case '6': /* trigger */ - if (params->events) { - retval = trace_event_add_trigger(params->events, optarg); + if (params->common.events) { + retval = trace_event_add_trigger(params->common.events, optarg); if (retval) { err_msg("Error adding trigger %s\n", optarg); exit(EXIT_FAILURE); @@ -1008,8 +1008,8 @@ static struct timerlat_params } break; case '7': /* filter */ - if (params->events) { - retval = trace_event_add_filter(params->events, optarg); + if (params->common.events) { + retval = trace_event_add_filter(params->common.events, optarg); if (retval) { err_msg("Error adding filter %s\n", optarg); exit(EXIT_FAILURE); @@ -1032,10 +1032,10 @@ static struct timerlat_params params->dump_tasks = 1; break; case '\2': - params->warmup = get_llong_from_str(optarg); + params->common.warmup = get_llong_from_str(optarg); break; case '\3': - params->buffer_size = get_llong_from_str(optarg); + params->common.buffer_size = get_llong_from_str(optarg); break; case '\4': params->deepest_idle_state = get_llong_from_str(optarg); @@ -1076,7 +1076,7 @@ static struct timerlat_params /* * Auto analysis only happens if stop tracing, thus: */ - if (!params->stop_us && !params->stop_total_us) + if (!params->common.stop_us && !params->common.stop_total_us) params->no_aa = 1; if (params->kernel_workload && params->user_workload) @@ -1167,9 +1167,9 @@ static void timerlat_hist_set_signals(struct timerlat_params *params) { signal(SIGINT, stop_hist); - if (params->duration) { + if (params->common.duration) { signal(SIGALRM, stop_hist); - alarm(params->duration); + alarm(params->common.duration); } } @@ -1235,16 +1235,16 @@ int timerlat_hist_main(int argc, char *argv[]) goto out_free; } - if (params->set_sched) { - retval = set_comm_sched_attr("timerlat/", ¶ms->sched_param); + if (params->common.set_sched) { + retval = set_comm_sched_attr("timerlat/", ¶ms->common.sched_param); if (retval) { err_msg("Failed to set sched parameters\n"); goto out_free; } } - if (params->cgroup && !params->user_workload) { - retval = set_comm_cgroup("timerlat/", params->cgroup_name); + if (params->common.cgroup && !params->user_workload) { + retval = set_comm_cgroup("timerlat/", params->common.cgroup_name); if (!retval) { err_msg("Failed to move threads to cgroup\n"); goto out_free; @@ -1268,7 +1268,7 @@ int timerlat_hist_main(int argc, char *argv[]) nr_cpus = sysconf(_SC_NPROCESSORS_CONF); for (i = 0; i < nr_cpus; i++) { - if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) continue; if (save_cpu_idle_disable_state(i) < 0) { err_msg("Could not save cpu idle state.\n"); @@ -1291,14 +1291,14 @@ int timerlat_hist_main(int argc, char *argv[]) params->threshold_actions.trace_output_inst = record->trace.inst; params->end_actions.trace_output_inst = record->trace.inst; - if (params->events) { - retval = trace_events_enable(&record->trace, params->events); + if (params->common.events) { + retval = trace_events_enable(&record->trace, params->common.events); if (retval) goto out_hist; } - if (params->buffer_size > 0) { - retval = trace_set_buffer_size(&record->trace, params->buffer_size); + if (params->common.buffer_size > 0) { + retval = trace_set_buffer_size(&record->trace, params->common.buffer_size); if (retval) goto out_hist; } @@ -1328,22 +1328,22 @@ int timerlat_hist_main(int argc, char *argv[]) /* all threads left */ params_u.stopped_running = 0; - params_u.set = ¶ms->monitored_cpus; - if (params->set_sched) - params_u.sched_param = ¶ms->sched_param; + params_u.set = ¶ms->common.monitored_cpus; + if (params->common.set_sched) + params_u.sched_param = ¶ms->common.sched_param; else params_u.sched_param = NULL; - params_u.cgroup_name = params->cgroup_name; + params_u.cgroup_name = params->common.cgroup_name; retval = pthread_create(&timerlat_u, NULL, timerlat_u_dispatcher, ¶ms_u); if (retval) err_msg("Error creating timerlat user-space threads\n"); } - if (params->warmup > 0) { - debug_msg("Warming up for %d seconds\n", params->warmup); - sleep(params->warmup); + if (params->common.warmup > 0) { + debug_msg("Warming up for %d seconds\n", params->common.warmup); + sleep(params->common.warmup); if (stop_tracing) goto out_hist; } @@ -1374,7 +1374,7 @@ int timerlat_hist_main(int argc, char *argv[]) if (params->mode == TRACING_MODE_TRACEFS) { while (!stop_tracing) { - sleep(params->sleep_time); + sleep(params->common.sleep_time); retval = tracefs_iterate_raw_events(trace->tep, trace->inst, @@ -1456,7 +1456,8 @@ int timerlat_hist_main(int argc, char *argv[]) printf("rtla timerlat hit stop tracing\n"); if (!params->no_aa) - timerlat_auto_analysis(params->stop_us, params->stop_total_us); + timerlat_auto_analysis(params->common.stop_us, + params->common.stop_total_us); return_value = FAILED; } @@ -1467,13 +1468,13 @@ out_hist: close(dma_latency_fd); if (params->deepest_idle_state >= -1) { for (i = 0; i < nr_cpus; i++) { - if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) continue; restore_cpu_idle_disable_state(i); } } - trace_events_destroy(&record->trace, params->events); - params->events = NULL; + trace_events_destroy(&record->trace, params->common.events); + params->common.events = NULL; out_free: timerlat_free_histogram(tool->data); osnoise_destroy_tool(aa); diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index c80b81c0b4da..9fb60f4dd092 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -457,7 +457,7 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *top) timerlat_top_header(params, top); for (i = 0; i < nr_cpus; i++) { - if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) continue; timerlat_top_print(top, i); timerlat_top_update_sum(top, i, &summary); @@ -618,8 +618,8 @@ static struct timerlat_params auto_thresh = get_llong_from_str(optarg); /* set thread stop to auto_thresh */ - params->stop_total_us = auto_thresh; - params->stop_us = auto_thresh; + params->common.stop_total_us = auto_thresh; + params->common.stop_us = auto_thresh; /* get stack trace */ params->print_stack = auto_thresh; @@ -633,8 +633,8 @@ static struct timerlat_params auto_thresh = get_llong_from_str(optarg); /* set thread stop to auto_thresh */ - params->stop_total_us = auto_thresh; - params->stop_us = auto_thresh; + params->common.stop_total_us = auto_thresh; + params->common.stop_us = auto_thresh; /* get stack trace */ params->print_stack = auto_thresh; @@ -643,27 +643,27 @@ static struct timerlat_params params->aa_only = 1; break; case 'c': - retval = parse_cpu_set(optarg, ¶ms->monitored_cpus); + retval = parse_cpu_set(optarg, ¶ms->common.monitored_cpus); if (retval) timerlat_top_usage("\nInvalid -c cpu list\n"); - params->cpus = optarg; + params->common.cpus = optarg; break; case 'C': - params->cgroup = 1; + params->common.cgroup = 1; if (!optarg) { /* will inherit this cgroup */ - params->cgroup_name = NULL; + params->common.cgroup_name = NULL; } else if (*optarg == '=') { /* skip the = */ - params->cgroup_name = ++optarg; + params->common.cgroup_name = ++optarg; } break; case 'D': config_debug = 1; break; case 'd': - params->duration = parse_seconds_duration(optarg); - if (!params->duration) + params->common.duration = parse_seconds_duration(optarg); + if (!params->common.duration) timerlat_top_usage("Invalid -d duration\n"); break; case 'e': @@ -673,24 +673,24 @@ static struct timerlat_params exit(EXIT_FAILURE); } - if (params->events) - tevent->next = params->events; - params->events = tevent; + if (params->common.events) + tevent->next = params->common.events; + params->common.events = tevent; break; case 'h': case '?': timerlat_top_usage(NULL); break; case 'H': - params->hk_cpus = 1; - retval = parse_cpu_set(optarg, ¶ms->hk_cpu_set); + params->common.hk_cpus = 1; + retval = parse_cpu_set(optarg, ¶ms->common.hk_cpu_set); if (retval) { err_msg("Error parsing house keeping CPUs\n"); exit(EXIT_FAILURE); } break; case 'i': - params->stop_us = get_llong_from_str(optarg); + params->common.stop_us = get_llong_from_str(optarg); break; case 'k': params->kernel_workload = true; @@ -704,10 +704,10 @@ static struct timerlat_params timerlat_top_usage("Period longer than 1 s\n"); break; case 'P': - retval = parse_prio(optarg, ¶ms->sched_param); + retval = parse_prio(optarg, ¶ms->common.sched_param); if (retval == -1) timerlat_top_usage("Invalid -P priority"); - params->set_sched = 1; + params->common.set_sched = 1; break; case 'q': params->quiet = 1; @@ -716,7 +716,7 @@ static struct timerlat_params params->print_stack = get_llong_from_str(optarg); break; case 'T': - params->stop_total_us = get_llong_from_str(optarg); + params->common.stop_total_us = get_llong_from_str(optarg); break; case 't': if (optarg) { @@ -736,8 +736,8 @@ static struct timerlat_params params->user_data = true; break; case '0': /* trigger */ - if (params->events) { - retval = trace_event_add_trigger(params->events, optarg); + if (params->common.events) { + retval = trace_event_add_trigger(params->common.events, optarg); if (retval) { err_msg("Error adding trigger %s\n", optarg); exit(EXIT_FAILURE); @@ -747,8 +747,8 @@ static struct timerlat_params } break; case '1': /* filter */ - if (params->events) { - retval = trace_event_add_filter(params->events, optarg); + if (params->common.events) { + retval = trace_event_add_filter(params->common.events, optarg); if (retval) { err_msg("Error adding filter %s\n", optarg); exit(EXIT_FAILURE); @@ -771,10 +771,10 @@ static struct timerlat_params params->dump_tasks = 1; break; case '6': - params->warmup = get_llong_from_str(optarg); + params->common.warmup = get_llong_from_str(optarg); break; case '7': - params->buffer_size = get_llong_from_str(optarg); + params->common.buffer_size = get_llong_from_str(optarg); break; case '8': params->deepest_idle_state = get_llong_from_str(optarg); @@ -809,7 +809,7 @@ static struct timerlat_params /* * Auto analysis only happens if stop tracing, thus: */ - if (!params->stop_us && !params->stop_total_us) + if (!params->common.stop_us && !params->common.stop_total_us) params->no_aa = 1; if (params->no_aa && params->aa_only) @@ -906,9 +906,9 @@ static void timerlat_top_set_signals(struct timerlat_params *params) { signal(SIGINT, stop_top); - if (params->duration) { + if (params->common.duration) { signal(SIGALRM, stop_top); - alarm(params->duration); + alarm(params->common.duration); } } @@ -926,7 +926,7 @@ timerlat_top_main_loop(struct osnoise_tool *top, int retval; while (!stop_tracing) { - sleep(params->sleep_time); + sleep(params->common.sleep_time); if (params->aa_only && !osnoise_trace_is_off(top, record)) continue; @@ -992,7 +992,7 @@ timerlat_top_bpf_main_loop(struct osnoise_tool *top, /* Pull and display data in a loop */ while (!stop_tracing) { - wait_retval = timerlat_bpf_wait(params->quiet ? -1 : params->sleep_time); + wait_retval = timerlat_bpf_wait(params->quiet ? -1 : params->common.sleep_time); retval = timerlat_top_bpf_pull_data(top); if (retval) { @@ -1094,16 +1094,16 @@ int timerlat_top_main(int argc, char *argv[]) goto out_free; } - if (params->set_sched) { - retval = set_comm_sched_attr("timerlat/", ¶ms->sched_param); + if (params->common.set_sched) { + retval = set_comm_sched_attr("timerlat/", ¶ms->common.sched_param); if (retval) { err_msg("Failed to set sched parameters\n"); goto out_free; } } - if (params->cgroup && !params->user_data) { - retval = set_comm_cgroup("timerlat/", params->cgroup_name); + if (params->common.cgroup && !params->user_data) { + retval = set_comm_cgroup("timerlat/", params->common.cgroup_name); if (!retval) { err_msg("Failed to move threads to cgroup\n"); goto out_free; @@ -1127,7 +1127,7 @@ int timerlat_top_main(int argc, char *argv[]) nr_cpus = sysconf(_SC_NPROCESSORS_CONF); for (i = 0; i < nr_cpus; i++) { - if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) continue; if (save_cpu_idle_disable_state(i) < 0) { err_msg("Could not save cpu idle state.\n"); @@ -1150,14 +1150,14 @@ int timerlat_top_main(int argc, char *argv[]) params->threshold_actions.trace_output_inst = record->trace.inst; params->end_actions.trace_output_inst = record->trace.inst; - if (params->events) { - retval = trace_events_enable(&record->trace, params->events); + if (params->common.events) { + retval = trace_events_enable(&record->trace, params->common.events); if (retval) goto out_top; } - if (params->buffer_size > 0) { - retval = trace_set_buffer_size(&record->trace, params->buffer_size); + if (params->common.buffer_size > 0) { + retval = trace_set_buffer_size(&record->trace, params->common.buffer_size); if (retval) goto out_top; } @@ -1190,22 +1190,22 @@ int timerlat_top_main(int argc, char *argv[]) /* all threads left */ params_u.stopped_running = 0; - params_u.set = ¶ms->monitored_cpus; - if (params->set_sched) - params_u.sched_param = ¶ms->sched_param; + params_u.set = ¶ms->common.monitored_cpus; + if (params->common.set_sched) + params_u.sched_param = ¶ms->common.sched_param; else params_u.sched_param = NULL; - params_u.cgroup_name = params->cgroup_name; + params_u.cgroup_name = params->common.cgroup_name; retval = pthread_create(&timerlat_u, NULL, timerlat_u_dispatcher, ¶ms_u); if (retval) err_msg("Error creating timerlat user-space threads\n"); } - if (params->warmup > 0) { - debug_msg("Warming up for %d seconds\n", params->warmup); - sleep(params->warmup); + if (params->common.warmup > 0) { + debug_msg("Warming up for %d seconds\n", params->common.warmup); + sleep(params->common.warmup); } /* @@ -1258,7 +1258,8 @@ int timerlat_top_main(int argc, char *argv[]) printf("rtla timerlat hit stop tracing\n"); if (!params->no_aa) - timerlat_auto_analysis(params->stop_us, params->stop_total_us); + timerlat_auto_analysis(params->common.stop_us, + params->common.stop_total_us); return_value = FAILED; } else if (params->aa_only) { @@ -1279,13 +1280,13 @@ out_top: close(dma_latency_fd); if (params->deepest_idle_state >= -1) { for (i = 0; i < nr_cpus; i++) { - if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus)) + if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) continue; restore_cpu_idle_disable_state(i); } } - trace_events_destroy(&record->trace, params->events); - params->events = NULL; + trace_events_destroy(&record->trace, params->common.events); + params->common.events = NULL; out_free: timerlat_free_top(top->data); if (aa && aa != top) From 5742bf62e6d3070f04a2ea688758431537076129 Mon Sep 17 00:00:00 2001 From: Crystal Wood Date: Sat, 6 Sep 2025 21:23:20 -0500 Subject: [PATCH 2184/2711] tools/rtla: Move top/hist params into common struct The hist members were very similar between timerlat and top, so just use one common hist struct. output_divisor, quiet, and pretty printing are pretty generic concepts that can go in the main struct even if not every specific tool (currently) uses them. Cc: John Kacur Cc: Costa Shulyupin Link: https://lore.kernel.org/20250907022325.243930-3-crwood@redhat.com Reviewed-by: Tomas Glozar Signed-off-by: Crystal Wood Signed-off-by: Steven Rostedt (Google) --- tools/tracing/rtla/src/common.h | 17 ++++ tools/tracing/rtla/src/osnoise.h | 19 +--- tools/tracing/rtla/src/osnoise_hist.c | 59 ++++++------ tools/tracing/rtla/src/osnoise_top.c | 19 ++-- tools/tracing/rtla/src/timerlat.h | 22 +---- tools/tracing/rtla/src/timerlat_bpf.c | 14 +-- tools/tracing/rtla/src/timerlat_hist.c | 127 +++++++++++++------------ tools/tracing/rtla/src/timerlat_top.c | 38 ++++---- 8 files changed, 152 insertions(+), 163 deletions(-) diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h index 0a44cfaa7c0b..276dfbc7f955 100644 --- a/tools/tracing/rtla/src/common.h +++ b/tools/tracing/rtla/src/common.h @@ -3,6 +3,17 @@ #include "utils.h" +struct hist_params { + char no_irq; + char no_thread; + char no_header; + char no_summary; + char no_index; + char with_zeros; + int bucket_size; + int entries; +}; + /* * common_params - Parameters shared between timerlat_params and osnoise_params */ @@ -27,4 +38,10 @@ struct common_params { char *cgroup_name; int hk_cpus; cpu_set_t hk_cpu_set; + + /* Other parameters */ + struct hist_params hist; + int output_divisor; + int pretty_output; + int quiet; }; diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h index 0386bb50ffa1..b64b39de97b5 100644 --- a/tools/tracing/rtla/src/osnoise.h +++ b/tools/tracing/rtla/src/osnoise.h @@ -15,24 +15,7 @@ struct osnoise_params { unsigned long long runtime; unsigned long long period; long long threshold; - union { - struct { - /* top only */ - int quiet; - int pretty_output; - enum osnoise_mode mode; - }; - struct { - /* hist only */ - int output_divisor; - char no_header; - char no_summary; - char no_index; - char with_zeros; - int bucket_size; - int entries; - }; - }; + enum osnoise_mode mode; }; /* diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index 3fb9bb553498..a31ab9b4ab21 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -102,8 +102,8 @@ static void osnoise_hist_update_multiple(struct osnoise_tool *tool, int cpu, int bucket; int *hist; - if (params->output_divisor) - duration = duration / params->output_divisor; + if (params->common.output_divisor) + duration = duration / params->common.output_divisor; bucket = duration / data->bucket_size; @@ -146,7 +146,7 @@ static int osnoise_init_trace_hist(struct osnoise_tool *tool) /* * Set the size of the bucket. */ - bucket_size = params->output_divisor * params->bucket_size; + bucket_size = params->common.output_divisor * params->common.hist.bucket_size; snprintf(buff, sizeof(buff), "duration.buckets=%d", bucket_size); data->trace_hist = tracefs_hist_alloc(tool->trace.tep, "osnoise", "sample_threshold", @@ -228,18 +228,18 @@ static void osnoise_hist_header(struct osnoise_tool *tool) char duration[26]; int cpu; - if (params->no_header) + if (params->common.hist.no_header) return; get_duration(tool->start_time, duration, sizeof(duration)); trace_seq_printf(s, "# RTLA osnoise histogram\n"); trace_seq_printf(s, "# Time unit is %s (%s)\n", - params->output_divisor == 1 ? "nanoseconds" : "microseconds", - params->output_divisor == 1 ? "ns" : "us"); + params->common.output_divisor == 1 ? "nanoseconds" : "microseconds", + params->common.output_divisor == 1 ? "ns" : "us"); trace_seq_printf(s, "# Duration: %s\n", duration); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(s, "Index"); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -267,10 +267,10 @@ osnoise_print_summary(struct osnoise_params *params, { int cpu; - if (params->no_summary) + if (params->common.hist.no_summary) return; - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "count:"); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -284,7 +284,7 @@ osnoise_print_summary(struct osnoise_params *params, } trace_seq_printf(trace->seq, "\n"); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "min: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -299,7 +299,7 @@ osnoise_print_summary(struct osnoise_params *params, } trace_seq_printf(trace->seq, "\n"); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "avg: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -317,7 +317,7 @@ osnoise_print_summary(struct osnoise_params *params, } trace_seq_printf(trace->seq, "\n"); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "max: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -352,7 +352,7 @@ osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *tool) for (bucket = 0; bucket < data->entries; bucket++) { total = 0; - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "%-6d", bucket * data->bucket_size); @@ -367,7 +367,7 @@ osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *tool) trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].samples[bucket]); } - if (total == 0 && !params->with_zeros) { + if (total == 0 && !params->common.hist.with_zeros) { trace_seq_reset(trace->seq); continue; } @@ -391,7 +391,7 @@ osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *tool) return; } - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "over: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -490,9 +490,9 @@ static struct osnoise_params exit(1); /* display data in microseconds */ - params->output_divisor = 1000; - params->bucket_size = 1; - params->entries = 256; + params->common.output_divisor = 1000; + params->common.hist.bucket_size = 1; + params->common.hist.entries = 256; while (1) { static struct option long_options[] = { @@ -547,8 +547,9 @@ static struct osnoise_params break; case 'b': - params->bucket_size = get_llong_from_str(optarg); - if ((params->bucket_size == 0) || (params->bucket_size >= 1000000)) + params->common.hist.bucket_size = get_llong_from_str(optarg); + if (params->common.hist.bucket_size == 0 || + params->common.hist.bucket_size >= 1000000) osnoise_hist_usage("Bucket size needs to be > 0 and <= 1000000\n"); break; case 'c': @@ -588,8 +589,9 @@ static struct osnoise_params params->common.events = tevent; break; case 'E': - params->entries = get_llong_from_str(optarg); - if ((params->entries < 10) || (params->entries > 9999999)) + params->common.hist.entries = get_llong_from_str(optarg); + if (params->common.hist.entries < 10 || + params->common.hist.entries > 9999999) osnoise_hist_usage("Entries must be > 10 and < 9999999\n"); break; case 'h': @@ -641,16 +643,16 @@ static struct osnoise_params params->trace_output = "osnoise_trace.txt"; break; case '0': /* no header */ - params->no_header = 1; + params->common.hist.no_header = 1; break; case '1': /* no summary */ - params->no_summary = 1; + params->common.hist.no_summary = 1; break; case '2': /* no index */ - params->no_index = 1; + params->common.hist.no_index = 1; break; case '3': /* with zeros */ - params->with_zeros = 1; + params->common.hist.with_zeros = 1; break; case '4': /* trigger */ if (params->common.events) { @@ -690,7 +692,7 @@ static struct osnoise_params exit(EXIT_FAILURE); } - if (params->no_index && !params->with_zeros) + if (params->common.hist.no_index && !params->common.hist.with_zeros) osnoise_hist_usage("no-index set and with-zeros not set - it does not make sense"); return params; @@ -729,7 +731,8 @@ static struct osnoise_tool if (!tool) return NULL; - tool->data = osnoise_alloc_histogram(nr_cpus, params->entries, params->bucket_size); + tool->data = osnoise_alloc_histogram(nr_cpus, params->common.hist.entries, + params->common.hist.bucket_size); if (!tool->data) goto out_err; diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index ad5daa8210aa..7c68feed300e 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -125,11 +125,12 @@ static void osnoise_top_header(struct osnoise_tool *top) { struct osnoise_params *params = top->params; struct trace_seq *s = top->trace.seq; + bool pretty = params->common.pretty_output; char duration[26]; get_duration(top->start_time, duration, sizeof(duration)); - if (params->pretty_output) + if (pretty) trace_seq_printf(s, "\033[2;37;40m"); trace_seq_printf(s, " "); @@ -143,13 +144,13 @@ static void osnoise_top_header(struct osnoise_tool *top) trace_seq_printf(s, " "); - if (params->pretty_output) + if (pretty) trace_seq_printf(s, "\033[0;0;0m"); trace_seq_printf(s, "\n"); trace_seq_printf(s, "duration: %9s | time is in us\n", duration); - if (params->pretty_output) + if (pretty) trace_seq_printf(s, "\033[2;30;47m"); trace_seq_printf(s, "CPU Period Runtime "); @@ -164,7 +165,7 @@ static void osnoise_top_header(struct osnoise_tool *top) trace_seq_printf(s, " IRQ Softirq Thread"); eol: - if (params->pretty_output) + if (pretty) trace_seq_printf(s, "\033[0;0;0m"); trace_seq_printf(s, "\n"); } @@ -232,7 +233,7 @@ osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *top) if (nr_cpus == -1) nr_cpus = sysconf(_SC_NPROCESSORS_CONF); - if (!params->quiet) + if (!params->common.quiet) clear_terminal(trace->seq); osnoise_top_header(top); @@ -446,7 +447,7 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) params->common.set_sched = 1; break; case 'q': - params->quiet = 1; + params->common.quiet = 1; break; case 'r': params->runtime = get_llong_from_str(optarg); @@ -534,8 +535,8 @@ osnoise_top_apply_config(struct osnoise_tool *tool, struct osnoise_params *param } } - if (isatty(STDOUT_FILENO) && !params->quiet) - params->pretty_output = 1; + if (isatty(STDOUT_FILENO) && !params->common.quiet) + params->common.pretty_output = 1; return 0; @@ -705,7 +706,7 @@ int osnoise_top_main(int argc, char **argv) goto out_top; } - if (!params->quiet) + if (!params->common.quiet) osnoise_print_stats(params, tool); if (osnoise_trace_is_off(tool, record)) diff --git a/tools/tracing/rtla/src/timerlat.h b/tools/tracing/rtla/src/timerlat.h index dd9e0f05bdad..212ee7971bab 100644 --- a/tools/tracing/rtla/src/timerlat.h +++ b/tools/tracing/rtla/src/timerlat.h @@ -23,7 +23,6 @@ struct timerlat_params { struct common_params common; long long timerlat_period_us; long long print_stack; - int output_divisor; int dma_latency; int no_aa; int dump_tasks; @@ -31,30 +30,11 @@ struct timerlat_params { int kernel_workload; int user_data; int deepest_idle_state; + int aa_only; enum timerlat_tracing_mode mode; struct actions threshold_actions; struct actions end_actions; - - union { - struct { - /* top only */ - int quiet; - int aa_only; - int pretty_output; - }; - struct { - /* hist only */ - char no_irq; - char no_thread; - char no_header; - char no_summary; - char no_index; - char with_zeros; - int bucket_size; - int entries; - }; - }; }; int timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params); diff --git a/tools/tracing/rtla/src/timerlat_bpf.c b/tools/tracing/rtla/src/timerlat_bpf.c index a6c77ac55e00..03be2606f54a 100644 --- a/tools/tracing/rtla/src/timerlat_bpf.c +++ b/tools/tracing/rtla/src/timerlat_bpf.c @@ -21,20 +21,20 @@ int timerlat_bpf_init(struct timerlat_params *params) return 1; /* Pass common options */ - bpf->rodata->output_divisor = params->output_divisor; - bpf->rodata->entries = params->entries; + bpf->rodata->output_divisor = params->common.output_divisor; + bpf->rodata->entries = params->common.hist.entries; bpf->rodata->irq_threshold = params->common.stop_us; bpf->rodata->thread_threshold = params->common.stop_total_us; bpf->rodata->aa_only = params->aa_only; - if (params->entries != 0) { + if (params->common.hist.entries != 0) { /* Pass histogram options */ - bpf->rodata->bucket_size = params->bucket_size; + bpf->rodata->bucket_size = params->common.hist.bucket_size; /* Set histogram array sizes */ - bpf_map__set_max_entries(bpf->maps.hist_irq, params->entries); - bpf_map__set_max_entries(bpf->maps.hist_thread, params->entries); - bpf_map__set_max_entries(bpf->maps.hist_user, params->entries); + bpf_map__set_max_entries(bpf->maps.hist_irq, params->common.hist.entries); + bpf_map__set_max_entries(bpf->maps.hist_thread, params->common.hist.entries); + bpf_map__set_max_entries(bpf->maps.hist_user, params->common.hist.entries); } else { /* No entries, disable histogram */ bpf_map__set_autocreate(bpf->maps.hist_irq, false); diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index a3de644f2b75..4dc22a749885 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -141,8 +141,8 @@ timerlat_hist_update(struct osnoise_tool *tool, int cpu, int bucket; int *hist; - if (params->output_divisor) - latency = latency / params->output_divisor; + if (params->common.output_divisor) + latency = latency / params->common.output_divisor; bucket = latency / data->bucket_size; @@ -288,18 +288,18 @@ static void timerlat_hist_header(struct osnoise_tool *tool) char duration[26]; int cpu; - if (params->no_header) + if (params->common.hist.no_header) return; get_duration(tool->start_time, duration, sizeof(duration)); trace_seq_printf(s, "# RTLA timerlat histogram\n"); trace_seq_printf(s, "# Time unit is %s (%s)\n", - params->output_divisor == 1 ? "nanoseconds" : "microseconds", - params->output_divisor == 1 ? "ns" : "us"); + params->common.output_divisor == 1 ? "nanoseconds" : "microseconds", + params->common.output_divisor == 1 ? "ns" : "us"); trace_seq_printf(s, "# Duration: %s\n", duration); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(s, "Index"); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -309,10 +309,10 @@ static void timerlat_hist_header(struct osnoise_tool *tool) if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) continue; - if (!params->no_irq) + if (!params->common.hist.no_irq) trace_seq_printf(s, " IRQ-%03d", cpu); - if (!params->no_thread) + if (!params->common.hist.no_thread) trace_seq_printf(s, " Thr-%03d", cpu); if (params->user_data) @@ -350,10 +350,10 @@ timerlat_print_summary(struct timerlat_params *params, { int cpu; - if (params->no_summary) + if (params->common.hist.no_summary) return; - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "count:"); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -363,11 +363,11 @@ timerlat_print_summary(struct timerlat_params *params, if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) continue; - if (!params->no_irq) + if (!params->common.hist.no_irq) trace_seq_printf(trace->seq, "%9llu ", data->hist[cpu].irq_count); - if (!params->no_thread) + if (!params->common.hist.no_thread) trace_seq_printf(trace->seq, "%9llu ", data->hist[cpu].thread_count); @@ -377,7 +377,7 @@ timerlat_print_summary(struct timerlat_params *params, } trace_seq_printf(trace->seq, "\n"); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "min: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -387,13 +387,13 @@ timerlat_print_summary(struct timerlat_params *params, if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) continue; - if (!params->no_irq) + if (!params->common.hist.no_irq) format_summary_value(trace->seq, data->hist[cpu].irq_count, data->hist[cpu].min_irq, false); - if (!params->no_thread) + if (!params->common.hist.no_thread) format_summary_value(trace->seq, data->hist[cpu].thread_count, data->hist[cpu].min_thread, @@ -407,7 +407,7 @@ timerlat_print_summary(struct timerlat_params *params, } trace_seq_printf(trace->seq, "\n"); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "avg: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -417,13 +417,13 @@ timerlat_print_summary(struct timerlat_params *params, if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) continue; - if (!params->no_irq) + if (!params->common.hist.no_irq) format_summary_value(trace->seq, data->hist[cpu].irq_count, data->hist[cpu].sum_irq, true); - if (!params->no_thread) + if (!params->common.hist.no_thread) format_summary_value(trace->seq, data->hist[cpu].thread_count, data->hist[cpu].sum_thread, @@ -437,7 +437,7 @@ timerlat_print_summary(struct timerlat_params *params, } trace_seq_printf(trace->seq, "\n"); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "max: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -447,13 +447,13 @@ timerlat_print_summary(struct timerlat_params *params, if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) continue; - if (!params->no_irq) + if (!params->common.hist.no_irq) format_summary_value(trace->seq, data->hist[cpu].irq_count, data->hist[cpu].max_irq, false); - if (!params->no_thread) + if (!params->common.hist.no_thread) format_summary_value(trace->seq, data->hist[cpu].thread_count, data->hist[cpu].max_thread, @@ -479,7 +479,7 @@ timerlat_print_stats_all(struct timerlat_params *params, struct timerlat_hist_cpu sum; int cpu; - if (params->no_summary) + if (params->common.hist.no_summary) return; memset(&sum, 0, sizeof(sum)); @@ -512,13 +512,13 @@ timerlat_print_stats_all(struct timerlat_params *params, update_max(&sum.max_user, &cpu_data->max_user); } - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "ALL: "); - if (!params->no_irq) + if (!params->common.hist.no_irq) trace_seq_printf(trace->seq, " IRQ"); - if (!params->no_thread) + if (!params->common.hist.no_thread) trace_seq_printf(trace->seq, " Thr"); if (params->user_data) @@ -526,14 +526,14 @@ timerlat_print_stats_all(struct timerlat_params *params, trace_seq_printf(trace->seq, "\n"); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "count:"); - if (!params->no_irq) + if (!params->common.hist.no_irq) trace_seq_printf(trace->seq, "%9llu ", sum.irq_count); - if (!params->no_thread) + if (!params->common.hist.no_thread) trace_seq_printf(trace->seq, "%9llu ", sum.thread_count); @@ -543,16 +543,16 @@ timerlat_print_stats_all(struct timerlat_params *params, trace_seq_printf(trace->seq, "\n"); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "min: "); - if (!params->no_irq) + if (!params->common.hist.no_irq) format_summary_value(trace->seq, sum.irq_count, sum.min_irq, false); - if (!params->no_thread) + if (!params->common.hist.no_thread) format_summary_value(trace->seq, sum.thread_count, sum.min_thread, @@ -566,16 +566,16 @@ timerlat_print_stats_all(struct timerlat_params *params, trace_seq_printf(trace->seq, "\n"); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "avg: "); - if (!params->no_irq) + if (!params->common.hist.no_irq) format_summary_value(trace->seq, sum.irq_count, sum.sum_irq, true); - if (!params->no_thread) + if (!params->common.hist.no_thread) format_summary_value(trace->seq, sum.thread_count, sum.sum_thread, @@ -589,16 +589,16 @@ timerlat_print_stats_all(struct timerlat_params *params, trace_seq_printf(trace->seq, "\n"); - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "max: "); - if (!params->no_irq) + if (!params->common.hist.no_irq) format_summary_value(trace->seq, sum.irq_count, sum.max_irq, false); - if (!params->no_thread) + if (!params->common.hist.no_thread) format_summary_value(trace->seq, sum.thread_count, sum.max_thread, @@ -631,7 +631,7 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) for (bucket = 0; bucket < data->entries; bucket++) { total = 0; - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "%-6d", bucket * data->bucket_size); @@ -642,13 +642,13 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) continue; - if (!params->no_irq) { + if (!params->common.hist.no_irq) { total += data->hist[cpu].irq[bucket]; trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].irq[bucket]); } - if (!params->no_thread) { + if (!params->common.hist.no_thread) { total += data->hist[cpu].thread[bucket]; trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].thread[bucket]); @@ -662,7 +662,7 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) } - if (total == 0 && !params->with_zeros) { + if (total == 0 && !params->common.hist.with_zeros) { trace_seq_reset(trace->seq); continue; } @@ -672,7 +672,7 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) trace_seq_reset(trace->seq); } - if (!params->no_index) + if (!params->common.hist.no_index) trace_seq_printf(trace->seq, "over: "); for (cpu = 0; cpu < data->nr_cpus; cpu++) { @@ -682,11 +682,11 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) continue; - if (!params->no_irq) + if (!params->common.hist.no_irq) trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].irq[data->entries]); - if (!params->no_thread) + if (!params->common.hist.no_thread) trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].thread[data->entries]); @@ -804,9 +804,9 @@ static struct timerlat_params params->deepest_idle_state = -2; /* display data in microseconds */ - params->output_divisor = 1000; - params->bucket_size = 1; - params->entries = 256; + params->common.output_divisor = 1000; + params->common.hist.bucket_size = 1; + params->common.hist.entries = 256; /* default to BPF mode */ params->mode = TRACING_MODE_BPF; @@ -894,8 +894,9 @@ static struct timerlat_params } break; case 'b': - params->bucket_size = get_llong_from_str(optarg); - if ((params->bucket_size == 0) || (params->bucket_size >= 1000000)) + params->common.hist.bucket_size = get_llong_from_str(optarg); + if (params->common.hist.bucket_size == 0 || + params->common.hist.bucket_size >= 1000000) timerlat_hist_usage("Bucket size needs to be > 0 and <= 1000000\n"); break; case 'D': @@ -919,9 +920,10 @@ static struct timerlat_params params->common.events = tevent; break; case 'E': - params->entries = get_llong_from_str(optarg); - if ((params->entries < 10) || (params->entries > 9999999)) - timerlat_hist_usage("Entries must be > 10 and < 9999999\n"); + params->common.hist.entries = get_llong_from_str(optarg); + if (params->common.hist.entries < 10 || + params->common.hist.entries > 9999999) + timerlat_hist_usage("Entries must be > 10 and < 9999999\n"); break; case 'h': case '?': @@ -942,7 +944,7 @@ static struct timerlat_params params->kernel_workload = 1; break; case 'n': - params->output_divisor = 1; + params->common.output_divisor = 1; break; case 'p': params->timerlat_period_us = get_llong_from_str(optarg); @@ -979,22 +981,22 @@ static struct timerlat_params params->user_data = 1; break; case '0': /* no irq */ - params->no_irq = 1; + params->common.hist.no_irq = 1; break; case '1': /* no thread */ - params->no_thread = 1; + params->common.hist.no_thread = 1; break; case '2': /* no header */ - params->no_header = 1; + params->common.hist.no_header = 1; break; case '3': /* no summary */ - params->no_summary = 1; + params->common.hist.no_summary = 1; break; case '4': /* no index */ - params->no_index = 1; + params->common.hist.no_index = 1; break; case '5': /* with zeros */ - params->with_zeros = 1; + params->common.hist.with_zeros = 1; break; case '6': /* trigger */ if (params->common.events) { @@ -1067,10 +1069,10 @@ static struct timerlat_params exit(EXIT_FAILURE); } - if (params->no_irq && params->no_thread) + if (params->common.hist.no_irq && params->common.hist.no_thread) timerlat_hist_usage("no-irq and no-thread set, there is nothing to do here"); - if (params->no_index && !params->with_zeros) + if (params->common.hist.no_index && !params->common.hist.with_zeros) timerlat_hist_usage("no-index set with with-zeros is not set - it does not make sense"); /* @@ -1127,7 +1129,8 @@ static struct osnoise_tool if (!tool) return NULL; - tool->data = timerlat_alloc_histogram(nr_cpus, params->entries, params->bucket_size); + tool->data = timerlat_alloc_histogram(nr_cpus, params->common.hist.entries, + params->common.hist.bucket_size); if (!tool->data) goto out_err; diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index 9fb60f4dd092..72be083d7d71 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -132,8 +132,8 @@ timerlat_top_update(struct osnoise_tool *tool, int cpu, struct timerlat_top_data *data = tool->data; struct timerlat_top_cpu *cpu_data = &data->cpu_data[cpu]; - if (params->output_divisor) - latency = latency / params->output_divisor; + if (params->common.output_divisor) + latency = latency / params->common.output_divisor; if (!thread) { cpu_data->irq_count++; @@ -258,39 +258,40 @@ static int timerlat_top_bpf_pull_data(struct osnoise_tool *tool) static void timerlat_top_header(struct timerlat_params *params, struct osnoise_tool *top) { struct trace_seq *s = top->trace.seq; + bool pretty = params->common.pretty_output; char duration[26]; get_duration(top->start_time, duration, sizeof(duration)); - if (params->pretty_output) + if (pretty) trace_seq_printf(s, "\033[2;37;40m"); trace_seq_printf(s, " Timer Latency "); if (params->user_data) trace_seq_printf(s, " "); - if (params->pretty_output) + if (pretty) trace_seq_printf(s, "\033[0;0;0m"); trace_seq_printf(s, "\n"); trace_seq_printf(s, "%-6s | IRQ Timer Latency (%s) | Thread Timer Latency (%s)", duration, - params->output_divisor == 1 ? "ns" : "us", - params->output_divisor == 1 ? "ns" : "us"); + params->common.output_divisor == 1 ? "ns" : "us", + params->common.output_divisor == 1 ? "ns" : "us"); if (params->user_data) { trace_seq_printf(s, " | Ret user Timer Latency (%s)", - params->output_divisor == 1 ? "ns" : "us"); + params->common.output_divisor == 1 ? "ns" : "us"); } trace_seq_printf(s, "\n"); - if (params->pretty_output) + if (pretty) trace_seq_printf(s, "\033[2;30;47m"); trace_seq_printf(s, "CPU COUNT | cur min avg max | cur min avg max"); if (params->user_data) trace_seq_printf(s, " | cur min avg max"); - if (params->pretty_output) + if (pretty) trace_seq_printf(s, "\033[0;0;0m"); trace_seq_printf(s, "\n"); } @@ -449,7 +450,7 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *top) if (nr_cpus == -1) nr_cpus = sysconf(_SC_NPROCESSORS_CONF); - if (!params->quiet) + if (!params->common.quiet) clear_terminal(trace->seq); timerlat_top_reset_sum(&summary); @@ -563,7 +564,7 @@ static struct timerlat_params params->deepest_idle_state = -2; /* display data in microseconds */ - params->output_divisor = 1000; + params->common.output_divisor = 1000; /* default to BPF mode */ params->mode = TRACING_MODE_BPF; @@ -696,7 +697,7 @@ static struct timerlat_params params->kernel_workload = true; break; case 'n': - params->output_divisor = 1; + params->common.output_divisor = 1; break; case 'p': params->timerlat_period_us = get_llong_from_str(optarg); @@ -710,7 +711,7 @@ static struct timerlat_params params->common.set_sched = 1; break; case 'q': - params->quiet = 1; + params->common.quiet = 1; break; case 's': params->print_stack = get_llong_from_str(optarg); @@ -842,8 +843,8 @@ timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_params *para if (retval) goto out_err; - if (isatty(STDOUT_FILENO) && !params->quiet) - params->pretty_output = 1; + if (isatty(STDOUT_FILENO) && !params->common.quiet) + params->common.pretty_output = 1; return 0; @@ -942,7 +943,7 @@ timerlat_top_main_loop(struct osnoise_tool *top, return retval; } - if (!params->quiet) + if (!params->common.quiet) timerlat_print_stats(params, top); if (osnoise_trace_is_off(top, record)) { @@ -992,7 +993,8 @@ timerlat_top_bpf_main_loop(struct osnoise_tool *top, /* Pull and display data in a loop */ while (!stop_tracing) { - wait_retval = timerlat_bpf_wait(params->quiet ? -1 : params->common.sleep_time); + wait_retval = timerlat_bpf_wait(params->common.quiet ? -1 : + params->common.sleep_time); retval = timerlat_top_bpf_pull_data(top); if (retval) { @@ -1000,7 +1002,7 @@ timerlat_top_bpf_main_loop(struct osnoise_tool *top, return retval; } - if (!params->quiet) + if (!params->common.quiet) timerlat_print_stats(params, top); if (wait_retval == 1) { From 263d7eacf8d17d66078700ff6b4b540d66f56278 Mon Sep 17 00:00:00 2001 From: Crystal Wood Date: Sat, 6 Sep 2025 21:23:21 -0500 Subject: [PATCH 2185/2711] tools/rtla: Create common_apply_config() Merge the common bits of osnoise_apply_config() and timerlat_apply_config(). Put the result in a new common.c, and move enough things to common.h so that common.c does not need to include osnoise.h. Cc: John Kacur Cc: Costa Shulyupin Link: https://lore.kernel.org/20250907022325.243930-4-crwood@redhat.com Reviewed-by: Tomas Glozar Signed-off-by: Crystal Wood Signed-off-by: Steven Rostedt (Google) --- tools/tracing/rtla/src/Build | 1 + tools/tracing/rtla/src/common.c | 63 ++++++++++++++++++++++++ tools/tracing/rtla/src/common.h | 67 ++++++++++++++++++++++++++ tools/tracing/rtla/src/osnoise.c | 37 ++------------ tools/tracing/rtla/src/osnoise.h | 64 ------------------------ tools/tracing/rtla/src/timerlat.c | 51 ++------------------ tools/tracing/rtla/src/timerlat.h | 1 - tools/tracing/rtla/src/timerlat_hist.c | 4 +- tools/tracing/rtla/src/timerlat_top.c | 4 +- 9 files changed, 142 insertions(+), 150 deletions(-) create mode 100644 tools/tracing/rtla/src/common.c diff --git a/tools/tracing/rtla/src/Build b/tools/tracing/rtla/src/Build index 66631280b75b..329e24a40cf7 100644 --- a/tools/tracing/rtla/src/Build +++ b/tools/tracing/rtla/src/Build @@ -1,6 +1,7 @@ rtla-y += trace.o rtla-y += utils.o rtla-y += actions.o +rtla-y += common.o rtla-y += osnoise.o rtla-y += osnoise_top.o rtla-y += osnoise_hist.o diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c new file mode 100644 index 000000000000..32a6faffc714 --- /dev/null +++ b/tools/tracing/rtla/src/common.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE + +#include +#include "common.h" + +/* + * common_apply_config - apply common configs to the initialized tool + */ +int +common_apply_config(struct osnoise_tool *tool, struct common_params *params) +{ + int retval, i; + + if (!params->sleep_time) + params->sleep_time = 1; + + retval = osnoise_set_cpus(tool->context, params->cpus ? params->cpus : "all"); + if (retval) { + err_msg("Failed to apply CPUs config\n"); + goto out_err; + } + + if (!params->cpus) { + for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) + CPU_SET(i, ¶ms->monitored_cpus); + } + + if (params->hk_cpus) { + retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set), + ¶ms->hk_cpu_set); + if (retval == -1) { + err_msg("Failed to set rtla to the house keeping CPUs\n"); + goto out_err; + } + } else if (params->cpus) { + /* + * Even if the user do not set a house-keeping CPU, try to + * move rtla to a CPU set different to the one where the user + * set the workload to run. + * + * No need to check results as this is an automatic attempt. + */ + auto_house_keeping(¶ms->monitored_cpus); + } + + /* + * Set workload according to type of thread if the kernel supports it. + * On kernels without support, user threads will have already failed + * on missing fd, and kernel threads do not need it. + */ + retval = osnoise_set_workload(tool->context, params->kernel_workload); + if (retval < -1) { + err_msg("Failed to set OSNOISE_WORKLOAD option\n"); + goto out_err; + } + + return 0; + +out_err: + return -1; +} + diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h index 276dfbc7f955..c306ba502688 100644 --- a/tools/tracing/rtla/src/common.h +++ b/tools/tracing/rtla/src/common.h @@ -1,8 +1,67 @@ /* SPDX-License-Identifier: GPL-2.0 */ #pragma once +#include "trace.h" #include "utils.h" +/* + * osnoise_context - read, store, write, restore osnoise configs. + */ +struct osnoise_context { + int flags; + int ref; + + char *curr_cpus; + char *orig_cpus; + + /* 0 as init value */ + unsigned long long orig_runtime_us; + unsigned long long runtime_us; + + /* 0 as init value */ + unsigned long long orig_period_us; + unsigned long long period_us; + + /* 0 as init value */ + long long orig_timerlat_period_us; + long long timerlat_period_us; + + /* 0 as init value */ + long long orig_tracing_thresh; + long long tracing_thresh; + + /* -1 as init value because 0 is disabled */ + long long orig_stop_us; + long long stop_us; + + /* -1 as init value because 0 is disabled */ + long long orig_stop_total_us; + long long stop_total_us; + + /* -1 as init value because 0 is disabled */ + long long orig_print_stack; + long long print_stack; + + /* -1 as init value because 0 is off */ + int orig_opt_irq_disable; + int opt_irq_disable; + + /* -1 as init value because 0 is off */ + int orig_opt_workload; + int opt_workload; +}; + +/* + * osnoise_tool - osnoise based tool definition. + */ +struct osnoise_tool { + struct trace_instance trace; + struct osnoise_context *context; + void *data; + void *params; + time_t start_time; +}; + struct hist_params { char no_irq; char no_thread; @@ -44,4 +103,12 @@ struct common_params { int output_divisor; int pretty_output; int quiet; + int kernel_workload; }; + +int osnoise_set_cpus(struct osnoise_context *context, char *cpus); +void osnoise_restore_cpus(struct osnoise_context *context); + +int osnoise_set_workload(struct osnoise_context *context, bool onoff); + +int common_apply_config(struct osnoise_tool *tool, struct common_params *params); diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c index 06ae7437c2c7..4051b21db69a 100644 --- a/tools/tracing/rtla/src/osnoise.c +++ b/tools/tracing/rtla/src/osnoise.c @@ -1120,21 +1120,14 @@ osnoise_report_missed_events(struct osnoise_tool *tool) } /* - * osnoise_apply_config - apply common configs to the initialized tool + * osnoise_apply_config - apply osnoise configs to the initialized tool */ int osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) { int retval; - if (!params->common.sleep_time) - params->common.sleep_time = 1; - - retval = osnoise_set_cpus(tool->context, params->common.cpus ? params->common.cpus : "all"); - if (retval) { - err_msg("Failed to apply CPUs config\n"); - goto out_err; - } + params->common.kernel_workload = true; if (params->runtime || params->period) { retval = osnoise_set_runtime_period(tool->context, @@ -1169,31 +1162,7 @@ osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) goto out_err; } - if (params->common.hk_cpus) { - retval = sched_setaffinity(getpid(), sizeof(params->common.hk_cpu_set), - ¶ms->common.hk_cpu_set); - if (retval == -1) { - err_msg("Failed to set rtla to the house keeping CPUs\n"); - goto out_err; - } - } else if (params->common.cpus) { - /* - * Even if the user do not set a house-keeping CPU, try to - * move rtla to a CPU set different to the one where the user - * set the workload to run. - * - * No need to check results as this is an automatic attempt. - */ - auto_house_keeping(¶ms->common.monitored_cpus); - } - - retval = osnoise_set_workload(tool->context, true); - if (retval < -1) { - err_msg("Failed to set OSNOISE_WORKLOAD option\n"); - goto out_err; - } - - return 0; + return common_apply_config(tool, ¶ms->common); out_err: return -1; diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h index b64b39de97b5..25baf46a2520 100644 --- a/tools/tracing/rtla/src/osnoise.h +++ b/tools/tracing/rtla/src/osnoise.h @@ -2,7 +2,6 @@ #pragma once #include "common.h" -#include "trace.h" enum osnoise_mode { MODE_OSNOISE = 0, @@ -18,53 +17,6 @@ struct osnoise_params { enum osnoise_mode mode; }; -/* - * osnoise_context - read, store, write, restore osnoise configs. - */ -struct osnoise_context { - int flags; - int ref; - - char *curr_cpus; - char *orig_cpus; - - /* 0 as init value */ - unsigned long long orig_runtime_us; - unsigned long long runtime_us; - - /* 0 as init value */ - unsigned long long orig_period_us; - unsigned long long period_us; - - /* 0 as init value */ - long long orig_timerlat_period_us; - long long timerlat_period_us; - - /* 0 as init value */ - long long orig_tracing_thresh; - long long tracing_thresh; - - /* -1 as init value because 0 is disabled */ - long long orig_stop_us; - long long stop_us; - - /* -1 as init value because 0 is disabled */ - long long orig_stop_total_us; - long long stop_total_us; - - /* -1 as init value because 0 is disabled */ - long long orig_print_stack; - long long print_stack; - - /* -1 as init value because 0 is off */ - int orig_opt_irq_disable; - int opt_irq_disable; - - /* -1 as init value because 0 is off */ - int orig_opt_workload; - int opt_workload; -}; - /* * *_INIT_VALs are also invalid values, they are used to * communicate errors. @@ -76,9 +28,6 @@ struct osnoise_context *osnoise_context_alloc(void); int osnoise_get_context(struct osnoise_context *context); void osnoise_put_context(struct osnoise_context *context); -int osnoise_set_cpus(struct osnoise_context *context, char *cpus); -void osnoise_restore_cpus(struct osnoise_context *context); - int osnoise_set_runtime_period(struct osnoise_context *context, unsigned long long runtime, unsigned long long period); @@ -105,19 +54,6 @@ int osnoise_set_print_stack(struct osnoise_context *context, long long print_stack); int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff); -int osnoise_set_workload(struct osnoise_context *context, bool onoff); - -/* - * osnoise_tool - osnoise based tool definition. - */ -struct osnoise_tool { - struct trace_instance trace; - struct osnoise_context *context; - void *data; - void *params; - time_t start_time; -}; - void osnoise_destroy_tool(struct osnoise_tool *top); struct osnoise_tool *osnoise_init_tool(char *tool_name); struct osnoise_tool *osnoise_init_trace_tool(char *tracer); diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c index 0b2f03e1e612..e4bf58db1dd2 100644 --- a/tools/tracing/rtla/src/timerlat.c +++ b/tools/tracing/rtla/src/timerlat.c @@ -24,21 +24,7 @@ int timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) { - int retval, i; - - if (!params->common.sleep_time) - params->common.sleep_time = 1; - - retval = osnoise_set_cpus(tool->context, params->common.cpus ? params->common.cpus : "all"); - if (retval) { - err_msg("Failed to apply CPUs config\n"); - goto out_err; - } - - if (!params->common.cpus) { - for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) - CPU_SET(i, ¶ms->common.monitored_cpus); - } + int retval; if (params->mode != TRACING_MODE_BPF) { /* @@ -75,29 +61,11 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) goto out_err; } - if (params->common.hk_cpus) { - retval = sched_setaffinity(getpid(), sizeof(params->common.hk_cpu_set), - ¶ms->common.hk_cpu_set); - if (retval == -1) { - err_msg("Failed to set rtla to the house keeping CPUs\n"); - goto out_err; - } - } else if (params->common.cpus) { - /* - * Even if the user do not set a house-keeping CPU, try to - * move rtla to a CPU set different to the one where the user - * set the workload to run. - * - * No need to check results as this is an automatic attempt. - */ - auto_house_keeping(¶ms->common.monitored_cpus); - } - /* * If the user did not specify a type of thread, try user-threads first. * Fall back to kernel threads otherwise. */ - if (!params->kernel_workload && !params->user_data) { + if (!params->common.kernel_workload && !params->user_data) { retval = tracefs_file_exists(NULL, "osnoise/per_cpu/cpu0/timerlat_fd"); if (retval) { debug_msg("User-space interface detected, setting user-threads\n"); @@ -105,22 +73,11 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) params->user_data = 1; } else { debug_msg("User-space interface not detected, setting kernel-threads\n"); - params->kernel_workload = 1; + params->common.kernel_workload = 1; } } - /* - * Set workload according to type of thread if the kernel supports it. - * On kernels without support, user threads will have already failed - * on missing timerlat_fd, and kernel threads do not need it. - */ - retval = osnoise_set_workload(tool->context, params->kernel_workload); - if (retval < -1) { - err_msg("Failed to set OSNOISE_WORKLOAD option\n"); - goto out_err; - } - - return 0; + return common_apply_config(tool, ¶ms->common); out_err: return -1; diff --git a/tools/tracing/rtla/src/timerlat.h b/tools/tracing/rtla/src/timerlat.h index 212ee7971bab..86cd9bac8855 100644 --- a/tools/tracing/rtla/src/timerlat.h +++ b/tools/tracing/rtla/src/timerlat.h @@ -27,7 +27,6 @@ struct timerlat_params { int no_aa; int dump_tasks; int user_workload; - int kernel_workload; int user_data; int deepest_idle_state; int aa_only; diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index 4dc22a749885..d339e2cffae2 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -941,7 +941,7 @@ static struct timerlat_params params->common.stop_us = get_llong_from_str(optarg); break; case 'k': - params->kernel_workload = 1; + params->common.kernel_workload = 1; break; case 'n': params->common.output_divisor = 1; @@ -1081,7 +1081,7 @@ static struct timerlat_params if (!params->common.stop_us && !params->common.stop_total_us) params->no_aa = 1; - if (params->kernel_workload && params->user_workload) + if (params->common.kernel_workload && params->user_workload) timerlat_hist_usage("--kernel-threads and --user-threads are mutually exclusive!"); /* diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index 72be083d7d71..bb42697d2575 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -694,7 +694,7 @@ static struct timerlat_params params->common.stop_us = get_llong_from_str(optarg); break; case 'k': - params->kernel_workload = true; + params->common.kernel_workload = true; break; case 'n': params->common.output_divisor = 1; @@ -816,7 +816,7 @@ static struct timerlat_params if (params->no_aa && params->aa_only) timerlat_top_usage("--no-aa and --aa-only are mutually exclusive!"); - if (params->kernel_workload && params->user_workload) + if (params->common.kernel_workload && params->user_workload) timerlat_top_usage("--kernel-threads and --user-threads are mutually exclusive!"); /* From 2f3172f9dd58cca0f188bc0766b619d24f8116ad Mon Sep 17 00:00:00 2001 From: Crystal Wood Date: Sat, 6 Sep 2025 21:23:22 -0500 Subject: [PATCH 2186/2711] tools/rtla: Consolidate code between osnoise/timerlat and hist/top Currently a lot of code is duplicated between the different rtla tools, making maintenance more difficult, and encouraging divergence such as features that are only implemented for certain tools even though they could be more broadly applicable. Merge the various main() functions into a common run_tool() with an ops struct for tool-specific details. Implement enough support for actions on osnoise to not need to keep the old params->trace_output path. Cc: John Kacur Cc: Costa Shulyupin Link: https://lore.kernel.org/20250907022325.243930-5-crwood@redhat.com Reviewed-by: Tomas Glozar Signed-off-by: Crystal Wood Signed-off-by: Steven Rostedt (Google) --- tools/tracing/rtla/src/common.c | 281 +++++++++++++++ tools/tracing/rtla/src/common.h | 60 +++- tools/tracing/rtla/src/osnoise.c | 66 ++-- tools/tracing/rtla/src/osnoise.h | 14 +- tools/tracing/rtla/src/osnoise_hist.c | 234 +++--------- tools/tracing/rtla/src/osnoise_top.c | 218 ++---------- tools/tracing/rtla/src/timerlat.c | 167 ++++++++- tools/tracing/rtla/src/timerlat.h | 16 +- tools/tracing/rtla/src/timerlat_bpf.c | 4 +- tools/tracing/rtla/src/timerlat_hist.c | 456 +++++------------------- tools/tracing/rtla/src/timerlat_top.c | 473 ++++--------------------- tools/tracing/rtla/src/trace.h | 3 - 12 files changed, 795 insertions(+), 1197 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index 32a6faffc714..2e6e3dac1897 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -1,9 +1,42 @@ // SPDX-License-Identifier: GPL-2.0 #define _GNU_SOURCE +#include +#include +#include #include #include "common.h" +struct trace_instance *trace_inst; +int stop_tracing; + +static void stop_trace(int sig) +{ + if (stop_tracing) { + /* + * Stop requested twice in a row; abort event processing and + * exit immediately + */ + tracefs_iterate_stop(trace_inst->inst); + return; + } + stop_tracing = 1; + if (trace_inst) + trace_instance_stop(trace_inst); +} + +/* + * set_signals - handles the signal to stop the tool + */ +static void set_signals(struct common_params *params) +{ + signal(SIGINT, stop_trace); + if (params->duration) { + signal(SIGALRM, stop_trace); + alarm(params->duration); + } +} + /* * common_apply_config - apply common configs to the initialized tool */ @@ -61,3 +94,251 @@ out_err: return -1; } + +int run_tool(struct tool_ops *ops, int argc, char *argv[]) +{ + struct common_params *params; + enum result return_value = ERROR; + struct osnoise_tool *tool; + bool stopped; + int retval; + + params = ops->parse_args(argc, argv); + if (!params) + exit(1); + + tool = ops->init_tool(params); + if (!tool) { + err_msg("Could not init osnoise tool\n"); + goto out_exit; + } + tool->ops = ops; + tool->params = params; + + /* + * Save trace instance into global variable so that SIGINT can stop + * the timerlat tracer. + * Otherwise, rtla could loop indefinitely when overloaded. + */ + trace_inst = &tool->trace; + + retval = ops->apply_config(tool); + if (retval) { + err_msg("Could not apply config\n"); + goto out_free; + } + + retval = enable_tracer_by_name(trace_inst->inst, ops->tracer); + if (retval) { + err_msg("Failed to enable %s tracer\n", ops->tracer); + goto out_free; + } + + if (params->set_sched) { + retval = set_comm_sched_attr(ops->comm_prefix, ¶ms->sched_param); + if (retval) { + err_msg("Failed to set sched parameters\n"); + goto out_free; + } + } + + if (params->cgroup && !params->user_data) { + retval = set_comm_cgroup(ops->comm_prefix, params->cgroup_name); + if (!retval) { + err_msg("Failed to move threads to cgroup\n"); + goto out_free; + } + } + + + if (params->threshold_actions.present[ACTION_TRACE_OUTPUT] || + params->end_actions.present[ACTION_TRACE_OUTPUT]) { + tool->record = osnoise_init_trace_tool(ops->tracer); + if (!tool->record) { + err_msg("Failed to enable the trace instance\n"); + goto out_free; + } + params->threshold_actions.trace_output_inst = tool->record->trace.inst; + params->end_actions.trace_output_inst = tool->record->trace.inst; + + if (params->events) { + retval = trace_events_enable(&tool->record->trace, params->events); + if (retval) + goto out_trace; + } + + if (params->buffer_size > 0) { + retval = trace_set_buffer_size(&tool->record->trace, params->buffer_size); + if (retval) + goto out_trace; + } + } + + if (params->user_workload) { + pthread_t user_thread; + + /* rtla asked to stop */ + params->user.should_run = 1; + /* all threads left */ + params->user.stopped_running = 0; + + params->user.set = ¶ms->monitored_cpus; + if (params->set_sched) + params->user.sched_param = ¶ms->sched_param; + else + params->user.sched_param = NULL; + + params->user.cgroup_name = params->cgroup_name; + + retval = pthread_create(&user_thread, NULL, timerlat_u_dispatcher, ¶ms->user); + if (retval) + err_msg("Error creating timerlat user-space threads\n"); + } + + retval = ops->enable(tool); + if (retval) + goto out_trace; + + tool->start_time = time(NULL); + set_signals(params); + + retval = ops->main(tool); + if (retval) + goto out_trace; + + if (params->user_workload && !params->user.stopped_running) { + params->user.should_run = 0; + sleep(1); + } + + ops->print_stats(tool); + + actions_perform(¶ms->end_actions); + + return_value = PASSED; + + stopped = osnoise_trace_is_off(tool, tool->record) && !stop_tracing; + if (stopped) { + printf("%s hit stop tracing\n", ops->tracer); + return_value = FAILED; + } + + if (ops->analyze) + ops->analyze(tool, stopped); + +out_trace: + trace_events_destroy(&tool->record->trace, params->events); + params->events = NULL; +out_free: + ops->free(tool); + osnoise_destroy_tool(tool->record); + osnoise_destroy_tool(tool); + actions_destroy(¶ms->threshold_actions); + actions_destroy(¶ms->end_actions); + free(params); +out_exit: + exit(return_value); +} + +int top_main_loop(struct osnoise_tool *tool) +{ + struct common_params *params = tool->params; + struct trace_instance *trace = &tool->trace; + struct osnoise_tool *record = tool->record; + int retval; + + while (!stop_tracing) { + sleep(params->sleep_time); + + if (params->aa_only && !osnoise_trace_is_off(tool, record)) + continue; + + retval = tracefs_iterate_raw_events(trace->tep, + trace->inst, + NULL, + 0, + collect_registered_events, + trace); + if (retval < 0) { + err_msg("Error iterating on events\n"); + return retval; + } + + if (!params->quiet) + tool->ops->print_stats(tool); + + if (osnoise_trace_is_off(tool, record)) { + actions_perform(¶ms->threshold_actions); + + if (!params->threshold_actions.continue_flag) + /* continue flag not set, break */ + return 0; + + /* continue action reached, re-enable tracing */ + if (record) + trace_instance_start(&record->trace); + if (tool->aa) + trace_instance_start(&tool->aa->trace); + trace_instance_start(trace); + } + + /* is there still any user-threads ? */ + if (params->user_workload) { + if (params->user.stopped_running) { + debug_msg("timerlat user space threads stopped!\n"); + break; + } + } + } + + return 0; +} + +int hist_main_loop(struct osnoise_tool *tool) +{ + struct common_params *params = tool->params; + struct trace_instance *trace = &tool->trace; + int retval = 0; + + while (!stop_tracing) { + sleep(params->sleep_time); + + retval = tracefs_iterate_raw_events(trace->tep, + trace->inst, + NULL, + 0, + collect_registered_events, + trace); + if (retval < 0) { + err_msg("Error iterating on events\n"); + break; + } + + if (osnoise_trace_is_off(tool, tool->record)) { + actions_perform(¶ms->threshold_actions); + + if (!params->threshold_actions.continue_flag) { + /* continue flag not set, break */ + break; + + /* continue action reached, re-enable tracing */ + if (tool->record) + trace_instance_start(&tool->record->trace); + if (tool->aa) + trace_instance_start(&tool->aa->trace); + trace_instance_start(&tool->trace); + } + break; + } + + /* is there still any user-threads ? */ + if (params->user_workload) { + if (params->user.stopped_running) { + debug_msg("user-space threads stopped!\n"); + break; + } + } + } + + return retval; +} diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h index c306ba502688..355f113a14a3 100644 --- a/tools/tracing/rtla/src/common.h +++ b/tools/tracing/rtla/src/common.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ #pragma once +#include "actions.h" +#include "timerlat_u.h" #include "trace.h" #include "utils.h" @@ -51,16 +53,8 @@ struct osnoise_context { int opt_workload; }; -/* - * osnoise_tool - osnoise based tool definition. - */ -struct osnoise_tool { - struct trace_instance trace; - struct osnoise_context *context; - void *data; - void *params; - time_t start_time; -}; +extern struct trace_instance *trace_inst; +extern int stop_tracing; struct hist_params { char no_irq; @@ -103,7 +97,46 @@ struct common_params { int output_divisor; int pretty_output; int quiet; + int user_workload; int kernel_workload; + int user_data; + int aa_only; + + struct actions threshold_actions; + struct actions end_actions; + struct timerlat_u_params user; +}; + +struct tool_ops; + +/* + * osnoise_tool - osnoise based tool definition. + * + * Only the "trace" and "context" fields are used for + * the additional trace instances (record and aa). + */ +struct osnoise_tool { + struct tool_ops *ops; + struct trace_instance trace; + struct osnoise_context *context; + void *data; + struct common_params *params; + time_t start_time; + struct osnoise_tool *record; + struct osnoise_tool *aa; +}; + +struct tool_ops { + const char *tracer; + const char *comm_prefix; + struct common_params *(*parse_args)(int argc, char *argv[]); + struct osnoise_tool *(*init_tool)(struct common_params *params); + int (*apply_config)(struct osnoise_tool *tool); + int (*enable)(struct osnoise_tool *tool); + int (*main)(struct osnoise_tool *tool); + void (*print_stats)(struct osnoise_tool *tool); + void (*analyze)(struct osnoise_tool *tool, bool stopped); + void (*free)(struct osnoise_tool *tool); }; int osnoise_set_cpus(struct osnoise_context *context, char *cpus); @@ -111,4 +144,11 @@ void osnoise_restore_cpus(struct osnoise_context *context); int osnoise_set_workload(struct osnoise_context *context, bool onoff); +void osnoise_destroy_tool(struct osnoise_tool *top); +struct osnoise_tool *osnoise_init_tool(char *tool_name); +struct osnoise_tool *osnoise_init_trace_tool(const char *tracer); +bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record); + int common_apply_config(struct osnoise_tool *tool, struct common_params *params); +int top_main_loop(struct osnoise_tool *tool); +int hist_main_loop(struct osnoise_tool *tool); diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c index 4051b21db69a..312c511fa004 100644 --- a/tools/tracing/rtla/src/osnoise.c +++ b/tools/tracing/rtla/src/osnoise.c @@ -906,22 +906,6 @@ static void osnoise_put_workload(struct osnoise_context *context) context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL; } -/* - * enable_osnoise - enable osnoise tracer in the trace_instance - */ -int enable_osnoise(struct trace_instance *trace) -{ - return enable_tracer_by_name(trace->inst, "osnoise"); -} - -/* - * enable_timerlat - enable timerlat tracer in the trace_instance - */ -int enable_timerlat(struct trace_instance *trace) -{ - return enable_tracer_by_name(trace->inst, "timerlat"); -} - enum { FLAG_CONTEXT_NEWLY_CREATED = (1 << 0), FLAG_CONTEXT_DELETED = (1 << 1), @@ -1056,7 +1040,7 @@ out_err: /* * osnoise_init_trace_tool - init a tracer instance to trace osnoise events */ -struct osnoise_tool *osnoise_init_trace_tool(char *tracer) +struct osnoise_tool *osnoise_init_trace_tool(const char *tracer) { struct osnoise_tool *trace; int retval; @@ -1168,6 +1152,44 @@ out_err: return -1; } +int osnoise_enable(struct osnoise_tool *tool) +{ + struct osnoise_params *params = to_osnoise_params(tool->params); + int retval; + + /* + * Start the tracer here, after having set all instances. + * + * Let the trace instance start first for the case of hitting a stop + * tracing while enabling other instances. The trace instance is the + * one with most valuable information. + */ + if (tool->record) + trace_instance_start(&tool->record->trace); + trace_instance_start(&tool->trace); + + if (params->common.warmup > 0) { + debug_msg("Warming up for %d seconds\n", params->common.warmup); + sleep(params->common.warmup); + if (stop_tracing) + return -1; + + /* + * Clean up the buffer. The osnoise workload do not run + * with tracing off to avoid creating a performance penalty + * when not needed. + */ + retval = tracefs_instance_file_write(tool->trace.inst, "trace", ""); + if (retval < 0) { + debug_msg("Error cleaning up the buffer"); + return retval; + } + + } + + return 0; +} + static void osnoise_usage(int err) { int i; @@ -1201,7 +1223,7 @@ int osnoise_main(int argc, char *argv[]) * default cmdline. */ if (argc == 1) { - osnoise_top_main(argc, argv); + run_tool(&osnoise_top_ops, argc, argv); exit(0); } @@ -1209,13 +1231,13 @@ int osnoise_main(int argc, char *argv[]) osnoise_usage(0); } else if (strncmp(argv[1], "-", 1) == 0) { /* the user skipped the tool, call the default one */ - osnoise_top_main(argc, argv); + run_tool(&osnoise_top_ops, argc, argv); exit(0); } else if (strcmp(argv[1], "top") == 0) { - osnoise_top_main(argc-1, &argv[1]); + run_tool(&osnoise_top_ops, argc-1, &argv[1]); exit(0); } else if (strcmp(argv[1], "hist") == 0) { - osnoise_hist_main(argc-1, &argv[1]); + run_tool(&osnoise_hist_ops, argc-1, &argv[1]); exit(0); } @@ -1226,6 +1248,6 @@ usage: int hwnoise_main(int argc, char *argv[]) { - osnoise_top_main(argc, argv); + run_tool(&osnoise_top_ops, argc, argv); exit(0); } diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h index 25baf46a2520..895687030c0b 100644 --- a/tools/tracing/rtla/src/osnoise.h +++ b/tools/tracing/rtla/src/osnoise.h @@ -10,13 +10,14 @@ enum osnoise_mode { struct osnoise_params { struct common_params common; - char *trace_output; unsigned long long runtime; unsigned long long period; long long threshold; enum osnoise_mode mode; }; +#define to_osnoise_params(ptr) container_of(ptr, struct osnoise_params, common) + /* * *_INIT_VALs are also invalid values, they are used to * communicate errors. @@ -54,14 +55,17 @@ int osnoise_set_print_stack(struct osnoise_context *context, long long print_stack); int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff); -void osnoise_destroy_tool(struct osnoise_tool *top); -struct osnoise_tool *osnoise_init_tool(char *tool_name); -struct osnoise_tool *osnoise_init_trace_tool(char *tracer); void osnoise_report_missed_events(struct osnoise_tool *tool); -bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record); int osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params); int osnoise_hist_main(int argc, char *argv[]); int osnoise_top_main(int argc, char **argv); +int osnoise_enable(struct osnoise_tool *tool); int osnoise_main(int argc, char **argv); int hwnoise_main(int argc, char **argv); + +extern struct tool_ops timerlat_top_ops, timerlat_hist_ops; +extern struct tool_ops osnoise_top_ops, osnoise_hist_ops; + +int run_tool(struct tool_ops *ops, int argc, char *argv[]); +int hist_main_loop(struct osnoise_tool *tool); diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index a31ab9b4ab21..2c2cdd467a67 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -54,6 +54,11 @@ osnoise_free_histogram(struct osnoise_hist_data *data) free(data); } +static void osnoise_free_hist_tool(struct osnoise_tool *tool) +{ + osnoise_free_histogram(tool->data); +} + /* * osnoise_alloc_histogram - alloc runtime data */ @@ -95,7 +100,7 @@ cleanup: static void osnoise_hist_update_multiple(struct osnoise_tool *tool, int cpu, unsigned long long duration, int count) { - struct osnoise_params *params = tool->params; + struct osnoise_params *params = to_osnoise_params(tool->params); struct osnoise_hist_data *data = tool->data; unsigned long long total_duration; int entries = data->entries; @@ -137,7 +142,7 @@ static void osnoise_destroy_trace_hist(struct osnoise_tool *tool) */ static int osnoise_init_trace_hist(struct osnoise_tool *tool) { - struct osnoise_params *params = tool->params; + struct osnoise_params *params = to_osnoise_params(tool->params); struct osnoise_hist_data *data = tool->data; int bucket_size; char buff[128]; @@ -222,7 +227,7 @@ static void osnoise_read_trace_hist(struct osnoise_tool *tool) */ static void osnoise_hist_header(struct osnoise_tool *tool) { - struct osnoise_params *params = tool->params; + struct osnoise_params *params = to_osnoise_params(tool->params); struct osnoise_hist_data *data = tool->data; struct trace_seq *s = tool->trace.seq; char duration[26]; @@ -339,8 +344,9 @@ osnoise_print_summary(struct osnoise_params *params, * osnoise_print_stats - print data for all CPUs */ static void -osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *tool) +osnoise_print_stats(struct osnoise_tool *tool) { + struct osnoise_params *params = to_osnoise_params(tool->params); struct osnoise_hist_data *data = tool->data; struct trace_instance *trace = &tool->trace; int has_samples = 0; @@ -477,18 +483,22 @@ static void osnoise_hist_usage(char *usage) /* * osnoise_hist_parse_args - allocs, parse and fill the cmd line parameters */ -static struct osnoise_params +static struct common_params *osnoise_hist_parse_args(int argc, char *argv[]) { struct osnoise_params *params; struct trace_events *tevent; int retval; int c; + char *trace_output = NULL; params = calloc(1, sizeof(*params)); if (!params) exit(1); + actions_init(¶ms->common.threshold_actions); + actions_init(¶ms->common.end_actions); + /* display data in microseconds */ params->common.output_divisor = 1000; params->common.hist.bucket_size = 1; @@ -543,7 +553,7 @@ static struct osnoise_params params->threshold = 1; /* set trace */ - params->trace_output = "osnoise_trace.txt"; + trace_output = "osnoise_trace.txt"; break; case 'b': @@ -634,13 +644,13 @@ static struct osnoise_params case 't': if (optarg) { if (optarg[0] == '=') - params->trace_output = &optarg[1]; + trace_output = &optarg[1]; else - params->trace_output = &optarg[0]; + trace_output = &optarg[0]; } else if (optind < argc && argv[optind][0] != '0') - params->trace_output = argv[optind]; + trace_output = argv[optind]; else - params->trace_output = "osnoise_trace.txt"; + trace_output = "osnoise_trace.txt"; break; case '0': /* no header */ params->common.hist.no_header = 1; @@ -687,6 +697,9 @@ static struct osnoise_params } } + if (trace_output) + actions_add_trace_output(¶ms->common.threshold_actions, trace_output); + if (geteuid()) { err_msg("rtla needs root permission\n"); exit(EXIT_FAILURE); @@ -695,32 +708,23 @@ static struct osnoise_params if (params->common.hist.no_index && !params->common.hist.with_zeros) osnoise_hist_usage("no-index set and with-zeros not set - it does not make sense"); - return params; + return ¶ms->common; } /* * osnoise_hist_apply_config - apply the hist configs to the initialized tool */ static int -osnoise_hist_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) +osnoise_hist_apply_config(struct osnoise_tool *tool) { - int retval; - - retval = osnoise_apply_config(tool, params); - if (retval) - goto out_err; - - return 0; - -out_err: - return -1; + return osnoise_apply_config(tool, to_osnoise_params(tool->params)); } /* * osnoise_init_hist - initialize a osnoise hist tool with parameters */ static struct osnoise_tool -*osnoise_init_hist(struct osnoise_params *params) +*osnoise_init_hist(struct common_params *params) { struct osnoise_tool *tool; int nr_cpus; @@ -731,13 +735,11 @@ static struct osnoise_tool if (!tool) return NULL; - tool->data = osnoise_alloc_histogram(nr_cpus, params->common.hist.entries, - params->common.hist.bucket_size); + tool->data = osnoise_alloc_histogram(nr_cpus, params->hist.entries, + params->hist.bucket_size); if (!tool->data) goto out_err; - tool->params = params; - return tool; out_err: @@ -745,171 +747,35 @@ out_err: return NULL; } -static int stop_tracing; -static void stop_hist(int sig) +static int osnoise_hist_enable(struct osnoise_tool *tool) { - stop_tracing = 1; -} - -/* - * osnoise_hist_set_signals - handles the signal to stop the tool - */ -static void -osnoise_hist_set_signals(struct osnoise_params *params) -{ - signal(SIGINT, stop_hist); - if (params->common.duration) { - signal(SIGALRM, stop_hist); - alarm(params->common.duration); - } -} - -int osnoise_hist_main(int argc, char *argv[]) -{ - struct osnoise_params *params; - struct osnoise_tool *record = NULL; - struct osnoise_tool *tool = NULL; - enum result return_value = ERROR; - struct trace_instance *trace; int retval; - params = osnoise_hist_parse_args(argc, argv); - if (!params) - exit(1); - - tool = osnoise_init_hist(params); - if (!tool) { - err_msg("Could not init osnoise hist\n"); - goto out_exit; - } - - retval = osnoise_hist_apply_config(tool, params); - if (retval) { - err_msg("Could not apply config\n"); - goto out_destroy; - } - - trace = &tool->trace; - - retval = enable_osnoise(trace); - if (retval) { - err_msg("Failed to enable osnoise tracer\n"); - goto out_destroy; - } - retval = osnoise_init_trace_hist(tool); if (retval) - goto out_destroy; + return retval; - if (params->common.set_sched) { - retval = set_comm_sched_attr("osnoise/", ¶ms->common.sched_param); - if (retval) { - err_msg("Failed to set sched parameters\n"); - goto out_free; - } - } + return osnoise_enable(tool); +} - if (params->common.cgroup) { - retval = set_comm_cgroup("timerlat/", params->common.cgroup_name); - if (!retval) { - err_msg("Failed to move threads to cgroup\n"); - goto out_free; - } - } - - if (params->trace_output) { - record = osnoise_init_trace_tool("osnoise"); - if (!record) { - err_msg("Failed to enable the trace instance\n"); - goto out_free; - } - - if (params->common.events) { - retval = trace_events_enable(&record->trace, params->common.events); - if (retval) - goto out_hist; - } - - if (params->common.buffer_size > 0) { - retval = trace_set_buffer_size(&record->trace, params->common.buffer_size); - if (retval) - goto out_hist; - } - } - - /* - * Start the tracer here, after having set all instances. - * - * Let the trace instance start first for the case of hitting a stop - * tracing while enabling other instances. The trace instance is the - * one with most valuable information. - */ - if (params->trace_output) - trace_instance_start(&record->trace); - trace_instance_start(trace); - - if (params->common.warmup > 0) { - debug_msg("Warming up for %d seconds\n", params->common.warmup); - sleep(params->common.warmup); - if (stop_tracing) - goto out_hist; - - /* - * Clean up the buffer. The osnoise workload do not run - * with tracing off to avoid creating a performance penalty - * when not needed. - */ - retval = tracefs_instance_file_write(trace->inst, "trace", ""); - if (retval < 0) { - debug_msg("Error cleaning up the buffer"); - goto out_hist; - } - - } - - tool->start_time = time(NULL); - osnoise_hist_set_signals(params); - - while (!stop_tracing) { - sleep(params->common.sleep_time); - - retval = tracefs_iterate_raw_events(trace->tep, - trace->inst, - NULL, - 0, - collect_registered_events, - trace); - if (retval < 0) { - err_msg("Error iterating on events\n"); - goto out_hist; - } - - if (osnoise_trace_is_off(tool, record)) - break; - } +static int osnoise_hist_main_loop(struct osnoise_tool *tool) +{ + int retval; + retval = hist_main_loop(tool); osnoise_read_trace_hist(tool); - osnoise_print_stats(params, tool); - - return_value = PASSED; - - if (osnoise_trace_is_off(tool, record)) { - printf("rtla osnoise hit stop tracing\n"); - save_trace_to_file(record ? record->trace.inst : NULL, - params->trace_output); - return_value = FAILED; - } - -out_hist: - trace_events_destroy(&record->trace, params->common.events); - params->common.events = NULL; -out_free: - osnoise_free_histogram(tool->data); -out_destroy: - osnoise_destroy_tool(record); - osnoise_destroy_tool(tool); - free(params); -out_exit: - exit(return_value); + return retval; } + +struct tool_ops osnoise_hist_ops = { + .tracer = "osnoise", + .comm_prefix = "osnoise/", + .parse_args = osnoise_hist_parse_args, + .init_tool = osnoise_init_hist, + .apply_config = osnoise_hist_apply_config, + .enable = osnoise_hist_enable, + .main = osnoise_hist_main_loop, + .print_stats = osnoise_print_stats, + .free = osnoise_free_hist_tool, +}; diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 7c68feed300e..5a56c276f9da 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -37,13 +37,17 @@ struct osnoise_top_data { /* * osnoise_free_top - free runtime data */ -static void -osnoise_free_top(struct osnoise_top_data *data) +static void osnoise_free_top(struct osnoise_top_data *data) { free(data->cpu_data); free(data); } +static void osnoise_free_top_tool(struct osnoise_tool *tool) +{ + osnoise_free_top(tool->data); +} + /* * osnoise_alloc_histogram - alloc runtime data */ @@ -123,7 +127,7 @@ osnoise_top_handler(struct trace_seq *s, struct tep_record *record, */ static void osnoise_top_header(struct osnoise_tool *top) { - struct osnoise_params *params = top->params; + struct osnoise_params *params = to_osnoise_params(top->params); struct trace_seq *s = top->trace.seq; bool pretty = params->common.pretty_output; char duration[26]; @@ -184,7 +188,7 @@ static void clear_terminal(struct trace_seq *seq) */ static void osnoise_top_print(struct osnoise_tool *tool, int cpu) { - struct osnoise_params *params = tool->params; + struct osnoise_params *params = to_osnoise_params(tool->params); struct trace_seq *s = tool->trace.seq; struct osnoise_top_cpu *cpu_data; struct osnoise_top_data *data; @@ -224,8 +228,9 @@ static void osnoise_top_print(struct osnoise_tool *tool, int cpu) * osnoise_print_stats - print data for all cpus */ static void -osnoise_print_stats(struct osnoise_params *params, struct osnoise_tool *top) +osnoise_print_stats(struct osnoise_tool *top) { + struct osnoise_params *params = to_osnoise_params(top->params); struct trace_instance *trace = &top->trace; static int nr_cpus = -1; int i; @@ -320,17 +325,21 @@ static void osnoise_top_usage(struct osnoise_params *params, char *usage) /* * osnoise_top_parse_args - allocs, parse and fill the cmd line parameters */ -struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) +struct common_params *osnoise_top_parse_args(int argc, char **argv) { struct osnoise_params *params; struct trace_events *tevent; int retval; int c; + char *trace_output = NULL; params = calloc(1, sizeof(*params)); if (!params) exit(1); + actions_init(¶ms->common.threshold_actions); + actions_init(¶ms->common.end_actions); + if (strcmp(argv[0], "hwnoise") == 0) { params->mode = MODE_HWNOISE; /* @@ -384,7 +393,7 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) params->threshold = 1; /* set trace */ - params->trace_output = "osnoise_trace.txt"; + trace_output = "osnoise_trace.txt"; break; case 'c': @@ -463,13 +472,13 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) case 't': if (optarg) { if (optarg[0] == '=') - params->trace_output = &optarg[1]; + trace_output = &optarg[1]; else - params->trace_output = &optarg[0]; + trace_output = &optarg[0]; } else if (optind < argc && argv[optind][0] != '-') - params->trace_output = argv[optind]; + trace_output = argv[optind]; else - params->trace_output = "osnoise_trace.txt"; + trace_output = "osnoise_trace.txt"; break; case 'T': params->threshold = get_llong_from_str(optarg); @@ -507,20 +516,24 @@ struct osnoise_params *osnoise_top_parse_args(int argc, char **argv) } } + if (trace_output) + actions_add_trace_output(¶ms->common.threshold_actions, trace_output); + if (geteuid()) { err_msg("osnoise needs root permission\n"); exit(EXIT_FAILURE); } - return params; + return ¶ms->common; } /* * osnoise_top_apply_config - apply the top configs to the initialized tool */ static int -osnoise_top_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) +osnoise_top_apply_config(struct osnoise_tool *tool) { + struct osnoise_params *params = to_osnoise_params(tool->params); int retval; retval = osnoise_apply_config(tool, params); @@ -547,7 +560,7 @@ out_err: /* * osnoise_init_top - initialize a osnoise top tool with parameters */ -struct osnoise_tool *osnoise_init_top(struct osnoise_params *params) +struct osnoise_tool *osnoise_init_top(struct common_params *params) { struct osnoise_tool *tool; int nr_cpus; @@ -564,175 +577,20 @@ struct osnoise_tool *osnoise_init_top(struct osnoise_params *params) return NULL; } - tool->params = params; - tep_register_event_handler(tool->trace.tep, -1, "ftrace", "osnoise", osnoise_top_handler, NULL); return tool; } -static int stop_tracing; -static void stop_top(int sig) -{ - stop_tracing = 1; -} - -/* - * osnoise_top_set_signals - handles the signal to stop the tool - */ -static void osnoise_top_set_signals(struct osnoise_params *params) -{ - signal(SIGINT, stop_top); - if (params->common.duration) { - signal(SIGALRM, stop_top); - alarm(params->common.duration); - } -} - -int osnoise_top_main(int argc, char **argv) -{ - struct osnoise_params *params; - struct osnoise_tool *record = NULL; - struct osnoise_tool *tool = NULL; - enum result return_value = ERROR; - struct trace_instance *trace; - int retval; - - params = osnoise_top_parse_args(argc, argv); - if (!params) - exit(1); - - tool = osnoise_init_top(params); - if (!tool) { - err_msg("Could not init osnoise top\n"); - goto out_exit; - } - - retval = osnoise_top_apply_config(tool, params); - if (retval) { - err_msg("Could not apply config\n"); - goto out_free; - } - - trace = &tool->trace; - - retval = enable_osnoise(trace); - if (retval) { - err_msg("Failed to enable osnoise tracer\n"); - goto out_free; - } - - if (params->common.set_sched) { - retval = set_comm_sched_attr("osnoise/", ¶ms->common.sched_param); - if (retval) { - err_msg("Failed to set sched parameters\n"); - goto out_free; - } - } - - if (params->common.cgroup) { - retval = set_comm_cgroup("osnoise/", params->common.cgroup_name); - if (!retval) { - err_msg("Failed to move threads to cgroup\n"); - goto out_free; - } - } - - if (params->trace_output) { - record = osnoise_init_trace_tool("osnoise"); - if (!record) { - err_msg("Failed to enable the trace instance\n"); - goto out_free; - } - - if (params->common.events) { - retval = trace_events_enable(&record->trace, params->common.events); - if (retval) - goto out_top; - } - - if (params->common.buffer_size > 0) { - retval = trace_set_buffer_size(&record->trace, params->common.buffer_size); - if (retval) - goto out_top; - } - } - - /* - * Start the tracer here, after having set all instances. - * - * Let the trace instance start first for the case of hitting a stop - * tracing while enabling other instances. The trace instance is the - * one with most valuable information. - */ - if (params->trace_output) - trace_instance_start(&record->trace); - trace_instance_start(trace); - - if (params->common.warmup > 0) { - debug_msg("Warming up for %d seconds\n", params->common.warmup); - sleep(params->common.warmup); - if (stop_tracing) - goto out_top; - - /* - * Clean up the buffer. The osnoise workload do not run - * with tracing off to avoid creating a performance penalty - * when not needed. - */ - retval = tracefs_instance_file_write(trace->inst, "trace", ""); - if (retval < 0) { - debug_msg("Error cleaning up the buffer"); - goto out_top; - } - - } - - tool->start_time = time(NULL); - osnoise_top_set_signals(params); - - while (!stop_tracing) { - sleep(params->common.sleep_time); - - retval = tracefs_iterate_raw_events(trace->tep, - trace->inst, - NULL, - 0, - collect_registered_events, - trace); - if (retval < 0) { - err_msg("Error iterating on events\n"); - goto out_top; - } - - if (!params->common.quiet) - osnoise_print_stats(params, tool); - - if (osnoise_trace_is_off(tool, record)) - break; - - } - - osnoise_print_stats(params, tool); - - return_value = PASSED; - - if (osnoise_trace_is_off(tool, record)) { - printf("osnoise hit stop tracing\n"); - save_trace_to_file(record ? record->trace.inst : NULL, - params->trace_output); - return_value = FAILED; - } - -out_top: - trace_events_destroy(&record->trace, params->common.events); - params->common.events = NULL; -out_free: - osnoise_free_top(tool->data); - osnoise_destroy_tool(record); - osnoise_destroy_tool(tool); - free(params); -out_exit: - exit(return_value); -} +struct tool_ops osnoise_top_ops = { + .tracer = "osnoise", + .comm_prefix = "osnoise/", + .parse_args = osnoise_top_parse_args, + .init_tool = osnoise_init_top, + .apply_config = osnoise_top_apply_config, + .enable = osnoise_enable, + .main = top_main_loop, + .print_stats = osnoise_print_stats, + .free = osnoise_free_top_tool, +}; diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c index e4bf58db1dd2..b69212874127 100644 --- a/tools/tracing/rtla/src/timerlat.c +++ b/tools/tracing/rtla/src/timerlat.c @@ -15,9 +15,13 @@ #include #include "timerlat.h" +#include "timerlat_aa.h" +#include "timerlat_bpf.h" #define DEFAULT_TIMERLAT_PERIOD 1000 /* 1ms */ +static int dma_latency_fd = -1; + /* * timerlat_apply_config - apply common configs to the initialized tool */ @@ -26,6 +30,24 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) { int retval; + /* + * Try to enable BPF, unless disabled explicitly. + * If BPF enablement fails, fall back to tracefs mode. + */ + if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) { + debug_msg("RTLA_NO_BPF set, disabling BPF\n"); + params->mode = TRACING_MODE_TRACEFS; + } else if (!tep_find_event_by_name(tool->trace.tep, "osnoise", "timerlat_sample")) { + debug_msg("osnoise:timerlat_sample missing, disabling BPF\n"); + params->mode = TRACING_MODE_TRACEFS; + } else { + retval = timerlat_bpf_init(params); + if (retval) { + debug_msg("Could not enable BPF\n"); + params->mode = TRACING_MODE_TRACEFS; + } + } + if (params->mode != TRACING_MODE_BPF) { /* * In tracefs and mixed mode, timerlat tracer handles stopping @@ -65,12 +87,12 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) * If the user did not specify a type of thread, try user-threads first. * Fall back to kernel threads otherwise. */ - if (!params->common.kernel_workload && !params->user_data) { + if (!params->common.kernel_workload && !params->common.user_data) { retval = tracefs_file_exists(NULL, "osnoise/per_cpu/cpu0/timerlat_fd"); if (retval) { debug_msg("User-space interface detected, setting user-threads\n"); - params->user_workload = 1; - params->user_data = 1; + params->common.user_workload = 1; + params->common.user_data = 1; } else { debug_msg("User-space interface not detected, setting kernel-threads\n"); params->common.kernel_workload = 1; @@ -83,6 +105,137 @@ out_err: return -1; } +int timerlat_enable(struct osnoise_tool *tool) +{ + struct timerlat_params *params = to_timerlat_params(tool->params); + int retval, nr_cpus, i; + + if (params->dma_latency >= 0) { + dma_latency_fd = set_cpu_dma_latency(params->dma_latency); + if (dma_latency_fd < 0) { + err_msg("Could not set /dev/cpu_dma_latency.\n"); + return -1; + } + } + + if (params->deepest_idle_state >= -1) { + if (!have_libcpupower_support()) { + err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n"); + return -1; + } + + nr_cpus = sysconf(_SC_NPROCESSORS_CONF); + + for (i = 0; i < nr_cpus; i++) { + if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) + continue; + if (save_cpu_idle_disable_state(i) < 0) { + err_msg("Could not save cpu idle state.\n"); + return -1; + } + if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) { + err_msg("Could not set deepest cpu idle state.\n"); + return -1; + } + } + } + + if (!params->no_aa) { + tool->aa = osnoise_init_tool("timerlat_aa"); + if (!tool->aa) + return -1; + + retval = timerlat_aa_init(tool->aa, params->dump_tasks); + if (retval) { + err_msg("Failed to enable the auto analysis instance\n"); + return retval; + } + + retval = enable_tracer_by_name(tool->aa->trace.inst, "timerlat"); + if (retval) { + err_msg("Failed to enable aa tracer\n"); + return retval; + } + } + + if (params->common.warmup > 0) { + debug_msg("Warming up for %d seconds\n", params->common.warmup); + sleep(params->common.warmup); + if (stop_tracing) + return -1; + } + + /* + * Start the tracers here, after having set all instances. + * + * Let the trace instance start first for the case of hitting a stop + * tracing while enabling other instances. The trace instance is the + * one with most valuable information. + */ + if (tool->record) + trace_instance_start(&tool->record->trace); + if (!params->no_aa) + trace_instance_start(&tool->aa->trace); + if (params->mode == TRACING_MODE_TRACEFS) { + trace_instance_start(&tool->trace); + } else { + retval = timerlat_bpf_attach(); + if (retval) { + err_msg("Error attaching BPF program\n"); + return retval; + } + } + + return 0; +} + +void timerlat_analyze(struct osnoise_tool *tool, bool stopped) +{ + struct timerlat_params *params = to_timerlat_params(tool->params); + + if (stopped) { + if (!params->no_aa) + timerlat_auto_analysis(params->common.stop_us, + params->common.stop_total_us); + } else if (params->common.aa_only) { + char *max_lat; + + /* + * If the trace did not stop with --aa-only, at least print + * the max known latency. + */ + max_lat = tracefs_instance_file_read(trace_inst->inst, "tracing_max_latency", NULL); + if (max_lat) { + printf(" Max latency was %s\n", max_lat); + free(max_lat); + } + } +} + +void timerlat_free(struct osnoise_tool *tool) +{ + struct timerlat_params *params = to_timerlat_params(tool->params); + int nr_cpus, i; + + timerlat_aa_destroy(); + if (dma_latency_fd >= 0) + close(dma_latency_fd); + if (params->deepest_idle_state >= -1) { + for (i = 0; i < nr_cpus; i++) { + if (params->common.cpus && + !CPU_ISSET(i, ¶ms->common.monitored_cpus)) + continue; + restore_cpu_idle_disable_state(i); + } + } + + osnoise_destroy_tool(tool->aa); + + if (params->mode != TRACING_MODE_TRACEFS) + timerlat_bpf_destroy(); + free_cpu_idle_disable_states(); +} + static void timerlat_usage(int err) { int i; @@ -116,7 +269,7 @@ int timerlat_main(int argc, char *argv[]) * default cmdline. */ if (argc == 1) { - timerlat_top_main(argc, argv); + run_tool(&timerlat_top_ops, argc, argv); exit(0); } @@ -124,13 +277,13 @@ int timerlat_main(int argc, char *argv[]) timerlat_usage(0); } else if (strncmp(argv[1], "-", 1) == 0) { /* the user skipped the tool, call the default one */ - timerlat_top_main(argc, argv); + run_tool(&timerlat_top_ops, argc, argv); exit(0); } else if (strcmp(argv[1], "top") == 0) { - timerlat_top_main(argc-1, &argv[1]); + run_tool(&timerlat_top_ops, argc-1, &argv[1]); exit(0); } else if (strcmp(argv[1], "hist") == 0) { - timerlat_hist_main(argc-1, &argv[1]); + run_tool(&timerlat_hist_ops, argc-1, &argv[1]); exit(0); } diff --git a/tools/tracing/rtla/src/timerlat.h b/tools/tracing/rtla/src/timerlat.h index 86cd9bac8855..fd6065f48bb7 100644 --- a/tools/tracing/rtla/src/timerlat.h +++ b/tools/tracing/rtla/src/timerlat.h @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include "actions.h" #include "osnoise.h" /* @@ -26,18 +25,15 @@ struct timerlat_params { int dma_latency; int no_aa; int dump_tasks; - int user_workload; - int user_data; int deepest_idle_state; - int aa_only; enum timerlat_tracing_mode mode; - - struct actions threshold_actions; - struct actions end_actions; }; -int timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params); +#define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, common) -int timerlat_hist_main(int argc, char *argv[]); -int timerlat_top_main(int argc, char *argv[]); +int timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params); int timerlat_main(int argc, char *argv[]); +int timerlat_enable(struct osnoise_tool *tool); +void timerlat_analyze(struct osnoise_tool *tool, bool stopped); +void timerlat_free(struct osnoise_tool *tool); + diff --git a/tools/tracing/rtla/src/timerlat_bpf.c b/tools/tracing/rtla/src/timerlat_bpf.c index 03be2606f54a..e97d16646bcd 100644 --- a/tools/tracing/rtla/src/timerlat_bpf.c +++ b/tools/tracing/rtla/src/timerlat_bpf.c @@ -25,7 +25,7 @@ int timerlat_bpf_init(struct timerlat_params *params) bpf->rodata->entries = params->common.hist.entries; bpf->rodata->irq_threshold = params->common.stop_us; bpf->rodata->thread_threshold = params->common.stop_total_us; - bpf->rodata->aa_only = params->aa_only; + bpf->rodata->aa_only = params->common.aa_only; if (params->common.hist.entries != 0) { /* Pass histogram options */ @@ -42,7 +42,7 @@ int timerlat_bpf_init(struct timerlat_params *params) bpf_map__set_autocreate(bpf->maps.hist_user, false); } - if (params->aa_only) { + if (params->common.aa_only) { /* Auto-analysis only, disable summary */ bpf_map__set_autocreate(bpf->maps.summary_irq, false); bpf_map__set_autocreate(bpf->maps.summary_thread, false); diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index d339e2cffae2..a9154f83f1a9 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -16,7 +16,6 @@ #include "timerlat.h" #include "timerlat_aa.h" -#include "timerlat_u.h" #include "timerlat_bpf.h" struct timerlat_hist_cpu { @@ -72,8 +71,12 @@ timerlat_free_histogram(struct timerlat_hist_data *data) /* one set of histograms per CPU */ if (data->hist) free(data->hist); +} - free(data); +static void timerlat_free_histogram_tool(struct osnoise_tool *tool) +{ + timerlat_free_histogram(tool->data); + timerlat_free(tool); } /* @@ -135,7 +138,7 @@ timerlat_hist_update(struct osnoise_tool *tool, int cpu, unsigned long long context, unsigned long long latency) { - struct timerlat_params *params = tool->params; + struct timerlat_params *params = to_timerlat_params(tool->params); struct timerlat_hist_data *data = tool->data; int entries = data->entries; int bucket; @@ -282,7 +285,7 @@ static int timerlat_hist_bpf_pull_data(struct osnoise_tool *tool) */ static void timerlat_hist_header(struct osnoise_tool *tool) { - struct timerlat_params *params = tool->params; + struct timerlat_params *params = to_timerlat_params(tool->params); struct timerlat_hist_data *data = tool->data; struct trace_seq *s = tool->trace.seq; char duration[26]; @@ -315,7 +318,7 @@ static void timerlat_hist_header(struct osnoise_tool *tool) if (!params->common.hist.no_thread) trace_seq_printf(s, " Thr-%03d", cpu); - if (params->user_data) + if (params->common.user_data) trace_seq_printf(s, " Usr-%03d", cpu); } trace_seq_printf(s, "\n"); @@ -371,7 +374,7 @@ timerlat_print_summary(struct timerlat_params *params, trace_seq_printf(trace->seq, "%9llu ", data->hist[cpu].thread_count); - if (params->user_data) + if (params->common.user_data) trace_seq_printf(trace->seq, "%9llu ", data->hist[cpu].user_count); } @@ -399,7 +402,7 @@ timerlat_print_summary(struct timerlat_params *params, data->hist[cpu].min_thread, false); - if (params->user_data) + if (params->common.user_data) format_summary_value(trace->seq, data->hist[cpu].user_count, data->hist[cpu].min_user, @@ -429,7 +432,7 @@ timerlat_print_summary(struct timerlat_params *params, data->hist[cpu].sum_thread, true); - if (params->user_data) + if (params->common.user_data) format_summary_value(trace->seq, data->hist[cpu].user_count, data->hist[cpu].sum_user, @@ -459,7 +462,7 @@ timerlat_print_summary(struct timerlat_params *params, data->hist[cpu].max_thread, false); - if (params->user_data) + if (params->common.user_data) format_summary_value(trace->seq, data->hist[cpu].user_count, data->hist[cpu].max_user, @@ -521,7 +524,7 @@ timerlat_print_stats_all(struct timerlat_params *params, if (!params->common.hist.no_thread) trace_seq_printf(trace->seq, " Thr"); - if (params->user_data) + if (params->common.user_data) trace_seq_printf(trace->seq, " Usr"); trace_seq_printf(trace->seq, "\n"); @@ -537,7 +540,7 @@ timerlat_print_stats_all(struct timerlat_params *params, trace_seq_printf(trace->seq, "%9llu ", sum.thread_count); - if (params->user_data) + if (params->common.user_data) trace_seq_printf(trace->seq, "%9llu ", sum.user_count); @@ -558,7 +561,7 @@ timerlat_print_stats_all(struct timerlat_params *params, sum.min_thread, false); - if (params->user_data) + if (params->common.user_data) format_summary_value(trace->seq, sum.user_count, sum.min_user, @@ -581,7 +584,7 @@ timerlat_print_stats_all(struct timerlat_params *params, sum.sum_thread, true); - if (params->user_data) + if (params->common.user_data) format_summary_value(trace->seq, sum.user_count, sum.sum_user, @@ -604,7 +607,7 @@ timerlat_print_stats_all(struct timerlat_params *params, sum.max_thread, false); - if (params->user_data) + if (params->common.user_data) format_summary_value(trace->seq, sum.user_count, sum.max_user, @@ -619,8 +622,9 @@ timerlat_print_stats_all(struct timerlat_params *params, * timerlat_print_stats - print data for each CPUs */ static void -timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) +timerlat_print_stats(struct osnoise_tool *tool) { + struct timerlat_params *params = to_timerlat_params(tool->params); struct timerlat_hist_data *data = tool->data; struct trace_instance *trace = &tool->trace; int bucket, cpu; @@ -654,7 +658,7 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) data->hist[cpu].thread[bucket]); } - if (params->user_data) { + if (params->common.user_data) { total += data->hist[cpu].user[bucket]; trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].user[bucket]); @@ -690,7 +694,7 @@ timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *tool) trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].thread[data->entries]); - if (params->user_data) + if (params->common.user_data) trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].user[data->entries]); } @@ -780,7 +784,7 @@ static void timerlat_hist_usage(char *usage) /* * timerlat_hist_parse_args - allocs, parse and fill the cmd line parameters */ -static struct timerlat_params +static struct common_params *timerlat_hist_parse_args(int argc, char *argv[]) { struct timerlat_params *params; @@ -794,8 +798,8 @@ static struct timerlat_params if (!params) exit(1); - actions_init(¶ms->threshold_actions); - actions_init(¶ms->end_actions); + actions_init(¶ms->common.threshold_actions); + actions_init(¶ms->common.end_actions); /* disabled by default */ params->dma_latency = -1; @@ -975,10 +979,10 @@ static struct timerlat_params trace_output = "timerlat_trace.txt"; break; case 'u': - params->user_workload = 1; + params->common.user_workload = 1; /* fallback: -u implies in -U */ case 'U': - params->user_data = 1; + params->common.user_data = 1; break; case '0': /* no irq */ params->common.hist.no_irq = 1; @@ -1043,14 +1047,14 @@ static struct timerlat_params params->deepest_idle_state = get_llong_from_str(optarg); break; case '\5': - retval = actions_parse(¶ms->threshold_actions, optarg); + retval = actions_parse(¶ms->common.threshold_actions, optarg); if (retval) { err_msg("Invalid action %s\n", optarg); exit(EXIT_FAILURE); } break; case '\6': - retval = actions_parse(¶ms->end_actions, optarg); + retval = actions_parse(¶ms->common.end_actions, optarg); if (retval) { err_msg("Invalid action %s\n", optarg); exit(EXIT_FAILURE); @@ -1062,7 +1066,7 @@ static struct timerlat_params } if (trace_output) - actions_add_trace_output(¶ms->threshold_actions, trace_output); + actions_add_trace_output(¶ms->common.threshold_actions, trace_output); if (geteuid()) { err_msg("rtla needs root permission\n"); @@ -1081,7 +1085,7 @@ static struct timerlat_params if (!params->common.stop_us && !params->common.stop_total_us) params->no_aa = 1; - if (params->common.kernel_workload && params->user_workload) + if (params->common.kernel_workload && params->common.user_workload) timerlat_hist_usage("--kernel-threads and --user-threads are mutually exclusive!"); /* @@ -1089,19 +1093,21 @@ static struct timerlat_params * mixed mode */ if (params->mode == TRACING_MODE_BPF && - (params->threshold_actions.present[ACTION_TRACE_OUTPUT] || - params->end_actions.present[ACTION_TRACE_OUTPUT] || !params->no_aa)) + (params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] || + params->common.end_actions.present[ACTION_TRACE_OUTPUT] || + !params->no_aa)) params->mode = TRACING_MODE_MIXED; - return params; + return ¶ms->common; } /* * timerlat_hist_apply_config - apply the hist configs to the initialized tool */ static int -timerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) +timerlat_hist_apply_config(struct osnoise_tool *tool) { + struct timerlat_params *params = to_timerlat_params(tool->params); int retval; retval = timerlat_apply_config(tool, params); @@ -1118,7 +1124,7 @@ out_err: * timerlat_init_hist - initialize a timerlat hist tool with parameters */ static struct osnoise_tool -*timerlat_init_hist(struct timerlat_params *params) +*timerlat_init_hist(struct common_params *params) { struct osnoise_tool *tool; int nr_cpus; @@ -1129,13 +1135,11 @@ static struct osnoise_tool if (!tool) return NULL; - tool->data = timerlat_alloc_histogram(nr_cpus, params->common.hist.entries, - params->common.hist.bucket_size); + tool->data = timerlat_alloc_histogram(nr_cpus, params->hist.entries, + params->hist.bucket_size); if (!tool->data) goto out_err; - tool->params = params; - tep_register_event_handler(tool->trace.tep, -1, "ftrace", "timerlat", timerlat_hist_handler, tool); @@ -1146,349 +1150,61 @@ out_err: return NULL; } -static int stop_tracing; -static struct trace_instance *hist_inst = NULL; -static void stop_hist(int sig) +static int timerlat_hist_bpf_main_loop(struct osnoise_tool *tool) { - if (stop_tracing) { - /* - * Stop requested twice in a row; abort event processing and - * exit immediately - */ - tracefs_iterate_stop(hist_inst->inst); - return; - } - stop_tracing = 1; - if (hist_inst) - trace_instance_stop(hist_inst); -} - -/* - * timerlat_hist_set_signals - handles the signal to stop the tool - */ -static void -timerlat_hist_set_signals(struct timerlat_params *params) -{ - signal(SIGINT, stop_hist); - if (params->common.duration) { - signal(SIGALRM, stop_hist); - alarm(params->common.duration); - } -} - -int timerlat_hist_main(int argc, char *argv[]) -{ - struct timerlat_params *params; - struct osnoise_tool *record = NULL; - struct timerlat_u_params params_u; - enum result return_value = ERROR; - struct osnoise_tool *tool = NULL; - struct osnoise_tool *aa = NULL; - struct trace_instance *trace; - int dma_latency_fd = -1; - pthread_t timerlat_u; + struct timerlat_params *params = to_timerlat_params(tool->params); int retval; - int nr_cpus, i; - params = timerlat_hist_parse_args(argc, argv); - if (!params) - exit(1); + while (!stop_tracing) { + timerlat_bpf_wait(-1); - tool = timerlat_init_hist(params); - if (!tool) { - err_msg("Could not init osnoise hist\n"); - goto out_exit; - } + if (!stop_tracing) { + /* Threshold overflow, perform actions on threshold */ + actions_perform(¶ms->common.threshold_actions); - trace = &tool->trace; - /* - * Save trace instance into global variable so that SIGINT can stop - * the timerlat tracer. - * Otherwise, rtla could loop indefinitely when overloaded. - */ - hist_inst = trace; + if (!params->common.threshold_actions.continue_flag) + /* continue flag not set, break */ + break; - /* - * Try to enable BPF, unless disabled explicitly. - * If BPF enablement fails, fall back to tracefs mode. - */ - if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) { - debug_msg("RTLA_NO_BPF set, disabling BPF\n"); - params->mode = TRACING_MODE_TRACEFS; - } else if (!tep_find_event_by_name(trace->tep, "osnoise", "timerlat_sample")) { - debug_msg("osnoise:timerlat_sample missing, disabling BPF\n"); - params->mode = TRACING_MODE_TRACEFS; - } else { - retval = timerlat_bpf_init(params); - if (retval) { - debug_msg("Could not enable BPF\n"); - params->mode = TRACING_MODE_TRACEFS; + /* continue action reached, re-enable tracing */ + if (tool->record) + trace_instance_start(&tool->record->trace); + if (tool->aa) + trace_instance_start(&tool->aa->trace); + timerlat_bpf_restart_tracing(); } } + timerlat_bpf_detach(); - retval = timerlat_hist_apply_config(tool, params); - if (retval) { - err_msg("Could not apply config\n"); - goto out_free; - } + retval = timerlat_hist_bpf_pull_data(tool); + if (retval) + err_msg("Error pulling BPF data\n"); - retval = enable_timerlat(trace); - if (retval) { - err_msg("Failed to enable timerlat tracer\n"); - goto out_free; - } - - if (params->common.set_sched) { - retval = set_comm_sched_attr("timerlat/", ¶ms->common.sched_param); - if (retval) { - err_msg("Failed to set sched parameters\n"); - goto out_free; - } - } - - if (params->common.cgroup && !params->user_workload) { - retval = set_comm_cgroup("timerlat/", params->common.cgroup_name); - if (!retval) { - err_msg("Failed to move threads to cgroup\n"); - goto out_free; - } - } - - if (params->dma_latency >= 0) { - dma_latency_fd = set_cpu_dma_latency(params->dma_latency); - if (dma_latency_fd < 0) { - err_msg("Could not set /dev/cpu_dma_latency.\n"); - goto out_free; - } - } - - if (params->deepest_idle_state >= -1) { - if (!have_libcpupower_support()) { - err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n"); - goto out_free; - } - - nr_cpus = sysconf(_SC_NPROCESSORS_CONF); - - for (i = 0; i < nr_cpus; i++) { - if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) - continue; - if (save_cpu_idle_disable_state(i) < 0) { - err_msg("Could not save cpu idle state.\n"); - goto out_free; - } - if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) { - err_msg("Could not set deepest cpu idle state.\n"); - goto out_free; - } - } - } - - if (params->threshold_actions.present[ACTION_TRACE_OUTPUT] || - params->end_actions.present[ACTION_TRACE_OUTPUT]) { - record = osnoise_init_trace_tool("timerlat"); - if (!record) { - err_msg("Failed to enable the trace instance\n"); - goto out_free; - } - params->threshold_actions.trace_output_inst = record->trace.inst; - params->end_actions.trace_output_inst = record->trace.inst; - - if (params->common.events) { - retval = trace_events_enable(&record->trace, params->common.events); - if (retval) - goto out_hist; - } - - if (params->common.buffer_size > 0) { - retval = trace_set_buffer_size(&record->trace, params->common.buffer_size); - if (retval) - goto out_hist; - } - } - - if (!params->no_aa) { - aa = osnoise_init_tool("timerlat_aa"); - if (!aa) - goto out_hist; - - retval = timerlat_aa_init(aa, params->dump_tasks); - if (retval) { - err_msg("Failed to enable the auto analysis instance\n"); - goto out_hist; - } - - retval = enable_timerlat(&aa->trace); - if (retval) { - err_msg("Failed to enable timerlat tracer\n"); - goto out_hist; - } - } - - if (params->user_workload) { - /* rtla asked to stop */ - params_u.should_run = 1; - /* all threads left */ - params_u.stopped_running = 0; - - params_u.set = ¶ms->common.monitored_cpus; - if (params->common.set_sched) - params_u.sched_param = ¶ms->common.sched_param; - else - params_u.sched_param = NULL; - - params_u.cgroup_name = params->common.cgroup_name; - - retval = pthread_create(&timerlat_u, NULL, timerlat_u_dispatcher, ¶ms_u); - if (retval) - err_msg("Error creating timerlat user-space threads\n"); - } - - if (params->common.warmup > 0) { - debug_msg("Warming up for %d seconds\n", params->common.warmup); - sleep(params->common.warmup); - if (stop_tracing) - goto out_hist; - } - - /* - * Start the tracers here, after having set all instances. - * - * Let the trace instance start first for the case of hitting a stop - * tracing while enabling other instances. The trace instance is the - * one with most valuable information. - */ - if (record) - trace_instance_start(&record->trace); - if (!params->no_aa) - trace_instance_start(&aa->trace); - if (params->mode == TRACING_MODE_TRACEFS) { - trace_instance_start(trace); - } else { - retval = timerlat_bpf_attach(); - if (retval) { - err_msg("Error attaching BPF program\n"); - goto out_hist; - } - } - - tool->start_time = time(NULL); - timerlat_hist_set_signals(params); - - if (params->mode == TRACING_MODE_TRACEFS) { - while (!stop_tracing) { - sleep(params->common.sleep_time); - - retval = tracefs_iterate_raw_events(trace->tep, - trace->inst, - NULL, - 0, - collect_registered_events, - trace); - if (retval < 0) { - err_msg("Error iterating on events\n"); - goto out_hist; - } - - if (osnoise_trace_is_off(tool, record)) { - actions_perform(¶ms->threshold_actions); - - if (!params->threshold_actions.continue_flag) - /* continue flag not set, break */ - break; - - /* continue action reached, re-enable tracing */ - if (record) - trace_instance_start(&record->trace); - if (!params->no_aa) - trace_instance_start(&aa->trace); - trace_instance_start(trace); - } - - /* is there still any user-threads ? */ - if (params->user_workload) { - if (params_u.stopped_running) { - debug_msg("timerlat user-space threads stopped!\n"); - break; - } - } - } - } else { - while (!stop_tracing) { - timerlat_bpf_wait(-1); - - if (!stop_tracing) { - /* Threshold overflow, perform actions on threshold */ - actions_perform(¶ms->threshold_actions); - - if (!params->threshold_actions.continue_flag) - /* continue flag not set, break */ - break; - - /* continue action reached, re-enable tracing */ - if (record) - trace_instance_start(&record->trace); - if (!params->no_aa) - trace_instance_start(&aa->trace); - timerlat_bpf_restart_tracing(); - } - } - } - - if (params->mode != TRACING_MODE_TRACEFS) { - timerlat_bpf_detach(); - retval = timerlat_hist_bpf_pull_data(tool); - if (retval) { - err_msg("Error pulling BPF data\n"); - goto out_hist; - } - } - - if (params->user_workload && !params_u.stopped_running) { - params_u.should_run = 0; - sleep(1); - } - - timerlat_print_stats(params, tool); - - actions_perform(¶ms->end_actions); - - return_value = PASSED; - - if (osnoise_trace_is_off(tool, record) && !stop_tracing) { - printf("rtla timerlat hit stop tracing\n"); - - if (!params->no_aa) - timerlat_auto_analysis(params->common.stop_us, - params->common.stop_total_us); - - return_value = FAILED; - } - -out_hist: - timerlat_aa_destroy(); - if (dma_latency_fd >= 0) - close(dma_latency_fd); - if (params->deepest_idle_state >= -1) { - for (i = 0; i < nr_cpus; i++) { - if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) - continue; - restore_cpu_idle_disable_state(i); - } - } - trace_events_destroy(&record->trace, params->common.events); - params->common.events = NULL; -out_free: - timerlat_free_histogram(tool->data); - osnoise_destroy_tool(aa); - osnoise_destroy_tool(record); - osnoise_destroy_tool(tool); - actions_destroy(¶ms->threshold_actions); - actions_destroy(¶ms->end_actions); - if (params->mode != TRACING_MODE_TRACEFS) - timerlat_bpf_destroy(); - free(params); - free_cpu_idle_disable_states(); -out_exit: - exit(return_value); + return retval; } + +static int timerlat_hist_main(struct osnoise_tool *tool) +{ + struct timerlat_params *params = to_timerlat_params(tool->params); + int retval; + + if (params->mode == TRACING_MODE_TRACEFS) + retval = hist_main_loop(tool); + else + retval = timerlat_hist_bpf_main_loop(tool); + + return retval; +} + +struct tool_ops timerlat_hist_ops = { + .tracer = "timerlat", + .comm_prefix = "timerlat/", + .parse_args = timerlat_hist_parse_args, + .init_tool = timerlat_init_hist, + .apply_config = timerlat_hist_apply_config, + .enable = timerlat_enable, + .main = timerlat_hist_main, + .print_stats = timerlat_print_stats, + .analyze = timerlat_analyze, + .free = timerlat_free_histogram_tool, +}; diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index bb42697d2575..4f1ce72d6a05 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -17,7 +17,6 @@ #include "timerlat.h" #include "timerlat_aa.h" -#include "timerlat_u.h" #include "timerlat_bpf.h" struct timerlat_top_cpu { @@ -49,13 +48,18 @@ struct timerlat_top_data { /* * timerlat_free_top - free runtime data */ -static void -timerlat_free_top(struct timerlat_top_data *data) +static void timerlat_free_top(struct timerlat_top_data *data) { free(data->cpu_data); free(data); } +static void timerlat_free_top_tool(struct osnoise_tool *tool) +{ + timerlat_free_top(tool->data); + timerlat_free(tool); +} + /* * timerlat_alloc_histogram - alloc runtime data */ @@ -128,7 +132,7 @@ timerlat_top_update(struct osnoise_tool *tool, int cpu, unsigned long long thread, unsigned long long latency) { - struct timerlat_params *params = tool->params; + struct timerlat_params *params = to_timerlat_params(tool->params); struct timerlat_top_data *data = tool->data; struct timerlat_top_cpu *cpu_data = &data->cpu_data[cpu]; @@ -164,15 +168,13 @@ timerlat_top_handler(struct trace_seq *s, struct tep_record *record, struct tep_event *event, void *context) { struct trace_instance *trace = context; - struct timerlat_params *params; unsigned long long latency, thread; struct osnoise_tool *top; int cpu = record->cpu; top = container_of(trace, struct osnoise_tool, trace); - params = top->params; - if (!params->aa_only) { + if (!top->params->aa_only) { tep_get_field_val(s, event, "context", record, &thread, 1); tep_get_field_val(s, event, "timer_latency", record, &latency, 1); @@ -267,7 +269,7 @@ static void timerlat_top_header(struct timerlat_params *params, struct osnoise_t trace_seq_printf(s, "\033[2;37;40m"); trace_seq_printf(s, " Timer Latency "); - if (params->user_data) + if (params->common.user_data) trace_seq_printf(s, " "); if (pretty) @@ -278,7 +280,7 @@ static void timerlat_top_header(struct timerlat_params *params, struct osnoise_t params->common.output_divisor == 1 ? "ns" : "us", params->common.output_divisor == 1 ? "ns" : "us"); - if (params->user_data) { + if (params->common.user_data) { trace_seq_printf(s, " | Ret user Timer Latency (%s)", params->common.output_divisor == 1 ? "ns" : "us"); } @@ -288,7 +290,7 @@ static void timerlat_top_header(struct timerlat_params *params, struct osnoise_t trace_seq_printf(s, "\033[2;30;47m"); trace_seq_printf(s, "CPU COUNT | cur min avg max | cur min avg max"); - if (params->user_data) + if (params->common.user_data) trace_seq_printf(s, " | cur min avg max"); if (pretty) @@ -303,8 +305,7 @@ static const char *no_value = " -"; */ static void timerlat_top_print(struct osnoise_tool *top, int cpu) { - - struct timerlat_params *params = top->params; + struct timerlat_params *params = to_timerlat_params(top->params); struct timerlat_top_data *data = top->data; struct timerlat_top_cpu *cpu_data = &data->cpu_data[cpu]; struct trace_seq *s = top->trace.seq; @@ -339,7 +340,7 @@ static void timerlat_top_print(struct osnoise_tool *top, int cpu) trace_seq_printf(s, "%9llu", cpu_data->max_thread); } - if (!params->user_data) { + if (!params->common.user_data) { trace_seq_printf(s, "\n"); return; } @@ -364,7 +365,7 @@ static void timerlat_top_print_sum(struct osnoise_tool *top, struct timerlat_top_cpu *summary) { const char *split = "----------------------------------------"; - struct timerlat_params *params = top->params; + struct timerlat_params *params = to_timerlat_params(top->params); unsigned long long count = summary->irq_count; struct trace_seq *s = top->trace.seq; int e = 0; @@ -381,7 +382,7 @@ timerlat_top_print_sum(struct osnoise_tool *top, struct timerlat_top_cpu *summar } trace_seq_printf(s, "%.*s|%.*s|%.*s", 15, split, 40, split, 39, split); - if (params->user_data) + if (params->common.user_data) trace_seq_printf(s, "-|%.*s", 39, split); trace_seq_printf(s, "\n"); @@ -406,7 +407,7 @@ timerlat_top_print_sum(struct osnoise_tool *top, struct timerlat_top_cpu *summar trace_seq_printf(s, "%9llu", summary->max_thread); } - if (!params->user_data) { + if (!params->common.user_data) { trace_seq_printf(s, "\n"); return; } @@ -437,14 +438,15 @@ static void clear_terminal(struct trace_seq *seq) * timerlat_print_stats - print data for all cpus */ static void -timerlat_print_stats(struct timerlat_params *params, struct osnoise_tool *top) +timerlat_print_stats(struct osnoise_tool *top) { + struct timerlat_params *params = to_timerlat_params(top->params); struct trace_instance *trace = &top->trace; struct timerlat_top_cpu summary; static int nr_cpus = -1; int i; - if (params->aa_only) + if (params->common.aa_only) return; if (nr_cpus == -1) @@ -540,7 +542,7 @@ static void timerlat_top_usage(char *usage) /* * timerlat_top_parse_args - allocs, parse and fill the cmd line parameters */ -static struct timerlat_params +static struct common_params *timerlat_top_parse_args(int argc, char **argv) { struct timerlat_params *params; @@ -554,8 +556,8 @@ static struct timerlat_params if (!params) exit(1); - actions_init(¶ms->threshold_actions); - actions_init(¶ms->end_actions); + actions_init(¶ms->common.threshold_actions); + actions_init(¶ms->common.end_actions); /* disabled by default */ params->dma_latency = -1; @@ -641,7 +643,7 @@ static struct timerlat_params params->print_stack = auto_thresh; /* set aa_only to avoid parsing the trace */ - params->aa_only = 1; + params->common.aa_only = 1; break; case 'c': retval = parse_cpu_set(optarg, ¶ms->common.monitored_cpus); @@ -731,10 +733,10 @@ static struct timerlat_params trace_output = "timerlat_trace.txt"; break; case 'u': - params->user_workload = true; + params->common.user_workload = true; /* fallback: -u implies -U */ case 'U': - params->user_data = true; + params->common.user_data = true; break; case '0': /* trigger */ if (params->common.events) { @@ -781,14 +783,14 @@ static struct timerlat_params params->deepest_idle_state = get_llong_from_str(optarg); break; case '9': - retval = actions_parse(¶ms->threshold_actions, optarg); + retval = actions_parse(¶ms->common.threshold_actions, optarg); if (retval) { err_msg("Invalid action %s\n", optarg); exit(EXIT_FAILURE); } break; case '\1': - retval = actions_parse(¶ms->end_actions, optarg); + retval = actions_parse(¶ms->common.end_actions, optarg); if (retval) { err_msg("Invalid action %s\n", optarg); exit(EXIT_FAILURE); @@ -800,7 +802,7 @@ static struct timerlat_params } if (trace_output) - actions_add_trace_output(¶ms->threshold_actions, trace_output); + actions_add_trace_output(¶ms->common.threshold_actions, trace_output); if (geteuid()) { err_msg("rtla needs root permission\n"); @@ -813,10 +815,10 @@ static struct timerlat_params if (!params->common.stop_us && !params->common.stop_total_us) params->no_aa = 1; - if (params->no_aa && params->aa_only) + if (params->no_aa && params->common.aa_only) timerlat_top_usage("--no-aa and --aa-only are mutually exclusive!"); - if (params->common.kernel_workload && params->user_workload) + if (params->common.kernel_workload && params->common.user_workload) timerlat_top_usage("--kernel-threads and --user-threads are mutually exclusive!"); /* @@ -824,19 +826,21 @@ static struct timerlat_params * mixed mode */ if (params->mode == TRACING_MODE_BPF && - (params->threshold_actions.present[ACTION_TRACE_OUTPUT] || - params->end_actions.present[ACTION_TRACE_OUTPUT] || !params->no_aa)) + (params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] || + params->common.end_actions.present[ACTION_TRACE_OUTPUT] || + !params->no_aa)) params->mode = TRACING_MODE_MIXED; - return params; + return ¶ms->common; } /* * timerlat_top_apply_config - apply the top configs to the initialized tool */ static int -timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_params *params) +timerlat_top_apply_config(struct osnoise_tool *top) { + struct timerlat_params *params = to_timerlat_params(top->params); int retval; retval = timerlat_apply_config(top, params); @@ -856,7 +860,7 @@ out_err: * timerlat_init_top - initialize a timerlat top tool with parameters */ static struct osnoise_tool -*timerlat_init_top(struct timerlat_params *params) +*timerlat_init_top(struct common_params *params) { struct osnoise_tool *top; int nr_cpus; @@ -871,8 +875,6 @@ static struct osnoise_tool if (!top->data) goto out_err; - top->params = params; - tep_register_event_handler(top->trace.tep, -1, "ftrace", "timerlat", timerlat_top_handler, top); @@ -883,109 +885,16 @@ out_err: return NULL; } -static int stop_tracing; -static struct trace_instance *top_inst = NULL; -static void stop_top(int sig) -{ - if (stop_tracing) { - /* - * Stop requested twice in a row; abort event processing and - * exit immediately - */ - tracefs_iterate_stop(top_inst->inst); - return; - } - stop_tracing = 1; - if (top_inst) - trace_instance_stop(top_inst); -} - -/* - * timerlat_top_set_signals - handles the signal to stop the tool - */ -static void -timerlat_top_set_signals(struct timerlat_params *params) -{ - signal(SIGINT, stop_top); - if (params->common.duration) { - signal(SIGALRM, stop_top); - alarm(params->common.duration); - } -} - -/* - * timerlat_top_main_loop - main loop to process events - */ -static int -timerlat_top_main_loop(struct osnoise_tool *top, - struct osnoise_tool *record, - struct osnoise_tool *aa, - struct timerlat_params *params, - struct timerlat_u_params *params_u) -{ - struct trace_instance *trace = &top->trace; - int retval; - - while (!stop_tracing) { - sleep(params->common.sleep_time); - - if (params->aa_only && !osnoise_trace_is_off(top, record)) - continue; - - retval = tracefs_iterate_raw_events(trace->tep, - trace->inst, - NULL, - 0, - collect_registered_events, - trace); - if (retval < 0) { - err_msg("Error iterating on events\n"); - return retval; - } - - if (!params->common.quiet) - timerlat_print_stats(params, top); - - if (osnoise_trace_is_off(top, record)) { - actions_perform(¶ms->threshold_actions); - - if (!params->threshold_actions.continue_flag) - /* continue flag not set, break */ - break; - - /* continue action reached, re-enable tracing */ - if (record) - trace_instance_start(&record->trace); - if (!params->no_aa) - trace_instance_start(&aa->trace); - trace_instance_start(trace); - } - - /* is there still any user-threads ? */ - if (params->user_workload) { - if (params_u->stopped_running) { - debug_msg("timerlat user space threads stopped!\n"); - break; - } - } - } - - return 0; -} - /* * timerlat_top_bpf_main_loop - main loop to process events (BPF variant) */ static int -timerlat_top_bpf_main_loop(struct osnoise_tool *top, - struct osnoise_tool *record, - struct osnoise_tool *aa, - struct timerlat_params *params, - struct timerlat_u_params *params_u) +timerlat_top_bpf_main_loop(struct osnoise_tool *tool) { + struct timerlat_params *params = to_timerlat_params(tool->params); int retval, wait_retval; - if (params->aa_only) { + if (params->common.aa_only) { /* Auto-analysis only, just wait for stop tracing */ timerlat_bpf_wait(-1); return 0; @@ -996,34 +905,34 @@ timerlat_top_bpf_main_loop(struct osnoise_tool *top, wait_retval = timerlat_bpf_wait(params->common.quiet ? -1 : params->common.sleep_time); - retval = timerlat_top_bpf_pull_data(top); + retval = timerlat_top_bpf_pull_data(tool); if (retval) { err_msg("Error pulling BPF data\n"); return retval; } if (!params->common.quiet) - timerlat_print_stats(params, top); + timerlat_print_stats(tool); if (wait_retval == 1) { /* Stopping requested by tracer */ - actions_perform(¶ms->threshold_actions); + actions_perform(¶ms->common.threshold_actions); - if (!params->threshold_actions.continue_flag) + if (!params->common.threshold_actions.continue_flag) /* continue flag not set, break */ break; /* continue action reached, re-enable tracing */ - if (record) - trace_instance_start(&record->trace); - if (!params->no_aa) - trace_instance_start(&aa->trace); + if (tool->record) + trace_instance_start(&tool->record->trace); + if (tool->aa) + trace_instance_start(&tool->aa->trace); timerlat_bpf_restart_tracing(); } /* is there still any user-threads ? */ - if (params->user_workload) { - if (params_u->stopped_running) { + if (params->common.user_workload) { + if (params->common.user.stopped_running) { debug_msg("timerlat user space threads stopped!\n"); break; } @@ -1033,274 +942,30 @@ timerlat_top_bpf_main_loop(struct osnoise_tool *top, return 0; } -int timerlat_top_main(int argc, char *argv[]) +static int timerlat_top_main_loop(struct osnoise_tool *tool) { - struct timerlat_params *params; - struct osnoise_tool *record = NULL; - struct timerlat_u_params params_u; - enum result return_value = ERROR; - struct osnoise_tool *top = NULL; - struct osnoise_tool *aa = NULL; - struct trace_instance *trace; - int dma_latency_fd = -1; - pthread_t timerlat_u; - char *max_lat; + struct timerlat_params *params = to_timerlat_params(tool->params); int retval; - int nr_cpus, i; - params = timerlat_top_parse_args(argc, argv); - if (!params) - exit(1); - - top = timerlat_init_top(params); - if (!top) { - err_msg("Could not init osnoise top\n"); - goto out_exit; - } - - trace = &top->trace; - /* - * Save trace instance into global variable so that SIGINT can stop - * the timerlat tracer. - * Otherwise, rtla could loop indefinitely when overloaded. - */ - top_inst = trace; - - /* - * Try to enable BPF, unless disabled explicitly. - * If BPF enablement fails, fall back to tracefs mode. - */ - if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) { - debug_msg("RTLA_NO_BPF set, disabling BPF\n"); - params->mode = TRACING_MODE_TRACEFS; - } else if (!tep_find_event_by_name(trace->tep, "osnoise", "timerlat_sample")) { - debug_msg("osnoise:timerlat_sample missing, disabling BPF\n"); - params->mode = TRACING_MODE_TRACEFS; - } else { - retval = timerlat_bpf_init(params); - if (retval) { - debug_msg("Could not enable BPF\n"); - params->mode = TRACING_MODE_TRACEFS; - } - } - - retval = timerlat_top_apply_config(top, params); - if (retval) { - err_msg("Could not apply config\n"); - goto out_free; - } - - retval = enable_timerlat(trace); - if (retval) { - err_msg("Failed to enable timerlat tracer\n"); - goto out_free; - } - - if (params->common.set_sched) { - retval = set_comm_sched_attr("timerlat/", ¶ms->common.sched_param); - if (retval) { - err_msg("Failed to set sched parameters\n"); - goto out_free; - } - } - - if (params->common.cgroup && !params->user_data) { - retval = set_comm_cgroup("timerlat/", params->common.cgroup_name); - if (!retval) { - err_msg("Failed to move threads to cgroup\n"); - goto out_free; - } - } - - if (params->dma_latency >= 0) { - dma_latency_fd = set_cpu_dma_latency(params->dma_latency); - if (dma_latency_fd < 0) { - err_msg("Could not set /dev/cpu_dma_latency.\n"); - goto out_free; - } - } - - if (params->deepest_idle_state >= -1) { - if (!have_libcpupower_support()) { - err_msg("rtla built without libcpupower, --deepest-idle-state is not supported\n"); - goto out_free; - } - - nr_cpus = sysconf(_SC_NPROCESSORS_CONF); - - for (i = 0; i < nr_cpus; i++) { - if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) - continue; - if (save_cpu_idle_disable_state(i) < 0) { - err_msg("Could not save cpu idle state.\n"); - goto out_free; - } - if (set_deepest_cpu_idle_state(i, params->deepest_idle_state) < 0) { - err_msg("Could not set deepest cpu idle state.\n"); - goto out_free; - } - } - } - - if (params->threshold_actions.present[ACTION_TRACE_OUTPUT] || - params->end_actions.present[ACTION_TRACE_OUTPUT]) { - record = osnoise_init_trace_tool("timerlat"); - if (!record) { - err_msg("Failed to enable the trace instance\n"); - goto out_free; - } - params->threshold_actions.trace_output_inst = record->trace.inst; - params->end_actions.trace_output_inst = record->trace.inst; - - if (params->common.events) { - retval = trace_events_enable(&record->trace, params->common.events); - if (retval) - goto out_top; - } - - if (params->common.buffer_size > 0) { - retval = trace_set_buffer_size(&record->trace, params->common.buffer_size); - if (retval) - goto out_top; - } - } - - if (!params->no_aa) { - aa = osnoise_init_tool("timerlat_aa"); - if (!aa) - goto out_top; - - retval = timerlat_aa_init(aa, params->dump_tasks); - if (retval) { - err_msg("Failed to enable the auto analysis instance\n"); - goto out_top; - } - - /* if it is re-using the main instance, there is no need to start it */ - if (aa != top) { - retval = enable_timerlat(&aa->trace); - if (retval) { - err_msg("Failed to enable timerlat tracer\n"); - goto out_top; - } - } - } - - if (params->user_workload) { - /* rtla asked to stop */ - params_u.should_run = 1; - /* all threads left */ - params_u.stopped_running = 0; - - params_u.set = ¶ms->common.monitored_cpus; - if (params->common.set_sched) - params_u.sched_param = ¶ms->common.sched_param; - else - params_u.sched_param = NULL; - - params_u.cgroup_name = params->common.cgroup_name; - - retval = pthread_create(&timerlat_u, NULL, timerlat_u_dispatcher, ¶ms_u); - if (retval) - err_msg("Error creating timerlat user-space threads\n"); - } - - if (params->common.warmup > 0) { - debug_msg("Warming up for %d seconds\n", params->common.warmup); - sleep(params->common.warmup); - } - - /* - * Start the tracers here, after having set all instances. - * - * Let the trace instance start first for the case of hitting a stop - * tracing while enabling other instances. The trace instance is the - * one with most valuable information. - */ - if (record) - trace_instance_start(&record->trace); - if (!params->no_aa) - trace_instance_start(&aa->trace); if (params->mode == TRACING_MODE_TRACEFS) { - trace_instance_start(trace); + retval = top_main_loop(tool); } else { - retval = timerlat_bpf_attach(); - if (retval) { - err_msg("Error attaching BPF program\n"); - goto out_top; - } - } - - top->start_time = time(NULL); - timerlat_top_set_signals(params); - - if (params->mode == TRACING_MODE_TRACEFS) - retval = timerlat_top_main_loop(top, record, aa, params, ¶ms_u); - else - retval = timerlat_top_bpf_main_loop(top, record, aa, params, ¶ms_u); - - if (retval) - goto out_top; - - if (params->mode != TRACING_MODE_TRACEFS) + retval = timerlat_top_bpf_main_loop(tool); timerlat_bpf_detach(); - - if (params->user_workload && !params_u.stopped_running) { - params_u.should_run = 0; - sleep(1); } - timerlat_print_stats(params, top); - - actions_perform(¶ms->end_actions); - - return_value = PASSED; - - if (osnoise_trace_is_off(top, record) && !stop_tracing) { - printf("rtla timerlat hit stop tracing\n"); - - if (!params->no_aa) - timerlat_auto_analysis(params->common.stop_us, - params->common.stop_total_us); - - return_value = FAILED; - } else if (params->aa_only) { - /* - * If the trace did not stop with --aa-only, at least print the - * max known latency. - */ - max_lat = tracefs_instance_file_read(trace->inst, "tracing_max_latency", NULL); - if (max_lat) { - printf(" Max latency was %s\n", max_lat); - free(max_lat); - } - } - -out_top: - timerlat_aa_destroy(); - if (dma_latency_fd >= 0) - close(dma_latency_fd); - if (params->deepest_idle_state >= -1) { - for (i = 0; i < nr_cpus; i++) { - if (params->common.cpus && !CPU_ISSET(i, ¶ms->common.monitored_cpus)) - continue; - restore_cpu_idle_disable_state(i); - } - } - trace_events_destroy(&record->trace, params->common.events); - params->common.events = NULL; -out_free: - timerlat_free_top(top->data); - if (aa && aa != top) - osnoise_destroy_tool(aa); - osnoise_destroy_tool(record); - osnoise_destroy_tool(top); - actions_destroy(¶ms->threshold_actions); - actions_destroy(¶ms->end_actions); - if (params->mode != TRACING_MODE_TRACEFS) - timerlat_bpf_destroy(); - free(params); - free_cpu_idle_disable_states(); -out_exit: - exit(return_value); + return retval; } + +struct tool_ops timerlat_top_ops = { + .tracer = "timerlat", + .comm_prefix = "timerlat/", + .parse_args = timerlat_top_parse_args, + .init_tool = timerlat_init_top, + .apply_config = timerlat_top_apply_config, + .enable = timerlat_enable, + .main = timerlat_top_main_loop, + .print_stats = timerlat_print_stats, + .analyze = timerlat_analyze, + .free = timerlat_free_top_tool, +}; diff --git a/tools/tracing/rtla/src/trace.h b/tools/tracing/rtla/src/trace.h index 3cd40dd3f06c..1e5aee4b828d 100644 --- a/tools/tracing/rtla/src/trace.h +++ b/tools/tracing/rtla/src/trace.h @@ -30,9 +30,6 @@ struct trace_seq *get_trace_seq(void); int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name); void disable_tracer(struct tracefs_instance *inst); -int enable_osnoise(struct trace_instance *trace); -int enable_timerlat(struct trace_instance *trace); - struct tracefs_instance *create_instance(char *instance_name); void destroy_instance(struct tracefs_instance *inst); From c4e30c22baa745173997c831011a95e03771e466 Mon Sep 17 00:00:00 2001 From: Crystal Wood Date: Sat, 6 Sep 2025 21:23:23 -0500 Subject: [PATCH 2187/2711] tools/rtla: Fix -A option name in test comment This was changed to --on-threshold when the patches were applied. Cc: John Kacur Cc: Costa Shulyupin Link: https://lore.kernel.org/20250907022325.243930-6-crwood@redhat.com Reviewed-by: Tomas Glozar Signed-off-by: Crystal Wood Signed-off-by: Steven Rostedt (Google) --- tools/tracing/rtla/tests/timerlat.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/tracing/rtla/tests/timerlat.t b/tools/tracing/rtla/tests/timerlat.t index c71aed5534bf..b5d1e7260a9b 100644 --- a/tools/tracing/rtla/tests/timerlat.t +++ b/tools/tracing/rtla/tests/timerlat.t @@ -47,9 +47,9 @@ check "trace output through -t" \ "timerlat hist -T 2 -t" 2 "^ Saving trace to timerlat_trace.txt$" check "trace output through -t with custom filename" \ "timerlat hist -T 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" -check "trace output through -A trace" \ +check "trace output through --on-threshold trace" \ "timerlat hist -T 2 --on-threshold trace" 2 "^ Saving trace to timerlat_trace.txt$" -check "trace output through -A trace with custom filename" \ +check "trace output through --on-threshold trace with custom filename" \ "timerlat hist -T 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" check "exec command" \ "timerlat hist -T 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$" From 3cd6b18d1025f2fca991c5d9543396892df3a8dd Mon Sep 17 00:00:00 2001 From: Crystal Wood Date: Sat, 6 Sep 2025 21:23:24 -0500 Subject: [PATCH 2188/2711] tools/rtla: Add test engine support for unexpected output Add a check() parameter to indicate which text must not appear in the output. Simplify the code so that we can print failures as they happen rather than trying to figure out what went wrong after printing "not ok". This also means that "not ok" gets printed after the info rather than before, which seems more intuitive anyway. Cc: John Kacur Cc: Costa Shulyupin Link: https://lore.kernel.org/20250907022325.243930-7-crwood@redhat.com Reviewed-by: Tomas Glozar Signed-off-by: Crystal Wood Signed-off-by: Steven Rostedt (Google) --- tools/tracing/rtla/tests/engine.sh | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tools/tracing/rtla/tests/engine.sh b/tools/tracing/rtla/tests/engine.sh index a97d644ead99..c7de3d6ed6a8 100644 --- a/tools/tracing/rtla/tests/engine.sh +++ b/tools/tracing/rtla/tests/engine.sh @@ -43,6 +43,7 @@ check() { tested_command=$1 expected_exitcode=${3:-0} expected_output=$4 + unexpected_output=$5 # Simple check: run rtla with given arguments and test exit code. # If TEST_COUNT is set, run the test. Otherwise, just count. ctr=$(($ctr + 1)) @@ -53,24 +54,33 @@ check() { # Run rtla; in case of failure, include its output as comment # in the test results. result=$(eval stdbuf -oL $TIMEOUT "$RTLA" $2 2>&1); exitcode=$? + failbuf='' + fail=0 + # Test if the results matches if requested - if [ -n "$expected_output" ] + if [ -n "$expected_output" ] && ! grep -qE "$expected_output" <<< "$result" then - grep -E "$expected_output" <<< "$result" > /dev/null; grep_result=$? - else - grep_result=0 + fail=1 + failbuf+=$(printf "# Output match failed: \"%s\"" "$expected_output") + failbuf+=$'\n' fi - if [ $exitcode -eq $expected_exitcode ] && [ $grep_result -eq 0 ] + if [ -n "$unexpected_output" ] && grep -qE "$unexpected_output" <<< "$result" + then + fail=1 + failbuf+=$(printf "# Output non-match failed: \"%s\"" "$unexpected_output") + failbuf+=$'\n' + fi + + if [ $exitcode -eq $expected_exitcode ] && [ $fail -eq 0 ] then echo "ok $ctr - $1" else - echo "not ok $ctr - $1" # Add rtla output and exit code as comments in case of failure + echo "not ok $ctr - $1" + echo -n "$failbuf" echo "$result" | col -b | while read line; do echo "# $line"; done printf "#\n# exit code %s\n" $exitcode - [ -n "$expected_output" ] && [ $grep_result -ne 0 ] && \ - printf "# Output match failed: \"%s\"\n" "$expected_output" fi fi } From 05b7e10687c69e0c28e62b9a74ce78b3e7463806 Mon Sep 17 00:00:00 2001 From: Crystal Wood Date: Sat, 6 Sep 2025 21:23:25 -0500 Subject: [PATCH 2189/2711] tools/rtla: Add remaining support for osnoise actions The basic functionality came with the consolidation; now hook up the command line options, and add documentation and tests. Cc: John Kacur Cc: Costa Shulyupin Link: https://lore.kernel.org/20250907022325.243930-8-crwood@redhat.com Reviewed-by: Tomas Glozar Signed-off-by: Crystal Wood Signed-off-by: Steven Rostedt (Google) --- Documentation/tools/rtla/common_options.rst | 61 +++++++++++++++ .../tools/rtla/common_osnoise_options.rst | 8 ++ .../tools/rtla/common_timerlat_options.rst | 74 +++---------------- Documentation/tools/rtla/rtla-hwnoise.rst | 2 + .../tools/rtla/rtla-osnoise-hist.rst | 2 + Documentation/tools/rtla/rtla-osnoise-top.rst | 2 + .../tools/rtla/rtla-timerlat-hist.rst | 2 + .../tools/rtla/rtla-timerlat-top.rst | 2 + tools/tracing/rtla/src/actions.c | 8 +- tools/tracing/rtla/src/actions.h | 2 +- tools/tracing/rtla/src/osnoise_hist.c | 20 +++++ tools/tracing/rtla/src/osnoise_top.c | 20 +++++ tools/tracing/rtla/src/timerlat_hist.c | 6 +- tools/tracing/rtla/src/timerlat_top.c | 6 +- tools/tracing/rtla/tests/osnoise.t | 27 ++++++- 15 files changed, 168 insertions(+), 74 deletions(-) diff --git a/Documentation/tools/rtla/common_options.rst b/Documentation/tools/rtla/common_options.rst index 2dc1575210aa..77ef35d3f831 100644 --- a/Documentation/tools/rtla/common_options.rst +++ b/Documentation/tools/rtla/common_options.rst @@ -53,6 +53,67 @@ **--trace-buffer-size** *kB* Set the per-cpu trace buffer size in kB for the tracing output. +**--on-threshold** *action* + + Defines an action to be executed when tracing is stopped on a latency threshold + specified by |threshold|. + + Multiple --on-threshold actions may be specified, and they will be executed in + the order they are provided. If any action fails, subsequent actions in the list + will not be executed. + + Supported actions are: + + - *trace[,file=]* + + Saves trace output, optionally taking a filename. Alternative to -t/--trace. + Note that nlike -t/--trace, specifying this multiple times will result in + the trace being saved multiple times. + + - *signal,num=,pid=* + + Sends signal to process. "parent" might be specified in place of pid to target + the parent process of rtla. + + - *shell,command=* + + Execute shell command. + + - *continue* + + Continue tracing after actions are executed instead of stopping. + + Example: + + $ rtla |tool| |thresharg| 20 --on-threshold trace + --on-threshold shell,command="grep ipi_send |tracer|\_trace.txt" + --on-threshold signal,num=2,pid=parent + + This will save a trace with the default filename "|tracer|\_trace.txt", print its + lines that contain the text "ipi_send" on standard output, and send signal 2 + (SIGINT) to the parent process. + + Performance Considerations: + + |actionsperf| + +**--on-end** *action* + + Defines an action to be executed at the end of tracing. + + Multiple --on-end actions can be specified, and they will be executed in the order + they are provided. If any action fails, subsequent actions in the list will not be + executed. + + See the documentation for **--on-threshold** for the list of supported actions, with + the exception that *continue* has no effect. + + Example: + + $ rtla |tool| -d 5s --on-end trace + + This runs rtla with the default options, and saves trace output at the end. + **-h**, **--help** Print help menu. diff --git a/Documentation/tools/rtla/common_osnoise_options.rst b/Documentation/tools/rtla/common_osnoise_options.rst index d73de2d58f5f..bd3c4f499193 100644 --- a/Documentation/tools/rtla/common_osnoise_options.rst +++ b/Documentation/tools/rtla/common_osnoise_options.rst @@ -1,3 +1,11 @@ +.. |threshold| replace:: **-a/--auto**, **-s/--stop**, or **-S/--stop-total** +.. |thresharg| replace:: -s +.. |tracer| replace:: osnoise + +.. |actionsperf| replace:: + Due to implementational limitations, actions might be delayed + up to one second after tracing is stopped. + **-a**, **--auto** *us* Set the automatic trace mode. This mode sets some commonly used options diff --git a/Documentation/tools/rtla/common_timerlat_options.rst b/Documentation/tools/rtla/common_timerlat_options.rst index 7854368f1827..1f5d024b53aa 100644 --- a/Documentation/tools/rtla/common_timerlat_options.rst +++ b/Documentation/tools/rtla/common_timerlat_options.rst @@ -1,3 +1,13 @@ +.. |threshold| replace:: **-a/--auto**, **-i/--irq**, or **-T/--thread** +.. |thresharg| replace:: -T +.. |tracer| replace:: timerlat + +.. |actionsperf| replace:: + For time-sensitive actions, it is recommended to run **rtla timerlat** with BPF + support and RT priority. Note that due to implementational limitations, actions + might be delayed up to one second after tracing is stopped if BPF mode is not + available or disabled. + **-a**, **--auto** *us* Set the automatic trace mode. This mode sets some commonly used options @@ -55,67 +65,3 @@ Set timerlat to run without workload, waiting for the user to dispatch a per-cpu task that waits for a new period on the tracing/osnoise/per_cpu/cpu$ID/timerlat_fd. See linux/tools/rtla/sample/timerlat_load.py for an example of user-load code. - -**--on-threshold** *action* - - Defines an action to be executed when tracing is stopped on a latency threshold - specified by **-i/--irq** or **-T/--thread**. - - Multiple --on-threshold actions may be specified, and they will be executed in - the order they are provided. If any action fails, subsequent actions in the list - will not be executed. - - Supported actions are: - - - *trace[,file=]* - - Saves trace output, optionally taking a filename. Alternative to -t/--trace. - Note that nlike -t/--trace, specifying this multiple times will result in - the trace being saved multiple times. - - - *signal,num=,pid=* - - Sends signal to process. "parent" might be specified in place of pid to target - the parent process of rtla. - - - *shell,command=* - - Execute shell command. - - - *continue* - - Continue tracing after actions are executed instead of stopping. - - Example: - - $ rtla timerlat -T 20 --on-threshold trace - --on-threshold shell,command="grep ipi_send timerlat_trace.txt" - --on-threshold signal,num=2,pid=parent - - This will save a trace with the default filename "timerlat_trace.txt", print its - lines that contain the text "ipi_send" on standard output, and send signal 2 - (SIGINT) to the parent process. - - Performance Considerations: - - For time-sensitive actions, it is recommended to run **rtla timerlat** with BPF - support and RT priority. Note that due to implementational limitations, actions - might be delayed up to one second after tracing is stopped if BPF mode is not - available or disabled. - -**--on-end** *action* - - Defines an action to be executed at the end of **rtla timerlat** tracing. - - Multiple --on-end actions can be specified, and they will be executed in the order - they are provided. If any action fails, subsequent actions in the list will not be - executed. - - See the documentation for **--on-threshold** for the list of supported actions, with - the exception that *continue* has no effect. - - Example: - - $ rtla timerlat -d 5s --on-end trace - - This runs rtla timerlat with default options and save trace output at the end. diff --git a/Documentation/tools/rtla/rtla-hwnoise.rst b/Documentation/tools/rtla/rtla-hwnoise.rst index fb1c52bbc00b..3a7163c02ac8 100644 --- a/Documentation/tools/rtla/rtla-hwnoise.rst +++ b/Documentation/tools/rtla/rtla-hwnoise.rst @@ -1,5 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 +.. |tool| replace:: hwnoise + ============ rtla-hwnoise ============ diff --git a/Documentation/tools/rtla/rtla-osnoise-hist.rst b/Documentation/tools/rtla/rtla-osnoise-hist.rst index f2e79d22c4c4..1fc60ef26106 100644 --- a/Documentation/tools/rtla/rtla-osnoise-hist.rst +++ b/Documentation/tools/rtla/rtla-osnoise-hist.rst @@ -1,3 +1,5 @@ +.. |tool| replace:: osnoise hist + =================== rtla-osnoise-hist =================== diff --git a/Documentation/tools/rtla/rtla-osnoise-top.rst b/Documentation/tools/rtla/rtla-osnoise-top.rst index 5d75d1394516..b1cbd7bcd4ae 100644 --- a/Documentation/tools/rtla/rtla-osnoise-top.rst +++ b/Documentation/tools/rtla/rtla-osnoise-top.rst @@ -1,3 +1,5 @@ +.. |tool| replace:: osnoise top + =================== rtla-osnoise-top =================== diff --git a/Documentation/tools/rtla/rtla-timerlat-hist.rst b/Documentation/tools/rtla/rtla-timerlat-hist.rst index b2d8726271b3..4923a362129b 100644 --- a/Documentation/tools/rtla/rtla-timerlat-hist.rst +++ b/Documentation/tools/rtla/rtla-timerlat-hist.rst @@ -1,3 +1,5 @@ +.. |tool| replace:: timerlat hist + ===================== rtla-timerlat-hist ===================== diff --git a/Documentation/tools/rtla/rtla-timerlat-top.rst b/Documentation/tools/rtla/rtla-timerlat-top.rst index ab6cb60c9083..50968cdd2095 100644 --- a/Documentation/tools/rtla/rtla-timerlat-top.rst +++ b/Documentation/tools/rtla/rtla-timerlat-top.rst @@ -1,3 +1,5 @@ +.. |tool| replace:: timerlat top + ==================== rtla-timerlat-top ==================== diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c index aaf0808125d7..991139f9069f 100644 --- a/tools/tracing/rtla/src/actions.c +++ b/tools/tracing/rtla/src/actions.c @@ -127,17 +127,17 @@ actions_add_continue(struct actions *self) * actions_parse - add an action based on text specification */ int -actions_parse(struct actions *self, const char *trigger) +actions_parse(struct actions *self, const char *trigger, const char *tracefn) { enum action_type type = ACTION_NONE; - char *token; + const char *token; char trigger_c[strlen(trigger)]; /* For ACTION_SIGNAL */ int signal = 0, pid = 0; /* For ACTION_TRACE_OUTPUT */ - char *trace_output; + const char *trace_output; strcpy(trigger_c, trigger); token = strtok(trigger_c, ","); @@ -160,7 +160,7 @@ actions_parse(struct actions *self, const char *trigger) case ACTION_TRACE_OUTPUT: /* Takes no argument */ if (token == NULL) - trace_output = "timerlat_trace.txt"; + trace_output = tracefn; else { if (strlen(token) > 5 && strncmp(token, "file=", 5) == 0) { trace_output = token + 5; diff --git a/tools/tracing/rtla/src/actions.h b/tools/tracing/rtla/src/actions.h index b10a19d55c49..a4f9b570775b 100644 --- a/tools/tracing/rtla/src/actions.h +++ b/tools/tracing/rtla/src/actions.h @@ -48,5 +48,5 @@ int actions_add_trace_output(struct actions *self, const char *trace_output); int actions_add_signal(struct actions *self, int signal, int pid); int actions_add_shell(struct actions *self, const char *command); int actions_add_continue(struct actions *self); -int actions_parse(struct actions *self, const char *trigger); +int actions_parse(struct actions *self, const char *trigger, const char *tracefn); int actions_perform(struct actions *self); diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index 2c2cdd467a67..dffb6d0a98d7 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -462,6 +462,8 @@ static void osnoise_hist_usage(char *usage) " in nanoseconds", " --warm-up: let the workload run for s seconds before collecting data", " --trace-buffer-size kB: set the per-cpu trace buffer size in kB", + " --on-threshold : define action to be executed at stop-total threshold, multiple are allowed", + " --on-end : define action to be executed at measurement end, multiple are allowed", NULL, }; @@ -531,6 +533,8 @@ static struct common_params {"filter", required_argument, 0, '5'}, {"warm-up", required_argument, 0, '6'}, {"trace-buffer-size", required_argument, 0, '7'}, + {"on-threshold", required_argument, 0, '8'}, + {"on-end", required_argument, 0, '9'}, {0, 0, 0, 0} }; @@ -692,6 +696,22 @@ static struct common_params case '7': params->common.buffer_size = get_llong_from_str(optarg); break; + case '8': + retval = actions_parse(¶ms->common.threshold_actions, optarg, + "osnoise_trace.txt"); + if (retval) { + err_msg("Invalid action %s\n", optarg); + exit(EXIT_FAILURE); + } + break; + case '9': + retval = actions_parse(¶ms->common.end_actions, optarg, + "osnoise_trace.txt"); + if (retval) { + err_msg("Invalid action %s\n", optarg); + exit(EXIT_FAILURE); + } + break; default: osnoise_hist_usage("Invalid option"); } diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 5a56c276f9da..95418f7ecc96 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -291,6 +291,8 @@ static void osnoise_top_usage(struct osnoise_params *params, char *usage) " in nanoseconds", " --warm-up s: let the workload run for s seconds before collecting data", " --trace-buffer-size kB: set the per-cpu trace buffer size in kB", + " --on-threshold : define action to be executed at stop-total threshold, multiple are allowed", + " --on-end: define action to be executed at measurement end, multiple are allowed", NULL, }; @@ -371,6 +373,8 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) {"filter", required_argument, 0, '1'}, {"warm-up", required_argument, 0, '2'}, {"trace-buffer-size", required_argument, 0, '3'}, + {"on-threshold", required_argument, 0, '4'}, + {"on-end", required_argument, 0, '5'}, {0, 0, 0, 0} }; @@ -511,6 +515,22 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) case '3': params->common.buffer_size = get_llong_from_str(optarg); break; + case '4': + retval = actions_parse(¶ms->common.threshold_actions, optarg, + "osnoise_trace.txt"); + if (retval) { + err_msg("Invalid action %s\n", optarg); + exit(EXIT_FAILURE); + } + break; + case '5': + retval = actions_parse(¶ms->common.end_actions, optarg, + "osnoise_trace.txt"); + if (retval) { + err_msg("Invalid action %s\n", optarg); + exit(EXIT_FAILURE); + } + break; default: osnoise_top_usage(params, "Invalid option"); } diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index a9154f83f1a9..606c1688057b 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -1047,14 +1047,16 @@ static struct common_params params->deepest_idle_state = get_llong_from_str(optarg); break; case '\5': - retval = actions_parse(¶ms->common.threshold_actions, optarg); + retval = actions_parse(¶ms->common.threshold_actions, optarg, + "timerlat_trace.txt"); if (retval) { err_msg("Invalid action %s\n", optarg); exit(EXIT_FAILURE); } break; case '\6': - retval = actions_parse(¶ms->common.end_actions, optarg); + retval = actions_parse(¶ms->common.end_actions, optarg, + "timerlat_trace.txt"); if (retval) { err_msg("Invalid action %s\n", optarg); exit(EXIT_FAILURE); diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index 4f1ce72d6a05..fc479a0dcb59 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -783,14 +783,16 @@ static struct common_params params->deepest_idle_state = get_llong_from_str(optarg); break; case '9': - retval = actions_parse(¶ms->common.threshold_actions, optarg); + retval = actions_parse(¶ms->common.threshold_actions, optarg, + "timerlat_trace.txt"); if (retval) { err_msg("Invalid action %s\n", optarg); exit(EXIT_FAILURE); } break; case '\1': - retval = actions_parse(¶ms->common.end_actions, optarg); + retval = actions_parse(¶ms->common.end_actions, optarg, + "timerlat_trace.txt"); if (retval) { err_msg("Invalid action %s\n", optarg); exit(EXIT_FAILURE); diff --git a/tools/tracing/rtla/tests/osnoise.t b/tools/tracing/rtla/tests/osnoise.t index 7574ec6a5a53..e3c89d45a6bb 100644 --- a/tools/tracing/rtla/tests/osnoise.t +++ b/tools/tracing/rtla/tests/osnoise.t @@ -8,7 +8,8 @@ set_timeout 2m check "verify help page" \ "osnoise --help" 0 "osnoise version" check "verify the --priority/-P param" \ - "osnoise top -P F:1 -c 0 -r 900000 -d 10s -q" + "osnoise top -P F:1 -c 0 -r 900000 -d 10s -q -S 1 --on-threshold shell,command=\"tests/scripts/check-priority.sh osnoise/ SCHED_FIFO 1\"" \ + 2 "Priorities are set correctly" check "verify the --stop/-s param" \ "osnoise top -s 30 -T 1" 2 "osnoise hit stop tracing" check "verify the --trace param" \ @@ -22,4 +23,28 @@ check "verify the --entries/-E param" \ check_with_osnoise_options "apply default period" \ "osnoise hist -s 1" 2 period_us=600000000 +# Actions tests +check "trace output through -t with custom filename" \ + "osnoise hist -S 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" +check "trace output through --on-threshold trace" \ + "osnoise hist -S 2 --on-threshold trace" 2 "^ Saving trace to osnoise_trace.txt$" +check "trace output through --on-threshold trace with custom filename" \ + "osnoise hist -S 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$" +check "exec command" \ + "osnoise hist -S 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$" +check "multiple actions" \ + "osnoise hist -S 2 --on-threshold shell,command='echo -n 1' --on-threshold shell,command='echo 2'" 2 "^12$" +check "hist stop at failed action" \ + "osnoise hist -S 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1# RTLA osnoise histogram$" +check "top stop at failed action" \ + "timerlat top -T 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh" +check "hist with continue" \ + "osnoise hist -S 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" +check "top with continue" \ + "osnoise top -q -S 2 -d 1s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$" +check "hist with trace output at end" \ + "osnoise hist -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$" +check "top with trace output at end" \ + "osnoise top -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$" + test_end From 7f7acd193ba8aaa8ed07cfadc335bb17a991fd42 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 25 Sep 2025 12:42:14 -0700 Subject: [PATCH 2190/2711] PM: runtime: Add basic kunit tests for API contracts In exploring the various return codes and failure modes of runtime PM APIs, I found it helpful to verify and codify many of them in unit tests, especially given that even the kerneldoc can be rather complex to reason through, and it also has had subtle errors of its own. Notably, I avoid testing the return codes for pm_runtime_put() and pm_runtime_put_autosuspend(), since code that checks them is probably wrong, and we're considering making them return 'void' altogether. I still test the sync() variants, since those have a bit more meaning to them. Signed-off-by: Brian Norris Signed-off-by: Rafael J. Wysocki --- drivers/base/Kconfig | 6 + drivers/base/power/Makefile | 1 + drivers/base/power/runtime-test.c | 253 ++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 drivers/base/power/runtime-test.c diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 064eb52ff7e2..1786d87b29e2 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -167,6 +167,12 @@ config PM_QOS_KUNIT_TEST depends on KUNIT=y default KUNIT_ALL_TESTS +config PM_RUNTIME_KUNIT_TEST + tristate "KUnit Tests for runtime PM" if !KUNIT_ALL_TESTS + depends on KUNIT + depends on PM + default KUNIT_ALL_TESTS + config HMEM_REPORTING bool default n diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 01f11629d241..2989e42d0161 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o wakeup_stats.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_HAVE_CLK) += clock_ops.o obj-$(CONFIG_PM_QOS_KUNIT_TEST) += qos-test.o +obj-$(CONFIG_PM_RUNTIME_KUNIT_TEST) += runtime-test.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/drivers/base/power/runtime-test.c b/drivers/base/power/runtime-test.c new file mode 100644 index 000000000000..2e966fd96664 --- /dev/null +++ b/drivers/base/power/runtime-test.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 Google, Inc. + */ + +#include +#include +#include +#include + +#define DEVICE_NAME "pm_runtime_test_device" + +static void pm_runtime_depth_test(struct kunit *test) +{ + struct device *dev = kunit_device_register(test, DEVICE_NAME); + + KUNIT_ASSERT_PTR_NE(test, NULL, dev); + + pm_runtime_enable(dev); + + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); + KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev)); + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); + KUNIT_EXPECT_EQ(test, 1, pm_runtime_get_sync(dev)); /* "already active" */ + KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev)); + KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev)); + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); +} + +/* Test pm_runtime_put() and friends when already suspended. */ +static void pm_runtime_already_suspended_test(struct kunit *test) +{ + struct device *dev = kunit_device_register(test, DEVICE_NAME); + + KUNIT_ASSERT_PTR_NE(test, NULL, dev); + + pm_runtime_enable(dev); + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); + + pm_runtime_get_noresume(dev); + KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev)); /* no wakeup needed */ + pm_runtime_put(dev); + + pm_runtime_get_noresume(dev); + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_put_sync(dev)); + + KUNIT_EXPECT_EQ(test, 1, pm_runtime_suspend(dev)); + KUNIT_EXPECT_EQ(test, 1, pm_runtime_autosuspend(dev)); + KUNIT_EXPECT_EQ(test, 1, pm_request_autosuspend(dev)); + + pm_runtime_get_noresume(dev); + KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync_autosuspend(dev)); + + pm_runtime_get_noresume(dev); + pm_runtime_put_autosuspend(dev); + + /* Grab 2 refcounts */ + pm_runtime_get_noresume(dev); + pm_runtime_get_noresume(dev); + /* The first put() sees usage_count 1 */ + KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync_autosuspend(dev)); + /* The second put() sees usage_count 0 but tells us "already suspended". */ + KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync_autosuspend(dev)); + + /* Should have remained suspended the whole time. */ + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); +} + +static void pm_runtime_idle_test(struct kunit *test) +{ + struct device *dev = kunit_device_register(test, DEVICE_NAME); + + KUNIT_ASSERT_PTR_NE(test, NULL, dev); + + pm_runtime_enable(dev); + + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); + KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev)); + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev)); + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); + pm_runtime_put_noidle(dev); + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); + KUNIT_EXPECT_EQ(test, 0, pm_runtime_idle(dev)); + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev)); + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_idle(dev)); +} + +static void pm_runtime_disabled_test(struct kunit *test) +{ + struct device *dev = kunit_device_register(test, DEVICE_NAME); + + KUNIT_ASSERT_PTR_NE(test, NULL, dev); + + /* Never called pm_runtime_enable() */ + KUNIT_EXPECT_FALSE(test, pm_runtime_enabled(dev)); + + /* "disabled" is treated as "active" */ + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); + KUNIT_EXPECT_FALSE(test, pm_runtime_suspended(dev)); + + /* + * Note: these "fail", but they still acquire/release refcounts, so + * keep them balanced. + */ + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get(dev)); + pm_runtime_put(dev); + + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get_sync(dev)); + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_put_sync(dev)); + + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get(dev)); + pm_runtime_put_autosuspend(dev); + + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_resume_and_get(dev)); + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_idle(dev)); + KUNIT_EXPECT_EQ(test, -EACCES, pm_request_idle(dev)); + KUNIT_EXPECT_EQ(test, -EACCES, pm_request_resume(dev)); + KUNIT_EXPECT_EQ(test, -EACCES, pm_request_autosuspend(dev)); + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_suspend(dev)); + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_resume(dev)); + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_autosuspend(dev)); + + /* Still disabled */ + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); + KUNIT_EXPECT_FALSE(test, pm_runtime_enabled(dev)); +} + +static void pm_runtime_error_test(struct kunit *test) +{ + struct device *dev = kunit_device_register(test, DEVICE_NAME); + + KUNIT_ASSERT_PTR_NE(test, NULL, dev); + + pm_runtime_enable(dev); + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); + + /* Fake a .runtime_resume() error */ + dev->power.runtime_error = -EIO; + + /* + * Note: these "fail", but they still acquire/release refcounts, so + * keep them balanced. + */ + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev)); + pm_runtime_put(dev); + + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get_sync(dev)); + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_put_sync(dev)); + + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev)); + pm_runtime_put_autosuspend(dev); + + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev)); + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_put_sync_autosuspend(dev)); + + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_resume_and_get(dev)); + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_idle(dev)); + KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_idle(dev)); + KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_resume(dev)); + KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_autosuspend(dev)); + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_suspend(dev)); + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_resume(dev)); + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_autosuspend(dev)); + + /* Error is still pending */ + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); + KUNIT_EXPECT_EQ(test, -EIO, dev->power.runtime_error); + /* Clear error */ + KUNIT_EXPECT_EQ(test, 0, pm_runtime_set_suspended(dev)); + KUNIT_EXPECT_EQ(test, 0, dev->power.runtime_error); + /* Still suspended */ + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); + + KUNIT_EXPECT_EQ(test, 0, pm_runtime_get(dev)); + KUNIT_EXPECT_EQ(test, 1, pm_runtime_barrier(dev)); /* resume was pending */ + pm_runtime_put(dev); + pm_runtime_suspend(dev); /* flush the put(), to suspend */ + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); + + KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev)); + KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev)); + + KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev)); + pm_runtime_put_autosuspend(dev); + + KUNIT_EXPECT_EQ(test, 0, pm_runtime_resume_and_get(dev)); + + /* + * The following should all return -EAGAIN (usage is non-zero) or 1 + * (already resumed). + */ + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev)); + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_idle(dev)); + KUNIT_EXPECT_EQ(test, 1, pm_request_resume(dev)); + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_autosuspend(dev)); + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_suspend(dev)); + KUNIT_EXPECT_EQ(test, 1, pm_runtime_resume(dev)); + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_autosuspend(dev)); + + KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev)); + + /* Suspended again */ + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); +} + +/* + * Explore a typical probe() sequence in which a device marks itself powered, + * but doesn't hold any runtime PM reference, so it suspends as soon as it goes + * idle. + */ +static void pm_runtime_probe_active_test(struct kunit *test) +{ + struct device *dev = kunit_device_register(test, DEVICE_NAME); + + KUNIT_ASSERT_PTR_NE(test, NULL, dev); + + KUNIT_EXPECT_TRUE(test, pm_runtime_status_suspended(dev)); + + KUNIT_EXPECT_EQ(test, 0, pm_runtime_set_active(dev)); + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); + + pm_runtime_enable(dev); + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); + + /* Nothing to flush. We stay active. */ + KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev)); + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); + + /* Ask for idle? Now we suspend. */ + KUNIT_EXPECT_EQ(test, 0, pm_runtime_idle(dev)); + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); +} + +static struct kunit_case pm_runtime_test_cases[] = { + KUNIT_CASE(pm_runtime_depth_test), + KUNIT_CASE(pm_runtime_already_suspended_test), + KUNIT_CASE(pm_runtime_idle_test), + KUNIT_CASE(pm_runtime_disabled_test), + KUNIT_CASE(pm_runtime_error_test), + KUNIT_CASE(pm_runtime_probe_active_test), + {} +}; + +static struct kunit_suite pm_runtime_test_suite = { + .name = "pm_runtime_test_cases", + .test_cases = pm_runtime_test_cases, +}; + +kunit_test_suite(pm_runtime_test_suite); +MODULE_DESCRIPTION("Runtime power management unit test suite"); +MODULE_LICENSE("GPL"); From d0b8651a026125d58b50b464aeb78f2c5956179f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 25 Sep 2025 12:42:15 -0700 Subject: [PATCH 2191/2711] PM: runtime: Make put{,_sync}() return 1 when already suspended The pm_runtime.h docs say pm_runtime_put() and pm_runtime_put_sync() return 1 when already suspended, but this is not true -- they return -EAGAIN. On the other hand, pm_runtime_put_sync_suspend() and pm_runtime_put_sync_autosuspend() *do* return 1. This is an artifact of the fact that the former are built on rpm_idle(), whereas the latter are built on rpm_suspend(). There are precious few pm_runtime_put()/pm_runtime_put_sync() callers that check the return code at all, but most of them only log errors, and usually only for negative error codes. None of them should be treating this as an error, so: * at best, this may fix some case where a driver treats this condition as an error, when it shouldn't; * at worst, this should make no effect; and * somewhere in between, we could potentially clear up non-fatal log messages. Fix the pm_runtime_already_suspended_test() while tweaking the behavior. The test makes a lot more sense when these all return 1 when the device is already suspended: pm_runtime_put_sync(dev); pm_runtime_suspend(dev); pm_runtime_autosuspend(dev); pm_request_autosuspend(dev); pm_runtime_put_sync_autosuspend(dev); Notably, I've avoided testing the return codes for these, since they really should be ignored by callers, and we may make them 'void' altogether: pm_runtime_put(dev); pm_runtime_put_autosuspend(dev); Signed-off-by: Brian Norris Reviewed-by: Dhruva Gole Reviewed-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime-test.c | 2 +- drivers/base/power/runtime.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/runtime-test.c b/drivers/base/power/runtime-test.c index 2e966fd96664..eca9885e807d 100644 --- a/drivers/base/power/runtime-test.c +++ b/drivers/base/power/runtime-test.c @@ -42,7 +42,7 @@ static void pm_runtime_already_suspended_test(struct kunit *test) pm_runtime_put(dev); pm_runtime_get_noresume(dev); - KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_put_sync(dev)); + KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync(dev)); KUNIT_EXPECT_EQ(test, 1, pm_runtime_suspend(dev)); KUNIT_EXPECT_EQ(test, 1, pm_runtime_autosuspend(dev)); diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 3e84dc4122de..faa68bf9ef3d 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -498,6 +498,9 @@ static int rpm_idle(struct device *dev, int rpmflags) if (retval < 0) ; /* Conditions are wrong. */ + else if ((rpmflags & RPM_GET_PUT) && retval == 1) + ; /* put() is allowed in RPM_SUSPENDED */ + /* Idle notifications are allowed only in the RPM_ACTIVE state. */ else if (dev->power.runtime_status != RPM_ACTIVE) retval = -EAGAIN; From fed7eaa4f037361fe4f3d4170649d6849a25998d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 25 Sep 2025 12:42:16 -0700 Subject: [PATCH 2192/2711] PM: runtime: Update kerneldoc return codes APIs based on __pm_runtime_idle() (pm_runtime_idle(), pm_request_idle()) do not return 1 when already suspended. They return -EAGAIN. This is already covered in the docs, so the entry for "1" is redundant and conflicting. (pm_runtime_put() and pm_runtime_put_sync() were previously incorrect, but that's fixed in "PM: runtime: pm_runtime_put{,_sync}() returns 1 when already suspended", to ensure consistency with APIs like pm_runtime_put_autosuspend().) RPM_GET_PUT APIs based on __pm_runtime_suspend() do return 1 when already suspended, but the language is a little unclear -- it's not really an "error", so it seems better to list as a clarification before the 0/success case. Additionally, they only actually return 1 when the refcount makes it to 0; if the usage counter is still non-zero, we return 0. pm_runtime_put(), etc., also don't appear at first like they can ever see "-EAGAIN: Runtime PM usage_count non-zero", because in non-racy conditions, pm_runtime_put() would drop its reference count, see it's non-zero, and return early (in __pm_runtime_idle()). However, it's possible to race with another actor that increments the usage_count afterward, since rpm_idle() is protected by a separate lock; in such a case, we may see -EAGAIN. Because this case is only seen in the presence of concurrent actors, it makes sense to clarify that this is when "usage_count **became** non-zero", by way of some racing actor. Lastly, pm_runtime_put_sync_suspend() duplicated some -EAGAIN language. Fix that. Fixes: 271ff96d6066 ("PM: runtime: Document return values of suspend-related API functions") Link: https://lore.kernel.org/linux-pm/aJ5pkEJuixTaybV4@google.com/ Signed-off-by: Brian Norris Reviewed-by: Sakari Ailus Cc: 6.17+ # 6.17+ Signed-off-by: Rafael J. Wysocki --- include/linux/pm_runtime.h | 56 +++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index d88d6b6ccf5b..d1ff76e0e2d0 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -350,13 +350,12 @@ static inline int pm_runtime_force_resume(struct device *dev) { return -ENXIO; } * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero, Runtime PM status change ongoing - * or device not in %RPM_ACTIVE state. + * * -EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change + * ongoing or device not in %RPM_ACTIVE state. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -EINPROGRESS: Suspend already in progress. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. * Other values and conditions for the above values are possible as returned by * Runtime PM idle and suspend callbacks. */ @@ -370,14 +369,15 @@ static inline int pm_runtime_idle(struct device *dev) * @dev: Target device. * * Return: + * * 1: Success; device was already suspended. * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing. + * * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change + * ongoing. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. * Other values and conditions for the above values are possible as returned by * Runtime PM suspend callbacks. */ @@ -396,14 +396,15 @@ static inline int pm_runtime_suspend(struct device *dev) * engaging its "idle check" callback. * * Return: + * * 1: Success; device was already suspended. * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing. + * * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change + * ongoing. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. * Other values and conditions for the above values are possible as returned by * Runtime PM suspend callbacks. */ @@ -433,13 +434,12 @@ static inline int pm_runtime_resume(struct device *dev) * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero, Runtime PM status change ongoing - * or device not in %RPM_ACTIVE state. + * * -EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change + * ongoing or device not in %RPM_ACTIVE state. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -EINPROGRESS: Suspend already in progress. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. */ static inline int pm_request_idle(struct device *dev) { @@ -464,15 +464,16 @@ static inline int pm_request_resume(struct device *dev) * equivalent pm_runtime_autosuspend() for @dev asynchronously. * * Return: + * * 1: Success; device was already suspended. * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing. + * * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change + * ongoing. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -EINPROGRESS: Suspend already in progress. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. */ static inline int pm_request_autosuspend(struct device *dev) { @@ -540,15 +541,16 @@ static inline int pm_runtime_resume_and_get(struct device *dev) * equal to 0, queue up a work item for @dev like in pm_request_idle(). * * Return: + * * 1: Success. Usage counter dropped to zero, but device was already suspended. * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing. + * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -EINPROGRESS: Suspend already in progress. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. */ static inline int pm_runtime_put(struct device *dev) { @@ -565,15 +567,16 @@ DEFINE_FREE(pm_runtime_put, struct device *, if (_T) pm_runtime_put(_T)) * equal to 0, queue up a work item for @dev like in pm_request_autosuspend(). * * Return: + * * 1: Success. Usage counter dropped to zero, but device was already suspended. * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing. + * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -EINPROGRESS: Suspend already in progress. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. */ static inline int __pm_runtime_put_autosuspend(struct device *dev) { @@ -590,15 +593,16 @@ static inline int __pm_runtime_put_autosuspend(struct device *dev) * in pm_request_autosuspend(). * * Return: + * * 1: Success. Usage counter dropped to zero, but device was already suspended. * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing. + * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -EINPROGRESS: Suspend already in progress. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. */ static inline int pm_runtime_put_autosuspend(struct device *dev) { @@ -619,14 +623,15 @@ static inline int pm_runtime_put_autosuspend(struct device *dev) * if it returns an error code. * * Return: + * * 1: Success. Usage counter dropped to zero, but device was already suspended. * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing. + * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. * Other values and conditions for the above values are possible as returned by * Runtime PM suspend callbacks. */ @@ -646,15 +651,15 @@ static inline int pm_runtime_put_sync(struct device *dev) * if it returns an error code. * * Return: + * * 1: Success. Usage counter dropped to zero, but device was already suspended. * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing. - * * -EAGAIN: usage_count non-zero or Runtime PM status change ongoing. + * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. * Other values and conditions for the above values are possible as returned by * Runtime PM suspend callbacks. */ @@ -677,15 +682,16 @@ static inline int pm_runtime_put_sync_suspend(struct device *dev) * if it returns an error code. * * Return: + * * 1: Success. Usage counter dropped to zero, but device was already suspended. * * 0: Success. * * -EINVAL: Runtime PM error. * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing. + * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. * * -EBUSY: Runtime PM child_count non-zero. * * -EPERM: Device PM QoS resume latency 0. * * -EINPROGRESS: Suspend already in progress. * * -ENOSYS: CONFIG_PM not enabled. - * * 1: Device already suspended. * Other values and conditions for the above values are possible as returned by * Runtime PM suspend callbacks. */ From 632d31067be2f414c57955efcf29c79290cc749b Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Fri, 26 Sep 2025 18:23:18 +0800 Subject: [PATCH 2193/2711] PM: sleep: Do not wait on SYNC_STATE_ONLY device links Device links with DL_FLAG_SYNC_STATE_ONLY should not affect system suspend and resume, and functions like device_reorder_to_tail() and device_link_add() don't try to reorder the consumers with that flag. However, dpm_wait_for_consumers() and dpm_wait_for_suppliers() don't check thas flag before triggering dpm_wait(), leading to potential hang during suspend/resume. This can be reproduced on MT8186 Corsola Chromebook with devicetree like: usb-a-connector { compatible = "usb-a-connector"; port { usb_a_con: endpoint { remote-endpoint = <&usb_hs>; }; }; }; usb_host { compatible = "mediatek,mt8186-xhci", "mediatek,mtk-xhci"; port { usb_hs: endpoint { remote-endpoint = <&usb_a_con>; }; }; }; In this case, the two nodes form a cycle and a SYNC_STATE_ONLY devlink between usb_host (supplier) and usb-a-connector (consumer) is created. Address this by exporting device_link_flag_is_sync_state_only() and making dpm_wait_for_consumers() and dpm_wait_for_suppliers() use it when deciding if dpm_wait() should be called. Fixes: 05ef983e0d65a ("driver core: Add device link support for SYNC_STATE_ONLY flag") Signed-off-by: Pin-yen Lin Link: https://patch.msgid.link/20250926102320.4053167-1-treapking@chromium.org [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/base/base.h | 1 + drivers/base/core.c | 2 +- drivers/base/power/main.c | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index 700aecd22fd3..86fa7fbb3548 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -248,6 +248,7 @@ void device_links_driver_cleanup(struct device *dev); void device_links_no_driver(struct device *dev); bool device_links_busy(struct device *dev); void device_links_unbind_consumers(struct device *dev); +bool device_link_flag_is_sync_state_only(u32 flags); void fw_devlink_drivers_done(void); void fw_devlink_probing_done(void); diff --git a/drivers/base/core.c b/drivers/base/core.c index d22d6b23e758..a54ec6df1058 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -287,7 +287,7 @@ static bool device_is_ancestor(struct device *dev, struct device *target) #define DL_MARKER_FLAGS (DL_FLAG_INFERRED | \ DL_FLAG_CYCLE | \ DL_FLAG_MANAGED) -static inline bool device_link_flag_is_sync_state_only(u32 flags) +bool device_link_flag_is_sync_state_only(u32 flags) { return (flags & ~DL_MARKER_FLAGS) == DL_FLAG_SYNC_STATE_ONLY; } diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index e3a7f25bf8d3..c97f8b139dc2 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -278,7 +278,8 @@ static void dpm_wait_for_suppliers(struct device *dev, bool async) * walking. */ dev_for_each_link_to_supplier(link, dev) - if (READ_ONCE(link->status) != DL_STATE_DORMANT) + if (READ_ONCE(link->status) != DL_STATE_DORMANT && + !device_link_flag_is_sync_state_only(link->flags)) dpm_wait(link->supplier, async); device_links_read_unlock(idx); @@ -335,7 +336,8 @@ static void dpm_wait_for_consumers(struct device *dev, bool async) * unregistration). */ dev_for_each_link_to_consumer(link, dev) - if (READ_ONCE(link->status) != DL_STATE_DORMANT) + if (READ_ONCE(link->status) != DL_STATE_DORMANT && + !device_link_flag_is_sync_state_only(link->flags)) dpm_wait(link->consumer, async); device_links_read_unlock(idx); From 623fa18f6c94e589b29c4e6277943364f1bb71d6 Mon Sep 17 00:00:00 2001 From: "Randall P. Embry" Date: Fri, 26 Sep 2025 18:27:29 +0900 Subject: [PATCH 2194/2711] 9p: clean up comment typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a few minor typos in comments (e.g. "trasnport" → "transport"). Signed-off-by: Randall P. Embry Message-ID: <20250926-v9fs_misc-v1-1-a8b3907fc04d@codewreck.org> Signed-off-by: Dominique Martinet --- fs/9p/v9fs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 77e9c4387c1d..01e70a464b60 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -438,8 +438,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, v9ses->flags &= ~V9FS_ACCESS_MASK; v9ses->flags |= V9FS_ACCESS_USER; } - /*FIXME !! */ - /* for legacy mode, fall back to V9FS_ACCESS_ANY */ + /* FIXME: for legacy mode, fall back to V9FS_ACCESS_ANY */ if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) && ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) { @@ -450,7 +449,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, if (!v9fs_proto_dotl(v9ses) || !((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) { /* - * We support ACL checks on clinet only if the protocol is + * We support ACL checks on client only if the protocol is * 9P2000.L and access is V9FS_ACCESS_CLIENT. */ v9ses->flags &= ~V9FS_ACL_MASK; @@ -669,7 +668,7 @@ static int __init init_v9fs(void) int err; pr_info("Installing v9fs 9p2000 file system support\n"); - /* TODO: Setup list of registered trasnport modules */ + /* TODO: Setup list of registered transport modules */ err = v9fs_init_inode_cache(); if (err < 0) { From 86db0c32f16c5538ddb740f54669ace8f3a1f3d7 Mon Sep 17 00:00:00 2001 From: "Randall P. Embry" Date: Fri, 26 Sep 2025 18:27:30 +0900 Subject: [PATCH 2195/2711] 9p: fix /sys/fs/9p/caches overwriting itself MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit caches_show() overwrote its buffer on each iteration, so only the last cache tag was visible in sysfs output. Properly append with snprintf(buf + count, …). Signed-off-by: Randall P. Embry Message-ID: <20250926-v9fs_misc-v1-2-a8b3907fc04d@codewreck.org> Signed-off-by: Dominique Martinet --- fs/9p/v9fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 01e70a464b60..4d289c56578f 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -560,7 +560,7 @@ static ssize_t caches_show(struct kobject *kobj, spin_lock(&v9fs_sessionlist_lock); list_for_each_entry(v9ses, &v9fs_sessionlist, slist) { if (v9ses->cachetag) { - n = snprintf(buf, limit, "%s\n", v9ses->cachetag); + n = snprintf(buf + count, limit, "%s\n", v9ses->cachetag); if (n < 0) { count = n; break; From 528f218b31aac4bbfc58914d43766a22ab545d48 Mon Sep 17 00:00:00 2001 From: "Randall P. Embry" Date: Fri, 26 Sep 2025 18:27:31 +0900 Subject: [PATCH 2196/2711] 9p: sysfs_init: don't hardcode error to ENOMEM v9fs_sysfs_init() always returned -ENOMEM on failure; return the actual sysfs_create_group() error instead. Signed-off-by: Randall P. Embry Message-ID: <20250926-v9fs_misc-v1-3-a8b3907fc04d@codewreck.org> Signed-off-by: Dominique Martinet --- fs/9p/v9fs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 4d289c56578f..a020a8f00a1a 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -596,13 +596,16 @@ static const struct attribute_group v9fs_attr_group = { static int __init v9fs_sysfs_init(void) { + int ret; + v9fs_kobj = kobject_create_and_add("9p", fs_kobj); if (!v9fs_kobj) return -ENOMEM; - if (sysfs_create_group(v9fs_kobj, &v9fs_attr_group)) { + ret = sysfs_create_group(v9fs_kobj, &v9fs_attr_group); + if (ret) { kobject_put(v9fs_kobj); - return -ENOMEM; + return ret; } return 0; From eed0e3d305530066b4fc5370107cff8ef1a0d229 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 9 Aug 2025 10:19:39 -0700 Subject: [PATCH 2197/2711] KEYS: trusted_tpm1: Compare HMAC values in constant time To prevent timing attacks, HMAC value comparison needs to be constant time. Replace the memcmp() with the correct function, crypto_memneq(). [For the Fixes commit I used the commit that introduced the memcmp(). It predates the introduction of crypto_memneq(), but it was still a bug at the time even though a helper function didn't exist yet.] Fixes: d00a1c72f7f4 ("keys: add new trusted key-type") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- security/keys/trusted-keys/trusted_tpm1.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c index 89c9798d1800..e73f2c6c817a 100644 --- a/security/keys/trusted-keys/trusted_tpm1.c +++ b/security/keys/trusted-keys/trusted_tpm1.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -241,7 +242,7 @@ int TSS_checkhmac1(unsigned char *buffer, if (ret < 0) goto out; - if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE)) + if (crypto_memneq(testhmac, authdata, SHA1_DIGEST_SIZE)) ret = -EINVAL; out: kfree_sensitive(sdesc); @@ -334,7 +335,7 @@ static int TSS_checkhmac2(unsigned char *buffer, TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0); if (ret < 0) goto out; - if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) { + if (crypto_memneq(testhmac1, authdata1, SHA1_DIGEST_SIZE)) { ret = -EINVAL; goto out; } @@ -343,7 +344,7 @@ static int TSS_checkhmac2(unsigned char *buffer, TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0); if (ret < 0) goto out; - if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE)) + if (crypto_memneq(testhmac2, authdata2, SHA1_DIGEST_SIZE)) ret = -EINVAL; out: kfree_sensitive(sdesc); From 366284cfbc8ff4110c00fc23285449f53df739a7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 9 Aug 2025 10:19:40 -0700 Subject: [PATCH 2198/2711] KEYS: trusted_tpm1: Use SHA-1 library instead of crypto_shash Use the SHA-1 and HMAC-SHA1 library functions instead of crypto_shash. This is simpler and faster. Replace the selection of CRYPTO, CRYPTO_HMAC, and CRYPTO_SHA1 with CRYPTO_LIB_SHA1 and CRYPTO_LIB_UTILS. The latter is needed for crypto_memneq() which was previously being pulled in via CRYPTO. Signed-off-by: Eric Biggers Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- security/keys/trusted-keys/Kconfig | 5 +- security/keys/trusted-keys/trusted_tpm1.c | 221 ++++------------------ 2 files changed, 36 insertions(+), 190 deletions(-) diff --git a/security/keys/trusted-keys/Kconfig b/security/keys/trusted-keys/Kconfig index 1fb8aa001995..204a68c1429d 100644 --- a/security/keys/trusted-keys/Kconfig +++ b/security/keys/trusted-keys/Kconfig @@ -5,10 +5,9 @@ config TRUSTED_KEYS_TPM bool "TPM-based trusted keys" depends on TCG_TPM >= TRUSTED_KEYS default y - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_SHA1 select CRYPTO_HASH_INFO + select CRYPTO_LIB_SHA1 + select CRYPTO_LIB_UTILS select ASN1_ENCODER select OID_REGISTRY select ASN1 diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c index e73f2c6c817a..126437459a74 100644 --- a/security/keys/trusted-keys/trusted_tpm1.c +++ b/security/keys/trusted-keys/trusted_tpm1.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -15,78 +16,24 @@ #include #include #include -#include -#include -#include #include #include #include -static const char hmac_alg[] = "hmac(sha1)"; -static const char hash_alg[] = "sha1"; static struct tpm_chip *chip; static struct tpm_digest *digests; -struct sdesc { - struct shash_desc shash; - char ctx[]; -}; - -static struct crypto_shash *hashalg; -static struct crypto_shash *hmacalg; - -static struct sdesc *init_sdesc(struct crypto_shash *alg) -{ - struct sdesc *sdesc; - int size; - - size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); - sdesc = kmalloc(size, GFP_KERNEL); - if (!sdesc) - return ERR_PTR(-ENOMEM); - sdesc->shash.tfm = alg; - return sdesc; -} - -static int TSS_sha1(const unsigned char *data, unsigned int datalen, - unsigned char *digest) -{ - struct sdesc *sdesc; - int ret; - - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - - ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest); - kfree_sensitive(sdesc); - return ret; -} - static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, unsigned int keylen, ...) { - struct sdesc *sdesc; + struct hmac_sha1_ctx hmac_ctx; va_list argp; unsigned int dlen; unsigned char *data; - int ret; + int ret = 0; - sdesc = init_sdesc(hmacalg); - if (IS_ERR(sdesc)) { - pr_info("can't alloc %s\n", hmac_alg); - return PTR_ERR(sdesc); - } - - ret = crypto_shash_setkey(hmacalg, key, keylen); - if (ret < 0) - goto out; - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; + hmac_sha1_init_usingrawkey(&hmac_ctx, key, keylen); va_start(argp, keylen); for (;;) { @@ -98,15 +45,11 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, ret = -EINVAL; break; } - ret = crypto_shash_update(&sdesc->shash, data, dlen); - if (ret < 0) - break; + hmac_sha1_update(&hmac_ctx, data, dlen); } va_end(argp); if (!ret) - ret = crypto_shash_final(&sdesc->shash, digest); -out: - kfree_sensitive(sdesc); + hmac_sha1_final(&hmac_ctx, digest); return ret; } @@ -118,26 +61,18 @@ int TSS_authhmac(unsigned char *digest, const unsigned char *key, unsigned char *h2, unsigned int h3, ...) { unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; + struct sha1_ctx sha_ctx; unsigned int dlen; unsigned char *data; unsigned char c; - int ret; + int ret = 0; va_list argp; if (!chip) return -ENODEV; - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - c = !!h3; - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; + sha1_init(&sha_ctx); va_start(argp, h3); for (;;) { dlen = va_arg(argp, unsigned int); @@ -148,19 +83,15 @@ int TSS_authhmac(unsigned char *digest, const unsigned char *key, ret = -EINVAL; break; } - ret = crypto_shash_update(&sdesc->shash, data, dlen); - if (ret < 0) - break; + sha1_update(&sha_ctx, data, dlen); } va_end(argp); if (!ret) - ret = crypto_shash_final(&sdesc->shash, paramdigest); + sha1_final(&sha_ctx, paramdigest); if (!ret) ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE, paramdigest, TPM_NONCE_SIZE, h1, TPM_NONCE_SIZE, h2, 1, &c, 0, 0); -out: - kfree_sensitive(sdesc); return ret; } EXPORT_SYMBOL_GPL(TSS_authhmac); @@ -183,7 +114,7 @@ int TSS_checkhmac1(unsigned char *buffer, unsigned char *authdata; unsigned char testhmac[SHA1_DIGEST_SIZE]; unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; + struct sha1_ctx sha_ctx; unsigned int dlen; unsigned int dpos; va_list argp; @@ -204,49 +135,29 @@ int TSS_checkhmac1(unsigned char *buffer, continueflag = authdata - 1; enonce = continueflag - TPM_NONCE_SIZE; - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, - sizeof result); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, - sizeof ordinal); - if (ret < 0) - goto out; + sha1_init(&sha_ctx); + sha1_update(&sha_ctx, (const u8 *)&result, sizeof(result)); + sha1_update(&sha_ctx, (const u8 *)&ordinal, sizeof(ordinal)); va_start(argp, keylen); for (;;) { dlen = va_arg(argp, unsigned int); if (dlen == 0) break; dpos = va_arg(argp, unsigned int); - ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); - if (ret < 0) - break; + sha1_update(&sha_ctx, buffer + dpos, dlen); } va_end(argp); - if (!ret) - ret = crypto_shash_final(&sdesc->shash, paramdigest); - if (ret < 0) - goto out; + sha1_final(&sha_ctx, paramdigest); ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest, TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce, 1, continueflag, 0, 0); if (ret < 0) - goto out; + return ret; if (crypto_memneq(testhmac, authdata, SHA1_DIGEST_SIZE)) - ret = -EINVAL; -out: - kfree_sensitive(sdesc); - return ret; + return -EINVAL; + return 0; } EXPORT_SYMBOL_GPL(TSS_checkhmac1); @@ -274,7 +185,7 @@ static int TSS_checkhmac2(unsigned char *buffer, unsigned char testhmac1[SHA1_DIGEST_SIZE]; unsigned char testhmac2[SHA1_DIGEST_SIZE]; unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; + struct sha1_ctx sha_ctx; unsigned int dlen; unsigned int dpos; va_list argp; @@ -297,22 +208,9 @@ static int TSS_checkhmac2(unsigned char *buffer, enonce1 = continueflag1 - TPM_NONCE_SIZE; enonce2 = continueflag2 - TPM_NONCE_SIZE; - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, - sizeof result); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, - sizeof ordinal); - if (ret < 0) - goto out; + sha1_init(&sha_ctx); + sha1_update(&sha_ctx, (const u8 *)&result, sizeof(result)); + sha1_update(&sha_ctx, (const u8 *)&ordinal, sizeof(ordinal)); va_start(argp, keylen2); for (;;) { @@ -320,35 +218,26 @@ static int TSS_checkhmac2(unsigned char *buffer, if (dlen == 0) break; dpos = va_arg(argp, unsigned int); - ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); - if (ret < 0) - break; + sha1_update(&sha_ctx, buffer + dpos, dlen); } va_end(argp); - if (!ret) - ret = crypto_shash_final(&sdesc->shash, paramdigest); - if (ret < 0) - goto out; + sha1_final(&sha_ctx, paramdigest); ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE, paramdigest, TPM_NONCE_SIZE, enonce1, TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0); if (ret < 0) - goto out; - if (crypto_memneq(testhmac1, authdata1, SHA1_DIGEST_SIZE)) { - ret = -EINVAL; - goto out; - } + return ret; + if (crypto_memneq(testhmac1, authdata1, SHA1_DIGEST_SIZE)) + return -EINVAL; ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE, paramdigest, TPM_NONCE_SIZE, enonce2, TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0); if (ret < 0) - goto out; + return ret; if (crypto_memneq(testhmac2, authdata2, SHA1_DIGEST_SIZE)) - ret = -EINVAL; -out: - kfree_sensitive(sdesc); - return ret; + return -EINVAL; + return 0; } /* @@ -499,9 +388,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, /* calculate encrypted authorization value */ memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE); memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE); - ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); - if (ret < 0) - goto out; + sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE); if (ret < 0) @@ -990,40 +877,6 @@ static int trusted_tpm_get_random(unsigned char *key, size_t key_len) return tpm_get_random(chip, key, key_len); } -static void trusted_shash_release(void) -{ - if (hashalg) - crypto_free_shash(hashalg); - if (hmacalg) - crypto_free_shash(hmacalg); -} - -static int __init trusted_shash_alloc(void) -{ - int ret; - - hmacalg = crypto_alloc_shash(hmac_alg, 0, 0); - if (IS_ERR(hmacalg)) { - pr_info("could not allocate crypto %s\n", - hmac_alg); - return PTR_ERR(hmacalg); - } - - hashalg = crypto_alloc_shash(hash_alg, 0, 0); - if (IS_ERR(hashalg)) { - pr_info("could not allocate crypto %s\n", - hash_alg); - ret = PTR_ERR(hashalg); - goto hashalg_fail; - } - - return 0; - -hashalg_fail: - crypto_free_shash(hmacalg); - return ret; -} - static int __init init_digests(void) { int i; @@ -1050,15 +903,10 @@ static int __init trusted_tpm_init(void) ret = init_digests(); if (ret < 0) goto err_put; - ret = trusted_shash_alloc(); - if (ret < 0) - goto err_free; ret = register_key_type(&key_type_trusted); if (ret < 0) - goto err_release; + goto err_free; return 0; -err_release: - trusted_shash_release(); err_free: kfree(digests); err_put: @@ -1071,7 +919,6 @@ static void trusted_tpm_exit(void) if (chip) { put_device(&chip->dev); kfree(digests); - trusted_shash_release(); unregister_key_type(&key_type_trusted); } } From 720a485d12c590750f40f4ffbe41e36725f43f3d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 9 Aug 2025 10:19:41 -0700 Subject: [PATCH 2199/2711] KEYS: trusted_tpm1: Move private functionality out of public header Move functionality used only by trusted_tpm1.c out of the public header . Specifically, change the exported functions into static functions, since they are not used outside trusted_tpm1.c, and move various other definitions and inline functions to trusted_tpm1.c. Signed-off-by: Eric Biggers Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- include/keys/trusted_tpm.h | 79 ---------------------- security/keys/trusted-keys/trusted_tpm1.c | 80 ++++++++++++++++++++--- 2 files changed, 72 insertions(+), 87 deletions(-) diff --git a/include/keys/trusted_tpm.h b/include/keys/trusted_tpm.h index a088b33fd0e3..0fadc6a4f166 100644 --- a/include/keys/trusted_tpm.h +++ b/include/keys/trusted_tpm.h @@ -5,41 +5,8 @@ #include #include -/* implementation specific TPM constants */ -#define TPM_SIZE_OFFSET 2 -#define TPM_RETURN_OFFSET 6 -#define TPM_DATA_OFFSET 10 - -#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset])) -#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) -#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) - extern struct trusted_key_ops trusted_key_tpm_ops; -struct osapsess { - uint32_t handle; - unsigned char secret[SHA1_DIGEST_SIZE]; - unsigned char enonce[TPM_NONCE_SIZE]; -}; - -/* discrete values, but have to store in uint16_t for TPM use */ -enum { - SEAL_keytype = 1, - SRK_keytype = 4 -}; - -int TSS_authhmac(unsigned char *digest, const unsigned char *key, - unsigned int keylen, unsigned char *h1, - unsigned char *h2, unsigned int h3, ...); -int TSS_checkhmac1(unsigned char *buffer, - const uint32_t command, - const unsigned char *ononce, - const unsigned char *key, - unsigned int keylen, ...); - -int trusted_tpm_send(unsigned char *cmd, size_t buflen); -int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce); - int tpm2_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options); @@ -47,50 +14,4 @@ int tpm2_unseal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options); -#define TPM_DEBUG 0 - -#if TPM_DEBUG -static inline void dump_options(struct trusted_key_options *o) -{ - pr_info("sealing key type %d\n", o->keytype); - pr_info("sealing key handle %0X\n", o->keyhandle); - pr_info("pcrlock %d\n", o->pcrlock); - pr_info("pcrinfo %d\n", o->pcrinfo_len); - print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE, - 16, 1, o->pcrinfo, o->pcrinfo_len, 0); -} - -static inline void dump_sess(struct osapsess *s) -{ - print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE, - 16, 1, &s->handle, 4, 0); - pr_info("secret:\n"); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, - 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0); - pr_info("trusted-key: enonce:\n"); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, - 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0); -} - -static inline void dump_tpm_buf(unsigned char *buf) -{ - int len; - - pr_info("\ntpm buffer\n"); - len = LOAD32(buf, TPM_SIZE_OFFSET); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); -} -#else -static inline void dump_options(struct trusted_key_options *o) -{ -} - -static inline void dump_sess(struct osapsess *s) -{ -} - -static inline void dump_tpm_buf(unsigned char *buf) -{ -} -#endif #endif diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c index 126437459a74..636acb66a4f6 100644 --- a/security/keys/trusted-keys/trusted_tpm1.c +++ b/security/keys/trusted-keys/trusted_tpm1.c @@ -24,6 +24,74 @@ static struct tpm_chip *chip; static struct tpm_digest *digests; +/* implementation specific TPM constants */ +#define TPM_SIZE_OFFSET 2 +#define TPM_RETURN_OFFSET 6 +#define TPM_DATA_OFFSET 10 + +#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset])) +#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) +#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) + +struct osapsess { + uint32_t handle; + unsigned char secret[SHA1_DIGEST_SIZE]; + unsigned char enonce[TPM_NONCE_SIZE]; +}; + +/* discrete values, but have to store in uint16_t for TPM use */ +enum { + SEAL_keytype = 1, + SRK_keytype = 4 +}; + +#define TPM_DEBUG 0 + +#if TPM_DEBUG +static inline void dump_options(struct trusted_key_options *o) +{ + pr_info("sealing key type %d\n", o->keytype); + pr_info("sealing key handle %0X\n", o->keyhandle); + pr_info("pcrlock %d\n", o->pcrlock); + pr_info("pcrinfo %d\n", o->pcrinfo_len); + print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE, + 16, 1, o->pcrinfo, o->pcrinfo_len, 0); +} + +static inline void dump_sess(struct osapsess *s) +{ + print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE, + 16, 1, &s->handle, 4, 0); + pr_info("secret:\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, + 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0); + pr_info("trusted-key: enonce:\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, + 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0); +} + +static inline void dump_tpm_buf(unsigned char *buf) +{ + int len; + + pr_info("\ntpm buffer\n"); + len = LOAD32(buf, TPM_SIZE_OFFSET); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); +} +#else +static inline void dump_options(struct trusted_key_options *o) +{ +} + +static inline void dump_sess(struct osapsess *s) +{ +} + +static inline void dump_tpm_buf(unsigned char *buf) +{ +} +#endif + static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, unsigned int keylen, ...) { @@ -56,7 +124,7 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, /* * calculate authorization info fields to send to TPM */ -int TSS_authhmac(unsigned char *digest, const unsigned char *key, +static int TSS_authhmac(unsigned char *digest, const unsigned char *key, unsigned int keylen, unsigned char *h1, unsigned char *h2, unsigned int h3, ...) { @@ -94,12 +162,11 @@ int TSS_authhmac(unsigned char *digest, const unsigned char *key, TPM_NONCE_SIZE, h2, 1, &c, 0, 0); return ret; } -EXPORT_SYMBOL_GPL(TSS_authhmac); /* * verify the AUTH1_COMMAND (Seal) result from TPM */ -int TSS_checkhmac1(unsigned char *buffer, +static int TSS_checkhmac1(unsigned char *buffer, const uint32_t command, const unsigned char *ononce, const unsigned char *key, @@ -159,7 +226,6 @@ int TSS_checkhmac1(unsigned char *buffer, return -EINVAL; return 0; } -EXPORT_SYMBOL_GPL(TSS_checkhmac1); /* * verify the AUTH2_COMMAND (unseal) result from TPM @@ -244,7 +310,7 @@ static int TSS_checkhmac2(unsigned char *buffer, * For key specific tpm requests, we will generate and send our * own TPM command packets using the drivers send function. */ -int trusted_tpm_send(unsigned char *cmd, size_t buflen) +static int trusted_tpm_send(unsigned char *cmd, size_t buflen) { struct tpm_buf buf; int rc; @@ -270,7 +336,6 @@ int trusted_tpm_send(unsigned char *cmd, size_t buflen) tpm_put_ops(chip); return rc; } -EXPORT_SYMBOL_GPL(trusted_tpm_send); /* * Lock a trusted key, by extending a selected PCR. @@ -324,7 +389,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, /* * Create an object independent authorisation protocol (oiap) session */ -int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) +static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) { int ret; @@ -341,7 +406,6 @@ int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) TPM_NONCE_SIZE); return 0; } -EXPORT_SYMBOL_GPL(oiap); struct tpm_digests { unsigned char encauth[SHA1_DIGEST_SIZE]; From 5851afffe2ab323a53e184ba5a35fddf268f096b Mon Sep 17 00:00:00 2001 From: Fan Wu Date: Mon, 15 Sep 2025 21:15:50 +0000 Subject: [PATCH 2200/2711] KEYS: X.509: Fix Basic Constraints CA flag parsing Fix the X.509 Basic Constraints CA flag parsing to correctly handle the ASN.1 DER encoded structure. The parser was incorrectly treating the length field as the boolean value. Per RFC 5280 section 4.1, X.509 certificates must use ASN.1 DER encoding. According to ITU-T X.690, a DER-encoded BOOLEAN is represented as: Tag (0x01), Length (0x01), Value (0x00 for FALSE, 0xFF for TRUE) The basicConstraints extension with CA:TRUE is encoded as: SEQUENCE (0x30) | Length | BOOLEAN (0x01) | Length (0x01) | Value (0xFF) ^-- v[2] ^-- v[3] ^-- v[4] The parser was checking v[3] (the length field, always 0x01) instead of v[4] (the actual boolean value, 0xFF for TRUE in DER encoding). Also handle the case where the extension is an empty SEQUENCE (30 00), which is valid for CA:FALSE when the default value is omitted as required by DER encoding rules (X.690 section 11.5). Per ITU-T X.690-0207: - Section 11.5: Default values must be omitted in DER - Section 11.1: DER requires TRUE to be encoded as 0xFF Link: https://datatracker.ietf.org/doc/html/rfc5280 Link: https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf Fixes: 30eae2b037af ("KEYS: X.509: Parse Basic Constraints for CA") Signed-off-by: Fan Wu Reviewed-by: Lukas Wunner Signed-off-by: Herbert Xu --- crypto/asymmetric_keys/x509_cert_parser.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 2ffe4ae90bea..8df3fa60a44f 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -610,11 +610,14 @@ int x509_process_extension(void *context, size_t hdrlen, /* * Get hold of the basicConstraints * v[1] is the encoding size - * (Expect 0x2 or greater, making it 1 or more bytes) + * (Expect 0x00 for empty SEQUENCE with CA:FALSE, or + * 0x03 or greater for non-empty SEQUENCE) * v[2] is the encoding type * (Expect an ASN1_BOOL for the CA) - * v[3] is the contents of the ASN1_BOOL - * (Expect 1 if the CA is TRUE) + * v[3] is the length of the ASN1_BOOL + * (Expect 1 for a single byte boolean) + * v[4] is the contents of the ASN1_BOOL + * (Expect 0xFF if the CA is TRUE) * vlen should match the entire extension size */ if (v[0] != (ASN1_CONS_BIT | ASN1_SEQ)) @@ -623,8 +626,13 @@ int x509_process_extension(void *context, size_t hdrlen, return -EBADMSG; if (v[1] != vlen - 2) return -EBADMSG; - if (vlen >= 4 && v[1] != 0 && v[2] == ASN1_BOOL && v[3] == 1) + /* Empty SEQUENCE means CA:FALSE (default value omitted per DER) */ + if (v[1] == 0) + return 0; + if (vlen >= 5 && v[2] == ASN1_BOOL && v[3] == 1 && v[4] == 0xFF) ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_CA; + else + return -EBADMSG; return 0; } From 612b1dfeb414dfa780a6316014ceddf9a74ff5c0 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 19 Sep 2025 08:20:02 -0500 Subject: [PATCH 2201/2711] hwrng: ks-sa - fix division by zero in ks_sa_rng_init Fix division by zero in ks_sa_rng_init caused by missing clock pointer initialization. The clk_get_rate() call is performed on an uninitialized clk pointer, resulting in division by zero when calculating delay values. Add clock initialization code before using the clock. Fixes: 6d01d8511dce ("hwrng: ks-sa - Add minimum sleep time before ready-polling") Signed-off-by: Nishanth Menon drivers/char/hw_random/ks-sa-rng.c | 7 +++++++ 1 file changed, 7 insertions(+) Reviewed-by: Alexander Sverdlin Signed-off-by: Herbert Xu --- drivers/char/hw_random/ks-sa-rng.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/hw_random/ks-sa-rng.c b/drivers/char/hw_random/ks-sa-rng.c index d8fd8a354482..9e408144a10c 100644 --- a/drivers/char/hw_random/ks-sa-rng.c +++ b/drivers/char/hw_random/ks-sa-rng.c @@ -231,6 +231,10 @@ static int ks_sa_rng_probe(struct platform_device *pdev) if (IS_ERR(ks_sa_rng->regmap_cfg)) return dev_err_probe(dev, -EINVAL, "syscon_node_to_regmap failed\n"); + ks_sa_rng->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(ks_sa_rng->clk)) + return dev_err_probe(dev, PTR_ERR(ks_sa_rng->clk), "Failed to get clock\n"); + pm_runtime_enable(dev); ret = pm_runtime_resume_and_get(dev); if (ret < 0) { From 298ced6c3b3c116987554364998e9d8cb94e0126 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Sat, 20 Sep 2025 07:16:51 +0700 Subject: [PATCH 2202/2711] crypto: doc - Add explicit title heading to API docs Documentation for crypto programming interfaces lack explicit title. As such, all its sections become entries in the toctree index. Add the title heading to tidy up toctree. Signed-off-by: Bagas Sanjaya Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Herbert Xu --- Documentation/crypto/api-aead.rst | 3 +++ Documentation/crypto/api-akcipher.rst | 3 +++ Documentation/crypto/api-digest.rst | 3 +++ Documentation/crypto/api-kpp.rst | 3 +++ Documentation/crypto/api-rng.rst | 3 +++ Documentation/crypto/api-sig.rst | 3 +++ Documentation/crypto/api-skcipher.rst | 3 +++ 7 files changed, 21 insertions(+) diff --git a/Documentation/crypto/api-aead.rst b/Documentation/crypto/api-aead.rst index d15256f1ae36..78d073319f96 100644 --- a/Documentation/crypto/api-aead.rst +++ b/Documentation/crypto/api-aead.rst @@ -1,3 +1,6 @@ +Authenticated Encryption With Associated Data (AEAD) +==================================================== + Authenticated Encryption With Associated Data (AEAD) Algorithm Definitions -------------------------------------------------------------------------- diff --git a/Documentation/crypto/api-akcipher.rst b/Documentation/crypto/api-akcipher.rst index ca1ecdd4a7d3..a31f5aef7667 100644 --- a/Documentation/crypto/api-akcipher.rst +++ b/Documentation/crypto/api-akcipher.rst @@ -1,3 +1,6 @@ +Asymmetric Cipher +================= + Asymmetric Cipher Algorithm Definitions --------------------------------------- diff --git a/Documentation/crypto/api-digest.rst b/Documentation/crypto/api-digest.rst index 7a1e670d6ce1..02a2bcc26a64 100644 --- a/Documentation/crypto/api-digest.rst +++ b/Documentation/crypto/api-digest.rst @@ -1,3 +1,6 @@ +Message Digest +============== + Message Digest Algorithm Definitions ------------------------------------ diff --git a/Documentation/crypto/api-kpp.rst b/Documentation/crypto/api-kpp.rst index 7d86ab906bdf..5794e2d10c95 100644 --- a/Documentation/crypto/api-kpp.rst +++ b/Documentation/crypto/api-kpp.rst @@ -1,3 +1,6 @@ +Key-agreement Protocol Primitives (KPP) +======================================= + Key-agreement Protocol Primitives (KPP) Cipher Algorithm Definitions -------------------------------------------------------------------- diff --git a/Documentation/crypto/api-rng.rst b/Documentation/crypto/api-rng.rst index 10ba7436cee4..23a94c0b272e 100644 --- a/Documentation/crypto/api-rng.rst +++ b/Documentation/crypto/api-rng.rst @@ -1,3 +1,6 @@ +Random Number Generator (RNG) +============================= + Random Number Algorithm Definitions ----------------------------------- diff --git a/Documentation/crypto/api-sig.rst b/Documentation/crypto/api-sig.rst index aaec18e26d54..4d8aba8aee8e 100644 --- a/Documentation/crypto/api-sig.rst +++ b/Documentation/crypto/api-sig.rst @@ -1,3 +1,6 @@ +Asymmetric Signature +==================== + Asymmetric Signature Algorithm Definitions ------------------------------------------ diff --git a/Documentation/crypto/api-skcipher.rst b/Documentation/crypto/api-skcipher.rst index 04d6cc5357c8..4b7c8160790a 100644 --- a/Documentation/crypto/api-skcipher.rst +++ b/Documentation/crypto/api-skcipher.rst @@ -1,3 +1,6 @@ +Symmetric Key Cipher +==================== + Block Cipher Algorithm Definitions ---------------------------------- From 166c83f7789ed02dc1f25bc7bed4a1beb25343aa Mon Sep 17 00:00:00 2001 From: Kael D'Alcamo Date: Sun, 21 Sep 2025 18:11:34 +0200 Subject: [PATCH 2203/2711] dt-bindings: rng: hisi-rng: convert to DT schema Convert the Devicetree binding documentation for hisilicon,hip04-rng and hisilicon,hip05-rng from plain text to YAML. Signed-off-by: Kael D'Alcamo Reviewed-by: Rob Herring (Arm) Signed-off-by: Herbert Xu --- .../devicetree/bindings/rng/hisi-rng.txt | 12 ------- .../devicetree/bindings/rng/hisi-rng.yaml | 32 +++++++++++++++++++ 2 files changed, 32 insertions(+), 12 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rng/hisi-rng.txt create mode 100644 Documentation/devicetree/bindings/rng/hisi-rng.yaml diff --git a/Documentation/devicetree/bindings/rng/hisi-rng.txt b/Documentation/devicetree/bindings/rng/hisi-rng.txt deleted file mode 100644 index d04d55a6c2f5..000000000000 --- a/Documentation/devicetree/bindings/rng/hisi-rng.txt +++ /dev/null @@ -1,12 +0,0 @@ -Hisilicon Random Number Generator - -Required properties: -- compatible : Should be "hisilicon,hip04-rng" or "hisilicon,hip05-rng" -- reg : Offset and length of the register set of this block - -Example: - -rng@d1010000 { - compatible = "hisilicon,hip05-rng"; - reg = <0xd1010000 0x100>; -}; diff --git a/Documentation/devicetree/bindings/rng/hisi-rng.yaml b/Documentation/devicetree/bindings/rng/hisi-rng.yaml new file mode 100644 index 000000000000..5406b2596f42 --- /dev/null +++ b/Documentation/devicetree/bindings/rng/hisi-rng.yaml @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rng/hisi-rng.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Hisilicon Random Number Generator + +maintainers: + - Kefeng Wang + +properties: + compatible: + enum: + - hisilicon,hip04-rng + - hisilicon,hip05-rng + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + rng@d1010000 { + compatible = "hisilicon,hip05-rng"; + reg = <0xd1010000 0x100>; + }; From 9fbad55d6f9db98ab9f1d48ac5e5f8f72fbac0cc Mon Sep 17 00:00:00 2001 From: Griffin Kroah-Hartman Date: Sat, 27 Sep 2025 21:11:55 -0700 Subject: [PATCH 2204/2711] dt-bindings: input: Add Awinic AW86927 Add bindings for the Awinic AW86927 haptic chip which can be found in smartphones. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Griffin Kroah-Hartman Link: https://lore.kernel.org/r/20250925-aw86927-v3-1-1fc6265b42de@fairphone.com Signed-off-by: Dmitry Torokhov --- .../bindings/input/awinic,aw86927.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/awinic,aw86927.yaml diff --git a/Documentation/devicetree/bindings/input/awinic,aw86927.yaml b/Documentation/devicetree/bindings/input/awinic,aw86927.yaml new file mode 100644 index 000000000000..b7252916bd72 --- /dev/null +++ b/Documentation/devicetree/bindings/input/awinic,aw86927.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/awinic,aw86927.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Awinic AW86927 LRA Haptic IC + +maintainers: + - Griffin Kroah-Hartman + +properties: + compatible: + const: awinic,aw86927 + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - reset-gpios + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + vibrator@5a { + compatible = "awinic,aw86927"; + reg = <0x5a>; + interrupts-extended = <&tlmm 101 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&tlmm 100 GPIO_ACTIVE_LOW>; + }; + }; From 52e06d564ce6a5f03177922b2fa5667781d5ff83 Mon Sep 17 00:00:00 2001 From: Griffin Kroah-Hartman Date: Sat, 27 Sep 2025 21:14:45 -0700 Subject: [PATCH 2205/2711] Input: aw86927 - add driver for Awinic AW86927 Add support for the I2C-connected Awinic AW86927 LRA haptic driver. This driver includes a hardcoded sine waveform to be uploaded to the AW86927's SRAM for haptic playback. This driver does not currently support all the capabilities of the AW86927, such as F0 calibration, RTP mode, and CONT mode. Signed-off-by: Griffin Kroah-Hartman Link: https://lore.kernel.org/r/20250925-aw86927-v3-2-1fc6265b42de@fairphone.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 11 + drivers/input/misc/Makefile | 1 + drivers/input/misc/aw86927.c | 847 +++++++++++++++++++++++++++++++++++ 3 files changed, 859 insertions(+) create mode 100644 drivers/input/misc/aw86927.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 0e6b49fb54bc..cc2558630797 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -126,6 +126,17 @@ config INPUT_ATMEL_CAPTOUCH To compile this driver as a module, choose M here: the module will be called atmel_captouch. +config INPUT_AW86927 + tristate "Awinic AW86927 Haptic Driver Support" + depends on I2C && INPUT + select INPUT_FF_MEMLESS + select REGMAP_I2C + help + Say Y here if you have an Awinic AW86927 haptic chip. + + To compile this driver as a module, choose M here: the + module will be called aw86927. + config INPUT_BBNSM_PWRKEY tristate "NXP BBNSM Power Key Driver" depends on ARCH_MXC || COMPILE_TEST diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index ae857c24f48e..f5ebfa9d9983 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_INPUT_ATC260X_ONKEY) += atc260x-onkey.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH) += atmel_captouch.o +obj-$(CONFIG_INPUT_AW86927) += aw86927.o obj-$(CONFIG_INPUT_BBNSM_PWRKEY) += nxp-bbnsm-pwrkey.o obj-$(CONFIG_INPUT_BMA150) += bma150.o obj-$(CONFIG_INPUT_CM109) += cm109.o diff --git a/drivers/input/misc/aw86927.c b/drivers/input/misc/aw86927.c new file mode 100644 index 000000000000..a0c88a7e1e1c --- /dev/null +++ b/drivers/input/misc/aw86927.c @@ -0,0 +1,847 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 Griffin Kroah-Hartman + * + * Partially based on vendor driver: + * Copyright (c) 2021 AWINIC Technology CO., LTD + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AW86927_RSTCFG_REG 0x00 +#define AW86927_RSTCFG_SOFTRST 0xaa + +#define AW86927_SYSINT_REG 0x02 +#define AW86927_SYSINT_BST_SCPI BIT(7) +#define AW86927_SYSINT_BST_OVPI BIT(6) +#define AW86927_SYSINT_UVLI BIT(5) +#define AW86927_SYSINT_FF_AEI BIT(4) +#define AW86927_SYSINT_FF_AFI BIT(3) +#define AW86927_SYSINT_OCDI BIT(2) +#define AW86927_SYSINT_OTI BIT(1) +#define AW86927_SYSINT_DONEI BIT(0) + +#define AW86927_SYSINTM_REG 0x03 +#define AW86927_SYSINTM_BST_OVPM BIT(6) +#define AW86927_SYSINTM_FF_AEM BIT(4) +#define AW86927_SYSINTM_FF_AFM BIT(3) +#define AW86927_SYSINTM_DONEM BIT(0) + +#define AW86927_PLAYCFG1_REG 0x06 +#define AW86927_PLAYCFG1_BST_MODE_MASK GENMASK(7, 7) +#define AW86927_PLAYCFG1_BST_MODE_BYPASS 0 +#define AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK GENMASK(6, 0) +#define AW86927_PLAYCFG1_BST_8500MV 0x50 + +#define AW86927_PLAYCFG2_REG 0x07 + +#define AW86927_PLAYCFG3_REG 0x08 +#define AW86927_PLAYCFG3_AUTO_BST_MASK GENMASK(4, 4) +#define AW86927_PLAYCFG3_AUTO_BST_ENABLE 1 +#define AW86927_PLAYCFG3_AUTO_BST_DISABLE 0 +#define AW86927_PLAYCFG3_PLAY_MODE_MASK GENMASK(1, 0) +#define AW86927_PLAYCFG3_PLAY_MODE_RAM 0 + +#define AW86927_PLAYCFG4_REG 0x09 +#define AW86927_PLAYCFG4_STOP BIT(1) +#define AW86927_PLAYCFG4_GO BIT(0) + +#define AW86927_WAVCFG1_REG 0x0a +#define AW86927_WAVCFG1_WAVSEQ1_MASK GENMASK(6, 0) + +#define AW86927_WAVCFG2_REG 0x0b +#define AW86927_WAVCFG2_WAVSEQ2_MASK GENMASK(6, 0) + +#define AW86927_WAVCFG9_REG 0x12 +#define AW86927_WAVCFG9_SEQ1LOOP_MASK GENMASK(7, 4) +#define AW86927_WAVCFG9_SEQ1LOOP_INFINITELY 0x0f + +#define AW86927_CONTCFG1_REG 0x18 +#define AW86927_CONTCFG1_BRK_BST_MD_MASK GENMASK(6, 6) + +#define AW86927_CONTCFG5_REG 0x1c +#define AW86927_CONTCFG5_BST_BRK_GAIN_MASK GENMASK(7, 4) +#define AW86927_CONTCFG5_BRK_GAIN_MASK GENMASK(3, 0) + +#define AW86927_CONTCFG10_REG 0x21 +#define AW86927_CONTCFG10_BRK_TIME_MASK GENMASK(7, 0) +#define AW86927_CONTCFG10_BRK_TIME_DEFAULT 8 + +#define AW86927_CONTCFG13_REG 0x24 +#define AW86927_CONTCFG13_TSET_MASK GENMASK(7, 4) +#define AW86927_CONTCFG13_BEME_SET_MASK GENMASK(3, 0) + +#define AW86927_BASEADDRH_REG 0x2d +#define AW86927_BASEADDRL_REG 0x2e + +#define AW86927_GLBRD5_REG 0x3f +#define AW86927_GLBRD5_STATE_MASK GENMASK(3, 0) +#define AW86927_GLBRD5_STATE_STANDBY 0 + +#define AW86927_RAMADDRH_REG 0x40 + +#define AW86927_RAMADDRL_REG 0x41 + +#define AW86927_RAMDATA_REG 0x42 + +#define AW86927_SYSCTRL3_REG 0x45 +#define AW86927_SYSCTRL3_STANDBY_MASK GENMASK(5, 5) +#define AW86927_SYSCTRL3_STANDBY_ON 1 +#define AW86927_SYSCTRL3_STANDBY_OFF 0 +#define AW86927_SYSCTRL3_EN_RAMINIT_MASK GENMASK(2, 2) +#define AW86927_SYSCTRL3_EN_RAMINIT_ON 1 +#define AW86927_SYSCTRL3_EN_RAMINIT_OFF 0 + +#define AW86927_SYSCTRL4_REG 0x46 +#define AW86927_SYSCTRL4_WAVDAT_MODE_MASK GENMASK(6, 5) +#define AW86927_SYSCTRL4_WAVDAT_24K 0 +#define AW86927_SYSCTRL4_INT_EDGE_MODE_MASK GENMASK(4, 4) +#define AW86927_SYSCTRL4_INT_EDGE_MODE_POS 0 +#define AW86927_SYSCTRL4_INT_MODE_MASK GENMASK(3, 3) +#define AW86927_SYSCTRL4_INT_MODE_EDGE 1 +#define AW86927_SYSCTRL4_GAIN_BYPASS_MASK GENMASK(0, 0) + +#define AW86927_PWMCFG1_REG 0x48 +#define AW86927_PWMCFG1_PRC_EN_MASK GENMASK(7, 7) +#define AW86927_PWMCFG1_PRC_DISABLE 0 + +#define AW86927_PWMCFG3_REG 0x4a +#define AW86927_PWMCFG3_PR_EN_MASK GENMASK(7, 7) +#define AW86927_PWMCFG3_PRCTIME_MASK GENMASK(6, 0) + +#define AW86927_PWMCFG4_REG 0x4b +#define AW86927_PWMCFG4_PRTIME_MASK GENMASK(7, 0) + +#define AW86927_VBATCTRL_REG 0x4c +#define AW86927_VBATCTRL_VBAT_MODE_MASK GENMASK(6, 6) +#define AW86927_VBATCTRL_VBAT_MODE_SW 0 + +#define AW86927_DETCFG1_REG 0x4d +#define AW86927_DETCFG1_DET_GO_MASK GENMASK(1, 0) +#define AW86927_DETCFG1_DET_GO_DET_SEQ0 1 +#define AW86927_DETCFG1_DET_GO_NA 0 + +#define AW86927_DETCFG2_REG 0x4e +#define AW86927_DETCFG2_DET_SEQ0_MASK GENMASK(6, 3) +#define AW86927_DETCFG2_DET_SEQ0_VBAT 0 +#define AW86927_DETCFG2_D2S_GAIN_MASK GENMASK(2, 0) +#define AW86927_DETCFG2_D2S_GAIN_10 4 + +#define AW86927_CHIPIDH_REG 0x57 +#define AW86927_CHIPIDL_REG 0x58 +#define AW86927_CHIPID 0x9270 + +#define AW86927_TMCFG_REG 0x5b +#define AW86927_TMCFG_UNLOCK 0x7d +#define AW86927_TMCFG_LOCK 0x00 + +#define AW86927_ANACFG11_REG 0x70 + +#define AW86927_ANACFG12_REG 0x71 +#define AW86927_ANACFG12_BST_SKIP_MASK GENMASK(7, 7) +#define AW86927_ANACFG12_BST_SKIP_SHUTDOWN 1 + +#define AW86927_ANACFG13_REG 0x72 +#define AW86927_ANACFG13_BST_PC_MASK GENMASK(7, 4) +#define AW86927_ANACFG13_BST_PEAKCUR_3P45A 6 + +#define AW86927_ANACFG15_REG 0x74 +#define AW86927_ANACFG15_BST_PEAK_MODE_MASK GENMASK(7, 7) +#define AW86927_ANACFG15_BST_PEAK_BACK 1 + +#define AW86927_ANACFG16_REG 0x75 +#define AW86927_ANACFG16_BST_SRC_MASK GENMASK(4, 4) +#define AW86927_ANACFG16_BST_SRC_3NS 0 + +/* default value of base addr */ +#define AW86927_RAM_BASE_ADDR 0x800 +#define AW86927_BASEADDRH_VAL 0x08 +#define AW86927_BASEADDRL_VAL 0x00 + +enum aw86927_work_mode { + AW86927_STANDBY_MODE, + AW86927_RAM_MODE, +}; + +struct aw86927_data { + struct work_struct play_work; + struct device *dev; + struct input_dev *input_dev; + struct i2c_client *client; + struct regmap *regmap; + struct gpio_desc *reset_gpio; + bool running; +}; + +static const struct regmap_config aw86927_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_NONE, + .max_register = 0x80, +}; + +/* + * Sine wave representing the magnitude of the drive to be used. + * Data is encoded in two's complement. + * round(84 * sin(x / 16.25)) + */ +static const u8 aw86927_waveform[] = { + 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x1a, 0x1f, 0x23, 0x28, 0x2d, 0x31, 0x35, + 0x39, 0x3d, 0x41, 0x44, 0x47, 0x4a, 0x4c, 0x4f, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x52, 0x51, 0x4f, 0x4d, 0x4a, 0x47, + 0x44, 0x41, 0x3d, 0x3a, 0x36, 0x31, 0x2d, 0x28, 0x24, 0x1f, 0x1a, 0x15, + 0x10, 0x0a, 0x05, 0x00, 0xfc, 0xf6, 0xf1, 0xec, 0xe7, 0xe2, 0xdd, 0xd8, + 0xd4, 0xcf, 0xcb, 0xc7, 0xc3, 0xbf, 0xbc, 0xb9, 0xb6, 0xb4, 0xb1, 0xb0, + 0xae, 0xad, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, 0xac, 0xae, 0xaf, 0xb1, + 0xb3, 0xb6, 0xb8, 0xbc, 0xbf, 0xc2, 0xc6, 0xca, 0xce, 0xd3, 0xd7, 0xdc, + 0xe1, 0xe6, 0xeb, 0xf0, 0xf5, 0xfb +}; + +struct aw86927_sram_waveform_header { + u8 version; + __be16 start_address; + __be16 end_address; +} __packed; + +static const struct aw86927_sram_waveform_header sram_waveform_header = { + .version = 0x01, + .start_address = cpu_to_be16(AW86927_RAM_BASE_ADDR + + sizeof(struct aw86927_sram_waveform_header)), + .end_address = cpu_to_be16(AW86927_RAM_BASE_ADDR + + sizeof(struct aw86927_sram_waveform_header) + + ARRAY_SIZE(aw86927_waveform) - 1), +}; + +static int aw86927_wait_enter_standby(struct aw86927_data *haptics) +{ + unsigned int reg_val; + int err; + + err = regmap_read_poll_timeout(haptics->regmap, AW86927_GLBRD5_REG, reg_val, + (FIELD_GET(AW86927_GLBRD5_STATE_MASK, reg_val) == + AW86927_GLBRD5_STATE_STANDBY), + 2500, 2500 * 100); + + if (err) { + dev_err(haptics->dev, "did not enter standby: %d\n", err); + return err; + } + return 0; +} + +static int aw86927_play_mode(struct aw86927_data *haptics, u8 play_mode) +{ + int err; + + switch (play_mode) { + case AW86927_STANDBY_MODE: + /* Briefly toggle standby, then toggle back to standby off */ + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL3_REG, + AW86927_SYSCTRL3_STANDBY_MASK, + FIELD_PREP(AW86927_SYSCTRL3_STANDBY_MASK, + AW86927_SYSCTRL3_STANDBY_ON)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL3_REG, + AW86927_SYSCTRL3_STANDBY_MASK, + FIELD_PREP(AW86927_SYSCTRL3_STANDBY_MASK, + AW86927_SYSCTRL3_STANDBY_OFF)); + if (err) + return err; + + break; + + case AW86927_RAM_MODE: + err = regmap_update_bits(haptics->regmap, + AW86927_PLAYCFG3_REG, + AW86927_PLAYCFG3_PLAY_MODE_MASK, + FIELD_PREP(AW86927_PLAYCFG3_PLAY_MODE_MASK, + AW86927_PLAYCFG3_PLAY_MODE_RAM)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_PLAYCFG1_REG, + AW86927_PLAYCFG1_BST_MODE_MASK, + FIELD_PREP(AW86927_PLAYCFG1_BST_MODE_MASK, + AW86927_PLAYCFG1_BST_MODE_BYPASS)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_VBATCTRL_REG, + AW86927_VBATCTRL_VBAT_MODE_MASK, + FIELD_PREP(AW86927_VBATCTRL_VBAT_MODE_MASK, + AW86927_VBATCTRL_VBAT_MODE_SW)); + if (err) + return err; + + break; + } + + return 0; +} + +static int aw86927_stop(struct aw86927_data *haptics) +{ + int err; + + err = regmap_write(haptics->regmap, AW86927_PLAYCFG4_REG, AW86927_PLAYCFG4_STOP); + if (err) { + dev_err(haptics->dev, "Failed to stop playback: %d\n", err); + return err; + } + + err = aw86927_wait_enter_standby(haptics); + if (err) { + dev_err(haptics->dev, "Failed to enter standby, trying to force it\n"); + err = aw86927_play_mode(haptics, AW86927_STANDBY_MODE); + if (err) + return err; + } + + return 0; +} + +static int aw86927_haptics_play(struct input_dev *dev, void *data, struct ff_effect *effect) +{ + struct aw86927_data *haptics = input_get_drvdata(dev); + int level; + + level = effect->u.rumble.strong_magnitude; + if (!level) + level = effect->u.rumble.weak_magnitude; + + /* If already running, don't restart playback */ + if (haptics->running && level) + return 0; + + haptics->running = level; + schedule_work(&haptics->play_work); + + return 0; +} + +static int aw86927_play_sine(struct aw86927_data *haptics) +{ + int err; + + err = aw86927_stop(haptics); + if (err) + return err; + + err = aw86927_play_mode(haptics, AW86927_RAM_MODE); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, AW86927_PLAYCFG3_REG, + AW86927_PLAYCFG3_AUTO_BST_MASK, + FIELD_PREP(AW86927_PLAYCFG3_AUTO_BST_MASK, + AW86927_PLAYCFG3_AUTO_BST_ENABLE)); + if (err) + return err; + + /* Set waveseq 1 to the first wave */ + err = regmap_update_bits(haptics->regmap, AW86927_WAVCFG1_REG, + AW86927_WAVCFG1_WAVSEQ1_MASK, + FIELD_PREP(AW86927_WAVCFG1_WAVSEQ1_MASK, 1)); + if (err) + return err; + + /* set wavseq 2 to zero */ + err = regmap_update_bits(haptics->regmap, AW86927_WAVCFG2_REG, + AW86927_WAVCFG2_WAVSEQ2_MASK, + FIELD_PREP(AW86927_WAVCFG2_WAVSEQ2_MASK, 0)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_WAVCFG9_REG, + AW86927_WAVCFG9_SEQ1LOOP_MASK, + FIELD_PREP(AW86927_WAVCFG9_SEQ1LOOP_MASK, + AW86927_WAVCFG9_SEQ1LOOP_INFINITELY)); + if (err) + return err; + + /* set gain to value lower than 0x80 to avoid distorted playback */ + err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, 0x7c); + if (err) + return err; + + /* Start playback */ + err = regmap_write(haptics->regmap, AW86927_PLAYCFG4_REG, AW86927_PLAYCFG4_GO); + if (err) + return err; + + return 0; +} + +static void aw86927_close(struct input_dev *input) +{ + struct aw86927_data *haptics = input_get_drvdata(input); + struct device *dev = &haptics->client->dev; + int err; + + cancel_work_sync(&haptics->play_work); + + err = aw86927_stop(haptics); + if (err) + dev_err(dev, "Failed to close the Driver: %d\n", err); +} + +static void aw86927_haptics_play_work(struct work_struct *work) +{ + struct aw86927_data *haptics = + container_of(work, struct aw86927_data, play_work); + struct device *dev = &haptics->client->dev; + int err; + + if (haptics->running) + err = aw86927_play_sine(haptics); + else + err = aw86927_stop(haptics); + + if (err) + dev_err(dev, "Failed to execute work command: %d\n", err); +} + +static void aw86927_hw_reset(struct aw86927_data *haptics) +{ + /* Assert reset */ + gpiod_set_value_cansleep(haptics->reset_gpio, 1); + /* Wait ~1ms */ + usleep_range(1000, 2000); + /* Deassert reset */ + gpiod_set_value_cansleep(haptics->reset_gpio, 0); + /* Wait ~8ms until I2C is accessible */ + usleep_range(8000, 8500); +} + +static int aw86927_haptic_init(struct aw86927_data *haptics) +{ + int err; + + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL4_REG, + AW86927_SYSCTRL4_WAVDAT_MODE_MASK, + FIELD_PREP(AW86927_SYSCTRL4_WAVDAT_MODE_MASK, + AW86927_SYSCTRL4_WAVDAT_24K)); + if (err) + return err; + + /* enable gain bypass */ + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL4_REG, + AW86927_SYSCTRL4_GAIN_BYPASS_MASK, + FIELD_PREP(AW86927_SYSCTRL4_GAIN_BYPASS_MASK, + 0x01)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_TMCFG_REG, AW86927_TMCFG_UNLOCK); + if (err) + return err; + + err = regmap_write(haptics->regmap, AW86927_ANACFG11_REG, 0x0f); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_ANACFG12_REG, + AW86927_ANACFG12_BST_SKIP_MASK, + FIELD_PREP(AW86927_ANACFG12_BST_SKIP_MASK, + AW86927_ANACFG12_BST_SKIP_SHUTDOWN)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_ANACFG15_REG, + AW86927_ANACFG15_BST_PEAK_MODE_MASK, + FIELD_PREP(AW86927_ANACFG15_BST_PEAK_MODE_MASK, + AW86927_ANACFG15_BST_PEAK_BACK)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_ANACFG16_REG, + AW86927_ANACFG16_BST_SRC_MASK, + FIELD_PREP(AW86927_ANACFG16_BST_SRC_MASK, + AW86927_ANACFG16_BST_SRC_3NS)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_TMCFG_REG, AW86927_TMCFG_LOCK); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_CONTCFG1_REG, + AW86927_CONTCFG1_BRK_BST_MD_MASK, + FIELD_PREP(AW86927_CONTCFG1_BRK_BST_MD_MASK, 0x00)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_CONTCFG5_REG, + FIELD_PREP(AW86927_CONTCFG5_BST_BRK_GAIN_MASK, 0x05) | + FIELD_PREP(AW86927_CONTCFG5_BRK_GAIN_MASK, 0x08)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, AW86927_CONTCFG10_REG, + AW86927_CONTCFG10_BRK_TIME_MASK, + FIELD_PREP(AW86927_CONTCFG10_BRK_TIME_MASK, + AW86927_CONTCFG10_BRK_TIME_DEFAULT)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_CONTCFG13_REG, + FIELD_PREP(AW86927_CONTCFG13_TSET_MASK, 0x06) | + FIELD_PREP(AW86927_CONTCFG13_BEME_SET_MASK, 0x02)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_DETCFG2_REG, + AW86927_DETCFG2_D2S_GAIN_MASK, + FIELD_PREP(AW86927_DETCFG2_D2S_GAIN_MASK, + AW86927_DETCFG2_D2S_GAIN_10)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_PWMCFG1_REG, + AW86927_PWMCFG1_PRC_EN_MASK, + FIELD_PREP(AW86927_PWMCFG1_PRC_EN_MASK, + AW86927_PWMCFG1_PRC_DISABLE)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_PWMCFG3_REG, + FIELD_PREP(AW86927_PWMCFG3_PR_EN_MASK, 0x01) | + FIELD_PREP(AW86927_PWMCFG3_PRCTIME_MASK, 0x3f)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_PWMCFG4_REG, + AW86927_PWMCFG4_PRTIME_MASK, + FIELD_PREP(AW86927_PWMCFG4_PRTIME_MASK, 0x32)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_TMCFG_REG, AW86927_TMCFG_UNLOCK); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_ANACFG13_REG, + AW86927_ANACFG13_BST_PC_MASK, + FIELD_PREP(AW86927_ANACFG13_BST_PC_MASK, + AW86927_ANACFG13_BST_PEAKCUR_3P45A)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_TMCFG_REG, AW86927_TMCFG_LOCK); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_PLAYCFG1_REG, + AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK, + FIELD_PREP(AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK, + AW86927_PLAYCFG1_BST_8500MV)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_PLAYCFG3_REG, + AW86927_PLAYCFG3_AUTO_BST_MASK, + FIELD_PREP(AW86927_PLAYCFG3_AUTO_BST_MASK, + AW86927_PLAYCFG3_AUTO_BST_DISABLE)); + if (err) + return err; + + return 0; +} + +static int aw86927_ram_init(struct aw86927_data *haptics) +{ + int err; + + err = aw86927_wait_enter_standby(haptics); + if (err) + return err; + + /* Enable SRAM init */ + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL3_REG, + AW86927_SYSCTRL3_EN_RAMINIT_MASK, + FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK, + AW86927_SYSCTRL3_EN_RAMINIT_ON)); + + /* Set base address for the start of the SRAM waveforms */ + err = regmap_write(haptics->regmap, + AW86927_BASEADDRH_REG, AW86927_BASEADDRH_VAL); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_BASEADDRL_REG, AW86927_BASEADDRL_VAL); + if (err) + return err; + + /* Set start of SRAM, before the data is written it will be the same as the base */ + err = regmap_write(haptics->regmap, + AW86927_RAMADDRH_REG, AW86927_BASEADDRH_VAL); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_RAMADDRL_REG, AW86927_BASEADDRL_VAL); + if (err) + return err; + + /* Write waveform header to SRAM */ + err = regmap_noinc_write(haptics->regmap, AW86927_RAMDATA_REG, + &sram_waveform_header, sizeof(sram_waveform_header)); + if (err) + return err; + + /* Write waveform to SRAM */ + err = regmap_noinc_write(haptics->regmap, AW86927_RAMDATA_REG, + aw86927_waveform, ARRAY_SIZE(aw86927_waveform)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_DETCFG2_REG, + AW86927_DETCFG2_DET_SEQ0_MASK, + FIELD_PREP(AW86927_DETCFG2_DET_SEQ0_MASK, + AW86927_DETCFG2_DET_SEQ0_VBAT)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_DETCFG1_REG, + AW86927_DETCFG1_DET_GO_MASK, + FIELD_PREP(AW86927_DETCFG1_DET_GO_MASK, + AW86927_DETCFG1_DET_GO_DET_SEQ0)); + if (err) + return err; + + usleep_range(3000, 3500); + + err = regmap_update_bits(haptics->regmap, + AW86927_DETCFG1_REG, + AW86927_DETCFG1_DET_GO_MASK, + FIELD_PREP(AW86927_DETCFG1_DET_GO_MASK, + AW86927_DETCFG1_DET_GO_NA)); + if (err) + return err; + + /* Disable SRAM init */ + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL3_REG, + AW86927_SYSCTRL3_EN_RAMINIT_MASK, + FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK, + AW86927_SYSCTRL3_EN_RAMINIT_OFF)); + if (err) + return err; + + return 0; +} + +static irqreturn_t aw86927_irq(int irq, void *data) +{ + struct aw86927_data *haptics = data; + struct device *dev = &haptics->client->dev; + unsigned int reg_val; + int err; + + err = regmap_read(haptics->regmap, AW86927_SYSINT_REG, ®_val); + if (err) { + dev_err(dev, "Failed to read SYSINT register: %d\n", err); + return IRQ_NONE; + } + + if (reg_val & AW86927_SYSINT_BST_SCPI) + dev_err(dev, "Received a Short Circuit Protection interrupt\n"); + if (reg_val & AW86927_SYSINT_BST_OVPI) + dev_err(dev, "Received an Over Voltage Protection interrupt\n"); + if (reg_val & AW86927_SYSINT_UVLI) + dev_err(dev, "Received an Under Voltage Lock Out interrupt\n"); + if (reg_val & AW86927_SYSINT_OCDI) + dev_err(dev, "Received an Over Current interrupt\n"); + if (reg_val & AW86927_SYSINT_OTI) + dev_err(dev, "Received an Over Temperature interrupt\n"); + + if (reg_val & AW86927_SYSINT_DONEI) + dev_dbg(dev, "Chip playback done!\n"); + if (reg_val & AW86927_SYSINT_FF_AFI) + dev_dbg(dev, "The RTP mode FIFO is almost full!\n"); + if (reg_val & AW86927_SYSINT_FF_AEI) + dev_dbg(dev, "The RTP mode FIFO is almost empty!\n"); + + return IRQ_HANDLED; +} + +static int aw86927_detect(struct aw86927_data *haptics) +{ + __be16 read_buf; + u16 chip_id; + int err; + + err = regmap_bulk_read(haptics->regmap, AW86927_CHIPIDH_REG, &read_buf, 2); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to read CHIPID registers\n"); + + chip_id = be16_to_cpu(read_buf); + + if (chip_id != AW86927_CHIPID) { + dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id); + return -ENODEV; + } + + return 0; +} + +static int aw86927_probe(struct i2c_client *client) +{ + struct aw86927_data *haptics; + int err; + + haptics = devm_kzalloc(&client->dev, sizeof(struct aw86927_data), GFP_KERNEL); + if (!haptics) + return -ENOMEM; + + haptics->dev = &client->dev; + haptics->client = client; + + i2c_set_clientdata(client, haptics); + + haptics->regmap = devm_regmap_init_i2c(client, &aw86927_regmap_config); + if (IS_ERR(haptics->regmap)) + return dev_err_probe(haptics->dev, PTR_ERR(haptics->regmap), + "Failed to allocate register map\n"); + + haptics->input_dev = devm_input_allocate_device(haptics->dev); + if (!haptics->input_dev) + return -ENOMEM; + + haptics->reset_gpio = devm_gpiod_get(haptics->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(haptics->reset_gpio)) + return dev_err_probe(haptics->dev, PTR_ERR(haptics->reset_gpio), + "Failed to get reset gpio\n"); + + /* Hardware reset */ + aw86927_hw_reset(haptics); + + /* Software reset */ + err = regmap_write(haptics->regmap, AW86927_RSTCFG_REG, AW86927_RSTCFG_SOFTRST); + if (err) + return dev_err_probe(haptics->dev, PTR_ERR(haptics->regmap), + "Failed Software reset\n"); + + /* Wait ~3ms until I2C is accessible */ + usleep_range(3000, 3500); + + err = aw86927_detect(haptics); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to find chip\n"); + + /* IRQ config */ + err = regmap_write(haptics->regmap, AW86927_SYSCTRL4_REG, + FIELD_PREP(AW86927_SYSCTRL4_INT_MODE_MASK, + AW86927_SYSCTRL4_INT_MODE_EDGE) | + FIELD_PREP(AW86927_SYSCTRL4_INT_EDGE_MODE_MASK, + AW86927_SYSCTRL4_INT_EDGE_MODE_POS)); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to configure interrupt modes\n"); + + err = regmap_write(haptics->regmap, AW86927_SYSINTM_REG, + AW86927_SYSINTM_BST_OVPM | + AW86927_SYSINTM_FF_AEM | + AW86927_SYSINTM_FF_AFM | + AW86927_SYSINTM_DONEM); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to configure interrupt masks\n"); + + err = devm_request_threaded_irq(haptics->dev, client->irq, NULL, + aw86927_irq, IRQF_ONESHOT, NULL, haptics); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to request threaded irq\n"); + + INIT_WORK(&haptics->play_work, aw86927_haptics_play_work); + + haptics->input_dev->name = "aw86927-haptics"; + haptics->input_dev->close = aw86927_close; + + input_set_drvdata(haptics->input_dev, haptics); + input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE); + + err = input_ff_create_memless(haptics->input_dev, NULL, aw86927_haptics_play); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to create FF dev\n"); + + /* Set up registers */ + err = aw86927_play_mode(haptics, AW86927_STANDBY_MODE); + if (err) + return dev_err_probe(haptics->dev, err, + "Failed to enter standby for Haptic init\n"); + + err = aw86927_haptic_init(haptics); + if (err) + return dev_err_probe(haptics->dev, err, "Haptic init failed\n"); + + /* RAM init, upload the waveform for playback */ + err = aw86927_ram_init(haptics); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to init aw86927 sram\n"); + + err = input_register_device(haptics->input_dev); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to register input device\n"); + + return 0; +} + +static const struct of_device_id aw86927_of_id[] = { + { .compatible = "awinic,aw86927" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, aw86927_of_id); + +static struct i2c_driver aw86927_driver = { + .driver = { + .name = "aw86927-haptics", + .of_match_table = aw86927_of_id, + }, + .probe = aw86927_probe, +}; + +module_i2c_driver(aw86927_driver); + +MODULE_AUTHOR("Griffin Kroah-Hartman "); +MODULE_DESCRIPTION("AWINIC AW86927 LRA Haptic Driver"); +MODULE_LICENSE("GPL"); From 399dbcadc01ebf0035f325eaa8c264f8b5cd0a14 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 28 Sep 2025 12:18:29 +0200 Subject: [PATCH 2206/2711] ACPI: battery: Add synchronization between interface updates There is no synchronization between different code paths in the ACPI battery driver that update its sysfs interface or its power supply class device interface. In some cases this results to functional failures due to race conditions. One example of this is when two ACPI notifications: - ACPI_BATTERY_NOTIFY_STATUS (0x80) - ACPI_BATTERY_NOTIFY_INFO (0x81) are triggered (by the platform firmware) in a row with a little delay in between after removing and reinserting a laptop battery. Both notifications cause acpi_battery_update() to be called and if the delay between them is sufficiently small, sysfs_add_battery() can be re-entered before battery->bat is set which leads to a duplicate sysfs entry error: sysfs: cannot create duplicate filename '/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0A:00/power_supply/BAT1' CPU: 1 UID: 0 PID: 185 Comm: kworker/1:4 Kdump: loaded Not tainted 6.12.38+deb13-amd64 #1 Debian 6.12.38-1 Hardware name: Gateway NV44 /SJV40-MV , BIOS V1.3121 04/08/2009 Workqueue: kacpi_notify acpi_os_execute_deferred Call Trace: dump_stack_lvl+0x5d/0x80 sysfs_warn_dup.cold+0x17/0x23 sysfs_create_dir_ns+0xce/0xe0 kobject_add_internal+0xba/0x250 kobject_add+0x96/0xc0 ? get_device_parent+0xde/0x1e0 device_add+0xe2/0x870 __power_supply_register.part.0+0x20f/0x3f0 ? wake_up_q+0x4e/0x90 sysfs_add_battery+0xa4/0x1d0 [battery] acpi_battery_update+0x19e/0x290 [battery] acpi_battery_notify+0x50/0x120 [battery] acpi_ev_notify_dispatch+0x49/0x70 acpi_os_execute_deferred+0x1a/0x30 process_one_work+0x177/0x330 worker_thread+0x251/0x390 ? __pfx_worker_thread+0x10/0x10 kthread+0xd2/0x100 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x34/0x50 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 kobject: kobject_add_internal failed for BAT1 with -EEXIST, don't try to register things with the same name in the same directory. There are also other scenarios in which analogous issues may occur. Address this by using a common lock in all of the code paths leading to updates of driver interfaces: ACPI Notify () handler, system resume callback and post-resume notification, device addition and removal. This new lock replaces sysfs_lock that has been used only in sysfs_remove_battery() which now is going to be always called under the new lock, so it doesn't need any internal locking any more. Fixes: 10666251554c ("ACPI: battery: Install Notify() handler directly") Closes: https://lore.kernel.org/linux-acpi/20250910142653.313360-1-luogf2025@163.com/ Reported-by: GuangFei Luo Tested-by: GuangFei Luo Cc: 6.6+ # 6.6+ Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 43 ++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 6905b56bf3e4..67b76492c839 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -92,7 +92,7 @@ enum { struct acpi_battery { struct mutex lock; - struct mutex sysfs_lock; + struct mutex update_lock; struct power_supply *bat; struct power_supply_desc bat_desc; struct acpi_device *device; @@ -904,15 +904,12 @@ static int sysfs_add_battery(struct acpi_battery *battery) static void sysfs_remove_battery(struct acpi_battery *battery) { - mutex_lock(&battery->sysfs_lock); - if (!battery->bat) { - mutex_unlock(&battery->sysfs_lock); + if (!battery->bat) return; - } + battery_hook_remove_battery(battery); power_supply_unregister(battery->bat); battery->bat = NULL; - mutex_unlock(&battery->sysfs_lock); } static void find_battery(const struct dmi_header *dm, void *private) @@ -1072,6 +1069,9 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) if (!battery) return; + + guard(mutex)(&battery->update_lock); + old = battery->bat; /* * On Acer Aspire V5-573G notifications are sometimes triggered too @@ -1094,21 +1094,22 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) } static int battery_notify(struct notifier_block *nb, - unsigned long mode, void *_unused) + unsigned long mode, void *_unused) { struct acpi_battery *battery = container_of(nb, struct acpi_battery, pm_nb); - int result; - switch (mode) { - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: + if (mode == PM_POST_SUSPEND || mode == PM_POST_HIBERNATION) { + guard(mutex)(&battery->update_lock); + if (!acpi_battery_present(battery)) return 0; if (battery->bat) { acpi_battery_refresh(battery); } else { + int result; + result = acpi_battery_get_info(battery); if (result) return result; @@ -1120,7 +1121,6 @@ static int battery_notify(struct notifier_block *nb, acpi_battery_init_alarm(battery); acpi_battery_get_state(battery); - break; } return 0; @@ -1198,6 +1198,8 @@ static int acpi_battery_update_retry(struct acpi_battery *battery) { int retry, ret; + guard(mutex)(&battery->update_lock); + for (retry = 5; retry; retry--) { ret = acpi_battery_update(battery, false); if (!ret) @@ -1208,6 +1210,13 @@ static int acpi_battery_update_retry(struct acpi_battery *battery) return ret; } +static void sysfs_battery_cleanup(struct acpi_battery *battery) +{ + guard(mutex)(&battery->update_lock); + + sysfs_remove_battery(battery); +} + static int acpi_battery_add(struct acpi_device *device) { int result = 0; @@ -1230,7 +1239,7 @@ static int acpi_battery_add(struct acpi_device *device) if (result) return result; - result = devm_mutex_init(&device->dev, &battery->sysfs_lock); + result = devm_mutex_init(&device->dev, &battery->update_lock); if (result) return result; @@ -1262,7 +1271,7 @@ fail_pm: device_init_wakeup(&device->dev, 0); unregister_pm_notifier(&battery->pm_nb); fail: - sysfs_remove_battery(battery); + sysfs_battery_cleanup(battery); return result; } @@ -1281,6 +1290,9 @@ static void acpi_battery_remove(struct acpi_device *device) device_init_wakeup(&device->dev, 0); unregister_pm_notifier(&battery->pm_nb); + + guard(mutex)(&battery->update_lock); + sysfs_remove_battery(battery); } @@ -1297,6 +1309,9 @@ static int acpi_battery_resume(struct device *dev) return -EINVAL; battery->update_time = 0; + + guard(mutex)(&battery->update_lock); + acpi_battery_update(battery, true); return 0; } From c7bc7e9070d6bd17fad1a3fc6a7de097834beff8 Mon Sep 17 00:00:00 2001 From: pengdonglin Date: Tue, 16 Sep 2025 12:47:22 +0800 Subject: [PATCH 2207/2711] ACPI: APEI: Remove redundant rcu_read_lock/unlock() under spinlock Since commit a8bb74acd8efe ("rcu: Consolidate RCU-sched update-side function definitions") there is no difference between rcu_read_lock(), rcu_read_lock_bh() and rcu_read_lock_sched() in terms of RCU read section and the relevant grace period. That means that spin_lock(), which implies rcu_read_lock_sched(), also implies rcu_read_lock(). There is no need no explicitly start a RCU read section if one has already been started implicitly by spin_lock(). Simplify the code and remove the inner rcu_read_lock() invocation. Signed-off-by: pengdonglin Signed-off-by: pengdonglin Reviewed-by: Hanjun Guo Link: https://patch.msgid.link/20250916044735.2316171-2-dolinux.peng@gmail.com [ rjw: Subject adjustment ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/ghes.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index a0d54993edb3..97ee19f2cae0 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1207,12 +1207,10 @@ static int ghes_notify_hed(struct notifier_block *this, unsigned long event, int ret = NOTIFY_DONE; spin_lock_irqsave(&ghes_notify_lock_irq, flags); - rcu_read_lock(); list_for_each_entry_rcu(ghes, &ghes_hed, list) { if (!ghes_proc(ghes)) ret = NOTIFY_OK; } - rcu_read_unlock(); spin_unlock_irqrestore(&ghes_notify_lock_irq, flags); return ret; From 064a97a29e3ba0e5d75b3b8ad5b762962aaad8ab Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 12 Sep 2025 14:07:43 +0200 Subject: [PATCH 2208/2711] dt-bindings: watchdog: add SMARC-sAM67 support The SMARC-sAM67 board has an on-board uC which has the same register interface as the older CPLD implementation on the SMARC-sAL28 board. Although the MCU emulates the same behavior, be prepared for any quirks and add a board specific compatible. Signed-off-by: Michael Walle Acked-by: Krzysztof Kozlowski Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml b/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml index 179272f74de5..b5b624e85468 100644 --- a/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml @@ -18,7 +18,12 @@ allOf: properties: compatible: - const: kontron,sl28cpld-wdt + oneOf: + - items: + - enum: + - kontron,sa67mcu-wdt + - const: kontron,sl28cpld-wdt + - const: kontron,sl28cpld-wdt reg: maxItems: 1 From c64c2a50cdd487e2270c875c1770cd55705d75ff Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Tue, 23 Sep 2025 13:03:52 -0600 Subject: [PATCH 2209/2711] watchdog/hpwdt New maintianer Update MAINTAINERS file with new contact. Signed-off-by: Jerry Hoemann Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index cd7ff55b5d32..7e9d68e795b6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10777,7 +10777,7 @@ S: Supported F: drivers/misc/hpilo.[ch] HEWLETT PACKARD ENTERPRISE ILO NMI WATCHDOG DRIVER -M: Jerry Hoemann +M: Craig Lamparter S: Supported F: Documentation/watchdog/hpwdt.rst F: drivers/watchdog/hpwdt.c From d3366a04770eea807f2826cbdb96934dd8c9bf79 Mon Sep 17 00:00:00 2001 From: Zhen Ni Date: Sun, 28 Sep 2025 14:37:37 +0800 Subject: [PATCH 2210/2711] Input: uinput - zero-initialize uinput_ff_upload_compat to avoid info leak Struct ff_effect_compat is embedded twice inside uinput_ff_upload_compat, contains internal padding. In particular, there is a hole after struct ff_replay to satisfy alignment requirements for the following union member. Without clearing the structure, copy_to_user() may leak stack data to userspace. Initialize ff_up_compat to zero before filling valid fields. Fixes: 2d56f3a32c0e ("Input: refactor evdev 32bit compat to be shareable with uinput") Cc: stable@vger.kernel.org Signed-off-by: Zhen Ni Link: https://lore.kernel.org/r/20250928063737.74590-1-zhen.ni@easystack.cn Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 2c51ea9d01d7..13336a2fd49c 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -775,6 +775,7 @@ static int uinput_ff_upload_to_user(char __user *buffer, if (in_compat_syscall()) { struct uinput_ff_upload_compat ff_up_compat; + memset(&ff_up_compat, 0, sizeof(ff_up_compat)); ff_up_compat.request_id = ff_up->request_id; ff_up_compat.retval = ff_up->retval; /* From db74430a4218f282d16e58a38337275ad3f9f517 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Sun, 28 Sep 2025 22:01:10 -0700 Subject: [PATCH 2211/2711] Input: psxpad-spi - add a check for the return value of spi_setup() The probe function in the psxpad-spi driver calls spi_setup() but fails to check its return value. If the SPI bus setup fails, the driver will still load successfully, resulting in potential error in later I/O operations. Add a check for the return value of spi_setup() and return an error on failure. Fixes: 8be193c7b1f4 ("Input: add support for PlayStation 1/2 joypads connected via SPI") Signed-off-by: Haotian Zhang Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/psxpad-spi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/input/joystick/psxpad-spi.c b/drivers/input/joystick/psxpad-spi.c index c47fc5f34bd0..f902a56d011f 100644 --- a/drivers/input/joystick/psxpad-spi.c +++ b/drivers/input/joystick/psxpad-spi.c @@ -344,7 +344,11 @@ static int psxpad_spi_probe(struct spi_device *spi) /* (PlayStation 1/2 joypad might be possible works 250kHz/500kHz) */ spi->controller->min_speed_hz = 125000; spi->controller->max_speed_hz = 125000; - spi_setup(spi); + err = spi_setup(spi); + if (err) { + dev_err(&spi->dev, "failed to set up SPI: %d\n", err); + return err; + } /* pad settings */ psxpad_set_motor_level(pad, 0, 0); From ebc4ed14a4dbf51307102bb7ffc82ed6c16a37c2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 9 Sep 2025 09:38:19 +0200 Subject: [PATCH 2212/2711] cpufreq: mediatek: fix device leak on probe failure Make sure to drop the reference to the cci device taken by of_find_device_by_node() on probe failure (e.g. probe deferral). Fixes: 0daa47325bae ("cpufreq: mediatek: Link CCI device to CPU") Cc: Jia-Wei Chang Cc: Rex-BC Chen Signed-off-by: Johan Hovold Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index 00de1166188a..5d50a231f944 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -403,9 +403,11 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) } info->cpu_clk = clk_get(cpu_dev, "cpu"); - if (IS_ERR(info->cpu_clk)) - return dev_err_probe(cpu_dev, PTR_ERR(info->cpu_clk), - "cpu%d: failed to get cpu clk\n", cpu); + if (IS_ERR(info->cpu_clk)) { + ret = PTR_ERR(info->cpu_clk); + dev_err_probe(cpu_dev, ret, "cpu%d: failed to get cpu clk\n", cpu); + goto out_put_cci_dev; + } info->inter_clk = clk_get(cpu_dev, "intermediate"); if (IS_ERR(info->inter_clk)) { @@ -551,6 +553,10 @@ out_free_inter_clock: out_free_mux_clock: clk_put(info->cpu_clk); +out_put_cci_dev: + if (info->soc_data->ccifreq_supported) + put_device(info->cci_dev); + return ret; } @@ -568,6 +574,8 @@ static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info) clk_put(info->inter_clk); dev_pm_opp_of_cpumask_remove_table(&info->cpus); dev_pm_opp_unregister_notifier(info->cpu_dev, &info->opp_nb); + if (info->soc_data->ccifreq_supported) + put_device(info->cci_dev); } static int mtk_cpufreq_init(struct cpufreq_policy *policy) From 24287f902095d845c6af9c2c369ba96877f5eb79 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 15 Sep 2025 15:59:54 +0200 Subject: [PATCH 2213/2711] rust: cpufreq: streamline find_supply_names Remove local variables from find_supply_names() and use .and_then() with the more concise kernel::kvec![] macro, instead of KVec::with_capacity() followed by .push() and Some(). No functional changes intended. Signed-off-by: Thorsten Blum Signed-off-by: Viresh Kumar --- drivers/cpufreq/rcpufreq_dt.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs index 7e1fbf9a091f..224d063c7cec 100644 --- a/drivers/cpufreq/rcpufreq_dt.rs +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -28,15 +28,11 @@ fn find_supply_name_exact(dev: &Device, name: &str) -> Option { /// Finds supply name for the CPU from DT. fn find_supply_names(dev: &Device, cpu: cpu::CpuId) -> Option> { // Try "cpu0" for older DTs, fallback to "cpu". - let name = (cpu.as_u32() == 0) + (cpu.as_u32() == 0) .then(|| find_supply_name_exact(dev, "cpu0")) .flatten() - .or_else(|| find_supply_name_exact(dev, "cpu"))?; - - let mut list = KVec::with_capacity(1, GFP_KERNEL).ok()?; - list.push(name, GFP_KERNEL).ok()?; - - Some(list) + .or_else(|| find_supply_name_exact(dev, "cpu")) + .and_then(|name| kernel::kvec![name].ok()) } /// Represents the cpufreq dt device. From 0b1bb980fd7cae126ee3d59f817068a13e321b07 Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Thu, 28 Aug 2025 21:48:12 -0500 Subject: [PATCH 2214/2711] cpufreq: tegra186: Set target frequency for all cpus in policy The original commit set all cores in a cluster to a shared policy, but did not update set_target to apply a frequency change to all cores for the policy. This caused most cores to remain stuck at their boot frequency. Fixes: be4ae8c19492 ("cpufreq: tegra186: Share policy per cluster") Signed-off-by: Aaron Kling Reviewed-by: Mikko Perttunen Signed-off-by: Viresh Kumar --- drivers/cpufreq/tegra186-cpufreq.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c index 4270686fc3e3..a9e1f9bd2a4e 100644 --- a/drivers/cpufreq/tegra186-cpufreq.c +++ b/drivers/cpufreq/tegra186-cpufreq.c @@ -93,10 +93,14 @@ static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy, { struct tegra186_cpufreq_data *data = cpufreq_get_driver_data(); struct cpufreq_frequency_table *tbl = policy->freq_table + index; - unsigned int edvd_offset = data->cpus[policy->cpu].edvd_offset; + unsigned int edvd_offset; u32 edvd_val = tbl->driver_data; + u32 cpu; - writel(edvd_val, data->regs + edvd_offset); + for_each_cpu(cpu, policy->cpus) { + edvd_offset = data->cpus[cpu].edvd_offset; + writel(edvd_val, data->regs + edvd_offset); + } return 0; } From ba6018929165fc914c665f071f8e8cdbac844a49 Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Thu, 28 Aug 2025 21:48:13 -0500 Subject: [PATCH 2215/2711] cpufreq: tegra186: Initialize all cores to max frequencies During initialization, the EDVD_COREx_VOLT_FREQ registers for some cores are still at reset values and not reflecting the actual frequency. This causes get calls to fail. Set all cores to their respective max frequency during probe to initialize the registers to working values. Suggested-by: Mikko Perttunen Signed-off-by: Aaron Kling Reviewed-by: Mikko Perttunen Signed-off-by: Viresh Kumar --- drivers/cpufreq/tegra186-cpufreq.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c index a9e1f9bd2a4e..136ab102f636 100644 --- a/drivers/cpufreq/tegra186-cpufreq.c +++ b/drivers/cpufreq/tegra186-cpufreq.c @@ -136,13 +136,14 @@ static struct cpufreq_driver tegra186_cpufreq_driver = { static struct cpufreq_frequency_table *init_vhint_table( struct platform_device *pdev, struct tegra_bpmp *bpmp, - struct tegra186_cpufreq_cluster *cluster, unsigned int cluster_id) + struct tegra186_cpufreq_cluster *cluster, unsigned int cluster_id, + int *num_rates) { struct cpufreq_frequency_table *table; struct mrq_cpu_vhint_request req; struct tegra_bpmp_message msg; struct cpu_vhint_data *data; - int err, i, j, num_rates = 0; + int err, i, j; dma_addr_t phys; void *virt; @@ -172,6 +173,7 @@ static struct cpufreq_frequency_table *init_vhint_table( goto free; } + *num_rates = 0; for (i = data->vfloor; i <= data->vceil; i++) { u16 ndiv = data->ndiv[i]; @@ -182,10 +184,10 @@ static struct cpufreq_frequency_table *init_vhint_table( if (i > 0 && ndiv == data->ndiv[i - 1]) continue; - num_rates++; + (*num_rates)++; } - table = devm_kcalloc(&pdev->dev, num_rates + 1, sizeof(*table), + table = devm_kcalloc(&pdev->dev, *num_rates + 1, sizeof(*table), GFP_KERNEL); if (!table) { table = ERR_PTR(-ENOMEM); @@ -227,7 +229,9 @@ static int tegra186_cpufreq_probe(struct platform_device *pdev) { struct tegra186_cpufreq_data *data; struct tegra_bpmp *bpmp; - unsigned int i = 0, err; + unsigned int i = 0, err, edvd_offset; + int num_rates = 0; + u32 edvd_val, cpu; data = devm_kzalloc(&pdev->dev, struct_size(data, clusters, TEGRA186_NUM_CLUSTERS), @@ -250,10 +254,21 @@ static int tegra186_cpufreq_probe(struct platform_device *pdev) for (i = 0; i < TEGRA186_NUM_CLUSTERS; i++) { struct tegra186_cpufreq_cluster *cluster = &data->clusters[i]; - cluster->table = init_vhint_table(pdev, bpmp, cluster, i); + cluster->table = init_vhint_table(pdev, bpmp, cluster, i, &num_rates); if (IS_ERR(cluster->table)) { err = PTR_ERR(cluster->table); goto put_bpmp; + } else if (!num_rates) { + err = -EINVAL; + goto put_bpmp; + } + + for (cpu = 0; cpu < ARRAY_SIZE(tegra186_cpus); cpu++) { + if (data->cpus[cpu].bpmp_cluster_id == i) { + edvd_val = cluster->table[num_rates - 1].driver_data; + edvd_offset = data->cpus[cpu].edvd_offset; + writel(edvd_val, data->regs + edvd_offset); + } } } From 27e06650a5eafe832a90fd2604f0c5e920857fae Mon Sep 17 00:00:00 2001 From: Wang Haoran Date: Sat, 20 Sep 2025 15:44:41 +0800 Subject: [PATCH 2216/2711] scsi: target: target_core_configfs: Add length check to avoid buffer overflow A buffer overflow arises from the usage of snprintf to write into the buffer "buf" in target_lu_gp_members_show function located in /drivers/target/target_core_configfs.c. This buffer is allocated with size LU_GROUP_NAME_BUF (256 bytes). snprintf(...) formats multiple strings into buf with the HBA name (hba->hba_group.cg_item), a slash character, a devicename (dev-> dev_group.cg_item) and a newline character, the total formatted string length may exceed the buffer size of 256 bytes. Since snprintf() returns the total number of bytes that would have been written (the length of %s/%sn ), this value may exceed the buffer length (256 bytes) passed to memcpy(), this will ultimately cause function memcpy reporting a buffer overflow error. An additional check of the return value of snprintf() can avoid this buffer overflow. Reported-by: Wang Haoran Reported-by: ziiiro Signed-off-by: Wang Haoran Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 0904ecae253a..b19acd662726 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -2774,7 +2774,7 @@ static ssize_t target_lu_gp_members_show(struct config_item *item, char *page) config_item_name(&dev->dev_group.cg_item)); cur_len++; /* Extra byte for NULL terminator */ - if ((cur_len + len) > PAGE_SIZE) { + if ((cur_len + len) > PAGE_SIZE || cur_len > LU_GROUP_NAME_BUF) { pr_warn("Ran out of lu_gp_show_attr" "_members buffer\n"); break; From fa7a0a53eeb7e16402f82c3d5a9ef4bf5efe9357 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 26 Sep 2025 15:39:10 +0200 Subject: [PATCH 2217/2711] s390: Add -Wno-pointer-sign to KBUILD_CFLAGS_DECOMPRESSOR If the decompressor is compiled with clang this can lead to the following warning: In file included from arch/s390/boot/startup.c:4: ... In file included from ./include/linux/pgtable.h:6: ./arch/s390/include/asm/pgtable.h:2065:48: warning: passing 'unsigned long *' to parameter of type 'long *' converts between pointers to integer types with different sign [-Wpointer-sign] 2065 | value = __atomic64_or_barrier(PGSTE_PCL_BIT, ptr); Add -Wno-pointer-sign to the decompressor compile flags, like it is also done for the kernel. This is similar to what was done for x86 to address the same problem [1]. [1] commit dca5203e3fe2 ("x86/boot: Add -Wno-pointer-sign to KBUILD_CFLAGS") Cc: stable@vger.kernel.org Reported-by: Gerd Bayer Signed-off-by: Heiko Carstens Reviewed-by: Alexander Gordeev Signed-off-by: Alexander Gordeev --- arch/s390/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 7679bc16b692..b4769241332b 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -25,6 +25,7 @@ endif KBUILD_CFLAGS_DECOMPRESSOR := $(CLANG_FLAGS) -m64 -O2 -mpacked-stack -std=gnu11 KBUILD_CFLAGS_DECOMPRESSOR += -DDISABLE_BRANCH_PROFILING -D__NO_FORTIFY KBUILD_CFLAGS_DECOMPRESSOR += -D__DECOMPRESSOR +KBUILD_CFLAGS_DECOMPRESSOR += -Wno-pointer-sign KBUILD_CFLAGS_DECOMPRESSOR += -fno-delete-null-pointer-checks -msoft-float -mbackchain KBUILD_CFLAGS_DECOMPRESSOR += -fno-asynchronous-unwind-tables KBUILD_CFLAGS_DECOMPRESSOR += -ffreestanding From f0edc8f113a39d1c9f8cf83e865c32b0668d80e0 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 25 Sep 2025 10:45:17 +0200 Subject: [PATCH 2218/2711] s390/cio/ioasm: Fix __xsch() condition code handling For the __xsch() inline assembly the conversion to flag output macros is incomplete. Only the conditional shift of the return value was added, while the required changes to the inline assembly itself are missing. If compiled with GCC versions before 14.2 this leads to a double shift of the cc output operand and therefore the returned value of __xsch() is incorrectly always zero, instead of the expected condition code. Fixes: e200565d434b ("s390/cio/ioasm: Convert to use flag output macros") Cc: stable@vger.kernel.org Signed-off-by: Heiko Carstens Acked-by: Alexander Gordeev Reviewed-by: Juergen Christ Signed-off-by: Alexander Gordeev --- drivers/s390/cio/ioasm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/ioasm.c b/drivers/s390/cio/ioasm.c index a540045b64a6..8b06b234e110 100644 --- a/drivers/s390/cio/ioasm.c +++ b/drivers/s390/cio/ioasm.c @@ -253,11 +253,10 @@ static inline int __xsch(struct subchannel_id schid) asm volatile( " lgr 1,%[r1]\n" " xsch\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (ccode) + CC_IPM(cc) + : CC_OUT(cc, ccode) : [r1] "d" (r1) - : "cc", "1"); + : CC_CLOBBER_LIST("1")); return CC_TRANSFORM(ccode); } From 4335edb7138b45abab65f01d2be77a9be9cfd2fe Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 25 Sep 2025 10:45:18 +0200 Subject: [PATCH 2219/2711] s390: Remove superfluous newlines from inline assemblies Remove superfluous newlines from inline assemblies. Compilers use the number of lines of inline assemblies as heuristic for the complexity and inline decisions. Therefore inline assemblies should only contain as many lines as required. A lot of inline assemblies contain a superfluous newline for the last line. Remove such newlines to improve compiler inlining decisions. Suggested-by: Juergen Christ Signed-off-by: Heiko Carstens Reviewed-by: Alexander Gordeev Reviewed-by: Juergen Christ Signed-off-by: Alexander Gordeev --- arch/s390/hypfs/hypfs_sprp.c | 2 +- arch/s390/include/asm/ap.h | 18 +++++++-------- arch/s390/include/asm/atomic_ops.h | 28 +++++++++++----------- arch/s390/include/asm/barrier.h | 8 +++---- arch/s390/include/asm/bitops.h | 2 +- arch/s390/include/asm/checksum.h | 2 +- arch/s390/include/asm/cmpxchg.h | 12 +++++----- arch/s390/include/asm/cpacf.h | 24 +++++++++---------- arch/s390/include/asm/ctlreg.h | 8 +++---- arch/s390/include/asm/fpu-insn.h | 36 ++++++++++++++--------------- arch/s390/include/asm/kvm_para.h | 2 +- arch/s390/include/asm/percpu.h | 8 +++---- arch/s390/include/asm/processor.h | 2 +- arch/s390/include/asm/rwonce.h | 2 +- arch/s390/include/asm/spinlock.h | 2 +- arch/s390/include/asm/stacktrace.h | 4 ++-- arch/s390/include/asm/string.h | 2 +- arch/s390/include/asm/syscall.h | 2 +- arch/s390/include/asm/timex.h | 2 +- arch/s390/kernel/diag/diag310.c | 2 +- arch/s390/kernel/diag/diag324.c | 2 +- arch/s390/kernel/setup.c | 2 +- arch/s390/kernel/skey.c | 2 +- arch/s390/kernel/smp.c | 2 +- arch/s390/kvm/kvm-s390.c | 6 ++--- arch/s390/lib/spinlock.c | 6 ++--- arch/s390/lib/string.c | 8 +++---- arch/s390/lib/test_unwind.c | 4 ++-- arch/s390/lib/xor.c | 8 +++---- arch/s390/mm/maccess.c | 2 +- arch/s390/mm/pgalloc.c | 2 +- arch/s390/pci/pci_insn.c | 4 ++-- drivers/s390/char/sclp_early_core.c | 2 +- drivers/s390/cio/cmf.c | 2 +- 34 files changed, 110 insertions(+), 110 deletions(-) diff --git a/arch/s390/hypfs/hypfs_sprp.c b/arch/s390/hypfs/hypfs_sprp.c index 9fc3f0dae8f0..a2952ed5518b 100644 --- a/arch/s390/hypfs/hypfs_sprp.c +++ b/arch/s390/hypfs/hypfs_sprp.c @@ -27,7 +27,7 @@ static inline unsigned long __hypfs_sprp_diag304(void *data, unsigned long cmd) { union register_pair r1 = { .even = virt_to_phys(data), }; - asm volatile("diag %[r1],%[r3],0x304\n" + asm volatile("diag %[r1],%[r3],0x304" : [r1] "+&d" (r1.pair) : [r3] "d" (cmd) : "memory"); diff --git a/arch/s390/include/asm/ap.h b/arch/s390/include/asm/ap.h index 352108727d7e..56817990c73d 100644 --- a/arch/s390/include/asm/ap.h +++ b/arch/s390/include/asm/ap.h @@ -143,7 +143,7 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, " lghi 2,0\n" /* 0 into gr2 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ - " lgr %[reg2],2\n" /* gr2 into reg2 */ + " lgr %[reg2],2" /* gr2 into reg2 */ : [reg1] "=&d" (reg1.value), [reg2] "=&d" (reg2) : [qid] "d" (qid) : "cc", "0", "1", "2"); @@ -186,7 +186,7 @@ static inline struct ap_queue_status ap_rapq(ap_qid_t qid, int fbit) asm volatile( " lgr 0,%[reg0]\n" /* qid arg into gr0 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */ - " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + " lgr %[reg1],1" /* gr1 (status) into reg1 */ : [reg1] "=&d" (reg1.value) : [reg0] "d" (reg0) : "cc", "0", "1"); @@ -211,7 +211,7 @@ static inline struct ap_queue_status ap_zapq(ap_qid_t qid, int fbit) asm volatile( " lgr 0,%[reg0]\n" /* qid arg into gr0 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */ - " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + " lgr %[reg1],1" /* gr1 (status) into reg1 */ : [reg1] "=&d" (reg1.value) : [reg0] "d" (reg0) : "cc", "0", "1"); @@ -315,7 +315,7 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid, " lgr 1,%[reg1]\n" /* irq ctrl into gr1 */ " lgr 2,%[reg2]\n" /* ni addr into gr2 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(AQIC) */ - " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + " lgr %[reg1],1" /* gr1 (status) into reg1 */ : [reg1] "+&d" (reg1.value) : [reg0] "d" (reg0), [reg2] "d" (reg2) : "cc", "memory", "0", "1", "2"); @@ -363,7 +363,7 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit, " lgr 1,%[reg1]\n" /* qact in info into gr1 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(QACT) */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ - " lgr %[reg2],2\n" /* qact out info into reg2 */ + " lgr %[reg2],2" /* qact out info into reg2 */ : [reg1] "+&d" (reg1.value), [reg2] "=&d" (reg2) : [reg0] "d" (reg0) : "cc", "0", "1", "2"); @@ -388,7 +388,7 @@ static inline struct ap_queue_status ap_bapq(ap_qid_t qid) asm volatile( " lgr 0,%[reg0]\n" /* qid arg into gr0 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(BAPQ) */ - " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + " lgr %[reg1],1" /* gr1 (status) into reg1 */ : [reg1] "=&d" (reg1.value) : [reg0] "d" (reg0) : "cc", "0", "1"); @@ -416,7 +416,7 @@ static inline struct ap_queue_status ap_aapq(ap_qid_t qid, unsigned int sec_idx) " lgr 0,%[reg0]\n" /* qid arg into gr0 */ " lgr 2,%[reg2]\n" /* secret index into gr2 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(AAPQ) */ - " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + " lgr %[reg1],1" /* gr1 (status) into reg1 */ : [reg1] "=&d" (reg1.value) : [reg0] "d" (reg0), [reg2] "d" (reg2) : "cc", "0", "1", "2"); @@ -453,7 +453,7 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, " lgr 0,%[reg0]\n" /* qid param in gr0 */ "0: .insn rre,0xb2ad0000,%[nqap_r1],%[nqap_r2]\n" " brc 2,0b\n" /* handle partial completion */ - " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + " lgr %[reg1],1" /* gr1 (status) into reg1 */ : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value), [nqap_r2] "+&d" (nqap_r2.pair) : [nqap_r1] "d" (nqap_r1.pair) @@ -518,7 +518,7 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, " brc 6,0b\n" /* handle partial complete */ "2: lgr %[reg0],0\n" /* gr0 (qid + info) into reg0 */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ - " lgr %[reg2],2\n" /* gr2 (res length) into reg2 */ + " lgr %[reg2],2" /* gr2 (res length) into reg2 */ : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value), [reg2] "=&d" (reg2), [rp1] "+&d" (rp1.pair), [rp2] "+&d" (rp2.pair) diff --git a/arch/s390/include/asm/atomic_ops.h b/arch/s390/include/asm/atomic_ops.h index 21c26d842832..845b77864412 100644 --- a/arch/s390/include/asm/atomic_ops.h +++ b/arch/s390/include/asm/atomic_ops.h @@ -17,7 +17,7 @@ static __always_inline int __atomic_read(const int *ptr) int val; asm volatile( - " l %[val],%[ptr]\n" + " l %[val],%[ptr]" : [val] "=d" (val) : [ptr] "R" (*ptr)); return val; } @@ -26,11 +26,11 @@ static __always_inline void __atomic_set(int *ptr, int val) { if (__builtin_constant_p(val) && val >= S16_MIN && val <= S16_MAX) { asm volatile( - " mvhi %[ptr],%[val]\n" + " mvhi %[ptr],%[val]" : [ptr] "=Q" (*ptr) : [val] "K" (val)); } else { asm volatile( - " st %[val],%[ptr]\n" + " st %[val],%[ptr]" : [ptr] "=R" (*ptr) : [val] "d" (val)); } } @@ -40,7 +40,7 @@ static __always_inline long __atomic64_read(const long *ptr) long val; asm volatile( - " lg %[val],%[ptr]\n" + " lg %[val],%[ptr]" : [val] "=d" (val) : [ptr] "RT" (*ptr)); return val; } @@ -49,11 +49,11 @@ static __always_inline void __atomic64_set(long *ptr, long val) { if (__builtin_constant_p(val) && val >= S16_MIN && val <= S16_MAX) { asm volatile( - " mvghi %[ptr],%[val]\n" + " mvghi %[ptr],%[val]" : [ptr] "=Q" (*ptr) : [val] "K" (val)); } else { asm volatile( - " stg %[val],%[ptr]\n" + " stg %[val],%[ptr]" : [ptr] "=RT" (*ptr) : [val] "d" (val)); } } @@ -66,7 +66,7 @@ static __always_inline op_type op_name(op_type val, op_type *ptr) \ op_type old; \ \ asm volatile( \ - op_string " %[old],%[val],%[ptr]\n" \ + op_string " %[old],%[val],%[ptr]" \ op_barrier \ : [old] "=d" (old), [ptr] "+QS" (*ptr) \ : [val] "d" (val) : "cc", "memory"); \ @@ -75,7 +75,7 @@ static __always_inline op_type op_name(op_type val, op_type *ptr) \ #define __ATOMIC_OPS(op_name, op_type, op_string) \ __ATOMIC_OP(op_name, op_type, op_string, "") \ - __ATOMIC_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n") + __ATOMIC_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0") __ATOMIC_OPS(__atomic_add, int, "laa") __ATOMIC_OPS(__atomic_and, int, "lan") @@ -94,14 +94,14 @@ __ATOMIC_OPS(__atomic64_xor, long, "laxg") static __always_inline void op_name(op_type val, op_type *ptr) \ { \ asm volatile( \ - op_string " %[ptr],%[val]\n" \ + op_string " %[ptr],%[val]" \ op_barrier \ : [ptr] "+QS" (*ptr) : [val] "i" (val) : "cc", "memory");\ } #define __ATOMIC_CONST_OPS(op_name, op_type, op_string) \ __ATOMIC_CONST_OP(op_name, op_type, op_string, "") \ - __ATOMIC_CONST_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n") + __ATOMIC_CONST_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0") __ATOMIC_CONST_OPS(__atomic_add_const, int, "asi") __ATOMIC_CONST_OPS(__atomic64_add_const, long, "agsi") @@ -179,7 +179,7 @@ static __always_inline bool op_name(op_type val, op_type *ptr) \ int cc; \ \ asm volatile( \ - op_string " %[tmp],%[val],%[ptr]\n" \ + op_string " %[tmp],%[val],%[ptr]" \ op_barrier \ : "=@cc" (cc), [tmp] "=d" (tmp), [ptr] "+QS" (*ptr) \ : [val] "d" (val) \ @@ -189,7 +189,7 @@ static __always_inline bool op_name(op_type val, op_type *ptr) \ #define __ATOMIC_TEST_OPS(op_name, op_type, op_string) \ __ATOMIC_TEST_OP(op_name, op_type, op_string, "") \ - __ATOMIC_TEST_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n") + __ATOMIC_TEST_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0") __ATOMIC_TEST_OPS(__atomic_add_and_test, int, "laal") __ATOMIC_TEST_OPS(__atomic64_add_and_test, long, "laalg") @@ -203,7 +203,7 @@ static __always_inline bool op_name(op_type val, op_type *ptr) \ int cc; \ \ asm volatile( \ - op_string " %[ptr],%[val]\n" \ + op_string " %[ptr],%[val]" \ op_barrier \ : "=@cc" (cc), [ptr] "+QS" (*ptr) \ : [val] "i" (val) \ @@ -213,7 +213,7 @@ static __always_inline bool op_name(op_type val, op_type *ptr) \ #define __ATOMIC_CONST_TEST_OPS(op_name, op_type, op_string) \ __ATOMIC_CONST_TEST_OP(op_name, op_type, op_string, "") \ - __ATOMIC_CONST_TEST_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n") + __ATOMIC_CONST_TEST_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0") __ATOMIC_CONST_TEST_OPS(__atomic_add_const_and_test, int, "alsi") __ATOMIC_CONST_TEST_OPS(__atomic64_add_const_and_test, long, "algsi") diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h index d82130d7f2b6..f3184073e754 100644 --- a/arch/s390/include/asm/barrier.h +++ b/arch/s390/include/asm/barrier.h @@ -18,9 +18,9 @@ #ifdef MARCH_HAS_Z196_FEATURES /* Fast-BCR without checkpoint synchronization */ -#define __ASM_BCR_SERIALIZE "bcr 14,0\n" +#define __ASM_BCR_SERIALIZE "bcr 14,0" #else -#define __ASM_BCR_SERIALIZE "bcr 15,0\n" +#define __ASM_BCR_SERIALIZE "bcr 15,0" #endif static __always_inline void bcr_serialize(void) @@ -69,12 +69,12 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, if (__builtin_constant_p(size) && size > 0) { asm(" clgr %2,%1\n" - " slbgr %0,%0\n" + " slbgr %0,%0" :"=d" (mask) : "d" (size-1), "d" (index) :"cc"); return mask; } asm(" clgr %1,%2\n" - " slbgr %0,%0\n" + " slbgr %0,%0" :"=d" (mask) : "d" (size), "d" (index) :"cc"); return ~mask; } diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h index 1564dd3a5a82..2d7d784643d5 100644 --- a/arch/s390/include/asm/bitops.h +++ b/arch/s390/include/asm/bitops.h @@ -62,7 +62,7 @@ static __always_inline bool arch_test_bit(unsigned long nr, const volatile unsig addr += (nr ^ (BITS_PER_LONG - BITS_PER_BYTE)) / BITS_PER_BYTE; mask = 1UL << (nr & (BITS_PER_BYTE - 1)); asm volatile( - " tm %[addr],%[mask]\n" + " tm %[addr],%[mask]" : "=@cc" (cc) : [addr] "Q" (*addr), [mask] "I" (mask) ); diff --git a/arch/s390/include/asm/checksum.h b/arch/s390/include/asm/checksum.h index d86dea5900e7..7e83dc2d3b06 100644 --- a/arch/s390/include/asm/checksum.h +++ b/arch/s390/include/asm/checksum.h @@ -27,7 +27,7 @@ static inline __wsum cksm(const void *buff, int len, __wsum sum) kmsan_check_memory(buff, len); asm volatile( "0: cksm %[sum],%[rp]\n" - " jo 0b\n" + " jo 0b" : [sum] "+&d" (sum), [rp] "+&d" (rp.pair) : : "cc", "memory"); return sum; } diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index a9e2006033b7..008357996262 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h @@ -18,7 +18,7 @@ void __cmpxchg_called_with_bad_pointer(void); static __always_inline u32 __cs_asm(u64 ptr, u32 old, u32 new) { asm volatile( - " cs %[old],%[new],%[ptr]\n" + " cs %[old],%[new],%[ptr]" : [old] "+d" (old), [ptr] "+Q" (*(u32 *)ptr) : [new] "d" (new) : "memory", "cc"); @@ -28,7 +28,7 @@ static __always_inline u32 __cs_asm(u64 ptr, u32 old, u32 new) static __always_inline u64 __csg_asm(u64 ptr, u64 old, u64 new) { asm volatile( - " csg %[old],%[new],%[ptr]\n" + " csg %[old],%[new],%[ptr]" : [old] "+d" (old), [ptr] "+QS" (*(u64 *)ptr) : [new] "d" (new) : "memory", "cc"); @@ -126,7 +126,7 @@ static __always_inline u64 __arch_cmpxchg(u64 ptr, u64 old, u64 new, int size) } \ case 4: { \ asm volatile( \ - " cs %[__old],%[__new],%[__ptr]\n" \ + " cs %[__old],%[__new],%[__ptr]" \ : [__old] "+d" (*__oldp), \ [__ptr] "+Q" (*(ptr)), \ "=@cc" (__cc) \ @@ -136,7 +136,7 @@ static __always_inline u64 __arch_cmpxchg(u64 ptr, u64 old, u64 new, int size) } \ case 8: { \ asm volatile( \ - " csg %[__old],%[__new],%[__ptr]\n" \ + " csg %[__old],%[__new],%[__ptr]" \ : [__old] "+d" (*__oldp), \ [__ptr] "+QS" (*(ptr)), \ "=@cc" (__cc) \ @@ -241,7 +241,7 @@ static __always_inline u64 __arch_xchg(u64 ptr, u64 x, int size) static __always_inline u128 arch_cmpxchg128(volatile u128 *ptr, u128 old, u128 new) { asm volatile( - " cdsg %[old],%[new],%[ptr]\n" + " cdsg %[old],%[new],%[ptr]" : [old] "+d" (old), [ptr] "+QS" (*ptr) : [new] "d" (new) : "memory", "cc"); @@ -258,7 +258,7 @@ static __always_inline bool arch_try_cmpxchg128(volatile u128 *ptr, u128 *oldp, int cc; asm volatile( - " cdsg %[old],%[new],%[ptr]\n" + " cdsg %[old],%[new],%[ptr]" : [old] "+d" (*oldp), [ptr] "+QS" (*ptr), "=@cc" (cc) : [new] "d" (new) : "memory"); diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h index 4bc5317fbb12..a83683169d98 100644 --- a/arch/s390/include/asm/cpacf.h +++ b/arch/s390/include/asm/cpacf.h @@ -229,7 +229,7 @@ static __always_inline void __cpacf_query_rre(u32 opc, u8 r1, u8 r2, asm volatile( " la %%r1,%[pb]\n" " lghi %%r0,%[fc]\n" - " .insn rre,%[opc] << 16,%[r1],%[r2]\n" + " .insn rre,%[opc] << 16,%[r1],%[r2]" : [pb] "=R" (*pb) : [opc] "i" (opc), [fc] "i" (fc), [r1] "i" (r1), [r2] "i" (r2) @@ -242,7 +242,7 @@ static __always_inline void __cpacf_query_rrf(u32 opc, u8 r1, u8 r2, u8 r3, asm volatile( " la %%r1,%[pb]\n" " lghi %%r0,%[fc]\n" - " .insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],%[m4]\n" + " .insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],%[m4]" : [pb] "=R" (*pb) : [opc] "i" (opc), [fc] "i" (fc), [r1] "i" (r1), [r2] "i" (r2), [r3] "i" (r3), [m4] "i" (m4) @@ -416,7 +416,7 @@ static inline int cpacf_km(unsigned long func, void *param, " lgr 0,%[fc]\n" " lgr 1,%[pba]\n" "0: .insn rre,%[opc] << 16,%[dst],%[src]\n" - " brc 1,0b\n" /* handle partial completion */ + " brc 1,0b" /* handle partial completion */ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair) : [fc] "d" (func), [pba] "d" ((unsigned long)param), [opc] "i" (CPACF_KM) @@ -448,7 +448,7 @@ static inline int cpacf_kmc(unsigned long func, void *param, " lgr 0,%[fc]\n" " lgr 1,%[pba]\n" "0: .insn rre,%[opc] << 16,%[dst],%[src]\n" - " brc 1,0b\n" /* handle partial completion */ + " brc 1,0b" /* handle partial completion */ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair) : [fc] "d" (func), [pba] "d" ((unsigned long)param), [opc] "i" (CPACF_KMC) @@ -476,7 +476,7 @@ static inline void cpacf_kimd(unsigned long func, void *param, " lgr 0,%[fc]\n" " lgr 1,%[pba]\n" "0: .insn rrf,%[opc] << 16,0,%[src],8,0\n" - " brc 1,0b\n" /* handle partial completion */ + " brc 1,0b" /* handle partial completion */ : [src] "+&d" (s.pair) : [fc] "d" (func), [pba] "d" ((unsigned long)(param)), [opc] "i" (CPACF_KIMD) @@ -501,7 +501,7 @@ static inline void cpacf_klmd(unsigned long func, void *param, " lgr 0,%[fc]\n" " lgr 1,%[pba]\n" "0: .insn rrf,%[opc] << 16,0,%[src],8,0\n" - " brc 1,0b\n" /* handle partial completion */ + " brc 1,0b" /* handle partial completion */ : [src] "+&d" (s.pair) : [fc] "d" (func), [pba] "d" ((unsigned long)param), [opc] "i" (CPACF_KLMD) @@ -530,7 +530,7 @@ static inline int _cpacf_kmac(unsigned long *gr0, void *param, " lgr 1,%[pba]\n" "0: .insn rre,%[opc] << 16,0,%[src]\n" " brc 1,0b\n" /* handle partial completion */ - " lgr %[r0],0\n" + " lgr %[r0],0" : [r0] "+d" (*gr0), [src] "+&d" (s.pair) : [pba] "d" ((unsigned long)param), [opc] "i" (CPACF_KMAC) @@ -580,7 +580,7 @@ static inline int cpacf_kmctr(unsigned long func, void *param, u8 *dest, " lgr 0,%[fc]\n" " lgr 1,%[pba]\n" "0: .insn rrf,%[opc] << 16,%[dst],%[src],%[ctr],0\n" - " brc 1,0b\n" /* handle partial completion */ + " brc 1,0b" /* handle partial completion */ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair), [ctr] "+&d" (c.pair) : [fc] "d" (func), [pba] "d" ((unsigned long)param), @@ -614,7 +614,7 @@ static inline void cpacf_prno(unsigned long func, void *param, " lgr 0,%[fc]\n" " lgr 1,%[pba]\n" "0: .insn rre,%[opc] << 16,%[dst],%[seed]\n" - " brc 1,0b\n" /* handle partial completion */ + " brc 1,0b" /* handle partial completion */ : [dst] "+&d" (d.pair) : [fc] "d" (func), [pba] "d" ((unsigned long)param), [seed] "d" (s.pair), [opc] "i" (CPACF_PRNO) @@ -640,7 +640,7 @@ static inline void cpacf_trng(u8 *ucbuf, unsigned long ucbuf_len, asm volatile ( " lghi 0,%[fc]\n" "0: .insn rre,%[opc] << 16,%[ucbuf],%[cbuf]\n" - " brc 1,0b\n" /* handle partial completion */ + " brc 1,0b" /* handle partial completion */ : [ucbuf] "+&d" (u.pair), [cbuf] "+&d" (c.pair) : [fc] "K" (CPACF_PRNO_TRNG), [opc] "i" (CPACF_PRNO) : "cc", "memory", "0"); @@ -692,7 +692,7 @@ static inline void cpacf_pckmo(long func, void *param) asm volatile( " lgr 0,%[fc]\n" " lgr 1,%[pba]\n" - " .insn rre,%[opc] << 16,0,0\n" /* PCKMO opcode */ + " .insn rre,%[opc] << 16,0,0" /* PCKMO opcode */ : : [fc] "d" (func), [pba] "d" ((unsigned long)param), [opc] "i" (CPACF_PCKMO) @@ -725,7 +725,7 @@ static inline void cpacf_kma(unsigned long func, void *param, u8 *dest, " lgr 0,%[fc]\n" " lgr 1,%[pba]\n" "0: .insn rrf,%[opc] << 16,%[dst],%[src],%[aad],0\n" - " brc 1,0b\n" /* handle partial completion */ + " brc 1,0b" /* handle partial completion */ : [dst] "+&d" (d.pair), [src] "+&d" (s.pair), [aad] "+&d" (a.pair) : [fc] "d" (func), [pba] "d" ((unsigned long)param), diff --git a/arch/s390/include/asm/ctlreg.h b/arch/s390/include/asm/ctlreg.h index e93cc240a1ed..1765a0320933 100644 --- a/arch/s390/include/asm/ctlreg.h +++ b/arch/s390/include/asm/ctlreg.h @@ -100,7 +100,7 @@ struct ctlreg { BUILD_BUG_ON(sizeof(struct addrtype) != _esize); \ typecheck(struct ctlreg, array[0]); \ asm volatile( \ - " lctlg %[_low],%[_high],%[_arr]\n" \ + " lctlg %[_low],%[_high],%[_arr]" \ : \ : [_arr] "Q" (*(struct addrtype *)(&array)), \ [_low] "i" (low), [_high] "i" (high) \ @@ -119,7 +119,7 @@ struct ctlreg { BUILD_BUG_ON(sizeof(struct addrtype) != _esize); \ typecheck(struct ctlreg, array[0]); \ asm volatile( \ - " stctg %[_low],%[_high],%[_arr]\n" \ + " stctg %[_low],%[_high],%[_arr]" \ : [_arr] "=Q" (*(struct addrtype *)(&array)) \ : [_low] "i" (low), [_high] "i" (high)); \ } while (0) @@ -127,7 +127,7 @@ struct ctlreg { static __always_inline void local_ctl_load(unsigned int cr, struct ctlreg *reg) { asm volatile( - " lctlg %[cr],%[cr],%[reg]\n" + " lctlg %[cr],%[cr],%[reg]" : : [reg] "Q" (*reg), [cr] "i" (cr) : "memory"); @@ -136,7 +136,7 @@ static __always_inline void local_ctl_load(unsigned int cr, struct ctlreg *reg) static __always_inline void local_ctl_store(unsigned int cr, struct ctlreg *reg) { asm volatile( - " stctg %[cr],%[cr],%[reg]\n" + " stctg %[cr],%[cr],%[reg]" : [reg] "=Q" (*reg) : [cr] "i" (cr)); } diff --git a/arch/s390/include/asm/fpu-insn.h b/arch/s390/include/asm/fpu-insn.h index 135bb89c0a89..e99f8bca8e08 100644 --- a/arch/s390/include/asm/fpu-insn.h +++ b/arch/s390/include/asm/fpu-insn.h @@ -38,7 +38,7 @@ asm(".include \"asm/fpu-insn-asm.h\"\n"); static __always_inline void fpu_cefbr(u8 f1, s32 val) { - asm volatile("cefbr %[f1],%[val]\n" + asm volatile("cefbr %[f1],%[val]" : : [f1] "I" (f1), [val] "d" (val) : "memory"); @@ -48,7 +48,7 @@ static __always_inline unsigned long fpu_cgebr(u8 f2, u8 mode) { unsigned long val; - asm volatile("cgebr %[val],%[mode],%[f2]\n" + asm volatile("cgebr %[val],%[mode],%[f2]" : [val] "=d" (val) : [f2] "I" (f2), [mode] "I" (mode) : "memory"); @@ -57,7 +57,7 @@ static __always_inline unsigned long fpu_cgebr(u8 f2, u8 mode) static __always_inline void fpu_debr(u8 f1, u8 f2) { - asm volatile("debr %[f1],%[f2]\n" + asm volatile("debr %[f1],%[f2]" : : [f1] "I" (f1), [f2] "I" (f2) : "memory"); @@ -66,7 +66,7 @@ static __always_inline void fpu_debr(u8 f1, u8 f2) static __always_inline void fpu_ld(unsigned short fpr, freg_t *reg) { instrument_read(reg, sizeof(*reg)); - asm volatile("ld %[fpr],%[reg]\n" + asm volatile("ld %[fpr],%[reg]" : : [fpr] "I" (fpr), [reg] "Q" (reg->ui) : "memory"); @@ -74,7 +74,7 @@ static __always_inline void fpu_ld(unsigned short fpr, freg_t *reg) static __always_inline void fpu_ldgr(u8 f1, u32 val) { - asm volatile("ldgr %[f1],%[val]\n" + asm volatile("ldgr %[f1],%[val]" : : [f1] "I" (f1), [val] "d" (val) : "memory"); @@ -113,7 +113,7 @@ static inline void fpu_lfpc_safe(unsigned int *fpc) static __always_inline void fpu_std(unsigned short fpr, freg_t *reg) { instrument_write(reg, sizeof(*reg)); - asm volatile("std %[fpr],%[reg]\n" + asm volatile("std %[fpr],%[reg]" : [reg] "=Q" (reg->ui) : [fpr] "I" (fpr) : "memory"); @@ -181,7 +181,7 @@ static __always_inline void fpu_vgfmg(u8 v1, u8 v2, u8 v3) static __always_inline void fpu_vl(u8 v1, const void *vxr) { instrument_read(vxr, sizeof(__vector128)); - asm volatile("VL %[v1],%O[vxr],,%R[vxr]\n" + asm volatile("VL %[v1],%O[vxr],,%R[vxr]" : : [vxr] "Q" (*(__vector128 *)vxr), [v1] "I" (v1) @@ -195,7 +195,7 @@ static __always_inline void fpu_vl(u8 v1, const void *vxr) instrument_read(vxr, sizeof(__vector128)); asm volatile( " la 1,%[vxr]\n" - " VL %[v1],0,,1\n" + " VL %[v1],0,,1" : : [vxr] "R" (*(__vector128 *)vxr), [v1] "I" (v1) @@ -239,7 +239,7 @@ static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr) size = min(index + 1, sizeof(__vector128)); instrument_read(vxr, size); - asm volatile("VLL %[v1],%[index],%O[vxr],%R[vxr]\n" + asm volatile("VLL %[v1],%[index],%O[vxr],%R[vxr]" : : [vxr] "Q" (*(u8 *)vxr), [index] "d" (index), @@ -257,7 +257,7 @@ static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr) instrument_read(vxr, size); asm volatile( " la 1,%[vxr]\n" - " VLL %[v1],%[index],0,1\n" + " VLL %[v1],%[index],0,1" : : [vxr] "R" (*(u8 *)vxr), [index] "d" (index), @@ -277,7 +277,7 @@ static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr) } *_v = (void *)(_vxrs); \ \ instrument_read(_v, size); \ - asm volatile("VLM %[v1],%[v3],%O[vxrs],%R[vxrs]\n" \ + asm volatile("VLM %[v1],%[v3],%O[vxrs],%R[vxrs]" \ : \ : [vxrs] "Q" (*_v), \ [v1] "I" (_v1), [v3] "I" (_v3) \ @@ -297,7 +297,7 @@ static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr) instrument_read(_v, size); \ asm volatile( \ " la 1,%[vxrs]\n" \ - " VLM %[v1],%[v3],0,1\n" \ + " VLM %[v1],%[v3],0,1" \ : \ : [vxrs] "R" (*_v), \ [v1] "I" (_v1), [v3] "I" (_v3) \ @@ -360,7 +360,7 @@ static __always_inline void fpu_vsrlb(u8 v1, u8 v2, u8 v3) static __always_inline void fpu_vst(u8 v1, const void *vxr) { instrument_write(vxr, sizeof(__vector128)); - asm volatile("VST %[v1],%O[vxr],,%R[vxr]\n" + asm volatile("VST %[v1],%O[vxr],,%R[vxr]" : [vxr] "=Q" (*(__vector128 *)vxr) : [v1] "I" (v1) : "memory"); @@ -373,7 +373,7 @@ static __always_inline void fpu_vst(u8 v1, const void *vxr) instrument_write(vxr, sizeof(__vector128)); asm volatile( " la 1,%[vxr]\n" - " VST %[v1],0,,1\n" + " VST %[v1],0,,1" : [vxr] "=R" (*(__vector128 *)vxr) : [v1] "I" (v1) : "memory", "1"); @@ -389,7 +389,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr) size = min(index + 1, sizeof(__vector128)); instrument_write(vxr, size); - asm volatile("VSTL %[v1],%[index],%O[vxr],%R[vxr]\n" + asm volatile("VSTL %[v1],%[index],%O[vxr],%R[vxr]" : [vxr] "=Q" (*(u8 *)vxr) : [index] "d" (index), [v1] "I" (v1) : "memory"); @@ -405,7 +405,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr) instrument_write(vxr, size); asm volatile( " la 1,%[vxr]\n" - " VSTL %[v1],%[index],0,1\n" + " VSTL %[v1],%[index],0,1" : [vxr] "=R" (*(u8 *)vxr) : [index] "d" (index), [v1] "I" (v1) : "memory", "1"); @@ -423,7 +423,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr) } *_v = (void *)(_vxrs); \ \ instrument_write(_v, size); \ - asm volatile("VSTM %[v1],%[v3],%O[vxrs],%R[vxrs]\n" \ + asm volatile("VSTM %[v1],%[v3],%O[vxrs],%R[vxrs]" \ : [vxrs] "=Q" (*_v) \ : [v1] "I" (_v1), [v3] "I" (_v3) \ : "memory"); \ @@ -442,7 +442,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr) instrument_write(_v, size); \ asm volatile( \ " la 1,%[vxrs]\n" \ - " VSTM %[v1],%[v3],0,1\n" \ + " VSTM %[v1],%[v3],0,1" \ : [vxrs] "=R" (*_v) \ : [v1] "I" (_v1), [v3] "I" (_v3) \ : "memory", "1"); \ diff --git a/arch/s390/include/asm/kvm_para.h b/arch/s390/include/asm/kvm_para.h index df73a052760c..00cc8c916cfb 100644 --- a/arch/s390/include/asm/kvm_para.h +++ b/arch/s390/include/asm/kvm_para.h @@ -76,7 +76,7 @@ long __kvm_hypercall##args(unsigned long nr HYPERCALL_PARM_##args) \ HYPERCALL_REGS_##args; \ \ asm volatile ( \ - " diag 2,4,0x500\n" \ + " diag 2,4,0x500" \ : "=d" (__rc) \ : "d" (__nr) HYPERCALL_FMT_##args \ : "memory", "cc"); \ diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h index 96af7d964014..965886dfe954 100644 --- a/arch/s390/include/asm/percpu.h +++ b/arch/s390/include/asm/percpu.h @@ -73,13 +73,13 @@ if (__builtin_constant_p(val__) && \ ((szcast)val__ > -129) && ((szcast)val__ < 128)) { \ asm volatile( \ - op2 " %[ptr__],%[val__]\n" \ + op2 " %[ptr__],%[val__]" \ : [ptr__] "+Q" (*ptr__) \ : [val__] "i" ((szcast)val__) \ : "cc"); \ } else { \ asm volatile( \ - op1 " %[old__],%[val__],%[ptr__]\n" \ + op1 " %[old__],%[val__],%[ptr__]" \ : [old__] "=d" (old__), [ptr__] "+Q" (*ptr__) \ : [val__] "d" (val__) \ : "cc"); \ @@ -98,7 +98,7 @@ preempt_disable_notrace(); \ ptr__ = raw_cpu_ptr(&(pcp)); \ asm volatile( \ - op " %[old__],%[val__],%[ptr__]\n" \ + op " %[old__],%[val__],%[ptr__]" \ : [old__] "=d" (old__), [ptr__] "+Q" (*ptr__) \ : [val__] "d" (val__) \ : "cc"); \ @@ -117,7 +117,7 @@ preempt_disable_notrace(); \ ptr__ = raw_cpu_ptr(&(pcp)); \ asm volatile( \ - op " %[old__],%[val__],%[ptr__]\n" \ + op " %[old__],%[val__],%[ptr__]" \ : [old__] "=d" (old__), [ptr__] "+Q" (*ptr__) \ : [val__] "d" (val__) \ : "cc"); \ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 6a9c08b80eda..93e1034485d7 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -163,7 +163,7 @@ static __always_inline void __stackleak_poison(unsigned long erase_low, "2: stg %[poison],0(%[addr])\n" " j 4f\n" "3: mvc 8(1,%[addr]),0(%[addr])\n" - "4:\n" + "4:" : [addr] "+&a" (erase_low), [count] "+&d" (count), [tmp] "=&a" (tmp) : [poison] "d" (poison) : "memory", "cc" diff --git a/arch/s390/include/asm/rwonce.h b/arch/s390/include/asm/rwonce.h index 91fc24520e82..402325ec20f0 100644 --- a/arch/s390/include/asm/rwonce.h +++ b/arch/s390/include/asm/rwonce.h @@ -19,7 +19,7 @@ \ BUILD_BUG_ON(sizeof(x) != 16); \ asm volatile( \ - " lpq %[val],%[_x]\n" \ + " lpq %[val],%[_x]" \ : [val] "=d" (__u.val) \ : [_x] "QS" (x) \ : "memory"); \ diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index f9935db9fd76..b06b183b7246 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h @@ -98,7 +98,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp) kcsan_release(); asm_inline volatile( ALTERNATIVE("nop", ".insn rre,0xb2fa0000,7,0", ALT_FACILITY(49)) /* NIAI 7 */ - " mvhhi %[lock],0\n" + " mvhhi %[lock],0" : [lock] "=Q" (((unsigned short *)&lp->lock)[1]) : : "memory"); diff --git a/arch/s390/include/asm/stacktrace.h b/arch/s390/include/asm/stacktrace.h index 1d5ca13dc90f..810a6b9d9628 100644 --- a/arch/s390/include/asm/stacktrace.h +++ b/arch/s390/include/asm/stacktrace.h @@ -199,7 +199,7 @@ static __always_inline unsigned long get_stack_pointer(struct task_struct *task, " lg 15,%[_stack]\n" \ " stg %[_frame],%[_bc](15)\n" \ " brasl 14,%[_fn]\n" \ - " lgr 15,%[_prev]\n" \ + " lgr 15,%[_prev]" \ : [_prev] "=&d" (prev), CALL_FMT_##nr \ : [_stack] "R" (__stack), \ [_bc] "i" (offsetof(struct stack_frame, back_chain)), \ @@ -250,7 +250,7 @@ static __always_inline unsigned long get_stack_pointer(struct task_struct *task, " lra 14,0(1)\n" \ " lpswe %[psw_enter]\n" \ "0: lpswe 0(7)\n" \ - "1:\n" \ + "1:" \ : CALL_FMT_##nr, [psw_leave] "=Q" (psw_leave) \ : [psw_enter] "Q" (psw_enter) \ : "7", CALL_CLOBBER_##nr); \ diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h index f8f68f4ef255..238e721e5a22 100644 --- a/arch/s390/include/asm/string.h +++ b/arch/s390/include/asm/string.h @@ -125,7 +125,7 @@ static inline void *memscan(void *s, int c, size_t n) asm volatile( " lgr 0,%[c]\n" "0: srst %[ret],%[s]\n" - " jo 0b\n" + " jo 0b" : [ret] "+&a" (ret), [s] "+&a" (s) : [c] "d" (c) : "cc", "memory", "0"); diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index bd4cb00ccd5e..10ce5c4ccbd6 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h @@ -155,7 +155,7 @@ long syscall##nr(unsigned long syscall SYSCALL_PARM_##nr) \ SYSCALL_REGS_##nr; \ \ asm volatile ( \ - " svc 0\n" \ + " svc 0" \ : "=d" (rc) \ : "d" (r1) SYSCALL_FMT_##nr \ : "memory"); \ diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index 59dfb8780f62..49447b40f038 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h @@ -81,7 +81,7 @@ static inline void set_tod_programmable_field(u16 val) { asm volatile( " lgr 0,%[val]\n" - " sckpf\n" + " sckpf" : : [val] "d" ((unsigned long)val) : "0"); diff --git a/arch/s390/kernel/diag/diag310.c b/arch/s390/kernel/diag/diag310.c index d6a34454aa5a..f411562aa7f6 100644 --- a/arch/s390/kernel/diag/diag310.c +++ b/arch/s390/kernel/diag/diag310.c @@ -66,7 +66,7 @@ static inline unsigned long diag310(unsigned long subcode, unsigned long size, v union register_pair rp = { .even = (unsigned long)addr, .odd = size }; diag_stat_inc(DIAG_STAT_X310); - asm volatile("diag %[rp],%[subcode],0x310\n" + asm volatile("diag %[rp],%[subcode],0x310" : [rp] "+d" (rp.pair) : [subcode] "d" (subcode) : "memory"); diff --git a/arch/s390/kernel/diag/diag324.c b/arch/s390/kernel/diag/diag324.c index f0a8b4841fb9..fe325c2a2d0d 100644 --- a/arch/s390/kernel/diag/diag324.c +++ b/arch/s390/kernel/diag/diag324.c @@ -101,7 +101,7 @@ static unsigned long diag324(unsigned long subcode, void *addr) union register_pair rp = { .even = (unsigned long)addr }; diag_stat_inc(DIAG_STAT_X324); - asm volatile("diag %[rp],%[subcode],0x324\n" + asm volatile("diag %[rp],%[subcode],0x324" : [rp] "+d" (rp.pair) : [subcode] "d" (subcode) : "memory"); diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 7b529868789f..892fce2b7549 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -839,7 +839,7 @@ static void __init setup_control_program_code(void) return; diag_stat_inc(DIAG_STAT_X318); - asm volatile("diag %0,0,0x318\n" : : "d" (diag318_info.val)); + asm volatile("diag %0,0,0x318" : : "d" (diag318_info.val)); } /* diff --git a/arch/s390/kernel/skey.c b/arch/s390/kernel/skey.c index ba049fd103c2..cc869de6e3a5 100644 --- a/arch/s390/kernel/skey.c +++ b/arch/s390/kernel/skey.c @@ -11,7 +11,7 @@ static inline unsigned long load_real_address(unsigned long address) unsigned long real; asm volatile( - " lra %[real],0(%[address])\n" + " lra %[real],0(%[address])" : [real] "=d" (real) : [address] "a" (address) : "cc"); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index e88ebe5339fc..da84c0dc6b7e 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -340,7 +340,7 @@ static void pcpu_delegate(struct pcpu *pcpu, int cpu, "0: sigp 0,%0,%2 # sigp restart to target cpu\n" " brc 2,0b # busy, try again\n" "1: sigp 0,%1,%3 # sigp stop to current cpu\n" - " brc 2,1b # busy, try again\n" + " brc 2,1b # busy, try again" : : "d" (pcpu->address), "d" (source_cpu), "K" (SIGP_RESTART), "K" (SIGP_STOP) : "0", "1", "cc"); diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index bf6fa8b9ca73..7ef46a2ef84d 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -356,7 +356,7 @@ static __always_inline void pfcr_query(u8 (*query)[16]) { asm volatile( " lghi 0,0\n" - " .insn rsy,0xeb0000000016,0,0,%[query]\n" + " .insn rsy,0xeb0000000016,0,0,%[query]" : [query] "=QS" (*query) : : "cc", "0"); @@ -368,7 +368,7 @@ static __always_inline void __sortl_query(u8 (*query)[32]) " lghi 0,0\n" " la 1,%[query]\n" /* Parameter registers are ignored */ - " .insn rre,0xb9380000,2,4\n" + " .insn rre,0xb9380000,2,4" : [query] "=R" (*query) : : "cc", "0", "1"); @@ -380,7 +380,7 @@ static __always_inline void __dfltcc_query(u8 (*query)[32]) " lghi 0,0\n" " la 1,%[query]\n" /* Parameter registers are ignored */ - " .insn rrf,0xb9390000,2,4,6,0\n" + " .insn rrf,0xb9390000,2,4,6,0" : [query] "=R" (*query) : : "cc", "0", "1"); diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index ad9da4038511..10db1e56a811 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -96,7 +96,7 @@ static inline int arch_load_niai4(int *lock) asm_inline volatile( ALTERNATIVE("nop", ".insn rre,0xb2fa0000,4,0", ALT_FACILITY(49)) /* NIAI 4 */ - " l %[owner],%[lock]\n" + " l %[owner],%[lock]" : [owner] "=d" (owner) : [lock] "R" (*lock) : "memory"); return owner; } @@ -109,7 +109,7 @@ static inline int arch_try_cmpxchg_niai8(int *lock, int old, int new) asm_inline volatile( ALTERNATIVE("nop", ".insn rre,0xb2fa0000,8,0", ALT_FACILITY(49)) /* NIAI 8 */ - " cs %[old],%[new],%[lock]\n" + " cs %[old],%[new],%[lock]" : [old] "+d" (old), [lock] "+Q" (*lock), "=@cc" (cc) : [new] "d" (new) : "memory"); @@ -124,7 +124,7 @@ static inline int arch_try_cmpxchg_niai8(int *lock, int old, int new) asm_inline volatile( ALTERNATIVE("nop", ".insn rre,0xb2fa0000,8,0", ALT_FACILITY(49)) /* NIAI 8 */ - " cs %[old],%[new],%[lock]\n" + " cs %[old],%[new],%[lock]" : [old] "+d" (old), [lock] "+Q" (*lock) : [new] "d" (new) : "cc", "memory"); diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c index 099de76e8b1a..757f58960198 100644 --- a/arch/s390/lib/string.c +++ b/arch/s390/lib/string.c @@ -27,7 +27,7 @@ static inline char *__strend(const char *s) asm volatile( " lghi 0,0\n" "0: srst %[e],%[s]\n" - " jo 0b\n" + " jo 0b" : [e] "+&a" (e), [s] "+&a" (s) : : "cc", "memory", "0"); @@ -41,7 +41,7 @@ static inline char *__strnend(const char *s, size_t n) asm volatile( " lghi 0,0\n" "0: srst %[p],%[s]\n" - " jo 0b\n" + " jo 0b" : [p] "+&d" (p), [s] "+&a" (s) : : "cc", "memory", "0"); @@ -95,7 +95,7 @@ char *strcat(char *dest, const char *src) "0: srst %[dummy],%[dest]\n" " jo 0b\n" "1: mvst %[dummy],%[src]\n" - " jo 1b\n" + " jo 1b" : [dummy] "+&a" (dummy), [dest] "+&a" (dest), [src] "+&a" (src) : : "cc", "memory", "0"); @@ -291,7 +291,7 @@ void *memscan(void *s, int c, size_t n) asm volatile( " lgr 0,%[c]\n" "0: srst %[ret],%[s]\n" - " jo 0b\n" + " jo 0b" : [ret] "+&a" (ret), [s] "+&a" (s) : [c] "d" (c) : "cc", "memory", "0"); diff --git a/arch/s390/lib/test_unwind.c b/arch/s390/lib/test_unwind.c index 6e42100875e7..6bb3fa5bf925 100644 --- a/arch/s390/lib/test_unwind.c +++ b/arch/s390/lib/test_unwind.c @@ -150,7 +150,7 @@ static __always_inline struct pt_regs fake_pt_regs(void) regs.gprs[15] = current_stack_pointer; asm volatile( - "basr %[psw_addr],0\n" + "basr %[psw_addr],0" : [psw_addr] "=d" (regs.psw.addr)); return regs; } @@ -232,7 +232,7 @@ static noinline void test_unwind_kprobed_func(void) asm volatile( " nopr %%r7\n" "test_unwind_kprobed_insn:\n" - " nopr %%r7\n" + " nopr %%r7" :); } diff --git a/arch/s390/lib/xor.c b/arch/s390/lib/xor.c index ce7bcf7c0032..1721b73b7803 100644 --- a/arch/s390/lib/xor.c +++ b/arch/s390/lib/xor.c @@ -27,7 +27,7 @@ static void xor_xc_2(unsigned long bytes, unsigned long * __restrict p1, "1: exrl %0,2f\n" " j 3f\n" "2: xc 0(1,%1),0(%2)\n" - "3:\n" + "3:" : : "d" (bytes), "a" (p1), "a" (p2) : "0", "cc", "memory"); } @@ -53,7 +53,7 @@ static void xor_xc_3(unsigned long bytes, unsigned long * __restrict p1, " j 4f\n" "2: xc 0(1,%1),0(%2)\n" "3: xc 0(1,%1),0(%3)\n" - "4:\n" + "4:" : "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3) : : "0", "cc", "memory"); } @@ -84,7 +84,7 @@ static void xor_xc_4(unsigned long bytes, unsigned long * __restrict p1, "2: xc 0(1,%1),0(%2)\n" "3: xc 0(1,%1),0(%3)\n" "4: xc 0(1,%1),0(%4)\n" - "5:\n" + "5:" : "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4) : : "0", "cc", "memory"); } @@ -121,7 +121,7 @@ static void xor_xc_5(unsigned long bytes, unsigned long * __restrict p1, "3: xc 0(1,%1),0(%3)\n" "4: xc 0(1,%1),0(%4)\n" "5: xc 0(1,%1),0(%5)\n" - "6:\n" + "6:" : "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4), "+a" (p5) : : "0", "cc", "memory"); diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c index 44426e0f2944..cfd219fe495c 100644 --- a/arch/s390/mm/maccess.c +++ b/arch/s390/mm/maccess.c @@ -41,7 +41,7 @@ static notrace long s390_kernel_write_odd(void *dst, const void *src, size_t siz " ex %1,0(1)\n" " lg %1,0(%3)\n" " lra %0,0(%0)\n" - " sturg %1,%0\n" + " sturg %1,%0" : "+&a" (aligned), "+&a" (count), "=m" (tmp) : "a" (&tmp), "a" (&tmp[offset]), "a" (src) : "cc", "memory", "1"); diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c index 36700384fe6b..7ffadc0576ac 100644 --- a/arch/s390/mm/pgalloc.c +++ b/arch/s390/mm/pgalloc.c @@ -245,7 +245,7 @@ static inline unsigned long base_lra(unsigned long address) unsigned long real; asm volatile( - " lra %0,0(%1)\n" + " lra %0,0(%1)" : "=d" (real) : "a" (address) : "cc"); return real; } diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c index eb978c8012be..35ceb1bea1c6 100644 --- a/arch/s390/pci/pci_insn.c +++ b/arch/s390/pci/pci_insn.c @@ -145,7 +145,7 @@ int zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib) return -EIO; asm volatile( - ".insn rsy,0xeb00000000d1,%[ctl],%[isc],%[iib]\n" + ".insn rsy,0xeb00000000d1,%[ctl],%[isc],%[iib]" : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [iib] "Q" (*iib)); return 0; @@ -442,7 +442,7 @@ EXPORT_SYMBOL_GPL(zpci_write_block); static inline void __pciwb_mio(void) { - asm volatile (".insn rre,0xb9d50000,0,0\n"); + asm volatile (".insn rre,0xb9d50000,0,0"); } void zpci_barrier(void) diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index b5bd40f13c75..55e50d428aab 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -51,7 +51,7 @@ void sclp_early_wait_irq(void) " stg %[addr],%[psw_wait_addr]\n" " stg %[addr],%[psw_ext_addr]\n" " lpswe %[psw_wait]\n" - "0:\n" + "0:" : [addr] "=&d" (addr), [psw_wait_addr] "=Q" (psw_wait.addr), [psw_ext_addr] "=Q" (get_lowcore()->external_new_psw.addr) diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index fdab760f1f28..b7048f2b036e 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -167,7 +167,7 @@ static inline void cmf_activate(void *area, unsigned int onoff) asm volatile( " lgr 1,%[r1]\n" " lgr 2,%[mbo]\n" - " schm\n" + " schm" : : [r1] "d" ((unsigned long)onoff), [mbo] "d" (virt_to_phys(area)) From 9a0abc39450a3123fd52533a662fbd37e0d1508c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 26 Sep 2025 17:47:14 +0200 Subject: [PATCH 2220/2711] PM: runtime: Add auto-cleanup macros for "resume and get" operations It is generally useful to be able to automatically drop a device's runtime PM usage counter incremented by runtime PM operations that resume a device and bump up its usage counter [1]. To that end, add guard definition macros allowing pm_runtime_put() and pm_runtime_put_autosuspend() to be used for the auto-cleanup in those cases. Simply put, a piece of code like below: pm_runtime_get_sync(dev); ..... pm_runtime_put(dev); return 0; can be transformed with guard() like: guard(pm_runtime_active)(dev); ..... return 0; (see the pm_runtime_put() call is gone). However, it is better to do proper error handling in the majority of cases, so doing something like this instead of the above is recommended: ACQUIRE(pm_runtime_active_try, pm)(dev); if (ACQUIRE_ERR(pm_runtime_active_try, &pm)) return -ENXIO; ..... return 0; In all of the cases in which runtime PM is known to be enabled for the given device or the device can be regarded as operational (and so it can be accessed) with runtime PM disabled, a piece of code like: ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret; ..... pm_runtime_put(dev); return 0; can be changed as follows: ACQUIRE(pm_runtime_active_try, pm)(dev); ret = ACQUIRE_ERR(pm_runtime_active_try, &pm); if (ret < 0) return ret; ..... return 0; (again, see the pm_runtime_put() call is gone). Still, if the device cannot be accessed unless runtime PM has been enabled for it, the pm_runtime_active_try_enabled guard variant needs to be used, that is (in the context of the example above): ACQUIRE(pm_runtime_active_try_enabled, pm)(dev); ret = ACQUIRE_ERR(pm_runtime_active_try_enabled, &pm); if (ret < 0) return ret; ..... return 0; When the original code calls pm_runtime_put_autosuspend(), use one of the "auto" guard variants, pm_runtime_active_auto/_try/_enabled, so for example, a piece of code like: ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret; ..... pm_runtime_put_autosuspend(dev); return 0; will become: ACQUIRE(pm_runtime_active_auto_try_enabled, pm)(dev); ret = ACQUIRE_ERR(pm_runtime_active_auto_try_enabled, &pm); if (ret < 0) return ret; ..... return 0; Note that the cases in which the return value of pm_runtime_get_sync() is checked can also be handled with the help of the new guard macros. For example, a piece of code like: ret = pm_runtime_get_sync(dev); if (ret < 0) { pm_runtime_put(dev); return ret; } ..... pm_runtime_put(dev); return 0; can be rewritten as: ACQUIRE(pm_runtime_active_auto_try_enabled, pm)(dev); ret = ACQUIRE_ERR(pm_runtime_active_auto_try_enabled, &pm); if (ret < 0) return ret; ..... return 0; or pm_runtime_get_active_try can be used if transparent handling of disabled runtime PM is desirable. Link: https://lore.kernel.org/linux-pm/878qimv24u.wl-tiwai@suse.de/ [1] Link: https://lore.kernel.org/linux-pm/20250926150613.000073a4@huawei.com/ Signed-off-by: Rafael J. Wysocki Acked-by: Dan Williams Reviewed-by: Takashi Iwai Link: https://patch.msgid.link/2238241.irdbgypaU6@rafael.j.wysocki [ rjw: Fixed leftovers from the previous version in the changelog ] Reviewed-by: Jonathan Cameron Reviewed-by: Dhruva Gole Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 2 ++ include/linux/pm_runtime.h | 44 ++++++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index faa68bf9ef3d..0fc825066ede 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -799,6 +799,8 @@ static int rpm_resume(struct device *dev, int rpmflags) if (dev->power.runtime_status == RPM_ACTIVE && dev->power.last_status == RPM_ACTIVE) retval = 1; + else if (rpmflags & RPM_TRANSPARENT) + goto out; else retval = -EACCES; } diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index d1ff76e0e2d0..e5426bdd0c9f 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -21,6 +21,7 @@ #define RPM_GET_PUT 0x04 /* Increment/decrement the usage_count */ #define RPM_AUTO 0x08 /* Use autosuspend_delay */ +#define RPM_TRANSPARENT 0x10 /* Succeed if runtime PM is disabled */ /* * Use this for defining a set of PM operations to be used in all situations @@ -512,6 +513,19 @@ static inline int pm_runtime_get_sync(struct device *dev) return __pm_runtime_resume(dev, RPM_GET_PUT); } +static inline int pm_runtime_get_active(struct device *dev, int rpmflags) +{ + int ret; + + ret = __pm_runtime_resume(dev, RPM_GET_PUT | rpmflags); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; + } + + return 0; +} + /** * pm_runtime_resume_and_get - Bump up usage counter of a device and resume it. * @dev: Target device. @@ -522,15 +536,7 @@ static inline int pm_runtime_get_sync(struct device *dev) */ static inline int pm_runtime_resume_and_get(struct device *dev) { - int ret; - - ret = __pm_runtime_resume(dev, RPM_GET_PUT); - if (ret < 0) { - pm_runtime_put_noidle(dev); - return ret; - } - - return 0; + return pm_runtime_get_active(dev, 0); } /** @@ -610,6 +616,26 @@ static inline int pm_runtime_put_autosuspend(struct device *dev) return __pm_runtime_put_autosuspend(dev); } +DEFINE_GUARD(pm_runtime_active, struct device *, + pm_runtime_get_sync(_T), pm_runtime_put(_T)); +DEFINE_GUARD(pm_runtime_active_auto, struct device *, + pm_runtime_get_sync(_T), pm_runtime_put_autosuspend(_T)); +/* + * Use the following guards with ACQUIRE()/ACQUIRE_ERR(). + * + * The difference between the "_try" and "_try_enabled" variants is that the + * former do not produce an error when runtime PM is disabled for the given + * device. + */ +DEFINE_GUARD_COND(pm_runtime_active, _try, + pm_runtime_get_active(_T, RPM_TRANSPARENT)) +DEFINE_GUARD_COND(pm_runtime_active, _try_enabled, + pm_runtime_resume_and_get(_T)) +DEFINE_GUARD_COND(pm_runtime_active_auto, _try, + pm_runtime_get_active(_T, RPM_TRANSPARENT)) +DEFINE_GUARD_COND(pm_runtime_active_auto, _try_enabled, + pm_runtime_resume_and_get(_T)) + /** * pm_runtime_put_sync - Drop device usage counter and run "idle check" if 0. * @dev: Target device. From 8ff5aaa7b8c9fb3e66df6f440ee109d00f8d7a1b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 26 Sep 2025 18:24:05 +0200 Subject: [PATCH 2221/2711] PCI/sysfs: Use runtime PM guard macro for auto-cleanup Use the newly introduced pm_runtime_active_try guard to simplify the code and add the proper error handling for PM runtime resume errors. Based on an earlier patch from Takashi Iwai [1]. Link: https://patch.msgid.link/20250919163147.4743-3-tiwai@suse.de [1] Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki Reviewed-by: Takashi Iwai Reviewed-by: Jonathan Cameron --- drivers/pci/pci-sysfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5eea14c1f7f5..c96301026f01 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1475,8 +1475,9 @@ static ssize_t reset_method_store(struct device *dev, return count; } - pm_runtime_get_sync(dev); - struct device *pmdev __free(pm_runtime_put) = dev; + ACQUIRE(pm_runtime_active_try, pm)(dev); + if (ACQUIRE_ERR(pm_runtime_active_try, &pm)) + return -ENXIO; if (sysfs_streq(buf, "default")) { pci_init_reset_methods(pdev); From d5e58ce1fb0f13a9a0845851f267ede3551cd9fe Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 26 Sep 2025 18:26:40 +0200 Subject: [PATCH 2222/2711] PM: runtime: Drop DEFINE_FREE() for pm_runtime_put() The DEFINE_FREE() for pm_runtime_put has been superseded by recently introduced runtime PM auto-cleanup macros and its only user has been converted to using one of the new macros, so drop it. Signed-off-by: Rafael J. Wysocki Reviewed-by: Dhruva Gole Reviewed-by: Takashi Iwai Reviewed-by: Jonathan Cameron --- include/linux/pm_runtime.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index e5426bdd0c9f..edb8aed5ef62 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -563,8 +563,6 @@ static inline int pm_runtime_put(struct device *dev) return __pm_runtime_idle(dev, RPM_GET_PUT | RPM_ASYNC); } -DEFINE_FREE(pm_runtime_put, struct device *, if (_T) pm_runtime_put(_T)) - /** * __pm_runtime_put_autosuspend - Drop device usage counter and queue autosuspend if 0. * @dev: Target device. From 5c34f2b6f89ad4f31db15f9c658b597e23bacdf8 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Sun, 28 Sep 2025 09:31:10 +0800 Subject: [PATCH 2223/2711] nvdimm: Remove duplicate linux/slab.h header ./drivers/nvdimm/bus.c: linux/slab.h is included more than once. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=25516 Signed-off-by: Jiapeng Chong Signed-off-by: Ira Weiny --- drivers/nvdimm/bus.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index ad3a0493f474..87178a53ff9c 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include From 99da5bf3dd6a8cb951adcace6153c34c86547811 Mon Sep 17 00:00:00 2001 From: Lenny Szubowicz Date: Tue, 16 Sep 2025 15:38:53 -0400 Subject: [PATCH 2224/2711] efi/x86: Memory protection on EfiGcdMemoryTypeMoreReliable Check for needed memory protection changes on EFI DXE GCD memory space descriptors with type EfiGcdMemoryTypeMoreReliable in addition to EfiGcdMemoryTypeSystemMemory. This fixes a fault on entry into the decompressed kernel from the EFI stub that occurs when the memory allocated for the decompressed kernel is more reliable memory, has NX/XP set, and the kernel needs to use the EFI DXE protocol to adjust memory protections. The memory descriptors returned by the DXE protocol GetMemorySpaceDescriptor() service use a different GCD memory type to distinguish more reliable memory ranges from their conventional counterparts. This is in contrast to the EFI memory descriptors returned by the EFI GetMemoryMap() service which use the EFI_MEMORY_MORE_RELIABLE memory attributes flag to identify EFI_CONVENTIONAL_MEMORY type regions that have this additional property. Signed-off-by: Lenny Szubowicz Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/x86-stub.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c index cafc90d4caaf..0f60a12401c2 100644 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@ -300,7 +300,7 @@ efi_status_t efi_adjust_memory_range_protection(unsigned long start, return EFI_SUCCESS; /* - * Don't modify memory region attributes, they are + * Don't modify memory region attributes, if they are * already suitable, to lower the possibility to * encounter firmware bugs. */ @@ -315,11 +315,13 @@ efi_status_t efi_adjust_memory_range_protection(unsigned long start, next = desc.base_address + desc.length; /* - * Only system memory is suitable for trampoline/kernel image placement, - * so only this type of memory needs its attributes to be modified. + * Only system memory and more reliable memory are suitable for + * trampoline/kernel image placement. So only those memory types + * may need to have attributes modified. */ - if (desc.gcd_memory_type != EfiGcdMemoryTypeSystemMemory || + if ((desc.gcd_memory_type != EfiGcdMemoryTypeSystemMemory && + desc.gcd_memory_type != EfiGcdMemoryTypeMoreReliable) || (desc.attributes & (EFI_MEMORY_RO | EFI_MEMORY_XP)) == 0) continue; From e4a0cf9f1d90e6888e5373da3314f761024f6c97 Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Thu, 18 Sep 2025 00:53:59 +0300 Subject: [PATCH 2225/2711] mtd: spinand: fix direct mapping creation sizes Continuous mode is only supported for data reads, thus writing requires only single flash page mapping. Signed-off-by: Mikhail Kshevetskiy Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index ea47028d021a..27af973bc12f 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1097,18 +1097,13 @@ static int spinand_create_dirmap(struct spinand_device *spinand, unsigned int plane) { struct nand_device *nand = spinand_to_nand(spinand); - struct spi_mem_dirmap_info info = { - .length = nanddev_page_size(nand) + - nanddev_per_page_oobsize(nand), - }; + struct spi_mem_dirmap_info info = { 0 }; struct spi_mem_dirmap_desc *desc; - if (spinand->cont_read_possible) - info.length = nanddev_eraseblock_size(nand); - /* The plane number is passed in MSB just above the column address */ info.offset = plane << fls(nand->memorg.pagesize); + info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); info.op_tmpl = *spinand->op_templates.update_cache; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, spinand->spimem, &info); @@ -1117,6 +1112,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc = desc; + if (spinand->cont_read_possible) + info.length = nanddev_eraseblock_size(nand); info.op_tmpl = *spinand->op_templates.read_cache; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, spinand->spimem, &info); @@ -1132,6 +1129,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand, return 0; } + info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); info.op_tmpl = *spinand->op_templates.update_cache; info.op_tmpl.data.ecc = true; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, @@ -1141,6 +1139,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc_ecc = desc; + if (spinand->cont_read_possible) + info.length = nanddev_eraseblock_size(nand); info.op_tmpl = *spinand->op_templates.read_cache; info.op_tmpl.data.ecc = true; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, From 004f8ea0d9917398aabff7388b3bf62a84a4088b Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Thu, 18 Sep 2025 00:54:00 +0300 Subject: [PATCH 2226/2711] mtd: spinand: try a regular dirmap if creating a dirmap for continuous reading fails Continuous reading may result in multiple flash pages reading in one operation. Typically only one flash page has read/written (a little bit more than 2-4 Kb), but continuous reading requires the spi controller to read up to 512 Kb in one operation without toggling CS in beetween. Roughly speaking spi controllers can be divided on 2 categories: * spi controllers without dirmap acceleration support * spi controllers with dirmap acceleration support Firt of them will have issues with continuous reading if restriction on the transfer length is implemented in the adjust_op_size() handler. Second group often supports acceleration of single page only reading. Thus enabling of continuous reading can break flash reading. This patch tries to create dirmap for continuous reading first and fallback to regular reading if spi controller refuses to create it. Signed-off-by: Mikhail Kshevetskiy Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 43 ++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 27af973bc12f..58ec85c98ab8 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1093,6 +1093,39 @@ static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs) return ret; } +static struct spi_mem_dirmap_desc *spinand_create_rdesc( + struct spinand_device *spinand, + struct spi_mem_dirmap_info *info) +{ + struct nand_device *nand = spinand_to_nand(spinand); + struct spi_mem_dirmap_desc *desc = NULL; + + if (spinand->cont_read_possible) { + /* + * spi controller may return an error if info->length is + * too large + */ + info->length = nanddev_eraseblock_size(nand); + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, info); + } + + if (IS_ERR_OR_NULL(desc)) { + /* + * continuous reading is not supported by flash or + * its spi controller, use regular reading + */ + spinand->cont_read_possible = false; + + info->length = nanddev_page_size(nand) + + nanddev_per_page_oobsize(nand); + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, info); + } + + return desc; +} + static int spinand_create_dirmap(struct spinand_device *spinand, unsigned int plane) { @@ -1112,11 +1145,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc = desc; - if (spinand->cont_read_possible) - info.length = nanddev_eraseblock_size(nand); info.op_tmpl = *spinand->op_templates.read_cache; - desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, - spinand->spimem, &info); + desc = spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); @@ -1139,12 +1169,9 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc_ecc = desc; - if (spinand->cont_read_possible) - info.length = nanddev_eraseblock_size(nand); info.op_tmpl = *spinand->op_templates.read_cache; info.op_tmpl.data.ecc = true; - desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, - spinand->spimem, &info); + desc = spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); From 010dc7f2dd6a0078ade3f88f627ed5fbf45ceb94 Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Thu, 18 Sep 2025 00:54:01 +0300 Subject: [PATCH 2227/2711] mtd: spinand: repeat reading in regular mode if continuous reading fails Continuous reading may result in multiple flash pages reading in one operation. Unfortunately, not all spinand controllers support such large reading. They will read less data. Unfortunately, the operation can't be continued. In this case: * disable continuous reading on this (not good enough) spi controller * repeat reading in regular mode. Signed-off-by: Mikhail Kshevetskiy Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 58ec85c98ab8..f92133b8e1a6 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -430,8 +430,16 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, * Dirmap accesses are allowed to toggle the CS. * Toggling the CS during a continuous read is forbidden. */ - if (nbytes && req->continuous) - return -EIO; + if (nbytes && req->continuous) { + /* + * Spi controller with broken support of continuous + * reading was detected. Disable future use of + * continuous reading and return -EAGAIN to retry + * reading within regular mode. + */ + spinand->cont_read_possible = false; + return -EAGAIN; + } } if (req->datalen) @@ -899,10 +907,19 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from, old_stats = mtd->ecc_stats; - if (spinand_use_cont_read(mtd, from, ops)) + if (spinand_use_cont_read(mtd, from, ops)) { ret = spinand_mtd_continuous_page_read(mtd, from, ops, &max_bitflips); - else + if (ret == -EAGAIN && !spinand->cont_read_possible) { + /* + * Spi controller with broken support of continuous + * reading was detected (see spinand_read_from_cache_op()), + * repeat reading in regular mode. + */ + ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips); + } + } else { ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips); + } if (ops->stats) { ops->stats->uncorrectable_errors += From 12bfcb84dc0852c97baff9ac1c0292a9db90c367 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Fri, 19 Sep 2025 03:52:00 -0400 Subject: [PATCH 2228/2711] dt-bindings: mtd: Add realtek,rtl9301-ecc Add a dtschema for the ECC engine on the Realtek RTL93xx SoCs. The engine supports BCH6 and BCH12 parity for 512 byte blocks. The hardware can make use of interrupts but this is not yet supported by the driver. From the known datasheets it is connected to the LXB (lexra bus) and propably depends on its clock. Provide an optional clock property that can describe the relation. Signed-off-by: Markus Stockhausen Reviewed-by: Rob Herring (Arm) Signed-off-by: Miquel Raynal --- .../bindings/mtd/realtek,rtl9301-ecc.yaml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/realtek,rtl9301-ecc.yaml diff --git a/Documentation/devicetree/bindings/mtd/realtek,rtl9301-ecc.yaml b/Documentation/devicetree/bindings/mtd/realtek,rtl9301-ecc.yaml new file mode 100644 index 000000000000..55b35c3db0ff --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/realtek,rtl9301-ecc.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/realtek,rtl9301-ecc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek SoCs NAND ECC engine + +maintainers: + - Markus Stockhausen + +properties: + compatible: + const: realtek,rtl9301-ecc + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <1>; + #size-cells = <1>; + + ecc0: ecc@1a600 { + compatible = "realtek,rtl9301-ecc"; + reg = <0x1a600 0x54>; + }; + }; From 3148d0e5b1c5733d69ec51b70c8280e46488750a Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Fri, 19 Sep 2025 03:52:01 -0400 Subject: [PATCH 2229/2711] mtd: nand: realtek-ecc: Add Realtek external ECC engine support The Realtek RTl93xx switch SoC series has a built in ECC controller that can provide BCH6 or BCH12 over 512 data and 6 tag bytes. It generates 10 (BCH6) or 20 (BCH12) bytes of parity. This engine will most likely work in conjunction with the Realtek spi-mem based NAND controller but can work on its own. Therefore the initial implementation will be of type external. Remark! The engine can support any data blocks that are multiples of 512 bytes. For now limit it to data+oob layouts that have been analyzed from existing devices. This way it keeps compatibility and pre-existing vendor data can be read. Signed-off-by: Markus Stockhausen Signed-off-by: Miquel Raynal --- drivers/mtd/nand/Kconfig | 8 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/ecc-realtek.c | 464 +++++++++++++++++++++++++++++++++ 3 files changed, 473 insertions(+) create mode 100644 drivers/mtd/nand/ecc-realtek.c diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 5b0c2c95f10c..4a17271076bc 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -61,6 +61,14 @@ config MTD_NAND_ECC_MEDIATEK help This enables support for the hardware ECC engine from Mediatek. +config MTD_NAND_ECC_REALTEK + tristate "Realtek RTL93xx hardware ECC engine" + depends on HAS_IOMEM + depends on MACH_REALTEK_RTL || COMPILE_TEST + select MTD_NAND_ECC + help + This enables support for the hardware ECC engine from Realtek. + endmenu endmenu diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 44913ff1bf12..2e0e56267718 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -3,6 +3,7 @@ nandcore-objs := core.o bbt.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o +obj-$(CONFIG_MTD_NAND_ECC_REALTEK) += ecc-realtek.o obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o obj-y += onenand/ diff --git a/drivers/mtd/nand/ecc-realtek.c b/drivers/mtd/nand/ecc-realtek.c new file mode 100644 index 000000000000..7d718934c909 --- /dev/null +++ b/drivers/mtd/nand/ecc-realtek.c @@ -0,0 +1,464 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support for Realtek hardware ECC engine in RTL93xx SoCs + */ + +#include +#include +#include +#include +#include +#include + +/* + * The Realtek ECC engine has two operation modes. + * + * - BCH6 : Generate 10 ECC bytes from 512 data bytes plus 6 free bytes + * - BCH12 : Generate 20 ECC bytes from 512 data bytes plus 6 free bytes + * + * It can run for arbitrary NAND flash chips with different block and OOB sizes. Currently there + * are only two known devices in the wild that have NAND flash and make use of this ECC engine + * (Linksys LGS328C & LGS352C). To keep compatibility with vendor firmware, new modes can only + * be added when new data layouts have been analyzed. For now allow BCH6 on flash with 2048 byte + * blocks and 64 bytes oob. + * + * This driver aligns with kernel ECC naming conventions. Neverthless a short notice on the + * Realtek naming conventions for the different structures in the OOB area. + * + * - BBI : Bad block indicator. The first two bytes of OOB. Protected by ECC! + * - tag : 6 User/free bytes. First tag "contains" 2 bytes BBI. Protected by ECC! + * - syndrome : ECC/parity bytes + * + * Altogether this gives currently the following block layout. + * + * +------+------+------+------+-----+------+------+------+------+-----+-----+-----+-----+ + * | 512 | 512 | 512 | 512 | 2 | 4 | 6 | 6 | 6 | 10 | 10 | 10 | 10 | + * +------+------+------+------+-----+------+------+------+------+-----+-----+-----+-----+ + * | data | data | data | data | BBI | free | free | free | free | ECC | ECC | ECC | ECC | + * +------+------+------+------+-----+------+------+------+------+-----+-----+-----+-----+ + */ + +#define RTL_ECC_ALLOWED_PAGE_SIZE 2048 +#define RTL_ECC_ALLOWED_OOB_SIZE 64 +#define RTL_ECC_ALLOWED_STRENGTH 6 + +#define RTL_ECC_BLOCK_SIZE 512 +#define RTL_ECC_FREE_SIZE 6 +#define RTL_ECC_PARITY_SIZE_BCH6 10 +#define RTL_ECC_PARITY_SIZE_BCH12 20 + +/* + * The engine is fed with two DMA regions. One for data (always 512 bytes) and one for free bytes + * and parity (either 16 bytes for BCH6 or 26 bytes for BCH12). Start and length of each must be + * aligned to a multiple of 4. + */ + +#define RTL_ECC_DMA_FREE_PARITY_SIZE ALIGN(RTL_ECC_FREE_SIZE + RTL_ECC_PARITY_SIZE_BCH12, 4) +#define RTL_ECC_DMA_SIZE (RTL_ECC_BLOCK_SIZE + RTL_ECC_DMA_FREE_PARITY_SIZE) + +#define RTL_ECC_CFG 0x00 +#define RTL_ECC_BCH6 0 +#define RTL_ECC_BCH12 BIT(28) +#define RTL_ECC_DMA_PRECISE BIT(12) +#define RTL_ECC_BURST_128 GENMASK(1, 0) +#define RTL_ECC_DMA_TRIGGER 0x08 +#define RTL_ECC_OP_DECODE 0 +#define RTL_ECC_OP_ENCODE BIT(0) +#define RTL_ECC_DMA_START 0x0c +#define RTL_ECC_DMA_TAG 0x10 +#define RTL_ECC_STATUS 0x14 +#define RTL_ECC_CORR_COUNT GENMASK(19, 12) +#define RTL_ECC_RESULT BIT(8) +#define RTL_ECC_ALL_ONE BIT(4) +#define RTL_ECC_OP_STATUS BIT(0) + +struct rtl_ecc_engine { + struct device *dev; + struct nand_ecc_engine engine; + struct mutex lock; + char *buf; + dma_addr_t buf_dma; + struct regmap *regmap; +}; + +struct rtl_ecc_ctx { + struct rtl_ecc_engine * rtlc; + struct nand_ecc_req_tweak_ctx req_ctx; + int steps; + int bch_mode; + int strength; + int parity_size; +}; + +static const struct regmap_config rtl_ecc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static inline void *nand_to_ctx(struct nand_device *nand) +{ + return nand->ecc.ctx.priv; +} + +static inline struct rtl_ecc_engine *nand_to_rtlc(struct nand_device *nand) +{ + struct nand_ecc_engine *eng = nand->ecc.engine; + + return container_of(eng, struct rtl_ecc_engine, engine); +} + +static int rtl_ecc_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + struct rtl_ecc_ctx *ctx = nand_to_ctx(nand); + + if (section < 0 || section >= ctx->steps) + return -ERANGE; + + oobregion->offset = ctx->steps * RTL_ECC_FREE_SIZE + section * ctx->parity_size; + oobregion->length = ctx->parity_size; + + return 0; +} + +static int rtl_ecc_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + struct rtl_ecc_ctx *ctx = nand_to_ctx(nand); + int bbm; + + if (section < 0 || section >= ctx->steps) + return -ERANGE; + + /* reserve 2 BBM bytes in first block */ + bbm = section ? 0 : 2; + oobregion->offset = section * RTL_ECC_FREE_SIZE + bbm; + oobregion->length = RTL_ECC_FREE_SIZE - bbm; + + return 0; +} + +static const struct mtd_ooblayout_ops rtl_ecc_ooblayout_ops = { + .ecc = rtl_ecc_ooblayout_ecc, + .free = rtl_ecc_ooblayout_free, +}; + +static void rtl_ecc_kick_engine(struct rtl_ecc_ctx *ctx, int operation) +{ + struct rtl_ecc_engine *rtlc = ctx->rtlc; + + regmap_write(rtlc->regmap, RTL_ECC_CFG, + ctx->bch_mode | RTL_ECC_BURST_128 | RTL_ECC_DMA_PRECISE); + + regmap_write(rtlc->regmap, RTL_ECC_DMA_START, rtlc->buf_dma); + regmap_write(rtlc->regmap, RTL_ECC_DMA_TAG, rtlc->buf_dma + RTL_ECC_BLOCK_SIZE); + regmap_write(rtlc->regmap, RTL_ECC_DMA_TRIGGER, operation); +} + +static int rtl_ecc_wait_for_engine(struct rtl_ecc_ctx *ctx) +{ + struct rtl_ecc_engine *rtlc = ctx->rtlc; + int ret, status, bitflips; + bool all_one; + + /* + * The ECC engine needs 6-8 us to encode/decode a BCH6 syndrome for 512 bytes of data + * and 6 free bytes. In case the NAND area has been erased and all data and oob is + * set to 0xff, decoding takes 30us (reason unknown). Although the engine can trigger + * interrupts when finished, use active polling for now. 12 us maximum wait time has + * proven to be a good tradeoff between performance and overhead. + */ + + ret = regmap_read_poll_timeout(rtlc->regmap, RTL_ECC_STATUS, status, + !(status & RTL_ECC_OP_STATUS), 12, 1000000); + if (ret) + return ret; + + ret = FIELD_GET(RTL_ECC_RESULT, status); + all_one = FIELD_GET(RTL_ECC_ALL_ONE, status); + bitflips = FIELD_GET(RTL_ECC_CORR_COUNT, status); + + /* For erased blocks (all bits one) error status can be ignored */ + if (all_one) + ret = 0; + + return ret ? -EBADMSG : bitflips; +} + +static int rtl_ecc_run_engine(struct rtl_ecc_ctx *ctx, char *data, char *free, + char *parity, int operation) +{ + struct rtl_ecc_engine *rtlc = ctx->rtlc; + char *buf_parity = rtlc->buf + RTL_ECC_BLOCK_SIZE + RTL_ECC_FREE_SIZE; + char *buf_free = rtlc->buf + RTL_ECC_BLOCK_SIZE; + char *buf_data = rtlc->buf; + int ret; + + mutex_lock(&rtlc->lock); + + memcpy(buf_data, data, RTL_ECC_BLOCK_SIZE); + memcpy(buf_free, free, RTL_ECC_FREE_SIZE); + memcpy(buf_parity, parity, ctx->parity_size); + + dma_sync_single_for_device(rtlc->dev, rtlc->buf_dma, RTL_ECC_DMA_SIZE, DMA_TO_DEVICE); + rtl_ecc_kick_engine(ctx, operation); + ret = rtl_ecc_wait_for_engine(ctx); + dma_sync_single_for_cpu(rtlc->dev, rtlc->buf_dma, RTL_ECC_DMA_SIZE, DMA_FROM_DEVICE); + + if (ret >= 0) { + memcpy(data, buf_data, RTL_ECC_BLOCK_SIZE); + memcpy(free, buf_free, RTL_ECC_FREE_SIZE); + memcpy(parity, buf_parity, ctx->parity_size); + } + + mutex_unlock(&rtlc->lock); + + return ret; +} + +static int rtl_ecc_prepare_io_req(struct nand_device *nand, struct nand_page_io_req *req) +{ + struct rtl_ecc_engine *rtlc = nand_to_rtlc(nand); + struct rtl_ecc_ctx *ctx = nand_to_ctx(nand); + char *data, *free, *parity; + int ret = 0; + + if (req->mode == MTD_OPS_RAW) + return 0; + + nand_ecc_tweak_req(&ctx->req_ctx, req); + + if (req->type == NAND_PAGE_READ) + return 0; + + free = req->oobbuf.in; + data = req->databuf.in; + parity = req->oobbuf.in + ctx->steps * RTL_ECC_FREE_SIZE; + + for (int i = 0; i < ctx->steps; i++) { + ret |= rtl_ecc_run_engine(ctx, data, free, parity, RTL_ECC_OP_ENCODE); + + free += RTL_ECC_FREE_SIZE; + data += RTL_ECC_BLOCK_SIZE; + parity += ctx->parity_size; + } + + if (unlikely(ret)) + dev_dbg(rtlc->dev, "ECC calculation failed\n"); + + return ret ? -EBADMSG : 0; +} + +static int rtl_ecc_finish_io_req(struct nand_device *nand, struct nand_page_io_req *req) +{ + struct rtl_ecc_engine *rtlc = nand_to_rtlc(nand); + struct rtl_ecc_ctx *ctx = nand_to_ctx(nand); + struct mtd_info *mtd = nanddev_to_mtd(nand); + char *data, *free, *parity; + bool failure = false; + int bitflips = 0; + + if (req->mode == MTD_OPS_RAW) + return 0; + + if (req->type == NAND_PAGE_WRITE) { + nand_ecc_restore_req(&ctx->req_ctx, req); + return 0; + } + + free = req->oobbuf.in; + data = req->databuf.in; + parity = req->oobbuf.in + ctx->steps * RTL_ECC_FREE_SIZE; + + for (int i = 0 ; i < ctx->steps; i++) { + int ret = rtl_ecc_run_engine(ctx, data, free, parity, RTL_ECC_OP_DECODE); + + if (unlikely(ret < 0)) + /* ECC totally fails for bitflips in erased blocks */ + ret = nand_check_erased_ecc_chunk(data, RTL_ECC_BLOCK_SIZE, + parity, ctx->parity_size, + free, RTL_ECC_FREE_SIZE, + ctx->strength); + if (unlikely(ret < 0)) { + failure = true; + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += ret; + bitflips = max_t(unsigned int, bitflips, ret); + } + + free += RTL_ECC_FREE_SIZE; + data += RTL_ECC_BLOCK_SIZE; + parity += ctx->parity_size; + } + + nand_ecc_restore_req(&ctx->req_ctx, req); + + if (unlikely(failure)) + dev_dbg(rtlc->dev, "ECC correction failed\n"); + else if (unlikely(bitflips > 2)) + dev_dbg(rtlc->dev, "%d bitflips detected\n", bitflips); + + return failure ? -EBADMSG : bitflips; +} + +static int rtl_ecc_check_support(struct nand_device *nand) +{ + struct mtd_info *mtd = nanddev_to_mtd(nand); + struct device *dev = nand->ecc.engine->dev; + + if (mtd->oobsize != RTL_ECC_ALLOWED_OOB_SIZE || + mtd->writesize != RTL_ECC_ALLOWED_PAGE_SIZE) { + dev_err(dev, "only flash geometry data=%d, oob=%d supported\n", + RTL_ECC_ALLOWED_PAGE_SIZE, RTL_ECC_ALLOWED_OOB_SIZE); + return -EINVAL; + } + + if (nand->ecc.user_conf.algo != NAND_ECC_ALGO_BCH || + nand->ecc.user_conf.strength != RTL_ECC_ALLOWED_STRENGTH || + nand->ecc.user_conf.placement != NAND_ECC_PLACEMENT_OOB || + nand->ecc.user_conf.step_size != RTL_ECC_BLOCK_SIZE) { + dev_err(dev, "only algo=bch, strength=%d, placement=oob, step=%d supported\n", + RTL_ECC_ALLOWED_STRENGTH, RTL_ECC_BLOCK_SIZE); + return -EINVAL; + } + + return 0; +} + +static int rtl_ecc_init_ctx(struct nand_device *nand) +{ + struct nand_ecc_props *conf = &nand->ecc.ctx.conf; + struct rtl_ecc_engine *rtlc = nand_to_rtlc(nand); + struct mtd_info *mtd = nanddev_to_mtd(nand); + int strength = nand->ecc.user_conf.strength; + struct device *dev = nand->ecc.engine->dev; + struct rtl_ecc_ctx *ctx; + int ret; + + ret = rtl_ecc_check_support(nand); + if (ret) + return ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + nand->ecc.ctx.priv = ctx; + mtd_set_ooblayout(mtd, &rtl_ecc_ooblayout_ops); + + conf->algo = NAND_ECC_ALGO_BCH; + conf->strength = strength; + conf->step_size = RTL_ECC_BLOCK_SIZE; + conf->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; + + ctx->rtlc = rtlc; + ctx->steps = mtd->writesize / RTL_ECC_BLOCK_SIZE; + ctx->strength = strength; + ctx->bch_mode = strength == 6 ? RTL_ECC_BCH6 : RTL_ECC_BCH12; + ctx->parity_size = strength == 6 ? RTL_ECC_PARITY_SIZE_BCH6 : RTL_ECC_PARITY_SIZE_BCH12; + + ret = nand_ecc_init_req_tweaking(&ctx->req_ctx, nand); + if (ret) + return ret; + + dev_dbg(dev, "using bch%d with geometry data=%dx%d, free=%dx6, parity=%dx%d", + conf->strength, ctx->steps, conf->step_size, + ctx->steps, ctx->steps, ctx->parity_size); + + return 0; +} + +static void rtl_ecc_cleanup_ctx(struct nand_device *nand) +{ + struct rtl_ecc_ctx *ctx = nand_to_ctx(nand); + + if (ctx) + nand_ecc_cleanup_req_tweaking(&ctx->req_ctx); +} + +static struct nand_ecc_engine_ops rtl_ecc_engine_ops = { + .init_ctx = rtl_ecc_init_ctx, + .cleanup_ctx = rtl_ecc_cleanup_ctx, + .prepare_io_req = rtl_ecc_prepare_io_req, + .finish_io_req = rtl_ecc_finish_io_req, +}; + +static int rtl_ecc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtl_ecc_engine *rtlc; + void __iomem *base; + int ret; + + rtlc = devm_kzalloc(dev, sizeof(*rtlc), GFP_KERNEL); + if (!rtlc) + return -ENOMEM; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + ret = devm_mutex_init(dev, &rtlc->lock); + if (ret) + return ret; + + rtlc->regmap = devm_regmap_init_mmio(dev, base, &rtl_ecc_regmap_config); + if (IS_ERR(rtlc->regmap)) + return PTR_ERR(rtlc->regmap); + + /* + * Focus on simplicity and use a preallocated DMA buffer for data exchange with the + * engine. For now make it a noncoherent memory model as invalidating/flushing caches + * is faster than reading/writing uncached memory on the known architectures. + */ + + rtlc->buf = dma_alloc_noncoherent(dev, RTL_ECC_DMA_SIZE, &rtlc->buf_dma, + DMA_BIDIRECTIONAL, GFP_KERNEL); + if (IS_ERR(rtlc->buf)) + return PTR_ERR(rtlc->buf); + + rtlc->dev = dev; + rtlc->engine.dev = dev; + rtlc->engine.ops = &rtl_ecc_engine_ops; + rtlc->engine.integration = NAND_ECC_ENGINE_INTEGRATION_EXTERNAL; + + nand_ecc_register_on_host_hw_engine(&rtlc->engine); + + platform_set_drvdata(pdev, rtlc); + + return 0; +} + +static void rtl_ecc_remove(struct platform_device *pdev) +{ + struct rtl_ecc_engine *rtlc = platform_get_drvdata(pdev); + + nand_ecc_unregister_on_host_hw_engine(&rtlc->engine); + dma_free_noncoherent(rtlc->dev, RTL_ECC_DMA_SIZE, rtlc->buf, rtlc->buf_dma, + DMA_BIDIRECTIONAL); +} + +static const struct of_device_id rtl_ecc_of_ids[] = { + { + .compatible = "realtek,rtl9301-ecc", + }, + { /* sentinel */ }, +}; + +static struct platform_driver rtl_ecc_driver = { + .driver = { + .name = "rtl-nand-ecc-engine", + .of_match_table = rtl_ecc_of_ids, + }, + .probe = rtl_ecc_probe, + .remove = rtl_ecc_remove, +}; +module_platform_driver(rtl_ecc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Markus Stockhausen "); +MODULE_DESCRIPTION("Realtek NAND hardware ECC controller"); From 8ed4728eb9f10b57c3eb02e0f6933a89ffcb8a91 Mon Sep 17 00:00:00 2001 From: Erick Karanja Date: Mon, 22 Sep 2025 14:07:27 +0300 Subject: [PATCH 2230/2711] mtd: rawnand: atmel: Fix error handling path in atmel_nand_controller_add_nands In case of a jump to the err label due to atmel_nand_create() or atmel_nand_controller_add_nand() failure, the reference to nand_np need to be released Use for_each_child_of_node_scoped() to fix the issue. Fixes: f88fc122cc34 ("mtd: nand: Cleanup/rework the atmel_nand driver") Signed-off-by: Erick Karanja Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/atmel/nand-controller.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 87481b60f315..8c7b086456b5 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1853,7 +1853,7 @@ atmel_nand_controller_legacy_add_nands(struct atmel_nand_controller *nc) static int atmel_nand_controller_add_nands(struct atmel_nand_controller *nc) { - struct device_node *np, *nand_np; + struct device_node *np; struct device *dev = nc->dev; int ret, reg_cells; u32 val; @@ -1880,7 +1880,7 @@ static int atmel_nand_controller_add_nands(struct atmel_nand_controller *nc) reg_cells += val; - for_each_child_of_node(np, nand_np) { + for_each_child_of_node_scoped(np, nand_np) { struct atmel_nand *nand; nand = atmel_nand_create(nc, nand_np, reg_cells); From fa1f26b48fe43195aa0ac4badf5651063590326f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Sep 2025 17:22:04 +0200 Subject: [PATCH 2231/2711] mtd: rawnand: omap2: fix device leak on probe failure Make sure to drop the reference to the elm device taken by of_find_device_by_node() during probe on errors and on driver unload. Fixes: 62116e5171e0 ("mtd: nand: omap2: Support for hardware BCH error correction.") Signed-off-by: Johan Hovold Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/omap2.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index b8af3a3533fc..61fd98ad5c78 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -1979,7 +1979,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip) err = rawnand_sw_bch_init(chip); if (err) { dev_err(dev, "Unable to use BCH library\n"); - return err; + goto err_put_elm_dev; } break; @@ -2016,7 +2016,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip) err = rawnand_sw_bch_init(chip); if (err) { dev_err(dev, "unable to use BCH library\n"); - return err; + goto err_put_elm_dev; } break; @@ -2054,7 +2054,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip) break; default: dev_err(dev, "Invalid or unsupported ECC scheme\n"); - return -EINVAL; + err = -EINVAL; + goto err_put_elm_dev; } if (elm_bch_strength >= 0) { @@ -2073,7 +2074,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip) info->nsteps_per_eccpg, chip->ecc.size, chip->ecc.bytes); if (err < 0) - return err; + goto err_put_elm_dev; } /* Check if NAND device's OOB is enough to store ECC signatures */ @@ -2083,10 +2084,24 @@ static int omap_nand_attach_chip(struct nand_chip *chip) dev_err(dev, "Not enough OOB bytes: required = %d, available=%d\n", min_oobbytes, mtd->oobsize); - return -EINVAL; + err = -EINVAL; + goto err_put_elm_dev; } return 0; + +err_put_elm_dev: + put_device(info->elm_dev); + + return err; +} + +static void omap_nand_detach_chip(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct omap_nand_info *info = mtd_to_omap(mtd); + + put_device(info->elm_dev); } static void omap_nand_data_in(struct nand_chip *chip, void *buf, @@ -2187,6 +2202,7 @@ static int omap_nand_exec_op(struct nand_chip *chip, static const struct nand_controller_ops omap_nand_controller_ops = { .attach_chip = omap_nand_attach_chip, + .detach_chip = omap_nand_detach_chip, .exec_op = omap_nand_exec_op, }; From 1001cc1171248ebb21d371fbe086b5d3f11b410b Mon Sep 17 00:00:00 2001 From: Maarten Zanders Date: Mon, 22 Sep 2025 17:39:38 +0200 Subject: [PATCH 2232/2711] mtd: nand: raw: gpmi: fix clocks when CONFIG_PM=N Commit f04ced6d545e ("mtd: nand: raw: gpmi: improve power management handling") moved all clock handling into PM callbacks. With CONFIG_PM disabled, those callbacks are missing, leaving the driver unusable. Add clock init/teardown for !CONFIG_PM builds to restore basic operation. Keeping the driver working without requiring CONFIG_PM is preferred over adding a Kconfig dependency. Fixes: f04ced6d545e ("mtd: nand: raw: gpmi: improve power management handling") Signed-off-by: Maarten Zanders Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index f4e68008ea03..a750f5839e34 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -145,6 +145,9 @@ err_clk: return ret; } +#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true) +#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false) + static int gpmi_init(struct gpmi_nand_data *this) { struct resources *r = &this->resources; @@ -2765,6 +2768,11 @@ static int gpmi_nand_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 500); pm_runtime_use_autosuspend(&pdev->dev); +#ifndef CONFIG_PM + ret = gpmi_enable_clk(this); + if (ret) + goto exit_acquire_resources; +#endif ret = gpmi_init(this); if (ret) @@ -2800,6 +2808,9 @@ static void gpmi_nand_remove(struct platform_device *pdev) release_resources(this); pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); +#ifndef CONFIG_PM + gpmi_disable_clk(this); +#endif } static int gpmi_pm_suspend(struct device *dev) @@ -2846,9 +2857,6 @@ static int gpmi_pm_resume(struct device *dev) return 0; } -#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true) -#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false) - static int gpmi_runtime_suspend(struct device *dev) { struct gpmi_nand_data *this = dev_get_drvdata(dev); From d496b6f42eb0455caf5d8cb30cf1f01b7fc2a747 Mon Sep 17 00:00:00 2001 From: Gopi Krishna Menon Date: Fri, 19 Sep 2025 00:14:14 +0530 Subject: [PATCH 2233/2711] mtd: cfi: use struct_size() helper for cfiq allocation Documentation/process/deprecated.rst recommends against performing dynamic size calculations in the arguments of memory allocator function due to the risk of overflow. Such calculations can wrap around and result in a smaller allocation than what the caller was expecting. Replace the size calculation in cfiq allocation with struct_size() helper to make the code clearer and handle the overflows correctly. Signed-off-by: Gopi Krishna Menon Reviewed-by: Vignesh Raghavendra link: https://lore.kernel.org/linux-kernel-mentees/20250922071137.900508-1-rk0006818@gmail.com/T/#u Signed-off-by: Miquel Raynal --- drivers/mtd/chips/cfi_probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index a04b6174181c..e254f9cd2796 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c @@ -208,7 +208,7 @@ static int __xipram cfi_chip_setup(struct map_info *map, if (!num_erase_regions) return 0; - cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); + cfi->cfiq = kmalloc(struct_size(cfi->cfiq, EraseRegionInfo, num_erase_regions), GFP_KERNEL); if (!cfi->cfiq) return 0; From 527668868862e0db65efc88fe82040f1e48d4ab3 Mon Sep 17 00:00:00 2001 From: Rahul Kumar Date: Mon, 22 Sep 2025 12:41:37 +0530 Subject: [PATCH 2234/2711] mtd: jedec_probe: use struct_size() helper for cfiq allocation Documentation/process/deprecated.rst recommends against performing dynamic size calculations in the arguments of memory allocator functions due to the risk of overflow. Such calculations can wrap around and result in a smaller allocation than expected. Replace the size calculation in cfiq allocation with struct_size() helper to make the code clearer and handle overflows correctly. Signed-off-by: Rahul Kumar Signed-off-by: Miquel Raynal --- drivers/mtd/chips/jedec_probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 3648348e92be..b285962eee2a 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1985,7 +1985,7 @@ static int cfi_jedec_setup(struct map_info *map, struct cfi_private *cfi, int in num_erase_regions = jedec_table[index].nr_regions; - cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); + cfi->cfiq = kmalloc(struct_size(cfi->cfiq, EraseRegionInfo, num_erase_regions), GFP_KERNEL); if (!cfi->cfiq) { //xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); return 0; From 192f981c14bfad4241446544cf0d27b9fa11a7bd Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Sep 2025 17:31:00 +0200 Subject: [PATCH 2235/2711] mtd: hyperbus: hbmc-am654: drop unused module alias The driver has never supported anything but OF probing so drop the unused platform module alias. Signed-off-by: Johan Hovold Signed-off-by: Miquel Raynal --- drivers/mtd/hyperbus/hbmc-am654.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/hyperbus/hbmc-am654.c b/drivers/mtd/hyperbus/hbmc-am654.c index 82a1e7b7e4d8..9d31464046b2 100644 --- a/drivers/mtd/hyperbus/hbmc-am654.c +++ b/drivers/mtd/hyperbus/hbmc-am654.c @@ -272,5 +272,4 @@ module_platform_driver(am654_hbmc_platform_driver); MODULE_DESCRIPTION("HBMC driver for AM654 SoC"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:hbmc-am654"); MODULE_AUTHOR("Vignesh Raghavendra "); From cc74c3f8e4bc01ecf9849a2b22706ba96a29f749 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Sep 2025 17:31:01 +0200 Subject: [PATCH 2236/2711] mtd: onenand: omap2: drop unused module alias The driver only supports OF probing since commit a758f50f10cf ("mtd: onenand: omap2: Configure driver from DT") so drop the unused platform module alias. Signed-off-by: Johan Hovold Signed-off-by: Miquel Raynal --- drivers/mtd/nand/onenand/onenand_omap2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/onenand/onenand_omap2.c b/drivers/mtd/nand/onenand/onenand_omap2.c index f9a386b69050..0793251ada3b 100644 --- a/drivers/mtd/nand/onenand/onenand_omap2.c +++ b/drivers/mtd/nand/onenand/onenand_omap2.c @@ -603,7 +603,6 @@ static struct platform_driver omap2_onenand_driver = { module_platform_driver(omap2_onenand_driver); -MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarkko Lavinen "); MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3"); From 7a3f3c5bdecfe3cf6cdd35073c2729a46894a34d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Sep 2025 17:31:02 +0200 Subject: [PATCH 2237/2711] mtd: rawnand: atmel: drop unused module alias The driver only supports OF probing since commit f88fc122cc34 ("mtd: nand: Cleanup/rework the atmel_nand driver") so drop the unused platform module alias. Signed-off-by: Johan Hovold Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/atmel/pmecc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/raw/atmel/pmecc.c b/drivers/mtd/nand/raw/atmel/pmecc.c index 0b402823b619..1d0e93e4edb1 100644 --- a/drivers/mtd/nand/raw/atmel/pmecc.c +++ b/drivers/mtd/nand/raw/atmel/pmecc.c @@ -1010,4 +1010,3 @@ module_platform_driver(atmel_pmecc_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Boris Brezillon "); MODULE_DESCRIPTION("PMECC engine driver"); -MODULE_ALIAS("platform:atmel_pmecc"); From b1a5c6de97b4c861c1ad1e7ad3818ebd32be190e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Sep 2025 17:31:03 +0200 Subject: [PATCH 2238/2711] mtd: rawnand: omap2: drop unused module alias The driver only supports OF probing since commit 086c321ec57b ("mtd: nand: omap2: Remove omap_nand_platform_data") so drop the unused platform module alias. Signed-off-by: Johan Hovold Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/omap2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index b8af3a3533fc..ef0f75fd1825 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -2316,6 +2316,5 @@ static struct platform_driver omap_nand_driver = { module_platform_driver(omap_nand_driver); -MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards"); From 1f7005d382f567b25cfb96d9f201f5448cf67f9a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Sep 2025 17:31:04 +0200 Subject: [PATCH 2239/2711] mtd: rawnand: pl353: drop unused module alias The driver has never supported anything but OF probing so drop the unused platform module alias. Signed-off-by: Johan Hovold Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/pl35x-nand-controller.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c index 09440ed4652e..a7dc45c7f214 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -1193,6 +1193,5 @@ static struct platform_driver pl35x_nandc_driver = { module_platform_driver(pl35x_nandc_driver); MODULE_AUTHOR("Xilinx, Inc."); -MODULE_ALIAS("platform:" PL35X_NANDC_DRIVER_NAME); MODULE_DESCRIPTION("ARM PL35X NAND controller driver"); MODULE_LICENSE("GPL"); From 61163e7373f678c453a4505865e0f8b27e506de8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Sep 2025 17:31:05 +0200 Subject: [PATCH 2240/2711] mtd: rawnand: rockchip: drop unused module alias The driver has never supported anything but OF probing so drop the unused platform module alias. Signed-off-by: Johan Hovold Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/rockchip-nand-controller.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c index c5d7cd8a6cab..9444ba02696d 100644 --- a/drivers/mtd/nand/raw/rockchip-nand-controller.c +++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c @@ -1505,4 +1505,3 @@ module_platform_driver(rk_nfc_driver); MODULE_LICENSE("Dual MIT/GPL"); MODULE_AUTHOR("Yifeng Zhao "); MODULE_DESCRIPTION("Rockchip Nand Flash Controller Driver"); -MODULE_ALIAS("platform:rockchip-nand-controller"); From 2f05c108664056f91e5f9171169c685f517ac568 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Sep 2025 17:31:06 +0200 Subject: [PATCH 2241/2711] mtd: rawnand: stm32_fmc2: drop unused module alias The driver has never supported anything but OF probing so drop the unused platform module alias. Signed-off-by: Johan Hovold Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index a960403081f1..d1ad07294a86 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -2156,7 +2156,6 @@ static struct platform_driver stm32_fmc2_nfc_driver = { }; module_platform_driver(stm32_fmc2_nfc_driver); -MODULE_ALIAS("platform:stm32_fmc2_nfc"); MODULE_AUTHOR("Christophe Kerello "); MODULE_DESCRIPTION("STMicroelectronics STM32 FMC2 NFC driver"); MODULE_LICENSE("GPL v2"); From 362f84c89e136539b8c3edb47f42fb06ce37bacf Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Sep 2025 17:31:07 +0200 Subject: [PATCH 2242/2711] mtd: rawnand: sunxi: drop unused module alias The driver has never supported anything but OF probing so drop the unused platform module alias. Signed-off-by: Johan Hovold Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/sunxi_nand.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 162cd5f4f234..f6a8e8ae819d 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -2205,4 +2205,3 @@ module_platform_driver(sunxi_nfc_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Boris BREZILLON"); MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver"); -MODULE_ALIAS("platform:sunxi_nand"); From e51d05f523e43ce5d2bad957943a2b14f68078cd Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Fri, 12 Sep 2025 15:37:58 +0530 Subject: [PATCH 2243/2711] PCI: keystone: Use devm_request_irq() to free "ks-pcie-error-irq" on exit Commit under Fixes introduced the IRQ handler for "ks-pcie-error-irq". The interrupt is acquired using "request_irq()" but is never freed if the driver exits due to an error. Although the section in the driver that invokes "request_irq()" has moved around over time, the issue hasn't been addressed until now. Fix this by using "devm_request_irq()" which automatically frees the interrupt if the driver exits. Fixes: 025dd3daeda7 ("PCI: keystone: Add error IRQ handler") Reported-by: Jiri Slaby Closes: https://lore.kernel.org/r/3d3a4b52-e343-42f3-9d69-94c259812143@kernel.org Signed-off-by: Siddharth Vadapalli Signed-off-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250912100802.3136121-2-s-vadapalli@ti.com --- drivers/pci/controller/dwc/pci-keystone.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index ac025bbd5bd5..42c88adb545d 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -1201,8 +1201,8 @@ static int ks_pcie_probe(struct platform_device *pdev) if (irq < 0) return irq; - ret = request_irq(irq, ks_pcie_err_irq_handler, IRQF_SHARED, - "ks-pcie-error-irq", ks_pcie); + ret = devm_request_irq(dev, irq, ks_pcie_err_irq_handler, IRQF_SHARED, + "ks-pcie-error-irq", ks_pcie); if (ret < 0) { dev_err(dev, "failed to request error IRQ %d\n", irq); From cfcd6cab2f33c24a68517f9e3131480b4000c2be Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Fri, 5 Sep 2025 14:14:34 -0700 Subject: [PATCH 2244/2711] PCI: j721e: Fix incorrect error message in probe() The probe() function prints "pm_runtime_get_sync failed" when j721e_pcie_ctrl_init() returns an error. This is misleading since the failure is not from pm_runtime, but from the controller init routine. Update the error message to correctly reflect the source. No functional changes. Fixes: f3e25911a430 ("PCI: j721e: Add TI J721E PCIe driver") Signed-off-by: Alok Tiwari Signed-off-by: Manivannan Sadhasivam Reviewed-by: Siddharth Vadapalli Link: https://patch.msgid.link/20250905211436.3048282-1-alok.a.tiwari@oracle.com --- drivers/pci/controller/cadence/pci-j721e.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c index 5a9ae33e2b93..5bc5ab20aa6d 100644 --- a/drivers/pci/controller/cadence/pci-j721e.c +++ b/drivers/pci/controller/cadence/pci-j721e.c @@ -575,7 +575,7 @@ static int j721e_pcie_probe(struct platform_device *pdev) ret = j721e_pcie_ctrl_init(pcie); if (ret < 0) { - dev_err_probe(dev, ret, "pm_runtime_get_sync failed\n"); + dev_err_probe(dev, ret, "j721e_pcie_ctrl_init failed\n"); goto err_get_sync; } From 285654d58a747eb431ee538c803c077d90525674 Mon Sep 17 00:00:00 2001 From: John Meneghini Date: Thu, 25 Sep 2025 09:07:29 -0400 Subject: [PATCH 2245/2711] Revert "scsi: qla2xxx: Fix memcpy() field-spanning write issue" This reverts commit 6f4b10226b6b1e7d1ff3cdb006cf0f6da6eed71e. We've been testing this patch and it turns out there is a significant bug here. This leaks memory and causes a driver hang. Link: https://lore.kernel.org/linux-scsi/yq1zfajqpec.fsf@ca-mkp.ca.oracle.com/ Signed-off-by: John Meneghini Acked-by: Gustavo A. R. Silva Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 10 ++++------ drivers/scsi/qla2xxx/qla_isr.c | 17 +++++++++-------- drivers/scsi/qla2xxx/qla_nvme.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 5 ++--- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 604e66bead1e..cb95b7b12051 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -4890,7 +4890,9 @@ struct purex_item { struct purex_item *pkt); atomic_t in_use; uint16_t size; - uint8_t iocb[] __counted_by(size); + struct { + uint8_t iocb[64]; + } iocb; }; #include "qla_edif.h" @@ -5099,6 +5101,7 @@ typedef struct scsi_qla_host { struct list_head head; spinlock_t lock; } purex_list; + struct purex_item default_item; struct name_list_extended gnl; /* Count of active session/fcport */ @@ -5127,11 +5130,6 @@ typedef struct scsi_qla_host { #define DPORT_DIAG_IN_PROGRESS BIT_0 #define DPORT_DIAG_CHIP_RESET_IN_PROGRESS BIT_1 uint16_t dport_status; - - /* Must be last --ends in a flexible-array member. */ - TRAILING_OVERLAP(struct purex_item, default_item, iocb, - uint8_t __default_item_iocb[QLA_DEFAULT_PAYLOAD_SIZE]; - ); } scsi_qla_host_t; struct qla27xx_image_status { diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 4559b490614d..c4c6b5c6658c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1077,17 +1077,17 @@ static struct purex_item * qla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size) { struct purex_item *item = NULL; + uint8_t item_hdr_size = sizeof(*item); if (size > QLA_DEFAULT_PAYLOAD_SIZE) { - item = kzalloc(struct_size(item, iocb, size), GFP_ATOMIC); + item = kzalloc(item_hdr_size + + (size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC); } else { if (atomic_inc_return(&vha->default_item.in_use) == 1) { item = &vha->default_item; goto initialize_purex_header; } else { - item = kzalloc( - struct_size(item, iocb, QLA_DEFAULT_PAYLOAD_SIZE), - GFP_ATOMIC); + item = kzalloc(item_hdr_size, GFP_ATOMIC); } } if (!item) { @@ -1127,16 +1127,17 @@ qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt, * @vha: SCSI driver HA context * @pkt: ELS packet */ -static struct purex_item * -qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt) +static struct purex_item +*qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt) { struct purex_item *item; - item = qla24xx_alloc_purex_item(vha, QLA_DEFAULT_PAYLOAD_SIZE); + item = qla24xx_alloc_purex_item(vha, + QLA_DEFAULT_PAYLOAD_SIZE); if (!item) return item; - memcpy(&item->iocb, pkt, QLA_DEFAULT_PAYLOAD_SIZE); + memcpy(&item->iocb, pkt, sizeof(item->iocb)); return item; } diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 065f9bcca26f..316594aa40cc 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -1308,7 +1308,7 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp) ql_dbg(ql_dbg_unsol, vha, 0x2121, "PURLS OP[%01x] size %d xchg addr 0x%x portid %06x\n", - item->iocb[3], item->size, uctx->exchange_address, + item->iocb.iocb[3], item->size, uctx->exchange_address, fcport->d_id.b24); /* +48 0 1 2 3 4 5 6 7 8 9 A B C D E F * ----- ----------------------------------------------- diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 98a5c105fdfd..9a2f328200ab 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -6459,10 +6459,9 @@ dealloc: void qla24xx_free_purex_item(struct purex_item *item) { - if (item == &item->vha->default_item) { + if (item == &item->vha->default_item) memset(&item->vha->default_item, 0, sizeof(struct purex_item)); - memset(&item->vha->__default_item_iocb, 0, QLA_DEFAULT_PAYLOAD_SIZE); - } else + else kfree(item); } From f966e02ae52192928d544262ee7a68611e333031 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Fri, 26 Sep 2025 09:29:26 +0800 Subject: [PATCH 2246/2711] scsi: ufs: core: Fix runtime suspend error deadlock Resolve the deadlock issue during runtime suspend when an error triggers the error handler. Prevent the deadlock by checking pm_op_in_progress and performing a quick recovery. This approach ensures that the error handler does not wait indefinitely for runtime PM to resume, allowing runtime suspend to proceed smoothly. Signed-off-by: Peter Wang Suggested-by: Bart Van Assche Reviewed-by: Bart Van Assche Message-Id: <20250926012940.3933367-1-peter.wang@mediatek.com> Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index b2e103aa4e62..fd7defb3e2cf 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6673,6 +6673,14 @@ static void ufshcd_err_handler(struct work_struct *work) } spin_unlock_irqrestore(hba->host->host_lock, flags); + ufshcd_rpm_get_noresume(hba); + if (hba->pm_op_in_progress) { + ufshcd_link_recovery(hba); + ufshcd_rpm_put(hba); + return; + } + ufshcd_rpm_put(hba); + ufshcd_err_handling_prepare(hba); spin_lock_irqsave(hba->host->host_lock, flags); From 0ba7a254afd037cfc2b656f379c54b43c6e574e8 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 29 Sep 2025 13:27:30 +0200 Subject: [PATCH 2247/2711] scsi: ufs: core: Fix PM QoS mutex initialization hba->pm_qos_mutex is used very early as a part of ufshcd_init(), so it need to be initialized before that call. This fixes the following warning: ------------[ cut here ]------------ DEBUG_LOCKS_WARN_ON(lock->magic != lock) WARNING: kernel/locking/mutex.c:577 at __mutex_lock+0x268/0x894, CPU#4: kworker/u32:4/72 Modules linked in: CPU: 4 UID: 0 PID: 72 Comm: kworker/u32:4 Not tainted 6.17.0-rc7-next-20250926+ #11223 PREEMPT Hardware name: Qualcomm Technologies, Inc. Robotics RB5 (DT) Workqueue: events_unbound deferred_probe_work_func pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : __mutex_lock+0x268/0x894 lr : __mutex_lock+0x268/0x894 ... Call trace: __mutex_lock+0x268/0x894 (P) mutex_lock_nested+0x24/0x30 ufshcd_pm_qos_update+0x30/0x78 ufshcd_setup_clocks+0x2d4/0x3c4 ufshcd_init+0x234/0x126c ufshcd_pltfrm_init+0x62c/0x82c ufs_qcom_probe+0x20/0x58 platform_probe+0x5c/0xac really_probe+0xbc/0x298 __driver_probe_device+0x78/0x12c driver_probe_device+0x40/0x164 __device_attach_driver+0xb8/0x138 bus_for_each_drv+0x80/0xdc __device_attach+0xa8/0x1b0 device_initial_probe+0x14/0x20 bus_probe_device+0xb0/0xb4 deferred_probe_work_func+0x8c/0xc8 process_one_work+0x208/0x60c worker_thread+0x244/0x388 kthread+0x150/0x228 ret_from_fork+0x10/0x20 irq event stamp: 57267 hardirqs last enabled at (57267): [] _raw_spin_unlock_irqrestore+0x74/0x78 hardirqs last disabled at (57266): [] clk_enable_lock+0x7c/0xf0 softirqs last enabled at (56270): [] handle_softirqs+0x4c4/0x4dc softirqs last disabled at (56265): [] __do_softirq+0x14/0x20 ---[ end trace 0000000000000000 ]--- Fixes: 79dde5f7dc7c ("scsi: ufs: core: Fix data race in CPU latency PM QoS request handling") Signed-off-by: Marek Szyprowski Reviewed-by: Bart Van Assche Message-Id: <20250929112730.3782765-1-m.szyprowski@samsung.com> Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index fd7defb3e2cf..319dd6f6229b 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10669,6 +10669,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) */ spin_lock_init(&hba->clk_gating.lock); + /* Initialize mutex for PM QoS request synchronization */ + mutex_init(&hba->pm_qos_mutex); + /* * Set the default power management level for runtime and system PM. * Host controller drivers can override them in their @@ -10757,9 +10760,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) mutex_init(&hba->wb_mutex); - /* Initialize mutex for PM QoS request synchronization */ - mutex_init(&hba->pm_qos_mutex); - init_rwsem(&hba->clk_scaling_lock); ufshcd_init_clk_gating(hba); From 60cd16a3b7439ccb699d0bf533799eeb894fd217 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Sat, 20 Sep 2025 21:42:01 +0800 Subject: [PATCH 2248/2711] scsi: mvsas: Fix use-after-free bugs in mvs_work_queue During the detaching of Marvell's SAS/SATA controller, the original code calls cancel_delayed_work() in mvs_free() to cancel the delayed work item mwq->work_q. However, if mwq->work_q is already running, the cancel_delayed_work() may fail to cancel it. This can lead to use-after-free scenarios where mvs_free() frees the mvs_info while mvs_work_queue() is still executing and attempts to access the already-freed mvs_info. A typical race condition is illustrated below: CPU 0 (remove) | CPU 1 (delayed work callback) mvs_pci_remove() | mvs_free() | mvs_work_queue() cancel_delayed_work() | kfree(mvi) | | mvi-> // UAF Replace cancel_delayed_work() with cancel_delayed_work_sync() to ensure that the delayed work item is properly canceled and any executing delayed work item completes before the mvs_info is deallocated. This bug was found by static analysis. Fixes: 20b09c2992fe ("[SCSI] mvsas: add support for 94xx; layout change; bug fixes") Signed-off-by: Duoming Zhou Signed-off-by: Martin K. Petersen --- drivers/scsi/mvsas/mv_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 2c72da6b8cf0..7f1ad305eee6 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -124,7 +124,7 @@ static void mvs_free(struct mvs_info *mvi) if (mvi->shost) scsi_host_put(mvi->shost); list_for_each_entry(mwq, &mvi->wq_list, entry) - cancel_delayed_work(&mwq->work_q); + cancel_delayed_work_sync(&mwq->work_q); kfree(mvi->rsvd_tags); kfree(mvi); } From 98a4f5b7359205ced1b6a626df3963bf7c5e5052 Mon Sep 17 00:00:00 2001 From: Jani Nurminen Date: Fri, 12 Sep 2025 11:09:48 +0200 Subject: [PATCH 2249/2711] PCI: xilinx-nwl: Fix ECAM programming When PCIe has been set up by the bootloader, the ecam_size field in the E_ECAM_CONTROL register already contains a value. The driver previously programmed it to 0xc (for 16 busses; 16 MB), but bumped to 0x10 (for 256 busses; 256 MB) by the commit 2fccd11518f1 ("PCI: xilinx-nwl: Modify ECAM size to enable support for 256 buses"). Regardless of what the bootloader has programmed, the driver ORs in a new maximal value without doing a proper RMW sequence. This can lead to problems. For example, if the bootloader programs in 0xc and the driver uses 0x10, the ORed result is 0x1c, which is beyond the ecam_max_size limit of 0x10 (from E_ECAM_CAPABILITIES). Avoid the problems by doing a proper RMW. Fixes: 2fccd11518f1 ("PCI: xilinx-nwl: Modify ECAM size to enable support for 256 buses") Signed-off-by: Jani Nurminen [mani: added stable tag] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org Link: https://patch.msgid.link/e83a2af2-af0b-4670-bcf5-ad408571c2b0@windriver.com --- drivers/pci/controller/pcie-xilinx-nwl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c index 05b8c205493c..7db2c96c6cec 100644 --- a/drivers/pci/controller/pcie-xilinx-nwl.c +++ b/drivers/pci/controller/pcie-xilinx-nwl.c @@ -718,9 +718,10 @@ static int nwl_pcie_bridge_init(struct nwl_pcie *pcie) nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, E_ECAM_CONTROL) | E_ECAM_CR_ENABLE, E_ECAM_CONTROL); - nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, E_ECAM_CONTROL) | - (NWL_ECAM_MAX_SIZE << E_ECAM_SIZE_SHIFT), - E_ECAM_CONTROL); + ecam_val = nwl_bridge_readl(pcie, E_ECAM_CONTROL); + ecam_val &= ~E_ECAM_SIZE_LOC; + ecam_val |= NWL_ECAM_MAX_SIZE << E_ECAM_SIZE_SHIFT; + nwl_bridge_writel(pcie, ecam_val, E_ECAM_CONTROL); nwl_bridge_writel(pcie, lower_32_bits(pcie->phys_ecam_base), E_ECAM_BASE_LO); From 74662f9f92b67c0ca55139c5aa392da0f0a26c08 Mon Sep 17 00:00:00 2001 From: Steven 'Steve' Kendall Date: Mon, 29 Sep 2025 21:33:34 +0000 Subject: [PATCH 2250/2711] ALSA: hda/hdmi: Add pin fix for HP ProDesk model The HP ProDesk 400 (SSID 103c:83f3) also needs a quirk for enabling HDMI outputs. This patch adds the required quirk entry. Signed-off-by: Steven 'Steve' Kendall Cc: Signed-off-by: Takashi Iwai --- sound/hda/codecs/hdmi/hdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c index dc38bfd9dba5..111c9b5335af 100644 --- a/sound/hda/codecs/hdmi/hdmi.c +++ b/sound/hda/codecs/hdmi/hdmi.c @@ -1549,6 +1549,7 @@ static const struct snd_pci_quirk force_connect_list[] = { SND_PCI_QUIRK(0x103c, 0x83e2, "HP EliteDesk 800 G4", 1), SND_PCI_QUIRK(0x103c, 0x83ef, "HP MP9 G4 Retail System AMS", 1), SND_PCI_QUIRK(0x103c, 0x845a, "HP EliteDesk 800 G4 DM 65W", 1), + SND_PCI_QUIRK(0x103c, 0x83f3, "HP ProDesk 400", 1), SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1), SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1), SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1), From 5deafa27d9ae040b75d392f60b12e300b42b4792 Mon Sep 17 00:00:00 2001 From: Gautam Gala Date: Wed, 24 Sep 2025 13:26:44 +0200 Subject: [PATCH 2251/2711] KVM: s390: Fix to clear PTE when discarding a swapped page KVM run fails when guests with 'cmm' cpu feature and host are under memory pressure and use swap heavily. This is because npages becomes ENOMEN (out of memory) in hva_to_pfn_slow() which inturn propagates as EFAULT to qemu. Clearing the page table entry when discarding an address that maps to a swap entry resolves the issue. Fixes: 200197908dc4 ("KVM: s390: Refactor and split some gmap helpers") Cc: stable@vger.kernel.org Suggested-by: Claudio Imbrenda Signed-off-by: Gautam Gala Reviewed-by: Claudio Imbrenda Signed-off-by: Claudio Imbrenda --- arch/s390/include/asm/pgtable.h | 22 ++++++++++++++++++++++ arch/s390/mm/gmap_helpers.c | 12 +++++++++++- arch/s390/mm/pgtable.c | 23 +---------------------- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 6d8bc27a366e..324f96485604 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -2010,4 +2010,26 @@ static inline unsigned long gmap_pgste_get_pgt_addr(unsigned long *pgt) return res; } +static inline pgste_t pgste_get_lock(pte_t *ptep) +{ + unsigned long value = 0; +#ifdef CONFIG_PGSTE + unsigned long *ptr = (unsigned long *)(ptep + PTRS_PER_PTE); + + do { + value = __atomic64_or_barrier(PGSTE_PCL_BIT, ptr); + } while (value & PGSTE_PCL_BIT); + value |= PGSTE_PCL_BIT; +#endif + return __pgste(value); +} + +static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) +{ +#ifdef CONFIG_PGSTE + barrier(); + WRITE_ONCE(*(unsigned long *)(ptep + PTRS_PER_PTE), pgste_val(pgste) & ~PGSTE_PCL_BIT); +#endif +} + #endif /* _S390_PAGE_H */ diff --git a/arch/s390/mm/gmap_helpers.c b/arch/s390/mm/gmap_helpers.c index a45d417ad951..c382005577bd 100644 --- a/arch/s390/mm/gmap_helpers.c +++ b/arch/s390/mm/gmap_helpers.c @@ -13,6 +13,7 @@ #include #include #include +#include /** * ptep_zap_swap_entry() - discard a swap entry. @@ -45,6 +46,7 @@ void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr) { struct vm_area_struct *vma; spinlock_t *ptl; + pgste_t pgste; pte_t *ptep; mmap_assert_locked(mm); @@ -58,8 +60,16 @@ void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr) ptep = get_locked_pte(mm, vmaddr, &ptl); if (unlikely(!ptep)) return; - if (pte_swap(*ptep)) + if (pte_swap(*ptep)) { + preempt_disable(); + pgste = pgste_get_lock(ptep); + ptep_zap_swap_entry(mm, pte_to_swp_entry(*ptep)); + pte_clear(mm, vmaddr, ptep); + + pgste_set_unlock(ptep, pgste); + preempt_enable(); + } pte_unmap_unlock(ptep, ptl); } EXPORT_SYMBOL_GPL(gmap_helper_zap_one_page); diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 7df70cd8f739..6b92c348b56f 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -23,6 +23,7 @@ #include #include #include +#include #include pgprot_t pgprot_writecombine(pgprot_t prot) @@ -114,28 +115,6 @@ static inline pte_t ptep_flush_lazy(struct mm_struct *mm, return old; } -static inline pgste_t pgste_get_lock(pte_t *ptep) -{ - unsigned long value = 0; -#ifdef CONFIG_PGSTE - unsigned long *ptr = (unsigned long *)(ptep + PTRS_PER_PTE); - - do { - value = __atomic64_or_barrier(PGSTE_PCL_BIT, ptr); - } while (value & PGSTE_PCL_BIT); - value |= PGSTE_PCL_BIT; -#endif - return __pgste(value); -} - -static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) -{ -#ifdef CONFIG_PGSTE - barrier(); - WRITE_ONCE(*(unsigned long *)(ptep + PTRS_PER_PTE), pgste_val(pgste) & ~PGSTE_PCL_BIT); -#endif -} - static inline pgste_t pgste_get(pte_t *ptep) { unsigned long pgste = 0; From adefb2ccea1e96b452cbbc39150bc0ccf1688b99 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Tue, 16 Sep 2025 14:18:28 -0300 Subject: [PATCH 2252/2711] drm/v3d: create a dedicated lock for dma fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't mix dma fence lock with the active_job lock. Use fence_lock to protect the dma fence used by drm scheduler when signalling a job completion and queue_lock to protect concurrent access to active bin job in OOM and stats collection for a given file priv. The issue was uncovered when PREEMPT_RT on with a system freeze when opening multiple Chromium tabs on Raspberry Pi 5. Link: https://github.com/raspberrypi/linux/issues/7035 Fixes: fa6a20c87470 ("drm/v3d: Address race-condition between per-fd GPU stats and fd release") Signed-off-by: Melissa Wen Acked-by: Iago Toral Quiroga Reviewed-by: Maíra Canal Signed-off-by: Melissa Wen Link: https://lore.kernel.org/r/20250916172022.2779837-1-mwen@igalia.com --- drivers/gpu/drm/v3d/v3d_drv.h | 2 ++ drivers/gpu/drm/v3d/v3d_fence.c | 2 +- drivers/gpu/drm/v3d/v3d_gem.c | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 0317f3d7452a..1884686985b8 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -62,6 +62,8 @@ struct v3d_queue_state { /* Currently active job for this queue */ struct v3d_job *active_job; spinlock_t queue_lock; + /* Protect dma fence for signalling job completion */ + spinlock_t fence_lock; }; /* Performance monitor object. The perform lifetime is controlled by userspace diff --git a/drivers/gpu/drm/v3d/v3d_fence.c b/drivers/gpu/drm/v3d/v3d_fence.c index 8f8471adae34..c82500a1df73 100644 --- a/drivers/gpu/drm/v3d/v3d_fence.c +++ b/drivers/gpu/drm/v3d/v3d_fence.c @@ -15,7 +15,7 @@ struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue q) fence->dev = &v3d->drm; fence->queue = q; fence->seqno = ++queue->emit_seqno; - dma_fence_init(&fence->base, &v3d_fence_ops, &queue->queue_lock, + dma_fence_init(&fence->base, &v3d_fence_ops, &queue->fence_lock, queue->fence_context, fence->seqno); return &fence->base; diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index c77d90aa9b82..bb110d35f749 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -273,6 +273,7 @@ v3d_gem_init(struct drm_device *dev) seqcount_init(&queue->stats.lock); spin_lock_init(&queue->queue_lock); + spin_lock_init(&queue->fence_lock); } spin_lock_init(&v3d->mm_lock); From 3a0f56d72a7575f03187a85b7869c76a862b40ab Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 29 Aug 2025 22:35:49 -0700 Subject: [PATCH 2253/2711] perf bpf-filter: Fix opts declaration on older libbpfs Building perf with LIBBPF_DYNAMIC (ie not the default static linking of libbpf with perf) is breaking as the libbpf isn't version 1.7 or newer, where dont_enable is added to bpf_perf_event_opts. To avoid this breakage add a compile time version check and don't declare the variable when not present. Fixes: 5e2ac8e8571df54d ("perf bpf-filter: Enable events manually") Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexei Starovoitov Cc: bpf@vger.kernel.org Cc: Hao Ge Cc: Ilya Leoshkevich Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-filter.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index a0b11f35395f..92308c38fbb5 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -443,6 +443,10 @@ err: return -1; } +#define LIBBPF_CURRENT_VERSION_GEQ(major, minor) \ + (LIBBPF_MAJOR_VERSION > (major) || \ + (LIBBPF_MAJOR_VERSION == (major) && LIBBPF_MINOR_VERSION >= (minor))) + int perf_bpf_filter__prepare(struct evsel *evsel, struct target *target) { int i, x, y, fd, ret; @@ -451,8 +455,12 @@ int perf_bpf_filter__prepare(struct evsel *evsel, struct target *target) struct bpf_link *link; struct perf_bpf_filter_entry *entry; bool needs_idx_hash = !target__has_cpu(target); +#if LIBBPF_CURRENT_VERSION_GEQ(1, 7) DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts, .dont_enable = true); +#else + DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts); +#endif entry = calloc(MAX_FILTERS, sizeof(*entry)); if (entry == NULL) From 5a022bf88fb0f4edde14b1f6f9029d96bffbf3e6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 19 Sep 2025 17:59:25 -0300 Subject: [PATCH 2254/2711] perf bpf: Move the LIBBPF_CURRENT_VERSION_GEQ macro to bpf-utils.h We need it to fix some other libbpf version dependent issues when building with LIBBPF_DYNAMIC=1. Reviewed-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Andrii Nakryiko Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-filter.c | 5 +---- tools/perf/util/bpf-utils.h | 5 +++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index 92308c38fbb5..1a2e7b388d57 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -56,6 +56,7 @@ #include "util/debug.h" #include "util/evsel.h" #include "util/target.h" +#include "util/bpf-utils.h" #include "util/bpf-filter.h" #include @@ -443,10 +444,6 @@ err: return -1; } -#define LIBBPF_CURRENT_VERSION_GEQ(major, minor) \ - (LIBBPF_MAJOR_VERSION > (major) || \ - (LIBBPF_MAJOR_VERSION == (major) && LIBBPF_MINOR_VERSION >= (minor))) - int perf_bpf_filter__prepare(struct evsel *evsel, struct target *target) { int i, x, y, fd, ret; diff --git a/tools/perf/util/bpf-utils.h b/tools/perf/util/bpf-utils.h index 86a5055cdfad..eafc43b8731f 100644 --- a/tools/perf/util/bpf-utils.h +++ b/tools/perf/util/bpf-utils.h @@ -8,6 +8,11 @@ #ifdef HAVE_LIBBPF_SUPPORT #include +#include + +#define LIBBPF_CURRENT_VERSION_GEQ(major, minor) \ + (LIBBPF_MAJOR_VERSION > (major) || \ + (LIBBPF_MAJOR_VERSION == (major) && LIBBPF_MINOR_VERSION >= (minor))) /* * Get bpf_prog_info in continuous memory From aacaf65bb11598669f8bfff413c63eaf7bcbb6f1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 19 Sep 2025 18:02:23 -0300 Subject: [PATCH 2255/2711] perf bpf: Check libbpf version to use btf_dump_type_data_opts.emit_strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building perf with LIBBPF_DYNAMIC=1 on a fedora system with libbpf-devel 1.5 I it was breaking with: util/bpf-event.c: In function ‘format_btf_variable’: util/bpf-event.c:291:18: error: ‘const struct btf_dump_type_data_opts’ has no member named ‘emit_strings’ 291 | .emit_strings = 1, | ^~~~~~~~~~~~ util/bpf-event.c:291:33: error: initialized field overwritten [-Werror=override-init] 291 | .emit_strings = 1, | ^ util/bpf-event.c:291:33: note: (near initialization for ‘opts.skip_names’) Check the version before using that feature. Reviewed-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Andrii Nakryiko Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-event.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c index 2298cd396c42..59f84aef91b4 100644 --- a/tools/perf/util/bpf-event.c +++ b/tools/perf/util/bpf-event.c @@ -288,7 +288,9 @@ static void format_btf_variable(struct btf *btf, char *buf, size_t buf_size, .sz = sizeof(struct btf_dump_type_data_opts), .skip_names = 1, .compact = 1, +#if LIBBPF_CURRENT_VERSION_GEQ(1, 7) .emit_strings = 1, +#endif }; struct btf_dump *d; size_t btf_size; From 76619e81a8f83c266ab454f11c32725881c955c4 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Sep 2025 10:27:27 -0700 Subject: [PATCH 2256/2711] perf vendor events intel: Update alderlake events to v1.34 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update alderlake events to v1.34 released in: https://github.com/intel/perfmon/commit/80b773ebcf601b0e48e31f2184ffef933c4d842e Event JSON automatically generated by: https://github.com/intel/perfmon/blob/main/scripts/create_perf_json.py Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Thomas Falcon Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/x86/alderlake/cache.json | 36 +++++++++++++++++++ tools/perf/pmu-events/arch/x86/mapfile.csv | 4 +-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/alderlake/cache.json b/tools/perf/pmu-events/arch/x86/alderlake/cache.json index 6a56c9ad8e43..4cd535baf703 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/cache.json @@ -1062,6 +1062,30 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts writebacks of modified cachelines that hit in the L3 or were snooped from another core's caches.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.COREWB_M.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x1F803C0008", + "PublicDescription": "Counts writebacks of modified cachelines that hit in the L3 or were snooped from another core's caches. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts writebacks of non-modified cachelines that hit in the L3 or were snooped from another core's caches.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.COREWB_NONM.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x1F803C1000", + "PublicDescription": "Counts writebacks of non-modified cachelines that hit in the L3 or were snooped from another core's caches. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts demand instruction fetches and L1 instruction cache prefetches that have any type of response.", "Counter": "0,1,2,3,4,5", @@ -1302,6 +1326,18 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts all data read, code read, RFO and ITOM requests including demands and prefetches to the core caches (L1 or L2) that hit in the L3 or were snooped from another core's caches.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.READS_TO_CORE.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x1F803C4477", + "PublicDescription": "Counts all data read, code read, RFO and ITOM requests including demands and prefetches to the core caches (L1 or L2) that hit in the L3 or were snooped from another core's caches. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts L1 data cache software prefetches which include T0/T1/T2 and NTA (except PREFETCHW) that have any type of response.", "Counter": "0,1,2,3,4,5", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index d9daab4d8461..4b706599124d 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -1,6 +1,6 @@ Family-model,Version,Filename,EventType -GenuineIntel-6-(97|9A|B7|BA|BF),v1.33,alderlake,core -GenuineIntel-6-BE,v1.33,alderlaken,core +GenuineIntel-6-(97|9A|B7|BA|BF),v1.34,alderlake,core +GenuineIntel-6-BE,v1.34,alderlaken,core GenuineIntel-6-C[56],v1.12,arrowlake,core GenuineIntel-6-(1C|26|27|35|36),v5,bonnell,core GenuineIntel-6-(3D|47),v30,broadwell,core From d41129fe5476664e927ca9e8825e39138f269d18 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Sep 2025 10:27:28 -0700 Subject: [PATCH 2257/2711] perf vendor events intel: Update arrowlake events to v1.13 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update arrowlake events to v1.13 released in: https://github.com/intel/perfmon/commit/718cdcec8b9637819af5e9eff8f705f731b0f971 Event JSON automatically generated by: https://github.com/intel/perfmon/blob/main/scripts/create_perf_json.py Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Thomas Falcon Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/x86/arrowlake/cache.json | 46 +++++++++++++++++-- .../pmu-events/arch/x86/arrowlake/memory.json | 6 +-- .../pmu-events/arch/x86/arrowlake/other.json | 2 +- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/cache.json b/tools/perf/pmu-events/arch/x86/arrowlake/cache.json index f5168b55a6f4..30dd56b487ba 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/cache.json @@ -1435,9 +1435,33 @@ "UMask": "0xf", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts writebacks of modified cachelines that hit in the L3 or were snooped from another core's caches.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.COREWB_M.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x7E001E00008", + "PublicDescription": "Counts writebacks of modified cachelines that hit in the L3 or were snooped from another core's caches. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts writebacks of non-modified cachelines that hit in the L3 or were snooped from another core's caches.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.COREWB_NONM.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x7E001E01000", + "PublicDescription": "Counts writebacks of non-modified cachelines that hit in the L3 or were snooped from another core's caches. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts demand data reads that have any type of response.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", @@ -1449,7 +1473,7 @@ }, { "BriefDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop hit in another cores caches, data forwarding is required as the data is modified.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM", "MSRIndex": "0x1a6,0x1a7", @@ -1461,7 +1485,7 @@ }, { "BriefDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop hit in another cores caches which forwarded the unmodified data to the requesting core.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD", "MSRIndex": "0x1a6,0x1a7", @@ -1473,7 +1497,7 @@ }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that have any type of response.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_RFO.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", @@ -1485,7 +1509,7 @@ }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by the L3 cache where a snoop hit in another cores caches, data forwarding is required as the data is modified.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_RFO.L3_HIT.SNOOP_HITM", "MSRIndex": "0x1a6,0x1a7", @@ -1495,6 +1519,18 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts all data read, code read, RFO and ITOM requests including demands and prefetches to the core caches (L1 or L2) that hit in the L3 or were snooped from another core's caches.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.READS_TO_CORE.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x7E001E04477", + "PublicDescription": "Counts all data read, code read, RFO and ITOM requests including demands and prefetches to the core caches (L1 or L2) that hit in the L3 or were snooped from another core's caches. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Any memory transaction that reached the SQ.", "Counter": "0,1,2,3,4,5,6,7,8,9", diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/memory.json b/tools/perf/pmu-events/arch/x86/arrowlake/memory.json index 1e6360347c0f..aba1e27e5e37 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/memory.json @@ -334,7 +334,7 @@ }, { "BriefDescription": "Counts demand data reads that were supplied by DRAM.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.DRAM", "MSRIndex": "0x1a6,0x1a7", @@ -346,7 +346,7 @@ }, { "BriefDescription": "Counts demand data reads that were not supplied by the L3 cache.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.L3_MISS", "MSRIndex": "0x1a6,0x1a7", @@ -358,7 +358,7 @@ }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were not supplied by the L3 cache.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_RFO.L3_MISS", "MSRIndex": "0x1a6,0x1a7", diff --git a/tools/perf/pmu-events/arch/x86/arrowlake/other.json b/tools/perf/pmu-events/arch/x86/arrowlake/other.json index 51bc763a5887..ab7aac14e697 100644 --- a/tools/perf/pmu-events/arch/x86/arrowlake/other.json +++ b/tools/perf/pmu-events/arch/x86/arrowlake/other.json @@ -66,7 +66,7 @@ }, { "BriefDescription": "Counts streaming stores that have any type of response.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.STREAMING_WR.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 4b706599124d..8daaa8f40b66 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -1,7 +1,7 @@ Family-model,Version,Filename,EventType GenuineIntel-6-(97|9A|B7|BA|BF),v1.34,alderlake,core GenuineIntel-6-BE,v1.34,alderlaken,core -GenuineIntel-6-C[56],v1.12,arrowlake,core +GenuineIntel-6-C[56],v1.13,arrowlake,core GenuineIntel-6-(1C|26|27|35|36),v5,bonnell,core GenuineIntel-6-(3D|47),v30,broadwell,core GenuineIntel-6-56,v12,broadwellde,core From 26bc991c8a95c72db37656d844c82f7f3dcfcfb1 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Sep 2025 10:27:29 -0700 Subject: [PATCH 2258/2711] perf vendor events intel: Update emeraldrapids events to v1.20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update emeraldrapids events to v1.20 released in: https://github.com/intel/perfmon/commit/868b433955f3e94126420ee9374b9e0a6ce2d83e https://github.com/intel/perfmon/commit/43681e2817a960d06c5b8870cc6d3e5b7b6feeb9 Also adds cpu_cstate_c0 and cpu_cstate_c6 metrics. Event JSON automatically generated by: https://github.com/intel/perfmon/blob/main/scripts/create_perf_json.py Signed-off-by: Ian Rogers Tested-by: Thomas Falcon Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/emeraldrapids/cache.json | 63 +++++++++++++++++++ .../arch/x86/emeraldrapids/emr-metrics.json | 12 ++++ .../arch/x86/emeraldrapids/uncore-cache.json | 11 ++++ .../arch/x86/emeraldrapids/uncore-memory.json | 22 +++++++ .../arch/x86/emeraldrapids/uncore-power.json | 2 - tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 6 files changed, 109 insertions(+), 3 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json index e96f938587bb..26568e4b77f7 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/cache.json @@ -1,4 +1,67 @@ [ + { + "BriefDescription": "Hit snoop reply with data, line invalidated.", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.I_FWD_FE", + "PublicDescription": "Counts responses to snoops indicating the line will now be (I)nvalidated: removed from this core's cache, after the data is forwarded back to the requestor and indicating the data was found unmodified in the (FE) Forward or Exclusive State in this cores caches cache. A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x20" + }, + { + "BriefDescription": "HitM snoop reply with data, line invalidated.", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.I_FWD_M", + "PublicDescription": "Counts responses to snoops indicating the line will now be (I)nvalidated: removed from this core's caches, after the data is forwarded back to the requestor, and indicating the data was found modified(M) in this cores caches cache (aka HitM response). A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x10" + }, + { + "BriefDescription": "Hit snoop reply without sending the data, line invalidated.", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.I_HIT_FSE", + "PublicDescription": "Counts responses to snoops indicating the line will now be (I)nvalidated in this core's caches without forwarded back to the requestor. The line was in Forward, Shared or Exclusive (FSE) state in this cores caches. A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x2" + }, + { + "BriefDescription": "Line not found snoop reply", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.MISS", + "PublicDescription": "Counts responses to snoops indicating that the data was not found (IHitI) in this core's caches. A single snoop response from the core counts on all hyperthreads of the Core.", + "SampleAfterValue": "1000003", + "UMask": "0x1" + }, + { + "BriefDescription": "Hit snoop reply with data, line kept in Shared state.", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.S_FWD_FE", + "PublicDescription": "Counts responses to snoops indicating the line may be kept on this core in the (S)hared state, after the data is forwarded back to the requestor, initially the data was found in the cache in the (FS) Forward or Shared state. A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x40" + }, + { + "BriefDescription": "HitM snoop reply with data, line kept in Shared state", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.S_FWD_M", + "PublicDescription": "Counts responses to snoops indicating the line may be kept on this core in the (S)hared state, after the data is forwarded back to the requestor, initially the data was found in the cache in the (M)odified state. A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x8" + }, + { + "BriefDescription": "Hit snoop reply without sending the data, line kept in Shared state.", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.S_HIT_FSE", + "PublicDescription": "Counts responses to snoops indicating the line was kept on this core in the (S)hared state, and that the data was found unmodified but not forwarded back to the requestor, initially the data was found in the cache in the (FSE) Forward, Shared state or Exclusive state. A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x4" + }, { "BriefDescription": "L1D.HWPF_MISS", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json index af0a7dd81e93..433ae5f50704 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/emr-metrics.json @@ -39,6 +39,18 @@ "MetricName": "cpi", "ScaleUnit": "1per_instr" }, + { + "BriefDescription": "The average number of cores that are in cstate C0 as observed by the power control unit (PCU)", + "MetricExpr": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C0 / UNC_P_CLOCKTICKS * #num_packages", + "MetricGroup": "cpu_cstate", + "MetricName": "cpu_cstate_c0" + }, + { + "BriefDescription": "The average number of cores are in cstate C6 as observed by the power control unit (PCU)", + "MetricExpr": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C6 / UNC_P_CLOCKTICKS * #num_packages", + "MetricGroup": "cpu_cstate", + "MetricName": "cpu_cstate_c6" + }, { "BriefDescription": "CPU operating frequency (in GHz)", "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC * #SYSTEM_TSC_FREQ / 1e9", diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-cache.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-cache.json index f453202d80c2..92cf47967f0b 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-cache.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-cache.json @@ -311,6 +311,17 @@ "UMask": "0x2", "Unit": "CHA" }, + { + "BriefDescription": "Distress signal asserted : DPT Remote", + "Counter": "0,1,2,3", + "EventCode": "0xaf", + "EventName": "UNC_CHA_DISTRESS_ASSERTED.DPT_NONLOCAL", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Distress signal asserted : DPT Remote : Counts the number of cycles either the local or incoming distress signals are asserted. : Dynamic Prefetch Throttle received by this tile", + "UMask": "0x8", + "Unit": "CHA" + }, { "BriefDescription": "Egress Blocking due to Ordering requirements : Down", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-memory.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-memory.json index 90f61c9511fc..30044177ccf8 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-memory.json @@ -3129,6 +3129,28 @@ "PublicDescription": "Clock-Enabled Self-Refresh : Counts the number of cycles when the iMC is in self-refresh and the iMC still has a clock. This happens in some package C-states. For example, the PCU may ask the iMC to enter self-refresh even though some of the cores are still processing. One use of this is for Monroe technology. Self-refresh is required during package C3 and C6, but there is no clock in the iMC at this time, so it is not possible to count these cases.", "Unit": "iMC" }, + { + "BriefDescription": "Throttle Cycles for Rank 0", + "Counter": "0,1,2,3", + "EventCode": "0x46", + "EventName": "UNC_M_POWER_THROTTLE_CYCLES.SLOT0", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Throttle Cycles for Rank 0 : Counts the number of cycles while the iMC is being throttled by either thermal constraints or by the PCU throttling. It is not possible to distinguish between the two. This can be filtered by rank. If multiple ranks are selected and are being throttled at the same time, the counter will only increment by 1. : Thermal throttling is performed per DIMM. We support 3 DIMMs per channel. This ID allows us to filter by ID.", + "UMask": "0x1", + "Unit": "iMC" + }, + { + "BriefDescription": "Throttle Cycles for Rank 0", + "Counter": "0,1,2,3", + "EventCode": "0x46", + "EventName": "UNC_M_POWER_THROTTLE_CYCLES.SLOT1", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Throttle Cycles for Rank 0 : Counts the number of cycles while the iMC is being throttled by either thermal constraints or by the PCU throttling. It is not possible to distinguish between the two. This can be filtered by rank. If multiple ranks are selected and are being throttled at the same time, the counter will only increment by 1.", + "UMask": "0x2", + "Unit": "iMC" + }, { "BriefDescription": "Precharge due to read, write, underfill, or PGT.", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-power.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-power.json index 9482ddaea4d1..71c35b165a3e 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-power.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-power.json @@ -178,7 +178,6 @@ "Counter": "0,1,2,3", "EventCode": "0x35", "EventName": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C0", - "Experimental": "1", "PerPkg": "1", "PublicDescription": "Number of cores in C0 : This is an occupancy event that tracks the number of cores that are in the chosen C-State. It can be used by itself to get the average number of cores in that C-state with thresholding to generate histograms, or with other PCU events and occupancy triggering to capture other details.", "Unit": "PCU" @@ -198,7 +197,6 @@ "Counter": "0,1,2,3", "EventCode": "0x37", "EventName": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C6", - "Experimental": "1", "PerPkg": "1", "PublicDescription": "Number of cores in C6 : This is an occupancy event that tracks the number of cores that are in the chosen C-State. It can be used by itself to get the average number of cores in that C-state with thresholding to generate histograms, or with other PCU events and occupancy triggering to capture other details.", "Unit": "PCU" diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 8daaa8f40b66..dec7bdd770cf 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -9,7 +9,7 @@ GenuineIntel-6-4F,v23,broadwellx,core GenuineIntel-6-55-[56789ABCDEF],v1.25,cascadelakex,core GenuineIntel-6-DD,v1.00,clearwaterforest,core GenuineIntel-6-9[6C],v1.05,elkhartlake,core -GenuineIntel-6-CF,v1.16,emeraldrapids,core +GenuineIntel-6-CF,v1.20,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core GenuineIntel-6-B6,v1.09,grandridge,core From 3c393a11695cf62faca423e7e4b4b70057f4cd8d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Sep 2025 10:27:30 -0700 Subject: [PATCH 2259/2711] perf vendor events intel: Update grandridge events to v1.10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update grandridge events to v1.10 released in: https://github.com/intel/perfmon/commit/c3028836415b8b5d31b8439eefc087492148c19f Event JSON automatically generated by: https://github.com/intel/perfmon/blob/main/scripts/create_perf_json.py Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Thomas Falcon Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/x86/grandridge/cache.json | 20 +++++++++---------- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/grandridge/cache.json b/tools/perf/pmu-events/arch/x86/grandridge/cache.json index 877052db1490..9abddb06a837 100644 --- a/tools/perf/pmu-events/arch/x86/grandridge/cache.json +++ b/tools/perf/pmu-events/arch/x86/grandridge/cache.json @@ -286,7 +286,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_1024", @@ -297,7 +297,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_128", @@ -308,7 +308,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_16", @@ -319,7 +319,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_2048", @@ -330,7 +330,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_256", @@ -341,7 +341,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_32", @@ -352,7 +352,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_4", @@ -363,7 +363,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_512", @@ -374,7 +374,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_64", @@ -385,7 +385,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_8", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index dec7bdd770cf..888d38e49766 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -12,7 +12,7 @@ GenuineIntel-6-9[6C],v1.05,elkhartlake,core GenuineIntel-6-CF,v1.20,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core -GenuineIntel-6-B6,v1.09,grandridge,core +GenuineIntel-6-B6,v1.10,grandridge,core GenuineIntel-6-A[DE],v1.12,graniterapids,core GenuineIntel-6-(3C|45|46),v36,haswell,core GenuineIntel-6-3F,v29,haswellx,core From 399464cc90aac5ddde00b4da6ed68f971978b78f Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Sep 2025 10:27:31 -0700 Subject: [PATCH 2260/2711] perf vendor events intel: Update graniterapids events to v1.15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update graniterapids events to v1.15 released in: https://github.com/intel/perfmon/commit/8af960a34864d291ad5a5a9f8fdf5a40486b78a1 https://github.com/intel/perfmon/commit/943667ba5b3f3203e47aede6bc7d017a26b89a26 Event JSON automatically generated by: https://github.com/intel/perfmon/blob/main/scripts/create_perf_json.py Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Thomas Falcon Signed-off-by: Arnaldo Carvalho de Melo --- .../graniterapids/uncore-interconnect.json | 10 +- .../arch/x86/graniterapids/uncore-memory.json | 112 ++++++++++++++++++ tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-interconnect.json index 6667fbc50452..5eb1145f204f 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-interconnect.json @@ -833,11 +833,19 @@ "Counter": "0,1,2,3", "EventCode": "0x1F", "EventName": "UNC_I_MISC1.LOST_FWD", - "Experimental": "1", "PerPkg": "1", "UMask": "0x10", "Unit": "IRP" }, + { + "BriefDescription": "Misc Events - Set 1 : Received Invalid : Secondary received a transfer that did not have sufficient MESI state", + "Counter": "0,1,2,3", + "EventCode": "0x1F", + "EventName": "UNC_I_MISC1.SEC_RCVD_INVLD", + "PerPkg": "1", + "UMask": "0x20", + "Unit": "IRP" + }, { "BriefDescription": "Snoop Hit E/S responses", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json index 9d385be59e3d..f559e27e2815 100644 --- a/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/graniterapids/uncore-memory.json @@ -56,6 +56,33 @@ "UMask": "0xcf", "Unit": "IMC" }, + { + "BriefDescription": "CAS count for SubChannel 0 regular reads", + "Counter": "0,1,2,3", + "EventCode": "0x05", + "EventName": "UNC_M_CAS_COUNT_SCH0.RD_NON_UNDERFILL", + "PerPkg": "1", + "UMask": "0xc3", + "Unit": "IMC" + }, + { + "BriefDescription": "CAS count for SubChannel 0 auto-precharge reads", + "Counter": "0,1,2,3", + "EventCode": "0x05", + "EventName": "UNC_M_CAS_COUNT_SCH0.RD_PRE_REG", + "PerPkg": "1", + "UMask": "0xc2", + "Unit": "IMC" + }, + { + "BriefDescription": "CAS count for SubChannel 0 auto-precharge underfill reads", + "Counter": "0,1,2,3", + "EventCode": "0x05", + "EventName": "UNC_M_CAS_COUNT_SCH0.RD_PRE_UNDERFILL", + "PerPkg": "1", + "UMask": "0xc8", + "Unit": "IMC" + }, { "BriefDescription": "CAS count for SubChannel 0 regular reads", "Counter": "0,1,2,3", @@ -74,6 +101,15 @@ "UMask": "0xc4", "Unit": "IMC" }, + { + "BriefDescription": "CAS count for SubChannel 0 underfill reads", + "Counter": "0,1,2,3", + "EventCode": "0x05", + "EventName": "UNC_M_CAS_COUNT_SCH0.RD_UNDERFILL_ALL", + "PerPkg": "1", + "UMask": "0xcc", + "Unit": "IMC" + }, { "BriefDescription": "CAS count for SubChannel 0, all writes", "Counter": "0,1,2,3", @@ -121,6 +157,33 @@ "UMask": "0xcf", "Unit": "IMC" }, + { + "BriefDescription": "CAS count for SubChannel 1 regular reads", + "Counter": "0,1,2,3", + "EventCode": "0x06", + "EventName": "UNC_M_CAS_COUNT_SCH1.RD_NON_UNDERFILL", + "PerPkg": "1", + "UMask": "0xc3", + "Unit": "IMC" + }, + { + "BriefDescription": "CAS count for SubChannel 1 auto-precharge reads", + "Counter": "0,1,2,3", + "EventCode": "0x06", + "EventName": "UNC_M_CAS_COUNT_SCH1.RD_PRE_REG", + "PerPkg": "1", + "UMask": "0xc2", + "Unit": "IMC" + }, + { + "BriefDescription": "CAS count for SubChannel 1 auto-precharge underfill reads", + "Counter": "0,1,2,3", + "EventCode": "0x06", + "EventName": "UNC_M_CAS_COUNT_SCH1.RD_PRE_UNDERFILL", + "PerPkg": "1", + "UMask": "0xc8", + "Unit": "IMC" + }, { "BriefDescription": "CAS count for SubChannel 1 regular reads", "Counter": "0,1,2,3", @@ -139,6 +202,15 @@ "UMask": "0xc4", "Unit": "IMC" }, + { + "BriefDescription": "CAS count for SubChannel 1 underfill reads", + "Counter": "0,1,2,3", + "EventCode": "0x06", + "EventName": "UNC_M_CAS_COUNT_SCH1.RD_UNDERFILL_ALL", + "PerPkg": "1", + "UMask": "0xcc", + "Unit": "IMC" + }, { "BriefDescription": "CAS count for SubChannel 1, all writes", "Counter": "0,1,2,3", @@ -188,6 +260,46 @@ "PublicDescription": "DRAM Clockticks", "Unit": "IMC" }, + { + "BriefDescription": "PMMNT is sending REF* commands while being in specified Refresh rate", + "Counter": "0,1,2,3", + "EventCode": "0x72", + "EventName": "UNC_M_MNTCMD_REFRATE.REFAB1X", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x1", + "Unit": "IMC" + }, + { + "BriefDescription": "PMMNT is sending REF* commands while being in specified Refresh rate", + "Counter": "0,1,2,3", + "EventCode": "0x72", + "EventName": "UNC_M_MNTCMD_REFRATE.REFAB2X", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x4", + "Unit": "IMC" + }, + { + "BriefDescription": "PMMNT is sending REF* commands while being in specified Refresh rate", + "Counter": "0,1,2,3", + "EventCode": "0x72", + "EventName": "UNC_M_MNTCMD_REFRATE.REFSB1X", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x2", + "Unit": "IMC" + }, + { + "BriefDescription": "PMMNT is sending REF* commands while being in specified Refresh rate", + "Counter": "0,1,2,3", + "EventCode": "0x72", + "EventName": "UNC_M_MNTCMD_REFRATE.REFSB2X", + "Experimental": "1", + "PerPkg": "1", + "UMask": "0x8", + "Unit": "IMC" + }, { "BriefDescription": "# of cycles MR4 temp readings forced 2x refresh", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 888d38e49766..6c0a6c3d2451 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -13,7 +13,7 @@ GenuineIntel-6-CF,v1.20,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core GenuineIntel-6-B6,v1.10,grandridge,core -GenuineIntel-6-A[DE],v1.12,graniterapids,core +GenuineIntel-6-A[DE],v1.15,graniterapids,core GenuineIntel-6-(3C|45|46),v36,haswell,core GenuineIntel-6-3F,v29,haswellx,core GenuineIntel-6-7[DE],v1.24,icelake,core From b4e77a135c039a37b6b15d443b32885508a30ebe Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Sep 2025 10:27:32 -0700 Subject: [PATCH 2261/2711] perf vendor events intel: Update lunarlake events to v1.18 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update lunarlake events to v1.18 released in: https://github.com/intel/perfmon/commit/04e11e566618d781b854f526d7e394ed50420638 Event JSON automatically generated by: https://github.com/intel/perfmon/blob/main/scripts/create_perf_json.py Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Thomas Falcon Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/x86/lunarlake/cache.json | 46 +++++++++++++++++-- .../pmu-events/arch/x86/lunarlake/memory.json | 6 +-- .../pmu-events/arch/x86/lunarlake/other.json | 2 +- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/cache.json b/tools/perf/pmu-events/arch/x86/lunarlake/cache.json index 29bcb847178f..402ca8fc50b6 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/cache.json @@ -1305,6 +1305,18 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts writebacks of modified cachelines that were supplied by the L3 cache.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.COREWB_M.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x7E001E00008", + "PublicDescription": "Counts writebacks of modified cachelines that were supplied by the L3 cache. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts writebacks of non-modified cachelines that have any type of response.", "Counter": "0,1,2,3,4,5,6,7", @@ -1317,6 +1329,18 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts writebacks of non-modified cachelines that were supplied by the L3 cache.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.COREWB_NONM.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x7E001E01000", + "PublicDescription": "Counts writebacks of non-modified cachelines that were supplied by the L3 cache. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts demand instruction fetches and L1 instruction cache prefetches that have any type of response.", "Counter": "0,1,2,3,4,5,6,7", @@ -1355,7 +1379,7 @@ }, { "BriefDescription": "Counts demand data reads that have any type of response.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", @@ -1367,7 +1391,7 @@ }, { "BriefDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop hit in another cores caches, data forwarding is required as the data is modified.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM", "MSRIndex": "0x1a6,0x1a7", @@ -1379,7 +1403,7 @@ }, { "BriefDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop hit in another cores caches which forwarded the unmodified data to the requesting core.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD", "MSRIndex": "0x1a6,0x1a7", @@ -1415,7 +1439,7 @@ }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that have any type of response.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_RFO.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", @@ -1427,7 +1451,7 @@ }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by the L3 cache where a snoop hit in another cores caches, data forwarding is required as the data is modified.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_RFO.L3_HIT.SNOOP_HITM", "MSRIndex": "0x1a6,0x1a7", @@ -1437,6 +1461,18 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts all data read, code read, RFO and ITOM requests including demands and prefetches to the core caches (L1 or L2) that were supplied by the L3 cache.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.READS_TO_CORE.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x7E001E04477", + "PublicDescription": "Counts all data read, code read, RFO and ITOM requests including demands and prefetches to the core caches (L1 or L2) that were supplied by the L3 cache. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Any memory transaction that reached the SQ.", "Counter": "0,1,2,3,4,5,6,7,8,9", diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/memory.json b/tools/perf/pmu-events/arch/x86/lunarlake/memory.json index 25021cb76f61..caa387e10259 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/memory.json @@ -352,7 +352,7 @@ }, { "BriefDescription": "Counts demand data reads that were supplied by DRAM.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.DRAM", "MSRIndex": "0x1a6,0x1a7", @@ -376,7 +376,7 @@ }, { "BriefDescription": "Counts demand data reads that were not supplied by the L3 cache and were supplied by the system memory (DRAM, MSC, or MMIO).", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.L3_MISS", "MSRIndex": "0x1a6,0x1a7", @@ -412,7 +412,7 @@ }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were not supplied by the L3 cache and were supplied by the system memory (DRAM, MSC, or MMIO).", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_RFO.L3_MISS", "MSRIndex": "0x1a6,0x1a7", diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/other.json b/tools/perf/pmu-events/arch/x86/lunarlake/other.json index 59949f9541d8..1df716442549 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/other.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/other.json @@ -151,7 +151,7 @@ }, { "BriefDescription": "Counts streaming stores that have any type of response.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.STREAMING_WR.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 6c0a6c3d2451..aa0e2b0c4ba4 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -22,7 +22,7 @@ GenuineIntel-6-3A,v24,ivybridge,core GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core GenuineIntel-6-(57|85),v16,knightslanding,core -GenuineIntel-6-BD,v1.17,lunarlake,core +GenuineIntel-6-BD,v1.18,lunarlake,core GenuineIntel-6-(AA|AC|B5),v1.16,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core From 53366556aab277688b325994953ca0e91e4c7120 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Sep 2025 10:27:33 -0700 Subject: [PATCH 2262/2711] perf vendor events intel: Update meteorlake events to v1.17 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update lunarlake events to v1.17 released in: https://github.com/intel/perfmon/commit/ec387ac70602283d01da32c2ff5fe9cb15d3d25b Event JSON automatically generated by: https://github.com/intel/perfmon/blob/main/scripts/create_perf_json.py Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Thomas Falcon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../pmu-events/arch/x86/meteorlake/cache.json | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index aa0e2b0c4ba4..3a15a0f75b96 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -23,7 +23,7 @@ GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core GenuineIntel-6-(57|85),v16,knightslanding,core GenuineIntel-6-BD,v1.18,lunarlake,core -GenuineIntel-6-(AA|AC|B5),v1.16,meteorlake,core +GenuineIntel-6-(AA|AC|B5),v1.17,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core GenuineIntel-6-CC,v1.00,pantherlake,core diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/cache.json b/tools/perf/pmu-events/arch/x86/meteorlake/cache.json index f1d8db284a02..d4731e300d6d 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/cache.json @@ -1178,6 +1178,30 @@ "UMask": "0x3", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts writebacks of modified cachelines that hit in the L3 or were snooped from another core's caches.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.COREWB_M.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x3F803C0008", + "PublicDescription": "Counts writebacks of modified cachelines that hit in the L3 or were snooped from another core's caches. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts writebacks of non-modified cachelines that hit in the L3 or were snooped from another core's caches.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.COREWB_NONM.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x3F803C1000", + "PublicDescription": "Counts writebacks of non-modified cachelines that hit in the L3 or were snooped from another core's caches. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts demand instruction fetches and L1 instruction cache prefetches that have any type of response.", "Counter": "0,1,2,3,4,5,6,7", @@ -1394,6 +1418,18 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts all data read, code read, RFO and ITOM requests including demands and prefetches to the core caches (L1 or L2) that hit in the L3 or were snooped from another core's caches.", + "Counter": "0,1,2,3", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.READS_TO_CORE.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x3F803C4477", + "PublicDescription": "Counts all data read, code read, RFO and ITOM requests including demands and prefetches to the core caches (L1 or L2) that hit in the L3 or were snooped from another core's caches. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Any memory transaction that reached the SQ.", "Counter": "0,1,2,3", From dd171167f220d01331b40b1c6c1cff820e861cf2 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Sep 2025 10:27:34 -0700 Subject: [PATCH 2263/2711] perf vendor events intel: Update pantherlake events to v1.00 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update pantherlake events to v1.00 released in: https://github.com/intel/perfmon/commit/b149786b6f9db18c09e6c89f3eb4fdb849ead2cf Event JSON automatically generated by: https://github.com/intel/perfmon/blob/main/scripts/create_perf_json.py Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Thomas Falcon Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/pantherlake/cache.json | 1125 +++++++++++- .../arch/x86/pantherlake/counter.json | 9 +- .../arch/x86/pantherlake/floating-point.json | 286 +++ .../arch/x86/pantherlake/frontend.json | 535 ++++++ .../arch/x86/pantherlake/memory.json | 106 +- .../arch/x86/pantherlake/other.json | 44 + .../arch/x86/pantherlake/pipeline.json | 1600 ++++++++++++++++- .../arch/x86/pantherlake/uncore-memory.json | 26 + .../arch/x86/pantherlake/virtual-memory.json | 248 +++ 9 files changed, 3932 insertions(+), 47 deletions(-) create mode 100644 tools/perf/pmu-events/arch/x86/pantherlake/floating-point.json create mode 100644 tools/perf/pmu-events/arch/x86/pantherlake/other.json create mode 100644 tools/perf/pmu-events/arch/x86/pantherlake/uncore-memory.json diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/cache.json b/tools/perf/pmu-events/arch/x86/pantherlake/cache.json index c84f3d9fdb10..7098ea1d6d16 100644 --- a/tools/perf/pmu-events/arch/x86/pantherlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/pantherlake/cache.json @@ -1,4 +1,135 @@ [ + { + "BriefDescription": "Counts the number of cache lines replaced in L0 data cache.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x51", + "EventName": "L1D.L0_REPLACEMENT", + "PublicDescription": "Counts L0 data line replacements including opportunistic replacements, and replacements that require stall-for-replace or block-for-replace.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cachelines replaced into the L1 d-cache. Successful replacements only (not blocked) and exclude WB-miss case", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x51", + "EventName": "L1D.L1_REPLACEMENT", + "PublicDescription": "Counts cachelines replaced into the L1 d-cache.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cachelines replaced into the L0 and L1 d-cache. Successful replacements only (not blocked) and exclude WB-miss case", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x51", + "EventName": "L1D.REPLACEMENT", + "PublicDescription": "Counts cachelines replaced into the L0 and L1 d-cache.", + "SampleAfterValue": "1000003", + "UMask": "0x5", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x49", + "EventName": "L1D_MISS.FB_FULL", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D Fill Buffer (FB) unavailability. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of cycles a demand request has waited due to L1D due to lack of L2 resources.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x49", + "EventName": "L1D_MISS.L2_STALLS", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of demand requests that missed L1D cache", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x49", + "EventName": "L1D_MISS.LOAD", + "PublicDescription": "Count occurrences (rising-edge) of DCACHE_PENDING sub-event0. Impl. sends per-port binary inc-bit the occupancy increases* (at FB alloc or promotion).", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of L1D misses that are outstanding", + "Counter": "2", + "EventCode": "0x48", + "EventName": "L1D_PENDING.LOAD", + "PublicDescription": "Counts number of L1D misses that are outstanding in each cycle, that is each cycle the number of Fill Buffers (FB) outstanding required by Demand Reads. FB either is held by demand loads, or it is held by non-demand loads and gets hit at least once by demand. The valid outstanding interval is defined until the FB deallocation by one of the following ways: from FB allocation, if FB is allocated by demand from the demand Hit FB, if it is allocated by hardware or software prefetch. Note: In the L1D, a Demand Read contains cacheable or noncacheable demand loads, including ones causing cache-line splits and reads due to page walks resulted from any request type.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles with L1D load Misses outstanding.", + "Counter": "2", + "CounterMask": "1", + "EventCode": "0x48", + "EventName": "L1D_PENDING.LOAD_CYCLES", + "PublicDescription": "Counts duration of L1D miss outstanding in cycles.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L2 cache lines filling L2", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x25", + "EventName": "L2_LINES_IN.ALL", + "PublicDescription": "Counts the number of L2 cache lines filling the L2. Counting does not cover rejects.", + "SampleAfterValue": "100003", + "UMask": "0x1f", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of cache lines filled into the L2 cache that are in Exclusive state", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x25", + "EventName": "L2_LINES_IN.E", + "PublicDescription": "Counts the number of cache lines filled into the L2 cache that are in Exclusive state. Counts on a per core basis.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Modified cache lines that are evicted by L2 cache when triggered by an L2 cache fill.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x26", + "EventName": "L2_LINES_OUT.NON_SILENT", + "PublicDescription": "Counts the number of lines that are evicted by L2 cache when triggered by an L2 cache fill. Those lines are in Modified state. Modified lines are written back to L3", + "SampleAfterValue": "200003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Non-modified cache lines that are silently dropped by L2 cache.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x26", + "EventName": "L2_LINES_OUT.SILENT", + "PublicDescription": "Counts the number of lines that are silently dropped by L2 cache. These lines are typically in Shared or Exclusive state. A non-threaded event.", + "SampleAfterValue": "200003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cache lines that have been L2 hardware prefetched but not used by demand accesses", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x26", + "EventName": "L2_LINES_OUT.USELESS_HWPF", + "PublicDescription": "Counts the number of cache lines that have been prefetched by the L2 hardware prefetcher but not used by demand access when evicted from the L2 cache", + "SampleAfterValue": "200003", + "UMask": "0x4", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of L2 cache accesses from front door requests for Code Read, Data Read, RFO, ITOM, and L2 Prefetches. Does not include rejects or recycles, per core event.", "Counter": "0,1,2,3,4,5,6,7", @@ -8,6 +139,35 @@ "UMask": "0x1ff", "Unit": "cpu_atom" }, + { + "BriefDescription": "All accesses to L2 cache [This event is alias to L2_RQSTS.REFERENCES, L2_RQSTS.ANY]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_REQUEST.ALL", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES, L2_RQSTS.ANY]", + "SampleAfterValue": "200003", + "UMask": "0xff", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of L2 cache accesses from front door requests that resulted in a Hit. Does not include rejects or recycles, per core event.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x24", + "EventName": "L2_REQUEST.HIT", + "SampleAfterValue": "1000003", + "UMask": "0x1bf", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Read requests with true-miss in L2 cache [This event is alias to L2_RQSTS.MISS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_REQUEST.MISS", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.MISS]", + "SampleAfterValue": "200003", + "UMask": "0x3f", + "Unit": "cpu_core" + }, { "BriefDescription": "L2 code requests", "Counter": "0,1,2,3,4,5,6,7,8,9", @@ -28,6 +188,106 @@ "UMask": "0xe1", "Unit": "cpu_core" }, + { + "BriefDescription": "All accesses to L2 cache [This event is alias to L2_RQSTS.REFERENCES, L2_REQUEST.ALL]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_RQSTS.ANY", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_RQSTS.REFERENCES, L2_REQUEST.ALL]", + "SampleAfterValue": "200003", + "UMask": "0xff", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L2 cache hits when fetching instructions, code reads.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_RQSTS.CODE_RD_HIT", + "PublicDescription": "Counts L2 cache hits when fetching instructions, code reads.", + "SampleAfterValue": "200003", + "UMask": "0x44", + "Unit": "cpu_core" + }, + { + "BriefDescription": "L2 cache misses when fetching instructions", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_RQSTS.CODE_RD_MISS", + "PublicDescription": "Counts L2 cache misses when fetching instructions.", + "SampleAfterValue": "200003", + "UMask": "0x24", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand Data Read requests that hit L2 cache", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_RQSTS.DEMAND_DATA_RD_HIT", + "PublicDescription": "Counts the number of demand Data Read requests initiated by load instructions that hit L2 cache.", + "SampleAfterValue": "200003", + "UMask": "0x41", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand Data Read miss L2 cache", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS", + "PublicDescription": "Counts demand Data Read requests with true-miss in the L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. An access is counted once.", + "SampleAfterValue": "200003", + "UMask": "0x21", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Read requests with true-miss in L2 cache [This event is alias to L2_REQUEST.MISS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_RQSTS.MISS", + "PublicDescription": "Counts read requests of any type with true-miss in the L2 cache. True-miss excludes L2 misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.MISS]", + "SampleAfterValue": "200003", + "UMask": "0x3f", + "Unit": "cpu_core" + }, + { + "BriefDescription": "All accesses to L2 cache [This event is alias to L2_REQUEST.ALL,L2_RQSTS.ANY]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_RQSTS.REFERENCES", + "PublicDescription": "Counts all requests that were hit or true misses in L2 cache. True-miss excludes misses that were merged with ongoing L2 misses. [This event is alias to L2_REQUEST.ALL,L2_RQSTS.ANY]", + "SampleAfterValue": "200003", + "UMask": "0xff", + "Unit": "cpu_core" + }, + { + "BriefDescription": "RFO requests that hit L2 cache", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_RQSTS.RFO_HIT", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that hit L2 cache.", + "SampleAfterValue": "200003", + "UMask": "0x42", + "Unit": "cpu_core" + }, + { + "BriefDescription": "RFO requests that miss L2 cache", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x24", + "EventName": "L2_RQSTS.RFO_MISS", + "PublicDescription": "Counts the RFO (Read-for-Ownership) requests that miss L2 cache.", + "SampleAfterValue": "200003", + "UMask": "0x22", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when L1D is locked", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x42", + "EventName": "LOCK_CYCLES.CACHE_LOCK_DURATION", + "PublicDescription": "This event counts the number of cycles when the L1D is locked.", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of cacheable memory requests that miss in the LLC. Counts on a per core basis.", "Counter": "0,1,2,3,4,5,6,7", @@ -68,13 +328,68 @@ "UMask": "0x4f", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts the number of unhalted cycles when the core is stalled due to an L1 demand load miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS_LOAD.ALL", + "SampleAfterValue": "1000003", + "UMask": "0x7f", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles the core is stalled due to a demand load which hit in the L2 cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS_LOAD.L2_HIT", + "PublicDescription": "Counts the number of cycles a core is stalled due to a demand load which hit in the L2 cache.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles the core is stalled due to a demand load which hit in the L2 cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS_LOAD.L2_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x7e", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of unhalted cycles when the core is stalled due to a demand load miss which hit in the LLC.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS_LOAD.LLC_HIT", + "SampleAfterValue": "1000003", + "UMask": "0x6", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of unhalted cycles when the core is stalled due to a demand load miss which missed all the local caches.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS_LOAD.LLC_MISS", + "SampleAfterValue": "1000003", + "UMask": "0x38", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of unhalted cycles when the core is stalled due to a demand load miss which missed all the caches. DRAM, MMIO or other LOCAL memory type provides the data.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS_LOAD.LLC_MISS_LOCALMEM", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts all retired load instructions.", "Counter": "0,1,2,3", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.ALL_LOADS", - "PublicDescription": "Counts Instructions with at least one architecturally visible load retired. Available PDIST counters: 0", + "PublicDescription": "Counts Instructions with at least one architecturally visible load retired. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x81", "Unit": "cpu_core" @@ -85,16 +400,442 @@ "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_INST_RETIRED.ALL_STORES", - "PublicDescription": "Counts all retired store instructions. Available PDIST counters: 0", + "PublicDescription": "Counts all retired store instructions. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x82", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired software prefetch instructions.", + "Counter": "0,1,2,3", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.ALL_SWPF", + "PublicDescription": "Counts all retired software prefetch instructions. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x84", + "Unit": "cpu_core" + }, + { + "BriefDescription": "All retired memory instructions.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.ANY", + "PublicDescription": "Counts all retired memory instructions - loads and stores. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x87", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions with locked access.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.LOCK_LOADS", + "PublicDescription": "Counts retired load instructions with locked access. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x21", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions that split across a cacheline boundary.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.SPLIT_LOADS", + "PublicDescription": "Counts retired load instructions that split across a cacheline boundary. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x41", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired store instructions that split across a cacheline boundary.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.SPLIT_STORES", + "PublicDescription": "Counts retired store instructions that split across a cacheline boundary. Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x42", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that hit the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_HIT_ANY", + "PublicDescription": "Number of retired instructions with a clean hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0xf", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions that hit the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_HIT_LOADS", + "PublicDescription": "Number of retired load instructions with a clean hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x9", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired store instructions that hit the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_HIT_STORES", + "PublicDescription": "Number of retired store instructions that hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0xa", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired SWPF instructions that hit the STLB.", + "Counter": "0,1,2,3", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_HIT_SWPF", + "PublicDescription": "Number of retired SWPF instructions that hit in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0xc", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that miss the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_MISS_ANY", + "PublicDescription": "Number of retired instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x17", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions that miss the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_MISS_LOADS", + "PublicDescription": "Number of retired load instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x11", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired store instructions that miss the STLB.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_MISS_STORES", + "PublicDescription": "Number of retired store instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x12", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired SWPF instructions that miss the STLB.", + "Counter": "0,1,2,3", + "EventCode": "0xd0", + "EventName": "MEM_INST_RETIRED.STLB_MISS_SWPF", + "PublicDescription": "Number of retired SWPF instructions that (start a) miss in the 2nd-level TLB (STLB). Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x14", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions whose data sources were a cross-core Snoop hits and forwards data from an in on-package core cache (induced by NI$)", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd2", + "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD", + "PublicDescription": "Counts retired load instructions whose data sources were a cross-core Snoop hits and forwards data from an in on-package core cache (induced by NI$) Available PDIST counters: 0,1", + "SampleAfterValue": "20011", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions whose data sources were HitM responses from shared L3, Hit-with-FWD is normally excluded.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd2", + "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_HITM", + "PublicDescription": "Counts retired load instructions whose data sources were HitM responses from shared L3, Hit-with-FWD is normally excluded. Available PDIST counters: 0,1", + "SampleAfterValue": "20011", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions whose data sources were L3 hit and cross-core snoop missed in on-pkg core cache.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd2", + "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS", + "PublicDescription": "Counts the retired load instructions whose data sources were L3 hit and cross-core snoop missed in on-pkg core cache. Available PDIST counters: 0,1", + "SampleAfterValue": "20011", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions whose data sources were L3 and cross-core snoop hits in on-pkg core cache", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd2", + "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD", + "PublicDescription": "Counts retired load instructions whose data sources were L3 and cross-core snoop hits in on-pkg core cache. Available PDIST counters: 0,1", + "SampleAfterValue": "20011", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions which data source is memory side cache.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd3", + "EventName": "MEM_LOAD_L3_MISS_RETIRED.MEMSIDE_CACHE", + "PublicDescription": "Retired load instructions which data source is memory side cache. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions with at least 1 uncacheable load or lock.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd4", + "EventName": "MEM_LOAD_MISC_RETIRED.UC", + "PublicDescription": "Retired instructions with at least one load to uncacheable memory-type, or at least one cache-line split locked access (Bus Lock). Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of completed demand load requests that missed the L1, but hit the FB(fill buffer), because a preceding miss to the same cacheline initiated the line to be brought into L1, but data is not yet ready in L1.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.FB_HIT", + "PublicDescription": "Counts retired load instructions with at least one uop was load missed in L1 but hit FB (Fill Buffers) due to preceding miss to the same cache line with data not ready. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions with L1 cache hits as data sources", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L1_HIT", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x101", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts retired load instructions with at least one uop that hit in the Level 0 of the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source.", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L1_HIT_L0", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 0 of the L1 data cache. This event includes all SW prefetches and lock instructions regardless of the data source. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts retired load instructions with at least one uop that hit in the Level 1 of the L1 data cache.", + "Counter": "0,1,2,3", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L1_HIT_L1", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the Level 1 of the L1 data cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions missed L1 cache as data sources", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L1_MISS", + "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L1 cache. Available PDIST counters: 0,1", + "SampleAfterValue": "200003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions with L2 cache hits as data sources", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L2_HIT", + "PublicDescription": "Counts retired load instructions with L2 cache hits as data sources. Available PDIST counters: 0,1", + "SampleAfterValue": "200003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions missed L2 cache as data sources", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L2_MISS", + "PublicDescription": "Counts retired load instructions missed L2 cache as data sources. Available PDIST counters: 0,1", + "SampleAfterValue": "100021", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions with L3 cache hits as data sources", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L3_HIT", + "PublicDescription": "Counts retired load instructions with at least one uop that hit in the L3 cache. Available PDIST counters: 0,1", + "SampleAfterValue": "100021", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired load instructions missed L3 cache as data sources", + "Counter": "0,1,2,3", + "Data_LA": "1", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_RETIRED.L3_MISS", + "PublicDescription": "Counts retired load instructions with at least one uop that missed in the L3 cache. Available PDIST counters: 0,1", + "SampleAfterValue": "50021", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of load ops retired that miss the L3 cache and hit in DRAM", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd3", + "EventName": "MEM_LOAD_UOPS_L3_MISS_RETIRED.LOCAL_DRAM", + "PublicDescription": "Counts the number of load ops retired that miss the L3 cache and hit in DRAM Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of load ops retired that miss the L3 cache and hit in memside cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd3", + "EventName": "MEM_LOAD_UOPS_L3_MISS_RETIRED.MEMSIDE_CACHE", + "PublicDescription": "Counts the number of load ops retired that miss the L3 cache and hit in memside cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of load ops retired that hit the L1 data cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_UOPS_RETIRED.L1_HIT", + "PublicDescription": "Counts the number of load ops retired that hit the L1 data cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of load ops retired that miss in the L1 data cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_UOPS_RETIRED.L1_MISS", + "PublicDescription": "Counts the number of load ops retired that miss in the L1 data cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of load ops retired that hit in the L2 cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_UOPS_RETIRED.L2_HIT", + "PublicDescription": "Counts the number of load ops retired that hit in the L2 cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of load ops retired that miss in the L2 cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_UOPS_RETIRED.L2_MISS", + "PublicDescription": "Counts the number of load ops retired that miss in the L2 cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x80", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of load ops retired that hit in the L3 cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd1", + "EventName": "MEM_LOAD_UOPS_RETIRED.L3_HIT", + "PublicDescription": "Counts the number of load ops retired that hit in the L3 cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1c", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that uops are blocked for any of the following reasons: load buffer, store buffer or RSV full.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x04", + "EventName": "MEM_SCHEDULER_BLOCK.ALL", + "SampleAfterValue": "1000003", + "UMask": "0x7", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that uops are blocked due to a load buffer full condition.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x04", + "EventName": "MEM_SCHEDULER_BLOCK.LD_BUF", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that uops are blocked due to an RSV full condition.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x04", + "EventName": "MEM_SCHEDULER_BLOCK.RSV", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of cycles that uops are blocked due to a store buffer full condition.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x04", + "EventName": "MEM_SCHEDULER_BLOCK.ST_BUF", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "MEM_STORE_RETIRED.L2_HIT", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x44", + "EventName": "MEM_STORE_RETIRED.L2_HIT", + "SampleAfterValue": "200003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of cache-lines required by retired stores whose Data Source is: Memory Side Cache", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x44", + "EventName": "MEM_STORE_RETIRED.MEMSIDE_CACHE", + "SampleAfterValue": "100021", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of load ops retired.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.ALL_LOADS", + "PublicDescription": "Counts the number of load ops retired. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x81", "Unit": "cpu_atom" @@ -104,129 +845,245 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.ALL_STORES", + "PublicDescription": "Counts the number of store ops retired. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x82", "Unit": "cpu_atom" }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_1024", "MSRIndex": "0x3F6", "MSRValue": "0x400", + "PublicDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_atom" }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_128", "MSRIndex": "0x3F6", "MSRValue": "0x80", + "PublicDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_atom" }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_16", "MSRIndex": "0x3F6", "MSRValue": "0x10", + "PublicDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_atom" }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_2048", "MSRIndex": "0x3F6", "MSRValue": "0x800", + "PublicDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_atom" }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_256", "MSRIndex": "0x3F6", "MSRValue": "0x100", + "PublicDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_atom" }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_32", "MSRIndex": "0x3F6", "MSRValue": "0x20", + "PublicDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_atom" }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_4", "MSRIndex": "0x3F6", "MSRValue": "0x4", + "PublicDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_atom" }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_512", "MSRIndex": "0x3F6", "MSRValue": "0x200", + "PublicDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_atom" }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_64", "MSRIndex": "0x3F6", "MSRValue": "0x40", + "PublicDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_atom" }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_8", "MSRIndex": "0x3F6", "MSRValue": "0x8", + "PublicDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x5", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of load uops retired that performed one or more locks", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd0", + "EventName": "MEM_UOPS_RETIRED.LOCK_LOADS", + "PublicDescription": "Counts the number of load uops retired that performed one or more locks Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x21", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of memory uops retired that were splits.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd0", + "EventName": "MEM_UOPS_RETIRED.SPLIT", + "PublicDescription": "Counts the number of memory uops retired that were splits. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x43", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retired split load uops.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd0", + "EventName": "MEM_UOPS_RETIRED.SPLIT_LOADS", + "PublicDescription": "Counts the number of retired split load uops. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x41", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retired split store uops.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd0", + "EventName": "MEM_UOPS_RETIRED.SPLIT_STORES", + "PublicDescription": "Counts the number of retired split store uops. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x42", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of memory uops retired that missed in the second level TLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd0", + "EventName": "MEM_UOPS_RETIRED.STLB_MISS", + "PublicDescription": "Counts the number of memory uops retired that missed in the second level TLB. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x13", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of load uops retired that miss in the second Level TLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd0", + "EventName": "MEM_UOPS_RETIRED.STLB_MISS_LOADS", + "PublicDescription": "Counts the number of load uops retired that miss in the second Level TLB. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x11", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of store uops retired that miss in the second level TLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd0", + "EventName": "MEM_UOPS_RETIRED.STLB_MISS_STORES", + "PublicDescription": "Counts the number of store uops retired that miss in the second level TLB. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x12", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts the number of stores uops retired same as MEM_UOPS_RETIRED.ALL_STORES", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.STORE_LATENCY", + "PublicDescription": "Counts the number of stores uops retired same as MEM_UOPS_RETIRED.ALL_STORES Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x6", "Unit": "cpu_atom" }, + { + "BriefDescription": "Retired memory uops for any access", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xe5", + "EventName": "MEM_UOP_RETIRED.ANY", + "PublicDescription": "Number of retired micro-operations (uops) for load or store memory accesses", + "SampleAfterValue": "1000003", + "UMask": "0xf", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts writebacks of modified cachelines that were supplied by the L3 cache.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.COREWB_M.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x7E001E00008", + "PublicDescription": "Counts writebacks of modified cachelines that were supplied by the L3 cache. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts writebacks of non-modified cachelines that were supplied by the L3 cache.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.COREWB_NONM.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x7E001E01000", + "PublicDescription": "Counts writebacks of non-modified cachelines that were supplied by the L3 cache. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts demand data reads that have any type of response.", "Counter": "0,1,2,3,4,5,6,7", @@ -241,7 +1098,7 @@ }, { "BriefDescription": "Counts demand data reads that have any type of response.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", @@ -251,6 +1108,30 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop hit in another cores caches, data forwarding is required as the data is modified.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x40001E00001", + "PublicDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop hit in another cores caches, data forwarding is required as the data is modified. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop hit in another cores caches which forwarded the unmodified data to the requesting core.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x20001E00001", + "PublicDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop hit in another cores caches which forwarded the unmodified data to the requesting core. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that have any type of response.", "Counter": "0,1,2,3,4,5,6,7", @@ -265,7 +1146,7 @@ }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that have any type of response.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_RFO.ANY_RESPONSE", "MSRIndex": "0x1a6,0x1a7", @@ -274,5 +1155,221 @@ "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by the L3 cache where a snoop hit in another cores caches, data forwarding is required as the data is modified.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_RFO.L3_HIT.SNOOP_HITM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x40001E00002", + "PublicDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were supplied by the L3 cache where a snoop hit in another cores caches, data forwarding is required as the data is modified. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts all data read, code read, RFO and ITOM requests including demands and prefetches to the core caches (L1 or L2) that were supplied by the L3 cache.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.READS_TO_CORE.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x7E001E04477", + "PublicDescription": "Counts all data read, code read, RFO and ITOM requests including demands and prefetches to the core caches (L1 or L2) that were supplied by the L3 cache. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Any memory transaction that reached the SQ.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x21", + "EventName": "OFFCORE_REQUESTS.ALL_REQUESTS", + "PublicDescription": "Counts memory transactions reached the super queue including requests initiated by the core, all L3 prefetches, page walks, etc..", + "SampleAfterValue": "100003", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand and prefetch data reads", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x21", + "EventName": "OFFCORE_REQUESTS.DATA_RD", + "PublicDescription": "Counts the demand and prefetch data reads. All Core Data Reads include cacheable 'Demands' and L2 prefetchers (not L3 prefetchers). Counting also covers reads due to page walks resulted from any request type.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cacheable and Non-Cacheable code read requests", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x21", + "EventName": "OFFCORE_REQUESTS.DEMAND_CODE_RD", + "PublicDescription": "Counts both cacheable and Non-Cacheable code read requests.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand Data Read requests sent to uncore", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x21", + "EventName": "OFFCORE_REQUESTS.DEMAND_DATA_RD", + "PublicDescription": "Counts the Demand Data Read requests sent to uncore. Use it in conjunction with OFFCORE_REQUESTS_OUTSTANDING to determine average latency in the uncore.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Demand RFO requests including regular RFOs, locks, ItoM", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x21", + "EventName": "OFFCORE_REQUESTS.DEMAND_RFO", + "PublicDescription": "Counts the demand RFO (read for ownership) requests including regular RFOs, locks, ItoM.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when offcore outstanding cacheable Core Data Read transactions are present in SuperQueue (SQ), queue to uncore.", + "Counter": "0,1,2,3", + "CounterMask": "1", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD", + "PublicDescription": "Counts cycles when offcore outstanding cacheable Core Data Read transactions are present in the super queue. A transaction is considered to be in the Offcore outstanding state between L2 miss and transaction completion sent to requestor (SQ de-allocation). See corresponding Umask under OFFCORE_REQUESTS.", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles with offcore outstanding Code Reads transactions in the SuperQueue (SQ), queue to uncore.", + "Counter": "0,1,2,3", + "CounterMask": "1", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_CODE_RD", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where at least 1 outstanding demand data read request is pending.", + "Counter": "0,1,2,3", + "CounterMask": "1", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles with offcore outstanding demand rfo reads transactions in SuperQueue (SQ), queue to uncore.", + "Counter": "0,1,2,3", + "CounterMask": "1", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO", + "PublicDescription": "Counts the number of offcore outstanding demand rfo Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Offcore outstanding cacheable Core Data Read transactions in SuperQueue (SQ), queue to uncore", + "Counter": "0,1,2,3", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD", + "PublicDescription": "Counts the number of offcore outstanding cacheable Core Data Read transactions in the super queue every cycle. A transaction is considered to be in the Offcore outstanding state between L2 miss and transaction completion sent to requestor (SQ de-allocation). See corresponding Umask under OFFCORE_REQUESTS.", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Offcore outstanding Code Reads transactions in the SuperQueue (SQ), queue to uncore, every cycle.", + "Counter": "0,1,2,3", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_CODE_RD", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "For every cycle, increments by the number of outstanding demand data read requests pending.", + "Counter": "0,1,2,3", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD", + "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Store Read transactions pending for off-core. Highly correlated.", + "Counter": "0,1,2,3", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_RFO", + "PublicDescription": "Counts the number of off-core outstanding read-for-ownership (RFO) store transactions every cycle. An RFO transaction is considered to be in the Off-core outstanding state between L2 cache miss and transaction completion.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts bus locks, accounts for cache line split locks and UC locks.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2c", + "EventName": "SQ_MISC.BUS_LOCK", + "PublicDescription": "Counts the more expensive bus lock needed to enforce cache coherency for certain memory accesses that need to be done atomically. Can be created by issuing an atomic instruction (via the LOCK prefix) which causes a cache line split or accesses uncacheable memory.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of PREFETCHNTA, PREFETCHW, PREFETCHT0, PREFETCHT1 or PREFETCHT2 instructions executed.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.ANY", + "SampleAfterValue": "100003", + "UMask": "0xf", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHNTA instructions executed.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.NTA", + "PublicDescription": "Counts the number of PREFETCHNTA instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHW instructions executed.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.PREFETCHW", + "PublicDescription": "Counts the number of PREFETCHW instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHT0 instructions executed.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.T0", + "PublicDescription": "Counts the number of PREFETCHT0 instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHT1 or PREFETCHT2 instructions executed.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.T1_T2", + "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" } ] diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/counter.json b/tools/perf/pmu-events/arch/x86/pantherlake/counter.json index 69f158a97707..432b6946ccbc 100644 --- a/tools/perf/pmu-events/arch/x86/pantherlake/counter.json +++ b/tools/perf/pmu-events/arch/x86/pantherlake/counter.json @@ -1,12 +1,17 @@ [ { "Unit": "cpu_atom", - "CountersNumFixed": "3", - "CountersNumGeneric": "39" + "CountersNumFixed": "7", + "CountersNumGeneric": "8" }, { "Unit": "cpu_core", "CountersNumFixed": "4", "CountersNumGeneric": "10" + }, + { + "Unit": "iMC", + "CountersNumFixed": "0", + "CountersNumGeneric": "5" } ] \ No newline at end of file diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/floating-point.json b/tools/perf/pmu-events/arch/x86/pantherlake/floating-point.json new file mode 100644 index 000000000000..57c26866bc79 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/pantherlake/floating-point.json @@ -0,0 +1,286 @@ +[ + { + "BriefDescription": "Cycles when floating-point divide unit is busy executing divide or square root operations.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0xb0", + "EventName": "ARITH.FPDIV_ACTIVE", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for floating-point operations only.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts all microcode FP assists.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc1", + "EventName": "ASSISTS.FP", + "PublicDescription": "Counts all microcode Floating Point assists.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "ASSISTS.SSE_AVX_MIX", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc1", + "EventName": "ASSISTS.SSE_AVX_MIX", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of FP-arith-uops dispatched on 1st VEC port (port 0). FP-arith-uops are of type ADD* / SUB* / MUL / FMA* / DPP.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V0", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of FP-arith-uops dispatched on 2nd VEC port (port 1)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V1", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of FP-arith-uops dispatched on 3rd VEC port (port 5)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V2", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of FP-arith-uops dispatched on 4th VEC port", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V3", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.128B_PACKED_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.128B_PACKED_SINGLE", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.256B_PACKED_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 4 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.256B_PACKED_SINGLE", + "PublicDescription": "Number of SSE/AVX computational 256-bit packed single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 8 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT RSQRT RCP DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of SSE/AVX computational 128-bit packed single and 256-bit packed double precision FP instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, 1 for each element. Applies to SSE* and AVX* packed single precision and packed double precision FP instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.4_FLOPS", + "PublicDescription": "Number of SSE/AVX computational 128-bit packed single precision and 256-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 or/and 4 computation operations, one for each element. Applies to SSE* and AVX* packed single precision floating-point and packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX RCP14 RSQRT14 SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x18", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of SSE/AVX computational scalar floating-point instructions retired; some instructions will count twice as noted below. Applies to SSE* and AVX* scalar, double and single precision floating-point: ADD SUB MUL DIV MIN MAX RCP14 RSQRT14 RANGE SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform multiple calculations per element.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.SCALAR", + "PublicDescription": "Number of SSE/AVX computational scalar single precision and double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "1000003", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.SCALAR_DOUBLE", + "PublicDescription": "Number of SSE/AVX computational scalar double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar double precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.SCALAR_SINGLE", + "PublicDescription": "Number of SSE/AVX computational scalar single precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 1 computational operation. Applies to SSE* and AVX* scalar single precision floating-point instructions: ADD SUB MUL DIV MIN MAX SQRT RSQRT RCP FM(N)ADD/SUB. FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of any Vector retired FP arithmetic instructions", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.VECTOR", + "PublicDescription": "Number of any Vector retired FP arithmetic instructions. The DAZ and FTZ flags in the MXCSR register need to be set when using these events.", + "SampleAfterValue": "1000003", + "UMask": "0x3c", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_OPS_RETIRED.VECTOR_128B", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.VECTOR_128B", + "SampleAfterValue": "100003", + "UMask": "0xc", + "Unit": "cpu_core" + }, + { + "BriefDescription": "FP_ARITH_OPS_RETIRED.VECTOR_256B", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc7", + "EventName": "FP_ARITH_OPS_RETIRED.VECTOR_256B", + "SampleAfterValue": "100003", + "UMask": "0x30", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of all types of floating point operations per uop with all default weighting", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_FLOPS_RETIRED.ALL", + "PublicDescription": "Counts the number of all types of floating point operations per uop with all default weighting Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x3", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of floating point operations that produce 32 bit single precision results", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_FLOPS_RETIRED.FP32", + "PublicDescription": "Counts the number of floating point operations that produce 32 bit single precision results Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of floating point operations that produce 64 bit double precision results", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc8", + "EventName": "FP_FLOPS_RETIRED.FP64", + "PublicDescription": "Counts the number of floating point operations that produce 64 bit double precision results Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retired instructions whose sources are a packed 128 bit double precision floating point. This may be SSE or AVX.128 operations.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_INST_RETIRED.128B_DP", + "PublicDescription": "Counts the number of retired instructions whose sources are a packed 128 bit double precision floating point. This may be SSE or AVX.128 operations. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retired instructions whose sources are a packed 128 bit single precision floating point. This may be SSE or AVX.128 operations.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_INST_RETIRED.128B_SP", + "PublicDescription": "Counts the number of retired instructions whose sources are a packed 128 bit single precision floating point. This may be SSE or AVX.128 operations. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retired instructions whose sources are a packed 256 bit double precision floating point.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_INST_RETIRED.256B_DP", + "PublicDescription": "Counts the number of retired instructions whose sources are a packed 256 bit double precision floating point. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retired instructions whose sources are a packed 256 bit single precision floating point.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_INST_RETIRED.256B_SP", + "PublicDescription": "Counts the number of retired instructions whose sources are a packed 256 bit single precision floating point. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retired instructions whose sources are a scalar 32bit single precision floating point.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_INST_RETIRED.32B_SP", + "PublicDescription": "Counts the number of retired instructions whose sources are a scalar 32bit single precision floating point. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retired instructions whose sources are a scalar 64 bit double precision floating point.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_INST_RETIRED.64B_DP", + "PublicDescription": "Counts the number of retired instructions whose sources are a scalar 64 bit double precision floating point. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the total number of floating point retired instructions.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc7", + "EventName": "FP_INST_RETIRED.ALL", + "PublicDescription": "Counts the total number of floating point retired instructions. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x3f", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of floating point operations retired that required microcode assist.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.FP_ASSIST", + "PublicDescription": "Counts the number of floating point operations retired that required microcode assist, which is not a reflection of the number of FP operations, instructions or uops.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + } +] diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/frontend.json b/tools/perf/pmu-events/arch/x86/pantherlake/frontend.json index aedf631e3c0f..d36faa683d3f 100644 --- a/tools/perf/pmu-events/arch/x86/pantherlake/frontend.json +++ b/tools/perf/pmu-events/arch/x86/pantherlake/frontend.json @@ -1,4 +1,369 @@ [ + { + "BriefDescription": "Counts the total number of BACLEARS due to all branch types including conditional and unconditional jumps, returns, and indirect branches.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe6", + "EventName": "BACLEARS.ANY", + "PublicDescription": "Counts the total number of BACLEARS, which occur when the Branch Target Buffer (BTB) prediction or lack thereof, was corrected by a later branch predictor in the frontend. Includes BACLEARS due to all branch types including conditional and unconditional jumps, returns, and indirect branches.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Clears due to Unknown Branches.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x60", + "EventName": "BACLEARS.ANY", + "PublicDescription": "Number of times the front-end is resteered when it finds a branch instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of BACLEARS due to a conditional jump.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe6", + "EventName": "BACLEARS.COND", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of BACLEARS due to an indirect branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe6", + "EventName": "BACLEARS.INDIRECT", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of BACLEARS due to a return branch.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe6", + "EventName": "BACLEARS.RETURN", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of BACLEARS due to a direct, unconditional jump.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe6", + "EventName": "BACLEARS.UNCOND", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Stalls caused by changing prefix length of the instruction.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x87", + "EventName": "DECODE.LCP", + "PublicDescription": "Counts cycles that the Instruction Length decoder (ILD) stalls occurred due to dynamically changing prefix length of the decoded instruction (by operand size prefix instruction 0x66, address size prefix instruction 0x67 or REX.W for Intel64). Count is proportional to the number of prefixes in a 16B-line. This may result in a three-cycle penalty for each LCP (Length changing prefix) in a 16-byte chunk.", + "SampleAfterValue": "500009", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles the Microcode Sequencer is busy.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x87", + "EventName": "DECODE.MS_BUSY", + "SampleAfterValue": "500009", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "DSB-to-MITE switch true penalty cycles.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x61", + "EventName": "DSB2MITE_SWITCHES.PENALTY_CYCLES", + "PublicDescription": "Decode Stream Buffer (DSB) is a Uop-cache that holds translations of previously fetched instructions that were decoded by the legacy x86 decode pipeline (MITE). This event counts fetch penalty cycles when a transition occurs from DSB to MITE.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired ANT branches", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.ANY_ANT", + "MSRIndex": "0x3F7", + "MSRValue": "0x9", + "PublicDescription": "Always Not Taken (ANT) conditional retired branches (no BTB entry and not mispredicted) Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced DSB miss.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.ANY_DSB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x1", + "PublicDescription": "Counts retired Instructions that experienced DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced a critical DSB miss.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.DSB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x11", + "PublicDescription": "Number of retired Instructions that experienced a critical DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Critical means stalls were exposed to the back-end as a result of the DSB miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to ITLB miss", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.ITLB_MISS", + "PublicDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to ITLB miss Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Retired Instructions who experienced iTLB true miss.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.ITLB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x14", + "PublicDescription": "Counts retired Instructions that experienced iTLB (Instruction TLB) true miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced Instruction L1 Cache true miss.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.L1I_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x12", + "PublicDescription": "Counts retired Instructions who experienced Instruction L1 Cache true miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced Instruction L2 Cache true miss.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.L2_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x13", + "PublicDescription": "Counts retired Instructions who experienced Instruction L2 Cache true miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_128", + "MSRIndex": "0x3F7", + "MSRValue": "0x608006", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 128 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 16 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_16", + "MSRIndex": "0x3F7", + "MSRValue": "0x601006", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 16 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions after front-end starvation of at least 2 cycles", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_2", + "MSRIndex": "0x3F7", + "MSRValue": "0x600206", + "PublicDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of at least 2 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_256", + "MSRIndex": "0x3F7", + "MSRValue": "0x610006", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 256 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end had at least 1 bubble-slot for a period of 2 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_2_BUBBLES_GE_1", + "MSRIndex": "0x3F7", + "MSRValue": "0x100206", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after the front-end had at least 1 bubble-slot for a period of 2 cycles. A bubble-slot is an empty issue-pipeline slot while there was no RAT stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 32 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_32", + "MSRIndex": "0x3F7", + "MSRValue": "0x602006", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 32 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_4", + "MSRIndex": "0x3F7", + "MSRValue": "0x600406", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 4 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_512", + "MSRIndex": "0x3F7", + "MSRValue": "0x620006", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 512 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_64", + "MSRIndex": "0x3F7", + "MSRValue": "0x604006", + "PublicDescription": "Counts retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 64 cycles which was not interrupted by a back-end stall. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that are fetched after an interval where the front-end delivered no uops for a period of 8 cycles which was not interrupted by a back-end stall.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.LATENCY_GE_8", + "MSRIndex": "0x3F7", + "MSRValue": "0x600806", + "PublicDescription": "Counts retired instructions that are delivered to the back-end after a front-end stall of at least 8 cycles. During this period the front-end delivered no uops. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted Retired ANT branches", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.MISP_ANT", + "MSRIndex": "0x3F7", + "MSRValue": "0x9", + "PublicDescription": "ANT retired branches that got just mispredicted Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts flows delivered by the Microcode Sequencer", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.MS_FLOWS", + "MSRIndex": "0x3F7", + "MSRValue": "0x8", + "PublicDescription": "Counts flows delivered by the Microcode Sequencer Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced STLB (2nd level TLB) true miss.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.STLB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x15", + "PublicDescription": "Counts retired Instructions that experienced STLB (2nd level TLB) true miss. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired instructions that caused clears due to being Unknown Branches.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.UNKNOWN_BRANCH", + "MSRIndex": "0x3F7", + "MSRValue": "0x17", + "PublicDescription": "Number retired branch instructions that caused the front-end to be resteered when it finds the instruction in a fetch line. This is called Unknown Branch which occurs for the first time a branch instruction is fetched or when the branch is not tracked by the BPU (Branch Prediction Unit) anymore. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to Instruction L1 cache miss, that hit in the L2 cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc9", + "EventName": "FRONTEND_RETIRED_SOURCE.ICACHE_L2_HIT", + "PublicDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to Instruction L1 cache miss, that hit in the L2 cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to ITLB miss that hit in the second level TLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc9", + "EventName": "FRONTEND_RETIRED_SOURCE.ITLB_STLB_HIT", + "PublicDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to ITLB miss that hit in the second level TLB. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to ITLB miss that also missed the second level TLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc9", + "EventName": "FRONTEND_RETIRED_SOURCE.ITLB_STLB_MISS", + "PublicDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to ITLB miss that also missed the second level TLB. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts every time the code stream enters into a new cache line by walking sequential from the previous line or being redirected by a jump.", "Counter": "0,1,2,3,4,5,6,7", @@ -8,6 +373,15 @@ "UMask": "0x3", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts every time the code stream enters into a new cache line by walking sequential from the previous line or being redirected by a jump and the instruction cache registers bytes are present.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x80", + "EventName": "ICACHE.HIT", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts every time the code stream enters into a new cache line by walking sequential from the previous line or being redirected by a jump and the instruction cache registers bytes are not present. -", "Counter": "0,1,2,3,4,5,6,7", @@ -17,6 +391,134 @@ "UMask": "0x2", "Unit": "cpu_atom" }, + { + "BriefDescription": "Cycles where a code fetch is stalled due to L1 instruction cache miss.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x80", + "EventName": "ICACHE_DATA.STALLS", + "PublicDescription": "Counts cycles where a code line fetch is stalled due to an L1 instruction cache miss. The decode pipeline works at a 32 Byte granularity.", + "SampleAfterValue": "500009", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "ICACHE_DATA.STALL_PERIODS", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0x80", + "EventName": "ICACHE_DATA.STALL_PERIODS", + "SampleAfterValue": "500009", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where a code fetch is stalled due to L1 instruction cache tag miss.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x83", + "EventName": "ICACHE_TAG.STALLS", + "PublicDescription": "Counts cycles where a code fetch is stalled due to L1 instruction cache tag miss.", + "SampleAfterValue": "200003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering any Uop", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0x79", + "EventName": "IDQ.DSB_CYCLES_ANY", + "PublicDescription": "Counts the number of cycles uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles DSB is delivering optimal number of Uops", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "8", + "EventCode": "0x79", + "EventName": "IDQ.DSB_CYCLES_OK", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x79", + "EventName": "IDQ.DSB_UOPS", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles MITE is delivering any Uop", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0x79", + "EventName": "IDQ.MITE_CYCLES_ANY", + "PublicDescription": "Counts the number of cycles uops were delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles MITE is delivering optimal number of Uops", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "8", + "EventCode": "0x79", + "EventName": "IDQ.MITE_CYCLES_OK", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops delivered to Instruction Decode Queue (IDQ) from MITE path", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x79", + "EventName": "IDQ.MITE_UOPS", + "PublicDescription": "Counts the number of uops delivered to Instruction Decode Queue (IDQ) from the MITE path. This also means that uops are not being delivered from the Decode Stream Buffer (DSB).", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when uops are being delivered to IDQ while MS is busy", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0x79", + "EventName": "IDQ.MS_CYCLES_ANY", + "PublicDescription": "Counts cycles during which uops are being delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Uops maybe initiated by Decode Stream Buffer (DSB) or MITE.", + "SampleAfterValue": "2000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of switches from DSB or MITE to the MS", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0x79", + "EventName": "IDQ.MS_SWITCHES", + "PublicDescription": "Number of switches from DSB (Decode Stream Buffer) or MITE (legacy decode pipeline) to the Microcode Sequencer.", + "SampleAfterValue": "100003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops initiated by MITE or Decode Stream Buffer (DSB) and delivered to Instruction Decode Queue (IDQ) while Microcode Sequencer (MS) is busy", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x79", + "EventName": "IDQ.MS_UOPS", + "PublicDescription": "Counts the number of uops initiated by MITE or Decode Stream Buffer (DSB) and delivered to Instruction Decode Queue (IDQ) while the Microcode Sequencer (MS) is busy. Counting includes uops that may 'bypass' the IDQ.", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, { "BriefDescription": "This event counts a subset of the Topdown Slots event that when no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations.", "Counter": "0,1,2,3,4,5,6,7,8,9", @@ -26,5 +528,38 @@ "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when optimal number of uops was delivered to the back-end when the back-end is not stalled", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0x9c", + "EventName": "IDQ_BUBBLES.CYCLES_FE_WAS_OK", + "Invert": "1", + "PublicDescription": "Counts the number of cycles when the optimal number of uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when no uops are delivered by the IDQ for 2 or more cycles when backend of the machine is not stalled - normally indicating a Fetch Latency issue", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x9c", + "EventName": "IDQ_BUBBLES.FETCH_LATENCY", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls for 2 or more cycles - normally indicating a Fetch Latency issue.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when no uops are not delivered by the IDQ when backend of the machine is not stalled", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "8", + "EventCode": "0x9c", + "EventName": "IDQ_BUBBLES.STARVATION_CYCLES", + "PublicDescription": "Counts the number of cycles when no uops were delivered by the Instruction Decode Queue (IDQ) to the back-end of the pipeline when there was no back-end stalls.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" } ] diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/memory.json b/tools/perf/pmu-events/arch/x86/pantherlake/memory.json index 47daee8cc00f..397a15dbb964 100644 --- a/tools/perf/pmu-events/arch/x86/pantherlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/pantherlake/memory.json @@ -1,4 +1,32 @@ [ + { + "BriefDescription": "Counts the number of cycles that the head (oldest load) of the load buffer is stalled due to a core bound stall including a store address match, a DTLB miss or a page walk that detains the load from retiring.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x05", + "EventName": "LD_HEAD.L1_BOUND_AT_RET", + "SampleAfterValue": "1000003", + "UMask": "0xf4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of machine clears due to memory ordering caused by a snoop from an external agent. Does not count internally generated machine clears such as those due to memory disambiguation.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of machine clears due to memory ordering conflicts.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", + "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles.", "Counter": "2,3,4,5,6,7,8,9", @@ -7,7 +35,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_1024", "MSRIndex": "0x3F6", "MSRValue": "0x400", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", "SampleAfterValue": "53", "UMask": "0x1", "Unit": "cpu_core" @@ -20,7 +48,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_128", "MSRIndex": "0x3F6", "MSRValue": "0x80", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", "SampleAfterValue": "1009", "UMask": "0x1", "Unit": "cpu_core" @@ -33,7 +61,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_16", "MSRIndex": "0x3F6", "MSRValue": "0x10", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 16 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", "SampleAfterValue": "20011", "UMask": "0x1", "Unit": "cpu_core" @@ -46,7 +74,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_2048", "MSRIndex": "0x3F6", "MSRValue": "0x800", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", "SampleAfterValue": "23", "UMask": "0x1", "Unit": "cpu_core" @@ -59,7 +87,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_256", "MSRIndex": "0x3F6", "MSRValue": "0x100", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", "SampleAfterValue": "503", "UMask": "0x1", "Unit": "cpu_core" @@ -72,7 +100,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_32", "MSRIndex": "0x3F6", "MSRValue": "0x20", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 32 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", "SampleAfterValue": "100007", "UMask": "0x1", "Unit": "cpu_core" @@ -85,7 +113,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_4", "MSRIndex": "0x3F6", "MSRValue": "0x4", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 4 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -98,7 +126,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_512", "MSRIndex": "0x3F6", "MSRValue": "0x200", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 512 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", "SampleAfterValue": "101", "UMask": "0x1", "Unit": "cpu_core" @@ -111,7 +139,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_64", "MSRIndex": "0x3F6", "MSRValue": "0x40", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 64 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", "SampleAfterValue": "2003", "UMask": "0x1", "Unit": "cpu_core" @@ -124,7 +152,7 @@ "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_8", "MSRIndex": "0x3F6", "MSRValue": "0x8", - "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 8 cycles. Reported latency may be longer than just the memory latency. Available PDIST counters: 0,1", "SampleAfterValue": "50021", "UMask": "0x1", "Unit": "cpu_core" @@ -135,11 +163,31 @@ "Data_LA": "1", "EventCode": "0xcd", "EventName": "MEM_TRANS_RETIRED.STORE_SAMPLE", - "PublicDescription": "Counts Retired memory accesses with at least 1 store operation. This PEBS event is the precisely-distributed (PDist) trigger covering all stores uops for sampling by the PEBS Store Latency Facility. The facility is described in Intel SDM Volume 3 section 19.9.8 Available PDIST counters: 0", + "PublicDescription": "Counts Retired memory accesses with at least 1 store operation. This PEBS event is the precisely-distributed (PDist) trigger covering all stores uops for sampling by the PEBS Store Latency Facility. The facility is described in Intel SDM Volume 3 section 19.9.8 Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts misaligned loads that are 4K page splits.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x13", + "EventName": "MISALIGN_MEM_REF.LOAD_PAGE_SPLIT", + "PublicDescription": "Counts misaligned loads that are 4K page splits. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts misaligned stores that are 4K page splits.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x13", + "EventName": "MISALIGN_MEM_REF.STORE_PAGE_SPLIT", + "PublicDescription": "Counts misaligned stores that are 4K page splits. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts demand data reads that were supplied by DRAM.", "Counter": "0,1,2,3,4,5,6,7", @@ -154,7 +202,7 @@ }, { "BriefDescription": "Counts demand data reads that were supplied by DRAM.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.DRAM", "MSRIndex": "0x1a6,0x1a7", @@ -178,7 +226,7 @@ }, { "BriefDescription": "Counts demand data reads that were not supplied by the L3 cache.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.L3_MISS", "MSRIndex": "0x1a6,0x1a7", @@ -202,7 +250,7 @@ }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were not supplied by the L3 cache.", - "Counter": "0,1,2,3", + "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_RFO.L3_MISS", "MSRIndex": "0x1a6,0x1a7", @@ -211,5 +259,35 @@ "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts demand data read requests that miss the L3 cache.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x21", + "EventName": "OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where data return is pending for a Demand Data Read request who miss L3 cache.", + "Counter": "0,1,2,3", + "CounterMask": "1", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_L3_MISS_DEMAND_DATA_RD", + "PublicDescription": "Cycles with at least 1 Demand Data Read requests who miss L3 cache in the superQ.", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache.", + "Counter": "0,1,2,3", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD", + "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache.", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" } ] diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/other.json b/tools/perf/pmu-events/arch/x86/pantherlake/other.json new file mode 100644 index 000000000000..d49651d4f112 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/pantherlake/other.json @@ -0,0 +1,44 @@ +[ + { + "BriefDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc1", + "EventName": "ASSISTS.HARDWARE", + "PublicDescription": "Count all other hardware assists or traps that are not necessarily architecturally exposed (through a software handler) beyond FP; SSE-AVX mix and A/D assists who are counted by dedicated sub-events. This includes, but not limited to, assists at EXE or MEM uop writeback like AVX* load/store/gather/scatter (non-FP GSSE-assist ) , assists generated by ROB like PEBS and RTIT, Uncore trap, RAR (Remote Action Request) and CET (Control flow Enforcement Technology) assists.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "ASSISTS.PAGE_FAULT", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc1", + "EventName": "ASSISTS.PAGE_FAULT", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts streaming stores that have any type of response.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.STREAMING_WR.ANY_RESPONSE", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x10800", + "PublicDescription": "Counts streaming stores that have any type of response. Available PDIST counters: 0", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles the uncore cannot take further requests", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0x2d", + "EventName": "XQ.FULL", + "PublicDescription": "number of cycles when the thread is active and the uncore cannot take any further requests (for example prefetches, loads or stores initiated by the Core that miss the L2 cache).", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + } +] diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json b/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json index 2caf2f85327f..2d805ac98c5b 100644 --- a/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/pantherlake/pipeline.json @@ -1,10 +1,51 @@ [ + { + "BriefDescription": "Cycles when divide unit is busy executing divide or square root operations.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0xb0", + "EventName": "ARITH.DIV_ACTIVE", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer and floating-point operations.", + "SampleAfterValue": "1000003", + "UMask": "0x9", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when integer divide unit is busy executing divide or square root operations.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0xb0", + "EventName": "ARITH.IDIV_ACTIVE", + "PublicDescription": "Counts cycles when divide unit is busy executing divide or square root operations. Accounts for integer operations only.", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of occurrences where a microcode assist is invoked by hardware.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc1", + "EventName": "ASSISTS.ANY", + "PublicDescription": "Counts the number of occurrences where a microcode assist is invoked by hardware. Examples include AD (page Access Dirty), FP and AVX related assists.", + "SampleAfterValue": "100003", + "UMask": "0x1f", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts cycles where the pipeline is stalled due to serializing operations.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xa2", + "EventName": "BE_STALLS.SCOREBOARD", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the total number of branch instructions retired for all branch types.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.ALL_BRANCHES", - "PublicDescription": "Counts the total number of instructions in which the instruction pointer (IP) of the processor is resteered due to a branch instruction and the branch instruction successfully retires. All branch type instructions are accounted for.", + "PublicDescription": "Counts the total number of instructions in which the instruction pointer (IP) of the processor is resteered due to a branch instruction and the branch instruction successfully retires. All branch type instructions are accounted for. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "Unit": "cpu_atom" }, @@ -13,16 +54,250 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc4", "EventName": "BR_INST_RETIRED.ALL_BRANCHES", - "PublicDescription": "Counts all branch instructions retired. Available PDIST counters: 0", + "PublicDescription": "Counts all branch instructions retired. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "Unit": "cpu_core" }, + { + "BriefDescription": "Conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND", + "PublicDescription": "Counts conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x7", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of not taken conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_NTAKEN", + "PublicDescription": "Counts the number of not taken conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Not taken branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_NTAKEN", + "PublicDescription": "Counts not taken branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Taken conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_TAKEN", + "PublicDescription": "Counts taken conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Taken backward conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_TAKEN_BWD", + "PublicDescription": "Counts taken backward conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Taken forward conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.COND_TAKEN_FWD", + "PublicDescription": "Counts taken forward conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Far branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.FAR_BRANCH", + "PublicDescription": "Counts far branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_INST_RETIRED.NEAR_INDIRECT]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.INDIRECT", + "PublicDescription": "This event is deprecated. [This event is alias to BR_INST_RETIRED.NEAR_INDIRECT] Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x50", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of near CALL branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_CALL", + "PublicDescription": "Counts the number of near CALL branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x30", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Direct and indirect near call instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_CALL", + "PublicDescription": "Counts both direct and indirect near call instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x30", + "Unit": "cpu_core" + }, + { + "BriefDescription": "near relative call instructions retired. [This event is alias to BR_INST_RETIRED.NEAR_REL_CALL]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_DIRECT_CALL", + "PublicDescription": "Counts near relative call instructions retired. [This event is alias to BR_INST_RETIRED.NEAR_REL_CALL] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "near relative jump instructions retired. [This event is alias to BR_INST_RETIRED.NEAR_REL_JMP]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_DIRECT_JMP", + "PublicDescription": "Counts near relative jump instructions retired. [This event is alias to BR_INST_RETIRED.NEAR_REL_JMP] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Indirect near branch instructions retired (excluding returns) [This event is alias to BR_INST_RETIRED.INDIRECT]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_INDIRECT", + "PublicDescription": "Counts near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. [This event is alias to BR_INST_RETIRED.INDIRECT] Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x50", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Indirect near call instructions retired. [This event is alias to BR_INST_RETIRED.NEAR_IND_CALL]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_INDIRECT_CALL", + "PublicDescription": "Counts indirect near call instructions retired. [This event is alias to BR_INST_RETIRED.NEAR_IND_CALL] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Indirect near jump instructions retired. [This event is alias to BR_INST_RETIRED.NEAR_IND_JMP]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_INDIRECT_JMP", + "PublicDescription": "Counts indirect near jump instructions retired. [This event is alias to BR_INST_RETIRED.NEAR_IND_JMP] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_INST_RETIRED.NEAR_INDIRECT_CALL]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_IND_CALL", + "PublicDescription": "This event is deprecated. [This event is alias to BR_INST_RETIRED.NEAR_INDIRECT_CALL] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_INST_RETIRED.NEAR_INDIRECT_JMP]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_IND_JMP", + "PublicDescription": "This event is deprecated. [This event is alias to BR_INST_RETIRED.NEAR_INDIRECT_JMP] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Indirect and Direct Relative near jump instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_JMP", + "PublicDescription": "Counts near jump instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0xc0", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_INST_RETIRED.NEAR_DIRECT_CALL]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_REL_CALL", + "PublicDescription": "This event is deprecated. [This event is alias to BR_INST_RETIRED.NEAR_DIRECT_CALL] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_INST_RETIRED.NEAR_DIRECT_JMP]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_REL_JMP", + "PublicDescription": "This event is deprecated. [This event is alias to BR_INST_RETIRED.NEAR_DIRECT_JMP] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Return instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_RETURN", + "PublicDescription": "Counts return instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of near taken branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_TAKEN", + "PublicDescription": "Counts the number of near taken branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0xfb", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Taken branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc4", + "EventName": "BR_INST_RETIRED.NEAR_TAKEN", + "PublicDescription": "Counts taken branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0xfb", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the total number of mispredicted branch instructions retired for all branch types.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.ALL_BRANCHES", - "PublicDescription": "Counts the total number of mispredicted branch instructions retired. All branch type instructions are accounted for. Prediction of the branch target address enables the processor to begin executing instructions before the non-speculative execution path is known. The branch prediction unit (BPU) predicts the target address based on the instruction pointer (IP) of the branch and on the execution path through which execution reached this IP. A branch misprediction occurs when the prediction is wrong, and results in discarding all instructions executed in the speculative path and re-fetching from the correct path.", + "PublicDescription": "Counts the total number of mispredicted branch instructions retired. All branch type instructions are accounted for. Prediction of the branch target address enables the processor to begin executing instructions before the non-speculative execution path is known. The branch prediction unit (BPU) predicts the target address based on the instruction pointer (IP) of the branch and on the execution path through which execution reached this IP. A branch misprediction occurs when the prediction is wrong, and results in discarding all instructions executed in the speculative path and re-fetching from the correct path. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "Unit": "cpu_atom" }, @@ -31,15 +306,438 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc5", "EventName": "BR_MISP_RETIRED.ALL_BRANCHES", - "PublicDescription": "Counts all the retired branch instructions that were mispredicted by the processor. A branch misprediction occurs when the processor incorrectly predicts the destination of the branch. When the misprediction is discovered at execution, all the instructions executed in the wrong (speculative) path must be discarded, and the processor must start fetching from the correct path. Available PDIST counters: 0", + "PublicDescription": "Counts all the retired branch instructions that were mispredicted by the processor. A branch misprediction occurs when the processor incorrectly predicts the destination of the branch. When the misprediction is discovered at execution, all the instructions executed in the wrong (speculative) path must be discarded, and the processor must start fetching from the correct path. Available PDIST counters: 0,1", "SampleAfterValue": "400009", "Unit": "cpu_core" }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.ALL_BRANCHES_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.ALL_BRANCHES_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.ALL_BRANCHES_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "Unit": "cpu_core" + }, + { + "BriefDescription": "All mispredicted branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.ALL_BRANCHES_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.ALL_BRANCHES_TPEBS", + "PublicDescription": "All mispredicted branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.ALL_BRANCHES_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND", + "PublicDescription": "Counts mispredicted conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x7", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.COND_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.COND_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8007", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of mispredicted not taken conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_NTAKEN", + "PublicDescription": "Counts the number of mispredicted not taken conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Mispredicted non-taken conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_NTAKEN", + "PublicDescription": "Counts the number of conditional branch instructions retired that were mispredicted and the branch direction was not taken. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.COND_NTAKEN_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_NTAKEN_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.COND_NTAKEN_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8004", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted non-taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.COND_NTAKEN_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_NTAKEN_TPEBS", + "PublicDescription": "Mispredicted non-taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.COND_NTAKEN_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8004", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of mispredicted taken conditional branch instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN", + "PublicDescription": "Counts the number of mispredicted taken conditional branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x3", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "number of branch instructions retired that were mispredicted and taken.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN", + "PublicDescription": "Counts taken conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "number of branch instructions retired that were mispredicted and taken backward.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_BWD", + "PublicDescription": "Counts taken backward conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_BWD_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_BWD_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_BWD_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8001", + "Unit": "cpu_core" + }, + { + "BriefDescription": "number of branch instructions retired that were mispredicted and taken backward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_BWD_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_BWD_TPEBS", + "PublicDescription": "number of branch instructions retired that were mispredicted and taken backward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_BWD_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8001", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8003", + "Unit": "cpu_core" + }, + { + "BriefDescription": "number of branch instructions retired that were mispredicted and taken forward.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD", + "PublicDescription": "Counts taken forward conditional mispredicted branch instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_FWD_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_FWD_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8002", + "Unit": "cpu_core" + }, + { + "BriefDescription": "number of branch instructions retired that were mispredicted and taken forward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_FWD_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_FWD_TPEBS", + "PublicDescription": "number of branch instructions retired that were mispredicted and taken forward. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_FWD_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8002", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TAKEN_TPEBS", + "PublicDescription": "Mispredicted taken conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.COND_TAKEN_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8003", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.COND_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.COND_TPEBS", + "PublicDescription": "Mispredicted conditional branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.COND_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8007", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.INDIRECT", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT] Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x50", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT_CALL]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.INDIRECT_CALL", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT_CALL] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT_CALL_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.INDIRECT_CALL_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT_CALL_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8010", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.INDIRECT_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x8050", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT_JMP]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.INDIRECT_JMP", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT_JMP] Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT_JMP_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.INDIRECT_JMP_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_INDIRECT_JMP_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x8040", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Miss-predicted near indirect branch instructions retired (excluding returns) [This event is alias to BR_MISP_RETIRED.INDIRECT]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT", + "PublicDescription": "Counts miss-predicted near indirect branch instructions retired excluding returns. TSX abort is an indirect branch. [This event is alias to BR_MISP_RETIRED.INDIRECT] Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x50", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted indirect CALL retired. [This event is alias to BR_MISP_RETIRED.INDIRECT_CALL]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT_CALL", + "PublicDescription": "Counts retired mispredicted indirect (near taken) CALL instructions, including both register and memory indirect. [This event is alias to BR_MISP_RETIRED.INDIRECT_CALL] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted indirect CALL retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.INDIRECT_CALL_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT_CALL_TPEBS", + "PublicDescription": "Mispredicted indirect CALL retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.INDIRECT_CALL_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x8010", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Miss-predicted near indirect jump instructions retired. [This event is alias to BR_MISP_RETIRED.INDIRECT_JMP]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT_JMP", + "PublicDescription": "Miss-predicted near indirect jump instructions retired. [This event is alias to BR_MISP_RETIRED.INDIRECT_JMP] Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Miss-predicted near indirect jump instructions retired. Precise cost. [This event is alias to BR_MISP_RETIRED.INDIRECT_JMP_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT_JMP_TPEBS", + "PublicDescription": "Miss-predicted near indirect jump instructions retired. Precise cost. [This event is alias to BR_MISP_RETIRED.INDIRECT_JMP_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x8040", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted near indirect branch instructions retired (excluding returns). This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.INDIRECT_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_INDIRECT_TPEBS", + "PublicDescription": "Mispredicted near indirect branch instructions retired (excluding returns). This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.INDIRECT_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "100003", + "UMask": "0x8050", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event counts the number of mispredicted ret instructions retired. Non PEBS [This event is alias to BR_MISP_RETIRED.RET]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_RETURN", + "PublicDescription": "This is a non-precise version (that is, does not use PEBS) of the event that counts mispredicted return instructions retired. [This event is alias to BR_MISP_RETIRED.RET] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted ret instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.RET_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_RETURN_TPEBS", + "PublicDescription": "Mispredicted ret instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.RET_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x8008", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of near branch instructions retired that were mispredicted and taken.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_TAKEN", + "PublicDescription": "Counts number of near branch instructions retired that were mispredicted and taken. Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0xfb", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_TAKEN_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_TAKEN_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_TAKEN_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x80fb", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Mispredicted taken near branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.NEAR_TAKEN_COST]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.NEAR_TAKEN_TPEBS", + "PublicDescription": "Mispredicted taken near branch instructions retired. This precise event may be used to get the misprediction cost via the Retire_Latency field of PEBS. It fires on the instruction that immediately follows the mispredicted branch. [This event is alias to BR_MISP_RETIRED.NEAR_TAKEN_COST] Available PDIST counters: 0,1", + "SampleAfterValue": "400009", + "UMask": "0x80fb", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_RETURN]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.RET", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_RETURN] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_RETURN_TPEBS]", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "Deprecated": "1", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.RET_COST", + "PublicDescription": "This event is deprecated. [This event is alias to BR_MISP_RETIRED.NEAR_RETURN_TPEBS] Available PDIST counters: 0,1", + "SampleAfterValue": "100007", + "UMask": "0x8008", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.C01", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.C02", + "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", + "SampleAfterValue": "2000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core clocks when the thread is in the C0.1 or C0.2 or running a PAUSE in C0 ACPI state.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.C0_WAIT", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction.", + "SampleAfterValue": "2000003", + "UMask": "0x70", + "Unit": "cpu_core" + }, { "BriefDescription": "Fixed Counter: Counts the number of unhalted core clock cycles.", "Counter": "Fixed counter 1", "EventName": "CPU_CLK_UNHALTED.CORE", - "SampleAfterValue": "1000003", + "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_atom" }, @@ -57,7 +755,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.CORE_P", - "SampleAfterValue": "1000003", + "SampleAfterValue": "2000003", "Unit": "cpu_atom" }, { @@ -69,11 +767,31 @@ "SampleAfterValue": "2000003", "Unit": "cpu_core" }, + { + "BriefDescription": "Core clocks when a PAUSE is pending.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.PAUSE", + "SampleAfterValue": "2000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of Pause instructions", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.PAUSE_INST", + "SampleAfterValue": "2000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, { "BriefDescription": "Fixed Counter: Counts the number of unhalted reference clock cycles.", "Counter": "Fixed counter 2", "EventName": "CPU_CLK_UNHALTED.REF_TSC", - "SampleAfterValue": "1000003", + "SampleAfterValue": "2000003", "UMask": "0x3", "Unit": "cpu_atom" }, @@ -92,7 +810,7 @@ "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.REF_TSC_P", "PublicDescription": "Counts the number of reference cycles that the core is not in a halt state. The core enters the halt state when it is running the HLT instruction. This event is not affected by core frequency changes and increments at a fixed frequency that is also used for the Time Stamp Counter (TSC). This event uses a programmable general purpose performance counter.", - "SampleAfterValue": "1000003", + "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_atom" }, @@ -110,7 +828,7 @@ "BriefDescription": "Fixed Counter: Counts the number of unhalted core clock cycles.", "Counter": "Fixed counter 1", "EventName": "CPU_CLK_UNHALTED.THREAD", - "SampleAfterValue": "1000003", + "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_atom" }, @@ -128,7 +846,7 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.THREAD_P", - "SampleAfterValue": "1000003", + "SampleAfterValue": "2000003", "Unit": "cpu_atom" }, { @@ -140,12 +858,131 @@ "SampleAfterValue": "2000003", "Unit": "cpu_core" }, + { + "BriefDescription": "Cycles while memory subsystem has an outstanding load.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "16", + "EventCode": "0xa3", + "EventName": "CYCLE_ACTIVITY.CYCLES_MEM_ANY", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Total execution stalls.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "4", + "EventCode": "0xa3", + "EventName": "CYCLE_ACTIVITY.STALLS_TOTAL", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Count number of times a load is depending on another load that had just write back its data or in previous or 2 cycles back. This event supports in-direct dependency through a single uop.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x02", + "EventName": "DEPENDENT_LOADS.ANY", + "SampleAfterValue": "1000003", + "UMask": "0x7", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles total of 1 uop is executed on all ports and Reservation Station was not empty.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.1_PORTS_UTIL", + "PublicDescription": "Counts cycles during which a total of 1 uop was executed on all ports and Reservation Station (RS) was not empty.", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles total of 2 or 3 uops are executed on all ports and Reservation Station (RS) was not empty.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.2_3_PORTS_UTIL", + "SampleAfterValue": "2000003", + "UMask": "0xc", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles total of 2 uops are executed on all ports and Reservation Station was not empty.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.2_PORTS_UTIL", + "PublicDescription": "Counts cycles during which a total of 2 uops were executed on all ports and Reservation Station (RS) was not empty.", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station was not empty.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.3_PORTS_UTIL", + "PublicDescription": "Cycles total of 3 uops are executed on all ports and Reservation Station (RS) was not empty.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station was not empty.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.4_PORTS_UTIL", + "PublicDescription": "Cycles total of 4 uops are executed on all ports and Reservation Station (RS) was not empty.", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Execution stalls while memory subsystem has an outstanding load.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "5", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.BOUND_ON_LOADS", + "SampleAfterValue": "2000003", + "UMask": "0x21", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where the Store Buffer was full and no loads caused an execution stall.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "2", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.BOUND_ON_STORES", + "PublicDescription": "Counts cycles where the Store Buffer was full and no loads caused an execution stall.", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles no uop executed while RS was not empty, the SB was not full and there was no outstanding load.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xa6", + "EventName": "EXE_ACTIVITY.EXE_BOUND_0_PORTS", + "PublicDescription": "Number of cycles total of 0 uops executed on all ports, Reservation Station (RS) was not empty, the Store Buffer (SB) was not full and there was no outstanding load.", + "SampleAfterValue": "1000003", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Instruction decoders utilized in a cycle", + "Counter": "2", + "EventCode": "0x75", + "EventName": "INST_DECODED.DECODERS", + "PublicDescription": "Number of decoders utilized in a cycle when the MITE (legacy decode pipeline) fetches instructions.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Fixed Counter: Counts the number of instructions retired.", "Counter": "Fixed counter 0", "EventName": "INST_RETIRED.ANY", "PublicDescription": "Fixed Counter: Counts the number of instructions retired. Available PDIST counters: 32", - "SampleAfterValue": "1000003", + "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_atom" }, @@ -163,7 +1000,8 @@ "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xc0", "EventName": "INST_RETIRED.ANY_P", - "SampleAfterValue": "1000003", + "PublicDescription": "Counts the number of instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "2000003", "Unit": "cpu_atom" }, { @@ -171,15 +1009,281 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xc0", "EventName": "INST_RETIRED.ANY_P", - "PublicDescription": "Counts the number of X86 instructions retired - an Architectural PerfMon event. Counting continues during hardware interrupts, traps, and inside interrupt handlers. Notes: INST_RETIRED.ANY is counted by a designated fixed counter freeing up programmable counters to count other events. INST_RETIRED.ANY_P is counted by a programmable counter. Available PDIST counters: 0", + "PublicDescription": "Counts the number of X86 instructions retired - an Architectural PerfMon event. Counting continues during hardware interrupts, traps, and inside interrupt handlers. Notes: INST_RETIRED.ANY is counted by a designated fixed counter freeing up programmable counters to count other events. INST_RETIRED.ANY_P is counted by a programmable counter. Available PDIST counters: 0,1", "SampleAfterValue": "2000003", "Unit": "cpu_core" }, + { + "BriefDescription": "retired macro-fused uops when there is a branch in the macro-fused pair (the two instructions that got macro-fused count once in this pmon)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.BR_FUSED", + "PublicDescription": "retired macro-fused uops when there is a branch in the macro-fused pair (the two instructions that got macro-fused count once in this pmon) Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INST_RETIRED.MACRO_FUSED", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.MACRO_FUSED", + "PublicDescription": "INST_RETIRED.MACRO_FUSED Available PDIST counters: 0,1", + "SampleAfterValue": "2000003", + "UMask": "0x30", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired NOP instructions.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.NOP", + "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions Available PDIST counters: 0,1", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Precise instruction retired with PEBS precise-distribution", + "Counter": "Fixed counter 0", + "EventName": "INST_RETIRED.PREC_DIST", + "PublicDescription": "A version of INST_RETIRED that allows for a precise distribution of samples across instructions retired. It utilizes the Precise Distribution of Instructions Retired (PDIR++) feature to fix bias in how retired instructions get sampled. Use on Fixed Counter 0. Available PDIST counters: 32", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Iterations of Repeat string retired instructions.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.REP_ITERATION", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent. Available PDIST counters: 0,1", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Bubble cycles of BPClear.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xad", + "EventName": "INT_MISC.BPCLEAR_CYCLES", + "MSRIndex": "0x3F7", + "MSRValue": "0xB", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Clears speculative count", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xad", + "EventName": "INT_MISC.CLEARS_COUNT", + "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears", + "SampleAfterValue": "500009", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xad", + "EventName": "INT_MISC.CLEAR_RESTEER_CYCLES", + "PublicDescription": "Cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", + "SampleAfterValue": "500009", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core cycles the allocator was stalled due to recovery from earlier clear event for this thread", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xad", + "EventName": "INT_MISC.RECOVERY_CYCLES", + "PublicDescription": "Counts core cycles when the Resource allocator was stalled due to recovery from an earlier branch misprediction or machine clear event.", + "SampleAfterValue": "500009", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Bubble cycles of BAClear (Unknown Branch).", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xad", + "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES", + "MSRIndex": "0x3F7", + "MSRValue": "0x7", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "TMA slots where uops got dropped", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xad", + "EventName": "INT_MISC.UOP_DROPPING", + "PublicDescription": "Estimated number of Top-down Microarchitecture Analysis slots that got dropped due to non front-end reasons", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of uops executed on integer port 0,1, 2, 3.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xb3", + "EventName": "INT_UOPS_EXECUTED.PRIMARY", + "SampleAfterValue": "1000003", + "UMask": "0x78", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of vector integer instructions retired of 128-bit vector-width.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.128BIT", + "SampleAfterValue": "1000003", + "UMask": "0x13", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of vector integer instructions retired of 256-bit vector-width.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.256BIT", + "SampleAfterValue": "1000003", + "UMask": "0xac", + "Unit": "cpu_core" + }, + { + "BriefDescription": "integer ADD, SUB, SAD 128-bit vector instructions.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.ADD_128", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 128-bit vector instructions.", + "SampleAfterValue": "1000003", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "integer ADD, SUB, SAD 256-bit vector instructions.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.ADD_256", + "PublicDescription": "Number of retired integer ADD/SUB (regular or horizontal), SAD 256-bit vector instructions.", + "SampleAfterValue": "1000003", + "UMask": "0xc", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INT_VEC_RETIRED.MUL_256", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.MUL_256", + "SampleAfterValue": "1000003", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INT_VEC_RETIRED.SHUFFLES", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.SHUFFLES", + "SampleAfterValue": "1000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INT_VEC_RETIRED.VNNI_128", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.VNNI_128", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "INT_VEC_RETIRED.VNNI_256", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xe7", + "EventName": "INT_VEC_RETIRED.VNNI_256", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of retired loads that are blocked because it initially appears to be store forward blocked, but subsequently is shown not to be blocked based on 4K alias check.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.ADDRESS_ALIAS", + "PublicDescription": "Counts the number of retired loads that are blocked because it initially appears to be store forward blocked, but subsequently is shown not to be blocked based on 4K alias check. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "False dependencies in MOB due to partial compare on address.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.ADDRESS_ALIAS", + "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of retired loads that are blocked for any of the following reasons: DTLB miss, address alias, store forward or data unknown (includes memory disambiguation blocks and ESP consuming load blocks).", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.ALL", + "PublicDescription": "Counts the number of retired loads that are blocked for any of the following reasons: DTLB miss, address alias, store forward or data unknown (includes memory disambiguation blocks and ESP consuming load blocks). Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Bank conflicts in DCU due to limited lookup ports.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.BANK_CONFLICT", + "PublicDescription": "Counts the number of times a load got blocked due to bank conflicts in DCU", + "SampleAfterValue": "100003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of retired loads that are blocked because its address exactly matches an older store whose data is not ready.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.DATA_UNKNOWN", + "PublicDescription": "Counts the number of retired loads that are blocked because its address exactly matches an older store whose data is not ready. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "The number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.NO_SR", + "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", + "SampleAfterValue": "100003", + "UMask": "0x88", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of times a load got early blocked due to preceding store operation with unknown address or unknown data. Excluding in-line (immediate) wakeups", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.STORE_EARLY", + "SampleAfterValue": "100003", + "UMask": "0xa1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of retired loads that are blocked because its address partially overlapped with an older store.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0x03", "EventName": "LD_BLOCKS.STORE_FORWARD", + "PublicDescription": "Counts the number of retired loads that are blocked because its address partially overlapped with an older store. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_atom" @@ -194,11 +1298,130 @@ "UMask": "0x82", "Unit": "cpu_core" }, + { + "BriefDescription": "Cycles Uops delivered by the LSD, but didn't come from the decoder.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0xa8", + "EventName": "LSD.CYCLES_ACTIVE", + "PublicDescription": "Counts the cycles when at least one uop is delivered by the LSD (Loop-stream detector).", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles optimal number of Uops delivered by the LSD, but did not come from the decoder.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "8", + "EventCode": "0xa8", + "EventName": "LSD.CYCLES_OK", + "PublicDescription": "Counts the cycles when optimal number of uops is delivered by the LSD (Loop-stream detector).", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of Uops delivered by the LSD.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xa8", + "EventName": "LSD.UOPS", + "PublicDescription": "Counts the number of uops delivered to the back-end by the LSD(Loop Stream Detector).", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of machine clears (nukes) of any type.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.COUNT", + "PublicDescription": "Counts the number of machine clears (nukes) of any type.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of machine clears due to memory ordering in which an internal load passes an older store within the same CPU.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.DISAMBIGUATION", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of machine clears due to a page fault. Counts both I-Side and D-Side (Loads/Stores) page faults. A page fault occurs when either the page is not present, or an access violation occurs.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.PAGE_FAULT", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Self-modifying code (SMC) detected.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.SMC", + "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts cycles where no execution is happening due to loads waiting for L1 cache (that is: no execution & load in flight & no load missed L1 cache)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x46", + "EventName": "MEMORY_STALLS.L1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts cycles where no execution is happening due to loads waiting for L2 cache (that is: no execution & load in flight & load missed L1 & no load missed L2 cache)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x46", + "EventName": "MEMORY_STALLS.L2", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts cycles where no execution is happening due to loads waiting for L3 cache (that is: no execution & load in flight & load missed L1 & load missed L2 cache & no load missed L3 Cache)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x46", + "EventName": "MEMORY_STALLS.L3", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts cycles where no execution is happening due to loads waiting for Memory (that is: no execution & load in flight & a load missed L3 cache)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x46", + "EventName": "MEMORY_STALLS.MEM", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "LFENCE instructions retired", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xe0", + "EventName": "MISC2_RETIRED.LFENCE", + "PublicDescription": "number of LFENCE retired instructions", + "SampleAfterValue": "400009", + "UMask": "0x20", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of LBR entries recorded. Requires LBRs to be enabled in IA32_LBR_CTL.", "Counter": "0,1,2,3,4,5,6,7", "EventCode": "0xe4", "EventName": "MISC_RETIRED.LBR_INSERTS", + "PublicDescription": "Counts the number of LBR entries recorded. Requires LBRs to be enabled in IA32_LBR_CTL. Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_atom" @@ -208,11 +1431,82 @@ "Counter": "0,1,2,3,4,5,6,7,8,9", "EventCode": "0xe4", "EventName": "MISC_RETIRED.LBR_INSERTS", - "PublicDescription": "LBR record is inserted Available PDIST counters: 0", + "PublicDescription": "LBR record is inserted Available PDIST counters: 0,1", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts the number of LFENCE instructions retired.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe0", + "EventName": "MISC_RETIRED1.LFENCE", + "PublicDescription": "Counts the number of LFENCE instructions retired. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of accesses to KeyLocker cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe1", + "EventName": "MISC_RETIRED2.KEYLOCKER_ACCESS", + "PublicDescription": "Counts the number of accesses to KeyLocker cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of misses to KeyLocker cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xe1", + "EventName": "MISC_RETIRED2.KEYLOCKER_MISS", + "PublicDescription": "Counts the number of misses to KeyLocker cache. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x11", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Cycles when Reservation Station (RS) is empty for the thread.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xa5", + "EventName": "RS.EMPTY", + "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses)", + "SampleAfterValue": "1000003", + "UMask": "0x7", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts end of periods where the Reservation Station (RS) was empty.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xa5", + "EventName": "RS.EMPTY_COUNT", + "Invert": "1", + "PublicDescription": "Counts end of periods where the Reservation Station (RS) was empty. Could be useful to closely sample on front-end latency issues (see the FRONTEND_RETIRED event of designated precise events)", + "SampleAfterValue": "100003", + "UMask": "0x7", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when RS was empty and a resource allocation stall is asserted", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xa5", + "EventName": "RS.EMPTY_RESOURCE", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of issue slots in a UMWAIT or TPAUSE instruction where no uop issues due to the instruction putting the CPU into the C0.1 activity state. For Tremont, UMWAIT and TPAUSE will only put the CPU into C0.1 activity state (not C0.2 activity state).", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x75", + "EventName": "SERIALIZATION.C01_MS_SCB", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_atom" + }, { "BriefDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions.", "Counter": "0,1,2,3,4,5,6,7,8,9", @@ -223,6 +1517,35 @@ "UMask": "0x2", "Unit": "cpu_core" }, + { + "BriefDescription": "TMA slots wasted due to incorrect speculations.", + "Counter": "0", + "EventCode": "0xa4", + "EventName": "TOPDOWN.BAD_SPEC_SLOTS", + "PublicDescription": "Number of slots of TMA method that were wasted due to incorrect speculation. It covers all types of control-flow or data-related mis-speculations.", + "SampleAfterValue": "10000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "TMA slots wasted due to incorrect speculation by branch mispredictions", + "Counter": "0", + "EventCode": "0xa4", + "EventName": "TOPDOWN.BR_MISPREDICT_SLOTS", + "PublicDescription": "Number of TMA slots that were wasted due to incorrect speculation by (any type of) branch mispredictions. This event estimates number of speculative operations that were issued but not retired as well as the out-of-order engine recovery past a branch misprediction.", + "SampleAfterValue": "10000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "TOPDOWN.MEMORY_BOUND_SLOTS", + "Counter": "3", + "EventCode": "0xa4", + "EventName": "TOPDOWN.MEMORY_BOUND_SLOTS", + "SampleAfterValue": "10000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, { "BriefDescription": "TMA slots available for an unhalted logical processor. Fixed counter - architectural event", "Counter": "Fixed counter 3", @@ -244,7 +1567,7 @@ }, { "BriefDescription": "Fixed Counter: Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear.", - "Counter": "36", + "Counter": "Fixed counter 4", "EventName": "TOPDOWN_BAD_SPECULATION.ALL", "SampleAfterValue": "1000003", "UMask": "0x5", @@ -279,7 +1602,7 @@ }, { "BriefDescription": "Fixed Counter: Counts the number of retirement slots not consumed due to front end stalls.", - "Counter": "37", + "Counter": "Fixed counter 5", "EventName": "TOPDOWN_FE_BOUND.ALL", "SampleAfterValue": "1000003", "UMask": "0x6", @@ -296,7 +1619,7 @@ }, { "BriefDescription": "Fixed Counter: Counts the number of consumed retirement slots.", - "Counter": "38", + "Counter": "Fixed counter 6", "EventName": "TOPDOWN_RETIRING.ALL", "SampleAfterValue": "1000003", "UMask": "0x7", @@ -312,6 +1635,237 @@ "UMask": "0x2", "Unit": "cpu_atom" }, + { + "BriefDescription": "Number of non dec-by-all uops decoded by decoder", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x76", + "EventName": "UOPS_DECODED.DEC0_UOPS", + "PublicDescription": "This event counts the number of not dec-by-all uops decoded by decoder 0.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops executed on INT EU ALU ports.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.ALU", + "PublicDescription": "Number of ALU integer uops dispatch to execution.", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops executed on any INT EU ports", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.INT_EU_ALL", + "PublicDescription": "Number of integer uops dispatched to execution.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of Uops dispatched/executed by any of the 3 JEUs (all ups that hold the JEU including macro; micro jumps; fetch-from-eip)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.JMP", + "PublicDescription": "Number of jump uops dispatch to execution", + "SampleAfterValue": "2000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops executed on Load ports", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.LOAD", + "PublicDescription": "Number of Load uops dispatched to execution.", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of (shift) 1-cycle Uops dispatched/executed by any of the Shift Eus", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.SHIFT", + "PublicDescription": "Number of SHIFT integer uops dispatch to execution", + "SampleAfterValue": "2000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of Uops dispatched/executed by Slow EU (e.g. 3+ cycles LEA, >1 cycles shift, iDIVs, CR; *H operation)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.SLOW", + "PublicDescription": "Number of Slow integer uops dispatch to execution.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of Uops dispatched on STA ports", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.STA", + "PublicDescription": "Number of STA (Store Address) uops dispatch to execution", + "SampleAfterValue": "2000003", + "UMask": "0x80", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops executed on STD ports", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb2", + "EventName": "UOPS_DISPATCHED.STD", + "PublicDescription": "Number of STD (Store Data) uops dispatch to execution", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where at least 1 uop was executed per-thread", + "Counter": "3", + "CounterMask": "1", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.CYCLES_GE_1", + "PublicDescription": "Cycles where at least 1 uop was executed per-thread.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where at least 2 uops were executed per-thread", + "Counter": "3", + "CounterMask": "2", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.CYCLES_GE_2", + "PublicDescription": "Cycles where at least 2 uops were executed per-thread.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where at least 3 uops were executed per-thread", + "Counter": "3", + "CounterMask": "3", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.CYCLES_GE_3", + "PublicDescription": "Cycles where at least 3 uops were executed per-thread.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where at least 4 uops were executed per-thread", + "Counter": "3", + "CounterMask": "4", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.CYCLES_GE_4", + "PublicDescription": "Cycles where at least 4 uops were executed per-thread.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts number of cycles no uops were dispatched to be executed on this thread.", + "Counter": "3", + "CounterMask": "1", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.STALLS", + "Invert": "1", + "PublicDescription": "Counts cycles during which no uops were dispatched from the Reservation Station (RS) per thread.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of uops to be executed per-thread each cycle.", + "Counter": "3", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.THREAD", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of x87 uops dispatched.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xb1", + "EventName": "UOPS_EXECUTED.X87", + "PublicDescription": "Counts the number of x87 uops executed.", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Uops that RAT issues to RS", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xae", + "EventName": "UOPS_ISSUED.ANY", + "PublicDescription": "Counts the number of uops that the Resource Allocation Table (RAT) issues to the Reservation Station (RS).", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "UOPS_ISSUED.CYCLES", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0xae", + "EventName": "UOPS_ISSUED.CYCLES", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles with retired uop(s).", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.CYCLES", + "PublicDescription": "Counts cycles where at least one uop has retired.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired uops except the last uop of each instruction.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.HEAVY", + "PublicDescription": "Counts the number of retired micro-operations (uops) except the last uop of each instruction. An instruction that is decoded into less than two uops does not contribute to the count.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "UOPS_RETIRED.MS", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.MS", + "MSRIndex": "0x3F7", + "MSRValue": "0x8", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of non-speculative switches to the Microcode Sequencer (MS)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.MS_SWITCHES", + "MSRIndex": "0x3F7", + "MSRValue": "0x8", + "PublicDescription": "Switches to the Microcode Sequencer", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, { "BriefDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric.", "Counter": "0,1,2,3,4,5,6,7,8,9", @@ -321,5 +1875,17 @@ "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles without actually retired uops.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.STALLS", + "Invert": "1", + "PublicDescription": "This event counts cycles without actually retired uops.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" } ] diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/uncore-memory.json b/tools/perf/pmu-events/arch/x86/pantherlake/uncore-memory.json new file mode 100644 index 000000000000..a881b99be5f3 --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/pantherlake/uncore-memory.json @@ -0,0 +1,26 @@ +[ + { + "BriefDescription": "Read CAS command sent to DRAM", + "Counter": "0,1,2,3,4", + "EventCode": "0x22", + "EventName": "UNC_M_CAS_COUNT_RD", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Write CAS command sent to DRAM", + "Counter": "0,1,2,3,4", + "EventCode": "0x23", + "EventName": "UNC_M_CAS_COUNT_WR", + "PerPkg": "1", + "Unit": "iMC" + }, + { + "BriefDescription": "Total number of read and write byte transfers to/from DRAM, in 32B chunk, per DDR channel. Counter increments by 1 after sending or receiving 32B chunk data.", + "Counter": "0,1,2,3,4", + "EventCode": "0x3C", + "EventName": "UNC_M_TOTAL_DATA", + "PerPkg": "1", + "Unit": "iMC" + } +] diff --git a/tools/perf/pmu-events/arch/x86/pantherlake/virtual-memory.json b/tools/perf/pmu-events/arch/x86/pantherlake/virtual-memory.json index 690c5dff9d9e..8d56c16b2a39 100644 --- a/tools/perf/pmu-events/arch/x86/pantherlake/virtual-memory.json +++ b/tools/perf/pmu-events/arch/x86/pantherlake/virtual-memory.json @@ -1,4 +1,43 @@ [ + { + "BriefDescription": "Counts the number of page walks initiated by a demand load that missed the first and second level TLBs.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x08", + "EventName": "DTLB_LOAD_MISSES.MISS_CAUSED_WALK", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of first level TLB misses but second level hits due to a demand load that did not start a page walk. Accounts for all page sizes. Will result in a DTLB write from STLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x08", + "EventName": "DTLB_LOAD_MISSES.STLB_HIT", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Loads that miss the DTLB and hit the STLB.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.STLB_HIT", + "PublicDescription": "Counts loads that miss the DTLB (Data TLB) and hit the STLB (Second level TLB).", + "SampleAfterValue": "100003", + "UMask": "0x320", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when at least one PMH is busy with a page walk for a demand load.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_ACTIVE", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a demand load.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of page walks completed due to load DTLB misses to any page size.", "Counter": "0,1,2,3,4,5,6,7", @@ -19,6 +58,86 @@ "UMask": "0xe", "Unit": "cpu_core" }, + { + "BriefDescription": "Page walks completed due to a demand data load to a 1G page.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_1G", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Page walks completed due to a demand data load to a 2M/4M page.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Page walks completed due to a demand data load to a 4K page.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data loads. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of page walks outstanding for a demand load in the PMH each cycle.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x12", + "EventName": "DTLB_LOAD_MISSES.WALK_PENDING", + "PublicDescription": "Counts the number of page walks outstanding for a demand load in the PMH (Page Miss Handler) each cycle.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of page walks initiated by a store that missed the first and second level TLBs.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x49", + "EventName": "DTLB_STORE_MISSES.MISS_CAUSED_WALK", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of first level TLB misses but second level hits due to stores that did not start a page walk. Accounts for all page sizes. Will result in a DTLB write from STLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x49", + "EventName": "DTLB_STORE_MISSES.STLB_HIT", + "PublicDescription": "Counts the number of first level TLB misses but second level hits due to a demand load that did not start a page walk. Accounts for all page sizes. Will result in a DTLB write from STLB.", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Stores that miss the DTLB and hit the STLB.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.STLB_HIT", + "PublicDescription": "Counts stores that miss the DTLB (Data TLB) and hit the STLB (2nd Level TLB).", + "SampleAfterValue": "100003", + "UMask": "0x320", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when at least one PMH is busy with a page walk for a store.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_ACTIVE", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a store.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of page walks completed due to store DTLB misses to any page size.", "Counter": "0,1,2,3,4,5,6,7", @@ -39,6 +158,85 @@ "UMask": "0xe", "Unit": "cpu_core" }, + { + "BriefDescription": "Page walks completed due to a demand data store to a 1G page.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_1G", + "PublicDescription": "Counts completed page walks (1G sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Page walks completed due to a demand data store to a 2M/4M page.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M", + "PublicDescription": "Counts completed page walks (2M/4M sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Page walks completed due to a demand data store to a 4K page.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K", + "PublicDescription": "Counts completed page walks (4K sizes) caused by demand data stores. This implies address translations missed in the DTLB and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of page walks outstanding for a store in the PMH each cycle.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x13", + "EventName": "DTLB_STORE_MISSES.WALK_PENDING", + "PublicDescription": "Counts the number of page walks outstanding for a store in the PMH (Page Miss Handler) each cycle.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of page walks initiated by a instruction fetch that missed the first and second level TLBs.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x85", + "EventName": "ITLB_MISSES.MISS_CAUSED_WALK", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of first level TLB misses but second level hits due to an instruction fetch that did not start a page walk. Account for all pages sizes. Will result in an ITLB write from STLB.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x85", + "EventName": "ITLB_MISSES.STLB_HIT", + "SampleAfterValue": "1000003", + "UMask": "0x20", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Instruction fetch requests that miss the ITLB and hit the STLB.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.STLB_HIT", + "PublicDescription": "Counts instruction fetch requests that miss the ITLB (Instruction TLB) and hit the STLB (Second-level TLB).", + "SampleAfterValue": "100003", + "UMask": "0x120", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles when at least one PMH is busy with a page walk for code (instruction fetch) request.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "CounterMask": "1", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.WALK_ACTIVE", + "PublicDescription": "Counts cycles when at least one PMH (Page Miss Handler) is busy with a page walk for a code (instruction fetch) request.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of page walks completed due to instruction fetch misses to any page size.", "Counter": "0,1,2,3,4,5,6,7", @@ -58,5 +256,55 @@ "SampleAfterValue": "100003", "UMask": "0xe", "Unit": "cpu_core" + }, + { + "BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (2M/4M)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M", + "PublicDescription": "Counts completed page walks (2M/4M page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Code miss in all TLB levels causes a page walk that completes. (4K)", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.WALK_COMPLETED_4K", + "PublicDescription": "Counts completed page walks (4K page sizes) caused by a code fetch. This implies it missed in the ITLB (Instruction TLB) and further levels of TLB. The page walk can end with or without a fault.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of page walks outstanding for iside in PMH every cycle.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x85", + "EventName": "ITLB_MISSES.WALK_PENDING", + "PublicDescription": "Counts the number of page walks outstanding for iside in PMH every cycle. A PMH page walk is outstanding from page walk start till PMH becomes idle again (ready to serve next walk). Includes EPT-walk intervals. Walks could be counted by edge detecting on this event, but would count restarted suspended walks.", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Number of page walks outstanding for an outstanding code request in the PMH each cycle.", + "Counter": "0,1,2,3,4,5,6,7,8,9", + "EventCode": "0x11", + "EventName": "ITLB_MISSES.WALK_PENDING", + "PublicDescription": "Counts the number of page walks outstanding for an outstanding code (instruction fetch) request in the PMH (Page Miss Handler) each cycle.", + "SampleAfterValue": "100003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of retired loads that are blocked due to a first level TLB miss.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.DTLB_MISS", + "PublicDescription": "Counts the number of retired loads that are blocked due to a first level TLB miss. Available PDIST counters: 0,1", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_atom" } ] From 0c32e2748c2968d51ab735e5ea19d867c7019828 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Sep 2025 10:27:35 -0700 Subject: [PATCH 2264/2711] perf vendor events intel: Update sapphirerapids events to v1.35 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update sapphirerapids events to v1.35 released in: https://github.com/intel/perfmon/commit/94ed947d7b5966e50a685118f69e8942976ec397 https://github.com/intel/perfmon/commit/9d993957a2a8fc1d4f843013c979a413141e9839 Also adds cpu_cstate_c0 and cpu_cstate_c6 metrics. Event JSON automatically generated by: https://github.com/intel/perfmon/blob/main/scripts/create_perf_json.py Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Thomas Falcon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../arch/x86/sapphirerapids/cache.json | 63 +++++++++++++++++++ .../arch/x86/sapphirerapids/spr-metrics.json | 12 ++++ .../arch/x86/sapphirerapids/uncore-cache.json | 11 ++++ .../x86/sapphirerapids/uncore-memory.json | 22 +++++++ .../arch/x86/sapphirerapids/uncore-power.json | 2 - 6 files changed, 109 insertions(+), 3 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 3a15a0f75b96..3938555d661e 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -29,7 +29,7 @@ GenuineIntel-6-2E,v4,nehalemex,core GenuineIntel-6-CC,v1.00,pantherlake,core GenuineIntel-6-A7,v1.04,rocketlake,core GenuineIntel-6-2A,v19,sandybridge,core -GenuineIntel-6-8F,v1.30,sapphirerapids,core +GenuineIntel-6-8F,v1.35,sapphirerapids,core GenuineIntel-6-AF,v1.11,sierraforest,core GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v59,skylake,core diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json index a30af5140e6c..c66324d41a89 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json @@ -1,4 +1,67 @@ [ + { + "BriefDescription": "Hit snoop reply with data, line invalidated.", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.I_FWD_FE", + "PublicDescription": "Counts responses to snoops indicating the line will now be (I)nvalidated: removed from this core's cache, after the data is forwarded back to the requestor and indicating the data was found unmodified in the (FE) Forward or Exclusive State in this cores caches cache. A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x20" + }, + { + "BriefDescription": "HitM snoop reply with data, line invalidated.", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.I_FWD_M", + "PublicDescription": "Counts responses to snoops indicating the line will now be (I)nvalidated: removed from this core's caches, after the data is forwarded back to the requestor, and indicating the data was found modified(M) in this cores caches cache (aka HitM response). A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x10" + }, + { + "BriefDescription": "Hit snoop reply without sending the data, line invalidated.", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.I_HIT_FSE", + "PublicDescription": "Counts responses to snoops indicating the line will now be (I)nvalidated in this core's caches without forwarded back to the requestor. The line was in Forward, Shared or Exclusive (FSE) state in this cores caches. A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x2" + }, + { + "BriefDescription": "Line not found snoop reply", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.MISS", + "PublicDescription": "Counts responses to snoops indicating that the data was not found (IHitI) in this core's caches. A single snoop response from the core counts on all hyperthreads of the Core.", + "SampleAfterValue": "1000003", + "UMask": "0x1" + }, + { + "BriefDescription": "Hit snoop reply with data, line kept in Shared state.", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.S_FWD_FE", + "PublicDescription": "Counts responses to snoops indicating the line may be kept on this core in the (S)hared state, after the data is forwarded back to the requestor, initially the data was found in the cache in the (FS) Forward or Shared state. A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x40" + }, + { + "BriefDescription": "HitM snoop reply with data, line kept in Shared state", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.S_FWD_M", + "PublicDescription": "Counts responses to snoops indicating the line may be kept on this core in the (S)hared state, after the data is forwarded back to the requestor, initially the data was found in the cache in the (M)odified state. A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x8" + }, + { + "BriefDescription": "Hit snoop reply without sending the data, line kept in Shared state.", + "Counter": "0,1,2,3", + "EventCode": "0x27", + "EventName": "CORE_SNOOP_RESPONSE.S_HIT_FSE", + "PublicDescription": "Counts responses to snoops indicating the line was kept on this core in the (S)hared state, and that the data was found unmodified but not forwarded back to the requestor, initially the data was found in the cache in the (FSE) Forward, Shared state or Exclusive state. A single snoop response from the core counts on all hyperthreads of the core.", + "SampleAfterValue": "1000003", + "UMask": "0x4" + }, { "BriefDescription": "L1D.HWPF_MISS", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json index 8a18d6e01ef4..b6a28227a58a 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json @@ -39,6 +39,18 @@ "MetricName": "cpi", "ScaleUnit": "1per_instr" }, + { + "BriefDescription": "The average number of cores that are in cstate C0 as observed by the power control unit (PCU)", + "MetricExpr": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C0 / UNC_P_CLOCKTICKS * #num_packages", + "MetricGroup": "cpu_cstate", + "MetricName": "cpu_cstate_c0" + }, + { + "BriefDescription": "The average number of cores are in cstate C6 as observed by the power control unit (PCU)", + "MetricExpr": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C6 / UNC_P_CLOCKTICKS * #num_packages", + "MetricGroup": "cpu_cstate", + "MetricName": "cpu_cstate_c6" + }, { "BriefDescription": "CPU operating frequency (in GHz)", "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC * #SYSTEM_TSC_FREQ / 1e9", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-cache.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-cache.json index a38db3e253f2..1bdda3c3ccbf 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-cache.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-cache.json @@ -311,6 +311,17 @@ "UMask": "0x2", "Unit": "CHA" }, + { + "BriefDescription": "Distress signal asserted : DPT Remote", + "Counter": "0,1,2,3", + "EventCode": "0xaf", + "EventName": "UNC_CHA_DISTRESS_ASSERTED.DPT_NONLOCAL", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Distress signal asserted : DPT Remote : Counts the number of cycles either the local or incoming distress signals are asserted. : Dynamic Prefetch Throttle received by this tile", + "UMask": "0x8", + "Unit": "CHA" + }, { "BriefDescription": "Egress Blocking due to Ordering requirements : Down", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-memory.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-memory.json index 90f61c9511fc..30044177ccf8 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-memory.json @@ -3129,6 +3129,28 @@ "PublicDescription": "Clock-Enabled Self-Refresh : Counts the number of cycles when the iMC is in self-refresh and the iMC still has a clock. This happens in some package C-states. For example, the PCU may ask the iMC to enter self-refresh even though some of the cores are still processing. One use of this is for Monroe technology. Self-refresh is required during package C3 and C6, but there is no clock in the iMC at this time, so it is not possible to count these cases.", "Unit": "iMC" }, + { + "BriefDescription": "Throttle Cycles for Rank 0", + "Counter": "0,1,2,3", + "EventCode": "0x46", + "EventName": "UNC_M_POWER_THROTTLE_CYCLES.SLOT0", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Throttle Cycles for Rank 0 : Counts the number of cycles while the iMC is being throttled by either thermal constraints or by the PCU throttling. It is not possible to distinguish between the two. This can be filtered by rank. If multiple ranks are selected and are being throttled at the same time, the counter will only increment by 1. : Thermal throttling is performed per DIMM. We support 3 DIMMs per channel. This ID allows us to filter by ID.", + "UMask": "0x1", + "Unit": "iMC" + }, + { + "BriefDescription": "Throttle Cycles for Rank 0", + "Counter": "0,1,2,3", + "EventCode": "0x46", + "EventName": "UNC_M_POWER_THROTTLE_CYCLES.SLOT1", + "Experimental": "1", + "PerPkg": "1", + "PublicDescription": "Throttle Cycles for Rank 0 : Counts the number of cycles while the iMC is being throttled by either thermal constraints or by the PCU throttling. It is not possible to distinguish between the two. This can be filtered by rank. If multiple ranks are selected and are being throttled at the same time, the counter will only increment by 1.", + "UMask": "0x2", + "Unit": "iMC" + }, { "BriefDescription": "Precharge due to read, write, underfill, or PGT.", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-power.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-power.json index 9482ddaea4d1..71c35b165a3e 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-power.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-power.json @@ -178,7 +178,6 @@ "Counter": "0,1,2,3", "EventCode": "0x35", "EventName": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C0", - "Experimental": "1", "PerPkg": "1", "PublicDescription": "Number of cores in C0 : This is an occupancy event that tracks the number of cores that are in the chosen C-State. It can be used by itself to get the average number of cores in that C-state with thresholding to generate histograms, or with other PCU events and occupancy triggering to capture other details.", "Unit": "PCU" @@ -198,7 +197,6 @@ "Counter": "0,1,2,3", "EventCode": "0x37", "EventName": "UNC_P_POWER_STATE_OCCUPANCY_CORES_C6", - "Experimental": "1", "PerPkg": "1", "PublicDescription": "Number of cores in C6 : This is an occupancy event that tracks the number of cores that are in the chosen C-State. It can be used by itself to get the average number of cores in that C-state with thresholding to generate histograms, or with other PCU events and occupancy triggering to capture other details.", "Unit": "PCU" From 3f20f98e2a542fba932d374253b7c81c0f0957e9 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 25 Sep 2025 10:27:36 -0700 Subject: [PATCH 2265/2711] perf vendor events intel: Update sierraforest events to v1.12 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update sierraforest events to v1.12 released in: https://github.com/intel/perfmon/commit/8279984b0b2eef35412c0281983ef59ae74f19ed Event JSON automatically generated by: https://github.com/intel/perfmon/blob/main/scripts/create_perf_json.py Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andreas Färber Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Manivannan Sadhasivam Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Thomas Falcon Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../arch/x86/sierraforest/cache.json | 61 +++++++++-- .../x86/sierraforest/uncore-interconnect.json | 10 +- .../arch/x86/sierraforest/uncore-io.json | 1 - .../arch/x86/sierraforest/uncore-memory.json | 103 ++++++++++++------ 5 files changed, 133 insertions(+), 44 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 3938555d661e..32093bded949 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -30,7 +30,7 @@ GenuineIntel-6-CC,v1.00,pantherlake,core GenuineIntel-6-A7,v1.04,rocketlake,core GenuineIntel-6-2A,v19,sandybridge,core GenuineIntel-6-8F,v1.35,sapphirerapids,core -GenuineIntel-6-AF,v1.11,sierraforest,core +GenuineIntel-6-AF,v1.12,sierraforest,core GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v59,skylake,core GenuineIntel-6-55-[01234],v1.37,skylakex,core diff --git a/tools/perf/pmu-events/arch/x86/sierraforest/cache.json b/tools/perf/pmu-events/arch/x86/sierraforest/cache.json index 877052db1490..b2650e8ae252 100644 --- a/tools/perf/pmu-events/arch/x86/sierraforest/cache.json +++ b/tools/perf/pmu-events/arch/x86/sierraforest/cache.json @@ -162,6 +162,14 @@ "SampleAfterValue": "1000003", "UMask": "0x6" }, + { + "BriefDescription": "Counts the number of unhalted cycles when the core is stalled due to a demand load miss which hit in the LLC, no snoop was required. LLC provides the data. If the core has access to an L3 cache, an LLC hit refers to an L3 cache hit, otherwise it counts zeros.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0x34", + "EventName": "MEM_BOUND_STALLS_LOAD.LLC_HIT_NOSNOOP", + "SampleAfterValue": "1000003", + "UMask": "0x2" + }, { "BriefDescription": "Counts the number of unhalted cycles when the core is stalled due to a demand load miss which missed all the local caches. If the core has access to an L3 cache, an LLC miss refers to an L3 cache miss, otherwise it is an L2 cache miss.", "Counter": "0,1,2,3,4,5,6,7", @@ -178,6 +186,14 @@ "SampleAfterValue": "1000003", "UMask": "0x80" }, + { + "BriefDescription": "Counts the total number of load ops retired that miss the L3 cache.", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd3", + "EventName": "MEM_LOAD_UOPS_L3_MISS_RETIRED.ALL", + "SampleAfterValue": "1000003", + "UMask": "0xff" + }, { "BriefDescription": "Counts the number of load ops retired that miss the L3 cache and hit in DRAM", "Counter": "0,1,2,3,4,5,6,7", @@ -186,6 +202,31 @@ "SampleAfterValue": "1000003", "UMask": "0x1" }, + { + "BriefDescription": "Counts the number of load ops retired that miss the L3 cache and hit in a Remote DRAM", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd3", + "EventName": "MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_DRAM_OR_NOFWD", + "PublicDescription": "Counts the number of load ops retired that miss the L3 cache and hit in a Remote DRAM, OR had a Remote snoop miss/no fwd and hit in the Local Dram", + "SampleAfterValue": "1000003", + "UMask": "0x2" + }, + { + "BriefDescription": "Counts the number of load ops retired that miss the L3 cache and hit in a Remote Cache and modified data was forwarded", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd3", + "EventName": "MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_FWD_HITM", + "SampleAfterValue": "1000003", + "UMask": "0x8" + }, + { + "BriefDescription": "Counts the number of load ops retired that miss the L3 cache and hit in a Remote Cache and non-modified data was forwarded", + "Counter": "0,1,2,3,4,5,6,7", + "EventCode": "0xd3", + "EventName": "MEM_LOAD_UOPS_L3_MISS_RETIRED.REMOTE_FWD_NONM", + "SampleAfterValue": "1000003", + "UMask": "0x4" + }, { "BriefDescription": "Counts the number of load ops retired that hit the L1 data cache.", "Counter": "0,1,2,3,4,5,6,7", @@ -286,7 +327,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_1024", @@ -297,7 +338,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_128", @@ -308,7 +349,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_16", @@ -319,7 +360,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_2048", @@ -330,7 +371,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_256", @@ -341,7 +382,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_32", @@ -352,7 +393,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_4", @@ -363,7 +404,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_512", @@ -374,7 +415,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_64", @@ -385,7 +426,7 @@ }, { "BriefDescription": "Counts the number of tagged load uops retired that exceed the latency threshold defined in MEC_CR_PEBS_LD_LAT_THRESHOLD - Only counts with PEBS enabled.", - "Counter": "0,1", + "Counter": "0,1,2,3,4,5,6,7", "Data_LA": "1", "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.LOAD_LATENCY_GT_8", diff --git a/tools/perf/pmu-events/arch/x86/sierraforest/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/sierraforest/uncore-interconnect.json index 952b6de3fefc..251e5d20fefe 100644 --- a/tools/perf/pmu-events/arch/x86/sierraforest/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/sierraforest/uncore-interconnect.json @@ -839,11 +839,19 @@ "Counter": "0,1,2,3", "EventCode": "0x1F", "EventName": "UNC_I_MISC1.LOST_FWD", - "Experimental": "1", "PerPkg": "1", "UMask": "0x10", "Unit": "IRP" }, + { + "BriefDescription": "Misc Events - Set 1 : Received Invalid : Secondary received a transfer that did not have sufficient MESI state", + "Counter": "0,1,2,3", + "EventCode": "0x1F", + "EventName": "UNC_I_MISC1.SEC_RCVD_INVLD", + "PerPkg": "1", + "UMask": "0x20", + "Unit": "IRP" + }, { "BriefDescription": "Snoop Hit E/S responses", "Counter": "0,1,2,3", diff --git a/tools/perf/pmu-events/arch/x86/sierraforest/uncore-io.json b/tools/perf/pmu-events/arch/x86/sierraforest/uncore-io.json index f4f956966e16..2ea2637df3fb 100644 --- a/tools/perf/pmu-events/arch/x86/sierraforest/uncore-io.json +++ b/tools/perf/pmu-events/arch/x86/sierraforest/uncore-io.json @@ -1321,7 +1321,6 @@ "FCMask": "0x01", "PerPkg": "1", "PortMask": "0x0FF", - "PublicDescription": "-", "UMask": "0x4", "Unit": "IIO" }, diff --git a/tools/perf/pmu-events/arch/x86/sierraforest/uncore-memory.json b/tools/perf/pmu-events/arch/x86/sierraforest/uncore-memory.json index c7e9dbe02eb0..a9fd7a34b24b 100644 --- a/tools/perf/pmu-events/arch/x86/sierraforest/uncore-memory.json +++ b/tools/perf/pmu-events/arch/x86/sierraforest/uncore-memory.json @@ -56,6 +56,33 @@ "UMask": "0xcf", "Unit": "IMC" }, + { + "BriefDescription": "CAS count for SubChannel 0 regular reads", + "Counter": "0,1,2,3", + "EventCode": "0x05", + "EventName": "UNC_M_CAS_COUNT_SCH0.RD_NON_UNDERFILL", + "PerPkg": "1", + "UMask": "0xc3", + "Unit": "IMC" + }, + { + "BriefDescription": "CAS count for SubChannel 0 auto-precharge reads", + "Counter": "0,1,2,3", + "EventCode": "0x05", + "EventName": "UNC_M_CAS_COUNT_SCH0.RD_PRE_REG", + "PerPkg": "1", + "UMask": "0xc2", + "Unit": "IMC" + }, + { + "BriefDescription": "CAS count for SubChannel 0 auto-precharge underfill reads", + "Counter": "0,1,2,3", + "EventCode": "0x05", + "EventName": "UNC_M_CAS_COUNT_SCH0.RD_PRE_UNDERFILL", + "PerPkg": "1", + "UMask": "0xc8", + "Unit": "IMC" + }, { "BriefDescription": "CAS count for SubChannel 0 regular reads", "Counter": "0,1,2,3", @@ -74,6 +101,15 @@ "UMask": "0xc4", "Unit": "IMC" }, + { + "BriefDescription": "CAS count for SubChannel 0 underfill reads", + "Counter": "0,1,2,3", + "EventCode": "0x05", + "EventName": "UNC_M_CAS_COUNT_SCH0.RD_UNDERFILL_ALL", + "PerPkg": "1", + "UMask": "0xcc", + "Unit": "IMC" + }, { "BriefDescription": "CAS count for SubChannel 0, all writes", "Counter": "0,1,2,3", @@ -121,6 +157,33 @@ "UMask": "0xcf", "Unit": "IMC" }, + { + "BriefDescription": "CAS count for SubChannel 1 regular reads", + "Counter": "0,1,2,3", + "EventCode": "0x06", + "EventName": "UNC_M_CAS_COUNT_SCH1.RD_NON_UNDERFILL", + "PerPkg": "1", + "UMask": "0xc3", + "Unit": "IMC" + }, + { + "BriefDescription": "CAS count for SubChannel 1 auto-precharge reads", + "Counter": "0,1,2,3", + "EventCode": "0x06", + "EventName": "UNC_M_CAS_COUNT_SCH1.RD_PRE_REG", + "PerPkg": "1", + "UMask": "0xc2", + "Unit": "IMC" + }, + { + "BriefDescription": "CAS count for SubChannel 1 auto-precharge underfill reads", + "Counter": "0,1,2,3", + "EventCode": "0x06", + "EventName": "UNC_M_CAS_COUNT_SCH1.RD_PRE_UNDERFILL", + "PerPkg": "1", + "UMask": "0xc8", + "Unit": "IMC" + }, { "BriefDescription": "CAS count for SubChannel 1 regular reads", "Counter": "0,1,2,3", @@ -139,6 +202,15 @@ "UMask": "0xc4", "Unit": "IMC" }, + { + "BriefDescription": "CAS count for SubChannel 1 underfill reads", + "Counter": "0,1,2,3", + "EventCode": "0x06", + "EventName": "UNC_M_CAS_COUNT_SCH1.RD_UNDERFILL_ALL", + "PerPkg": "1", + "UMask": "0xcc", + "Unit": "IMC" + }, { "BriefDescription": "CAS count for SubChannel 1, all writes", "Counter": "0,1,2,3", @@ -195,7 +267,6 @@ "EventName": "UNC_M_MR4_2XREF_CYCLES.SCH0_DIMM0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -206,7 +277,6 @@ "EventName": "UNC_M_MR4_2XREF_CYCLES.SCH0_DIMM1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -217,7 +287,6 @@ "EventName": "UNC_M_MR4_2XREF_CYCLES.SCH1_DIMM0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x4", "Unit": "IMC" }, @@ -228,7 +297,6 @@ "EventName": "UNC_M_MR4_2XREF_CYCLES.SCH1_DIMM1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x8", "Unit": "IMC" }, @@ -239,7 +307,6 @@ "EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH0_DIMM0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -250,7 +317,6 @@ "EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH0_DIMM1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -261,7 +327,6 @@ "EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH1_DIMM0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x4", "Unit": "IMC" }, @@ -272,7 +337,6 @@ "EventName": "UNC_M_PDC_MR4ACTIVE_CYCLES.SCH1_DIMM1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x8", "Unit": "IMC" }, @@ -283,7 +347,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -294,7 +357,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -305,7 +367,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK2", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x4", "Unit": "IMC" }, @@ -316,7 +377,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH0_RANK3", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x8", "Unit": "IMC" }, @@ -327,7 +387,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x10", "Unit": "IMC" }, @@ -338,7 +397,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x20", "Unit": "IMC" }, @@ -349,7 +407,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK2", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x40", "Unit": "IMC" }, @@ -360,7 +417,6 @@ "EventName": "UNC_M_POWERDOWN_CYCLES.SCH1_RANK3", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x80", "Unit": "IMC" }, @@ -371,7 +427,6 @@ "EventName": "UNC_M_POWER_CHANNEL_PPD_CYCLES", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "Unit": "IMC" }, { @@ -381,7 +436,6 @@ "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES.SLOT0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -392,7 +446,6 @@ "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES.SLOT1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -423,7 +476,6 @@ "EventName": "UNC_M_POWER_THROTTLE_CYCLES.MR4BLKEN", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x8", "Unit": "IMC" }, @@ -434,7 +486,6 @@ "EventName": "UNC_M_POWER_THROTTLE_CYCLES.RAPLBLK", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x4", "Unit": "IMC" }, @@ -617,7 +668,6 @@ "EventName": "UNC_M_SELF_REFRESH.ENTER_SUCCESS", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "UNC_M_SELF_REFRESH.ENTER_SUCCESS", "UMask": "0x2", "Unit": "IMC" }, @@ -628,7 +678,6 @@ "EventName": "UNC_M_SELF_REFRESH.ENTER_SUCCESS_CYCLES", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -639,7 +688,6 @@ "EventName": "UNC_M_THROTTLE_CRIT_CYCLES.SLOT0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -650,7 +698,6 @@ "EventName": "UNC_M_THROTTLE_CRIT_CYCLES.SLOT1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -661,7 +708,6 @@ "EventName": "UNC_M_THROTTLE_HIGH_CYCLES.SLOT0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -672,7 +718,6 @@ "EventName": "UNC_M_THROTTLE_HIGH_CYCLES.SLOT1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -683,7 +728,6 @@ "EventName": "UNC_M_THROTTLE_LOW_CYCLES.SLOT0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -694,7 +738,6 @@ "EventName": "UNC_M_THROTTLE_LOW_CYCLES.SLOT1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, @@ -705,7 +748,6 @@ "EventName": "UNC_M_THROTTLE_MID_CYCLES.SLOT0", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x1", "Unit": "IMC" }, @@ -716,7 +758,6 @@ "EventName": "UNC_M_THROTTLE_MID_CYCLES.SLOT1", "Experimental": "1", "PerPkg": "1", - "PublicDescription": "-", "UMask": "0x2", "Unit": "IMC" }, From 15463eece957be34da64b4d6fe18fc98981bf487 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 18 Sep 2025 17:32:59 -0700 Subject: [PATCH 2266/2711] KVM: s390/vfio-ap: Use kvm_is_gpa_in_memslot() instead of open coded equivalent Use kvm_is_gpa_in_memslot() to check the validity of the notification indicator byte address instead of open coding equivalent logic in the VFIO AP driver. Opportunistically use a dedicated wrapper that exists and is exported expressly for the VFIO AP module. kvm_is_gpa_in_memslot() is generally unsuitable for use outside of KVM; other drivers typically shouldn't rely on KVM's memslots, and using the API requires kvm->srcu (or slots_lock) to be held for the entire duration of the usage, e.g. to avoid TOCTOU bugs. handle_pqap() is a bit of a special case, as it's explicitly invoked from KVM with kvm->srcu already held, and the VFIO AP driver is in many ways an extension of KVM that happens to live in a separate module. Providing a dedicated API for the VFIO AP driver will allow restricting the vast majority of generic KVM's exports to KVM submodules (e.g. to x86's kvm-{amd,intel}.ko vendor mdoules). No functional change intended. Acked-by: Anthony Krowiak Reviewed-by: Christian Borntraeger Link: https://lore.kernel.org/r/20250919003303.1355064-2-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/s390/include/asm/kvm_host.h | 2 ++ arch/s390/kvm/priv.c | 8 ++++++++ drivers/s390/crypto/vfio_ap_ops.c | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 95d15416c39d..c2ba3d4398c5 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -722,6 +722,8 @@ extern int kvm_s390_enter_exit_sie(struct kvm_s390_sie_block *scb, extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc); extern int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc); +bool kvm_s390_is_gpa_in_memslot(struct kvm *kvm, gpa_t gpa); + static inline void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot) {} static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 9253c70897a8..9a71b6e00948 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -605,6 +605,14 @@ static int handle_io_inst(struct kvm_vcpu *vcpu) } } +#if IS_ENABLED(CONFIG_VFIO_AP) +bool kvm_s390_is_gpa_in_memslot(struct kvm *kvm, gpa_t gpa) +{ + return kvm_is_gpa_in_memslot(kvm, gpa); +} +EXPORT_SYMBOL_FOR_MODULES(kvm_s390_is_gpa_in_memslot, "vfio_ap"); +#endif + /* * handle_pqap: Handling pqap interception * @vcpu: the vcpu having issue the pqap instruction diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 766557547f83..eb5ff49f6fe7 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -354,7 +354,7 @@ static int vfio_ap_validate_nib(struct kvm_vcpu *vcpu, dma_addr_t *nib) if (!*nib) return -EINVAL; - if (kvm_is_error_hva(gfn_to_hva(vcpu->kvm, *nib >> PAGE_SHIFT))) + if (!kvm_s390_is_gpa_in_memslot(vcpu->kvm, *nib)) return -EINVAL; return 0; From 20c48920583675e67b3824f147726e0fbda735ce Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 18 Sep 2025 17:33:00 -0700 Subject: [PATCH 2267/2711] KVM: Export KVM-internal symbols for sub-modules only Rework the vast majority of KVM's exports to expose symbols only to KVM submodules, i.e. to x86's kvm-{amd,intel}.ko and PPC's kvm-{pr,hv}.ko. With few exceptions, KVM's exported APIs are intended (and safe) for KVM- internal usage only. Keep kvm_get_kvm(), kvm_get_kvm_safe(), and kvm_put_kvm() as normal exports, as they are needed by VFIO, and are generally safe for external usage (though ideally even the get/put APIs would be KVM-internal, and VFIO would pin a VM by grabbing a reference to its associated file). Implement a framework in kvm_types.h in anticipation of providing a macro to restrict KVM-specific kernel exports, i.e. to provide symbol exports for KVM if and only if KVM is built as one or more modules. Link: https://lore.kernel.org/r/20250919003303.1355064-3-seanjc@google.com Cc: Nathan Chancellor Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/powerpc/include/asm/Kbuild | 1 - arch/powerpc/include/asm/kvm_types.h | 15 ++++ arch/x86/include/asm/kvm_types.h | 10 +++ include/linux/kvm_types.h | 25 ++++-- virt/kvm/eventfd.c | 2 +- virt/kvm/guest_memfd.c | 4 +- virt/kvm/kvm_main.c | 128 +++++++++++++-------------- 7 files changed, 110 insertions(+), 75 deletions(-) create mode 100644 arch/powerpc/include/asm/kvm_types.h diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild index e5fdc336c9b2..2e23533b67e3 100644 --- a/arch/powerpc/include/asm/Kbuild +++ b/arch/powerpc/include/asm/Kbuild @@ -3,7 +3,6 @@ generated-y += syscall_table_32.h generated-y += syscall_table_64.h generated-y += syscall_table_spu.h generic-y += agp.h -generic-y += kvm_types.h generic-y += mcs_spinlock.h generic-y += qrwlock.h generic-y += early_ioremap.h diff --git a/arch/powerpc/include/asm/kvm_types.h b/arch/powerpc/include/asm/kvm_types.h new file mode 100644 index 000000000000..5d4bffea7d47 --- /dev/null +++ b/arch/powerpc/include/asm/kvm_types.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_PPC_KVM_TYPES_H +#define _ASM_PPC_KVM_TYPES_H + +#if IS_MODULE(CONFIG_KVM_BOOK3S_64_PR) && IS_MODULE(CONFIG_KVM_BOOK3S_64_HV) +#define KVM_SUB_MODULES kvm-pr,kvm-hv +#elif IS_MODULE(CONFIG_KVM_BOOK3S_64_PR) +#define KVM_SUB_MODULES kvm-pr +#elif IS_MODULE(CONFIG_KVM_BOOK3S_64_HV) +#define KVM_SUB_MODULES kvm-hv +#else +#undef KVM_SUB_MODULES +#endif + +#endif diff --git a/arch/x86/include/asm/kvm_types.h b/arch/x86/include/asm/kvm_types.h index 08f1b57d3b62..23268a188e70 100644 --- a/arch/x86/include/asm/kvm_types.h +++ b/arch/x86/include/asm/kvm_types.h @@ -2,6 +2,16 @@ #ifndef _ASM_X86_KVM_TYPES_H #define _ASM_X86_KVM_TYPES_H +#if IS_MODULE(CONFIG_KVM_AMD) && IS_MODULE(CONFIG_KVM_INTEL) +#define KVM_SUB_MODULES kvm-amd,kvm-intel +#elif IS_MODULE(CONFIG_KVM_AMD) +#define KVM_SUB_MODULES kvm-amd +#elif IS_MODULE(CONFIG_KVM_INTEL) +#define KVM_SUB_MODULES kvm-intel +#else +#undef KVM_SUB_MODULES +#endif + #define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40 #endif /* _ASM_X86_KVM_TYPES_H */ diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index 827ecc0b7e10..490464c205b4 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h @@ -3,6 +3,23 @@ #ifndef __KVM_TYPES_H__ #define __KVM_TYPES_H__ +#include +#include +#include +#include + +#ifdef KVM_SUB_MODULES +#define EXPORT_SYMBOL_FOR_KVM_INTERNAL(symbol) \ + EXPORT_SYMBOL_FOR_MODULES(symbol, __stringify(KVM_SUB_MODULES)) +#else +#define EXPORT_SYMBOL_FOR_KVM_INTERNAL(symbol) +#endif + +#ifndef __ASSEMBLER__ + +#include +#include + struct kvm; struct kvm_async_pf; struct kvm_device_ops; @@ -19,13 +36,6 @@ struct kvm_memslots; enum kvm_mr_change; -#include -#include -#include -#include - -#include - /* * Address types: * @@ -116,5 +126,6 @@ struct kvm_vcpu_stat_generic { }; #define KVM_STATS_NAME_SIZE 48 +#endif /* !__ASSEMBLER__ */ #endif /* __KVM_TYPES_H__ */ diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index 6b1133a6617f..a7794ffdb976 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -525,7 +525,7 @@ bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin) return false; } -EXPORT_SYMBOL_GPL(kvm_irq_has_notifier); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_irq_has_notifier); void kvm_notify_acked_gsi(struct kvm *kvm, int gsi) { diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c index 1d323ca178cb..94bafd6c558c 100644 --- a/virt/kvm/guest_memfd.c +++ b/virt/kvm/guest_memfd.c @@ -702,7 +702,7 @@ out: fput(file); return r; } -EXPORT_SYMBOL_GPL(kvm_gmem_get_pfn); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_gmem_get_pfn); #ifdef CONFIG_HAVE_KVM_ARCH_GMEM_POPULATE long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long npages, @@ -785,5 +785,5 @@ put_folio_and_exit: fput(file); return ret && !i ? ret : i; } -EXPORT_SYMBOL_GPL(kvm_gmem_populate); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_gmem_populate); #endif diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index c0c5626ab71d..226faeaa8e56 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -77,22 +77,22 @@ MODULE_LICENSE("GPL"); /* Architectures should define their poll value according to the halt latency */ unsigned int halt_poll_ns = KVM_HALT_POLL_NS_DEFAULT; module_param(halt_poll_ns, uint, 0644); -EXPORT_SYMBOL_GPL(halt_poll_ns); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(halt_poll_ns); /* Default doubles per-vcpu halt_poll_ns. */ unsigned int halt_poll_ns_grow = 2; module_param(halt_poll_ns_grow, uint, 0644); -EXPORT_SYMBOL_GPL(halt_poll_ns_grow); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(halt_poll_ns_grow); /* The start value to grow halt_poll_ns from */ unsigned int halt_poll_ns_grow_start = 10000; /* 10us */ module_param(halt_poll_ns_grow_start, uint, 0644); -EXPORT_SYMBOL_GPL(halt_poll_ns_grow_start); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(halt_poll_ns_grow_start); /* Default halves per-vcpu halt_poll_ns. */ unsigned int halt_poll_ns_shrink = 2; module_param(halt_poll_ns_shrink, uint, 0644); -EXPORT_SYMBOL_GPL(halt_poll_ns_shrink); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(halt_poll_ns_shrink); /* * Allow direct access (from KVM or the CPU) without MMU notifier protection @@ -170,7 +170,7 @@ void vcpu_load(struct kvm_vcpu *vcpu) kvm_arch_vcpu_load(vcpu, cpu); put_cpu(); } -EXPORT_SYMBOL_GPL(vcpu_load); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(vcpu_load); void vcpu_put(struct kvm_vcpu *vcpu) { @@ -180,7 +180,7 @@ void vcpu_put(struct kvm_vcpu *vcpu) __this_cpu_write(kvm_running_vcpu, NULL); preempt_enable(); } -EXPORT_SYMBOL_GPL(vcpu_put); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(vcpu_put); /* TODO: merge with kvm_arch_vcpu_should_kick */ static bool kvm_request_needs_ipi(struct kvm_vcpu *vcpu, unsigned req) @@ -288,7 +288,7 @@ bool kvm_make_all_cpus_request(struct kvm *kvm, unsigned int req) return called; } -EXPORT_SYMBOL_GPL(kvm_make_all_cpus_request); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_make_all_cpus_request); void kvm_flush_remote_tlbs(struct kvm *kvm) { @@ -309,7 +309,7 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) || kvm_make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH)) ++kvm->stat.generic.remote_tlb_flush; } -EXPORT_SYMBOL_GPL(kvm_flush_remote_tlbs); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_flush_remote_tlbs); void kvm_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, u64 nr_pages) { @@ -499,7 +499,7 @@ void kvm_destroy_vcpus(struct kvm *kvm) atomic_set(&kvm->online_vcpus, 0); } -EXPORT_SYMBOL_GPL(kvm_destroy_vcpus); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_destroy_vcpus); #ifdef CONFIG_KVM_GENERIC_MMU_NOTIFIER static inline struct kvm *mmu_notifier_to_kvm(struct mmu_notifier *mn) @@ -1365,7 +1365,7 @@ void kvm_put_kvm_no_destroy(struct kvm *kvm) { WARN_ON(refcount_dec_and_test(&kvm->users_count)); } -EXPORT_SYMBOL_GPL(kvm_put_kvm_no_destroy); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_put_kvm_no_destroy); static int kvm_vm_release(struct inode *inode, struct file *filp) { @@ -1397,7 +1397,7 @@ out_unlock: } return -EINTR; } -EXPORT_SYMBOL_GPL(kvm_trylock_all_vcpus); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_trylock_all_vcpus); int kvm_lock_all_vcpus(struct kvm *kvm) { @@ -1422,7 +1422,7 @@ out_unlock: } return r; } -EXPORT_SYMBOL_GPL(kvm_lock_all_vcpus); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_lock_all_vcpus); void kvm_unlock_all_vcpus(struct kvm *kvm) { @@ -1434,7 +1434,7 @@ void kvm_unlock_all_vcpus(struct kvm *kvm) kvm_for_each_vcpu(i, vcpu, kvm) mutex_unlock(&vcpu->mutex); } -EXPORT_SYMBOL_GPL(kvm_unlock_all_vcpus); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_unlock_all_vcpus); /* * Allocation size is twice as large as the actual dirty bitmap size. @@ -2142,7 +2142,7 @@ int kvm_set_internal_memslot(struct kvm *kvm, return kvm_set_memory_region(kvm, mem); } -EXPORT_SYMBOL_GPL(kvm_set_internal_memslot); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_internal_memslot); static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region2 *mem) @@ -2201,7 +2201,7 @@ int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log, *is_dirty = 1; return 0; } -EXPORT_SYMBOL_GPL(kvm_get_dirty_log); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_dirty_log); #else /* CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT */ /** @@ -2636,7 +2636,7 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) { return __gfn_to_memslot(kvm_memslots(kvm), gfn); } -EXPORT_SYMBOL_GPL(gfn_to_memslot); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(gfn_to_memslot); struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn) { @@ -2670,7 +2670,7 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn return NULL; } -EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_memslot); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_gfn_to_memslot); bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn) { @@ -2678,7 +2678,7 @@ bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn) return kvm_is_visible_memslot(memslot); } -EXPORT_SYMBOL_GPL(kvm_is_visible_gfn); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_is_visible_gfn); bool kvm_vcpu_is_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn) { @@ -2686,7 +2686,7 @@ bool kvm_vcpu_is_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn) return kvm_is_visible_memslot(memslot); } -EXPORT_SYMBOL_GPL(kvm_vcpu_is_visible_gfn); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_is_visible_gfn); unsigned long kvm_host_page_size(struct kvm_vcpu *vcpu, gfn_t gfn) { @@ -2743,19 +2743,19 @@ unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, { return gfn_to_hva_many(slot, gfn, NULL); } -EXPORT_SYMBOL_GPL(gfn_to_hva_memslot); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(gfn_to_hva_memslot); unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) { return gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL); } -EXPORT_SYMBOL_GPL(gfn_to_hva); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(gfn_to_hva); unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn) { return gfn_to_hva_many(kvm_vcpu_gfn_to_memslot(vcpu, gfn), gfn, NULL); } -EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_hva); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_gfn_to_hva); /* * Return the hva of a @gfn and the R/W attribute if possible. @@ -2819,7 +2819,7 @@ void kvm_release_page_clean(struct page *page) kvm_set_page_accessed(page); put_page(page); } -EXPORT_SYMBOL_GPL(kvm_release_page_clean); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_release_page_clean); void kvm_release_page_dirty(struct page *page) { @@ -2829,7 +2829,7 @@ void kvm_release_page_dirty(struct page *page) kvm_set_page_dirty(page); kvm_release_page_clean(page); } -EXPORT_SYMBOL_GPL(kvm_release_page_dirty); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_release_page_dirty); static kvm_pfn_t kvm_resolve_pfn(struct kvm_follow_pfn *kfp, struct page *page, struct follow_pfnmap_args *map, bool writable) @@ -3073,7 +3073,7 @@ kvm_pfn_t __kvm_faultin_pfn(const struct kvm_memory_slot *slot, gfn_t gfn, return kvm_follow_pfn(&kfp); } -EXPORT_SYMBOL_GPL(__kvm_faultin_pfn); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_faultin_pfn); int kvm_prefetch_pages(struct kvm_memory_slot *slot, gfn_t gfn, struct page **pages, int nr_pages) @@ -3090,7 +3090,7 @@ int kvm_prefetch_pages(struct kvm_memory_slot *slot, gfn_t gfn, return get_user_pages_fast_only(addr, nr_pages, FOLL_WRITE, pages); } -EXPORT_SYMBOL_GPL(kvm_prefetch_pages); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_prefetch_pages); /* * Don't use this API unless you are absolutely, positively certain that KVM @@ -3112,7 +3112,7 @@ struct page *__gfn_to_page(struct kvm *kvm, gfn_t gfn, bool write) (void)kvm_follow_pfn(&kfp); return refcounted_page; } -EXPORT_SYMBOL_GPL(__gfn_to_page); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__gfn_to_page); int __kvm_vcpu_map(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map, bool writable) @@ -3146,7 +3146,7 @@ int __kvm_vcpu_map(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map, return map->hva ? 0 : -EFAULT; } -EXPORT_SYMBOL_GPL(__kvm_vcpu_map); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_vcpu_map); void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map) { @@ -3174,7 +3174,7 @@ void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map) map->page = NULL; map->pinned_page = NULL; } -EXPORT_SYMBOL_GPL(kvm_vcpu_unmap); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_unmap); static int next_segment(unsigned long len, int offset) { @@ -3210,7 +3210,7 @@ int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset, return __kvm_read_guest_page(slot, gfn, data, offset, len); } -EXPORT_SYMBOL_GPL(kvm_read_guest_page); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_read_guest_page); int kvm_vcpu_read_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, void *data, int offset, int len) @@ -3219,7 +3219,7 @@ int kvm_vcpu_read_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, void *data, return __kvm_read_guest_page(slot, gfn, data, offset, len); } -EXPORT_SYMBOL_GPL(kvm_vcpu_read_guest_page); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_read_guest_page); int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len) { @@ -3239,7 +3239,7 @@ int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len) } return 0; } -EXPORT_SYMBOL_GPL(kvm_read_guest); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_read_guest); int kvm_vcpu_read_guest(struct kvm_vcpu *vcpu, gpa_t gpa, void *data, unsigned long len) { @@ -3259,7 +3259,7 @@ int kvm_vcpu_read_guest(struct kvm_vcpu *vcpu, gpa_t gpa, void *data, unsigned l } return 0; } -EXPORT_SYMBOL_GPL(kvm_vcpu_read_guest); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_read_guest); static int __kvm_read_guest_atomic(struct kvm_memory_slot *slot, gfn_t gfn, void *data, int offset, unsigned long len) @@ -3290,7 +3290,7 @@ int kvm_vcpu_read_guest_atomic(struct kvm_vcpu *vcpu, gpa_t gpa, return __kvm_read_guest_atomic(slot, gfn, data, offset, len); } -EXPORT_SYMBOL_GPL(kvm_vcpu_read_guest_atomic); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_read_guest_atomic); /* Copy @len bytes from @data into guest memory at '(@gfn * PAGE_SIZE) + @offset' */ static int __kvm_write_guest_page(struct kvm *kvm, @@ -3320,7 +3320,7 @@ int kvm_write_guest_page(struct kvm *kvm, gfn_t gfn, return __kvm_write_guest_page(kvm, slot, gfn, data, offset, len); } -EXPORT_SYMBOL_GPL(kvm_write_guest_page); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_write_guest_page); int kvm_vcpu_write_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, const void *data, int offset, int len) @@ -3329,7 +3329,7 @@ int kvm_vcpu_write_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, return __kvm_write_guest_page(vcpu->kvm, slot, gfn, data, offset, len); } -EXPORT_SYMBOL_GPL(kvm_vcpu_write_guest_page); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_write_guest_page); int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data, unsigned long len) @@ -3350,7 +3350,7 @@ int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data, } return 0; } -EXPORT_SYMBOL_GPL(kvm_write_guest); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_write_guest); int kvm_vcpu_write_guest(struct kvm_vcpu *vcpu, gpa_t gpa, const void *data, unsigned long len) @@ -3371,7 +3371,7 @@ int kvm_vcpu_write_guest(struct kvm_vcpu *vcpu, gpa_t gpa, const void *data, } return 0; } -EXPORT_SYMBOL_GPL(kvm_vcpu_write_guest); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_write_guest); static int __kvm_gfn_to_hva_cache_init(struct kvm_memslots *slots, struct gfn_to_hva_cache *ghc, @@ -3420,7 +3420,7 @@ int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc, struct kvm_memslots *slots = kvm_memslots(kvm); return __kvm_gfn_to_hva_cache_init(slots, ghc, gpa, len); } -EXPORT_SYMBOL_GPL(kvm_gfn_to_hva_cache_init); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_gfn_to_hva_cache_init); int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, void *data, unsigned int offset, @@ -3451,14 +3451,14 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, return 0; } -EXPORT_SYMBOL_GPL(kvm_write_guest_offset_cached); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_write_guest_offset_cached); int kvm_write_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, void *data, unsigned long len) { return kvm_write_guest_offset_cached(kvm, ghc, data, 0, len); } -EXPORT_SYMBOL_GPL(kvm_write_guest_cached); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_write_guest_cached); int kvm_read_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, void *data, unsigned int offset, @@ -3488,14 +3488,14 @@ int kvm_read_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, return 0; } -EXPORT_SYMBOL_GPL(kvm_read_guest_offset_cached); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_read_guest_offset_cached); int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, void *data, unsigned long len) { return kvm_read_guest_offset_cached(kvm, ghc, data, 0, len); } -EXPORT_SYMBOL_GPL(kvm_read_guest_cached); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_read_guest_cached); int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len) { @@ -3515,7 +3515,7 @@ int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len) } return 0; } -EXPORT_SYMBOL_GPL(kvm_clear_guest); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_clear_guest); void mark_page_dirty_in_slot(struct kvm *kvm, const struct kvm_memory_slot *memslot, @@ -3540,7 +3540,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm, set_bit_le(rel_gfn, memslot->dirty_bitmap); } } -EXPORT_SYMBOL_GPL(mark_page_dirty_in_slot); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(mark_page_dirty_in_slot); void mark_page_dirty(struct kvm *kvm, gfn_t gfn) { @@ -3549,7 +3549,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn) memslot = gfn_to_memslot(kvm, gfn); mark_page_dirty_in_slot(kvm, memslot, gfn); } -EXPORT_SYMBOL_GPL(mark_page_dirty); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(mark_page_dirty); void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn) { @@ -3558,7 +3558,7 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn) memslot = kvm_vcpu_gfn_to_memslot(vcpu, gfn); mark_page_dirty_in_slot(vcpu->kvm, memslot, gfn); } -EXPORT_SYMBOL_GPL(kvm_vcpu_mark_page_dirty); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_mark_page_dirty); void kvm_sigset_activate(struct kvm_vcpu *vcpu) { @@ -3795,7 +3795,7 @@ out: trace_kvm_vcpu_wakeup(halt_ns, waited, vcpu_valid_wakeup(vcpu)); } -EXPORT_SYMBOL_GPL(kvm_vcpu_halt); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_halt); bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu) { @@ -3807,7 +3807,7 @@ bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu) return false; } -EXPORT_SYMBOL_GPL(kvm_vcpu_wake_up); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_wake_up); #ifndef CONFIG_S390 /* @@ -3859,7 +3859,7 @@ void __kvm_vcpu_kick(struct kvm_vcpu *vcpu, bool wait) out: put_cpu(); } -EXPORT_SYMBOL_GPL(__kvm_vcpu_kick); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_vcpu_kick); #endif /* !CONFIG_S390 */ int kvm_vcpu_yield_to(struct kvm_vcpu *target) @@ -3882,7 +3882,7 @@ int kvm_vcpu_yield_to(struct kvm_vcpu *target) return ret; } -EXPORT_SYMBOL_GPL(kvm_vcpu_yield_to); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_yield_to); /* * Helper that checks whether a VCPU is eligible for directed yield. @@ -4037,7 +4037,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me, bool yield_to_kernel_mode) /* Ensure vcpu is not eligible during next spinloop */ kvm_vcpu_set_dy_eligible(me, false); } -EXPORT_SYMBOL_GPL(kvm_vcpu_on_spin); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_on_spin); static bool kvm_page_in_dirty_ring(struct kvm *kvm, unsigned long pgoff) { @@ -5019,7 +5019,7 @@ bool kvm_are_all_memslots_empty(struct kvm *kvm) return true; } -EXPORT_SYMBOL_GPL(kvm_are_all_memslots_empty); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_are_all_memslots_empty); static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm, struct kvm_enable_cap *cap) @@ -5474,7 +5474,7 @@ bool file_is_kvm(struct file *file) { return file && file->f_op == &kvm_vm_fops; } -EXPORT_SYMBOL_GPL(file_is_kvm); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(file_is_kvm); static int kvm_dev_ioctl_create_vm(unsigned long type) { @@ -5569,10 +5569,10 @@ static struct miscdevice kvm_dev = { #ifdef CONFIG_KVM_GENERIC_HARDWARE_ENABLING bool enable_virt_at_load = true; module_param(enable_virt_at_load, bool, 0444); -EXPORT_SYMBOL_GPL(enable_virt_at_load); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_virt_at_load); __visible bool kvm_rebooting; -EXPORT_SYMBOL_GPL(kvm_rebooting); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_rebooting); static DEFINE_PER_CPU(bool, virtualization_enabled); static DEFINE_MUTEX(kvm_usage_lock); @@ -5723,7 +5723,7 @@ err_cpuhp: --kvm_usage_count; return r; } -EXPORT_SYMBOL_GPL(kvm_enable_virtualization); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_enable_virtualization); void kvm_disable_virtualization(void) { @@ -5736,7 +5736,7 @@ void kvm_disable_virtualization(void) cpuhp_remove_state(CPUHP_AP_KVM_ONLINE); kvm_arch_disable_virtualization(); } -EXPORT_SYMBOL_GPL(kvm_disable_virtualization); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_disable_virtualization); static int kvm_init_virtualization(void) { @@ -5885,7 +5885,7 @@ int kvm_io_bus_write(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr, r = __kvm_io_bus_write(vcpu, bus, &range, val); return r < 0 ? r : 0; } -EXPORT_SYMBOL_GPL(kvm_io_bus_write); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_io_bus_write); int kvm_io_bus_write_cookie(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr, int len, const void *val, long cookie) @@ -5954,7 +5954,7 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr, r = __kvm_io_bus_read(vcpu, bus, &range, val); return r < 0 ? r : 0; } -EXPORT_SYMBOL_GPL(kvm_io_bus_read); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_io_bus_read); static void __free_bus(struct rcu_head *rcu) { @@ -6078,7 +6078,7 @@ out_unlock: return iodev; } -EXPORT_SYMBOL_GPL(kvm_io_bus_get_dev); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_io_bus_get_dev); static int kvm_debugfs_open(struct inode *inode, struct file *file, int (*get)(void *, u64 *), int (*set)(void *, u64), @@ -6415,7 +6415,7 @@ struct kvm_vcpu *kvm_get_running_vcpu(void) return vcpu; } -EXPORT_SYMBOL_GPL(kvm_get_running_vcpu); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_running_vcpu); /** * kvm_get_running_vcpus - get the per-CPU array of currently running vcpus. @@ -6550,7 +6550,7 @@ err_cpu_kick_mask: kmem_cache_destroy(kvm_vcpu_cache); return r; } -EXPORT_SYMBOL_GPL(kvm_init); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_init); void kvm_exit(void) { @@ -6573,4 +6573,4 @@ void kvm_exit(void) kvm_async_pf_deinit(); kvm_irqfd_exit(); } -EXPORT_SYMBOL_GPL(kvm_exit); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_exit); From d273b52b6fad95b6b00b93250151c323c19de50d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 18 Sep 2025 17:33:01 -0700 Subject: [PATCH 2268/2711] KVM: x86: Move kvm_intr_is_single_vcpu() to lapic.c Move kvm_intr_is_single_vcpu() to lapic.c, drop its export, and make its "fast" helper local to lapic.c. kvm_intr_is_single_vcpu() is only usable if the local APIC is in-kernel, i.e. it most definitely belongs in the local APIC code. No functional change intended. Fixes: cf04ec393ed0 ("KVM: x86: Dedup AVIC vs. PI code for identifying target vCPU") Link: https://lore.kernel.org/r/20250919003303.1355064-4-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 3 --- arch/x86/kvm/irq.c | 28 ---------------------------- arch/x86/kvm/lapic.c | 33 +++++++++++++++++++++++++++++++-- arch/x86/kvm/lapic.h | 4 ++-- 4 files changed, 33 insertions(+), 35 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 0eed9b430849..48598d017d6f 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2416,9 +2416,6 @@ void __user *__x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, bool kvm_vcpu_is_reset_bsp(struct kvm_vcpu *vcpu); bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu); -bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq, - struct kvm_vcpu **dest_vcpu); - static inline bool kvm_irq_is_postable(struct kvm_lapic_irq *irq) { /* We can only post Fixed and LowPrio IRQs */ diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index a6b122f732be..153134893301 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -354,34 +354,6 @@ int kvm_set_routing_entry(struct kvm *kvm, return 0; } -bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq, - struct kvm_vcpu **dest_vcpu) -{ - int r = 0; - unsigned long i; - struct kvm_vcpu *vcpu; - - if (kvm_intr_is_single_vcpu_fast(kvm, irq, dest_vcpu)) - return true; - - kvm_for_each_vcpu(i, vcpu, kvm) { - if (!kvm_apic_present(vcpu)) - continue; - - if (!kvm_apic_match_dest(vcpu, NULL, irq->shorthand, - irq->dest_id, irq->dest_mode)) - continue; - - if (++r == 2) - return false; - - *dest_vcpu = vcpu; - } - - return r == 1; -} -EXPORT_SYMBOL_GPL(kvm_intr_is_single_vcpu); - void kvm_scan_ioapic_irq(struct kvm_vcpu *vcpu, u32 dest_id, u16 dest_mode, u8 vector, unsigned long *ioapic_handled_vectors) { diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 3b76192b24e9..b5e47c523164 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1237,8 +1237,9 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, * interrupt. * - Otherwise, use remapped mode to inject the interrupt. */ -bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, struct kvm_lapic_irq *irq, - struct kvm_vcpu **dest_vcpu) +static bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, + struct kvm_lapic_irq *irq, + struct kvm_vcpu **dest_vcpu) { struct kvm_apic_map *map; unsigned long bitmap; @@ -1265,6 +1266,34 @@ bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, struct kvm_lapic_irq *irq, return ret; } +bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq, + struct kvm_vcpu **dest_vcpu) +{ + int r = 0; + unsigned long i; + struct kvm_vcpu *vcpu; + + if (kvm_intr_is_single_vcpu_fast(kvm, irq, dest_vcpu)) + return true; + + kvm_for_each_vcpu(i, vcpu, kvm) { + if (!kvm_apic_present(vcpu)) + continue; + + if (!kvm_apic_match_dest(vcpu, NULL, irq->shorthand, + irq->dest_id, irq->dest_mode)) + continue; + + if (++r == 2) + return false; + + *dest_vcpu = vcpu; + } + + return r == 1; +} +EXPORT_SYMBOL_GPL(kvm_intr_is_single_vcpu); + int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, struct kvm_lapic_irq *irq, struct dest_map *dest_map) { diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 50123fe7f58f..282b9b7da98c 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -236,8 +236,8 @@ void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu); void kvm_bitmap_or_dest_vcpus(struct kvm *kvm, struct kvm_lapic_irq *irq, unsigned long *vcpu_bitmap); -bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, struct kvm_lapic_irq *irq, - struct kvm_vcpu **dest_vcpu); +bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq, + struct kvm_vcpu **dest_vcpu); void kvm_lapic_switch_to_sw_timer(struct kvm_vcpu *vcpu); void kvm_lapic_switch_to_hv_timer(struct kvm_vcpu *vcpu); void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu); From 6560468305da263c35ff51cde1dd74d6a228b286 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 18 Sep 2025 17:33:02 -0700 Subject: [PATCH 2269/2711] KVM: x86: Drop pointless exports of kvm_arch_xxx() hooks Drop the exporting of several kvm_arch_xxx() hooks that are only called from arch-neutral code, i.e. that are only called from kvm.ko. Link: https://lore.kernel.org/r/20250919003303.1355064-5-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5542b8d83602..a618a30423a7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -13922,14 +13922,12 @@ void kvm_arch_register_noncoherent_dma(struct kvm *kvm) if (atomic_inc_return(&kvm->arch.noncoherent_dma_count) == 1) kvm_noncoherent_dma_assignment_start_or_stop(kvm); } -EXPORT_SYMBOL_GPL(kvm_arch_register_noncoherent_dma); void kvm_arch_unregister_noncoherent_dma(struct kvm *kvm) { if (!atomic_dec_return(&kvm->arch.noncoherent_dma_count)) kvm_noncoherent_dma_assignment_start_or_stop(kvm); } -EXPORT_SYMBOL_GPL(kvm_arch_unregister_noncoherent_dma); bool kvm_arch_has_noncoherent_dma(struct kvm *kvm) { @@ -13941,7 +13939,6 @@ bool kvm_arch_no_poll(struct kvm_vcpu *vcpu) { return (vcpu->arch.msr_kvm_poll_control & 1) == 0; } -EXPORT_SYMBOL_GPL(kvm_arch_no_poll); #ifdef CONFIG_KVM_GUEST_MEMFD /* From 6b36119b94d0b2bb8cea9d512017efafd461d6ac Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 18 Sep 2025 17:33:03 -0700 Subject: [PATCH 2270/2711] KVM: x86: Export KVM-internal symbols for sub-modules only Rework almost all of KVM x86's exports to expose symbols only to KVM's vendor modules, i.e. to kvm-{amd,intel}.ko. Keep the generic exports that are guarded by CONFIG_KVM_EXTERNAL_WRITE_TRACKING=y, as they're explicitly designed/intended for external usage. Link: https://lore.kernel.org/r/20250919003303.1355064-6-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/cpuid.c | 10 +- arch/x86/kvm/hyperv.c | 4 +- arch/x86/kvm/irq.c | 6 +- arch/x86/kvm/kvm_onhyperv.c | 6 +- arch/x86/kvm/lapic.c | 40 +++---- arch/x86/kvm/mmu/mmu.c | 36 +++--- arch/x86/kvm/mmu/spte.c | 10 +- arch/x86/kvm/mmu/tdp_mmu.c | 2 +- arch/x86/kvm/pmu.c | 10 +- arch/x86/kvm/smm.c | 2 +- arch/x86/kvm/x86.c | 220 ++++++++++++++++++------------------ 11 files changed, 173 insertions(+), 173 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index d290dbc96831..52524e0ca97f 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -34,7 +34,7 @@ * aligned to sizeof(unsigned long) because it's not accessed via bitops. */ u32 kvm_cpu_caps[NR_KVM_CPU_CAPS] __read_mostly; -EXPORT_SYMBOL_GPL(kvm_cpu_caps); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_cpu_caps); struct cpuid_xstate_sizes { u32 eax; @@ -131,7 +131,7 @@ struct kvm_cpuid_entry2 *kvm_find_cpuid_entry2( return NULL; } -EXPORT_SYMBOL_GPL(kvm_find_cpuid_entry2); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_find_cpuid_entry2); static int kvm_check_cpuid(struct kvm_vcpu *vcpu) { @@ -1261,7 +1261,7 @@ void kvm_set_cpu_caps(void) kvm_cpu_cap_clear(X86_FEATURE_RDPID); } } -EXPORT_SYMBOL_GPL(kvm_set_cpu_caps); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cpu_caps); #undef F #undef SCATTERED_F @@ -2085,7 +2085,7 @@ bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, used_max_basic); return exact; } -EXPORT_SYMBOL_GPL(kvm_cpuid); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_cpuid); int kvm_emulate_cpuid(struct kvm_vcpu *vcpu) { @@ -2103,4 +2103,4 @@ int kvm_emulate_cpuid(struct kvm_vcpu *vcpu) kvm_rdx_write(vcpu, edx); return kvm_skip_emulated_instruction(vcpu); } -EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_cpuid); diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index a471900c7325..38595ecb990d 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -923,7 +923,7 @@ bool kvm_hv_assist_page_enabled(struct kvm_vcpu *vcpu) return false; return vcpu->arch.pv_eoi.msr_val & KVM_MSR_ENABLED; } -EXPORT_SYMBOL_GPL(kvm_hv_assist_page_enabled); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_hv_assist_page_enabled); int kvm_hv_get_assist_page(struct kvm_vcpu *vcpu) { @@ -935,7 +935,7 @@ int kvm_hv_get_assist_page(struct kvm_vcpu *vcpu) return kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.pv_eoi.data, &hv_vcpu->vp_assist_page, sizeof(struct hv_vp_assist_page)); } -EXPORT_SYMBOL_GPL(kvm_hv_get_assist_page); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_hv_get_assist_page); static void stimer_prepare_msg(struct kvm_vcpu_hv_stimer *stimer) { diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index 153134893301..7cc8950005b6 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -103,7 +103,7 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v) return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ } -EXPORT_SYMBOL_GPL(kvm_cpu_has_injectable_intr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_cpu_has_injectable_intr); /* * check if there is pending interrupt without @@ -119,7 +119,7 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v) return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ } -EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_cpu_has_interrupt); /* * Read pending interrupt(from non-APIC source) @@ -148,7 +148,7 @@ int kvm_cpu_get_extint(struct kvm_vcpu *v) WARN_ON_ONCE(!irqchip_split(v->kvm)); return get_userspace_extint(v); } -EXPORT_SYMBOL_GPL(kvm_cpu_get_extint); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_cpu_get_extint); /* * Read pending interrupt vector and intack. diff --git a/arch/x86/kvm/kvm_onhyperv.c b/arch/x86/kvm/kvm_onhyperv.c index ded0bd688c65..ee53e75a60cb 100644 --- a/arch/x86/kvm/kvm_onhyperv.c +++ b/arch/x86/kvm/kvm_onhyperv.c @@ -101,13 +101,13 @@ int hv_flush_remote_tlbs_range(struct kvm *kvm, gfn_t start_gfn, gfn_t nr_pages) return __hv_flush_remote_tlbs_range(kvm, &range); } -EXPORT_SYMBOL_GPL(hv_flush_remote_tlbs_range); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(hv_flush_remote_tlbs_range); int hv_flush_remote_tlbs(struct kvm *kvm) { return __hv_flush_remote_tlbs_range(kvm, NULL); } -EXPORT_SYMBOL_GPL(hv_flush_remote_tlbs); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(hv_flush_remote_tlbs); void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp) { @@ -121,4 +121,4 @@ void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp) spin_unlock(&kvm_arch->hv_root_tdp_lock); } } -EXPORT_SYMBOL_GPL(hv_track_root_tdp); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(hv_track_root_tdp); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index b5e47c523164..0ae7f913d782 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -106,7 +106,7 @@ bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector) } __read_mostly DEFINE_STATIC_KEY_FALSE(kvm_has_noapic_vcpu); -EXPORT_SYMBOL_GPL(kvm_has_noapic_vcpu); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_has_noapic_vcpu); __read_mostly DEFINE_STATIC_KEY_DEFERRED_FALSE(apic_hw_disabled, HZ); __read_mostly DEFINE_STATIC_KEY_DEFERRED_FALSE(apic_sw_disabled, HZ); @@ -646,7 +646,7 @@ bool __kvm_apic_update_irr(unsigned long *pir, void *regs, int *max_irr) return ((max_updated_irr != -1) && (max_updated_irr == *max_irr)); } -EXPORT_SYMBOL_GPL(__kvm_apic_update_irr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_apic_update_irr); bool kvm_apic_update_irr(struct kvm_vcpu *vcpu, unsigned long *pir, int *max_irr) { @@ -657,7 +657,7 @@ bool kvm_apic_update_irr(struct kvm_vcpu *vcpu, unsigned long *pir, int *max_irr apic->irr_pending = true; return irr_updated; } -EXPORT_SYMBOL_GPL(kvm_apic_update_irr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_update_irr); static inline int apic_search_irr(struct kvm_lapic *apic) { @@ -697,7 +697,7 @@ void kvm_apic_clear_irr(struct kvm_vcpu *vcpu, int vec) { apic_clear_irr(vec, vcpu->arch.apic); } -EXPORT_SYMBOL_GPL(kvm_apic_clear_irr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_clear_irr); static void *apic_vector_to_isr(int vec, struct kvm_lapic *apic) { @@ -779,7 +779,7 @@ void kvm_apic_update_hwapic_isr(struct kvm_vcpu *vcpu) kvm_x86_call(hwapic_isr_update)(vcpu, apic_find_highest_isr(apic)); } -EXPORT_SYMBOL_GPL(kvm_apic_update_hwapic_isr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_update_hwapic_isr); int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) { @@ -790,7 +790,7 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) */ return apic_find_highest_irr(vcpu->arch.apic); } -EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_lapic_find_highest_irr); static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, int vector, int level, int trig_mode, @@ -954,7 +954,7 @@ void kvm_apic_update_ppr(struct kvm_vcpu *vcpu) { apic_update_ppr(vcpu->arch.apic); } -EXPORT_SYMBOL_GPL(kvm_apic_update_ppr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_update_ppr); static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr) { @@ -1065,7 +1065,7 @@ bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, return false; } } -EXPORT_SYMBOL_GPL(kvm_apic_match_dest); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_match_dest); static int kvm_vector_to_index(u32 vector, u32 dest_vcpus, const unsigned long *bitmap, u32 bitmap_size) @@ -1292,7 +1292,7 @@ bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq, return r == 1; } -EXPORT_SYMBOL_GPL(kvm_intr_is_single_vcpu); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_intr_is_single_vcpu); int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, struct kvm_lapic_irq *irq, struct dest_map *dest_map) @@ -1569,7 +1569,7 @@ void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector) kvm_ioapic_send_eoi(apic, vector); kvm_make_request(KVM_REQ_EVENT, apic->vcpu); } -EXPORT_SYMBOL_GPL(kvm_apic_set_eoi_accelerated); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_set_eoi_accelerated); static void kvm_icr_to_lapic_irq(struct kvm_lapic *apic, u32 icr_low, u32 icr_high, struct kvm_lapic_irq *irq) @@ -1600,7 +1600,7 @@ void kvm_apic_send_ipi(struct kvm_lapic *apic, u32 icr_low, u32 icr_high) kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq, NULL); } -EXPORT_SYMBOL_GPL(kvm_apic_send_ipi); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_send_ipi); static u32 apic_get_tmcct(struct kvm_lapic *apic) { @@ -1717,7 +1717,7 @@ u64 kvm_lapic_readable_reg_mask(struct kvm_lapic *apic) return valid_reg_mask; } -EXPORT_SYMBOL_GPL(kvm_lapic_readable_reg_mask); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_lapic_readable_reg_mask); static int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len, void *data) @@ -1958,7 +1958,7 @@ void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu) lapic_timer_int_injected(vcpu)) __kvm_wait_lapic_expire(vcpu); } -EXPORT_SYMBOL_GPL(kvm_wait_lapic_expire); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_wait_lapic_expire); static void kvm_apic_inject_pending_timer_irqs(struct kvm_lapic *apic) { @@ -2272,7 +2272,7 @@ void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu) out: preempt_enable(); } -EXPORT_SYMBOL_GPL(kvm_lapic_expired_hv_timer); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_lapic_expired_hv_timer); void kvm_lapic_switch_to_hv_timer(struct kvm_vcpu *vcpu) { @@ -2525,7 +2525,7 @@ void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu) { kvm_lapic_reg_write(vcpu->arch.apic, APIC_EOI, 0); } -EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_lapic_set_eoi); #define X2APIC_ICR_RESERVED_BITS (GENMASK_ULL(31, 20) | GENMASK_ULL(17, 16) | BIT(13)) @@ -2608,7 +2608,7 @@ void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset) else kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset)); } -EXPORT_SYMBOL_GPL(kvm_apic_write_nodecode); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_write_nodecode); void kvm_free_lapic(struct kvm_vcpu *vcpu) { @@ -2746,7 +2746,7 @@ int kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value, bool host_initiated) kvm_recalculate_apic_map(vcpu->kvm); return 0; } -EXPORT_SYMBOL_GPL(kvm_apic_set_base); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_set_base); void kvm_apic_update_apicv(struct kvm_vcpu *vcpu) { @@ -2794,7 +2794,7 @@ int kvm_alloc_apic_access_page(struct kvm *kvm) return 0; } -EXPORT_SYMBOL_GPL(kvm_alloc_apic_access_page); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_alloc_apic_access_page); void kvm_inhibit_apic_access_page(struct kvm_vcpu *vcpu) { @@ -3058,7 +3058,7 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) __apic_update_ppr(apic, &ppr); return apic_has_interrupt_for_ppr(apic, ppr); } -EXPORT_SYMBOL_GPL(kvm_apic_has_interrupt); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_has_interrupt); int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu) { @@ -3117,7 +3117,7 @@ void kvm_apic_ack_interrupt(struct kvm_vcpu *vcpu, int vector) } } -EXPORT_SYMBOL_GPL(kvm_apic_ack_interrupt); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_ack_interrupt); static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s, bool set) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 55335dbd70ce..667d66cf76d5 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -110,7 +110,7 @@ static bool __ro_after_init tdp_mmu_allowed; #ifdef CONFIG_X86_64 bool __read_mostly tdp_mmu_enabled = true; module_param_named(tdp_mmu, tdp_mmu_enabled, bool, 0444); -EXPORT_SYMBOL_GPL(tdp_mmu_enabled); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(tdp_mmu_enabled); #endif static int max_huge_page_level __read_mostly; @@ -3865,7 +3865,7 @@ void kvm_mmu_free_roots(struct kvm *kvm, struct kvm_mmu *mmu, write_unlock(&kvm->mmu_lock); } } -EXPORT_SYMBOL_GPL(kvm_mmu_free_roots); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_free_roots); void kvm_mmu_free_guest_mode_roots(struct kvm *kvm, struct kvm_mmu *mmu) { @@ -3892,7 +3892,7 @@ void kvm_mmu_free_guest_mode_roots(struct kvm *kvm, struct kvm_mmu *mmu) kvm_mmu_free_roots(kvm, mmu, roots_to_free); } -EXPORT_SYMBOL_GPL(kvm_mmu_free_guest_mode_roots); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_free_guest_mode_roots); static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, int quadrant, u8 level) @@ -4876,7 +4876,7 @@ int kvm_handle_page_fault(struct kvm_vcpu *vcpu, u64 error_code, return r; } -EXPORT_SYMBOL_GPL(kvm_handle_page_fault); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_handle_page_fault); #ifdef CONFIG_X86_64 static int kvm_tdp_mmu_page_fault(struct kvm_vcpu *vcpu, @@ -4966,7 +4966,7 @@ int kvm_tdp_map_page(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code, u8 *level return -EIO; } } -EXPORT_SYMBOL_GPL(kvm_tdp_map_page); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_tdp_map_page); long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, struct kvm_pre_fault_memory *range) @@ -5162,7 +5162,7 @@ void kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd) __clear_sp_write_flooding_count(sp); } } -EXPORT_SYMBOL_GPL(kvm_mmu_new_pgd); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_new_pgd); static bool sync_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn, unsigned int access) @@ -5808,7 +5808,7 @@ void kvm_init_shadow_npt_mmu(struct kvm_vcpu *vcpu, unsigned long cr0, shadow_mmu_init_context(vcpu, context, cpu_role, root_role); kvm_mmu_new_pgd(vcpu, nested_cr3); } -EXPORT_SYMBOL_GPL(kvm_init_shadow_npt_mmu); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_init_shadow_npt_mmu); static union kvm_cpu_role kvm_calc_shadow_ept_root_page_role(struct kvm_vcpu *vcpu, bool accessed_dirty, @@ -5862,7 +5862,7 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly, kvm_mmu_new_pgd(vcpu, new_eptp); } -EXPORT_SYMBOL_GPL(kvm_init_shadow_ept_mmu); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_init_shadow_ept_mmu); static void init_kvm_softmmu(struct kvm_vcpu *vcpu, union kvm_cpu_role cpu_role) @@ -5927,7 +5927,7 @@ void kvm_init_mmu(struct kvm_vcpu *vcpu) else init_kvm_softmmu(vcpu, cpu_role); } -EXPORT_SYMBOL_GPL(kvm_init_mmu); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_init_mmu); void kvm_mmu_after_set_cpuid(struct kvm_vcpu *vcpu) { @@ -5963,7 +5963,7 @@ void kvm_mmu_reset_context(struct kvm_vcpu *vcpu) kvm_mmu_unload(vcpu); kvm_init_mmu(vcpu); } -EXPORT_SYMBOL_GPL(kvm_mmu_reset_context); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_reset_context); int kvm_mmu_load(struct kvm_vcpu *vcpu) { @@ -5997,7 +5997,7 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu) out: return r; } -EXPORT_SYMBOL_GPL(kvm_mmu_load); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_load); void kvm_mmu_unload(struct kvm_vcpu *vcpu) { @@ -6059,7 +6059,7 @@ void kvm_mmu_free_obsolete_roots(struct kvm_vcpu *vcpu) __kvm_mmu_free_obsolete_roots(vcpu->kvm, &vcpu->arch.root_mmu); __kvm_mmu_free_obsolete_roots(vcpu->kvm, &vcpu->arch.guest_mmu); } -EXPORT_SYMBOL_GPL(kvm_mmu_free_obsolete_roots); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_free_obsolete_roots); static u64 mmu_pte_write_fetch_gpte(struct kvm_vcpu *vcpu, gpa_t *gpa, int *bytes) @@ -6385,7 +6385,7 @@ emulate: return x86_emulate_instruction(vcpu, cr2_or_gpa, emulation_type, insn, insn_len); } -EXPORT_SYMBOL_GPL(kvm_mmu_page_fault); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_page_fault); void kvm_mmu_print_sptes(struct kvm_vcpu *vcpu, gpa_t gpa, const char *msg) { @@ -6401,7 +6401,7 @@ void kvm_mmu_print_sptes(struct kvm_vcpu *vcpu, gpa_t gpa, const char *msg) pr_cont(", spte[%d] = 0x%llx", level, sptes[level]); pr_cont("\n"); } -EXPORT_SYMBOL_GPL(kvm_mmu_print_sptes); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_print_sptes); static void __kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, u64 addr, hpa_t root_hpa) @@ -6467,7 +6467,7 @@ void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, __kvm_mmu_invalidate_addr(vcpu, mmu, addr, mmu->prev_roots[i].hpa); } } -EXPORT_SYMBOL_GPL(kvm_mmu_invalidate_addr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_invalidate_addr); void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva) { @@ -6484,7 +6484,7 @@ void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva) kvm_mmu_invalidate_addr(vcpu, vcpu->arch.walk_mmu, gva, KVM_MMU_ROOTS_ALL); ++vcpu->stat.invlpg; } -EXPORT_SYMBOL_GPL(kvm_mmu_invlpg); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_invlpg); void kvm_mmu_invpcid_gva(struct kvm_vcpu *vcpu, gva_t gva, unsigned long pcid) @@ -6537,7 +6537,7 @@ void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level, else max_huge_page_level = PG_LEVEL_2M; } -EXPORT_SYMBOL_GPL(kvm_configure_mmu); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_configure_mmu); static void free_mmu_pages(struct kvm_mmu *mmu) { @@ -7204,7 +7204,7 @@ restart: return need_tlb_flush; } -EXPORT_SYMBOL_GPL(kvm_zap_gfn_range); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_zap_gfn_range); static void kvm_rmap_zap_collapsible_sptes(struct kvm *kvm, const struct kvm_memory_slot *slot) diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index df31039b5d63..37647afde7d3 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -22,7 +22,7 @@ bool __read_mostly enable_mmio_caching = true; static bool __ro_after_init allow_mmio_caching; module_param_named(mmio_caching, enable_mmio_caching, bool, 0444); -EXPORT_SYMBOL_GPL(enable_mmio_caching); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_mmio_caching); bool __read_mostly kvm_ad_enabled; @@ -470,13 +470,13 @@ void kvm_mmu_set_mmio_spte_mask(u64 mmio_value, u64 mmio_mask, u64 access_mask) shadow_mmio_mask = mmio_mask; shadow_mmio_access_mask = access_mask; } -EXPORT_SYMBOL_GPL(kvm_mmu_set_mmio_spte_mask); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_set_mmio_spte_mask); void kvm_mmu_set_mmio_spte_value(struct kvm *kvm, u64 mmio_value) { kvm->arch.shadow_mmio_value = mmio_value; } -EXPORT_SYMBOL_GPL(kvm_mmu_set_mmio_spte_value); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_set_mmio_spte_value); void kvm_mmu_set_me_spte_mask(u64 me_value, u64 me_mask) { @@ -487,7 +487,7 @@ void kvm_mmu_set_me_spte_mask(u64 me_value, u64 me_mask) shadow_me_value = me_value; shadow_me_mask = me_mask; } -EXPORT_SYMBOL_GPL(kvm_mmu_set_me_spte_mask); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_set_me_spte_mask); void kvm_mmu_set_ept_masks(bool has_ad_bits, bool has_exec_only) { @@ -513,7 +513,7 @@ void kvm_mmu_set_ept_masks(bool has_ad_bits, bool has_exec_only) kvm_mmu_set_mmio_spte_mask(VMX_EPT_MISCONFIG_WX_VALUE, VMX_EPT_RWX_MASK | VMX_EPT_SUPPRESS_VE_BIT, 0); } -EXPORT_SYMBOL_GPL(kvm_mmu_set_ept_masks); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_set_ept_masks); void kvm_mmu_reset_all_pte_masks(void) { diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 7059ac9d58e2..c5734ca5c17d 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -1982,7 +1982,7 @@ bool kvm_tdp_mmu_gpa_is_mapped(struct kvm_vcpu *vcpu, u64 gpa) spte = sptes[leaf]; return is_shadow_present_pte(spte) && is_last_spte(spte, leaf); } -EXPORT_SYMBOL_GPL(kvm_tdp_mmu_gpa_is_mapped); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_tdp_mmu_gpa_is_mapped); /* * Returns the last level spte pointer of the shadow page walk for the given diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index b7dc5bd981ba..40ac4cb44ed2 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -31,7 +31,7 @@ static struct x86_pmu_capability __read_mostly kvm_host_pmu; /* KVM's PMU capabilities, i.e. the intersection of KVM and hardware support. */ struct x86_pmu_capability __read_mostly kvm_pmu_cap; -EXPORT_SYMBOL_GPL(kvm_pmu_cap); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_pmu_cap); struct kvm_pmu_emulated_event_selectors { u64 INSTRUCTIONS_RETIRED; @@ -373,7 +373,7 @@ void pmc_write_counter(struct kvm_pmc *pmc, u64 val) pmc->counter &= pmc_bitmask(pmc); pmc_update_sample_period(pmc); } -EXPORT_SYMBOL_GPL(pmc_write_counter); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(pmc_write_counter); static int filter_cmp(const void *pa, const void *pb, u64 mask) { @@ -581,7 +581,7 @@ void kvm_pmu_recalc_pmc_emulation(struct kvm_pmu *pmu, struct kvm_pmc *pmc) if (pmc_is_event_match(pmc, kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED)) bitmap_set(pmu->pmc_counting_branches, pmc->idx, 1); } -EXPORT_SYMBOL_GPL(kvm_pmu_recalc_pmc_emulation); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_pmu_recalc_pmc_emulation); void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) { @@ -996,13 +996,13 @@ void kvm_pmu_instruction_retired(struct kvm_vcpu *vcpu) { kvm_pmu_trigger_event(vcpu, vcpu_to_pmu(vcpu)->pmc_counting_instructions); } -EXPORT_SYMBOL_GPL(kvm_pmu_instruction_retired); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_pmu_instruction_retired); void kvm_pmu_branch_retired(struct kvm_vcpu *vcpu) { kvm_pmu_trigger_event(vcpu, vcpu_to_pmu(vcpu)->pmc_counting_branches); } -EXPORT_SYMBOL_GPL(kvm_pmu_branch_retired); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_pmu_branch_retired); static bool is_masked_filter_valid(const struct kvm_x86_pmu_event_filter *filter) { diff --git a/arch/x86/kvm/smm.c b/arch/x86/kvm/smm.c index b0b14ba37f9a..f623c5986119 100644 --- a/arch/x86/kvm/smm.c +++ b/arch/x86/kvm/smm.c @@ -131,7 +131,7 @@ void kvm_smm_changed(struct kvm_vcpu *vcpu, bool entering_smm) kvm_mmu_reset_context(vcpu); } -EXPORT_SYMBOL_GPL(kvm_smm_changed); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_smm_changed); void process_smi(struct kvm_vcpu *vcpu) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a618a30423a7..4b8138bd4857 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -97,10 +97,10 @@ * vendor module being reloaded with different module parameters. */ struct kvm_caps kvm_caps __read_mostly; -EXPORT_SYMBOL_GPL(kvm_caps); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_caps); struct kvm_host_values kvm_host __read_mostly; -EXPORT_SYMBOL_GPL(kvm_host); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_host); #define ERR_PTR_USR(e) ((void __user *)ERR_PTR(e)) @@ -155,7 +155,7 @@ module_param(ignore_msrs, bool, 0644); bool __read_mostly report_ignored_msrs = true; module_param(report_ignored_msrs, bool, 0644); -EXPORT_SYMBOL_GPL(report_ignored_msrs); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(report_ignored_msrs); unsigned int min_timer_period_us = 200; module_param(min_timer_period_us, uint, 0644); @@ -169,7 +169,7 @@ module_param(tsc_tolerance_ppm, uint, 0644); bool __read_mostly enable_vmware_backdoor = false; module_param(enable_vmware_backdoor, bool, 0444); -EXPORT_SYMBOL_GPL(enable_vmware_backdoor); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_vmware_backdoor); /* * Flags to manipulate forced emulation behavior (any non-zero value will @@ -184,7 +184,7 @@ module_param(pi_inject_timer, bint, 0644); /* Enable/disable PMU virtualization */ bool __read_mostly enable_pmu = true; -EXPORT_SYMBOL_GPL(enable_pmu); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_pmu); module_param(enable_pmu, bool, 0444); bool __read_mostly eager_page_split = true; @@ -211,7 +211,7 @@ struct kvm_user_return_msrs { }; u32 __read_mostly kvm_nr_uret_msrs; -EXPORT_SYMBOL_GPL(kvm_nr_uret_msrs); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_nr_uret_msrs); static u32 __read_mostly kvm_uret_msrs_list[KVM_MAX_NR_USER_RETURN_MSRS]; static struct kvm_user_return_msrs __percpu *user_return_msrs; @@ -230,16 +230,16 @@ static struct kvm_user_return_msrs __percpu *user_return_msrs; #define KVM_SUPPORTED_XSS (XFEATURE_MASK_CET_ALL) bool __read_mostly allow_smaller_maxphyaddr = 0; -EXPORT_SYMBOL_GPL(allow_smaller_maxphyaddr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(allow_smaller_maxphyaddr); bool __read_mostly enable_apicv = true; -EXPORT_SYMBOL_GPL(enable_apicv); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_apicv); bool __read_mostly enable_ipiv = true; -EXPORT_SYMBOL_GPL(enable_ipiv); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_ipiv); bool __read_mostly enable_device_posted_irqs = true; -EXPORT_SYMBOL_GPL(enable_device_posted_irqs); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_device_posted_irqs); const struct _kvm_stats_desc kvm_vm_stats_desc[] = { KVM_GENERIC_VM_STATS(), @@ -628,7 +628,7 @@ int kvm_add_user_return_msr(u32 msr) kvm_uret_msrs_list[kvm_nr_uret_msrs] = msr; return kvm_nr_uret_msrs++; } -EXPORT_SYMBOL_GPL(kvm_add_user_return_msr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_add_user_return_msr); int kvm_find_user_return_msr(u32 msr) { @@ -640,7 +640,7 @@ int kvm_find_user_return_msr(u32 msr) } return -1; } -EXPORT_SYMBOL_GPL(kvm_find_user_return_msr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_find_user_return_msr); static void kvm_user_return_msr_cpu_online(void) { @@ -680,7 +680,7 @@ int kvm_set_user_return_msr(unsigned slot, u64 value, u64 mask) kvm_user_return_register_notifier(msrs); return 0; } -EXPORT_SYMBOL_GPL(kvm_set_user_return_msr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_user_return_msr); void kvm_user_return_msr_update_cache(unsigned int slot, u64 value) { @@ -689,13 +689,13 @@ void kvm_user_return_msr_update_cache(unsigned int slot, u64 value) msrs->values[slot].curr = value; kvm_user_return_register_notifier(msrs); } -EXPORT_SYMBOL_GPL(kvm_user_return_msr_update_cache); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_user_return_msr_update_cache); u64 kvm_get_user_return_msr(unsigned int slot) { return this_cpu_ptr(user_return_msrs)->values[slot].curr; } -EXPORT_SYMBOL_GPL(kvm_get_user_return_msr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_user_return_msr); static void drop_user_return_notifiers(void) { @@ -717,7 +717,7 @@ noinstr void kvm_spurious_fault(void) /* Fault while not rebooting. We want the trace. */ BUG_ON(!kvm_rebooting); } -EXPORT_SYMBOL_GPL(kvm_spurious_fault); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_spurious_fault); #define EXCPT_BENIGN 0 #define EXCPT_CONTRIBUTORY 1 @@ -822,7 +822,7 @@ void kvm_deliver_exception_payload(struct kvm_vcpu *vcpu, ex->has_payload = false; ex->payload = 0; } -EXPORT_SYMBOL_GPL(kvm_deliver_exception_payload); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_deliver_exception_payload); static void kvm_queue_exception_vmexit(struct kvm_vcpu *vcpu, unsigned int vector, bool has_error_code, u32 error_code, @@ -906,7 +906,7 @@ void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr) { kvm_multiple_exception(vcpu, nr, false, 0, false, 0); } -EXPORT_SYMBOL_GPL(kvm_queue_exception); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_queue_exception); void kvm_queue_exception_p(struct kvm_vcpu *vcpu, unsigned nr, @@ -914,7 +914,7 @@ void kvm_queue_exception_p(struct kvm_vcpu *vcpu, unsigned nr, { kvm_multiple_exception(vcpu, nr, false, 0, true, payload); } -EXPORT_SYMBOL_GPL(kvm_queue_exception_p); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_queue_exception_p); static void kvm_queue_exception_e_p(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code, unsigned long payload) @@ -949,7 +949,7 @@ void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned int nr, vcpu->arch.exception.has_payload = false; vcpu->arch.exception.payload = 0; } -EXPORT_SYMBOL_GPL(kvm_requeue_exception); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_requeue_exception); int kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err) { @@ -960,7 +960,7 @@ int kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err) return 1; } -EXPORT_SYMBOL_GPL(kvm_complete_insn_gp); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_complete_insn_gp); static int complete_emulated_insn_gp(struct kvm_vcpu *vcpu, int err) { @@ -1010,7 +1010,7 @@ void kvm_inject_emulated_page_fault(struct kvm_vcpu *vcpu, fault_mmu->inject_page_fault(vcpu, fault); } -EXPORT_SYMBOL_GPL(kvm_inject_emulated_page_fault); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_inject_emulated_page_fault); void kvm_inject_nmi(struct kvm_vcpu *vcpu) { @@ -1022,7 +1022,7 @@ void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code) { kvm_multiple_exception(vcpu, nr, true, error_code, false, 0); } -EXPORT_SYMBOL_GPL(kvm_queue_exception_e); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_queue_exception_e); /* * Checks if cpl <= required_cpl; if true, return true. Otherwise queue @@ -1044,7 +1044,7 @@ bool kvm_require_dr(struct kvm_vcpu *vcpu, int dr) kvm_queue_exception(vcpu, UD_VECTOR); return false; } -EXPORT_SYMBOL_GPL(kvm_require_dr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_require_dr); static inline u64 pdptr_rsvd_bits(struct kvm_vcpu *vcpu) { @@ -1099,7 +1099,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) return 1; } -EXPORT_SYMBOL_GPL(load_pdptrs); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(load_pdptrs); static bool kvm_is_valid_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { @@ -1152,7 +1152,7 @@ void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned lon if ((cr0 ^ old_cr0) & KVM_MMU_CR0_ROLE_BITS) kvm_mmu_reset_context(vcpu); } -EXPORT_SYMBOL_GPL(kvm_post_set_cr0); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_post_set_cr0); int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) { @@ -1196,13 +1196,13 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) return 0; } -EXPORT_SYMBOL_GPL(kvm_set_cr0); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr0); void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw) { (void)kvm_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~0x0eul) | (msw & 0x0f)); } -EXPORT_SYMBOL_GPL(kvm_lmsw); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_lmsw); void kvm_load_guest_xsave_state(struct kvm_vcpu *vcpu) { @@ -1225,7 +1225,7 @@ void kvm_load_guest_xsave_state(struct kvm_vcpu *vcpu) kvm_is_cr4_bit_set(vcpu, X86_CR4_PKE))) wrpkru(vcpu->arch.pkru); } -EXPORT_SYMBOL_GPL(kvm_load_guest_xsave_state); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_load_guest_xsave_state); void kvm_load_host_xsave_state(struct kvm_vcpu *vcpu) { @@ -1251,7 +1251,7 @@ void kvm_load_host_xsave_state(struct kvm_vcpu *vcpu) } } -EXPORT_SYMBOL_GPL(kvm_load_host_xsave_state); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_load_host_xsave_state); #ifdef CONFIG_X86_64 static inline u64 kvm_guest_supported_xfd(struct kvm_vcpu *vcpu) @@ -1304,7 +1304,7 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr) vcpu->arch.cpuid_dynamic_bits_dirty = true; return 0; } -EXPORT_SYMBOL_GPL(__kvm_set_xcr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_set_xcr); int kvm_emulate_xsetbv(struct kvm_vcpu *vcpu) { @@ -1317,7 +1317,7 @@ int kvm_emulate_xsetbv(struct kvm_vcpu *vcpu) return kvm_skip_emulated_instruction(vcpu); } -EXPORT_SYMBOL_GPL(kvm_emulate_xsetbv); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_xsetbv); static bool kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { @@ -1365,7 +1365,7 @@ void kvm_post_set_cr4(struct kvm_vcpu *vcpu, unsigned long old_cr4, unsigned lon kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu); } -EXPORT_SYMBOL_GPL(kvm_post_set_cr4); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_post_set_cr4); int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { @@ -1399,7 +1399,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) return 0; } -EXPORT_SYMBOL_GPL(kvm_set_cr4); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr4); static void kvm_invalidate_pcid(struct kvm_vcpu *vcpu, unsigned long pcid) { @@ -1491,7 +1491,7 @@ handle_tlb_flush: return 0; } -EXPORT_SYMBOL_GPL(kvm_set_cr3); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr3); int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) { @@ -1503,7 +1503,7 @@ int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) vcpu->arch.cr8 = cr8; return 0; } -EXPORT_SYMBOL_GPL(kvm_set_cr8); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr8); unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu) { @@ -1512,7 +1512,7 @@ unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu) else return vcpu->arch.cr8; } -EXPORT_SYMBOL_GPL(kvm_get_cr8); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_cr8); static void kvm_update_dr0123(struct kvm_vcpu *vcpu) { @@ -1537,7 +1537,7 @@ void kvm_update_dr7(struct kvm_vcpu *vcpu) if (dr7 & DR7_BP_EN_MASK) vcpu->arch.switch_db_regs |= KVM_DEBUGREG_BP_ENABLED; } -EXPORT_SYMBOL_GPL(kvm_update_dr7); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_update_dr7); static u64 kvm_dr6_fixed(struct kvm_vcpu *vcpu) { @@ -1578,7 +1578,7 @@ int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val) return 0; } -EXPORT_SYMBOL_GPL(kvm_set_dr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_dr); unsigned long kvm_get_dr(struct kvm_vcpu *vcpu, int dr) { @@ -1595,7 +1595,7 @@ unsigned long kvm_get_dr(struct kvm_vcpu *vcpu, int dr) return vcpu->arch.dr7; } } -EXPORT_SYMBOL_GPL(kvm_get_dr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_dr); int kvm_emulate_rdpmc(struct kvm_vcpu *vcpu) { @@ -1611,7 +1611,7 @@ int kvm_emulate_rdpmc(struct kvm_vcpu *vcpu) kvm_rdx_write(vcpu, data >> 32); return kvm_skip_emulated_instruction(vcpu); } -EXPORT_SYMBOL_GPL(kvm_emulate_rdpmc); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_rdpmc); /* * Some IA32_ARCH_CAPABILITIES bits have dependencies on MSRs that KVM @@ -1750,7 +1750,7 @@ bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) return __kvm_valid_efer(vcpu, efer); } -EXPORT_SYMBOL_GPL(kvm_valid_efer); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_valid_efer); static int set_efer(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { @@ -1793,7 +1793,7 @@ void kvm_enable_efer_bits(u64 mask) { efer_reserved_bits &= ~mask; } -EXPORT_SYMBOL_GPL(kvm_enable_efer_bits); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_enable_efer_bits); bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type) { @@ -1836,7 +1836,7 @@ out: return allowed; } -EXPORT_SYMBOL_GPL(kvm_msr_allowed); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_msr_allowed); /* * Write @data into the MSR specified by @index. Select MSR specific fault @@ -2025,13 +2025,13 @@ int __kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data) { return kvm_get_msr_ignored_check(vcpu, index, data, false); } -EXPORT_SYMBOL_GPL(__kvm_emulate_msr_read); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_emulate_msr_read); int __kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data) { return kvm_set_msr_ignored_check(vcpu, index, data, false); } -EXPORT_SYMBOL_GPL(__kvm_emulate_msr_write); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_emulate_msr_write); int kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data) { @@ -2040,7 +2040,7 @@ int kvm_emulate_msr_read(struct kvm_vcpu *vcpu, u32 index, u64 *data) return __kvm_emulate_msr_read(vcpu, index, data); } -EXPORT_SYMBOL_GPL(kvm_emulate_msr_read); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_msr_read); int kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data) { @@ -2049,7 +2049,7 @@ int kvm_emulate_msr_write(struct kvm_vcpu *vcpu, u32 index, u64 data) return __kvm_emulate_msr_write(vcpu, index, data); } -EXPORT_SYMBOL_GPL(kvm_emulate_msr_write); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_msr_write); static void complete_userspace_rdmsr(struct kvm_vcpu *vcpu) @@ -2158,7 +2158,7 @@ int kvm_emulate_rdmsr(struct kvm_vcpu *vcpu) return __kvm_emulate_rdmsr(vcpu, kvm_rcx_read(vcpu), -1, complete_fast_rdmsr); } -EXPORT_SYMBOL_GPL(kvm_emulate_rdmsr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_rdmsr); int kvm_emulate_rdmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg) { @@ -2166,7 +2166,7 @@ int kvm_emulate_rdmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg) return __kvm_emulate_rdmsr(vcpu, msr, reg, complete_fast_rdmsr_imm); } -EXPORT_SYMBOL_GPL(kvm_emulate_rdmsr_imm); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_rdmsr_imm); static int __kvm_emulate_wrmsr(struct kvm_vcpu *vcpu, u32 msr, u64 data) { @@ -2194,13 +2194,13 @@ int kvm_emulate_wrmsr(struct kvm_vcpu *vcpu) return __kvm_emulate_wrmsr(vcpu, kvm_rcx_read(vcpu), kvm_read_edx_eax(vcpu)); } -EXPORT_SYMBOL_GPL(kvm_emulate_wrmsr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_wrmsr); int kvm_emulate_wrmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg) { return __kvm_emulate_wrmsr(vcpu, msr, kvm_register_read(vcpu, reg)); } -EXPORT_SYMBOL_GPL(kvm_emulate_wrmsr_imm); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_wrmsr_imm); int kvm_emulate_as_nop(struct kvm_vcpu *vcpu) { @@ -2212,7 +2212,7 @@ int kvm_emulate_invd(struct kvm_vcpu *vcpu) /* Treat an INVD instruction as a NOP and just skip it. */ return kvm_emulate_as_nop(vcpu); } -EXPORT_SYMBOL_GPL(kvm_emulate_invd); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_invd); fastpath_t handle_fastpath_invd(struct kvm_vcpu *vcpu) { @@ -2221,14 +2221,14 @@ fastpath_t handle_fastpath_invd(struct kvm_vcpu *vcpu) return EXIT_FASTPATH_REENTER_GUEST; } -EXPORT_SYMBOL_GPL(handle_fastpath_invd); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(handle_fastpath_invd); int kvm_handle_invalid_op(struct kvm_vcpu *vcpu) { kvm_queue_exception(vcpu, UD_VECTOR); return 1; } -EXPORT_SYMBOL_GPL(kvm_handle_invalid_op); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_handle_invalid_op); static int kvm_emulate_monitor_mwait(struct kvm_vcpu *vcpu, const char *insn) @@ -2254,13 +2254,13 @@ int kvm_emulate_mwait(struct kvm_vcpu *vcpu) { return kvm_emulate_monitor_mwait(vcpu, "MWAIT"); } -EXPORT_SYMBOL_GPL(kvm_emulate_mwait); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_mwait); int kvm_emulate_monitor(struct kvm_vcpu *vcpu) { return kvm_emulate_monitor_mwait(vcpu, "MONITOR"); } -EXPORT_SYMBOL_GPL(kvm_emulate_monitor); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_monitor); static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu) { @@ -2298,13 +2298,13 @@ fastpath_t handle_fastpath_wrmsr(struct kvm_vcpu *vcpu) return __handle_fastpath_wrmsr(vcpu, kvm_rcx_read(vcpu), kvm_read_edx_eax(vcpu)); } -EXPORT_SYMBOL_GPL(handle_fastpath_wrmsr); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(handle_fastpath_wrmsr); fastpath_t handle_fastpath_wrmsr_imm(struct kvm_vcpu *vcpu, u32 msr, int reg) { return __handle_fastpath_wrmsr(vcpu, msr, kvm_register_read(vcpu, reg)); } -EXPORT_SYMBOL_GPL(handle_fastpath_wrmsr_imm); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(handle_fastpath_wrmsr_imm); /* * Adapt set_msr() to msr_io()'s calling convention @@ -2670,7 +2670,7 @@ u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc) return vcpu->arch.l1_tsc_offset + kvm_scale_tsc(host_tsc, vcpu->arch.l1_tsc_scaling_ratio); } -EXPORT_SYMBOL_GPL(kvm_read_l1_tsc); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_read_l1_tsc); u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier) { @@ -2685,7 +2685,7 @@ u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier) nested_offset += l2_offset; return nested_offset; } -EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_offset); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_calc_nested_tsc_offset); u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier) { @@ -2695,7 +2695,7 @@ u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier) return l1_multiplier; } -EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_multiplier); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_calc_nested_tsc_multiplier); static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 l1_offset) { @@ -3773,7 +3773,7 @@ void kvm_service_local_tlb_flush_requests(struct kvm_vcpu *vcpu) if (kvm_check_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu)) kvm_vcpu_flush_tlb_guest(vcpu); } -EXPORT_SYMBOL_GPL(kvm_service_local_tlb_flush_requests); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_service_local_tlb_flush_requests); static void record_steal_time(struct kvm_vcpu *vcpu) { @@ -4327,7 +4327,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) } return 0; } -EXPORT_SYMBOL_GPL(kvm_set_msr_common); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_msr_common); static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) { @@ -4680,7 +4680,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) } return 0; } -EXPORT_SYMBOL_GPL(kvm_get_msr_common); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_msr_common); /* * Read or write a bunch of msrs. All parameters are kernel addresses. @@ -7836,7 +7836,7 @@ gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u64 access = (kvm_x86_call(get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; return mmu->gva_to_gpa(vcpu, mmu, gva, access, exception); } -EXPORT_SYMBOL_GPL(kvm_mmu_gva_to_gpa_read); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_gva_to_gpa_read); gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, struct x86_exception *exception) @@ -7847,7 +7847,7 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, access |= PFERR_WRITE_MASK; return mmu->gva_to_gpa(vcpu, mmu, gva, access, exception); } -EXPORT_SYMBOL_GPL(kvm_mmu_gva_to_gpa_write); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_gva_to_gpa_write); /* uses this to access any guest's mapped memory without checking CPL */ gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, @@ -7933,7 +7933,7 @@ int kvm_read_guest_virt(struct kvm_vcpu *vcpu, return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, exception); } -EXPORT_SYMBOL_GPL(kvm_read_guest_virt); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_read_guest_virt); static int emulator_read_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val, unsigned int bytes, @@ -8005,7 +8005,7 @@ int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val, return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, PFERR_WRITE_MASK, exception); } -EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_write_guest_virt_system); static int kvm_check_emulate_insn(struct kvm_vcpu *vcpu, int emul_type, void *insn, int insn_len) @@ -8039,7 +8039,7 @@ int handle_ud(struct kvm_vcpu *vcpu) return kvm_emulate_instruction(vcpu, emul_type); } -EXPORT_SYMBOL_GPL(handle_ud); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(handle_ud); static int vcpu_is_mmio_gpa(struct kvm_vcpu *vcpu, unsigned long gva, gpa_t gpa, bool write) @@ -8518,7 +8518,7 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu) kvm_emulate_wbinvd_noskip(vcpu); return kvm_skip_emulated_instruction(vcpu); } -EXPORT_SYMBOL_GPL(kvm_emulate_wbinvd); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_wbinvd); @@ -9016,7 +9016,7 @@ void kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip) kvm_set_rflags(vcpu, ctxt->eflags); } } -EXPORT_SYMBOL_GPL(kvm_inject_realmode_interrupt); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_inject_realmode_interrupt); static void prepare_emulation_failure_exit(struct kvm_vcpu *vcpu, u64 *data, u8 ndata, u8 *insn_bytes, u8 insn_size) @@ -9081,13 +9081,13 @@ void __kvm_prepare_emulation_failure_exit(struct kvm_vcpu *vcpu, u64 *data, { prepare_emulation_failure_exit(vcpu, data, ndata, NULL, 0); } -EXPORT_SYMBOL_GPL(__kvm_prepare_emulation_failure_exit); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_prepare_emulation_failure_exit); void kvm_prepare_emulation_failure_exit(struct kvm_vcpu *vcpu) { __kvm_prepare_emulation_failure_exit(vcpu, NULL, 0); } -EXPORT_SYMBOL_GPL(kvm_prepare_emulation_failure_exit); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_prepare_emulation_failure_exit); void kvm_prepare_event_vectoring_exit(struct kvm_vcpu *vcpu, gpa_t gpa) { @@ -9109,7 +9109,7 @@ void kvm_prepare_event_vectoring_exit(struct kvm_vcpu *vcpu, gpa_t gpa) run->internal.suberror = KVM_INTERNAL_ERROR_DELIVERY_EV; run->internal.ndata = ndata; } -EXPORT_SYMBOL_GPL(kvm_prepare_event_vectoring_exit); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_prepare_event_vectoring_exit); static int handle_emulation_failure(struct kvm_vcpu *vcpu, int emulation_type) { @@ -9233,7 +9233,7 @@ int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu) r = kvm_vcpu_do_singlestep(vcpu); return r; } -EXPORT_SYMBOL_GPL(kvm_skip_emulated_instruction); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_skip_emulated_instruction); static bool kvm_is_code_breakpoint_inhibited(struct kvm_vcpu *vcpu) { @@ -9364,7 +9364,7 @@ int x86_decode_emulated_instruction(struct kvm_vcpu *vcpu, int emulation_type, return r; } -EXPORT_SYMBOL_GPL(x86_decode_emulated_instruction); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(x86_decode_emulated_instruction); int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, int emulation_type, void *insn, int insn_len) @@ -9588,14 +9588,14 @@ int kvm_emulate_instruction(struct kvm_vcpu *vcpu, int emulation_type) { return x86_emulate_instruction(vcpu, 0, emulation_type, NULL, 0); } -EXPORT_SYMBOL_GPL(kvm_emulate_instruction); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_instruction); int kvm_emulate_instruction_from_buffer(struct kvm_vcpu *vcpu, void *insn, int insn_len) { return x86_emulate_instruction(vcpu, 0, 0, insn, insn_len); } -EXPORT_SYMBOL_GPL(kvm_emulate_instruction_from_buffer); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_instruction_from_buffer); static int complete_fast_pio_out_port_0x7e(struct kvm_vcpu *vcpu) { @@ -9690,7 +9690,7 @@ int kvm_fast_pio(struct kvm_vcpu *vcpu, int size, unsigned short port, int in) ret = kvm_fast_pio_out(vcpu, size, port); return ret && kvm_skip_emulated_instruction(vcpu); } -EXPORT_SYMBOL_GPL(kvm_fast_pio); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_fast_pio); static int kvmclock_cpu_down_prep(unsigned int cpu) { @@ -10147,7 +10147,7 @@ out_free_x86_emulator_cache: kmem_cache_destroy(x86_emulator_cache); return r; } -EXPORT_SYMBOL_GPL(kvm_x86_vendor_init); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_x86_vendor_init); void kvm_x86_vendor_exit(void) { @@ -10181,7 +10181,7 @@ void kvm_x86_vendor_exit(void) kvm_x86_ops.enable_virtualization_cpu = NULL; mutex_unlock(&vendor_module_lock); } -EXPORT_SYMBOL_GPL(kvm_x86_vendor_exit); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_x86_vendor_exit); #ifdef CONFIG_X86_64 static int kvm_pv_clock_pairing(struct kvm_vcpu *vcpu, gpa_t paddr, @@ -10245,7 +10245,7 @@ bool kvm_apicv_activated(struct kvm *kvm) { return (READ_ONCE(kvm->arch.apicv_inhibit_reasons) == 0); } -EXPORT_SYMBOL_GPL(kvm_apicv_activated); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apicv_activated); bool kvm_vcpu_apicv_activated(struct kvm_vcpu *vcpu) { @@ -10255,7 +10255,7 @@ bool kvm_vcpu_apicv_activated(struct kvm_vcpu *vcpu) return (vm_reasons | vcpu_reasons) == 0; } -EXPORT_SYMBOL_GPL(kvm_vcpu_apicv_activated); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_apicv_activated); static void set_or_clear_apicv_inhibit(unsigned long *inhibits, enum kvm_apicv_inhibit reason, bool set) @@ -10431,7 +10431,7 @@ out: vcpu->run->hypercall.ret = ret; return 1; } -EXPORT_SYMBOL_GPL(____kvm_emulate_hypercall); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(____kvm_emulate_hypercall); int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) { @@ -10444,7 +10444,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) return __kvm_emulate_hypercall(vcpu, kvm_x86_call(get_cpl)(vcpu), complete_hypercall_exit); } -EXPORT_SYMBOL_GPL(kvm_emulate_hypercall); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_hypercall); static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt) { @@ -10887,7 +10887,7 @@ out: preempt_enable(); up_read(&vcpu->kvm->arch.apicv_update_lock); } -EXPORT_SYMBOL_GPL(__kvm_vcpu_update_apicv); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__kvm_vcpu_update_apicv); static void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu) { @@ -10963,7 +10963,7 @@ void kvm_set_or_clear_apicv_inhibit(struct kvm *kvm, __kvm_set_or_clear_apicv_inhibit(kvm, reason, set); up_write(&kvm->arch.apicv_update_lock); } -EXPORT_SYMBOL_GPL(kvm_set_or_clear_apicv_inhibit); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_or_clear_apicv_inhibit); static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu) { @@ -11517,7 +11517,7 @@ bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu) return false; } -EXPORT_SYMBOL_GPL(kvm_vcpu_has_events); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_has_events); int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) { @@ -11670,7 +11670,7 @@ int kvm_emulate_halt_noskip(struct kvm_vcpu *vcpu) { return __kvm_emulate_halt(vcpu, KVM_MP_STATE_HALTED, KVM_EXIT_HLT); } -EXPORT_SYMBOL_GPL(kvm_emulate_halt_noskip); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_halt_noskip); int kvm_emulate_halt(struct kvm_vcpu *vcpu) { @@ -11681,7 +11681,7 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu) */ return kvm_emulate_halt_noskip(vcpu) && ret; } -EXPORT_SYMBOL_GPL(kvm_emulate_halt); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_halt); fastpath_t handle_fastpath_hlt(struct kvm_vcpu *vcpu) { @@ -11693,7 +11693,7 @@ fastpath_t handle_fastpath_hlt(struct kvm_vcpu *vcpu) return EXIT_FASTPATH_EXIT_HANDLED; } -EXPORT_SYMBOL_GPL(handle_fastpath_hlt); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(handle_fastpath_hlt); int kvm_emulate_ap_reset_hold(struct kvm_vcpu *vcpu) { @@ -11702,7 +11702,7 @@ int kvm_emulate_ap_reset_hold(struct kvm_vcpu *vcpu) return __kvm_emulate_halt(vcpu, KVM_MP_STATE_AP_RESET_HOLD, KVM_EXIT_AP_RESET_HOLD) && ret; } -EXPORT_SYMBOL_GPL(kvm_emulate_ap_reset_hold); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_emulate_ap_reset_hold); bool kvm_arch_dy_has_pending_interrupt(struct kvm_vcpu *vcpu) { @@ -12255,7 +12255,7 @@ unhandled_task_switch: vcpu->run->internal.ndata = 0; return 0; } -EXPORT_SYMBOL_GPL(kvm_task_switch); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_task_switch); static bool kvm_is_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { @@ -12956,7 +12956,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) if (init_event) kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu); } -EXPORT_SYMBOL_GPL(kvm_vcpu_reset); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_reset); void kvm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector) { @@ -12968,7 +12968,7 @@ void kvm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector) kvm_set_segment(vcpu, &cs, VCPU_SREG_CS); kvm_rip_write(vcpu, 0); } -EXPORT_SYMBOL_GPL(kvm_vcpu_deliver_sipi_vector); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_deliver_sipi_vector); void kvm_arch_enable_virtualization(void) { @@ -13086,7 +13086,7 @@ bool kvm_vcpu_is_reset_bsp(struct kvm_vcpu *vcpu) { return vcpu->kvm->arch.bsp_vcpu_id == vcpu->vcpu_id; } -EXPORT_SYMBOL_GPL(kvm_vcpu_is_reset_bsp); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_is_reset_bsp); bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu) { @@ -13250,7 +13250,7 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, return (void __user *)hva; } -EXPORT_SYMBOL_GPL(__x86_set_memory_region); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(__x86_set_memory_region); void kvm_arch_pre_destroy_vm(struct kvm *kvm) { @@ -13658,13 +13658,13 @@ unsigned long kvm_get_linear_rip(struct kvm_vcpu *vcpu) return (u32)(get_segment_base(vcpu, VCPU_SREG_CS) + kvm_rip_read(vcpu)); } -EXPORT_SYMBOL_GPL(kvm_get_linear_rip); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_linear_rip); bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip) { return kvm_get_linear_rip(vcpu) == linear_rip; } -EXPORT_SYMBOL_GPL(kvm_is_linear_rip); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_is_linear_rip); unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu) { @@ -13675,7 +13675,7 @@ unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu) rflags &= ~X86_EFLAGS_TF; return rflags; } -EXPORT_SYMBOL_GPL(kvm_get_rflags); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_rflags); static void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) { @@ -13690,7 +13690,7 @@ void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) __kvm_set_rflags(vcpu, rflags); kvm_make_request(KVM_REQ_EVENT, vcpu); } -EXPORT_SYMBOL_GPL(kvm_set_rflags); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_rflags); static inline u32 kvm_async_pf_hash_fn(gfn_t gfn) { @@ -13933,7 +13933,7 @@ bool kvm_arch_has_noncoherent_dma(struct kvm *kvm) { return atomic_read(&kvm->arch.noncoherent_dma_count); } -EXPORT_SYMBOL_GPL(kvm_arch_has_noncoherent_dma); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_arch_has_noncoherent_dma); bool kvm_arch_no_poll(struct kvm_vcpu *vcpu) { @@ -13989,7 +13989,7 @@ int kvm_spec_ctrl_test_value(u64 value) return ret; } -EXPORT_SYMBOL_GPL(kvm_spec_ctrl_test_value); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_spec_ctrl_test_value); void kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_code) { @@ -14014,7 +14014,7 @@ void kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_c } vcpu->arch.walk_mmu->inject_page_fault(vcpu, &fault); } -EXPORT_SYMBOL_GPL(kvm_fixup_and_inject_pf_error); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_fixup_and_inject_pf_error); /* * Handles kvm_read/write_guest_virt*() result and either injects #PF or returns @@ -14043,7 +14043,7 @@ int kvm_handle_memory_failure(struct kvm_vcpu *vcpu, int r, return 0; } -EXPORT_SYMBOL_GPL(kvm_handle_memory_failure); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_handle_memory_failure); int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva) { @@ -14107,7 +14107,7 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva) return 1; } } -EXPORT_SYMBOL_GPL(kvm_handle_invpcid); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_handle_invpcid); static int complete_sev_es_emulated_mmio(struct kvm_vcpu *vcpu) { @@ -14192,7 +14192,7 @@ int kvm_sev_es_mmio_write(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned int bytes, return 0; } -EXPORT_SYMBOL_GPL(kvm_sev_es_mmio_write); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_sev_es_mmio_write); int kvm_sev_es_mmio_read(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned int bytes, void *data) @@ -14230,7 +14230,7 @@ int kvm_sev_es_mmio_read(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned int bytes, return 0; } -EXPORT_SYMBOL_GPL(kvm_sev_es_mmio_read); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_sev_es_mmio_read); static void advance_sev_es_emulated_pio(struct kvm_vcpu *vcpu, unsigned count, int size) { @@ -14318,7 +14318,7 @@ int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, return in ? kvm_sev_es_ins(vcpu, size, port) : kvm_sev_es_outs(vcpu, size, port); } -EXPORT_SYMBOL_GPL(kvm_sev_es_string_io); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_sev_es_string_io); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_entry); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit); From bb7663dec67b691528f104894429b3859fb16c14 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 29 Sep 2025 18:09:39 -0700 Subject: [PATCH 2271/2711] scsi: ufs: sysfs: Make HID attributes visible Call sysfs_update_group() after reading the device descriptor to ensure the HID sysfs attributes are visible when the feature is supported. Fixes: ae7795a8c258 ("scsi: ufs: core: Add HID support") Signed-off-by: Daniel Lee Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-sysfs.c | 2 +- drivers/ufs/core/ufs-sysfs.h | 1 + drivers/ufs/core/ufshcd.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index 0086816b27cd..c040afc6668e 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -1949,7 +1949,7 @@ static umode_t ufs_sysfs_hid_is_visible(struct kobject *kobj, return hba->dev_info.hid_sup ? attr->mode : 0; } -static const struct attribute_group ufs_sysfs_hid_group = { +const struct attribute_group ufs_sysfs_hid_group = { .name = "hid", .attrs = ufs_sysfs_hid, .is_visible = ufs_sysfs_hid_is_visible, diff --git a/drivers/ufs/core/ufs-sysfs.h b/drivers/ufs/core/ufs-sysfs.h index 8d94af3b8077..6efb82a082fd 100644 --- a/drivers/ufs/core/ufs-sysfs.h +++ b/drivers/ufs/core/ufs-sysfs.h @@ -14,5 +14,6 @@ void ufs_sysfs_remove_nodes(struct device *dev); extern const struct attribute_group ufs_sysfs_unit_descriptor_group; extern const struct attribute_group ufs_sysfs_lun_attributes_group; +extern const struct attribute_group ufs_sysfs_hid_group; #endif diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 319dd6f6229b..127b691402f9 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8480,6 +8480,8 @@ static int ufs_get_device_desc(struct ufs_hba *hba) DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP) & UFS_DEV_HID_SUPPORT; + sysfs_update_group(&hba->dev->kobj, &ufs_sysfs_hid_group); + model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; err = ufshcd_read_string_desc(hba, model_index, From 558ae4579810fa0fef011944230c65a6f3087f85 Mon Sep 17 00:00:00 2001 From: Hoyoung Seo Date: Tue, 30 Sep 2025 15:14:28 +0900 Subject: [PATCH 2272/2711] scsi: ufs: core: Include UTP error in INT_FATAL_ERRORS When a UTP error occurs in isolation, UFS is not currently recoverable. This is because the UTP error is not considered fatal in the error handling code, leading to either an I/O timeout or an OCS error. Add the UTP error flag to INT_FATAL_ERRORS so the controller will be reset in this situation. sd 0:0:0:0: [sda] tag#38 UNKNOWN(0x2003) Result: hostbyte=0x07 driverbyte=DRIVER_OK cmd_age=0s sd 0:0:0:0: [sda] tag#38 CDB: opcode=0x28 28 00 00 51 24 e2 00 00 08 00 I/O error, dev sda, sector 42542864 op 0x0:(READ) flags 0x80700 phys_seg 8 prio class 2 OCS error from controller = 9 for tag 39 pa_err[1] = 0x80000010 at 2667224756 us pa_err: total cnt=2 dl_err[0] = 0x80000002 at 2667148060 us dl_err[1] = 0x80002000 at 2667282844 us No record of nl_err No record of tl_err No record of dme_err No record of auto_hibern8_err fatal_err[0] = 0x804 at 2667282836 us --------------------------------------------------- REGISTER --------------------------------------------------- NAME OFFSET VALUE STD HCI SFR 0xfffffff0 0x0 AHIT 0x18 0x814 INTERRUPT STATUS 0x20 0x1000 INTERRUPT ENABLE 0x24 0x70ef5 [mkp: commit desc] Signed-off-by: Hoyoung Seo Reviewed-by: Bart Van Assche Message-Id: <20250930061428.617955-1-hy50.seo@samsung.com> Signed-off-by: Martin K. Petersen --- include/ufs/ufshci.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index 612500a7088f..e64b70132101 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -180,6 +180,7 @@ static inline u32 ufshci_version(u32 major, u32 minor) #define UTP_TASK_REQ_COMPL 0x200 #define UIC_COMMAND_COMPL 0x400 #define DEVICE_FATAL_ERROR 0x800 +#define UTP_ERROR 0x1000 #define CONTROLLER_FATAL_ERROR 0x10000 #define SYSTEM_BUS_FATAL_ERROR 0x20000 #define CRYPTO_ENGINE_FATAL_ERROR 0x40000 @@ -199,7 +200,8 @@ static inline u32 ufshci_version(u32 major, u32 minor) CONTROLLER_FATAL_ERROR |\ SYSTEM_BUS_FATAL_ERROR |\ CRYPTO_ENGINE_FATAL_ERROR |\ - UIC_LINK_LOST) + UIC_LINK_LOST |\ + UTP_ERROR) /* HCS - Host Controller Status 30h */ #define DEVICE_PRESENT 0x1 From d655a684c24dde9e9f3f98f3dbae5a4f592117d4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 30 Sep 2025 15:25:33 +0300 Subject: [PATCH 2273/2711] Input: aw86927 - fix error code in probe() Fix this copy and paste bug. Return "err" instead of PTR_ERR(haptics->regmap). Fixes: 52e06d564ce6 ("Input: aw86927 - add driver for Awinic AW86927") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/aNvMPTnOovdBitdP@stanley.mountain Signed-off-by: Dmitry Torokhov --- drivers/input/misc/aw86927.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/misc/aw86927.c b/drivers/input/misc/aw86927.c index a0c88a7e1e1c..8ad361239cfe 100644 --- a/drivers/input/misc/aw86927.c +++ b/drivers/input/misc/aw86927.c @@ -759,8 +759,7 @@ static int aw86927_probe(struct i2c_client *client) /* Software reset */ err = regmap_write(haptics->regmap, AW86927_RSTCFG_REG, AW86927_RSTCFG_SOFTRST); if (err) - return dev_err_probe(haptics->dev, PTR_ERR(haptics->regmap), - "Failed Software reset\n"); + return dev_err_probe(haptics->dev, err, "Failed Software reset\n"); /* Wait ~3ms until I2C is accessible */ usleep_range(3000, 3500); From d391bb1955747edc9f92e67d35c79ada996a93eb Mon Sep 17 00:00:00 2001 From: Qianfeng Rong Date: Mon, 4 Aug 2025 15:24:11 +0800 Subject: [PATCH 2274/2711] fbdev: xenfb: Use vmalloc_array to simplify code Use vmalloc_array() instead of vmalloc() to simplify the function xenfb_probe(). Signed-off-by: Qianfeng Rong Signed-off-by: Helge Deller --- drivers/video/fbdev/xen-fbfront.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index c90f48ebb15e..d8f3bfb2dd6c 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -390,7 +390,7 @@ static int xenfb_probe(struct xenbus_device *dev, info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; - info->gfns = vmalloc(array_size(sizeof(unsigned long), info->nr_pages)); + info->gfns = vmalloc_array(info->nr_pages, sizeof(unsigned long)); if (!info->gfns) goto error_nomem; From 43b30be2e7211d982b005d118dd6a12f97b9d458 Mon Sep 17 00:00:00 2001 From: Zsolt Kajtar Date: Sun, 10 Aug 2025 17:47:54 +0200 Subject: [PATCH 2275/2711] fbdev: s3fb: Implement powersave for S3 FB This patch implements power saving for S3 cards by powering down the RAMDAC and stopping MCLK and DCLK while the card is supposed to be suspended. The RAMDAC is also disabled while the screen is blanked and the DCLK in stopped while in DPMS power off. The practical difference it makes is that on a machine with such a card the display will be placed in DPMS power off while standby is activated (due to stopped DCLK). Same like when using other cards with implemented power saving functionality. Without it on my setup the connected display powers up and stays that way showing VT63 while in standby. Sort of annoying as before standby it's specifically placed into DPMS off in Xorg for a while. The used functionality should exists for sure on Trio32 to Aurora64V (according to the documentation) so I think it's generally applicable. I'm using this on S3 Trio 3D and S3 Virge DX. Signed-off-by: Zsolt Kajtar Signed-off-by: Helge Deller --- drivers/video/fbdev/s3fb.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c index ff84106ecf1c..9b3fca9b3e08 100644 --- a/drivers/video/fbdev/s3fb.c +++ b/drivers/video/fbdev/s3fb.c @@ -988,34 +988,30 @@ static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static int s3fb_blank(int blank_mode, struct fb_info *info) { struct s3fb_info *par = info->par; + u8 data; + + data = (blank_mode == FB_BLANK_UNBLANK) ? 0x00 : 0x20; + svga_wseq_mask(par->state.vgabase, 0x01, data, 0x20); + svga_wseq_mask(par->state.vgabase, 0x18, data, 0x20); switch (blank_mode) { - case FB_BLANK_UNBLANK: - fb_dbg(info, "unblank\n"); - svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06); - svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); - break; - case FB_BLANK_NORMAL: - fb_dbg(info, "blank\n"); - svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06); - svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); + default: + data = 0x00; break; case FB_BLANK_HSYNC_SUSPEND: - fb_dbg(info, "hsync\n"); - svga_wcrt_mask(par->state.vgabase, 0x56, 0x02, 0x06); - svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); + data = 0x02; break; case FB_BLANK_VSYNC_SUSPEND: - fb_dbg(info, "vsync\n"); - svga_wcrt_mask(par->state.vgabase, 0x56, 0x04, 0x06); - svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); + data = 0x04; break; case FB_BLANK_POWERDOWN: - fb_dbg(info, "sync down\n"); - svga_wcrt_mask(par->state.vgabase, 0x56, 0x06, 0x06); - svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); + data = 0x06; break; } + svga_wcrt_mask(par->state.vgabase, 0x56, data, 0x06); + + data = (blank_mode == FB_BLANK_POWERDOWN) ? 0x01 : 0x00; + svga_wseq_mask(par->state.vgabase, 0x14, data, 0x01); return 0; } @@ -1445,6 +1441,8 @@ static int __maybe_unused s3_pci_suspend(struct device *dev) } fb_set_suspend(info, 1); + svga_wseq_mask(par->state.vgabase, 0x18, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x14, 0x03, 0x03); mutex_unlock(&(par->open_lock)); console_unlock(); @@ -1471,6 +1469,9 @@ static int __maybe_unused s3_pci_resume(struct device *dev) return 0; } + vga_wseq(par->state.vgabase, 0x08, 0x06); + svga_wseq_mask(par->state.vgabase, 0x18, 0x00, 0x20); + svga_wseq_mask(par->state.vgabase, 0x14, 0x00, 0x03); s3fb_set_par(info); fb_set_suspend(info, 0); From 69c9820d40892f7c10db03c5364795f5bb12aced Mon Sep 17 00:00:00 2001 From: Zsolt Kajtar Date: Mon, 18 Aug 2025 22:44:26 +0200 Subject: [PATCH 2276/2711] fbdev: s3fb: Implement 1 and 2 BPP modes, improve 4 BPP With the right setup S3 cards can display 1 and 2 BPP packed pixel modes, even in high resolutions. So this patch makes them available. The 4 BPP packed pixel mode had one pixel column of garbage on the left side due to how the shift register works, this is fixed now. There was a limitation that only 8 pixel wide fonts could be used at 4 BPP. Since the CFB routines were updated to handle reverse pixel ordering correctly that limitation doesn't exists and was removed now. In 4 BPP interleaved planes mode font widths of multiply of 8 are accepted now, not just 8 pixels. The horizontal screen position will not move as much between modes as it used to. That was caused by the various amount of pipeline delay which is compensated now as much as possible. While adjusting the code direct port access of PEL registers was corrected. Should work now on systems where these are memory mapped. I've noticed that when in 1 BPP mode the console is used with Unicode fonts erasing might be done with non-blanks. That's a bug in the VT code and so not part of this patch. Signed-off-by: Zsolt Kajtar Signed-off-by: Helge Deller --- drivers/video/fbdev/Kconfig | 1 + drivers/video/fbdev/s3fb.c | 140 ++++++++++++++++++++++++++---------- 2 files changed, 105 insertions(+), 36 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index c21484d15f0c..1500dca8c416 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1060,6 +1060,7 @@ config FB_S3 select FB_TILEBLITTING select FB_SVGALIB select VGASTATE + select FB_CFB_REV_PIXELS_IN_BYTE select FONT_8x16 if FRAMEBUFFER_CONSOLE help Driver for graphics boards with S3 Trio / S3 Virge chip. diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c index 9b3fca9b3e08..a6cfed0a87fa 100644 --- a/drivers/video/fbdev/s3fb.c +++ b/drivers/video/fbdev/s3fb.c @@ -50,10 +50,14 @@ struct s3fb_info { static const struct svga_fb_format s3fb_formats[] = { { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4, FB_VISUAL_PSEUDOCOLOR, 8, 16}, - { 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 0, - FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16}, + { 1, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 0, 0}, 2, + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 32, 64}, + { 2, {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0}, 2, + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 32}, { 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 1, FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 8, 16}, + { 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 2, + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16}, { 8, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 4, 8}, {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0, @@ -557,7 +561,7 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) /* 32bpp mode is not supported on VIRGE VX, 24bpp is not supported on others */ - if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6)) + if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 9) : (rv == 8)) rv = -EINVAL; if (rv < 0) { @@ -607,7 +611,7 @@ static int s3fb_set_par(struct fb_info *info) struct s3fb_info *par = info->par; u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes; u32 bpp = info->var.bits_per_pixel; - u32 htotal, hsstart; + u32 htotal, hsstart, pel_msk; if (bpp != 0) { info->fix.ypanstep = 1; @@ -617,9 +621,11 @@ static int s3fb_set_par(struct fb_info *info) info->tileops = NULL; /* in 4bpp supports 8p wide tiles only, any tiles otherwise */ - if (bpp == 4) { + if (bpp == 4 && (info->var.nonstd & 1) != 0) { + int i; bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH); - set_bit(8 - 1, info->pixmap.blit_x); + for (i = 8; i <= FB_MAX_BLIT_WIDTH; i += 8) + set_bit(i - 1, info->pixmap.blit_x); } else { bitmap_fill(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH); } @@ -730,7 +736,7 @@ static int s3fb_set_par(struct fb_info *info) vga_wcrt(par->state.vgabase, 0x50, 0x00); vga_wcrt(par->state.vgabase, 0x67, 0x50); msleep(10); /* screen remains blank sometimes without this */ - vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09); + vga_wcrt(par->state.vgabase, 0x63, (mode <= 4) ? 0x90 : 0x09); vga_wcrt(par->state.vgabase, 0x66, 0x90); } @@ -763,12 +769,17 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(par->state.vgabase, 0x31, 0x00, 0x40); multiplex = 0; hmul = 1; + pel_msk = 0xff; + + svga_wcrt_mask(par->state.vgabase, 0x08, 0x00, 0x60); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x00, 0x60); /* Set mode-specific register values */ switch (mode) { case 0: fb_dbg(info, "text mode\n"); svga_set_textmode_vga_regs(par->state.vgabase); + pel_msk = 0x0f; /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); @@ -783,8 +794,11 @@ static int s3fb_set_par(struct fb_info *info) } break; case 1: - fb_dbg(info, "4 bit pseudocolor\n"); - vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40); + fb_dbg(info, "1 bit pseudocolor\n"); + svga_wseq_mask(par->state.vgabase, 0x01, 0x10, 0x14); + svga_wcrt_mask(par->state.vgabase, 0x08, 0x60, 0x60); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60); + pel_msk = 0x01; /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); @@ -794,7 +808,13 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); break; case 2: - fb_dbg(info, "4 bit pseudocolor, planar\n"); + fb_dbg(info, "2 bit pseudocolor\n"); + svga_wseq_mask(par->state.vgabase, 0x01, 0x04, 0x14); + svga_wseq_mask(par->state.vgabase, 0x04, 0x08, 0x08); + vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x08, 0x20, 0x60); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60); + pel_msk = 0x03; /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); @@ -804,8 +824,35 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); break; case 3: + fb_dbg(info, "4 bit pseudocolor, planar\n"); + pel_msk = 0x0f; + + /* Set additional registers like in 8-bit mode */ + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60); + + /* disable enhanced mode */ + svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); + break; + case 4: + fb_dbg(info, "4 bit pseudocolor\n"); + vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40); + svga_wattr(par->state.vgabase, 0x33, 0x01); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60); + pel_msk = 0xf0; + + /* Set additional registers like in 8-bit mode */ + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); + + /* disable enhanced mode */ + svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); + break; + case 5: fb_dbg(info, "8 bit pseudocolor\n"); svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x20, 0x60); if (info->var.pixclock > 20000 || par->chip == CHIP_357_VIRGE_GX2 || par->chip == CHIP_359_VIRGE_GX2P || @@ -819,7 +866,7 @@ static int s3fb_set_par(struct fb_info *info) multiplex = 1; } break; - case 4: + case 6: fb_dbg(info, "5/5/5 truecolor\n"); if (par->chip == CHIP_988_VIRGE_VX) { if (info->var.pixclock > 20000) @@ -847,7 +894,7 @@ static int s3fb_set_par(struct fb_info *info) hmul = 2; } break; - case 5: + case 7: fb_dbg(info, "5/6/5 truecolor\n"); if (par->chip == CHIP_988_VIRGE_VX) { if (info->var.pixclock > 20000) @@ -875,12 +922,12 @@ static int s3fb_set_par(struct fb_info *info) hmul = 2; } break; - case 6: + case 8: /* VIRGE VX case */ fb_dbg(info, "8/8/8 truecolor\n"); svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0); break; - case 7: + case 9: fb_dbg(info, "8/8/8/8 truecolor\n"); svga_wcrt_mask(par->state.vgabase, 0x50, 0x30, 0x30); svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0); @@ -889,6 +936,7 @@ static int s3fb_set_par(struct fb_info *info) fb_err(info, "unsupported mode - bug\n"); return -EINVAL; } + vga_w(par->state.vgabase, VGA_PEL_MSK, pel_msk); if (par->chip != CHIP_988_VIRGE_VX) { svga_wseq_mask(par->state.vgabase, 0x15, multiplex ? 0x10 : 0x00, 0x10); @@ -927,33 +975,26 @@ static int s3fb_set_par(struct fb_info *info) static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *fb) { + struct s3fb_info *par = fb->par; + int cols; + switch (fb->var.bits_per_pixel) { case 0: + case 1: + case 2: case 4: - if (regno >= 16) - return -EINVAL; - - if ((fb->var.bits_per_pixel == 4) && - (fb->var.nonstd == 0)) { - outb(0xF0, VGA_PEL_MSK); - outb(regno*16, VGA_PEL_IW); - } else { - outb(0x0F, VGA_PEL_MSK); - outb(regno, VGA_PEL_IW); - } - outb(red >> 10, VGA_PEL_D); - outb(green >> 10, VGA_PEL_D); - outb(blue >> 10, VGA_PEL_D); - break; case 8: - if (regno >= 256) + cols = 1 << (fb->var.bits_per_pixel ? fb->var.bits_per_pixel : 4); + if (regno >= cols) return -EINVAL; - outb(0xFF, VGA_PEL_MSK); - outb(regno, VGA_PEL_IW); - outb(red >> 10, VGA_PEL_D); - outb(green >> 10, VGA_PEL_D); - outb(blue >> 10, VGA_PEL_D); + if ((fb->var.bits_per_pixel == 4) && ((fb->var.nonstd & 1) == 0)) + regno <<= 4; + + vga_w(par->state.vgabase, VGA_PEL_IW, regno); + vga_w(par->state.vgabase, VGA_PEL_D, red >> 10); + vga_w(par->state.vgabase, VGA_PEL_D, green >> 10); + vga_w(par->state.vgabase, VGA_PEL_D, blue >> 10); break; case 16: if (regno >= 16) @@ -1041,6 +1082,33 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } +/* Get capabilities of accelerator based on the mode */ + +static void s3fb_get_caps(struct fb_info *info, struct fb_blit_caps *caps, + struct fb_var_screeninfo *var) +{ + int i; + + if (var->bits_per_pixel == 0) { + /* can only support 256 8x16 bitmap */ + bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH); + set_bit(8 - 1, caps->x); + bitmap_zero(caps->y, FB_MAX_BLIT_HEIGHT); + set_bit(16 - 1, caps->y); + caps->len = 256; + } else { + if (var->bits_per_pixel == 4 && (var->nonstd & 1) != 0) { + bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH); + for (i = 8; i <= FB_MAX_BLIT_WIDTH; i += 8) + set_bit(i - 1, caps->x); + } else { + bitmap_fill(caps->x, FB_MAX_BLIT_WIDTH); + } + bitmap_fill(caps->y, FB_MAX_BLIT_HEIGHT); + caps->len = ~(u32)0; + } +} + /* ------------------------------------------------------------------------- */ /* Frame buffer operations */ @@ -1059,7 +1127,7 @@ static const struct fb_ops s3fb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = s3fb_imageblit, __FB_DEFAULT_IOMEM_OPS_MMAP, - .fb_get_caps = svga_get_caps, + .fb_get_caps = s3fb_get_caps, }; /* ------------------------------------------------------------------------- */ From aad1d99beaaf132e2024a52727c24894cdf9474a Mon Sep 17 00:00:00 2001 From: Zsolt Kajtar Date: Thu, 21 Aug 2025 04:42:48 +0200 Subject: [PATCH 2277/2711] fbdev: core: Fix ubsan warning in pixel_to_pat It could be triggered on 32 bit big endian machines at 32 bpp in the pattern realignment. In this case just return early as the result is an identity. Signed-off-by: Zsolt Kajtar Signed-off-by: Helge Deller --- drivers/video/fbdev/core/fb_fillrect.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/video/fbdev/core/fb_fillrect.h b/drivers/video/fbdev/core/fb_fillrect.h index 66042e534de7..f366670a53af 100644 --- a/drivers/video/fbdev/core/fb_fillrect.h +++ b/drivers/video/fbdev/core/fb_fillrect.h @@ -92,8 +92,7 @@ static unsigned long pixel_to_pat(int bpp, u32 color) pattern = pattern | pattern << bpp; break; default: - pattern = color; - break; + return color; } #ifndef __LITTLE_ENDIAN pattern <<= (BITS_PER_LONG % bpp); From c7d655ef2e0ca25ae2c46df47eb62ada9e820c78 Mon Sep 17 00:00:00 2001 From: Chelsy Ratnawat Date: Sun, 24 Aug 2025 08:23:27 -0700 Subject: [PATCH 2278/2711] fbdev: Use string choices helpers Use string_choices.h helpers instead of hard-coded strings. Signed-off-by: Chelsy Ratnawat Signed-off-by: Helge Deller --- drivers/video/fbdev/core/fbmon.c | 7 ++++--- drivers/video/fbdev/nvidia/nvidia.c | 3 ++- drivers/video/fbdev/pxafb.c | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c index 3b779c27c271..0a65bef01e3c 100644 --- a/drivers/video/fbdev/core/fbmon.c +++ b/drivers/video/fbdev/core/fbmon.c @@ -36,6 +36,7 @@ #include